@united-workforce/cli 0.3.0 → 0.5.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 (319) hide show
  1. package/README.md +45 -11
  2. package/dist/.build-fingerprint +1 -0
  3. package/dist/__tests__/adapter-json-roundtrip.test.js +17 -7
  4. package/dist/__tests__/adapter-json-roundtrip.test.js.map +1 -1
  5. package/dist/__tests__/agent-resolution-llm-free.test.d.ts +2 -0
  6. package/dist/__tests__/agent-resolution-llm-free.test.d.ts.map +1 -0
  7. package/dist/__tests__/agent-resolution-llm-free.test.js +30 -0
  8. package/dist/__tests__/agent-resolution-llm-free.test.js.map +1 -0
  9. package/dist/__tests__/build-step-entry.test.d.ts +2 -0
  10. package/dist/__tests__/build-step-entry.test.d.ts.map +1 -0
  11. package/dist/__tests__/build-step-entry.test.js +173 -0
  12. package/dist/__tests__/build-step-entry.test.js.map +1 -0
  13. package/dist/__tests__/clear-thread-failed-attempts.test.d.ts +2 -0
  14. package/dist/__tests__/clear-thread-failed-attempts.test.d.ts.map +1 -0
  15. package/dist/__tests__/clear-thread-failed-attempts.test.js +93 -0
  16. package/dist/__tests__/clear-thread-failed-attempts.test.js.map +1 -0
  17. package/dist/__tests__/concurrency.test.d.ts +2 -0
  18. package/dist/__tests__/concurrency.test.d.ts.map +1 -0
  19. package/dist/__tests__/concurrency.test.js +196 -0
  20. package/dist/__tests__/concurrency.test.js.map +1 -0
  21. package/dist/__tests__/config.test.js +26 -302
  22. package/dist/__tests__/config.test.js.map +1 -1
  23. package/dist/__tests__/current-role.test.js +7 -6
  24. package/dist/__tests__/current-role.test.js.map +1 -1
  25. package/dist/__tests__/e2e-mock-agent.test.js +43 -30
  26. package/dist/__tests__/e2e-mock-agent.test.js.map +1 -1
  27. package/dist/__tests__/format-text-default.test.d.ts +2 -0
  28. package/dist/__tests__/format-text-default.test.d.ts.map +1 -0
  29. package/dist/__tests__/format-text-default.test.js +43 -0
  30. package/dist/__tests__/format-text-default.test.js.map +1 -0
  31. package/dist/__tests__/format-text-registry.test.d.ts +2 -0
  32. package/dist/__tests__/format-text-registry.test.d.ts.map +1 -0
  33. package/dist/__tests__/format-text-registry.test.js +158 -0
  34. package/dist/__tests__/format-text-registry.test.js.map +1 -0
  35. package/dist/__tests__/issue-180-workflow-ref-removed.test.d.ts +2 -0
  36. package/dist/__tests__/issue-180-workflow-ref-removed.test.d.ts.map +1 -0
  37. package/dist/__tests__/issue-180-workflow-ref-removed.test.js +40 -0
  38. package/dist/__tests__/issue-180-workflow-ref-removed.test.js.map +1 -0
  39. package/dist/__tests__/log-text-renderer.test.d.ts +2 -0
  40. package/dist/__tests__/log-text-renderer.test.d.ts.map +1 -0
  41. package/dist/__tests__/log-text-renderer.test.js +265 -0
  42. package/dist/__tests__/log-text-renderer.test.js.map +1 -0
  43. package/dist/__tests__/moderator-evaluate.test.js +9 -50
  44. package/dist/__tests__/moderator-evaluate.test.js.map +1 -1
  45. package/dist/__tests__/output-mapper-thread-list-startedat.test.d.ts +2 -0
  46. package/dist/__tests__/output-mapper-thread-list-startedat.test.d.ts.map +1 -0
  47. package/dist/__tests__/output-mapper-thread-list-startedat.test.js +102 -0
  48. package/dist/__tests__/output-mapper-thread-list-startedat.test.js.map +1 -0
  49. package/dist/__tests__/output-mapper-workflow-add.test.d.ts +2 -0
  50. package/dist/__tests__/output-mapper-workflow-add.test.d.ts.map +1 -0
  51. package/dist/__tests__/output-mapper-workflow-add.test.js +22 -0
  52. package/dist/__tests__/output-mapper-workflow-add.test.js.map +1 -0
  53. package/dist/__tests__/pid-recycling.test.d.ts +2 -0
  54. package/dist/__tests__/pid-recycling.test.d.ts.map +1 -0
  55. package/dist/__tests__/pid-recycling.test.js +273 -0
  56. package/dist/__tests__/pid-recycling.test.js.map +1 -0
  57. package/dist/__tests__/prompt.test.js +365 -2
  58. package/dist/__tests__/prompt.test.js.map +1 -1
  59. package/dist/__tests__/resolve-head-hash.test.js +12 -4
  60. package/dist/__tests__/resolve-head-hash.test.js.map +1 -1
  61. package/dist/__tests__/setup-agent-discovery.test.js +21 -30
  62. package/dist/__tests__/setup-agent-discovery.test.js.map +1 -1
  63. package/dist/__tests__/setup-complexity.test.js +2 -168
  64. package/dist/__tests__/setup-complexity.test.js.map +1 -1
  65. package/dist/__tests__/setup-no-llm.test.d.ts +2 -0
  66. package/dist/__tests__/setup-no-llm.test.d.ts.map +1 -0
  67. package/dist/__tests__/setup-no-llm.test.js +52 -0
  68. package/dist/__tests__/setup-no-llm.test.js.map +1 -0
  69. package/dist/__tests__/solve-issue-tea-worktree.test.js +27 -28
  70. package/dist/__tests__/solve-issue-tea-worktree.test.js.map +1 -1
  71. package/dist/__tests__/step-ask.test.d.ts +2 -0
  72. package/dist/__tests__/step-ask.test.d.ts.map +1 -0
  73. package/dist/__tests__/step-ask.test.js +507 -0
  74. package/dist/__tests__/step-ask.test.js.map +1 -0
  75. package/dist/__tests__/step-show-json.test.js +1 -0
  76. package/dist/__tests__/step-show-json.test.js.map +1 -1
  77. package/dist/__tests__/step-timing.test.js +2 -0
  78. package/dist/__tests__/step-timing.test.js.map +1 -1
  79. package/dist/__tests__/store-global-cas.test.js +2 -2
  80. package/dist/__tests__/store-global-cas.test.js.map +1 -1
  81. package/dist/__tests__/store-unified-threads.test.js +28 -26
  82. package/dist/__tests__/store-unified-threads.test.js.map +1 -1
  83. package/dist/__tests__/thread-cancel-status.test.js +25 -19
  84. package/dist/__tests__/thread-cancel-status.test.js.map +1 -1
  85. package/dist/__tests__/thread-cancel-text-renderer.test.d.ts +2 -0
  86. package/dist/__tests__/thread-cancel-text-renderer.test.d.ts.map +1 -0
  87. package/dist/__tests__/thread-cancel-text-renderer.test.js +110 -0
  88. package/dist/__tests__/thread-cancel-text-renderer.test.js.map +1 -0
  89. package/dist/__tests__/thread-list-filters.test.js +354 -17
  90. package/dist/__tests__/thread-list-filters.test.js.map +1 -1
  91. package/dist/__tests__/thread-list-template-ms-date.test.d.ts +2 -0
  92. package/dist/__tests__/thread-list-template-ms-date.test.d.ts.map +1 -0
  93. package/dist/__tests__/thread-list-template-ms-date.test.js +102 -0
  94. package/dist/__tests__/thread-list-template-ms-date.test.js.map +1 -0
  95. package/dist/__tests__/thread-list-workflow-corrupt.test.d.ts +2 -0
  96. package/dist/__tests__/thread-list-workflow-corrupt.test.d.ts.map +1 -0
  97. package/dist/__tests__/thread-list-workflow-corrupt.test.js +157 -0
  98. package/dist/__tests__/thread-list-workflow-corrupt.test.js.map +1 -0
  99. package/dist/__tests__/thread-poke.test.d.ts +2 -0
  100. package/dist/__tests__/thread-poke.test.d.ts.map +1 -0
  101. package/dist/__tests__/thread-poke.test.js +422 -0
  102. package/dist/__tests__/thread-poke.test.js.map +1 -0
  103. package/dist/__tests__/thread-read-xml-tags.test.js +10 -9
  104. package/dist/__tests__/thread-read-xml-tags.test.js.map +1 -1
  105. package/dist/__tests__/thread-resume.test.js +21 -15
  106. package/dist/__tests__/thread-resume.test.js.map +1 -1
  107. package/dist/__tests__/thread-show-status.test.js +17 -28
  108. package/dist/__tests__/thread-show-status.test.js.map +1 -1
  109. package/dist/__tests__/thread-start-cwd-cli.test.js +15 -3
  110. package/dist/__tests__/thread-start-cwd-cli.test.js.map +1 -1
  111. package/dist/__tests__/thread-stop-text-renderer.test.d.ts +2 -0
  112. package/dist/__tests__/thread-stop-text-renderer.test.d.ts.map +1 -0
  113. package/dist/__tests__/thread-stop-text-renderer.test.js +148 -0
  114. package/dist/__tests__/thread-stop-text-renderer.test.js.map +1 -0
  115. package/dist/__tests__/thread-suspend-step.test.js +13 -16
  116. package/dist/__tests__/thread-suspend-step.test.js.map +1 -1
  117. package/dist/__tests__/thread-suspended-display.test.js +10 -22
  118. package/dist/__tests__/thread-suspended-display.test.js.map +1 -1
  119. package/dist/__tests__/thread-test-helpers.d.ts +7 -0
  120. package/dist/__tests__/thread-test-helpers.d.ts.map +1 -1
  121. package/dist/__tests__/thread-test-helpers.js +13 -0
  122. package/dist/__tests__/thread-test-helpers.js.map +1 -1
  123. package/dist/__tests__/thread.test.js +15 -13
  124. package/dist/__tests__/thread.test.js.map +1 -1
  125. package/dist/__tests__/validate-semantic.test.js +105 -23
  126. package/dist/__tests__/validate-semantic.test.js.map +1 -1
  127. package/dist/__tests__/workflow-list-recursive.test.d.ts +2 -0
  128. package/dist/__tests__/workflow-list-recursive.test.d.ts.map +1 -0
  129. package/dist/__tests__/workflow-list-recursive.test.js +286 -0
  130. package/dist/__tests__/workflow-list-recursive.test.js.map +1 -0
  131. package/dist/__tests__/workflow-resolution.test.js +46 -28
  132. package/dist/__tests__/workflow-resolution.test.js.map +1 -1
  133. package/dist/__tests__/workflow-show-resolution.test.d.ts +2 -0
  134. package/dist/__tests__/workflow-show-resolution.test.d.ts.map +1 -0
  135. package/dist/__tests__/workflow-show-resolution.test.js +213 -0
  136. package/dist/__tests__/workflow-show-resolution.test.js.map +1 -0
  137. package/dist/__tests__/workflow-validate.test.d.ts +2 -0
  138. package/dist/__tests__/workflow-validate.test.d.ts.map +1 -0
  139. package/dist/__tests__/workflow-validate.test.js +707 -0
  140. package/dist/__tests__/workflow-validate.test.js.map +1 -0
  141. package/dist/__tests__/write-envelope.test.d.ts +2 -0
  142. package/dist/__tests__/write-envelope.test.d.ts.map +1 -0
  143. package/dist/__tests__/write-envelope.test.js +201 -0
  144. package/dist/__tests__/write-envelope.test.js.map +1 -0
  145. package/dist/background/background.d.ts +22 -1
  146. package/dist/background/background.d.ts.map +1 -1
  147. package/dist/background/background.js +83 -6
  148. package/dist/background/background.js.map +1 -1
  149. package/dist/background/index.d.ts +1 -1
  150. package/dist/background/index.d.ts.map +1 -1
  151. package/dist/background/index.js +1 -1
  152. package/dist/background/index.js.map +1 -1
  153. package/dist/background/types.d.ts +1 -0
  154. package/dist/background/types.d.ts.map +1 -1
  155. package/dist/cli.js +120 -62
  156. package/dist/cli.js.map +1 -1
  157. package/dist/commands/config.d.ts +3 -1
  158. package/dist/commands/config.d.ts.map +1 -1
  159. package/dist/commands/config.js +17 -31
  160. package/dist/commands/config.js.map +1 -1
  161. package/dist/commands/prompt.d.ts.map +1 -1
  162. package/dist/commands/prompt.js +57 -31
  163. package/dist/commands/prompt.js.map +1 -1
  164. package/dist/commands/setup.d.ts +12 -39
  165. package/dist/commands/setup.d.ts.map +1 -1
  166. package/dist/commands/setup.js +72 -303
  167. package/dist/commands/setup.js.map +1 -1
  168. package/dist/commands/step.d.ts +44 -1
  169. package/dist/commands/step.d.ts.map +1 -1
  170. package/dist/commands/step.js +255 -11
  171. package/dist/commands/step.js.map +1 -1
  172. package/dist/commands/thread.d.ts +16 -3
  173. package/dist/commands/thread.d.ts.map +1 -1
  174. package/dist/commands/thread.js +423 -142
  175. package/dist/commands/thread.js.map +1 -1
  176. package/dist/commands/workflow.d.ts +9 -1
  177. package/dist/commands/workflow.d.ts.map +1 -1
  178. package/dist/commands/workflow.js +126 -6
  179. package/dist/commands/workflow.js.map +1 -1
  180. package/dist/concurrency/concurrency.d.ts +34 -0
  181. package/dist/concurrency/concurrency.d.ts.map +1 -0
  182. package/dist/concurrency/concurrency.js +216 -0
  183. package/dist/concurrency/concurrency.js.map +1 -0
  184. package/dist/concurrency/index.d.ts +3 -0
  185. package/dist/concurrency/index.d.ts.map +1 -0
  186. package/dist/concurrency/index.js +2 -0
  187. package/dist/concurrency/index.js.map +1 -0
  188. package/dist/concurrency/types.d.ts +19 -0
  189. package/dist/concurrency/types.d.ts.map +1 -0
  190. package/dist/concurrency/types.js +2 -0
  191. package/dist/concurrency/types.js.map +1 -0
  192. package/dist/format.d.ts +69 -2
  193. package/dist/format.d.ts.map +1 -1
  194. package/dist/format.js +198 -1
  195. package/dist/format.js.map +1 -1
  196. package/dist/moderator/__tests__/evaluate.test.js +31 -17
  197. package/dist/moderator/__tests__/evaluate.test.js.map +1 -1
  198. package/dist/moderator/evaluate.d.ts.map +1 -1
  199. package/dist/moderator/evaluate.js +4 -16
  200. package/dist/moderator/evaluate.js.map +1 -1
  201. package/dist/moderator/index.d.ts +1 -2
  202. package/dist/moderator/index.d.ts.map +1 -1
  203. package/dist/moderator/index.js +0 -1
  204. package/dist/moderator/index.js.map +1 -1
  205. package/dist/moderator/types.d.ts +6 -10
  206. package/dist/moderator/types.d.ts.map +1 -1
  207. package/dist/moderator/types.js +1 -3
  208. package/dist/moderator/types.js.map +1 -1
  209. package/dist/output-mappers.d.ts +122 -0
  210. package/dist/output-mappers.d.ts.map +1 -0
  211. package/dist/output-mappers.js +134 -0
  212. package/dist/output-mappers.js.map +1 -0
  213. package/dist/schemas.d.ts +6 -1
  214. package/dist/schemas.d.ts.map +1 -1
  215. package/dist/schemas.js +34 -5
  216. package/dist/schemas.js.map +1 -1
  217. package/dist/store.d.ts +28 -9
  218. package/dist/store.d.ts.map +1 -1
  219. package/dist/store.js +75 -16
  220. package/dist/store.js.map +1 -1
  221. package/dist/text-renderers.d.ts +30 -0
  222. package/dist/text-renderers.d.ts.map +1 -0
  223. package/dist/text-renderers.js +251 -0
  224. package/dist/text-renderers.js.map +1 -0
  225. package/dist/validate-semantic.d.ts.map +1 -1
  226. package/dist/validate-semantic.js +95 -61
  227. package/dist/validate-semantic.js.map +1 -1
  228. package/dist/validate.d.ts +6 -0
  229. package/dist/validate.d.ts.map +1 -1
  230. package/dist/validate.js +24 -0
  231. package/dist/validate.js.map +1 -1
  232. package/examples/brainstorm.yaml +130 -0
  233. package/examples/debate.yaml +169 -0
  234. package/examples/socratic-questioning.yaml +112 -0
  235. package/package.json +9 -10
  236. package/src/__tests__/adapter-json-roundtrip.test.ts +16 -7
  237. package/src/__tests__/agent-resolution-llm-free.test.ts +39 -0
  238. package/src/__tests__/build-step-entry.test.ts +203 -0
  239. package/src/__tests__/clear-thread-failed-attempts.test.ts +122 -0
  240. package/src/__tests__/concurrency.test.ts +266 -0
  241. package/src/__tests__/config.test.ts +33 -321
  242. package/src/__tests__/current-role.test.ts +7 -6
  243. package/src/__tests__/e2e-mock-agent.test.ts +65 -30
  244. package/src/__tests__/fixtures/e2e-count.workflow.yaml +1 -0
  245. package/src/__tests__/fixtures/e2e-linear.workflow.yaml +1 -0
  246. package/src/__tests__/fixtures/{e2e-mustache.workflow.yaml → e2e-liquid.workflow.yaml} +3 -2
  247. package/src/__tests__/fixtures/e2e-loop.workflow.yaml +1 -0
  248. package/src/__tests__/fixtures/e2e-suspend.mock.yaml +2 -2
  249. package/src/__tests__/fixtures/e2e-suspend.workflow.yaml +6 -10
  250. package/src/__tests__/format-text-default.test.ts +49 -0
  251. package/src/__tests__/format-text-registry.test.ts +173 -0
  252. package/src/__tests__/issue-180-workflow-ref-removed.test.ts +43 -0
  253. package/src/__tests__/log-text-renderer.test.ts +294 -0
  254. package/src/__tests__/moderator-evaluate.test.ts +9 -52
  255. package/src/__tests__/output-mapper-thread-list-startedat.test.ts +124 -0
  256. package/src/__tests__/output-mapper-workflow-add.test.ts +24 -0
  257. package/src/__tests__/pid-recycling.test.ts +329 -0
  258. package/src/__tests__/prompt.test.ts +443 -2
  259. package/src/__tests__/resolve-head-hash.test.ts +11 -4
  260. package/src/__tests__/setup-agent-discovery.test.ts +26 -51
  261. package/src/__tests__/setup-complexity.test.ts +1 -203
  262. package/src/__tests__/setup-no-llm.test.ts +68 -0
  263. package/src/__tests__/solve-issue-tea-worktree.test.ts +27 -31
  264. package/src/__tests__/step-ask.test.ts +677 -0
  265. package/src/__tests__/step-show-json.test.ts +1 -0
  266. package/src/__tests__/step-timing.test.ts +2 -0
  267. package/src/__tests__/store-global-cas.test.ts +2 -2
  268. package/src/__tests__/store-unified-threads.test.ts +30 -27
  269. package/src/__tests__/thread-cancel-status.test.ts +27 -20
  270. package/src/__tests__/thread-cancel-text-renderer.test.ts +125 -0
  271. package/src/__tests__/thread-list-filters.test.ts +443 -17
  272. package/src/__tests__/thread-list-template-ms-date.test.ts +110 -0
  273. package/src/__tests__/thread-list-workflow-corrupt.test.ts +198 -0
  274. package/src/__tests__/thread-poke.test.ts +554 -0
  275. package/src/__tests__/thread-read-xml-tags.test.ts +9 -11
  276. package/src/__tests__/thread-resume.test.ts +20 -15
  277. package/src/__tests__/thread-show-status.test.ts +17 -29
  278. package/src/__tests__/thread-start-cwd-cli.test.ts +15 -3
  279. package/src/__tests__/thread-stop-text-renderer.test.ts +168 -0
  280. package/src/__tests__/thread-suspend-step.test.ts +13 -16
  281. package/src/__tests__/thread-suspended-display.test.ts +10 -22
  282. package/src/__tests__/thread-test-helpers.ts +15 -1
  283. package/src/__tests__/thread.test.ts +14 -14
  284. package/src/__tests__/validate-semantic.test.ts +118 -33
  285. package/src/__tests__/workflow-list-recursive.test.ts +370 -0
  286. package/src/__tests__/workflow-resolution.test.ts +48 -29
  287. package/src/__tests__/workflow-show-resolution.test.ts +286 -0
  288. package/src/__tests__/workflow-validate.test.ts +828 -0
  289. package/src/__tests__/write-envelope.test.ts +257 -0
  290. package/src/background/background.ts +88 -6
  291. package/src/background/index.ts +2 -0
  292. package/src/background/types.ts +1 -0
  293. package/src/cli.ts +184 -77
  294. package/src/commands/config.ts +16 -33
  295. package/src/commands/prompt.ts +57 -31
  296. package/src/commands/setup.ts +80 -358
  297. package/src/commands/step.ts +339 -12
  298. package/src/commands/thread.ts +511 -171
  299. package/src/commands/workflow.ts +155 -4
  300. package/src/concurrency/concurrency.ts +245 -0
  301. package/src/concurrency/index.ts +10 -0
  302. package/src/concurrency/types.ts +19 -0
  303. package/src/format.ts +282 -2
  304. package/src/moderator/__tests__/evaluate.test.ts +34 -17
  305. package/src/moderator/evaluate.ts +5 -17
  306. package/src/moderator/index.ts +1 -6
  307. package/src/moderator/types.ts +6 -14
  308. package/src/output-mappers.ts +254 -0
  309. package/src/schemas.ts +51 -5
  310. package/src/store.ts +86 -20
  311. package/src/text-renderers.ts +355 -0
  312. package/src/validate-semantic.ts +125 -73
  313. package/src/validate.ts +27 -0
  314. package/dist/__tests__/setup-validate.test.d.ts +0 -2
  315. package/dist/__tests__/setup-validate.test.d.ts.map +0 -1
  316. package/dist/__tests__/setup-validate.test.js +0 -108
  317. package/dist/__tests__/setup-validate.test.js.map +0 -1
  318. package/src/__tests__/setup-validate.test.ts +0 -148
  319. /package/src/__tests__/fixtures/{e2e-mustache.mock.yaml → e2e-liquid.mock.yaml} +0 -0
