@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/client/config.d.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
+
import type { ConfigItemDefinition } from "../project/types.js";
|
|
1
2
|
import type { RemoteClientRequestOptions } from "./transport.js";
|
|
3
|
+
export interface FetchRemoteConfigOptions extends RemoteClientRequestOptions {
|
|
4
|
+
/** 本地声明只可加强远端保护,不能撤销服务端标记。 */
|
|
5
|
+
localDeclarations?: Record<string, ConfigItemDefinition>;
|
|
6
|
+
/** 提供当前目录声明时,仅在响应包标识匹配后启用。 */
|
|
7
|
+
localPackageId?: string;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 拉取远端配置视图(可定向指定包)。
|
|
7
|
-
*/
|
|
8
|
-
export declare function fetchRemoteConfig(serverUrl: string, token?: string, packageId?: string, options?: RemoteClientRequestOptions): Promise<any>;
|
|
9
|
-
/**
|
|
10
|
-
* 写入单个远端配置键值。
|
|
10
|
+
* 在核心边界归一化配置安全视图;仅接受 configViewVersion:1 新协议。
|
|
11
|
+
* 旧协议无法证明来源与元数据真实性,统一抛出协议不支持错误,不猜测来源。
|
|
11
12
|
*/
|
|
13
|
+
export declare function normalizeRemoteConfigResponse(rawResponse: any, options?: Pick<FetchRemoteConfigOptions, "localDeclarations" | "localPackageId"> & {
|
|
14
|
+
packageId?: string;
|
|
15
|
+
}): any;
|
|
16
|
+
/** 拉取远端配置;返回值与元数据均已完成安全归一化。 */
|
|
17
|
+
export declare function fetchRemoteConfig(serverUrl: string, token?: string, packageId?: string, options?: FetchRemoteConfigOptions): Promise<any>;
|
|
18
|
+
/** 单键查询可解析仅由环境变量提供的模板实例;服务端必须返回同键完整单项视图。 */
|
|
19
|
+
export declare function fetchRemoteConfigItem(serverUrl: string, key: string, token?: string, packageId?: string, options?: FetchRemoteConfigOptions): Promise<any>;
|
|
20
|
+
/** 写入仍为整键替换;服务端在持久化之前校验。 */
|
|
12
21
|
export declare function setRemoteConfig(serverUrl: string, key: string, value: unknown, token?: string, packageId?: string, options?: RemoteClientRequestOptions): Promise<any>;
|
|
13
|
-
/**
|
|
14
|
-
* 删除单个远端配置键。
|
|
15
|
-
*/
|
|
16
22
|
export declare function deleteRemoteConfig(serverUrl: string, key: string, token?: string, packageId?: string, options?: RemoteClientRequestOptions): Promise<any>;
|
|
17
|
-
/**
|
|
18
|
-
* 拉取远端配置环境变量检查结果(可定向指定包)。
|
|
19
|
-
*/
|
|
20
23
|
export declare function fetchRemoteConfigEnv(serverUrl: string, token?: string, packageId?: string, options?: RemoteClientRequestOptions): Promise<any>;
|
package/dist/client/config.js
CHANGED
|
@@ -1,22 +1,125 @@
|
|
|
1
|
+
import { CONFIG_SOURCES } from "../service/types.js";
|
|
2
|
+
import { ActionDockError, PROTOCOL_UNSUPPORTED } from "../errors.js";
|
|
3
|
+
import { assertConcreteConfigKey, assertValidConfigDeclarations, resolveConfigDeclaration, } from "../project/config-declarations.js";
|
|
4
|
+
import { redactConfigValueAtPaths, redactConfigValueForDeclarations, sanitizeConfigDefinitions, } from "../storage/mask.js";
|
|
1
5
|
import { buildQueryString, fetchRemoteJson } from "./transport.js";
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
/** 判定远端响应中的 source 是否为合法 ConfigSource(含 null);合法值单一事实源为 CONFIG_SOURCES 元组。 */
|
|
10
|
+
function isValidConfigSource(source) {
|
|
11
|
+
return source === null || (typeof source === "string" && CONFIG_SOURCES.includes(source));
|
|
12
|
+
}
|
|
13
|
+
/** 在核心边界校验配置安全视图契约:来源合法、状态与值自洽,不满足即拒绝;诊断不携带配置原文。 */
|
|
14
|
+
function assertValidConfigValueView(item) {
|
|
15
|
+
if (!isRecord(item) || typeof item.key !== "string" || typeof item.configured !== "boolean" || typeof item.secret !== "boolean" ||
|
|
16
|
+
!isValidConfigSource(item.source) || !Array.isArray(item.redactedPaths) ||
|
|
17
|
+
item.redactedPaths.some((path) => typeof path !== "string")) {
|
|
18
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, "Remote configuration view violates the config view protocol: source must be one of override/package/global/env/default/null and metadata must be complete");
|
|
19
|
+
}
|
|
20
|
+
// source null 仅代表未命中:不得携带生效值或隐藏路径,也不得宣称已配置。
|
|
21
|
+
if (item.source === null) {
|
|
22
|
+
if (item.configured !== false || item.value !== undefined || item.redactedPaths.length > 0) {
|
|
23
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, `Remote configuration view for '${item.key}' declares no effective source but carries configured state, a value, or redaction paths`);
|
|
24
|
+
}
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// default 与未命中同样不是显式配置;显式来源必须宣称已配置。
|
|
28
|
+
if (item.source === "default") {
|
|
29
|
+
if (item.configured !== false) {
|
|
30
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, `Remote configuration view for '${item.key}' declares a default source but claims configured state`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else if (item.configured !== true) {
|
|
34
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, `Remote configuration view for '${item.key}' declares an explicit source but claims unconfigured state`);
|
|
35
|
+
}
|
|
36
|
+
// 声明有来源就必须有实际生效值;整项隐藏可省略 value 但必须携带根隐藏路径。
|
|
37
|
+
if (item.value === undefined && !item.redactedPaths.includes("")) {
|
|
38
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, `Remote configuration view for '${item.key}' declares an effective source but omits both the value and the root redaction path`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
2
41
|
/**
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 拉取远端配置视图(可定向指定包)。
|
|
42
|
+
* 在核心边界归一化配置安全视图;仅接受 configViewVersion:1 新协议。
|
|
43
|
+
* 旧协议无法证明来源与元数据真实性,统一抛出协议不支持错误,不猜测来源。
|
|
7
44
|
*/
|
|
45
|
+
export function normalizeRemoteConfigResponse(rawResponse, options) {
|
|
46
|
+
if (!rawResponse || typeof rawResponse !== "object") {
|
|
47
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, "Remote configuration response violates the config view protocol: response must be an object");
|
|
48
|
+
}
|
|
49
|
+
// 新协议门槛提前到一切声明解析之前:缺失 configViewVersion:1 视为旧服务端,
|
|
50
|
+
// 直接拒绝,避免旧协议因其他字段错误先报清单/参数错误。
|
|
51
|
+
if (rawResponse.configViewVersion !== 1) {
|
|
52
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, "Remote server did not declare configViewVersion: 1; legacy configuration responses without safe view metadata are no longer supported");
|
|
53
|
+
}
|
|
54
|
+
if (!Array.isArray(rawResponse.items)) {
|
|
55
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, "Remote configuration response is missing safe views");
|
|
56
|
+
}
|
|
57
|
+
const remoteDeclared = isRecord(rawResponse.declared) ? rawResponse.declared : {};
|
|
58
|
+
const matchesLocalPackage = !options?.localPackageId ||
|
|
59
|
+
rawResponse.packageId === options.localPackageId || options.packageId === options.localPackageId;
|
|
60
|
+
const localDeclared = matchesLocalPackage ? options?.localDeclarations ?? {} : {};
|
|
61
|
+
assertValidConfigDeclarations(remoteDeclared);
|
|
62
|
+
assertValidConfigDeclarations(localDeclared);
|
|
63
|
+
const declarationsFor = (key) => [
|
|
64
|
+
resolveConfigDeclaration(remoteDeclared, key)?.item,
|
|
65
|
+
resolveConfigDeclaration(localDeclared, key)?.item,
|
|
66
|
+
].filter((item) => item !== undefined);
|
|
67
|
+
const items = rawResponse.items.map((item) => {
|
|
68
|
+
assertValidConfigValueView(item);
|
|
69
|
+
assertConcreteConfigKey(item.key);
|
|
70
|
+
// 路径只是保护策略,不是原值已经被替换的证据;先实际应用服务端路径。
|
|
71
|
+
const remoteSafe = redactConfigValueAtPaths(item.value, item.redactedPaths);
|
|
72
|
+
const declaredSafe = redactConfigValueForDeclarations(remoteSafe.value, declarationsFor(item.key));
|
|
73
|
+
const safe = redactConfigValueAtPaths(declaredSafe.value, [
|
|
74
|
+
...remoteSafe.redactedPaths, ...declaredSafe.redactedPaths,
|
|
75
|
+
]);
|
|
76
|
+
return {
|
|
77
|
+
key: item.key,
|
|
78
|
+
configured: item.configured,
|
|
79
|
+
secret: item.secret || remoteSafe.secret || declaredSafe.secret,
|
|
80
|
+
source: item.source,
|
|
81
|
+
value: safe.value,
|
|
82
|
+
redactedPaths: safe.redactedPaths,
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
// 只返回已知安全字段,避免 spread 原响应把原始别名重新带出边界。
|
|
86
|
+
return {
|
|
87
|
+
ok: rawResponse.ok ?? true,
|
|
88
|
+
configViewVersion: 1,
|
|
89
|
+
packageId: rawResponse.packageId ?? options?.packageId,
|
|
90
|
+
declared: sanitizeConfigDefinitions({ ...localDeclared, ...remoteDeclared }) ?? {},
|
|
91
|
+
items,
|
|
92
|
+
values: Object.fromEntries(items.map((item) => [item.key,
|
|
93
|
+
item.value === undefined && item.redactedPaths.includes("") ? "********" : item.value,
|
|
94
|
+
])),
|
|
95
|
+
masked: Object.fromEntries(items.map((item) => [item.key, item.redactedPaths])),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** 拉取远端配置;返回值与元数据均已完成安全归一化。 */
|
|
8
99
|
export async function fetchRemoteConfig(serverUrl, token, packageId, options) {
|
|
9
|
-
|
|
100
|
+
const raw = await fetchRemoteJson(serverUrl, `/api/v2/config${buildQueryString({ package: packageId })}`, token, {
|
|
10
101
|
errorPrefix: "Failed to fetch remote config",
|
|
11
102
|
allowInsecureHttp: options?.allowInsecureHttp,
|
|
12
103
|
insecure: options?.insecure,
|
|
13
104
|
dispatcher: options?.dispatcher,
|
|
14
105
|
});
|
|
106
|
+
return normalizeRemoteConfigResponse(raw, { ...options, packageId });
|
|
15
107
|
}
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
|
|
108
|
+
/** 单键查询可解析仅由环境变量提供的模板实例;服务端必须返回同键完整单项视图。 */
|
|
109
|
+
export async function fetchRemoteConfigItem(serverUrl, key, token, packageId, options) {
|
|
110
|
+
assertConcreteConfigKey(key);
|
|
111
|
+
const raw = await fetchRemoteJson(serverUrl, `/api/v2/config${buildQueryString({ package: packageId, key })}`, token, { ...options, errorPrefix: "Failed to fetch remote configuration item" });
|
|
112
|
+
// 严格单项契约:新协议必须提供与请求键一致的完整 item;
|
|
113
|
+
// 真正未命中由服务端返回同键 source null 视图,不接受列表或空 items 伪装单项。
|
|
114
|
+
if (!raw || typeof raw !== "object" || raw.configViewVersion !== 1 ||
|
|
115
|
+
!isRecord(raw.item) || raw.item.key !== key) {
|
|
116
|
+
throw new ActionDockError(PROTOCOL_UNSUPPORTED, `Remote server did not return a complete single-item config view for key '${key}'; servers that ignore the key query parameter are no longer supported`);
|
|
117
|
+
}
|
|
118
|
+
return normalizeRemoteConfigResponse({ ...raw, items: [raw.item] }, { ...options, packageId });
|
|
119
|
+
}
|
|
120
|
+
/** 写入仍为整键替换;服务端在持久化之前校验。 */
|
|
19
121
|
export async function setRemoteConfig(serverUrl, key, value, token, packageId, options) {
|
|
122
|
+
assertConcreteConfigKey(key);
|
|
20
123
|
return fetchRemoteJson(serverUrl, "/api/v2/config", token, {
|
|
21
124
|
method: "PUT",
|
|
22
125
|
body: { key, value, package: packageId },
|
|
@@ -26,10 +129,8 @@ export async function setRemoteConfig(serverUrl, key, value, token, packageId, o
|
|
|
26
129
|
dispatcher: options?.dispatcher,
|
|
27
130
|
});
|
|
28
131
|
}
|
|
29
|
-
/**
|
|
30
|
-
* 删除单个远端配置键。
|
|
31
|
-
*/
|
|
32
132
|
export async function deleteRemoteConfig(serverUrl, key, token, packageId, options) {
|
|
133
|
+
assertConcreteConfigKey(key);
|
|
33
134
|
return fetchRemoteJson(serverUrl, `/api/v2/config/${encodeURIComponent(key)}${buildQueryString({ package: packageId })}`, token, {
|
|
34
135
|
method: "DELETE",
|
|
35
136
|
errorPrefix: `Failed to delete remote config '${key}'`,
|
|
@@ -38,9 +139,6 @@ export async function deleteRemoteConfig(serverUrl, key, token, packageId, optio
|
|
|
38
139
|
dispatcher: options?.dispatcher,
|
|
39
140
|
});
|
|
40
141
|
}
|
|
41
|
-
/**
|
|
42
|
-
* 拉取远端配置环境变量检查结果(可定向指定包)。
|
|
43
|
-
*/
|
|
44
142
|
export async function fetchRemoteConfigEnv(serverUrl, token, packageId, options) {
|
|
45
143
|
return fetchRemoteJson(serverUrl, `/api/v2/config/env${buildQueryString({ package: packageId })}`, token, {
|
|
46
144
|
errorPrefix: "Failed to fetch remote config env checks",
|
package/dist/client/index.d.ts
CHANGED
|
@@ -13,4 +13,4 @@ export type { RemoteExecuteOptions, RemoteExecutionResult } from "./actions.js";
|
|
|
13
13
|
export { fetchRemotePlaybookShow, fetchRemotePlaybooks } from "./playbooks.js";
|
|
14
14
|
export { cancelRemoteRun, cleanExpiredRemoteRuns, clearRemoteRuns, fetchRemoteRun, fetchRemoteRuns, } from "./runs.js";
|
|
15
15
|
export { clearRemoteState, deleteRemoteStateKey, fetchRemoteStateList, getRemoteStateKey, setRemoteStateKey, } from "./state.js";
|
|
16
|
-
export { deleteRemoteConfig, fetchRemoteConfig, fetchRemoteConfigEnv, setRemoteConfig, } from "./config.js";
|
|
16
|
+
export { deleteRemoteConfig, fetchRemoteConfig, fetchRemoteConfigItem, fetchRemoteConfigEnv, setRemoteConfig, normalizeRemoteConfigResponse, type FetchRemoteConfigOptions, } from "./config.js";
|
package/dist/client/index.js
CHANGED
|
@@ -17,4 +17,4 @@ export { cancelRemoteRun, cleanExpiredRemoteRuns, clearRemoteRuns, fetchRemoteRu
|
|
|
17
17
|
// 6. 状态存储管理域
|
|
18
18
|
export { clearRemoteState, deleteRemoteStateKey, fetchRemoteStateList, getRemoteStateKey, setRemoteStateKey, } from "./state.js";
|
|
19
19
|
// 7. 配置管理域
|
|
20
|
-
export { deleteRemoteConfig, fetchRemoteConfig, fetchRemoteConfigEnv, setRemoteConfig, } from "./config.js";
|
|
20
|
+
export { deleteRemoteConfig, fetchRemoteConfig, fetchRemoteConfigItem, fetchRemoteConfigEnv, setRemoteConfig, normalizeRemoteConfigResponse, } from "./config.js";
|
package/dist/errors.d.ts
CHANGED
|
@@ -71,6 +71,10 @@ export declare const CAPABILITY_UNAVAILABLE = "CAPABILITY_UNAVAILABLE";
|
|
|
71
71
|
export declare const STATE_KEY_NOT_FOUND = "STATE_KEY_NOT_FOUND";
|
|
72
72
|
/** SQLite 数据库忙或锁定 */
|
|
73
73
|
export declare const STORAGE_BUSY = "STORAGE_BUSY";
|
|
74
|
+
/** 所需生产依赖未就绪且当前环境不允许或不满足自动首装条件 */
|
|
75
|
+
export declare const DEPENDENCIES_NOT_READY = "DEPENDENCIES_NOT_READY";
|
|
76
|
+
/** 自动依赖安装进程启动失败、超时或非零退出 */
|
|
77
|
+
export declare const DEPENDENCY_INSTALL_FAILED = "DEPENDENCY_INSTALL_FAILED";
|
|
74
78
|
/** 工程事务锁被其他活跃进程持有 */
|
|
75
79
|
export declare const PROJECT_BUSY = "PROJECT_BUSY";
|
|
76
80
|
/** 工程存在未恢复的崩溃事务,需要执行恢复流程 */
|
|
@@ -298,6 +302,14 @@ export declare const EXECUTION_CONCURRENCY_LIMIT = "EXECUTION_CONCURRENCY_LIMIT"
|
|
|
298
302
|
export declare const PROJECT_CONFIG_NOT_FOUND = "PROJECT_CONFIG_NOT_FOUND";
|
|
299
303
|
/** 项目清单加载失败 */
|
|
300
304
|
export declare const MANIFEST_LOAD_FAILED = "MANIFEST_LOAD_FAILED";
|
|
305
|
+
/** 配置项数据值不符合声明的模式规范 */
|
|
306
|
+
export declare const CONFIG_VALUE_INVALID = "CONFIG_VALUE_INVALID";
|
|
307
|
+
/** 配置加密密钥缺失、无效或与存储域身份不符等加密配置错误 */
|
|
308
|
+
export declare const CONFIG_ENCRYPTION_ERROR = "CONFIG_ENCRYPTION_ERROR";
|
|
309
|
+
/** 配置密文解密失败(信封格式非法、版本未知、密钥身份不符或认证校验失败) */
|
|
310
|
+
export declare const CONFIG_DECRYPT_FAILED = "CONFIG_DECRYPT_FAILED";
|
|
311
|
+
/** 配置加密与解密错误按结构化错误码识别,跨模块副本也不得吞没或覆盖。 */
|
|
312
|
+
export declare function isConfigEncryptionError(error: unknown): boolean;
|
|
301
313
|
/** 动作标识符不符合命名规范 */
|
|
302
314
|
export declare const INVALID_ACTION_ID = "INVALID_ACTION_ID";
|
|
303
315
|
/** 规程标识符不符合命名规范 */
|
|
@@ -348,7 +360,7 @@ export declare function resolveExecutionHint(targetRef: string, error?: {
|
|
|
348
360
|
/**
|
|
349
361
|
* 集中定义的标准结构化错误码联合类型。
|
|
350
362
|
*/
|
|
351
|
-
export type ErrorCode = typeof PACKAGE_NOT_FOUND | typeof ACTION_PACKAGE_VERSION_CONFLICT | typeof ACTION_NOT_FOUND | typeof ACTION_LOAD_FAILED | typeof ACTION_FAILED | typeof ACTION_TIMEOUT | typeof ACTION_CANCELLED | typeof INPUT_VALIDATION_FAILED | typeof OUTPUT_VALIDATION_FAILED | typeof INPUT_NOT_JSON | typeof OUTPUT_NOT_JSON | typeof ACTION_SUBRUN_LIMIT | typeof ACTION_CALL_CYCLE | typeof UNDECLARED_ACTION_DEPENDENCY | typeof INVALID_ACTION_REF | typeof IDEMPOTENCY_CONFLICT | typeof EXECUTION_FAILED | typeof UNHANDLED_EXECUTION_ERROR | typeof RUN_REPOSITORY_UNAVAILABLE | typeof RUN_PERSISTENCE_FAILED | typeof STANDALONE_ASYNC_UNSUPPORTED | typeof INVOCATION_UNSUPPORTED | typeof HOST_PROCESS_EXITED | typeof EXECUTION_ABORTED | typeof TIMEOUT | typeof SERVICE_CLOSED | typeof NETWORK_ERROR | typeof INSECURE_TRANSPORT | typeof REMOTE_REQUEST_FAILED | typeof REMOTE_STREAM_UNAVAILABLE | typeof CAPABILITY_UNAVAILABLE | typeof STATE_KEY_NOT_FOUND | typeof STORAGE_BUSY | typeof PROJECT_BUSY | typeof PROJECT_RECOVERY_REQUIRED | typeof EVENT_BACKPRESSURE_LIMIT | typeof EVENT_CURSOR_EXPIRED | typeof PROCESS_OUTPUT_LIMIT | typeof PROCESS_SPAWN_ERROR | typeof PROCESS_CANCELLED | typeof PROCESS_TIMEOUT | typeof UNAUTHORIZED | typeof NOT_FOUND | typeof SERVER_ERROR | typeof BAD_REQUEST | typeof PACKAGE_FORBIDDEN | typeof ACTION_FORBIDDEN | typeof PLAYBOOK_NOT_FOUND | typeof REQUEST_TOO_LARGE | typeof ACTION_START_FAILED | typeof ACTION_EXECUTION_ERROR | typeof ACTIONS_LIST_ERROR | typeof PLAYBOOKS_LIST_ERROR | typeof RUNS_LIST_ERROR | typeof RUNS_CLEAR_ERROR | typeof INFO_ERROR | typeof PACKAGES_INFO_ERROR | typeof DOCTOR_ERROR | typeof RUN_INTERRUPTED | typeof CONFIG_ENV_ERROR | typeof CONFIG_LIST_ERROR | typeof CONFIG_SET_ERROR | typeof CONFIG_DELETE_ERROR | typeof STATE_LIST_ERROR | typeof STATE_CLEAR_ERROR | typeof STATE_KEY_ERROR | typeof DATA_DIR_IN_USE | typeof DATA_DIR_RECOVERY_REQUIRED | typeof UNSUPPORTED_STORAGE_SCHEMA | typeof STORED_ERROR_DECODE_FAILED | typeof PROCESS_FAILED | typeof GENERATED_TYPES_OUTDATED | typeof PROTOCOL_UNSUPPORTED | typeof SERVICE_RESULT_UNKNOWN | typeof MCP_TOOL_NAME_COLLISION | typeof ACCESS_DENIED | typeof UNSUPPORTED_CAPABILITY | typeof CONTROL_BUSY | typeof CONTROL_EXPIRED | typeof CONTROL_REVOKED | typeof PROCESS_QUARANTINED | typeof PROCESS_LOST | typeof REQUEST_CONFLICT | typeof INPUT_OUTCOME_UNKNOWN | typeof OUTPUT_GAP | typeof OUTPUT_UNAVAILABLE | typeof INVALID_CURSOR | typeof QUEUE_FULL | typeof QUOTA_EXCEEDED | typeof INPUT_CLOSED | typeof INVALID_FLAT_ARGUMENT | typeof INVALID_JSON | typeof INVALID_JSON_LITERAL | typeof INPUT_PATH_CONFLICT | typeof FLAT_INPUT_LIMIT_EXCEEDED | typeof INPUT_LIMIT_EXCEEDED | typeof INPUT_POLICY_VIOLATION | typeof INPUT_CONFLICT | typeof INPUT_FILE_NOT_FOUND | typeof INPUT_FILE_READ_FAILED | typeof INVALID_ARGUMENT | typeof PACKAGE_NOT_ALLOWED | typeof INVALID_PACKAGE_ID | typeof PATH_TRAVERSAL | typeof AMBIGUOUS_STATE_KEY | typeof RUN_NOT_FOUND | typeof RUN_ALREADY_FINISHED | typeof IPC_ERROR | typeof SERVICE_ERROR | typeof PROFILE_NOT_FOUND | typeof LOCKFILE_READ_FAILED | typeof LOCKFILE_CORRUPTED | typeof LOCKFILE_INVALID | typeof UNSUPPORTED_LOCKFILE_VERSION | typeof MANIFEST_READ_FAILED | typeof MANIFEST_CORRUPTED | typeof MANIFEST_INVALID | typeof UNSUPPORTED_MANIFEST_SCHEMA | typeof MANIFEST_NOT_FOUND | typeof MANIFEST_DIGEST_MISMATCH | typeof REGISTRY_CORRUPTED | typeof ASYNC_TRANSACTION_UNSUPPORTED | typeof STORAGE_CLOSED | typeof PACKAGE_ID_CONFLICT | typeof INVALID_PATH | typeof STORAGE_INIT_FAILED | typeof INVALID_STATE | typeof PROCESS_NOT_FOUND | typeof MODULE_RESOLVE_FAILED | typeof EXECUTION_CONCURRENCY_LIMIT | typeof PROJECT_CONFIG_NOT_FOUND | typeof MANIFEST_LOAD_FAILED | typeof INVALID_ACTION_ID | typeof INVALID_PLAYBOOK_ID | typeof PROJECT_ROOT_NOT_FOUND;
|
|
363
|
+
export type ErrorCode = typeof PACKAGE_NOT_FOUND | typeof ACTION_PACKAGE_VERSION_CONFLICT | typeof ACTION_NOT_FOUND | typeof ACTION_LOAD_FAILED | typeof ACTION_FAILED | typeof ACTION_TIMEOUT | typeof ACTION_CANCELLED | typeof INPUT_VALIDATION_FAILED | typeof OUTPUT_VALIDATION_FAILED | typeof INPUT_NOT_JSON | typeof OUTPUT_NOT_JSON | typeof ACTION_SUBRUN_LIMIT | typeof ACTION_CALL_CYCLE | typeof UNDECLARED_ACTION_DEPENDENCY | typeof INVALID_ACTION_REF | typeof IDEMPOTENCY_CONFLICT | typeof EXECUTION_FAILED | typeof UNHANDLED_EXECUTION_ERROR | typeof RUN_REPOSITORY_UNAVAILABLE | typeof RUN_PERSISTENCE_FAILED | typeof STANDALONE_ASYNC_UNSUPPORTED | typeof INVOCATION_UNSUPPORTED | typeof HOST_PROCESS_EXITED | typeof EXECUTION_ABORTED | typeof TIMEOUT | typeof SERVICE_CLOSED | typeof NETWORK_ERROR | typeof INSECURE_TRANSPORT | typeof REMOTE_REQUEST_FAILED | typeof REMOTE_STREAM_UNAVAILABLE | typeof CAPABILITY_UNAVAILABLE | typeof STATE_KEY_NOT_FOUND | typeof STORAGE_BUSY | typeof DEPENDENCIES_NOT_READY | typeof DEPENDENCY_INSTALL_FAILED | typeof PROJECT_BUSY | typeof PROJECT_RECOVERY_REQUIRED | typeof EVENT_BACKPRESSURE_LIMIT | typeof EVENT_CURSOR_EXPIRED | typeof PROCESS_OUTPUT_LIMIT | typeof PROCESS_SPAWN_ERROR | typeof PROCESS_CANCELLED | typeof PROCESS_TIMEOUT | typeof UNAUTHORIZED | typeof NOT_FOUND | typeof SERVER_ERROR | typeof BAD_REQUEST | typeof PACKAGE_FORBIDDEN | typeof ACTION_FORBIDDEN | typeof PLAYBOOK_NOT_FOUND | typeof REQUEST_TOO_LARGE | typeof ACTION_START_FAILED | typeof ACTION_EXECUTION_ERROR | typeof ACTIONS_LIST_ERROR | typeof PLAYBOOKS_LIST_ERROR | typeof RUNS_LIST_ERROR | typeof RUNS_CLEAR_ERROR | typeof INFO_ERROR | typeof PACKAGES_INFO_ERROR | typeof DOCTOR_ERROR | typeof RUN_INTERRUPTED | typeof CONFIG_ENV_ERROR | typeof CONFIG_LIST_ERROR | typeof CONFIG_SET_ERROR | typeof CONFIG_DELETE_ERROR | typeof STATE_LIST_ERROR | typeof STATE_CLEAR_ERROR | typeof STATE_KEY_ERROR | typeof DATA_DIR_IN_USE | typeof DATA_DIR_RECOVERY_REQUIRED | typeof UNSUPPORTED_STORAGE_SCHEMA | typeof STORED_ERROR_DECODE_FAILED | typeof PROCESS_FAILED | typeof GENERATED_TYPES_OUTDATED | typeof PROTOCOL_UNSUPPORTED | typeof SERVICE_RESULT_UNKNOWN | typeof MCP_TOOL_NAME_COLLISION | typeof ACCESS_DENIED | typeof UNSUPPORTED_CAPABILITY | typeof CONTROL_BUSY | typeof CONTROL_EXPIRED | typeof CONTROL_REVOKED | typeof PROCESS_QUARANTINED | typeof PROCESS_LOST | typeof REQUEST_CONFLICT | typeof INPUT_OUTCOME_UNKNOWN | typeof OUTPUT_GAP | typeof OUTPUT_UNAVAILABLE | typeof INVALID_CURSOR | typeof QUEUE_FULL | typeof QUOTA_EXCEEDED | typeof INPUT_CLOSED | typeof INVALID_FLAT_ARGUMENT | typeof INVALID_JSON | typeof INVALID_JSON_LITERAL | typeof INPUT_PATH_CONFLICT | typeof FLAT_INPUT_LIMIT_EXCEEDED | typeof INPUT_LIMIT_EXCEEDED | typeof INPUT_POLICY_VIOLATION | typeof INPUT_CONFLICT | typeof INPUT_FILE_NOT_FOUND | typeof INPUT_FILE_READ_FAILED | typeof INVALID_ARGUMENT | typeof PACKAGE_NOT_ALLOWED | typeof INVALID_PACKAGE_ID | typeof PATH_TRAVERSAL | typeof AMBIGUOUS_STATE_KEY | typeof RUN_NOT_FOUND | typeof RUN_ALREADY_FINISHED | typeof IPC_ERROR | typeof SERVICE_ERROR | typeof PROFILE_NOT_FOUND | typeof LOCKFILE_READ_FAILED | typeof LOCKFILE_CORRUPTED | typeof LOCKFILE_INVALID | typeof UNSUPPORTED_LOCKFILE_VERSION | typeof MANIFEST_READ_FAILED | typeof MANIFEST_CORRUPTED | typeof MANIFEST_INVALID | typeof UNSUPPORTED_MANIFEST_SCHEMA | typeof MANIFEST_NOT_FOUND | typeof MANIFEST_DIGEST_MISMATCH | typeof REGISTRY_CORRUPTED | typeof ASYNC_TRANSACTION_UNSUPPORTED | typeof STORAGE_CLOSED | typeof PACKAGE_ID_CONFLICT | typeof INVALID_PATH | typeof STORAGE_INIT_FAILED | typeof INVALID_STATE | typeof PROCESS_NOT_FOUND | typeof MODULE_RESOLVE_FAILED | typeof EXECUTION_CONCURRENCY_LIMIT | typeof PROJECT_CONFIG_NOT_FOUND | typeof MANIFEST_LOAD_FAILED | typeof CONFIG_VALUE_INVALID | typeof CONFIG_ENCRYPTION_ERROR | typeof CONFIG_DECRYPT_FAILED | typeof INVALID_ACTION_ID | typeof INVALID_PLAYBOOK_ID | typeof PROJECT_ROOT_NOT_FOUND;
|
|
352
364
|
/** 全仓统一错误码类型别名 */
|
|
353
365
|
export type ActionDockErrorCode = ErrorCode;
|
|
354
366
|
/**
|
package/dist/errors.js
CHANGED
|
@@ -71,6 +71,10 @@ export const CAPABILITY_UNAVAILABLE = "CAPABILITY_UNAVAILABLE";
|
|
|
71
71
|
export const STATE_KEY_NOT_FOUND = "STATE_KEY_NOT_FOUND";
|
|
72
72
|
/** SQLite 数据库忙或锁定 */
|
|
73
73
|
export const STORAGE_BUSY = "STORAGE_BUSY";
|
|
74
|
+
/** 所需生产依赖未就绪且当前环境不允许或不满足自动首装条件 */
|
|
75
|
+
export const DEPENDENCIES_NOT_READY = "DEPENDENCIES_NOT_READY";
|
|
76
|
+
/** 自动依赖安装进程启动失败、超时或非零退出 */
|
|
77
|
+
export const DEPENDENCY_INSTALL_FAILED = "DEPENDENCY_INSTALL_FAILED";
|
|
74
78
|
/** 工程事务锁被其他活跃进程持有 */
|
|
75
79
|
export const PROJECT_BUSY = "PROJECT_BUSY";
|
|
76
80
|
/** 工程存在未恢复的崩溃事务,需要执行恢复流程 */
|
|
@@ -299,6 +303,21 @@ export const EXECUTION_CONCURRENCY_LIMIT = "EXECUTION_CONCURRENCY_LIMIT";
|
|
|
299
303
|
export const PROJECT_CONFIG_NOT_FOUND = "PROJECT_CONFIG_NOT_FOUND";
|
|
300
304
|
/** 项目清单加载失败 */
|
|
301
305
|
export const MANIFEST_LOAD_FAILED = "MANIFEST_LOAD_FAILED";
|
|
306
|
+
/** 配置项数据值不符合声明的模式规范 */
|
|
307
|
+
export const CONFIG_VALUE_INVALID = "CONFIG_VALUE_INVALID";
|
|
308
|
+
/** 配置加密密钥缺失、无效或与存储域身份不符等加密配置错误 */
|
|
309
|
+
export const CONFIG_ENCRYPTION_ERROR = "CONFIG_ENCRYPTION_ERROR";
|
|
310
|
+
/** 配置密文解密失败(信封格式非法、版本未知、密钥身份不符或认证校验失败) */
|
|
311
|
+
export const CONFIG_DECRYPT_FAILED = "CONFIG_DECRYPT_FAILED";
|
|
312
|
+
const CONFIG_ENCRYPTION_ERROR_CODES = new Set([
|
|
313
|
+
CONFIG_ENCRYPTION_ERROR,
|
|
314
|
+
CONFIG_DECRYPT_FAILED,
|
|
315
|
+
]);
|
|
316
|
+
/** 配置加密与解密错误按结构化错误码识别,跨模块副本也不得吞没或覆盖。 */
|
|
317
|
+
export function isConfigEncryptionError(error) {
|
|
318
|
+
const code = error?.code;
|
|
319
|
+
return typeof code === "string" && CONFIG_ENCRYPTION_ERROR_CODES.has(code);
|
|
320
|
+
}
|
|
302
321
|
/** 动作标识符不符合命名规范 */
|
|
303
322
|
export const INVALID_ACTION_ID = "INVALID_ACTION_ID";
|
|
304
323
|
/** 规程标识符不符合命名规范 */
|
|
@@ -372,6 +391,12 @@ export function resolveExecutionHint(targetRef, error) {
|
|
|
372
391
|
if (error.code === ACTION_TIMEOUT) {
|
|
373
392
|
return "Tip: Increase timeout via '--timeout <duration>', or run in background via '--async' and track with 'ad runs show <runId>'.";
|
|
374
393
|
}
|
|
394
|
+
if (error.code === DEPENDENCIES_NOT_READY) {
|
|
395
|
+
return error.hint || error.details?.hint || "Tip: Install missing dependencies using 'npm install' or 'bun install'.";
|
|
396
|
+
}
|
|
397
|
+
if (error.code === DEPENDENCY_INSTALL_FAILED) {
|
|
398
|
+
return error.hint || error.details?.hint || "Tip: Check error output above and try running the package manager manually.";
|
|
399
|
+
}
|
|
375
400
|
if (error.hint && typeof error.hint === "string") {
|
|
376
401
|
return error.hint;
|
|
377
402
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { createActionCallKey } from "../invocation/policy.js";
|
|
2
3
|
import { parseActionRef } from "../catalog/resolve-action.js";
|
|
3
4
|
import { computeDigest } from "../project/digest.js";
|
|
4
5
|
import { loadActions, loadProjectConfig } from "../project/loader.js";
|
|
@@ -265,7 +266,7 @@ export class DefaultExecutionService {
|
|
|
265
266
|
const finalizer = createRunFinalizer(this.storage, runId);
|
|
266
267
|
// 调用栈快照跟踪
|
|
267
268
|
const callStack = context.callStack ? [...context.callStack] : [];
|
|
268
|
-
const callKey =
|
|
269
|
+
const callKey = createActionCallKey(targetActionId, targetPackageId, context.targetScope);
|
|
269
270
|
const lastStackItem = callStack[callStack.length - 1];
|
|
270
271
|
const isAlreadyAtTop = lastStackItem === callKey ||
|
|
271
272
|
(targetActionId && lastStackItem === targetActionId) ||
|
|
@@ -288,7 +289,18 @@ export class DefaultExecutionService {
|
|
|
288
289
|
}
|
|
289
290
|
}
|
|
290
291
|
if (typeof context.timeoutMs === "number" && context.timeoutMs > 0) {
|
|
291
|
-
|
|
292
|
+
if (context.deadline !== undefined) {
|
|
293
|
+
const remainingMs = Math.max(0, context.deadline - Date.now());
|
|
294
|
+
if (remainingMs <= 0) {
|
|
295
|
+
controller.abort(new ActionDockError(ACTION_TIMEOUT, `Action exceeded timeout of ${context.initialTimeoutMs ?? context.timeoutMs}ms`, { timeoutMs: context.initialTimeoutMs ?? context.timeoutMs }));
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
finalizer.startTimeout(controller, remainingMs, context.initialTimeoutMs ?? context.timeoutMs);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
finalizer.startTimeout(controller, context.timeoutMs, context.initialTimeoutMs);
|
|
303
|
+
}
|
|
292
304
|
}
|
|
293
305
|
const effectiveOwner = context.owner ||
|
|
294
306
|
createDefaultProcessOwner({
|
|
@@ -312,7 +324,7 @@ export class DefaultExecutionService {
|
|
|
312
324
|
owner: effectiveOwner,
|
|
313
325
|
progress: bridge.progressReporter,
|
|
314
326
|
logger: bridge.executionLogger,
|
|
315
|
-
onActionInvoke: (childAction, childInput, parentRunId) => this.invokeChildAction({
|
|
327
|
+
onActionInvoke: (childAction, childInput, parentRunId, options) => this.invokeChildAction({
|
|
316
328
|
controller,
|
|
317
329
|
rootRunId,
|
|
318
330
|
childAction,
|
|
@@ -324,6 +336,8 @@ export class DefaultExecutionService {
|
|
|
324
336
|
context,
|
|
325
337
|
effectiveProcess,
|
|
326
338
|
effectiveOwner,
|
|
339
|
+
logger: bridge.executionLogger,
|
|
340
|
+
options,
|
|
327
341
|
}),
|
|
328
342
|
});
|
|
329
343
|
const executionPromise = this.raceExecution({
|
|
@@ -423,6 +437,8 @@ export class DefaultExecutionService {
|
|
|
423
437
|
package: opts.package || this.identity,
|
|
424
438
|
signal: opts.signal,
|
|
425
439
|
timeoutMs: opts.timeoutMs,
|
|
440
|
+
initialTimeoutMs: opts.initialTimeoutMs,
|
|
441
|
+
deadline: opts.deadline,
|
|
426
442
|
maxCallDepth: opts.maxCallDepth,
|
|
427
443
|
config: opts.config || opts.configOverrides,
|
|
428
444
|
tenantId: opts.tenantId || opts.owner?.tenantId,
|
|
@@ -480,20 +496,36 @@ export class DefaultExecutionService {
|
|
|
480
496
|
};
|
|
481
497
|
}
|
|
482
498
|
catch (err) {
|
|
483
|
-
return this.classifyExecutionError(err, runId, context
|
|
499
|
+
return this.classifyExecutionError(err, runId, context, controller, finalizer);
|
|
484
500
|
}
|
|
485
501
|
}
|
|
486
|
-
classifyExecutionError(err, runId,
|
|
502
|
+
classifyExecutionError(err, runId, context, controller, finalizer) {
|
|
503
|
+
const timeoutBudget = context.initialTimeoutMs ?? context.timeoutMs;
|
|
487
504
|
if (finalizer.isTimeout) {
|
|
488
505
|
const error = {
|
|
489
506
|
code: ACTION_TIMEOUT,
|
|
490
|
-
message: `Action exceeded timeout of ${
|
|
507
|
+
message: `Action exceeded timeout of ${timeoutBudget}ms`,
|
|
491
508
|
};
|
|
492
509
|
finalizer.finalize("timed_out", undefined, error);
|
|
493
510
|
return { ok: false, runId, error: finalizer.persistError || error };
|
|
494
511
|
}
|
|
495
512
|
if (controller.signal.aborted) {
|
|
496
513
|
const reason = controller.signal.reason;
|
|
514
|
+
const reasonCode = reason?.code;
|
|
515
|
+
const isTimeoutReason = reasonCode === ACTION_TIMEOUT ||
|
|
516
|
+
(reason?.details && reason.details.code === ACTION_TIMEOUT) ||
|
|
517
|
+
(reason instanceof Error && reason.message?.includes("exceeded timeout")) ||
|
|
518
|
+
(typeof reason === "string" && reason.includes("exceeded timeout"));
|
|
519
|
+
if (isTimeoutReason) {
|
|
520
|
+
const error = {
|
|
521
|
+
code: ACTION_TIMEOUT,
|
|
522
|
+
message: (reason instanceof Error && reason.message?.includes("exceeded timeout"))
|
|
523
|
+
? reason.message
|
|
524
|
+
: `Action exceeded timeout of ${timeoutBudget}ms`,
|
|
525
|
+
};
|
|
526
|
+
finalizer.finalize("timed_out", undefined, error);
|
|
527
|
+
return { ok: false, runId, error: finalizer.persistError || error };
|
|
528
|
+
}
|
|
497
529
|
const reasonMsg = reason instanceof Error
|
|
498
530
|
? reason.message
|
|
499
531
|
: typeof reason === "string"
|
|
@@ -520,7 +552,7 @@ export class DefaultExecutionService {
|
|
|
520
552
|
};
|
|
521
553
|
}
|
|
522
554
|
async invokeChildAction(args) {
|
|
523
|
-
const { controller, rootRunId, childAction, childInput, parentRunId, currentActionId, currentAction, callStack, context, effectiveProcess, effectiveOwner, } = args;
|
|
555
|
+
const { controller, rootRunId, childAction, childInput, parentRunId, currentActionId, currentAction, callStack, context, effectiveProcess, effectiveOwner, logger, options, } = args;
|
|
524
556
|
const invoker = this.actionInvoker;
|
|
525
557
|
if (!invoker) {
|
|
526
558
|
throw new ActionDockError(INVOCATION_UNSUPPORTED, "Nested action invocation requires a Host ActionInvoker");
|
|
@@ -541,18 +573,20 @@ export class DefaultExecutionService {
|
|
|
541
573
|
package: this.identity,
|
|
542
574
|
signal: controller.signal,
|
|
543
575
|
timeoutMs: context.timeoutMs,
|
|
576
|
+
initialTimeoutMs: context.initialTimeoutMs,
|
|
577
|
+
deadline: context.deadline,
|
|
544
578
|
maxCallDepth: context.maxCallDepth,
|
|
545
579
|
config: context.config,
|
|
546
580
|
tenantId: effectiveOwner.tenantId,
|
|
547
581
|
principalId: effectiveOwner.principalId,
|
|
548
582
|
hostSessionId: context.hostSessionId || this.hostSessionId,
|
|
549
|
-
logger: context.logger,
|
|
583
|
+
logger: logger ?? context.logger,
|
|
550
584
|
progress: context.progress,
|
|
551
585
|
process: effectiveProcess,
|
|
552
586
|
owner: effectiveOwner,
|
|
553
587
|
origin: context.origin,
|
|
554
588
|
};
|
|
555
|
-
return await invoker(childAction, childInput, invocationContext);
|
|
589
|
+
return await invoker(childAction, childInput, invocationContext, options);
|
|
556
590
|
}
|
|
557
591
|
async checkIdempotencyGate(input, context, actionRef, effectiveClock) {
|
|
558
592
|
if (!context.requestId) {
|
|
@@ -561,7 +595,7 @@ export class DefaultExecutionService {
|
|
|
561
595
|
const digestPayload = {
|
|
562
596
|
input,
|
|
563
597
|
config: context.config,
|
|
564
|
-
timeoutMs: context.timeoutMs,
|
|
598
|
+
timeoutMs: context.initialTimeoutMs ?? context.timeoutMs,
|
|
565
599
|
};
|
|
566
600
|
const inputDigest = computeDigest(digestPayload);
|
|
567
601
|
const provisionalRunId = crypto.randomUUID();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActionDefinition, ActionRef, ExecutionEvent, ExecutionResult, JsonValue, Logger, ProcessAPI, RunRecord, RunStatus } from "@actiondock/sdk";
|
|
1
|
+
import type { ActionDefinition, ActionInvokeOptions, ActionRef, ExecutionEvent, ExecutionResult, JsonValue, Logger, ProcessAPI, RunRecord, RunStatus } from "@actiondock/sdk";
|
|
2
2
|
import type { ProjectConfig } from "../project/types.js";
|
|
3
3
|
import type { Clock } from "../storage/clock.js";
|
|
4
4
|
import type { EventSink } from "../runtime/events.js";
|
|
@@ -6,7 +6,7 @@ import type { RuntimeStorage } from "../storage/types.js";
|
|
|
6
6
|
import type { ModuleLoader } from "../platform/module-loader.js";
|
|
7
7
|
import { type PackageIdentity, type RunOptions, type InvocationContext, createInvocationContext, createRootInvocationContext } from "../invocation/types.js";
|
|
8
8
|
export { createInvocationContext, createRootInvocationContext };
|
|
9
|
-
export type { PackageIdentity, RunOptions, InvocationContext };
|
|
9
|
+
export type { PackageIdentity, RunOptions, InvocationContext, ActionInvokeOptions };
|
|
10
10
|
/**
|
|
11
11
|
* 局部动作解析器委托函数契约(仅限当前包内部动作)。
|
|
12
12
|
*/
|
|
@@ -29,7 +29,7 @@ export interface ExecutionHandle {
|
|
|
29
29
|
/**
|
|
30
30
|
* 跨包动作调用委托函数。
|
|
31
31
|
*/
|
|
32
|
-
export type ActionInvoker = (childAction: ActionRef | string, childInput: unknown, context: InvocationContext) => Promise<unknown>;
|
|
32
|
+
export type ActionInvoker = (childAction: ActionRef | string, childInput: unknown, context: InvocationContext, options?: ActionInvokeOptions) => Promise<unknown>;
|
|
33
33
|
/**
|
|
34
34
|
* 统一执行协调服务配置选项。
|
|
35
35
|
*/
|
package/dist/host/host.d.ts
CHANGED
|
@@ -9,13 +9,20 @@ import type { StateEntry } from "../storage/types.js";
|
|
|
9
9
|
export declare class DefaultActionDockHost implements ActionDockHost {
|
|
10
10
|
readonly hostSessionId: string;
|
|
11
11
|
readonly options: ActionDockHostOptions;
|
|
12
|
+
readonly allowInstall?: boolean;
|
|
12
13
|
private runtimes;
|
|
14
|
+
private extraRuntimes;
|
|
15
|
+
private extraRuntimeScopes;
|
|
13
16
|
readonly policy: InvocationPolicy;
|
|
14
17
|
private hostPublicPackageIds;
|
|
15
18
|
private maxCallDepth;
|
|
16
19
|
private maxSubRuns;
|
|
17
20
|
private eventSink;
|
|
18
21
|
private isClosed;
|
|
22
|
+
private readonly prepareLocalPackage?;
|
|
23
|
+
private readonly closeController;
|
|
24
|
+
private readonly activePreparations;
|
|
25
|
+
private closePromise?;
|
|
19
26
|
private dataDirLock?;
|
|
20
27
|
private failedLinkedPackages;
|
|
21
28
|
private failedAutoLoad?;
|
|
@@ -26,6 +33,9 @@ export declare class DefaultActionDockHost implements ActionDockHost {
|
|
|
26
33
|
private globalStorage?;
|
|
27
34
|
private initPromise?;
|
|
28
35
|
private isInitialized;
|
|
36
|
+
private readonly actionBindings;
|
|
37
|
+
private readonly remoteTargets;
|
|
38
|
+
private readonly remoteInvoker;
|
|
29
39
|
readonly discovery: DiscoveryPort;
|
|
30
40
|
readonly execution: ExecutionPort;
|
|
31
41
|
readonly runs: RunsPort;
|
|
@@ -60,6 +70,8 @@ export declare class DefaultActionDockHost implements ActionDockHost {
|
|
|
60
70
|
* 外部注入的 Runtime 保持既有生命周期约定,不在此预热。
|
|
61
71
|
*/
|
|
62
72
|
private prewarmManagedRuntimes;
|
|
73
|
+
/** 返回的 Runtime 由 Host 统一接管,端口只清理自身缓存和附属资源。 */
|
|
74
|
+
private closeInvocationTargets;
|
|
63
75
|
/**
|
|
64
76
|
* 异步安全回滚初始化失败时所占用的资源。
|
|
65
77
|
*/
|
|
@@ -106,6 +118,12 @@ export declare class DefaultActionDockHost implements ActionDockHost {
|
|
|
106
118
|
describePlaybook(id: string): Promise<PlaybookSpec>;
|
|
107
119
|
runAction(ref: ActionRef | string, input: JsonValue, options?: RunOptions): Promise<ExecutionResult>;
|
|
108
120
|
startAction(ref: ActionRef | string, input: JsonValue, options?: RunOptions): Promise<ExecutionTicket>;
|
|
121
|
+
/**
|
|
122
|
+
* 私有本地 Action 调度中枢。
|
|
123
|
+
* 统一处理本地已授权目标的准备(若已注入 prepareLocalPackage 且存在物理包根路径)、
|
|
124
|
+
* 中断与关闭复核,并分发至目标 Runtime 的 startInvocation。
|
|
125
|
+
*/
|
|
126
|
+
private dispatchLocalInvocation;
|
|
109
127
|
getRun(runId: string, signal?: AbortSignal): Promise<RunRecord | undefined>;
|
|
110
128
|
listRuns(query?: ListRunsOptions, signal?: AbortSignal): Promise<RunRecord[]>;
|
|
111
129
|
countRuns(query?: ListRunsOptions, signal?: AbortSignal): Promise<number>;
|
|
@@ -120,7 +138,8 @@ export declare class DefaultActionDockHost implements ActionDockHost {
|
|
|
120
138
|
cancelRun(runId: string, reason?: string): Promise<CancelResult>;
|
|
121
139
|
private subscribeEvents;
|
|
122
140
|
private getGlobalStorage;
|
|
123
|
-
private
|
|
141
|
+
private findAllDeclaredConfigItems;
|
|
142
|
+
private protectGlobalConfigView;
|
|
124
143
|
private resolveRuntime;
|
|
125
144
|
/**
|
|
126
145
|
* 解析目标包运行时:未命中时抛出统一的包未找到错误。
|