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
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FFmpeg Utility Module
|
|
3
|
+
*
|
|
4
|
+
* Provides video processing operations using FFmpeg
|
|
5
|
+
*/
|
|
6
|
+
import { exec } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
/**
|
|
11
|
+
* Check if FFmpeg is installed and available
|
|
12
|
+
*/
|
|
13
|
+
export async function checkFfmpegInstalled() {
|
|
14
|
+
try {
|
|
15
|
+
await execAsync('ffmpeg -version');
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get the duration of a video in seconds
|
|
24
|
+
*/
|
|
25
|
+
export async function getVideoDuration(videoPath) {
|
|
26
|
+
if (!existsSync(videoPath)) {
|
|
27
|
+
throw new Error(`Video file not found: ${videoPath}`);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const { stdout } = await execAsync(`ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${videoPath}"`);
|
|
31
|
+
const duration = parseFloat(stdout.trim());
|
|
32
|
+
if (isNaN(duration)) {
|
|
33
|
+
throw new Error(`Failed to parse video duration: ${stdout}`);
|
|
34
|
+
}
|
|
35
|
+
return duration;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw new Error(`Failed to get video duration: ${error instanceof Error ? error.message : String(error)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Trim a video from startTime for the specified duration
|
|
43
|
+
*/
|
|
44
|
+
export async function trimVideo(videoPath, startTime, duration, outputPath) {
|
|
45
|
+
if (!existsSync(videoPath)) {
|
|
46
|
+
throw new Error(`Video file not found: ${videoPath}`);
|
|
47
|
+
}
|
|
48
|
+
if (startTime < 0 || duration <= 0) {
|
|
49
|
+
throw new Error(`Invalid trim parameters: startTime=${startTime}, duration=${duration}`);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
await execAsync(`ffmpeg -i "${videoPath}" -ss ${startTime} -t ${duration} -c copy "${outputPath}" -y`);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
throw new Error(`Failed to trim video: ${error instanceof Error ? error.message : String(error)}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Add an audio track to a video
|
|
60
|
+
*/
|
|
61
|
+
export async function addAudioTrack(videoPath, audioPath, outputPath, volume = 1.0) {
|
|
62
|
+
if (!existsSync(videoPath)) {
|
|
63
|
+
throw new Error(`Video file not found: ${videoPath}`);
|
|
64
|
+
}
|
|
65
|
+
if (!existsSync(audioPath)) {
|
|
66
|
+
throw new Error(`Audio file not found: ${audioPath}`);
|
|
67
|
+
}
|
|
68
|
+
if (volume < 0 || volume > 1) {
|
|
69
|
+
throw new Error(`Volume must be between 0 and 1, got: ${volume}`);
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
// Mix video audio with background audio, adjust volume of background
|
|
73
|
+
await execAsync(`ffmpeg -i "${videoPath}" -i "${audioPath}" -filter_complex "[1:a]volume=${volume}[a1];[0:a][a1]amix=inputs=2:duration=first[aout]" -map 0:v -map "[aout]" -c:v copy -c:a aac "${outputPath}" -y`);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
throw new Error(`Failed to add audio track: ${error instanceof Error ? error.message : String(error)}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Concatenate multiple videos with transitions
|
|
81
|
+
*/
|
|
82
|
+
export async function concatenateVideos(videoPaths, outputPath, options = {}) {
|
|
83
|
+
if (videoPaths.length === 0) {
|
|
84
|
+
throw new Error('No videos provided for concatenation');
|
|
85
|
+
}
|
|
86
|
+
// Check all input files exist
|
|
87
|
+
for (const videoPath of videoPaths) {
|
|
88
|
+
if (!existsSync(videoPath)) {
|
|
89
|
+
throw new Error(`Video file not found: ${videoPath}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const { transition = 'crossfade', transitionDuration = 0.5 } = options;
|
|
93
|
+
try {
|
|
94
|
+
if (transition === 'cut') {
|
|
95
|
+
// Simple concatenation without transitions
|
|
96
|
+
await concatenateWithCut(videoPaths, outputPath);
|
|
97
|
+
}
|
|
98
|
+
else if (transition === 'crossfade') {
|
|
99
|
+
// Crossfade transition between videos
|
|
100
|
+
await concatenateWithCrossfade(videoPaths, outputPath, transitionDuration);
|
|
101
|
+
}
|
|
102
|
+
else if (transition === 'fade') {
|
|
103
|
+
// Fade to black transition between videos
|
|
104
|
+
await concatenateWithFade(videoPaths, outputPath, transitionDuration);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
throw new Error(`Unknown transition type: ${transition}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
throw new Error(`Failed to concatenate videos: ${error instanceof Error ? error.message : String(error)}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Concatenate videos with simple cut (no transition)
|
|
116
|
+
*/
|
|
117
|
+
async function concatenateWithCut(videoPaths, outputPath) {
|
|
118
|
+
// Create a temporary concat file
|
|
119
|
+
const concatListPath = outputPath + '.concat.txt';
|
|
120
|
+
const fs = await import('fs/promises');
|
|
121
|
+
const concatContent = videoPaths.map(path => `file '${path}'`).join('\n');
|
|
122
|
+
await fs.writeFile(concatListPath, concatContent);
|
|
123
|
+
try {
|
|
124
|
+
await execAsync(`ffmpeg -f concat -safe 0 -i "${concatListPath}" -c copy "${outputPath}" -y`);
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
// Clean up concat file
|
|
128
|
+
await fs.unlink(concatListPath).catch(() => { });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function concatenateWithCrossfade(videoPaths, outputPath, transitionDuration) {
|
|
132
|
+
if (videoPaths.length === 1) {
|
|
133
|
+
const fs = await import('fs/promises');
|
|
134
|
+
const firstVideo = videoPaths[0];
|
|
135
|
+
if (!firstVideo) {
|
|
136
|
+
throw new Error('No video path provided');
|
|
137
|
+
}
|
|
138
|
+
await fs.copyFile(firstVideo, outputPath);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const durations = [];
|
|
142
|
+
for (const videoPath of videoPaths) {
|
|
143
|
+
const dur = await getVideoDuration(videoPath);
|
|
144
|
+
durations.push(dur);
|
|
145
|
+
}
|
|
146
|
+
let filterComplex = '';
|
|
147
|
+
let audioFilterComplex = '';
|
|
148
|
+
let currentVideoLabel = '[0:v]';
|
|
149
|
+
let currentAudioLabel = '[0:a]';
|
|
150
|
+
let cumulativeOffset = durations[0] - transitionDuration;
|
|
151
|
+
for (let i = 1; i < videoPaths.length; i++) {
|
|
152
|
+
const isLast = i === videoPaths.length - 1;
|
|
153
|
+
const nextVideoLabel = isLast ? '[outv]' : `[v${i}]`;
|
|
154
|
+
const nextAudioLabel = isLast ? '[outa]' : `[a${i}]`;
|
|
155
|
+
filterComplex += `${currentVideoLabel}[${i}:v]xfade=transition=fade:duration=${transitionDuration}:offset=${cumulativeOffset}${nextVideoLabel};`;
|
|
156
|
+
audioFilterComplex += `${currentAudioLabel}[${i}:a]acrossfade=d=${transitionDuration}${nextAudioLabel};`;
|
|
157
|
+
currentVideoLabel = nextVideoLabel;
|
|
158
|
+
currentAudioLabel = nextAudioLabel;
|
|
159
|
+
if (!isLast) {
|
|
160
|
+
cumulativeOffset += durations[i] - transitionDuration;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const fullFilter = filterComplex + audioFilterComplex.slice(0, -1);
|
|
164
|
+
const inputs = videoPaths.map(path => `-i "${path}"`).join(' ');
|
|
165
|
+
await execAsync(`ffmpeg ${inputs} -filter_complex "${fullFilter}" -map "[outv]" -map "[outa]" "${outputPath}" -y`);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Concatenate videos with fade to black transition
|
|
169
|
+
*/
|
|
170
|
+
async function concatenateWithFade(videoPaths, outputPath, duration) {
|
|
171
|
+
if (videoPaths.length === 1) {
|
|
172
|
+
// No transition needed for single video
|
|
173
|
+
const fs = await import('fs/promises');
|
|
174
|
+
const firstVideo = videoPaths[0];
|
|
175
|
+
if (!firstVideo) {
|
|
176
|
+
throw new Error('No video path provided');
|
|
177
|
+
}
|
|
178
|
+
await fs.copyFile(firstVideo, outputPath);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// For fade transition, we fade out each clip and fade in the next
|
|
182
|
+
// This is complex with FFmpeg, using a simpler concatenation approach
|
|
183
|
+
const inputs = videoPaths.map(path => `-i "${path}"`).join(' ');
|
|
184
|
+
// Build filter to fade out and fade in
|
|
185
|
+
let filterComplex = '';
|
|
186
|
+
for (let i = 0; i < videoPaths.length; i++) {
|
|
187
|
+
if (i < videoPaths.length - 1) {
|
|
188
|
+
// Fade out at the end of each video except the last
|
|
189
|
+
filterComplex += `[${i}:v]fade=t=out:st=0:d=${duration}[v${i}out];`;
|
|
190
|
+
// Fade in at the start of next video
|
|
191
|
+
filterComplex += `[${i + 1}:v]fade=t=in:st=0:d=${duration}[v${i + 1}in];`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Concatenate the faded segments
|
|
195
|
+
const concatInputs = videoPaths.map((_, i) => {
|
|
196
|
+
if (i === 0)
|
|
197
|
+
return '[v0out]';
|
|
198
|
+
if (i === videoPaths.length - 1)
|
|
199
|
+
return `[v${i}in]`;
|
|
200
|
+
return `[v${i}out][v${i}in]`;
|
|
201
|
+
}).join('');
|
|
202
|
+
filterComplex += `${concatInputs}concat=n=${videoPaths.length}:v=1:a=0[outv]`;
|
|
203
|
+
await execAsync(`ffmpeg ${inputs} -filter_complex "${filterComplex}" -map "[outv]" "${outputPath}" -y`);
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=ffmpeg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../../src/utils/ffmpeg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-handler.d.ts","sourceRoot":"","sources":["../../src/utils/file-handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-handler.js","sourceRoot":"","sources":["../../src/utils/file-handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,gDAAgD;IAChD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-processing.d.ts","sourceRoot":"","sources":["../../src/utils/image-processing.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5F"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Processing Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utilities for processing and manipulating images
|
|
5
|
+
*/
|
|
6
|
+
export function resizeImage(buffer, _width, _height) {
|
|
7
|
+
// Placeholder - will be implemented when needed
|
|
8
|
+
return Promise.resolve(buffer);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=image-processing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-processing.js","sourceRoot":"","sources":["../../src/utils/image-processing.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,MAAc,EAAE,OAAe;IACzE,gDAAgD;IAChD,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Plugin Verification Guide
|
|
2
|
+
|
|
3
|
+
## How to Verify OpenCode Visual Toolkit Has Loaded
|
|
4
|
+
|
|
5
|
+
### ✅ Plugin Is Now Installed
|
|
6
|
+
|
|
7
|
+
The plugin is installed at:
|
|
8
|
+
- **Location**: `~/.config/opencode/node_modules/opencode-visual-toolkit/`
|
|
9
|
+
- **Type**: Symlinked (any changes to source will reflect immediately)
|
|
10
|
+
- **Status**: ✓ Installed successfully
|
|
11
|
+
|
|
12
|
+
### Method 1: Check Package.json (Quickest)
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cat ~/.config/opencode/package.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
You should see:
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"opencode-visual-toolkit": "file:///Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Method 2: Run the Test Script
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cd /Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana
|
|
31
|
+
node test-plugin-load.js
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Expected output:
|
|
35
|
+
```
|
|
36
|
+
✅ Plugin loaded successfully!
|
|
37
|
+
✓ Plugin has 19 tools registered:
|
|
38
|
+
• generate_image
|
|
39
|
+
• edit_image
|
|
40
|
+
• restore_image
|
|
41
|
+
• generate_app_icon
|
|
42
|
+
... (and 15 more)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Method 3: Check Symlink
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ls -la ~/.config/opencode/node_modules/ | grep visual
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Should show:
|
|
52
|
+
```
|
|
53
|
+
drwxr-xr-x@ 30 jarvis staff 960 Jan 15 17:47 opencode-visual-toolkit
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Method 4: Use OpenCode Desktop (Final Verification)
|
|
57
|
+
|
|
58
|
+
1. **Restart OpenCode Desktop app** (Important!)
|
|
59
|
+
2. **Start a conversation**
|
|
60
|
+
3. **Try one of these prompts**:
|
|
61
|
+
- "Generate a modern app icon with a gradient background"
|
|
62
|
+
- "Create iOS app icons with a blue rocket"
|
|
63
|
+
- "Analyze this screenshot" (attach an image)
|
|
64
|
+
|
|
65
|
+
4. **Watch for console output**:
|
|
66
|
+
- If loaded: You'll see `🎨 Visual Toolkit Plugin initializing...`
|
|
67
|
+
- If tools work: The AI will use tools like `generate_image` or `generate_app_icon`
|
|
68
|
+
|
|
69
|
+
### Method 5: Check OpenCode Desktop Logs
|
|
70
|
+
|
|
71
|
+
Look for startup messages in Console.app:
|
|
72
|
+
```bash
|
|
73
|
+
# Filter for opencode messages
|
|
74
|
+
log show --predicate 'process == "OpenCode"' --last 5m | grep -i "visual\|toolkit\|plugin"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Look for:
|
|
78
|
+
```
|
|
79
|
+
🎨 Visual Toolkit Plugin initializing...
|
|
80
|
+
✅ Visual Toolkit Plugin initialized successfully
|
|
81
|
+
📦 Registered 19 tools across 6 categories
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 🎯 Available Tools (19 Total)
|
|
85
|
+
|
|
86
|
+
Once loaded, these tools are available to the AI:
|
|
87
|
+
|
|
88
|
+
### Core Image Tools (3)
|
|
89
|
+
- `generate_image` - Create images from text prompts
|
|
90
|
+
- `edit_image` - Modify existing images
|
|
91
|
+
- `restore_image` - Enhance/restore image quality
|
|
92
|
+
|
|
93
|
+
### App Asset Tools (5)
|
|
94
|
+
- `generate_app_icon` - Complete icon sets for iOS/Android
|
|
95
|
+
- `generate_app_screenshots` - App Store screenshots
|
|
96
|
+
- `resize_for_devices` - Device-specific resizing
|
|
97
|
+
- `generate_device_mockup` - Screenshot in device frame
|
|
98
|
+
- `generate_launch_images` - Splash screens
|
|
99
|
+
|
|
100
|
+
### Analysis Tools (3)
|
|
101
|
+
- `analyze_screenshot` - UI/UX analysis
|
|
102
|
+
- `compare_screenshots` - Visual diff
|
|
103
|
+
- `analyze_mockup` - Extract design specs
|
|
104
|
+
|
|
105
|
+
### Design-to-Code Tools (2)
|
|
106
|
+
- `mockup_to_code` - Design → Component code
|
|
107
|
+
- `sketch_to_code` - Wireframe → Component code
|
|
108
|
+
|
|
109
|
+
### Documentation Tools (4)
|
|
110
|
+
- `generate_architecture_diagram` - System diagrams
|
|
111
|
+
- `generate_sequence_diagram` - Interaction flows
|
|
112
|
+
- `generate_readme_banner` - Project banners
|
|
113
|
+
- `generate_social_preview` - OG images
|
|
114
|
+
|
|
115
|
+
### Video Tools (2)
|
|
116
|
+
- `generate_video` - Text-to-video
|
|
117
|
+
- `image_to_video` - Animate static images
|
|
118
|
+
|
|
119
|
+
## 🔧 Troubleshooting
|
|
120
|
+
|
|
121
|
+
### Plugin Not Loading?
|
|
122
|
+
|
|
123
|
+
1. **Check config**:
|
|
124
|
+
```bash
|
|
125
|
+
cat ~/.config/opencode/opencode.json | grep visual
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
2. **Reinstall**:
|
|
129
|
+
```bash
|
|
130
|
+
cd ~/.config/opencode
|
|
131
|
+
bun install file:///Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
3. **Rebuild plugin**:
|
|
135
|
+
```bash
|
|
136
|
+
cd /Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana
|
|
137
|
+
npm run build
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
4. **Restart OpenCode Desktop** completely (quit and relaunch)
|
|
141
|
+
|
|
142
|
+
### Tools Not Working?
|
|
143
|
+
|
|
144
|
+
Check for API key:
|
|
145
|
+
```bash
|
|
146
|
+
echo $GEMINI_API_KEY
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
If empty, set it:
|
|
150
|
+
```bash
|
|
151
|
+
export GEMINI_API_KEY="your-key-here"
|
|
152
|
+
# Or add to ~/.zshrc or ~/.bashrc
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 📝 Quick Test Commands
|
|
156
|
+
|
|
157
|
+
Once OpenCode Desktop is running, try:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
# Simple image generation
|
|
161
|
+
"Generate a sunset over mountains"
|
|
162
|
+
|
|
163
|
+
# App icon creation
|
|
164
|
+
"Create iOS and Android app icons with a blue rocket on gradient"
|
|
165
|
+
|
|
166
|
+
# Screenshot analysis
|
|
167
|
+
"Analyze this screenshot for accessibility issues"
|
|
168
|
+
(attach a screenshot)
|
|
169
|
+
|
|
170
|
+
# Architecture diagram
|
|
171
|
+
"Generate an architecture diagram for a microservices setup with API gateway, auth service, and database"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## ✨ Development Mode
|
|
175
|
+
|
|
176
|
+
Since the plugin is symlinked:
|
|
177
|
+
1. Make changes to source files in `/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana/src/`
|
|
178
|
+
2. Run `npm run build`
|
|
179
|
+
3. Restart OpenCode Desktop
|
|
180
|
+
4. Changes are immediately available!
|
|
181
|
+
|
|
182
|
+
No need to reinstall or republish during development.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{"timestamp": "2026-01-15T22:00:39.792449", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
2
|
+
{"timestamp": "2026-01-15T22:08:18.926305", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "25724116-cbbc-469d-b60e-24067617f91f", "transcript_path": "/Users/jarvis/.claude/projects/-Volumes-DevHub-ext-factory-toolbox-opencode-nanobanana/25724116-cbbc-469d-b60e-24067617f91f.jsonl", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false}}
|
|
3
|
+
{"timestamp": "2026-01-15T22:13:04.118940", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "2b13250f-1fc6-4bd4-862c-f5752242fd97", "transcript_path": "/Users/jarvis/.claude/projects/-Volumes-DevHub-ext-factory-toolbox-opencode-nanobanana/2b13250f-1fc6-4bd4-862c-f5752242fd97.jsonl", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false}}
|
|
4
|
+
{"timestamp": "2026-01-15T22:16:20.750184", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "72cc404d-000a-453f-b92d-694e6ba811f6", "transcript_path": "/Users/jarvis/.claude/projects/-Volumes-DevHub-ext-factory-toolbox-opencode-nanobanana/72cc404d-000a-453f-b92d-694e6ba811f6.jsonl", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false}}
|
|
5
|
+
{"timestamp": "2026-01-15T22:20:17.072795", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "0405b117-b75e-4350-8eb6-461fb17eaf7e", "transcript_path": "/Users/jarvis/.claude/projects/-Volumes-DevHub-ext-factory-toolbox-opencode-nanobanana/0405b117-b75e-4350-8eb6-461fb17eaf7e.jsonl", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false}}
|
|
6
|
+
{"timestamp": "2026-01-15T22:24:05.058329", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "69b9cb0a-2c2a-4246-b624-d52f8ed1984f", "transcript_path": "/Users/jarvis/.claude/projects/-Volumes-DevHub-ext-factory-toolbox-opencode-nanobanana/69b9cb0a-2c2a-4246-b624-d52f8ed1984f.jsonl", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false}}
|
|
7
|
+
{"timestamp": "2026-01-15T22:27:05.038371", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "e9391284-fe17-4b47-a172-4e794f9db2aa", "transcript_path": "/Users/jarvis/.claude/projects/-Volumes-DevHub-ext-factory-toolbox-opencode-nanobanana/e9391284-fe17-4b47-a172-4e794f9db2aa.jsonl", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false}}
|
|
8
|
+
{"timestamp": "2026-01-15T23:19:45.874487", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
9
|
+
{"timestamp": "2026-01-15T23:30:39.781089", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
10
|
+
{"timestamp": "2026-01-15T23:31:34.583609", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
11
|
+
{"timestamp": "2026-01-15T23:34:28.798867", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
12
|
+
{"timestamp": "2026-01-15T23:37:23.880307", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
13
|
+
{"timestamp": "2026-01-15T23:39:00.241460", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
14
|
+
{"timestamp": "2026-01-15T23:45:17.443835", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
15
|
+
{"timestamp": "2026-01-15T23:47:48.342027", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
16
|
+
{"timestamp": "2026-01-15T23:49:03.280634", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
17
|
+
{"timestamp": "2026-01-15T23:52:58.327080", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
18
|
+
{"timestamp": "2026-01-15T23:54:31.824156", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
19
|
+
{"timestamp": "2026-01-15T23:57:02.269266", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
20
|
+
{"timestamp": "2026-01-16T00:07:44.971323", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
21
|
+
{"timestamp": "2026-01-16T00:32:32.595832", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
22
|
+
{"timestamp": "2026-01-16T00:35:44.239427", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
23
|
+
{"timestamp": "2026-01-16T00:39:41.999014", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
24
|
+
{"timestamp": "2026-01-16T00:42:42.402937", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
25
|
+
{"timestamp": "2026-01-16T00:47:13.684693", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
26
|
+
{"timestamp": "2026-01-16T00:48:11.053152", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
27
|
+
{"timestamp": "2026-01-16T00:51:21.432320", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
28
|
+
{"timestamp": "2026-01-16T00:53:31.446573", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
29
|
+
{"timestamp": "2026-01-16T00:54:12.543023", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
30
|
+
{"timestamp": "2026-01-16T00:54:30.659805", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
31
|
+
{"timestamp": "2026-01-16T00:55:24.557565", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
32
|
+
{"timestamp": "2026-01-16T00:55:59.645737", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
33
|
+
{"timestamp": "2026-01-16T00:56:57.602192", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
34
|
+
{"timestamp": "2026-01-16T00:57:35.214763", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
35
|
+
{"timestamp": "2026-01-16T00:57:58.674384", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
36
|
+
{"timestamp": "2026-01-16T01:03:00.851495", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
37
|
+
{"timestamp": "2026-01-16T01:05:27.145720", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
38
|
+
{"timestamp": "2026-01-16T01:08:07.273806", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
39
|
+
{"timestamp": "2026-01-16T01:13:26.725036", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
40
|
+
{"timestamp": "2026-01-16T01:24:11.918209", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_43bcfce0bffeI9i1ho8WxbquLe", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_43bcfce0bffeI9i1ho8WxbquLe-agent-ses_43bcfce0bffeI9i1ho8WxbquLe.json", "hook_source": "opencode-plugin"}}
|
|
41
|
+
{"timestamp": "2026-01-16T01:26:32.286373", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
42
|
+
{"timestamp": "2026-01-16T01:34:19.600320", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
43
|
+
{"timestamp": "2026-01-16T01:36:19.823231", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
44
|
+
{"timestamp": "2026-01-16T01:37:32.014331", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
45
|
+
{"timestamp": "2026-01-16T01:59:15.370364", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
|
46
|
+
{"timestamp": "2026-01-16T02:00:15.245964", "project": "opencode-nanobanana", "project_type": "Node.js", "branch": "ralph/storyboard-video", "type": null, "message": null, "raw_data": {"session_id": "ses_4416828deffe8t5ImXQjBCml8S", "cwd": "/Volumes/DevHub_ext/factory/toolbox/opencode-nanobanana", "permission_mode": "bypassPermissions", "hook_event_name": "Stop", "stop_hook_active": false, "todo_path": "/Users/jarvis/.claude/todos/ses_4416828deffe8t5ImXQjBCml8S-agent-ses_4416828deffe8t5ImXQjBCml8S.json", "hook_source": "opencode-plugin"}}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-nanobanana",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenCode plugin for visual AI: video generation (Veo 3), image generation (Imagen 3), storyboards, app icons, and visual analysis powered by Google Gemini",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"test:watch": "vitest",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"lint": "tsc --noEmit",
|
|
21
|
+
"clean": "rm -rf dist",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"opencode",
|
|
26
|
+
"mcp",
|
|
27
|
+
"plugin",
|
|
28
|
+
"gemini",
|
|
29
|
+
"veo",
|
|
30
|
+
"imagen",
|
|
31
|
+
"video-generation",
|
|
32
|
+
"image-generation",
|
|
33
|
+
"ai",
|
|
34
|
+
"visual-toolkit",
|
|
35
|
+
"app-icons",
|
|
36
|
+
"storyboard"
|
|
37
|
+
],
|
|
38
|
+
"author": "NautCoder",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/48Nauts-Operator/opencode-nanobanana.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/48Nauts-Operator/opencode-nanobanana/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/48Nauts-Operator/opencode-nanobanana#readme",
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18.0.0"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@google/genai": "^1.36.0",
|
|
53
|
+
"sharp": "^0.33.0",
|
|
54
|
+
"zod": "^3.22.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^20.0.0",
|
|
58
|
+
"typescript": "^5.3.0",
|
|
59
|
+
"vitest": "^1.0.0"
|
|
60
|
+
}
|
|
61
|
+
}
|