@actiondock/core 2.5.0 → 2.6.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 (134) hide show
  1. package/dist/app/app.d.ts +14 -1
  2. package/dist/app/app.js +88 -215
  3. package/dist/app/static-index.d.ts +39 -0
  4. package/dist/app/static-index.js +164 -0
  5. package/dist/app/types.d.ts +5 -0
  6. package/dist/catalog/action-index.js +6 -4
  7. package/dist/catalog/package-catalog.js +2 -1
  8. package/dist/doctor/checks/index.d.ts +5 -0
  9. package/dist/doctor/checks/index.js +5 -0
  10. package/dist/doctor/checks/project-locate.d.ts +6 -0
  11. package/dist/doctor/checks/project-locate.js +36 -0
  12. package/dist/doctor/checks/project.d.ts +6 -0
  13. package/dist/doctor/checks/project.js +383 -0
  14. package/dist/doctor/checks/registry.d.ts +13 -0
  15. package/dist/doctor/checks/registry.js +207 -0
  16. package/dist/doctor/checks/runtime.d.ts +13 -0
  17. package/dist/doctor/checks/runtime.js +90 -0
  18. package/dist/doctor/checks/storage.d.ts +5 -0
  19. package/dist/doctor/checks/storage.js +34 -0
  20. package/dist/doctor/context.d.ts +35 -0
  21. package/dist/doctor/context.js +11 -0
  22. package/dist/doctor/doctor.d.ts +5 -0
  23. package/dist/doctor/doctor.js +33 -602
  24. package/dist/errors.d.ts +2 -0
  25. package/dist/errors.js +2 -0
  26. package/dist/execution/service.js +14 -9
  27. package/dist/host/host.d.ts +33 -0
  28. package/dist/host/host.js +222 -362
  29. package/dist/host/routing.d.ts +92 -0
  30. package/dist/host/routing.js +238 -0
  31. package/dist/host/types.d.ts +8 -0
  32. package/dist/ipc/host.js +38 -0
  33. package/dist/platform/types.d.ts +7 -0
  34. package/dist/process/control-arbiter.d.ts +107 -0
  35. package/dist/process/control-arbiter.js +251 -0
  36. package/dist/process/diagnostics-sink.d.ts +26 -0
  37. package/dist/process/diagnostics-sink.js +35 -0
  38. package/dist/process/index.d.ts +7 -0
  39. package/dist/process/index.js +7 -0
  40. package/dist/process/input-dispatcher.d.ts +88 -0
  41. package/dist/process/input-dispatcher.js +240 -0
  42. package/dist/process/managed-record.d.ts +78 -0
  43. package/dist/process/managed-record.js +1 -0
  44. package/dist/process/process-manager.d.ts +15 -56
  45. package/dist/process/process-manager.js +119 -707
  46. package/dist/process/reservation-table.d.ts +39 -0
  47. package/dist/process/reservation-table.js +80 -0
  48. package/dist/process/run-executor.d.ts +16 -0
  49. package/dist/process/run-executor.js +155 -0
  50. package/dist/process/terminal-output-cache.d.ts +66 -0
  51. package/dist/process/terminal-output-cache.js +132 -0
  52. package/dist/profile/client-actions.d.ts +56 -0
  53. package/dist/profile/client-actions.js +215 -0
  54. package/dist/profile/client-config.d.ts +20 -0
  55. package/dist/profile/client-config.js +51 -0
  56. package/dist/profile/client-health.d.ts +14 -0
  57. package/dist/profile/client-health.js +68 -0
  58. package/dist/profile/client-playbooks.d.ts +19 -0
  59. package/dist/profile/client-playbooks.js +36 -0
  60. package/dist/profile/client-query.d.ts +30 -0
  61. package/dist/profile/client-query.js +70 -0
  62. package/dist/profile/client-runs.d.ts +42 -0
  63. package/dist/profile/client-runs.js +58 -0
  64. package/dist/profile/client-state.d.ts +56 -0
  65. package/dist/profile/client-state.js +83 -0
  66. package/dist/profile/client-transport.d.ts +61 -0
  67. package/dist/profile/client-transport.js +155 -0
  68. package/dist/profile/client.d.ts +23 -142
  69. package/dist/profile/client.js +28 -588
  70. package/dist/profile/manager.js +1 -1
  71. package/dist/project/closure.d.ts +4 -4
  72. package/dist/project/closure.js +11 -5
  73. package/dist/project/init.js +2 -2
  74. package/dist/project/loader.d.ts +0 -25
  75. package/dist/project/loader.js +1 -154
  76. package/dist/project/transactions.d.ts +12 -14
  77. package/dist/project/transactions.js +60 -836
  78. package/dist/registry/registry.js +6 -4
  79. package/dist/registry/resolve.js +1 -1
  80. package/dist/runtime/action-registry.d.ts +45 -0
  81. package/dist/runtime/action-registry.js +108 -0
  82. package/dist/runtime/clock.d.ts +5 -17
  83. package/dist/runtime/clock.js +5 -15
  84. package/dist/runtime/context.d.ts +3 -0
  85. package/dist/runtime/context.js +17 -56
  86. package/dist/runtime/index.d.ts +3 -0
  87. package/dist/runtime/index.js +3 -0
  88. package/dist/runtime/package-runner-factory.d.ts +82 -0
  89. package/dist/runtime/package-runner-factory.js +186 -0
  90. package/dist/runtime/run-persistence.d.ts +85 -0
  91. package/dist/runtime/run-persistence.js +111 -0
  92. package/dist/runtime/runner.d.ts +23 -33
  93. package/dist/runtime/runner.js +92 -286
  94. package/dist/runtime/standalone.d.ts +11 -1
  95. package/dist/runtime/standalone.js +137 -25
  96. package/dist/server/dispatcher.d.ts +8 -3
  97. package/dist/server/dispatcher.js +16 -40
  98. package/dist/server/routes/runs.js +6 -4
  99. package/dist/server/security.d.ts +1 -7
  100. package/dist/server/security.js +2 -13
  101. package/dist/storage/clock.d.ts +25 -0
  102. package/dist/storage/clock.js +23 -0
  103. package/dist/storage/data-dir-lock.d.ts +3 -36
  104. package/dist/storage/data-dir-lock.js +48 -881
  105. package/dist/storage/index.d.ts +8 -1
  106. package/dist/storage/index.js +8 -2
  107. package/dist/storage/lazy.js +1 -0
  108. package/dist/storage/lock-core.d.ts +162 -0
  109. package/dist/storage/lock-core.js +885 -0
  110. package/dist/storage/sqlite.d.ts +19 -6
  111. package/dist/storage/sqlite.js +81 -89
  112. package/dist/storage/types.d.ts +27 -5
  113. package/dist/storage/types.js +21 -0
  114. package/dist/storage/utils.d.ts +22 -0
  115. package/dist/storage/utils.js +34 -0
  116. package/dist/target/local.d.ts +1 -0
  117. package/dist/target/local.js +23 -17
  118. package/dist/target/remote-errors.d.ts +21 -0
  119. package/dist/target/remote-errors.js +51 -0
  120. package/dist/target/remote-polling.d.ts +35 -0
  121. package/dist/target/remote-polling.js +104 -0
  122. package/dist/target/remote.d.ts +4 -0
  123. package/dist/target/remote.js +108 -301
  124. package/dist/target/sse-parser.d.ts +35 -0
  125. package/dist/target/sse-parser.js +163 -0
  126. package/dist/target/target.js +2 -0
  127. package/dist/target/types.d.ts +6 -0
  128. package/dist/utils/index.d.ts +1 -0
  129. package/dist/utils/index.js +1 -0
  130. package/dist/utils/net.d.ts +10 -0
  131. package/dist/utils/net.js +16 -0
  132. package/dist/version.d.ts +1 -1
  133. package/dist/version.js +1 -1
  134. package/package.json +2 -2