package/src/cli.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env -S node --disable-warning=ExperimentalWarning
2
2
 
3
- import type { CasRef, ThreadId, ThreadStatus } from "@united-workforce/protocol";
3
+ import type { CasRef, OutputSchemaName, ThreadId, ThreadStatus } from "@united-workforce/protocol";
4
4
  import { Command } from "commander";
5
5
  import { cmdConfigGet, cmdConfigList, cmdConfigSet } from "./commands/config.js";
6
6
  import { cmdLogClean, cmdLogList, cmdLogShow } from "./commands/log.js";
@@ -11,12 +11,13 @@ import {
11
11
  cmdPromptUsage,
12
12
  cmdPromptWorkflowAuthoring,
13
13
  } from "./commands/prompt.js";
14
- import { cmdSetup, cmdSetupInteractive, resolvePresetBaseUrl } from "./commands/setup.js";
15
- import { cmdStepFork, cmdStepList, cmdStepRead, cmdStepShow } from "./commands/step.js";
14
+ import { cmdSetup, cmdSetupInteractive } from "./commands/setup.js";
15
+ import { cmdStepAsk, cmdStepFork, cmdStepList, cmdStepRead, cmdStepShow } from "./commands/step.js";
16
16
  import {
17
17
  cmdThreadCancel,
18
18
  cmdThreadExec,
19
19
  cmdThreadList,
20
+ cmdThreadPoke,
20
21
  cmdThreadRead,
21
22
  cmdThreadResume,
22
23
  cmdThreadShow,
@@ -25,13 +26,67 @@ import {
25
26
  THREAD_READ_DEFAULT_QUOTA,
26
27
  } from "./commands/thread.js";
27
28
  import { parseTimeInput } from "./commands/thread-time-parser.js";
28
- import { cmdWorkflowAdd, cmdWorkflowList, cmdWorkflowShow } from "./commands/workflow.js";
29
- import { formatOutput, type OutputFormat } from "./format.js";
30
- import { resolveStorageRoot } from "./store.js";
29
+ import {
30
+ cmdWorkflowAdd,
31
+ cmdWorkflowList,
32
+ cmdWorkflowShow,
33
+ cmdWorkflowValidate,
34
+ } from "./commands/workflow.js";
35
+ import {
36
+ formatOutput,
37
+ isOutputFormat,
38
+ type OutputFormat,
39
+ SUPPORTED_FORMATS,
40
+ writeEnvelope,
41
+ } from "./format.js";
42
+ import {
43
+ toStepDetailPayload,
44
+ toStepListPayload,
45
+ toThreadExecPayload,
46
+ toThreadListPayload,
47
+ toThreadStartPayload,
48
+ toThreadStatusPayload,
49
+ toValidateResultPayload,
50
+ toWorkflowAddPayload,
51
+ toWorkflowDetailPayload,
52
+ toWorkflowListPayload,
53
+ } from "./output-mappers.js";
54
+ import { createUwfStore, resolveStorageRoot } from "./store.js";
55
+
56
+ function getFormat(): OutputFormat {
57
+ const raw = program.opts().format as string;
58
+ if (!isOutputFormat(raw)) {
59
+ process.stderr.write(
60
+ `Invalid --format: ${raw}. Must be one of: ${SUPPORTED_FORMATS.join(", ")}\n`,
61
+ );
62
+ process.exit(1);
63
+ }
64
+ return raw;
65
+ }
66
+
67
+ async function writeOutput(
68
+ payload: unknown,
69
+ schemaName: OutputSchemaName,
70
+ storageRoot: string,
71
+ ): Promise<void> {
72
+ const fmt = getFormat();
73
+ const uwf = await createUwfStore(storageRoot);
74
+ await writeEnvelope(payload, schemaName, {
75
+ format: fmt,
76
+ store: uwf.store,
77
+ schemas: uwf.schemas,
78
+ });
79
+ }
31
80
 
32
- function writeOutput(data: unknown): void {
33
- const fmt = program.opts().format as OutputFormat;
34
- process.stdout.write(`${formatOutput(data, fmt)}\n`);
81
+ /**
82
+ * Legacy raw output for commands without an output schema (log/config/setup).
83
+ * Always emits text/JSON/YAML based on the active --format. For `text`
84
+ * (the default) it renders via the per-command registry when available
85
+ * and falls back to JSON.
86
+ */
87
+ function writeRawOutput(data: unknown, commandPath?: string): void {
88
+ const fmt = getFormat();
89
+ process.stdout.write(`${formatOutput(data, fmt, commandPath)}\n`);
35
90
  }
36
91
 
37
92
  function runAction(action: () => Promise<void>): void {
@@ -54,7 +109,11 @@ program
54
109
  " workflow → thread → step → turn",
55
110
  )
56
111
  .version(pkg.default.version, "-V, --version");
57
- program.option("--format <fmt>", "Output format: json or yaml", "json");
112
+ program.option(
113
+ "--format <fmt>",
114
+ "Output format: text (default), json, yaml, raw-json, raw-yaml",
115
+ "text",
116
+ );
58
117
 
59
118
  const workflow = program
60
119
  .command("workflow")
@@ -68,7 +127,22 @@ workflow
68
127
  const storageRoot = resolveStorageRoot();
69
128
  runAction(async () => {
70
129
  const result = await cmdWorkflowAdd(storageRoot, file);
71
- writeOutput(result);
130
+ await writeOutput(toWorkflowAddPayload(result), "workflow-add", storageRoot);
131
+ });
132
+ });
133
+
134
+ workflow
135
+ .command("validate")
136
+ .description("Validate a workflow YAML without registering it (CI-friendly)")
137
+ .argument("<file>", "Workflow YAML file")
138
+ .action((file: string) => {
139
+ const storageRoot = resolveStorageRoot();
140
+ runAction(async () => {
141
+ const errors = await cmdWorkflowValidate(file);
142
+ await writeOutput(toValidateResultPayload(errors), "validate-result", storageRoot);
143
+ if (errors.length > 0) {
144
+ process.exit(1);
145
+ }
72
146
  });
73
147
  });
