@actiondock/core 2.0.11 → 2.2.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 (258) hide show
  1. package/README.md +61 -30
  2. package/dist/app/app.d.ts +73 -0
  3. package/dist/app/app.js +700 -0
  4. package/dist/app/index.d.ts +2 -0
  5. package/dist/app/index.js +2 -0
  6. package/dist/app/types.d.ts +283 -0
  7. package/dist/app/types.js +1 -0
  8. package/dist/catalog/action-index.d.ts +9 -0
  9. package/dist/catalog/action-index.js +93 -0
  10. package/dist/catalog/action-resolver.d.ts +20 -0
  11. package/dist/catalog/action-resolver.js +95 -0
  12. package/dist/catalog/index.d.ts +5 -0
  13. package/dist/catalog/index.js +5 -0
  14. package/dist/catalog/location-registry.d.ts +15 -0
  15. package/dist/catalog/location-registry.js +138 -0
  16. package/dist/catalog/package-catalog.d.ts +7 -0
  17. package/dist/catalog/package-catalog.js +76 -0
  18. package/dist/catalog/types.d.ts +68 -0
  19. package/dist/catalog/types.js +1 -0
  20. package/dist/doctor/doctor.d.ts +7 -0
  21. package/dist/doctor/doctor.js +613 -0
  22. package/dist/doctor/index.d.ts +2 -0
  23. package/dist/doctor/index.js +2 -0
  24. package/dist/doctor/types.d.ts +23 -0
  25. package/dist/doctor/types.js +1 -0
  26. package/dist/errors.d.ts +122 -0
  27. package/dist/errors.js +123 -0
  28. package/dist/execution/index.d.ts +2 -0
  29. package/dist/execution/index.js +2 -0
  30. package/dist/execution/service.d.ts +79 -0
  31. package/dist/execution/service.js +633 -0
  32. package/dist/execution/types.d.ts +131 -0
  33. package/dist/execution/types.js +1 -0
  34. package/dist/export/index.d.ts +1 -0
  35. package/dist/export/index.js +1 -0
  36. package/dist/export/templates.d.ts +71 -0
  37. package/dist/export/templates.js +621 -0
  38. package/dist/filter/index.d.ts +1 -0
  39. package/dist/filter/index.js +1 -0
  40. package/dist/filter/intent.d.ts +33 -0
  41. package/dist/filter/intent.js +123 -0
  42. package/dist/host/host.d.ts +55 -0
  43. package/dist/host/host.js +740 -0
  44. package/dist/host/index.d.ts +2 -0
  45. package/dist/host/index.js +2 -0
  46. package/dist/host/types.d.ts +81 -0
  47. package/dist/host/types.js +1 -0
  48. package/dist/index.d.ts +21 -0
  49. package/dist/index.js +20 -0
  50. package/dist/ipc/diagnostic.d.ts +65 -0
  51. package/dist/ipc/diagnostic.js +129 -0
  52. package/dist/ipc/host.d.ts +7 -0
  53. package/dist/ipc/host.js +93 -0
  54. package/dist/ipc/index.d.ts +4 -0
  55. package/dist/ipc/index.js +4 -0
  56. package/dist/ipc/target.d.ts +56 -0
  57. package/dist/ipc/target.js +297 -0
  58. package/dist/ipc/types.d.ts +42 -0
  59. package/dist/ipc/types.js +1 -0
  60. package/dist/platform/default.d.ts +32 -0
  61. package/dist/platform/default.js +40 -0
  62. package/dist/platform/index.d.ts +3 -0
  63. package/dist/platform/index.js +3 -0
  64. package/dist/platform/node-fs.d.ts +37 -0
  65. package/dist/platform/node-fs.js +81 -0
  66. package/dist/platform/types.d.ts +104 -0
  67. package/dist/platform/types.js +1 -0
  68. package/dist/profile/client.d.ts +162 -0
  69. package/dist/profile/client.js +467 -0
  70. package/dist/profile/index.d.ts +3 -0
  71. package/dist/profile/index.js +3 -0
  72. package/dist/profile/manager.d.ts +47 -0
  73. package/dist/profile/manager.js +294 -0
  74. package/dist/profile/types.d.ts +61 -0
  75. package/dist/profile/types.js +1 -0
  76. package/dist/project/closure.d.ts +25 -0
  77. package/dist/project/closure.js +68 -0
  78. package/dist/project/digest.d.ts +29 -0
  79. package/dist/project/digest.js +324 -0
  80. package/dist/project/index.d.ts +10 -0
  81. package/dist/project/index.js +10 -0
  82. package/dist/project/init.d.ts +26 -0
  83. package/dist/project/init.js +175 -0
  84. package/dist/project/loader.d.ts +99 -0
  85. package/dist/project/loader.js +484 -0
  86. package/dist/project/lockfile.d.ts +55 -0
  87. package/dist/project/lockfile.js +175 -0
  88. package/dist/project/manifest.d.ts +22 -0
  89. package/dist/project/manifest.js +220 -0
  90. package/dist/project/resolver.d.ts +116 -0
  91. package/dist/project/resolver.js +376 -0
  92. package/dist/project/transactions.d.ts +103 -0
  93. package/dist/project/transactions.js +1203 -0
  94. package/dist/project/types-generator.d.ts +33 -0
  95. package/dist/project/types-generator.js +168 -0
  96. package/dist/project/types.d.ts +107 -0
  97. package/dist/project/types.js +1 -0
  98. package/dist/registry/index.d.ts +5 -0
  99. package/dist/registry/index.js +5 -0
  100. package/dist/registry/lock.d.ts +27 -0
  101. package/dist/registry/lock.js +93 -0
  102. package/dist/registry/registry.d.ts +45 -0
  103. package/dist/registry/registry.js +611 -0
  104. package/dist/registry/resolve.d.ts +62 -0
  105. package/dist/registry/resolve.js +195 -0
  106. package/dist/registry/scan.d.ts +38 -0
  107. package/dist/registry/scan.js +135 -0
  108. package/dist/registry/types.d.ts +117 -0
  109. package/dist/registry/types.js +1 -0
  110. package/dist/runtime/action-collection.d.ts +27 -0
  111. package/dist/runtime/action-collection.js +57 -0
  112. package/dist/runtime/clock.d.ts +19 -0
  113. package/dist/runtime/clock.js +17 -0
  114. package/dist/runtime/context.d.ts +86 -0
  115. package/dist/runtime/context.js +242 -0
  116. package/dist/runtime/env.d.ts +56 -0
  117. package/dist/runtime/env.js +159 -0
  118. package/dist/runtime/events.d.ts +93 -0
  119. package/dist/runtime/events.js +604 -0
  120. package/dist/runtime/execution-manager.d.ts +48 -0
  121. package/dist/runtime/execution-manager.js +66 -0
  122. package/dist/runtime/index.d.ts +10 -0
  123. package/dist/runtime/index.js +10 -0
  124. package/dist/runtime/module-loader.d.ts +34 -0
  125. package/dist/runtime/module-loader.js +16 -0
  126. package/dist/runtime/process.d.ts +9 -0
  127. package/dist/runtime/process.js +146 -0
  128. package/dist/runtime/runner.d.ts +293 -0
  129. package/dist/runtime/runner.js +984 -0
  130. package/dist/runtime/standalone.d.ts +89 -0
  131. package/dist/runtime/standalone.js +536 -0
  132. package/dist/schema/validator.d.ts +28 -0
  133. package/dist/schema/validator.js +116 -0
  134. package/dist/server/body.d.ts +40 -0
  135. package/dist/server/body.js +93 -0
  136. package/dist/server/index.d.ts +5 -0
  137. package/dist/server/index.js +5 -0
  138. package/dist/server/routes/actions.d.ts +5 -0
  139. package/dist/server/routes/actions.js +298 -0
  140. package/dist/server/routes/common.d.ts +47 -0
  141. package/dist/server/routes/common.js +104 -0
  142. package/dist/server/routes/config.d.ts +6 -0
  143. package/dist/server/routes/config.js +173 -0
  144. package/dist/server/routes/doctor.d.ts +5 -0
  145. package/dist/server/routes/doctor.js +63 -0
  146. package/dist/server/routes/health.d.ts +5 -0
  147. package/dist/server/routes/health.js +35 -0
  148. package/dist/server/routes/index.d.ts +9 -0
  149. package/dist/server/routes/index.js +9 -0
  150. package/dist/server/routes/info.d.ts +7 -0
  151. package/dist/server/routes/info.js +158 -0
  152. package/dist/server/routes/playbooks.d.ts +5 -0
  153. package/dist/server/routes/playbooks.js +134 -0
  154. package/dist/server/routes/runs.d.ts +5 -0
  155. package/dist/server/routes/runs.js +343 -0
  156. package/dist/server/routes/state.d.ts +6 -0
  157. package/dist/server/routes/state.js +169 -0
  158. package/dist/server/security.d.ts +44 -0
  159. package/dist/server/security.js +101 -0
  160. package/dist/server/server.d.ts +15 -0
  161. package/dist/server/server.js +355 -0
  162. package/dist/server/types.d.ts +78 -0
  163. package/dist/server/types.js +1 -0
  164. package/dist/storage/data-dir-lock.d.ts +119 -0
  165. package/dist/storage/data-dir-lock.js +1016 -0
  166. package/dist/storage/driver.d.ts +9 -0
  167. package/dist/storage/driver.js +59 -0
  168. package/dist/storage/index.d.ts +64 -0
  169. package/dist/storage/index.js +98 -0
  170. package/dist/storage/lazy.d.ts +8 -0
  171. package/dist/storage/lazy.js +44 -0
  172. package/dist/storage/mask.d.ts +26 -0
  173. package/dist/storage/mask.js +48 -0
  174. package/dist/storage/params.d.ts +13 -0
  175. package/dist/storage/params.js +32 -0
  176. package/dist/storage/sqlite.d.ts +79 -0
  177. package/dist/storage/sqlite.js +689 -0
  178. package/dist/storage/types.d.ts +172 -0
  179. package/dist/storage/types.js +14 -0
  180. package/dist/target/index.d.ts +4 -0
  181. package/dist/target/index.js +4 -0
  182. package/dist/target/local.d.ts +52 -0
  183. package/dist/target/local.js +343 -0
  184. package/dist/target/remote.d.ts +76 -0
  185. package/dist/target/remote.js +839 -0
  186. package/dist/target/target.d.ts +6 -0
  187. package/dist/target/target.js +35 -0
  188. package/dist/target/types.d.ts +246 -0
  189. package/dist/target/types.js +34 -0
  190. package/dist/utils/index.d.ts +49 -0
  191. package/dist/utils/index.js +180 -0
  192. package/dist/version.d.ts +4 -0
  193. package/dist/version.js +4 -0
  194. package/package.json +13 -13
  195. package/src/build/index.ts +0 -1
  196. package/src/build/templates.ts +0 -59
  197. package/src/catalog/action-index.ts +0 -92
  198. package/src/catalog/action-resolver.ts +0 -120
  199. package/src/catalog/index.ts +0 -5
  200. package/src/catalog/location-registry.ts +0 -134
  201. package/src/catalog/package-catalog.ts +0 -87
  202. package/src/catalog/types.ts +0 -75
  203. package/src/doctor/doctor.ts +0 -419
  204. package/src/doctor/index.ts +0 -2
  205. package/src/doctor/types.ts +0 -25
  206. package/src/execution/index.ts +0 -2
  207. package/src/execution/service.ts +0 -322
  208. package/src/execution/types.ts +0 -73
  209. package/src/export/index.ts +0 -1
  210. package/src/export/templates.ts +0 -590
  211. package/src/filter/index.ts +0 -1
  212. package/src/filter/intent.ts +0 -154
  213. package/src/index.ts +0 -16
  214. package/src/profile/client.ts +0 -552
  215. package/src/profile/index.ts +0 -3
  216. package/src/profile/manager.ts +0 -341
  217. package/src/profile/types.ts +0 -71
  218. package/src/project/index.ts +0 -4
  219. package/src/project/init.ts +0 -242
  220. package/src/project/loader.ts +0 -479
  221. package/src/project/manifest.ts +0 -299
  222. package/src/project/types.ts +0 -141
  223. package/src/registry/index.ts +0 -2
  224. package/src/registry/registry.ts +0 -940
  225. package/src/registry/types.ts +0 -127
  226. package/src/runtime/clock.ts +0 -41
  227. package/src/runtime/context.ts +0 -259
  228. package/src/runtime/env.ts +0 -172
  229. package/src/runtime/events.ts +0 -142
  230. package/src/runtime/execution-manager.ts +0 -74
  231. package/src/runtime/index.ts +0 -10
  232. package/src/runtime/module-loader.ts +0 -67
  233. package/src/runtime/process.ts +0 -245
  234. package/src/runtime/runner.ts +0 -527
  235. package/src/runtime/standalone.ts +0 -429
  236. package/src/schema/validator.ts +0 -61
  237. package/src/server/body.ts +0 -112
  238. package/src/server/index.ts +0 -7
  239. package/src/server/routes/actions.ts +0 -262
  240. package/src/server/routes/common.ts +0 -126
  241. package/src/server/routes/config.ts +0 -147
  242. package/src/server/routes/doctor.ts +0 -29
  243. package/src/server/routes/health.ts +0 -40
  244. package/src/server/routes/index.ts +0 -9
  245. package/src/server/routes/info.ts +0 -221
  246. package/src/server/routes/playbooks.ts +0 -109
  247. package/src/server/routes/runs.ts +0 -301
  248. package/src/server/routes/state.ts +0 -133
  249. package/src/server/runtime-registry.ts +0 -115
  250. package/src/server/security.ts +0 -115
  251. package/src/server/server.ts +0 -251
  252. package/src/server/types.ts +0 -57
  253. package/src/storage/driver.ts +0 -126
  254. package/src/storage/index.ts +0 -81
  255. package/src/storage/mask.ts +0 -34
  256. package/src/storage/sqlite.ts +0 -714
  257. package/src/storage/types.ts +0 -139
  258. package/src/utils/index.ts +0 -62
