@actiondock/core 2.6.0 → 2.8.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.
Files changed (268) hide show
  1. package/README.md +61 -68
  2. package/dist/catalog/action-catalog.d.ts +56 -0
  3. package/dist/catalog/action-catalog.js +202 -0
  4. package/dist/catalog/discovery.d.ts +60 -0
  5. package/dist/catalog/discovery.js +119 -0
  6. package/dist/catalog/graph.d.ts +190 -0
  7. package/dist/catalog/graph.js +589 -0
  8. package/dist/catalog/index.d.ts +5 -5
  9. package/dist/catalog/index.js +5 -5
  10. package/dist/catalog/resolve-action.d.ts +43 -0
  11. package/dist/catalog/resolve-action.js +119 -0
  12. package/dist/catalog/resolve-playbook.d.ts +26 -0
  13. package/dist/catalog/resolve-playbook.js +114 -0
  14. package/dist/doctor/checks/project.js +27 -8
  15. package/dist/doctor/checks/registry.js +2 -2
  16. package/dist/doctor/checks/runtime.js +34 -1
  17. package/dist/errors.d.ts +122 -10
  18. package/dist/errors.js +123 -10
  19. package/dist/execution/service.d.ts +18 -16
  20. package/dist/execution/service.js +183 -252
  21. package/dist/execution/types.d.ts +25 -69
  22. package/dist/execution/types.js +2 -1
  23. package/dist/filter/intent.d.ts +8 -9
  24. package/dist/filter/intent.js +49 -10
  25. package/dist/graph/index.d.ts +4 -0
  26. package/dist/graph/index.js +4 -0
  27. package/dist/host/host.d.ts +74 -32
  28. package/dist/host/host.js +585 -336
  29. package/dist/host/routing.d.ts +15 -48
  30. package/dist/host/routing.js +90 -153
  31. package/dist/host/types.d.ts +50 -17
  32. package/dist/index.d.ts +21 -22
  33. package/dist/index.js +19 -21
  34. package/dist/input/advice.d.ts +104 -0
  35. package/dist/input/advice.js +716 -0
  36. package/dist/input/describe.d.ts +106 -0
  37. package/dist/input/describe.js +176 -0
  38. package/dist/input/file-input.d.ts +54 -0
  39. package/dist/input/file-input.js +124 -0
  40. package/dist/input/flat-decode.d.ts +11 -0
  41. package/dist/input/flat-decode.js +13 -0
  42. package/dist/input/flat-errors.d.ts +71 -0
  43. package/dist/input/flat-errors.js +87 -0
  44. package/dist/input/flat-materializer.d.ts +29 -0
  45. package/dist/input/flat-materializer.js +177 -0
  46. package/dist/input/flat-parser.d.ts +50 -0
  47. package/dist/input/flat-parser.js +169 -0
  48. package/dist/input/flat-predicates.d.ts +34 -0
  49. package/dist/input/flat-predicates.js +50 -0
  50. package/dist/input/index.d.ts +14 -0
  51. package/dist/input/index.js +14 -0
  52. package/dist/input/input-resolver.d.ts +63 -0
  53. package/dist/input/input-resolver.js +254 -0
  54. package/dist/input/json-depth-scanner.d.ts +17 -0
  55. package/dist/input/json-depth-scanner.js +49 -0
  56. package/dist/input/metadata.d.ts +99 -0
  57. package/dist/input/metadata.js +99 -0
  58. package/dist/input/stdin-input.d.ts +26 -0
  59. package/dist/input/stdin-input.js +125 -0
  60. package/dist/input/utf8.d.ts +19 -0
  61. package/dist/input/utf8.js +36 -0
  62. package/dist/input/validation-mapper.d.ts +27 -0
  63. package/dist/input/validation-mapper.js +144 -0
  64. package/dist/invocation/index.d.ts +2 -0
  65. package/dist/invocation/index.js +2 -0
  66. package/dist/invocation/policy.d.ts +157 -0
  67. package/dist/invocation/policy.js +231 -0
  68. package/dist/invocation/types.d.ts +172 -0
  69. package/dist/invocation/types.js +97 -0
  70. package/dist/ipc/diagnostic.d.ts +0 -12
  71. package/dist/ipc/diagnostic.js +0 -21
  72. package/dist/ipc/host.d.ts +4 -4
  73. package/dist/ipc/host.js +44 -47
  74. package/dist/ipc/index.d.ts +1 -1
  75. package/dist/ipc/index.js +1 -1
  76. package/dist/ipc/service.d.ts +40 -0
  77. package/dist/ipc/service.js +349 -0
  78. package/dist/ipc/types.d.ts +21 -15
  79. package/dist/json/index.d.ts +1 -0
  80. package/dist/json/index.js +1 -0
  81. package/dist/json/value-validator.d.ts +88 -0
  82. package/dist/json/value-validator.js +330 -0
  83. package/dist/node/index.d.ts +1 -0
  84. package/dist/node/index.js +1 -0
  85. package/dist/node/module-loader.d.ts +63 -0
  86. package/dist/node/module-loader.js +112 -0
  87. package/dist/package/index.d.ts +23 -0
  88. package/dist/package/index.js +18 -0
  89. package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
  90. package/dist/{app/app.js → package/runtime.js} +140 -95
  91. package/dist/{app → package}/static-index.js +58 -41
  92. package/dist/package/storage-view.d.ts +13 -0
  93. package/dist/package/storage-view.js +22 -0
  94. package/dist/{app → package}/types.d.ts +76 -57
  95. package/dist/package/types.js +22 -0
  96. package/dist/platform/index.d.ts +1 -1
  97. package/dist/platform/index.js +1 -1
  98. package/dist/platform/node.d.ts +48 -0
  99. package/dist/platform/node.js +96 -0
  100. package/dist/platform/types.d.ts +0 -9
  101. package/dist/process/control-arbiter.d.ts +2 -1
  102. package/dist/process/control-arbiter.js +1 -2
  103. package/dist/process/driver.d.ts +9 -8
  104. package/dist/process/driver.js +11 -22
  105. package/dist/process/index.d.ts +2 -0
  106. package/dist/process/index.js +2 -0
  107. package/dist/process/managed-record.d.ts +2 -2
  108. package/dist/process/process-driver.d.ts +109 -0
  109. package/dist/process/process-driver.js +650 -0
  110. package/dist/process/process-executor.d.ts +47 -0
  111. package/dist/process/process-executor.js +296 -0
  112. package/dist/process/process-manager.js +48 -26
  113. package/dist/process/run-executor.js +12 -12
  114. package/dist/profile/client-actions.js +2 -2
  115. package/dist/profile/client-health.js +3 -2
  116. package/dist/profile/client-query.js +5 -6
  117. package/dist/profile/client-transport.d.ts +19 -17
  118. package/dist/profile/client-transport.js +48 -80
  119. package/dist/profile/client.d.ts +2 -2
  120. package/dist/profile/client.js +1 -1
  121. package/dist/profile/index.d.ts +1 -0
  122. package/dist/profile/index.js +1 -0
  123. package/dist/profile/manager.d.ts +5 -0
  124. package/dist/profile/manager.js +41 -6
  125. package/dist/project/closure.js +2 -2
  126. package/dist/project/index.d.ts +8 -1
  127. package/dist/project/index.js +10 -1
  128. package/dist/project/init.js +2 -2
  129. package/dist/project/loader.d.ts +1 -1
  130. package/dist/project/loader.js +26 -29
  131. package/dist/project/transactions.js +5 -10
  132. package/dist/registry/index.d.ts +3 -1
  133. package/dist/registry/index.js +2 -1
  134. package/dist/registry/lock.d.ts +28 -7
  135. package/dist/registry/lock.js +136 -16
  136. package/dist/registry/registry.d.ts +1 -5
  137. package/dist/registry/registry.js +1 -53
  138. package/dist/registry/scan.d.ts +0 -15
  139. package/dist/registry/scan.js +0 -59
  140. package/dist/registry/store.d.ts +42 -0
  141. package/dist/registry/store.js +43 -0
  142. package/dist/registry/types.d.ts +0 -24
  143. package/dist/runtime/action-collection.d.ts +1 -1
  144. package/dist/runtime/action-registry.d.ts +0 -4
  145. package/dist/runtime/action-registry.js +0 -7
  146. package/dist/runtime/context.js +5 -11
  147. package/dist/runtime/events.js +3 -6
  148. package/dist/runtime/identity.d.ts +22 -0
  149. package/dist/runtime/identity.js +10 -0
  150. package/dist/runtime/index.d.ts +1 -2
  151. package/dist/runtime/index.js +1 -2
  152. package/dist/runtime/module-loader.d.ts +2 -34
  153. package/dist/runtime/module-loader.js +1 -16
  154. package/dist/runtime/process.d.ts +6 -24
  155. package/dist/runtime/process.js +1 -118
  156. package/dist/runtime/run-persistence.js +2 -5
  157. package/dist/runtime/runner.d.ts +33 -103
  158. package/dist/runtime/runner.js +142 -404
  159. package/dist/runtime/standalone.d.ts +37 -9
  160. package/dist/runtime/standalone.js +195 -136
  161. package/dist/schema/index.d.ts +1 -0
  162. package/dist/schema/index.js +1 -0
  163. package/dist/schema/validator.d.ts +10 -0
  164. package/dist/schema/validator.js +48 -54
  165. package/dist/server/body.d.ts +16 -8
  166. package/dist/server/body.js +33 -16
  167. package/dist/server/dispatcher.d.ts +6 -10
  168. package/dist/server/dispatcher.js +24 -32
  169. package/dist/server/http-server.d.ts +87 -0
  170. package/dist/server/http-server.js +304 -0
  171. package/dist/server/index.d.ts +11 -0
  172. package/dist/server/index.js +10 -0
  173. package/dist/server/mcp-endpoint.d.ts +61 -0
  174. package/dist/server/mcp-endpoint.js +118 -0
  175. package/dist/server/routes/actions.js +34 -28
  176. package/dist/server/routes/common.d.ts +10 -14
  177. package/dist/server/routes/common.js +32 -56
  178. package/dist/server/routes/config.js +54 -64
  179. package/dist/server/routes/doctor.d.ts +1 -1
  180. package/dist/server/routes/doctor.js +10 -18
  181. package/dist/server/routes/health.d.ts +1 -1
  182. package/dist/server/routes/health.js +2 -3
  183. package/dist/server/routes/info.d.ts +2 -2
  184. package/dist/server/routes/info.js +12 -13
  185. package/dist/server/routes/playbooks.js +16 -29
  186. package/dist/server/routes/runs.js +95 -117
  187. package/dist/server/routes/state.js +63 -62
  188. package/dist/server/server.d.ts +2 -2
  189. package/dist/server/server.js +43 -227
  190. package/dist/server/types.d.ts +8 -19
  191. package/dist/service/factory.d.ts +12 -0
  192. package/dist/service/factory.js +85 -0
  193. package/dist/{target → service}/index.d.ts +1 -1
  194. package/dist/{target → service}/index.js +1 -1
  195. package/dist/service/local.d.ts +27 -0
  196. package/dist/service/local.js +138 -0
  197. package/dist/{target → service}/remote-errors.d.ts +3 -6
  198. package/dist/service/remote-errors.js +38 -0
  199. package/dist/{target → service}/remote-polling.d.ts +2 -2
  200. package/dist/{target → service}/remote-polling.js +8 -8
  201. package/dist/service/remote.d.ts +34 -0
  202. package/dist/service/remote.js +634 -0
  203. package/dist/service/sse-stream.d.ts +24 -0
  204. package/dist/service/sse-stream.js +139 -0
  205. package/dist/service/types.d.ts +272 -0
  206. package/dist/service/types.js +32 -0
  207. package/dist/storage/data-dir-lock.js +10 -5
  208. package/dist/storage/driver.d.ts +2 -1
  209. package/dist/storage/driver.js +3 -52
  210. package/dist/storage/index.d.ts +1 -0
  211. package/dist/storage/index.js +1 -0
  212. package/dist/storage/lock-core.d.ts +2 -6
  213. package/dist/storage/lock-core.js +4 -17
  214. package/dist/storage/params.d.ts +2 -8
  215. package/dist/storage/params.js +2 -8
  216. package/dist/storage/sqlite-driver.d.ts +40 -0
  217. package/dist/storage/sqlite-driver.js +116 -0
  218. package/dist/storage/sqlite.js +21 -6
  219. package/dist/storage/types.d.ts +4 -4
  220. package/dist/storage/types.js +2 -2
  221. package/dist/utils/index.d.ts +53 -0
  222. package/dist/utils/index.js +99 -4
  223. package/dist/utils/process.d.ts +10 -0
  224. package/dist/utils/process.js +21 -0
  225. package/dist/version.d.ts +1 -1
  226. package/dist/version.js +1 -1
  227. package/package.json +41 -3
  228. package/dist/app/index.d.ts +0 -2
  229. package/dist/app/index.js +0 -2
  230. package/dist/app/types.js +0 -1
  231. package/dist/catalog/action-index.d.ts +0 -9
  232. package/dist/catalog/action-index.js +0 -95
  233. package/dist/catalog/action-resolver.d.ts +0 -20
  234. package/dist/catalog/action-resolver.js +0 -95
  235. package/dist/catalog/location-registry.d.ts +0 -15
  236. package/dist/catalog/location-registry.js +0 -138
  237. package/dist/catalog/package-catalog.d.ts +0 -7
  238. package/dist/catalog/package-catalog.js +0 -77
  239. package/dist/catalog/types.d.ts +0 -68
  240. package/dist/catalog/types.js +0 -1
  241. package/dist/export/index.d.ts +0 -1
  242. package/dist/export/index.js +0 -1
  243. package/dist/export/templates.d.ts +0 -71
  244. package/dist/export/templates.js +0 -623
  245. package/dist/ipc/target.d.ts +0 -74
  246. package/dist/ipc/target.js +0 -365
  247. package/dist/platform/default.d.ts +0 -38
  248. package/dist/platform/default.js +0 -78
  249. package/dist/project/resolver.d.ts +0 -116
  250. package/dist/project/resolver.js +0 -376
  251. package/dist/registry/resolve.d.ts +0 -62
  252. package/dist/registry/resolve.js +0 -195
  253. package/dist/runtime/execution-manager.d.ts +0 -48
  254. package/dist/runtime/execution-manager.js +0 -66
  255. package/dist/runtime/package-runner-factory.d.ts +0 -82
  256. package/dist/runtime/package-runner-factory.js +0 -186
  257. package/dist/target/local.d.ts +0 -53
  258. package/dist/target/local.js +0 -349
  259. package/dist/target/remote-errors.js +0 -51
  260. package/dist/target/remote.d.ts +0 -86
  261. package/dist/target/remote.js +0 -818
  262. package/dist/target/target.d.ts +0 -6
  263. package/dist/target/target.js +0 -37
  264. package/dist/target/types.d.ts +0 -261
  265. package/dist/target/types.js +0 -35
  266. /package/dist/{app → package}/static-index.d.ts +0 -0
  267. /package/dist/{target → service}/sse-parser.d.ts +0 -0
  268. /package/dist/{target → service}/sse-parser.js +0 -0
