@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.
Files changed (268) hide show
  1. package/README.md +61 -68
  2. package/dist/catalog/action-catalog.d.ts +56 -0
  3. package/dist/catalog/action-catalog.js +202 -0
  4. package/dist/catalog/discovery.d.ts +60 -0
  5. package/dist/catalog/discovery.js +119 -0
  6. package/dist/catalog/graph.d.ts +190 -0
  7. package/dist/catalog/graph.js +589 -0
  8. package/dist/catalog/index.d.ts +5 -5
  9. package/dist/catalog/index.js +5 -5
  10. package/dist/catalog/resolve-action.d.ts +43 -0
  11. package/dist/catalog/resolve-action.js +119 -0
  12. package/dist/catalog/resolve-playbook.d.ts +26 -0
  13. package/dist/catalog/resolve-playbook.js +114 -0
  14. package/dist/doctor/checks/project.js +27 -8
  15. package/dist/doctor/checks/registry.js +2 -2
  16. package/dist/doctor/checks/runtime.js +34 -1
  17. package/dist/errors.d.ts +122 -10
  18. package/dist/errors.js +123 -10
  19. package/dist/execution/service.d.ts +18 -16
  20. package/dist/execution/service.js +183 -252
  21. package/dist/execution/types.d.ts +25 -69
  22. package/dist/execution/types.js +2 -1
  23. package/dist/filter/intent.d.ts +8 -9
  24. package/dist/filter/intent.js +49 -10
  25. package/dist/graph/index.d.ts +4 -0
  26. package/dist/graph/index.js +4 -0
  27. package/dist/host/host.d.ts +74 -32
  28. package/dist/host/host.js +585 -336
  29. package/dist/host/routing.d.ts +15 -48
  30. package/dist/host/routing.js +90 -153
  31. package/dist/host/types.d.ts +50 -17
  32. package/dist/index.d.ts +21 -22
  33. package/dist/index.js +19 -21
  34. package/dist/input/advice.d.ts +104 -0
  35. package/dist/input/advice.js +716 -0
  36. package/dist/input/describe.d.ts +106 -0
  37. package/dist/input/describe.js +176 -0
  38. package/dist/input/file-input.d.ts +54 -0
  39. package/dist/input/file-input.js +124 -0
  40. package/dist/input/flat-decode.d.ts +11 -0
  41. package/dist/input/flat-decode.js +13 -0
  42. package/dist/input/flat-errors.d.ts +71 -0
  43. package/dist/input/flat-errors.js +87 -0
  44. package/dist/input/flat-materializer.d.ts +29 -0
  45. package/dist/input/flat-materializer.js +177 -0
  46. package/dist/input/flat-parser.d.ts +50 -0
  47. package/dist/input/flat-parser.js +169 -0
  48. package/dist/input/flat-predicates.d.ts +34 -0
  49. package/dist/input/flat-predicates.js +50 -0
  50. package/dist/input/index.d.ts +14 -0
  51. package/dist/input/index.js +14 -0
  52. package/dist/input/input-resolver.d.ts +63 -0
  53. package/dist/input/input-resolver.js +254 -0
  54. package/dist/input/json-depth-scanner.d.ts +17 -0
  55. package/dist/input/json-depth-scanner.js +49 -0
  56. package/dist/input/metadata.d.ts +99 -0
  57. package/dist/input/metadata.js +99 -0
  58. package/dist/input/stdin-input.d.ts +26 -0
  59. package/dist/input/stdin-input.js +125 -0
  60. package/dist/input/utf8.d.ts +19 -0
  61. package/dist/input/utf8.js +36 -0
  62. package/dist/input/validation-mapper.d.ts +27 -0
  63. package/dist/input/validation-mapper.js +144 -0
  64. package/dist/invocation/index.d.ts +2 -0
  65. package/dist/invocation/index.js +2 -0
  66. package/dist/invocation/policy.d.ts +157 -0
  67. package/dist/invocation/policy.js +231 -0
  68. package/dist/invocation/types.d.ts +172 -0
  69. package/dist/invocation/types.js +97 -0
  70. package/dist/ipc/diagnostic.d.ts +0 -12
  71. package/dist/ipc/diagnostic.js +0 -21
  72. package/dist/ipc/host.d.ts +4 -4
  73. package/dist/ipc/host.js +44 -47
  74. package/dist/ipc/index.d.ts +1 -1
  75. package/dist/ipc/index.js +1 -1
  76. package/dist/ipc/service.d.ts +40 -0
  77. package/dist/ipc/service.js +349 -0
  78. package/dist/ipc/types.d.ts +21 -15
  79. package/dist/json/index.d.ts +1 -0
  80. package/dist/json/index.js +1 -0
  81. package/dist/json/value-validator.d.ts +88 -0
  82. package/dist/json/value-validator.js +330 -0
  83. package/dist/node/index.d.ts +1 -0
  84. package/dist/node/index.js +1 -0
  85. package/dist/node/module-loader.d.ts +63 -0
  86. package/dist/node/module-loader.js +112 -0
  87. package/dist/package/index.d.ts +23 -0
  88. package/dist/package/index.js +18 -0
  89. package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
  90. package/dist/{app/app.js → package/runtime.js} +140 -95
  91. package/dist/{app → package}/static-index.js +58 -41
  92. package/dist/package/storage-view.d.ts +13 -0
  93. package/dist/package/storage-view.js +22 -0
  94. package/dist/{app → package}/types.d.ts +76 -57
  95. package/dist/package/types.js +22 -0
  96. package/dist/platform/index.d.ts +1 -1
  97. package/dist/platform/index.js +1 -1
  98. package/dist/platform/node.d.ts +48 -0
  99. package/dist/platform/node.js +96 -0
  100. package/dist/platform/types.d.ts +0 -9
  101. package/dist/process/control-arbiter.d.ts +2 -1
  102. package/dist/process/control-arbiter.js +1 -2
  103. package/dist/process/driver.d.ts +9 -8
  104. package/dist/process/driver.js +11 -22
  105. package/dist/process/index.d.ts +2 -0
  106. package/dist/process/index.js +2 -0
  107. package/dist/process/managed-record.d.ts +2 -2
  108. package/dist/process/process-driver.d.ts +109 -0
  109. package/dist/process/process-driver.js +650 -0
  110. package/dist/process/process-executor.d.ts +47 -0
  111. package/dist/process/process-executor.js +296 -0
  112. package/dist/process/process-manager.js +48 -26
  113. package/dist/process/run-executor.js +12 -12
  114. package/dist/profile/client-actions.js +2 -2
  115. package/dist/profile/client-health.js +3 -2
  116. package/dist/profile/client-query.js +5 -6
  117. package/dist/profile/client-transport.d.ts +19 -17
  118. package/dist/profile/client-transport.js +48 -80
  119. package/dist/profile/client.d.ts +2 -2
  120. package/dist/profile/client.js +1 -1
  121. package/dist/profile/index.d.ts +1 -0
  122. package/dist/profile/index.js +1 -0
  123. package/dist/profile/manager.d.ts +5 -0
  124. package/dist/profile/manager.js +41 -6
  125. package/dist/project/closure.js +2 -2
  126. package/dist/project/index.d.ts +8 -1
  127. package/dist/project/index.js +10 -1
  128. package/dist/project/init.js +2 -2
  129. package/dist/project/loader.d.ts +1 -1
  130. package/dist/project/loader.js +26 -29
  131. package/dist/project/transactions.js +5 -10
  132. package/dist/registry/index.d.ts +3 -1
  133. package/dist/registry/index.js +2 -1
  134. package/dist/registry/lock.d.ts +28 -7
  135. package/dist/registry/lock.js +136 -16
  136. package/dist/registry/registry.d.ts +1 -5
  137. package/dist/registry/registry.js +1 -53
  138. package/dist/registry/scan.d.ts +0 -15
  139. package/dist/registry/scan.js +0 -59
  140. package/dist/registry/store.d.ts +42 -0
  141. package/dist/registry/store.js +43 -0
  142. package/dist/registry/types.d.ts +0 -24
  143. package/dist/runtime/action-collection.d.ts +1 -1
  144. package/dist/runtime/action-registry.d.ts +0 -4
  145. package/dist/runtime/action-registry.js +0 -7
  146. package/dist/runtime/context.js +5 -11
  147. package/dist/runtime/events.js +3 -6
  148. package/dist/runtime/identity.d.ts +22 -0
  149. package/dist/runtime/identity.js +10 -0
  150. package/dist/runtime/index.d.ts +1 -2
  151. package/dist/runtime/index.js +1 -2
  152. package/dist/runtime/module-loader.d.ts +2 -34
  153. package/dist/runtime/module-loader.js +1 -16
  154. package/dist/runtime/process.d.ts +6 -24
  155. package/dist/runtime/process.js +1 -118
  156. package/dist/runtime/run-persistence.js +2 -5
  157. package/dist/runtime/runner.d.ts +33 -103
  158. package/dist/runtime/runner.js +142 -404
  159. package/dist/runtime/standalone.d.ts +37 -9
  160. package/dist/runtime/standalone.js +195 -136
  161. package/dist/schema/index.d.ts +1 -0
  162. package/dist/schema/index.js +1 -0
  163. package/dist/schema/validator.d.ts +10 -0
  164. package/dist/schema/validator.js +48 -54
  165. package/dist/server/body.d.ts +16 -8
  166. package/dist/server/body.js +33 -16
  167. package/dist/server/dispatcher.d.ts +6 -10
  168. package/dist/server/dispatcher.js +24 -32
  169. package/dist/server/http-server.d.ts +87 -0
  170. package/dist/server/http-server.js +304 -0
  171. package/dist/server/index.d.ts +11 -0
  172. package/dist/server/index.js +10 -0
  173. package/dist/server/mcp-endpoint.d.ts +61 -0
  174. package/dist/server/mcp-endpoint.js +118 -0
  175. package/dist/server/routes/actions.js +34 -28
  176. package/dist/server/routes/common.d.ts +10 -14
  177. package/dist/server/routes/common.js +32 -56
  178. package/dist/server/routes/config.js +54 -64
  179. package/dist/server/routes/doctor.d.ts +1 -1
  180. package/dist/server/routes/doctor.js +10 -18
  181. package/dist/server/routes/health.d.ts +1 -1
  182. package/dist/server/routes/health.js +2 -3
  183. package/dist/server/routes/info.d.ts +2 -2
  184. package/dist/server/routes/info.js +12 -13
  185. package/dist/server/routes/playbooks.js +16 -29
  186. package/dist/server/routes/runs.js +95 -117
  187. package/dist/server/routes/state.js +63 -62
  188. package/dist/server/server.d.ts +2 -2
  189. package/dist/server/server.js +43 -227
  190. package/dist/server/types.d.ts +8 -19
  191. package/dist/service/factory.d.ts +12 -0
  192. package/dist/service/factory.js +85 -0
  193. package/dist/{target → service}/index.d.ts +1 -1
  194. package/dist/{target → service}/index.js +1 -1
  195. package/dist/service/local.d.ts +27 -0
  196. package/dist/service/local.js +138 -0
  197. package/dist/{target → service}/remote-errors.d.ts +3 -6
  198. package/dist/service/remote-errors.js +38 -0
  199. package/dist/{target → service}/remote-polling.d.ts +2 -2
  200. package/dist/{target → service}/remote-polling.js +8 -8
  201. package/dist/service/remote.d.ts +34 -0
  202. package/dist/service/remote.js +634 -0
  203. package/dist/service/sse-stream.d.ts +24 -0
  204. package/dist/service/sse-stream.js +139 -0
  205. package/dist/service/types.d.ts +272 -0
  206. package/dist/service/types.js +32 -0
  207. package/dist/storage/data-dir-lock.js +10 -5
  208. package/dist/storage/driver.d.ts +2 -1
  209. package/dist/storage/driver.js +3 -52
  210. package/dist/storage/index.d.ts +1 -0
  211. package/dist/storage/index.js +1 -0
  212. package/dist/storage/lock-core.d.ts +2 -6
  213. package/dist/storage/lock-core.js +4 -17
  214. package/dist/storage/params.d.ts +2 -8
  215. package/dist/storage/params.js +2 -8
  216. package/dist/storage/sqlite-driver.d.ts +40 -0
  217. package/dist/storage/sqlite-driver.js +116 -0
  218. package/dist/storage/sqlite.js +21 -6
  219. package/dist/storage/types.d.ts +4 -4
  220. package/dist/storage/types.js +2 -2
  221. package/dist/utils/index.d.ts +53 -0
  222. package/dist/utils/index.js +99 -4
  223. package/dist/utils/process.d.ts +10 -0
  224. package/dist/utils/process.js +21 -0
  225. package/dist/version.d.ts +1 -1
  226. package/dist/version.js +1 -1
  227. package/package.json +41 -3
  228. package/dist/app/index.d.ts +0 -2
  229. package/dist/app/index.js +0 -2
  230. package/dist/app/types.js +0 -1
  231. package/dist/catalog/action-index.d.ts +0 -9
  232. package/dist/catalog/action-index.js +0 -95
  233. package/dist/catalog/action-resolver.d.ts +0 -20
  234. package/dist/catalog/action-resolver.js +0 -95
  235. package/dist/catalog/location-registry.d.ts +0 -15
  236. package/dist/catalog/location-registry.js +0 -138
  237. package/dist/catalog/package-catalog.d.ts +0 -7
  238. package/dist/catalog/package-catalog.js +0 -77
  239. package/dist/catalog/types.d.ts +0 -68
  240. package/dist/catalog/types.js +0 -1
  241. package/dist/export/index.d.ts +0 -1
  242. package/dist/export/index.js +0 -1
  243. package/dist/export/templates.d.ts +0 -71
  244. package/dist/export/templates.js +0 -623
  245. package/dist/ipc/target.d.ts +0 -74
  246. package/dist/ipc/target.js +0 -365
  247. package/dist/platform/default.d.ts +0 -38
  248. package/dist/platform/default.js +0 -78
  249. package/dist/project/resolver.d.ts +0 -116
  250. package/dist/project/resolver.js +0 -376
  251. package/dist/registry/resolve.d.ts +0 -62
  252. package/dist/registry/resolve.js +0 -195
  253. package/dist/runtime/execution-manager.d.ts +0 -48
  254. package/dist/runtime/execution-manager.js +0 -66
  255. package/dist/runtime/package-runner-factory.d.ts +0 -82
  256. package/dist/runtime/package-runner-factory.js +0 -186
  257. package/dist/target/local.d.ts +0 -53
  258. package/dist/target/local.js +0 -349
  259. package/dist/target/remote-errors.js +0 -51
  260. package/dist/target/remote.d.ts +0 -86
  261. package/dist/target/remote.js +0 -818
  262. package/dist/target/target.d.ts +0 -6
  263. package/dist/target/target.js +0 -37
  264. package/dist/target/types.d.ts +0 -261
  265. package/dist/target/types.js +0 -35
  266. /package/dist/{app → package}/static-index.d.ts +0 -0
  267. /package/dist/{target → service}/sse-parser.d.ts +0 -0
  268. /package/dist/{target → service}/sse-parser.js +0 -0