74
148
 
@@ -79,8 +153,8 @@ workflow
79
153
  .action((id: string) => {
80
154
  const storageRoot = resolveStorageRoot();
81
155
  runAction(async () => {
82
- const result = await cmdWorkflowShow(storageRoot, id);
83
- writeOutput(result);
156
+ const result = await cmdWorkflowShow(storageRoot, id, process.cwd());
157
+ await writeOutput(toWorkflowDetailPayload(result), "workflow-detail", storageRoot);
84
158
  });
85
159
  });
86
160
 
@@ -91,7 +165,7 @@ workflow
91
165
  const storageRoot = resolveStorageRoot();
92
166
  runAction(async () => {
93
167
  const result = await cmdWorkflowList(storageRoot, process.cwd());
94
- writeOutput(result);
168
+ await writeOutput(toWorkflowListPayload(result), "workflow-list", storageRoot);
95
169
  });
96
170
  });
97
171
 
@@ -113,7 +187,7 @@ thread
113
187
  process.cwd(),
114
188
  opts.cwd ?? process.cwd(),
115
189
  );
116
- writeOutput(result);
190
+ await writeOutput(toThreadStartPayload(result), "thread-start", storageRoot);
117
191
  });
118
192
  });
119
193
 
@@ -150,11 +224,7 @@ thread
150
224
  background,
