@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
@@ -1,7 +1,7 @@
1
1
  import { type ActionDefinition } from "@actiondock/sdk";
2
- import type { ActionSpec } from "../app/types.js";
2
+ import type { ActionSpec } from "../package/types.js";
3
3
  import type { ConfigItemDefinition } from "../project/types.js";
4
- import type { ActionDockTarget } from "../target/types.js";
4
+ import type { ActionDockService } from "../service/types.js";
5
5
  /**
6
6
  * 退出状态码常量。
7
7
  */
@@ -11,6 +11,13 @@ export declare const ExitCode: {
11
11
  readonly INVALID_ARGUMENT: 2;
12
12
  readonly SIGINT: 130;
13
13
  };
14
+ /**
15
+ * 调用控制选项契约。
16
+ */
17
+ export interface InvocationControl {
18
+ signal?: AbortSignal;
19
+ cancellationSource?: "external" | "sigint";
20
+ }
14
21
  /**
15
22
  * 独立二进制运行分发器配置选项。
16
23
  */
@@ -21,8 +28,8 @@ export interface StandaloneDispatcherOptions {
21
28
  version: string;
22
29
  /** 描述信息 */
23
30
  description?: string;
24
- /** 已构造的 ActionDockTarget 门面(若未传入则依据 actions/config 自动创建) */
25
- target?: ActionDockTarget;
31
+ /** 已构造的 ActionDockService 服务(若未传入则依据 actions/config 自动创建) */
32
+ service?: ActionDockService;
26
33
  /** 声明的配置依赖定义(兼容选项) */
27
34
  configDefs?: Record<string, ConfigItemDefinition>;
28
35
  config?: Record<string, ConfigItemDefinition>;
@@ -49,7 +56,7 @@ export interface StandaloneDispatcherOptions {
49
56
  *
50
57
  * 职责:
51
58
  * 1. 负责轻量参数解析、诊断输出渲染与统一退出码管理。
52
- * 2. 统一面向 ActionDockTarget 门面调用能力(支持本地 LocalTarget 与 IPC 监督隔离 Target)。
59
+ * 2. 统一面向 ActionDockService 服务调用能力。
53
60
  * 3. 严格遵循 ActionDock 2.0 输出协议约定:结果数据专走 stdout,日志与错误专走 stderr。
54
61
  * 4. 独立入口拒绝异步启动语义,显式拦截并返回 STANDALONE_ASYNC_UNSUPPORTED。
55
62
  */
@@ -58,23 +65,39 @@ export declare class StandaloneDispatcher {
58
65
  constructor(options: StandaloneDispatcherOptions);
59
66
  private writeOut;
60
67
  private writeErr;
61
- private createLocalTarget;
68
+ /**
69
+ * 统一错误输出辅助方法。
70
+ *
71
+ * JSON 模式向 stdout 输出两空格缩进的标准错误结构;
72
+ * 纯文本模式向 stderr 输出单行错误消息(默认携带 Error: 前缀)。
73
+ * 消息文本与退出码由调用方逐字给定,输出字节严格保持不变。
74
+ *
75
+ * @param isJson 是否处于 JSON 输出模式
76
+ * @param code 错误码
77
+ * @param message JSON 模式错误消息(兼作纯文本默认消息主体)
78
+ * @param exitCode 调用方应返回的退出状态码
79
+ * @param options 可选项:textMessage 覆盖纯文本消息全文;details 为 JSON 模式可选结构化详情
80
+ * @returns 透传 exitCode 供调用方直接返回
81
+ */
82
+ private emitError;
83
+ private createLocalService;
62
84
  /**
63
85
  * 解析命令行参数并分发执行对应子命令。
64
86
  *
65
87
  * @param argv 命令行参数数组(如 process.argv.slice(2))
88
+ * @param control 可选的中断与取消控制契约
66
89
  * @returns 退出状态码(0: 成功, 1: 失败, 2: 参数错误, 130: 中断)
67
90
  */
68
- dispatch(argv: string[]): Promise<number>;
91
+ dispatch(argv: string[], control?: InvocationControl): Promise<number>;
69
92
  private handleList;
70
93
  private handleDescribe;
71
94
  private handleRun;
72
95
  private handleConfig;
73
96
  private handleState;
74
97
  /**
75
- * 判定配置读取异常是否为目标层能力缺失(键未配置语义)而非内部故障。
98
+ * 判定配置读取异常是否为服务能力缺失(键未配置语义)而非内部故障。
76
99
  */
77
- private isTargetCapabilityError;
100
+ private isServiceCapabilityError;
78
101
  /**
79
102
  * 解析携带命名空间前缀的状态键参数:委托 sdk 单一事实源 decodeStateKey。
80
103
  *
@@ -97,3 +120,8 @@ export declare class StandaloneRuntime {
97
120
  * 工厂函数:创建独立运行时实例。
98
121
  */
99
122
  export declare function createStandaloneRuntime(options: StandaloneRuntimeOptions): StandaloneRuntime;
123
+ /**
124
+ * 独立二进制进程入口适配器。
125
+ * 仅在命令行可执行入口调用,负责全局 SIGINT 监听与退出状态码写入。
126
+ */
127
+ export declare function runStandaloneProcess(argv: string[], options: StandaloneDispatcherOptions): Promise<void>;
@@ -1,8 +1,9 @@
1
- import { readFileSync } from "node:fs";
2
1
  import { decodeStateKey } from "@actiondock/sdk";
3
2
  import { filterWithFallbackInfo } from "../filter/index.js";
4
- import { createActionDockTarget } from "../target/target.js";
3
+ import { createActionDock } from "../service/factory.js";
5
4
  import { STANDALONE_ASYNC_UNSUPPORTED } from "../errors.js";
5
+ import { resolveActionInput, formatActionDetail, buildActionDescribePayload, mapInputValidationFailure, } from "../input/index.js";
6
+ import { validateActionInputValue } from "../json/value-validator.js";
6
7
  import { normalizeActionCollection } from "./action-collection.js";
7
8
  import { parseDuration } from "../utils/index.js";
8
9
  /**
@@ -19,7 +20,7 @@ export const ExitCode = {
19
20
  *
20
21
  * 职责:
21
22
  * 1. 负责轻量参数解析、诊断输出渲染与统一退出码管理。
22
- * 2. 统一面向 ActionDockTarget 门面调用能力(支持本地 LocalTarget 与 IPC 监督隔离 Target)。
23
+ * 2. 统一面向 ActionDockService 服务调用能力。
23
24
  * 3. 严格遵循 ActionDock 2.0 输出协议约定:结果数据专走 stdout,日志与错误专走 stderr。
24
25
  * 4. 独立入口拒绝异步启动语义,显式拦截并返回 STANDALONE_ASYNC_UNSUPPORTED。
25
26
  */
@@ -44,18 +45,49 @@ export class StandaloneDispatcher {
44
45
  console.error(msg);
45
46
  }
46
47
  }
47
- async createLocalTarget(dataDir, configOverrides = {}) {
48
- if (this.options.target) {
49
- return { target: this.options.target, ownsTarget: false };
48
+ /**
49
+ * 统一错误输出辅助方法。
50
+ *
51
+ * JSON 模式向 stdout 输出两空格缩进的标准错误结构;
52
+ * 纯文本模式向 stderr 输出单行错误消息(默认携带 Error: 前缀)。
53
+ * 消息文本与退出码由调用方逐字给定,输出字节严格保持不变。
54
+ *
55
+ * @param isJson 是否处于 JSON 输出模式
56
+ * @param code 错误码
57
+ * @param message JSON 模式错误消息(兼作纯文本默认消息主体)
58
+ * @param exitCode 调用方应返回的退出状态码
59
+ * @param options 可选项:textMessage 覆盖纯文本消息全文;details 为 JSON 模式可选结构化详情
60
+ * @returns 透传 exitCode 供调用方直接返回
61
+ */
62
+ emitError(isJson, code, message, exitCode, options) {
63
+ if (isJson) {
64
+ const details = options?.details;
65
+ this.writeOut(JSON.stringify({
66
+ ok: false,
67
+ error: {
68
+ code,
69
+ message,
70
+ ...(details !== undefined ? { details } : {}),
71
+ },
72
+ }, null, 2));
73
+ }
74
+ else {
75
+ this.writeErr(options?.textMessage ?? `Error: ${message}`);
76
+ }
77
+ return exitCode;
78
+ }
79
+ async createLocalService(dataDir, configOverrides = {}) {
80
+ if (this.options.service) {
81
+ return { service: this.options.service, ownsService: false };
50
82
  }
51
- if (this.options.inMemory && this.options._sharedTarget) {
52
- return { target: this.options._sharedTarget, ownsTarget: false };
83
+ if (this.options.inMemory && this.options._sharedService) {
84
+ return { service: this.options._sharedService, ownsService: false };
53
85
  }
54
86
  // 归一化 Action 集合:单一入口统一三形态输入
55
87
  const { actionsMap, actionSpecs } = normalizeActionCollection(this.options.actions);
56
88
  // projectConfig.actions 要求 manifest 形态,字段语义兼容,此处显式收敛类型
57
89
  const manifestActions = actionSpecs;
58
- const appOptions = {
90
+ const runtimeOptions = {
59
91
  projectConfig: {
60
92
  id: this.options.packageId,
61
93
  name: this.options.packageId,
@@ -70,38 +102,40 @@ export class StandaloneDispatcher {
70
102
  customHome: this.options.customHome,
71
103
  inMemory: this.options.inMemory,
72
104
  };
73
- const target = await createActionDockTarget({
74
- type: "local",
75
- appOptions,
105
+ const service = await createActionDock({
106
+ runtimeOptions,
76
107
  });
77
108
  if (this.options.inMemory) {
78
- this.options._sharedTarget = target;
79
- return { target, ownsTarget: false };
109
+ this.options._sharedService = service;
110
+ return { service, ownsService: false };
80
111
  }
81
- return { target, ownsTarget: true };
112
+ return { service, ownsService: true };
82
113
  }
83
114
  /**
84
115
  * 解析命令行参数并分发执行对应子命令。
85
116
  *
86
117
  * @param argv 命令行参数数组(如 process.argv.slice(2))
118
+ * @param control 可选的中断与取消控制契约
87
119
  * @returns 退出状态码(0: 成功, 1: 失败, 2: 参数错误, 130: 中断)
88
120
  */
89
- async dispatch(argv) {
90
- const args = [...argv];
121
+ async dispatch(argv, control) {
122
+ const separator = argv.indexOf("--");
123
+ const controlArgs = separator >= 0 ? argv.slice(0, separator) : argv;
124
+ const actionArgs = separator >= 0 ? argv.slice(separator + 1) : [];
91
125
  let dataDir;
92
126
  const configOverrides = {};
93
- // 1. 提取全局参数(--data-dir, --config)
127
+ // 1. 提取全局参数(--data-dir, --config)仅从 controlArgs 中解析
94
128
  const filteredArgs = [];
95
- for (let i = 0; i < args.length; i++) {
96
- const arg = args[i];
97
- if (arg === "--data-dir" && i + 1 < args.length) {
98
- dataDir = args[++i];
129
+ for (let i = 0; i < controlArgs.length; i++) {
130
+ const arg = controlArgs[i];
131
+ if (arg === "--data-dir" && i + 1 < controlArgs.length) {
132
+ dataDir = controlArgs[++i];
99
133
  }
100
134
  else if (arg.startsWith("--data-dir=")) {
101
135
  dataDir = arg.slice(11);
102
136
  }
103
- else if (arg === "--config" && i + 1 < args.length) {
104
- const pair = args[++i];
137
+ else if (arg === "--config" && i + 1 < controlArgs.length) {
138
+ const pair = controlArgs[++i];
105
139
  const [k, ...v] = pair.split("=");
106
140
  if (k)
107
141
  configOverrides[k] = v.join("=");
@@ -119,21 +153,10 @@ export class StandaloneDispatcher {
119
153
  const command = filteredArgs[0] || "help";
120
154
  const subArgs = filteredArgs.slice(1);
121
155
  // 2. 独立入口拒绝异步启动语义
122
- if (args.includes("--async")) {
123
- const isJson = args.includes("--json");
124
- if (isJson) {
125
- this.writeOut(JSON.stringify({
126
- ok: false,
127
- error: {
128
- code: STANDALONE_ASYNC_UNSUPPORTED,
129
- message: "Async execution is not supported in standalone single-execution binaries. Use 'ad serve' or remote target.",
130
- },
131
- }, null, 2));
132
- }
133
- else {
134
- this.writeErr(`Error [${STANDALONE_ASYNC_UNSUPPORTED}]: Async execution is not supported in standalone single-execution binaries.`);
135
- }
136
- return ExitCode.FAILURE;
156
+ if (controlArgs.includes("--async")) {
157
+ return this.emitError(controlArgs.includes("--json"), STANDALONE_ASYNC_UNSUPPORTED, "Async execution is not supported in standalone single-execution binaries. Use 'ad serve' or remote target.", ExitCode.FAILURE, {
158
+ textMessage: `Error [${STANDALONE_ASYNC_UNSUPPORTED}]: Async execution is not supported in standalone single-execution binaries.`,
159
+ });
137
160
  }
138
161
  // 3. 版本与帮助快速处理(无需初始化 Host / Storage)
139
162
  if (command === "-v" || command === "-V" || command === "--version" || command === "version") {
@@ -144,56 +167,61 @@ export class StandaloneDispatcher {
144
167
  this.printHelp();
145
168
  return ExitCode.SUCCESS;
146
169
  }
147
- let target;
148
- let ownsTarget = false;
170
+ let service;
171
+ let ownsService = false;
149
172
  try {
150
- const targetRes = await this.createLocalTarget(dataDir, configOverrides);
151
- target = targetRes.target;
152
- ownsTarget = targetRes.ownsTarget;
173
+ const serviceRes = await this.createLocalService(dataDir, configOverrides);
174
+ service = serviceRes.service;
175
+ ownsService = serviceRes.ownsService;
153
176
  }
154
177
  catch (err) {
155
- this.writeErr(`Error initializing standalone target: ${err?.message || err}`);
178
+ this.writeErr(`Error initializing standalone service: ${err?.message || err}`);
156
179
  return ExitCode.FAILURE;
157
180
  }
158
- const controller = new AbortController();
159
- const sigintHandler = () => {
160
- controller.abort(new Error("Interrupted by SIGINT"));
161
- };
162
- process.once("SIGINT", sigintHandler);
163
181
  try {
182
+ let code;
164
183
  switch (command) {
165
184
  case "list":
166
- return await this.handleList(target, subArgs);
185
+ code = await this.handleList(service, subArgs);
186
+ break;
167
187
  case "describe":
168
188
  case "show":
169
- return await this.handleDescribe(target, subArgs);
189
+ code = await this.handleDescribe(service, subArgs);
190
+ break;
170
191
  case "run":
171
- return await this.handleRun(target, subArgs, controller.signal);
192
+ code = await this.handleRun(service, subArgs, actionArgs, control?.signal);
193
+ break;
172
194
  case "config":
173
- return await this.handleConfig(target, subArgs);
195
+ code = await this.handleConfig(service, subArgs);
196
+ break;
174
197
  case "state":
175
- return await this.handleState(target, subArgs);
198
+ code = await this.handleState(service, subArgs);
199
+ break;
176
200
  default:
177
201
  this.writeErr(`Unknown command: '${command}'`);
178
202
  this.printHelp();
179
203
  return ExitCode.INVALID_ARGUMENT;
180
204
  }
205
+ if (control?.cancellationSource === "sigint" && control?.signal?.aborted) {
206
+ return ExitCode.SIGINT;
207
+ }
208
+ return code;
181
209
  }
182
210
  catch (err) {
183
- if (err?.name === "AbortError" || controller.signal.aborted) {
211
+ if (control?.cancellationSource === "sigint" &&
212
+ (control?.signal?.aborted || err?.name === "AbortError" || err?.code === "SIGINT_INTERRUPTED")) {
184
213
  return ExitCode.SIGINT;
185
214
  }
186
215
  this.writeErr(`Error: ${err?.message || err}`);
187
216
  return ExitCode.FAILURE;
188
217
  }
189
218
  finally {
190
- process.removeListener("SIGINT", sigintHandler);
191
- if (ownsTarget) {
192
- await target.close();
219
+ if (ownsService) {
220
+ await service.close();
193
221
  }
194
222
  }
195
223
  }
196
- async handleList(target, subArgs) {
224
+ async handleList(service, subArgs) {
197
225
  const isJson = subArgs.includes("--json");
198
226
  const noFallback = subArgs.includes("--no-fallback");
199
227
  let intent;
@@ -215,7 +243,7 @@ export class StandaloneDispatcher {
215
243
  }
216
244
  }
217
245
  const effectiveIntent = intent || (positionalPatterns.length > 0 ? positionalPatterns.join("|") : undefined);
218
- const actions = await target.listActions();
246
+ const actions = await service.discovery.listActions();
219
247
  const list = actions.map((a) => ({
220
248
  id: a.id,
221
249
  description: a.description || "",
@@ -233,94 +261,89 @@ export class StandaloneDispatcher {
233
261
  }
234
262
  return ExitCode.SUCCESS;
235
263
  }
236
- async handleDescribe(target, subArgs) {
264
+ async handleDescribe(service, subArgs) {
237
265
  const id = subArgs.find((a) => !a.startsWith("-"));
238
266
  const isJson = subArgs.includes("--json");
239
267
  if (!id) {
240
- this.writeErr("Error: Action ID is required for describe");
241
- return ExitCode.INVALID_ARGUMENT;
268
+ return this.emitError(isJson, "INVALID_ARGUMENT", "Action ID is required for describe", ExitCode.INVALID_ARGUMENT);
242
269
  }
243
270
  let action;
244
271
  try {
245
- action = await target.describeAction(id);
272
+ action = await service.discovery.describeAction(id);
246
273
  }
247
274
  catch {
248
- this.writeErr(`Error: Action '${id}' not found`);
249
- return ExitCode.INVALID_ARGUMENT;
275
+ return this.emitError(isJson, "INVALID_ARGUMENT", `Action '${id}' not found`, ExitCode.INVALID_ARGUMENT);
250
276
  }
251
- const detail = {
252
- id: action.id,
277
+ const payload = buildActionDescribePayload(action, {
253
278
  packageId: this.options.packageId,
254
- description: action.description,
255
- inputSchema: action.inputSchema,
256
- outputSchema: action.outputSchema,
257
- };
279
+ });
258
280
  if (isJson) {
259
- this.writeOut(JSON.stringify(detail, null, 2));
281
+ this.writeOut(JSON.stringify(payload, null, 2));
260
282
  }
261
283
  else {
262
- let text = `Action: ${action.id}\n`;
263
- if (action.description)
264
- text += `Description: ${action.description}\n`;
265
- if (action.inputSchema) {
266
- text += `\nInput Schema:\n${JSON.stringify(action.inputSchema, null, 2)}\n`;
267
- }
268
- if (action.outputSchema) {
269
- text += `\nOutput Schema:\n${JSON.stringify(action.outputSchema, null, 2)}\n`;
270
- }
271
- this.writeOut(text.trimEnd());
284
+ this.writeOut(formatActionDetail(payload));
272
285
  }
273
286
  return ExitCode.SUCCESS;
274
287
  }
275
- async handleRun(target, subArgs, signal) {
288
+ async handleRun(service, subArgs, actionArgs, signal) {
289
+ const isJson = subArgs.includes("--json");
276
290
  const id = subArgs.find((a) => !a.startsWith("-"));
277
291
  if (!id) {
278
- this.writeErr("Error: Action ID is required for run");
279
- return ExitCode.INVALID_ARGUMENT;
292
+ return this.emitError(isJson, "INVALID_ARGUMENT", "Error: Action ID is required for run", ExitCode.INVALID_ARGUMENT, { textMessage: "Error: Action ID is required for run" });
280
293
  }
281
- let input = {};
294
+ let inputStr;
295
+ let inputFile;
282
296
  let timeoutMs;
283
- let isJson = false;
284
297
  for (let i = 0; i < subArgs.length; i++) {
285
298
  const arg = subArgs[i];
286
- if (arg === "--json") {
287
- isJson = true;
288
- }
289
- else if (arg === "--timeout" && i + 1 < subArgs.length) {
290
- timeoutMs = parseDuration(subArgs[++i]);
291
- }
292
- else if (arg.startsWith("--timeout=")) {
293
- timeoutMs = parseDuration(arg.slice(10));
294
- }
295
- else if (arg === "--input" && i + 1 < subArgs.length) {
299
+ if (arg === "--timeout" && i + 1 < subArgs.length) {
296
300
  try {
297
- input = JSON.parse(subArgs[++i]);
301
+ timeoutMs = parseDuration(subArgs[++i]);
298
302
  }
299
- catch (e) {
300
- this.writeErr(`Error parsing --input JSON: ${e.message}`);
301
- return ExitCode.INVALID_ARGUMENT;
303
+ catch (err) {
304
+ return this.emitError(isJson, "INVALID_ARGUMENT", `Invalid timeout format: ${err?.message || err}`, ExitCode.INVALID_ARGUMENT);
302
305
  }
303
306
  }
304
- else if (arg.startsWith("--input=")) {
307
+ else if (arg.startsWith("--timeout=")) {
305
308
  try {
306
- input = JSON.parse(arg.slice(8));
309
+ timeoutMs = parseDuration(arg.slice(10));
307
310
  }
308
- catch (e) {
309
- this.writeErr(`Error parsing --input JSON: ${e.message}`);
310
- return ExitCode.INVALID_ARGUMENT;
311
+ catch (err) {
312
+ return this.emitError(isJson, "INVALID_ARGUMENT", `Invalid timeout format: ${err?.message || err}`, ExitCode.INVALID_ARGUMENT);
311
313
  }
312
314
  }
315
+ else if (arg === "--input" && i + 1 < subArgs.length) {
316
+ inputStr = subArgs[++i];
317
+ }
318
+ else if (arg.startsWith("--input=")) {
319
+ inputStr = arg.slice(8);
320
+ }
313
321
  else if (arg === "--input-file" && i + 1 < subArgs.length) {
314
- try {
315
- input = JSON.parse(readFileSync(subArgs[++i], "utf-8"));
316
- }
317
- catch (e) {
318
- this.writeErr(`Error reading --input-file: ${e.message}`);
319
- return ExitCode.INVALID_ARGUMENT;
320
- }
322
+ inputFile = subArgs[++i];
323
+ }
324
+ else if (arg.startsWith("--input-file=")) {
325
+ inputFile = arg.slice(13);
326
+ }
327
+ }
328
+ let input;
329
+ try {
330
+ input = await resolveActionInput({
331
+ input: inputStr,
332
+ inputFile,
333
+ flatArgs: actionArgs.length > 0 ? actionArgs : undefined,
334
+ stdin: process.stdin,
335
+ });
336
+ const check = validateActionInputValue(input);
337
+ if (!check.valid) {
338
+ throw mapInputValidationFailure("cli-pre-target", check);
321
339
  }
322
340
  }
323
- const result = await target.runAction(id, input, {
341
+ catch (err) {
342
+ return this.emitError(isJson, err?.code || "INVALID_ARGUMENT", err?.message || String(err), ExitCode.INVALID_ARGUMENT, {
343
+ details: err?.details,
344
+ });
345
+ }
346
+ const result = await service.execution.run(id, input, {
324
347
  signal,
325
348
  timeoutMs,
326
349
  });
@@ -409,10 +432,14 @@ export class StandaloneDispatcher {
409
432
  }
410
433
  return result.ok ? ExitCode.SUCCESS : ExitCode.FAILURE;
411
434
  }
412
- async handleConfig(target, subArgs) {
435
+ async handleConfig(service, subArgs) {
413
436
  const sub = subArgs[0] || "list";
437
+ if (!service.management) {
438
+ this.writeErr("Error: management port is not enabled on this service");
439
+ return ExitCode.FAILURE;
440
+ }
414
441
  if (sub === "list") {
415
- const views = await target.listConfig(this.options.packageId);
442
+ const views = await service.management.config.list(this.options.packageId);
416
443
  const dict = {};
417
444
  for (const v of views) {
418
445
  if (v.configured && v.value !== undefined) {
@@ -429,13 +456,13 @@ export class StandaloneDispatcher {
429
456
  return ExitCode.INVALID_ARGUMENT;
430
457
  }
431
458
  try {
432
- const item = await target.getConfig(this.options.packageId, key);
459
+ const item = await service.management.config.get(this.options.packageId, key);
433
460
  this.writeOut(item.configured ? JSON.stringify(item.value) : "undefined");
434
461
  return ExitCode.SUCCESS;
435
462
  }
436
463
  catch (err) {
437
- // 目标层能力缺失(如远端未开启管理接口)视为键未配置,输出 undefined
438
- if (this.isTargetCapabilityError(err)) {
464
+ // 服务能力缺失(如远端未开启管理接口)视为键未配置,输出 undefined
465
+ if (this.isServiceCapabilityError(err)) {
439
466
  this.writeOut("undefined");
440
467
  return ExitCode.SUCCESS;
441
468
  }
@@ -458,7 +485,7 @@ export class StandaloneDispatcher {
458
485
  catch {
459
486
  parsed = rawVal;
460
487
  }
461
- await target.setConfig(this.options.packageId, key, parsed);
488
+ await service.management.config.set(this.options.packageId, key, parsed);
462
489
  this.writeOut(`Config '${key}' updated`);
463
490
  return ExitCode.SUCCESS;
464
491
  }
@@ -468,18 +495,22 @@ export class StandaloneDispatcher {
468
495
  this.writeErr("Error: config key required");
469
496
  return ExitCode.INVALID_ARGUMENT;
470
497
  }
471
- await target.deleteConfig(this.options.packageId, key);
498
+ await service.management.config.delete(this.options.packageId, key);
472
499
  this.writeOut(`Config '${key}' deleted`);
473
500
  return ExitCode.SUCCESS;
474
501
  }
475
502
  this.writeErr(`Unknown config subcommand: '${sub}'`);
476
503
  return ExitCode.INVALID_ARGUMENT;
477
504
  }
478
- async handleState(target, subArgs) {
505
+ async handleState(service, subArgs) {
479
506
  const sub = subArgs[0] || "list";
480
507
  let namespace;
481
508
  let isAll = false;
482
509
  let isJson = false;
510
+ if (!service.management) {
511
+ this.writeErr("Error: management port is not enabled on this service");
512
+ return ExitCode.FAILURE;
513
+ }
483
514
  for (let i = 1; i < subArgs.length; i++) {
484
515
  if ((subArgs[i] === "-n" || subArgs[i] === "--namespace") && i + 1 < subArgs.length) {
485
516
  namespace = subArgs[++i];
@@ -496,7 +527,7 @@ export class StandaloneDispatcher {
496
527
  }
497
528
  if (sub === "list") {
498
529
  const prefix = subArgs[1] && !subArgs[1].startsWith("-") ? subArgs[1] : "";
499
- const keys = await target.listStateKeys(this.options.packageId, "", {
530
+ const keys = await service.management.state.list(this.options.packageId, "", {
500
531
  namespace,
501
532
  prefix: prefix || undefined,
502
533
  all: isAll,
@@ -517,7 +548,7 @@ export class StandaloneDispatcher {
517
548
  ns = decoded.namespace || undefined;
518
549
  actualKey = decoded.key;
519
550
  }
520
- const val = await target.getState(this.options.packageId, "", actualKey, { namespace: ns });
551
+ const val = await service.management.state.get(this.options.packageId, "", actualKey, { namespace: ns });
521
552
  if (isJson) {
522
553
  this.writeOut(JSON.stringify({ key, value: val }, null, 2));
523
554
  }
@@ -556,7 +587,7 @@ export class StandaloneDispatcher {
556
587
  ttl = parseInt(subArgs[i].slice(6), 10);
557
588
  }
558
589
  }
559
- await target.setState(this.options.packageId, "", actualKey, parsed, { namespace: ns, ttl });
590
+ await service.management.state.set(this.options.packageId, "", actualKey, parsed, { namespace: ns, ttl });
560
591
  const displayKey = ns ? `${ns}:${actualKey}` : actualKey;
561
592
  this.writeOut(`State '${displayKey}' updated`);
562
593
  return ExitCode.SUCCESS;
@@ -567,7 +598,7 @@ export class StandaloneDispatcher {
567
598
  this.writeErr("Error: state key required");
568
599
  return ExitCode.INVALID_ARGUMENT;
569
600
  }
570
- const deleted = await target.deleteState(this.options.packageId, "", key, { namespace });
601
+ const deleted = await service.management.state.delete(this.options.packageId, "", key, { namespace });
571
602
  if (deleted) {
572
603
  this.writeOut(`State '${key}' deleted`);
573
604
  return ExitCode.SUCCESS;
@@ -577,7 +608,7 @@ export class StandaloneDispatcher {
577
608
  }
578
609
  if (sub === "clear" || sub === "clean") {
579
610
  const prefix = subArgs[1] && !subArgs[1].startsWith("-") ? subArgs[1] : "";
580
- const count = await target.clearState(this.options.packageId, "", {
611
+ const count = await service.management.state.clear(this.options.packageId, "", {
581
612
  namespace,
582
613
  all: isAll,
583
614
  prefix: prefix || undefined,
@@ -589,15 +620,12 @@ export class StandaloneDispatcher {
589
620
  return ExitCode.INVALID_ARGUMENT;
590
621
  }
591
622
  /**
592
- * 判定配置读取异常是否为目标层能力缺失(键未配置语义)而非内部故障。
623
+ * 判定配置读取异常是否为服务能力缺失(键未配置语义)而非内部故障。
593
624
  */
594
- isTargetCapabilityError(err) {
625
+ isServiceCapabilityError(err) {
595
626
  const code = String(err?.code || "");
596
- const msg = String(err?.message || "");
597
- return (code === "TARGET_CAPABILITY_UNAVAILABLE" ||
598
- code === "CAPABILITY_UNAVAILABLE" ||
599
- msg.includes("TARGET_CAPABILITY_UNAVAILABLE") ||
600
- msg.includes("Management APIs are not enabled"));
627
+ return (code === "CAPABILITY_UNAVAILABLE" ||
628
+ code === "TARGET_CAPABILITY_UNAVAILABLE");
601
629
  }
602
630
  /**
603
631
  * 解析携带命名空间前缀的状态键参数:委托 sdk 单一事实源 decodeStateKey。
@@ -646,3 +674,34 @@ export class StandaloneRuntime {
646
674
  export function createStandaloneRuntime(options) {
647
675
  return new StandaloneRuntime(options);
648
676
  }
677
+ /**
678
+ * 独立二进制进程入口适配器。
679
+ * 仅在命令行可执行入口调用,负责全局 SIGINT 监听与退出状态码写入。
680
+ */
681
+ export async function runStandaloneProcess(argv, options) {
682
+ const controller = new AbortController();
683
+ const control = {
684
+ signal: controller.signal,
685
+ };
686
+ let sigintCount = 0;
687
+ const sigintHandler = () => {
688
+ sigintCount++;
689
+ if (sigintCount === 1) {
690
+ control.cancellationSource = "sigint";
691
+ controller.abort(new Error("Interrupted by SIGINT"));
692
+ }
693
+ else {
694
+ process.exitCode = 130;
695
+ process.exit(130);
696
+ }
697
+ };
698
+ process.on("SIGINT", sigintHandler);
699
+ try {
700
+ const dispatcher = new StandaloneDispatcher(options);
701
+ const exitCode = await dispatcher.dispatch(argv, control);
702
+ process.exitCode = exitCode;
703
+ }
704
+ finally {
705
+ process.removeListener("SIGINT", sigintHandler);
706
+ }
707
+ }
@@ -0,0 +1 @@
1
+ export * from "./validator.js";
@@ -0,0 +1 @@
1
+ export * from "./validator.js";