cowork-os 0.3.21 → 0.3.25

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 (252) hide show
  1. package/README.md +372 -10
  2. package/connectors/README.md +20 -0
  3. package/connectors/asana-mcp/README.md +24 -0
  4. package/connectors/asana-mcp/dist/index.js +427 -0
  5. package/connectors/asana-mcp/package.json +15 -0
  6. package/connectors/asana-mcp/src/index.ts +553 -0
  7. package/connectors/asana-mcp/tsconfig.json +13 -0
  8. package/connectors/hubspot-mcp/README.md +35 -0
  9. package/connectors/hubspot-mcp/dist/index.js +454 -0
  10. package/connectors/hubspot-mcp/package.json +15 -0
  11. package/connectors/hubspot-mcp/src/index.ts +562 -0
  12. package/connectors/hubspot-mcp/tsconfig.json +13 -0
  13. package/connectors/jira-mcp/README.md +49 -0
  14. package/connectors/jira-mcp/dist/index.js +588 -0
  15. package/connectors/jira-mcp/package.json +15 -0
  16. package/connectors/jira-mcp/src/index.ts +711 -0
  17. package/connectors/jira-mcp/tsconfig.json +13 -0
  18. package/connectors/linear-mcp/README.md +22 -0
  19. package/connectors/linear-mcp/dist/index.js +402 -0
  20. package/connectors/linear-mcp/package.json +15 -0
  21. package/connectors/linear-mcp/src/index.ts +522 -0
  22. package/connectors/linear-mcp/tsconfig.json +13 -0
  23. package/connectors/okta-mcp/README.md +24 -0
  24. package/connectors/okta-mcp/dist/index.js +411 -0
  25. package/connectors/okta-mcp/package.json +15 -0
  26. package/connectors/okta-mcp/src/index.ts +520 -0
  27. package/connectors/okta-mcp/tsconfig.json +13 -0
  28. package/connectors/salesforce-mcp/README.md +47 -0
  29. package/connectors/salesforce-mcp/dist/index.js +584 -0
  30. package/connectors/salesforce-mcp/package.json +15 -0
  31. package/connectors/salesforce-mcp/src/index.ts +722 -0
  32. package/connectors/salesforce-mcp/tsconfig.json +13 -0
  33. package/connectors/servicenow-mcp/README.md +26 -0
  34. package/connectors/servicenow-mcp/dist/index.js +400 -0
  35. package/connectors/servicenow-mcp/package.json +15 -0
  36. package/connectors/servicenow-mcp/src/index.ts +500 -0
  37. package/connectors/servicenow-mcp/tsconfig.json +13 -0
  38. package/connectors/templates/mcp-connector/README.md +31 -0
  39. package/connectors/templates/mcp-connector/package.json +15 -0
  40. package/connectors/templates/mcp-connector/src/index.ts +330 -0
  41. package/connectors/templates/mcp-connector/tsconfig.json +13 -0
  42. package/connectors/zendesk-mcp/README.md +40 -0
  43. package/connectors/zendesk-mcp/dist/index.js +431 -0
  44. package/connectors/zendesk-mcp/package.json +15 -0
  45. package/connectors/zendesk-mcp/src/index.ts +543 -0
  46. package/connectors/zendesk-mcp/tsconfig.json +13 -0
  47. package/dist/electron/electron/agent/custom-skill-loader.js +31 -1
  48. package/dist/electron/electron/agent/daemon.js +189 -13
  49. package/dist/electron/electron/agent/executor.js +895 -78
  50. package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
  51. package/dist/electron/electron/agent/llm/azure-openai-provider.js +328 -0
  52. package/dist/electron/electron/agent/llm/bedrock-provider.js +49 -9
  53. package/dist/electron/electron/agent/llm/github-copilot-provider.js +97 -0
  54. package/dist/electron/electron/agent/llm/groq-provider.js +33 -0
  55. package/dist/electron/electron/agent/llm/index.js +13 -1
  56. package/dist/electron/electron/agent/llm/kimi-provider.js +33 -0
  57. package/dist/electron/electron/agent/llm/openai-compatible-provider.js +116 -0
  58. package/dist/electron/electron/agent/llm/openai-compatible.js +111 -0
  59. package/dist/electron/electron/agent/llm/openai-oauth.js +2 -1
  60. package/dist/electron/electron/agent/llm/openrouter-provider.js +1 -1
  61. package/dist/electron/electron/agent/llm/provider-factory.js +350 -4
  62. package/dist/electron/electron/agent/llm/types.js +66 -1
  63. package/dist/electron/electron/agent/llm/xai-provider.js +33 -0
  64. package/dist/electron/electron/agent/search/provider-factory.js +38 -2
  65. package/dist/electron/electron/agent/tools/box-tools.js +231 -0
  66. package/dist/electron/electron/agent/tools/builtin-settings.js +28 -0
  67. package/dist/electron/electron/agent/tools/dropbox-tools.js +237 -0
  68. package/dist/electron/electron/agent/tools/file-tools.js +66 -3
  69. package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
  70. package/dist/electron/electron/agent/tools/grep-tools.js +90 -10
  71. package/dist/electron/electron/agent/tools/image-tools.js +11 -1
  72. package/dist/electron/electron/agent/tools/notion-tools.js +312 -0
  73. package/dist/electron/electron/agent/tools/onedrive-tools.js +217 -0
  74. package/dist/electron/electron/agent/tools/registry.js +548 -10
  75. package/dist/electron/electron/agent/tools/search-tools.js +28 -10
  76. package/dist/electron/electron/agent/tools/sharepoint-tools.js +243 -0
  77. package/dist/electron/electron/agent/tools/shell-tools.js +12 -3
  78. package/dist/electron/electron/agent/tools/x-tools.js +1 -1
  79. package/dist/electron/electron/agents/agent-dispatch.js +63 -0
  80. package/dist/electron/electron/database/repositories.js +19 -5
  81. package/dist/electron/electron/database/schema.js +8 -0
  82. package/dist/electron/electron/gateway/channels/whatsapp.js +55 -0
  83. package/dist/electron/electron/gateway/index.js +75 -1
  84. package/dist/electron/electron/gateway/router.js +209 -154
  85. package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
  86. package/dist/electron/electron/ipc/handlers.js +763 -267
  87. package/dist/electron/electron/main.js +63 -0
  88. package/dist/electron/electron/mcp/oauth/connector-oauth.js +333 -0
  89. package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +503 -154
  90. package/dist/electron/electron/memory/MemoryService.js +2 -1
  91. package/dist/electron/electron/preload.js +78 -1
  92. package/dist/electron/electron/settings/appearance-manager.js +18 -1
  93. package/dist/electron/electron/settings/box-manager.js +54 -0
  94. package/dist/electron/electron/settings/dropbox-manager.js +54 -0
  95. package/dist/electron/electron/settings/google-drive-manager.js +54 -0
  96. package/dist/electron/electron/settings/notion-manager.js +56 -0
  97. package/dist/electron/electron/settings/onedrive-manager.js +54 -0
  98. package/dist/electron/electron/settings/sharepoint-manager.js +54 -0
  99. package/dist/electron/electron/utils/box-api.js +153 -0
  100. package/dist/electron/electron/utils/dropbox-api.js +144 -0
  101. package/dist/electron/electron/utils/env-migration.js +19 -0
  102. package/dist/electron/electron/utils/google-drive-api.js +152 -0
  103. package/dist/electron/electron/utils/notion-api.js +103 -0
  104. package/dist/electron/electron/utils/onedrive-api.js +113 -0
  105. package/dist/electron/electron/utils/sharepoint-api.js +109 -0
  106. package/dist/electron/electron/utils/validation.js +98 -3
  107. package/dist/electron/electron/utils/x-cli.js +1 -1
  108. package/dist/electron/shared/channelMessages.js +284 -3
  109. package/dist/electron/shared/llm-provider-catalog.js +198 -0
  110. package/dist/electron/shared/types.js +90 -1
  111. package/package.json +14 -3
  112. package/resources/skills/nano-banana-pro.json +4 -4
  113. package/resources/skills/openai-image-gen.json +3 -3
  114. package/resources/skills/scripts/gen.py +163 -0
  115. package/resources/skills/scripts/generate_image.py +91 -0
  116. package/src/electron/agent/custom-skill-loader.ts +34 -1
  117. package/src/electron/agent/daemon.ts +210 -14
  118. package/src/electron/agent/executor.ts +1124 -85
  119. package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
  120. package/src/electron/agent/llm/azure-openai-provider.ts +388 -0
  121. package/src/electron/agent/llm/bedrock-provider.ts +62 -9
  122. package/src/electron/agent/llm/github-copilot-provider.ts +117 -0
  123. package/src/electron/agent/llm/groq-provider.ts +39 -0
  124. package/src/electron/agent/llm/index.ts +6 -0
  125. package/src/electron/agent/llm/kimi-provider.ts +39 -0
  126. package/src/electron/agent/llm/openai-compatible-provider.ts +153 -0
  127. package/src/electron/agent/llm/openai-compatible.ts +133 -0
  128. package/src/electron/agent/llm/openai-oauth.ts +2 -1
  129. package/src/electron/agent/llm/openrouter-provider.ts +2 -1
  130. package/src/electron/agent/llm/provider-factory.ts +459 -6
  131. package/src/electron/agent/llm/types.ts +95 -1
  132. package/src/electron/agent/llm/xai-provider.ts +39 -0
  133. package/src/electron/agent/search/provider-factory.ts +43 -2
  134. package/src/electron/agent/tools/box-tools.ts +239 -0
  135. package/src/electron/agent/tools/builtin-settings.ts +36 -0
  136. package/src/electron/agent/tools/dropbox-tools.ts +237 -0
  137. package/src/electron/agent/tools/file-tools.ts +66 -3
  138. package/src/electron/agent/tools/gmail-tools.ts +240 -0
  139. package/src/electron/agent/tools/google-calendar-tools.ts +258 -0
  140. package/src/electron/agent/tools/google-drive-tools.ts +228 -0
  141. package/src/electron/agent/tools/grep-tools.ts +97 -12
  142. package/src/electron/agent/tools/image-tools.ts +11 -1
  143. package/src/electron/agent/tools/notion-tools.ts +330 -0
  144. package/src/electron/agent/tools/onedrive-tools.ts +217 -0
  145. package/src/electron/agent/tools/registry.ts +794 -10
  146. package/src/electron/agent/tools/search-tools.ts +29 -11
  147. package/src/electron/agent/tools/sharepoint-tools.ts +247 -0
  148. package/src/electron/agent/tools/shell-tools.ts +11 -3
  149. package/src/electron/agent/tools/x-tools.ts +1 -1
  150. package/src/electron/agents/agent-dispatch.ts +79 -0
  151. package/src/electron/database/SecureSettingsRepository.ts +7 -1
  152. package/src/electron/database/repositories.ts +58 -6
  153. package/src/electron/database/schema.ts +8 -0
  154. package/src/electron/gateway/channels/discord.ts +4 -0
  155. package/src/electron/gateway/channels/google-chat.ts +3 -0
  156. package/src/electron/gateway/channels/line.ts +3 -0
  157. package/src/electron/gateway/channels/matrix-client.ts +15 -0
  158. package/src/electron/gateway/channels/matrix.ts +31 -0
  159. package/src/electron/gateway/channels/mattermost.ts +3 -0
  160. package/src/electron/gateway/channels/signal.ts +3 -0
  161. package/src/electron/gateway/channels/slack.ts +9 -4
  162. package/src/electron/gateway/channels/teams.ts +4 -0
  163. package/src/electron/gateway/channels/telegram.ts +2 -0
  164. package/src/electron/gateway/channels/twitch.ts +2 -0
  165. package/src/electron/gateway/channels/types.ts +8 -0
  166. package/src/electron/gateway/channels/whatsapp.ts +66 -0
  167. package/src/electron/gateway/index.ts +95 -2
  168. package/src/electron/gateway/router.ts +231 -161
  169. package/src/electron/gateway/security.ts +21 -9
  170. package/src/electron/ipc/canvas-handlers.ts +10 -0
  171. package/src/electron/ipc/handlers.ts +848 -292
  172. package/src/electron/main.ts +35 -0
  173. package/src/electron/mcp/oauth/connector-oauth.ts +448 -0
  174. package/src/electron/mcp/registry/MCPRegistryManager.ts +343 -12
  175. package/src/electron/memory/MemoryService.ts +7 -1
  176. package/src/electron/preload.ts +200 -5
  177. package/src/electron/settings/appearance-manager.ts +20 -2
  178. package/src/electron/settings/box-manager.ts +58 -0
  179. package/src/electron/settings/dropbox-manager.ts +58 -0
  180. package/src/electron/settings/google-workspace-manager.ts +59 -0
  181. package/src/electron/settings/notion-manager.ts +60 -0
  182. package/src/electron/settings/onedrive-manager.ts +58 -0
  183. package/src/electron/settings/sharepoint-manager.ts +58 -0
  184. package/src/electron/utils/box-api.ts +184 -0
  185. package/src/electron/utils/dropbox-api.ts +171 -0
  186. package/src/electron/utils/env-migration.ts +22 -0
  187. package/src/electron/utils/gmail-api.ts +121 -0
  188. package/src/electron/utils/google-calendar-api.ts +115 -0
  189. package/src/electron/utils/google-workspace-api.ts +228 -0
  190. package/src/electron/utils/google-workspace-auth.ts +109 -0
  191. package/src/electron/utils/google-workspace-oauth.ts +232 -0
  192. package/src/electron/utils/notion-api.ts +126 -0
  193. package/src/electron/utils/onedrive-api.ts +137 -0
  194. package/src/electron/utils/sharepoint-api.ts +132 -0
  195. package/src/electron/utils/validation.ts +128 -1
  196. package/src/electron/utils/x-cli.ts +1 -1
  197. package/src/renderer/App.tsx +119 -8
  198. package/src/renderer/components/ActivityFeedItem.tsx +34 -17
  199. package/src/renderer/components/AgentWorkingStatePanel.tsx +7 -5
  200. package/src/renderer/components/AppearanceSettings.tsx +37 -2
  201. package/src/renderer/components/BlueBubblesSettings.tsx +18 -7
  202. package/src/renderer/components/BoxSettings.tsx +203 -0
  203. package/src/renderer/components/BrowserView.tsx +101 -0
  204. package/src/renderer/components/BuiltinToolsSettings.tsx +105 -0
  205. package/src/renderer/components/CanvasPreview.tsx +68 -1
  206. package/src/renderer/components/ConnectorEnvModal.tsx +116 -0
  207. package/src/renderer/components/ConnectorSetupModal.tsx +566 -0
  208. package/src/renderer/components/ConnectorsSettings.tsx +397 -0
  209. package/src/renderer/components/ControlPlaneSettings.tsx +2 -0
  210. package/src/renderer/components/DiscordSettings.tsx +18 -7
  211. package/src/renderer/components/DropboxSettings.tsx +202 -0
  212. package/src/renderer/components/EmailSettings.tsx +18 -7
  213. package/src/renderer/components/FileViewer.tsx +21 -13
  214. package/src/renderer/components/GoogleChatSettings.tsx +17 -7
  215. package/src/renderer/components/GoogleWorkspaceSettings.tsx +332 -0
  216. package/src/renderer/components/ImessageSettings.tsx +22 -11
  217. package/src/renderer/components/LineIcons.tsx +376 -0
  218. package/src/renderer/components/LineSettings.tsx +18 -7
  219. package/src/renderer/components/MCPSettings.tsx +56 -0
  220. package/src/renderer/components/MainContent.tsx +740 -76
  221. package/src/renderer/components/MatrixSettings.tsx +18 -7
  222. package/src/renderer/components/MattermostSettings.tsx +18 -7
  223. package/src/renderer/components/NodesSettings.tsx +58 -99
  224. package/src/renderer/components/NotificationPanel.tsx +25 -11
  225. package/src/renderer/components/NotionSettings.tsx +231 -0
  226. package/src/renderer/components/Onboarding/Onboarding.tsx +13 -1
  227. package/src/renderer/components/OnboardingModal.tsx +70 -1
  228. package/src/renderer/components/OneDriveSettings.tsx +212 -0
  229. package/src/renderer/components/RightPanel.tsx +141 -28
  230. package/src/renderer/components/ScheduledTasksSettings.tsx +10 -62
  231. package/src/renderer/components/SearchSettings.tsx +118 -114
  232. package/src/renderer/components/Settings.tsx +1425 -651
  233. package/src/renderer/components/SharePointSettings.tsx +224 -0
  234. package/src/renderer/components/Sidebar.tsx +94 -19
  235. package/src/renderer/components/SignalSettings.tsx +18 -7
  236. package/src/renderer/components/SkillHubBrowser.tsx +144 -185
  237. package/src/renderer/components/SlackSettings.tsx +18 -7
  238. package/src/renderer/components/TaskQuickActions.tsx +11 -6
  239. package/src/renderer/components/TaskTimeline.tsx +58 -26
  240. package/src/renderer/components/TeamsSettings.tsx +18 -7
  241. package/src/renderer/components/TelegramSettings.tsx +18 -7
  242. package/src/renderer/components/ThemeIcon.tsx +16 -0
  243. package/src/renderer/components/TwitchSettings.tsx +18 -7
  244. package/src/renderer/components/VoiceSettings.tsx +30 -74
  245. package/src/renderer/components/WhatsAppSettings.tsx +48 -37
  246. package/src/renderer/components/WorkingStateHistory.tsx +7 -5
  247. package/src/renderer/components/WorkspaceSelector.tsx +42 -13
  248. package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
  249. package/src/renderer/styles/index.css +2333 -209
  250. package/src/shared/channelMessages.ts +367 -4
  251. package/src/shared/llm-provider-catalog.ts +217 -0
  252. package/src/shared/types.ts +251 -2
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CUSTOM_PROVIDER_IDS = exports.CUSTOM_PROVIDER_MAP = exports.CUSTOM_PROVIDER_CATALOG = void 0;
4
+ exports.CUSTOM_PROVIDER_CATALOG = [
5
+ {
6
+ id: 'opencode',
7
+ name: 'OpenCode Zen',
8
+ compatibility: 'openai',
9
+ defaultModel: '',
10
+ apiKeyLabel: 'API Key / Token',
11
+ apiKeyPlaceholder: 'Enter token',
12
+ requiresBaseUrl: true,
13
+ description: 'OpenAI-compatible endpoint required.',
14
+ },
15
+ {
16
+ id: 'google-vertex',
17
+ name: 'Google Vertex',
18
+ compatibility: 'openai',
19
+ defaultModel: 'gemini-2.0-flash',
20
+ apiKeyLabel: 'Access Token',
21
+ apiKeyPlaceholder: 'ya29...',
22
+ requiresBaseUrl: true,
23
+ description: 'Requires a compatible gateway endpoint.',
24
+ },
25
+ {
26
+ id: 'google-antigravity',
27
+ name: 'Google Antigravity',
28
+ compatibility: 'openai',
29
+ defaultModel: 'gemini-2.0-flash',
30
+ apiKeyLabel: 'Access Token',
31
+ apiKeyPlaceholder: 'ya29...',
32
+ requiresBaseUrl: true,
33
+ description: 'Requires a compatible gateway endpoint.',
34
+ },
35
+ {
36
+ id: 'google-gemini-cli',
37
+ name: 'Google Gemini CLI',
38
+ compatibility: 'openai',
39
+ defaultModel: 'gemini-2.0-flash',
40
+ apiKeyLabel: 'Access Token',
41
+ apiKeyPlaceholder: 'ya29...',
42
+ requiresBaseUrl: true,
43
+ description: 'Requires a compatible gateway endpoint.',
44
+ },
45
+ {
46
+ id: 'zai',
47
+ name: 'Z.AI',
48
+ compatibility: 'openai',
49
+ defaultModel: 'glm-4.7',
50
+ apiKeyLabel: 'API Key',
51
+ apiKeyPlaceholder: 'zai-...',
52
+ requiresBaseUrl: true,
53
+ description: 'OpenAI-compatible endpoint required.',
54
+ },
55
+ {
56
+ id: 'glm',
57
+ name: 'GLM',
58
+ compatibility: 'openai',
59
+ defaultModel: 'glm-4-plus',
60
+ apiKeyLabel: 'API Key',
61
+ apiKeyPlaceholder: 'glm-...',
62
+ requiresBaseUrl: true,
63
+ description: 'OpenAI-compatible endpoint required.',
64
+ },
65
+ {
66
+ id: 'vercel-ai-gateway',
67
+ name: 'Vercel AI Gateway',
68
+ compatibility: 'anthropic',
69
+ baseUrl: 'https://ai-gateway.vercel.sh/v1',
70
+ defaultModel: 'claude-3-5-sonnet-20241022',
71
+ apiKeyLabel: 'API Key',
72
+ apiKeyPlaceholder: 'vgw_...',
73
+ apiKeyUrl: 'https://vercel.com/docs/ai-gateway',
74
+ },
75
+ {
76
+ id: 'moonshot',
77
+ name: 'Moonshot (Kimi)',
78
+ compatibility: 'openai',
79
+ baseUrl: 'https://api.moonshot.ai/v1',
80
+ defaultModel: 'kimi-k2.5',
81
+ apiKeyLabel: 'API Key',
82
+ apiKeyPlaceholder: 'sk-...',
83
+ },
84
+ {
85
+ id: 'cerebras',
86
+ name: 'Cerebras',
87
+ compatibility: 'openai',
88
+ baseUrl: 'https://api.cerebras.ai/v1',
89
+ defaultModel: 'llama3.1-8b',
90
+ apiKeyLabel: 'API Key',
91
+ apiKeyPlaceholder: 'csk_...',
92
+ apiKeyUrl: 'https://cloud.cerebras.ai/',
93
+ },
94
+ {
95
+ id: 'mistral',
96
+ name: 'Mistral',
97
+ compatibility: 'openai',
98
+ baseUrl: 'https://api.mistral.ai/v1',
99
+ defaultModel: 'mistral-large-latest',
100
+ apiKeyLabel: 'API Key',
101
+ apiKeyPlaceholder: 'mistral-...',
102
+ apiKeyUrl: 'https://console.mistral.ai/',
103
+ },
104
+ {
105
+ id: 'github-copilot',
106
+ name: 'GitHub Copilot',
107
+ compatibility: 'openai',
108
+ defaultModel: 'gpt-4o',
109
+ apiKeyLabel: 'GitHub Token',
110
+ apiKeyPlaceholder: 'ghp_...',
111
+ },
112
+ {
113
+ id: 'qwen-portal',
114
+ name: 'Qwen',
115
+ compatibility: 'anthropic',
116
+ baseUrl: 'https://portal.qwen.ai/v1',
117
+ defaultModel: 'coder-model',
118
+ apiKeyLabel: 'API Key / Token',
119
+ apiKeyPlaceholder: 'qwen-...',
120
+ },
121
+ {
122
+ id: 'minimax',
123
+ name: 'MiniMax',
124
+ compatibility: 'openai',
125
+ baseUrl: 'https://api.minimax.chat/v1',
126
+ defaultModel: 'MiniMax-M2.1',
127
+ apiKeyLabel: 'API Key',
128
+ apiKeyPlaceholder: 'minimax-...',
129
+ },
130
+ {
131
+ id: 'minimax-portal',
132
+ name: 'MiniMax Portal',
133
+ compatibility: 'anthropic',
134
+ baseUrl: 'https://api.minimax.io/anthropic',
135
+ defaultModel: 'MiniMax-M2.1',
136
+ apiKeyLabel: 'API Key / Token',
137
+ apiKeyPlaceholder: 'minimax-...',
138
+ },
139
+ {
140
+ id: 'xiaomi',
141
+ name: 'Xiaomi MiMo',
142
+ compatibility: 'anthropic',
143
+ baseUrl: 'https://api.xiaomimimo.com/anthropic',
144
+ defaultModel: 'mimo-v2-flash',
145
+ apiKeyLabel: 'API Key',
146
+ apiKeyPlaceholder: 'mimo-...',
147
+ },
148
+ {
149
+ id: 'venice',
150
+ name: 'Venice AI',
151
+ compatibility: 'openai',
152
+ baseUrl: 'https://api.venice.ai/api/v1',
153
+ defaultModel: 'llama-3.3-70b',
154
+ apiKeyLabel: 'API Key',
155
+ apiKeyPlaceholder: 'venice-...',
156
+ },
157
+ {
158
+ id: 'synthetic',
159
+ name: 'Synthetic',
160
+ compatibility: 'anthropic',
161
+ baseUrl: 'https://api.synthetic.new/anthropic',
162
+ defaultModel: 'hf:MiniMaxAI/MiniMax-M2.1',
163
+ apiKeyLabel: 'API Key',
164
+ apiKeyPlaceholder: 'syn_...',
165
+ },
166
+ {
167
+ id: 'kimi-code',
168
+ name: 'Kimi Code',
169
+ compatibility: 'openai',
170
+ baseUrl: 'https://api.kimi.com/coding/v1',
171
+ defaultModel: 'kimi-for-coding',
172
+ apiKeyLabel: 'API Key',
173
+ apiKeyPlaceholder: 'sk-...',
174
+ },
175
+ {
176
+ id: 'openai-compatible',
177
+ name: 'OpenAI-Compatible (Custom)',
178
+ compatibility: 'openai',
179
+ baseUrl: 'http://localhost:1234/v1',
180
+ defaultModel: 'gpt-4o-mini',
181
+ apiKeyLabel: 'API Key (Optional)',
182
+ apiKeyPlaceholder: 'sk-...',
183
+ requiresBaseUrl: true,
184
+ apiKeyOptional: true,
185
+ },
186
+ {
187
+ id: 'anthropic-compatible',
188
+ name: 'Anthropic-Compatible (Custom)',
189
+ compatibility: 'anthropic',
190
+ baseUrl: 'http://localhost:4000',
191
+ defaultModel: 'claude-3-5-sonnet-20241022',
192
+ apiKeyLabel: 'API Key',
193
+ apiKeyPlaceholder: 'sk-...',
194
+ requiresBaseUrl: true,
195
+ },
196
+ ];
197
+ exports.CUSTOM_PROVIDER_MAP = new Map(exports.CUSTOM_PROVIDER_CATALOG.map((provider) => [provider.id, provider]));
198
+ exports.CUSTOM_PROVIDER_IDS = new Set(exports.CUSTOM_PROVIDER_CATALOG.map((provider) => provider.id));
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // Core types shared between main and renderer processes
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.VOICE_LANGUAGES = exports.OPENAI_VOICES = exports.DEFAULT_VOICE_SETTINGS = exports.ANALOGY_DOMAINS = exports.DEFAULT_RELATIONSHIP = exports.DEFAULT_QUIRKS = exports.DEFAULT_RESPONSE_STYLE = exports.PERSONA_DEFINITIONS = exports.PERSONALITY_DEFINITIONS = exports.DEFAULT_QUEUE_SETTINGS = exports.DEFAULT_BLOCKED_COMMAND_PATTERNS = exports.DEFAULT_TRUSTED_COMMAND_PATTERNS = exports.IPC_CHANNELS = exports.BOARD_COLUMNS = exports.DEFAULT_AGENT_ROLES = exports.TEMP_WORKSPACE_NAME = exports.TEMP_WORKSPACE_ID = exports.CONTEXT_TOOL_RESTRICTIONS = exports.TOOL_RISK_LEVELS = exports.TOOL_GROUPS = exports.ACCENT_COLORS = void 0;
4
+ exports.VOICE_LANGUAGES = exports.OPENAI_VOICES = exports.DEFAULT_VOICE_SETTINGS = exports.ANALOGY_DOMAINS = exports.DEFAULT_RELATIONSHIP = exports.DEFAULT_QUIRKS = exports.DEFAULT_RESPONSE_STYLE = exports.PERSONA_DEFINITIONS = exports.PERSONALITY_DEFINITIONS = exports.DEFAULT_QUEUE_SETTINGS = exports.DEFAULT_BLOCKED_COMMAND_PATTERNS = exports.DEFAULT_TRUSTED_COMMAND_PATTERNS = exports.LLM_PROVIDER_TYPES = exports.CUSTOM_LLM_PROVIDER_TYPES = exports.BUILTIN_LLM_PROVIDER_TYPES = exports.IPC_CHANNELS = exports.BOARD_COLUMNS = exports.DEFAULT_AGENT_ROLES = exports.TEMP_WORKSPACE_NAME = exports.TEMP_WORKSPACE_ID = exports.CONTEXT_TOOL_RESTRICTIONS = exports.TOOL_RISK_LEVELS = exports.TOOL_GROUPS = exports.ACCENT_COLORS = void 0;
5
5
  exports.getPersonalityById = getPersonalityById;