151
225
  backgroundWorker,
152
226
  );
153
- if (results.length === 1) {
154
- writeOutput(results[0]);
155
- } else {
156
- writeOutput(results);
157
- }
227
+ await writeOutput(toThreadExecPayload(results), "thread-exec", storageRoot);
158
228
  });
159
229
  },
160
230
  );
@@ -167,7 +237,7 @@ thread
167
237
  const storageRoot = resolveStorageRoot();
168
238
  runAction(async () => {
169
239
  const result = await cmdThreadShow(storageRoot, threadId);
170
- writeOutput(result);
240
+ await writeOutput(toThreadStatusPayload(result), "thread-status", storageRoot);
171
241
  });
172
242
  });
173
243
 
@@ -178,11 +248,18 @@ function parseStatusFilter(status: string | undefined): ThreadStatus[] | null {
178
248
  if (raw === "active") return ["idle", "running"];
179
249
 
180
250
  const parts = raw.split(",").map((s) => s.trim());
181
- const validStatuses: ThreadStatus[] = ["idle", "running", "suspended", "completed", "cancelled"];
251
+ const validStatuses: ThreadStatus[] = [
252
+ "idle",
253
+ "running",
254
+ "suspended",
255
+ "end",
256
+ "cancelled",
257
+ "corrupt",
258
+ ];
182
259
  for (const part of parts) {
183
260
  if (!validStatuses.includes(part as ThreadStatus)) {
184
261
  process.stderr.write(
185
- `Invalid status: ${part}. Must be one of: idle, running, suspended, completed, cancelled, active\n`,
262
+ `Invalid status: ${part}. Must be one of: idle, running, suspended, end, cancelled, active\n`,
186
263
  );
187
264
  process.exit(1);
188
265
  }
@@ -232,11 +309,12 @@ function parsePaginationOptions(
232
309
 
233
310
  thread
234
311
  .command("list")
235
- .description("List threads")
312
+ .description("List threads (defaults to active: idle + running + corrupt)")
236
313
  .option(
237
314
  "--status <status>",
238
- "Filter by status: idle, running, completed, cancelled, active (idle+running), or comma-separated values",
315
+ "Filter by status: idle, running, end, cancelled, active (idle+running), or comma-separated values",
239
316
  )
317
+ .option("--all", "Show all threads regardless of status (overrides default active-only filter)")
240
318
  .option("--after <date>", "Filter threads created after this date (ISO or relative like '7d')")
241
319
  .option("--before <date>", "Filter threads created before this date (ISO or relative like '7d')")
242
320
  .option("--skip <n>", "Skip first n threads")
@@ -244,6 +322,7 @@ thread
244
322
  .action(
245
323
  (opts: {
246
324
  status: string | undefined;
325
+ all: boolean | undefined;
247
326
  after: string | undefined;
248
327
  before: string | undefined;
249
328
  skip: string | undefined;
@@ -255,6 +334,7 @@ thread
255
334
  const nowMs = Date.now();
256
335
  const { afterMs, beforeMs } = parseTimeFilters(opts.after, opts.before, nowMs);
257
336
  const { skip, take } = parsePaginationOptions(opts.skip, opts.take);
337
+ const showAll = opts.all === true;
258
338
 
259
339
  const result = await cmdThreadList(
260
340
  storageRoot,
@@ -263,8 +343,9 @@ thread
263
343
  beforeMs,
264
344
  skip,
265
345
  take,
346
+ showAll,
266
347
  );
267
- writeOutput(result);
348
+ await writeOutput(toThreadListPayload(result), "thread-list", storageRoot);
268
349
  });
269
350
  },
270
351
  );
@@ -286,7 +367,27 @@ thread
286
367
  supplement,
287
368
  agentOverride,
288
369
  );
289
- writeOutput(result);
370
+ await writeOutput(toThreadStatusPayload(result), "thread-status", storageRoot);
371
+ });
372
+ });
373
+
374
+ thread
375
+ .command("poke")
376
+ .description("Re-run the head step's agent with a supplementary prompt (replaces head step)")
377
+ .argument("<thread-id>", "Thread ULID")
378
+ .requiredOption("-p, --prompt <text>", "Supplementary prompt for the agent")
379
+ .option("--agent <cmd>", "Override agent command (defaults to head step's agent)")
380
+ .action((threadId: string, opts: { prompt: string; agent: string | undefined }) => {
381
+ const storageRoot = resolveStorageRoot();
382
+ runAction(async () => {
383
+ const agentOverride = opts.agent ?? null;
384
+ const result = await cmdThreadPoke(
385
+ storageRoot,
386
+ threadId as ThreadId,
387
+ opts.prompt,
388
+ agentOverride,
389
+ );
390
+ await writeOutput(toThreadStatusPayload(result), "thread-status", storageRoot);
290
391
  });
291
392
  });