@@ -1,221 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { filterWithFallbackInfo } from "../../filter";
3
- import { loadActions, loadPlaybooks, loadProjectConfig } from "../../project/loader";
4
- import { getRegistryStatus, listLinkedPackages } from "../../registry/registry";
5
- import { type RouteContext, jsonResponse } from "./common";
6
-
7
- /**
8
- * 处理系统探索与自省接口(GET /api/v1/info)。
9
- */
10
- export async function handleInfoRoute(ctx: RouteContext): Promise<Response | null> {
11
- const { req, url, pathname, corsHeaders, projectRoot, customHome, options } = ctx;
12
-
13
- if (pathname !== "/api/v1/info" || req.method !== "GET") {
14
- return null;
15
- }
16
-
17
- try {
18
- const isTree = url.searchParams.get("tree") === "true";
19
- if (isTree) {
20
- const status = getRegistryStatus(customHome);
21
- return jsonResponse(
22
- { ok: true, type: "tree", ...status },
23
- 200,
24
- corsHeaders
25
- );
26
- }
27
-
28
- const intent = url.searchParams.get("intent") || undefined;
29
- const targetPkg = url.searchParams.get("package") || undefined;
30
-
31
- // 收集所有候选包全量元数据
32
- const aggregatedPackages: any[] = [];
33
-
34
- if (projectRoot) {
35
- try {
36
- const config = loadProjectConfig(projectRoot);
37
- const actions = await loadActions(projectRoot, config.actionsDir);
38
- const playbooks = loadPlaybooks(projectRoot, config.playbooksDir);
39
- aggregatedPackages.push({
40
- id: config.id,
41
- name: config.name,
42
- version: config.version,
43
- description: config.description || "",
44
- path: projectRoot,
45
- actionsCount: actions.size,
46
- playbooksCount: playbooks.size,
47
- actions: Array.from(actions.entries()).map(([id, a]) => ({
48
- id,
49
- description: a.description || "",
50
- inputSchema: a.inputSchema || null,
51
- outputSchema: a.outputSchema || null,
52
- })),
53
- playbooks: Array.from(playbooks.entries()).map(([id, p]) => ({
54
- id,
55
- description: p.description || "",
56
- actions: p.actions || [],
57
- })),
58
- configDeclared: config.config || {},
59
- });
60
- } catch {
61
- // 忽略解析异常
62
- }
63
- } else {
64
- const linked = listLinkedPackages(customHome);
65
- for (const pkg of linked) {
66
- if (!existsSync(pkg.path)) continue;
67
- try {
68
- const config = loadProjectConfig(pkg.path);
69
- const actions = await loadActions(pkg.path, config.actionsDir);
70
- const playbooks = loadPlaybooks(pkg.path, config.playbooksDir);
71
- aggregatedPackages.push({
72
- id: config.id,
73
- name: config.name,
74
- version: config.version,
75
- description: config.description || "",
76
- path: pkg.path,
77
- actionsCount: actions.size,
78
- playbooksCount: playbooks.size,
79
- actions: Array.from(actions.entries()).map(([id, a]) => ({
80
- id,
81
- description: a.description || "",
82
- inputSchema: a.inputSchema || null,
83
- outputSchema: a.outputSchema || null,
84
- })),
85
- playbooks: Array.from(playbooks.entries()).map(([id, p]) => ({
86
- id,
87
- description: p.description || "",
88
- actions: p.actions || [],
89
- })),
90
- configDeclared: config.config || {},
91
- });
92
- } catch {
93
- // 忽略故障包
94
- }
95
- }
96
- }
97
-
98
- // 显式指定 package 详情下钻
99
- if (targetPkg) {
100
- const matched = aggregatedPackages.find(
101
- (p) => p.id === targetPkg || p.path === targetPkg
102
- );
103
- if (!matched) {
104
- return jsonResponse(
105
- {
106
- ok: false,
107
- error: {
108
- code: "PACKAGE_NOT_FOUND",
109
- message: `Package '${targetPkg}' not found on remote server`,
110
- },
111
- },
112
- 404,
113
- corsHeaders
114
- );
115
- }
116
- return jsonResponse(
117
- {
118
- ok: true,
119
- type: "package_detail",
120
- ...matched,
121
- ...(options.exposeDebugInfo ? { projectRoot: matched.path } : {}),
122
- },
123
- 200,
124
- corsHeaders
125
- );
126
- }
127
-
128
- // 意图过滤与决议
129
- if (intent) {
130
- const filterRes = filterWithFallbackInfo(
131
- aggregatedPackages,
132
- intent,
133
- [
134
- (p) => p.id,
135
- (p) => p.name,
136
- (p) => p.description,
137
- (p) => p.actions.map((a: any) => a.id),
138
- (p) => p.actions.map((a: any) => a.description),
139
- (p) => p.playbooks.map((pb: any) => pb.id),
140
- (p) => p.playbooks.map((pb: any) => pb.description),
141
- ],
142
- true
143
- );
144
-
145
- // 唯一命中智能展开详情
146
- if (filterRes.matchedCount === 1) {
147
- const single = filterRes.items[0];
148
- return jsonResponse(
149
- {
150
- ok: true,
151
- type: "package_detail",
152
- isSingleMatch: true,
153
- ...single,
154
- ...(options.exposeDebugInfo ? { projectRoot: single.path } : {}),
155
- },
156
- 200,
157
- corsHeaders
158
- );
159
- }
160
-
161
- return jsonResponse(
162
- {
163
- ok: true,
164
- type: "package_list",
165
- isFallback: filterRes.isFallback,
166
- packages: filterRes.items,
167
- },
168
- 200,
169
- corsHeaders
170
- );
171
- }
172
-
173
- // 单包模式直接展开详情
174
- if (projectRoot && aggregatedPackages.length === 1) {
175
- const p = aggregatedPackages[0];
176
- return jsonResponse(
177
- {
178
- ok: true,
179
- type: "package_detail",
180
- id: p.id,
181
- name: p.name,
182
- version: p.version,
183
- description: p.description,
184
- actionsCount: p.actionsCount,
185
- playbooksCount: p.playbooksCount,
186
- actions: p.actions.map((a: any) => a.id),
187
- actionsDetail: p.actions,
188
- playbooks: p.playbooks.map((pb: any) => pb.id),
189
- playbooksDetail: p.playbooks,
190
- configDeclared: p.configDeclared,
191
- linkedPackages: listLinkedPackages(customHome),
192
- ...(options.exposeDebugInfo ? { projectRoot } : {}),
193
- },
194
- 200,
195
- corsHeaders
196
- );
197
- }
198
-
199
- // 全局注册表概览
200
- return jsonResponse(
201
- {
202
- ok: true,
203
- type: "package_list",
204
- version: "2.0.0",
205
- packages: aggregatedPackages,
206
- linkedPackages: listLinkedPackages(customHome),
207
- },
208
- 200,
209
- corsHeaders
210
- );
211
- } catch (err: any) {
212
- return jsonResponse(
213
- {
214
- ok: false,
215
- error: { code: "INFO_ERROR", message: err.message },
216
- },
217
- 500,
218
- corsHeaders
219
- );
220
- }
221
- }
@@ -1,109 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { filterByIntent } from "../../filter";
3
- import { loadPlaybooks, loadProjectConfig } from "../../project/loader";
4
- import { listLinkedPackages, resolvePlaybookProject } from "../../registry/registry";
5
- import { type RouteContext, jsonResponse } from "./common";
6
-
7
- /**
8
- * 处理 Playbook 列表与 SOP 详情接口。
9
- */
10
- export async function handlePlaybooksRoutes(ctx: RouteContext): Promise<Response | null> {
11
- const { req, url, pathname, corsHeaders, projectRoot, customHome } = ctx;
12
-
13
- // 1. Playbooks List: GET /api/v1/playbooks
14
- if (pathname === "/api/v1/playbooks" && req.method === "GET") {
15
- try {
16
- const pbList: Array<{
17
- id: string;
18
- description: string;
19
- actions: string[];
20
- packageId: string;
21
- filePath: string;
22
- }> = [];
23
-
24
- const targetPkg = url.searchParams.get("package");
25
- const intent = url.searchParams.get("intent");
26
-
27
- const roots: Array<{ root: string; packageId: string }> = [];
28
- if (projectRoot) {
29
- const cfg = loadProjectConfig(projectRoot);
30
- roots.push({ root: projectRoot, packageId: cfg.id });
31
- }
32
- const linked = listLinkedPackages(customHome);
33
- for (const pkg of linked) {
34
- if (projectRoot && pkg.path === projectRoot) continue;
35
- if (!existsSync(pkg.path)) continue;
36
- roots.push({ root: pkg.path, packageId: pkg.id });
37
- }
38
-
39
- for (const item of roots) {
40
- if (targetPkg && item.packageId !== targetPkg && item.root !== targetPkg) continue;
41
- try {
42
- const cfg = loadProjectConfig(item.root);
43
- const pbs = loadPlaybooks(item.root, cfg.playbooksDir);
44
- for (const [id, pb] of pbs.entries()) {
45
- pbList.push({
46
- id,
47
- description: pb.description || "",
48
- actions: pb.actions || [],
49
- packageId: item.packageId,
50
- filePath: pb.filePath,
51
- });
52
- }
53
- } catch {}
54
- }
55
-
56
- const filtered = intent
57
- ? filterByIntent(
58
- pbList,
59
- intent,
60
- [(p) => p.id, (p) => p.description, (p) => p.packageId, (p) => p.actions],
61
- false
62
- )
63
- : pbList;
64
-
65
- return jsonResponse(filtered, 200, corsHeaders);
66
- } catch (err: any) {
67
- return jsonResponse(
68
- { ok: false, error: { code: "PLAYBOOKS_LIST_ERROR", message: err.message } },
69
- 500,
70
- corsHeaders
71
- );
72
- }
73
- }
74
-
75
- // 2. Playbook Show: GET /api/v1/playbooks/:id
76
- const pbShowMatch = pathname.match(/^\/api\/v1\/playbooks\/([^/]+)$/);
77
- if (pbShowMatch && req.method === "GET") {
78
- const pbId = decodeURIComponent(pbShowMatch[1]);
79
- try {
80
- const resolved = resolvePlaybookProject(
81
- pbId,
82
- projectRoot || process.cwd(),
83
- customHome
84
- );
85
- const pb = resolved.playbook;
86
- return jsonResponse(
87
- {
88
- ok: true,
89
- id: pb.id,
90
- packageId: resolved.packageId,
91
- description: pb.description || "",
92
- actions: pb.actions || [],
93
- filePath: pb.filePath,
94
- content: pb.content,
95
- },
96
- 200,
97
- corsHeaders
98
- );
99
- } catch (err: any) {
100
- return jsonResponse(
101
- { ok: false, error: { code: "PLAYBOOK_NOT_FOUND", message: err.message } },
102
- 404,
103
- corsHeaders
104
- );
105
- }
106
- }
107
-
108
- return null;
109
- }
@@ -1,301 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { filterByIntent } from "../../filter";
3
- import { loadProjectConfig } from "../../project/loader";
4
- import { listLinkedPackages } from "../../registry/registry";
5
- import type { RuntimeStorage } from "../../storage/types";
6
- import { readJsonBody } from "../body";
7
- import { type RouteContext, findRunAcrossStorages, jsonResponse } from "./common";
8
-
9
- /**
10
- * 处理历史运行记录检索、清理、详情及 SSE 流式日志接口。
11
- */
12
- export async function handleRunsRoutes(ctx: RouteContext): Promise<Response | null> {
13
- const { req, url, pathname, corsHeaders, projectRoot, customHome, runtimeRegistry, options } = ctx;
14
-
15
- // 1. Runs List: GET /api/v1/runs
16
- if (pathname === "/api/v1/runs" && req.method === "GET") {
17
- try {
18
- const status = url.searchParams.get("status") || undefined;
19
- const actionId = url.searchParams.get("actionId") || undefined;
20
- const packageId = url.searchParams.get("packageId") || undefined;
21
- const intent = url.searchParams.get("intent") || undefined;
22
- const limit = parseInt(url.searchParams.get("limit") || "50", 10);
23
-
24
- const allRuns: any[] = [];
25
- const seenRunIds = new Set<string>();
26
-
27
- const candidateStorages: Array<{ packageId: string; storage: RuntimeStorage }> = [];
28
- if (projectRoot) {
29
- try {
30
- const cfg = loadProjectConfig(projectRoot);
31
- candidateStorages.push({
32
- packageId: cfg.id,
33
- storage: runtimeRegistry.getStorage(cfg.id, projectRoot),
34
- });
35
- } catch {}
36
- }
37
- const linked = listLinkedPackages(customHome);
38
- for (const pkg of linked) {
39
- if (projectRoot && pkg.path === projectRoot) continue;
40
- if (!existsSync(pkg.path)) continue;
41
- candidateStorages.push({
42
- packageId: pkg.id,
43
- storage: runtimeRegistry.getStorage(pkg.id, pkg.path),
44
- });
45
- }
46
-
47
- for (const item of candidateStorages) {
48
- if (packageId && item.packageId !== packageId) continue;
49
- try {
50
- const records = item.storage.listRuns({ actionId, limit });
51
- for (const r of records) {
52
- if (!seenRunIds.has(r.id)) {
53
- seenRunIds.add(r.id);
54
- if (status && r.status !== status) continue;
55
- allRuns.push(r);
56
- }
57
- }
58
- } catch {}
59
- }
60
-
61
- allRuns.sort((a, b) => (b.startedAt || "").localeCompare(a.startedAt || ""));
62
-
63
- const filtered = intent
64
- ? filterByIntent(
65
- allRuns,
66
- intent,
67
- [(r) => r.id, (r) => r.actionId, (r) => r.status, (r) => r.packageId],
68
- false
69
- )
70
- : allRuns;
71
-
72
- const sliced = filtered.slice(0, limit);
73
- return jsonResponse(
74
- { ok: true, total: filtered.length, items: sliced },
75
- 200,
76
- corsHeaders
77
- );
78
- } catch (err: any) {
79
- return jsonResponse(
80
- { ok: false, error: { code: "RUNS_LIST_ERROR", message: err.message } },
81
- 500,
82
- corsHeaders
83
- );
84
- }
85
- }
86
-
87
- // 2. Runs Clear: POST /api/v1/runs/clear or DELETE /api/v1/runs
88
- if (
89
- (pathname === "/api/v1/runs/clear" && req.method === "POST") ||
90
- (pathname === "/api/v1/runs" && req.method === "DELETE")
91
- ) {
92
- try {
93
- let body: any = {};
94
- if (req.method === "POST" || req.headers.get("content-type")?.includes("json")) {
95
- body = await readJsonBody(req, { maxBytes: options.maxBodyBytes }).catch(() => ({}));
96
- }
97
- const packageId = url.searchParams.get("packageId") || body.packageId || undefined;
98
- const actionId = url.searchParams.get("actionId") || body.actionId || undefined;
99
- const status = url.searchParams.get("status") || body.status || undefined;
100
-
101
- let clearedCount = 0;
102
- const candidateStorages: RuntimeStorage[] = [];
103
- if (projectRoot) {
104
- try {
105
- const cfg = loadProjectConfig(projectRoot);
106
- candidateStorages.push(runtimeRegistry.getStorage(cfg.id, projectRoot));
107
- } catch {}
108
- }
109
- const linked = listLinkedPackages(customHome);
110
- for (const pkg of linked) {
111
- if (projectRoot && pkg.path === projectRoot) continue;
112
- if (!existsSync(pkg.path)) continue;
113
- if (packageId && pkg.id !== packageId) continue;
114
- candidateStorages.push(runtimeRegistry.getStorage(pkg.id, pkg.path));
115
- }
116
-
117
- for (const storage of candidateStorages) {
118
- clearedCount += storage.clearRuns({ actionId, status });
119
- }
120
-
121
- return jsonResponse({ ok: true, clearedCount }, 200, corsHeaders);
122
- } catch (err: any) {
123
- return jsonResponse(
124
- { ok: false, error: { code: "RUNS_CLEAR_ERROR", message: err.message } },
125
- 500,
126
- corsHeaders
127
- );
128
- }
129
- }
130
-
131
- // 3. Run Stream (SSE): GET /api/v1/runs/:runId/stream
132
- const runStreamMatch = pathname.match(/^\/api\/v1\/runs\/([^/]+)\/stream$/);
133
- if (runStreamMatch && req.method === "GET") {
134
- const runId = decodeURIComponent(runStreamMatch[1]);
135
- const found = findRunAcrossStorages(runId, runtimeRegistry, projectRoot, customHome);
136
- const activeHandle = runtimeRegistry.executionManager.get(runId);
137
-
138
- if (!found && !activeHandle) {
139
- return jsonResponse(
140
- { ok: false, error: { code: "RUN_NOT_FOUND", message: `Run '${runId}' not found` } },
141
- 404,
142
- corsHeaders
143
- );
144
- }
145
-
146
- const stream = new ReadableStream({
147
- start(controller) {
148
- const encoder = new TextEncoder();
149
- const sendEvent = (event: string, data: any) => {
150
- try {
151
- controller.enqueue(
152
- encoder.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`)
153
- );
154
- } catch {}
155
- };
156
-
157
- if (activeHandle) {
158
- sendEvent("status", { runId, status: "running" });
159
- const unsubscribe = runtimeRegistry.subscribe(runId, (evt) => {
160
- sendEvent(evt.type, evt.data);
161
- if (evt.type === "finish") {
162
- try { controller.close(); } catch {}
163
- }
164
- });
165
-
166
- activeHandle.result.then(
167
- (res) => {
168
- sendEvent("finish", res);
169
- try { controller.close(); } catch {}
170
- },
171
- (err) => {
172
- sendEvent("finish", {
173
- ok: false,
174
- error: { message: err?.message || String(err) },
175
- });
176
- try { controller.close(); } catch {}
177
- }
178
- );
179
-
180
- req.signal.addEventListener("abort", () => {
181
- unsubscribe();
182
- try { controller.close(); } catch {}
183
- });
184
- } else if (found) {
185
- sendEvent("finish", found.run);
186
- controller.close();
187
- }
188
- },
189
- });
190
-
191
- return new Response(stream, {
192
- status: 200,
193
- headers: {
194
- "Content-Type": "text/event-stream",
195
- "Cache-Control": "no-cache",
196
- "Connection": "keep-alive",
197
- ...corsHeaders,
198
- },
199
- });
200
- }
201
-
202
- // 4. Run Show: GET /api/v1/runs/:runId
203
- const runShowMatch = pathname.match(/^\/api\/v1\/runs\/([^/]+)$/);
204
- if (runShowMatch && req.method === "GET") {
205
- const runId = decodeURIComponent(runShowMatch[1]);
206
- const found = findRunAcrossStorages(runId, runtimeRegistry, projectRoot, customHome);
207
-
208
- if (!found) {
209
- return jsonResponse(
210
- {
211
- ok: false,
212
- error: {
213
- code: "RUN_NOT_FOUND",
214
- message: `Run '${runId}' not found`,
215
- },
216
- },
217
- 404,
218
- corsHeaders
219
- );
220
- }
221
-
222
- return jsonResponse(found.run, 200, corsHeaders);
223
- }
224
-
225
- // 5. Run Cancel: POST /api/v1/runs/:runId/cancel
226
- const runCancelMatch = pathname.match(/^\/api\/v1\/runs\/([^/]+)\/cancel$/);
227
- if (runCancelMatch && req.method === "POST") {
228
- const runId = decodeURIComponent(runCancelMatch[1]);
229
- let body: any = {};
230
- try {
231
- body = await readJsonBody(req, { maxBytes: options.maxBodyBytes });
232
- } catch {
233
- // Body is optional
234
- }
235
-
236
- const reason = body?.reason || "Cancelled by client request";
237
-
238
- const activeHandle = runtimeRegistry.executionManager.get(runId);
239
- if (activeHandle) {
240
- const cancelled = runtimeRegistry.executionManager.cancel(runId, reason);
241
- if (cancelled) {
242
- return jsonResponse(
243
- {
244
- ok: true,
245
- runId,
246
- status: "cancelled",
247
- },
248
- 200,
249
- corsHeaders
250
- );
251
- }
252
- }
253
-
254
- const found = findRunAcrossStorages(runId, runtimeRegistry, projectRoot, customHome);
255
- if (!found) {
256
- return jsonResponse(
257
- {
258
- ok: false,
259
- error: {
260
- code: "RUN_NOT_FOUND",
261
- message: `Run '${runId}' not found`,
262
- },
263
- },
264
- 404,
265
- corsHeaders
266
- );
267
- }
268
-
269
- const { storage, run } = found;
270
- if (run.status === "success" || run.status === "failed" || run.status === "cancelled") {
271
- return jsonResponse(
272
- {
273
- ok: false,
274
- error: {
275
- code: "RUN_ALREADY_FINISHED",
276
- message: `Run '${runId}' has already finished with status '${run.status}'`,
277
- },
278
- },
279
- 409,
280
- corsHeaders
281
- );
282
- }
283
-
284
- storage.updateRun(runId, "cancelled", undefined, {
285
- code: "ACTION_CANCELLED",
286
- message: reason,
287
- });
288
-
289
- return jsonResponse(
290
- {
291
- ok: true,
292
- runId,
293
- status: "cancelled",
294
- },
295
- 200,
296
- corsHeaders
297
- );
298
- }
299
-
300
- return null;
301
- }