opencode-nanobanana 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/.ralph-events.json +151 -0
  2. package/.ralph-last-branch +1 -0
  3. package/.ralph-monitor-state.json +7 -0
  4. package/.ralph-monitor.pid +1 -0
  5. package/.ralph-timing.json +26 -0
  6. package/README.md +708 -0
  7. package/dist/index.d.ts +18 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +21 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/platforms/android.d.ts +94 -0
  12. package/dist/platforms/android.d.ts.map +1 -0
  13. package/dist/platforms/android.js +123 -0
  14. package/dist/platforms/android.js.map +1 -0
  15. package/dist/platforms/ios.d.ts +51 -0
  16. package/dist/platforms/ios.d.ts.map +1 -0
  17. package/dist/platforms/ios.js +149 -0
  18. package/dist/platforms/ios.js.map +1 -0
  19. package/dist/platforms/macos.d.ts +33 -0
  20. package/dist/platforms/macos.d.ts.map +1 -0
  21. package/dist/platforms/macos.js +50 -0
  22. package/dist/platforms/macos.js.map +1 -0
  23. package/dist/platforms/watchos.d.ts +36 -0
  24. package/dist/platforms/watchos.d.ts.map +1 -0
  25. package/dist/platforms/watchos.js +113 -0
  26. package/dist/platforms/watchos.js.map +1 -0
  27. package/dist/platforms/web.d.ts +64 -0
  28. package/dist/platforms/web.d.ts.map +1 -0
  29. package/dist/platforms/web.js +96 -0
  30. package/dist/platforms/web.js.map +1 -0
  31. package/dist/providers/gemini.d.ts +41 -0
  32. package/dist/providers/gemini.d.ts.map +1 -0
  33. package/dist/providers/gemini.js +177 -0
  34. package/dist/providers/gemini.js.map +1 -0
  35. package/dist/tools/analyze/compare.d.ts +12 -0
  36. package/dist/tools/analyze/compare.d.ts.map +1 -0
  37. package/dist/tools/analyze/compare.js +83 -0
  38. package/dist/tools/analyze/compare.js.map +1 -0
  39. package/dist/tools/analyze/mockup.d.ts +12 -0
  40. package/dist/tools/analyze/mockup.d.ts.map +1 -0
  41. package/dist/tools/analyze/mockup.js +88 -0
  42. package/dist/tools/analyze/mockup.js.map +1 -0
  43. package/dist/tools/analyze/screenshot.d.ts +12 -0
  44. package/dist/tools/analyze/screenshot.d.ts.map +1 -0
  45. package/dist/tools/analyze/screenshot.js +61 -0
  46. package/dist/tools/analyze/screenshot.js.map +1 -0
  47. package/dist/tools/app-assets/app-icon.d.ts +9 -0
  48. package/dist/tools/app-assets/app-icon.d.ts.map +1 -0
  49. package/dist/tools/app-assets/app-icon.js +133 -0
  50. package/dist/tools/app-assets/app-icon.js.map +1 -0
  51. package/dist/tools/app-assets/device-mockup.d.ts +9 -0
  52. package/dist/tools/app-assets/device-mockup.d.ts.map +1 -0
  53. package/dist/tools/app-assets/device-mockup.js +139 -0
  54. package/dist/tools/app-assets/device-mockup.js.map +1 -0
  55. package/dist/tools/app-assets/launch-images.d.ts +3 -0
  56. package/dist/tools/app-assets/launch-images.d.ts.map +1 -0
  57. package/dist/tools/app-assets/launch-images.js +171 -0
  58. package/dist/tools/app-assets/launch-images.js.map +1 -0
  59. package/dist/tools/app-assets/resize-devices.d.ts +14 -0
  60. package/dist/tools/app-assets/resize-devices.d.ts.map +1 -0
  61. package/dist/tools/app-assets/resize-devices.js +296 -0
  62. package/dist/tools/app-assets/resize-devices.js.map +1 -0
  63. package/dist/tools/app-assets/screenshots.d.ts +14 -0
  64. package/dist/tools/app-assets/screenshots.d.ts.map +1 -0
  65. package/dist/tools/app-assets/screenshots.js +186 -0
  66. package/dist/tools/app-assets/screenshots.js.map +1 -0
  67. package/dist/tools/core/edit-image.d.ts +12 -0
  68. package/dist/tools/core/edit-image.d.ts.map +1 -0
  69. package/dist/tools/core/edit-image.js +102 -0
  70. package/dist/tools/core/edit-image.js.map +1 -0
  71. package/dist/tools/core/generate-image.d.ts +12 -0
  72. package/dist/tools/core/generate-image.d.ts.map +1 -0
  73. package/dist/tools/core/generate-image.js +96 -0
  74. package/dist/tools/core/generate-image.js.map +1 -0
  75. package/dist/tools/core/restore-image.d.ts +12 -0
  76. package/dist/tools/core/restore-image.d.ts.map +1 -0
  77. package/dist/tools/core/restore-image.js +104 -0
  78. package/dist/tools/core/restore-image.js.map +1 -0
  79. package/dist/tools/design/mockup-to-code.d.ts +3 -0
  80. package/dist/tools/design/mockup-to-code.d.ts.map +1 -0
  81. package/dist/tools/design/mockup-to-code.js +311 -0
  82. package/dist/tools/design/mockup-to-code.js.map +1 -0
  83. package/dist/tools/design/sketch-to-code.d.ts +3 -0
  84. package/dist/tools/design/sketch-to-code.d.ts.map +1 -0
  85. package/dist/tools/design/sketch-to-code.js +325 -0
  86. package/dist/tools/design/sketch-to-code.js.map +1 -0
  87. package/dist/tools/docs/architecture-diagram.d.ts +12 -0
  88. package/dist/tools/docs/architecture-diagram.d.ts.map +1 -0
  89. package/dist/tools/docs/architecture-diagram.js +179 -0
  90. package/dist/tools/docs/architecture-diagram.js.map +1 -0
  91. package/dist/tools/docs/readme-banner.d.ts +6 -0
  92. package/dist/tools/docs/readme-banner.d.ts.map +1 -0
  93. package/dist/tools/docs/readme-banner.js +108 -0
  94. package/dist/tools/docs/readme-banner.js.map +1 -0
  95. package/dist/tools/docs/sequence-diagram.d.ts +12 -0
  96. package/dist/tools/docs/sequence-diagram.d.ts.map +1 -0
  97. package/dist/tools/docs/sequence-diagram.js +161 -0
  98. package/dist/tools/docs/sequence-diagram.js.map +1 -0
  99. package/dist/tools/docs/social-preview.d.ts +11 -0
  100. package/dist/tools/docs/social-preview.d.ts.map +1 -0
  101. package/dist/tools/docs/social-preview.js +111 -0
  102. package/dist/tools/docs/social-preview.js.map +1 -0
  103. package/dist/tools/video/extend-video.d.ts +14 -0
  104. package/dist/tools/video/extend-video.d.ts.map +1 -0
  105. package/dist/tools/video/extend-video.js +39 -0
  106. package/dist/tools/video/extend-video.js.map +1 -0
  107. package/dist/tools/video/generate-video.d.ts +14 -0
  108. package/dist/tools/video/generate-video.d.ts.map +1 -0
  109. package/dist/tools/video/generate-video.js +39 -0
  110. package/dist/tools/video/generate-video.js.map +1 -0
  111. package/dist/tools/video/image-to-video.d.ts +15 -0
  112. package/dist/tools/video/image-to-video.d.ts.map +1 -0
  113. package/dist/tools/video/image-to-video.js +42 -0
  114. package/dist/tools/video/image-to-video.js.map +1 -0
  115. package/dist/tools/video/storyboard-video.d.ts +91 -0
  116. package/dist/tools/video/storyboard-video.d.ts.map +1 -0
  117. package/dist/tools/video/storyboard-video.js +230 -0
  118. package/dist/tools/video/storyboard-video.js.map +1 -0
  119. package/dist/utils/ffmpeg.d.ts +30 -0
  120. package/dist/utils/ffmpeg.d.ts.map +1 -0
  121. package/dist/utils/ffmpeg.js +205 -0
  122. package/dist/utils/ffmpeg.js.map +1 -0
  123. package/dist/utils/file-handler.d.ts +7 -0
  124. package/dist/utils/file-handler.d.ts.map +1 -0
  125. package/dist/utils/file-handler.js +10 -0
  126. package/dist/utils/file-handler.js.map +1 -0
  127. package/dist/utils/image-processing.d.ts +7 -0
  128. package/dist/utils/image-processing.d.ts.map +1 -0
  129. package/dist/utils/image-processing.js +10 -0
  130. package/dist/utils/image-processing.js.map +1 -0
  131. package/docs/PLUGIN-VERIFICATION.md +182 -0
  132. package/logs/notifications.jsonl +46 -0
  133. package/package.json +61 -0
  134. package/prd.json +216 -0
  135. package/progress.txt +145 -0
  136. package/ralph-report.html +297 -0
  137. package/src/index.ts +23 -0
  138. package/src/platforms/android/.gitkeep +0 -0
  139. package/src/platforms/ios/.gitkeep +0 -0
  140. package/src/platforms/web/.gitkeep +0 -0
  141. package/src/providers/.gitkeep +0 -0
  142. package/src/providers/gemini.ts +288 -0
  143. package/src/tools/core/.gitkeep +0 -0
  144. package/src/tools/platform/.gitkeep +0 -0
  145. package/src/tools/video/extend-video.ts +71 -0
  146. package/src/tools/video/generate-video.ts +70 -0
  147. package/src/tools/video/image-to-video.ts +76 -0
  148. package/src/tools/video/storyboard-video.ts +325 -0
  149. package/src/utils/.gitkeep +0 -0
  150. package/src/utils/ffmpeg.ts +266 -0
  151. package/src/utils/file-handler.ts +10 -0
  152. package/src/utils/image-processing.ts +10 -0
  153. package/templates/.gitkeep +0 -0
  154. package/test-analyze-screenshot.ts +50 -0
  155. package/test-app-icons.ts +55 -0
  156. package/test-cat-sunset.ts +30 -0
  157. package/test-full-plugin.ts +88 -0
  158. package/test-icon-gen.ts +30 -0
  159. package/test-output/test-edit.png +0 -0
  160. package/test-output/test-generate.png +0 -0
  161. package/test-output/test-video.mp4 +0 -0
  162. package/test-plugin-load.js +45 -0
  163. package/test-princess-emma-continue.ts +35 -0
  164. package/test-princess-emma-full.ts +38 -0
  165. package/test-princess-emma-short.ts +32 -0
  166. package/test-princess-emma-with-reference.ts +34 -0
  167. package/test-princess-emma.ts +38 -0
  168. package/test-product-ad.ts +66 -0
  169. package/test-ralph-droid.ts +30 -0
  170. package/test-social-preview.ts +61 -0
  171. package/test-veo31-live.ts +187 -0
  172. package/test-video-gen.ts +40 -0
  173. package/test-video-veo.ts +73 -0
  174. package/test-zurich-video.ts +64 -0
  175. package/tests/.gitkeep +0 -0
  176. package/tests/providers/gemini.test.ts +388 -0
  177. package/tests/utils/ffmpeg.test.ts +328 -0
  178. package/tests/video/storyboard.test.ts +469 -0
  179. package/tsconfig.json +25 -0
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Generate App Screenshots Tool
3
+ *
4
+ * Creates App Store screenshots for iOS and iPad devices.
5
+ * Supports two modes:
6
+ * - 'image': Resizes existing image to all device dimensions
7
+ * - 'code': Generates visuals from code/design description via Gemini
8
+ */
9
+ import { tool } from '@opencode-ai/plugin/tool';
10
+ import { GeminiProvider } from '../../providers/gemini.js';
11
+ import { loadImage, saveImage, ensureDirectory } from '../../utils/file-handler.js';
12
+ import { resize } from '../../utils/image-processing.js';
13
+ import { IOS_SCREENSHOT_SIZES } from '../../platforms/ios.js';
14
+ import path from 'node:path';
15
+ /**
16
+ * Tool args schema
17
+ */
18
+ const generateScreenshotsArgs = {
19
+ source: tool.schema.string().describe('Source content: image path for "image" mode, or description for "code" mode'),
20
+ sourceType: tool.schema.enum(['image', 'code']).describe('Type of source: "image" to resize existing image, or "code" to generate from description'),
21
+ platforms: tool.schema.array(tool.schema.enum(['ios', 'ipad'])).optional().describe('Target platforms. Defaults to ["ios", "ipad"]'),
22
+ devices: tool.schema.array(tool.schema.string()).optional().describe('Specific devices to target (e.g., ["6.9-inch", "iPad-12.9"]). Defaults to all devices'),
23
+ addDeviceFrame: tool.schema.boolean().optional().describe('Add device frame to screenshots (future feature). Defaults to false'),
24
+ outputDir: tool.schema.string().optional().describe('Custom output directory. Defaults to "./generated-assets/screenshots"')
25
+ };
26
+ /**
27
+ * Filter screenshot sizes by platform
28
+ */
29
+ function filterByPlatform(sizes, platforms) {
30
+ return sizes.filter(size => {
31
+ const isPhone = size.device.includes('iPhone');
32
+ const isTablet = size.device.includes('iPad');
33
+ if (platforms.includes('ios') && isPhone)
34
+ return true;
35
+ if (platforms.includes('ipad') && isTablet)
36
+ return true;
37
+ return false;
38
+ });
39
+ }
40
+ /**
41
+ * Filter screenshot sizes by device names
42
+ */
43
+ function filterByDevices(sizes, deviceNames) {
44
+ return sizes.filter(size => deviceNames.includes(size.name));
45
+ }
46
+ /**
47
+ * Tool definition for generate_app_screenshots
48
+ */
49
+ export const generateScreenshotsTool = tool({
50
+ description: 'Generate App Store screenshots for iOS and iPad devices. Supports resizing existing images or generating from code/design descriptions.',
51
+ args: generateScreenshotsArgs,
52
+ async execute(args, _context) {
53
+ try {
54
+ const { source, sourceType, platforms = ['ios', 'ipad'], devices, addDeviceFrame = false, outputDir = './generated-assets/screenshots' } = args;
55
+ // Ensure output directory exists
56
+ await ensureDirectory(outputDir);
57
+ // Filter screenshot sizes based on platforms and devices
58
+ let targetSizes = IOS_SCREENSHOT_SIZES;
59
+ if (platforms.length > 0) {
60
+ targetSizes = filterByPlatform(targetSizes, platforms);
61
+ }
62
+ if (devices && devices.length > 0) {
63
+ targetSizes = filterByDevices(targetSizes, devices);
64
+ }
65
+ if (targetSizes.length === 0) {
66
+ return [
67
+ '✗ Error: No matching devices found',
68
+ '',
69
+ `Platforms: ${platforms.join(', ')}`,
70
+ devices ? `Devices: ${devices.join(', ')}` : '',
71
+ '',
72
+ 'Available devices:',
73
+ ...IOS_SCREENSHOT_SIZES.map(s => ` - ${s.name} (${s.device})`)
74
+ ].join('\n');
75
+ }
76
+ const savedPaths = [];
77
+ if (sourceType === 'image') {
78
+ // Mode 1: Resize existing image to all device dimensions
79
+ const sourceBuffer = await loadImage(source);
80
+ for (const size of targetSizes) {
81
+ // Create device-specific directory
82
+ const deviceDir = path.join(outputDir, size.name);
83
+ await ensureDirectory(deviceDir);
84
+ // Resize image to device dimensions
85
+ // Using 'cover' fit mode to fill the screen without letterboxing
86
+ const resizedBuffer = await resize(sourceBuffer, size.width, size.height, {
87
+ fit: 'cover',
88
+ position: 'center'
89
+ });
90
+ // Save screenshot
91
+ const filename = `screenshot-${size.name}.png`;
92
+ const filepath = path.join(deviceDir, filename);
93
+ // Save using our file handler (it returns the path)
94
+ await saveImage(resizedBuffer, deviceDir, `screenshot-${size.name}`, 0);
95
+ savedPaths.push(filepath);
96
+ }
97
+ return [
98
+ `✓ Successfully resized image to ${targetSizes.length} device screenshot(s)`,
99
+ '',
100
+ `Source: ${source}`,
101
+ `Mode: Resize from image`,
102
+ '',
103
+ 'Generated screenshots:',
104
+ ...savedPaths.map((p, i) => ` ${i + 1}. ${p}`),
105
+ '',
106
+ `Output directory: ${outputDir}`
107
+ ].join('\n');
108
+ }
109
+ else {
110
+ // Mode 2: Generate visuals from code/design description via Gemini
111
+ const provider = new GeminiProvider();
112
+ for (const size of targetSizes) {
113
+ // Create device-specific directory
114
+ const deviceDir = path.join(outputDir, size.name);
115
+ await ensureDirectory(deviceDir);
116
+ // Generate screenshot for this specific device size
117
+ const prompt = [
118
+ source,
119
+ '',
120
+ `Generate an App Store screenshot for ${size.device} (${size.width}x${size.height}px).`,
121
+ 'The screenshot should be visually polished and ready for App Store submission.',
122
+ addDeviceFrame ? 'Include the device frame in the screenshot.' : ''
123
+ ].filter(Boolean).join('\n');
124
+ const imageBuffers = await provider.generateImage(prompt, {
125
+ aspectRatio: size.width > size.height ? '9:16' : '16:9',
126
+ count: 1
127
+ });
128
+ const buffer = imageBuffers[0];
129
+ if (!buffer) {
130
+ throw new Error(`Failed to generate screenshot for ${size.device}`);
131
+ }
132
+ // Resize to exact device dimensions
133
+ const resizedBuffer = await resize(buffer, size.width, size.height, {
134
+ fit: 'cover',
135
+ position: 'center'
136
+ });
137
+ // Save screenshot
138
+ const filepath = await saveImage(resizedBuffer, deviceDir, `screenshot-${size.name}`, 0);
139
+ savedPaths.push(filepath);
140
+ }
141
+ return [
142
+ `✓ Successfully generated ${targetSizes.length} screenshot(s) from description`,
143
+ '',
144
+ `Description: "${source}"`,
145
+ `Mode: Generated via Gemini`,
146
+ '',
147
+ 'Generated screenshots:',
148
+ ...savedPaths.map((p, i) => ` ${i + 1}. ${p}`),
149
+ '',
150
+ `Output directory: ${outputDir}`
151
+ ].join('\n');
152
+ }
153
+ }
154
+ catch (error) {
155
+ // Handle errors with user-friendly messages
156
+ if (error instanceof Error) {
157
+ if (error.message.includes('GEMINI_API_KEY')) {
158
+ return [
159
+ '✗ Error: Gemini API key not found',
160
+ '',
161
+ 'Please set your GEMINI_API_KEY environment variable.',
162
+ 'Get your API key at: https://makersuite.google.com/app/apikey'
163
+ ].join('\n');
164
+ }
165
+ if (error.message.includes('ENOENT') || error.message.includes('no such file')) {
166
+ return [
167
+ '✗ Error: Source image file not found',
168
+ '',
169
+ `Path: ${args.source}`,
170
+ '',
171
+ 'Please check the file path and try again.'
172
+ ].join('\n');
173
+ }
174
+ return [
175
+ '✗ Screenshot generation failed',
176
+ '',
177
+ `Error: ${error.message}`,
178
+ '',
179
+ 'Please check your inputs and try again.'
180
+ ].join('\n');
181
+ }
182
+ return '✗ Screenshot generation failed with an unknown error';
183
+ }
184
+ }
185
+ });
186
+ //# sourceMappingURL=screenshots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshots.js","sourceRoot":"","sources":["../../../src/tools/app-assets/screenshots.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Edit Image Tool
3
+ *
4
+ * Modifies existing images using natural language instructions with Google Gemini's vision and generation capabilities.
5
+ * Loads a source image, sends it with edit instructions to Gemini, and saves the result.
6
+ */
7
+ import { type ToolDefinition } from '@opencode-ai/plugin/tool';
8
+ /**
9
+ * Tool definition for edit_image
10
+ */
11
+ export declare const editImageTool: ToolDefinition;
12
+ //# sourceMappingURL=edit-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-image.d.ts","sourceRoot":"","sources":["../../../src/tools/core/edit-image.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAgBrE;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,cA4F1B,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Edit Image Tool
3
+ *
4
+ * Modifies existing images using natural language instructions with Google Gemini's vision and generation capabilities.
5
+ * Loads a source image, sends it with edit instructions to Gemini, and saves the result.
6
+ */
7
+ import { tool } from '@opencode-ai/plugin/tool';
8
+ import { GeminiProvider } from '../../providers/gemini.js';
9
+ import { loadImage, saveImage, getOutputDir } from '../../utils/file-handler.js';
10
+ import path from 'path';
11
+ /**
12
+ * Tool args schema
13
+ */
14
+ const editImageArgs = {
15
+ imagePath: tool.schema.string().describe('Path to the source image file to edit'),
16
+ editPrompt: tool.schema.string().describe('Natural language instructions for how to edit the image'),
17
+ outputPath: tool.schema.string()
18
+ .optional()
19
+ .describe('Custom output directory path. Defaults to "./generated-assets"')
20
+ };
21
+ /**
22
+ * Tool definition for edit_image
23
+ */
24
+ export const editImageTool = tool({
25
+ description: 'Edit an existing image using natural language instructions. Loads a source image, applies edits via Gemini vision AI, and saves the result with an "_edited" suffix.',
26
+ args: editImageArgs,
27
+ async execute(args, _context) {
28
+ try {
29
+ // Initialize Gemini provider
30
+ const provider = new GeminiProvider();
31
+ // Extract parameters
32
+ const { imagePath, editPrompt, outputPath } = args;
33
+ // Determine output directory
34
+ const outputDir = outputPath || getOutputDir();
35
+ // Load source image
36
+ let sourceBuffer;
37
+ try {
38
+ sourceBuffer = await loadImage(imagePath);
39
+ }
40
+ catch (loadError) {
41
+ return [
42
+ '✗ Failed to load source image',
43
+ '',
44
+ `Error: ${loadError instanceof Error ? loadError.message : 'Unknown error'}`,
45
+ '',
46
+ `Image path: ${imagePath}`,
47
+ 'Please check that the file exists and is accessible.'
48
+ ].join('\n');
49
+ }
50
+ // Edit image using Gemini
51
+ const editedBuffer = await provider.editImage(sourceBuffer, editPrompt);
52
+ // Generate output filename with '_edited' suffix
53
+ const parsedPath = path.parse(imagePath);
54
+ const baseFilename = parsedPath.name;
55
+ const editedPrompt = `${baseFilename}_edited`;
56
+ // Save edited image
57
+ const savedPath = await saveImage(editedBuffer, outputDir, editedPrompt, 0);
58
+ // Build success message
59
+ return [
60
+ `✓ Successfully edited image`,
61
+ ``,
62
+ `Source: ${imagePath}`,
63
+ `Edit instruction: "${editPrompt}"`,
64
+ ``,
65
+ `Saved to: ${savedPath}`,
66
+ `Output directory: ${outputDir}`
67
+ ].join('\n');
68
+ }
69
+ catch (error) {
70
+ // Handle errors with user-friendly messages
71
+ if (error instanceof Error) {
72
+ if (error.message.includes('GEMINI_API_KEY')) {
73
+ return [
74
+ '✗ Error: Gemini API key not found',
75
+ '',
76
+ 'Please set your GEMINI_API_KEY environment variable.',
77
+ 'Get your API key at: https://makersuite.google.com/app/apikey'
78
+ ].join('\n');
79
+ }
80
+ if (error.message.includes('No edited image was returned')) {
81
+ return [
82
+ '✗ Image editing failed',
83
+ '',
84
+ 'Gemini did not return an edited image.',
85
+ 'This may happen if the edit prompt is unclear or not supported.',
86
+ '',
87
+ 'Try rephrasing your edit instruction with more specific details.'
88
+ ].join('\n');
89
+ }
90
+ return [
91
+ '✗ Image editing failed',
92
+ '',
93
+ `Error: ${error.message}`,
94
+ '',
95
+ 'Please check your image path and edit prompt, then try again.'
96
+ ].join('\n');
97
+ }
98
+ return '✗ Image editing failed with an unknown error';
99
+ }
100
+ }
101
+ });
102
+ //# sourceMappingURL=edit-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-image.js","sourceRoot":"","sources":["../../../src/tools/core/edit-image.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Generate Image Tool
3
+ *
4
+ * Creates images from text prompts using Google Gemini's Imagen model.
5
+ * Supports batch generation, aspect ratio control, and custom output paths.
6
+ */
7
+ import { type ToolDefinition } from '@opencode-ai/plugin/tool';
8
+ /**
9
+ * Tool definition for generate_image
10
+ */
11
+ export declare const generateImageTool: ToolDefinition;
12
+ //# sourceMappingURL=generate-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-image.d.ts","sourceRoot":"","sources":["../../../src/tools/core/generate-image.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAuBrE;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAiF9B,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Generate Image Tool
3
+ *
4
+ * Creates images from text prompts using Google Gemini's Imagen model.
5
+ * Supports batch generation, aspect ratio control, and custom output paths.
6
+ */
7
+ import { tool } from '@opencode-ai/plugin/tool';
8
+ import { GeminiProvider } from '../../providers/gemini.js';
9
+ import { saveImage, getOutputDir } from '../../utils/file-handler.js';
10
+ /**
11
+ * Tool args schema
12
+ */
13
+ const generateImageArgs = {
14
+ prompt: tool.schema.string().describe('Text description of the image to generate'),
15
+ aspectRatio: tool.schema.string()
16
+ .optional()
17
+ .describe('Aspect ratio for the image (e.g., "1:1", "16:9", "9:16"). Defaults to "1:1"'),
18
+ outputPath: tool.schema.string()
19
+ .optional()
20
+ .describe('Custom output directory path. Defaults to "./generated-assets"'),
21
+ count: tool.schema.number()
22
+ .int()
23
+ .min(1)
24
+ .max(8)
25
+ .optional()
26
+ .describe('Number of images to generate (1-8). Defaults to 1')
27
+ };
28
+ /**
29
+ * Tool definition for generate_image
30
+ */
31
+ export const generateImageTool = tool({
32
+ description: 'Generate images from text prompts using Gemini Imagen. Supports batch generation (1-8 images), aspect ratio control, and custom output paths.',
33
+ args: generateImageArgs,
34
+ async execute(args, _context) {
35
+ try {
36
+ // Initialize Gemini provider
37
+ const provider = new GeminiProvider();
38
+ // Extract parameters with defaults
39
+ const { prompt, aspectRatio = '1:1', count = 1, outputPath } = args;
40
+ // Determine output directory
41
+ const outputDir = outputPath || getOutputDir();
42
+ // Generate images using Gemini
43
+ const imageBuffers = await provider.generateImage(prompt, {
44
+ aspectRatio,
45
+ count
46
+ });
47
+ // Save all generated images
48
+ const savedPaths = [];
49
+ for (let i = 0; i < imageBuffers.length; i++) {
50
+ const buffer = imageBuffers[i];
51
+ if (!buffer) {
52
+ throw new Error(`Failed to generate image ${i + 1}`);
53
+ }
54
+ const filepath = await saveImage(buffer, outputDir, prompt, i);
55
+ savedPaths.push(filepath);
56
+ }
57
+ // Build success message
58
+ const imageWord = count === 1 ? 'image' : 'images';
59
+ const pathList = savedPaths.map((p, i) => ` ${i + 1}. ${p}`).join('\n');
60
+ return [
61
+ `✓ Successfully generated ${count} ${imageWord} from prompt: "${prompt}"`,
62
+ ``,
63
+ `Saved to:`,
64
+ pathList,
65
+ ``,
66
+ `Aspect ratio: ${aspectRatio}`,
67
+ `Output directory: ${outputDir}`
68
+ ].join('\n');
69
+ }
70
+ catch (error) {
71
+ // Handle errors with user-friendly messages
72
+ if (error instanceof Error) {
73
+ if (error.message.includes('GEMINI_API_KEY')) {
74
+ return [
75
+ '✗ Error: Gemini API key not found',
76
+ '',
77
+ 'Please set your GEMINI_API_KEY environment variable.',
78
+ 'Get your API key at: https://makersuite.google.com/app/apikey'
79
+ ].join('\n');
80
+ }
81
+ if (error.message.includes('Count must be between')) {
82
+ return `✗ Error: ${error.message}`;
83
+ }
84
+ return [
85
+ '✗ Image generation failed',
86
+ '',
87
+ `Error: ${error.message}`,
88
+ '',
89
+ 'Please check your prompt and try again.'
90
+ ].join('\n');
91
+ }
92
+ return '✗ Image generation failed with an unknown error';
93
+ }
94
+ }
95
+ });
96
+ //# sourceMappingURL=generate-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-image.js","sourceRoot":"","sources":["../../../src/tools/core/generate-image.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Restore Image Tool
3
+ *
4
+ * Enhances or repairs damaged images using Google Gemini's vision and generation capabilities.
5
+ * Loads a source image, applies restoration/enhancement, and saves the result.
6
+ */
7
+ import { type ToolDefinition } from '@opencode-ai/plugin/tool';
8
+ /**
9
+ * Tool definition for restore_image
10
+ */
11
+ export declare const restoreImageTool: ToolDefinition;
12
+ //# sourceMappingURL=restore-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore-image.d.ts","sourceRoot":"","sources":["../../../src/tools/core/restore-image.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAkBrE;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,cA4F7B,CAAC"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Restore Image Tool
3
+ *
4
+ * Enhances or repairs damaged images using Google Gemini's vision and generation capabilities.
5
+ * Loads a source image, applies restoration/enhancement, and saves the result.
6
+ */
7
+ import { tool } from '@opencode-ai/plugin/tool';
8
+ import { GeminiProvider } from '../../providers/gemini.js';
9
+ import { loadImage, saveImage, getOutputDir } from '../../utils/file-handler.js';
10
+ import path from 'path';
11
+ /**
12
+ * Tool args schema
13
+ */
14
+ const restoreImageArgs = {
15
+ imagePath: tool.schema.string().describe('Path to the source image file to restore'),
16
+ instructions: tool.schema.string()
17
+ .optional()
18
+ .describe('Optional custom restoration instructions. Defaults to "restore and enhance this image"'),
19
+ outputPath: tool.schema.string()
20
+ .optional()
21
+ .describe('Custom output directory path. Defaults to "./generated-assets"')
22
+ };
23
+ /**
24
+ * Tool definition for restore_image
25
+ */
26
+ export const restoreImageTool = tool({
27
+ description: 'Restore and enhance an image to improve quality, remove damage, or repair artifacts. Uses Gemini vision AI to intelligently restore images and saves the result with a "_restored" suffix.',
28
+ args: restoreImageArgs,
29
+ async execute(args, _context) {
30
+ try {
31
+ // Initialize Gemini provider
32
+ const provider = new GeminiProvider();
33
+ // Extract parameters
34
+ const { imagePath, instructions = 'restore and enhance this image', outputPath } = args;
35
+ // Determine output directory
36
+ const outputDir = outputPath || getOutputDir();
37
+ // Load source image
38
+ let sourceBuffer;
39
+ try {
40
+ sourceBuffer = await loadImage(imagePath);
41
+ }
42
+ catch (loadError) {
43
+ return [
44
+ '✗ Failed to load source image',
45
+ '',
46
+ `Error: ${loadError instanceof Error ? loadError.message : 'Unknown error'}`,
47
+ '',
48
+ `Image path: ${imagePath}`,
49
+ 'Please check that the file exists and is accessible.'
50
+ ].join('\n');
51
+ }
52
+ // Restore image using Gemini editImage method
53
+ const restoredBuffer = await provider.editImage(sourceBuffer, instructions);
54
+ // Generate output filename with '_restored' suffix
55
+ const parsedPath = path.parse(imagePath);
56
+ const baseFilename = parsedPath.name;
57
+ const restoredPrompt = `${baseFilename}_restored`;
58
+ // Save restored image
59
+ const savedPath = await saveImage(restoredBuffer, outputDir, restoredPrompt, 0);
60
+ // Build success message
61
+ return [
62
+ `✓ Successfully restored image`,
63
+ ``,
64
+ `Source: ${imagePath}`,
65
+ `Restoration instruction: "${instructions}"`,
66
+ ``,
67
+ `Saved to: ${savedPath}`,
68
+ `Output directory: ${outputDir}`
69
+ ].join('\n');
70
+ }
71
+ catch (error) {
72
+ // Handle errors with user-friendly messages
73
+ if (error instanceof Error) {
74
+ if (error.message.includes('GEMINI_API_KEY')) {
75
+ return [
76
+ '✗ Error: Gemini API key not found',
77
+ '',
78
+ 'Please set your GEMINI_API_KEY environment variable.',
79
+ 'Get your API key at: https://makersuite.google.com/app/apikey'
80
+ ].join('\n');
81
+ }
82
+ if (error.message.includes('No edited image was returned')) {
83
+ return [
84
+ '✗ Image restoration failed',
85
+ '',
86
+ 'Gemini did not return a restored image.',
87
+ 'This may happen if the image cannot be processed or the format is unsupported.',
88
+ '',
89
+ 'Try using a different image format (PNG, JPEG) or check if the image is corrupted.'
90
+ ].join('\n');
91
+ }
92
+ return [
93
+ '✗ Image restoration failed',
94
+ '',
95
+ `Error: ${error.message}`,
96
+ '',
97
+ 'Please check your image path and try again.'
98
+ ].join('\n');
99
+ }
100
+ return '✗ Image restoration failed with an unknown error';
101
+ }
102
+ }
103
+ });
104
+ //# sourceMappingURL=restore-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore-image.js","sourceRoot":"","sources":["../../../src/tools/core/restore-image.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type ToolDefinition } from '@opencode-ai/plugin/tool';
2
+ export declare const mockupToCodeTool: ToolDefinition;
3
+ //# sourceMappingURL=mockup-to-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockup-to-code.d.ts","sourceRoot":"","sources":["../../../src/tools/design/mockup-to-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAIrE,eAAO,MAAM,gBAAgB,EAAE,cA4C7B,CAAC"}