@@ -1,376 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { basename, dirname, join, resolve } from "node:path";
3
- import { listLinkedPackages } from "../registry/registry.js";
4
- import { computeManifestDigest, parseJsonWithoutDuplicates } from "./digest.js";
5
- import { loadLockfile } from "./lockfile.js";
6
- import { loadPlaybooks } from "./loader.js";
7
- import { loadManifest, MANIFEST_FILE_NAME } from "./manifest.js";
8
- /**
9
- * 解析基础 SemVer 版本字符串。
10
- */
11
- export function parseSemVer(v) {
12
- const match = v.trim().replace(/^[v=]/, "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
13
- if (!match)
14
- return null;
15
- return {
16
- major: parseInt(match[1], 10),
17
- minor: parseInt(match[2], 10),
18
- patch: parseInt(match[3], 10),
19
- prerelease: match[4],
20
- };
21
- }
22
- /**
23
- * 校验两个语义化版本范围是否兼容并能收敛为单一解析版本。
24
- * 遵循设计规范:直接或传递版本范围无法收敛时拒绝并抛出 ACTION_PACKAGE_VERSION_CONFLICT。
25
- */
26
- export function areVersionsCompatible(v1, v2) {
27
- if (v1 === v2 || v1 === "*" || v2 === "*" || !v1 || !v2) {
28
- return true;
29
- }
30
- // 处理前缀范围符(如 ^1.0.0, ~1.0.0)
31
- const clean1 = v1.trim().replace(/^[\^~=]/, "");
32
- const clean2 = v2.trim().replace(/^[\^~=]/, "");
33
- const sem1 = parseSemVer(clean1);
34
- const sem2 = parseSemVer(clean2);
35
- if (!sem1 || !sem2) {
36
- // 非标准 SemVer 时按字面匹配
37
- return v1 === v2;
38
- }
39
- // 若存在主版本号不一致,则严格视为不兼容
40
- if (sem1.major !== sem2.major) {
41
- return false;
42
- }
43
- // 若带波浪号(~1.2.0),次版本号必须一致
44
- if (v1.startsWith("~") || v2.startsWith("~")) {
45
- if (sem1.minor !== sem2.minor) {
46
- return false;
47
- }
48
- }
49
- return true;
50
- }
51
- /**
52
- * 版本冲突错误。
53
- */
54
- export class ActionPackageVersionConflictError extends Error {
55
- code = "ACTION_PACKAGE_VERSION_CONFLICT";
56
- packageId;
57
- conflicts;
58
- constructor(packageId, conflicts) {
59
- const details = conflicts.map((c) => `'${c.requester}' 要求 '${c.rangeOrVersion}'`).join(", ");
60
- super(`ACTION_PACKAGE_VERSION_CONFLICT: 逻辑包 '${packageId}' 存在不可收敛的版本冲突: ${details}`);
61
- this.name = "ActionPackageVersionConflictError";
62
- this.packageId = packageId;
63
- this.conflicts = conflicts;
64
- }
65
- }
66
- /**
67
- * 未声明依赖调用拦截错误。
68
- */
69
- export class UndeclaredActionDependencyError extends Error {
70
- code = "UNDECLARED_ACTION_DEPENDENCY";
71
- targetRef;
72
- caller;
73
- constructor(targetRef, caller, reason) {
74
- const msg = caller
75
- ? `UNDECLARED_ACTION_DEPENDENCY: Action '${caller}' 未在 'uses' 中声明对 '${targetRef}' 的跨包依赖`
76
- : `UNDECLARED_ACTION_DEPENDENCY: 根调用 Action '${targetRef}' 被拒绝: 目标包既非 actiondock.json 直接依赖,亦未被可见 Playbook 委托${reason ? ` (${reason})` : ""}`;
77
- super(msg);
78
- this.name = "UndeclaredActionDependencyError";
79
- this.targetRef = targetRef;
80
- this.caller = caller;
81
- }
82
- }
83
- /**
84
- * 依赖解析器 ActionPackageResolver。
85
- * 负责从 actiondock.json.dependencies 与 actiondock.lock.json 建立包索引与依赖闭包,
86
- * 实施版本冲突检测与调用可见性鉴权。
87
- */
88
- export class ActionPackageResolver {
89
- projectRoot;
90
- options;
91
- resolvedGraph;
92
- constructor(options) {
93
- this.projectRoot = resolve(options.projectRoot);
94
- this.options = { ...options, projectRoot: this.projectRoot };
95
- }
96
- /**
97
- * 同步解析依赖图。
98
- */
99
- resolveSync() {
100
- if (this.resolvedGraph) {
101
- return this.resolvedGraph;
102
- }
103
- const rootManifest = this.options.manifest ||
104
- loadManifest(this.projectRoot) || {
105
- id: basename(this.projectRoot),
106
- version: "0.1.0",
107
- };
108
- const rootPackageId = rootManifest.id;
109
- const lockfile = this.options.lockfile ?? loadLockfile(this.projectRoot);
110
- const packages = new Map();
111
- const directDependencyIds = new Set();
112
- const transitiveDependencyIds = new Set();
113
- const versionRequirements = new Map();
114
- // 记录根包自身
115
- const rootDigest = computeManifestDigest(rootManifest);
116
- packages.set(rootPackageId, {
117
- packageId: rootPackageId,
118
- npmPackage: rootPackageId,
119
- version: rootManifest.version || "0.1.0",
120
- packageRoot: this.projectRoot,
121
- manifest: rootManifest,
122
- manifestDigest: rootDigest,
123
- isDirect: true,
124
- isRoot: true,
125
- });
126
- directDependencyIds.add(rootPackageId);
127
- // 探测开发本地软链接覆盖
128
- const devLinkMap = new Map();
129
- if (this.options.allowDevLinks) {
130
- try {
131
- const linked = listLinkedPackages(this.options.customHome);
132
- for (const entry of linked) {
133
- if (existsSync(entry.path)) {
134
- devLinkMap.set(entry.id, entry.path);
135
- }
136
- }
137
- }
138
- catch {
139
- // 忽略扫描外部链接包异常
140
- }
141
- }
142
- function recordRequirement(pkgId, requester, rangeOrVersion) {
143
- const existing = versionRequirements.get(pkgId) || [];
144
- for (const req of existing) {
145
- if (!areVersionsCompatible(req.rangeOrVersion, rangeOrVersion)) {
146
- throw new ActionPackageVersionConflictError(pkgId, [
147
- req,
148
- { requester, rangeOrVersion },
149
- ]);
150
- }
151
- }
152
- existing.push({ requester, rangeOrVersion });
153
- versionRequirements.set(pkgId, existing);
154
- }
155
- // 广度优先遍历解析直接与间接依赖
156
- const queue = [];
157
- for (const [depId, spec] of Object.entries(rootManifest.dependencies || {})) {
158
- directDependencyIds.add(depId);
159
- recordRequirement(depId, rootPackageId, spec);
160
- queue.push({
161
- pkgId: depId,
162
- requester: rootPackageId,
163
- rangeOrSpec: spec,
164
- isDirect: true,
165
- });
166
- }
167
- while (queue.length > 0) {
168
- const item = queue.shift();
169
- if (packages.has(item.pkgId)) {
170
- continue;
171
- }
172
- // 寻址包安装根目录
173
- let pkgDir = null;
174
- const locked = lockfile?.packages?.[item.pkgId];
175
- // 优先级:显式注入路径 -> 开发软链接覆盖 -> 锁文件记录 -> node_modules 探测
176
- if (this.options.packageRoots?.[item.pkgId]) {
177
- pkgDir = this.options.packageRoots[item.pkgId];
178
- }
179
- else if (devLinkMap.has(item.pkgId)) {
180
- pkgDir = devLinkMap.get(item.pkgId);
181
- }
182
- else {
183
- const candidateNames = [];
184
- if (locked?.npmPackage) {
185
- candidateNames.push(locked.npmPackage);
186
- }
187
- candidateNames.push(item.rangeOrSpec);
188
- candidateNames.push(item.pkgId);
189
- let cur = this.projectRoot;
190
- while (true) {
191
- for (const candName of candidateNames) {
192
- const candPath = join(cur, "node_modules", candName);
193
- if (existsSync(candPath) && existsSync(join(candPath, MANIFEST_FILE_NAME))) {
194
- pkgDir = candPath;
195
- break;
196
- }
197
- }
198
- if (pkgDir)
199
- break;
200
- const parent = dirname(cur);
201
- if (parent === cur)
202
- break;
203
- cur = parent;
204
- }
205
- }
206
- if (!pkgDir || !existsSync(pkgDir)) {
207
- throw new Error(`PACKAGE_NOT_FOUND: Package '${item.pkgId}' required by '${item.requester}' is not installed in ${this.projectRoot}. Please run 'ad add ${item.rangeOrSpec}'.`);
208
- }
209
- const manifestPath = join(pkgDir, MANIFEST_FILE_NAME);
210
- if (!existsSync(manifestPath)) {
211
- throw new Error(`Action package '${item.pkgId}' at '${pkgDir}' misses required manifest 'actiondock.json'`);
212
- }
213
- let manifestRaw;
214
- try {
215
- manifestRaw = readFileSync(manifestPath, "utf-8");
216
- }
217
- catch (err) {
218
- throw new Error(`Failed to read manifest for '${item.pkgId}': ${err.message}`);
219
- }
220
- const depManifest = parseJsonWithoutDuplicates(manifestRaw);
221
- const actualDigest = computeManifestDigest(depManifest);
222
- // 锁文件摘要校验
223
- if (locked?.manifestDigest && locked.manifestDigest !== actualDigest) {
224
- throw new Error(`Manifest digest mismatch for package '${item.pkgId}': expected '${locked.manifestDigest}', got '${actualDigest}'. Re-resolution required.`);
225
- }
226
- const pkgVersion = depManifest.version || locked?.version || "0.1.0";
227
- // 校验版本是否满足已知要求
228
- const reqs = versionRequirements.get(item.pkgId) || [];
229
- for (const req of reqs) {
230
- if (!areVersionsCompatible(req.rangeOrVersion, pkgVersion)) {
231
- throw new ActionPackageVersionConflictError(item.pkgId, [
232
- req,
233
- { requester: item.pkgId, rangeOrVersion: pkgVersion },
234
- ]);
235
- }
236
- }
237
- const info = {
238
- packageId: item.pkgId,
239
- npmPackage: locked?.npmPackage || item.rangeOrSpec,
240
- version: pkgVersion,
241
- packageRoot: pkgDir,
242
- manifest: depManifest,
243
- manifestDigest: actualDigest,
244
- isDirect: item.isDirect,
245
- isRoot: false,
246
- };
247
- packages.set(item.pkgId, info);
248
- if (!item.isDirect) {
249
- transitiveDependencyIds.add(item.pkgId);
250
- }
251
- // 继续搜寻传递依赖
252
- for (const [subDepId, subSpec] of Object.entries(depManifest.dependencies || {})) {
253
- recordRequirement(subDepId, item.pkgId, subSpec);
254
- if (!packages.has(subDepId)) {
255
- queue.push({
256
- pkgId: subDepId,
257
- requester: item.pkgId,
258
- rangeOrSpec: subSpec,
259
- isDirect: false,
260
- });
261
- }
262
- }
263
- }
264
- // 收集可见 Playbook 与被委托 Action
265
- const visiblePlaybooks = new Map();
266
- const delegatedActions = new Set();
267
- // 根包 Playbooks
268
- try {
269
- const rootPbs = loadPlaybooks(this.projectRoot);
270
- for (const [id, pb] of rootPbs.entries()) {
271
- visiblePlaybooks.set(id, pb);
272
- visiblePlaybooks.set(`${rootPackageId}/${id}`, pb);
273
- }
274
- }
275
- catch {
276
- // 忽略根包 Playbook 加载异常
277
- }
278
- // 直接依赖包 Playbooks
279
- for (const depId of directDependencyIds) {
280
- if (depId === rootPackageId)
281
- continue;
282
- const depPkg = packages.get(depId);
283
- if (depPkg) {
284
- try {
285
- const depPbs = loadPlaybooks(depPkg.packageRoot);
286
- for (const [id, pb] of depPbs.entries()) {
287
- visiblePlaybooks.set(`${depId}/${id}`, pb);
288
- }
289
- }
290
- catch {
291
- // 忽略依赖包 Playbook 加载异常
292
- }
293
- }
294
- }
295
- // 可见 Playbook 点名委托的 Action 收集
296
- for (const pb of visiblePlaybooks.values()) {
297
- if (Array.isArray(pb.actions)) {
298
- for (const actRef of pb.actions) {
299
- if (typeof actRef === "string" && actRef.trim()) {
300
- delegatedActions.add(actRef.trim());
301
- }
302
- }
303
- }
304
- }
305
- this.resolvedGraph = {
306
- rootPackageId,
307
- packages,
308
- directDependencyIds,
309
- transitiveDependencyIds,
310
- visiblePlaybooks,
311
- delegatedActions,
312
- };
313
- return this.resolvedGraph;
314
- }
315
- /**
316
- * 异步解析依赖图。
317
- */
318
- async resolve() {
319
- return this.resolveSync();
320
- }
321
- /**
322
- * 判定目标 Action 是否允许作为根调用发起。
323
- * 规则:
324
- * - 目标属于当前根包;
325
- * - 目标属于 actiondock.json 直接依赖;
326
- * - 目标属于可见 Playbook 精确委托点名的 Action。
327
- */
328
- canRootCall(targetPackageId, targetActionId) {
329
- const graph = this.resolveSync();
330
- if (targetPackageId === graph.rootPackageId) {
331
- return true;
332
- }
333
- if (graph.directDependencyIds.has(targetPackageId)) {
334
- return true;
335
- }
336
- const qualifiedRef = `${targetPackageId}/${targetActionId}`;
337
- if (graph.delegatedActions.has(qualifiedRef)) {
338
- return true;
339
- }
340
- return false;
341
- }
342
- /**
343
- * 校验根调用权限,不合法时抛出 UNDECLARED_ACTION_DEPENDENCY。
344
- */
345
- assertRootCallAllowed(targetPackageId, targetActionId) {
346
- if (!this.canRootCall(targetPackageId, targetActionId)) {
347
- throw new UndeclaredActionDependencyError(`${targetPackageId}/${targetActionId}`);
348
- }
349
- }
350
- /**
351
- * 判定跨包级联调用是否合法。
352
- * 规则:调用者 Action 必须在 actiondock.json 的 uses 中显式声明对目标 Action 的依赖。
353
- */
354
- canCascadeCall(callerPackageId, callerActionId, targetPackageId, targetActionId) {
355
- if (callerPackageId === targetPackageId) {
356
- return true;
357
- }
358
- const graph = this.resolveSync();
359
- const callerPkg = graph.packages.get(callerPackageId);
360
- if (!callerPkg) {
361
- return false;
362
- }
363
- const callerActionEntry = callerPkg.manifest.actions?.[callerActionId];
364
- const usesList = callerActionEntry?.uses || [];
365
- const targetRef = `${targetPackageId}/${targetActionId}`;
366
- return usesList.some((u) => u === targetRef || u === `${targetPackageId}/*` || u === targetPackageId);
367
- }
368
- /**
369
- * 校验跨包级联调用权限,不合法时抛出 UNDECLARED_ACTION_DEPENDENCY。
370
- */
371
- assertCascadeCallAllowed(callerPackageId, callerActionId, targetPackageId, targetActionId) {
372
- if (!this.canCascadeCall(callerPackageId, callerActionId, targetPackageId, targetActionId)) {
373
- throw new UndeclaredActionDependencyError(`${targetPackageId}/${targetActionId}`, `${callerPackageId}/${callerActionId}`);
374
- }
375
- }
376
- }
@@ -1,62 +0,0 @@
1
- import type { ActionDockManifest, PlaybookDefinition } from "../project/types.js";
2
- import type { LinkedPackageEntry } from "./types.js";
3
- /**
4
- * 流程步骤的惰性执行体:同步驱动器直接调用,异步驱动器 await,
5
- * 执行中抛出的异常由驱动器通过 it.throw 回灌生成器的 try/catch。
6
- */
7
- type FlowThunk = () => any;
8
- /**
9
- * 实体解析探针:命中返回实体值(Action 场景恒为 true),未命中返回 undefined。
10
- */
11
- type EntityProbe<V> = (projectRoot: string, config: ActionDockManifest, entityId: string) => V;
12
- /**
13
- * 由命中结果构造最终解析产物。
14
- */
15
- type EntityResultBuilder<V, R> = (projectRoot: string, packageId: string, entityId: string, value: V) => R;
16
- interface ResolveEntityFlowOptions<V, R> {
17
- /** 实体完整标识符(可能是裸 ID 或 <pkg>/<id>、<pkg>:<id> 形式) */
18
- identifier: string;
19
- /** 起始工作目录 */
20
- cwd: string;
21
- /** 实体名词(Action 或 Playbook),仅用于错误文案 */
22
- entityNoun: string;
23
- /** 获取链接包列表(同步或异步由注入方决定,流程通过 thunk 统一驱动) */
24
- listLinkedPackages: () => LinkedPackageEntry[];
25
- /** 实体探针 */
26
- probe: EntityProbe<V>;
27
- /** 解析结果构造器 */
28
- buildResult: EntityResultBuilder<V, R>;
29
- }
30
- /**
31
- * 实体解析唯一流程(生成器表达):
32
- * 当前项目探测 → scoped 标识符拆分 → 注册表精确匹配 → 遍历链接包 →
33
- * 单命中返回、多命中报错、零命中报错。
34
- *
35
- * 仅将可能异步的操作(探针、链接列表获取)以 thunk 形式 yield,
36
- * 由 runFlowSync / runFlowAsync 双驱动器分别以同步调用或 await 方式执行。
37
- */
38
- export declare function resolveEntityFlow<V, R>(opts: ResolveEntityFlowOptions<V, R>): Generator<FlowThunk, R, any>;
39
- /**
40
- * 同步驱动器:逐个调用 thunk 并把结果回灌生成器,
41
- * thunk 抛出的异常经 it.throw 回灌生成器内部的 try/catch 处理。
42
- * 同步流程中误注入异步 thunk 时立即抛错,避免 Promise 被当作命中值静默错判。
43
- */
44
- export declare function runFlowSync<R>(flow: Generator<FlowThunk, R, any>): R;
45
- /**
46
- * 异步驱动器:await 每个 thunk 后回灌结果,拒绝原因经 it.throw 回灌。
47
- */
48
- export declare function runFlowAsync<R>(flow: Generator<FlowThunk, R, any>): Promise<R>;
49
- /**
50
- * Action 探针(同步):manifest 声明优先,其次探测源码文件是否落盘。
51
- */
52
- export declare function probeActionSync(projectRoot: string, config: ActionDockManifest, actionId: string): true | undefined;
53
- /**
54
- * Action 探针(异步):manifest 声明优先,其次加载源码模块;
55
- * 模块加载失败时回退同步探测,保证与同步路径判定一致。
56
- */
57
- export declare function probeActionAsync(projectRoot: string, config: ActionDockManifest, actionId: string): Promise<true | undefined>;
58
- /**
59
- * Playbook 探针:以 actiondock.json 的 playbooks 声明为唯一事实源,命中返回规程定义。
60
- */
61
- export declare function probePlaybook(projectRoot: string, config: ActionDockManifest, playbookId: string): PlaybookDefinition | undefined;
62
- export {};
@@ -1,195 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { findProjectRoot, loadActions, loadPlaybooks, loadProjectConfig } from "../project/loader.js";
4
- import { loadManifest } from "../project/manifest.js";
5
- import { getPackageSlug } from "../utils/index.js";
6
- /**
7
- * 实体解析唯一流程(生成器表达):
8
- * 当前项目探测 → scoped 标识符拆分 → 注册表精确匹配 → 遍历链接包 →
9
- * 单命中返回、多命中报错、零命中报错。
10
- *
11
- * 仅将可能异步的操作(探针、链接列表获取)以 thunk 形式 yield,
12
- * 由 runFlowSync / runFlowAsync 双驱动器分别以同步调用或 await 方式执行。
13
- */
14
- export function* resolveEntityFlow(opts) {
15
- const { identifier, entityNoun } = opts;
16
- // 当前项目(或其父级项目)优先探测
17
- const currentRoot = findProjectRoot(opts.cwd);
18
- if (currentRoot) {
19
- try {
20
- const config = loadProjectConfig(currentRoot);
21
- const hit = yield () => opts.probe(currentRoot, config, identifier);
22
- if (hit !== undefined) {
23
- return opts.buildResult(currentRoot, config.id, identifier, hit);
24
- }
25
- }
26
- catch {
27
- // 当前项目配置损坏或探测失败:忽略并继续注册表查找
28
- }
29
- }
30
- // scoped 标识符拆分:<package-id>/<entity-id> 或 <package-id>:<entity-id>
31
- let targetPackage;
32
- let pureEntityId = identifier;
33
- if (identifier.includes("/")) {
34
- const slashIdx = identifier.lastIndexOf("/");
35
- targetPackage = identifier.slice(0, slashIdx);
36
- pureEntityId = identifier.slice(slashIdx + 1);
37
- }
38
- else if (identifier.includes(":")) {
39
- const colonIdx = identifier.lastIndexOf(":");
40
- targetPackage = identifier.slice(0, colonIdx);
41
- pureEntityId = identifier.slice(colonIdx + 1);
42
- }
43
- const linkedList = yield () => opts.listLinkedPackages();
44
- if (targetPackage) {
45
- let targetRoot;
46
- let targetPkgId = targetPackage;
47
- if (currentRoot) {
48
- try {
49
- const config = loadProjectConfig(currentRoot);
50
- if (config.id === targetPackage || getPackageSlug(config.id) === targetPackage) {
51
- targetRoot = currentRoot;
52
- targetPkgId = config.id;
53
- }
54
- }
55
- catch {
56
- // 当前项目配置损坏:忽略,回退注册表匹配
57
- }
58
- }
59
- let pkg;
60
- if (!targetRoot) {
61
- pkg = linkedList.find((p) => p.id === targetPackage || getPackageSlug(p.id) === targetPackage);
62
- if (pkg && existsSync(pkg.path)) {
63
- targetRoot = pkg.path;
64
- targetPkgId = pkg.id;
65
- }
66
- }
67
- if (!targetRoot || !existsSync(targetRoot)) {
68
- throw new Error(`Linked package '${targetPackage}' not found or path no longer exists (${pkg?.path || "unregistered"}). Run 'ad link' in the package directory.`);
69
- }
70
- const config = loadProjectConfig(targetRoot);
71
- const hit = yield () => opts.probe(targetRoot, config, pureEntityId);
72
- if (hit === undefined) {
73
- throw new Error(`${entityNoun} '${pureEntityId}' not found in package '${targetPkgId}' (${targetRoot})`);
74
- }
75
- return opts.buildResult(targetRoot, targetPkgId, pureEntityId, hit);
76
- }
77
- // 遍历全部链接包搜索
78
- const matches = [];
79
- for (const pkg of linkedList) {
80
- if (!existsSync(pkg.path))
81
- continue;
82
- try {
83
- const config = loadProjectConfig(pkg.path);
84
- const hit = yield () => opts.probe(pkg.path, config, identifier);
85
- if (hit !== undefined) {
86
- matches.push({ entry: pkg, entityId: identifier, value: hit });
87
- }
88
- }
89
- catch {
90
- // 忽略损坏的链接包:单个包配置或探测异常不应中断其余包的匹配
91
- }
92
- }
93
- if (matches.length === 1) {
94
- const m = matches[0];
95
- return opts.buildResult(m.entry.path, m.entry.id, m.entityId, m.value);
96
- }
97
- if (matches.length > 1) {
98
- const pkgList = matches.map((m) => `'${m.entry.id}'`).join(", ");
99
- throw new Error(`${entityNoun} '${identifier}' is provided by multiple linked packages: ${pkgList}. Please specify using '<package-id>/${identifier}'.`);
100
- }
101
- if (currentRoot) {
102
- throw new Error(`${entityNoun} '${identifier}' not found in current project or any linked packages`);
103
- }
104
- else {
105
- throw new Error(`${entityNoun} '${identifier}' not found. You are not in an ActionDock project, and no linked package provides '${identifier}'. Use 'ad link' to register your package.`);
106
- }
107
- }
108
- /**
109
- * 同步驱动器:逐个调用 thunk 并把结果回灌生成器,
110
- * thunk 抛出的异常经 it.throw 回灌生成器内部的 try/catch 处理。
111
- * 同步流程中误注入异步 thunk 时立即抛错,避免 Promise 被当作命中值静默错判。
112
- */
113
- export function runFlowSync(flow) {
114
- let step = flow.next();
115
- while (!step.done) {
116
- const value = step.value();
117
- if (value !== undefined && typeof value.then === "function") {
118
- throw new Error("Synchronous resolution received an asynchronous effect; check the injected probe and linked-list loader");
119
- }
120
- let next;
121
- try {
122
- next = flow.next(value);
123
- }
124
- catch (err) {
125
- next = flow.throw(err);
126
- }
127
- step = next;
128
- }
129
- return step.value;
130
- }
131
- /**
132
- * 异步驱动器:await 每个 thunk 后回灌结果,拒绝原因经 it.throw 回灌。
133
- */
134
- export async function runFlowAsync(flow) {
135
- let step = flow.next();
136
- while (!step.done) {
137
- let next;
138
- try {
139
- next = flow.next(await step.value());
140
- }
141
- catch (err) {
142
- next = flow.throw(err);
143
- }
144
- step = next;
145
- }
146
- return step.value;
147
- }
148
- /**
149
- * Action 探针(同步):manifest 声明优先,其次探测源码文件是否落盘。
150
- */
151
- export function probeActionSync(projectRoot, config, actionId) {
152
- const manifest = loadManifest(projectRoot);
153
- if (manifest?.actions && actionId in manifest.actions) {
154
- return true;
155
- }
156
- const dir = join(projectRoot, config.actionsDir || "actions");
157
- if (!existsSync(dir)) {
158
- return undefined;
159
- }
160
- if (actionId.includes("..") || actionId.startsWith("/") || actionId.startsWith("\\")) {
161
- return undefined;
162
- }
163
- if (existsSync(join(dir, `${actionId}.ts`)) || existsSync(join(dir, `${actionId}.js`))) {
164
- return true;
165
- }
166
- const relFile = actionId.replace(/\./g, "/");
167
- if (existsSync(join(dir, `${relFile}.ts`)) || existsSync(join(dir, `${relFile}.js`))) {
168
- return true;
169
- }
170
- return undefined;
171
- }
172
- /**
173
- * Action 探针(异步):manifest 声明优先,其次加载源码模块;
174
- * 模块加载失败时回退同步探测,保证与同步路径判定一致。
175
- */
176
- export async function probeActionAsync(projectRoot, config, actionId) {
177
- const manifest = loadManifest(projectRoot);
178
- if (manifest?.actions && actionId in manifest.actions) {
179
- return true;
180
- }
181
- try {
182
- const actions = await loadActions(projectRoot, config.actionsDir);
183
- return actions.has(actionId) ? true : undefined;
184
- }
185
- catch {
186
- return probeActionSync(projectRoot, config, actionId);
187
- }
188
- }
189
- /**
190
- * Playbook 探针:以 actiondock.json 的 playbooks 声明为唯一事实源,命中返回规程定义。
191
- */
192
- export function probePlaybook(projectRoot, config, playbookId) {
193
- const playbooks = loadPlaybooks(projectRoot, config.playbooksDir);
194
- return playbooks.get(playbookId);
195
- }
@@ -1,48 +0,0 @@
1
- import type { ExecutionHandle } from "./runner.js";
2
- /**
3
- * 内存中活跃执行句柄(In-flight Execution Handles)生命周期管理器。
4
- *
5
- * 职责:
6
- * 1. 集中追踪正在执行的异步 Action 任务句柄。
7
- * 2. 任务完成(无论成功或失败)后通过 Promise.finally 自动注销,防止内存泄漏。
8
- * 3. 支持依据 runId 查询、遍历或主动发送取消信号(cancel)。
9
- */
10
- export declare class ExecutionManager {
11
- private active;
12
- /**
13
- * 注册一个活跃的执行句柄。
14
- * 当底层 Promise 完成结算(resolve/reject)时,自动从活跃映射表中移除。
15
- *
16
- * @param handle 执行句柄对象
17
- */
18
- register(handle: ExecutionHandle): void;
19
- /**
20
- * 根据 runId 检索正在执行的任务句柄。
21
- *
22
- * @param runId 运行 ID
23
- * @returns 匹配的 ExecutionHandle 或 undefined
24
- */
25
- get(runId: string): ExecutionHandle | undefined;
26
- /**
27
- * 向指定 runId 的在途执行任务发送取消信号。
28
- *
29
- * @param runId 目标运行 ID
30
- * @param reason 取消原因描述
31
- * @returns 若句柄存在且成功触发中断返回 true;若任务不存在或已完成返回 false
32
- */
33
- cancel(runId: string, reason?: string): boolean;
34
- /**
35
- * 手动从活跃集合中移除执行句柄。
36
- *
37
- * @param runId 运行 ID
38
- */
39
- remove(runId: string): void;
40
- /**
41
- * 获取当前系统中所有正在执行的活跃句柄列表。
42
- */
43
- list(): ExecutionHandle[];
44
- /**
45
- * 清空所有活跃执行句柄。
46
- */
47
- clear(): void;
48
- }