@actiondock/builder 2.0.12 → 2.2.1
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 +46 -30
- package/dist/archive.d.ts +24 -3
- package/dist/archive.js +519 -0
- package/dist/build.d.ts +5 -37
- package/dist/build.js +576 -0
- package/dist/dependency-check.d.ts +14 -0
- package/dist/dependency-check.js +246 -0
- package/dist/errors.d.ts +3 -30
- package/dist/errors.js +22 -0
- package/dist/exporter.d.ts +24 -14
- package/dist/exporter.js +761 -0
- package/dist/fs-utils.d.ts +16 -0
- package/dist/fs-utils.js +146 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.js +21 -1875
- package/dist/manifest.d.ts +75 -0
- package/dist/manifest.js +213 -0
- package/dist/pack.d.ts +13 -0
- package/dist/pack.js +339 -0
- package/dist/planner.d.ts +51 -9
- package/dist/planner.js +681 -0
- package/dist/types.d.ts +204 -73
- package/dist/types.js +1 -0
- package/package.json +8 -9
- package/dist/compiler.d.ts +0 -22
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
3
|
+
import { isPathOutsideBoundary } from "@actiondock/core";
|
|
4
|
+
import { BuilderError } from "./errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* 移除源码中的单行与多行注释,防止注释内的相对路径字符串误触发依赖解析。
|
|
7
|
+
*/
|
|
8
|
+
function stripComments(source) {
|
|
9
|
+
return source.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, "");
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 从源码中快速提取以相对路径(./ 或 ../)引入的静态或动态导入说明符。
|
|
13
|
+
*/
|
|
14
|
+
export function extractRelativeSpecifiers(source) {
|
|
15
|
+
const cleanSource = stripComments(source);
|
|
16
|
+
const specifiers = new Set();
|
|
17
|
+
// 1. 无 from 的直接副作用导入:import "./side-effect.js"
|
|
18
|
+
const sideEffectRegex = /\bimport\s+['"](\.{1,2}(?:\/[^'"]*)?)['"]/g;
|
|
19
|
+
let match;
|
|
20
|
+
while ((match = sideEffectRegex.exec(cleanSource)) !== null) {
|
|
21
|
+
if (match[1]) {
|
|
22
|
+
specifiers.add(match[1]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// 2. 静态 import 与 export 携带 from 语句:import { x } from "./x.js", export * from "./y.js"
|
|
26
|
+
const fromRegex = /\b(?:import|export)(?:\s+type)?\s+(?:[^;"']*?)\s+from\s+['"](\.{1,2}(?:\/[^'"]*)?)['"]/g;
|
|
27
|
+
while ((match = fromRegex.exec(cleanSource)) !== null) {
|
|
28
|
+
if (match[1]) {
|
|
29
|
+
specifiers.add(match[1]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// 3. 动态 import() 与 require()
|
|
33
|
+
const dynamicRegex = /\b(?:import|require)\s*\(\s*['"](\.{1,2}(?:\/[^'"]*)?)['"]\s*\)/g;
|
|
34
|
+
while ((match = dynamicRegex.exec(cleanSource)) !== null) {
|
|
35
|
+
if (match[1]) {
|
|
36
|
+
specifiers.add(match[1]);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return Array.from(specifiers);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 支持的候选扩展名列表。
|
|
43
|
+
*/
|
|
44
|
+
const RESOLUTION_EXTENSIONS = [
|
|
45
|
+
"",
|
|
46
|
+
".ts",
|
|
47
|
+
".js",
|
|
48
|
+
".mts",
|
|
49
|
+
".mjs",
|
|
50
|
+
".tsx",
|
|
51
|
+
".jsx",
|
|
52
|
+
".cjs",
|
|
53
|
+
".cts",
|
|
54
|
+
".json",
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* 将相对模块说明符解析为磁盘上的物理真实文件路径。
|
|
58
|
+
*/
|
|
59
|
+
export function resolveRelativeModule(fromDir, specifier) {
|
|
60
|
+
const basePath = resolve(fromDir, specifier);
|
|
61
|
+
// 1. 精确匹配文件
|
|
62
|
+
if (existsSync(basePath) && statSync(basePath).isFile()) {
|
|
63
|
+
try {
|
|
64
|
+
return realpathSync(basePath);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return basePath;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// 2. ESM TypeScript 映射:导入写了 .js / .mjs / .cjs,但在源码中真实文件为 .ts / .mts / .cts
|
|
71
|
+
if (specifier.endsWith(".js")) {
|
|
72
|
+
const tsCandidate = basePath.slice(0, -3) + ".ts";
|
|
73
|
+
if (existsSync(tsCandidate) && statSync(tsCandidate).isFile()) {
|
|
74
|
+
try {
|
|
75
|
+
return realpathSync(tsCandidate);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return tsCandidate;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const tsxCandidate = basePath.slice(0, -3) + ".tsx";
|
|
82
|
+
if (existsSync(tsxCandidate) && statSync(tsxCandidate).isFile()) {
|
|
83
|
+
try {
|
|
84
|
+
return realpathSync(tsxCandidate);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return tsxCandidate;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (specifier.endsWith(".mjs")) {
|
|
92
|
+
const mtsCandidate = basePath.slice(0, -4) + ".mts";
|
|
93
|
+
if (existsSync(mtsCandidate) && statSync(mtsCandidate).isFile()) {
|
|
94
|
+
try {
|
|
95
|
+
return realpathSync(mtsCandidate);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return mtsCandidate;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (specifier.endsWith(".cjs")) {
|
|
103
|
+
const ctsCandidate = basePath.slice(0, -4) + ".cts";
|
|
104
|
+
if (existsSync(ctsCandidate) && statSync(ctsCandidate).isFile()) {
|
|
105
|
+
try {
|
|
106
|
+
return realpathSync(ctsCandidate);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return ctsCandidate;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 3. 补充扩展名尝试
|
|
114
|
+
for (const ext of RESOLUTION_EXTENSIONS) {
|
|
115
|
+
const cand = basePath + ext;
|
|
116
|
+
if (existsSync(cand) && statSync(cand).isFile()) {
|
|
117
|
+
try {
|
|
118
|
+
return realpathSync(cand);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return cand;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// 4. 目录默认 index 尝试
|
|
126
|
+
for (const ext of RESOLUTION_EXTENSIONS) {
|
|
127
|
+
if (ext === "")
|
|
128
|
+
continue;
|
|
129
|
+
const cand = join(basePath, `index${ext}`);
|
|
130
|
+
if (existsSync(cand) && statSync(cand).isFile()) {
|
|
131
|
+
try {
|
|
132
|
+
return realpathSync(cand);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return cand;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 断言 Action 源码中引用的本地相对模块已全部纳入导出规划。
|
|
143
|
+
* 若发现引用了未被 actions 或 files 声明收集的本地文件,直接抛出 BuilderError 终止构建。
|
|
144
|
+
*/
|
|
145
|
+
export function assertRelativeDependenciesIntegrity(projectRoot, plan) {
|
|
146
|
+
const root = resolve(projectRoot);
|
|
147
|
+
let realRoot;
|
|
148
|
+
try {
|
|
149
|
+
realRoot = existsSync(root) ? realpathSync(root) : root;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
realRoot = root;
|
|
153
|
+
}
|
|
154
|
+
// 收集已包含在构建规划中的全部文件物理绝对路径
|
|
155
|
+
const collectedPaths = new Set();
|
|
156
|
+
for (const act of plan.actions) {
|
|
157
|
+
if (act.resolvedPath) {
|
|
158
|
+
try {
|
|
159
|
+
const real = existsSync(act.resolvedPath)
|
|
160
|
+
? realpathSync(act.resolvedPath)
|
|
161
|
+
: resolve(act.resolvedPath);
|
|
162
|
+
collectedPaths.add(real);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
collectedPaths.add(resolve(act.resolvedPath));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
for (const dep of plan.dependencies.modulesAndAssets) {
|
|
170
|
+
if (dep.resolvedPath) {
|
|
171
|
+
try {
|
|
172
|
+
const real = existsSync(dep.resolvedPath)
|
|
173
|
+
? realpathSync(dep.resolvedPath)
|
|
174
|
+
: resolve(dep.resolvedPath);
|
|
175
|
+
collectedPaths.add(real);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
collectedPaths.add(resolve(dep.resolvedPath));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 待校验文件队列(包括全部 Action 及其收集的 TS/JS 模块)
|
|
183
|
+
const queue = [];
|
|
184
|
+
for (const act of plan.actions) {
|
|
185
|
+
if (act.resolvedPath && existsSync(act.resolvedPath)) {
|
|
186
|
+
try {
|
|
187
|
+
queue.push({
|
|
188
|
+
file: existsSync(act.resolvedPath)
|
|
189
|
+
? realpathSync(act.resolvedPath)
|
|
190
|
+
: resolve(act.resolvedPath),
|
|
191
|
+
actionId: act.id,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
queue.push({
|
|
196
|
+
file: resolve(act.resolvedPath),
|
|
197
|
+
actionId: act.id,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const visited = new Set();
|
|
203
|
+
while (queue.length > 0) {
|
|
204
|
+
const { file, actionId } = queue.shift();
|
|
205
|
+
if (visited.has(file))
|
|
206
|
+
continue;
|
|
207
|
+
visited.add(file);
|
|
208
|
+
let content;
|
|
209
|
+
try {
|
|
210
|
+
content = readFileSync(file, "utf-8");
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const specifiers = extractRelativeSpecifiers(content);
|
|
216
|
+
for (const specifier of specifiers) {
|
|
217
|
+
const resolvedTarget = resolveRelativeModule(dirname(file), specifier);
|
|
218
|
+
if (!resolvedTarget) {
|
|
219
|
+
// 相对路径对应的文件在磁盘上不存在
|
|
220
|
+
const relFromFile = relative(realRoot, file).replace(/\\/g, "/");
|
|
221
|
+
throw new BuilderError(`Action '${actionId}' (${relFromFile}) imports relative module '${specifier}', but the file does not exist on disk.`, "FILE_NOT_FOUND");
|
|
222
|
+
}
|
|
223
|
+
// 检查目标文件是否越出项目根目录
|
|
224
|
+
const relToRoot = relative(realRoot, resolvedTarget);
|
|
225
|
+
if (isPathOutsideBoundary(relToRoot) || resolve(resolvedTarget) === resolve(realRoot, "..")) {
|
|
226
|
+
throw new BuilderError(`Action '${actionId}' imports relative module '${specifier}', which resolves outside project root: '${resolvedTarget}'. External relative imports outside project root are not allowed in exported Skill packages.`, "EXTERNAL_LOCAL_DEPENDENCY");
|
|
227
|
+
}
|
|
228
|
+
// 检查目标文件是否在构建收集集合中
|
|
229
|
+
if (!collectedPaths.has(resolvedTarget)) {
|
|
230
|
+
const normalizedRel = relToRoot.replace(/\\/g, "/");
|
|
231
|
+
const fromRel = relative(realRoot, file).replace(/\\/g, "/");
|
|
232
|
+
throw new BuilderError(`Action '${actionId}' (${fromRel}) imports relative module '${specifier}' (resolving to '${normalizedRel}'), which is not included in the export plan.\nTo fix this, declare '${normalizedRel}' or its parent directory in the 'files' field of actiondock.json.`, "UNMET_LOCAL_DEPENDENCY");
|
|
233
|
+
}
|
|
234
|
+
// 如果引用的目标文件本身也是已收集的 TS/JS 代码文件,且尚未遍历过,加入队列递归检查
|
|
235
|
+
if ((resolvedTarget.endsWith(".ts") ||
|
|
236
|
+
resolvedTarget.endsWith(".js") ||
|
|
237
|
+
resolvedTarget.endsWith(".mts") ||
|
|
238
|
+
resolvedTarget.endsWith(".mjs") ||
|
|
239
|
+
resolvedTarget.endsWith(".tsx") ||
|
|
240
|
+
resolvedTarget.endsWith(".jsx")) &&
|
|
241
|
+
!visited.has(resolvedTarget)) {
|
|
242
|
+
queue.push({ file: resolvedTarget, actionId });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 构建模块基础错误类。
|
|
3
3
|
*/
|
|
4
4
|
export declare class BuilderError extends Error {
|
|
5
|
-
|
|
5
|
+
readonly code?: string;
|
|
6
|
+
constructor(message: string, code?: string);
|
|
6
7
|
}
|
|
7
8
|
/**
|
|
8
9
|
* 构建规划阶段抛出的错误。
|
|
@@ -11,31 +12,3 @@ export declare class PlannerError extends BuilderError {
|
|
|
11
12
|
readonly code: string;
|
|
12
13
|
constructor(message: string, code?: string);
|
|
13
14
|
}
|
|
14
|
-
/**
|
|
15
|
-
* 编译器参数与目标平台校验错误。
|
|
16
|
-
*/
|
|
17
|
-
export declare class CompilerValidationError extends BuilderError {
|
|
18
|
-
readonly code: string;
|
|
19
|
-
readonly target?: string;
|
|
20
|
-
constructor(message: string, options?: {
|
|
21
|
-
code?: string;
|
|
22
|
-
target?: string;
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* 编译器调用执行失败错误。包含标准化错误码与详情。
|
|
27
|
-
*/
|
|
28
|
-
export declare class CompilerError extends BuilderError {
|
|
29
|
-
readonly code: string;
|
|
30
|
-
readonly exitCode: number;
|
|
31
|
-
readonly rawError: string;
|
|
32
|
-
readonly details: string[];
|
|
33
|
-
readonly target?: string;
|
|
34
|
-
constructor(message: string, options: {
|
|
35
|
-
code: string;
|
|
36
|
-
exitCode: number;
|
|
37
|
-
rawError: string;
|
|
38
|
-
details?: string[];
|
|
39
|
-
target?: string;
|
|
40
|
-
});
|
|
41
|
-
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 构建模块基础错误类。
|
|
3
|
+
*/
|
|
4
|
+
export class BuilderError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(message, code) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "BuilderError";
|
|
9
|
+
this.code = code;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 构建规划阶段抛出的错误。
|
|
14
|
+
*/
|
|
15
|
+
export class PlannerError extends BuilderError {
|
|
16
|
+
code;
|
|
17
|
+
constructor(message, code = "PLANNER_ERROR") {
|
|
18
|
+
super(message, code);
|
|
19
|
+
this.name = "PlannerError";
|
|
20
|
+
this.code = code;
|
|
21
|
+
}
|
|
22
|
+
}
|
package/dist/exporter.d.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* 获取内部 @actiondock/* 依赖的版本号规则。
|
|
3
|
-
* 若为主干预发布版本(包含破折号如 -beta / -rc),直接对齐精确版本;普通正式版采用 ^ 范围约束。
|
|
4
|
-
*/
|
|
5
|
-
export declare function getInternalDependencyVersion(version?: string): string;
|
|
6
|
-
import type { BatchSkillExportOptions, BatchSkillExportResult, CompositeSkillExportOptions, CompositeSkillExportResult, SkillExporterOptions, SkillExportResult } from "./types";
|
|
1
|
+
import type { BatchSkillExportOptions, BatchSkillExportResult, CompositeSkillExportOptions, CompositeSkillExportResult, SkillExporterOptions, SkillExportResult } from "./types.js";
|
|
7
2
|
/**
|
|
8
3
|
* 检索单个 Action 项目目录中已存在的 SKILL.md 文件。
|
|
9
4
|
*/
|
|
@@ -14,22 +9,37 @@ export declare function findExistingSingleSkillMd(projectRoot: string, explicitP
|
|
|
14
9
|
export declare function findExistingCompositeSkillMd(options: CompositeSkillExportOptions): string | undefined;
|
|
15
10
|
/**
|
|
16
11
|
* Agent Skill 导出器。
|
|
17
|
-
* 负责源码型 Skill
|
|
12
|
+
* 负责源码型 Skill 与 Node 目录型 Skill 的构建、打包与分发。
|
|
18
13
|
*/
|
|
19
14
|
export declare class SkillExporter {
|
|
20
15
|
/**
|
|
21
16
|
* 导出 Skill 产物包。
|
|
17
|
+
* 主流程仅做编排,各阶段职责由独立函数承担。
|
|
22
18
|
*
|
|
23
19
|
* @param options 导出配置
|
|
24
20
|
* @returns 导出产物详细描述
|
|
25
21
|
*/
|
|
26
22
|
export(options: SkillExporterOptions): Promise<SkillExportResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Node 目录型 Skill 导出:复用 Node 目录型构建,并在 Skill 内生成调用该入口的 SKILL.md。
|
|
25
|
+
*/
|
|
26
|
+
private exportNodeSkill;
|
|
27
|
+
/**
|
|
28
|
+
* 源码型 Skill 导出:暂存目录内完成清单、说明书与源码装配后原子替换目标目录。
|
|
29
|
+
*/
|
|
30
|
+
private exportSourceSkill;
|
|
31
|
+
/**
|
|
32
|
+
* 静态辅助调用单个 Skill 导出方法。
|
|
33
|
+
* @deprecated 实例方法的历史便捷入口,请直接使用实例方法,将在两个版本后移除。
|
|
34
|
+
*/
|
|
35
|
+
static export(options: SkillExporterOptions): Promise<SkillExportResult>;
|
|
27
36
|
/**
|
|
28
37
|
* 批量导出多个 Skill。
|
|
29
38
|
*/
|
|
30
39
|
exportBatch(options: BatchSkillExportOptions): Promise<BatchSkillExportResult>;
|
|
31
40
|
/**
|
|
32
41
|
* 静态辅助调用批量导出方法。
|
|
42
|
+
* @deprecated 实例方法的历史便捷入口,请直接使用实例方法,将在两个版本后移除。
|
|
33
43
|
*/
|
|
34
44
|
static exportBatch(options: BatchSkillExportOptions): Promise<BatchSkillExportResult>;
|
|
35
45
|
/**
|
|
@@ -38,22 +48,22 @@ export declare class SkillExporter {
|
|
|
38
48
|
exportComposite(options: CompositeSkillExportOptions): Promise<CompositeSkillExportResult>;
|
|
39
49
|
/**
|
|
40
50
|
* 静态辅助调用复合导出方法。
|
|
51
|
+
* @deprecated 实例方法的历史便捷入口,请直接使用实例方法,将在两个版本后移除。
|
|
41
52
|
*/
|
|
42
53
|
static exportComposite(options: CompositeSkillExportOptions): Promise<CompositeSkillExportResult>;
|
|
43
|
-
/**
|
|
44
|
-
* 静态辅助调用方法。
|
|
45
|
-
*/
|
|
46
|
-
static export(options: SkillExporterOptions): Promise<SkillExportResult>;
|
|
47
54
|
}
|
|
48
55
|
/**
|
|
49
|
-
*
|
|
56
|
+
* 导出单个 Skill 产物的顶层便捷函数。
|
|
57
|
+
* @deprecated SkillExporter 实例与静态方法之外的历史第三入口,请直接使用 SkillExporter 实例,将在两个版本后移除。
|
|
50
58
|
*/
|
|
51
59
|
export declare function exportSkill(options: SkillExporterOptions): Promise<SkillExportResult>;
|
|
52
60
|
/**
|
|
53
|
-
*
|
|
61
|
+
* 批量导出多个 Skill 产物的顶层便捷函数。
|
|
62
|
+
* @deprecated SkillExporter 实例与静态方法之外的历史第三入口,请直接使用 SkillExporter 实例,将在两个版本后移除。
|
|
54
63
|
*/
|
|
55
64
|
export declare function exportSkillBatch(options: BatchSkillExportOptions): Promise<BatchSkillExportResult>;
|
|
56
65
|
/**
|
|
57
|
-
*
|
|
66
|
+
* 导出复合技能套件的顶层便捷函数。
|
|
67
|
+
* @deprecated SkillExporter 实例与静态方法之外的历史第三入口,请直接使用 SkillExporter 实例,将在两个版本后移除。
|
|
58
68
|
*/
|
|
59
69
|
export declare function exportCompositeSkill(options: CompositeSkillExportOptions): Promise<CompositeSkillExportResult>;
|