groove-dev 0.27.119 → 0.27.121

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 (47) hide show
  1. package/moe-training/client/trajectory-capture.js +55 -0
  2. package/moe-training/test/client/trajectory-capture.test.js +63 -0
  3. package/node_modules/@groove-dev/cli/package.json +1 -1
  4. package/node_modules/@groove-dev/cli/src/commands/start.js +2 -1
  5. package/node_modules/@groove-dev/daemon/package.json +1 -1
  6. package/node_modules/@groove-dev/daemon/src/api.js +30 -10
  7. package/node_modules/@groove-dev/daemon/src/conversations.js +54 -32
  8. package/node_modules/@groove-dev/daemon/src/introducer.js +45 -20
  9. package/node_modules/@groove-dev/daemon/src/process.js +47 -1
  10. package/node_modules/@groove-dev/daemon/src/teams.js +33 -0
  11. package/node_modules/@groove-dev/gui/dist/assets/{index-DT6Jbf_q.css → index-BLd3MON8.css} +1 -1
  12. package/node_modules/@groove-dev/gui/dist/assets/{index-BxPCaxlC.js → index-bmkBX18f.js} +1721 -1721
  13. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  14. package/node_modules/@groove-dev/gui/package.json +1 -1
  15. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +3 -41
  16. package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +4 -43
  17. package/node_modules/@groove-dev/gui/src/components/layout/status-bar.jsx +8 -10
  18. package/node_modules/@groove-dev/gui/src/components/onboarding/setup-wizard.jsx +8 -23
  19. package/node_modules/@groove-dev/gui/src/components/settings/ProviderSetupWizard.jsx +54 -143
  20. package/node_modules/@groove-dev/gui/src/components/ui/data-sharing-modal.jsx +7 -57
  21. package/node_modules/@groove-dev/gui/src/stores/groove.js +13 -0
  22. package/node_modules/@groove-dev/gui/src/views/settings.jsx +50 -84
  23. package/node_modules/@groove-dev/gui/src/views/teams.jsx +61 -1
  24. package/node_modules/moe-training/client/trajectory-capture.js +55 -0
  25. package/node_modules/moe-training/test/client/trajectory-capture.test.js +63 -0
  26. package/package.json +1 -1
  27. package/packages/cli/package.json +1 -1
  28. package/packages/cli/src/commands/start.js +2 -1
  29. package/packages/daemon/package.json +1 -1
  30. package/packages/daemon/src/api.js +30 -10
  31. package/packages/daemon/src/conversations.js +54 -32
  32. package/packages/daemon/src/introducer.js +45 -20
  33. package/packages/daemon/src/process.js +47 -1
  34. package/packages/daemon/src/teams.js +33 -0
  35. package/packages/gui/dist/assets/{index-DT6Jbf_q.css → index-BLd3MON8.css} +1 -1
  36. package/packages/gui/dist/assets/{index-BxPCaxlC.js → index-bmkBX18f.js} +1721 -1721
  37. package/packages/gui/dist/index.html +2 -2
  38. package/packages/gui/package.json +1 -1
  39. package/packages/gui/src/components/agents/agent-config.jsx +3 -41
  40. package/packages/gui/src/components/agents/spawn-wizard.jsx +4 -43
  41. package/packages/gui/src/components/layout/status-bar.jsx +8 -10
  42. package/packages/gui/src/components/onboarding/setup-wizard.jsx +8 -23
  43. package/packages/gui/src/components/settings/ProviderSetupWizard.jsx +54 -143
  44. package/packages/gui/src/components/ui/data-sharing-modal.jsx +7 -57
  45. package/packages/gui/src/stores/groove.js +13 -0
  46. package/packages/gui/src/views/settings.jsx +50 -84
  47. package/packages/gui/src/views/teams.jsx +61 -1
@@ -62,10 +62,8 @@ function ProviderCard({ provider, onKeyChange }) {
62
62
  const [customPathOpen, setCustomPathOpen] = useState(false);
63
63
  const [customPath, setCustomPath] = useState('');
64
64
  const [savingPath, setSavingPath] = useState(false);
65
- const [loginPending, setLoginPending] = useState(false);
66
65
  const addToast = useGrooveStore((s) => s.addToast);
67
66
  const installProgress = useGrooveStore((s) => s.providerInstallProgress[provider.id]);
68
- const loginProvider = useGrooveStore((s) => s.loginProvider);
69
67
  const setProviderPath = useGrooveStore((s) => s.setProviderPath);
70
68
  const verifyProvider = useGrooveStore((s) => s.verifyProvider);
71
69
  const installProvider = useGrooveStore((s) => s.installProvider);
@@ -100,15 +98,6 @@ function ProviderCard({ provider, onKeyChange }) {
100
98
  }
101
99
  }
