@united-workforce/cli 0.7.0 → 0.8.1
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 +32 -5
- package/dist/.build-fingerprint +1 -0
- package/dist/__tests__/broker-step-active-turns.test.d.ts +20 -0
- package/dist/__tests__/broker-step-active-turns.test.d.ts.map +1 -0
- package/dist/__tests__/broker-step-active-turns.test.js +428 -0
- package/dist/__tests__/broker-step-active-turns.test.js.map +1 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.d.ts +13 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.d.ts.map +1 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.js +429 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.js.map +1 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.d.ts +18 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.js +313 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.js.map +1 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.d.ts +28 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.js +322 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.js.map +1 -0
- package/dist/__tests__/log-tag-validity.test.d.ts +2 -0
- package/dist/__tests__/log-tag-validity.test.d.ts.map +1 -0
- package/dist/__tests__/log-tag-validity.test.js +110 -0
- package/dist/__tests__/log-tag-validity.test.js.map +1 -0
- package/dist/__tests__/setup-agent-discovery.test.js +23 -23
- package/dist/__tests__/setup-agent-discovery.test.js.map +1 -1
- package/dist/__tests__/step-show-json.test.js +5 -5
- package/dist/__tests__/step-show-json.test.js.map +1 -1
- package/dist/__tests__/step-show-text.test.d.ts +2 -0
- package/dist/__tests__/step-show-text.test.d.ts.map +1 -0
- package/dist/__tests__/step-show-text.test.js +192 -0
- package/dist/__tests__/step-show-text.test.js.map +1 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.d.ts +21 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.js +356 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.js.map +1 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.d.ts +21 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.js +476 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.js.map +1 -0
- package/dist/__tests__/step-turns.test.d.ts +24 -0
- package/dist/__tests__/step-turns.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns.test.js +646 -0
- package/dist/__tests__/step-turns.test.js.map +1 -0
- package/dist/__tests__/store-turn-chain.test.d.ts +2 -0
- package/dist/__tests__/store-turn-chain.test.d.ts.map +1 -0
- package/dist/__tests__/store-turn-chain.test.js +341 -0
- package/dist/__tests__/store-turn-chain.test.js.map +1 -0
- package/dist/__tests__/thread-list-limit-offset.test.d.ts +24 -0
- package/dist/__tests__/thread-list-limit-offset.test.d.ts.map +1 -0
- package/dist/__tests__/thread-list-limit-offset.test.js +254 -0
- package/dist/__tests__/thread-list-limit-offset.test.js.map +1 -0
- package/dist/__tests__/thread-list-template-ms-date.test.js +7 -2
- package/dist/__tests__/thread-list-template-ms-date.test.js.map +1 -1
- package/dist/__tests__/thread.test.js +28 -14
- package/dist/__tests__/thread.test.js.map +1 -1
- package/dist/cli.js +910 -344
- package/dist/cli.js.map +1 -1
- package/dist/commands/broker-step.d.ts +10 -3
- package/dist/commands/broker-step.d.ts.map +1 -1
- package/dist/commands/broker-step.js +231 -27
- package/dist/commands/broker-step.js.map +1 -1
- package/dist/commands/prompt.d.ts.map +1 -1
- package/dist/commands/prompt.js +42 -50
- package/dist/commands/prompt.js.map +1 -1
- package/dist/commands/setup.d.ts +6 -4
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +16 -26
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/step.d.ts +48 -1
- package/dist/commands/step.d.ts.map +1 -1
- package/dist/commands/step.js +496 -3
- package/dist/commands/step.js.map +1 -1
- package/dist/output-mappers.d.ts +8 -0
- package/dist/output-mappers.d.ts.map +1 -1
- package/dist/output-mappers.js +72 -18
- package/dist/output-mappers.js.map +1 -1
- package/dist/schemas.d.ts +3 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +17 -3
- package/dist/schemas.js.map +1 -1
- package/dist/store.d.ts +147 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +254 -1
- package/dist/store.js.map +1 -1
- package/dist/text-renderers.d.ts.map +1 -1
- package/dist/text-renderers.js +27 -2
- package/dist/text-renderers.js.map +1 -1
- package/package.json +7 -6
- package/src/__tests__/broker-step-active-turns.test.ts +509 -0
- package/src/__tests__/broker-step-turn-chain-phase2.test.ts +525 -0
- package/src/__tests__/e2e-broker-step-suspend.test.ts +351 -0
- package/src/__tests__/e2e-thread-resume-timeout-suspend.test.ts +360 -0
- package/src/__tests__/log-tag-validity.test.ts +124 -0
- package/src/__tests__/setup-agent-discovery.test.ts +23 -23
- package/src/__tests__/step-show-json.test.ts +5 -5
- package/src/__tests__/step-show-text.test.ts +236 -0
- package/src/__tests__/step-turns-cli-subprocess.test.ts +411 -0
- package/src/__tests__/step-turns-panorama-phase3.test.ts +579 -0
- package/src/__tests__/step-turns.test.ts +734 -0
- package/src/__tests__/store-turn-chain.test.ts +386 -0
- package/src/__tests__/thread-list-limit-offset.test.ts +305 -0
- package/src/__tests__/thread-list-template-ms-date.test.ts +7 -2
- package/src/__tests__/thread.test.ts +29 -15
- package/src/cli.ts +1056 -483
- package/src/commands/broker-step.ts +315 -38
- package/src/commands/prompt.ts +42 -50
- package/src/commands/setup.ts +16 -28
- package/src/commands/step.ts +655 -3
- package/src/output-mappers.ts +99 -21
- package/src/schemas.ts +32 -2
- package/src/store.ts +297 -2
- package/src/text-renderers.ts +35 -2
package/src/cli.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --disable-warning=ExperimentalWarning
|
|
2
2
|
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { createCLI, type ParsedFlags } from "@ocas/cli-kit";
|
|
3
7
|
import type { CasRef, OutputSchemaName, ThreadId, ThreadStatus } from "@united-workforce/protocol";
|
|
4
|
-
import {
|
|
8
|
+
import { z } from "zod";
|
|
5
9
|
import { cmdConfigGet, cmdConfigList, cmdConfigSet } from "./commands/config.js";
|
|
6
10
|
import { cmdLogClean, cmdLogList, cmdLogShow } from "./commands/log.js";
|
|
7
11
|
import {
|
|
@@ -12,7 +16,14 @@ import {
|
|
|
12
16
|
cmdPromptWorkflowAuthoring,
|
|
13
17
|
} from "./commands/prompt.js";
|
|
14
18
|
import { cmdSetup, cmdSetupInteractive } from "./commands/setup.js";
|
|
15
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
cmdStepAsk,
|
|
21
|
+
cmdStepFork,
|
|
22
|
+
cmdStepList,
|
|
23
|
+
cmdStepRead,
|
|
24
|
+
cmdStepShow,
|
|
25
|
+
cmdStepTurns,
|
|
26
|
+
} from "./commands/step.js";
|
|
16
27
|
import {
|
|
17
28
|
cmdThreadCancel,
|
|
18
29
|
cmdThreadExec,
|
|
@@ -54,8 +65,22 @@ import {
|
|
|
54
65
|
} from "./output-mappers.js";
|
|
55
66
|
import { createUwfStore, resolveStorageRoot } from "./store.js";
|
|
56
67
|
|
|
68
|
+
// --- Package version (readFileSync replaces dynamic import) ---
|
|
69
|
+
|
|
70
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
71
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8")) as {
|
|
72
|
+
version: string;
|
|
73
|
+
};
|
|
74
|
+
const VERSION = pkg.version;
|
|
75
|
+
|
|
76
|
+
// --- Module-level state (cli-kit v0.2.1 workaround: no global --format) ---
|
|
77
|
+
// Parsed from argv early, before cli-kit sees it.
|
|
78
|
+
let formatOverride: string | null = null;
|
|
79
|
+
// Parsed from argv early — cli-kit rejects values starting with `-`.
|
|
80
|
+
let countOverride: string | null = null;
|
|
81
|
+
|
|
57
82
|
function getFormat(): OutputFormat {
|
|
58
|
-
const raw =
|
|
83
|
+
const raw = formatOverride ?? "text";
|
|
59
84
|
if (!isOutputFormat(raw)) {
|
|
60
85
|
process.stderr.write(
|
|
61
86
|
`Invalid --format: ${raw}. Must be one of: ${SUPPORTED_FORMATS.join(", ")}\n`,
|
|
@@ -85,164 +110,21 @@ async function writeOutput(
|
|
|
85
110
|
* (the default) it renders via the per-command registry when available
|
|
86
111
|
* and falls back to JSON.
|
|
87
112
|
*/
|
|
88
|
-
function writeRawOutput(data: unknown, commandPath
|
|
113
|
+
function writeRawOutput(data: unknown, commandPath: string | null = null): void {
|
|
89
114
|
const fmt = getFormat();
|
|
90
|
-
process.stdout.write(`${formatOutput(data, fmt, commandPath)}\n`);
|
|
115
|
+
process.stdout.write(`${formatOutput(data, fmt, commandPath ?? undefined)}\n`);
|
|
91
116
|
}
|
|
92
117
|
|
|
93
|
-
function runAction(action: () => Promise<void>): void {
|
|
94
|
-
action().catch((e: unknown) => {
|
|
118
|
+
function runAction(action: () => Promise<void>): Promise<void> {
|
|
119
|
+
return action().catch((e: unknown) => {
|
|
95
120
|
const message = e instanceof Error ? e.message : String(e);
|
|
96
121
|
process.stderr.write(`${message}\n`);
|
|
97
122
|
process.exit(1);
|
|
98
123
|
});
|
|
99
124
|
}
|
|
100
125
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// eslint-disable-next-line -- dynamic import for version
|
|
104
|
-
const pkg = await import("../package.json", { with: { type: "json" } });
|
|
105
|
-
program
|
|
106
|
-
.name("uwf")
|
|
107
|
-
.description(
|
|
108
|
-
"Stateless workflow CLI\n\n" +
|
|
109
|
-
"Four-layer architecture:\n" +
|
|
110
|
-
" workflow → thread → step → turn",
|
|
111
|
-
)
|
|
112
|
-
.version(pkg.default.version, "-V, --version");
|
|
113
|
-
program.option(
|
|
114
|
-
"--format <fmt>",
|
|
115
|
-
"Output format: text (default), json, yaml, raw-json, raw-yaml",
|
|
116
|
-
"text",
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
const workflow = program
|
|
120
|
-
.command("workflow")
|
|
121
|
-
.description("Workflow definitions (layer 1: templates)");
|
|
126
|
+
// --- Helper functions for thread list / step turns parsing (unchanged) ---
|
|
122
127
|
|
|
123
|
-
workflow
|
|
124
|
-
.command("add")
|
|
125
|
-
.description("Register a workflow from YAML")
|
|
126
|
-
.argument("<file>", "Workflow YAML file")
|
|
127
|
-
.action((file: string) => {
|
|
128
|
-
const storageRoot = resolveStorageRoot();
|
|
129
|
-
runAction(async () => {
|
|
130
|
-
const result = await cmdWorkflowAdd(storageRoot, file);
|
|
131
|
-
await writeOutput(toWorkflowAddPayload(result), "workflow-add", storageRoot);
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
workflow
|
|
136
|
-
.command("validate")
|
|
137
|
-
.description("Validate a workflow YAML without registering it (CI-friendly)")
|
|
138
|
-
.argument("<file>", "Workflow YAML file")
|
|
139
|
-
.action((file: string) => {
|
|
140
|
-
const storageRoot = resolveStorageRoot();
|
|
141
|
-
runAction(async () => {
|
|
142
|
-
const errors = await cmdWorkflowValidate(file);
|
|
143
|
-
await writeOutput(toValidateResultPayload(errors), "validate-result", storageRoot);
|
|
144
|
-
if (errors.length > 0) {
|
|
145
|
-
process.exit(1);
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
workflow
|
|
151
|
-
.command("show")
|
|
152
|
-
.description("Show a workflow by name or CAS hash")
|
|
153
|
-
.argument("<id>", "Workflow name or hash")
|
|
154
|
-
.action((id: string) => {
|
|
155
|
-
const storageRoot = resolveStorageRoot();
|
|
156
|
-
runAction(async () => {
|
|
157
|
-
const result = await cmdWorkflowShow(storageRoot, id, process.cwd());
|
|
158
|
-
await writeOutput(toWorkflowDetailPayload(result), "workflow-detail", storageRoot);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
workflow
|
|
163
|
-
.command("list")
|
|
164
|
-
.description("List registered workflows")
|
|
165
|
-
.action(() => {
|
|
166
|
-
const storageRoot = resolveStorageRoot();
|
|
167
|
-
runAction(async () => {
|
|
168
|
-
const result = await cmdWorkflowList(storageRoot, process.cwd());
|
|
169
|
-
await writeOutput(toWorkflowListPayload(result), "workflow-list", storageRoot);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const thread = program.command("thread").description("Thread execution (layer 2: instances)");
|
|
174
|
-
|
|
175
|
-
thread
|
|
176
|
-
.command("start")
|
|
177
|
-
.description("Create a thread without executing")
|
|
178
|
-
.argument("<workflow>", "Workflow name or hash")
|
|
179
|
-
.requiredOption("-p, --prompt <text>", "User prompt")
|
|
180
|
-
.option("--cwd <path>", "Working directory for thread execution (default: process.cwd())")
|
|
181
|
-
.action((workflow: string, opts: { prompt: string; cwd: string | undefined }) => {
|
|
182
|
-
const storageRoot = resolveStorageRoot();
|
|
183
|
-
runAction(async () => {
|
|
184
|
-
const result = await cmdThreadStart(
|
|
185
|
-
storageRoot,
|
|
186
|
-
workflow,
|
|
187
|
-
opts.prompt,
|
|
188
|
-
process.cwd(),
|
|
189
|
-
opts.cwd ?? process.cwd(),
|
|
190
|
-
);
|
|
191
|
-
await writeOutput(toThreadStartPayload(result), "thread-start", storageRoot);
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
thread
|
|
196
|
-
.command("exec")
|
|
197
|
-
.description("Execute one or more steps")
|
|
198
|
-
.argument("<thread-id>", "Thread ULID")
|
|
199
|
-
.option("--agent <cmd>", "Override agent command")
|
|
200
|
-
.option("-c, --count <number>", "Number of steps to run (default: 1)")
|
|
201
|
-
.option("--background", "Run in background and return immediately")
|
|
202
|
-
.option("--_background-worker", "Internal flag for background worker process", false)
|
|
203
|
-
.action(
|
|
204
|
-
(
|
|
205
|
-
threadId: string,
|
|
206
|
-
opts: {
|
|
207
|
-
agent: string | undefined;
|
|
208
|
-
count: string | undefined;
|
|
209
|
-
background: boolean;
|
|
210
|
-
_backgroundWorker: boolean;
|
|
211
|
-
},
|
|
212
|
-
) => {
|
|
213
|
-
const storageRoot = resolveStorageRoot();
|
|
214
|
-
runAction(async () => {
|
|
215
|
-
const agentOverride = opts.agent ?? null;
|
|
216
|
-
const count = opts.count !== undefined ? Number(opts.count) : 1;
|
|
217
|
-
const background = opts.background ?? false;
|
|
218
|
-
const backgroundWorker = opts._backgroundWorker ?? false;
|
|
219
|
-
|
|
220
|
-
const results = await cmdThreadExec(
|
|
221
|
-
storageRoot,
|
|
222
|
-
threadId,
|
|
223
|
-
agentOverride,
|
|
224
|
-
count,
|
|
225
|
-
background,
|
|
226
|
-
backgroundWorker,
|
|
227
|
-
);
|
|
228
|
-
await writeOutput(toThreadExecPayload(results), "thread-exec", storageRoot);
|
|
229
|
-
});
|
|
230
|
-
},
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
thread
|
|
234
|
-
.command("show")
|
|
235
|
-
.description("Show thread head pointer")
|
|
236
|
-
.argument("<thread-id>", "Thread ULID")
|
|
237
|
-
.action((threadId: string) => {
|
|
238
|
-
const storageRoot = resolveStorageRoot();
|
|
239
|
-
runAction(async () => {
|
|
240
|
-
const result = await cmdThreadShow(storageRoot, threadId);
|
|
241
|
-
await writeOutput(toThreadStatusPayload(result), "thread-status", storageRoot);
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
// Helper functions for thread list command parsing
|
|
246
128
|
function parseStatusFilter(status: string | undefined): ThreadStatus[] | null {
|
|
247
129
|
if (status === undefined) return null;
|
|
248
130
|
const raw = status.trim();
|
|
@@ -308,123 +190,850 @@ function parsePaginationOptions(
|
|
|
308
190
|
return { skip: skipVal, take: takeVal };
|
|
309
191
|
}
|
|
310
192
|
|
|
311
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Parse a `step turns` `--limit`/`--offset` value into a non-negative integer, or
|
|
195
|
+
* `null` when the flag is absent (the OCAS `ListOptions` "no limit" / offset-0
|
|
196
|
+
* convention). `--limit 0` is a legal value (renders no turns); negative or
|
|
197
|
+
* non-numeric values are a CLI usage error (exit non-zero). The `flag` label is
|
|
198
|
+
* used verbatim in the error message.
|
|
199
|
+
*/
|
|
200
|
+
function parseTurnsPageOption(flag: string, value: string | undefined): number | null {
|
|
201
|
+
if (value === undefined) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const trimmed = value.trim();
|
|
205
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
206
|
+
process.stderr.write(`${flag} must be a non-negative integer\n`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
return Number.parseInt(trimmed, 10);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Resolve `thread list` pagination from both the canonical repo-wide
|
|
214
|
+
* `ListOptions` vocabulary (`--limit`/`--offset`, as used by `step turns`) and
|
|
215
|
+
* the backward-compatible legacy aliases (`--skip`/`--take`). The canonical
|
|
216
|
+
* flags map onto the existing `cmdThreadList` parameters: `--limit` → `take`
|
|
217
|
+
* (max items), `--offset` → `skip` (items skipped from the front of the
|
|
218
|
+
* newest-first list). When both a canonical flag and its legacy alias are
|
|
219
|
+
* supplied, the canonical flag wins and the alias is the fallback.
|
|
220
|
+
* `--limit`/`--offset` are validated via `parseTurnsPageOption` (same
|
|
221
|
+
* non-negative-integer rule and flag-named error as `step turns`); `--limit 0`
|
|
222
|
+
* is legal and yields no items (the `ListOptions` "no limit" convention treats
|
|
223
|
+
* an absent flag, not 0, as "all items").
|
|
224
|
+
*/
|
|
225
|
+
function resolveThreadListPagination(flags: {
|
|
226
|
+
skip: string | undefined;
|
|
227
|
+
take: string | undefined;
|
|
228
|
+
limit: string | undefined;
|
|
229
|
+
offset: string | undefined;
|
|
230
|
+
}): { skip: number | null; take: number | null } {
|
|
231
|
+
const legacy = parsePaginationOptions(flags.skip, flags.take);
|
|
232
|
+
const limit = parseTurnsPageOption("--limit", flags.limit);
|
|
233
|
+
const offset = parseTurnsPageOption("--offset", flags.offset);
|
|
234
|
+
return {
|
|
235
|
+
skip: offset ?? legacy.skip,
|
|
236
|
+
take: limit ?? legacy.take,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// --- Positional arg helper (cli-kit workaround: custom missing-arg message) ---
|
|
241
|
+
// cli-kit emits "Missing positional arguments" as NDJSON; tests expect a
|
|
242
|
+
// plain "missing required argument" message on stderr. We don't declare
|
|
243
|
+
// .arg() on commands and read positionals from the _positionals field that
|
|
244
|
+
// cli-kit injects into the flags object.
|
|
245
|
+
|
|
246
|
+
function getPositionals(flags: ParsedFlags): string[] {
|
|
247
|
+
const p = flags._positionals;
|
|
248
|
+
return Array.isArray(p) ? (p as string[]) : [];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function requirePositional(flags: ParsedFlags, index: number, name: string): string {
|
|
252
|
+
const positionals = getPositionals(flags);
|
|
253
|
+
const value = positionals[index];
|
|
254
|
+
if (value === undefined) {
|
|
255
|
+
process.stderr.write(`Error: missing required argument: ${name}\n`);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
return value;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// --- Help text (cli-kit v0.2.1 workaround: no per-command --help) ---
|
|
262
|
+
|
|
263
|
+
const TOP_LEVEL_HELP = `Usage: uwf <command> [options]
|
|
264
|
+
|
|
265
|
+
Stateless workflow CLI
|
|
266
|
+
|
|
267
|
+
Four-layer architecture:
|
|
268
|
+
workflow → thread → step → turn
|
|
269
|
+
|
|
270
|
+
Commands:
|
|
271
|
+
workflow Workflow definitions (layer 1: templates)
|
|
272
|
+
thread Thread execution (layer 2: instances)
|
|
273
|
+
step Step results (layer 3: single cycle)
|
|
274
|
+
prompt Built-in prompt references for agents
|
|
275
|
+
setup Configure the default agent
|
|
276
|
+
log Process-level debug logs
|
|
277
|
+
config Configuration management
|
|
278
|
+
|
|
279
|
+
Standard flags:
|
|
280
|
+
--format <fmt> Output format: text (default), json, yaml, raw-json, raw-yaml
|
|
281
|
+
-V, --version Show version
|
|
282
|
+
-h, --help Show this help
|
|
283
|
+
`;
|
|
284
|
+
|
|
285
|
+
const PROMPT_HELP = `Usage: uwf prompt <command>
|
|
286
|
+
|
|
287
|
+
Built-in prompt references for agents
|
|
288
|
+
|
|
289
|
+
Commands:
|
|
290
|
+
usage Print the usage reference (CLI guide + typical workflows)
|
|
291
|
+
bootstrap Print setup instructions for installing uwf skills
|
|
292
|
+
workflow-authoring Print the workflow authoring reference (YAML design guide)
|
|
293
|
+
adapter-developing Print the adapter developing reference (building agent adapters)
|
|
294
|
+
list List all available prompt names
|
|
295
|
+
`;
|
|
296
|
+
|
|
297
|
+
const WORKFLOW_HELP = `Usage: uwf workflow <command>
|
|
298
|
+
|
|
299
|
+
Workflow definitions (layer 1: templates)
|
|
300
|
+
|
|
301
|
+
Commands:
|
|
302
|
+
add Register a workflow from YAML
|
|
303
|
+
validate Validate a workflow YAML without registering it (CI-friendly)
|
|
304
|
+
show Show a workflow by name or CAS hash
|
|
305
|
+
list List registered workflows
|
|
306
|
+
`;
|
|
307
|
+
|
|
308
|
+
const WORKFLOW_ADD_HELP = `Usage: uwf workflow add <file>
|
|
309
|
+
|
|
310
|
+
Register a workflow from YAML
|
|
311
|
+
|
|
312
|
+
Arguments:
|
|
313
|
+
file Workflow YAML file
|
|
314
|
+
`;
|
|
315
|
+
|
|
316
|
+
const WORKFLOW_VALIDATE_HELP = `Usage: uwf workflow validate <file>
|
|
317
|
+
|
|
318
|
+
Validate a workflow YAML without registering it (CI-friendly)
|
|
319
|
+
|
|
320
|
+
Arguments:
|
|
321
|
+
file Workflow YAML file
|
|
322
|
+
`;
|
|
323
|
+
|
|
324
|
+
const WORKFLOW_SHOW_HELP = `Usage: uwf workflow show <id>
|
|
325
|
+
|
|
326
|
+
Show a workflow by name or CAS hash
|
|
327
|
+
|
|
328
|
+
Arguments:
|
|
329
|
+
id Workflow name or hash
|
|
330
|
+
`;
|
|
331
|
+
|
|
332
|
+
const WORKFLOW_LIST_HELP = `Usage: uwf workflow list
|
|
333
|
+
|
|
334
|
+
List registered workflows
|
|
335
|
+
`;
|
|
336
|
+
|
|
337
|
+
const THREAD_HELP = `Usage: uwf thread <command>
|
|
338
|
+
|
|
339
|
+
Thread execution (layer 2: instances)
|
|
340
|
+
|
|
341
|
+
Commands:
|
|
342
|
+
start Create a thread without executing
|
|
343
|
+
exec Execute one or more steps
|
|
344
|
+
show Show thread head pointer
|
|
345
|
+
list List threads (defaults to active: idle + running + corrupt)
|
|
346
|
+
resume Resume a suspended thread and re-run the suspended role
|
|
347
|
+
poke Re-run the head step's agent with a supplementary prompt
|
|
348
|
+
stop Stop background execution of a thread (keep thread active)
|
|
349
|
+
cancel Cancel a thread (stop execution and move to history)
|
|
350
|
+
join Block until a running thread finishes, then return the final result
|
|
351
|
+
read Read thread context as human-readable markdown
|
|
352
|
+
`;
|
|
353
|
+
|
|
354
|
+
const THREAD_START_HELP = `Usage: uwf thread start <workflow> [options]
|
|
355
|
+
|
|
356
|
+
Create a thread without executing
|
|
357
|
+
|
|
358
|
+
Arguments:
|
|
359
|
+
workflow Workflow name or hash
|
|
360
|
+
|
|
361
|
+
Options:
|
|
362
|
+
-p, --prompt <text> User prompt (required)
|
|
363
|
+
--cwd <path> Working directory for thread execution (default: process.cwd())
|
|
364
|
+
`;
|
|
365
|
+
|
|
366
|
+
const THREAD_EXEC_HELP = `Usage: uwf thread exec <thread-id> [options]
|
|
367
|
+
|
|
368
|
+
Execute one or more steps
|
|
369
|
+
|
|
370
|
+
Arguments:
|
|
371
|
+
thread-id Thread ULID
|
|
372
|
+
|
|
373
|
+
Options:
|
|
374
|
+
--agent <cmd> Override agent command
|
|
375
|
+
-c, --count <number> Number of steps to run (default: 1)
|
|
376
|
+
--background Run in background and return immediately
|
|
377
|
+
`;
|
|
378
|
+
|
|
379
|
+
const THREAD_SHOW_HELP = `Usage: uwf thread show <thread-id>
|
|
380
|
+
|
|
381
|
+
Show thread head pointer
|
|
382
|
+
|
|
383
|
+
Arguments:
|
|
384
|
+
thread-id Thread ULID
|
|
385
|
+
`;
|
|
386
|
+
|
|
387
|
+
const THREAD_LIST_HELP = `Usage: uwf thread list [options]
|
|
388
|
+
|
|
389
|
+
List threads (defaults to active: idle + running + corrupt)
|
|
390
|
+
|
|
391
|
+
Options:
|
|
392
|
+
--status <status> Filter by status: idle, running, end, cancelled, active, or comma-separated
|
|
393
|
+
--all Show all threads regardless of status
|
|
394
|
+
--after <date> Filter threads created after this date
|
|
395
|
+
--before <date> Filter threads created before this date
|
|
396
|
+
--limit <n> Return at most n threads (newest first)
|
|
397
|
+
--offset <m> Skip the first m threads (newest first)
|
|
398
|
+
--take <n> Alias for --limit
|
|
399
|
+
--skip <n> Alias for --offset
|
|
400
|
+
`;
|
|
401
|
+
|
|
402
|
+
const THREAD_RESUME_HELP = `Usage: uwf thread resume <thread-id> [options]
|
|
403
|
+
|
|
404
|
+
Resume a suspended thread and re-run the suspended role
|
|
405
|
+
|
|
406
|
+
Arguments:
|
|
407
|
+
thread-id Thread ULID
|
|
408
|
+
|
|
409
|
+
Options:
|
|
410
|
+
-p, --prompt <text> Supplementary info to append to the resume prompt
|
|
411
|
+
--agent <cmd> Override agent command
|
|
412
|
+
`;
|
|
413
|
+
|
|
414
|
+
const THREAD_POKE_HELP = `Usage: uwf thread poke <thread-id> [options]
|
|
415
|
+
|
|
416
|
+
Re-run the head step's agent with a supplementary prompt (replaces head step)
|
|
417
|
+
|
|
418
|
+
Arguments:
|
|
419
|
+
thread-id Thread ULID
|
|
420
|
+
|
|
421
|
+
Options:
|
|
422
|
+
-p, --prompt <text> Supplementary prompt for the agent (required)
|
|
423
|
+
--agent <cmd> Override agent command (defaults to head step's agent)
|
|
424
|
+
`;
|
|
425
|
+
|
|
426
|
+
const THREAD_STOP_HELP = `Usage: uwf thread stop <thread-id>
|
|
427
|
+
|
|
428
|
+
Stop background execution of a thread (keep thread active)
|
|
429
|
+
|
|
430
|
+
Arguments:
|
|
431
|
+
thread-id Thread ULID
|
|
432
|
+
`;
|
|
433
|
+
|
|
434
|
+
const THREAD_CANCEL_HELP = `Usage: uwf thread cancel <thread-id>
|
|
435
|
+
|
|
436
|
+
Cancel a thread (stop execution and move to history)
|
|
437
|
+
|
|
438
|
+
Arguments:
|
|
439
|
+
thread-id Thread ULID
|
|
440
|
+
`;
|
|
441
|
+
|
|
442
|
+
const THREAD_JOIN_HELP = `Usage: uwf thread join <thread-id> [options]
|
|
443
|
+
|
|
444
|
+
Block until a running thread finishes, then return the final result
|
|
445
|
+
|
|
446
|
+
Arguments:
|
|
447
|
+
thread-id Thread ULID
|
|
448
|
+
|
|
449
|
+
Options:
|
|
450
|
+
--timeout <seconds> Max seconds to wait before giving up
|
|
451
|
+
`;
|
|
452
|
+
|
|
453
|
+
const THREAD_READ_HELP = `Usage: uwf thread read <thread-id> [options]
|
|
454
|
+
|
|
455
|
+
Read thread context as human-readable markdown
|
|
456
|
+
|
|
457
|
+
Arguments:
|
|
458
|
+
thread-id Thread ULID
|
|
459
|
+
|
|
460
|
+
Options:
|
|
461
|
+
--quota <chars> Max output characters
|
|
462
|
+
--before <step-hash> Load steps before this hash (exclusive)
|
|
463
|
+
--start Include start step in output
|
|
464
|
+
`;
|
|
465
|
+
|
|
466
|
+
const STEP_HELP = `Usage: uwf step <command>
|
|
467
|
+
|
|
468
|
+
Step results (layer 3: single cycle)
|
|
469
|
+
|
|
470
|
+
Commands:
|
|
471
|
+
list List all steps in a thread
|
|
472
|
+
show Show details of a specific step
|
|
473
|
+
ask Ask a follow-up question to a historical step's agent
|
|
474
|
+
read Read a step's turns as human-readable markdown
|
|
475
|
+
turns Show all turns across a thread's steps
|
|
476
|
+
fork Fork a thread from a specific step
|
|
477
|
+
`;
|
|
478
|
+
|
|
479
|
+
const STEP_LIST_HELP = `Usage: uwf step list <thread-id>
|
|
480
|
+
|
|
481
|
+
List all steps in a thread
|
|
482
|
+
|
|
483
|
+
Arguments:
|
|
484
|
+
thread-id Thread ULID
|
|
485
|
+
`;
|
|
486
|
+
|
|
487
|
+
const STEP_SHOW_HELP = `Usage: uwf step show <step-hash>
|
|
488
|
+
|
|
489
|
+
Show details of a specific step
|
|
490
|
+
|
|
491
|
+
Arguments:
|
|
492
|
+
step-hash CAS hash of the StepNode
|
|
493
|
+
`;
|
|
494
|
+
|
|
495
|
+
const STEP_ASK_HELP = `Usage: uwf step ask <step-hash> [options]
|
|
496
|
+
|
|
497
|
+
Ask a follow-up question to a historical step's agent (read-only; no thread mutation)
|
|
498
|
+
|
|
499
|
+
Arguments:
|
|
500
|
+
step-hash CAS hash of the StepNode to query
|
|
501
|
+
|
|
502
|
+
Options:
|
|
503
|
+
-p, --prompt <text> Question to ask the step's agent (required)
|
|
504
|
+
--agent <cmd> Override agent command
|
|
505
|
+
--no-fork Skip session-fork; spawn fresh ask session
|
|
506
|
+
`;
|
|
507
|
+
|
|
508
|
+
const STEP_READ_HELP = `Usage: uwf step read <step-hash> [options]
|
|
509
|
+
|
|
510
|
+
Read a step's turns as human-readable markdown
|
|
511
|
+
|
|
512
|
+
Arguments:
|
|
513
|
+
step-hash CAS hash of the StepNode
|
|
514
|
+
|
|
515
|
+
Options:
|
|
516
|
+
--quota <chars> Max output characters (default: 4000)
|
|
517
|
+
--prompt Show the assembled prompt sent to the agent
|
|
518
|
+
`;
|
|
519
|
+
|
|
520
|
+
const STEP_TURNS_HELP = `Usage: uwf step turns <thread-id> [options]
|
|
521
|
+
|
|
522
|
+
Show all turns across a thread's steps (the whole-chain panorama)
|
|
523
|
+
|
|
524
|
+
Arguments:
|
|
525
|
+
thread-id Thread ULID
|
|
526
|
+
|
|
527
|
+
Options:
|
|
528
|
+
--role <role> Filter to one role's steps across the whole chain
|
|
529
|
+
--live Follow the in-flight step's turns
|
|
530
|
+
--limit <n> Max turns to show from the flattened cross-step sequence
|
|
531
|
+
--offset <n> Skip the first N turns of the flattened cross-step sequence
|
|
532
|
+
`;
|
|
533
|
+
|
|
534
|
+
const STEP_FORK_HELP = `Usage: uwf step fork <step-hash>
|
|
535
|
+
|
|
536
|
+
Fork a thread from a specific step
|
|
537
|
+
|
|
538
|
+
Arguments:
|
|
539
|
+
step-hash CAS hash of the StartNode or StepNode to fork from
|
|
540
|
+
`;
|
|
541
|
+
|
|
542
|
+
const SETUP_HELP = `Usage: uwf setup [options]
|
|
543
|
+
|
|
544
|
+
Configure the default agent. Run without --agent for interactive wizard.
|
|
545
|
+
|
|
546
|
+
Options:
|
|
547
|
+
--agent <name> Default agent adapter (e.g. builtin, or a Sumeru gateway alias)
|
|
548
|
+
`;
|
|
549
|
+
|
|
550
|
+
const LOG_HELP = `Usage: uwf log <command>
|
|
551
|
+
|
|
552
|
+
Process-level debug logs
|
|
553
|
+
|
|
554
|
+
Commands:
|
|
555
|
+
list List log files with sizes
|
|
556
|
+
show Show and filter log entries
|
|
557
|
+
clean Delete log files older than given date
|
|
558
|
+
`;
|
|
559
|
+
|
|
560
|
+
const LOG_LIST_HELP = `Usage: uwf log list
|
|
561
|
+
|
|
562
|
+
List log files with sizes
|
|
563
|
+
`;
|
|
564
|
+
|
|
565
|
+
const LOG_SHOW_HELP = `Usage: uwf log show [options]
|
|
566
|
+
|
|
567
|
+
Show and filter log entries
|
|
568
|
+
|
|
569
|
+
Options:
|
|
570
|
+
--thread <thread-id> Filter by thread ID
|
|
571
|
+
--process <pid> Filter by process ID
|
|
572
|
+
--date <date> Filter by date (YYYY-MM-DD)
|
|
573
|
+
`;
|
|
574
|
+
|
|
575
|
+
const LOG_CLEAN_HELP = `Usage: uwf log clean --before <date>
|
|
576
|
+
|
|
577
|
+
Delete log files older than given date
|
|
578
|
+
|
|
579
|
+
Options:
|
|
580
|
+
--before <date> Delete files before this date (YYYY-MM-DD) (required)
|
|
581
|
+
`;
|
|
582
|
+
|
|
583
|
+
const CONFIG_HELP = `Usage: uwf config <command>
|
|
584
|
+
|
|
585
|
+
Configuration management
|
|
586
|
+
|
|
587
|
+
Commands:
|
|
588
|
+
list Display all configuration values (masks API keys)
|
|
589
|
+
get Get a specific configuration value
|
|
590
|
+
set Set a specific configuration value
|
|
591
|
+
`;
|
|
592
|
+
|
|
593
|
+
const CONFIG_LIST_HELP = `Usage: uwf config list
|
|
594
|
+
|
|
595
|
+
Display all configuration values (masks API keys)
|
|
596
|
+
`;
|
|
597
|
+
|
|
598
|
+
const CONFIG_GET_HELP = `Usage: uwf config get <key>
|
|
599
|
+
|
|
600
|
+
Get a specific configuration value
|
|
601
|
+
|
|
602
|
+
Arguments:
|
|
603
|
+
key Dot-notation path to config value
|
|
604
|
+
`;
|
|
605
|
+
|
|
606
|
+
const CONFIG_SET_HELP = `Usage: uwf config set <key> <value>
|
|
607
|
+
|
|
608
|
+
Set a specific configuration value
|
|
609
|
+
|
|
610
|
+
Arguments:
|
|
611
|
+
key Dot-notation path to config value
|
|
612
|
+
value New value (use JSON array for 'args' key)
|
|
613
|
+
`;
|
|
614
|
+
|
|
615
|
+
const HELP_MAP: Record<string, string> = {
|
|
616
|
+
"": TOP_LEVEL_HELP,
|
|
617
|
+
prompt: PROMPT_HELP,
|
|
618
|
+
workflow: WORKFLOW_HELP,
|
|
619
|
+
"workflow add": WORKFLOW_ADD_HELP,
|
|
620
|
+
"workflow validate": WORKFLOW_VALIDATE_HELP,
|
|
621
|
+
"workflow show": WORKFLOW_SHOW_HELP,
|
|
622
|
+
"workflow list": WORKFLOW_LIST_HELP,
|
|
623
|
+
thread: THREAD_HELP,
|
|
624
|
+
"thread start": THREAD_START_HELP,
|
|
625
|
+
"thread exec": THREAD_EXEC_HELP,
|
|
626
|
+
"thread show": THREAD_SHOW_HELP,
|
|
627
|
+
"thread list": THREAD_LIST_HELP,
|
|
628
|
+
"thread resume": THREAD_RESUME_HELP,
|
|
629
|
+
"thread poke": THREAD_POKE_HELP,
|
|
630
|
+
"thread stop": THREAD_STOP_HELP,
|
|
631
|
+
"thread cancel": THREAD_CANCEL_HELP,
|
|
632
|
+
"thread join": THREAD_JOIN_HELP,
|
|
633
|
+
"thread read": THREAD_READ_HELP,
|
|
634
|
+
step: STEP_HELP,
|
|
635
|
+
"step list": STEP_LIST_HELP,
|
|
636
|
+
"step show": STEP_SHOW_HELP,
|
|
637
|
+
"step ask": STEP_ASK_HELP,
|
|
638
|
+
"step read": STEP_READ_HELP,
|
|
639
|
+
"step turns": STEP_TURNS_HELP,
|
|
640
|
+
"step fork": STEP_FORK_HELP,
|
|
641
|
+
setup: SETUP_HELP,
|
|
642
|
+
log: LOG_HELP,
|
|
643
|
+
"log list": LOG_LIST_HELP,
|
|
644
|
+
"log show": LOG_SHOW_HELP,
|
|
645
|
+
"log clean": LOG_CLEAN_HELP,
|
|
646
|
+
config: CONFIG_HELP,
|
|
647
|
+
"config list": CONFIG_LIST_HELP,
|
|
648
|
+
"config get": CONFIG_GET_HELP,
|
|
649
|
+
"config set": CONFIG_SET_HELP,
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
// --- Early intercepts (cli-kit v0.2.1 workarounds) ---
|
|
653
|
+
|
|
654
|
+
/** Print help text for the command path extracted from argv, then exit. */
|
|
655
|
+
function printHelp(argv: string[]): void {
|
|
656
|
+
const helpIdx = argv.findIndex((t) => t === "--help" || t === "-h");
|
|
657
|
+
const tokens = helpIdx >= 0 ? argv.slice(0, helpIdx).filter((t) => !t.startsWith("-")) : [];
|
|
658
|
+
for (let len = tokens.length; len >= 0; len--) {
|
|
659
|
+
const path = tokens.slice(0, len).join(" ");
|
|
660
|
+
const text = HELP_MAP[path];
|
|
661
|
+
if (text !== undefined) {
|
|
662
|
+
process.stdout.write(text);
|
|
663
|
+
process.exit(0);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
process.stdout.write(TOP_LEVEL_HELP);
|
|
667
|
+
process.exit(0);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/** Intercept deprecated commands before cli-kit parsing. Prints message + exit(1). */
|
|
671
|
+
function handleDeprecated(argv: string[]): void {
|
|
672
|
+
const [cmd, sub] = argv;
|
|
673
|
+
if (cmd === "workflow" && sub === "put") {
|
|
674
|
+
process.stderr.write(`Error: Command 'workflow put' has been removed.
|
|
675
|
+
Use 'workflow add' instead.
|
|
676
|
+
|
|
677
|
+
For more information, see: uwf help workflow add
|
|
678
|
+
`);
|
|
679
|
+
process.exit(1);
|
|
680
|
+
}
|
|
681
|
+
if (cmd === "thread") {
|
|
682
|
+
if (sub === "step") {
|
|
683
|
+
process.stderr.write(`Error: Command 'thread step' has been removed.
|
|
684
|
+
Use 'thread exec' instead.
|
|
685
|
+
|
|
686
|
+
For more information, see: uwf help thread exec
|
|
687
|
+
`);
|
|
688
|
+
process.exit(1);
|
|
689
|
+
}
|
|
690
|
+
if (sub === "steps") {
|
|
691
|
+
process.stderr.write(`Error: Command 'thread steps' has been removed.
|
|
692
|
+
Use 'step list' instead.
|
|
693
|
+
|
|
694
|
+
For more information, see: uwf help step list
|
|
695
|
+
`);
|
|
696
|
+
process.exit(1);
|
|
697
|
+
}
|
|
698
|
+
if (sub === "step-details") {
|
|
699
|
+
process.stderr.write(`Error: Command 'thread step-details' has been removed.
|
|
700
|
+
Use 'step show' instead.
|
|
701
|
+
|
|
702
|
+
For more information, see: uwf help step show
|
|
703
|
+
`);
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
if (sub === "fork") {
|
|
707
|
+
process.stderr.write(`Error: Command 'thread fork' has been removed.
|
|
708
|
+
Use 'step fork' instead.
|
|
709
|
+
|
|
710
|
+
For more information, see: uwf help step fork
|
|
711
|
+
`);
|
|
712
|
+
process.exit(1);
|
|
713
|
+
}
|
|
714
|
+
if (sub === "kill") {
|
|
715
|
+
process.stderr.write(`Error: Command 'thread kill' has been removed.
|
|
716
|
+
Use 'thread stop' to stop background execution (keep thread active),
|
|
717
|
+
or 'thread cancel' to cancel and archive the thread.
|
|
718
|
+
|
|
719
|
+
For more information, see:
|
|
720
|
+
uwf help thread stop
|
|
721
|
+
uwf help thread cancel
|
|
722
|
+
`);
|
|
723
|
+
process.exit(1);
|
|
724
|
+
}
|
|
725
|
+
if (sub === "running") {
|
|
726
|
+
process.stderr.write(`Error: Command 'thread running' has been removed.
|
|
727
|
+
Use 'thread list --status running' instead.
|
|
728
|
+
|
|
729
|
+
For more information, see: uwf help thread list
|
|
730
|
+
`);
|
|
731
|
+
process.exit(1);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/** Strip `--format <value>` / `--format=value` from argv, returning cleaned argv. */
|
|
737
|
+
function stripFormatFlag(argv: string[]): string[] {
|
|
738
|
+
const out: string[] = [];
|
|
739
|
+
for (let i = 0; i < argv.length; i++) {
|
|
740
|
+
const token = argv[i];
|
|
741
|
+
if (token === "--format") {
|
|
742
|
+
const value = argv[i + 1];
|
|
743
|
+
if (value !== undefined) {
|
|
744
|
+
formatOverride = value;
|
|
745
|
+
i++;
|
|
746
|
+
}
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
if (token.startsWith("--format=")) {
|
|
750
|
+
formatOverride = token.slice("--format=".length);
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
out.push(token);
|
|
754
|
+
}
|
|
755
|
+
return out;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/** Strip `--count <value>` / `--count=value` / `-c <value>` from argv. */
|
|
759
|
+
function stripCountFlag(argv: string[]): string[] {
|
|
760
|
+
const out: string[] = [];
|
|
761
|
+
for (let i = 0; i < argv.length; i++) {
|
|
762
|
+
const token = argv[i];
|
|
763
|
+
if (token === "--count" || token === "-c") {
|
|
764
|
+
const value = argv[i + 1];
|
|
765
|
+
if (value !== undefined) {
|
|
766
|
+
countOverride = value;
|
|
767
|
+
i++;
|
|
768
|
+
}
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
if (token.startsWith("--count=")) {
|
|
772
|
+
countOverride = token.slice("--count=".length);
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
out.push(token);
|
|
776
|
+
}
|
|
777
|
+
return out;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// --- Build CLI with @ocas/cli-kit ---
|
|
781
|
+
|
|
782
|
+
const cli = createCLI({
|
|
783
|
+
name: "uwf",
|
|
784
|
+
version: VERSION,
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
const unknownSchema = z.unknown();
|
|
788
|
+
|
|
789
|
+
// ── workflow group ───────────────────────────────────────────────────────────
|
|
790
|
+
|
|
791
|
+
const workflow = cli.command("workflow");
|
|
792
|
+
|
|
793
|
+
workflow
|
|
794
|
+
.command("add")
|
|
795
|
+
.returns(unknownSchema, "")
|
|
796
|
+
.action(async (_args, flags) => {
|
|
797
|
+
const file = requirePositional(flags, 0, "file");
|
|
798
|
+
const storageRoot = resolveStorageRoot();
|
|
799
|
+
await runAction(async () => {
|
|
800
|
+
const result = await cmdWorkflowAdd(storageRoot, file);
|
|
801
|
+
await writeOutput(toWorkflowAddPayload(result), "workflow-add", storageRoot);
|
|
802
|
+
});
|
|
803
|
+
return undefined;
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
workflow
|
|
807
|
+
.command("validate")
|
|
808
|
+
.returns(unknownSchema, "")
|
|
809
|
+
.action(async (_args, flags) => {
|
|
810
|
+
const file = requirePositional(flags, 0, "file");
|
|
811
|
+
const storageRoot = resolveStorageRoot();
|
|
812
|
+
await runAction(async () => {
|
|
813
|
+
const errors = await cmdWorkflowValidate(file);
|
|
814
|
+
await writeOutput(toValidateResultPayload(errors), "validate-result", storageRoot);
|
|
815
|
+
if (errors.length > 0) {
|
|
816
|
+
process.exit(1);
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
return undefined;
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
workflow
|
|
823
|
+
.command("show")
|
|
824
|
+
.returns(unknownSchema, "")
|
|
825
|
+
.action(async (_args, flags) => {
|
|
826
|
+
const id = requirePositional(flags, 0, "id");
|
|
827
|
+
const storageRoot = resolveStorageRoot();
|
|
828
|
+
await runAction(async () => {
|
|
829
|
+
const result = await cmdWorkflowShow(storageRoot, id, process.cwd());
|
|
830
|
+
await writeOutput(toWorkflowDetailPayload(result), "workflow-detail", storageRoot);
|
|
831
|
+
});
|
|
832
|
+
return undefined;
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
workflow
|
|
312
836
|
.command("list")
|
|
313
|
-
.
|
|
314
|
-
.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
all: boolean | undefined;
|
|
327
|
-
after: string | undefined;
|
|
328
|
-
before: string | undefined;
|
|
329
|
-
skip: string | undefined;
|
|
330
|
-
take: string | undefined;
|
|
331
|
-
}) => {
|
|
332
|
-
const storageRoot = resolveStorageRoot();
|
|
333
|
-
runAction(async () => {
|
|
334
|
-
const statusFilter = parseStatusFilter(opts.status);
|
|
335
|
-
const nowMs = Date.now();
|
|
336
|
-
const { afterMs, beforeMs } = parseTimeFilters(opts.after, opts.before, nowMs);
|
|
337
|
-
const { skip, take } = parsePaginationOptions(opts.skip, opts.take);
|
|
338
|
-
const showAll = opts.all === true;
|
|
339
|
-
|
|
340
|
-
const result = await cmdThreadList(
|
|
341
|
-
storageRoot,
|
|
342
|
-
statusFilter,
|
|
343
|
-
afterMs,
|
|
344
|
-
beforeMs,
|
|
345
|
-
skip,
|
|
346
|
-
take,
|
|
347
|
-
showAll,
|
|
348
|
-
);
|
|
349
|
-
await writeOutput(toThreadListPayload(result), "thread-list", storageRoot);
|
|
350
|
-
});
|
|
351
|
-
},
|
|
352
|
-
);
|
|
837
|
+
.returns(unknownSchema, "")
|
|
838
|
+
.action(async () => {
|
|
839
|
+
const storageRoot = resolveStorageRoot();
|
|
840
|
+
await runAction(async () => {
|
|
841
|
+
const result = await cmdWorkflowList(storageRoot, process.cwd());
|
|
842
|
+
await writeOutput(toWorkflowListPayload(result), "workflow-list", storageRoot);
|
|
843
|
+
});
|
|
844
|
+
return undefined;
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// ── thread group ─────────────────────────────────────────────────────────────
|
|
848
|
+
|
|
849
|
+
const thread = cli.command("thread");
|
|
353
850
|
|
|
354
851
|
thread
|
|
355
|
-
.command("
|
|
356
|
-
.
|
|
357
|
-
.
|
|
358
|
-
.
|
|
359
|
-
.
|
|
360
|
-
.action((
|
|
852
|
+
.command("start")
|
|
853
|
+
.flag("prompt", { type: "string" })
|
|
854
|
+
.flag("p", { type: "string" })
|
|
855
|
+
.flag("cwd", { type: "string" })
|
|
856
|
+
.returns(unknownSchema, "")
|
|
857
|
+
.action(async (_args, flags) => {
|
|
858
|
+
const workflowName = requirePositional(flags, 0, "workflow");
|
|
859
|
+
const prompt = (flags.prompt as string | undefined) ?? (flags.p as string | undefined);
|
|
860
|
+
if (prompt === undefined) {
|
|
861
|
+
process.stderr.write("Error: missing required option: -p, --prompt <text>\n");
|
|
862
|
+
process.exit(1);
|
|
863
|
+
}
|
|
864
|
+
const storageRoot = resolveStorageRoot();
|
|
865
|
+
await runAction(async () => {
|
|
866
|
+
const result = await cmdThreadStart(
|
|
867
|
+
storageRoot,
|
|
868
|
+
workflowName,
|
|
869
|
+
prompt,
|
|
870
|
+
process.cwd(),
|
|
871
|
+
(flags.cwd as string | undefined) ?? process.cwd(),
|
|
872
|
+
);
|
|
873
|
+
await writeOutput(toThreadStartPayload(result), "thread-start", storageRoot);
|
|
874
|
+
});
|
|
875
|
+
return undefined;
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
thread
|
|
879
|
+
.command("exec")
|
|
880
|
+
.flag("agent", { type: "string" })
|
|
881
|
+
.flag("background", { type: "boolean", default: false })
|
|
882
|
+
.flag("_background-worker", { type: "boolean", default: false })
|
|
883
|
+
.returns(unknownSchema, "")
|
|
884
|
+
.action(async (_args, flags) => {
|
|
885
|
+
const threadId = requirePositional(flags, 0, "thread-id");
|
|
361
886
|
const storageRoot = resolveStorageRoot();
|
|
362
|
-
runAction(async () => {
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
const
|
|
887
|
+
await runAction(async () => {
|
|
888
|
+
const agentOverride = (flags.agent as string | undefined) ?? null;
|
|
889
|
+
const count = countOverride !== null ? Number(countOverride) : 1;
|
|
890
|
+
const background = flags.background as boolean;
|
|
891
|
+
const backgroundWorker = (flags["_background-worker"] as boolean) ?? false;
|
|
892
|
+
const results = await cmdThreadExec(
|
|
366
893
|
storageRoot,
|
|
367
|
-
threadId
|
|
368
|
-
supplement,
|
|
894
|
+
threadId,
|
|
369
895
|
agentOverride,
|
|
896
|
+
count,
|
|
897
|
+
background,
|
|
898
|
+
backgroundWorker,
|
|
370
899
|
);
|
|
900
|
+
await writeOutput(toThreadExecPayload(results), "thread-exec", storageRoot);
|
|
901
|
+
});
|
|
902
|
+
return undefined;
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
thread
|
|
906
|
+
.command("show")
|
|
907
|
+
.returns(unknownSchema, "")
|
|
908
|
+
.action(async (_args, flags) => {
|
|
909
|
+
const threadId = requirePositional(flags, 0, "thread-id");
|
|
910
|
+
const storageRoot = resolveStorageRoot();
|
|
911
|
+
await runAction(async () => {
|
|
912
|
+
const result = await cmdThreadShow(storageRoot, threadId);
|
|
371
913
|
await writeOutput(toThreadStatusPayload(result), "thread-status", storageRoot);
|
|
372
914
|
});
|
|
915
|
+
return undefined;
|
|
373
916
|
});
|
|
374
917
|
|
|
375
918
|
thread
|
|
376
|
-
.command("
|
|
377
|
-
.
|
|
378
|
-
.
|
|
379
|
-
.
|
|
380
|
-
.
|
|
381
|
-
.
|
|
919
|
+
.command("list")
|
|
920
|
+
.flag("status", { type: "string" })
|
|
921
|
+
.flag("all", { type: "boolean", default: false })
|
|
922
|
+
.flag("after", { type: "string" })
|
|
923
|
+
.flag("before", { type: "string" })
|
|
924
|
+
.flag("skip", { type: "string" })
|
|
925
|
+
.flag("take", { type: "string" })
|
|
926
|
+
.flag("limit", { type: "string" })
|
|
927
|
+
.flag("offset", { type: "string" })
|
|
928
|
+
.returns(unknownSchema, "")
|
|
929
|
+
.action(async (_args, flags) => {
|
|
382
930
|
const storageRoot = resolveStorageRoot();
|
|
383
|
-
runAction(async () => {
|
|
384
|
-
const
|
|
385
|
-
const
|
|
931
|
+
await runAction(async () => {
|
|
932
|
+
const statusFilter = parseStatusFilter(flags.status as string | undefined);
|
|
933
|
+
const nowMs = Date.now();
|
|
934
|
+
const { afterMs, beforeMs } = parseTimeFilters(
|
|
935
|
+
flags.after as string | undefined,
|
|
936
|
+
flags.before as string | undefined,
|
|
937
|
+
nowMs,
|
|
938
|
+
);
|
|
939
|
+
const { skip, take } = resolveThreadListPagination({
|
|
940
|
+
skip: flags.skip as string | undefined,
|
|
941
|
+
take: flags.take as string | undefined,
|
|
942
|
+
limit: flags.limit as string | undefined,
|
|
943
|
+
offset: flags.offset as string | undefined,
|
|
944
|
+
});
|
|
945
|
+
const showAll = flags.all === true;
|
|
946
|
+
const result = await cmdThreadList(
|
|
386
947
|
storageRoot,
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
948
|
+
statusFilter,
|
|
949
|
+
afterMs,
|
|
950
|
+
beforeMs,
|
|
951
|
+
skip,
|
|
952
|
+
take,
|
|
953
|
+
showAll,
|
|
390
954
|
);
|
|
955
|
+
await writeOutput(toThreadListPayload(result), "thread-list", storageRoot);
|
|
956
|
+
});
|
|
957
|
+
return undefined;
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
thread
|
|
961
|
+
.command("resume")
|
|
962
|
+
.flag("prompt", { type: "string" })
|
|
963
|
+
.flag("p", { type: "string" })
|
|
964
|
+
.flag("agent", { type: "string" })
|
|
965
|
+
.returns(unknownSchema, "")
|
|
966
|
+
.action(async (_args, flags) => {
|
|
967
|
+
const threadId = requirePositional(flags, 0, "thread-id") as ThreadId;
|
|
968
|
+
const storageRoot = resolveStorageRoot();
|
|
969
|
+
const prompt = (flags.prompt as string | undefined) ?? (flags.p as string | undefined);
|
|
970
|
+
await runAction(async () => {
|
|
971
|
+
const supplement = prompt ?? null;
|
|
972
|
+
const agentOverride = (flags.agent as string | undefined) ?? null;
|
|
973
|
+
const result = await cmdThreadResume(storageRoot, threadId, supplement, agentOverride);
|
|
391
974
|
await writeOutput(toThreadStatusPayload(result), "thread-status", storageRoot);
|
|
392
975
|
});
|
|
976
|
+
return undefined;
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
thread
|
|
980
|
+
.command("poke")
|
|
981
|
+
.flag("prompt", { type: "string" })
|
|
982
|
+
.flag("p", { type: "string" })
|
|
983
|
+
.flag("agent", { type: "string" })
|
|
984
|
+
.returns(unknownSchema, "")
|
|
985
|
+
.action(async (_args, flags) => {
|
|
986
|
+
const threadId = requirePositional(flags, 0, "thread-id") as ThreadId;
|
|
987
|
+
const prompt = (flags.prompt as string | undefined) ?? (flags.p as string | undefined);
|
|
988
|
+
if (prompt === undefined) {
|
|
989
|
+
process.stderr.write("Error: missing required option: -p, --prompt <text>\n");
|
|
990
|
+
process.exit(1);
|
|
991
|
+
}
|
|
992
|
+
const storageRoot = resolveStorageRoot();
|
|
993
|
+
await runAction(async () => {
|
|
994
|
+
const agentOverride = (flags.agent as string | undefined) ?? null;
|
|
995
|
+
const result = await cmdThreadPoke(storageRoot, threadId, prompt, agentOverride);
|
|
996
|
+
await writeOutput(toThreadStatusPayload(result), "thread-status", storageRoot);
|
|
997
|
+
});
|
|
998
|
+
return undefined;
|
|
393
999
|
});
|
|
394
1000
|
|
|
395
1001
|
thread
|
|
396
1002
|
.command("stop")
|
|
397
|
-
.
|
|
398
|
-
.
|
|
399
|
-
|
|
1003
|
+
.returns(unknownSchema, "")
|
|
1004
|
+
.action(async (_args, flags) => {
|
|
1005
|
+
const threadId = requirePositional(flags, 0, "thread-id");
|
|
400
1006
|
const storageRoot = resolveStorageRoot();
|
|
401
|
-
runAction(async () => {
|
|
1007
|
+
await runAction(async () => {
|
|
402
1008
|
const result = await cmdThreadStop(storageRoot, threadId);
|
|
403
1009
|
writeRawOutput(result, "thread stop");
|
|
404
1010
|
});
|
|
1011
|
+
return undefined;
|
|
405
1012
|
});
|
|
406
1013
|
|
|
407
1014
|
thread
|
|
408
1015
|
.command("cancel")
|
|
409
|
-
.
|
|
410
|
-
.
|
|
411
|
-
|
|
1016
|
+
.returns(unknownSchema, "")
|
|
1017
|
+
.action(async (_args, flags) => {
|
|
1018
|
+
const threadId = requirePositional(flags, 0, "thread-id");
|
|
412
1019
|
const storageRoot = resolveStorageRoot();
|
|
413
|
-
runAction(async () => {
|
|
1020
|
+
await runAction(async () => {
|
|
414
1021
|
const result = await cmdThreadCancel(storageRoot, threadId);
|
|
415
1022
|
writeRawOutput(result, "thread cancel");
|
|
416
1023
|
});
|
|
1024
|
+
return undefined;
|
|
417
1025
|
});
|
|
418
1026
|
|
|
419
1027
|
thread
|
|
420
1028
|
.command("join")
|
|
421
|
-
.
|
|
422
|
-
.
|
|
423
|
-
.
|
|
424
|
-
|
|
1029
|
+
.flag("timeout", { type: "string" })
|
|
1030
|
+
.returns(unknownSchema, "")
|
|
1031
|
+
.action(async (_args, flags) => {
|
|
1032
|
+
const threadId = requirePositional(flags, 0, "thread-id");
|
|
425
1033
|
const storageRoot = resolveStorageRoot();
|
|
426
|
-
runAction(async () => {
|
|
427
|
-
const
|
|
1034
|
+
await runAction(async () => {
|
|
1035
|
+
const timeoutRaw = flags.timeout as string | undefined;
|
|
1036
|
+
const timeoutMs = timeoutRaw !== undefined ? Number(timeoutRaw) * 1000 : null;
|
|
428
1037
|
if (timeoutMs !== null && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) {
|
|
429
1038
|
process.stderr.write("invalid --timeout: must be a positive number\n");
|
|
430
1039
|
process.exit(1);
|
|
@@ -432,375 +1041,339 @@ thread
|
|
|
432
1041
|
const results = await cmdThreadJoin(storageRoot, threadId, timeoutMs);
|
|
433
1042
|
await writeOutput(toThreadExecPayload(results), "thread-exec", storageRoot);
|
|
434
1043
|
});
|
|
1044
|
+
return undefined;
|
|
435
1045
|
});
|
|
436
1046
|
|
|
437
1047
|
thread
|
|
438
1048
|
.command("read")
|
|
439
|
-
.
|
|
440
|
-
.
|
|
441
|
-
.
|
|
442
|
-
.
|
|
443
|
-
.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
1049
|
+
.flag("quota", { type: "string", default: String(THREAD_READ_DEFAULT_QUOTA) })
|
|
1050
|
+
.flag("before", { type: "string" })
|
|
1051
|
+
.flag("start", { type: "boolean", default: false })
|
|
1052
|
+
.returns(unknownSchema, "")
|
|
1053
|
+
.action(async (_args, flags) => {
|
|
1054
|
+
const threadId = requirePositional(flags, 0, "thread-id") as ThreadId;
|
|
1055
|
+
const storageRoot = resolveStorageRoot();
|
|
1056
|
+
await runAction(async () => {
|
|
1057
|
+
const quota = Number.parseInt(flags.quota as string, 10);
|
|
1058
|
+
if (!Number.isFinite(quota) || quota < 1) {
|
|
1059
|
+
process.stderr.write("invalid --quota: must be a positive integer\n");
|
|
1060
|
+
process.exit(1);
|
|
1061
|
+
}
|
|
1062
|
+
const before = (flags.before as string | undefined) ?? null;
|
|
1063
|
+
const markdown = await cmdThreadRead(
|
|
1064
|
+
storageRoot,
|
|
1065
|
+
threadId,
|
|
1066
|
+
quota,
|
|
1067
|
+
before,
|
|
1068
|
+
(flags.start as boolean) ?? false,
|
|
1069
|
+
);
|
|
1070
|
+
process.stdout.write(markdown.endsWith("\n") ? markdown : `${markdown}\n`);
|
|
1071
|
+
});
|
|
1072
|
+
return undefined;
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
// ── step group ───────────────────────────────────────────────────────────────
|
|
465
1076
|
|
|
466
|
-
const step =
|
|
1077
|
+
const step = cli.command("step");
|
|
467
1078
|
|
|
468
1079
|
step
|
|
469
1080
|
.command("list")
|
|
470
|
-
.
|
|
471
|
-
.
|
|
472
|
-
|
|
1081
|
+
.returns(unknownSchema, "")
|
|
1082
|
+
.action(async (_args, flags) => {
|
|
1083
|
+
const threadId = requirePositional(flags, 0, "thread-id");
|
|
473
1084
|
const storageRoot = resolveStorageRoot();
|
|
474
|
-
runAction(async () => {
|
|
1085
|
+
await runAction(async () => {
|
|
475
1086
|
const result = await cmdStepList(storageRoot, threadId);
|
|
476
1087
|
await writeOutput(toStepListPayload(result), "step-list", storageRoot);
|
|
477
1088
|
});
|
|
1089
|
+
return undefined;
|
|
478
1090
|
});
|
|
479
1091
|
|
|
480
1092
|
step
|
|
481
1093
|
.command("show")
|
|
482
|
-
.
|
|
483
|
-
.
|
|
484
|
-
|
|
1094
|
+
.returns(unknownSchema, "")
|
|
1095
|
+
.action(async (_args, flags) => {
|
|
1096
|
+
const stepHash = requirePositional(flags, 0, "step-hash") as CasRef;
|
|
485
1097
|
const storageRoot = resolveStorageRoot();
|
|
486
|
-
runAction(async () => {
|
|
487
|
-
const detail = await cmdStepShow(storageRoot, stepHash
|
|
488
|
-
await writeOutput(
|
|
489
|
-
toStepDetailPayload(stepHash as CasRef, detail),
|
|
490
|
-
"step-detail",
|
|
491
|
-
storageRoot,
|
|
492
|
-
);
|
|
1098
|
+
await runAction(async () => {
|
|
1099
|
+
const detail = await cmdStepShow(storageRoot, stepHash);
|
|
1100
|
+
await writeOutput(toStepDetailPayload(stepHash, detail), "step-detail", storageRoot);
|
|
493
1101
|
});
|
|
1102
|
+
return undefined;
|
|
494
1103
|
});
|
|
495
1104
|
|
|
496
1105
|
step
|
|
497
1106
|
.command("ask")
|
|
498
|
-
.
|
|
499
|
-
|
|
500
|
-
)
|
|
501
|
-
.
|
|
502
|
-
.
|
|
503
|
-
.
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
});
|
|
517
|
-
process.stdout.write(stdout.endsWith("\n") ? stdout : `${stdout}\n`);
|
|
1107
|
+
.flag("prompt", { type: "string" })
|
|
1108
|
+
.flag("p", { type: "string" })
|
|
1109
|
+
.flag("agent", { type: "string" })
|
|
1110
|
+
.flag("no-fork", { type: "boolean", default: false })
|
|
1111
|
+
.returns(unknownSchema, "")
|
|
1112
|
+
.action(async (_args, flags) => {
|
|
1113
|
+
const stepHash = requirePositional(flags, 0, "step-hash") as CasRef;
|
|
1114
|
+
const prompt = (flags.prompt as string | undefined) ?? (flags.p as string | undefined);
|
|
1115
|
+
if (prompt === undefined) {
|
|
1116
|
+
process.stderr.write("Error: missing required option: -p, --prompt <text>\n");
|
|
1117
|
+
process.exit(1);
|
|
1118
|
+
}
|
|
1119
|
+
const storageRoot = resolveStorageRoot();
|
|
1120
|
+
await runAction(async () => {
|
|
1121
|
+
const stdout = await cmdStepAsk(storageRoot, stepHash, {
|
|
1122
|
+
prompt,
|
|
1123
|
+
agentOverride: (flags.agent as string | undefined) ?? null,
|
|
1124
|
+
fork: !(flags["no-fork"] as boolean),
|
|
518
1125
|
});
|
|
519
|
-
|
|
520
|
-
|
|
1126
|
+
process.stdout.write(stdout.endsWith("\n") ? stdout : `${stdout}\n`);
|
|
1127
|
+
});
|
|
1128
|
+
return undefined;
|
|
1129
|
+
});
|
|
521
1130
|
|
|
522
1131
|
step
|
|
523
1132
|
.command("read")
|
|
524
|
-
.
|
|
525
|
-
.
|
|
526
|
-
.
|
|
527
|
-
.
|
|
528
|
-
|
|
1133
|
+
.flag("quota", { type: "string", default: "4000" })
|
|
1134
|
+
.flag("prompt", { type: "boolean", default: false })
|
|
1135
|
+
.returns(unknownSchema, "")
|
|
1136
|
+
.action(async (_args, flags) => {
|
|
1137
|
+
const stepHash = requirePositional(flags, 0, "step-hash") as CasRef;
|
|
529
1138
|
const storageRoot = resolveStorageRoot();
|
|
530
|
-
runAction(async () => {
|
|
531
|
-
const quota = Number.parseInt(
|
|
1139
|
+
await runAction(async () => {
|
|
1140
|
+
const quota = Number.parseInt(flags.quota as string, 10);
|
|
532
1141
|
if (!Number.isFinite(quota) || quota < 1) {
|
|
533
1142
|
process.stderr.write("invalid --quota: must be a positive integer\n");
|
|
534
1143
|
process.exit(1);
|
|
535
1144
|
}
|
|
536
|
-
const markdown = await cmdStepRead(
|
|
537
|
-
storageRoot,
|
|
538
|
-
stepHash as CasRef,
|
|
539
|
-
quota,
|
|
540
|
-
opts.prompt === true,
|
|
541
|
-
);
|
|
1145
|
+
const markdown = await cmdStepRead(storageRoot, stepHash, quota, flags.prompt === true);
|
|
542
1146
|
process.stdout.write(markdown.endsWith("\n") ? markdown : `${markdown}\n`);
|
|
543
1147
|
});
|
|
1148
|
+
return undefined;
|
|
544
1149
|
});
|
|
545
1150
|
|
|
546
1151
|
step
|
|
547
|
-
.command("
|
|
548
|
-
.
|
|
549
|
-
.
|
|
550
|
-
.
|
|
1152
|
+
.command("turns")
|
|
1153
|
+
.flag("role", { type: "string" })
|
|
1154
|
+
.flag("live", { type: "boolean", default: false })
|
|
1155
|
+
.flag("limit", { type: "string" })
|
|
1156
|
+
.flag("offset", { type: "string" })
|
|
1157
|
+
.returns(unknownSchema, "")
|
|
1158
|
+
.action(async (_args, flags) => {
|
|
1159
|
+
const threadId = requirePositional(flags, 0, "thread-id") as ThreadId;
|
|
551
1160
|
const storageRoot = resolveStorageRoot();
|
|
552
|
-
runAction(async () => {
|
|
553
|
-
const
|
|
554
|
-
|
|
1161
|
+
await runAction(async () => {
|
|
1162
|
+
const limit = parseTurnsPageOption("--limit", flags.limit as string | undefined);
|
|
1163
|
+
const offset = parseTurnsPageOption("--offset", flags.offset as string | undefined) ?? 0;
|
|
1164
|
+
const markdown = await cmdStepTurns(storageRoot, threadId, {
|
|
1165
|
+
role: (flags.role as string | undefined) ?? null,
|
|
1166
|
+
live: flags.live === true,
|
|
1167
|
+
limit,
|
|
1168
|
+
offset,
|
|
1169
|
+
});
|
|
1170
|
+
if (markdown !== "") {
|
|
1171
|
+
process.stdout.write(markdown.endsWith("\n") ? markdown : `${markdown}\n`);
|
|
1172
|
+
}
|
|
555
1173
|
});
|
|
1174
|
+
return undefined;
|
|
556
1175
|
});
|
|
557
1176
|
|
|
558
|
-
|
|
559
|
-
// These commands have been removed. Show helpful error messages.
|
|
560
|
-
|
|
561
|
-
workflow
|
|
562
|
-
.command("put")
|
|
563
|
-
.description("[DEPRECATED] Use 'workflow add' instead")
|
|
564
|
-
.argument("<file>", "Workflow YAML file")
|
|
565
|
-
.action(() => {
|
|
566
|
-
process.stderr.write(`Error: Command 'workflow put' has been removed.
|
|
567
|
-
Use 'workflow add' instead.
|
|
568
|
-
|
|
569
|
-
For more information, see: uwf help workflow add
|
|
570
|
-
`);
|
|
571
|
-
process.exit(1);
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
thread
|
|
575
|
-
.command("step")
|
|
576
|
-
.description("[DEPRECATED] Use 'thread exec' instead")
|
|
577
|
-
.argument("<thread-id>", "Thread ULID")
|
|
578
|
-
.allowUnknownOption()
|
|
579
|
-
.action(() => {
|
|
580
|
-
process.stderr.write(`Error: Command 'thread step' has been removed.
|
|
581
|
-
Use 'thread exec' instead.
|
|
582
|
-
|
|
583
|
-
For more information, see: uwf help thread exec
|
|
584
|
-
`);
|
|
585
|
-
process.exit(1);
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
thread
|
|
589
|
-
.command("steps")
|
|
590
|
-
.description("[DEPRECATED] Use 'step list' instead")
|
|
591
|
-
.argument("<thread-id>", "Thread ULID")
|
|
592
|
-
.action(() => {
|
|
593
|
-
process.stderr.write(`Error: Command 'thread steps' has been removed.
|
|
594
|
-
Use 'step list' instead.
|
|
595
|
-
|
|
596
|
-
For more information, see: uwf help step list
|
|
597
|
-
`);
|
|
598
|
-
process.exit(1);
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
thread
|
|
602
|
-
.command("step-details")
|
|
603
|
-
.description("[DEPRECATED] Use 'step show' instead")
|
|
604
|
-
.argument("<step-hash>", "Step hash")
|
|
605
|
-
.action(() => {
|
|
606
|
-
process.stderr.write(`Error: Command 'thread step-details' has been removed.
|
|
607
|
-
Use 'step show' instead.
|
|
608
|
-
|
|
609
|
-
For more information, see: uwf help step show
|
|
610
|
-
`);
|
|
611
|
-
process.exit(1);
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
thread
|
|
1177
|
+
step
|
|
615
1178
|
.command("fork")
|
|
616
|
-
.
|
|
617
|
-
.
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
thread
|
|
628
|
-
.command("kill")
|
|
629
|
-
.description("[DEPRECATED] Use 'thread stop' or 'thread cancel' instead")
|
|
630
|
-
.argument("<thread-id>", "Thread ULID")
|
|
631
|
-
.action(() => {
|
|
632
|
-
process.stderr.write(`Error: Command 'thread kill' has been removed.
|
|
633
|
-
Use 'thread stop' to stop background execution (keep thread active),
|
|
634
|
-
or 'thread cancel' to cancel and archive the thread.
|
|
635
|
-
|
|
636
|
-
For more information, see:
|
|
637
|
-
uwf help thread stop
|
|
638
|
-
uwf help thread cancel
|
|
639
|
-
`);
|
|
640
|
-
process.exit(1);
|
|
1179
|
+
.returns(unknownSchema, "")
|
|
1180
|
+
.action(async (_args, flags) => {
|
|
1181
|
+
const stepHash = requirePositional(flags, 0, "step-hash") as CasRef;
|
|
1182
|
+
const storageRoot = resolveStorageRoot();
|
|
1183
|
+
await runAction(async () => {
|
|
1184
|
+
const result = await cmdStepFork(storageRoot, stepHash);
|
|
1185
|
+
writeRawOutput(result);
|
|
1186
|
+
});
|
|
1187
|
+
return undefined;
|
|
641
1188
|
});
|
|
642
1189
|
|
|
643
|
-
|
|
644
|
-
.command("running")
|
|
645
|
-
.description("[DEPRECATED] Use 'thread list --status running' instead")
|
|
646
|
-
.action(() => {
|
|
647
|
-
process.stderr.write(`Error: Command 'thread running' has been removed.
|
|
648
|
-
Use 'thread list --status running' instead.
|
|
649
|
-
|
|
650
|
-
For more information, see: uwf help thread list
|
|
651
|
-
`);
|
|
652
|
-
process.exit(1);
|
|
653
|
-
});
|
|
1190
|
+
// ── prompt group ─────────────────────────────────────────────────────────────
|
|
654
1191
|
|
|
655
|
-
const
|
|
656
|
-
prompt.addHelpCommand(false);
|
|
1192
|
+
const promptGroup = cli.command("prompt");
|
|
657
1193
|
|
|
658
|
-
|
|
1194
|
+
promptGroup
|
|
659
1195
|
.command("usage")
|
|
660
|
-
.
|
|
661
|
-
.action(() => {
|
|
1196
|
+
.returns(unknownSchema, "")
|
|
1197
|
+
.action(async () => {
|
|
662
1198
|
console.log(cmdPromptUsage());
|
|
1199
|
+
return undefined;
|
|
663
1200
|
});
|
|
664
1201
|
|
|
665
|
-
|
|
1202
|
+
promptGroup
|
|
666
1203
|
.command("bootstrap")
|
|
667
|
-
.
|
|
668
|
-
.action(() => {
|
|
1204
|
+
.returns(unknownSchema, "")
|
|
1205
|
+
.action(async () => {
|
|
669
1206
|
console.log(cmdPromptBootstrap());
|
|
1207
|
+
return undefined;
|
|
670
1208
|
});
|
|
671
1209
|
|
|
672
|
-
|
|
1210
|
+
promptGroup
|
|
673
1211
|
.command("workflow-authoring")
|
|
674
|
-
.
|
|
675
|
-
.action(() => {
|
|
1212
|
+
.returns(unknownSchema, "")
|
|
1213
|
+
.action(async () => {
|
|
676
1214
|
console.log(cmdPromptWorkflowAuthoring());
|
|
1215
|
+
return undefined;
|
|
677
1216
|
});
|
|
678
1217
|
|
|
679
|
-
|
|
1218
|
+
promptGroup
|
|
680
1219
|
.command("adapter-developing")
|
|
681
|
-
.
|
|
682
|
-
.action(() => {
|
|
1220
|
+
.returns(unknownSchema, "")
|
|
1221
|
+
.action(async () => {
|
|
683
1222
|
console.log(cmdPromptAdapterDeveloping());
|
|
1223
|
+
return undefined;
|
|
684
1224
|
});
|
|
685
1225
|
|
|
686
|
-
|
|
1226
|
+
promptGroup
|
|
687
1227
|
.command("list")
|
|
688
|
-
.
|
|
689
|
-
.action(() => {
|
|
1228
|
+
.returns(unknownSchema, "")
|
|
1229
|
+
.action(async () => {
|
|
690
1230
|
console.log(cmdPromptList().join("\n"));
|
|
1231
|
+
return undefined;
|
|
691
1232
|
});
|
|
692
1233
|
|
|
693
|
-
|
|
1234
|
+
// ── setup (top-level) ────────────────────────────────────────────────────────
|
|
1235
|
+
|
|
1236
|
+
cli
|
|
694
1237
|
.command("setup")
|
|
695
|
-
.
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
)
|
|
699
|
-
.option("--agent <name>", "Default agent adapter (e.g. hermes → uwf-hermes)")
|
|
700
|
-
.action((opts: { agent?: string }) => {
|
|
1238
|
+
.flag("agent", { type: "string" })
|
|
1239
|
+
.returns(unknownSchema, "")
|
|
1240
|
+
.action(async (_args, flags) => {
|
|
701
1241
|
const storageRoot = resolveStorageRoot();
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
1242
|
+
const agent = flags.agent as string | undefined;
|
|
1243
|
+
await runAction(async () => {
|
|
1244
|
+
if (agent !== undefined && agent !== "") {
|
|
1245
|
+
const result = await cmdSetup({ agent, storageRoot });
|
|
705
1246
|
writeRawOutput(result);
|
|
706
1247
|
} else {
|
|
707
1248
|
await cmdSetupInteractive(storageRoot);
|
|
708
1249
|
}
|
|
709
1250
|
});
|
|
1251
|
+
return undefined;
|
|
710
1252
|
});
|
|
711
1253
|
|
|
712
|
-
|
|
1254
|
+
// ── log group ────────────────────────────────────────────────────────────────
|
|
1255
|
+
|
|
1256
|
+
const log = cli.command("log");
|
|
713
1257
|
|
|
714
1258
|
log
|
|
715
1259
|
.command("list")
|
|
716
|
-
.
|
|
717
|
-
.action(() => {
|
|
1260
|
+
.returns(unknownSchema, "")
|
|
1261
|
+
.action(async () => {
|
|
718
1262
|
const storageRoot = resolveStorageRoot();
|
|
719
|
-
runAction(async () => {
|
|
1263
|
+
await runAction(async () => {
|
|
720
1264
|
const result = await cmdLogList(storageRoot);
|
|
721
1265
|
writeRawOutput(result, "log list");
|
|
722
1266
|
});
|
|
1267
|
+
return undefined;
|
|
723
1268
|
});
|
|
724
1269
|
|
|
725
1270
|
log
|
|
726
1271
|
.command("show")
|
|
727
|
-
.
|
|
728
|
-
.
|
|
729
|
-
.
|
|
730
|
-
.
|
|
731
|
-
.action(
|
|
732
|
-
(
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
runAction(async () => {
|
|
739
|
-
const result = await cmdLogShow(storageRoot, {
|
|
740
|
-
thread: opts.thread ?? null,
|
|
741
|
-
process: opts.process ?? null,
|
|
742
|
-
date: opts.date ?? null,
|
|
743
|
-
});
|
|
744
|
-
writeRawOutput(result, "log show");
|
|
1272
|
+
.flag("thread", { type: "string" })
|
|
1273
|
+
.flag("process", { type: "string" })
|
|
1274
|
+
.flag("date", { type: "string" })
|
|
1275
|
+
.returns(unknownSchema, "")
|
|
1276
|
+
.action(async (_args, flags) => {
|
|
1277
|
+
const storageRoot = resolveStorageRoot();
|
|
1278
|
+
await runAction(async () => {
|
|
1279
|
+
const result = await cmdLogShow(storageRoot, {
|
|
1280
|
+
thread: (flags.thread as string | undefined) ?? null,
|
|
1281
|
+
process: (flags.process as string | undefined) ?? null,
|
|
1282
|
+
date: (flags.date as string | undefined) ?? null,
|
|
745
1283
|
});
|
|
746
|
-
|
|
747
|
-
|
|
1284
|
+
writeRawOutput(result, "log show");
|
|
1285
|
+
});
|
|
1286
|
+
return undefined;
|
|
1287
|
+
});
|
|
748
1288
|
|
|
749
1289
|
log
|
|
750
1290
|
.command("clean")
|
|
751
|
-
.
|
|
752
|
-
.
|
|
753
|
-
.action((
|
|
1291
|
+
.flag("before", { type: "string" })
|
|
1292
|
+
.returns(unknownSchema, "")
|
|
1293
|
+
.action(async (_args, flags) => {
|
|
1294
|
+
const before = flags.before as string | undefined;
|
|
1295
|
+
if (before === undefined) {
|
|
1296
|
+
process.stderr.write("Error: missing required option: --before <date>\n");
|
|
1297
|
+
process.exit(1);
|
|
1298
|
+
}
|
|
754
1299
|
const storageRoot = resolveStorageRoot();
|
|
755
|
-
runAction(async () => {
|
|
756
|
-
const result = await cmdLogClean(storageRoot,
|
|
1300
|
+
await runAction(async () => {
|
|
1301
|
+
const result = await cmdLogClean(storageRoot, before);
|
|
757
1302
|
writeRawOutput(result);
|
|
758
1303
|
});
|
|
1304
|
+
return undefined;
|
|
759
1305
|
});
|
|
760
1306
|
|
|
761
|
-
|
|
1307
|
+
// ── config group ─────────────────────────────────────────────────────────────
|
|
1308
|
+
|
|
1309
|
+
const config = cli.command("config");
|
|
762
1310
|
|
|
763
1311
|
config
|
|
764
1312
|
.command("list")
|
|
765
|
-
.
|
|
766
|
-
.action(() => {
|
|
1313
|
+
.returns(unknownSchema, "")
|
|
1314
|
+
.action(async () => {
|
|
767
1315
|
const storageRoot = resolveStorageRoot();
|
|
768
|
-
runAction(async () => {
|
|
1316
|
+
await runAction(async () => {
|
|
769
1317
|
const result = await cmdConfigList(storageRoot);
|
|
770
1318
|
writeRawOutput(result, "config list");
|
|
771
1319
|
});
|
|
1320
|
+
return undefined;
|
|
772
1321
|
});
|
|
773
1322
|
|
|
774
1323
|
config
|
|
775
1324
|
.command("get")
|
|
776
|
-
.
|
|
777
|
-
.
|
|
778
|
-
"
|
|
779
|
-
"Dot-notation path to config value (e.g., defaultAgent, providers.dashscope.baseUrl)",
|
|
780
|
-
)
|
|
781
|
-
.action((key: string) => {
|
|
1325
|
+
.returns(unknownSchema, "")
|
|
1326
|
+
.action(async (_args, flags) => {
|
|
1327
|
+
const key = requirePositional(flags, 0, "key");
|
|
782
1328
|
const storageRoot = resolveStorageRoot();
|
|
783
|
-
runAction(async () => {
|
|
1329
|
+
await runAction(async () => {
|
|
784
1330
|
const result = await cmdConfigGet(storageRoot, key);
|
|
785
1331
|
writeRawOutput({ value: result }, "config get");
|
|
786
1332
|
});
|
|
1333
|
+
return undefined;
|
|
787
1334
|
});
|
|
788
1335
|
|
|
789
1336
|
config
|
|
790
1337
|
.command("set")
|
|
791
|
-
.
|
|
792
|
-
.
|
|
793
|
-
|
|
794
|
-
|
|
1338
|
+
.returns(unknownSchema, "")
|
|
1339
|
+
.action(async (_args, flags) => {
|
|
1340
|
+
const key = requirePositional(flags, 0, "key");
|
|
1341
|
+
const value = requirePositional(flags, 1, "value");
|
|
795
1342
|
const storageRoot = resolveStorageRoot();
|
|
796
|
-
runAction(async () => {
|
|
1343
|
+
await runAction(async () => {
|
|
797
1344
|
const result = await cmdConfigSet(storageRoot, key, value);
|
|
798
1345
|
writeRawOutput(result, "config set");
|
|
799
1346
|
});
|
|
1347
|
+
return undefined;
|
|
800
1348
|
});
|
|
801
1349
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1350
|
+
// --- Main execution: early intercepts + cli.run() ---
|
|
1351
|
+
|
|
1352
|
+
const rawArgv = process.argv.slice(2);
|
|
1353
|
+
|
|
1354
|
+
// 1. --version / -V (cli-kit doesn't handle these)
|
|
1355
|
+
const firstToken = rawArgv[0];
|
|
1356
|
+
if (firstToken === "--version" || firstToken === "-V") {
|
|
1357
|
+
process.stdout.write(`${VERSION}\n`);
|
|
1358
|
+
process.exit(0);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// 2. Strip --format (cli-kit has no global --format; parse into module-level var)
|
|
1362
|
+
const argvNoFormat = stripFormatFlag(rawArgv);
|
|
1363
|
+
|
|
1364
|
+
// 3. --help / -h / no args (cli-kit has no per-command --help)
|
|
1365
|
+
if (argvNoFormat.length === 0 || argvNoFormat.includes("--help") || argvNoFormat.includes("-h")) {
|
|
1366
|
+
printHelp(argvNoFormat);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// 4. Deprecated commands (intercept before cli-kit parsing)
|
|
1370
|
+
handleDeprecated(argvNoFormat);
|
|
1371
|
+
|
|
1372
|
+
// 5. Strip --count / -c (cli-kit rejects values starting with `-`)
|
|
1373
|
+
const argvNoCount = stripCountFlag(argvNoFormat);
|
|
1374
|
+
|
|
1375
|
+
// 6. Run cli-kit
|
|
1376
|
+
const exitCode = await cli.run({ argv: argvNoCount });
|
|
1377
|
+
if (exitCode !== 0) {
|
|
1378
|
+
process.exit(exitCode);
|
|
1379
|
+
}
|