groove-dev 0.27.14 → 0.27.17

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.
Files changed (169) hide show
  1. package/README.md +37 -1
  2. package/developerID_application.cer +0 -0
  3. package/node_modules/@groove-dev/daemon/src/api.js +587 -68
  4. package/node_modules/@groove-dev/daemon/src/classifier.js +24 -0
  5. package/node_modules/@groove-dev/daemon/src/credentials.js +12 -2
  6. package/node_modules/@groove-dev/daemon/src/federation/ambassador.js +204 -0
  7. package/node_modules/@groove-dev/daemon/src/federation/connection.js +359 -0
  8. package/node_modules/@groove-dev/daemon/src/federation/contracts.js +112 -0
  9. package/node_modules/@groove-dev/daemon/src/federation/whitelist.js +190 -0
  10. package/node_modules/@groove-dev/daemon/src/federation.js +166 -7
  11. package/node_modules/@groove-dev/daemon/src/index.js +172 -19
  12. package/node_modules/@groove-dev/daemon/src/introducer.js +52 -7
  13. package/node_modules/@groove-dev/daemon/src/journalist.js +46 -1
  14. package/node_modules/@groove-dev/daemon/src/memory.js +36 -16
  15. package/node_modules/@groove-dev/daemon/src/process.js +140 -23
  16. package/node_modules/@groove-dev/daemon/src/providers/base.js +1 -0
  17. package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +1 -0
  18. package/node_modules/@groove-dev/daemon/src/providers/codex.js +124 -28
  19. package/node_modules/@groove-dev/daemon/src/providers/gemini.js +104 -17
  20. package/node_modules/@groove-dev/daemon/src/providers/index.js +17 -0
  21. package/node_modules/@groove-dev/daemon/src/registry.js +10 -1
  22. package/node_modules/@groove-dev/daemon/src/rotator.js +93 -30
  23. package/node_modules/@groove-dev/daemon/src/skills.js +33 -3
  24. package/node_modules/@groove-dev/daemon/src/terminal-pty.js +9 -1
  25. package/node_modules/@groove-dev/daemon/src/tool-executor.js +11 -5
  26. package/node_modules/@groove-dev/daemon/src/toys.js +69 -0
  27. package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +24 -5
  28. package/node_modules/@groove-dev/daemon/templates/toys-catalog.json +242 -0
  29. package/node_modules/@groove-dev/daemon/test/classifier.test.js +98 -0
  30. package/node_modules/@groove-dev/daemon/test/introducer.test.js +72 -1
  31. package/node_modules/@groove-dev/daemon/test/journalist.test.js +117 -0
  32. package/node_modules/@groove-dev/daemon/test/memory.test.js +37 -1
  33. package/node_modules/@groove-dev/daemon/test/rotator.test.js +183 -4
  34. package/node_modules/@groove-dev/gui/dist/assets/index-BglPgjlu.js +8607 -0
  35. package/node_modules/@groove-dev/gui/dist/assets/index-CGcwmmJv.css +1 -0
  36. package/node_modules/@groove-dev/gui/dist/index.html +3 -2
  37. package/node_modules/@groove-dev/gui/index.html +1 -0
  38. package/node_modules/@groove-dev/gui/src/app.css +7 -0
  39. package/node_modules/@groove-dev/gui/src/app.jsx +37 -10
  40. package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +21 -31
  41. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +11 -6
  42. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +2 -2
  43. package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +42 -1
  44. package/node_modules/@groove-dev/gui/src/components/editor/breadcrumbs.jsx +30 -0
  45. package/node_modules/@groove-dev/gui/src/components/editor/code-editor.jsx +33 -2
  46. package/node_modules/@groove-dev/gui/src/components/editor/editor-status-bar.jsx +26 -0
  47. package/node_modules/@groove-dev/gui/src/components/editor/editor-tabs.jsx +113 -34
  48. package/node_modules/@groove-dev/gui/src/components/editor/goto-line.jsx +35 -0
  49. package/node_modules/@groove-dev/gui/src/components/editor/terminal.jsx +12 -6
  50. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +13 -3
  51. package/node_modules/@groove-dev/gui/src/components/layout/app-shell.jsx +0 -1
  52. package/node_modules/@groove-dev/gui/src/components/layout/breadcrumb-bar.jsx +165 -47
  53. package/node_modules/@groove-dev/gui/src/components/layout/command-palette.jsx +6 -2
  54. package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +10 -9
  55. package/node_modules/@groove-dev/gui/src/components/marketplace/repo-import.jsx +9 -1
  56. package/node_modules/@groove-dev/gui/src/components/onboarding/provider-card.jsx +134 -0
  57. package/node_modules/@groove-dev/gui/src/components/onboarding/setup-wizard.jsx +819 -0
  58. package/node_modules/@groove-dev/gui/src/components/pro/pro-gate.jsx +12 -5
  59. package/node_modules/@groove-dev/gui/src/components/pro/upgrade-card.jsx +15 -8
  60. package/node_modules/@groove-dev/gui/src/components/pro/upgrade-modal.jsx +151 -0
  61. package/node_modules/@groove-dev/gui/src/components/settings/federation-activity.jsx +98 -0
  62. package/node_modules/@groove-dev/gui/src/components/settings/federation-panel.jsx +290 -0
  63. package/node_modules/@groove-dev/gui/src/components/settings/federation-peers.jsx +126 -0
  64. package/node_modules/@groove-dev/gui/src/components/settings/federation-wizard.jsx +293 -0
  65. package/node_modules/@groove-dev/gui/src/components/settings/quick-connect.jsx +110 -67
  66. package/node_modules/@groove-dev/gui/src/components/settings/remote-server-card.jsx +3 -3
  67. package/node_modules/@groove-dev/gui/src/components/settings/server-detail.jsx +310 -0
  68. package/node_modules/@groove-dev/gui/src/components/settings/server-dialog.jsx +4 -1
  69. package/node_modules/@groove-dev/gui/src/components/settings/server-list.jsx +59 -0
  70. package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +549 -0
  71. package/node_modules/@groove-dev/gui/src/components/toys/toy-card.jsx +78 -0
  72. package/node_modules/@groove-dev/gui/src/components/toys/toy-creator.jsx +144 -0
  73. package/node_modules/@groove-dev/gui/src/components/toys/toy-launcher.jsx +187 -0
  74. package/node_modules/@groove-dev/gui/src/components/ui/toast.jsx +2 -2
  75. package/node_modules/@groove-dev/gui/src/lib/electron.js +15 -0
  76. package/node_modules/@groove-dev/gui/src/lib/format.js +1 -0
  77. package/node_modules/@groove-dev/gui/src/stores/groove.js +373 -58
  78. package/node_modules/@groove-dev/gui/src/views/agents.jsx +148 -42
  79. package/node_modules/@groove-dev/gui/src/views/editor.jsx +92 -2
  80. package/node_modules/@groove-dev/gui/src/views/federation.jsx +37 -0
  81. package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +2 -42
  82. package/node_modules/@groove-dev/gui/src/views/settings.jsx +32 -132
  83. package/node_modules/@groove-dev/gui/src/views/subscription-panel.jsx +327 -0
  84. package/node_modules/@groove-dev/gui/src/views/teams.jsx +3 -3
  85. package/node_modules/@groove-dev/gui/src/views/toys.jsx +162 -0
  86. package/package.json +1 -1
  87. package/packages/daemon/src/api.js +587 -68
  88. package/packages/daemon/src/classifier.js +24 -0
  89. package/packages/daemon/src/credentials.js +12 -2
  90. package/packages/daemon/src/federation/ambassador.js +204 -0
  91. package/packages/daemon/src/federation/connection.js +359 -0
  92. package/packages/daemon/src/federation/contracts.js +112 -0
  93. package/packages/daemon/src/federation/whitelist.js +190 -0
  94. package/packages/daemon/src/federation.js +166 -7
  95. package/packages/daemon/src/index.js +172 -19
  96. package/packages/daemon/src/introducer.js +52 -7
  97. package/packages/daemon/src/journalist.js +46 -1
  98. package/packages/daemon/src/memory.js +36 -16
  99. package/packages/daemon/src/process.js +140 -23
  100. package/packages/daemon/src/providers/base.js +1 -0
  101. package/packages/daemon/src/providers/claude-code.js +1 -0
  102. package/packages/daemon/src/providers/codex.js +124 -28
  103. package/packages/daemon/src/providers/gemini.js +104 -17
  104. package/packages/daemon/src/providers/index.js +17 -0
  105. package/packages/daemon/src/registry.js +10 -1
  106. package/packages/daemon/src/rotator.js +93 -30
  107. package/packages/daemon/src/skills.js +33 -3
  108. package/packages/daemon/src/terminal-pty.js +9 -1
  109. package/packages/daemon/src/tool-executor.js +11 -5
  110. package/packages/daemon/src/toys.js +69 -0
  111. package/packages/daemon/src/tunnel-manager.js +24 -5
  112. package/packages/daemon/templates/toys-catalog.json +242 -0
  113. package/packages/gui/dist/assets/index-BglPgjlu.js +8607 -0
  114. package/packages/gui/dist/assets/index-CGcwmmJv.css +1 -0
  115. package/packages/gui/dist/index.html +3 -2
  116. package/packages/gui/index.html +1 -0
  117. package/packages/gui/src/app.css +7 -0
  118. package/packages/gui/src/app.jsx +37 -10
  119. package/packages/gui/src/components/agents/agent-chat.jsx +21 -31
  120. package/packages/gui/src/components/agents/agent-config.jsx +11 -6
  121. package/packages/gui/src/components/agents/agent-feed.jsx +2 -2
  122. package/packages/gui/src/components/agents/spawn-wizard.jsx +42 -1
  123. package/packages/gui/src/components/editor/breadcrumbs.jsx +30 -0
  124. package/packages/gui/src/components/editor/code-editor.jsx +33 -2
  125. package/packages/gui/src/components/editor/editor-status-bar.jsx +26 -0
  126. package/packages/gui/src/components/editor/editor-tabs.jsx +113 -34
  127. package/packages/gui/src/components/editor/goto-line.jsx +35 -0
  128. package/packages/gui/src/components/editor/terminal.jsx +12 -6
  129. package/packages/gui/src/components/layout/activity-bar.jsx +13 -3
  130. package/packages/gui/src/components/layout/app-shell.jsx +0 -1
  131. package/packages/gui/src/components/layout/breadcrumb-bar.jsx +165 -47
  132. package/packages/gui/src/components/layout/command-palette.jsx +6 -2
  133. package/packages/gui/src/components/layout/terminal-panel.jsx +10 -9
  134. package/packages/gui/src/components/marketplace/repo-import.jsx +9 -1
  135. package/packages/gui/src/components/onboarding/provider-card.jsx +134 -0
  136. package/packages/gui/src/components/onboarding/setup-wizard.jsx +819 -0
  137. package/packages/gui/src/components/pro/pro-gate.jsx +12 -5
  138. package/packages/gui/src/components/pro/upgrade-card.jsx +15 -8
  139. package/packages/gui/src/components/pro/upgrade-modal.jsx +151 -0
  140. package/packages/gui/src/components/settings/federation-activity.jsx +98 -0
  141. package/packages/gui/src/components/settings/federation-panel.jsx +290 -0
  142. package/packages/gui/src/components/settings/federation-peers.jsx +126 -0
  143. package/packages/gui/src/components/settings/federation-wizard.jsx +293 -0
  144. package/packages/gui/src/components/settings/quick-connect.jsx +110 -67
  145. package/packages/gui/src/components/settings/remote-server-card.jsx +3 -3
  146. package/packages/gui/src/components/settings/server-detail.jsx +310 -0
  147. package/packages/gui/src/components/settings/server-dialog.jsx +4 -1
  148. package/packages/gui/src/components/settings/server-list.jsx +59 -0
  149. package/packages/gui/src/components/settings/ssh-wizard.jsx +549 -0
  150. package/packages/gui/src/components/toys/toy-card.jsx +78 -0
  151. package/packages/gui/src/components/toys/toy-creator.jsx +144 -0
  152. package/packages/gui/src/components/toys/toy-launcher.jsx +187 -0
  153. package/packages/gui/src/components/ui/toast.jsx +2 -2
  154. package/packages/gui/src/lib/electron.js +15 -0
  155. package/packages/gui/src/lib/format.js +1 -0
  156. package/packages/gui/src/stores/groove.js +373 -58
  157. package/packages/gui/src/views/agents.jsx +148 -42
  158. package/packages/gui/src/views/editor.jsx +92 -2
  159. package/packages/gui/src/views/federation.jsx +37 -0
  160. package/packages/gui/src/views/marketplace.jsx +2 -42
  161. package/packages/gui/src/views/settings.jsx +32 -132
  162. package/packages/gui/src/views/subscription-panel.jsx +327 -0
  163. package/packages/gui/src/views/teams.jsx +3 -3
  164. package/packages/gui/src/views/toys.jsx +162 -0
  165. package/plans/chat-persistence-refactor.md +154 -0
  166. package/node_modules/@groove-dev/gui/dist/assets/index-BE6lYcd7.css +0 -1
  167. package/node_modules/@groove-dev/gui/dist/assets/index-zdzOLAZM.js +0 -677
  168. package/packages/gui/dist/assets/index-BE6lYcd7.css +0 -1
  169. package/packages/gui/dist/assets/index-zdzOLAZM.js +0 -677
