@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,17 +1,21 @@
1
- import { randomUUID } from "node:crypto";
2
- import { ActionResolver } from "../catalog/action-resolver.js";
1
+ import { existsSync } from "node:fs";
2
+ import { parseActionRef } from "../catalog/resolve-action.js";
3
3
  import { computeDigest } from "../project/digest.js";
4
+ import { loadActions, loadProjectConfig } from "../project/loader.js";
4
5
  import { InMemoryEventSink } from "../runtime/events.js";
5
6
  import { ActionRunner } from "../runtime/runner.js";
6
- import { ACTION_NOT_FOUND, EXECUTION_FAILED, IDEMPOTENCY_CONFLICT, RUN_REPOSITORY_UNAVAILABLE, UNHANDLED_EXECUTION_ERROR, describeActionLoadFailure, } from "../errors.js";
7
+ import { ActionDockError, ACTION_NOT_FOUND, EXECUTION_FAILED, IDEMPOTENCY_CONFLICT, RUN_REPOSITORY_UNAVAILABLE, UNHANDLED_EXECUTION_ERROR, describeActionLoadFailure, } from "../errors.js";
7
8
  import { resultStatusToRunStatus } from "../storage/types.js";
8
9
  /**
9
10
  * 统一执行协调服务实现。
10
11
  */
