@united-workforce/cli 0.1.1 → 0.2.1-rc.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 (71) hide show
  1. package/dist/__tests__/adapter-json-roundtrip.test.js +4 -1
  2. package/dist/__tests__/adapter-json-roundtrip.test.js.map +1 -1
  3. package/dist/__tests__/current-role.test.js +15 -3
  4. package/dist/__tests__/current-role.test.js.map +1 -1
  5. package/dist/__tests__/moderator-evaluate.test.js +20 -4
  6. package/dist/__tests__/moderator-evaluate.test.js.map +1 -1
  7. package/dist/__tests__/prompt.test.js +30 -42
  8. package/dist/__tests__/prompt.test.js.map +1 -1
  9. package/dist/__tests__/step-timing.test.js +8 -2
  10. package/dist/__tests__/step-timing.test.js.map +1 -1
  11. package/dist/__tests__/thread-location.test.js +15 -3
  12. package/dist/__tests__/thread-location.test.js.map +1 -1
  13. package/dist/__tests__/thread-resume.test.js +21 -6
  14. package/dist/__tests__/thread-resume.test.js.map +1 -1
  15. package/dist/__tests__/thread-show-status.test.js +10 -2
  16. package/dist/__tests__/thread-show-status.test.js.map +1 -1
  17. package/dist/__tests__/thread-start-cwd-cli.test.js +5 -1
  18. package/dist/__tests__/thread-start-cwd-cli.test.js.map +1 -1
  19. package/dist/__tests__/thread-suspend-step.test.js +4 -1
  20. package/dist/__tests__/thread-suspend-step.test.js.map +1 -1
  21. package/dist/__tests__/thread-suspended-display.test.js +12 -3
  22. package/dist/__tests__/thread-suspended-display.test.js.map +1 -1
  23. package/dist/__tests__/validate-semantic.test.js +29 -12
  24. package/dist/__tests__/validate-semantic.test.js.map +1 -1
  25. package/dist/__tests__/workflow-resolution.test.js +4 -1
  26. package/dist/__tests__/workflow-resolution.test.js.map +1 -1
  27. package/dist/cli.js +5 -17
  28. package/dist/cli.js.map +1 -1
  29. package/dist/commands/prompt.d.ts +3 -4
  30. package/dist/commands/prompt.d.ts.map +1 -1
  31. package/dist/commands/prompt.js +120 -43
  32. package/dist/commands/prompt.js.map +1 -1
  33. package/dist/commands/thread.d.ts.map +1 -1
  34. package/dist/commands/thread.js +3 -7
  35. package/dist/commands/thread.js.map +1 -1
  36. package/dist/moderator/__tests__/evaluate.test.js +12 -12
  37. package/dist/moderator/__tests__/evaluate.test.js.map +1 -1
  38. package/dist/moderator/evaluate.d.ts.map +1 -1
  39. package/dist/moderator/evaluate.js +1 -7
  40. package/dist/moderator/evaluate.js.map +1 -1
  41. package/dist/validate-semantic.d.ts.map +1 -1
  42. package/dist/validate-semantic.js +4 -12
  43. package/dist/validate-semantic.js.map +1 -1
  44. package/dist/validate.js +3 -3
  45. package/dist/validate.js.map +1 -1
  46. package/package.json +3 -3
  47. package/src/__tests__/adapter-json-roundtrip.test.ts +4 -1
  48. package/src/__tests__/current-role.test.ts +15 -3
  49. package/src/__tests__/fixtures/e2e-count.workflow.yaml +2 -1
  50. package/src/__tests__/fixtures/e2e-linear.workflow.yaml +2 -1
  51. package/src/__tests__/fixtures/e2e-loop.workflow.yaml +2 -1
  52. package/src/__tests__/fixtures/e2e-mustache.workflow.yaml +2 -1
  53. package/src/__tests__/fixtures/e2e-suspend.workflow.yaml +2 -1
  54. package/src/__tests__/moderator-evaluate.test.ts +21 -4
  55. package/src/__tests__/prompt.test.ts +29 -46
  56. package/src/__tests__/step-timing.test.ts +8 -2
  57. package/src/__tests__/thread-location.test.ts +15 -3
  58. package/src/__tests__/thread-resume.test.ts +21 -6
  59. package/src/__tests__/thread-show-status.test.ts +10 -2
  60. package/src/__tests__/thread-start-cwd-cli.test.ts +5 -1
  61. package/src/__tests__/thread-suspend-step.test.ts +4 -1
  62. package/src/__tests__/thread-suspended-display.test.ts +12 -3
  63. package/src/__tests__/validate-semantic.test.ts +36 -16
  64. package/src/__tests__/workflow-resolution.test.ts +4 -1
  65. package/src/cli.ts +4 -20
  66. package/src/commands/prompt.ts +119 -44
  67. package/src/commands/thread.ts +3 -8
  68. package/src/moderator/__tests__/evaluate.test.ts +12 -12
  69. package/src/moderator/evaluate.ts +1 -6
  70. package/src/validate-semantic.ts +4 -13
  71. package/src/validate.ts +3 -3