292
393
 
@@ -298,7 +399,7 @@ thread
298
399
  const storageRoot = resolveStorageRoot();
299
400
  runAction(async () => {
300
401
  const result = await cmdThreadStop(storageRoot, threadId);
301
- writeOutput(result);
402
+ writeRawOutput(result, "thread stop");
302
403
  });
303
404
  });
304
405
 
@@ -310,7 +411,7 @@ thread
310
411
  const storageRoot = resolveStorageRoot();
311
412
  runAction(async () => {
312
413
  const result = await cmdThreadCancel(storageRoot, threadId);
313
- writeOutput(result);
414
+ writeRawOutput(result, "thread cancel");
314
415
  });
315
416
  });
316
417
 
@@ -353,7 +454,7 @@ step
353
454
  const storageRoot = resolveStorageRoot();
354
455
  runAction(async () => {
355
456
  const result = await cmdStepList(storageRoot, threadId);
356
- writeOutput(result);
457
+ await writeOutput(toStepListPayload(result), "step-list", storageRoot);
357
458
  });
358
459
  });
359
460
 
@@ -365,10 +466,40 @@ step
365
466
  const storageRoot = resolveStorageRoot();
366
467
  runAction(async () => {
367
468
  const detail = await cmdStepShow(storageRoot, stepHash as CasRef);
368
- writeOutput(detail);
469
+ await writeOutput(
470
+ toStepDetailPayload(stepHash as CasRef, detail),
471
+ "step-detail",
472
+ storageRoot,
473
+ );
369
474
  });
