@actiondock/core 2.0.11 → 2.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/templates.d.ts +19 -0
- package/dist/catalog/action-index.d.ts +9 -0
- package/dist/catalog/action-resolver.d.ts +20 -0
- package/dist/catalog/location-registry.d.ts +15 -0
- package/dist/catalog/package-catalog.d.ts +7 -0
- package/dist/catalog/types.d.ts +68 -0
- package/dist/doctor/doctor.d.ts +6 -0
- package/dist/doctor/types.d.ts +23 -0
- package/dist/execution/index.d.ts +2 -0
- package/dist/execution/service.d.ts +74 -0
- package/dist/execution/types.d.ts +74 -0
- package/dist/export/templates.d.ts +33 -0
- package/dist/filter/intent.d.ts +33 -0
- package/{src/index.ts → dist/index.d.ts} +1 -1
- package/dist/index.js +8458 -0
- package/dist/profile/client.d.ts +116 -0
- package/dist/profile/manager.d.ts +47 -0
- package/dist/profile/types.d.ts +61 -0
- package/dist/project/closure.d.ts +25 -0
- package/{src/project/index.ts → dist/project/index.d.ts} +1 -0
- package/dist/project/init.d.ts +27 -0
- package/dist/project/loader.d.ts +105 -0
- package/dist/project/manifest.d.ts +44 -0
- package/dist/project/types.d.ts +131 -0
- package/dist/registry/registry.d.ts +24 -0
- package/dist/registry/types.d.ts +117 -0
- package/dist/runtime/clock.d.ts +21 -0
- package/dist/runtime/context.d.ts +75 -0
- package/dist/runtime/env.d.ts +54 -0
- package/dist/runtime/events.d.ts +61 -0
- package/dist/runtime/execution-manager.d.ts +48 -0
- package/{src/runtime/index.ts → dist/runtime/index.d.ts} +0 -1
- package/dist/runtime/module-loader.d.ts +42 -0
- package/dist/runtime/process.d.ts +11 -0
- package/dist/runtime/runner.d.ts +186 -0
- package/dist/runtime/standalone.d.ts +40 -0
- package/dist/schema/validator.d.ts +28 -0
- package/dist/server/body.d.ts +40 -0
- package/{src/server/index.ts → dist/server/index.d.ts} +0 -1
- package/dist/server/routes/actions.d.ts +5 -0
- package/dist/server/routes/common.d.ts +36 -0
- package/dist/server/routes/config.d.ts +5 -0
- package/dist/server/routes/doctor.d.ts +5 -0
- package/dist/server/routes/health.d.ts +5 -0
- package/dist/server/routes/info.d.ts +5 -0
- package/dist/server/routes/playbooks.d.ts +5 -0
- package/dist/server/routes/runs.d.ts +5 -0
- package/dist/server/routes/state.d.ts +5 -0
- package/dist/server/runtime-registry.d.ts +78 -0
- package/dist/server/security.d.ts +37 -0
- package/dist/server/server.d.ts +15 -0
- package/dist/server/types.d.ts +59 -0
- package/dist/storage/driver.d.ts +15 -0
- package/dist/storage/index.d.ts +44 -0
- package/{src/storage/mask.ts → dist/storage/mask.d.ts} +5 -20
- package/dist/storage/sqlite.d.ts +66 -0
- package/dist/storage/types.d.ts +121 -0
- package/dist/utils/index.d.ts +29 -0
- package/dist/version.d.ts +4 -0
- package/package.json +11 -10
- package/src/build/templates.ts +0 -59
- package/src/catalog/action-index.ts +0 -92
- package/src/catalog/action-resolver.ts +0 -120
- package/src/catalog/location-registry.ts +0 -134
- package/src/catalog/package-catalog.ts +0 -87
- package/src/catalog/types.ts +0 -75
- package/src/doctor/doctor.ts +0 -419
- package/src/doctor/types.ts +0 -25
- package/src/execution/index.ts +0 -2
- package/src/execution/service.ts +0 -322
- package/src/execution/types.ts +0 -73
- package/src/export/templates.ts +0 -590
- package/src/filter/intent.ts +0 -154
- package/src/profile/client.ts +0 -552
- package/src/profile/manager.ts +0 -341
- package/src/profile/types.ts +0 -71
- package/src/project/init.ts +0 -242
- package/src/project/loader.ts +0 -479
- package/src/project/manifest.ts +0 -299
- package/src/project/types.ts +0 -141
- package/src/registry/registry.ts +0 -940
- package/src/registry/types.ts +0 -127
- package/src/runtime/clock.ts +0 -41
- package/src/runtime/context.ts +0 -259
- package/src/runtime/env.ts +0 -172
- package/src/runtime/events.ts +0 -142
- package/src/runtime/execution-manager.ts +0 -74
- package/src/runtime/module-loader.ts +0 -67
- package/src/runtime/process.ts +0 -245
- package/src/runtime/runner.ts +0 -527
- package/src/runtime/standalone.ts +0 -429
- package/src/schema/validator.ts +0 -61
- package/src/server/body.ts +0 -112
- package/src/server/routes/actions.ts +0 -262
- package/src/server/routes/common.ts +0 -126
- package/src/server/routes/config.ts +0 -147
- package/src/server/routes/doctor.ts +0 -29
- package/src/server/routes/health.ts +0 -40
- package/src/server/routes/info.ts +0 -221
- package/src/server/routes/playbooks.ts +0 -109
- package/src/server/routes/runs.ts +0 -301
- package/src/server/routes/state.ts +0 -133
- package/src/server/runtime-registry.ts +0 -115
- package/src/server/security.ts +0 -115
- package/src/server/server.ts +0 -251
- package/src/server/types.ts +0 -57
- package/src/storage/driver.ts +0 -126
- package/src/storage/index.ts +0 -81
- package/src/storage/sqlite.ts +0 -714
- package/src/storage/types.ts +0 -139
- package/src/utils/index.ts +0 -62
- /package/{src/build/index.ts → dist/build/index.d.ts} +0 -0
- /package/{src/catalog/index.ts → dist/catalog/index.d.ts} +0 -0
- /package/{src/doctor/index.ts → dist/doctor/index.d.ts} +0 -0
- /package/{src/export/index.ts → dist/export/index.d.ts} +0 -0
- /package/{src/filter/index.ts → dist/filter/index.d.ts} +0 -0
- /package/{src/profile/index.ts → dist/profile/index.d.ts} +0 -0
- /package/{src/registry/index.ts → dist/registry/index.d.ts} +0 -0
- /package/{src/server/routes/index.ts → dist/server/routes/index.d.ts} +0 -0
|
@@ -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
|
-
}
|