@actiondock/core 2.0.7 → 2.0.9
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/package.json +9 -3
- package/src/project/init.ts +2 -2
- package/src/project/loader.ts +64 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actiondock/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "ActionDock Core Engine - Project loader, runtime execution, SQLite storage, standalone builder, and skill exporter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"test": "bun test"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@actiondock/sdk": "^2.0.
|
|
30
|
+
"@actiondock/sdk": "^2.0.9",
|
|
31
31
|
"ajv": "^8.17.1",
|
|
32
32
|
"ajv-formats": "^3.0.1",
|
|
33
33
|
"yaml": "^2.7.0"
|
|
@@ -36,7 +36,13 @@
|
|
|
36
36
|
"@types/bun": "latest",
|
|
37
37
|
"typescript": "^5.7.0"
|
|
38
38
|
},
|
|
39
|
-
"keywords": [
|
|
39
|
+
"keywords": [
|
|
40
|
+
"actiondock",
|
|
41
|
+
"core",
|
|
42
|
+
"runtime",
|
|
43
|
+
"storage",
|
|
44
|
+
"builder"
|
|
45
|
+
],
|
|
40
46
|
"author": "team4u",
|
|
41
47
|
"license": "Apache-2.0",
|
|
42
48
|
"repository": {
|
package/src/project/init.ts
CHANGED
|
@@ -108,10 +108,10 @@ export function initProject(targetDir: string, options: InitOptions = {}): void
|
|
|
108
108
|
node: ">=22.12.0",
|
|
109
109
|
},
|
|
110
110
|
dependencies: {
|
|
111
|
-
"@actiondock/sdk": "^2.0.
|
|
111
|
+
"@actiondock/sdk": "^2.0.9",
|
|
112
112
|
},
|
|
113
113
|
devDependencies: {
|
|
114
|
-
"@actiondock/testing": "^2.0.
|
|
114
|
+
"@actiondock/testing": "^2.0.9",
|
|
115
115
|
"@types/node": "^22.12.0",
|
|
116
116
|
"tsx": "^4.19.0",
|
|
117
117
|
"typescript": "^5.7.0",
|
package/src/project/loader.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
3
4
|
import { basename, dirname, join, resolve } from "node:path";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
4
6
|
import YAML from "yaml";
|
|
5
7
|
import type { ActionDefinition } from "@actiondock/sdk";
|
|
6
8
|
import type { PlaybookDefinition, PlaybookFrontmatter, ProjectConfig } from "./types";
|
|
7
9
|
|
|
10
|
+
/**
|
|
11
|
+
* 将绝对路径规范化为 ESM 动态导入可用的 file:// URL 标识符。
|
|
12
|
+
* Windows 绝对路径(如 D:\a\b.ts)不是合法的 ESM 标识符,会被解析为 "d:" 协议导致
|
|
13
|
+
* 加载失败;POSIX 绝对路径虽可直接导入,统一转换后跨平台行为一致。
|
|
14
|
+
*/
|
|
15
|
+
function toImportSpecifier(filePath: string): string {
|
|
16
|
+
return pathToFileURL(filePath).href;
|
|
17
|
+
}
|
|
18
|
+
|
|
8
19
|
/**
|
|
9
20
|
* 从指定目录开始向上逐级递归查找包含 `actiondock.json` 的项目根目录。
|
|
10
21
|
*
|
|
@@ -70,8 +81,15 @@ export function loadProjectConfig(projectRoot: string): ProjectConfig {
|
|
|
70
81
|
|
|
71
82
|
/**
|
|
72
83
|
* 探测宿主系统中可用的包管理工具(优先级:pnpm > npm > yarn > bun)。
|
|
84
|
+
* 可通过环境变量 ACTIONDOCK_INSTALLER 强制指定(如 npm、pnpm、yarn、bun)。
|
|
85
|
+
* 探测必须经 shell 执行:Windows 下 npm/pnpm/yarn 均为 .cmd 垫片,
|
|
86
|
+
* 不经 shell 的 spawnSync 无法解析,将错误地回退到原生 exe 的 bun。
|
|
73
87
|
*/
|
|
74
88
|
function getInstallCommand(): string[] {
|
|
89
|
+
const preferred = process.env.ACTIONDOCK_INSTALLER?.trim();
|
|
90
|
+
if (preferred) {
|
|
91
|
+
return [preferred, "install"];
|
|
92
|
+
}
|
|
75
93
|
const candidates: [string, string][] = [
|
|
76
94
|
["pnpm", "install"],
|
|
77
95
|
["npm", "install"],
|
|
@@ -80,8 +98,9 @@ function getInstallCommand(): string[] {
|
|
|
80
98
|
];
|
|
81
99
|
for (const [pm, action] of candidates) {
|
|
82
100
|
try {
|
|
83
|
-
const check = spawnSync(pm
|
|
101
|
+
const check = spawnSync(`${pm} --version`, {
|
|
84
102
|
stdio: "pipe",
|
|
103
|
+
shell: true,
|
|
85
104
|
});
|
|
86
105
|
if (check.status === 0) {
|
|
87
106
|
return [pm, action];
|
|
@@ -93,6 +112,30 @@ function getInstallCommand(): string[] {
|
|
|
93
112
|
return ["npm", "install"];
|
|
94
113
|
}
|
|
95
114
|
|
|
115
|
+
/**
|
|
116
|
+
* 解析 npm 风格 .npmrc 中的 strict-ssl 配置(项目级优先于用户级)。
|
|
117
|
+
* 返回 undefined 表示各级配置均未声明该键。
|
|
118
|
+
*/
|
|
119
|
+
function resolveNpmStrictSsl(projectRoot: string): boolean | undefined {
|
|
120
|
+
const configPaths = [join(projectRoot, ".npmrc"), join(homedir(), ".npmrc")];
|
|
121
|
+
for (const configPath of configPaths) {
|
|
122
|
+
try {
|
|
123
|
+
if (!existsSync(configPath)) continue;
|
|
124
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
125
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
126
|
+
const matched = line.match(/^\s*strict-ssl\s*=\s*(\S+)\s*$/i);
|
|
127
|
+
if (matched) {
|
|
128
|
+
const falsy = ["false", "0", "no", "off"];
|
|
129
|
+
return !falsy.includes(matched[1].toLowerCase());
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} catch {
|
|
133
|
+
// 配置不可读时继续检查下一级
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
96
139
|
/**
|
|
97
140
|
* 确保项目依赖(node_modules)已正确安装。
|
|
98
141
|
* 若尚未安装或加载失败时,自动触发包管理器执行依赖安装。
|
|
@@ -131,14 +174,30 @@ export function ensureProjectDependencies(projectRoot: string, force = false): b
|
|
|
131
174
|
`[actiondock] Installing dependencies using ${installCmd[0]} for '${pkg.name || basename(projectRoot)}'...\n`
|
|
132
175
|
);
|
|
133
176
|
|
|
134
|
-
|
|
177
|
+
// bun 不读取 .npmrc 的 strict-ssl 配置;当 npm 侧已声明 strict-ssl=false 时,
|
|
178
|
+
// 桥接为 bun 子进程的 NODE_TLS_REJECT_UNAUTHORIZED=0,保证内网自签名证书源下行为一致
|
|
179
|
+
const childEnv = { ...process.env };
|
|
180
|
+
if (installCmd[0] === "bun" && resolveNpmStrictSsl(projectRoot) === false) {
|
|
181
|
+
childEnv.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// shell 模式下须传入单一命令字符串;候选命令均来自内置白名单,无注入面
|
|
185
|
+
const proc = spawnSync(installCmd.join(" "), {
|
|
135
186
|
cwd: projectRoot,
|
|
136
187
|
stdio: "pipe",
|
|
188
|
+
shell: true,
|
|
189
|
+
env: childEnv,
|
|
137
190
|
});
|
|
138
191
|
|
|
139
192
|
if (proc.status !== 0) {
|
|
140
193
|
const errText = proc.stderr?.toString() || `Unknown error during ${installCmd[0]} install`;
|
|
141
194
|
process.stderr.write(`[actiondock] Warning: Dependency installation failed: ${errText}\n`);
|
|
195
|
+
if (installCmd[0] === "bun" && /SELF_SIGNED_CERT|CERT_|UNABLE_TO_VERIFY|ERR_TLS/i.test(errText)) {
|
|
196
|
+
process.stderr.write(
|
|
197
|
+
`[actiondock] Hint: bun ignores 'strict-ssl=false' from .npmrc. ` +
|
|
198
|
+
`Add 'strict-ssl=false' to the project or user .npmrc, or set ACTIONDOCK_INSTALLER=npm.\n`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
142
201
|
return false;
|
|
143
202
|
}
|
|
144
203
|
|
|
@@ -220,7 +279,7 @@ export async function loadActions(
|
|
|
220
279
|
// 动态导入,若缺失模块则自动触发依赖重装与二次重试
|
|
221
280
|
let imported: any;
|
|
222
281
|
try {
|
|
223
|
-
imported = await import(file);
|
|
282
|
+
imported = await import(toImportSpecifier(file));
|
|
224
283
|
} catch (err: any) {
|
|
225
284
|
const msg = String(err.message || "");
|
|
226
285
|
if (
|
|
@@ -232,7 +291,7 @@ export async function loadActions(
|
|
|
232
291
|
) {
|
|
233
292
|
const installed = ensureProjectDependencies(projectRoot, true);
|
|
234
293
|
if (installed) {
|
|
235
|
-
imported = await import(file);
|
|
294
|
+
imported = await import(toImportSpecifier(file));
|
|
236
295
|
} else {
|
|
237
296
|
throw err;
|
|
238
297
|
}
|
|
@@ -283,7 +342,7 @@ export async function loadActionFileMap(
|
|
|
283
342
|
|
|
284
343
|
for (const file of files) {
|
|
285
344
|
try {
|
|
286
|
-
const imported = await import(file);
|
|
345
|
+
const imported = await import(toImportSpecifier(file));
|
|
287
346
|
const act = imported.default || imported.action;
|
|
288
347
|
if (act && typeof act === "object" && typeof act.id === "string") {
|
|
289
348
|
map.set(act.id, {
|