groove-dev 0.26.30 → 0.26.32

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.
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" type="image/png" href="/favicon.png" />
7
7
  <title>Groove GUI</title>
8
- <script type="module" crossorigin src="/assets/index-vxioP1y2.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CwUZRfEx.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/vendor-C0HXlhrU.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/reactflow-BQPfi37R.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/codemirror-BBL3i_JW.js">
@@ -4,6 +4,7 @@ import { ChevronDown, ChevronRight } from 'lucide-react';
4
4
  import { fmtNum, fmtDollar } from '../../lib/format';
5
5
  import { cn } from '../../lib/cn';
6
6
  import { statusColor, roleColor } from '../../lib/status';
7
+ import { HEX, hexAlpha } from '../../lib/theme-hex';
7
8
  import { ScrollArea } from '../ui/scroll-area';
8
9
 
9
10
  const COST_SOURCE_LABEL = { actual: 'ACT', estimated: 'EST', local: 'LOC' };
@@ -24,7 +25,7 @@ const AgentRow = memo(function AgentRow({ agent, isRotating }) {
24
25
  const successRate = quality?.toolSuccessRate != null ? Math.round(quality.toolSuccessRate * 100) : null;
25
26
  const thresholdPct = agent.rotationThreshold ? Math.round(agent.rotationThreshold * 100) : null;
26
27
  const rc = roleColor(agent.role);
27
- const barColor = contextPct > 80 ? '#e06c75' : contextPct > 60 ? '#e5c07b' : isAlive ? '#33afbc' : '#333842';
28
+ const barColor = contextPct > 80 ? HEX.danger : contextPct > 60 ? HEX.warning : isAlive ? HEX.accent : HEX.surface5;
28
29
 
29
30
  return (
30
31
  <div className="px-3 pl-6 py-2 hover:bg-[rgba(51,175,188,0.06)] transition-colors space-y-1.5">
@@ -94,7 +95,7 @@ const AgentRow = memo(function AgentRow({ agent, isRotating }) {
94
95
  <div className="flex items-center gap-2">
95
96
  <div
96
97
  className="relative flex-1 h-[4px] rounded-full overflow-visible"
97
- style={{ background: 'rgba(51,175,188,0.12)' }}
98
+ style={{ background: hexAlpha(HEX.accent, 0.12) }}
98
99
  >
99
100
  <div
100
101
  className="absolute inset-y-0 left-0 rounded-full transition-all duration-700"
@@ -103,7 +104,7 @@ const AgentRow = memo(function AgentRow({ agent, isRotating }) {
103
104
  {thresholdPct && (
104
105
  <div
105
106
  className="absolute top-[-2px] w-px h-[8px]"
106
- style={{ left: `${thresholdPct}%`, background: '#c678dd' }}
107
+ style={{ left: `${thresholdPct}%`, background: HEX.purple }}
107
108
  title={`Rotation at ${thresholdPct}%`}
108
109
  />
109
110
  )}
@@ -126,7 +127,7 @@ function TeamSection({ team, members, rotatingSet }) {
126
127
  <button
127
128
  onClick={() => setExpanded((e) => !e)}
128
129
  className="w-full flex items-center gap-2 px-3 py-1.5 text-left transition-colors hover:bg-[rgba(51,175,188,0.08)] bg-[rgba(51,175,188,0.05)]"
129
- style={{ borderLeft: isActive ? '2px solid #33afbc' : '2px solid transparent' }}
130
+ style={{ borderLeft: isActive ? `2px solid ${HEX.accent}` : '2px solid transparent' }}
130
131
  >
131
132
  {expanded
132
133
  ? <ChevronDown size={10} className="text-text-4 flex-shrink-0" />
@@ -141,7 +142,7 @@ function TeamSection({ team, members, rotatingSet }) {
141
142
  )}
142
143
  <span
143
144
  className="text-2xs font-mono tabular-nums flex-shrink-0 ml-1.5"
144
- style={{ color: isActive ? '#33afbc' : undefined }}
145
+ style={{ color: isActive ? HEX.accent : undefined }}
145
146
  >
146
147
  {runningCount}/{members.length}
147
148
  </span>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.26.30",
3
+ "version": "0.26.32",
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)",
@@ -1822,14 +1822,35 @@ Keep responses concise. Help them think, don't lecture them about the system the
1822
1822
  );
1823
1823
 
1824
1824
  if (existing && prompt) {
1825
- // Instruct the existing agent instead of spawning a new one
1825
+ // Reuse existing agent: kill the old process and spawn fresh with full context.
1826
+ // This ensures the agent gets intro context, project map, and design system —
1827
+ // resume() bypasses all of that and the agent spawns blind.
1826
1828
  try {
1827
- const newAgent = await daemon.processes.resume(existing.id, prompt);
1829
+ // Kill old process if running
1830
+ if (existing.status === 'running' || existing.status === 'starting') {
1831
+ try { await daemon.processes.kill(existing.id); } catch { /* already dead */ }
1832
+ }
1833
+ // Remove old entry
1834
+ daemon.registry.remove(existing.id);
1835
+ daemon.locks.release(existing.id);
1836
+
1837
+ // Spawn fresh with the same name/team but new prompt + full context
1838
+ const validated = validateAgentConfig({
1839
+ role: existing.role,
1840
+ scope: config.scope || existing.scope || [],
1841
+ prompt,
1842
+ provider: config.provider || existing.provider || undefined,
1843
+ model: config.model || existing.model || 'auto',
1844
+ permission: config.permission || existing.permission || 'auto',
1845
+ workingDir: existing.workingDir || projectWorkingDir,
1846
+ name: existing.name,
1847
+ });
1848
+ validated.teamId = defaultTeamId;
1849
+ const newAgent = await daemon.processes.spawn(validated);
1828
1850
  reused.push({ id: newAgent.id, name: newAgent.name, role: newAgent.role, reusedFrom: existing.name });
1829
1851
  phase1Ids.push(newAgent.id);
1830
1852
  daemon.audit.log('team.reuse', { oldId: existing.id, newId: newAgent.id, role: config.role });
1831
1853
  } catch (err) {
1832
- // Reuse failed — fall through to spawn
1833
1854
  failed.push({ role: config.role, error: `reuse failed: ${err.message}` });
1834
1855
  }
1835
1856
  } else {
@@ -51,7 +51,7 @@ export class Registry extends EventEmitter {
51
51
  if (!agent) return null;
52
52
 
53
53
  // Only allow known fields to prevent prototype pollution
54
- const SAFE_FIELDS = ['status', 'pid', 'tokensUsed', 'contextUsage', 'lastActivity', 'model', 'provider', 'name', 'routingMode', 'routingReason', 'sessionId', 'skills', 'integrations', 'workingDir', 'effort', 'costUsd', 'durationMs', 'turns', 'inputTokens', 'outputTokens', 'teamId'];
54
+ const SAFE_FIELDS = ['status', 'pid', 'tokensUsed', 'contextUsage', 'lastActivity', 'model', 'provider', 'name', 'routingMode', 'routingReason', 'sessionId', 'skills', 'integrations', 'workingDir', 'effort', 'costUsd', 'durationMs', 'turns', 'inputTokens', 'outputTokens', 'teamId', 'permission', 'scope'];
55
55
  for (const key of Object.keys(updates)) {
56
56
  if (SAFE_FIELDS.includes(key)) {
57
57
  agent[key] = updates[key];
@@ -12,22 +12,28 @@ const MODES = {
12
12
  AUTO_FLOOR: 'auto-floor', // Auto, but never below a floor model
13
13
  };
14
14
 
15
- // Role-based tier hints for new agents with no classifier data yet
15
+ // Role-based tier hints for new agents with no classifier data yet.
16
+ // Default everything to heavy — intelligence out of the box. Users can
17
+ // downgrade to auto/medium if they want to optimize cost. A failed task
18
+ // at a cheaper model costs more than a successful one at the best model.
16
19
  const ROLE_HINTS = {
17
- planner: 'heavy', // Planning is foundational — needs deep reasoning
18
- fullstack: 'heavy', // End-to-end work needs full capability
19
- slides: 'heavy', // Design quality needs top-tier model
20
- creative: 'heavy', // Writing quality needs top-tier model
21
- security: 'heavy', // Security audits need deep reasoning
22
- backend: 'medium',
23
- frontend: 'medium',
24
- testing: 'medium',
25
- devops: 'medium',
26
- database: 'medium',
27
- analyst: 'medium',
28
- docs: 'light',
29
- support: 'light',
30
- ea: 'light',
20
+ planner: 'heavy',
21
+ fullstack: 'heavy',
22
+ frontend: 'heavy',
23
+ backend: 'heavy',
24
+ slides: 'heavy',
25
+ creative: 'heavy',
26
+ security: 'heavy',
27
+ testing: 'heavy',
28
+ devops: 'heavy',
29
+ database: 'heavy',
30
+ analyst: 'heavy',
31
+ docs: 'heavy',
32
+ support: 'heavy',
33
+ ea: 'heavy',
34
+ cmo: 'heavy',
35
+ cfo: 'heavy',
36
+ home: 'heavy',
31
37
  };
32
38
 
33
39
  export class ModelRouter {