@actiondock/core 2.0.11 → 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 +61 -30
- package/dist/app/app.d.ts +73 -0
- package/dist/app/app.js +700 -0
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +2 -0
- package/dist/app/types.d.ts +283 -0
- package/dist/app/types.js +1 -0
- package/dist/catalog/action-index.d.ts +9 -0
- package/dist/catalog/action-index.js +93 -0
- package/dist/catalog/action-resolver.d.ts +20 -0
- package/dist/catalog/action-resolver.js +95 -0
- package/dist/catalog/index.d.ts +5 -0
- package/dist/catalog/index.js +5 -0
- package/dist/catalog/location-registry.d.ts +15 -0
- package/dist/catalog/location-registry.js +138 -0
- package/dist/catalog/package-catalog.d.ts +7 -0
- package/dist/catalog/package-catalog.js +76 -0
- package/dist/catalog/types.d.ts +68 -0
- package/dist/catalog/types.js +1 -0
- package/dist/doctor/doctor.d.ts +7 -0
- package/dist/doctor/doctor.js +613 -0
- package/dist/doctor/index.d.ts +2 -0
- package/dist/doctor/index.js +2 -0
- package/dist/doctor/types.d.ts +23 -0
- package/dist/doctor/types.js +1 -0
- package/dist/errors.d.ts +122 -0
- package/dist/errors.js +123 -0
- package/dist/execution/index.d.ts +2 -0
- package/dist/execution/index.js +2 -0
- package/dist/execution/service.d.ts +79 -0
- package/dist/execution/service.js +633 -0
- package/dist/execution/types.d.ts +131 -0
- package/dist/execution/types.js +1 -0
- package/dist/export/index.d.ts +1 -0
- package/dist/export/index.js +1 -0
- package/dist/export/templates.d.ts +71 -0
- package/dist/export/templates.js +621 -0
- package/dist/filter/index.d.ts +1 -0
- package/dist/filter/index.js +1 -0
- package/dist/filter/intent.d.ts +33 -0
- package/dist/filter/intent.js +123 -0
- package/dist/host/host.d.ts +55 -0
- package/dist/host/host.js +740 -0
- package/dist/host/index.d.ts +2 -0
- package/dist/host/index.js +2 -0
- package/dist/host/types.d.ts +81 -0
- package/dist/host/types.js +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +20 -0
- package/dist/ipc/diagnostic.d.ts +65 -0
- package/dist/ipc/diagnostic.js +129 -0
- package/dist/ipc/host.d.ts +7 -0
- package/dist/ipc/host.js +93 -0
- package/dist/ipc/index.d.ts +4 -0
- package/dist/ipc/index.js +4 -0
- package/dist/ipc/target.d.ts +56 -0
- package/dist/ipc/target.js +297 -0
- package/dist/ipc/types.d.ts +42 -0
- package/dist/ipc/types.js +1 -0
- package/dist/platform/default.d.ts +32 -0
- package/dist/platform/default.js +40 -0
- package/dist/platform/index.d.ts +3 -0
- package/dist/platform/index.js +3 -0
- package/dist/platform/node-fs.d.ts +37 -0
- package/dist/platform/node-fs.js +81 -0
- package/dist/platform/types.d.ts +104 -0
- package/dist/platform/types.js +1 -0
- package/dist/profile/client.d.ts +162 -0
- package/dist/profile/client.js +467 -0
- package/dist/profile/index.d.ts +3 -0
- package/dist/profile/index.js +3 -0
- package/dist/profile/manager.d.ts +47 -0
- package/dist/profile/manager.js +294 -0
- package/dist/profile/types.d.ts +61 -0
- package/dist/profile/types.js +1 -0
- package/dist/project/closure.d.ts +25 -0
- package/dist/project/closure.js +68 -0
- package/dist/project/digest.d.ts +29 -0
- package/dist/project/digest.js +324 -0
- package/dist/project/index.d.ts +10 -0
- package/dist/project/index.js +10 -0
- package/dist/project/init.d.ts +26 -0
- package/dist/project/init.js +175 -0
- package/dist/project/loader.d.ts +99 -0
- package/dist/project/loader.js +484 -0
- package/dist/project/lockfile.d.ts +55 -0
- package/dist/project/lockfile.js +175 -0
- package/dist/project/manifest.d.ts +22 -0
- package/dist/project/manifest.js +220 -0
- package/dist/project/resolver.d.ts +116 -0
- package/dist/project/resolver.js +376 -0
- package/dist/project/transactions.d.ts +103 -0
- package/dist/project/transactions.js +1203 -0
- package/dist/project/types-generator.d.ts +33 -0
- package/dist/project/types-generator.js +168 -0
- package/dist/project/types.d.ts +107 -0
- package/dist/project/types.js +1 -0
- package/dist/registry/index.d.ts +5 -0
- package/dist/registry/index.js +5 -0
- package/dist/registry/lock.d.ts +27 -0
- package/dist/registry/lock.js +93 -0
- package/dist/registry/registry.d.ts +45 -0
- package/dist/registry/registry.js +611 -0
- package/dist/registry/resolve.d.ts +62 -0
- package/dist/registry/resolve.js +195 -0
- package/dist/registry/scan.d.ts +38 -0
- package/dist/registry/scan.js +135 -0
- package/dist/registry/types.d.ts +117 -0
- package/dist/registry/types.js +1 -0
- package/dist/runtime/action-collection.d.ts +27 -0
- package/dist/runtime/action-collection.js +57 -0
- package/dist/runtime/clock.d.ts +19 -0
- package/dist/runtime/clock.js +17 -0
- package/dist/runtime/context.d.ts +86 -0
- package/dist/runtime/context.js +242 -0
- package/dist/runtime/env.d.ts +56 -0
- package/dist/runtime/env.js +159 -0
- package/dist/runtime/events.d.ts +93 -0
- package/dist/runtime/events.js +604 -0
- package/dist/runtime/execution-manager.d.ts +48 -0
- package/dist/runtime/execution-manager.js +66 -0
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/module-loader.d.ts +34 -0
- package/dist/runtime/module-loader.js +16 -0
- package/dist/runtime/process.d.ts +9 -0
- package/dist/runtime/process.js +146 -0
- package/dist/runtime/runner.d.ts +293 -0
- package/dist/runtime/runner.js +984 -0
- package/dist/runtime/standalone.d.ts +89 -0
- package/dist/runtime/standalone.js +536 -0
- package/dist/schema/validator.d.ts +28 -0
- package/dist/schema/validator.js +116 -0
- package/dist/server/body.d.ts +40 -0
- package/dist/server/body.js +93 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +5 -0
- package/dist/server/routes/actions.d.ts +5 -0
- package/dist/server/routes/actions.js +298 -0
- package/dist/server/routes/common.d.ts +47 -0
- package/dist/server/routes/common.js +104 -0
- package/dist/server/routes/config.d.ts +6 -0
- package/dist/server/routes/config.js +173 -0
- package/dist/server/routes/doctor.d.ts +5 -0
- package/dist/server/routes/doctor.js +63 -0
- package/dist/server/routes/health.d.ts +5 -0
- package/dist/server/routes/health.js +35 -0
- package/dist/server/routes/index.d.ts +9 -0
- package/dist/server/routes/index.js +9 -0
- package/dist/server/routes/info.d.ts +7 -0
- package/dist/server/routes/info.js +158 -0
- package/dist/server/routes/playbooks.d.ts +5 -0
- package/dist/server/routes/playbooks.js +134 -0
- package/dist/server/routes/runs.d.ts +5 -0
- package/dist/server/routes/runs.js +343 -0
- package/dist/server/routes/state.d.ts +6 -0
- package/dist/server/routes/state.js +169 -0
- package/dist/server/security.d.ts +44 -0
- package/dist/server/security.js +101 -0
- package/dist/server/server.d.ts +15 -0
- package/dist/server/server.js +355 -0
- package/dist/server/types.d.ts +78 -0
- package/dist/server/types.js +1 -0
- package/dist/storage/data-dir-lock.d.ts +119 -0
- package/dist/storage/data-dir-lock.js +1016 -0
- package/dist/storage/driver.d.ts +9 -0
- package/dist/storage/driver.js +59 -0
- package/dist/storage/index.d.ts +64 -0
- package/dist/storage/index.js +98 -0
- package/dist/storage/lazy.d.ts +8 -0
- package/dist/storage/lazy.js +44 -0
- package/dist/storage/mask.d.ts +26 -0
- package/dist/storage/mask.js +48 -0
- package/dist/storage/params.d.ts +13 -0
- package/dist/storage/params.js +32 -0
- package/dist/storage/sqlite.d.ts +79 -0
- package/dist/storage/sqlite.js +689 -0
- package/dist/storage/types.d.ts +172 -0
- package/dist/storage/types.js +14 -0
- package/dist/target/index.d.ts +4 -0
- package/dist/target/index.js +4 -0
- package/dist/target/local.d.ts +52 -0
- package/dist/target/local.js +343 -0
- package/dist/target/remote.d.ts +76 -0
- package/dist/target/remote.js +839 -0
- package/dist/target/target.d.ts +6 -0
- package/dist/target/target.js +35 -0
- package/dist/target/types.d.ts +246 -0
- package/dist/target/types.js +34 -0
- package/dist/utils/index.d.ts +49 -0
- package/dist/utils/index.js +180 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +4 -0
- package/package.json +13 -13
- package/src/build/index.ts +0 -1
- package/src/build/templates.ts +0 -59
- package/src/catalog/action-index.ts +0 -92
- package/src/catalog/action-resolver.ts +0 -120
- package/src/catalog/index.ts +0 -5
- package/src/catalog/location-registry.ts +0 -134
- package/src/catalog/package-catalog.ts +0 -87
- package/src/catalog/types.ts +0 -75
- package/src/doctor/doctor.ts +0 -419
- package/src/doctor/index.ts +0 -2
- package/src/doctor/types.ts +0 -25
- package/src/execution/index.ts +0 -2
- package/src/execution/service.ts +0 -322
- package/src/execution/types.ts +0 -73
- package/src/export/index.ts +0 -1
- package/src/export/templates.ts +0 -590
- package/src/filter/index.ts +0 -1
- package/src/filter/intent.ts +0 -154
- package/src/index.ts +0 -16
- package/src/profile/client.ts +0 -552
- package/src/profile/index.ts +0 -3
- package/src/profile/manager.ts +0 -341
- package/src/profile/types.ts +0 -71
- package/src/project/index.ts +0 -4
- package/src/project/init.ts +0 -242
- package/src/project/loader.ts +0 -479
- package/src/project/manifest.ts +0 -299
- package/src/project/types.ts +0 -141
- package/src/registry/index.ts +0 -2
- package/src/registry/registry.ts +0 -940
- package/src/registry/types.ts +0 -127
- package/src/runtime/clock.ts +0 -41
- package/src/runtime/context.ts +0 -259
- package/src/runtime/env.ts +0 -172
- package/src/runtime/events.ts +0 -142
- package/src/runtime/execution-manager.ts +0 -74
- package/src/runtime/index.ts +0 -10
- package/src/runtime/module-loader.ts +0 -67
- package/src/runtime/process.ts +0 -245
- package/src/runtime/runner.ts +0 -527
- package/src/runtime/standalone.ts +0 -429
- package/src/schema/validator.ts +0 -61
- package/src/server/body.ts +0 -112
- package/src/server/index.ts +0 -7
- package/src/server/routes/actions.ts +0 -262
- package/src/server/routes/common.ts +0 -126
- package/src/server/routes/config.ts +0 -147
- package/src/server/routes/doctor.ts +0 -29
- package/src/server/routes/health.ts +0 -40
- package/src/server/routes/index.ts +0 -9
- package/src/server/routes/info.ts +0 -221
- package/src/server/routes/playbooks.ts +0 -109
- package/src/server/routes/runs.ts +0 -301
- package/src/server/routes/state.ts +0 -133
- package/src/server/runtime-registry.ts +0 -115
- package/src/server/security.ts +0 -115
- package/src/server/server.ts +0 -251
- package/src/server/types.ts +0 -57
- package/src/storage/driver.ts +0 -126
- package/src/storage/index.ts +0 -81
- package/src/storage/mask.ts +0 -34
- package/src/storage/sqlite.ts +0 -714
- package/src/storage/types.ts +0 -139
- package/src/utils/index.ts +0 -62
package/src/project/loader.ts
DELETED
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
5
|
-
import { pathToFileURL } from "node:url";
|
|
6
|
-
import YAML from "yaml";
|
|
7
|
-
import type { ActionDefinition } from "@actiondock/sdk";
|
|
8
|
-
import { getModuleLoader } from "../runtime/module-loader";
|
|
9
|
-
import type { PlaybookDefinition, PlaybookFrontmatter, ProjectConfig } from "./types";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* 将绝对路径规范化为 ESM 动态导入可用的 file:// URL 标识符。
|
|
13
|
-
* Windows 绝对路径(如 D:\a\b.ts)不是合法的 ESM 标识符,会被解析为 "d:" 协议导致
|
|
14
|
-
* 加载失败;POSIX 绝对路径虽可直接导入,统一转换后跨平台行为一致。
|
|
15
|
-
*/
|
|
16
|
-
function toImportSpecifier(filePath: string): string {
|
|
17
|
-
return pathToFileURL(filePath).href;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* 从指定目录开始向上逐级递归查找包含 `actiondock.json` 的项目根目录。
|
|
22
|
-
*
|
|
23
|
-
* @param cwd 起始搜索目录(默认为 process.cwd())
|
|
24
|
-
* @returns 项目根目录绝对路径,若未找到则返回 null
|
|
25
|
-
*/
|
|
26
|
-
export function findProjectRoot(cwd?: string): string | null {
|
|
27
|
-
let current: string;
|
|
28
|
-
try {
|
|
29
|
-
current = resolve(cwd || process.cwd());
|
|
30
|
-
} catch {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
while (true) {
|
|
34
|
-
try {
|
|
35
|
-
const configPath = join(current, "actiondock.json");
|
|
36
|
-
if (existsSync(configPath)) {
|
|
37
|
-
return current;
|
|
38
|
-
}
|
|
39
|
-
} catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
const parent = dirname(current);
|
|
43
|
-
if (parent === current) {
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
current = parent;
|
|
47
|
-
}
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 加载并校验指定目录下的 `actiondock.json` 配置文件。
|
|
53
|
-
*
|
|
54
|
-
* @param projectRoot 项目根目录绝对路径
|
|
55
|
-
* @returns 解析后的 ProjectConfig 对象
|
|
56
|
-
* @throws {Error} 若文件不存在或 JSON 格式错误、缺失必要字段
|
|
57
|
-
*/
|
|
58
|
-
export function loadProjectConfig(projectRoot: string): ProjectConfig {
|
|
59
|
-
const configPath = join(projectRoot, "actiondock.json");
|
|
60
|
-
if (!existsSync(configPath)) {
|
|
61
|
-
throw new Error(`actiondock.json not found in ${projectRoot}`);
|
|
62
|
-
}
|
|
63
|
-
const content = readFileSync(configPath, "utf-8");
|
|
64
|
-
try {
|
|
65
|
-
const parsed = JSON.parse(content);
|
|
66
|
-
if (!parsed.id || typeof parsed.id !== "string") {
|
|
67
|
-
throw new Error("actiondock.json missing required 'id' field");
|
|
68
|
-
}
|
|
69
|
-
if (!parsed.name || typeof parsed.name !== "string") {
|
|
70
|
-
parsed.name = parsed.id;
|
|
71
|
-
}
|
|
72
|
-
if (!parsed.version || typeof parsed.version !== "string") {
|
|
73
|
-
parsed.version = "0.1.0";
|
|
74
|
-
}
|
|
75
|
-
parsed.actionsDir = parsed.actionsDir || "actions";
|
|
76
|
-
parsed.playbooksDir = parsed.playbooksDir || "playbooks";
|
|
77
|
-
return parsed as ProjectConfig;
|
|
78
|
-
} catch (err: any) {
|
|
79
|
-
throw new Error(`Failed to parse actiondock.json: ${err.message}`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 探测宿主系统中可用的包管理工具(优先级:pnpm > npm > yarn > bun)。
|
|
85
|
-
* 可通过环境变量 ACTIONDOCK_INSTALLER 强制指定(如 npm、pnpm、yarn、bun)。
|
|
86
|
-
* 探测必须经 shell 执行:Windows 下 npm/pnpm/yarn 均为 .cmd 垫片,
|
|
87
|
-
* 不经 shell 的 spawnSync 无法解析,将错误地回退到原生 exe 的 bun。
|
|
88
|
-
*/
|
|
89
|
-
function getInstallCommand(): string[] {
|
|
90
|
-
const preferred = process.env.ACTIONDOCK_INSTALLER?.trim();
|
|
91
|
-
if (preferred) {
|
|
92
|
-
return [preferred, "install"];
|
|
93
|
-
}
|
|
94
|
-
const candidates: [string, string][] = [
|
|
95
|
-
["pnpm", "install"],
|
|
96
|
-
["npm", "install"],
|
|
97
|
-
["yarn", "install"],
|
|
98
|
-
["bun", "install"],
|
|
99
|
-
];
|
|
100
|
-
for (const [pm, action] of candidates) {
|
|
101
|
-
try {
|
|
102
|
-
const check = spawnSync(`${pm} --version`, {
|
|
103
|
-
stdio: "pipe",
|
|
104
|
-
shell: true,
|
|
105
|
-
});
|
|
106
|
-
if (check.status === 0) {
|
|
107
|
-
return [pm, action];
|
|
108
|
-
}
|
|
109
|
-
} catch {
|
|
110
|
-
// 继续探测下一个候选包管理器
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return ["npm", "install"];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* 解析 npm 风格 .npmrc 中的 strict-ssl 配置(项目级优先于用户级)。
|
|
118
|
-
* 返回 undefined 表示各级配置均未声明该键。
|
|
119
|
-
*/
|
|
120
|
-
function resolveNpmStrictSsl(projectRoot: string): boolean | undefined {
|
|
121
|
-
const configPaths = [join(projectRoot, ".npmrc"), join(homedir(), ".npmrc")];
|
|
122
|
-
for (const configPath of configPaths) {
|
|
123
|
-
try {
|
|
124
|
-
if (!existsSync(configPath)) continue;
|
|
125
|
-
const raw = readFileSync(configPath, "utf-8");
|
|
126
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
127
|
-
const matched = line.match(/^\s*strict-ssl\s*=\s*(\S+)\s*$/i);
|
|
128
|
-
if (matched) {
|
|
129
|
-
const falsy = ["false", "0", "no", "off"];
|
|
130
|
-
return !falsy.includes(matched[1].toLowerCase());
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
} catch {
|
|
134
|
-
// 配置不可读时继续检查下一级
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* 确保项目依赖(node_modules)已正确安装。
|
|
142
|
-
* 若尚未安装或加载失败时,自动触发包管理器执行依赖安装。
|
|
143
|
-
*
|
|
144
|
-
* @param projectRoot 项目根目录
|
|
145
|
-
* @param force 是否强制重新安装
|
|
146
|
-
* @returns 是否成功执行了安装
|
|
147
|
-
*/
|
|
148
|
-
export function ensureProjectDependencies(projectRoot: string, force = false): boolean {
|
|
149
|
-
if (process.env.ACTIONDOCK_AUTO_INSTALL === "false") {
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
const pkgJsonPath = join(projectRoot, "package.json");
|
|
153
|
-
if (!existsSync(pkgJsonPath)) {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const nodeModulesPath = join(projectRoot, "node_modules");
|
|
158
|
-
if (!force && existsSync(nodeModulesPath)) {
|
|
159
|
-
return false;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
const raw = readFileSync(pkgJsonPath, "utf-8");
|
|
164
|
-
const pkg = JSON.parse(raw);
|
|
165
|
-
const hasDeps =
|
|
166
|
-
(pkg.dependencies && Object.keys(pkg.dependencies).length > 0) ||
|
|
167
|
-
(pkg.devDependencies && Object.keys(pkg.devDependencies).length > 0);
|
|
168
|
-
|
|
169
|
-
if (!hasDeps && !force) {
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const installCmd = getInstallCommand();
|
|
174
|
-
process.stderr.write(
|
|
175
|
-
`[actiondock] Installing dependencies using ${installCmd[0]} for '${pkg.name || basename(projectRoot)}'...\n`
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
// bun 不读取 .npmrc 的 strict-ssl 配置;当 npm 侧已声明 strict-ssl=false 时,
|
|
179
|
-
// 桥接为 bun 子进程的 NODE_TLS_REJECT_UNAUTHORIZED=0,保证内网自签名证书源下行为一致
|
|
180
|
-
const childEnv = { ...process.env };
|
|
181
|
-
if (installCmd[0] === "bun" && resolveNpmStrictSsl(projectRoot) === false) {
|
|
182
|
-
childEnv.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// shell 模式下须传入单一命令字符串;候选命令均来自内置白名单,无注入面
|
|
186
|
-
const proc = spawnSync(installCmd.join(" "), {
|
|
187
|
-
cwd: projectRoot,
|
|
188
|
-
stdio: "pipe",
|
|
189
|
-
shell: true,
|
|
190
|
-
env: childEnv,
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
if (proc.status !== 0) {
|
|
194
|
-
const errText = proc.stderr?.toString() || `Unknown error during ${installCmd[0]} install`;
|
|
195
|
-
process.stderr.write(`[actiondock] Warning: Dependency installation failed: ${errText}\n`);
|
|
196
|
-
if (installCmd[0] === "bun" && /SELF_SIGNED_CERT|CERT_|UNABLE_TO_VERIFY|ERR_TLS/i.test(errText)) {
|
|
197
|
-
process.stderr.write(
|
|
198
|
-
`[actiondock] Hint: bun ignores 'strict-ssl=false' from .npmrc. ` +
|
|
199
|
-
`Add 'strict-ssl=false' to the project or user .npmrc, or set ACTIONDOCK_INSTALLER=npm.\n`
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
process.stderr.write(`[actiondock] Dependencies installed successfully.\n`);
|
|
206
|
-
return true;
|
|
207
|
-
} catch (err: any) {
|
|
208
|
-
process.stderr.write(`[actiondock] Warning: Failed to run auto-install: ${err.message}\n`);
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* 递归扫描指定目录下的特定后缀文件(自动排除测试文件 *.test.ts, *.spec.ts 和 *.d.ts)。
|
|
215
|
-
*/
|
|
216
|
-
function scanFiles(dir: string, extension: string): string[] {
|
|
217
|
-
if (!existsSync(dir)) return [];
|
|
218
|
-
const results: string[] = [];
|
|
219
|
-
|
|
220
|
-
function walk(current: string) {
|
|
221
|
-
const entries = readdirSync(current);
|
|
222
|
-
for (const entry of entries) {
|
|
223
|
-
const fullPath = join(current, entry);
|
|
224
|
-
const stat = statSync(fullPath);
|
|
225
|
-
if (stat.isDirectory()) {
|
|
226
|
-
walk(fullPath);
|
|
227
|
-
} else if (stat.isFile() && fullPath.endsWith(extension)) {
|
|
228
|
-
// 排除测试与类型声明文件
|
|
229
|
-
if (
|
|
230
|
-
!fullPath.endsWith(".test.ts") &&
|
|
231
|
-
!fullPath.endsWith(".spec.ts") &&
|
|
232
|
-
!fullPath.endsWith(".d.ts")
|
|
233
|
-
) {
|
|
234
|
-
results.push(fullPath);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
walk(dir);
|
|
241
|
-
return results;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* 发现并检索项目 actions 目录下的所有 Action 源码文件(.ts)。
|
|
246
|
-
*
|
|
247
|
-
* @param projectRoot 项目根目录
|
|
248
|
-
* @param actionsDir actions 子目录名称(默认 "actions")
|
|
249
|
-
*/
|
|
250
|
-
export function discoverActionFiles(
|
|
251
|
-
projectRoot: string,
|
|
252
|
-
actionsDir = "actions"
|
|
253
|
-
): string[] {
|
|
254
|
-
const fullDir = join(projectRoot, actionsDir);
|
|
255
|
-
return scanFiles(fullDir, ".ts");
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* 动态导入并加载项目下的所有 Action 定义对象。
|
|
260
|
-
*
|
|
261
|
-
* @param projectRoot 项目根目录
|
|
262
|
-
* @param actionsDir actions 子目录(默认 "actions")
|
|
263
|
-
* @param options 控制是否允许自动安装依赖等选项
|
|
264
|
-
* @returns Map<ActionId, ActionDefinition> 映射
|
|
265
|
-
*/
|
|
266
|
-
export async function loadActions(
|
|
267
|
-
projectRoot: string,
|
|
268
|
-
actionsDir = "actions",
|
|
269
|
-
options: { autoInstall?: boolean } = { autoInstall: true }
|
|
270
|
-
): Promise<Map<string, ActionDefinition>> {
|
|
271
|
-
if (options.autoInstall !== false) {
|
|
272
|
-
ensureProjectDependencies(projectRoot);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const files = discoverActionFiles(projectRoot, actionsDir);
|
|
276
|
-
const actions = new Map<string, ActionDefinition>();
|
|
277
|
-
const loader = getModuleLoader();
|
|
278
|
-
|
|
279
|
-
for (const file of files) {
|
|
280
|
-
try {
|
|
281
|
-
// 动态导入,若缺失模块则自动触发依赖重装与二次重试
|
|
282
|
-
let imported: any;
|
|
283
|
-
try {
|
|
284
|
-
imported = await loader.load(file);
|
|
285
|
-
} catch (err: any) {
|
|
286
|
-
const msg = String(err.message || "");
|
|
287
|
-
if (
|
|
288
|
-
options.autoInstall !== false &&
|
|
289
|
-
(msg.includes("Cannot find package") ||
|
|
290
|
-
msg.includes("Cannot find module") ||
|
|
291
|
-
msg.includes("ERR_MODULE_NOT_FOUND") ||
|
|
292
|
-
msg.includes("Could not resolve"))
|
|
293
|
-
) {
|
|
294
|
-
const installed = ensureProjectDependencies(projectRoot, true);
|
|
295
|
-
if (installed) {
|
|
296
|
-
imported = await loader.load(file);
|
|
297
|
-
} else {
|
|
298
|
-
throw err;
|
|
299
|
-
}
|
|
300
|
-
} else {
|
|
301
|
-
throw err;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const action = imported.default || imported.action;
|
|
306
|
-
if (action && typeof action === "object" && typeof action.id === "string") {
|
|
307
|
-
if (actions.has(action.id)) {
|
|
308
|
-
throw new Error(
|
|
309
|
-
`Duplicate action ID '${action.id}' found in ${file} (previously loaded)`
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
actions.set(action.id, action);
|
|
313
|
-
} else {
|
|
314
|
-
console.warn(
|
|
315
|
-
`[WARN] File ${file} does not export a valid default ActionDefinition`
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
} catch (err: any) {
|
|
319
|
-
throw new Error(`Failed to load action from ${file}: ${err.message}`);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return actions;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Action 文件映射条目,包含 Action ID、源文件绝对路径与 Action 定义对象。
|
|
328
|
-
*/
|
|
329
|
-
export interface ActionFileEntry {
|
|
330
|
-
id: string;
|
|
331
|
-
filePath: string;
|
|
332
|
-
action: ActionDefinition;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* 加载并建立 Action ID 与其物理源码文件路径之间的映射关系(供构建打包器及清单同步使用)。
|
|
337
|
-
*/
|
|
338
|
-
export async function loadActionFileMap(
|
|
339
|
-
projectRoot: string,
|
|
340
|
-
actionsDir = "actions",
|
|
341
|
-
options: { autoInstall?: boolean; strict?: boolean } = { autoInstall: true, strict: false }
|
|
342
|
-
): Promise<Map<string, ActionFileEntry>> {
|
|
343
|
-
if (options.autoInstall !== false) {
|
|
344
|
-
ensureProjectDependencies(projectRoot);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const files = discoverActionFiles(projectRoot, actionsDir);
|
|
348
|
-
const map = new Map<string, ActionFileEntry>();
|
|
349
|
-
const loader = getModuleLoader();
|
|
350
|
-
|
|
351
|
-
for (const file of files) {
|
|
352
|
-
try {
|
|
353
|
-
let imported: any;
|
|
354
|
-
try {
|
|
355
|
-
imported = await loader.load(file);
|
|
356
|
-
} catch (err: any) {
|
|
357
|
-
const msg = String(err.message || "");
|
|
358
|
-
if (
|
|
359
|
-
options.autoInstall !== false &&
|
|
360
|
-
(msg.includes("Cannot find package") ||
|
|
361
|
-
msg.includes("Cannot find module") ||
|
|
362
|
-
msg.includes("ERR_MODULE_NOT_FOUND") ||
|
|
363
|
-
msg.includes("Could not resolve"))
|
|
364
|
-
) {
|
|
365
|
-
const installed = ensureProjectDependencies(projectRoot, true);
|
|
366
|
-
if (installed) {
|
|
367
|
-
imported = await loader.load(file);
|
|
368
|
-
} else {
|
|
369
|
-
throw err;
|
|
370
|
-
}
|
|
371
|
-
} else {
|
|
372
|
-
throw err;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const act = imported.default || imported.action;
|
|
377
|
-
if (act && typeof act === "object" && typeof act.id === "string") {
|
|
378
|
-
if (map.has(act.id)) {
|
|
379
|
-
throw new Error(
|
|
380
|
-
`Duplicate action ID '${act.id}' found in ${file} (previously loaded from ${map.get(act.id)!.filePath})`
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
map.set(act.id, {
|
|
384
|
-
id: act.id,
|
|
385
|
-
filePath: resolve(file),
|
|
386
|
-
action: act,
|
|
387
|
-
});
|
|
388
|
-
} else if (options.strict) {
|
|
389
|
-
console.warn(`[WARN] File ${file} does not export a valid default ActionDefinition`);
|
|
390
|
-
}
|
|
391
|
-
} catch (err: any) {
|
|
392
|
-
if (options.strict) {
|
|
393
|
-
throw new Error(`Failed to load action from ${file}: ${err.message}`);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return map;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
* 发现项目 playbooks 目录下的所有 Playbook Markdown 文档(.md)。
|
|
403
|
-
*/
|
|
404
|
-
export function discoverPlaybookFiles(
|
|
405
|
-
projectRoot: string,
|
|
406
|
-
playbooksDir = "playbooks"
|
|
407
|
-
): string[] {
|
|
408
|
-
const fullDir = join(projectRoot, playbooksDir);
|
|
409
|
-
return scanFiles(fullDir, ".md");
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* 解析单个 Playbook Markdown 文件的内容与 YAML Frontmatter 头部元数据。
|
|
414
|
-
*
|
|
415
|
-
* @param content 文件文本内容
|
|
416
|
-
* @param filePath 物理文件路径
|
|
417
|
-
* @returns PlaybookDefinition 对象
|
|
418
|
-
*/
|
|
419
|
-
export function parsePlaybookContent(
|
|
420
|
-
content: string,
|
|
421
|
-
filePath: string
|
|
422
|
-
): PlaybookDefinition {
|
|
423
|
-
let frontmatter: Partial<PlaybookFrontmatter> = {};
|
|
424
|
-
let body = content;
|
|
425
|
-
|
|
426
|
-
// 正则提取以 --- 包裹的 YAML Frontmatter
|
|
427
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
428
|
-
if (match) {
|
|
429
|
-
try {
|
|
430
|
-
frontmatter = YAML.parse(match[1]) || {};
|
|
431
|
-
body = match[2];
|
|
432
|
-
} catch (err: any) {
|
|
433
|
-
console.warn(`[WARN] Failed to parse frontmatter in ${filePath}: ${err.message}`);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const filename = filePath.split("/").pop() || "unknown";
|
|
438
|
-
const defaultId = filename.replace(/\.md$/, "");
|
|
439
|
-
|
|
440
|
-
return {
|
|
441
|
-
id: frontmatter.id || defaultId,
|
|
442
|
-
description: frontmatter.description,
|
|
443
|
-
actions: Array.isArray(frontmatter.actions) ? frontmatter.actions : [],
|
|
444
|
-
content: body.trim(),
|
|
445
|
-
filePath,
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* 加载项目 playbooks 目录下的所有 Playbook SOP 文档。
|
|
451
|
-
*
|
|
452
|
-
* @param projectRoot 项目根目录
|
|
453
|
-
* @param playbooksDir playbooks 子目录(默认 "playbooks")
|
|
454
|
-
* @returns Map<PlaybookId, PlaybookDefinition> 映射
|
|
455
|
-
*/
|
|
456
|
-
export function loadPlaybooks(
|
|
457
|
-
projectRoot: string,
|
|
458
|
-
playbooksDir = "playbooks"
|
|
459
|
-
): Map<string, PlaybookDefinition> {
|
|
460
|
-
const files = discoverPlaybookFiles(projectRoot, playbooksDir);
|
|
461
|
-
const playbooks = new Map<string, PlaybookDefinition>();
|
|
462
|
-
|
|
463
|
-
for (const file of files) {
|
|
464
|
-
try {
|
|
465
|
-
const content = readFileSync(file, "utf-8");
|
|
466
|
-
const playbook = parsePlaybookContent(content, file);
|
|
467
|
-
if (playbooks.has(playbook.id)) {
|
|
468
|
-
throw new Error(
|
|
469
|
-
`Duplicate playbook ID '${playbook.id}' found in ${file}`
|
|
470
|
-
);
|
|
471
|
-
}
|
|
472
|
-
playbooks.set(playbook.id, playbook);
|
|
473
|
-
} catch (err: any) {
|
|
474
|
-
throw new Error(`Failed to load playbook from ${file}: ${err.message}`);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
return playbooks;
|
|
479
|
-
}
|