From 008eae54112c65e2cf92d0891e2a160457c0b746 Mon Sep 17 00:00:00 2001 From: Thomas Brugman Date: Sun, 26 Jul 2026 16:18:32 +0200 Subject: [PATCH] fix(ui): preserve parenthesized tildes in markdown --- .changeset/fuzzy-tildes-smile.md | 5 ++++ packages/ui/src/context/marked.tsx | 11 ++++++++ .../kilocode/markdown-strikethrough.test.ts | 26 +++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 .changeset/fuzzy-tildes-smile.md create mode 100644 packages/ui/src/kilocode/markdown-strikethrough.test.ts diff --git a/.changeset/fuzzy-tildes-smile.md b/.changeset/fuzzy-tildes-smile.md new file mode 100644 index 00000000000..39c76209f86 --- /dev/null +++ b/.changeset/fuzzy-tildes-smile.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Preserve parenthesized tilde expressions as literal text in rendered chat messages. diff --git a/packages/ui/src/context/marked.tsx b/packages/ui/src/context/marked.tsx index 050b7005264..33af8ff08e2 100644 --- a/packages/ui/src/context/marked.tsx +++ b/packages/ui/src/context/marked.tsx @@ -321,6 +321,17 @@ export const createMarkedParser = (props: { nativeParser?: NativeMarkdownParser }, // kilocode_change end }, + // kilocode_change start: Marked accepts a tilde preceded by an opening + // parenthesis as the closing delimiter. It is left-flanking there, so + // preserve it literally instead of corrupting text such as "(~1 GB)". + tokenizer: { + del(src) { + const match = this.rules.inline.del.exec(src) + if (match?.[0].at(-2) === "(") return + return false + }, + }, + // kilocode_change end }, // kilocode_change start: enable only double-dollar math. // Single $ is far more common as a currency symbol in agent responses diff --git a/packages/ui/src/kilocode/markdown-strikethrough.test.ts b/packages/ui/src/kilocode/markdown-strikethrough.test.ts new file mode 100644 index 00000000000..3ef4c42e51c --- /dev/null +++ b/packages/ui/src/kilocode/markdown-strikethrough.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, test } from "bun:test" +import { createMarkedParser } from "../context/marked" + +describe("Markdown strikethrough boundaries", () => { + test.each(["(~a (~b", "~a (~b", "(~24 GB) and (~5.7 GB)", "(~/.config) and (~/.cache)"])( + "preserves parenthesized tildes in %s", + async (text) => { + const parser = createMarkedParser({}) + const html = await Promise.resolve(parser.parse(text)) + + expect(html).not.toContain("") + expect(html).toContain(text) + }, + ) + + test.each([ + ["~removed~", "removed"], + ["~~removed~~", "removed"], + ["(~removed~)", "(removed)"], + ])("keeps valid strikethrough syntax in %s", async (text, expected) => { + const parser = createMarkedParser({}) + const html = await Promise.resolve(parser.parse(text)) + + expect(html).toContain(expected) + }) +})