@actiondock/core 2.7.0 → 2.9.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.
- package/README.md +77 -64
- package/dist/catalog/action-catalog.d.ts +56 -0
- package/dist/catalog/action-catalog.js +202 -0
- package/dist/catalog/discovery.d.ts +60 -0
- package/dist/catalog/discovery.js +119 -0
- package/dist/catalog/graph.d.ts +190 -0
- package/dist/catalog/graph.js +589 -0
- package/dist/catalog/index.d.ts +5 -5
- package/dist/catalog/index.js +5 -5
- package/dist/catalog/resolve-action.d.ts +43 -0
- package/dist/catalog/resolve-action.js +119 -0
- package/dist/catalog/resolve-playbook.d.ts +26 -0
- package/dist/catalog/resolve-playbook.js +114 -0
- package/dist/doctor/checks/project.js +27 -8
- package/dist/doctor/checks/registry.js +2 -2
- package/dist/doctor/checks/runtime.js +34 -1
- package/dist/errors.d.ts +106 -10
- package/dist/errors.js +105 -10
- package/dist/execution/service.d.ts +18 -16
- package/dist/execution/service.js +183 -252
- package/dist/execution/types.d.ts +25 -69
- package/dist/execution/types.js +2 -1
- package/dist/filter/intent.d.ts +8 -9
- package/dist/filter/intent.js +49 -10
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.js +4 -0
- package/dist/host/host.d.ts +74 -32
- package/dist/host/host.js +585 -336
- package/dist/host/routing.d.ts +15 -48
- package/dist/host/routing.js +90 -153
- package/dist/host/types.d.ts +50 -17
- package/dist/index.d.ts +21 -24
- package/dist/index.js +19 -23
- package/dist/input/advice.d.ts +5 -1
- package/dist/input/advice.js +163 -214
- package/dist/input/describe.d.ts +1 -1
- package/dist/input/flat-errors.d.ts +5 -6
- package/dist/input/flat-errors.js +6 -6
- package/dist/input/flat-materializer.js +42 -44
- package/dist/invocation/index.d.ts +2 -0
- package/dist/invocation/index.js +2 -0
- package/dist/invocation/policy.d.ts +157 -0
- package/dist/invocation/policy.js +231 -0
- package/dist/invocation/types.d.ts +172 -0
- package/dist/invocation/types.js +97 -0
- package/dist/ipc/diagnostic.d.ts +0 -12
- package/dist/ipc/diagnostic.js +0 -21
- package/dist/ipc/host.d.ts +4 -4
- package/dist/ipc/host.js +44 -47
- package/dist/ipc/index.d.ts +1 -1
- package/dist/ipc/index.js +1 -1
- package/dist/ipc/service.d.ts +40 -0
- package/dist/ipc/service.js +349 -0
- package/dist/ipc/types.d.ts +21 -15
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/module-loader.d.ts +63 -0
- package/dist/node/module-loader.js +112 -0
- package/dist/package/index.d.ts +23 -0
- package/dist/package/index.js +18 -0
- package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
- package/dist/{app/app.js → package/runtime.js} +140 -95
- package/dist/{app → package}/static-index.js +58 -41
- package/dist/package/storage-view.d.ts +13 -0
- package/dist/package/storage-view.js +22 -0
- package/dist/{app → package}/types.d.ts +76 -57
- package/dist/package/types.js +22 -0
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +1 -1
- package/dist/platform/node.d.ts +48 -0
- package/dist/platform/node.js +96 -0
- package/dist/platform/types.d.ts +0 -9
- package/dist/process/control-arbiter.d.ts +2 -1
- package/dist/process/control-arbiter.js +1 -2
- package/dist/process/driver.d.ts +9 -8
- package/dist/process/driver.js +11 -22
- package/dist/process/index.d.ts +2 -0
- package/dist/process/index.js +2 -0
- package/dist/process/managed-record.d.ts +2 -2
- package/dist/process/process-driver.d.ts +109 -0
- package/dist/process/process-driver.js +650 -0
- package/dist/process/process-executor.d.ts +47 -0
- package/dist/process/process-executor.js +296 -0
- package/dist/process/process-manager.js +48 -26
- package/dist/process/run-executor.js +12 -12
- package/dist/profile/client-actions.js +2 -2
- package/dist/profile/client-health.js +2 -2
- package/dist/profile/client-query.js +5 -6
- package/dist/profile/client-transport.d.ts +19 -17
- package/dist/profile/client-transport.js +47 -80
- package/dist/profile/client.d.ts +2 -2
- package/dist/profile/client.js +1 -1
- package/dist/profile/index.d.ts +1 -0
- package/dist/profile/index.js +1 -0
- package/dist/profile/manager.d.ts +5 -0
- package/dist/profile/manager.js +41 -6
- package/dist/project/closure.js +2 -2
- package/dist/project/index.d.ts +8 -1
- package/dist/project/index.js +10 -1
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +1 -1
- package/dist/project/loader.js +26 -29
- package/dist/project/transactions.js +5 -10
- package/dist/project/types.d.ts +5 -0
- package/dist/registry/index.d.ts +3 -1
- package/dist/registry/index.js +2 -1
- package/dist/registry/lock.d.ts +28 -7
- package/dist/registry/lock.js +136 -16
- package/dist/registry/registry.d.ts +1 -5
- package/dist/registry/registry.js +1 -53
- package/dist/registry/scan.d.ts +0 -15
- package/dist/registry/scan.js +0 -59
- package/dist/registry/store.d.ts +42 -0
- package/dist/registry/store.js +43 -0
- package/dist/registry/types.d.ts +0 -24
- package/dist/runtime/action-collection.d.ts +1 -1
- package/dist/runtime/action-registry.d.ts +0 -4
- package/dist/runtime/action-registry.js +0 -7
- package/dist/runtime/context.js +5 -11
- package/dist/runtime/events.js +3 -6
- package/dist/runtime/identity.d.ts +22 -0
- package/dist/runtime/identity.js +10 -0
- package/dist/runtime/index.d.ts +1 -2
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/module-loader.d.ts +2 -34
- package/dist/runtime/module-loader.js +1 -16
- package/dist/runtime/process.d.ts +6 -24
- package/dist/runtime/process.js +1 -118
- package/dist/runtime/run-persistence.js +2 -5
- package/dist/runtime/runner.d.ts +33 -93
- package/dist/runtime/runner.js +132 -364
- package/dist/runtime/standalone.d.ts +23 -8
- package/dist/runtime/standalone.js +100 -147
- package/dist/server/body.d.ts +16 -8
- package/dist/server/body.js +33 -16
- package/dist/server/dispatcher.d.ts +6 -10
- package/dist/server/dispatcher.js +24 -32
- package/dist/server/http-server.d.ts +87 -0
- package/dist/server/http-server.js +304 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.js +11 -0
- package/dist/server/mcp-endpoint.d.ts +61 -0
- package/dist/server/mcp-endpoint.js +118 -0
- package/dist/server/policy.d.ts +138 -0
- package/dist/server/policy.js +368 -0
- package/dist/server/routes/actions.js +114 -64
- package/dist/server/routes/common.d.ts +18 -33
- package/dist/server/routes/common.js +45 -65
- package/dist/server/routes/config.d.ts +1 -1
- package/dist/server/routes/config.js +55 -65
- package/dist/server/routes/doctor.d.ts +1 -1
- package/dist/server/routes/doctor.js +13 -21
- package/dist/server/routes/health.d.ts +1 -1
- package/dist/server/routes/health.js +4 -5
- package/dist/server/routes/info.d.ts +2 -2
- package/dist/server/routes/info.js +17 -24
- package/dist/server/routes/playbooks.js +23 -36
- package/dist/server/routes/runs.js +151 -141
- package/dist/server/routes/state.d.ts +1 -1
- package/dist/server/routes/state.js +64 -63
- package/dist/server/security.d.ts +11 -0
- package/dist/server/security.js +36 -19
- package/dist/server/server.d.ts +2 -2
- package/dist/server/server.js +224 -238
- package/dist/server/types.d.ts +68 -21
- package/dist/service/factory.d.ts +12 -0
- package/dist/service/factory.js +85 -0
- package/dist/{target → service}/index.d.ts +1 -1
- package/dist/{target → service}/index.js +1 -1
- package/dist/service/local.d.ts +27 -0
- package/dist/service/local.js +138 -0
- package/dist/{target → service}/remote-errors.d.ts +3 -6
- package/dist/service/remote-errors.js +38 -0
- package/dist/{target → service}/remote-polling.d.ts +2 -2
- package/dist/{target → service}/remote-polling.js +8 -8
- package/dist/service/remote.d.ts +34 -0
- package/dist/service/remote.js +634 -0
- package/dist/service/sse-stream.d.ts +24 -0
- package/dist/service/sse-stream.js +139 -0
- package/dist/service/types.d.ts +272 -0
- package/dist/service/types.js +32 -0
- package/dist/storage/data-dir-lock.js +10 -5
- package/dist/storage/driver.d.ts +2 -1
- package/dist/storage/driver.js +3 -52
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/lock-core.d.ts +2 -6
- package/dist/storage/lock-core.js +4 -17
- package/dist/storage/params.d.ts +2 -8
- package/dist/storage/params.js +2 -8
- package/dist/storage/sqlite-driver.d.ts +40 -0
- package/dist/storage/sqlite-driver.js +116 -0
- package/dist/storage/sqlite.js +21 -6
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.js +2 -2
- package/dist/utils/index.d.ts +53 -0
- package/dist/utils/index.js +99 -4
- package/dist/utils/process.d.ts +10 -0
- package/dist/utils/process.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +41 -3
- package/dist/app/index.d.ts +0 -2
- package/dist/app/index.js +0 -2
- package/dist/app/types.js +0 -1
- package/dist/catalog/action-index.d.ts +0 -9
- package/dist/catalog/action-index.js +0 -95
- package/dist/catalog/action-resolver.d.ts +0 -20
- package/dist/catalog/action-resolver.js +0 -95
- package/dist/catalog/location-registry.d.ts +0 -15
- package/dist/catalog/location-registry.js +0 -138
- package/dist/catalog/package-catalog.d.ts +0 -7
- package/dist/catalog/package-catalog.js +0 -77
- package/dist/catalog/types.d.ts +0 -68
- package/dist/catalog/types.js +0 -1
- package/dist/export/index.d.ts +0 -1
- package/dist/export/index.js +0 -1
- package/dist/export/templates.d.ts +0 -71
- package/dist/export/templates.js +0 -635
- package/dist/ipc/target.d.ts +0 -74
- package/dist/ipc/target.js +0 -365
- package/dist/platform/default.d.ts +0 -38
- package/dist/platform/default.js +0 -78
- package/dist/project/resolver.d.ts +0 -116
- package/dist/project/resolver.js +0 -376
- package/dist/registry/resolve.d.ts +0 -62
- package/dist/registry/resolve.js +0 -195
- package/dist/runtime/execution-manager.d.ts +0 -48
- package/dist/runtime/execution-manager.js +0 -66
- package/dist/runtime/package-runner-factory.d.ts +0 -82
- package/dist/runtime/package-runner-factory.js +0 -186
- package/dist/target/local.d.ts +0 -53
- package/dist/target/local.js +0 -349
- package/dist/target/remote-errors.js +0 -51
- package/dist/target/remote.d.ts +0 -86
- package/dist/target/remote.js +0 -818
- package/dist/target/target.d.ts +0 -6
- package/dist/target/target.js +0 -37
- package/dist/target/types.d.ts +0 -261
- package/dist/target/types.js +0 -35
- /package/dist/{app → package}/static-index.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.js +0 -0
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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.
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
|
|
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
|
-
|
|
124
|
-
this.
|
|
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,
|
|
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 =
|
|
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 =
|
|
137
|
+
const effectiveClock = this.clock;
|
|
183
138
|
// requestId 幂等检查与去重处理
|
|
184
|
-
const gateResult = await this.checkIdempotencyGate(input,
|
|
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
|
-
|
|
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 (
|
|
209
|
-
if (
|
|
210
|
-
controller.abort(
|
|
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(
|
|
214
|
-
|
|
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,
|
|
219
|
-
|
|
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:
|
|
223
|
-
parentRunId:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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:
|
|
184
|
+
timeoutMs: context.timeoutMs,
|
|
229
185
|
progress: bridge.progressReporter,
|
|
230
186
|
logger: bridge.executionLogger,
|
|
231
|
-
process:
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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:
|
|
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,
|
|
267
|
-
if (!
|
|
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:
|
|
273
|
-
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:
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
* 解析执行目标:确定目标
|
|
295
|
+
* 解析执行目标:确定目标 Action 定义。
|
|
296
|
+
* 铁律 4:Runner 不找 Package,ExecutionService 仅执行本 Package 的 Action。
|
|
341
297
|
*/
|
|
342
298
|
async resolveExecutionTarget(parsedRef, targetPackageId, targetActionId) {
|
|
343
|
-
|
|
299
|
+
const runnerToUse = this._runner;
|
|
344
300
|
let resolveError;
|
|
345
301
|
if (targetPackageId && targetPackageId !== this.packageId) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
*
|
|
371
|
+
* 解析指定 Action 定义(供 PackageRuntime 或内部使用)。
|
|
391
372
|
*/
|
|
392
|
-
|
|
393
|
-
|
|
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,
|
|
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 =
|
|
397
|
+
const rootRunId = context.rootRunId || context.parentRunId || runId;
|
|
407
398
|
const initialRun = {
|
|
408
399
|
id: runId,
|
|
409
400
|
rootRunId,
|
|
410
|
-
parentRunId:
|
|
401
|
+
parentRunId: context.parentRunId,
|
|
411
402
|
packageId: targetPackageId,
|
|
412
|
-
packageInstanceId:
|
|
403
|
+
packageInstanceId: context.package.instanceId || target.runner.packageInstanceId,
|
|
413
404
|
actionId: targetActionId,
|
|
414
|
-
generationId:
|
|
405
|
+
generationId: context.package.generation || target.runner.generationId,
|
|
415
406
|
ownerId: this.ownerId,
|
|
416
|
-
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
|
-
|
|
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,
|
|
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:
|
|
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
|
-
|
|
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: (
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|