102
100
 
103
- async function handleLogin(body) {
104
- try {
105
- setLoginPending(true);
106
- await loginProvider(provider.id, body);
107
- } catch {
108
- setLoginPending(false);
109
- }
110
- }
111
-
112
101
  async function handleSavePath() {
113
102
  if (!customPath.trim()) return;
114
103
  setSavingPath(true);
@@ -321,15 +310,30 @@ function ProviderCard({ provider, onKeyChange }) {
321
310
  {effectivelyInstalled && !isReady && !settingKey && !isInstalling && (
322
311
  <div className="flex flex-col gap-3 flex-1">
323
312
  {/* ── Claude Code auth ── */}
324
- {provider.id === 'claude-code' && !loginPending && (
313
+ {provider.id === 'claude-code' && (
325
314
  <>
326
- <div className="space-y-1.5">
327
- <p className="text-xs text-text-1 font-sans font-medium">Sign in with your Claude account</p>
328
- <p className="text-2xs text-text-3 font-sans">A browser window will open where you can sign in with your existing Anthropic account or Claude subscription.</p>
315
+ <div className="space-y-2">
316
+ <p className="text-xs text-text-1 font-sans font-medium">Sign in via terminal</p>
317
+ <div className="space-y-1.5">
318
+ <div className="flex items-start gap-2">
319
+ <span className="text-2xs font-bold text-accent font-mono mt-0.5">1</span>
320
+ <p className="text-2xs text-text-2 font-sans flex items-center gap-1">
321
+ <Terminal size={10} className="text-text-3 flex-shrink-0" />
322
+ Open the Groove terminal below
323
+ </p>
324
+ </div>
325
+ <div className="flex items-start gap-2">
326
+ <span className="text-2xs font-bold text-accent font-mono mt-0.5">2</span>
327
+ <p className="text-2xs text-text-2 font-sans">
328
+ Run: <code className="font-mono text-accent bg-surface-4 px-1.5 py-0.5 rounded text-2xs">claude</code>
329
+ </p>
330
+ </div>
331
+ <div className="flex items-start gap-2">
332
+ <span className="text-2xs font-bold text-accent font-mono mt-0.5">3</span>
333
+ <p className="text-2xs text-text-2 font-sans">Follow the prompts to sign in with your Anthropic account</p>
334
+ </div>
335
+ </div>
329
336
  </div>
330
- <Button variant="primary" size="sm" onClick={() => handleLogin()} className="w-full h-9 text-xs gap-1.5">
331
- <ExternalLink size={12} /> Sign In
332
- </Button>
333
337
  <button
334
338
  onClick={() => { setSettingKey(true); setShowKey(false); setKeyInput(''); }}
335
339
  className="text-2xs text-text-4 hover:text-accent cursor-pointer font-sans text-center"
@@ -340,15 +344,36 @@ function ProviderCard({ provider, onKeyChange }) {
340
344
  )}
341
345
 
342
346
  {/* ── Codex auth ── */}
343
- {provider.id === 'codex' && !loginPending && (
347
+ {provider.id === 'codex' && (
344
348
  <>
345
- <div className="space-y-1.5">
346
- <p className="text-xs text-text-1 font-sans font-medium">Sign in with your ChatGPT account</p>
347
- <p className="text-2xs text-text-3 font-sans">A browser window will open where you can sign in with your ChatGPT Plus or Teams subscription.</p>
349
+ <div className="space-y-2">
350
+ <p className="text-xs text-text-1 font-sans font-medium">Sign in via terminal</p>
351
+ <div className="space-y-1.5">
352
+ <div className="flex items-start gap-2">
353
+ <span className="text-2xs font-bold text-accent font-mono mt-0.5">1</span>
354
+ <p className="text-2xs text-text-2 font-sans flex items-center gap-1">
355
+ <Terminal size={10} className="text-text-3 flex-shrink-0" />
356
+ Open the Groove terminal below
357
+ </p>
358
+ </div>
359
+ <div className="flex items-start gap-2">
360
+ <span className="text-2xs font-bold text-accent font-mono mt-0.5">2</span>
361
+ <p className="text-2xs text-text-2 font-sans">
362
+ Run: <code className="font-mono text-accent bg-surface-4 px-1.5 py-0.5 rounded text-2xs">npm i -g @openai/codex</code> (if not installed)
363
+ </p>
364
+ </div>
365
+ <div className="flex items-start gap-2">
366
+ <span className="text-2xs font-bold text-accent font-mono mt-0.5">3</span>
367
+ <p className="text-2xs text-text-2 font-sans">
368
+ Run: <code className="font-mono text-accent bg-surface-4 px-1.5 py-0.5 rounded text-2xs">codex login</code>
369
+ </p>
370
+ </div>
371
+ <div className="flex items-start gap-2">
372
+ <span className="text-2xs font-bold text-accent font-mono mt-0.5">4</span>
373
+ <p className="text-2xs text-text-2 font-sans">Follow the prompts to authenticate</p>
374
+ </div>
375
+ </div>
348
376
  </div>
349
- <Button variant="primary" size="sm" onClick={() => handleLogin({ method: 'chatgpt-plus' })} className="w-full h-9 text-xs gap-1.5">
350
- <ExternalLink size={12} /> Sign In
351
- </Button>
352
377
  <button
353
378
  onClick={() => { setSettingKey(true); setShowKey(false); setKeyInput(''); }}
354
379
  className="text-2xs text-text-4 hover:text-accent cursor-pointer font-sans text-center"
@@ -442,65 +467,6 @@ function ProviderCard({ provider, onKeyChange }) {
442
467
  </>
443
468
  )}
444
469
 
445
- {/* ── Any provider: login pending state ── */}
446
- {(provider.id === 'claude-code' || provider.id === 'codex') && loginPending && (
447
- <div className="flex flex-col gap-3">
448
- <div className="flex items-center gap-2 p-3 bg-accent/5 border border-accent/15 rounded-md">
449
- <Loader2 size={14} className="text-accent animate-spin" />
450
- <div>
451
- <p className="text-xs text-accent font-sans font-medium">Check your browser</p>
452
- <p className="text-2xs text-text-3 font-sans">Complete the sign-in in the browser window that opened.</p>
453
- </div>
454
- </div>
455
- <Button
456
- variant="primary"
457
- size="sm"
458
- disabled={checking}
459
- onClick={async () => {
460
- if (provider.id === 'codex') {
461
- setChecking(true);
462
- try {
463
- const res = await api.post(`/providers/codex/verify`);
464
- if (res.authenticated) {
465
- setLoginPending(false);
466
- if (onKeyChange) onKeyChange();
467
- } else {
468
- addToast('error', 'Authentication not detected yet. Please complete sign-in in your browser and try again.');
469
- }
470
- } catch {
471
- addToast('error', 'Authentication not detected yet. Please complete sign-in in your browser and try again.');
472
- } finally {
473
- setChecking(false);
474
- }
475
- } else {
476
- setChecking(true);
477
- try {
478
- const res = await api.post(`/providers/claude-code/verify`);
479
- if (res.authenticated) {
480
- setLoginPending(false);
481
- if (onKeyChange) onKeyChange();
482
- } else {
483
- addToast('error', 'Authentication not detected yet. Please complete sign-in in your browser and try again.');
484
- }
485
- } catch {
486
- addToast('error', 'Authentication not detected yet. Please complete sign-in in your browser and try again.');
487
- } finally {
488
- setChecking(false);
489
- }
490
- }
491
- }}
492
- className="w-full h-8 text-xs gap-1.5"
493
- >
494
- {checking ? <Loader2 size={12} className="animate-spin" /> : <Check size={12} />} I've signed in
495
- </Button>
496
- <button
497
- onClick={() => setLoginPending(false)}
498
- className="text-2xs text-text-4 hover:text-text-2 cursor-pointer font-sans text-center"
499
- >
500
- Cancel
501
- </button>
502
- </div>
503
- )}
504
470
  </div>
505
471
  )}
506
472
 
@@ -9,10 +9,11 @@ import { api } from '../lib/api';
9
9
  import { useToast } from '../lib/hooks/use-toast';
10
10
  import { fmtNum, fmtDollar, timeAgo, fmtUptime } from '../lib/format';
11
11
  import { cn } from '../lib/cn';
12
+ import { Dialog, DialogContent } from '../components/ui/dialog';
12
13
  import {
13
14
  Clock, CheckCircle, XCircle, AlertTriangle, ShieldCheck, ShieldX,
14
15
  Users, Folder, Cpu, Trash2, Play, Pause, LayoutDashboard, ListChecks, Calendar,
15
- Archive, RotateCcw, ChevronRight,
16
+ Archive, RotateCcw, ChevronRight, ArrowUpCircle,
16
17
  } from 'lucide-react';
17
18
  import { TeamRemovalDialog, PurgeConfirmDialog } from '../components/teams/team-removal-dialog';
18
19
 
@@ -28,9 +29,11 @@ function TeamsDashboard() {
28
29
  const fetchArchivedTeams = useGrooveStore((s) => s.fetchArchivedTeams);
29
30
  const restoreTeam = useGrooveStore((s) => s.restoreTeam);
30
31
  const purgeTeam = useGrooveStore((s) => s.purgeTeam);
32
+ const promoteTeam = useGrooveStore((s) => s.promoteTeam);
31
33
 
32
34
  const [archiveConfirm, setArchiveConfirm] = useState(null);
33
35
  const [purgeConfirm, setPurgeConfirm] = useState(null);
36
+ const [promoteConfirm, setPromoteConfirm] = useState(null);
34
37
  const [archivedOpen, setArchivedOpen] = useState(false);
35
38
 
36
39
  useEffect(() => { fetchArchivedTeams(); }, []);
@@ -84,6 +87,15 @@ function TeamsDashboard() {
84
87
  </div>
85
88
  )}
86
89
  </div>
90
+ {team.mode !== 'production' && (
91
+ <button
92
+ onClick={() => setPromoteConfirm(team)}
93
+ className="p-1.5 text-text-4 hover:text-success rounded transition-colors cursor-pointer"
94
+ title="Promote to production"
95
+ >
96
+ <ArrowUpCircle size={13} />
97
+ </button>
98
+ )}
87
99
  <button
88
100
  onClick={() => {
89
101
  if (teamAgents.some((a) => a.status === 'running' || a.status === 'starting')) {
@@ -195,10 +207,58 @@ function TeamsDashboard() {
195
207
  onOpenChange={(open) => !open && setPurgeConfirm(null)}
196
208
  onPurge={purgeTeam}
197
209
  />
210
+
211
+ <PromoteConfirmDialog
212
+ team={promoteConfirm}
213
+ open={!!promoteConfirm}
214
+ onOpenChange={(open) => !open && setPromoteConfirm(null)}
215
+ onPromote={promoteTeam}
216
+ />
198
217
  </div>
199
218
  );
200
219
  }
201
220
 
221
+ function PromoteConfirmDialog({ team, open, onOpenChange, onPromote }) {
222
+ const [promoting, setPromoting] = useState(false);
223
+
224
+ useEffect(() => {
225
+ if (!open) setPromoting(false);
226
+ }, [open]);
227
+
228
+ async function handleConfirm() {
229
+ setPromoting(true);
230
+ try {
231
+ await onPromote(team?.id);
232
+ onOpenChange(false);
233
+ } catch {
234
+ setPromoting(false);
235
+ }
236
+ }
237
+
238
+ return (
239
+ <Dialog open={open} onOpenChange={onOpenChange}>
240
+ <DialogContent title="Promote to Production" description="Promote this team to production mode">
241
+ <div className="px-5 py-4 space-y-3">
242
+ <p className="text-sm text-text-1 font-sans">
243
+ Promote <span className="font-semibold text-text-0">{team?.name}</span> to production?
244
+ </p>
245
+ <p className="text-xs text-text-3 font-sans">
246
+ This will move files from the team directory into the project directory.
247
+ The team will switch to production mode and files will persist when the team is removed.
248
+ </p>
249
+ </div>
250
+ <div className="px-5 py-3 border-t border-border-subtle flex justify-end gap-2">
251
+ <Button variant="ghost" size="sm" onClick={() => onOpenChange(false)}>Cancel</Button>
252
+ <Button variant="primary" size="sm" disabled={promoting} onClick={handleConfirm} className="gap-1.5">
253
+ <ArrowUpCircle size={12} />
254
+ {promoting ? 'Promoting...' : 'Promote'}
255
+ </Button>
256
+ </div>
257
+ </DialogContent>
258
+ </Dialog>
259
+ );
260
+ }
261
+
202
262
  function Stat({ label, value, color }) {
203
263
  return (
204
264
  <div className="text-center">