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.
- package/.ralph-events.json +151 -0
- package/.ralph-last-branch +1 -0
- package/.ralph-monitor-state.json +7 -0
- package/.ralph-monitor.pid +1 -0
- package/.ralph-timing.json +26 -0
- package/README.md +708 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/platforms/android.d.ts +94 -0
- package/dist/platforms/android.d.ts.map +1 -0
- package/dist/platforms/android.js +123 -0
- package/dist/platforms/android.js.map +1 -0
- package/dist/platforms/ios.d.ts +51 -0
- package/dist/platforms/ios.d.ts.map +1 -0
- package/dist/platforms/ios.js +149 -0
- package/dist/platforms/ios.js.map +1 -0
- package/dist/platforms/macos.d.ts +33 -0
- package/dist/platforms/macos.d.ts.map +1 -0
- package/dist/platforms/macos.js +50 -0
- package/dist/platforms/macos.js.map +1 -0
- package/dist/platforms/watchos.d.ts +36 -0
- package/dist/platforms/watchos.d.ts.map +1 -0
- package/dist/platforms/watchos.js +113 -0
- package/dist/platforms/watchos.js.map +1 -0
- package/dist/platforms/web.d.ts +64 -0
- package/dist/platforms/web.d.ts.map +1 -0
- package/dist/platforms/web.js +96 -0
- package/dist/platforms/web.js.map +1 -0
- package/dist/providers/gemini.d.ts +41 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +177 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/tools/analyze/compare.d.ts +12 -0
- package/dist/tools/analyze/compare.d.ts.map +1 -0
- package/dist/tools/analyze/compare.js +83 -0
- package/dist/tools/analyze/compare.js.map +1 -0
- package/dist/tools/analyze/mockup.d.ts +12 -0
- package/dist/tools/analyze/mockup.d.ts.map +1 -0
- package/dist/tools/analyze/mockup.js +88 -0
- package/dist/tools/analyze/mockup.js.map +1 -0
- package/dist/tools/analyze/screenshot.d.ts +12 -0
- package/dist/tools/analyze/screenshot.d.ts.map +1 -0
- package/dist/tools/analyze/screenshot.js +61 -0
- package/dist/tools/analyze/screenshot.js.map +1 -0
- package/dist/tools/app-assets/app-icon.d.ts +9 -0
- package/dist/tools/app-assets/app-icon.d.ts.map +1 -0
- package/dist/tools/app-assets/app-icon.js +133 -0
- package/dist/tools/app-assets/app-icon.js.map +1 -0
- package/dist/tools/app-assets/device-mockup.d.ts +9 -0
- package/dist/tools/app-assets/device-mockup.d.ts.map +1 -0
- package/dist/tools/app-assets/device-mockup.js +139 -0
- package/dist/tools/app-assets/device-mockup.js.map +1 -0
- package/dist/tools/app-assets/launch-images.d.ts +3 -0
- package/dist/tools/app-assets/launch-images.d.ts.map +1 -0
- package/dist/tools/app-assets/launch-images.js +171 -0
- package/dist/tools/app-assets/launch-images.js.map +1 -0
- package/dist/tools/app-assets/resize-devices.d.ts +14 -0
- package/dist/tools/app-assets/resize-devices.d.ts.map +1 -0
- package/dist/tools/app-assets/resize-devices.js +296 -0
- package/dist/tools/app-assets/resize-devices.js.map +1 -0
- package/dist/tools/app-assets/screenshots.d.ts +14 -0
- package/dist/tools/app-assets/screenshots.d.ts.map +1 -0
- package/dist/tools/app-assets/screenshots.js +186 -0
- package/dist/tools/app-assets/screenshots.js.map +1 -0
- package/dist/tools/core/edit-image.d.ts +12 -0
- package/dist/tools/core/edit-image.d.ts.map +1 -0
- package/dist/tools/core/edit-image.js +102 -0
- package/dist/tools/core/edit-image.js.map +1 -0
- package/dist/tools/core/generate-image.d.ts +12 -0
- package/dist/tools/core/generate-image.d.ts.map +1 -0
- package/dist/tools/core/generate-image.js +96 -0
- package/dist/tools/core/generate-image.js.map +1 -0
- package/dist/tools/core/restore-image.d.ts +12 -0
- package/dist/tools/core/restore-image.d.ts.map +1 -0
- package/dist/tools/core/restore-image.js +104 -0
- package/dist/tools/core/restore-image.js.map +1 -0
- package/dist/tools/design/mockup-to-code.d.ts +3 -0
- package/dist/tools/design/mockup-to-code.d.ts.map +1 -0
- package/dist/tools/design/mockup-to-code.js +311 -0
- package/dist/tools/design/mockup-to-code.js.map +1 -0
- package/dist/tools/design/sketch-to-code.d.ts +3 -0
- package/dist/tools/design/sketch-to-code.d.ts.map +1 -0
- package/dist/tools/design/sketch-to-code.js +325 -0
- package/dist/tools/design/sketch-to-code.js.map +1 -0
- package/dist/tools/docs/architecture-diagram.d.ts +12 -0
- package/dist/tools/docs/architecture-diagram.d.ts.map +1 -0
- package/dist/tools/docs/architecture-diagram.js +179 -0
- package/dist/tools/docs/architecture-diagram.js.map +1 -0
- package/dist/tools/docs/readme-banner.d.ts +6 -0
- package/dist/tools/docs/readme-banner.d.ts.map +1 -0
- package/dist/tools/docs/readme-banner.js +108 -0
- package/dist/tools/docs/readme-banner.js.map +1 -0
- package/dist/tools/docs/sequence-diagram.d.ts +12 -0
- package/dist/tools/docs/sequence-diagram.d.ts.map +1 -0
- package/dist/tools/docs/sequence-diagram.js +161 -0
- package/dist/tools/docs/sequence-diagram.js.map +1 -0
- package/dist/tools/docs/social-preview.d.ts +11 -0
- package/dist/tools/docs/social-preview.d.ts.map +1 -0
- package/dist/tools/docs/social-preview.js +111 -0
- package/dist/tools/docs/social-preview.js.map +1 -0
- package/dist/tools/video/extend-video.d.ts +14 -0
- package/dist/tools/video/extend-video.d.ts.map +1 -0
- package/dist/tools/video/extend-video.js +39 -0
- package/dist/tools/video/extend-video.js.map +1 -0
- package/dist/tools/video/generate-video.d.ts +14 -0
- package/dist/tools/video/generate-video.d.ts.map +1 -0
- package/dist/tools/video/generate-video.js +39 -0
- package/dist/tools/video/generate-video.js.map +1 -0
- package/dist/tools/video/image-to-video.d.ts +15 -0
- package/dist/tools/video/image-to-video.d.ts.map +1 -0
- package/dist/tools/video/image-to-video.js +42 -0
- package/dist/tools/video/image-to-video.js.map +1 -0
- package/dist/tools/video/storyboard-video.d.ts +91 -0
- package/dist/tools/video/storyboard-video.d.ts.map +1 -0
- package/dist/tools/video/storyboard-video.js +230 -0
- package/dist/tools/video/storyboard-video.js.map +1 -0
- package/dist/utils/ffmpeg.d.ts +30 -0
- package/dist/utils/ffmpeg.d.ts.map +1 -0
- package/dist/utils/ffmpeg.js +205 -0
- package/dist/utils/ffmpeg.js.map +1 -0
- package/dist/utils/file-handler.d.ts +7 -0
- package/dist/utils/file-handler.d.ts.map +1 -0
- package/dist/utils/file-handler.js +10 -0
- package/dist/utils/file-handler.js.map +1 -0
- package/dist/utils/image-processing.d.ts +7 -0
- package/dist/utils/image-processing.d.ts.map +1 -0
- package/dist/utils/image-processing.js +10 -0
- package/dist/utils/image-processing.js.map +1 -0
- package/docs/PLUGIN-VERIFICATION.md +182 -0
- package/logs/notifications.jsonl +46 -0
- package/package.json +61 -0
- package/prd.json +216 -0
- package/progress.txt +145 -0
- package/ralph-report.html +297 -0
- package/src/index.ts +23 -0
- package/src/platforms/android/.gitkeep +0 -0
- package/src/platforms/ios/.gitkeep +0 -0
- package/src/platforms/web/.gitkeep +0 -0
- package/src/providers/.gitkeep +0 -0
- package/src/providers/gemini.ts +288 -0
- package/src/tools/core/.gitkeep +0 -0
- package/src/tools/platform/.gitkeep +0 -0
- package/src/tools/video/extend-video.ts +71 -0
- package/src/tools/video/generate-video.ts +70 -0
- package/src/tools/video/image-to-video.ts +76 -0
- package/src/tools/video/storyboard-video.ts +325 -0
- package/src/utils/.gitkeep +0 -0
- package/src/utils/ffmpeg.ts +266 -0
- package/src/utils/file-handler.ts +10 -0
- package/src/utils/image-processing.ts +10 -0
- package/templates/.gitkeep +0 -0
- package/test-analyze-screenshot.ts +50 -0
- package/test-app-icons.ts +55 -0
- package/test-cat-sunset.ts +30 -0
- package/test-full-plugin.ts +88 -0
- package/test-icon-gen.ts +30 -0
- package/test-output/test-edit.png +0 -0
- package/test-output/test-generate.png +0 -0
- package/test-output/test-video.mp4 +0 -0
- package/test-plugin-load.js +45 -0
- package/test-princess-emma-continue.ts +35 -0
- package/test-princess-emma-full.ts +38 -0
- package/test-princess-emma-short.ts +32 -0
- package/test-princess-emma-with-reference.ts +34 -0
- package/test-princess-emma.ts +38 -0
- package/test-product-ad.ts +66 -0
- package/test-ralph-droid.ts +30 -0
- package/test-social-preview.ts +61 -0
- package/test-veo31-live.ts +187 -0
- package/test-video-gen.ts +40 -0
- package/test-video-veo.ts +73 -0
- package/test-zurich-video.ts +64 -0
- package/tests/.gitkeep +0 -0
- package/tests/providers/gemini.test.ts +388 -0
- package/tests/utils/ffmpeg.test.ts +328 -0
- package/tests/video/storyboard.test.ts +469 -0
- 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>
|