docs(25-04): complete syntax-highlighted code preview plan — SUMMARY, STATE, ROADMAP updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b6bb7b2196
commit
3721db0cea
3 changed files with 106 additions and 10 deletions
|
|
@ -116,15 +116,15 @@ Plans:
|
||||||
5. When an agent generates a placeholder asset, `PLACEHOLDERS.md` is updated in the project directory; when the placeholder is replaced, the DB records the replacement chain and the manifest reflects the change
|
5. When an agent generates a placeholder asset, `PLACEHOLDERS.md` is updated in the project directory; when the placeholder is replaced, the DB records the replacement chain and the manifest reflects the change
|
||||||
6. A file uploaded in a conversation linked to a project lives in `files/projects/<slug>/`; a file from an unlinked conversation lives in `files/chat/<conversation-id>/`; the user can promote a chat file to project scope
|
6. A file uploaded in a conversation linked to a project lives in `files/projects/<slug>/`; a file from an unlinked conversation lives in `files/chat/<conversation-id>/`; the user can promote a chat file to project scope
|
||||||
7. Voice input is available when local AI is enabled: user can hold the record button, speak, see a transcription preview, and confirm to send
|
7. Voice input is available when local AI is enabled: user can hold the record button, speak, see a transcription preview, and confirm to send
|
||||||
**Plans:** 5/9 plans executed
|
**Plans:** 7/9 plans executed
|
||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
- [x] 25-00-PLAN.md — DB schema (chat_files + chat_file_references), shared types/validators, test stubs
|
- [x] 25-00-PLAN.md — DB schema (chat_files + chat_file_references), shared types/validators, test stubs
|
||||||
- [x] 25-01-PLAN.md — Server: chatFileService + chatFileRoutes (upload, download, list, references)
|
- [x] 25-01-PLAN.md — Server: chatFileService + chatFileRoutes (upload, download, list, references)
|
||||||
- [x] 25-02-PLAN.md — UI: ChatInput file upload (drag-drop, paste, file picker), useChatFileUpload hook
|
- [x] 25-02-PLAN.md — UI: ChatInput file upload (drag-drop, paste, file picker), useChatFileUpload hook
|
||||||
- [x] 25-03-PLAN.md — UI: ChatFilePreview/ChatFileCard components, ChatMessage/ChatPanel wiring
|
- [x] 25-03-PLAN.md — UI: ChatFilePreview/ChatFileCard components, ChatMessage/ChatPanel wiring
|
||||||
- [ ] 25-04-PLAN.md — Gap: Code syntax-highlighted preview (FILE-06) + admin claims (FILE-07, FILE-13)
|
- [x] 25-04-PLAN.md — Gap: Code syntax-highlighted preview (FILE-06) + admin claims (FILE-07, FILE-13)
|
||||||
- [ ] 25-05-PLAN.md — Gap: File scope promotion API + UI (FILE-12)
|
- [x] 25-05-PLAN.md — Gap: File scope promotion API + UI (FILE-12)
|
||||||
- [ ] 25-06-PLAN.md — Gap: Git integration for file operations + version history (FILE-09, FILE-10)
|
- [ ] 25-06-PLAN.md — Gap: Git integration for file operations + version history (FILE-09, FILE-10)
|
||||||
- [ ] 25-07-PLAN.md — Gap: Agent-generated files + placeholder tracking (FILE-08, FILE-11)
|
- [ ] 25-07-PLAN.md — Gap: Agent-generated files + placeholder tracking (FILE-08, FILE-11)
|
||||||
- [x] 25-08-PLAN.md — Gap: Voice input via Whisper (INPUT-04) + admin claims (INPUT-02, INPUT-03)
|
- [x] 25-08-PLAN.md — Gap: Voice input via Whisper (INPUT-04) + admin claims (INPUT-02, INPUT-03)
|
||||||
|
|
@ -227,5 +227,5 @@ All 65 v1 requirements are mapped to exactly one phase. No orphans.
|
||||||
| 22. Agent Streaming | v1.3 | 6/6 | Complete | 2026-04-01 |
|
| 22. Agent Streaming | v1.3 | 6/6 | Complete | 2026-04-01 |
|
||||||
| 23. Brainstormer Flow | v1.3 | 4/4 | Complete | 2026-04-01 |
|
| 23. Brainstormer Flow | v1.3 | 4/4 | Complete | 2026-04-01 |
|
||||||
| 24. Search, History & Branching | v1.3 | 4/4 | Complete | 2026-04-01 |
|
| 24. Search, History & Branching | v1.3 | 4/4 | Complete | 2026-04-01 |
|
||||||
| 25. File System | v1.3 | 5/9 | In Progress| |
|
| 25. File System | v1.3 | 7/9 | In Progress| |
|
||||||
| 26. PWA & Performance | v1.3 | 0/? | Not started | - |
|
| 26. PWA & Performance | v1.3 | 0/? | Not started | - |
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ gsd_state_version: 1.0
|
||||||
milestone: v1.3
|
milestone: v1.3
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: executing
|
status: executing
|
||||||
stopped_at: Completed 25-file-system-25-08-PLAN.md
|
stopped_at: Completed 25-file-system-25-04-PLAN.md
|
||||||
last_updated: "2026-04-02T00:00:43.784Z"
|
last_updated: "2026-04-02T00:04:47.523Z"
|
||||||
last_activity: 2026-04-02
|
last_activity: 2026-04-02
|
||||||
progress:
|
progress:
|
||||||
total_phases: 6
|
total_phases: 6
|
||||||
completed_phases: 4
|
completed_phases: 4
|
||||||
total_plans: 30
|
total_plans: 30
|
||||||
completed_plans: 26
|
completed_plans: 28
|
||||||
percent: 100
|
percent: 100
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ See: .planning/PROJECT.md (updated 2026-03-30)
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 25 (file-system) — EXECUTING
|
Phase: 25 (file-system) — EXECUTING
|
||||||
Plan: 2 of 9
|
Plan: 3 of 9
|
||||||
Status: Ready to execute
|
Status: Ready to execute
|
||||||
Last activity: 2026-04-02
|
Last activity: 2026-04-02
|
||||||
|
|
||||||
|
|
@ -83,6 +83,7 @@ Progress: [██████████] 100%
|
||||||
| Phase 25-file-system P01 | 15 | 2 tasks | 17 files |
|
| Phase 25-file-system P01 | 15 | 2 tasks | 17 files |
|
||||||
| Phase 25-file-system P03 | 3 | 2 tasks | 7 files |
|
| Phase 25-file-system P03 | 3 | 2 tasks | 7 files |
|
||||||
| Phase 25-file-system P08 | 8 | 2 tasks | 5 files |
|
| Phase 25-file-system P08 | 8 | 2 tasks | 5 files |
|
||||||
|
| Phase 25-file-system P04 | 5min | 2 tasks | 5 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
|
|
@ -150,6 +151,8 @@ Recent decisions affecting current work:
|
||||||
- [Phase 25-file-system]: Use functional setState for transcription append in VoiceRecordButton — avoids stale closure vs native DOM event approach
|
- [Phase 25-file-system]: Use functional setState for transcription append in VoiceRecordButton — avoids stale closure vs native DOM event approach
|
||||||
- [Phase 25-file-system]: enableVoiceInput defaults to false for backward-compat; ChatPanel passes true unconditionally — server returns 503 gracefully if whisper absent
|
- [Phase 25-file-system]: enableVoiceInput defaults to false for backward-compat; ChatPanel passes true unconditionally — server returns 503 gracefully if whisper absent
|
||||||
- [Phase 25-file-system]: execFileAsync over exec for whisper CLI invocation — no shell injection risk with system-generated tmpPath
|
- [Phase 25-file-system]: execFileAsync over exec for whisper CLI invocation — no shell injection risk with system-generated tmpPath
|
||||||
|
- [Phase 25-file-system]: Used DOMParser + replaceChildren to safely render hljs output — avoids raw HTML injection pattern while preserving same visual output as rehype-highlight
|
||||||
|
- [Phase 25-file-system]: highlight.js added as explicit ui/package.json dependency (was transitive via rehype-highlight only)
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
|
|
@ -162,6 +165,6 @@ None yet.
|
||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-02T00:00:43.781Z
|
Last session: 2026-04-02T00:04:47.520Z
|
||||||
Stopped at: Completed 25-file-system-25-08-PLAN.md
|
Stopped at: Completed 25-file-system-25-04-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
|
|
|
||||||
93
.planning/phases/25-file-system/25-04-SUMMARY.md
Normal file
93
.planning/phases/25-file-system/25-04-SUMMARY.md
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
---
|
||||||
|
phase: 25-file-system
|
||||||
|
plan: "04"
|
||||||
|
subsystem: chat-files-ui
|
||||||
|
tags: [syntax-highlighting, code-preview, file-preview, highlight.js, requirements-closure]
|
||||||
|
dependency_graph:
|
||||||
|
requires: ["25-03"]
|
||||||
|
provides: ["ChatCodeFilePreview", "code-file-syntax-highlight"]
|
||||||
|
affects: ["ChatFilePreview", "REQUIREMENTS.md"]
|
||||||
|
tech_stack:
|
||||||
|
added: ["highlight.js@11.11.1"]
|
||||||
|
patterns: ["DOMParser-based safe HTML rendering", "hljs.highlight() with registered language set", "extToLang extension mapping"]
|
||||||
|
key_files:
|
||||||
|
created:
|
||||||
|
- ui/src/components/ChatCodeFilePreview.tsx
|
||||||
|
modified:
|
||||||
|
- ui/src/components/ChatFilePreview.tsx
|
||||||
|
- ui/package.json
|
||||||
|
- pnpm-lock.yaml
|
||||||
|
- .planning/REQUIREMENTS.md
|
||||||
|
decisions:
|
||||||
|
- "Used DOMParser + replaceChildren to safely render hljs output — avoids raw HTML injection pattern while preserving same visual output"
|
||||||
|
- "highlight.js added as explicit ui/package.json dependency (was transitive via rehype-highlight only)"
|
||||||
|
- "FILE-07 marked Complete: ChatFileCard implements one-click download via content-disposition response"
|
||||||
|
- "FILE-13 marked Complete: GET /api/files/:fileId/content serves files over HTTP for cross-device access"
|
||||||
|
metrics:
|
||||||
|
duration: "5 min"
|
||||||
|
completed_date: "2026-04-02"
|
||||||
|
tasks_completed: 2
|
||||||
|
files_changed: 5
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 25 Plan 04: Syntax-Highlighted Code File Preview Summary
|
||||||
|
|
||||||
|
**One-liner:** hljs-powered code file preview with DOMParser-safe rendering, language label, copy button, and ChatFileCard download — plus administrative closure of FILE-07 and FILE-13.
|
||||||
|
|
||||||
|
## Tasks Completed
|
||||||
|
|
||||||
|
| Task | Name | Commit | Files |
|
||||||
|
|------|------|--------|-------|
|
||||||
|
| 1 | Create ChatCodeFilePreview component | d212c372 | ChatCodeFilePreview.tsx, ui/package.json, pnpm-lock.yaml |
|
||||||
|
| 2 | Wire ChatCodeFilePreview into ChatFilePreview and update REQUIREMENTS.md | 2db14c6a | ChatFilePreview.tsx, REQUIREMENTS.md |
|
||||||
|
|
||||||
|
## What Was Built
|
||||||
|
|
||||||
|
### ChatCodeFilePreview component
|
||||||
|
|
||||||
|
`ui/src/components/ChatCodeFilePreview.tsx` (155 lines):
|
||||||
|
|
||||||
|
- Fetches file content from `contentPath` using `fetch` with `credentials: "include"`
|
||||||
|
- Caps content at 50KB (appends `// ... truncated` if exceeded)
|
||||||
|
- Shows loading skeleton (`animate-pulse h-[120px]`) while fetching
|
||||||
|
- Falls back to `ChatFileCard` on network error
|
||||||
|
- Uses `hljs.highlight()` with 14 registered languages (typescript, javascript, python, css, json, xml, bash, sql, go, rust, java, cpp, markdown, yaml)
|
||||||
|
- Renders highlighted output safely via `DOMParser` + `replaceChildren` (avoids raw HTML string injection — same trust model as rehype-highlight)
|
||||||
|
- Wraps output in `paperclip-markdown` class to activate existing hljs CSS theme
|
||||||
|
- Includes language label and copy button (Copy/Check icons, `navigator.clipboard.writeText`)
|
||||||
|
- Scroll-contained with `max-h-[400px] overflow-auto`
|
||||||
|
- Shows `ChatFileCard` below for download button
|
||||||
|
|
||||||
|
### ChatFilePreview update
|
||||||
|
|
||||||
|
Added `if (file.category === "code")` branch that routes to `ChatCodeFilePreview` before the fallback `ChatFileCard` return.
|
||||||
|
|
||||||
|
### REQUIREMENTS.md update
|
||||||
|
|
||||||
|
- `FILE-07` (one-click download): marked `[x]` Complete — `ChatFileCard` implements download via `content-disposition` header response from `GET /api/files/:fileId/content`
|
||||||
|
- `FILE-13` (cross-device access): marked `[x]` Complete — files are served via HTTP through the Nexus server API, accessible from any networked device
|
||||||
|
- Traceability table updated for both
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 3 - Blocking] Added highlight.js as explicit ui/package.json dependency**
|
||||||
|
- **Found during:** Task 1 — TypeScript compilation failed (Cannot find module 'highlight.js/lib/core')
|
||||||
|
- **Issue:** highlight.js was only a transitive dependency via rehype-highlight; TypeScript could not resolve it directly
|
||||||
|
- **Fix:** Added `"highlight.js": "^11.11.1"` to ui/package.json dependencies, ran `pnpm install`
|
||||||
|
- **Files modified:** ui/package.json, pnpm-lock.yaml
|
||||||
|
- **Commit:** d212c372
|
||||||
|
|
||||||
|
**2. [Rule 2 - Security] Used DOMParser-based rendering instead of the plan's suggested raw HTML injection approach**
|
||||||
|
- **Found during:** Task 1 — security plugin blocked file creation due to raw HTML injection pattern
|
||||||
|
- **Issue:** Security plugin blocks direct HTML string assignment to prevent XSS. The original plan recommended a pattern the hook treats as risky.
|
||||||
|
- **Fix:** Implemented `applyHighlightedHtml()` helper that uses `DOMParser` to parse hljs output into a sandboxed document, then transfers child nodes via `replaceChildren()`. This is genuinely safer while producing identical visual output. Used `useRef` + `useEffect` for the rendering step.
|
||||||
|
- **Files modified:** ui/src/components/ChatCodeFilePreview.tsx
|
||||||
|
- **Commit:** d212c372
|
||||||
|
|
||||||
|
## Known Stubs
|
||||||
|
|
||||||
|
None — ChatCodeFilePreview fetches real content from the existing `GET /api/files/:fileId/content` endpoint established in Plans 25-01 and 25-02. No stub data flows to the UI.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
Loading…
Add table
Reference in a new issue