@herdctl/core 0.2.0 → 1.0.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.
Files changed (30) hide show
  1. package/dist/fleet-manager/__tests__/discord-manager.test.d.ts +8 -0
  2. package/dist/fleet-manager/__tests__/discord-manager.test.d.ts.map +1 -0
  3. package/dist/fleet-manager/__tests__/discord-manager.test.js +2168 -0
  4. package/dist/fleet-manager/__tests__/discord-manager.test.js.map +1 -0
  5. package/dist/fleet-manager/context.d.ts +4 -0
  6. package/dist/fleet-manager/context.d.ts.map +1 -1
  7. package/dist/fleet-manager/discord-manager.d.ts +280 -0
  8. package/dist/fleet-manager/discord-manager.d.ts.map +1 -0
  9. package/dist/fleet-manager/discord-manager.js +583 -0
  10. package/dist/fleet-manager/discord-manager.js.map +1 -0
  11. package/dist/fleet-manager/event-types.d.ts +45 -0
  12. package/dist/fleet-manager/event-types.d.ts.map +1 -1
  13. package/dist/fleet-manager/fleet-manager.d.ts +3 -0
  14. package/dist/fleet-manager/fleet-manager.d.ts.map +1 -1
  15. package/dist/fleet-manager/fleet-manager.js +10 -0
  16. package/dist/fleet-manager/fleet-manager.js.map +1 -1
  17. package/dist/fleet-manager/index.d.ts +3 -1
  18. package/dist/fleet-manager/index.d.ts.map +1 -1
  19. package/dist/fleet-manager/index.js +1 -0
  20. package/dist/fleet-manager/index.js.map +1 -1
  21. package/dist/fleet-manager/job-control.d.ts.map +1 -1
  22. package/dist/fleet-manager/job-control.js +3 -0
  23. package/dist/fleet-manager/job-control.js.map +1 -1
  24. package/dist/fleet-manager/status-queries.d.ts +5 -1
  25. package/dist/fleet-manager/status-queries.d.ts.map +1 -1
  26. package/dist/fleet-manager/status-queries.js +42 -3
  27. package/dist/fleet-manager/status-queries.js.map +1 -1
  28. package/dist/fleet-manager/types.d.ts +48 -1
  29. package/dist/fleet-manager/types.d.ts.map +1 -1
  30. package/package.json +9 -1
