@united-workforce/cli 0.4.0 → 0.6.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 (223) hide show
  1. package/README.md +30 -3
  2. package/dist/.build-fingerprint +1 -0
  3. package/dist/__tests__/adapter-json-roundtrip.test.js +16 -6
  4. package/dist/__tests__/adapter-json-roundtrip.test.js.map +1 -1
  5. package/dist/__tests__/concurrency.test.d.ts +2 -0
  6. package/dist/__tests__/concurrency.test.d.ts.map +1 -0
  7. package/dist/__tests__/concurrency.test.js +196 -0
  8. package/dist/__tests__/concurrency.test.js.map +1 -0
  9. package/dist/__tests__/config-text-renderer.test.d.ts +2 -0
  10. package/dist/__tests__/config-text-renderer.test.d.ts.map +1 -0
  11. package/dist/__tests__/config-text-renderer.test.js +137 -0
  12. package/dist/__tests__/config-text-renderer.test.js.map +1 -0
  13. package/dist/__tests__/e2e-mock-agent.test.js +23 -7
  14. package/dist/__tests__/e2e-mock-agent.test.js.map +1 -1
  15. package/dist/__tests__/format-text-default.test.d.ts +2 -0
  16. package/dist/__tests__/format-text-default.test.d.ts.map +1 -0
  17. package/dist/__tests__/format-text-default.test.js +43 -0
  18. package/dist/__tests__/format-text-default.test.js.map +1 -0
  19. package/dist/__tests__/format-text-registry.test.d.ts +2 -0
  20. package/dist/__tests__/format-text-registry.test.d.ts.map +1 -0
  21. package/dist/__tests__/format-text-registry.test.js +158 -0
  22. package/dist/__tests__/format-text-registry.test.js.map +1 -0
  23. package/dist/__tests__/issue-180-workflow-ref-removed.test.js +1 -1
  24. package/dist/__tests__/log-text-renderer.test.d.ts +2 -0
  25. package/dist/__tests__/log-text-renderer.test.d.ts.map +1 -0
  26. package/dist/__tests__/log-text-renderer.test.js +265 -0
  27. package/dist/__tests__/log-text-renderer.test.js.map +1 -0
  28. package/dist/__tests__/output-mapper-thread-list-startedat.test.d.ts +2 -0
  29. package/dist/__tests__/output-mapper-thread-list-startedat.test.d.ts.map +1 -0
  30. package/dist/__tests__/output-mapper-thread-list-startedat.test.js +102 -0
  31. package/dist/__tests__/output-mapper-thread-list-startedat.test.js.map +1 -0
  32. package/dist/__tests__/output-mapper-workflow-add.test.d.ts +2 -0
  33. package/dist/__tests__/output-mapper-workflow-add.test.d.ts.map +1 -0
  34. package/dist/__tests__/output-mapper-workflow-add.test.js +22 -0
  35. package/dist/__tests__/output-mapper-workflow-add.test.js.map +1 -0
  36. package/dist/__tests__/pid-recycling.test.js +9 -7
  37. package/dist/__tests__/pid-recycling.test.js.map +1 -1
  38. package/dist/__tests__/prompt.test.js +46 -4
  39. package/dist/__tests__/prompt.test.js.map +1 -1
  40. package/dist/__tests__/resolve-head-hash.test.js +8 -0
  41. package/dist/__tests__/resolve-head-hash.test.js.map +1 -1
  42. package/dist/__tests__/solve-issue-tea-worktree.test.js +3 -1
  43. package/dist/__tests__/solve-issue-tea-worktree.test.js.map +1 -1
  44. package/dist/__tests__/step-ask.test.js +9 -1
  45. package/dist/__tests__/step-ask.test.js.map +1 -1
  46. package/dist/__tests__/store-unified-threads.test.js +19 -17
  47. package/dist/__tests__/store-unified-threads.test.js.map +1 -1
  48. package/dist/__tests__/thread-agent-failure-suspended.test.d.ts +2 -0
  49. package/dist/__tests__/thread-agent-failure-suspended.test.d.ts.map +1 -0
  50. package/dist/__tests__/thread-agent-failure-suspended.test.js +332 -0
  51. package/dist/__tests__/thread-agent-failure-suspended.test.js.map +1 -0
  52. package/dist/__tests__/thread-cancel-status.test.js +19 -13
  53. package/dist/__tests__/thread-cancel-status.test.js.map +1 -1
  54. package/dist/__tests__/thread-cancel-text-renderer.test.d.ts +2 -0
  55. package/dist/__tests__/thread-cancel-text-renderer.test.d.ts.map +1 -0
  56. package/dist/__tests__/thread-cancel-text-renderer.test.js +110 -0
  57. package/dist/__tests__/thread-cancel-text-renderer.test.js.map +1 -0
  58. package/dist/__tests__/thread-join.test.d.ts +2 -0
  59. package/dist/__tests__/thread-join.test.d.ts.map +1 -0
  60. package/dist/__tests__/thread-join.test.js +77 -0
  61. package/dist/__tests__/thread-join.test.js.map +1 -0
  62. package/dist/__tests__/thread-list-filters.test.js +10 -8
  63. package/dist/__tests__/thread-list-filters.test.js.map +1 -1
  64. package/dist/__tests__/thread-list-template-ms-date.test.d.ts +2 -0
  65. package/dist/__tests__/thread-list-template-ms-date.test.d.ts.map +1 -0
  66. package/dist/__tests__/thread-list-template-ms-date.test.js +102 -0
  67. package/dist/__tests__/thread-list-template-ms-date.test.js.map +1 -0
  68. package/dist/__tests__/thread-list-workflow-corrupt.test.d.ts +2 -0
  69. package/dist/__tests__/thread-list-workflow-corrupt.test.d.ts.map +1 -0
  70. package/dist/__tests__/thread-list-workflow-corrupt.test.js +157 -0
  71. package/dist/__tests__/thread-list-workflow-corrupt.test.js.map +1 -0
  72. package/dist/__tests__/thread-poke.test.js +15 -2
  73. package/dist/__tests__/thread-poke.test.js.map +1 -1
  74. package/dist/__tests__/thread-read-xml-tags.test.js +10 -9
  75. package/dist/__tests__/thread-read-xml-tags.test.js.map +1 -1
  76. package/dist/__tests__/thread-resume.test.js +11 -1
  77. package/dist/__tests__/thread-resume.test.js.map +1 -1
  78. package/dist/__tests__/thread-start-cwd-cli.test.js +15 -3
  79. package/dist/__tests__/thread-start-cwd-cli.test.js.map +1 -1
  80. package/dist/__tests__/thread-stop-text-renderer.test.d.ts +2 -0
  81. package/dist/__tests__/thread-stop-text-renderer.test.d.ts.map +1 -0
  82. package/dist/__tests__/thread-stop-text-renderer.test.js +148 -0
  83. package/dist/__tests__/thread-stop-text-renderer.test.js.map +1 -0
  84. package/dist/__tests__/thread-suspend-step.test.js +5 -2
  85. package/dist/__tests__/thread-suspend-step.test.js.map +1 -1
  86. package/dist/__tests__/thread-test-helpers.d.ts +7 -0
  87. package/dist/__tests__/thread-test-helpers.d.ts.map +1 -1
  88. package/dist/__tests__/thread-test-helpers.js +13 -0
  89. package/dist/__tests__/thread-test-helpers.js.map +1 -1
  90. package/dist/__tests__/thread.test.js +11 -9
  91. package/dist/__tests__/thread.test.js.map +1 -1
  92. package/dist/__tests__/validate-semantic.test.js +56 -2
  93. package/dist/__tests__/validate-semantic.test.js.map +1 -1
  94. package/dist/__tests__/workflow-list-recursive.test.js +10 -7
  95. package/dist/__tests__/workflow-list-recursive.test.js.map +1 -1
  96. package/dist/__tests__/workflow-paths.test.d.ts +2 -0
  97. package/dist/__tests__/workflow-paths.test.d.ts.map +1 -0
  98. package/dist/__tests__/workflow-paths.test.js +261 -0
  99. package/dist/__tests__/workflow-paths.test.js.map +1 -0
  100. package/dist/__tests__/workflow-resolution.test.js +10 -7
  101. package/dist/__tests__/workflow-resolution.test.js.map +1 -1
  102. package/dist/__tests__/workflow-show-resolution.test.js +10 -7
  103. package/dist/__tests__/workflow-show-resolution.test.js.map +1 -1
  104. package/dist/__tests__/workflow-validate.test.js +75 -55
  105. package/dist/__tests__/workflow-validate.test.js.map +1 -1
  106. package/dist/__tests__/write-envelope.test.d.ts +2 -0
  107. package/dist/__tests__/write-envelope.test.d.ts.map +1 -0
  108. package/dist/__tests__/write-envelope.test.js +201 -0
  109. package/dist/__tests__/write-envelope.test.js.map +1 -0
  110. package/dist/cli.js +76 -36
  111. package/dist/cli.js.map +1 -1
  112. package/dist/commands/config.d.ts +5 -0
  113. package/dist/commands/config.d.ts.map +1 -1
  114. package/dist/commands/config.js +81 -3
  115. package/dist/commands/config.js.map +1 -1
  116. package/dist/commands/prompt.d.ts.map +1 -1
  117. package/dist/commands/prompt.js +42 -29
  118. package/dist/commands/prompt.js.map +1 -1
  119. package/dist/commands/setup.d.ts +9 -4
  120. package/dist/commands/setup.d.ts.map +1 -1
  121. package/dist/commands/setup.js +51 -7
  122. package/dist/commands/setup.js.map +1 -1
  123. package/dist/commands/thread.d.ts +12 -0
  124. package/dist/commands/thread.d.ts.map +1 -1
  125. package/dist/commands/thread.js +226 -9
  126. package/dist/commands/thread.js.map +1 -1
  127. package/dist/commands/workflow.d.ts +2 -2
  128. package/dist/commands/workflow.d.ts.map +1 -1
  129. package/dist/commands/workflow.js +26 -10
  130. package/dist/commands/workflow.js.map +1 -1
  131. package/dist/concurrency/concurrency.d.ts +34 -0
  132. package/dist/concurrency/concurrency.d.ts.map +1 -0
  133. package/dist/concurrency/concurrency.js +216 -0
  134. package/dist/concurrency/concurrency.js.map +1 -0
  135. package/dist/concurrency/index.d.ts +3 -0
  136. package/dist/concurrency/index.d.ts.map +1 -0
  137. package/dist/concurrency/index.js +2 -0
  138. package/dist/concurrency/index.js.map +1 -0
  139. package/dist/concurrency/types.d.ts +19 -0
  140. package/dist/concurrency/types.d.ts.map +1 -0
  141. package/dist/concurrency/types.js +2 -0
  142. package/dist/concurrency/types.js.map +1 -0
  143. package/dist/format.d.ts +69 -2
  144. package/dist/format.d.ts.map +1 -1
  145. package/dist/format.js +198 -1
  146. package/dist/format.js.map +1 -1
  147. package/dist/output-mappers.d.ts +122 -0
  148. package/dist/output-mappers.d.ts.map +1 -0
  149. package/dist/output-mappers.js +134 -0
  150. package/dist/output-mappers.js.map +1 -0
  151. package/dist/schemas.d.ts +4 -1
  152. package/dist/schemas.d.ts.map +1 -1
  153. package/dist/schemas.js +31 -4
  154. package/dist/schemas.js.map +1 -1
  155. package/dist/store.d.ts +11 -0
  156. package/dist/store.d.ts.map +1 -1
  157. package/dist/store.js +20 -1
  158. package/dist/store.js.map +1 -1
  159. package/dist/text-renderers.d.ts +30 -0
  160. package/dist/text-renderers.d.ts.map +1 -0
  161. package/dist/text-renderers.js +251 -0
  162. package/dist/text-renderers.js.map +1 -0
  163. package/dist/validate-semantic.d.ts.map +1 -1
  164. package/dist/validate-semantic.js +28 -11
  165. package/dist/validate-semantic.js.map +1 -1
  166. package/examples/brainstorm.yaml +130 -0
  167. package/examples/debate.yaml +169 -0
  168. package/examples/socratic-questioning.yaml +112 -0
  169. package/package.json +12 -11
  170. package/src/__tests__/adapter-json-roundtrip.test.ts +15 -6
  171. package/src/__tests__/concurrency.test.ts +266 -0
  172. package/src/__tests__/config-text-renderer.test.ts +156 -0
  173. package/src/__tests__/e2e-mock-agent.test.ts +45 -7
  174. package/src/__tests__/format-text-default.test.ts +49 -0
  175. package/src/__tests__/format-text-registry.test.ts +173 -0
  176. package/src/__tests__/issue-180-workflow-ref-removed.test.ts +1 -1
  177. package/src/__tests__/log-text-renderer.test.ts +294 -0
  178. package/src/__tests__/output-mapper-thread-list-startedat.test.ts +124 -0
  179. package/src/__tests__/output-mapper-workflow-add.test.ts +24 -0
  180. package/src/__tests__/pid-recycling.test.ts +9 -8
  181. package/src/__tests__/prompt.test.ts +48 -4
  182. package/src/__tests__/resolve-head-hash.test.ts +7 -0
  183. package/src/__tests__/solve-issue-tea-worktree.test.ts +3 -1
  184. package/src/__tests__/step-ask.test.ts +8 -1
  185. package/src/__tests__/store-unified-threads.test.ts +21 -18
  186. package/src/__tests__/thread-agent-failure-suspended.test.ts +406 -0
  187. package/src/__tests__/thread-cancel-status.test.ts +21 -14
  188. package/src/__tests__/thread-cancel-text-renderer.test.ts +125 -0
  189. package/src/__tests__/thread-join.test.ts +103 -0
  190. package/src/__tests__/thread-list-filters.test.ts +9 -9
  191. package/src/__tests__/thread-list-template-ms-date.test.ts +110 -0
  192. package/src/__tests__/thread-list-workflow-corrupt.test.ts +198 -0
  193. package/src/__tests__/thread-poke.test.ts +14 -2
  194. package/src/__tests__/thread-read-xml-tags.test.ts +9 -11
  195. package/src/__tests__/thread-resume.test.ts +10 -1
  196. package/src/__tests__/thread-start-cwd-cli.test.ts +15 -3
  197. package/src/__tests__/thread-stop-text-renderer.test.ts +168 -0
  198. package/src/__tests__/thread-suspend-step.test.ts +5 -2
  199. package/src/__tests__/thread-test-helpers.ts +15 -1
  200. package/src/__tests__/thread.test.ts +10 -10
  201. package/src/__tests__/validate-semantic.test.ts +59 -2
  202. package/src/__tests__/workflow-list-recursive.test.ts +9 -9
  203. package/src/__tests__/workflow-paths.test.ts +337 -0
  204. package/src/__tests__/workflow-resolution.test.ts +9 -8
  205. package/src/__tests__/workflow-show-resolution.test.ts +9 -8
  206. package/src/__tests__/workflow-validate.test.ts +78 -56
  207. package/src/__tests__/write-envelope.test.ts +257 -0
  208. package/src/cli.ts +111 -35
  209. package/src/commands/config.ts +85 -3
  210. package/src/commands/prompt.ts +42 -29
  211. package/src/commands/setup.ts +57 -7
  212. package/src/commands/thread.ts +280 -9
  213. package/src/commands/workflow.ts +32 -11
  214. package/src/concurrency/concurrency.ts +245 -0
  215. package/src/concurrency/index.ts +10 -0
  216. package/src/concurrency/types.ts +19 -0
  217. package/src/format.ts +282 -2
  218. package/src/output-mappers.ts +255 -0
  219. package/src/schemas.ts +39 -3
  220. package/src/store.ts +25 -1
  221. package/src/text-renderers.ts +355 -0
  222. package/src/validate-semantic.ts +33 -12
  223. package/LICENSE +0 -21
