@actiondock/core 2.10.0 → 2.12.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 (252) hide show
  1. package/README.md +1 -2
  2. package/dist/catalog/action-catalog.js +3 -33
  3. package/dist/catalog/discovery.d.ts +0 -3
  4. package/dist/catalog/discovery.js +4 -4
  5. package/dist/catalog/graph.d.ts +0 -4
  6. package/dist/catalog/graph.js +8 -14
  7. package/dist/{profile/client-actions.d.ts → client/actions.d.ts} +1 -1
  8. package/dist/{profile/client-actions.js → client/actions.js} +2 -8
  9. package/dist/{profile/client-config.d.ts → client/config.d.ts} +1 -1
  10. package/dist/{profile/client-config.js → client/config.js} +1 -1
  11. package/dist/client/dispatcher.d.ts +4 -0
  12. package/dist/client/dispatcher.js +21 -0
  13. package/dist/client/health.d.ts +38 -0
  14. package/dist/{profile/client-health.js → client/health.js} +9 -6
  15. package/dist/client/index.d.ts +16 -0
  16. package/dist/client/index.js +20 -0
  17. package/dist/{profile/client-playbooks.d.ts → client/playbooks.d.ts} +1 -1
  18. package/dist/{profile/client-playbooks.js → client/playbooks.js} +1 -1
  19. package/dist/{profile/client-runs.d.ts → client/runs.d.ts} +4 -2
  20. package/dist/{profile/client-runs.js → client/runs.js} +7 -1
  21. package/dist/{profile/client-state.d.ts → client/state.d.ts} +1 -1
  22. package/dist/{profile/client-state.js → client/state.js} +1 -1
  23. package/dist/{profile/client-transport.d.ts → client/transport.d.ts} +29 -10
  24. package/dist/{profile/client-transport.js → client/transport.js} +125 -35
  25. package/dist/doctor/checks/index.d.ts +1 -1
  26. package/dist/doctor/checks/index.js +1 -1
  27. package/dist/doctor/checks/project.js +20 -88
  28. package/dist/doctor/checks/runtime.d.ts +0 -4
  29. package/dist/doctor/checks/runtime.js +0 -28
  30. package/dist/doctor/doctor.js +1 -2
  31. package/dist/errors.d.ts +53 -3
  32. package/dist/errors.js +53 -3
  33. package/dist/execution/service.d.ts +55 -37
  34. package/dist/execution/service.js +601 -212
  35. package/dist/execution/types.d.ts +24 -5
  36. package/dist/host/host.d.ts +42 -22
  37. package/dist/host/host.js +562 -149
  38. package/dist/host/routing.js +6 -6
  39. package/dist/host/types.d.ts +25 -13
  40. package/dist/index.d.ts +9 -4
  41. package/dist/index.js +5 -2
  42. package/dist/input/advice.d.ts +0 -44
  43. package/dist/input/advice.js +7 -141
  44. package/dist/input/flat-materializer.js +1 -1
  45. package/dist/input/flat-parser.js +1 -1
  46. package/dist/input/index.d.ts +0 -1
  47. package/dist/input/index.js +0 -1
  48. package/dist/input/input-resolver.js +1 -1
  49. package/dist/input/validation-mapper.d.ts +1 -1
  50. package/dist/ipc/diagnostic.d.ts +8 -21
  51. package/dist/ipc/diagnostic.js +24 -57
  52. package/dist/ipc/host.js +21 -7
  53. package/dist/ipc/service.d.ts +14 -0
  54. package/dist/ipc/service.js +132 -26
  55. package/dist/ipc/types.d.ts +0 -4
  56. package/dist/package/index.d.ts +4 -5
  57. package/dist/package/index.js +1 -2
  58. package/dist/package/runtime.d.ts +94 -23
  59. package/dist/package/runtime.js +628 -274
  60. package/dist/package/static-index.d.ts +3 -6
  61. package/dist/package/static-index.js +11 -40
  62. package/dist/package/types.d.ts +19 -4
  63. package/dist/platform/index.d.ts +2 -1
  64. package/dist/platform/index.js +2 -1
  65. package/dist/platform/loader-hook.d.ts +32 -0
  66. package/dist/platform/loader-hook.js +90 -0
  67. package/dist/{node → platform}/module-loader.d.ts +13 -0
  68. package/dist/{node → platform}/module-loader.js +51 -4
  69. package/dist/platform/node.d.ts +19 -8
  70. package/dist/platform/node.js +50 -20
  71. package/dist/platform/types.d.ts +7 -47
  72. package/dist/process/context-process.d.ts +3 -18
  73. package/dist/process/context-process.js +3 -44
  74. package/dist/process/control.d.ts +21 -0
  75. package/dist/process/control.js +34 -0
  76. package/dist/process/converters.d.ts +23 -0
  77. package/dist/process/converters.js +92 -0
  78. package/dist/process/cursor.js +2 -22
  79. package/dist/process/{diagnostics-sink.d.ts → diagnostics.d.ts} +0 -7
  80. package/dist/process/{diagnostics-sink.js → diagnostics.js} +6 -8
  81. package/dist/process/index.d.ts +1 -3
  82. package/dist/process/index.js +1 -3
  83. package/dist/process/input-dispatcher.d.ts +4 -13
  84. package/dist/process/input-dispatcher.js +48 -69
  85. package/dist/process/managed-record.d.ts +3 -31
  86. package/dist/process/metadata-store.d.ts +0 -41
  87. package/dist/process/metadata-store.js +2 -341
  88. package/dist/process/process-driver.js +2 -2
  89. package/dist/process/process-manager.d.ts +8 -50
  90. package/dist/process/process-manager.js +28 -417
  91. package/dist/process/quotas.d.ts +14 -0
  92. package/dist/process/quotas.js +29 -0
  93. package/dist/process/run-executor.js +0 -1
  94. package/dist/process/terminal-output-cache.d.ts +20 -34
  95. package/dist/process/terminal-output-cache.js +43 -64
  96. package/dist/profile/index.d.ts +1 -2
  97. package/dist/profile/index.js +1 -2
  98. package/dist/profile/manager.d.ts +2 -4
  99. package/dist/profile/manager.js +10 -40
  100. package/dist/profile/types.d.ts +1 -17
  101. package/dist/project/digest.d.ts +5 -1
  102. package/dist/project/digest.js +81 -219
  103. package/dist/project/index.d.ts +4 -5
  104. package/dist/project/index.js +4 -5
  105. package/dist/project/init.js +2 -2
  106. package/dist/project/loader.d.ts +3 -3
  107. package/dist/project/loader.js +72 -50
  108. package/dist/project/lockfile.js +6 -5
  109. package/dist/project/manifest.js +5 -4
  110. package/dist/project/transactions.d.ts +4 -42
  111. package/dist/project/transactions.js +83 -138
  112. package/dist/project/types-generator.js +2 -1
  113. package/dist/project/types.d.ts +2 -0
  114. package/dist/registry/index.d.ts +0 -1
  115. package/dist/registry/index.js +0 -1
  116. package/dist/registry/lock.d.ts +2 -11
  117. package/dist/registry/lock.js +14 -183
  118. package/dist/registry/registry.d.ts +1 -6
  119. package/dist/registry/registry.js +5 -17
  120. package/dist/runtime/action-registry.d.ts +1 -5
  121. package/dist/runtime/action-registry.js +0 -12
  122. package/dist/runtime/context.js +2 -2
  123. package/dist/runtime/events.d.ts +11 -50
  124. package/dist/runtime/events.js +88 -368
  125. package/dist/runtime/index.d.ts +0 -4
  126. package/dist/runtime/index.js +0 -4
  127. package/dist/runtime/run-persistence.d.ts +2 -0
  128. package/dist/runtime/run-persistence.js +2 -1
  129. package/dist/runtime/standalone-commands.d.ts +18 -0
  130. package/dist/runtime/standalone-commands.js +466 -0
  131. package/dist/runtime/standalone-help.d.ts +20 -0
  132. package/dist/runtime/standalone-help.js +72 -0
  133. package/dist/runtime/standalone.d.ts +1 -44
  134. package/dist/runtime/standalone.js +32 -573
  135. package/dist/schema/validator.d.ts +2 -2
  136. package/dist/schema/validator.js +2 -9
  137. package/dist/server/index.d.ts +0 -2
  138. package/dist/server/index.js +0 -2
  139. package/dist/server/routes/actions.js +1 -1
  140. package/dist/server/routes/info.js +1 -1
  141. package/dist/server/routes/playbooks.js +1 -1
  142. package/dist/server/routes/runs.js +123 -16
  143. package/dist/server/routes/state.js +43 -18
  144. package/dist/server/security.d.ts +1 -1
  145. package/dist/server/security.js +2 -2
  146. package/dist/server/server.js +3 -7
  147. package/dist/service/factory.js +4 -3
  148. package/dist/service/index.d.ts +1 -1
  149. package/dist/service/index.js +1 -1
  150. package/dist/service/remote-errors.d.ts +1 -1
  151. package/dist/service/remote-errors.js +6 -6
  152. package/dist/service/remote-polling.d.ts +3 -0
  153. package/dist/service/remote-polling.js +10 -5
  154. package/dist/service/remote.d.ts +5 -1
  155. package/dist/service/remote.js +108 -17
  156. package/dist/service/sse-stream.js +2 -2
  157. package/dist/service/types.d.ts +22 -19
  158. package/dist/service/types.js +1 -24
  159. package/dist/storage/clock.d.ts +1 -1
  160. package/dist/storage/clock.js +1 -1
  161. package/dist/storage/data-dir-lock.d.ts +10 -22
  162. package/dist/storage/data-dir-lock.js +28 -56
  163. package/dist/storage/file-lock.d.ts +64 -0
  164. package/dist/storage/file-lock.js +447 -0
  165. package/dist/storage/index.d.ts +2 -2
  166. package/dist/storage/index.js +5 -4
  167. package/dist/storage/run-liveness.d.ts +48 -0
  168. package/dist/storage/run-liveness.js +44 -0
  169. package/dist/storage/sqlite-config.d.ts +16 -0
  170. package/dist/storage/sqlite-config.js +59 -0
  171. package/dist/storage/sqlite-driver.d.ts +3 -1
  172. package/dist/storage/sqlite-driver.js +14 -4
  173. package/dist/storage/sqlite-events.d.ts +13 -0
  174. package/dist/storage/sqlite-events.js +48 -0
  175. package/dist/storage/sqlite-runs.d.ts +107 -0
  176. package/dist/storage/sqlite-runs.js +622 -0
  177. package/dist/storage/sqlite-schema.d.ts +5 -0
  178. package/dist/storage/sqlite-schema.js +143 -0
  179. package/dist/storage/sqlite-state.d.ts +33 -0
  180. package/dist/storage/sqlite-state.js +270 -0
  181. package/dist/storage/sqlite.d.ts +30 -57
  182. package/dist/storage/sqlite.js +84 -741
  183. package/dist/storage/types.d.ts +35 -2
  184. package/dist/utils/index.d.ts +18 -14
  185. package/dist/utils/index.js +37 -29
  186. package/dist/utils/semver.d.ts +18 -0
  187. package/dist/utils/semver.js +19 -0
  188. package/dist/utils/warning.d.ts +1 -0
  189. package/dist/utils/warning.js +52 -0
  190. package/dist/{json/value-validator.d.ts → value-validator.d.ts} +9 -0
  191. package/dist/value-validator.js +330 -0
  192. package/dist/version.d.ts +1 -1
  193. package/dist/version.js +1 -1
  194. package/package.json +10 -12
  195. package/dist/execution/index.d.ts +0 -2
  196. package/dist/execution/index.js +0 -2
  197. package/dist/filter/index.d.ts +0 -1
  198. package/dist/filter/index.js +0 -1
  199. package/dist/graph/index.d.ts +0 -4
  200. package/dist/graph/index.js +0 -4
  201. package/dist/input/metadata.d.ts +0 -99
  202. package/dist/input/metadata.js +0 -99
  203. package/dist/invocation/index.d.ts +0 -2
  204. package/dist/invocation/index.js +0 -2
  205. package/dist/ipc/index.d.ts +0 -4
  206. package/dist/ipc/index.js +0 -4
  207. package/dist/json/index.d.ts +0 -1
  208. package/dist/json/index.js +0 -1
  209. package/dist/json/value-validator.js +0 -330
  210. package/dist/node/index.d.ts +0 -1
  211. package/dist/node/index.js +0 -1
  212. package/dist/platform/node-fs.d.ts +0 -37
  213. package/dist/platform/node-fs.js +0 -81
  214. package/dist/process/control-arbiter.d.ts +0 -108
  215. package/dist/process/control-arbiter.js +0 -250
  216. package/dist/process/process-executor.d.ts +0 -47
  217. package/dist/process/process-executor.js +0 -296
  218. package/dist/profile/client-health.d.ts +0 -14
  219. package/dist/profile/client-query.d.ts +0 -30
  220. package/dist/profile/client-query.js +0 -69
  221. package/dist/profile/client.d.ts +0 -26
  222. package/dist/profile/client.js +0 -31
  223. package/dist/project/closure.d.ts +0 -25
  224. package/dist/project/closure.js +0 -74
  225. package/dist/registry/store.d.ts +0 -42
  226. package/dist/registry/store.js +0 -43
  227. package/dist/runtime/clock.d.ts +0 -7
  228. package/dist/runtime/clock.js +0 -7
  229. package/dist/runtime/module-loader.d.ts +0 -2
  230. package/dist/runtime/module-loader.js +0 -1
  231. package/dist/runtime/process.d.ts +0 -8
  232. package/dist/runtime/process.js +0 -1
  233. package/dist/runtime/runner.d.ts +0 -234
  234. package/dist/runtime/runner.js +0 -609
  235. package/dist/schema/index.d.ts +0 -1
  236. package/dist/schema/index.js +0 -1
  237. package/dist/server/dispatcher.d.ts +0 -25
  238. package/dist/server/dispatcher.js +0 -54
  239. package/dist/service/local.d.ts +0 -27
  240. package/dist/service/local.js +0 -141
  241. package/dist/storage/driver.d.ts +0 -10
  242. package/dist/storage/driver.js +0 -10
  243. package/dist/storage/lazy.d.ts +0 -8
  244. package/dist/storage/lazy.js +0 -45
  245. package/dist/storage/lock-core.d.ts +0 -158
  246. package/dist/storage/lock-core.js +0 -872
  247. package/dist/utils/net.d.ts +0 -10
  248. package/dist/utils/net.js +0 -16
  249. package/dist/utils/process.d.ts +0 -10
  250. package/dist/utils/process.js +0 -21
  251. /package/dist/{filter → utils}/intent.d.ts +0 -0
  252. /package/dist/{filter → utils}/intent.js +0 -0
