@actiondock/core 2.19.0 → 2.21.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/dist/client/config.d.ts +17 -14
- package/dist/client/config.js +112 -14
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/errors.d.ts +13 -1
- package/dist/errors.js +25 -0
- package/dist/execution/service.js +44 -10
- package/dist/execution/types.d.ts +3 -3
- package/dist/host/host.d.ts +20 -1
- package/dist/host/host.js +430 -66
- package/dist/host/types.d.ts +13 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.js +5 -1
- package/dist/input/config-override.d.ts +5 -0
- package/dist/input/config-override.js +23 -0
- package/dist/input/input-resolver.d.ts +24 -7
- package/dist/input/input-resolver.js +73 -5
- package/dist/invocation/bindings.d.ts +53 -0
- package/dist/invocation/bindings.js +248 -0
- package/dist/invocation/policy.d.ts +5 -1
- package/dist/invocation/policy.js +16 -9
- package/dist/invocation/remote.d.ts +40 -0
- package/dist/invocation/remote.js +489 -0
- package/dist/invocation/types.d.ts +33 -0
- package/dist/invocation/types.js +11 -1
- package/dist/package/index.d.ts +2 -2
- package/dist/package/runtime.js +48 -15
- package/dist/platform/node.d.ts +6 -0
- package/dist/platform/node.js +59 -16
- package/dist/platform/types.d.ts +59 -1
- package/dist/process/command-executor.d.ts +35 -0
- package/dist/process/command-executor.js +326 -0
- package/dist/process/index.d.ts +1 -0
- package/dist/process/index.js +1 -0
- package/dist/process/process-driver.d.ts +19 -6
- package/dist/process/process-driver.js +223 -54
- package/dist/process/run-executor.js +101 -47
- package/dist/project/config-declarations.d.ts +61 -0
- package/dist/project/config-declarations.js +297 -0
- package/dist/project/dependencies.d.ts +92 -0
- package/dist/project/dependencies.js +543 -0
- package/dist/project/index.d.ts +8 -2
- package/dist/project/index.js +8 -2
- package/dist/project/init.js +2 -2
- package/dist/project/loader.js +19 -30
- package/dist/project/manifest.js +10 -0
- package/dist/project/package-manager.d.ts +40 -0
- package/dist/project/package-manager.js +224 -0
- package/dist/project/preparation.d.ts +8 -0
- package/dist/project/preparation.js +130 -0
- package/dist/project/transactions.d.ts +5 -1
- package/dist/project/transactions.js +35 -75
- package/dist/project/types.d.ts +30 -0
- package/dist/runtime/context.d.ts +27 -5
- package/dist/runtime/context.js +98 -26
- package/dist/runtime/env.js +15 -1
- package/dist/runtime/run-persistence.d.ts +1 -1
- package/dist/runtime/run-persistence.js +4 -3
- package/dist/runtime/standalone-commands.d.ts +2 -2
- package/dist/runtime/standalone-commands.js +113 -47
- package/dist/runtime/standalone-help.d.ts +1 -0
- package/dist/runtime/standalone-help.js +15 -9
- package/dist/runtime/standalone.js +2 -2
- package/dist/security/config-cipher.d.ts +54 -0
- package/dist/security/config-cipher.js +190 -0
- package/dist/security/config-key.d.ts +35 -0
- package/dist/security/config-key.js +469 -0
- package/dist/server/policy.d.ts +24 -107
- package/dist/server/policy.js +134 -291
- package/dist/server/routes/actions.js +10 -8
- package/dist/server/routes/common.d.ts +5 -20
- package/dist/server/routes/common.js +22 -58
- package/dist/server/routes/config.js +84 -7
- package/dist/server/routes/doctor.d.ts +1 -0
- package/dist/server/routes/doctor.js +4 -3
- package/dist/server/routes/info.js +100 -13
- package/dist/server/routes/playbooks.js +1 -3
- package/dist/server/routes/runs.js +96 -18
- package/dist/server/server.js +25 -53
- package/dist/server/types.d.ts +6 -6
- package/dist/service/factory.js +4 -0
- package/dist/service/remote.js +14 -29
- package/dist/service/types.d.ts +28 -5
- package/dist/service/types.js +8 -0
- package/dist/storage/config-value.d.ts +33 -0
- package/dist/storage/config-value.js +102 -0
- package/dist/storage/file-lock.js +35 -21
- package/dist/storage/index.d.ts +24 -2
- package/dist/storage/index.js +65 -2
- package/dist/storage/mask.d.ts +33 -6
- package/dist/storage/mask.js +298 -16
- package/dist/storage/migrations/index.d.ts +40 -0
- package/dist/storage/migrations/index.js +96 -0
- package/dist/storage/migrations/v2-to-v3.d.ts +16 -0
- package/dist/storage/migrations/v2-to-v3.js +116 -0
- package/dist/storage/sqlite-config.d.ts +62 -3
- package/dist/storage/sqlite-config.js +163 -9
- package/dist/storage/sqlite-driver.d.ts +5 -2
- package/dist/storage/sqlite-driver.js +24 -3
- package/dist/storage/sqlite-schema.d.ts +20 -2
- package/dist/storage/sqlite-schema.js +129 -132
- package/dist/storage/sqlite.d.ts +7 -2
- package/dist/storage/sqlite.js +64 -13
- package/dist/storage/types.d.ts +72 -4
- package/dist/storage/types.js +7 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/host/host.js
CHANGED
|
@@ -8,16 +8,20 @@ import { hasPendingTransactions, isProjectLockHeld, recoverPendingTransactions }
|
|
|
8
8
|
import { listLinkedPackages } from "../registry/registry.js";
|
|
9
9
|
import { InMemoryEventSink } from "../runtime/events.js";
|
|
10
10
|
import { snapshotRunOrigin } from "../runtime/run-origin.js";
|
|
11
|
-
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
|
+
import { ActionDockError, ACTION_CANCELLED, ACTION_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_SUBRUN_LIMIT, ACTION_TIMEOUT, EXECUTION_FAILED, INVALID_ACTION_REF, PACKAGE_ID_CONFLICT, PACKAGE_NOT_FOUND, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, SERVICE_CLOSED, UNDECLARED_ACTION_DEPENDENCY, } from "../errors.js";
|
|
12
12
|
import { InvocationPolicy } from "../invocation/policy.js";
|
|
13
|
+
import { loadActionBindings, resolveActionBinding, validateActionBindings, } from "../invocation/bindings.js";
|
|
14
|
+
import { RemoteInvocationExecutor } from "../invocation/remote.js";
|
|
15
|
+
import { resolveTarget } from "../profile/manager.js";
|
|
13
16
|
import { createAbortError } from "../ipc/service.js";
|
|
14
17
|
import { DataDirLock } from "../storage/data-dir-lock.js";
|
|
15
18
|
import { DefaultActionCatalog, DefaultPackageGraph, PackageGraphBuilder, resolveAction, } from "../catalog/index.js";
|
|
16
19
|
import { parseActionRef } from "../catalog/resolve-action.js";
|
|
17
20
|
import { buildRuntimeError, collectPackageInfos, describeActionAcrossRuntimes, describeVisiblePlaybook, isRootCallVisible, listVisiblePlaybooks, packageNotFoundMessage, parseRefLoose, resolveProjectRoot, } from "./routing.js";
|
|
18
21
|
import { CAPABILITY_UNAVAILABLE } from "../errors.js";
|
|
19
|
-
import { createGlobalStorage,
|
|
22
|
+
import { createGlobalStorage, redactConfigValueAtPaths, redactConfigValueForDeclarations, readConfigWithProtection, redactConfigValueWithProtection } from "../storage/index.js";
|
|
20
23
|
import { filterByIntent } from "../utils/intent.js";
|
|
24
|
+
import { assertConcreteConfigKey, isConfigTemplate, resolveConfigDeclaration, validateConfigValue, } from "../project/config-declarations.js";
|
|
21
25
|
function isPackageRuntime(item) {
|
|
22
26
|
return (typeof item === "object" &&
|
|
23
27
|
item !== null &&
|
|
@@ -56,16 +60,33 @@ function withAbortSignal(op, signal) {
|
|
|
56
60
|
});
|
|
57
61
|
});
|
|
58
62
|
}
|
|
63
|
+
function isActionTimeoutReason(reason) {
|
|
64
|
+
if (!reason)
|
|
65
|
+
return false;
|
|
66
|
+
const code = reason?.code;
|
|
67
|
+
if (code === ACTION_TIMEOUT)
|
|
68
|
+
return true;
|
|
69
|
+
if (reason?.details?.code === ACTION_TIMEOUT)
|
|
70
|
+
return true;
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
59
73
|
export class DefaultActionDockHost {
|
|
60
74
|
hostSessionId;
|
|
61
75
|
options;
|
|
76
|
+
allowInstall;
|
|
62
77
|
runtimes = new Map();
|
|
78
|
+
extraRuntimes = new Set();
|
|
79
|
+
extraRuntimeScopes = new Map();
|
|
63
80
|
policy;
|
|
64
81
|
hostPublicPackageIds = new Set();
|
|
65
82
|
maxCallDepth;
|
|
66
83
|
maxSubRuns;
|
|
67
84
|
eventSink;
|
|
68
85
|
isClosed = false;
|
|
86
|
+
prepareLocalPackage;
|
|
87
|
+
closeController = new AbortController();
|
|
88
|
+
activePreparations = new Set();
|
|
89
|
+
closePromise;
|
|
69
90
|
dataDirLock;
|
|
70
91
|
failedLinkedPackages = new Map();
|
|
71
92
|
failedAutoLoad;
|
|
@@ -76,6 +97,9 @@ export class DefaultActionDockHost {
|
|
|
76
97
|
globalStorage;
|
|
77
98
|
initPromise;
|
|
78
99
|
isInitialized = false;
|
|
100
|
+
actionBindings = new Map();
|
|
101
|
+
remoteTargets = new Map();
|
|
102
|
+
remoteInvoker;
|
|
79
103
|
discovery;
|
|
80
104
|
execution;
|
|
81
105
|
runs;
|
|
@@ -100,6 +124,9 @@ export class DefaultActionDockHost {
|
|
|
100
124
|
}
|
|
101
125
|
this.hostSessionId = randomUUID();
|
|
102
126
|
this.options = options;
|
|
127
|
+
this.allowInstall = options.allowInstall;
|
|
128
|
+
this.prepareLocalPackage = options.prepareLocalPackage;
|
|
129
|
+
this.remoteInvoker = new RemoteInvocationExecutor({ logger: options.logger });
|
|
103
130
|
this.maxCallDepth = options.maxCallDepth ?? 16;
|
|
104
131
|
this.maxSubRuns = options.maxSubRuns ?? 64;
|
|
105
132
|
this.policy = new InvocationPolicy({
|
|
@@ -348,6 +375,21 @@ export class DefaultActionDockHost {
|
|
|
348
375
|
// 持有者在返回前打开共享全局存储,保留对全局库存储错误的提前发现能力
|
|
349
376
|
this.getGlobalStorage();
|
|
350
377
|
}
|
|
378
|
+
/** 返回的 Runtime 由 Host 统一接管,端口只清理自身缓存和附属资源。 */
|
|
379
|
+
async closeInvocationTargets() {
|
|
380
|
+
const extras = Array.from(this.extraRuntimes).filter((runtime) => this.runtimes.get(runtime.packageId) !== runtime);
|
|
381
|
+
this.extraRuntimes.clear();
|
|
382
|
+
this.extraRuntimeScopes.clear();
|
|
383
|
+
const results = await Promise.allSettled(extras.map((runtime) => runtime.close()));
|
|
384
|
+
const errors = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
385
|
+
try {
|
|
386
|
+
await this.options.platform?.invocationTargets?.close?.();
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
errors.push(error);
|
|
390
|
+
}
|
|
391
|
+
return errors;
|
|
392
|
+
}
|
|
351
393
|
/**
|
|
352
394
|
* 异步安全回滚初始化失败时所占用的资源。
|
|
353
395
|
*/
|
|
@@ -363,7 +405,11 @@ export class DefaultActionDockHost {
|
|
|
363
405
|
// 忽略 Runtime 关闭异常
|
|
364
406
|
}
|
|
365
407
|
}));
|
|
408
|
+
const invocationCloseErrors = await this.closeInvocationTargets();
|
|
366
409
|
this.runtimes.clear();
|
|
410
|
+
this.actionBindings.clear();
|
|
411
|
+
this.remoteTargets.clear();
|
|
412
|
+
await this.remoteInvoker.close();
|
|
367
413
|
try {
|
|
368
414
|
this.globalStorage?.close();
|
|
369
415
|
}
|
|
@@ -379,6 +425,8 @@ export class DefaultActionDockHost {
|
|
|
379
425
|
}
|
|
380
426
|
this.dataDirLock = undefined;
|
|
381
427
|
this.isClosed = true;
|
|
428
|
+
if (invocationCloseErrors.length)
|
|
429
|
+
throw new AggregateError(invocationCloseErrors, "Invocation target cleanup failed");
|
|
382
430
|
}
|
|
383
431
|
/**
|
|
384
432
|
* 阶段函数:注册显式传入的 packages 列表(PackageRuntimeOptions 配置或包目录物理路径)。
|
|
@@ -438,7 +486,10 @@ export class DefaultActionDockHost {
|
|
|
438
486
|
if (!this.recoverOrphans) {
|
|
439
487
|
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.`);
|
|
440
488
|
}
|
|
441
|
-
|
|
489
|
+
if (this.allowInstall === false || process.env.ACTIONDOCK_AUTO_INSTALL === "false") {
|
|
490
|
+
throw new ActionDockError(PROJECT_RECOVERY_REQUIRED, `PROJECT_RECOVERY_REQUIRED: Project at '${root}' has pending transactions requiring recovery install, but installation is disabled (--no-install or ACTIONDOCK_AUTO_INSTALL=false).`);
|
|
491
|
+
}
|
|
492
|
+
await recoverPendingTransactions(root, { frozenInstall: true, allowInstall: this.allowInstall });
|
|
442
493
|
}
|
|
443
494
|
try {
|
|
444
495
|
const config = loadProjectConfig(root);
|
|
@@ -551,21 +602,75 @@ export class DefaultActionDockHost {
|
|
|
551
602
|
* 铁律 2:跨包调用改走 ActionInvoker 回到 Host 执行主链,经由唯一的 InvocationPolicy 授权后调用目标 Package 的 ExecutionService。
|
|
552
603
|
*/
|
|
553
604
|
createActionInvoker(callerRuntime) {
|
|
554
|
-
return async (childAction, childInput, context) => {
|
|
555
|
-
|
|
605
|
+
return async (childAction, childInput, context, options) => {
|
|
606
|
+
if (this.isClosed)
|
|
607
|
+
throw new ActionDockError(SERVICE_CLOSED, "ActionDockHost is closed");
|
|
608
|
+
if (context.signal.aborted)
|
|
609
|
+
throw new ActionDockError(ACTION_CANCELLED, "Caller invocation is cancelled");
|
|
610
|
+
const parsed = parseActionRef(childAction);
|
|
611
|
+
// 裸引用仍由既有解析器消歧;远端专属依赖须使用完全限定引用。
|
|
612
|
+
const localResolved = parsed.packageId ? undefined : resolveAction(childAction, {
|
|
556
613
|
caller: callerRuntime.packageId,
|
|
557
614
|
graph: this.graph,
|
|
558
615
|
catalog: this.catalog,
|
|
559
616
|
});
|
|
560
|
-
const targetPackageId =
|
|
561
|
-
const targetActionId =
|
|
562
|
-
const
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
617
|
+
const targetPackageId = parsed.packageId ?? localResolved.package.id;
|
|
618
|
+
const targetActionId = parsed.actionId;
|
|
619
|
+
const canonicalRef = `${targetPackageId}/${targetActionId}`;
|
|
620
|
+
const canonicalActionRef = { packageId: targetPackageId, actionId: targetActionId };
|
|
621
|
+
const callerBindings = this.actionBindings.get(callerRuntime.packageId) ?? {};
|
|
622
|
+
const isNamedTarget = Boolean(options?.binding && options.binding !== "default");
|
|
623
|
+
// 目标装配是同步解析,不在此引入另一条执行或网络调用链。
|
|
624
|
+
const targetOverride = this.options.platform?.invocationTargets?.resolve(canonicalActionRef, options, {
|
|
625
|
+
packageId: callerRuntime.packageId,
|
|
626
|
+
actionId: context.caller?.actionId,
|
|
627
|
+
});
|
|
628
|
+
let targetRuntime;
|
|
629
|
+
let targetScope;
|
|
630
|
+
let isRemote = false;
|
|
631
|
+
let remoteProfile;
|
|
632
|
+
if (targetOverride) {
|
|
633
|
+
if (targetOverride.runtime.packageId !== targetPackageId) {
|
|
634
|
+
throw new ActionDockError(INVALID_ACTION_REF, `Invocation target packageId mismatch: expected '${targetPackageId}', got '${targetOverride.runtime.packageId}'`);
|
|
635
|
+
}
|
|
636
|
+
targetRuntime = targetOverride.runtime;
|
|
637
|
+
this.extraRuntimes.add(targetRuntime);
|
|
638
|
+
this.bindRuntime(targetRuntime);
|
|
639
|
+
targetScope = targetOverride.scope ?? (isNamedTarget ? `binding:${options?.binding}` : undefined);
|
|
640
|
+
if (targetScope)
|
|
641
|
+
this.extraRuntimeScopes.set(targetRuntime, targetScope);
|
|
566
642
|
}
|
|
643
|
+
else {
|
|
644
|
+
// 没有绑定的旧调用不引入额外的清单命名约束,保持编程式 Runtime 兼容。
|
|
645
|
+
const binding = options?.binding !== undefined || Object.hasOwn(callerBindings, canonicalRef)
|
|
646
|
+
? resolveActionBinding(callerBindings, canonicalRef, options?.binding)
|
|
647
|
+
: undefined;
|
|
648
|
+
if (binding?.type === "remote") {
|
|
649
|
+
isRemote = true;
|
|
650
|
+
remoteProfile = binding.profile;
|
|
651
|
+
targetScope = `profile:${binding.profile}`;
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
isRemote = false;
|
|
655
|
+
if (!localResolved) {
|
|
656
|
+
resolveAction(childAction, { caller: callerRuntime.packageId, graph: this.graph, catalog: this.catalog });
|
|
657
|
+
}
|
|
658
|
+
const isLogicalSamePackage = targetPackageId === callerRuntime.packageId;
|
|
659
|
+
targetRuntime = isLogicalSamePackage ? callerRuntime : this.getRuntime(targetPackageId);
|
|
660
|
+
if (targetRuntime)
|
|
661
|
+
targetScope = this.extraRuntimeScopes.get(targetRuntime);
|
|
662
|
+
if (!targetRuntime) {
|
|
663
|
+
throw new ActionDockError(PACKAGE_NOT_FOUND, packageNotFoundMessage(targetPackageId, this.failedLinkedPackages));
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
const isLogicalSamePackage = targetPackageId === callerRuntime.packageId;
|
|
668
|
+
const isPhysicalSameRuntime = Boolean(targetRuntime && targetRuntime === callerRuntime);
|
|
669
|
+
const requiresExplicitUses = Boolean(isRemote ||
|
|
670
|
+
targetOverride?.requiresExplicitUses ||
|
|
671
|
+
(isNamedTarget && targetOverride !== undefined));
|
|
567
672
|
// 跨包 uses 依赖声明校验(统一委托 InvocationPolicy 单一事实源)
|
|
568
|
-
if (!
|
|
673
|
+
if (!isLogicalSamePackage || requiresExplicitUses) {
|
|
569
674
|
let declaredUses = context.caller?.declaredUses;
|
|
570
675
|
if (!declaredUses) {
|
|
571
676
|
try {
|
|
@@ -580,7 +685,11 @@ export class DefaultActionDockHost {
|
|
|
580
685
|
packageId: callerRuntime.packageId,
|
|
581
686
|
actionId: context.caller?.actionId || "",
|
|
582
687
|
declaredUses,
|
|
583
|
-
}, {
|
|
688
|
+
}, {
|
|
689
|
+
packageId: targetPackageId,
|
|
690
|
+
actionId: targetActionId,
|
|
691
|
+
requiresExplicitUses,
|
|
692
|
+
}, this.graph);
|
|
584
693
|
if (authErr) {
|
|
585
694
|
const hint = authErr.details?.hint;
|
|
586
695
|
const msg = hint ? `${authErr.message}\n${hint}` : authErr.message;
|
|
@@ -593,7 +702,7 @@ export class DefaultActionDockHost {
|
|
|
593
702
|
throw new ActionDockError(depthErr.code, depthErr.message, depthErr.details);
|
|
594
703
|
}
|
|
595
704
|
// 调用链环路死锁检测
|
|
596
|
-
const cycle = this.policy.checkCycle(context.callStack, targetActionId, targetPackageId, callerRuntime.packageId);
|
|
705
|
+
const cycle = this.policy.checkCycle(context.callStack, targetActionId, targetPackageId, callerRuntime.packageId, targetScope);
|
|
597
706
|
if (cycle.error) {
|
|
598
707
|
throw new ActionDockError(cycle.error.code, cycle.error.message, cycle.error.details);
|
|
599
708
|
}
|
|
@@ -608,14 +717,18 @@ export class DefaultActionDockHost {
|
|
|
608
717
|
}
|
|
609
718
|
try {
|
|
610
719
|
const nextCallStack = [...context.callStack, cycle.callKey];
|
|
720
|
+
if (isRemote) {
|
|
721
|
+
const candidate = this.catalog.find({ packageId: targetPackageId, actionId: targetActionId })[0];
|
|
722
|
+
return await this.remoteInvoker.invoke(this.remoteTargets.get(remoteProfile), { packageId: targetPackageId, actionId: targetActionId }, childInput, { ...context, callStack: nextCallStack }, { binding: options?.binding ?? "default", profile: remoteProfile }, candidate?.contract);
|
|
723
|
+
}
|
|
611
724
|
const targetOwner = context.owner
|
|
612
725
|
? {
|
|
613
726
|
tenantId: context.owner.tenantId,
|
|
614
727
|
principalId: context.owner.principalId,
|
|
615
|
-
packageInstanceId:
|
|
728
|
+
packageInstanceId: isPhysicalSameRuntime
|
|
616
729
|
? (context.owner.packageInstanceId || callerRuntime.identity.instanceId)
|
|
617
730
|
: targetRuntime.identity.instanceId,
|
|
618
|
-
generationId:
|
|
731
|
+
generationId: isPhysicalSameRuntime
|
|
619
732
|
? (context.owner.generationId || callerRuntime.identity.generation)
|
|
620
733
|
: targetRuntime.identity.generation,
|
|
621
734
|
}
|
|
@@ -626,6 +739,7 @@ export class DefaultActionDockHost {
|
|
|
626
739
|
parentRunId: context.parentRunId,
|
|
627
740
|
caller: context.caller,
|
|
628
741
|
callStack: nextCallStack,
|
|
742
|
+
targetScope,
|
|
629
743
|
package: targetRuntime.identity,
|
|
630
744
|
signal: context.signal,
|
|
631
745
|
timeoutMs: context.timeoutMs,
|
|
@@ -641,7 +755,7 @@ export class DefaultActionDockHost {
|
|
|
641
755
|
owner: targetOwner,
|
|
642
756
|
origin: context.origin,
|
|
643
757
|
};
|
|
644
|
-
const ticket = await
|
|
758
|
+
const ticket = await this.dispatchLocalInvocation(targetRuntime, targetActionId, childInput, subInvocationContext);
|
|
645
759
|
if (!ticket.result) {
|
|
646
760
|
throw new ActionDockError(EXECUTION_FAILED, `Execution ticket for run '${ticket.runId}' has no result Promise`);
|
|
647
761
|
}
|
|
@@ -699,6 +813,27 @@ export class DefaultActionDockHost {
|
|
|
699
813
|
}
|
|
700
814
|
throw new ActionDockError(PACKAGE_ID_CONFLICT, `Package ID conflict: package '${runtime.packageId}' is already registered in host`);
|
|
701
815
|
}
|
|
816
|
+
const explicitBindings = this.options.actionBindings;
|
|
817
|
+
const bindings = explicitBindings && Object.hasOwn(explicitBindings, runtime.packageId)
|
|
818
|
+
? validateActionBindings(explicitBindings[runtime.packageId])
|
|
819
|
+
: runtime.packageRoot ? loadActionBindings(runtime.packageRoot) : validateActionBindings({});
|
|
820
|
+
for (const group of Object.values(bindings)) {
|
|
821
|
+
for (const target of Object.values(group)) {
|
|
822
|
+
if (target.type !== "remote" || this.remoteTargets.has(target.profile))
|
|
823
|
+
continue;
|
|
824
|
+
const resolved = resolveTarget({ profile: target.profile }, this.options.customHome);
|
|
825
|
+
if (resolved.type !== "remote" || !resolved.serverUrl) {
|
|
826
|
+
throw new ActionDockError(INVALID_ACTION_REF, `Binding profile '${target.profile}' must identify a remote service`);
|
|
827
|
+
}
|
|
828
|
+
this.remoteTargets.set(target.profile, Object.freeze({
|
|
829
|
+
serverUrl: resolved.serverUrl,
|
|
830
|
+
token: resolved.token,
|
|
831
|
+
insecure: resolved.insecure,
|
|
832
|
+
allowInsecureHttp: resolved.allowInsecureHttp,
|
|
833
|
+
}));
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
this.actionBindings.set(runtime.packageId, bindings);
|
|
702
837
|
this.runtimes.set(runtime.packageId, runtime);
|
|
703
838
|
if (isPublic) {
|
|
704
839
|
this.hostPublicPackageIds.add(runtime.packageId);
|
|
@@ -856,8 +991,182 @@ export class DefaultActionDockHost {
|
|
|
856
991
|
process: this.options.process,
|
|
857
992
|
origin: effectiveOptions.origin,
|
|
858
993
|
});
|
|
859
|
-
//
|
|
860
|
-
return
|
|
994
|
+
// 调度目标包执行服务(经由本地分发中枢统一准备与复核)
|
|
995
|
+
return this.dispatchLocalInvocation(targetRuntime, targetActionId, input, rootContext);
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* 私有本地 Action 调度中枢。
|
|
999
|
+
* 统一处理本地已授权目标的准备(若已注入 prepareLocalPackage 且存在物理包根路径)、
|
|
1000
|
+
* 中断与关闭复核,并分发至目标 Runtime 的 startInvocation。
|
|
1001
|
+
*/
|
|
1002
|
+
async dispatchLocalInvocation(targetRuntime, targetActionId, input, context) {
|
|
1003
|
+
if (this.isClosed) {
|
|
1004
|
+
const runId = context.runId;
|
|
1005
|
+
const error = buildRuntimeError(SERVICE_CLOSED, "ActionDockHost is closed: new tasks rejected", { package: targetRuntime.packageId, action: targetActionId, phase: "dispatch" });
|
|
1006
|
+
return {
|
|
1007
|
+
runId,
|
|
1008
|
+
status: "failed",
|
|
1009
|
+
result: Promise.resolve({ ok: false, runId, error }),
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
const isRootCall = !context.caller;
|
|
1013
|
+
const initialTimeoutMs = context.initialTimeoutMs ?? (typeof context.timeoutMs === "number" && context.timeoutMs > 0 ? context.timeoutMs : undefined);
|
|
1014
|
+
const deadline = context.deadline ?? (initialTimeoutMs !== undefined ? Date.now() + initialTimeoutMs : undefined);
|
|
1015
|
+
if (context.signal.aborted) {
|
|
1016
|
+
const runId = context.runId;
|
|
1017
|
+
const isTimeout = isActionTimeoutReason(context.signal.reason);
|
|
1018
|
+
const error = buildRuntimeError(isTimeout ? ACTION_TIMEOUT : ACTION_CANCELLED, isTimeout
|
|
1019
|
+
? `Action exceeded timeout of ${initialTimeoutMs ?? context.timeoutMs}ms`
|
|
1020
|
+
: "Action execution was cancelled before starting", { package: targetRuntime.packageId, action: targetActionId, phase: "dispatch" });
|
|
1021
|
+
return {
|
|
1022
|
+
runId,
|
|
1023
|
+
status: "failed",
|
|
1024
|
+
result: Promise.resolve({ ok: false, runId, error }),
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
let timeoutController;
|
|
1028
|
+
let prepTimeoutTimer;
|
|
1029
|
+
if (isRootCall && typeof context.timeoutMs === "number" && context.timeoutMs > 0) {
|
|
1030
|
+
timeoutController = new AbortController();
|
|
1031
|
+
const remaining = deadline ? Math.max(0, deadline - Date.now()) : context.timeoutMs;
|
|
1032
|
+
const timeoutReason = new ActionDockError(ACTION_TIMEOUT, `Action exceeded timeout of ${initialTimeoutMs ?? context.timeoutMs}ms`, { package: targetRuntime.packageId, action: targetActionId, phase: "preparation" });
|
|
1033
|
+
if (remaining <= 0) {
|
|
1034
|
+
timeoutController.abort(timeoutReason);
|
|
1035
|
+
}
|
|
1036
|
+
else {
|
|
1037
|
+
prepTimeoutTimer = setTimeout(() => {
|
|
1038
|
+
timeoutController?.abort(timeoutReason);
|
|
1039
|
+
}, remaining);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
const signalSources = [context.signal, this.closeController.signal];
|
|
1043
|
+
if (timeoutController) {
|
|
1044
|
+
signalSources.push(timeoutController.signal);
|
|
1045
|
+
}
|
|
1046
|
+
const mergedSignal = AbortSignal.any(signalSources);
|
|
1047
|
+
if (this.prepareLocalPackage && targetRuntime.packageRoot) {
|
|
1048
|
+
const prepPromise = Promise.resolve().then(() => this.prepareLocalPackage({
|
|
1049
|
+
identity: targetRuntime.identity,
|
|
1050
|
+
packageRoot: targetRuntime.packageRoot,
|
|
1051
|
+
}, {
|
|
1052
|
+
signal: mergedSignal,
|
|
1053
|
+
rootRunId: context.rootRunId,
|
|
1054
|
+
}));
|
|
1055
|
+
this.activePreparations.add(prepPromise);
|
|
1056
|
+
try {
|
|
1057
|
+
await prepPromise;
|
|
1058
|
+
}
|
|
1059
|
+
catch (err) {
|
|
1060
|
+
if (prepTimeoutTimer !== undefined) {
|
|
1061
|
+
clearTimeout(prepTimeoutTimer);
|
|
1062
|
+
prepTimeoutTimer = undefined;
|
|
1063
|
+
}
|
|
1064
|
+
const errCode = err?.code;
|
|
1065
|
+
const isClosed = this.closeController.signal.aborted;
|
|
1066
|
+
const isExternalCancelled = context.signal.aborted;
|
|
1067
|
+
const isTimeout = timeoutController?.signal.aborted ||
|
|
1068
|
+
isActionTimeoutReason(context.signal.reason) ||
|
|
1069
|
+
errCode === ACTION_TIMEOUT ||
|
|
1070
|
+
(err?.details && err.details.code === ACTION_TIMEOUT);
|
|
1071
|
+
let code;
|
|
1072
|
+
let message = err?.message || "Package preparation failed";
|
|
1073
|
+
if (isTimeout) {
|
|
1074
|
+
code = ACTION_TIMEOUT;
|
|
1075
|
+
message = (err?.message && err.message.includes("exceeded timeout"))
|
|
1076
|
+
? err.message
|
|
1077
|
+
: `Action exceeded timeout of ${initialTimeoutMs ?? context.timeoutMs}ms`;
|
|
1078
|
+
}
|
|
1079
|
+
else if (err instanceof ActionDockError) {
|
|
1080
|
+
code = err.code;
|
|
1081
|
+
}
|
|
1082
|
+
else if (isClosed) {
|
|
1083
|
+
code = SERVICE_CLOSED;
|
|
1084
|
+
message = "ActionDockHost is closed: new tasks rejected";
|
|
1085
|
+
}
|
|
1086
|
+
else if (isExternalCancelled) {
|
|
1087
|
+
code = ACTION_CANCELLED;
|
|
1088
|
+
message = "Action execution was cancelled";
|
|
1089
|
+
}
|
|
1090
|
+
else if (err?.code && typeof err.code === "string") {
|
|
1091
|
+
code = err.code;
|
|
1092
|
+
}
|
|
1093
|
+
else {
|
|
1094
|
+
code = EXECUTION_FAILED;
|
|
1095
|
+
}
|
|
1096
|
+
const hint = err?.details?.hint ?? err?.hint;
|
|
1097
|
+
const details = {
|
|
1098
|
+
...(err?.details || {}),
|
|
1099
|
+
package: targetRuntime.packageId,
|
|
1100
|
+
action: targetActionId,
|
|
1101
|
+
phase: "preparation",
|
|
1102
|
+
...(hint ? { hint } : {}),
|
|
1103
|
+
};
|
|
1104
|
+
const runId = context.runId;
|
|
1105
|
+
const error = buildRuntimeError(code, message, details);
|
|
1106
|
+
return {
|
|
1107
|
+
runId,
|
|
1108
|
+
status: "failed",
|
|
1109
|
+
result: Promise.resolve({ ok: false, runId, error }),
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
finally {
|
|
1113
|
+
this.activePreparations.delete(prepPromise);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
if (prepTimeoutTimer !== undefined) {
|
|
1117
|
+
clearTimeout(prepTimeoutTimer);
|
|
1118
|
+
prepTimeoutTimer = undefined;
|
|
1119
|
+
}
|
|
1120
|
+
// 准备后再次复核取消与 Host 关闭状态
|
|
1121
|
+
if (this.isClosed || this.closeController.signal.aborted) {
|
|
1122
|
+
const runId = context.runId;
|
|
1123
|
+
const error = buildRuntimeError(SERVICE_CLOSED, "ActionDockHost is closed: new tasks rejected", { package: targetRuntime.packageId, action: targetActionId, phase: "post-preparation" });
|
|
1124
|
+
return {
|
|
1125
|
+
runId,
|
|
1126
|
+
status: "failed",
|
|
1127
|
+
result: Promise.resolve({ ok: false, runId, error }),
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
if (context.signal.aborted) {
|
|
1131
|
+
const runId = context.runId;
|
|
1132
|
+
const isTimeout = isActionTimeoutReason(context.signal.reason);
|
|
1133
|
+
const error = buildRuntimeError(isTimeout ? ACTION_TIMEOUT : ACTION_CANCELLED, isTimeout
|
|
1134
|
+
? `Action exceeded timeout of ${initialTimeoutMs ?? context.timeoutMs}ms`
|
|
1135
|
+
: "Action execution was cancelled after preparation", { package: targetRuntime.packageId, action: targetActionId, phase: "post-preparation" });
|
|
1136
|
+
return {
|
|
1137
|
+
runId,
|
|
1138
|
+
status: "failed",
|
|
1139
|
+
result: Promise.resolve({ ok: false, runId, error }),
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
const remainingBudget = deadline !== undefined
|
|
1143
|
+
? Math.max(0, deadline - Date.now())
|
|
1144
|
+
: context.timeoutMs;
|
|
1145
|
+
if (deadline !== undefined && typeof remainingBudget === "number" && remainingBudget <= 0) {
|
|
1146
|
+
const runId = context.runId;
|
|
1147
|
+
const error = buildRuntimeError(ACTION_TIMEOUT, `Action exceeded timeout of ${initialTimeoutMs ?? context.timeoutMs}ms`, { package: targetRuntime.packageId, action: targetActionId, phase: "post-preparation" });
|
|
1148
|
+
return {
|
|
1149
|
+
runId,
|
|
1150
|
+
status: "failed",
|
|
1151
|
+
result: Promise.resolve({ ok: false, runId, error }),
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
const effectiveContext = {
|
|
1155
|
+
...context,
|
|
1156
|
+
signal: mergedSignal,
|
|
1157
|
+
initialTimeoutMs,
|
|
1158
|
+
deadline,
|
|
1159
|
+
timeoutMs: remainingBudget,
|
|
1160
|
+
};
|
|
1161
|
+
const ticket = await targetRuntime.startInvocation(targetActionId, input, effectiveContext);
|
|
1162
|
+
if (ticket.result) {
|
|
1163
|
+
ticket.result.finally(() => {
|
|
1164
|
+
if (prepTimeoutTimer !== undefined) {
|
|
1165
|
+
clearTimeout(prepTimeoutTimer);
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
return ticket;
|
|
861
1170
|
}
|
|
862
1171
|
async getRun(runId, signal) {
|
|
863
1172
|
await this.ensureInitialized();
|
|
@@ -1227,31 +1536,47 @@ export class DefaultActionDockHost {
|
|
|
1227
1536
|
}) ||
|
|
1228
1537
|
Array.from(this.runtimes.values()).some((rt) => Boolean(rt.inMemory || rt.options?.inMemory));
|
|
1229
1538
|
const inMemory = Boolean(this.options.inMemory || hasInMemoryPackage);
|
|
1539
|
+
// 旧版本全局库迁移的声明并集:取首次打开时已加载包的声明字典;
|
|
1540
|
+
// 后续 registerRuntime 带来的新声明属当前版本正常写入,不重跑历史迁移
|
|
1541
|
+
const configDeclarations = this.listRuntimes()
|
|
1542
|
+
.map((runtime) => runtime.projectConfig?.config)
|
|
1543
|
+
.filter((config) => Boolean(config && Object.keys(config).length > 0));
|
|
1230
1544
|
this.globalStorage =
|
|
1231
1545
|
this.options.platform?.storage?.createGlobalStorage?.({
|
|
1232
1546
|
dataDir: this.options.dataDir,
|
|
1233
1547
|
customHome: this.options.customHome,
|
|
1234
1548
|
...(inMemory ? { inMemory: true } : {}),
|
|
1549
|
+
configDeclarations,
|
|
1235
1550
|
}) ??
|
|
1236
1551
|
createGlobalStorage({
|
|
1237
1552
|
dataDir: this.options.dataDir,
|
|
1238
1553
|
customHome: this.options.customHome,
|
|
1239
1554
|
inMemory,
|
|
1555
|
+
configDeclarations,
|
|
1240
1556
|
});
|
|
1241
1557
|
}
|
|
1242
1558
|
return this.globalStorage;
|
|
1243
1559
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1560
|
+
findAllDeclaredConfigItems(key) {
|
|
1561
|
+
const items = [];
|
|
1246
1562
|
for (const runtime of this.listRuntimes()) {
|
|
1247
|
-
const
|
|
1248
|
-
if (item) {
|
|
1249
|
-
|
|
1250
|
-
return item;
|
|
1251
|
-
foundItem = item;
|
|
1563
|
+
const decl = resolveConfigDeclaration(runtime.projectConfig?.config, key);
|
|
1564
|
+
if (decl?.item) {
|
|
1565
|
+
items.push(decl.item);
|
|
1252
1566
|
}
|
|
1253
1567
|
}
|
|
1254
|
-
return
|
|
1568
|
+
return items;
|
|
1569
|
+
}
|
|
1570
|
+
protectGlobalConfigView(view) {
|
|
1571
|
+
if (view.source !== "global")
|
|
1572
|
+
return view;
|
|
1573
|
+
const items = this.findAllDeclaredConfigItems(view.key);
|
|
1574
|
+
if (items.length === 0)
|
|
1575
|
+
return view;
|
|
1576
|
+
// 外部注入的运行时可能持有独立全局库;只能加强它返回的安全值,不能换读 Host 的库。
|
|
1577
|
+
const merged = redactConfigValueForDeclarations(view.value, items);
|
|
1578
|
+
const safe = redactConfigValueAtPaths(merged.value, [...view.redactedPaths, ...merged.redactedPaths]);
|
|
1579
|
+
return { ...view, ...safe, secret: view.secret || merged.secret };
|
|
1255
1580
|
}
|
|
1256
1581
|
resolveRuntime(packageId) {
|
|
1257
1582
|
if (packageId) {
|
|
@@ -1272,32 +1597,43 @@ export class DefaultActionDockHost {
|
|
|
1272
1597
|
}
|
|
1273
1598
|
async getConfig(packageId, key) {
|
|
1274
1599
|
await this.ensureInitialized();
|
|
1600
|
+
assertConcreteConfigKey(key);
|
|
1275
1601
|
if (packageId === "global") {
|
|
1276
1602
|
const globalStorage = this.getGlobalStorage();
|
|
1277
|
-
|
|
1278
|
-
const
|
|
1279
|
-
const
|
|
1280
|
-
const
|
|
1603
|
+
// 原子快照配对读取值与历史保护声明,消除并发删除造成的值与规则错配
|
|
1604
|
+
const snapshot = readConfigWithProtection(globalStorage, key);
|
|
1605
|
+
const configured = snapshot !== undefined;
|
|
1606
|
+
const items = this.findAllDeclaredConfigItems(key);
|
|
1607
|
+
const redacted = redactConfigValueWithProtection(snapshot?.value, items, snapshot?.protection);
|
|
1281
1608
|
return {
|
|
1282
1609
|
key,
|
|
1283
1610
|
configured,
|
|
1284
|
-
secret:
|
|
1285
|
-
source: configured ? "global" :
|
|
1286
|
-
value:
|
|
1611
|
+
secret: redacted.secret,
|
|
1612
|
+
source: configured ? "global" : null,
|
|
1613
|
+
value: redacted.value,
|
|
1614
|
+
redactedPaths: redacted.redactedPaths,
|
|
1287
1615
|
};
|
|
1288
1616
|
}
|
|
1289
|
-
return this.requireRuntime(packageId).getConfig(key);
|
|
1617
|
+
return this.protectGlobalConfigView(await this.requireRuntime(packageId).getConfig(key));
|
|
1290
1618
|
}
|
|
1291
1619
|
async setConfig(packageId, key, value) {
|
|
1292
1620
|
await this.ensureInitialized();
|
|
1621
|
+
assertConcreteConfigKey(key);
|
|
1293
1622
|
if (packageId === "global") {
|
|
1294
|
-
|
|
1623
|
+
const items = this.findAllDeclaredConfigItems(key);
|
|
1624
|
+
for (const item of items) {
|
|
1625
|
+
validateConfigValue(key, value, item);
|
|
1626
|
+
}
|
|
1627
|
+
// 传递全部已加载包各自解析出的有效声明并集(各包内具体键优先于模板),
|
|
1628
|
+
// 由存储统一判定整键加密并合并历史保护
|
|
1629
|
+
await this.getGlobalStorage().setConfig(key, value, items.length > 0 ? { declarations: items } : undefined);
|
|
1295
1630
|
return;
|
|
1296
1631
|
}
|
|
1297
1632
|
await this.requireRuntime(packageId).setConfig(key, value);
|
|
1298
1633
|
}
|
|
1299
1634
|
async deleteConfig(packageId, key) {
|
|
1300
1635
|
await this.ensureInitialized();
|
|
1636
|
+
assertConcreteConfigKey(key);
|
|
1301
1637
|
if (packageId === "global") {
|
|
1302
1638
|
return await this.getGlobalStorage().deleteConfig(key);
|
|
1303
1639
|
}
|
|
@@ -1308,19 +1644,32 @@ export class DefaultActionDockHost {
|
|
|
1308
1644
|
if (packageId === "global") {
|
|
1309
1645
|
const globalStorage = this.getGlobalStorage();
|
|
1310
1646
|
const all = globalStorage.listConfig();
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1647
|
+
const views = [];
|
|
1648
|
+
for (const key of Object.keys(all)) {
|
|
1649
|
+
if (isConfigTemplate(key)) {
|
|
1650
|
+
continue;
|
|
1651
|
+
}
|
|
1652
|
+
// 同源原子重读:值与历史保护声明取自同一次读取;
|
|
1653
|
+
// 行在列键之后又被并发删除时跳过该项,不回退旧值
|
|
1654
|
+
const snapshot = readConfigWithProtection(globalStorage, key);
|
|
1655
|
+
if (snapshot === undefined) {
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
const items = this.findAllDeclaredConfigItems(key);
|
|
1659
|
+
const redacted = redactConfigValueWithProtection(snapshot.value, items, snapshot.protection);
|
|
1660
|
+
views.push({
|
|
1315
1661
|
key,
|
|
1316
1662
|
configured: true,
|
|
1317
|
-
secret:
|
|
1663
|
+
secret: redacted.secret,
|
|
1318
1664
|
source: "global",
|
|
1319
|
-
value:
|
|
1320
|
-
|
|
1321
|
-
|
|
1665
|
+
value: redacted.value,
|
|
1666
|
+
redactedPaths: redacted.redactedPaths,
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
return views;
|
|
1322
1670
|
}
|
|
1323
|
-
|
|
1671
|
+
const views = await this.requireRuntime(packageId).listConfig();
|
|
1672
|
+
return views.map((view) => this.protectGlobalConfigView(view));
|
|
1324
1673
|
}
|
|
1325
1674
|
async getState(packageId, actionId, key, options) {
|
|
1326
1675
|
await this.ensureInitialized();
|
|
@@ -1365,33 +1714,48 @@ export class DefaultActionDockHost {
|
|
|
1365
1714
|
* 外部传入借用的 Runtime 实例生命周期完全由调用方负责管理,Host 关闭时仅解绑引用并清理自身内部实例。
|
|
1366
1715
|
*/
|
|
1367
1716
|
async close(options) {
|
|
1717
|
+
if (this.closePromise)
|
|
1718
|
+
return this.closePromise;
|
|
1368
1719
|
if (this.isClosed)
|
|
1369
1720
|
return;
|
|
1370
|
-
this.
|
|
1371
|
-
|
|
1372
|
-
|
|
1721
|
+
this.closePromise = (async () => {
|
|
1722
|
+
this.isClosed = true;
|
|
1723
|
+
this.closeController.abort(new ActionDockError(SERVICE_CLOSED, "ActionDockHost is closing"));
|
|
1724
|
+
if (this.activePreparations.size > 0) {
|
|
1725
|
+
await Promise.allSettled(Array.from(this.activePreparations));
|
|
1726
|
+
}
|
|
1727
|
+
const allRuntimes = Array.from(this.runtimes.values());
|
|
1728
|
+
await Promise.all(allRuntimes.map(async (runtime) => {
|
|
1729
|
+
try {
|
|
1730
|
+
await runtime.close(options);
|
|
1731
|
+
}
|
|
1732
|
+
catch {
|
|
1733
|
+
// 忽略 Runtime 关闭异常,确保全部安全释放
|
|
1734
|
+
}
|
|
1735
|
+
}));
|
|
1736
|
+
const invocationCloseErrors = await this.closeInvocationTargets();
|
|
1737
|
+
this.runtimes.clear();
|
|
1738
|
+
this.actionBindings.clear();
|
|
1739
|
+
this.remoteTargets.clear();
|
|
1740
|
+
await this.remoteInvoker.close();
|
|
1373
1741
|
try {
|
|
1374
|
-
|
|
1742
|
+
this.globalStorage?.close();
|
|
1375
1743
|
}
|
|
1376
1744
|
catch {
|
|
1377
|
-
//
|
|
1745
|
+
// 忽略全局存储关闭异常
|
|
1378
1746
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
catch {
|
|
1392
|
-
// 忽略目录排他锁释放异常
|
|
1393
|
-
}
|
|
1394
|
-
this.dataDirLock = undefined;
|
|
1747
|
+
this.globalStorage = undefined;
|
|
1748
|
+
try {
|
|
1749
|
+
this.dataDirLock?.release();
|
|
1750
|
+
}
|
|
1751
|
+
catch {
|
|
1752
|
+
// 忽略目录排他锁释放异常
|
|
1753
|
+
}
|
|
1754
|
+
this.dataDirLock = undefined;
|
|
1755
|
+
if (invocationCloseErrors.length)
|
|
1756
|
+
throw new AggregateError(invocationCloseErrors, "Invocation target cleanup failed");
|
|
1757
|
+
})();
|
|
1758
|
+
return this.closePromise;
|
|
1395
1759
|
}
|
|
1396
1760
|
}
|
|
1397
1761
|
/**
|