package/README.md CHANGED
@@ -37,11 +37,25 @@ bun link packages/cli
37
37
  ### Global options
38
38
 
39
39
  ```
40
- -V, --version Show version
41
- --format <json|yaml> Output format (default: json)
42
- -h, --help Show help
40
+ -V, --version Show version
41
+ --format <text|json|yaml|raw-json|raw-yaml> Output format (default: text)
42
+ -h, --help Show help
43
43
  ```
44
44
 
45
+ ### Output formats
46
+
47
+ | Format | Shape | Use case |
48
+ |--------|-------|----------|
49
+ | `text` (default) | Liquid-rendered, human-readable | Interactive terminal use |
50
+ | `json` | `{"type": "<schemaHash>", "value": <payload>}` | Self-describing JSON |
51
+ | `yaml` | YAML envelope with `type` and `value` keys | Self-describing YAML |
52
+ | `raw-json` | bare `<payload>` (no envelope) | 0.5.0-compatible JSON |
53
+ | `raw-yaml` | bare `<payload>` (no envelope) | 0.5.0-compatible YAML |
54
+
55
+ The `text` format renders each command's output through a Liquid template registered at `@ocas/template/text/<schemaHash>`, where `<schemaHash>` is the CAS hash of the corresponding `@uwf/output/<name>` schema (e.g. `@uwf/output/thread-start`, `@uwf/output/validate-result`). Schemas and templates are registered idempotently on first use.
56
+
57
+ The `json` and `yaml` envelopes carry the schema hash on the `type` field so consumers can dispatch on schema (and validate against the registered schema in CAS).
58
+
45
59
  ### Thread (Layer 2: Execution Instances)
