groove-dev 0.27.91 → 0.27.93
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/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/api.js +228 -3
- package/node_modules/@groove-dev/daemon/src/introducer.js +42 -0
- package/node_modules/@groove-dev/daemon/src/process.js +5 -1
- package/node_modules/@groove-dev/daemon/src/providers/base.js +4 -0
- package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +8 -0
- package/node_modules/@groove-dev/daemon/src/providers/codex.js +33 -4
- package/node_modules/@groove-dev/daemon/src/providers/gemini.js +14 -1
- package/node_modules/@groove-dev/daemon/src/providers/grok.js +8 -1
- package/node_modules/@groove-dev/daemon/src/providers/local.js +8 -1
- package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +74 -5
- package/node_modules/@groove-dev/daemon/src/validate.js +22 -1
- package/node_modules/@groove-dev/gui/dist/assets/{codemirror-BBL3i_JW.js → codemirror-CFF1Lrnz.js} +10 -10
- package/node_modules/@groove-dev/gui/dist/assets/index-Bo6AeNmM.css +1 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-VB4_k5Pz.js +8653 -0
- package/node_modules/@groove-dev/gui/dist/index.html +3 -3
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +26 -44
- package/node_modules/@groove-dev/gui/src/components/agents/agent-file-tree.jsx +29 -28
- package/node_modules/@groove-dev/gui/src/components/agents/workspace-mode.jsx +53 -143
- package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +3 -30
- package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +163 -153
- package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +15 -5
- package/node_modules/@groove-dev/gui/src/components/chat/conversation-list.jsx +26 -17
- package/node_modules/@groove-dev/gui/src/components/editor/code-editor.jsx +32 -26
- package/node_modules/@groove-dev/gui/src/components/settings/quick-connect.jsx +5 -1
- package/node_modules/@groove-dev/gui/src/components/settings/remote-server-card.jsx +9 -5
- package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +5 -1
- package/node_modules/@groove-dev/gui/src/components/ui/slider.jsx +50 -0
- package/node_modules/@groove-dev/gui/src/stores/groove.js +151 -12
- package/node_modules/@groove-dev/gui/src/views/agents.jsx +720 -38
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +228 -3
- package/packages/daemon/src/introducer.js +42 -0
- package/packages/daemon/src/process.js +5 -1
- package/packages/daemon/src/providers/base.js +4 -0
- package/packages/daemon/src/providers/claude-code.js +8 -0
- package/packages/daemon/src/providers/codex.js +33 -4
- package/packages/daemon/src/providers/gemini.js +14 -1
- package/packages/daemon/src/providers/grok.js +8 -1
- package/packages/daemon/src/providers/local.js +8 -1
- package/packages/daemon/src/tunnel-manager.js +74 -5
- package/packages/daemon/src/validate.js +22 -1
- package/packages/gui/dist/assets/{codemirror-BBL3i_JW.js → codemirror-CFF1Lrnz.js} +10 -10
- package/packages/gui/dist/assets/index-Bo6AeNmM.css +1 -0
- package/packages/gui/dist/assets/index-VB4_k5Pz.js +8653 -0
- package/packages/gui/dist/index.html +3 -3
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/agent-chat.jsx +26 -44
- package/packages/gui/src/components/agents/agent-file-tree.jsx +29 -28
- package/packages/gui/src/components/agents/workspace-mode.jsx +53 -143
- package/packages/gui/src/components/chat/chat-header.jsx +3 -30
- package/packages/gui/src/components/chat/chat-input.jsx +163 -153
- package/packages/gui/src/components/chat/chat-view.jsx +15 -5
- package/packages/gui/src/components/chat/conversation-list.jsx +26 -17
- package/packages/gui/src/components/editor/code-editor.jsx +32 -26
- package/packages/gui/src/components/settings/quick-connect.jsx +5 -1
- package/packages/gui/src/components/settings/remote-server-card.jsx +9 -5
- package/packages/gui/src/components/settings/ssh-wizard.jsx +5 -1
- package/packages/gui/src/components/ui/slider.jsx +50 -0
- package/packages/gui/src/stores/groove.js +151 -12
- package/packages/gui/src/views/agents.jsx +720 -38
- package/workspace.png +0 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-D4vJ_1ET.css +0 -1
- package/node_modules/@groove-dev/gui/dist/assets/index-MLIZRMj1.js +0 -8642
- package/packages/gui/dist/assets/index-D4vJ_1ET.css +0 -1
- package/packages/gui/dist/assets/index-MLIZRMj1.js +0 -8642
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
import { cn } from '../../lib/cn';
|
|
3
|
+
|
|
4
|
+
export function TuningSlider({
|
|
5
|
+
label, value, onChange, min = 0, max = 100, step = 1,
|
|
6
|
+
formatValue, displayValue, disabled, className,
|
|
7
|
+
}) {
|
|
8
|
+
const pct = ((value - min) / (max - min)) * 100;
|
|
9
|
+
const fmt = displayValue || formatValue;
|
|
10
|
+
const display = typeof fmt === 'function' ? fmt(value) : (typeof fmt === 'string' ? fmt : value);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={cn('flex items-center gap-3 h-10', disabled && 'opacity-40 pointer-events-none', className)}>
|
|
14
|
+
<span className="text-xs text-text-2 font-sans w-28 shrink-0">{label}</span>
|
|
15
|
+
<span className="text-2xs text-text-4 font-mono w-6 text-right shrink-0">{min}</span>
|
|
16
|
+
<div className="relative flex-1 flex items-center group">
|
|
17
|
+
<div className="absolute inset-y-0 flex items-center w-full pointer-events-none">
|
|
18
|
+
<div className="w-full h-1.5 rounded-full bg-surface-5 overflow-hidden">
|
|
19
|
+
<div
|
|
20
|
+
className="h-full rounded-full bg-accent transition-all"
|
|
21
|
+
style={{ width: `${pct}%` }}
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<input
|
|
26
|
+
type="range"
|
|
27
|
+
min={min}
|
|
28
|
+
max={max}
|
|
29
|
+
step={step}
|
|
30
|
+
value={value}
|
|
31
|
+
disabled={disabled}
|
|
32
|
+
onChange={(e) => onChange(Number(e.target.value))}
|
|
33
|
+
className="relative w-full h-4 appearance-none bg-transparent cursor-pointer
|
|
34
|
+
[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4
|
|
35
|
+
[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-accent [&::-webkit-slider-thumb]:border-2
|
|
36
|
+
[&::-webkit-slider-thumb]:border-surface-1 [&::-webkit-slider-thumb]:shadow-[0_0_6px_rgba(51,175,188,0.4)]
|
|
37
|
+
[&::-webkit-slider-thumb]:hover:shadow-[0_0_10px_rgba(51,175,188,0.6)]
|
|
38
|
+
[&::-webkit-slider-thumb]:transition-shadow
|
|
39
|
+
[&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:rounded-full
|
|
40
|
+
[&::-moz-range-thumb]:bg-accent [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-surface-1
|
|
41
|
+
[&::-moz-range-thumb]:shadow-[0_0_6px_rgba(51,175,188,0.4)]
|
|
42
|
+
[&::-moz-range-track]:bg-transparent
|
|
43
|
+
disabled:cursor-not-allowed"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
<span className="text-2xs text-text-4 font-mono w-6 shrink-0">{max}</span>
|
|
47
|
+
<span className="text-xs text-accent font-mono font-semibold w-10 text-right shrink-0">{display}</span>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -62,6 +62,17 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
62
62
|
previewChat: [],
|
|
63
63
|
previewIterating: false,
|
|
64
64
|
|
|
65
|
+
// ── Team Launch Config (set during planner spawn, cascades to team) ──
|
|
66
|
+
teamLaunchConfig: null, // { provider, model, reasoningEffort, temperature, verbosity }
|
|
67
|
+
|
|
68
|
+
// ── Team Builder ──────────────────────────────────────────
|
|
69
|
+
teamBuilderOpen: false,
|
|
70
|
+
teamBuilderRoles: [],
|
|
71
|
+
teamBuilderSettings: { provider: null, model: null, reasoningEffort: 50, temperature: 0.5 },
|
|
72
|
+
teamBuilderTask: '',
|
|
73
|
+
teamBuilderLaunchMode: 'plan',
|
|
74
|
+
teamTemplates: { builtIn: [], custom: [] },
|
|
75
|
+
|
|
65
76
|
// ── Navigation ────────────────────────────────────────────
|
|
66
77
|
activeView: 'agents', // 'agents' | 'editor' | 'dashboard' | 'marketplace' | 'teams' | 'settings' | 'preview'
|
|
67
78
|
detailPanel: null, // null | { type: 'agent', agentId } | { type: 'spawn' } | { type: 'journalist' }
|
|
@@ -428,6 +439,19 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
428
439
|
set({ activityLog: log });
|
|
429
440
|
persistJSON('groove:activityLog', log);
|
|
430
441
|
}
|
|
442
|
+
|
|
443
|
+
// Open-on-write: auto-open files the agent writes in workspace mode
|
|
444
|
+
if (get().workspaceMode && Array.isArray(data.data)) {
|
|
445
|
+
const WRITE_TOOLS = new Set(['Write', 'Edit', 'write_file', 'edit_file', 'create_file']);
|
|
446
|
+
for (const block of data.data) {
|
|
447
|
+
if (block.type !== 'tool_use' || !WRITE_TOOLS.has(block.name)) continue;
|
|
448
|
+
const filePath = block.input?.file_path || block.input?.path;
|
|
449
|
+
if (filePath && agentId === get().workspaceAgentId) {
|
|
450
|
+
const relPath = filePath.replace(/^\/[^/]+.*?\/groove\//, '');
|
|
451
|
+
get().openFile(relPath);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
431
455
|
break;
|
|
432
456
|
}
|
|
433
457
|
|
|
@@ -1537,9 +1561,18 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
1537
1561
|
async launchRecommendedTeam(modifiedAgents) {
|
|
1538
1562
|
try {
|
|
1539
1563
|
const teamId = get().recommendedTeam?.teamId || null;
|
|
1564
|
+
const tlc = get().teamLaunchConfig;
|
|
1540
1565
|
set({ recommendedTeam: null }); // Dismiss modal immediately
|
|
1541
1566
|
get().addToast('info', 'Launching team...');
|
|
1542
|
-
const body = {
|
|
1567
|
+
const body = {
|
|
1568
|
+
...(modifiedAgents && { agents: modifiedAgents }),
|
|
1569
|
+
...(teamId && { teamId }),
|
|
1570
|
+
...(tlc?.provider && { teamProvider: tlc.provider }),
|
|
1571
|
+
...(tlc?.model && { teamModel: tlc.model }),
|
|
1572
|
+
...(tlc?.reasoningEffort != null && { teamReasoningEffort: tlc.reasoningEffort }),
|
|
1573
|
+
...(tlc?.temperature != null && { teamTemperature: tlc.temperature }),
|
|
1574
|
+
...(tlc?.verbosity != null && { teamVerbosity: tlc.verbosity }),
|
|
1575
|
+
};
|
|
1543
1576
|
const result = await api.post('/recommended-team/launch', body);
|
|
1544
1577
|
const totalOk = (result.launched || 0) + (result.reused || 0);
|
|
1545
1578
|
const failures = result.failed || [];
|
|
@@ -1577,6 +1610,104 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
1577
1610
|
}
|
|
1578
1611
|
},
|
|
1579
1612
|
|
|
1613
|
+
// ── Team Builder ──────────────────────────────────────────
|
|
1614
|
+
|
|
1615
|
+
openTeamBuilder() { set({ teamBuilderOpen: true }); },
|
|
1616
|
+
closeTeamBuilder() {
|
|
1617
|
+
set({
|
|
1618
|
+
teamBuilderOpen: false,
|
|
1619
|
+
teamBuilderRoles: [],
|
|
1620
|
+
teamBuilderSettings: { provider: null, model: null, reasoningEffort: 50, temperature: 0.5 },
|
|
1621
|
+
teamBuilderTask: '',
|
|
1622
|
+
teamBuilderLaunchMode: 'plan',
|
|
1623
|
+
});
|
|
1624
|
+
},
|
|
1625
|
+
addTeamBuilderRole(role) {
|
|
1626
|
+
set((s) => ({
|
|
1627
|
+
teamBuilderRoles: [...s.teamBuilderRoles, {
|
|
1628
|
+
role, name: '', provider: null, model: null,
|
|
1629
|
+
reasoningEffort: null, temperature: null, prompt: '',
|
|
1630
|
+
}],
|
|
1631
|
+
}));
|
|
1632
|
+
},
|
|
1633
|
+
removeTeamBuilderRole(index) {
|
|
1634
|
+
set((s) => ({ teamBuilderRoles: s.teamBuilderRoles.filter((_, i) => i !== index) }));
|
|
1635
|
+
},
|
|
1636
|
+
updateTeamBuilderRole(index, updates) {
|
|
1637
|
+
set((s) => ({
|
|
1638
|
+
teamBuilderRoles: s.teamBuilderRoles.map((r, i) => i === index ? { ...r, ...updates } : r),
|
|
1639
|
+
}));
|
|
1640
|
+
},
|
|
1641
|
+
applyTemplate(template) {
|
|
1642
|
+
set({
|
|
1643
|
+
teamBuilderRoles: (template.roles || []).map((r) => ({
|
|
1644
|
+
role: typeof r === 'string' ? r : r.role,
|
|
1645
|
+
name: '', provider: null, model: null,
|
|
1646
|
+
reasoningEffort: null, temperature: null, prompt: '',
|
|
1647
|
+
})),
|
|
1648
|
+
});
|
|
1649
|
+
},
|
|
1650
|
+
setTeamBuilderSettings(settings) {
|
|
1651
|
+
set((s) => ({ teamBuilderSettings: { ...s.teamBuilderSettings, ...settings } }));
|
|
1652
|
+
},
|
|
1653
|
+
setTeamBuilderTask(task) { set({ teamBuilderTask: task }); },
|
|
1654
|
+
setTeamBuilderLaunchMode(mode) { set({ teamBuilderLaunchMode: mode }); },
|
|
1655
|
+
|
|
1656
|
+
async fetchTeamTemplates() {
|
|
1657
|
+
try {
|
|
1658
|
+
const data = await api.get('/team-templates');
|
|
1659
|
+
set({ teamTemplates: data });
|
|
1660
|
+
} catch { /* endpoint may not exist yet */ }
|
|
1661
|
+
},
|
|
1662
|
+
|
|
1663
|
+
async saveTeamTemplate(name) {
|
|
1664
|
+
try {
|
|
1665
|
+
const { teamBuilderRoles, teamBuilderSettings } = get();
|
|
1666
|
+
await api.post('/team-templates', {
|
|
1667
|
+
name,
|
|
1668
|
+
roles: teamBuilderRoles.map((r) => r.role),
|
|
1669
|
+
settings: teamBuilderSettings,
|
|
1670
|
+
});
|
|
1671
|
+
get().addToast('success', `Template "${name}" saved`);
|
|
1672
|
+
get().fetchTeamTemplates();
|
|
1673
|
+
} catch (err) {
|
|
1674
|
+
get().addToast('error', 'Failed to save template', err.message);
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
|
|
1678
|
+
async deleteTeamTemplate(name) {
|
|
1679
|
+
try {
|
|
1680
|
+
await api.delete(`/team-templates/${encodeURIComponent(name)}`);
|
|
1681
|
+
get().addToast('info', `Template "${name}" deleted`);
|
|
1682
|
+
get().fetchTeamTemplates();
|
|
1683
|
+
} catch (err) {
|
|
1684
|
+
get().addToast('error', 'Failed to delete template', err.message);
|
|
1685
|
+
}
|
|
1686
|
+
},
|
|
1687
|
+
|
|
1688
|
+
async launchTeamBuilder() {
|
|
1689
|
+
const { teamBuilderRoles, teamBuilderSettings, teamBuilderTask, teamBuilderLaunchMode, activeTeamId } = get();
|
|
1690
|
+
if (teamBuilderRoles.length === 0) return;
|
|
1691
|
+
try {
|
|
1692
|
+
get().addToast('info', 'Launching team...');
|
|
1693
|
+
const body = {
|
|
1694
|
+
task: teamBuilderTask,
|
|
1695
|
+
roles: teamBuilderRoles,
|
|
1696
|
+
settings: teamBuilderSettings,
|
|
1697
|
+
launchMode: teamBuilderLaunchMode,
|
|
1698
|
+
teamId: activeTeamId,
|
|
1699
|
+
};
|
|
1700
|
+
const result = await api.post('/team-builder/launch', body);
|
|
1701
|
+
const count = result.launched || result.agents?.length || 0;
|
|
1702
|
+
get().addToast('success', `Launched ${count} agent${count !== 1 ? 's' : ''}`);
|
|
1703
|
+
get().closeTeamBuilder();
|
|
1704
|
+
return result;
|
|
1705
|
+
} catch (err) {
|
|
1706
|
+
get().addToast('error', 'Team launch failed', err.message);
|
|
1707
|
+
throw err;
|
|
1708
|
+
}
|
|
1709
|
+
},
|
|
1710
|
+
|
|
1580
1711
|
// ── GitHub Repo Import ────────────────────────────────────
|
|
1581
1712
|
|
|
1582
1713
|
async fetchImportedRepos() {
|
|
@@ -1946,10 +2077,13 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
1946
2077
|
get().addChatMessage(id, 'user', message, false);
|
|
1947
2078
|
set((s) => ({ thinkingAgents: new Set([...s.thinkingAgents, id]) }));
|
|
1948
2079
|
|
|
1949
|
-
//
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
2080
|
+
// Auto-attach active file context when in workspace mode
|
|
2081
|
+
let enriched = message;
|
|
2082
|
+
if (get().workspaceMode && get().workspaceAgentId === id && get().editorActiveFile) {
|
|
2083
|
+
const filePath = get().editorActiveFile;
|
|
2084
|
+
enriched = `[Active file: ${filePath}]\n\n${message}`;
|
|
2085
|
+
}
|
|
2086
|
+
|
|
1953
2087
|
const snapshot = {
|
|
1954
2088
|
chatHistory: [...(get().chatHistory[id] || [])],
|
|
1955
2089
|
activityLog: [...(get().activityLog[id] || [])],
|
|
@@ -1957,7 +2091,7 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
1957
2091
|
};
|
|
1958
2092
|
|
|
1959
2093
|
try {
|
|
1960
|
-
const data = await api.post(`/agents/${encodeURIComponent(id)}/instruct`, { message });
|
|
2094
|
+
const data = await api.post(`/agents/${encodeURIComponent(id)}/instruct`, { message: enriched });
|
|
1961
2095
|
|
|
1962
2096
|
if (data.status === 'message_sent') {
|
|
1963
2097
|
return data;
|
|
@@ -2364,18 +2498,23 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
2364
2498
|
set({ workspaceMode: on });
|
|
2365
2499
|
localStorage.setItem('groove:workspaceMode', String(on));
|
|
2366
2500
|
if (on) {
|
|
2367
|
-
get().closeDetail();
|
|
2368
|
-
}
|
|
2369
|
-
if (on && !get().workspaceAgentId) {
|
|
2370
2501
|
const teamAgents = get().agents.filter((a) => a.teamId === get().activeTeamId);
|
|
2371
|
-
const
|
|
2372
|
-
const
|
|
2373
|
-
|
|
2502
|
+
const current = get().workspaceAgentId;
|
|
2503
|
+
const belongsToTeam = current && teamAgents.some((a) => a.id === current);
|
|
2504
|
+
if (!belongsToTeam) {
|
|
2505
|
+
const selected = get().detailPanel?.type === 'agent' ? get().detailPanel.agentId : null;
|
|
2506
|
+
const selectedInTeam = selected && teamAgents.some((a) => a.id === selected);
|
|
2507
|
+
const running = teamAgents.find((a) => a.status === 'running');
|
|
2508
|
+
set({ workspaceAgentId: (selectedInTeam ? selected : null) || running?.id || teamAgents[0]?.id || null });
|
|
2509
|
+
}
|
|
2510
|
+
const agentId = get().workspaceAgentId;
|
|
2511
|
+
if (agentId) get().selectAgent(agentId);
|
|
2374
2512
|
}
|
|
2375
2513
|
},
|
|
2376
2514
|
|
|
2377
2515
|
setWorkspaceAgent(id) {
|
|
2378
2516
|
set({ workspaceAgentId: id });
|
|
2517
|
+
if (id) get().selectAgent(id);
|
|
2379
2518
|
},
|
|
2380
2519
|
|
|
2381
2520
|
captureSnapshot(path, content) {
|