groove-dev 0.27.142 → 0.27.144

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 (187) hide show
  1. package/node_modules/@groove-dev/cli/package.json +1 -1
  2. package/node_modules/@groove-dev/daemon/package.json +1 -1
  3. package/node_modules/@groove-dev/daemon/src/api.js +1086 -6532
  4. package/node_modules/@groove-dev/daemon/src/gateways/manager.js +35 -1
  5. package/node_modules/@groove-dev/daemon/src/index.js +3 -0
  6. package/node_modules/@groove-dev/daemon/src/journalist.js +23 -13
  7. package/node_modules/@groove-dev/daemon/src/mlx-server.js +365 -0
  8. package/node_modules/@groove-dev/daemon/src/model-lab.js +308 -12
  9. package/node_modules/@groove-dev/daemon/src/pm.js +1 -1
  10. package/node_modules/@groove-dev/daemon/src/process.js +2 -2
  11. package/node_modules/@groove-dev/daemon/src/providers/local.js +36 -8
  12. package/node_modules/@groove-dev/daemon/src/registry.js +21 -5
  13. package/node_modules/@groove-dev/daemon/src/routes/agents.js +889 -0
  14. package/node_modules/@groove-dev/daemon/src/routes/coordination.js +318 -0
  15. package/node_modules/@groove-dev/daemon/src/routes/files.js +751 -0
  16. package/node_modules/@groove-dev/daemon/src/routes/integrations.js +485 -0
  17. package/node_modules/@groove-dev/daemon/src/routes/network.js +1784 -0
  18. package/node_modules/@groove-dev/daemon/src/routes/providers.js +755 -0
  19. package/node_modules/@groove-dev/daemon/src/routes/schedules.js +110 -0
  20. package/node_modules/@groove-dev/daemon/src/routes/teams.js +650 -0
  21. package/node_modules/@groove-dev/daemon/src/scheduler.js +456 -24
  22. package/node_modules/@groove-dev/daemon/src/teams.js +1 -1
  23. package/node_modules/@groove-dev/daemon/src/validate.js +38 -1
  24. package/node_modules/@groove-dev/daemon/templates/mlx-setup.json +12 -0
  25. package/node_modules/@groove-dev/daemon/templates/tgi-setup.json +1 -1
  26. package/node_modules/@groove-dev/daemon/templates/vllm-setup.json +1 -1
  27. package/node_modules/@groove-dev/daemon/test/introducer.test.js +3 -3
  28. package/node_modules/@groove-dev/daemon/test/journalist.test.js +7 -10
  29. package/node_modules/@groove-dev/daemon/test/registry.test.js +38 -0
  30. package/node_modules/@groove-dev/gui/dist/assets/index-BcoF6_eF.js +1012 -0
  31. package/node_modules/@groove-dev/gui/dist/assets/index-Dd7qhiEd.css +1 -0
  32. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  33. package/node_modules/@groove-dev/gui/package.json +1 -1
  34. package/{packages/gui/src/app.jsx → node_modules/@groove-dev/gui/src/App.jsx} +0 -2
  35. package/node_modules/@groove-dev/gui/src/app.css +35 -0
  36. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +1 -128
  37. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +144 -31
  38. package/node_modules/@groove-dev/gui/src/components/agents/agent-node.jsx +8 -13
  39. package/node_modules/@groove-dev/gui/src/components/agents/code-review.jsx +159 -122
  40. package/node_modules/@groove-dev/gui/src/components/agents/diff-viewer.jsx +23 -23
  41. package/node_modules/@groove-dev/gui/src/components/agents/journalist-panel.jsx +1 -1
  42. package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +2 -135
  43. package/node_modules/@groove-dev/gui/src/components/automations/automation-card.jsx +274 -0
  44. package/node_modules/@groove-dev/gui/src/components/automations/automation-wizard.jsx +1136 -0
  45. package/node_modules/@groove-dev/gui/src/components/dashboard/activity-feed.jsx +3 -3
  46. package/node_modules/@groove-dev/gui/src/components/dashboard/cache-ring.jsx +5 -5
  47. package/node_modules/@groove-dev/gui/src/components/dashboard/context-gauges.jsx +6 -8
  48. package/node_modules/@groove-dev/gui/src/components/dashboard/fleet-panel.jsx +8 -14
  49. package/node_modules/@groove-dev/gui/src/components/dashboard/intel-panel.jsx +238 -656
  50. package/node_modules/@groove-dev/gui/src/components/dashboard/kpi-card.jsx +3 -3
  51. package/node_modules/@groove-dev/gui/src/components/dashboard/routing-chart.jsx +3 -3
  52. package/node_modules/@groove-dev/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
  53. package/node_modules/@groove-dev/gui/src/components/dashboard/token-chart.jsx +4 -4
  54. package/node_modules/@groove-dev/gui/src/components/editor/selection-menu.jsx +2 -0
  55. package/node_modules/@groove-dev/gui/src/components/lab/lab-assistant.jsx +316 -82
  56. package/node_modules/@groove-dev/gui/src/components/lab/metrics-panel.jsx +187 -32
  57. package/node_modules/@groove-dev/gui/src/components/lab/parameter-panel.jsx +195 -14
  58. package/node_modules/@groove-dev/gui/src/components/lab/runtime-config.jsx +286 -102
  59. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -4
  60. package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +4 -2
  61. package/node_modules/@groove-dev/gui/src/components/layout/welcome-splash.jsx +137 -108
  62. package/node_modules/@groove-dev/gui/src/components/network/network-health.jsx +2 -2
  63. package/node_modules/@groove-dev/gui/src/components/network/performance-dashboard.jsx +4 -4
  64. package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +81 -99
  65. package/node_modules/@groove-dev/gui/src/components/ui/sheet.jsx +5 -2
  66. package/node_modules/@groove-dev/gui/src/lib/cron.js +64 -0
  67. package/node_modules/@groove-dev/gui/src/lib/status.js +24 -24
  68. package/node_modules/@groove-dev/gui/src/lib/theme-hex.js +1 -0
  69. package/node_modules/@groove-dev/gui/src/stores/groove.js +34 -3144
  70. package/node_modules/@groove-dev/gui/src/stores/helpers.js +10 -0
  71. package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +452 -0
  72. package/node_modules/@groove-dev/gui/src/stores/slices/automations-slice.js +96 -0
  73. package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +227 -0
  74. package/node_modules/@groove-dev/gui/src/stores/slices/editor-slice.js +285 -0
  75. package/node_modules/@groove-dev/gui/src/stores/slices/marketplace-slice.js +461 -0
  76. package/node_modules/@groove-dev/gui/src/stores/slices/network-slice.js +361 -0
  77. package/node_modules/@groove-dev/gui/src/stores/slices/preview-slice.js +109 -0
  78. package/node_modules/@groove-dev/gui/src/stores/slices/providers-slice.js +897 -0
  79. package/node_modules/@groove-dev/gui/src/stores/slices/teams-slice.js +413 -0
  80. package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +98 -0
  81. package/node_modules/@groove-dev/gui/src/views/agents.jsx +5 -5
  82. package/node_modules/@groove-dev/gui/src/views/dashboard.jsx +12 -13
  83. package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +191 -3
  84. package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +17 -6
  85. package/node_modules/@groove-dev/gui/src/views/models.jsx +410 -509
  86. package/node_modules/@groove-dev/gui/src/views/network.jsx +3 -3
  87. package/node_modules/@groove-dev/gui/src/views/settings.jsx +81 -94
  88. package/node_modules/@groove-dev/gui/src/views/teams.jsx +40 -483
  89. package/package.json +1 -1
  90. package/packages/cli/package.json +1 -1
  91. package/packages/daemon/package.json +1 -1
  92. package/packages/daemon/src/api.js +1086 -6532
  93. package/packages/daemon/src/gateways/manager.js +35 -1
  94. package/packages/daemon/src/index.js +3 -0
  95. package/packages/daemon/src/journalist.js +23 -13
  96. package/packages/daemon/src/mlx-server.js +365 -0
  97. package/packages/daemon/src/model-lab.js +308 -12
  98. package/packages/daemon/src/pm.js +1 -1
  99. package/packages/daemon/src/process.js +2 -2
  100. package/packages/daemon/src/providers/local.js +36 -8
  101. package/packages/daemon/src/registry.js +21 -5
  102. package/packages/daemon/src/routes/agents.js +889 -0
  103. package/packages/daemon/src/routes/coordination.js +318 -0
  104. package/packages/daemon/src/routes/files.js +751 -0
  105. package/packages/daemon/src/routes/integrations.js +485 -0
  106. package/packages/daemon/src/routes/network.js +1784 -0
  107. package/packages/daemon/src/routes/providers.js +755 -0
  108. package/packages/daemon/src/routes/schedules.js +110 -0
  109. package/packages/daemon/src/routes/teams.js +650 -0
  110. package/packages/daemon/src/scheduler.js +456 -24
  111. package/packages/daemon/src/teams.js +1 -1
  112. package/packages/daemon/src/validate.js +38 -1
  113. package/packages/daemon/templates/mlx-setup.json +12 -0
  114. package/packages/daemon/templates/tgi-setup.json +1 -1
  115. package/packages/daemon/templates/vllm-setup.json +1 -1
  116. package/packages/gui/dist/assets/index-BcoF6_eF.js +1012 -0
  117. package/packages/gui/dist/assets/index-Dd7qhiEd.css +1 -0
  118. package/packages/gui/dist/index.html +2 -2
  119. package/packages/gui/package.json +1 -1
  120. package/{node_modules/@groove-dev/gui/src/app.jsx → packages/gui/src/App.jsx} +0 -2
  121. package/packages/gui/src/app.css +35 -0
  122. package/packages/gui/src/components/agents/agent-config.jsx +1 -128
  123. package/packages/gui/src/components/agents/agent-feed.jsx +144 -31
  124. package/packages/gui/src/components/agents/agent-node.jsx +8 -13
  125. package/packages/gui/src/components/agents/code-review.jsx +159 -122
  126. package/packages/gui/src/components/agents/diff-viewer.jsx +23 -23
  127. package/packages/gui/src/components/agents/journalist-panel.jsx +1 -1
  128. package/packages/gui/src/components/agents/spawn-wizard.jsx +2 -135
  129. package/packages/gui/src/components/automations/automation-card.jsx +274 -0
  130. package/packages/gui/src/components/automations/automation-wizard.jsx +1136 -0
  131. package/packages/gui/src/components/dashboard/activity-feed.jsx +3 -3
  132. package/packages/gui/src/components/dashboard/cache-ring.jsx +5 -5
  133. package/packages/gui/src/components/dashboard/context-gauges.jsx +6 -8
  134. package/packages/gui/src/components/dashboard/fleet-panel.jsx +8 -14
  135. package/packages/gui/src/components/dashboard/intel-panel.jsx +238 -656
  136. package/packages/gui/src/components/dashboard/kpi-card.jsx +3 -3
  137. package/packages/gui/src/components/dashboard/routing-chart.jsx +3 -3
  138. package/packages/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
  139. package/packages/gui/src/components/dashboard/token-chart.jsx +4 -4
  140. package/packages/gui/src/components/editor/selection-menu.jsx +2 -0
  141. package/packages/gui/src/components/lab/lab-assistant.jsx +316 -82
  142. package/packages/gui/src/components/lab/metrics-panel.jsx +187 -32
  143. package/packages/gui/src/components/lab/parameter-panel.jsx +195 -14
  144. package/packages/gui/src/components/lab/runtime-config.jsx +286 -102
  145. package/packages/gui/src/components/layout/activity-bar.jsx +2 -4
  146. package/packages/gui/src/components/layout/terminal-panel.jsx +4 -2
  147. package/packages/gui/src/components/layout/welcome-splash.jsx +137 -108
  148. package/packages/gui/src/components/network/network-health.jsx +2 -2
  149. package/packages/gui/src/components/network/performance-dashboard.jsx +4 -4
  150. package/packages/gui/src/components/settings/ssh-wizard.jsx +81 -99
  151. package/packages/gui/src/components/ui/sheet.jsx +5 -2
  152. package/packages/gui/src/lib/cron.js +64 -0
  153. package/packages/gui/src/lib/status.js +24 -24
  154. package/packages/gui/src/lib/theme-hex.js +1 -0
  155. package/packages/gui/src/stores/groove.js +34 -3144
  156. package/packages/gui/src/stores/helpers.js +10 -0
  157. package/packages/gui/src/stores/slices/agents-slice.js +452 -0
  158. package/packages/gui/src/stores/slices/automations-slice.js +96 -0
  159. package/packages/gui/src/stores/slices/chat-slice.js +227 -0
  160. package/packages/gui/src/stores/slices/editor-slice.js +285 -0
  161. package/packages/gui/src/stores/slices/marketplace-slice.js +461 -0
  162. package/packages/gui/src/stores/slices/network-slice.js +361 -0
  163. package/packages/gui/src/stores/slices/preview-slice.js +109 -0
  164. package/packages/gui/src/stores/slices/providers-slice.js +897 -0
  165. package/packages/gui/src/stores/slices/teams-slice.js +413 -0
  166. package/packages/gui/src/stores/slices/ui-slice.js +98 -0
  167. package/packages/gui/src/views/agents.jsx +5 -5
  168. package/packages/gui/src/views/dashboard.jsx +12 -13
  169. package/packages/gui/src/views/marketplace.jsx +191 -3
  170. package/packages/gui/src/views/model-lab.jsx +17 -6
  171. package/packages/gui/src/views/models.jsx +410 -509
  172. package/packages/gui/src/views/network.jsx +3 -3
  173. package/packages/gui/src/views/settings.jsx +81 -94
  174. package/packages/gui/src/views/teams.jsx +40 -483
  175. package/SECURITY_SWEEP.md +0 -228
  176. package/TRAINING_DATA_v4.md +0 -6
  177. package/node_modules/@groove-dev/gui/dist/assets/index-Bjd91ufV.js +0 -984
  178. package/node_modules/@groove-dev/gui/dist/assets/index-BqdwIFn4.css +0 -1
  179. package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +0 -322
  180. package/node_modules/@groove-dev/gui/src/views/preview.jsx +0 -6
  181. package/node_modules/@groove-dev/gui/src/views/subscription-panel.jsx +0 -327
  182. package/packages/gui/dist/assets/index-Bjd91ufV.js +0 -984
  183. package/packages/gui/dist/assets/index-BqdwIFn4.css +0 -1
  184. package/packages/gui/src/components/agents/agent-chat.jsx +0 -322
  185. package/packages/gui/src/views/preview.jsx +0 -6
  186. package/packages/gui/src/views/subscription-panel.jsx +0 -327
  187. 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';
