@actiondock/core 2.9.1 → 2.11.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 (256) hide show
  1. package/README.md +1 -2
  2. package/dist/catalog/action-catalog.js +3 -33
  3. package/dist/catalog/discovery.d.ts +0 -3
  4. package/dist/catalog/discovery.js +4 -4
  5. package/dist/catalog/graph.d.ts +0 -4
  6. package/dist/catalog/graph.js +12 -15
  7. package/dist/{profile/client-actions.d.ts → client/actions.d.ts} +1 -1
  8. package/dist/{profile/client-actions.js → client/actions.js} +2 -8
  9. package/dist/{profile/client-config.d.ts → client/config.d.ts} +1 -1
  10. package/dist/{profile/client-config.js → client/config.js} +1 -1
  11. package/dist/client/dispatcher.d.ts +4 -0
  12. package/dist/client/dispatcher.js +21 -0
  13. package/dist/client/health.d.ts +38 -0
  14. package/dist/{profile/client-health.js → client/health.js} +9 -6
  15. package/dist/client/index.d.ts +16 -0
  16. package/dist/client/index.js +20 -0
  17. package/dist/{profile/client-playbooks.d.ts → client/playbooks.d.ts} +1 -1
  18. package/dist/{profile/client-playbooks.js → client/playbooks.js} +1 -1
  19. package/dist/{profile/client-runs.d.ts → client/runs.d.ts} +4 -2
  20. package/dist/{profile/client-runs.js → client/runs.js} +7 -1
  21. package/dist/{profile/client-state.d.ts → client/state.d.ts} +1 -1
  22. package/dist/{profile/client-state.js → client/state.js} +1 -1
  23. package/dist/{profile/client-transport.d.ts → client/transport.d.ts} +29 -10
  24. package/dist/{profile/client-transport.js → client/transport.js} +125 -35
  25. package/dist/doctor/checks/index.d.ts +1 -1
  26. package/dist/doctor/checks/index.js +1 -1
  27. package/dist/doctor/checks/project.js +24 -92
  28. package/dist/doctor/checks/registry.js +1 -1
  29. package/dist/doctor/checks/runtime.d.ts +0 -4
  30. package/dist/doctor/checks/runtime.js +0 -28
  31. package/dist/doctor/doctor.js +1 -2
  32. package/dist/errors.d.ts +85 -4
  33. package/dist/errors.js +114 -4
  34. package/dist/execution/service.d.ts +55 -37
  35. package/dist/execution/service.js +601 -212
  36. package/dist/execution/types.d.ts +24 -5
  37. package/dist/host/host.d.ts +42 -22
  38. package/dist/host/host.js +565 -150
  39. package/dist/host/routing.js +6 -6
  40. package/dist/host/types.d.ts +25 -13
  41. package/dist/index.d.ts +9 -4
  42. package/dist/index.js +5 -2
  43. package/dist/input/advice.d.ts +0 -44
  44. package/dist/input/advice.js +7 -141
  45. package/dist/input/describe.d.ts +6 -0
  46. package/dist/input/describe.js +26 -1
  47. package/dist/input/flat-materializer.js +1 -1
  48. package/dist/input/flat-parser.js +1 -1
  49. package/dist/input/index.d.ts +0 -1
  50. package/dist/input/index.js +0 -1
  51. package/dist/input/input-resolver.js +2 -2
  52. package/dist/input/validation-mapper.d.ts +1 -1
  53. package/dist/invocation/policy.js +2 -0
  54. package/dist/ipc/diagnostic.d.ts +8 -21
  55. package/dist/ipc/diagnostic.js +24 -57
  56. package/dist/ipc/host.js +21 -7
  57. package/dist/ipc/service.d.ts +14 -0
  58. package/dist/ipc/service.js +132 -26
  59. package/dist/ipc/types.d.ts +0 -4
  60. package/dist/package/index.d.ts +4 -5
  61. package/dist/package/index.js +1 -2
  62. package/dist/package/runtime.d.ts +94 -23
  63. package/dist/package/runtime.js +628 -274
  64. package/dist/package/static-index.d.ts +3 -6
  65. package/dist/package/static-index.js +11 -40
  66. package/dist/package/types.d.ts +19 -4
  67. package/dist/platform/index.d.ts +2 -1
  68. package/dist/platform/index.js +2 -1
  69. package/dist/platform/loader-hook.d.ts +32 -0
  70. package/dist/platform/loader-hook.js +90 -0
  71. package/dist/{node → platform}/module-loader.d.ts +13 -0
  72. package/dist/{node → platform}/module-loader.js +51 -4
  73. package/dist/platform/node.d.ts +19 -8
  74. package/dist/platform/node.js +50 -20
  75. package/dist/platform/types.d.ts +7 -47
  76. package/dist/process/context-process.d.ts +3 -18
  77. package/dist/process/context-process.js +3 -44
  78. package/dist/process/control.d.ts +21 -0
  79. package/dist/process/control.js +34 -0
  80. package/dist/process/converters.d.ts +23 -0
  81. package/dist/process/converters.js +92 -0
  82. package/dist/process/cursor.js +2 -22
  83. package/dist/process/{diagnostics-sink.d.ts → diagnostics.d.ts} +0 -7
  84. package/dist/process/{diagnostics-sink.js → diagnostics.js} +6 -8
  85. package/dist/process/index.d.ts +1 -3
  86. package/dist/process/index.js +1 -3
  87. package/dist/process/input-dispatcher.d.ts +4 -13
  88. package/dist/process/input-dispatcher.js +48 -69
  89. package/dist/process/managed-record.d.ts +3 -31
  90. package/dist/process/metadata-store.d.ts +0 -41
  91. package/dist/process/metadata-store.js +2 -341
  92. package/dist/process/process-driver.js +2 -2
  93. package/dist/process/process-manager.d.ts +8 -50
  94. package/dist/process/process-manager.js +28 -417
  95. package/dist/process/quotas.d.ts +14 -0
  96. package/dist/process/quotas.js +29 -0
  97. package/dist/process/run-executor.js +0 -1
  98. package/dist/process/terminal-output-cache.d.ts +20 -34
  99. package/dist/process/terminal-output-cache.js +43 -64
  100. package/dist/profile/index.d.ts +1 -2
  101. package/dist/profile/index.js +1 -2
  102. package/dist/profile/manager.d.ts +2 -4
  103. package/dist/profile/manager.js +10 -40
  104. package/dist/profile/types.d.ts +1 -17
  105. package/dist/project/digest.d.ts +5 -1
  106. package/dist/project/digest.js +81 -219
  107. package/dist/project/index.d.ts +4 -5
  108. package/dist/project/index.js +4 -5
  109. package/dist/project/init.js +2 -2
  110. package/dist/project/loader.d.ts +3 -3
  111. package/dist/project/loader.js +72 -50
  112. package/dist/project/lockfile.js +6 -5
  113. package/dist/project/manifest.js +5 -4
  114. package/dist/project/transactions.d.ts +4 -42
  115. package/dist/project/transactions.js +83 -138
  116. package/dist/project/types-generator.js +2 -1
  117. package/dist/project/types.d.ts +2 -0
  118. package/dist/registry/index.d.ts +0 -1
  119. package/dist/registry/index.js +0 -1
  120. package/dist/registry/lock.d.ts +2 -11
  121. package/dist/registry/lock.js +14 -183
  122. package/dist/registry/registry.d.ts +1 -6
  123. package/dist/registry/registry.js +5 -17
  124. package/dist/runtime/action-registry.d.ts +1 -5
  125. package/dist/runtime/action-registry.js +0 -12
  126. package/dist/runtime/context.js +2 -2
  127. package/dist/runtime/events.d.ts +11 -50
  128. package/dist/runtime/events.js +88 -368
  129. package/dist/runtime/index.d.ts +0 -4
  130. package/dist/runtime/index.js +0 -4
  131. package/dist/runtime/run-persistence.d.ts +2 -0
  132. package/dist/runtime/run-persistence.js +2 -1
  133. package/dist/runtime/standalone-commands.d.ts +18 -0
  134. package/dist/runtime/standalone-commands.js +466 -0
  135. package/dist/runtime/standalone-help.d.ts +20 -0
  136. package/dist/runtime/standalone-help.js +72 -0
  137. package/dist/runtime/standalone.d.ts +1 -44
  138. package/dist/runtime/standalone.js +31 -526
  139. package/dist/schema/validator.d.ts +2 -2
  140. package/dist/schema/validator.js +2 -9
  141. package/dist/server/index.d.ts +0 -2
  142. package/dist/server/index.js +0 -2
  143. package/dist/server/routes/actions.js +1 -1
  144. package/dist/server/routes/info.js +1 -1
  145. package/dist/server/routes/playbooks.js +1 -1
  146. package/dist/server/routes/runs.js +123 -16
  147. package/dist/server/routes/state.js +43 -18
  148. package/dist/server/security.d.ts +1 -1
  149. package/dist/server/security.js +2 -2
  150. package/dist/server/server.js +3 -7
  151. package/dist/service/factory.js +4 -3
  152. package/dist/service/index.d.ts +1 -1
  153. package/dist/service/index.js +1 -1
  154. package/dist/service/remote-errors.d.ts +1 -1
  155. package/dist/service/remote-errors.js +6 -6
  156. package/dist/service/remote-polling.d.ts +3 -0
  157. package/dist/service/remote-polling.js +10 -5
  158. package/dist/service/remote.d.ts +5 -1
  159. package/dist/service/remote.js +108 -17
  160. package/dist/service/sse-stream.js +2 -2
  161. package/dist/service/types.d.ts +22 -19
  162. package/dist/service/types.js +1 -24
  163. package/dist/storage/clock.d.ts +1 -1
  164. package/dist/storage/clock.js +1 -1
  165. package/dist/storage/data-dir-lock.d.ts +10 -22
  166. package/dist/storage/data-dir-lock.js +28 -56
  167. package/dist/storage/file-lock.d.ts +64 -0
  168. package/dist/storage/file-lock.js +447 -0
  169. package/dist/storage/index.d.ts +2 -2
  170. package/dist/storage/index.js +5 -4
  171. package/dist/storage/run-liveness.d.ts +48 -0
  172. package/dist/storage/run-liveness.js +44 -0
  173. package/dist/storage/sqlite-config.d.ts +16 -0
  174. package/dist/storage/sqlite-config.js +59 -0
  175. package/dist/storage/sqlite-driver.d.ts +3 -1
  176. package/dist/storage/sqlite-driver.js +14 -4
  177. package/dist/storage/sqlite-events.d.ts +13 -0
  178. package/dist/storage/sqlite-events.js +48 -0
  179. package/dist/storage/sqlite-runs.d.ts +107 -0
  180. package/dist/storage/sqlite-runs.js +622 -0
  181. package/dist/storage/sqlite-schema.d.ts +5 -0
  182. package/dist/storage/sqlite-schema.js +143 -0
  183. package/dist/storage/sqlite-state.d.ts +33 -0
  184. package/dist/storage/sqlite-state.js +270 -0
  185. package/dist/storage/sqlite.d.ts +30 -57
  186. package/dist/storage/sqlite.js +84 -741
  187. package/dist/storage/types.d.ts +35 -2
  188. package/dist/utils/index.d.ts +18 -14
  189. package/dist/utils/index.js +37 -29
  190. package/dist/utils/semver.d.ts +18 -0
  191. package/dist/utils/semver.js +19 -0
  192. package/dist/utils/warning.d.ts +1 -0
  193. package/dist/utils/warning.js +52 -0
  194. package/dist/{json/value-validator.d.ts → value-validator.d.ts} +9 -0
  195. package/dist/value-validator.js +330 -0
  196. package/dist/version.d.ts +1 -1
  197. package/dist/version.js +1 -1
  198. package/package.json +10 -12
  199. package/dist/execution/index.d.ts +0 -2
  200. package/dist/execution/index.js +0 -2
  201. package/dist/filter/index.d.ts +0 -1
  202. package/dist/filter/index.js +0 -1
  203. package/dist/graph/index.d.ts +0 -4
  204. package/dist/graph/index.js +0 -4
  205. package/dist/input/metadata.d.ts +0 -99
  206. package/dist/input/metadata.js +0 -99
  207. package/dist/invocation/index.d.ts +0 -2
  208. package/dist/invocation/index.js +0 -2
  209. package/dist/ipc/index.d.ts +0 -4
  210. package/dist/ipc/index.js +0 -4
  211. package/dist/json/index.d.ts +0 -1
  212. package/dist/json/index.js +0 -1
  213. package/dist/json/value-validator.js +0 -330
  214. package/dist/node/index.d.ts +0 -1
  215. package/dist/node/index.js +0 -1
  216. package/dist/platform/node-fs.d.ts +0 -37
  217. package/dist/platform/node-fs.js +0 -81
  218. package/dist/process/control-arbiter.d.ts +0 -108
  219. package/dist/process/control-arbiter.js +0 -250
  220. package/dist/process/process-executor.d.ts +0 -47
  221. package/dist/process/process-executor.js +0 -296
  222. package/dist/profile/client-health.d.ts +0 -14
  223. package/dist/profile/client-query.d.ts +0 -30
  224. package/dist/profile/client-query.js +0 -69
  225. package/dist/profile/client.d.ts +0 -26
  226. package/dist/profile/client.js +0 -31
  227. package/dist/project/closure.d.ts +0 -25
  228. package/dist/project/closure.js +0 -74
  229. package/dist/registry/store.d.ts +0 -42
  230. package/dist/registry/store.js +0 -43
  231. package/dist/runtime/clock.d.ts +0 -7
  232. package/dist/runtime/clock.js +0 -7
  233. package/dist/runtime/module-loader.d.ts +0 -2
  234. package/dist/runtime/module-loader.js +0 -1
  235. package/dist/runtime/process.d.ts +0 -8
  236. package/dist/runtime/process.js +0 -1
  237. package/dist/runtime/runner.d.ts +0 -234
  238. package/dist/runtime/runner.js +0 -609
  239. package/dist/schema/index.d.ts +0 -1
  240. package/dist/schema/index.js +0 -1
  241. package/dist/server/dispatcher.d.ts +0 -25
  242. package/dist/server/dispatcher.js +0 -54
  243. package/dist/service/local.d.ts +0 -27
  244. package/dist/service/local.js +0 -141
  245. package/dist/storage/driver.d.ts +0 -10
  246. package/dist/storage/driver.js +0 -10
  247. package/dist/storage/lazy.d.ts +0 -8
  248. package/dist/storage/lazy.js +0 -45
  249. package/dist/storage/lock-core.d.ts +0 -158
  250. package/dist/storage/lock-core.js +0 -872
  251. package/dist/utils/net.d.ts +0 -10
  252. package/dist/utils/net.js +0 -16
  253. package/dist/utils/process.d.ts +0 -10
  254. package/dist/utils/process.js +0 -21
  255. /package/dist/{filter → utils}/intent.d.ts +0 -0
  256. /package/dist/{filter → utils}/intent.js +0 -0