@@ -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 { Readable } from "node:stream";
5
- import { pipeline } from "node:stream/promises";
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 requestListener = async (req, res) => {
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 new Promise((resolve) => {
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 2.0 原生轻量级 HTTP 服务端。
141
- * 作为 ActionDockHost 与 ActionDockTarget 的薄适配层,负责中间件流转、认证拦截与路由分发。
39
+ * 启动 ActionDock 原生轻量级 HTTP 服务端。
40
+ * 面向 ActionDockService 服务端口,负责中间件流转、认证拦截与路由分发。
142
41
  */
143
42
  export async function startActionDockServer(options = {}) {
144
- let hostInstance = options.hostInstance ??
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
- // 若调用方未传入 host 或 target,通过 projectRoot、customHome、platform 等直接创建宿主
164
- if (!targetInstance && !hostInstance) {
55
+ let serviceInstance = options.service;
56
+ // 若未传 service,服务端统一通过 createActionDock() 实例化,不再接受或处理外部传入的 Host 实体
57
+ if (!serviceInstance) {
165
58
  const scanLinkedPackages = options.scanLinkedPackages ?? !projectRoot;
166
- hostInstance = await createActionDockHost({
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
- autoLoadCurrentProject: true,
66
+ enableManagement: options.enableManagement,
174
67
  });
175
68
  }
176
- if (!targetInstance && hostInstance) {
177
- targetInstance = new LocalActionDockTarget(hostInstance);
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
- host: hostInstance,
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
- options.mcpHandler &&
131
+ mcpEndpointHandler &&
237
132
  (pathname === "/mcp" || pathname.startsWith("/mcp/"))) {
238
- if (!verifyBearerToken(req, token, options)) {
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. 业务领域路由分发(完全委托 Target / Host)
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
- host: hostInstance,
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 (targetInstance) {
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 hostInstance.close(stopOptions);
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
  },
@@ -1,5 +1,4 @@
1
- import type { ActionDockHost } from "../host/types.js";
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"),或关联的 ActionDockHost 宿主实例 */
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
- /** 关联的 ActionDockHost 宿主实例(若启动时传入或创建) */
84
- host?: ActionDockHost;
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
+ }
@@ -1,4 +1,4 @@
1
1
  export * from "./types.js";
2
2
  export * from "./local.js";
3
3
  export * from "./remote.js";
4
- export * from "./target.js";
4
+ export * from "./factory.js";
@@ -1,4 +1,4 @@
1
1
  export * from "./types.js";
2
2
  export * from "./local.js";
3
3
  export * from "./remote.js";
4
- export * from "./target.js";
4
+ export * from "./factory.js";
@@ -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
+ }