@sensigo/realm-cli 0.38.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/agent/drive-failure.d.ts +62 -0
  2. package/dist/agent/drive-failure.d.ts.map +1 -0
  3. package/dist/agent/drive-failure.js +241 -0
  4. package/dist/agent/drive-failure.js.map +1 -0
  5. package/dist/agent/providers/agent-utils.d.ts +132 -0
  6. package/dist/agent/providers/agent-utils.d.ts.map +1 -1
  7. package/dist/agent/providers/agent-utils.js +348 -1
  8. package/dist/agent/providers/agent-utils.js.map +1 -1
  9. package/dist/agent/providers/anthropic-provider.d.ts +51 -1
  10. package/dist/agent/providers/anthropic-provider.d.ts.map +1 -1
  11. package/dist/agent/providers/anthropic-provider.js +109 -30
  12. package/dist/agent/providers/anthropic-provider.js.map +1 -1
  13. package/dist/agent/providers/llm-provider.d.ts +13 -1
  14. package/dist/agent/providers/llm-provider.d.ts.map +1 -1
  15. package/dist/agent/providers/llm-provider.js +8 -4
  16. package/dist/agent/providers/llm-provider.js.map +1 -1
  17. package/dist/agent/providers/openai-provider.d.ts +6 -1
  18. package/dist/agent/providers/openai-provider.d.ts.map +1 -1
  19. package/dist/agent/providers/openai-provider.js +75 -20
  20. package/dist/agent/providers/openai-provider.js.map +1 -1
  21. package/dist/agent/providers/openai-reasoning-provider.d.ts +4 -1
  22. package/dist/agent/providers/openai-reasoning-provider.d.ts.map +1 -1
  23. package/dist/agent/providers/openai-reasoning-provider.js +21 -6
  24. package/dist/agent/providers/openai-reasoning-provider.js.map +1 -1
  25. package/dist/agent/run-agent.d.ts +9 -0
  26. package/dist/agent/run-agent.d.ts.map +1 -1
  27. package/dist/agent/run-agent.js +775 -680
  28. package/dist/agent/run-agent.js.map +1 -1
  29. package/dist/agent/run-attach.d.ts.map +1 -1
  30. package/dist/agent/run-attach.js +58 -11
  31. package/dist/agent/run-attach.js.map +1 -1
  32. package/dist/agent/test-support/anthropic-stub.d.ts +45 -0
  33. package/dist/agent/test-support/anthropic-stub.d.ts.map +1 -0
  34. package/dist/agent/test-support/anthropic-stub.js +146 -0
  35. package/dist/agent/test-support/anthropic-stub.js.map +1 -0
  36. package/dist/agent/test-support/composed-journey.d.ts +40 -0
  37. package/dist/agent/test-support/composed-journey.d.ts.map +1 -0
  38. package/dist/agent/test-support/composed-journey.js +104 -0
  39. package/dist/agent/test-support/composed-journey.js.map +1 -0
  40. package/dist/agent/test-support/mcp-server-entry.d.ts +20 -0
  41. package/dist/agent/test-support/mcp-server-entry.d.ts.map +1 -0
  42. package/dist/agent/test-support/mcp-server-entry.js +39 -0
  43. package/dist/agent/test-support/mcp-server-entry.js.map +1 -0
  44. package/dist/agent/test-support/openai-stub.d.ts +47 -0
  45. package/dist/agent/test-support/openai-stub.d.ts.map +1 -0
  46. package/dist/agent/test-support/openai-stub.js +115 -0
  47. package/dist/agent/test-support/openai-stub.js.map +1 -0
  48. package/dist/commands/abandon.d.ts.map +1 -1
  49. package/dist/commands/abandon.js +8 -1
  50. package/dist/commands/abandon.js.map +1 -1
  51. package/dist/commands/agent.d.ts.map +1 -1
  52. package/dist/commands/agent.js +17 -0
  53. package/dist/commands/agent.js.map +1 -1
  54. package/dist/commands/cleanup.d.ts.map +1 -1
  55. package/dist/commands/cleanup.js +21 -9
  56. package/dist/commands/cleanup.js.map +1 -1
  57. package/dist/commands/export.d.ts +5 -2
  58. package/dist/commands/export.d.ts.map +1 -1
  59. package/dist/commands/export.js +1 -1
  60. package/dist/commands/export.js.map +1 -1
  61. package/dist/commands/gc.d.ts +1 -1
  62. package/dist/commands/gc.d.ts.map +1 -1
  63. package/dist/commands/gc.js +29 -4
  64. package/dist/commands/gc.js.map +1 -1
  65. package/dist/commands/inspect.d.ts.map +1 -1
  66. package/dist/commands/inspect.js +86 -1
  67. package/dist/commands/inspect.js.map +1 -1
  68. package/dist/commands/list.d.ts.map +1 -1
  69. package/dist/commands/list.js +35 -0
  70. package/dist/commands/list.js.map +1 -1
  71. package/dist/commands/listen.d.ts.map +1 -1
  72. package/dist/commands/listen.js +9 -5
  73. package/dist/commands/listen.js.map +1 -1
  74. package/dist/commands/purge.d.ts +22 -1
  75. package/dist/commands/purge.d.ts.map +1 -1
  76. package/dist/commands/purge.js +70 -42
  77. package/dist/commands/purge.js.map +1 -1
  78. package/dist/commands/register.d.ts.map +1 -1
  79. package/dist/commands/register.js +3 -1
  80. package/dist/commands/register.js.map +1 -1
  81. package/dist/commands/run-migrate.d.ts +83 -0
  82. package/dist/commands/run-migrate.d.ts.map +1 -0
  83. package/dist/commands/run-migrate.js +303 -0
  84. package/dist/commands/run-migrate.js.map +1 -0
  85. package/dist/commands/validate.d.ts.map +1 -1
  86. package/dist/commands/validate.js +7 -5
  87. package/dist/commands/validate.js.map +1 -1
  88. package/dist/commands/watch.d.ts.map +1 -1
  89. package/dist/commands/watch.js +6 -4
  90. package/dist/commands/watch.js.map +1 -1
  91. package/dist/commands-registry.d.ts.map +1 -1
  92. package/dist/commands-registry.js +4 -0
  93. package/dist/commands-registry.js.map +1 -1
  94. package/dist/index.js +1 -1
  95. package/dist/lib/loader-warnings.d.ts +22 -1
  96. package/dist/lib/loader-warnings.d.ts.map +1 -1
  97. package/dist/lib/loader-warnings.js +42 -2
  98. package/dist/lib/loader-warnings.js.map +1 -1
  99. package/package.json +5 -4
