opencode-nanobanana 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/.ralph-events.json +151 -0
  2. package/.ralph-last-branch +1 -0
  3. package/.ralph-monitor-state.json +7 -0
  4. package/.ralph-monitor.pid +1 -0
  5. package/.ralph-timing.json +26 -0
  6. package/README.md +708 -0
  7. package/dist/index.d.ts +18 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +21 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/platforms/android.d.ts +94 -0
  12. package/dist/platforms/android.d.ts.map +1 -0
  13. package/dist/platforms/android.js +123 -0
  14. package/dist/platforms/android.js.map +1 -0
  15. package/dist/platforms/ios.d.ts +51 -0
  16. package/dist/platforms/ios.d.ts.map +1 -0
  17. package/dist/platforms/ios.js +149 -0
  18. package/dist/platforms/ios.js.map +1 -0
  19. package/dist/platforms/macos.d.ts +33 -0
  20. package/dist/platforms/macos.d.ts.map +1 -0
  21. package/dist/platforms/macos.js +50 -0
  22. package/dist/platforms/macos.js.map +1 -0
  23. package/dist/platforms/watchos.d.ts +36 -0
  24. package/dist/platforms/watchos.d.ts.map +1 -0
  25. package/dist/platforms/watchos.js +113 -0
  26. package/dist/platforms/watchos.js.map +1 -0
  27. package/dist/platforms/web.d.ts +64 -0
  28. package/dist/platforms/web.d.ts.map +1 -0
  29. package/dist/platforms/web.js +96 -0
  30. package/dist/platforms/web.js.map +1 -0
  31. package/dist/providers/gemini.d.ts +41 -0
  32. package/dist/providers/gemini.d.ts.map +1 -0
  33. package/dist/providers/gemini.js +177 -0
  34. package/dist/providers/gemini.js.map +1 -0
  35. package/dist/tools/analyze/compare.d.ts +12 -0
  36. package/dist/tools/analyze/compare.d.ts.map +1 -0
  37. package/dist/tools/analyze/compare.js +83 -0
  38. package/dist/tools/analyze/compare.js.map +1 -0
  39. package/dist/tools/analyze/mockup.d.ts +12 -0
  40. package/dist/tools/analyze/mockup.d.ts.map +1 -0
  41. package/dist/tools/analyze/mockup.js +88 -0
  42. package/dist/tools/analyze/mockup.js.map +1 -0
  43. package/dist/tools/analyze/screenshot.d.ts +12 -0
  44. package/dist/tools/analyze/screenshot.d.ts.map +1 -0
  45. package/dist/tools/analyze/screenshot.js +61 -0
  46. package/dist/tools/analyze/screenshot.js.map +1 -0
  47. package/dist/tools/app-assets/app-icon.d.ts +9 -0
  48. package/dist/tools/app-assets/app-icon.d.ts.map +1 -0
  49. package/dist/tools/app-assets/app-icon.js +133 -0
  50. package/dist/tools/app-assets/app-icon.js.map +1 -0
  51. package/dist/tools/app-assets/device-mockup.d.ts +9 -0
  52. package/dist/tools/app-assets/device-mockup.d.ts.map +1 -0
  53. package/dist/tools/app-assets/device-mockup.js +139 -0
  54. package/dist/tools/app-assets/device-mockup.js.map +1 -0
  55. package/dist/tools/app-assets/launch-images.d.ts +3 -0
  56. package/dist/tools/app-assets/launch-images.d.ts.map +1 -0
  57. package/dist/tools/app-assets/launch-images.js +171 -0
  58. package/dist/tools/app-assets/launch-images.js.map +1 -0
  59. package/dist/tools/app-assets/resize-devices.d.ts +14 -0
  60. package/dist/tools/app-assets/resize-devices.d.ts.map +1 -0
  61. package/dist/tools/app-assets/resize-devices.js +296 -0
  62. package/dist/tools/app-assets/resize-devices.js.map +1 -0
  63. package/dist/tools/app-assets/screenshots.d.ts +14 -0
  64. package/dist/tools/app-assets/screenshots.d.ts.map +1 -0
  65. package/dist/tools/app-assets/screenshots.js +186 -0
  66. package/dist/tools/app-assets/screenshots.js.map +1 -0
  67. package/dist/tools/core/edit-image.d.ts +12 -0
  68. package/dist/tools/core/edit-image.d.ts.map +1 -0
  69. package/dist/tools/core/edit-image.js +102 -0
  70. package/dist/tools/core/edit-image.js.map +1 -0
  71. package/dist/tools/core/generate-image.d.ts +12 -0
  72. package/dist/tools/core/generate-image.d.ts.map +1 -0
  73. package/dist/tools/core/generate-image.js +96 -0
  74. package/dist/tools/core/generate-image.js.map +1 -0
  75. package/dist/tools/core/restore-image.d.ts +12 -0
  76. package/dist/tools/core/restore-image.d.ts.map +1 -0
  77. package/dist/tools/core/restore-image.js +104 -0
  78. package/dist/tools/core/restore-image.js.map +1 -0
  79. package/dist/tools/design/mockup-to-code.d.ts +3 -0
  80. package/dist/tools/design/mockup-to-code.d.ts.map +1 -0
  81. package/dist/tools/design/mockup-to-code.js +311 -0
  82. package/dist/tools/design/mockup-to-code.js.map +1 -0
  83. package/dist/tools/design/sketch-to-code.d.ts +3 -0
  84. package/dist/tools/design/sketch-to-code.d.ts.map +1 -0
  85. package/dist/tools/design/sketch-to-code.js +325 -0
  86. package/dist/tools/design/sketch-to-code.js.map +1 -0
  87. package/dist/tools/docs/architecture-diagram.d.ts +12 -0
  88. package/dist/tools/docs/architecture-diagram.d.ts.map +1 -0
  89. package/dist/tools/docs/architecture-diagram.js +179 -0
  90. package/dist/tools/docs/architecture-diagram.js.map +1 -0
  91. package/dist/tools/docs/readme-banner.d.ts +6 -0
  92. package/dist/tools/docs/readme-banner.d.ts.map +1 -0
  93. package/dist/tools/docs/readme-banner.js +108 -0
  94. package/dist/tools/docs/readme-banner.js.map +1 -0
  95. package/dist/tools/docs/sequence-diagram.d.ts +12 -0
  96. package/dist/tools/docs/sequence-diagram.d.ts.map +1 -0
  97. package/dist/tools/docs/sequence-diagram.js +161 -0
  98. package/dist/tools/docs/sequence-diagram.js.map +1 -0
  99. package/dist/tools/docs/social-preview.d.ts +11 -0
  100. package/dist/tools/docs/social-preview.d.ts.map +1 -0
  101. package/dist/tools/docs/social-preview.js +111 -0
  102. package/dist/tools/docs/social-preview.js.map +1 -0
  103. package/dist/tools/video/extend-video.d.ts +14 -0
  104. package/dist/tools/video/extend-video.d.ts.map +1 -0
  105. package/dist/tools/video/extend-video.js +39 -0
  106. package/dist/tools/video/extend-video.js.map +1 -0
  107. package/dist/tools/video/generate-video.d.ts +14 -0
  108. package/dist/tools/video/generate-video.d.ts.map +1 -0
  109. package/dist/tools/video/generate-video.js +39 -0
  110. package/dist/tools/video/generate-video.js.map +1 -0
  111. package/dist/tools/video/image-to-video.d.ts +15 -0
  112. package/dist/tools/video/image-to-video.d.ts.map +1 -0
  113. package/dist/tools/video/image-to-video.js +42 -0
  114. package/dist/tools/video/image-to-video.js.map +1 -0
  115. package/dist/tools/video/storyboard-video.d.ts +91 -0
  116. package/dist/tools/video/storyboard-video.d.ts.map +1 -0
  117. package/dist/tools/video/storyboard-video.js +230 -0
  118. package/dist/tools/video/storyboard-video.js.map +1 -0
  119. package/dist/utils/ffmpeg.d.ts +30 -0
  120. package/dist/utils/ffmpeg.d.ts.map +1 -0
  121. package/dist/utils/ffmpeg.js +205 -0
  122. package/dist/utils/ffmpeg.js.map +1 -0
  123. package/dist/utils/file-handler.d.ts +7 -0
  124. package/dist/utils/file-handler.d.ts.map +1 -0
  125. package/dist/utils/file-handler.js +10 -0
  126. package/dist/utils/file-handler.js.map +1 -0
  127. package/dist/utils/image-processing.d.ts +7 -0
  128. package/dist/utils/image-processing.d.ts.map +1 -0
  129. package/dist/utils/image-processing.js +10 -0
  130. package/dist/utils/image-processing.js.map +1 -0
  131. package/docs/PLUGIN-VERIFICATION.md +182 -0
  132. package/logs/notifications.jsonl +46 -0
  133. package/package.json +61 -0
  134. package/prd.json +216 -0
  135. package/progress.txt +145 -0
  136. package/ralph-report.html +297 -0
  137. package/src/index.ts +23 -0
  138. package/src/platforms/android/.gitkeep +0 -0
  139. package/src/platforms/ios/.gitkeep +0 -0
  140. package/src/platforms/web/.gitkeep +0 -0
  141. package/src/providers/.gitkeep +0 -0
  142. package/src/providers/gemini.ts +288 -0
  143. package/src/tools/core/.gitkeep +0 -0
  144. package/src/tools/platform/.gitkeep +0 -0
  145. package/src/tools/video/extend-video.ts +71 -0
  146. package/src/tools/video/generate-video.ts +70 -0
  147. package/src/tools/video/image-to-video.ts +76 -0
  148. package/src/tools/video/storyboard-video.ts +325 -0
  149. package/src/utils/.gitkeep +0 -0
  150. package/src/utils/ffmpeg.ts +266 -0
  151. package/src/utils/file-handler.ts +10 -0
  152. package/src/utils/image-processing.ts +10 -0
  153. package/templates/.gitkeep +0 -0
  154. package/test-analyze-screenshot.ts +50 -0
  155. package/test-app-icons.ts +55 -0
  156. package/test-cat-sunset.ts +30 -0
  157. package/test-full-plugin.ts +88 -0
  158. package/test-icon-gen.ts +30 -0
  159. package/test-output/test-edit.png +0 -0
  160. package/test-output/test-generate.png +0 -0
  161. package/test-output/test-video.mp4 +0 -0
  162. package/test-plugin-load.js +45 -0
  163. package/test-princess-emma-continue.ts +35 -0
  164. package/test-princess-emma-full.ts +38 -0
  165. package/test-princess-emma-short.ts +32 -0
  166. package/test-princess-emma-with-reference.ts +34 -0
  167. package/test-princess-emma.ts +38 -0
  168. package/test-product-ad.ts +66 -0
  169. package/test-ralph-droid.ts +30 -0
  170. package/test-social-preview.ts +61 -0
  171. package/test-veo31-live.ts +187 -0
  172. package/test-video-gen.ts +40 -0
  173. package/test-video-veo.ts +73 -0
  174. package/test-zurich-video.ts +64 -0
  175. package/tests/.gitkeep +0 -0
  176. package/tests/providers/gemini.test.ts +388 -0
  177. package/tests/utils/ffmpeg.test.ts +328 -0
  178. package/tests/video/storyboard.test.ts +469 -0
  179. package/tsconfig.json +25 -0
