whale-code 6.4.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 (319) hide show
  1. package/README.md +95 -0
  2. package/bin/swag-agent.js +9 -0
  3. package/bin/swagmanager-mcp.js +321 -0
  4. package/dist/cli/app.d.ts +26 -0
  5. package/dist/cli/app.js +64 -0
  6. package/dist/cli/chat/AgentSelector.d.ts +14 -0
  7. package/dist/cli/chat/AgentSelector.js +14 -0
  8. package/dist/cli/chat/ChatApp.d.ts +9 -0
  9. package/dist/cli/chat/ChatApp.js +267 -0
  10. package/dist/cli/chat/ChatInput.d.ts +39 -0
  11. package/dist/cli/chat/ChatInput.js +509 -0
  12. package/dist/cli/chat/MarkdownText.d.ts +10 -0
  13. package/dist/cli/chat/MarkdownText.js +20 -0
  14. package/dist/cli/chat/MessageList.d.ts +37 -0
  15. package/dist/cli/chat/MessageList.js +80 -0
  16. package/dist/cli/chat/ModelSelector.d.ts +20 -0
  17. package/dist/cli/chat/ModelSelector.js +73 -0
  18. package/dist/cli/chat/RewindViewer.d.ts +26 -0
  19. package/dist/cli/chat/RewindViewer.js +185 -0
  20. package/dist/cli/chat/StoreSelector.d.ts +14 -0
  21. package/dist/cli/chat/StoreSelector.js +24 -0
  22. package/dist/cli/chat/StreamingText.d.ts +12 -0
  23. package/dist/cli/chat/StreamingText.js +12 -0
  24. package/dist/cli/chat/SubagentPanel.d.ts +45 -0
  25. package/dist/cli/chat/SubagentPanel.js +110 -0
  26. package/dist/cli/chat/TeamPanel.d.ts +21 -0
  27. package/dist/cli/chat/TeamPanel.js +42 -0
  28. package/dist/cli/chat/ToolIndicator.d.ts +25 -0
  29. package/dist/cli/chat/ToolIndicator.js +436 -0
  30. package/dist/cli/chat/hooks/useAgentLoop.d.ts +39 -0
  31. package/dist/cli/chat/hooks/useAgentLoop.js +382 -0
  32. package/dist/cli/chat/hooks/useSlashCommands.d.ts +37 -0
  33. package/dist/cli/chat/hooks/useSlashCommands.js +387 -0
  34. package/dist/cli/commands/config-cmd.d.ts +10 -0
  35. package/dist/cli/commands/config-cmd.js +99 -0
  36. package/dist/cli/commands/doctor.d.ts +14 -0
  37. package/dist/cli/commands/doctor.js +172 -0
  38. package/dist/cli/commands/init.d.ts +16 -0
  39. package/dist/cli/commands/init.js +278 -0
  40. package/dist/cli/commands/mcp.d.ts +12 -0
  41. package/dist/cli/commands/mcp.js +162 -0
  42. package/dist/cli/login/LoginApp.d.ts +7 -0
  43. package/dist/cli/login/LoginApp.js +157 -0
  44. package/dist/cli/print-mode.d.ts +31 -0
  45. package/dist/cli/print-mode.js +202 -0
  46. package/dist/cli/serve-mode.d.ts +37 -0
  47. package/dist/cli/serve-mode.js +636 -0
  48. package/dist/cli/services/agent-definitions.d.ts +25 -0
  49. package/dist/cli/services/agent-definitions.js +91 -0
  50. package/dist/cli/services/agent-events.d.ts +178 -0
  51. package/dist/cli/services/agent-events.js +175 -0
  52. package/dist/cli/services/agent-loop.d.ts +90 -0
  53. package/dist/cli/services/agent-loop.js +762 -0
  54. package/dist/cli/services/agent-worker-base.d.ts +97 -0
  55. package/dist/cli/services/agent-worker-base.js +220 -0
  56. package/dist/cli/services/auth-service.d.ts +30 -0
  57. package/dist/cli/services/auth-service.js +160 -0
  58. package/dist/cli/services/background-processes.d.ts +126 -0
  59. package/dist/cli/services/background-processes.js +318 -0
  60. package/dist/cli/services/browser-auth.d.ts +24 -0
  61. package/dist/cli/services/browser-auth.js +180 -0
  62. package/dist/cli/services/claude-md-loader.d.ts +16 -0
  63. package/dist/cli/services/claude-md-loader.js +58 -0
  64. package/dist/cli/services/config-store.d.ts +47 -0
  65. package/dist/cli/services/config-store.js +79 -0
  66. package/dist/cli/services/debug-log.d.ts +10 -0
  67. package/dist/cli/services/debug-log.js +52 -0
  68. package/dist/cli/services/error-logger.d.ts +58 -0
  69. package/dist/cli/services/error-logger.js +269 -0
  70. package/dist/cli/services/file-history.d.ts +21 -0
  71. package/dist/cli/services/file-history.js +83 -0
  72. package/dist/cli/services/format-server-response.d.ts +16 -0
  73. package/dist/cli/services/format-server-response.js +440 -0
  74. package/dist/cli/services/git-context.d.ts +11 -0
  75. package/dist/cli/services/git-context.js +66 -0
  76. package/dist/cli/services/hooks.d.ts +85 -0
  77. package/dist/cli/services/hooks.js +258 -0
  78. package/dist/cli/services/interactive-tools.d.ts +125 -0
  79. package/dist/cli/services/interactive-tools.js +260 -0
  80. package/dist/cli/services/keybinding-manager.d.ts +52 -0
  81. package/dist/cli/services/keybinding-manager.js +115 -0
  82. package/dist/cli/services/local-tools.d.ts +22 -0
  83. package/dist/cli/services/local-tools.js +697 -0
  84. package/dist/cli/services/lsp-manager.d.ts +18 -0
  85. package/dist/cli/services/lsp-manager.js +717 -0
  86. package/dist/cli/services/mcp-client.d.ts +48 -0
  87. package/dist/cli/services/mcp-client.js +157 -0
  88. package/dist/cli/services/memory-manager.d.ts +16 -0
  89. package/dist/cli/services/memory-manager.js +57 -0
  90. package/dist/cli/services/model-manager.d.ts +18 -0
  91. package/dist/cli/services/model-manager.js +71 -0
  92. package/dist/cli/services/model-router.d.ts +26 -0
  93. package/dist/cli/services/model-router.js +149 -0
  94. package/dist/cli/services/permission-modes.d.ts +13 -0
  95. package/dist/cli/services/permission-modes.js +43 -0
  96. package/dist/cli/services/rewind.d.ts +84 -0
  97. package/dist/cli/services/rewind.js +194 -0
  98. package/dist/cli/services/ripgrep.d.ts +28 -0
  99. package/dist/cli/services/ripgrep.js +138 -0
  100. package/dist/cli/services/sandbox.d.ts +29 -0
  101. package/dist/cli/services/sandbox.js +97 -0
  102. package/dist/cli/services/server-tools.d.ts +61 -0
  103. package/dist/cli/services/server-tools.js +543 -0
  104. package/dist/cli/services/session-persistence.d.ts +23 -0
  105. package/dist/cli/services/session-persistence.js +99 -0
  106. package/dist/cli/services/subagent-worker.d.ts +19 -0
  107. package/dist/cli/services/subagent-worker.js +41 -0
  108. package/dist/cli/services/subagent.d.ts +47 -0
  109. package/dist/cli/services/subagent.js +647 -0
  110. package/dist/cli/services/system-prompt.d.ts +7 -0
  111. package/dist/cli/services/system-prompt.js +198 -0
  112. package/dist/cli/services/team-lead.d.ts +73 -0
  113. package/dist/cli/services/team-lead.js +512 -0
  114. package/dist/cli/services/team-state.d.ts +77 -0
  115. package/dist/cli/services/team-state.js +398 -0
  116. package/dist/cli/services/teammate.d.ts +31 -0
  117. package/dist/cli/services/teammate.js +689 -0
  118. package/dist/cli/services/telemetry.d.ts +61 -0
  119. package/dist/cli/services/telemetry.js +209 -0
  120. package/dist/cli/services/tools/agent-tools.d.ts +14 -0
  121. package/dist/cli/services/tools/agent-tools.js +347 -0
  122. package/dist/cli/services/tools/file-ops.d.ts +15 -0
  123. package/dist/cli/services/tools/file-ops.js +487 -0
  124. package/dist/cli/services/tools/search-tools.d.ts +8 -0
  125. package/dist/cli/services/tools/search-tools.js +186 -0
  126. package/dist/cli/services/tools/shell-exec.d.ts +10 -0
  127. package/dist/cli/services/tools/shell-exec.js +168 -0
  128. package/dist/cli/services/tools/task-manager.d.ts +28 -0
  129. package/dist/cli/services/tools/task-manager.js +209 -0
  130. package/dist/cli/services/tools/web-tools.d.ts +11 -0
  131. package/dist/cli/services/tools/web-tools.js +395 -0
  132. package/dist/cli/setup/SetupApp.d.ts +9 -0
  133. package/dist/cli/setup/SetupApp.js +191 -0
  134. package/dist/cli/shared/MatrixIntro.d.ts +4 -0
  135. package/dist/cli/shared/MatrixIntro.js +83 -0
  136. package/dist/cli/shared/Theme.d.ts +74 -0
  137. package/dist/cli/shared/Theme.js +127 -0
  138. package/dist/cli/shared/WhaleBanner.d.ts +10 -0
  139. package/dist/cli/shared/WhaleBanner.js +12 -0
  140. package/dist/cli/shared/markdown.d.ts +21 -0
  141. package/dist/cli/shared/markdown.js +756 -0
  142. package/dist/cli/status/StatusApp.d.ts +4 -0
  143. package/dist/cli/status/StatusApp.js +105 -0
  144. package/dist/cli/stores/StoreApp.d.ts +7 -0
  145. package/dist/cli/stores/StoreApp.js +81 -0
  146. package/dist/index.d.ts +15 -0
  147. package/dist/index.js +538 -0
  148. package/dist/local-agent/connection.d.ts +48 -0
  149. package/dist/local-agent/connection.js +332 -0
  150. package/dist/local-agent/discovery.d.ts +18 -0
  151. package/dist/local-agent/discovery.js +146 -0
  152. package/dist/local-agent/executor.d.ts +34 -0
  153. package/dist/local-agent/executor.js +241 -0
  154. package/dist/local-agent/index.d.ts +14 -0
  155. package/dist/local-agent/index.js +198 -0
  156. package/dist/node/adapters/base.d.ts +35 -0
  157. package/dist/node/adapters/base.js +10 -0
  158. package/dist/node/adapters/discord.d.ts +29 -0
  159. package/dist/node/adapters/discord.js +299 -0
  160. package/dist/node/adapters/email.d.ts +23 -0
  161. package/dist/node/adapters/email.js +218 -0
  162. package/dist/node/adapters/imessage.d.ts +17 -0
  163. package/dist/node/adapters/imessage.js +118 -0
  164. package/dist/node/adapters/slack.d.ts +26 -0
  165. package/dist/node/adapters/slack.js +259 -0
  166. package/dist/node/adapters/sms.d.ts +23 -0
  167. package/dist/node/adapters/sms.js +161 -0
  168. package/dist/node/adapters/telegram.d.ts +17 -0
  169. package/dist/node/adapters/telegram.js +101 -0
  170. package/dist/node/adapters/webchat.d.ts +27 -0
  171. package/dist/node/adapters/webchat.js +160 -0
  172. package/dist/node/adapters/whatsapp.d.ts +28 -0
  173. package/dist/node/adapters/whatsapp.js +230 -0
  174. package/dist/node/cli.d.ts +2 -0
  175. package/dist/node/cli.js +325 -0
  176. package/dist/node/config.d.ts +17 -0
  177. package/dist/node/config.js +31 -0
  178. package/dist/node/runtime.d.ts +50 -0
  179. package/dist/node/runtime.js +351 -0
  180. package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +11 -0
  181. package/dist/server/handlers/__test-utils__/mock-supabase.js +393 -0
  182. package/dist/server/handlers/analytics.d.ts +17 -0
  183. package/dist/server/handlers/analytics.js +266 -0
  184. package/dist/server/handlers/api-keys.d.ts +6 -0
  185. package/dist/server/handlers/api-keys.js +221 -0
  186. package/dist/server/handlers/billing.d.ts +33 -0
  187. package/dist/server/handlers/billing.js +272 -0
  188. package/dist/server/handlers/browser.d.ts +10 -0
  189. package/dist/server/handlers/browser.js +517 -0
  190. package/dist/server/handlers/catalog.d.ts +99 -0
  191. package/dist/server/handlers/catalog.js +976 -0
  192. package/dist/server/handlers/comms.d.ts +254 -0
  193. package/dist/server/handlers/comms.js +588 -0
  194. package/dist/server/handlers/creations.d.ts +6 -0
  195. package/dist/server/handlers/creations.js +479 -0
  196. package/dist/server/handlers/crm.d.ts +89 -0
  197. package/dist/server/handlers/crm.js +538 -0
  198. package/dist/server/handlers/discovery.d.ts +6 -0
  199. package/dist/server/handlers/discovery.js +288 -0
  200. package/dist/server/handlers/embeddings.d.ts +92 -0
  201. package/dist/server/handlers/embeddings.js +197 -0
  202. package/dist/server/handlers/enrichment.d.ts +8 -0
  203. package/dist/server/handlers/enrichment.js +768 -0
  204. package/dist/server/handlers/image-gen.d.ts +6 -0
  205. package/dist/server/handlers/image-gen.js +409 -0
  206. package/dist/server/handlers/inventory.d.ts +319 -0
  207. package/dist/server/handlers/inventory.js +447 -0
  208. package/dist/server/handlers/kali.d.ts +10 -0
  209. package/dist/server/handlers/kali.js +210 -0
  210. package/dist/server/handlers/llm-providers.d.ts +6 -0
  211. package/dist/server/handlers/llm-providers.js +673 -0
  212. package/dist/server/handlers/local-agent.d.ts +6 -0
  213. package/dist/server/handlers/local-agent.js +118 -0
  214. package/dist/server/handlers/meta-ads.d.ts +111 -0
  215. package/dist/server/handlers/meta-ads.js +2279 -0
  216. package/dist/server/handlers/nodes.d.ts +33 -0
  217. package/dist/server/handlers/nodes.js +699 -0
  218. package/dist/server/handlers/operations.d.ts +138 -0
  219. package/dist/server/handlers/operations.js +131 -0
  220. package/dist/server/handlers/platform.d.ts +23 -0
  221. package/dist/server/handlers/platform.js +227 -0
  222. package/dist/server/handlers/supply-chain.d.ts +19 -0
  223. package/dist/server/handlers/supply-chain.js +327 -0
  224. package/dist/server/handlers/transcription.d.ts +17 -0
  225. package/dist/server/handlers/transcription.js +121 -0
  226. package/dist/server/handlers/video-gen.d.ts +6 -0
  227. package/dist/server/handlers/video-gen.js +466 -0
  228. package/dist/server/handlers/voice.d.ts +8 -0
  229. package/dist/server/handlers/voice.js +1146 -0
  230. package/dist/server/handlers/workflow-steps.d.ts +86 -0
  231. package/dist/server/handlers/workflow-steps.js +2349 -0
  232. package/dist/server/handlers/workflows.d.ts +7 -0
  233. package/dist/server/handlers/workflows.js +989 -0
  234. package/dist/server/index.d.ts +1 -0
  235. package/dist/server/index.js +2427 -0
  236. package/dist/server/lib/batch-client.d.ts +80 -0
  237. package/dist/server/lib/batch-client.js +467 -0
  238. package/dist/server/lib/code-worker-pool.d.ts +31 -0
  239. package/dist/server/lib/code-worker-pool.js +224 -0
  240. package/dist/server/lib/code-worker.d.ts +1 -0
  241. package/dist/server/lib/code-worker.js +188 -0
  242. package/dist/server/lib/compaction-service.d.ts +32 -0
  243. package/dist/server/lib/compaction-service.js +162 -0
  244. package/dist/server/lib/logger.d.ts +19 -0
  245. package/dist/server/lib/logger.js +46 -0
  246. package/dist/server/lib/otel.d.ts +38 -0
  247. package/dist/server/lib/otel.js +126 -0
  248. package/dist/server/lib/pg-rate-limiter.d.ts +21 -0
  249. package/dist/server/lib/pg-rate-limiter.js +86 -0
  250. package/dist/server/lib/prompt-sanitizer.d.ts +37 -0
  251. package/dist/server/lib/prompt-sanitizer.js +177 -0
  252. package/dist/server/lib/provider-capabilities.d.ts +85 -0
  253. package/dist/server/lib/provider-capabilities.js +190 -0
  254. package/dist/server/lib/provider-failover.d.ts +74 -0
  255. package/dist/server/lib/provider-failover.js +210 -0
  256. package/dist/server/lib/rate-limiter.d.ts +39 -0
  257. package/dist/server/lib/rate-limiter.js +147 -0
  258. package/dist/server/lib/server-agent-loop.d.ts +107 -0
  259. package/dist/server/lib/server-agent-loop.js +667 -0
  260. package/dist/server/lib/server-subagent.d.ts +78 -0
  261. package/dist/server/lib/server-subagent.js +203 -0
  262. package/dist/server/lib/session-checkpoint.d.ts +51 -0
  263. package/dist/server/lib/session-checkpoint.js +145 -0
  264. package/dist/server/lib/ssrf-guard.d.ts +13 -0
  265. package/dist/server/lib/ssrf-guard.js +240 -0
  266. package/dist/server/lib/supabase-client.d.ts +7 -0
  267. package/dist/server/lib/supabase-client.js +78 -0
  268. package/dist/server/lib/template-resolver.d.ts +31 -0
  269. package/dist/server/lib/template-resolver.js +215 -0
  270. package/dist/server/lib/utils.d.ts +16 -0
  271. package/dist/server/lib/utils.js +147 -0
  272. package/dist/server/local-agent-gateway.d.ts +82 -0
  273. package/dist/server/local-agent-gateway.js +426 -0
  274. package/dist/server/providers/anthropic.d.ts +20 -0
  275. package/dist/server/providers/anthropic.js +199 -0
  276. package/dist/server/providers/bedrock.d.ts +20 -0
  277. package/dist/server/providers/bedrock.js +194 -0
  278. package/dist/server/providers/gemini.d.ts +24 -0
  279. package/dist/server/providers/gemini.js +486 -0
  280. package/dist/server/providers/openai.d.ts +24 -0
  281. package/dist/server/providers/openai.js +522 -0
  282. package/dist/server/providers/registry.d.ts +32 -0
  283. package/dist/server/providers/registry.js +58 -0
  284. package/dist/server/providers/shared.d.ts +32 -0
  285. package/dist/server/providers/shared.js +124 -0
  286. package/dist/server/providers/types.d.ts +92 -0
  287. package/dist/server/providers/types.js +12 -0
  288. package/dist/server/proxy-handlers.d.ts +6 -0
  289. package/dist/server/proxy-handlers.js +89 -0
  290. package/dist/server/tool-router.d.ts +149 -0
  291. package/dist/server/tool-router.js +803 -0
  292. package/dist/server/validation.d.ts +24 -0
  293. package/dist/server/validation.js +301 -0
  294. package/dist/server/worker.d.ts +19 -0
  295. package/dist/server/worker.js +201 -0
  296. package/dist/setup.d.ts +8 -0
  297. package/dist/setup.js +181 -0
  298. package/dist/shared/agent-core.d.ts +157 -0
  299. package/dist/shared/agent-core.js +534 -0
  300. package/dist/shared/anthropic-types.d.ts +105 -0
  301. package/dist/shared/anthropic-types.js +7 -0
  302. package/dist/shared/api-client.d.ts +90 -0
  303. package/dist/shared/api-client.js +379 -0
  304. package/dist/shared/constants.d.ts +33 -0
  305. package/dist/shared/constants.js +80 -0
  306. package/dist/shared/sse-parser.d.ts +26 -0
  307. package/dist/shared/sse-parser.js +259 -0
  308. package/dist/shared/tool-dispatch.d.ts +52 -0
  309. package/dist/shared/tool-dispatch.js +191 -0
  310. package/dist/shared/types.d.ts +72 -0
  311. package/dist/shared/types.js +7 -0
  312. package/dist/updater.d.ts +25 -0
  313. package/dist/updater.js +140 -0
  314. package/dist/webchat/widget.d.ts +0 -0
  315. package/dist/webchat/widget.js +397 -0
  316. package/package.json +95 -0
  317. package/src/cli/services/builtin-skills/commit.md +19 -0
  318. package/src/cli/services/builtin-skills/review-pr.md +21 -0
  319. package/src/cli/services/builtin-skills/review.md +18 -0
