nexus/.planning/milestones/v1.3-phases/25-file-system/25-04-PLAN.md
Nexus Dev ffc7b130e4 chore: archive v1.3 phase directories to milestones/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:48 +00:00

8.6 KiB

phase plan type wave depends_on files_modified autonomous gap_closure requirements must_haves
25-file-system 04 execute 1
25-03
ui/src/components/ChatFilePreview.tsx
ui/src/components/ChatCodeFilePreview.tsx
.planning/REQUIREMENTS.md
true true
FILE-06
FILE-07
FILE-13
truths artifacts key_links
Code files attached to messages render with syntax highlighting in the chat
FILE-07 and FILE-13 are marked Complete in REQUIREMENTS.md
path provides min_lines
ui/src/components/ChatCodeFilePreview.tsx Syntax-highlighted code file preview component 40
path provides
ui/src/components/ChatFilePreview.tsx Updated preview that delegates code files to ChatCodeFilePreview
from to via pattern
ui/src/components/ChatFilePreview.tsx ui/src/components/ChatCodeFilePreview.tsx import and render for code category ChatCodeFilePreview
from to via pattern
ui/src/components/ChatCodeFilePreview.tsx /api/files/:fileId/content fetch to load file text content fetch.*content
Add syntax-highlighted code file preview to chat messages and close administrative requirement gaps.

Purpose: FILE-06 requires "code files show a syntax-highlighted preview" but ChatFilePreview currently renders only a ChatFileCard for code files. This plan fetches code file content via the existing GET /api/files/:fileId/content endpoint and renders it with highlight.js (already installed and used by ChatMarkdownMessage via rehype-highlight). Also formally marks FILE-07 (download) and FILE-13 (cross-device access) as Complete since they are functionally implemented.

