@actiondock/cli 2.11.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,6 +59,10 @@ ad run sample.greet -- name=Alice count:=1
59
59
  # 复杂参数或对象从文件读取(与扁平参数互斥)
60
60
  ad run sample.greet --input-file input.json
61
61
 
62
+ # 原始文本管道绑定(假定已注册 summarize 动作且 text 是字符串入参)
63
+ # 可与扁平赋值组合,与 --input / --input-file 互斥
64
+ printf '这是一段正文' | ad run summarize --stdin-field text -- style=brief
65
+
62
66
  # 自动化与脚本通过标准输入传递
63
67
  cat input.json | ad run sample.greet --input-file -
64
68
  ```
@@ -126,11 +130,12 @@ ad pack
126
130
  - 路径冲突(叶节点与容器冲突、对象与数组冲突、重复赋值)严格拒绝(`INPUT_PATH_CONFLICT`)。
127
131
  - 拦截原型污染敏感属性(`__proto__`、`constructor`、`prototype`)。
128
132
  - 三种输入模式互斥:扁平参数、`--input` 与 `--input-file` 严格互斥,不可混用(`INPUT_CONFLICT`);未指定输入时默认为 `{}`。
133
+ - 原始文本管道绑定:`printf '正文' | ad run <action> --stdin-field <field> [-- <assignments...>]` 将 stdin 完整正文原样绑定为指定顶层字段的字符串值(不解析类型、不剥 BOM、不修剪空白、空输入为空字符串);可与扁平赋值组合,与 `--input` / `--input-file` 互斥;stdin 源字节与绑定后的最终入参序列化大小各自受默认 10MiB 上限约束,分别超限报 `INPUT_LIMIT_EXCEEDED` 与 `FLAT_INPUT_LIMIT_EXCEEDED`,JSON 转义放大也计入最终大小;严格 UTF-8 校验失败报读取错误。管道非事务,高风险写入先完整生成并校验再执行。
129
134
  - 传统输入选项:
130
135
  - 简单内联参数:使用 `--input <json>` 直接解析 JSON 字符串。
131
136
  - 复杂对象文件:使用 `--input-file <path>` 读取文件并解析 JSON,避免各类终端的引号转义损坏。
132
137
  - 标准输入管道:使用 `--input-file -` 从标准输入读取全部数据并解析 JSON。
133
- - 统一解析:解析前均自动剔除 UTF-8 BOM 标记,且不设人为大小上限。
138
+ - 统一解析:JSON 输入在解析前剔除 UTF-8 BOM,默认大小上限为 10MiB;改用文件不会解除限制。原始文本绑定保留正文 BOM。
134
139
 
135
140
  ### Windows 与多终端传参建议
136
141
 
@@ -152,8 +157,13 @@ $data | ConvertTo-Json -Depth 100 | ad run complex-action --input-file -
152
157
 
153
158
  ### Action 输出模式与机器模式
154
159
 
155
- - **默认原始纯文本输出**:`ad run` 默认采用面向终端人类阅读与 LLM Agent 上下文消费的原始输出模式。直接将执行结果正文内容(如文件 `content`、`text`、`message` 或标量字符串)输出至 stdout(保留真实换行且无 JSON 转义),相关元数据(如文件路径、行号范围、截断标记)独立输出至 stderr,符合 Unix 管道安全原则。业务执行失败时在 stderr 输出错误详情并以退出码 1 退出。
156
- - **机器 JSON 格式**(`--json`):当需要以程序化方式消费、获取完整结构化数据或被外部系统集成时,传入 `--json`。面向智能体调用推荐使用该模式;此时输出标准 JSON 结果(包含 `ok`、`runId`、`data` 或 `error`);若参数解析出错输出标准错误信封并以退出码 2 退出。
160
+ - **默认纯文本输出**:`ad run` 默认采用纯文本模式。标量直接输出;结构化对象完整输出为标准 JSON 格式到 stdout;不进行私有业务字段自动嗅探。
161
+ - **显式正文输出与默认注解**:
162
+ - 显式指定正文字段:通过 `ad run <id> --text-field <field> -- ...` 提取结果中特定顶层自有字符串字段输出至 stdout(保留真实换行且无 JSON 转义),其余字段以 JSON 对象形式输出至 stderr(元数据为空时不输出)。
163
+ - 声明式默认正文:Action 清单中声明 `annotations["actiondock.cli"] = { "textField": "<field>" }` 时,未指定 `--text-field` 时自动按声明提取正文与元数据;显式 `--text-field` 优先于默认注解。
164
+ - 严格校验与契约闭环:正文字段缺失、非字符串或返回数据非对象时,明确输出错误并以退出码 1 退出,不静默回退,不改写运行记录。契约通过 `ad describe` 呈现通道语义与覆盖指引,并通过 `ad validate` 进行纯静态元数据合规校验。
165
+ - 参数互斥:`--text-field` 与 `--json`、`--async` 严格互斥,在执行前校验并以退出码 2 退出。
166
+ - **机器模式**(`--json`):当需要以程序化方式消费、获取完整结构化数据或被外部系统集成时,传入 `--json`。此时始终输出完整执行信封(包含 `ok`、`runId`、`data` 或 `error`),忽略默认正文注解;若参数解析出错输出标准错误信封并以退出码 2 退出。
157
167
 
158
168
  ---
159
169
 
@@ -166,9 +176,9 @@ $data | ConvertTo-Json -Depth 100 | ad run complex-action --input-file -
166
176
  | `ad remove <package>` | 卸载并更新锁定依赖,提供原子回滚保护 |
167
177
  | `ad info [patterns...]` | 检索包元数据与能力清单,支持模式匹配与树形展示 |
168
178
  | `ad list [patterns...]` | 列出包内所有已注册的 Action |
169
- | `ad describe <id>` | 编码顾问:查看 Action 的详情、模式字段明细、Flat 编码指引与建议赋值 |
170
- | `ad run <id>` | 本地或远程执行指定 Action(规范语法 `ad run <id> [options] -- <assignments...>`,支持 `--json` 输出标准信封) |
171
- | `ad validate [id]` | 校验 Action 规范与模式规范 |
179
+ | `ad describe <id>` | 编码顾问:查看 Action 的详情、模式字段明细、Flat 编码指引、建议赋值与输出选择契约 |
180
+ | `ad run <id>` | 本地或远程执行指定 Action(规范语法 `ad run <id> [options] -- <assignments...>`,支持 `--stdin-field` 绑定原始文本、`--text-field` 提取正文与 `--json` 输出标准信封) |
181
+ | `ad validate [id]` | 校验 Action 规范、模式规范与输出选择契约 |
172
182
  | `ad doctor` | 执行运行环境与项目结构健康诊断 |
173
183
  | `ad action create <id>` | 创建新 Action 源码 |
174
184
  | `ad playbook list` / `show` | 查看智能体操作规程 Playbook |
@@ -199,8 +199,9 @@ ${returnBody}
199
199
  writeStdout(`\nParameter contract:`, context);
200
200
  writeStdout(` ad describe ${id}`, context);
201
201
  writeStdout(`\nUsage:`, context);
202
- writeStdout(` Pass parameters according to describe assignment template: ad run ${id} --json -- ASSIGNMENT...`, context);
203
- writeStdout(` Complex input or large text: ad run ${id} --json --input-file input.json`, 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);
204
205
  }
205
206
  catch (err) {
206
207
  throw wrapAsExecutionError(err);
@@ -2,14 +2,18 @@ import { type InvocationControl } from "@actiondock/core/server";
2
2
  import type { ExecutionResult } from "@actiondock/sdk";
3
3
  import { Command } from "commander";
4
4
  import type { CliContext } from "../types.js";
5
+ export interface RawExecutionRenderOptions {
6
+ textField?: string;
7
+ }
5
8
  /**
6
9
  * 以原始纯文本形式渲染 Action 执行终态结果(默认纯文本模式)。
7
10
  *
8
11
  * 设计契约:
9
12
  * - 通用纯文本透传:标量直接输出,结构化对象按标准规范呈现,杜绝私有业务字段嗅探。
13
+ * - 显式或声明式正文输出:指定 textField 时仅输出该自有字符串字段至 stdout,剩余字段以 JSON 对象形式输出至 stderr。
10
14
  * - 标准输出仅承载业务有效载荷,保持原生排版与真实换行,供用户调阅或下游管道消费。
11
15
  */
12
- export declare function renderRawExecutionResult(targetRef: string, result: ExecutionResult, context?: CliContext): void;
16
+ export declare function renderRawExecutionResult(targetRef: string, result: ExecutionResult, context?: CliContext, options?: RawExecutionRenderOptions): void;
13
17
  /**
14
18
  * 统一执行 Action 核心逻辑(使用 ActionDockService 服务端口)。
15
19
  *
@@ -1,18 +1,27 @@
1
1
  import { validateActionInputValue, mapInputValidationFailure, } from "@actiondock/core/project";
2
2
  import { resolveTarget, } from "@actiondock/core/profile";
3
- import { resolveExecutionHint } from "@actiondock/core";
3
+ import { ACTION_NOT_FOUND, NOT_FOUND, resolveExecutionHint, } from "@actiondock/core";
4
4
  import { ArgumentError, ExecutionError, SigintError, packageNotFoundError } from "../errors.js";
5
- import { writeStderr, writeStdout } from "../renderer.js";
5
+ import { extractTextFieldPayload, resolveActionDefaultTextField, writeStderr, writeStdout, } from "../renderer.js";
6
6
  import { applyTargetOptions, getEffectiveOptions, resolveActionInput, resolveLocalPackageRoot, resolveTimeoutMs, withService, } from "../utils/index.js";
7
7
  /**
8
8
  * 以原始纯文本形式渲染 Action 执行终态结果(默认纯文本模式)。
9
9
  *
10
10
  * 设计契约:
11
11
  * - 通用纯文本透传:标量直接输出,结构化对象按标准规范呈现,杜绝私有业务字段嗅探。
12
+ * - 显式或声明式正文输出:指定 textField 时仅输出该自有字符串字段至 stdout,剩余字段以 JSON 对象形式输出至 stderr。
12
13
  * - 标准输出仅承载业务有效载荷,保持原生排版与真实换行,供用户调阅或下游管道消费。
13
14
  */
14
- export function renderRawExecutionResult(targetRef, result, context) {
15
+ export function renderRawExecutionResult(targetRef, result, context, options) {
15
16
  if (result.ok) {
17
+ if (options?.textField !== undefined) {
18
+ const { text, metadata } = extractTextFieldPayload(result.data, options.textField);
19
+ writeStdout(text, context);
20
+ if (metadata) {
21
+ writeStderr(JSON.stringify(metadata, null, 2), context);
22
+ }
23
+ return;
24
+ }
16
25
  const data = result.data;
17
26
  let rawText;
18
27
  if (typeof data === "string") {
@@ -58,6 +67,24 @@ export async function executeAction(id, options, context, flatArgs, control) {
58
67
  if (!id) {
59
68
  throw new ArgumentError("Action ID is required for run");
60
69
  }
70
+ if (options.textField !== undefined) {
71
+ if (typeof options.textField !== "string" || options.textField.trim() === "") {
72
+ throw new ArgumentError("The --text-field option requires a non-empty field name.");
73
+ }
74
+ if (options.json) {
75
+ throw new ArgumentError("Cannot specify both --text-field and --json.");
76
+ }
77
+ if (options.async) {
78
+ throw new ArgumentError("Cannot specify both --text-field and --async.");
79
+ }
80
+ }
81
+ // --stdin-field 与 --text-field 分属输入绑定与输出选择,可同时使用;
82
+ // 与完整 JSON 输入来源的互斥由共享 resolver 统一裁决(INPUT_CONFLICT)
83
+ if (options.stdinField !== undefined) {
84
+ if (typeof options.stdinField !== "string") {
85
+ throw new ArgumentError("The --stdin-field option requires a field name.");
86
+ }
87
+ }
61
88
  const effectiveControl = control ?? context?.control;
62
89
  const effectiveSignal = effectiveControl?.signal;
63
90
  const effectiveFlatArgs = flatArgs ?? options.flatArgs;
@@ -65,7 +92,9 @@ export async function executeAction(id, options, context, flatArgs, control) {
65
92
  input: options.input,
66
93
  inputFile: options.inputFile,
67
94
  flatArgs: effectiveFlatArgs && effectiveFlatArgs.length > 0 ? effectiveFlatArgs : undefined,
95
+ stdinField: options.stdinField,
68
96
  stdin: context?.stdin,
97
+ signal: effectiveSignal,
69
98
  });
70
99
  const check = validateActionInputValue(input);
71
100
  if (!check.valid) {
@@ -131,6 +160,21 @@ export async function executeAction(id, options, context, flatArgs, control) {
131
160
  }
132
161
  }
133
162
  else {
163
+ let effectiveTextField = options.textField;
164
+ if (!isMachine && effectiveTextField === undefined) {
165
+ try {
166
+ const spec = await service.discovery.describeAction(targetRef);
167
+ effectiveTextField = resolveActionDefaultTextField(spec.annotations);
168
+ }
169
+ catch (err) {
170
+ if (err?.code === ACTION_NOT_FOUND || err?.code === NOT_FOUND) {
171
+ // 若动作未找到,继续交由 execution.run 生成统一的执行与提示结果
172
+ }
173
+ else {
174
+ throw err;
175
+ }
176
+ }
177
+ }
134
178
  const result = await service.execution.run(targetRef, input, {
135
179
  signal: effectiveSignal,
136
180
  timeoutMs,
@@ -152,7 +196,7 @@ export async function executeAction(id, options, context, flatArgs, control) {
152
196
  }
153
197
  }
154
198
  else {
155
- renderRawExecutionResult(targetRef, result, context);
199
+ renderRawExecutionResult(targetRef, result, context, { textField: effectiveTextField });
156
200
  }
157
201
  if (!result.ok) {
158
202
  if (context) {
@@ -203,6 +247,15 @@ Flat Input Syntax & Examples:
203
247
  # Nested object properties
204
248
  ad run <id> -- user.name="alice" user.age:=30
205
249
 
250
+ Text Field Output:
251
+ # Extract specific text field to stdout (remaining fields as JSON to stderr)
252
+ ad run <id> --text-field content -- path="README.md"
253
+
254
+ Raw Text Input from stdin:
255
+ # Bind entire stdin content as a string to the given input field
256
+ printf 'body text' | ad run <id> --stdin-field text -- style=brief
257
+ cat report.md | ad run <id> --stdin-field content
258
+
206
259
  Complex or multiline inputs:
207
260
  # Pass via JSON file with --input-file to avoid shell escaping issues
208
261
  ad run <id> --input-file input.json`;