@@ -0,0 +1,6 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ export declare function handleImageGen(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<{
3
+ success: boolean;
4
+ data?: unknown;
5
+ error?: string;
6
+ }>;
@@ -0,0 +1,409 @@
1
+ // server/handlers/image-gen.ts — Multi-provider image generation with batch/parallel support
2
+ // Providers: OpenAI (DALL-E 3), Google (Imagen 3), Gemini (native image generation)
3
+ // Auto-uploads to Supabase storage and inserts into store_media table
4
+ import OpenAI from "openai";
5
+ import { GoogleGenAI } from "@google/genai";
6
+ async function getImageCredentials(sb, storeId) {
7
+ const creds = {};
8
+ const keys = ["OPENAI_API_KEY", "GOOGLE_AI_API_KEY"];
9
+ const results = await Promise.all(keys.map(async (k) => {
10
+ try {
11
+ const r = await sb.rpc("decrypt_secret", { p_name: k, p_store_id: storeId });
12
+ return r.data;
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }));
18
+ if (results[0])
19
+ creds.openai = results[0];
20
+ if (results[1])
21
+ creds.google = results[1];
22
+ return creds;
23
+ }
24
+ // ============================================================================
25
+ // PROVIDER IMPLEMENTATIONS
26
+ // ============================================================================
27
+ async function generateWithDalle(apiKey, prompt, size, quality, style) {
28
+ const client = new OpenAI({ apiKey });
29
+ const validSizes = ["1024x1024", "1024x1792", "1792x1024"];
30
+ const selectedSize = validSizes.includes(size) ? size : "1024x1024";
31
+ const resp = await client.images.generate({
32
+ model: "dall-e-3",
33
+ prompt,
34
+ n: 1,
35
+ size: selectedSize,
36
+ quality: quality === "hd" ? "hd" : "standard",
37
+ style: style === "natural" ? "natural" : "vivid",
38
+ response_format: "b64_json",
39
+ });
40
+ const first = resp.data?.[0];
41
+ if (!first?.b64_json)
42
+ throw new Error("DALL-E returned no image data");
43
+ return {
44
+ base64: first.b64_json,
45
+ revisedPrompt: first.revised_prompt || prompt,
46
+ };
47
+ }
48
+ async function generateWithImagen(apiKey, prompt, aspectRatio) {
49
+ const client = new GoogleGenAI({ apiKey });
50
+ const validRatios = ["1:1", "3:4", "4:3", "9:16", "16:9"];
51
+ const selectedRatio = validRatios.includes(aspectRatio) ? aspectRatio : "1:1";
52
+ const response = await client.models.generateImages({
53
+ model: "imagen-4.0-generate-001",
54
+ prompt,
55
+ config: {
56
+ numberOfImages: 1,
57
+ aspectRatio: selectedRatio,
58
+ },
59
+ });
60
+ const image = response.generatedImages?.[0];
61
+ if (!image?.image?.imageBytes) {
62
+ throw new Error("Imagen returned no image data");
63
+ }
64
+ return { base64: image.image.imageBytes };
65
+ }
66
+ async function generateWithGemini(apiKey, prompt, model = "gemini-2.5-flash-image") {
67
+ const client = new GoogleGenAI({ apiKey });
68
+ const response = await client.models.generateContent({
69
+ model,
70
+ contents: prompt,
71
+ config: {
72
+ responseModalities: ["TEXT", "IMAGE"],
73
+ },
74
+ });
75
+ // Find image part in response
76
+ const parts = response.candidates?.[0]?.content?.parts;
77
+ if (!parts)
78
+ throw new Error("Gemini returned no content parts");
79
+ for (const part of parts) {
80
+ if (part.inlineData?.data) {
81
+ return {
82
+ base64: part.inlineData.data,
83
+ mimeType: part.inlineData.mimeType || "image/png",
84
+ };
85
+ }
86
+ }
87
+ throw new Error("Gemini response contained no image data");
88
+ }
89
+ // ============================================================================
90
+ // STORAGE + MEDIA HELPERS
91
+ // ============================================================================
92
+ async function uploadAndRecord(sb, storeId, base64Data, prompt, provider, model, mimeType = "image/png") {
93
+ const id = crypto.randomUUID();
94
+ const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
95
+ const fileName = `${id}.${ext}`;
96
+ const storeIdUpper = storeId.toUpperCase();
97
+ const storagePath = `ai-generated/${storeIdUpper}/standalone/${fileName}`;
98
+ // Decode base64 to buffer
99
+ const buffer = Buffer.from(base64Data, "base64");
100
+ // Upload to Supabase storage
101
+ const { error: uploadErr } = await sb.storage
102
+ .from("product-images")
103
+ .upload(storagePath, buffer, {
104
+ contentType: mimeType,
105
+ upsert: true,
106
+ });
107
+ if (uploadErr) {
108
+ throw new Error(`Storage upload failed: ${uploadErr.message}`);
109
+ }
110
+ // Get public URL
111
+ const { data: urlData } = sb.storage.from("product-images").getPublicUrl(storagePath);
112
+ const fileUrl = urlData.publicUrl;
113
+ // Determine AI tags based on provider
114
+ const aiTags = [
115
+ provider === "openai" ? "DALL-E 3" : provider === "imagen" ? "Imagen 3" : "Gemini",
116
+ "AI Generated",
117
+ ];
118
+ // Insert into store_media
119
+ const { data: mediaRow, error: mediaErr } = await sb
120
+ .from("store_media")
121
+ .insert({
122
+ store_id: storeId,
123
+ file_name: fileName,
124
+ file_path: storagePath,
125
+ file_url: fileUrl,
126
+ file_size: buffer.length,
127
+ file_type: mimeType,
128
+ category: "ai_generated",
129
+ ai_tags: aiTags,
130
+ ai_description: prompt.substring(0, 500),
131
+ source: `mcp-${provider}`,
132
+ folder: "ai-generated",
133
+ })
134
+ .select("id")
135
+ .single();
136
+ if (mediaErr) {
137
+ console.error("[image-gen] store_media insert error:", mediaErr.message);
138
+ }
139
+ return {
140
+ id,
141
+ provider,
142
+ model,
143
+ prompt,
144
+ file_url: fileUrl,
145
+ file_name: fileName,
146
+ file_size: buffer.length,
147
+ media_id: mediaRow?.id || id,
148
+ };
149
+ }
150
+ // ============================================================================
151
+ // HANDLER
152
+ // ============================================================================
153
+ export async function handleImageGen(sb, args, storeId) {
154
+ const action = args.action;
155
+ if (!storeId) {
156
+ return { success: false, error: "store_id is required" };
157
+ }
158
+ switch (action) {
159
+ // ================================================================
160
+ // GENERATE — single image generation
161
+ // ================================================================
162
+ case "generate": {
163
+ const prompt = args.prompt;
164
+ if (!prompt)
165
+ return { success: false, error: "prompt is required" };
166
+ const provider = args.provider || "openai";
167
+ const size = args.size || "1024x1024";
168
+ const quality = args.quality || "standard";
169
+ const style = args.style || "vivid";
170
+ const aspectRatio = args.aspect_ratio || "1:1";
171
+ const creds = await getImageCredentials(sb, storeId);
172
+ try {
173
+ let base64;
174
+ let model;
175
+ let mimeType = "image/png";
176
+ switch (provider) {
177
+ case "openai": {
178
+ if (!creds.openai)
179
+ return { success: false, error: "OpenAI API key not configured" };
180
+ const result = await generateWithDalle(creds.openai, prompt, size, quality, style);
181
+ base64 = result.base64;
182
+ model = "dall-e-3";
183
+ break;
184
+ }
185
+ case "imagen": {
186
+ if (!creds.google)
187
+ return { success: false, error: "Google AI API key not configured" };
188
+ const result = await generateWithImagen(creds.google, prompt, aspectRatio);
189
+ base64 = result.base64;
190
+ model = "imagen-4.0-generate-001";
191
+ break;
192
+ }
193
+ case "gemini": {
194
+ if (!creds.google)
195
+ return { success: false, error: "Google AI API key not configured" };
196
+ const result = await generateWithGemini(creds.google, prompt);
197
+ base64 = result.base64;
198
+ model = "gemini-2.5-flash-image";
199
+ mimeType = result.mimeType;
200
+ break;
201
+ }
202
+ case "gemini3": {
203
+ if (!creds.google)
204
+ return { success: false, error: "Google AI API key not configured" };
205
+ const result = await generateWithGemini(creds.google, prompt, "gemini-3-pro-image-preview");
206
+ base64 = result.base64;
207
+ model = "gemini-3-pro-image-preview";
208
+ mimeType = result.mimeType;
209
+ break;
210
+ }
211
+ default:
212
+ return { success: false, error: `Unknown provider: ${provider}. Use openai, imagen, gemini, or gemini3` };
213
+ }
214
+ const image = await uploadAndRecord(sb, storeId, base64, prompt, provider, model, mimeType);
215
+ return { success: true, data: image };
216
+ }
217
+ catch (err) {
218
+ const msg = err instanceof Error ? err.message : String(err);
219
+ return { success: false, error: `Image generation failed: ${msg}` };
220
+ }
221
+ }
222
+ // ================================================================
223
+ // BATCH — parallel batch generation (multiple prompts and/or providers)
224
+ // ================================================================
225
+ case "batch": {
226
+ const items = args.items;
227
+ if (!items || !Array.isArray(items) || items.length === 0) {
228
+ return { success: false, error: "items array is required with at least one {prompt} entry" };
229
+ }
230
+ if (items.length > 10) {
231
+ return { success: false, error: "Maximum 10 images per batch" };
232
+ }
233
+ const creds = await getImageCredentials(sb, storeId);
234
+ // Run all generations in parallel
235
+ const results = await Promise.allSettled(items.map(async (item) => {
236
+ const provider = item.provider || "openai";
237
+ const size = item.size || "1024x1024";
238
+ const quality = item.quality || "standard";
239
+ const style = item.style || "vivid";
240
+ const aspectRatio = item.aspect_ratio || "1:1";
241
+ let base64;
242
+ let model;
243
+ let mimeType = "image/png";
244
+ switch (provider) {
245
+ case "openai": {
246
+ if (!creds.openai)
247
+ throw new Error("OpenAI API key not configured");
248
+ const result = await generateWithDalle(creds.openai, item.prompt, size, quality, style);
249
+ base64 = result.base64;
250
+ model = "dall-e-3";
251
+ break;
252
+ }
253
+ case "imagen": {
254
+ if (!creds.google)
255
+ throw new Error("Google AI API key not configured");
256
+ const result = await generateWithImagen(creds.google, item.prompt, aspectRatio);
257
+ base64 = result.base64;
258
+ model = "imagen-4.0-generate-001";
259
+ break;
260
+ }
261
+ case "gemini": {
262
+ if (!creds.google)
263
+ throw new Error("Google AI API key not configured");
264
+ const result = await generateWithGemini(creds.google, item.prompt);
265
+ base64 = result.base64;
266
+ model = "gemini-2.5-flash-image";
267
+ mimeType = result.mimeType;
268
+ break;
269
+ }
270
+ case "gemini3": {
271
+ if (!creds.google)
272
+ throw new Error("Google AI API key not configured");
273
+ const result = await generateWithGemini(creds.google, item.prompt, "gemini-3-pro-image-preview");
274
+ base64 = result.base64;
275
+ model = "gemini-3-pro-image-preview";
276
+ mimeType = result.mimeType;
277
+ break;
278
+ }
279
+ default:
280
+ throw new Error(`Unknown provider: ${provider}`);
281
+ }
282
+ return uploadAndRecord(sb, storeId, base64, item.prompt, provider, model, mimeType);
283
+ }));
284
+ const images = [];
285
+ const errors = [];
286
+ results.forEach((r, i) => {
287
+ if (r.status === "fulfilled") {
288
+ images.push(r.value);
289
+ }
290
+ else {
291
+ errors.push({
292
+ index: i,
293
+ prompt: items[i].prompt,
294
+ error: r.reason instanceof Error ? r.reason.message : String(r.reason),
295
+ });
296
+ }
297
+ });
298
+ return {
299
+ success: true,
300
+ data: {
301
+ generated: images.length,
302
+ failed: errors.length,
303
+ total: items.length,
304
+ images,
305
+ ...(errors.length > 0 ? { errors } : {}),
306
+ },
307
+ };
308
+ }
309
+ // ================================================================
310
+ // LIST — list generated images from store_media
311
+ // ================================================================
312
+ case "list": {
313
+ const limit = Math.min(args.limit || 25, 100);
314
+ const category = args.category || "ai_generated";
315
+ const folder = args.folder;
316
+ let query = sb
317
+ .from("store_media")
318
+ .select("id, file_name, file_url, file_size, file_type, category, ai_tags, ai_description, source, folder, created_at")
319
+ .eq("store_id", storeId)
320
+ .eq("status", "active")
321
+ .order("created_at", { ascending: false })
322
+ .limit(limit);
323
+ if (category !== "all") {
324
+ query = query.eq("category", category);
325
+ }
326
+ if (folder) {
327
+ query = query.eq("folder", folder);
328
+ }
329
+ const { data, error } = await query;
330
+ if (error)
331
+ return { success: false, error: error.message };
332
+ return { success: true, data: { images: data, count: data?.length || 0 } };
333
+ }
334
+ // ================================================================
335
+ // GET — get a specific image by media_id
336
+ // ================================================================
337
+ case "get": {
338
+ const mediaId = args.media_id;
339
+ if (!mediaId)
340
+ return { success: false, error: "media_id is required" };
341
+ const { data, error } = await sb
342
+ .from("store_media")
343
+ .select("*")
344
+ .eq("id", mediaId)
345
+ .eq("store_id", storeId)
346
+ .single();
347
+ if (error)
348
+ return { success: false, error: error.message };
349
+ return { success: true, data };
350
+ }
351
+ // ================================================================
352
+ // DELETE — soft-delete an image (set status to archived)
353
+ // ================================================================
354
+ case "delete": {
355
+ const mediaId = args.media_id;
356
+ if (!mediaId)
357
+ return { success: false, error: "media_id is required" };
358
+ const { error } = await sb
359
+ .from("store_media")
360
+ .update({ status: "archived", updated_at: new Date().toISOString() })
361
+ .eq("id", mediaId)
362
+ .eq("store_id", storeId);
363
+ if (error)
364
+ return { success: false, error: error.message };
365
+ return { success: true, data: { deleted: mediaId } };
366
+ }
367
+ // ================================================================
368
+ // PROVIDERS — list available image generation providers
369
+ // ================================================================
370
+ case "providers": {
371
+ const creds = await getImageCredentials(sb, storeId);
372
+ return {
373
+ success: true,
374
+ data: {
375
+ providers: [
376
+ {
377
+ provider: "openai",
378
+ model: "dall-e-3",
379
+ configured: !!creds.openai,
380
+ sizes: ["1024x1024", "1024x1792", "1792x1024"],
381
+ quality_options: ["standard", "hd"],
382
+ style_options: ["vivid", "natural"],
383
+ },
384
+ {
385
+ provider: "imagen",
386
+ model: "imagen-4.0-generate-001",
387
+ configured: !!creds.google,
388
+ aspect_ratios: ["1:1", "3:4", "4:3", "9:16", "16:9"],
389
+ },
390
+ {
391
+ provider: "gemini",
392
+ model: "gemini-2.5-flash-image",
393
+ configured: !!creds.google,
394
+ note: "Gemini 2.5 Flash native image generation (Nano Banana)",
395
+ },
396
+ {
397
+ provider: "gemini3",
398
+ model: "gemini-3-pro-image-preview",
399
+ configured: !!creds.google,
400
+ note: "Gemini 3 Pro image generation — highest quality Google model",
401
+ },
402
+ ],
403
+ },
404
+ };
405
+ }
406
+ default:
407
+ return { success: false, error: `Unknown action: ${action}. Valid: generate, batch, list, get, delete, providers` };
408
+ }
409
+ }