@actiondock/core 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/dist/catalog/discovery.d.ts +3 -3
- package/dist/catalog/graph.d.ts +8 -6
- package/dist/catalog/graph.js +62 -197
- package/dist/catalog/resolve-playbook.d.ts +2 -2
- package/dist/catalog/resolve-playbook.js +53 -12
- package/dist/execution/service.js +6 -0
- package/dist/execution/types.d.ts +2 -2
- package/dist/host/host.js +16 -5
- package/dist/host/routing.d.ts +1 -1
- package/dist/host/routing.js +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.js +0 -1
- package/dist/invocation/types.d.ts +5 -1
- package/dist/invocation/types.js +5 -0
- package/dist/package/runtime.d.ts +2 -2
- package/dist/package/runtime.js +9 -5
- package/dist/package/static-index.d.ts +6 -4
- package/dist/package/static-index.js +60 -12
- package/dist/package/types.d.ts +5 -5
- package/dist/project/index.d.ts +0 -1
- package/dist/project/index.js +0 -1
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +2 -4
- package/dist/project/loader.js +34 -38
- package/dist/project/manifest.d.ts +0 -2
- package/dist/project/manifest.js +1 -17
- package/dist/project/types.d.ts +0 -31
- package/dist/registry/registry.js +15 -27
- package/dist/runtime/context.d.ts +3 -3
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/run-origin.d.ts +9 -0
- package/dist/runtime/run-origin.js +33 -0
- package/dist/runtime/run-persistence.d.ts +3 -1
- package/dist/runtime/run-persistence.js +3 -0
- package/dist/runtime/standalone-commands.js +2 -8
- package/dist/runtime/standalone.d.ts +0 -2
- package/dist/server/policy.d.ts +8 -0
- package/dist/server/policy.js +14 -0
- package/dist/server/routes/actions.js +5 -0
- package/dist/service/types.d.ts +3 -1
- package/dist/storage/sqlite-runs.js +9 -3
- package/dist/storage/sqlite-schema.js +5 -1
- package/dist/storage/utils.d.ts +5 -2
- package/dist/storage/utils.js +7 -2
- package/dist/utils/semver.d.ts +1 -2
- package/dist/utils/semver.js +5 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/dist/project/skill-dir.d.ts +0 -72
- package/dist/project/skill-dir.js +0 -244
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActionDockManifest
|
|
1
|
+
import type { ActionDockManifest } from "../project/types.js";
|
|
2
2
|
import type { PackageIdentity } from "../runtime/identity.js";
|
|
3
3
|
/**
|
|
4
4
|
* 发现的包基本信息规范。
|
|
@@ -8,8 +8,8 @@ export interface DiscoveredPackage {
|
|
|
8
8
|
readonly id: string;
|
|
9
9
|
/** 包物理根目录绝对路径 */
|
|
10
10
|
readonly root: string;
|
|
11
|
-
/**
|
|
12
|
-
readonly manifest: ActionDockManifest
|
|
11
|
+
/** 包清单定义 */
|
|
12
|
+
readonly manifest: ActionDockManifest;
|
|
13
13
|
/** 包物理与快照身份凭证(可选,由已有运行时传入) */
|
|
14
14
|
readonly identity?: PackageIdentity;
|
|
15
15
|
/** 是否来自工作区目录扫描发现 */
|
package/dist/catalog/graph.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { ActionDockError } from "../errors.js";
|
|
2
2
|
import { type ActionDockLockfile } from "../project/lockfile.js";
|
|
3
|
-
import type { ActionDockManifest, PlaybookDefinition
|
|
3
|
+
import type { ActionDockManifest, PlaybookDefinition } from "../project/types.js";
|
|
4
4
|
import { type PackageIdentity } from "../runtime/identity.js";
|
|
5
5
|
import { parseSemVer, type SemVer } from "../utils/index.js";
|
|
6
6
|
import { type DiscoveredPackage, type PackageDiscoveryOptions } from "./discovery.js";
|
|
7
7
|
export type { SemVer };
|
|
8
8
|
export { parseSemVer };
|
|
9
|
+
/**
|
|
10
|
+
* 校验两个语义化版本范围是否兼容并能收敛为单一解析版本。
|
|
11
|
+
* 遵循设计规范:直接或传递版本范围无法收敛时拒绝并抛出 ACTION_PACKAGE_VERSION_CONFLICT。
|
|
12
|
+
*/
|
|
9
13
|
export declare function areVersionsCompatible(v1: string, v2: string): boolean;
|
|
10
14
|
/**
|
|
11
15
|
* 版本冲突错误。
|
|
@@ -51,8 +55,8 @@ export interface PackageNode {
|
|
|
51
55
|
readonly packageId: string;
|
|
52
56
|
/** 包根目录绝对物理路径 */
|
|
53
57
|
readonly root: string;
|
|
54
|
-
/**
|
|
55
|
-
readonly manifest: ActionDockManifest
|
|
58
|
+
/** 包清单规范 */
|
|
59
|
+
readonly manifest: ActionDockManifest;
|
|
56
60
|
/** 包清单摘要哈希 */
|
|
57
61
|
readonly manifestDigest: string;
|
|
58
62
|
/** 包版本号 */
|
|
@@ -141,14 +145,12 @@ export declare class DefaultPackageGraph implements PackageGraph {
|
|
|
141
145
|
export interface PackageGraphBuilderOptions {
|
|
142
146
|
/** 预先发现的包集合,若未提供则通过 PackageDiscovery 自动发现 */
|
|
143
147
|
packages?: DiscoveredPackage[];
|
|
144
|
-
/** 完整显式集合的依赖存在性与选定版本校验(Host 增量注册时不启用)。 */
|
|
145
|
-
validateDependencies?: boolean;
|
|
146
148
|
/** 根工程根目录或根包标识(与 projectRoot 互为别名) */
|
|
147
149
|
root?: string;
|
|
148
150
|
/** 当前工程根目录绝对或相对物理路径 */
|
|
149
151
|
projectRoot?: string;
|
|
150
152
|
/** 显式根清单 */
|
|
151
|
-
manifest?: ActionDockManifest
|
|
153
|
+
manifest?: ActionDockManifest;
|
|
152
154
|
/** 锁文件规范对象(若未显式提供且 projectRoot 存在,则尝试自动读取 actiondock.lock.json) */
|
|
153
155
|
lockfile?: ActionDockLockfile;
|
|
154
156
|
/** 是否允许扫描与链接开发软链接包(默认根据 discoveryOptions 判定) */
|
package/dist/catalog/graph.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
-
import { ActionDockError, ACTION_PACKAGE_VERSION_CONFLICT, MANIFEST_DIGEST_MISMATCH, MANIFEST_NOT_FOUND, MANIFEST_READ_FAILED, PACKAGE_NOT_FOUND,
|
|
3
|
+
import { ActionDockError, ACTION_PACKAGE_VERSION_CONFLICT, MANIFEST_DIGEST_MISMATCH, MANIFEST_NOT_FOUND, MANIFEST_READ_FAILED, PACKAGE_NOT_FOUND, UNDECLARED_ACTION_DEPENDENCY, } from "../errors.js";
|
|
4
4
|
import { computeManifestDigest, parseJsonWithoutDuplicates } from "../project/digest.js";
|
|
5
5
|
import { loadLockfile } from "../project/lockfile.js";
|
|
6
6
|
import { loadPlaybooks, loadProjectConfig } from "../project/loader.js";
|
|
@@ -10,124 +10,30 @@ import { createPackageIdentity } from "../runtime/identity.js";
|
|
|
10
10
|
import { parseSemVer } from "../utils/index.js";
|
|
11
11
|
import { PackageDiscovery } from "./discovery.js";
|
|
12
12
|
export { parseSemVer };
|
|
13
|
-
/** 有限版本契约:严格三段版本(允许 v/= 前缀)、^、~、*;不猜测其他范围。 */
|
|
14
|
-
function parseVersionRange(value) {
|
|
15
|
-
const text = value.trim();
|
|
16
|
-
if (!text || text === "*")
|
|
17
|
-
return {};
|
|
18
|
-
const prefix = text[0];
|
|
19
|
-
const minimum = parseSemVer(prefix === "^" || prefix === "~" ? text.slice(1) : text);
|
|
20
|
-
if (!minimum)
|
|
21
|
-
return undefined;
|
|
22
|
-
if (prefix !== "^" && prefix !== "~")
|
|
23
|
-
return { minimum, exact: true };
|
|
24
|
-
const maximum = prefix === "~"
|
|
25
|
-
? { major: minimum.major, minor: minimum.minor + 1, patch: 0 }
|
|
26
|
-
: minimum.major > 0 ? { major: minimum.major + 1, minor: 0, patch: 0 }
|
|
27
|
-
: minimum.minor > 0 ? { major: 0, minor: minimum.minor + 1, patch: 0 }
|
|
28
|
-
: { major: 0, minor: 0, patch: minimum.patch + 1 };
|
|
29
|
-
return { minimum, maximum };
|
|
30
|
-
}
|
|
31
|
-
function compareVersions(a, b) {
|
|
32
|
-
const core = a.major - b.major || a.minor - b.minor || a.patch - b.patch;
|
|
33
|
-
if (core)
|
|
34
|
-
return core;
|
|
35
|
-
if (a.prerelease === b.prerelease)
|
|
36
|
-
return 0;
|
|
37
|
-
if (a.prerelease === undefined)
|
|
38
|
-
return 1;
|
|
39
|
-
if (b.prerelease === undefined)
|
|
40
|
-
return -1;
|
|
41
|
-
const left = a.prerelease.split(".");
|
|
42
|
-
const right = b.prerelease.split(".");
|
|
43
|
-
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
44
|
-
if (left[i] === undefined)
|
|
45
|
-
return -1;
|
|
46
|
-
if (right[i] === undefined)
|
|
47
|
-
return 1;
|
|
48
|
-
if (left[i] === right[i])
|
|
49
|
-
continue;
|
|
50
|
-
const numericLeft = /^\d+$/.test(left[i]);
|
|
51
|
-
const numericRight = /^\d+$/.test(right[i]);
|
|
52
|
-
if (numericLeft && numericRight)
|
|
53
|
-
return BigInt(left[i]) < BigInt(right[i]) ? -1 : 1;
|
|
54
|
-
if (numericLeft !== numericRight)
|
|
55
|
-
return numericLeft ? -1 : 1;
|
|
56
|
-
return left[i] < right[i] ? -1 : 1;
|
|
57
|
-
}
|
|
58
|
-
return 0;
|
|
59
|
-
}
|
|
60
|
-
function satisfiesRange(version, range) {
|
|
61
|
-
if (range.exact)
|
|
62
|
-
return compareVersions(version, range.minimum) === 0;
|
|
63
|
-
if (range.minimum && compareVersions(version, range.minimum) < 0)
|
|
64
|
-
return false;
|
|
65
|
-
if (range.maximum && compareVersions(version, range.maximum) >= 0)
|
|
66
|
-
return false;
|
|
67
|
-
// 预发布版本仅在范围下界显式点名同一核心版本的预发布时纳入。
|
|
68
|
-
if (version.prerelease !== undefined) {
|
|
69
|
-
const min = range.minimum;
|
|
70
|
-
return Boolean(min?.prerelease && version.major === min.major && version.minor === min.minor && version.patch === min.patch);
|
|
71
|
-
}
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
export function areVersionsCompatible(v1, v2) {
|
|
75
|
-
const left = parseVersionRange(v1);
|
|
76
|
-
const right = parseVersionRange(v2);
|
|
77
|
-
if (!left || !right)
|
|
78
|
-
return false;
|
|
79
|
-
const candidate = !left.minimum ? right.minimum : !right.minimum ? left.minimum
|
|
80
|
-
: compareVersions(left.minimum, right.minimum) >= 0 ? left.minimum : right.minimum;
|
|
81
|
-
if (!candidate)
|
|
82
|
-
return true;
|
|
83
|
-
if (satisfiesRange(candidate, left) && satisfiesRange(candidate, right))
|
|
84
|
-
return true;
|
|
85
|
-
// 两个范围可以在预发布下界之后的稳定版本交汇,但不能改变精确版本。
|
|
86
|
-
const stable = { major: candidate.major, minor: candidate.minor, patch: candidate.patch };
|
|
87
|
-
return satisfiesRange(stable, left) && satisfiesRange(stable, right);
|
|
88
|
-
}
|
|
89
13
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* 规则:
|
|
93
|
-
* - 范围操作符开头:^, ~, <, >, =, *;
|
|
94
|
-
* - 复合范围操作符:|| 或 - 范围;
|
|
95
|
-
* - X 范围与通配:如 1.x, 1.2.x, 1.*, 1.2.*, v1.x 等;
|
|
96
|
-
* - 不完整两段或一段版本:如 1, 1.2, v1, v1.2 等;
|
|
97
|
-
* - 版本三段式开头但未被严格解析器支持的非法形态。
|
|
14
|
+
* 校验两个语义化版本范围是否兼容并能收敛为单一解析版本。
|
|
15
|
+
* 遵循设计规范:直接或传递版本范围无法收敛时拒绝并抛出 ACTION_PACKAGE_VERSION_CONFLICT。
|
|
98
16
|
*/
|
|
99
|
-
function
|
|
100
|
-
|
|
101
|
-
if (!text)
|
|
102
|
-
return false;
|
|
103
|
-
if (/^[~^<>=*]/.test(text))
|
|
104
|
-
return true;
|
|
105
|
-
if (/\|\||\s+-\s+/.test(text))
|
|
106
|
-
return true;
|
|
107
|
-
if (/^v?\d+\.(?:[xX*]|\d+\.[xX*])(?:$|[-+])/.test(text))
|
|
108
|
-
return true;
|
|
109
|
-
if (/^v?\d+(?:\.\d+)?$/.test(text))
|
|
110
|
-
return true;
|
|
111
|
-
if (/^v?\d+\.\d+\.\d+/.test(text))
|
|
17
|
+
export function areVersionsCompatible(v1, v2) {
|
|
18
|
+
if (v1 === v2 || v1 === "*" || v2 === "*" || !v1 || !v2) {
|
|
112
19
|
return true;
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
/** 获取描述不是版本约束;仅真实范围及锁定版本参与版本兼容校验。 */
|
|
116
|
-
function dependencyVersionRequirements(spec, locked) {
|
|
117
|
-
const requirements = [];
|
|
118
|
-
const range = spec === undefined ? undefined : parseVersionRange(spec);
|
|
119
|
-
if (spec !== undefined && range)
|
|
120
|
-
requirements.push(spec);
|
|
121
|
-
else if (spec !== undefined && isUnsupportedVersionRange(spec)) {
|
|
122
|
-
throw new ActionDockError(INVALID_ARGUMENT, `Unsupported Action package version range '${spec}'; supported forms are exact versions, ^, ~ and *`);
|
|
123
20
|
}
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
21
|
+
const clean1 = v1.trim().replace(/^[\^~=]/, "");
|
|
22
|
+
const clean2 = v2.trim().replace(/^[\^~=]/, "");
|
|
23
|
+
const sem1 = parseSemVer(clean1);
|
|
24
|
+
const sem2 = parseSemVer(clean2);
|
|
25
|
+
if (!sem1 || !sem2) {
|
|
26
|
+
return v1 === v2;
|
|
27
|
+
}
|
|
28
|
+
if (sem1.major !== sem2.major) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (v1.startsWith("~") || v2.startsWith("~")) {
|
|
32
|
+
if (sem1.minor !== sem2.minor) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
129
35
|
}
|
|
130
|
-
return
|
|
36
|
+
return true;
|
|
131
37
|
}
|
|
132
38
|
/**
|
|
133
39
|
* 版本冲突错误。
|
|
@@ -321,20 +227,30 @@ function computeTransitiveDependencies(nodes) {
|
|
|
321
227
|
function collectVisiblePlaybooks(rootNode, nodes) {
|
|
322
228
|
const visiblePlaybooks = new Map();
|
|
323
229
|
const delegatedActions = new Set();
|
|
324
|
-
if (rootNode) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
230
|
+
if (rootNode && rootNode.root && existsSync(rootNode.root)) {
|
|
231
|
+
try {
|
|
232
|
+
const rootPbs = loadPlaybooks(rootNode.root, undefined, rootNode.manifest);
|
|
233
|
+
for (const [id, pb] of rootPbs.entries()) {
|
|
234
|
+
visiblePlaybooks.set(id, pb);
|
|
235
|
+
visiblePlaybooks.set(`${rootNode.packageId}/${id}`, pb);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// 忽略根包 Playbook 加载异常
|
|
329
240
|
}
|
|
330
241
|
for (const depId of rootNode.directDependencies) {
|
|
331
242
|
if (depId === rootNode.packageId)
|
|
332
243
|
continue;
|
|
333
244
|
const depNode = nodes.get(depId);
|
|
334
|
-
if (depNode) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
245
|
+
if (depNode && depNode.root && existsSync(depNode.root)) {
|
|
246
|
+
try {
|
|
247
|
+
const depPbs = loadPlaybooks(depNode.root, undefined, depNode.manifest);
|
|
248
|
+
for (const [id, pb] of depPbs.entries()) {
|
|
249
|
+
visiblePlaybooks.set(`${depId}/${id}`, pb);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
// 忽略依赖包 Playbook 加载异常
|
|
338
254
|
}
|
|
339
255
|
}
|
|
340
256
|
}
|
|
@@ -364,16 +280,13 @@ export class PackageGraphBuilder {
|
|
|
364
280
|
*/
|
|
365
281
|
buildFromPackages(nodes, generation) {
|
|
366
282
|
for (const pkg of this.options.packages) {
|
|
367
|
-
if (nodes.has(pkg.id)) {
|
|
368
|
-
throw new ActionDockError(PACKAGE_ID_CONFLICT, `Package ID '${pkg.id}' occurs more than once in explicit package graph`);
|
|
369
|
-
}
|
|
370
283
|
const fields = createPackageNodeFields({
|
|
371
284
|
id: pkg.id,
|
|
372
285
|
root: pkg.root,
|
|
373
286
|
manifest: pkg.manifest,
|
|
374
287
|
npmPackage: pkg.id,
|
|
375
288
|
isDirect: Boolean(pkg.isCurrentProject),
|
|
376
|
-
isRoot:
|
|
289
|
+
isRoot: Boolean(pkg.isCurrentProject),
|
|
377
290
|
identity: pkg.identity,
|
|
378
291
|
generation,
|
|
379
292
|
});
|
|
@@ -395,48 +308,20 @@ export class PackageGraphBuilder {
|
|
|
395
308
|
}
|
|
396
309
|
}
|
|
397
310
|
if (!rootIdentity) {
|
|
398
|
-
const currentProjectNodes = Array.from(nodes.values()).filter((n) => n.isDirect);
|
|
399
|
-
if (currentProjectNodes.length === 1) {
|
|
400
|
-
rootIdentity = currentProjectNodes[0].identity;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
for (const [id, node] of nodes) {
|
|
404
|
-
const isTheRoot = Boolean(rootIdentity && node.identity.id === rootIdentity.id);
|
|
405
|
-
nodes.set(id, { ...node, isRoot: isTheRoot, isDirect: isTheRoot || Boolean(node.isDirect) });
|
|
406
|
-
}
|
|
407
|
-
if (this.options.validateDependencies) {
|
|
408
311
|
for (const node of nodes.values()) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
if (!dep) {
|
|
413
|
-
throw new ActionDockError(PACKAGE_NOT_FOUND, `Package '${depId}' required by '${node.packageId}' is missing from explicit graph`);
|
|
414
|
-
}
|
|
415
|
-
for (const requirement of dependencyVersionRequirements(spec)) {
|
|
416
|
-
if (!areVersionsCompatible(requirement, dep.version)) {
|
|
417
|
-
throw new ActionPackageVersionConflictError(depId, [
|
|
418
|
-
{ requester: node.packageId, rangeOrVersion: requirement },
|
|
419
|
-
{ requester: depId, rangeOrVersion: dep.version },
|
|
420
|
-
]);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
// 根锁文件也可能锁定传递依赖,不能只检查直接 dependencies。
|
|
425
|
-
for (const [depId, locked] of Object.entries(lockfile?.packages || {})) {
|
|
426
|
-
const dep = nodes.get(depId);
|
|
427
|
-
if (!dep)
|
|
428
|
-
continue;
|
|
429
|
-
for (const requirement of dependencyVersionRequirements(undefined, locked)) {
|
|
430
|
-
if (!areVersionsCompatible(requirement, dep.version)) {
|
|
431
|
-
throw new ActionPackageVersionConflictError(depId, [
|
|
432
|
-
{ requester: node.packageId, rangeOrVersion: requirement },
|
|
433
|
-
{ requester: depId, rangeOrVersion: dep.version },
|
|
434
|
-
]);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
312
|
+
if (node.isRoot) {
|
|
313
|
+
rootIdentity = node.identity;
|
|
314
|
+
break;
|
|
437
315
|
}
|
|
438
316
|
}
|
|
439
317
|
}
|
|
318
|
+
if (rootIdentity) {
|
|
319
|
+
const rootNode = nodes.get(rootIdentity.id);
|
|
320
|
+
if (rootNode) {
|
|
321
|
+
rootNode.isRoot = true;
|
|
322
|
+
rootNode.isDirect = true;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
440
325
|
linkDirectDependencies(nodes);
|
|
441
326
|
computeTransitiveDependencies(nodes);
|
|
442
327
|
const effectiveRootNode = rootIdentity ? nodes.get(rootIdentity.id) : undefined;
|
|
@@ -530,13 +415,6 @@ export class PackageGraphBuilder {
|
|
|
530
415
|
// 忽略扫描外部链接包异常
|
|
531
416
|
}
|
|
532
417
|
}
|
|
533
|
-
const requesterLocks = new Map([[rootPackageId, lockfile]]);
|
|
534
|
-
const getRequesterLock = (requester) => {
|
|
535
|
-
if (!requesterLocks.has(requester)) {
|
|
536
|
-
requesterLocks.set(requester, loadLockfile(nodes.get(requester).root));
|
|
537
|
-
}
|
|
538
|
-
return requesterLocks.get(requester);
|
|
539
|
-
};
|
|
540
418
|
const versionRequirements = new Map();
|
|
541
419
|
function recordRequirement(pkgId, requester, rangeOrVersion) {
|
|
542
420
|
const existing = versionRequirements.get(pkgId) || [];
|
|
@@ -551,22 +429,10 @@ export class PackageGraphBuilder {
|
|
|
551
429
|
existing.push({ requester, rangeOrVersion });
|
|
552
430
|
versionRequirements.set(pkgId, existing);
|
|
553
431
|
}
|
|
554
|
-
const recordDependency = (pkgId, requester, spec) => {
|
|
555
|
-
const requesterLocked = getRequesterLock(requester)?.packages[pkgId];
|
|
556
|
-
for (const requirement of dependencyVersionRequirements(spec, requesterLocked)) {
|
|
557
|
-
recordRequirement(pkgId, requester, requirement);
|
|
558
|
-
}
|
|
559
|
-
const rootLocked = lockfile?.packages[pkgId];
|
|
560
|
-
if (rootLocked && rootLocked !== requesterLocked) {
|
|
561
|
-
for (const requirement of dependencyVersionRequirements(undefined, rootLocked)) {
|
|
562
|
-
recordRequirement(pkgId, rootPackageId, requirement);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
432
|
const queue = [];
|
|
567
433
|
for (const [depId, spec] of Object.entries(rootManifest.dependencies || {})) {
|
|
568
434
|
rootNode.directDependencies.add(depId);
|
|
569
|
-
|
|
435
|
+
recordRequirement(depId, rootPackageId, spec);
|
|
570
436
|
queue.push({
|
|
571
437
|
pkgId: depId,
|
|
572
438
|
requester: rootPackageId,
|
|
@@ -594,7 +460,7 @@ export class PackageGraphBuilder {
|
|
|
594
460
|
continue;
|
|
595
461
|
}
|
|
596
462
|
let pkgDir = null;
|
|
597
|
-
const locked =
|
|
463
|
+
const locked = lockfile?.packages?.[item.pkgId];
|
|
598
464
|
if (packageRootsRecord?.[item.pkgId]) {
|
|
599
465
|
pkgDir = packageRootsRecord[item.pkgId];
|
|
600
466
|
}
|
|
@@ -608,7 +474,7 @@ export class PackageGraphBuilder {
|
|
|
608
474
|
}
|
|
609
475
|
candidateNames.push(item.rangeOrSpec);
|
|
610
476
|
candidateNames.push(item.pkgId);
|
|
611
|
-
let cur =
|
|
477
|
+
let cur = absProjectRoot;
|
|
612
478
|
while (true) {
|
|
613
479
|
for (const candName of candidateNames) {
|
|
614
480
|
const candPath = join(cur, "node_modules", candName);
|
|
@@ -640,9 +506,6 @@ export class PackageGraphBuilder {
|
|
|
640
506
|
throw new ActionDockError(MANIFEST_READ_FAILED, `Failed to read manifest for '${item.pkgId}': ${err.message}`);
|
|
641
507
|
}
|
|
642
508
|
const depManifest = parseJsonWithoutDuplicates(manifestRaw);
|
|
643
|
-
if (depManifest.id !== item.pkgId) {
|
|
644
|
-
throw new ActionDockError(PACKAGE_ID_CONFLICT, `Expected package '${item.pkgId}' at '${pkgDir}', found '${depManifest.id}'`);
|
|
645
|
-
}
|
|
646
509
|
const actualDigest = computeManifestDigest(depManifest);
|
|
647
510
|
if (locked?.manifestDigest && locked.manifestDigest !== actualDigest) {
|
|
648
511
|
throw new ActionDockError(MANIFEST_DIGEST_MISMATCH, `Manifest digest mismatch for package '${item.pkgId}': expected '${locked.manifestDigest}', got '${actualDigest}'. Re-resolution required.`);
|
|
@@ -675,13 +538,15 @@ export class PackageGraphBuilder {
|
|
|
675
538
|
};
|
|
676
539
|
nodes.set(item.pkgId, newNode);
|
|
677
540
|
for (const [subDepId, subSpec] of Object.entries(depManifest.dependencies || {})) {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
541
|
+
recordRequirement(subDepId, item.pkgId, subSpec);
|
|
542
|
+
if (!nodes.has(subDepId)) {
|
|
543
|
+
queue.push({
|
|
544
|
+
pkgId: subDepId,
|
|
545
|
+
requester: item.pkgId,
|
|
546
|
+
rangeOrSpec: subSpec,
|
|
547
|
+
isDirect: false,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
685
550
|
}
|
|
686
551
|
}
|
|
687
552
|
if (scanLinked) {
|
|
@@ -20,7 +20,7 @@ export interface ResolvePlaybookContext {
|
|
|
20
20
|
readonly caller?: string;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
* 替代原 registry 内部的 resolvePlaybookProject 启发式搜索。
|
|
23
|
+
* 纯领域规程解析函数 resolvePlaybook。
|
|
24
|
+
* 基于 PackageGraph 替代原 registry 内部的 resolvePlaybookProject 启发式搜索。
|
|
25
25
|
*/
|
|
26
26
|
export declare function resolvePlaybook(identifier: string, context: ResolvePlaybookContext): ResolvedPlaybook;
|
|
@@ -1,12 +1,48 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
1
3
|
import { loadPlaybooks } from "../project/loader.js";
|
|
2
4
|
import { getPackageSlug } from "../utils/index.js";
|
|
3
5
|
import { ActionDockError, INVALID_ACTION_REF, NOT_FOUND, PACKAGE_NOT_FOUND } from "../errors.js";
|
|
4
6
|
function getNodePlaybooks(node) {
|
|
5
|
-
|
|
7
|
+
const map = new Map();
|
|
8
|
+
if (node.root && existsSync(node.root)) {
|
|
9
|
+
try {
|
|
10
|
+
const diskPlaybooks = loadPlaybooks(node.root, node.manifest?.playbooksDir);
|
|
11
|
+
for (const [k, v] of diskPlaybooks) {
|
|
12
|
+
map.set(k, v);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// 忽略磁盘规程目录扫描异常
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (node.manifest?.playbooks && typeof node.manifest.playbooks === "object") {
|
|
20
|
+
for (const [id, item] of Object.entries(node.manifest.playbooks)) {
|
|
21
|
+
const existing = map.get(id);
|
|
22
|
+
let content = item.content ?? existing?.content ?? "";
|
|
23
|
+
let filePath = item.entry && node.root
|
|
24
|
+
? resolve(node.root, item.entry)
|
|
25
|
+
: existing?.filePath;
|
|
26
|
+
if (!content && filePath && existsSync(filePath)) {
|
|
27
|
+
try {
|
|
28
|
+
content = readFileSync(filePath, "utf-8");
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
}
|
|
32
|
+
map.set(id, {
|
|
33
|
+
id,
|
|
34
|
+
description: item.description ?? existing?.description,
|
|
35
|
+
actions: item.actions ?? existing?.actions ?? [],
|
|
36
|
+
content,
|
|
37
|
+
filePath: filePath || "",
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return map;
|
|
6
42
|
}
|
|
7
43
|
/**
|
|
8
|
-
*
|
|
9
|
-
* 替代原 registry 内部的 resolvePlaybookProject 启发式搜索。
|
|
44
|
+
* 纯领域规程解析函数 resolvePlaybook。
|
|
45
|
+
* 基于 PackageGraph 替代原 registry 内部的 resolvePlaybookProject 启发式搜索。
|
|
10
46
|
*/
|
|
11
47
|
export function resolvePlaybook(identifier, context) {
|
|
12
48
|
const str = identifier.trim();
|
|
@@ -51,15 +87,20 @@ export function resolvePlaybook(identifier, context) {
|
|
|
51
87
|
// 3. 全局搜索
|
|
52
88
|
const matches = [];
|
|
53
89
|
for (const node of context.graph.packages.values()) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
90
|
+
try {
|
|
91
|
+
const playbooks = getNodePlaybooks(node);
|
|
92
|
+
const pb = playbooks.get(str);
|
|
93
|
+
if (pb) {
|
|
94
|
+
matches.push({
|
|
95
|
+
packageId: node.identity.id,
|
|
96
|
+
projectRoot: node.root,
|
|
97
|
+
playbookId: str,
|
|
98
|
+
playbook: pb,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// 忽略单个包加载异常
|
|
63
104
|
}
|
|
64
105
|
}
|
|
65
106
|
if (matches.length === 1) {
|
|
@@ -7,6 +7,7 @@ import { InMemoryEventSink } from "../runtime/events.js";
|
|
|
7
7
|
import { ActionDockError, ACTION_CANCELLED, ACTION_FAILED, ACTION_NOT_FOUND, ACTION_TIMEOUT, EXECUTION_CONCURRENCY_LIMIT, EXECUTION_FAILED, IDEMPOTENCY_CONFLICT, INPUT_NOT_JSON, INPUT_VALIDATION_FAILED, INVALID_ARGUMENT, INVOCATION_UNSUPPORTED, OUTPUT_NOT_JSON, OUTPUT_VALIDATION_FAILED, RUN_REPOSITORY_UNAVAILABLE, SERVICE_CLOSED, UNHANDLED_EXECUTION_ERROR, describeActionLoadFailure, } from "../errors.js";
|
|
8
8
|
import { resultStatusToRunStatus } from "../storage/types.js";
|
|
9
9
|
import { createDefaultProcessOwner, } from "../invocation/types.js";
|
|
10
|
+
import { snapshotRunOrigin } from "../runtime/run-origin.js";
|
|
10
11
|
import { ActionRegistry, isActionDefinitionObject, resolveAnonymousActionId, } from "../runtime/action-registry.js";
|
|
11
12
|
import { buildInitialRunRecord, createRunFinalizer, createRunOrThrow, tryCreateRun, } from "../runtime/run-persistence.js";
|
|
12
13
|
import { createActionContext } from "../runtime/context.js";
|
|
@@ -432,6 +433,7 @@ export class DefaultExecutionService {
|
|
|
432
433
|
process: opts.process || this.process,
|
|
433
434
|
owner: opts.owner,
|
|
434
435
|
requestId: opts.requestId,
|
|
436
|
+
origin: snapshotRunOrigin(opts.origin),
|
|
435
437
|
};
|
|
436
438
|
}
|
|
437
439
|
async raceExecution(args) {
|
|
@@ -548,6 +550,7 @@ export class DefaultExecutionService {
|
|
|
548
550
|
progress: context.progress,
|
|
549
551
|
process: effectiveProcess,
|
|
550
552
|
owner: effectiveOwner,
|
|
553
|
+
origin: context.origin,
|
|
551
554
|
};
|
|
552
555
|
return await invoker(childAction, childInput, invocationContext);
|
|
553
556
|
}
|
|
@@ -712,8 +715,10 @@ export class DefaultExecutionService {
|
|
|
712
715
|
message: `Action '${targetActionId}' not found in package '${targetPackageId}'`,
|
|
713
716
|
};
|
|
714
717
|
const rootRunId = context.rootRunId || context.parentRunId || runId;
|
|
718
|
+
const origin = snapshotRunOrigin(context.origin);
|
|
715
719
|
const initialRun = {
|
|
716
720
|
id: runId,
|
|
721
|
+
...(origin !== undefined ? { origin } : {}),
|
|
717
722
|
rootRunId,
|
|
718
723
|
parentRunId: context.parentRunId,
|
|
719
724
|
packageId: targetPackageId,
|
|
@@ -777,6 +782,7 @@ export class DefaultExecutionService {
|
|
|
777
782
|
runId,
|
|
778
783
|
rootRunId,
|
|
779
784
|
parentRunId: context.parentRunId,
|
|
785
|
+
origin: context.origin,
|
|
780
786
|
ownerId: context.principalId || context.tenantId || this.ownerId,
|
|
781
787
|
hostSessionId: context.hostSessionId || this.hostSessionId,
|
|
782
788
|
hostPid: this.hostPid,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ActionDefinition, ActionRef, ExecutionEvent, ExecutionResult, JsonValue, Logger, ProcessAPI, RunRecord, RunStatus } from "@actiondock/sdk";
|
|
2
|
-
import type { ProjectConfig
|
|
2
|
+
import type { ProjectConfig } from "../project/types.js";
|
|
3
3
|
import type { Clock } from "../storage/clock.js";
|
|
4
4
|
import type { EventSink } from "../runtime/events.js";
|
|
5
5
|
import type { RuntimeStorage } from "../storage/types.js";
|
|
@@ -40,7 +40,7 @@ export interface ExecutionServiceOptions {
|
|
|
40
40
|
storage: RuntimeStorage;
|
|
41
41
|
globalStorage?: RuntimeStorage;
|
|
42
42
|
projectRoot?: string;
|
|
43
|
-
projectConfig?: ProjectConfig
|
|
43
|
+
projectConfig?: ProjectConfig;
|
|
44
44
|
configOverrides?: Record<string, unknown>;
|
|
45
45
|
actions?: Map<string, ActionDefinition>;
|
|
46
46
|
process?: ProcessAPI;
|
package/dist/host/host.js
CHANGED
|
@@ -7,6 +7,7 @@ import { findProjectRoot, loadProjectConfig } from "../project/loader.js";
|
|
|
7
7
|
import { hasPendingTransactions, isProjectLockHeld, recoverPendingTransactions } from "../project/transactions.js";
|
|
8
8
|
import { listLinkedPackages } from "../registry/registry.js";
|
|
9
9
|
import { InMemoryEventSink } from "../runtime/events.js";
|
|
10
|
+
import { snapshotRunOrigin } from "../runtime/run-origin.js";
|
|
10
11
|
import { ActionDockError, ACTION_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_SUBRUN_LIMIT, EXECUTION_FAILED, INVALID_ACTION_REF, PACKAGE_ID_CONFLICT, PACKAGE_NOT_FOUND, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, SERVICE_CLOSED, UNDECLARED_ACTION_DEPENDENCY, } from "../errors.js";
|
|
11
12
|
import { InvocationPolicy } from "../invocation/policy.js";
|
|
12
13
|
import { createAbortError } from "../ipc/service.js";
|
|
@@ -135,6 +136,7 @@ export class DefaultActionDockHost {
|
|
|
135
136
|
};
|
|
136
137
|
this.execution = {
|
|
137
138
|
async run(ref, input, opts) {
|
|
139
|
+
const origin = snapshotRunOrigin(opts?.origin);
|
|
138
140
|
await self.ensureInitialized();
|
|
139
141
|
const actionRef = typeof ref === "string" ? parseActionRef(ref) : ref;
|
|
140
142
|
const cleanOpts = {
|
|
@@ -142,10 +144,12 @@ export class DefaultActionDockHost {
|
|
|
142
144
|
timeoutMs: opts?.timeoutMs,
|
|
143
145
|
config: opts?.config,
|
|
144
146
|
requestId: opts?.requestId,
|
|
147
|
+
origin,
|
|
145
148
|
};
|
|
146
149
|
return self.runAction(actionRef, (input ?? {}), cleanOpts);
|
|
147
150
|
},
|
|
148
151
|
async start(ref, input, opts) {
|
|
152
|
+
const origin = snapshotRunOrigin(opts?.origin);
|
|
149
153
|
await self.ensureInitialized();
|
|
150
154
|
const actionRef = typeof ref === "string" ? parseActionRef(ref) : ref;
|
|
151
155
|
const cleanOpts = {
|
|
@@ -153,6 +157,7 @@ export class DefaultActionDockHost {
|
|
|
153
157
|
timeoutMs: opts?.timeoutMs,
|
|
154
158
|
config: opts?.config,
|
|
155
159
|
requestId: opts?.requestId,
|
|
160
|
+
origin,
|
|
156
161
|
};
|
|
157
162
|
return self.startAction(actionRef, (input ?? {}), cleanOpts);
|
|
158
163
|
},
|
|
@@ -634,6 +639,7 @@ export class DefaultActionDockHost {
|
|
|
634
639
|
progress: context.progress,
|
|
635
640
|
process: context.process,
|
|
636
641
|
owner: targetOwner,
|
|
642
|
+
origin: context.origin,
|
|
637
643
|
};
|
|
638
644
|
const ticket = await targetRuntime.startInvocation(targetActionId, childInput, subInvocationContext);
|
|
639
645
|
if (!ticket.result) {
|
|
@@ -752,14 +758,18 @@ export class DefaultActionDockHost {
|
|
|
752
758
|
return describeVisiblePlaybook(this.listRuntimes(), id, this.visibility());
|
|
753
759
|
}
|
|
754
760
|
async runAction(ref, input, options = {}) {
|
|
761
|
+
const origin = snapshotRunOrigin(options.origin);
|
|
762
|
+
const effectiveOptions = { ...options, origin };
|
|
755
763
|
await this.ensureInitialized();
|
|
756
|
-
const ticket = await this.startAction(ref, input,
|
|
764
|
+
const ticket = await this.startAction(ref, input, effectiveOptions);
|
|
757
765
|
if (!ticket.result) {
|
|
758
766
|
throw new ActionDockError(EXECUTION_FAILED, `Execution ticket for run '${ticket.runId}' has no result Promise`);
|
|
759
767
|
}
|
|
760
768
|
return ticket.result;
|
|
761
769
|
}
|
|
762
770
|
async startAction(ref, input, options = {}) {
|
|
771
|
+
const origin = snapshotRunOrigin(options.origin);
|
|
772
|
+
const effectiveOptions = { ...options, origin };
|
|
763
773
|
await this.ensureInitialized();
|
|
764
774
|
if (this.isClosed) {
|
|
765
775
|
throw new ActionDockError(SERVICE_CLOSED, "ActionDockHost is closed: new tasks rejected");
|
|
@@ -837,13 +847,14 @@ export class DefaultActionDockHost {
|
|
|
837
847
|
const rootContext = createRootInvocationContext({
|
|
838
848
|
targetPackage: targetRuntime.identity,
|
|
839
849
|
callStack: [rootKey],
|
|
840
|
-
signal:
|
|
841
|
-
timeoutMs:
|
|
842
|
-
config:
|
|
843
|
-
requestId:
|
|
850
|
+
signal: effectiveOptions.signal,
|
|
851
|
+
timeoutMs: effectiveOptions.timeoutMs,
|
|
852
|
+
config: effectiveOptions.config,
|
|
853
|
+
requestId: effectiveOptions.requestId,
|
|
844
854
|
hostSessionId: this.hostSessionId,
|
|
845
855
|
maxCallDepth: this.maxCallDepth,
|
|
846
856
|
process: this.options.process,
|
|
857
|
+
origin: effectiveOptions.origin,
|
|
847
858
|
});
|
|
848
859
|
// 调度目标包执行服务
|
|
849
860
|
return targetRuntime.startInvocation(targetActionId, input, rootContext);
|
package/dist/host/routing.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export declare function listVisiblePlaybooks(runtimes: readonly PackageRuntime[]
|
|
|
25
25
|
graph?: PackageGraph;
|
|
26
26
|
}): Promise<PlaybookSummary[]>;
|
|
27
27
|
/**
|
|
28
|
-
* 静态查询指定 Playbook
|
|
28
|
+
* 静态查询指定 Playbook 规范:基于 resolvePlaybook 统一纯领域解析。
|
|
29
29
|
*/
|
|
30
30
|
export declare function describeVisiblePlaybook(runtimes: readonly PackageRuntime[], id: string, visibility: {
|
|
31
31
|
hostPublicPackageIds: ReadonlySet<string>;
|