groove-dev 0.24.13 → 0.24.14

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-BWfJkR97.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CsWIdDVz.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">
@@ -212,22 +212,47 @@ function AgentTreeInner() {
212
212
  },
213
213
  ];
214
214
 
215
+ // Track occupied positions so new nodes don't overlap existing ones
216
+ const occupied = new Set();
217
+ const posKey = (x, y) => `${Math.round(x / 100)},${Math.round(y / 100)}`;
218
+
219
+ // First pass: place agents with saved positions
220
+ const pending = [];
215
221
  agents.forEach((agent, i) => {
216
222
  const key = agent.name || agent.id;
217
- const row = Math.floor(i / MAX_PER_ROW);
218
- const col = i % MAX_PER_ROW;
223
+ if (saved[key]) {
224
+ const pos = saved[key];
225
+ occupied.add(posKey(pos.x, pos.y));
226
+ nodes.push({
227
+ id: agent.id, type: 'agentNode', position: pos,
228
+ data: { agent, timeline: tokenTimeline[agent.id] || [] },
229
+ draggable: true, selectable: true,
230
+ });
231
+ } else {
232
+ pending.push({ agent, index: i });
233
+ }
234
+ });
235
+
236
+ // Second pass: place new agents in non-overlapping positions
237
+ for (const { agent, index } of pending) {
238
+ const row = Math.floor(index / MAX_PER_ROW);
239
+ const col = index % MAX_PER_ROW;
219
240
  const totalInRow = Math.min(agents.length - row * MAX_PER_ROW, MAX_PER_ROW);
220
241
  const offsetX = -((totalInRow - 1) * NODE_X_GAP) / 2;
242
+ let pos = { x: offsetX + col * NODE_X_GAP, y: 140 + row * NODE_Y_GAP };
243
+
244
+ // If position is occupied, shift down until we find empty space
245
+ while (occupied.has(posKey(pos.x, pos.y))) {
246
+ pos = { x: pos.x, y: pos.y + NODE_Y_GAP };
247
+ }
248
+ occupied.add(posKey(pos.x, pos.y));
221
249
 
222
250
  nodes.push({
223
- id: agent.id,
224
- type: 'agentNode',
225
- position: saved[key] || { x: offsetX + col * NODE_X_GAP, y: 140 + row * NODE_Y_GAP },
251
+ id: agent.id, type: 'agentNode', position: pos,
226
252
  data: { agent, timeline: tokenTimeline[agent.id] || [] },
227
- draggable: true,
228
- selectable: true,
253
+ draggable: true, selectable: true,
229
254
  });
230
- });
255
+ }
231
256
 
232
257
  return nodes;
233
258
  }, [agents, tokenTimeline]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.24.13",
3
+ "version": "0.24.14",
4
4
  "description": "Open-source agent orchestration layer — the AI company OS. 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.",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",