@actiondock/cli 2.9.1 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +3 -3
  2. package/bin/ad.js +225 -5
  3. package/dist/commands/action/create.d.ts +1 -1
  4. package/dist/commands/action/create.js +6 -14
  5. package/dist/commands/add.js +1 -1
  6. package/dist/commands/config/delete.js +3 -1
  7. package/dist/commands/config/env.js +2 -1
  8. package/dist/commands/config/get.js +3 -1
  9. package/dist/commands/config/list.js +6 -5
  10. package/dist/commands/config/schema.js +16 -10
  11. package/dist/commands/config/set.js +3 -1
  12. package/dist/commands/describe.js +6 -4
  13. package/dist/commands/export.js +34 -16
  14. package/dist/commands/index.d.ts +37 -24
  15. package/dist/commands/index.js +346 -48
  16. package/dist/commands/info.js +34 -9
  17. package/dist/commands/list.js +13 -2
  18. package/dist/commands/mcp.js +0 -1
  19. package/dist/commands/playbook.js +67 -52
  20. package/dist/commands/profile.js +2 -1
  21. package/dist/commands/remove.js +1 -1
  22. package/dist/commands/run.d.ts +2 -1
  23. package/dist/commands/run.js +19 -56
  24. package/dist/commands/runs.d.ts +6 -1
  25. package/dist/commands/runs.js +274 -11
  26. package/dist/commands/serve.js +5 -2
  27. package/dist/commands/state.js +84 -15
  28. package/dist/errors.d.ts +5 -3
  29. package/dist/errors.js +23 -7
  30. package/dist/index.d.ts +10 -2
  31. package/dist/index.js +15 -12
  32. package/dist/prompt.d.ts +3 -0
  33. package/dist/prompt.js +6 -14
  34. package/dist/renderer.d.ts +8 -151
  35. package/dist/renderer.js +17 -375
  36. package/dist/renderers/action.d.ts +51 -0
  37. package/dist/renderers/action.js +112 -0
  38. package/dist/renderers/config.d.ts +31 -0
  39. package/dist/renderers/config.js +93 -0
  40. package/dist/renderers/playbook.d.ts +19 -0
  41. package/dist/renderers/playbook.js +42 -0
  42. package/dist/renderers/project.d.ts +45 -0
  43. package/dist/renderers/project.js +196 -0
  44. package/dist/renderers/runs.d.ts +15 -0
  45. package/dist/renderers/runs.js +47 -0
  46. package/dist/renderers/state.d.ts +4 -0
  47. package/dist/renderers/state.js +19 -0
  48. package/dist/services/config-merge.js +1 -2
  49. package/dist/services/index.d.ts +1 -0
  50. package/dist/services/index.js +1 -0
  51. package/dist/services/run-watch.d.ts +156 -0
  52. package/dist/services/run-watch.js +395 -0
  53. package/dist/types.d.ts +37 -0
  54. package/dist/utils/cert.js +1 -1
  55. package/dist/utils/index.d.ts +1 -1
  56. package/dist/utils/index.js +1 -1
  57. package/dist/utils/input.d.ts +2 -1
  58. package/dist/utils/input.js +2 -1
  59. package/dist/utils/target.d.ts +6 -2
  60. package/dist/utils/target.js +4 -4
  61. package/dist/utils/utils.d.ts +1 -1
  62. package/dist/utils/utils.js +4 -12
  63. package/dist/utils/warning.d.ts +4 -0
  64. package/dist/utils/warning.js +4 -0
  65. package/package.json +5 -5
  66. package/dist/commands/state-list.d.ts +0 -24
  67. package/dist/commands/state-list.js +0 -81
  68. package/dist/standalone/index.d.ts +0 -12
  69. package/dist/standalone/index.js +0 -13
  70. package/dist/utils/duration.d.ts +0 -1
  71. package/dist/utils/duration.js +0 -1
@@ -3,11 +3,11 @@ import { dirname, isAbsolute, relative, resolve } from "node:path";
3
3
  import { assertPathWithinRoot, loadActions, loadManifest, loadPlaybooks, saveManifest, filterWithFallbackInfo, } from "@actiondock/core/project";
4
4
  import { DefaultActionCatalog, PackageGraphBuilder, resolveAction, resolvePlaybook, } from "@actiondock/core/graph";
5
5
  import { fetchRemotePlaybooks, fetchRemotePlaybookShow, } from "@actiondock/core/profile";
