@actiondock/cli 2.10.0 → 2.12.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 (64) hide show
  1. package/README.md +10 -5
  2. package/bin/ad.js +225 -5
  3. package/dist/commands/action/create.d.ts +1 -1
  4. package/dist/commands/action/create.js +7 -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/set.js +3 -1
  11. package/dist/commands/describe.js +2 -3
  12. package/dist/commands/export.js +34 -16
  13. package/dist/commands/index.d.ts +37 -24
  14. package/dist/commands/index.js +326 -48
  15. package/dist/commands/mcp.js +0 -1
  16. package/dist/commands/playbook.js +15 -35
  17. package/dist/commands/profile.js +2 -1
  18. package/dist/commands/remove.js +1 -1
  19. package/dist/commands/run.d.ts +7 -2
  20. package/dist/commands/run.js +47 -59
  21. package/dist/commands/runs.d.ts +6 -1
  22. package/dist/commands/runs.js +274 -11
  23. package/dist/commands/serve.js +5 -2
  24. package/dist/commands/state.js +84 -15
  25. package/dist/index.d.ts +10 -2
  26. package/dist/index.js +15 -12
  27. package/dist/prompt.d.ts +3 -0
  28. package/dist/prompt.js +6 -14
  29. package/dist/renderer.d.ts +7 -137
  30. package/dist/renderer.js +6 -438
  31. package/dist/renderers/action.d.ts +78 -0
  32. package/dist/renderers/action.js +187 -0
  33. package/dist/renderers/config.d.ts +31 -0
  34. package/dist/renderers/config.js +93 -0
  35. package/dist/renderers/playbook.d.ts +19 -0
  36. package/dist/renderers/playbook.js +42 -0
  37. package/dist/renderers/project.d.ts +45 -0
  38. package/dist/renderers/project.js +196 -0
  39. package/dist/renderers/runs.d.ts +15 -0
  40. package/dist/renderers/runs.js +47 -0
  41. package/dist/renderers/state.d.ts +4 -0
  42. package/dist/renderers/state.js +19 -0
  43. package/dist/services/config-merge.js +1 -2
  44. package/dist/services/index.d.ts +1 -0
  45. package/dist/services/index.js +1 -0
  46. package/dist/services/run-watch.d.ts +156 -0
  47. package/dist/services/run-watch.js +395 -0
  48. package/dist/utils/cert.js +1 -1
  49. package/dist/utils/index.d.ts +1 -1
  50. package/dist/utils/index.js +1 -1
  51. package/dist/utils/input.d.ts +2 -1
  52. package/dist/utils/input.js +2 -1
  53. package/dist/utils/target.d.ts +6 -2
  54. package/dist/utils/target.js +4 -4
  55. package/dist/utils/utils.js +3 -11
  56. package/dist/utils/warning.d.ts +4 -0
  57. package/dist/utils/warning.js +4 -0
  58. package/package.json +5 -5
  59. package/dist/commands/state-list.d.ts +0 -24
  60. package/dist/commands/state-list.js +0 -81
  61. package/dist/standalone/index.d.ts +0 -12
  62. package/dist/standalone/index.js +0 -13
  63. package/dist/utils/duration.d.ts +0 -1
  64. package/dist/utils/duration.js +0 -1
package/README.md CHANGED
@@ -152,8 +152,13 @@ $data | ConvertTo-Json -Depth 100 | ad run complex-action --input-file -
152
152
 
153
153
  ### Action 输出模式与机器模式
154
154
 
155
- - **默认原始纯文本输出**:`ad run` 默认采用面向终端人类阅读与 LLM Agent 上下文消费的原始输出模式。直接将执行结果正文内容(如文件 `content`、`text`、`message` 或标量字符串)输出至 stdout(保留真实换行且无 JSON 转义),相关元数据(如文件路径、行号范围、截断标记)独立输出至 stderr,符合 Unix 管道安全原则。业务执行失败时在 stderr 输出错误详情并以退出码 1 退出。
156
- - **机器 JSON 格式**(`--json`):当需要以程序化方式消费、获取完整结构化数据或被外部系统集成时,传入 `--json`。面向智能体调用推荐使用该模式;此时输出标准 JSON 结果(包含 `ok`、`runId`、`data` 或 `error`);若参数解析出错输出标准错误信封并以退出码 2 退出。
155
+ - **默认纯文本输出**:`ad run` 默认采用纯文本模式。标量直接输出;结构化对象完整输出为标准 JSON 格式到 stdout;不进行私有业务字段自动嗅探。
156
+ - **显式正文输出与默认注解**:
157
+ - 显式指定正文字段:通过 `ad run <id> --text-field <field> -- ...` 提取结果中特定顶层自有字符串字段输出至 stdout(保留真实换行且无 JSON 转义),其余字段以 JSON 对象形式输出至 stderr(元数据为空时不输出)。
158
+ - 声明式默认正文:Action 清单中声明 `annotations["actiondock.cli"] = { "textField": "<field>" }` 时,未指定 `--text-field` 时自动按声明提取正文与元数据;显式 `--text-field` 优先于默认注解。
159
+ - 严格校验:正文字段缺失、非字符串或返回数据非对象时,明确输出错误并以退出码 1 退出,不静默回退,不改写运行记录。
160
+ - 参数互斥:`--text-field` 与 `--json`、`--async` 严格互斥,在执行前校验并以退出码 2 退出。
161
+ - **机器模式**(`--json`):当需要以程序化方式消费、获取完整结构化数据或被外部系统集成时,传入 `--json`。此时始终输出完整执行信封(包含 `ok`、`runId`、`data` 或 `error`),忽略默认正文注解;若参数解析出错输出标准错误信封并以退出码 2 退出。
157
162
 
