@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.
- package/README.md +45 -11
- package/dist/.build-fingerprint +1 -0
- package/dist/__tests__/adapter-json-roundtrip.test.js +17 -7
- package/dist/__tests__/adapter-json-roundtrip.test.js.map +1 -1
- package/dist/__tests__/agent-resolution-llm-free.test.d.ts +2 -0
- package/dist/__tests__/agent-resolution-llm-free.test.d.ts.map +1 -0
- package/dist/__tests__/agent-resolution-llm-free.test.js +30 -0
- package/dist/__tests__/agent-resolution-llm-free.test.js.map +1 -0
- package/dist/__tests__/build-step-entry.test.d.ts +2 -0
- package/dist/__tests__/build-step-entry.test.d.ts.map +1 -0
- package/dist/__tests__/build-step-entry.test.js +173 -0
- package/dist/__tests__/build-step-entry.test.js.map +1 -0
- package/dist/__tests__/clear-thread-failed-attempts.test.d.ts +2 -0
- package/dist/__tests__/clear-thread-failed-attempts.test.d.ts.map +1 -0
- package/dist/__tests__/clear-thread-failed-attempts.test.js +93 -0
- package/dist/__tests__/clear-thread-failed-attempts.test.js.map +1 -0
- package/dist/__tests__/concurrency.test.d.ts +2 -0
- package/dist/__tests__/concurrency.test.d.ts.map +1 -0
- package/dist/__tests__/concurrency.test.js +196 -0
- package/dist/__tests__/concurrency.test.js.map +1 -0
- package/dist/__tests__/config.test.js +26 -302
- package/dist/__tests__/config.test.js.map +1 -1
- package/dist/__tests__/current-role.test.js +7 -6
- package/dist/__tests__/current-role.test.js.map +1 -1
- package/dist/__tests__/e2e-mock-agent.test.js +43 -30
- package/dist/__tests__/e2e-mock-agent.test.js.map +1 -1
- package/dist/__tests__/format-text-default.test.d.ts +2 -0
- package/dist/__tests__/format-text-default.test.d.ts.map +1 -0
- package/dist/__tests__/format-text-default.test.js +43 -0
- package/dist/__tests__/format-text-default.test.js.map +1 -0
- package/dist/__tests__/format-text-registry.test.d.ts +2 -0
- package/dist/__tests__/format-text-registry.test.d.ts.map +1 -0
- package/dist/__tests__/format-text-registry.test.js +158 -0
- package/dist/__tests__/format-text-registry.test.js.map +1 -0
- package/dist/__tests__/issue-180-workflow-ref-removed.test.d.ts +2 -0
- package/dist/__tests__/issue-180-workflow-ref-removed.test.d.ts.map +1 -0
- package/dist/__tests__/issue-180-workflow-ref-removed.test.js +40 -0
- package/dist/__tests__/issue-180-workflow-ref-removed.test.js.map +1 -0
- package/dist/__tests__/log-text-renderer.test.d.ts +2 -0
- package/dist/__tests__/log-text-renderer.test.d.ts.map +1 -0
- package/dist/__tests__/log-text-renderer.test.js +265 -0
- package/dist/__tests__/log-text-renderer.test.js.map +1 -0
- package/dist/__tests__/moderator-evaluate.test.js +9 -50
- package/dist/__tests__/moderator-evaluate.test.js.map +1 -1
- package/dist/__tests__/output-mapper-thread-list-startedat.test.d.ts +2 -0
- package/dist/__tests__/output-mapper-thread-list-startedat.test.d.ts.map +1 -0
- package/dist/__tests__/output-mapper-thread-list-startedat.test.js +102 -0
- package/dist/__tests__/output-mapper-thread-list-startedat.test.js.map +1 -0
- package/dist/__tests__/output-mapper-workflow-add.test.d.ts +2 -0
- package/dist/__tests__/output-mapper-workflow-add.test.d.ts.map +1 -0
- package/dist/__tests__/output-mapper-workflow-add.test.js +22 -0
- package/dist/__tests__/output-mapper-workflow-add.test.js.map +1 -0
- package/dist/__tests__/pid-recycling.test.d.ts +2 -0
- package/dist/__tests__/pid-recycling.test.d.ts.map +1 -0
- package/dist/__tests__/pid-recycling.test.js +273 -0
- package/dist/__tests__/pid-recycling.test.js.map +1 -0
- package/dist/__tests__/prompt.test.js +365 -2
- package/dist/__tests__/prompt.test.js.map +1 -1
- package/dist/__tests__/resolve-head-hash.test.js +12 -4
- package/dist/__tests__/resolve-head-hash.test.js.map +1 -1
- package/dist/__tests__/setup-agent-discovery.test.js +21 -30
- package/dist/__tests__/setup-agent-discovery.test.js.map +1 -1
- package/dist/__tests__/setup-complexity.test.js +2 -168
- package/dist/__tests__/setup-complexity.test.js.map +1 -1
- package/dist/__tests__/setup-no-llm.test.d.ts +2 -0
- package/dist/__tests__/setup-no-llm.test.d.ts.map +1 -0
- package/dist/__tests__/setup-no-llm.test.js +52 -0
- package/dist/__tests__/setup-no-llm.test.js.map +1 -0
- package/dist/__tests__/solve-issue-tea-worktree.test.js +27 -28
- package/dist/__tests__/solve-issue-tea-worktree.test.js.map +1 -1
- package/dist/__tests__/step-ask.test.d.ts +2 -0
- package/dist/__tests__/step-ask.test.d.ts.map +1 -0
- package/dist/__tests__/step-ask.test.js +507 -0
- package/dist/__tests__/step-ask.test.js.map +1 -0
- package/dist/__tests__/step-show-json.test.js +1 -0
- package/dist/__tests__/step-show-json.test.js.map +1 -1
- package/dist/__tests__/step-timing.test.js +2 -0
- package/dist/__tests__/step-timing.test.js.map +1 -1
- package/dist/__tests__/store-global-cas.test.js +2 -2
- package/dist/__tests__/store-global-cas.test.js.map +1 -1
- package/dist/__tests__/store-unified-threads.test.js +28 -26
- package/dist/__tests__/store-unified-threads.test.js.map +1 -1
- package/dist/__tests__/thread-cancel-status.test.js +25 -19
- package/dist/__tests__/thread-cancel-status.test.js.map +1 -1
- package/dist/__tests__/thread-cancel-text-renderer.test.d.ts +2 -0
- package/dist/__tests__/thread-cancel-text-renderer.test.d.ts.map +1 -0
- package/dist/__tests__/thread-cancel-text-renderer.test.js +110 -0
- package/dist/__tests__/thread-cancel-text-renderer.test.js.map +1 -0
- package/dist/__tests__/thread-list-filters.test.js +354 -17
- package/dist/__tests__/thread-list-filters.test.js.map +1 -1
- package/dist/__tests__/thread-list-template-ms-date.test.d.ts +2 -0
- package/dist/__tests__/thread-list-template-ms-date.test.d.ts.map +1 -0
- package/dist/__tests__/thread-list-template-ms-date.test.js +102 -0
- package/dist/__tests__/thread-list-template-ms-date.test.js.map +1 -0
- package/dist/__tests__/thread-list-workflow-corrupt.test.d.ts +2 -0
- package/dist/__tests__/thread-list-workflow-corrupt.test.d.ts.map +1 -0
- package/dist/__tests__/thread-list-workflow-corrupt.test.js +157 -0
- package/dist/__tests__/thread-list-workflow-corrupt.test.js.map +1 -0
- package/dist/__tests__/thread-poke.test.d.ts +2 -0
- package/dist/__tests__/thread-poke.test.d.ts.map +1 -0
- package/dist/__tests__/thread-poke.test.js +422 -0
- package/dist/__tests__/thread-poke.test.js.map +1 -0
- package/dist/__tests__/thread-read-xml-tags.test.js +10 -9
- package/dist/__tests__/thread-read-xml-tags.test.js.map +1 -1
- package/dist/__tests__/thread-resume.test.js +21 -15
- package/dist/__tests__/thread-resume.test.js.map +1 -1
- package/dist/__tests__/thread-show-status.test.js +17 -28
- package/dist/__tests__/thread-show-status.test.js.map +1 -1
- package/dist/__tests__/thread-start-cwd-cli.test.js +15 -3
- package/dist/__tests__/thread-start-cwd-cli.test.js.map +1 -1
- package/dist/__tests__/thread-stop-text-renderer.test.d.ts +2 -0
- package/dist/__tests__/thread-stop-text-renderer.test.d.ts.map +1 -0
- package/dist/__tests__/thread-stop-text-renderer.test.js +148 -0
- package/dist/__tests__/thread-stop-text-renderer.test.js.map +1 -0
- package/dist/__tests__/thread-suspend-step.test.js +13 -16
- package/dist/__tests__/thread-suspend-step.test.js.map +1 -1
- package/dist/__tests__/thread-suspended-display.test.js +10 -22
- package/dist/__tests__/thread-suspended-display.test.js.map +1 -1
- package/dist/__tests__/thread-test-helpers.d.ts +7 -0
- package/dist/__tests__/thread-test-helpers.d.ts.map +1 -1
- package/dist/__tests__/thread-test-helpers.js +13 -0
- package/dist/__tests__/thread-test-helpers.js.map +1 -1
- package/dist/__tests__/thread.test.js +15 -13
- package/dist/__tests__/thread.test.js.map +1 -1
- package/dist/__tests__/validate-semantic.test.js +105 -23
- package/dist/__tests__/validate-semantic.test.js.map +1 -1
- package/dist/__tests__/workflow-list-recursive.test.d.ts +2 -0
- package/dist/__tests__/workflow-list-recursive.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-list-recursive.test.js +286 -0
- package/dist/__tests__/workflow-list-recursive.test.js.map +1 -0
- package/dist/__tests__/workflow-resolution.test.js +46 -28
- package/dist/__tests__/workflow-resolution.test.js.map +1 -1
- package/dist/__tests__/workflow-show-resolution.test.d.ts +2 -0
- package/dist/__tests__/workflow-show-resolution.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-show-resolution.test.js +213 -0
- package/dist/__tests__/workflow-show-resolution.test.js.map +1 -0
- package/dist/__tests__/workflow-validate.test.d.ts +2 -0
- package/dist/__tests__/workflow-validate.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-validate.test.js +707 -0
- package/dist/__tests__/workflow-validate.test.js.map +1 -0
- package/dist/__tests__/write-envelope.test.d.ts +2 -0
- package/dist/__tests__/write-envelope.test.d.ts.map +1 -0
- package/dist/__tests__/write-envelope.test.js +201 -0
- package/dist/__tests__/write-envelope.test.js.map +1 -0
- package/dist/background/background.d.ts +22 -1
- package/dist/background/background.d.ts.map +1 -1
- package/dist/background/background.js +83 -6
- package/dist/background/background.js.map +1 -1
- package/dist/background/index.d.ts +1 -1
- package/dist/background/index.d.ts.map +1 -1
- package/dist/background/index.js +1 -1
- package/dist/background/index.js.map +1 -1
- package/dist/background/types.d.ts +1 -0
- package/dist/background/types.d.ts.map +1 -1
- package/dist/cli.js +120 -62
- package/dist/cli.js.map +1 -1
- package/dist/commands/config.d.ts +3 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +17 -31
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/prompt.d.ts.map +1 -1
- package/dist/commands/prompt.js +57 -31
- package/dist/commands/prompt.js.map +1 -1
- package/dist/commands/setup.d.ts +12 -39
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +72 -303
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/step.d.ts +44 -1
- package/dist/commands/step.d.ts.map +1 -1
- package/dist/commands/step.js +255 -11
- package/dist/commands/step.js.map +1 -1
- package/dist/commands/thread.d.ts +16 -3
- package/dist/commands/thread.d.ts.map +1 -1
- package/dist/commands/thread.js +423 -142
- package/dist/commands/thread.js.map +1 -1
- package/dist/commands/workflow.d.ts +9 -1
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +126 -6
- package/dist/commands/workflow.js.map +1 -1
- package/dist/concurrency/concurrency.d.ts +34 -0
- package/dist/concurrency/concurrency.d.ts.map +1 -0
- package/dist/concurrency/concurrency.js +216 -0
- package/dist/concurrency/concurrency.js.map +1 -0
- package/dist/concurrency/index.d.ts +3 -0
- package/dist/concurrency/index.d.ts.map +1 -0
- package/dist/concurrency/index.js +2 -0
- package/dist/concurrency/index.js.map +1 -0
- package/dist/concurrency/types.d.ts +19 -0
- package/dist/concurrency/types.d.ts.map +1 -0
- package/dist/concurrency/types.js +2 -0
- package/dist/concurrency/types.js.map +1 -0
- package/dist/format.d.ts +69 -2
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +198 -1
- package/dist/format.js.map +1 -1
- package/dist/moderator/__tests__/evaluate.test.js +31 -17
- package/dist/moderator/__tests__/evaluate.test.js.map +1 -1
- package/dist/moderator/evaluate.d.ts.map +1 -1
- package/dist/moderator/evaluate.js +4 -16
- package/dist/moderator/evaluate.js.map +1 -1
- package/dist/moderator/index.d.ts +1 -2
- package/dist/moderator/index.d.ts.map +1 -1
- package/dist/moderator/index.js +0 -1
- package/dist/moderator/index.js.map +1 -1
- package/dist/moderator/types.d.ts +6 -10
- package/dist/moderator/types.d.ts.map +1 -1
- package/dist/moderator/types.js +1 -3
- package/dist/moderator/types.js.map +1 -1
- package/dist/output-mappers.d.ts +122 -0
- package/dist/output-mappers.d.ts.map +1 -0
- package/dist/output-mappers.js +134 -0
- package/dist/output-mappers.js.map +1 -0
- package/dist/schemas.d.ts +6 -1
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +34 -5
- package/dist/schemas.js.map +1 -1
- package/dist/store.d.ts +28 -9
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +75 -16
- package/dist/store.js.map +1 -1
- package/dist/text-renderers.d.ts +30 -0
- package/dist/text-renderers.d.ts.map +1 -0
- package/dist/text-renderers.js +251 -0
- package/dist/text-renderers.js.map +1 -0
- package/dist/validate-semantic.d.ts.map +1 -1
- package/dist/validate-semantic.js +95 -61
- package/dist/validate-semantic.js.map +1 -1
- package/dist/validate.d.ts +6 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +24 -0
- package/dist/validate.js.map +1 -1
- package/examples/brainstorm.yaml +130 -0
- package/examples/debate.yaml +169 -0
- package/examples/socratic-questioning.yaml +112 -0
- package/package.json +9 -10
- package/src/__tests__/adapter-json-roundtrip.test.ts +16 -7
- package/src/__tests__/agent-resolution-llm-free.test.ts +39 -0
- package/src/__tests__/build-step-entry.test.ts +203 -0
- package/src/__tests__/clear-thread-failed-attempts.test.ts +122 -0
- package/src/__tests__/concurrency.test.ts +266 -0
- package/src/__tests__/config.test.ts +33 -321
- package/src/__tests__/current-role.test.ts +7 -6
- package/src/__tests__/e2e-mock-agent.test.ts +65 -30
- package/src/__tests__/fixtures/e2e-count.workflow.yaml +1 -0
- package/src/__tests__/fixtures/e2e-linear.workflow.yaml +1 -0
- package/src/__tests__/fixtures/{e2e-mustache.workflow.yaml → e2e-liquid.workflow.yaml} +3 -2
- package/src/__tests__/fixtures/e2e-loop.workflow.yaml +1 -0
- package/src/__tests__/fixtures/e2e-suspend.mock.yaml +2 -2
- package/src/__tests__/fixtures/e2e-suspend.workflow.yaml +6 -10
- package/src/__tests__/format-text-default.test.ts +49 -0
- package/src/__tests__/format-text-registry.test.ts +173 -0
- package/src/__tests__/issue-180-workflow-ref-removed.test.ts +43 -0
- package/src/__tests__/log-text-renderer.test.ts +294 -0
- package/src/__tests__/moderator-evaluate.test.ts +9 -52
- package/src/__tests__/output-mapper-thread-list-startedat.test.ts +124 -0
- package/src/__tests__/output-mapper-workflow-add.test.ts +24 -0
- package/src/__tests__/pid-recycling.test.ts +329 -0
- package/src/__tests__/prompt.test.ts +443 -2
- package/src/__tests__/resolve-head-hash.test.ts +11 -4
- package/src/__tests__/setup-agent-discovery.test.ts +26 -51
- package/src/__tests__/setup-complexity.test.ts +1 -203
- package/src/__tests__/setup-no-llm.test.ts +68 -0
- package/src/__tests__/solve-issue-tea-worktree.test.ts +27 -31
- package/src/__tests__/step-ask.test.ts +677 -0
- package/src/__tests__/step-show-json.test.ts +1 -0
- package/src/__tests__/step-timing.test.ts +2 -0
- package/src/__tests__/store-global-cas.test.ts +2 -2
- package/src/__tests__/store-unified-threads.test.ts +30 -27
- package/src/__tests__/thread-cancel-status.test.ts +27 -20
- package/src/__tests__/thread-cancel-text-renderer.test.ts +125 -0
- package/src/__tests__/thread-list-filters.test.ts +443 -17
- package/src/__tests__/thread-list-template-ms-date.test.ts +110 -0
- package/src/__tests__/thread-list-workflow-corrupt.test.ts +198 -0
- package/src/__tests__/thread-poke.test.ts +554 -0
- package/src/__tests__/thread-read-xml-tags.test.ts +9 -11
- package/src/__tests__/thread-resume.test.ts +20 -15
- package/src/__tests__/thread-show-status.test.ts +17 -29
- package/src/__tests__/thread-start-cwd-cli.test.ts +15 -3
- package/src/__tests__/thread-stop-text-renderer.test.ts +168 -0
- package/src/__tests__/thread-suspend-step.test.ts +13 -16
- package/src/__tests__/thread-suspended-display.test.ts +10 -22
- package/src/__tests__/thread-test-helpers.ts +15 -1
- package/src/__tests__/thread.test.ts +14 -14
- package/src/__tests__/validate-semantic.test.ts +118 -33
- package/src/__tests__/workflow-list-recursive.test.ts +370 -0
- package/src/__tests__/workflow-resolution.test.ts +48 -29
- package/src/__tests__/workflow-show-resolution.test.ts +286 -0
- package/src/__tests__/workflow-validate.test.ts +828 -0
- package/src/__tests__/write-envelope.test.ts +257 -0
- package/src/background/background.ts +88 -6
- package/src/background/index.ts +2 -0
- package/src/background/types.ts +1 -0
- package/src/cli.ts +184 -77
- package/src/commands/config.ts +16 -33
- package/src/commands/prompt.ts +57 -31
- package/src/commands/setup.ts +80 -358
- package/src/commands/step.ts +339 -12
- package/src/commands/thread.ts +511 -171
- package/src/commands/workflow.ts +155 -4
- package/src/concurrency/concurrency.ts +245 -0
- package/src/concurrency/index.ts +10 -0
- package/src/concurrency/types.ts +19 -0
- package/src/format.ts +282 -2
- package/src/moderator/__tests__/evaluate.test.ts +34 -17
- package/src/moderator/evaluate.ts +5 -17
- package/src/moderator/index.ts +1 -6
- package/src/moderator/types.ts +6 -14
- package/src/output-mappers.ts +254 -0
- package/src/schemas.ts +51 -5
- package/src/store.ts +86 -20
- package/src/text-renderers.ts +355 -0
- package/src/validate-semantic.ts +125 -73
- package/src/validate.ts +27 -0
- package/dist/__tests__/setup-validate.test.d.ts +0 -2
- package/dist/__tests__/setup-validate.test.d.ts.map +0 -1
- package/dist/__tests__/setup-validate.test.js +0 -108
- package/dist/__tests__/setup-validate.test.js.map +0 -1
- package/src/__tests__/setup-validate.test.ts +0 -148
- /package/src/__tests__/fixtures/{e2e-mustache.mock.yaml → e2e-liquid.mock.yaml} +0 -0
|
@@ -27,12 +27,19 @@ const SUSPEND_MESSAGE = "Please clarify: Which API?";
|
|
|
27
27
|
type MockAgentMode = "suspend" | "ok";
|
|
28
28
|
|
|
29
29
|
let tmpDir: string;
|
|
30
|
+
let savedOcasHome: string | undefined;
|
|
30
31
|
|
|
31
32
|
beforeEach(async () => {
|
|
33
|
+
savedOcasHome = process.env.OCAS_HOME;
|
|
32
34
|
tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-resume-test-"));
|
|
33
35
|
});
|
|
34
36
|
|
|
35
37
|
afterEach(async () => {
|
|
38
|
+
if (savedOcasHome === undefined) {
|
|
39
|
+
delete process.env.OCAS_HOME;
|
|
40
|
+
} else {
|
|
41
|
+
process.env.OCAS_HOME = savedOcasHome;
|
|
42
|
+
}
|
|
36
43
|
await rm(tmpDir, { recursive: true, force: true });
|
|
37
44
|
});
|
|
38
45
|
|
|
@@ -75,11 +82,6 @@ async function setupSuspendedThread(mode: MockAgentMode): Promise<{
|
|
|
75
82
|
resume: { role: "worker", prompt: "Resume the work", location: null },
|
|
76
83
|
},
|
|
77
84
|
worker: {
|
|
78
|
-
needs_input: {
|
|
79
|
-
role: "$SUSPEND",
|
|
80
|
-
prompt: "Please clarify: {{{question}}}",
|
|
81
|
-
location: null,
|
|
82
|
-
},
|
|
83
85
|
ok: { role: "reviewer", prompt: "Review the work", location: null },
|
|
84
86
|
},
|
|
85
87
|
reviewer: { done: { role: "$END", prompt: "Done", location: null } },
|
|
@@ -95,9 +97,9 @@ async function setupSuspendedThread(mode: MockAgentMode): Promise<{
|
|
|
95
97
|
process.env.OCAS_HOME = casDir;
|
|
96
98
|
await seedThreads(tmpDir, { [THREAD_ID]: startHash });
|
|
97
99
|
|
|
98
|
-
const outputHash = await store.cas.put(
|
|
99
|
-
$status: "
|
|
100
|
-
|
|
100
|
+
const outputHash = await store.cas.put(schemas.suspendOutput, {
|
|
101
|
+
$status: "$SUSPEND",
|
|
102
|
+
reason: SUSPEND_MESSAGE,
|
|
101
103
|
});
|
|
102
104
|
const detailHash = await store.cas.put(schemas.text, "mock detail");
|
|
103
105
|
|
|
@@ -132,14 +134,15 @@ async function setupSuspendedThread(mode: MockAgentMode): Promise<{
|
|
|
132
134
|
const mockAgentPath = join(tmpDir, "mock-agent.sh");
|
|
133
135
|
|
|
134
136
|
const frontmatter =
|
|
135
|
-
mode === "suspend" ? { $status: "
|
|
137
|
+
mode === "suspend" ? { $status: "$SUSPEND", reason: SUSPEND_MESSAGE } : { $status: "ok" };
|
|
138
|
+
const frontmatterSchema = mode === "suspend" ? schemas.suspendOutput : outputSchemaHash;
|
|
136
139
|
|
|
137
140
|
const adapterJson = JSON.stringify({
|
|
138
141
|
stepHash: await store.cas.put(schemas.stepNode, {
|
|
139
142
|
start: startHash,
|
|
140
143
|
prev: stepHash,
|
|
141
144
|
role: "worker",
|
|
142
|
-
output: await store.cas.put(
|
|
145
|
+
output: await store.cas.put(frontmatterSchema, frontmatter),
|
|
143
146
|
detail: detailHash,
|
|
144
147
|
agent: "uwf-mock",
|
|
145
148
|
edgePrompt: "resume prompt placeholder",
|
|
@@ -177,7 +180,7 @@ echo '${adapterJson}'
|
|
|
177
180
|
const configPath = join(tmpDir, "config.yaml");
|
|
178
181
|
await writeFile(
|
|
179
182
|
configPath,
|
|
180
|
-
`defaultAgent: uwf-hermes\
|
|
183
|
+
`defaultAgent: uwf-hermes\nagentOverrides: null\nagents:\n uwf-hermes:\n command: uwf-hermes\n`,
|
|
181
184
|
);
|
|
182
185
|
|
|
183
186
|
return { casDir, mockAgentPath, promptCapturePath };
|
|
@@ -188,8 +191,10 @@ function runUwf(
|
|
|
188
191
|
casDir: string,
|
|
189
192
|
): { stdout: string; stderr: string; status: number } {
|
|
190
193
|
const cliPath = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "dist", "cli.js");
|
|
194
|
+
// Tests parse stdout as bare JSON; default --format text would break that.
|
|
195
|
+
const formatArgs = args.includes("--format") ? args : ["--format", "raw-json", ...args];
|
|
191
196
|
try {
|
|
192
|
-
const stdout = execFileSync(process.execPath, [cliPath, ...
|
|
197
|
+
const stdout = execFileSync(process.execPath, [cliPath, ...formatArgs], {
|
|
193
198
|
encoding: "utf8",
|
|
194
199
|
stdio: ["ignore", "pipe", "pipe"],
|
|
195
200
|
env: {
|
|
@@ -338,7 +343,7 @@ describe("uwf thread resume", () => {
|
|
|
338
343
|
}
|
|
339
344
|
});
|
|
340
345
|
|
|
341
|
-
test("multiple suspend/resume cycles", async () => {
|
|
346
|
+
test("multiple suspend/resume cycles", { timeout: 15_000 }, async () => {
|
|
342
347
|
const originalCasDir = process.env.OCAS_HOME;
|
|
343
348
|
const { casDir, mockAgentPath, promptCapturePath } = await setupSuspendedThread("suspend");
|
|
344
349
|
process.env.OCAS_HOME = casDir;
|
|
@@ -537,7 +542,7 @@ describe("uwf thread resume - completed threads", () => {
|
|
|
537
542
|
await seedThreads(tmpDir, {
|
|
538
543
|
[THREAD_ID]: {
|
|
539
544
|
head: reviewerStepHash,
|
|
540
|
-
status: "
|
|
545
|
+
status: "end",
|
|
541
546
|
suspendedRole: null,
|
|
542
547
|
suspendMessage: null,
|
|
543
548
|
completedAt: 1716600002000,
|
|
@@ -599,7 +604,7 @@ echo '${adapterJson}'
|
|
|
599
604
|
const configPath = join(tmpDir, "config.yaml");
|
|
600
605
|
await writeFile(
|
|
601
606
|
configPath,
|
|
602
|
-
`defaultAgent: uwf-hermes\
|
|
607
|
+
`defaultAgent: uwf-hermes\nagentOverrides: null\nagents:\n uwf-hermes:\n command: uwf-hermes\n`,
|
|
603
608
|
);
|
|
604
609
|
|
|
605
610
|
const result = runUwf(
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { putSchema } from "@ocas/core";
|
|
5
4
|
import type { CasRef, ThreadId } from "@united-workforce/protocol";
|
|
6
5
|
import { describe, expect, test } from "vitest";
|
|
7
|
-
import { createMarker, deleteMarker } from "../background/index.js";
|
|
6
|
+
import { createMarker, deleteMarker, getProcessStartTime } from "../background/index.js";
|
|
8
7
|
import { cmdThreadShow, cmdThreadStart } from "../commands/thread.js";
|
|
9
8
|
import { completeThread, createUwfStore, loadAllThreads, setThread } from "../store.js";
|
|
10
9
|
|
|
11
|
-
const OUTPUT_SCHEMA = {
|
|
12
|
-
type: "object" as const,
|
|
13
|
-
properties: {
|
|
14
|
-
$status: { type: "string" as const },
|
|
15
|
-
question: { type: "string" as const },
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
|
|
19
10
|
const TEST_WORKFLOW_YAML = `
|
|
20
11
|
name: test-status
|
|
21
12
|
description: Test workflow for status field
|
|
@@ -59,15 +50,12 @@ roles:
|
|
|
59
50
|
capabilities: ["coding"]
|
|
60
51
|
procedure: Work
|
|
61
52
|
output: |
|
|
62
|
-
$status: "
|
|
63
|
-
question: "Which API?"
|
|
53
|
+
$status: "done"
|
|
64
54
|
frontmatter:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
$status: { const: "needs_input" }
|
|
70
|
-
question: { type: string }
|
|
55
|
+
type: object
|
|
56
|
+
required: ["$status"]
|
|
57
|
+
properties:
|
|
58
|
+
$status: { const: "done" }
|
|
71
59
|
graph:
|
|
72
60
|
$START:
|
|
73
61
|
new:
|
|
@@ -79,9 +67,9 @@ graph:
|
|
|
79
67
|
prompt: "Resume work"
|
|
80
68
|
location: null
|
|
81
69
|
worker:
|
|
82
|
-
|
|
83
|
-
role: $
|
|
84
|
-
prompt: "
|
|
70
|
+
done:
|
|
71
|
+
role: $END
|
|
72
|
+
prompt: "Done"
|
|
85
73
|
location: null
|
|
86
74
|
`;
|
|
87
75
|
|
|
@@ -97,8 +85,7 @@ async function insertStepNode(
|
|
|
97
85
|
if (headEntry === undefined) throw new Error(`thread ${threadId} not in index`);
|
|
98
86
|
const head = headEntry.head;
|
|
99
87
|
|
|
100
|
-
const
|
|
101
|
-
const outputHash = await uwf.store.cas.put(outputSchemaHash, outputPayload);
|
|
88
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.suspendOutput, outputPayload);
|
|
102
89
|
const detailHash = await uwf.store.cas.put(uwf.schemas.text, "detail-placeholder");
|
|
103
90
|
|
|
104
91
|
const headNode = uwf.store.cas.get(head);
|
|
@@ -183,6 +170,7 @@ describe("thread show status field", () => {
|
|
|
183
170
|
workflow,
|
|
184
171
|
pid: process.pid,
|
|
185
172
|
startedAt: Date.now(),
|
|
173
|
+
processStartTime: getProcessStartTime(process.pid),
|
|
186
174
|
});
|
|
187
175
|
|
|
188
176
|
try {
|
|
@@ -216,11 +204,11 @@ describe("thread show status field", () => {
|
|
|
216
204
|
const head = index[threadId]!.head;
|
|
217
205
|
if (!head) throw new Error("Thread not found in index");
|
|
218
206
|
|
|
219
|
-
completeThread(uwfForIndex.varStore, threadId, "
|
|
207
|
+
completeThread(uwfForIndex.varStore, threadId, "end");
|
|
220
208
|
|
|
221
209
|
const result = await cmdThreadShow(storageRoot, threadId);
|
|
222
210
|
|
|
223
|
-
expect(result.status).toBe("
|
|
211
|
+
expect(result.status).toBe("end");
|
|
224
212
|
expect(result.done).toBe(true);
|
|
225
213
|
expect(result.background).toBe(null);
|
|
226
214
|
expect(result.thread).toBe(threadId);
|
|
@@ -274,11 +262,11 @@ describe("thread show status field", () => {
|
|
|
274
262
|
const head = index[threadId]!.head;
|
|
275
263
|
if (!head) throw new Error("Thread not found in index");
|
|
276
264
|
|
|
277
|
-
completeThread(uwfForIndex.varStore, threadId, "
|
|
265
|
+
completeThread(uwfForIndex.varStore, threadId, "end");
|
|
278
266
|
|
|
279
267
|
const result = await cmdThreadShow(storageRoot, threadId);
|
|
280
268
|
|
|
281
|
-
expect(result.status).toBe("
|
|
269
|
+
expect(result.status).toBe("end");
|
|
282
270
|
expect(result.done).toBe(true);
|
|
283
271
|
expect(result.background).toBe(null);
|
|
284
272
|
|
|
@@ -300,8 +288,8 @@ describe("thread show status field", () => {
|
|
|
300
288
|
const threadId = startResult.thread as ThreadId;
|
|
301
289
|
|
|
302
290
|
await insertStepNode(storageRoot, threadId, "worker", {
|
|
303
|
-
$status: "
|
|
304
|
-
|
|
291
|
+
$status: "$SUSPEND",
|
|
292
|
+
reason: "Please clarify: Which API?",
|
|
305
293
|
});
|
|
306
294
|
|
|
307
295
|
const result = await cmdThreadShow(storageRoot, threadId);
|
|
@@ -150,16 +150,28 @@ graph:
|
|
|
150
150
|
// Verify CLI accepts --cwd option (no error thrown)
|
|
151
151
|
const output = execFileSync(
|
|
152
152
|
process.execPath,
|
|
153
|
-
[
|
|
153
|
+
[
|
|
154
|
+
uwfBin,
|
|
155
|
+
"--format",
|
|
156
|
+
"raw-json",
|
|
157
|
+
"thread",
|
|
158
|
+
"start",
|
|
159
|
+
"test-cwd-cli",
|
|
160
|
+
"-p",
|
|
161
|
+
"test prompt",
|
|
162
|
+
"--cwd",
|
|
163
|
+
testCwd,
|
|
164
|
+
],
|
|
154
165
|
{
|
|
155
166
|
env: { ...process.env, UWF_HOME: storageRoot, OCAS_HOME: casDir },
|
|
156
167
|
encoding: "utf8",
|
|
157
168
|
},
|
|
158
169
|
);
|
|
159
170
|
|
|
171
|
+
// raw-json envelope value for thread-start: { threadId, workflowHash }
|
|
160
172
|
const result = JSON.parse(output);
|
|
161
|
-
expect(result.
|
|
162
|
-
expect(result.
|
|
173
|
+
expect(result.threadId).toBeDefined();
|
|
174
|
+
expect(result.workflowHash).toBeDefined();
|
|
163
175
|
|
|
164
176
|
// The fact that we got here without throwing means CLI accepted the --cwd option
|
|
165
177
|
// The actual cwd functionality is tested by the other tests using cmdThreadStart directly
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { formatOutput, getTextRenderer, TEXT_RENDERERS } from "../format.js";
|
|
3
|
+
import { renderThreadStop } from "../text-renderers.js";
|
|
4
|
+
|
|
5
|
+
describe("thread stop — text renderer registration", () => {
|
|
6
|
+
test("TEXT_RENDERERS contains 'thread stop'", () => {
|
|
7
|
+
expect(getTextRenderer("thread stop")).toBeDefined();
|
|
8
|
+
expect(typeof getTextRenderer("thread stop")).toBe("function");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("TEXT_RENDERERS['thread stop'] is the same reference as renderThreadStop", () => {
|
|
12
|
+
expect(TEXT_RENDERERS["thread stop"]).toBe(renderThreadStop);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("renderThreadStop is exported from text-renderers.ts", () => {
|
|
16
|
+
expect(typeof renderThreadStop).toBe("function");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("renderThreadStop — output shape (stopped=true)", () => {
|
|
21
|
+
test("returns a string for full payload", () => {
|
|
22
|
+
const out = renderThreadStop({
|
|
23
|
+
thread: "01JTEST00000000000000STOP1",
|
|
24
|
+
stopped: true,
|
|
25
|
+
});
|
|
26
|
+
expect(typeof out).toBe("string");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("includes the stopped thread's ULID", () => {
|
|
30
|
+
const out = renderThreadStop({
|
|
31
|
+
thread: "01JTEST00000000000000STOP1",
|
|
32
|
+
stopped: true,
|
|
33
|
+
});
|
|
34
|
+
expect(out).toContain("01JTEST00000000000000STOP1");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("indicates stopped status (yes)", () => {
|
|
38
|
+
const out = renderThreadStop({
|
|
39
|
+
thread: "01JTEST00000000000000STOP1",
|
|
40
|
+
stopped: true,
|
|
41
|
+
});
|
|
42
|
+
const lower = out.toLowerCase();
|
|
43
|
+
const hasStopMarker = lower.includes("stopped") && lower.includes("yes");
|
|
44
|
+
expect(hasStopMarker).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("does NOT begin with '{' or '[' (not raw JSON)", () => {
|
|
48
|
+
const out = renderThreadStop({
|
|
49
|
+
thread: "01JTEST00000000000000STOP1",
|
|
50
|
+
stopped: true,
|
|
51
|
+
});
|
|
52
|
+
const trimmed = out.trimStart();
|
|
53
|
+
expect(trimmed.startsWith("{")).toBe(false);
|
|
54
|
+
expect(trimmed.startsWith("[")).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("does NOT contain literal 'undefined'", () => {
|
|
58
|
+
const out = renderThreadStop({
|
|
59
|
+
thread: "01JTEST00000000000000STOP1",
|
|
60
|
+
stopped: true,
|
|
61
|
+
});
|
|
62
|
+
expect(out).not.toContain("undefined");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("renderThreadStop — stopped=false variant", () => {
|
|
67
|
+
test("returns a string for stopped=false payload", () => {
|
|
68
|
+
const out = renderThreadStop({
|
|
69
|
+
thread: "01JTEST00000000000000STOP1",
|
|
70
|
+
stopped: false,
|
|
71
|
+
});
|
|
72
|
+
expect(typeof out).toBe("string");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("includes the thread's ULID even when stopped=false", () => {
|
|
76
|
+
const out = renderThreadStop({
|
|
77
|
+
thread: "01JTEST00000000000000STOP1",
|
|
78
|
+
stopped: false,
|
|
79
|
+
});
|
|
80
|
+
expect(out).toContain("01JTEST00000000000000STOP1");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("indicates not-stopped status (no)", () => {
|
|
84
|
+
const out = renderThreadStop({
|
|
85
|
+
thread: "01JTEST00000000000000STOP1",
|
|
86
|
+
stopped: false,
|
|
87
|
+
});
|
|
88
|
+
const lower = out.toLowerCase();
|
|
89
|
+
const hasNoMarker = lower.includes("stopped") && lower.includes("no");
|
|
90
|
+
expect(hasNoMarker).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("does NOT contain literal 'undefined' for stopped=false", () => {
|
|
94
|
+
const out = renderThreadStop({
|
|
95
|
+
thread: "01JTEST00000000000000STOP1",
|
|
96
|
+
stopped: false,
|
|
97
|
+
});
|
|
98
|
+
expect(out).not.toContain("undefined");
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("renderThreadStop — partial / missing data", () => {
|
|
103
|
+
test("missing 'stopped' field — returns string, no throw, no 'undefined'", () => {
|
|
104
|
+
const out = renderThreadStop({ thread: "01JTEST00000000000000STOP1" });
|
|
105
|
+
expect(typeof out).toBe("string");
|
|
106
|
+
expect(out).not.toContain("undefined");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("missing 'thread' field — returns string, no throw, no 'undefined'", () => {
|
|
110
|
+
const out = renderThreadStop({ stopped: true });
|
|
111
|
+
expect(typeof out).toBe("string");
|
|
112
|
+
expect(out).not.toContain("undefined");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("empty object — returns string, no throw, no 'undefined'", () => {
|
|
116
|
+
const out = renderThreadStop({});
|
|
117
|
+
expect(typeof out).toBe("string");
|
|
118
|
+
expect(out).not.toContain("undefined");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("null payload — returns string, no throw", () => {
|
|
122
|
+
expect(() => renderThreadStop(null)).not.toThrow();
|
|
123
|
+
const out = renderThreadStop(null);
|
|
124
|
+
expect(typeof out).toBe("string");
|
|
125
|
+
expect(out).not.toContain("undefined");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("non-object payload (string) — returns string, no throw", () => {
|
|
129
|
+
expect(() => renderThreadStop("oops")).not.toThrow();
|
|
130
|
+
const out = renderThreadStop("oops");
|
|
131
|
+
expect(typeof out).toBe("string");
|
|
132
|
+
expect(out).not.toContain("undefined");
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe("formatOutput integration — thread stop", () => {
|
|
137
|
+
test("formatOutput(data, 'text', 'thread stop') uses renderer", () => {
|
|
138
|
+
const data = { thread: "01JTEST00000000000000STOP1", stopped: true };
|
|
139
|
+
const out = formatOutput(data, "text", "thread stop");
|
|
140
|
+
expect(typeof out).toBe("string");
|
|
141
|
+
expect(out).not.toContain("undefined");
|
|
142
|
+
expect(out.trimStart().startsWith("{")).toBe(false);
|
|
143
|
+
expect(out).toContain("01JTEST00000000000000STOP1");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("formatOutput(data, 'json', 'thread stop') still emits parseable JSON", () => {
|
|
147
|
+
const data = { thread: "01JTEST00000000000000STOP1", stopped: true };
|
|
148
|
+
const out = formatOutput(data, "json", "thread stop");
|
|
149
|
+
const parsed = JSON.parse(out);
|
|
150
|
+
expect(parsed).toEqual(data);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("formatOutput(data, 'yaml', 'thread stop') still emits YAML", () => {
|
|
154
|
+
const data = { thread: "01JTEST00000000000000STOP1", stopped: true };
|
|
155
|
+
const out = formatOutput(data, "yaml", "thread stop");
|
|
156
|
+
expect(typeof out).toBe("string");
|
|
157
|
+
expect(out).toContain("thread:");
|
|
158
|
+
expect(out).toContain("stopped:");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("formatOutput for stopped=false variant under text format", () => {
|
|
162
|
+
const data = { thread: "01JTEST00000000000000STOP1", stopped: false };
|
|
163
|
+
const out = formatOutput(data, "text", "thread stop");
|
|
164
|
+
expect(typeof out).toBe("string");
|
|
165
|
+
expect(out).not.toContain("undefined");
|
|
166
|
+
expect(out).toContain("01JTEST00000000000000STOP1");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -62,13 +62,7 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
|
|
|
62
62
|
new: { role: "worker", prompt: "Start work", location: null },
|
|
63
63
|
resume: { role: "worker", prompt: "Resume work", location: null },
|
|
64
64
|
},
|
|
65
|
-
worker: {
|
|
66
|
-
needs_input: {
|
|
67
|
-
role: "$SUSPEND",
|
|
68
|
-
prompt: "Please clarify: {{{question}}}",
|
|
69
|
-
location: null,
|
|
70
|
-
},
|
|
71
|
-
},
|
|
65
|
+
worker: {},
|
|
72
66
|
},
|
|
73
67
|
});
|
|
74
68
|
|
|
@@ -81,9 +75,9 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
|
|
|
81
75
|
const threadId = "01SUSPENDSTEPTEST0000000" as ThreadId;
|
|
82
76
|
await seedThreads(tmpDir, { [threadId]: startHash });
|
|
83
77
|
|
|
84
|
-
const outputHash = await store.cas.put(
|
|
85
|
-
$status: "
|
|
86
|
-
|
|
78
|
+
const outputHash = await store.cas.put(schemas.suspendOutput, {
|
|
79
|
+
$status: "$SUSPEND",
|
|
80
|
+
reason: "Please clarify: Which API?",
|
|
87
81
|
});
|
|
88
82
|
const detailHash = await store.cas.put(schemas.text, "mock detail");
|
|
89
83
|
|
|
@@ -109,7 +103,7 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
|
|
|
109
103
|
stepHash,
|
|
110
104
|
detailHash,
|
|
111
105
|
role: "worker",
|
|
112
|
-
frontmatter: { $status: "
|
|
106
|
+
frontmatter: { $status: "$SUSPEND", reason: "Please clarify: Which API?" },
|
|
113
107
|
body: "",
|
|
114
108
|
startedAtMs,
|
|
115
109
|
completedAtMs,
|
|
@@ -119,13 +113,13 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
|
|
|
119
113
|
const configPath = join(tmpDir, "config.yaml");
|
|
120
114
|
await writeFile(
|
|
121
115
|
configPath,
|
|
122
|
-
`defaultAgent: uwf-hermes\
|
|
116
|
+
`defaultAgent: uwf-hermes\nagentOverrides: null\nagents:\n uwf-hermes:\n command: uwf-hermes\n`,
|
|
123
117
|
);
|
|
124
118
|
|
|
125
119
|
const cliPath = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "dist", "cli.js");
|
|
126
120
|
const stdout = execFileSync(
|
|
127
121
|
process.execPath,
|
|
128
|
-
[cliPath, "thread", "exec", threadId, "--agent", mockAgentPath],
|
|
122
|
+
[cliPath, "--format", "raw-json", "thread", "exec", threadId, "--agent", mockAgentPath],
|
|
129
123
|
{
|
|
130
124
|
encoding: "utf8",
|
|
131
125
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -139,7 +133,10 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
|
|
|
139
133
|
},
|
|
140
134
|
);
|
|
141
135
|
|
|
142
|
-
|
|
136
|
+
// thread exec envelope value: { threadId, workflowHash, steps: [...] }
|
|
137
|
+
const envelope = JSON.parse(stdout.trim());
|
|
138
|
+
expect(envelope.steps).toHaveLength(1);
|
|
139
|
+
const cliOutput = envelope.steps[0];
|
|
143
140
|
expect(cliOutput.status).toBe("suspended");
|
|
144
141
|
expect(cliOutput.head).toBe(stepHash);
|
|
145
142
|
expect(cliOutput.suspendedRole).toBe("worker");
|
|
@@ -154,8 +151,8 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
|
|
|
154
151
|
|
|
155
152
|
const outputNode = storeAfter.cas.get(outputHash);
|
|
156
153
|
expect(outputNode?.payload).toEqual({
|
|
157
|
-
$status: "
|
|
158
|
-
|
|
154
|
+
$status: "$SUSPEND",
|
|
155
|
+
reason: "Please clarify: Which API?",
|
|
159
156
|
});
|
|
160
157
|
|
|
161
158
|
const { createUwfStore, getThread } = await import("../store.js");
|
|
@@ -59,13 +59,7 @@ describe("suspended thread display", () => {
|
|
|
59
59
|
new: { role: "worker", prompt: "Start work", location: null },
|
|
60
60
|
resume: { role: "worker", prompt: "Resume work", location: null },
|
|
61
61
|
},
|
|
62
|
-
worker: {
|
|
63
|
-
needs_input: {
|
|
64
|
-
role: "$SUSPEND",
|
|
65
|
-
prompt: "Please provide more details: {{{question}}}",
|
|
66
|
-
location: null,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
62
|
+
worker: {},
|
|
69
63
|
},
|
|
70
64
|
});
|
|
71
65
|
|
|
@@ -77,9 +71,9 @@ describe("suspended thread display", () => {
|
|
|
77
71
|
|
|
78
72
|
// Create suspended thread
|
|
79
73
|
const suspendedThreadId = "01SUSPENDEDTHREAD0000000" as ThreadId;
|
|
80
|
-
const outputHash = await uwf.store.cas.put(
|
|
81
|
-
$status: "
|
|
82
|
-
|
|
74
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.suspendOutput, {
|
|
75
|
+
$status: "$SUSPEND",
|
|
76
|
+
reason: "Please provide more details: What is the target API?",
|
|
83
77
|
});
|
|
84
78
|
const detailHash = await uwf.store.cas.put(uwf.schemas.text, "mock detail");
|
|
85
79
|
|
|
@@ -118,8 +112,8 @@ describe("suspended thread display", () => {
|
|
|
118
112
|
[idleThreadId]: idleEntry,
|
|
119
113
|
});
|
|
120
114
|
|
|
121
|
-
// Test thread list
|
|
122
|
-
const listResult = await cmdThreadList(tmpDir, null, null, null, null, null);
|
|
115
|
+
// Test thread list — pass showAll=true to include suspended threads
|
|
116
|
+
const listResult = await cmdThreadList(tmpDir, null, null, null, null, null, true);
|
|
123
117
|
|
|
124
118
|
// Find the suspended and idle threads in results
|
|
125
119
|
const suspendedItem = listResult.find((item) => item.thread === suspendedThreadId);
|
|
@@ -169,13 +163,7 @@ describe("suspended thread display", () => {
|
|
|
169
163
|
new: { role: "worker", prompt: "Start work", location: null },
|
|
170
164
|
resume: { role: "worker", prompt: "Resume work", location: null },
|
|
171
165
|
},
|
|
172
|
-
worker: {
|
|
173
|
-
needs_input: {
|
|
174
|
-
role: "$SUSPEND",
|
|
175
|
-
prompt: "Need clarification: {{{question}}}",
|
|
176
|
-
location: null,
|
|
177
|
-
},
|
|
178
|
-
},
|
|
166
|
+
worker: {},
|
|
179
167
|
},
|
|
180
168
|
});
|
|
181
169
|
|
|
@@ -186,9 +174,9 @@ describe("suspended thread display", () => {
|
|
|
186
174
|
});
|
|
187
175
|
|
|
188
176
|
const threadId = "01SUSPENDSHOW000000000" as ThreadId;
|
|
189
|
-
const outputHash = await uwf.store.cas.put(
|
|
190
|
-
$status: "
|
|
191
|
-
|
|
177
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.suspendOutput, {
|
|
178
|
+
$status: "$SUSPEND",
|
|
179
|
+
reason: "Need clarification: Which database to use?",
|
|
192
180
|
});
|
|
193
181
|
const detailHash = await uwf.store.cas.put(uwf.schemas.text, "mock detail");
|
|
194
182
|
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
1
3
|
import type { CasRef, ThreadId, ThreadIndexEntry } from "@united-workforce/protocol";
|
|
2
4
|
import { createThreadIndexEntry } from "@united-workforce/protocol";
|
|
3
|
-
import { createUwfStore, setThread } from "../store.js";
|
|
5
|
+
import { createUwfStore, setThread, type UwfStore } from "../store.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create an isolated UwfStore backed by a tmpdir.
|
|
9
|
+
* Sets process.env.OCAS_HOME so CAS resolves to the test's directory.
|
|
10
|
+
* Callers MUST save/restore OCAS_HOME in afterEach.
|
|
11
|
+
*/
|
|
12
|
+
export async function makeUwfStore(storageRoot: string): Promise<UwfStore> {
|
|
13
|
+
const casDir = join(storageRoot, "cas");
|
|
14
|
+
await mkdir(casDir, { recursive: true });
|
|
15
|
+
process.env.OCAS_HOME = casDir;
|
|
16
|
+
return createUwfStore(storageRoot);
|
|
17
|
+
}
|
|
4
18
|
|
|
5
19
|
async function ensureHeadInCas(
|
|
6
20
|
uwf: Awaited<ReturnType<typeof createUwfStore>>,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { bootstrap, putSchema, type Store } from "@ocas/core";
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
THREAD_READ_DEFAULT_QUOTA,
|
|
12
12
|
} from "../commands/thread.js";
|
|
13
13
|
import type { UwfStore } from "../store.js";
|
|
14
|
-
import { completeThread,
|
|
15
|
-
import { seedThreads } from "./thread-test-helpers.js";
|
|
14
|
+
import { completeThread, setThread } from "../store.js";
|
|
15
|
+
import { makeUwfStore, seedThreads } from "./thread-test-helpers.js";
|
|
16
16
|
|
|
17
17
|
// ── schemas used in tests ────────────────────────────────────────────────────
|
|
18
18
|
|
|
@@ -54,13 +54,6 @@ const DETAIL_SCHEMA = {
|
|
|
54
54
|
|
|
55
55
|
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
56
56
|
|
|
57
|
-
async function makeUwfStore(storageRoot: string): Promise<UwfStore> {
|
|
58
|
-
const casDir = join(storageRoot, "cas");
|
|
59
|
-
await mkdir(casDir, { recursive: true });
|
|
60
|
-
process.env.OCAS_HOME = casDir;
|
|
61
|
-
return createUwfStore(storageRoot);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
57
|
async function registerDetailSchemas(store: Store) {
|
|
65
58
|
await bootstrap(store);
|
|
66
59
|
const [turn, detail] = await Promise.all([
|
|
@@ -73,12 +66,19 @@ async function registerDetailSchemas(store: Store) {
|
|
|
73
66
|
// ── fixture ───────────────────────────────────────────────────────────────────
|
|
74
67
|
|
|
75
68
|
let tmpDir: string;
|
|
69
|
+
let savedOcasHome: string | undefined;
|
|
76
70
|
|
|
77
71
|
beforeEach(async () => {
|
|
72
|
+
savedOcasHome = process.env.OCAS_HOME;
|
|
78
73
|
tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-test-"));
|
|
79
74
|
});
|
|
80
75
|
|
|
81
76
|
afterEach(async () => {
|
|
77
|
+
if (savedOcasHome === undefined) {
|
|
78
|
+
delete process.env.OCAS_HOME;
|
|
79
|
+
} else {
|
|
80
|
+
process.env.OCAS_HOME = savedOcasHome;
|
|
81
|
+
}
|
|
82
82
|
await rm(tmpDir, { recursive: true, force: true });
|
|
83
83
|
});
|
|
84
84
|
|
|
@@ -752,7 +752,7 @@ describe("cmdStepList with completed threads", () => {
|
|
|
752
752
|
suspendMessage: null,
|
|
753
753
|
completedAt: null,
|
|
754
754
|
});
|
|
755
|
-
completeThread(uwf.varStore, threadId, "
|
|
755
|
+
completeThread(uwf.varStore, threadId, "end");
|
|
756
756
|
|
|
757
757
|
const result = await cmdStepList(tmpDir, threadId);
|
|
758
758
|
|
|
@@ -881,7 +881,7 @@ describe("cmdStepShow with completed threads", () => {
|
|
|
881
881
|
suspendMessage: null,
|
|
882
882
|
completedAt: null,
|
|
883
883
|
});
|
|
884
|
-
completeThread(uwf.varStore, threadId, "
|
|
884
|
+
completeThread(uwf.varStore, threadId, "end");
|
|
885
885
|
|
|
886
886
|
const result = await cmdStepShow(tmpDir, stepHash);
|
|
887
887
|
|
|
@@ -944,7 +944,7 @@ describe("cmdThreadRead with completed threads", () => {
|
|
|
944
944
|
suspendMessage: null,
|
|
945
945
|
completedAt: null,
|
|
946
946
|
});
|
|
947
|
-
completeThread(uwf.varStore, threadId, "
|
|
947
|
+
completeThread(uwf.varStore, threadId, "end");
|
|
948
948
|
|
|
949
949
|
const markdown = await cmdThreadRead(tmpDir, threadId, THREAD_READ_DEFAULT_QUOTA, null, false);
|
|
950
950
|
|
|
@@ -1007,7 +1007,7 @@ describe("cmdThreadRead with completed threads", () => {
|
|
|
1007
1007
|
suspendMessage: null,
|
|
1008
1008
|
completedAt: null,
|
|
1009
1009
|
});
|
|
1010
|
-
completeThread(uwf.varStore, threadId, "
|
|
1010
|
+
completeThread(uwf.varStore, threadId, "end");
|
|
1011
1011
|
|
|
1012
1012
|
const markdown = await cmdThreadRead(
|
|
1013
1013
|
tmpDir,
|