6
- import { findProjectRoot, loadProjectConfig, } from "@actiondock/core";
7
- import { listLinkedPackages, resolvePackageRoot, } from "@actiondock/core/registry";
8
- import { ArgumentError, CliError, ExecutionError, NO_PROJECT_NO_LINKED_MESSAGE, notInProjectError, packageNotFoundError, wrapAsExecutionError, } from "../errors.js";
6
+ import { loadProjectConfig, } from "@actiondock/core";
7
+ import { listLinkedPackages, } from "@actiondock/core/registry";
8
+ import { ArgumentError, CliError, ExecutionError, NO_PROJECT_NO_LINKED_MESSAGE, wrapAsExecutionError, } from "../errors.js";
9
9
  import { renderPlaybookDetail, renderPlaybookList, renderResult, writeStdout, } from "../renderer.js";
10
- import { applyTargetOptions, getEffectiveOptions, remoteTargetSuffix, resolveFallbackStrategy, resolveIntent, resolveTargetFromOptions, } from "../utils/index.js";
10
+ import { applyTargetOptions, getEffectiveOptions, remoteTargetSuffix, requirePackageRoot, resolveFallbackStrategy, resolveIntent, resolveLocalPackageRoot, resolveTargetFromOptions, } from "../utils/index.js";
11
11
  /**
12
12
  * 注册 Playbook 命令集合(list, show, validate, create)。
13
13
  *
@@ -31,6 +31,9 @@ export function registerPlaybookCommands(program, context) {
31
31
  const options = getEffectiveOptions(rawOptions, cmd);
32
32
  const effectiveIntent = resolveIntent(options.intent, patterns);
33
33
  const { shouldFallback, isMachine } = resolveFallbackStrategy(options);
34
+ const hints = [
35
+ "Tip: Run 'ad playbook show <id>' to inspect procedure steps before execution.",
36
+ ];
34
37
  // 1. 远端服务分支
35
38
  const target = resolveTargetFromOptions(options, context);
36
39
  if (target.type === "remote") {
@@ -40,6 +43,10 @@ export function registerPlaybookCommands(program, context) {
40
43
  allowInsecureHttp: Boolean(options.allowInsecureHttp),
41
44
  insecure: target.insecure,
42
45
  });
46
+ if (isMachine) {
47
+ renderResult({ items: remotePbs, hints }, { json: options.json, context });
48
+ return;
49
+ }
43
50
  renderResult(remotePbs, {
44
51
  json: options.json,
45
52
  humanFormatter: () => renderPlaybookList(remotePbs, `Playbooks ${remoteTargetSuffix(target)}`, false, effectiveIntent),
@@ -48,16 +55,9 @@ export function registerPlaybookCommands(program, context) {
48
55
  return;
49
56
  }
50
57
  // 2. 本地工程模式
51
- let targetRoot = null;
52
- if (options.package) {
53
- targetRoot = resolvePackageRoot(options.package);
54
- if (!targetRoot) {
55
- throw packageNotFoundError(options.package);
56
- }
57
- }
58
- else {
59
- targetRoot = findProjectRoot();
60
- }
58
+ const targetRoot = options.package
59
+ ? requirePackageRoot(options.package).root
60
+ : resolveLocalPackageRoot();
61
61
  if (targetRoot) {
62
62
  const config = loadProjectConfig(targetRoot);
63
63
  const playbooks = loadPlaybooks(targetRoot, config.playbooksDir);
@@ -67,8 +67,16 @@ export function registerPlaybookCommands(program, context) {
67
67
  packageId: config.id,
68
68
  }));
69
69
  const filterRes = filterWithFallbackInfo(rawList, effectiveIntent, [(p) => p.id, (p) => p.description], shouldFallback);
70
- if (filterRes.isFallback && isMachine) {
71
- renderResult({ items: filterRes.items, isFallback: true, matchedCount: 0 }, { json: options.json, context });
70
+ if (isMachine) {
71
+ if (filterRes.isFallback) {
72
+ renderResult({ items: filterRes.items, isFallback: true, matchedCount: 0, hints }, { json: options.json, context });
73
+ return;
74
+ }
75
+ renderResult({
76
+ items: filterRes.items,
77
+ ...(filterRes.matchedCount !== undefined ? { matchedCount: filterRes.matchedCount } : {}),
78
+ hints,
79
+ }, { json: options.json, context });
72
80
  return;
73
81
  }
74
82
  renderResult(filterRes.items, {
@@ -81,6 +89,10 @@ export function registerPlaybookCommands(program, context) {
81
89
  // 3. 扫描所有已链接的外部包
82
90
  const linkedList = listLinkedPackages(context?.customHome);
83
91
  if (linkedList.length === 0) {
92
+ if (isMachine) {
93
+ renderResult({ packages: [], hints }, { json: options.json, context });
94
+ return;
95
+ }
84
96
  renderResult([], {
85
97
  json: options.json,
86
98
  humanFormatter: () => NO_PROJECT_NO_LINKED_MESSAGE,
@@ -136,8 +148,12 @@ export function registerPlaybookCommands(program, context) {
136
148
  isFallback = true;
137
149
  }
138
150
  }
139
- if (isFallback && isMachine) {
140
- renderResult({ packages: filteredPackages, isFallback: true, matchedCount: 0 }, { json: options.json, context });
151
+ if (isMachine) {
152
+ if (isFallback) {
153
+ renderResult({ packages: filteredPackages, isFallback: true, matchedCount: 0, hints }, { json: options.json, context });
154
+ return;
155
+ }
156
+ renderResult({ packages: filteredPackages, hints }, { json: options.json, context });
141
157
  return;
142
158
  }
143
159
  renderResult(filteredPackages, {
@@ -150,6 +166,7 @@ export function registerPlaybookCommands(program, context) {
150
166
  lines.push(` - ${pb.id.padEnd(26)} ${pb.description || ""}`);
151
167
  }
152
168
  }
169
+ lines.push("\nTip: Run 'ad playbook show <id>' to inspect procedure steps before execution.");
153
170
  return lines.join("\n");
154
171
  },
155
172
  context,
@@ -169,39 +186,46 @@ export function registerPlaybookCommands(program, context) {
169
186
  // 1. 远端服务分支
170
187
  const target = resolveTargetFromOptions(options, context);
171
188
  if (target.type === "remote") {
172
- const detail = await fetchRemotePlaybookShow(target.serverUrl, id, target.token, {
173
- allowInsecureHttp: Boolean(options.allowInsecureHttp),
174
- insecure: target.insecure,
175
- });
176
- renderResult(detail, {
177
- json: options.json,
178
- humanFormatter: () => renderPlaybookDetail(detail),
179
- context,
180
- });
181
- return;
189
+ try {
190
+ const detail = await fetchRemotePlaybookShow(target.serverUrl, id, target.token, {
191
+ allowInsecureHttp: Boolean(options.allowInsecureHttp),
192
+ insecure: target.insecure,
193
+ });
194
+ renderResult(detail, {
195
+ json: options.json,
196
+ humanFormatter: () => renderPlaybookDetail(detail),
197
+ context,
198
+ });
199
+ return;
200
+ }
201
+ catch (err) {
202
+ const hint = "Tip: Run 'ad playbook list' to discover available playbooks.";
203
+ throw new ArgumentError(`${err.message}\n${hint}`, err?.details, err?.code, hint);
204
+ }
182
205
  }
183
206
  // 2. 本地项目模式
184
207
  let showTarget = id;
185
208
  if (options.package && !id.includes("/")) {
186
- const pkgRoot = resolvePackageRoot(options.package);
187
- if (!pkgRoot) {
188
- throw packageNotFoundError(options.package);
189
- }
209
+ requirePackageRoot(options.package);
190
210
  showTarget = `${options.package}/${id}`;
191
211
  }
192
212
  let resolved;
193
213
  try {
194
214
  const graph = new PackageGraphBuilder({
195
- root: findProjectRoot() || undefined,
215
+ root: resolveLocalPackageRoot() || undefined,
196
216
  customHome: context?.customHome,
197
217
  allowDevLinks: true,
198
218
  }).buildSync();
199
219
  resolved = resolvePlaybook(showTarget, { graph });
200
220
  }
201
221
  catch (err) {
202
- throw new ArgumentError(err.message);
222
+ const hint = "Tip: Run 'ad playbook list' to discover available playbooks.";
223
+ throw new ArgumentError(`${err.message}\n${hint}`, err?.details, err?.code, hint);
203
224
  }
204
225
  const pb = resolved.playbook;
226
+ const hints = [
227
+ "Tip: Follow steps sequentially. Invoke constituent actions using 'ad run <action> [options] -- <assignments...>'.",
228
+ ];
205
229
  const detail = {
206
230
  id: pb.id,
207
231
  packageId: resolved.packageId,
@@ -209,6 +233,7 @@ export function registerPlaybookCommands(program, context) {
209
233
  actions: pb.actions,
210
234
  filePath: pb.filePath,
211
235
  content: pb.content,
236
+ hints,
212
237
  };
213
238
  renderResult(detail, {
214
239
  json: options.json,
@@ -224,16 +249,9 @@ export function registerPlaybookCommands(program, context) {
224
249
  .option("--json", "Output as JSON")
225
250
  .action(async (id, rawOptions, cmd) => {
226
251
  const options = getEffectiveOptions(rawOptions, cmd);
227
- let root = null;
228
- if (options.package) {
229
- root = resolvePackageRoot(options.package);
230
- if (!root) {
231
- throw packageNotFoundError(options.package);
232
- }
233
- }
234
- else {
235
- root = findProjectRoot();
236
- }
252
+ const root = options.package
253
+ ? requirePackageRoot(options.package).root
254
+ : resolveLocalPackageRoot();
237
255
  const targets = [];
238
256
  if (root) {
239
257
  const config = loadProjectConfig(root);
@@ -253,7 +271,7 @@ export function registerPlaybookCommands(program, context) {
253
271
  let resolved;
254
272
  try {
255
273
  const graph = new PackageGraphBuilder({
256
- root: findProjectRoot() || undefined,
274
+ root: resolveLocalPackageRoot() || undefined,
257
275
  customHome: context?.customHome,
258
276
  allowDevLinks: true,
259
277
  }).buildSync();
@@ -292,7 +310,7 @@ export function registerPlaybookCommands(program, context) {
292
310
  }
293
311
  const results = [];
294
312
  const graph = new PackageGraphBuilder({
295
- root: findProjectRoot() || undefined,
313
+ root: resolveLocalPackageRoot() || undefined,
296
314
  customHome: context?.customHome,
297
315
  allowDevLinks: true,
298
316
  }).buildSync();
@@ -317,14 +335,14 @@ export function registerPlaybookCommands(program, context) {
317
335
  resolveAction(actRef, { graph, catalog, caller: target.packageId });
318
336
  }
319
337
  catch (e) {
320
- errors.push(`Referenced cross-package action '${actRef}' not resolvable: ${e.message}`);
338
+ errors.push(`Referenced cross-package action '${actRef}' not resolvable: ${e.message}. Hint: Action '${actRef}' not found. Run 'ad action create ${actRef}' to create local action, or 'ad add <pkg>' to install external dependency.`);
321
339
  }
322
340
  }
323
341
  else {
324
342
  const foundInActions = actions.has(actRef);
325
343
  const foundInManifest = Boolean(manifest?.actions?.[actRef]);
326
344
  if (!foundInActions && !foundInManifest) {
327
- errors.push(`Referenced action '${actRef}' not found in project actions`);
345
+ errors.push(`Referenced action '${actRef}' not found in project actions. Hint: Action '${actRef}' not found. Run 'ad action create ${actRef}' to create local action, or 'ad add <pkg>' to install external dependency.`);
328
346
  }
329
347
  }
330
348
  }
@@ -374,10 +392,7 @@ export function registerPlaybookCommands(program, context) {
374
392
  });
375
393
  }
376
394
  export function handlePlaybookCreate(id, options, context) {
377
- const root = findProjectRoot();
378
- if (!root) {
379
- throw notInProjectError();
380
- }
395
+ const { root } = requirePackageRoot(undefined);
381
396
  try {
382
397
  const config = loadProjectConfig(root);
383
398
  const pbDir = resolve(root, config.playbooksDir || "playbooks");
@@ -1,4 +1,5 @@
1
- import { addProfile, checkRemoteHealth, getProfile, listProfiles, loadProfiles, removeProfile, resolveProfileToken, resolveTarget, toSnakeUpperCase, updateProfile, useProfile, } from "@actiondock/core/profile";
1
+ import { addProfile, checkRemoteHealth, getProfile, listProfiles, loadProfiles, removeProfile, resolveProfileToken, resolveTarget, updateProfile, useProfile, } from "@actiondock/core/profile";
2
+ import { toSnakeUpperCase } from "@actiondock/core";
2
3
  import { filterWithFallbackInfo, maskSecretValue, } from "@actiondock/core/project";
3
4
  import { ArgumentError, ExecutionError, wrapAsExecutionError, } from "../errors.js";
4
5
  import { renderResult, writeStderr, writeStdout } from "../renderer.js";
@@ -79,7 +79,7 @@ export function registerRemoveCommand(program, context) {
79
79
  }
80
80
  // 调用包管理器执行卸载(说明符白名单校验,消除 win32 shell 拼接注入面)
81
81
  assertSafePackageSpec(npmPackageName);
82
- const installCmd = getInstallCommand(root);
82
+ const installCmd = await getInstallCommand(root);
83
83
  const pm = installCmd[0];
84
84
  const args = pm === "bun" ? ["remove", npmPackageName] : ["uninstall", npmPackageName, "--ignore-scripts"];
85
85
  const uninstallProc = await spawnAsync(pm, args, {
@@ -6,7 +6,8 @@ import type { CliContext } from "../types.js";
6
6
  * 以原始纯文本形式渲染 Action 执行终态结果(默认纯文本模式)。
7
7
  *
8
8
  * 设计契约:
9
- * 1. stdout: 仅承载业务有效载荷(payload)。保持原生排版、未转义多行与真实换行,供用户阅读或下游管道直接消费。
9
+ * - 通用纯文本透传:标量直接输出,结构化对象按标准规范呈现,杜绝私有业务字段嗅探。
10
+ * - 标准输出仅承载业务有效载荷,保持原生排版与真实换行,供用户调阅或下游管道消费。
10
11
  */
