@herdctl/discord 1.1.1 → 1.2.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 (134) hide show
  1. package/README.md +14 -1
  2. package/dist/__tests__/attachments.test.d.ts +8 -0
  3. package/dist/__tests__/attachments.test.d.ts.map +1 -0
  4. package/dist/__tests__/attachments.test.js +439 -0
  5. package/dist/__tests__/attachments.test.js.map +1 -0
  6. package/dist/__tests__/discord-connector.test.js +4 -1
  7. package/dist/__tests__/discord-connector.test.js.map +1 -1
  8. package/dist/__tests__/embeds.test.d.ts +2 -0
  9. package/dist/__tests__/embeds.test.d.ts.map +1 -0
  10. package/dist/__tests__/embeds.test.js +47 -0
  11. package/dist/__tests__/embeds.test.js.map +1 -0
  12. package/dist/__tests__/logger.test.js +4 -1
  13. package/dist/__tests__/logger.test.js.map +1 -1
  14. package/dist/__tests__/manager.test.js +1193 -28
  15. package/dist/__tests__/manager.test.js.map +1 -1
  16. package/dist/__tests__/message-normalizer.test.d.ts +2 -0
  17. package/dist/__tests__/message-normalizer.test.d.ts.map +1 -0
  18. package/dist/__tests__/message-normalizer.test.js +83 -0
  19. package/dist/__tests__/message-normalizer.test.js.map +1 -0
  20. package/dist/__tests__/runtime-parity.test.d.ts +2 -0
  21. package/dist/__tests__/runtime-parity.test.d.ts.map +1 -0
  22. package/dist/__tests__/runtime-parity.test.js +157 -0
  23. package/dist/__tests__/runtime-parity.test.js.map +1 -0
  24. package/dist/auto-mode-handler.d.ts.map +1 -1
  25. package/dist/auto-mode-handler.js +9 -0
  26. package/dist/auto-mode-handler.js.map +1 -1
  27. package/dist/commands/__tests__/command-manager.test.js +63 -3
  28. package/dist/commands/__tests__/command-manager.test.js.map +1 -1
  29. package/dist/commands/__tests__/extended-commands.test.d.ts +2 -0
  30. package/dist/commands/__tests__/extended-commands.test.d.ts.map +1 -0
  31. package/dist/commands/__tests__/extended-commands.test.js +159 -0
  32. package/dist/commands/__tests__/extended-commands.test.js.map +1 -0
  33. package/dist/commands/__tests__/help.test.js +5 -6
  34. package/dist/commands/__tests__/help.test.js.map +1 -1
  35. package/dist/commands/__tests__/reset.test.js +14 -6
  36. package/dist/commands/__tests__/reset.test.js.map +1 -1
  37. package/dist/commands/__tests__/status.test.js +27 -25
  38. package/dist/commands/__tests__/status.test.js.map +1 -1
  39. package/dist/commands/cancel.d.ts +3 -0
  40. package/dist/commands/cancel.d.ts.map +1 -0
  41. package/dist/commands/cancel.js +7 -0
  42. package/dist/commands/cancel.js.map +1 -0
  43. package/dist/commands/command-manager.d.ts +4 -1
  44. package/dist/commands/command-manager.d.ts.map +1 -1
  45. package/dist/commands/command-manager.js +65 -3
  46. package/dist/commands/command-manager.js.map +1 -1
  47. package/dist/commands/config.d.ts +3 -0
  48. package/dist/commands/config.d.ts.map +1 -0
  49. package/dist/commands/config.js +33 -0
  50. package/dist/commands/config.js.map +1 -0
  51. package/dist/commands/help.d.ts +1 -1
  52. package/dist/commands/help.d.ts.map +1 -1
  53. package/dist/commands/help.js +26 -12
  54. package/dist/commands/help.js.map +1 -1
  55. package/dist/commands/index.d.ts +12 -1
  56. package/dist/commands/index.d.ts.map +1 -1
  57. package/dist/commands/index.js +12 -1
  58. package/dist/commands/index.js.map +1 -1
  59. package/dist/commands/new.d.ts +3 -0
  60. package/dist/commands/new.d.ts.map +1 -0
  61. package/dist/commands/new.js +22 -0
  62. package/dist/commands/new.js.map +1 -0
  63. package/dist/commands/ping.d.ts +3 -0
  64. package/dist/commands/ping.d.ts.map +1 -0
  65. package/dist/commands/ping.js +22 -0
  66. package/dist/commands/ping.js.map +1 -0
  67. package/dist/commands/reset.d.ts +1 -1
  68. package/dist/commands/reset.d.ts.map +1 -1
  69. package/dist/commands/reset.js +13 -13
  70. package/dist/commands/reset.js.map +1 -1
  71. package/dist/commands/retry.d.ts +3 -0
  72. package/dist/commands/retry.d.ts.map +1 -0
  73. package/dist/commands/retry.js +25 -0
  74. package/dist/commands/retry.js.map +1 -0
  75. package/dist/commands/session.d.ts +3 -0
  76. package/dist/commands/session.d.ts.map +1 -0
  77. package/dist/commands/session.js +47 -0
  78. package/dist/commands/session.js.map +1 -0
  79. package/dist/commands/skill.d.ts +3 -0
  80. package/dist/commands/skill.d.ts.map +1 -0
  81. package/dist/commands/skill.js +44 -0
  82. package/dist/commands/skill.js.map +1 -0
  83. package/dist/commands/skills.d.ts +3 -0
  84. package/dist/commands/skills.d.ts.map +1 -0
  85. package/dist/commands/skills.js +30 -0
  86. package/dist/commands/skills.js.map +1 -0
  87. package/dist/commands/status.d.ts +1 -1
  88. package/dist/commands/status.d.ts.map +1 -1
  89. package/dist/commands/status.js +25 -18
  90. package/dist/commands/status.js.map +1 -1
  91. package/dist/commands/stop.d.ts +3 -0
  92. package/dist/commands/stop.d.ts.map +1 -0
  93. package/dist/commands/stop.js +25 -0
  94. package/dist/commands/stop.js.map +1 -0
  95. package/dist/commands/tools.d.ts +3 -0
  96. package/dist/commands/tools.d.ts.map +1 -0
  97. package/dist/commands/tools.js +30 -0
  98. package/dist/commands/tools.js.map +1 -0
  99. package/dist/commands/types.d.ts +71 -1
  100. package/dist/commands/types.d.ts.map +1 -1
  101. package/dist/commands/usage.d.ts +3 -0
  102. package/dist/commands/usage.d.ts.map +1 -0
  103. package/dist/commands/usage.js +58 -0
  104. package/dist/commands/usage.js.map +1 -0
  105. package/dist/discord-connector.d.ts +10 -1
  106. package/dist/discord-connector.d.ts.map +1 -1
  107. package/dist/discord-connector.js +153 -8
  108. package/dist/discord-connector.js.map +1 -1
  109. package/dist/embeds.d.ts +47 -0
  110. package/dist/embeds.d.ts.map +1 -0
  111. package/dist/embeds.js +121 -0
  112. package/dist/embeds.js.map +1 -0
  113. package/dist/index.d.ts +6 -2
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +3 -1
  116. package/dist/index.js.map +1 -1
  117. package/dist/manager.d.ts +53 -24
  118. package/dist/manager.d.ts.map +1 -1
  119. package/dist/manager.js +1031 -217
  120. package/dist/manager.js.map +1 -1
  121. package/dist/mention-handler.d.ts.map +1 -1
  122. package/dist/mention-handler.js +27 -0
  123. package/dist/mention-handler.js.map +1 -1
  124. package/dist/message-normalizer.d.ts +40 -0
  125. package/dist/message-normalizer.d.ts.map +1 -0
  126. package/dist/message-normalizer.js +99 -0
  127. package/dist/message-normalizer.js.map +1 -0
  128. package/dist/types.d.ts +80 -3
  129. package/dist/types.d.ts.map +1 -1
  130. package/dist/voice-transcriber.d.ts +31 -0
  131. package/dist/voice-transcriber.d.ts.map +1 -0
  132. package/dist/voice-transcriber.js +44 -0
  133. package/dist/voice-transcriber.js.map +1 -0
  134. package/package.json +3 -3
