CoDEVX / scripts /local-smoke.mjs
CodexMacTiger
feat: live package-scoped chat and thinking logs
837e3ac
import http from "node:http";
import { readFile } from "node:fs/promises";
import path from "node:path";
const appBaseUrl = process.env.APP_BASE_URL || "http://127.0.0.1:3000";
const seedPath = path.join(
process.cwd(),
"agentic_pm_demo_codex_plans/data/work-packages.seed.json",
);
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
function buildFakeLlmResponse(joinedMessages) {
if (joinedMessages.includes("Connection test.")) {
return "Connected to the configured model.";
}
if (joinedMessages.includes('"mode": "ask"')) {
return "Verification method explains how the requirement will be checked, such as by test, inspection, or analysis.";
}
if (joinedMessages.includes('"mode": "plan"')) {
return "Please break this package into review tasks.";
}
if (joinedMessages.includes('"mode": "change"')) {
return "Please update the objective to include cybersecurity acceptance criteria.";
}
return JSON.stringify({
choices: [
{
message: {
content: JSON.stringify({
assistantMessage: "Fallback JSON response.",
boardAction: { type: "none", workPackageId: null },
}),
},
},
],
});
}
async function startFakeLlmServer() {
const server = http.createServer((req, res) => {
let body = "";
req.on("data", (chunk) => {
body += chunk;
});
req.on("end", () => {
let payload = {};
try {
payload = JSON.parse(body || "{}");
} catch {
payload = {};
}
const joinedMessages = Array.isArray(payload.messages)
? payload.messages.map((message) => String(message?.content || "")).join("\n\n")
: "";
res.writeHead(200, { "content-type": "text/plain" });
res.end(buildFakeLlmResponse(joinedMessages));
});
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
const address = server.address();
if (!address || typeof address === "string") {
throw new Error("Could not determine fake LLM server address.");
}
return {
server,
baseUrl: `http://127.0.0.1:${address.port}/v1`,
};
}
async function postJson(url, body) {
const response = await fetch(url, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
const payload = await response.json();
if (!response.ok) {
throw new Error(`Request failed (${response.status}): ${JSON.stringify(payload)}`);
}
return payload;
}
async function main() {
const seed = JSON.parse(await readFile(seedPath, "utf8"));
const { server, baseUrl } = await startFakeLlmServer();
try {
console.log(`Smoke target: ${appBaseUrl}`);
console.log(`Fake LLM: ${baseUrl}`);
const llmConfig = {
apiKey: "live-key",
baseUrl,
model: "fake-model",
};
const connection = await postJson(`${appBaseUrl}/api/test-connection`, {
llmConfig,
});
assert(connection.ok === true, "Connection test did not succeed.");
assert(
connection.message === "Connected to the configured model.",
"Connection test message mismatch.",
);
console.log("PASS connection");
const ask = await postJson(`${appBaseUrl}/api/chat`, {
messages: [{ role: "user", content: "@SRS ask What does verification method mean?" }],
workPackages: seed,
selectedWorkPackageId: "wp-srs",
parsedCommand: {
referencedPackageName: "System Requirements Specification",
mode: "ask",
instruction: "What does verification method mean?",
},
llmConfig,
});
assert(
typeof ask.assistantMessage === "string" &&
ask.assistantMessage.includes("Verification method explains"),
"Ask response was not human-readable.",
);
assert(
!ask.assistantMessage.includes("Network or parsing error"),
"Ask response fell back to network/parsing error.",
);
assert(ask.boardAction?.type === "none", "Ask response changed the board.");
console.log("PASS ask");
const plan = await postJson(`${appBaseUrl}/api/chat`, {
messages: [{ role: "user", content: "@SRS plan Break this into review tasks." }],
workPackages: seed,
selectedWorkPackageId: "wp-srs",
parsedCommand: {
referencedPackageName: "System Requirements Specification",
mode: "plan",
instruction: "Break this into review tasks.",
},
llmConfig,
});
assert(
typeof plan.assistantMessage === "string" &&
plan.assistantMessage.includes("Planned next steps for SRS"),
"Plan response message mismatch.",
);
assert(plan.boardAction?.type === "update", "Plan did not return an update.");
assert(plan.boardAction?.workPackageId === "wp-srs", "Plan updated the wrong package.");
assert(
Array.isArray(plan.boardAction?.fields?.tasks) &&
plan.boardAction.fields.tasks.length > 0,
"Plan did not provide tasks.",
);
console.log("PASS plan");
const change = await postJson(`${appBaseUrl}/api/chat`, {
messages: [
{ role: "user", content: "@SRS change Add cybersecurity acceptance criteria." },
],
workPackages: seed,
selectedWorkPackageId: "wp-srs",
parsedCommand: {
referencedPackageName: "System Requirements Specification",
mode: "change",
instruction: "Add cybersecurity acceptance criteria.",
},
llmConfig,
});
assert(
typeof change.assistantMessage === "string" &&
change.assistantMessage.includes("Updated SRS"),
"Change response message mismatch.",
);
assert(change.boardAction?.type === "update", "Change did not return an update.");
assert(
change.boardAction?.workPackageId === "wp-srs",
"Change updated the wrong package.",
);
assert(
String(change.boardAction?.fields?.objective || "").includes(
"Add cybersecurity acceptance criteria.",
),
"Change response did not update the objective.",
);
console.log("PASS change");
console.log("Smoke test complete.");
} finally {
await new Promise((resolve, reject) => {
server.close((error) => {
if (error) {
reject(error);
return;
}
resolve();
});
});
}
}
main().catch((error) => {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
});