11
12
  export declare function renderRawExecutionResult(targetRef: string, result: ExecutionResult, context?: CliContext): void;
12
13
  /**
@@ -1,5 +1,6 @@
1
1
  import { validateActionInputValue, mapInputValidationFailure, } from "@actiondock/core/project";
2
2
  import { resolveTarget, } from "@actiondock/core/profile";
3
+ import { resolveExecutionHint } from "@actiondock/core";
3
4
  import { ArgumentError, ExecutionError, SigintError, packageNotFoundError } from "../errors.js";
4
5
  import { writeStderr, writeStdout } from "../renderer.js";
5
6
  import { applyTargetOptions, getEffectiveOptions, resolveActionInput, resolveLocalPackageRoot, resolveTimeoutMs, withService, } from "../utils/index.js";
@@ -7,44 +8,18 @@ import { applyTargetOptions, getEffectiveOptions, resolveActionInput, resolveLoc
7
8
  * 以原始纯文本形式渲染 Action 执行终态结果(默认纯文本模式)。
8
9
  *
9
10
  * 设计契约:
10
- * 1. stdout: 仅承载业务有效载荷(payload)。保持原生排版、未转义多行与真实换行,供用户阅读或下游管道直接消费。
11
+ * - 通用纯文本透传:标量直接输出,结构化对象按标准规范呈现,杜绝私有业务字段嗅探。
12
+ * - 标准输出仅承载业务有效载荷,保持原生排版与真实换行,供用户调阅或下游管道消费。
11
13
  */
