@actiondock/core 2.15.0 → 2.16.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.
@@ -1,4 +1,4 @@
1
- import type { ActionDockManifest, PlaybookSourceManifest } from "../project/types.js";
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 | PlaybookSourceManifest;
11
+ /** 包清单定义 */
12
+ readonly manifest: ActionDockManifest;
13
13
  /** 包物理与快照身份凭证(可选,由已有运行时传入) */
14
14
  readonly identity?: PackageIdentity;
15
15
  /** 是否来自工作区目录扫描发现 */
@@ -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, PlaybookSourceManifest } from "../project/types.js";
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 | PlaybookSourceManifest;
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 | PlaybookSourceManifest;
153
+ manifest?: ActionDockManifest;
152
154
  /** 锁文件规范对象(若未显式提供且 projectRoot 存在,则尝试自动读取 actiondock.lock.json) */
153
155
  lockfile?: ActionDockLockfile;
154
156
  /** 是否允许扫描与链接开发软链接包(默认根据 discoveryOptions 判定) */
@@ -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, PACKAGE_ID_CONFLICT, INVALID_ARGUMENT, UNDECLARED_ACTION_DEPENDENCY, } from "../errors.js";
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 isUnsupportedVersionRange(spec) {
100
- const text = spec.trim();
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 lockedVersion = locked?.resolved || locked?.version;
125
- if (lockedVersion && parseSemVer(lockedVersion))
126
- requirements.push(lockedVersion);
127
- else if (lockedVersion) {
128
- throw new ActionDockError(INVALID_ARGUMENT, `Invalid locked Action package version '${lockedVersion}'`);
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 requirements;
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
- const rootPbs = loadPlaybooks(rootNode.root || "", undefined, rootNode.manifest);
326
- for (const [id, pb] of rootPbs.entries()) {
327
- visiblePlaybooks.set(id, pb);
328
- visiblePlaybooks.set(`${rootNode.packageId}/${id}`, pb);
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
- const depPbs = loadPlaybooks(depNode.root || "", undefined, depNode.manifest);
336
- for (const [id, pb] of depPbs.entries()) {
337
- visiblePlaybooks.set(`${depId}/${id}`, pb);
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: false,
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
- const lockfile = node.root ? loadLockfile(node.root) : null;
410
- for (const [depId, spec] of Object.entries(node.manifest.dependencies || {})) {
411
- const dep = nodes.get(depId);
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
- recordDependency(depId, rootPackageId, spec);
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 = getRequesterLock(item.requester)?.packages[item.pkgId] || lockfile?.packages[item.pkgId];
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 = nodes.get(item.requester)?.root || absProjectRoot;
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
- recordDependency(subDepId, item.pkgId, subSpec);
679
- queue.push({
680
- pkgId: subDepId,
681
- requester: item.pkgId,
682
- rangeOrSpec: subSpec,
683
- isDirect: false,
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
- * 基于 PackageGraph 的规程寻址函数,正文统一由规程加载层提供。
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
- return loadPlaybooks(node.root, node.manifest.playbooksDir, node.manifest);
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
- * 基于 PackageGraph 的规程寻址函数,正文统一由规程加载层提供。
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
- const playbooks = getNodePlaybooks(node);
55
- const pb = playbooks.get(str);
56
- if (pb) {
57
- matches.push({
58
- packageId: node.identity.id,
59
- projectRoot: node.root,
60
- playbookId: str,
61
- playbook: pb,
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) {
@@ -1,5 +1,5 @@
1
1
  import type { ActionDefinition, ActionRef, ExecutionEvent, ExecutionResult, JsonValue, Logger, ProcessAPI, RunRecord, RunStatus } from "@actiondock/sdk";
2
- import type { ProjectConfig, RuntimeProjectConfig } from "../project/types.js";
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 | RuntimeProjectConfig;
43
+ projectConfig?: ProjectConfig;
44
44
  configOverrides?: Record<string, unknown>;
45
45
  actions?: Map<string, ActionDefinition>;
46
46
  process?: ProcessAPI;
@@ -25,7 +25,7 @@ export declare function listVisiblePlaybooks(runtimes: readonly PackageRuntime[]
25
25
  graph?: PackageGraph;
26
26
  }): Promise<PlaybookSummary[]>;
27
27
  /**
28
- * 静态查询指定 Playbook 规范:委托 resolvePlaybook 统一寻址与来源加载。
28
+ * 静态查询指定 Playbook 规范:基于 resolvePlaybook 统一纯领域解析。
29
29
  */
30
30
  export declare function describeVisiblePlaybook(runtimes: readonly PackageRuntime[], id: string, visibility: {
31
31
  hostPublicPackageIds: ReadonlySet<string>;
@@ -83,7 +83,7 @@ function buildFallbackGraph(runtimes) {
83
83
  ])));
84
84
  }
85
85
  /**
86
- * 静态查询指定 Playbook 规范:委托 resolvePlaybook 统一寻址与来源加载。
86
+ * 静态查询指定 Playbook 规范:基于 resolvePlaybook 统一纯领域解析。
87
87
  */
88
88
  export async function describeVisiblePlaybook(runtimes, id, visibility) {
89
89
  const graph = visibility.graph || buildFallbackGraph(runtimes);
package/dist/index.d.ts CHANGED
@@ -22,8 +22,6 @@ export { startActionDockServer, } from "./server/server.js";
22
22
  export type { ServerOptions, ServerOptions as ActionDockServerOptions, ActionDockServerInstance, } from "./server/types.js";
23
23
  export { initProject } from "./project/init.js";
24
24
  export { loadProjectConfig, findProjectRoot, } from "./project/loader.js";
25
- export { discoverLocalSkillDirectory, inspectLocalPackageDirectory, queryLocalPackageDirectory, validateLocalSkillPackages, isExplicitPath, } from "./project/skill-dir.js";
26
- export type { ProjectConfig, PlaybookSourceManifest, RuntimeProjectConfig, } from "./project/types.js";
27
- export type { LocalSkillDirectory, LocalPackageEntry, } from "./project/skill-dir.js";
25
+ export type { ProjectConfig, } from "./project/types.js";
28
26
  export type { PackageGraph, } from "./catalog/graph.js";
29
27
  export { ActionDockError, ProcessError, PACKAGE_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_NOT_FOUND, ACTION_LOAD_FAILED, ACTION_FAILED, ACTION_TIMEOUT, ACTION_CANCELLED, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, ACTION_CALL_CYCLE, UNDECLARED_ACTION_DEPENDENCY, INVALID_ACTION_REF, IDEMPOTENCY_CONFLICT, EXECUTION_FAILED, UNHANDLED_EXECUTION_ERROR, RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, STANDALONE_ASYNC_UNSUPPORTED, HOST_PROCESS_EXITED, EXECUTION_ABORTED, TIMEOUT, NETWORK_ERROR, CAPABILITY_UNAVAILABLE, STATE_KEY_NOT_FOUND, STORAGE_BUSY, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, EVENT_BACKPRESSURE_LIMIT, EVENT_CURSOR_EXPIRED, PROCESS_OUTPUT_LIMIT, PROCESS_SPAWN_ERROR, PROCESS_CANCELLED, PROCESS_TIMEOUT, UNAUTHORIZED, NOT_FOUND, SERVER_ERROR, PACKAGE_FORBIDDEN, ACTION_FORBIDDEN, PLAYBOOK_NOT_FOUND, REQUEST_TOO_LARGE, ACTION_START_FAILED, ACTION_EXECUTION_ERROR, DATA_DIR_IN_USE, DATA_DIR_RECOVERY_REQUIRED, PROCESS_FAILED, MCP_TOOL_NAME_COLLISION, ACCESS_DENIED, INVALID_FLAT_ARGUMENT, INVALID_JSON, INVALID_JSON_LITERAL, INPUT_PATH_CONFLICT, FLAT_INPUT_LIMIT_EXCEEDED, INPUT_LIMIT_EXCEEDED, INPUT_POLICY_VIOLATION, INPUT_CONFLICT, INPUT_FILE_NOT_FOUND, INPUT_FILE_READ_FAILED, INVALID_ARGUMENT, PACKAGE_NOT_ALLOWED, INVALID_PACKAGE_ID, PATH_TRAVERSAL, AMBIGUOUS_STATE_KEY, RUN_NOT_FOUND, RUN_ALREADY_FINISHED, PROJECT_ROOT_NOT_FOUND, describeActionLoadFailure, createErrorEnvelope, resolveExecutionHint, } from "./errors.js";
package/dist/index.js CHANGED
@@ -19,6 +19,5 @@ export { startActionDockServer, } from "./server/server.js";
19
19
  // 6. 核心工程辅助
20
20
  export { initProject } from "./project/init.js";
21
21
  export { loadProjectConfig, findProjectRoot, } from "./project/loader.js";
22
- export { discoverLocalSkillDirectory, inspectLocalPackageDirectory, queryLocalPackageDirectory, validateLocalSkillPackages, isExplicitPath, } from "./project/skill-dir.js";
23
22
  // 8. 统一错误模型与核心标准错误码常量
24
23
  export { ActionDockError, ProcessError, PACKAGE_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_NOT_FOUND, ACTION_LOAD_FAILED, ACTION_FAILED, ACTION_TIMEOUT, ACTION_CANCELLED, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, ACTION_CALL_CYCLE, UNDECLARED_ACTION_DEPENDENCY, INVALID_ACTION_REF, IDEMPOTENCY_CONFLICT, EXECUTION_FAILED, UNHANDLED_EXECUTION_ERROR, RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, STANDALONE_ASYNC_UNSUPPORTED, HOST_PROCESS_EXITED, EXECUTION_ABORTED, TIMEOUT, NETWORK_ERROR, CAPABILITY_UNAVAILABLE, STATE_KEY_NOT_FOUND, STORAGE_BUSY, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, EVENT_BACKPRESSURE_LIMIT, EVENT_CURSOR_EXPIRED, PROCESS_OUTPUT_LIMIT, PROCESS_SPAWN_ERROR, PROCESS_CANCELLED, PROCESS_TIMEOUT, UNAUTHORIZED, NOT_FOUND, SERVER_ERROR, PACKAGE_FORBIDDEN, ACTION_FORBIDDEN, PLAYBOOK_NOT_FOUND, REQUEST_TOO_LARGE, ACTION_START_FAILED, ACTION_EXECUTION_ERROR, DATA_DIR_IN_USE, DATA_DIR_RECOVERY_REQUIRED, PROCESS_FAILED, MCP_TOOL_NAME_COLLISION, ACCESS_DENIED, INVALID_FLAT_ARGUMENT, INVALID_JSON, INVALID_JSON_LITERAL, INPUT_PATH_CONFLICT, FLAT_INPUT_LIMIT_EXCEEDED, INPUT_LIMIT_EXCEEDED, INPUT_POLICY_VIOLATION, INPUT_CONFLICT, INPUT_FILE_NOT_FOUND, INPUT_FILE_READ_FAILED, INVALID_ARGUMENT, PACKAGE_NOT_ALLOWED, INVALID_PACKAGE_ID, PATH_TRAVERSAL, AMBIGUOUS_STATE_KEY, RUN_NOT_FOUND, RUN_ALREADY_FINISHED, PROJECT_ROOT_NOT_FOUND, describeActionLoadFailure, createErrorEnvelope, resolveExecutionHint, } from "./errors.js";
@@ -1,6 +1,6 @@
1
1
  import type { ExecutionEvent, ExecutionResult, JsonValue, RunRecord } from "@actiondock/sdk";
2
2
  import type { ActionInvoker, CancelResult, ExecutionTicket } from "../execution/types.js";
3
- import type { ProjectConfig, RuntimeProjectConfig } from "../project/types.js";
3
+ import type { ProjectConfig } from "../project/types.js";
4
4
  import { type PackageIdentity } from "../runtime/identity.js";
5
5
  import { type InvocationContext, type RunOptions } from "../invocation/types.js";
6
6
  import type { ActionSpec, ActionSummary, ConfigValueView, HostManagedPackageRuntime, ListActionsOptions, ListRunsOptions, PackageInfo, PackageRuntime, PackageRuntimeOptions, PackageRuntimeInternalOptions, PlaybookSpec, PlaybookSummary, StateScopeOptions } from "./types.js";
@@ -21,7 +21,7 @@ export declare class DefaultPackageRuntime implements HostManagedPackageRuntime
21
21
  readonly packageInstanceId: string;
22
22
  readonly generationId: string;
23
23
  readonly packageRoot?: string;
24
- readonly projectConfig: ProjectConfig | RuntimeProjectConfig;
24
+ readonly projectConfig: ProjectConfig;
25
25
  readonly inMemory: boolean;
26
26
  private readonly platform;
27
27
  private readonly actionsMap;
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { DefaultExecutionService } from "../execution/service.js";
4
4
  import { createNodePlatform } from "../platform/index.js";
5
- import { completeRuntimeProjectConfig, findProjectRoot, loadProjectConfig } from "../project/loader.js";
5
+ import { findProjectRoot, loadProjectConfig } from "../project/loader.js";
6
6
  import { RuntimeConfig } from "../runtime/context.js";
7
7
  import { normalizeActionCollection } from "../runtime/action-collection.js";
8
8
  import { isSecretConfigKey, sanitizeConfigDefinitions } from "../storage/mask.js";
@@ -125,8 +125,6 @@ export class DefaultPackageRuntime {
125
125
  version: "0.1.0",
126
126
  };
127
127
  }
128
- // 在唯一装配边界确定规程来源,索引与包图共享同一份完整配置快照。
129
- projectConfig = completeRuntimeProjectConfig(packageRoot, projectConfig);
130
128
  this.packageRoot = packageRoot;
131
129
  this.projectConfig = projectConfig;
132
130
  // 兼容未在公开选项契约中显式声明的包实例标识与代系标识内部参数透传
@@ -1,5 +1,5 @@
1
1
  import type { ActionDefinition } from "@actiondock/sdk";
2
- import type { ProjectConfig, RuntimeProjectConfig } from "../project/types.js";
2
+ import type { ProjectConfig } from "../project/types.js";
3
3
  import type { ActionSpec, PlaybookSpec } from "./types.js";
4
4
  /**
5
5
  * 静态清单索引构建入参:同一包的全部静态事实来源。
@@ -10,8 +10,8 @@ export interface StaticIndexInput {
10
10
  packageRoot?: string;
11
11
  /** 包唯一标识 */
12
12
  packageId: string;
13
- /** 项目配置(规范化清单配置快照或运行时来源,单一事实源) */
14
- projectConfig: ProjectConfig | RuntimeProjectConfig;
13
+ /** 项目配置(规范化清单配置快照,单一事实源) */
14
+ projectConfig: ProjectConfig;
15
15
  }
16
16
  /** Action 索引构建入参:静态事实来源之上叠加内存注入的 Action 定义集合 */
17
17
  export interface StaticActionIndexInput extends StaticIndexInput {
@@ -29,6 +29,8 @@ export interface StaticActionIndexInput extends StaticIndexInput {
29
29
  export declare function buildStaticActionMap(input: StaticActionIndexInput): Map<string, ActionSpec>;
30
30
  /**
31
31
  * 静态读取并聚合指定包的 Playbook 规范索引。
32
- * 统一复用 project/loader 的 loadPlaybooks(单一事实源),不再自行读文件或吞异常。
32
+ *
33
+ * 聚合来源:磁盘规程目录扫描(以 actiondock.json 声明为事实源)与
34
+ * 项目配置中声明的 playbooks;同键时配置声明覆盖磁盘扫描结果。
33
35
  */
34
36
  export declare function buildStaticPlaybookMap(input: StaticIndexInput): Map<string, PlaybookSpec>;