@@ -0,0 +1,104 @@
1
+ // composed-journey.ts — the provider-INDEPENDENT body of the composed journey (issue #398).
2
+ //
3
+ // The journey is: a real agent step calls a real tool on a REAL MCP stdio child (realm's own
4
+ // server), the tool fails politely with `isError: true`, and the failure has to survive the
5
+ // provider's mint, the store, and the render all the way to what an operator sees. Everything in
6
+ // that sentence except the model's answer is shipped code.
7
+ //
8
+ // WHY FACTORED. Each provider needs its own journey — the two mints are structural twins and a
9
+ // cell on one proves nothing about the other — but only the PROVIDER SEAM differs. Duplicating a
10
+ // hundred lines per provider is how the two copies drift into testing different things, which is
11
+ // the failure this whole harness exists to prevent one level down.
12
+ //
13
+ // NO ASSERTIONS LIVE HERE. This returns the artifacts; the cells assert. That keeps every
14
+ // expectation vitest-side and visible in the file a reader opens when a journey fails, and it is
15
+ // why this file imports nothing from vitest — it compiles into the published dist (`files:
16
+ // ["dist"]`), unreachable via the exports map, exactly like the sibling stub helpers.
17
+ //
18
+ // REDACTION HAZARD, INHERITED BY EVERY CALLER. `sanitizeError` (agent-utils.ts) redacts every
19
+ // `process.env` value longer than four characters as a SUBSTRING, from tool results and from
20
+ // errors alike. A cell that sets an API key for this journey must choose a value that collides
21
+ // with no text it later asserts on — otherwise the assertion reads `[REDACTED]` and the failure
22
+ // looks like a product bug. Both shipped cells use distinctive `sk-…-composed-journey-0000`
23
+ // values for this reason.
24
+ import { mkdtempSync, mkdirSync } from 'node:fs';
25
+ import { tmpdir } from 'node:os';
26
+ import { join } from 'node:path';
27
+ import { JsonFileStore, JsonWorkflowStore, ExtensionRegistry } from '@sensigo/realm';
28
+ import { runAgent } from '../run-agent.js';
29
+ import { inspectRun } from '../../commands/inspect.js';
30
+ import { resolveMcpServerEntry } from './mcp-server-entry.js';
31
+ /**
32
+ * Creates an isolated HOME for one journey run.
33
+ *
34
+ * ONE temp home for BOTH store surfaces, and this is load-bearing rather than tidy: the MCP child
35
+ * inherits HOME and creates `$HOME/.realm/workflows` at STARTUP, before any tool call. Pointing
36
+ * only the parent at a temp directory leaves the child writing into the real `~/.realm` — and a
37
+ * real workflow that happened to share the probe id would turn the tool's polite failure into a
38
+ * success, so the journey would go green having proved nothing.
39
+ */
40
+ export function makeJourneyHome(prefix) {
41
+ const home = mkdtempSync(join(tmpdir(), prefix));
42
+ mkdirSync(join(home, '.realm'), { recursive: true });
43
+ return home;
44
+ }
45
+ /**
46
+ * Runs the journey and returns its artifacts, read back from the REAL store rather than from
47
+ * return values.
48
+ */
49
+ export async function runComposedJourney(tempHome, options) {
50
+ const definition = {
51
+ id: 'composed-journey-wf',
52
+ name: 'Composed Journey',
53
+ version: 1,
54
+ schema_version: 1,
55
+ mcp_servers: [
56
+ {
57
+ id: 'realm',
58
+ transport: 'stdio',
59
+ command: process.execPath,
60
+ args: [resolveMcpServerEntry()],
61
+ // MERGED over the inherited environment by the SDK, so PATH survives and `node` still
62
+ // resolves — this redirects HOME without isolating the child from everything else.
63
+ env: { HOME: tempHome },
64
+ },
65
+ ],
66
+ steps: {
67
+ ask: {
68
+ description: 'Ask realm about a workflow that does not exist',
69
+ execution: 'agent',
70
+ depends_on: [],
71
+ tools: ['realm:get_workflow_protocol'],
72
+ // Present so the scripted final answer has something to validate against: a mismatch
73
+ // engages the #217 repair loop and the journey's first assertion then fails for a reason
74
+ // unrelated to the chain under test.
75
+ input_schema: {
76
+ type: 'object',
77
+ properties: { summary: { type: 'string' } },
78
+ required: ['summary'],
79
+ },
80
+ },
81
+ },
82
+ };
83
+ const store = new JsonFileStore(join(tempHome, '.realm', 'runs'));
84
+ const workflowStore = new JsonWorkflowStore(join(tempHome, '.realm', 'workflows'));
85
+ await workflowStore.register(definition);
86
+ const result = await runAgent({
87
+ store,
88
+ workflowStore,
89
+ provider: options.provider,
90
+ registry: new ExtensionRegistry(),
91
+ }, { definition, params: {}, pollIntervalMs: 50 });
92
+ const runs = await store.list();
93
+ const runId = runs[0]?.id ?? '';
94
+ const run = await store.get(runId);
95
+ return {
96
+ result,
97
+ runCount: runs.length,
98
+ run,
99
+ toolCalls: run.evidence.flatMap((snap) => snap.tool_calls ?? []),
100
+ inspectOutput: await inspectRun(runId, store, workflowStore),
101
+ inspectVerboseOutput: await inspectRun(runId, store, workflowStore, { verbose: true }),
102
+ };
103
+ }
104
+ //# sourceMappingURL=composed-journey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composed-journey.js","sourceRoot":"","sources":["../../../src/agent/test-support/composed-journey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The built server entry.
3
+ *
4
+ * FOUR `..`: test-support → agent → src → cli → packages. A file one directory shallower needs
5
+ * THREE, so this is exactly the constant that gets miscounted when copied between them — hence
6
+ * the depth pin in this module's tests, which catches the off-by-one while the dist IS built (the
7
+ * symptom otherwise is a confident "not built" message about a path that was never right).
8
+ */
9
+ export declare const DEFAULT_MCP_SERVER_ENTRY: string;
10
+ /** The message a caller sees when the dist is missing — exported so a test can pin it. */
11
+ export declare const MCP_SERVER_DIST_ABSENT = "mcp-server dist not built \u2014 run `npm run build` first (turbo guarantees it for `npm test`; running this file directly after a clean checkout does not)";
12
+ /**
13
+ * Returns the server entry path, or throws a message that names the actual problem.
14
+ *
15
+ * The candidate is an argument rather than an injectable module-level override, so the check runs
16
+ * at CALL time: a journey cell calls this at module scope and gets the same whole-file failure it
17
+ * would have got from a bad constant, but with a sentence explaining it.
18
+ */
19
+ export declare function resolveMcpServerEntry(candidate?: string): string;
20
+ //# sourceMappingURL=mcp-server-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server-entry.d.ts","sourceRoot":"","sources":["../../../src/agent/test-support/mcp-server-entry.ts"],"names":[],"mappings":"AAeA;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,QAEpC,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,sBAAsB,gKACuH,CAAC;AAE3J;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,GAAE,MAAiC,GAAG,MAAM,CAK1F"}
@@ -0,0 +1,39 @@
1
+ // mcp-server-entry.ts — resolves the path to realm's own MCP server entry point for journey tests
2
+ // that spawn it as a real child process.
3
+ //
4
+ // WHY THIS IS NOT JUST A CONSTANT. The path is only valid once mcp-server has been built, and the
5
+ // build is guaranteed by the task graph rather than by anything in this file: `test` dependsOn
6
+ // `build`, `build` dependsOn `^build`, and cli depends on `@sensigo/realm-mcp` — so `npm test`
7
+ // always has the dist. Running a journey file DIRECTLY after a clean checkout does not, and
8
+ // without this check the failure is an ENOENT from `child_process.spawn` several layers down,
9
+ // which reads like a broken test rather than a missing build step.
10
+ //
11
+ // It resolves from THIS FILE rather than the working directory, because vitest's cwd is not
12
+ // something a test should depend on.
13
+ import { existsSync } from 'node:fs';
14
+ import { fileURLToPath } from 'node:url';
15
+ /**
16
+ * The built server entry.
17
+ *
18
+ * FOUR `..`: test-support → agent → src → cli → packages. A file one directory shallower needs
19
+ * THREE, so this is exactly the constant that gets miscounted when copied between them — hence
20
+ * the depth pin in this module's tests, which catches the off-by-one while the dist IS built (the
21
+ * symptom otherwise is a confident "not built" message about a path that was never right).
22
+ */
23
+ export const DEFAULT_MCP_SERVER_ENTRY = fileURLToPath(new URL('../../../../mcp-server/dist/server.js', import.meta.url));
24
+ /** The message a caller sees when the dist is missing — exported so a test can pin it. */
25
+ export const MCP_SERVER_DIST_ABSENT = 'mcp-server dist not built — run `npm run build` first (turbo guarantees it for `npm test`; running this file directly after a clean checkout does not)';
26
+ /**
27
+ * Returns the server entry path, or throws a message that names the actual problem.
28
+ *
29
+ * The candidate is an argument rather than an injectable module-level override, so the check runs
30
+ * at CALL time: a journey cell calls this at module scope and gets the same whole-file failure it
31
+ * would have got from a bad constant, but with a sentence explaining it.
32
+ */
33
+ export function resolveMcpServerEntry(candidate = DEFAULT_MCP_SERVER_ENTRY) {
34
+ if (!existsSync(candidate)) {
35
+ throw new Error(`${MCP_SERVER_DIST_ABSENT} (looked for: ${candidate})`);
36
+ }
37
+ return candidate;
38
+ }
39
+ //# sourceMappingURL=mcp-server-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server-entry.js","sourceRoot":"","sources":["../../../src/agent/test-support/mcp-server-entry.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,yCAAyC;AACzC,EAAE;AACF,kGAAkG;AAClG,+FAA+F;AAC/F,+FAA+F;AAC/F,4FAA4F;AAC5F,8FAA8F;AAC9F,mEAAmE;AACnE,EAAE;AACF,4FAA4F;AAC5F,qCAAqC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,aAAa,CACnD,IAAI,GAAG,CAAC,uCAAuC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAClE,CAAC;AAEF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,sBAAsB,GACjC,wJAAwJ,CAAC;AAE3J;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,YAAoB,wBAAwB;IAChF,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,GAAG,sBAAsB,iBAAiB,SAAS,GAAG,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,47 @@
1
+ /** One scripted tool call: which tool to name, and the arguments to script for it. */
2
+ export interface StubToolCall {
3
+ /** Matched against the bare tool names the request advertises. */
4
+ match: RegExp;
5
+ /** Scripted arguments — JSON-encoded into `function.arguments` for the SDK. */
6
+ arguments: Record<string, unknown>;
7
+ }
8
+ export interface StubOptions {
9
+ firstToolCall: StubToolCall;
10
+ /**
11
+ * The assistant's final answer, returned on every turn after the tool result comes back.
12
+ * MUST validate against the driven step's `input_schema` — a mismatch engages the #217 schema
13
+ * repair loop, and the journey's own assertions then fail for a reason unrelated to the chain
14
+ * under test.
15
+ */
16
+ finalContent: Record<string, unknown>;
17
+ }
18
+ export interface OpenAiStub {
19
+ /** Pass to `new OpenAIProvider(model, baseUrl)`. */
20
+ baseUrl: string;
21
+ /** Every request body the provider sent, parsed. Assert against this to pin what went over the wire. */
22
+ requests: ChatCompletionRequest[];
23
+ close: () => Promise<void>;
24
+ }
25
+ interface ChatCompletionRequest {
26
+ model?: string;
27
+ messages?: Array<{
28
+ role?: string;
29
+ content?: unknown;
30
+ tool_calls?: unknown;
31
+ }>;
32
+ tools?: Array<{
33
+ type?: string;
34
+ function?: {
35
+ name?: string;
36
+ description?: string;
37
+ };
38
+ }>;
39
+ [key: string]: unknown;
40
+ }
41
+ /**
42
+ * Starts the stub on an ephemeral port. Always `close()` it in a `finally` — a leaked listener
43
+ * keeps the vitest worker alive past the test.
44
+ */
45
+ export declare function startOpenAiStub(options: StubOptions): Promise<OpenAiStub>;
46
+ export {};
47
+ //# sourceMappingURL=openai-stub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-stub.d.ts","sourceRoot":"","sources":["../../../src/agent/test-support/openai-stub.ts"],"names":[],"mappings":"AAgCA,sFAAsF;AACtF,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,YAAY,CAAC;IAC5B;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,wGAAwG;IACxG,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,UAAU,qBAAqB;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC7E,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IACrF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA0E/E"}
@@ -0,0 +1,115 @@
1
+ // openai-stub.ts — an in-process HTTP server speaking just enough of the chat-completions dialect
2
+ // to drive the REAL `OpenAIProvider` through a scripted tool call.
3
+ //
4
+ // WHY THIS EXISTS. A journey test that mocks the provider proves the test's own mocks work. This
5
+ // stub sits at the WIRE instead, so everything above it — the provider's request building, its
6
+ // tool-call parsing, the tool loop, the ToolCallRecord mint — is the shipped code running for
7
+ // real. The only thing faked is the model's answer, which is the one part that cannot be run.
8
+ //
9
+ // WHY IN-PROCESS AND NOT A CHILD. Flake hygiene. A journey cell like this is exactly the class
10
+ // issue #371 tracks, so it gets one child process in total (the MCP server, which must be a child
11
+ // to be real) and nothing else. An ephemeral port means no collisions under parallel runs.
12
+ //
13
+ // THE WIRE SHAPES BELOW ARE EXECUTED FACTS, not guesses — each one was verified against the
14
+ // installed openai SDK, and each has a failure mode that is confusing rather than obvious:
15
+ // - Content-Type MUST be application/json. Without it the SDK hands the provider the body as a
16
+ // raw string, `choices` is undefined, and the provider dies with a TypeError nowhere near the
17
+ // cause.
18
+ // - `function.arguments` MUST be a JSON-ENCODED STRING. The provider `JSON.parse`s it outside
19
+ // its try block, so an object there throws and fails the step.
20
+ // - the echoed tool name MUST be the BARE advertised name, read back from the request's own
21
+ // `tools` array. run-agent advertises the bare name; the namespaced `server:tool` id never
22
+ // reaches the wire, so hardcoding the namespaced form fails for a reason that looks like a
23
+ // product bug.
24
+ // REDACTION HAZARD, INHERITED BY EVERY CALLER. `sanitizeError` (agent-utils.ts) redacts every
25
+ // `process.env` value longer than four characters as a SUBSTRING, from tool results and from
26
+ // errors alike. A cell that sets an API key for this journey must choose a value colliding with no
27
+ // text it later asserts on — otherwise the assertion reads `[REDACTED]` and the failure looks like
28
+ // a product bug rather than a test's own environment choice. The shipped cell uses
29
+ // `sk-test-composed-journey-0000` for exactly this reason.
30
+ import { createServer } from 'node:http';
31
+ /**
32
+ * Starts the stub on an ephemeral port. Always `close()` it in a `finally` — a leaked listener
33
+ * keeps the vitest worker alive past the test.
34
+ */
35
+ export async function startOpenAiStub(options) {
36
+ const requests = [];
37
+ const server = createServer((req, res) => {
38
+ let raw = '';
39
+ req.on('data', (chunk) => {
40
+ raw += chunk.toString();
41
+ });
42
+ req.on('end', () => {
43
+ let body = {};
44
+ try {
45
+ body = JSON.parse(raw || '{}');
46
+ }
47
+ catch {
48
+ // A malformed body is the test's problem, not the stub's — record it as empty and let the
49
+ // assertions on `requests` show what actually arrived.
50
+ }
51
+ requests.push(body);
52
+ // Turn 1 is the one with no tool result in it yet. Keyed on the conversation's own contents
53
+ // rather than a call counter, so a retry or a repair iteration cannot desynchronise the
54
+ // script from what the provider actually asked for.
55
+ const alreadyToolAnswered = (body.messages ?? []).some((m) => m.role === 'tool');
56
+ const payload = alreadyToolAnswered
57
+ ? {
58
+ choices: [
59
+ { message: { role: 'assistant', content: JSON.stringify(options.finalContent) } },
60
+ ],
61
+ }
62
+ : {
63
+ choices: [
64
+ {
65
+ message: {
66
+ role: 'assistant',
67
+ content: null,
68
+ tool_calls: [
69
+ {
70
+ id: 'call_1',
71
+ type: 'function',
72
+ function: {
73
+ name: pickToolName(body, options.firstToolCall.match),
74
+ // JSON-encoded STRING, not an object — see the header.
75
+ arguments: JSON.stringify(options.firstToolCall.arguments),
76
+ },
77
+ },
78
+ ],
79
+ },
80
+ },
81
+ ],
82
+ };
83
+ const text = JSON.stringify(payload);
84
+ res.writeHead(200, {
85
+ // Load-bearing — see the header.
86
+ 'Content-Type': 'application/json',
87
+ 'Content-Length': String(Buffer.byteLength(text)),
88
+ });
89
+ res.end(text);
90
+ });
91
+ });
92
+ await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
93
+ const { port } = server.address();
94
+ return {
95
+ baseUrl: `http://127.0.0.1:${String(port)}/v1`,
96
+ requests,
97
+ close: () => new Promise((resolve) => {
98
+ server.close(() => {
99
+ resolve();
100
+ });
101
+ }),
102
+ };
103
+ }
104
+ /**
105
+ * Reads the tool name back out of the request the provider actually sent, so the stub can never
106
+ * name a tool the provider did not advertise. Falls back to the pattern's source only when nothing
107
+ * matched — which makes the resulting failure name the mismatch instead of hiding it.
108
+ */
109
+ function pickToolName(body, match) {
110
+ const advertised = (body.tools ?? [])
111
+ .map((t) => t.function?.name)
112
+ .filter((n) => typeof n === 'string');
113
+ return advertised.find((n) => match.test(n)) ?? `NO_ADVERTISED_TOOL_MATCHING_${match.source}`;
114
+ }
115
+ //# sourceMappingURL=openai-stub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-stub.js","sourceRoot":"","sources":["../../../src/agent/test-support/openai-stub.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"abandon.d.ts","sourceRoot":"","sources":["../../src/commands/abandon.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,eAAO,MAAM,cAAc,SAoBvB,CAAC"}
1
+ {"version":3,"file":"abandon.d.ts","sourceRoot":"","sources":["../../src/commands/abandon.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,eAAO,MAAM,cAAc,SA2BvB,CAAC"}
@@ -8,8 +8,15 @@ export const abandonCommand = new Command('abandon')
8
8
  const { JsonFileStore, abandonRun } = await import('@sensigo/realm');
9
9
  const runStore = new JsonFileStore();
10
10
  try {
11
+ // issue #367: read first, so the output can say whether THIS call changed anything —
12
+ // abandoning an already-abandoned run is an idempotent no-op and used to print exactly the
13
+ // same line as a real kill.
14
+ const before = await runStore.get(runId);
15
+ const alreadyAbandoned = before.abandoned_at !== undefined;
11
16
  const run = await abandonRun(runStore, runId, opts.reason);
12
- console.log(`Run '${runId}' abandoned (phase: '${run.run_phase}'). Reason: ${run.terminal_reason}.\n` +
17
+ console.log(`Run '${runId}' abandoned (phase: '${run.run_phase}').` +
18
+ (alreadyAbandoned ? ' Already abandoned (no change this call).' : '') +
19
+ ` Reason: ${run.terminal_reason}.\n` +
13
20
  `To re-run the same idempotency key, use start_run with on_terminal_match: 'rerun' (default 'reuse' returns this abandoned run).\n` +
14
21
  // issue #222 — the documented/advised abandon contract: unconditional, same wording as
15
22
  // the abandon_run MCP tool's `note` field (abandon-run.ts).
@@ -1 +1 @@
1
- {"version":3,"file":"abandon.js","sourceRoot":"","sources":["../../src/commands/abandon.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,uEAAuE,CAAC;KACpF,QAAQ,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAChD,MAAM,CAAC,iBAAiB,EAAE,mDAAmD,CAAC;KAC9E,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAyB,EAAE,EAAE;IACzD,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CACT,QAAQ,KAAK,wBAAwB,GAAG,CAAC,SAAS,eAAe,GAAG,CAAC,eAAe,KAAK;YACvF,mIAAmI;YACnI,uFAAuF;YACvF,4DAA4D;YAC5D,6FAA6F,CAChG,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"abandon.js","sourceRoot":"","sources":["../../src/commands/abandon.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,uEAAuE,CAAC;KACpF,QAAQ,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAChD,MAAM,CAAC,iBAAiB,EAAE,mDAAmD,CAAC;KAC9E,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAyB,EAAE,EAAE;IACzD,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,qFAAqF;QACrF,2FAA2F;QAC3F,4BAA4B;QAC5B,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,gBAAgB,GAAG,MAAM,CAAC,YAAY,KAAK,SAAS,CAAC;QAC3D,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CACT,QAAQ,KAAK,wBAAwB,GAAG,CAAC,SAAS,KAAK;YACrD,CAAC,gBAAgB,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,YAAY,GAAG,CAAC,eAAe,KAAK;YACpC,mIAAmI;YACnI,uFAAuF;YACvF,4DAA4D;YAC5D,6FAA6F,CAChG,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;AAI1D,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,WAAW,EAAmB,MAAM,oCAAoC,CAAC;AAIlF,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,0CAA0C,CAAC;AAIlD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,uBAAuB,CAAC,WAAW,CAAC,EAC/C,IAAI,EAAE;IACJ,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B,GACA,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,gBAAgB,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAsB5F;AAiBD,eAAO,MAAM,YAAY,SAqPtB,CAAC"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;AAI1D,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,WAAW,EAAmB,MAAM,oCAAoC,CAAC;AAIlF,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,0CAA0C,CAAC;AAIlD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,uBAAuB,CAAC,WAAW,CAAC,EAC/C,IAAI,EAAE;IACJ,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B,GACA,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,gBAAgB,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAsB5F;AA8BD,eAAO,MAAM,YAAY,SAoQtB,CAAC"}
@@ -58,6 +58,18 @@ function parseSchemaRetries(value) {
58
58
  }
59
59
  return n;
60
60
  }
61
+ /**
62
+ * Commander argParser for `--llm-timeout` (issue #401). Same idiom and the same reasons as
63
+ * `parseSchemaRetries` above; the value is a PER-ATTEMPT ceiling in seconds, so zero is rejected
64
+ * along with the negatives — a zero-second budget would abort every request before it started.
65
+ */
66
+ function parseLlmTimeout(value) {
67
+ const n = Number(value);
68
+ if (!Number.isInteger(n) || n <= 0) {
69
+ throw new InvalidArgumentError('--llm-timeout must be a positive integer number of seconds.');
70
+ }
71
+ return n;
72
+ }
61
73
  export const agentCommand = new Command('agent')
62
74
  .description('Run a workflow autonomously using an LLM provider')
63
75
  .option('--workflow <path>', 'Path to workflow directory or workflow.yaml file')
@@ -78,6 +90,9 @@ export const agentCommand = new Command('agent')
78
90
  .option('--schema-retries <n>', "Number of in-drive repair attempts when an agent step's output is rejected by " +
79
91
  'output_schema/input_schema validation (issue #217) — the drive re-prompts the same step ' +
80
92
  "with the validator's errors appended. 0 disables (today's behavior).", parseSchemaRetries, 2)
93
+ .option('--llm-timeout <seconds>', 'Per-attempt ceiling for each model request, in seconds (issue #401). A step that authors ' +
94
+ "its own `llm_timeout_seconds` WINS; this fills in for every step that doesn't. Default " +
95
+ '600. When the ceiling fires the drive stops and records why, naming this lever.', parseLlmTimeout)
81
96
  .action(async (opts) => {
82
97
  if (!opts.workflow && !opts.runId) {
83
98
  console.error('Error: one of --workflow or --run-id is required');
@@ -171,6 +186,7 @@ export const agentCommand = new Command('agent')
171
186
  // issue #217: default 2, threaded exactly like mintWriterNonce above. Commander
172
187
  // always supplies a value (the option's own default), so this is never undefined.
173
188
  schemaRetries: opts.schemaRetries,
189
+ llmTimeoutSeconds: opts.llmTimeout,
174
190
  ...(gateHandler ? { gateHandler } : {}),
175
191
  ...(loaded.secretValues !== undefined
176
192
  ? { redactionValues: loaded.secretValues }
@@ -211,6 +227,7 @@ export const agentCommand = new Command('agent')
211
227
  // issue #217: default 2, threaded exactly like mintWriterNonce above. Commander
212
228
  // always supplies a value (the option's own default), so this is never undefined.
213
229
  schemaRetries: opts.schemaRetries,
230
+ llmTimeoutSeconds: opts.llmTimeout,
214
231
  ...(gateHandler ? { gateHandler } : {}),
215
232
  ...(loaded.secretValues !== undefined
216
233
  ? { redactionValues: loaded.secretValues }
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAI1D;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EAChD,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC;IAAE,QAAQ,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC,CAgCpC;AAED,eAAO,MAAM,cAAc,SAsBvB,CAAC"}
1
+ {"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAI1D;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EAChD,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC;IAAE,QAAQ,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC,CAuCpC;AAED,eAAO,MAAM,cAAc,SA+BvB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  // cleanup command — marks idle non-terminal runs as abandoned.
2
2
  import { Command } from 'commander';
3
- import { WAITING_PHASES } from '@sensigo/realm';
3
+ import { WAITING_PHASES, deriveRunPhase, sealRunLevel } from '@sensigo/realm';
4
4
  import { parseDuration } from '../lib/parse-duration.js';
5
5
  /**
6
6
  * List all non-terminal runs idle for longer than `olderThan` and mark them abandoned.
@@ -17,7 +17,15 @@ export async function cleanupRuns(options, runStore) {
17
17
  if (run.terminal_state) {
18
18
  continue;
19
19
  }
20
- if (WAITING_PHASES.has(run.run_phase)) {
20
+ // issue #367: DERIVE the phase, and check the gate directly. Keying the waiting-skip on the
21
+ // PERSISTED `run_phase` is the disposal-rule violation #282 exists to close — and it is not
22
+ // theoretical here: a record whose persisted phase is stale while a human is genuinely waiting
23
+ // on a live gate was being sealed `cleanup_sweep` with `pending_gate` still on the record, i.e.
24
+ // this command was freshly minting the very zombie shape #282 closed, and killing a run
25
+ // somebody was answering. The stale-phase population is exactly what `gc --heal` exists for,
26
+ // so cleanup-before-heal is an ordinary ordering. `abandonRun` already checks the gate; this
27
+ // brings its sweeping sibling in line.
28
+ if (run.pending_gate !== undefined || WAITING_PHASES.has(deriveRunPhase(run))) {
21
29
  continue;
22
30
  }
23
31
  const idleMs = now - new Date(run.updated_at).getTime();
@@ -27,13 +35,10 @@ export async function cleanupRuns(options, runStore) {
27
35
  }
28
36
  if (!(options.dryRun ?? false)) {
29
37
  for (const run of affected) {
30
- await runStore.update({
31
- ...run,
32
- abandoned_at: new Date().toISOString(),
33
- run_phase: 'abandoned',
34
- terminal_state: true,
35
- terminal_reason: 'Marked abandoned by realm cleanup',
36
- });
38
+ // issue #367: run-level seal through the ONE bypass-writer chokepoint — it stamps
39
+ // sealed_by {arm: 'cleanup_sweep'} alongside abandoned_at, and the fossil hand-written
40
+ // run_phase is retired (the store write tail derives it — the #282 class).
41
+ await runStore.update(sealRunLevel(run, 'cleanup_sweep', 'Marked abandoned by realm cleanup'));
37
42
  }
38
43
  }
39
44
  return { affected };
@@ -54,6 +59,13 @@ export const cleanupCommand = new Command('cleanup')
54
59
  else {
55
60
  console.log(`Marked ${n} run(s) as abandoned.`);
56
61
  }
62
+ // issue #367: name the runs, and say what abandoning them means. Both sibling surfaces ship
63
+ // this advisory unconditionally; the sweeping one printed a bare count, which is the harder
64
+ // case to check afterwards — an operator could not tell WHICH runs a sweep had killed.
65
+ for (const run of affected) {
66
+ console.log(` • ${run.id}`);
67
+ }
68
+ console.log(`abandon is a kill — declared finalizers (if any) did NOT run; 'abort' is the graceful path.`);
57
69
  }
58
70
  catch (err) {
59
71
  console.error(err instanceof Error ? err.message : String(err));
@@ -1 +1 @@
1
- {"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAgD,EAChD,QAAkB;IAElB,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAElC,MAAM,QAAQ,GAAgB,EAAE,CAAC;IACjC,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;YACvB,SAAS;QACX,CAAC;QACD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACtC,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;QACxD,IAAI,MAAM,IAAI,SAAS,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,EAAE,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,QAAQ,CAAC,MAAM,CAAC;gBACpB,GAAG,GAAG;gBACN,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACtC,SAAS,EAAE,WAAW;gBACtB,cAAc,EAAE,IAAI;gBACpB,eAAe,EAAE,mCAAmC;aACrD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,0CAA0C,CAAC;KACvD,cAAc,CACb,yBAAyB,EACzB,iEAAiE,CAClE;KACA,MAAM,CAAC,WAAW,EAAE,8DAA8D,CAAC;KACnF,MAAM,CAAC,KAAK,EAAE,IAA6C,EAAE,EAAE;IAC9D,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC1B,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"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"}
@@ -15,9 +15,12 @@ export interface ExportBundle {
15
15
  * v1 bundle's completeness is UNKNOWN to a reader — it was written back when export was
16
16
  * all-or-nothing (any read failure meant no bundle at all), so v1's mere existence was itself a
17
17
  * (weaker) completeness signal, but nothing in a v1 bundle states it explicitly. v2 always
18
- * states it explicitly via `complete`. Bumped 2 → 3 (issue #197 PR-2): adds `sealed`.
18
+ * states it explicitly via `complete`. Bumped 2 → 3 (issue #197 PR-2): adds `sealed`. Bumped
19
+ * 3 → 4 (issue #367): the run record now carries `sealed_by`, and its ABSENCE from a v3 bundle
20
+ * is three-way ambiguous — the run predates #367, or the exporter predates it, or the seal was
21
+ * genuinely never stamped. The version is what disambiguates.
19
22
  */
20
- realm_export_version: 3;
23
+ realm_export_version: 4;
21
24
  /** ISO-8601, stamped by the CLI at assembly time. */
22
25
  exported_at: string;
23
26
  /** The full RunRecord — steps, evidence, skip_details, claims, etc. */
@@ -1 +1 @@
1
- {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EACV,SAAS,EACT,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACf,MAAM,gBAAgB,CAAC;AASxB,6FAA6F;AAC7F,MAAM,WAAW,mBAAmB;IAClC;kGAC8F;IAC9F,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,oBAAoB,EAAE,CAAC,CAAC;IACxB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,GAAG,EAAE,SAAS,CAAC;IACf;;iDAE6C;IAC7C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC;;;qFAGiF;IACjF,eAAe,EAAE,OAAO,CAAC;IACzB;;;;8DAI0D;IAC1D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/B;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,GAAG,IAAI,CAAC;IAChD;;;;;;OAMG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,eAAe,EAAE,mBAAmB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,YAAY,CAAC;IACrB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAChC,kBAAkB,EAAE;QAClB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;YAAC,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KACnF,CAAC;IACF;;;;;;;;;OASG;IACH,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,eAAe,GAAG,kBAAkB,CAAC,CAAC;CAChF;AAiED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,YAAY,EACpB,GAAG,GAAE,IAAiB,GACrB,OAAO,CAAC,eAAe,CAAC,CA+F1B;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,MAAM,CAqCxE;AAQD,eAAO,MAAM,aAAa,SAkEtB,CAAC"}
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EACV,SAAS,EACT,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACf,MAAM,gBAAgB,CAAC;AASxB,6FAA6F;AAC7F,MAAM,WAAW,mBAAmB;IAClC;kGAC8F;IAC9F,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;OASG;IACH,oBAAoB,EAAE,CAAC,CAAC;IACxB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,GAAG,EAAE,SAAS,CAAC;IACf;;iDAE6C;IAC7C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC;;;qFAGiF;IACjF,eAAe,EAAE,OAAO,CAAC;IACzB;;;;8DAI0D;IAC1D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/B;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,GAAG,IAAI,CAAC;IAChD;;;;;;OAMG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,eAAe,EAAE,mBAAmB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,YAAY,CAAC;IACrB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAChC,kBAAkB,EAAE;QAClB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;YAAC,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KACnF,CAAC;IACF;;;;;;;;;OASG;IACH,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,eAAe,GAAG,kBAAkB,CAAC,CAAC;CAChF;AAiED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,YAAY,EACpB,GAAG,GAAE,IAAiB,GACrB,OAAO,CAAC,eAAe,CAAC,CA+F1B;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,MAAM,CAqCxE;AAQD,eAAO,MAAM,aAAa,SAkEtB,CAAC"}
@@ -154,7 +154,7 @@ export async function buildExportBundle(runId, stores, now = new Date()) {
154
154
  ? redactLiveClaimNonces(wal, sealed, run.in_progress_steps)
155
155
  : { wal, sealed };
156
156
  const bundle = {
157
- realm_export_version: 3,
157
+ realm_export_version: 4,
158
158
  exported_at: now.toISOString(),
159
159
  run,
160
160
  attempts,