groove-dev 0.27.42 → 0.27.45

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 (55) hide show
  1. package/default/groovedev-beta-auth-endpoint.md +166 -0
  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 +619 -0
  5. package/node_modules/@groove-dev/daemon/src/firstrun.js +11 -0
  6. package/node_modules/@groove-dev/daemon/src/index.js +28 -0
  7. package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +1 -1
  8. package/node_modules/@groove-dev/daemon/src/providers/groove-network.js +114 -0
  9. package/node_modules/@groove-dev/daemon/src/providers/index.js +2 -0
  10. package/node_modules/@groove-dev/gui/dist/assets/index-BoIbnaqa.js +8607 -0
  11. package/node_modules/@groove-dev/gui/dist/assets/index-CyVj0fHl.css +1 -0
  12. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  13. package/node_modules/@groove-dev/gui/package.json +1 -1
  14. package/node_modules/@groove-dev/gui/src/app.jsx +3 -0
  15. package/node_modules/@groove-dev/gui/src/components/editor/terminal.jsx +5 -0
  16. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +7 -3
  17. package/node_modules/@groove-dev/gui/src/components/layout/status-bar.jsx +12 -0
  18. package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +25 -7
  19. package/node_modules/@groove-dev/gui/src/components/network/network-status.jsx +164 -0
  20. package/node_modules/@groove-dev/gui/src/components/network/node-details.jsx +66 -0
  21. package/node_modules/@groove-dev/gui/src/components/network/node-toggle.jsx +172 -0
  22. package/node_modules/@groove-dev/gui/src/stores/groove.js +191 -0
  23. package/node_modules/@groove-dev/gui/src/views/agents.jsx +1 -1
  24. package/node_modules/@groove-dev/gui/src/views/network.jsx +227 -0
  25. package/node_modules/@groove-dev/gui/src/views/settings.jsx +88 -1
  26. package/package.json +1 -1
  27. package/packages/cli/package.json +1 -1
  28. package/packages/daemon/package.json +1 -1
  29. package/packages/daemon/src/api.js +619 -0
  30. package/packages/daemon/src/firstrun.js +11 -0
  31. package/packages/daemon/src/index.js +28 -0
  32. package/packages/daemon/src/providers/claude-code.js +1 -1
  33. package/packages/daemon/src/providers/groove-network.js +114 -0
  34. package/packages/daemon/src/providers/index.js +2 -0
  35. package/packages/gui/dist/assets/index-BoIbnaqa.js +8607 -0
  36. package/packages/gui/dist/assets/index-CyVj0fHl.css +1 -0
  37. package/packages/gui/dist/index.html +2 -2
  38. package/packages/gui/package.json +1 -1
  39. package/packages/gui/src/app.jsx +3 -0
  40. package/packages/gui/src/components/editor/terminal.jsx +5 -0
  41. package/packages/gui/src/components/layout/activity-bar.jsx +7 -3
  42. package/packages/gui/src/components/layout/status-bar.jsx +12 -0
  43. package/packages/gui/src/components/layout/terminal-panel.jsx +25 -7
  44. package/packages/gui/src/components/network/network-status.jsx +164 -0
  45. package/packages/gui/src/components/network/node-details.jsx +66 -0
  46. package/packages/gui/src/components/network/node-toggle.jsx +172 -0
  47. package/packages/gui/src/stores/groove.js +191 -0
  48. package/packages/gui/src/views/agents.jsx +1 -1
  49. package/packages/gui/src/views/network.jsx +227 -0
  50. package/packages/gui/src/views/settings.jsx +88 -1
  51. package/analyist/groove-security-audit.md +0 -323
  52. package/node_modules/@groove-dev/gui/dist/assets/index-C1C2biHU.js +0 -8607
  53. package/node_modules/@groove-dev/gui/dist/assets/index-Dx7i-7_K.css +0 -1
  54. package/packages/gui/dist/assets/index-C1C2biHU.js +0 -8607
  55. package/packages/gui/dist/assets/index-Dx7i-7_K.css +0 -1
