@actiondock/builder 2.0.12 → 2.2.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 +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,16 @@
|
|
|
1
|
+
export declare function moveDirAtomic(src: string, dest: string): Promise<void>;
|
|
2
|
+
/**
|
|
3
|
+
* 递归收集目录内全部文件的相对路径(正斜杠分隔,名称排序)。
|
|
4
|
+
* 统一排序保证产物文件清单与内容摘要的确定性。
|
|
5
|
+
*/
|
|
6
|
+
export declare function collectRelativeFiles(dir: string, baseDir?: string): string[];
|
|
7
|
+
/**
|
|
8
|
+
* 获取内部 @actiondock/* 依赖的版本号规则。
|
|
9
|
+
* 预发布版本采用精确锁定,正式版本采用 ^ 语义范围。
|
|
10
|
+
*/
|
|
11
|
+
export declare function getInternalDependencyVersion(version?: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* 以新目录原子替换已存在的目标目录(含失败回滚保护)。
|
|
14
|
+
* promotion 失败后优先 backup -> target 回滚;只有新 target 完整成功后才能删除 backup。
|
|
15
|
+
*/
|
|
16
|
+
export declare function replaceDirAtomic(stagingDir: string, targetDir: string): Promise<void>;
|
package/dist/fs-utils.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { cpSync, existsSync, readdirSync, renameSync, rmSync, statSync } from "node:fs";
|
|
2
|
+
import { join, relative, sep } from "node:path";
|
|
3
|
+
import { ACTIONDOCK_VERSION } from "@actiondock/core";
|
|
4
|
+
/**
|
|
5
|
+
* builder 包内共享的文件系统基础设施。
|
|
6
|
+
* 消除 pack / build / exporter 三个业务模块中成体系的重复实现,
|
|
7
|
+
* 保证目录扫描排序与原子移动等关键行为存在单一事实源。
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* 跨文件系统/分区的原子移动目录辅助函数。
|
|
11
|
+
* 优先 rename,遇到瞬时性错误码按指数退避重试,最终回退为递归复制后删除。
|
|
12
|
+
*/
|
|
13
|
+
const TRANSIENT_MOVE_ERROR_CODES = new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
|
|
14
|
+
const MOVE_RETRY_ATTEMPTS = 5;
|
|
15
|
+
export async function moveDirAtomic(src, dest) {
|
|
16
|
+
let lastErr;
|
|
17
|
+
for (let attempt = 1; attempt <= MOVE_RETRY_ATTEMPTS; attempt++) {
|
|
18
|
+
try {
|
|
19
|
+
renameSync(src, dest);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
lastErr = err;
|
|
24
|
+
if (err?.code === "EXDEV") {
|
|
25
|
+
// 跨文件系统/分区,立即转入跨设备原子搬迁流程
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
if (!TRANSIENT_MOVE_ERROR_CODES.has(err?.code)) {
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
await new Promise((r) => setTimeout(r, 50 * attempt));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (lastErr?.code !== "EXDEV") {
|
|
35
|
+
throw lastErr;
|
|
36
|
+
}
|
|
37
|
+
// 跨设备场景:先复制到 dest 同父目录下的临时目录,再同设备 rename 保证 dest 提升的原子性
|
|
38
|
+
const tempDest = `${dest}.tmp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
39
|
+
try {
|
|
40
|
+
cpSync(src, tempDest, { recursive: true });
|
|
41
|
+
for (let attempt = 1; attempt <= MOVE_RETRY_ATTEMPTS; attempt++) {
|
|
42
|
+
try {
|
|
43
|
+
renameSync(tempDest, dest);
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (attempt === MOVE_RETRY_ATTEMPTS || !TRANSIENT_MOVE_ERROR_CODES.has(err?.code)) {
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
await new Promise((r) => setTimeout(r, 50 * attempt));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
rmSync(src, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
if (existsSync(tempDest)) {
|
|
57
|
+
try {
|
|
58
|
+
rmSync(tempDest, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// 忽略临时目录清理异常
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 递归收集目录内全部文件的相对路径(正斜杠分隔,名称排序)。
|
|
69
|
+
* 统一排序保证产物文件清单与内容摘要的确定性。
|
|
70
|
+
*/
|
|
71
|
+
export function collectRelativeFiles(dir, baseDir = dir) {
|
|
72
|
+
if (!existsSync(dir))
|
|
73
|
+
return [];
|
|
74
|
+
const results = [];
|
|
75
|
+
const entries = readdirSync(dir).sort();
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
const fullPath = join(dir, entry);
|
|
78
|
+
const stat = statSync(fullPath);
|
|
79
|
+
if (stat.isDirectory()) {
|
|
80
|
+
results.push(...collectRelativeFiles(fullPath, baseDir));
|
|
81
|
+
}
|
|
82
|
+
else if (stat.isFile()) {
|
|
83
|
+
results.push(relative(baseDir, fullPath).split(sep).join("/"));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 获取内部 @actiondock/* 依赖的版本号规则。
|
|
90
|
+
* 预发布版本采用精确锁定,正式版本采用 ^ 语义范围。
|
|
91
|
+
*/
|
|
92
|
+
export function getInternalDependencyVersion(version = ACTIONDOCK_VERSION) {
|
|
93
|
+
if (version.includes("-")) {
|
|
94
|
+
return version;
|
|
95
|
+
}
|
|
96
|
+
return `^${version}`;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 以新目录原子替换已存在的目标目录(含失败回滚保护)。
|
|
100
|
+
* promotion 失败后优先 backup -> target 回滚;只有新 target 完整成功后才能删除 backup。
|
|
101
|
+
*/
|
|
102
|
+
export async function replaceDirAtomic(stagingDir, targetDir) {
|
|
103
|
+
if (existsSync(targetDir)) {
|
|
104
|
+
const backupDir = `${targetDir}.old-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
105
|
+
await moveDirAtomic(targetDir, backupDir);
|
|
106
|
+
try {
|
|
107
|
+
await moveDirAtomic(stagingDir, targetDir);
|
|
108
|
+
}
|
|
109
|
+
catch (promoteErr) {
|
|
110
|
+
// staging 提升失败:清理可能残留的损坏目标目录,并将 backup 恢复至 targetDir
|
|
111
|
+
if (existsSync(targetDir)) {
|
|
112
|
+
try {
|
|
113
|
+
rmSync(targetDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// 忽略清理残余异常
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
await moveDirAtomic(backupDir, targetDir);
|
|
121
|
+
}
|
|
122
|
+
catch (rollbackErr) {
|
|
123
|
+
throw new Error(`Failed to promote directory to '${targetDir}' (${promoteErr instanceof Error ? promoteErr.message : String(promoteErr)}), and rollback from backup '${backupDir}' also failed: ${rollbackErr?.message || String(rollbackErr)}`);
|
|
124
|
+
}
|
|
125
|
+
throw promoteErr;
|
|
126
|
+
}
|
|
127
|
+
// 只有新 target 完整成功后才能删除 backup
|
|
128
|
+
rmSync(backupDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
try {
|
|
132
|
+
await moveDirAtomic(stagingDir, targetDir);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
if (existsSync(targetDir)) {
|
|
136
|
+
try {
|
|
137
|
+
rmSync(targetDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// 忽略清理残余异常
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
throw err;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
export
|
|
7
|
-
export
|
|
1
|
+
/**
|
|
2
|
+
* @actiondock/builder 公共导出面。
|
|
3
|
+
* 采用显式命名导出替代全量 export *,保证公开 API 边界清晰可控。
|
|
4
|
+
*/
|
|
5
|
+
export { BuilderError, PlannerError } from "./errors.js";
|
|
6
|
+
export { collectRelativeFiles, getInternalDependencyVersion, moveDirAtomic, replaceDirAtomic, } from "./fs-utils.js";
|
|
7
|
+
export { assertNoFileProtocolDeps, assertValidManifestActionIds, serializeManifestAction, serializeManifestPlaybooks, serializePlanManifest, } from "./manifest.js";
|
|
8
|
+
export type { SerializePlanManifestOptions } from "./manifest.js";
|
|
9
|
+
export { createTarGzArchive, createTarGzArchiveAsync, createZipArchive, createZipArchiveAsync, writeToStream, } from "./archive.js";
|
|
10
|
+
export type { TarGzArchiveOptions } from "./archive.js";
|
|
11
|
+
export { BuildPlanner, buildPlan, SelectionPlanner, selectionPlan } from "./planner.js";
|
|
12
|
+
export { assertRelativeDependenciesIntegrity, extractRelativeSpecifiers, resolveRelativeModule, } from "./dependency-check.js";
|
|
13
|
+
export { buildProject } from "./build.js";
|
|
14
|
+
export { packProject } from "./pack.js";
|
|
15
|
+
export { exportCompositeSkill, exportSkill, exportSkillBatch, findExistingCompositeSkillMd, findExistingSingleSkillMd, SkillExporter, } from "./exporter.js";
|
|
16
|
+
export type { ActionDependency, ArchiveFormat, AssetDependency, BatchSkillExportOptions, BatchSkillExportResult, BuildOptions, BuildPlan, BuildPlanDependencies, BuildPlannerOptions, BuildResult, CompositeSkillExportOptions, CompositeSkillExportResult, ExternalDependency, LockfileInfo, PackOptions, PackResult, PlaybookPlanEntry, ProjectConfigWithDeclarations, SelectionPlan, SelectionPlannerOptions, SkillExporterOptions, SkillExportResult, } from "./types.js";
|