12
14
  export function renderRawExecutionResult(targetRef, result, context) {
13
15
  if (result.ok) {
14
16
  const data = result.data;
15
17
  let rawText;
16
- let metaInfo;
17
18
  if (typeof data === "string") {
18
19
  rawText = data;
19
20
  }
20
21
  else if (data !== null && typeof data === "object") {
21
- if ("content" in data && data.content !== undefined) {
22
- rawText =
23
- typeof data.content === "object" && data.content !== null
24
- ? JSON.stringify(data.content, null, 2)
25
- : String(data.content);
26
- const { content, ...rest } = data;
27
- if (Object.keys(rest).length > 0) {
28
- metaInfo = rest;
29
- }
30
- }
31
- else if ("text" in data && typeof data.text === "string") {
32
- rawText = data.text;
33
- const { text, ...rest } = data;
34
- if (Object.keys(rest).length > 0) {
35
- metaInfo = rest;
36
- }
37
- }
38
- else if ("message" in data && typeof data.message === "string") {
39
- rawText = data.message;
40
- const { message, ...rest } = data;
41
- if (Object.keys(rest).length > 0) {
42
- metaInfo = rest;
43
- }
44
- }
45
- else {
46
- rawText = JSON.stringify(data, null, 2);
47
- }
22
+ rawText = JSON.stringify(data, null, 2);
48
23
  }
49
24
  else if (data !== undefined) {
50
25
  rawText = String(data);
@@ -52,32 +27,6 @@ export function renderRawExecutionResult(targetRef, result, context) {
52
27
  else {
53
28
  rawText = "";
54
29
  }
55
- if (metaInfo) {
56
- const parts = [];
57
- const title = metaInfo.path ? String(metaInfo.path) : targetRef;
58
- parts.push(title);
59
- if (metaInfo.startLine !== undefined && metaInfo.endLine !== undefined) {
60
- parts.push(`lines ${metaInfo.startLine}-${metaInfo.endLine}`);
61
- }
62
- else if (metaInfo.line !== undefined) {
63
- parts.push(`line ${metaInfo.line}`);
64
- }
65
- if (metaInfo.hasMore !== undefined) {
66
- parts.push(`hasMore: ${metaInfo.hasMore}`);
67
- }
68
- if (metaInfo.truncated) {
69
- parts.push("truncated: true");
70
- }
71
- const handled = new Set(["path", "startLine", "endLine", "line", "hasMore", "truncated"]);
72
- for (const [k, v] of Object.entries(metaInfo)) {
73
- if (!handled.has(k) && v !== undefined) {
74
- parts.push(`${k}: ${typeof v === "object" ? JSON.stringify(v) : v}`);
75
- }
76
- }
77
- if (parts.length > 0) {
78
- writeStderr(`[${parts.join(" | ")}]`, context);
79
- }
80
- }
81
30
  writeStdout(rawText, context);
82
31
  }
83
32
  else {
@@ -87,6 +36,10 @@ export function renderRawExecutionResult(targetRef, result, context) {
87
36
  ? result.error.details
88
37
  : JSON.stringify(result.error.details, null, 2), context);
89
38
  }
39
+ const hint = resolveExecutionHint(targetRef, result.error);
40
+ if (hint) {
41
+ writeStderr(hint, context);
42
+ }
90
43
  if (context) {
91
44
  context.exitCode = 1;
92
45
  }
@@ -189,7 +142,14 @@ export async function executeAction(id, options, context, flatArgs, control) {
189
142
  throw new SigintError();
190
143
  }
191
144
  if (isMachine) {
192
- writeStdout(JSON.stringify(result, null, 2), context);
145
+ if (!result.ok) {
146
+ const hint = resolveExecutionHint(targetRef, result.error);
147
+ const machineOutput = hint !== undefined ? { ...result, hint } : result;
148
+ writeStdout(JSON.stringify(machineOutput, null, 2), context);
149
+ }
150
+ else {
151
+ writeStdout(JSON.stringify(result, null, 2), context);
152
+ }
193
153
  }
194
154
  else {
195
155
  renderRawExecutionResult(targetRef, result, context);
@@ -260,6 +220,9 @@ export function attachRunCommand(parent, context) {
260
220
  .option("-i, --input <json>", "Action input as inline JSON")
261
221
  .option("-f, --input-file <path>", "Action input from JSON file, or '-' for stdin")
262
222
  .option("-c, --config <key=value...>", "Temporary config override (repeatable)");
223
+ cmd.unknownOption = function (flag) {
224
+ this.error(`unknown option '${flag}'\nHint: Separate action inputs from CLI options using '--', e.g.: ad run <id> [options] -- <param>=<val> or <param>:=<json>.`, { code: "commander.unknownOption" });
225
+ };
263
226
  return applyTargetOptions(cmd)
264
227
  .option("--timeout <duration>", "Execution timeout (e.g. 30s, 5m, 500ms)")
265
228
  .option("--request-id <id>", "Idempotency request ID for deduplication")
@@ -1,7 +1,12 @@
1
1
  import { Command } from "commander";
2
2
  import type { CliContext } from "../types.js";
3
3
  /**
4
- * 注册 runs 动作执行历史管理命令(list、show、clear、cancel)。
4
+ * 归一化 requestId 选项值为去重后的非空原样字符串数组。
5
+ * 将 requestId 作为不作解释的原样字符串,不拆分逗号、不剔除首尾空白,只做非空有效字符串检查与去重。
6
+ */
7
+ export declare function normalizeRequestIds(raw: unknown): string[];
8
+ /**
9
+ * 注册 runs 动作执行历史管理命令(list、show、watch、clear、cancel)。
5
10
  *
6
11
  * @param program Commander 实例
7
12
  * @param context 命令行上下文