@@ -16,6 +16,7 @@ describe('Rotator', () => {
16
16
  get(id) { return this.agents.find((a) => a.id === id) || null; },
17
17
  getAll() { return this.agents; },
18
18
  update(id, updates) { const a = this.agents.find((x) => x.id === id); if (a) Object.assign(a, updates); return a; },
19
+ remove(id) { this.agents = this.agents.filter((a) => a.id !== id); return true; },
19
20
  agents: [],
20
21
  };
21
22
 
@@ -36,6 +37,7 @@ describe('Rotator', () => {
36
37
  adaptive: {
37
38
  extractSignals() { return { errorCount: 0, repetitions: 0, scopeViolations: 0, toolCalls: 0, toolFailures: 0, filesWritten: 0 }; },
38
39
  recordSession() { return { score: 70, threshold: 0.75, converged: false }; },
40
+ getThreshold() { return 0.65; },
39
41
  },
40
42
  classifier: {
41
43
  agentWindows: {},
@@ -166,8 +168,185 @@ describe('Rotator', () => {
166
168
  assert.equal(stats.totalTokensSaved, 8000);
167
169
  });
168
170
 
169
- // Safety triggers (token ceiling, velocity, role multipliers) removed in
170
- // v0.27.6 they produced false positives on legitimate heavy exploration
171
- // and killed planners mid-task. The v0.26.39 rotator (context + quality +
172
- // natural compaction only) is the known-good behavior.
171
+ it('should include cooldown and token ceiling in stats', () => {
172
+ const stats = rotator.getStats();
173
+ assert.equal(stats.cooldownMs, 5 * 60 * 1000);
174
+ assert.equal(stats.tokenCeiling, 5_000_000);
175
+ assert.deepEqual(stats.roleMultipliers, { planner: 10, fullstack: 4, security: 4, analyst: 5 });
176
+ assert.equal(stats.tokenCeilingRotations, 0);
177
+ });
178
+
179
+ it('should enforce cooldown — skip context rotation within 5 minutes', async () => {
180
+ // Use gemini provider (non-self-managing)
181
+ const agent = {
182
+ id: 'g1', name: 'gemini-1', role: 'backend', status: 'running',
183
+ provider: 'gemini', scope: [], model: null,
184
+ tokensUsed: 1000, contextUsage: 0.70, workingDir: '/tmp',
185
+ lastActivity: new Date(Date.now() - 30_000).toISOString(),
186
+ spawnedAt: new Date(Date.now() - 300_000).toISOString(),
187
+ };
188
+ mockDaemon.registry.agents = [agent];
189
+ mockDaemon.adaptive.getThreshold = () => 0.65;
190
+
191
+ // Manually set a recent rotation time
192
+ rotator.lastRotationTime.set('g1', Date.now() - 60_000); // 1 min ago (within 5-min cooldown)
193
+
194
+ await rotator.check();
195
+
196
+ // Should NOT rotate — cooldown is active
197
+ const history = rotator.getHistory();
198
+ assert.equal(history.length, 0);
199
+ });
200
+
201
+ it('should allow rotation after cooldown expires', async () => {
202
+ const agent = {
203
+ id: 'g2', name: 'gemini-2', role: 'backend', status: 'running',
204
+ provider: 'gemini', scope: [], model: null,
205
+ tokensUsed: 1000, contextUsage: 0.70, workingDir: '/tmp',
206
+ lastActivity: new Date(Date.now() - 30_000).toISOString(),
207
+ spawnedAt: new Date(Date.now() - 300_000).toISOString(),
208
+ };
209
+ mockDaemon.registry.agents = [agent];
210
+ mockDaemon.adaptive.getThreshold = () => 0.65;
211
+
212
+ // Set rotation time well in the past (6 min ago — cooldown expired)
213
+ rotator.lastRotationTime.set('g2', Date.now() - 6 * 60 * 1000);
214
+
215
+ await rotator.check();
216
+
217
+ // Should rotate — cooldown expired
218
+ const history = rotator.getHistory();
219
+ assert.equal(history.length, 1);
220
+ assert.equal(history[0].reason, 'context_threshold');
221
+ });
222
+
223
+ it('should trigger token ceiling rotation for non-self-managing provider', async () => {
224
+ const agent = {
225
+ id: 'g3', name: 'gemini-3', role: 'backend', status: 'running',
226
+ provider: 'gemini', scope: [], model: null,
227
+ tokensUsed: 5_500_000, contextUsage: 0.50, workingDir: '/tmp',
228
+ lastActivity: new Date(Date.now() - 30_000).toISOString(),
229
+ spawnedAt: new Date(Date.now() - 300_000).toISOString(),
230
+ };
231
+ mockDaemon.registry.agents = [agent];
232
+
233
+ await rotator.check();
234
+
235
+ const history = rotator.getHistory();
236
+ assert.equal(history.length, 1);
237
+ assert.equal(history[0].reason, 'token_ceiling');
238
+ });
239
+
240
+ it('should respect role multipliers — planner gets 50M ceiling', async () => {
241
+ const agent = {
242
+ id: 'g4', name: 'gemini-planner', role: 'planner', status: 'running',
243
+ provider: 'gemini', scope: [], model: null,
244
+ tokensUsed: 8_000_000, contextUsage: 0.50, workingDir: '/tmp',
245
+ lastActivity: new Date(Date.now() - 30_000).toISOString(),
246
+ spawnedAt: new Date(Date.now() - 300_000).toISOString(),
247
+ };
248
+ mockDaemon.registry.agents = [agent];
249
+
250
+ await rotator.check();
251
+
252
+ // 8M < 50M (planner ceiling = 5M * 10), should NOT token-ceiling rotate
253
+ const history = rotator.getHistory();
254
+ const tokenCeilingRotations = history.filter((r) => r.reason === 'token_ceiling');
255
+ assert.equal(tokenCeilingRotations.length, 0);
256
+ });
257
+
258
+ it('should token ceiling rotate planner at 50M+', async () => {
259
+ const agent = {
260
+ id: 'g5', name: 'gemini-planner-2', role: 'planner', status: 'running',
261
+ provider: 'gemini', scope: [], model: null,
262
+ tokensUsed: 55_000_000, contextUsage: 0.50, workingDir: '/tmp',
263
+ lastActivity: new Date(Date.now() - 30_000).toISOString(),
264
+ spawnedAt: new Date(Date.now() - 300_000).toISOString(),
265
+ };
266
+ mockDaemon.registry.agents = [agent];
267
+
268
+ await rotator.check();
269
+
270
+ const history = rotator.getHistory();
271
+ assert.equal(history.length, 1);
272
+ assert.equal(history[0].reason, 'token_ceiling');
273
+ });
274
+
275
+ it('should bypass cooldown for hard ceiling', async () => {
276
+ const agent = {
277
+ id: 'g6', name: 'gemini-hot', role: 'backend', status: 'running',
278
+ provider: 'gemini', scope: [], model: null,
279
+ tokensUsed: 1000, contextUsage: 0.85, workingDir: '/tmp',
280
+ lastActivity: new Date(Date.now() - 30_000).toISOString(),
281
+ spawnedAt: new Date(Date.now() - 300_000).toISOString(),
282
+ };
283
+ mockDaemon.registry.agents = [agent];
284
+
285
+ // Set recent cooldown
286
+ rotator.lastRotationTime.set('g6', Date.now() - 60_000); // 1 min ago
287
+
288
+ await rotator.check();
289
+
290
+ // Hard ceiling (85% >= 80%) should bypass cooldown
291
+ const history = rotator.getHistory();
292
+ assert.equal(history.length, 1);
293
+ assert.equal(history[0].reason, 'hard_ceiling');
294
+ });
295
+
296
+ it('should bypass cooldown for token ceiling', async () => {
297
+ const agent = {
298
+ id: 'g7', name: 'gemini-tokens', role: 'backend', status: 'running',
299
+ provider: 'gemini', scope: [], model: null,
300
+ tokensUsed: 6_000_000, contextUsage: 0.50, workingDir: '/tmp',
301
+ lastActivity: new Date(Date.now() - 30_000).toISOString(),
302
+ spawnedAt: new Date(Date.now() - 300_000).toISOString(),
303
+ };
304
+ mockDaemon.registry.agents = [agent];
305
+
306
+ // Set recent cooldown
307
+ rotator.lastRotationTime.set('g7', Date.now() - 60_000); // 1 min ago
308
+
309
+ await rotator.check();
310
+
311
+ // Token ceiling (6M >= 5M) should bypass cooldown
312
+ const history = rotator.getHistory();
313
+ assert.equal(history.length, 1);
314
+ assert.equal(history[0].reason, 'token_ceiling');
315
+ });
316
+
317
+ it('should NOT apply token ceiling to self-managing providers (Claude Code)', async () => {
318
+ const agent = {
319
+ id: 'c1', name: 'claude-heavy', role: 'backend', status: 'running',
320
+ provider: 'claude-code', scope: [], model: null,
321
+ tokensUsed: 10_000_000, contextUsage: 0.50, workingDir: '/tmp',
322
+ lastActivity: new Date(Date.now() - 30_000).toISOString(),
323
+ spawnedAt: new Date(Date.now() - 300_000).toISOString(),
324
+ };
325
+ mockDaemon.registry.agents = [agent];
326
+
327
+ await rotator.check();
328
+
329
+ // Claude Code self-manages — token ceiling should NOT fire
330
+ const history = rotator.getHistory();
331
+ const tokenCeilingRotations = history.filter((r) => r.reason === 'token_ceiling');
332
+ assert.equal(tokenCeilingRotations.length, 0);
333
+ });
334
+
335
+ it('should record lastRotationTime after successful rotation', async () => {
336
+ const agent = {
337
+ id: 'a3', name: 'backend-3', role: 'backend',
338
+ provider: 'claude-code', scope: [], model: null,
339
+ tokensUsed: 3000, contextUsage: 0.9, workingDir: '/tmp',
340
+ };
341
+ mockDaemon.registry.agents = [agent];
342
+
343
+ assert.equal(rotator.lastRotationTime.has('a3'), false);
344
+
345
+ const newAgent = await rotator.rotate('a3');
346
+
347
+ assert.equal(rotator.lastRotationTime.has('a3'), false);
348
+ assert.equal(rotator.lastRotationTime.has(newAgent.id), true);
349
+ const elapsed = Date.now() - rotator.lastRotationTime.get(newAgent.id);
350
+ assert.ok(elapsed < 1000); // Should be very recent
351
+ });
173
352
  });