groove-dev 0.22.22 → 0.22.26

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,12 +5,12 @@
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-COKbbm6r.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-HrPG73DF.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">
12
12
  <link rel="modulepreload" crossorigin href="/assets/xterm--7_ns2zW.js">
13
- <link rel="stylesheet" crossorigin href="/assets/index-Cu3h6_1j.css">
13
+ <link rel="stylesheet" crossorigin href="/assets/index-BlH4CGdR.css">
14
14
  </head>
15
15
  <body>
16
16
  <div id="root"></div>
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.22.21",
3
+ "version": "0.22.25",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -410,9 +410,10 @@ function BootSequence({ agent }) {
410
410
  <div className="flex flex-col justify-center h-full px-2 py-6">
411
411
  {/* Agent identity */}
412
412
  <div className="flex items-center gap-3 mb-6">
413
- <div className="relative w-10 h-10">
414
- <span className="absolute inset-0 rounded-lg border-2 border-transparent border-t-accent animate-spin" style={{ animationDuration: '1s' }} />
415
- <span className="absolute inset-[3px] rounded-md bg-accent/8" />
413
+ <div className="relative w-9 h-9">
414
+ <span className="absolute inset-0 rounded-full border-2 border-accent/20 animate-ping" style={{ animationDuration: '2s' }} />
415
+ <span className="absolute inset-0 rounded-full border-2 border-transparent border-t-accent animate-spin" style={{ animationDuration: '1s' }} />
416
+ <span className="absolute inset-[5px] rounded-full bg-accent/8" />
416
417
  </div>
417
418
  <div>
418
419
  <p className="text-sm font-bold text-text-0 font-sans">{agent.name}</p>
@@ -118,14 +118,15 @@ export const useGrooveStore = create((set, get) => ({
118
118
 
119
119
  case 'agent:output': {
120
120
  const { agentId, data } = msg;
121
- // Extract text from Claude Code content blocks or plain strings
122
- let text = '';
121
+
122
+ // Separate text content from tool calls
123
+ let chatText = '';
124
+ let activityText = '';
123
125
  if (typeof data.data === 'string') {
124
- text = data.data;
126
+ chatText = data.data;
125
127
  } else if (Array.isArray(data.data)) {
126
- const textParts = data.data.filter((b) => b.type === 'text').map((b) => b.text);
127
- const toolParts = data.data.filter((b) => b.type === 'tool_use').map((b) => `[${b.name}] ${typeof b.input === 'string' ? b.input : JSON.stringify(b.input || '').slice(0, 100)}`);
128
- text = [...textParts, ...toolParts].join('\n');
128
+ chatText = data.data.filter((b) => b.type === 'text').map((b) => b.text).join('\n');
129
+ activityText = data.data.filter((b) => b.type === 'tool_use').map((b) => `${b.name}: ${typeof b.input === 'string' ? b.input.slice(0, 80) : (b.input?.command || b.input?.path || b.input?.pattern || JSON.stringify(b.input || '').slice(0, 80))}`).join('\n');
129
130
  }
130
131
 
131
132
  // Update agent metrics in real-time (contextUsage, tokensUsed)
@@ -140,22 +141,24 @@ export const useGrooveStore = create((set, get) => ({
140
141
  set({ agents });
141
142
  }
142
143
 
143
- // Promote assistant text and result responses to chat bubbles
144
- if ((data.subtype === 'assistant' || data.type === 'result') && text && text.trim()) {
144
+ // Text responses chat bubbles (only real text, not tool calls)
145
+ if ((data.subtype === 'assistant' || data.type === 'result') && chatText && chatText.trim()) {
145
146
  const history = { ...get().chatHistory };
146
147
  if (!history[agentId]) history[agentId] = [];
147
- history[agentId] = [...history[agentId].slice(-100), { from: 'agent', text: text.trim(), timestamp: Date.now() }];
148
+ history[agentId] = [...history[agentId].slice(-100), { from: 'agent', text: chatText.trim(), timestamp: Date.now() }];
148
149
  set({ chatHistory: history });
149
150
  persistJSON('groove:chatHistory', history);
150
- } else if (text && text.trim()) {
151
- // Non-empty activity goes to activity log
151
+ }
152
+
153
+ // Tool calls → activity log (shown in streaming bar, not as chat bubbles)
154
+ if (activityText && activityText.trim()) {
152
155
  const log = { ...get().activityLog };
153
156
  if (!log[agentId]) log[agentId] = [];
154
157
  log[agentId] = [...log[agentId].slice(-200), {
155
158
  timestamp: Date.now(),
156
- text: text.trim(),
159
+ text: activityText.trim(),
157
160
  type: data.type,
158
- subtype: data.subtype || null,
161
+ subtype: 'tool',
159
162
  }];
160
163
  set({ activityLog: log });
161
164
  persistJSON('groove:activityLog', log);
@@ -532,8 +532,6 @@ export default function AgentsView() {
532
532
  try {
533
533
  const agent = await spawnAgent({ role: 'planner' });
534
534
  if (agent?.id) {
535
- const addChat = useGrooveStore.getState().addChatMessage;
536
- addChat(agent.id, 'system', 'Planner is starting up...');
537
535
  selectAgent(agent.id);
538
536
  }
539
537
  } catch { /* toast handles */ }