@@ -1,591 +1,31 @@
1
- import { randomUUID } from "node:crypto";
2
- import { normalizeServerUrl } from "./manager.js";
3
- import { ACTION_CANCELLED, ACTION_TIMEOUT, NETWORK_ERROR } from "../errors.js";
4
- import { isLoopbackHost } from "../server/security.js";
5
- import { getInsecureDispatcher } from "../server/dispatcher.js";
6
1
  /**
7
- * 校验在携带认证 Token 时传输层协议是否安全。
8
- * 若请求携带认证 Token 且目标为非本地回环的明文 http://,默认报错拒绝。
9
- * 可通过 allowInsecureHttp 选项、insecure 选项、环境变量或命令行参数豁免。
10
- */
11
- export function assertSecureTransport(serverUrl, token, allowInsecureHttpOrOptions, insecureArg) {
12
- if (!token || !token.trim()) {
13
- return;
14
- }
15
- let allowInsecureHttp = false;
16
- let insecure = false;
17
- if (typeof allowInsecureHttpOrOptions === "object" && allowInsecureHttpOrOptions !== null) {
18
- allowInsecureHttp = Boolean(allowInsecureHttpOrOptions.allowInsecureHttp);
19
- insecure = Boolean(allowInsecureHttpOrOptions.insecure);
20
- }
21
- else {
22
- allowInsecureHttp = Boolean(allowInsecureHttpOrOptions);
23
- insecure = Boolean(insecureArg);
24
- }
25
- const allow = allowInsecureHttp ||
26
- insecure ||
27
- (typeof process !== "undefined" &&
28
- (process.env?.ACTIONDOCK_ALLOW_INSECURE_HTTP === "true" ||
29
- process.env?.ACTIONDOCK_ALLOW_INSECURE_HTTP === "1" ||
30
- process.env?.ACTIONDOCK_INSECURE === "true" ||
31
- process.env?.ACTIONDOCK_INSECURE === "1"));
32
- if (allow) {
33
- return;
34
- }
35
- const base = normalizeServerUrl(serverUrl);
36
- if (base.startsWith("http://")) {
37
- try {
38
- const parsed = new URL(base);
39
- if (!isLoopbackHost(parsed.hostname)) {
40
- const err = new Error(`Insecure HTTP connection with authentication token to non-loopback host '${parsed.hostname}' is prohibited. Use HTTPS or pass --allow-insecure-http to override.`);
41
- err.code = "INSECURE_TRANSPORT";
42
- throw err;
43
- }
44
- }
45
- catch (e) {
46
- if (e.code === "INSECURE_TRANSPORT") {
47
- throw e;
48
- }
49
- }
50
- }
51
- }
52
- function buildHeaders(token) {
53
- const headers = {
54
- Accept: "application/json",
55
- };
56
- if (token && token.trim()) {
57
- headers.Authorization = `Bearer ${token.trim()}`;
58
- }
59
- return headers;
60
- }
61
- /**
62
- * 探测指定远端 ActionDock 服务的健康状态与网络延迟。
2
+ * 远端 Profile 客户端聚合入口。
3
+ *
4
+ * 历史上全部端点函数集中于单一 client.ts(约 950 行),现按域拆分为
5
+ * 单一职责模块,此处仅保留聚合 re-export,导入路径 ./client 与
6
+ * @actiondock/core 的公共导出面保持完全兼容。
63
7
  *
64
- * @param serverUrl 目标服务端地址
65
- * @param token 鉴权 Token(可选)
66
- * @param timeoutMs 探测超时时间(默认 5000ms)
67
- * @param options 传输与安全控制选项
8
+ * 模块划分:
9
+ * - client-transport:传输层(鉴权头、明文校验、协议回退)
10
+ * - client-query:共享请求与查询构造层
11
+ * - client-health:健康检查
12
+ * - client-actions:执行与 Action 查询
13
+ * - client-playbooks:Playbook 规程查询
14
+ * - client-runs:运行记录管理
15
+ * - client-state:状态存储管理
16
+ * - client-config:配置管理
68
17
  */
