@herdctl/discord 0.0.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 (137) hide show
  1. package/dist/__tests__/auto-mode-handler.test.d.ts +2 -0
  2. package/dist/__tests__/auto-mode-handler.test.d.ts.map +1 -0
  3. package/dist/__tests__/auto-mode-handler.test.js +362 -0
  4. package/dist/__tests__/auto-mode-handler.test.js.map +1 -0
  5. package/dist/__tests__/discord-connector.test.d.ts +2 -0
  6. package/dist/__tests__/discord-connector.test.d.ts.map +1 -0
  7. package/dist/__tests__/discord-connector.test.js +958 -0
  8. package/dist/__tests__/discord-connector.test.js.map +1 -0
  9. package/dist/__tests__/error-handler.test.d.ts +2 -0
  10. package/dist/__tests__/error-handler.test.d.ts.map +1 -0
  11. package/dist/__tests__/error-handler.test.js +509 -0
  12. package/dist/__tests__/error-handler.test.js.map +1 -0
  13. package/dist/__tests__/errors.test.d.ts +2 -0
  14. package/dist/__tests__/errors.test.d.ts.map +1 -0
  15. package/dist/__tests__/errors.test.js +152 -0
  16. package/dist/__tests__/errors.test.js.map +1 -0
  17. package/dist/__tests__/logger.test.d.ts +2 -0
  18. package/dist/__tests__/logger.test.d.ts.map +1 -0
  19. package/dist/__tests__/logger.test.js +282 -0
  20. package/dist/__tests__/logger.test.js.map +1 -0
  21. package/dist/__tests__/mention-handler.test.d.ts +2 -0
  22. package/dist/__tests__/mention-handler.test.d.ts.map +1 -0
  23. package/dist/__tests__/mention-handler.test.js +547 -0
  24. package/dist/__tests__/mention-handler.test.js.map +1 -0
  25. package/dist/auto-mode-handler.d.ts +145 -0
  26. package/dist/auto-mode-handler.d.ts.map +1 -0
  27. package/dist/auto-mode-handler.js +211 -0
  28. package/dist/auto-mode-handler.js.map +1 -0
  29. package/dist/commands/__tests__/command-manager.test.d.ts +2 -0
  30. package/dist/commands/__tests__/command-manager.test.d.ts.map +1 -0
  31. package/dist/commands/__tests__/command-manager.test.js +307 -0
  32. package/dist/commands/__tests__/command-manager.test.js.map +1 -0
  33. package/dist/commands/__tests__/help.test.d.ts +2 -0
  34. package/dist/commands/__tests__/help.test.d.ts.map +1 -0
  35. package/dist/commands/__tests__/help.test.js +105 -0
  36. package/dist/commands/__tests__/help.test.js.map +1 -0
  37. package/dist/commands/__tests__/reset.test.d.ts +2 -0
  38. package/dist/commands/__tests__/reset.test.d.ts.map +1 -0
  39. package/dist/commands/__tests__/reset.test.js +140 -0
  40. package/dist/commands/__tests__/reset.test.js.map +1 -0
  41. package/dist/commands/__tests__/status.test.d.ts +2 -0
  42. package/dist/commands/__tests__/status.test.d.ts.map +1 -0
  43. package/dist/commands/__tests__/status.test.js +205 -0
  44. package/dist/commands/__tests__/status.test.js.map +1 -0
  45. package/dist/commands/command-manager.d.ts +66 -0
  46. package/dist/commands/command-manager.d.ts.map +1 -0
  47. package/dist/commands/command-manager.js +191 -0
  48. package/dist/commands/command-manager.js.map +1 -0
  49. package/dist/commands/help.d.ts +8 -0
  50. package/dist/commands/help.d.ts.map +1 -0
  51. package/dist/commands/help.js +27 -0
  52. package/dist/commands/help.js.map +1 -0
  53. package/dist/commands/index.d.ts +12 -0
  54. package/dist/commands/index.d.ts.map +1 -0
  55. package/dist/commands/index.js +13 -0
  56. package/dist/commands/index.js.map +1 -0
  57. package/dist/commands/reset.d.ts +9 -0
  58. package/dist/commands/reset.d.ts.map +1 -0
  59. package/dist/commands/reset.js +28 -0
  60. package/dist/commands/reset.js.map +1 -0
  61. package/dist/commands/status.d.ts +9 -0
  62. package/dist/commands/status.d.ts.map +1 -0
  63. package/dist/commands/status.js +102 -0
  64. package/dist/commands/status.js.map +1 -0
  65. package/dist/commands/types.d.ts +87 -0
  66. package/dist/commands/types.d.ts.map +1 -0
  67. package/dist/commands/types.js +8 -0
  68. package/dist/commands/types.js.map +1 -0
  69. package/dist/discord-connector.d.ts +154 -0
  70. package/dist/discord-connector.d.ts.map +1 -0
  71. package/dist/discord-connector.js +638 -0
  72. package/dist/discord-connector.js.map +1 -0
  73. package/dist/error-handler.d.ts +237 -0
  74. package/dist/error-handler.d.ts.map +1 -0
  75. package/dist/error-handler.js +433 -0
  76. package/dist/error-handler.js.map +1 -0
  77. package/dist/errors.d.ts +61 -0
  78. package/dist/errors.d.ts.map +1 -0
  79. package/dist/errors.js +77 -0
  80. package/dist/errors.js.map +1 -0
  81. package/dist/index.d.ts +34 -0
  82. package/dist/index.d.ts.map +1 -0
  83. package/dist/index.js +36 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/logger.d.ts +119 -0
  86. package/dist/logger.d.ts.map +1 -0
  87. package/dist/logger.js +198 -0
  88. package/dist/logger.js.map +1 -0
  89. package/dist/mention-handler.d.ts +176 -0
  90. package/dist/mention-handler.d.ts.map +1 -0
  91. package/dist/mention-handler.js +236 -0
  92. package/dist/mention-handler.js.map +1 -0
  93. package/dist/session-manager/__tests__/errors.test.d.ts +2 -0
  94. package/dist/session-manager/__tests__/errors.test.d.ts.map +1 -0
  95. package/dist/session-manager/__tests__/errors.test.js +124 -0
  96. package/dist/session-manager/__tests__/errors.test.js.map +1 -0
  97. package/dist/session-manager/__tests__/session-manager.test.d.ts +2 -0
  98. package/dist/session-manager/__tests__/session-manager.test.d.ts.map +1 -0
  99. package/dist/session-manager/__tests__/session-manager.test.js +517 -0
  100. package/dist/session-manager/__tests__/session-manager.test.js.map +1 -0
  101. package/dist/session-manager/__tests__/types.test.d.ts +2 -0
  102. package/dist/session-manager/__tests__/types.test.d.ts.map +1 -0
  103. package/dist/session-manager/__tests__/types.test.js +169 -0
  104. package/dist/session-manager/__tests__/types.test.js.map +1 -0
  105. package/dist/session-manager/errors.d.ts +58 -0
  106. package/dist/session-manager/errors.d.ts.map +1 -0
  107. package/dist/session-manager/errors.js +70 -0
  108. package/dist/session-manager/errors.js.map +1 -0
  109. package/dist/session-manager/index.d.ts +11 -0
  110. package/dist/session-manager/index.d.ts.map +1 -0
  111. package/dist/session-manager/index.js +12 -0
  112. package/dist/session-manager/index.js.map +1 -0
  113. package/dist/session-manager/session-manager.d.ts +107 -0
  114. package/dist/session-manager/session-manager.d.ts.map +1 -0
  115. package/dist/session-manager/session-manager.js +347 -0
  116. package/dist/session-manager/session-manager.js.map +1 -0
  117. package/dist/session-manager/types.d.ts +167 -0
  118. package/dist/session-manager/types.d.ts.map +1 -0
  119. package/dist/session-manager/types.js +57 -0
  120. package/dist/session-manager/types.js.map +1 -0
  121. package/dist/types.d.ts +323 -0
  122. package/dist/types.d.ts.map +1 -0
  123. package/dist/types.js +8 -0
  124. package/dist/types.js.map +1 -0
  125. package/dist/utils/__tests__/formatting.test.d.ts +2 -0
  126. package/dist/utils/__tests__/formatting.test.d.ts.map +1 -0
  127. package/dist/utils/__tests__/formatting.test.js +571 -0
  128. package/dist/utils/__tests__/formatting.test.js.map +1 -0
  129. package/dist/utils/formatting.d.ts +211 -0
  130. package/dist/utils/formatting.d.ts.map +1 -0
  131. package/dist/utils/formatting.js +305 -0
  132. package/dist/utils/formatting.js.map +1 -0
  133. package/dist/utils/index.d.ts +5 -0
  134. package/dist/utils/index.d.ts.map +1 -0
  135. package/dist/utils/index.js +9 -0
  136. package/dist/utils/index.js.map +1 -0
  137. package/package.json +49 -0
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Session manager for Discord channel conversations
3
+ *
4
+ * Provides per-channel session management for Claude conversations,
5
+ * enabling conversation context preservation across Discord channels.
6
+ *
7
+ * Sessions are stored at .herdctl/discord-sessions/<agent-name>.yaml
8
+ */
9
+ import { mkdir } from "node:fs/promises";
10
+ import { join, dirname } from "node:path";
11
+ import { randomUUID } from "node:crypto";
12
+ import { stringify as stringifyYaml, parse as parseYaml } from "yaml";
13
+ import { readFile, writeFile, rename, unlink } from "node:fs/promises";
14
+ import { randomBytes } from "node:crypto";
15
+ import { DiscordSessionStateSchema, createInitialSessionState, } from "./types.js";
16
+ import { SessionStateReadError, SessionStateWriteError, SessionDirectoryCreateError, } from "./errors.js";
17
+ // =============================================================================
18
+ // Default Logger
19
+ // =============================================================================
20
+ function createDefaultLogger(agentName) {
21
+ const prefix = `[session:${agentName}]`;
22
+ return {
23
+ debug: (msg, data) => console.debug(prefix, msg, data ? JSON.stringify(data) : ""),
24
+ info: (msg, data) => console.info(prefix, msg, data ? JSON.stringify(data) : ""),
25
+ warn: (msg, data) => console.warn(prefix, msg, data ? JSON.stringify(data) : ""),
26
+ error: (msg, data) => console.error(prefix, msg, data ? JSON.stringify(data) : ""),
27
+ };
28
+ }
29
+ // =============================================================================
30
+ // Session Manager Implementation
31
+ // =============================================================================
32
+ /**
33
+ * SessionManager manages per-channel Claude sessions for a Discord agent.
34
+ *
35
+ * Each agent has its own SessionManager instance, storing session mappings
36
+ * in a YAML file at .herdctl/discord-sessions/<agent-name>.yaml
37
+ *
38
+ * Features:
39
+ * - Create new sessions for channels/DMs
40
+ * - Resume existing sessions when user sends messages
41
+ * - Automatic session expiry based on configurable timeout
42
+ * - Cleanup expired sessions on startup
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const sessionManager = new SessionManager({
47
+ * agentName: 'my-agent',
48
+ * stateDir: '.herdctl',
49
+ * sessionExpiryHours: 24,
50
+ * });
51
+ *
52
+ * // Get or create a session for a channel
53
+ * const { sessionId, isNew } = await sessionManager.getOrCreateSession('channel-123');
54
+ *
55
+ * // After sending/receiving a message
56
+ * await sessionManager.touchSession('channel-123');
57
+ *
58
+ * // Cleanup expired sessions on startup
59
+ * const cleanedUp = await sessionManager.cleanupExpiredSessions();
60
+ * ```
61
+ */
62
+ export class SessionManager {
63
+ agentName;
64
+ stateDir;
65
+ sessionExpiryHours;
66
+ logger;
67
+ stateFilePath;
68
+ // In-memory cache of session state
69
+ state = null;
70
+ constructor(options) {
71
+ this.agentName = options.agentName;
72
+ this.stateDir = options.stateDir;
73
+ this.sessionExpiryHours = options.sessionExpiryHours ?? 24;
74
+ this.logger =
75
+ options.logger ?? createDefaultLogger(options.agentName);
76
+ // Compute state file path
77
+ this.stateFilePath = join(this.stateDir, "discord-sessions", `${this.agentName}.yaml`);
78
+ }
79
+ // ===========================================================================
80
+ // Public API
81
+ // ===========================================================================
82
+ /**
83
+ * Get or create a session for a channel/DM
84
+ *
85
+ * If an active (non-expired) session exists, returns it.
86
+ * Otherwise, creates a new session with a generated session ID.
87
+ */
88
+ async getOrCreateSession(channelId) {
89
+ const existingSession = await this.getSession(channelId);
90
+ if (existingSession) {
91
+ this.logger.info("Resuming existing session", {
92
+ channelId,
93
+ sessionId: existingSession.sessionId,
94
+ });
95
+ return {
96
+ sessionId: existingSession.sessionId,
97
+ isNew: false,
98
+ };
99
+ }
100
+ // Create new session
101
+ const sessionId = this.generateSessionId();
102
+ const state = await this.loadState();
103
+ const now = new Date().toISOString();
104
+ state.channels[channelId] = {
105
+ sessionId,
106
+ lastMessageAt: now,
107
+ };
108
+ await this.saveState(state);
109
+ this.logger.info("Created new session", { channelId, sessionId });
110
+ return {
111
+ sessionId,
112
+ isNew: true,
113
+ };
114
+ }
115
+ /**
116
+ * Update the last message timestamp for a session
117
+ */
118
+ async touchSession(channelId) {
119
+ const state = await this.loadState();
120
+ const session = state.channels[channelId];
121
+ if (!session) {
122
+ this.logger.warn("Attempted to touch non-existent session", {
123
+ channelId,
124
+ });
125
+ return;
126
+ }
127
+ session.lastMessageAt = new Date().toISOString();
128
+ await this.saveState(state);
129
+ this.logger.debug("Touched session", {
130
+ channelId,
131
+ sessionId: session.sessionId,
132
+ });
133
+ }
134
+ /**
135
+ * Get an existing session without creating one
136
+ *
137
+ * Returns null if no session exists or if the session is expired.
138
+ */
139
+ async getSession(channelId) {
140
+ const state = await this.loadState();
141
+ const session = state.channels[channelId];
142
+ if (!session) {
143
+ return null;
144
+ }
145
+ // Check if session is expired
146
+ if (this.isSessionExpired(session)) {
147
+ this.logger.info("Session expired", {
148
+ channelId,
149
+ sessionId: session.sessionId,
150
+ lastMessageAt: session.lastMessageAt,
151
+ expiryHours: this.sessionExpiryHours,
152
+ });
153
+ return null;
154
+ }
155
+ return session;
156
+ }
157
+ /**
158
+ * Clear a specific session
159
+ */
160
+ async clearSession(channelId) {
161
+ const state = await this.loadState();
162
+ if (!state.channels[channelId]) {
163
+ return false;
164
+ }
165
+ const sessionId = state.channels[channelId].sessionId;
166
+ delete state.channels[channelId];
167
+ await this.saveState(state);
168
+ this.logger.info("Cleared session", { channelId, sessionId });
169
+ return true;
170
+ }
171
+ /**
172
+ * Clean up all expired sessions
173
+ *
174
+ * Should be called on connector startup and periodically.
175
+ */
176
+ async cleanupExpiredSessions() {
177
+ const state = await this.loadState();
178
+ const channelIds = Object.keys(state.channels);
179
+ let cleanedUp = 0;
180
+ for (const channelId of channelIds) {
181
+ const session = state.channels[channelId];
182
+ if (this.isSessionExpired(session)) {
183
+ this.logger.debug("Cleaning up expired session", {
184
+ channelId,
185
+ sessionId: session.sessionId,
186
+ lastMessageAt: session.lastMessageAt,
187
+ });
188
+ delete state.channels[channelId];
189
+ cleanedUp++;
190
+ }
191
+ }
192
+ if (cleanedUp > 0) {
193
+ await this.saveState(state);
194
+ this.logger.info("Cleaned up expired sessions", { count: cleanedUp });
195
+ }
196
+ return cleanedUp;
197
+ }
198
+ // ===========================================================================
199
+ // Private Helpers
200
+ // ===========================================================================
201
+ /**
202
+ * Generate a unique session ID
203
+ */
204
+ generateSessionId() {
205
+ return `discord-${this.agentName}-${randomUUID()}`;
206
+ }
207
+ /**
208
+ * Check if a session is expired
209
+ */
210
+ isSessionExpired(session) {
211
+ const lastMessageAt = new Date(session.lastMessageAt);
212
+ const now = new Date();
213
+ const expiryMs = this.sessionExpiryHours * 60 * 60 * 1000;
214
+ return now.getTime() - lastMessageAt.getTime() > expiryMs;
215
+ }
216
+ /**
217
+ * Load session state from disk
218
+ *
219
+ * Returns cached state if available, otherwise loads from file.
220
+ * Creates initial state if file doesn't exist.
221
+ */
222
+ async loadState() {
223
+ if (this.state) {
224
+ return this.state;
225
+ }
226
+ let content;
227
+ try {
228
+ content = await readFile(this.stateFilePath, "utf-8");
229
+ }
230
+ catch (error) {
231
+ const code = error.code;
232
+ // File doesn't exist - create initial state
233
+ if (code === "ENOENT") {
234
+ this.state = createInitialSessionState(this.agentName);
235
+ return this.state;
236
+ }
237
+ // Other read errors are fatal
238
+ throw new SessionStateReadError(this.agentName, this.stateFilePath, { cause: error });
239
+ }
240
+ // Handle empty file
241
+ if (content.trim() === "") {
242
+ this.state = createInitialSessionState(this.agentName);
243
+ return this.state;
244
+ }
245
+ // Parse YAML - treat parse errors as corrupted state
246
+ let parsed;
247
+ try {
248
+ parsed = parseYaml(content);
249
+ }
250
+ catch (error) {
251
+ this.logger.warn("Corrupted session state file, creating fresh state", {
252
+ error: error.message,
253
+ });
254
+ this.state = createInitialSessionState(this.agentName);
255
+ return this.state;
256
+ }
257
+ // Validate against schema - treat validation errors as corrupted state
258
+ const validated = DiscordSessionStateSchema.safeParse(parsed);
259
+ if (!validated.success) {
260
+ this.logger.warn("Corrupted session state file, creating fresh state", {
261
+ error: validated.error.message,
262
+ });
263
+ this.state = createInitialSessionState(this.agentName);
264
+ return this.state;
265
+ }
266
+ this.state = validated.data;
267
+ return this.state;
268
+ }
269
+ /**
270
+ * Save session state to disk atomically
271
+ */
272
+ async saveState(state) {
273
+ // Ensure directory exists
274
+ await this.ensureDirectoryExists();
275
+ // Update in-memory cache
276
+ this.state = state;
277
+ // Write atomically
278
+ const yamlContent = stringifyYaml(state, { indent: 2, lineWidth: 120 });
279
+ const tempPath = this.generateTempPath(this.stateFilePath);
280
+ try {
281
+ await writeFile(tempPath, yamlContent, "utf-8");
282
+ await this.renameWithRetry(tempPath, this.stateFilePath);
283
+ }
284
+ catch (error) {
285
+ // Clean up temp file on failure
286
+ try {
287
+ await unlink(tempPath);
288
+ }
289
+ catch {
290
+ // Ignore cleanup errors
291
+ }
292
+ throw new SessionStateWriteError(this.agentName, this.stateFilePath, { cause: error });
293
+ }
294
+ }
295
+ /**
296
+ * Ensure the discord-sessions directory exists
297
+ */
298
+ async ensureDirectoryExists() {
299
+ const dir = dirname(this.stateFilePath);
300
+ try {
301
+ await mkdir(dir, { recursive: true });
302
+ }
303
+ catch (error) {
304
+ const code = error.code;
305
+ // EEXIST is fine - directory already exists
306
+ if (code !== "EEXIST") {
307
+ throw new SessionDirectoryCreateError(this.agentName, dir, { cause: error });
308
+ }
309
+ }
310
+ }
311
+ /**
312
+ * Generate a temp file path for atomic writes
313
+ */
314
+ generateTempPath(targetPath) {
315
+ const dir = dirname(targetPath);
316
+ const random = randomBytes(8).toString("hex");
317
+ const filename = `${this.agentName}.yaml`;
318
+ return join(dir, `.${filename}.tmp.${random}`);
319
+ }
320
+ /**
321
+ * Rename with retry logic for Windows compatibility
322
+ */
323
+ async renameWithRetry(oldPath, newPath, maxRetries = 3, baseDelayMs = 50) {
324
+ let lastError;
325
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
326
+ try {
327
+ await rename(oldPath, newPath);
328
+ return;
329
+ }
330
+ catch (error) {
331
+ lastError = error;
332
+ const code = error.code;
333
+ // Only retry on Windows-specific errors
334
+ if (code !== "EACCES" && code !== "EPERM") {
335
+ throw error;
336
+ }
337
+ // Don't delay on the last attempt
338
+ if (attempt < maxRetries) {
339
+ const delay = baseDelayMs * Math.pow(2, attempt);
340
+ await new Promise((resolve) => setTimeout(resolve, delay));
341
+ }
342
+ }
343
+ }
344
+ throw lastError;
345
+ }
346
+ }
347
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/session-manager/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAOL,yBAAyB,EACzB,yBAAyB,GAE1B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,aAAa,CAAC;AAErB,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,SAAS,mBAAmB,CAAC,SAAiB;IAC5C,MAAM,MAAM,GAAG,YAAY,SAAS,GAAG,CAAC;IACxC,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CACnB,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAClB,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAClB,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CACnB,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,iCAAiC;AACjC,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,OAAO,cAAc;IACT,SAAS,CAAS;IAEjB,QAAQ,CAAS;IACjB,kBAAkB,CAAS;IAC3B,MAAM,CAAuB;IAC7B,aAAa,CAAS;IAEvC,mCAAmC;IAC3B,KAAK,GAA+B,IAAI,CAAC;IAEjD,YAAY,OAA8B;QACxC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAC3D,IAAI,CAAC,MAAM;YACT,OAAO,CAAC,MAAM,IAAI,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAE3D,0BAA0B;QAC1B,IAAI,CAAC,aAAa,GAAG,IAAI,CACvB,IAAI,CAAC,QAAQ,EACb,kBAAkB,EAClB,GAAG,IAAI,CAAC,SAAS,OAAO,CACzB,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,aAAa;IACb,8EAA8E;IAE9E;;;;;OAKG;IACH,KAAK,CAAC,kBAAkB,CAAC,SAAiB;QACxC,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAEzD,IAAI,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE;gBAC5C,SAAS;gBACT,SAAS,EAAE,eAAe,CAAC,SAAS;aACrC,CAAC,CAAC;YACH,OAAO;gBACL,SAAS,EAAE,eAAe,CAAC,SAAS;gBACpC,KAAK,EAAE,KAAK;aACb,CAAC;QACJ,CAAC;QAED,qBAAqB;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG;YAC1B,SAAS;YACT,aAAa,EAAE,GAAG;SACnB,CAAC;QAEF,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAE5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;QAElE,OAAO;YACL,SAAS;YACT,KAAK,EAAE,IAAI;SACZ,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,SAAiB;QAClC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAE1C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,EAAE;gBAC1D,SAAS;aACV,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,OAAO,CAAC,aAAa,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAE5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE;YACnC,SAAS;YACT,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAE1C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,8BAA8B;QAC9B,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;gBAClC,SAAS;gBACT,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;gBACpC,WAAW,EAAE,IAAI,CAAC,kBAAkB;aACrC,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,SAAiB;QAClC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAErC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC;QACtD,OAAO,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACjC,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAE5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,sBAAsB;QAC1B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YAC1C,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE;oBAC/C,SAAS;oBACT,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;iBACrC,CAAC,CAAC;gBACH,OAAO,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;gBACjC,SAAS,EAAE,CAAC;YACd,CAAC;QACH,CAAC;QAED,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAClB,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,8EAA8E;IAC9E,kBAAkB;IAClB,8EAA8E;IAE9E;;OAEG;IACK,iBAAiB;QACvB,OAAO,WAAW,IAAI,CAAC,SAAS,IAAI,UAAU,EAAE,EAAE,CAAC;IACrD,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,OAAuB;QAC9C,MAAM,aAAa,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACtD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAC1D,OAAO,GAAG,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC;IAC5D,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,SAAS;QACrB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAED,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;YAEnD,4CAA4C;YAC5C,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtB,IAAI,CAAC,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACvD,OAAO,IAAI,CAAC,KAAK,CAAC;YACpB,CAAC;YAED,8BAA8B;YAC9B,MAAM,IAAI,qBAAqB,CAC7B,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,aAAa,EAClB,EAAE,KAAK,EAAE,KAAc,EAAE,CAC1B,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAED,qDAAqD;QACrD,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oDAAoD,EAAE;gBACrE,KAAK,EAAG,KAAe,CAAC,OAAO;aAChC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAED,uEAAuE;QACvE,MAAM,SAAS,GAAG,yBAAyB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oDAAoD,EAAE;gBACrE,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,OAAO;aAC/B,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,SAAS,CAAC,KAA0B;QAChD,0BAA0B;QAC1B,MAAM,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAEnC,yBAAyB;QACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,mBAAmB;QACnB,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAE3D,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;YAChD,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gCAAgC;YAChC,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;YAED,MAAM,IAAI,sBAAsB,CAC9B,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,aAAa,EAClB,EAAE,KAAK,EAAE,KAAc,EAAE,CAC1B,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,qBAAqB;QACjC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;YACnD,4CAA4C;YAC5C,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtB,MAAM,IAAI,2BAA2B,CACnC,IAAI,CAAC,SAAS,EACd,GAAG,EACH,EAAE,KAAK,EAAE,KAAc,EAAE,CAC1B,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,UAAkB;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,SAAS,OAAO,CAAC;QAC1C,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,QAAQ,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe,CAC3B,OAAe,EACf,OAAe,EACf,UAAU,GAAG,CAAC,EACd,WAAW,GAAG,EAAE;QAEhB,IAAI,SAA4B,CAAC;QAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;YACvD,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC/B,OAAO;YACT,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,GAAG,KAAc,CAAC;gBAC3B,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;gBAEnD,wCAAwC;gBACxC,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC1C,MAAM,KAAK,CAAC;gBACd,CAAC;gBAED,kCAAkC;gBAClC,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;oBACzB,MAAM,KAAK,GAAG,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;oBACjD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,SAAS,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Type definitions for Discord session management
3
+ *
4
+ * Provides interfaces for per-channel session state tracking,
5
+ * enabling conversation context preservation across Discord channels.
6
+ */
7
+ import { z } from "zod";
8
+ /**
9
+ * Schema for individual channel/DM session mapping
10
+ */
11
+ export declare const ChannelSessionSchema: z.ZodObject<{
12
+ /** Claude session ID for resuming conversations */
13
+ sessionId: z.ZodString;
14
+ /** ISO timestamp when last message was sent/received */
15
+ lastMessageAt: z.ZodString;
16
+ }, "strip", z.ZodTypeAny, {
17
+ sessionId: string;
18
+ lastMessageAt: string;
19
+ }, {
20
+ sessionId: string;
21
+ lastMessageAt: string;
22
+ }>;
23
+ /**
24
+ * Schema for the entire agent's Discord session state file
25
+ *
26
+ * Stored at .herdctl/discord-sessions/<agent-name>.yaml
27
+ */
28
+ export declare const DiscordSessionStateSchema: z.ZodObject<{
29
+ /** Version for future schema migrations */
30
+ version: z.ZodLiteral<1>;
31
+ /** Agent name this session state belongs to */
32
+ agentName: z.ZodString;
33
+ /** Map of channel/DM ID to session info */
34
+ channels: z.ZodRecord<z.ZodString, z.ZodObject<{
35
+ /** Claude session ID for resuming conversations */
36
+ sessionId: z.ZodString;
37
+ /** ISO timestamp when last message was sent/received */
38
+ lastMessageAt: z.ZodString;
39
+ }, "strip", z.ZodTypeAny, {
40
+ sessionId: string;
41
+ lastMessageAt: string;
42
+ }, {
43
+ sessionId: string;
44
+ lastMessageAt: string;
45
+ }>>;
46
+ }, "strip", z.ZodTypeAny, {
47
+ channels: Record<string, {
48
+ sessionId: string;
49
+ lastMessageAt: string;
50
+ }>;
51
+ version: 1;
52
+ agentName: string;
53
+ }, {
54
+ channels: Record<string, {
55
+ sessionId: string;
56
+ lastMessageAt: string;
57
+ }>;
58
+ version: 1;
59
+ agentName: string;
60
+ }>;
61
+ export type ChannelSession = z.infer<typeof ChannelSessionSchema>;
62
+ export type DiscordSessionState = z.infer<typeof DiscordSessionStateSchema>;
63
+ /**
64
+ * Logger interface for session manager operations
65
+ */
66
+ export interface SessionManagerLogger {
67
+ debug(message: string, data?: Record<string, unknown>): void;
68
+ info(message: string, data?: Record<string, unknown>): void;
69
+ warn(message: string, data?: Record<string, unknown>): void;
70
+ error(message: string, data?: Record<string, unknown>): void;
71
+ }
72
+ /**
73
+ * Options for configuring the SessionManager
74
+ */
75
+ export interface SessionManagerOptions {
76
+ /**
77
+ * Name of the agent this session manager is for
78
+ */
79
+ agentName: string;
80
+ /**
81
+ * Root path for state storage (e.g., .herdctl)
82
+ * Sessions will be stored at <stateDir>/discord-sessions/<agent-name>.yaml
83
+ */
84
+ stateDir: string;
85
+ /**
86
+ * Session expiry timeout in hours
87
+ * Sessions inactive for longer than this will be considered expired
88
+ *
89
+ * @default 24
90
+ */
91
+ sessionExpiryHours?: number;
92
+ /**
93
+ * Logger for session manager operations
94
+ *
95
+ * @default console-based logger
96
+ */
97
+ logger?: SessionManagerLogger;
98
+ }
99
+ /**
100
+ * Result of getting or creating a session
101
+ */
102
+ export interface SessionResult {
103
+ /** Claude session ID */
104
+ sessionId: string;
105
+ /** Whether this is a newly created session */
106
+ isNew: boolean;
107
+ }
108
+ /**
109
+ * Interface that all session managers must implement
110
+ */
111
+ export interface ISessionManager {
112
+ /**
113
+ * Get or create a session for a channel/DM
114
+ *
115
+ * If an active (non-expired) session exists, returns it.
116
+ * Otherwise, creates a new session.
117
+ *
118
+ * @param channelId - Discord channel or DM ID
119
+ * @returns Session info with sessionId and isNew flag
120
+ */
121
+ getOrCreateSession(channelId: string): Promise<SessionResult>;
122
+ /**
123
+ * Update the last message timestamp for a session
124
+ *
125
+ * Called after each message to keep the session active.
126
+ *
127
+ * @param channelId - Discord channel or DM ID
128
+ */
129
+ touchSession(channelId: string): Promise<void>;
130
+ /**
131
+ * Get an existing session without creating one
132
+ *
133
+ * Returns null if no session exists or if the session is expired.
134
+ *
135
+ * @param channelId - Discord channel or DM ID
136
+ * @returns The session if it exists and is not expired, null otherwise
137
+ */
138
+ getSession(channelId: string): Promise<ChannelSession | null>;
139
+ /**
140
+ * Clear a specific session
141
+ *
142
+ * @param channelId - Discord channel or DM ID
143
+ * @returns true if the session was cleared, false if it didn't exist
144
+ */
145
+ clearSession(channelId: string): Promise<boolean>;
146
+ /**
147
+ * Clean up all expired sessions
148
+ *
149
+ * Should be called on connector startup and periodically.
150
+ *
151
+ * @returns Number of sessions that were cleaned up
152
+ */
153
+ cleanupExpiredSessions(): Promise<number>;
154
+ /**
155
+ * Name of the agent this session manager is for
156
+ */
157
+ readonly agentName: string;
158
+ }
159
+ /**
160
+ * Create initial session state for a new agent
161
+ */
162
+ export declare function createInitialSessionState(agentName: string): DiscordSessionState;
163
+ /**
164
+ * Create a new channel session
165
+ */
166
+ export declare function createChannelSession(sessionId: string): ChannelSession;
167
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/session-manager/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;GAEG;AACH,eAAO,MAAM,oBAAoB;IAC/B,mDAAmD;;IAGnD,wDAAwD;;;;;;;;EAIxD,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB;IACpC,2CAA2C;;IAG3C,+CAA+C;;IAG/C,2CAA2C;;QArB3C,mDAAmD;;QAGnD,wDAAwD;;;;;;;;;;;;;;;;;;;;;;;EAoBxD,CAAC;AAMH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAM5E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9D;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAMD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAElB,8CAA8C;IAC9C,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;;OAQG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE9D;;;;;;OAMG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C;;;;;;;OAOG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAE9D;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAElD;;;;;;OAMG;IACH,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE1C;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAMD;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAChB,mBAAmB,CAMrB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAKtE"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Type definitions for Discord session management
3
+ *
4
+ * Provides interfaces for per-channel session state tracking,
5
+ * enabling conversation context preservation across Discord channels.
6
+ */
7
+ import { z } from "zod";
8
+ // =============================================================================
9
+ // Session Schema
10
+ // =============================================================================
11
+ /**
12
+ * Schema for individual channel/DM session mapping
13
+ */
14
+ export const ChannelSessionSchema = z.object({
15
+ /** Claude session ID for resuming conversations */
16
+ sessionId: z.string().min(1, "Session ID cannot be empty"),
17
+ /** ISO timestamp when last message was sent/received */
18
+ lastMessageAt: z.string().datetime({
19
+ message: "lastMessageAt must be a valid ISO datetime string",
20
+ }),
21
+ });
22
+ /**
23
+ * Schema for the entire agent's Discord session state file
24
+ *
25
+ * Stored at .herdctl/discord-sessions/<agent-name>.yaml
26
+ */
27
+ export const DiscordSessionStateSchema = z.object({
28
+ /** Version for future schema migrations */
29
+ version: z.literal(1),
30
+ /** Agent name this session state belongs to */
31
+ agentName: z.string().min(1, "Agent name cannot be empty"),
32
+ /** Map of channel/DM ID to session info */
33
+ channels: z.record(z.string(), ChannelSessionSchema),
34
+ });
35
+ // =============================================================================
36
+ // Factory Functions
37
+ // =============================================================================
38
+ /**
39
+ * Create initial session state for a new agent
40
+ */
41
+ export function createInitialSessionState(agentName) {
42
+ return {
43
+ version: 1,
44
+ agentName,
45
+ channels: {},
46
+ };
47
+ }
48
+ /**
49
+ * Create a new channel session
50
+ */
51
+ export function createChannelSession(sessionId) {
52
+ return {
53
+ sessionId,
54
+ lastMessageAt: new Date().toISOString(),
55
+ };
56
+ }
57
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/session-manager/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,mDAAmD;IACnD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,4BAA4B,CAAC;IAE1D,wDAAwD;IACxD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC;QACjC,OAAO,EAAE,mDAAmD;KAC7D,CAAC;CACH,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,2CAA2C;IAC3C,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAErB,+CAA+C;IAC/C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,4BAA4B,CAAC;IAE1D,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC;CACrD,CAAC,CAAC;AA8HH,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,SAAiB;IAEjB,OAAO;QACL,OAAO,EAAE,CAAC;QACV,SAAS;QACT,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,OAAO;QACL,SAAS;QACT,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACxC,CAAC;AACJ,CAAC"}