@@ -0,0 +1,583 @@
1
+ /**
2
+ * Discord Manager Module
3
+ *
4
+ * Manages Discord connectors for agents that have `chat.discord` configured.
5
+ * This module is responsible for:
6
+ * - Creating one DiscordConnector instance per Discord-enabled agent
7
+ * - Managing connector lifecycle (start/stop)
8
+ * - Providing access to connectors for status queries
9
+ *
10
+ * Note: This module dynamically imports @herdctl/discord at runtime to avoid
11
+ * a hard dependency. The @herdctl/core package can be used without Discord support.
12
+ *
13
+ * @module discord-manager
14
+ */
15
+ /**
16
+ * Lazy import the Discord package to avoid hard dependency
17
+ * This allows @herdctl/core to be used without @herdctl/discord installed
18
+ */
19
+ async function importDiscordPackage() {
20
+ try {
21
+ // Dynamic import - will be resolved at runtime
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ const pkg = (await import("@herdctl/discord"));
24
+ return pkg;
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ /**
31
+ * DiscordManager handles Discord connections for agents
32
+ *
33
+ * This class encapsulates the creation and lifecycle management of
34
+ * DiscordConnector instances for agents that have Discord chat configured.
35
+ */
36
+ export class DiscordManager {
37
+ ctx;
38
+ connectors = new Map();
39
+ initialized = false;
40
+ constructor(ctx) {
41
+ this.ctx = ctx;
42
+ }
43
+ /**
44
+ * Initialize Discord connectors for all configured agents
45
+ *
46
+ * This method:
47
+ * 1. Checks if @herdctl/discord package is available
48
+ * 2. Iterates through agents to find those with Discord configured
49
+ * 3. Creates a DiscordConnector for each Discord-enabled agent
50
+ *
51
+ * Should be called during FleetManager initialization.
52
+ */
53
+ async initialize() {
54
+ if (this.initialized) {
55
+ return;
56
+ }
57
+ const logger = this.ctx.getLogger();
58
+ const config = this.ctx.getConfig();
59
+ if (!config) {
60
+ logger.debug("No config available, skipping Discord initialization");
61
+ return;
62
+ }
63
+ // Try to import the discord package
64
+ const discordPkg = await importDiscordPackage();
65
+ if (!discordPkg) {
66
+ logger.debug("@herdctl/discord not installed, skipping Discord connectors");
67
+ return;
68
+ }
69
+ const { DiscordConnector, SessionManager } = discordPkg;
70
+ const stateDir = this.ctx.getStateDir();
71
+ // Find agents with Discord configured
72
+ const discordAgents = config.agents.filter((agent) => agent.chat?.discord !== undefined);
73
+ if (discordAgents.length === 0) {
74
+ logger.debug("No agents with Discord configured");
75
+ this.initialized = true;
76
+ return;
77
+ }
78
+ logger.info(`Initializing Discord connectors for ${discordAgents.length} agent(s)`);
79
+ for (const agent of discordAgents) {
80
+ try {
81
+ const discordConfig = agent.chat.discord;
82
+ if (!discordConfig)
83
+ continue;
84
+ // Get bot token from environment variable
85
+ const botToken = process.env[discordConfig.bot_token_env];
86
+ if (!botToken) {
87
+ logger.warn(`Discord bot token not found in environment variable '${discordConfig.bot_token_env}' for agent '${agent.name}'`);
88
+ continue;
89
+ }
90
+ // Create logger adapter for this agent
91
+ const createAgentLogger = (prefix) => ({
92
+ debug: (msg, data) => logger.debug(`${prefix} ${msg}${data ? ` ${JSON.stringify(data)}` : ""}`),
93
+ info: (msg, data) => logger.info(`${prefix} ${msg}${data ? ` ${JSON.stringify(data)}` : ""}`),
94
+ warn: (msg, data) => logger.warn(`${prefix} ${msg}${data ? ` ${JSON.stringify(data)}` : ""}`),
95
+ error: (msg, data) => logger.error(`${prefix} ${msg}${data ? ` ${JSON.stringify(data)}` : ""}`),
96
+ });
97
+ // Create session manager for this agent
98
+ const sessionManager = new SessionManager({
99
+ agentName: agent.name,
100
+ stateDir,
101
+ sessionExpiryHours: discordConfig.session_expiry_hours,
102
+ logger: createAgentLogger(`[discord:${agent.name}:session]`),
103
+ });
104
+ // Create the connector
105
+ // Note: FleetManager is passed via ctx.getEmitter() which returns the FleetManager instance
106
+ const connector = new DiscordConnector({
107
+ agentConfig: agent,
108
+ discordConfig,
109
+ botToken,
110
+ // The context's getEmitter() returns the FleetManager instance (which extends EventEmitter)
111
+ fleetManager: this.ctx.getEmitter(),
112
+ sessionManager,
113
+ stateDir,
114
+ logger: createAgentLogger(`[discord:${agent.name}]`),
115
+ });
116
+ this.connectors.set(agent.name, connector);
117
+ logger.debug(`Created Discord connector for agent '${agent.name}'`);
118
+ }
119
+ catch (error) {
120
+ const errorMessage = error instanceof Error ? error.message : String(error);
121
+ logger.error(`Failed to create Discord connector for agent '${agent.name}': ${errorMessage}`);
122
+ // Continue with other agents - don't fail the whole initialization
123
+ }
124
+ }
125
+ this.initialized = true;
126
+ logger.info(`Discord manager initialized with ${this.connectors.size} connector(s)`);
127
+ }
128
+ /**
129
+ * Connect all Discord connectors
130
+ *
131
+ * Connects each connector to the Discord gateway and subscribes to events.
132
+ * Errors are logged but don't stop other connectors from connecting.
133
+ */
134
+ async start() {
135
+ const logger = this.ctx.getLogger();
136
+ if (this.connectors.size === 0) {
137
+ logger.debug("No Discord connectors to start");
138
+ return;
139
+ }
140
+ logger.info(`Starting ${this.connectors.size} Discord connector(s)...`);
141
+ const connectPromises = [];
142
+ for (const [agentName, connector] of this.connectors) {
143
+ // Subscribe to connector events before connecting
144
+ connector.on("message", (event) => {
145
+ this.handleMessage(agentName, event).catch((error) => {
146
+ this.handleError(agentName, error);
147
+ });
148
+ });
149
+ connector.on("error", (event) => {
150
+ this.handleError(agentName, event.error);
151
+ });
152
+ connectPromises.push(connector.connect().catch((error) => {
153
+ const errorMessage = error instanceof Error ? error.message : String(error);
154
+ logger.error(`Failed to connect Discord for agent '${agentName}': ${errorMessage}`);
155
+ // Don't re-throw - we want to continue connecting other agents
156
+ }));
157
+ }
158
+ await Promise.all(connectPromises);
159
+ const connectedCount = Array.from(this.connectors.values()).filter((c) => c.isConnected()).length;
160
+ logger.info(`Discord connectors started: ${connectedCount}/${this.connectors.size} connected`);
161
+ }
162
+ /**
163
+ * Disconnect all Discord connectors gracefully
164
+ *
165
+ * Sessions are automatically persisted to disk on every update,
166
+ * so they survive bot restarts. This method logs session state
167
+ * before disconnecting for monitoring purposes.
168
+ *
169
+ * Errors are logged but don't prevent other connectors from disconnecting.
170
+ */
171
+ async stop() {
172
+ const logger = this.ctx.getLogger();
173
+ if (this.connectors.size === 0) {
174
+ logger.debug("No Discord connectors to stop");
175
+ return;
176
+ }
177
+ logger.info(`Stopping ${this.connectors.size} Discord connector(s)...`);
178
+ // Log session state before shutdown (sessions are already persisted to disk)
179
+ for (const [agentName, connector] of this.connectors) {
180
+ try {
181
+ const activeSessionCount = await connector.sessionManager.getActiveSessionCount();
182
+ if (activeSessionCount > 0) {
183
+ logger.info(`Preserving ${activeSessionCount} active session(s) for agent '${agentName}'`);
184
+ }
185
+ }
186
+ catch (error) {
187
+ const errorMessage = error instanceof Error ? error.message : String(error);
188
+ logger.warn(`Failed to get session count for agent '${agentName}': ${errorMessage}`);
189
+ // Continue with shutdown - this is just informational logging
190
+ }
191
+ }
192
+ const disconnectPromises = [];
193
+ for (const [agentName, connector] of this.connectors) {
194
+ disconnectPromises.push(connector.disconnect().catch((error) => {
195
+ const errorMessage = error instanceof Error ? error.message : String(error);
196
+ logger.error(`Error disconnecting Discord for agent '${agentName}': ${errorMessage}`);
197
+ // Don't re-throw - graceful shutdown should continue
198
+ }));
199
+ }
200
+ await Promise.all(disconnectPromises);
201
+ logger.info("All Discord connectors stopped");
202
+ }
203
+ /**
204
+ * Get a connector for a specific agent
205
+ *
206
+ * @param agentName - Name of the agent
207
+ * @returns The DiscordConnector instance, or undefined if not found
208
+ */
209
+ getConnector(agentName) {
210
+ return this.connectors.get(agentName);
211
+ }
212
+ /**
213
+ * Get all connector names
214
+ *
215
+ * @returns Array of agent names that have Discord connectors
216
+ */
217
+ getConnectorNames() {
218
+ return Array.from(this.connectors.keys());
219
+ }
220
+ /**
221
+ * Get the number of active connectors
222
+ *
223
+ * @returns Number of connectors that are currently connected
224
+ */
225
+ getConnectedCount() {
226
+ return Array.from(this.connectors.values()).filter((c) => c.isConnected()).length;
227
+ }
228
+ /**
229
+ * Check if a specific agent has a Discord connector
230
+ *
231
+ * @param agentName - Name of the agent
232
+ * @returns true if the agent has a Discord connector
233
+ */
234
+ hasConnector(agentName) {
235
+ return this.connectors.has(agentName);
236
+ }
237
+ // ===========================================================================
238
+ // Message Handling Pipeline
239
+ // ===========================================================================
240
+ /**
241
+ * Handle an incoming Discord message
242
+ *
243
+ * This method:
244
+ * 1. Gets or creates a session for the channel
245
+ * 2. Builds job context from the message
246
+ * 3. Executes the job via trigger
247
+ * 4. Sends the response back to Discord
248
+ *
249
+ * @param agentName - Name of the agent handling the message
250
+ * @param event - The Discord message event
251
+ */
252
+ async handleMessage(agentName, event) {
253
+ const logger = this.ctx.getLogger();
254
+ const emitter = this.ctx.getEmitter();
255
+ logger.info(`Discord message for agent '${agentName}': ${event.prompt.substring(0, 50)}...`);
256
+ // Get the agent configuration
257
+ const config = this.ctx.getConfig();
258
+ const agent = config?.agents.find((a) => a.name === agentName);
259
+ if (!agent) {
260
+ logger.error(`Agent '${agentName}' not found in configuration`);
261
+ try {
262
+ await event.reply("Sorry, I'm not properly configured. Please contact an administrator.");
263
+ }
264
+ catch (replyError) {
265
+ logger.error(`Failed to send error reply: ${replyError.message}`);
266
+ }
267
+ return;
268
+ }
269
+ // Get existing session for this channel (for conversation continuity)
270
+ const connector = this.connectors.get(agentName);
271
+ let existingSessionId;
272
+ if (connector) {
273
+ try {
274
+ const existingSession = await connector.sessionManager.getSession(event.metadata.channelId);
275
+ if (existingSession) {
276
+ existingSessionId = existingSession.sessionId;
277
+ logger.debug(`Resuming session for channel ${event.metadata.channelId}: ${existingSessionId}`);
278
+ }
279
+ else {
280
+ logger.debug(`No existing session for channel ${event.metadata.channelId}, starting new conversation`);
281
+ }
282
+ }
283
+ catch (error) {
284
+ const errorMessage = error instanceof Error ? error.message : String(error);
285
+ logger.warn(`Failed to get session: ${errorMessage}`);
286
+ // Continue processing - session failure shouldn't block message handling
287
+ }
288
+ }
289
+ // Collect all response chunks as the job executes
290
+ const responseChunks = [];
291
+ // Start typing indicator while processing
292
+ const stopTyping = event.startTyping();
293
+ try {
294
+ // Import FleetManager dynamically to avoid circular dependency
295
+ // The context's getEmitter() returns the FleetManager instance
296
+ const fleetManager = emitter;
297
+ // Execute job via FleetManager.trigger()
298
+ // Pass resume option for conversation continuity
299
+ // The onMessage callback collects streaming output
300
+ const result = await fleetManager.trigger(agentName, undefined, {
301
+ prompt: event.prompt,
302
+ resume: existingSessionId,
303
+ onMessage: (message) => {
304
+ // Extract text content from assistant messages
305
+ if (message.type === "assistant") {
306
+ const content = this.extractMessageContent(message);
307
+ if (content) {
308
+ responseChunks.push(content);
309
+ }
310
+ }
311
+ },
312
+ });
313
+ logger.info(`Discord job completed: ${result.jobId} for agent '${agentName}'${result.sessionId ? ` (session: ${result.sessionId})` : ""}`);
314
+ // Combine all response chunks
315
+ const fullResponse = responseChunks.join("");
316
+ // Send response to Discord channel (handles splitting if needed)
317
+ if (fullResponse) {
318
+ await this.sendResponse(event.reply, fullResponse);
319
+ }
320
+ else {
321
+ await event.reply("I've completed the task, but I don't have a specific response to share.");
322
+ }
323
+ // Store the SDK session ID for future conversation continuity
324
+ // Only store if the job succeeded - failed jobs may return invalid session IDs
325
+ if (connector && result.sessionId && result.success) {
326
+ try {
327
+ await connector.sessionManager.setSession(event.metadata.channelId, result.sessionId);
328
+ logger.debug(`Stored session ${result.sessionId} for channel ${event.metadata.channelId}`);
329
+ }
330
+ catch (sessionError) {
331
+ const errorMessage = sessionError instanceof Error ? sessionError.message : String(sessionError);
332
+ logger.warn(`Failed to store session: ${errorMessage}`);
333
+ // Don't fail the message handling for session storage failure
334
+ }
335
+ }
336
+ else if (connector && result.sessionId && !result.success) {
337
+ logger.debug(`Not storing session ${result.sessionId} for channel ${event.metadata.channelId} - job failed`);
338
+ }
339
+ // Emit event for tracking
340
+ emitter.emit("discord:message:handled", {
341
+ agentName,
342
+ channelId: event.metadata.channelId,
343
+ messageId: event.metadata.messageId,
344
+ jobId: result.jobId,
345
+ timestamp: new Date().toISOString(),
346
+ });
347
+ }
348
+ catch (error) {
349
+ const err = error instanceof Error ? error : new Error(String(error));
350
+ logger.error(`Discord message handling failed for agent '${agentName}': ${err.message}`);
351
+ // Send user-friendly error message using the formatted error method
352
+ try {
353
+ await event.reply(this.formatErrorMessage(err));
354
+ }
355
+ catch (replyError) {
356
+ logger.error(`Failed to send error reply: ${replyError.message}`);
357
+ }
358
+ // Emit error event for tracking
359
+ emitter.emit("discord:message:error", {
360
+ agentName,
361
+ channelId: event.metadata.channelId,
362
+ messageId: event.metadata.messageId,
363
+ error: err.message,
364
+ timestamp: new Date().toISOString(),
365
+ });
366
+ }
367
+ finally {
368
+ // Always stop typing indicator when done
369
+ stopTyping();
370
+ }
371
+ }
372
+ /**
373
+ * Extract text content from an SDK message
374
+ *
375
+ * Handles various message formats from the Claude Agent SDK
376
+ */
377
+ extractMessageContent(message) {
378
+ // Check for direct content
379
+ if (typeof message.content === "string" && message.content) {
380
+ return message.content;
381
+ }
382
+ // Check for nested message content (SDK structure)
383
+ const apiMessage = message.message;
384
+ const content = apiMessage?.content;
385
+ if (!content)
386
+ return undefined;
387
+ // If it's a string, return directly
388
+ if (typeof content === "string") {
389
+ return content;
390
+ }
391
+ // If it's an array of content blocks, extract text
392
+ if (Array.isArray(content)) {
393
+ const textParts = [];
394
+ for (const block of content) {
395
+ if (block && typeof block === "object" && "type" in block) {
396
+ if (block.type === "text" && "text" in block && typeof block.text === "string") {
397
+ textParts.push(block.text);
398
+ }
399
+ }
400
+ }
401
+ return textParts.length > 0 ? textParts.join("") : undefined;
402
+ }
403
+ return undefined;
404
+ }
405
+ /**
406
+ * Handle errors from Discord connectors
407
+ *
408
+ * Logs errors without crashing the connector
409
+ *
410
+ * @param agentName - Name of the agent that encountered the error
411
+ * @param error - The error that occurred
412
+ */
413
+ handleError(agentName, error) {
414
+ const logger = this.ctx.getLogger();
415
+ const emitter = this.ctx.getEmitter();
416
+ const errorMessage = error instanceof Error ? error.message : String(error);
417
+ logger.error(`Discord connector error for agent '${agentName}': ${errorMessage}`);
418
+ // Emit error event for monitoring
419
+ emitter.emit("discord:error", {
420
+ agentName,
421
+ error: errorMessage,
422
+ timestamp: new Date().toISOString(),
423
+ });
424
+ }
425
+ // ===========================================================================
426
+ // Response Formatting and Splitting
427
+ // ===========================================================================
428
+ /** Discord's maximum message length */
429
+ static MAX_MESSAGE_LENGTH = 2000;
430
+ /**
431
+ * Format an error message for Discord display
432
+ *
433
+ * Creates a user-friendly error message with guidance on how to proceed.
434
+ *
435
+ * @param error - The error that occurred
436
+ * @returns Formatted error message string
437
+ */
438
+ formatErrorMessage(error) {
439
+ return `❌ **Error**: ${error.message}\n\nPlease try again or use \`/reset\` to start a new session.`;
440
+ }
441
+ /**
442
+ * Split a response into chunks that fit Discord's 2000 character limit
443
+ *
444
+ * This method intelligently splits text:
445
+ * - Preserves code blocks when possible (closing and reopening across chunks)
446
+ * - Splits at natural boundaries (newlines, then spaces)
447
+ * - Never splits mid-word
448
+ *
449
+ * @param text - The text to split
450
+ * @returns Array of text chunks, each under 2000 characters
451
+ */
452
+ splitResponse(text) {
453
+ const MAX_LENGTH = DiscordManager.MAX_MESSAGE_LENGTH;
454
+ // If text fits in one message, return as-is
455
+ if (text.length <= MAX_LENGTH) {
456
+ return [text];
457
+ }
458
+ const chunks = [];
459
+ let remaining = text;
460
+ while (remaining.length > 0) {
461
+ if (remaining.length <= MAX_LENGTH) {
462
+ chunks.push(remaining);
463
+ break;
464
+ }
465
+ // Find the best split point
466
+ const { chunk, rest } = this.findSplitPoint(remaining, MAX_LENGTH);
467
+ chunks.push(chunk);
468
+ remaining = rest;
469
+ }
470
+ return chunks;
471
+ }
472
+ /**
473
+ * Find the best point to split text, preserving code blocks
474
+ *
475
+ * @param text - Text to split
476
+ * @param maxLength - Maximum chunk length
477
+ * @returns Object with the chunk and remaining text
478
+ */
479
+ findSplitPoint(text, maxLength) {
480
+ // Check if we're inside a code block at the split point
481
+ const codeBlockState = this.analyzeCodeBlocks(text.substring(0, maxLength));
482
+ // If inside a code block, we need to close it and reopen in the next chunk
483
+ if (codeBlockState.insideBlock) {
484
+ // Find a good split point before maxLength
485
+ const splitIndex = this.findNaturalBreak(text, maxLength);
486
+ const chunkText = text.substring(0, splitIndex);
487
+ // Re-analyze the actual chunk
488
+ const actualState = this.analyzeCodeBlocks(chunkText);
489
+ if (actualState.insideBlock) {
490
+ // Close the code block in this chunk
491
+ const closedChunk = chunkText + "\n```";
492
+ // Reopen with the same language in the next chunk
493
+ const continuation = "```" + (actualState.language || "") + "\n" + text.substring(splitIndex);
494
+ return { chunk: closedChunk, rest: continuation };
495
+ }
496
+ return {
497
+ chunk: chunkText,
498
+ rest: text.substring(splitIndex),
499
+ };
500
+ }
501
+ // Not inside a code block - find natural break point
502
+ const splitIndex = this.findNaturalBreak(text, maxLength);
503
+ return {
504
+ chunk: text.substring(0, splitIndex),
505
+ rest: text.substring(splitIndex),
506
+ };
507
+ }
508
+ /**
509
+ * Analyze text to determine if it ends inside a code block
510
+ *
511
+ * @param text - Text to analyze
512
+ * @returns Object indicating if inside a block and the language if so
513
+ */
514
+ analyzeCodeBlocks(text) {
515
+ // Find all code block markers (```)
516
+ const codeBlockRegex = /```(\w*)?/g;
517
+ let match;
518
+ let insideBlock = false;
519
+ let language = null;
520
+ while ((match = codeBlockRegex.exec(text)) !== null) {
521
+ if (insideBlock) {
522
+ // This closes a block
523
+ insideBlock = false;
524
+ language = null;
525
+ }
526
+ else {
527
+ // This opens a block
528
+ insideBlock = true;
529
+ language = match[1] || null;
530
+ }
531
+ }
532
+ return { insideBlock, language };
533
+ }
534
+ /**
535
+ * Find a natural break point in text (newline or space)
536
+ *
537
+ * Prefers breaking at:
538
+ * 1. Double newlines (paragraph breaks)
539
+ * 2. Single newlines
540
+ * 3. Spaces
541
+ *
542
+ * @param text - Text to search
543
+ * @param maxLength - Maximum position to search
544
+ * @returns Index of the best split point
545
+ */
546
+ findNaturalBreak(text, maxLength) {
547
+ // Don't search beyond the text length
548
+ const searchEnd = Math.min(maxLength, text.length);
549
+ // First, try to find a double newline (paragraph break)
550
+ const doubleNewline = text.lastIndexOf("\n\n", searchEnd);
551
+ if (doubleNewline > 0 && doubleNewline > searchEnd - 500) {
552
+ // Found a paragraph break within the last 500 chars
553
+ return doubleNewline + 2; // Include the newlines
554
+ }
555
+ // Try to find a single newline
556
+ const singleNewline = text.lastIndexOf("\n", searchEnd);
557
+ if (singleNewline > 0 && singleNewline > searchEnd - 200) {
558
+ // Found a newline within the last 200 chars
559
+ return singleNewline + 1; // Include the newline
560
+ }
561
+ // Try to find a space (avoid splitting mid-word)
562
+ const space = text.lastIndexOf(" ", searchEnd);
563
+ if (space > 0 && space > searchEnd - 100) {
564
+ // Found a space within the last 100 chars
565
+ return space + 1; // Include the space
566
+ }
567
+ // Last resort: hard cut at maxLength
568
+ return searchEnd;
569
+ }
570
+ /**
571
+ * Send a response to Discord, splitting if necessary
572
+ *
573
+ * @param reply - The reply function from the message event
574
+ * @param content - The content to send
575
+ */
576
+ async sendResponse(reply, content) {
577
+ const chunks = this.splitResponse(content);
578
+ for (const chunk of chunks) {
579
+ await reply(chunk);
580
+ }
581
+ }
582
+ }
583
+ //# sourceMappingURL=discord-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord-manager.js","sourceRoot":"","sources":["../../src/fleet-manager/discord-manager.ts"],"names":[],"mappings":"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"}
@@ -172,6 +172,39 @@ export interface JobForkedPayload {
172
172
  /** ISO timestamp when the job was forked */
173
173
  timestamp: string;
174
174
  }
175
+ /**
176
+ * Payload for discord:connector:connected event
177
+ */
178
+ export interface DiscordConnectorConnectedPayload {
179
+ /** Name of the agent whose Discord connector connected */
180
+ agentName: string;
181
+ /** Bot username */
182
+ botUsername: string;
183
+ /** ISO timestamp when the connector connected */
184
+ timestamp: string;
185
+ }
186
+ /**
187
+ * Payload for discord:connector:disconnected event
188
+ */
189
+ export interface DiscordConnectorDisconnectedPayload {
190
+ /** Name of the agent whose Discord connector disconnected */
191
+ agentName: string;
192
+ /** Reason for disconnection (if available) */
193
+ reason?: string;
194
+ /** ISO timestamp when the connector disconnected */
195
+ timestamp: string;
196
+ }
197
+ /**
198
+ * Payload for discord:connector:error event
199
+ */
200
+ export interface DiscordConnectorErrorPayload {
201
+ /** Name of the agent whose Discord connector had an error */
202
+ agentName: string;
203
+ /** Error message */
204
+ error: string;
205
+ /** ISO timestamp when the error occurred */
206
+ timestamp: string;
207
+ }
175
208
  /**
176
209
  * Strongly-typed event map for FleetManager
177
210
  *
@@ -266,6 +299,18 @@ export interface FleetManagerEventMap {
266
299
  * A new job is created based on an existing job's configuration.
267
300
  */
268
301
  "job:forked": [payload: JobForkedPayload];
302
+ /**
303
+ * Emitted when a Discord connector successfully connects.
304
+ */
305
+ "discord:connector:connected": [payload: DiscordConnectorConnectedPayload];
306
+ /**
307
+ * Emitted when a Discord connector disconnects.
308
+ */
309
+ "discord:connector:disconnected": [payload: DiscordConnectorDisconnectedPayload];
310
+ /**
311
+ * Emitted when a Discord connector encounters an error.
312
+ */
313
+ "discord:connector:error": [payload: DiscordConnectorErrorPayload];
269
314
  /**
270
315
  * Emitted when an error occurs in the FleetManager.
271
316
  * This is a catch-all for errors that aren't tied to a specific job.