@@ -57,10 +57,14 @@ roles:
57
57
  $status: { type: string, enum: ["ready"] }
58
58
  graph:
59
59
  $START:
60
- _:
60
+ new:
61
61
  role: planner
62
62
  prompt: "Plan the work"
63
63
  location: null
64
+ resume:
65
+ role: planner
66
+ prompt: "Resume the work"
67
+ location: null
64
68
  planner:
65
69
  ready:
66
70
  role: $END
@@ -113,10 +117,14 @@ roles:
113
117
  $status: { type: string, enum: ["ready"] }
114
118
  graph:
115
119
  $START:
116
- _:
120
+ new:
117
121
  role: planner
118
122
  prompt: "Plan"
119
123
  location: null
124
+ resume:
125
+ role: planner
126
+ prompt: "Resume"
127
+ location: null
120
128
  planner:
121
129
  ready:
122
130
  role: $END
@@ -156,10 +164,14 @@ roles:
156
164
  $status: { type: string, enum: ["ready"] }
157
165
  graph:
158
166
  $START:
159
- _:
167
+ new:
160
168
  role: planner
161
169
  prompt: "Plan"
162
170
  location: null
171
+ resume:
172
+ role: planner
173
+ prompt: "Resume"
174
+ location: null
163
175
  planner:
164
176
  ready:
165
177
  role: $END
@@ -70,7 +70,10 @@ async function setupSuspendedThread(mode: MockAgentMode): Promise<{
70
70
  },
71
71
  },
72
72
  graph: {
73
- $START: { _: { role: "worker", prompt: "Start work", location: null } },
73
+ $START: {
74
+ new: { role: "worker", prompt: "Start work", location: null },
75
+ resume: { role: "worker", prompt: "Resume the work", location: null },
76
+ },
74
77
  worker: {
75
78
  needs_input: {
76
79
  role: "$SUSPEND",
@@ -233,7 +236,10 @@ describe("uwf thread resume", () => {
233
236
  },
234
237
  },
235
238
  graph: {
236
- $START: { _: { role: "worker", prompt: "Start", location: null } },
239
+ $START: {
240
+ new: { role: "worker", prompt: "Start", location: null },
241
+ resume: { role: "worker", prompt: "Resume", location: null },
242
+ },
237
243
  worker: { done: { role: "$END", prompt: "Done", location: null } },
238
244
  },
239
245
  });
@@ -479,7 +485,10 @@ describe("uwf thread resume - completed threads", () => {
479
485
  },
480
486
  },
481
487
  graph: {
482
- $START: { _: { role: "worker", prompt: "Start work", location: null } },
488
+ $START: {
489
+ new: { role: "worker", prompt: "Start work", location: null },
490
+ resume: { role: "worker", prompt: "Resume the work", location: null },
491
+ },
483
492
  worker: { done: { role: "reviewer", prompt: "Review the work", location: null } },
484
493
  reviewer: { done: { role: "$END", prompt: "Done", location: null } },
485
494
  },
@@ -610,7 +619,7 @@ echo '${adapterJson}'
610
619
  expect(cliOutput.done).toBe(false);
611
620
 
612
621
  const capturedPrompt = await readFile(promptCapturePath, "utf8");
613
- expect(capturedPrompt).toContain("Previous run completed");
622
+ expect(capturedPrompt).toContain("Resume the work");
614
623
  expect(capturedPrompt).toContain("Additional context");
615
624
 
616
625
  const storeModule = await import("../store.js");
@@ -640,7 +649,10 @@ echo '${adapterJson}'
640
649
  },
