@herdctl/web 0.0.1 → 0.1.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.
- package/LICENSE +21 -0
- package/dist/client/assets/index-Cyochp2F.css +1 -0
- package/dist/client/assets/index-mp9jz5eD.js +373 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/favicon.svg +1 -0
- package/dist/client/herdctl-logo.svg +29 -0
- package/dist/client/index.html +21 -0
- package/dist/server/__tests__/routes.test.d.ts +8 -0
- package/dist/server/__tests__/routes.test.d.ts.map +1 -0
- package/dist/server/__tests__/routes.test.js +535 -0
- package/dist/server/__tests__/routes.test.js.map +1 -0
- package/dist/server/__tests__/ws-handler.test.d.ts +7 -0
- package/dist/server/__tests__/ws-handler.test.d.ts.map +1 -0
- package/dist/server/__tests__/ws-handler.test.js +380 -0
- package/dist/server/__tests__/ws-handler.test.js.map +1 -0
- package/dist/server/chat/index.d.ts +5 -0
- package/dist/server/chat/index.d.ts.map +1 -0
- package/dist/server/chat/index.js +5 -0
- package/dist/server/chat/index.js.map +1 -0
- package/dist/server/chat/web-chat-manager.d.ts +158 -0
- package/dist/server/chat/web-chat-manager.d.ts.map +1 -0
- package/dist/server/chat/web-chat-manager.js +437 -0
- package/dist/server/chat/web-chat-manager.js.map +1 -0
- package/dist/server/index.d.ts +144 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +341 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/routes/agents.d.ts +15 -0
- package/dist/server/routes/agents.d.ts.map +1 -0
- package/dist/server/routes/agents.js +66 -0
- package/dist/server/routes/agents.js.map +1 -0
- package/dist/server/routes/chat.d.ts +18 -0
- package/dist/server/routes/chat.d.ts.map +1 -0
- package/dist/server/routes/chat.js +191 -0
- package/dist/server/routes/chat.js.map +1 -0
- package/dist/server/routes/fleet.d.ts +15 -0
- package/dist/server/routes/fleet.d.ts.map +1 -0
- package/dist/server/routes/fleet.js +36 -0
- package/dist/server/routes/fleet.js.map +1 -0
- package/dist/server/routes/jobs.d.ts +17 -0
- package/dist/server/routes/jobs.d.ts.map +1 -0
- package/dist/server/routes/jobs.js +188 -0
- package/dist/server/routes/jobs.js.map +1 -0
- package/dist/server/routes/schedules.d.ts +16 -0
- package/dist/server/routes/schedules.d.ts.map +1 -0
- package/dist/server/routes/schedules.js +126 -0
- package/dist/server/routes/schedules.js.map +1 -0
- package/dist/server/ws/fleet-bridge.d.ts +80 -0
- package/dist/server/ws/fleet-bridge.d.ts.map +1 -0
- package/dist/server/ws/fleet-bridge.js +184 -0
- package/dist/server/ws/fleet-bridge.js.map +1 -0
- package/dist/server/ws/handler.d.ts +93 -0
- package/dist/server/ws/handler.d.ts.map +1 -0
- package/dist/server/ws/handler.js +270 -0
- package/dist/server/ws/handler.js.map +1 -0
- package/dist/server/ws/index.d.ts +8 -0
- package/dist/server/ws/index.d.ts.map +1 -0
- package/dist/server/ws/index.js +8 -0
- package/dist/server/ws/index.js.map +1 -0
- package/dist/server/ws/types.d.ts +215 -0
- package/dist/server/ws/types.d.ts.map +1 -0
- package/dist/server/ws/types.js +67 -0
- package/dist/server/ws/types.js.map +1 -0
- package/package.json +77 -1
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web server factory and WebManager for @herdctl/web
|
|
3
|
+
*
|
|
4
|
+
* Creates a Fastify server that serves the React SPA and provides
|
|
5
|
+
* REST API endpoints and WebSocket connections for fleet management.
|
|
6
|
+
*/
|
|
7
|
+
import Fastify from "fastify";
|
|
8
|
+
import fastifyCors from "@fastify/cors";
|
|
9
|
+
import fastifyStatic from "@fastify/static";
|
|
10
|
+
import fastifyWebsocket from "@fastify/websocket";
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
import { join, dirname } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { createLogger, listJobs, } from "@herdctl/core";
|
|
15
|
+
import { registerFleetRoutes } from "./routes/fleet.js";
|
|
16
|
+
import { registerAgentRoutes } from "./routes/agents.js";
|
|
17
|
+
import { registerJobRoutes } from "./routes/jobs.js";
|
|
18
|
+
import { registerScheduleRoutes } from "./routes/schedules.js";
|
|
19
|
+
import { registerChatRoutes } from "./routes/chat.js";
|
|
20
|
+
import { WebSocketHandler, FleetBridge } from "./ws/index.js";
|
|
21
|
+
import { WebChatManager } from "./chat/index.js";
|
|
22
|
+
const logger = createLogger("web");
|
|
23
|
+
// Get the directory of this file to find the client build
|
|
24
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
25
|
+
const __dirname = dirname(__filename);
|
|
26
|
+
/**
|
|
27
|
+
* Creates a Fastify web server instance with WebSocket support
|
|
28
|
+
*
|
|
29
|
+
* The server is returned but NOT started - the caller controls the lifecycle.
|
|
30
|
+
* The returned FleetBridge should be started after the server starts listening,
|
|
31
|
+
* and stopped before the server closes.
|
|
32
|
+
*
|
|
33
|
+
* @param fleetManager - FleetManager instance for API calls and event subscription
|
|
34
|
+
* @param config - Server configuration
|
|
35
|
+
* @returns WebServerResult containing server, wsHandler, fleetBridge, and chatManager
|
|
36
|
+
*/
|
|
37
|
+
export async function createWebServer(fleetManager, config) {
|
|
38
|
+
const server = Fastify({
|
|
39
|
+
logger: false, // We use our own logger
|
|
40
|
+
});
|
|
41
|
+
// Register CORS for development (allow localhost origins)
|
|
42
|
+
await server.register(fastifyCors, {
|
|
43
|
+
origin: [
|
|
44
|
+
"http://localhost:3232",
|
|
45
|
+
"http://localhost:5173", // Vite dev server
|
|
46
|
+
"http://127.0.0.1:3232",
|
|
47
|
+
"http://127.0.0.1:5173",
|
|
48
|
+
`http://${config.host}:${config.port}`,
|
|
49
|
+
],
|
|
50
|
+
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
51
|
+
});
|
|
52
|
+
// Register WebSocket plugin
|
|
53
|
+
await server.register(fastifyWebsocket);
|
|
54
|
+
// Create WebSocket handler, fleet bridge, and chat manager
|
|
55
|
+
const wsHandler = new WebSocketHandler(fleetManager);
|
|
56
|
+
const fleetBridge = new FleetBridge(fleetManager, wsHandler);
|
|
57
|
+
const chatManager = new WebChatManager();
|
|
58
|
+
// Initialize chat manager if state directory is provided
|
|
59
|
+
if (config.stateDir) {
|
|
60
|
+
await chatManager.initialize(fleetManager, config.stateDir, {
|
|
61
|
+
enabled: true,
|
|
62
|
+
port: config.port,
|
|
63
|
+
host: config.host,
|
|
64
|
+
session_expiry_hours: config.sessionExpiryHours ?? 24,
|
|
65
|
+
open_browser: false,
|
|
66
|
+
});
|
|
67
|
+
// Wire up chat manager to WebSocket handler
|
|
68
|
+
wsHandler.setChatManager(chatManager);
|
|
69
|
+
}
|
|
70
|
+
// Register WebSocket route at /ws
|
|
71
|
+
server.get("/ws", { websocket: true }, (socket, _request) => {
|
|
72
|
+
// Handle new WebSocket connection
|
|
73
|
+
wsHandler.handleConnection(socket).catch((error) => {
|
|
74
|
+
logger.warn(`Error handling WebSocket connection: ${error.message}`);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// Register static file serving for the built React SPA
|
|
78
|
+
// The client build outputs to dist/client/ relative to package root
|
|
79
|
+
// When compiled, this file is at dist/server/index.js
|
|
80
|
+
// So we need to go up two levels to get to dist/client
|
|
81
|
+
const clientDistPath = join(__dirname, "..", "client");
|
|
82
|
+
try {
|
|
83
|
+
await server.register(fastifyStatic, {
|
|
84
|
+
root: clientDistPath,
|
|
85
|
+
prefix: "/",
|
|
86
|
+
// Don't serve index.html for API routes
|
|
87
|
+
wildcard: false,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Client dist may not exist in development - that's OK
|
|
92
|
+
logger.debug("Client dist not found, static serving disabled");
|
|
93
|
+
}
|
|
94
|
+
// Register REST API routes
|
|
95
|
+
registerFleetRoutes(server, fleetManager);
|
|
96
|
+
registerAgentRoutes(server, fleetManager);
|
|
97
|
+
registerJobRoutes(server, fleetManager, listJobs);
|
|
98
|
+
registerScheduleRoutes(server, fleetManager);
|
|
99
|
+
registerChatRoutes(server, fleetManager, chatManager);
|
|
100
|
+
// Health check endpoint
|
|
101
|
+
server.get("/api/health", async (_request, reply) => {
|
|
102
|
+
return reply.send({ status: "ok", timestamp: new Date().toISOString() });
|
|
103
|
+
});
|
|
104
|
+
// SPA fallback - serve index.html for non-API, non-WS routes
|
|
105
|
+
// This must be registered after static file serving and API routes
|
|
106
|
+
const indexPath = join(clientDistPath, "index.html");
|
|
107
|
+
server.setNotFoundHandler(async (request, reply) => {
|
|
108
|
+
const url = request.url;
|
|
109
|
+
// Don't serve SPA for API routes, WebSocket, or static assets
|
|
110
|
+
if (url.startsWith("/api/") ||
|
|
111
|
+
url === "/ws" ||
|
|
112
|
+
url.startsWith("/assets/")) {
|
|
113
|
+
return reply.status(404).send({ error: "Not found" });
|
|
114
|
+
}
|
|
115
|
+
// Serve index.html for SPA routing
|
|
116
|
+
if (existsSync(indexPath)) {
|
|
117
|
+
const html = readFileSync(indexPath, "utf-8");
|
|
118
|
+
return reply.type("text/html").send(html);
|
|
119
|
+
}
|
|
120
|
+
// Client build not available
|
|
121
|
+
return reply.status(503).send({
|
|
122
|
+
error: "Client not built",
|
|
123
|
+
message: "Run 'pnpm build:client' to build the web dashboard",
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
// Log registered routes in debug mode
|
|
127
|
+
logger.debug("Web server routes registered (REST + WebSocket + SPA fallback)");
|
|
128
|
+
return { server, wsHandler, fleetBridge, chatManager };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* WebManager manages the web dashboard server lifecycle
|
|
132
|
+
*
|
|
133
|
+
* Implements IChatManager interface for integration with FleetManager.
|
|
134
|
+
* Unlike Discord/Slack managers which have per-agent connectors,
|
|
135
|
+
* WebManager provides a single dashboard that serves all agents.
|
|
136
|
+
*/
|
|
137
|
+
export class WebManager {
|
|
138
|
+
ctx;
|
|
139
|
+
server = null;
|
|
140
|
+
wsHandler = null;
|
|
141
|
+
fleetBridge = null;
|
|
142
|
+
initialized = false;
|
|
143
|
+
connectorState = {
|
|
144
|
+
status: "disconnected",
|
|
145
|
+
connectedAt: null,
|
|
146
|
+
disconnectedAt: null,
|
|
147
|
+
reconnectAttempts: 0,
|
|
148
|
+
lastError: null,
|
|
149
|
+
botUser: null,
|
|
150
|
+
messageStats: {
|
|
151
|
+
received: 0,
|
|
152
|
+
sent: 0,
|
|
153
|
+
ignored: 0,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
constructor(ctx) {
|
|
157
|
+
this.ctx = ctx;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Initialize the web manager
|
|
161
|
+
*
|
|
162
|
+
* Creates the Fastify server with WebSocket support and REST API routes.
|
|
163
|
+
* Does not start listening - that happens in start().
|
|
164
|
+
*/
|
|
165
|
+
async initialize() {
|
|
166
|
+
if (this.initialized) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const log = this.ctx.getLogger();
|
|
170
|
+
const config = this.ctx.getConfig();
|
|
171
|
+
// Web config is at fleet level (config.fleet.web), not on ResolvedConfig directly
|
|
172
|
+
if (!config?.fleet?.web?.enabled) {
|
|
173
|
+
log.debug("Web UI not enabled in configuration");
|
|
174
|
+
this.initialized = true;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const webConfig = config.fleet.web;
|
|
178
|
+
try {
|
|
179
|
+
// Get the FleetManager instance (the context IS the FleetManager)
|
|
180
|
+
const fleetManager = this.ctx.getEmitter();
|
|
181
|
+
// Create the web server with all components
|
|
182
|
+
const stateDir = this.ctx.getStateDir();
|
|
183
|
+
const result = await createWebServer(fleetManager, {
|
|
184
|
+
host: webConfig.host,
|
|
185
|
+
port: webConfig.port,
|
|
186
|
+
stateDir,
|
|
187
|
+
sessionExpiryHours: webConfig.session_expiry_hours,
|
|
188
|
+
});
|
|
189
|
+
this.server = result.server;
|
|
190
|
+
this.wsHandler = result.wsHandler;
|
|
191
|
+
this.fleetBridge = result.fleetBridge;
|
|
192
|
+
this.initialized = true;
|
|
193
|
+
log.debug("Web manager initialized");
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
197
|
+
this.connectorState.lastError = errorMessage;
|
|
198
|
+
log.error(`Failed to initialize web manager: ${errorMessage}`);
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Start the web server
|
|
204
|
+
*
|
|
205
|
+
* Starts listening on the configured host:port and begins
|
|
206
|
+
* broadcasting FleetManager events to WebSocket clients.
|
|
207
|
+
*/
|
|
208
|
+
async start() {
|
|
209
|
+
const log = this.ctx.getLogger();
|
|
210
|
+
const config = this.ctx.getConfig();
|
|
211
|
+
// Web config is at fleet level (config.fleet.web)
|
|
212
|
+
if (!config?.fleet?.web?.enabled) {
|
|
213
|
+
log.debug("Web UI not enabled, skipping start");
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (!this.initialized) {
|
|
217
|
+
throw new Error("WebManager must be initialized before starting");
|
|
218
|
+
}
|
|
219
|
+
if (!this.server || !this.fleetBridge) {
|
|
220
|
+
log.debug("Web server not created (initialization may have failed)");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const webConfig = config.fleet.web;
|
|
224
|
+
try {
|
|
225
|
+
// Start the Fastify server
|
|
226
|
+
await this.server.listen({
|
|
227
|
+
host: webConfig.host,
|
|
228
|
+
port: webConfig.port,
|
|
229
|
+
});
|
|
230
|
+
// Start the fleet bridge to broadcast events
|
|
231
|
+
this.fleetBridge.start();
|
|
232
|
+
// Update connector state
|
|
233
|
+
this.connectorState.status = "connected";
|
|
234
|
+
this.connectorState.connectedAt = new Date().toISOString();
|
|
235
|
+
this.connectorState.lastError = null;
|
|
236
|
+
const url = `http://${webConfig.host}:${webConfig.port}`;
|
|
237
|
+
log.info(`Web dashboard available at ${url}`);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
241
|
+
this.connectorState.status = "error";
|
|
242
|
+
this.connectorState.lastError = errorMessage;
|
|
243
|
+
log.error(`Failed to start web server: ${errorMessage}`);
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Stop the web server
|
|
249
|
+
*
|
|
250
|
+
* Gracefully shuts down the Fastify server and stops event broadcasting.
|
|
251
|
+
*/
|
|
252
|
+
async stop() {
|
|
253
|
+
const log = this.ctx.getLogger();
|
|
254
|
+
if (this.fleetBridge) {
|
|
255
|
+
this.fleetBridge.stop();
|
|
256
|
+
}
|
|
257
|
+
if (this.wsHandler) {
|
|
258
|
+
this.wsHandler.closeAll();
|
|
259
|
+
}
|
|
260
|
+
if (this.server) {
|
|
261
|
+
try {
|
|
262
|
+
await this.server.close();
|
|
263
|
+
log.debug("Web server stopped");
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
267
|
+
log.warn(`Error stopping web server: ${errorMessage}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
this.connectorState.status = "disconnected";
|
|
271
|
+
this.connectorState.disconnectedAt = new Date().toISOString();
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Check if the manager is initialized
|
|
275
|
+
*/
|
|
276
|
+
isInitialized() {
|
|
277
|
+
return this.initialized;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Get the connector names managed by this manager
|
|
281
|
+
*
|
|
282
|
+
* Unlike Discord/Slack which have per-agent connectors,
|
|
283
|
+
* the web dashboard returns ["web"] to indicate it manages
|
|
284
|
+
* the single web interface.
|
|
285
|
+
*/
|
|
286
|
+
getConnectorNames() {
|
|
287
|
+
return ["web"];
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get the count of connected WebSocket clients
|
|
291
|
+
*/
|
|
292
|
+
getConnectedCount() {
|
|
293
|
+
return this.wsHandler?.getConnectedCount() ?? 0;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Check if a specific agent is accessible via the web dashboard
|
|
297
|
+
*
|
|
298
|
+
* All agents are accessible via the web dashboard, so this always returns true.
|
|
299
|
+
*/
|
|
300
|
+
hasAgent(_agentName) {
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Get the connector state for a specific agent
|
|
305
|
+
*
|
|
306
|
+
* Since the web dashboard doesn't have per-agent connectors,
|
|
307
|
+
* this returns the overall web server state for any agent.
|
|
308
|
+
*/
|
|
309
|
+
getState(_agentName) {
|
|
310
|
+
return {
|
|
311
|
+
...this.connectorState,
|
|
312
|
+
// Update message stats with current connected count
|
|
313
|
+
messageStats: {
|
|
314
|
+
...this.connectorState.messageStats,
|
|
315
|
+
// We can use received to track total connections over time if needed
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Get the internal web manager state
|
|
321
|
+
*
|
|
322
|
+
* This provides additional state information beyond the IChatManager interface.
|
|
323
|
+
*/
|
|
324
|
+
getWebState() {
|
|
325
|
+
const config = this.ctx.getConfig();
|
|
326
|
+
const webConfig = config?.fleet?.web;
|
|
327
|
+
return {
|
|
328
|
+
initialized: this.initialized,
|
|
329
|
+
running: this.connectorState.status === "connected",
|
|
330
|
+
host: webConfig?.host ?? null,
|
|
331
|
+
port: webConfig?.port ?? null,
|
|
332
|
+
connectedClients: this.getConnectedCount(),
|
|
333
|
+
startedAt: this.connectorState.connectedAt,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// Re-export WebSocket types for consumers
|
|
338
|
+
export { WebSocketHandler, FleetBridge, isClientMessage, isChatSendMessage, isAgentStartedPayload, isAgentStoppedPayload, } from "./ws/index.js";
|
|
339
|
+
// Re-export chat types for consumers
|
|
340
|
+
export { WebChatManager, } from "./chat/index.js";
|
|
341
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent REST API routes
|
|
3
|
+
*
|
|
4
|
+
* Provides endpoints for retrieving agent information.
|
|
5
|
+
*/
|
|
6
|
+
import type { FastifyInstance } from "fastify";
|
|
7
|
+
import type { FleetManager } from "@herdctl/core";
|
|
8
|
+
/**
|
|
9
|
+
* Register agent-related routes
|
|
10
|
+
*
|
|
11
|
+
* @param server - Fastify instance
|
|
12
|
+
* @param fleetManager - FleetManager instance
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerAgentRoutes(server: FastifyInstance, fleetManager: FleetManager): void;
|
|
15
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/server/routes/agents.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,CAwDN"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent REST API routes
|
|
3
|
+
*
|
|
4
|
+
* Provides endpoints for retrieving agent information.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Register agent-related routes
|
|
8
|
+
*
|
|
9
|
+
* @param server - Fastify instance
|
|
10
|
+
* @param fleetManager - FleetManager instance
|
|
11
|
+
*/
|
|
12
|
+
export function registerAgentRoutes(server, fleetManager) {
|
|
13
|
+
/**
|
|
14
|
+
* GET /api/agents
|
|
15
|
+
*
|
|
16
|
+
* Returns a list of all agents with their current status.
|
|
17
|
+
* Each agent includes:
|
|
18
|
+
* - Name and description
|
|
19
|
+
* - Current status (idle, running, error)
|
|
20
|
+
* - Current/last job IDs
|
|
21
|
+
* - Schedule information
|
|
22
|
+
* - Chat connector statuses
|
|
23
|
+
*/
|
|
24
|
+
server.get("/api/agents", async (_request, reply) => {
|
|
25
|
+
try {
|
|
26
|
+
const agents = await fleetManager.getAgentInfo();
|
|
27
|
+
return reply.send(agents);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
+
return reply.status(500).send({
|
|
32
|
+
error: `Failed to get agents: ${message}`,
|
|
33
|
+
statusCode: 500,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* GET /api/agents/:name
|
|
39
|
+
*
|
|
40
|
+
* Returns detailed information for a single agent.
|
|
41
|
+
*
|
|
42
|
+
* @param name - Agent name (URL parameter)
|
|
43
|
+
*/
|
|
44
|
+
server.get("/api/agents/:name", async (request, reply) => {
|
|
45
|
+
try {
|
|
46
|
+
const { name } = request.params;
|
|
47
|
+
const agent = await fleetManager.getAgentInfoByName(name);
|
|
48
|
+
return reply.send(agent);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
+
// Check if it's a "not found" error
|
|
53
|
+
if (message.toLowerCase().includes("not found")) {
|
|
54
|
+
return reply.status(404).send({
|
|
55
|
+
error: message,
|
|
56
|
+
statusCode: 404,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return reply.status(500).send({
|
|
60
|
+
error: `Failed to get agent: ${message}`,
|
|
61
|
+
statusCode: 500,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/server/routes/agents.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAuB,EACvB,YAA0B;IAE1B;;;;;;;;;;OAUG;IACH,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;QAClD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,YAAY,EAAE,CAAC;YACjD,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,yBAAyB,OAAO,EAAE;gBACzC,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH;;;;;;OAMG;IACH,MAAM,CAAC,GAAG,CAEP,mBAAmB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC/C,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;YAChC,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,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,oCAAoC;YACpC,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,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;AACL,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat REST API routes
|
|
3
|
+
*
|
|
4
|
+
* Provides endpoints for managing chat sessions and messages.
|
|
5
|
+
* Actual message streaming happens via WebSocket.
|
|
6
|
+
*/
|
|
7
|
+
import type { FastifyInstance } from "fastify";
|
|
8
|
+
import type { FleetManager } from "@herdctl/core";
|
|
9
|
+
import type { WebChatManager } from "../chat/index.js";
|
|
10
|
+
/**
|
|
11
|
+
* Register chat-related routes
|
|
12
|
+
*
|
|
13
|
+
* @param server - Fastify instance
|
|
14
|
+
* @param fleetManager - FleetManager instance
|
|
15
|
+
* @param chatManager - WebChatManager instance
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerChatRoutes(server: FastifyInstance, fleetManager: FleetManager, chatManager: WebChatManager): void;
|
|
18
|
+
//# sourceMappingURL=chat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/server/routes/chat.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,cAAc,GAC1B,IAAI,CA+MN"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat REST API routes
|
|
3
|
+
*
|
|
4
|
+
* Provides endpoints for managing chat sessions and messages.
|
|
5
|
+
* Actual message streaming happens via WebSocket.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Register chat-related routes
|
|
9
|
+
*
|
|
10
|
+
* @param server - Fastify instance
|
|
11
|
+
* @param fleetManager - FleetManager instance
|
|
12
|
+
* @param chatManager - WebChatManager instance
|
|
13
|
+
*/
|
|
14
|
+
export function registerChatRoutes(server, fleetManager, chatManager) {
|
|
15
|
+
/**
|
|
16
|
+
* POST /api/chat/:agentName/sessions
|
|
17
|
+
*
|
|
18
|
+
* Create a new chat session for an agent.
|
|
19
|
+
*
|
|
20
|
+
* @returns { sessionId, createdAt }
|
|
21
|
+
*/
|
|
22
|
+
server.post("/api/chat/:agentName/sessions", async (request, reply) => {
|
|
23
|
+
try {
|
|
24
|
+
const { agentName } = request.params;
|
|
25
|
+
// Verify agent exists
|
|
26
|
+
try {
|
|
27
|
+
await fleetManager.getAgentInfoByName(agentName);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return reply.status(404).send({
|
|
31
|
+
error: `Agent not found: ${agentName}`,
|
|
32
|
+
statusCode: 404,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const session = await chatManager.createSession(agentName);
|
|
36
|
+
return reply.status(201).send({
|
|
37
|
+
sessionId: session.sessionId,
|
|
38
|
+
createdAt: session.createdAt,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
43
|
+
return reply.status(500).send({
|
|
44
|
+
error: `Failed to create session: ${message}`,
|
|
45
|
+
statusCode: 500,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* GET /api/chat/:agentName/sessions
|
|
51
|
+
*
|
|
52
|
+
* List all chat sessions for an agent.
|
|
53
|
+
*
|
|
54
|
+
* @returns { sessions: [{ sessionId, createdAt, lastMessageAt, messageCount, preview }] }
|
|
55
|
+
*/
|
|
56
|
+
server.get("/api/chat/:agentName/sessions", async (request, reply) => {
|
|
57
|
+
try {
|
|
58
|
+
const { agentName } = request.params;
|
|
59
|
+
// Verify agent exists
|
|
60
|
+
try {
|
|
61
|
+
await fleetManager.getAgentInfoByName(agentName);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return reply.status(404).send({
|
|
65
|
+
error: `Agent not found: ${agentName}`,
|
|
66
|
+
statusCode: 404,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const sessions = await chatManager.listSessions(agentName);
|
|
70
|
+
return reply.send({ sessions });
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
74
|
+
return reply.status(500).send({
|
|
75
|
+
error: `Failed to list sessions: ${message}`,
|
|
76
|
+
statusCode: 500,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* GET /api/chat/:agentName/sessions/:sessionId
|
|
82
|
+
*
|
|
83
|
+
* Get session details with message history.
|
|
84
|
+
*
|
|
85
|
+
* @returns { sessionId, messages, createdAt, lastMessageAt }
|
|
86
|
+
*/
|
|
87
|
+
server.get("/api/chat/:agentName/sessions/:sessionId", async (request, reply) => {
|
|
88
|
+
try {
|
|
89
|
+
const { agentName, sessionId } = request.params;
|
|
90
|
+
const session = await chatManager.getSession(agentName, sessionId);
|
|
91
|
+
if (!session) {
|
|
92
|
+
return reply.status(404).send({
|
|
93
|
+
error: `Session not found: ${sessionId}`,
|
|
94
|
+
statusCode: 404,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return reply.send(session);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
101
|
+
return reply.status(500).send({
|
|
102
|
+
error: `Failed to get session: ${message}`,
|
|
103
|
+
statusCode: 500,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* DELETE /api/chat/:agentName/sessions/:sessionId
|
|
109
|
+
*
|
|
110
|
+
* Delete a chat session.
|
|
111
|
+
*
|
|
112
|
+
* @returns { deleted: true }
|
|
113
|
+
*/
|
|
114
|
+
server.delete("/api/chat/:agentName/sessions/:sessionId", async (request, reply) => {
|
|
115
|
+
try {
|
|
116
|
+
const { agentName, sessionId } = request.params;
|
|
117
|
+
const deleted = await chatManager.deleteSession(agentName, sessionId);
|
|
118
|
+
if (!deleted) {
|
|
119
|
+
return reply.status(404).send({
|
|
120
|
+
error: `Session not found: ${sessionId}`,
|
|
121
|
+
statusCode: 404,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return reply.send({ deleted: true });
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
128
|
+
return reply.status(500).send({
|
|
129
|
+
error: `Failed to delete session: ${message}`,
|
|
130
|
+
statusCode: 500,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* POST /api/chat/:agentName/sessions/:sessionId/messages
|
|
136
|
+
*
|
|
137
|
+
* Send a message in a chat session. The actual response streams via WebSocket.
|
|
138
|
+
*
|
|
139
|
+
* Request body: { message: string }
|
|
140
|
+
* @returns { jobId }
|
|
141
|
+
*/
|
|
142
|
+
server.post("/api/chat/:agentName/sessions/:sessionId/messages", async (request, reply) => {
|
|
143
|
+
try {
|
|
144
|
+
const { agentName, sessionId } = request.params;
|
|
145
|
+
const { message } = request.body;
|
|
146
|
+
if (!message || typeof message !== "string") {
|
|
147
|
+
return reply.status(400).send({
|
|
148
|
+
error: "Message is required",
|
|
149
|
+
statusCode: 400,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// Verify session exists
|
|
153
|
+
const session = await chatManager.getSession(agentName, sessionId);
|
|
154
|
+
if (!session) {
|
|
155
|
+
return reply.status(404).send({
|
|
156
|
+
error: `Session not found: ${sessionId}`,
|
|
157
|
+
statusCode: 404,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
// Note: This endpoint just validates and returns immediately.
|
|
161
|
+
// The actual message sending should be done via WebSocket (chat:send)
|
|
162
|
+
// to enable streaming responses.
|
|
163
|
+
//
|
|
164
|
+
// However, we provide this REST endpoint for clients that want a simpler
|
|
165
|
+
// request/response pattern without streaming.
|
|
166
|
+
// In that case, we collect all chunks and return when complete.
|
|
167
|
+
let response = "";
|
|
168
|
+
const result = await chatManager.sendMessage(agentName, sessionId, message, (chunk) => {
|
|
169
|
+
response += chunk;
|
|
170
|
+
});
|
|
171
|
+
if (!result.success) {
|
|
172
|
+
return reply.status(500).send({
|
|
173
|
+
error: result.error ?? "Failed to send message",
|
|
174
|
+
statusCode: 500,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return reply.send({
|
|
178
|
+
jobId: result.jobId,
|
|
179
|
+
response,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
184
|
+
return reply.status(500).send({
|
|
185
|
+
error: `Failed to send message: ${message}`,
|
|
186
|
+
statusCode: 500,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/server/routes/chat.ts"],"names":[],"mappings":"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"}
|