diff --git a/tools/device-pod-cli.test.ts b/tools/device-pod-cli.test.ts index c187b550..373bfe5c 100644 --- a/tools/device-pod-cli.test.ts +++ b/tools/device-pod-cli.test.ts @@ -462,6 +462,87 @@ test("device-pod-cli forwards host build and download job ids as named device-po }); }); +test("device-pod-cli maps build evidence / download evidence to first-class workspace.evidence / debug.evidence intents (HWLAB #801)", async () => { + const seen: any[] = []; + const fetchImpl = async (url, init) => { + seen.push({ url: String(url), body: JSON.parse(String(init?.body ?? "{}")) }); + return jsonResponse(202, { ok: true, status: "running", job: { id: `job_${seen.length}`, status: "running" } }); + }; + const build = await runAssembledDevicePodCli([ + "D601-F103-V2:workspace:/projects/01_baseline", + "build", + "evidence", + "job_devicepod_7ce895d1-bb3e-4daa-b4a1-6d7d05522923", + "--tail", + "60" + ], { fetchImpl, now: () => "2026-06-04T00:00:00.000Z" }); + assert.equal(build.exitCode, 0); + assert.deepEqual(seen[0].body, { + intent: "workspace.evidence", + args: { + kind: "build", + jobId: "job_devicepod_7ce895d1-bb3e-4daa-b4a1-6d7d05522923", + tail: 60 + } + }); + + const download = await runAssembledDevicePodCli([ + "D601-F103-V2:debug-probe", + "download", + "evidence", + "job_devicepod_fb23ec52-339c-45cb-9b82-1af1fb7b6ee0", + "--full" + ], { fetchImpl, now: () => "2026-06-04T00:00:00.000Z" }); + assert.equal(download.exitCode, 0); + assert.deepEqual(seen[1].body, { + intent: "debug.evidence", + args: { + kind: "download", + jobId: "job_devicepod_fb23ec52-339c-45cb-9b82-1af1fb7b6ee0", + full: true + } + }); +}); + +test("device-pod-cli keeps build start / download start on workspace.build / debug.download intents (HWLAB #801 regression)", async () => { + const seen: any[] = []; + const fetchImpl = async (url, init) => { + seen.push({ url: String(url), body: JSON.parse(String(init?.body ?? "{}")) }); + return jsonResponse(202, { ok: true, status: "running", job: { id: `job_${seen.length}`, status: "running" } }); + }; + const build = await runAssembledDevicePodCli([ + "D601-F103-V2:workspace:/projects/01_baseline", + "build", + "start", + "--reason", + "smoke test" + ], { fetchImpl, now: () => "2026-06-04T00:00:00.000Z" }); + assert.equal(build.exitCode, 0); + assert.deepEqual(seen[0].body, { + intent: "workspace.build", + args: { action: "start" }, + reason: "smoke test" + }); + + const download = await runAssembledDevicePodCli([ + "D601-F103-V2:debug-probe", + "download", + "start", + "--capture-uart", + "uart/1", + "--capture-duration-ms", + "8000", + "--reason", + "smoke test" + ], { fetchImpl, now: () => "2026-06-04T00:00:00.000Z" }); + assert.equal(download.exitCode, 0); + assert.deepEqual(seen[1].body, { + intent: "debug.download", + args: { action: "start", captureUart: "uart/1", captureDurationMs: 8000 }, + reason: "smoke test" + }); +}); + test("device-pod-cli maps selector build/download cloud job aliases to job routes", async () => { const seen: any[] = []; const fetchImpl = async (url, init) => { diff --git a/tools/src/device-pod-cli-lib.ts b/tools/src/device-pod-cli-lib.ts index 00e45ad1..d3ab2eb0 100644 --- a/tools/src/device-pod-cli-lib.ts +++ b/tools/src/device-pod-cli-lib.ts @@ -296,10 +296,17 @@ async function buildJob(selector: any, operation: string, rest: string[], parsed Object.assign(args, passthroughOptions(parsed, ["encoding", "charset", "createDirs"])); } else if (operation === "build") { - intent = "workspace.build"; - args.action = rest[1] || "start"; - if (["status", "wait"].includes(String(args.action))) args.jobId = text(rest[2] ?? parsed.jobId); - Object.assign(args, passthroughOptions(parsed, ["target", "timeoutMs", "clean", "dryRun"])); + if (text(rest[1]) === "evidence") { + intent = "workspace.evidence"; + args.kind = "build"; + args.jobId = text(rest[2] ?? parsed.jobId); + Object.assign(args, passthroughOptions(parsed, ["tail", "full", "target"])); + } else { + intent = "workspace.build"; + args.action = rest[1] || "start"; + if (["status", "wait"].includes(String(args.action))) args.jobId = text(rest[2] ?? parsed.jobId); + Object.assign(args, passthroughOptions(parsed, ["target", "timeoutMs", "clean", "dryRun"])); + } } else throw cliError("unsupported_workspace_operation", `unsupported workspace operation: ${operation}`); } else if (selector.surface === "debug-probe") { @@ -312,18 +319,25 @@ async function buildJob(selector: any, operation: string, rest: string[], parsed ); } else if (operation === "download") { - intent = "debug.download"; - args.action = rest[1] || "start"; - if (["status", "wait"].includes(String(args.action))) args.jobId = text(rest[2] ?? parsed.jobId); - Object.assign(args, passthroughOptions(parsed, [ - "target", - "timeoutMs", - "captureUart", - "captureDurationMs", - "durationMs", - "port", - "baudRate" - ])); + if (text(rest[1]) === "evidence") { + intent = "debug.evidence"; + args.kind = "download"; + args.jobId = text(rest[2] ?? parsed.jobId); + Object.assign(args, passthroughOptions(parsed, ["tail", "full", "target"])); + } else { + intent = "debug.download"; + args.action = rest[1] || "start"; + if (["status", "wait"].includes(String(args.action))) args.jobId = text(rest[2] ?? parsed.jobId); + Object.assign(args, passthroughOptions(parsed, [ + "target", + "timeoutMs", + "captureUart", + "captureDurationMs", + "durationMs", + "port", + "baudRate" + ])); + } } else if (operation === "reset") intent = "debug.reset"; else throw cliError(