groove-dev 0.27.140 → 0.27.142

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 (98) hide show
  1. package/node_modules/@groove-dev/cli/package.json +1 -1
  2. package/node_modules/@groove-dev/daemon/integrations-registry.json +12 -44
  3. package/node_modules/@groove-dev/daemon/package.json +1 -1
  4. package/node_modules/@groove-dev/daemon/src/api.js +100 -23
  5. package/node_modules/@groove-dev/daemon/src/integrations.js +10 -0
  6. package/node_modules/@groove-dev/daemon/src/introducer.js +1 -1
  7. package/node_modules/@groove-dev/daemon/src/journalist.js +171 -1
  8. package/node_modules/@groove-dev/daemon/src/keeper.js +2 -2
  9. package/node_modules/@groove-dev/daemon/src/memory.js +8 -5
  10. package/node_modules/@groove-dev/daemon/src/model-lab.js +11 -0
  11. package/node_modules/@groove-dev/daemon/src/process.js +65 -0
  12. package/node_modules/@groove-dev/daemon/src/rotator.js +25 -8
  13. package/node_modules/@groove-dev/daemon/src/validate.js +8 -0
  14. package/node_modules/@groove-dev/gui/dist/assets/{codemirror-BQqYnZfL.js → codemirror-BYKpdS2W.js} +10 -10
  15. package/node_modules/@groove-dev/gui/dist/assets/index-Bjd91ufV.js +984 -0
  16. package/node_modules/@groove-dev/gui/dist/assets/index-BqdwIFn4.css +1 -0
  17. package/node_modules/@groove-dev/gui/dist/index.html +3 -3
  18. package/node_modules/@groove-dev/gui/package.json +1 -1
  19. package/node_modules/@groove-dev/gui/src/app.jsx +0 -2
  20. package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +3 -4
  21. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +8 -2
  22. package/node_modules/@groove-dev/gui/src/components/agents/agent-file-tree.jsx +12 -8
  23. package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +79 -5
  24. package/node_modules/@groove-dev/gui/src/components/agents/code-review.jsx +5 -4
  25. package/node_modules/@groove-dev/gui/src/components/agents/workspace-mode.jsx +109 -12
  26. package/node_modules/@groove-dev/gui/src/components/dashboard/context-gauges.jsx +111 -0
  27. package/node_modules/@groove-dev/gui/src/components/dashboard/routing-chart.jsx +70 -33
  28. package/node_modules/@groove-dev/gui/src/components/editor/ai-panel.jsx +77 -6
  29. package/node_modules/@groove-dev/gui/src/components/editor/code-editor.jsx +2 -68
  30. package/node_modules/@groove-dev/gui/src/components/editor/file-tree.jsx +2 -49
  31. package/node_modules/@groove-dev/gui/src/components/editor/terminal.jsx +15 -4
  32. package/node_modules/@groove-dev/gui/src/components/keeper/global-modals.jsx +10 -10
  33. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +1 -2
  34. package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +151 -3
  35. package/node_modules/@groove-dev/gui/src/components/marketplace/integration-wizard.jsx +223 -18
  36. package/node_modules/@groove-dev/gui/src/stores/groove.js +107 -29
  37. package/node_modules/@groove-dev/gui/src/views/agents.jsx +114 -56
  38. package/node_modules/@groove-dev/gui/src/views/dashboard.jsx +2 -0
  39. package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +3 -71
  40. package/node_modules/@groove-dev/gui/src/views/memory.jsx +9 -9
  41. package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +1 -6
  42. package/node_modules/@groove-dev/gui/src/views/models.jsx +658 -565
  43. package/package.json +1 -1
  44. package/packages/cli/package.json +1 -1
  45. package/packages/daemon/integrations-registry.json +12 -44
  46. package/packages/daemon/package.json +1 -1
  47. package/packages/daemon/src/api.js +100 -23
  48. package/packages/daemon/src/integrations.js +10 -0
  49. package/packages/daemon/src/introducer.js +1 -1
  50. package/packages/daemon/src/journalist.js +171 -1
  51. package/packages/daemon/src/keeper.js +2 -2
  52. package/packages/daemon/src/memory.js +8 -5
  53. package/packages/daemon/src/model-lab.js +11 -0
  54. package/packages/daemon/src/process.js +65 -0
  55. package/packages/daemon/src/rotator.js +25 -8
  56. package/packages/daemon/src/validate.js +8 -0
  57. package/packages/gui/dist/assets/{codemirror-BQqYnZfL.js → codemirror-BYKpdS2W.js} +10 -10
  58. package/packages/gui/dist/assets/index-Bjd91ufV.js +984 -0
  59. package/packages/gui/dist/assets/index-BqdwIFn4.css +1 -0
  60. package/packages/gui/dist/index.html +3 -3
  61. package/packages/gui/package.json +1 -1
  62. package/packages/gui/src/app.jsx +0 -2
  63. package/packages/gui/src/components/agents/agent-chat.jsx +3 -4
  64. package/packages/gui/src/components/agents/agent-feed.jsx +8 -2
  65. package/packages/gui/src/components/agents/agent-file-tree.jsx +12 -8
  66. package/packages/gui/src/components/agents/agent-panel.jsx +79 -5
  67. package/packages/gui/src/components/agents/code-review.jsx +5 -4
  68. package/packages/gui/src/components/agents/workspace-mode.jsx +109 -12
  69. package/packages/gui/src/components/dashboard/context-gauges.jsx +111 -0
  70. package/packages/gui/src/components/dashboard/routing-chart.jsx +70 -33
  71. package/packages/gui/src/components/editor/ai-panel.jsx +77 -6
  72. package/packages/gui/src/components/editor/code-editor.jsx +2 -68
  73. package/packages/gui/src/components/editor/file-tree.jsx +2 -49
  74. package/packages/gui/src/components/editor/terminal.jsx +15 -4
  75. package/packages/gui/src/components/keeper/global-modals.jsx +10 -10
  76. package/packages/gui/src/components/layout/activity-bar.jsx +1 -2
  77. package/packages/gui/src/components/layout/terminal-panel.jsx +151 -3
  78. package/packages/gui/src/components/marketplace/integration-wizard.jsx +223 -18
  79. package/packages/gui/src/stores/groove.js +107 -29
  80. package/packages/gui/src/views/agents.jsx +114 -56
  81. package/packages/gui/src/views/dashboard.jsx +2 -0
  82. package/packages/gui/src/views/marketplace.jsx +3 -71
  83. package/packages/gui/src/views/memory.jsx +9 -9
  84. package/packages/gui/src/views/model-lab.jsx +1 -6
  85. package/packages/gui/src/views/models.jsx +658 -565
  86. package/plan_files/keeper-manual.md +53 -42
  87. package/node_modules/@groove-dev/gui/dist/assets/index-BV9CAiw1.css +0 -1
  88. package/node_modules/@groove-dev/gui/dist/assets/index-DK6UIz0n.js +0 -8698
  89. package/node_modules/@groove-dev/gui/src/components/toys/toy-card.jsx +0 -78
  90. package/node_modules/@groove-dev/gui/src/components/toys/toy-creator.jsx +0 -144
  91. package/node_modules/@groove-dev/gui/src/components/toys/toy-launcher.jsx +0 -187
  92. package/node_modules/@groove-dev/gui/src/views/toys.jsx +0 -162
  93. package/packages/gui/dist/assets/index-BV9CAiw1.css +0 -1
  94. package/packages/gui/dist/assets/index-DK6UIz0n.js +0 -8698
  95. package/packages/gui/src/components/toys/toy-card.jsx +0 -78
  96. package/packages/gui/src/components/toys/toy-creator.jsx +0 -144
  97. package/packages/gui/src/components/toys/toy-launcher.jsx +0 -187
  98. package/packages/gui/src/views/toys.jsx +0 -162