@@ -1,11 +1,8 @@
1
- import { decodeStateKey } from "@actiondock/sdk";
2
- import { filterWithFallbackInfo } from "../filter/index.js";
3
1
  import { createActionDock } from "../service/factory.js";
4
2
  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";
7
3
  import { normalizeActionCollection } from "./action-collection.js";
8
- import { parseDuration } from "../utils/index.js";
4
+ import { parseStandaloneArgs, printHelp, emitError } from "./standalone-help.js";
5
+ import { handleList, handleDescribe, handleRun, handleConfig, handleState, } from "./standalone-commands.js";
9
6
  /**
10
7
  * 退出状态码常量。
11
8
  */
@@ -45,38 +42,10 @@ export class StandaloneDispatcher {
45
42
  console.error(msg);
46
43
  }
47
44
  }
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
45
  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;
46
+ return emitError(this.writeOut.bind(this), this.writeErr.bind(this), isJson, code, message, exitCode, options);
78
47
  }
79
- async createLocalService(dataDir, configOverrides = {}) {
48
+ async createLocalService(dataDir, configOverrides = {}, accessMode = "owner") {
80
49
  if (this.options.service) {
81
50
  return { service: this.options.service, ownsService: false };
82
51
  }
@@ -104,6 +73,9 @@ export class StandaloneDispatcher {
104
73
  };
105
74
  const service = await createActionDock({
106
75
  runtimeOptions,
76
+ // 发现入口使用旁观初始化:不创建数据库、不取目录锁、不收割遗留运行记录;
77
+ // 执行与写入入口继续持有者初始化(默认 recoverOrphans 语义)
78
+ ...(accessMode === "observer" ? { recoverOrphans: false } : {}),
107
79
  });
108
80
  if (this.options.inMemory) {
109
81
  this.options._sharedService = service;
@@ -111,6 +83,13 @@ export class StandaloneDispatcher {
111
83
  }
112
84
  return { service, ownsService: true };
113
85
  }
86
+ printHelp() {
87
+ printHelp(this.writeOut.bind(this), {
88
+ packageId: this.options.packageId,
89
+ version: this.options.version,
90
+ description: this.options.description,
91
+ });
92
+ }
114
93
  /**
115
94
  * 解析命令行参数并分发执行对应子命令。
116
95
  *
@@ -119,39 +98,7 @@ export class StandaloneDispatcher {
119
98
  * @returns 退出状态码(0: 成功, 1: 失败, 2: 参数错误, 130: 中断)
120
99
  */
121
100
  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) : [];
125
- let dataDir;
126
- const configOverrides = {};
127
- // 1. 提取全局参数(--data-dir, --config)仅从 controlArgs 中解析
128
- const filteredArgs = [];
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];
133
- }
134
- else if (arg.startsWith("--data-dir=")) {
135
- dataDir = arg.slice(11);
136
- }
137
- else if (arg === "--config" && i + 1 < controlArgs.length) {
138
- const pair = controlArgs[++i];
139
- const [k, ...v] = pair.split("=");
140
- if (k)
141
- configOverrides[k] = v.join("=");
142
- }
143
- else if (arg.startsWith("--config=")) {
144
- const pair = arg.slice(9);
145
- const [k, ...v] = pair.split("=");
146
- if (k)
147
- configOverrides[k] = v.join("=");
148
- }
149
- else {
150
- filteredArgs.push(arg);
151
- }
152
- }
153
- const command = filteredArgs[0] || "help";
154
- const subArgs = filteredArgs.slice(1);
101
+ const { controlArgs, actionArgs, dataDir, configOverrides, command, subArgs, } = parseStandaloneArgs(argv);
155
102
  // 2. 独立入口拒绝异步启动语义