641
650
  },
642
651
  graph: {
643
- $START: { _: { role: "worker", prompt: "Start", location: null } },
652
+ $START: {
653
+ new: { role: "worker", prompt: "Start", location: null },
654
+ resume: { role: "worker", prompt: "Resume", location: null },
655
+ },
644
656
  worker: { done: { role: "$END", prompt: "Done", location: null } },
645
657
  },
646
658
  });
@@ -688,7 +700,10 @@ echo '${adapterJson}'
688
700
  },
689
701
  },
690
702
  graph: {
691
- $START: { _: { role: "worker", prompt: "Start", location: null } },
703
+ $START: {
704
+ new: { role: "worker", prompt: "Start", location: null },
705
+ resume: { role: "worker", prompt: "Resume", location: null },
706
+ },
692
707
  worker: { done: { role: "$END", prompt: "Done", location: null } },
693
708
  },
694
709
  });
@@ -34,10 +34,14 @@ roles:
34
34
  $status: { type: string, enum: ["ready"] }
35
35
  graph:
36
36
  $START:
37
- _:
37
+ new:
38
38
  role: planner
39
39
  prompt: "Plan the work"
40
40
  location: null
41
+ resume:
42
+ role: planner
43
+ prompt: "Resume the work"
44
+ location: null
41
45
  planner:
42
46
  ready:
43
47
  role: $END
@@ -66,10 +70,14 @@ roles:
66
70
  question: { type: string }
67
71
  graph:
68
72
  $START:
69
- _:
73
+ new:
70
74
  role: worker
71
75
  prompt: "Start work"
72
76
  location: null
77
+ resume:
78
+ role: worker
79
+ prompt: "Resume work"
80
+ location: null
73
81
  worker:
74
82
  needs_input:
75
83
  role: $SUSPEND
@@ -57,10 +57,14 @@ roles:
57
57
  $status: { type: string, enum: ["ready"] }
58
58
  graph:
59
59
  $START:
60
- _:
60
+ new:
61
61
  role: planner
62
62
  prompt: "Plan the work"
63
63
  location: null
64
+ resume:
65
+ role: planner
66
+ prompt: "Resume the work"
67
+ location: null
64
68
  planner:
65
69
  ready:
66
70
  role: $END
@@ -58,7 +58,10 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
58
58
  },
59
59
  },