@@ -23,12 +23,27 @@ const RIGHT_MAX = 360;
23
23
 
24
24
  function ModelSelector() {
25
25
  const models = useGrooveStore((s) => s.labModels);
26
+ const runtimes = useGrooveStore((s) => s.labRuntimes);
26
27
  const activeRuntime = useGrooveStore((s) => s.labActiveRuntime);
27
28
  const activeModel = useGrooveStore((s) => s.labActiveModel);
28
29
  const setActiveModel = useGrooveStore((s) => s.setLabActiveModel);
29
30
 
30
31
  if (!activeRuntime) return null;
31
32
 
33
+ const rt = runtimes.find((r) => r.id === activeRuntime);
34
+ const online = rt?.status === 'connected';
35
+
36
+ if (!online) {
37
+ return (
38
+ <div className="space-y-1.5">
39
+ <span className="text-2xs font-semibold font-sans text-text-3 uppercase tracking-wider">Model</span>
40
+ <p className="text-2xs text-text-4 font-sans px-1">Start the runtime to select a model</p>
41
+ </div>
42
+ );
43
+ }
44
+
45
+ if (models.length <= 1 && activeModel) return null;
46
+
32
47
  return (
33
48
  <div className="space-y-1.5">
34
49
  <span className="text-2xs font-semibold font-sans text-text-3 uppercase tracking-wider">Model</span>
@@ -45,9 +60,6 @@ function ModelSelector() {
45
60
  </div>
46
61
  )}
47
62
  />
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
63
  </div>
52
64
  );
53
65
  }
@@ -172,8 +184,7 @@ export default function ModelLabView() {
172
184
  </div>
173
185
  <ScrollArea className="flex-1 min-h-0">
174
186
  <div className="px-4 pb-4 space-y-5 divide-y divide-border-subtle [&>*]:pt-5 [&>*:first-child]:pt-0">
175
- <LaunchModel />
176
- <RuntimeConfig />
187
+ <RuntimeSection />
177
188
  <ModelSelector />
178
189
  <ParameterPanel />
179
190
  <PresetManager />