@herdctl/web 0.0.1 → 0.1.1

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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/dist/client/assets/index-Cyochp2F.css +1 -0
  4. package/dist/client/assets/index-mp9jz5eD.js +373 -0
  5. package/dist/client/favicon.ico +0 -0
  6. package/dist/client/favicon.svg +1 -0
  7. package/dist/client/herdctl-logo.svg +29 -0
  8. package/dist/client/index.html +21 -0
  9. package/dist/server/__tests__/routes.test.d.ts +8 -0
  10. package/dist/server/__tests__/routes.test.d.ts.map +1 -0
  11. package/dist/server/__tests__/routes.test.js +535 -0
  12. package/dist/server/__tests__/routes.test.js.map +1 -0
  13. package/dist/server/__tests__/ws-handler.test.d.ts +7 -0
  14. package/dist/server/__tests__/ws-handler.test.d.ts.map +1 -0
  15. package/dist/server/__tests__/ws-handler.test.js +380 -0
  16. package/dist/server/__tests__/ws-handler.test.js.map +1 -0
  17. package/dist/server/chat/index.d.ts +5 -0
  18. package/dist/server/chat/index.d.ts.map +1 -0
  19. package/dist/server/chat/index.js +5 -0
  20. package/dist/server/chat/index.js.map +1 -0
  21. package/dist/server/chat/web-chat-manager.d.ts +158 -0
  22. package/dist/server/chat/web-chat-manager.d.ts.map +1 -0
  23. package/dist/server/chat/web-chat-manager.js +437 -0
  24. package/dist/server/chat/web-chat-manager.js.map +1 -0
  25. package/dist/server/index.d.ts +144 -0
  26. package/dist/server/index.d.ts.map +1 -0
  27. package/dist/server/index.js +341 -0
  28. package/dist/server/index.js.map +1 -0
  29. package/dist/server/routes/agents.d.ts +15 -0
  30. package/dist/server/routes/agents.d.ts.map +1 -0
  31. package/dist/server/routes/agents.js +66 -0
  32. package/dist/server/routes/agents.js.map +1 -0
  33. package/dist/server/routes/chat.d.ts +18 -0
  34. package/dist/server/routes/chat.d.ts.map +1 -0
  35. package/dist/server/routes/chat.js +191 -0
  36. package/dist/server/routes/chat.js.map +1 -0
  37. package/dist/server/routes/fleet.d.ts +15 -0
  38. package/dist/server/routes/fleet.d.ts.map +1 -0
  39. package/dist/server/routes/fleet.js +36 -0
  40. package/dist/server/routes/fleet.js.map +1 -0
  41. package/dist/server/routes/jobs.d.ts +17 -0
  42. package/dist/server/routes/jobs.d.ts.map +1 -0
  43. package/dist/server/routes/jobs.js +188 -0
  44. package/dist/server/routes/jobs.js.map +1 -0
  45. package/dist/server/routes/schedules.d.ts +16 -0
  46. package/dist/server/routes/schedules.d.ts.map +1 -0
  47. package/dist/server/routes/schedules.js +126 -0
  48. package/dist/server/routes/schedules.js.map +1 -0
  49. package/dist/server/ws/fleet-bridge.d.ts +80 -0
  50. package/dist/server/ws/fleet-bridge.d.ts.map +1 -0
  51. package/dist/server/ws/fleet-bridge.js +184 -0
  52. package/dist/server/ws/fleet-bridge.js.map +1 -0
  53. package/dist/server/ws/handler.d.ts +93 -0
  54. package/dist/server/ws/handler.d.ts.map +1 -0
  55. package/dist/server/ws/handler.js +270 -0
  56. package/dist/server/ws/handler.js.map +1 -0
  57. package/dist/server/ws/index.d.ts +8 -0
  58. package/dist/server/ws/index.d.ts.map +1 -0
  59. package/dist/server/ws/index.js +8 -0
  60. package/dist/server/ws/index.js.map +1 -0
  61. package/dist/server/ws/types.d.ts +215 -0
  62. package/dist/server/ws/types.d.ts.map +1 -0
  63. package/dist/server/ws/types.js +67 -0
  64. package/dist/server/ws/types.js.map +1 -0
  65. package/package.json +77 -1
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill-rule="evenodd" d="M81 36 64 0 47 36l-1 2-9-10a6 6 0 0 0-9 9l10 10h-2L0 64l36 17h2L28 91a6 6 0 1 0 9 9l9-10 1 2 17 36 17-36v-2l9 10a6 6 0 1 0 9-9l-9-9 2-1 36-17-36-17-2-1 9-9a6 6 0 1 0-9-9l-9 10v-2Zm-17 2-2 5c-4 8-11 15-19 19l-5 2 5 2c8 4 15 11 19 19l2 5 2-5c4-8 11-15 19-19l5-2-5-2c-8-4-15-11-19-19l-2-5Z" clip-rule="evenodd"/><path d="M118 19a6 6 0 0 0-9-9l-3 3a6 6 0 1 0 9 9l3-3Zm-96 4c-2 2-6 2-9 0l-3-3a6 6 0 1 1 9-9l3 3c3 2 3 6 0 9Zm0 82c-2-2-6-2-9 0l-3 3a6 6 0 1 0 9 9l3-3c3-2 3-6 0-9Zm96 4a6 6 0 0 1-9 9l-3-3a6 6 0 1 1 9-9l3 3Z"/><style>path{fill:#000}@media (prefers-color-scheme:dark){path{fill:#fff}}</style></svg>
@@ -0,0 +1,29 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120">
2
+ <!-- Background rounded square (like K8s uses heptagon) -->
3
+ <rect x="5" y="5" width="110" height="110" rx="20" ry="20" fill="#326CE5"/>
4
+
5
+ <!-- h structure: lines connecting nodes -->
6
+ <g stroke="white" stroke-width="4" stroke-linecap="round">
7
+ <!-- Left vertical (full height) -->
8
+ <line x1="35" y1="30" x2="35" y2="90"/>
9
+ <!-- Right vertical (crossbar to bottom only) -->
10
+ <line x1="85" y1="60" x2="85" y2="90"/>
11
+ <!-- Horizontal crossbar -->
12
+ <line x1="35" y1="60" x2="85" y2="60"/>
13
+ </g>
14
+
15
+ <!-- Nodes (circles at connection points) -->
16
+ <g fill="white">
17
+ <!-- Left vertical nodes -->
18
+ <circle cx="35" cy="30" r="8"/> <!-- Top left -->
19
+ <circle cx="35" cy="60" r="8"/> <!-- Left middle -->
20
+ <circle cx="35" cy="90" r="8"/> <!-- Bottom left -->
21
+
22
+ <!-- Right vertical nodes (no top-right anymore) -->
23
+ <circle cx="85" cy="60" r="8"/> <!-- Right middle -->
24
+ <circle cx="85" cy="90" r="8"/> <!-- Bottom right -->
25
+
26
+ <!-- Central hub (slightly larger) -->
27
+ <circle cx="60" cy="60" r="10"/>
28
+ </g>
29
+ </svg>
@@ -0,0 +1,21 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>herdctl Dashboard</title>
7
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
8
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
9
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
11
+ <link
12
+ href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600&family=Lora:ital,wght@0,400;0,500;1,400&display=swap"
13
+ rel="stylesheet"
14
+ />
15
+ <script type="module" crossorigin src="/assets/index-mp9jz5eD.js"></script>
16
+ <link rel="stylesheet" crossorigin href="/assets/index-Cyochp2F.css">
17
+ </head>
18
+ <body class="bg-herd-bg text-herd-fg font-sans antialiased">
19
+ <div id="root"></div>
20
+ </body>
21
+ </html>
@@ -0,0 +1,8 @@
1
+ /**
2
+ * REST API route tests for @herdctl/web
3
+ *
4
+ * Tests the Fastify routes using fastify.inject() for isolated testing
5
+ * without needing a real server or network connections.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=routes.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.test.d.ts","sourceRoot":"","sources":["../../../src/server/__tests__/routes.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,535 @@
1
+ /**
2
+ * REST API route tests for @herdctl/web
3
+ *
4
+ * Tests the Fastify routes using fastify.inject() for isolated testing
5
+ * without needing a real server or network connections.
6
+ */
7
+ import { describe, it, expect, beforeEach, vi } from "vitest";
8
+ import Fastify from "fastify";
9
+ import { registerFleetRoutes } from "../routes/fleet.js";
10
+ import { registerAgentRoutes } from "../routes/agents.js";
11
+ import { registerJobRoutes } from "../routes/jobs.js";
12
+ import { registerScheduleRoutes } from "../routes/schedules.js";
13
+ // =============================================================================
14
+ // Mock FleetManager
15
+ // =============================================================================
16
+ function createMockFleetManager() {
17
+ return {
18
+ getFleetStatus: vi.fn(),
19
+ getAgentInfo: vi.fn(),
20
+ getAgentInfoByName: vi.fn(),
21
+ getSchedules: vi.fn(),
22
+ trigger: vi.fn(),
23
+ enableSchedule: vi.fn(),
24
+ disableSchedule: vi.fn(),
25
+ cancelJob: vi.fn(),
26
+ forkJob: vi.fn(),
27
+ getAgents: vi.fn().mockReturnValue([]),
28
+ getStateDir: vi.fn().mockReturnValue("/tmp/test-state"),
29
+ on: vi.fn(),
30
+ off: vi.fn(),
31
+ };
32
+ }
33
+ // =============================================================================
34
+ // Fleet Routes
35
+ // =============================================================================
36
+ describe("Fleet Routes", () => {
37
+ let server;
38
+ let mockFM;
39
+ beforeEach(async () => {
40
+ server = Fastify();
41
+ mockFM = createMockFleetManager();
42
+ registerFleetRoutes(server, mockFM);
43
+ await server.ready();
44
+ });
45
+ describe("GET /api/fleet/status", () => {
46
+ it("returns fleet status", async () => {
47
+ const mockStatus = {
48
+ state: "running",
49
+ uptimeSeconds: 120,
50
+ initializedAt: "2025-01-01T00:00:00Z",
51
+ startedAt: "2025-01-01T00:00:00Z",
52
+ stoppedAt: null,
53
+ counts: {
54
+ totalAgents: 2,
55
+ runningAgents: 1,
56
+ idleAgents: 1,
57
+ errorAgents: 0,
58
+ totalJobs: 5,
59
+ runningJobs: 1,
60
+ completedJobs: 3,
61
+ failedJobs: 1,
62
+ },
63
+ scheduler: {
64
+ status: "running",
65
+ checkCount: 10,
66
+ triggerCount: 2,
67
+ lastCheckAt: "2025-01-01T00:02:00Z",
68
+ checkIntervalMs: 5000,
69
+ },
70
+ };
71
+ mockFM.getFleetStatus.mockResolvedValue(mockStatus);
72
+ const response = await server.inject({
73
+ method: "GET",
74
+ url: "/api/fleet/status",
75
+ });
76
+ expect(response.statusCode).toBe(200);
77
+ expect(response.json()).toEqual(mockStatus);
78
+ expect(mockFM.getFleetStatus).toHaveBeenCalledOnce();
79
+ });
80
+ it("returns 500 when FleetManager throws", async () => {
81
+ mockFM.getFleetStatus.mockRejectedValue(new Error("Internal failure"));
82
+ const response = await server.inject({
83
+ method: "GET",
84
+ url: "/api/fleet/status",
85
+ });
86
+ expect(response.statusCode).toBe(500);
87
+ const body = response.json();
88
+ expect(body.error).toContain("Internal failure");
89
+ expect(body.statusCode).toBe(500);
90
+ });
91
+ });
92
+ });
93
+ // =============================================================================
94
+ // Agent Routes
95
+ // =============================================================================
96
+ describe("Agent Routes", () => {
97
+ let server;
98
+ let mockFM;
99
+ beforeEach(async () => {
100
+ server = Fastify();
101
+ mockFM = createMockFleetManager();
102
+ registerAgentRoutes(server, mockFM);
103
+ await server.ready();
104
+ });
105
+ describe("GET /api/agents", () => {
106
+ it("returns agent list", async () => {
107
+ const mockAgents = [
108
+ {
109
+ name: "coder",
110
+ status: "running",
111
+ currentJobId: "job-1",
112
+ lastJobId: null,
113
+ maxConcurrent: 1,
114
+ runningCount: 1,
115
+ errorMessage: null,
116
+ scheduleCount: 2,
117
+ schedules: [],
118
+ },
119
+ {
120
+ name: "reviewer",
121
+ status: "idle",
122
+ currentJobId: null,
123
+ lastJobId: "job-2",
124
+ maxConcurrent: 1,
125
+ runningCount: 0,
126
+ errorMessage: null,
127
+ scheduleCount: 1,
128
+ schedules: [],
129
+ },
130
+ ];
131
+ mockFM.getAgentInfo.mockResolvedValue(mockAgents);
132
+ const response = await server.inject({
133
+ method: "GET",
134
+ url: "/api/agents",
135
+ });
136
+ expect(response.statusCode).toBe(200);
137
+ expect(response.json()).toEqual(mockAgents);
138
+ expect(mockFM.getAgentInfo).toHaveBeenCalledOnce();
139
+ });
140
+ it("returns 500 when FleetManager throws", async () => {
141
+ mockFM.getAgentInfo.mockRejectedValue(new Error("DB error"));
142
+ const response = await server.inject({
143
+ method: "GET",
144
+ url: "/api/agents",
145
+ });
146
+ expect(response.statusCode).toBe(500);
147
+ expect(response.json().error).toContain("DB error");
148
+ });
149
+ });
150
+ describe("GET /api/agents/:name", () => {
151
+ it("returns a single agent", async () => {
152
+ const mockAgent = {
153
+ name: "coder",
154
+ status: "running",
155
+ currentJobId: "job-1",
156
+ lastJobId: null,
157
+ maxConcurrent: 1,
158
+ runningCount: 1,
159
+ errorMessage: null,
160
+ scheduleCount: 0,
161
+ schedules: [],
162
+ };
163
+ mockFM.getAgentInfoByName.mockResolvedValue(mockAgent);
164
+ const response = await server.inject({
165
+ method: "GET",
166
+ url: "/api/agents/coder",
167
+ });
168
+ expect(response.statusCode).toBe(200);
169
+ expect(response.json()).toEqual(mockAgent);
170
+ expect(mockFM.getAgentInfoByName).toHaveBeenCalledWith("coder");
171
+ });
172
+ it("returns 404 when agent not found", async () => {
173
+ mockFM.getAgentInfoByName.mockRejectedValue(new Error("Agent not found: unknown-agent"));
174
+ const response = await server.inject({
175
+ method: "GET",
176
+ url: "/api/agents/unknown-agent",
177
+ });
178
+ expect(response.statusCode).toBe(404);
179
+ expect(response.json().statusCode).toBe(404);
180
+ });
181
+ it("returns 500 for unexpected errors", async () => {
182
+ mockFM.getAgentInfoByName.mockRejectedValue(new Error("Unexpected error"));
183
+ const response = await server.inject({
184
+ method: "GET",
185
+ url: "/api/agents/coder",
186
+ });
187
+ expect(response.statusCode).toBe(500);
188
+ expect(response.json().error).toContain("Unexpected error");
189
+ });
190
+ });
191
+ });
192
+ // =============================================================================
193
+ // Job Routes
194
+ // =============================================================================
195
+ describe("Job Routes", () => {
196
+ let server;
197
+ let mockFM;
198
+ let mockListJobs;
199
+ beforeEach(async () => {
200
+ server = Fastify();
201
+ mockFM = createMockFleetManager();
202
+ mockListJobs = vi.fn();
203
+ registerJobRoutes(server, mockFM, mockListJobs);
204
+ await server.ready();
205
+ });
206
+ describe("GET /api/jobs", () => {
207
+ it("returns paginated jobs", async () => {
208
+ const mockJobs = [
209
+ {
210
+ id: "job-1",
211
+ agent: "coder",
212
+ prompt: "Fix bug",
213
+ status: "completed",
214
+ started_at: "2025-01-01T00:00:00Z",
215
+ },
216
+ {
217
+ id: "job-2",
218
+ agent: "reviewer",
219
+ prompt: "Review PR",
220
+ status: "running",
221
+ started_at: "2025-01-01T00:01:00Z",
222
+ },
223
+ ];
224
+ mockListJobs.mockResolvedValue({ jobs: mockJobs, errors: [] });
225
+ const response = await server.inject({
226
+ method: "GET",
227
+ url: "/api/jobs",
228
+ });
229
+ expect(response.statusCode).toBe(200);
230
+ const body = response.json();
231
+ expect(body.jobs).toHaveLength(2);
232
+ expect(body.total).toBe(2);
233
+ expect(body.limit).toBe(50);
234
+ expect(body.offset).toBe(0);
235
+ });
236
+ it("respects limit and offset query params", async () => {
237
+ const manyJobs = Array.from({ length: 10 }, (_, i) => ({
238
+ id: `job-${i}`,
239
+ agent: "coder",
240
+ prompt: `Task ${i}`,
241
+ status: "completed",
242
+ started_at: "2025-01-01T00:00:00Z",
243
+ }));
244
+ mockListJobs.mockResolvedValue({ jobs: manyJobs, errors: [] });
245
+ const response = await server.inject({
246
+ method: "GET",
247
+ url: "/api/jobs?limit=3&offset=2",
248
+ });
249
+ expect(response.statusCode).toBe(200);
250
+ const body = response.json();
251
+ expect(body.jobs).toHaveLength(3);
252
+ expect(body.jobs[0].jobId).toBe("job-2");
253
+ expect(body.total).toBe(10);
254
+ expect(body.limit).toBe(3);
255
+ expect(body.offset).toBe(2);
256
+ });
257
+ it("clamps limit to max 100", async () => {
258
+ mockListJobs.mockResolvedValue({ jobs: [], errors: [] });
259
+ const response = await server.inject({
260
+ method: "GET",
261
+ url: "/api/jobs?limit=999",
262
+ });
263
+ expect(response.statusCode).toBe(200);
264
+ expect(response.json().limit).toBe(100);
265
+ });
266
+ it("passes filter params to listJobs", async () => {
267
+ mockListJobs.mockResolvedValue({ jobs: [], errors: [] });
268
+ await server.inject({
269
+ method: "GET",
270
+ url: "/api/jobs?agentName=coder&status=running",
271
+ });
272
+ expect(mockListJobs).toHaveBeenCalledWith("/tmp/test-state/jobs", { agent: "coder", status: "running" });
273
+ });
274
+ it("returns 500 on error", async () => {
275
+ mockListJobs.mockRejectedValue(new Error("Disk error"));
276
+ const response = await server.inject({
277
+ method: "GET",
278
+ url: "/api/jobs",
279
+ });
280
+ expect(response.statusCode).toBe(500);
281
+ expect(response.json().error).toContain("Disk error");
282
+ });
283
+ });
284
+ describe("POST /api/jobs/:id/cancel", () => {
285
+ it("cancels a job successfully", async () => {
286
+ const mockResult = {
287
+ jobId: "job-1",
288
+ success: true,
289
+ terminationType: "graceful",
290
+ canceledAt: "2025-01-01T00:05:00Z",
291
+ };
292
+ mockFM.cancelJob.mockResolvedValue(mockResult);
293
+ const response = await server.inject({
294
+ method: "POST",
295
+ url: "/api/jobs/job-1/cancel",
296
+ });
297
+ expect(response.statusCode).toBe(200);
298
+ expect(response.json()).toEqual(mockResult);
299
+ expect(mockFM.cancelJob).toHaveBeenCalledWith("job-1");
300
+ });
301
+ it("returns 404 when job not found", async () => {
302
+ mockFM.cancelJob.mockRejectedValue(new Error("Job not found: missing"));
303
+ const response = await server.inject({
304
+ method: "POST",
305
+ url: "/api/jobs/missing/cancel",
306
+ });
307
+ expect(response.statusCode).toBe(404);
308
+ });
309
+ it("returns 500 on unexpected error", async () => {
310
+ mockFM.cancelJob.mockRejectedValue(new Error("Process kill failed"));
311
+ const response = await server.inject({
312
+ method: "POST",
313
+ url: "/api/jobs/job-1/cancel",
314
+ });
315
+ expect(response.statusCode).toBe(500);
316
+ expect(response.json().error).toContain("Process kill failed");
317
+ });
318
+ });
319
+ describe("POST /api/jobs/:id/fork", () => {
320
+ it("forks a job successfully", async () => {
321
+ const mockResult = {
322
+ jobId: "job-2",
323
+ forkedFromJobId: "job-1",
324
+ agentName: "coder",
325
+ startedAt: "2025-01-01T00:06:00Z",
326
+ };
327
+ mockFM.forkJob.mockResolvedValue(mockResult);
328
+ const response = await server.inject({
329
+ method: "POST",
330
+ url: "/api/jobs/job-1/fork",
331
+ payload: {},
332
+ });
333
+ expect(response.statusCode).toBe(200);
334
+ expect(response.json()).toEqual(mockResult);
335
+ expect(mockFM.forkJob).toHaveBeenCalledWith("job-1", undefined);
336
+ });
337
+ it("passes prompt override when provided", async () => {
338
+ mockFM.forkJob.mockResolvedValue({
339
+ jobId: "job-3",
340
+ forkedFromJobId: "job-1",
341
+ agentName: "coder",
342
+ startedAt: "2025-01-01T00:07:00Z",
343
+ prompt: "New prompt",
344
+ });
345
+ const response = await server.inject({
346
+ method: "POST",
347
+ url: "/api/jobs/job-1/fork",
348
+ payload: { prompt: "New prompt" },
349
+ });
350
+ expect(response.statusCode).toBe(200);
351
+ expect(mockFM.forkJob).toHaveBeenCalledWith("job-1", { prompt: "New prompt" });
352
+ });
353
+ it("returns 404 when original job not found", async () => {
354
+ mockFM.forkJob.mockRejectedValue(new Error("Job not found: missing"));
355
+ const response = await server.inject({
356
+ method: "POST",
357
+ url: "/api/jobs/missing/fork",
358
+ payload: {},
359
+ });
360
+ expect(response.statusCode).toBe(404);
361
+ });
362
+ });
363
+ });
364
+ // =============================================================================
365
+ // Schedule Routes
366
+ // =============================================================================
367
+ describe("Schedule Routes", () => {
368
+ let server;
369
+ let mockFM;
370
+ beforeEach(async () => {
371
+ server = Fastify();
372
+ mockFM = createMockFleetManager();
373
+ registerScheduleRoutes(server, mockFM);
374
+ await server.ready();
375
+ });
376
+ describe("GET /api/schedules", () => {
377
+ it("returns schedule list", async () => {
378
+ const mockSchedules = [
379
+ {
380
+ name: "daily-review",
381
+ agentName: "reviewer",
382
+ type: "cron",
383
+ cron: "0 9 * * *",
384
+ status: "idle",
385
+ lastRunAt: null,
386
+ nextRunAt: "2025-01-02T09:00:00Z",
387
+ runCount: 0,
388
+ },
389
+ {
390
+ name: "hourly-check",
391
+ agentName: "coder",
392
+ type: "interval",
393
+ interval: "1h",
394
+ status: "running",
395
+ lastRunAt: "2025-01-01T08:00:00Z",
396
+ nextRunAt: "2025-01-01T09:00:00Z",
397
+ runCount: 5,
398
+ },
399
+ ];
400
+ mockFM.getSchedules.mockResolvedValue(mockSchedules);
401
+ const response = await server.inject({
402
+ method: "GET",
403
+ url: "/api/schedules",
404
+ });
405
+ expect(response.statusCode).toBe(200);
406
+ expect(response.json()).toEqual(mockSchedules);
407
+ expect(mockFM.getSchedules).toHaveBeenCalledOnce();
408
+ });
409
+ it("returns 500 when FleetManager throws", async () => {
410
+ mockFM.getSchedules.mockRejectedValue(new Error("Scheduler error"));
411
+ const response = await server.inject({
412
+ method: "GET",
413
+ url: "/api/schedules",
414
+ });
415
+ expect(response.statusCode).toBe(500);
416
+ expect(response.json().error).toContain("Scheduler error");
417
+ });
418
+ });
419
+ describe("POST /api/agents/:name/trigger", () => {
420
+ it("triggers an agent successfully", async () => {
421
+ const mockResult = {
422
+ jobId: "job-1",
423
+ agentName: "coder",
424
+ scheduleName: null,
425
+ startedAt: "2025-01-01T00:00:00Z",
426
+ };
427
+ mockFM.trigger.mockResolvedValue(mockResult);
428
+ const response = await server.inject({
429
+ method: "POST",
430
+ url: "/api/agents/coder/trigger",
431
+ payload: {},
432
+ });
433
+ expect(response.statusCode).toBe(200);
434
+ expect(response.json()).toEqual(mockResult);
435
+ expect(mockFM.trigger).toHaveBeenCalledWith("coder", undefined, { prompt: undefined });
436
+ });
437
+ it("passes schedule name and prompt", async () => {
438
+ mockFM.trigger.mockResolvedValue({
439
+ jobId: "job-2",
440
+ agentName: "coder",
441
+ scheduleName: "daily-review",
442
+ startedAt: "2025-01-01T00:00:00Z",
443
+ prompt: "Custom task",
444
+ });
445
+ const response = await server.inject({
446
+ method: "POST",
447
+ url: "/api/agents/coder/trigger",
448
+ payload: { scheduleName: "daily-review", prompt: "Custom task" },
449
+ });
450
+ expect(response.statusCode).toBe(200);
451
+ expect(mockFM.trigger).toHaveBeenCalledWith("coder", "daily-review", { prompt: "Custom task" });
452
+ });
453
+ it("returns 404 when agent not found", async () => {
454
+ mockFM.trigger.mockRejectedValue(new Error("Agent not found: missing"));
455
+ const response = await server.inject({
456
+ method: "POST",
457
+ url: "/api/agents/missing/trigger",
458
+ payload: {},
459
+ });
460
+ expect(response.statusCode).toBe(404);
461
+ });
462
+ it("returns 500 on unexpected error", async () => {
463
+ mockFM.trigger.mockRejectedValue(new Error("Queue full"));
464
+ const response = await server.inject({
465
+ method: "POST",
466
+ url: "/api/agents/coder/trigger",
467
+ payload: {},
468
+ });
469
+ expect(response.statusCode).toBe(500);
470
+ expect(response.json().error).toContain("Queue full");
471
+ });
472
+ });
473
+ describe("POST /api/schedules/:agentName/:scheduleName/enable", () => {
474
+ it("enables a schedule", async () => {
475
+ const mockSchedule = {
476
+ name: "daily-review",
477
+ agentName: "reviewer",
478
+ type: "cron",
479
+ status: "idle",
480
+ };
481
+ mockFM.enableSchedule.mockResolvedValue(mockSchedule);
482
+ const response = await server.inject({
483
+ method: "POST",
484
+ url: "/api/schedules/reviewer/daily-review/enable",
485
+ });
486
+ expect(response.statusCode).toBe(200);
487
+ expect(response.json()).toEqual(mockSchedule);
488
+ expect(mockFM.enableSchedule).toHaveBeenCalledWith("reviewer", "daily-review");
489
+ });
490
+ it("returns 404 when schedule not found", async () => {
491
+ mockFM.enableSchedule.mockRejectedValue(new Error("Schedule not found: nonexistent"));
492
+ const response = await server.inject({
493
+ method: "POST",
494
+ url: "/api/schedules/reviewer/nonexistent/enable",
495
+ });
496
+ expect(response.statusCode).toBe(404);
497
+ });
498
+ });
499
+ describe("POST /api/schedules/:agentName/:scheduleName/disable", () => {
500
+ it("disables a schedule", async () => {
501
+ const mockSchedule = {
502
+ name: "daily-review",
503
+ agentName: "reviewer",
504
+ type: "cron",
505
+ status: "disabled",
506
+ };
507
+ mockFM.disableSchedule.mockResolvedValue(mockSchedule);
508
+ const response = await server.inject({
509
+ method: "POST",
510
+ url: "/api/schedules/reviewer/daily-review/disable",
511
+ });
512
+ expect(response.statusCode).toBe(200);
513
+ expect(response.json()).toEqual(mockSchedule);
514
+ expect(mockFM.disableSchedule).toHaveBeenCalledWith("reviewer", "daily-review");
515
+ });
516
+ it("returns 404 when schedule not found", async () => {
517
+ mockFM.disableSchedule.mockRejectedValue(new Error("Schedule not found: nonexistent"));
518
+ const response = await server.inject({
519
+ method: "POST",
520
+ url: "/api/schedules/reviewer/nonexistent/disable",
521
+ });
522
+ expect(response.statusCode).toBe(404);
523
+ });
524
+ it("returns 500 on unexpected error", async () => {
525
+ mockFM.disableSchedule.mockRejectedValue(new Error("State save failed"));
526
+ const response = await server.inject({
527
+ method: "POST",
528
+ url: "/api/schedules/reviewer/daily-review/disable",
529
+ });
530
+ expect(response.statusCode).toBe(500);
531
+ expect(response.json().error).toContain("State save failed");
532
+ });
533
+ });
534
+ });
535
+ //# sourceMappingURL=routes.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.test.js","sourceRoot":"","sources":["../../../src/server/__tests__/routes.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * WebSocket handler and type guard tests for @herdctl/web
3
+ *
4
+ * Tests the WebSocket message type guards and handler behavior.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=ws-handler.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-handler.test.d.ts","sourceRoot":"","sources":["../../../src/server/__tests__/ws-handler.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}