groove-dev 0.27.73 → 0.27.74
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.
- package/CLAUDE.md +7 -0
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +2 -1
- package/node_modules/@groove-dev/daemon/src/providers/codex.js +3 -1
- package/node_modules/@groove-dev/daemon/src/providers/gemini.js +2 -1
- package/node_modules/@groove-dev/daemon/src/providers/index.js +21 -8
- package/node_modules/@groove-dev/gui/dist/assets/{index-Deza1S0i.js → index-DFP3r2yE.js} +31 -31
- package/node_modules/@groove-dev/gui/dist/assets/{index-BFc7Ov6v.css → index-QR7lyguO.css} +1 -1
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/views/settings.jsx +79 -9
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/providers/claude-code.js +2 -1
- package/packages/daemon/src/providers/codex.js +3 -1
- package/packages/daemon/src/providers/gemini.js +2 -1
- package/packages/daemon/src/providers/index.js +21 -8
- package/packages/gui/dist/assets/{index-Deza1S0i.js → index-DFP3r2yE.js} +31 -31
- package/packages/gui/dist/assets/{index-BFc7Ov6v.css → index-QR7lyguO.css} +1 -1
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/views/settings.jsx +79 -9
|
@@ -14,7 +14,7 @@ import { api } from '../lib/api';
|
|
|
14
14
|
import { cn } from '../lib/cn';
|
|
15
15
|
import { fmtUptime } from '../lib/format';
|
|
16
16
|
import {
|
|
17
|
-
Key, Eye, EyeOff, Check, Cpu, Download, Loader2,
|
|
17
|
+
Key, Eye, EyeOff, Check, Cpu, Download, Loader2, RefreshCw, Terminal, Copy,
|
|
18
18
|
FolderOpen, FolderSearch, Users, Gauge, ChevronRight,
|
|
19
19
|
ShieldCheck, Settings, Lock,
|
|
20
20
|
Newspaper, Radio, Send, MessageSquare, MessageCircle,
|
|
@@ -62,6 +62,9 @@ function ProviderCard({ provider, onKeyChange }) {
|
|
|
62
62
|
const installProgress = useGrooveStore((s) => s.providerInstallProgress[provider.id]);
|
|
63
63
|
const loginProvider = useGrooveStore((s) => s.loginProvider);
|
|
64
64
|
const setProviderPath = useGrooveStore((s) => s.setProviderPath);
|
|
65
|
+
const verifyProvider = useGrooveStore((s) => s.verifyProvider);
|
|
66
|
+
const installProvider = useGrooveStore((s) => s.installProvider);
|
|
67
|
+
const [checking, setChecking] = useState(false);
|
|
65
68
|
|
|
66
69
|
const isLocal = provider.authType === 'local';
|
|
67
70
|
const isSubscription = provider.authType === 'subscription';
|
|
@@ -221,20 +224,87 @@ function ProviderCard({ provider, onKeyChange }) {
|
|
|
221
224
|
</div>
|
|
222
225
|
)}
|
|
223
226
|
|
|
224
|
-
{/* Not installed
|
|
227
|
+
{/* Not installed */}
|
|
225
228
|
{!provider.installed && !isInstalling && !settingKey && (
|
|
226
|
-
<div className="flex flex-col
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
229
|
+
<div className="flex flex-col gap-2.5 flex-1">
|
|
230
|
+
{/* Install error from last attempt */}
|
|
231
|
+
{installProgress?.error && (
|
|
232
|
+
<div className="p-2.5 bg-danger/5 border border-danger/15 rounded-md">
|
|
233
|
+
<p className="text-2xs text-danger font-sans break-all">{installProgress.error}</p>
|
|
234
|
+
</div>
|
|
235
|
+
)}
|
|
236
|
+
|
|
237
|
+
{/* Auto-install button */}
|
|
230
238
|
<Button
|
|
231
239
|
variant="primary"
|
|
232
240
|
size="sm"
|
|
233
|
-
onClick={() =>
|
|
234
|
-
className="h-8
|
|
241
|
+
onClick={() => installProvider(provider.id).catch(() => {})}
|
|
242
|
+
className="w-full h-8 text-2xs gap-1.5"
|
|
235
243
|
>
|
|
236
|
-
<Download size={
|
|
244
|
+
<Download size={11} /> Install {provider.name}
|
|
237
245
|
</Button>
|
|
246
|
+
|
|
247
|
+
{/* Manual install command */}
|
|
248
|
+
{provider.installCommand && (
|
|
249
|
+
<div className="space-y-1">
|
|
250
|
+
<p className="text-2xs text-text-4 font-sans">Or install manually in your terminal:</p>
|
|
251
|
+
<div className="flex items-center gap-1">
|
|
252
|
+
<code className="flex-1 px-2 py-1.5 bg-surface-0 border border-border-subtle rounded text-2xs font-mono text-text-2 select-all">
|
|
253
|
+
{provider.installCommand}
|
|
254
|
+
</code>
|
|
255
|
+
<button
|
|
256
|
+
onClick={() => { navigator.clipboard.writeText(provider.installCommand); addToast('success', 'Copied'); }}
|
|
257
|
+
className="p-1.5 text-text-4 hover:text-text-2 cursor-pointer"
|
|
258
|
+
>
|
|
259
|
+
<Copy size={10} />
|
|
260
|
+
</button>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
)}
|
|
264
|
+
|
|
265
|
+
{/* Re-check + custom path */}
|
|
266
|
+
<div className="flex items-center gap-2 pt-1">
|
|
267
|
+
<Button
|
|
268
|
+
variant="ghost"
|
|
269
|
+
size="sm"
|
|
270
|
+
onClick={async () => {
|
|
271
|
+
setChecking(true);
|
|
272
|
+
try {
|
|
273
|
+
await verifyProvider(provider.id);
|
|
274
|
+
if (onKeyChange) onKeyChange();
|
|
275
|
+
} catch { /* handled in store */ }
|
|
276
|
+
setChecking(false);
|
|
277
|
+
}}
|
|
278
|
+
disabled={checking}
|
|
279
|
+
className="h-7 text-2xs gap-1 px-2"
|
|
280
|
+
>
|
|
281
|
+
<RefreshCw size={10} className={checking ? 'animate-spin' : ''} /> Re-check
|
|
282
|
+
</Button>
|
|
283
|
+
<button
|
|
284
|
+
onClick={() => setCustomPathOpen(!customPathOpen)}
|
|
285
|
+
className="text-2xs text-text-4 hover:text-accent cursor-pointer font-sans"
|
|
286
|
+
>
|
|
287
|
+
Set custom path
|
|
288
|
+
</button>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
{/* Custom path input (shown for not-installed too) */}
|
|
292
|
+
{customPathOpen && (
|
|
293
|
+
<div className="space-y-2">
|
|
294
|
+
<div className="flex gap-2">
|
|
295
|
+
<input
|
|
296
|
+
value={customPath}
|
|
297
|
+
onChange={(e) => setCustomPath(e.target.value)}
|
|
298
|
+
onKeyDown={(e) => e.key === 'Enter' && handleSavePath()}
|
|
299
|
+
placeholder={`/path/to/${provider.id}`}
|
|
300
|
+
className="flex-1 h-7 px-2 text-2xs bg-surface-0 border border-border-subtle rounded-md text-text-0 font-mono placeholder:text-text-4 focus:outline-none focus:ring-1 focus:ring-accent"
|
|
301
|
+
/>
|
|
302
|
+
<Button variant="primary" size="sm" onClick={handleSavePath} disabled={!customPath.trim() || savingPath} className="h-7 text-2xs px-2.5">
|
|
303
|
+
{savingPath ? '...' : 'Save'}
|
|
304
|
+
</Button>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
)}
|
|
238
308
|
</div>
|
|
239
309
|
)}
|
|
240
310
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "groove-dev",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.74",
|
|
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)",
|
|
@@ -46,7 +46,8 @@ export class ClaudeCodeProvider extends Provider {
|
|
|
46
46
|
|
|
47
47
|
static isInstalled() {
|
|
48
48
|
try {
|
|
49
|
-
|
|
49
|
+
const cmd = process.platform === 'win32' ? 'where claude' : 'which claude';
|
|
50
|
+
execSync(cmd, { stdio: 'ignore' });
|
|
50
51
|
return true;
|
|
51
52
|
} catch {
|
|
52
53
|
return false;
|
|
@@ -36,6 +36,7 @@ export class CodexProvider extends Provider {
|
|
|
36
36
|
// Auth hint — Codex uses its own auth system, not just env vars
|
|
37
37
|
static authHint = 'Codex requires `codex login` — run: echo "YOUR_KEY" | codex login --with-api-key';
|
|
38
38
|
static models = [
|
|
39
|
+
{ id: 'gpt-5.5', name: 'GPT-5.5', tier: 'heavy', maxContext: 200000, pricing: { input: 0.03, output: 0.12 } },
|
|
39
40
|
{ id: 'gpt-5.4-pro', name: 'GPT-5.4 Pro', tier: 'heavy', maxContext: 200000, pricing: { input: 0.015, output: 0.06 } },
|
|
40
41
|
{ id: 'gpt-5.4', name: 'GPT-5.4', tier: 'heavy', maxContext: 200000, pricing: { input: 0.005, output: 0.02 } },
|
|
41
42
|
{ id: 'gpt-5.4-mini', name: 'GPT-5.4 Mini', tier: 'medium', maxContext: 200000, pricing: { input: 0.001, output: 0.004 } },
|
|
@@ -46,7 +47,8 @@ export class CodexProvider extends Provider {
|
|
|
46
47
|
|
|
47
48
|
static isInstalled() {
|
|
48
49
|
try {
|
|
49
|
-
|
|
50
|
+
const cmd = process.platform === 'win32' ? 'where codex' : 'which codex';
|
|
51
|
+
execSync(cmd, { stdio: 'ignore' });
|
|
50
52
|
return true;
|
|
51
53
|
} catch {
|
|
52
54
|
return false;
|
|
@@ -40,7 +40,8 @@ export class GeminiProvider extends Provider {
|
|
|
40
40
|
|
|
41
41
|
static isInstalled() {
|
|
42
42
|
try {
|
|
43
|
-
|
|
43
|
+
const cmd = process.platform === 'win32' ? 'where gemini' : 'which gemini';
|
|
44
|
+
execSync(cmd, { stdio: 'ignore' });
|
|
44
45
|
return true;
|
|
45
46
|
} catch {
|
|
46
47
|
return false;
|
|
@@ -37,17 +37,30 @@ export function getProviderPath(id) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
(function augmentPath() {
|
|
40
|
-
const
|
|
40
|
+
const isWin = process.platform === 'win32';
|
|
41
|
+
const extra = isWin ? [] : ['/usr/local/bin', '/opt/homebrew/bin'];
|
|
41
42
|
try {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
43
|
+
const suppressErr = isWin ? '2>NUL' : '2>/dev/null';
|
|
44
|
+
const npmPrefix = execSync(`npm config get prefix ${suppressErr}`, { encoding: 'utf8', timeout: 5000 }).trim();
|
|
45
|
+
if (npmPrefix) {
|
|
46
|
+
extra.push(isWin ? npmPrefix : `${npmPrefix}/bin`);
|
|
47
|
+
}
|
|
45
48
|
} catch { /* npm itself may not be in PATH yet */ }
|
|
46
|
-
const home = process.env.HOME || '';
|
|
47
|
-
if (home)
|
|
49
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
50
|
+
if (home) {
|
|
51
|
+
if (isWin) {
|
|
52
|
+
extra.push(`${home}\\AppData\\Roaming\\npm`);
|
|
53
|
+
} else {
|
|
54
|
+
extra.push(`${home}/.npm-global/bin`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (isWin) {
|
|
58
|
+
const pf = process.env.ProgramFiles || 'C:\\Program Files';
|
|
59
|
+
extra.push(`${pf}\\nodejs`);
|
|
60
|
+
}
|
|
48
61
|
const cur = process.env.PATH || '';
|
|
49
|
-
const toAdd = extra.filter(p => p && !cur.split(
|
|
50
|
-
if (toAdd.length) process.env.PATH = [...toAdd, cur].join(
|
|
62
|
+
const toAdd = extra.filter(p => p && !cur.split(pathDelimiter).includes(p));
|
|
63
|
+
if (toAdd.length) process.env.PATH = [...toAdd, cur].join(pathDelimiter);
|
|
51
64
|
})();
|
|
52
65
|
|
|
53
66
|
const providers = {
|