diff --git a/src/utils/slashCommands/compact.test.ts b/src/utils/slashCommands/compact.test.ts index 387b61d9f9..76a69c35bd 100644 --- a/src/utils/slashCommands/compact.test.ts +++ b/src/utils/slashCommands/compact.test.ts @@ -214,4 +214,23 @@ describe("multiline continue messages", () => { continueMessage: undefined, }); }); + + it("does not parse lines after newline as flags", () => { + // Bug: multiline content starting with -t or -c should not be parsed as flags + const result = parseCommand("/compact\n-t should be treated as message content"); + expect(result).toEqual({ + type: "compact", + maxOutputTokens: undefined, + continueMessage: "-t should be treated as message content", + }); + }); + + it("does not parse lines after newline as flags with existing flag", () => { + const result = parseCommand("/compact -t 5000\n-c this is not a flag"); + expect(result).toEqual({ + type: "compact", + maxOutputTokens: 5000, + continueMessage: "-c this is not a flag", + }); + }); }); diff --git a/src/utils/slashCommands/registry.ts b/src/utils/slashCommands/registry.ts index a2a95bfae2..1f0a71a66d 100644 --- a/src/utils/slashCommands/registry.ts +++ b/src/utils/slashCommands/registry.ts @@ -171,16 +171,22 @@ const compactCommandDefinition: SlashCommandDefinition = { key: "compact", description: "Compact conversation history using AI summarization. Use -t to set max output tokens. Add continue message on lines after the command.", - handler: ({ cleanRemainingTokens, rawInput }): ParsedCommand => { + handler: ({ rawInput }): ParsedCommand => { // Split rawInput into first line (for flags) and remaining lines (for multiline continue) // rawInput format: "-t 5000\nContinue here" or "\nContinue here" (starts with newline if no flags) const hasMultilineContent = rawInput.includes("\n"); const lines = rawInput.split("\n"); - // Note: firstLine could be empty string if rawInput starts with \n (which is fine) + const firstLine = lines[0]; // First line contains flags const remainingLines = lines.slice(1).join("\n").trim(); + // Tokenize ONLY the first line to extract flags + // This prevents content after newlines from being parsed as flags + const firstLineTokens = (firstLine.match(/(?:[^\s"]+|"[^"]*")+/g) ?? []).map((token) => + token.replace(/^"(.*)"$/, "$1") + ); + // Parse flags from first line using minimist - const parsed = minimist(cleanRemainingTokens, { + const parsed = minimist(firstLineTokens, { string: ["t", "c"], unknown: (arg: string) => { // Unknown flags starting with - are errors @@ -191,8 +197,8 @@ const compactCommandDefinition: SlashCommandDefinition = { }, }); - // Check for unknown flags - const unknownFlags = cleanRemainingTokens.filter( + // Check for unknown flags (only from first line) + const unknownFlags = firstLineTokens.filter( (token) => token.startsWith("-") && token !== "-t" && token !== "-c" ); if (unknownFlags.length > 0) {