@actiondock/core 2.6.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -68
- package/dist/catalog/action-catalog.d.ts +56 -0
- package/dist/catalog/action-catalog.js +202 -0
- package/dist/catalog/discovery.d.ts +60 -0
- package/dist/catalog/discovery.js +119 -0
- package/dist/catalog/graph.d.ts +190 -0
- package/dist/catalog/graph.js +589 -0
- package/dist/catalog/index.d.ts +5 -5
- package/dist/catalog/index.js +5 -5
- package/dist/catalog/resolve-action.d.ts +43 -0
- package/dist/catalog/resolve-action.js +119 -0
- package/dist/catalog/resolve-playbook.d.ts +26 -0
- package/dist/catalog/resolve-playbook.js +114 -0
- package/dist/doctor/checks/project.js +27 -8
- package/dist/doctor/checks/registry.js +2 -2
- package/dist/doctor/checks/runtime.js +34 -1
- package/dist/errors.d.ts +122 -10
- package/dist/errors.js +123 -10
- package/dist/execution/service.d.ts +18 -16
- package/dist/execution/service.js +183 -252
- package/dist/execution/types.d.ts +25 -69
- package/dist/execution/types.js +2 -1
- package/dist/filter/intent.d.ts +8 -9
- package/dist/filter/intent.js +49 -10
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.js +4 -0
- package/dist/host/host.d.ts +74 -32
- package/dist/host/host.js +585 -336
- package/dist/host/routing.d.ts +15 -48
- package/dist/host/routing.js +90 -153
- package/dist/host/types.d.ts +50 -17
- package/dist/index.d.ts +21 -22
- package/dist/index.js +19 -21
- package/dist/input/advice.d.ts +104 -0
- package/dist/input/advice.js +716 -0
- package/dist/input/describe.d.ts +106 -0
- package/dist/input/describe.js +176 -0
- package/dist/input/file-input.d.ts +54 -0
- package/dist/input/file-input.js +124 -0
- package/dist/input/flat-decode.d.ts +11 -0
- package/dist/input/flat-decode.js +13 -0
- package/dist/input/flat-errors.d.ts +71 -0
- package/dist/input/flat-errors.js +87 -0
- package/dist/input/flat-materializer.d.ts +29 -0
- package/dist/input/flat-materializer.js +177 -0
- package/dist/input/flat-parser.d.ts +50 -0
- package/dist/input/flat-parser.js +169 -0
- package/dist/input/flat-predicates.d.ts +34 -0
- package/dist/input/flat-predicates.js +50 -0
- package/dist/input/index.d.ts +14 -0
- package/dist/input/index.js +14 -0
- package/dist/input/input-resolver.d.ts +63 -0
- package/dist/input/input-resolver.js +254 -0
- package/dist/input/json-depth-scanner.d.ts +17 -0
- package/dist/input/json-depth-scanner.js +49 -0
- package/dist/input/metadata.d.ts +99 -0
- package/dist/input/metadata.js +99 -0
- package/dist/input/stdin-input.d.ts +26 -0
- package/dist/input/stdin-input.js +125 -0
- package/dist/input/utf8.d.ts +19 -0
- package/dist/input/utf8.js +36 -0
- package/dist/input/validation-mapper.d.ts +27 -0
- package/dist/input/validation-mapper.js +144 -0
- package/dist/invocation/index.d.ts +2 -0
- package/dist/invocation/index.js +2 -0
- package/dist/invocation/policy.d.ts +157 -0
- package/dist/invocation/policy.js +231 -0
- package/dist/invocation/types.d.ts +172 -0
- package/dist/invocation/types.js +97 -0
- package/dist/ipc/diagnostic.d.ts +0 -12
- package/dist/ipc/diagnostic.js +0 -21
- package/dist/ipc/host.d.ts +4 -4
- package/dist/ipc/host.js +44 -47
- package/dist/ipc/index.d.ts +1 -1
- package/dist/ipc/index.js +1 -1
- package/dist/ipc/service.d.ts +40 -0
- package/dist/ipc/service.js +349 -0
- package/dist/ipc/types.d.ts +21 -15
- package/dist/json/index.d.ts +1 -0
- package/dist/json/index.js +1 -0
- package/dist/json/value-validator.d.ts +88 -0
- package/dist/json/value-validator.js +330 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/module-loader.d.ts +63 -0
- package/dist/node/module-loader.js +112 -0
- package/dist/package/index.d.ts +23 -0
- package/dist/package/index.js +18 -0
- package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
- package/dist/{app/app.js → package/runtime.js} +140 -95
- package/dist/{app → package}/static-index.js +58 -41
- package/dist/package/storage-view.d.ts +13 -0
- package/dist/package/storage-view.js +22 -0
- package/dist/{app → package}/types.d.ts +76 -57
- package/dist/package/types.js +22 -0
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +1 -1
- package/dist/platform/node.d.ts +48 -0
- package/dist/platform/node.js +96 -0
- package/dist/platform/types.d.ts +0 -9
- package/dist/process/control-arbiter.d.ts +2 -1
- package/dist/process/control-arbiter.js +1 -2
- package/dist/process/driver.d.ts +9 -8
- package/dist/process/driver.js +11 -22
- package/dist/process/index.d.ts +2 -0
- package/dist/process/index.js +2 -0
- package/dist/process/managed-record.d.ts +2 -2
- package/dist/process/process-driver.d.ts +109 -0
- package/dist/process/process-driver.js +650 -0
- package/dist/process/process-executor.d.ts +47 -0
- package/dist/process/process-executor.js +296 -0
- package/dist/process/process-manager.js +48 -26
- package/dist/process/run-executor.js +12 -12
- package/dist/profile/client-actions.js +2 -2
- package/dist/profile/client-health.js +3 -2
- package/dist/profile/client-query.js +5 -6
- package/dist/profile/client-transport.d.ts +19 -17
- package/dist/profile/client-transport.js +48 -80
- package/dist/profile/client.d.ts +2 -2
- package/dist/profile/client.js +1 -1
- package/dist/profile/index.d.ts +1 -0
- package/dist/profile/index.js +1 -0
- package/dist/profile/manager.d.ts +5 -0
- package/dist/profile/manager.js +41 -6
- package/dist/project/closure.js +2 -2
- package/dist/project/index.d.ts +8 -1
- package/dist/project/index.js +10 -1
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +1 -1
- package/dist/project/loader.js +26 -29
- package/dist/project/transactions.js +5 -10
- package/dist/registry/index.d.ts +3 -1
- package/dist/registry/index.js +2 -1
- package/dist/registry/lock.d.ts +28 -7
- package/dist/registry/lock.js +136 -16
- package/dist/registry/registry.d.ts +1 -5
- package/dist/registry/registry.js +1 -53
- package/dist/registry/scan.d.ts +0 -15
- package/dist/registry/scan.js +0 -59
- package/dist/registry/store.d.ts +42 -0
- package/dist/registry/store.js +43 -0
- package/dist/registry/types.d.ts +0 -24
- package/dist/runtime/action-collection.d.ts +1 -1
- package/dist/runtime/action-registry.d.ts +0 -4
- package/dist/runtime/action-registry.js +0 -7
- package/dist/runtime/context.js +5 -11
- package/dist/runtime/events.js +3 -6
- package/dist/runtime/identity.d.ts +22 -0
- package/dist/runtime/identity.js +10 -0
- package/dist/runtime/index.d.ts +1 -2
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/module-loader.d.ts +2 -34
- package/dist/runtime/module-loader.js +1 -16
- package/dist/runtime/process.d.ts +6 -24
- package/dist/runtime/process.js +1 -118
- package/dist/runtime/run-persistence.js +2 -5
- package/dist/runtime/runner.d.ts +33 -103
- package/dist/runtime/runner.js +142 -404
- package/dist/runtime/standalone.d.ts +37 -9
- package/dist/runtime/standalone.js +195 -136
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/validator.d.ts +10 -0
- package/dist/schema/validator.js +48 -54
- package/dist/server/body.d.ts +16 -8
- package/dist/server/body.js +33 -16
- package/dist/server/dispatcher.d.ts +6 -10
- package/dist/server/dispatcher.js +24 -32
- package/dist/server/http-server.d.ts +87 -0
- package/dist/server/http-server.js +304 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +10 -0
- package/dist/server/mcp-endpoint.d.ts +61 -0
- package/dist/server/mcp-endpoint.js +118 -0
- package/dist/server/routes/actions.js +34 -28
- package/dist/server/routes/common.d.ts +10 -14
- package/dist/server/routes/common.js +32 -56
- package/dist/server/routes/config.js +54 -64
- package/dist/server/routes/doctor.d.ts +1 -1
- package/dist/server/routes/doctor.js +10 -18
- package/dist/server/routes/health.d.ts +1 -1
- package/dist/server/routes/health.js +2 -3
- package/dist/server/routes/info.d.ts +2 -2
- package/dist/server/routes/info.js +12 -13
- package/dist/server/routes/playbooks.js +16 -29
- package/dist/server/routes/runs.js +95 -117
- package/dist/server/routes/state.js +63 -62
- package/dist/server/server.d.ts +2 -2
- package/dist/server/server.js +43 -227
- package/dist/server/types.d.ts +8 -19
- package/dist/service/factory.d.ts +12 -0
- package/dist/service/factory.js +85 -0
- package/dist/{target → service}/index.d.ts +1 -1
- package/dist/{target → service}/index.js +1 -1
- package/dist/service/local.d.ts +27 -0
- package/dist/service/local.js +138 -0
- package/dist/{target → service}/remote-errors.d.ts +3 -6
- package/dist/service/remote-errors.js +38 -0
- package/dist/{target → service}/remote-polling.d.ts +2 -2
- package/dist/{target → service}/remote-polling.js +8 -8
- package/dist/service/remote.d.ts +34 -0
- package/dist/service/remote.js +634 -0
- package/dist/service/sse-stream.d.ts +24 -0
- package/dist/service/sse-stream.js +139 -0
- package/dist/service/types.d.ts +272 -0
- package/dist/service/types.js +32 -0
- package/dist/storage/data-dir-lock.js +10 -5
- package/dist/storage/driver.d.ts +2 -1
- package/dist/storage/driver.js +3 -52
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/lock-core.d.ts +2 -6
- package/dist/storage/lock-core.js +4 -17
- package/dist/storage/params.d.ts +2 -8
- package/dist/storage/params.js +2 -8
- package/dist/storage/sqlite-driver.d.ts +40 -0
- package/dist/storage/sqlite-driver.js +116 -0
- package/dist/storage/sqlite.js +21 -6
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.js +2 -2
- package/dist/utils/index.d.ts +53 -0
- package/dist/utils/index.js +99 -4
- package/dist/utils/process.d.ts +10 -0
- package/dist/utils/process.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +41 -3
- package/dist/app/index.d.ts +0 -2
- package/dist/app/index.js +0 -2
- package/dist/app/types.js +0 -1
- package/dist/catalog/action-index.d.ts +0 -9
- package/dist/catalog/action-index.js +0 -95
- package/dist/catalog/action-resolver.d.ts +0 -20
- package/dist/catalog/action-resolver.js +0 -95
- package/dist/catalog/location-registry.d.ts +0 -15
- package/dist/catalog/location-registry.js +0 -138
- package/dist/catalog/package-catalog.d.ts +0 -7
- package/dist/catalog/package-catalog.js +0 -77
- package/dist/catalog/types.d.ts +0 -68
- package/dist/catalog/types.js +0 -1
- package/dist/export/index.d.ts +0 -1
- package/dist/export/index.js +0 -1
- package/dist/export/templates.d.ts +0 -71
- package/dist/export/templates.js +0 -623
- package/dist/ipc/target.d.ts +0 -74
- package/dist/ipc/target.js +0 -365
- package/dist/platform/default.d.ts +0 -38
- package/dist/platform/default.js +0 -78
- package/dist/project/resolver.d.ts +0 -116
- package/dist/project/resolver.js +0 -376
- package/dist/registry/resolve.d.ts +0 -62
- package/dist/registry/resolve.js +0 -195
- package/dist/runtime/execution-manager.d.ts +0 -48
- package/dist/runtime/execution-manager.js +0 -66
- package/dist/runtime/package-runner-factory.d.ts +0 -82
- package/dist/runtime/package-runner-factory.js +0 -186
- package/dist/target/local.d.ts +0 -53
- package/dist/target/local.js +0 -349
- package/dist/target/remote-errors.js +0 -51
- package/dist/target/remote.d.ts +0 -86
- package/dist/target/remote.js +0 -818
- package/dist/target/target.d.ts +0 -6
- package/dist/target/target.js +0 -37
- package/dist/target/types.d.ts +0 -261
- package/dist/target/types.js +0 -35
- /package/dist/{app → package}/static-index.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.js +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { InputValidationSource } from "./flat-errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* 校验并严格解码字节序列为合法 UTF-8 字符串。
|
|
4
|
+
* 使用 TextDecoder("utf-8", { fatal: true }) 拦截非法编码字节并抛出结构化 INVALID_JSON 异常。
|
|
5
|
+
*
|
|
6
|
+
* @param bytes 待解码的原始字节数据
|
|
7
|
+
* @param source 输入校验来源(默认为 full-json-inline)
|
|
8
|
+
* @returns 解码后的 UTF-8 文本
|
|
9
|
+
* @throws InputError 当包含非法 UTF-8 字节序列时抛出 INVALID_JSON 异常
|
|
10
|
+
*/
|
|
11
|
+
export declare function decodeUtf8Strict(bytes: Uint8Array | Buffer, source?: InputValidationSource): string;
|
|
12
|
+
/**
|
|
13
|
+
* 仅剥离输入字符串起始处的恰好一个 U+FEFF BOM。
|
|
14
|
+
* 若存在双重 BOM(\uFEFF\uFEFF),仅剥离首个,第二个保留给后续 JSON 解析器以触发 SYNTAX_ERROR。
|
|
15
|
+
*
|
|
16
|
+
* @param text 原始输入文本
|
|
17
|
+
* @returns 剥离首个 BOM 后的文本
|
|
18
|
+
*/
|
|
19
|
+
export declare function stripBom(text: string): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { mapInputValidationFailure } from "./validation-mapper.js";
|
|
2
|
+
/**
|
|
3
|
+
* 校验并严格解码字节序列为合法 UTF-8 字符串。
|
|
4
|
+
* 使用 TextDecoder("utf-8", { fatal: true }) 拦截非法编码字节并抛出结构化 INVALID_JSON 异常。
|
|
5
|
+
*
|
|
6
|
+
* @param bytes 待解码的原始字节数据
|
|
7
|
+
* @param source 输入校验来源(默认为 full-json-inline)
|
|
8
|
+
* @returns 解码后的 UTF-8 文本
|
|
9
|
+
* @throws InputError 当包含非法 UTF-8 字节序列时抛出 INVALID_JSON 异常
|
|
10
|
+
*/
|
|
11
|
+
export function decodeUtf8Strict(bytes, source = "full-json-inline") {
|
|
12
|
+
try {
|
|
13
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
14
|
+
return decoder.decode(bytes);
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
throw mapInputValidationFailure(source, {
|
|
18
|
+
valid: false,
|
|
19
|
+
code: "INVALID_UTF8",
|
|
20
|
+
reason: `Invalid UTF-8 encoding: ${err instanceof Error ? err.message : String(err)}`,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 仅剥离输入字符串起始处的恰好一个 U+FEFF BOM。
|
|
26
|
+
* 若存在双重 BOM(\uFEFF\uFEFF),仅剥离首个,第二个保留给后续 JSON 解析器以触发 SYNTAX_ERROR。
|
|
27
|
+
*
|
|
28
|
+
* @param text 原始输入文本
|
|
29
|
+
* @returns 剥离首个 BOM 后的文本
|
|
30
|
+
*/
|
|
31
|
+
export function stripBom(text) {
|
|
32
|
+
if (text.charCodeAt(0) === 0xfeff) {
|
|
33
|
+
return text.slice(1);
|
|
34
|
+
}
|
|
35
|
+
return text;
|
|
36
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { InputError, type InputValidationSource } from "./flat-errors.js";
|
|
2
|
+
import type { ActionInputValidationResult, JsonValueValidationResult } from "../json/value-validator.js";
|
|
3
|
+
/**
|
|
4
|
+
* 校验失败结构化输入描述。
|
|
5
|
+
*/
|
|
6
|
+
export type ValidationFailureInput = Exclude<ActionInputValidationResult, {
|
|
7
|
+
valid: true;
|
|
8
|
+
}> | Exclude<JsonValueValidationResult, {
|
|
9
|
+
valid: true;
|
|
10
|
+
}> | {
|
|
11
|
+
valid: false;
|
|
12
|
+
kind?: "json-value" | "input-policy";
|
|
13
|
+
code: string;
|
|
14
|
+
reason: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
property?: string;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* 将校验失败结果根据输入来源映射为统一结构化异常。
|
|
21
|
+
* 遵循技术设计文档第 19 节 Mapping Table 规范。
|
|
22
|
+
*
|
|
23
|
+
* @param source 输入校验来源
|
|
24
|
+
* @param result 校验失败结果对象
|
|
25
|
+
* @returns 映射后的结构化输入异常
|
|
26
|
+
*/
|
|
27
|
+
export declare function mapInputValidationFailure(source: InputValidationSource, result: ActionInputValidationResult | JsonValueValidationResult | ValidationFailureInput): InputError;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { INPUT_NOT_JSON, INPUT_VALIDATION_FAILED, } from "../errors.js";
|
|
2
|
+
import { InputError, invalidJson, invalidJsonLiteral, flatInputLimitExceeded, inputLimitExceeded, inputPolicyViolation, } from "./flat-errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* 将校验失败结果根据输入来源映射为统一结构化异常。
|
|
5
|
+
* 遵循技术设计文档第 19 节 Mapping Table 规范。
|
|
6
|
+
*
|
|
7
|
+
* @param source 输入校验来源
|
|
8
|
+
* @param result 校验失败结果对象
|
|
9
|
+
* @returns 映射后的结构化输入异常
|
|
10
|
+
*/
|
|
11
|
+
export function mapInputValidationFailure(source, result) {
|
|
12
|
+
const failure = result;
|
|
13
|
+
const code = failure.code;
|
|
14
|
+
const reason = failure.reason;
|
|
15
|
+
const path = failure.path;
|
|
16
|
+
const isPolicyViolation = failure.kind === "input-policy" || code === "FORBIDDEN_PROPERTY";
|
|
17
|
+
switch (source) {
|
|
18
|
+
case "flat-json-literal": {
|
|
19
|
+
if (code === "SYNTAX_ERROR") {
|
|
20
|
+
return invalidJsonLiteral(reason || "Invalid JSON literal syntax", {
|
|
21
|
+
reason: "SYNTAX_ERROR",
|
|
22
|
+
path,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (code === "NON_FINITE_NUMBER") {
|
|
26
|
+
return invalidJsonLiteral(reason || "Non-finite number in JSON literal", {
|
|
27
|
+
reason: "NON_FINITE_NUMBER",
|
|
28
|
+
path,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (code === "MAX_JSON_DEPTH") {
|
|
32
|
+
return invalidJsonLiteral(reason || "Max JSON depth limit exceeded in JSON literal", {
|
|
33
|
+
reason: "MAX_JSON_DEPTH",
|
|
34
|
+
path,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return invalidJsonLiteral(reason || "Invalid JSON literal value", {
|
|
38
|
+
reason: "INVALID_JSON_VALUE",
|
|
39
|
+
path,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
case "full-json-inline":
|
|
43
|
+
case "full-json-file":
|
|
44
|
+
case "full-json-stdin": {
|
|
45
|
+
const cliSource = source === "full-json-inline"
|
|
46
|
+
? "inline-json"
|
|
47
|
+
: source === "full-json-file"
|
|
48
|
+
? "file"
|
|
49
|
+
: "stdin";
|
|
50
|
+
if (code === "SYNTAX_ERROR") {
|
|
51
|
+
return invalidJson(reason || "Invalid JSON syntax", {
|
|
52
|
+
reason: "SYNTAX_ERROR",
|
|
53
|
+
source: cliSource,
|
|
54
|
+
path,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (code === "INVALID_UTF8") {
|
|
58
|
+
return invalidJson(reason || "Invalid UTF-8 encoding in JSON input", {
|
|
59
|
+
reason: "INVALID_UTF8",
|
|
60
|
+
source: cliSource,
|
|
61
|
+
path,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (code === "NON_FINITE_NUMBER") {
|
|
65
|
+
return invalidJson(reason || "Number is non-finite or NaN", {
|
|
66
|
+
reason: "NON_FINITE_NUMBER",
|
|
67
|
+
source: cliSource,
|
|
68
|
+
path,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (code === "MAX_JSON_DEPTH") {
|
|
72
|
+
return invalidJson(reason || "Max JSON depth limit exceeded", {
|
|
73
|
+
reason: "MAX_JSON_DEPTH",
|
|
74
|
+
source: cliSource,
|
|
75
|
+
path,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return invalidJson(reason || "Invalid JSON value", {
|
|
79
|
+
reason: "INVALID_JSON_VALUE",
|
|
80
|
+
source: cliSource,
|
|
81
|
+
path,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
case "flat-materialized": {
|
|
85
|
+
if (code === "MAX_JSON_DEPTH") {
|
|
86
|
+
return flatInputLimitExceeded(reason || "Materialized JSON depth limit exceeded", {
|
|
87
|
+
reason: "MAX_MATERIALIZED_JSON_DEPTH",
|
|
88
|
+
path,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (code === "MAX_MATERIALIZED_BYTES") {
|
|
92
|
+
return flatInputLimitExceeded(reason || "Materialized input size exceeds limit", {
|
|
93
|
+
reason: "MAX_MATERIALIZED_BYTES",
|
|
94
|
+
path,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return flatInputLimitExceeded(reason || "Materialized input validation failed", {
|
|
98
|
+
reason: "INVALID_JSON_VALUE",
|
|
99
|
+
path,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
case "cli-pre-target": {
|
|
103
|
+
if (isPolicyViolation) {
|
|
104
|
+
const property = failure.property;
|
|
105
|
+
return inputPolicyViolation(reason || `Forbidden property "${property}" is not allowed in Action input`, {
|
|
106
|
+
reason: "FORBIDDEN_PROPERTY",
|
|
107
|
+
property,
|
|
108
|
+
path,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (code === "MAX_JSON_DEPTH") {
|
|
112
|
+
return inputLimitExceeded(reason || "Max JSON depth limit exceeded", {
|
|
113
|
+
reason: "MAX_JSON_DEPTH",
|
|
114
|
+
path,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (code === "NON_FINITE_NUMBER") {
|
|
118
|
+
return invalidJson(reason || "Number is non-finite or NaN", {
|
|
119
|
+
reason: "NON_FINITE_NUMBER",
|
|
120
|
+
path,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return invalidJson(reason || "Invalid JSON value in Action input", {
|
|
124
|
+
reason: "INVALID_JSON_VALUE",
|
|
125
|
+
path,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
case "runtime": {
|
|
129
|
+
if (isPolicyViolation) {
|
|
130
|
+
return new InputError(INPUT_VALIDATION_FAILED, reason || "Action input contains forbidden property", [reason || "Forbidden property in input"]);
|
|
131
|
+
}
|
|
132
|
+
return new InputError(INPUT_NOT_JSON, reason || "Input is not a valid JSON value", {
|
|
133
|
+
reason: code,
|
|
134
|
+
path,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
default: {
|
|
138
|
+
return new InputError(INPUT_NOT_JSON, reason || "Input validation failed", {
|
|
139
|
+
reason: code,
|
|
140
|
+
path,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { type ErrorCode } from "../errors.js";
|
|
2
|
+
import type { PackageGraph } from "../catalog/graph.js";
|
|
3
|
+
/**
|
|
4
|
+
* 调用治理策略初始化选项。
|
|
5
|
+
*/
|
|
6
|
+
export interface InvocationPolicyOptions {
|
|
7
|
+
/** 最大调用嵌套深度限制(默认 16) */
|
|
8
|
+
maxCallDepth?: number;
|
|
9
|
+
/** 单个根任务下最大并发活跃子任务数(默认 64) */
|
|
10
|
+
maxSubRuns?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 根调用可见性上下文。
|
|
14
|
+
*/
|
|
15
|
+
export interface RootVisibilityContext {
|
|
16
|
+
/** 宿主公开暴露的包标识集合 */
|
|
17
|
+
hostPublicPackageIds: ReadonlySet<string>;
|
|
18
|
+
/** 包依赖拓扑图 */
|
|
19
|
+
graph?: PackageGraph;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 调用方声明规范契约。
|
|
23
|
+
*/
|
|
24
|
+
export interface CallerActionInfo {
|
|
25
|
+
packageId: string;
|
|
26
|
+
actionId: string;
|
|
27
|
+
declaredUses?: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 目标 Action 规范契约。
|
|
31
|
+
*/
|
|
32
|
+
export interface TargetActionInfo {
|
|
33
|
+
packageId: string;
|
|
34
|
+
actionId: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 调用治理策略错误描述。
|
|
38
|
+
*/
|
|
39
|
+
export interface PolicyError {
|
|
40
|
+
code: ErrorCode;
|
|
41
|
+
message: string;
|
|
42
|
+
details?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 环路检测结果。
|
|
46
|
+
*/
|
|
47
|
+
export interface CycleCheckResult {
|
|
48
|
+
callKey: string;
|
|
49
|
+
error?: PolicyError;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 全局统一调用治理策略服务(InvocationPolicy)。
|
|
53
|
+
*
|
|
54
|
+
* 铁律 5 单一事实源:统一负责 root visibility、caller -> callee authorization、
|
|
55
|
+
* uses 检查、max call depth、cycle detection、subrun quota 与 lineage policy。
|
|
56
|
+
* 彻底消除 Host、ExecutionService 与 ActionRunner 中分散重复的检查逻辑。
|
|
57
|
+
*/
|
|
58
|
+
export declare class InvocationPolicy {
|
|
59
|
+
readonly maxCallDepth: number;
|
|
60
|
+
readonly maxSubRuns: number;
|
|
61
|
+
private readonly activeSubRunsPerRoot;
|
|
62
|
+
private visibilityContext?;
|
|
63
|
+
constructor(options?: InvocationPolicyOptions);
|
|
64
|
+
/**
|
|
65
|
+
* 设置路由可见性上下文。
|
|
66
|
+
*/
|
|
67
|
+
setVisibilityContext(context?: RootVisibilityContext): void;
|
|
68
|
+
/**
|
|
69
|
+
* 严格断言根调用可见性(Root Visibility Assertion)。
|
|
70
|
+
* 若不可见则抛出 ActionDockError(UNDECLARED_ACTION_DEPENDENCY, ...)。
|
|
71
|
+
*/
|
|
72
|
+
assertRootVisibility(resolved: {
|
|
73
|
+
package: {
|
|
74
|
+
id: string;
|
|
75
|
+
};
|
|
76
|
+
ref: {
|
|
77
|
+
actionId: string;
|
|
78
|
+
};
|
|
79
|
+
}, context?: RootVisibilityContext): void;
|
|
80
|
+
/**
|
|
81
|
+
* 根调用可见性判定与鉴权(Root Visibility Policy)。
|
|
82
|
+
*
|
|
83
|
+
* 判定规则:
|
|
84
|
+
* - 宿主公开注册的包(直接依赖包或显式声明包)允许根调用;
|
|
85
|
+
* - 传递依赖包必须经由可见 Playbook 委托授权,否则拦截并返回 UNDECLARED_ACTION_DEPENDENCY。
|
|
86
|
+
*
|
|
87
|
+
* @param targetPackageId 目标包标识
|
|
88
|
+
* @param targetActionId 目标 Action 标识
|
|
89
|
+
* @param context 路由可见性上下文
|
|
90
|
+
* @returns 若拦截返回标准 RuntimeError,通过则返回 undefined
|
|
91
|
+
*/
|
|
92
|
+
checkRootVisibility(targetPackageId: string, targetActionId: string, context: RootVisibilityContext): PolicyError | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* 调用方至目标动作 uses 依赖声明授权校验(Caller -> Callee Authorization & Uses Policy)。
|
|
95
|
+
*
|
|
96
|
+
* 判定规则:
|
|
97
|
+
* - 同包内部 Action 互调自然合法,豁免 uses 声明;
|
|
98
|
+
* - 跨包调用必须在调用方 Action 的 uses 声明列表中显式声明目标(完全限定名、通配符或包名),
|
|
99
|
+
* 或经由 PackageGraph.canCascadeCall 裁决通过;未声明直接拦截。
|
|
100
|
+
*
|
|
101
|
+
* @param caller 调用方 Action 标识与声明上下文
|
|
102
|
+
* @param target 目标 Action 标识
|
|
103
|
+
* @param graph 可选的包依赖拓扑图
|
|
104
|
+
* @returns 若鉴权未通过返回标准 RuntimeError,通过则返回 undefined
|
|
105
|
+
*/
|
|
106
|
+
checkUsesAuthorization(caller: CallerActionInfo, target: TargetActionInfo, graph?: PackageGraph): PolicyError | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* 调用嵌套最大深度限制校验(Max Call Depth Policy)。
|
|
109
|
+
*
|
|
110
|
+
* 超限时返回标准 ACTION_CALL_CYCLE 错误。
|
|
111
|
+
*
|
|
112
|
+
* @param callStack 当前已累积的调用栈切片
|
|
113
|
+
* @param targetActionId 欲调用的目标 Action 标识
|
|
114
|
+
* @param maxDepthOverride 临时执行覆盖的最大深度限制
|
|
115
|
+
* @returns 超限错误或 undefined
|
|
116
|
+
*/
|
|
117
|
+
checkCallDepth(callStack: readonly string[], targetActionId: string, maxDepthOverride?: number): PolicyError | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* 调用链环路死锁检测(Cycle Detection Policy)。
|
|
120
|
+
*
|
|
121
|
+
* 计算目标调用键并在历史调用栈中执行检测,杜绝 A -> B -> A 形成死锁。
|
|
122
|
+
* 命中环路时返回 ACTION_CALL_CYCLE 错误。
|
|
123
|
+
*
|
|
124
|
+
* @param callStack 当前已累积的调用栈切片
|
|
125
|
+
* @param targetActionId 欲调用的目标 Action 标识
|
|
126
|
+
* @param targetPackageId 目标 Action 所属包标识
|
|
127
|
+
* @param currentPackageId 当前执行发起方包标识
|
|
128
|
+
* @returns 包含规范化 callKey 与可选错误的结构体
|
|
129
|
+
*/
|
|
130
|
+
checkCycle(callStack: readonly string[], targetActionId: string, targetPackageId?: string, currentPackageId?: string): CycleCheckResult;
|
|
131
|
+
/**
|
|
132
|
+
* 并发活跃子任务配额检查(Sub-Run Quota Policy)。
|
|
133
|
+
*
|
|
134
|
+
* 针对同源 rootRunId 限制派生的并发子任务上限,防止资源耗尽。
|
|
135
|
+
*
|
|
136
|
+
* @param rootRunId 根运行标识符
|
|
137
|
+
* @returns 超限错误或 undefined
|
|
138
|
+
*/
|
|
139
|
+
checkSubRunQuota(rootRunId: string): PolicyError | undefined;
|
|
140
|
+
/**
|
|
141
|
+
* 申请子任务并发配额槽位。
|
|
142
|
+
*
|
|
143
|
+
* @param rootRunId 根运行标识符
|
|
144
|
+
* @returns 是否成功获取槽位(若已达上限返回 false)
|
|
145
|
+
*/
|
|
146
|
+
acquireSubRun(rootRunId: string): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* 释放已申请的子任务并发配额槽位。
|
|
149
|
+
*
|
|
150
|
+
* @param rootRunId 根运行标识符
|
|
151
|
+
*/
|
|
152
|
+
releaseSubRun(rootRunId: string): void;
|
|
153
|
+
/**
|
|
154
|
+
* 获取指定根运行当前的活跃并发子任务计数。
|
|
155
|
+
*/
|
|
156
|
+
getActiveSubRuns(rootRunId: string): number;
|
|
157
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { ACTION_CALL_CYCLE, ACTION_SUBRUN_LIMIT, UNDECLARED_ACTION_DEPENDENCY, ActionDockError, } from "../errors.js";
|
|
2
|
+
import { isUsesDeclared } from "../catalog/graph.js";
|
|
3
|
+
/**
|
|
4
|
+
* 全局统一调用治理策略服务(InvocationPolicy)。
|
|
5
|
+
*
|
|
6
|
+
* 铁律 5 单一事实源:统一负责 root visibility、caller -> callee authorization、
|
|
7
|
+
* uses 检查、max call depth、cycle detection、subrun quota 与 lineage policy。
|
|
8
|
+
* 彻底消除 Host、ExecutionService 与 ActionRunner 中分散重复的检查逻辑。
|
|
9
|
+
*/
|
|
10
|
+
export class InvocationPolicy {
|
|
11
|
+
maxCallDepth;
|
|
12
|
+
maxSubRuns;
|
|
13
|
+
activeSubRunsPerRoot = new Map();
|
|
14
|
+
visibilityContext;
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.maxCallDepth = options.maxCallDepth ?? 16;
|
|
17
|
+
this.maxSubRuns = options.maxSubRuns ?? 64;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 设置路由可见性上下文。
|
|
21
|
+
*/
|
|
22
|
+
setVisibilityContext(context) {
|
|
23
|
+
this.visibilityContext = context;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 严格断言根调用可见性(Root Visibility Assertion)。
|
|
27
|
+
* 若不可见则抛出 ActionDockError(UNDECLARED_ACTION_DEPENDENCY, ...)。
|
|
28
|
+
*/
|
|
29
|
+
assertRootVisibility(resolved, context) {
|
|
30
|
+
const ctx = context ?? this.visibilityContext;
|
|
31
|
+
if (!ctx) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const error = this.checkRootVisibility(resolved.package.id, resolved.ref.actionId, ctx);
|
|
35
|
+
if (error) {
|
|
36
|
+
throw new ActionDockError(error.code, error.message, error.details);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 根调用可见性判定与鉴权(Root Visibility Policy)。
|
|
41
|
+
*
|
|
42
|
+
* 判定规则:
|
|
43
|
+
* - 宿主公开注册的包(直接依赖包或显式声明包)允许根调用;
|
|
44
|
+
* - 传递依赖包必须经由可见 Playbook 委托授权,否则拦截并返回 UNDECLARED_ACTION_DEPENDENCY。
|
|
45
|
+
*
|
|
46
|
+
* @param targetPackageId 目标包标识
|
|
47
|
+
* @param targetActionId 目标 Action 标识
|
|
48
|
+
* @param context 路由可见性上下文
|
|
49
|
+
* @returns 若拦截返回标准 RuntimeError,通过则返回 undefined
|
|
50
|
+
*/
|
|
51
|
+
checkRootVisibility(targetPackageId, targetActionId, context) {
|
|
52
|
+
const isPublic = context.hostPublicPackageIds.has(targetPackageId);
|
|
53
|
+
if (isPublic) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
if (context.graph && !context.graph.canRootCall(targetPackageId, targetActionId)) {
|
|
57
|
+
return {
|
|
58
|
+
code: UNDECLARED_ACTION_DEPENDENCY,
|
|
59
|
+
message: `Root call to action '${targetPackageId}/${targetActionId}' is not allowed: package '${targetPackageId}' is not declared as a direct dependency in actiondock.json and is not delegated by a visible playbook`,
|
|
60
|
+
details: { target: `${targetPackageId}/${targetActionId}` },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 调用方至目标动作 uses 依赖声明授权校验(Caller -> Callee Authorization & Uses Policy)。
|
|
67
|
+
*
|
|
68
|
+
* 判定规则:
|
|
69
|
+
* - 同包内部 Action 互调自然合法,豁免 uses 声明;
|
|
70
|
+
* - 跨包调用必须在调用方 Action 的 uses 声明列表中显式声明目标(完全限定名、通配符或包名),
|
|
71
|
+
* 或经由 PackageGraph.canCascadeCall 裁决通过;未声明直接拦截。
|
|
72
|
+
*
|
|
73
|
+
* @param caller 调用方 Action 标识与声明上下文
|
|
74
|
+
* @param target 目标 Action 标识
|
|
75
|
+
* @param graph 可选的包依赖拓扑图
|
|
76
|
+
* @returns 若鉴权未通过返回标准 RuntimeError,通过则返回 undefined
|
|
77
|
+
*/
|
|
78
|
+
checkUsesAuthorization(caller, target, graph) {
|
|
79
|
+
// 同包调用完全自由开放,不作限制
|
|
80
|
+
if (!caller.packageId || !target.packageId || caller.packageId === target.packageId) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const targetRef = `${target.packageId}/${target.actionId}`;
|
|
84
|
+
const callerNode = graph?.getNode(caller.packageId);
|
|
85
|
+
const shortActionId = caller.actionId.includes("/")
|
|
86
|
+
? caller.actionId.split("/").pop()
|
|
87
|
+
: caller.actionId;
|
|
88
|
+
const usesList = caller.declaredUses ||
|
|
89
|
+
callerNode?.manifest?.actions?.[shortActionId]?.uses ||
|
|
90
|
+
callerNode?.manifest?.actions?.[caller.actionId]?.uses ||
|
|
91
|
+
[];
|
|
92
|
+
const isAllowed = graph
|
|
93
|
+
? graph.canCascadeCall(caller.packageId, caller.actionId, target.packageId, target.actionId)
|
|
94
|
+
: usesList.some((u) => isUsesDeclared(u, target.packageId, target.actionId));
|
|
95
|
+
if (!isAllowed) {
|
|
96
|
+
return {
|
|
97
|
+
code: UNDECLARED_ACTION_DEPENDENCY,
|
|
98
|
+
message: `Undeclared cross-package dependency: Action '${caller.packageId}/${caller.actionId}' does not declare dependency on '${targetRef}' in 'uses'`,
|
|
99
|
+
details: {
|
|
100
|
+
caller: `${caller.packageId}/${caller.actionId}`,
|
|
101
|
+
target: targetRef,
|
|
102
|
+
declaredUses: usesList,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 调用嵌套最大深度限制校验(Max Call Depth Policy)。
|
|
110
|
+
*
|
|
111
|
+
* 超限时返回标准 ACTION_CALL_CYCLE 错误。
|
|
112
|
+
*
|
|
113
|
+
* @param callStack 当前已累积的调用栈切片
|
|
114
|
+
* @param targetActionId 欲调用的目标 Action 标识
|
|
115
|
+
* @param maxDepthOverride 临时执行覆盖的最大深度限制
|
|
116
|
+
* @returns 超限错误或 undefined
|
|
117
|
+
*/
|
|
118
|
+
checkCallDepth(callStack, targetActionId, maxDepthOverride) {
|
|
119
|
+
const limit = maxDepthOverride ?? this.maxCallDepth;
|
|
120
|
+
if (callStack.length >= limit) {
|
|
121
|
+
return {
|
|
122
|
+
code: ACTION_CALL_CYCLE,
|
|
123
|
+
message: `Maximum call depth of ${limit} exceeded: ${callStack.join(" -> ")} -> ${targetActionId}`,
|
|
124
|
+
details: {
|
|
125
|
+
reason: "depth_exceeded",
|
|
126
|
+
maxDepth: limit,
|
|
127
|
+
callStack: [...callStack],
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 调用链环路死锁检测(Cycle Detection Policy)。
|
|
135
|
+
*
|
|
136
|
+
* 计算目标调用键并在历史调用栈中执行检测,杜绝 A -> B -> A 形成死锁。
|
|
137
|
+
* 命中环路时返回 ACTION_CALL_CYCLE 错误。
|
|
138
|
+
*
|
|
139
|
+
* @param callStack 当前已累积的调用栈切片
|
|
140
|
+
* @param targetActionId 欲调用的目标 Action 标识
|
|
141
|
+
* @param targetPackageId 目标 Action 所属包标识
|
|
142
|
+
* @param currentPackageId 当前执行发起方包标识
|
|
143
|
+
* @returns 包含规范化 callKey 与可选错误的结构体
|
|
144
|
+
*/
|
|
145
|
+
checkCycle(callStack, targetActionId, targetPackageId, currentPackageId) {
|
|
146
|
+
const isExternal = Boolean(targetPackageId && currentPackageId && targetPackageId !== currentPackageId);
|
|
147
|
+
const callKey = targetPackageId
|
|
148
|
+
? `${targetPackageId}/${targetActionId}`
|
|
149
|
+
: targetActionId;
|
|
150
|
+
let hasCycle = false;
|
|
151
|
+
if (isExternal) {
|
|
152
|
+
hasCycle = callStack.includes(callKey);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
hasCycle =
|
|
156
|
+
callStack.includes(callKey) ||
|
|
157
|
+
callStack.includes(targetActionId) ||
|
|
158
|
+
(targetPackageId ? callStack.includes(`${targetPackageId}/${targetActionId}`) : false);
|
|
159
|
+
}
|
|
160
|
+
if (hasCycle) {
|
|
161
|
+
return {
|
|
162
|
+
callKey,
|
|
163
|
+
error: {
|
|
164
|
+
code: ACTION_CALL_CYCLE,
|
|
165
|
+
message: `Cycle detected in action invocation: ${callStack.join(" -> ")} -> ${callKey}`,
|
|
166
|
+
details: {
|
|
167
|
+
reason: "cycle_detected",
|
|
168
|
+
callStack: [...callStack],
|
|
169
|
+
target: callKey,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return { callKey };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* 并发活跃子任务配额检查(Sub-Run Quota Policy)。
|
|
178
|
+
*
|
|
179
|
+
* 针对同源 rootRunId 限制派生的并发子任务上限,防止资源耗尽。
|
|
180
|
+
*
|
|
181
|
+
* @param rootRunId 根运行标识符
|
|
182
|
+
* @returns 超限错误或 undefined
|
|
183
|
+
*/
|
|
184
|
+
checkSubRunQuota(rootRunId) {
|
|
185
|
+
const current = this.activeSubRunsPerRoot.get(rootRunId) || 0;
|
|
186
|
+
if (current >= this.maxSubRuns) {
|
|
187
|
+
return {
|
|
188
|
+
code: ACTION_SUBRUN_LIMIT,
|
|
189
|
+
message: `Maximum concurrent sub-runs (${this.maxSubRuns}) reached for root run '${rootRunId}'`,
|
|
190
|
+
details: {
|
|
191
|
+
limit: this.maxSubRuns,
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* 申请子任务并发配额槽位。
|
|
199
|
+
*
|
|
200
|
+
* @param rootRunId 根运行标识符
|
|
201
|
+
* @returns 是否成功获取槽位(若已达上限返回 false)
|
|
202
|
+
*/
|
|
203
|
+
acquireSubRun(rootRunId) {
|
|
204
|
+
const current = this.activeSubRunsPerRoot.get(rootRunId) || 0;
|
|
205
|
+
if (current >= this.maxSubRuns) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
this.activeSubRunsPerRoot.set(rootRunId, current + 1);
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* 释放已申请的子任务并发配额槽位。
|
|
213
|
+
*
|
|
214
|
+
* @param rootRunId 根运行标识符
|
|
215
|
+
*/
|
|
216
|
+
releaseSubRun(rootRunId) {
|
|
217
|
+
const current = this.activeSubRunsPerRoot.get(rootRunId) || 1;
|
|
218
|
+
if (current <= 1) {
|
|
219
|
+
this.activeSubRunsPerRoot.delete(rootRunId);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
this.activeSubRunsPerRoot.set(rootRunId, current - 1);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* 获取指定根运行当前的活跃并发子任务计数。
|
|
227
|
+
*/
|
|
228
|
+
getActiveSubRuns(rootRunId) {
|
|
229
|
+
return this.activeSubRunsPerRoot.get(rootRunId) || 0;
|
|
230
|
+
}
|
|
231
|
+
}
|