5.8 KiB
5.8 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick | 260329-ton | execute | 1 |
|
true |
|
Purpose: AI-generated texts (greetings, letter intros, forest comments) contain Markdown formatting like f for emphasis, but .textContent displays them as plaintext with visible asterisks. Switching to .innerHTML with a safe inline markdown renderer fixes this.
Output: A renderInlineMarkdown() utility function used at all 3 AI-text insertion points.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/STATE.md @src/utils/markdown.ts (will be created) @src/app.ts @src/ui/screens.ts @src/forest/reward.ts Task 1: Create renderInlineMarkdown utility with tests src/utils/markdown.ts, src/utils/markdown.test.ts - renderInlineMarkdown("hello") returns "hello" (plain text unchanged) - renderInlineMarkdown("press *f*") returns "press <em>f</em>" (single asterisks become em) - renderInlineMarkdown("very **important**") returns "very <strong>important</strong>" (double asterisks become strong) - renderInlineMarkdown("**bold** and *italic*") handles both in one string - renderInlineMarkdown("a <script>alert(1)</script>") escapes HTML entities BEFORE markdown processing (XSS safe) - renderInlineMarkdown("2 * 3 * 4") does NOT wrap standalone asterisks with spaces (only wrapping content like *word*) - renderInlineMarkdown("") returns "" (empty string) Create src/utils/markdown.ts exporting a single function renderInlineMarkdown(text: string): string.Implementation approach:
1. First escape HTML special chars: & < > " ' (using string replace chains, no DOM needed)
2. Then apply regex for **bold**: /\*\*(.+?)\*\*/g -> <strong>$1</strong>
3. Then apply regex for *italic*: /\*(.+?)\*/g -> <em>$1</em>
(Order matters: bold first so ** is not consumed as two single *)
No external dependencies. Pure function, no DOM.
Create src/utils/markdown.test.ts with vitest tests covering all behaviors above.
1. src/app.ts line 227:
BEFORE: textEl.textContent = text;
AFTER: textEl.innerHTML = renderInlineMarkdown(text);
2. src/ui/screens.ts line 422:
BEFORE: companionText.textContent = introText;
AFTER: companionText.innerHTML = renderInlineMarkdown(introText);
3. src/forest/reward.ts line 207:
BEFORE: companionTextEl.textContent = comment;
AFTER: companionTextEl.innerHTML = renderInlineMarkdown(comment);
IMPORTANT: Do NOT change any other .textContent assignments in these files. The other assignments use hardcoded German strings (no markdown) or set empty strings. Only the 3 lines above receive AI-generated text that may contain markdown.
<success_criteria>
- AI-generated companion texts with italic or bold markdown render as styled HTML
- Plain text and hardcoded strings are unaffected
- HTML in generated text is escaped (no injection risk)
- All existing tests continue to pass </success_criteria>