@actiondock/core 2.7.0 → 2.9.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 (243) hide show
  1. package/README.md +77 -64
  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 +106 -10
  18. package/dist/errors.js +105 -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 -24
  33. package/dist/index.js +19 -23
  34. package/dist/input/advice.d.ts +5 -1
  35. package/dist/input/advice.js +163 -214
  36. package/dist/input/describe.d.ts +1 -1
  37. package/dist/input/flat-errors.d.ts +5 -6
  38. package/dist/input/flat-errors.js +6 -6
  39. package/dist/input/flat-materializer.js +42 -44
  40. package/dist/invocation/index.d.ts +2 -0
  41. package/dist/invocation/index.js +2 -0
  42. package/dist/invocation/policy.d.ts +157 -0
  43. package/dist/invocation/policy.js +231 -0
  44. package/dist/invocation/types.d.ts +172 -0
  45. package/dist/invocation/types.js +97 -0
  46. package/dist/ipc/diagnostic.d.ts +0 -12
  47. package/dist/ipc/diagnostic.js +0 -21
  48. package/dist/ipc/host.d.ts +4 -4
  49. package/dist/ipc/host.js +44 -47
  50. package/dist/ipc/index.d.ts +1 -1
  51. package/dist/ipc/index.js +1 -1
  52. package/dist/ipc/service.d.ts +40 -0
  53. package/dist/ipc/service.js +349 -0
  54. package/dist/ipc/types.d.ts +21 -15
  55. package/dist/node/index.d.ts +1 -0
  56. package/dist/node/index.js +1 -0
  57. package/dist/node/module-loader.d.ts +63 -0
  58. package/dist/node/module-loader.js +112 -0
  59. package/dist/package/index.d.ts +23 -0
  60. package/dist/package/index.js +18 -0
  61. package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
  62. package/dist/{app/app.js → package/runtime.js} +140 -95
  63. package/dist/{app → package}/static-index.js +58 -41
  64. package/dist/package/storage-view.d.ts +13 -0
  65. package/dist/package/storage-view.js +22 -0
  66. package/dist/{app → package}/types.d.ts +76 -57
  67. package/dist/package/types.js +22 -0
  68. package/dist/platform/index.d.ts +1 -1
  69. package/dist/platform/index.js +1 -1
  70. package/dist/platform/node.d.ts +48 -0
  71. package/dist/platform/node.js +96 -0
  72. package/dist/platform/types.d.ts +0 -9
  73. package/dist/process/control-arbiter.d.ts +2 -1
  74. package/dist/process/control-arbiter.js +1 -2
  75. package/dist/process/driver.d.ts +9 -8
  76. package/dist/process/driver.js +11 -22
  77. package/dist/process/index.d.ts +2 -0
  78. package/dist/process/index.js +2 -0
  79. package/dist/process/managed-record.d.ts +2 -2
  80. package/dist/process/process-driver.d.ts +109 -0
  81. package/dist/process/process-driver.js +650 -0
  82. package/dist/process/process-executor.d.ts +47 -0
  83. package/dist/process/process-executor.js +296 -0
  84. package/dist/process/process-manager.js +48 -26
  85. package/dist/process/run-executor.js +12 -12
  86. package/dist/profile/client-actions.js +2 -2
  87. package/dist/profile/client-health.js +2 -2
  88. package/dist/profile/client-query.js +5 -6
  89. package/dist/profile/client-transport.d.ts +19 -17
  90. package/dist/profile/client-transport.js +47 -80
  91. package/dist/profile/client.d.ts +2 -2
  92. package/dist/profile/client.js +1 -1
  93. package/dist/profile/index.d.ts +1 -0
  94. package/dist/profile/index.js +1 -0
  95. package/dist/profile/manager.d.ts +5 -0
  96. package/dist/profile/manager.js +41 -6
  97. package/dist/project/closure.js +2 -2
  98. package/dist/project/index.d.ts +8 -1
  99. package/dist/project/index.js +10 -1
  100. package/dist/project/init.js +2 -2
  101. package/dist/project/loader.d.ts +1 -1
  102. package/dist/project/loader.js +26 -29
  103. package/dist/project/transactions.js +5 -10
  104. package/dist/project/types.d.ts +5 -0
  105. package/dist/registry/index.d.ts +3 -1
  106. package/dist/registry/index.js +2 -1
  107. package/dist/registry/lock.d.ts +28 -7
  108. package/dist/registry/lock.js +136 -16
  109. package/dist/registry/registry.d.ts +1 -5
  110. package/dist/registry/registry.js +1 -53
  111. package/dist/registry/scan.d.ts +0 -15
  112. package/dist/registry/scan.js +0 -59
  113. package/dist/registry/store.d.ts +42 -0
  114. package/dist/registry/store.js +43 -0
  115. package/dist/registry/types.d.ts +0 -24
  116. package/dist/runtime/action-collection.d.ts +1 -1
  117. package/dist/runtime/action-registry.d.ts +0 -4
  118. package/dist/runtime/action-registry.js +0 -7
  119. package/dist/runtime/context.js +5 -11
  120. package/dist/runtime/events.js +3 -6
  121. package/dist/runtime/identity.d.ts +22 -0
  122. package/dist/runtime/identity.js +10 -0
  123. package/dist/runtime/index.d.ts +1 -2
  124. package/dist/runtime/index.js +1 -2
  125. package/dist/runtime/module-loader.d.ts +2 -34
  126. package/dist/runtime/module-loader.js +1 -16
  127. package/dist/runtime/process.d.ts +6 -24
  128. package/dist/runtime/process.js +1 -118
  129. package/dist/runtime/run-persistence.js +2 -5
  130. package/dist/runtime/runner.d.ts +33 -93
  131. package/dist/runtime/runner.js +132 -364
  132. package/dist/runtime/standalone.d.ts +23 -8
  133. package/dist/runtime/standalone.js +100 -147
  134. package/dist/server/body.d.ts +16 -8
  135. package/dist/server/body.js +33 -16
  136. package/dist/server/dispatcher.d.ts +6 -10
  137. package/dist/server/dispatcher.js +24 -32
  138. package/dist/server/http-server.d.ts +87 -0
  139. package/dist/server/http-server.js +304 -0
  140. package/dist/server/index.d.ts +12 -0
  141. package/dist/server/index.js +11 -0
  142. package/dist/server/mcp-endpoint.d.ts +61 -0
  143. package/dist/server/mcp-endpoint.js +118 -0
  144. package/dist/server/policy.d.ts +138 -0
  145. package/dist/server/policy.js +368 -0
  146. package/dist/server/routes/actions.js +114 -64
  147. package/dist/server/routes/common.d.ts +18 -33
  148. package/dist/server/routes/common.js +45 -65
  149. package/dist/server/routes/config.d.ts +1 -1
  150. package/dist/server/routes/config.js +55 -65
  151. package/dist/server/routes/doctor.d.ts +1 -1
  152. package/dist/server/routes/doctor.js +13 -21
  153. package/dist/server/routes/health.d.ts +1 -1
  154. package/dist/server/routes/health.js +4 -5
  155. package/dist/server/routes/info.d.ts +2 -2
  156. package/dist/server/routes/info.js +17 -24
  157. package/dist/server/routes/playbooks.js +23 -36
  158. package/dist/server/routes/runs.js +151 -141
  159. package/dist/server/routes/state.d.ts +1 -1
  160. package/dist/server/routes/state.js +64 -63
  161. package/dist/server/security.d.ts +11 -0
  162. package/dist/server/security.js +36 -19
  163. package/dist/server/server.d.ts +2 -2
  164. package/dist/server/server.js +224 -238
  165. package/dist/server/types.d.ts +68 -21
  166. package/dist/service/factory.d.ts +12 -0
  167. package/dist/service/factory.js +85 -0
  168. package/dist/{target → service}/index.d.ts +1 -1
  169. package/dist/{target → service}/index.js +1 -1
  170. package/dist/service/local.d.ts +27 -0
  171. package/dist/service/local.js +138 -0
  172. package/dist/{target → service}/remote-errors.d.ts +3 -6
  173. package/dist/service/remote-errors.js +38 -0
  174. package/dist/{target → service}/remote-polling.d.ts +2 -2
  175. package/dist/{target → service}/remote-polling.js +8 -8
  176. package/dist/service/remote.d.ts +34 -0
  177. package/dist/service/remote.js +634 -0
  178. package/dist/service/sse-stream.d.ts +24 -0
  179. package/dist/service/sse-stream.js +139 -0
  180. package/dist/service/types.d.ts +272 -0
  181. package/dist/service/types.js +32 -0
  182. package/dist/storage/data-dir-lock.js +10 -5
  183. package/dist/storage/driver.d.ts +2 -1
  184. package/dist/storage/driver.js +3 -52
  185. package/dist/storage/index.d.ts +1 -0
  186. package/dist/storage/index.js +1 -0
  187. package/dist/storage/lock-core.d.ts +2 -6
  188. package/dist/storage/lock-core.js +4 -17
  189. package/dist/storage/params.d.ts +2 -8
  190. package/dist/storage/params.js +2 -8
  191. package/dist/storage/sqlite-driver.d.ts +40 -0
  192. package/dist/storage/sqlite-driver.js +116 -0
  193. package/dist/storage/sqlite.js +21 -6
  194. package/dist/storage/types.d.ts +4 -4
  195. package/dist/storage/types.js +2 -2
  196. package/dist/utils/index.d.ts +53 -0
  197. package/dist/utils/index.js +99 -4
  198. package/dist/utils/process.d.ts +10 -0
  199. package/dist/utils/process.js +21 -0
  200. package/dist/version.d.ts +1 -1
  201. package/dist/version.js +1 -1
  202. package/package.json +41 -3
  203. package/dist/app/index.d.ts +0 -2
  204. package/dist/app/index.js +0 -2
  205. package/dist/app/types.js +0 -1
  206. package/dist/catalog/action-index.d.ts +0 -9
  207. package/dist/catalog/action-index.js +0 -95
  208. package/dist/catalog/action-resolver.d.ts +0 -20
  209. package/dist/catalog/action-resolver.js +0 -95
  210. package/dist/catalog/location-registry.d.ts +0 -15
  211. package/dist/catalog/location-registry.js +0 -138
  212. package/dist/catalog/package-catalog.d.ts +0 -7
  213. package/dist/catalog/package-catalog.js +0 -77
  214. package/dist/catalog/types.d.ts +0 -68
  215. package/dist/catalog/types.js +0 -1
  216. package/dist/export/index.d.ts +0 -1
  217. package/dist/export/index.js +0 -1
  218. package/dist/export/templates.d.ts +0 -71
  219. package/dist/export/templates.js +0 -635
  220. package/dist/ipc/target.d.ts +0 -74
  221. package/dist/ipc/target.js +0 -365
  222. package/dist/platform/default.d.ts +0 -38
  223. package/dist/platform/default.js +0 -78
  224. package/dist/project/resolver.d.ts +0 -116
  225. package/dist/project/resolver.js +0 -376
  226. package/dist/registry/resolve.d.ts +0 -62
  227. package/dist/registry/resolve.js +0 -195
  228. package/dist/runtime/execution-manager.d.ts +0 -48
  229. package/dist/runtime/execution-manager.js +0 -66
  230. package/dist/runtime/package-runner-factory.d.ts +0 -82
  231. package/dist/runtime/package-runner-factory.js +0 -186
  232. package/dist/target/local.d.ts +0 -53
  233. package/dist/target/local.js +0 -349
  234. package/dist/target/remote-errors.js +0 -51
  235. package/dist/target/remote.d.ts +0 -86
  236. package/dist/target/remote.js +0 -818
  237. package/dist/target/target.d.ts +0 -6
  238. package/dist/target/target.js +0 -37
  239. package/dist/target/types.d.ts +0 -261
  240. package/dist/target/types.js +0 -35
  241. /package/dist/{app → package}/static-index.d.ts +0 -0
  242. /package/dist/{target → service}/sse-parser.d.ts +0 -0
  243. /package/dist/{target → service}/sse-parser.js +0 -0
