@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
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Fleet status REST API routes
3
+ *
4
+ * Provides endpoints for retrieving fleet-level status information.
5
+ */
6
+ import type { FastifyInstance } from "fastify";
7
+ import type { FleetManager } from "@herdctl/core";
8
+ /**
9
+ * Register fleet-related routes
10
+ *
11
+ * @param server - Fastify instance
12
+ * @param fleetManager - FleetManager instance
13
+ */
14
+ export declare function registerFleetRoutes(server: FastifyInstance, fleetManager: FleetManager): void;
15
+ //# sourceMappingURL=fleet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet.d.ts","sourceRoot":"","sources":["../../../src/server/routes/fleet.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,YAAY,GACzB,IAAI,CAsBN"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Fleet status REST API routes
3
+ *
4
+ * Provides endpoints for retrieving fleet-level status information.
5
+ */
6
+ /**
7
+ * Register fleet-related routes
8
+ *
9
+ * @param server - Fastify instance
10
+ * @param fleetManager - FleetManager instance
11
+ */
12
+ export function registerFleetRoutes(server, fleetManager) {
13
+ /**
14
+ * GET /api/fleet/status
15
+ *
16
+ * Returns the current fleet status including:
17
+ * - Fleet state (running, stopped, etc.)
18
+ * - Uptime information
19
+ * - Agent and job counts
20
+ * - Scheduler state
21
+ */
22
+ server.get("/api/fleet/status", async (_request, reply) => {
23
+ try {
24
+ const status = await fleetManager.getFleetStatus();
25
+ return reply.send(status);
26
+ }
27
+ catch (error) {
28
+ const message = error instanceof Error ? error.message : String(error);
29
+ return reply.status(500).send({
30
+ error: `Failed to get fleet status: ${message}`,
31
+ statusCode: 500,
32
+ });
33
+ }
34
+ });
35
+ }
36
+ //# sourceMappingURL=fleet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet.js","sourceRoot":"","sources":["../../../src/server/routes/fleet.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAuB,EACvB,YAA0B;IAE1B;;;;;;;;OAQG;IACH,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;QACxD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,cAAc,EAAE,CAAC;YACnD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC5B,KAAK,EAAE,+BAA+B,OAAO,EAAE;gBAC/C,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Job REST API routes
3
+ *
4
+ * Provides endpoints for retrieving job information with pagination and filtering,
5
+ * as well as job control actions (cancel, fork).
6
+ */
7
+ import type { FastifyInstance } from "fastify";
8
+ import type { FleetManager, listJobs } from "@herdctl/core";
9
+ /**
10
+ * Register job-related routes
11
+ *
12
+ * @param server - Fastify instance
13
+ * @param fleetManager - FleetManager instance
14
+ * @param listJobsFn - Function to list jobs from state directory
15
+ */
16
+ export declare function registerJobRoutes(server: FastifyInstance, fleetManager: FleetManager, listJobsFn: typeof listJobs): void;
17
+ //# sourceMappingURL=jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../../../src/server/routes/jobs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAa,QAAQ,EAAiB,MAAM,eAAe,CAAC;AA2CtF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,OAAO,QAAQ,GAC1B,IAAI,CAoLN"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Job REST API routes
3
+ *
4
+ * Provides endpoints for retrieving job information with pagination and filtering,
5
+ * as well as job control actions (cancel, fork).
6
+ */
7
+ import { createLogger, resolveWorkingDirectory } from "@herdctl/core";
8
+ const logger = createLogger("web:jobs");
9
+ /**
10
+ * Map a core Job object (snake_case) to a client-friendly JobSummary (camelCase)
11
+ */
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ function mapJobToSummary(job, agents) {
14
+ const agent = agents.find((a) => a.name === job.agent);
15
+ const workspace = agent ? resolveWorkingDirectory(agent) : undefined;
16
+ return {
17
+ jobId: job.id,
18
+ agentName: job.agent,
19
+ prompt: job.prompt ?? "",
20
+ status: job.status,
21
+ createdAt: job.started_at,
22
+ startedAt: job.started_at,
23
+ completedAt: job.finished_at ?? undefined,
24
+ exitCode: job.exit_reason === "success" ? 0 : job.exit_reason === "error" ? 1 : undefined,
25
+ error: undefined,
26
+ sessionId: job.session_id ?? undefined,
27
+ triggerType: job.trigger_type ?? "manual",
28
+ workspace,
29
+ };
30
+ }
31
+ /**
32
+ * Register job-related routes
33
+ *
34
+ * @param server - Fastify instance
35
+ * @param fleetManager - FleetManager instance
36
+ * @param listJobsFn - Function to list jobs from state directory
37
+ */
38
+ export function registerJobRoutes(server, fleetManager, listJobsFn) {
39
+ /**
40
+ * GET /api/jobs
41
+ *
42
+ * Returns a paginated list of jobs with optional filtering.
43
+ *
44
+ * Query parameters:
45
+ * - limit: Maximum number of jobs (default: 50, max: 100)
46
+ * - offset: Number of jobs to skip (default: 0)
47
+ * - agentName: Filter by agent name
48
+ * - status: Filter by job status (pending, running, completed, failed, cancelled)
49
+ */
50
+ server.get("/api/jobs", async (request, reply) => {
51
+ try {
52
+ const { limit = 50, offset = 0, agentName, status } = request.query;
53
+ // Validate and clamp limit
54
+ const clampedLimit = Math.min(Math.max(1, limit), 100);
55
+ const clampedOffset = Math.max(0, offset);
56
+ // Get jobs directory from FleetManager's state directory
57
+ const stateDir = fleetManager.getStateDir();
58
+ const jobsDir = `${stateDir}/jobs`;
59
+ // Build filter
60
+ const filter = {};
61
+ if (agentName) {
62
+ filter.agent = agentName;
63
+ }
64
+ if (status) {
65
+ filter.status = status;
66
+ }
67
+ // List all matching jobs (listJobs already sorts by started_at desc)
68
+ const result = await listJobsFn(jobsDir, filter);
69
+ // Apply pagination
70
+ const paginatedJobs = result.jobs.slice(clampedOffset, clampedOffset + clampedLimit);
71
+ const agents = fleetManager.getAgents();
72
+ return reply.send({
73
+ jobs: paginatedJobs.map((j) => mapJobToSummary(j, agents)),
74
+ total: result.jobs.length,
75
+ limit: clampedLimit,
76
+ offset: clampedOffset,
77
+ errors: result.errors,
78
+ });
79
+ }
80
+ catch (error) {
81
+ const message = error instanceof Error ? error.message : String(error);
82
+ return reply.status(500).send({
83
+ error: `Failed to list jobs: ${message}`,
84
+ statusCode: 500,
85
+ });
86
+ }
87
+ });
88
+ /**
89
+ * GET /api/jobs/:id
90
+ *
91
+ * Returns full metadata for a single job.
92
+ *
93
+ * @param id - Job ID (URL parameter)
94
+ */
95
+ server.get("/api/jobs/:id", async (request, reply) => {
96
+ try {
97
+ const { id } = request.params;
98
+ // Import getJob dynamically to avoid circular dependencies
99
+ const { getJob } = await import("@herdctl/core");
100
+ // Get jobs directory from FleetManager's state directory
101
+ const stateDir = fleetManager.getStateDir();
102
+ const jobsDir = `${stateDir}/jobs`;
103
+ const job = await getJob(jobsDir, id);
104
+ if (!job) {
105
+ return reply.status(404).send({
106
+ error: `Job not found: ${id}`,
107
+ statusCode: 404,
108
+ });
109
+ }
110
+ const agents = fleetManager.getAgents();
111
+ return reply.send(mapJobToSummary(job, agents));
112
+ }
113
+ catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ return reply.status(500).send({
116
+ error: `Failed to get job: ${message}`,
117
+ statusCode: 500,
118
+ });
119
+ }
120
+ });
121
+ /**
122
+ * POST /api/jobs/:id/cancel
123
+ *
124
+ * Cancels a running job.
125
+ *
126
+ * @param id - Job ID (URL parameter)
127
+ * @returns CancelJobResult
128
+ */
129
+ server.post("/api/jobs/:id/cancel", async (request, reply) => {
130
+ try {
131
+ const { id } = request.params;
132
+ logger.info("Cancelling job", { jobId: id });
133
+ const result = await fleetManager.cancelJob(id);
134
+ logger.info("Job cancelled", { jobId: id, terminationType: result.terminationType });
135
+ return reply.send(result);
136
+ }
137
+ catch (error) {
138
+ const message = error instanceof Error ? error.message : String(error);
139
+ if (message.toLowerCase().includes("not found")) {
140
+ return reply.status(404).send({
141
+ error: message,
142
+ statusCode: 404,
143
+ });
144
+ }
145
+ logger.error("Failed to cancel job", { error: message });
146
+ return reply.status(500).send({
147
+ error: `Failed to cancel job: ${message}`,
148
+ statusCode: 500,
149
+ });
150
+ }
151
+ });
152
+ /**
153
+ * POST /api/jobs/:id/fork
154
+ *
155
+ * Forks an existing job, creating a new job based on its configuration.
156
+ * Optionally accepts a prompt override.
157
+ *
158
+ * @param id - Job ID to fork (URL parameter)
159
+ * @body prompt - Optional prompt override for the forked job
160
+ * @returns ForkJobResult
161
+ */
162
+ server.post("/api/jobs/:id/fork", async (request, reply) => {
163
+ try {
164
+ const { id } = request.params;
165
+ const { prompt } = request.body ?? {};
166
+ const modifications = prompt ? { prompt } : undefined;
167
+ logger.info("Forking job", { jobId: id, hasPromptOverride: !!prompt });
168
+ const result = await fleetManager.forkJob(id, modifications);
169
+ logger.info("Job forked", { originalJobId: id, newJobId: result.jobId });
170
+ return reply.send(result);
171
+ }
172
+ catch (error) {
173
+ const message = error instanceof Error ? error.message : String(error);
174
+ if (message.toLowerCase().includes("not found")) {
175
+ return reply.status(404).send({
176
+ error: message,
177
+ statusCode: 404,
178
+ });
179
+ }
180
+ logger.error("Failed to fork job", { error: message });
181
+ return reply.status(500).send({
182
+ error: `Failed to fork job: ${message}`,
183
+ statusCode: 500,
184
+ });
185
+ }
186
+ });
187
+ }
188
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../../src/server/routes/jobs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAEtE,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;AAExC;;GAEG;AACH,8DAA8D;AAC9D,SAAS,eAAe,CAAC,GAAQ,EAAE,MAAuB;IACxD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAErE,OAAO;QACL,KAAK,EAAE,GAAG,CAAC,EAAE;QACb,SAAS,EAAE,GAAG,CAAC,KAAK;QACpB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;QACxB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,SAAS;QACzC,QAAQ,EAAE,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QACzF,KAAK,EAAE,SAAS;QAChB,SAAS,EAAE,GAAG,CAAC,UAAU,IAAI,SAAS;QACtC,WAAW,EAAE,GAAG,CAAC,YAAY,IAAI,QAAQ;QACzC,SAAS;KACV,CAAC;AACJ,CAAC;AAgBD;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAuB,EACvB,YAA0B,EAC1B,UAA2B;IAE3B;;;;;;;;;;OAUG;IACH,MAAM,CAAC,GAAG,CAEP,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;YAEpE,2BAA2B;YAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;YACvD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YAE1C,yDAAyD;YACzD,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,GAAG,QAAQ,OAAO,CAAC;YAEnC,eAAe;YACf,MAAM,MAAM,GAAqC,EAAE,CAAC;YACpD,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,CAAC,KAAK,GAAG,SAAS,CAAC;YAC3B,CAAC;YACD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACzB,CAAC;YAED,qEAAqE;YACrE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAEjD,mBAAmB;YACnB,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CACrC,aAAa,EACb,aAAa,GAAG,YAAY,CAC7B,CAAC;YAEF,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC;YACxC,OAAO,KAAK,CAAC,IAAI,CAAC;gBAChB,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;gBAC1D,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM;gBACzB,KAAK,EAAE,YAAY;gBACnB,MAAM,EAAE,aAAa;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC5B,KAAK,EAAE,wBAAwB,OAAO,EAAE;gBACxC,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH;;;;;;OAMG;IACH,MAAM,CAAC,GAAG,CAEP,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC3C,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;YAE9B,2DAA2D;YAC3D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;YAEjD,yDAAyD;YACzD,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,GAAG,QAAQ,OAAO,CAAC;YAEnC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAEtC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBAC5B,KAAK,EAAE,kBAAkB,EAAE,EAAE;oBAC7B,UAAU,EAAE,GAAG;iBAChB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC;YACxC,OAAO,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC5B,KAAK,EAAE,sBAAsB,OAAO,EAAE;gBACtC,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CAER,sBAAsB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAClD,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;YAE7C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAEhD,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;YACrF,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAEvE,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBAChD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBAC5B,KAAK,EAAE,OAAO;oBACd,UAAU,EAAE,GAAG;iBAChB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACzD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC5B,KAAK,EAAE,yBAAyB,OAAO,EAAE;gBACzC,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH;;;;;;;;;OASG;IACH,MAAM,CAAC,IAAI,CAGR,oBAAoB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAChD,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;YAC9B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YAEtC,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;YACtD,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;YAE7D,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YACzE,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAEvE,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBAChD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBAC5B,KAAK,EAAE,OAAO;oBACd,UAAU,EAAE,GAAG;iBAChB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACvD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC5B,KAAK,EAAE,uBAAuB,OAAO,EAAE;gBACvC,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Schedule REST API routes
3
+ *
4
+ * Provides endpoints for retrieving and managing schedule information,
5
+ * including triggering agents and enabling/disabling schedules.
6
+ */
7
+ import type { FastifyInstance } from "fastify";
8
+ import type { FleetManager } from "@herdctl/core";
9
+ /**
10
+ * Register schedule-related routes
11
+ *
12
+ * @param server - Fastify instance
13
+ * @param fleetManager - FleetManager instance
14
+ */
15
+ export declare function registerScheduleRoutes(server: FastifyInstance, fleetManager: FleetManager): void;
16
+ //# sourceMappingURL=schedules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedules.d.ts","sourceRoot":"","sources":["../../../src/server/routes/schedules.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,YAAY,GACzB,IAAI,CA4HN"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Schedule REST API routes
3
+ *
4
+ * Provides endpoints for retrieving and managing schedule information,
5
+ * including triggering agents and enabling/disabling schedules.
6
+ */
7
+ /**
8
+ * Register schedule-related routes
9
+ *
10
+ * @param server - Fastify instance
11
+ * @param fleetManager - FleetManager instance
12
+ */
13
+ export function registerScheduleRoutes(server, fleetManager) {
14
+ /**
15
+ * GET /api/schedules
16
+ *
17
+ * Returns all schedules across all agents.
18
+ * Each schedule includes:
19
+ * - Name and agent name
20
+ * - Type (interval, cron, webhook, chat)
21
+ * - Interval or cron expression
22
+ * - Status (idle, running, disabled)
23
+ * - Last run and next run timestamps
24
+ */
25
+ server.get("/api/schedules", async (_request, reply) => {
26
+ try {
27
+ const schedules = await fleetManager.getSchedules();
28
+ return reply.send(schedules);
29
+ }
30
+ catch (error) {
31
+ const message = error instanceof Error ? error.message : String(error);
32
+ return reply.status(500).send({
33
+ error: `Failed to get schedules: ${message}`,
34
+ statusCode: 500,
35
+ });
36
+ }
37
+ });
38
+ /**
39
+ * POST /api/agents/:name/trigger
40
+ *
41
+ * Triggers a job for the specified agent.
42
+ * Optionally targets a specific schedule and/or overrides the prompt.
43
+ *
44
+ * @param name - Agent name (URL parameter)
45
+ * @body scheduleName - Optional schedule name to trigger
46
+ * @body prompt - Optional prompt override
47
+ */
48
+ server.post("/api/agents/:name/trigger", async (request, reply) => {
49
+ try {
50
+ const { name } = request.params;
51
+ const { scheduleName, prompt } = request.body ?? {};
52
+ const result = await fleetManager.trigger(name, scheduleName, { prompt });
53
+ return reply.send(result);
54
+ }
55
+ catch (error) {
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ if (message.toLowerCase().includes("not found")) {
58
+ return reply.status(404).send({
59
+ error: message,
60
+ statusCode: 404,
61
+ });
62
+ }
63
+ return reply.status(500).send({
64
+ error: `Failed to trigger agent: ${message}`,
65
+ statusCode: 500,
66
+ });
67
+ }
68
+ });
69
+ /**
70
+ * POST /api/schedules/:agentName/:scheduleName/enable
71
+ *
72
+ * Enables a disabled schedule.
73
+ *
74
+ * @param agentName - Agent name (URL parameter)
75
+ * @param scheduleName - Schedule name (URL parameter)
76
+ */
77
+ server.post("/api/schedules/:agentName/:scheduleName/enable", async (request, reply) => {
78
+ try {
79
+ const { agentName, scheduleName } = request.params;
80
+ const schedule = await fleetManager.enableSchedule(agentName, scheduleName);
81
+ return reply.send(schedule);
82
+ }
83
+ catch (error) {
84
+ const message = error instanceof Error ? error.message : String(error);
85
+ if (message.toLowerCase().includes("not found")) {
86
+ return reply.status(404).send({
87
+ error: message,
88
+ statusCode: 404,
89
+ });
90
+ }
91
+ return reply.status(500).send({
92
+ error: `Failed to enable schedule: ${message}`,
93
+ statusCode: 500,
94
+ });
95
+ }
96
+ });
97
+ /**
98
+ * POST /api/schedules/:agentName/:scheduleName/disable
99
+ *
100
+ * Disables an active schedule.
101
+ *
102
+ * @param agentName - Agent name (URL parameter)
103
+ * @param scheduleName - Schedule name (URL parameter)
104
+ */
105
+ server.post("/api/schedules/:agentName/:scheduleName/disable", async (request, reply) => {
106
+ try {
107
+ const { agentName, scheduleName } = request.params;
108
+ const schedule = await fleetManager.disableSchedule(agentName, scheduleName);
109
+ return reply.send(schedule);
110
+ }
111
+ catch (error) {
112
+ const message = error instanceof Error ? error.message : String(error);
113
+ if (message.toLowerCase().includes("not found")) {
114
+ return reply.status(404).send({
115
+ error: message,
116
+ statusCode: 404,
117
+ });
118
+ }
119
+ return reply.status(500).send({
120
+ error: `Failed to disable schedule: ${message}`,
121
+ statusCode: 500,
122
+ });
123
+ }
124
+ });
125
+ }
126
+ //# sourceMappingURL=schedules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedules.js","sourceRoot":"","sources":["../../../src/server/routes/schedules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Fleet Bridge - Connects FleetManager events to WebSocket broadcasts
3
+ *
4
+ * This module subscribes to FleetManager events and broadcasts them to
5
+ * connected WebSocket clients. It handles event filtering so that high-volume
6
+ * events like job:output are only sent to subscribed clients.
7
+ */
8
+ import { type FleetManager } from "@herdctl/core";
9
+ import type { WebSocketHandler } from "./handler.js";
10
+ /**
11
+ * FleetBridge connects FleetManager events to WebSocket clients
12
+ */
13
+ export declare class FleetBridge {
14
+ private fleetManager;
15
+ private wsHandler;
16
+ private isStarted;
17
+ private handlers;
18
+ constructor(fleetManager: FleetManager, wsHandler: WebSocketHandler);
19
+ /**
20
+ * Start listening to FleetManager events and broadcasting to WebSocket clients
21
+ */
22
+ start(): void;
23
+ /**
24
+ * Stop listening to FleetManager events
25
+ */
26
+ stop(): void;
27
+ /**
28
+ * Check if the bridge is currently running
29
+ */
30
+ isRunning(): boolean;
31
+ /**
32
+ * Handle agent:started event
33
+ *
34
+ * Broadcast to ALL clients (low volume event)
35
+ */
36
+ private onAgentStarted;
37
+ /**
38
+ * Handle agent:stopped event
39
+ *
40
+ * Broadcast to ALL clients (low volume event)
41
+ */
42
+ private onAgentStopped;
43
+ /**
44
+ * Handle job:created event
45
+ *
46
+ * Broadcast to ALL clients (low volume event)
47
+ */
48
+ private onJobCreated;
49
+ /**
50
+ * Handle job:output event
51
+ *
52
+ * Broadcast ONLY to clients subscribed to this agent (high volume event)
53
+ */
54
+ private onJobOutput;
55
+ /**
56
+ * Handle job:completed event
57
+ *
58
+ * Broadcast to ALL clients (low volume event)
59
+ */
60
+ private onJobCompleted;
61
+ /**
62
+ * Handle job:failed event
63
+ *
64
+ * Broadcast to ALL clients (low volume event)
65
+ */
66
+ private onJobFailed;
67
+ /**
68
+ * Handle job:cancelled event
69
+ *
70
+ * Broadcast to ALL clients (low volume event)
71
+ */
72
+ private onJobCancelled;
73
+ /**
74
+ * Handle schedule:triggered event
75
+ *
76
+ * Broadcast to ALL clients (low volume event)
77
+ */
78
+ private onScheduleTriggered;
79
+ }
80
+ //# sourceMappingURL=fleet-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet-bridge.d.ts","sourceRoot":"","sources":["../../../src/server/ws/fleet-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEL,KAAK,YAAY,EASlB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIrD;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,QAAQ,CASd;gBAEU,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,gBAAgB;IAKnE;;OAEG;IACH,KAAK,IAAI,IAAI;IAsBb;;OAEG;IACH,IAAI,IAAI,IAAI;IAsBZ;;OAEG;IACH,SAAS,IAAI,OAAO;IAQpB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAQpB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAYnB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAQnB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;CAO5B"}