groove-dev 0.27.143 → 0.27.145

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 (251) hide show
  1. package/CLAUDE.md +0 -7
  2. package/node_modules/@groove-dev/cli/package.json +1 -1
  3. package/node_modules/@groove-dev/daemon/package.json +1 -1
  4. package/node_modules/@groove-dev/daemon/src/api.js +1086 -6532
  5. package/node_modules/@groove-dev/daemon/src/conversations.js +18 -48
  6. package/node_modules/@groove-dev/daemon/src/gateways/manager.js +35 -1
  7. package/node_modules/@groove-dev/daemon/src/index.js +3 -0
  8. package/node_modules/@groove-dev/daemon/src/journalist.js +23 -13
  9. package/node_modules/@groove-dev/daemon/src/mlx-server.js +365 -0
  10. package/node_modules/@groove-dev/daemon/src/model-lab.js +308 -12
  11. package/node_modules/@groove-dev/daemon/src/pm.js +1 -1
  12. package/node_modules/@groove-dev/daemon/src/process.js +2 -2
  13. package/node_modules/@groove-dev/daemon/src/providers/local.js +36 -8
  14. package/node_modules/@groove-dev/daemon/src/registry.js +21 -5
  15. package/node_modules/@groove-dev/daemon/src/routes/agents.js +812 -0
  16. package/node_modules/@groove-dev/daemon/src/routes/coordination.js +318 -0
  17. package/node_modules/@groove-dev/daemon/src/routes/files.js +751 -0
  18. package/node_modules/@groove-dev/daemon/src/routes/integrations.js +485 -0
  19. package/node_modules/@groove-dev/daemon/src/routes/network.js +1784 -0
  20. package/node_modules/@groove-dev/daemon/src/routes/providers.js +755 -0
  21. package/node_modules/@groove-dev/daemon/src/routes/schedules.js +110 -0
  22. package/node_modules/@groove-dev/daemon/src/routes/teams.js +650 -0
  23. package/node_modules/@groove-dev/daemon/src/scheduler.js +456 -24
  24. package/node_modules/@groove-dev/daemon/src/teams.js +1 -1
  25. package/node_modules/@groove-dev/daemon/src/validate.js +38 -1
  26. package/node_modules/@groove-dev/daemon/templates/mlx-setup.json +12 -0
  27. package/node_modules/@groove-dev/daemon/templates/tgi-setup.json +1 -1
  28. package/node_modules/@groove-dev/daemon/templates/vllm-setup.json +1 -1
  29. package/node_modules/@groove-dev/daemon/test/introducer.test.js +3 -3
  30. package/node_modules/@groove-dev/daemon/test/journalist.test.js +7 -10
  31. package/node_modules/@groove-dev/daemon/test/registry.test.js +38 -0
  32. package/node_modules/@groove-dev/gui/dist/assets/index-Bxc0gU06.js +1006 -0
  33. package/node_modules/@groove-dev/gui/dist/assets/index-C0pztKBn.css +1 -0
  34. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  35. package/node_modules/@groove-dev/gui/package.json +1 -1
  36. package/node_modules/@groove-dev/gui/src/{app.jsx → App.jsx} +0 -2
  37. package/node_modules/@groove-dev/gui/src/app.css +35 -0
  38. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +1 -128
  39. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +210 -112
  40. package/node_modules/@groove-dev/gui/src/components/agents/agent-node.jsx +8 -13
  41. package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +2 -70
  42. package/node_modules/@groove-dev/gui/src/components/agents/code-review.jsx +159 -122
  43. package/node_modules/@groove-dev/gui/src/components/agents/diff-viewer.jsx +23 -23
  44. package/node_modules/@groove-dev/gui/src/components/agents/journalist-panel.jsx +1 -1
  45. package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +2 -135
  46. package/node_modules/@groove-dev/gui/src/components/automations/automation-card.jsx +274 -0
  47. package/node_modules/@groove-dev/gui/src/components/automations/automation-wizard.jsx +1136 -0
  48. package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +2 -0
  49. package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +68 -66
  50. package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +4 -8
  51. package/node_modules/@groove-dev/gui/src/components/dashboard/activity-feed.jsx +3 -3
  52. package/node_modules/@groove-dev/gui/src/components/dashboard/cache-ring.jsx +5 -5
  53. package/node_modules/@groove-dev/gui/src/components/dashboard/context-gauges.jsx +6 -8
  54. package/node_modules/@groove-dev/gui/src/components/dashboard/fleet-panel.jsx +8 -14
  55. package/node_modules/@groove-dev/gui/src/components/dashboard/intel-panel.jsx +238 -656
  56. package/node_modules/@groove-dev/gui/src/components/dashboard/kpi-card.jsx +3 -3
  57. package/node_modules/@groove-dev/gui/src/components/dashboard/routing-chart.jsx +3 -3
  58. package/node_modules/@groove-dev/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
  59. package/node_modules/@groove-dev/gui/src/components/dashboard/token-chart.jsx +4 -4
  60. package/node_modules/@groove-dev/gui/src/components/lab/chat-playground.jsx +39 -31
  61. package/node_modules/@groove-dev/gui/src/components/lab/lab-assistant.jsx +316 -82
  62. package/node_modules/@groove-dev/gui/src/components/lab/metrics-panel.jsx +187 -32
  63. package/node_modules/@groove-dev/gui/src/components/lab/parameter-panel.jsx +200 -18
  64. package/node_modules/@groove-dev/gui/src/components/lab/preset-manager.jsx +17 -14
  65. package/node_modules/@groove-dev/gui/src/components/lab/runtime-config.jsx +335 -152
  66. package/node_modules/@groove-dev/gui/src/components/lab/system-prompt-editor.jsx +10 -8
  67. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -4
  68. package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +4 -2
  69. package/node_modules/@groove-dev/gui/src/components/layout/welcome-splash.jsx +137 -108
  70. package/node_modules/@groove-dev/gui/src/components/network/network-health.jsx +2 -2
  71. package/node_modules/@groove-dev/gui/src/components/network/performance-dashboard.jsx +4 -4
  72. package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +81 -99
  73. package/node_modules/@groove-dev/gui/src/components/ui/sheet.jsx +5 -2
  74. package/node_modules/@groove-dev/gui/src/components/ui/slider.jsx +8 -8
  75. package/node_modules/@groove-dev/gui/src/lib/cron.js +64 -0
  76. package/node_modules/@groove-dev/gui/src/lib/status.js +25 -24
  77. package/node_modules/@groove-dev/gui/src/lib/theme-hex.js +1 -0
  78. package/node_modules/@groove-dev/gui/src/stores/groove.js +51 -3144
  79. package/node_modules/@groove-dev/gui/src/stores/helpers.js +10 -0
  80. package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +459 -0
  81. package/node_modules/@groove-dev/gui/src/stores/slices/automations-slice.js +96 -0
  82. package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +226 -0
  83. package/node_modules/@groove-dev/gui/src/stores/slices/editor-slice.js +285 -0
  84. package/node_modules/@groove-dev/gui/src/stores/slices/marketplace-slice.js +461 -0
  85. package/node_modules/@groove-dev/gui/src/stores/slices/network-slice.js +361 -0
  86. package/node_modules/@groove-dev/gui/src/stores/slices/preview-slice.js +109 -0
  87. package/node_modules/@groove-dev/gui/src/stores/slices/providers-slice.js +897 -0
  88. package/node_modules/@groove-dev/gui/src/stores/slices/teams-slice.js +413 -0
  89. package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +98 -0
  90. package/node_modules/@groove-dev/gui/src/views/agents.jsx +5 -5
  91. package/node_modules/@groove-dev/gui/src/views/dashboard.jsx +12 -13
  92. package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +191 -3
  93. package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +54 -12
  94. package/node_modules/@groove-dev/gui/src/views/models.jsx +419 -496
  95. package/node_modules/@groove-dev/gui/src/views/network.jsx +3 -3
  96. package/node_modules/@groove-dev/gui/src/views/settings.jsx +81 -94
  97. package/node_modules/@groove-dev/gui/src/views/teams.jsx +40 -483
  98. package/node_modules/axios/CHANGELOG.md +260 -0
  99. package/node_modules/axios/README.md +595 -223
  100. package/node_modules/axios/dist/axios.js +1460 -1090
  101. package/node_modules/axios/dist/axios.js.map +1 -1
  102. package/node_modules/axios/dist/axios.min.js +3 -3
  103. package/node_modules/axios/dist/axios.min.js.map +1 -1
  104. package/node_modules/axios/dist/browser/axios.cjs +1560 -1132
  105. package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
  106. package/node_modules/axios/dist/esm/axios.js +1557 -1128
  107. package/node_modules/axios/dist/esm/axios.js.map +1 -1
  108. package/node_modules/axios/dist/esm/axios.min.js +2 -2
  109. package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
  110. package/node_modules/axios/dist/node/axios.cjs +1594 -1057
  111. package/node_modules/axios/dist/node/axios.cjs.map +1 -1
  112. package/node_modules/axios/index.d.cts +40 -41
  113. package/node_modules/axios/index.d.ts +151 -227
  114. package/node_modules/axios/index.js +2 -0
  115. package/node_modules/axios/lib/adapters/adapters.js +4 -2
  116. package/node_modules/axios/lib/adapters/fetch.js +147 -16
  117. package/node_modules/axios/lib/adapters/http.js +306 -58
  118. package/node_modules/axios/lib/adapters/xhr.js +6 -2
  119. package/node_modules/axios/lib/core/Axios.js +7 -3
  120. package/node_modules/axios/lib/core/AxiosError.js +120 -34
  121. package/node_modules/axios/lib/core/AxiosHeaders.js +27 -25
  122. package/node_modules/axios/lib/core/buildFullPath.js +1 -1
  123. package/node_modules/axios/lib/core/dispatchRequest.js +19 -7
  124. package/node_modules/axios/lib/core/mergeConfig.js +21 -4
  125. package/node_modules/axios/lib/core/settle.js +7 -11
  126. package/node_modules/axios/lib/defaults/index.js +14 -9
  127. package/node_modules/axios/lib/env/data.js +1 -1
  128. package/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +1 -2
  129. package/node_modules/axios/lib/helpers/buildURL.js +1 -1
  130. package/node_modules/axios/lib/helpers/cookies.js +14 -2
  131. package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +28 -1
  132. package/node_modules/axios/lib/helpers/formDataToJSON.js +3 -1
  133. package/node_modules/axios/lib/helpers/formDataToStream.js +3 -2
  134. package/node_modules/axios/lib/helpers/parseProtocol.js +1 -1
  135. package/node_modules/axios/lib/helpers/progressEventReducer.js +5 -5
  136. package/node_modules/axios/lib/helpers/resolveConfig.js +54 -18
  137. package/node_modules/axios/lib/helpers/shouldBypassProxy.js +74 -2
  138. package/node_modules/axios/lib/helpers/toFormData.js +10 -2
  139. package/node_modules/axios/lib/helpers/validator.js +3 -1
  140. package/node_modules/axios/lib/utils.js +33 -21
  141. package/node_modules/axios/package.json +17 -24
  142. package/node_modules/follow-redirects/README.md +7 -5
  143. package/node_modules/follow-redirects/index.js +24 -1
  144. package/node_modules/follow-redirects/package.json +1 -1
  145. package/package.json +1 -1
  146. package/packages/cli/package.json +1 -1
  147. package/packages/daemon/package.json +1 -1
  148. package/packages/daemon/src/api.js +1086 -6532
  149. package/packages/daemon/src/conversations.js +18 -48
  150. package/packages/daemon/src/gateways/manager.js +35 -1
  151. package/packages/daemon/src/index.js +3 -0
  152. package/packages/daemon/src/journalist.js +23 -13
  153. package/packages/daemon/src/mlx-server.js +365 -0
  154. package/packages/daemon/src/model-lab.js +308 -12
  155. package/packages/daemon/src/pm.js +1 -1
  156. package/packages/daemon/src/process.js +2 -2
  157. package/packages/daemon/src/providers/local.js +36 -8
  158. package/packages/daemon/src/registry.js +21 -5
  159. package/packages/daemon/src/routes/agents.js +812 -0
  160. package/packages/daemon/src/routes/coordination.js +318 -0
  161. package/packages/daemon/src/routes/files.js +751 -0
  162. package/packages/daemon/src/routes/integrations.js +485 -0
  163. package/packages/daemon/src/routes/network.js +1784 -0
  164. package/packages/daemon/src/routes/providers.js +755 -0
  165. package/packages/daemon/src/routes/schedules.js +110 -0
  166. package/packages/daemon/src/routes/teams.js +650 -0
  167. package/packages/daemon/src/scheduler.js +456 -24
  168. package/packages/daemon/src/teams.js +1 -1
  169. package/packages/daemon/src/validate.js +38 -1
  170. package/packages/daemon/templates/mlx-setup.json +12 -0
  171. package/packages/daemon/templates/tgi-setup.json +1 -1
  172. package/packages/daemon/templates/vllm-setup.json +1 -1
  173. package/packages/gui/dist/assets/index-Bxc0gU06.js +1006 -0
  174. package/packages/gui/dist/assets/index-C0pztKBn.css +1 -0
  175. package/packages/gui/dist/index.html +2 -2
  176. package/packages/gui/package.json +1 -1
  177. package/packages/gui/src/{app.jsx → App.jsx} +0 -2
  178. package/packages/gui/src/app.css +35 -0
  179. package/packages/gui/src/components/agents/agent-config.jsx +1 -128
  180. package/packages/gui/src/components/agents/agent-feed.jsx +210 -112
  181. package/packages/gui/src/components/agents/agent-node.jsx +8 -13
  182. package/packages/gui/src/components/agents/agent-panel.jsx +2 -70
  183. package/packages/gui/src/components/agents/code-review.jsx +159 -122
  184. package/packages/gui/src/components/agents/diff-viewer.jsx +23 -23
  185. package/packages/gui/src/components/agents/journalist-panel.jsx +1 -1
  186. package/packages/gui/src/components/agents/spawn-wizard.jsx +2 -135
  187. package/packages/gui/src/components/automations/automation-card.jsx +274 -0
  188. package/packages/gui/src/components/automations/automation-wizard.jsx +1136 -0
  189. package/packages/gui/src/components/chat/chat-header.jsx +2 -0
  190. package/packages/gui/src/components/chat/chat-input.jsx +68 -66
  191. package/packages/gui/src/components/chat/chat-view.jsx +4 -8
  192. package/packages/gui/src/components/dashboard/activity-feed.jsx +3 -3
  193. package/packages/gui/src/components/dashboard/cache-ring.jsx +5 -5
  194. package/packages/gui/src/components/dashboard/context-gauges.jsx +6 -8
  195. package/packages/gui/src/components/dashboard/fleet-panel.jsx +8 -14
  196. package/packages/gui/src/components/dashboard/intel-panel.jsx +238 -656
  197. package/packages/gui/src/components/dashboard/kpi-card.jsx +3 -3
  198. package/packages/gui/src/components/dashboard/routing-chart.jsx +3 -3
  199. package/packages/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
  200. package/packages/gui/src/components/dashboard/token-chart.jsx +4 -4
  201. package/packages/gui/src/components/lab/chat-playground.jsx +39 -31
  202. package/packages/gui/src/components/lab/lab-assistant.jsx +316 -82
  203. package/packages/gui/src/components/lab/metrics-panel.jsx +187 -32
  204. package/packages/gui/src/components/lab/parameter-panel.jsx +200 -18
  205. package/packages/gui/src/components/lab/preset-manager.jsx +17 -14
  206. package/packages/gui/src/components/lab/runtime-config.jsx +335 -152
  207. package/packages/gui/src/components/lab/system-prompt-editor.jsx +10 -8
  208. package/packages/gui/src/components/layout/activity-bar.jsx +2 -4
  209. package/packages/gui/src/components/layout/terminal-panel.jsx +4 -2
  210. package/packages/gui/src/components/layout/welcome-splash.jsx +137 -108
  211. package/packages/gui/src/components/network/network-health.jsx +2 -2
  212. package/packages/gui/src/components/network/performance-dashboard.jsx +4 -4
  213. package/packages/gui/src/components/settings/ssh-wizard.jsx +81 -99
  214. package/packages/gui/src/components/ui/sheet.jsx +5 -2
  215. package/packages/gui/src/components/ui/slider.jsx +8 -8
  216. package/packages/gui/src/lib/cron.js +64 -0
  217. package/packages/gui/src/lib/status.js +25 -24
  218. package/packages/gui/src/lib/theme-hex.js +1 -0
  219. package/packages/gui/src/stores/groove.js +51 -3144
  220. package/packages/gui/src/stores/helpers.js +10 -0
  221. package/packages/gui/src/stores/slices/agents-slice.js +459 -0
  222. package/packages/gui/src/stores/slices/automations-slice.js +96 -0
  223. package/packages/gui/src/stores/slices/chat-slice.js +226 -0
  224. package/packages/gui/src/stores/slices/editor-slice.js +285 -0
  225. package/packages/gui/src/stores/slices/marketplace-slice.js +461 -0
  226. package/packages/gui/src/stores/slices/network-slice.js +361 -0
  227. package/packages/gui/src/stores/slices/preview-slice.js +109 -0
  228. package/packages/gui/src/stores/slices/providers-slice.js +897 -0
  229. package/packages/gui/src/stores/slices/teams-slice.js +413 -0
  230. package/packages/gui/src/stores/slices/ui-slice.js +98 -0
  231. package/packages/gui/src/views/agents.jsx +5 -5
  232. package/packages/gui/src/views/dashboard.jsx +12 -13
  233. package/packages/gui/src/views/marketplace.jsx +191 -3
  234. package/packages/gui/src/views/model-lab.jsx +54 -12
  235. package/packages/gui/src/views/models.jsx +419 -496
  236. package/packages/gui/src/views/network.jsx +3 -3
  237. package/packages/gui/src/views/settings.jsx +81 -94
  238. package/packages/gui/src/views/teams.jsx +40 -483
  239. package/SECURITY_SWEEP.md +0 -228
  240. package/TRAINING_DATA_v4.md +0 -6
  241. package/node_modules/@groove-dev/gui/dist/assets/index-CCVvAoQn.css +0 -1
  242. package/node_modules/@groove-dev/gui/dist/assets/index-DGIv_TRm.js +0 -984
  243. package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +0 -379
  244. package/node_modules/@groove-dev/gui/src/views/preview.jsx +0 -6
  245. package/node_modules/@groove-dev/gui/src/views/subscription-panel.jsx +0 -327
  246. package/packages/gui/dist/assets/index-CCVvAoQn.css +0 -1
  247. package/packages/gui/dist/assets/index-DGIv_TRm.js +0 -984
  248. package/packages/gui/src/components/agents/agent-chat.jsx +0 -379
  249. package/packages/gui/src/views/preview.jsx +0 -6
  250. package/packages/gui/src/views/subscription-panel.jsx +0 -327
  251. package/test.py +0 -571
