@actiondock/core 2.6.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -68
- package/dist/catalog/action-catalog.d.ts +56 -0
- package/dist/catalog/action-catalog.js +202 -0
- package/dist/catalog/discovery.d.ts +60 -0
- package/dist/catalog/discovery.js +119 -0
- package/dist/catalog/graph.d.ts +190 -0
- package/dist/catalog/graph.js +589 -0
- package/dist/catalog/index.d.ts +5 -5
- package/dist/catalog/index.js +5 -5
- package/dist/catalog/resolve-action.d.ts +43 -0
- package/dist/catalog/resolve-action.js +119 -0
- package/dist/catalog/resolve-playbook.d.ts +26 -0
- package/dist/catalog/resolve-playbook.js +114 -0
- package/dist/doctor/checks/project.js +27 -8
- package/dist/doctor/checks/registry.js +2 -2
- package/dist/doctor/checks/runtime.js +34 -1
- package/dist/errors.d.ts +122 -10
- package/dist/errors.js +123 -10
- package/dist/execution/service.d.ts +18 -16
- package/dist/execution/service.js +183 -252
- package/dist/execution/types.d.ts +25 -69
- package/dist/execution/types.js +2 -1
- package/dist/filter/intent.d.ts +8 -9
- package/dist/filter/intent.js +49 -10
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.js +4 -0
- package/dist/host/host.d.ts +74 -32
- package/dist/host/host.js +585 -336
- package/dist/host/routing.d.ts +15 -48
- package/dist/host/routing.js +90 -153
- package/dist/host/types.d.ts +50 -17
- package/dist/index.d.ts +21 -22
- package/dist/index.js +19 -21
- package/dist/input/advice.d.ts +104 -0
- package/dist/input/advice.js +716 -0
- package/dist/input/describe.d.ts +106 -0
- package/dist/input/describe.js +176 -0
- package/dist/input/file-input.d.ts +54 -0
- package/dist/input/file-input.js +124 -0
- package/dist/input/flat-decode.d.ts +11 -0
- package/dist/input/flat-decode.js +13 -0
- package/dist/input/flat-errors.d.ts +71 -0
- package/dist/input/flat-errors.js +87 -0
- package/dist/input/flat-materializer.d.ts +29 -0
- package/dist/input/flat-materializer.js +177 -0
- package/dist/input/flat-parser.d.ts +50 -0
- package/dist/input/flat-parser.js +169 -0
- package/dist/input/flat-predicates.d.ts +34 -0
- package/dist/input/flat-predicates.js +50 -0
- package/dist/input/index.d.ts +14 -0
- package/dist/input/index.js +14 -0
- package/dist/input/input-resolver.d.ts +63 -0
- package/dist/input/input-resolver.js +254 -0
- package/dist/input/json-depth-scanner.d.ts +17 -0
- package/dist/input/json-depth-scanner.js +49 -0
- package/dist/input/metadata.d.ts +99 -0
- package/dist/input/metadata.js +99 -0
- package/dist/input/stdin-input.d.ts +26 -0
- package/dist/input/stdin-input.js +125 -0
- package/dist/input/utf8.d.ts +19 -0
- package/dist/input/utf8.js +36 -0
- package/dist/input/validation-mapper.d.ts +27 -0
- package/dist/input/validation-mapper.js +144 -0
- package/dist/invocation/index.d.ts +2 -0
- package/dist/invocation/index.js +2 -0
- package/dist/invocation/policy.d.ts +157 -0
- package/dist/invocation/policy.js +231 -0
- package/dist/invocation/types.d.ts +172 -0
- package/dist/invocation/types.js +97 -0
- package/dist/ipc/diagnostic.d.ts +0 -12
- package/dist/ipc/diagnostic.js +0 -21
- package/dist/ipc/host.d.ts +4 -4
- package/dist/ipc/host.js +44 -47
- package/dist/ipc/index.d.ts +1 -1
- package/dist/ipc/index.js +1 -1
- package/dist/ipc/service.d.ts +40 -0
- package/dist/ipc/service.js +349 -0
- package/dist/ipc/types.d.ts +21 -15
- package/dist/json/index.d.ts +1 -0
- package/dist/json/index.js +1 -0
- package/dist/json/value-validator.d.ts +88 -0
- package/dist/json/value-validator.js +330 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/module-loader.d.ts +63 -0
- package/dist/node/module-loader.js +112 -0
- package/dist/package/index.d.ts +23 -0
- package/dist/package/index.js +18 -0
- package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
- package/dist/{app/app.js → package/runtime.js} +140 -95
- package/dist/{app → package}/static-index.js +58 -41
- package/dist/package/storage-view.d.ts +13 -0
- package/dist/package/storage-view.js +22 -0
- package/dist/{app → package}/types.d.ts +76 -57
- package/dist/package/types.js +22 -0
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +1 -1
- package/dist/platform/node.d.ts +48 -0
- package/dist/platform/node.js +96 -0
- package/dist/platform/types.d.ts +0 -9
- package/dist/process/control-arbiter.d.ts +2 -1
- package/dist/process/control-arbiter.js +1 -2
- package/dist/process/driver.d.ts +9 -8
- package/dist/process/driver.js +11 -22
- package/dist/process/index.d.ts +2 -0
- package/dist/process/index.js +2 -0
- package/dist/process/managed-record.d.ts +2 -2
- package/dist/process/process-driver.d.ts +109 -0
- package/dist/process/process-driver.js +650 -0
- package/dist/process/process-executor.d.ts +47 -0
- package/dist/process/process-executor.js +296 -0
- package/dist/process/process-manager.js +48 -26
- package/dist/process/run-executor.js +12 -12
- package/dist/profile/client-actions.js +2 -2
- package/dist/profile/client-health.js +3 -2
- package/dist/profile/client-query.js +5 -6
- package/dist/profile/client-transport.d.ts +19 -17
- package/dist/profile/client-transport.js +48 -80
- package/dist/profile/client.d.ts +2 -2
- package/dist/profile/client.js +1 -1
- package/dist/profile/index.d.ts +1 -0
- package/dist/profile/index.js +1 -0
- package/dist/profile/manager.d.ts +5 -0
- package/dist/profile/manager.js +41 -6
- package/dist/project/closure.js +2 -2
- package/dist/project/index.d.ts +8 -1
- package/dist/project/index.js +10 -1
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +1 -1
- package/dist/project/loader.js +26 -29
- package/dist/project/transactions.js +5 -10
- package/dist/registry/index.d.ts +3 -1
- package/dist/registry/index.js +2 -1
- package/dist/registry/lock.d.ts +28 -7
- package/dist/registry/lock.js +136 -16
- package/dist/registry/registry.d.ts +1 -5
- package/dist/registry/registry.js +1 -53
- package/dist/registry/scan.d.ts +0 -15
- package/dist/registry/scan.js +0 -59
- package/dist/registry/store.d.ts +42 -0
- package/dist/registry/store.js +43 -0
- package/dist/registry/types.d.ts +0 -24
- package/dist/runtime/action-collection.d.ts +1 -1
- package/dist/runtime/action-registry.d.ts +0 -4
- package/dist/runtime/action-registry.js +0 -7
- package/dist/runtime/context.js +5 -11
- package/dist/runtime/events.js +3 -6
- package/dist/runtime/identity.d.ts +22 -0
- package/dist/runtime/identity.js +10 -0
- package/dist/runtime/index.d.ts +1 -2
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/module-loader.d.ts +2 -34
- package/dist/runtime/module-loader.js +1 -16
- package/dist/runtime/process.d.ts +6 -24
- package/dist/runtime/process.js +1 -118
- package/dist/runtime/run-persistence.js +2 -5
- package/dist/runtime/runner.d.ts +33 -103
- package/dist/runtime/runner.js +142 -404
- package/dist/runtime/standalone.d.ts +37 -9
- package/dist/runtime/standalone.js +195 -136
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/validator.d.ts +10 -0
- package/dist/schema/validator.js +48 -54
- package/dist/server/body.d.ts +16 -8
- package/dist/server/body.js +33 -16
- package/dist/server/dispatcher.d.ts +6 -10
- package/dist/server/dispatcher.js +24 -32
- package/dist/server/http-server.d.ts +87 -0
- package/dist/server/http-server.js +304 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +10 -0
- package/dist/server/mcp-endpoint.d.ts +61 -0
- package/dist/server/mcp-endpoint.js +118 -0
- package/dist/server/routes/actions.js +34 -28
- package/dist/server/routes/common.d.ts +10 -14
- package/dist/server/routes/common.js +32 -56
- package/dist/server/routes/config.js +54 -64
- package/dist/server/routes/doctor.d.ts +1 -1
- package/dist/server/routes/doctor.js +10 -18
- package/dist/server/routes/health.d.ts +1 -1
- package/dist/server/routes/health.js +2 -3
- package/dist/server/routes/info.d.ts +2 -2
- package/dist/server/routes/info.js +12 -13
- package/dist/server/routes/playbooks.js +16 -29
- package/dist/server/routes/runs.js +95 -117
- package/dist/server/routes/state.js +63 -62
- package/dist/server/server.d.ts +2 -2
- package/dist/server/server.js +43 -227
- package/dist/server/types.d.ts +8 -19
- package/dist/service/factory.d.ts +12 -0
- package/dist/service/factory.js +85 -0
- package/dist/{target → service}/index.d.ts +1 -1
- package/dist/{target → service}/index.js +1 -1
- package/dist/service/local.d.ts +27 -0
- package/dist/service/local.js +138 -0
- package/dist/{target → service}/remote-errors.d.ts +3 -6
- package/dist/service/remote-errors.js +38 -0
- package/dist/{target → service}/remote-polling.d.ts +2 -2
- package/dist/{target → service}/remote-polling.js +8 -8
- package/dist/service/remote.d.ts +34 -0
- package/dist/service/remote.js +634 -0
- package/dist/service/sse-stream.d.ts +24 -0
- package/dist/service/sse-stream.js +139 -0
- package/dist/service/types.d.ts +272 -0
- package/dist/service/types.js +32 -0
- package/dist/storage/data-dir-lock.js +10 -5
- package/dist/storage/driver.d.ts +2 -1
- package/dist/storage/driver.js +3 -52
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/lock-core.d.ts +2 -6
- package/dist/storage/lock-core.js +4 -17
- package/dist/storage/params.d.ts +2 -8
- package/dist/storage/params.js +2 -8
- package/dist/storage/sqlite-driver.d.ts +40 -0
- package/dist/storage/sqlite-driver.js +116 -0
- package/dist/storage/sqlite.js +21 -6
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.js +2 -2
- package/dist/utils/index.d.ts +53 -0
- package/dist/utils/index.js +99 -4
- package/dist/utils/process.d.ts +10 -0
- package/dist/utils/process.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +41 -3
- package/dist/app/index.d.ts +0 -2
- package/dist/app/index.js +0 -2
- package/dist/app/types.js +0 -1
- package/dist/catalog/action-index.d.ts +0 -9
- package/dist/catalog/action-index.js +0 -95
- package/dist/catalog/action-resolver.d.ts +0 -20
- package/dist/catalog/action-resolver.js +0 -95
- package/dist/catalog/location-registry.d.ts +0 -15
- package/dist/catalog/location-registry.js +0 -138
- package/dist/catalog/package-catalog.d.ts +0 -7
- package/dist/catalog/package-catalog.js +0 -77
- package/dist/catalog/types.d.ts +0 -68
- package/dist/catalog/types.js +0 -1
- package/dist/export/index.d.ts +0 -1
- package/dist/export/index.js +0 -1
- package/dist/export/templates.d.ts +0 -71
- package/dist/export/templates.js +0 -623
- package/dist/ipc/target.d.ts +0 -74
- package/dist/ipc/target.js +0 -365
- package/dist/platform/default.d.ts +0 -38
- package/dist/platform/default.js +0 -78
- package/dist/project/resolver.d.ts +0 -116
- package/dist/project/resolver.js +0 -376
- package/dist/registry/resolve.d.ts +0 -62
- package/dist/registry/resolve.js +0 -195
- package/dist/runtime/execution-manager.d.ts +0 -48
- package/dist/runtime/execution-manager.js +0 -66
- package/dist/runtime/package-runner-factory.d.ts +0 -82
- package/dist/runtime/package-runner-factory.js +0 -186
- package/dist/target/local.d.ts +0 -53
- package/dist/target/local.js +0 -349
- package/dist/target/remote-errors.js +0 -51
- package/dist/target/remote.d.ts +0 -86
- package/dist/target/remote.js +0 -818
- package/dist/target/target.d.ts +0 -6
- package/dist/target/target.js +0 -37
- package/dist/target/types.d.ts +0 -261
- package/dist/target/types.js +0 -35
- /package/dist/{app → package}/static-index.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.js +0 -0
package/dist/server/server.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import { createServer as createNodeHttpServer } from "node:http";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
1
|
import { resolve } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { createActionDockHost } from "../host/host.js";
|
|
2
|
+
import { NodeHttpServer } from "./http-server.js";
|
|
3
|
+
import { createActionDock } from "../service/factory.js";
|
|
7
4
|
import { NOT_FOUND, UNAUTHORIZED } from "../errors.js";
|
|
8
5
|
import { ensureDependencyClosure } from "../project/closure.js";
|
|
9
6
|
import { findProjectRoot } from "../project/loader.js";
|
|
10
7
|
import { listLinkedPackages, resolvePackageRoot } from "../registry/registry.js";
|
|
11
|
-
import { LocalActionDockTarget } from "../target/local.js";
|
|
12
8
|
import { handleActionsRoutes, handleConfigRoutes, handleDoctorRoute, handleHealthRoute, handleInfoRoute, handlePlaybooksRoutes, handleRunsRoutes, handleStateRoutes, jsonResponse, } from "./routes/index.js";
|
|
13
|
-
import { DEFAULT_MAX_BODY_BYTES } from "./body.js";
|
|
14
9
|
import { isLoopbackHost, resolveCorsHeaders, verifyBearerToken } from "./security.js";
|
|
10
|
+
import { createMcpEndpointHandler } from "./mcp-endpoint.js";
|
|
15
11
|
/**
|
|
16
12
|
* 规范化主机地址用于拼接 URL。
|
|
17
13
|
* 若 host 包含冒号 : 且不以 [ 开头,则添加中括号包裹(IPv6 标准格式)。
|
|
@@ -23,132 +19,28 @@ export function formatHostForUrl(host) {
|
|
|
23
19
|
* 根据当前运行时环境启动标准 Web Request/Response 兼容的 HTTP 服务。
|
|
24
20
|
*/
|
|
25
21
|
export async function launchHttpServer(port, host, fetchHandler, tls) {
|
|
26
|
-
const
|
|
27
|
-
const ac = new AbortController();
|
|
28
|
-
const onReqClose = () => {
|
|
29
|
-
if (!req.complete) {
|
|
30
|
-
ac.abort(new Error("Request aborted by client"));
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
const onResClose = () => {
|
|
34
|
-
if (!res.writableFinished) {
|
|
35
|
-
ac.abort(new Error("Request aborted by client"));
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
req.on("close", onReqClose);
|
|
39
|
-
res.on("close", onResClose);
|
|
40
|
-
try {
|
|
41
|
-
const protocol = req.socket?.encrypted ? "https" : "http";
|
|
42
|
-
const hostHeader = req.headers.host || "127.0.0.1";
|
|
43
|
-
const url = new URL(req.url || "/", `${protocol}://${hostHeader}`).href;
|
|
44
|
-
const headers = new Headers();
|
|
45
|
-
for (const [k, v] of Object.entries(req.headers)) {
|
|
46
|
-
if (v === undefined)
|
|
47
|
-
continue;
|
|
48
|
-
if (Array.isArray(v)) {
|
|
49
|
-
for (const item of v)
|
|
50
|
-
headers.append(k, item);
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
headers.set(k, v);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const method = (req.method || "GET").toUpperCase();
|
|
57
|
-
const hasBody = method !== "GET" && method !== "HEAD";
|
|
58
|
-
const init = { method, headers, signal: ac.signal };
|
|
59
|
-
if (hasBody) {
|
|
60
|
-
init.body = Readable.toWeb(req);
|
|
61
|
-
init.duplex = "half";
|
|
62
|
-
}
|
|
63
|
-
const webReq = new Request(url, init);
|
|
64
|
-
const webRes = await fetchHandler(webReq);
|
|
65
|
-
res.statusCode = webRes.status;
|
|
66
|
-
if (webRes.statusText)
|
|
67
|
-
res.statusMessage = webRes.statusText;
|
|
68
|
-
webRes.headers.forEach((v, k) => res.setHeader(k, v));
|
|
69
|
-
if (!webRes.body) {
|
|
70
|
-
res.end();
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
await pipeline(Readable.fromWeb(webRes.body), res);
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
if (!res.headersSent) {
|
|
77
|
-
res.statusCode = 500;
|
|
78
|
-
res.end(JSON.stringify({ error: err?.message || String(err) }));
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
res.destroy(err);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
finally {
|
|
85
|
-
req.removeListener("close", onReqClose);
|
|
86
|
-
res.removeListener("close", onResClose);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
let srv;
|
|
90
|
-
if (tls) {
|
|
91
|
-
let cert = tls.cert;
|
|
92
|
-
if (!cert && tls.certPath) {
|
|
93
|
-
cert = readFileSync(tls.certPath);
|
|
94
|
-
}
|
|
95
|
-
let key = tls.key;
|
|
96
|
-
if (!key && tls.keyPath) {
|
|
97
|
-
key = readFileSync(tls.keyPath);
|
|
98
|
-
}
|
|
99
|
-
const httpsOptions = {
|
|
100
|
-
cert,
|
|
101
|
-
key,
|
|
102
|
-
};
|
|
103
|
-
if (tls.ca) {
|
|
104
|
-
httpsOptions.ca = tls.ca;
|
|
105
|
-
}
|
|
106
|
-
if (tls.passphrase) {
|
|
107
|
-
httpsOptions.passphrase = tls.passphrase;
|
|
108
|
-
}
|
|
109
|
-
const { createServer: createHttpsServer } = await import("node:https");
|
|
110
|
-
srv = createHttpsServer(httpsOptions, requestListener);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
srv = createNodeHttpServer(requestListener);
|
|
114
|
-
}
|
|
115
|
-
const instance = {
|
|
22
|
+
const server = new NodeHttpServer({
|
|
116
23
|
port,
|
|
24
|
+
host,
|
|
25
|
+
fetch: fetchHandler,
|
|
26
|
+
tls,
|
|
27
|
+
});
|
|
28
|
+
await server.listen(port, host);
|
|
29
|
+
const instance = {
|
|
30
|
+
port: server.port,
|
|
117
31
|
stop: async () => {
|
|
118
|
-
await
|
|
119
|
-
srv.close(() => resolve());
|
|
120
|
-
srv.closeAllConnections?.();
|
|
121
|
-
});
|
|
32
|
+
await server.close();
|
|
122
33
|
},
|
|
34
|
+
ready: Promise.resolve(),
|
|
123
35
|
};
|
|
124
|
-
await new Promise((resolve, reject) => {
|
|
125
|
-
srv.once("error", (err) => {
|
|
126
|
-
reject(err);
|
|
127
|
-
});
|
|
128
|
-
srv.listen(port, host, () => {
|
|
129
|
-
const addr = srv.address();
|
|
130
|
-
if (typeof addr === "object" && addr) {
|
|
131
|
-
instance.port = addr.port;
|
|
132
|
-
}
|
|
133
|
-
resolve();
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
instance.ready = Promise.resolve();
|
|
137
36
|
return instance;
|
|
138
37
|
}
|
|
139
38
|
/**
|
|
140
|
-
* 启动 ActionDock
|
|
141
|
-
*
|
|
39
|
+
* 启动 ActionDock 原生轻量级 HTTP 服务端。
|
|
40
|
+
* 面向 ActionDockService 服务端口,负责中间件流转、认证拦截与路由分发。
|
|
142
41
|
*/
|
|
143
42
|
export async function startActionDockServer(options = {}) {
|
|
144
|
-
|
|
145
|
-
(options.host && typeof options.host === "object" && "listActions" in options.host
|
|
146
|
-
? options.host
|
|
147
|
-
: undefined);
|
|
148
|
-
let targetInstance = options.target;
|
|
149
|
-
const hostString = typeof options.host === "string"
|
|
150
|
-
? options.host
|
|
151
|
-
: (options.hostname ?? "127.0.0.1");
|
|
43
|
+
const hostString = options.hostname ?? options.host ?? "127.0.0.1";
|
|
152
44
|
const port = options.port ?? 5177;
|
|
153
45
|
const host = hostString;
|
|
154
46
|
const token = options.token;
|
|
@@ -160,27 +52,22 @@ export async function startActionDockServer(options = {}) {
|
|
|
160
52
|
if (!isLoopbackHost(host) && !token && !options.allowInsecureNoAuth) {
|
|
161
53
|
throw new Error("Authentication token is required when binding to a non-loopback address. Use --allow-insecure-no-auth to override.");
|
|
162
54
|
}
|
|
163
|
-
|
|
164
|
-
|
|
55
|
+
let serviceInstance = options.service;
|
|
56
|
+
// 若未传 service,服务端统一通过 createActionDock() 实例化,不再接受或处理外部传入的 Host 实体
|
|
57
|
+
if (!serviceInstance) {
|
|
165
58
|
const scanLinkedPackages = options.scanLinkedPackages ?? !projectRoot;
|
|
166
|
-
|
|
59
|
+
serviceInstance = await createActionDock({
|
|
167
60
|
projectRoot: projectRoot || undefined,
|
|
168
61
|
customHome,
|
|
169
62
|
platform: options.platform,
|
|
170
63
|
dataDir: options.dataDir,
|
|
171
64
|
inMemory: options.inMemory,
|
|
172
65
|
scanLinkedPackages,
|
|
173
|
-
|
|
66
|
+
enableManagement: options.enableManagement,
|
|
174
67
|
});
|
|
175
68
|
}
|
|
176
|
-
if (!
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
else if (targetInstance && !hostInstance) {
|
|
180
|
-
const inner = targetInstance?.unwrap?.();
|
|
181
|
-
if (inner && "listApps" in inner) {
|
|
182
|
-
hostInstance = inner;
|
|
183
|
-
}
|
|
69
|
+
if (!serviceInstance) {
|
|
70
|
+
throw new Error("Failed to initialize ActionDockService for server");
|
|
184
71
|
}
|
|
185
72
|
const roots = [];
|
|
186
73
|
if (projectRoot) {
|
|
@@ -204,6 +91,15 @@ export async function startActionDockServer(options = {}) {
|
|
|
204
91
|
if (roots.length > 0) {
|
|
205
92
|
await ensureDependencyClosure(roots, { customHome });
|
|
206
93
|
}
|
|
94
|
+
// MCP 统一网关端点处理器:鉴权、请求体限流与委托序列收敛为共享单一事实源
|
|
95
|
+
const mcpEndpointHandler = options.mcpHandler
|
|
96
|
+
? createMcpEndpointHandler(options.mcpHandler, {
|
|
97
|
+
token,
|
|
98
|
+
allowQueryToken: options.allowQueryToken,
|
|
99
|
+
corsOrigins: options.corsOrigins,
|
|
100
|
+
maxBodyBytes: options.maxBodyBytes,
|
|
101
|
+
})
|
|
102
|
+
: undefined;
|
|
207
103
|
const fetchHandler = async (req) => {
|
|
208
104
|
const origin = req.headers.get("origin");
|
|
209
105
|
const corsHeaders = resolveCorsHeaders(origin, options.corsOrigins);
|
|
@@ -222,8 +118,7 @@ export async function startActionDockServer(options = {}) {
|
|
|
222
118
|
corsHeaders,
|
|
223
119
|
projectRoot,
|
|
224
120
|
customHome,
|
|
225
|
-
|
|
226
|
-
target: targetInstance,
|
|
121
|
+
service: serviceInstance,
|
|
227
122
|
options,
|
|
228
123
|
};
|
|
229
124
|
// 1. 健康检查路由(内部处理独立鉴权逻辑)
|
|
@@ -231,82 +126,11 @@ export async function startActionDockServer(options = {}) {
|
|
|
231
126
|
if (healthResponse) {
|
|
232
127
|
return healthResponse;
|
|
233
128
|
}
|
|
234
|
-
// 2. MCP
|
|
129
|
+
// 2. MCP 统一网关端点(委托共享端点处理器)
|
|
235
130
|
if (options.enableMcp !== false &&
|
|
236
|
-
|
|
131
|
+
mcpEndpointHandler &&
|
|
237
132
|
(pathname === "/mcp" || pathname.startsWith("/mcp/"))) {
|
|
238
|
-
|
|
239
|
-
return jsonResponse({
|
|
240
|
-
ok: false,
|
|
241
|
-
error: {
|
|
242
|
-
code: UNAUTHORIZED,
|
|
243
|
-
message: "Invalid or missing Bearer token",
|
|
244
|
-
},
|
|
245
|
-
}, 401, corsHeaders);
|
|
246
|
-
}
|
|
247
|
-
// 请求体体积限制保护
|
|
248
|
-
const maxBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
249
|
-
const contentLengthHeader = req.headers.get("content-length");
|
|
250
|
-
if (contentLengthHeader) {
|
|
251
|
-
const parsedLength = parseInt(contentLengthHeader, 10);
|
|
252
|
-
if (!isNaN(parsedLength) && parsedLength > maxBytes) {
|
|
253
|
-
return jsonResponse({
|
|
254
|
-
ok: false,
|
|
255
|
-
error: {
|
|
256
|
-
code: "REQUEST_TOO_LARGE",
|
|
257
|
-
message: "Request body exceeds maximum allowed size",
|
|
258
|
-
},
|
|
259
|
-
}, 413, corsHeaders);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
let mcpReq = req;
|
|
263
|
-
if (req.body && req.method !== "GET" && req.method !== "HEAD") {
|
|
264
|
-
const reader = req.body.getReader();
|
|
265
|
-
const chunks = [];
|
|
266
|
-
let totalBytes = 0;
|
|
267
|
-
let tooLarge = false;
|
|
268
|
-
try {
|
|
269
|
-
while (true) {
|
|
270
|
-
const { done, value } = await reader.read();
|
|
271
|
-
if (done)
|
|
272
|
-
break;
|
|
273
|
-
if (value) {
|
|
274
|
-
totalBytes += value.byteLength;
|
|
275
|
-
if (totalBytes > maxBytes) {
|
|
276
|
-
tooLarge = true;
|
|
277
|
-
await reader.cancel();
|
|
278
|
-
break;
|
|
279
|
-
}
|
|
280
|
-
chunks.push(value);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
finally {
|
|
285
|
-
reader.releaseLock();
|
|
286
|
-
}
|
|
287
|
-
if (tooLarge) {
|
|
288
|
-
return jsonResponse({
|
|
289
|
-
ok: false,
|
|
290
|
-
error: {
|
|
291
|
-
code: "REQUEST_TOO_LARGE",
|
|
292
|
-
message: "Request body exceeds maximum allowed size",
|
|
293
|
-
},
|
|
294
|
-
}, 413, corsHeaders);
|
|
295
|
-
}
|
|
296
|
-
const merged = new Uint8Array(totalBytes);
|
|
297
|
-
let offset = 0;
|
|
298
|
-
for (const chunk of chunks) {
|
|
299
|
-
merged.set(chunk, offset);
|
|
300
|
-
offset += chunk.byteLength;
|
|
301
|
-
}
|
|
302
|
-
mcpReq = new Request(req.url, {
|
|
303
|
-
method: req.method,
|
|
304
|
-
headers: req.headers,
|
|
305
|
-
body: merged,
|
|
306
|
-
signal: req.signal,
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
const mcpRes = await options.mcpHandler(mcpReq);
|
|
133
|
+
const mcpRes = await mcpEndpointHandler(req);
|
|
310
134
|
if (mcpRes)
|
|
311
135
|
return mcpRes;
|
|
312
136
|
}
|
|
@@ -320,7 +144,7 @@ export async function startActionDockServer(options = {}) {
|
|
|
320
144
|
},
|
|
321
145
|
}, 401, corsHeaders);
|
|
322
146
|
}
|
|
323
|
-
// 4. 业务领域路由分发(完全委托
|
|
147
|
+
// 4. 业务领域路由分发(完全委托 Service)
|
|
324
148
|
const routeResponse = (await handleInfoRoute(ctx)) ||
|
|
325
149
|
(await handleDoctorRoute(ctx)) ||
|
|
326
150
|
(await handleActionsRoutes(ctx)) ||
|
|
@@ -353,28 +177,20 @@ export async function startActionDockServer(options = {}) {
|
|
|
353
177
|
set port(val) {
|
|
354
178
|
server.port = val;
|
|
355
179
|
},
|
|
356
|
-
|
|
357
|
-
target: targetInstance,
|
|
180
|
+
service: serviceInstance,
|
|
358
181
|
get url() {
|
|
359
182
|
return `${protocol}://${formatHostForUrl(actualHost)}:${this.port}`;
|
|
360
183
|
},
|
|
361
184
|
ready: Promise.resolve(),
|
|
362
185
|
stop: async (stopOptions) => {
|
|
363
186
|
await server.stop(true);
|
|
364
|
-
if (
|
|
365
|
-
try {
|
|
366
|
-
await targetInstance.close(stopOptions?.graceMs !== undefined ? { timeoutMs: stopOptions.graceMs } : undefined);
|
|
367
|
-
}
|
|
368
|
-
catch {
|
|
369
|
-
// 忽略关闭异常
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if (hostInstance && hostInstance !== targetInstance?.unwrap?.()) {
|
|
187
|
+
if (serviceInstance) {
|
|
373
188
|
try {
|
|
374
|
-
await
|
|
189
|
+
await serviceInstance.close(stopOptions);
|
|
375
190
|
}
|
|
376
|
-
catch {
|
|
377
|
-
//
|
|
191
|
+
catch (err) {
|
|
192
|
+
// 服务关闭失败不阻断停机流程,但保留可观测诊断
|
|
193
|
+
console.warn(`[ActionDockServer] Service close failed during stop: ${err instanceof Error ? err.message : String(err)}`);
|
|
378
194
|
}
|
|
379
195
|
}
|
|
380
196
|
},
|
package/dist/server/types.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ActionDockTarget } from "../target/types.js";
|
|
1
|
+
import type { ActionDockService } from "../service/types.js";
|
|
3
2
|
export interface CoreHttpServerInstance {
|
|
4
3
|
port: number;
|
|
5
4
|
stop: (closeActiveConnections?: boolean) => void | Promise<void>;
|
|
@@ -19,26 +18,18 @@ export interface ServerTlsOptions {
|
|
|
19
18
|
/** 私钥密码口令(若私钥被密码加密) */
|
|
20
19
|
passphrase?: string;
|
|
21
20
|
}
|
|
22
|
-
export type CoreHttpServerFactory = (options: {
|
|
23
|
-
port: number;
|
|
24
|
-
host: string;
|
|
25
|
-
fetch: (req: Request) => Promise<Response>;
|
|
26
|
-
tls?: ServerTlsOptions;
|
|
27
|
-
}) => CoreHttpServerInstance | Promise<CoreHttpServerInstance>;
|
|
28
21
|
/**
|
|
29
22
|
* 启动 ActionDock HTTP Runner 服务端的配置选项。
|
|
30
23
|
*/
|
|
31
24
|
export interface ServerOptions {
|
|
32
25
|
/** 监听端口号(默认 5177) */
|
|
33
26
|
port?: number;
|
|
34
|
-
/** 绑定监听的主机地址(默认 "127.0.0.1"
|
|
35
|
-
host?: string | ActionDockHost;
|
|
36
|
-
/** 显式绑定的 ActionDockHost 宿主实例(向前兼容别名) */
|
|
37
|
-
hostInstance?: ActionDockHost;
|
|
38
|
-
/** 关联的目标 ActionDockTarget 门面实例 */
|
|
39
|
-
target?: ActionDockTarget;
|
|
40
|
-
/** 显式绑定的主机地址(当 host 传入 ActionDockHost 时的可选覆盖项) */
|
|
27
|
+
/** 绑定监听的主机地址(默认 "127.0.0.1") */
|
|
41
28
|
hostname?: string;
|
|
29
|
+
/** 绑定监听的主机地址(hostname 的字符串别名) */
|
|
30
|
+
host?: string;
|
|
31
|
+
/** 关联的标准 ActionDockService 服务端口实例 */
|
|
32
|
+
service?: ActionDockService;
|
|
42
33
|
/** 用于 HTTP Bearer Token 鉴权的密钥令牌 */
|
|
43
34
|
token?: string;
|
|
44
35
|
/** 是否允许通过 URL 查询参数携带 Token 进行鉴权(默认 false,关闭以防泄露) */
|
|
@@ -80,10 +71,8 @@ export interface ServerOptions {
|
|
|
80
71
|
export interface ActionDockServerInstance {
|
|
81
72
|
/** 实际监听的端口号 */
|
|
82
73
|
port: number;
|
|
83
|
-
/** 关联的
|
|
84
|
-
|
|
85
|
-
/** 关联的 ActionDockTarget 目标门面实例 */
|
|
86
|
-
target?: ActionDockTarget;
|
|
74
|
+
/** 关联的 ActionDockService 服务端口实例 */
|
|
75
|
+
service: ActionDockService;
|
|
87
76
|
/** 服务端可访问的基础 URL(如 "http://127.0.0.1:5177") */
|
|
88
77
|
url: string;
|
|
89
78
|
/** 服务就绪 Promise(可等待端口解析与监听建立) */
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { RemoteActionDockService } from "./remote.js";
|
|
2
|
+
import type { ActionDockService, ConnectActionDockOptions, CreateActionDockOptions, RemoteServiceOptions } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 工厂函数:创建本地 ActionDock 服务实例。
|
|
5
|
+
* 遵循标准 Service Ports 体系,屏蔽底层多包协调或单包存储细节。
|
|
6
|
+
*/
|
|
7
|
+
export declare function createActionDock(options?: CreateActionDockOptions): Promise<ActionDockService>;
|
|
8
|
+
/**
|
|
9
|
+
* 工厂函数:连接远端 ActionDock 服务实例。
|
|
10
|
+
* 支持传入目标 HTTP 根地址、Profile 别名或完整连接配置选项。
|
|
11
|
+
*/
|
|
12
|
+
export declare function connectActionDock(urlOrProfile: string | RemoteServiceOptions, options?: ConnectActionDockOptions): Promise<RemoteActionDockService>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createActionDockHost } from "../host/host.js";
|
|
2
|
+
import { LocalActionDockService } from "./local.js";
|
|
3
|
+
import { RemoteActionDockService } from "./remote.js";
|
|
4
|
+
import { ActionDockError, INVALID_ARGUMENT, NOT_FOUND } from "../errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* 工厂函数:创建本地 ActionDock 服务实例。
|
|
7
|
+
* 遵循标准 Service Ports 体系,屏蔽底层多包协调或单包存储细节。
|
|
8
|
+
*/
|
|
9
|
+
export async function createActionDock(options = {}) {
|
|
10
|
+
if (options.runtimeOptions) {
|
|
11
|
+
const inMemory = options.inMemory ?? options.runtimeOptions.inMemory;
|
|
12
|
+
const host = await createActionDockHost({
|
|
13
|
+
packages: [options.runtimeOptions],
|
|
14
|
+
autoLoadCurrentProject: false,
|
|
15
|
+
scanLinkedPackages: false,
|
|
16
|
+
inMemory,
|
|
17
|
+
dataDir: options.dataDir ?? options.runtimeOptions.dataDir,
|
|
18
|
+
customHome: options.customHome ?? options.runtimeOptions.customHome,
|
|
19
|
+
platform: options.platform ?? options.runtimeOptions.platform,
|
|
20
|
+
clock: options.runtimeOptions.clock,
|
|
21
|
+
process: options.runtimeOptions.process,
|
|
22
|
+
logger: options.runtimeOptions.logger,
|
|
23
|
+
recoverOrphans: options.recoverOrphans,
|
|
24
|
+
});
|
|
25
|
+
return new LocalActionDockService(host, { enableManagement: options.enableManagement });
|
|
26
|
+
}
|
|
27
|
+
const host = await createActionDockHost({
|
|
28
|
+
scanLinkedPackages: options.scanLinkedPackages ?? true,
|
|
29
|
+
...options,
|
|
30
|
+
recoverOrphans: options.recoverOrphans ?? true,
|
|
31
|
+
...(options.hostOptions || {}),
|
|
32
|
+
});
|
|
33
|
+
return new LocalActionDockService(host, { enableManagement: options.enableManagement });
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 工厂函数:连接远端 ActionDock 服务实例。
|
|
37
|
+
* 支持传入目标 HTTP 根地址、Profile 别名或完整连接配置选项。
|
|
38
|
+
*/
|
|
39
|
+
export async function connectActionDock(urlOrProfile, options) {
|
|
40
|
+
let targetUrl;
|
|
41
|
+
let token = options?.token;
|
|
42
|
+
let insecure = options?.insecure;
|
|
43
|
+
let allowInsecureHttp = options?.allowInsecureHttp;
|
|
44
|
+
let dispatcher = options?.dispatcher;
|
|
45
|
+
let timeoutMs = options?.timeoutMs;
|
|
46
|
+
let baseTimeoutMs = options?.baseTimeoutMs;
|
|
47
|
+
if (typeof urlOrProfile === "object" && urlOrProfile !== null) {
|
|
48
|
+
targetUrl = urlOrProfile.serverUrl;
|
|
49
|
+
token = urlOrProfile.token ?? token;
|
|
50
|
+
insecure = urlOrProfile.insecure ?? insecure;
|
|
51
|
+
allowInsecureHttp = urlOrProfile.allowInsecureHttp ?? allowInsecureHttp;
|
|
52
|
+
dispatcher = urlOrProfile.dispatcher ?? dispatcher;
|
|
53
|
+
timeoutMs = urlOrProfile.timeoutMs ?? timeoutMs;
|
|
54
|
+
baseTimeoutMs = urlOrProfile.baseTimeoutMs ?? baseTimeoutMs;
|
|
55
|
+
}
|
|
56
|
+
else if (typeof urlOrProfile === "string") {
|
|
57
|
+
if (urlOrProfile.startsWith("http://") || urlOrProfile.startsWith("https://")) {
|
|
58
|
+
targetUrl = urlOrProfile;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const { resolveTarget } = await import("../profile/manager.js");
|
|
62
|
+
const resolved = resolveTarget({ profile: urlOrProfile }, options?.customHome);
|
|
63
|
+
if (resolved.type !== "remote" || !resolved.serverUrl) {
|
|
64
|
+
throw new ActionDockError(NOT_FOUND, `Profile '${urlOrProfile}' not found or is not a remote profile`);
|
|
65
|
+
}
|
|
66
|
+
targetUrl = resolved.serverUrl;
|
|
67
|
+
token = resolved.token ?? token;
|
|
68
|
+
insecure = resolved.insecure ?? insecure;
|
|
69
|
+
allowInsecureHttp = resolved.allowInsecureHttp ?? allowInsecureHttp;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new ActionDockError(INVALID_ARGUMENT, "Invalid urlOrProfile argument for connectActionDock");
|
|
74
|
+
}
|
|
75
|
+
return new RemoteActionDockService({
|
|
76
|
+
serverUrl: targetUrl,
|
|
77
|
+
token,
|
|
78
|
+
insecure,
|
|
79
|
+
allowInsecureHttp,
|
|
80
|
+
dispatcher,
|
|
81
|
+
timeoutMs,
|
|
82
|
+
baseTimeoutMs,
|
|
83
|
+
enableManagement: options?.enableManagement,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PackageInfo } from "../package/types.js";
|
|
2
|
+
import type { ActionDockHost } from "../host/types.js";
|
|
3
|
+
import type { ActionDockService, ConfigPort, DiscoveryPort, EventsPort, ExecutionPort, RunsPort, StatePort } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* 本地 ActionDockService 实现。
|
|
6
|
+
* 遵循标准 Service Ports 体系,面向 ActionDockHost 协调中枢提供结构化服务端口,
|
|
7
|
+
* 严禁暴露 unwrap 穿透到内部领域对象。
|
|
8
|
+
*/
|
|
9
|
+
export declare class LocalActionDockService implements ActionDockService {
|
|
10
|
+
protected readonly host: ActionDockHost;
|
|
11
|
+
readonly discovery: DiscoveryPort;
|
|
12
|
+
readonly execution: ExecutionPort;
|
|
13
|
+
readonly runs: RunsPort;
|
|
14
|
+
readonly events: EventsPort;
|
|
15
|
+
readonly management?: {
|
|
16
|
+
config: ConfigPort;
|
|
17
|
+
state: StatePort;
|
|
18
|
+
};
|
|
19
|
+
constructor(host: ActionDockHost, options?: {
|
|
20
|
+
enableManagement?: boolean;
|
|
21
|
+
});
|
|
22
|
+
info(): Promise<PackageInfo[]>;
|
|
23
|
+
close(options?: {
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
graceMs?: number;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
}
|