fix(cli): retain JavaScript evidence through final cleanup (#9595)

fix(cli): retain JavaScript evidence after final cleanup
This commit is contained in:
morluto authored and GitHub committed 2026-11-09 19:34:10 +08:00
1 parent 9536ebb7ca
commit a6c10a28f4
2 files changed
+92 -6

No files matched your search

@@ -1,10 +1,14 @@
import { afterEach, expect, it } from "vitest";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { afterEach, expect, it, vi } from "vitest";
import { ArtifactResourceScope } from "../../../src/artifacts/ArtifactResourceScope.js";
import {
closeCliJavaScriptResources,
CliJavaScriptAnalysisHost,
runCliJavaScriptApplicationAnalysis,
} from "../../../src/cli/javascriptApplicationAnalysis.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const originalClose = ArtifactResourceScope.prototype.close;
@@ -17,6 +21,80 @@ afterEach(async () => {
const openCliScope = (): Promise<unknown> =>
runCliJavaScriptApplicationAnalysis({}, {});
it.each([false, true])(
"retains completed JavaScript Evidence when final cleanup fails (cancelled=%s)",
async (cancelled) => {
const root = await createTestTempDirectory("cli-js-cleanup-evidence-");
await writeFile(join(root, "index.js"), "export const answer = 42;\n");
const host = new CliJavaScriptAnalysisHost();
const controller = new AbortController();
const retry = vi
.spyOn(host.scope(), "retryCleanup")
.mockImplementationOnce(async () => {
if (cancelled) controller.abort("stop after analysis");
throw new Error("cleanup failed");
});
try {
const result = await runCliJavaScriptApplicationAnalysis(
{ input_path: root },
{},
controller.signal,
undefined,
host,
);
expect(result).toMatchObject({
code: "cleanup_incomplete",
details: {
partial_observation: {
operation: "analyze_javascript_application",
normalized_result: { input_path: root },
},
},
});
if (cancelled)
expect(result).toMatchObject({
details: { diagnostics: { primary_error: { code: "cancelled" } } },
});
} finally {
retry.mockRestore();
await host.close();
}
},
);
it("retains completed JavaScript Evidence when cancellation arrives during final cleanup", async () => {
const root = await createTestTempDirectory("cli-js-cancel-evidence-");
await writeFile(join(root, "index.js"), "export const answer = 42;\n");
const host = new CliJavaScriptAnalysisHost();
const controller = new AbortController();
const retry = vi
.spyOn(host.scope(), "retryCleanup")
.mockImplementationOnce(async () => {
controller.abort("stop after analysis");
});
try {
const result = await runCliJavaScriptApplicationAnalysis(
{ input_path: root },
{},
controller.signal,
undefined,
host,
);
expect(result).toMatchObject({
code: "cancelled",
details: {
partial_observation: {
operation: "analyze_javascript_application",
normalized_result: { input_path: root },
},
},
});
} finally {
retry.mockRestore();
await host.close();
}
});
it("retries JavaScript worker shutdown when the first close fails", async () => {
let calls = 0;
ArtifactResourceScope.prototype.close = function (