@@ -19,10 +19,12 @@ import { IntegrationWizard, GoogleWorkspaceWizard } from '../components/marketpl
19
19
  import { RepoImport } from '../components/marketplace/repo-import';
20
20
  import { RepoCard } from '../components/marketplace/repo-card';
21
21
  import { RepoNukeDialog } from '../components/marketplace/repo-nuke-dialog';
22
+ import { Dialog, DialogContent } from '../components/ui/dialog';
23
+ import { Input } from '../components/ui/input';
22
24
  import {
23
- ChevronLeft, Plug, LogIn,
25
+ ChevronLeft, Plug, LogIn, Plus,
24
26
  Upload, Package, Download, ShoppingBag, RefreshCw, Trash2,
25
- GitBranch,
27
+ GitBranch, Users, Loader2,
26
28
  } from 'lucide-react';
27
29
 
28
30
  // ── Skill Detail ─────────────────────────────────────────
@@ -211,7 +213,178 @@ function SkillDetail({ skill, onBack }) {
211
213
  );
212
214
  }
213
215
 
214
- // ── Skills Browse ────────────────────────────────────────
216
+ // ── New Integration Wizard ───────────────────────────────
217
+ function NewIntegrationWizard({ open, onClose }) {
218
+ const [teamMode, setTeamMode] = useState('new');
219
+ const [teamName, setTeamName] = useState('');
220
+ const [selectedTeamId, setSelectedTeamId] = useState('');
221
+ const [name, setName] = useState('');
222
+ const [docsUrl, setDocsUrl] = useState('');
223
+ const [apiKey, setApiKey] = useState('');
224
+ const [spawning, setSpawning] = useState(false);
225
+
226
+ const teams = useGrooveStore((s) => s.teams);
227
+ const activeTeamId = useGrooveStore((s) => s.activeTeamId);
228
+ const createTeam = useGrooveStore((s) => s.createTeam);
229
+ const spawnAgent = useGrooveStore((s) => s.spawnAgent);
230
+ const setActiveView = useGrooveStore((s) => s.setActiveView);
231
+ const selectAgent = useGrooveStore((s) => s.selectAgent);
232
+ const toast = useToast();
233
+
234
+ useEffect(() => {
235
+ if (open) {
236
+ setTeamMode('new');
237
+ setTeamName('');
238
+ setSelectedTeamId(activeTeamId || '');
239
+ setName('');
240
+ setDocsUrl('');
241
+ setApiKey('');
242
+ setSpawning(false);
243
+ }
244
+ }, [open, activeTeamId]);
245
+
246
+ async function handleGo() {
247
+ if (!name.trim()) return;
248
+ setSpawning(true);
249
+ try {
250
+ let teamId;
251
+ if (teamMode === 'new') {
252
+ const team = await createTeam(teamName.trim() || name.trim());
253
+ teamId = team.id;
254
+ } else {
255
+ teamId = selectedTeamId;
256
+ }
257
+
258
+ const lines = [
259
+ `The user wants to integrate the **${name.trim()}** API into their project.`,
260
+ '',
261
+ ];
262
+ if (docsUrl.trim()) lines.push(`**API Documentation:** ${docsUrl.trim()}`);
263
+ if (apiKey.trim()) lines.push(`**API Key:** The user has provided an API key. Store it securely using environment variables — never hardcode it.`);
264
+ lines.push(
265
+ '',
266
+ 'Start by:',
267
+ '1. Reviewing the API documentation to understand available endpoints and authentication',
268
+ '2. Asking the user what they want to build with this API',
269
+ '3. Setting up the necessary configuration and authentication',
270
+ '4. Building the integration together',
271
+ '',
272
+ 'Ask the user about their project and how they\'d like to use this API.',
273
+ );
274
+
275
+ const prompt = lines.join('\n');
276
+ const agent = await spawnAgent({ role: 'fullstack', prompt, teamId });
277
+
278
+ if (apiKey.trim()) {
279
+ await api.post(`/agents/${agent.id}/instruct`, {
280
+ message: `Here is the API key for ${name.trim()}: \`${apiKey.trim()}\`\n\nStore this in a .env file as an environment variable. Do not commit it to git.`,
281
+ }).catch(() => {});
282
+ }
283
+
284
+ setActiveView('agents');
285
+ selectAgent(agent.id);
286
+ onClose();
287
+ } catch (err) {
288
+ toast('error', 'Failed to start integration', err.message);
289
+ setSpawning(false);
290
+ }
291
+ }
292
+
293
+ const canGo = name.trim() && (teamMode === 'new' || selectedTeamId);
294
+
295
+ return (
296
+ <Dialog open={open} onOpenChange={(v) => !v && onClose()}>
297
+ <DialogContent title="New Integration" description="Set up a custom API integration">
298
+ <div className="px-5 py-4 flex flex-col gap-4">
299
+ <Input
300
+ label="Integration name"
301
+ placeholder="e.g. NASA APOD, Stripe, Twilio…"
302
+ value={name}
303
+ onChange={(e) => setName(e.target.value)}
304
+ autoFocus
305
+ />
306
+
307
+ <Input
308
+ label="Documentation URL"
309
+ placeholder="https://api.example.com/docs"
310
+ value={docsUrl}
311
+ onChange={(e) => setDocsUrl(e.target.value)}
312
+ />
313
+
314
+ <Input
315
+ label="API key (optional)"
316
+ placeholder="sk-..."
317
+ value={apiKey}
318
+ onChange={(e) => setApiKey(e.target.value)}
319
+ mono
320
+ type="password"
321
+ />
322
+
323
+ {/* Team selection */}
324
+ <div className="flex flex-col gap-2">
325
+ <span className="text-xs font-medium text-text-2 font-sans">Team</span>
326
+ <div className="flex gap-2">
327
+ <button
328
+ onClick={() => setTeamMode('new')}
329
+ className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-2 rounded-md text-xs font-medium font-sans border transition-colors cursor-pointer ${
330
+ teamMode === 'new'
331
+ ? 'border-accent bg-accent/10 text-accent'
332
+ : 'border-border bg-surface-0 text-text-2 hover:border-accent/50'
333
+ }`}
334
+ >
335
+ <Plus size={12} />
336
+ New team
337
+ </button>
338
+ <button
339
+ onClick={() => setTeamMode('existing')}
340
+ className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-2 rounded-md text-xs font-medium font-sans border transition-colors cursor-pointer ${
341
+ teamMode === 'existing'
342
+ ? 'border-accent bg-accent/10 text-accent'
343
+ : 'border-border bg-surface-0 text-text-2 hover:border-accent/50'
344
+ }`}
345
+ >
346
+ <Users size={12} />
347
+ Existing team
348
+ </button>
349
+ </div>
350
+
351
+ {teamMode === 'new' ? (
352
+ <Input
353
+ placeholder={name ? name.trim() : 'Team name (defaults to integration name)'}
354
+ value={teamName}
355
+ onChange={(e) => setTeamName(e.target.value)}
356
+ />
357
+ ) : (
358
+ <select
359
+ value={selectedTeamId}
360
+ onChange={(e) => setSelectedTeamId(e.target.value)}
361
+ className="h-8 w-full rounded-md px-3 text-sm font-sans bg-surface-1 border border-border text-text-0 focus:outline-none focus:ring-1 focus:ring-accent focus:border-accent cursor-pointer"
362
+ >
363
+ <option value="">Select a team…</option>
364
+ {teams.map((t) => (
365
+ <option key={t.id} value={t.id}>{t.name}</option>
366
+ ))}
367
+ </select>
368
+ )}
369
+ </div>
370
+
371
+ <Button
372
+ onClick={handleGo}
373
+ disabled={!canGo || spawning}
374
+ className="w-full mt-1"
375
+ >
376
+ {spawning ? (
377
+ <><Loader2 size={14} className="animate-spin" /> Setting up…</>
378
+ ) : (
379
+ 'Go'
380
+ )}
381
+ </Button>
382
+ </div>
383
+ </DialogContent>
384
+ </Dialog>
385
+ );
386
+ }
387
+
215
388
  // ── Integrations Browse ──────────────────────────────────
