@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.
Files changed (268) hide show
  1. package/README.md +61 -68
  2. package/dist/catalog/action-catalog.d.ts +56 -0
  3. package/dist/catalog/action-catalog.js +202 -0
  4. package/dist/catalog/discovery.d.ts +60 -0
  5. package/dist/catalog/discovery.js +119 -0
  6. package/dist/catalog/graph.d.ts +190 -0
  7. package/dist/catalog/graph.js +589 -0
  8. package/dist/catalog/index.d.ts +5 -5
  9. package/dist/catalog/index.js +5 -5
  10. package/dist/catalog/resolve-action.d.ts +43 -0
  11. package/dist/catalog/resolve-action.js +119 -0
  12. package/dist/catalog/resolve-playbook.d.ts +26 -0
  13. package/dist/catalog/resolve-playbook.js +114 -0
  14. package/dist/doctor/checks/project.js +27 -8
  15. package/dist/doctor/checks/registry.js +2 -2
  16. package/dist/doctor/checks/runtime.js +34 -1
  17. package/dist/errors.d.ts +122 -10
  18. package/dist/errors.js +123 -10
  19. package/dist/execution/service.d.ts +18 -16
  20. package/dist/execution/service.js +183 -252
  21. package/dist/execution/types.d.ts +25 -69
  22. package/dist/execution/types.js +2 -1
  23. package/dist/filter/intent.d.ts +8 -9
  24. package/dist/filter/intent.js +49 -10
  25. package/dist/graph/index.d.ts +4 -0
  26. package/dist/graph/index.js +4 -0
  27. package/dist/host/host.d.ts +74 -32
  28. package/dist/host/host.js +585 -336
  29. package/dist/host/routing.d.ts +15 -48
  30. package/dist/host/routing.js +90 -153
  31. package/dist/host/types.d.ts +50 -17
  32. package/dist/index.d.ts +21 -22
  33. package/dist/index.js +19 -21
  34. package/dist/input/advice.d.ts +104 -0
  35. package/dist/input/advice.js +716 -0
  36. package/dist/input/describe.d.ts +106 -0
  37. package/dist/input/describe.js +176 -0
  38. package/dist/input/file-input.d.ts +54 -0
  39. package/dist/input/file-input.js +124 -0
  40. package/dist/input/flat-decode.d.ts +11 -0
  41. package/dist/input/flat-decode.js +13 -0
  42. package/dist/input/flat-errors.d.ts +71 -0
  43. package/dist/input/flat-errors.js +87 -0
  44. package/dist/input/flat-materializer.d.ts +29 -0
  45. package/dist/input/flat-materializer.js +177 -0
  46. package/dist/input/flat-parser.d.ts +50 -0
  47. package/dist/input/flat-parser.js +169 -0
  48. package/dist/input/flat-predicates.d.ts +34 -0
  49. package/dist/input/flat-predicates.js +50 -0
  50. package/dist/input/index.d.ts +14 -0
  51. package/dist/input/index.js +14 -0
  52. package/dist/input/input-resolver.d.ts +63 -0
  53. package/dist/input/input-resolver.js +254 -0
  54. package/dist/input/json-depth-scanner.d.ts +17 -0
  55. package/dist/input/json-depth-scanner.js +49 -0
  56. package/dist/input/metadata.d.ts +99 -0
  57. package/dist/input/metadata.js +99 -0
  58. package/dist/input/stdin-input.d.ts +26 -0
  59. package/dist/input/stdin-input.js +125 -0
  60. package/dist/input/utf8.d.ts +19 -0
  61. package/dist/input/utf8.js +36 -0
  62. package/dist/input/validation-mapper.d.ts +27 -0
  63. package/dist/input/validation-mapper.js +144 -0
  64. package/dist/invocation/index.d.ts +2 -0
  65. package/dist/invocation/index.js +2 -0
  66. package/dist/invocation/policy.d.ts +157 -0
  67. package/dist/invocation/policy.js +231 -0
  68. package/dist/invocation/types.d.ts +172 -0
  69. package/dist/invocation/types.js +97 -0
  70. package/dist/ipc/diagnostic.d.ts +0 -12
  71. package/dist/ipc/diagnostic.js +0 -21
  72. package/dist/ipc/host.d.ts +4 -4
  73. package/dist/ipc/host.js +44 -47
  74. package/dist/ipc/index.d.ts +1 -1
  75. package/dist/ipc/index.js +1 -1
  76. package/dist/ipc/service.d.ts +40 -0
  77. package/dist/ipc/service.js +349 -0
  78. package/dist/ipc/types.d.ts +21 -15
  79. package/dist/json/index.d.ts +1 -0
  80. package/dist/json/index.js +1 -0
  81. package/dist/json/value-validator.d.ts +88 -0
  82. package/dist/json/value-validator.js +330 -0
  83. package/dist/node/index.d.ts +1 -0
  84. package/dist/node/index.js +1 -0
  85. package/dist/node/module-loader.d.ts +63 -0
  86. package/dist/node/module-loader.js +112 -0
  87. package/dist/package/index.d.ts +23 -0
  88. package/dist/package/index.js +18 -0
  89. package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
  90. package/dist/{app/app.js → package/runtime.js} +140 -95
  91. package/dist/{app → package}/static-index.js +58 -41
  92. package/dist/package/storage-view.d.ts +13 -0
  93. package/dist/package/storage-view.js +22 -0
  94. package/dist/{app → package}/types.d.ts +76 -57
  95. package/dist/package/types.js +22 -0
  96. package/dist/platform/index.d.ts +1 -1
  97. package/dist/platform/index.js +1 -1
  98. package/dist/platform/node.d.ts +48 -0
  99. package/dist/platform/node.js +96 -0
  100. package/dist/platform/types.d.ts +0 -9
  101. package/dist/process/control-arbiter.d.ts +2 -1
  102. package/dist/process/control-arbiter.js +1 -2
  103. package/dist/process/driver.d.ts +9 -8
  104. package/dist/process/driver.js +11 -22
  105. package/dist/process/index.d.ts +2 -0
  106. package/dist/process/index.js +2 -0
  107. package/dist/process/managed-record.d.ts +2 -2
  108. package/dist/process/process-driver.d.ts +109 -0
  109. package/dist/process/process-driver.js +650 -0
  110. package/dist/process/process-executor.d.ts +47 -0
  111. package/dist/process/process-executor.js +296 -0
  112. package/dist/process/process-manager.js +48 -26
  113. package/dist/process/run-executor.js +12 -12
  114. package/dist/profile/client-actions.js +2 -2
  115. package/dist/profile/client-health.js +3 -2
  116. package/dist/profile/client-query.js +5 -6
  117. package/dist/profile/client-transport.d.ts +19 -17
  118. package/dist/profile/client-transport.js +48 -80
  119. package/dist/profile/client.d.ts +2 -2
  120. package/dist/profile/client.js +1 -1
  121. package/dist/profile/index.d.ts +1 -0
  122. package/dist/profile/index.js +1 -0
  123. package/dist/profile/manager.d.ts +5 -0
  124. package/dist/profile/manager.js +41 -6
  125. package/dist/project/closure.js +2 -2
  126. package/dist/project/index.d.ts +8 -1
  127. package/dist/project/index.js +10 -1
  128. package/dist/project/init.js +2 -2
  129. package/dist/project/loader.d.ts +1 -1
  130. package/dist/project/loader.js +26 -29
  131. package/dist/project/transactions.js +5 -10
  132. package/dist/registry/index.d.ts +3 -1
  133. package/dist/registry/index.js +2 -1
  134. package/dist/registry/lock.d.ts +28 -7
  135. package/dist/registry/lock.js +136 -16
  136. package/dist/registry/registry.d.ts +1 -5
  137. package/dist/registry/registry.js +1 -53
  138. package/dist/registry/scan.d.ts +0 -15
  139. package/dist/registry/scan.js +0 -59
  140. package/dist/registry/store.d.ts +42 -0
  141. package/dist/registry/store.js +43 -0
  142. package/dist/registry/types.d.ts +0 -24
  143. package/dist/runtime/action-collection.d.ts +1 -1
  144. package/dist/runtime/action-registry.d.ts +0 -4
  145. package/dist/runtime/action-registry.js +0 -7
  146. package/dist/runtime/context.js +5 -11
  147. package/dist/runtime/events.js +3 -6
  148. package/dist/runtime/identity.d.ts +22 -0
  149. package/dist/runtime/identity.js +10 -0
  150. package/dist/runtime/index.d.ts +1 -2
  151. package/dist/runtime/index.js +1 -2
  152. package/dist/runtime/module-loader.d.ts +2 -34
  153. package/dist/runtime/module-loader.js +1 -16
  154. package/dist/runtime/process.d.ts +6 -24
  155. package/dist/runtime/process.js +1 -118
  156. package/dist/runtime/run-persistence.js +2 -5
  157. package/dist/runtime/runner.d.ts +33 -103
  158. package/dist/runtime/runner.js +142 -404
  159. package/dist/runtime/standalone.d.ts +37 -9
  160. package/dist/runtime/standalone.js +195 -136
  161. package/dist/schema/index.d.ts +1 -0
  162. package/dist/schema/index.js +1 -0
  163. package/dist/schema/validator.d.ts +10 -0
  164. package/dist/schema/validator.js +48 -54
  165. package/dist/server/body.d.ts +16 -8
  166. package/dist/server/body.js +33 -16
  167. package/dist/server/dispatcher.d.ts +6 -10
  168. package/dist/server/dispatcher.js +24 -32
  169. package/dist/server/http-server.d.ts +87 -0
  170. package/dist/server/http-server.js +304 -0
  171. package/dist/server/index.d.ts +11 -0
  172. package/dist/server/index.js +10 -0
  173. package/dist/server/mcp-endpoint.d.ts +61 -0
  174. package/dist/server/mcp-endpoint.js +118 -0
  175. package/dist/server/routes/actions.js +34 -28
  176. package/dist/server/routes/common.d.ts +10 -14
  177. package/dist/server/routes/common.js +32 -56
  178. package/dist/server/routes/config.js +54 -64
  179. package/dist/server/routes/doctor.d.ts +1 -1
  180. package/dist/server/routes/doctor.js +10 -18
  181. package/dist/server/routes/health.d.ts +1 -1
  182. package/dist/server/routes/health.js +2 -3
  183. package/dist/server/routes/info.d.ts +2 -2
  184. package/dist/server/routes/info.js +12 -13
  185. package/dist/server/routes/playbooks.js +16 -29
  186. package/dist/server/routes/runs.js +95 -117
  187. package/dist/server/routes/state.js +63 -62
  188. package/dist/server/server.d.ts +2 -2
  189. package/dist/server/server.js +43 -227
  190. package/dist/server/types.d.ts +8 -19
  191. package/dist/service/factory.d.ts +12 -0
  192. package/dist/service/factory.js +85 -0
  193. package/dist/{target → service}/index.d.ts +1 -1
  194. package/dist/{target → service}/index.js +1 -1
  195. package/dist/service/local.d.ts +27 -0
  196. package/dist/service/local.js +138 -0
  197. package/dist/{target → service}/remote-errors.d.ts +3 -6
  198. package/dist/service/remote-errors.js +38 -0
  199. package/dist/{target → service}/remote-polling.d.ts +2 -2
  200. package/dist/{target → service}/remote-polling.js +8 -8
  201. package/dist/service/remote.d.ts +34 -0
  202. package/dist/service/remote.js +634 -0
  203. package/dist/service/sse-stream.d.ts +24 -0
  204. package/dist/service/sse-stream.js +139 -0
  205. package/dist/service/types.d.ts +272 -0
  206. package/dist/service/types.js +32 -0
  207. package/dist/storage/data-dir-lock.js +10 -5
  208. package/dist/storage/driver.d.ts +2 -1
  209. package/dist/storage/driver.js +3 -52
  210. package/dist/storage/index.d.ts +1 -0
  211. package/dist/storage/index.js +1 -0
  212. package/dist/storage/lock-core.d.ts +2 -6
  213. package/dist/storage/lock-core.js +4 -17
  214. package/dist/storage/params.d.ts +2 -8
  215. package/dist/storage/params.js +2 -8
  216. package/dist/storage/sqlite-driver.d.ts +40 -0
  217. package/dist/storage/sqlite-driver.js +116 -0
  218. package/dist/storage/sqlite.js +21 -6
  219. package/dist/storage/types.d.ts +4 -4
  220. package/dist/storage/types.js +2 -2
  221. package/dist/utils/index.d.ts +53 -0
  222. package/dist/utils/index.js +99 -4
  223. package/dist/utils/process.d.ts +10 -0
  224. package/dist/utils/process.js +21 -0
  225. package/dist/version.d.ts +1 -1
  226. package/dist/version.js +1 -1
  227. package/package.json +41 -3
  228. package/dist/app/index.d.ts +0 -2
  229. package/dist/app/index.js +0 -2
  230. package/dist/app/types.js +0 -1
  231. package/dist/catalog/action-index.d.ts +0 -9
  232. package/dist/catalog/action-index.js +0 -95
  233. package/dist/catalog/action-resolver.d.ts +0 -20
  234. package/dist/catalog/action-resolver.js +0 -95
  235. package/dist/catalog/location-registry.d.ts +0 -15
  236. package/dist/catalog/location-registry.js +0 -138
  237. package/dist/catalog/package-catalog.d.ts +0 -7
  238. package/dist/catalog/package-catalog.js +0 -77
  239. package/dist/catalog/types.d.ts +0 -68
  240. package/dist/catalog/types.js +0 -1
  241. package/dist/export/index.d.ts +0 -1
  242. package/dist/export/index.js +0 -1
  243. package/dist/export/templates.d.ts +0 -71
  244. package/dist/export/templates.js +0 -623
  245. package/dist/ipc/target.d.ts +0 -74
  246. package/dist/ipc/target.js +0 -365
  247. package/dist/platform/default.d.ts +0 -38
  248. package/dist/platform/default.js +0 -78
  249. package/dist/project/resolver.d.ts +0 -116
  250. package/dist/project/resolver.js +0 -376
  251. package/dist/registry/resolve.d.ts +0 -62
  252. package/dist/registry/resolve.js +0 -195
  253. package/dist/runtime/execution-manager.d.ts +0 -48
  254. package/dist/runtime/execution-manager.js +0 -66
  255. package/dist/runtime/package-runner-factory.d.ts +0 -82
  256. package/dist/runtime/package-runner-factory.js +0 -186
  257. package/dist/target/local.d.ts +0 -53
  258. package/dist/target/local.js +0 -349
  259. package/dist/target/remote-errors.js +0 -51
  260. package/dist/target/remote.d.ts +0 -86
  261. package/dist/target/remote.js +0 -818
  262. package/dist/target/target.d.ts +0 -6
  263. package/dist/target/target.js +0 -37
  264. package/dist/target/types.d.ts +0 -261
  265. package/dist/target/types.js +0 -35
  266. /package/dist/{app → package}/static-index.d.ts +0 -0
  267. /package/dist/{target → service}/sse-parser.d.ts +0 -0
  268. /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,2 @@
1
+ export * from "./types.js";
2
+ export * from "./policy.js";
@@ -0,0 +1,2 @@
1
+ export * from "./types.js";
2
+ export * from "./policy.js";
@@ -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
+ }