@actiondock/core 2.7.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 (236) 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 +102 -10
  18. package/dist/errors.js +103 -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 -24
  33. package/dist/index.js +19 -23
  34. package/dist/input/advice.d.ts +5 -1
  35. package/dist/input/advice.js +163 -214
  36. package/dist/input/describe.d.ts +1 -1
  37. package/dist/input/flat-errors.d.ts +5 -6
  38. package/dist/input/flat-errors.js +6 -6
  39. package/dist/input/flat-materializer.js +42 -44
  40. package/dist/invocation/index.d.ts +2 -0
  41. package/dist/invocation/index.js +2 -0
  42. package/dist/invocation/policy.d.ts +157 -0
  43. package/dist/invocation/policy.js +231 -0
  44. package/dist/invocation/types.d.ts +172 -0
  45. package/dist/invocation/types.js +97 -0
  46. package/dist/ipc/diagnostic.d.ts +0 -12
  47. package/dist/ipc/diagnostic.js +0 -21
  48. package/dist/ipc/host.d.ts +4 -4
  49. package/dist/ipc/host.js +44 -47
  50. package/dist/ipc/index.d.ts +1 -1
  51. package/dist/ipc/index.js +1 -1
  52. package/dist/ipc/service.d.ts +40 -0
  53. package/dist/ipc/service.js +349 -0
  54. package/dist/ipc/types.d.ts +21 -15
  55. package/dist/node/index.d.ts +1 -0
  56. package/dist/node/index.js +1 -0
  57. package/dist/node/module-loader.d.ts +63 -0
  58. package/dist/node/module-loader.js +112 -0
  59. package/dist/package/index.d.ts +23 -0
  60. package/dist/package/index.js +18 -0
  61. package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
  62. package/dist/{app/app.js → package/runtime.js} +140 -95
  63. package/dist/{app → package}/static-index.js +58 -41
  64. package/dist/package/storage-view.d.ts +13 -0
  65. package/dist/package/storage-view.js +22 -0
  66. package/dist/{app → package}/types.d.ts +76 -57
  67. package/dist/package/types.js +22 -0
  68. package/dist/platform/index.d.ts +1 -1
  69. package/dist/platform/index.js +1 -1
  70. package/dist/platform/node.d.ts +48 -0
  71. package/dist/platform/node.js +96 -0
  72. package/dist/platform/types.d.ts +0 -9
  73. package/dist/process/control-arbiter.d.ts +2 -1
  74. package/dist/process/control-arbiter.js +1 -2
  75. package/dist/process/driver.d.ts +9 -8
  76. package/dist/process/driver.js +11 -22
  77. package/dist/process/index.d.ts +2 -0
  78. package/dist/process/index.js +2 -0
  79. package/dist/process/managed-record.d.ts +2 -2
  80. package/dist/process/process-driver.d.ts +109 -0
  81. package/dist/process/process-driver.js +650 -0
  82. package/dist/process/process-executor.d.ts +47 -0
  83. package/dist/process/process-executor.js +296 -0
  84. package/dist/process/process-manager.js +48 -26
  85. package/dist/process/run-executor.js +12 -12
  86. package/dist/profile/client-actions.js +2 -2
  87. package/dist/profile/client-health.js +2 -2
  88. package/dist/profile/client-query.js +5 -6
  89. package/dist/profile/client-transport.d.ts +19 -17
  90. package/dist/profile/client-transport.js +47 -80
  91. package/dist/profile/client.d.ts +2 -2
  92. package/dist/profile/client.js +1 -1
  93. package/dist/profile/index.d.ts +1 -0
  94. package/dist/profile/index.js +1 -0
  95. package/dist/profile/manager.d.ts +5 -0
  96. package/dist/profile/manager.js +41 -6
  97. package/dist/project/closure.js +2 -2
  98. package/dist/project/index.d.ts +8 -1
  99. package/dist/project/index.js +10 -1
  100. package/dist/project/init.js +2 -2
  101. package/dist/project/loader.d.ts +1 -1
  102. package/dist/project/loader.js +26 -29
  103. package/dist/project/transactions.js +5 -10
  104. package/dist/registry/index.d.ts +3 -1
  105. package/dist/registry/index.js +2 -1
  106. package/dist/registry/lock.d.ts +28 -7
  107. package/dist/registry/lock.js +136 -16
  108. package/dist/registry/registry.d.ts +1 -5
  109. package/dist/registry/registry.js +1 -53
  110. package/dist/registry/scan.d.ts +0 -15
  111. package/dist/registry/scan.js +0 -59
  112. package/dist/registry/store.d.ts +42 -0
  113. package/dist/registry/store.js +43 -0
  114. package/dist/registry/types.d.ts +0 -24
  115. package/dist/runtime/action-collection.d.ts +1 -1
  116. package/dist/runtime/action-registry.d.ts +0 -4
  117. package/dist/runtime/action-registry.js +0 -7
  118. package/dist/runtime/context.js +5 -11
  119. package/dist/runtime/events.js +3 -6
  120. package/dist/runtime/identity.d.ts +22 -0
  121. package/dist/runtime/identity.js +10 -0
  122. package/dist/runtime/index.d.ts +1 -2
  123. package/dist/runtime/index.js +1 -2
  124. package/dist/runtime/module-loader.d.ts +2 -34
  125. package/dist/runtime/module-loader.js +1 -16
  126. package/dist/runtime/process.d.ts +6 -24
  127. package/dist/runtime/process.js +1 -118
  128. package/dist/runtime/run-persistence.js +2 -5
  129. package/dist/runtime/runner.d.ts +33 -93
  130. package/dist/runtime/runner.js +132 -364
  131. package/dist/runtime/standalone.d.ts +23 -8
  132. package/dist/runtime/standalone.js +100 -147
  133. package/dist/server/body.d.ts +16 -8
  134. package/dist/server/body.js +33 -16
  135. package/dist/server/dispatcher.d.ts +6 -10
  136. package/dist/server/dispatcher.js +24 -32
  137. package/dist/server/http-server.d.ts +87 -0
  138. package/dist/server/http-server.js +304 -0
  139. package/dist/server/index.d.ts +11 -0
  140. package/dist/server/index.js +10 -0
  141. package/dist/server/mcp-endpoint.d.ts +61 -0
  142. package/dist/server/mcp-endpoint.js +118 -0
  143. package/dist/server/routes/actions.js +34 -28
  144. package/dist/server/routes/common.d.ts +10 -14
  145. package/dist/server/routes/common.js +32 -56
  146. package/dist/server/routes/config.js +54 -64
  147. package/dist/server/routes/doctor.d.ts +1 -1
  148. package/dist/server/routes/doctor.js +10 -18
  149. package/dist/server/routes/health.d.ts +1 -1
  150. package/dist/server/routes/health.js +2 -3
  151. package/dist/server/routes/info.d.ts +2 -2
  152. package/dist/server/routes/info.js +12 -13
  153. package/dist/server/routes/playbooks.js +16 -29
  154. package/dist/server/routes/runs.js +95 -117
  155. package/dist/server/routes/state.js +63 -62
  156. package/dist/server/server.d.ts +2 -2
  157. package/dist/server/server.js +43 -227
  158. package/dist/server/types.d.ts +8 -19
  159. package/dist/service/factory.d.ts +12 -0
  160. package/dist/service/factory.js +85 -0
  161. package/dist/{target → service}/index.d.ts +1 -1
  162. package/dist/{target → service}/index.js +1 -1
  163. package/dist/service/local.d.ts +27 -0
  164. package/dist/service/local.js +138 -0
  165. package/dist/{target → service}/remote-errors.d.ts +3 -6
  166. package/dist/service/remote-errors.js +38 -0
  167. package/dist/{target → service}/remote-polling.d.ts +2 -2
  168. package/dist/{target → service}/remote-polling.js +8 -8
  169. package/dist/service/remote.d.ts +34 -0
  170. package/dist/service/remote.js +634 -0
  171. package/dist/service/sse-stream.d.ts +24 -0
  172. package/dist/service/sse-stream.js +139 -0
  173. package/dist/service/types.d.ts +272 -0
  174. package/dist/service/types.js +32 -0
  175. package/dist/storage/data-dir-lock.js +10 -5
  176. package/dist/storage/driver.d.ts +2 -1
  177. package/dist/storage/driver.js +3 -52
  178. package/dist/storage/index.d.ts +1 -0
  179. package/dist/storage/index.js +1 -0
  180. package/dist/storage/lock-core.d.ts +2 -6
  181. package/dist/storage/lock-core.js +4 -17
  182. package/dist/storage/params.d.ts +2 -8
  183. package/dist/storage/params.js +2 -8
  184. package/dist/storage/sqlite-driver.d.ts +40 -0
  185. package/dist/storage/sqlite-driver.js +116 -0
  186. package/dist/storage/sqlite.js +21 -6
  187. package/dist/storage/types.d.ts +4 -4
  188. package/dist/storage/types.js +2 -2
  189. package/dist/utils/index.d.ts +53 -0
  190. package/dist/utils/index.js +99 -4
  191. package/dist/utils/process.d.ts +10 -0
  192. package/dist/utils/process.js +21 -0
  193. package/dist/version.d.ts +1 -1
  194. package/dist/version.js +1 -1
  195. package/package.json +41 -3
  196. package/dist/app/index.d.ts +0 -2
  197. package/dist/app/index.js +0 -2
  198. package/dist/app/types.js +0 -1
  199. package/dist/catalog/action-index.d.ts +0 -9
  200. package/dist/catalog/action-index.js +0 -95
  201. package/dist/catalog/action-resolver.d.ts +0 -20
  202. package/dist/catalog/action-resolver.js +0 -95
  203. package/dist/catalog/location-registry.d.ts +0 -15
  204. package/dist/catalog/location-registry.js +0 -138
  205. package/dist/catalog/package-catalog.d.ts +0 -7
  206. package/dist/catalog/package-catalog.js +0 -77
  207. package/dist/catalog/types.d.ts +0 -68
  208. package/dist/catalog/types.js +0 -1
  209. package/dist/export/index.d.ts +0 -1
  210. package/dist/export/index.js +0 -1
  211. package/dist/export/templates.d.ts +0 -71
  212. package/dist/export/templates.js +0 -635
  213. package/dist/ipc/target.d.ts +0 -74
  214. package/dist/ipc/target.js +0 -365
  215. package/dist/platform/default.d.ts +0 -38
  216. package/dist/platform/default.js +0 -78
  217. package/dist/project/resolver.d.ts +0 -116
  218. package/dist/project/resolver.js +0 -376
  219. package/dist/registry/resolve.d.ts +0 -62
  220. package/dist/registry/resolve.js +0 -195
  221. package/dist/runtime/execution-manager.d.ts +0 -48
  222. package/dist/runtime/execution-manager.js +0 -66
  223. package/dist/runtime/package-runner-factory.d.ts +0 -82
  224. package/dist/runtime/package-runner-factory.js +0 -186
  225. package/dist/target/local.d.ts +0 -53
  226. package/dist/target/local.js +0 -349
  227. package/dist/target/remote-errors.js +0 -51
  228. package/dist/target/remote.d.ts +0 -86
  229. package/dist/target/remote.js +0 -818
  230. package/dist/target/target.d.ts +0 -6
  231. package/dist/target/target.js +0 -37
  232. package/dist/target/types.d.ts +0 -261
  233. package/dist/target/types.js +0 -35
  234. /package/dist/{app → package}/static-index.d.ts +0 -0
  235. /package/dist/{target → service}/sse-parser.d.ts +0 -0
  236. /package/dist/{target → service}/sse-parser.js +0 -0