6
6
  exports.getPersonaById = getPersonaById;
7
7
  exports.ACCENT_COLORS = [
@@ -59,6 +59,12 @@ exports.TOOL_GROUPS = {
59
59
  'group:network': [
60
60
  'web_search',
61
61
  'x_action',
62
+ 'notion_action',
63
+ 'box_action',
64
+ 'onedrive_action',
65
+ 'google_drive_action',
66
+ 'dropbox_action',
67
+ 'sharepoint_action',
62
68
  'browser_navigate',
63
69
  'browser_screenshot',
64
70
  'browser_get_content',
@@ -141,6 +147,12 @@ exports.TOOL_RISK_LEVELS = {
141
147
  browser_save_pdf: 'network',
142
148
  browser_close: 'network',
143
149
  x_action: 'network',
150
+ notion_action: 'network',
151
+ box_action: 'network',
152
+ onedrive_action: 'network',
153
+ google_drive_action: 'network',
154
+ dropbox_action: 'network',
155
+ sharepoint_action: 'network',
144
156
  // Meta
145
157
  revise_plan: 'read',
146
158
  };
@@ -462,6 +474,7 @@ exports.IPC_CHANNELS = {
462
474
  WORKSPACE_LIST: 'workspace:list',
463
475
  WORKSPACE_CREATE: 'workspace:create',
464
476
  WORKSPACE_UPDATE_PERMISSIONS: 'workspace:updatePermissions',
477
+ WORKSPACE_TOUCH: 'workspace:touch',
465
478
  WORKSPACE_GET_TEMP: 'workspace:getTemp', // Get or create temp workspace
466
479
  // Approval operations
467
480
  APPROVAL_RESPOND: 'approval:respond',
@@ -503,6 +516,9 @@ exports.IPC_CHANNELS = {
503
516
  LLM_GET_GEMINI_MODELS: 'llm:getGeminiModels',
504
517
  LLM_GET_OPENROUTER_MODELS: 'llm:getOpenRouterModels',
505
518
  LLM_GET_OPENAI_MODELS: 'llm:getOpenAIModels',
519
+ LLM_GET_GROQ_MODELS: 'llm:getGroqModels',
520
+ LLM_GET_XAI_MODELS: 'llm:getXAIModels',
521
+ LLM_GET_KIMI_MODELS: 'llm:getKimiModels',
506
522
  LLM_OPENAI_OAUTH_START: 'llm:openaiOAuthStart',
507
523
  LLM_OPENAI_OAUTH_LOGOUT: 'llm:openaiOAuthLogout',
508
524
  LLM_GET_BEDROCK_MODELS: 'llm:getBedrockModels',
@@ -528,6 +544,36 @@ exports.IPC_CHANNELS = {
528
544
  X_SAVE_SETTINGS: 'x:saveSettings',
529
545
  X_TEST_CONNECTION: 'x:testConnection',
530
546
  X_GET_STATUS: 'x:getStatus',
547
+ // Notion Settings
548
+ NOTION_GET_SETTINGS: 'notion:getSettings',
549
+ NOTION_SAVE_SETTINGS: 'notion:saveSettings',
550
+ NOTION_TEST_CONNECTION: 'notion:testConnection',
551
+ NOTION_GET_STATUS: 'notion:getStatus',
552
+ // Box Settings
553
+ BOX_GET_SETTINGS: 'box:getSettings',
554
+ BOX_SAVE_SETTINGS: 'box:saveSettings',
555
+ BOX_TEST_CONNECTION: 'box:testConnection',
556
+ BOX_GET_STATUS: 'box:getStatus',
557
+ // OneDrive Settings
558
+ ONEDRIVE_GET_SETTINGS: 'onedrive:getSettings',
559
+ ONEDRIVE_SAVE_SETTINGS: 'onedrive:saveSettings',
560
+ ONEDRIVE_TEST_CONNECTION: 'onedrive:testConnection',
561
+ ONEDRIVE_GET_STATUS: 'onedrive:getStatus',
562
+ // Google Drive Settings
563
+ GOOGLE_DRIVE_GET_SETTINGS: 'googleDrive:getSettings',
564
+ GOOGLE_DRIVE_SAVE_SETTINGS: 'googleDrive:saveSettings',
565
+ GOOGLE_DRIVE_TEST_CONNECTION: 'googleDrive:testConnection',
566
+ GOOGLE_DRIVE_GET_STATUS: 'googleDrive:getStatus',
567
+ // Dropbox Settings
568
+ DROPBOX_GET_SETTINGS: 'dropbox:getSettings',
569
+ DROPBOX_SAVE_SETTINGS: 'dropbox:saveSettings',
570
+ DROPBOX_TEST_CONNECTION: 'dropbox:testConnection',
571
+ DROPBOX_GET_STATUS: 'dropbox:getStatus',
572
+ // SharePoint Settings
573
+ SHAREPOINT_GET_SETTINGS: 'sharepoint:getSettings',
574
+ SHAREPOINT_SAVE_SETTINGS: 'sharepoint:saveSettings',
575
+ SHAREPOINT_TEST_CONNECTION: 'sharepoint:testConnection',
576
+ SHAREPOINT_GET_STATUS: 'sharepoint:getStatus',
531
577
  // App Updates
532
578
  APP_CHECK_UPDATES: 'app:checkUpdates',
533
579
  APP_DOWNLOAD_UPDATE: 'app:downloadUpdate',
@@ -579,6 +625,8 @@ exports.IPC_CHANNELS = {
579
625
  MCP_REGISTRY_UNINSTALL: 'mcp:registryUninstall',
580
626
  MCP_REGISTRY_CHECK_UPDATES: 'mcp:registryCheckUpdates',
581
627
  MCP_REGISTRY_UPDATE_SERVER: 'mcp:registryUpdateServer',
628
+ // MCP Connector OAuth
629
+ MCP_CONNECTOR_OAUTH_START: 'mcp:connectorOAuthStart',
582
630
  // MCP Host
583
631
  MCP_HOST_START: 'mcp:hostStart',
584
632
  MCP_HOST_STOP: 'mcp:hostStop',
@@ -671,6 +719,7 @@ exports.IPC_CHANNELS = {
671
719
  CANVAS_EXPORT_HTML: 'canvas:exportHTML',
672
720
  CANVAS_EXPORT_TO_FOLDER: 'canvas:exportToFolder',
673
721
  CANVAS_OPEN_IN_BROWSER: 'canvas:openInBrowser',
722
+ CANVAS_OPEN_URL: 'canvas:openUrl',
674
723
  CANVAS_GET_SESSION_DIR: 'canvas:getSessionDir',
675
724
  // Mobile Companion Nodes
676
725
  NODE_LIST: 'node:list',
@@ -718,6 +767,46 @@ exports.IPC_CHANNELS = {
718
767
  VOICE_TEST_AZURE: 'voice:testAzure',
719
768
  VOICE_EVENT: 'voice:event',
720
769
  };
770
+ // LLM Provider types
771
+ exports.BUILTIN_LLM_PROVIDER_TYPES = [
772
+ 'anthropic',
773
+ 'bedrock',
774
+ 'ollama',
775
+ 'gemini',
776
+ 'openrouter',
777
+ 'openai',
778
+ 'azure',
779
+ 'groq',
780
+ 'xai',
781
+ 'kimi',
782
+ ];
783
+ exports.CUSTOM_LLM_PROVIDER_TYPES = [
784
+ 'moonshot',
785
+ 'opencode',
786
+ 'google-vertex',
787
+ 'google-antigravity',
788
+ 'google-gemini-cli',
789
+ 'zai',
790
+ 'glm',
791
+ 'vercel-ai-gateway',
792
+ 'cerebras',
793
+ 'mistral',
794
+ 'github-copilot',
795
+ 'qwen-portal',
796
+ 'minimax',
797
+ 'minimax-portal',
798
+ 'xiaomi',
799
+ 'venice',
800
+ 'synthetic',
801
+ 'kimi-code',
802
+ 'kimi-coding',
803
+ 'openai-compatible',
804
+ 'anthropic-compatible',
805
+ ];
806
+ exports.LLM_PROVIDER_TYPES = [
807
+ ...exports.BUILTIN_LLM_PROVIDER_TYPES,
808
+ ...exports.CUSTOM_LLM_PROVIDER_TYPES,
809
+ ];
721
810
  // Default trusted command patterns (glob-like patterns)
722
811
  exports.DEFAULT_TRUSTED_COMMAND_PATTERNS = [
723
812
  'npm test*',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cowork-os",
3
- "version": "0.3.21",
3
+ "version": "0.3.25",
4
4
  "description": "CoWork OS - The operating system for personal AI assistants",
5
5
  "overrides": {
6
6
  "undici": "^7.0.0"
@@ -44,9 +44,10 @@
44
44
  "dev": "concurrently \"npm run dev:react\" \"npm run dev:electron\"",
45
45
  "dev:react": "vite",
46
46
  "dev:electron": "tsc -p tsconfig.electron.json && cross-env NODE_ENV=development electron .",
47
- "build": "npm run build:react && npm run build:electron",
47
+ "build": "npm run build:react && npm run build:electron && npm run build:connectors",
48
48
  "build:react": "vite build",
49
49
  "build:electron": "tsc -p tsconfig.electron.json",
50
+ "build:connectors": "concurrently -n salesforce,jira,hubspot,zendesk,servicenow,linear,asana,okta \"tsc -p connectors/salesforce-mcp/tsconfig.json\" \"tsc -p connectors/jira-mcp/tsconfig.json\" \"tsc -p connectors/hubspot-mcp/tsconfig.json\" \"tsc -p connectors/zendesk-mcp/tsconfig.json\" \"tsc -p connectors/servicenow-mcp/tsconfig.json\" \"tsc -p connectors/linear-mcp/tsconfig.json\" \"tsc -p connectors/asana-mcp/tsconfig.json\" \"tsc -p connectors/okta-mcp/tsconfig.json\"",
50
51
  "package": "npm run build && electron-builder",
51
52
  "lint": "eslint src --ext ts,tsx",
52
53
  "type-check": "tsc --noEmit",
@@ -135,7 +136,17 @@
135
136
  "from": "resources/skills",
136
137
  "to": "skills",
137
138
  "filter": [
138
- "**/*.json"
139
+ "**/*.json",
140
+ "scripts/**"
141
+ ]
142
+ },
143
+ {
144
+ "from": "connectors",
145
+ "to": "connectors",
146
+ "filter": [
147
+ "**/dist/**",
148
+ "**/README.md",
149
+ "**/package.json"
139
150
  ]
140
151
  }
141
152
  ],
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "id": "nano-banana-pro",
3
3
  "name": "Nano-banana-pro",
4
- "description": "Generate or edit images via Gemini 3 Pro Image (Nano Banana Pro).",
5
- "icon": "🍌",
4
+ "description": "Generate images using Nano Banana Pro (Gemini 3 Pro) via the built-in tool.",
5
+ "icon": "\ud83c\udf4c",
6
6
  "category": "Tools",
7
- "prompt": "# Nano Banana Pro (Gemini 3 Pro Image)\n\nUse the bundled script to generate or edit images.\n\nGenerate\n\n```bash\nuv run {baseDir}/scripts/generate_image.py --prompt \"your image description\" --filename \"output.png\" --resolution 1K\n```\n\nEdit (single image)\n\n```bash\nuv run {baseDir}/scripts/generate_image.py --prompt \"edit instructions\" --filename \"output.png\" -i \"/path/in.png\" --resolution 2K\n```\n\nMulti-image composition (up to 14 images)\n\n```bash\nuv run {baseDir}/scripts/generate_image.py --prompt \"combine these into one scene\" --filename \"output.png\" -i img1.png -i img2.png -i img3.png\n```\n\nAPI key\n\n- `GEMINI_API_KEY` env var\n- Or set `skills.\"nano-banana-pro\".apiKey` / `skills.\"nano-banana-pro\".env.GEMINI_API_KEY` in `~/.CoWork-OSS/CoWork-OSS.json`\n\nNotes\n\n- Resolutions: `1K` (default), `2K`, `4K`.\n- Use timestamps in filenames: `yyyy-mm-dd-hh-mm-ss-name.png`.\n- The script prints a `MEDIA:` line for CoWork-OSS to auto-attach on supported chat providers.\n- Do not read the image back; report the saved path only.",
7
+ "prompt": "# Nano Banana Pro (Image Generation)\n\nUse the built-in image generation tool.\n\nGenerate (preferred)\n\n- Call the `generate_image` tool with:\n - `model`: `nano-banana-pro`\n - `prompt`: your image description\n - `imageSize`: `1K` or `2K`\n - `filename`: optional (saved into the workspace)\n\nAPI key\n\n- Requires Gemini API key configured in Settings.\n- If the key is missing, tell the user to set it up and do not attempt fallbacks.\n",
8
8
  "parameters": [],
9
9
  "enabled": true
10
- }
10
+ }
@@ -2,9 +2,9 @@
2
2
  "id": "openai-image-gen",
3
3
  "name": "Openai-image-gen",
4
4
  "description": "Batch-generate images via OpenAI Images API. Random prompt sampler + `index.html` gallery.",
5
- "icon": "🖼️",
5
+ "icon": "\ud83d\uddbc\ufe0f",
6
6
  "category": "Tools",
7
- "prompt": "# OpenAI Image Gen\n\nGenerate a handful of “random but structured prompts and render them via the OpenAI Images API.\n\n## Run\n\n```bash\npython3 {baseDir}/scripts/gen.py\nopen ~/Projects/tmp/openai-image-gen-*/index.html # if ~/Projects/tmp exists; else ./tmp/...\n```\n\nUseful flags:\n\n```bash\n# GPT image models with various options\npython3 {baseDir}/scripts/gen.py --count 16 --model gpt-image-1\npython3 {baseDir}/scripts/gen.py --prompt \"ultra-detailed studio photo of a lobster astronaut\" --count 4\npython3 {baseDir}/scripts/gen.py --size 1536x1024 --quality high --out-dir ./out/images\npython3 {baseDir}/scripts/gen.py --model gpt-image-1.5 --background transparent --output-format webp\n\n# DALL-E 3 (note: count is automatically limited to 1)\npython3 {baseDir}/scripts/gen.py --model dall-e-3 --quality hd --size 1792x1024 --style vivid\npython3 {baseDir}/scripts/gen.py --model dall-e-3 --style natural --prompt \"serene mountain landscape\"\n\n# DALL-E 2\npython3 {baseDir}/scripts/gen.py --model dall-e-2 --size 512x512 --count 4\n```\n\n## Model-Specific Parameters\n\nDifferent models support different parameter values. The script automatically selects appropriate defaults based on the model.\n\n### Size\n\n- **GPT image models** (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`): `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto`\n - Default: `1024x1024`\n- **dall-e-3**: `1024x1024`, `1792x1024`, or `1024x1792`\n - Default: `1024x1024`\n- **dall-e-2**: `256x256`, `512x512`, or `1024x1024`\n - Default: `1024x1024`\n\n### Quality\n\n- **GPT image models**: `auto`, `high`, `medium`, or `low`\n - Default: `high`\n- **dall-e-3**: `hd` or `standard`\n - Default: `standard`\n- **dall-e-2**: `standard` only\n - Default: `standard`\n\n### Other Notable Differences\n\n- **dall-e-3** only supports generating 1 image at a time (`n=1`). The script automatically limits count to 1 when using this model.\n- **GPT image models** support additional parameters:\n - `--background`: `transparent`, `opaque`, or `auto` (default)\n - `--output-format`: `png` (default), `jpeg`, or `webp`\n - Note: `stream` and `moderation` are available via API but not yet implemented in this script\n- **dall-e-3** has a `--style` parameter: `vivid` (hyper-real, dramatic) or `natural` (more natural looking)\n\n## Output\n\n- `*.png`, `*.jpeg`, or `*.webp` images (output format depends on model + `--output-format`)\n- `prompts.json` (prompt file mapping)\n- `index.html` (thumbnail gallery)",
7
+ "prompt": "# OpenAI Image Gen\n\nGenerate a handful of \u201crandom but structured\u201d prompts and render them via the OpenAI Images API.\n\n## Run\n\n```bash\npython3 {baseDir}/scripts/gen.py\nopen ~/Projects/tmp/openai-image-gen-*/index.html # if ~/Projects/tmp exists; else ./tmp/...\n```\n\nUseful flags:\n\n```bash\n# GPT image models with various options\npython3 {baseDir}/scripts/gen.py --count 16 --model gpt-image-1\npython3 {baseDir}/scripts/gen.py --prompt \"ultra-detailed studio photo of a lobster astronaut\" --count 4\npython3 {baseDir}/scripts/gen.py --size 1536x1024 --quality high --out-dir ./out/images\npython3 {baseDir}/scripts/gen.py --model gpt-image-1.5 --background transparent --output-format webp\n\n# DALL-E 3 (note: count is automatically limited to 1)\npython3 {baseDir}/scripts/gen.py --model dall-e-3 --quality hd --size 1792x1024 --style vivid\npython3 {baseDir}/scripts/gen.py --model dall-e-3 --style natural --prompt \"serene mountain landscape\"\n\n# DALL-E 2\npython3 {baseDir}/scripts/gen.py --model dall-e-2 --size 512x512 --count 4\n```\n\n## Model-Specific Parameters\n\nDifferent models support different parameter values. The script automatically selects appropriate defaults based on the model.\n\n### Size\n\n- **GPT image models** (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`): `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto`\n - Default: `1024x1024`\n- **dall-e-3**: `1024x1024`, `1792x1024`, or `1024x1792`\n - Default: `1024x1024`\n- **dall-e-2**: `256x256`, `512x512`, or `1024x1024`\n - Default: `1024x1024`\n\n### Quality\n\n- **GPT image models**: `auto`, `high`, `medium`, or `low`\n - Default: `high`\n- **dall-e-3**: `hd` or `standard`\n - Default: `standard`\n- **dall-e-2**: `standard` only\n - Default: `standard`\n\n### Other Notable Differences\n\n- **dall-e-3** only supports generating 1 image at a time (`n=1`). The script automatically limits count to 1 when using this model.\n- **GPT image models** support additional parameters:\n - `--background`: `transparent`, `opaque`, or `auto` (default)\n - `--output-format`: `png` (default), `jpeg`, or `webp`\n - Note: `stream` and `moderation` are available via API but not yet implemented in this script\n- **dall-e-3** has a `--style` parameter: `vivid` (hyper-real, dramatic) or `natural` (more natural looking)\n\n## Output\n\n- `*.png`, `*.jpeg`, or `*.webp` images (output format depends on model + `--output-format`)\n- `prompts.json` (prompt \u2192 file mapping)\n- `index.html` (thumbnail gallery)\n\n## API key\n\n- `OPENAI_API_KEY` env var\n- Or set `skills.\\\"openai-image-gen\\\".apiKey` / `skills.\\\"openai-image-gen\\\".env.OPENAI_API_KEY` in `~/.CoWork-OSS/CoWork-OSS.json`\n",
8
8
  "parameters": [],
9
9
  "enabled": true
10
- }
10
+ }
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env python3
2
+ """Minimal OpenAI image generation script (stdlib only)."""
3
+
4
+ import argparse
5
+ import base64
6
+ import datetime
7
+ import json
8
+ import os
9
+ import random
10
+ import sys
11
+ import urllib.error
12
+ import urllib.request
13
+ from pathlib import Path
14
+
15
+ OPENAI_URL = "https://api.openai.com/v1/images/generations"
16
+
17
+ DEFAULT_PROMPTS = [
18
+ "ultra-detailed studio photo of a lobster astronaut",
19
+ "cinematic wide shot of a glasshouse cafe in a tropical rainforest, morning mist",
20
+ "macro photograph of dewdrops on a spiderweb at sunrise, shallow depth of field",
21
+ "isometric cutaway of a cozy cabin library, warm lighting, rainy window",
22
+ "surreal desert landscape with floating rocks, golden hour light",
23
+ ]
24
+
25
+
26
+ def _require_api_key() -> str:
27
+ api_key = os.environ.get("OPENAI_API_KEY")
28
+ if not api_key:
29
+ print("ERROR: OPENAI_API_KEY is not set", file=sys.stderr)
30
+ sys.exit(2)
31
+ return api_key
32
+
33
+
34
+ def _post_json(payload: dict) -> dict:
35
+ api_key = _require_api_key()
36
+ data = json.dumps(payload).encode("utf-8")
37
+ req = urllib.request.Request(
38
+ OPENAI_URL,
39
+ data=data,
40
+ headers={
41
+ "Authorization": f"Bearer {api_key}",
42
+ "Content-Type": "application/json",
43
+ },
44
+ method="POST",
45
+ )
46
+ try:
47
+ with urllib.request.urlopen(req) as resp:
48
+ return json.load(resp)
49
+ except urllib.error.HTTPError as err:
50
+ body = err.read().decode("utf-8", "ignore")
51
+ print(f"OpenAI API error: {err.code} {err.reason}\n{body}", file=sys.stderr)
52
+ sys.exit(3)
53
+
54
+
55
+ def _model_supports_gpt_image(model: str) -> bool:
56
+ return model.startswith("gpt-image")
57
+
58
+
59
+ def build_payload(args: argparse.Namespace, prompt: str) -> dict:
60
+ payload = {
61
+ "model": args.model,
62
+ "prompt": prompt,
63
+ "n": args.count,
64
+ "size": args.size,
65
+ "response_format": "b64_json",
66
+ }
67
+
68
+ if args.quality:
69
+ payload["quality"] = args.quality
70
+ if args.style and args.model.startswith("dall-e-3"):
71
+ payload["style"] = args.style
72
+ if _model_supports_gpt_image(args.model):
73
+ if args.background:
74
+ payload["background"] = args.background
75
+ if args.output_format:
76
+ payload["output_format"] = args.output_format
77
+
78
+ return payload
79
+
80
+
81
+ def _resolve_output_format(args: argparse.Namespace) -> str:
82
+ if args.output_format:
83
+ return args.output_format
84
+ return "png"
85
+
86
+
87
+ def _write_index(out_dir: Path, files: list[str]) -> None:
88
+ index_path = out_dir / "index.html"
89
+ rows = "\n".join([f'<div><img src="{Path(f).name}" alt="image" /></div>' for f in files])
90
+ html = f"""<!doctype html>
91
+ <html>
92
+ <head>
93
+ <meta charset=\"utf-8\" />
94
+ <title>Image Gallery</title>
95
+ <style>body{{font-family:Arial,sans-serif}} img{{max-width:100%;height:auto;margin:8px 0}}</style>
96
+ </head>
97
+ <body>
98
+ {rows}
99
+ </body>
100
+ </html>
101
+ """
102
+ index_path.write_text(html)
103
+
104
+
105
+ def main() -> None:
106
+ parser = argparse.ArgumentParser(description="OpenAI image generation script")
107
+ parser.add_argument("--prompt", help="Image prompt text")
108
+ parser.add_argument("--count", type=int, default=1)
109
+ parser.add_argument("--model", default="gpt-image-1")
110
+ parser.add_argument("--size", default="1024x1024")
111
+ parser.add_argument("--quality", default=None)
112
+ parser.add_argument("--out-dir", default="./out/images")
113
+ parser.add_argument("--output-format", default=None)
114
+ parser.add_argument("--background", default=None)
115
+ parser.add_argument("--style", default=None)
116
+ args = parser.parse_args()
117
+
118
+ if args.count < 1:
119
+ print("ERROR: --count must be >= 1", file=sys.stderr)
120
+ sys.exit(2)
121
+
122
+ if args.model.startswith("dall-e-3") and args.count != 1:
123
+ print("ERROR: dall-e-3 only supports --count 1", file=sys.stderr)
124
+ sys.exit(2)
125
+
126
+ prompt = args.prompt
127
+ if not prompt:
128
+ prompt = random.choice(DEFAULT_PROMPTS)
129
+
130
+ payload = build_payload(args, prompt)
131
+ result = _post_json(payload)
132
+ data = result.get("data", [])
133
+ if not data:
134
+ print("ERROR: No image data returned", file=sys.stderr)
135
+ sys.exit(4)
136
+
137
+ out_dir = Path(args.out_dir).expanduser()
138
+ out_dir.mkdir(parents=True, exist_ok=True)
139
+
140
+ ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
141
+ output_format = _resolve_output_format(args)
142
+
143
+ files: list[str] = []
144
+ for idx, item in enumerate(data, start=1):
145
+ b64 = item.get("b64_json")
146
+ if not b64:
147
+ continue
148
+ filename = out_dir / f"image_{ts}_{idx}.{output_format}"
149
+ with open(filename, "wb") as f:
150
+ f.write(base64.b64decode(b64))
151
+ files.append(str(filename))
152
+ print(f"MEDIA: {filename}")
153
+
154
+ # Write prompts.json and index.html for quick browsing
155
+ prompts_path = out_dir / "prompts.json"
156
+ prompts_path.write_text(json.dumps({"prompt": prompt, "files": files}, indent=2))
157
+ _write_index(out_dir, files)
158
+
159
+ print(f"Saved {len(files)} image(s) to {out_dir}")
160
+
161
+
162
+ if __name__ == "__main__":
163
+ main()