@@ -10,7 +10,7 @@ import { RootNode } from '../components/agents/root-node';
10
10
  import { cn } from '../lib/cn';
11
11
  import { Button } from '../components/ui/button';
12
12
  import { Badge } from '../components/ui/badge';
13
- import { Plus, Users, UserPlus, Zap, X, Check, Rocket, Server, Monitor, Code2, TestTube, Shield, Pencil, Copy, Trash2, ChevronDown, ChevronLeft, ChevronRight, FolderOpen, Eye, Settings2, Search, GripVertical, Cloud, FileText, Database, Megaphone, Calculator, UserCheck, Headphones, BarChart3, Pen, Presentation, Globe, MessageCircle, Save, Layers, Box, HardDrive, LayoutGrid } from 'lucide-react';
13
+ import { Plus, Users, UserPlus, Zap, X, Check, Rocket, Server, Monitor, Code2, TestTube, Shield, Pencil, Copy, Trash2, ChevronDown, ChevronLeft, ChevronRight, FolderOpen, Eye, Settings2, Search, GripVertical, Cloud, FileText, Database, Megaphone, Calculator, UserCheck, Headphones, BarChart3, Pen, Presentation, Globe, MessageCircle, Save, Layers, LayoutGrid, Activity, Gauge, Cpu } from 'lucide-react';
14
14
  import { PreviewWorkspace } from '../components/preview/preview-workspace';
