@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.
- package/README.md +1 -2
- package/dist/catalog/action-catalog.js +3 -33
- package/dist/catalog/discovery.d.ts +0 -3
- package/dist/catalog/discovery.js +4 -4
- package/dist/catalog/graph.d.ts +0 -4
- package/dist/catalog/graph.js +8 -14
- package/dist/{profile/client-actions.d.ts → client/actions.d.ts} +1 -1
- package/dist/{profile/client-actions.js → client/actions.js} +2 -8
- package/dist/{profile/client-config.d.ts → client/config.d.ts} +1 -1
- package/dist/{profile/client-config.js → client/config.js} +1 -1
- package/dist/client/dispatcher.d.ts +4 -0
- package/dist/client/dispatcher.js +21 -0
- package/dist/client/health.d.ts +38 -0
- package/dist/{profile/client-health.js → client/health.js} +9 -6
- package/dist/client/index.d.ts +16 -0
- package/dist/client/index.js +20 -0
- package/dist/{profile/client-playbooks.d.ts → client/playbooks.d.ts} +1 -1
- package/dist/{profile/client-playbooks.js → client/playbooks.js} +1 -1
- package/dist/{profile/client-runs.d.ts → client/runs.d.ts} +4 -2
- package/dist/{profile/client-runs.js → client/runs.js} +7 -1
- package/dist/{profile/client-state.d.ts → client/state.d.ts} +1 -1
- package/dist/{profile/client-state.js → client/state.js} +1 -1
- package/dist/{profile/client-transport.d.ts → client/transport.d.ts} +29 -10
- package/dist/{profile/client-transport.js → client/transport.js} +125 -35
- package/dist/doctor/checks/index.d.ts +1 -1
- package/dist/doctor/checks/index.js +1 -1
- package/dist/doctor/checks/project.js +20 -88
- package/dist/doctor/checks/runtime.d.ts +0 -4
- package/dist/doctor/checks/runtime.js +0 -28
- package/dist/doctor/doctor.js +1 -2
- package/dist/errors.d.ts +53 -3
- package/dist/errors.js +53 -3
- package/dist/execution/service.d.ts +55 -37
- package/dist/execution/service.js +601 -212
- package/dist/execution/types.d.ts +24 -5
- package/dist/host/host.d.ts +42 -22
- package/dist/host/host.js +562 -149
- package/dist/host/routing.js +6 -6
- package/dist/host/types.d.ts +25 -13
- package/dist/index.d.ts +9 -4
- package/dist/index.js +5 -2
- package/dist/input/advice.d.ts +0 -44
- package/dist/input/advice.js +7 -141
- package/dist/input/flat-materializer.js +1 -1
- package/dist/input/flat-parser.js +1 -1
- package/dist/input/index.d.ts +0 -1
- package/dist/input/index.js +0 -1
- package/dist/input/input-resolver.js +1 -1
- package/dist/input/validation-mapper.d.ts +1 -1
- package/dist/ipc/diagnostic.d.ts +8 -21
- package/dist/ipc/diagnostic.js +24 -57
- package/dist/ipc/host.js +21 -7
- package/dist/ipc/service.d.ts +14 -0
- package/dist/ipc/service.js +132 -26
- package/dist/ipc/types.d.ts +0 -4
- package/dist/package/index.d.ts +4 -5
- package/dist/package/index.js +1 -2
- package/dist/package/runtime.d.ts +94 -23
- package/dist/package/runtime.js +628 -274
- package/dist/package/static-index.d.ts +3 -6
- package/dist/package/static-index.js +11 -40
- package/dist/package/types.d.ts +19 -4
- package/dist/platform/index.d.ts +2 -1
- package/dist/platform/index.js +2 -1
- package/dist/platform/loader-hook.d.ts +32 -0
- package/dist/platform/loader-hook.js +90 -0
- package/dist/{node → platform}/module-loader.d.ts +13 -0
- package/dist/{node → platform}/module-loader.js +51 -4
- package/dist/platform/node.d.ts +19 -8
- package/dist/platform/node.js +50 -20
- package/dist/platform/types.d.ts +7 -47
- package/dist/process/context-process.d.ts +3 -18
- package/dist/process/context-process.js +3 -44
- package/dist/process/control.d.ts +21 -0
- package/dist/process/control.js +34 -0
- package/dist/process/converters.d.ts +23 -0
- package/dist/process/converters.js +92 -0
- package/dist/process/cursor.js +2 -22
- package/dist/process/{diagnostics-sink.d.ts → diagnostics.d.ts} +0 -7
- package/dist/process/{diagnostics-sink.js → diagnostics.js} +6 -8
- package/dist/process/index.d.ts +1 -3
- package/dist/process/index.js +1 -3
- package/dist/process/input-dispatcher.d.ts +4 -13
- package/dist/process/input-dispatcher.js +48 -69
- package/dist/process/managed-record.d.ts +3 -31
- package/dist/process/metadata-store.d.ts +0 -41
- package/dist/process/metadata-store.js +2 -341
- package/dist/process/process-driver.js +2 -2
- package/dist/process/process-manager.d.ts +8 -50
- package/dist/process/process-manager.js +28 -417
- package/dist/process/quotas.d.ts +14 -0
- package/dist/process/quotas.js +29 -0
- package/dist/process/run-executor.js +0 -1
- package/dist/process/terminal-output-cache.d.ts +20 -34
- package/dist/process/terminal-output-cache.js +43 -64
- package/dist/profile/index.d.ts +1 -2
- package/dist/profile/index.js +1 -2
- package/dist/profile/manager.d.ts +2 -4
- package/dist/profile/manager.js +10 -40
- package/dist/profile/types.d.ts +1 -17
- package/dist/project/digest.d.ts +5 -1
- package/dist/project/digest.js +81 -219
- package/dist/project/index.d.ts +4 -5
- package/dist/project/index.js +4 -5
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +3 -3
- package/dist/project/loader.js +72 -50
- package/dist/project/lockfile.js +6 -5
- package/dist/project/manifest.js +5 -4
- package/dist/project/transactions.d.ts +4 -42
- package/dist/project/transactions.js +83 -138
- package/dist/project/types-generator.js +2 -1
- package/dist/project/types.d.ts +2 -0
- package/dist/registry/index.d.ts +0 -1
- package/dist/registry/index.js +0 -1
- package/dist/registry/lock.d.ts +2 -11
- package/dist/registry/lock.js +14 -183
- package/dist/registry/registry.d.ts +1 -6
- package/dist/registry/registry.js +5 -17
- package/dist/runtime/action-registry.d.ts +1 -5
- package/dist/runtime/action-registry.js +0 -12
- package/dist/runtime/context.js +2 -2
- package/dist/runtime/events.d.ts +11 -50
- package/dist/runtime/events.js +88 -368
- package/dist/runtime/index.d.ts +0 -4
- package/dist/runtime/index.js +0 -4
- package/dist/runtime/run-persistence.d.ts +2 -0
- package/dist/runtime/run-persistence.js +2 -1
- package/dist/runtime/standalone-commands.d.ts +18 -0
- package/dist/runtime/standalone-commands.js +466 -0
- package/dist/runtime/standalone-help.d.ts +20 -0
- package/dist/runtime/standalone-help.js +72 -0
- package/dist/runtime/standalone.d.ts +1 -44
- package/dist/runtime/standalone.js +32 -573
- package/dist/schema/validator.d.ts +2 -2
- package/dist/schema/validator.js +2 -9
- package/dist/server/index.d.ts +0 -2
- package/dist/server/index.js +0 -2
- package/dist/server/routes/actions.js +1 -1
- package/dist/server/routes/info.js +1 -1
- package/dist/server/routes/playbooks.js +1 -1
- package/dist/server/routes/runs.js +123 -16
- package/dist/server/routes/state.js +43 -18
- package/dist/server/security.d.ts +1 -1
- package/dist/server/security.js +2 -2
- package/dist/server/server.js +3 -7
- package/dist/service/factory.js +4 -3
- package/dist/service/index.d.ts +1 -1
- package/dist/service/index.js +1 -1
- package/dist/service/remote-errors.d.ts +1 -1
- package/dist/service/remote-errors.js +6 -6
- package/dist/service/remote-polling.d.ts +3 -0
- package/dist/service/remote-polling.js +10 -5
- package/dist/service/remote.d.ts +5 -1
- package/dist/service/remote.js +108 -17
- package/dist/service/sse-stream.js +2 -2
- package/dist/service/types.d.ts +22 -19
- package/dist/service/types.js +1 -24
- package/dist/storage/clock.d.ts +1 -1
- package/dist/storage/clock.js +1 -1
- package/dist/storage/data-dir-lock.d.ts +10 -22
- package/dist/storage/data-dir-lock.js +28 -56
- package/dist/storage/file-lock.d.ts +64 -0
- package/dist/storage/file-lock.js +447 -0
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +5 -4
- package/dist/storage/run-liveness.d.ts +48 -0
- package/dist/storage/run-liveness.js +44 -0
- package/dist/storage/sqlite-config.d.ts +16 -0
- package/dist/storage/sqlite-config.js +59 -0
- package/dist/storage/sqlite-driver.d.ts +3 -1
- package/dist/storage/sqlite-driver.js +14 -4
- package/dist/storage/sqlite-events.d.ts +13 -0
- package/dist/storage/sqlite-events.js +48 -0
- package/dist/storage/sqlite-runs.d.ts +107 -0
- package/dist/storage/sqlite-runs.js +622 -0
- package/dist/storage/sqlite-schema.d.ts +5 -0
- package/dist/storage/sqlite-schema.js +143 -0
- package/dist/storage/sqlite-state.d.ts +33 -0
- package/dist/storage/sqlite-state.js +270 -0
- package/dist/storage/sqlite.d.ts +30 -57
- package/dist/storage/sqlite.js +84 -741
- package/dist/storage/types.d.ts +35 -2
- package/dist/utils/index.d.ts +18 -14
- package/dist/utils/index.js +37 -29
- package/dist/utils/semver.d.ts +18 -0
- package/dist/utils/semver.js +19 -0
- package/dist/utils/warning.d.ts +1 -0
- package/dist/utils/warning.js +52 -0
- package/dist/{json/value-validator.d.ts → value-validator.d.ts} +9 -0
- package/dist/value-validator.js +330 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +10 -12
- package/dist/execution/index.d.ts +0 -2
- package/dist/execution/index.js +0 -2
- package/dist/filter/index.d.ts +0 -1
- package/dist/filter/index.js +0 -1
- package/dist/graph/index.d.ts +0 -4
- package/dist/graph/index.js +0 -4
- package/dist/input/metadata.d.ts +0 -99
- package/dist/input/metadata.js +0 -99
- package/dist/invocation/index.d.ts +0 -2
- package/dist/invocation/index.js +0 -2
- package/dist/ipc/index.d.ts +0 -4
- package/dist/ipc/index.js +0 -4
- package/dist/json/index.d.ts +0 -1
- package/dist/json/index.js +0 -1
- package/dist/json/value-validator.js +0 -330
- package/dist/node/index.d.ts +0 -1
- package/dist/node/index.js +0 -1
- package/dist/platform/node-fs.d.ts +0 -37
- package/dist/platform/node-fs.js +0 -81
- package/dist/process/control-arbiter.d.ts +0 -108
- package/dist/process/control-arbiter.js +0 -250
- package/dist/process/process-executor.d.ts +0 -47
- package/dist/process/process-executor.js +0 -296
- package/dist/profile/client-health.d.ts +0 -14
- package/dist/profile/client-query.d.ts +0 -30
- package/dist/profile/client-query.js +0 -69
- package/dist/profile/client.d.ts +0 -26
- package/dist/profile/client.js +0 -31
- package/dist/project/closure.d.ts +0 -25
- package/dist/project/closure.js +0 -74
- package/dist/registry/store.d.ts +0 -42
- package/dist/registry/store.js +0 -43
- package/dist/runtime/clock.d.ts +0 -7
- package/dist/runtime/clock.js +0 -7
- package/dist/runtime/module-loader.d.ts +0 -2
- package/dist/runtime/module-loader.js +0 -1
- package/dist/runtime/process.d.ts +0 -8
- package/dist/runtime/process.js +0 -1
- package/dist/runtime/runner.d.ts +0 -234
- package/dist/runtime/runner.js +0 -609
- package/dist/schema/index.d.ts +0 -1
- package/dist/schema/index.js +0 -1
- package/dist/server/dispatcher.d.ts +0 -25
- package/dist/server/dispatcher.js +0 -54
- package/dist/service/local.d.ts +0 -27
- package/dist/service/local.js +0 -141
- package/dist/storage/driver.d.ts +0 -10
- package/dist/storage/driver.js +0 -10
- package/dist/storage/lazy.d.ts +0 -8
- package/dist/storage/lazy.js +0 -45
- package/dist/storage/lock-core.d.ts +0 -158
- package/dist/storage/lock-core.js +0 -872
- package/dist/utils/net.d.ts +0 -10
- package/dist/utils/net.js +0 -16
- package/dist/utils/process.d.ts +0 -10
- package/dist/utils/process.js +0 -21
- /package/dist/{filter → utils}/intent.d.ts +0 -0
- /package/dist/{filter → utils}/intent.js +0 -0
package/dist/host/host.js
CHANGED
|
@@ -7,15 +7,16 @@ import { findProjectRoot, loadProjectConfig } from "../project/loader.js";
|
|
|
7
7
|
import { hasPendingTransactions, isProjectLockHeld, recoverPendingTransactions } from "../project/transactions.js";
|
|
8
8
|
import { listLinkedPackages } from "../registry/registry.js";
|
|
9
9
|
import { InMemoryEventSink } from "../runtime/events.js";
|
|
10
|
-
import { ActionDockError, ACTION_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_SUBRUN_LIMIT, INVALID_ACTION_REF, PACKAGE_NOT_FOUND, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, UNDECLARED_ACTION_DEPENDENCY, } from "../errors.js";
|
|
10
|
+
import { ActionDockError, ACTION_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_SUBRUN_LIMIT, EXECUTION_FAILED, INVALID_ACTION_REF, PACKAGE_ID_CONFLICT, PACKAGE_NOT_FOUND, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, SERVICE_CLOSED, UNDECLARED_ACTION_DEPENDENCY, } from "../errors.js";
|
|
11
11
|
import { InvocationPolicy } from "../invocation/policy.js";
|
|
12
|
+
import { createAbortError } from "../ipc/service.js";
|
|
12
13
|
import { DataDirLock } from "../storage/data-dir-lock.js";
|
|
13
14
|
import { DefaultActionCatalog, DefaultPackageGraph, PackageGraphBuilder, resolveAction, } from "../catalog/index.js";
|
|
15
|
+
import { parseActionRef } from "../catalog/resolve-action.js";
|
|
14
16
|
import { buildRuntimeError, collectPackageInfos, describeActionAcrossRuntimes, describeVisiblePlaybook, isRootCallVisible, listVisiblePlaybooks, packageNotFoundMessage, parseRefLoose, resolveProjectRoot, } from "./routing.js";
|
|
15
|
-
import { ServiceError } from "../service/types.js";
|
|
16
17
|
import { CAPABILITY_UNAVAILABLE } from "../errors.js";
|
|
17
18
|
import { createGlobalStorage, isSecretConfigKey } from "../storage/index.js";
|
|
18
|
-
import { filterByIntent } from "../
|
|
19
|
+
import { filterByIntent } from "../utils/intent.js";
|
|
19
20
|
function isPackageRuntime(item) {
|
|
20
21
|
return (typeof item === "object" &&
|
|
21
22
|
item !== null &&
|
|
@@ -24,6 +25,36 @@ function isPackageRuntime(item) {
|
|
|
24
25
|
"runAction" in item &&
|
|
25
26
|
typeof item.runAction === "function");
|
|
26
27
|
}
|
|
28
|
+
/** 并发解析运行记录归属包(公共端口查询,不新建执行服务) */
|
|
29
|
+
async function findRunOwnerRuntime(runtimes, runId) {
|
|
30
|
+
const results = await Promise.all(runtimes.map(async (rt) => ({ rt, record: await rt.getRun(runId).catch(() => undefined) })));
|
|
31
|
+
return results.find((r) => r.record !== undefined)?.rt;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 包装异步操作以响应 AbortSignal 取消信号。
|
|
35
|
+
* 若信号已中止立即抛出 AbortError,否则挂载一次性中止监听并在操作完成时注销。
|
|
36
|
+
*/
|
|
37
|
+
function withAbortSignal(op, signal) {
|
|
38
|
+
if (signal?.aborted) {
|
|
39
|
+
throw createAbortError(signal.reason);
|
|
40
|
+
}
|
|
41
|
+
if (!signal) {
|
|
42
|
+
return op();
|
|
43
|
+
}
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const onAbort = () => {
|
|
46
|
+
reject(createAbortError(signal.reason));
|
|
47
|
+
};
|
|
48
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
49
|
+
op().then((res) => {
|
|
50
|
+
signal.removeEventListener("abort", onAbort);
|
|
51
|
+
resolve(res);
|
|
52
|
+
}, (err) => {
|
|
53
|
+
signal.removeEventListener("abort", onAbort);
|
|
54
|
+
reject(err);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
27
58
|
export class DefaultActionDockHost {
|
|
28
59
|
hostSessionId;
|
|
29
60
|
options;
|
|
@@ -42,7 +73,30 @@ export class DefaultActionDockHost {
|
|
|
42
73
|
graph;
|
|
43
74
|
catalog;
|
|
44
75
|
globalStorage;
|
|
76
|
+
initPromise;
|
|
77
|
+
isInitialized = false;
|
|
78
|
+
discovery;
|
|
79
|
+
execution;
|
|
80
|
+
runs;
|
|
81
|
+
events;
|
|
82
|
+
management;
|
|
83
|
+
/** 自引用 host 属性,向后兼容服务实例字段访问 */
|
|
84
|
+
get host() {
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* @deprecated 直接使用 new DefaultActionDockHost() 构造已弃用,请迁移至 createActionDockHost() 异步工厂函数以完成完整的生命周期初始化。
|
|
89
|
+
*/
|
|
45
90
|
constructor(options = {}, internalOptions) {
|
|
91
|
+
if (!internalOptions?.fromFactory) {
|
|
92
|
+
const warnMsg = "[Host] Direct instantiation via new DefaultActionDockHost() is @deprecated and only performs minimal object assembly. Use createActionDockHost() for full lifecycle initialization.";
|
|
93
|
+
if (options.logger?.warn) {
|
|
94
|
+
options.logger.warn(warnMsg);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
console.warn(warnMsg);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
46
100
|
this.hostSessionId = randomUUID();
|
|
47
101
|
this.options = options;
|
|
48
102
|
this.maxCallDepth = options.maxCallDepth ?? 16;
|
|
@@ -56,92 +110,254 @@ export class DefaultActionDockHost {
|
|
|
56
110
|
this.recoverOrphans = options.recoverOrphans !== false;
|
|
57
111
|
this.graph = new DefaultPackageGraph(new Map());
|
|
58
112
|
this.catalog = new DefaultActionCatalog(this.graph);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
113
|
+
const self = this;
|
|
114
|
+
this.discovery = {
|
|
115
|
+
async listPackages() {
|
|
116
|
+
await self.ensureInitialized();
|
|
117
|
+
return self.info();
|
|
118
|
+
},
|
|
119
|
+
async listActions(opts) {
|
|
120
|
+
await self.ensureInitialized();
|
|
121
|
+
return self.listActions(opts);
|
|
122
|
+
},
|
|
123
|
+
async describeAction(ref) {
|
|
124
|
+
await self.ensureInitialized();
|
|
125
|
+
return self.describeAction(ref);
|
|
126
|
+
},
|
|
127
|
+
async listPlaybooks(opts) {
|
|
128
|
+
await self.ensureInitialized();
|
|
129
|
+
return self.listPlaybooks(opts);
|
|
130
|
+
},
|
|
131
|
+
async describePlaybook(id) {
|
|
132
|
+
await self.ensureInitialized();
|
|
133
|
+
return self.describePlaybook(id);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
this.execution = {
|
|
137
|
+
async run(ref, input, opts) {
|
|
138
|
+
await self.ensureInitialized();
|
|
139
|
+
const actionRef = typeof ref === "string" ? parseActionRef(ref) : ref;
|
|
140
|
+
const cleanOpts = {
|
|
141
|
+
signal: opts?.signal,
|
|
142
|
+
timeoutMs: opts?.timeoutMs,
|
|
143
|
+
config: opts?.config,
|
|
144
|
+
requestId: opts?.requestId,
|
|
145
|
+
};
|
|
146
|
+
return self.runAction(actionRef, (input ?? {}), cleanOpts);
|
|
147
|
+
},
|
|
148
|
+
async start(ref, input, opts) {
|
|
149
|
+
await self.ensureInitialized();
|
|
150
|
+
const actionRef = typeof ref === "string" ? parseActionRef(ref) : ref;
|
|
151
|
+
const cleanOpts = {
|
|
152
|
+
signal: opts?.signal,
|
|
153
|
+
timeoutMs: opts?.timeoutMs,
|
|
154
|
+
config: opts?.config,
|
|
155
|
+
requestId: opts?.requestId,
|
|
156
|
+
};
|
|
157
|
+
return self.startAction(actionRef, (input ?? {}), cleanOpts);
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
this.runs = {
|
|
161
|
+
async list(query, options) {
|
|
162
|
+
await self.ensureInitialized();
|
|
163
|
+
const effectiveSignal = options?.signal ?? query?.signal;
|
|
164
|
+
return withAbortSignal(() => self.listRuns(query, effectiveSignal), effectiveSignal);
|
|
165
|
+
},
|
|
166
|
+
async count(query, options) {
|
|
167
|
+
await self.ensureInitialized();
|
|
168
|
+
const effectiveSignal = options?.signal ?? query?.signal;
|
|
169
|
+
return withAbortSignal(() => self.countRuns(query, effectiveSignal), effectiveSignal);
|
|
170
|
+
},
|
|
171
|
+
async get(runId, options) {
|
|
172
|
+
await self.ensureInitialized();
|
|
173
|
+
const effectiveSignal = options?.signal;
|
|
174
|
+
return withAbortSignal(() => self.getRun(runId, effectiveSignal), effectiveSignal);
|
|
175
|
+
},
|
|
176
|
+
async cancel(runId, reason) {
|
|
177
|
+
await self.ensureInitialized();
|
|
178
|
+
return self.cancelRun(runId, reason);
|
|
179
|
+
},
|
|
180
|
+
async clear(opts) {
|
|
181
|
+
await self.ensureInitialized();
|
|
182
|
+
return self.clearRuns(opts);
|
|
183
|
+
},
|
|
184
|
+
async cleanExpired(policy) {
|
|
185
|
+
await self.ensureInitialized();
|
|
186
|
+
return self.cleanExpiredRuns(policy);
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
const eventsFn = ((runId, opts) => {
|
|
190
|
+
return (async function* () {
|
|
191
|
+
await self.ensureInitialized();
|
|
192
|
+
yield* self.subscribeEvents(runId, opts);
|
|
193
|
+
})();
|
|
194
|
+
});
|
|
195
|
+
eventsFn.events = (runId, opts) => {
|
|
196
|
+
return (async function* () {
|
|
197
|
+
await self.ensureInitialized();
|
|
198
|
+
yield* self.subscribeEvents(runId, opts);
|
|
199
|
+
})();
|
|
200
|
+
};
|
|
201
|
+
this.events = eventsFn;
|
|
202
|
+
if (options.enableManagement !== false) {
|
|
203
|
+
this.management = {
|
|
204
|
+
config: {
|
|
205
|
+
async get(packageId, key) {
|
|
206
|
+
await self.ensureInitialized();
|
|
207
|
+
return self.getConfig(packageId, key);
|
|
208
|
+
},
|
|
209
|
+
async set(packageId, key, value) {
|
|
210
|
+
await self.ensureInitialized();
|
|
211
|
+
return self.setConfig(packageId, key, value);
|
|
212
|
+
},
|
|
213
|
+
async delete(packageId, key) {
|
|
214
|
+
await self.ensureInitialized();
|
|
215
|
+
return self.deleteConfig(packageId, key);
|
|
216
|
+
},
|
|
217
|
+
async list(packageId) {
|
|
218
|
+
await self.ensureInitialized();
|
|
219
|
+
return self.listConfig(packageId);
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
state: {
|
|
223
|
+
async get(packageId, actionId, key, opts) {
|
|
224
|
+
await self.ensureInitialized();
|
|
225
|
+
return self.getState(packageId, actionId, key, opts);
|
|
226
|
+
},
|
|
227
|
+
async set(packageId, actionId, key, value, opts) {
|
|
228
|
+
await self.ensureInitialized();
|
|
229
|
+
return self.setState(packageId, actionId, key, value, opts);
|
|
230
|
+
},
|
|
231
|
+
async delete(packageId, actionId, key, opts) {
|
|
232
|
+
await self.ensureInitialized();
|
|
233
|
+
return self.deleteState(packageId, actionId, key, opts);
|
|
234
|
+
},
|
|
235
|
+
async list(packageId, actionId, opts) {
|
|
236
|
+
await self.ensureInitialized();
|
|
237
|
+
return self.listStateKeys(packageId, actionId, opts);
|
|
238
|
+
},
|
|
239
|
+
async clear(packageId, actionId, opts) {
|
|
240
|
+
await self.ensureInitialized();
|
|
241
|
+
return self.clearState(packageId, actionId, opts);
|
|
242
|
+
},
|
|
243
|
+
async listEntries(packageId, opts) {
|
|
244
|
+
await self.ensureInitialized();
|
|
245
|
+
return self.listStateEntries(packageId, opts);
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
};
|
|
67
249
|
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* 静态工厂方法:创建并初始化 ActionDockHost 宿主容器。
|
|
253
|
+
*/
|
|
254
|
+
static async create(options = {}) {
|
|
255
|
+
let createdHost;
|
|
68
256
|
try {
|
|
69
|
-
|
|
257
|
+
createdHost = new DefaultActionDockHost(options, { fromFactory: true });
|
|
258
|
+
await createdHost.ensureInitialized();
|
|
259
|
+
return createdHost;
|
|
70
260
|
}
|
|
71
261
|
catch (err) {
|
|
72
|
-
|
|
262
|
+
if (createdHost) {
|
|
263
|
+
try {
|
|
264
|
+
await createdHost.rollbackInitialization();
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// 忽略宿主回滚异常,确保抛出原始异常
|
|
268
|
+
}
|
|
269
|
+
}
|
|
73
270
|
throw err;
|
|
74
271
|
}
|
|
75
272
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
273
|
+
/**
|
|
274
|
+
* 确保宿主容器已完成异步生命周期初始化。
|
|
275
|
+
* 当通过 ActionDockHost.create() / createActionDockHost() 创建时在工厂阶段预先就绪;
|
|
276
|
+
* 当直接通过 new DefaultActionDockHost() 构造时,在首次异步调用时惰性触发加载。
|
|
277
|
+
*/
|
|
278
|
+
async ensureInitialized() {
|
|
279
|
+
if (this.isInitialized) {
|
|
280
|
+
return;
|
|
82
281
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.registerLinkedPackages(this.options);
|
|
282
|
+
if (this.isClosed) {
|
|
283
|
+
throw new ActionDockError(SERVICE_CLOSED, "ActionDockHost is closed");
|
|
86
284
|
}
|
|
87
|
-
this.
|
|
285
|
+
if (!this.initPromise) {
|
|
286
|
+
this.initPromise = this.performInitialization();
|
|
287
|
+
}
|
|
288
|
+
await this.initPromise;
|
|
88
289
|
}
|
|
89
|
-
async
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
290
|
+
async performInitialization() {
|
|
291
|
+
try {
|
|
292
|
+
// 当指定非内存 dataDir 且以持有者身份打开时获取排他目录锁,防止并发冲突;
|
|
293
|
+
// 旁观 Host(recoverOrphans: false)不获取执行宿主的排他锁,也不创建数据目录
|
|
294
|
+
if (this.options.dataDir &&
|
|
295
|
+
!this.options.inMemory &&
|
|
296
|
+
this.recoverOrphans &&
|
|
297
|
+
!this.dataDirLock) {
|
|
298
|
+
this.dataDirLock = DataDirLock.acquire(this.options.dataDir, {
|
|
299
|
+
hostSessionId: this.hostSessionId,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
// 阶段一:注册显式传入的 packages 列表(仅建立身份与路由,不打开资源)
|
|
303
|
+
this.registerExplicitPackages(this.options);
|
|
304
|
+
// 阶段二:自动加载当前工程(若发现工程根目录且未显式禁用)
|
|
305
|
+
if (this.options.autoLoadCurrentProject !== false) {
|
|
306
|
+
await this.loadCurrentProject(this.options);
|
|
307
|
+
}
|
|
308
|
+
// 阶段三:扫描已软链接的外部包并注册至 Host(仅建立身份与路由)
|
|
309
|
+
if (this.options.scanLinkedPackages) {
|
|
310
|
+
this.registerLinkedPackages(this.options);
|
|
103
311
|
}
|
|
104
|
-
this.
|
|
312
|
+
this.rebuildGraphAndCatalog();
|
|
313
|
+
// 阶段四:持有者身份在工厂返回前显式预热全部内部包的存储与运行记录恢复;
|
|
314
|
+
// 旁观身份(recoverOrphans: false)跳过预热,首次持久化调用时才按需打开
|
|
315
|
+
if (this.recoverOrphans) {
|
|
316
|
+
await this.prewarmManagedRuntimes();
|
|
317
|
+
}
|
|
318
|
+
this.isInitialized = true;
|
|
105
319
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
320
|
+
catch (err) {
|
|
321
|
+
this.initPromise = undefined;
|
|
322
|
+
try {
|
|
323
|
+
await this.rollbackInitialization();
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// 吞没回滚自身的副错误以确保向上抛出原始的初始化异常
|
|
327
|
+
}
|
|
328
|
+
throw err;
|
|
109
329
|
}
|
|
110
|
-
this.rebuildGraphAndCatalog();
|
|
111
330
|
}
|
|
112
331
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* 异步语境下逐个 await 全部 runtime.close() 后再依次释放全局存储与目录锁。
|
|
332
|
+
* 持有者预热:等待内部创建的全部包完成存储准备(含运行记录恢复),
|
|
333
|
+
* 并打开共享全局存储。预热的是存储,不是执行服务、进程接口或业务模块;
|
|
334
|
+
* 任一包准备失败按既有初始化失败时机整体回滚。
|
|
335
|
+
* 外部注入的 Runtime 保持既有生命周期约定,不在此预热。
|
|
118
336
|
*/
|
|
119
|
-
async
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
const closePromise = runtime.close();
|
|
125
|
-
if (closePromise && typeof closePromise.catch === "function") {
|
|
126
|
-
closePromise.catch(() => { });
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
// 忽略 runtime 关闭异常
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
const allRuntimes = Array.from(this.runtimes.values());
|
|
136
|
-
await Promise.all(allRuntimes.map(async (runtime) => {
|
|
137
|
-
try {
|
|
138
|
-
await runtime.close();
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
// 忽略 Runtime 关闭异常
|
|
142
|
-
}
|
|
143
|
-
}));
|
|
337
|
+
async prewarmManagedRuntimes() {
|
|
338
|
+
const managed = Array.from(this.runtimes.values()).filter((rt) => rt instanceof DefaultPackageRuntime);
|
|
339
|
+
if (managed.length === 0) {
|
|
340
|
+
return;
|
|
144
341
|
}
|
|
342
|
+
await Promise.all(managed.map((rt) => rt.prepareResources()));
|
|
343
|
+
// 持有者在返回前打开共享全局存储,保留对全局库存储错误的提前发现能力
|
|
344
|
+
this.getGlobalStorage();
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* 异步安全回滚初始化失败时所占用的资源。
|
|
348
|
+
*/
|
|
349
|
+
async rollbackInitialization() {
|
|
350
|
+
this.isInitialized = false;
|
|
351
|
+
this.initPromise = undefined;
|
|
352
|
+
const allRuntimes = Array.from(this.runtimes.values());
|
|
353
|
+
await Promise.all(allRuntimes.map(async (runtime) => {
|
|
354
|
+
try {
|
|
355
|
+
await runtime.close();
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
// 忽略 Runtime 关闭异常
|
|
359
|
+
}
|
|
360
|
+
}));
|
|
145
361
|
this.runtimes.clear();
|
|
146
362
|
try {
|
|
147
363
|
this.globalStorage?.close();
|
|
@@ -159,15 +375,6 @@ export class DefaultActionDockHost {
|
|
|
159
375
|
this.dataDirLock = undefined;
|
|
160
376
|
this.isClosed = true;
|
|
161
377
|
}
|
|
162
|
-
/**
|
|
163
|
-
* 异步安全回滚初始化失败时所占用的资源。
|
|
164
|
-
*/
|
|
165
|
-
async rollbackInitialization() {
|
|
166
|
-
await this.rollbackResources(false);
|
|
167
|
-
}
|
|
168
|
-
rollbackSync() {
|
|
169
|
-
void this.rollbackResources(true);
|
|
170
|
-
}
|
|
171
378
|
/**
|
|
172
379
|
* 阶段函数:注册显式传入的 packages 列表(PackageRuntimeOptions 配置或包目录物理路径)。
|
|
173
380
|
*/
|
|
@@ -184,7 +391,8 @@ export class DefaultActionDockHost {
|
|
|
184
391
|
const runtime = new DefaultPackageRuntime({
|
|
185
392
|
...packageOptions,
|
|
186
393
|
hostSessionId: this.hostSessionId,
|
|
187
|
-
globalStorage: packageOptions.globalStorage
|
|
394
|
+
globalStorage: packageOptions.globalStorage,
|
|
395
|
+
globalStorageProvider: () => this.getGlobalStorage(),
|
|
188
396
|
platform: packageOptions.platform ?? options.platform,
|
|
189
397
|
inMemory: packageOptions.inMemory ?? options.inMemory,
|
|
190
398
|
customHome: packageOptions.customHome ?? options.customHome,
|
|
@@ -210,21 +418,22 @@ export class DefaultActionDockHost {
|
|
|
210
418
|
* - 自动探测场景(未传 projectRoot,由 findProjectRoot 发现)失败时记录实例诊断
|
|
211
419
|
* failedAutoLoad 并在创建时输出单行告警,保持宿主其余能力可用但绝不无声。
|
|
212
420
|
*/
|
|
213
|
-
loadCurrentProject(options) {
|
|
421
|
+
async loadCurrentProject(options) {
|
|
214
422
|
const explicitRoot = options.projectRoot;
|
|
215
423
|
const root = resolveProjectRoot(options, () => findProjectRoot());
|
|
216
424
|
if (!root) {
|
|
217
425
|
return;
|
|
218
426
|
}
|
|
219
427
|
if (isProjectLockHeld(root)) {
|
|
220
|
-
|
|
221
|
-
err.code = PROJECT_BUSY;
|
|
222
|
-
throw err;
|
|
428
|
+
throw new ActionDockError(PROJECT_BUSY, "PROJECT_BUSY: Project directory is locked by another active process holding project.lock");
|
|
223
429
|
}
|
|
224
430
|
if (hasPendingTransactions(root)) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
431
|
+
// 旁观路径(recoverOrphans: false)不自动恢复待恢复事务:
|
|
432
|
+
// 不触发依赖安装或清单回滚,直接报告恢复需求,由持有者入口完成恢复
|
|
433
|
+
if (!this.recoverOrphans) {
|
|
434
|
+
throw new ActionDockError(PROJECT_RECOVERY_REQUIRED, `PROJECT_RECOVERY_REQUIRED: Project at '${root}' has pending transactions requiring recovery. Run an owner command (e.g. 'ad add' or 'ad run') to complete recovery before querying.`);
|
|
435
|
+
}
|
|
436
|
+
await recoverPendingTransactions(root, { frozenInstall: true });
|
|
228
437
|
}
|
|
229
438
|
try {
|
|
230
439
|
const config = loadProjectConfig(root);
|
|
@@ -249,7 +458,7 @@ export class DefaultActionDockHost {
|
|
|
249
458
|
projectConfig: pkg.manifest,
|
|
250
459
|
identity: pkg.identity,
|
|
251
460
|
hostSessionId: this.hostSessionId,
|
|
252
|
-
|
|
461
|
+
globalStorageProvider: () => this.getGlobalStorage(),
|
|
253
462
|
platform: options.platform,
|
|
254
463
|
inMemory: options.inMemory,
|
|
255
464
|
customHome: options.customHome,
|
|
@@ -304,7 +513,7 @@ export class DefaultActionDockHost {
|
|
|
304
513
|
packageRoot: linked.path,
|
|
305
514
|
projectConfig: config,
|
|
306
515
|
hostSessionId: this.hostSessionId,
|
|
307
|
-
|
|
516
|
+
globalStorageProvider: () => this.getGlobalStorage(),
|
|
308
517
|
platform: options.platform,
|
|
309
518
|
inMemory: options.inMemory,
|
|
310
519
|
customHome: options.customHome,
|
|
@@ -428,7 +637,7 @@ export class DefaultActionDockHost {
|
|
|
428
637
|
};
|
|
429
638
|
const ticket = await targetRuntime.startInvocation(targetActionId, childInput, subInvocationContext);
|
|
430
639
|
if (!ticket.result) {
|
|
431
|
-
throw new
|
|
640
|
+
throw new ActionDockError(EXECUTION_FAILED, `Execution ticket for run '${ticket.runId}' has no result Promise`);
|
|
432
641
|
}
|
|
433
642
|
const result = await ticket.result;
|
|
434
643
|
if (!result.ok) {
|
|
@@ -482,7 +691,7 @@ export class DefaultActionDockHost {
|
|
|
482
691
|
if (existing === runtime) {
|
|
483
692
|
return;
|
|
484
693
|
}
|
|
485
|
-
throw new
|
|
694
|
+
throw new ActionDockError(PACKAGE_ID_CONFLICT, `Package ID conflict: package '${runtime.packageId}' is already registered in host`);
|
|
486
695
|
}
|
|
487
696
|
this.runtimes.set(runtime.packageId, runtime);
|
|
488
697
|
if (isPublic) {
|
|
@@ -490,27 +699,18 @@ export class DefaultActionDockHost {
|
|
|
490
699
|
}
|
|
491
700
|
this.bindRuntime(runtime);
|
|
492
701
|
this.rebuildGraphAndCatalog();
|
|
493
|
-
//
|
|
494
|
-
//
|
|
495
|
-
if (this.recoverOrphans) {
|
|
496
|
-
if (typeof runtime.recoverDeadSessionRuns === "function") {
|
|
497
|
-
try {
|
|
498
|
-
runtime.recoverDeadSessionRuns(this.hostSessionId);
|
|
499
|
-
}
|
|
500
|
-
catch (err) {
|
|
501
|
-
// 单包恢复失败不阻断整体接管流程,但必须可观测
|
|
502
|
-
console.warn(`[actiondock] recoverDeadSessionRuns failed for package '${runtime.packageId}': ${err instanceof Error ? err.message : String(err)}`);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
702
|
+
// 注册阶段只建立身份与路由;运行记录恢复收敛到包存储准备路径(持有者工厂预热时统一执行),
|
|
703
|
+
// 旁观 Host 注册不触碰其他进程的在途记录
|
|
506
704
|
}
|
|
507
705
|
registerRuntime(runtime) {
|
|
508
706
|
this.registerRuntimeInternal(runtime, true);
|
|
509
707
|
}
|
|
510
708
|
async info() {
|
|
709
|
+
await this.ensureInitialized();
|
|
511
710
|
return collectPackageInfos(this.listRuntimes());
|
|
512
711
|
}
|
|
513
712
|
async listActions(options) {
|
|
713
|
+
await this.ensureInitialized();
|
|
514
714
|
// 外层完成可见性筛选与跨包限定名改写后,统一委托共享过滤函数完成检索
|
|
515
715
|
const results = [];
|
|
516
716
|
const runtimes = this.listRuntimes();
|
|
@@ -533,9 +733,11 @@ export class DefaultActionDockHost {
|
|
|
533
733
|
return applyActionSummaryFilters(results, options);
|
|
534
734
|
}
|
|
535
735
|
async describeAction(ref) {
|
|
736
|
+
await this.ensureInitialized();
|
|
536
737
|
return describeActionAcrossRuntimes(ref, this.listRuntimes(), this.visibility(), this.failedLinkedPackages, this.catalog, this.graph);
|
|
537
738
|
}
|
|
538
739
|
async listPlaybooks(options) {
|
|
740
|
+
await this.ensureInitialized();
|
|
539
741
|
let pbs = await listVisiblePlaybooks(this.listRuntimes(), this.visibility());
|
|
540
742
|
if (options?.package) {
|
|
541
743
|
pbs = pbs.filter((p) => p.packageId === options.package);
|
|
@@ -546,18 +748,21 @@ export class DefaultActionDockHost {
|
|
|
546
748
|
return pbs;
|
|
547
749
|
}
|
|
548
750
|
async describePlaybook(id) {
|
|
751
|
+
await this.ensureInitialized();
|
|
549
752
|
return describeVisiblePlaybook(this.listRuntimes(), id, this.visibility());
|
|
550
753
|
}
|
|
551
754
|
async runAction(ref, input, options = {}) {
|
|
755
|
+
await this.ensureInitialized();
|
|
552
756
|
const ticket = await this.startAction(ref, input, options);
|
|
553
757
|
if (!ticket.result) {
|
|
554
|
-
throw new
|
|
758
|
+
throw new ActionDockError(EXECUTION_FAILED, `Execution ticket for run '${ticket.runId}' has no result Promise`);
|
|
555
759
|
}
|
|
556
760
|
return ticket.result;
|
|
557
761
|
}
|
|
558
762
|
async startAction(ref, input, options = {}) {
|
|
763
|
+
await this.ensureInitialized();
|
|
559
764
|
if (this.isClosed) {
|
|
560
|
-
throw new
|
|
765
|
+
throw new ActionDockError(SERVICE_CLOSED, "ActionDockHost is closed: new tasks rejected");
|
|
561
766
|
}
|
|
562
767
|
// - 统一基于纯领域 resolveAction 解析目标包与 Action 动作标识
|
|
563
768
|
let resolved;
|
|
@@ -643,21 +848,151 @@ export class DefaultActionDockHost {
|
|
|
643
848
|
// 调度目标包执行服务
|
|
644
849
|
return targetRuntime.startInvocation(targetActionId, input, rootContext);
|
|
645
850
|
}
|
|
646
|
-
async getRun(runId) {
|
|
851
|
+
async getRun(runId, signal) {
|
|
852
|
+
await this.ensureInitialized();
|
|
853
|
+
if (signal?.aborted) {
|
|
854
|
+
throw createAbortError(signal.reason);
|
|
855
|
+
}
|
|
647
856
|
for (const runtime of this.listRuntimes()) {
|
|
857
|
+
if (signal?.aborted) {
|
|
858
|
+
throw createAbortError(signal.reason);
|
|
859
|
+
}
|
|
648
860
|
const record = await runtime.getRun(runId);
|
|
861
|
+
if (signal?.aborted) {
|
|
862
|
+
throw createAbortError(signal.reason);
|
|
863
|
+
}
|
|
649
864
|
if (record)
|
|
650
865
|
return record;
|
|
651
866
|
}
|
|
652
867
|
return undefined;
|
|
653
868
|
}
|
|
654
|
-
async listRuns(query) {
|
|
869
|
+
async listRuns(query, signal) {
|
|
870
|
+
await this.ensureInitialized();
|
|
871
|
+
const effectiveSignal = signal ?? query?.signal;
|
|
872
|
+
if (effectiveSignal?.aborted) {
|
|
873
|
+
throw createAbortError(effectiveSignal.reason);
|
|
874
|
+
}
|
|
655
875
|
const runtimes = query?.packageId
|
|
656
876
|
? [this.getRuntime(query.packageId)].filter(Boolean)
|
|
657
|
-
:
|
|
877
|
+
: query?.packageAllowlist && query.packageAllowlist.length > 0
|
|
878
|
+
? query.packageAllowlist.map((id) => this.getRuntime(id)).filter(Boolean)
|
|
879
|
+
: this.listRuntimes();
|
|
880
|
+
// 当存在 intent 过滤时:分批读取并在内存中累积命中记录,先过滤后分页
|
|
881
|
+
if (query?.intent) {
|
|
882
|
+
const intentStr = query.intent;
|
|
883
|
+
const matchedRecords = [];
|
|
884
|
+
const BATCH_SIZE = 100;
|
|
885
|
+
const targetLimit = query.limit;
|
|
886
|
+
const targetOffset = query.offset ?? 0;
|
|
887
|
+
const neededCount = targetLimit !== undefined ? targetOffset + targetLimit : Infinity;
|
|
888
|
+
if (runtimes.length === 1) {
|
|
889
|
+
const runtime = runtimes[0];
|
|
890
|
+
let batchOffset = 0;
|
|
891
|
+
while (true) {
|
|
892
|
+
if (effectiveSignal?.aborted) {
|
|
893
|
+
throw createAbortError(effectiveSignal.reason);
|
|
894
|
+
}
|
|
895
|
+
const batch = await runtime.listRuns({
|
|
896
|
+
actionId: query.actionId,
|
|
897
|
+
status: query.status,
|
|
898
|
+
requestIds: query.requestIds,
|
|
899
|
+
limit: BATCH_SIZE,
|
|
900
|
+
offset: batchOffset,
|
|
901
|
+
signal: effectiveSignal,
|
|
902
|
+
});
|
|
903
|
+
if (effectiveSignal?.aborted) {
|
|
904
|
+
throw createAbortError(effectiveSignal.reason);
|
|
905
|
+
}
|
|
906
|
+
if (batch.length === 0)
|
|
907
|
+
break;
|
|
908
|
+
batchOffset += batch.length;
|
|
909
|
+
const normalized = batch.map((r) => ({
|
|
910
|
+
...r,
|
|
911
|
+
packageId: r.packageId || runtime.packageId,
|
|
912
|
+
}));
|
|
913
|
+
const filtered = filterByIntent(normalized, intentStr, [(r) => r.id, (r) => r.actionId, (r) => r.status, (r) => r.packageId], false);
|
|
914
|
+
matchedRecords.push(...filtered);
|
|
915
|
+
if (matchedRecords.length >= neededCount) {
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
if (batch.length < BATCH_SIZE) {
|
|
919
|
+
break;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
else {
|
|
924
|
+
for (const runtime of runtimes) {
|
|
925
|
+
if (effectiveSignal?.aborted) {
|
|
926
|
+
throw createAbortError(effectiveSignal.reason);
|
|
927
|
+
}
|
|
928
|
+
let batchOffset = 0;
|
|
929
|
+
while (true) {
|
|
930
|
+
if (effectiveSignal?.aborted) {
|
|
931
|
+
throw createAbortError(effectiveSignal.reason);
|
|
932
|
+
}
|
|
933
|
+
const batch = await runtime.listRuns({
|
|
934
|
+
actionId: query.actionId,
|
|
935
|
+
status: query.status,
|
|
936
|
+
requestIds: query.requestIds,
|
|
937
|
+
limit: BATCH_SIZE,
|
|
938
|
+
offset: batchOffset,
|
|
939
|
+
signal: effectiveSignal,
|
|
940
|
+
});
|
|
941
|
+
if (effectiveSignal?.aborted) {
|
|
942
|
+
throw createAbortError(effectiveSignal.reason);
|
|
943
|
+
}
|
|
944
|
+
if (batch.length === 0)
|
|
945
|
+
break;
|
|
946
|
+
batchOffset += batch.length;
|
|
947
|
+
const normalized = batch.map((r) => ({
|
|
948
|
+
...r,
|
|
949
|
+
packageId: r.packageId || runtime.packageId,
|
|
950
|
+
}));
|
|
951
|
+
const filtered = filterByIntent(normalized, intentStr, [(r) => r.id, (r) => r.actionId, (r) => r.status, (r) => r.packageId], false);
|
|
952
|
+
matchedRecords.push(...filtered);
|
|
953
|
+
if (batch.length < BATCH_SIZE) {
|
|
954
|
+
break;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
matchedRecords.sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime());
|
|
959
|
+
}
|
|
960
|
+
const end = targetLimit !== undefined ? targetOffset + targetLimit : undefined;
|
|
961
|
+
return matchedRecords.slice(targetOffset, end);
|
|
962
|
+
}
|
|
963
|
+
// 当不存在 intent 过滤时:
|
|
964
|
+
if (runtimes.length === 1) {
|
|
965
|
+
if (effectiveSignal?.aborted) {
|
|
966
|
+
throw createAbortError(effectiveSignal.reason);
|
|
967
|
+
}
|
|
968
|
+
const runtime = runtimes[0];
|
|
969
|
+
const recs = await runtime.listRuns(query ? { ...query, signal: effectiveSignal } : { signal: effectiveSignal });
|
|
970
|
+
if (effectiveSignal?.aborted) {
|
|
971
|
+
throw createAbortError(effectiveSignal.reason);
|
|
972
|
+
}
|
|
973
|
+
return recs.map((r) => ({
|
|
974
|
+
...r,
|
|
975
|
+
packageId: r.packageId || runtime.packageId,
|
|
976
|
+
}));
|
|
977
|
+
}
|
|
978
|
+
// 跨包联合查询:下推 limit/offset 或合并排序
|
|
658
979
|
const records = [];
|
|
980
|
+
const fetchLimit = query?.limit !== undefined
|
|
981
|
+
? (query.offset ?? 0) + query.limit
|
|
982
|
+
: undefined;
|
|
659
983
|
for (const runtime of runtimes) {
|
|
660
|
-
|
|
984
|
+
if (effectiveSignal?.aborted) {
|
|
985
|
+
throw createAbortError(effectiveSignal.reason);
|
|
986
|
+
}
|
|
987
|
+
const recs = await runtime.listRuns({
|
|
988
|
+
...query,
|
|
989
|
+
offset: 0,
|
|
990
|
+
limit: fetchLimit,
|
|
991
|
+
signal: effectiveSignal,
|
|
992
|
+
});
|
|
993
|
+
if (effectiveSignal?.aborted) {
|
|
994
|
+
throw createAbortError(effectiveSignal.reason);
|
|
995
|
+
}
|
|
661
996
|
for (const r of recs) {
|
|
662
997
|
records.push({
|
|
663
998
|
...r,
|
|
@@ -666,16 +1001,87 @@ export class DefaultActionDockHost {
|
|
|
666
1001
|
}
|
|
667
1002
|
}
|
|
668
1003
|
records.sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime());
|
|
669
|
-
|
|
1004
|
+
const start = query?.offset ?? 0;
|
|
1005
|
+
const end = query?.limit !== undefined ? start + query.limit : undefined;
|
|
1006
|
+
return records.slice(start, end);
|
|
1007
|
+
}
|
|
1008
|
+
async countRuns(query, signal) {
|
|
1009
|
+
await this.ensureInitialized();
|
|
1010
|
+
const effectiveSignal = signal ?? query?.signal;
|
|
1011
|
+
if (effectiveSignal?.aborted) {
|
|
1012
|
+
throw createAbortError(effectiveSignal.reason);
|
|
1013
|
+
}
|
|
1014
|
+
const runtimes = query?.packageId
|
|
1015
|
+
? [this.getRuntime(query.packageId)].filter(Boolean)
|
|
1016
|
+
: query?.packageAllowlist && query.packageAllowlist.length > 0
|
|
1017
|
+
? query.packageAllowlist.map((id) => this.getRuntime(id)).filter(Boolean)
|
|
1018
|
+
: this.listRuntimes();
|
|
670
1019
|
if (query?.intent) {
|
|
671
|
-
|
|
1020
|
+
const intentStr = query.intent;
|
|
1021
|
+
let count = 0;
|
|
1022
|
+
const BATCH_SIZE = 100;
|
|
1023
|
+
for (const runtime of runtimes) {
|
|
1024
|
+
if (effectiveSignal?.aborted) {
|
|
1025
|
+
throw createAbortError(effectiveSignal.reason);
|
|
1026
|
+
}
|
|
1027
|
+
let batchOffset = 0;
|
|
1028
|
+
while (true) {
|
|
1029
|
+
if (effectiveSignal?.aborted) {
|
|
1030
|
+
throw createAbortError(effectiveSignal.reason);
|
|
1031
|
+
}
|
|
1032
|
+
const batch = await runtime.listRuns({
|
|
1033
|
+
actionId: query.actionId,
|
|
1034
|
+
status: query.status,
|
|
1035
|
+
requestIds: query.requestIds,
|
|
1036
|
+
limit: BATCH_SIZE,
|
|
1037
|
+
offset: batchOffset,
|
|
1038
|
+
signal: effectiveSignal,
|
|
1039
|
+
});
|
|
1040
|
+
if (effectiveSignal?.aborted) {
|
|
1041
|
+
throw createAbortError(effectiveSignal.reason);
|
|
1042
|
+
}
|
|
1043
|
+
if (batch.length === 0)
|
|
1044
|
+
break;
|
|
1045
|
+
batchOffset += batch.length;
|
|
1046
|
+
const normalized = batch.map((r) => ({
|
|
1047
|
+
...r,
|
|
1048
|
+
packageId: r.packageId || runtime.packageId,
|
|
1049
|
+
}));
|
|
1050
|
+
const filtered = filterByIntent(normalized, intentStr, [(r) => r.id, (r) => r.actionId, (r) => r.status, (r) => r.packageId], false);
|
|
1051
|
+
count += filtered.length;
|
|
1052
|
+
if (batch.length < BATCH_SIZE) {
|
|
1053
|
+
break;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return count;
|
|
672
1058
|
}
|
|
673
|
-
|
|
674
|
-
|
|
1059
|
+
let total = 0;
|
|
1060
|
+
for (const runtime of runtimes) {
|
|
1061
|
+
if (effectiveSignal?.aborted) {
|
|
1062
|
+
throw createAbortError(effectiveSignal.reason);
|
|
1063
|
+
}
|
|
1064
|
+
if (typeof runtime.countRuns === "function") {
|
|
1065
|
+
total += await runtime.countRuns(query ? { ...query, signal: effectiveSignal } : { signal: effectiveSignal });
|
|
1066
|
+
}
|
|
1067
|
+
else {
|
|
1068
|
+
const all = await runtime.listRuns({
|
|
1069
|
+
actionId: query?.actionId,
|
|
1070
|
+
status: query?.status,
|
|
1071
|
+
requestIds: query?.requestIds,
|
|
1072
|
+
limit: 100_000,
|
|
1073
|
+
signal: effectiveSignal,
|
|
1074
|
+
});
|
|
1075
|
+
if (effectiveSignal?.aborted) {
|
|
1076
|
+
throw createAbortError(effectiveSignal.reason);
|
|
1077
|
+
}
|
|
1078
|
+
total += all.length;
|
|
1079
|
+
}
|
|
675
1080
|
}
|
|
676
|
-
return
|
|
1081
|
+
return total;
|
|
677
1082
|
}
|
|
678
1083
|
async clearRuns(options) {
|
|
1084
|
+
await this.ensureInitialized();
|
|
679
1085
|
const runtimes = options?.packageId
|
|
680
1086
|
? [this.getRuntime(options.packageId)].filter(Boolean)
|
|
681
1087
|
: this.listRuntimes();
|
|
@@ -687,6 +1093,7 @@ export class DefaultActionDockHost {
|
|
|
687
1093
|
return total;
|
|
688
1094
|
}
|
|
689
1095
|
async cleanExpiredRuns(policy) {
|
|
1096
|
+
await this.ensureInitialized();
|
|
690
1097
|
let total = 0;
|
|
691
1098
|
for (const runtime of this.listRuntimes()) {
|
|
692
1099
|
if (typeof runtime.cleanExpiredRuns === "function") {
|
|
@@ -697,6 +1104,7 @@ export class DefaultActionDockHost {
|
|
|
697
1104
|
return total;
|
|
698
1105
|
}
|
|
699
1106
|
async cancelRun(runId, reason) {
|
|
1107
|
+
await this.ensureInitialized();
|
|
700
1108
|
for (const runtime of this.listRuntimes()) {
|
|
701
1109
|
const res = await runtime.cancelRun(runId, reason);
|
|
702
1110
|
if (res.outcome !== "not_found") {
|
|
@@ -705,27 +1113,38 @@ export class DefaultActionDockHost {
|
|
|
705
1113
|
}
|
|
706
1114
|
return { outcome: "not_found", runId };
|
|
707
1115
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
1116
|
+
subscribeEvents(runId, options) {
|
|
1117
|
+
const self = this;
|
|
1118
|
+
// 事件订阅可异步解析包归属:逐包并发查询运行记录(公共端口,不新建执行服务),
|
|
1119
|
+
// 命中则使用该包事件源,全部未命中回退 Host 事件源
|
|
1120
|
+
return (async function* () {
|
|
1121
|
+
const runtimes = self.listRuntimes();
|
|
1122
|
+
const owner = await findRunOwnerRuntime(runtimes, runId);
|
|
1123
|
+
if (owner) {
|
|
1124
|
+
yield* owner.events(runId, options);
|
|
1125
|
+
return;
|
|
713
1126
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
return firstRuntime.events(runId, options);
|
|
718
|
-
}
|
|
719
|
-
return this.eventSink.subscribe(runId, options);
|
|
1127
|
+
// Host 共享事件源作为统一回退(与执行服务装配使用同一 sink,完成事件不丢失)
|
|
1128
|
+
yield* self.eventSink.subscribe(runId, options);
|
|
1129
|
+
})();
|
|
720
1130
|
}
|
|
721
1131
|
getGlobalStorage() {
|
|
722
1132
|
if (!this.globalStorage) {
|
|
723
|
-
const hasInMemoryPackage = this.options.packages?.some((item) =>
|
|
1133
|
+
const hasInMemoryPackage = this.options.packages?.some((item) => {
|
|
1134
|
+
if (typeof item === "string")
|
|
1135
|
+
return false;
|
|
1136
|
+
if (isPackageRuntime(item)) {
|
|
1137
|
+
return Boolean(item.inMemory || item.options?.inMemory);
|
|
1138
|
+
}
|
|
1139
|
+
return Boolean(item.inMemory);
|
|
1140
|
+
}) ||
|
|
1141
|
+
Array.from(this.runtimes.values()).some((rt) => Boolean(rt.inMemory || rt.options?.inMemory));
|
|
724
1142
|
const inMemory = Boolean(this.options.inMemory || hasInMemoryPackage);
|
|
725
1143
|
this.globalStorage =
|
|
726
1144
|
this.options.platform?.storage?.createGlobalStorage?.({
|
|
727
1145
|
dataDir: this.options.dataDir,
|
|
728
1146
|
customHome: this.options.customHome,
|
|
1147
|
+
...(inMemory ? { inMemory: true } : {}),
|
|
729
1148
|
}) ??
|
|
730
1149
|
createGlobalStorage({
|
|
731
1150
|
dataDir: this.options.dataDir,
|
|
@@ -760,11 +1179,12 @@ export class DefaultActionDockHost {
|
|
|
760
1179
|
requireRuntime(packageId) {
|
|
761
1180
|
const runtime = this.resolveRuntime(packageId);
|
|
762
1181
|
if (!runtime) {
|
|
763
|
-
throw new
|
|
1182
|
+
throw new ActionDockError(PACKAGE_NOT_FOUND, `Package '${packageId}' not found in host`);
|
|
764
1183
|
}
|
|
765
1184
|
return runtime;
|
|
766
1185
|
}
|
|
767
1186
|
async getConfig(packageId, key) {
|
|
1187
|
+
await this.ensureInitialized();
|
|
768
1188
|
if (packageId === "global") {
|
|
769
1189
|
const globalStorage = this.getGlobalStorage();
|
|
770
1190
|
const val = globalStorage.getConfig(key);
|
|
@@ -782,6 +1202,7 @@ export class DefaultActionDockHost {
|
|
|
782
1202
|
return this.requireRuntime(packageId).getConfig(key);
|
|
783
1203
|
}
|
|
784
1204
|
async setConfig(packageId, key, value) {
|
|
1205
|
+
await this.ensureInitialized();
|
|
785
1206
|
if (packageId === "global") {
|
|
786
1207
|
await this.getGlobalStorage().setConfig(key, value);
|
|
787
1208
|
return;
|
|
@@ -789,12 +1210,14 @@ export class DefaultActionDockHost {
|
|
|
789
1210
|
await this.requireRuntime(packageId).setConfig(key, value);
|
|
790
1211
|
}
|
|
791
1212
|
async deleteConfig(packageId, key) {
|
|
1213
|
+
await this.ensureInitialized();
|
|
792
1214
|
if (packageId === "global") {
|
|
793
1215
|
return await this.getGlobalStorage().deleteConfig(key);
|
|
794
1216
|
}
|
|
795
1217
|
return await this.requireRuntime(packageId).deleteConfig(key);
|
|
796
1218
|
}
|
|
797
1219
|
async listConfig(packageId) {
|
|
1220
|
+
await this.ensureInitialized();
|
|
798
1221
|
if (packageId === "global") {
|
|
799
1222
|
const globalStorage = this.getGlobalStorage();
|
|
800
1223
|
const all = globalStorage.listConfig();
|
|
@@ -813,11 +1236,13 @@ export class DefaultActionDockHost {
|
|
|
813
1236
|
return this.requireRuntime(packageId).listConfig();
|
|
814
1237
|
}
|
|
815
1238
|
async getState(packageId, actionId, key, options) {
|
|
1239
|
+
await this.ensureInitialized();
|
|
816
1240
|
return this.requireRuntime(packageId).getState(actionId, key, options);
|
|
817
1241
|
}
|
|
818
1242
|
async setState(packageId, actionId, key, value, options) {
|
|
1243
|
+
await this.ensureInitialized();
|
|
819
1244
|
const runtime = this.requireRuntime(packageId);
|
|
820
|
-
if (actionId) {
|
|
1245
|
+
if (actionId !== undefined) {
|
|
821
1246
|
await runtime.setActionState(actionId, key, value, options);
|
|
822
1247
|
}
|
|
823
1248
|
else {
|
|
@@ -825,18 +1250,22 @@ export class DefaultActionDockHost {
|
|
|
825
1250
|
}
|
|
826
1251
|
}
|
|
827
1252
|
async deleteState(packageId, actionId, key, options) {
|
|
1253
|
+
await this.ensureInitialized();
|
|
828
1254
|
return this.requireRuntime(packageId).deleteState(actionId, key, options);
|
|
829
1255
|
}
|
|
830
1256
|
async listStateKeys(packageId, actionId, options) {
|
|
1257
|
+
await this.ensureInitialized();
|
|
831
1258
|
return this.requireRuntime(packageId).listStateKeys(actionId, options);
|
|
832
1259
|
}
|
|
833
1260
|
async clearState(packageId, actionId, options) {
|
|
1261
|
+
await this.ensureInitialized();
|
|
834
1262
|
return this.requireRuntime(packageId).clearState(actionId, options);
|
|
835
1263
|
}
|
|
836
1264
|
async listStateEntries(packageId, options) {
|
|
1265
|
+
await this.ensureInitialized();
|
|
837
1266
|
const runtime = this.resolveRuntime(packageId);
|
|
838
1267
|
if (!runtime) {
|
|
839
|
-
throw new
|
|
1268
|
+
throw new ActionDockError(CAPABILITY_UNAVAILABLE, `CAPABILITY_UNAVAILABLE: Package '${packageId}' not found in host`);
|
|
840
1269
|
}
|
|
841
1270
|
if (!runtime.listStateEntries) {
|
|
842
1271
|
return [];
|
|
@@ -882,21 +1311,5 @@ export class DefaultActionDockHost {
|
|
|
882
1311
|
* 工厂函数:创建并初始化 ActionDockHost 宿主容器。
|
|
883
1312
|
*/
|
|
884
1313
|
export async function createActionDockHost(options = {}) {
|
|
885
|
-
|
|
886
|
-
try {
|
|
887
|
-
createdHost = new DefaultActionDockHost(options, { deferInit: true });
|
|
888
|
-
await createdHost.initializeAsync();
|
|
889
|
-
return createdHost;
|
|
890
|
-
}
|
|
891
|
-
catch (err) {
|
|
892
|
-
if (createdHost) {
|
|
893
|
-
try {
|
|
894
|
-
await createdHost.rollbackInitialization();
|
|
895
|
-
}
|
|
896
|
-
catch {
|
|
897
|
-
// 忽略宿主回滚异常,确保抛出原始异常
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
throw err;
|
|
901
|
-
}
|
|
1314
|
+
return DefaultActionDockHost.create(options);
|
|
902
1315
|
}
|