@@ -219,7 +272,8 @@ export function attachRunCommand(parent, context) {
219
272
  .option("-P, --package <id>", "Target package ID or path")
220
273
  .option("-i, --input <json>", "Action input as inline JSON")
221
274
  .option("-f, --input-file <path>", "Action input from JSON file, or '-' for stdin")
222
- .option("-c, --config <key=value...>", "Temporary config override (repeatable)");
275
+ .option("-c, --config <key=value...>", "Temporary config override (repeatable)")
276
+ .option("--stdin-field <field>", "Bind raw stdin text to a top-level action input field");
223
277
  cmd.unknownOption = function (flag) {
224
278
  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
279
  };
@@ -229,6 +283,7 @@ export function attachRunCommand(parent, context) {
229
283
  .option("--async", "Execute asynchronously in background (requires remote server or profile)")
230
284
  .option("--data-dir <path>", "Custom database directory")
231
285
  .option("--json", "Output as JSON")
286
+ .option("--text-field <field>", "Extract and output a specific top-level string field as raw text")
232
287
  .addHelpText("after", RUN_HELP_AFTER_TEXT)
233
288
  .action(async (id, params, rawOptions, cmd) => {
234
289
  let flatArgs;
@@ -1,4 +1,4 @@
1
- import { checkGeneratedTypes, GENERATED_TYPES_OUTDATED_CODE, loadActions, } from "@actiondock/core/project";
1
+ import { checkGeneratedTypes, GENERATED_TYPES_OUTDATED_CODE, loadActions, analyzeActionOutputContract, } from "@actiondock/core/project";
2
2
  import { ArgumentError, ExecutionError } from "../errors.js";
3
3
  import { renderActionValidation, renderResult } from "../renderer.js";
4
4
  import { getEffectiveOptions, requirePackageRoot } from "../utils/index.js";
@@ -49,10 +49,22 @@ export function attachValidateCommand(parent, context) {
49
49
  if (outSchema && typeof outSchema !== "object") {
50
50
  errors.push("Invalid outputSchema object");
51
51
  }
52
+ const annotations = item.spec?.annotations ?? item.act?.annotations;
53
+ const contractAnalysis = analyzeActionOutputContract({
54
+ annotations,
55
+ outputSchema: outSchema,
56
+ });
57
+ if (contractAnalysis.errors.length > 0) {
58
+ for (const err of contractAnalysis.errors) {
59
+ errors.push(err);
60
+ }
61
+ }
62
+ const warnings = contractAnalysis.warnings.slice();
52
63
  results.push({
53
64
  id: item.id,
54
65
  valid: errors.length === 0,
55
66
  errors,
67
+ ...(warnings.length > 0 ? { warnings } : {}),
56
68
  });
57
69
  }
58
70
  const allValid = results.every((r) => r.valid);
@@ -1,5 +1,32 @@
1
- import type { ActionSpec } from "@actiondock/core";
2
- import { buildActionDescribePayload } from "@actiondock/core/project";
1
+ import { formatActionDetail, type FormatActionDetailOptions } from "@actiondock/core/project";
2
+ export { formatActionDetail, type FormatActionDetailOptions, };
3
+ /**
4
+ * 解析 Action 注解中的默认正文输出字段声明。
5
+ *
6
+ * 契约规范:
7
+ * - 注解键名固定为 actiondock.cli,值必须为非空非数组对象。
8
+ * - 正文字段键名为 textField,值必须为非空字符串。
9
+ * - 无相关注解或未声明 textField 时返回 undefined。
10
+ * - 注解存在但类型非法时抛出 ExecutionError (INVALID_ANNOTATION)。
11
+ */
12
+ export declare function resolveActionDefaultTextField(annotations?: Record<string, unknown>): string | undefined;
13
+ /**
14
+ * 结构化正文与元数据抽取结果。
15
+ */
16
+ export interface TextFieldExtractionResult {
17
+ text: string;
18
+ metadata?: Record<string, unknown>;
19
+ }
20
+ /**
21
+ * 从 Action 执行数据中抽取指定自有顶层正文字段及剩余元数据。
22
+ *
23
+ * 契约规范:
24
+ * - 仅支持结果数据的顶层自有字符串字段,拒绝通过原型链提取。
25
+ * - 结果数据本身必须为对象且不能为数组。
26
+ * - 目标字段必须存在且值为字符串(空字符串为合法有效正文)。
27
+ * - 剩余元数据安全构造,杜绝原型污染;元数据为空时返回 undefined。
28
+ */
29
+ export declare function extractTextFieldPayload(data: unknown, textField: string): TextFieldExtractionResult;
3
30
  /**
4
31
  * 格式化渲染 Action 列表。
5
32
  */
@@ -8,30 +35,9 @@ export declare function renderActionList(items: Array<{
8
35
  description: string;
9
36
  packageId?: string;
10
37
  }>, title?: string, isFallback?: boolean, intent?: string): string;
11
- /**
12
- * 格式化渲染 Action 详情人类可读文本。
13
- *
14
- * @param input Action 描述载荷或 Action 规范
15
- * @returns 格式化后的说明文本
16
- */
17
- export declare function formatActionDetail(input: ReturnType<typeof buildActionDescribePayload> | (Partial<ActionSpec> & {
18
- id: string;
19
- }) | {
20
- id: string;
21
- packageId?: string;
22
- projectRoot?: string;
23
- description?: string;
24
- inputSchema?: unknown;
25
- outputSchema?: unknown;
26
- tags?: string[];
27
- annotations?: Record<string, unknown>;
28
- uses?: string[];
29
- entry?: string;
30
- [key: string]: any;
31
- }): string;
32
38
  /**
33
39
  * 格式化渲染 Action 详情(编码顾问 Encoding Advisor)。
34
- * 统一复用 formatActionDetail 实现。
40
+ * 统一复用核心 formatActionDetail 实现。
35
41
  */
36
42
  export declare function renderActionDetail(action: {
37
43
  id: string;
@@ -48,4 +54,5 @@ export declare function renderActionValidation(results: Array<{
48
54
  id: string;
49
55
  valid: boolean;
50
56
  errors: string[];
57
+ warnings?: string[];
51
58
  }>): string;
@@ -1,4 +1,61 @@
1
- import { buildActionDescribePayload, ACTION_DESCRIBE_SYNTAX_REFERENCE, } from "@actiondock/core/project";
1
+ import { inspectActionTextFieldAnnotation, formatActionDetail, } from "@actiondock/core/project";
2
+ export { formatActionDetail, };
3
+ import { ExecutionError } from "../errors.js";
4
+ /**
5
+ * 解析 Action 注解中的默认正文输出字段声明。
6
+ *
7
+ * 契约规范:
8
+ * - 注解键名固定为 actiondock.cli,值必须为非空非数组对象。
9
+ * - 正文字段键名为 textField,值必须为非空字符串。
10
+ * - 无相关注解或未声明 textField 时返回 undefined。
11
+ * - 注解存在但类型非法时抛出 ExecutionError (INVALID_ANNOTATION)。
12
+ */
13
+ export function resolveActionDefaultTextField(annotations) {
14
+ const inspection = inspectActionTextFieldAnnotation(annotations);
15
+ if (!inspection.valid) {
16
+ throw new ExecutionError(inspection.error, undefined, "INVALID_ANNOTATION");
17
+ }
18
+ return inspection.textField;
19
+ }
20
+ /**
21
+ * 从 Action 执行数据中抽取指定自有顶层正文字段及剩余元数据。
22
+ *
23
+ * 契约规范:
24
+ * - 仅支持结果数据的顶层自有字符串字段,拒绝通过原型链提取。
25
+ * - 结果数据本身必须为对象且不能为数组。
26
+ * - 目标字段必须存在且值为字符串(空字符串为合法有效正文)。
27
+ * - 剩余元数据安全构造,杜绝原型污染;元数据为空时返回 undefined。
28
+ */
29
+ export function extractTextFieldPayload(data, textField) {
30
+ if (typeof data !== "object" || data === null || Array.isArray(data)) {
31
+ throw new ExecutionError(`CLI output format error: expected result data to be an object, but received ${data === null ? "null" : Array.isArray(data) ? "an array" : typeof data}.`, undefined, "OUTPUT_FORMAT_ERROR");
32
+ }
33
+ if (!Object.hasOwn(data, textField)) {
34
+ throw new ExecutionError(`CLI output format error: text field '${textField}' was not found in result data.`, undefined, "OUTPUT_FORMAT_ERROR");
35
+ }
36
+ const textValue = data[textField];
37
+ if (typeof textValue !== "string") {
38
+ throw new ExecutionError(`CLI output format error: text field '${textField}' must be a string, but received ${textValue === null ? "null" : Array.isArray(textValue) ? "an array" : typeof textValue}.`, undefined, "OUTPUT_FORMAT_ERROR");
39
+ }
40
+ const metadata = {};
41
+ let hasMetadata = false;
42
+ for (const key of Object.keys(data)) {
43
+ if (key === textField) {
44
+ continue;
45
+ }
46
+ Object.defineProperty(metadata, key, {
47
+ value: data[key],
48
+ enumerable: true,
49
+ writable: true,
50
+ configurable: true,
51
+ });
52
+ hasMetadata = true;
53
+ }
54
+ return {
55
+ text: textValue,
56
+ metadata: hasMetadata ? metadata : undefined,
57
+ };
58
+ }
2
59
  /**
3
60
  * 格式化渲染 Action 列表。
4
61
  */
@@ -19,78 +76,9 @@ export function renderActionList(items, title = "Actions", isFallback = false, i
19
76
  lines.push("\nTip: For composite or multi-step tasks, check 'ad playbook list' for standard operating procedures.");
20
77
  return lines.join("\n");
21
78
  }
22
- /**
23
- * 格式化渲染 Action 详情人类可读文本。
24
- *
25
- * @param input Action 描述载荷或 Action 规范
26
- * @returns 格式化后的说明文本
27
- */
28
- export function formatActionDetail(input) {
29
- const payload = "inputAdvice" in input && input.inputAdvice
30
- ? input
31
- : buildActionDescribePayload(input);
32
- const lines = [];
33
- lines.push(`Action: ${payload.id}`);
34
- if (payload.packageId) {
35
- lines.push(`Package: ${payload.packageId}`);
36
- }
37
- if (payload.description) {
38
- lines.push(`Description: ${payload.description}`);
39
- }
40
- if (payload.tags && payload.tags.length > 0) {
41
- lines.push(`Tags: ${payload.tags.join(", ")}`);
42
- }
43
- if (payload.uses && payload.uses.length > 0) {
44
- lines.push(`Uses: ${payload.uses.join(", ")}`);
45
- }
46
- if (payload.entry) {
47
- lines.push(`Entry: ${payload.entry}`);
48
- }
49
- if (payload.inputSchema !== undefined) {
50
- lines.push("");
51
- lines.push("Input Schema:");
52
- lines.push(typeof payload.inputSchema === "string"
53
- ? payload.inputSchema
54
- : JSON.stringify(payload.inputSchema, null, 2));
55
- }
56
- if (payload.outputSchema !== undefined) {
57
- lines.push("");
58
- lines.push("Output Schema:");
59
- lines.push(typeof payload.outputSchema === "string"
60
- ? payload.outputSchema
61
- : JSON.stringify(payload.outputSchema, null, 2));
62
- }
63
- lines.push("");
64
- lines.push(`Recommended Input: ${payload.inputAdvice.recommendedMode}`);
65
- if (payload.inputAdvice.reason) {
66
- lines.push(`Reason: ${payload.inputAdvice.reason}`);
67
- }
68
- const hasAssignments = Boolean(payload.inputAdvice.assignments &&
69
- Object.keys(payload.inputAdvice.assignments).length > 0);
70
- if (hasAssignments) {
71
- lines.push("");
72
- lines.push("Assignments:");
73
- for (const [key, op] of Object.entries(payload.inputAdvice.assignments)) {
74
- lines.push(` ${key}${op}`);
75
- }
76
- }
77
- if (payload.inputAdvice.recommendedMode === "flat" || hasAssignments) {
78
- lines.push("");
79
- lines.push("Syntax Reference:");
80
- lines.push(...(payload.syntaxReference || ACTION_DESCRIBE_SYNTAX_REFERENCE));
81
- }
82
- if (payload.inputAdvice.issues && payload.inputAdvice.issues.length > 0) {
83
- lines.push("");
84
- lines.push("Issues:");
85
- for (const issue of payload.inputAdvice.issues) {
86
- lines.push(` - ${issue.path}: ${issue.code}`);
87
- }
88
- }
89
- return lines.join("\n");
90
- }
91
79
  /**
92
80
  * 格式化渲染 Action 详情(编码顾问 Encoding Advisor)。
93
- * 统一复用 formatActionDetail 实现。
81
+ * 统一复用核心 formatActionDetail 实现。
94
82
  */
95
83
  export function renderActionDetail(action) {
96
84
  return formatActionDetail(action);
@@ -102,10 +90,19 @@ export function renderActionValidation(results) {
102
90
  const lines = [];
103
91
  for (const r of results) {
104
92
  if (r.valid) {
105
- lines.push(`[OK] ${r.id}: Valid`);
93
+ if (r.warnings && r.warnings.length > 0) {
94
+ lines.push(`[OK] ${r.id}: Valid (warnings: ${r.warnings.join("; ")})`);
95
+ }
96
+ else {
97
+ lines.push(`[OK] ${r.id}: Valid`);
98
+ }
106
99
  }
107
100
  else {
108
- lines.push(`[FAIL] ${r.id}: ${r.errors.join(", ")}`);
101
+ let msg = `[FAIL] ${r.id}: ${r.errors.join(", ")}`;
102
+ if (r.warnings && r.warnings.length > 0) {
103
+ msg += ` (warnings: ${r.warnings.join("; ")})`;
104
+ }
105
+ lines.push(msg);
109
106
  }
110
107
  }
111
108
  return lines.join("\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actiondock/cli",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "ActionDock CLI facade for developing, testing, building, and exporting standalone Agent Actions and Skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,10 +34,10 @@
34
34
  "test": "node ../../scripts/run-tests.ts"
35
35
  },
36
36
  "dependencies": {
37
- "@actiondock/builder": "^2.11.0",
38
- "@actiondock/core": "^2.11.0",
39
- "@actiondock/mcp": "^2.11.0",
40
- "@actiondock/sdk": "^2.11.0",
37
+ "@actiondock/builder": "^2.13.0",
38
+ "@actiondock/core": "^2.13.0",
39
+ "@actiondock/mcp": "^2.13.0",
40
+ "@actiondock/sdk": "^2.13.0",
41
41
  "commander": "^13.1.0",
42
42
  "selfsigned": "^5.5.0"
43
43
  },