46
60
 
47
61
  | Command | Description |
@@ -145,6 +159,19 @@ Engine config: `~/.uwf/config.yaml` (LLM-free — only `agents`, `defaultAgent`,
145
159
 
146
160
  ## Migration Guide
147
161
 
162
+ ### Breaking Changes (v0.5 → v0.6) — output envelope
163
+
164
+ `uwf` now emits an ocas envelope (`{ type, value }`) for `--format json` and `--format yaml`, and the default format changed from `json` to `text`.
165
+
166
+ | Old (0.5) | New (0.6) | What to do |
167
+ |-----------|-----------|------------|
168
+ | `--format json` (bare value) | `--format raw-json` (bare value, unchanged) | Quick fix: add `raw-` prefix |
169
+ | `--format yaml` (bare value) | `--format raw-yaml` (bare value, unchanged) | Quick fix: add `raw-` prefix |
170
+ | `--format json` (bare value) | `--format json` (envelope `{type,value}`) | Recommended: parse `value` field (`jq '.value'`) |
171
+ | default `json` | default `text` (Liquid-rendered) | Pipelines must opt into `--format raw-json` or `json` |
172
+
173
+ `uwf workflow validate` now writes a `validate-result` envelope to **stdout** (`✓ valid` / `✗ invalid (N errors)\n - <msg>`) instead of writing errors to stderr; exit codes (0/1) are unchanged.
174
+
148
175
  ### Breaking Changes (v0.x → v1.x)
149
176
 
150
177
  The CLI was reorganized to clarify the four-layer architecture. **No backward compatibility** — old commands have been removed.
@@ -0,0 +1 @@
1
+ c83fdefd2d40c71f9bd9c9ec4634e0765625ac0fb68d1013e8fffc7565d7b0d0
@@ -20,10 +20,18 @@ const OUTPUT_SCHEMA = {
20
20
  };
21
21
  // ── fixture ──────────────────────────────────────────────────────────────────
22
22
  let tmpDir;
23
+ let savedOcasHome;
23
24
  beforeEach(async () => {
25
+ savedOcasHome = process.env.OCAS_HOME;
24
26
  tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-roundtrip-test-"));
25
27
  });
26
28
  afterEach(async () => {
29
+ if (savedOcasHome === undefined) {
30
+ delete process.env.OCAS_HOME;
31
+ }
32
+ else {
33
+ process.env.OCAS_HOME = savedOcasHome;
34
+ }
27
35
  await rm(tmpDir, { recursive: true, force: true });
28
36
  });
29
37
  describe("C1: adapter JSON round-trip integration", () => {
@@ -105,7 +113,7 @@ describe("C1: adapter JSON round-trip integration", () => {
105
113
  let stderr;
106
114
  let exitCode;
107
115
  try {
108
- stdout = execFileSync(process.execPath, [cliPath, "thread", "exec", threadId, "--agent", mockAgentPath], {
116
+ stdout = execFileSync(process.execPath, [cliPath, "--format", "raw-json", "thread", "exec", threadId, "--agent", mockAgentPath], {
109
117
  encoding: "utf8",
110
118
  stdio: ["ignore", "pipe", "pipe"],
111
119
  env: {
@@ -129,14 +137,16 @@ describe("C1: adapter JSON round-trip integration", () => {
129
137
  if (exitCode !== 0) {
130
138
  throw new Error(`CLI exited with code ${exitCode}\nstdout: ${stdout}\nstderr: ${stderr}`);
131
139
  }
132
- // Parse CLI output
140
+ // Parse CLI output (raw-json envelope value: { threadId, workflowHash, steps: [...] })
133
141
  const cliOutput = JSON.parse(stdout.trim());
134
- expect(cliOutput).toHaveProperty("thread", threadId);
135
- expect(cliOutput).toHaveProperty("head", stepHash);
136
- expect(cliOutput.head).toMatch(/^[0-9A-HJ-NP-TV-Z]{13}$/);
142
+ expect(cliOutput).toHaveProperty("threadId", threadId);
143
+ expect(cliOutput.steps).toHaveLength(1);
144
+ const firstStep = cliOutput.steps[0];
145
+ expect(firstStep).toHaveProperty("head", stepHash);
146
+ expect(firstStep.head).toMatch(/^[0-9A-HJ-NP-TV-Z]{13}$/);
137
147
  // Verify the CAS step node exists and has correct metadata
138
148
  const storeAfter = await openStore(casDir);
139
- const stepNode = storeAfter.cas.get(cliOutput.head);
149
+ const stepNode = storeAfter.cas.get(firstStep.head);
140
150
  expect(stepNode).not.toBeNull();
141
151
  const payload = stepNode.payload;
142
152
  expect(payload.role).toBe("worker");
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-json-roundtrip.test.js","sourceRoot":"","sources":["../../src/__tests__/adapter-json-roundtrip.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"adapter-json-roundtrip.test.js","sourceRoot":"","sources":["../../src/__tests__/adapter-json-roundtrip.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=concurrency.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/concurrency.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,196 @@
1
+ import { mkdir, mkdtemp, readdir, rm, writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
5
+ import { acquireSlot, cleanStaleSlots, countActiveSlots, DEFAULT_MAX_RUNNING, getSlotsDir, installSlotCleanup, } from "../concurrency/index.js";
6
+ // ── test setup ────────────────────────────────────────────────────────────────
7
+ let tmpDir;
8
+ beforeEach(async () => {
9
+ tmpDir = await mkdtemp(join(tmpdir(), "concurrency-test-"));
10
+ });
11
+ afterEach(async () => {
12
+ await rm(tmpDir, { recursive: true, force: true });
13
+ });
14
+ // ── Spec: concurrency-acquire-slot-under-limit ──────────────────────────────
15
+ describe("acquireSlot succeeds immediately when below maxRunning", () => {
16
+ test("creates slot file and returns SlotHandle when under limit", async () => {
17
+ const handle = await acquireSlot(tmpDir, 2);
18
+ // Slot file exists
19
+ const slotsDir = getSlotsDir(tmpDir);
20
+ const files = await readdir(slotsDir);
21
+ expect(files).toContain(`${process.pid}.slot`);
22
+ // Returns a SlotHandle with release()
23
+ expect(handle).toHaveProperty("release");
24
+ expect(typeof handle.release).toBe("function");
25
+ // countActiveSlots returns 1
26
+ const count = await countActiveSlots(tmpDir);
27
+ expect(count).toBe(1);
28
+ // Cleanup
29
+ await handle.release();
30
+ });
31
+ test("returns immediately (no blocking) when slots available", async () => {
32
+ const start = Date.now();
33
+ const handle = await acquireSlot(tmpDir, 2);
34
+ const elapsed = Date.now() - start;
35
+ // Should complete in well under 1 second (no polling delay)
36
+ expect(elapsed).toBeLessThan(500);
37
+ await handle.release();
38
+ });
39
+ });
40
+ // ── Spec: concurrency-acquire-slot-blocks-at-limit ──────────────────────────
41
+ describe("acquireSlot blocks when at capacity", () => {
42
+ test("calls onWaiting when all slots are occupied", async () => {
43
+ // Create a slot file for a "live" process — use parent PID (same user, signalable)
44
+ const slotsDir = getSlotsDir(tmpDir);
45
+ await mkdir(slotsDir, { recursive: true });
46
+ const blockerPid = process.ppid;
47
+ await writeFile(join(slotsDir, `${blockerPid}.slot`), "", "utf8");
48
+ const onWaiting = vi.fn();
49
+ const onAcquired = vi.fn();
50
+ // maxRunning=1, one slot occupied → should block
51
+ // Release the blocking slot after a brief delay
52
+ setTimeout(async () => {
53
+ await rm(join(slotsDir, `${blockerPid}.slot`), { force: true });
54
+ }, 200);
55
+ const handle = await acquireSlot(tmpDir, 1, {
56
+ onWaiting,
57
+ onAcquired,
58
+ pollIntervalMs: 100,
59
+ });
60
+ expect(onWaiting).toHaveBeenCalled();
61
+ expect(onAcquired).toHaveBeenCalled();
62
+ await handle.release();
63
+ });
64
+ test("polls with interval and proceeds after slot is freed", async () => {
65
+ const slotsDir = getSlotsDir(tmpDir);
66
+ await mkdir(slotsDir, { recursive: true });
67
+ const blockerPid = process.ppid;
68
+ await writeFile(join(slotsDir, `${blockerPid}.slot`), "", "utf8");
69
+ // Remove after 250ms
70
+ setTimeout(async () => {
71
+ await rm(join(slotsDir, `${blockerPid}.slot`), { force: true });
72
+ }, 250);
73
+ const start = Date.now();
74
+ const handle = await acquireSlot(tmpDir, 1, { pollIntervalMs: 100 });
75
+ const elapsed = Date.now() - start;
76
+ // Should have waited at least ~200ms (polling)
77
+ expect(elapsed).toBeGreaterThanOrEqual(150);
78
+ await handle.release();
79
+ });
80
+ });
81
+ // ── Spec: concurrency-stale-slot-cleanup ────────────────────────────────────
82
+ describe("cleanStaleSlots removes slot files for dead PIDs", () => {
83
+ test("removes slot file for dead PID, preserves live PID", async () => {
84
+ const slotsDir = getSlotsDir(tmpDir);
85
+ await mkdir(slotsDir, { recursive: true });
86
+ // Dead PID (99999999 should not exist)
87
+ await writeFile(join(slotsDir, "99999999.slot"), "", "utf8");
88
+ // Live PID (current process)
89
+ await writeFile(join(slotsDir, `${process.pid}.slot`), "", "utf8");
90
+ const cleaned = await cleanStaleSlots(tmpDir);
91
+ expect(cleaned).toBe(1);
92
+ const files = await readdir(slotsDir);
93
+ expect(files).not.toContain("99999999.slot");
94
+ expect(files).toContain(`${process.pid}.slot`);
95
+ });
96
+ test("countActiveSlots reflects correct count after cleanup", async () => {
97
+ const slotsDir = getSlotsDir(tmpDir);
98
+ await mkdir(slotsDir, { recursive: true });
99
+ // 1 dead + 1 live
100
+ await writeFile(join(slotsDir, "99999999.slot"), "", "utf8");
101
+ await writeFile(join(slotsDir, `${process.pid}.slot`), "", "utf8");
102
+ // Before cleanup: 2 files
103
+ const beforeFiles = await readdir(slotsDir);
104
+ expect(beforeFiles.filter((f) => f.endsWith(".slot")).length).toBe(2);
105
+ await cleanStaleSlots(tmpDir);
106
+ // After cleanup
107
+ const count = await countActiveSlots(tmpDir);
108
+ expect(count).toBe(1);
109
+ });
110
+ });
111
+ // ── Spec: concurrency-race-protection-rollback ──────────────────────────────
112
+ describe("acquireSlot rolls back on race condition", () => {
113
+ test("rolls back slot file if post-write count exceeds maxRunning", async () => {
114
+ const slotsDir = getSlotsDir(tmpDir);
115
+ await mkdir(slotsDir, { recursive: true });
116
+ // Simulate: maxRunning=2, and we already have 1 slot from another live process
117
+ const blockerPid = process.ppid;
118
+ await writeFile(join(slotsDir, `${blockerPid}.slot`), "", "utf8");
119
+ // Our process writes its slot, making count=2 which equals maxRunning=2
120
+ // This should succeed (at limit, not over)
121
+ const handle = await acquireSlot(tmpDir, 2);
122
+ const count = await countActiveSlots(tmpDir);
123
+ expect(count).toBe(2);
124
+ await handle.release();
125
+ });
126
+ test("when another slot appears during write, rollback occurs", async () => {
127
+ // This tests the double-check logic. We'll simulate by pre-filling to capacity.
128
+ const slotsDir = getSlotsDir(tmpDir);
129
+ await mkdir(slotsDir, { recursive: true });
130
+ // maxRunning=1, one slot already occupied by parent PID
131
+ const blockerPid = process.ppid;
132
+ await writeFile(join(slotsDir, `${blockerPid}.slot`), "", "utf8");
133
+ // Release after delay so acquireSlot can proceed
134
+ setTimeout(async () => {
135
+ await rm(join(slotsDir, `${blockerPid}.slot`), { force: true });
136
+ }, 200);
137
+ const handle = await acquireSlot(tmpDir, 1, { pollIntervalMs: 100 });
138
+ // After acquiring, only our slot should exist
139
+ const files = await readdir(slotsDir);
140
+ const slotFiles = files.filter((f) => f.endsWith(".slot"));
141
+ expect(slotFiles).toContain(`${process.pid}.slot`);
142
+ await handle.release();
143
+ });
144
+ });
145
+ // ── Spec: concurrency-exec-signal-cleanup ────────────────────────────────────
146
+ describe("installSlotCleanup removes slot on signal", () => {
147
+ test("release function removes slot file", async () => {
148
+ const handle = await acquireSlot(tmpDir, 2);
149
+ // Verify slot exists
150
+ const slotsDir = getSlotsDir(tmpDir);
151
+ const filesBefore = await readdir(slotsDir);
152
+ expect(filesBefore).toContain(`${process.pid}.slot`);
153
+ // installSlotCleanup returns a cleanup function
154
+ const cleanup = installSlotCleanup(handle);
155
+ // Call release directly (simulating what signal handler would do)
156
+ await handle.release();
157
+ const filesAfter = await readdir(slotsDir);
158
+ expect(filesAfter).not.toContain(`${process.pid}.slot`);
159
+ // Uninstall the cleanup handler
160
+ cleanup();
161
+ });
162
+ });
163
+ // ── Spec: concurrency-default-max-running ────────────────────────────────────
164
+ describe("DEFAULT_MAX_RUNNING is 2", () => {
165
+ test("constant equals 2", () => {
166
+ expect(DEFAULT_MAX_RUNNING).toBe(2);
167
+ });
168
+ });
169
+ // ── Spec: concurrency-exec-uses-slot (unit level) ───────────────────────────
170
+ describe("slot lifecycle during exec", () => {
171
+ test("acquireSlot + release = 0 active slots", async () => {
172
+ const handle = await acquireSlot(tmpDir, 2);
173
+ expect(await countActiveSlots(tmpDir)).toBe(1);
174
+ await handle.release();
175
+ expect(await countActiveSlots(tmpDir)).toBe(0);
176
+ });
177
+ test("release is idempotent", async () => {
178
+ const handle = await acquireSlot(tmpDir, 2);
179
+ await handle.release();
180
+ // Calling release again should not throw
181
+ await handle.release();
182
+ expect(await countActiveSlots(tmpDir)).toBe(0);
183
+ });
184
+ });
185
+ // ── Spec: concurrency-config-set-max-running ─────────────────────────────────
186
+ describe("config set concurrency.maxRunning", () => {
187
+ test("concurrency config key is validated correctly", async () => {
188
+ // Import config module to test the key validation
189
+ const { parseDotPath, setNestedValue } = await import("../commands/config.js");
190
+ const config = {};
191
+ const path = parseDotPath("concurrency.maxRunning");
192
+ setNestedValue(config, path, 3);
193
+ expect(config).toEqual({ concurrency: { maxRunning: 3 } });
194
+ });
195
+ });
196
+ //# sourceMappingURL=concurrency.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.test.js","sourceRoot":"","sources":["../../src/__tests__/concurrency.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config-text-renderer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-text-renderer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/config-text-renderer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,137 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { formatOutput } from "../format.js";
3
+ describe("config text renderers", () => {
4
+ describe("config list", () => {
5
+ test("renders flat key-value pairs in text format", () => {
6
+ const data = {
7
+ defaultAgent: "claude-code",
8
+ agents: {
9
+ hermes: {
10
+ command: "uwf-hermes",
11
+ args: [],
12
+ },
13
+ "claude-code": {
14
+ command: "uwf-claude-code",
15
+ args: [],
16
+ },
17
+ },
18
+ concurrency: {
19
+ maxRunning: 4,
20
+ },
21
+ };
22
+ const result = formatOutput(data, "text", "config list");
23
+ expect(result).toContain("defaultAgent");
24
+ expect(result).toContain("claude-code");
25
+ expect(result).toContain("agents.hermes.command");
26
+ expect(result).toContain("uwf-hermes");
27
+ expect(result).toContain("agents.hermes.args");
28
+ expect(result).toContain("[]");
29
+ expect(result).toContain("agents.claude-code.command");
30
+ expect(result).toContain("uwf-claude-code");
31
+ expect(result).toContain("concurrency.maxRunning");
32
+ expect(result).toContain("4");
33
+ });
34
+ test("uses dot-notation for nested keys", () => {
35
+ const data = {
36
+ agents: {
37
+ hermes: {
38
+ command: "uwf-hermes",
39
+ },
40
+ },
41
+ };
42
+ const result = formatOutput(data, "text", "config list");
43
+ expect(result).toContain("agents.hermes.command");
44
+ });
45
+ test("displays array values as JSON", () => {
46
+ const data = {
47
+ agents: {
48
+ hermes: {
49
+ args: ["--flag", "--verbose"],
50
+ },
51
+ },
52
+ };
53
+ const result = formatOutput(data, "text", "config list");
54
+ expect(result).toContain('["--flag","--verbose"]');
55
+ });
56
+ test("does not throw on empty config", () => {
57
+ const result = formatOutput({}, "text", "config list");
58
+ expect(result).toBe("");
59
+ });
60
+ test("does not throw on null/undefined data", () => {
61
+ expect(() => formatOutput(null, "text", "config list")).not.toThrow();
62
+ expect(() => formatOutput(undefined, "text", "config list")).not.toThrow();
63
+ });
64
+ });
65
+ describe("config get", () => {
66
+ test("renders scalar value as bare string", () => {
67
+ const data = { value: "claude-code" };
68
+ const result = formatOutput(data, "text", "config get");
69
+ expect(result).toBe("claude-code");
70
+ });
71
+ test("renders number value as string", () => {
72
+ const data = { value: 4 };
73
+ const result = formatOutput(data, "text", "config get");
74
+ expect(result).toBe("4");
75
+ });
76
+ test("renders object value as flattened key-value pairs", () => {
77
+ const data = {
78
+ value: {
79
+ command: "uwf-hermes",
80
+ args: [],
81
+ },
82
+ };
83
+ const result = formatOutput(data, "text", "config get");
84
+ expect(result).toContain("command");
85
+ expect(result).toContain("uwf-hermes");
86
+ expect(result).toContain("args");
87
+ expect(result).toContain("[]");
88
+ });
89
+ test("does not throw on null value", () => {
90
+ expect(() => formatOutput({ value: null }, "text", "config get")).not.toThrow();
91
+ });
92
+ test("does not throw on missing value field", () => {
93
+ expect(() => formatOutput({}, "text", "config get")).not.toThrow();
94
+ });
95
+ });
96
+ describe("config set", () => {
97
+ test("renders key = value confirmation for scalar", () => {
98
+ const data = { key: "defaultAgent", value: "hermes" };
99
+ const result = formatOutput(data, "text", "config set");
100
+ expect(result).toBe("defaultAgent = hermes");
101
+ });
102
+ test("renders key = value for array values as JSON", () => {
103
+ const data = { key: "agents.hermes.args", value: ["--verbose"] };
104
+ const result = formatOutput(data, "text", "config set");
105
+ expect(result).toBe('agents.hermes.args = ["--verbose"]');
106
+ });
107
+ test("does not throw on missing key/value", () => {
108
+ expect(() => formatOutput({}, "text", "config set")).not.toThrow();
109
+ expect(() => formatOutput(null, "text", "config set")).not.toThrow();
110
+ });
111
+ });
112
+ describe("text format fallback", () => {
113
+ test("falls back to JSON pretty-print when no renderer registered", () => {
114
+ const data = { hello: "world" };
115
+ const result = formatOutput(data, "text", "unknown command");
116
+ expect(result).toBe(JSON.stringify(data, null, 2));
117
+ });
118
+ test("falls back to JSON pretty-print when commandPath is null", () => {
119
+ const data = { hello: "world" };
120
+ const result = formatOutput(data, "text", undefined);
121
+ expect(result).toBe(JSON.stringify(data, null, 2));
122
+ });
123
+ });
124
+ describe("json and yaml formats unaffected", () => {
125
+ test("json format still works with commandPath", () => {
126
+ const data = { key: "value" };
127
+ const result = formatOutput(data, "json", "config list");
128
+ expect(result).toBe(JSON.stringify(data));
129
+ });
130
+ test("yaml format still works with commandPath", () => {
131
+ const data = { key: "value" };
132
+ const result = formatOutput(data, "yaml", "config list");
133
+ expect(result).toContain("key: value");
134
+ });
135
+ });
136
+ });
137
+ //# sourceMappingURL=config-text-renderer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-text-renderer.test.js","sourceRoot":"","sources":["../../src/__tests__/config-text-renderer.test.ts"],"names":[],"mappings":"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"}
@@ -86,7 +86,7 @@ async function addWorkflow(workflowFixture, workflowName) {
86
86
  return result.hash;
87
87
  }
88
88
  function runExec(threadId, count = null) {
89
- const args = [CLI_PATH, "thread", "exec", threadId];
89
+ const args = [CLI_PATH, "--format", "raw-json", "thread", "exec", threadId];
90
90
  if (count !== null) {
91
91
  args.push("--count", String(count));
92
92
  }
@@ -108,7 +108,7 @@ function runExec(threadId, count = null) {
108
108
  /** Invoke `uwf thread resume <threadId> -p <prompt>` through the built CLI. */
109
109
  function runResume(threadId, prompt) {
110
110
  try {
111
- const stdout = execFileSync(process.execPath, [CLI_PATH, "thread", "resume", threadId, "-p", prompt], {
111
+ const stdout = execFileSync(process.execPath, [CLI_PATH, "--format", "raw-json", "thread", "resume", threadId, "-p", prompt], {
112
112
  encoding: "utf8",
113
113
  stdio: ["ignore", "pipe", "pipe"],
114
114
  env: { ...process.env, UWF_HOME: uwfHome, OCAS_HOME: casDir },
@@ -122,12 +122,28 @@ function runResume(threadId, prompt) {
122
122
  return { stdout: err.stdout ?? "", stderr: err.stderr ?? "", exitCode: err.status ?? 1 };
123
123
  }
124
124
  }
125
+ function projectStep(envelope, idx) {
126
+ const step = envelope.steps[idx];
127
+ if (step === undefined) {
128
+ throw new Error(`thread exec envelope has no step at index ${idx}`);
129
+ }
130
+ return {
131
+ thread: envelope.threadId,
132
+ head: step.head,
133
+ status: step.status,
134
+ currentRole: step.currentRole,
135
+ suspendedRole: step.suspendedRole,
136
+ suspendMessage: step.suspendMessage,
137
+ done: step.done,
138
+ };
139
+ }
125
140
  function execStep(threadId) {
126
141
  const { stdout, stderr, exitCode } = runExec(threadId);
127
142
  if (exitCode !== 0) {
128
143
  throw new Error(`thread exec failed (code ${exitCode})\nstdout: ${stdout}\nstderr: ${stderr}`);
129
144
  }
130
- return JSON.parse(stdout.trim());
145
+ const envelope = JSON.parse(stdout.trim());
146
+ return projectStep(envelope, 0);
131
147
  }
132
148
  function getStepNode(store, hash) {
133
149
  const node = store.cas.get(hash);
@@ -310,10 +326,10 @@ describe("E2E mock-agent: full uwf pipeline", { timeout: 15_000 }, () => {
310
326
  // Single invocation with --count 3 → moderator drives analyst → developer → reviewer → $END.
311
327
  const { stdout, stderr, exitCode } = runExec(threadId, 3);
312
328
  expect(exitCode, `stderr: ${stderr}`).toBe(0);
313
- // Multi-step exec emits a JSON array (one entry per executed step).
314
- const results = JSON.parse(stdout.trim());
315
- expect(Array.isArray(results)).toBe(true);
316
- expect(results).toHaveLength(3);
329
+ // Multi-step exec emits a single envelope with a `steps` array (one entry per executed step).
330
+ const envelope = JSON.parse(stdout.trim());
331
+ expect(envelope.steps).toHaveLength(3);
332
+ const results = [projectStep(envelope, 0), projectStep(envelope, 1), projectStep(envelope, 2)];
317
333
  expect(results[0].status).toBe("idle");
318
334
  expect(results[0].currentRole).toBe("developer");
319
335
  expect(results[1].status).toBe("idle");