@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,437 @@
1
+ /**
2
+ * Web Chat Manager for @herdctl/web
3
+ *
4
+ * Manages chat sessions for the web platform using @herdctl/chat infrastructure.
5
+ * Each web session maps to a unique conversation thread with an agent.
6
+ */
7
+ import { randomUUID } from "node:crypto";
8
+ import { mkdir, readFile, writeFile, unlink } from "node:fs/promises";
9
+ import { join, dirname } from "node:path";
10
+ import { createLogger, } from "@herdctl/core";
11
+ import { ChatSessionManager, extractMessageContent, } from "@herdctl/chat";
12
+ const logger = createLogger("web:chat");
13
+ // =============================================================================
14
+ // WebChatManager Implementation
15
+ // =============================================================================
16
+ /**
17
+ * WebChatManager manages chat sessions for the web platform
18
+ *
19
+ * Uses ChatSessionManager from @herdctl/chat for per-agent session management.
20
+ * Message history is stored in JSON files at `.herdctl/web/chat-history/<agent>/<session>.json`
21
+ */
22
+ export class WebChatManager {
23
+ fleetManager = null;
24
+ stateDir = null;
25
+ sessionExpiryHours = 24;
26
+ initialized = false;
27
+ /** Per-agent session managers */
28
+ sessionManagers = new Map();
29
+ /** In-memory session metadata cache (agentName -> sessionId -> metadata) */
30
+ sessionMetadata = new Map();
31
+ /**
32
+ * Initialize the WebChatManager
33
+ *
34
+ * @param fleetManager - FleetManager instance for triggering jobs
35
+ * @param stateDir - State directory (e.g., ".herdctl")
36
+ * @param config - Web configuration from fleet config
37
+ */
38
+ async initialize(fleetManager, stateDir, config) {
39
+ if (this.initialized) {
40
+ return;
41
+ }
42
+ this.fleetManager = fleetManager;
43
+ this.stateDir = stateDir;
44
+ this.sessionExpiryHours = config.session_expiry_hours ?? 24;
45
+ // Get fleet config to find all agents
46
+ const fleetConfig = await fleetManager.getConfig();
47
+ if (!fleetConfig) {
48
+ logger.warn("No fleet config available, chat manager initialized without agents");
49
+ this.initialized = true;
50
+ return;
51
+ }
52
+ // Create session managers for each agent
53
+ for (const agent of fleetConfig.agents) {
54
+ await this.createSessionManagerForAgent(agent.name);
55
+ }
56
+ // Ensure chat history directories exist
57
+ await this.ensureChatHistoryDir();
58
+ this.initialized = true;
59
+ logger.info(`Web chat manager initialized with ${this.sessionManagers.size} agent(s)`);
60
+ }
61
+ /**
62
+ * Create a new chat session for an agent
63
+ *
64
+ * @param agentName - Name of the agent
65
+ * @returns Session info with sessionId and createdAt
66
+ */
67
+ async createSession(agentName) {
68
+ this.ensureInitialized();
69
+ // Ensure we have a session manager for this agent
70
+ let sessionManager = this.sessionManagers.get(agentName);
71
+ if (!sessionManager) {
72
+ sessionManager = await this.createSessionManagerForAgent(agentName);
73
+ }
74
+ // Generate a unique session UUID for the web session
75
+ const sessionId = randomUUID();
76
+ const now = new Date().toISOString();
77
+ // Create session metadata
78
+ const session = {
79
+ sessionId,
80
+ agentName,
81
+ createdAt: now,
82
+ lastMessageAt: now,
83
+ messageCount: 0,
84
+ };
85
+ // Store in metadata cache
86
+ let agentSessions = this.sessionMetadata.get(agentName);
87
+ if (!agentSessions) {
88
+ agentSessions = new Map();
89
+ this.sessionMetadata.set(agentName, agentSessions);
90
+ }
91
+ agentSessions.set(sessionId, session);
92
+ // Initialize empty message history file
93
+ await this.saveMessageHistory(agentName, sessionId, []);
94
+ // Register in ChatSessionManager using sessionId as the channelId
95
+ // (For web, each session is its own "channel")
96
+ await sessionManager.setSession(sessionId, sessionId);
97
+ logger.info(`Created web chat session`, { agentName, sessionId });
98
+ return session;
99
+ }
100
+ /**
101
+ * List all sessions for an agent
102
+ *
103
+ * @param agentName - Name of the agent
104
+ * @returns Array of session summaries
105
+ */
106
+ async listSessions(agentName) {
107
+ this.ensureInitialized();
108
+ // Load sessions from disk if not in cache
109
+ await this.loadSessionsFromDisk(agentName);
110
+ const agentSessions = this.sessionMetadata.get(agentName);
111
+ if (!agentSessions) {
112
+ return [];
113
+ }
114
+ // Return sessions sorted by lastMessageAt (most recent first)
115
+ const sessions = Array.from(agentSessions.values());
116
+ sessions.sort((a, b) => new Date(b.lastMessageAt).getTime() - new Date(a.lastMessageAt).getTime());
117
+ return sessions;
118
+ }
119
+ /**
120
+ * Get session details with message history
121
+ *
122
+ * @param agentName - Name of the agent
123
+ * @param sessionId - Session ID
124
+ * @returns Session details with messages, or null if not found
125
+ */
126
+ async getSession(agentName, sessionId) {
127
+ this.ensureInitialized();
128
+ // Load sessions from disk if not in cache
129
+ await this.loadSessionsFromDisk(agentName);
130
+ const agentSessions = this.sessionMetadata.get(agentName);
131
+ const session = agentSessions?.get(sessionId);
132
+ if (!session) {
133
+ return null;
134
+ }
135
+ // Load message history
136
+ const messages = await this.loadMessageHistory(agentName, sessionId);
137
+ return {
138
+ ...session,
139
+ messages,
140
+ };
141
+ }
142
+ /**
143
+ * Delete a session
144
+ *
145
+ * @param agentName - Name of the agent
146
+ * @param sessionId - Session ID
147
+ * @returns true if deleted, false if not found
148
+ */
149
+ async deleteSession(agentName, sessionId) {
150
+ this.ensureInitialized();
151
+ const agentSessions = this.sessionMetadata.get(agentName);
152
+ if (!agentSessions?.has(sessionId)) {
153
+ return false;
154
+ }
155
+ // Remove from metadata cache
156
+ agentSessions.delete(sessionId);
157
+ // Delete message history file
158
+ await this.deleteMessageHistory(agentName, sessionId);
159
+ // Clear from ChatSessionManager
160
+ const sessionManager = this.sessionManagers.get(agentName);
161
+ if (sessionManager) {
162
+ await sessionManager.clearSession(sessionId);
163
+ }
164
+ logger.info(`Deleted web chat session`, { agentName, sessionId });
165
+ return true;
166
+ }
167
+ /**
168
+ * Send a message and trigger agent execution
169
+ *
170
+ * @param agentName - Name of the agent
171
+ * @param sessionId - Session ID
172
+ * @param message - User message text
173
+ * @param onChunk - Callback for streaming response chunks
174
+ * @returns Result with jobId
175
+ */
176
+ async sendMessage(agentName, sessionId, message, onChunk) {
177
+ this.ensureInitialized();
178
+ if (!this.fleetManager) {
179
+ return {
180
+ jobId: "",
181
+ success: false,
182
+ error: "Fleet manager not available",
183
+ };
184
+ }
185
+ // Load sessions from disk if not in cache
186
+ await this.loadSessionsFromDisk(agentName);
187
+ const agentSessions = this.sessionMetadata.get(agentName);
188
+ const session = agentSessions?.get(sessionId);
189
+ if (!session) {
190
+ return {
191
+ jobId: "",
192
+ success: false,
193
+ error: `Session not found: ${sessionId}`,
194
+ };
195
+ }
196
+ // Get existing SDK session ID for conversation continuity
197
+ const sessionManager = this.sessionManagers.get(agentName);
198
+ let existingSdkSessionId;
199
+ if (sessionManager) {
200
+ const existingSession = await sessionManager.getSession(sessionId);
201
+ if (existingSession && existingSession.sessionId !== sessionId) {
202
+ // The session manager stores the SDK session ID, not our web session ID
203
+ existingSdkSessionId = existingSession.sessionId;
204
+ logger.debug(`Resuming SDK session`, { agentName, sessionId, sdkSessionId: existingSdkSessionId });
205
+ }
206
+ }
207
+ // Load message history and add user message
208
+ const messages = await this.loadMessageHistory(agentName, sessionId);
209
+ const userMessage = {
210
+ role: "user",
211
+ content: message,
212
+ timestamp: new Date().toISOString(),
213
+ };
214
+ messages.push(userMessage);
215
+ await this.saveMessageHistory(agentName, sessionId, messages);
216
+ // Update session metadata
217
+ session.lastMessageAt = userMessage.timestamp;
218
+ session.messageCount = messages.length;
219
+ session.preview = message.substring(0, 100);
220
+ // Accumulate assistant response
221
+ let assistantContent = "";
222
+ try {
223
+ // Trigger job via FleetManager
224
+ const result = await this.fleetManager.trigger(agentName, undefined, {
225
+ triggerType: "web",
226
+ prompt: message,
227
+ resume: existingSdkSessionId,
228
+ onMessage: async (sdkMessage) => {
229
+ // Extract text content from assistant messages
230
+ if (sdkMessage.type === "assistant") {
231
+ const content = extractMessageContent(sdkMessage);
232
+ if (content) {
233
+ assistantContent += content;
234
+ // Send chunk to client
235
+ await onChunk(content);
236
+ }
237
+ }
238
+ },
239
+ });
240
+ // Store assistant message if we got any content
241
+ if (assistantContent) {
242
+ const assistantMessage = {
243
+ role: "assistant",
244
+ content: assistantContent,
245
+ timestamp: new Date().toISOString(),
246
+ };
247
+ messages.push(assistantMessage);
248
+ await this.saveMessageHistory(agentName, sessionId, messages);
249
+ // Update session metadata
250
+ session.lastMessageAt = assistantMessage.timestamp;
251
+ session.messageCount = messages.length;
252
+ session.preview = assistantContent.substring(0, 100);
253
+ }
254
+ // Store SDK session ID for future conversation continuity
255
+ if (sessionManager && result.sessionId && result.success) {
256
+ await sessionManager.setSession(sessionId, result.sessionId);
257
+ logger.debug(`Stored SDK session`, { agentName, sessionId, sdkSessionId: result.sessionId });
258
+ }
259
+ return {
260
+ jobId: result.jobId,
261
+ success: result.success,
262
+ error: result.error?.message,
263
+ };
264
+ }
265
+ catch (error) {
266
+ const errorMessage = error instanceof Error ? error.message : String(error);
267
+ logger.error(`Failed to send message`, { agentName, sessionId, error: errorMessage });
268
+ return {
269
+ jobId: "",
270
+ success: false,
271
+ error: errorMessage,
272
+ };
273
+ }
274
+ }
275
+ // ===========================================================================
276
+ // Private Helpers
277
+ // ===========================================================================
278
+ /**
279
+ * Ensure the manager is initialized
280
+ */
281
+ ensureInitialized() {
282
+ if (!this.initialized) {
283
+ throw new Error("WebChatManager not initialized. Call initialize() first.");
284
+ }
285
+ }
286
+ /**
287
+ * Create a session manager for an agent
288
+ */
289
+ async createSessionManagerForAgent(agentName) {
290
+ const chatLogger = {
291
+ debug: (msg, data) => logger.debug(`[${agentName}] ${msg}${data ? ` ${JSON.stringify(data)}` : ""}`),
292
+ info: (msg, data) => logger.info(`[${agentName}] ${msg}${data ? ` ${JSON.stringify(data)}` : ""}`),
293
+ warn: (msg, data) => logger.warn(`[${agentName}] ${msg}${data ? ` ${JSON.stringify(data)}` : ""}`),
294
+ error: (msg, data) => logger.error(`[${agentName}] ${msg}${data ? ` ${JSON.stringify(data)}` : ""}`),
295
+ };
296
+ const sessionManager = new ChatSessionManager({
297
+ platform: "web",
298
+ agentName,
299
+ stateDir: this.stateDir,
300
+ sessionExpiryHours: this.sessionExpiryHours,
301
+ logger: chatLogger,
302
+ });
303
+ this.sessionManagers.set(agentName, sessionManager);
304
+ logger.debug(`Created session manager for agent`, { agentName });
305
+ return sessionManager;
306
+ }
307
+ /**
308
+ * Get the chat history directory path
309
+ */
310
+ getChatHistoryDir(agentName) {
311
+ return join(this.stateDir, "web", "chat-history", agentName);
312
+ }
313
+ /**
314
+ * Get the message history file path for a session
315
+ */
316
+ getMessageHistoryPath(agentName, sessionId) {
317
+ return join(this.getChatHistoryDir(agentName), `${sessionId}.json`);
318
+ }
319
+ /**
320
+ * Ensure chat history directories exist
321
+ */
322
+ async ensureChatHistoryDir() {
323
+ const baseDir = join(this.stateDir, "web", "chat-history");
324
+ await mkdir(baseDir, { recursive: true });
325
+ }
326
+ /**
327
+ * Load message history from disk
328
+ */
329
+ async loadMessageHistory(agentName, sessionId) {
330
+ const filePath = this.getMessageHistoryPath(agentName, sessionId);
331
+ try {
332
+ const content = await readFile(filePath, "utf-8");
333
+ const data = JSON.parse(content);
334
+ return data.messages ?? [];
335
+ }
336
+ catch (error) {
337
+ const code = error.code;
338
+ if (code === "ENOENT") {
339
+ return [];
340
+ }
341
+ logger.warn(`Failed to load message history`, {
342
+ agentName,
343
+ sessionId,
344
+ error: error.message,
345
+ });
346
+ return [];
347
+ }
348
+ }
349
+ /**
350
+ * Save message history to disk
351
+ */
352
+ async saveMessageHistory(agentName, sessionId, messages) {
353
+ const filePath = this.getMessageHistoryPath(agentName, sessionId);
354
+ const dir = dirname(filePath);
355
+ await mkdir(dir, { recursive: true });
356
+ const data = {
357
+ sessionId,
358
+ agentName,
359
+ messages,
360
+ updatedAt: new Date().toISOString(),
361
+ };
362
+ await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
363
+ }
364
+ /**
365
+ * Delete message history file
366
+ */
367
+ async deleteMessageHistory(agentName, sessionId) {
368
+ const filePath = this.getMessageHistoryPath(agentName, sessionId);
369
+ try {
370
+ await unlink(filePath);
371
+ }
372
+ catch (error) {
373
+ const code = error.code;
374
+ if (code !== "ENOENT") {
375
+ logger.warn(`Failed to delete message history`, {
376
+ agentName,
377
+ sessionId,
378
+ error: error.message,
379
+ });
380
+ }
381
+ }
382
+ }
383
+ /**
384
+ * Load sessions from disk into metadata cache
385
+ */
386
+ async loadSessionsFromDisk(agentName) {
387
+ // Skip if already loaded
388
+ if (this.sessionMetadata.has(agentName)) {
389
+ return;
390
+ }
391
+ const dir = this.getChatHistoryDir(agentName);
392
+ const agentSessions = new Map();
393
+ try {
394
+ const { readdir } = await import("node:fs/promises");
395
+ const files = await readdir(dir);
396
+ for (const file of files) {
397
+ if (!file.endsWith(".json"))
398
+ continue;
399
+ const sessionId = file.slice(0, -5); // Remove .json
400
+ const filePath = join(dir, file);
401
+ try {
402
+ const content = await readFile(filePath, "utf-8");
403
+ const data = JSON.parse(content);
404
+ const messages = data.messages ?? [];
405
+ const lastMessage = messages[messages.length - 1];
406
+ const firstMessage = messages[0];
407
+ agentSessions.set(sessionId, {
408
+ sessionId,
409
+ agentName,
410
+ createdAt: firstMessage?.timestamp ?? data.updatedAt,
411
+ lastMessageAt: lastMessage?.timestamp ?? data.updatedAt,
412
+ messageCount: messages.length,
413
+ preview: lastMessage?.content?.substring(0, 100),
414
+ });
415
+ }
416
+ catch (error) {
417
+ logger.warn(`Failed to load session file`, {
418
+ agentName,
419
+ sessionId,
420
+ error: error.message,
421
+ });
422
+ }
423
+ }
424
+ }
425
+ catch (error) {
426
+ const code = error.code;
427
+ if (code !== "ENOENT") {
428
+ logger.warn(`Failed to read chat history directory`, {
429
+ agentName,
430
+ error: error.message,
431
+ });
432
+ }
433
+ }
434
+ this.sessionMetadata.set(agentName, agentSessions);
435
+ }
436
+ }
437
+ //# sourceMappingURL=web-chat-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-chat-manager.js","sourceRoot":"","sources":["../../../src/server/chat/web-chat-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
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 { type FastifyInstance } from "fastify";
8
+ import { type FleetManager, type FleetManagerContext, type IChatManager, type ChatManagerConnectorState } from "@herdctl/core";
9
+ import { WebSocketHandler, FleetBridge } from "./ws/index.js";
10
+ import { WebChatManager } from "./chat/index.js";
11
+ /**
12
+ * Configuration for the web server
13
+ */
14
+ export interface WebServerConfig {
15
+ /** Port to listen on */
16
+ port: number;
17
+ /** Host to bind to */
18
+ host: string;
19
+ }
20
+ /**
21
+ * Result of createWebServer containing server and related components
22
+ */
23
+ export interface WebServerResult {
24
+ /** The Fastify server instance */
25
+ server: FastifyInstance;
26
+ /** WebSocket handler for managing client connections */
27
+ wsHandler: WebSocketHandler;
28
+ /** Fleet bridge for event broadcasting */
29
+ fleetBridge: FleetBridge;
30
+ /** Web chat manager for handling chat sessions */
31
+ chatManager: WebChatManager;
32
+ }
33
+ /**
34
+ * Configuration for the web server (extended with state directory)
35
+ */
36
+ export interface WebServerConfigExtended extends WebServerConfig {
37
+ /** State directory for persistence (e.g., ".herdctl") */
38
+ stateDir?: string;
39
+ /** Session expiry in hours for chat sessions */
40
+ sessionExpiryHours?: number;
41
+ }
42
+ /**
43
+ * Creates a Fastify web server instance with WebSocket support
44
+ *
45
+ * The server is returned but NOT started - the caller controls the lifecycle.
46
+ * The returned FleetBridge should be started after the server starts listening,
47
+ * and stopped before the server closes.
48
+ *
49
+ * @param fleetManager - FleetManager instance for API calls and event subscription
50
+ * @param config - Server configuration
51
+ * @returns WebServerResult containing server, wsHandler, fleetBridge, and chatManager
52
+ */
53
+ export declare function createWebServer(fleetManager: FleetManager, config: WebServerConfigExtended): Promise<WebServerResult>;
54
+ /**
55
+ * State object for WebManager
56
+ */
57
+ export interface WebManagerState {
58
+ /** Whether the manager has been initialized */
59
+ initialized: boolean;
60
+ /** Whether the server is currently running */
61
+ running: boolean;
62
+ /** Host the server is bound to */
63
+ host: string | null;
64
+ /** Port the server is listening on */
65
+ port: number | null;
66
+ /** Number of connected WebSocket clients */
67
+ connectedClients: number;
68
+ /** ISO timestamp when the server started */
69
+ startedAt: string | null;
70
+ }
71
+ /**
72
+ * WebManager manages the web dashboard server lifecycle
73
+ *
74
+ * Implements IChatManager interface for integration with FleetManager.
75
+ * Unlike Discord/Slack managers which have per-agent connectors,
76
+ * WebManager provides a single dashboard that serves all agents.
77
+ */
78
+ export declare class WebManager implements IChatManager {
79
+ private ctx;
80
+ private server;
81
+ private wsHandler;
82
+ private fleetBridge;
83
+ private initialized;
84
+ private connectorState;
85
+ constructor(ctx: FleetManagerContext);
86
+ /**
87
+ * Initialize the web manager
88
+ *
89
+ * Creates the Fastify server with WebSocket support and REST API routes.
90
+ * Does not start listening - that happens in start().
91
+ */
92
+ initialize(): Promise<void>;
93
+ /**
94
+ * Start the web server
95
+ *
96
+ * Starts listening on the configured host:port and begins
97
+ * broadcasting FleetManager events to WebSocket clients.
98
+ */
99
+ start(): Promise<void>;
100
+ /**
101
+ * Stop the web server
102
+ *
103
+ * Gracefully shuts down the Fastify server and stops event broadcasting.
104
+ */
105
+ stop(): Promise<void>;
106
+ /**
107
+ * Check if the manager is initialized
108
+ */
109
+ isInitialized(): boolean;
110
+ /**
111
+ * Get the connector names managed by this manager
112
+ *
113
+ * Unlike Discord/Slack which have per-agent connectors,
114
+ * the web dashboard returns ["web"] to indicate it manages
115
+ * the single web interface.
116
+ */
117
+ getConnectorNames(): string[];
118
+ /**
119
+ * Get the count of connected WebSocket clients
120
+ */
121
+ getConnectedCount(): number;
122
+ /**
123
+ * Check if a specific agent is accessible via the web dashboard
124
+ *
125
+ * All agents are accessible via the web dashboard, so this always returns true.
126
+ */
127
+ hasAgent(_agentName: string): boolean;
128
+ /**
129
+ * Get the connector state for a specific agent
130
+ *
131
+ * Since the web dashboard doesn't have per-agent connectors,
132
+ * this returns the overall web server state for any agent.
133
+ */
134
+ getState(_agentName: string): ChatManagerConnectorState | undefined;
135
+ /**
136
+ * Get the internal web manager state
137
+ *
138
+ * This provides additional state information beyond the IChatManager interface.
139
+ */
140
+ getWebState(): WebManagerState;
141
+ }
142
+ export { WebSocketHandler, FleetBridge, type WebSocketClient, type ClientMessage, type ServerMessage, type SubscribeMessage, type UnsubscribeMessage, type PingMessage, type FleetStatusMessage, type AgentUpdatedMessage, type JobCreatedMessage, type JobOutputMessage, type JobCompletedMessage, type JobFailedMessage, type JobCancelledMessage, type ScheduleTriggeredMessage, type PongMessage, type ChatSendMessage, type ChatResponseMessage, type ChatCompleteMessage, type ChatErrorMessage, isClientMessage, isChatSendMessage, isAgentStartedPayload, isAgentStoppedPayload, } from "./ws/index.js";
143
+ export { WebChatManager, type WebChatSession, type WebChatSessionDetails, type ChatMessage, type SendMessageResult, type OnChunkCallback, } from "./chat/index.js";
144
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}