Output: ChatCodeFilePreview component, updated ChatFilePreview, updated REQUIREMENTS.md

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/25-file-system/25-03-SUMMARY.md Task 1: Create ChatCodeFilePreview component ui/src/components/ChatCodeFilePreview.tsx - ui/src/components/ChatFilePreview.tsx - ui/src/components/ChatCodeBlock.tsx - ui/src/components/ChatMarkdownMessage.tsx - ui/src/index.css (for hljs theme CSS classes) Create `ui/src/components/ChatCodeFilePreview.tsx` that:
  1. Accepts props: { file: ChatFile; contentPath: string } (same as ChatFilePreview)
  2. Uses useState for content: string | null, loading: boolean, error: boolean
  3. Uses useEffect to fetch contentPath with credentials: "include" and read as text. Cap at 50KB (if text.length > 50000, truncate and append \n// ... truncated). Set loading=false after fetch.
  4. While loading, render a skeleton: <div className="rounded-lg border border-border bg-muted animate-pulse h-[120px]" />
  5. On error, fall back to <ChatFileCard file={file} contentPath={contentPath} />
  6. On success, render:
    • A <div className="paperclip-markdown rounded-lg border border-border overflow-hidden"> wrapper (the paperclip-markdown class activates existing hljs theme CSS)
    • A header bar: <div className="flex items-center justify-between bg-card border-b border-border px-3 py-1"> with:
      • Language label from file extension (use extToLang mapping function)
      • Copy button using same pattern as ChatCodeBlock (Copy/Check icons from lucide-react, navigator.clipboard.writeText)
    • A <pre><code> block. Use hljs.highlight(content, { language: lang }) from highlight.js/lib/core to produce highlighted HTML. Render the highlighted output safely. hljs.highlight produces only <span class="hljs-..."> tokens from source code — this is the same trust model as rehype-highlight used in ChatMarkdownMessage. If the language is not registered, fall back to hljs.highlightAuto(content).
    • Max height: max-h-[400px] overflow-auto
    • Below the code block, render <ChatFileCard file={file} contentPath={contentPath} /> for the download button

Import highlight.js: import hljs from "highlight.js/lib/core". Since rehype-highlight already uses highlight.js, the package is available. Register common languages explicitly (import from highlight.js/lib/languages/...) for: typescript, javascript, python, css, json, xml, bash, sql, go, rust, java, cpp, markdown, yaml.

Extension-to-language map function:

function extToLang(filename: string): string {
  const ext = filename.split(".").pop()?.toLowerCase() ?? "";
  const map: Record<string, string> = {
    ts: "typescript", tsx: "typescript", js: "javascript", jsx: "javascript",
    py: "python", rb: "ruby", rs: "rust", go: "go", java: "java",
    css: "css", html: "xml", json: "json", sh: "bash", bash: "bash",
    yaml: "yaml", yml: "yaml", toml: "ini", md: "markdown",
    c: "c", cpp: "cpp", cs: "csharp", kt: "kotlin", swift: "swift",
    php: "php", sql: "sql", xml: "xml",
  };
  return map[ext] ?? ext;
}
cd /opt/nexus && npx tsc --noEmit -p ui/tsconfig.json 2>&1 | head -20 - File `ui/src/components/ChatCodeFilePreview.tsx` exists - Contains `import hljs from` for highlight.js - Contains `fetch(contentPath` for loading file content - Contains `hljs.highlight` for rendering highlighted code - Contains `paperclip-markdown` class on wrapper div - Contains `ChatFileCard` import and render for download fallback - Contains `max-h-[400px]` for scroll containment - Contains `extToLang` or equivalent extension mapping function ChatCodeFilePreview component renders fetched code content with syntax highlighting, copy button, language label, and download card Task 2: Wire ChatCodeFilePreview into ChatFilePreview and update REQUIREMENTS.md ui/src/components/ChatFilePreview.tsx, .planning/REQUIREMENTS.md - ui/src/components/ChatFilePreview.tsx - ui/src/components/ChatCodeFilePreview.tsx - .planning/REQUIREMENTS.md 1. Update `ui/src/components/ChatFilePreview.tsx`: - Add import: `import { ChatCodeFilePreview } from "./ChatCodeFilePreview";` - Add a new branch before the fallback return, after the image branch: ``` if (file.category === "code") { return ; } ``` - Keep the existing fallback `return ` for document/other categories
  1. Update .planning/REQUIREMENTS.md:
    • Change FILE-07 line from - [ ] **FILE-07** to - [x] **FILE-07** (ChatFileCard implements one-click download)
    • Change FILE-13 line from - [ ] **FILE-13** to - [x] **FILE-13** (GET /api/files/:fileId/content serves files over HTTP for cross-device access)
    • In the Traceability table, change FILE-07 status from Pending to Complete
    • In the Traceability table, change FILE-13 status from Pending to Complete cd /opt/nexus && grep -n "ChatCodeFilePreview" ui/src/components/ChatFilePreview.tsx && grep "FILE-07" .planning/REQUIREMENTS.md | head -3 && grep "FILE-13" .planning/REQUIREMENTS.md | head -3 <acceptance_criteria>
    • ui/src/components/ChatFilePreview.tsx contains import { ChatCodeFilePreview }
    • ui/src/components/ChatFilePreview.tsx contains file.category === "code" branch routing to ChatCodeFilePreview
    • .planning/REQUIREMENTS.md contains - [x] **FILE-07**
    • .planning/REQUIREMENTS.md contains - [x] **FILE-13**
    • REQUIREMENTS.md Traceability table shows FILE-07 as Complete
    • REQUIREMENTS.md Traceability table shows FILE-13 as Complete </acceptance_criteria> Code files in chat messages render with syntax highlighting; FILE-07 and FILE-13 marked Complete in REQUIREMENTS.md
- `npx tsc --noEmit -p ui/tsconfig.json` passes - `grep "ChatCodeFilePreview" ui/src/components/ChatFilePreview.tsx` shows import and usage - `grep "\[x\].*FILE-07" .planning/REQUIREMENTS.md` matches - `grep "\[x\].*FILE-13" .planning/REQUIREMENTS.md` matches

<success_criteria>

  • Code file attachments in chat render with syntax-highlighted preview (not just a download card)
  • FILE-07 and FILE-13 marked Complete in REQUIREMENTS.md
  • TypeScript compiles without errors </success_criteria>
After completion, create `.planning/phases/25-file-system/25-04-SUMMARY.md`