69
- export async function checkRemoteHealth(serverUrl, token, timeoutMs = 5000, options) {
70
- const startTime = Date.now();
71
- let timer;
72
- try {
73
- assertSecureTransport(serverUrl, token, {
74
- allowInsecureHttp: options?.allowInsecureHttp,
75
- insecure: options?.insecure,
76
- });
77
- const base = normalizeServerUrl(serverUrl);
78
- const v2Url = `${base}/api/v2/health`;
79
- const controller = new AbortController();
80
- timer = setTimeout(() => controller.abort(), timeoutMs);
81
- const fetchInit = {
82
- method: "GET",
83
- headers: buildHeaders(token),
84
- signal: controller.signal,
85
- };
86
- if (options?.dispatcher) {
87
- fetchInit.dispatcher = options.dispatcher;
88
- }
89
- else if (options?.insecure) {
90
- fetchInit.dispatcher = getInsecureDispatcher();
91
- }
92
- let res = await fetch(v2Url, fetchInit);
93
- if (res.status === 404) {
94
- try {
95
- const v1Res = await fetch(`${base}/api/v1/health`, fetchInit);
96
- if (v1Res.ok || v1Res.status !== 404) {
97
- res = v1Res;
98
- }
99
- }
100
- catch { }
101
- }
102
- const latencyMs = Date.now() - startTime;
103
- if (!res.ok) {
104
- const text = await res.text().catch(() => "");
105
- return {
106
- ok: false,
107
- latencyMs,
108
- error: `Server responded with status ${res.status}: ${text || res.statusText}`,
109
- };
110
- }
111
- const data = (await res.json().catch(() => ({})));
112
- return {
113
- ok: true,
114
- status: data.status || "healthy",
115
- version: data.version,
116
- uptime: data.uptime,
117
- latencyMs,
118
- };
119
- }
120
- catch (err) {
121
- const latencyMs = Date.now() - startTime;
122
- return {
123
- ok: false,
124
- latencyMs,
125
- error: err.name === "AbortError" ? "Connection timed out" : err.message,
126
- };
127
- }
128
- finally {
129
- if (timer !== undefined) {
130
- clearTimeout(timer);
131
- }
132
- }
133
- }
134
- export async function executeRemoteAction(serverUrl, actionId, input = {}, configOverridesOrOptions, tokenArg) {
135
- // Parse options / backwards compatibility
136
- let configOverrides;
137
- let token = tokenArg;
138
- let timeoutMs;
139
- let signal;
140
- let isAsync = false;
141
- let requestId;
142
- let allowInsecureHttp;
143
- let insecure;
144
- let dispatcher;
145
- if (configOverridesOrOptions && typeof configOverridesOrOptions === "object") {
146
- if ("token" in configOverridesOrOptions ||
147
- "timeoutMs" in configOverridesOrOptions ||
148
- "signal" in configOverridesOrOptions ||
149
- "async" in configOverridesOrOptions ||
150
- "requestId" in configOverridesOrOptions ||
151
- "configOverrides" in configOverridesOrOptions ||
152
- "allowInsecureHttp" in configOverridesOrOptions ||
153
- "insecure" in configOverridesOrOptions ||
154
- "dispatcher" in configOverridesOrOptions) {
155
- const opts = configOverridesOrOptions;
156
- configOverrides = opts.configOverrides;
157
- token = opts.token ?? tokenArg;
158
- timeoutMs = opts.timeoutMs;
159
- signal = opts.signal;
160
- isAsync = Boolean(opts.async);
161
- requestId = opts.requestId;
162
- allowInsecureHttp = opts.allowInsecureHttp;
163
- insecure = opts.insecure;
164
- dispatcher = opts.dispatcher;
165
- }
166
- else {
167
- configOverrides = configOverridesOrOptions;
168
- }
169
- }
170
- assertSecureTransport(serverUrl, token, { allowInsecureHttp, insecure });
171
- const base = normalizeServerUrl(serverUrl);
172
- const v2Url = `${base}/api/v2/actions/${encodeURIComponent(actionId)}/run`;
173
- const executionPayload = {};
174
- if (isAsync) {
175
- executionPayload.mode = "async";
176
- }
177
- if (typeof timeoutMs === "number" && timeoutMs > 0) {
178
- executionPayload.timeoutMs = timeoutMs;
179
- }
180
- if (requestId) {
181
- executionPayload.requestId = requestId;
182
- }
183
- // 组合外部取消信号与本地超时守卫:服务端僵死时仍能在 timeoutMs 内本地中断,避免永久挂起
184
- let timeoutTimer;
185
- let localTimedOut = false;
186
- try {
187
- const headers = {
188
- ...buildHeaders(token),
189
- "Content-Type": "application/json",
190
- };
191
- if (requestId) {
192
- headers["Idempotency-Key"] = requestId;
193
- headers["x-request-id"] = requestId;
194
- }
195
- const reqBody = JSON.stringify({
196
- input,
197
- config: configOverrides,
198
- execution: Object.keys(executionPayload).length > 0 ? executionPayload : undefined,
199
- });
200
- const controller = new AbortController();
201
- const onExternalAbort = () => controller.abort(signal?.reason);
202
- if (signal) {
203
- if (signal.aborted) {
204
- controller.abort(signal.reason);
205
- }
206
- else {
207
- signal.addEventListener("abort", onExternalAbort, { once: true });
208
- }
209
- }
210
- if (typeof timeoutMs === "number" && timeoutMs > 0) {
211
- timeoutTimer = setTimeout(() => {
212
- localTimedOut = true;
213
- controller.abort();
214
- }, timeoutMs);
215
- }
216
- const fetchInit = {
217
- method: "POST",
218
- headers,
219
- body: reqBody,
220
- signal: controller.signal,
221
- };
222
- if (dispatcher) {
223
- fetchInit.dispatcher = dispatcher;
224
- }
225
- else if (insecure) {
226
- fetchInit.dispatcher = getInsecureDispatcher();
227
- }
228
- let res;
229
- try {
230
- res = await fetch(v2Url, fetchInit);
231
- if (res.status === 404) {
232
- try {
233
- const v1Res = await fetch(`${base}/api/v1/actions/${encodeURIComponent(actionId)}/run`, fetchInit);
234
- if (v1Res.ok || v1Res.status !== 404) {
235
- res = v1Res;
236
- }
237
- }
238
- catch { }
239
- }
240
- }
241
- finally {
242
- if (timeoutTimer !== undefined) {
243
- clearTimeout(timeoutTimer);
244
- }
245
- if (signal) {
246
- signal.removeEventListener("abort", onExternalAbort);
247
- }
248
- }
249
- const data = (await res.json().catch(() => null));
250
- if (data && typeof data === "object" && typeof data.ok === "boolean") {
251
- return data;
252
- }
253
- if (!res.ok) {
254
- // 错误信封严禁伪造 runId:与任何真实运行无关的标识会让调用方查询永远 not_found
255
- return {
256
- ok: false,
257
- runId: "",
258
- error: {
259
- code: res.status === 401 ? "UNAUTHORIZED" : "REMOTE_EXECUTION_FAILED",
260
- message: `Remote server HTTP ${res.status}: ${res.statusText}`,
261
- details: data,
262
- },
263
- };
264
- }
265
- return {
266
- ok: true,
267
- runId: randomUUID(),
268
- data,
269
- };
270
- }
271
- catch (err) {
272
- // 本地超时守卫触发时归类为超时;外部信号中止时归类为取消
273
- if (localTimedOut) {
274
- return {
275
- ok: false,
276
- runId: "",
277
- error: {
278
- code: ACTION_TIMEOUT,
279
- message: `Remote execution exceeded local timeout of ${timeoutMs}ms`,
280
- },
281
- };
282
- }
283
- if (err.name === "AbortError" || signal?.aborted) {
284
- return {
285
- ok: false,
286
- runId: "",
287
- error: {
288
- code: ACTION_CANCELLED,
289
- message: "Action execution was cancelled",
290
- },
291
- };
292
- }
293
- return {
294
- ok: false,
295
- runId: "",
296
- error: {
297
- code: NETWORK_ERROR,
298
- message: `Failed to connect to remote ActionDock server at ${serverUrl}: ${err.message}`,
299
- },
300
- };
301
- }
302
- }
303
- async function fetchRemoteJson(serverUrl, path, token, options = {}) {
304
- assertSecureTransport(serverUrl, token, {
305
- allowInsecureHttp: options.allowInsecureHttp,
306
- insecure: options.insecure,
307
- });
308
- const base = normalizeServerUrl(serverUrl);
309
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
310
- const url = `${base}${normalizedPath}`;
311
- const method = options.method || "GET";
312
- const headers = {
313
- ...buildHeaders(token),
314
- };
315
- if (options.body !== undefined) {
316
- headers["Content-Type"] = "application/json";
317
- }
318
- const fetchInit = {
319
- method,
320
- headers,
321
- body: options.body !== undefined ? JSON.stringify(options.body) : undefined,
322
- };
323
- if (options.dispatcher) {
324
- fetchInit.dispatcher = options.dispatcher;
325
- }
326
- else if (options.insecure) {
327
- fetchInit.dispatcher = getInsecureDispatcher();
328
- }
329
- let res = await fetch(url, fetchInit);
330
- if (res.status === 404 && normalizedPath.startsWith("/api/v2/")) {
331
- const v1Path = normalizedPath.replace("/api/v2/", "/api/v1/");
332
- try {
333
- const v1Res = await fetch(`${base}${v1Path}`, fetchInit);
334
- if (v1Res.ok || v1Res.status !== 404) {
335
- res = v1Res;
336
- }
337
- }
338
- catch { }
339
- }
340
- const data = (await res.json().catch(() => ({})));
341
- if (!res.ok || (options.method === "POST" && data && data.ok === false)) {
342
- const errorPrefix = options.errorPrefix || "Remote request failed";
343
- const msg = data?.error?.message || `${errorPrefix} (${res.status}): ${res.statusText}`;
344
- const err = new Error(msg);
345
- if (data?.error?.code) {
346
- err.code = data.error.code;
347
- }
348
- err.status = res.status;
349
- err.errorData = data?.error;
350
- err.details = data?.error?.details ?? data?.error;
351
- throw err;
352
- }
353
- return data;
354
- }
355
- export async function fetchRemoteRun(serverUrl, runId, token, options) {
356
- return fetchRemoteJson(serverUrl, `/api/v2/runs/${encodeURIComponent(runId)}`, token, {
357
- errorPrefix: `Failed to fetch remote run '${runId}'`,
358
- allowInsecureHttp: options?.allowInsecureHttp,
359
- insecure: options?.insecure,
360
- dispatcher: options?.dispatcher,
361
- });
362
- }
363
- export async function cancelRemoteRun(serverUrl, runId, token, reason, options) {
364
- return fetchRemoteJson(serverUrl, `/api/v2/runs/${encodeURIComponent(runId)}/cancel`, token, {
365
- method: "POST",
366
- body: { reason },
367
- errorPrefix: `Failed to cancel remote run '${runId}'`,
368
- allowInsecureHttp: options?.allowInsecureHttp,
369
- insecure: options?.insecure,
370
- dispatcher: options?.dispatcher,
371
- });
372
- }
373
- export async function fetchRemoteActions(serverUrl, token, intent, options) {
374
- const query = intent ? `?intent=${encodeURIComponent(intent)}` : "";
375
- return fetchRemoteJson(serverUrl, `/api/v2/actions${query}`, token, {
376
- errorPrefix: "Failed to fetch remote actions",
377
- allowInsecureHttp: options?.allowInsecureHttp,
378
- insecure: options?.insecure,
379
- dispatcher: options?.dispatcher,
380
- });
381
- }
382
- export async function fetchRemoteActionShow(serverUrl, actionId, token, options) {
383
- return fetchRemoteJson(serverUrl, `/api/v2/actions/${encodeURIComponent(actionId)}`, token, {
384
- errorPrefix: `Failed to fetch remote action '${actionId}'`,
385
- allowInsecureHttp: options?.allowInsecureHttp,
386
- insecure: options?.insecure,
387
- dispatcher: options?.dispatcher,
388
- });
389
- }
390
- export async function fetchRemoteInfo(serverUrl, token, options) {
391
- const params = new URLSearchParams();
392
- if (options?.intent)
393
- params.set("intent", options.intent);
394
- if (options?.package)
395
- params.set("package", options.package);
396
- if (options?.tree)
397
- params.set("tree", "true");
398
- const qs = params.toString() ? `?${params.toString()}` : "";
399
- return fetchRemoteJson(serverUrl, `/api/v2/info${qs}`, token, {
400
- errorPrefix: "Failed to fetch remote info",
401
- allowInsecureHttp: options?.allowInsecureHttp,
402
- insecure: options?.insecure,
403
- dispatcher: options?.dispatcher,
404
- });
405
- }
406
- export async function fetchRemoteDoctor(serverUrl, token, targetPackage, options) {
407
- const query = targetPackage ? `?package=${encodeURIComponent(targetPackage)}` : "";
408
- return fetchRemoteJson(serverUrl, `/api/v2/doctor${query}`, token, {
409
- errorPrefix: "Failed to fetch remote doctor report",
410
- allowInsecureHttp: options?.allowInsecureHttp,
411
- insecure: options?.insecure,
412
- dispatcher: options?.dispatcher,
413
- });
414
- }
415
- export async function fetchRemotePlaybooks(serverUrl, token, options) {
416
- const params = new URLSearchParams();
417
- if (options?.intent)
418
- params.set("intent", options.intent);
419
- if (options?.package)
420
- params.set("package", options.package);
421
- const qs = params.toString() ? `?${params.toString()}` : "";
422
- return fetchRemoteJson(serverUrl, `/api/v2/playbooks${qs}`, token, {
423
- errorPrefix: "Failed to fetch remote playbooks",
424
- allowInsecureHttp: options?.allowInsecureHttp,
425
- insecure: options?.insecure,
426
- dispatcher: options?.dispatcher,
427
- });
428
- }
429
- export async function fetchRemotePlaybookShow(serverUrlOrPlaybookId, playbookIdOrToken, tokenOrOptions, optionsArg) {
430
- let serverUrl = serverUrlOrPlaybookId;
431
- let playbookId = playbookIdOrToken || "";
432
- let token;
433
- let options = optionsArg;
434
- if (typeof tokenOrOptions === "object") {
435
- options = tokenOrOptions;
436
- }
437
- else if (typeof tokenOrOptions === "string") {
438
- token = tokenOrOptions;
439
- }
440
- return fetchRemoteJson(serverUrl, `/api/v2/playbooks/${encodeURIComponent(playbookId)}`, token, {
441
- errorPrefix: `Failed to fetch remote playbook '${playbookId}'`,
442
- allowInsecureHttp: options?.allowInsecureHttp,
443
- insecure: options?.insecure,
444
- dispatcher: options?.dispatcher,
445
- });
446
- }
447
- export async function fetchRemoteRuns(serverUrl, token, options) {
448
- const params = new URLSearchParams();
449
- if (options?.status)
450
- params.set("status", options.status);
451
- if (options?.actionId)
452
- params.set("actionId", options.actionId);
453
- if (options?.packageId)
454
- params.set("packageId", options.packageId);
455
- if (options?.intent)
456
- params.set("intent", options.intent);
457
- if (options?.limit)
458
- params.set("limit", String(options.limit));
459
- const qs = params.toString() ? `?${params.toString()}` : "";
460
- return fetchRemoteJson(serverUrl, `/api/v2/runs${qs}`, token, {
461
- errorPrefix: "Failed to fetch remote runs",
462
- allowInsecureHttp: options?.allowInsecureHttp,
463
- insecure: options?.insecure,
464
- dispatcher: options?.dispatcher,
465
- });
466
- }
467
- export async function clearRemoteRuns(serverUrl, token, options) {
468
- return fetchRemoteJson(serverUrl, "/api/v2/runs/clear", token, {
469
- method: "POST",
470
- body: options || {},
471
- errorPrefix: "Failed to clear remote runs",
472
- allowInsecureHttp: options?.allowInsecureHttp,
473
- insecure: options?.insecure,
474
- dispatcher: options?.dispatcher,
475
- });
476
- }
477
- export async function fetchRemoteStateList(serverUrl, token, options) {
478
- const params = new URLSearchParams();
479
- if (options?.package)
480
- params.set("package", options.package);
481
- if (options?.action)
482
- params.set("action", options.action);
483
- if (options?.namespace !== undefined)
484
- params.set("namespace", options.namespace);
485
- if (options?.prefix)
486
- params.set("prefix", options.prefix);
487
- const qs = params.toString() ? `?${params.toString()}` : "";
488
- return fetchRemoteJson(serverUrl, `/api/v2/state${qs}`, token, {
489
- errorPrefix: "Failed to list remote state keys",
490
- allowInsecureHttp: options?.allowInsecureHttp,
491
- insecure: options?.insecure,
492
- dispatcher: options?.dispatcher,
493
- });
494
- }
495
- export async function getRemoteStateKey(serverUrl, key, token, options) {
496
- const params = new URLSearchParams();
497
- if (options?.package)
498
- params.set("package", options.package);
499
- if (options?.action)
500
- params.set("action", options.action);
501
- if (options?.namespace !== undefined)
502
- params.set("namespace", options.namespace);
503
- const qs = params.toString() ? `?${params.toString()}` : "";
504
- return fetchRemoteJson(serverUrl, `/api/v2/state/${encodeURIComponent(key)}${qs}`, token, {
505
- errorPrefix: `Failed to fetch remote state key '${key}'`,
506
- allowInsecureHttp: options?.allowInsecureHttp,
507
- insecure: options?.insecure,
508
- dispatcher: options?.dispatcher,
509
- });
510
- }
511
- export async function setRemoteStateKey(serverUrl, key, value, token, options) {
512
- return fetchRemoteJson(serverUrl, `/api/v2/state/${encodeURIComponent(key)}`, token, {
513
- method: "PUT",
514
- body: {
515
- value,
516
- package: options?.package,
517
- action: options?.action,
518
- namespace: options?.namespace,
519
- ttl: options?.ttl,
520
- },
521
- errorPrefix: `Failed to set remote state key '${key}'`,
522
- allowInsecureHttp: options?.allowInsecureHttp,
523
- insecure: options?.insecure,
524
- dispatcher: options?.dispatcher,
525
- });
526
- }
527
- export async function deleteRemoteStateKey(serverUrl, key, token, options) {
528
- const params = new URLSearchParams();
529
- if (options?.package)
530
- params.set("package", options.package);
531
- if (options?.action)
532
- params.set("action", options.action);
533
- if (options?.namespace !== undefined)
534
- params.set("namespace", options.namespace);
535
- const qs = params.toString() ? `?${params.toString()}` : "";
536
- return fetchRemoteJson(serverUrl, `/api/v2/state/${encodeURIComponent(key)}${qs}`, token, {
537
- method: "DELETE",
538
- errorPrefix: `Failed to delete remote state key '${key}'`,
539
- allowInsecureHttp: options?.allowInsecureHttp,
540
- insecure: options?.insecure,
541
- dispatcher: options?.dispatcher,
542
- });
543
- }
544
- export async function clearRemoteState(serverUrl, token, options) {
545
- return fetchRemoteJson(serverUrl, "/api/v2/state/clear", token, {
546
- method: "POST",
547
- body: options || {},
548
- errorPrefix: "Failed to clear remote state",
549
- allowInsecureHttp: options?.allowInsecureHttp,
550
- insecure: options?.insecure,
551
- dispatcher: options?.dispatcher,
552
- });
553
- }
554
- export async function fetchRemoteConfig(serverUrl, token, packageId, options) {
555
- const query = packageId ? `?package=${encodeURIComponent(packageId)}` : "";
556
- return fetchRemoteJson(serverUrl, `/api/v2/config${query}`, token, {
557
- errorPrefix: "Failed to fetch remote config",
558
- allowInsecureHttp: options?.allowInsecureHttp,
559
- insecure: options?.insecure,
560
- dispatcher: options?.dispatcher,
561
- });
562
- }
563
- export async function setRemoteConfig(serverUrl, key, value, token, packageId, options) {
564
- return fetchRemoteJson(serverUrl, "/api/v2/config", token, {
565
- method: "PUT",
566
- body: { key, value, package: packageId },
567
- errorPrefix: `Failed to set remote config '${key}'`,
568
- allowInsecureHttp: options?.allowInsecureHttp,
569
- insecure: options?.insecure,
570
- dispatcher: options?.dispatcher,
571
- });
572
- }
573
- export async function deleteRemoteConfig(serverUrl, key, token, packageId, options) {
574
- const query = packageId ? `?package=${encodeURIComponent(packageId)}` : "";
575
- return fetchRemoteJson(serverUrl, `/api/v2/config/${encodeURIComponent(key)}${query}`, token, {
576
- method: "DELETE",
577
- errorPrefix: `Failed to delete remote config '${key}'`,
578
- allowInsecureHttp: options?.allowInsecureHttp,
579
- insecure: options?.insecure,
580
- dispatcher: options?.dispatcher,
581
- });
582
- }
583
- export async function fetchRemoteConfigEnv(serverUrl, token, packageId, options) {
584
- const query = packageId ? `?package=${encodeURIComponent(packageId)}` : "";
585
- return fetchRemoteJson(serverUrl, `/api/v2/config/env${query}`, token, {
586
- errorPrefix: "Failed to fetch remote config env checks",
587
- allowInsecureHttp: options?.allowInsecureHttp,
588
- insecure: options?.insecure,
589
- dispatcher: options?.dispatcher,
590
- });
591
- }
18
+ // 传输层与通用类型
19
+ export { assertSecureTransport, createRemoteFetch, fetchWithProtocolFallback, listProtocolRouteCandidates, } from "./client-transport.js";
20
+ // 健康检查
21
+ export { checkRemoteHealth } from "./client-health.js";
22
+ // 执行与 Action 查询
23
+ export { executeRemoteAction, fetchRemoteActionShow, fetchRemoteActions, fetchRemoteDoctor, fetchRemoteInfo, } from "./client-actions.js";
24
+ // Playbook 规程查询
25
+ export { fetchRemotePlaybookShow, fetchRemotePlaybooks } from "./client-playbooks.js";
26
+ // 运行记录管理
27
+ export { cancelRemoteRun, clearRemoteRuns, fetchRemoteRun, fetchRemoteRuns, } from "./client-runs.js";
28
+ // 状态存储管理
29
+ export { clearRemoteState, deleteRemoteStateKey, fetchRemoteStateList, getRemoteStateKey, setRemoteStateKey, } from "./client-state.js";
30
+ // 配置管理
31
+ export { deleteRemoteConfig, fetchRemoteConfig, fetchRemoteConfigEnv, setRemoteConfig, } from "./client-config.js";
@@ -1,7 +1,7 @@
1
1
  import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { toSnakeUpperCase } from "../runtime/env.js";
