* fix(markdown): require paired || delimiters for spoiler detection
An unpaired || (odd count across all inline tokens) would open a
spoiler that never closes, causing closeRemainingStyles to extend it
to the end of the text. This made all content after an unpaired ||
appear as hidden/spoiler in Telegram.
Pre-count || delimiters across the entire inline token group and skip
spoiler injection entirely when the count is less than 2 or odd. This
prevents single | characters and unpaired || from triggering spoiler
formatting.
Closes#26068
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: preserve valid spoiler pairs with trailing unmatched delimiters (#26105) (thanks @Sid-Qin)
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
YAML 1.1 default schema silently coerces values like "on" to true and
"off" to false, which can cause unexpected behavior in frontmatter
parsing. Explicitly set schema: "core" to use YAML 1.2 rules that
only recognize true/false/null literals.
* fix: Signal and markdown formatting improvements
Markdown IR fixes:
- Fix list-paragraph spacing (extra newline between list items and following paragraphs)
- Fix nested list indentation and newline handling
- Fix blockquote_close emitting redundant newline (inner content handles spacing)
- Render horizontal rules as visible ─── separator instead of silent drop
- Strip inner cell styles in code-mode tables to prevent overlapping with code_block span
Signal formatting fixes:
- Normalize URLs for dedup comparison (strip protocol, www., trailing slash)
- Render headings as bold text (headingStyle: 'bold')
- Add '> ' prefix to blockquotes for visual distinction
- Re-chunk after link expansion to respect chunk size limits
Tests:
- 51 new tests for markdown IR (spacing, lists, blockquotes, tables, HR)
- 18 new tests for Signal formatting (URL dedup, headings, blockquotes, HR, chunking)
- Update Slack nested list test expectation to match corrected IR output
* refactor: style-aware Signal text chunker
Replace indexOf-based chunk position tracking with deterministic
cursor tracking. The new splitSignalFormattedText:
- Splits at whitespace/newline boundaries within the limit
- Avoids breaking inside parentheses (preserves expanded link URLs)
- Slices style ranges at chunk boundaries with correct local offsets
- Tracks position via offset arithmetic instead of fragile indexOf
Removes dependency on chunkText from auto-reply/chunk.
Tests: 19 new tests covering style preservation across chunk boundaries,
edge cases (empty text, under limit, exact split points), and integration
with link expansion.
* fix: correct Signal style offsets with multiple link expansions
applyInsertionsToStyles() was using original coordinates for each
insertion without tracking cumulative shift from prior insertions.
This caused bold/italic/etc styles to drift to wrong text positions
when multiple markdown links expanded in a single message.
Added cumulative shift tracking and a regression test.
* test: clean up test noise and fix ineffective assertions
- Remove console.log from ir.list-spacing and ir.hr-spacing tests
- Fix ir.nested-lists.test.ts: remove ineffective regex assertion
- Fix ir.hr-spacing.test.ts: add actual assertions to edge case test
* refactor: split Signal formatting tests (#9781) (thanks @heyhudson)
---------
Co-authored-by: Hudson <258693705+hudson-rivera@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(whatsapp): convert Markdown bold/strikethrough to WhatsApp formatting
* refactor: Move `escapeRegExp` utility function to `utils.js`.
---------
Co-authored-by: Luna AI <luna@coredirection.ai>
Unify style and link closing in render.ts to use LIFO order across
both element types, fixing cases where bold/italic spans containing
autolinks produced invalid HTML like <b><a></b></a>.
Tables render poorly in Telegram (pipes stripped, whitespace collapses).
This adds a 'tableMode' option to markdownToIR that converts tables to
nested bullet points, which render cleanly on mobile.
- Add tableMode: 'flat' | 'bullets' to MarkdownParseOptions
- Track table state during token rendering
- Render tables as bullet points with first column as row labels
- Apply bold styling to row labels for visual hierarchy
- Enable tableMode: 'bullets' for Telegram formatter
Closes #TBD