Skip to content

feat(bridge): render markdown in the Windows tray meeting-summary window#178

Open
Vortiago wants to merge 2 commits into
mainfrom
hidden-floating-riddle
Open

feat(bridge): render markdown in the Windows tray meeting-summary window#178
Vortiago wants to merge 2 commits into
mainfrom
hidden-floating-riddle

Conversation

@Vortiago

Copy link
Copy Markdown
Owner

Why

The Windows tray bridge's per-meeting window showed the LLM summary in a read-only TextBox, so the raw markdown (## Decisions, - bullet, **owner**, `api/tap`) appeared as literal markup — hard to read. The backend serves the summary as raw markdown (it never pre-renders HTML), and the web dashboard already renders a small, deliberately-minimal markdown subset. This brings the same readability to the tray window.

What

  • SummaryMarkdown (TapScribe.Bridge.Core, net10.0, no WinForms): a pure parser of the same subset the web renderMarkdown/_inlineMd supports — ####### headings, -/* bullets, 1./1) numbered (renumbered sequentially), fenced ``` code blocks (verbatim), paragraphs, and inline `code`/`bold`/`italic` (flat, no nesting). Includes a `Plain()` wrapper for non-markdown status/failure lines. Exhaustively unit-tested on the Linux/CI cross-platform job.
  • SummaryRichText (TapScribe.TrayBridge): paints the block model onto a read-only RichTextBox with native styled runs — heading fonts, bullet/number prefixes, bold/italic, monospace code. No new dependency, no WebView2 runtime (a plain static helper, not a Control subclass, so it never trips WFO1000).
  • MeetingFormView gains a BodyIsMarkdown signal (true only for the Done summary) so the dumb WinForms shell routes markdown-vs-plain explicitly and a raw recorder error line can't be reinterpreted as markdown.
  • MeetingForm: TextBoxRichTextBox; Copy now yields the raw markdown source (clean to paste into markdown-aware tools); the per-tick Apply re-renders only when the body actually changes.

Design notes

  • The markdown subset deliberately mirrors the web renderer (tapscribe/web/js/templates.js) so the two stay in conceptual sync; they remain independent JS/C# implementations (no shared code across the boundary).
  • Parsing lives in the cross-platform, unit-tested Core; the WinForms shell stays a dumb projection — matching the PipelineView/StatusView/MeetingFormView pattern.
  • RichTextBox chosen over WebView2 to avoid a runtime dependency for a deliberately tiny markdown subset.

Testing

  • dotnet test tests/TapScribe.Bridge.Core.Tests — 250 pass (new SummaryMarkdownTests + MeetingFormView BodyIsMarkdown assertions; existing tests unchanged). Mirrors the CI ubuntu cross-platform job.
  • dotnet build TapScribe.WindowsTrayBridge.slnx -c Release -p:EnableWindowsTargeting=true — clean, 0 warnings (mirrors the Windows compile job).
  • Reviewed with /simplify (reuse/simplification/efficiency/altitude) and /code-review (xhigh).
  • ⚠️ Manual Windows check still needed (GUI can't run on the Linux dev box): end a meeting / re-open a past meeting → summary shows formatted headings, bullets, numbered items, bold/italic, monospace code; Copy puts raw markdown on the clipboard.

🤖 Generated with Claude Code

The per-meeting window showed the LLM summary in a read-only TextBox, so raw
markdown (`## Decisions`, `- bullet`, `**owner**`) appeared as literal markup
and was hard to read. Render it instead, mirroring the web dashboard's minimal
markdown subset.

- SummaryMarkdown (Core, net10.0, no WinForms): pure parser of the same subset
  the web renderMarkdown supports (#..###### headings, -/* bullets, 1./1)
  numbered, fenced code, paragraphs, inline `code`/**bold**/*italic*), plus a
  Plain() wrapper for non-markdown status/failure lines. Exhaustively unit-tested
  on the Linux/CI cross-platform job.
- SummaryRichText (TrayBridge): paints the block model onto a read-only
  RichTextBox with styled runs — no new dependency, no WebView2 runtime.
- MeetingFormView gains a BodyIsMarkdown signal (true only for the Done summary)
  so the shell never reinterprets a plain status / recorder-error line as markdown.
- MeetingForm: TextBox -> RichTextBox; Copy yields the raw markdown source; the
  per-tick Apply re-renders only when the body actually changes.
Replace the per-line trailing-'\r' strip with an up-front Replace("\r\n","\n")
so the loop iterates the normalised line directly. Removes the foreach
loop-variable remap CodeQL flagged (cs/linq/missed-select) and is behaviour-
equivalent — a lone '\r' still stays literal within a line, matching the web
renderer's /\r?\n/ split. The CRLF parse test still pins the equivalence.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants