@united-workforce/cli 0.1.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 (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +221 -0
  3. package/dist/__tests__/adapter-json-roundtrip.test.d.ts +2 -0
  4. package/dist/__tests__/adapter-json-roundtrip.test.d.ts.map +1 -0
  5. package/dist/__tests__/adapter-json-roundtrip.test.js +147 -0
  6. package/dist/__tests__/adapter-json-roundtrip.test.js.map +1 -0
  7. package/dist/__tests__/config.test.d.ts +2 -0
  8. package/dist/__tests__/config.test.d.ts.map +1 -0
  9. package/dist/__tests__/config.test.js +685 -0
  10. package/dist/__tests__/config.test.js.map +1 -0
  11. package/dist/__tests__/current-role.test.d.ts +2 -0
  12. package/dist/__tests__/current-role.test.d.ts.map +1 -0
  13. package/dist/__tests__/current-role.test.js +401 -0
  14. package/dist/__tests__/current-role.test.js.map +1 -0
  15. package/dist/__tests__/e2e-mock-agent.test.d.ts +2 -0
  16. package/dist/__tests__/e2e-mock-agent.test.d.ts.map +1 -0
  17. package/dist/__tests__/e2e-mock-agent.test.js +401 -0
  18. package/dist/__tests__/e2e-mock-agent.test.js.map +1 -0
  19. package/dist/__tests__/include-tag.test.d.ts +2 -0
  20. package/dist/__tests__/include-tag.test.d.ts.map +1 -0
  21. package/dist/__tests__/include-tag.test.js +69 -0
  22. package/dist/__tests__/include-tag.test.js.map +1 -0
  23. package/dist/__tests__/log.test.d.ts +2 -0
  24. package/dist/__tests__/log.test.d.ts.map +1 -0
  25. package/dist/__tests__/log.test.js +161 -0
  26. package/dist/__tests__/log.test.js.map +1 -0
  27. package/dist/__tests__/moderator-evaluate.test.d.ts +2 -0
  28. package/dist/__tests__/moderator-evaluate.test.d.ts.map +1 -0
  29. package/dist/__tests__/moderator-evaluate.test.js +170 -0
  30. package/dist/__tests__/moderator-evaluate.test.js.map +1 -0
  31. package/dist/__tests__/preload.d.ts +3 -0
  32. package/dist/__tests__/preload.d.ts.map +1 -0
  33. package/dist/__tests__/preload.js +6 -0
  34. package/dist/__tests__/preload.js.map +1 -0
  35. package/dist/__tests__/prompt.test.d.ts +2 -0
  36. package/dist/__tests__/prompt.test.d.ts.map +1 -0
  37. package/dist/__tests__/prompt.test.js +111 -0
  38. package/dist/__tests__/prompt.test.js.map +1 -0
  39. package/dist/__tests__/resolve-head-hash.test.d.ts +2 -0
  40. package/dist/__tests__/resolve-head-hash.test.d.ts.map +1 -0
  41. package/dist/__tests__/resolve-head-hash.test.js +66 -0
  42. package/dist/__tests__/resolve-head-hash.test.js.map +1 -0
  43. package/dist/__tests__/setup-agent-discovery.test.d.ts +2 -0
  44. package/dist/__tests__/setup-agent-discovery.test.d.ts.map +1 -0
  45. package/dist/__tests__/setup-agent-discovery.test.js +119 -0
  46. package/dist/__tests__/setup-agent-discovery.test.js.map +1 -0
  47. package/dist/__tests__/setup-complexity.test.d.ts +2 -0
  48. package/dist/__tests__/setup-complexity.test.d.ts.map +1 -0
  49. package/dist/__tests__/setup-complexity.test.js +314 -0
  50. package/dist/__tests__/setup-complexity.test.js.map +1 -0
  51. package/dist/__tests__/setup-validate.test.d.ts +2 -0
  52. package/dist/__tests__/setup-validate.test.d.ts.map +1 -0
  53. package/dist/__tests__/setup-validate.test.js +108 -0
  54. package/dist/__tests__/setup-validate.test.js.map +1 -0
  55. package/dist/__tests__/solve-issue-tea-worktree.test.d.ts +2 -0
  56. package/dist/__tests__/solve-issue-tea-worktree.test.d.ts.map +1 -0
  57. package/dist/__tests__/solve-issue-tea-worktree.test.js +107 -0
  58. package/dist/__tests__/solve-issue-tea-worktree.test.js.map +1 -0
  59. package/dist/__tests__/spawn-agent-json.test.d.ts +2 -0
  60. package/dist/__tests__/spawn-agent-json.test.d.ts.map +1 -0
  61. package/dist/__tests__/spawn-agent-json.test.js +79 -0
  62. package/dist/__tests__/spawn-agent-json.test.js.map +1 -0
  63. package/dist/__tests__/step-read.test.d.ts +2 -0
  64. package/dist/__tests__/step-read.test.d.ts.map +1 -0
  65. package/dist/__tests__/step-read.test.js +561 -0
  66. package/dist/__tests__/step-read.test.js.map +1 -0
  67. package/dist/__tests__/step-show-json.test.d.ts +2 -0
  68. package/dist/__tests__/step-show-json.test.d.ts.map +1 -0
  69. package/dist/__tests__/step-show-json.test.js +311 -0
  70. package/dist/__tests__/step-show-json.test.js.map +1 -0
  71. package/dist/__tests__/step-timing.test.d.ts +2 -0
  72. package/dist/__tests__/step-timing.test.d.ts.map +1 -0
  73. package/dist/__tests__/step-timing.test.js +345 -0
  74. package/dist/__tests__/step-timing.test.js.map +1 -0
  75. package/dist/__tests__/store-global-cas.test.d.ts +2 -0
  76. package/dist/__tests__/store-global-cas.test.d.ts.map +1 -0
  77. package/dist/__tests__/store-global-cas.test.js +235 -0
  78. package/dist/__tests__/store-global-cas.test.js.map +1 -0
  79. package/dist/__tests__/store-storage-root.test.d.ts +2 -0
  80. package/dist/__tests__/store-storage-root.test.d.ts.map +1 -0
  81. package/dist/__tests__/store-storage-root.test.js +43 -0
  82. package/dist/__tests__/store-storage-root.test.js.map +1 -0
  83. package/dist/__tests__/store-unified-threads.test.d.ts +2 -0
  84. package/dist/__tests__/store-unified-threads.test.d.ts.map +1 -0
  85. package/dist/__tests__/store-unified-threads.test.js +189 -0
  86. package/dist/__tests__/store-unified-threads.test.js.map +1 -0
  87. package/dist/__tests__/thread-cancel-status.test.d.ts +2 -0
  88. package/dist/__tests__/thread-cancel-status.test.d.ts.map +1 -0
  89. package/dist/__tests__/thread-cancel-status.test.js +111 -0
  90. package/dist/__tests__/thread-cancel-status.test.js.map +1 -0
  91. package/dist/__tests__/thread-list-filters.test.d.ts +2 -0
  92. package/dist/__tests__/thread-list-filters.test.d.ts.map +1 -0
  93. package/dist/__tests__/thread-list-filters.test.js +442 -0
  94. package/dist/__tests__/thread-list-filters.test.js.map +1 -0
  95. package/dist/__tests__/thread-location.test.d.ts +2 -0
  96. package/dist/__tests__/thread-location.test.d.ts.map +1 -0
  97. package/dist/__tests__/thread-location.test.js +159 -0
  98. package/dist/__tests__/thread-location.test.js.map +1 -0
  99. package/dist/__tests__/thread-read-quota.test.d.ts +2 -0
  100. package/dist/__tests__/thread-read-quota.test.d.ts.map +1 -0
  101. package/dist/__tests__/thread-read-quota.test.js +546 -0
  102. package/dist/__tests__/thread-read-quota.test.js.map +1 -0
  103. package/dist/__tests__/thread-read-xml-tags.test.d.ts +2 -0
  104. package/dist/__tests__/thread-read-xml-tags.test.d.ts.map +1 -0
  105. package/dist/__tests__/thread-read-xml-tags.test.js +610 -0
  106. package/dist/__tests__/thread-read-xml-tags.test.js.map +1 -0
  107. package/dist/__tests__/thread-resume.test.d.ts +2 -0
  108. package/dist/__tests__/thread-resume.test.d.ts.map +1 -0
  109. package/dist/__tests__/thread-resume.test.js +592 -0
  110. package/dist/__tests__/thread-resume.test.js.map +1 -0
  111. package/dist/__tests__/thread-show-status.test.d.ts +2 -0
  112. package/dist/__tests__/thread-show-status.test.d.ts.map +1 -0
  113. package/dist/__tests__/thread-show-status.test.js +267 -0
  114. package/dist/__tests__/thread-show-status.test.js.map +1 -0
  115. package/dist/__tests__/thread-start-cwd-cli.test.d.ts +2 -0
  116. package/dist/__tests__/thread-start-cwd-cli.test.d.ts.map +1 -0
  117. package/dist/__tests__/thread-start-cwd-cli.test.js +130 -0
  118. package/dist/__tests__/thread-start-cwd-cli.test.js.map +1 -0
  119. package/dist/__tests__/thread-step-count.test.d.ts +2 -0
  120. package/dist/__tests__/thread-step-count.test.d.ts.map +1 -0
  121. package/dist/__tests__/thread-step-count.test.js +55 -0
  122. package/dist/__tests__/thread-step-count.test.js.map +1 -0
  123. package/dist/__tests__/thread-suspend-step.test.d.ts +2 -0
  124. package/dist/__tests__/thread-suspend-step.test.d.ts.map +1 -0
  125. package/dist/__tests__/thread-suspend-step.test.js +155 -0
  126. package/dist/__tests__/thread-suspend-step.test.js.map +1 -0
  127. package/dist/__tests__/thread-suspended-display.test.d.ts +2 -0
  128. package/dist/__tests__/thread-suspended-display.test.d.ts.map +1 -0
  129. package/dist/__tests__/thread-suspended-display.test.js +247 -0
  130. package/dist/__tests__/thread-suspended-display.test.js.map +1 -0
  131. package/dist/__tests__/thread-test-helpers.d.ts +4 -0
  132. package/dist/__tests__/thread-test-helpers.d.ts.map +1 -0
  133. package/dist/__tests__/thread-test-helpers.js +23 -0
  134. package/dist/__tests__/thread-test-helpers.js.map +1 -0
  135. package/dist/__tests__/thread.test.d.ts +2 -0
  136. package/dist/__tests__/thread.test.d.ts.map +1 -0
  137. package/dist/__tests__/thread.test.js +883 -0
  138. package/dist/__tests__/thread.test.js.map +1 -0
  139. package/dist/__tests__/validate-semantic.test.d.ts +2 -0
  140. package/dist/__tests__/validate-semantic.test.d.ts.map +1 -0
  141. package/dist/__tests__/validate-semantic.test.js +408 -0
  142. package/dist/__tests__/validate-semantic.test.js.map +1 -0
  143. package/dist/__tests__/workflow-resolution.test.d.ts +2 -0
  144. package/dist/__tests__/workflow-resolution.test.d.ts.map +1 -0
  145. package/dist/__tests__/workflow-resolution.test.js +308 -0
  146. package/dist/__tests__/workflow-resolution.test.js.map +1 -0
  147. package/dist/background/background.d.ts +38 -0
  148. package/dist/background/background.d.ts.map +1 -0
  149. package/dist/background/background.js +123 -0
  150. package/dist/background/background.js.map +1 -0
  151. package/dist/background/index.d.ts +3 -0
  152. package/dist/background/index.d.ts.map +1 -0
  153. package/dist/background/index.js +2 -0
  154. package/dist/background/index.js.map +1 -0
  155. package/dist/background/types.d.ts +9 -0
  156. package/dist/background/types.d.ts.map +1 -0
  157. package/dist/background/types.js +2 -0
  158. package/dist/background/types.js.map +1 -0
  159. package/dist/cli.d.ts +3 -0
  160. package/dist/cli.d.ts.map +1 -0
  161. package/dist/cli.js +535 -0
  162. package/dist/cli.js.map +1 -0
  163. package/dist/commands/config.d.ts +41 -0
  164. package/dist/commands/config.d.ts.map +1 -0
  165. package/dist/commands/config.js +252 -0
  166. package/dist/commands/config.js.map +1 -0
  167. package/dist/commands/log.d.ts +26 -0
  168. package/dist/commands/log.d.ts.map +1 -0
  169. package/dist/commands/log.js +79 -0
  170. package/dist/commands/log.js.map +1 -0
  171. package/dist/commands/prompt.d.ts +6 -0
  172. package/dist/commands/prompt.d.ts.map +1 -0
  173. package/dist/commands/prompt.js +67 -0
  174. package/dist/commands/prompt.js.map +1 -0
  175. package/dist/commands/setup.d.ts +73 -0
  176. package/dist/commands/setup.d.ts.map +1 -0
  177. package/dist/commands/setup.js +522 -0
  178. package/dist/commands/setup.js.map +1 -0
  179. package/dist/commands/shared.d.ts +31 -0
  180. package/dist/commands/shared.d.ts.map +1 -0
  181. package/dist/commands/shared.js +154 -0
  182. package/dist/commands/shared.js.map +1 -0
  183. package/dist/commands/step.d.ts +18 -0
  184. package/dist/commands/step.d.ts.map +1 -0
  185. package/dist/commands/step.js +257 -0
  186. package/dist/commands/step.js.map +1 -0
  187. package/dist/commands/thread-time-parser.d.ts +6 -0
  188. package/dist/commands/thread-time-parser.d.ts.map +1 -0
  189. package/dist/commands/thread-time-parser.js +22 -0
  190. package/dist/commands/thread-time-parser.js.map +1 -0
  191. package/dist/commands/thread.d.ts +38 -0
  192. package/dist/commands/thread.d.ts.map +1 -0
  193. package/dist/commands/thread.js +1087 -0
  194. package/dist/commands/thread.js.map +1 -0
  195. package/dist/commands/workflow.d.ts +24 -0
  196. package/dist/commands/workflow.d.ts.map +1 -0
  197. package/dist/commands/workflow.js +138 -0
  198. package/dist/commands/workflow.js.map +1 -0
  199. package/dist/format.d.ts +3 -0
  200. package/dist/format.d.ts.map +1 -0
  201. package/dist/format.js +10 -0
  202. package/dist/format.js.map +1 -0
  203. package/dist/include.d.ts +12 -0
  204. package/dist/include.d.ts.map +1 -0
  205. package/dist/include.js +35 -0
  206. package/dist/include.js.map +1 -0
  207. package/dist/moderator/__tests__/evaluate.test.d.ts +2 -0
  208. package/dist/moderator/__tests__/evaluate.test.d.ts.map +1 -0
  209. package/dist/moderator/__tests__/evaluate.test.js +167 -0
  210. package/dist/moderator/__tests__/evaluate.test.js.map +1 -0
  211. package/dist/moderator/evaluate.d.ts +6 -0
  212. package/dist/moderator/evaluate.d.ts.map +1 -0
  213. package/dist/moderator/evaluate.js +65 -0
  214. package/dist/moderator/evaluate.js.map +1 -0
  215. package/dist/moderator/index.d.ts +4 -0
  216. package/dist/moderator/index.d.ts.map +1 -0
  217. package/dist/moderator/index.js +3 -0
  218. package/dist/moderator/index.js.map +1 -0
  219. package/dist/moderator/types.d.ts +25 -0
  220. package/dist/moderator/types.d.ts.map +1 -0
  221. package/dist/moderator/types.js +4 -0
  222. package/dist/moderator/types.js.map +1 -0
  223. package/dist/schemas.d.ts +16 -0
  224. package/dist/schemas.d.ts.map +1 -0
  225. package/dist/schemas.js +17 -0
  226. package/dist/schemas.js.map +1 -0
  227. package/dist/store.d.ts +77 -0
  228. package/dist/store.d.ts.map +1 -0
  229. package/dist/store.js +392 -0
  230. package/dist/store.js.map +1 -0
  231. package/dist/validate-semantic.d.ts +7 -0
  232. package/dist/validate-semantic.d.ts.map +1 -0
  233. package/dist/validate-semantic.js +263 -0
  234. package/dist/validate-semantic.js.map +1 -0
  235. package/dist/validate.d.ts +16 -0
  236. package/dist/validate.d.ts.map +1 -0
  237. package/dist/validate.js +115 -0
  238. package/dist/validate.js.map +1 -0
  239. package/package.json +44 -0
  240. package/src/__tests__/adapter-json-roundtrip.test.ts +181 -0
  241. package/src/__tests__/config.test.ts +740 -0
  242. package/src/__tests__/current-role.test.ts +438 -0
  243. package/src/__tests__/e2e-mock-agent.test.ts +498 -0
  244. package/src/__tests__/fixtures/e2e-completed-resume.mock.yaml +15 -0
  245. package/src/__tests__/fixtures/e2e-count.mock.yaml +19 -0
  246. package/src/__tests__/fixtures/e2e-count.workflow.yaml +45 -0
  247. package/src/__tests__/fixtures/e2e-linear.mock.yaml +13 -0
  248. package/src/__tests__/fixtures/e2e-linear.workflow.yaml +32 -0
  249. package/src/__tests__/fixtures/e2e-loop.mock.yaml +25 -0
  250. package/src/__tests__/fixtures/e2e-loop.workflow.yaml +36 -0
  251. package/src/__tests__/fixtures/e2e-mismatch.mock.yaml +16 -0
  252. package/src/__tests__/fixtures/e2e-mustache.mock.yaml +15 -0
  253. package/src/__tests__/fixtures/e2e-mustache.workflow.yaml +34 -0
  254. package/src/__tests__/fixtures/e2e-suspend.mock.yaml +14 -0
  255. package/src/__tests__/fixtures/e2e-suspend.workflow.yaml +24 -0
  256. package/src/__tests__/include-tag.test.ts +84 -0
  257. package/src/__tests__/log.test.ts +181 -0
  258. package/src/__tests__/moderator-evaluate.test.ts +186 -0
  259. package/src/__tests__/preload.ts +7 -0
  260. package/src/__tests__/prompt.test.ts +129 -0
  261. package/src/__tests__/resolve-head-hash.test.ts +86 -0
  262. package/src/__tests__/setup-agent-discovery.test.ts +167 -0
  263. package/src/__tests__/setup-complexity.test.ts +381 -0
  264. package/src/__tests__/setup-validate.test.ts +148 -0
  265. package/src/__tests__/solve-issue-tea-worktree.test.ts +144 -0
  266. package/src/__tests__/spawn-agent-json.test.ts +100 -0
  267. package/src/__tests__/step-read.test.ts +632 -0
  268. package/src/__tests__/step-show-json.test.ts +373 -0
  269. package/src/__tests__/step-timing.test.ts +392 -0
  270. package/src/__tests__/store-global-cas.test.ts +308 -0
  271. package/src/__tests__/store-storage-root.test.ts +49 -0
  272. package/src/__tests__/store-unified-threads.test.ts +235 -0
  273. package/src/__tests__/thread-cancel-status.test.ts +138 -0
  274. package/src/__tests__/thread-list-filters.test.ts +572 -0
  275. package/src/__tests__/thread-location.test.ts +186 -0
  276. package/src/__tests__/thread-read-quota.test.ts +613 -0
  277. package/src/__tests__/thread-read-xml-tags.test.ts +717 -0
  278. package/src/__tests__/thread-resume.test.ts +710 -0
  279. package/src/__tests__/thread-show-status.test.ts +317 -0
  280. package/src/__tests__/thread-start-cwd-cli.test.ts +164 -0
  281. package/src/__tests__/thread-step-count.test.ts +70 -0
  282. package/src/__tests__/thread-suspend-step.test.ts +181 -0
  283. package/src/__tests__/thread-suspended-display.test.ts +287 -0
  284. package/src/__tests__/thread-test-helpers.ts +37 -0
  285. package/src/__tests__/thread.test.ts +1025 -0
  286. package/src/__tests__/validate-semantic.test.ts +474 -0
  287. package/src/__tests__/workflow-resolution.test.ts +421 -0
  288. package/src/background/background.ts +147 -0
  289. package/src/background/index.ts +11 -0
  290. package/src/background/types.ts +9 -0
  291. package/src/cli.ts +692 -0
  292. package/src/commands/config.ts +304 -0
  293. package/src/commands/log.ts +116 -0
  294. package/src/commands/prompt.ts +81 -0
  295. package/src/commands/setup.ts +603 -0
  296. package/src/commands/shared.ts +227 -0
  297. package/src/commands/step.ts +343 -0
  298. package/src/commands/thread-time-parser.ts +23 -0
  299. package/src/commands/thread.ts +1575 -0
  300. package/src/commands/workflow.ts +213 -0
  301. package/src/format.ts +12 -0
  302. package/src/include.ts +37 -0
  303. package/src/moderator/__tests__/evaluate.test.ts +199 -0
  304. package/src/moderator/evaluate.ts +80 -0
  305. package/src/moderator/index.ts +7 -0
  306. package/src/moderator/types.ts +24 -0
  307. package/src/schemas.ts +26 -0
  308. package/src/store.ts +479 -0
  309. package/src/validate-semantic.ts +304 -0
  310. package/src/validate.ts +137 -0
@@ -0,0 +1,267 @@
1
+ import { mkdir, rm, writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { putSchema } from "@ocas/core";
5
+ import { describe, expect, test } from "vitest";
6
+ import { createMarker, deleteMarker } from "../background/index.js";
7
+ import { cmdThreadShow, cmdThreadStart } from "../commands/thread.js";
8
+ import { completeThread, createUwfStore, loadAllThreads, setThread } from "../store.js";
9
+ const OUTPUT_SCHEMA = {
10
+ type: "object",
11
+ properties: {
12
+ $status: { type: "string" },
13
+ question: { type: "string" },
14
+ },
15
+ };
16
+ const TEST_WORKFLOW_YAML = `
17
+ name: test-status
18
+ description: Test workflow for status field
19
+ roles:
20
+ planner:
21
+ description: Plans the work
22
+ goal: Plan implementation
23
+ capabilities: ["planning"]
24
+ procedure: Plan
25
+ output: |
26
+ $status: "ready"
27
+ frontmatter:
28
+ type: object
29
+ required: ["$status"]
30
+ properties:
31
+ $status: { type: string, enum: ["ready"] }
32
+ graph:
33
+ $START:
34
+ _:
35
+ role: planner
36
+ prompt: "Plan the work"
37
+ location: null
38
+ planner:
39
+ ready:
40
+ role: $END
41
+ prompt: "Done"
42
+ location: null
43
+ `;
44
+ const SUSPEND_WORKFLOW_YAML = `
45
+ name: test-suspend-status
46
+ description: Test workflow for suspended status
47
+ roles:
48
+ worker:
49
+ description: Worker role
50
+ goal: Work
51
+ capabilities: ["coding"]
52
+ procedure: Work
53
+ output: |
54
+ $status: "needs_input"
55
+ question: "Which API?"
56
+ frontmatter:
57
+ oneOf:
58
+ - type: object
59
+ required: ["$status", "question"]
60
+ properties:
61
+ $status: { const: "needs_input" }
62
+ question: { type: string }
63
+ graph:
64
+ $START:
65
+ _:
66
+ role: worker
67
+ prompt: "Start work"
68
+ location: null
69
+ worker:
70
+ needs_input:
71
+ role: $SUSPEND
72
+ prompt: "Please clarify: {{{question}}}"
73
+ location: null
74
+ `;
75
+ async function insertStepNode(storageRoot, threadId, role, outputPayload) {
76
+ const uwf = await createUwfStore(storageRoot);
77
+ const index = loadAllThreads(uwf.varStore);
78
+ const headEntry = index[threadId];
79
+ if (headEntry === undefined)
80
+ throw new Error(`thread ${threadId} not in index`);
81
+ const head = headEntry.head;
82
+ const outputSchemaHash = await putSchema(uwf.store, OUTPUT_SCHEMA);
83
+ const outputHash = await uwf.store.cas.put(outputSchemaHash, outputPayload);
84
+ const detailHash = await uwf.store.cas.put(uwf.schemas.text, "detail-placeholder");
85
+ const headNode = uwf.store.cas.get(head);
86
+ if (headNode === null)
87
+ throw new Error(`head ${head} not found`);
88
+ const isStart = headNode.type === uwf.schemas.startNode;
89
+ const startHash = isStart ? head : headNode.payload.start;
90
+ const stepHash = (await uwf.store.cas.put(uwf.schemas.stepNode, {
91
+ start: startHash,
92
+ prev: isStart ? null : head,
93
+ role,
94
+ output: outputHash,
95
+ detail: detailHash,
96
+ agent: "uwf-test",
97
+ edgePrompt: "edge",
98
+ startedAtMs: Date.now(),
99
+ completedAtMs: Date.now() + 1,
100
+ cwd: "/tmp",
101
+ assembledPrompt: null,
102
+ }));
103
+ setThread(uwf.varStore, threadId, {
104
+ head: stepHash,
105
+ status: "idle",
106
+ suspendedRole: null,
107
+ suspendMessage: null,
108
+ completedAt: null,
109
+ });
110
+ }
111
+ describe("thread show status field", () => {
112
+ let tmpDir;
113
+ let storageRoot;
114
+ async function setupTestEnv() {
115
+ tmpDir = join(tmpdir(), `uwf-test-status-${Date.now()}`);
116
+ storageRoot = join(tmpDir, "storage");
117
+ await mkdir(storageRoot, { recursive: true });
118
+ }
119
+ async function teardown() {
120
+ if (tmpDir) {
121
+ await rm(tmpDir, { recursive: true, force: true });
122
+ }
123
+ }
124
+ test("active idle thread shows status 'idle'", async () => {
125
+ await setupTestEnv();
126
+ const workflowPath = join(tmpDir, "test-status.yaml");
127
+ await writeFile(workflowPath, TEST_WORKFLOW_YAML, "utf8");
128
+ // Create a thread
129
+ const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir);
130
+ const threadId = startResult.thread;
131
+ // Show the thread (should be idle)
132
+ const result = await cmdThreadShow(storageRoot, threadId);
133
+ expect(result.status).toBe("idle");
134
+ expect(result.done).toBe(false);
135
+ expect(result.background).toBe(null);
136
+ expect(result.thread).toBe(threadId);
137
+ await teardown();
138
+ });
139
+ test("active running thread shows status 'running'", async () => {
140
+ await setupTestEnv();
141
+ const workflowPath = join(tmpDir, "test-status.yaml");
142
+ await writeFile(workflowPath, TEST_WORKFLOW_YAML, "utf8");
143
+ // Create a thread
144
+ const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir);
145
+ const threadId = startResult.thread;
146
+ const workflow = startResult.workflow;
147
+ // Create a running marker
148
+ await createMarker(storageRoot, {
149
+ thread: threadId,
150
+ workflow,
151
+ pid: process.pid,
152
+ startedAt: Date.now(),
153
+ });
154
+ try {
155
+ const result = await cmdThreadShow(storageRoot, threadId);
156
+ expect(result.status).toBe("running");
157
+ expect(result.done).toBe(false);
158
+ expect(result.background).toBe(null);
159
+ expect(result.thread).toBe(threadId);
160
+ }
161
+ finally {
162
+ // Cleanup: delete marker
163
+ await deleteMarker(storageRoot, threadId);
164
+ await teardown();
165
+ }
166
+ });
167
+ test("completed thread shows status 'completed'", async () => {
168
+ await setupTestEnv();
169
+ const workflowPath = join(tmpDir, "test-status.yaml");
170
+ await writeFile(workflowPath, TEST_WORKFLOW_YAML, "utf8");
171
+ // Create a thread
172
+ const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir);
173
+ const threadId = startResult.thread;
174
+ const _workflow = startResult.workflow;
175
+ // Get the head hash before moving to history
176
+ const uwfForIndex = await createUwfStore(storageRoot);
177
+ const index = loadAllThreads(uwfForIndex.varStore);
178
+ const head = index[threadId].head;
179
+ if (!head)
180
+ throw new Error("Thread not found in index");
181
+ completeThread(uwfForIndex.varStore, threadId, "completed");
182
+ const result = await cmdThreadShow(storageRoot, threadId);
183
+ expect(result.status).toBe("completed");
184
+ expect(result.done).toBe(true);
185
+ expect(result.background).toBe(null);
186
+ expect(result.thread).toBe(threadId);
187
+ await teardown();
188
+ });
189
+ test("cancelled thread shows status 'cancelled'", async () => {
190
+ await setupTestEnv();
191
+ const workflowPath = join(tmpDir, "test-status.yaml");
192
+ await writeFile(workflowPath, TEST_WORKFLOW_YAML, "utf8");
193
+ // Create a thread
194
+ const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir);
195
+ const threadId = startResult.thread;
196
+ const _workflow = startResult.workflow;
197
+ // Get the head hash before moving to history
198
+ const uwfForIndex = await createUwfStore(storageRoot);
199
+ const index = loadAllThreads(uwfForIndex.varStore);
200
+ const head = index[threadId].head;
201
+ if (!head)
202
+ throw new Error("Thread not found in index");
203
+ completeThread(uwfForIndex.varStore, threadId, "cancelled");
204
+ const result = await cmdThreadShow(storageRoot, threadId);
205
+ expect(result.status).toBe("cancelled");
206
+ expect(result.done).toBe(true);
207
+ expect(result.background).toBe(null);
208
+ expect(result.thread).toBe(threadId);
209
+ await teardown();
210
+ });
211
+ test("legacy completed thread without reason shows status 'completed'", async () => {
212
+ await setupTestEnv();
213
+ const workflowPath = join(tmpDir, "test-status.yaml");
214
+ await writeFile(workflowPath, TEST_WORKFLOW_YAML, "utf8");
215
+ // Create a thread
216
+ const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir);
217
+ const threadId = startResult.thread;
218
+ const _workflow = startResult.workflow;
219
+ // Get the head hash before moving to history
220
+ const uwfForIndex = await createUwfStore(storageRoot);
221
+ const index = loadAllThreads(uwfForIndex.varStore);
222
+ const head = index[threadId].head;
223
+ if (!head)
224
+ throw new Error("Thread not found in index");
225
+ completeThread(uwfForIndex.varStore, threadId, "completed");
226
+ const result = await cmdThreadShow(storageRoot, threadId);
227
+ expect(result.status).toBe("completed");
228
+ expect(result.done).toBe(true);
229
+ expect(result.background).toBe(null);
230
+ await teardown();
231
+ });
232
+ test("active suspended thread shows status 'suspended'", async () => {
233
+ await setupTestEnv();
234
+ const casDir = join(tmpDir, "cas");
235
+ await mkdir(casDir, { recursive: true });
236
+ const originalCasDir = process.env.OCAS_HOME;
237
+ process.env.OCAS_HOME = casDir;
238
+ try {
239
+ const workflowPath = join(tmpDir, "test-suspend-status.yaml");
240
+ await writeFile(workflowPath, SUSPEND_WORKFLOW_YAML, "utf8");
241
+ const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir);
242
+ const threadId = startResult.thread;
243
+ await insertStepNode(storageRoot, threadId, "worker", {
244
+ $status: "needs_input",
245
+ question: "Which API?",
246
+ });
247
+ const result = await cmdThreadShow(storageRoot, threadId);
248
+ expect(result.status).toBe("suspended");
249
+ expect(result.done).toBe(false);
250
+ expect(result.currentRole).toBe(null);
251
+ expect(result.suspendedRole).toBe("worker");
252
+ expect(result.suspendMessage).toBe("Please clarify: Which API?");
253
+ expect(result.background).toBe(null);
254
+ expect(result.thread).toBe(threadId);
255
+ }
256
+ finally {
257
+ if (originalCasDir === undefined) {
258
+ delete process.env.OCAS_HOME;
259
+ }
260
+ else {
261
+ process.env.OCAS_HOME = originalCasDir;
262
+ }
263
+ await teardown();
264
+ }
265
+ });
266
+ });
267
+ //# sourceMappingURL=thread-show-status.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-show-status.test.js","sourceRoot":"","sources":["../../src/__tests__/thread-show-status.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExF,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,QAAiB;IACvB,UAAU,EAAE;QACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE;QACpC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE;KACtC;CACF,CAAC;AAEF,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2B1B,CAAC;AAEF,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8B7B,CAAC;AAEF,KAAK,UAAU,cAAc,CAC3B,WAAmB,EACnB,QAAkB,EAClB,IAAY,EACZ,aAAsC;IAEtC,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClC,IAAI,SAAS,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,UAAU,QAAQ,eAAe,CAAC,CAAC;IAChF,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;IAE5B,MAAM,gBAAgB,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;IAC5E,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;IAEnF,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,QAAQ,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,YAAY,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;IACxD,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,QAAQ,CAAC,OAA6B,CAAC,KAAK,CAAC;IAEjF,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE;QAC9D,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;QAC3B,IAAI;QACJ,MAAM,EAAE,UAAU;QAClB,MAAM,EAAE,UAAU;QAClB,KAAK,EAAE,UAAU;QACjB,UAAU,EAAE,MAAM;QAClB,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;QACvB,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC;QAC7B,GAAG,EAAE,MAAM;QACX,eAAe,EAAE,IAAI;KACtB,CAAC,CAAW,CAAC;IAEd,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE;QAChC,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,MAAM;QACd,aAAa,EAAE,IAAI;QACnB,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;AACL,CAAC;AAED,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,IAAI,MAAc,CAAC;IACnB,IAAI,WAAmB,CAAC;IAExB,KAAK,UAAU,YAAY;QACzB,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACzD,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,UAAU,QAAQ;QACrB,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,IAAI,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,YAAY,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;QAE1D,kBAAkB;QAClB,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAkB,CAAC;QAEhD,mCAAmC;QACnC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAE1D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAErC,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,YAAY,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;QAE1D,kBAAkB;QAClB,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAkB,CAAC;QAChD,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;QAEtC,0BAA0B;QAC1B,MAAM,YAAY,CAAC,WAAW,EAAE;YAC9B,MAAM,EAAE,QAAQ;YAChB,QAAQ;YACR,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YAE1D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;gBAAS,CAAC;YACT,yBAAyB;YACzB,MAAM,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YAC1C,MAAM,QAAQ,EAAE,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,YAAY,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;QAE1D,kBAAkB;QAClB,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAkB,CAAC;QAChD,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,CAAC;QAEvC,6CAA6C;QAC7C,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAE,CAAC,IAAI,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAExD,cAAc,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAE5D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAE1D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAErC,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,YAAY,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;QAE1D,kBAAkB;QAClB,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAkB,CAAC;QAChD,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,CAAC;QAEvC,6CAA6C;QAC7C,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAE,CAAC,IAAI,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAExD,cAAc,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAE5D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAE1D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAErC,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,YAAY,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;QAE1D,kBAAkB;QAClB,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAkB,CAAC;QAChD,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,CAAC;QAEvC,6CAA6C;QAC7C,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAE,CAAC,IAAI,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAExD,cAAc,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAE5D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAE1D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAErC,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,YAAY,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACnC,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;QAE/B,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;YAC9D,MAAM,SAAS,CAAC,YAAY,EAAE,qBAAqB,EAAE,MAAM,CAAC,CAAC;YAE7D,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;YAC3F,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAkB,CAAC;YAEhD,MAAM,cAAc,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE;gBACpD,OAAO,EAAE,aAAa;gBACtB,QAAQ,EAAE,YAAY;aACvB,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YAE1D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YACjE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;gBAAS,CAAC;YACT,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBACjC,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,cAAc,CAAC;YACzC,CAAC;YACD,MAAM,QAAQ,EAAE,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=thread-start-cwd-cli.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-start-cwd-cli.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/thread-start-cwd-cli.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,130 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { mkdir, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { describe, expect, test } from "vitest";
7
+ import { cmdThreadStart } from "../commands/thread.js";
8
+ import { createUwfStore, getThread } from "../store.js";
9
+ describe("thread start --cwd CLI option", () => {
10
+ let tmpDir;
11
+ let storageRoot;
12
+ let casDir;
13
+ let originalEnv;
14
+ async function setupTestEnv() {
15
+ tmpDir = join(tmpdir(), `uwf-test-cwd-cli-${Date.now()}`);
16
+ storageRoot = join(tmpDir, "storage");
17
+ casDir = join(tmpDir, "cas");
18
+ await mkdir(storageRoot, { recursive: true });
19
+ await mkdir(casDir, { recursive: true });
20
+ // Set OCAS_HOME for this test
21
+ originalEnv = process.env.OCAS_HOME;
22
+ process.env.OCAS_HOME = casDir;
23
+ }
24
+ async function teardown() {
25
+ if (tmpDir) {
26
+ await rm(tmpDir, { recursive: true, force: true });
27
+ }
28
+ // Restore original environment
29
+ if (originalEnv === undefined) {
30
+ delete process.env.OCAS_HOME;
31
+ }
32
+ else {
33
+ process.env.OCAS_HOME = originalEnv;
34
+ }
35
+ }
36
+ async function createTestWorkflow() {
37
+ const workflowYaml = `
38
+ name: test-cwd-cli
39
+ description: Test workflow for CLI cwd option
40
+ roles:
41
+ planner:
42
+ description: Plans the work
43
+ goal: Plan implementation
44
+ capabilities: ["planning"]
45
+ procedure: Plan
46
+ output: |
47
+ $status: "ready"
48
+ frontmatter:
49
+ type: object
50
+ required: ["$status"]
51
+ properties:
52
+ $status: { type: string, enum: ["ready"] }
53
+ graph:
54
+ $START:
55
+ _:
56
+ role: planner
57
+ prompt: "Plan the work"
58
+ location: null
59
+ planner:
60
+ ready:
61
+ role: $END
62
+ prompt: "Done"
63
+ location: null
64
+ `;
65
+ const workflowPath = join(tmpDir, "test-cwd-cli.yaml");
66
+ await writeFile(workflowPath, workflowYaml, "utf8");
67
+ return workflowPath;
68
+ }
69
+ async function getStartNodeCwd(threadId) {
70
+ const uwf = await createUwfStore(storageRoot);
71
+ const entry = getThread(uwf.varStore, threadId);
72
+ const headHash = entry.head;
73
+ expect(headHash).toBeDefined();
74
+ const startNode = uwf.store.cas.get(headHash);
75
+ expect(startNode).not.toBe(null);
76
+ expect(startNode?.type).toBe(uwf.schemas.startNode);
77
+ const startPayload = startNode?.payload;
78
+ return startPayload.cwd;
79
+ }
80
+ test("thread start with custom cwd via cmdThreadStart", async () => {
81
+ await setupTestEnv();
82
+ const workflowPath = await createTestWorkflow();
83
+ const testCwd = "/test/custom/path";
84
+ const result = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir, testCwd);
85
+ expect(result.thread).toBeDefined();
86
+ const actualCwd = await getStartNodeCwd(result.thread);
87
+ expect(actualCwd).toBe(testCwd);
88
+ await teardown();
89
+ });
90
+ test("thread start without cwd defaults to process.cwd()", async () => {
91
+ await setupTestEnv();
92
+ const workflowPath = await createTestWorkflow();
93
+ // Call without cwd parameter (it defaults to process.cwd())
94
+ const result = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir);
95
+ expect(result.thread).toBeDefined();
96
+ const actualCwd = await getStartNodeCwd(result.thread);
97
+ expect(actualCwd).toBe(process.cwd());
98
+ await teardown();
99
+ });
100
+ test("thread start with relative path fails", async () => {
101
+ await setupTestEnv();
102
+ const workflowPath = await createTestWorkflow();
103
+ await expect(cmdThreadStart(storageRoot, workflowPath, "test", tmpDir, "relative/path")).rejects.toThrow();
104
+ await teardown();
105
+ });
106
+ test("CLI accepts --cwd option without error", async () => {
107
+ await setupTestEnv();
108
+ const workflowPath = await createTestWorkflow();
109
+ const testCwd = "/test/cli/path";
110
+ const pkgRoot = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
111
+ const uwfBin = join(pkgRoot, "dist", "cli.js");
112
+ // Register the workflow
113
+ execFileSync(process.execPath, [uwfBin, "workflow", "add", workflowPath], {
114
+ env: { ...process.env, UWF_HOME: storageRoot, OCAS_HOME: casDir },
115
+ encoding: "utf8",
116
+ });
117
+ // Verify CLI accepts --cwd option (no error thrown)
118
+ const output = execFileSync(process.execPath, [uwfBin, "thread", "start", "test-cwd-cli", "-p", "test prompt", "--cwd", testCwd], {
119
+ env: { ...process.env, UWF_HOME: storageRoot, OCAS_HOME: casDir },
120
+ encoding: "utf8",
121
+ });
122
+ const result = JSON.parse(output);
123
+ expect(result.thread).toBeDefined();
124
+ expect(result.workflow).toBeDefined();
125
+ // The fact that we got here without throwing means CLI accepted the --cwd option
126
+ // The actual cwd functionality is tested by the other tests using cmdThreadStart directly
127
+ await teardown();
128
+ });
129
+ });
130
+ //# sourceMappingURL=thread-start-cwd-cli.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-start-cwd-cli.test.js","sourceRoot":"","sources":["../../src/__tests__/thread-start-cwd-cli.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExD,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,IAAI,MAAc,CAAC;IACnB,IAAI,WAAmB,CAAC;IACxB,IAAI,MAAc,CAAC;IACnB,IAAI,WAA+B,CAAC;IAEpC,KAAK,UAAU,YAAY;QACzB,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC1D,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC7B,MAAM,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzC,8BAA8B;QAC9B,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;IACjC,CAAC;IAED,KAAK,UAAU,QAAQ;QACrB,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,+BAA+B;QAC/B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,WAAW,CAAC;QACtC,CAAC;IACH,CAAC;IAED,KAAK,UAAU,kBAAkB;QAC/B,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BxB,CAAC;QAEE,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;QACvD,MAAM,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;QACpD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,KAAK,UAAU,eAAe,CAAC,QAAgB;QAC7C,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAoB,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,KAAM,CAAC,IAAI,CAAC;QAC7B,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAE/B,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAkB,CAAC,CAAC;QACxD,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEpD,MAAM,YAAY,GAAG,SAAS,EAAE,OAA2B,CAAC;QAC5D,OAAO,YAAY,CAAC,GAAG,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,mBAAmB,CAAC;QAEpC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAE/F,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEhC,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAEhD,4DAA4D;QAC5D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;QAEtF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAEtC,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAEhD,MAAM,MAAM,CACV,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,CAC3E,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAEpB,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,YAAY,EAAE,CAAC;QAErB,MAAM,YAAY,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,gBAAgB,CAAC;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAE/C,wBAAwB;QACxB,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE;YACxE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE;YACjE,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;QAEH,oDAAoD;QACpD,MAAM,MAAM,GAAG,YAAY,CACzB,OAAO,CAAC,QAAQ,EAChB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,CAAC,EAClF;YACE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE;YACjE,QAAQ,EAAE,MAAM;SACjB,CACF,CAAC;QAEF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAEtC,iFAAiF;QACjF,0FAA0F;QAC1F,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=thread-step-count.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-step-count.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/thread-step-count.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { describe, expect, test } from "vitest";
5
+ import { validateCount } from "../commands/thread.js";
6
+ const CLI_PATH = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "dist", "cli.js");
7
+ function runCli(args) {
8
+ try {
9
+ const stdout = execFileSync("node", [CLI_PATH, ...args], {
10
+ encoding: "utf8",
11
+ env: { ...process.env, UWF_HOME: "/tmp/uwf-test-nonexistent" },
12
+ stdio: ["ignore", "pipe", "pipe"],
13
+ });
14
+ return { stdout, stderr: "", exitCode: 0 };
15
+ }
16
+ catch (e) {
17
+ const err = e;
18
+ return {
19
+ stdout: err.stdout ?? "",
20
+ stderr: err.stderr ?? "",
21
+ exitCode: err.status ?? 1,
22
+ };
23
+ }
24
+ }
25
+ describe("thread exec --count CLI parsing", { timeout: 30_000 }, () => {
26
+ test("--help shows -c/--count option", () => {
27
+ const result = runCli(["thread", "exec", "--help"]);
28
+ const combined = result.stdout + result.stderr;
29
+ expect(combined).toContain("--count");
30
+ expect(combined).toContain("-c");
31
+ });
32
+ test("description says 'one or more steps'", () => {
33
+ const result = runCli(["thread", "exec", "--help"]);
34
+ const combined = result.stdout + result.stderr;
35
+ expect(combined).toContain("one or more steps");
36
+ });
37
+ });
38
+ describe("validateCount", () => {
39
+ test("count=0 throws validation error", () => {
40
+ expect(() => validateCount(0)).toThrow("positive integer");
41
+ });
42
+ test("negative count throws validation error", () => {
43
+ expect(() => validateCount(-1)).toThrow("positive integer");
44
+ });
45
+ test("non-integer count throws validation error", () => {
46
+ expect(() => validateCount(1.5)).toThrow("positive integer");
47
+ });
48
+ test("count=1 passes validation", () => {
49
+ expect(() => validateCount(1)).not.toThrow();
50
+ });
51
+ test("count=3 passes validation", () => {
52
+ expect(() => validateCount(3)).not.toThrow();
53
+ });
54
+ });
55
+ //# sourceMappingURL=thread-step-count.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-step-count.test.js","sourceRoot":"","sources":["../../src/__tests__/thread-step-count.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=thread-suspend-step.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-suspend-step.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/thread-suspend-step.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,155 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { putSchema } from "@ocas/core";
7
+ import { openStore } from "@ocas/fs";
8
+ import { afterEach, beforeEach, describe, expect, test } from "vitest";
9
+ import { cmdThreadShow } from "../commands/thread.js";
10
+ import { registerUwfSchemas } from "../schemas.js";
11
+ import { seedThreads } from "./thread-test-helpers.js";
12
+ const OUTPUT_SCHEMA = {
13
+ type: "object",
14
+ properties: {
15
+ $status: { type: "string" },
16
+ question: { type: "string" },
17
+ },
18
+ required: ["$status"],
19
+ additionalProperties: false,
20
+ };
21
+ let tmpDir;
22
+ beforeEach(async () => {
23
+ tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-suspend-step-test-"));
24
+ });
25
+ afterEach(async () => {
26
+ await rm(tmpDir, { recursive: true, force: true });
27
+ });
28
+ describe("suspend step CAS chain and threads.yaml metadata", () => {
29
+ test("thread exec records suspend step in CAS and suspend metadata in threads.yaml", async () => {
30
+ const casDir = join(tmpDir, "cas");
31
+ await mkdir(casDir, { recursive: true });
32
+ const originalCasDir = process.env.OCAS_HOME;
33
+ process.env.OCAS_HOME = casDir;
34
+ try {
35
+ const store = await openStore(casDir);
36
+ const schemas = await registerUwfSchemas(store);
37
+ const outputSchemaHash = await putSchema(store, OUTPUT_SCHEMA);
38
+ const workflowHash = await store.cas.put(schemas.workflow, {
39
+ name: "test-suspend-step",
40
+ description: "suspend step integration test",
41
+ roles: {
42
+ worker: {
43
+ description: "Worker role",
44
+ goal: "Work",
45
+ capabilities: [],
46
+ procedure: "work",
47
+ output: "result",
48
+ frontmatter: outputSchemaHash,
49
+ },
50
+ },
51
+ graph: {
52
+ $START: { _: { role: "worker", prompt: "Start work", location: null } },
53
+ worker: {
54
+ needs_input: {
55
+ role: "$SUSPEND",
56
+ prompt: "Please clarify: {{{question}}}",
57
+ location: null,
58
+ },
59
+ },
60
+ },
61
+ });
62
+ const startHash = await store.cas.put(schemas.startNode, {
63
+ workflow: workflowHash,
64
+ prompt: "Test suspend task",
65
+ cwd: tmpDir,
66
+ });
67
+ const threadId = "01SUSPENDSTEPTEST0000000";
68
+ await seedThreads(tmpDir, { [threadId]: startHash });
69
+ const outputHash = await store.cas.put(outputSchemaHash, {
70
+ $status: "needs_input",
71
+ question: "Which API?",
72
+ });
73
+ const detailHash = await store.cas.put(schemas.text, "mock detail");
74
+ const startedAtMs = 1716600000000;
75
+ const completedAtMs = 1716600001500;
76
+ const stepHash = await store.cas.put(schemas.stepNode, {
77
+ start: startHash,
78
+ prev: null,
79
+ role: "worker",
80
+ output: outputHash,
81
+ detail: detailHash,
82
+ agent: "uwf-mock",
83
+ edgePrompt: "Start work",
84
+ startedAtMs,
85
+ completedAtMs,
86
+ cwd: tmpDir,
87
+ assembledPrompt: null,
88
+ });
89
+ const mockAgentPath = join(tmpDir, "mock-agent.sh");
90
+ const adapterJson = JSON.stringify({
91
+ stepHash,
92
+ detailHash,
93
+ role: "worker",
94
+ frontmatter: { $status: "needs_input", question: "Which API?" },
95
+ body: "",
96
+ startedAtMs,
97
+ completedAtMs,
98
+ });
99
+ await writeFile(mockAgentPath, `#!/bin/sh\necho '${adapterJson}'\n`, { mode: 0o755 });
100
+ const configPath = join(tmpDir, "config.yaml");
101
+ await writeFile(configPath, `defaultAgent: uwf-hermes\ndefaultModel: test-model\nagentOverrides: null\nagents: {}\nproviders: {}\nmodels: {}\n`);
102
+ const cliPath = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "dist", "cli.js");
103
+ const stdout = execFileSync(process.execPath, [cliPath, "thread", "exec", threadId, "--agent", mockAgentPath], {
104
+ encoding: "utf8",
105
+ stdio: ["ignore", "pipe", "pipe"],
106
+ env: {
107
+ ...process.env,
108
+ UWF_HOME: tmpDir,
109
+ OCAS_HOME: casDir,
110
+ },
111
+ cwd: tmpDir,
112
+ timeout: 30000,
113
+ });
114
+ const cliOutput = JSON.parse(stdout.trim());
115
+ expect(cliOutput.status).toBe("suspended");
116
+ expect(cliOutput.head).toBe(stepHash);
117
+ expect(cliOutput.suspendedRole).toBe("worker");
118
+ expect(cliOutput.suspendMessage).toBe("Please clarify: Which API?");
119
+ const storeAfter = await openStore(casDir);
120
+ const stepNode = storeAfter.cas.get(cliOutput.head);
121
+ expect(stepNode).not.toBeNull();
122
+ const payload = stepNode.payload;
123
+ expect(payload.role).toBe("worker");
124
+ expect(payload.output).toBe(outputHash);
125
+ const outputNode = storeAfter.cas.get(outputHash);
126
+ expect(outputNode?.payload).toEqual({
127
+ $status: "needs_input",
128
+ question: "Which API?",
129
+ });
130
+ const { createUwfStore, getThread } = await import("../store.js");
131
+ const uwf = await createUwfStore(tmpDir);
132
+ const threadEntry = getThread(uwf.varStore, threadId);
133
+ expect(threadEntry).toEqual({
134
+ head: stepHash,
135
+ status: "suspended",
136
+ suspendedRole: "worker",
137
+ suspendMessage: "Please clarify: Which API?",
138
+ completedAt: null,
139
+ });
140
+ const showResult = await cmdThreadShow(tmpDir, threadId);
141
+ expect(showResult.status).toBe("suspended");
142
+ expect(showResult.suspendMessage).toBe("Please clarify: Which API?");
143
+ expect(showResult.suspendedRole).toBe("worker");
144
+ }
145
+ finally {
146
+ if (originalCasDir === undefined) {
147
+ delete process.env.OCAS_HOME;
148
+ }
149
+ else {
150
+ process.env.OCAS_HOME = originalCasDir;
151
+ }
152
+ }
153
+ });
154
+ });
155
+ //# sourceMappingURL=thread-suspend-step.test.js.map