@@ -0,0 +1,634 @@
1
+ import { parseActionRef } from "../catalog/resolve-action.js";
2
+ import { ActionDockError, ACTION_CANCELLED, CAPABILITY_UNAVAILABLE, INVALID_ARGUMENT, TIMEOUT, } from "../errors.js";
3
+ import { cancelRemoteRun, clearRemoteRuns, clearRemoteState, deleteRemoteConfig, deleteRemoteStateKey, executeRemoteAction, fetchRemoteActionShow, fetchRemoteActions, fetchRemoteConfig, fetchRemoteInfo, fetchRemotePlaybookShow, fetchRemotePlaybooks, fetchRemoteRun, fetchRemoteRuns, fetchRemoteStateList, getRemoteStateKey, setRemoteConfig, setRemoteStateKey, } from "../profile/client.js";
4
+ import { isRemoteStateKeyNotFound, wrapRemoteError } from "./remote-errors.js";
5
+ import { formatTerminalRunResult, pollRunCompletion } from "./remote-polling.js";
6
+ import { streamRemoteEvents } from "./sse-stream.js";
7
+ import { isTerminalRunStatus } from "../storage/types.js";
8
+ import { ACTIONDOCK_PROTOCOL_VERSION, PROTOCOL_UNSUPPORTED, SERVICE_CLOSED, ServiceError, } from "./types.js";
9
+ /**
10
+ * 远程 ActionDockService 端口实现。
11
+ * 封装与远端 ActionDock 服务的 HTTP / SSE 协议交互,
12
+ * 遵循统一的 Service Ports 契约。
13
+ */
14
+ export class RemoteActionDockService {
15
+ serverUrl;
16
+ token;
17
+ timeoutMs;
18
+ baseTimeoutMs;
19
+ allowInsecureHttp;
20
+ insecure;
21
+ dispatcher;
22
+ isClosed = false;
23
+ discovery;
24
+ execution;
25
+ runs;
26
+ events;
27
+ management;
28
+ constructor(options) {
29
+ if (!options.serverUrl) {
30
+ throw new ActionDockError(INVALID_ARGUMENT, "serverUrl is required for RemoteActionDockService");
31
+ }
32
+ this.serverUrl = options.serverUrl;
33
+ this.token = options.token;
34
+ this.timeoutMs = options.timeoutMs;
35
+ this.baseTimeoutMs = options.baseTimeoutMs ?? 60000;
36
+ this.allowInsecureHttp = options.allowInsecureHttp;
37
+ this.insecure = options.insecure;
38
+ this.dispatcher = options.dispatcher;
39
+ const self = this;
40
+ this.discovery = {
41
+ async listPackages() {
42
+ self.assertNotClosed();
43
+ let raw;
44
+ try {
45
+ raw = await fetchRemoteInfo(self.serverUrl, self.token, {
46
+ allowInsecureHttp: self.allowInsecureHttp,
47
+ insecure: self.insecure,
48
+ dispatcher: self.dispatcher,
49
+ });
50
+ }
51
+ catch (err) {
52
+ wrapRemoteError(err);
53
+ }
54
+ const protocolVersion = (raw && typeof raw === "object" && raw.protocolVersion) || ACTIONDOCK_PROTOCOL_VERSION;
55
+ if (protocolVersion && typeof protocolVersion === "string") {
56
+ const [remoteMajor] = protocolVersion.split(".");
57
+ const [currentMajor] = ACTIONDOCK_PROTOCOL_VERSION.split(".");
58
+ if (remoteMajor !== currentMajor) {
59
+ throw new ServiceError(PROTOCOL_UNSUPPORTED, `PROTOCOL_UNSUPPORTED: Remote server protocol version '${protocolVersion}' is incompatible with expected '${ACTIONDOCK_PROTOCOL_VERSION}'`);
60
+ }
61
+ }
62
+ if (Array.isArray(raw)) {
63
+ return raw;
64
+ }
65
+ if (raw && typeof raw === "object") {
66
+ if (Array.isArray(raw.packages)) {
67
+ return raw.packages;
68
+ }
69
+ if (raw.packages && typeof raw.packages === "object") {
70
+ return Object.values(raw.packages);
71
+ }
72
+ }
73
+ return [];
74
+ },
75
+ async listActions(opts) {
76
+ self.assertNotClosed();
77
+ const rawList = await fetchRemoteActions(self.serverUrl, self.token, opts?.query, {
78
+ allowInsecureHttp: self.allowInsecureHttp,
79
+ insecure: self.insecure,
80
+ dispatcher: self.dispatcher,
81
+ });
82
+ let summaries = rawList.map((item) => ({
83
+ id: item.id,
84
+ description: item.description,
85
+ tags: item.tags,
86
+ inputSchema: item.inputSchema,
87
+ outputSchema: item.outputSchema,
88
+ packageId: item.packageId,
89
+ }));
90
+ if (opts?.prefix) {
91
+ summaries = summaries.filter((s) => s.id.startsWith(opts.prefix));
92
+ }
93
+ if (opts?.tags && opts.tags.length > 0) {
94
+ summaries = summaries.filter((s) => opts.tags.every((t) => s.tags?.includes(t)));
95
+ }
96
+ return summaries;
97
+ },
98
+ async describeAction(ref) {
99
+ self.assertNotClosed();
100
+ let parsed;
101
+ try {
102
+ parsed = parseActionRef(ref);
103
+ }
104
+ catch {
105
+ parsed = typeof ref === "object" ? ref : { actionId: ref };
106
+ }
107
+ const actionId = parsed.packageId
108
+ ? `${parsed.packageId}/${parsed.actionId}`
109
+ : parsed.actionId;
110
+ const raw = await fetchRemoteActionShow(self.serverUrl, actionId, self.token, {
111
+ allowInsecureHttp: self.allowInsecureHttp,
112
+ insecure: self.insecure,
113
+ dispatcher: self.dispatcher,
114
+ });
115
+ return {
116
+ id: raw.id,
117
+ description: raw.description,
118
+ inputSchema: raw.inputSchema,
119
+ outputSchema: raw.outputSchema,
120
+ tags: raw.tags,
121
+ annotations: raw.annotations,
122
+ uses: raw.uses,
123
+ entry: raw.entry,
124
+ filePath: raw.filePath,
125
+ packageId: raw.packageId ?? parsed.packageId,
126
+ };
127
+ },
128
+ async listPlaybooks(opts) {
129
+ self.assertNotClosed();
130
+ const rawList = await fetchRemotePlaybooks(self.serverUrl, self.token, {
131
+ ...opts,
132
+ allowInsecureHttp: self.allowInsecureHttp,
133
+ insecure: self.insecure,
134
+ dispatcher: self.dispatcher,
135
+ });
136
+ return rawList.map((item) => ({
137
+ id: item.id,
138
+ description: item.description,
139
+ actions: item.actions,
140
+ packageId: item.packageId,
141
+ filePath: item.filePath,
142
+ }));
143
+ },
144
+ async describePlaybook(id) {
145
+ self.assertNotClosed();
146
+ const raw = await fetchRemotePlaybookShow(self.serverUrl, id, self.token, {
147
+ allowInsecureHttp: self.allowInsecureHttp,
148
+ insecure: self.insecure,
149
+ dispatcher: self.dispatcher,
150
+ });
151
+ const parsedPkgId = id.includes("/") ? id.slice(0, id.lastIndexOf("/")) : undefined;
152
+ return {
153
+ id: raw.id,
154
+ description: raw.description,
155
+ actions: raw.actions,
156
+ filePath: raw.filePath,
157
+ content: raw.content,
158
+ packageId: raw.packageId ?? parsedPkgId,
159
+ };
160
+ },
161
+ };
162
+ this.execution = {
163
+ async run(ref, input, opts) {
164
+ self.assertNotClosed();
165
+ let parsed;
166
+ try {
167
+ parsed = parseActionRef(ref);
168
+ }
169
+ catch {
170
+ parsed = typeof ref === "object" ? ref : { actionId: String(ref) };
171
+ }
172
+ const actionId = parsed.packageId
173
+ ? `${parsed.packageId}/${parsed.actionId}`
174
+ : parsed.actionId;
175
+ return executeRemoteAction(self.serverUrl, actionId, (input ?? {}), {
176
+ configOverrides: opts?.config,
177
+ token: self.token,
178
+ timeoutMs: opts?.timeoutMs ?? self.timeoutMs,
179
+ signal: opts?.signal,
180
+ requestId: opts?.requestId,
181
+ async: false,
182
+ allowInsecureHttp: self.allowInsecureHttp,
183
+ insecure: self.insecure,
184
+ dispatcher: self.dispatcher,
185
+ });
186
+ },
187
+ async start(ref, input, opts) {
188
+ self.assertNotClosed();
189
+ let parsed;
190
+ try {
191
+ parsed = parseActionRef(ref);
192
+ }
193
+ catch {
194
+ parsed = typeof ref === "object" ? ref : { actionId: String(ref) };
195
+ }
196
+ const actionId = parsed.packageId
197
+ ? `${parsed.packageId}/${parsed.actionId}`
198
+ : parsed.actionId;
199
+ const res = await executeRemoteAction(self.serverUrl, actionId, (input ?? {}), {
200
+ configOverrides: opts?.config,
201
+ token: self.token,
202
+ timeoutMs: opts?.timeoutMs ?? self.timeoutMs,
203
+ signal: opts?.signal,
204
+ requestId: opts?.requestId,
205
+ async: true,
206
+ allowInsecureHttp: self.allowInsecureHttp,
207
+ insecure: self.insecure,
208
+ dispatcher: self.dispatcher,
209
+ });
210
+ if (!res.ok) {
211
+ return {
212
+ runId: res.runId,
213
+ status: "failed",
214
+ result: Promise.resolve(res),
215
+ };
216
+ }
217
+ const runId = res.runId || res.data?.runId;
218
+ const status = res.status || res.data?.status || "running";
219
+ return {
220
+ runId,
221
+ status,
222
+ result: self.waitForRunCompletion(runId, opts?.signal, opts?.timeoutMs),
223
+ };
224
+ },
225
+ };
226
+ this.runs = {
227
+ async list(query) {
228
+ self.assertNotClosed();
229
+ try {
230
+ const res = await fetchRemoteRuns(self.serverUrl, self.token, {
231
+ packageId: query?.packageId,
232
+ actionId: query?.actionId,
233
+ status: query?.status,
234
+ intent: query?.intent,
235
+ limit: query?.limit,
236
+ allowInsecureHttp: self.allowInsecureHttp,
237
+ insecure: self.insecure,
238
+ dispatcher: self.dispatcher,
239
+ });
240
+ return res.items || [];
241
+ }
242
+ catch (err) {
243
+ wrapRemoteError(err);
244
+ }
245
+ },
246
+ async get(runId) {
247
+ self.assertNotClosed();
248
+ try {
249
+ return await fetchRemoteRun(self.serverUrl, runId, self.token, {
250
+ allowInsecureHttp: self.allowInsecureHttp,
251
+ insecure: self.insecure,
252
+ dispatcher: self.dispatcher,
253
+ });
254
+ }
255
+ catch (err) {
256
+ const code = String(err?.code || "");
257
+ if (code === "RUN_NOT_FOUND" || code === "NOT_FOUND" || err?.status === 404) {
258
+ return undefined;
259
+ }
260
+ throw err;
261
+ }
262
+ },
263
+ async cancel(runId, reason) {
264
+ self.assertNotClosed();
265
+ try {
266
+ const res = await cancelRemoteRun(self.serverUrl, runId, self.token, reason, {
267
+ allowInsecureHttp: self.allowInsecureHttp,
268
+ insecure: self.insecure,
269
+ dispatcher: self.dispatcher,
270
+ });
271
+ return { outcome: "requested", runId: res.runId };
272
+ }
273
+ catch (err) {
274
+ const code = String(err?.code || "");
275
+ if (code === "RUN_ALREADY_FINISHED") {
276
+ let status = err?.errorData?.status || err?.details?.status;
277
+ if (!status) {
278
+ try {
279
+ const run = await self.runs.get(runId);
280
+ if (run?.status) {
281
+ status = run.status;
282
+ }
283
+ }
284
+ catch { }
285
+ }
286
+ return { outcome: "already_terminal", runId, status: status || "failed" };
287
+ }
288
+ if (code === "RUN_NOT_FOUND" || code === "NOT_FOUND" || err?.status === 404) {
289
+ return { outcome: "not_found", runId };
290
+ }
291
+ throw err;
292
+ }
293
+ },
294
+ async clear(opts) {
295
+ self.assertNotClosed();
296
+ try {
297
+ const res = await clearRemoteRuns(self.serverUrl, self.token, {
298
+ ...opts,
299
+ allowInsecureHttp: self.allowInsecureHttp,
300
+ insecure: self.insecure,
301
+ dispatcher: self.dispatcher,
302
+ });
303
+ return res.clearedCount ?? 0;
304
+ }
305
+ catch (err) {
306
+ wrapRemoteError(err);
307
+ }
308
+ },
309
+ };
310
+ this.events = {
311
+ events(runId, opts) {
312
+ self.assertNotClosed();
313
+ async function* stream() {
314
+ self.assertNotClosed();
315
+ for await (const event of streamRemoteEvents(self.serverUrl, runId, self.token, {
316
+ ...opts,
317
+ allowInsecureHttp: self.allowInsecureHttp,
318
+ insecure: self.insecure,
319
+ dispatcher: self.dispatcher,
320
+ })) {
321
+ self.assertNotClosed();
322
+ yield event;
323
+ }
324
+ }
325
+ return stream();
326
+ },
327
+ };
328
+ if (options?.enableManagement !== false) {
329
+ this.management = {
330
+ config: {
331
+ async get(packageId, key) {
332
+ self.assertNotClosed();
333
+ try {
334
+ const list = await self.management.config.list(packageId);
335
+ const found = list.find((c) => c.key === key);
336
+ if (found) {
337
+ return found;
338
+ }
339
+ return {
340
+ key,
341
+ configured: false,
342
+ secret: false,
343
+ source: "default",
344
+ value: undefined,
345
+ };
346
+ }
347
+ catch (err) {
348
+ wrapRemoteError(err);
349
+ }
350
+ },
351
+ async set(packageId, key, value) {
352
+ self.assertNotClosed();
353
+ try {
354
+ await setRemoteConfig(self.serverUrl, key, value, self.token, packageId || undefined, {
355
+ allowInsecureHttp: self.allowInsecureHttp,
356
+ insecure: self.insecure,
357
+ dispatcher: self.dispatcher,
358
+ });
359
+ }
360
+ catch (err) {
361
+ wrapRemoteError(err);
362
+ }
363
+ },
364
+ async delete(packageId, key) {
365
+ self.assertNotClosed();
366
+ try {
367
+ const res = await deleteRemoteConfig(self.serverUrl, key, self.token, packageId || undefined, {
368
+ allowInsecureHttp: self.allowInsecureHttp,
369
+ insecure: self.insecure,
370
+ dispatcher: self.dispatcher,
371
+ });
372
+ return Boolean(res?.deleted ?? true);
373
+ }
374
+ catch (err) {
375
+ wrapRemoteError(err);
376
+ }
377
+ },
378
+ async list(packageId) {
379
+ self.assertNotClosed();
380
+ try {
381
+ const res = await fetchRemoteConfig(self.serverUrl, self.token, packageId || undefined, {
382
+ allowInsecureHttp: self.allowInsecureHttp,
383
+ insecure: self.insecure,
384
+ dispatcher: self.dispatcher,
385
+ });
386
+ if (Array.isArray(res))
387
+ return res;
388
+ if (Array.isArray(res?.items))
389
+ return res.items;
390
+ if (Array.isArray(res?.config))
391
+ return res.config;
392
+ const values = res?.values || {};
393
+ const declared = res?.declared || {};
394
+ const defaultSource = packageId === "global" ? "global" : "package";
395
+ return Object.entries(values).map(([k, v]) => ({
396
+ key: k,
397
+ configured: v !== undefined,
398
+ secret: Boolean(declared[k]?.secret),
399
+ source: defaultSource,
400
+ value: v,
401
+ }));
402
+ }
403
+ catch (err) {
404
+ wrapRemoteError(err);
405
+ }
406
+ },
407
+ },
408
+ state: {
409
+ async get(packageId, actionId, key, opts) {
410
+ self.assertNotClosed();
411
+ try {
412
+ const res = await getRemoteStateKey(self.serverUrl, key, self.token, {
413
+ package: packageId || undefined,
414
+ action: actionId || undefined,
415
+ namespace: opts?.namespace,
416
+ allowInsecureHttp: self.allowInsecureHttp,
417
+ insecure: self.insecure,
418
+ dispatcher: self.dispatcher,
419
+ });
420
+ if (res === undefined)
421
+ return undefined;
422
+ if (opts?.detail) {
423
+ return res;
424
+ }
425
+ return (res?.value !== undefined ? res.value : res);
426
+ }
427
+ catch (err) {
428
+ if (isRemoteStateKeyNotFound(err)) {
429
+ return undefined;
430
+ }
431
+ wrapRemoteError(err);
432
+ }
433
+ },
434
+ async set(packageId, actionId, key, value, opts) {
435
+ self.assertNotClosed();
436
+ try {
437
+ await setRemoteStateKey(self.serverUrl, key, value, self.token, {
438
+ package: packageId || undefined,
439
+ action: actionId || undefined,
440
+ namespace: opts?.namespace,
441
+ ttl: opts?.ttl,
442
+ allowInsecureHttp: self.allowInsecureHttp,
443
+ insecure: self.insecure,
444
+ dispatcher: self.dispatcher,
445
+ });
446
+ }
447
+ catch (err) {
448
+ wrapRemoteError(err);
449
+ }
450
+ },
451
+ async delete(packageId, actionId, key, opts) {
452
+ self.assertNotClosed();
453
+ try {
454
+ const res = await deleteRemoteStateKey(self.serverUrl, key, self.token, {
455
+ package: packageId || undefined,
456
+ action: actionId || undefined,
457
+ namespace: opts?.namespace,
458
+ allowInsecureHttp: self.allowInsecureHttp,
459
+ insecure: self.insecure,
460
+ dispatcher: self.dispatcher,
461
+ });
462
+ return Boolean(res?.deleted ?? true);
463
+ }
464
+ catch (err) {
465
+ if (isRemoteStateKeyNotFound(err)) {
466
+ return false;
467
+ }
468
+ wrapRemoteError(err);
469
+ }
470
+ },
471
+ async list(packageId, actionId, opts) {
472
+ self.assertNotClosed();
473
+ try {
474
+ const res = await fetchRemoteStateList(self.serverUrl, self.token, {
475
+ package: packageId || undefined,
476
+ action: actionId || undefined,
477
+ namespace: opts?.namespace,
478
+ prefix: opts?.prefix,
479
+ allowInsecureHttp: self.allowInsecureHttp,
480
+ insecure: self.insecure,
481
+ dispatcher: self.dispatcher,
482
+ });
483
+ return res.keys || [];
484
+ }
485
+ catch (err) {
486
+ wrapRemoteError(err);
487
+ }
488
+ },
489
+ async clear(packageId, actionId, opts) {
490
+ self.assertNotClosed();
491
+ try {
492
+ const res = await clearRemoteState(self.serverUrl, self.token, {
493
+ package: packageId || undefined,
494
+ action: actionId || undefined,
495
+ namespace: opts?.namespace,
496
+ prefix: opts?.prefix,
497
+ all: opts?.all,
498
+ allowInsecureHttp: self.allowInsecureHttp,
499
+ insecure: self.insecure,
500
+ dispatcher: self.dispatcher,
501
+ });
502
+ return res.clearedCount ?? 0;
503
+ }
504
+ catch (err) {
505
+ wrapRemoteError(err);
506
+ }
507
+ },
508
+ async listEntries(_packageId, _opts) {
509
+ self.assertNotClosed();
510
+ throw new ServiceError(CAPABILITY_UNAVAILABLE, "CAPABILITY_UNAVAILABLE: listStateEntries is not supported on remote service");
511
+ },
512
+ },
513
+ };
514
+ }
515
+ }
516
+ assertNotClosed() {
517
+ if (this.isClosed) {
518
+ throw new ServiceError(SERVICE_CLOSED, "RemoteActionDockService is closed");
519
+ }
520
+ }
521
+ async info() {
522
+ return this.discovery.listPackages();
523
+ }
524
+ async waitForRunCompletion(runId, signal, timeoutMs) {
525
+ const startTime = Date.now();
526
+ const maxWaitMs = Math.max(this.baseTimeoutMs, timeoutMs ?? 0);
527
+ // 服务已关闭时的统一失败结果
528
+ const closedResult = () => ({
529
+ ok: false,
530
+ runId,
531
+ error: {
532
+ code: SERVICE_CLOSED,
533
+ message: "RemoteActionDockService is closed",
534
+ },
535
+ });
536
+ // 外部取消信号已触发时的统一取消结果
537
+ const cancelledResult = () => ({
538
+ ok: false,
539
+ runId,
540
+ error: {
541
+ code: ACTION_CANCELLED,
542
+ message: "Action execution was cancelled",
543
+ },
544
+ });
545
+ if (signal?.aborted) {
546
+ return cancelledResult();
547
+ }
548
+ if (this.isClosed) {
549
+ return closedResult();
550
+ }
551
+ const internalController = new AbortController();
552
+ let sseTimedOut = false;
553
+ let timer;
554
+ if (maxWaitMs > 0 && maxWaitMs !== Infinity) {
555
+ timer = setTimeout(() => {
556
+ sseTimedOut = true;
557
+ internalController.abort();
558
+ }, maxWaitMs);
559
+ }
560
+ const onAbort = () => {
561
+ internalController.abort();
562
+ };
563
+ if (signal) {
564
+ signal.addEventListener("abort", onAbort, { once: true });
565
+ }
566
+ try {
567
+ for await (const evt of this.events.events(runId, { signal: internalController.signal })) {
568
+ if (evt.type === "finish") {
569
+ const res = evt.result || evt.data || evt;
570
+ if (typeof res?.ok === "boolean") {
571
+ return res;
572
+ }
573
+ }
574
+ }
575
+ }
576
+ catch (err) {
577
+ if (err?.code === SERVICE_CLOSED || this.isClosed) {
578
+ return closedResult();
579
+ }
580
+ if (!signal?.aborted && !sseTimedOut) {
581
+ console.warn(`[ActionDock] SSE event stream unavailable for run '${runId}', falling back to polling: ${err?.message || String(err)}`);
582
+ }
583
+ }
584
+ finally {
585
+ if (timer) {
586
+ clearTimeout(timer);
587
+ }
588
+ if (signal) {
589
+ signal.removeEventListener("abort", onAbort);
590
+ }
591
+ }
592
+ if (signal?.aborted) {
593
+ return cancelledResult();
594
+ }
595
+ const remainingWaitMs = Math.max(0, maxWaitMs - (Date.now() - startTime));
596
+ if (remainingWaitMs <= 0) {
597
+ if (this.isClosed) {
598
+ return closedResult();
599
+ }
600
+ try {
601
+ const run = await this.runs.get(runId);
602
+ if (run && isTerminalRunStatus(run.status)) {
603
+ return formatTerminalRunResult(run, runId);
604
+ }
605
+ }
606
+ catch (err) {
607
+ if (err?.code === SERVICE_CLOSED || this.isClosed) {
608
+ return closedResult();
609
+ }
610
+ throw err;
611
+ }
612
+ const waitedMs = Date.now() - startTime;
613
+ return {
614
+ ok: false,
615
+ runId,
616
+ error: {
617
+ code: TIMEOUT,
618
+ message: `Timed out waiting for run '${runId}' completion after ${waitedMs}ms`,
619
+ },
620
+ };
621
+ }
622
+ return pollRunCompletion({
623
+ baseTimeoutMs: this.baseTimeoutMs,
624
+ isClosed: () => this.isClosed,
625
+ getRun: (id) => this.runs.get(id),
626
+ }, runId, signal, remainingWaitMs, startTime, maxWaitMs);
627
+ }
628
+ async close(_options) {
629
+ if (this.isClosed) {
630
+ return;
631
+ }
632
+ this.isClosed = true;
633
+ }
634
+ }
@@ -0,0 +1,24 @@
1
+ import type { ExecutionEvent } from "@actiondock/sdk";
2
+ import { type SseMessage } from "./sse-parser.js";
3
+ /**
4
+ * 将 SSE 消息载荷解码为统一执行事件。
5
+ *
6
+ * 非 JSON 数据行直接忽略;finish 事件取 data.result 字段,其余事件字段展开合并。
7
+ */
8
+ export declare function decodeExecutionEvent(msg: SseMessage, runId: string): ExecutionEvent | undefined;
9
+ /**
10
+ * 订阅远端运行事件流(Server-Sent Events)。
11
+ *
12
+ * 候选路由探测与自动回退:优先尝试标准 v2 路由 /api/v2/runs/:runId/events,
13
+ * 失败时回退至既有路由 /api/v2/runs/:runId/stream;
14
+ * 全部候选均不可用(网络异常或非流式响应)时抛出携带各候选 URL 与
15
+ * 失败原因的 REMOTE_STREAM_UNAVAILABLE 聚合错误,严禁以空流伪装正常。
16
+ */
17
+ export declare function streamRemoteEvents(serverUrl: string, runId: string, token?: string, options?: {
18
+ after?: number | string;
19
+ signal?: AbortSignal;
20
+ maxQueueSize?: number;
21
+ allowInsecureHttp?: boolean;
22
+ insecure?: boolean;
23
+ dispatcher?: unknown;
24
+ }): AsyncIterable<ExecutionEvent>;