174 lines
8.6 KiB
Markdown
174 lines
8.6 KiB
Markdown
---
|
|
phase: 25-file-system
|
|
plan: 04
|
|
type: execute
|
|
wave: 1
|
|
depends_on: ["25-03"]
|
|
files_modified:
|
|
- ui/src/components/ChatFilePreview.tsx
|
|
- ui/src/components/ChatCodeFilePreview.tsx
|
|
- .planning/REQUIREMENTS.md
|
|
autonomous: true
|
|
gap_closure: true
|
|
requirements: [FILE-06, FILE-07, FILE-13]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "Code files attached to messages render with syntax highlighting in the chat"
|
|
- "FILE-07 and FILE-13 are marked Complete in REQUIREMENTS.md"
|
|
artifacts:
|
|
- path: "ui/src/components/ChatCodeFilePreview.tsx"
|
|
provides: "Syntax-highlighted code file preview component"
|
|
min_lines: 40
|
|
- path: "ui/src/components/ChatFilePreview.tsx"
|
|
provides: "Updated preview that delegates code files to ChatCodeFilePreview"
|
|
key_links:
|
|
- from: "ui/src/components/ChatFilePreview.tsx"
|
|
to: "ui/src/components/ChatCodeFilePreview.tsx"
|
|
via: "import and render for code category"
|
|
pattern: "ChatCodeFilePreview"
|
|
- from: "ui/src/components/ChatCodeFilePreview.tsx"
|
|
to: "/api/files/:fileId/content"
|
|
via: "fetch to load file text content"
|
|
pattern: "fetch.*content"
|
|
---
|
|
|
|
<objective>
|
|
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
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
|
@$HOME/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/25-file-system/25-03-SUMMARY.md
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create ChatCodeFilePreview component</name>
|
|
<files>ui/src/components/ChatCodeFilePreview.tsx</files>
|
|
<read_first>
|
|
- ui/src/components/ChatFilePreview.tsx
|
|
- ui/src/components/ChatCodeBlock.tsx
|
|
- ui/src/components/ChatMarkdownMessage.tsx
|
|
- ui/src/index.css (for hljs theme CSS classes)
|
|
</read_first>
|
|
<action>
|
|
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:
|
|
```typescript
|
|
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;
|
|
}
|
|
```
|
|
</action>
|
|
<verify>
|
|
<automated>cd /opt/nexus && npx tsc --noEmit -p ui/tsconfig.json 2>&1 | head -20</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- 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
|
|
</acceptance_criteria>
|
|
<done>ChatCodeFilePreview component renders fetched code content with syntax highlighting, copy button, language label, and download card</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Wire ChatCodeFilePreview into ChatFilePreview and update REQUIREMENTS.md</name>
|
|
<files>ui/src/components/ChatFilePreview.tsx, .planning/REQUIREMENTS.md</files>
|
|
<read_first>
|
|
- ui/src/components/ChatFilePreview.tsx
|
|
- ui/src/components/ChatCodeFilePreview.tsx
|
|
- .planning/REQUIREMENTS.md
|
|
</read_first>
|
|
<action>
|
|
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 <ChatCodeFilePreview file={file} contentPath={contentPath} />;
|
|
}
|
|
```
|
|
- Keep the existing fallback `return <ChatFileCard ... />` for document/other categories
|
|
|
|
2. 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`
|
|
</action>
|
|
<verify>
|
|
<automated>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</automated>
|
|
</verify>
|
|
<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>
|
|
<done>Code files in chat messages render with syntax highlighting; FILE-07 and FILE-13 marked Complete in REQUIREMENTS.md</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `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
|
|
</verification>
|
|
|
|
<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>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/25-file-system/25-04-SUMMARY.md`
|
|
</output>
|