package/prd.json ADDED
@@ -0,0 +1,216 @@
1
+ {
2
+ "projectName": "opencode-visual-toolkit-storyboard",
3
+ "description": "Add storyboard video generation feature using Veo 3.1 with native audio, multi-scene support, transitions, and video stitching capabilities.",
4
+ "branchName": "ralph/storyboard-video",
5
+ "repository": "48Nauts-Operator/opencode-nanobanana",
6
+ "techStack": {
7
+ "runtime": "Bun",
8
+ "language": "TypeScript",
9
+ "framework": "OpenCode Plugin",
10
+ "dependencies": [
11
+ "@google/genai",
12
+ "@opencode-ai/plugin",
13
+ "sharp",
14
+ "zod"
15
+ ],
16
+ "externalTools": [
17
+ "ffmpeg"
18
+ ]
19
+ },
20
+ "userStories": [
21
+ {
22
+ "id": "VEO3-001",
23
+ "title": "Upgrade to Veo 3.1 API",
24
+ "description": "Update GeminiProvider to use Veo 3.1 model with native audio support and new features.",
25
+ "priority": 1,
26
+ "acceptanceCriteria": [
27
+ "Update generateVideo() to use model 'veo-3.1-generate-001'",
28
+ "Add support for native audio generation (enabled by default)",
29
+ "Add resolution option: '720p' or '1080p' (default: '720p')",
30
+ "Add duration option: 4, 6, or 8 seconds (default: 8)",
31
+ "Update animateImage() to use Veo 3.1",
32
+ "Add generateAudio config option to enable/disable audio",
33
+ "Update tests for new Veo 3.1 parameters",
34
+ "Verify audio is included in generated videos"
35
+ ],
36
+ "passes": true
37
+ },
38
+ {
39
+ "id": "VEO3-002",
40
+ "title": "Video Extension API Support",
41
+ "description": "Add support for Veo 3.1 video extension feature to extend existing videos with new content.",
42
+ "priority": 2,
43
+ "acceptanceCriteria": [
44
+ "Add extendVideo(videoBuffer, prompt, options) method to GeminiProvider",
45
+ "Method takes existing video and extends it with new prompt",
46
+ "Returns extended video buffer",
47
+ "Supports same options as generateVideo (aspectRatio, resolution)",
48
+ "Handles API polling for long-running operation",
49
+ "Add unit test for extendVideo method"
50
+ ],
51
+ "passes": true
52
+ },
53
+ {
54
+ "id": "VEO3-003",
55
+ "title": "Reference Image Support",
56
+ "description": "Add support for Veo 3.1 reference images feature to guide video generation with up to 3 reference images.",
57
+ "priority": 3,
58
+ "acceptanceCriteria": [
59
+ "Add generateVideoWithReferences(prompt, referenceImages[], options) method",
60
+ "referenceImages is array of {buffer, description} objects (max 3)",
61
+ "Reference images guide character/object/scene consistency",
62
+ "Returns video buffer with content matching references",
63
+ "Add unit test for reference image feature"
64
+ ],
65
+ "passes": true
66
+ },
67
+ {
68
+ "id": "FFMPEG-001",
69
+ "title": "FFmpeg Utility Module",
70
+ "description": "Create FFmpeg utility module for video processing operations.",
71
+ "priority": 4,
72
+ "acceptanceCriteria": [
73
+ "Create src/utils/ffmpeg.ts utility module",
74
+ "checkFfmpegInstalled() returns boolean",
75
+ "concatenateVideos(videoPaths[], outputPath, transition) stitches videos",
76
+ "Transition options: 'cut', 'crossfade', 'fade'",
77
+ "transitionDuration parameter for crossfade/fade (default: 0.5s)",
78
+ "getVideoDuration(videoPath) returns duration in seconds",
79
+ "trimVideo(videoPath, startTime, duration, outputPath) trims video",
80
+ "addAudioTrack(videoPath, audioPath, outputPath) adds background music",
81
+ "All functions return Promise and handle errors gracefully",
82
+ "Add unit tests with mocked ffmpeg commands"
83
+ ],
84
+ "passes": true
85
+ },
86
+ {
87
+ "id": "STORY-001",
88
+ "title": "Storyboard Video Tool - Core",
89
+ "description": "Implement generate_storyboard_video tool that generates multiple scenes and stitches them together.",
90
+ "priority": 5,
91
+ "acceptanceCriteria": [
92
+ "Create src/tools/video/storyboard-video.ts",
93
+ "Tool accepts scenes[] array of scene description strings",
94
+ "Tool accepts style option to prefix all scenes (e.g., 'cinematic', 'commercial')",
95
+ "Tool accepts aspectRatio option (default: '16:9')",
96
+ "Tool accepts transition option: 'cut', 'crossfade', 'fade' (default: 'crossfade')",
97
+ "Tool accepts transitionDuration option (default: 0.5)",
98
+ "Tool accepts outputPath option",
99
+ "Generates all scenes in parallel for speed",
100
+ "Uses FFmpeg to stitch scenes with transitions",
101
+ "Returns path to final combined video",
102
+ "Handles errors for individual scenes gracefully"
103
+ ],
104
+ "passes": true
105
+ },
106
+ {
107
+ "id": "STORY-002",
108
+ "title": "Storyboard Character Consistency",
109
+ "description": "Add character consistency feature to storyboard tool using style prefix and reference images.",
110
+ "priority": 6,
111
+ "acceptanceCriteria": [
112
+ "Add characterDescription option to storyboard tool",
113
+ "Character description is prepended to each scene prompt",
114
+ "Add referenceImages option (array of image paths)",
115
+ "Reference images are used with Veo 3.1 reference feature",
116
+ "Character appears consistent across all scenes",
117
+ "Add example in tool description showing character consistency usage"
118
+ ],
119
+ "passes": true
120
+ },
121
+ {
122
+ "id": "STORY-003",
123
+ "title": "Storyboard Audio Options",
124
+ "description": "Add audio control options to storyboard tool.",
125
+ "priority": 7,
126
+ "acceptanceCriteria": [
127
+ "Add generateAudio option (default: true) to enable/disable native Veo audio",
128
+ "Add backgroundMusic option (path to audio file)",
129
+ "Background music is mixed with native audio if both enabled",
130
+ "Add musicVolume option (0.0-1.0, default: 0.3) for background music level",
131
+ "FFmpeg handles audio mixing",
132
+ "Final video has properly mixed audio track"
133
+ ],
134
+ "passes": true
135
+ },
136
+ {
137
+ "id": "STORY-004",
138
+ "title": "Storyboard Progress Callback",
139
+ "description": "Add progress reporting for long-running storyboard generation.",
140
+ "priority": 8,
141
+ "acceptanceCriteria": [
142
+ "Tool logs progress for each scene generation",
143
+ "Format: 'Generating scene 1/5...' etc.",
144
+ "Logs when stitching begins",
145
+ "Logs total generation time at completion",
146
+ "Returns detailed result with per-scene timing"
147
+ ],
148
+ "passes": true
149
+ },
150
+ {
151
+ "id": "EXTEND-001",
152
+ "title": "Extend Video Tool",
153
+ "description": "Implement extend_video tool that extends an existing video with new content.",
154
+ "priority": 9,
155
+ "acceptanceCriteria": [
156
+ "Create src/tools/video/extend-video.ts",
157
+ "Tool accepts videoPath (required) - path to existing video",
158
+ "Tool accepts prompt (required) - description of extension content",
159
+ "Tool accepts outputPath (optional)",
160
+ "Uses Veo 3.1 video extension API",
161
+ "Returns path to extended video",
162
+ "Add tool to plugin exports"
163
+ ],
164
+ "passes": true
165
+ },
166
+ {
167
+ "id": "TEST-001",
168
+ "title": "Storyboard Integration Tests",
169
+ "description": "Add integration tests for storyboard video generation.",
170
+ "priority": 10,
171
+ "acceptanceCriteria": [
172
+ "Create tests/video/storyboard.test.ts",
173
+ "Test multi-scene generation with mocked Veo API",
174
+ "Test FFmpeg stitching with mocked commands",
175
+ "Test transition options (cut, crossfade, fade)",
176
+ "Test character consistency with style prefix",
177
+ "Test error handling for failed scenes",
178
+ "All tests pass"
179
+ ],
180
+ "passes": true
181
+ },
182
+ {
183
+ "id": "DOCS-001",
184
+ "title": "Update README with Storyboard Documentation",
185
+ "description": "Document the new storyboard video generation feature in README.",
186
+ "priority": 11,
187
+ "acceptanceCriteria": [
188
+ "Add Storyboard Video section to README",
189
+ "Document generate_storyboard_video tool parameters",
190
+ "Document extend_video tool parameters",
191
+ "Add example usage for multi-scene video",
192
+ "Add example usage for character consistency",
193
+ "Add example usage for background music",
194
+ "Document FFmpeg requirement",
195
+ "Update feature list at top of README"
196
+ ],
197
+ "passes": true
198
+ },
199
+ {
200
+ "id": "UPDATE-001",
201
+ "title": "Update Existing Video Tools for Veo 3.1",
202
+ "description": "Update generate_video and image_to_video tools to use Veo 3.1 and expose new options.",
203
+ "priority": 12,
204
+ "acceptanceCriteria": [
205
+ "Update generate_video tool to use Veo 3.1",
206
+ "Add resolution parameter (720p/1080p)",
207
+ "Add duration parameter (4/6/8 seconds)",
208
+ "Add generateAudio parameter (default: true)",
209
+ "Update image_to_video tool similarly",
210
+ "Update tool descriptions to mention audio support",
211
+ "Update README video tools section"
212
+ ],
213
+ "passes": true
214
+ }
215
+ ]
216
+ }
package/progress.txt ADDED
@@ -0,0 +1,145 @@
1
+ # Ralph Ultra Progress Log
2
+ Started: Thu Jan 15 22:01:15 CET 2026
3
+
4
+ ## Codebase Patterns
5
+ - Use Veo 3.1 API with correct field names: `durationSeconds`, `imageBytes`, `videoBytes`
6
+ - Always import enums from @google/genai (e.g., VideoGenerationReferenceType)
7
+ - GeminiProvider handles all API polling automatically - return VideoGenerationResult with buffer
8
+ - Tests use vitest with mocked GenAI SDK - use `importOriginal` for accessing real types
9
+ - Use fake timers for testing async operations with delays
10
+ - FFmpeg operations require exec() for complex shell features - ensure all paths are validated and quoted
11
+ - Mock child_process.exec using callback pattern in tests
12
+ ---
13
+
14
+ ## 2026-01-15 22:07 - VEO3-001, VEO3-002, VEO3-003
15
+ - Implemented GeminiProvider with full Veo 3.1 support
16
+ - Files changed:
17
+ - src/providers/gemini.ts (new) - Complete provider implementation
18
+ - src/utils/file-handler.ts (new) - Placeholder utility
19
+ - src/utils/image-processing.ts (new) - Placeholder utility
20
+ - tests/providers/gemini.test.ts (new) - Comprehensive test suite
21
+ - **Learnings for future iterations:**
22
+ - Veo 3.1 API uses `durationSeconds` not `duration`, `imageBytes` not `data`, `videoBytes` for video input
23
+ - Reference images use `VideoGenerationReferenceType.ASSET` enum for character/scene consistency
24
+ - Import actual types from @google/genai using `importOriginal` in mocks to access enums
25
+ - Use fake timers (`vi.useFakeTimers()`) for tests with polling to avoid timeouts
26
+ - TypeScript strict mode catches many API mismatches early - always run typecheck
27
+ - The GeminiProvider wraps Google GenAI SDK and handles all polling automatically
28
+ ---
29
+ ## 2026-01-15 22:11 - FFMPEG-001
30
+ - Implemented FFmpeg utility module for video processing
31
+ - Files changed:
32
+ - src/utils/ffmpeg.ts (new) - FFmpeg utility functions
33
+ - tests/utils/ffmpeg.test.ts (new) - Comprehensive test suite with 27 tests
34
+ - **Learnings for future iterations:**
35
+ - Use promisify pattern from 'util' to convert exec callback to async/await
36
+ - Always check file existence with existsSync before FFmpeg operations
37
+ - FFmpeg concatenation has 3 approaches: cut (simple concat file), crossfade (xfade filter), fade (fade in/out filter)
38
+ - Mock child_process.exec in tests - use callback pattern: callback(error, {stdout, stderr})
39
+ - TypeScript strict mode catches array access issues (videoPaths[0] can be undefined)
40
+ - Handle single video edge case by copying file instead of concatenating
41
+ - Add volume parameter to addAudioTrack for mixing audio levels (0.0-1.0)
42
+ - FFmpeg filter_complex is powerful but complex - keep fallback to simple approaches
43
+ ---
44
+ ## 2026-01-15 22:15 - STORY-001
45
+ - Implemented storyboard video generation tool with parallel scene generation
46
+ - Files changed:
47
+ - src/tools/video/storyboard-video.ts (new) - Complete storyboard video tool implementation
48
+ - src/index.ts (modified) - Export storyboard tool and ffmpeg utilities
49
+ - **Learnings for future iterations:**
50
+ - Use Promise.all() for parallel scene generation to maximize throughput
51
+ - Store temporary scene files in tmpdir() and clean up after stitching
52
+ - Graceful error handling: partial success is acceptable, filter failed scenes
53
+ - Always remove unused imports to pass TypeScript strict checks
54
+ - GeminiProvider.generateVideo() returns buffer directly, write to temp file for FFmpeg
55
+ - Tool returns detailed result object with timing per scene and success/failure counts
56
+ - Console.log progress messages help users track long-running operations
57
+ - The style option is prepended to each scene prompt for consistent styling
58
+ ---
59
+ ## 2026-01-15 23:15 - STORY-002
60
+ - Implemented character consistency feature for storyboard videos
61
+ - Files changed:
62
+ - src/tools/video/storyboard-video.ts (modified) - Added characterDescription and referenceImages options
63
+ - **Learnings for future iterations:**
64
+ - Character consistency uses two complementary approaches: text description prepended to prompts + reference images
65
+ - Reference images are loaded from file paths and converted to ReferenceImage objects with buffers
66
+ - GeminiProvider.generateVideoWithReferences() uses the same options as generateVideo()
67
+ - When both characterDescription and referenceImages are provided, they work together for maximum consistency
68
+ - The prompt building order is: characterDescription + style + scene description
69
+ - Import readFile from 'fs/promises' to load reference image buffers
70
+ - Reference images max limit is 3 (validated before loading)
71
+ - Console.log messages help users understand what consistency features are being used
72
+ ---
73
+ ## 2026-01-15 22:17 - STORY-003
74
+ - Implemented audio control options for storyboard video generation
75
+ - Files changed:
76
+ - src/tools/video/storyboard-video.ts (modified) - Added audio options and mixing logic
77
+ - **Learnings for future iterations:**
78
+ - The addAudioTrack() FFmpeg utility already handles mixing native video audio with background music using amix filter
79
+ - Audio mixing happens AFTER stitching - create temporary stitched video, then mix audio, then clean up
80
+ - Use two-stage output path approach: stitchedVideoPath (temp if music) vs outputPath (final)
81
+ - musicVolume parameter controls background music level (0.0-1.0), native audio stays at full volume
82
+ - Console.log progress messages help users understand when audio mixing is happening
83
+ - generateAudio option is passed directly to Veo API calls to control native audio generation
84
+ - All acceptance criteria met: generateAudio option, backgroundMusic option, musicVolume control, proper mixing
85
+ ---
86
+ ## 2026-01-15 22:30 - STORY-004
87
+ - Enhanced progress reporting for storyboard video generation
88
+ - Files changed:
89
+ - src/tools/video/storyboard-video.ts (modified) - Enhanced progress logging throughout
90
+ - **Learnings for future iterations:**
91
+ - Progress reporting should be comprehensive and structured: initial config summary → per-scene progress → stitching phase → completion summary
92
+ - Use consistent formatting with indentation for hierarchical progress messages: top-level operations without indent, sub-operations with 3-space indent
93
+ - Show configuration upfront so users understand what's happening before long operations begin
94
+ - Include timing metrics in summary: total time, average per-scene time, success rate
95
+ - Progress format "[X/Y]" is clearer than "X/Y" when mixed with descriptive text
96
+ - Calculate derived metrics (avg scene time, success rate) to give users actionable insights
97
+ - Use emojis consistently for visual categorization: 🎬 for storyboard ops, 📹 for scenes, 🎞️ for stitching, ✨ for completion
98
+ - Always show output path at the end so users know where to find their result
99
+ ---
100
+ ## 2026-01-15 22:42 - EXTEND-001
101
+ - Implemented extend_video tool for extending existing videos with new content
102
+ - Files changed:
103
+ - src/tools/video/extend-video.ts (new) - Complete extend video tool implementation
104
+ - src/index.ts (modified) - Added extend-video export
105
+ - **Learnings for future iterations:**
106
+ - Tools follow consistent pattern: options interface, result interface, main function
107
+ - GeminiProvider.extendVideo() wraps Veo 3.1 video extension API with automatic polling
108
+ - Read input video with readFile from 'fs/promises', pass buffer to provider
109
+ - Progress logging pattern from STORY-004 is valuable for all long-running operations
110
+ - Tool exports must be added to src/index.ts for public API access
111
+ - TypeScript strict mode validates all option types and return types
112
+ - Use tmpdir() for default output paths with timestamp to avoid collisions
113
+ - The extend video API is simpler than generate - just video buffer + prompt + options
114
+ ---
115
+ ## 2026-01-15 23:45 - TEST-001
116
+ - Implemented comprehensive integration tests for storyboard video generation
117
+ - Files changed:
118
+ - tests/video/storyboard.test.ts (new) - 20 integration tests covering all functionality
119
+ - prd.json (modified) - Marked TEST-001 as complete
120
+ - **Learnings for future iterations:**
121
+ - Bun test runner doesn't support vi.mocked() helper - use type casting (ffmpeg.func as any).mockX() instead
122
+ - Don't use vi.clearAllTimers() - not available in this test environment
123
+ - Integration tests should verify complete workflows: API calls → file operations → stitching → cleanup
124
+ - Test error paths are important: partial failures, total failures, and edge cases
125
+ - Mocked operations complete instantly, so totalTime may be 0 - use toBeGreaterThanOrEqual(0) instead of toBeGreaterThan(0)
126
+ - Organize tests by feature area with describe blocks for better readability
127
+ - Test both happy path and error scenarios for robust coverage
128
+ - All 20 tests passing: multi-scene generation, FFmpeg stitching, transitions, character consistency, error handling, progress reporting
129
+ ---
130
+ ## 2026-01-15 22:37 - DOCS-001
131
+ - Created comprehensive README.md with complete documentation
132
+ - Files changed:
133
+ - README.md (new) - 513 lines of comprehensive documentation
134
+ - prd.json (modified) - Marked DOCS-001 as complete
135
+ - **Learnings for future iterations:**
136
+ - README should be comprehensive yet scannable - use clear sections and hierarchies
137
+ - Include both API reference (parameters, types) and practical examples (code snippets)
138
+ - Document requirements prominently (FFmpeg, Node version) early in the README
139
+ - Best practices section helps users avoid common pitfalls
140
+ - Multiple examples for different use cases (basic, advanced, edge cases) improve usability
141
+ - Troubleshooting section addresses common setup issues proactively
142
+ - Progress logging output in examples helps users understand what to expect
143
+ - The README serves both as reference documentation and tutorial/guide
144
+ - Include TypeScript type definitions reference for better developer experience
145
+ ---
@@ -0,0 +1,297 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Ralph Report - opencode-nanobanana</title>
7
+ <style>
8
+ * { box-sizing: border-box; margin: 0; padding: 0; }
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
11
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
12
+ color: #e2e8f0;
13
+ min-height: 100vh;
14
+ padding: 2rem;
15
+ }
16
+ .container { max-width: 1200px; margin: 0 auto; }
17
+ h1 {
18
+ font-size: 2.5rem;
19
+ margin-bottom: 0.5rem;
20
+ background: linear-gradient(90deg, #60a5fa, #a78bfa);
21
+ -webkit-background-clip: text;
22
+ -webkit-text-fill-color: transparent;
23
+ }
24
+ .subtitle { color: #94a3b8; margin-bottom: 2rem; }
25
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin-bottom: 2rem; }
26
+ .card {
27
+ background: rgba(255,255,255,0.05);
28
+ border: 1px solid rgba(255,255,255,0.1);
29
+ border-radius: 1rem;
30
+ padding: 1.5rem;
31
+ backdrop-filter: blur(10px);
32
+ }
33
+ .card-title { font-size: 0.875rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
34
+ .card-value { font-size: 2rem; font-weight: 700; }
35
+ .status-badge {
36
+ display: inline-flex;
37
+ align-items: center;
38
+ gap: 0.5rem;
39
+ padding: 0.5rem 1rem;
40
+ border-radius: 9999px;
41
+ font-weight: 600;
42
+ background: #3b82f622;
43
+ color: #3b82f6;
44
+ border: 1px solid #3b82f644;
45
+ }
46
+ .section { margin-bottom: 2rem; }
47
+ .section-title { font-size: 1.25rem; margin-bottom: 1rem; color: #f1f5f9; }
48
+ table { width: 100%; border-collapse: collapse; }
49
+ th, td { padding: 0.75rem 1rem; text-align: left; border-bottom: 1px solid rgba(255,255,255,0.1); }
50
+ th { color: #94a3b8; font-weight: 500; font-size: 0.875rem; text-transform: uppercase; }
51
+ tr:hover { background: rgba(255,255,255,0.03); }
52
+ .event-type {
53
+ display: inline-block;
54
+ padding: 0.25rem 0.5rem;
55
+ border-radius: 0.25rem;
56
+ font-size: 0.75rem;
57
+ font-weight: 600;
58
+ text-transform: uppercase;
59
+ }
60
+ .event-complete { background: #22c55e22; color: #22c55e; }
61
+ .event-restart { background: #f59e0b22; color: #f59e0b; }
62
+ .event-error { background: #ef444422; color: #ef4444; }
63
+ .event-start { background: #3b82f622; color: #3b82f6; }
64
+ .event-info { background: #6b728022; color: #94a3b8; }
65
+ .progress-bar {
66
+ height: 8px;
67
+ background: rgba(255,255,255,0.1);
68
+ border-radius: 4px;
69
+ overflow: hidden;
70
+ margin-top: 0.5rem;
71
+ }
72
+ .progress-fill {
73
+ height: 100%;
74
+ background: linear-gradient(90deg, #22c55e, #3b82f6);
75
+ border-radius: 4px;
76
+ transition: width 0.3s ease;
77
+ }
78
+ .duration-comparison {
79
+ display: flex;
80
+ align-items: center;
81
+ gap: 0.5rem;
82
+ }
83
+ .faster { color: #22c55e; }
84
+ .slower { color: #f59e0b; }
85
+ .timestamp { color: #64748b; font-size: 0.875rem; }
86
+ .empty-state { text-align: center; padding: 3rem; color: #64748b; }
87
+ footer { margin-top: 3rem; text-align: center; color: #64748b; font-size: 0.875rem; }
88
+ </style>
89
+ </head>
90
+ <body>
91
+ <div class="container">
92
+ <header>
93
+ <h1>Ralph Report</h1>
94
+ <p class="subtitle">opencode-nanobanana on macos</p>
95
+ </header>
96
+
97
+ <div class="grid">
98
+ <div class="card">
99
+ <div class="card-title">Status</div>
100
+ <div class="status-badge">
101
+ <span>⟳</span>
102
+ <span>running</span>
103
+ </div>
104
+ </div>
105
+ <div class="card">
106
+ <div class="card-title">Stories Completed</div>
107
+ <div class="card-value">4 / 12</div>
108
+ </div>
109
+ <div class="card">
110
+ <div class="card-title">Total Time</div>
111
+ <div class="card-value">25m</div>
112
+ <div class="progress-bar">
113
+ <div class="progress-fill" style="width: 31%"></div>
114
+ </div>
115
+ <div style="font-size: 0.875rem; color: #64748b; margin-top: 0.25rem;">vs 1h 20m estimated</div>
116
+ </div>
117
+ <div class="card">
118
+ <div class="card-title">ETA</div>
119
+ <div class="card-value" style="color: #60a5fa">24m</div>
120
+ <div style="font-size: 0.875rem; color: #64748b; margin-top: 0.25rem;">~2026-01-15 22:50 (medium)</div>
121
+ </div>
122
+ </div>
123
+
124
+ <div class="grid">
125
+ <div class="card">
126
+ <div class="card-title">Files Changed</div>
127
+ <div class="card-value">43</div>
128
+ </div>
129
+ <div class="card">
130
+ <div class="card-title">Lines Added</div>
131
+ <div class="card-value" style="color: #22c55e">+3030</div>
132
+ </div>
133
+ <div class="card">
134
+ <div class="card-title">Lines Removed</div>
135
+ <div class="card-value" style="color: #ef4444">-263</div>
136
+ </div>
137
+ <div class="card">
138
+ <div class="card-title">Restarts</div>
139
+ <div class="card-value" style="color: #22c55e">0</div>
140
+ </div>
141
+ </div>
142
+
143
+ <div class="grid">
144
+ <div class="card">
145
+ <div class="card-title">Total Cost</div>
146
+ <div class="card-value" style="color: #a78bfa">$11.37</div>
147
+ </div>
148
+ <div class="card">
149
+ <div class="card-title">Input Tokens</div>
150
+ <div class="card-value">241.3K</div>
151
+ </div>
152
+ <div class="card">
153
+ <div class="card-title">Output Tokens</div>
154
+ <div class="card-value">709.4K</div>
155
+ </div>
156
+ <div class="card">
157
+ <div class="card-title">Total Tokens</div>
158
+ <div class="card-value">950.8K</div>
159
+ </div>
160
+ </div>
161
+
162
+ <div class="section">
163
+ <h2 class="section-title">Stories Completed</h2>
164
+ <div class="card">
165
+ <table>
166
+ <thead>
167
+ <tr>
168
+ <th>Story</th>
169
+ <th>Duration</th>
170
+ <th>Estimate</th>
171
+ <th>Diff</th>
172
+ <th>Files</th>
173
+ <th>Lines</th>
174
+ <th>Completed</th>
175
+ </tr>
176
+ </thead>
177
+ <tbody>
178
+ <tr>
179
+ <td><strong>VEO3-001</strong></td>
180
+ <td>10m</td>
181
+ <td>20m</td>
182
+ <td class="faster">-10m</td>
183
+ <td>7</td>
184
+ <td><span class="faster">+834</span>/<span class="slower">-219</span></td>
185
+ <td class="timestamp">2026-01-15T22:11:20+01:00</td>
186
+ </tr>
187
+ <tr>
188
+ <td><strong>FFMPEG-001</strong></td>
189
+ <td>5m</td>
190
+ <td>20m</td>
191
+ <td class="faster">-15m</td>
192
+ <td>6</td>
193
+ <td><span class="faster">+829</span>/<span class="slower">-3</span></td>
194
+ <td class="timestamp">2026-01-15T22:16:23+01:00</td>
195
+ </tr>
196
+ <tr>
197
+ <td><strong>STORY-002</strong></td>
198
+ <td>5m</td>
199
+ <td>20m</td>
200
+ <td class="faster">-15m</td>
201
+ <td>22</td>
202
+ <td><span class="faster">+1204</span>/<span class="slower">-13</span></td>
203
+ <td class="timestamp">2026-01-15T22:21:26+01:00</td>
204
+ </tr>
205
+ <tr>
206
+ <td><strong>STORY-003</strong></td>
207
+ <td>5m</td>
208
+ <td>20m</td>
209
+ <td class="faster">-15m</td>
210
+ <td>8</td>
211
+ <td><span class="faster">+163</span>/<span class="slower">-28</span></td>
212
+ <td class="timestamp">2026-01-15T22:26:28+01:00</td>
213
+ </tr>
214
+ </tbody>
215
+ </table>
216
+ </div>
217
+ </div>
218
+
219
+ <div class="section">
220
+ <h2 class="section-title">Restarts</h2>
221
+ <div class="card">
222
+ <table>
223
+ <thead>
224
+ <tr>
225
+ <th>Reason</th>
226
+ <th>Story</th>
227
+ <th>Time</th>
228
+ </tr>
229
+ </thead>
230
+ <tbody>
231
+ <tr><td colspan="3" class="empty-state">No restarts - clean run!</td></tr>
232
+ </tbody>
233
+ </table>
234
+ </div>
235
+ </div>
236
+
237
+ <div class="section">
238
+ <h2 class="section-title">Event Timeline</h2>
239
+ <div class="card">
240
+ <table>
241
+ <thead>
242
+ <tr>
243
+ <th>Type</th>
244
+ <th>Message</th>
245
+ <th>Story</th>
246
+ <th>Time</th>
247
+ </tr>
248
+ </thead>
249
+ <tbody>
250
+ <tr>
251
+ <td><span class="event-type event-start">started</span></td>
252
+ <td>Monitor started for opencode-nanobanana</td>
253
+ <td></td>
254
+ <td class="timestamp">2026-01-15T22:01:15+01:00</td>
255
+ </tr>
256
+ <tr>
257
+ <td><span class="event-type event-start">start</span></td>
258
+ <td>Ralph started</td>
259
+ <td>VEO3-001</td>
260
+ <td class="timestamp">2026-01-15T22:01:18+01:00</td>
261
+ </tr>
262
+ <tr>
263
+ <td><span class="event-type event-complete">story_complete</span></td>
264
+ <td>Completed: VEO3-001 in 10m</td>
265
+ <td>VEO3-001</td>
266
+ <td class="timestamp">2026-01-15T22:11:20+01:00</td>
267
+ </tr>
268
+ <tr>
269
+ <td><span class="event-type event-complete">story_complete</span></td>
270
+ <td>Completed: FFMPEG-001 in 5m</td>
271
+ <td>FFMPEG-001</td>
272
+ <td class="timestamp">2026-01-15T22:16:23+01:00</td>
273
+ </tr>
274
+ <tr>
275
+ <td><span class="event-type event-complete">story_complete</span></td>
276
+ <td>Completed: STORY-002 in 5m</td>
277
+ <td>STORY-002</td>
278
+ <td class="timestamp">2026-01-15T22:21:26+01:00</td>
279
+ </tr>
280
+ <tr>
281
+ <td><span class="event-type event-complete">story_complete</span></td>
282
+ <td>Completed: STORY-003 in 5m</td>
283
+ <td>STORY-003</td>
284
+ <td class="timestamp">2026-01-15T22:26:28+01:00</td>
285
+ </tr>
286
+ </tbody>
287
+ </table>
288
+ </div>
289
+ </div>
290
+
291
+ <footer>
292
+ <p>Generated by Ralph Monitor on 2026-01-15 22:26:30</p>
293
+ <p>Started: 2026-01-15T22:01:15+01:00 | Ended: running</p>
294
+ </footer>
295
+ </div>
296
+ </body>
297
+ </html>