@@ -0,0 +1,227 @@
1
+ // FSL-1.1-Apache-2.0 — see LICENSE
2
+ import { useEffect, useState } from 'react';
3
+ import { useGrooveStore } from '../stores/groove';
4
+ import { ScrollArea } from '../components/ui/scroll-area';
5
+ import { StatusDot } from '../components/ui/status-dot';
6
+ import { Badge } from '../components/ui/badge';
7
+ import { Button } from '../components/ui/button';
8
+ import { Dialog, DialogContent, DialogTrigger } from '../components/ui/dialog';
9
+ import { NodeToggle } from '../components/network/node-toggle';
10
+ import { NodeDetails } from '../components/network/node-details';
11
+ import { NetworkStatus } from '../components/network/network-status';
12
+ import { Globe, Download, Check, AlertCircle, Loader2, Trash2 } from 'lucide-react';
13
+
14
+ const REQUIREMENTS = [
15
+ 'Python 3.10 or higher',
16
+ '~2 GB disk space for model shards',
17
+ '8 GB+ RAM recommended',
18
+ ];
19
+
20
+ function InstallProgress({ progress }) {
21
+ const percent = Math.max(0, Math.min(100, Number.isFinite(progress.percent) ? progress.percent : 0));
22
+ return (
23
+ <div className="w-full flex flex-col gap-3">
24
+ <div className="h-2 w-full rounded-full bg-surface-3 overflow-hidden">
25
+ <div
26
+ className="h-full rounded-full bg-accent transition-all duration-500 ease-out"
27
+ style={{ width: `${percent}%` }}
28
+ />
29
+ </div>
30
+ <div className="flex items-center justify-between text-2xs font-mono text-text-3 tabular-nums">
31
+ <div className="flex items-center gap-2 text-text-2 font-sans">
32
+ <Loader2 size={12} className="animate-spin text-accent" />
33
+ <span className="truncate">{progress.message || 'Installing…'}</span>
34
+ </div>
35
+ <span>{percent}%</span>
36
+ </div>
37
+ </div>
38
+ );
39
+ }
40
+
41
+ function InstallError({ message, onRetry }) {
42
+ return (
43
+ <div className="w-full flex flex-col gap-3">
44
+ <div className="rounded-md border border-danger/40 bg-danger/10 px-4 py-3 flex items-start gap-2.5 text-left">
45
+ <AlertCircle size={14} className="text-danger flex-shrink-0 mt-0.5" />
46
+ <div className="flex-1 min-w-0">
47
+ <div className="text-xs font-semibold text-danger font-sans mb-0.5">Install failed</div>
48
+ <div className="text-xs text-text-1 font-sans break-words">{message}</div>
49
+ </div>
50
+ </div>
51
+ <Button variant="primary" size="lg" onClick={onRetry} className="w-full">
52
+ <Download size={14} />
53
+ Retry Install
54
+ </Button>
55
+ </div>
56
+ );
57
+ }
58
+
59
+ function InstallGate() {
60
+ const installNetworkPackage = useGrooveStore((s) => s.installNetworkPackage);
61
+ const progress = useGrooveStore((s) => s.networkInstallProgress);
62
+ const { installing, error } = progress;
63
+
64
+ return (
65
+ <div className="flex flex-col items-center justify-center min-h-full px-6 py-12">
66
+ <div className="w-full max-w-md flex flex-col items-center text-center">
67
+ <div className="mb-5 rounded-full bg-surface-2 border border-border-subtle p-5">
68
+ <Globe size={48} className="text-text-3" strokeWidth={1.25} />
69
+ </div>
70
+ <h3 className="text-base font-semibold text-text-0 font-sans mb-2">
71
+ Install Groove Network
72
+ </h3>
73
+ <p className="text-sm text-text-2 font-sans leading-relaxed mb-6">
74
+ The network package enables decentralized LLM inference. Contribute your compute power or run models across the Groove network.
75
+ </p>
76
+
77
+ <div className="w-full rounded-md border border-border-subtle bg-surface-1 px-4 py-3 mb-6">
78
+ <div className="text-2xs font-semibold text-text-3 font-sans uppercase tracking-wider mb-2 text-left">
79
+ Requirements
80
+ </div>
81
+ <ul className="flex flex-col gap-1.5">
82
+ {REQUIREMENTS.map((req) => (
83
+ <li key={req} className="flex items-center gap-2 text-xs font-sans text-text-1 text-left">
84
+ <Check size={12} className="text-accent flex-shrink-0" />
85
+ <span>{req}</span>
86
+ </li>
87
+ ))}
88
+ </ul>
89
+ </div>
90
+
91
+ {installing ? (
92
+ <InstallProgress progress={progress} />
93
+ ) : error ? (
94
+ <InstallError message={error} onRetry={() => installNetworkPackage()} />
95
+ ) : (
96
+ <>
97
+ <Button
98
+ variant="primary"
99
+ size="lg"
100
+ onClick={() => installNetworkPackage()}
101
+ className="w-full"
102
+ >
103
+ <Download size={14} />
104
+ Install Network Package
105
+ </Button>
106
+ <p className="text-2xs font-sans text-text-3 mt-3">
107
+ This will download and set up the Groove Network runtime (~500 MB)
108
+ </p>
109
+ </>
110
+ )}
111
+ </div>
112
+ </div>
113
+ );
114
+ }
115
+
116
+ function UninstallButton() {
117
+ const [open, setOpen] = useState(false);
118
+ const uninstallNetworkPackage = useGrooveStore((s) => s.uninstallNetworkPackage);
119
+ const [busy, setBusy] = useState(false);
120
+
121
+ const confirm = async () => {
122
+ setBusy(true);
123
+ try {
124
+ await uninstallNetworkPackage();
125
+ setOpen(false);
126
+ } catch { /* toast already shown */ }
127
+ finally { setBusy(false); }
128
+ };
129
+
130
+ return (
131
+ <Dialog open={open} onOpenChange={setOpen}>
132
+ <DialogTrigger asChild>
133
+ <button
134
+ type="button"
135
+ className="inline-flex items-center gap-1.5 text-2xs font-sans text-text-3 hover:text-danger transition-colors"
136
+ >
137
+ <Trash2 size={11} />
138
+ Uninstall Network Package
139
+ </button>
140
+ </DialogTrigger>
141
+ <DialogContent title="Uninstall Network Package" description="Confirm uninstall">
142
+ <div className="px-5 py-4 flex flex-col gap-3">
143
+ <p className="text-sm text-text-1 font-sans leading-relaxed">
144
+ This will stop your node and remove the network package from <span className="font-mono text-text-2">~/.groove/network</span>.
145
+ </p>
146
+ <p className="text-xs text-text-3 font-sans leading-relaxed">
147
+ Your identity (<span className="font-mono">~/.groove/node_key.json</span>) will be preserved — you can reinstall later without losing your wallet.
148
+ </p>
149
+ </div>
150
+ <div className="flex items-center justify-end gap-2 px-5 py-3 border-t border-border-subtle bg-surface-0">
151
+ <Button variant="ghost" size="sm" onClick={() => setOpen(false)} disabled={busy}>Cancel</Button>
152
+ <Button variant="danger" size="sm" onClick={confirm} disabled={busy}>
153
+ {busy ? <Loader2 size={12} className="animate-spin" /> : <Trash2 size={12} />}
154
+ Uninstall
155
+ </Button>
156
+ </div>
157
+ </DialogContent>
158
+ </Dialog>
159
+ );
160
+ }
161
+
162
+ export default function NetworkView() {
163
+ const fetchNetworkNodeStatus = useGrooveStore((s) => s.fetchNetworkNodeStatus);
164
+ const fetchNetworkStatus = useGrooveStore((s) => s.fetchNetworkStatus);
165
+ const node = useGrooveStore((s) => s.networkNode);
166
+ const installed = useGrooveStore((s) => s.networkInstalled);
167
+
168
+ useEffect(() => {
169
+ fetchNetworkNodeStatus();
170
+ if (installed) {
171
+ fetchNetworkStatus();
172
+ const interval = setInterval(() => { fetchNetworkStatus(); }, 10000);
173
+ return () => clearInterval(interval);
174
+ }
175
+ }, [fetchNetworkNodeStatus, fetchNetworkStatus, installed]);
176
+
177
+ return (
178
+ <div className="flex flex-col h-full">
179
+ {/* Header */}
180
+ <div className="flex items-center gap-3 px-4 py-2.5 bg-surface-1 border-b border-border flex-shrink-0">
181
+ <Globe size={14} className="text-accent" />
182
+ <h2 className="text-sm font-semibold text-text-0 font-sans">Groove Network</h2>
183
+ <Badge variant="purple">Early Access</Badge>
184
+ <div className="flex-1" />
185
+ {installed && (
186
+ <>
187
+ <UninstallButton />
188
+ <div className="flex items-center gap-1.5 text-2xs font-sans text-text-3">
189
+ <StatusDot status={node.active ? 'running' : 'crashed'} size="sm" />
190
+ {node.active ? 'Contributing' : 'Idle'}
191
+ </div>
192
+ </>
193
+ )}
194
+ </div>
195
+
196
+ {/* Body */}
197
+ <ScrollArea className="flex-1">
198
+ {!installed ? (
199
+ <InstallGate />
200
+ ) : (
201
+ <div className="p-4 grid grid-cols-1 xl:grid-cols-2 gap-4">
202
+ {/* Left column — node operator */}
203
+ <div className="flex flex-col gap-3 min-w-0">
204
+ <div>
205
+ <div className="flex items-center gap-2 mb-2 px-0.5">
206
+ <span className="text-2xs font-semibold text-text-3 font-sans uppercase tracking-wider">Node Operator</span>
207
+ <div className="flex-1 h-px bg-border-subtle" />
208
+ </div>
209
+ <NodeToggle />
210
+ </div>
211
+ <NodeDetails />
212
+ </div>
213
+
214
+ {/* Right column — network status */}
215
+ <div className="flex flex-col gap-3 min-w-0">
216
+ <div className="flex items-center gap-2 px-0.5">
217
+ <span className="text-2xs font-semibold text-text-3 font-sans uppercase tracking-wider">Network Status</span>
218
+ <div className="flex-1 h-px bg-border-subtle" />
219
+ </div>
220
+ <NetworkStatus />
221
+ </div>
222
+ </div>
223
+ )}
224
+ </ScrollArea>
225
+ </div>
226
+ );
227
+ }
@@ -15,7 +15,7 @@ import { fmtUptime } from '../lib/format';
15
15
  import {
16
16
  Key, Eye, EyeOff, Check, Cpu,
17
17
  FolderOpen, FolderSearch, Users, Gauge,
18
- ShieldCheck, Settings,
18
+ ShieldCheck, Settings, Lock,
19
19
  Newspaper, Radio, Send, MessageSquare, MessageCircle,
20
20
  Plus, Trash2, Plug, PlugZap, TestTube, X, HelpCircle, ExternalLink,
21
21
  } from 'lucide-react';