11
12
  export class DefaultExecutionService {
13
+ identity;
12
14
  packageId;
13
15
  storage;
14
16
  projectConfig;
17
+ projectRoot;
18
+ moduleLoader;
15
19
  eventSink;
16
20
  packageInstanceId;
17
21
  generationId;
@@ -22,86 +26,56 @@ export class DefaultExecutionService {
22
26
  logger;
23
27
  clock;
24
28
  process;
25
- platform;
26
29
  actionResolver;
27
30
  activeRuns = new Map();
28
- reservedSlots = 0;
29
- isClosing = false;
30
- ownsStorage;
31
- ownsGlobalStorage;
32
31
  globalStorage;
32
+ actionInvoker;
33
+ isClosing = false;
34
+ reservedSlots = 0;
33
35
  constructor(options) {
34
- this.platform = options.platform;
35
- this.packageId = options.packageId;
36
- this.packageInstanceId = options.packageInstanceId || this.packageId;
37
- this.generationId = options.generationId || "1";
36
+ if (!options.identity) {
37
+ throw new Error("DefaultExecutionService requires 'identity' PackageIdentity option");
38
+ }
39
+ if (!options.storage) {
40
+ throw new Error("DefaultExecutionService requires 'storage' option");
41
+ }
42
+ this.identity = options.identity;
43
+ this.packageId = this.identity.id;
44
+ this.packageInstanceId = this.identity.instanceId;
45
+ this.generationId = this.identity.generation;
38
46
  this.hostSessionId = options.hostSessionId;
39
47
  this.projectConfig = options.projectConfig;
40
- this.eventSink = options.eventSink || options.platform?.eventSink || new InMemoryEventSink();
48
+ this.projectRoot = options.projectRoot;
49
+ this.moduleLoader = options.moduleLoader;
50
+ this.eventSink = options.eventSink || new InMemoryEventSink();
41
51
  this.maxActiveRuns = options.maxActiveRuns || 32;
42
- this.ownerId = options.ownerId || `host-${randomUUID().slice(0, 8)}`;
52
+ this.ownerId = options.ownerId || `host-${crypto.randomUUID().slice(0, 8)}`;
43
53
  this.actionResolver = options.actionResolver;
44
54
  this.logger = options.logger;
45
- if (options.platform) {
46
- this.clock = options.platform.clock;
47
- this.process = options.platform.process;
48
- this.storage =
49
- options.storage ??
50
- options.platform.storage.createStorage(this.packageId, {
51
- projectRoot: options.projectRoot,
52
- customHome: options.customHome,
53
- // 执行服务属于数据目录持有者主路径,打开时收割遗留孤儿运行
54
- recoverOrphans: true,
55
- });
56
- }
57
- else {
58
- this.clock = options.clock;
59
- this.process = options.process;
60
- if (!options.storage) {
61
- throw new Error("ExecutionService requires either 'storage' or 'platform' option");
62
- }
63
- this.storage = options.storage;
64
- }
65
- const globalStorage = options.platform
66
- ? (options.globalStorage ??
67
- options.platform.storage.createGlobalStorage({ customHome: options.customHome, recoverOrphans: true }))
68
- : options.globalStorage;
69
- this.ownsStorage = !options.storage;
70
- this.ownsGlobalStorage = !options.globalStorage && !!options.platform;
71
- this.globalStorage = globalStorage;
55
+ this.actionInvoker = options.actionInvoker;
56
+ this.storage = options.storage;
57
+ this.globalStorage = options.globalStorage;
58
+ this.clock = options.clock;
59
+ this.process = options.process;
72
60
  this._runner = new ActionRunner({
73
- packageId: this.packageId,
74
- packageInstanceId: this.packageInstanceId,
75
- generationId: this.generationId,
61
+ identity: this.identity,
76
62
  hostSessionId: this.hostSessionId,
77
63
  storage: this.storage,
78
- globalStorage,
64
+ globalStorage: this.globalStorage,
79
65
  projectRoot: options.projectRoot,
80
66
  projectConfig: this.projectConfig,
81
67
  configOverrides: options.configOverrides,
82
68
  actions: options.actions,
83
69
  process: this.process,
84
70
  clock: this.clock,
85
- platform: options.platform,
86
- maxCallDepth: options.maxCallDepth,
87
- maxSubRuns: options.maxSubRuns,
88
- actionResolver: (ref, currentPkgId) => {
89
- const parsed = typeof ref === "string" ? ActionResolver.parseRef(ref) : ref;
90
- if (parsed.packageId && parsed.packageId !== this.packageId) {
91
- return undefined;
92
- }
93
- if (currentPkgId && currentPkgId !== this.packageId) {
94
- return undefined;
95
- }
96
- return this.actionResolver ? this.actionResolver(parsed) : undefined;
97
- },
98
- getStorageForPackage: options.getStorageForPackage,
99
- packageContextResolver: options.packageContextResolver,
71
+ actionResolver: this.actionResolver,
100
72
  customHome: options.customHome,
73
+ actionInvoker: this.actionInvoker,
101
74
  });
102
75
  }
103
- get runner() {
104
- return this._runner;
76
+ setActionInvoker(invoker) {
77
+ this.actionInvoker = invoker;
78
+ this._runner.setActionInvoker(invoker);
105
79
  }
106
80
  registerAction(idOrAction, actionDef) {
107
81
  if (typeof idOrAction === "string") {
@@ -120,39 +94,20 @@ export class DefaultExecutionService {
120
94
  getActiveHandle(runId) {
121
95
  return this.activeRuns.get(runId)?.handle;
122
96
  }
123
- setPackageContextResolver(resolver) {
124
- this._runner.setPackageContextResolver(resolver);
125
- }
126
- async resolveTargetAction(ref) {
127
- const parsed = typeof ref === "string" ? ActionResolver.parseRef(ref) : ref;
128
- const actionId = parsed.actionId;
129
- const targetPackageId = parsed.packageId || this.packageId;
130
- let runner = this._runner;
131
- if (targetPackageId !== this.packageId) {
132
- const targetRunner = await this._runner.resolveTargetPackageRunner(targetPackageId);
133
- if (!targetRunner)
134
- return undefined;
135
- runner = targetRunner;
136
- }
137
- const fromRunner = runner.getAction(actionId);
138
- if (fromRunner)
139
- return fromRunner;
140
- if (this.actionResolver && targetPackageId === this.packageId) {
141
- return this.actionResolver(parsed);
142
- }
143
- return undefined;
144
- }
145
- async execute(ref, input, options = {}) {
146
- const ticket = await this.start(ref, input, options);
97
+ async execute(ref, input, context) {
98
+ const ticket = await this.start(ref, input, context);
147
99
  if (!ticket.result) {
148
100
  throw new Error(`Execution ticket for run '${ticket.runId}' has no result Promise`);
149
101
  }
150
102
  return ticket.result;
151
103
  }
104
+ async run(ref, input, context) {
105
+ return this.execute(ref, input, context);
106
+ }
152
107
  get activeRunsCount() {
153
108
  return this.activeRuns.size + this.reservedSlots;
154
109
  }
155
- async start(ref, input, options = {}) {
110
+ async start(ref, input, context) {
156
111
  if (this.isClosing) {
157
112
  throw new Error("ExecutionService is closing: new tasks rejected");
158
113
  }
@@ -171,7 +126,7 @@ export class DefaultExecutionService {
171
126
  try {
172
127
  let parsedRef;
173
128
  try {
174
- parsedRef = ActionResolver.parseRef(ref);
129
+ parsedRef = parseActionRef(ref);
175
130
  }
176
131
  catch {
177
132
  parsedRef = typeof ref === "object" ? ref : { actionId: ref };
@@ -179,9 +134,9 @@ export class DefaultExecutionService {
179
134
  const targetActionId = parsedRef.actionId;
180
135
  const targetPackageId = parsedRef.packageId || this.packageId;
181
136
  const actionRef = `${targetPackageId}/${targetActionId}`;
182
- const effectiveClock = options.platform?.clock ?? this.clock;
137
+ const effectiveClock = this.clock;
183
138
  // requestId 幂等检查与去重处理
184
- const gateResult = await this.checkIdempotencyGate(input, options, actionRef, effectiveClock);
139
+ const gateResult = await this.checkIdempotencyGate(input, context, actionRef, effectiveClock);
185
140
  if (gateResult.ticket) {
186
141
  releaseSlot();
187
142
  return gateResult.ticket;
@@ -193,7 +148,7 @@ export class DefaultExecutionService {
193
148
  return this.failTicketForMissingAction({
194
149
  target,
195
150
  input,
196
- options,
151
+ context,
197
152
  targetPackageId,
198
153
  targetActionId,
199
154
  designatedRunId,
@@ -205,36 +160,44 @@ export class DefaultExecutionService {
205
160
  }
206
161
  const controller = new AbortController();
207
162
  let onAbort;
208
- if (options.signal && typeof options.signal.addEventListener === "function") {
209
- if (options.signal.aborted) {
210
- controller.abort(options.signal.reason);
163
+ if (context.signal && typeof context.signal.addEventListener === "function") {
164
+ if (context.signal.aborted) {
165
+ controller.abort(context.signal.reason);
211
166
  }
212
167
  else {
213
- onAbort = () => controller.abort(options.signal?.reason);
214
- options.signal.addEventListener("abort", onAbort, { once: true });
168
+ onAbort = () => controller.abort(context.signal?.reason);
169
+ context.signal.addEventListener("abort", onAbort, { once: true });
215
170
  }
216
171
  }
217
- const runId = designatedRunId || randomUUID();
218
- const bridge = this.createEventBridge({ runId, options, effectiveClock });
219
- this.registerResolvedAction(target.runner, targetPackageId, targetActionId, target.action);
172
+ const runId = designatedRunId || context.runId || crypto.randomUUID();
173
+ const bridge = this.createEventBridge({ runId, context, effectiveClock });
174
+ target.runner.registerAction(targetActionId, target.action);
220
175
  const handle = target.runner.start(targetActionId, input, {
221
176
  runId,
222
- rootRunId: options.rootRunId,
223
- parentRunId: options.parentRunId,
224
- hostSessionId: options.hostSessionId || this.hostSessionId,
225
- maxCallDepth: options.maxCallDepth,
226
- configOverrides: options.config,
177
+ rootRunId: context.rootRunId,
178
+ parentRunId: context.parentRunId,
179
+ callStack: context.callStack ? [...context.callStack] : undefined,
180
+ hostSessionId: context.hostSessionId || this.hostSessionId,
181
+ maxCallDepth: context.maxCallDepth,
182
+ configOverrides: context.config,
227
183
  signal: controller.signal,
228
- timeoutMs: options.timeoutMs,
184
+ timeoutMs: context.timeoutMs,
229
185
  progress: bridge.progressReporter,
230
186
  logger: bridge.executionLogger,
231
- process: options.process || options.platform?.process || this.process,
232
- platform: options.platform || this.platform,
233
- packageInstanceId: options.packageInstanceId,
234
- generationId: options.generationId,
235
- tenantId: options.tenantId,
236
- principalId: options.principalId,
237
- owner: options.owner,
187
+ process: context.process || this.process,
188
+ packageInstanceId: context.package.instanceId,
189
+ generationId: context.package.generation,
190
+ tenantId: context.owner?.tenantId || context.tenantId,
191
+ principalId: context.owner?.principalId || context.principalId,
192
+ owner: context.owner
193
+ ? {
194
+ tenantId: context.owner.tenantId,
195
+ principalId: context.owner.principalId,
196
+ packageInstanceId: context.owner.packageInstanceId || context.package.instanceId,
197
+ generationId: context.owner.generationId || context.package.generation,
198
+ }
199
+ : undefined,
200
+ actionInvoker: this.actionInvoker,
238
201
  });
239
202
  const activeItem = {
240
203
  runId: handle.runId,
@@ -242,7 +205,7 @@ export class DefaultExecutionService {
242
205
  controller,
243
206
  status: "running",
244
207
  startedAt: (effectiveClock?.now() ?? new Date()).toISOString(),
245
- signal: options.signal,
208
+ signal: context.signal,
246
209
  onAbort,
247
210
  };
248
211
  this.activeRuns.set(handle.runId, activeItem);
@@ -263,43 +226,35 @@ export class DefaultExecutionService {
263
226
  /**
264
227
  * 幂等门检查:digest 计算与冲突/重复分流(重复命中时直接返回已有票据)。
265
228
  */
266
- async checkIdempotencyGate(input, options, actionRef, effectiveClock) {
267
- if (!options.requestId) {
229
+ async checkIdempotencyGate(input, context, actionRef, effectiveClock) {
230
+ if (!context.requestId) {
268
231
  return {};
269
232
  }
270
233
  const digestPayload = {
271
234
  input,
272
- config: options.config,
273
- timeoutMs: options.timeoutMs,
235
+ config: context.config,
236
+ timeoutMs: context.timeoutMs,
274
237
  };
275
238
  const inputDigest = computeDigest(digestPayload);
276
- const provisionalRunId = randomUUID();
239
+ const provisionalRunId = crypto.randomUUID();
277
240
  if (!this.storage.checkAndRecordIdempotency) {
278
241
  return {};
279
242
  }
280
243
  const idemp = this.storage.checkAndRecordIdempotency({
281
244
  ownerId: this.ownerId,
282
245
  actionRef,
283
- requestId: options.requestId,
246
+ requestId: context.requestId,
284
247
  inputDigest,
285
248
  runId: provisionalRunId,
286
249
  createdAt: (effectiveClock?.now() ?? new Date()).toISOString(),
287
250
  });
288
251
  if (idemp.outcome === "conflict") {
289
- const conflictError = {
290
- code: IDEMPOTENCY_CONFLICT,
291
- message: `Idempotency conflict for requestId '${options.requestId}': input parameters digest mismatch`,
292
- details: {
293
- requestId: options.requestId,
294
- actionRef,
295
- expectedDigest: idemp.existingDigest,
296
- actualDigest: inputDigest,
297
- },
298
- };
299
- const err = new Error(conflictError.message);
300
- err.code = conflictError.code;
301
- err.details = conflictError.details;
302
- throw err;
252
+ throw new ActionDockError(IDEMPOTENCY_CONFLICT, `Idempotency conflict for requestId '${context.requestId}': input parameters digest mismatch`, {
253
+ requestId: context.requestId,
254
+ actionRef,
255
+ expectedDigest: idemp.existingDigest,
256
+ actualDigest: inputDigest,
257
+ });
303
258
  }
304
259
  if (idemp.outcome === "duplicate") {
305
260
  const existingRunId = idemp.runId;
@@ -337,42 +292,61 @@ export class DefaultExecutionService {
337
292
  return { designatedRunId: provisionalRunId };
338
293
  }
339
294
  /**
340
- * 解析执行目标:确定目标 Runner 并解析目标 Action 定义。
295
+ * 解析执行目标:确定目标 Action 定义。
296
+ * 铁律 4:Runner 不找 Package,ExecutionService 仅执行本 Package 的 Action。
341
297
  */
342
298
  async resolveExecutionTarget(parsedRef, targetPackageId, targetActionId) {
343
- let runnerToUse = this._runner;
299
+ const runnerToUse = this._runner;
344
300
  let resolveError;
345
301
  if (targetPackageId && targetPackageId !== this.packageId) {
346
- const targetRunner = await this._runner.resolveTargetPackageRunner(targetPackageId);
347
- if (targetRunner) {
348
- runnerToUse = targetRunner;
302
+ resolveError = {
303
+ code: ACTION_NOT_FOUND,
304
+ message: `Package '${this.packageId}' cannot execute action for external package '${targetPackageId}'`,
305
+ };
306
+ return { runner: runnerToUse, action: undefined, resolveError };
307
+ }
308
+ let action = runnerToUse.getAction(targetActionId) || runnerToUse.getAction(`${targetPackageId}/${targetActionId}`);
309
+ if (!action) {
310
+ const resolution = await runnerToUse.resolveAction(parsedRef);
311
+ if (resolution.status === "found") {
312
+ action = resolution.action;
349
313
  }
350
314
  else {
351
- resolveError = {
352
- code: ACTION_NOT_FOUND,
353
- message: `Target package '${targetPackageId}' not found or unresolvable`,
354
- };
355
- }
356
- }
357
- let action;
358
- if (!resolveError) {
359
- action = runnerToUse.getAction(targetActionId) || runnerToUse.getAction(`${targetPackageId}/${targetActionId}`);
360
- if (!action) {
361
- const resolution = await runnerToUse.resolveAction(parsedRef);
362
- if (resolution.status === "found") {
363
- action = resolution.action;
364
- }
365
- else if (resolution.status === "load_failed") {
366
- resolveError = describeActionLoadFailure(resolution.error, {
367
- actionId: targetActionId,
368
- packageId: resolution.packageId,
369
- projectRoot: resolution.projectRoot,
370
- });
315
+ const targetAction = await this.actionResolver?.(targetActionId);
316
+ if (targetAction) {
317
+ action = targetAction;
371
318
  }
372
- else {
373
- const targetAction = await this.resolveTargetAction(parsedRef);
374
- if (targetAction) {
375
- action = targetAction;
319
+ else if (this.projectRoot && existsSync(this.projectRoot)) {
320
+ let config;
321
+ try {
322
+ config = this.projectConfig || loadProjectConfig(this.projectRoot);
323
+ }
324
+ catch (err) {
325
+ resolveError = describeActionLoadFailure(err, {
326
+ actionId: targetActionId,
327
+ packageId: this.packageId,
328
+ projectRoot: this.projectRoot,
329
+ });
330
+ return { runner: runnerToUse, action: undefined, resolveError };
331
+ }
332
+ let actionsMap;
333
+ try {
334
+ actionsMap = await loadActions(this.projectRoot, config.actionsDir, {
335
+ loader: this.moduleLoader,
336
+ });
337
+ }
338
+ catch (err) {
339
+ resolveError = describeActionLoadFailure(err, {
340
+ actionId: targetActionId,
341
+ packageId: this.packageId,
342
+ projectRoot: this.projectRoot,
343
+ });
344
+ return { runner: runnerToUse, action: undefined, resolveError };
345
+ }
346
+ const matched = actionsMap.get(targetActionId);
347
+ if (matched) {
348
+ action = matched;
349
+ runnerToUse.registerAction(targetActionId, matched);
376
350
  }
377
351
  else {
378
352
  resolveError = {
@@ -382,38 +356,55 @@ export class DefaultExecutionService {
382
356
  };
383
357
  }
384
358
  }
359
+ else {
360
+ resolveError = {
361
+ code: ACTION_NOT_FOUND,
362
+ message: `Action '${targetActionId}' not found in package '${targetPackageId}'`,
363
+ details: resolution.reason ? { reason: resolution.reason } : undefined,
364
+ };
365
+ }
385
366
  }
386
367
  }
387
368
  return { runner: runnerToUse, action, resolveError };
388
369
  }
389
370
  /**
390
- * 注册解析成功的目标 Action 至目标 Runner(收敛为单一注册入口)。
371
+ * 解析指定 Action 定义(供 PackageRuntime 或内部使用)。
391
372
  */
392
- registerResolvedAction(runner, targetPackageId, targetActionId, action) {
393
- runner.registerAction(targetActionId, action);
373
+ async resolveAction(ref) {
374
+ let parsedRef;
375
+ try {
376
+ parsedRef = parseActionRef(ref);
377
+ }
378
+ catch {
379
+ parsedRef = typeof ref === "object" ? ref : { actionId: ref };
380
+ }
381
+ const targetActionId = parsedRef.actionId;
382
+ const targetPackageId = parsedRef.packageId || this.packageId;
383
+ const target = await this.resolveExecutionTarget(parsedRef, targetPackageId, targetActionId);
384
+ return target.action;
394
385
  }
395
386
  /**
396
387
  * 目标 Action 缺失时的失败票据:落库 failed 记录并补发 status 与 finish 事件。
397
388
  */
398
389
  failTicketForMissingAction(args) {
399
- const { target, input, options, targetPackageId, targetActionId, designatedRunId, effectiveClock } = args;
400
- const runId = designatedRunId || randomUUID();
390
+ const { target, input, context, targetPackageId, targetActionId, designatedRunId, effectiveClock } = args;
391
+ const runId = designatedRunId || context.runId || crypto.randomUUID();
401
392
  const now = (effectiveClock?.now() ?? new Date()).toISOString();
402
393
  const error = target.resolveError || {
403
394
  code: ACTION_NOT_FOUND,
404
395
  message: `Action '${targetActionId}' not found in package '${targetPackageId}'`,
405
396
  };
406
- const rootRunId = options.rootRunId || options.parentRunId || runId;
397
+ const rootRunId = context.rootRunId || context.parentRunId || runId;
407
398
  const initialRun = {
408
399
  id: runId,
409
400
  rootRunId,
410
- parentRunId: options.parentRunId,
401
+ parentRunId: context.parentRunId,
411
402
  packageId: targetPackageId,
412
- packageInstanceId: options.packageInstanceId || target.runner.packageInstanceId || targetPackageId,
403
+ packageInstanceId: context.package.instanceId || target.runner.packageInstanceId,
413
404
  actionId: targetActionId,
414
- generationId: options.generationId || target.runner.generationId || "1",
405
+ generationId: context.package.generation || target.runner.generationId,
415
406
  ownerId: this.ownerId,
416
- hostSessionId: options.hostSessionId || this.hostSessionId,
407
+ hostSessionId: context.hostSessionId || this.hostSessionId,
417
408
  status: "failed",
418
409
  input,
419
410
  error,
@@ -424,10 +415,7 @@ export class DefaultExecutionService {
424
415
  target.runner.getStorage().createRun(initialRun);
425
416
  }
426
417
  catch (err) {
427
- const repErr = new Error(`RUN_REPOSITORY_UNAVAILABLE: Failed to initialize run record in repository: ${err?.message || String(err)}`);
428
- repErr.code = RUN_REPOSITORY_UNAVAILABLE;
429
- repErr.details = { originalError: err?.message };
430
- throw repErr;
418
+ throw new ActionDockError(RUN_REPOSITORY_UNAVAILABLE, `RUN_REPOSITORY_UNAVAILABLE: Failed to initialize run record in repository: ${err?.message || String(err)}`, { originalError: err?.message });
431
419
  }
432
420
  this.eventSink.emit({
433
421
  runId,
@@ -464,13 +452,13 @@ export class DefaultExecutionService {
464
452
  * 创建执行事件桥:事件序列号分配、进度报告器与双写日志适配器。
465
453
  */
466
454
  createEventBridge(args) {
467
- const { runId, options, effectiveClock } = args;
455
+ const { runId, context, effectiveClock } = args;
468
456
  let sequence = 0;
469
457
  const emitEvent = (payload) => {
470
458
  const evt = {
471
459
  ...payload,
472
460
  runId,
473
- rootRunId: options.rootRunId || options.parentRunId || runId,
461
+ rootRunId: context.rootRunId || context.parentRunId || runId,
474
462
  sequence: sequence++,
475
463
  timestamp: (effectiveClock?.now() ?? new Date()).toISOString(),
476
464
  };
@@ -478,7 +466,7 @@ export class DefaultExecutionService {
478
466
  };
479
467
  const progressReporter = {
480
468
  report(current, total, message) {
481
- options.progress?.report(current, total, message);
469
+ context.progress?.report(current, total, message);
482
470
  emitEvent({
483
471
  type: "progress",
484
472
  current,
@@ -487,47 +475,21 @@ export class DefaultExecutionService {
487
475
  });
488
476
  },
489
477
  };
478
+ const mkLevelLogger = (level) => (message, data) => {
479
+ this.logger?.[level](message, data);
480
+ context.logger?.[level](message, data);
481
+ emitEvent({
482
+ type: "log",
483
+ level,
484
+ message,
485
+ data: data,
486
+ });
487
+ };
490
488
  const executionLogger = {
491
- debug: (message, data) => {
492
- this.logger?.debug(message, data);
493
- options.logger?.debug(message, data);
494
- emitEvent({
495
- type: "log",
496
- level: "debug",
497
- message,
498
- data: data,
499
- });
500
- },
501
- info: (message, data) => {
502
- this.logger?.info(message, data);
503
- options.logger?.info(message, data);
504
- emitEvent({
505
- type: "log",
506
- level: "info",
507
- message,
508
- data: data,
509
- });
510
- },
511
- warn: (message, data) => {
512
- this.logger?.warn(message, data);
513
- options.logger?.warn(message, data);
514
- emitEvent({
515
- type: "log",
516
- level: "warn",
517
- message,
518
- data: data,
519
- });
520
- },
521
- error: (message, data) => {
522
- this.logger?.error(message, data);
523
- options.logger?.error(message, data);
524
- emitEvent({
525
- type: "log",
526
- level: "error",
527
- message,
528
- data: data,
529
- });
530
- },
489
+ debug: mkLevelLogger("debug"),
490
+ info: mkLevelLogger("info"),
491
+ warn: mkLevelLogger("warn"),
492
+ error: mkLevelLogger("error"),
531
493
  };
532
494
  return { emitEvent, progressReporter, executionLogger };
533
495
  }
@@ -566,26 +528,7 @@ export class DefaultExecutionService {
566
528
  });
567
529
  }
568
530
  async get(runId) {
569
- const record = this.storage.getRun(runId);
570
- if (record)
571
- return record;
572
- // 检查所有已解析的目标包 Runner 存储
573
- const visited = new Set([this._runner]);
574
- const queue = [this._runner];
575
- while (queue.length > 0) {
576
- const runner = queue.shift();
577
- for (const [_, childRunner] of runner.getPackageRunners()) {
578
- if (!visited.has(childRunner)) {
579
- visited.add(childRunner);
580
- queue.push(childRunner);
581
- const childRecord = childRunner.getStorage().getRun(runId);
582
- if (childRecord) {
583
- return childRecord;
584
- }
585
- }
586
- }
587
- }
588
- return undefined;
531
+ return this.storage.getRun(runId) ?? undefined;
589
532
  }
590
533
  async cancel(runId, reason) {
591
534
  const active = this.activeRuns.get(runId);
@@ -631,19 +574,7 @@ export class DefaultExecutionService {
631
574
  }
632
575
  }
633
576
  this.activeRuns.clear();
634
- // 级联释放跨包子包 Runner 及其独立创建的存储连接(幂等,异常不阻断后续释放)
635
- try {
636
- await this._runner.dispose();
637
- }
638
- catch {
639
- // 子包释放异常已在 dispose 内部隔离,此处仅需保障主流程继续
640
- }
641
- if (this.ownsStorage && this.storage && typeof this.storage.close === "function") {
642
- await this.storage.close();
643
- }
644
- if (this.ownsGlobalStorage && this.globalStorage && typeof this.globalStorage.close === "function") {
645
- await this.globalStorage.close();
646
- }
577
+ await this._runner.dispose();
647
578
  }
648
579
  }
649
580
  export { DefaultExecutionService as ExecutionService };