15
15
  import { WorkspaceMode } from '../components/agents/workspace-mode';
16
16
  import { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuSeparator } from '../components/ui/context-menu';
@@ -1258,7 +1258,7 @@ function RecommendedTeamCard() {
1258
1258
  const [tsModel, setTsModel] = useState(teamLaunchConfig?.model || '');
1259
1259
  const [tsReasoning, setTsReasoning] = useState(teamLaunchConfig?.reasoningEffort ?? 50);
1260
1260
  const [tsTemp, setTsTemp] = useState(teamLaunchConfig?.temperature ?? 0.5);
1261
- const [tsMode, setTsMode] = useState(teamLaunchConfig?.mode || 'sandbox');
1261
+ const [expandedAgent, setExpandedAgent] = useState(null);
1262
1262
 
1263
1263
  useEffect(() => {
1264
1264
  fetchProviders().then((list) => {
@@ -1283,6 +1283,15 @@ function RecommendedTeamCard() {
1283
1283
  setEditedAgents(next);
1284
1284
  }
1285
1285
 
1286
+ function handleAgentField(i, updates) {
1287
+ if (typeof updates === 'string') {
1288
+ const [field, value] = [updates, arguments[2]];
1289
+ setEditedAgents((prev) => (prev ?? agentEdits).map((a, idx) => idx === i ? { ...a, [field]: value } : a));
1290
+ } else {
1291
+ setEditedAgents((prev) => (prev ?? agentEdits).map((a, idx) => idx === i ? { ...a, ...updates } : a));
1292
+ }
1293
+ }
1294
+
1286
1295
  function handleTsProviderChange(id) {
1287
1296
  setTsProvider(id);
1288
1297
  const p = providers.find((x) => x.id === id);
@@ -1298,7 +1307,6 @@ function RecommendedTeamCard() {
1298
1307
  ...(tsProvider && { provider: tsProvider, model: tsModel }),
1299
1308
  reasoningEffort: tsReasoning,
1300
1309
  ...(showTemp && { temperature: tsTemp }),
1301
- mode: tsMode,
1302
1310
  },
1303
1311
  });
1304
1312
  try {
@@ -1376,41 +1384,6 @@ function RecommendedTeamCard() {
1376
1384
  formatValue={(v) => v.toFixed(2)}
1377
1385
  />
1378
1386
  )}
1379
- {/* Build Mode */}
1380
- <div className="space-y-1">
1381
- <label className="text-2xs text-text-3 font-sans">Build Mode</label>
1382
- <div className="flex rounded-md bg-surface-4 border border-border-subtle p-0.5">
1383
- <button
1384
- onClick={() => setTsMode('sandbox')}
1385
- className={cn(
1386
- 'flex-1 flex items-center justify-center gap-1.5 rounded px-2 py-1.5 text-xs font-sans transition-all cursor-pointer',
1387
- tsMode === 'sandbox'
1388
- ? 'bg-surface-2 text-text-0 font-semibold shadow-sm'
1389
- : 'text-text-3 hover:text-text-1',
1390
- )}
1391
- >
1392
- <Box size={11} />
1393
- Sandbox
1394
- </button>
1395
- <button
1396
- onClick={() => setTsMode('production')}
1397
- className={cn(
1398
- 'flex-1 flex items-center justify-center gap-1.5 rounded px-2 py-1.5 text-xs font-sans transition-all cursor-pointer',
1399
- tsMode === 'production'
1400
- ? 'bg-surface-2 text-text-0 font-semibold shadow-sm'
1401
- : 'text-text-3 hover:text-text-1',
1402
- )}
1403
- >
1404
- <HardDrive size={11} />
1405
- Production
1406
- </button>
1407
- </div>
1408
- <p className="text-2xs text-text-4 font-sans">
1409
- {tsMode === 'sandbox'
1410
- ? 'Files live in a team directory, removable with the team'
1411
- : 'Files live in the project directory, persist forever'}
1412
- </p>
1413
- </div>
1414
1387
  </div>
1415
1388
  )}
1416
1389
  </div>
@@ -1419,31 +1392,116 @@ function RecommendedTeamCard() {
1419
1392
  {agentEdits.map((a, i) => {
1420
1393
  const Icon = ROLE_ICONS[a.role] || Code2;
1421
1394
  const nameValid = !a.name || NAME_RE.test(a.name);
1395
+ const isExpanded = expandedAgent === i;
1396
+ const agentProvider = providers.find((p) => p.id === (a.provider || tsProvider));
1397
+ const agentModels = (agentProvider?.models || []).filter((m) => m.type !== 'image' && !m.disabled);
1422
1398
  return (
1423
- <div key={i} className="flex items-center gap-2 px-2.5 py-1.5 rounded-md bg-surface-4 border border-border-subtle">
1424
- <Icon size={12} className="text-text-2 shrink-0" />
1425
- <input
1426
- type="text"
1427
- value={a.name}
1428
- onChange={(e) => handleNameChange(i, e.target.value)}
1429
- placeholder={a.role}
1430
- className={cn(
1431
- 'flex-1 min-w-0 bg-transparent text-xs font-mono text-text-0 outline-none placeholder:text-text-4',
1432
- !nameValid && 'text-red-400',
1399
+ <div key={i} className="rounded-md bg-surface-4 border border-border-subtle overflow-hidden">
1400
+ <div
1401
+ className="flex items-center gap-2 px-2.5 py-1.5 cursor-pointer hover:bg-surface-5/50 transition-colors"
1402
+ onClick={() => setExpandedAgent(isExpanded ? null : i)}
1403
+ >
1404
+ <Icon size={12} className="text-text-2 shrink-0" />
1405
+ <input
1406
+ type="text"
1407
+ value={a.name}
1408
+ onChange={(e) => handleNameChange(i, e.target.value)}
1409
+ onClick={(e) => e.stopPropagation()}
1410
+ placeholder={a.role}
1411
+ className={cn(
1412
+ 'flex-1 min-w-0 bg-transparent text-xs font-mono text-text-0 outline-none placeholder:text-text-4',
1413
+ !nameValid && 'text-red-400',
1414
+ )}
1415
+ maxLength={64}
1416
+ spellCheck={false}
1417
+ />
1418
+ {a.provider && a.provider !== tsProvider && (
1419
+ <span className="text-2xs text-accent font-mono shrink-0">{a.provider}</span>
1433
1420
  )}
1434
- maxLength={64}
1435
- spellCheck={false}
1436
- />
1437
- {a.scope?.length > 0 && (
1438
- <span className="text-2xs text-text-4 font-mono shrink-0 truncate max-w-[120px]">
1439
- {a.scope[0]}{a.scope.length > 1 ? ` +${a.scope.length - 1}` : ''}
1440
- </span>
1421
+ {a.scope?.length > 0 && (
1422
+ <span className="text-2xs text-text-4 font-mono shrink-0 truncate max-w-[120px]">
1423
+ {a.scope[0]}{a.scope.length > 1 ? ` +${a.scope.length - 1}` : ''}
1424
+ </span>
1425
+ )}
1426
+ <ChevronDown size={10} className={cn('text-text-4 shrink-0 transition-transform duration-200', !isExpanded && '-rotate-90')} />
1427
+ </div>
1428
+ {isExpanded && (
1429
+ <div className="px-2.5 pb-2.5 pt-1 space-y-2.5 border-t border-border-subtle">
1430
+ <div className="flex gap-2">
1431
+ <div className="flex-1 space-y-1">
1432
+ <label className="flex items-center gap-1 text-2xs text-text-3 font-sans"><Cpu size={10} />Provider</label>
1433
+ <Select value={a.provider || ''} onValueChange={(id) => {
1434
+ const p = providers.find((x) => x.id === id);
1435
+ const pModels = (p?.models || []).filter((m) => m.type !== 'image' && !m.disabled);
1436
+ handleAgentField(i, { provider: id, model: pModels[0]?.id || '' });
1437
+ }}>
1438
+ <SelectTrigger placeholder="Team default" className="bg-surface-3 h-7 text-xs" />
1439
+ <SelectContent>
1440
+ <SelectItem value="">Team default</SelectItem>
1441
+ {providers.map((p) => (
1442
+ <SelectItem key={p.id} value={p.id}>{p.displayName || p.name || p.id}</SelectItem>
1443
+ ))}
1444
+ </SelectContent>
1445
+ </Select>
1446
+ </div>
1447
+ <div className="flex-1 space-y-1">
1448
+ <label className="text-2xs text-text-3 font-sans">Model</label>
1449
+ <Select value={a.model || ''} onValueChange={(v) => handleAgentField(i, 'model', v)}>
1450
+ <SelectTrigger placeholder="Auto" className="bg-surface-3 h-7 text-xs" />
1451
+ <SelectContent>
1452
+ <SelectItem value="">Auto</SelectItem>
1453
+ {agentModels.map((m) => (
1454
+ <SelectItem key={m.id} value={m.id}>{m.name || m.id}</SelectItem>
1455
+ ))}
1456
+ </SelectContent>
1457
+ </Select>
1458
+ </div>
1459
+ </div>
1460
+ <div className="space-y-1">
1461
+ <label className="flex items-center gap-1 text-2xs text-text-3 font-sans"><Activity size={10} />Model Routing</label>
1462
+ <div className="flex bg-surface-3 rounded-md p-0.5 border border-border-subtle">
1463
+ {[{ value: 'fixed', label: 'Fixed' }, { value: 'auto', label: 'Auto' }, { value: 'auto-floor', label: 'Auto + Floor' }].map((opt) => (
1464
+ <button
1465
+ key={opt.value}
1466
+ onClick={() => handleAgentField(i, 'routingMode', opt.value)}
1467
+ className={cn(
1468
+ 'flex-1 px-2 py-1 text-2xs font-semibold font-sans rounded transition-all cursor-pointer',
1469
+ (a.routingMode || 'auto') === opt.value
1470
+ ? 'bg-accent/15 text-accent shadow-sm'
1471
+ : 'text-text-3 hover:text-text-1',
1472
+ )}
1473
+ >
1474
+ {opt.label}
1475
+ </button>
1476
+ ))}
1477
+ </div>
1478
+ </div>
1479
+ <div className="space-y-1">
1480
+ <label className="flex items-center gap-1 text-2xs text-text-3 font-sans"><Gauge size={10} />Effort Level</label>
1481
+ <div className="flex bg-surface-3 rounded-md p-0.5 border border-border-subtle">
1482
+ {[{ value: 'min', label: 'Min' }, { value: 'low', label: 'Low' }, { value: 'default', label: 'Default' }, { value: 'high', label: 'High' }, { value: 'max', label: 'Max' }].map((opt) => (
1483
+ <button
1484
+ key={opt.value}
1485
+ onClick={() => handleAgentField(i, 'effort', opt.value)}
1486
+ className={cn(
1487
+ 'flex-1 px-1.5 py-1 text-2xs font-semibold font-sans rounded transition-all cursor-pointer',
1488
+ (a.effort || 'default') === opt.value
1489
+ ? 'bg-accent/15 text-accent shadow-sm'
1490
+ : 'text-text-3 hover:text-text-1',
1491
+ )}
1492
+ >
1493
+ {opt.label}
1494
+ </button>
1495
+ ))}
1496
+ </div>
1497
+ </div>
1498
+ </div>
1441
1499
  )}
1442
1500
  </div>
1443
1501
  );
1444
1502
  })}
1445
1503
 
1446
- {recommendedTeam.projectDir && tsMode === 'sandbox' && (
1504
+ {recommendedTeam.projectDir && (
1447
1505
  <div className="flex items-center gap-1.5 text-2xs text-text-2 font-mono pt-0.5">
1448
1506
  <span className="text-text-4">Project:</span>
1449
1507
  <span className="text-accent">{recommendedTeam.projectDir}/</span>
@@ -4,6 +4,7 @@ import { useGrooveStore } from '../stores/groove';
4
4
  import { DashboardHeader } from '../components/dashboard/header-bar';
5
5
  import { KpiStrip } from '../components/dashboard/kpi-card';
6
6
  import { FleetPanel } from '../components/dashboard/fleet-panel';
7
+ import { ContextGauges } from '../components/dashboard/context-gauges';
7
8
  import { TokenChart } from '../components/dashboard/token-chart';
8
9
  import { CacheRing } from '../components/dashboard/cache-ring';
9
10
  import { RoutingChart } from '../components/dashboard/routing-chart';
@@ -142,6 +143,7 @@ export default function DashboardView() {
142
143
  <div className="px-3 pt-2.5 pb-1 flex-shrink-0">
143
144
  <span className="text-2xs font-mono text-text-3 uppercase tracking-widest">Agent Fleet</span>
144
145
  </div>
146
+ <ContextGauges agentBreakdown={agentBreakdown} />
145
147
  <FleetPanel agentBreakdown={agentBreakdown} rotating={rotating} teams={teams} />
146
148
  </div>
147
149
 
@@ -4,15 +4,13 @@ import { ScrollArea } from '../components/ui/scroll-area';
4
4
  import { Badge } from '../components/ui/badge';
5
5
  import { Button } from '../components/ui/button';
6
6
  import { Skeleton } from '../components/ui/skeleton';
7
- import { SkillCard, SkillCardSkeleton } from '../components/marketplace/skill-card';
7
+ import { SkillCardSkeleton } from '../components/marketplace/skill-card';
8
8
  import { MarketplaceCard } from '../components/marketplace/marketplace-card';
9
9
  import { SearchBar } from '../components/marketplace/search-bar';
10
- import { CategoryBar } from '../components/marketplace/category-bar';
11
10
  import { MarketplaceBadge } from '../components/marketplace/marketplace-badge';
12
11
  import { StarRating } from '../components/marketplace/star-rating';
13
12
  import { PriceBadge } from '../components/marketplace/price-badge';
14
13
  import { VerifiedShield } from '../components/marketplace/verified-shield';
15
- import { markFavorites } from '../components/marketplace/favorites';
16
14
  import { api } from '../lib/api';
17
15
  import { useToast } from '../lib/hooks/use-toast';
18
16
  import { fmtNum, timeAgo } from '../lib/format';
@@ -22,7 +20,7 @@ import { RepoImport } from '../components/marketplace/repo-import';
22
20
  import { RepoCard } from '../components/marketplace/repo-card';
23
21
  import { RepoNukeDialog } from '../components/marketplace/repo-nuke-dialog';
24
22
  import {
25
- ChevronLeft, ChevronDown, Sparkles, Plug, LogIn,
23
+ ChevronLeft, Plug, LogIn,
26
24
  Upload, Package, Download, ShoppingBag, RefreshCw, Trash2,
27
25
  GitBranch,
28
26
  } from 'lucide-react';
@@ -214,70 +212,6 @@ function SkillDetail({ skill, onBack }) {
214
212
  }
215
213
 
216
214
  // ── Skills Browse ────────────────────────────────────────
217
- function SkillsBrowse() {
218
- const [skills, setSkills] = useState([]);
219
- const [loading, setLoading] = useState(true);
220
- const [search, setSearch] = useState('');
221
- const [category, setCategory] = useState('');
222
- const [sort, setSort] = useState('popular');
223
- const [selectedSkill, setSelectedSkill] = useState(null);
224
-
225
- useEffect(() => {
226
- setLoading(true);
227
- const params = new URLSearchParams();
228
- if (search) params.set('search', search);
229
- if (category) params.set('category', category);
230
- if (sort) params.set('sort', sort);
231
- api.get(`/skills/registry?${params}`)
232
- .then((d) => setSkills(markFavorites(d.skills || d.items || (Array.isArray(d) ? d : []))))
233
- .catch(() => setSkills([]))
234
- .finally(() => setLoading(false));
235
- }, [search, category, sort]);
236
-
237
- if (selectedSkill) {
238
- return <SkillDetail skill={selectedSkill} onBack={() => setSelectedSkill(null)} />;
239
- }
240
-
241
- return (
242
- <ScrollArea className="h-full">
243
- <div className="px-5 py-4">
244
- <div className="flex items-center gap-3">
245
- <div className="w-72">
246
- <SearchBar value={search} onChange={setSearch} />
247
- </div>
248
- <CategoryBar selected={category} onSelect={setCategory} />
249
- <div className="flex-1" />
250
- <div className="relative flex-shrink-0">
251
- <select
252
- value={sort}
253
- onChange={(e) => setSort(e.target.value)}
254
- className="appearance-none font-sans cursor-pointer pr-7 py-2 pl-3 text-xs bg-surface-0 border border-border-subtle rounded text-text-1 focus:outline-none"
255
- >
256
- <option value="popular">Popular</option>
257
- <option value="rating">Top Rated</option>
258
- <option value="newest">Newest</option>
259
- <option value="name">A-Z</option>
260
- </select>
261
- <ChevronDown size={12} className="absolute right-2 top-1/2 -translate-y-1/2 text-text-4 pointer-events-none" />
262
- </div>
263
- <span className="text-2xs text-text-4 font-mono flex-shrink-0">{skills.length}</span>
264
- </div>
265
-
266
- <div className="mt-4 grid gap-3" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))' }}>
267
- {loading
268
- ? Array.from({ length: 8 }).map((_, i) => <SkillCardSkeleton key={i} />)
269
- : skills.map((s) => <SkillCard key={s.id} skill={s} onClick={setSelectedSkill} />)
270
- }
271
- </div>
272
-
273
- {!loading && skills.length === 0 && (
274
- <div className="text-center py-16 text-text-4 font-sans text-sm">No skills found.</div>
275
- )}
276
- </div>
277
- </ScrollArea>
278
- );
279
- }
280
-
281
215
  // ── Integrations Browse ──────────────────────────────────
282
216
  const GOOGLE_IDS = new Set(['gmail', 'google-calendar', 'google-drive', 'google-docs', 'google-sheets', 'google-slides']);
283
217
 
@@ -666,10 +600,9 @@ function GitHubBrowse() {
666
600
 
667
601
  // ── Main ─────────────────────────────────────────────────
668
602
  export default function MarketplaceView() {
669
- const [tab, setTab] = useState('skills');
603
+ const [tab, setTab] = useState('integrations');
670
604
 
671
605
  const tabs = [
672
- { id: 'skills', label: 'Skills', icon: Sparkles },
673
606
  { id: 'integrations', label: 'Integrations', icon: Plug },
674
607
  { id: 'github', label: 'GitHub', icon: GitBranch },
675
608
  { id: 'library', label: 'My Library', icon: Package },
@@ -701,7 +634,6 @@ export default function MarketplaceView() {
701
634
 
702
635
  {/* Content */}
703
636
  <div className="flex-1 min-h-0">
704
- {tab === 'skills' && <SkillsBrowse />}
705
637
  {tab === 'integrations' && <IntegrationsBrowse />}
706
638
  {tab === 'github' && <GitHubBrowse />}
707
639
  {tab === 'library' && <MyLibrary />}
@@ -7,15 +7,15 @@ import { Dialog, DialogContent } from '../components/ui/dialog';
7
7
  import { BookOpen, Plus, Search, Trash2, Pencil, ChevronRight, Hash, FolderOpen, Clock, Save, Link2, FileText, Sparkles, HelpCircle } from 'lucide-react';
8
8
 
9
9
  const COMMANDS = [
10
- { cmd: '[save]', args: '#tag', desc: 'Save the current message as a tagged memory' },
11
- { cmd: '[append]', args: '#tag', desc: 'Add to an existing memory without overwriting' },
12
- { cmd: '[update]', args: '#tag', desc: 'Open the editor to modify a memory in place' },
13
- { cmd: '[delete]', args: '#tag', desc: 'Remove a memory permanently' },
14
- { cmd: '[view]', args: '#tag', desc: 'Read a memory in the viewer' },
15
- { cmd: '[read]', args: '#tag1 #tag2 ...', desc: 'Send memory content to the agent — agent reads it, chat stays clean' },
16
- { cmd: '[doc]', args: '#tag', desc: 'AI synthesizes the full conversation into a document' },
17
- { cmd: '[link]', args: '#tag path/to/doc', desc: 'Link a memory to a NORTHSTAR or external document' },
18
- { cmd: '[instruct]', args: '', desc: 'Show this command reference' },
10
+ { cmd: 'save', args: '#tag', desc: 'Save the message and send it to the agent' },
11
+ { cmd: 'append', args: '#tag', desc: 'Add to an existing memory and send to agent' },
12
+ { cmd: 'update', args: '#tag', desc: 'Open the editor to modify a memory in place' },
13
+ { cmd: 'delete', args: '#tag', desc: 'Remove a memory permanently' },
14
+ { cmd: 'view', args: '#tag', desc: 'Read a memory in the viewer' },
15
+ { cmd: 'read', args: '#tag1 #tag2 ...', desc: 'Send memory content to the agent — chat stays clean' },
16
+ { cmd: 'doc', args: '#tag', desc: 'AI synthesizes the full conversation into a document' },
17
+ { cmd: 'link', args: '#tag path/to/doc', desc: 'Link a memory to a NORTHSTAR or external document' },
18
+ { cmd: '[instruct]', args: '', desc: 'Show this command reference' },
19
19
  ];
20
20
 
21
21
  function formatRelative(iso) {
@@ -171,17 +171,12 @@ export default function ModelLabView() {
171
171
  <PanelToggle collapsed={false} onClick={() => setLeftCollapsed(true)} side="left" />
172
172
  </div>
173
173
  <ScrollArea className="flex-1 min-h-0">
174
- <div className="px-4 pb-4 space-y-5">
174
+ <div className="px-4 pb-4 space-y-5 divide-y divide-border-subtle [&>*]:pt-5 [&>*:first-child]:pt-0">
175
175
  <LaunchModel />
176
- <div className="h-px bg-border-subtle" />
177
176
  <RuntimeConfig />
178
- <div className="h-px bg-border-subtle" />
179
177
  <ModelSelector />
180
- <div className="h-px bg-border-subtle" />
181
178
  <ParameterPanel />
182
- <div className="h-px bg-border-subtle" />
183
179
  <PresetManager />
184
- <div className="h-px bg-border-subtle" />
185
180
  <SystemPromptEditor />
186
181
  </div>
187
182
  </ScrollArea>