@actiondock/core 2.18.0 → 2.20.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/client/runs.d.ts +9 -0
- package/dist/client/runs.js +7 -0
- package/dist/errors.d.ts +3 -1
- package/dist/errors.js +2 -0
- package/dist/execution/service.js +8 -5
- package/dist/execution/types.d.ts +3 -3
- package/dist/host/host.d.ts +9 -1
- package/dist/host/host.js +266 -45
- package/dist/host/types.d.ts +3 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -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 +2 -0
- package/dist/invocation/types.js +1 -0
- package/dist/package/index.d.ts +1 -1
- package/dist/package/runtime.js +105 -15
- package/dist/platform/types.d.ts +48 -1
- package/dist/project/config-declarations.d.ts +61 -0
- package/dist/project/config-declarations.js +297 -0
- package/dist/project/index.d.ts +5 -2
- package/dist/project/index.js +5 -2
- package/dist/project/init.js +2 -2
- package/dist/project/loader.js +4 -0
- package/dist/project/manifest.js +10 -0
- package/dist/project/types.d.ts +30 -0
- package/dist/runtime/context.d.ts +6 -3
- package/dist/runtime/context.js +60 -13
- package/dist/runtime/env.js +15 -1
- 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/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 +65 -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 +112 -18
- package/dist/server/server.d.ts +2 -1
- package/dist/server/server.js +38 -55
- package/dist/server/types.d.ts +6 -6
- package/dist/service/factory.js +1 -0
- package/dist/service/remote.js +28 -29
- package/dist/service/types.d.ts +34 -5
- package/dist/service/types.js +8 -0
- package/dist/storage/mask.d.ts +33 -6
- package/dist/storage/mask.js +298 -16
- package/dist/storage/sqlite-runs.d.ts +5 -17
- package/dist/storage/sqlite-runs.js +127 -5
- package/dist/storage/sqlite.d.ts +5 -17
- package/dist/storage/sqlite.js +2 -2
- package/dist/storage/types.d.ts +31 -16
- 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, 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 } 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 &&
|
|
@@ -60,6 +64,8 @@ export class DefaultActionDockHost {
|
|
|
60
64
|
hostSessionId;
|
|
61
65
|
options;
|
|
62
66
|
runtimes = new Map();
|
|
67
|
+
extraRuntimes = new Set();
|
|
68
|
+
extraRuntimeScopes = new Map();
|
|
63
69
|
policy;
|
|
64
70
|
hostPublicPackageIds = new Set();
|
|
65
71
|
maxCallDepth;
|
|
@@ -76,6 +82,9 @@ export class DefaultActionDockHost {
|
|
|
76
82
|
globalStorage;
|
|
77
83
|
initPromise;
|
|
78
84
|
isInitialized = false;
|
|
85
|
+
actionBindings = new Map();
|
|
86
|
+
remoteTargets = new Map();
|
|
87
|
+
remoteInvoker;
|
|
79
88
|
discovery;
|
|
80
89
|
execution;
|
|
81
90
|
runs;
|
|
@@ -100,6 +109,7 @@ export class DefaultActionDockHost {
|
|
|
100
109
|
}
|
|
101
110
|
this.hostSessionId = randomUUID();
|
|
102
111
|
this.options = options;
|
|
112
|
+
this.remoteInvoker = new RemoteInvocationExecutor({ logger: options.logger });
|
|
103
113
|
this.maxCallDepth = options.maxCallDepth ?? 16;
|
|
104
114
|
this.maxSubRuns = options.maxSubRuns ?? 64;
|
|
105
115
|
this.policy = new InvocationPolicy({
|
|
@@ -348,6 +358,21 @@ export class DefaultActionDockHost {
|
|
|
348
358
|
// 持有者在返回前打开共享全局存储,保留对全局库存储错误的提前发现能力
|
|
349
359
|
this.getGlobalStorage();
|
|
350
360
|
}
|
|
361
|
+
/** 返回的 Runtime 由 Host 统一接管,端口只清理自身缓存和附属资源。 */
|
|
362
|
+
async closeInvocationTargets() {
|
|
363
|
+
const extras = Array.from(this.extraRuntimes).filter((runtime) => this.runtimes.get(runtime.packageId) !== runtime);
|
|
364
|
+
this.extraRuntimes.clear();
|
|
365
|
+
this.extraRuntimeScopes.clear();
|
|
366
|
+
const results = await Promise.allSettled(extras.map((runtime) => runtime.close()));
|
|
367
|
+
const errors = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
368
|
+
try {
|
|
369
|
+
await this.options.platform?.invocationTargets?.close?.();
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
errors.push(error);
|
|
373
|
+
}
|
|
374
|
+
return errors;
|
|
375
|
+
}
|
|
351
376
|
/**
|
|
352
377
|
* 异步安全回滚初始化失败时所占用的资源。
|
|
353
378
|
*/
|
|
@@ -363,7 +388,11 @@ export class DefaultActionDockHost {
|
|
|
363
388
|
// 忽略 Runtime 关闭异常
|
|
364
389
|
}
|
|
365
390
|
}));
|
|
391
|
+
const invocationCloseErrors = await this.closeInvocationTargets();
|
|
366
392
|
this.runtimes.clear();
|
|
393
|
+
this.actionBindings.clear();
|
|
394
|
+
this.remoteTargets.clear();
|
|
395
|
+
await this.remoteInvoker.close();
|
|
367
396
|
try {
|
|
368
397
|
this.globalStorage?.close();
|
|
369
398
|
}
|
|
@@ -379,6 +408,8 @@ export class DefaultActionDockHost {
|
|
|
379
408
|
}
|
|
380
409
|
this.dataDirLock = undefined;
|
|
381
410
|
this.isClosed = true;
|
|
411
|
+
if (invocationCloseErrors.length)
|
|
412
|
+
throw new AggregateError(invocationCloseErrors, "Invocation target cleanup failed");
|
|
382
413
|
}
|
|
383
414
|
/**
|
|
384
415
|
* 阶段函数:注册显式传入的 packages 列表(PackageRuntimeOptions 配置或包目录物理路径)。
|
|
@@ -551,21 +582,75 @@ export class DefaultActionDockHost {
|
|
|
551
582
|
* 铁律 2:跨包调用改走 ActionInvoker 回到 Host 执行主链,经由唯一的 InvocationPolicy 授权后调用目标 Package 的 ExecutionService。
|
|
552
583
|
*/
|
|
553
584
|
createActionInvoker(callerRuntime) {
|
|
554
|
-
return async (childAction, childInput, context) => {
|
|
555
|
-
|
|
585
|
+
return async (childAction, childInput, context, options) => {
|
|
586
|
+
if (this.isClosed)
|
|
587
|
+
throw new ActionDockError(SERVICE_CLOSED, "ActionDockHost is closed");
|
|
588
|
+
if (context.signal.aborted)
|
|
589
|
+
throw new ActionDockError(ACTION_CANCELLED, "Caller invocation is cancelled");
|
|
590
|
+
const parsed = parseActionRef(childAction);
|
|
591
|
+
// 裸引用仍由既有解析器消歧;远端专属依赖须使用完全限定引用。
|
|
592
|
+
const localResolved = parsed.packageId ? undefined : resolveAction(childAction, {
|
|
556
593
|
caller: callerRuntime.packageId,
|
|
557
594
|
graph: this.graph,
|
|
558
595
|
catalog: this.catalog,
|
|
559
596
|
});
|
|
560
|
-
const targetPackageId =
|
|
561
|
-
const targetActionId =
|
|
562
|
-
const
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
597
|
+
const targetPackageId = parsed.packageId ?? localResolved.package.id;
|
|
598
|
+
const targetActionId = parsed.actionId;
|
|
599
|
+
const canonicalRef = `${targetPackageId}/${targetActionId}`;
|
|
600
|
+
const canonicalActionRef = { packageId: targetPackageId, actionId: targetActionId };
|
|
601
|
+
const callerBindings = this.actionBindings.get(callerRuntime.packageId) ?? {};
|
|
602
|
+
const isNamedTarget = Boolean(options?.binding && options.binding !== "default");
|
|
603
|
+
// 目标装配是同步解析,不在此引入另一条执行或网络调用链。
|
|
604
|
+
const targetOverride = this.options.platform?.invocationTargets?.resolve(canonicalActionRef, options, {
|
|
605
|
+
packageId: callerRuntime.packageId,
|
|
606
|
+
actionId: context.caller?.actionId,
|
|
607
|
+
});
|
|
608
|
+
let targetRuntime;
|
|
609
|
+
let targetScope;
|
|
610
|
+
let isRemote = false;
|
|
611
|
+
let remoteProfile;
|
|
612
|
+
if (targetOverride) {
|
|
613
|
+
if (targetOverride.runtime.packageId !== targetPackageId) {
|
|
614
|
+
throw new ActionDockError(INVALID_ACTION_REF, `Invocation target packageId mismatch: expected '${targetPackageId}', got '${targetOverride.runtime.packageId}'`);
|
|
615
|
+
}
|
|
616
|
+
targetRuntime = targetOverride.runtime;
|
|
617
|
+
this.extraRuntimes.add(targetRuntime);
|
|
618
|
+
this.bindRuntime(targetRuntime);
|
|
619
|
+
targetScope = targetOverride.scope ?? (isNamedTarget ? `binding:${options?.binding}` : undefined);
|
|
620
|
+
if (targetScope)
|
|
621
|
+
this.extraRuntimeScopes.set(targetRuntime, targetScope);
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
// 没有绑定的旧调用不引入额外的清单命名约束,保持编程式 Runtime 兼容。
|
|
625
|
+
const binding = options?.binding !== undefined || Object.hasOwn(callerBindings, canonicalRef)
|
|
626
|
+
? resolveActionBinding(callerBindings, canonicalRef, options?.binding)
|
|
627
|
+
: undefined;
|
|
628
|
+
if (binding?.type === "remote") {
|
|
629
|
+
isRemote = true;
|
|
630
|
+
remoteProfile = binding.profile;
|
|
631
|
+
targetScope = `profile:${binding.profile}`;
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
isRemote = false;
|
|
635
|
+
if (!localResolved) {
|
|
636
|
+
resolveAction(childAction, { caller: callerRuntime.packageId, graph: this.graph, catalog: this.catalog });
|
|
637
|
+
}
|
|
638
|
+
const isLogicalSamePackage = targetPackageId === callerRuntime.packageId;
|
|
639
|
+
targetRuntime = isLogicalSamePackage ? callerRuntime : this.getRuntime(targetPackageId);
|
|
640
|
+
if (targetRuntime)
|
|
641
|
+
targetScope = this.extraRuntimeScopes.get(targetRuntime);
|
|
642
|
+
if (!targetRuntime) {
|
|
643
|
+
throw new ActionDockError(PACKAGE_NOT_FOUND, packageNotFoundMessage(targetPackageId, this.failedLinkedPackages));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
566
646
|
}
|
|
647
|
+
const isLogicalSamePackage = targetPackageId === callerRuntime.packageId;
|
|
648
|
+
const isPhysicalSameRuntime = Boolean(targetRuntime && targetRuntime === callerRuntime);
|
|
649
|
+
const requiresExplicitUses = Boolean(isRemote ||
|
|
650
|
+
targetOverride?.requiresExplicitUses ||
|
|
651
|
+
(isNamedTarget && targetOverride !== undefined));
|
|
567
652
|
// 跨包 uses 依赖声明校验(统一委托 InvocationPolicy 单一事实源)
|
|
568
|
-
if (!
|
|
653
|
+
if (!isLogicalSamePackage || requiresExplicitUses) {
|
|
569
654
|
let declaredUses = context.caller?.declaredUses;
|
|
570
655
|
if (!declaredUses) {
|
|
571
656
|
try {
|
|
@@ -580,7 +665,11 @@ export class DefaultActionDockHost {
|
|
|
580
665
|
packageId: callerRuntime.packageId,
|
|
581
666
|
actionId: context.caller?.actionId || "",
|
|
582
667
|
declaredUses,
|
|
583
|
-
}, {
|
|
668
|
+
}, {
|
|
669
|
+
packageId: targetPackageId,
|
|
670
|
+
actionId: targetActionId,
|
|
671
|
+
requiresExplicitUses,
|
|
672
|
+
}, this.graph);
|
|
584
673
|
if (authErr) {
|
|
585
674
|
const hint = authErr.details?.hint;
|
|
586
675
|
const msg = hint ? `${authErr.message}\n${hint}` : authErr.message;
|
|
@@ -593,7 +682,7 @@ export class DefaultActionDockHost {
|
|
|
593
682
|
throw new ActionDockError(depthErr.code, depthErr.message, depthErr.details);
|
|
594
683
|
}
|
|
595
684
|
// 调用链环路死锁检测
|
|
596
|
-
const cycle = this.policy.checkCycle(context.callStack, targetActionId, targetPackageId, callerRuntime.packageId);
|
|
685
|
+
const cycle = this.policy.checkCycle(context.callStack, targetActionId, targetPackageId, callerRuntime.packageId, targetScope);
|
|
597
686
|
if (cycle.error) {
|
|
598
687
|
throw new ActionDockError(cycle.error.code, cycle.error.message, cycle.error.details);
|
|
599
688
|
}
|
|
@@ -608,14 +697,18 @@ export class DefaultActionDockHost {
|
|
|
608
697
|
}
|
|
609
698
|
try {
|
|
610
699
|
const nextCallStack = [...context.callStack, cycle.callKey];
|
|
700
|
+
if (isRemote) {
|
|
701
|
+
const candidate = this.catalog.find({ packageId: targetPackageId, actionId: targetActionId })[0];
|
|
702
|
+
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);
|
|
703
|
+
}
|
|
611
704
|
const targetOwner = context.owner
|
|
612
705
|
? {
|
|
613
706
|
tenantId: context.owner.tenantId,
|
|
614
707
|
principalId: context.owner.principalId,
|
|
615
|
-
packageInstanceId:
|
|
708
|
+
packageInstanceId: isPhysicalSameRuntime
|
|
616
709
|
? (context.owner.packageInstanceId || callerRuntime.identity.instanceId)
|
|
617
710
|
: targetRuntime.identity.instanceId,
|
|
618
|
-
generationId:
|
|
711
|
+
generationId: isPhysicalSameRuntime
|
|
619
712
|
? (context.owner.generationId || callerRuntime.identity.generation)
|
|
620
713
|
: targetRuntime.identity.generation,
|
|
621
714
|
}
|
|
@@ -626,6 +719,7 @@ export class DefaultActionDockHost {
|
|
|
626
719
|
parentRunId: context.parentRunId,
|
|
627
720
|
caller: context.caller,
|
|
628
721
|
callStack: nextCallStack,
|
|
722
|
+
targetScope,
|
|
629
723
|
package: targetRuntime.identity,
|
|
630
724
|
signal: context.signal,
|
|
631
725
|
timeoutMs: context.timeoutMs,
|
|
@@ -699,6 +793,27 @@ export class DefaultActionDockHost {
|
|
|
699
793
|
}
|
|
700
794
|
throw new ActionDockError(PACKAGE_ID_CONFLICT, `Package ID conflict: package '${runtime.packageId}' is already registered in host`);
|
|
701
795
|
}
|
|
796
|
+
const explicitBindings = this.options.actionBindings;
|
|
797
|
+
const bindings = explicitBindings && Object.hasOwn(explicitBindings, runtime.packageId)
|
|
798
|
+
? validateActionBindings(explicitBindings[runtime.packageId])
|
|
799
|
+
: runtime.packageRoot ? loadActionBindings(runtime.packageRoot) : validateActionBindings({});
|
|
800
|
+
for (const group of Object.values(bindings)) {
|
|
801
|
+
for (const target of Object.values(group)) {
|
|
802
|
+
if (target.type !== "remote" || this.remoteTargets.has(target.profile))
|
|
803
|
+
continue;
|
|
804
|
+
const resolved = resolveTarget({ profile: target.profile }, this.options.customHome);
|
|
805
|
+
if (resolved.type !== "remote" || !resolved.serverUrl) {
|
|
806
|
+
throw new ActionDockError(INVALID_ACTION_REF, `Binding profile '${target.profile}' must identify a remote service`);
|
|
807
|
+
}
|
|
808
|
+
this.remoteTargets.set(target.profile, Object.freeze({
|
|
809
|
+
serverUrl: resolved.serverUrl,
|
|
810
|
+
token: resolved.token,
|
|
811
|
+
insecure: resolved.insecure,
|
|
812
|
+
allowInsecureHttp: resolved.allowInsecureHttp,
|
|
813
|
+
}));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
this.actionBindings.set(runtime.packageId, bindings);
|
|
702
817
|
this.runtimes.set(runtime.packageId, runtime);
|
|
703
818
|
if (isPublic) {
|
|
704
819
|
this.hostPublicPackageIds.add(runtime.packageId);
|
|
@@ -906,6 +1021,12 @@ export class DefaultActionDockHost {
|
|
|
906
1021
|
const batch = await runtime.listRuns({
|
|
907
1022
|
actionId: query.actionId,
|
|
908
1023
|
status: query.status,
|
|
1024
|
+
channel: query.channel,
|
|
1025
|
+
view: query.view,
|
|
1026
|
+
since: query.since,
|
|
1027
|
+
until: query.until,
|
|
1028
|
+
rootRunId: query.rootRunId,
|
|
1029
|
+
parentRunId: query.parentRunId,
|
|
909
1030
|
requestIds: query.requestIds,
|
|
910
1031
|
limit: BATCH_SIZE,
|
|
911
1032
|
offset: batchOffset,
|
|
@@ -921,8 +1042,21 @@ export class DefaultActionDockHost {
|
|
|
921
1042
|
...r,
|
|
922
1043
|
packageId: r.packageId || runtime.packageId,
|
|
923
1044
|
}));
|
|
924
|
-
|
|
925
|
-
|
|
1045
|
+
let filtered = normalized;
|
|
1046
|
+
if (query.channel)
|
|
1047
|
+
filtered = filtered.filter((r) => r.origin?.channel === query.channel);
|
|
1048
|
+
if (query.view)
|
|
1049
|
+
filtered = filtered.filter((r) => r.origin?.viewName === query.view);
|
|
1050
|
+
if (query.since)
|
|
1051
|
+
filtered = filtered.filter((r) => r.startedAt >= query.since);
|
|
1052
|
+
if (query.until)
|
|
1053
|
+
filtered = filtered.filter((r) => r.startedAt <= query.until);
|
|
1054
|
+
if (query.rootRunId)
|
|
1055
|
+
filtered = filtered.filter((r) => r.rootRunId === query.rootRunId);
|
|
1056
|
+
if (query.parentRunId)
|
|
1057
|
+
filtered = filtered.filter((r) => r.parentRunId === query.parentRunId);
|
|
1058
|
+
const intentMatched = filterByIntent(filtered, intentStr, [(r) => r.id, (r) => r.actionId, (r) => r.status, (r) => r.packageId], false);
|
|
1059
|
+
matchedRecords.push(...intentMatched);
|
|
926
1060
|
if (matchedRecords.length >= neededCount) {
|
|
927
1061
|
break;
|
|
928
1062
|
}
|
|
@@ -944,6 +1078,12 @@ export class DefaultActionDockHost {
|
|
|
944
1078
|
const batch = await runtime.listRuns({
|
|
945
1079
|
actionId: query.actionId,
|
|
946
1080
|
status: query.status,
|
|
1081
|
+
channel: query.channel,
|
|
1082
|
+
view: query.view,
|
|
1083
|
+
since: query.since,
|
|
1084
|
+
until: query.until,
|
|
1085
|
+
rootRunId: query.rootRunId,
|
|
1086
|
+
parentRunId: query.parentRunId,
|
|
947
1087
|
requestIds: query.requestIds,
|
|
948
1088
|
limit: BATCH_SIZE,
|
|
949
1089
|
offset: batchOffset,
|
|
@@ -959,8 +1099,21 @@ export class DefaultActionDockHost {
|
|
|
959
1099
|
...r,
|
|
960
1100
|
packageId: r.packageId || runtime.packageId,
|
|
961
1101
|
}));
|
|
962
|
-
|
|
963
|
-
|
|
1102
|
+
let filtered = normalized;
|
|
1103
|
+
if (query.channel)
|
|
1104
|
+
filtered = filtered.filter((r) => r.origin?.channel === query.channel);
|
|
1105
|
+
if (query.view)
|
|
1106
|
+
filtered = filtered.filter((r) => r.origin?.viewName === query.view);
|
|
1107
|
+
if (query.since)
|
|
1108
|
+
filtered = filtered.filter((r) => r.startedAt >= query.since);
|
|
1109
|
+
if (query.until)
|
|
1110
|
+
filtered = filtered.filter((r) => r.startedAt <= query.until);
|
|
1111
|
+
if (query.rootRunId)
|
|
1112
|
+
filtered = filtered.filter((r) => r.rootRunId === query.rootRunId);
|
|
1113
|
+
if (query.parentRunId)
|
|
1114
|
+
filtered = filtered.filter((r) => r.parentRunId === query.parentRunId);
|
|
1115
|
+
const intentMatched = filterByIntent(filtered, intentStr, [(r) => r.id, (r) => r.actionId, (r) => r.status, (r) => r.packageId], false);
|
|
1116
|
+
matchedRecords.push(...intentMatched);
|
|
964
1117
|
if (batch.length < BATCH_SIZE) {
|
|
965
1118
|
break;
|
|
966
1119
|
}
|
|
@@ -1043,6 +1196,12 @@ export class DefaultActionDockHost {
|
|
|
1043
1196
|
const batch = await runtime.listRuns({
|
|
1044
1197
|
actionId: query.actionId,
|
|
1045
1198
|
status: query.status,
|
|
1199
|
+
channel: query.channel,
|
|
1200
|
+
view: query.view,
|
|
1201
|
+
since: query.since,
|
|
1202
|
+
until: query.until,
|
|
1203
|
+
rootRunId: query.rootRunId,
|
|
1204
|
+
parentRunId: query.parentRunId,
|
|
1046
1205
|
requestIds: query.requestIds,
|
|
1047
1206
|
limit: BATCH_SIZE,
|
|
1048
1207
|
offset: batchOffset,
|
|
@@ -1058,8 +1217,21 @@ export class DefaultActionDockHost {
|
|
|
1058
1217
|
...r,
|
|
1059
1218
|
packageId: r.packageId || runtime.packageId,
|
|
1060
1219
|
}));
|
|
1061
|
-
|
|
1062
|
-
|
|
1220
|
+
let filtered = normalized;
|
|
1221
|
+
if (query.channel)
|
|
1222
|
+
filtered = filtered.filter((r) => r.origin?.channel === query.channel);
|
|
1223
|
+
if (query.view)
|
|
1224
|
+
filtered = filtered.filter((r) => r.origin?.viewName === query.view);
|
|
1225
|
+
if (query.since)
|
|
1226
|
+
filtered = filtered.filter((r) => r.startedAt >= query.since);
|
|
1227
|
+
if (query.until)
|
|
1228
|
+
filtered = filtered.filter((r) => r.startedAt <= query.until);
|
|
1229
|
+
if (query.rootRunId)
|
|
1230
|
+
filtered = filtered.filter((r) => r.rootRunId === query.rootRunId);
|
|
1231
|
+
if (query.parentRunId)
|
|
1232
|
+
filtered = filtered.filter((r) => r.parentRunId === query.parentRunId);
|
|
1233
|
+
const intentMatched = filterByIntent(filtered, intentStr, [(r) => r.id, (r) => r.actionId, (r) => r.status, (r) => r.packageId], false);
|
|
1234
|
+
count += intentMatched.length;
|
|
1063
1235
|
if (batch.length < BATCH_SIZE) {
|
|
1064
1236
|
break;
|
|
1065
1237
|
}
|
|
@@ -1079,6 +1251,12 @@ export class DefaultActionDockHost {
|
|
|
1079
1251
|
const all = await runtime.listRuns({
|
|
1080
1252
|
actionId: query?.actionId,
|
|
1081
1253
|
status: query?.status,
|
|
1254
|
+
channel: query?.channel,
|
|
1255
|
+
view: query?.view,
|
|
1256
|
+
since: query?.since,
|
|
1257
|
+
until: query?.until,
|
|
1258
|
+
rootRunId: query?.rootRunId,
|
|
1259
|
+
parentRunId: query?.parentRunId,
|
|
1082
1260
|
requestIds: query?.requestIds,
|
|
1083
1261
|
limit: 100_000,
|
|
1084
1262
|
signal: effectiveSignal,
|
|
@@ -1086,7 +1264,20 @@ export class DefaultActionDockHost {
|
|
|
1086
1264
|
if (effectiveSignal?.aborted) {
|
|
1087
1265
|
throw createAbortError(effectiveSignal.reason);
|
|
1088
1266
|
}
|
|
1089
|
-
|
|
1267
|
+
let filtered = all;
|
|
1268
|
+
if (query?.channel)
|
|
1269
|
+
filtered = filtered.filter((r) => r.origin?.channel === query.channel);
|
|
1270
|
+
if (query?.view)
|
|
1271
|
+
filtered = filtered.filter((r) => r.origin?.viewName === query.view);
|
|
1272
|
+
if (query?.since)
|
|
1273
|
+
filtered = filtered.filter((r) => r.startedAt >= query.since);
|
|
1274
|
+
if (query?.until)
|
|
1275
|
+
filtered = filtered.filter((r) => r.startedAt <= query.until);
|
|
1276
|
+
if (query?.rootRunId)
|
|
1277
|
+
filtered = filtered.filter((r) => r.rootRunId === query.rootRunId);
|
|
1278
|
+
if (query?.parentRunId)
|
|
1279
|
+
filtered = filtered.filter((r) => r.parentRunId === query.parentRunId);
|
|
1280
|
+
total += filtered.length;
|
|
1090
1281
|
}
|
|
1091
1282
|
}
|
|
1092
1283
|
return total;
|
|
@@ -1165,17 +1356,26 @@ export class DefaultActionDockHost {
|
|
|
1165
1356
|
}
|
|
1166
1357
|
return this.globalStorage;
|
|
1167
1358
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1359
|
+
findAllDeclaredConfigItems(key) {
|
|
1360
|
+
const items = [];
|
|
1170
1361
|
for (const runtime of this.listRuntimes()) {
|
|
1171
|
-
const
|
|
1172
|
-
if (item) {
|
|
1173
|
-
|
|
1174
|
-
return item;
|
|
1175
|
-
foundItem = item;
|
|
1362
|
+
const decl = resolveConfigDeclaration(runtime.projectConfig?.config, key);
|
|
1363
|
+
if (decl?.item) {
|
|
1364
|
+
items.push(decl.item);
|
|
1176
1365
|
}
|
|
1177
1366
|
}
|
|
1178
|
-
return
|
|
1367
|
+
return items;
|
|
1368
|
+
}
|
|
1369
|
+
protectGlobalConfigView(view) {
|
|
1370
|
+
if (view.source !== "global")
|
|
1371
|
+
return view;
|
|
1372
|
+
const items = this.findAllDeclaredConfigItems(view.key);
|
|
1373
|
+
if (items.length === 0)
|
|
1374
|
+
return view;
|
|
1375
|
+
// 外部注入的运行时可能持有独立全局库;只能加强它返回的安全值,不能换读 Host 的库。
|
|
1376
|
+
const merged = redactConfigValueForDeclarations(view.value, items);
|
|
1377
|
+
const safe = redactConfigValueAtPaths(merged.value, [...view.redactedPaths, ...merged.redactedPaths]);
|
|
1378
|
+
return { ...view, ...safe, secret: view.secret || merged.secret };
|
|
1179
1379
|
}
|
|
1180
1380
|
resolveRuntime(packageId) {
|
|
1181
1381
|
if (packageId) {
|
|
@@ -1196,25 +1396,32 @@ export class DefaultActionDockHost {
|
|
|
1196
1396
|
}
|
|
1197
1397
|
async getConfig(packageId, key) {
|
|
1198
1398
|
await this.ensureInitialized();
|
|
1399
|
+
assertConcreteConfigKey(key);
|
|
1199
1400
|
if (packageId === "global") {
|
|
1200
1401
|
const globalStorage = this.getGlobalStorage();
|
|
1201
1402
|
const val = globalStorage.getConfig(key);
|
|
1202
1403
|
const configured = val !== undefined;
|
|
1203
|
-
const
|
|
1204
|
-
const
|
|
1404
|
+
const items = this.findAllDeclaredConfigItems(key);
|
|
1405
|
+
const redacted = redactConfigValueForDeclarations(val, items);
|
|
1205
1406
|
return {
|
|
1206
1407
|
key,
|
|
1207
1408
|
configured,
|
|
1208
|
-
secret:
|
|
1209
|
-
source: configured ? "global" :
|
|
1210
|
-
value:
|
|
1409
|
+
secret: redacted.secret,
|
|
1410
|
+
source: configured ? "global" : null,
|
|
1411
|
+
value: redacted.value,
|
|
1412
|
+
redactedPaths: redacted.redactedPaths,
|
|
1211
1413
|
};
|
|
1212
1414
|
}
|
|
1213
|
-
return this.requireRuntime(packageId).getConfig(key);
|
|
1415
|
+
return this.protectGlobalConfigView(await this.requireRuntime(packageId).getConfig(key));
|
|
1214
1416
|
}
|
|
1215
1417
|
async setConfig(packageId, key, value) {
|
|
1216
1418
|
await this.ensureInitialized();
|
|
1419
|
+
assertConcreteConfigKey(key);
|
|
1217
1420
|
if (packageId === "global") {
|
|
1421
|
+
const items = this.findAllDeclaredConfigItems(key);
|
|
1422
|
+
for (const item of items) {
|
|
1423
|
+
validateConfigValue(key, value, item);
|
|
1424
|
+
}
|
|
1218
1425
|
await this.getGlobalStorage().setConfig(key, value);
|
|
1219
1426
|
return;
|
|
1220
1427
|
}
|
|
@@ -1222,6 +1429,7 @@ export class DefaultActionDockHost {
|
|
|
1222
1429
|
}
|
|
1223
1430
|
async deleteConfig(packageId, key) {
|
|
1224
1431
|
await this.ensureInitialized();
|
|
1432
|
+
assertConcreteConfigKey(key);
|
|
1225
1433
|
if (packageId === "global") {
|
|
1226
1434
|
return await this.getGlobalStorage().deleteConfig(key);
|
|
1227
1435
|
}
|
|
@@ -1232,19 +1440,26 @@ export class DefaultActionDockHost {
|
|
|
1232
1440
|
if (packageId === "global") {
|
|
1233
1441
|
const globalStorage = this.getGlobalStorage();
|
|
1234
1442
|
const all = globalStorage.listConfig();
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1443
|
+
const views = [];
|
|
1444
|
+
for (const [key, val] of Object.entries(all)) {
|
|
1445
|
+
if (isConfigTemplate(key)) {
|
|
1446
|
+
continue;
|
|
1447
|
+
}
|
|
1448
|
+
const items = this.findAllDeclaredConfigItems(key);
|
|
1449
|
+
const redacted = redactConfigValueForDeclarations(val, items);
|
|
1450
|
+
views.push({
|
|
1239
1451
|
key,
|
|
1240
1452
|
configured: true,
|
|
1241
|
-
secret:
|
|
1453
|
+
secret: redacted.secret,
|
|
1242
1454
|
source: "global",
|
|
1243
|
-
value:
|
|
1244
|
-
|
|
1245
|
-
|
|
1455
|
+
value: redacted.value,
|
|
1456
|
+
redactedPaths: redacted.redactedPaths,
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
return views;
|
|
1246
1460
|
}
|
|
1247
|
-
|
|
1461
|
+
const views = await this.requireRuntime(packageId).listConfig();
|
|
1462
|
+
return views.map((view) => this.protectGlobalConfigView(view));
|
|
1248
1463
|
}
|
|
1249
1464
|
async getState(packageId, actionId, key, options) {
|
|
1250
1465
|
await this.ensureInitialized();
|
|
@@ -1301,7 +1516,11 @@ export class DefaultActionDockHost {
|
|
|
1301
1516
|
// 忽略 Runtime 关闭异常,确保全部安全释放
|
|
1302
1517
|
}
|
|
1303
1518
|
}));
|
|
1519
|
+
const invocationCloseErrors = await this.closeInvocationTargets();
|
|
1304
1520
|
this.runtimes.clear();
|
|
1521
|
+
this.actionBindings.clear();
|
|
1522
|
+
this.remoteTargets.clear();
|
|
1523
|
+
await this.remoteInvoker.close();
|
|
1305
1524
|
try {
|
|
1306
1525
|
this.globalStorage?.close();
|
|
1307
1526
|
}
|
|
@@ -1316,6 +1535,8 @@ export class DefaultActionDockHost {
|
|
|
1316
1535
|
// 忽略目录排他锁释放异常
|
|
1317
1536
|
}
|
|
1318
1537
|
this.dataDirLock = undefined;
|
|
1538
|
+
if (invocationCloseErrors.length)
|
|
1539
|
+
throw new AggregateError(invocationCloseErrors, "Invocation target cleanup failed");
|
|
1319
1540
|
}
|
|
1320
1541
|
}
|
|
1321
1542
|
/**
|
package/dist/host/types.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { EventSink } from "../runtime/events.js";
|
|
|
7
7
|
import type { RuntimePlatform } from "../platform/types.js";
|
|
8
8
|
import type { ActionDockService, ConfigValueView, EventsPort, ListRunsOptions, StateScopeOptions } from "../service/types.js";
|
|
9
9
|
import type { StateEntry } from "../storage/types.js";
|
|
10
|
+
import type { ActionBindings } from "../invocation/bindings.js";
|
|
10
11
|
/**
|
|
11
12
|
* 宿主事件服务端口(既作为独立方法调用,又满足 EventsPort 规范)。
|
|
12
13
|
*/
|
|
@@ -21,6 +22,8 @@ export interface HostEventsPort extends EventsPort {
|
|
|
21
22
|
* ActionDock 宿主容器初始化配置选项。
|
|
22
23
|
*/
|
|
23
24
|
export interface ActionDockHostOptions {
|
|
25
|
+
/** 按调用方包覆盖运行时命名绑定;未覆盖的包读取其 .actiondock/bindings.json。 */
|
|
26
|
+
actionBindings?: Readonly<Record<string, ActionBindings>>;
|
|
24
27
|
/** 显式预注册的包列表(PackageRuntime 实例、PackageRuntimeOptions 配置或包目录物理路径)。Host 统一管理其生命周期,关闭时统一释放。 */
|
|
25
28
|
packages?: Array<PackageRuntime | PackageRuntimeOptions | string>;
|
|
26
29
|
/** 当前工程根目录绝对物理路径 */
|
package/dist/index.d.ts
CHANGED
|
@@ -7,15 +7,16 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export { ACTIONDOCK_VERSION } from "./version.js";
|
|
9
9
|
export { createActionDock, connectActionDock, } from "./service/factory.js";
|
|
10
|
-
export type { ActionDockService, ActionDockService as ActionDock, DiscoveryPort, ExecutionPort, RunsPort, EventsPort, RunEventSubscriptionOptions, ConfigPort, StatePort, CreateActionDockOptions, ConnectActionDockOptions, RemoteServiceOptions, ConfigValueView, ListRunsOptions, RunReadOptions, StateScopeOptions, } from "./service/types.js";
|
|
10
|
+
export type { ActionDockService, ActionDockService as ActionDock, DiscoveryPort, ExecutionPort, RunsPort, EventsPort, RunEventSubscriptionOptions, ConfigPort, StatePort, CreateActionDockOptions, ConnectActionDockOptions, RemoteServiceOptions, ConfigValueView, ConfigSource, ListRunsOptions, RunReadOptions, StateScopeOptions, } from "./service/types.js";
|
|
11
11
|
export { isTerminalRunStatus, DEFAULT_RUNS_RETENTION_MS, DEFAULT_MAX_RUNS_PER_PACKAGE, DEFAULT_MIN_RETAIN_RUNS, } from "./storage/types.js";
|
|
12
12
|
export { isRunHostDead } from "./storage/run-liveness.js";
|
|
13
13
|
export type { TerminalRunStatus } from "./storage/types.js";
|
|
14
14
|
export { parseDuration } from "./utils/index.js";
|
|
15
15
|
export { toSnakeUpperCase, resolveEnvValue } from "./runtime/env.js";
|
|
16
16
|
export type { ResolvedEnv } from "./runtime/env.js";
|
|
17
|
-
export type { ActionRef, ResolvedActionRef, ExecutionResult, RunRecord, RunOrigin, ExecutionEvent, } from "@actiondock/sdk";
|
|
17
|
+
export type { ActionInvokeOptions, ActionRef, ResolvedActionRef, ExecutionResult, RunRecord, RunOrigin, ExecutionEvent, } from "@actiondock/sdk";
|
|
18
18
|
export type { RunOptions, ExecutionTicket, CancelResult, } from "./execution/types.js";
|
|
19
|
+
export type { ActionBindings, ActionBindingTarget } from "./invocation/bindings.js";
|
|
19
20
|
export type { ActionSpec, ActionSummary, PlaybookSpec, PlaybookSummary, PackageInfo, ListActionsOptions, } from "./package/types.js";
|
|
20
21
|
export { createNodePlatform, } from "./platform/node.js";
|
|
21
22
|
export { startActionDockServer, } from "./server/server.js";
|
|
@@ -24,4 +25,4 @@ export { initProject } from "./project/init.js";
|
|
|
24
25
|
export { loadProjectConfig, findProjectRoot, } from "./project/loader.js";
|
|
25
26
|
export type { ProjectConfig, } from "./project/types.js";
|
|
26
27
|
export type { PackageGraph, } from "./catalog/graph.js";
|
|
27
|
-
export { ActionDockError, ProcessError, PACKAGE_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_NOT_FOUND, ACTION_LOAD_FAILED, ACTION_FAILED, ACTION_TIMEOUT, ACTION_CANCELLED, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, ACTION_CALL_CYCLE, UNDECLARED_ACTION_DEPENDENCY, INVALID_ACTION_REF, IDEMPOTENCY_CONFLICT, EXECUTION_FAILED, UNHANDLED_EXECUTION_ERROR, RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, STANDALONE_ASYNC_UNSUPPORTED, HOST_PROCESS_EXITED, EXECUTION_ABORTED, TIMEOUT, NETWORK_ERROR, CAPABILITY_UNAVAILABLE, STATE_KEY_NOT_FOUND, STORAGE_BUSY, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, EVENT_BACKPRESSURE_LIMIT, EVENT_CURSOR_EXPIRED, PROCESS_OUTPUT_LIMIT, PROCESS_SPAWN_ERROR, PROCESS_CANCELLED, PROCESS_TIMEOUT, UNAUTHORIZED, NOT_FOUND, SERVER_ERROR, PACKAGE_FORBIDDEN, ACTION_FORBIDDEN, PLAYBOOK_NOT_FOUND, REQUEST_TOO_LARGE, ACTION_START_FAILED, ACTION_EXECUTION_ERROR, DATA_DIR_IN_USE, DATA_DIR_RECOVERY_REQUIRED, PROCESS_FAILED, MCP_TOOL_NAME_COLLISION, ACCESS_DENIED, INVALID_FLAT_ARGUMENT, INVALID_JSON, INVALID_JSON_LITERAL, INPUT_PATH_CONFLICT, FLAT_INPUT_LIMIT_EXCEEDED, INPUT_LIMIT_EXCEEDED, INPUT_POLICY_VIOLATION, INPUT_CONFLICT, INPUT_FILE_NOT_FOUND, INPUT_FILE_READ_FAILED, INVALID_ARGUMENT, PACKAGE_NOT_ALLOWED, INVALID_PACKAGE_ID, PATH_TRAVERSAL, AMBIGUOUS_STATE_KEY, RUN_NOT_FOUND, RUN_ALREADY_FINISHED, PROJECT_ROOT_NOT_FOUND, describeActionLoadFailure, createErrorEnvelope, resolveExecutionHint, } from "./errors.js";
|
|
28
|
+
export { ActionDockError, ProcessError, PACKAGE_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_NOT_FOUND, ACTION_LOAD_FAILED, ACTION_FAILED, ACTION_TIMEOUT, ACTION_CANCELLED, CONFIG_VALUE_INVALID, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, ACTION_CALL_CYCLE, UNDECLARED_ACTION_DEPENDENCY, INVALID_ACTION_REF, IDEMPOTENCY_CONFLICT, EXECUTION_FAILED, UNHANDLED_EXECUTION_ERROR, RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, STANDALONE_ASYNC_UNSUPPORTED, HOST_PROCESS_EXITED, EXECUTION_ABORTED, TIMEOUT, NETWORK_ERROR, CAPABILITY_UNAVAILABLE, STATE_KEY_NOT_FOUND, STORAGE_BUSY, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, EVENT_BACKPRESSURE_LIMIT, EVENT_CURSOR_EXPIRED, PROCESS_OUTPUT_LIMIT, PROCESS_SPAWN_ERROR, PROCESS_CANCELLED, PROCESS_TIMEOUT, UNAUTHORIZED, NOT_FOUND, SERVER_ERROR, PACKAGE_FORBIDDEN, ACTION_FORBIDDEN, PLAYBOOK_NOT_FOUND, REQUEST_TOO_LARGE, ACTION_START_FAILED, ACTION_EXECUTION_ERROR, DATA_DIR_IN_USE, DATA_DIR_RECOVERY_REQUIRED, PROCESS_FAILED, MCP_TOOL_NAME_COLLISION, ACCESS_DENIED, INVALID_FLAT_ARGUMENT, INVALID_JSON, INVALID_JSON_LITERAL, INPUT_PATH_CONFLICT, FLAT_INPUT_LIMIT_EXCEEDED, INPUT_LIMIT_EXCEEDED, INPUT_POLICY_VIOLATION, INPUT_CONFLICT, INPUT_FILE_NOT_FOUND, INPUT_FILE_READ_FAILED, INVALID_ARGUMENT, PACKAGE_NOT_ALLOWED, INVALID_PACKAGE_ID, PATH_TRAVERSAL, AMBIGUOUS_STATE_KEY, RUN_NOT_FOUND, RUN_ALREADY_FINISHED, PROJECT_ROOT_NOT_FOUND, describeActionLoadFailure, createErrorEnvelope, resolveExecutionHint, } from "./errors.js";
|
package/dist/index.js
CHANGED
|
@@ -20,4 +20,4 @@ export { startActionDockServer, } from "./server/server.js";
|
|
|
20
20
|
export { initProject } from "./project/init.js";
|
|
21
21
|
export { loadProjectConfig, findProjectRoot, } from "./project/loader.js";
|
|
22
22
|
// 8. 统一错误模型与核心标准错误码常量
|
|
23
|
-
export { ActionDockError, ProcessError, PACKAGE_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_NOT_FOUND, ACTION_LOAD_FAILED, ACTION_FAILED, ACTION_TIMEOUT, ACTION_CANCELLED, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, ACTION_CALL_CYCLE, UNDECLARED_ACTION_DEPENDENCY, INVALID_ACTION_REF, IDEMPOTENCY_CONFLICT, EXECUTION_FAILED, UNHANDLED_EXECUTION_ERROR, RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, STANDALONE_ASYNC_UNSUPPORTED, HOST_PROCESS_EXITED, EXECUTION_ABORTED, TIMEOUT, NETWORK_ERROR, CAPABILITY_UNAVAILABLE, STATE_KEY_NOT_FOUND, STORAGE_BUSY, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, EVENT_BACKPRESSURE_LIMIT, EVENT_CURSOR_EXPIRED, PROCESS_OUTPUT_LIMIT, PROCESS_SPAWN_ERROR, PROCESS_CANCELLED, PROCESS_TIMEOUT, UNAUTHORIZED, NOT_FOUND, SERVER_ERROR, PACKAGE_FORBIDDEN, ACTION_FORBIDDEN, PLAYBOOK_NOT_FOUND, REQUEST_TOO_LARGE, ACTION_START_FAILED, ACTION_EXECUTION_ERROR, DATA_DIR_IN_USE, DATA_DIR_RECOVERY_REQUIRED, PROCESS_FAILED, MCP_TOOL_NAME_COLLISION, ACCESS_DENIED, INVALID_FLAT_ARGUMENT, INVALID_JSON, INVALID_JSON_LITERAL, INPUT_PATH_CONFLICT, FLAT_INPUT_LIMIT_EXCEEDED, INPUT_LIMIT_EXCEEDED, INPUT_POLICY_VIOLATION, INPUT_CONFLICT, INPUT_FILE_NOT_FOUND, INPUT_FILE_READ_FAILED, INVALID_ARGUMENT, PACKAGE_NOT_ALLOWED, INVALID_PACKAGE_ID, PATH_TRAVERSAL, AMBIGUOUS_STATE_KEY, RUN_NOT_FOUND, RUN_ALREADY_FINISHED, PROJECT_ROOT_NOT_FOUND, describeActionLoadFailure, createErrorEnvelope, resolveExecutionHint, } from "./errors.js";
|
|
23
|
+
export { ActionDockError, ProcessError, PACKAGE_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_NOT_FOUND, ACTION_LOAD_FAILED, ACTION_FAILED, ACTION_TIMEOUT, ACTION_CANCELLED, CONFIG_VALUE_INVALID, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, ACTION_CALL_CYCLE, UNDECLARED_ACTION_DEPENDENCY, INVALID_ACTION_REF, IDEMPOTENCY_CONFLICT, EXECUTION_FAILED, UNHANDLED_EXECUTION_ERROR, RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, STANDALONE_ASYNC_UNSUPPORTED, HOST_PROCESS_EXITED, EXECUTION_ABORTED, TIMEOUT, NETWORK_ERROR, CAPABILITY_UNAVAILABLE, STATE_KEY_NOT_FOUND, STORAGE_BUSY, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, EVENT_BACKPRESSURE_LIMIT, EVENT_CURSOR_EXPIRED, PROCESS_OUTPUT_LIMIT, PROCESS_SPAWN_ERROR, PROCESS_CANCELLED, PROCESS_TIMEOUT, UNAUTHORIZED, NOT_FOUND, SERVER_ERROR, PACKAGE_FORBIDDEN, ACTION_FORBIDDEN, PLAYBOOK_NOT_FOUND, REQUEST_TOO_LARGE, ACTION_START_FAILED, ACTION_EXECUTION_ERROR, DATA_DIR_IN_USE, DATA_DIR_RECOVERY_REQUIRED, PROCESS_FAILED, MCP_TOOL_NAME_COLLISION, ACCESS_DENIED, INVALID_FLAT_ARGUMENT, INVALID_JSON, INVALID_JSON_LITERAL, INPUT_PATH_CONFLICT, FLAT_INPUT_LIMIT_EXCEEDED, INPUT_LIMIT_EXCEEDED, INPUT_POLICY_VIOLATION, INPUT_CONFLICT, INPUT_FILE_NOT_FOUND, INPUT_FILE_READ_FAILED, INVALID_ARGUMENT, PACKAGE_NOT_ALLOWED, INVALID_PACKAGE_ID, PATH_TRAVERSAL, AMBIGUOUS_STATE_KEY, RUN_NOT_FOUND, RUN_ALREADY_FINISHED, PROJECT_ROOT_NOT_FOUND, describeActionLoadFailure, createErrorEnvelope, resolveExecutionHint, } from "./errors.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ActionDockError, INVALID_ARGUMENT } from "../errors.js";
|
|
2
|
+
import { assertConcreteConfigKey } from "../project/config-declarations.js";
|
|
3
|
+
import { parseJson } from "./input-resolver.js";
|
|
4
|
+
/** 配置赋值只识别等号左侧的 :=,不物化路径,也不把解析失败回退为字符串。 */
|
|
5
|
+
export function parseConfigOverrideAssignment(pair) {
|
|
6
|
+
const equals = pair.indexOf("=");
|
|
7
|
+
if (equals < 0) {
|
|
8
|
+
throw new ActionDockError(INVALID_ARGUMENT, "Expected configuration assignment 'KEY=value' or 'KEY:=json'");
|
|
9
|
+
}
|
|
10
|
+
const json = equals > 0 && pair[equals - 1] === ":";
|
|
11
|
+
const key = pair.slice(0, json ? equals - 1 : equals);
|
|
12
|
+
assertConcreteConfigKey(key);
|
|
13
|
+
const rawValue = pair.slice(equals + 1);
|
|
14
|
+
if (!json)
|
|
15
|
+
return { key, value: rawValue };
|
|
16
|
+
try {
|
|
17
|
+
return { key, value: parseJson(rawValue, "configuration override") };
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// JSON.parse 和通用输入校验的诊断可能含输入片段,不能直接回显或挂载 cause。
|
|
21
|
+
throw new ActionDockError(INVALID_ARGUMENT, `Invalid JSON configuration override for '${key}'`);
|
|
22
|
+
}
|
|
23
|
+
}
|