158
163
  ---
159
164
 
@@ -166,15 +171,15 @@ $data | ConvertTo-Json -Depth 100 | ad run complex-action --input-file -
166
171
  | `ad remove <package>` | 卸载并更新锁定依赖,提供原子回滚保护 |
167
172
  | `ad info [patterns...]` | 检索包元数据与能力清单,支持模式匹配与树形展示 |
168
173
  | `ad list [patterns...]` | 列出包内所有已注册的 Action |
169
- | `ad describe <id>` | 编码顾问:查看 Action 的详情、模式字段明细、Flat 编码指引与建议赋值(别名 `ad show`) |
170
- | `ad run <id>` | 本地或远程执行指定 Action(规范语法 `ad run <id> [options] -- <assignments...>`,支持 `--json` 输出标准信封) |
174
+ | `ad describe <id>` | 编码顾问:查看 Action 的详情、模式字段明细、Flat 编码指引与建议赋值 |
175
+ | `ad run <id>` | 本地或远程执行指定 Action(规范语法 `ad run <id> [options] -- <assignments...>`,支持 `--text-field` 提取正文与 `--json` 输出标准信封) |
171
176
  | `ad validate [id]` | 校验 Action 规范与模式规范 |
172
177
  | `ad doctor` | 执行运行环境与项目结构健康诊断 |
173
178
  | `ad action create <id>` | 创建新 Action 源码 |
174
179
  | `ad playbook list` / `show` | 查看智能体操作规程 Playbook |
175
180
  | `ad config list` / `get` / `set` | 管理包运行时配置与环境变量绑定 |
176
181
  | `ad state list` / `get` / `set` / `delete` / `clear` | 查看与维护 SQLite 持久化状态 |
177
- | `ad runs list` / `show` / `clear` | 查询任务执行历史与追踪记录,或按时间与数量策略清理历史数据 |
182
+ | `ad runs list` / `show` / `watch` / `clear` | 查询任务执行历史、阻塞等待运行终态聚合退出,或按时间与数量策略清理历史数据;list 支持 `--request-id` 过滤,watch 支持按 `--request-id` 反查等待(后台派工场景主控无 runId 时使用) |
178
183
  | `ad test` | 执行快速单元测试 |
179
184
  | `ad build` | 构建 Node.js 目录交付产物(支持 `--vendor-deps` 与 `--archive`) |
180
185
  | `ad pack` | 打包为标准 npm tarball(`.tgz`),支持 `--dry-run` |
package/bin/ad.js CHANGED
@@ -1,8 +1,26 @@
1
1
  #!/usr/bin/env node
2
+ import { enableCompileCache } from "node:module";
3
+ try {
4
+ enableCompileCache?.();
5
+ } catch {}
6
+ try {
7
+ await import("@actiondock/core/warning");
8
+ } catch {
9
+ try {
10
+ const { resolve } = await import("node:path");
11
+ const { existsSync } = await import("node:fs");
12
+ const { pathToFileURL } = await import("node:url");
13
+ const coreWarningSrc = resolve(import.meta.dirname, "../../core/src/utils/warning.ts");
14
+ if (existsSync(coreWarningSrc)) {
15
+ await import(pathToFileURL(coreWarningSrc).href);
16
+ }
17
+ } catch {}
18
+ }
19
+
2
20
  import { spawn } from "node:child_process";
3
- import { existsSync } from "node:fs";
21
+ import { existsSync, readFileSync } from "node:fs";
4
22
  import { createRequire } from "node:module";
5
- import { resolve } from "node:path";
23
+ import { resolve, dirname, join } from "node:path";
6
24
  import { fileURLToPath, pathToFileURL } from "node:url";
7
25
 