@@ -940,6 +940,91 @@ function AddGatewayCard({ existingTypes, onAdd }) {
940
940
  );
941
941
  }
942
942
 
943
+ /* ── Early Access Section ─────────────────────────────────── */
944
+
945
+ function EarlyAccessSection() {
946
+ const networkUnlocked = useGrooveStore((s) => s.networkUnlocked);
947
+ const activateBeta = useGrooveStore((s) => s.activateBeta);
948
+ const deactivateBeta = useGrooveStore((s) => s.deactivateBeta);
949
+ const [code, setCode] = useState('');
950
+ const [submitting, setSubmitting] = useState(false);
951
+ const [error, setError] = useState('');
952
+
953
+ useEffect(() => {
954
+ if (!error) return;
955
+ const t = setTimeout(() => setError(''), 3000);
956
+ return () => clearTimeout(t);
957
+ }, [error]);
958
+
959
+ async function handleSubmit() {
960
+ const trimmed = code.trim();
961
+ if (!trimmed || submitting) return;
962
+ setSubmitting(true);
963
+ setError('');
964
+ try {
965
+ await activateBeta(trimmed);
966
+ setCode('');
967
+ } catch (err) {
968
+ setError(err.message || 'Invalid code');
969
+ } finally {
970
+ setSubmitting(false);
971
+ }
972
+ }
973
+
974
+ async function handleDeactivate() {
975
+ try { await deactivateBeta(); } catch { /* toast handled in store */ }
976
+ }
977
+
978
+ return (
979
+ <div>
980
+ <div className="flex items-center gap-2 mb-2.5 px-0.5">
981
+ <span className="text-2xs font-semibold text-text-3 font-sans uppercase tracking-wider">Early Access</span>
982
+ <div className="flex-1 h-px bg-border-subtle" />
983
+ </div>
984
+ <div className="rounded-lg border border-border-subtle bg-surface-1 px-4 py-3.5 max-w-md">
985
+ {networkUnlocked ? (
986
+ <div className="flex items-center gap-2.5">
987
+ <div className="w-6 h-6 rounded-full bg-success/10 flex items-center justify-center flex-shrink-0">
988
+ <Check size={12} className="text-success" />
989
+ </div>
990
+ <div className="flex-1 text-xs font-sans text-text-1">Early access enabled</div>
991
+ <button
992
+ onClick={handleDeactivate}
993
+ className="text-2xs text-text-4 hover:text-danger cursor-pointer font-sans"
994
+ >
995
+ Deactivate
996
+ </button>
997
+ </div>
998
+ ) : (
999
+ <div className="flex items-center gap-2">
1000
+ <Lock size={12} className="text-text-4 flex-shrink-0" />
1001
+ <input
1002
+ value={code}
1003
+ onChange={(e) => setCode(e.target.value)}
1004
+ onKeyDown={(e) => e.key === 'Enter' && handleSubmit()}
1005
+ type="text"
1006
+ placeholder="Enter invite code"
1007
+ className="flex-1 h-8 px-2.5 text-xs bg-surface-0 border border-border rounded-md text-text-0 font-mono placeholder:text-text-4 focus:outline-none focus:ring-1 focus:ring-accent"
1008
+ />
1009
+ <Button
1010
+ variant="primary"
1011
+ size="sm"
1012
+ onClick={handleSubmit}
1013
+ disabled={!code.trim() || submitting}
1014
+ className="h-8 text-xs px-3"
1015
+ >
1016
+ {submitting ? '...' : 'Submit'}
1017
+ </Button>
1018
+ </div>
1019
+ )}
1020
+ {error && !networkUnlocked && (
1021
+ <div className="mt-2 text-2xs text-danger font-sans">{error}</div>
1022
+ )}
1023
+ </div>
1024
+ </div>
1025
+ );
1026
+ }
1027
+
943
1028
  /* ── Main Settings View ────────────────────────────────────── */
944
1029
 
945
1030
  export default function SettingsView() {
@@ -1200,6 +1285,8 @@ export default function SettingsView() {
1200
1285
  </div>
1201
1286
  )}
1202
1287
 
1288
+ {/* ═══════ EARLY ACCESS ═══════ */}
1289
+ <EarlyAccessSection />
1203
1290
 
1204
1291
  </div>
1205
1292
  </ScrollArea>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.27.42",
3
+ "version": "0.27.45",
4
4
  "description": "Open-source agent orchestration layer — the AI company OS. Local model agent engine (GGUF/Ollama/llama-server), HuggingFace model browser, MCP integrations (Slack, Gmail, Stripe, 15+), agent scheduling (cron), business roles (CMO, CFO, EA). GUI dashboard, multi-agent coordination, zero cold-start, infinite sessions. Works with Claude Code, Codex, Gemini CLI, Ollama, any local model.",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.27.42",
3
+ "version": "0.27.45",
4
4
  "description": "GROOVE CLI — manage AI coding agents from your terminal",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/daemon",
3
- "version": "0.27.42",
3
+ "version": "0.27.45",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",