@@ -1,33 +1,47 @@
1
- import { existsSync } from "node:fs";
2
- import { randomUUID } from "node:crypto";
3
- import { ActionResolver } from "../catalog/action-resolver.js";
4
- import { loadActions, loadProjectConfig } from "../project/loader.js";
5
- import { resolveActionProject } from "../registry/registry.js";
6
- import { ACTION_CALL_CYCLE, ACTION_CYCLE_DETECTED, ACTION_FAILED, ACTION_MAX_DEPTH_EXCEEDED, ACTION_NOT_FOUND, ACTION_SUBRUN_LIMIT, ACTION_TIMEOUT, describeActionLoadFailure, INPUT_NOT_JSON, MAX_SUBRUNS_REACHED, OUTPUT_NOT_JSON, ACTION_CANCELLED, PACKAGE_NOT_FOUND, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, UNDECLARED_ACTION_DEPENDENCY, } from "../errors.js";
1
+ import { parseActionRef } from "../catalog/resolve-action.js";
2
+ import { ACTION_FAILED, ACTION_NOT_FOUND, ACTION_TIMEOUT, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_CANCELLED, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INVOCATION_UNSUPPORTED, ActionDockError, } from "../errors.js";
7
3
  import { validateSchemaOnly } from "../schema/validator.js";