216
389
  const GOOGLE_IDS = new Set(['gmail', 'google-calendar', 'google-drive', 'google-docs', 'google-sheets', 'google-slides']);
217
390
 
@@ -222,6 +395,7 @@ function IntegrationsBrowse() {
222
395
  const [selectedIntegration, setSelectedIntegration] = useState(null);
223
396
  const [showWizard, setShowWizard] = useState(false);
224
397
  const [showGoogleWizard, setShowGoogleWizard] = useState(false);
398
+ const [showNewWizard, setShowNewWizard] = useState(false);
225
399
 
226
400
  const fetchItems = () => {
227
401
  setLoading(true);
@@ -261,6 +435,15 @@ function IntegrationsBrowse() {
261
435
  <SearchBar value={search} onChange={setSearch} placeholder="Search integrations..." />
262
436
  </div>
263
437
  <div className="flex-1" />
438
+ <Button
439
+ variant="ghost"
440
+ size="sm"
441
+ onClick={() => setShowNewWizard(true)}
442
+ className="gap-1 text-xs"
443
+ >
444
+ <Plus size={13} />
445
+ New
446
+ </Button>
264
447
  <span className="text-2xs text-text-4 font-mono flex-shrink-0">
265
448
  {otherItems.length + (googleItems.length > 0 ? 1 : 0)}
266
449
  </span>
@@ -312,6 +495,11 @@ function IntegrationsBrowse() {
312
495
  open={showGoogleWizard}
313
496
  onClose={() => { setShowGoogleWizard(false); fetchItems(); }}
314
497
  />
498
+
499
+ <NewIntegrationWizard
500
+ open={showNewWizard}
501
+ onClose={() => setShowNewWizard(false)}
502
+ />
315
503
  </ScrollArea>
316
504
  );
317
505
  }
@@ -4,7 +4,7 @@ import { useGrooveStore } from '../stores/groove';
4
4
  import { ScrollArea } from '../components/ui/scroll-area';
5
5
  import { Tooltip } from '../components/ui/tooltip';
6
6
  import { Combobox } from '../components/ui/combobox';
7
- import { RuntimeConfig, LaunchModel } from '../components/lab/runtime-config';
7
+ import { RuntimeSection } from '../components/lab/runtime-config';
8
8
  import { ParameterPanel } from '../components/lab/parameter-panel';
9
9
  import { SystemPromptEditor } from '../components/lab/system-prompt-editor';
10
10
  import { ChatPlayground } from '../components/lab/chat-playground';
@@ -12,7 +12,7 @@ import { LabAssistant } from '../components/lab/lab-assistant';
12
12
  import { MetricsPanel } from '../components/lab/metrics-panel';
13
13
  import { PresetManager } from '../components/lab/preset-manager';
14
14
  import { cn } from '../lib/cn';
15
- import { FlaskConical, PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen, Box } from 'lucide-react';
15
+ import { FlaskConical, PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen, Box, ChevronRight } from 'lucide-react';
16
16
 
17
17
  const LEFT_DEFAULT = 280;
18
18
  const LEFT_MIN = 220;
@@ -21,17 +21,63 @@ const RIGHT_DEFAULT = 240;
21
21
  const RIGHT_MIN = 200;
22
22
  const RIGHT_MAX = 360;
23
23
 
24
+ export function SidebarSection({ label, action, children, className, collapsible = false, defaultOpen = true }) {
25
+ const [open, setOpen] = useState(defaultOpen);
26
+ const isOpen = collapsible ? open : true;
27
+
28
+ return (
29
+ <div className={cn('space-y-3', className)}>
30
+ {label && (
31
+ <div className="flex items-center justify-between h-6">
32
+ {collapsible ? (
33
+ <button
34
+ onClick={() => setOpen(!open)}
35
+ className="flex items-center gap-1.5 cursor-pointer group"
36
+ >
37
+ <ChevronRight
38
+ size={10}
39
+ className={cn(
40
+ 'text-text-4 transition-transform duration-150 flex-shrink-0',
41
+ isOpen && 'rotate-90',
42
+ )}
43
+ />
44
+ <span className="text-[10px] font-semibold font-sans text-text-3 uppercase tracking-widest group-hover:text-text-2 transition-colors">{label}</span>
45
+ </button>
46
+ ) : (
47
+ <span className="text-[10px] font-semibold font-sans text-text-3 uppercase tracking-widest">{label}</span>
48
+ )}
49
+ {isOpen && action}
50
+ </div>
51
+ )}
52
+ {isOpen && children}
53
+ </div>
54
+ );
55
+ }
56
+
24
57
  function ModelSelector() {
25
58
  const models = useGrooveStore((s) => s.labModels);
59
+ const runtimes = useGrooveStore((s) => s.labRuntimes);
26
60
  const activeRuntime = useGrooveStore((s) => s.labActiveRuntime);
27
61
  const activeModel = useGrooveStore((s) => s.labActiveModel);
28
62
  const setActiveModel = useGrooveStore((s) => s.setLabActiveModel);
29
63
 
30
64
  if (!activeRuntime) return null;
31
65
 
66
+ const rt = runtimes.find((r) => r.id === activeRuntime);
67
+ const online = rt?.status === 'connected';
68
+
69
+ if (!online) {
70
+ return (
71
+ <SidebarSection label="Model">
72
+ <p className="text-2xs text-text-4 font-sans">Start the runtime to select a model</p>
73
+ </SidebarSection>
74
+ );
75
+ }
76
+
77
+ if (models.length <= 1 && activeModel) return null;
78
+
32
79
  return (
33
- <div className="space-y-1.5">
34
- <span className="text-2xs font-semibold font-sans text-text-3 uppercase tracking-wider">Model</span>
80
+ <SidebarSection label="Model">
35
81
  <Combobox
36
82
  value={activeModel || ''}
37
83
  onChange={setActiveModel}
@@ -45,10 +91,7 @@ function ModelSelector() {
45
91
  </div>
46
92
  )}
47
93
  />
48
- {!activeModel && models.length === 0 && (
49
- <p className="text-2xs text-text-4 font-sans px-1">No models discovered — type a model name or test the runtime</p>
50
- )}
51
- </div>
94
+ </SidebarSection>
52
95
  );
53
96
  }
54
97
 
@@ -163,7 +206,7 @@ export default function ModelLabView() {
163
206
  style={leftCollapsed ? undefined : { width: leftWidth }}
164
207
  >
165
208
  <div className="h-full flex flex-col">
166
- <div className="flex-shrink-0 flex items-center justify-between px-4 h-10">
209
+ <div className="flex-shrink-0 flex items-center justify-between px-4 h-10 border-b border-border-subtle">
167
210
  <div className="flex items-center gap-2">
168
211
  <FlaskConical size={13} className="text-accent" />
169
212
  <span className="text-xs font-semibold font-sans text-text-1">Model Lab</span>
@@ -171,9 +214,8 @@ export default function ModelLabView() {
171
214
  <PanelToggle collapsed={false} onClick={() => setLeftCollapsed(true)} side="left" />
172
215
  </div>
173
216
  <ScrollArea className="flex-1 min-h-0">
174
- <div className="px-4 pb-4 space-y-5 divide-y divide-border-subtle [&>*]:pt-5 [&>*:first-child]:pt-0">
175
- <LaunchModel />
176
- <RuntimeConfig />
217
+ <div className="px-4 py-4 space-y-6">
218
+ <RuntimeSection />
177
219
  <ModelSelector />
178
220
  <ParameterPanel />
179
221
  <PresetManager />