diff --git a/src/discord/split.ts b/src/discord/split.ts index 154b325..2c2515d 100644 --- a/src/discord/split.ts +++ b/src/discord/split.ts @@ -28,6 +28,12 @@ export function splitForDiscord(text: string, limit = 1900): string[] { let fenceLang = ""; const flush = () => { + // Hard-split if current exceeds the Discord hard limit (e.g. because + // a fence closure "\n```" was appended after the soft-limit check). + while (current.length > DISCORD_HARD_LIMIT) { + chunks.push(current.slice(0, DISCORD_HARD_LIMIT)); + current = current.slice(DISCORD_HARD_LIMIT); + } if (current.length > 0) { chunks.push(current); current = ""; @@ -43,7 +49,10 @@ export function splitForDiscord(text: string, limit = 1900): string[] { const separator = current.length > 0 ? "\n" : ""; const addition = separator + line; - if (current.length + addition.length > effectiveLimit) { + // Reserve space for a closing fence (``` + newline) when inside a code block + const fenceOverhead = inFence ? 4 : 0; // "\n```".length + + if (current.length + addition.length + fenceOverhead > effectiveLimit) { // Need to flush before adding this line if (inFence) { // Close the open fence before flushing diff --git a/tests/unit/split-for-discord.test.ts b/tests/unit/split-for-discord.test.ts index c7baeed..507e520 100644 --- a/tests/unit/split-for-discord.test.ts +++ b/tests/unit/split-for-discord.test.ts @@ -101,4 +101,20 @@ describe("splitForDiscord", () => { const idx = result.indexOf(closingChunk!); expect(result[idx + 1]).toMatch(/^```python/); }); + + // Regression: fence closure "\n```" must not push a chunk beyond the 2000 hard limit + it("does not exceed 2000 chars even when fence closure is appended at limit boundary", () => { + const fenceOpen = "```typescript\n"; + // Line long enough that current is near 2000 when fence closure is added + const longLine = "x".repeat(1984); + const nextLine = "y".repeat(10); + const fenceClose = "\n```"; + + const text = fenceOpen + longLine + "\n" + nextLine + fenceClose; + const result = splitForDiscord(text, 2000); + + for (const chunk of result) { + expect(chunk.length).toBeLessThanOrEqual(DISCORD_HARD_LIMIT); + } + }); });