@actiondock/core 2.9.1 → 2.11.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 +12 -15
- 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 +24 -92
- package/dist/doctor/checks/registry.js +1 -1
- 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 +85 -4
- package/dist/errors.js +114 -4
- 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 +565 -150
- 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/describe.d.ts +6 -0
- package/dist/input/describe.js +26 -1
- 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 +2 -2
- package/dist/input/validation-mapper.d.ts +1 -1
- package/dist/invocation/policy.js +2 -0
- 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 +31 -526
- 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,
|
|
@@ -368,7 +577,9 @@ export class DefaultActionDockHost {
|
|
|
368
577
|
declaredUses,
|
|
369
578
|
}, { packageId: targetPackageId, actionId: targetActionId }, this.graph);
|
|
370
579
|
if (authErr) {
|
|
371
|
-
|
|
580
|
+
const hint = authErr.details?.hint;
|
|
581
|
+
const msg = hint ? `${authErr.message}\n${hint}` : authErr.message;
|
|
582
|
+
throw new ActionDockError(authErr.code, msg, authErr.details, undefined, hint);
|
|
372
583
|
}
|
|
373
584
|
}
|
|
374
585
|
// 调用嵌套深度限制校验
|
|
@@ -426,7 +637,7 @@ export class DefaultActionDockHost {
|
|
|
426
637
|
};
|
|
427
638
|
const ticket = await targetRuntime.startInvocation(targetActionId, childInput, subInvocationContext);
|
|
428
639
|
if (!ticket.result) {
|
|
429
|
-
throw new
|
|
640
|
+
throw new ActionDockError(EXECUTION_FAILED, `Execution ticket for run '${ticket.runId}' has no result Promise`);
|
|
430
641
|
}
|
|
431
642
|
const result = await ticket.result;
|
|
432
643
|
if (!result.ok) {
|
|
@@ -480,7 +691,7 @@ export class DefaultActionDockHost {
|
|
|
480
691
|
if (existing === runtime) {
|
|
481
692
|
return;
|
|
482
693
|
}
|
|
483
|
-
throw new
|
|
694
|
+
throw new ActionDockError(PACKAGE_ID_CONFLICT, `Package ID conflict: package '${runtime.packageId}' is already registered in host`);
|
|
484
695
|
}
|
|
485
696
|
this.runtimes.set(runtime.packageId, runtime);
|
|
486
697
|
if (isPublic) {
|
|
@@ -488,27 +699,18 @@ export class DefaultActionDockHost {
|
|
|
488
699
|
}
|
|
489
700
|
this.bindRuntime(runtime);
|
|
490
701
|
this.rebuildGraphAndCatalog();
|
|
491
|
-
//
|
|
492
|
-
//
|
|
493
|
-
if (this.recoverOrphans) {
|
|
494
|
-
if (typeof runtime.recoverDeadSessionRuns === "function") {
|
|
495
|
-
try {
|
|
496
|
-
runtime.recoverDeadSessionRuns(this.hostSessionId);
|
|
497
|
-
}
|
|
498
|
-
catch (err) {
|
|
499
|
-
// 单包恢复失败不阻断整体接管流程,但必须可观测
|
|
500
|
-
console.warn(`[actiondock] recoverDeadSessionRuns failed for package '${runtime.packageId}': ${err instanceof Error ? err.message : String(err)}`);
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
702
|
+
// 注册阶段只建立身份与路由;运行记录恢复收敛到包存储准备路径(持有者工厂预热时统一执行),
|
|
703
|
+
// 旁观 Host 注册不触碰其他进程的在途记录
|
|
504
704
|
}
|
|
505
705
|
registerRuntime(runtime) {
|
|
506
706
|
this.registerRuntimeInternal(runtime, true);
|
|
507
707
|
}
|
|
508
708
|
async info() {
|
|
709
|
+
await this.ensureInitialized();
|
|
509
710
|
return collectPackageInfos(this.listRuntimes());
|
|
510
711
|
}
|
|
511
712
|
async listActions(options) {
|
|
713
|
+
await this.ensureInitialized();
|
|
512
714
|
// 外层完成可见性筛选与跨包限定名改写后,统一委托共享过滤函数完成检索
|
|
513
715
|
const results = [];
|
|
514
716
|
const runtimes = this.listRuntimes();
|
|
@@ -531,9 +733,11 @@ export class DefaultActionDockHost {
|
|
|
531
733
|
return applyActionSummaryFilters(results, options);
|
|
532
734
|
}
|
|
533
735
|
async describeAction(ref) {
|
|
736
|
+
await this.ensureInitialized();
|
|
534
737
|
return describeActionAcrossRuntimes(ref, this.listRuntimes(), this.visibility(), this.failedLinkedPackages, this.catalog, this.graph);
|
|
535
738
|
}
|
|
536
739
|
async listPlaybooks(options) {
|
|
740
|
+
await this.ensureInitialized();
|
|
537
741
|
let pbs = await listVisiblePlaybooks(this.listRuntimes(), this.visibility());
|
|
538
742
|
if (options?.package) {
|
|
539
743
|
pbs = pbs.filter((p) => p.packageId === options.package);
|
|
@@ -544,18 +748,21 @@ export class DefaultActionDockHost {
|
|
|
544
748
|
return pbs;
|
|
545
749
|
}
|
|
546
750
|
async describePlaybook(id) {
|
|
751
|
+
await this.ensureInitialized();
|
|
547
752
|
return describeVisiblePlaybook(this.listRuntimes(), id, this.visibility());
|
|
548
753
|
}
|
|
549
754
|
async runAction(ref, input, options = {}) {
|
|
755
|
+
await this.ensureInitialized();
|
|
550
756
|
const ticket = await this.startAction(ref, input, options);
|
|
551
757
|
if (!ticket.result) {
|
|
552
|
-
throw new
|
|
758
|
+
throw new ActionDockError(EXECUTION_FAILED, `Execution ticket for run '${ticket.runId}' has no result Promise`);
|
|
553
759
|
}
|
|
554
760
|
return ticket.result;
|
|
555
761
|
}
|
|
556
762
|
async startAction(ref, input, options = {}) {
|
|
763
|
+
await this.ensureInitialized();
|
|
557
764
|
if (this.isClosed) {
|
|
558
|
-
throw new
|
|
765
|
+
throw new ActionDockError(SERVICE_CLOSED, "ActionDockHost is closed: new tasks rejected");
|
|
559
766
|
}
|
|
560
767
|
// - 统一基于纯领域 resolveAction 解析目标包与 Action 动作标识
|
|
561
768
|
let resolved;
|
|
@@ -641,21 +848,151 @@ export class DefaultActionDockHost {
|
|
|
641
848
|
// 调度目标包执行服务
|
|
642
849
|
return targetRuntime.startInvocation(targetActionId, input, rootContext);
|
|
643
850
|
}
|
|
644
|
-
async getRun(runId) {
|
|
851
|
+
async getRun(runId, signal) {
|
|
852
|
+
await this.ensureInitialized();
|
|
853
|
+
if (signal?.aborted) {
|
|
854
|
+
throw createAbortError(signal.reason);
|
|
855
|
+
}
|
|
645
856
|
for (const runtime of this.listRuntimes()) {
|
|
857
|
+
if (signal?.aborted) {
|
|
858
|
+
throw createAbortError(signal.reason);
|
|
859
|
+
}
|
|
646
860
|
const record = await runtime.getRun(runId);
|
|
861
|
+
if (signal?.aborted) {
|
|
862
|
+
throw createAbortError(signal.reason);
|
|
863
|
+
}
|
|
647
864
|
if (record)
|
|
648
865
|
return record;
|
|
649
866
|
}
|
|
650
867
|
return undefined;
|
|
651
868
|
}
|
|
652
|
-
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
|
+
}
|
|
653
875
|
const runtimes = query?.packageId
|
|
654
876
|
? [this.getRuntime(query.packageId)].filter(Boolean)
|
|
655
|
-
:
|
|
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 或合并排序
|
|
656
979
|
const records = [];
|
|
980
|
+
const fetchLimit = query?.limit !== undefined
|
|
981
|
+
? (query.offset ?? 0) + query.limit
|
|
982
|
+
: undefined;
|
|
657
983
|
for (const runtime of runtimes) {
|
|
658
|
-
|
|
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
|
+
}
|
|
659
996
|
for (const r of recs) {
|
|
660
997
|
records.push({
|
|
661
998
|
...r,
|
|
@@ -664,16 +1001,87 @@ export class DefaultActionDockHost {
|
|
|
664
1001
|
}
|
|
665
1002
|
}
|
|
666
1003
|
records.sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime());
|
|
667
|
-
|
|
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();
|
|
668
1019
|
if (query?.intent) {
|
|
669
|
-
|
|
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;
|
|
670
1058
|
}
|
|
671
|
-
|
|
672
|
-
|
|
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
|
+
}
|
|
673
1080
|
}
|
|
674
|
-
return
|
|
1081
|
+
return total;
|
|
675
1082
|
}
|
|
676
1083
|
async clearRuns(options) {
|
|
1084
|
+
await this.ensureInitialized();
|
|
677
1085
|
const runtimes = options?.packageId
|
|
678
1086
|
? [this.getRuntime(options.packageId)].filter(Boolean)
|
|
679
1087
|
: this.listRuntimes();
|
|
@@ -685,6 +1093,7 @@ export class DefaultActionDockHost {
|
|
|
685
1093
|
return total;
|
|
686
1094
|
}
|
|
687
1095
|
async cleanExpiredRuns(policy) {
|
|
1096
|
+
await this.ensureInitialized();
|
|
688
1097
|
let total = 0;
|
|
689
1098
|
for (const runtime of this.listRuntimes()) {
|
|
690
1099
|
if (typeof runtime.cleanExpiredRuns === "function") {
|
|
@@ -695,6 +1104,7 @@ export class DefaultActionDockHost {
|
|
|
695
1104
|
return total;
|
|
696
1105
|
}
|
|
697
1106
|
async cancelRun(runId, reason) {
|
|
1107
|
+
await this.ensureInitialized();
|
|
698
1108
|
for (const runtime of this.listRuntimes()) {
|
|
699
1109
|
const res = await runtime.cancelRun(runId, reason);
|
|
700
1110
|
if (res.outcome !== "not_found") {
|
|
@@ -703,27 +1113,38 @@ export class DefaultActionDockHost {
|
|
|
703
1113
|
}
|
|
704
1114
|
return { outcome: "not_found", runId };
|
|
705
1115
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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;
|
|
711
1126
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
return firstRuntime.events(runId, options);
|
|
716
|
-
}
|
|
717
|
-
return this.eventSink.subscribe(runId, options);
|
|
1127
|
+
// Host 共享事件源作为统一回退(与执行服务装配使用同一 sink,完成事件不丢失)
|
|
1128
|
+
yield* self.eventSink.subscribe(runId, options);
|
|
1129
|
+
})();
|
|
718
1130
|
}
|
|
719
1131
|
getGlobalStorage() {
|
|
720
1132
|
if (!this.globalStorage) {
|
|
721
|
-
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));
|
|
722
1142
|
const inMemory = Boolean(this.options.inMemory || hasInMemoryPackage);
|
|
723
1143
|
this.globalStorage =
|
|
724
1144
|
this.options.platform?.storage?.createGlobalStorage?.({
|
|
725
1145
|
dataDir: this.options.dataDir,
|
|
726
1146
|
customHome: this.options.customHome,
|
|
1147
|
+
...(inMemory ? { inMemory: true } : {}),
|
|
727
1148
|
}) ??
|
|
728
1149
|
createGlobalStorage({
|
|
729
1150
|
dataDir: this.options.dataDir,
|
|
@@ -758,11 +1179,12 @@ export class DefaultActionDockHost {
|
|
|
758
1179
|
requireRuntime(packageId) {
|
|
759
1180
|
const runtime = this.resolveRuntime(packageId);
|
|
760
1181
|
if (!runtime) {
|
|
761
|
-
throw new
|
|
1182
|
+
throw new ActionDockError(PACKAGE_NOT_FOUND, `Package '${packageId}' not found in host`);
|
|
762
1183
|
}
|
|
763
1184
|
return runtime;
|
|
764
1185
|
}
|
|
765
1186
|
async getConfig(packageId, key) {
|
|
1187
|
+
await this.ensureInitialized();
|
|
766
1188
|
if (packageId === "global") {
|
|
767
1189
|
const globalStorage = this.getGlobalStorage();
|
|
768
1190
|
const val = globalStorage.getConfig(key);
|
|
@@ -780,6 +1202,7 @@ export class DefaultActionDockHost {
|
|
|
780
1202
|
return this.requireRuntime(packageId).getConfig(key);
|
|
781
1203
|
}
|
|
782
1204
|
async setConfig(packageId, key, value) {
|
|
1205
|
+
await this.ensureInitialized();
|
|
783
1206
|
if (packageId === "global") {
|
|
784
1207
|
await this.getGlobalStorage().setConfig(key, value);
|
|
785
1208
|
return;
|
|
@@ -787,12 +1210,14 @@ export class DefaultActionDockHost {
|
|
|
787
1210
|
await this.requireRuntime(packageId).setConfig(key, value);
|
|
788
1211
|
}
|
|
789
1212
|
async deleteConfig(packageId, key) {
|
|
1213
|
+
await this.ensureInitialized();
|
|
790
1214
|
if (packageId === "global") {
|
|
791
1215
|
return await this.getGlobalStorage().deleteConfig(key);
|
|
792
1216
|
}
|
|
793
1217
|
return await this.requireRuntime(packageId).deleteConfig(key);
|
|
794
1218
|
}
|
|
795
1219
|
async listConfig(packageId) {
|
|
1220
|
+
await this.ensureInitialized();
|
|
796
1221
|
if (packageId === "global") {
|
|
797
1222
|
const globalStorage = this.getGlobalStorage();
|
|
798
1223
|
const all = globalStorage.listConfig();
|
|
@@ -811,11 +1236,13 @@ export class DefaultActionDockHost {
|
|
|
811
1236
|
return this.requireRuntime(packageId).listConfig();
|
|
812
1237
|
}
|
|
813
1238
|
async getState(packageId, actionId, key, options) {
|
|
1239
|
+
await this.ensureInitialized();
|
|
814
1240
|
return this.requireRuntime(packageId).getState(actionId, key, options);
|
|
815
1241
|
}
|
|
816
1242
|
async setState(packageId, actionId, key, value, options) {
|
|
1243
|
+
await this.ensureInitialized();
|
|
817
1244
|
const runtime = this.requireRuntime(packageId);
|
|
818
|
-
if (actionId) {
|
|
1245
|
+
if (actionId !== undefined) {
|
|
819
1246
|
await runtime.setActionState(actionId, key, value, options);
|
|
820
1247
|
}
|
|
821
1248
|
else {
|
|
@@ -823,18 +1250,22 @@ export class DefaultActionDockHost {
|
|
|
823
1250
|
}
|
|
824
1251
|
}
|
|
825
1252
|
async deleteState(packageId, actionId, key, options) {
|
|
1253
|
+
await this.ensureInitialized();
|
|
826
1254
|
return this.requireRuntime(packageId).deleteState(actionId, key, options);
|
|
827
1255
|
}
|
|
828
1256
|
async listStateKeys(packageId, actionId, options) {
|
|
1257
|
+
await this.ensureInitialized();
|
|
829
1258
|
return this.requireRuntime(packageId).listStateKeys(actionId, options);
|
|
830
1259
|
}
|
|
831
1260
|
async clearState(packageId, actionId, options) {
|
|
1261
|
+
await this.ensureInitialized();
|
|
832
1262
|
return this.requireRuntime(packageId).clearState(actionId, options);
|
|
833
1263
|
}
|
|
834
1264
|
async listStateEntries(packageId, options) {
|
|
1265
|
+
await this.ensureInitialized();
|
|
835
1266
|
const runtime = this.resolveRuntime(packageId);
|
|
836
1267
|
if (!runtime) {
|
|
837
|
-
throw new
|
|
1268
|
+
throw new ActionDockError(CAPABILITY_UNAVAILABLE, `CAPABILITY_UNAVAILABLE: Package '${packageId}' not found in host`);
|
|
838
1269
|
}
|
|
839
1270
|
if (!runtime.listStateEntries) {
|
|
840
1271
|
return [];
|
|
@@ -880,21 +1311,5 @@ export class DefaultActionDockHost {
|
|
|
880
1311
|
* 工厂函数:创建并初始化 ActionDockHost 宿主容器。
|
|
881
1312
|
*/
|
|
882
1313
|
export async function createActionDockHost(options = {}) {
|
|
883
|
-
|
|
884
|
-
try {
|
|
885
|
-
createdHost = new DefaultActionDockHost(options, { deferInit: true });
|
|
886
|
-
await createdHost.initializeAsync();
|
|
887
|
-
return createdHost;
|
|
888
|
-
}
|
|
889
|
-
catch (err) {
|
|
890
|
-
if (createdHost) {
|
|
891
|
-
try {
|
|
892
|
-
await createdHost.rollbackInitialization();
|
|
893
|
-
}
|
|
894
|
-
catch {
|
|
895
|
-
// 忽略宿主回滚异常,确保抛出原始异常
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
throw err;
|
|
899
|
-
}
|
|
1314
|
+
return DefaultActionDockHost.create(options);
|
|
900
1315
|
}
|