--- phase: 09-video-history plan: 01 type: execute --- Add history carousel for generated videos in GenerateVideoNode, matching the image history pattern. Purpose: Allow users to browse through previously generated videos without re-generating, improving workflow iteration speed. Output: GenerateVideoNode with carousel navigation controls and persistent video history stored to generations folder. ~/.claude/get-shit-done/workflows/execute-phase.md ~/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md # Key reference files (pattern to follow): @src/components/nodes/GenerateImageNode.tsx - Has carousel controls to copy pattern from (lines 295-334, 609-636) @src/types/index.ts - Has ImageHistoryItem/CarouselImageItem types (lines 117-134) @src/store/workflowStore.ts - Has imageHistory handling in executeWorkflow (lines 1201-1207, 1893-1899) @src/app/api/load-generation/route.ts - Currently only handles .png, needs video support @src/app/api/save-generation/route.ts - Already supports video (line 12-16), good reference # Files to modify: @src/components/nodes/GenerateVideoNode.tsx Task 1: Add video history types and store support src/types/index.ts, src/store/workflowStore.ts 1. In src/types/index.ts: - Add `CarouselVideoItem` type after `CarouselImageItem` (line ~135): ```typescript export interface CarouselVideoItem { id: string; timestamp: number; prompt: string; model: string; // Model ID for video (not ModelType since external providers) } ``` - Update `GenerateVideoNodeData` interface (line ~165) to add: ```typescript videoHistory: CarouselVideoItem[]; selectedVideoHistoryIndex: number; ``` 2. In src/store/workflowStore.ts: - Update `createDefaultNodeData` for "generateVideo" case (around line 214) to include: ```typescript videoHistory: [], selectedVideoHistoryIndex: 0, ``` - In `executeWorkflow` where generateVideo success is handled (around line 1392-1398), add video history tracking after setting outputVideo: - Generate unique ID: `const videoId = crypto.randomUUID();` - Create history item: `{ id: videoId, timestamp: Date.now(), prompt: text || '', model: nodeData.selectedModel?.modelId || '' }` - Update history array (prepend new item): `videoHistory: [newHistoryItem, ...(nodeData.videoHistory || [])].slice(0, 50)` - Set `selectedVideoHistoryIndex: 0` - Call save-generation API with video and videoId (async, don't await) - Do the same for regenerateNode video handling (around line 2136-2142) Import `crypto` from Node.js is not needed - use Math.random() fallback pattern already in codebase, or check if crypto.randomUUID exists. TypeScript compiles: `npm run build` passes without type errors related to video history GenerateVideoNodeData has videoHistory and selectedVideoHistoryIndex fields. Workflow execution saves videos to history and persists to generations folder. Task 2: Update load-generation API to support video formats src/app/api/load-generation/route.ts Update the load-generation API to handle video files in addition to images: 1. Change the hardcoded `.png` extension logic (line 54) to search for the file by ID with multiple extensions: - Define supported extensions: `const extensions = ['png', 'jpg', 'jpeg', 'webp', 'gif', 'mp4', 'webm', 'mov'];` - Loop through extensions to find the file that exists - If no file found with any extension, return 404 2. Update the MIME type detection based on actual file extension found: ```typescript const extToMime: Record = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', webp: 'image/webp', gif: 'image/gif', mp4: 'video/mp4', webm: 'video/webm', mov: 'video/quicktime', }; ``` 3. Return appropriate response field: - For images: `{ success: true, image: dataUrl }` - For videos: `{ success: true, video: dataUrl }` - Include `contentType` field to indicate type: `contentType: extension.startsWith('mp4') || extension === 'webm' || extension === 'mov' ? 'video' : 'image'` API handles video loading: Create a test .mp4 file in generations folder and verify the endpoint returns it correctly load-generation API can load both images and videos by ID, with correct MIME types and response fields Task 3: Add carousel controls to GenerateVideoNode src/components/nodes/GenerateVideoNode.tsx Add carousel UI and navigation to GenerateVideoNode, following GenerateImageNode pattern: 1. Add state for loading: ```typescript const [isLoadingCarouselVideo, setIsLoadingCarouselVideo] = useState(false); ``` 2. Get generationsPath from store: ```typescript const generationsPath = useWorkflowStore((state) => state.generationsPath); ``` 3. Add loadVideoById callback (copy pattern from GenerateImageNode lines 266-293): ```typescript const loadVideoById = useCallback(async (videoId: string) => { if (!generationsPath) return null; try { const response = await fetch("/api/load-generation", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ directoryPath: generationsPath, imageId: videoId }), }); if (!response.ok) return null; const result = await response.json(); return result.success ? (result.video || result.image) : null; } catch { return null; } }, [generationsPath]); ``` 4. Add carousel navigation handlers (copy pattern from GenerateImageNode lines 295-333): ```typescript const handleCarouselPrevious = useCallback(async () => { ... }, [...]); const handleCarouselNext = useCallback(async () => { ... }, [...]); ``` Adapt for video: use `videoHistory`, `selectedVideoHistoryIndex`, `outputVideo` 5. Add carousel UI after the video element, inside the outputVideo conditional (around line 388): - Check `hasCarouselVideos = (nodeData.videoHistory || []).length > 1` - Add carousel controls div with prev/next buttons (copy from GenerateImageNode lines 609-636) - Show "N / M" indicator using videoHistory length and selectedVideoHistoryIndex 6. Add loading overlay for carousel navigation (copy from GenerateImageNode lines 572-595): - Inside the video preview div, add conditional overlay when isLoadingCarouselVideo is true Visual inspection: Generate 2+ videos with same node, verify carousel appears and navigation works GenerateVideoNode has prev/next carousel buttons showing after first regeneration, allowing users to browse video history Before declaring phase complete: - [ ] `npm run build` succeeds without errors - [ ] GenerateVideoNode shows carousel controls after 2+ generations - [ ] Carousel navigation loads previous videos from disk - [ ] Videos persist across page refresh (stored in generations folder) - [ ] No TypeScript errors - All tasks completed - All verification checks pass - Video history works identically to image history pattern - Carousel shows N/M indicator and prev/next navigation - Videos saved to and loaded from generations folder After completion, create `.planning/phases/09-video-history/09-01-SUMMARY.md` following summary template.