@@ -1,609 +0,0 @@
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";
3
- import { validateSchemaOnly } from "../schema/validator.js";
4
- import { validateActionInputValue } from "../json/value-validator.js";
5
- import { createActionContext, StderrLogger } from "./context.js";
6
- import { createDefaultProcessOwner } from "../invocation/types.js";
7
- import { ActionRegistry, findLocalAction, isActionDefinitionObject, resolveAnonymousActionId, } from "./action-registry.js";
8
- import { buildInitialRunRecord, createRunFinalizer, createRunOrThrow, tryCreateRun, } from "./run-persistence.js";
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
- }
30
- /**
31
- * ActionDock 核心执行引擎(ActionRunner)。
32
- *
33
- * 本类为执行编排壳:负责 Action 执行的全生命周期编排(校验、深度与环路检测、
34
- * 超时与取消竞态、子调用 uses 授权与错误分类),并将单一职责域委托至独立模块:
35
- * - Action 注册与检索委托 ActionRegistry(action-registry.ts)
36
- * - RunRecord 构造与落库委托 run-persistence.ts
37
- * - 跨包动作调用委托注入的 ActionInvoker 并重返目标包执行服务
38
- *
39
- * 入参 (inputSchema) 与出参 (outputSchema) 的 JSON Schema 严格校验、嵌套 Action
40
- * 相互调用的环路检测(Cycle Detection)、超时 (Timeout) 与中断信号 (AbortSignal)
41
- * 竞态控制与运行记录持久化编排仍由本类承担。
42
- */
43
- export class ActionRunner {
44
- identity;
45
- packageId;
46
- packageInstanceId;
47
- generationId;
48
- storage;
49
- globalStorage;
50
- projectRoot;
51
- projectConfig;
52
- configOverrides;
53
- registry;
54
- clock;
55
- process;
56
- customHome;
57
- actionResolver;
58
- hostSessionId;
59
- actionInvoker;
60
- constructor(options) {
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;
68
- this.hostSessionId = options.hostSessionId;
69
- this.projectRoot = options.projectRoot;
70
- this.projectConfig = options.projectConfig;
71
- this.configOverrides = options.configOverrides || {};
72
- this.registry = new ActionRegistry(options.actions);
73
- this.customHome = options.customHome;
74
- this.actionInvoker = options.actionInvoker;
75
- this.actionResolver = options.actionResolver;
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;
83
- }
84
- /** 本地 Action 注册表底层映射 */
85
- get actions() {
86
- return this.registry.map;
87
- }
88
- getStorage() {
89
- return this.storage;
90
- }
91
- registerAction(idOrAction, actionDef) {
92
- this.registry.registerAction(idOrAction, actionDef);
93
- }
94
- /**
95
- * 根据 ID 检索注册的 Action。
96
- */
97
- getAction(id) {
98
- return this.registry.getAction(id);
99
- }
100
- /**
101
- * 设置子任务动作调用委托器。
102
- */
103
- setActionInvoker(invoker) {
104
- this.actionInvoker = invoker;
105
- }
106
- /**
107
- * 动态解析 Action(支持本地注册表、自定义解析器委托与已链接包目录索引检索)。
108
- *
109
- * @param actionOrRef Action 定义对象、引用或标识符
110
- * @returns 解析判别联合结果(found | not_found)
111
- */
112
- async resolveAction(actionOrRef) {
113
- if (isActionDefinitionObject(actionOrRef)) {
114
- return { status: "found", action: actionOrRef };
115
- }
116
- const ref = actionOrRef;
117
- let parsed;
118
- try {
119
- parsed = parseActionRef(ref);
120
- }
121
- catch (err) {
122
- return { status: "not_found", reason: err.message };
123
- }
124
- const targetActionId = parsed.actionId;
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
- }
133
- // 本地 actions 映射表优先检索
134
- const localMatched = findLocalAction(this.actions, parsed, this.packageId);
135
- if (localMatched) {
136
- return { status: "found", action: localMatched };
137
- }
138
- // 外部注入的局部 actionResolver 调度
139
- if (this.actionResolver) {
140
- try {
141
- const customResolved = await this.actionResolver(targetActionId);
142
- if (customResolved) {
143
- this.actions.set(targetActionId, customResolved);
144
- if (this.packageId) {
145
- this.actions.set(`${this.packageId}/${targetActionId}`, customResolved);
146
- }
147
- return { status: "found", action: customResolved };
148
- }
149
- }
150
- catch (err) {
151
- return { status: "not_found", reason: err.message };
152
- }
153
- }
154
- // 铁律 4:Runner 不找 Package:只能执行自己所属 Package 的 Action
155
- return {
156
- status: "not_found",
157
- reason: `Action '${targetActionId}' not found in package '${this.packageId}'`,
158
- };
159
- }
160
- /**
161
- * 获取当前 Runner 已注册的所有 Action 列表。
162
- */
163
- listActions() {
164
- return this.registry.listActions();
165
- }
166
- /**
167
- * 异步启动 Action 的执行并立即返回 ExecutionHandle 句柄。
168
- *
169
- * @param actionOrId Action 定义对象、引用或标识符
170
- * @param input 传递给 Action 的输入数据
171
- * @param options 执行控制选项(超时、取消信号、父运行 ID 等)
172
- * @returns 包含 runId、result Promise 和 cancel 方法的执行句柄
173
- */
174
- start(actionOrId, input = {}, options = {}) {
175
- const runCtx = this.prepareRunContext(actionOrId, input, options);
176
- const { runId, targetActionId, targetPackageId } = runCtx;
177
- // 输入参数 JSON 格式与合法性防御校验(拦截 NaN/Infinity/循环引用等非 JSON 类型及非法原型键策略违规)
178
- const inputCheck = validateActionInputValue(input);
179
- if (!inputCheck.valid) {
180
- const error = buildInputValidationError(targetActionId, inputCheck);
181
- // 安全记录 failed 状态(不可序列化或策略违规的非法 input 严禁直接写入持久化存储)
182
- tryCreateRun(this.storage, buildInitialRunRecord(this.buildRunPersistenceInput(runCtx), "failed", error));
183
- return {
184
- runId,
185
- result: Promise.resolve({ ok: false, runId, error }),
186
- cancel: () => false,
187
- };
188
- }
189
- // 始终优先将执行尝试持久化到存储中(确保任意异常与终态都可追溯)
190
- createRunOrThrow(this.storage, buildInitialRunRecord(this.buildRunPersistenceInput(runCtx), "running"));
191
- const finalizer = createRunFinalizer(this.storage, runCtx.runId);
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);
200
- }
201
- // 输入参数 JSON Schema 校验(若 action 已就绪)
202
- const schemaError = this.checkActionInputSchema(runCtx.action, targetActionId, input);
203
- if (schemaError) {
204
- finalizer.finalize("failed", undefined, schemaError);
205
- return {
206
- runId,
207
- result: Promise.resolve({ ok: false, runId, error: schemaError }),
208
- cancel: () => false,
209
- };
210
- }
211
- // 初始化 AbortController 与超时定时器
212
- const controller = new AbortController();
213
- let onAbort;
214
- if (options.signal) {
215
- if (options.signal.aborted) {
216
- controller.abort(options.signal.reason);
217
- }
218
- else {
219
- onAbort = () => controller.abort(options.signal?.reason);
220
- options.signal.addEventListener("abort", onAbort, { once: true });
221
- finalizer.signal = options.signal;
222
- finalizer.onAbort = onAbort;
223
- }
224
- }
225
- if (typeof options.timeoutMs === "number" && options.timeoutMs > 0) {
226
- finalizer.startTimeout(controller, options.timeoutMs);
227
- }
228
- // 构建 ActionContext 运行时上下文
229
- const ctx = this.buildActionContext({
230
- runCtx,
231
- controller,
232
- rootRunId: this.computeRootRunId(runCtx),
233
- });
234
- // 执行 Action 业务逻辑并与取消/超时信号进行竞态
235
- const executionPromise = this.raceExecutionAndAbort({
236
- runCtx,
237
- actionOrId,
238
- input,
239
- options,
240
- controller,
241
- finalizer,
242
- ctx,
243
- });
244
- return {
245
- runId,
246
- result: executionPromise,
247
- cancel: (reason) => {
248
- if (finalizer.finalized || controller.signal.aborted) {
249
- return false;
250
- }
251
- if (options.signal && onAbort) {
252
- options.signal.removeEventListener("abort", onAbort);
253
- finalizer.onAbort = undefined;
254
- }
255
- controller.abort(new Error(reason || "Action execution was cancelled"));
256
- return true;
257
- },
258
- };
259
- }
260
- /**
261
- * 计算根运行标识(优先显式 rootRunId,其次 parentRunId,最后自身 runId)。
262
- */
263
- computeRootRunId(runCtx) {
264
- return runCtx.options.rootRunId || runCtx.options.parentRunId || runCtx.runId;
265
- }
266
- /**
267
- * 预解析执行目标并装配运行期共享上下文对象(runId、目标标识、时钟源与调用栈快照)。
268
- */
269
- prepareRunContext(actionOrId, input, options) {
270
- const runId = options.runId || crypto.randomUUID();
271
- const effectiveClock = options.clock ?? this.clock;
272
- const effectiveProcess = options.process || this.process;
273
- const startedAt = effectiveClock?.now().toISOString() ||
274
- (typeof this.storage.clock?.now === "function"
275
- ? this.storage.clock.now().toISOString()
276
- : new Date().toISOString());
277
- const callStack = [...(options.callStack || [])];
278
- let action;
279
- let targetActionId;
280
- let targetPackageId = this.packageId;
281
- if (isActionDefinitionObject(actionOrId)) {
282
- action = actionOrId;
283
- const actObj = action;
284
- if (actObj.id) {
285
- targetActionId = actObj.id;
286
- }
287
- else {
288
- targetActionId = resolveAnonymousActionId(this.actions, action);
289
- }
290
- this.actions.set(targetActionId, action);
291
- }
292
- else {
293
- const parsed = parseActionRef(actionOrId);
294
- targetActionId = parsed.actionId;
295
- if (parsed.packageId) {
296
- targetPackageId = parsed.packageId;
297
- }
298
- action = findLocalAction(this.actions, parsed, this.packageId);
299
- }
300
- return {
301
- runId,
302
- options,
303
- input,
304
- action,
305
- actionOrId,
306
- targetActionId,
307
- targetPackageId,
308
- effectiveProcess,
309
- startedAt,
310
- callStack,
311
- };
312
- }
313
- /**
314
- * 依据运行期上下文装配落库模块入参(RunRecord 构造领域契约)。
315
- */
316
- buildRunPersistenceInput(runCtx) {
317
- const { options, targetPackageId, targetActionId, startedAt, input } = runCtx;
318
- return {
319
- runId: runCtx.runId,
320
- rootRunId: this.computeRootRunId(runCtx),
321
- parentRunId: options.parentRunId,
322
- ownerId: options.ownerId,
323
- hostSessionId: options.hostSessionId,
324
- packageInstanceId: options.packageInstanceId,
325
- generationId: options.generationId,
326
- targetPackageId,
327
- targetActionId,
328
- startedAt,
329
- input,
330
- runnerPackageId: this.packageId,
331
- runnerPackageInstanceId: this.packageInstanceId,
332
- runnerGenerationId: this.generationId,
333
- runnerHostSessionId: this.hostSessionId,
334
- };
335
- }
336
- /**
337
- * 输入参数 JSON Schema 校验(若 action 已就绪,返回校验错误或 undefined)。
338
- */
339
- checkActionInputSchema(action, targetActionId, input) {
340
- const targetInputSchema = action?.inputSchema !== undefined
341
- ? action.inputSchema
342
- : this.projectConfig?.actions?.[targetActionId]?.inputSchema;
343
- if (targetInputSchema !== undefined) {
344
- const val = validateSchemaOnly(targetInputSchema, input);
345
- if (!val.valid) {
346
- return {
347
- code: INPUT_VALIDATION_FAILED,
348
- message: `Input schema validation failed for action '${targetActionId}'`,
349
- details: val.errors,
350
- };
351
- }
352
- }
353
- return undefined;
354
- }
355
- /**
356
- * 构建 ActionContext 运行时上下文(内嵌子 Action 调用委托提为私有方法)。
357
- */
358
- buildActionContext(args) {
359
- const { runCtx, controller, rootRunId } = args;
360
- const { options, targetPackageId, targetActionId, effectiveProcess } = runCtx;
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
- });
368
- return createActionContext({
369
- actionId: targetActionId,
370
- storage: this.storage,
371
- globalStorage: this.globalStorage,
372
- overrides: { ...this.configOverrides, ...(options.configOverrides || {}) },
373
- projectConfig: this.projectConfig,
374
- runId: runCtx.runId,
375
- rootRunId,
376
- parentRunId: options.parentRunId,
377
- signal: controller.signal,
378
- process: effectiveProcess,
379
- owner: effectiveOwner,
380
- progress: options.progress,
381
- logger: options.logger || new StderrLogger(targetActionId),
382
- onActionInvoke: (childAction, childInput, parentRunId) => this.invokeChildAction({
383
- runCtx,
384
- controller,
385
- rootRunId,
386
- childAction,
387
- childInput,
388
- parentRunId,
389
- }),
390
- });
391
- }
392
- /**
393
- * 子 Action 调用委托:
394
- * 必须委托 Host 动作调用器(走 Host 执行主链与 InvocationPolicy 鉴权);
395
- * 缺少 actionInvoker 时直接抛出 INVOCATION_UNSUPPORTED,严禁跨包或同包无约束执行逃逸。
396
- */
397
- async invokeChildAction(args) {
398
- const { runCtx, controller, rootRunId, childAction, childInput, parentRunId } = args;
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,
410
- });
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);
438
- }
439
- /**
440
- * 执行 Action 业务逻辑并与取消/超时信号进行竞态,返回执行结果信封 Promise。
441
- */
442
- raceExecutionAndAbort(args) {
443
- const { runCtx, actionOrId, input, options, controller, finalizer, ctx } = args;
444
- const { runId, targetActionId } = runCtx;
445
- const abortPromise = new Promise((_, reject) => {
446
- const rejectWithReason = () => reject(controller.signal.reason || new Error("Action execution was cancelled"));
447
- if (controller.signal.aborted) {
448
- rejectWithReason();
449
- }
450
- else {
451
- controller.signal.addEventListener("abort", rejectWithReason, { once: true });
452
- // 成功与失败路径统一注销:finalize 时回收监听句柄,避免信号对象残留引用
453
- finalizer.raceListenerRemovers.push(() => {
454
- controller.signal.removeEventListener("abort", rejectWithReason);
455
- });
456
- }
457
- });
458
- return (async () => {
459
- try {
460
- let currentAction = runCtx.action;
461
- if (!currentAction) {
462
- const resolution = await this.resolveAction(actionOrId);
463
- if (resolution.status === "found") {
464
- currentAction = resolution.action;
465
- runCtx.action = currentAction;
466
- }
467
- else {
468
- const error = {
469
- code: ACTION_NOT_FOUND,
470
- message: `Action '${targetActionId}' not found in registry or linked packages`,
471
- details: resolution.reason ? { reason: resolution.reason } : undefined,
472
- };
473
- finalizer.finalize("failed", undefined, error);
474
- return { ok: false, runId, error };
475
- }
476
- const inputCheck = validateActionInputValue(input);
477
- if (!inputCheck.valid) {
478
- const error = buildInputValidationError(targetActionId, inputCheck);
479
- finalizer.finalize("failed", undefined, error);
480
- return { ok: false, runId, error };
481
- }
482
- // 复用统一校验入口:优先 action 声明 schema,缺失时回退 projectConfig 清单声明
483
- const schemaError = this.checkActionInputSchema(currentAction, targetActionId, input);
484
- if (schemaError) {
485
- finalizer.finalize("failed", undefined, schemaError);
486
- return { ok: false, runId, error: schemaError };
487
- }
488
- }
489
- const rawOutput = await Promise.race([
490
- Promise.resolve().then(() => currentAction.run(input, ctx)),
491
- abortPromise,
492
- ]);
493
- // 输出结果非 JSON 格式与合法性校验(拦截 NaN/Infinity/循环引用等)
494
- const outputCheck = validateJsonValue(rawOutput);
495
- if (!outputCheck.valid) {
496
- const error = {
497
- code: OUTPUT_NOT_JSON,
498
- message: `Output validation failed for action '${targetActionId}': ${outputCheck.reason}`,
499
- };
500
- finalizer.finalize("failed", undefined, error);
501
- return { ok: false, runId, error };
502
- }
503
- // 输出结果 Schema 校验
504
- const outputSchemaError = this.checkActionOutputSchema(currentAction, targetActionId, rawOutput);
505
- if (outputSchemaError) {
506
- finalizer.finalize("failed", undefined, outputSchemaError);
507
- return { ok: false, runId, error: outputSchemaError };
508
- }
509
- finalizer.finalize("success", rawOutput);
510
- if (finalizer.persistError) {
511
- return { ok: false, runId, error: finalizer.persistError };
512
- }
513
- return {
514
- ok: true,
515
- runId,
516
- data: rawOutput,
517
- };
518
- }
519
- catch (err) {
520
- return this.classifyExecutionError(err, runCtx, controller, finalizer);
521
- }
522
- finally {
523
- // 仅释放 run 级隔离实例;平台级共享 ContextProcessAPI 生命周期归平台所有,严禁在此误 dispose
524
- if (ctx &&
525
- ctx.process?.runScoped === true &&
526
- typeof ctx.process.dispose === "function") {
527
- try {
528
- await ctx.process.dispose();
529
- }
530
- catch { }
531
- }
532
- }
533
- })();
534
- }
535
- /**
536
- * 输出结果 Schema 校验(返回校验错误或 undefined)。
537
- */
538
- checkActionOutputSchema(action, targetActionId, rawOutput) {
539
- const targetOutputSchema = action?.outputSchema !== undefined
540
- ? action.outputSchema
541
- : this.projectConfig?.actions?.[targetActionId]?.outputSchema;
542
- if (targetOutputSchema !== undefined) {
543
- const outVal = validateSchemaOnly(targetOutputSchema, rawOutput);
544
- if (!outVal.valid) {
545
- return {
546
- code: OUTPUT_VALIDATION_FAILED,
547
- message: `Output schema validation failed for action '${targetActionId}'`,
548
- details: outVal.errors,
549
- };
550
- }
551
- }
552
- return undefined;
553
- }
554
- /**
555
- * 异常分类收敛:超时、取消与业务失败分别映射为对应终态与错误码。
556
- */
557
- classifyExecutionError(err, runCtx, controller, finalizer) {
558
- const { runId, options } = runCtx;
559
- if (finalizer.isTimeout) {
560
- const error = {
561
- code: ACTION_TIMEOUT,
562
- message: `Action exceeded timeout of ${options.timeoutMs}ms`,
563
- };
564
- finalizer.finalize("timed_out", undefined, error);
565
- return { ok: false, runId, error: finalizer.persistError || error };
566
- }
567
- if (controller.signal.aborted) {
568
- const reason = controller.signal.reason;
569
- const reasonMsg = reason instanceof Error
570
- ? reason.message
571
- : typeof reason === "string"
572
- ? reason
573
- : undefined;
574
- const error = {
575
- code: ACTION_CANCELLED,
576
- message: "Action execution was cancelled",
577
- details: reasonMsg ? { reason: reasonMsg } : undefined,
578
- };
579
- finalizer.finalize("cancelled", undefined, error);
580
- return { ok: false, runId, error: finalizer.persistError || error };
581
- }
582
- const error = {
583
- code: err?.code || ACTION_FAILED,
584
- message: err?.message || String(err),
585
- details: err?.details,
586
- };
587
- finalizer.finalize("failed", undefined, error);
588
- return {
589
- ok: false,
590
- runId,
591
- error: finalizer.persistError || error,
592
- };
593
- }
594
- /**
595
- * 释放 Runner 持有的资源。
596
- * 铁律 4:Runner 仅执行自己所属 Package 的 Action,不管理外部包生命周期。
597
- */
598
- async dispose() { }
599
- /**
600
- * 同步等待方式执行指定 Action,直接返回 ExecutionResult 信封结果。
601
- *
602
- * @param actionOrId Action 定义对象、引用或标识符
603
- * @param input 输入参数
604
- * @param options 执行控制选项
605
- */
606
- async execute(actionOrId, input = {}, options = {}) {
607
- return this.start(actionOrId, input, options).result;
608
- }
609
- }
@@ -1 +0,0 @@
1
- export * from "./validator.js";
@@ -1 +0,0 @@
1
- export * from "./validator.js";
@@ -1,25 +0,0 @@
1
- /**
2
- * 获取底层 HTTP 调度器(如 Undici Agent 或自定义 Dispatcher)的提供者函数契约。
3
- */
4
- export type FetchDispatcherProvider = () => unknown;
5
- /**
6
- * 注册全局用于忽略服务端证书校验的调度器提供者。
7
- */
8
- export declare function setInsecureDispatcherProvider(provider?: FetchDispatcherProvider): void;
9
- /**
10
- * 获取当前已注册的调度器提供者函数。
11
- */
12
- export declare function getInsecureDispatcherProvider(): FetchDispatcherProvider | undefined;
13
- /**
14
- * 获取用于忽略服务端证书校验的全局单例 Undici Agent 调度器。
15
- * 显式配置 bodyTimeout: 0 以防止 SSE 长连接与流式事件读取出现 UND_ERR_BODY_TIMEOUT 空闲超时断流。
16
- */
17
- export declare function getInsecureDispatcher(): unknown;
18
- /**
19
- * 显式安装平台调度器:向 core 注册本模块的提供者函数。
20
- */
21
- export declare function installInsecureDispatcher(): void;
22
- /**
23
- * 显式强制重置并销毁调度器连接池(仅用于单元测试重置或进程退出)。
24
- */
25
- export declare function closeInsecureDispatcher(): Promise<void>;
@@ -1,54 +0,0 @@
1
- import { Agent } from "undici";
2
- let insecureDispatcherProvider;
3
- let globalInsecureAgent;
4
- /**
5
- * 注册全局用于忽略服务端证书校验的调度器提供者。
6
- */
7
- export function setInsecureDispatcherProvider(provider) {
8
- insecureDispatcherProvider = provider;
9
- }
10
- /**
11
- * 获取当前已注册的调度器提供者函数。
12
- */
13
- export function getInsecureDispatcherProvider() {
14
- return insecureDispatcherProvider;
15
- }
16
- /**
17
- * 获取用于忽略服务端证书校验的全局单例 Undici Agent 调度器。
18
- * 显式配置 bodyTimeout: 0 以防止 SSE 长连接与流式事件读取出现 UND_ERR_BODY_TIMEOUT 空闲超时断流。
19
- */
20
- export function getInsecureDispatcher() {
21
- if (insecureDispatcherProvider) {
22
- return insecureDispatcherProvider();
23
- }
24
- if (!globalInsecureAgent || globalInsecureAgent.closed || globalInsecureAgent.destroyed) {
25
- globalInsecureAgent = new Agent({
26
- connect: {
27
- rejectUnauthorized: false,
28
- },
29
- bodyTimeout: 0,
30
- });
31
- }
32
- return globalInsecureAgent;
33
- }
34
- /**
35
- * 显式安装平台调度器:向 core 注册本模块的提供者函数。
36
- */
37
- export function installInsecureDispatcher() {
38
- setInsecureDispatcherProvider(getInsecureDispatcher);
39
- }
40
- /**
41
- * 显式强制重置并销毁调度器连接池(仅用于单元测试重置或进程退出)。
42
- */
43
- export async function closeInsecureDispatcher() {
44
- if (globalInsecureAgent) {
45
- const agent = globalInsecureAgent;
46
- globalInsecureAgent = undefined;
47
- try {
48
- await agent.close();
49
- }
50
- catch (err) {
51
- console.warn("[actiondock] closeInsecureDispatcher failed to close agent:", err);
52
- }
53
- }
54
- }