package/README.md CHANGED
@@ -140,7 +140,7 @@ This allows you to run multiple agents with different Discord identities, each w
140
140
  - **DM Support** - Users can chat privately with agents
141
141
  - **Channel Support** - Agents can participate in server channels
142
142
  - **Per-Agent Bots** - Each agent can have its own Discord bot identity
143
- - **Slash Commands** - Built-in `/status`, `/reset`, and `/help` commands
143
+ - **Slash Commands** - Built-in `/help`, `/ping`, `/config`, `/tools`, `/usage`, `/skills`, `/skill`, `/status`, `/session`, `/reset`, `/new`, `/stop`, `/cancel`, `/retry`
144
144
  - **Typing Indicators** - Visual feedback while agent is processing
145
145
  - **Message Splitting** - Long responses are automatically split to fit Discord's limits
146
146
 
@@ -149,8 +149,21 @@ This allows you to run multiple agents with different Discord identities, each w
149
149
  | Command | Description |
150
150
  |---------|-------------|
151
151
  | `/help` | Show available commands and usage |
152
+ | `/ping` | Quick health check |
153
+ | `/config` | Show runtime-relevant agent configuration |
154
+ | `/tools` | Show allowed/denied tools and MCP servers |
155
+ | `/usage` | Show latest run usage for this channel |
156
+ | `/skills` | List discovered skills for this agent |
157
+ | `/skill` | Trigger a skill (with autocomplete) |
152
158
  | `/status` | Show agent status and current session info |
