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