60
60
  graph: {
61
- $START: { _: { role: "worker", prompt: "Start work", location: null } },
61
+ $START: {
62
+ new: { role: "worker", prompt: "Start work", location: null },
63
+ resume: { role: "worker", prompt: "Resume work", location: null },
64
+ },
62
65
  worker: {
63
66
  needs_input: {
64
67
  role: "$SUSPEND",
@@ -55,7 +55,10 @@ describe("suspended thread display", () => {
55
55
  },
56
56
  },
57
57
  graph: {
58
- $START: { _: { role: "worker", prompt: "Start work", location: null } },
58
+ $START: {
59
+ new: { role: "worker", prompt: "Start work", location: null },
60
+ resume: { role: "worker", prompt: "Resume work", location: null },
61
+ },
59
62
  worker: {
60
63
  needs_input: {
61
64
  role: "$SUSPEND",
@@ -162,7 +165,10 @@ describe("suspended thread display", () => {
162
165
  },
163
166
  },
164
167
  graph: {
165
- $START: { _: { role: "worker", prompt: "Start work", location: null } },
168
+ $START: {
169
+ new: { role: "worker", prompt: "Start work", location: null },
170
+ resume: { role: "worker", prompt: "Resume work", location: null },
171
+ },
166
172
  worker: {
167
173
  needs_input: {
168
174
  role: "$SUSPEND",
@@ -248,7 +254,10 @@ describe("suspended thread display", () => {
248
254
  },
249
255
  },
250
256
  graph: {
251
- $START: { _: { role: "worker", prompt: "Start work", location: null } },
257
+ $START: {
258
+ new: { role: "worker", prompt: "Start work", location: null },
259
+ resume: { role: "worker", prompt: "Resume work", location: null },
260
+ },
252
261
  },
253
262
  });
254
263
 
@@ -51,7 +51,10 @@ function makeWorkflow(overrides?: Partial<WorkflowPayload>): WorkflowPayload {
51
51
  },
52
52
  },
53
53
  graph: {
54
- $START: { _: { role: "writer", prompt: "Begin writing", location: null } },
54
+ $START: {
55
+ new: { role: "writer", prompt: "Begin writing", location: null },
56
+ resume: { role: "writer", prompt: "Review previous output and continue", location: null },
57
+ },
55
58
  writer: { done: { role: "reviewer", prompt: "Review this: {{{plan}}}", location: null } },
56
59
  reviewer: {
57
60
  approved: { role: "$END", prompt: "Done: {{{summary}}}", location: null },
@@ -135,27 +138,38 @@ describe("Suite 2: Graph Structure", () => {
135
138
  expect(errors.some((e) => e.includes("$START must be defined in graph"))).toBe(true);
136
139
  });
137
140
 
138
- test("2.2 $START has multiple status keys", () => {
141
+ test("2.2 $START missing resume edge", () => {
139
142
  const wf = makeWorkflow();
140
143
  wf.graph.$START = {
141
- _: { role: "writer", prompt: "Begin", location: null },
142
- other: { role: "reviewer", prompt: "Also", location: null },
144
+ new: { role: "writer", prompt: "Begin", location: null },
143
145
  };
144
146
  const errors = validateWorkflow(wf);
145
147
  expect(
146
- errors.some((e) => e.includes('$START must have exactly one edge with status "_"')),
148
+ errors.some((e) => e.includes('$START must have edges with statuses "new" and "resume"')),
147
149
  ).toBe(true);
148
150
  });
149
151
 
150
- test("2.3 $START edge uses non-_ status", () => {
152
+ test("2.3 $START missing new edge", () => {
151
153
  const wf = makeWorkflow();
152
- wf.graph.$START = { ready: { role: "writer", prompt: "Begin", location: null } };
154
+ wf.graph.$START = {
155
+ resume: { role: "writer", prompt: "Resume", location: null },
156
+ };
153
157
  const errors = validateWorkflow(wf);
154
158
  expect(
155
- errors.some((e) => e.includes('$START must have exactly one edge with status "_"')),
159
+ errors.some((e) => e.includes('$START must have edges with statuses "new" and "resume"')),
156
160
  ).toBe(true);
157
161
  });
158
162
 
163
+ test("2.3b $START with new and resume passes", () => {
164
+ const wf = makeWorkflow();
165
+ wf.graph.$START = {
166
+ new: { role: "writer", prompt: "Begin", location: null },
167
+ resume: { role: "writer", prompt: "Resume", location: null },
168
+ };
169
+ const errors = validateWorkflow(wf);
170
+ expect(errors.some((e) => e.includes("$START must have edges"))).toBe(false);
171
+ });
172
+
159
173
  test("2.4 $END has outgoing edges", () => {
160
174
  const wf = makeWorkflow();
161
175
  wf.graph.$END = { _: { role: "writer", prompt: "Loop", location: null } };
@@ -193,15 +207,18 @@ describe("Suite 2: Graph Structure", () => {
193
207
  });
194
208
 
195
209
  describe("Suite 3: Status-Edge Consistency", () => {
196
- test("3.1 user role using _ graph key is rejected", () => {
210
+ test("3.1 user role using _ graph key is treated as an unknown status", () => {
211
+ // "_" is no longer special-cased — it's just a status key that does not
212
+ // match the role's $status enum, so it surfaces as extra/missing keys.
197
213
  const wf = makeWorkflow();
198
214
  wf.graph.writer = { _: { role: "reviewer", prompt: "Review", location: null } };
199
215
  const errors = validateWorkflow(wf);
200
- expect(
201
- errors.some((e) =>
202
- e.includes('role "writer" must use explicit $status keys in graph, not "_"'),
203
- ),
204
- ).toBe(true);
216
+ expect(errors.some((e) => e.includes('role "writer" graph has extra status keys: _'))).toBe(
217
+ true,
218
+ );
219
+ expect(errors.some((e) => e.includes('role "writer" graph is missing status keys: done'))).toBe(
220
+ true,
221
+ );
205
222
  });
206
223
 
207
224
  test("3.2 user role graph key not matching $status enum", () => {
@@ -240,13 +257,16 @@ describe("Suite 3: Status-Edge Consistency", () => {
240
257
  ).toBe(true);
241
258
  });
242
259
 
243
- test("3.5 multi-exit role with _ key", () => {
260
+ test("3.5 multi-exit role with _ key is treated as an unknown status", () => {
244
261
  const wf = makeWorkflow();
245
262
  wf.graph.reviewer = { _: { role: "$END", prompt: "Done", location: null } };
246
263
  const errors = validateWorkflow(wf);
264
+ expect(errors.some((e) => e.includes('role "reviewer" graph has extra status keys: _'))).toBe(
265
+ true,
266
+ );
247
267
  expect(
248
268
  errors.some((e) =>
249
- e.includes('role "reviewer" must use explicit $status keys in graph, not "_"'),
269
+ e.includes('role "reviewer" graph is missing status keys: approved, rejected'),
250
270
  ),
251
271
  ).toBe(true);
252
272
  });
@@ -38,7 +38,10 @@ function makeMinimalPayload(name: string, description: string): WorkflowPayload
38
38
  },
39
39
  },
40
40
  graph: {
41
- $START: { _: { role: "worker", prompt: "start working", location: null } },
41
+ $START: {
42
+ new: { role: "worker", prompt: "start working", location: null },
43
+ resume: { role: "worker", prompt: "resume working", location: null },
44
+ },
42
45
  worker: { done: { role: "$END", prompt: "done", location: null } },
43
46
  },
44
47
  };
package/src/cli.ts CHANGED
@@ -8,9 +8,7 @@ import {
8
8
  cmdPromptAdapterDeveloping,
9
9
  cmdPromptBootstrap,
10
10
  cmdPromptList,
11
- cmdPromptSetup,
12
11
  cmdPromptUsage,
13
- cmdPromptUsageReference,
14
12
  cmdPromptWorkflowAuthoring,
15
13
  } from "./commands/prompt.js";
16
14
  import { cmdSetup, cmdSetupInteractive } from "./commands/setup.js";
@@ -509,23 +507,16 @@ prompt.addHelpCommand(false);
509
507
 
510
508
  prompt
511
509
  .command("usage")
512
- .description("Print the complete skill content (all references combined)")
510
+ .description("Print the usage reference (CLI guide + typical workflows)")
513
511
  .action(() => {
514
512
  console.log(cmdPromptUsage());
515
513
  });
516
514
 
517
515
  prompt
518
- .command("setup")
519
- .description("Print setup instructions for installing the uwf skill")
520
- .action(() => {
521
- console.log(cmdPromptSetup());
522
- });
523
-
524
- prompt
525
- .command("usage-reference")
526
- .description("Print the usage reference (CLI guide + typical workflows)")
516
+ .command("bootstrap")
517
+ .description("Print setup instructions for installing uwf skills")
527
518
  .action(() => {
528
- console.log(cmdPromptUsageReference());
519
+ console.log(cmdPromptBootstrap());
529
520
  });
530
521
 
531
522
  prompt
@@ -542,13 +533,6 @@ prompt
542
533
  console.log(cmdPromptAdapterDeveloping());
543
534
  });
544
535
 
545
- prompt
546
- .command("bootstrap")
547
- .description("Print the bootstrap skill YAML for Hermes agents")
548
- .action(() => {
549
- console.log(cmdPromptBootstrap());
550
- });
551
-
552
536
  prompt
553
537
  .command("list")
554
538
  .description("List all available prompt names")
@@ -1,14 +1,13 @@
1
1
  import {
2
2
  generateAdapterDevelopingReference,
3
- generateBootstrapReference,
4
3
  generateUsageReference,
5
4
  generateWorkflowAuthoringReference,
5
+ VERSION,
6
6
  } from "@united-workforce/util";
7
7
 
8
8
  export {
9
9
  generateAdapterDevelopingReference as cmdPromptAdapterDeveloping,
10
- generateBootstrapReference as cmdPromptBootstrap,
11
- generateUsageReference as cmdPromptUsageReference,
10
+ generateUsageReference as cmdPromptUsage,
12
11
  generateWorkflowAuthoringReference as cmdPromptWorkflowAuthoring,
13
12
  };
14
13
 
@@ -16,66 +15,142 @@ const PROMPT_ENTRIES: ReadonlyArray<{ name: string; generate: () => string }> =
16
15
  { name: "usage", generate: generateUsageReference },
17
16
  { name: "workflow-authoring", generate: generateWorkflowAuthoringReference },
18
17
  { name: "adapter-developing", generate: generateAdapterDevelopingReference },
19
- { name: "bootstrap", generate: generateBootstrapReference },
20
18
  ];
21
19
 
22
20
  export function cmdPromptList(): ReadonlyArray<string> {
23
21
  return PROMPT_ENTRIES.map((e) => e.name);
24
22
  }
25
23
 
26
- export function cmdPromptUsage(): string {
27
- return PROMPT_ENTRIES.filter((e) => e.name !== "bootstrap")
28
- .map((e) => e.generate())
29
- .join("\n\n---\n\n");
30
- }
24
+ export function cmdPromptBootstrap(): string {
25
+ return `# uwf Bootstrap
26
+
27
+ Set up or upgrade uwf (United Workforce) — from zero to running your first workflow.
28
+
29
+ ## Scenario A: Fresh Install
30
+
31
+ ### Step 1 — Install CLI and agent adapter
32
+
33
+ \`\`\`bash
34
+ npm install -g @united-workforce/cli
35
+ uwf --version # should print ${VERSION}
36
+ \`\`\`
37
+
38
+ Install an agent adapter (at least one is required):
39
+
40
+ | Adapter | Install | When to use |
41
+ |---------|---------|-------------|
42
+ | uwf-hermes | \`npm install -g @united-workforce/agent-hermes\` | When your agent framework is Hermes Agent |
43
+ | uwf-claude-code | \`npm install -g @united-workforce/agent-claude-code\` | When using Claude Code CLI directly |
44
+ | uwf-builtin | \`npm install -g @united-workforce/agent-builtin\` | Lightweight built-in agent (no external dependency) |
45
+
46
+ Verify the adapter is installed: \`uwf-hermes --version\` (or whichever you chose).
47
+
48
+ ### Step 2 — Configure provider and model
49
+
50
+ uwf needs an LLM provider to run agents. **Ask the user** for their provider, API key, and model, then run:
51
+
52
+ \`\`\`bash
53
+ uwf setup --provider <name> --base-url <url> --api-key <key> --model <model> [--agent <adapter>]
54
+ \`\`\`
55
+
56
+ Preset providers (base-url is auto-filled when using a preset name):
57
+ openai, xai, openrouter, venice, dashscope, deepseek, siliconflow, volcengine, kimi, glm, stepfun, minimax, ollama
58
+
59
+ Example:
60
+ \`\`\`bash
61
+ uwf setup --provider openrouter --api-key sk-or-... --model anthropic/claude-sonnet-4 --agent uwf-hermes
62
+ \`\`\`
63
+
64
+ If the user doesn't know what to choose, suggest \`openrouter\` with \`anthropic/claude-sonnet-4\` as a sensible default.
65
+
66
+ Config is saved to \`~/.uwf/config.yaml\`. Verify with \`cat ~/.uwf/config.yaml\`.
67
+
68
+ ### Step 3 — Install skills
69
+
70
+ Run each command and create a skill from its output:
31
71
 
32
- export function cmdPromptSetup(): string {
33
- return `# uwf Skill Setup
72
+ \`\`\`bash
73
+ uwf prompt usage # save as skill "uwf-usage"
74
+ uwf prompt workflow-authoring # → save as skill "uwf-workflow-authoring"
75
+ uwf prompt adapter-developing # → save as skill "uwf-adapter-developing"
76
+ \`\`\`
77
+
78
+ Each command outputs a complete SKILL.md with YAML frontmatter. Use your agent framework's skill creation API to save them (e.g. \`skill_manage(action='create', name='uwf-usage', content=<output>)\`).
79
+
80
+ Verify skills are installed by listing them (e.g. \`skills_list()\`) and confirming all three appear.
81
+
82
+ ### Step 4 — Verify end-to-end
83
+
84
+ Run a quick smoke test with the built-in eval workflow:
34
85
 
35
- You are being asked to install or update the uwf (United Workforce) skill
36
- so that you know how to use the \`uwf\` CLI for workflow orchestration.
86
+ \`\`\`bash
87
+ # Start a thread with the example workflow
88
+ uwf thread start examples/eval-simple.yaml -p "Hello, test run"
89
+
90
+ # Execute one step
91
+ uwf thread exec <thread-id>
92
+
93
+ # Check result
94
+ uwf thread show <thread-id>
95
+ \`\`\`
37
96
 
38
- ## Steps
97
+ If the thread reaches \`$END\` or produces output, the setup is working.
39
98
 
40
- 1. **Check if uwf CLI is installed:**
41
- \`\`\`bash
42
- uwf --help
43
- \`\`\`
44
- If not installed: \`npm install -g @united-workforce/cli\`
99
+ ## Scenario B: Upgrade from Previous Version
45
100
 
46
- 2. **Clean up old versions of the skill** (if any exist):
47
- - Look for any existing uwf/workflow skill files in your skill directories
48
- (e.g. \`~/.hermes/skills/uwf/SKILL.md\` or similar paths).
49
- - If a skill exists, read its \`version\` from the YAML frontmatter.
50
- - If the version matches the current CLI version (\`uwf --version\`), you're done — no update needed.
51
- - If the version is older, **delete the old skill file** before proceeding.
101
+ ### Step 1 Update packages
52
102
 
53
- 3. **Install the bootstrap skill:**
54
- \`\`\`bash
55
- uwf prompt bootstrap > ~/.hermes/skills/uwf/SKILL.md
56
- \`\`\`
57
- The bootstrap prompt already includes complete YAML frontmatter — no editing needed.
103
+ \`\`\`bash
104
+ npm install -g @united-workforce/cli@latest
105
+ uwf --version # should print ${VERSION}
58
106
 
59
- 4. **Verify** the skill is loadable by your agent framework.
107
+ # Also update your adapter(s)
108
+ npm install -g @united-workforce/agent-hermes@latest
109
+ \`\`\`
60
110
 
61
- ## Individual prompts
111
+ ### Step 2 — Regenerate skills
62
112
 
63
- Each prompt outputs a complete SKILL.md with frontmatter pipe directly to a file:
113
+ Skill content is bundled with the CLIalways regenerate after upgrading:
64
114
 
65
115
  \`\`\`bash
66
- uwf prompt list # list available prompt names
67
- uwf prompt usage > ~/.hermes/skills/uwf-usage/SKILL.md # CLI usage guide
68
- uwf prompt workflow-authoring > ~/.hermes/skills/uwf-workflow-authoring/SKILL.md
69
- uwf prompt adapter-developing > ~/.hermes/skills/uwf-adapter-developing/SKILL.md
70
- uwf prompt bootstrap > ~/.hermes/skills/uwf/SKILL.md # bootstrap skill
116
+ uwf prompt usage # update skill "uwf-usage"
117
+ uwf prompt workflow-authoring # update skill "uwf-workflow-authoring"
118
+ uwf prompt adapter-developing # update skill "uwf-adapter-developing"
71
119
  \`\`\`
72
120
 
73
- ## Notes
121
+ ### Step 3 — Migrate workflow YAML files (if needed)
74
122
 
75
- - The skill content is bundled with the CLI and versioned with it — always use
76
- \`uwf prompt usage\` to get the content matching your installed version.
77
- - Do NOT hand-edit the skill body. If the CLI is updated, re-run \`uwf prompt setup\`
78
- and follow the steps again.
79
- - When upgrading, always delete the old skill first to avoid stale instructions.
123
+ Check the changelog for breaking changes. Known migrations:
124
+
125
+ - **v0.2.0**: \`$START._\` \`$START.new\` + \`$START.resume\`. All workflow YAML files must be updated:
126
+ \`\`\`yaml
127
+ # Before (v0.1.x)
128
+ $START:
129
+ _: { role: planner, prompt: "..." }
130
+
131
+ # After (v0.2.0+)
132
+ $START:
133
+ new: { role: planner, prompt: "..." }
134
+ resume: { role: planner, prompt: "Review previous run and continue." }
135
+ \`\`\`
136
+
137
+ Update all \`.workflow/\` and \`.workflows/\` YAML files in your projects. \`uwf workflow add\` will reject files with the old \`_\` syntax.
138
+
139
+ ### Step 4 — Verify
140
+
141
+ \`\`\`bash
142
+ uwf thread start <your-workflow> -p "upgrade test"
143
+ uwf thread exec <thread-id>
144
+ \`\`\`
145
+
146
+ ## Available prompts
147
+
148
+ \`\`\`bash
149
+ uwf prompt list # list available prompt names
150
+ uwf prompt usage # CLI usage guide
151
+ uwf prompt workflow-authoring # workflow YAML design guide
152
+ uwf prompt adapter-developing # building agent adapters
153
+ uwf prompt bootstrap # this guide
154
+ \`\`\`
80
155
  `;
81
156
  }
@@ -911,7 +911,7 @@ function resolveEvaluateArgs(
911
911
  chain: ChainState,
912
912
  ): { lastRole: string; lastOutput: EvaluateLastOutput } {
913
913
  if (chain.headIsStart) {
914
- return { lastRole: START_ROLE, lastOutput: { [STATUS_KEY]: "_" } };
914
+ return { lastRole: START_ROLE, lastOutput: { [STATUS_KEY]: "new" } };
915
915
  }
916
916
 
917
917
  const lastStep = chain.stepsNewestFirst[0];
@@ -1037,7 +1037,6 @@ function archiveThread(uwf: UwfStore, threadId: ThreadId, _workflow: CasRef, _he
1037
1037
  completeThread(uwf.varStore, threadId, "completed");
1038
1038
  }
1039
1039
 
1040
- // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: orchestration function with inherent branching
1041
1040
  export async function cmdThreadResume(
1042
1041
  storageRoot: string,
1043
1042
  threadId: ThreadId,
@@ -1101,7 +1100,7 @@ export async function cmdThreadResume(
1101
1100
 
1102
1101
  // status === "completed"
1103
1102
  const workflow = loadWorkflowPayload(uwf, workflowHash);
1104
- const startResult = evaluate(workflow.graph, START_ROLE, {});
1103
+ const startResult = evaluate(workflow.graph, START_ROLE, { [STATUS_KEY]: "resume" });
1105
1104
  if (!startResult.ok) {
1106
1105
  fail(`failed to evaluate $START: ${startResult.error.message}`);
1107
1106
  }
@@ -1113,11 +1112,7 @@ export async function cmdThreadResume(
1113
1112
  }
1114
1113
 
1115
1114
  const startRole = startResult.value.role;
1116
- const completedPromptPrefix = "Previous run completed. Resuming with additional context.";
1117
- const completedResumePrompt =
1118
- supplement !== null && supplement !== ""
1119
- ? `${completedPromptPrefix}\n\n${supplement}`
1120
- : completedPromptPrefix;
1115
+ const completedResumePrompt = buildResumePrompt(startResult.value.prompt, supplement);
1121
1116
 
1122
1117
  const updatedEntry = { ...entry, status: "idle" as const, completedAt: null };
1123
1118
  setThread(uwf.varStore, threadId, updatedEntry);