@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 +16 -6
- package/dist/commands/action/create.js +3 -2
- package/dist/commands/run.d.ts +5 -1
- package/dist/commands/run.js +60 -5
- package/dist/commands/validate.js +13 -1
- package/dist/renderers/action.d.ts +31 -24
- package/dist/renderers/action.js +70 -73
- package/package.json +5 -5
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
|
-
-
|
|
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
|
-
-
|
|
156
|
-
-
|
|
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} --
|
|
203
|
-
writeStdout(` Complex input or large text: ad run ${id} --
|
|
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);
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -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
|
*
|
package/dist/commands/run.js
CHANGED
|
@@ -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
|
|
2
|
-
|
|
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
|
-
*
|
|
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;
|
package/dist/renderers/action.js
CHANGED
|
@@ -1,4 +1,61 @@
|
|
|
1
|
-
import {
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
38
|
-
"@actiondock/core": "^2.
|
|
39
|
-
"@actiondock/mcp": "^2.
|
|
40
|
-
"@actiondock/sdk": "^2.
|
|
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
|
},
|