@actiondock/builder 2.7.0 → 2.8.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 +4 -5
- package/dist/archive.d.ts +0 -16
- package/dist/archive.js +35 -202
- package/dist/build.d.ts +1 -0
- package/dist/build.js +26 -61
- package/dist/dependency-check.js +36 -89
- package/dist/export-batch.js +4 -6
- package/dist/export-composite.js +8 -22
- package/dist/export-node.js +1 -1
- package/dist/export-source.js +11 -61
- package/dist/exporter.js +3 -9
- package/dist/fs-utils.d.ts +3 -2
- package/dist/fs-utils.js +9 -66
- package/dist/index.d.ts +3 -10
- package/dist/index.js +5 -16
- package/dist/manifest.d.ts +26 -0
- package/dist/manifest.js +67 -2
- package/dist/pack.js +37 -47
- package/dist/planner.js +73 -102
- package/dist/skill/index.d.ts +1 -0
- package/dist/skill/index.js +1 -0
- package/dist/skill/templates.d.ts +60 -0
- package/dist/skill/templates.js +507 -0
- package/dist/skill-md.d.ts +2 -1
- package/dist/skill-md.js +2 -1
- package/dist/stage-sources.d.ts +25 -0
- package/dist/stage-sources.js +51 -0
- package/dist/types.d.ts +18 -23
- package/dist/types.js +10 -1
- package/package.json +3 -4
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
function getCleanSkillMetadata(config) {
|
|
3
|
+
const cleanName = config.id.replace(/[^a-zA-Z0-9-_]/g, "-").toLowerCase();
|
|
4
|
+
const desc = config.description || `AI Agent skill for ${config.name} (${config.id})`;
|
|
5
|
+
return { cleanName, desc };
|
|
6
|
+
}
|
|
7
|
+
function renderActionListMarkdown(actions, options = {}) {
|
|
8
|
+
return actions
|
|
9
|
+
.map((a) => {
|
|
10
|
+
const aDesc = a.description ? ` - ${a.description}` : "";
|
|
11
|
+
const idLabel = options.packageId
|
|
12
|
+
? `\`${options.packageId}/${a.id}\` (或 \`${a.id}\`)`
|
|
13
|
+
: `\`${a.id}\``;
|
|
14
|
+
const lines = [`- ${idLabel}${aDesc}`];
|
|
15
|
+
// 标注元数据解析
|
|
16
|
+
if (a.annotations && typeof a.annotations === "object") {
|
|
17
|
+
const annoList = [];
|
|
18
|
+
if (a.annotations.readOnly === true) {
|
|
19
|
+
annoList.push("只读操作");
|
|
20
|
+
}
|
|
21
|
+
if (a.annotations.destructive === true) {
|
|
22
|
+
annoList.push("破坏性操作(执行前须向用户确认)");
|
|
23
|
+
}
|
|
24
|
+
if (annoList.length > 0) {
|
|
25
|
+
lines.push(` - 属性标注: ${annoList.join(", ")}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// 输入参数模式解析
|
|
29
|
+
if (a.inputSchema &&
|
|
30
|
+
typeof a.inputSchema === "object" &&
|
|
31
|
+
a.inputSchema.properties) {
|
|
32
|
+
const props = a.inputSchema.properties;
|
|
33
|
+
const req = (a.inputSchema.required || []);
|
|
34
|
+
const propKeys = Object.keys(props);
|
|
35
|
+
if (propKeys.length > 0) {
|
|
36
|
+
lines.push(" - 输入参数:");
|
|
37
|
+
for (const k of propKeys) {
|
|
38
|
+
const p = props[k] || {};
|
|
39
|
+
const typeStr = p.type ? `\`${p.type}\`` : "`any`";
|
|
40
|
+
const reqStr = req.includes(k) ? ", 必填" : "";
|
|
41
|
+
const descStr = p.description ? `: ${p.description}` : "";
|
|
42
|
+
const defStr = p.default !== undefined
|
|
43
|
+
? ` (默认值: \`${JSON.stringify(p.default)}\`)`
|
|
44
|
+
: "";
|
|
45
|
+
lines.push(` - \`${k}\` (${typeStr}${reqStr})${descStr}${defStr}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
lines.push(" - 输入参数: 无");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
lines.push(" - 输入参数: 无");
|
|
54
|
+
}
|
|
55
|
+
// 输出字段模式解析
|
|
56
|
+
if (a.outputSchema &&
|
|
57
|
+
typeof a.outputSchema === "object" &&
|
|
58
|
+
a.outputSchema.properties) {
|
|
59
|
+
const outProps = a.outputSchema.properties;
|
|
60
|
+
const outKeys = Object.keys(outProps);
|
|
61
|
+
if (outKeys.length > 0) {
|
|
62
|
+
lines.push(" - 输出字段:");
|
|
63
|
+
for (const k of outKeys) {
|
|
64
|
+
const p = outProps[k] || {};
|
|
65
|
+
const typeStr = p.type ? `\`${p.type}\`` : "`any`";
|
|
66
|
+
const descStr = p.description ? `: ${p.description}` : "";
|
|
67
|
+
lines.push(` - \`${k}\` (${typeStr})${descStr}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return lines.join("\n");
|
|
72
|
+
})
|
|
73
|
+
.join("\n\n");
|
|
74
|
+
}
|
|
75
|
+
function renderPlaybookSectionMarkdown(playbooks, playbooksDir = "playbooks") {
|
|
76
|
+
if (playbooks.length === 0)
|
|
77
|
+
return "";
|
|
78
|
+
const normalizedDir = playbooksDir.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
79
|
+
const list = playbooks
|
|
80
|
+
.map((p) => {
|
|
81
|
+
const rel = `./${normalizedDir}/${basename(p.filePath)}`;
|
|
82
|
+
return `- **${p.id}** (\`${rel}\`): ${p.description || "业务操作指南"}`;
|
|
83
|
+
})
|
|
84
|
+
.join("\n");
|
|
85
|
+
return `
|
|
86
|
+
## 业务操作规程
|
|
87
|
+
|
|
88
|
+
> [!IMPORTANT]
|
|
89
|
+
> **规程优先准则**:当处理复合业务任务时,智能体必须优先检查是否存在匹配场景的 Playbook。若存在规程,必须优先查阅并严格遵循规程界定的步骤时序与校验逻辑推进,严禁无序拼凑调用底层 Action。
|
|
90
|
+
|
|
91
|
+
Playbook SOPs 为复杂业务任务提供逐步指导规程。详细规程请查阅对应文档:
|
|
92
|
+
|
|
93
|
+
${list}
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 渲染「结构化响应解析」小节:三处生成器共用同一 JSON 信封代码块,
|
|
98
|
+
* 仅首行名词与 stdout/stderr 描述行随变体分化。
|
|
99
|
+
*/
|
|
100
|
+
function renderJsonEnvelopeSection(wording, options) {
|
|
101
|
+
const noun = wording === "envelope" ? "信封" : "结果";
|
|
102
|
+
const stdoutLine = wording === "envelope"
|
|
103
|
+
? "- `stdout`:标准 JSON 信封结果。当 `ok` 为 `true` 时,从 `data` 提取业务返回值推进后续步骤;当 `ok` 为 `false` 时,从 `error` 提取错误码与信息以判定自愈策略或上报。"
|
|
104
|
+
: "- `stdout`:标准 JSON 结果信封。当 `ok` 为 `true` 时,从 `data` 提取业务数据;当 `ok` 为 `false` 时,从 `error` 读取错误原因以处理异常。";
|
|
105
|
+
const stderrTail = wording === "envelope" ? "跟踪" : "";
|
|
106
|
+
const descriptionBlock = options?.withDescriptions === false
|
|
107
|
+
? ""
|
|
108
|
+
: `\n\n${stdoutLine}\n- \`stderr\`:执行日志与诊断${stderrTail}信息。`;
|
|
109
|
+
return `### 结构化响应解析
|
|
110
|
+
|
|
111
|
+
所有 Action 执行结果均在 \`stdout\` 输出标准格式的 JSON ${noun}:
|
|
112
|
+
|
|
113
|
+
\`\`\`json
|
|
114
|
+
// 执行成功响应 (ok 为 true)
|
|
115
|
+
{
|
|
116
|
+
"ok": true,
|
|
117
|
+
"runId": "01J...",
|
|
118
|
+
"data": { ... }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 执行失败响应 (ok 为 false)
|
|
122
|
+
{
|
|
123
|
+
"ok": false,
|
|
124
|
+
"runId": "01J...",
|
|
125
|
+
"error": {
|
|
126
|
+
"code": "ACTION_EXECUTION_FAILED",
|
|
127
|
+
"message": "错误详细描述信息"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
\`\`\`${descriptionBlock}`;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 渲染「故障排查与环境安装指引」整节:source 与 composite 共用完整安装指引,
|
|
134
|
+
* 差异点(依赖安装步骤标题、重新链接步骤标题、复合链接语义说明)通过参数分化。
|
|
135
|
+
*/
|
|
136
|
+
function renderTroubleshootingSection(options) {
|
|
137
|
+
const relinkNote = options.compositeLinkNote
|
|
138
|
+
? `\n \`ad link\` 会自动识别并注册工作区下的所有子包,使其中的 Action 随时可以通过完全限定标识调用。`
|
|
139
|
+
: "";
|
|
140
|
+
return `---
|
|
141
|
+
|
|
142
|
+
## 故障排查与环境安装指引(按需查阅)
|
|
143
|
+
|
|
144
|
+
> [!NOTE]
|
|
145
|
+
> **按需排查原则**:默认宿主环境中已预置 \`ad\` 命令行工具与 Node.js 运行环境。正常执行流程直接调用上述 Action 即可,**严禁在任务启动前盲目进行前置环境检查或体检**;仅在终端明确报错提示命令不存在(如 \`ad: command not found\`)或提示依赖缺失时,方可按本节指引安装初始化。
|
|
146
|
+
|
|
147
|
+
### 命令行工具与环境依赖未就绪时的安装指引
|
|
148
|
+
|
|
149
|
+
若宿主环境未安装 \`ad\` 命令行工具或依赖缺失,请依次按如下步骤完成安装:
|
|
150
|
+
|
|
151
|
+
- **环境要求**:Node.js 版本大于等于 24.12.0(执行 \`node -v\` 确认)。
|
|
152
|
+
- **全局安装 ActionDock 命令行工具**:
|
|
153
|
+
\`\`\`bash
|
|
154
|
+
npm install -g @actiondock/cli
|
|
155
|
+
\`\`\`
|
|
156
|
+
- **${options.dependencyStepLabel}**:
|
|
157
|
+
若在技能目录内调用时提示模块缺失,在 \`<skill_root>\` 目录下安装生产依赖:
|
|
158
|
+
\`\`\`bash
|
|
159
|
+
cd "<skill_root>" && npm install --omit=dev
|
|
160
|
+
\`\`\`
|
|
161
|
+
- **验证工具就绪**:
|
|
162
|
+
\`\`\`bash
|
|
163
|
+
ad --version
|
|
164
|
+
\`\`\`
|
|
165
|
+
- **环境诊断与体检**:
|
|
166
|
+
安装完成后若仍遇到异常,执行体检命令排查:
|
|
167
|
+
\`\`\`bash
|
|
168
|
+
ad doctor
|
|
169
|
+
\`\`\`
|
|
170
|
+
- **${options.relinkStepLabel}**:
|
|
171
|
+
\`\`\`bash
|
|
172
|
+
ad link "<skill_root>"
|
|
173
|
+
\`\`\`${relinkNote}`;
|
|
174
|
+
}
|
|
175
|
+
export function generateSourceSkillMd(config, actions, playbooks) {
|
|
176
|
+
const { cleanName, desc } = getCleanSkillMetadata(config);
|
|
177
|
+
const pkgId = config.id;
|
|
178
|
+
const firstAction = actions[0]?.id || "sample.greet";
|
|
179
|
+
const playbookSection = renderPlaybookSectionMarkdown(playbooks, config.playbooksDir || "playbooks");
|
|
180
|
+
const actionListMd = renderActionListMarkdown(actions, { packageId: pkgId });
|
|
181
|
+
return `---
|
|
182
|
+
name: ${cleanName}
|
|
183
|
+
description: ${desc}
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
# ${config.name} (${config.id})
|
|
187
|
+
|
|
188
|
+
${desc}
|
|
189
|
+
|
|
190
|
+
## ActionDock 运行时
|
|
191
|
+
|
|
192
|
+
本技能为 **ActionDock 源码型技能包**。智能体可直接通过宿主环境中已安装的 ActionDock 命令行工具 \`ad\` 执行其中的 Action。
|
|
193
|
+
|
|
194
|
+
### 注册与链接
|
|
195
|
+
|
|
196
|
+
在初次调用或初始化时,将包含本 \`SKILL.md\` 的目录解析为 \`<skill_root>\` 并完成注册:
|
|
197
|
+
|
|
198
|
+
\`\`\`bash
|
|
199
|
+
ad link "<skill_root>"
|
|
200
|
+
\`\`\`
|
|
201
|
+
|
|
202
|
+
> \`ad link\` 天然具备幂等性,同一 Package 多次执行会直接更新路径,可安全重复调用。若初次运行提示依赖缺失,可在 \`<skill_root>\` 目录下执行 \`npm install --omit=dev\` 安装生产依赖。
|
|
203
|
+
|
|
204
|
+
### 动作参数契约按需调阅
|
|
205
|
+
|
|
206
|
+
在调用未知参数的 Action 前,可在终端执行命令查阅该 Action 的输入输出模式与详细说明:
|
|
207
|
+
|
|
208
|
+
\`\`\`bash
|
|
209
|
+
ad describe ${pkgId}/${firstAction}
|
|
210
|
+
\`\`\`
|
|
211
|
+
|
|
212
|
+
### 执行 Action
|
|
213
|
+
|
|
214
|
+
为避免多技能之间的 Action ID 命名冲突,建议统一使用带有 Package 前缀的完全限定 ID。
|
|
215
|
+
|
|
216
|
+
推荐在执行前调用 describe 命令调阅确切参数契约:
|
|
217
|
+
|
|
218
|
+
\`\`\`bash
|
|
219
|
+
# 调阅参数契约与建议赋值样例
|
|
220
|
+
ad describe ${pkgId}/${firstAction}
|
|
221
|
+
|
|
222
|
+
# 调用语法格式(其中 ASSIGNMENT 根据 ad describe 查阅的参数契约提供)
|
|
223
|
+
ad run ${pkgId}/${firstAction} --json -- ASSIGNMENT...
|
|
224
|
+
\`\`\`
|
|
225
|
+
|
|
226
|
+
将参数写入 JSON 文件并通过 --input-file 传递:
|
|
227
|
+
|
|
228
|
+
\`\`\`bash
|
|
229
|
+
ad run ${pkgId}/${firstAction} --json --input-file input.json
|
|
230
|
+
\`\`\`
|
|
231
|
+
|
|
232
|
+
> 免注册本地执行:
|
|
233
|
+
> 若工作目录已位于本技能根目录,亦可直接免 link 执行:
|
|
234
|
+
> \`\`\`bash
|
|
235
|
+
> cd <skill_root>
|
|
236
|
+
> ad run ${firstAction} --json
|
|
237
|
+
> \`\`\`
|
|
238
|
+
|
|
239
|
+
${renderJsonEnvelopeSection("envelope")}
|
|
240
|
+
${playbookSection}
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Action 目录
|
|
244
|
+
|
|
245
|
+
${actionListMd}
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 运行时配置与持久化状态
|
|
250
|
+
|
|
251
|
+
如需检查或配置该 Package 的运行时参数与持久化数据:
|
|
252
|
+
|
|
253
|
+
\`\`\`bash
|
|
254
|
+
# 查看与设置配置项
|
|
255
|
+
ad config list --package ${pkgId}
|
|
256
|
+
ad config set KEY VALUE --package ${pkgId}
|
|
257
|
+
|
|
258
|
+
# 查看与检索状态数据
|
|
259
|
+
ad state list --package ${pkgId}
|
|
260
|
+
ad state get KEY --package ${pkgId}
|
|
261
|
+
\`\`\`
|
|
262
|
+
|
|
263
|
+
${renderTroubleshootingSection({
|
|
264
|
+
dependencyStepLabel: "安装技能源码依赖",
|
|
265
|
+
relinkStepLabel: "完成安装后重新链接本技能",
|
|
266
|
+
})}
|
|
267
|
+
`;
|
|
268
|
+
}
|
|
269
|
+
export function generateStandaloneSkillMd(config, actions, playbooks, binaryRelPath = "./bin/action-bin") {
|
|
270
|
+
const { cleanName, desc } = getCleanSkillMetadata(config);
|
|
271
|
+
const firstAction = actions[0]?.id || "sample.greet";
|
|
272
|
+
const playbookSection = renderPlaybookSectionMarkdown(playbooks, config.playbooksDir || "playbooks");
|
|
273
|
+
const actionListMd = renderActionListMarkdown(actions);
|
|
274
|
+
return `---
|
|
275
|
+
name: ${cleanName}
|
|
276
|
+
description: ${desc}
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
# ${config.name} (${config.id})
|
|
280
|
+
|
|
281
|
+
${desc}
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
### 动作参数契约按需调阅
|
|
285
|
+
|
|
286
|
+
在调用未知参数的 Action 前,可在终端执行命令查阅该 Action 的输入输出模式与详细说明:
|
|
287
|
+
|
|
288
|
+
\`\`\`bash
|
|
289
|
+
${binaryRelPath} describe ${firstAction}
|
|
290
|
+
\`\`\`
|
|
291
|
+
|
|
292
|
+
### 执行 Action
|
|
293
|
+
|
|
294
|
+
推荐在执行前调用 describe 命令调阅确切参数契约:
|
|
295
|
+
|
|
296
|
+
\`\`\`bash
|
|
297
|
+
# 调阅参数契约与建议赋值样例
|
|
298
|
+
${binaryRelPath} describe ${firstAction}
|
|
299
|
+
|
|
300
|
+
# 调用语法格式(其中 ASSIGNMENT 根据 describe 查阅的参数契约提供)
|
|
301
|
+
${binaryRelPath} run ${firstAction} --json -- ASSIGNMENT...
|
|
302
|
+
\`\`\`
|
|
303
|
+
|
|
304
|
+
将参数写入 JSON 文件并通过 --input-file 传递:
|
|
305
|
+
|
|
306
|
+
\`\`\`bash
|
|
307
|
+
${binaryRelPath} run ${firstAction} --json --input-file input.json
|
|
308
|
+
\`\`\`
|
|
309
|
+
|
|
310
|
+
${renderJsonEnvelopeSection("result")}
|
|
311
|
+
${playbookSection}
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Action 目录
|
|
315
|
+
|
|
316
|
+
${actionListMd}
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 运行时配置与持久化状态
|
|
321
|
+
|
|
322
|
+
程序会自动管理其 SQLite 数据库。如需检查或配置:
|
|
323
|
+
|
|
324
|
+
\`\`\`bash
|
|
325
|
+
# 查看与设置配置项
|
|
326
|
+
${binaryRelPath} config list
|
|
327
|
+
${binaryRelPath} config set KEY VALUE
|
|
328
|
+
|
|
329
|
+
# 查看与检索状态数据
|
|
330
|
+
${binaryRelPath} state list
|
|
331
|
+
${binaryRelPath} state get KEY
|
|
332
|
+
\`\`\`
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 故障排查与依赖自愈指引(按需查阅)
|
|
337
|
+
|
|
338
|
+
若在宿主环境中执行时提示模块缺失,在技能根目录下安装生产依赖:
|
|
339
|
+
|
|
340
|
+
\`\`\`bash
|
|
341
|
+
npm install --omit=dev
|
|
342
|
+
\`\`\`
|
|
343
|
+
`;
|
|
344
|
+
}
|
|
345
|
+
export const COMPOSITE_CUSTOM_SLOTS = [
|
|
346
|
+
"intro",
|
|
347
|
+
"after-init",
|
|
348
|
+
"after-describe",
|
|
349
|
+
"after-actions",
|
|
350
|
+
"after-playbooks",
|
|
351
|
+
"after-invoke",
|
|
352
|
+
"append",
|
|
353
|
+
];
|
|
354
|
+
/** 工作区内约定俗成的复合技能自定义说明书文件名。 */
|
|
355
|
+
export const COMPOSITE_CUSTOM_DECLARATION_FILE = "SKILL.custom.md";
|
|
356
|
+
const CUSTOM_SLOT_MARKER_PATTERN = /^\s*<!--\s*actiondock:slot\s+([a-zA-Z][a-zA-Z0-9-]*)\s*-->\s*$/;
|
|
357
|
+
/**
|
|
358
|
+
* 解析自定义说明书正文:以 `<!-- actiondock:slot <name> -->` 标记行分段。
|
|
359
|
+
* 首个标记之前的内容归入 `append` 槽位;未知槽位名直接抛错,避免拼写错误被静默吞掉。
|
|
360
|
+
*/
|
|
361
|
+
export function parseCustomSections(source) {
|
|
362
|
+
const sections = [];
|
|
363
|
+
let currentSlot = "append";
|
|
364
|
+
let buffer = [];
|
|
365
|
+
const flush = () => {
|
|
366
|
+
const content = buffer.join("\n").trim();
|
|
367
|
+
buffer = [];
|
|
368
|
+
if (content) {
|
|
369
|
+
sections.push({ slot: currentSlot, content });
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
for (const line of source.split(/\r?\n/)) {
|
|
373
|
+
const match = line.match(CUSTOM_SLOT_MARKER_PATTERN);
|
|
374
|
+
if (match) {
|
|
375
|
+
flush();
|
|
376
|
+
const slot = match[1];
|
|
377
|
+
if (!COMPOSITE_CUSTOM_SLOTS.includes(slot)) {
|
|
378
|
+
throw new Error(`Unknown ActionDock custom slot '${match[1]}'. Valid slots: ${COMPOSITE_CUSTOM_SLOTS.join(", ")}`);
|
|
379
|
+
}
|
|
380
|
+
currentSlot = slot;
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
buffer.push(line);
|
|
384
|
+
}
|
|
385
|
+
flush();
|
|
386
|
+
return sections;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* 解析复合技能自定义说明书文件:支持 YAML frontmatter 中的 `description` 覆盖,
|
|
390
|
+
* 正文按槽位标记解析为自定义段落。
|
|
391
|
+
*/
|
|
392
|
+
export function parseCustomSkillDeclaration(source) {
|
|
393
|
+
let body = source;
|
|
394
|
+
let description;
|
|
395
|
+
const frontmatter = source.match(/^\uFEFF?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/);
|
|
396
|
+
if (frontmatter) {
|
|
397
|
+
body = source.slice(frontmatter[0].length);
|
|
398
|
+
const descLine = frontmatter[1].match(/^description:[ \t]*(.+?)[ \t]*$/m);
|
|
399
|
+
if (descLine) {
|
|
400
|
+
description = descLine[1].replace(/^["']|["']$/g, "");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return { description, sections: parseCustomSections(body) };
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* 生成多包聚合的复合模式 SKILL.md 文档。
|
|
407
|
+
*/
|
|
408
|
+
export function generateCompositeSkillMd(bundleName, description, packages, options) {
|
|
409
|
+
const cleanName = bundleName.replace(/[^a-zA-Z0-9-_]/g, "-").toLowerCase();
|
|
410
|
+
const samplePkg = packages.find((p) => p.actions && p.actions.length > 0);
|
|
411
|
+
const sampleActionId = samplePkg
|
|
412
|
+
? `${samplePkg.config.id}/${samplePkg.actions[0].id}`
|
|
413
|
+
: "sample.greet";
|
|
414
|
+
const actionSections = packages
|
|
415
|
+
.map((pkg) => {
|
|
416
|
+
const actList = pkg.actions
|
|
417
|
+
.map((a) => {
|
|
418
|
+
const desc = a.description ? `: ${a.description}` : "";
|
|
419
|
+
return `- \`${pkg.config.id}/${a.id}\`${desc}`;
|
|
420
|
+
})
|
|
421
|
+
.join("\n");
|
|
422
|
+
return `### ${pkg.config.name} (${pkg.config.id})\n${actList || "- 无可用 Action"}`;
|
|
423
|
+
})
|
|
424
|
+
.join("\n\n");
|
|
425
|
+
const playbookEntries = [];
|
|
426
|
+
const packagesBaseDir = options?.packagesBaseDir ?? "packages";
|
|
427
|
+
for (const pkg of packages) {
|
|
428
|
+
for (const pb of pkg.playbooks) {
|
|
429
|
+
const relPath = packagesBaseDir === "."
|
|
430
|
+
? `./${pkg.packageDir}/playbooks/${basename(pb.filePath)}`
|
|
431
|
+
: `packages/${pkg.packageDir}/playbooks/${basename(pb.filePath)}`;
|
|
432
|
+
playbookEntries.push(`- [${pb.name || pb.id}](${relPath}): ${pb.description || "标准操作规程"}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const sIntro = `---
|
|
436
|
+
name: ${cleanName}
|
|
437
|
+
description: ${description}
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
# ${bundleName} 复合技能套件
|
|
441
|
+
|
|
442
|
+
${description}`;
|
|
443
|
+
const sDescribe = `## 动作参数契约按需调阅
|
|
444
|
+
|
|
445
|
+
为节省上下文开销,各 Action 的详细参数结构不静态内嵌在说明书中。在调用未知参数的 Action 前,可在终端执行命令查阅输入输出约束:
|
|
446
|
+
|
|
447
|
+
\`\`\`bash
|
|
448
|
+
ad describe ${sampleActionId}
|
|
449
|
+
\`\`\``;
|
|
450
|
+
const sActions = `## 可用 Action 工具清单
|
|
451
|
+
|
|
452
|
+
${actionSections}
|
|
453
|
+
|
|
454
|
+
---`;
|
|
455
|
+
const sPlaybooks = playbookEntries.length > 0
|
|
456
|
+
? `## 推荐操作规程
|
|
457
|
+
|
|
458
|
+
涉及多步骤或业务流程时,优先遵循以下原位规程:
|
|
459
|
+
|
|
460
|
+
${playbookEntries.join("\n")}
|
|
461
|
+
|
|
462
|
+
---`
|
|
463
|
+
: "";
|
|
464
|
+
const sInvoke = `## 标准调用命令
|
|
465
|
+
|
|
466
|
+
推荐在执行前调用 describe 命令调阅确切参数契约:
|
|
467
|
+
|
|
468
|
+
\`\`\`bash
|
|
469
|
+
# 调阅参数契约与建议赋值样例
|
|
470
|
+
ad describe ${sampleActionId}
|
|
471
|
+
|
|
472
|
+
# 调用语法格式(其中 ASSIGNMENT 根据 ad describe 查阅的参数契约提供)
|
|
473
|
+
ad run ${sampleActionId} --json -- ASSIGNMENT...
|
|
474
|
+
\`\`\`
|
|
475
|
+
|
|
476
|
+
将参数写入 JSON 文件并通过 --input-file 传递:
|
|
477
|
+
|
|
478
|
+
\`\`\`bash
|
|
479
|
+
ad run ${sampleActionId} --json --input-file input.json
|
|
480
|
+
\`\`\`
|
|
481
|
+
|
|
482
|
+
${renderJsonEnvelopeSection("envelope", { withDescriptions: false })}`;
|
|
483
|
+
const sTroubleshooting = renderTroubleshootingSection({
|
|
484
|
+
dependencyStepLabel: "安装复合技能聚合依赖",
|
|
485
|
+
relinkStepLabel: "完成安装后重新链接复合技能",
|
|
486
|
+
compositeLinkNote: true,
|
|
487
|
+
});
|
|
488
|
+
const parts = [
|
|
489
|
+
{ slot: "intro", text: sIntro },
|
|
490
|
+
{ slot: "after-describe", text: sDescribe },
|
|
491
|
+
{ slot: "after-actions", text: sActions },
|
|
492
|
+
{ slot: "after-playbooks", text: sPlaybooks },
|
|
493
|
+
{ slot: "after-invoke", text: sInvoke },
|
|
494
|
+
{ slot: "after-init", text: sTroubleshooting },
|
|
495
|
+
{ slot: "append", text: "" },
|
|
496
|
+
];
|
|
497
|
+
// 自定义段落按文件顺序插入到对应槽位(倒序插入保证同槽位多段保持先后)
|
|
498
|
+
const customSections = options?.customSections ?? [];
|
|
499
|
+
for (const section of [...customSections].reverse()) {
|
|
500
|
+
const anchorIndex = parts.findIndex((p) => p.slot === section.slot);
|
|
501
|
+
parts.splice(anchorIndex + 1, 0, { slot: section.slot, text: section.content });
|
|
502
|
+
}
|
|
503
|
+
return (parts
|
|
504
|
+
.filter((p) => p.text.trim().length > 0)
|
|
505
|
+
.map((p) => p.text.trim())
|
|
506
|
+
.join("\n\n") + "\n");
|
|
507
|
+
}
|
package/dist/skill-md.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PlaybookDefinition, type ProjectConfig } from "@actiondock/core/project";
|
|
2
|
+
import { type CompositeCustomDeclaration, type SkillActionItem } from "./skill/index.js";
|
|
2
3
|
import type { CompositeSkillExportOptions, SelectionPlan } from "./types.js";
|
|
3
4
|
/**
|
|
4
5
|
* SKILL.md 发现、复用与模板视图适配层。
|
package/dist/skill-md.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { getPackageSlug, } from "@actiondock/core/project";
|
|
4
|
+
import { COMPOSITE_CUSTOM_DECLARATION_FILE, parseCustomSkillDeclaration, } from "./skill/index.js";
|
|
4
5
|
import { BuilderError } from "./errors.js";
|
|
5
6
|
/**
|
|
6
7
|
* 将规划产物中的 Action 列表适配为模板所需的 SkillActionItem 视图。
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ActionDependency, AssetDependency, PlaybookPlanEntry, SelectionPlan } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* stageSources 共享拷贝内核。
|
|
4
|
+
*
|
|
5
|
+
* build 与 pack 两个同名 stageSources 的拷贝循环(Action 入口、Playbook、
|
|
6
|
+
* modulesAndAssets)重叠约七成,差异仅在编译排除与目标路径细节;
|
|
7
|
+
* 本模块收敛为单一拷贝实现,各链路通过谓词与目标路径计算函数分化差异,
|
|
8
|
+
* 产物文件清单保持不变。
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* 共享拷贝内核选项:各链路仅通过谓词分化差异。
|
|
12
|
+
*/
|
|
13
|
+
export interface CopyPlanEntriesOptions {
|
|
14
|
+
/** Action 入口拷贝谓词(如 build 拷贝全部自有入口、pack 仅拷贝非 TypeScript 入口) */
|
|
15
|
+
copyAction?: (action: ActionDependency) => boolean;
|
|
16
|
+
/** modulesAndAssets 拷贝谓词(如 pack 跳过已编译的 TypeScript 模块) */
|
|
17
|
+
copyModule?: (dep: AssetDependency) => boolean;
|
|
18
|
+
/** Playbook 目标相对路径计算(build 收敛到 playbooksDir,pack 保留源工程相对路径) */
|
|
19
|
+
playbookRelPath?: (playbook: PlaybookPlanEntry) => string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* stageSources 共享拷贝内核:Action 入口、Playbook 规程、modulesAndAssets 三类条目的统一物化。
|
|
23
|
+
* 返回已拷贝 Action 入口的相对导入说明符清单(build 的入口生成使用,pack 忽略)。
|
|
24
|
+
*/
|
|
25
|
+
export declare function copyPlanEntries(stagingDir: string, plan: SelectionPlan, options?: CopyPlanEntriesOptions): string[];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join } from "node:path";
|
|
3
|
+
import { isOwnAction } from "./types.js";
|
|
4
|
+
/** 拷贝单个文件到目标相对路径,自动创建父目录 */
|
|
5
|
+
function copyPlanFile(stagingDir, srcPath, relPath) {
|
|
6
|
+
const destPath = join(stagingDir, relPath);
|
|
7
|
+
mkdirSync(dirname(destPath), { recursive: true });
|
|
8
|
+
copyFileSync(srcPath, destPath);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* stageSources 共享拷贝内核:Action 入口、Playbook 规程、modulesAndAssets 三类条目的统一物化。
|
|
12
|
+
* 返回已拷贝 Action 入口的相对导入说明符清单(build 的入口生成使用,pack 忽略)。
|
|
13
|
+
*/
|
|
14
|
+
export function copyPlanEntries(stagingDir, plan, options = {}) {
|
|
15
|
+
// 拷贝 Action 源码文件,保留相对路径(仅拷贝包自有 Action,跨包外部依赖不物化进本包目录)
|
|
16
|
+
const relativeActionImports = [];
|
|
17
|
+
for (const act of plan.actions) {
|
|
18
|
+
if (!isOwnAction(act)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (options.copyAction && !options.copyAction(act)) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (existsSync(act.resolvedPath)) {
|
|
25
|
+
copyPlanFile(stagingDir, act.resolvedPath, act.entry);
|
|
26
|
+
relativeActionImports.push(`./${act.entry.replace(/\\/g, "/")}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// 拷贝 Playbook 规程文件
|
|
30
|
+
if (plan.playbooks.length > 0) {
|
|
31
|
+
const defaultPlaybooksDir = plan.playbooksDir || "playbooks";
|
|
32
|
+
for (const pb of plan.playbooks) {
|
|
33
|
+
if (!existsSync(pb.filePath)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const relPath = options.playbookRelPath
|
|
37
|
+
? options.playbookRelPath(pb)
|
|
38
|
+
: join(defaultPlaybooksDir, basename(pb.filePath));
|
|
39
|
+
copyPlanFile(stagingDir, pb.filePath, relPath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// 拷贝声明的代码文件与静态资产
|
|
43
|
+
for (const dep of plan.dependencies.modulesAndAssets) {
|
|
44
|
+
if ((dep.type === "asset" || dep.type === "module" || dep.type === "file") &&
|
|
45
|
+
existsSync(dep.resolvedPath) &&
|
|
46
|
+
(!options.copyModule || options.copyModule(dep))) {
|
|
47
|
+
copyPlanFile(stagingDir, dep.resolvedPath, dep.path);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return relativeActionImports;
|
|
51
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ProjectConfig } from "@actiondock/core";
|
|
2
|
+
import type { ActionDockManifest } from "@actiondock/core/project";
|
|
2
3
|
/**
|
|
3
4
|
* 规划输入侧的项目配置扩展字段。
|
|
4
5
|
* actiondock.json 实际承载 uses、files、assets 等扩展声明,
|
|
@@ -37,6 +38,14 @@ export interface ActionDependency {
|
|
|
37
38
|
/** 扩展注解 */
|
|
38
39
|
annotations?: Record<string, unknown>;
|
|
39
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* 判定 Action 是否为当前包自有(非外部依赖包且 ID 不含跨包斜杠前缀)。
|
|
43
|
+
*
|
|
44
|
+
* 产物契约核心谓词:入口生成、清单序列化、源码物化、导出统计等全部链路
|
|
45
|
+
* 必须经由此单一事实源判定,避免外部标记与斜杠 ID 双条件在某处漏改一半
|
|
46
|
+
* 导致孤儿模块或清单漂移。
|
|
47
|
+
*/
|
|
48
|
+
export declare function isOwnAction(action: Pick<ActionDependency, "id" | "isExternal">): boolean;
|
|
40
49
|
/**
|
|
41
50
|
* 资产或模块依赖描述。
|
|
42
51
|
*/
|
|
@@ -196,20 +205,6 @@ export interface BuildOptions {
|
|
|
196
205
|
manifest?: ActionDockManifest;
|
|
197
206
|
/** 是否跳过本地相对依赖完整性校验(默认 false) */
|
|
198
207
|
skipDependencyValidation?: boolean;
|
|
199
|
-
/**
|
|
200
|
-
* 已移除的单文件二进制输出目标平台参数。
|
|
201
|
-
* 若传入将抛出 UNSUPPORTED_BUILD_MODE 错误。
|
|
202
|
-
*/
|
|
203
|
-
target?: string;
|
|
204
|
-
/**
|
|
205
|
-
* 已移除的字节码预编译参数。
|
|
206
|
-
* 若传入将抛出 UNSUPPORTED_BUILD_MODE 错误。
|
|
207
|
-
*/
|
|
208
|
-
bytecode?: boolean;
|
|
209
|
-
/**
|
|
210
|
-
* 代码混淆选项(历史遗留占位字段,目录型构建不再读取)。
|
|
211
|
-
*/
|
|
212
|
-
minify?: boolean;
|
|
213
208
|
}
|
|
214
209
|
/**
|
|
215
210
|
* 目录型构建产物结果描述。
|
|
@@ -326,15 +321,11 @@ export interface SkillExporterOptions {
|
|
|
326
321
|
customMdPath?: string;
|
|
327
322
|
/** 所属 Workspace 根目录(可选) */
|
|
328
323
|
workspaceRoot?: string;
|
|
329
|
-
/**
|
|
330
|
-
* 已废弃的独立单文件编译选项。
|
|
331
|
-
* 若传入将抛出替代方案提示或错误。
|
|
332
|
-
*/
|
|
333
|
-
standalone?: boolean;
|
|
334
|
-
target?: string;
|
|
335
|
-
bytecode?: boolean;
|
|
336
|
-
minify?: boolean;
|
|
337
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* 导出 Skill 选项契约(对齐标准接口命名)。
|
|
327
|
+
*/
|
|
328
|
+
export type ExportSkillOptions = SkillExporterOptions;
|
|
338
329
|
/**
|
|
339
330
|
* Skill 导出完成结果。
|
|
340
331
|
*/
|
|
@@ -362,6 +353,10 @@ export interface SkillExportResult {
|
|
|
362
353
|
/** 若复用了已有的 SKILL.md 文件,返回该文件的绝对路径 */
|
|
363
354
|
usedExistingSkillMd?: string;
|
|
364
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* 导出 Skill 结果契约(对齐标准接口命名)。
|
|
358
|
+
*/
|
|
359
|
+
export type ExportSkillResult = SkillExportResult;
|
|
365
360
|
/**
|
|
366
361
|
* 批量 Skill 导出选项。
|
|
367
362
|
*/
|
package/dist/types.js
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 判定 Action 是否为当前包自有(非外部依赖包且 ID 不含跨包斜杠前缀)。
|
|
3
|
+
*
|
|
4
|
+
* 产物契约核心谓词:入口生成、清单序列化、源码物化、导出统计等全部链路
|
|
5
|
+
* 必须经由此单一事实源判定,避免外部标记与斜杠 ID 双条件在某处漏改一半
|
|
6
|
+
* 导致孤儿模块或清单漂移。
|
|
7
|
+
*/
|
|
8
|
+
export function isOwnAction(action) {
|
|
9
|
+
return !action.isExternal && !action.id.includes("/");
|
|
10
|
+
}
|