4
+ import { validateActionInputValue } from "../json/value-validator.js";
8
5
  import { createActionContext, StderrLogger } from "./context.js";
9
- import { ActionRegistry, findLocalAction, isActionDefinitionObject, parseActionRef, resolveAnonymousActionId, } from "./action-registry.js";
6
+ import { createDefaultProcessOwner } from "../invocation/types.js";
7
+ import { ActionRegistry, findLocalAction, isActionDefinitionObject, resolveAnonymousActionId, } from "./action-registry.js";
10
8
  import { buildInitialRunRecord, createRunFinalizer, createRunOrThrow, tryCreateRun, } from "./run-persistence.js";
11
- import { PackageRunnerFactory } from "./package-runner-factory.js";
12
- // 错误码常量已收敛至 src/errors.ts 单一事实源,此处保留 re-export 以维持既有导入路径兼容。
13
- export { RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, MAX_SUBRUNS_REACHED, ACTION_CALL_CYCLE, ACTION_CYCLE_DETECTED, ACTION_MAX_DEPTH_EXCEEDED, } from "../errors.js";
14
- import { validateJsonValue, validateActionInputValue, assertJsonValue, } from "../json/value-validator.js";
15
- // 复用统一迭代式 JsonValue 校验器,杜绝深层递归栈溢出,并保持既有导出兼容
16
- export { validateJsonValue, validateActionInputValue, assertJsonValue, };
9
+ import { validateJsonValue } from "../json/value-validator.js";
10
+ /**
11
+ * 将输入值校验结果映射为标准运行时错误(单一事实源)。
12
+ *
13
+ * json-value 分支映射 INPUT_NOT_JSON(非 JSON 类型值),input-policy 分支映射
14
+ * INPUT_VALIDATION_FAILED(策略违规)并携带 details 数组;start 同步路径与
15
+ * raceExecutionAndAbort 延迟解析路径共用,确保错误码与 details 结构一致。
16
+ */
17
+ function buildInputValidationError(targetActionId, check) {
18
+ if (check.kind === "json-value") {
19
+ return {
20
+ code: INPUT_NOT_JSON,
21
+ message: `Input validation failed for action '${targetActionId}': ${check.reason}`,
22
+ };
23
+ }
24
+ return {
25
+ code: INPUT_VALIDATION_FAILED,
26
+ message: `Input validation failed for action '${targetActionId}': ${check.reason}`,
27
+ details: [check.reason],
28
+ };
29
+ }
17
30
  /**
18
31
  * ActionDock 核心执行引擎(ActionRunner)。
19
32
  *
20
33
  * 本类为执行编排壳:负责 Action 执行的全生命周期编排(校验、深度与环路检测、
21
34
  * 超时与取消竞态、子调用 uses 授权与错误分类),并将单一职责域委托至独立模块:
22
- * - Action 注册与检索委托 `ActionRegistry`(action-registry.ts)
35
+ * - Action 注册与检索委托 ActionRegistry(action-registry.ts)
23
36
  * - RunRecord 构造与落库委托 run-persistence.ts
24
- * - 跨包 Runner 构建与缓存委托 `PackageRunnerFactory`(package-runner-factory.ts)
37
+ * - 跨包动作调用委托注入的 ActionInvoker 并重返目标包执行服务
25
38
  *
26
39
  * 入参 (inputSchema) 与出参 (outputSchema) 的 JSON Schema 严格校验、嵌套 Action
27
40
  * 相互调用的环路检测(Cycle Detection)、超时 (Timeout) 与中断信号 (AbortSignal)
28
41
  * 竞态控制与运行记录持久化编排仍由本类承担。
29
42
  */
