@actiondock/builder 2.17.0 → 2.18.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 +1 -2
- package/dist/build.js +16 -3
- package/dist/export-composite.js +3 -1
- package/dist/export-source.js +15 -2
- package/dist/exporter.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/skill/custom-parser.d.ts +8 -2
- package/dist/skill/custom-parser.js +3 -1
- package/dist/skill/templates.d.ts +8 -2
- package/dist/skill/templates.js +91 -44
- package/dist/skill-md.d.ts +9 -3
- package/dist/skill-md.js +59 -11
- package/dist/types.d.ts +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -46,8 +46,7 @@ ActionDock 2.x 构建规划、目录交付与技能导出包。
|
|
|
46
46
|
- 显式外部依赖物化:支持 `bundleDeps` 选项。当显式开启且依赖闭包跨越外部已链接包时,自顶向下递归解析依赖链并将外部依赖包物理物化进产物根目录的 `packages/*` 子目录,展开为自包含的微型工作区产物结构;展开为复合形态时与过滤参数严格互斥(抛出 `FILTERS_UNSUPPORTED_FOR_COMPOSITE` 错误)。
|
|
47
47
|
- 独立自包含 Node 目录型导出:支持 `standalone` 选项(等价于 `mode: "node"`),生成免全局 `ad` 命令行工具的自包含目录,内置独立运行脚本与说明书,配合 `vendorDeps` 可实现生产依赖完全内置。
|
|
48
48
|
- 本地依赖完整性强校验:严格断言 Action 源码中的相对路径导入。若引用了未在 `actions` 且未在 `files` 字段中声明的本地模块,直接中断构建并抛出 `BuilderError`(错误码 `UNMET_LOCAL_DEPENDENCY`),彻底杜绝缺失依赖的产物分发。
|
|
49
|
-
-
|
|
50
|
-
- 复合套件导出与说明书定制:支持 `exportCompositeSkill` 函数将工作区内的多个包统一导出为复合工作区技能套件;支持通过 `customMdPath` 注入插槽定制模板,通过 `skillMdOnly` 实现就地仅原位刷新说明书。
|
|
49
|
+
- 说明书定制与复合套件导出:支持单包与复合套件通过 `customMdPath` 注入插槽定制模板(或放置 `SKILL.custom.md` 自动发现);支持 `exportCompositeSkill` 函数将工作区内的多个包统一导出为复合工作区技能套件;支持通过 `skillMdOnly` 实现就地仅原位刷新说明书。
|
|
51
50
|
- 压缩归档:支持 `archive` 选项将导出的技能目录打包为 `.zip` 或 `.tar.gz` 格式。
|
|
52
51
|
|
|
53
52
|
---
|
package/dist/build.js
CHANGED
|
@@ -12,7 +12,7 @@ import { generateNodeHostEntrySource, generateNodeSupervisorEntrySource } from "
|
|
|
12
12
|
import { vendorDependencies } from "./vendor.js";
|
|
13
13
|
import { generateStandaloneSkillMd } from "./skill/templates.js";
|
|
14
14
|
import { writeRuntimeReferenceFile } from "./export-source.js";
|
|
15
|
-
import { buildConfigForTemplates, writeSkillMd, } from "./skill-md.js";
|
|
15
|
+
import { buildConfigForTemplates, resolveCustomSkillDeclaration, writeSkillMd, } from "./skill-md.js";
|
|
16
16
|
import { createArchive, resolveArchiveFormat } from "./export-archive.js";
|
|
17
17
|
export { copyPlanEntries } from "./stage-sources.js";
|
|
18
18
|
/**
|
|
@@ -310,9 +310,22 @@ export async function exportNodeSkill(root, targetSkillDir, plan, options, pkgSl
|
|
|
310
310
|
allowInstallScripts: options.allowInstallScripts,
|
|
311
311
|
requireReproducible: options.requireReproducible,
|
|
312
312
|
});
|
|
313
|
-
const
|
|
313
|
+
const customDeclaration = resolveCustomSkillDeclaration({
|
|
314
|
+
projectRoot: root,
|
|
315
|
+
customMdPath: options.customMdPath,
|
|
316
|
+
workspaceRoot: options.workspaceRoot,
|
|
317
|
+
});
|
|
318
|
+
const usedExistingSkillMd = writeSkillMd(root, targetSkillDir, {
|
|
319
|
+
skipSkillMd: options.skipSkillMd,
|
|
320
|
+
skillMdPath: options.skillMdPath,
|
|
321
|
+
pkgSlug,
|
|
322
|
+
hasCustomDeclaration: Boolean(customDeclaration),
|
|
323
|
+
}, () => {
|
|
314
324
|
const configForTemplates = buildConfigForTemplates(plan, plan.actionsDir || "actions", plan.playbooksDir || "playbooks");
|
|
315
|
-
return generateStandaloneSkillMd(configForTemplates, plan.actions, plan.playbooks, "node ./entry.mjs"
|
|
325
|
+
return generateStandaloneSkillMd(configForTemplates, plan.actions, plan.playbooks, "node ./entry.mjs", {
|
|
326
|
+
customSections: customDeclaration?.sections,
|
|
327
|
+
description: customDeclaration?.description,
|
|
328
|
+
});
|
|
316
329
|
});
|
|
317
330
|
// 仅在使用自动模板时生成默认运行参考文件;Node 目录型使用自身入口,不要求全局安装 ad
|
|
318
331
|
if (usedExistingSkillMd === undefined && !options.skipSkillMd) {
|
package/dist/export-composite.js
CHANGED
|
@@ -114,7 +114,9 @@ export async function exportCompositeImpl(options, exportSubpackage) {
|
|
|
114
114
|
playbooks: playbookIds,
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
|
-
|
|
117
|
+
const shouldCheckExisting = !skillMdOnly &&
|
|
118
|
+
(Boolean(options.skillMdPath) || !customDeclaration);
|
|
119
|
+
existingSkillPath = shouldCheckExisting ? findExistingCompositeSkillMd(options) : undefined;
|
|
118
120
|
const description = options.description ||
|
|
119
121
|
customDeclaration?.description ||
|
|
120
122
|
`ActionDock 复合技能套件,聚合 ${packageInfos.map((p) => p.config.name).join("、")}`;
|
package/dist/export-source.js
CHANGED
|
@@ -8,7 +8,7 @@ import { getInternalDependencyVersion } from "./fs-utils.js";
|
|
|
8
8
|
import { assertValidManifestActionIds, sanitizeExportDependencies, serializePlanManifest, } from "./manifest.js";
|
|
9
9
|
import { copyPlanEntries } from "./stage-sources.js";
|
|
10
10
|
import { isOwnAction } from "./types.js";
|
|
11
|
-
import { buildConfigForTemplates, writeSkillMd, } from "./skill-md.js";
|
|
11
|
+
import { buildConfigForTemplates, resolveCustomSkillDeclaration, writeSkillMd, } from "./skill-md.js";
|
|
12
12
|
/**
|
|
13
13
|
* 源码型 Skill 导出装配层。
|
|
14
14
|
*
|
|
@@ -21,8 +21,21 @@ import { buildConfigForTemplates, writeSkillMd, } from "./skill-md.js";
|
|
|
21
21
|
export function stageSourceSkill(root, skillDir, plan, options, pkgSlug) {
|
|
22
22
|
const actionsDir = plan.actionsDir || "actions";
|
|
23
23
|
const playbooksDir = plan.playbooksDir || "playbooks";
|
|
24
|
+
const customDeclaration = resolveCustomSkillDeclaration({
|
|
25
|
+
projectRoot: root,
|
|
26
|
+
customMdPath: options.customMdPath,
|
|
27
|
+
workspaceRoot: options.workspaceRoot,
|
|
28
|
+
});
|
|
24
29
|
const configForTemplates = buildConfigForTemplates(plan, actionsDir, playbooksDir);
|
|
25
|
-
const usedExistingSkillMd = writeSkillMd(root, skillDir, {
|
|
30
|
+
const usedExistingSkillMd = writeSkillMd(root, skillDir, {
|
|
31
|
+
skipSkillMd: options.skipSkillMd,
|
|
32
|
+
skillMdPath: options.skillMdPath,
|
|
33
|
+
pkgSlug,
|
|
34
|
+
hasCustomDeclaration: Boolean(customDeclaration),
|
|
35
|
+
}, () => generateSourceSkillMd(configForTemplates, plan.actions.filter((a) => isOwnAction(a)), plan.playbooks, {
|
|
36
|
+
customSections: customDeclaration?.sections,
|
|
37
|
+
description: customDeclaration?.description,
|
|
38
|
+
}));
|
|
26
39
|
// 导出精简后的 actiondock.json 项目配置(项目元数据与清单的单一事实源)
|
|
27
40
|
const exportedConfig = serializePlanManifest(plan, {
|
|
28
41
|
omitEmptyConfig: true,
|
package/dist/exporter.js
CHANGED
|
@@ -24,6 +24,9 @@ export class SkillExporter {
|
|
|
24
24
|
* @returns 导出产物详细描述
|
|
25
25
|
*/
|
|
26
26
|
async export(options) {
|
|
27
|
+
if (options.skillMdPath && options.customMdPath) {
|
|
28
|
+
throw new BuilderError("Options 'skillMdPath' and 'customMdPath' cannot be used together. Specify 'skillMdPath' to reuse an existing static document, or 'customMdPath' to customize template generation with custom slots.", "INVALID_EXPORT_OPTIONS");
|
|
29
|
+
}
|
|
27
30
|
const root = resolve(options.projectRoot);
|
|
28
31
|
const mode = options.standalone === true || options.mode === "node" ? "node" : "source";
|
|
29
32
|
// 调用 SelectionPlanner 执行声明式构建规划
|
|
@@ -122,6 +125,9 @@ export class SkillExporter {
|
|
|
122
125
|
* 复合模式导出:将多个包聚合为一个统一的复合技能目录。
|
|
123
126
|
*/
|
|
124
127
|
async exportComposite(options) {
|
|
128
|
+
if (options.skillMdPath && options.customMdPath) {
|
|
129
|
+
throw new BuilderError("Options 'skillMdPath' and 'customMdPath' cannot be used together. Specify 'skillMdPath' to reuse an existing static document, or 'customMdPath' to customize template generation with custom slots.", "INVALID_EXPORT_OPTIONS");
|
|
130
|
+
}
|
|
125
131
|
return exportCompositeImpl(options, (opts) => this.export(opts));
|
|
126
132
|
}
|
|
127
133
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,4 +8,6 @@ export { packProject } from "./pack.js";
|
|
|
8
8
|
export { exportCompositeSkill, exportSkill, SkillExporter, } from "./exporter.js";
|
|
9
9
|
export { allocatePackageDirName } from "./manifest.js";
|
|
10
10
|
export { SelectionPlanner } from "./planner.js";
|
|
11
|
+
export { COMPOSITE_CUSTOM_DECLARATION_FILE, COMPOSITE_CUSTOM_SLOTS, SKILL_CUSTOM_DECLARATION_FILE, SKILL_CUSTOM_SLOTS, parseCustomSections, parseCustomSkillDeclaration, } from "./skill/index.js";
|
|
12
|
+
export type { CompositeCustomDeclaration, CompositeCustomSection, CompositeCustomSlot, SkillCustomDeclaration, SkillCustomSection, SkillCustomSlot, } from "./skill/index.js";
|
|
11
13
|
export type { ArchiveFormat, BuildOptions, BuildPlan, BuildProjectWithPlanOptions, BuildResult, CompositeSkillExportOptions, CompositeSkillExportResult, ExportSkillOptions, ExportSkillResult, PackOptions, PackResult, SelectionPlan, SelectionPlannerOptions, SkillExporterOptions, SkillExportResult, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -11,3 +11,5 @@ export { exportCompositeSkill, exportSkill, SkillExporter, } from "./exporter.js
|
|
|
11
11
|
export { allocatePackageDirName } from "./manifest.js";
|
|
12
12
|
// 构建规划器
|
|
13
13
|
export { SelectionPlanner } from "./planner.js";
|
|
14
|
+
// 技能说明书自定义契约与解析
|
|
15
|
+
export { COMPOSITE_CUSTOM_DECLARATION_FILE, COMPOSITE_CUSTOM_SLOTS, SKILL_CUSTOM_DECLARATION_FILE, SKILL_CUSTOM_SLOTS, parseCustomSections, parseCustomSkillDeclaration, } from "./skill/index.js";
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 自定义技能说明书(SKILL.custom.md)的槽位,
|
|
3
3
|
* 决定自定义段落插入到官方模板生成结果中的位置。
|
|
4
|
+
* 单包导出与复合套件导出共用同一套槽位体系。
|
|
4
5
|
*/
|
|
5
6
|
export type CompositeCustomSlot = "intro" | "after-init" | "after-describe" | "after-actions" | "after-playbooks" | "after-invoke" | "append";
|
|
7
|
+
export type SkillCustomSlot = CompositeCustomSlot;
|
|
6
8
|
export declare const COMPOSITE_CUSTOM_SLOTS: readonly CompositeCustomSlot[];
|
|
7
|
-
|
|
9
|
+
export declare const SKILL_CUSTOM_SLOTS: readonly CompositeCustomSlot[];
|
|
10
|
+
/** 约定俗成的自定义技能说明书文件名(单包与复合套件通用)。 */
|
|
8
11
|
export declare const COMPOSITE_CUSTOM_DECLARATION_FILE = "SKILL.custom.md";
|
|
12
|
+
export declare const SKILL_CUSTOM_DECLARATION_FILE = "SKILL.custom.md";
|
|
9
13
|
export interface CompositeCustomSection {
|
|
10
14
|
slot: CompositeCustomSlot;
|
|
11
15
|
content: string;
|
|
12
16
|
}
|
|
17
|
+
export type SkillCustomSection = CompositeCustomSection;
|
|
13
18
|
export interface CompositeCustomDeclaration {
|
|
14
19
|
/** 自定义说明书 frontmatter 中声明的 description 覆盖值 */
|
|
15
20
|
description?: string;
|
|
16
21
|
sections: CompositeCustomSection[];
|
|
17
22
|
}
|
|
23
|
+
export type SkillCustomDeclaration = CompositeCustomDeclaration;
|
|
18
24
|
export declare const CUSTOM_SLOT_MARKER_PATTERN: RegExp;
|
|
19
25
|
/**
|
|
20
26
|
* 解析自定义说明书正文:以 `<!-- actiondock:slot <name> -->` 标记行分段。
|
|
@@ -8,8 +8,10 @@ export const COMPOSITE_CUSTOM_SLOTS = [
|
|
|
8
8
|
"after-invoke",
|
|
9
9
|
"append",
|
|
10
10
|
];
|
|
11
|
-
|
|
11
|
+
export const SKILL_CUSTOM_SLOTS = COMPOSITE_CUSTOM_SLOTS;
|
|
12
|
+
/** 约定俗成的自定义技能说明书文件名(单包与复合套件通用)。 */
|
|
12
13
|
export const COMPOSITE_CUSTOM_DECLARATION_FILE = "SKILL.custom.md";
|
|
14
|
+
export const SKILL_CUSTOM_DECLARATION_FILE = COMPOSITE_CUSTOM_DECLARATION_FILE;
|
|
13
15
|
export const CUSTOM_SLOT_MARKER_PATTERN = /^\s*<!--\s*actiondock:slot\s+([a-zA-Z][a-zA-Z0-9-]*)\s*-->\s*$/;
|
|
14
16
|
/**
|
|
15
17
|
* 解析自定义说明书正文:以 `<!-- actiondock:slot <name> -->` 标记行分段。
|
|
@@ -33,8 +33,14 @@ export declare function renderRuntimeReferenceContent(options: {
|
|
|
33
33
|
}): string;
|
|
34
34
|
/** 运行时参考文件的导出目录内相对路径(单一事实源) */
|
|
35
35
|
export declare const RUNTIME_REFERENCE_REL_PATH = "references/actiondock-runtime.md";
|
|
36
|
-
export declare function generateSourceSkillMd(config: ProjectConfig, actions: SkillActionItem[], playbooks: SkillPlaybookItem[]
|
|
37
|
-
|
|
36
|
+
export declare function generateSourceSkillMd(config: ProjectConfig, actions: SkillActionItem[], playbooks: SkillPlaybookItem[], options?: {
|
|
37
|
+
customSections?: CompositeCustomSection[];
|
|
38
|
+
description?: string;
|
|
39
|
+
}): string;
|
|
40
|
+
export declare function generateStandaloneSkillMd(config: ProjectConfig, actions: SkillActionItem[], playbooks: SkillPlaybookItem[], binaryRelPath?: string, options?: {
|
|
41
|
+
customSections?: CompositeCustomSection[];
|
|
42
|
+
description?: string;
|
|
43
|
+
}): string;
|
|
38
44
|
export interface CompositeSkillPackageInfo {
|
|
39
45
|
config: ProjectConfig;
|
|
40
46
|
actions: Array<{
|
package/dist/skill/templates.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { basename } from "node:path";
|
|
2
|
-
function getCleanSkillMetadata(config) {
|
|
2
|
+
function getCleanSkillMetadata(config, descriptionOverride) {
|
|
3
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})`;
|
|
4
|
+
const desc = descriptionOverride || config.description || `AI Agent skill for ${config.name} (${config.id})`;
|
|
5
5
|
return { cleanName, desc };
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
@@ -202,52 +202,53 @@ function renderTroubleshootingSection(referenceRelPath) {
|
|
|
202
202
|
}
|
|
203
203
|
/** 运行时参考文件的导出目录内相对路径(单一事实源) */
|
|
204
204
|
export const RUNTIME_REFERENCE_REL_PATH = "references/actiondock-runtime.md";
|
|
205
|
-
export function generateSourceSkillMd(config, actions, playbooks) {
|
|
206
|
-
const { cleanName, desc } = getCleanSkillMetadata(config);
|
|
205
|
+
export function generateSourceSkillMd(config, actions, playbooks, options) {
|
|
206
|
+
const { cleanName, desc } = getCleanSkillMetadata(config, options?.description);
|
|
207
207
|
const pkgId = config.id;
|
|
208
208
|
const firstAction = actions[0]?.id || "sample.greet";
|
|
209
209
|
const playbookSection = renderPlaybookSectionMarkdown(playbooks, config.playbooksDir || "playbooks");
|
|
210
210
|
const actionListMd = renderActionListMarkdown(actions, { packageId: pkgId });
|
|
211
|
-
|
|
211
|
+
const sIntro = `---
|
|
212
212
|
name: ${cleanName}
|
|
213
213
|
description: ${desc}
|
|
214
214
|
---
|
|
215
215
|
|
|
216
216
|
# ${config.name} (${config.id})
|
|
217
217
|
|
|
218
|
-
${desc}
|
|
219
|
-
|
|
220
|
-
## ActionDock 运行时
|
|
218
|
+
${desc}`;
|
|
219
|
+
const sInit = `## ActionDock 运行时
|
|
221
220
|
|
|
222
|
-
本技能为
|
|
221
|
+
本技能为 ActionDock 源码型技能包。智能体可直接通过宿主环境中已安装的 ActionDock 命令行工具 \`ad\` 执行其中的 Action。
|
|
223
222
|
|
|
224
|
-
###
|
|
223
|
+
### 安装依赖与注册链接
|
|
225
224
|
|
|
226
|
-
|
|
225
|
+
本技能面向全局挂载使用。在初次调用或初始化时,将包含本 \`SKILL.md\` 的目录解析为 \`<skill_root>\`。标准流程为先安装生产依赖,再执行注册链接,之后可在任意工作目录通过完全限定 ID 全局调用:
|
|
227
226
|
|
|
228
227
|
\`\`\`bash
|
|
228
|
+
# 安装生产依赖
|
|
229
|
+
cd "<skill_root>" && npm install --omit=dev
|
|
230
|
+
|
|
231
|
+
# 注册并链接到 ActionDock
|
|
229
232
|
ad link "<skill_root>"
|
|
230
233
|
\`\`\`
|
|
231
234
|
|
|
232
|
-
> \`ad link\` 天然具备幂等性,同一 Package
|
|
233
|
-
|
|
234
|
-
### 动作参数契约按需调阅
|
|
235
|
+
> \`ad link\` 天然具备幂等性,同一 Package 多次执行会直接更新路径,可安全重复调用。若后续依赖发生变更,可重新执行上述安装依赖与链接命令更新环境。`;
|
|
236
|
+
const sDescribe = `### 动作参数契约按需调阅
|
|
235
237
|
|
|
236
238
|
在调用未知参数的 Action 前,可在终端执行命令查阅该 Action 的输入输出模式与详细说明:
|
|
237
239
|
|
|
238
240
|
\`\`\`bash
|
|
239
241
|
ad describe ${pkgId}/${firstAction}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
### 执行 Action
|
|
242
|
+
\`\`\``;
|
|
243
|
+
const sInvoke = `### 执行 Action
|
|
243
244
|
|
|
244
245
|
为避免多技能之间的 Action ID 命名冲突,建议统一使用带有 Package 前缀的完全限定 ID。
|
|
245
246
|
|
|
246
247
|
${renderInvocationGuidance(`ad describe ${pkgId}/${firstAction}`, `ad run ${pkgId}/${firstAction}`)}
|
|
247
248
|
|
|
248
|
-
${renderJsonEnvelopeSection("envelope")}
|
|
249
|
-
|
|
250
|
-
|
|
249
|
+
${renderJsonEnvelopeSection("envelope")}`;
|
|
250
|
+
const sPlaybooks = playbookSection.trim();
|
|
251
|
+
const sActions = `---
|
|
251
252
|
|
|
252
253
|
## Action 目录
|
|
253
254
|
|
|
@@ -267,41 +268,54 @@ ad config set KEY VALUE --package ${pkgId}
|
|
|
267
268
|
# 查看与检索状态数据
|
|
268
269
|
ad state list --package ${pkgId}
|
|
269
270
|
ad state get KEY --package ${pkgId}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
\`\`\``;
|
|
272
|
+
const sTroubleshooting = renderTroubleshootingSection(RUNTIME_REFERENCE_REL_PATH);
|
|
273
|
+
const parts = [
|
|
274
|
+
{ slot: "intro", text: sIntro },
|
|
275
|
+
{ slot: "after-init", text: sInit },
|
|
276
|
+
{ slot: "after-describe", text: sDescribe },
|
|
277
|
+
{ slot: "after-invoke", text: sInvoke },
|
|
278
|
+
{ slot: "after-playbooks", text: sPlaybooks },
|
|
279
|
+
{ slot: "after-actions", text: sActions },
|
|
280
|
+
{ slot: "append", text: sTroubleshooting },
|
|
281
|
+
];
|
|
282
|
+
const customSections = options?.customSections ?? [];
|
|
283
|
+
for (const section of [...customSections].reverse()) {
|
|
284
|
+
const anchorIndex = parts.findIndex((p) => p.slot === section.slot);
|
|
285
|
+
parts.splice(anchorIndex + 1, 0, { slot: section.slot, text: section.content });
|
|
286
|
+
}
|
|
287
|
+
return (parts
|
|
288
|
+
.filter((p) => p.text.trim().length > 0)
|
|
289
|
+
.map((p) => p.text.trim())
|
|
290
|
+
.join("\n\n") + "\n");
|
|
274
291
|
}
|
|
275
|
-
export function generateStandaloneSkillMd(config, actions, playbooks, binaryRelPath = "./bin/action-bin") {
|
|
276
|
-
const { cleanName, desc } = getCleanSkillMetadata(config);
|
|
292
|
+
export function generateStandaloneSkillMd(config, actions, playbooks, binaryRelPath = "./bin/action-bin", options) {
|
|
293
|
+
const { cleanName, desc } = getCleanSkillMetadata(config, options?.description);
|
|
277
294
|
const firstAction = actions[0]?.id || "sample.greet";
|
|
278
295
|
const playbookSection = renderPlaybookSectionMarkdown(playbooks, config.playbooksDir || "playbooks");
|
|
279
296
|
const actionListMd = renderActionListMarkdown(actions);
|
|
280
|
-
|
|
297
|
+
const sIntro = `---
|
|
281
298
|
name: ${cleanName}
|
|
282
299
|
description: ${desc}
|
|
283
300
|
---
|
|
284
301
|
|
|
285
302
|
# ${config.name} (${config.id})
|
|
286
303
|
|
|
287
|
-
${desc}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
### 动作参数契约按需调阅
|
|
304
|
+
${desc}`;
|
|
305
|
+
const sDescribe = `### 动作参数契约按需调阅
|
|
291
306
|
|
|
292
307
|
在调用未知参数的 Action 前,可在终端执行命令查阅该 Action 的输入输出模式与详细说明:
|
|
293
308
|
|
|
294
309
|
\`\`\`bash
|
|
295
310
|
${binaryRelPath} describe ${firstAction}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
### 执行 Action
|
|
311
|
+
\`\`\``;
|
|
312
|
+
const sInvoke = `### 执行 Action
|
|
299
313
|
|
|
300
314
|
${renderInvocationGuidance(`${binaryRelPath} describe ${firstAction}`, `${binaryRelPath} run ${firstAction}`)}
|
|
301
315
|
|
|
302
|
-
${renderJsonEnvelopeSection("result")}
|
|
303
|
-
|
|
304
|
-
|
|
316
|
+
${renderJsonEnvelopeSection("result")}`;
|
|
317
|
+
const sPlaybooks = playbookSection.trim();
|
|
318
|
+
const sActions = `---
|
|
305
319
|
|
|
306
320
|
## Action 目录
|
|
307
321
|
|
|
@@ -321,9 +335,8 @@ ${binaryRelPath} config set KEY VALUE
|
|
|
321
335
|
# 查看与检索状态数据
|
|
322
336
|
${binaryRelPath} state list
|
|
323
337
|
${binaryRelPath} state get KEY
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
---
|
|
338
|
+
\`\`\``;
|
|
339
|
+
const sTroubleshooting = `---
|
|
327
340
|
|
|
328
341
|
## 故障排查与依赖自愈指引(按需查阅)
|
|
329
342
|
|
|
@@ -334,8 +347,25 @@ ${binaryRelPath} state get KEY
|
|
|
334
347
|
npm install --omit=dev
|
|
335
348
|
\`\`\`
|
|
336
349
|
|
|
337
|
-
完整环境安装与自愈指引按需查阅:[${RUNTIME_REFERENCE_REL_PATH}](${RUNTIME_REFERENCE_REL_PATH})
|
|
338
|
-
|
|
350
|
+
完整环境安装与自愈指引按需查阅:[${RUNTIME_REFERENCE_REL_PATH}](${RUNTIME_REFERENCE_REL_PATH})`;
|
|
351
|
+
const parts = [
|
|
352
|
+
{ slot: "intro", text: sIntro },
|
|
353
|
+
{ slot: "after-init", text: "" },
|
|
354
|
+
{ slot: "after-describe", text: sDescribe },
|
|
355
|
+
{ slot: "after-invoke", text: sInvoke },
|
|
356
|
+
{ slot: "after-playbooks", text: sPlaybooks },
|
|
357
|
+
{ slot: "after-actions", text: sActions },
|
|
358
|
+
{ slot: "append", text: sTroubleshooting },
|
|
359
|
+
];
|
|
360
|
+
const customSections = options?.customSections ?? [];
|
|
361
|
+
for (const section of [...customSections].reverse()) {
|
|
362
|
+
const anchorIndex = parts.findIndex((p) => p.slot === section.slot);
|
|
363
|
+
parts.splice(anchorIndex + 1, 0, { slot: section.slot, text: section.content });
|
|
364
|
+
}
|
|
365
|
+
return (parts
|
|
366
|
+
.filter((p) => p.text.trim().length > 0)
|
|
367
|
+
.map((p) => p.text.trim())
|
|
368
|
+
.join("\n\n") + "\n");
|
|
339
369
|
}
|
|
340
370
|
/**
|
|
341
371
|
* 生成多包聚合的复合模式 SKILL.md 文档。
|
|
@@ -375,6 +405,23 @@ description: ${description}
|
|
|
375
405
|
# ${bundleName} 复合技能套件
|
|
376
406
|
|
|
377
407
|
${description}`;
|
|
408
|
+
const sInit = `## ActionDock 运行时
|
|
409
|
+
|
|
410
|
+
本技能为 ActionDock 复合技能套件,聚合了多个功能包。智能体可直接通过宿主环境中已安装的 ActionDock 命令行工具 \`ad\` 执行其中的 Action。
|
|
411
|
+
|
|
412
|
+
### 安装依赖与注册链接
|
|
413
|
+
|
|
414
|
+
本技能面向全局挂载使用。在初次调用或初始化时,将包含本 \`SKILL.md\` 的目录解析为 \`<skill_root>\`。标准流程为先安装复合套件聚合生产依赖,再执行注册链接,之后可在任意工作目录通过完全限定 ID 全局调用:
|
|
415
|
+
|
|
416
|
+
\`\`\`bash
|
|
417
|
+
# 安装复合套件聚合依赖
|
|
418
|
+
cd "<skill_root>" && npm install --omit=dev
|
|
419
|
+
|
|
420
|
+
# 注册并链接工作区子包到 ActionDock
|
|
421
|
+
ad link "<skill_root>"
|
|
422
|
+
\`\`\`
|
|
423
|
+
|
|
424
|
+
> \`ad link\` 会自动识别并注册工作区下的所有子包,使其中的 Action 随时可以通过完全限定标识调用。\`ad link\` 天然具备幂等性,可安全重复调用。若后续依赖发生变更,可重新执行上述安装依赖与链接命令更新环境。`;
|
|
378
425
|
const sDescribe = `## 动作参数契约按需调阅
|
|
379
426
|
|
|
380
427
|
为节省上下文开销,各 Action 的详细参数结构不静态内嵌在说明书中。在调用未知参数的 Action 前,可在终端执行命令查阅输入输出约束:
|
|
@@ -404,12 +451,12 @@ ${renderJsonEnvelopeSection("envelope", { withDescriptions: false })}`;
|
|
|
404
451
|
const sTroubleshooting = renderTroubleshootingSection(RUNTIME_REFERENCE_REL_PATH);
|
|
405
452
|
const parts = [
|
|
406
453
|
{ slot: "intro", text: sIntro },
|
|
454
|
+
{ slot: "after-init", text: sInit },
|
|
407
455
|
{ slot: "after-describe", text: sDescribe },
|
|
408
456
|
{ slot: "after-actions", text: sActions },
|
|
409
457
|
{ slot: "after-playbooks", text: sPlaybooks },
|
|
410
458
|
{ slot: "after-invoke", text: sInvoke },
|
|
411
|
-
{ slot: "
|
|
412
|
-
{ slot: "append", text: "" },
|
|
459
|
+
{ slot: "append", text: sTroubleshooting },
|
|
413
460
|
];
|
|
414
461
|
// 自定义段落按文件顺序插入到对应槽位(倒序插入保证同槽位多段保持先后)
|
|
415
462
|
const customSections = options?.customSections ?? [];
|
package/dist/skill-md.d.ts
CHANGED
|
@@ -16,10 +16,15 @@ export declare function findExistingSingleSkillMd(projectRoot: string, explicitP
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function findExistingCompositeSkillMd(options: CompositeSkillExportOptions): string | undefined;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* 解析技能自定义说明书:显式 customMdPath 优先(缺失即报错),
|
|
20
|
+
* 否则单包导出按项目根目录,复合导出按工作区根目录与当前目录自动发现 `SKILL.custom.md`。
|
|
21
21
|
*/
|
|
22
|
-
export declare function resolveCustomSkillDeclaration(options:
|
|
22
|
+
export declare function resolveCustomSkillDeclaration(options: {
|
|
23
|
+
projectRoot?: string;
|
|
24
|
+
customMdPath?: string;
|
|
25
|
+
workspaceRoot?: string;
|
|
26
|
+
projectRoots?: string[];
|
|
27
|
+
}): (CompositeCustomDeclaration & {
|
|
23
28
|
file: string;
|
|
24
29
|
}) | undefined;
|
|
25
30
|
/**
|
|
@@ -30,6 +35,7 @@ export declare function writeSkillMd(root: string, destDir: string, options: {
|
|
|
30
35
|
skipSkillMd?: boolean;
|
|
31
36
|
skillMdPath?: string;
|
|
32
37
|
pkgSlug: string;
|
|
38
|
+
hasCustomDeclaration?: boolean;
|
|
33
39
|
}, generate: () => string): string | undefined;
|
|
34
40
|
/**
|
|
35
41
|
* 构造模板生成所需的 ProjectConfig 视图。
|
package/dist/skill-md.js
CHANGED
|
@@ -13,7 +13,10 @@ import { BuilderError } from "./errors.js";
|
|
|
13
13
|
* 检索单个 Action 项目目录中已存在的 SKILL.md 文件。
|
|
14
14
|
*/
|
|
15
15
|
export function findExistingSingleSkillMd(projectRoot, explicitPath, pkgSlug) {
|
|
16
|
-
if (explicitPath
|
|
16
|
+
if (explicitPath) {
|
|
17
|
+
if (!existsSync(explicitPath)) {
|
|
18
|
+
throw new BuilderError(`Skill document file not found: '${explicitPath}'`);
|
|
19
|
+
}
|
|
17
20
|
try {
|
|
18
21
|
if (statSync(explicitPath).isFile())
|
|
19
22
|
return resolve(explicitPath);
|
|
@@ -21,6 +24,7 @@ export function findExistingSingleSkillMd(projectRoot, explicitPath, pkgSlug) {
|
|
|
21
24
|
catch {
|
|
22
25
|
// 忽略文件属性读取异常
|
|
23
26
|
}
|
|
27
|
+
throw new BuilderError(`Skill document path is not a regular file: '${explicitPath}'`);
|
|
24
28
|
}
|
|
25
29
|
const candidates = [
|
|
26
30
|
join(projectRoot, "SKILL.md"),
|
|
@@ -48,7 +52,10 @@ export function findExistingSingleSkillMd(projectRoot, explicitPath, pkgSlug) {
|
|
|
48
52
|
* 检索复合套件工作区中已存在的 SKILL.md 文件。
|
|
49
53
|
*/
|
|
50
54
|
export function findExistingCompositeSkillMd(options) {
|
|
51
|
-
if (options.skillMdPath
|
|
55
|
+
if (options.skillMdPath) {
|
|
56
|
+
if (!existsSync(options.skillMdPath)) {
|
|
57
|
+
throw new BuilderError(`Skill document file not found: '${options.skillMdPath}'`);
|
|
58
|
+
}
|
|
52
59
|
try {
|
|
53
60
|
if (statSync(options.skillMdPath).isFile())
|
|
54
61
|
return resolve(options.skillMdPath);
|
|
@@ -56,6 +63,7 @@ export function findExistingCompositeSkillMd(options) {
|
|
|
56
63
|
catch {
|
|
57
64
|
// 忽略文件属性读取异常
|
|
58
65
|
}
|
|
66
|
+
throw new BuilderError(`Skill document path is not a regular file: '${options.skillMdPath}'`);
|
|
59
67
|
}
|
|
60
68
|
const bundleSlug = getPackageSlug(options.bundleName);
|
|
61
69
|
const searchDirs = new Set();
|
|
@@ -95,8 +103,8 @@ export function findExistingCompositeSkillMd(options) {
|
|
|
95
103
|
return undefined;
|
|
96
104
|
}
|
|
97
105
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
106
|
+
* 解析技能自定义说明书:显式 customMdPath 优先(缺失即报错),
|
|
107
|
+
* 否则单包导出按项目根目录,复合导出按工作区根目录与当前目录自动发现 `SKILL.custom.md`。
|
|
100
108
|
*/
|
|
101
109
|
export function resolveCustomSkillDeclaration(options) {
|
|
102
110
|
let filePath;
|
|
@@ -106,14 +114,52 @@ export function resolveCustomSkillDeclaration(options) {
|
|
|
106
114
|
}
|
|
107
115
|
filePath = resolve(options.customMdPath);
|
|
108
116
|
}
|
|
117
|
+
else if (options.projectRoot) {
|
|
118
|
+
const root = resolve(options.projectRoot);
|
|
119
|
+
const candidates = [
|
|
120
|
+
join(root, COMPOSITE_CUSTOM_DECLARATION_FILE),
|
|
121
|
+
join(root, "skill.custom.md"),
|
|
122
|
+
join(root, "skills", COMPOSITE_CUSTOM_DECLARATION_FILE),
|
|
123
|
+
join(root, "skills", "skill.custom.md"),
|
|
124
|
+
];
|
|
125
|
+
for (const candidate of candidates) {
|
|
126
|
+
if (existsSync(candidate)) {
|
|
127
|
+
try {
|
|
128
|
+
if (statSync(candidate).isFile()) {
|
|
129
|
+
filePath = candidate;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// 忽略文件属性读取异常
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
109
139
|
else {
|
|
110
140
|
const searchDirs = [options.workspaceRoot, process.cwd()].filter(Boolean);
|
|
111
141
|
for (const dir of searchDirs) {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
142
|
+
const candidates = [
|
|
143
|
+
join(resolve(dir), COMPOSITE_CUSTOM_DECLARATION_FILE),
|
|
144
|
+
join(resolve(dir), "skill.custom.md"),
|
|
145
|
+
join(resolve(dir), "skills", COMPOSITE_CUSTOM_DECLARATION_FILE),
|
|
146
|
+
join(resolve(dir), "skills", "skill.custom.md"),
|
|
147
|
+
];
|
|
148
|
+
for (const candidate of candidates) {
|
|
149
|
+
if (existsSync(candidate)) {
|
|
150
|
+
try {
|
|
151
|
+
if (statSync(candidate).isFile()) {
|
|
152
|
+
filePath = candidate;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// 忽略文件属性读取异常
|
|
158
|
+
}
|
|
159
|
+
}
|
|
116
160
|
}
|
|
161
|
+
if (filePath)
|
|
162
|
+
break;
|
|
117
163
|
}
|
|
118
164
|
}
|
|
119
165
|
if (!filePath) {
|
|
@@ -129,9 +175,11 @@ export function resolveCustomSkillDeclaration(options) {
|
|
|
129
175
|
* 返回实际复用的已有 SKILL.md 路径(若发生复用)。
|
|
130
176
|
*/
|
|
131
177
|
export function writeSkillMd(root, destDir, options, generate) {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
178
|
+
const shouldCheckExisting = !options.skipSkillMd &&
|
|
179
|
+
(Boolean(options.skillMdPath) || !options.hasCustomDeclaration);
|
|
180
|
+
const existingSkill = shouldCheckExisting
|
|
181
|
+
? findExistingSingleSkillMd(root, options.skillMdPath, options.pkgSlug)
|
|
182
|
+
: undefined;
|
|
135
183
|
if (existingSkill) {
|
|
136
184
|
const destSkillMd = join(destDir, "SKILL.md");
|
|
137
185
|
if (resolve(existingSkill) !== resolve(destSkillMd)) {
|
package/dist/types.d.ts
CHANGED
|
@@ -340,7 +340,7 @@ export interface SkillExporterOptions {
|
|
|
340
340
|
skipDependencyValidation?: boolean;
|
|
341
341
|
/** 内部标识:是否作为复合套件子包导出(避免闭包再次触发嵌套 mini-workspace) */
|
|
342
342
|
_isSubpackage?: boolean;
|
|
343
|
-
/**
|
|
343
|
+
/** 自定义技能说明书(SKILL.custom.md)文件路径;缺省时自动在项目或工作区根目录下发现同名文件 */
|
|
344
344
|
customMdPath?: string;
|
|
345
345
|
/** 所属 Workspace 根目录(可选) */
|
|
346
346
|
workspaceRoot?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actiondock/builder",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "ActionDock Build Planner, distribution packaging, and Skill exporter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"test": "node ../../scripts/run-tests.ts"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@actiondock/core": "^2.
|
|
33
|
-
"@actiondock/sdk": "^2.
|
|
32
|
+
"@actiondock/core": "^2.18.0",
|
|
33
|
+
"@actiondock/sdk": "^2.18.0"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"actiondock",
|