156
103
  if (controlArgs.includes("--async")) {
157
104
  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, {
@@ -170,7 +117,10 @@ export class StandaloneDispatcher {
170
117
  let service;
171
118
  let ownsService = false;
172
119
  try {
173
- const serviceRes = await this.createLocalService(dataDir, configOverrides);
120
+ // 复用既有命令分发结果确定访问性质:发现命令(list/describe)为旁观;
121
+ // 执行与写入命令(run/config/state)为持有者
122
+ const accessMode = command === "list" || command === "describe" || command === "show" ? "observer" : "owner";
123
+ const serviceRes = await this.createLocalService(dataDir, configOverrides, accessMode);
174
124
  service = serviceRes.service;
175
125
  ownsService = serviceRes.ownsService;
176
126
  }
@@ -178,24 +128,31 @@ export class StandaloneDispatcher {
178
128
  this.writeErr(`Error initializing standalone service: ${err?.message || err}`);
179
129
  return ExitCode.FAILURE;
180
130
  }
131
+ const ctx = {
132
+ service,
133
+ options: this.options,
134
+ writeOut: this.writeOut.bind(this),
135
+ writeErr: this.writeErr.bind(this),
136
+ emitError: this.emitError.bind(this),
137
+ };
181
138
  try {
182
139
  let code;
183
140
  switch (command) {
184
141
  case "list":
185
- code = await this.handleList(service, subArgs);
142
+ code = await handleList(ctx, subArgs);
186
143
  break;
187
144
  case "describe":
188
145
  case "show":
189
- code = await this.handleDescribe(service, subArgs);
146
+ code = await handleDescribe(ctx, subArgs);
190
147
  break;
191
148
  case "run":
192
- code = await this.handleRun(service, subArgs, actionArgs, control?.signal);
149
+ code = await handleRun(ctx, subArgs, actionArgs, control?.signal);
193
150
  break;
194
151
  case "config":
195
- code = await this.handleConfig(service, subArgs);
152
+ code = await handleConfig(ctx, subArgs);
196
153
  break;
197
154
  case "state":
198
- code = await this.handleState(service, subArgs);
155
+ code = await handleState(ctx, subArgs);
199
156
  break;
200
157
  default:
201
158
  this.writeErr(`Unknown command: '${command}'`);
@@ -221,458 +178,6 @@ export class StandaloneDispatcher {
221
178
  }
222
179
  }
223
180
  }
224
- async handleList(service, subArgs) {
225
- const isJson = subArgs.includes("--json");
226
- const noFallback = subArgs.includes("--no-fallback");
227
- let intent;
228
- const positionalPatterns = [];
229
- for (let i = 0; i < subArgs.length; i++) {
230
- const arg = subArgs[i];
231
- if (arg === "--intent" || arg === "-i") {
232
- if (i + 1 < subArgs.length)
233
- intent = subArgs[++i];
234
- }
235
- else if (arg.startsWith("--intent=")) {
236
- intent = arg.slice(9);
237
- }
238
- else if (arg.startsWith("-i=")) {
239
- intent = arg.slice(3);
240
- }
241
- else if (!arg.startsWith("-")) {
242
- positionalPatterns.push(arg);
243
- }
244
- }
245
- const effectiveIntent = intent || (positionalPatterns.length > 0 ? positionalPatterns.join("|") : undefined);
246
- const actions = await service.discovery.listActions();
247
- const list = actions.map((a) => ({
248
- id: a.id,
249
- description: a.description || "",
250
- }));
251
- const filterRes = filterWithFallbackInfo(list, effectiveIntent, [(a) => a.id, (a) => a.description], !noFallback);
252
- if (isJson) {
253
- this.writeOut(JSON.stringify(filterRes.items, null, 2));
254
- }
255
- else {
256
- let text = `Actions in ${this.options.packageId} (v${this.options.version}):\n\n`;
257
- for (const a of filterRes.items) {
258
- text += ` ${a.id.padEnd(28)} ${a.description}\n`;
259
- }
260
- this.writeOut(text.trimEnd());
261
- }
262
- return ExitCode.SUCCESS;
263
- }
264
- async handleDescribe(service, subArgs) {
265
- const id = subArgs.find((a) => !a.startsWith("-"));
266
- const isJson = subArgs.includes("--json");
267
- if (!id) {
268
- return this.emitError(isJson, "INVALID_ARGUMENT", "Action ID is required for describe", ExitCode.INVALID_ARGUMENT);
269
- }
270
- let action;
271
- try {
272
- action = await service.discovery.describeAction(id);
273
- }
274
- catch {
275
- return this.emitError(isJson, "INVALID_ARGUMENT", `Action '${id}' not found`, ExitCode.INVALID_ARGUMENT);
276
- }
277
- const payload = buildActionDescribePayload(action, {
278
- packageId: this.options.packageId,
279
- });
280
- if (isJson) {
281
- this.writeOut(JSON.stringify(payload, null, 2));
282
- }
283
- else {
284
- this.writeOut(formatActionDetail(payload));
285
- }
286
- return ExitCode.SUCCESS;
287
- }
288
- async handleRun(service, subArgs, actionArgs, signal) {
289
- const isJson = subArgs.includes("--json");
290
- const id = subArgs.find((a) => !a.startsWith("-"));
291
- if (!id) {
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" });
293
- }
294
- let inputStr;
295
- let inputFile;
296
- let timeoutMs;
297
- for (let i = 0; i < subArgs.length; i++) {
298
- const arg = subArgs[i];
299
- if (arg === "--timeout" && i + 1 < subArgs.length) {
300
- try {
301
- timeoutMs = parseDuration(subArgs[++i]);
302
- }
303
- catch (err) {
304
- return this.emitError(isJson, "INVALID_ARGUMENT", `Invalid timeout format: ${err?.message || err}`, ExitCode.INVALID_ARGUMENT);
305
- }
306
- }
307
- else if (arg.startsWith("--timeout=")) {
308
- try {
309
- timeoutMs = parseDuration(arg.slice(10));
310
- }
311
- catch (err) {
312
- return this.emitError(isJson, "INVALID_ARGUMENT", `Invalid timeout format: ${err?.message || err}`, ExitCode.INVALID_ARGUMENT);
313
- }
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
- }
321
- else if (arg === "--input-file" && i + 1 < subArgs.length) {
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);
339
- }
340
- }
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, {
347
- signal,
348
- timeoutMs,
349
- });
350
- if (isJson) {
351
- this.writeOut(JSON.stringify(result, null, 2));
352
- }
353
- else {
354
- if (result.ok) {
355
- const data = result.data;
356
- let rawText;
357
- let metaInfo;
358
- if (typeof data === "string") {
359
- rawText = data;
360
- }
361
- else if (data !== null && typeof data === "object") {
362
- if ("content" in data && data.content !== undefined) {
363
- rawText =
364
- typeof data.content === "object" && data.content !== null
365
- ? JSON.stringify(data.content, null, 2)
366
- : String(data.content);
367
- const { content, ...rest } = data;
368
- if (Object.keys(rest).length > 0) {
369
- metaInfo = rest;
370
- }
371
- }
372
- else if ("text" in data && typeof data.text === "string") {
373
- rawText = data.text;
374
- const { text, ...rest } = data;
375
- if (Object.keys(rest).length > 0) {
376
- metaInfo = rest;
377
- }
378
- }
379
- else if ("message" in data && typeof data.message === "string") {
380
- rawText = data.message;
381
- const { message, ...rest } = data;
382
- if (Object.keys(rest).length > 0) {
383
- metaInfo = rest;
384
- }
385
- }
386
- else {
387
- rawText = JSON.stringify(data, null, 2);
388
- }
389
- }
390
- else if (data !== undefined) {
391
- rawText = String(data);
392
- }
393
- else {
394
- rawText = "";
395
- }
396
- if (metaInfo) {
397
- const parts = [];
398
- const title = metaInfo.path ? String(metaInfo.path) : id;
399
- parts.push(title);
400
- if (metaInfo.startLine !== undefined && metaInfo.endLine !== undefined) {
401
- parts.push(`lines ${metaInfo.startLine}-${metaInfo.endLine}`);
402
- }
403
- else if (metaInfo.line !== undefined) {
404
- parts.push(`line ${metaInfo.line}`);
405
- }
406
- if (metaInfo.hasMore !== undefined) {
407
- parts.push(`hasMore: ${metaInfo.hasMore}`);
408
- }
409
- if (metaInfo.truncated) {
410
- parts.push("truncated: true");
411
- }
412
- const handled = new Set(["path", "startLine", "endLine", "line", "hasMore", "truncated"]);
413
- for (const [k, v] of Object.entries(metaInfo)) {
414
- if (!handled.has(k) && v !== undefined) {
415
- parts.push(`${k}: ${typeof v === "object" ? JSON.stringify(v) : v}`);
416
- }
417
- }
418
- if (parts.length > 0) {
419
- this.writeErr(`[${parts.join(" | ")}]`);
420
- }
421
- }
422
- this.writeOut(rawText);
423
- }
424
- else {
425
- this.writeErr(`Error [${result.error.code}]: ${result.error.message}`);
426
- if (result.error.details) {
427
- this.writeErr(typeof result.error.details === "string"
428
- ? result.error.details
429
- : JSON.stringify(result.error.details, null, 2));
430
- }
431
- }
432
- }
433
- return result.ok ? ExitCode.SUCCESS : ExitCode.FAILURE;
434
- }
435
- async handleConfig(service, subArgs) {
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
- }
441
- if (sub === "list") {
442
- const views = await service.management.config.list(this.options.packageId);
443
- const dict = {};
444
- for (const v of views) {
445
- if (v.configured && v.value !== undefined) {
446
- dict[v.key] = v.value;
447
- }
448
- }
449
- this.writeOut(JSON.stringify(dict, null, 2));
450
- return ExitCode.SUCCESS;
451
- }
452
- if (sub === "get") {
453
- const key = subArgs[1];
454
- if (!key) {
455
- this.writeErr("Error: config key required");
456
- return ExitCode.INVALID_ARGUMENT;
457
- }
458
- try {
459
- const item = await service.management.config.get(this.options.packageId, key);
460
- this.writeOut(item.configured ? JSON.stringify(item.value) : "undefined");
461
- return ExitCode.SUCCESS;
462
- }
463
- catch (err) {
464
- // 服务能力缺失(如远端未开启管理接口)视为键未配置,输出 undefined
465
- if (this.isServiceCapabilityError(err)) {
466
- this.writeOut("undefined");
467
- return ExitCode.SUCCESS;
468
- }
469
- // 内部异常严禁吞没:透传 stderr 并以 FAILURE 退出码暴露
470
- this.writeErr(`Error reading config '${key}': ${err?.message || String(err)}`);
471
- return ExitCode.FAILURE;
472
- }
473
- }
474
- if (sub === "set") {
475
- const key = subArgs[1];
476
- const rawVal = subArgs[2];
477
- if (!key || rawVal === undefined) {
478
- this.writeErr("Error: key and value required");
479
- return ExitCode.INVALID_ARGUMENT;
480
- }
481
- let parsed = rawVal;
482
- try {
483
- parsed = JSON.parse(rawVal);
484
- }
485
- catch {
486
- parsed = rawVal;
487
- }
488
- await service.management.config.set(this.options.packageId, key, parsed);
489
- this.writeOut(`Config '${key}' updated`);
490
- return ExitCode.SUCCESS;
491
- }
492
- if (sub === "delete") {
493
- const key = subArgs[1];
494
- if (!key) {
495
- this.writeErr("Error: config key required");
496
- return ExitCode.INVALID_ARGUMENT;
497
- }
498
- await service.management.config.delete(this.options.packageId, key);
499
- this.writeOut(`Config '${key}' deleted`);
500
- return ExitCode.SUCCESS;
501
- }
502
- this.writeErr(`Unknown config subcommand: '${sub}'`);
503
- return ExitCode.INVALID_ARGUMENT;
504
- }
505
- async handleState(service, subArgs) {
506
- const sub = subArgs[0] || "list";
507
- let namespace;
508
- let isAll = false;
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
- }
514
- for (let i = 1; i < subArgs.length; i++) {
515
- if ((subArgs[i] === "-n" || subArgs[i] === "--namespace") && i + 1 < subArgs.length) {
516
- namespace = subArgs[++i];
517
- }
518
- else if (subArgs[i].startsWith("--namespace=")) {
519
- namespace = subArgs[i].slice(12);
520
- }
521
- else if (subArgs[i] === "-a" || subArgs[i] === "--all") {
522
- isAll = true;
523
- }
524
- else if (subArgs[i] === "--json") {
525
- isJson = true;
526
- }
527
- }
528
- if (sub === "list") {
529
- const prefix = subArgs[1] && !subArgs[1].startsWith("-") ? subArgs[1] : "";
530
- const keys = await service.management.state.list(this.options.packageId, "", {
531
- namespace,
532
- prefix: prefix || undefined,
533
- all: isAll,
534
- });
535
- this.writeOut(JSON.stringify(keys, null, 2));
536
- return ExitCode.SUCCESS;
537
- }
538
- if (sub === "get") {
539
- const key = subArgs[1] && !subArgs[1].startsWith("-") ? subArgs[1] : subArgs[2];
540
- if (!key) {
541
- this.writeErr("Error: state key required");
542
- return ExitCode.INVALID_ARGUMENT;
543
- }
544
- let ns = namespace;
545
- let actualKey = key;
546
- if (ns === undefined) {
547
- const decoded = this.decodeStateKeyArg(key);
548
- ns = decoded.namespace || undefined;
549
- actualKey = decoded.key;
550
- }
551
- const val = await service.management.state.get(this.options.packageId, "", actualKey, { namespace: ns });
552
- if (isJson) {
553
- this.writeOut(JSON.stringify({ key, value: val }, null, 2));
554
- }
555
- else {
556
- this.writeOut(val !== undefined ? JSON.stringify(val) : "undefined");
557
- }
558
- return ExitCode.SUCCESS;
559
- }
560
- if (sub === "set") {
561
- const key = subArgs[1];
562
- const rawVal = subArgs[2];
563
- if (!key || rawVal === undefined) {
564
- this.writeErr("Error: key and value required");
565
- return ExitCode.INVALID_ARGUMENT;
566
- }
567
- let ns = namespace || "";
568
- let actualKey = key;
569
- if (namespace === undefined) {
570
- const decoded = this.decodeStateKeyArg(key);
571
- ns = decoded.namespace;
572
- actualKey = decoded.key;
573
- }
574
- let parsed = rawVal;
575
- try {
576
- parsed = JSON.parse(rawVal);
577
- }
578
- catch {
579
- parsed = rawVal;
580
- }
581
- let ttl;
582
- for (let i = 3; i < subArgs.length; i++) {
583
- if (subArgs[i] === "--ttl" && i + 1 < subArgs.length) {
584
- ttl = parseInt(subArgs[++i], 10);
585
- }
586
- else if (subArgs[i].startsWith("--ttl=")) {
587
- ttl = parseInt(subArgs[i].slice(6), 10);
588
- }
589
- }
590
- await service.management.state.set(this.options.packageId, "", actualKey, parsed, { namespace: ns, ttl });
591
- const displayKey = ns ? `${ns}:${actualKey}` : actualKey;
592
- this.writeOut(`State '${displayKey}' updated`);
593
- return ExitCode.SUCCESS;
594
- }
595
- if (sub === "delete" || sub === "rm") {
596
- const key = subArgs[1] && !subArgs[1].startsWith("-") ? subArgs[1] : subArgs[2];
597
- if (!key) {
598
- this.writeErr("Error: state key required");
599
- return ExitCode.INVALID_ARGUMENT;
600
- }
601
- const deleted = await service.management.state.delete(this.options.packageId, "", key, { namespace });
602
- if (deleted) {
603
- this.writeOut(`State '${key}' deleted`);
604
- return ExitCode.SUCCESS;
605
- }
606
- this.writeErr(`Error: State key '${key}' not found`);
607
- return ExitCode.FAILURE;
608
- }
609
- if (sub === "clear" || sub === "clean") {
610
- const prefix = subArgs[1] && !subArgs[1].startsWith("-") ? subArgs[1] : "";
611
- const count = await service.management.state.clear(this.options.packageId, "", {
612
- namespace,
613
- all: isAll,
614
- prefix: prefix || undefined,
615
- });
616
- this.writeOut(`Cleared ${count} state entry(s)`);
617
- return ExitCode.SUCCESS;
618
- }
619
- this.writeErr(`Unknown state subcommand: '${sub}'`);
620
- return ExitCode.INVALID_ARGUMENT;
621
- }
622
- /**
623
- * 判定配置读取异常是否为服务能力缺失(键未配置语义)而非内部故障。
624
- */
625
- isServiceCapabilityError(err) {
626
- const code = String(err?.code || "");
627
- return (code === "CAPABILITY_UNAVAILABLE" ||
628
- code === "TARGET_CAPABILITY_UNAVAILABLE");
629
- }
630
- /**
631
- * 解析携带命名空间前缀的状态键参数:委托 sdk 单一事实源 decodeStateKey。
632
- *
633
- * 解析失败(如存在多个未转义冒号的歧义键)时按纯键处理,交由存储层兜底。
634
- */
635
- decodeStateKeyArg(key) {
636
- try {
637
- return decodeStateKey(key);
638
- }
639
- catch {
640
- return { namespace: "", key };
641
- }
642
- }
643
- printHelp() {
644
- this.writeOut(`${this.options.packageId} (v${this.options.version})`);
645
- if (this.options.description)
646
- this.writeOut(`${this.options.description}\n`);
647
- this.writeOut("Usage:");
648
- this.writeOut(" <cmd> list [--json] List available actions");
649
- this.writeOut(" <cmd> describe <id> [--json] Show action details and schemas");
650
- this.writeOut(" <cmd> run <id> [--input '<json>'] Execute action (raw text output by default)");
651
- this.writeOut(" <cmd> run <id> [--json] Output standard execution result in JSON format");
652
- this.writeOut(" <cmd> config list/get/set/delete Manage package configuration");
653
- this.writeOut(" <cmd> state list/get/set/delete Manage shared state store");
654
- this.writeOut("\nGlobal options:");
655
- this.writeOut(" --data-dir <path> Custom runtime database directory");
656
- this.writeOut(" --config <KEY=val> Temporary config override");
657
- }
658
- }
659
- export class StandaloneRuntime {
660
- dispatcher;
661
- constructor(options) {
662
- this.dispatcher = new StandaloneDispatcher(options);
663
- }
664
- async run(argv) {
665
- const code = await this.dispatcher.dispatch(argv);
666
- if (code !== ExitCode.SUCCESS && code !== ExitCode.FAILURE) {
667
- process.exit(code);
668
- }
669
- }
670
- }
671
- /**
672
- * 工厂函数:创建独立运行时实例。
673
- */
674
- export function createStandaloneRuntime(options) {
675
- return new StandaloneRuntime(options);
676
181
  }
