@actiondock/builder 2.15.0 → 2.17.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 +37 -15
- package/dist/dependency-check.d.ts +1 -1
- package/dist/dependency-check.js +5 -0
- package/dist/entry-generators.d.ts +2 -9
- package/dist/entry-generators.js +21 -43
- package/dist/export-composite.d.ts +1 -1
- package/dist/export-composite.js +54 -125
- package/dist/export-source.d.ts +1 -1
- package/dist/export-source.js +8 -32
- package/dist/exporter.js +7 -36
- package/dist/planner.js +78 -74
- package/dist/skill/templates.d.ts +5 -7
- package/dist/skill/templates.js +67 -96
- package/dist/skill-md.d.ts +0 -8
- package/dist/skill-md.js +0 -46
- package/dist/types.d.ts +8 -9
- package/package.json +3 -3
- package/dist/derived-graph.d.ts +0 -4
- package/dist/derived-graph.js +0 -30
- package/dist/source-graph.d.ts +0 -4
- package/dist/source-graph.js +0 -33
package/dist/export-source.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readFileSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { basename, dirname, join } from "node:path";
|
|
3
3
|
import { mkdirSync } from "node:fs";
|
|
4
|
-
import { generateNodeHostEntrySource, generateNodeSupervisorEntrySource } from "./entry-generators.js";
|
|
5
|
-
import { appendLocalExecutionContract } from "./skill-md.js";
|
|
6
4
|
import { generateSourceSkillMd } from "./skill/index.js";
|
|
7
5
|
import { RUNTIME_REFERENCE_REL_PATH, renderRuntimeReferenceContent, } from "./skill/templates.js";
|
|
8
|
-
import { loadManifest } from "@actiondock/core/project";
|
|
9
6
|
import { BuilderError } from "./errors.js";
|
|
10
7
|
import { getInternalDependencyVersion } from "./fs-utils.js";
|
|
11
8
|
import { assertValidManifestActionIds, sanitizeExportDependencies, serializePlanManifest, } from "./manifest.js";
|
|
12
9
|
import { copyPlanEntries } from "./stage-sources.js";
|
|
10
|
+
import { isOwnAction } from "./types.js";
|
|
13
11
|
import { buildConfigForTemplates, writeSkillMd, } from "./skill-md.js";
|
|
14
12
|
/**
|
|
15
13
|
* 源码型 Skill 导出装配层。
|
|
@@ -24,24 +22,18 @@ export function stageSourceSkill(root, skillDir, plan, options, pkgSlug) {
|
|
|
24
22
|
const actionsDir = plan.actionsDir || "actions";
|
|
25
23
|
const playbooksDir = plan.playbooksDir || "playbooks";
|
|
26
24
|
const configForTemplates = buildConfigForTemplates(plan, actionsDir, playbooksDir);
|
|
27
|
-
const usedExistingSkillMd = writeSkillMd(root, skillDir, { skipSkillMd: options.skipSkillMd, skillMdPath: options.skillMdPath, pkgSlug }, () => generateSourceSkillMd(configForTemplates, plan.actions.filter((a) =>
|
|
25
|
+
const usedExistingSkillMd = writeSkillMd(root, skillDir, { skipSkillMd: options.skipSkillMd, skillMdPath: options.skillMdPath, pkgSlug }, () => generateSourceSkillMd(configForTemplates, plan.actions.filter((a) => isOwnAction(a)), plan.playbooks));
|
|
28
26
|
// 导出精简后的 actiondock.json 项目配置(项目元数据与清单的单一事实源)
|
|
29
27
|
const exportedConfig = serializePlanManifest(plan, {
|
|
30
28
|
omitEmptyConfig: true,
|
|
31
29
|
includeDirs: { actionsDir, playbooksDir },
|
|
32
30
|
});
|
|
33
|
-
const originalManifest = options.manifest || loadManifest(root);
|
|
34
|
-
if (originalManifest?.dependencies)
|
|
35
|
-
exportedConfig.dependencies = originalManifest.dependencies;
|
|
36
|
-
const packageUses = originalManifest?.uses;
|
|
37
|
-
if (packageUses)
|
|
38
|
-
exportedConfig.uses = packageUses;
|
|
39
31
|
if (exportedConfig.actions && typeof exportedConfig.actions === "object") {
|
|
40
32
|
assertValidManifestActionIds(exportedConfig.actions);
|
|
41
33
|
}
|
|
42
34
|
writeFileSync(join(skillDir, "actiondock.json"), JSON.stringify(exportedConfig, null, 2) + "\n", "utf-8");
|
|
43
35
|
// 导出 package.json
|
|
44
|
-
writeSourceSkillPkgJson(root, skillDir, plan, pkgSlug
|
|
36
|
+
writeSourceSkillPkgJson(root, skillDir, plan, pkgSlug);
|
|
45
37
|
// 拷贝 tsconfig.json(若存在)
|
|
46
38
|
const tsconfigPath = join(root, "tsconfig.json");
|
|
47
39
|
if (existsSync(tsconfigPath)) {
|
|
@@ -51,27 +43,13 @@ export function stageSourceSkill(root, skillDir, plan, options, pkgSlug) {
|
|
|
51
43
|
copyPlanEntries(skillDir, plan, {
|
|
52
44
|
playbookRelPath: (pb) => join(playbooksDir, basename(pb.filePath)),
|
|
53
45
|
});
|
|
54
|
-
if (!options._isSubpackage) {
|
|
55
|
-
for (const name of ["entry.mjs", "entry-host.js"]) {
|
|
56
|
-
if (existsSync(join(skillDir, name))) {
|
|
57
|
-
throw new BuilderError(`Source Skill entry conflict: '${name}' is reserved for the local runtime entry; refusing to overwrite a declared file.`, "SOURCE_ENTRY_CONFLICT");
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
writeFileSync(join(skillDir, "entry.mjs"), generateNodeSupervisorEntrySource(plan), "utf-8");
|
|
61
|
-
writeFileSync(join(skillDir, "entry-host.js"), generateNodeHostEntrySource(undefined, {
|
|
62
|
-
localPackages: [{ packageId: plan.packageId, relativeRoot: "." }],
|
|
63
|
-
}), "utf-8");
|
|
64
|
-
if (usedExistingSkillMd)
|
|
65
|
-
appendLocalExecutionContract(join(skillDir, "SKILL.md"), [plan]);
|
|
66
|
-
}
|
|
67
46
|
// 声明资产拷贝完成后再物化默认运行参考文件:仅在使用自动模板时生成;
|
|
68
47
|
// 与项目声明资产同路径冲突时报错不覆盖(拷贝在前,冲突检测能真实命中)
|
|
69
48
|
if (usedExistingSkillMd === undefined && !options.skipSkillMd) {
|
|
70
49
|
writeRuntimeReferenceFile(skillDir, {
|
|
71
50
|
dependencyStepLabel: "安装技能源码依赖",
|
|
72
51
|
relinkStepLabel: "完成安装后重新链接本技能",
|
|
73
|
-
invocationStyle: "
|
|
74
|
-
entryRelPath: 'node "<skill_root>/entry.mjs"',
|
|
52
|
+
invocationStyle: "global-ad",
|
|
75
53
|
});
|
|
76
54
|
}
|
|
77
55
|
return usedExistingSkillMd;
|
|
@@ -88,16 +66,15 @@ export function writeRuntimeReferenceFile(destDir, options) {
|
|
|
88
66
|
mkdirSync(dirname(referencePath), { recursive: true });
|
|
89
67
|
writeFileSync(referencePath, renderRuntimeReferenceContent(options), "utf-8");
|
|
90
68
|
}
|
|
91
|
-
function writeSourceSkillPkgJson(root, skillDir, plan, pkgSlug
|
|
69
|
+
function writeSourceSkillPkgJson(root, skillDir, plan, pkgSlug) {
|
|
92
70
|
let exportedPkg;
|
|
93
|
-
const fallbackName = options?.defaultPackageName || pkgSlug;
|
|
94
71
|
const projectPkgPath = join(root, "package.json");
|
|
95
72
|
if (existsSync(projectPkgPath)) {
|
|
96
73
|
try {
|
|
97
74
|
const raw = readFileSync(projectPkgPath, "utf-8");
|
|
98
75
|
const parsed = JSON.parse(raw);
|
|
99
76
|
exportedPkg = {
|
|
100
|
-
name: parsed.name ||
|
|
77
|
+
name: parsed.name || pkgSlug,
|
|
101
78
|
version: plan.version || parsed.version || "0.1.0",
|
|
102
79
|
description: plan.description || parsed.description,
|
|
103
80
|
type: "module",
|
|
@@ -108,13 +85,12 @@ function writeSourceSkillPkgJson(root, skillDir, plan, pkgSlug, options) {
|
|
|
108
85
|
if (err instanceof BuilderError) {
|
|
109
86
|
throw err;
|
|
110
87
|
}
|
|
111
|
-
exportedPkg = fallbackSkillPkg(plan,
|
|
88
|
+
exportedPkg = fallbackSkillPkg(plan, pkgSlug);
|
|
112
89
|
}
|
|
113
90
|
}
|
|
114
91
|
else {
|
|
115
|
-
exportedPkg = fallbackSkillPkg(plan,
|
|
92
|
+
exportedPkg = fallbackSkillPkg(plan, pkgSlug);
|
|
116
93
|
}
|
|
117
|
-
exportedPkg.dependencies["@actiondock/core"] ??= getInternalDependencyVersion();
|
|
118
94
|
writeFileSync(join(skillDir, "package.json"), JSON.stringify(exportedPkg, null, 2) + "\n", "utf-8");
|
|
119
95
|
}
|
|
120
96
|
/** 无 package.json 或解析失败时的兜底导出描述 */
|
package/dist/exporter.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
-
import { getPackageSlug
|
|
3
|
+
import { getPackageSlug } from "@actiondock/core/project";
|
|
4
4
|
import { BuilderError } from "./errors.js";
|
|
5
5
|
import { replaceDirAtomic } from "./fs-utils.js";
|
|
6
6
|
import { collectRelativeFiles } from "./fs-utils.js";
|
|
7
|
-
import { createSourcePackageGraph } from "./source-graph.js";
|
|
8
|
-
import { deriveEffectivePackageGraph } from "./derived-graph.js";
|
|
9
7
|
import { SelectionPlanner } from "./planner.js";
|
|
10
8
|
import { isOwnAction } from "./types.js";
|
|
11
9
|
import { createArchive, resolveArchiveFormat } from "./export-archive.js";
|
|
@@ -27,36 +25,9 @@ export class SkillExporter {
|
|
|
27
25
|
*/
|
|
28
26
|
async export(options) {
|
|
29
27
|
const root = resolve(options.projectRoot);
|
|
30
|
-
const mode = options.mode === "node" ? "node" : "source";
|
|
31
|
-
// 共享图、规划与源码清单使用同一有效声明;显式 manifest 不从磁盘继承依赖。
|
|
32
|
-
if (mode === "source" && (options.config || options.manifest)) {
|
|
33
|
-
const graphNode = options.packageGraph && Array.from(options.packageGraph.packages.values()).find((p) => resolve(p.root) === root);
|
|
34
|
-
const baseManifest = options.manifest || graphNode?.manifest || loadManifest(root) || {};
|
|
35
|
-
const manifest = {
|
|
36
|
-
...baseManifest,
|
|
37
|
-
...options.config,
|
|
38
|
-
...options.manifest,
|
|
39
|
-
// 保持既有 config 元数据优先级;动作、dependencies、uses 使用有效清单声明。
|
|
40
|
-
...Object.fromEntries([
|
|
41
|
-
"id", "name", "version", "description", "config", "actionsDir", "playbooksDir",
|
|
42
|
-
].map((key) => [key, options.config?.[key]]).filter(([, value]) => value !== undefined)),
|
|
43
|
-
};
|
|
44
|
-
options = {
|
|
45
|
-
...options,
|
|
46
|
-
manifest,
|
|
47
|
-
config: { ...manifest, name: manifest.name || manifest.id, version: manifest.version || "0.1.0" },
|
|
48
|
-
};
|
|
49
|
-
}
|
|
28
|
+
const mode = options.standalone === true || options.mode === "node" ? "node" : "source";
|
|
50
29
|
// 调用 SelectionPlanner 执行声明式构建规划
|
|
51
|
-
const packageGraph = mode === "source" && options.packageGraph
|
|
52
|
-
? deriveEffectivePackageGraph(options.packageGraph, root, options.manifest)
|
|
53
|
-
: options.packageGraph ?? (mode === "source" ? createSourcePackageGraph([root], options.manifest) : undefined);
|
|
54
|
-
options = {
|
|
55
|
-
...options,
|
|
56
|
-
packageGraph,
|
|
57
|
-
};
|
|
58
30
|
const plan = SelectionPlanner.plan({
|
|
59
|
-
packageGraph,
|
|
60
31
|
projectRoot: root,
|
|
61
32
|
config: options.config,
|
|
62
33
|
manifest: options.manifest,
|
|
@@ -68,20 +39,19 @@ export class SkillExporter {
|
|
|
68
39
|
const defaultFolderName = `${pkgSlug}-skill`;
|
|
69
40
|
const defaultSkillDir = join(root, "dist", defaultFolderName);
|
|
70
41
|
const targetSkillDir = resolve(options.outDir || defaultSkillDir);
|
|
71
|
-
const hasExternalDeps = Boolean(
|
|
72
|
-
//
|
|
42
|
+
const hasExternalDeps = Boolean(plan.externalProjectRoots && plan.externalProjectRoots.length > 0);
|
|
43
|
+
// 单包源码导出若开启 bundleDeps 且依赖闭包含外部包,导成 mini-workspace 形态(packages/ 下带齐依赖包),和 bundle 统一成一个交付形状
|
|
73
44
|
// 该复合分支会展开全部依赖包,无法保留调用方传入的 actions/playbooks 过滤选项;
|
|
74
45
|
// 静默丢弃过滤会导致产物全量导出,必须显式拒绝并给出调整指引(CLI 侧已有 roots>1 守卫,此处补齐 composite 分支守卫)
|
|
75
46
|
const hasFilters = Boolean((options.actions && options.actions.length > 0) ||
|
|
76
47
|
(options.playbooks && options.playbooks.length > 0));
|
|
77
|
-
const willUseComposite = mode === "source" && !options._isSubpackage && hasExternalDeps;
|
|
48
|
+
const willUseComposite = mode === "source" && !options._isSubpackage && hasExternalDeps && options.bundleDeps === true;
|
|
78
49
|
if (hasFilters && willUseComposite) {
|
|
79
50
|
throw new BuilderError("Filtering options (--actions, --playbook) cannot be combined with a source export whose dependency closure spans external linked packages (composite mini-workspace output). Remove the filtering options to export the full closure, or adjust the 'uses' declarations so the closure stays within a single package.", "FILTERS_UNSUPPORTED_FOR_COMPOSITE");
|
|
80
51
|
}
|
|
81
52
|
if (willUseComposite) {
|
|
82
|
-
const allProjectRoots = Array.from(new Set([root, ...
|
|
53
|
+
const allProjectRoots = Array.from(new Set([root, ...plan.externalProjectRoots]));
|
|
83
54
|
const compositeRes = await this.exportComposite({
|
|
84
|
-
packageGraph,
|
|
85
55
|
bundleName: plan.packageName || plan.packageId,
|
|
86
56
|
projectRoots: allProjectRoots,
|
|
87
57
|
outDir: targetSkillDir,
|
|
@@ -90,6 +60,7 @@ export class SkillExporter {
|
|
|
90
60
|
workspaceRoot: options.workspaceRoot,
|
|
91
61
|
skillMdPath: options.skillMdPath,
|
|
92
62
|
customMdPath: options.customMdPath,
|
|
63
|
+
bundleDeps: options.bundleDeps,
|
|
93
64
|
});
|
|
94
65
|
return {
|
|
95
66
|
packageId: plan.packageId,
|
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, loadProjectConfig, } from "@actiondock/core";
|
|
3
|
+
import { ActionDockError, ACTION_NOT_FOUND, UNDECLARED_ACTION_DEPENDENCY, 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,16 +150,13 @@ 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
|
-
|
|
157
|
-
? actId.slice(config.id.length + 1)
|
|
158
|
-
: actId;
|
|
159
|
-
if (!manifestActions[localId] && !manifestActions[actId]) {
|
|
156
|
+
if (!manifestActions[actId]) {
|
|
160
157
|
throw new PlannerError(`Action '${actId}' specified in build options was not found in manifest`, "ACTION_NOT_FOUND");
|
|
161
158
|
}
|
|
162
|
-
initialActionIds.add(
|
|
159
|
+
initialActionIds.add(actId);
|
|
163
160
|
}
|
|
164
161
|
}
|
|
165
162
|
// 若均未显式指定,默认包含清单中的全部 Action
|
|
@@ -168,87 +165,94 @@ export class SelectionPlanner {
|
|
|
168
165
|
initialActionIds.add(actId);
|
|
169
166
|
}
|
|
170
167
|
}
|
|
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
|
+
}
|
|
171
177
|
return { initialActionIds, selectedPlaybooks };
|
|
172
178
|
}
|
|
173
179
|
/**
|
|
174
180
|
* 进行依赖闭包(uses)解析计算,自动处理环形依赖与传递依赖(支持当前清单与已链接外部包)。
|
|
175
181
|
*/
|
|
176
|
-
resolveClosure(root, manifest, config, initialActionIds
|
|
182
|
+
resolveClosure(root, manifest, config, initialActionIds) {
|
|
177
183
|
const resolvedActionIds = new Set();
|
|
184
|
+
// queued 与 resolvedActionIds 联合判重,避免高入度节点在 uses 图中被重复入队导致 O(边数) 重复解析
|
|
185
|
+
const queued = new Set(initialActionIds);
|
|
186
|
+
const queue = Array.from(initialActionIds);
|
|
178
187
|
const externalActionRoots = new Map();
|
|
179
188
|
const externalActionEntries = new Map();
|
|
180
|
-
const
|
|
189
|
+
const manifestActions = manifest.actions || {};
|
|
190
|
+
const graph = new PackageGraphBuilder({ root, allowDevLinks: true }).buildSync();
|
|
181
191
|
const catalog = new DefaultActionCatalog(graph);
|
|
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 });
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
192
|
while (queue.length > 0) {
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
193
|
+
const currentId = queue.shift();
|
|
194
|
+
queued.delete(currentId);
|
|
195
|
+
if (resolvedActionIds.has(currentId)) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
let entry = manifestActions[currentId] || config?.actions?.[currentId];
|
|
199
|
+
let entryRoot = root;
|
|
200
|
+
if (!entry) {
|
|
201
|
+
const resolved = resolveAction(currentId, { graph, catalog, caller: config?.id });
|
|
202
|
+
const resolvedPkgId = resolved.package.id;
|
|
203
|
+
const resolvedActionId = resolved.ref.actionId;
|
|
204
|
+
const extNode = graph.packages.get(resolvedPkgId);
|
|
205
|
+
if (extNode && existsSync(extNode.root)) {
|
|
206
|
+
const extRoot = extNode.root;
|
|
207
|
+
let extConfig;
|
|
208
|
+
try {
|
|
209
|
+
extConfig = loadProjectConfig(extRoot);
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
extConfig = {
|
|
213
|
+
id: resolvedPkgId,
|
|
214
|
+
name: resolvedPkgId,
|
|
215
|
+
version: "0.1.0",
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const externalManifest = loadManifest(extRoot);
|
|
219
|
+
const externalEntry = externalManifest?.actions?.[resolvedActionId] ||
|
|
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
|
+
}
|
|
216
238
|
}
|
|
217
239
|
}
|
|
218
|
-
for (const actionId of Object.keys(node.manifest.actions || {})) {
|
|
219
|
-
queue.push({ id: `${packageId}/${actionId}`, caller: packageId, isInitialAction: false });
|
|
220
|
-
}
|
|
221
|
-
continue;
|
|
222
240
|
}
|
|
223
|
-
|
|
224
|
-
|
|
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);
|
|
241
|
+
if (!entry) {
|
|
242
|
+
throw new ActionDockError(ACTION_NOT_FOUND, `Action '${currentId}' referenced in dependency closure (uses) was not found in manifest or linked packages`);
|
|
243
243
|
}
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
queue.push({ id: use, caller: pkgId, isInitialAction: false });
|
|
248
|
-
}
|
|
244
|
+
if (entryRoot !== root) {
|
|
245
|
+
externalActionRoots.set(currentId, entryRoot);
|
|
246
|
+
externalActionEntries.set(currentId, entry);
|
|
249
247
|
}
|
|
250
|
-
|
|
251
|
-
|
|
248
|
+
resolvedActionIds.add(currentId);
|
|
249
|
+
if (entry.uses && Array.isArray(entry.uses)) {
|
|
250
|
+
for (const depId of entry.uses) {
|
|
251
|
+
if (!resolvedActionIds.has(depId) && !queued.has(depId)) {
|
|
252
|
+
queued.add(depId);
|
|
253
|
+
queue.push(depId);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
252
256
|
}
|
|
253
257
|
}
|
|
254
258
|
return { resolvedActionIds, externalActionRoots, externalActionEntries };
|
|
@@ -447,7 +451,7 @@ export class SelectionPlanner {
|
|
|
447
451
|
const playbooksMap = this.collectPlaybooks(root, config, manifest);
|
|
448
452
|
const { initialActionIds, selectedPlaybooks } = this.resolveInitialSelection(options, manifest, config, playbooksMap);
|
|
449
453
|
// 依赖闭包解析与 Action 依赖结构物化
|
|
450
|
-
const closure = this.resolveClosure(root, manifest, config, initialActionIds
|
|
454
|
+
const closure = this.resolveClosure(root, manifest, config, initialActionIds);
|
|
451
455
|
let finalPlaybooks = selectedPlaybooks;
|
|
452
456
|
// 若指定了 Action 但未指定 Playbook,反向裁剪排除无法满足依赖的 Playbook
|
|
453
457
|
if (options?.actions && options.actions.length > 0 && (!options.playbooks || options.playbooks.length === 0)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActionSpec, ProjectConfig
|
|
1
|
+
import type { ActionSpec, ProjectConfig } from "@actiondock/core";
|
|
2
2
|
import type { PlaybookDefinition } from "@actiondock/core/project";
|
|
3
3
|
import type { CompositeCustomSection } from "./custom-parser.js";
|
|
4
4
|
export type SkillActionItem = ActionSpec | {
|
|
@@ -26,9 +26,9 @@ export declare function renderRuntimeReferenceContent(options: {
|
|
|
26
26
|
relinkStepLabel: string;
|
|
27
27
|
/** 是否在重新链接步骤末尾附加复合链接语义说明 */
|
|
28
28
|
compositeLinkNote?: boolean;
|
|
29
|
-
/**
|
|
30
|
-
invocationStyle: "global-ad" | "
|
|
31
|
-
/** Node 目录型的入口相对路径(invocationStyle 为 node-entry
|
|
29
|
+
/** 调用方式说明:源码型与 Node 目录型分化(如是否需要全局 ad) */
|
|
30
|
+
invocationStyle: "global-ad" | "node-entry";
|
|
31
|
+
/** Node 目录型的入口相对路径(invocationStyle 为 node-entry 时使用) */
|
|
32
32
|
entryRelPath?: string;
|
|
33
33
|
}): string;
|
|
34
34
|
/** 运行时参考文件的导出目录内相对路径(单一事实源) */
|
|
@@ -36,7 +36,7 @@ export declare const RUNTIME_REFERENCE_REL_PATH = "references/actiondock-runtime
|
|
|
36
36
|
export declare function generateSourceSkillMd(config: ProjectConfig, actions: SkillActionItem[], playbooks: SkillPlaybookItem[]): string;
|
|
37
37
|
export declare function generateStandaloneSkillMd(config: ProjectConfig, actions: SkillActionItem[], playbooks: SkillPlaybookItem[], binaryRelPath?: string): string;
|
|
38
38
|
export interface CompositeSkillPackageInfo {
|
|
39
|
-
config: ProjectConfig
|
|
39
|
+
config: ProjectConfig;
|
|
40
40
|
actions: Array<{
|
|
41
41
|
id: string;
|
|
42
42
|
description?: string;
|
|
@@ -54,8 +54,6 @@ 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";
|
|
59
57
|
/** 规程链接的子包目录前缀:导出布局为 "packages"(默认);就地生成时传 "." 使用工作区实际目录 */
|
|
60
58
|
packagesBaseDir?: string;
|
|
61
59
|
}): string;
|