370
475
  });
371
476
 
477
+ step
478
+ .command("ask")
479
+ .description(
480
+ "Ask a follow-up question to a historical step's agent (read-only; no thread mutation)",
481
+ )
482
+ .argument("<step-hash>", "CAS hash of the StepNode to query")
483
+ .requiredOption("-p, --prompt <text>", "Question to ask the step's agent")
484
+ .option("--agent <cmd>", "Override agent command (defaults to the step's recorded agent)")
485
+ .option(
486
+ "--no-fork",
487
+ "Skip session-fork; spawn the agent in a fresh ask session and inject the step's detail ref for context",
488
+ )
489
+ .action(
490
+ (stepHash: string, opts: { prompt: string; agent: string | undefined; fork: boolean }) => {
491
+ const storageRoot = resolveStorageRoot();
492
+ runAction(async () => {
493
+ const stdout = await cmdStepAsk(storageRoot, stepHash as CasRef, {
494
+ prompt: opts.prompt,
495
+ agentOverride: opts.agent ?? null,
496
+ fork: opts.fork,
497
+ });
498
+ process.stdout.write(stdout.endsWith("\n") ? stdout : `${stdout}\n`);
499
+ });
500
+ },
501
+ );
502
+
372
503
  step
373
504
  .command("read")
374
505
  .description("Read a step's turns as human-readable markdown")
@@ -401,7 +532,7 @@ step
401
532
  const storageRoot = resolveStorageRoot();
402
533
  runAction(async () => {
403
534
  const result = await cmdStepFork(storageRoot, stepHash as CasRef);
404
- writeOutput(result);
535
+ writeRawOutput(result);
405
536
  });
406
537
  });
407
538
 
@@ -542,46 +673,22 @@ prompt
542
673
 
543
674
  program
544
675
  .command("setup")
545
- .description("Configure provider, model, and agent. Run without options for interactive wizard.")
546
- .option("--provider <name>", "Provider name")
547
- .option("--base-url <url>", "OpenAI-compatible API base URL")
548
- .option("--api-key <key>", "API key")
549
- .option("--model <name>", "Default model name")
676
+ .description(
677
+ "Configure the default agent. Run without --agent for interactive wizard.\n" +
678
+ "Each adapter owns its own LLM configuration — the engine config is LLM-free.",
679
+ )
550
680
  .option("--agent <name>", "Default agent adapter (e.g. hermes → uwf-hermes)")
551
- .action(
552
- (opts: {
553
- provider?: string;
554
- baseUrl?: string;
555
- apiKey?: string;
556
- model?: string;
557
- agent?: string;
558
- }) => {
559
- const storageRoot = resolveStorageRoot();
560
- runAction(async () => {
561
- // Resolve preset base-url when provider is known but --base-url is omitted
562
- const resolvedBaseUrl =
563
- opts.baseUrl ??
564
- (opts.provider !== undefined ? resolvePresetBaseUrl(opts.provider) : null);
565
- if (opts.provider && resolvedBaseUrl && opts.apiKey && opts.model) {
566
- const result = await cmdSetup({
567
- provider: opts.provider,
568
- baseUrl: resolvedBaseUrl,
569
- apiKey: opts.apiKey,
570
- model: opts.model,
571
- agent: opts.agent ?? undefined,
572
- storageRoot,
573
- });
574
- writeOutput(result);
575
- } else if (!opts.provider && !opts.baseUrl && !opts.apiKey && !opts.model) {
576
- await cmdSetupInteractive(storageRoot);
577
- } else {
578
- throw new Error(
579
- "Non-interactive setup requires: --provider, --api-key, --model (--base-url is optional for preset providers)",
580
- );
581
- }
582
- });
583
- },
584
- );
681
+ .action((opts: { agent?: string }) => {
682
+ const storageRoot = resolveStorageRoot();
683
+ runAction(async () => {
684
+ if (opts.agent !== undefined && opts.agent !== "") {
685
+ const result = await cmdSetup({ agent: opts.agent, storageRoot });
686
+ writeRawOutput(result);
687
+ } else {
688
+ await cmdSetupInteractive(storageRoot);
689
+ }
690
+ });
691
+ });
585
692
 