30
43
  export class ActionRunner {
44
+ identity;
31
45
  packageId;
32
46
  packageInstanceId;
33
47
  generationId;
@@ -39,76 +53,41 @@ export class ActionRunner {
39
53
  registry;
40
54
  clock;
41
55
  process;
42
- platform;
43
- maxCallDepth;
44
- maxSubRuns;
45
- activeSubRuns = 0;
46
- packageFactory;
47
- actionResolver;
48
- getStorageForPackage;
49
56
  customHome;
57
+ actionResolver;
50
58
  hostSessionId;
59
+ actionInvoker;
51
60
  constructor(options) {
52
- this.packageId = options.packageId;
53
- this.packageInstanceId = options.packageInstanceId || options.packageId;
54
- this.generationId = options.generationId || "1";
61
+ if (!options.identity) {
62
+ throw new Error("ActionRunner requires 'identity' PackageIdentity option");
63
+ }
64
+ this.identity = options.identity;
65
+ this.packageId = this.identity.id;
66
+ this.packageInstanceId = this.identity.instanceId;
67
+ this.generationId = this.identity.generation;
55
68
  this.hostSessionId = options.hostSessionId;
56
69
  this.projectRoot = options.projectRoot;
57
70
  this.projectConfig = options.projectConfig;
58
71
  this.configOverrides = options.configOverrides || {};
59
72
  this.registry = new ActionRegistry(options.actions);
60
73
  this.customHome = options.customHome;
61
- this.platform = options.platform;
62
- if (options.platform) {
63
- this.clock = options.platform.clock;
64
- this.process = options.platform.process;
65
- this.storage = options.storage ?? options.platform.storage.createStorage(this.packageId, {
66
- projectRoot: this.projectRoot,
67
- customHome: this.customHome,
68
- // Runner 作为执行宿主组件属于持有者路径,打开时收割遗留孤儿运行
69
- recoverOrphans: true,
70
- });
71
- this.globalStorage = options.globalStorage ?? options.platform.storage.createGlobalStorage({
72
- customHome: this.customHome,
73
- });
74
- }
75
- else {
76
- if (!options.storage) {
77
- throw new Error("ActionRunner requires either 'storage' or 'platform' option");
78
- }
79
- this.storage = options.storage;
80
- this.globalStorage = options.globalStorage;
81
- this.process = options.process;
82
- this.clock = options.clock;
83
- }
84
- this.maxCallDepth = options.maxCallDepth ?? 16;
85
- this.maxSubRuns = options.maxSubRuns ?? 64;
74
+ this.actionInvoker = options.actionInvoker;
86
75
  this.actionResolver = options.actionResolver;
87
- this.getStorageForPackage = options.getStorageForPackage;
88
- this.packageFactory = new PackageRunnerFactory({
89
- globalStorage: this.globalStorage,
90
- projectRoot: this.projectRoot,
91
- process: this.process,
92
- clock: this.clock,
93
- platform: this.platform,
94
- maxCallDepth: this.maxCallDepth,
95
- maxSubRuns: this.maxSubRuns,
96
- actionResolver: this.actionResolver,
97
- getStorageForPackage: this.getStorageForPackage,
98
- packageContextResolver: options.packageContextResolver,
99
- customHome: this.customHome,
100
- }, (opts) => new ActionRunner(opts));
76
+ if (!options.storage) {
77
+ throw new Error("ActionRunner requires 'storage' option");
78
+ }
79
+ this.storage = options.storage;
80
+ this.globalStorage = options.globalStorage;
81
+ this.clock = options.clock;
82
+ this.process = options.process;
101
83
  }
102
- /** 本地 Action 注册表底层映射(仅内部与跨包工厂委托使用) */
84
+ /** 本地 Action 注册表底层映射 */
103
85
  get actions() {
104
86
  return this.registry.map;
105
87
  }
106
88
  getStorage() {
107
89
  return this.storage;
108
90
  }
109
- getPackageRunners() {
110
- return this.packageFactory.runners;
111
- }
112
91
  registerAction(idOrAction, actionDef) {
113
92
  this.registry.registerAction(idOrAction, actionDef);
114
93
  }
@@ -118,11 +97,17 @@ export class ActionRunner {
118
97
  getAction(id) {
119
98
  return this.registry.getAction(id);
120
99
  }
100
+ /**
101
+ * 设置子任务动作调用委托器。
102
+ */
103
+ setActionInvoker(invoker) {
104
+ this.actionInvoker = invoker;
105
+ }
121
106
  /**
122
107
  * 动态解析 Action(支持本地注册表、自定义解析器委托与已链接包目录索引检索)。
123
108
  *
124
109
  * @param actionOrRef Action 定义对象、引用或标识符
125
- * @returns 解析判别联合结果(found | not_found | load_failed)
110
+ * @returns 解析判别联合结果(found | not_found)
126
111
  */
127
112
  async resolveAction(actionOrRef) {
128
113
  if (isActionDefinitionObject(actionOrRef)) {
@@ -138,24 +123,26 @@ export class ActionRunner {
138
123
  }
139
124
  const targetActionId = parsed.actionId;
140
125
  const targetPackageId = parsed.packageId;
126
+ // 铁律:ActionRunner 仅限执行当前包局部 Action,任何跨包请求直接拒绝,禁止跨包解析和执行
127
+ if (targetPackageId && targetPackageId !== this.packageId) {
128
+ return {
129
+ status: "not_found",
130
+ reason: `Cross-package action '${targetPackageId}/${targetActionId}' cannot be resolved by ActionRunner of package '${this.packageId}'`,
131
+ };
132
+ }
141
133
  // 本地 actions 映射表优先检索
142
134
  const localMatched = findLocalAction(this.actions, parsed, this.packageId);
143
135
  if (localMatched) {
144
136
  return { status: "found", action: localMatched };
145
137
  }
146
- // 外部注入的自定义 actionResolver 调度
138
+ // 外部注入的局部 actionResolver 调度
147
139
  if (this.actionResolver) {
148
140
  try {
149
- const customResolved = await this.actionResolver(ref, this.packageId);
141
+ const customResolved = await this.actionResolver(targetActionId);
150
142
  if (customResolved) {
151
- if (targetPackageId && targetPackageId !== this.packageId) {
152
- this.actions.set(`${targetPackageId}/${targetActionId}`, customResolved);
153
- }
154
- else {
155
- this.actions.set(targetActionId, customResolved);
156
- if (this.packageId) {
157
- this.actions.set(`${this.packageId}/${targetActionId}`, customResolved);
158
- }
143
+ this.actions.set(targetActionId, customResolved);
144
+ if (this.packageId) {
145
+ this.actions.set(`${this.packageId}/${targetActionId}`, customResolved);
159
146
  }
160
147
  return { status: "found", action: customResolved };
161
148
  }
@@ -164,61 +151,10 @@ export class ActionRunner {
164
151
  return { status: "not_found", reason: err.message };
165
152
  }
166
153
  }
167
- // 基于全局链接注册表与目录索引的动态寻址与按需加载
168
- const identifier = targetPackageId
169
- ? `${targetPackageId}/${targetActionId}`
170
- : targetActionId;
171
- let resolved;
172
- try {
173
- resolved = await resolveActionProject(identifier, this.projectRoot, this.customHome);
174
- }
175
- catch (err) {
176
- return { status: "not_found", reason: err.message };
177
- }
178
- if (!resolved || !existsSync(resolved.projectRoot)) {
179
- return {
180
- status: "not_found",
181
- reason: `Project root not found for action '${identifier}'`,
182
- };
183
- }
184
- let config;
185
- try {
186
- config = loadProjectConfig(resolved.projectRoot);
187
- }
188
- catch (err) {
189
- return {
190
- status: "load_failed",
191
- error: err instanceof Error ? err : new Error(String(err)),
192
- packageId: resolved.packageId,
193
- projectRoot: resolved.projectRoot,
194
- };
195
- }
196
- let actionsMap;
197
- try {
198
- actionsMap = await loadActions(resolved.projectRoot, config.actionsDir, {
199
- loader: this.platform?.modules,
200
- });
201
- }
202
- catch (err) {
203
- return {
204
- status: "load_failed",
205
- error: err instanceof Error ? err : new Error(String(err)),
206
- packageId: resolved.packageId,
207
- projectRoot: resolved.projectRoot,
208
- };
209
- }
210
- const matched = actionsMap.get(resolved.actionId);
211
- if (matched) {
212
- this.actions.set(`${resolved.packageId}/${resolved.actionId}`, matched);
213
- // 仅当目标包就是当前项目时才注册短标识符,避免跨包动态载入污染全局短标识符
214
- if (!targetPackageId || resolved.packageId === this.packageId) {
215
- this.actions.set(resolved.actionId, matched);
216
- }
217
- return { status: "found", action: matched };
218
- }
154
+ // 铁律 4:Runner 不找 Package:只能执行自己所属 Package 的 Action
219
155
  return {
220
156
  status: "not_found",
221
- reason: `Action '${resolved.actionId}' not found in package '${resolved.packageId}' (${resolved.projectRoot})`,
157
+ reason: `Action '${targetActionId}' not found in package '${this.packageId}'`,
222
158
  };
223
159
  }
224
160
  /**
@@ -227,22 +163,6 @@ export class ActionRunner {
227
163
  listActions() {
228
164
  return this.registry.listActions();
229
165
  }
230
- /**
231
- * 注入或更新跨包运行上下文解析委托。
232
- */
233
- setPackageContextResolver(resolver) {
234
- this.packageFactory.setPackageContextResolver(resolver);
235
- }
236
- /**
237
- * 跨包运行时解析与获取(确保跨包执行具备独立的配置、存储、状态与 Action 注册表)。
238
- *
239
- * 缓存 miss 后存在长异步窗口(加载配置、扫描 Action、打开存储),并发调用会重复构建
240
- * Runner、重复打开 SQLite 连接且子任务限流计数分裂;故以 in-flight Promise 去重,
241
- * 并发方 await 同一构建任务,构建失败时移除该 Promise 以便后续重试。
242
- */
243
- async resolveTargetPackageRunner(targetPackageId) {
244
- return this.packageFactory.resolveTargetPackageRunner(targetPackageId);
245
- }
246
166
  /**
247
167
  * 异步启动 Action 的执行并立即返回 ExecutionHandle 句柄。
248
168
  *
@@ -257,16 +177,7 @@ export class ActionRunner {
257
177
  // 输入参数 JSON 格式与合法性防御校验(拦截 NaN/Infinity/循环引用等非 JSON 类型及非法原型键策略违规)
258
178
  const inputCheck = validateActionInputValue(input);
259
179
  if (!inputCheck.valid) {
260
- const error = inputCheck.kind === "json-value"
261
- ? {
262
- code: INPUT_NOT_JSON,
263
- message: `Input validation failed for action '${targetActionId}': ${inputCheck.reason}`,
264
- }
265
- : {
266
- code: INPUT_VALIDATION_FAILED,
267
- message: `Input validation failed for action '${targetActionId}': ${inputCheck.reason}`,
268
- details: [inputCheck.reason],
269
- };
180
+ const error = buildInputValidationError(targetActionId, inputCheck);
270
181
  // 安全记录 failed 状态(不可序列化或策略违规的非法 input 严禁直接写入持久化存储)
271
182
  tryCreateRun(this.storage, buildInitialRunRecord(this.buildRunPersistenceInput(runCtx), "failed", error));
272
183
  return {
@@ -278,27 +189,15 @@ export class ActionRunner {
278
189
  // 始终优先将执行尝试持久化到存储中(确保任意异常与终态都可追溯)
279
190
  createRunOrThrow(this.storage, buildInitialRunRecord(this.buildRunPersistenceInput(runCtx), "running"));
280
191
  const finalizer = createRunFinalizer(this.storage, runCtx.runId);
281
- // 调用嵌套深度限制检测 (Max Call Depth Check)
282
- const depthError = this.checkCallDepth(runCtx.callStack, targetActionId, runCtx.options);
283
- if (depthError) {
284
- finalizer.finalize("failed", undefined, depthError);
285
- return {
286
- runId,
287
- result: Promise.resolve({ ok: false, runId, error: depthError }),
288
- cancel: () => false,
289
- };
192
+ // 记录调用栈快照(供子任务追溯,若已处于调用栈顶则不重复追加)
193
+ const callKey = targetPackageId ? `${targetPackageId}/${targetActionId}` : targetActionId;
194
+ const lastStackItem = runCtx.callStack[runCtx.callStack.length - 1];
195
+ const isAlreadyAtTop = lastStackItem === callKey ||
196
+ (targetActionId && lastStackItem === targetActionId) ||
197
+ (targetPackageId && lastStackItem === `${targetPackageId}/${targetActionId}`);
198
+ if (!isAlreadyAtTop) {
199
+ runCtx.callStack.push(callKey);
290
200
  }
291
- // 环路死锁检测 (Cycle Detection)
292
- const cycle = this.computeCallKey(runCtx.callStack, targetActionId, targetPackageId);
293
- if (cycle.error) {
294
- finalizer.finalize("failed", undefined, cycle.error);
295
- return {
296
- runId,
297
- result: Promise.resolve({ ok: false, runId, error: cycle.error }),
298
- cancel: () => false,
299
- };
300
- }
301
- runCtx.callStack.push(cycle.callKey);
302
201
  // 输入参数 JSON Schema 校验(若 action 已就绪)
303
202
  const schemaError = this.checkActionInputSchema(runCtx.action, targetActionId, input);
304
203
  if (schemaError) {
@@ -368,9 +267,9 @@ export class ActionRunner {
368
267
  * 预解析执行目标并装配运行期共享上下文对象(runId、目标标识、时钟源与调用栈快照)。
369
268
  */
370
269
  prepareRunContext(actionOrId, input, options) {
371
- const runId = options.runId || randomUUID();
372
- const effectiveClock = options.platform?.clock ?? this.clock;
373
- const effectiveProcess = options.process || options.platform?.process || this.process;
270
+ const runId = options.runId || crypto.randomUUID();
271
+ const effectiveClock = options.clock ?? this.clock;
272
+ const effectiveProcess = options.process || this.process;
374
273
  const startedAt = effectiveClock?.now().toISOString() ||
375
274
  (typeof this.storage.clock?.now === "function"
376
275
  ? this.storage.clock.now().toISOString()
@@ -434,44 +333,6 @@ export class ActionRunner {
434
333
  runnerHostSessionId: this.hostSessionId,
435
334
  };
436
335
  }
437
- /**
438
- * 调用嵌套深度限制检测(超限时返回 ACTION_CALL_CYCLE 错误)。
439
- */
440
- checkCallDepth(callStack, targetActionId, options) {
441
- // 执行级 options.maxCallDepth 可覆盖构造级默认值,保留原覆盖契约
442
- const maxDepth = options.maxCallDepth ?? this.maxCallDepth;
443
- if (callStack.length >= maxDepth) {
444
- return {
445
- code: ACTION_CALL_CYCLE,
446
- message: `Maximum call depth of ${maxDepth} exceeded: ${callStack.join(" -> ")} -> ${targetActionId}`,
447
- details: { alias: ACTION_MAX_DEPTH_EXCEEDED, reason: "depth_exceeded", maxDepth, callStack: [...callStack] },
448
- };
449
- }
450
- return undefined;
451
- }
452
- /**
453
- * 计算调用键并执行环路死锁检测(命中时返回携带错误的调用键结果)。
454
- */
455
- computeCallKey(callStack, targetActionId, targetPackageId) {
456
- const isExternal = Boolean(targetPackageId && targetPackageId !== this.packageId);
457
- const callKey = isExternal
458
- ? `${targetPackageId}/${targetActionId}`
459
- : targetActionId;
460
- const hasCycle = isExternal
461
- ? callStack.includes(callKey)
462
- : (callStack.includes(callKey) || (this.packageId ? callStack.includes(`${this.packageId}/${targetActionId}`) : false));
463
- if (hasCycle) {
464
- return {
465
- callKey,
466
- error: {
467
- code: ACTION_CALL_CYCLE,
468
- message: `Cycle detected in action invocation: ${callStack.join(" -> ")} -> ${callKey}`,
469
- details: { alias: ACTION_CYCLE_DETECTED, reason: "cycle_detected", callStack: [...callStack], target: callKey },
470
- },
471
- };
472
- }
473
- return { callKey };
474
- }
475
336
  /**
476
337
  * 输入参数 JSON Schema 校验(若 action 已就绪,返回校验错误或 undefined)。
477
338
  */
@@ -497,12 +358,13 @@ export class ActionRunner {
497
358
  buildActionContext(args) {
498
359
  const { runCtx, controller, rootRunId } = args;
499
360
  const { options, targetPackageId, targetActionId, effectiveProcess } = runCtx;
500
- const effectiveOwner = options.owner || {
501
- tenantId: options.tenantId || "default",
502
- principalId: options.principalId || options.ownerId || "default",
503
- packageInstanceId: options.packageInstanceId || (this.packageId === targetPackageId ? this.packageInstanceId : targetPackageId),
504
- generationId: options.generationId || (this.packageId === targetPackageId ? this.generationId : "1"),
505
- };
361
+ const effectiveOwner = options.owner ||
362
+ createDefaultProcessOwner({
363
+ tenantId: options.tenantId,
364
+ principalId: options.principalId || options.ownerId,
365
+ packageInstanceId: options.packageInstanceId || this.packageInstanceId,
366
+ generationId: options.generationId || this.generationId,
367
+ });
506
368
  return createActionContext({
507
369
  actionId: targetActionId,
508
370
  storage: this.storage,
@@ -528,121 +390,51 @@ export class ActionRunner {
528
390
  });
529
391
  }
530
392
  /**
531
- * 子 Action 调用委托:并发上限守卫、uses 跨包声明校验与子执行派发。
393
+ * 子 Action 调用委托:
394
+ * 必须委托 Host 动作调用器(走 Host 执行主链与 InvocationPolicy 鉴权);
395
+ * 缺少 actionInvoker 时直接抛出 INVOCATION_UNSUPPORTED,严禁跨包或同包无约束执行逃逸。
532
396
  */
533
397
  async invokeChildAction(args) {
534
398
  const { runCtx, controller, rootRunId, childAction, childInput, parentRunId } = args;
535
- const { options, targetActionId, effectiveProcess, callStack } = runCtx;
536
- if (this.activeSubRuns >= this.maxSubRuns) {
537
- const err = new Error(`Maximum concurrent sub-runs (${this.maxSubRuns}) reached`);
538
- err.code = ACTION_SUBRUN_LIMIT;
539
- err.details = { alias: MAX_SUBRUNS_REACHED, limit: this.maxSubRuns };
540
- throw err;
541
- }
542
- let childPackageId = this.packageId;
543
- const parsed = ActionResolver.parseRef(childAction);
544
- if (parsed.packageId) {
545
- childPackageId = parsed.packageId;
546
- }
547
- const childActionId = parsed.actionId;
548
- const effectiveParentOwner = options.owner || {
549
- tenantId: options.tenantId || "default",
550
- principalId: options.principalId || options.ownerId || "default",
551
- packageInstanceId: options.packageInstanceId || this.packageInstanceId || this.packageId,
552
- generationId: options.generationId || this.generationId || "1",
553
- };
554
- const isSamePackage = !childPackageId || childPackageId === this.packageId;
555
- this.activeSubRuns++;
556
- try {
557
- const runnerToUse = await this.resolveChildRunner(childPackageId, childActionId);
558
- if (runnerToUse !== this) {
559
- this.assertDeclaredUses(runCtx.action, targetActionId, childPackageId, childActionId);
560
- }
561
- const childPackageInstanceId = isSamePackage
562
- ? effectiveParentOwner.packageInstanceId
563
- : (runnerToUse !== this ? runnerToUse.packageInstanceId : childPackageId);
564
- const childGenerationId = isSamePackage
565
- ? effectiveParentOwner.generationId
566
- : (runnerToUse !== this ? runnerToUse.generationId : "1");
567
- const childOwner = {
568
- tenantId: effectiveParentOwner.tenantId,
569
- principalId: effectiveParentOwner.principalId,
570
- packageInstanceId: childPackageInstanceId,
571
- generationId: childGenerationId,
572
- };
573
- const childResult = await runnerToUse.execute(childAction, childInput, {
574
- rootRunId,
575
- parentRunId,
576
- callStack,
577
- signal: controller.signal,
578
- process: effectiveProcess,
579
- platform: options.platform || this.platform,
580
- progress: options.progress,
581
- logger: options.logger,
582
- configOverrides: options.configOverrides,
583
- maxCallDepth: options.maxCallDepth ?? this.maxCallDepth,
584
- tenantId: childOwner.tenantId,
585
- principalId: childOwner.principalId,
586
- ownerId: childOwner.principalId,
587
- packageInstanceId: childOwner.packageInstanceId,
588
- generationId: childOwner.generationId,
589
- owner: childOwner,
590
- hostSessionId: options.hostSessionId ?? this.hostSessionId,
399
+ const { options, effectiveProcess, callStack } = runCtx;
400
+ const invoker = options.actionInvoker || this.actionInvoker;
401
+ if (!invoker) {
402
+ throw new ActionDockError(INVOCATION_UNSUPPORTED, "Nested action invocation requires a Host ActionInvoker");
403
+ }
404
+ const effectiveParentOwner = options.owner ||
405
+ createDefaultProcessOwner({
406
+ tenantId: options.tenantId,
407
+ principalId: options.principalId || options.ownerId,
408
+ packageInstanceId: this.packageInstanceId,
409
+ generationId: this.generationId,
591
410
  });
592
- if (!childResult.ok) {
593
- const err = new Error(childResult.error.message);
594
- err.code = childResult.error.code;
595
- err.details = childResult.error.details;
596
- throw err;
597
- }
598
- return childResult.data;
599
- }
600
- finally {
601
- this.activeSubRuns--;
602
- }
603
- }
604
- /**
605
- * 校验跨包子调用是否已在 uses 声明中授权(未声明时抛出 UNDECLARED_ACTION_DEPENDENCY)。
606
- */
607
- assertDeclaredUses(action, targetActionId, childPackageId, childActionId) {
608
- if (!childPackageId || childPackageId === this.packageId) {
609
- return;
610
- }
611
- const actionConfig = this.projectConfig?.actions?.[targetActionId];
612
- const rawUses = actionConfig?.uses ?? action?.uses;
613
- const declaredUses = Array.isArray(rawUses) ? rawUses : [];
614
- const targetRef = `${childPackageId}/${childActionId}`;
615
- const isAllowed = declaredUses.some((u) => u === targetRef || u === `${childPackageId}/*` || u === childPackageId);
616
- if (!isAllowed) {
617
- const err = new Error(`Undeclared cross-package dependency: Action '${this.packageId}/${targetActionId}' does not declare '${targetRef}' in 'uses'`);
618
- err.code = UNDECLARED_ACTION_DEPENDENCY;
619
- err.details = {
620
- caller: `${this.packageId}/${targetActionId}`,
621
- target: targetRef,
622
- declaredUses: rawUses,
623
- };
624
- throw err;
625
- }
626
- }
627
- /**
628
- * 解析子调用应使用的 Runner(本包或已解析的目标包 Runner)。
629
- */
630
- async resolveChildRunner(childPackageId, childActionId) {
631
- if (childPackageId && childPackageId !== this.packageId) {
632
- const targetRunner = await this.resolveTargetPackageRunner(childPackageId);
633
- if (targetRunner) {
634
- return targetRunner;
635
- }
636
- if (this.actions.has(`${childPackageId}/${childActionId}`)) {
637
- return this;
638
- }
639
- if (!this.actionResolver) {
640
- const err = new Error(`Package '${childPackageId}' could not be resolved`);
641
- err.code = PACKAGE_NOT_FOUND;
642
- throw err;
643
- }
644
- }
645
- return this;
411
+ const childRunId = crypto.randomUUID();
412
+ const invocationContext = {
413
+ runId: childRunId,
414
+ rootRunId,
415
+ parentRunId: parentRunId || runCtx.runId,
416
+ caller: {
417
+ packageId: this.packageId,
418
+ actionId: runCtx.targetActionId,
419
+ runId: runCtx.runId,
420
+ declaredUses: runCtx.action?.uses ||
421
+ this.projectConfig?.actions?.[runCtx.targetActionId]?.uses,
422
+ },
423
+ callStack: [...callStack],
424
+ package: this.identity,
425
+ signal: controller.signal,
426
+ timeoutMs: options.timeoutMs,
427
+ maxCallDepth: options.maxCallDepth,
428
+ config: options.configOverrides,
429
+ tenantId: effectiveParentOwner.tenantId,
430
+ principalId: effectiveParentOwner.principalId,
431
+ hostSessionId: options.hostSessionId || this.hostSessionId,
432
+ logger: options.logger,
433
+ progress: options.progress,
434
+ process: effectiveProcess,
435
+ owner: effectiveParentOwner,
436
+ };
437
+ return await invoker(childAction, childInput, invocationContext);
646
438
  }
647
439
  /**
648
440
  * 执行 Action 业务逻辑并与取消/超时信号进行竞态,返回执行结果信封 Promise。
@@ -672,16 +464,6 @@ export class ActionRunner {
672
464
  currentAction = resolution.action;
673
465
  runCtx.action = currentAction;
674
466
  }
675
- else if (resolution.status === "load_failed") {
676
- const cause = resolution.error;
677
- const error = describeActionLoadFailure(cause, {
678
- actionId: targetActionId,
679
- packageId: resolution.packageId,
680
- projectRoot: resolution.projectRoot,
681
- });
682
- finalizer.finalize("failed", undefined, error);
683
- return { ok: false, runId, error };
684
- }
685
467
  else {
686
468
  const error = {
687
469
  code: ACTION_NOT_FOUND,
@@ -693,16 +475,7 @@ export class ActionRunner {
693
475
  }
694
476
  const inputCheck = validateActionInputValue(input);
695
477
  if (!inputCheck.valid) {
696
- const error = inputCheck.kind === "json-value"
697
- ? {
698
- code: INPUT_NOT_JSON,
699
- message: `Input validation failed for action '${targetActionId}': ${inputCheck.reason}`,
700
- }
701
- : {
702
- code: INPUT_VALIDATION_FAILED,
703
- message: `Input validation failed for action '${targetActionId}': ${inputCheck.reason}`,
704
- details: [inputCheck.reason],
705
- };
478
+ const error = buildInputValidationError(targetActionId, inputCheck);
706
479
  finalizer.finalize("failed", undefined, error);
707
480
  return { ok: false, runId, error };
708
481
  }
@@ -819,15 +592,10 @@ export class ActionRunner {
819
592
  };
820
593
  }
821
594
  /**
822
- * 释放 Runner 持有的跨包资源:遍历关闭全部子包 Runner 及其独立创建的存储连接。
823
- *
824
- * 幂等且并发安全:重复调用直接复用首次 Promise;子包存储异常不阻断其余释放;
825
- * 仅关闭由本 Runner 构建子包 Runner 时独立创建的存储,外部注入的存储(如经
826
- * packageContextResolver 传入的目标包自身存储)生命周期归所有者管理,不在此误关。
595
+ * 释放 Runner 持有的资源。
596
+ * 铁律 4:Runner 仅执行自己所属 Package 的 Action,不管理外部包生命周期。
827
597
  */
828
- async dispose() {
829
- return this.packageFactory.dispose();
830
- }
598
+ async dispose() { }
831
599
  /**
832
600
  * 同步等待方式执行指定 Action,直接返回 ExecutionResult 信封结果。
833
601
  *