import assert from "node:assert/strict"; import { mkdtemp, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { test } from "bun:test"; import { resolveWebObserveActionJson } from "./web-probe-observe-actions"; test("web observe action JSON recovery accepts concrete start contract", () => { const resolved = resolveWebObserveActionJson({ stdout: JSON.stringify({ ok: true, command: "web-probe-observe start", jobId: "webobs-fixture", stateDir: ".state/web-observe/JD01/v03/fixture", valuesRedacted: true, }), stderr: "", exitCode: 0, timedOut: false, }, "start"); assert.equal(resolved.source, "stdout"); assert.equal(resolved.parsed?.jobId, "webobs-fixture"); assert.equal(resolved.diagnostics.stdoutContractAccepted, true); }); test("web observe action JSON recovery reads dump wrapper for status contract", async () => { const dir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-status-dump-")); const dumpPath = join(dir, "status.json"); await writeFile(dumpPath, JSON.stringify({ ok: true, status: "running", jobId: "webobs-fixture", heartbeat: { status: "running" }, diagnostics: { heartbeatStale: false }, }) + "\n"); const resolved = resolveWebObserveActionJson({ stdout: JSON.stringify({ ok: true, data: { outputTruncated: true, reason: "stdout-json-bytes-exceeded-threshold", dump: { path: dumpPath }, }, }), stderr: "", exitCode: 0, timedOut: false, }, "status"); assert.equal(resolved.source, "dump"); assert.equal(resolved.parsed?.jobId, "webobs-fixture"); assert.equal(resolved.diagnostics.stdoutKind, "dump-wrapper"); assert.equal(resolved.diagnostics.dumpPath, dumpPath); }); test("web observe action JSON recovery reads SSH truncation summary dump for command contract", async () => { const dir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-command-dump-")); const dumpPath = join(dir, "command.json"); await writeFile(dumpPath, JSON.stringify({ ok: true, queued: false, waitTimedOut: false, commandId: "cmd-fixture", }) + "\n"); const summary = { code: "ssh-truncation-summary", stdout: { stream: "stdout", dumpPath, forwardedBytes: 10240, thresholdBytes: 10240, }, }; const resolved = resolveWebObserveActionJson({ stdout: `UNIDESK_SSH_TRUNCATION_SUMMARY ${JSON.stringify(summary)}\n`, stderr: "", exitCode: 0, timedOut: false, }, "command"); assert.equal(resolved.source, "dump"); assert.equal(resolved.parsed?.commandId, "cmd-fixture"); assert.equal(resolved.diagnostics.stdoutKind, "ssh-truncation-summary"); assert.equal(resolved.diagnostics.dumpPath, dumpPath); }); test("web observe action JSON recovery rejects ok-only action contract", () => { const resolved = resolveWebObserveActionJson({ stdout: JSON.stringify({ ok: true }), stderr: "", exitCode: 0, timedOut: false, }, "start"); assert.equal(resolved.parsed, null); assert.equal(resolved.source, null); assert.equal(resolved.diagnostics.stdoutKind, "json"); assert.equal(resolved.diagnostics.fallbackReason, "stdout-json-contract-invalid"); assert.equal(resolved.diagnostics.stdoutContractAccepted, false); });