4
- import { isLoopbackHost } from "../server/security.js";
4
+ import { isLoopbackHost } from "../utils/net.js";
5
5
  import { getActionDockHome } from "../utils/index.js";
6
6
  const PROFILE_NAME_REGEX = /^[a-zA-Z0-9_\-\.]+$/;
7
7
  /**
@@ -9,17 +9,17 @@ export interface EnsureDependencyClosureOptions {
9
9
  customHome?: string;
10
10
  }
11
11
  export interface DependencyClosureResult {
12
- /** 成功执行依赖安装或更新的项目根路径列表 */
12
+ /** 成功执行依赖预装的项目根路径列表(默认实现下永远为空) */
13
13
  installed: string[];
14
14
  /** 无法在注册表中解析包引用的警告列表 */
15
15
  warnings: string[];
16
16
  }
17
17
  /**
18
- * 广度优先遍历 (BFS) uses 声明的跨包依赖闭包,对涉及的每个项目包逐一执行依赖预装(ensureProjectDependencies)。
19
- * 内部已尊重 ACTIONDOCK_AUTO_INSTALL=false 环境变量。
18
+ * 广度优先遍历 (BFS) uses 声明的跨包依赖闭包,对涉及的每个项目包逐一调用依赖预装回调。
19
+ * 默认预装回调为明确的不操作(ActionDock 2.0 不做运行时安装);可通过 opts.ensure 注入自定义实现。
20
20
  *
21
21
  * @param roots 根项目目录列表
22
22
  * @param opts 选项参数
23
- * @returns 安装成功的路径列表及警告信息
23
+ * @returns 预装成功的路径列表及警告信息
24
24
  */