586
693
  const log = program.command("log").description("Process-level debug logs");
587
694
 
@@ -592,7 +699,7 @@ log
592
699
  const storageRoot = resolveStorageRoot();
593
700
  runAction(async () => {
594
701
  const result = await cmdLogList(storageRoot);
595
- writeOutput(result);
702
+ writeRawOutput(result, "log list");
596
703
  });
597
704
  });
598
705
 
@@ -615,7 +722,7 @@ log
615
722
  process: opts.process ?? null,
616
723
  date: opts.date ?? null,
617
724
  });
618
- writeOutput(result);
725
+ writeRawOutput(result, "log show");
619
726
  });
620
727
  },
621
728
  );
@@ -628,7 +735,7 @@ log
628
735
  const storageRoot = resolveStorageRoot();
629
736
  runAction(async () => {
630
737
  const result = await cmdLogClean(storageRoot, opts.before);
631
- writeOutput(result);
738
+ writeRawOutput(result);
632
739
  });
633
740
  });
634
741
 
@@ -641,7 +748,7 @@ config
641
748
  const storageRoot = resolveStorageRoot();
642
749
  runAction(async () => {
643
750
  const result = await cmdConfigList(storageRoot);
644
- writeOutput(result);
751
+ writeRawOutput(result, "config list");
645
752
  });
646
753
  });
647
754
 
@@ -656,7 +763,7 @@ config
656
763
  const storageRoot = resolveStorageRoot();
657
764
  runAction(async () => {
658
765
  const result = await cmdConfigGet(storageRoot, key);
659
- writeOutput({ value: result });
766
+ writeRawOutput({ value: result }, "config get");
660
767
  });
661
768
  });
662
769
 
@@ -669,7 +776,7 @@ config
669
776
  const storageRoot = resolveStorageRoot();
670
777
  runAction(async () => {
671
778
  const result = await cmdConfigSet(storageRoot, key, value);
672
- writeOutput(result);
779
+ writeRawOutput(result, "config set");
673
780
  });
674
781
  });
675
782
 
@@ -3,20 +3,14 @@ import { join } from "node:path";
3
3
  import { parse, stringify } from "yaml";
4
4
 
5
5
  /**
6
- * Valid configuration key schema
6
+ * Valid configuration key schema. Engine config is LLM-free — providers,
7
+ * models, defaultModel, and modelOverrides are no longer accepted here.
8
+ * Each adapter owns its own LLM configuration.
7
9
  */
8
10
  const VALID_CONFIG_KEYS: Record<
9
11
  string,
10
12
  { nested: boolean; knownFields?: string[]; minDepth?: number }
