@united-workforce/cli 0.7.0 → 0.8.1

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 (111) hide show
  1. package/README.md +32 -5
  2. package/dist/.build-fingerprint +1 -0
  3. package/dist/__tests__/broker-step-active-turns.test.d.ts +20 -0
  4. package/dist/__tests__/broker-step-active-turns.test.d.ts.map +1 -0
  5. package/dist/__tests__/broker-step-active-turns.test.js +428 -0
  6. package/dist/__tests__/broker-step-active-turns.test.js.map +1 -0
  7. package/dist/__tests__/broker-step-turn-chain-phase2.test.d.ts +13 -0
  8. package/dist/__tests__/broker-step-turn-chain-phase2.test.d.ts.map +1 -0
  9. package/dist/__tests__/broker-step-turn-chain-phase2.test.js +429 -0
  10. package/dist/__tests__/broker-step-turn-chain-phase2.test.js.map +1 -0
  11. package/dist/__tests__/e2e-broker-step-suspend.test.d.ts +18 -0
  12. package/dist/__tests__/e2e-broker-step-suspend.test.d.ts.map +1 -0
  13. package/dist/__tests__/e2e-broker-step-suspend.test.js +313 -0
  14. package/dist/__tests__/e2e-broker-step-suspend.test.js.map +1 -0
  15. package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.d.ts +28 -0
  16. package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.d.ts.map +1 -0
  17. package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.js +322 -0
  18. package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.js.map +1 -0
  19. package/dist/__tests__/log-tag-validity.test.d.ts +2 -0
  20. package/dist/__tests__/log-tag-validity.test.d.ts.map +1 -0
  21. package/dist/__tests__/log-tag-validity.test.js +110 -0
  22. package/dist/__tests__/log-tag-validity.test.js.map +1 -0
  23. package/dist/__tests__/setup-agent-discovery.test.js +23 -23
  24. package/dist/__tests__/setup-agent-discovery.test.js.map +1 -1
  25. package/dist/__tests__/step-show-json.test.js +5 -5
  26. package/dist/__tests__/step-show-json.test.js.map +1 -1
  27. package/dist/__tests__/step-show-text.test.d.ts +2 -0
  28. package/dist/__tests__/step-show-text.test.d.ts.map +1 -0
  29. package/dist/__tests__/step-show-text.test.js +192 -0
  30. package/dist/__tests__/step-show-text.test.js.map +1 -0
  31. package/dist/__tests__/step-turns-cli-subprocess.test.d.ts +21 -0
  32. package/dist/__tests__/step-turns-cli-subprocess.test.d.ts.map +1 -0
  33. package/dist/__tests__/step-turns-cli-subprocess.test.js +356 -0
  34. package/dist/__tests__/step-turns-cli-subprocess.test.js.map +1 -0
  35. package/dist/__tests__/step-turns-panorama-phase3.test.d.ts +21 -0
  36. package/dist/__tests__/step-turns-panorama-phase3.test.d.ts.map +1 -0
  37. package/dist/__tests__/step-turns-panorama-phase3.test.js +476 -0
  38. package/dist/__tests__/step-turns-panorama-phase3.test.js.map +1 -0
  39. package/dist/__tests__/step-turns.test.d.ts +24 -0
  40. package/dist/__tests__/step-turns.test.d.ts.map +1 -0
  41. package/dist/__tests__/step-turns.test.js +646 -0
  42. package/dist/__tests__/step-turns.test.js.map +1 -0
  43. package/dist/__tests__/store-turn-chain.test.d.ts +2 -0
  44. package/dist/__tests__/store-turn-chain.test.d.ts.map +1 -0
  45. package/dist/__tests__/store-turn-chain.test.js +341 -0
  46. package/dist/__tests__/store-turn-chain.test.js.map +1 -0
  47. package/dist/__tests__/thread-list-limit-offset.test.d.ts +24 -0
  48. package/dist/__tests__/thread-list-limit-offset.test.d.ts.map +1 -0
  49. package/dist/__tests__/thread-list-limit-offset.test.js +254 -0
  50. package/dist/__tests__/thread-list-limit-offset.test.js.map +1 -0
  51. package/dist/__tests__/thread-list-template-ms-date.test.js +7 -2
  52. package/dist/__tests__/thread-list-template-ms-date.test.js.map +1 -1
  53. package/dist/__tests__/thread.test.js +28 -14
  54. package/dist/__tests__/thread.test.js.map +1 -1
  55. package/dist/cli.js +910 -344
  56. package/dist/cli.js.map +1 -1
  57. package/dist/commands/broker-step.d.ts +10 -3
  58. package/dist/commands/broker-step.d.ts.map +1 -1
  59. package/dist/commands/broker-step.js +231 -27
  60. package/dist/commands/broker-step.js.map +1 -1
  61. package/dist/commands/prompt.d.ts.map +1 -1
  62. package/dist/commands/prompt.js +42 -50
  63. package/dist/commands/prompt.js.map +1 -1
  64. package/dist/commands/setup.d.ts +6 -4
  65. package/dist/commands/setup.d.ts.map +1 -1
  66. package/dist/commands/setup.js +16 -26
  67. package/dist/commands/setup.js.map +1 -1
  68. package/dist/commands/step.d.ts +48 -1
  69. package/dist/commands/step.d.ts.map +1 -1
  70. package/dist/commands/step.js +496 -3
  71. package/dist/commands/step.js.map +1 -1
  72. package/dist/output-mappers.d.ts +8 -0
  73. package/dist/output-mappers.d.ts.map +1 -1
  74. package/dist/output-mappers.js +72 -18
  75. package/dist/output-mappers.js.map +1 -1
  76. package/dist/schemas.d.ts +3 -0
  77. package/dist/schemas.d.ts.map +1 -1
  78. package/dist/schemas.js +17 -3
  79. package/dist/schemas.js.map +1 -1
  80. package/dist/store.d.ts +147 -1
  81. package/dist/store.d.ts.map +1 -1
  82. package/dist/store.js +254 -1
  83. package/dist/store.js.map +1 -1
  84. package/dist/text-renderers.d.ts.map +1 -1
  85. package/dist/text-renderers.js +27 -2
  86. package/dist/text-renderers.js.map +1 -1
  87. package/package.json +7 -6
  88. package/src/__tests__/broker-step-active-turns.test.ts +509 -0
  89. package/src/__tests__/broker-step-turn-chain-phase2.test.ts +525 -0
  90. package/src/__tests__/e2e-broker-step-suspend.test.ts +351 -0
  91. package/src/__tests__/e2e-thread-resume-timeout-suspend.test.ts +360 -0
  92. package/src/__tests__/log-tag-validity.test.ts +124 -0
  93. package/src/__tests__/setup-agent-discovery.test.ts +23 -23
  94. package/src/__tests__/step-show-json.test.ts +5 -5
  95. package/src/__tests__/step-show-text.test.ts +236 -0
  96. package/src/__tests__/step-turns-cli-subprocess.test.ts +411 -0
  97. package/src/__tests__/step-turns-panorama-phase3.test.ts +579 -0
  98. package/src/__tests__/step-turns.test.ts +734 -0
  99. package/src/__tests__/store-turn-chain.test.ts +386 -0
  100. package/src/__tests__/thread-list-limit-offset.test.ts +305 -0
  101. package/src/__tests__/thread-list-template-ms-date.test.ts +7 -2
  102. package/src/__tests__/thread.test.ts +29 -15
  103. package/src/cli.ts +1056 -483
  104. package/src/commands/broker-step.ts +315 -38
  105. package/src/commands/prompt.ts +42 -50
  106. package/src/commands/setup.ts +16 -28
  107. package/src/commands/step.ts +655 -3
  108. package/src/output-mappers.ts +99 -21
  109. package/src/schemas.ts +32 -2
  110. package/src/store.ts +297 -2
  111. package/src/text-renderers.ts +35 -2
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Spec 4 (issue #435, Phase 2) — verification contract for the RFC #95 loop
3
+ * `timeout → suspend (checkpoint) → resume`.
4
+ *
5
+ * This is verification-only: NO resume code changed in Phase 2. The test proves
6
+ * the *existing* `uwf thread resume` path already satisfies the timeout-suspend
7
+ * resume contract by wiring the spec-3 producer to the resume consumer:
8
+ *
9
+ * 1. Drive a real sumeru send-timeout through `executeBrokerStep` (the SSE
10
+ * stream ends in `suspend`, exactly as Spec 3 verifies) so the thread's
11
+ * head step is a genuine `$status: "$SUSPEND"` node and the `(threadId,
12
+ * role)` broker session is mapped to the sumeru session.
13
+ * 2. Seed the thread to `suspended` (mirroring what `finalizeAgentStep` does
14
+ * after a suspended broker step) and assert `cmdThreadShow` reports
15
+ * `suspended` with the timeout reason — a valid resume precondition.
16
+ * 3. Call `cmdThreadResume`. Assert it is accepted, issues a FRESH
17
+ * `broker.send()` for the suspended role on the SAME mapped session (so the
18
+ * sumeru adapter resumes by `nativeId` rather than starting over), delivers
19
+ * the `-p` supplement as the continuation prompt, and — when that resumed
20
+ * send now completes (`kind:"completed"`) — advances the thread out of
21
+ * `suspended` (here straight to `end`).
22
+ *
23
+ * The second send is a `done` stream, so the gate opens and the thread proceeds;
24
+ * if it had timed out again it would simply re-arm `suspended` (Spec 3 path),
25
+ * never an error.
26
+ */
27
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
28
+ import { tmpdir } from "node:os";
29
+ import { join } from "node:path";
30
+ import { putSchema } from "@ocas/core";
31
+ import { createProcessLogger } from "@united-workforce/util";
32
+ import { getConfigPath } from "@united-workforce/util-agent";
33
+ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
34
+ import { executeBrokerStep, openBrokerSessionStore } from "../commands/broker-step.js";
35
+ import { cmdThreadResume, cmdThreadShow } from "../commands/thread.js";
36
+ import { createUwfStore } from "../store.js";
37
+ import { seedThreads } from "./thread-test-helpers.js";
38
+ function sseFrame(id, event, data) {
39
+ return `id: ${id}\nevent: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
40
+ }
41
+ function buildSseResponse(frames) {
42
+ const encoder = new TextEncoder();
43
+ const stream = new ReadableStream({
44
+ start(controller) {
45
+ for (const frame of frames)
46
+ controller.enqueue(encoder.encode(frame));
47
+ controller.close();
48
+ },
49
+ });
50
+ return new Response(stream, {
51
+ status: 200,
52
+ headers: { "Content-Type": "text/event-stream; charset=utf-8" },
53
+ });
54
+ }
55
+ function buildJsonResponse(status, body) {
56
+ return new Response(JSON.stringify(body), {
57
+ status,
58
+ headers: { "Content-Type": "application/json" },
59
+ });
60
+ }
61
+ const PLANNER_OUTPUT_SCHEMA = {
62
+ title: "planner-output",
63
+ type: "object",
64
+ required: ["$status", "plan"],
65
+ properties: {
66
+ $status: { type: "string", enum: ["done", "failed"] },
67
+ plan: { type: "string" },
68
+ },
69
+ additionalProperties: false,
70
+ };
71
+ const PLANNER_RAW_OUTPUT = `---
72
+ $status: done
73
+ plan: ship it
74
+ ---
75
+ the plan body`;
76
+ const HOST = "http://127.0.0.1:7900";
77
+ const GATEWAY = "planner-gw";
78
+ const ALIAS = "planner-agent";
79
+ const SESSION_ID = "ses_resume_e2e";
80
+ const THREAD_ID = "06FCBROKERRESUMESTEP0001";
81
+ const ROLE = "planner";
82
+ const NATIVE_ID = "ses_native_abc";
83
+ const ELAPSED_MS = 1800000;
84
+ const WORKFLOW_NAME = "broker-resume-e2e";
85
+ const SUPPLEMENT = "继续上次未完成的任务";
86
+ function buildConfig() {
87
+ return {
88
+ agents: { [ALIAS]: { host: HOST, gateway: GATEWAY } },
89
+ defaultAgent: ALIAS,
90
+ agentOverrides: null,
91
+ };
92
+ }
93
+ /**
94
+ * Write the on-disk `config.yaml` that `cmdThreadResume` reloads via
95
+ * `loadWorkflowConfig`. Must use the Phase-3 `{host, gateway}` shape (the
96
+ * normalizer rejects the legacy `{command}` form).
97
+ */
98
+ async function writeConfig(storageRoot) {
99
+ const yaml = `defaultAgent: ${ALIAS}\nagentOverrides: null\nagents:\n ${ALIAS}:\n host: ${HOST}\n gateway: ${GATEWAY}\n`;
100
+ await writeFile(getConfigPath(storageRoot), yaml, "utf8");
101
+ }
102
+ async function buildWorkflow(uwf) {
103
+ const frontmatterHash = (await putSchema(uwf.store, PLANNER_OUTPUT_SCHEMA));
104
+ const workflow = {
105
+ version: 1,
106
+ name: WORKFLOW_NAME,
107
+ description: "broker step resume end-to-end",
108
+ roles: {
109
+ planner: {
110
+ description: "plans things",
111
+ goal: "produce a plan",
112
+ capabilities: [],
113
+ procedure: "think hard",
114
+ output: "frontmatter+body",
115
+ frontmatter: frontmatterHash,
116
+ },
117
+ },
118
+ graph: {
119
+ planner: {
120
+ // Non-empty $END prompt: the resumed `done` stream routes through the
121
+ // post-step moderator, which rejects an empty edge template.
122
+ done: { role: "$END", prompt: "done", location: null },
123
+ },
124
+ },
125
+ };
126
+ const startHash = (await uwf.store.cas.put(uwf.schemas.startNode, {
127
+ workflow: await uwf.store.cas.put(uwf.schemas.workflow, workflow),
128
+ prompt: "p",
129
+ cwd: "/tmp/work",
130
+ }));
131
+ return { workflow, startHash };
132
+ }
133
+ function suspendStream() {
134
+ return buildSseResponse([
135
+ sseFrame(1, "turn", {
136
+ type: "@sumeru/turn",
137
+ value: { index: 0, role: "user", content: "edge prompt", timestamp: "", toolCalls: null },
138
+ }),
139
+ sseFrame(2, "turn", {
140
+ type: "@sumeru/turn",
141
+ value: { index: 1, role: "assistant", content: "draft1", timestamp: "", toolCalls: null },
142
+ }),
143
+ sseFrame(3, "suspend", {
144
+ type: "@sumeru/suspend",
145
+ value: { reason: "timeout", nativeId: NATIVE_ID, elapsedMs: ELAPSED_MS },
146
+ }),
147
+ ]);
148
+ }
149
+ function completedStream() {
150
+ return buildSseResponse([
151
+ sseFrame(1, "turn", {
152
+ type: "@sumeru/turn",
153
+ value: {
154
+ index: 1,
155
+ role: "assistant",
156
+ content: PLANNER_RAW_OUTPUT,
157
+ timestamp: "",
158
+ toolCalls: null,
159
+ },
160
+ }),
161
+ sseFrame(2, "done", {
162
+ type: "@sumeru/summary",
163
+ value: { turnCount: 2, tokens: { in: 9, out: 4 }, durationMs: 42 },
164
+ }),
165
+ ]);
166
+ }
167
+ function resolveFetchUrl(input) {
168
+ if (typeof input === "string")
169
+ return input;
170
+ if (input instanceof URL)
171
+ return input.href;
172
+ return input.url;
173
+ }
174
+ function makePlog(tmpDir) {
175
+ return createProcessLogger({
176
+ storageRoot: tmpDir,
177
+ context: { thread: THREAD_ID, workflow: WORKFLOW_NAME },
178
+ });
179
+ }
180
+ describe("uwf thread resume — timeout-suspended thread resumes via fresh send (issue #435)", () => {
181
+ let tmpDir;
182
+ let savedOcasHome;
183
+ let calls;
184
+ // First send (the step that suspends) → suspend stream; every send after the
185
+ // first (the resume) → completed stream. A counter, not a swap, so the resume
186
+ // genuinely re-enters the same stub.
187
+ let messageCallCount;
188
+ beforeEach(async () => {
189
+ savedOcasHome = process.env.OCAS_HOME;
190
+ tmpDir = await mkdtemp(join(tmpdir(), "broker-resume-e2e-"));
191
+ process.env.OCAS_HOME = join(tmpDir, "cas");
192
+ calls = [];
193
+ messageCallCount = 0;
194
+ vi.stubGlobal("fetch", async (input, init) => {
195
+ const url = resolveFetchUrl(input);
196
+ const method = init?.method ?? "GET";
197
+ const body = typeof init?.body === "string" ? init.body : "";
198
+ calls.push({ url, method, body });
199
+ if (url.endsWith(`/gateways/${GATEWAY}/sessions`)) {
200
+ return buildJsonResponse(201, {
201
+ type: "@sumeru/session",
202
+ value: { id: SESSION_ID, gateway: GATEWAY },
203
+ });
204
+ }
205
+ if (url.endsWith(`/sessions/${SESSION_ID}/messages`)) {
206
+ messageCallCount += 1;
207
+ return messageCallCount === 1 ? suspendStream() : completedStream();
208
+ }
209
+ return buildJsonResponse(500, { error: "unexpected url", url });
210
+ });
211
+ });
212
+ afterEach(async () => {
213
+ vi.unstubAllGlobals();
214
+ if (savedOcasHome === undefined)
215
+ delete process.env.OCAS_HOME;
216
+ else
217
+ process.env.OCAS_HOME = savedOcasHome;
218
+ await rm(tmpDir, { recursive: true, force: true });
219
+ });
220
+ /**
221
+ * Drive a real send-timeout through `executeBrokerStep`, then seed the thread
222
+ * to `suspended` at the produced `$SUSPEND` step (mirroring `finalizeAgentStep`
223
+ * after a suspended broker step). Returns the suspend step hash and reason.
224
+ */
225
+ async function suspendThread(uwf, workflow, startHash) {
226
+ const result = await executeBrokerStep({
227
+ storageRoot: tmpDir,
228
+ uwf,
229
+ config: buildConfig(),
230
+ workflow,
231
+ threadId: THREAD_ID,
232
+ role: ROLE,
233
+ edgePrompt: "make a plan",
234
+ effectiveCwd: "/tmp/work",
235
+ startHash,
236
+ prevHash: null,
237
+ agentOverride: null,
238
+ previousAttempts: null,
239
+ plog: makePlog(tmpDir),
240
+ });
241
+ const reason = result.frontmatter.reason;
242
+ await seedThreads(tmpDir, {
243
+ [THREAD_ID]: {
244
+ head: result.stepHash,
245
+ status: "suspended",
246
+ suspendedRole: ROLE,
247
+ suspendMessage: reason,
248
+ completedAt: null,
249
+ },
250
+ });
251
+ return { suspendHash: result.stepHash, reason };
252
+ }
253
+ test("a timeout-suspended thread is shown as suspended, then resume advances it past the gate", async () => {
254
+ const uwf = await createUwfStore(tmpDir);
255
+ const { workflow, startHash } = await buildWorkflow(uwf);
256
+ await writeConfig(tmpDir);
257
+ const { suspendHash, reason } = await suspendThread(uwf, workflow, startHash);
258
+ // Precondition: the thread sits in `suspended` carrying the timeout reason.
259
+ const show = await cmdThreadShow(tmpDir, THREAD_ID);
260
+ expect(show.status).toBe("suspended");
261
+ expect(show.suspendedRole).toBe(ROLE);
262
+ expect(show.suspendMessage).toBe(reason);
263
+ expect(show.suspendMessage).toContain(NATIVE_ID);
264
+ // Resume is accepted and the resumed send completes, so the thread leaves
265
+ // `suspended` and advances (here straight to `end` via the `done` edge).
266
+ const resumeOut = await cmdThreadResume(tmpDir, THREAD_ID, SUPPLEMENT, null);
267
+ expect(resumeOut.status).toBe("end");
268
+ expect(resumeOut.done).toBe(true);
269
+ expect(resumeOut.error).toBeNull();
270
+ expect(resumeOut.head).not.toBe(suspendHash);
271
+ // And `thread show` agrees the gate is gone.
272
+ const showAfter = await cmdThreadShow(tmpDir, THREAD_ID);
273
+ expect(showAfter.status).toBe("end");
274
+ expect(showAfter.suspendedRole).toBeNull();
275
+ expect(showAfter.suspendMessage).toBeNull();
276
+ });
277
+ test("resume issues a FRESH send reusing the SAME mapped session (no new createSession)", async () => {
278
+ const uwf = await createUwfStore(tmpDir);
279
+ const { workflow, startHash } = await buildWorkflow(uwf);
280
+ await writeConfig(tmpDir);
281
+ await suspendThread(uwf, workflow, startHash);
282
+ await cmdThreadResume(tmpDir, THREAD_ID, SUPPLEMENT, null);
283
+ // Exactly ONE createSession (during the suspend) — resume reuses the cached
284
+ // (threadId, role) → sessionId mapping rather than spawning a new session.
285
+ const createCalls = calls.filter((c) => c.url.endsWith(`/gateways/${GATEWAY}/sessions`));
286
+ expect(createCalls).toHaveLength(1);
287
+ // TWO sends, both addressed to the SAME session id: the suspended send and
288
+ // the resume continuation. The sumeru adapter resumes by nativeId off this
289
+ // shared session.
290
+ const messageCalls = calls.filter((c) => c.url.endsWith("/messages"));
291
+ expect(messageCalls).toHaveLength(2);
292
+ for (const call of messageCalls) {
293
+ expect(call.url).toContain(`/sessions/${SESSION_ID}/messages`);
294
+ }
295
+ // The broker session row still points at the same session for a future resume.
296
+ const sessionStore = openBrokerSessionStore(tmpDir);
297
+ try {
298
+ const row = sessionStore.getSession(THREAD_ID, ROLE);
299
+ expect(row?.sessionId).toBe(SESSION_ID);
300
+ expect(row?.host).toBe(HOST);
301
+ expect(row?.gateway).toBe(GATEWAY);
302
+ }
303
+ finally {
304
+ sessionStore.close();
305
+ }
306
+ });
307
+ test("the -p supplement is delivered as the continuation prompt on the resume send", async () => {
308
+ const uwf = await createUwfStore(tmpDir);
309
+ const { workflow, startHash } = await buildWorkflow(uwf);
310
+ await writeConfig(tmpDir);
311
+ await suspendThread(uwf, workflow, startHash);
312
+ await cmdThreadResume(tmpDir, THREAD_ID, SUPPLEMENT, null);
313
+ const messageCalls = calls.filter((c) => c.url.endsWith("/messages"));
314
+ const resumeSend = messageCalls[1];
315
+ expect(resumeSend).toBeDefined();
316
+ // The resume prompt = suspend reason + the operator supplement; both ride
317
+ // the assembled prompt body of the continuation send.
318
+ expect(resumeSend?.body).toContain(SUPPLEMENT);
319
+ expect(resumeSend?.body).toContain(NATIVE_ID);
320
+ });
321
+ });
322
+ //# sourceMappingURL=e2e-thread-resume-timeout-suspend.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-thread-resume-timeout-suspend.test.js","sourceRoot":"","sources":["../../src/__tests__/e2e-thread-resume-timeout-suspend.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=log-tag-validity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-tag-validity.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/log-tag-validity.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,110 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { describe, expect, test } from "vitest";
4
+ /**
5
+ * Static regression guard for log tags (#426).
6
+ *
7
+ * Every `log()` call site uses a hand-written 8-char Crockford Base32 tag.
8
+ * Crockford Base32 excludes I, L, O, U to avoid visual ambiguity, and
9
+ * `assertValidLogTag()` (util/process-logger/log-tag.ts) throws at runtime
10
+ * when a tag contains an illegal character.
11
+ *
12
+ * The bug: `PL_FRONTMATTER_FAIL = "F4FA1L7Z"` (a leet spelling of
13
+ * "FRONTMATTER FAIL") smuggled an `L` into the tag. It only fires on the
14
+ * frontmatter-extraction-failure path, so it stayed dormant until a planner
15
+ * step failed extraction — then the failure logger itself crashed the process,
16
+ * masking the real error.
17
+ *
18
+ * This test scans the source of the cli + broker packages and asserts that
19
+ * EVERY literal tag — whether written inline as `log("XXXXXXXX", ...)` or as a
20
+ * `const PL_* = "XXXXXXXX"` constant — is a valid Crockford Base32 tag. A new
21
+ * illegal tag, in any file, fails here at build time instead of at runtime.
22
+ */
23
+ // Crockford Base32 alphabet — no I, L, O, U (mirrors util/src/base32.ts).
24
+ const CROCKFORD_BASE32_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
25
+ const TAG_CHAR_SET = new Set(CROCKFORD_BASE32_ALPHABET.split(""));
26
+ const TAG_LENGTH = 8;
27
+ function isValidLogTag(tag) {
28
+ if (tag.length !== TAG_LENGTH) {
29
+ return false;
30
+ }
31
+ for (const ch of tag) {
32
+ if (!TAG_CHAR_SET.has(ch.toUpperCase())) {
33
+ return false;
34
+ }
35
+ }
36
+ return true;
37
+ }
38
+ // Roots scanned for log-tag literals, relative to this test file.
39
+ const SCAN_ROOTS = [
40
+ join(__dirname, ".."), // packages/cli/src
41
+ join(__dirname, "..", "..", "..", "broker", "src"), // packages/broker/src
42
+ ];
43
+ async function collectTsFiles(dir) {
44
+ const out = [];
45
+ let names;
46
+ try {
47
+ names = await readdir(dir);
48
+ }
49
+ catch {
50
+ return out;
51
+ }
52
+ for (const name of names) {
53
+ if (name === "node_modules" || name === "dist") {
54
+ continue;
55
+ }
56
+ const full = join(dir, name);
57
+ const info = await stat(full);
58
+ if (info.isDirectory()) {
59
+ out.push(...(await collectTsFiles(full)));
60
+ }
61
+ else if (info.isFile() && name.endsWith(".ts") && !name.endsWith(".test.ts")) {
62
+ out.push(full);
63
+ }
64
+ }
65
+ return out;
66
+ }
67
+ // Matches `log("XXXXXXXX"` call sites and `... = "XXXXXXXX"` tag constants.
68
+ // The capturing group grabs an 8-char alphanumeric literal; isValidLogTag then
69
+ // decides legality. We intentionally over-collect (any 8-char string assigned
70
+ // to a PL_/TAG const or passed as log()'s first arg) and validate each.
71
+ const LOG_CALL_RE = /\blog\(\s*"([0-9A-Za-z]{8})"/g;
72
+ const TAG_CONST_RE = /\bconst\s+(?:PL_[A-Z0-9_]+|[A-Z0-9_]*TAG[A-Z0-9_]*)\s*=\s*"([0-9A-Za-z]{8})"/g;
73
+ async function collectTagOccurrences() {
74
+ const occurrences = [];
75
+ for (const root of SCAN_ROOTS) {
76
+ const files = await collectTsFiles(root);
77
+ for (const file of files) {
78
+ const content = await readFile(file, "utf8");
79
+ for (const re of [LOG_CALL_RE, TAG_CONST_RE]) {
80
+ re.lastIndex = 0;
81
+ let m = re.exec(content);
82
+ while (m !== null) {
83
+ occurrences.push({ tag: m[1], file, context: m[0] });
84
+ m = re.exec(content);
85
+ }
86
+ }
87
+ }
88
+ }
89
+ return occurrences;
90
+ }
91
+ describe("log tag validity (#426 regression guard)", () => {
92
+ test("collects at least the known PL_ tag constants", async () => {
93
+ const occurrences = await collectTagOccurrences();
94
+ // Sanity: the scan must actually find tags, otherwise the regex/paths broke
95
+ // and the guard below would pass vacuously.
96
+ expect(occurrences.length).toBeGreaterThanOrEqual(10);
97
+ });
98
+ test("every log tag literal in cli + broker is valid Crockford Base32", async () => {
99
+ const occurrences = await collectTagOccurrences();
100
+ const invalid = occurrences.filter((o) => !isValidLogTag(o.tag));
101
+ const report = invalid.map((o) => ` ${o.tag} (${o.context}) in ${o.file}`).join("\n");
102
+ expect(invalid, `Illegal Crockford Base32 log tags found:\n${report}`).toEqual([]);
103
+ });
104
+ test("the specific F4FA1L7Z bug (#426) stays fixed", async () => {
105
+ const occurrences = await collectTagOccurrences();
106
+ const offenders = occurrences.filter((o) => o.tag === "F4FA1L7Z");
107
+ expect(offenders).toEqual([]);
108
+ });
109
+ });
110
+ //# sourceMappingURL=log-tag-validity.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-tag-validity.test.js","sourceRoot":"","sources":["../../src/__tests__/log-tag-validity.test.ts"],"names":[],"mappings":"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"}
@@ -8,16 +8,16 @@ import { _agentNameFromBinary, _printAgentMenu, cmdSetup } from "../commands/set
8
8
  // ─── _agentNameFromBinary ────────────────────────────────────────────────────
9
9
  describe("_agentNameFromBinary", () => {
10
10
  test("strips uwf- prefix", () => {
11
- expect(_agentNameFromBinary("uwf-hermes")).toBe("hermes");
11
+ expect(_agentNameFromBinary("uwf-builtin")).toBe("builtin");
12
12
  });
13
13
  test("strips uwf- prefix for compound names", () => {
14
- expect(_agentNameFromBinary("uwf-claude-code")).toBe("claude-code");
14
+ expect(_agentNameFromBinary("uwf-some-gateway")).toBe("some-gateway");
15
15
  });
16
16
  test("returns as-is when no uwf- prefix", () => {
17
- expect(_agentNameFromBinary("hermes")).toBe("hermes");
17
+ expect(_agentNameFromBinary("builtin")).toBe("builtin");
18
18
  });
19
- test("handles uwf-builtin", () => {
20
- expect(_agentNameFromBinary("uwf-builtin")).toBe("builtin");
19
+ test("handles uwf-mock", () => {
20
+ expect(_agentNameFromBinary("uwf-mock")).toBe("mock");
21
21
  });
22
22
  });
23
23
  // ─── _printAgentMenu ─────────────────────────────────────────────────────────
@@ -27,9 +27,9 @@ describe("_printAgentMenu", () => {
27
27
  vi.spyOn(console, "log").mockImplementation((...args) => {
28
28
  logs.push(args.join(" "));
29
29
  });
30
- _printAgentMenu(["uwf-hermes", "uwf-claude-code"]);
31
- expect(logs.some((l) => l.includes("Hermes"))).toBe(true);
32
- expect(logs.some((l) => l.includes("Claude Code"))).toBe(true);
30
+ _printAgentMenu(["uwf-builtin", "uwf-mock"]);
31
+ expect(logs.some((l) => l.includes("Built-in"))).toBe(true);
32
+ expect(logs.some((l) => l.includes("Mock"))).toBe(true);
33
33
  vi.restoreAllMocks();
34
34
  });
35
35
  test("prints unknown agents with binary name as label", () => {
@@ -63,32 +63,32 @@ describe("cmdSetup agent configuration (engine config is LLM-free, issue #143)",
63
63
  expect(config.defaultAgent).toBe("claude-code");
64
64
  });
65
65
  test("preserves existing agents when adding new one", async () => {
66
- await cmdSetup({ agent: "hermes", storageRoot });
66
+ await cmdSetup({ agent: "builtin", storageRoot });
67
67
  await cmdSetup({ agent: "claude-code", storageRoot });
68
68
  const config = parse(readFileSync(join(storageRoot, "config.yaml"), "utf8"));
69
- expect(config.agents.hermes).toBeDefined();
69
+ expect(config.agents.builtin).toBeDefined();
70
70
  expect(config.agents["claude-code"]).toBeDefined();
71
71
  expect(config.defaultAgent).toBe("claude-code");
72
72
  });
73
73
  test("updates defaultAgent on re-run with different agent", async () => {
74
- await cmdSetup({ agent: "hermes", storageRoot });
74
+ await cmdSetup({ agent: "mock", storageRoot });
75
75
  const config1 = parse(readFileSync(join(storageRoot, "config.yaml"), "utf8"));
76
- expect(config1.defaultAgent).toBe("hermes");
76
+ expect(config1.defaultAgent).toBe("mock");
77
77
  await cmdSetup({ agent: "builtin", storageRoot });
78
78
  const config2 = parse(readFileSync(join(storageRoot, "config.yaml"), "utf8"));
79
79
  expect(config2.defaultAgent).toBe("builtin");
80
80
  });
81
81
  test("normalizes agent name with uwf- prefix to bare name", async () => {
82
- const result = await cmdSetup({ agent: "uwf-hermes", storageRoot });
83
- expect(result.defaultAgent).toBe("hermes");
82
+ const result = await cmdSetup({ agent: "uwf-builtin", storageRoot });
83
+ expect(result.defaultAgent).toBe("builtin");
84
84
  const config = parse(readFileSync(join(storageRoot, "config.yaml"), "utf8"));
85
- expect(config.agents.hermes).toEqual({
85
+ expect(config.agents.builtin).toEqual({
86
86
  host: "http://127.0.0.1:7900",
87
- gateway: "hermes",
87
+ gateway: "builtin",
88
88
  });
89
- expect(config.defaultAgent).toBe("hermes");
89
+ expect(config.defaultAgent).toBe("builtin");
90
90
  // Verify no duplicate uwf- prefix
91
- expect(config.agents["uwf-hermes"]).toBeUndefined();
91
+ expect(config.agents["uwf-builtin"]).toBeUndefined();
92
92
  });
93
93
  test("normalizes uwf-claude-code to claude-code", async () => {
94
94
  const result = await cmdSetup({ agent: "uwf-claude-code", storageRoot });
@@ -106,17 +106,17 @@ describe("cmdSetup agent configuration (engine config is LLM-free, issue #143)",
106
106
  // First create a config that contains legacy LLM fields
107
107
  const { writeFileSync, mkdirSync } = await import("node:fs");
108
108
  mkdirSync(storageRoot, { recursive: true });
109
- writeFileSync(join(storageRoot, "config.yaml"), "providers:\n openai: { baseUrl: x, apiKey: y }\nmodels:\n default: { provider: openai, name: gpt-4o }\ndefaultModel: default\nagents:\n hermes: { host: 'http://127.0.0.1:7900', gateway: hermes }\ndefaultAgent: hermes\n", "utf8");
110
- await cmdSetup({ agent: "hermes", storageRoot });
109
+ writeFileSync(join(storageRoot, "config.yaml"), "providers:\n openai: { baseUrl: x, apiKey: y }\nmodels:\n default: { provider: openai, name: gpt-4o }\ndefaultModel: default\nagents:\n builtin: { host: 'http://127.0.0.1:7900', gateway: builtin }\ndefaultAgent: builtin\n", "utf8");
110
+ await cmdSetup({ agent: "builtin", storageRoot });
111
111
  const config = parse(readFileSync(join(storageRoot, "config.yaml"), "utf8"));
112
112
  expect(config.providers).toBeUndefined();
113
113
  expect(config.models).toBeUndefined();
114
114
  expect(config.defaultModel).toBeUndefined();
115
- expect(config.agents.hermes).toEqual({
115
+ expect(config.agents.builtin).toEqual({
116
116
  host: "http://127.0.0.1:7900",
117
- gateway: "hermes",
117
+ gateway: "builtin",
118
118
  });
119
- expect(config.defaultAgent).toBe("hermes");
119
+ expect(config.defaultAgent).toBe("builtin");
120
120
  });
121
121
  });
122
122
  //# sourceMappingURL=setup-agent-discovery.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup-agent-discovery.test.js","sourceRoot":"","sources":["../../src/__tests__/setup-agent-discovery.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup-agent-discovery.test.js","sourceRoot":"","sources":["../../src/__tests__/setup-agent-discovery.test.ts"],"names":[],"mappings":"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"}
@@ -133,7 +133,7 @@ describe("cmdStepShow JSON serialization", () => {
133
133
  expect(() => JSON.parse(jsonOutput)).not.toThrow();
134
134
  expect(jsonOutput).toContain("\\n");
135
135
  const parsed = JSON.parse(jsonOutput);
136
- expect(parsed.turns[0].toolCalls[0].args).toContain("\n");
136
+ expect(parsed.detail.turns[0].toolCalls[0].args).toContain("\n");
137
137
  });
138
138
  test("escapes tabs in tool call args", async () => {
139
139
  const setup = await setupTest(casDir);
@@ -194,7 +194,7 @@ describe("cmdStepShow JSON serialization", () => {
194
194
  const jsonOutput = formatOutput(result, "json");
195
195
  expect(() => JSON.parse(jsonOutput)).not.toThrow();
196
196
  const parsed = JSON.parse(jsonOutput);
197
- expect(parsed.turns).toBeDefined();
197
+ expect(parsed.detail.turns).toBeDefined();
198
198
  });
199
199
  test("handles Unicode control characters", async () => {
200
200
  const setup = await setupTest(casDir);
@@ -240,7 +240,7 @@ describe("cmdStepShow JSON serialization", () => {
240
240
  const jsonOutput = formatOutput(result, "json");
241
241
  expect(() => JSON.parse(jsonOutput)).not.toThrow();
242
242
  const parsed = JSON.parse(jsonOutput);
243
- expect(parsed.turns).toHaveLength(2);
243
+ expect(parsed.detail.turns).toHaveLength(2);
244
244
  });
245
245
  test("YAML output format is unaffected", async () => {
246
246
  const setup = await setupTest(casDir);
@@ -276,7 +276,7 @@ describe("cmdStepShow JSON serialization", () => {
276
276
  const jsonOutput = formatOutput(result, "json");
277
277
  expect(() => JSON.parse(jsonOutput)).not.toThrow();
278
278
  const parsed = JSON.parse(jsonOutput);
279
- expect(parsed.turns).toBeDefined();
279
+ expect(parsed.detail.turns).toBeDefined();
280
280
  });
281
281
  test("handles large step with multiple tool calls", async () => {
282
282
  const setup = await setupTest(casDir);
@@ -306,7 +306,7 @@ describe("cmdStepShow JSON serialization", () => {
306
306
  expect(duration).toBeLessThan(2000);
307
307
  expect(() => JSON.parse(jsonOutput)).not.toThrow();
308
308
  const parsed = JSON.parse(jsonOutput);
309
- expect(parsed.turns).toHaveLength(25);
309
+ expect(parsed.detail.turns).toHaveLength(25);
310
310
  });
311
311
  });
312
312
  //# sourceMappingURL=step-show-json.test.js.map