677
182
  /**
678
183
  * 独立二进制进程入口适配器。
@@ -10,9 +10,9 @@ export interface ValidationResult {
10
10
  }
11
11
  /**
12
12
  * 递归检查数据中是否包含危险的原型污染属性键名(__proto__、constructor、prototype)。
13
- * 内部委托 validateActionInputValue 执行迭代遍历,确保环路安全、有向无环图安全且无调用栈溢出风险。
14
13
  */
15
- export declare function hasDangerousKeys(data: unknown): boolean;
14
+ import { hasDangerousKeys } from "../value-validator.js";
15
+ export { hasDangerousKeys };
16
16
  /**
17
17
  * 内部纯 Schema 校验器。
18
18
  * 仅处理布尔 Schema 与 Ajv 规则校验,严禁执行 dangerous-key 遍历。
@@ -18,15 +18,8 @@ const validatorCache = new WeakMap();
18
18
  /**
19
19
  * 递归检查数据中是否包含危险的原型污染属性键名(__proto__、constructor、prototype)。
20
20
  */
21
- import { validateActionInputValue } from "../json/value-validator.js";
22
- /**
23
- * 递归检查数据中是否包含危险的原型污染属性键名(__proto__、constructor、prototype)。
24
- * 内部委托 validateActionInputValue 执行迭代遍历,确保环路安全、有向无环图安全且无调用栈溢出风险。
25
- */
26
- export function hasDangerousKeys(data) {
27
- const result = validateActionInputValue(data);
28
- return !result.valid && result.kind === "input-policy";
29
- }
21
+ import { hasDangerousKeys } from "../value-validator.js";
22
+ export { hasDangerousKeys };
30
23
  /**
31
24
  * 内部纯 Schema 校验器。
32
25
  * 仅处理布尔 Schema 与 Ajv 规则校验,严禁执行 dangerous-key 遍历。
@@ -5,7 +5,6 @@ export * from "./body.js";
5
5
  export * from "./routes/index.js";
6
6
  export * from "./server.js";
7
7
  export * from "./mcp-endpoint.js";
8
- export * from "./dispatcher.js";
9
8
  export * from "./http-server.js";
10
9
  export { serveParentIpc } from "../ipc/host.js";
11
10
  export { IpcActionDockService } from "../ipc/service.js";
@@ -13,6 +12,5 @@ export type { IpcServiceOptions } from "../ipc/types.js";
13
12
  export { parseDuration } from "../utils/index.js";
14
13
  export type { ActionDockHost, ActionDockHostOptions, } from "../host/types.js";
15
14
  export { createActionDockHost, DefaultActionDockHost, } from "../host/host.js";
16
- export { LocalActionDockService, } from "../service/local.js";
17
15
  export { RemoteActionDockService, } from "../service/remote.js";
18
16
  export { ExitCode, StandaloneDispatcher, type StandaloneDispatcherOptions, type InvocationControl, runStandaloneProcess, } from "../runtime/standalone.js";
@@ -5,13 +5,11 @@ export * from "./body.js";
5
5
  export * from "./routes/index.js";
6
6
  export * from "./server.js";
7
7
  export * from "./mcp-endpoint.js";
8
- export * from "./dispatcher.js";
9
8
  export * from "./http-server.js";
10
9
  export { serveParentIpc } from "../ipc/host.js";
11
10
  export { IpcActionDockService } from "../ipc/service.js";
12
11
  export { parseDuration } from "../utils/index.js";
13
12
  export { createActionDockHost, DefaultActionDockHost, } from "../host/host.js";
14
- export { LocalActionDockService, } from "../service/local.js";
15
13
  export { RemoteActionDockService, } from "../service/remote.js";
16
14
  // 独立进程分发器与退出控制
17
15
  export { ExitCode, StandaloneDispatcher, runStandaloneProcess, } from "../runtime/standalone.js";