25
25
  export declare function ensureDependencyClosure(roots: string[], opts?: EnsureDependencyClosureOptions): Promise<DependencyClosureResult>;
@@ -1,15 +1,21 @@
1
1
  import { resolve } from "node:path";
2
2
  import { ActionResolver } from "../catalog/action-resolver.js";
3
3
  import { resolvePackageRoot } from "../registry/registry.js";
4
- import { ensureProjectDependencies } from "./loader.js";
5
4
  import { loadManifest } from "./manifest.js";
6
5
  /**
7
- * 广度优先遍历 (BFS) uses 声明的跨包依赖闭包,对涉及的每个项目包逐一执行依赖预装(ensureProjectDependencies)。
8
- * 内部已尊重 ACTIONDOCK_AUTO_INSTALL=false 环境变量。
6
+ * 依赖预装的默认实现:明确的不操作。
7
+ * ActionDock 2.0 移除了运行时静默在线安装,保留该签名仅为闭包遍历提供注入点(便于单测 Mock 与自定义扩展)。
8
+ */
9
+ function noopEnsure() {
10
+ return false;
11
+ }
12
+ /**
13
+ * 广度优先遍历 (BFS) uses 声明的跨包依赖闭包,对涉及的每个项目包逐一调用依赖预装回调。
14
+ * 默认预装回调为明确的不操作(ActionDock 2.0 不做运行时安装);可通过 opts.ensure 注入自定义实现。
9
15
  *
10
16
  * @param roots 根项目目录列表
11
17
  * @param opts 选项参数
12
- * @returns 安装成功的路径列表及警告信息
18
+ * @returns 预装成功的路径列表及警告信息
13
19
  */
14
20
  export async function ensureDependencyClosure(roots, opts = {}) {
15
21
  const seen = new Set();
@@ -24,7 +30,7 @@ export async function ensureDependencyClosure(roots, opts = {}) {
24
30
  if (seen.has(root))
25
31
  continue;
26
32
  seen.add(root);
27
- const ensureFn = opts.ensure ?? ensureProjectDependencies;
33
+ const ensureFn = opts.ensure ?? noopEnsure;
28
34
  const wasInstalled = await ensureFn(root);
29
35
  if (wasInstalled) {
30
36
  installed.push(root);