159
+ | `/session` | Show session and run state for the current channel |
153
160
  | `/reset` | Clear conversation context (start fresh) |
161
+ | `/new` | Start a fresh conversation (alias for reset behavior) |
162
+ | `/stop` | Stop the active run in this channel |
163
+ | `/cancel` | Alias for `/stop` |
164
+ | `/retry` | Retry the last prompt in this channel |
165
+
166
+ To invoke slash commands, type `/` in Discord and pick the command under your bot app in Discord's command picker. Slash commands are routed as interaction events, not regular text messages.
154
167
 
155
168
  ## Bot Setup
156
169
 
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tests for Discord file attachment support
3
+ *
4
+ * Tests attachment categorization, MIME pattern matching, and the
5
+ * processAttachments / cleanupAttachments pipeline.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=attachments.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/attachments.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Tests for Discord file attachment support
3
+ *
4
+ * Tests attachment categorization, MIME pattern matching, and the
5
+ * processAttachments / cleanupAttachments pipeline.
6
+ */
7
+ import { mkdir, readFile, rm, stat } from "node:fs/promises";
8
+ import { tmpdir } from "node:os";
9
+ import { basename, dirname, join } from "node:path";
10
+ import { DiscordAttachmentsSchema } from "@herdctl/core";
11
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
12
+ import { DiscordConnector } from "../discord-connector.js";
13
+ import { DiscordManager } from "../manager.js";
14
+ // =============================================================================
15
+ // Mock discord.js (required because DiscordConnector imports it at module level)
16
+ // =============================================================================
17
+ vi.mock("discord.js", () => {
18
+ const { EventEmitter } = require("node:events");
19
+ class MockClient extends EventEmitter {
20
+ user = { id: "bot123", username: "TestBot", discriminator: "0001", setActivity: vi.fn() };
21
+ rest = new EventEmitter();
22
+ login = vi.fn().mockResolvedValue("token");
23
+ destroy = vi.fn();
24
+ }
25
+ return {
26
+ Client: MockClient,
27
+ GatewayIntentBits: { Guilds: 1, GuildMessages: 2, DirectMessages: 4, MessageContent: 8 },
28
+ Partials: { Channel: 0, Message: 1 },
29
+ Events: { ClientReady: "ready", MessageCreate: "messageCreate" },
30
+ MessageFlags: { IsVoiceMessage: 1 << 13 },
31
+ AttachmentBuilder: vi.fn(),
32
+ };
33
+ });
34
+ vi.mock("@discordjs/rest", () => ({
35
+ RESTEvents: { RateLimited: "rateLimited" },
36
+ }));
37
+ // =============================================================================
38
+ // Access private static methods for unit testing
39
+ // =============================================================================
40
+ // biome-ignore lint/suspicious/noExplicitAny: accessing private statics for testing
41
+ const ConnectorAny = DiscordConnector;
42
+ // biome-ignore lint/suspicious/noExplicitAny: accessing private statics for testing
43
+ const ManagerAny = DiscordManager;
44
+ // =============================================================================
45
+ // Schema Tests
46
+ // =============================================================================
47
+ describe("DiscordAttachmentsSchema", () => {
48
+ it("uses correct defaults when no fields are provided", () => {
49
+ const result = DiscordAttachmentsSchema.parse({});
50
+ expect(result).toEqual({
51
+ enabled: false,
52
+ max_file_size_mb: 10,
53
+ max_files_per_message: 5,
54
+ allowed_types: ["image/*", "application/pdf", "text/*"],
55
+ download_dir: ".discord-attachments",
56
+ cleanup_after_processing: true,
57
+ });
58
+ });
59
+ it("accepts full custom configuration", () => {
60
+ const result = DiscordAttachmentsSchema.parse({
61
+ enabled: true,
62
+ max_file_size_mb: 25,
63
+ max_files_per_message: 3,
64
+ allowed_types: ["image/png", "text/plain"],
65
+ download_dir: "my-downloads",
66
+ cleanup_after_processing: false,
67
+ });
68
+ expect(result.enabled).toBe(true);
69
+ expect(result.max_file_size_mb).toBe(25);
70
+ expect(result.max_files_per_message).toBe(3);
71
+ expect(result.allowed_types).toEqual(["image/png", "text/plain"]);
72
+ expect(result.download_dir).toBe("my-downloads");
73
+ expect(result.cleanup_after_processing).toBe(false);
74
+ });
75
+ it("rejects negative max_file_size_mb", () => {
76
+ expect(() => DiscordAttachmentsSchema.parse({ max_file_size_mb: -1 })).toThrow();
77
+ });
78
+ it("rejects zero max_files_per_message", () => {
79
+ expect(() => DiscordAttachmentsSchema.parse({ max_files_per_message: 0 })).toThrow();
80
+ });
81
+ });
82
+ // =============================================================================
83
+ // Categorize Content Type Tests
84
+ // =============================================================================
85
+ describe("_categorizeContentType", () => {
86
+ const categorize = ConnectorAny._categorizeContentType;
87
+ it("categorizes image/* as image", () => {
88
+ expect(categorize("image/png")).toBe("image");
89
+ expect(categorize("image/jpeg")).toBe("image");
90
+ expect(categorize("image/gif")).toBe("image");
91
+ expect(categorize("image/webp")).toBe("image");
92
+ });
93
+ it("categorizes application/pdf as pdf", () => {
94
+ expect(categorize("application/pdf")).toBe("pdf");
95
+ });
96
+ it("categorizes text/* as text", () => {
97
+ expect(categorize("text/plain")).toBe("text");
98
+ expect(categorize("text/html")).toBe("text");
99
+ expect(categorize("text/csv")).toBe("text");
100
+ expect(categorize("text/yaml")).toBe("text");
101
+ });
102
+ it("categorizes common code MIME types as text", () => {
103
+ expect(categorize("application/json")).toBe("text");
104
+ expect(categorize("application/javascript")).toBe("text");
105
+ expect(categorize("application/typescript")).toBe("text");
106
+ expect(categorize("application/x-yaml")).toBe("text");
107
+ expect(categorize("application/x-sh")).toBe("text");
108
+ expect(categorize("application/xml")).toBe("text");
109
+ });
110
+ it("returns unsupported for unknown types", () => {
111
+ expect(categorize("application/octet-stream")).toBe("unsupported");
112
+ expect(categorize("application/zip")).toBe("unsupported");
113
+ expect(categorize("video/mp4")).toBe("unsupported");
114
+ expect(categorize("audio/mpeg")).toBe("unsupported");
115
+ });
116
+ it("handles content types with charset parameters", () => {
117
+ expect(categorize("text/plain; charset=utf-8")).toBe("text");
118
+ expect(categorize("application/json; charset=utf-8")).toBe("text");
119
+ });
120
+ it("is case-insensitive", () => {
121
+ expect(categorize("Image/PNG")).toBe("image");
122
+ expect(categorize("APPLICATION/PDF")).toBe("pdf");
123
+ expect(categorize("Text/Plain")).toBe("text");
124
+ });
125
+ });
126
+ // =============================================================================
127
+ // MIME Pattern Matching Tests
128
+ // =============================================================================
129
+ describe("matchesMimePattern", () => {
130
+ const matches = ManagerAny.matchesMimePattern;
131
+ it("matches exact MIME types", () => {
132
+ expect(matches("image/png", "image/png")).toBe(true);
133
+ expect(matches("text/plain", "text/plain")).toBe(true);
134
+ expect(matches("application/pdf", "application/pdf")).toBe(true);
135
+ });
136
+ it("matches wildcard patterns", () => {
137
+ expect(matches("image/png", "image/*")).toBe(true);
138
+ expect(matches("image/jpeg", "image/*")).toBe(true);
139
+ expect(matches("text/plain", "text/*")).toBe(true);
140
+ expect(matches("text/html", "text/*")).toBe(true);
141
+ });
142
+ it("does not match different types", () => {
143
+ expect(matches("text/plain", "image/*")).toBe(false);
144
+ expect(matches("image/png", "text/*")).toBe(false);
145
+ expect(matches("application/pdf", "image/*")).toBe(false);
146
+ });
147
+ it("handles content types with parameters", () => {
148
+ expect(matches("text/plain; charset=utf-8", "text/*")).toBe(true);
149
+ expect(matches("text/plain; charset=utf-8", "text/plain")).toBe(true);
150
+ });
151
+ it("is case-insensitive", () => {
152
+ expect(matches("Image/PNG", "image/*")).toBe(true);
153
+ expect(matches("image/png", "Image/*")).toBe(true);
154
+ });
155
+ });
156
+ // =============================================================================
157
+ // processAttachments Tests
158
+ // =============================================================================
159
+ describe("processAttachments", () => {
160
+ const processAttachments = ManagerAny.processAttachments.bind(ManagerAny);
161
+ const mockLogger = {
162
+ debug: vi.fn(),
163
+ info: vi.fn(),
164
+ warn: vi.fn(),
165
+ error: vi.fn(),
166
+ };
167
+ let testDir;
168
+ beforeEach(async () => {
169
+ vi.clearAllMocks();
170
+ testDir = join(tmpdir(), `herdctl-test-${Date.now()}`);
171
+ await mkdir(testDir, { recursive: true });
172
+ });
173
+ afterEach(async () => {
174
+ vi.unstubAllGlobals();
175
+ await rm(testDir, { recursive: true, force: true });
176
+ });
177
+ const defaultConfig = DiscordAttachmentsSchema.parse({ enabled: true });
178
+ function makeAttachment(overrides = {}) {
179
+ return {
180
+ id: "att_1",
181
+ name: "test.txt",
182
+ url: "https://cdn.discordapp.com/attachments/test.txt",
183
+ contentType: "text/plain",
184
+ size: 100,
185
+ category: "text",
186
+ ...overrides,
187
+ };
188
+ }
189
+ it("skips attachments not in allowed_types", async () => {
190
+ const config = DiscordAttachmentsSchema.parse({
191
+ enabled: true,
192
+ allowed_types: ["image/*"],
193
+ });
194
+ const attachment = makeAttachment({ contentType: "text/plain", category: "text" });
195
+ const result = await processAttachments([attachment], config, testDir, mockLogger);
196
+ expect(result.promptSections).toHaveLength(0);
197
+ expect(result.skippedFiles).toHaveLength(1);
198
+ expect(result.skippedFiles[0].reason).toContain("not in allowed_types");
199
+ });
200
+ it("skips attachments exceeding size limit", async () => {
201
+ const config = DiscordAttachmentsSchema.parse({
202
+ enabled: true,
203
+ max_file_size_mb: 1,
204
+ });
205
+ const attachment = makeAttachment({
206
+ size: 2 * 1024 * 1024, // 2MB
207
+ });
208
+ const result = await processAttachments([attachment], config, testDir, mockLogger);
209
+ expect(result.promptSections).toHaveLength(0);
210
+ expect(result.skippedFiles).toHaveLength(1);
211
+ expect(result.skippedFiles[0].reason).toContain("exceeds");
212
+ });
213
+ it("limits files to max_files_per_message", async () => {
214
+ const config = DiscordAttachmentsSchema.parse({
215
+ enabled: true,
216
+ max_files_per_message: 2,
217
+ });
218
+ const attachments = [
219
+ makeAttachment({ id: "1", name: "a.txt" }),
220
+ makeAttachment({ id: "2", name: "b.txt" }),
221
+ makeAttachment({ id: "3", name: "c.txt" }),
222
+ ];
223
+ // Mock fetch for text attachments
224
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
225
+ ok: true,
226
+ text: async () => "content",
227
+ }));
228
+ const result = await processAttachments(attachments, config, testDir, mockLogger);
229
+ // Only first 2 should be processed, 3rd should be skipped
230
+ expect(result.skippedFiles).toContainEqual(expect.objectContaining({ name: "c.txt", reason: "exceeded max_files_per_message" }));
231
+ vi.unstubAllGlobals();
232
+ });
233
+ it("inlines text file content into prompt", async () => {
234
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
235
+ ok: true,
236
+ text: async () => "hello world",
237
+ }));
238
+ const attachment = makeAttachment({ name: "script.py", contentType: "text/x-python" });
239
+ const result = await processAttachments([attachment], defaultConfig, testDir, mockLogger);
240
+ expect(result.promptSections).toHaveLength(1);
241
+ expect(result.promptSections[0]).toContain("--- File: script.py (text/x-python) ---");
242
+ expect(result.promptSections[0]).toContain("hello world");
243
+ expect(result.promptSections[0]).toContain("--- End of script.py ---");
244
+ expect(result.downloadedPaths).toHaveLength(0);
245
+ vi.unstubAllGlobals();
246
+ });
247
+ it("truncates large text files", async () => {
248
+ const largeContent = "x".repeat(60_000);
249
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
250
+ ok: true,
251
+ text: async () => largeContent,
252
+ }));
253
+ const attachment = makeAttachment();
254
+ const result = await processAttachments([attachment], defaultConfig, testDir, mockLogger);
255
+ expect(result.promptSections).toHaveLength(1);
256
+ expect(result.promptSections[0]).toContain("truncated at 50000 chars");
257
+ vi.unstubAllGlobals();
258
+ });
259
+ it("downloads images to disk and returns file path in prompt", async () => {
260
+ const imageData = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);
261
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
262
+ ok: true,
263
+ arrayBuffer: async () => imageData.buffer.slice(imageData.byteOffset, imageData.byteOffset + imageData.byteLength),
264
+ }));
265
+ const attachment = makeAttachment({
266
+ name: "screenshot.png",
267
+ contentType: "image/png",
268
+ category: "image",
269
+ });
270
+ const result = await processAttachments([attachment], defaultConfig, testDir, mockLogger);
271
+ expect(result.promptSections).toHaveLength(1);
272
+ expect(result.promptSections[0]).toContain("[Image attached:");
273
+ expect(result.promptSections[0]).toContain("att_1-screenshot.png");
274
+ expect(result.promptSections[0]).toContain("Use the Read tool");
275
+ expect(result.downloadedPaths).toHaveLength(1);
276
+ expect(basename(result.downloadedPaths[0])).toBe("att_1-screenshot.png");
277
+ // Verify file was actually written
278
+ const fileContents = await readFile(result.downloadedPaths[0]);
279
+ expect(Buffer.from(fileContents)).toEqual(Buffer.from(imageData));
280
+ vi.unstubAllGlobals();
281
+ });
282
+ it("downloads PDFs to disk and returns file path in prompt", async () => {
283
+ const pdfData = Buffer.from("%PDF-1.4");
284
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
285
+ ok: true,
286
+ arrayBuffer: async () => pdfData.buffer,
287
+ }));
288
+ const attachment = makeAttachment({
289
+ name: "document.pdf",
290
+ contentType: "application/pdf",
291
+ category: "pdf",
292
+ });
293
+ const result = await processAttachments([attachment], defaultConfig, testDir, mockLogger);
294
+ expect(result.promptSections).toHaveLength(1);
295
+ expect(result.promptSections[0]).toContain("[PDF attached:");
296
+ expect(result.promptSections[0]).toContain("att_1-document.pdf");
297
+ expect(result.downloadedPaths).toHaveLength(1);
298
+ expect(basename(result.downloadedPaths[0])).toBe("att_1-document.pdf");
299
+ vi.unstubAllGlobals();
300
+ });
301
+ it("skips binary attachments when no working directory", async () => {
302
+ const attachment = makeAttachment({
303
+ name: "photo.jpg",
304
+ contentType: "image/jpeg",
305
+ category: "image",
306
+ });
307
+ const result = await processAttachments([attachment], defaultConfig, undefined, mockLogger);
308
+ expect(result.promptSections).toHaveLength(0);
309
+ expect(result.skippedFiles).toHaveLength(1);
310
+ expect(result.skippedFiles[0].reason).toContain("no working_directory");
311
+ });
312
+ it("handles fetch failures gracefully", async () => {
313
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
314
+ ok: false,
315
+ status: 404,
316
+ }));
317
+ const attachment = makeAttachment();
318
+ const result = await processAttachments([attachment], defaultConfig, testDir, mockLogger);
319
+ expect(result.promptSections).toHaveLength(0);
320
+ expect(result.skippedFiles).toHaveLength(1);
321
+ expect(result.skippedFiles[0].reason).toContain("download/processing failed");
322
+ expect(mockLogger.warn).toHaveBeenCalled();
323
+ vi.unstubAllGlobals();
324
+ });
325
+ it("handles network errors gracefully", async () => {
326
+ vi.stubGlobal("fetch", vi.fn().mockRejectedValue(new Error("Network error")));
327
+ const attachment = makeAttachment();
328
+ const result = await processAttachments([attachment], defaultConfig, testDir, mockLogger);
329
+ expect(result.promptSections).toHaveLength(0);
330
+ expect(result.skippedFiles).toHaveLength(1);
331
+ expect(result.skippedFiles[0].reason).toContain("Network error");
332
+ vi.unstubAllGlobals();
333
+ });
334
+ it("uses different download directories across attachment runs", async () => {
335
+ const imageData = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);
336
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
337
+ ok: true,
338
+ arrayBuffer: async () => imageData.buffer.slice(imageData.byteOffset, imageData.byteOffset + imageData.byteLength),
339
+ }));
340
+ const first = await processAttachments([
341
+ makeAttachment({
342
+ id: "run1",
343
+ name: "one.png",
344
+ contentType: "image/png",
345
+ category: "image",
346
+ }),
347
+ ], defaultConfig, testDir, mockLogger);
348
+ const second = await processAttachments([
349
+ makeAttachment({
350
+ id: "run2",
351
+ name: "two.png",
352
+ contentType: "image/png",
353
+ category: "image",
354
+ }),
355
+ ], defaultConfig, testDir, mockLogger);
356
+ expect(first.downloadedPaths).toHaveLength(1);
357
+ expect(second.downloadedPaths).toHaveLength(1);
358
+ expect(dirname(first.downloadedPaths[0])).not.toBe(dirname(second.downloadedPaths[0]));
359
+ vi.unstubAllGlobals();
360
+ });
361
+ it("preserves both binary attachments when filenames are duplicated", async () => {
362
+ const firstPayload = Buffer.from("first");
363
+ const secondPayload = Buffer.from("second");
364
+ vi.stubGlobal("fetch", vi
365
+ .fn()
366
+ .mockResolvedValueOnce({
367
+ ok: true,
368
+ arrayBuffer: async () => firstPayload.buffer.slice(firstPayload.byteOffset, firstPayload.byteOffset + firstPayload.byteLength),
369
+ })
370
+ .mockResolvedValueOnce({
371
+ ok: true,
372
+ arrayBuffer: async () => secondPayload.buffer.slice(secondPayload.byteOffset, secondPayload.byteOffset + secondPayload.byteLength),
373
+ }));
374
+ const duplicatedName = "same-name.png";
375
+ const attachments = [
376
+ makeAttachment({
377
+ id: "att_101",
378
+ name: duplicatedName,
379
+ contentType: "image/png",
380
+ category: "image",
381
+ }),
382
+ makeAttachment({
383
+ id: "att_202",
384
+ name: duplicatedName,
385
+ contentType: "image/png",
386
+ category: "image",
387
+ }),
388
+ ];
389
+ const result = await processAttachments(attachments, defaultConfig, testDir, mockLogger);
390
+ expect(result.downloadedPaths).toHaveLength(2);
391
+ expect(result.downloadedPaths[0]).not.toBe(result.downloadedPaths[1]);
392
+ expect(basename(result.downloadedPaths[0])).toBe("att_101-same-name.png");
393
+ expect(basename(result.downloadedPaths[1])).toBe("att_202-same-name.png");
394
+ const firstBytes = await readFile(result.downloadedPaths[0]);
395
+ const secondBytes = await readFile(result.downloadedPaths[1]);
396
+ expect(Buffer.from(firstBytes)).toEqual(firstPayload);
397
+ expect(Buffer.from(secondBytes)).toEqual(secondPayload);
398
+ vi.unstubAllGlobals();
399
+ });
400
+ });
401
+ // =============================================================================
402
+ // cleanupAttachments Tests
403
+ // =============================================================================
404
+ describe("cleanupAttachments", () => {
405
+ const cleanupAttachments = ManagerAny.cleanupAttachments.bind(ManagerAny);
406
+ const mockLogger = {
407
+ debug: vi.fn(),
408
+ info: vi.fn(),
409
+ warn: vi.fn(),
410
+ error: vi.fn(),
411
+ };
412
+ let testDir;
413
+ beforeEach(async () => {
414
+ vi.clearAllMocks();
415
+ testDir = join(tmpdir(), `herdctl-cleanup-${Date.now()}`);
416
+ await mkdir(testDir, { recursive: true });
417
+ });
418
+ afterEach(async () => {
419
+ await rm(testDir, { recursive: true, force: true });
420
+ });
421
+ it("removes downloaded files and empty parent directories", async () => {
422
+ const subDir = join(testDir, "timestamp123");
423
+ await mkdir(subDir, { recursive: true });
424
+ const filePath = join(subDir, "test.png");
425
+ await import("node:fs/promises").then((fs) => fs.writeFile(filePath, "data"));
426
+ await cleanupAttachments([filePath], mockLogger);
427
+ // File should be gone
428
+ await expect(stat(filePath)).rejects.toThrow();
429
+ // Parent timestamp dir should also be gone
430
+ await expect(stat(subDir)).rejects.toThrow();
431
+ });
432
+ it("handles missing files gracefully", async () => {
433
+ const nonexistent = join(testDir, "nope.txt");
434
+ // Should not throw
435
+ await cleanupAttachments([nonexistent], mockLogger);
436
+ expect(mockLogger.debug).toHaveBeenCalled();
437
+ });
438
+ });
439
+ //# sourceMappingURL=attachments.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments.test.js","sourceRoot":"","sources":["../../src/__tests__/attachments.test.ts"],"names":[],"mappings":"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"}
@@ -95,9 +95,12 @@ function createMockDiscordConfig() {
95
95
  tool_results: true,
96
96
  tool_result_max_length: 900,
97
97
  system_status: true,
98
- result_summary: false,
98
+ result_summary: true,
99
99
  typing_indicator: true,
100
100
  errors: true,
101
+ acknowledge_emoji: "eyes",
102
+ assistant_messages: "answers",
103
+ progress_indicator: true,
101
104
  },
102
105
  guilds: [
103
106
  {