@actiondock/builder 2.12.0 → 2.14.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/dist/derived-graph.d.ts +4 -0
- package/dist/derived-graph.js +30 -0
- package/dist/entry-generators.d.ts +9 -2
- package/dist/entry-generators.js +46 -25
- package/dist/export-composite.d.ts +1 -1
- package/dist/export-composite.js +125 -51
- package/dist/export-source.js +32 -7
- package/dist/exporter.js +33 -3
- package/dist/planner.js +74 -78
- package/dist/skill/templates.d.ts +5 -3
- package/dist/skill/templates.js +101 -68
- package/dist/skill-md.d.ts +8 -0
- package/dist/skill-md.js +46 -0
- package/dist/source-graph.d.ts +4 -0
- package/dist/source-graph.js +33 -0
- package/dist/types.d.ts +9 -0
- package/package.json +3 -3
package/dist/planner.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, statSync } from "node:fs";
|
|
2
2
|
import { basename, join, relative, resolve } from "node:path";
|
|
3
|
-
import { ActionDockError, ACTION_NOT_FOUND,
|
|
3
|
+
import { ActionDockError, ACTION_NOT_FOUND, loadProjectConfig, } from "@actiondock/core";
|
|
4
4
|
import { assertPathWithinRoot, traverseDirectory, loadManifest, loadPlaybooks, validateManifest, } from "@actiondock/core/project";
|
|
5
5
|
import { DefaultActionCatalog, PackageGraphBuilder, resolveAction, } from "@actiondock/core/graph";
|
|
6
6
|
import { PlannerError } from "./errors.js";
|
|
@@ -150,13 +150,16 @@ export class SelectionPlanner {
|
|
|
150
150
|
selectedPlaybooks = Array.from(playbooksMap.values());
|
|
151
151
|
}
|
|
152
152
|
const manifestActions = manifest.actions || {};
|
|
153
|
-
// 若显式指定了 Action
|
|
153
|
+
// 若显式指定了 Action 列表,加入集合(保持本包短名与完全限定名解析契约)
|
|
154
154
|
if (options?.actions && options.actions.length > 0) {
|
|
155
155
|
for (const actId of options.actions) {
|
|
156
|
-
|
|
156
|
+
const localId = actId.startsWith(`${config.id}/`)
|
|
157
|
+
? actId.slice(config.id.length + 1)
|
|
158
|
+
: actId;
|
|
159
|
+
if (!manifestActions[localId] && !manifestActions[actId]) {
|
|
157
160
|
throw new PlannerError(`Action '${actId}' specified in build options was not found in manifest`, "ACTION_NOT_FOUND");
|
|
158
161
|
}
|
|
159
|
-
initialActionIds.add(actId);
|
|
162
|
+
initialActionIds.add(manifestActions[localId] ? localId : actId);
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
// 若均未显式指定,默认包含清单中的全部 Action
|
|
@@ -165,95 +168,88 @@ export class SelectionPlanner {
|
|
|
165
168
|
initialActionIds.add(actId);
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
|
-
// 当前包在 actiondock.json 中声明的顶层 uses 直接依赖
|
|
169
|
-
const currentPkgUses = config?.uses;
|
|
170
|
-
if (Array.isArray(currentPkgUses)) {
|
|
171
|
-
for (const depId of currentPkgUses) {
|
|
172
|
-
if (typeof depId === "string" && depId.trim()) {
|
|
173
|
-
initialActionIds.add(depId.trim());
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
171
|
return { initialActionIds, selectedPlaybooks };
|
|
178
172
|
}
|
|
179
173
|
/**
|
|
180
174
|
* 进行依赖闭包(uses)解析计算,自动处理环形依赖与传递依赖(支持当前清单与已链接外部包)。
|
|
181
175
|
*/
|
|
182
|
-
resolveClosure(root, manifest, config, initialActionIds) {
|
|
176
|
+
resolveClosure(root, manifest, config, initialActionIds, packageGraph) {
|
|
183
177
|
const resolvedActionIds = new Set();
|
|
184
|
-
// queued 与 resolvedActionIds 联合判重,避免高入度节点在 uses 图中被重复入队导致 O(边数) 重复解析
|
|
185
|
-
const queued = new Set(initialActionIds);
|
|
186
|
-
const queue = Array.from(initialActionIds);
|
|
187
178
|
const externalActionRoots = new Map();
|
|
188
179
|
const externalActionEntries = new Map();
|
|
189
|
-
const
|
|
190
|
-
const graph = new PackageGraphBuilder({ root, allowDevLinks: true }).buildSync();
|
|
180
|
+
const graph = packageGraph ?? new PackageGraphBuilder({ root, manifest, allowDevLinks: true }).buildSync();
|
|
191
181
|
const catalog = new DefaultActionCatalog(graph);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
182
|
+
const queue = [];
|
|
183
|
+
const visitedPackages = new Set();
|
|
184
|
+
const expandedPackages = new Set();
|
|
185
|
+
for (const id of initialActionIds) {
|
|
186
|
+
queue.push({ id, caller: config.id, isInitialAction: true });
|
|
187
|
+
}
|
|
188
|
+
const rawRootUses = manifest.uses ?? config.uses ?? [];
|
|
189
|
+
visitedPackages.add(config.id);
|
|
190
|
+
for (const use of rawRootUses) {
|
|
191
|
+
if (typeof use === "string" && use.trim()) {
|
|
192
|
+
queue.push({ id: use.trim(), caller: config.id, isInitialAction: false });
|
|
197
193
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
extConfig?.actions?.[resolvedActionId];
|
|
221
|
-
if (!externalEntry) {
|
|
222
|
-
throw new ActionDockError(UNDECLARED_ACTION_DEPENDENCY, `UNDECLARED_ACTION_DEPENDENCY: Action '${resolvedActionId}' is not declared in package '${resolvedPkgId}' manifest`);
|
|
223
|
-
}
|
|
224
|
-
entry = externalEntry;
|
|
225
|
-
entryRoot = extRoot;
|
|
226
|
-
// 依赖包 actiondock.json 中声明的传递依赖闭包(入队前查重,避免重复膨胀)
|
|
227
|
-
const extPkgUses = extConfig?.uses;
|
|
228
|
-
if (Array.isArray(extPkgUses)) {
|
|
229
|
-
for (const u of extPkgUses) {
|
|
230
|
-
const trimmedUse = typeof u === "string" ? u.trim() : "";
|
|
231
|
-
if (trimmedUse &&
|
|
232
|
-
!resolvedActionIds.has(trimmedUse) &&
|
|
233
|
-
!queued.has(trimmedUse)) {
|
|
234
|
-
queued.add(trimmedUse);
|
|
235
|
-
queue.push(trimmedUse);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
194
|
+
}
|
|
195
|
+
while (queue.length > 0) {
|
|
196
|
+
const { id, caller, isInitialAction } = queue.shift();
|
|
197
|
+
// uses 支持包名与包级通配符;将其展开为该包的完整动作集合。
|
|
198
|
+
// 明确选中的初始动作不按包名展开;uses 中的裸包名和通配符仍按包级引用处理。
|
|
199
|
+
const isWildcard = id.endsWith("/*");
|
|
200
|
+
const packageId = isWildcard
|
|
201
|
+
? id.slice(0, -2)
|
|
202
|
+
: !isInitialAction && graph.hasPackage(id)
|
|
203
|
+
? id
|
|
204
|
+
: undefined;
|
|
205
|
+
if (packageId) {
|
|
206
|
+
const node = graph.getPackage(packageId);
|
|
207
|
+
if (!node)
|
|
208
|
+
throw new PlannerError(`Package '${packageId}' referenced by uses was not found`, "PACKAGE_NOT_FOUND");
|
|
209
|
+
if (expandedPackages.has(packageId))
|
|
210
|
+
continue;
|
|
211
|
+
expandedPackages.add(packageId);
|
|
212
|
+
if (!visitedPackages.has(packageId)) {
|
|
213
|
+
visitedPackages.add(packageId);
|
|
214
|
+
for (const use of node.manifest.uses || []) {
|
|
215
|
+
queue.push({ id: use, caller: packageId, isInitialAction: false });
|
|
238
216
|
}
|
|
239
217
|
}
|
|
218
|
+
for (const actionId of Object.keys(node.manifest.actions || {})) {
|
|
219
|
+
queue.push({ id: `${packageId}/${actionId}`, caller: packageId, isInitialAction: false });
|
|
220
|
+
}
|
|
221
|
+
continue;
|
|
240
222
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
223
|
+
// 保持显式 config/manifest 的单包规划语义,不让磁盘图覆盖调用方清单。
|
|
224
|
+
const localId = id.startsWith(`${config.id}/`) ? id.slice(config.id.length + 1) : id;
|
|
225
|
+
const isLocal = (caller === config.id || id.startsWith(`${config.id}/`)) &&
|
|
226
|
+
Boolean(manifest.actions?.[localId] || config.actions?.[localId]);
|
|
227
|
+
const resolved = isLocal ? undefined : resolveAction(id, { graph, catalog, caller });
|
|
228
|
+
const pkgId = resolved?.package.id || config.id;
|
|
229
|
+
const actionId = resolved?.ref.actionId || localId;
|
|
230
|
+
const node = graph.getPackage(pkgId);
|
|
231
|
+
const canonicalId = pkgId === config.id ? actionId : `${pkgId}/${actionId}`;
|
|
232
|
+
if (resolvedActionIds.has(canonicalId))
|
|
233
|
+
continue;
|
|
234
|
+
const entry = pkgId === config.id
|
|
235
|
+
? manifest.actions?.[actionId] || config.actions?.[actionId]
|
|
236
|
+
: node.manifest.actions?.[actionId];
|
|
237
|
+
if (!entry)
|
|
238
|
+
throw new ActionDockError(ACTION_NOT_FOUND, `Action '${id}' is not declared in manifest`);
|
|
239
|
+
resolvedActionIds.add(canonicalId);
|
|
240
|
+
if (pkgId !== config.id) {
|
|
241
|
+
externalActionRoots.set(canonicalId, node.root);
|
|
242
|
+
externalActionEntries.set(canonicalId, entry);
|
|
247
243
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
for (const
|
|
251
|
-
|
|
252
|
-
queued.add(depId);
|
|
253
|
-
queue.push(depId);
|
|
254
|
-
}
|
|
244
|
+
if (!visitedPackages.has(pkgId)) {
|
|
245
|
+
visitedPackages.add(pkgId);
|
|
246
|
+
for (const use of node?.manifest.uses || []) {
|
|
247
|
+
queue.push({ id: use, caller: pkgId, isInitialAction: false });
|
|
255
248
|
}
|
|
256
249
|
}
|
|
250
|
+
for (const use of entry.uses || []) {
|
|
251
|
+
queue.push({ id: use, caller: pkgId, isInitialAction: false });
|
|
252
|
+
}
|
|
257
253
|
}
|
|
258
254
|
return { resolvedActionIds, externalActionRoots, externalActionEntries };
|
|
259
255
|
}
|
|
@@ -451,7 +447,7 @@ export class SelectionPlanner {
|
|
|
451
447
|
const playbooksMap = this.collectPlaybooks(root, config, manifest);
|
|
452
448
|
const { initialActionIds, selectedPlaybooks } = this.resolveInitialSelection(options, manifest, config, playbooksMap);
|
|
453
449
|
// 依赖闭包解析与 Action 依赖结构物化
|
|
454
|
-
const closure = this.resolveClosure(root, manifest, config, initialActionIds);
|
|
450
|
+
const closure = this.resolveClosure(root, manifest, config, initialActionIds, options?.packageGraph);
|
|
455
451
|
let finalPlaybooks = selectedPlaybooks;
|
|
456
452
|
// 若指定了 Action 但未指定 Playbook,反向裁剪排除无法满足依赖的 Playbook
|
|
457
453
|
if (options?.actions && options.actions.length > 0 && (!options.playbooks || options.playbooks.length === 0)) {
|
|
@@ -26,9 +26,9 @@ export declare function renderRuntimeReferenceContent(options: {
|
|
|
26
26
|
relinkStepLabel: string;
|
|
27
27
|
/** 是否在重新链接步骤末尾附加复合链接语义说明 */
|
|
28
28
|
compositeLinkNote?: boolean;
|
|
29
|
-
/**
|
|
30
|
-
invocationStyle: "global-ad" | "node-entry";
|
|
31
|
-
/** Node 目录型的入口相对路径(invocationStyle 为 node-entry 时使用) */
|
|
29
|
+
/** 调用方式说明:源码型(source-ad)、Node 目录型(node-entry)与开发全局模式(global-ad) */
|
|
30
|
+
invocationStyle: "global-ad" | "source-ad" | "node-entry";
|
|
31
|
+
/** Node 目录型的入口相对路径(invocationStyle 为 node-entry 或 source-ad 时使用) */
|
|
32
32
|
entryRelPath?: string;
|
|
33
33
|
}): string;
|
|
34
34
|
/** 运行时参考文件的导出目录内相对路径(单一事实源) */
|
|
@@ -54,6 +54,8 @@ export interface CompositeSkillPackageInfo {
|
|
|
54
54
|
*/
|
|
55
55
|
export declare function generateCompositeSkillMd(bundleName: string, description: string, packages: CompositeSkillPackageInfo[], options?: {
|
|
56
56
|
customSections?: CompositeCustomSection[];
|
|
57
|
+
/** 调用方式:开发全局模式(global-ad)、源码 Skill(source-ad)与独立 Node 目录型(node-entry) */
|
|
58
|
+
invocationStyle?: "global-ad" | "source-ad" | "node-entry";
|
|
57
59
|
/** 规程链接的子包目录前缀:导出布局为 "packages"(默认);就地生成时传 "." 使用工作区实际目录 */
|
|
58
60
|
packagesBaseDir?: string;
|
|
59
61
|
}): string;
|
package/dist/skill/templates.js
CHANGED
|
@@ -13,7 +13,7 @@ function renderActionListMarkdown(actions, options = {}) {
|
|
|
13
13
|
.map((a) => {
|
|
14
14
|
const aDesc = a.description ? ` - ${a.description}` : "";
|
|
15
15
|
const idLabel = options.packageId
|
|
16
|
-
? `\`${options.packageId}/${a.id}
|
|
16
|
+
? `\`${options.packageId}/${a.id}\``
|
|
17
17
|
: `\`${a.id}\``;
|
|
18
18
|
const lines = [`- ${idLabel}${aDesc}`];
|
|
19
19
|
// 标注元数据解析(安全标注不得从主说明移走)
|
|
@@ -67,12 +67,16 @@ ${describeCmd}
|
|
|
67
67
|
|
|
68
68
|
# 调用语法格式(其中 ASSIGNMENT 根据 describe 查阅的参数契约提供)
|
|
69
69
|
${runCmd} -- ASSIGNMENT...
|
|
70
|
+
|
|
71
|
+
# 管道原始文本绑定(FIELD 为 describe 查阅的字符串字段名)
|
|
72
|
+
printf '整段原始文本' | ${runCmd} --stdin-field FIELD
|
|
70
73
|
\`\`\`
|
|
71
74
|
|
|
72
|
-
|
|
75
|
+
输入模式选择(原有三种输入方式严格互斥,仅选其一;\`--stdin-field\` 原始文本绑定可与扁平赋值组合):
|
|
73
76
|
|
|
74
77
|
- 扁平赋值为默认首选:参数项少且结构简单时,直接以 \`-- key="value" count:=10\` 形式内联传递。
|
|
75
78
|
- 文件输入用于复杂参数:当参数含深层嵌套结构、大段文本或内容易被终端引号转义破坏时,将完整 JSON 写入文件并通过 \`--input-file input.json\` 传递。
|
|
79
|
+
- 管道原始文本绑定:当只需向单个字符串字段(如 text、content、csv、diff)传入整段原始文本时,使用 \`--stdin-field <field>\` 绑定 stdin 正文,正文保持原样不解析类型,可与扁平赋值补充其他字段。
|
|
76
80
|
|
|
77
81
|
输出模式选择(避免浪费上下文 token):
|
|
78
82
|
|
|
@@ -120,30 +124,60 @@ function renderJsonEnvelopeSection(wording, options) {
|
|
|
120
124
|
* 由主说明按需链接调阅,不在每个技能正文重复展开整套安装与框架管理教程。
|
|
121
125
|
*/
|
|
122
126
|
export function renderRuntimeReferenceContent(options) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
if (options.invocationStyle === "node-entry") {
|
|
128
|
+
const entry = options.entryRelPath || "node ./entry.mjs";
|
|
129
|
+
return `# ActionDock 运行时环境参考
|
|
130
|
+
|
|
131
|
+
本技能为独立 Node.js 运行目录交付,直接使用随附的 \`${entry}\` 入口执行,不要求全局安装 ActionDock 命令行工具,不读取 Registry 或当前工作目录项目。
|
|
132
|
+
|
|
133
|
+
## 调用方式
|
|
128
134
|
|
|
129
135
|
\`\`\`bash
|
|
130
|
-
${
|
|
131
|
-
${
|
|
132
|
-
${
|
|
136
|
+
${entry} list
|
|
137
|
+
${entry} describe <package-id>/<action-id>
|
|
138
|
+
${entry} run <package-id>/<action-id> -- ASSIGNMENT...
|
|
133
139
|
\`\`\`
|
|
134
140
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
## 按需排查与依赖安装
|
|
142
|
+
|
|
143
|
+
正常执行直接调用入口,不做前置体检。仅在模块缺失或运行环境报错时修复:
|
|
144
|
+
|
|
145
|
+
- Node.js 版本要求大于等于 24.12.0。
|
|
146
|
+
- ${options.dependencyStepLabel}:在技能根目录执行 \`npm install --omit=dev\`,由 npm 安装生产依赖。
|
|
147
|
+
- 默认共享统一数据存储。仅在需要数据隔离等特殊场景下追加 \`--data-dir <path>\`。
|
|
148
|
+
- 验证就绪:执行 \`${entry} list\`。
|
|
149
|
+
`;
|
|
150
|
+
}
|
|
151
|
+
if (options.invocationStyle === "source-ad") {
|
|
152
|
+
return `# ActionDock 运行时环境参考
|
|
153
|
+
|
|
154
|
+
本技能通过 \`ad ... -P "<skill_root>"\` 执行,封闭加载本地包集合,不读取全局 Registry 或当前工作目录项目。
|
|
155
|
+
|
|
156
|
+
## 调用方式
|
|
157
|
+
|
|
158
|
+
\`\`\`bash
|
|
159
|
+
ad list -P "<skill_root>"
|
|
160
|
+
ad describe <package-id>/<action-id> -P "<skill_root>"
|
|
161
|
+
ad run <package-id>/<action-id> -P "<skill_root>" -- ASSIGNMENT...
|
|
162
|
+
\`\`\`
|
|
163
|
+
|
|
164
|
+
本地封闭执行不支持 \`--async\`。默认共享统一数据存储,仅在需要数据隔离等特殊场景下追加 \`--data-dir <path>\`。
|
|
165
|
+
|
|
166
|
+
## 按需排查与依赖安装
|
|
167
|
+
|
|
168
|
+
正常执行直接调用入口,不做前置体检。仅在模块缺失或运行环境报错时修复:
|
|
169
|
+
|
|
170
|
+
- Node.js 版本要求大于等于 24.12.0。
|
|
171
|
+
- ${options.dependencyStepLabel}:在技能根目录执行 \`npm install --omit=dev\`,由 npm 安装生产依赖。
|
|
172
|
+
- 验证就绪:执行 \`ad list -P "<skill_root>"\`。
|
|
173
|
+
`;
|
|
174
|
+
}
|
|
175
|
+
const relinkNote = options.compositeLinkNote
|
|
176
|
+
? `\`ad link\` 会自动识别并注册工作区下的所有子包,使其中的 Action 随时可以通过完全限定标识调用。`
|
|
177
|
+
: "";
|
|
178
|
+
const invocationSection = `本说明书用于开发工作区,通过全局安装的 \`ad\` 命令行工具执行,不代表完整技能导出。`;
|
|
179
|
+
const probePrinciple = `默认宿主环境中已预置 \`ad\` 命令行工具与 Node.js 运行环境。正常执行流程直接调用上述 Action 即可,严禁在任务启动前盲目进行前置环境检查或体检;仅在终端明确报错提示命令不存在或依赖缺失时,方可按本文指引安装初始化。`;
|
|
180
|
+
const cliInstallSection = `- **环境要求**:Node.js 版本大于等于 24.12.0(执行 \`node -v\` 确认)。
|
|
147
181
|
- **全局安装 ActionDock 命令行工具**:
|
|
148
182
|
\`\`\`bash
|
|
149
183
|
npm install -g @actiondock/cli
|
|
@@ -171,7 +205,7 @@ ${cliInstallSection}
|
|
|
171
205
|
cd "<skill_root>" && npm install --omit=dev
|
|
172
206
|
\`\`\`
|
|
173
207
|
- **验证就绪**:
|
|
174
|
-
|
|
208
|
+
ad --version
|
|
175
209
|
- **环境诊断与体检**(仅全局接入 \`ad\` 后适用):
|
|
176
210
|
安装完成后若仍遇到异常,执行体检命令排查:
|
|
177
211
|
\`\`\`bash
|
|
@@ -200,10 +234,9 @@ function renderTroubleshootingSection(referenceRelPath) {
|
|
|
200
234
|
export const RUNTIME_REFERENCE_REL_PATH = "references/actiondock-runtime.md";
|
|
201
235
|
export function generateSourceSkillMd(config, actions, playbooks) {
|
|
202
236
|
const { cleanName, desc } = getCleanSkillMetadata(config);
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
const actionListMd = renderActionListMarkdown(actions, { packageId: pkgId });
|
|
237
|
+
const firstAction = `${config.id}/${actions[0]?.id || "sample.greet"}`;
|
|
238
|
+
const defaultDescribe = `ad describe ${firstAction} -P "<skill_root>"`;
|
|
239
|
+
const defaultRun = `ad run ${firstAction} -P "<skill_root>"`;
|
|
207
240
|
return `---
|
|
208
241
|
name: ${cleanName}
|
|
209
242
|
description: ${desc}
|
|
@@ -213,56 +246,32 @@ description: ${desc}
|
|
|
213
246
|
|
|
214
247
|
${desc}
|
|
215
248
|
|
|
216
|
-
##
|
|
217
|
-
|
|
218
|
-
本技能为 **ActionDock 源码型技能包**。智能体可直接通过宿主环境中已安装的 ActionDock 命令行工具 \`ad\` 执行其中的 Action。
|
|
219
|
-
|
|
220
|
-
### 注册与链接(全局调用)
|
|
221
|
-
|
|
222
|
-
本技能面向全局挂载使用:在初次调用或初始化时,将包含本 \`SKILL.md\` 的目录解析为 \`<skill_root>\` 并完成注册链接,之后可在任意工作目录通过完全限定 ID 全局调用:
|
|
223
|
-
|
|
224
|
-
\`\`\`bash
|
|
225
|
-
ad link "<skill_root>"
|
|
226
|
-
\`\`\`
|
|
227
|
-
|
|
228
|
-
> \`ad link\` 天然具备幂等性,同一 Package 多次执行会直接更新路径,可安全重复调用。若初次运行提示依赖缺失,可在 \`<skill_root>\` 目录下执行 \`npm install --omit=dev\` 安装生产依赖。
|
|
229
|
-
|
|
230
|
-
### 动作参数契约按需调阅
|
|
231
|
-
|
|
232
|
-
在调用未知参数的 Action 前,可在终端执行命令查阅该 Action 的输入输出模式与详细说明:
|
|
233
|
-
|
|
234
|
-
\`\`\`bash
|
|
235
|
-
ad describe ${pkgId}/${firstAction}
|
|
236
|
-
\`\`\`
|
|
237
|
-
|
|
238
|
-
### 执行 Action
|
|
249
|
+
## 本地执行
|
|
239
250
|
|
|
240
|
-
|
|
251
|
+
将本文件所在目录解析为 \`<skill_root>\`。默认通过 \`ad ... -P "<skill_root>"\` 执行,只加载随附的确定版本包,不读取 Registry 或当前工作目录项目,不需要 \`ad link\`。
|
|
252
|
+
首次缺少依赖时,在技能根目录执行 \`npm install --omit=dev\`。
|
|
253
|
+
默认共享统一数据存储,仅在需要数据隔离等特殊场景下追加 \`--data-dir <path>\`。
|
|
254
|
+
本地封闭执行不支持 \`--async\`。
|
|
241
255
|
|
|
242
|
-
${renderInvocationGuidance(
|
|
256
|
+
${renderInvocationGuidance(defaultDescribe, defaultRun)}
|
|
243
257
|
|
|
244
258
|
${renderJsonEnvelopeSection("envelope")}
|
|
245
|
-
${
|
|
246
|
-
---
|
|
259
|
+
${renderPlaybookSectionMarkdown(playbooks, config.playbooksDir || "playbooks")}
|
|
247
260
|
|
|
248
261
|
## Action 目录
|
|
249
262
|
|
|
250
|
-
${
|
|
251
|
-
|
|
252
|
-
---
|
|
263
|
+
${renderActionListMarkdown(actions, { packageId: config.id })}
|
|
253
264
|
|
|
254
265
|
## 运行时配置与持久化状态
|
|
255
266
|
|
|
256
|
-
如需检查或配置该 Package 的运行时参数与持久化数据:
|
|
257
|
-
|
|
258
267
|
\`\`\`bash
|
|
259
268
|
# 查看与设置配置项
|
|
260
|
-
ad config list
|
|
261
|
-
ad config set KEY VALUE
|
|
269
|
+
ad config list -P "<skill_root>"
|
|
270
|
+
ad config set KEY VALUE -P "<skill_root>"
|
|
262
271
|
|
|
263
272
|
# 查看与检索状态数据
|
|
264
|
-
ad state list
|
|
265
|
-
ad state get KEY
|
|
273
|
+
ad state list -P "<skill_root>"
|
|
274
|
+
ad state get KEY -P "<skill_root>"
|
|
266
275
|
\`\`\`
|
|
267
276
|
|
|
268
277
|
${renderTroubleshootingSection(RUNTIME_REFERENCE_REL_PATH)}
|
|
@@ -358,8 +367,8 @@ export function generateCompositeSkillMd(bundleName, description, packages, opti
|
|
|
358
367
|
for (const pkg of packages) {
|
|
359
368
|
for (const pb of pkg.playbooks) {
|
|
360
369
|
const relPath = packagesBaseDir === "."
|
|
361
|
-
? `./${pkg.packageDir}
|
|
362
|
-
: `packages/${pkg.packageDir}
|
|
370
|
+
? `./${pkg.packageDir}/${pkg.config.playbooksDir || "playbooks"}/${basename(pb.filePath)}`
|
|
371
|
+
: `packages/${pkg.packageDir}/${pkg.config.playbooksDir || "playbooks"}/${basename(pb.filePath)}`;
|
|
363
372
|
playbookEntries.push(`- [${pb.name || pb.id}](${relPath}): ${pb.description || "标准操作规程"}`);
|
|
364
373
|
}
|
|
365
374
|
}
|
|
@@ -371,12 +380,36 @@ description: ${description}
|
|
|
371
380
|
# ${bundleName} 复合技能套件
|
|
372
381
|
|
|
373
382
|
${description}`;
|
|
383
|
+
const invocationStyle = options?.invocationStyle ?? "source-ad";
|
|
384
|
+
const isGlobalAd = invocationStyle === "global-ad";
|
|
385
|
+
const isNodeEntry = invocationStyle === "node-entry";
|
|
386
|
+
const describeCmd = isGlobalAd
|
|
387
|
+
? `ad describe ${sampleActionId}`
|
|
388
|
+
: isNodeEntry
|
|
389
|
+
? `node "<skill_root>/entry.mjs" describe ${sampleActionId}`
|
|
390
|
+
: `ad describe ${sampleActionId} -P "<skill_root>"`;
|
|
391
|
+
const runCmd = isGlobalAd
|
|
392
|
+
? `ad run ${sampleActionId}`
|
|
393
|
+
: isNodeEntry
|
|
394
|
+
? `node "<skill_root>/entry.mjs" run ${sampleActionId}`
|
|
395
|
+
: `ad run ${sampleActionId} -P "<skill_root>"`;
|
|
396
|
+
const localGuidance = isGlobalAd
|
|
397
|
+
? ""
|
|
398
|
+
: isNodeEntry
|
|
399
|
+
? `将本文件所在目录解析为 \`<skill_root>\`。直接使用随附的 \`node "<skill_root>/entry.mjs"\` 入口执行,不要求全局安装 \`ad\` 命令行工具,不读取 Registry 或当前工作目录项目。
|
|
400
|
+
缺少依赖时,在技能根目录执行 \`npm install --omit=dev\`。默认共享统一数据存储,仅在需要数据隔离等特殊场景下追加 \`--data-dir <path>\`。
|
|
401
|
+
本地封闭执行不支持 \`--async\`;复合技能不提供配置与状态管理子命令,配置覆盖使用 \`--config KEY=VALUE\`。`
|
|
402
|
+
: `将本文件所在目录解析为 \`<skill_root>\`。默认通过 \`ad ... -P "<skill_root>"\` 执行,仅使用本技能封闭包含的本地包集合,不通过 Registry 或当前工作目录项目执行,亦不需要 \`ad link\`。此执行约定优先于自定义正文中的历史调用说明。
|
|
403
|
+
缺少依赖时,在技能根目录执行 \`npm install --omit=dev\`。默认共享统一数据存储,仅在需要数据隔离等特殊场景下追加 \`--data-dir <path>\`。
|
|
404
|
+
本地封闭执行不支持 \`--async\`;复合技能不提供配置与状态管理子命令,配置覆盖使用 \`--config KEY=VALUE\`。`;
|
|
374
405
|
const sDescribe = `## 动作参数契约按需调阅
|
|
375
406
|
|
|
407
|
+
${localGuidance}
|
|
408
|
+
|
|
376
409
|
为节省上下文开销,各 Action 的详细参数结构不静态内嵌在说明书中。在调用未知参数的 Action 前,可在终端执行命令查阅输入输出约束:
|
|
377
410
|
|
|
378
411
|
\`\`\`bash
|
|
379
|
-
|
|
412
|
+
${describeCmd}
|
|
380
413
|
\`\`\``;
|
|
381
414
|
const sActions = `## 可用 Action 工具清单
|
|
382
415
|
|
|
@@ -393,8 +426,8 @@ ${playbookEntries.join("\n")}
|
|
|
393
426
|
---`
|
|
394
427
|
: "";
|
|
395
428
|
const sInvoke = `## 标准调用命令
|
|
396
|
-
|
|
397
|
-
${renderInvocationGuidance(
|
|
429
|
+
|
|
430
|
+
${renderInvocationGuidance(describeCmd, runCmd)}
|
|
398
431
|
|
|
399
432
|
${renderJsonEnvelopeSection("envelope", { withDescriptions: false })}`;
|
|
400
433
|
const sTroubleshooting = renderTroubleshootingSection(RUNTIME_REFERENCE_REL_PATH);
|
package/dist/skill-md.d.ts
CHANGED
|
@@ -35,3 +35,11 @@ export declare function writeSkillMd(root: string, destDir: string, options: {
|
|
|
35
35
|
* 构造模板生成所需的 ProjectConfig 视图。
|
|
36
36
|
*/
|
|
37
37
|
export declare function buildConfigForTemplates(plan: SelectionPlan, actionsDir: string, playbooksDir: string): ProjectConfig;
|
|
38
|
+
/** 刷新有边界标记的本地执行约定,保留生成块之外的用户正文。 */
|
|
39
|
+
export declare function appendLocalExecutionContract(file: string, packages: Array<{
|
|
40
|
+
packageId: string;
|
|
41
|
+
actions: Array<{
|
|
42
|
+
id: string;
|
|
43
|
+
isExternal?: boolean;
|
|
44
|
+
}>;
|
|
45
|
+
}>): void;
|
package/dist/skill-md.js
CHANGED
|
@@ -159,3 +159,49 @@ export function buildConfigForTemplates(plan, actionsDir, playbooksDir) {
|
|
|
159
159
|
config: plan.configDefs,
|
|
160
160
|
};
|
|
161
161
|
}
|
|
162
|
+
/** 刷新有边界标记的本地执行约定,保留生成块之外的用户正文。 */
|
|
163
|
+
export function appendLocalExecutionContract(file, packages) {
|
|
164
|
+
const commands = packages.flatMap((pkg) => pkg.actions
|
|
165
|
+
.filter((action) => !action.isExternal)
|
|
166
|
+
.map((action) => `- \`${pkg.packageId}/${action.id}\``));
|
|
167
|
+
const content = readFileSync(file, "utf-8");
|
|
168
|
+
const block = `<!-- actiondock:local-execution -->
|
|
169
|
+
## 本地执行约定
|
|
170
|
+
|
|
171
|
+
本节为导出器根据实际包清单生成的执行约定,优先于上文保留的历史调用或初始化说明。
|
|
172
|
+
将本文件所在目录解析为 \`<skill_root>\`。默认使用 \`ad ... -P "<skill_root>"\` 执行,仅加载本技能封闭包含的本地包集合,不通过 Registry、当前工作目录项目或 \`ad link\` 调度。
|
|
173
|
+
|
|
174
|
+
\`\`\`bash
|
|
175
|
+
cd "<skill_root>" && npm install --omit=dev
|
|
176
|
+
ad list -P "<skill_root>"
|
|
177
|
+
ad describe <package-id>/<action-id> -P "<skill_root>"
|
|
178
|
+
ad run <package-id>/<action-id> -P "<skill_root>" -- ASSIGNMENT...
|
|
179
|
+
\`\`\`
|
|
180
|
+
|
|
181
|
+
默认共享统一数据存储,仅在需要数据隔离等特殊场景下追加 \`--data-dir <path>\`;封闭执行不支持 \`--async\`。
|
|
182
|
+
|
|
183
|
+
### 本次导出的可用动作
|
|
184
|
+
|
|
185
|
+
${commands.join("\n")}
|
|
186
|
+
<!-- actiondock:local-execution:end -->`;
|
|
187
|
+
const startMarker = "<!-- actiondock:local-execution -->";
|
|
188
|
+
const endMarker = "<!-- actiondock:local-execution:end -->";
|
|
189
|
+
let cursor = 0;
|
|
190
|
+
let refreshed = "";
|
|
191
|
+
let found = false;
|
|
192
|
+
while (true) {
|
|
193
|
+
const start = content.indexOf(startMarker, cursor);
|
|
194
|
+
const end = content.indexOf(endMarker, cursor);
|
|
195
|
+
if (start < 0 && end < 0)
|
|
196
|
+
break;
|
|
197
|
+
const nextStart = start < 0 ? -1 : content.indexOf(startMarker, start + startMarker.length);
|
|
198
|
+
if (start < 0 || end < start || (nextStart >= 0 && nextStart < end)) {
|
|
199
|
+
throw new BuilderError("Incomplete or misordered local execution block markers; refusing to replace user content");
|
|
200
|
+
}
|
|
201
|
+
refreshed += content.slice(cursor, start) + (found ? "" : block);
|
|
202
|
+
found = true;
|
|
203
|
+
cursor = end + endMarker.length;
|
|
204
|
+
}
|
|
205
|
+
refreshed += content.slice(cursor);
|
|
206
|
+
writeFileSync(file, found ? refreshed : content + "\n\n" + block + "\n", "utf-8");
|
|
207
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ActionDockManifest } from "@actiondock/core/project";
|
|
2
|
+
import { type PackageGraph } from "@actiondock/core/graph";
|
|
3
|
+
/** 源码导出只使用显式包与正式安装依赖;显式兄弟包优先于任何依赖查找。 */
|
|
4
|
+
export declare function createSourcePackageGraph(projectRoots: string[], rootManifest?: ActionDockManifest): PackageGraph;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { ActionDockError } from "@actiondock/core";
|
|
4
|
+
import { loadManifest } from "@actiondock/core/project";
|
|
5
|
+
import { PackageGraphBuilder } from "@actiondock/core/graph";
|
|
6
|
+
import { BuilderError } from "./errors.js";
|
|
7
|
+
/** 源码导出只使用显式包与正式安装依赖;显式兄弟包优先于任何依赖查找。 */
|
|
8
|
+
export function createSourcePackageGraph(projectRoots, rootManifest) {
|
|
9
|
+
const packages = new Map();
|
|
10
|
+
const register = (pkg) => {
|
|
11
|
+
const existing = packages.get(pkg.id);
|
|
12
|
+
if (existing && realpathSync(existing.root) !== realpathSync(pkg.root)) {
|
|
13
|
+
throw new ActionDockError("PACKAGE_ID_CONFLICT", `Package ID '${pkg.id}' is declared by multiple directories: '${existing.root}' and '${pkg.root}'`);
|
|
14
|
+
}
|
|
15
|
+
packages.set(pkg.id, pkg);
|
|
16
|
+
};
|
|
17
|
+
for (const [index, root] of projectRoots.entries()) {
|
|
18
|
+
const absRoot = resolve(root);
|
|
19
|
+
const manifest = index === 0 && rootManifest ? rootManifest : loadManifest(absRoot);
|
|
20
|
+
if (!manifest)
|
|
21
|
+
throw new BuilderError(`Missing actiondock.json at '${absRoot}'`);
|
|
22
|
+
register({ id: manifest.id, root: absRoot, manifest });
|
|
23
|
+
}
|
|
24
|
+
const packageRoots = Object.fromEntries(Array.from(packages.values(), (p) => [p.id, p.root]));
|
|
25
|
+
// 每个显式包的正式依赖均纳入闭包,统一查重后再构造供所有规划共享的图。
|
|
26
|
+
for (const pkg of Array.from(packages.values())) {
|
|
27
|
+
const graph = new PackageGraphBuilder({ root: pkg.root, manifest: pkg.manifest, packageRoots, allowDevLinks: false }).buildSync();
|
|
28
|
+
for (const node of graph.packages.values()) {
|
|
29
|
+
register({ id: node.packageId, root: node.root, manifest: node.manifest });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return new PackageGraphBuilder({ packages: Array.from(packages.values()), validateDependencies: true }).buildSync();
|
|
33
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ProjectConfig } from "@actiondock/core";
|
|
2
|
+
import type { PackageGraph } from "@actiondock/core/graph";
|
|
2
3
|
import type { ActionDockManifest } from "@actiondock/core/project";
|
|
3
4
|
/**
|
|
4
5
|
* 规划输入侧的项目配置扩展字段。
|
|
@@ -150,6 +151,8 @@ export type SelectionPlan = BuildPlan;
|
|
|
150
151
|
* 声明式选择规划器配置选项。
|
|
151
152
|
*/
|
|
152
153
|
export interface SelectionPlannerOptions {
|
|
154
|
+
/** 显式共享包图,提供时不再发现 Registry 或当前工程。 */
|
|
155
|
+
packageGraph?: PackageGraph;
|
|
153
156
|
/** 项目根目录绝对路径 */
|
|
154
157
|
projectRoot: string;
|
|
155
158
|
/** 显式传入的项目配置(若未提供则从 actiondock.json 读取) */
|
|
@@ -304,6 +307,8 @@ export interface PackResult {
|
|
|
304
307
|
* Skill 导出选项。
|
|
305
308
|
*/
|
|
306
309
|
export interface SkillExporterOptions {
|
|
310
|
+
/** 复合导出共享的明确包集合。 */
|
|
311
|
+
packageGraph?: PackageGraph;
|
|
307
312
|
/** 源码项目根目录绝对路径 */
|
|
308
313
|
projectRoot: string;
|
|
309
314
|
/** 导出模式:source 源码型 Skill 或 node 目录型 Skill(默认 source) */
|
|
@@ -336,6 +341,8 @@ export interface SkillExporterOptions {
|
|
|
336
341
|
skipDependencyValidation?: boolean;
|
|
337
342
|
/** 内部标识:是否作为复合套件子包导出(避免闭包再次触发嵌套 mini-workspace) */
|
|
338
343
|
_isSubpackage?: boolean;
|
|
344
|
+
/** 复合套件子包缺省 npm 包名(当子包无 package.json 或缺少 name 时使用) */
|
|
345
|
+
defaultPackageName?: string;
|
|
339
346
|
/** 自定义复合技能说明书文件路径 */
|
|
340
347
|
customMdPath?: string;
|
|
341
348
|
/** 所属 Workspace 根目录(可选) */
|
|
@@ -380,6 +387,8 @@ export type ExportSkillResult = SkillExportResult;
|
|
|
380
387
|
* 复合 Skill 套件导出选项。
|
|
381
388
|
*/
|
|
382
389
|
export interface CompositeSkillExportOptions {
|
|
390
|
+
/** 复用源码导出已解析的有效包图,避免丢失显式清单。 */
|
|
391
|
+
packageGraph?: PackageGraph;
|
|
383
392
|
/** 复合技能套件名称 */
|
|
384
393
|
bundleName: string;
|
|
385
394
|
/** 参与聚合的项目根目录绝对路径列表 */
|