11
13
  > = {
12
- providers: {
13
- nested: true,
14
- knownFields: ["baseUrl", "apiKey"],
15
- },
16
- models: {
17
- nested: true,
18
- knownFields: ["provider", "name"],
19
- },
20
14
  agents: {
21
15
  nested: true,
22
16
  knownFields: ["command", "args"],
@@ -26,14 +20,12 @@ const VALID_CONFIG_KEYS: Record<
26
20
  // agentOverrides.<workflowName>.<roleName> = agentAlias (string value)
27
21
  // No knownFields — workflow/role names are user-defined
28
22
  },
29
- modelOverrides: {
23
+ defaultAgent: { nested: false },
24
+ concurrency: {
30
25
  nested: true,
26
+ knownFields: ["maxRunning"],
31
27
  minDepth: 2,
32
- // modelOverrides.<scenario> = modelAlias (string value)
33
- // No knownFields — scenarios are user-defined
34
28
  },
35
- defaultAgent: { nested: false },
36
- defaultModel: { nested: false },
37
29
  };
38
30
 
39
31
  /**
@@ -175,27 +167,12 @@ export function setNestedValue(obj: Record<string, unknown>, path: string[], val
175
167
  }
176
168
 
177
169
  /**
178
- * Deep clone and mask all apiKey values in providers section
170
+ * Deep clone the config. Engine config is LLM-free, so there are no apiKey
171
+ * fields to mask — this function is preserved as a defensive deep-clone
172
+ * boundary used by `cmdConfigList`.
179
173
  */
180
174
  export function maskApiKeys(config: Record<string, unknown>): Record<string, unknown> {
181
- // Deep clone
182
- const cloned = JSON.parse(JSON.stringify(config)) as Record<string, unknown>;
183
-
184
- // Mask apiKey values in providers
185
- if (cloned.providers && typeof cloned.providers === "object") {
186
- const providers = cloned.providers as Record<string, unknown>;
187
- for (const providerName of Object.keys(providers)) {
188
- const provider = providers[providerName];
189
- if (provider && typeof provider === "object") {
190
- const providerObj = provider as Record<string, unknown>;
191
- if ("apiKey" in providerObj) {
192
- providerObj.apiKey = "***MASKED***";
193
- }
194
- }
195
- }
196
- }
197
-
198
- return cloned;
175
+ return JSON.parse(JSON.stringify(config)) as Record<string, unknown>;
199
176
  }
200
177
 
201
178
  /**
@@ -292,6 +269,12 @@ export async function cmdConfigSet(
292
269
  let parsedValue: unknown = value;
293
270
  if (lastSegment === "args") {
294
271
  parsedValue = parseArgsValue(value);
272
+ } else if (lastSegment === "maxRunning") {
273
+ const num = Number(value);
274
+ if (!Number.isInteger(num) || num < 1) {
275
+ throw new Error("Value for 'maxRunning' must be a positive integer");
276
+ }
277
+ parsedValue = num;
295
278
  }
296
279
 
297
280
  // Validate we're not setting a property on a non-object
@@ -148,44 +148,36 @@ pipx install 'hermes-agent[acp]'
148
148
  pip install -e '.[acp]'
149
149
  \`\`\`
150
150
 
151
- ### Step 2 — Configure provider and model
151
+ ### Step 2 — Configure default agent
152
152
 
153
- uwf needs an LLM provider to run agents. **Ask the user** for their provider, API key, and model, then run:
153
+ Run the interactive wizard:
154
154
 
155
155
  \`\`\`bash
156
- uwf setup --provider <name> --api-key <key> --model <model> --agent <adapter-command>
156
+ uwf setup
157
157
  \`\`\`
158
158
 
159
- **Note:** \`--agent\` takes the adapter **command name** (e.g. \`uwf-hermes\`), not the npm package name.
160
-
161
- **Preset providers** — when using a preset name, \`--base-url\` is auto-filled and can be omitted:
162
-
163
- | Provider | Name | Default base URL |
164
- |----------|------|-----------------|
165
- | OpenAI | \`openai\` | https://api.openai.com/v1 |
166
- | xAI | \`xai\` | https://api.x.ai/v1 |
167
- | OpenRouter | \`openrouter\` | https://openrouter.ai/api/v1 |
168
- | Venice | \`venice\` | https://api.venice.ai/api/v1 |
169
- | Dashscope | \`dashscope\` | https://dashscope.aliyuncs.com/compatible-mode/v1 |
170
- | DeepSeek | \`deepseek\` | https://api.deepseek.com/v1 |
171
- | SiliconFlow | \`siliconflow\` | https://api.siliconflow.cn/v1 |
172
- | VolcEngine | \`volcengine\` | https://ark.cn-beijing.volces.com/api/v3 |
173
- | Kimi (Moonshot) | \`kimi\` | https://api.moonshot.cn/v1 |
174
- | GLM (Zhipu AI) | \`glm\` | https://open.bigmodel.cn/api/paas/v4 |
175
- | StepFun | \`stepfun\` | https://api.stepfun.com/v1 |
176
- | MiniMax | \`minimax\` | https://api.minimax.io/v1 |
177
- | Ollama (local) | \`ollama\` | http://localhost:11434/v1 |
178
-
179
- For **non-preset providers**, you must specify \`--base-url\` manually.
180
-
181
- Example:
159
+ Or configure non-interactively:
160
+
182
161
  \`\`\`bash
183
- uwf setup --provider openrouter --api-key sk-or-... --model anthropic/claude-sonnet-4 --agent uwf-hermes
162
+ uwf setup --agent <adapter-command>
163
+ \`\`\`
164
+
165
+ **Note:** \`--agent\` takes the adapter **command name** (e.g. \`uwf-hermes\`, \`uwf-claude-code\`), not the npm package name.
166
+
167
+ Config is saved to \`~/.uwf/config.yaml\`:
168
+
169
+ \`\`\`yaml
170
+ agents:
171
+ hermes:
172
+ command: uwf-hermes
173
+ args: []
174
+ defaultAgent: hermes
175
+ agentOverrides: {}
184
176
  \`\`\`
185
177
 
186
- If the user doesn't know what to choose, suggest \`openrouter\` with \`anthropic/claude-sonnet-4\` as a sensible default.
178
+ **LLM configuration** is per-adapter each adapter manages its own provider, model, and API key settings independently (typically via environment variables like \`CLAUDE_MODEL\`, \`ANTHROPIC_API_KEY\`, etc.). The engine config (\`~/.uwf/config.yaml\`) is LLM-free.
187
179
 
188
- Config is saved to \`~/.uwf/config.yaml\`. Verify with \`cat ~/.uwf/config.yaml\`.
180
+ Verify with \`cat ~/.uwf/config.yaml\`.
189
181
 
190
182
  ### Step 3 — Install skills
191
183
 
@@ -241,7 +233,17 @@ uwf thread exec <thread-id>
241
233
  uwf thread show <thread-id>
242
234
  \`\`\`
243
235
 
244
- If the thread reaches \`$END\` with status \`completed\`, the setup is working.
236
+ If the thread reaches \`$END\` with status \`end\`, the setup is working.
237
+
238
+ To verify suspend/resume and poke:
239
+
240
+ \`\`\`bash
241
+ # After a role yields with $status: "$SUSPEND", resume the suspended thread:
242
+ uwf thread resume <thread-id> -p "Additional context for the agent"
243
+
244
+ # Re-run the head step's agent with a supplementary prompt (replaces head step):
245
+ uwf thread poke <thread-id> -p "Try again with this hint"
246
+ \`\`\`
245
247
 
246
248
  ## Scenario B: Upgrade from Previous Version
247
249
 
@@ -297,7 +299,7 @@ Check the changelog for breaking changes. Known migrations:
297
299
  resume: { role: planner, prompt: "Review previous run and continue." }
298
300
  \`\`\`
299
301
 
300
- Update all \`.workflow/\` and \`.workflows/\` YAML files in your projects. \`uwf workflow add\` will reject files with the old \`_\` syntax.
302
+ Update all \`.workflows/\` and \`.workflow/\` YAML files in your projects. \`uwf workflow add\` will reject files with the old \`_\` syntax.
301
303
 
302
304
  - **v0.2.1**: \`$status: { enum: [value] }\` → \`$status: { const: "value" }\`. The validator no longer accepts \`enum\` for \`$status\`. Update all workflow YAML files:
303
305
  \`\`\`yaml
@@ -310,6 +312,9 @@ Update all \`.workflow/\` and \`.workflows/\` YAML files in your projects. \`uwf
310
312
  # For multi-exit, use oneOf with const (unchanged)
311
313
  \`\`\`
312
314
 
315
+ - **v0.4.0**: Thread status \`completed\` → \`end\`. Update scripts that filter \`--status completed\` to use \`--status end\`. Legacy on-disk \`status: completed\` is normalized to \`end\` on read.
316
+ - **v0.4.0**: \`$SUSPEND\` is now an engine-level coroutine yield, not a graph target. Workflows that routed to \`role: "$SUSPEND"\` must emit \`$status: "$SUSPEND"\` with a \`reason\` from the role output instead. The thread becomes \`suspended\`; continue with \`uwf thread resume\`.
317
+
313
318
  ### Step 4 — Verify
314
319
 
315
320
  \`\`\`bash
@@ -326,5 +331,26 @@ uwf prompt workflow-authoring # workflow YAML design guide
326
331
  uwf prompt adapter-developing # building agent adapters
327
332
  uwf prompt bootstrap # this guide
328
333
  \`\`\`
334
+
335
+ ## What's next — introduce uwf to the user
336
+
337
+ After setup is complete, give the user a brief introduction to what uwf can do
338
+ and invite them to try it. Cover these three things:
339
+
340
+ 1. **Run workflows** — execute pre-built workflows to automate multi-step tasks.
341
+ Setup auto-registers example workflows, ready to use immediately.
342
+ 2. **Create workflows** — design custom YAML workflows for their own recurring tasks
343
+ (code review, issue triage, release pipelines, etc.). Use \`uwf prompt workflow-authoring\`
344
+ for the authoring guide.
345
+ 3. **Debug & improve workflows** — iterate on workflow definitions, inspect thread state
346
+ with \`uwf thread show\`, replay failed steps with \`uwf thread poke\`, and refine
347
+ role procedures based on real execution results.
348
+
349
+ **Discover & try built-in examples:**
350
+
351
+ Run \`uwf workflow list\` to see which workflows are registered (setup auto-registers
352
+ several built-in examples). Show the user what's available, then invite them to try
353
+ one — for instance, suggest a fun debate topic like "AI 是否会抢了人类的工作?" and
354
+ offer to kick it off for them.
329
355
  `;
330
356
  }