@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.
- package/dist/app/app.d.ts +14 -1
- package/dist/app/app.js +88 -215
- package/dist/app/static-index.d.ts +39 -0
- package/dist/app/static-index.js +164 -0
- package/dist/app/types.d.ts +5 -0
- package/dist/catalog/action-index.js +6 -4
- package/dist/catalog/package-catalog.js +2 -1
- package/dist/doctor/checks/index.d.ts +5 -0
- package/dist/doctor/checks/index.js +5 -0
- package/dist/doctor/checks/project-locate.d.ts +6 -0
- package/dist/doctor/checks/project-locate.js +36 -0
- package/dist/doctor/checks/project.d.ts +6 -0
- package/dist/doctor/checks/project.js +383 -0
- package/dist/doctor/checks/registry.d.ts +13 -0
- package/dist/doctor/checks/registry.js +207 -0
- package/dist/doctor/checks/runtime.d.ts +13 -0
- package/dist/doctor/checks/runtime.js +90 -0
- package/dist/doctor/checks/storage.d.ts +5 -0
- package/dist/doctor/checks/storage.js +34 -0
- package/dist/doctor/context.d.ts +35 -0
- package/dist/doctor/context.js +11 -0
- package/dist/doctor/doctor.d.ts +5 -0
- package/dist/doctor/doctor.js +33 -602
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +2 -0
- package/dist/execution/service.js +14 -9
- package/dist/host/host.d.ts +33 -0
- package/dist/host/host.js +222 -362
- package/dist/host/routing.d.ts +92 -0
- package/dist/host/routing.js +238 -0
- package/dist/host/types.d.ts +8 -0
- package/dist/ipc/host.js +38 -0
- package/dist/platform/types.d.ts +7 -0
- package/dist/process/control-arbiter.d.ts +107 -0
- package/dist/process/control-arbiter.js +251 -0
- package/dist/process/diagnostics-sink.d.ts +26 -0
- package/dist/process/diagnostics-sink.js +35 -0
- package/dist/process/index.d.ts +7 -0
- package/dist/process/index.js +7 -0
- package/dist/process/input-dispatcher.d.ts +88 -0
- package/dist/process/input-dispatcher.js +240 -0
- package/dist/process/managed-record.d.ts +78 -0
- package/dist/process/managed-record.js +1 -0
- package/dist/process/process-manager.d.ts +15 -56
- package/dist/process/process-manager.js +119 -707
- package/dist/process/reservation-table.d.ts +39 -0
- package/dist/process/reservation-table.js +80 -0
- package/dist/process/run-executor.d.ts +16 -0
- package/dist/process/run-executor.js +155 -0
- package/dist/process/terminal-output-cache.d.ts +66 -0
- package/dist/process/terminal-output-cache.js +132 -0
- package/dist/profile/client-actions.d.ts +56 -0
- package/dist/profile/client-actions.js +215 -0
- package/dist/profile/client-config.d.ts +20 -0
- package/dist/profile/client-config.js +51 -0
- package/dist/profile/client-health.d.ts +14 -0
- package/dist/profile/client-health.js +68 -0
- package/dist/profile/client-playbooks.d.ts +19 -0
- package/dist/profile/client-playbooks.js +36 -0
- package/dist/profile/client-query.d.ts +30 -0
- package/dist/profile/client-query.js +70 -0
- package/dist/profile/client-runs.d.ts +42 -0
- package/dist/profile/client-runs.js +58 -0
- package/dist/profile/client-state.d.ts +56 -0
- package/dist/profile/client-state.js +83 -0
- package/dist/profile/client-transport.d.ts +61 -0
- package/dist/profile/client-transport.js +155 -0
- package/dist/profile/client.d.ts +23 -142
- package/dist/profile/client.js +28 -588
- package/dist/profile/manager.js +1 -1
- package/dist/project/closure.d.ts +4 -4
- package/dist/project/closure.js +11 -5
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +0 -25
- package/dist/project/loader.js +1 -154
- package/dist/project/transactions.d.ts +12 -14
- package/dist/project/transactions.js +60 -836
- package/dist/registry/registry.js +6 -4
- package/dist/registry/resolve.js +1 -1
- package/dist/runtime/action-registry.d.ts +45 -0
- package/dist/runtime/action-registry.js +108 -0
- package/dist/runtime/clock.d.ts +5 -17
- package/dist/runtime/clock.js +5 -15
- package/dist/runtime/context.d.ts +3 -0
- package/dist/runtime/context.js +17 -56
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/package-runner-factory.d.ts +82 -0
- package/dist/runtime/package-runner-factory.js +186 -0
- package/dist/runtime/run-persistence.d.ts +85 -0
- package/dist/runtime/run-persistence.js +111 -0
- package/dist/runtime/runner.d.ts +23 -33
- package/dist/runtime/runner.js +92 -286
- package/dist/runtime/standalone.d.ts +11 -1
- package/dist/runtime/standalone.js +137 -25
- package/dist/server/dispatcher.d.ts +8 -3
- package/dist/server/dispatcher.js +16 -40
- package/dist/server/routes/runs.js +6 -4
- package/dist/server/security.d.ts +1 -7
- package/dist/server/security.js +2 -13
- package/dist/storage/clock.d.ts +25 -0
- package/dist/storage/clock.js +23 -0
- package/dist/storage/data-dir-lock.d.ts +3 -36
- package/dist/storage/data-dir-lock.js +48 -881
- package/dist/storage/index.d.ts +8 -1
- package/dist/storage/index.js +8 -2
- package/dist/storage/lazy.js +1 -0
- package/dist/storage/lock-core.d.ts +162 -0
- package/dist/storage/lock-core.js +885 -0
- package/dist/storage/sqlite.d.ts +19 -6
- package/dist/storage/sqlite.js +81 -89
- package/dist/storage/types.d.ts +27 -5
- package/dist/storage/types.js +21 -0
- package/dist/storage/utils.d.ts +22 -0
- package/dist/storage/utils.js +34 -0
- package/dist/target/local.d.ts +1 -0
- package/dist/target/local.js +23 -17
- package/dist/target/remote-errors.d.ts +21 -0
- package/dist/target/remote-errors.js +51 -0
- package/dist/target/remote-polling.d.ts +35 -0
- package/dist/target/remote-polling.js +104 -0
- package/dist/target/remote.d.ts +4 -0
- package/dist/target/remote.js +108 -301
- package/dist/target/sse-parser.d.ts +35 -0
- package/dist/target/sse-parser.js +163 -0
- package/dist/target/target.js +2 -0
- package/dist/target/types.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/net.d.ts +10 -0
- package/dist/utils/net.js +16 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/profile/client.js
CHANGED
|
@@ -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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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";
|
package/dist/profile/manager.js
CHANGED
|
@@ -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 "../
|
|
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
|
|
19
|
-
*
|
|
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>;
|
package/dist/project/closure.js
CHANGED
|
@@ -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
|
-
*
|
|
8
|
-
*
|
|
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 ??
|
|
33
|
+
const ensureFn = opts.ensure ?? noopEnsure;
|
|
28
34
|
const wasInstalled = await ensureFn(root);
|
|
29
35
|
if (wasInstalled) {
|
|
30
36
|
installed.push(root);
|