8
26
  const isBun = typeof process.versions.bun !== "undefined";
@@ -10,11 +28,206 @@ const hasTsx =
10
28
  process.execArgv.some((arg, i) => arg === "--import" && process.execArgv[i + 1]?.includes("tsx")) ||
11
29
  process.execArgv.some((arg) => arg.includes("tsx"));
12
30
 
13
- if (!isBun && !hasTsx) {
31
+ const nodeMajor = parseInt(process.versions.node?.split(".")[0] || "0", 10);
32
+ const hasNativeTypeStripping =
33
+ nodeMajor >= 24 ||
34
+ Boolean(process.features?.typescript) ||
35
+ process.execArgv.includes("--experimental-strip-types") ||
36
+ process.execArgv.includes("--experimental-transform-types") ||
37
+ Boolean(process.env.NODE_OPTIONS?.includes("--experimental-strip-types")) ||
38
+ Boolean(process.env.NODE_OPTIONS?.includes("--experimental-transform-types"));
39
+
40
+ const ROUTINE_COMMANDS = new Set([
41
+ "list",
42
+ "info",
43
+ "describe",
44
+ "validate",
45
+ "config",
46
+ "doctor",
47
+ "state",
48
+ "runs",
49
+ "add",
50
+ "remove",
51
+ "init",
52
+ "new",
53
+ "link",
54
+ "unlink",
55
+ "pack",
56
+ "generate",
57
+ "profile",
58
+ "help",
59
+ ]);
60
+
61
+ function findNearestProjectRoot(startDir = process.cwd()) {
62
+ let current;
63
+ try {
64
+ current = resolve(startDir);
65
+ } catch {
66
+ return startDir;
67
+ }
68
+ while (true) {
69
+ if (existsSync(join(current, "actiondock.json"))) {
70
+ return current;
71
+ }
72
+ const parent = dirname(current);
73
+ if (parent === current) break;
74
+ current = parent;
75
+ }
76
+ return startDir;
77
+ }
78
+
79
+ /**
80
+ * 决定是否需要派生 tsx 加载器:
81
+ * - 纯 TypeScript 工程在 Node 24 原生环境下直接执行,绝不派生进程;
82
+ * - 常规运维与元数据命令(ad -v、ad info、ad list、ad config 等)绝不派生;
83
+ * - 仅当环境显式要求、或直接执行的 Action / 工程配置声明了 JSX/TSX 等非标准语法时,按需派生 tsx。
84
+ */
85
+ function checkNeedsTsx(rawArgv) {
86
+ if (isBun || hasTsx) {
87
+ return { needsTsx: false, projectRoot: process.cwd() };
88
+ }
89
+
90
+ const explicitTsx =
91
+ process.env.ACTIONDOCK_FORCE_TSX === "1" ||
92
+ process.env.ACTIONDOCK_FORCE_TSX === "true" ||
93
+ process.env.ACTIONDOCK_TSX === "1" ||
94
+ process.env.ACTIONDOCK_TSX === "true" ||
95
+ process.env.TSX === "1" ||
96
+ rawArgv.includes("--tsx") ||
97
+ rawArgv.includes("--force-tsx");
98
+
99
+ if (explicitTsx) {
100
+ return { needsTsx: true, projectRoot: process.cwd() };
101
+ }
102
+
103
+ if (!hasNativeTypeStripping) {
104
+ return { needsTsx: true, projectRoot: process.cwd() };
105
+ }
106
+
107
+ if (
108
+ rawArgv.length === 0 ||
109
+ rawArgv.includes("-v") ||
110
+ rawArgv.includes("--version") ||
111
+ rawArgv.includes("-V") ||
112
+ rawArgv.includes("-h") ||
113
+ rawArgv.includes("--help")
114
+ ) {
115
+ return { needsTsx: false, projectRoot: process.cwd() };
116
+ }
117
+
118
+ let mainCommand = null;
119
+ let actionTarget = null;
120
+ let targetDir = process.cwd();
121
+
122
+ for (let i = 0; i < rawArgv.length; i++) {
123
+ const token = rawArgv[i];
124
+ if (token === "--cwd" || token === "-C" || token === "--project" || token === "--dir") {
125
+ const next = rawArgv[i + 1];
126
+ if (next && !next.startsWith("-")) {
127
+ try {
128
+ targetDir = resolve(next);
129
+ } catch {}
130
+ }
131
+ i++;
132
+ continue;
133
+ }
134
+ if (token.startsWith("-")) {
135
+ continue;
136
+ }
137
+ if (!mainCommand) {
138
+ mainCommand = token;
139
+ continue;
140
+ }
141
+ if (!actionTarget) {
142
+ actionTarget = token;
143
+ break;
144
+ }
145
+ }
146
+
147
+ if (!mainCommand || ROUTINE_COMMANDS.has(mainCommand)) {
148
+ return { needsTsx: false, projectRoot: targetDir };
149
+ }
150
+
151
+ if (mainCommand === "action") {
152
+ if (!actionTarget || actionTarget === "create") {
153
+ return { needsTsx: false, projectRoot: targetDir };
154
+ }
155
+ } else if (mainCommand === "playbook") {
156
+ if (!actionTarget || actionTarget === "list" || actionTarget === "show" || actionTarget === "validate" || actionTarget === "create") {
157
+ return { needsTsx: false, projectRoot: targetDir };
158
+ }
159
+ }
160
+
161
+ if (actionTarget && (actionTarget.endsWith(".tsx") || actionTarget.endsWith(".jsx"))) {
162
+ return { needsTsx: true, projectRoot: targetDir };
163
+ }
164
+
165
+ const projectRoot = findNearestProjectRoot(targetDir);
166
+
167
+ const manifestPath = join(projectRoot, "actiondock.json");
168
+ if (existsSync(manifestPath)) {
169
+ try {
170
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
171
+ if (
172
+ manifest.jsx === true ||
173
+ manifest.tsx === true ||
174
+ manifest.transpile === true ||
175
+ manifest.runtime === "tsx" ||
176
+ manifest.runtime?.transpiler === "tsx" ||
177
+ Boolean(manifest.compilerOptions?.jsx)
178
+ ) {
179
+ return { needsTsx: true, projectRoot };
180
+ }
181
+
182
+ if (actionTarget && manifest.actions?.[actionTarget]?.entry) {
183
+ const entry = String(manifest.actions[actionTarget].entry);
184
+ if (entry.endsWith(".tsx") || entry.endsWith(".jsx")) {
185
+ return { needsTsx: true, projectRoot };
186
+ }
187
+ }
188
+
189
+ if (manifest.actions) {
190
+ for (const entry of Object.values(manifest.actions)) {
191
+ if (typeof entry?.entry === "string" && (entry.entry.endsWith(".tsx") || entry.entry.endsWith(".jsx"))) {
192
+ return { needsTsx: true, projectRoot };
193
+ }
194
+ }
195
+ }
196
+ } catch {}
197
+ }
198
+
199
+ const tsconfigPath = join(projectRoot, "tsconfig.json");
200
+ if (existsSync(tsconfigPath)) {
201
+ try {
202
+ const content = readFileSync(tsconfigPath, "utf-8");
203
+ if (/"jsx"\s*:/i.test(content)) {
204
+ return { needsTsx: true, projectRoot };
205
+ }
206
+ } catch {}
207
+ }
208
+
209
+ const pkgPath = join(projectRoot, "package.json");
210
+ if (existsSync(pkgPath)) {
211
+ try {
212
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
213
+ if (pkg.jsx) {
214
+ return { needsTsx: true, projectRoot };
215
+ }
216
+ } catch {}
217
+ }
218
+
219
+ return { needsTsx: false, projectRoot };
220
+ }
221
+
222
+ const rawArgv = process.argv.slice(2);
223
+ const { needsTsx, projectRoot } = checkNeedsTsx(rawArgv);
224
+
225
+ if (needsTsx) {
14
226
  const require = createRequire(import.meta.url);
15
227
  let tsxSpecifier = null;
228
+ const searchPaths = [import.meta.dirname, process.cwd(), projectRoot];
16
229
  try {
17
- tsxSpecifier = pathToFileURL(require.resolve("tsx", { paths: [import.meta.dirname, process.cwd()] })).href;
230
+ tsxSpecifier = pathToFileURL(require.resolve("tsx", { paths: searchPaths })).href;
18
231
  } catch {
19
232
  try {
20
233
  tsxSpecifier = pathToFileURL(require.resolve("tsx")).href;
@@ -24,9 +237,16 @@ if (!isBun && !hasTsx) {
24
237
  }
25
238
 
26
239
  if (tsxSpecifier) {
240
+ const extraFlags = [];
241
+ if (process.env.ACTIONDOCK_SILENCE_WARNINGS !== "0") {
242
+ extraFlags.push("--no-warnings=ExperimentalWarning");
243
+ }
244
+ if (nodeMajor >= 24) {
245
+ extraFlags.push("--no-strip-types");
246
+ }
27
247
  const child = spawn(
28
248
  process.execPath,
29
- ["--import", tsxSpecifier, fileURLToPath(import.meta.url), ...process.argv.slice(2)],
249
+ [...extraFlags, "--import", tsxSpecifier, fileURLToPath(import.meta.url), ...rawArgv],
30
250
  {
31
251
  stdio: "inherit",
32
252
  }
@@ -8,7 +8,7 @@ export declare function parseSchemaFields(rawFields?: string[] | string): {
8
8
  required: string[];
9
9
  } | null;
10
10
  /**
11
- * 注册 action 命令组(action create, action list, action describe, action run, action validate)。
11
+ * 注册 action 命令组(仅保留脚手架创建指令 action create)。
12
12
  *
13
13
  * @param program Commander 根程序对象
14
14
  * @param context 命令行上下文
@@ -4,10 +4,6 @@ import { assertPathWithinRoot, getPackageSlug, loadManifest, saveManifest, write
4
4
  import { findProjectRoot, loadProjectConfig, } from "@actiondock/core";
5
5
  import { ExecutionError, notInProjectError, wrapAsExecutionError } from "../../errors.js";
6
6
  import { writeStdout } from "../../renderer.js";
7
- import { attachDescribeCommand } from "../describe.js";
8
- import { attachListCommand } from "../list.js";
9
- import { attachRunCommand } from "../run.js";
10
- import { attachValidateCommand } from "../validate.js";
11
7
  /**
12
8
  * 解析用户通过命令行传入的字段定义字符串(如 name:string, count?:number)。
13
9
  */
@@ -63,7 +59,7 @@ export function parseSchemaFields(rawFields) {
63
59
  return { properties, required };
64
60
  }
65
61
  /**
66
- * 注册 action 命令组(action create, action list, action describe, action run, action validate)。
62
+ * 注册 action 命令组(仅保留脚手架创建指令 action create)。
67
63
  *
68
64
  * @param program Commander 根程序对象
69
65
  * @param context 命令行上下文
@@ -71,7 +67,7 @@ export function parseSchemaFields(rawFields) {
71
67
  export function registerActionCommands(program, context) {
72
68
  const actionCmd = program
73
69
  .command("action")
74
- .description("Manage Action definitions and lifecycle (create, list, describe, run, validate)");
70
+ .description("Manage Action definitions and scaffolding (create)");
75
71
  actionCmd
76
72
  .command("create <id>")
77
73
  .description("Scaffold a new Action definition file")
@@ -82,10 +78,6 @@ export function registerActionCommands(program, context) {
82
78
  .action(async (id, options) => {
83
79
  await handleActionCreate(id, options, context);
84
80
  });
85
- attachListCommand(actionCmd, context);
86
- attachDescribeCommand(actionCmd, context);
87
- attachRunCommand(actionCmd, context);
88
- attachValidateCommand(actionCmd, context);
89
81
  }
90
82
  export async function handleActionCreate(id, options, context) {
91
83
  const root = findProjectRoot();
@@ -204,11 +196,12 @@ ${returnBody}
204
196
  // 始终自动生成或更新类型声明文件,确保单一事实源即时生效
205
197
  writeActionTypes(root, manifest);
206
198
  writeStdout(`[OK] Created Action '${id}' at ${targetFullFile}`, context);
207
- writeStdout(`\n查阅参数契约:`, context);
199
+ writeStdout(`\nParameter contract:`, context);
208
200
  writeStdout(` ad describe ${id}`, context);
209
- writeStdout(`\n调用方式:`, context);
210
- writeStdout(` 根据 describe 输出的赋值模板传递参数:ad run ${id} --json -- ASSIGNMENT...`, context);
211
- writeStdout(` 复杂输入或大段文本:ad run ${id} --json --input-file input.json`, context);
201
+ writeStdout(`\nUsage:`, context);
202
+ writeStdout(` Pass parameters according to describe assignment template: ad run ${id} -- ASSIGNMENT...`, context);
203
+ writeStdout(` Complex input or large text: ad run ${id} --input-file input.json`, context);
204
+ writeStdout(` Append --json only when structured extraction is needed`, context);
212
205
  }
213
206
  catch (err) {
214
207
  throw wrapAsExecutionError(err);
@@ -44,7 +44,7 @@ export function registerAddCommand(program, context) {
44
44
  const tx = await beginTransaction(root, `ad add ${packageSpec}`);
45
45
  try {
46
46
  // 调用包管理器执行安装(默认禁用生命周期安装脚本)
47
- const installCmd = getInstallCommand(root);
47
+ const installCmd = await getInstallCommand(root);
48
48
  const pm = installCmd[0];
49
49
  const args = [];
50
50
  if (pm === "bun") {
@@ -45,6 +45,8 @@ export function registerConfigDeleteCommand(configCmd, context) {
45
45
  const projConfig = loadProjectConfig(root);
46
46
  await service.management?.config.delete(projConfig.id, key);
47
47
  writeStdout(`[OK] Configuration '${key}' deleted for package '${projConfig.id}'`, context);
48
- });
48
+ },
49
+ // 按实际查询范围打开存储:显式包寻址结果作为本地根目录传递
50
+ { localRoot: root || undefined });
49
51
  });
50
52
  }
@@ -1,4 +1,5 @@
1
- import { fetchRemoteConfigEnv, resolveEnvValue, } from "@actiondock/core/profile";
1
+ import { resolveEnvValue } from "@actiondock/core";
2
+ import { fetchRemoteConfigEnv } from "@actiondock/core/profile";
2
3
  import { isSecretConfigKey, } from "@actiondock/core/project";
3
4
  import { renderConfigEnv, renderResult } from "../../renderer.js";
4
5
  import { applyTargetOptions, getEffectiveOptions, requirePackageRoot, resolveTargetFromOptions } from "../../utils/index.js";
@@ -89,6 +89,8 @@ export function registerConfigGetCommand(configCmd, context) {
89
89
  humanFormatter: () => (displayValue !== undefined ? String(displayValue) : ""),
90
90
  context,
91
91
  });
92
- });
92
+ },
93
+ // 按实际查询范围打开存储:显式包寻址结果作为本地根目录传递
94
+ { localRoot: root || undefined });
93
95
  });
94
96
  }
@@ -1,11 +1,10 @@
1
1
  import { fetchRemoteConfig, } from "@actiondock/core/profile";
2
- import { findProjectRoot, loadProjectConfig, } from "@actiondock/core";
2
+ import { loadProjectConfig, } from "@actiondock/core";
3
3
  import { filterWithFallbackInfo, isSecretConfigKey, maskSecretValue, } from "@actiondock/core/project";
4
- import { resolvePackageRoot, } from "@actiondock/core/registry";
5
4
  import { packageNotFoundError } from "../../errors.js";
6
5
  import { renderConfigList, renderResult } from "../../renderer.js";
7
6
  import { buildMergedConfigEntries } from "../../services/config-merge.js";
8
- import { applyTargetOptions, getEffectiveOptions, remoteTargetLabel, resolveFallbackStrategy, resolveIntent, resolveTargetFromOptions, withService, } from "../../utils/index.js";
7
+ import { applyTargetOptions, getEffectiveOptions, remoteTargetLabel, resolveFallbackStrategy, resolveIntent, resolveLocalPackageRoot, resolveTargetFromOptions, withService, } from "../../utils/index.js";
9
8
  /**
10
9
  * 构造单条配置项的展示视图(含掩码决策,reveal 为假且为敏感键时打码)。
11
10
  * 掩码决策收敛于命令层,renderer 仅负责值的字符串格式化。
@@ -58,9 +57,9 @@ export function registerConfigListCommand(configCmd, context) {
58
57
  });
59
58
  return;
60
59
  }
61
- // 本地分支(通过 Service 门面统一访问)
60
+ // 本地分支(通过 Service 门面统一访问):显式包寻址结果作为本地根目录传递(仅 local 分支求值)
62
61
  await withService(options, context, async (service) => {
63
- const root = options.package ? resolvePackageRoot(options.package) : findProjectRoot();
62
+ const root = resolveLocalPackageRoot(options.package) || undefined;
64
63
  // 全局作用域分支:显式 --global 或无工程回退时仅列举全局配置
65
64
  if (options.global || !root) {
66
65
  if (!options.global && options.package) {
@@ -85,6 +84,8 @@ export function registerConfigListCommand(configCmd, context) {
85
84
  humanFormatter: () => renderConfigList(filterRes.items, `${projConfig.name} (${projConfig.id})`, filterRes.isFallback, effectiveIntent),
86
85
  context,
87
86
  });
87
+ }, {
88
+ localRoot: () => resolveLocalPackageRoot(options.package) || undefined,
88
89
  });
89
90
  });
90
91
  }
@@ -79,6 +79,8 @@ export function registerConfigSetCommand(configCmd, context) {
79
79
  }
80
80
  await service.management?.config.set(projConfig.id, key, parsedVal);
81
81
  writeStdout(`[OK] Configuration '${key}' updated for package '${projConfig.id}'`, context);
82
- });
82
+ },
83
+ // 按实际查询范围打开存储:显式包寻址结果作为本地根目录传递
84
+ { localRoot: root || undefined });
83
85
  });
84
86
  }
@@ -1,7 +1,7 @@
1
1
  import { ACTION_NOT_FOUND, PACKAGE_NOT_FOUND, NOT_FOUND, } from "@actiondock/core";
2
- import { buildActionDescribePayload, formatActionDetail, } from "@actiondock/core/project";
2
+ import { buildActionDescribePayload, } from "@actiondock/core/project";
3
3
  import { ArgumentError, ExecutionError, packageNotFoundError } from "../errors.js";
4
- import { renderResult } from "../renderer.js";
4
+ import { formatActionDetail, renderResult } from "../renderer.js";
5
5
  import { applyTargetOptions, getEffectiveOptions, resolveLocalPackageRoot, withService, } from "../utils/index.js";
6
6
  /**
7
7
  * 挂载 describe 子命令至指定 Commander 节点。
@@ -12,7 +12,6 @@ import { applyTargetOptions, getEffectiveOptions, resolveLocalPackageRoot, withS
12
12
  export function attachDescribeCommand(parent, context) {
13
13
  const cmd = parent
14
14
  .command("describe <id>")
15
- .alias("show")
16
15
  .description("Show action definition, schema, and description")
17
16
  .option("-P, --package <id>", "Target package ID or path");
18
17
  return applyTargetOptions(cmd)
@@ -1,7 +1,7 @@
1
- import { existsSync } from "node:fs";
2
- import { basename } from "node:path";
1
+ import { existsSync, mkdirSync } from "node:fs";
2
+ import { basename, join, resolve } from "node:path";
3
3
  import { discoverProjects, listLinkedPackages, resolvePackageRoot, } from "@actiondock/core/registry";
4
- import { findProjectRoot, } from "@actiondock/core";
4
+ import { findProjectRoot, loadProjectConfig, } from "@actiondock/core";
5
5
  import { ExecutionError, notInProjectError, packageNotFoundError, wrapAsExecutionError } from "../errors.js";
6
6
  import { renderResult, writeStdout } from "../renderer.js";
7
7
  import { getEffectiveOptions, parseListOption } from "../utils/index.js";
@@ -83,7 +83,7 @@ export function registerExportCommand(program, context) {
83
83
  }
84
84
  const isMachine = Boolean(options.json);
85
85
  try {
86
- const { exportCompositeSkill, exportSkill, exportSkillBatch } = await import("@actiondock/builder");
86
+ const { allocatePackageDirName, exportCompositeSkill, exportSkill } = await import("@actiondock/builder");
87
87
  if (options.bundle !== undefined) {
88
88
  const bundleName = typeof options.bundle === "string" && options.bundle.trim()
89
89
  ? options.bundle.trim()
@@ -129,18 +129,36 @@ export function registerExportCommand(program, context) {
129
129
  if (!isMachine) {
130
130
  writeStdout(`Batch exporting ${roots.length} Skill packages...`);
131
131
  }
132
- const batchRes = await exportSkillBatch({
133
- projectRoots: roots,
134
- mode,
135
- outDir: options.out,
136
- archive: options.archive,
137
- playbooks: options.playbook,
138
- actions: options.actions,
139
- skillMdPath: options.skillMd,
140
- vendorDeps: options.vendorDeps,
141
- allowInstallScripts: options.allowInstallScripts,
142
- requireReproducible: options.requireReproducible,
143
- });
132
+ const baseOutDir = resolve(options.out || join(process.cwd(), "dist", "skills"));
133
+ mkdirSync(baseOutDir, { recursive: true });
134
+ const usedDirNames = new Set();
135
+ const results = [];
136
+ for (const projectRoot of roots) {
137
+ const config = loadProjectConfig(projectRoot);
138
+ const pkgSlug = allocatePackageDirName(usedDirNames, config.id);
139
+ const pkgOutDir = join(baseOutDir, `${pkgSlug}-skill`);
140
+ const res = await exportSkill({
141
+ projectRoot,
142
+ mode,
143
+ outDir: pkgOutDir,
144
+ archive: options.archive,
145
+ playbooks: options.playbook,
146
+ actions: options.actions,
147
+ skillMdPath: options.skillMd,
148
+ vendorDeps: options.vendorDeps,
149
+ allowInstallScripts: options.allowInstallScripts,
150
+ requireReproducible: options.requireReproducible,
151
+ });
152
+ results.push(res);
153
+ }
154
+ const totalActions = results.reduce((sum, r) => sum + r.actionsCount, 0);
155
+ const totalPlaybooks = results.reduce((sum, r) => sum + r.playbooksCount, 0);
156
+ const batchRes = {
157
+ results,
158
+ outDir: baseOutDir,
159
+ totalActions,
160
+ totalPlaybooks,
161
+ };
144
162
  renderResult(batchRes, {
145
163
  json: isMachine,
146
164
  humanFormatter: () => {
@@ -1,31 +1,44 @@
1
1
  import { Command } from "commander";
2
2
  import type { CliContext } from "../types.js";
3
- import { registerActionCommands } from "./action/index.js";
4
- import { registerAddCommand } from "./add.js";
5
- import { registerBuildCommand } from "./build.js";
6
- import { registerConfigCommands } from "./config/index.js";
7
- import { registerDescribeCommand } from "./describe.js";
8
- import { registerDoctorCommand } from "./doctor.js";
9
- import { registerExportCommand } from "./export.js";
10
- import { registerGenerateCommands } from "./generate.js";
11
- import { registerInfoCommand } from "./info.js";
12
- import { registerInitCommand } from "./init.js";
13
- import { registerLinkCommands } from "./link.js";
14
- import { registerListCommand } from "./list.js";
15
- import { registerMcpCommands } from "./mcp.js";
16
- import { registerPackCommand } from "./pack.js";
17
- import { registerPlaybookCommands } from "./playbook.js";
18
- import { registerProfileCommands } from "./profile.js";
19
- import { registerRemoveCommand } from "./remove.js";
20
- import { registerRunCommand } from "./run.js";
21
- import { registerRunsCommands } from "./runs.js";
22
- import { registerServeCommand } from "./serve.js";
23
- import { registerStateCommands } from "./state.js";
24
- import { registerTestCommand } from "./test.js";
25
- import { registerValidateCommand } from "./validate.js";
26
3
  /**
27
4
  * CLI 版本号(来自 package.json 单一事实源)。
28
5
  */
29
6
  export declare const CLI_VERSION: string;
7
+ /**
8
+ * 判断命令行参数数组是否以宿主运行环境(node、bun、tsx 等)及入口脚本为前置元素。
9
+ */
10
+ export declare function isNodeArgv(argv: readonly string[]): boolean;
11
+ /**
12
+ * 从命令行参数数组中解析出目标子命令名称(跳过全局选项与启动包装参数)。
13
+ *
14
+ * @param argv 命令行原始参数数组
15
+ * @param parseOptions Commander 解析选项(如 { from: 'user' })
16
+ * @returns 目标子命令名称或 null
17
+ */
18
+ export declare function resolveTargetSubcommand(argv: readonly string[], parseOptions?: {
19
+ from?: string;
20
+ }): string | null;
30
21
  export declare function createCliProgram(context?: CliContext): Command;
31
- export { registerActionCommands, registerAddCommand, registerBuildCommand, registerConfigCommands, registerDescribeCommand, registerDoctorCommand, registerExportCommand, registerGenerateCommands, registerInfoCommand, registerInitCommand, registerLinkCommands, registerListCommand, registerMcpCommands, registerPackCommand, registerPlaybookCommands, registerProfileCommands, registerRemoveCommand, registerRunCommand, registerRunsCommands, registerServeCommand, registerStateCommands, registerTestCommand, registerValidateCommand, };
22
+ export declare const registerActionCommands: (program: Command, context?: CliContext) => Promise<any>;
23
+ export declare const registerAddCommand: (program: Command, context?: CliContext) => Promise<any>;
24
+ export declare const registerBuildCommand: (program: Command, context?: CliContext) => Promise<any>;
25
+ export declare const registerConfigCommands: (program: Command, context?: CliContext) => Promise<any>;
26
+ export declare const registerDescribeCommand: (program: Command, context?: CliContext) => Promise<any>;
27
+ export declare const registerDoctorCommand: (program: Command, context?: CliContext) => Promise<any>;
28
+ export declare const registerExportCommand: (program: Command, context?: CliContext) => Promise<any>;
29
+ export declare const registerGenerateCommands: (program: Command, context?: CliContext) => Promise<any>;
30
+ export declare const registerInfoCommand: (program: Command, context?: CliContext) => Promise<any>;
31
+ export declare const registerInitCommand: (program: Command) => Promise<any>;
32
+ export declare const registerLinkCommands: (program: Command) => Promise<any>;
33
+ export declare const registerListCommand: (program: Command, context?: CliContext) => Promise<any>;
34
+ export declare const registerMcpCommands: (program: Command, context?: CliContext) => Promise<any>;
35
+ export declare const registerPackCommand: (program: Command, context?: CliContext) => Promise<any>;
36
+ export declare const registerPlaybookCommands: (program: Command, context?: CliContext) => Promise<any>;
37
+ export declare const registerProfileCommands: (program: Command) => Promise<any>;
38
+ export declare const registerRemoveCommand: (program: Command, context?: CliContext) => Promise<any>;
39
+ export declare const registerRunCommand: (program: Command, context?: CliContext) => Promise<any>;
40
+ export declare const registerRunsCommands: (program: Command, context?: CliContext) => Promise<any>;
41
+ export declare const registerServeCommand: (program: Command, context?: CliContext) => Promise<any>;
42
+ export declare const registerStateCommands: (program: Command, context?: CliContext) => Promise<any>;
43
+ export declare const registerTestCommand: (program: Command) => Promise<any>;
44
+ export declare const registerValidateCommand: (program: Command, context?: CliContext) => Promise<any>;