From 59991367dd5fc0bb956cf84c39548d7e37cd657d Mon Sep 17 00:00:00 2001 From: Nexus Dev Date: Thu, 2 Apr 2026 00:06:18 +0000 Subject: [PATCH] =?UTF-8?q?docs(25-06):=20complete=20git=20file=20versioni?= =?UTF-8?q?ng=20plan=20=E2=80=94=20SUMMARY,=20STATE,=20ROADMAP=20updated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gitFileService with ensureRepo/commitFile/getLog using safe execFile - GET /files/:fileId/history endpoint for git version history - FILE-09 and FILE-10 marked Complete --- .planning/ROADMAP.md | 6 +- .planning/STATE.md | 16 ++- .../phases/25-file-system/25-06-SUMMARY.md | 110 ++++++++++++++++++ 3 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 .planning/phases/25-file-system/25-06-SUMMARY.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 952827ea..e0ebf290 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -116,7 +116,7 @@ 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 6. A file uploaded in a conversation linked to a project lives in `files/projects//`; a file from an unlinked conversation lives in `files/chat//`; 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 -**Plans:** 7/9 plans executed +**Plans:** 8/9 plans executed Plans: - [x] 25-00-PLAN.md — DB schema (chat_files + chat_file_references), shared types/validators, test stubs @@ -125,7 +125,7 @@ Plans: - [x] 25-03-PLAN.md — UI: ChatFilePreview/ChatFileCard components, ChatMessage/ChatPanel wiring - [x] 25-04-PLAN.md — Gap: Code syntax-highlighted preview (FILE-06) + admin claims (FILE-07, FILE-13) - [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) +- [x] 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) - [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 | | 23. Brainstormer Flow | 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 | 7/9 | In Progress| | +| 25. File System | v1.3 | 8/9 | In Progress| | | 26. PWA & Performance | v1.3 | 0/? | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 4b7499cc..4961bfdf 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.3 milestone_name: milestone status: executing -stopped_at: Completed 25-file-system-25-04-PLAN.md -last_updated: "2026-04-02T00:04:47.523Z" +stopped_at: Completed 25-file-system-25-06-PLAN.md +last_updated: "2026-04-02T00:06:07.957Z" last_activity: 2026-04-02 progress: total_phases: 6 completed_phases: 4 total_plans: 30 - completed_plans: 28 + completed_plans: 29 percent: 100 --- @@ -26,7 +26,7 @@ See: .planning/PROJECT.md (updated 2026-03-30) ## Current Position Phase: 25 (file-system) — EXECUTING -Plan: 3 of 9 +Plan: 4 of 9 Status: Ready to execute Last activity: 2026-04-02 @@ -84,6 +84,7 @@ Progress: [██████████] 100% | Phase 25-file-system P03 | 3 | 2 tasks | 7 files | | Phase 25-file-system P08 | 8 | 2 tasks | 5 files | | Phase 25-file-system P04 | 5min | 2 tasks | 5 files | +| Phase 25-file-system P06 | 5 | 2 tasks | 5 files | ## Accumulated Context @@ -153,6 +154,9 @@ Recent decisions affecting current work: - [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) +- [Phase 25-file-system]: Used execFile (not exec) for git commands in gitFileService — array-based args prevent shell injection +- [Phase 25-file-system]: Git commit is fire-and-forget after upload — response not blocked by git operation +- [Phase 25-file-system]: History route placed before /content route to avoid Express path ambiguity on /files/:fileId/* ### Pending Todos @@ -165,6 +169,6 @@ None yet. ## Session Continuity -Last session: 2026-04-02T00:04:47.520Z -Stopped at: Completed 25-file-system-25-04-PLAN.md +Last session: 2026-04-02T00:06:07.954Z +Stopped at: Completed 25-file-system-25-06-PLAN.md Resume file: None diff --git a/.planning/phases/25-file-system/25-06-SUMMARY.md b/.planning/phases/25-file-system/25-06-SUMMARY.md new file mode 100644 index 00000000..aa9a3df7 --- /dev/null +++ b/.planning/phases/25-file-system/25-06-SUMMARY.md @@ -0,0 +1,110 @@ +--- +phase: 25-file-system +plan: "06" +subsystem: api +tags: [git, versioning, file-history, execFile, child_process] + +# Dependency graph +requires: + - phase: 25-01 + provides: chatFileService, chatFileRoutes, StorageService integration + - phase: 25-00 + provides: chat_files DB schema, ChatFile shared types + +provides: + - gitFileService with ensureRepo, commitFile, getLog using safe execFile + - GET /files/:fileId/history endpoint returning git log entries + - Git commit on every file upload (non-blocking fire-and-forget) + - ChatFileHistoryEntry shared type + +affects: [25-file-system, any plan using file version history] + +# Tech tracking +tech-stack: + added: [node:child_process execFile, node:util promisify] + patterns: [fire-and-forget git commit after upload, execFile array args for shell-injection safety] + +key-files: + created: + - server/src/services/git-file-service.ts + modified: + - server/src/routes/chat-files.ts + - packages/shared/src/types/chat.ts + - packages/shared/src/index.ts + - .planning/REQUIREMENTS.md + +key-decisions: + - "Used execFile (not exec) for all git commands — array-based args prevent shell injection" + - "Git commit is fire-and-forget (.catch(() => {})) so upload response is not blocked" + - "History route placed before /content route to prevent Express /files/:fileId/* ambiguity" + - "resolveDefaultStorageDir() used to find storage root — same path LocalDiskProvider uses" + +patterns-established: + - "gitFileService: factory function returning interface with ensureRepo/commitFile/getLog" + - "ensureRepo lazily initializes git repo on first use — idempotent via .git dir check" + +requirements-completed: [FILE-09, FILE-10] + +# Metrics +duration: 5min +completed: 2026-04-01 +--- + +# Phase 25 Plan 06: Git File Versioning Summary + +**Git versioning layer added to file uploads: gitFileService wraps git CLI with safe execFile, every upload creates a commit, GET /files/:fileId/history exposes git log** + +## Performance + +- **Duration:** 5 min +- **Started:** 2026-04-01T21:59:30Z +- **Completed:** 2026-04-01T22:04:30Z +- **Tasks:** 2 +- **Files modified:** 5 + +## Accomplishments +- Created gitFileService with ensureRepo (lazy git init), commitFile (add+commit via execFile), getLog (parse git log output) +- Wired git commit into POST /conversations/:id/files upload flow as non-blocking fire-and-forget +- Added GET /files/:fileId/history endpoint returning paginated git log entries (max 100) +- Added ChatFileHistoryEntry interface to shared types and exported from shared package index + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Create gitFileService and ChatFileHistoryEntry type** - `eb954635` (feat) +2. **Task 2: Wire git commits into upload flow and add history endpoint** - `6ba745b9` (feat) + +**Requirements metadata:** `637ecc74` (chore: mark FILE-09 and FILE-10 complete) + +## Files Created/Modified +- `server/src/services/git-file-service.ts` - Git service with ensureRepo/commitFile/getLog methods +- `server/src/routes/chat-files.ts` - Added git import, storageDir, gitSvc, fire-and-forget commit, /history route +- `packages/shared/src/types/chat.ts` - Added ChatFileHistoryEntry interface +- `packages/shared/src/index.ts` - Exported ChatFileHistoryEntry +- `.planning/REQUIREMENTS.md` - Marked FILE-09 and FILE-10 as Complete + +## Decisions Made +- Used `execFile` (promisified from `node:util`) instead of `exec` — array args cannot be shell-injected even if objectKey contained special chars +- Git commit is fire-and-forget (`gitSvc.commitFile(...).catch(() => {})`) — upload response sent immediately, git tracking happens asynchronously +- History endpoint placed before `/files/:fileId/content` so Express route matching finds `/history` before falling through to `:fileId` catch-all patterns +- Used `resolveDefaultStorageDir()` from `home-paths.ts` — the exact same path construction that `LocalDiskProvider` uses for its `root` directory + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered +- Worktree was on a different branch (`worktree-agent-afd26110`) without phase-25 prerequisite files. Resolved by checking out required files from `gsd/phase-25-file-system` branch before applying plan 06 changes. + +## User Setup Required +None - no external service configuration required. + +## Next Phase Readiness +- Git versioning infrastructure complete for FILE-09 and FILE-10 requirements +- gitFileService ready for reuse by any future plan needing git tracking on storage files +- History endpoint available at GET /files/:fileId/history?limit=N + +--- +*Phase: 25-file-system* +*Completed: 2026-04-01*