fix(test-harness): restore promisify(exec) + unblock CLI introspection probes
The vitest child-process guard wrapped exec/execFile without preserving the
`[util.promisify.custom]` symbol, so awaited `execAsync` resolved to a raw
stdout string instead of `{stdout, stderr}`. That single regression cascaded
through ~60 "failing" tests across cli, core, engine, and dashboard whose
production code was actually correct. Also relax the AI-CLI blocklist for
cheap introspection (--version/--help/which …), give SIGTERM'd subprocesses a
brief grace period before being flagged as "left running", fix a few real
test-side bugs uncovered along the way (executor mock step transitions, iOS
last-resort keyboard path, mission SSE replay tests racing with the real AI
agent), and convert dashboard route tests' dynamic `await import("../server.js")`
to static imports so first-test timings drop from 2–5s to <200ms.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4406,12 +4406,21 @@ const mockedReviewStep = vi.mocked(mockedReviewStepFn);
|
||||
*/
|
||||
async function captureTools(): Promise<Record<string, (id: string, params: any) => Promise<any>>> {
|
||||
const store = createMockStore();
|
||||
store.updateStep.mockResolvedValue({
|
||||
steps: [
|
||||
{ name: "Preflight", status: "done" },
|
||||
{ name: "Implement", status: "in-progress" },
|
||||
{ name: "Testing", status: "pending" },
|
||||
],
|
||||
// Simulate the real TaskStore: forward transitions persist, but in-progress
|
||||
// regressions on done/skipped steps are rejected so executor.ts can surface
|
||||
// the "already <status>" diagnostic.
|
||||
const stepStates: Array<{ name: string; status: string }> = [
|
||||
{ name: "Preflight", status: "done" },
|
||||
{ name: "Implement", status: "in-progress" },
|
||||
{ name: "Testing", status: "pending" },
|
||||
];
|
||||
store.updateStep.mockImplementation(async (_taskId: string, stepIndex: number, status: string) => {
|
||||
const current = stepStates[stepIndex];
|
||||
const isRegression = status === "in-progress" && (current.status === "done" || current.status === "skipped");
|
||||
if (!isRegression) {
|
||||
current.status = status;
|
||||
}
|
||||
return { steps: stepStates.map((s) => ({ ...s })) };
|
||||
});
|
||||
mockedExistsSync.mockReturnValue(true);
|
||||
|
||||
@@ -4675,10 +4684,13 @@ describe("Code review verdict enforcement - fn_task_update blocking", () => {
|
||||
mockedReviewStep.mockResolvedValue({ verdict: "REVISE", review: "Fix", summary: "Bad" });
|
||||
|
||||
const tools = await captureTools();
|
||||
await tools.fn_review_step("c1", { step: 1, type: "code", step_name: "Step1", baseline: "a" });
|
||||
// Target step 3 (Testing, currently pending) so the in-progress transition is
|
||||
// a valid forward move — the assertion below only verifies that a REVISE on
|
||||
// the same step does not produce the "Cannot mark … as done" block.
|
||||
await tools.fn_review_step("c1", { step: 3, type: "code", step_name: "Testing", baseline: "a" });
|
||||
|
||||
// "in-progress" should still work even with REVISE
|
||||
const result = await tools.fn_task_update("c2", { step: 1, status: "in-progress" });
|
||||
const result = await tools.fn_task_update("c2", { step: 3, status: "in-progress" });
|
||||
expect(result.content[0].text).not.toContain("Cannot mark");
|
||||
expect(result.content[0].text).toContain("→ in-progress");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user