groove-dev 0.27.0 → 0.27.1

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-eCrVowF0.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-Bl1_J0sN.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">
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -249,25 +249,52 @@ export const useGrooveStore = create((set, get) => ({
249
249
  break;
250
250
 
251
251
  case 'rotation:start':
252
- get().addToast('info', `Rotating ${msg.agentName}...`);
252
+ // Silent — rotation must feel seamless to the user.
253
+ // Visibility is available in dashboard Intel panel for curious users.
253
254
  break;
254
255
 
255
256
  case 'rotation:complete': {
256
- get().addToast('success', `Rotated ${msg.agentName}`, `Saved ${msg.tokensSaved} tokens`);
257
- const panel = get().detailPanel;
258
- if (panel?.type === 'agent' && panel.agentId === msg.oldAgentId && msg.newAgentId) {
259
- set((s) => {
260
- const chatHistory = { ...s.chatHistory };
261
- const tokenTimeline = { ...s.tokenTimeline };
262
- const activityLog = { ...s.activityLog };
263
- if (chatHistory[msg.oldAgentId]?.length) chatHistory[msg.newAgentId] = [...chatHistory[msg.oldAgentId]];
264
- if (tokenTimeline[msg.oldAgentId]?.length) tokenTimeline[msg.newAgentId] = [...tokenTimeline[msg.oldAgentId]];
265
- if (activityLog[msg.oldAgentId]?.length) activityLog[msg.newAgentId] = [...activityLog[msg.oldAgentId]];
257
+ // Silent toast seamless infinite sessions are the whole promise.
258
+ // Migrate all agent-keyed state to the new ID ALWAYS, not just when
259
+ // the old agent's panel is open. Chat history, activity log, token
260
+ // timeline all carry forward so no state is orphaned.
261
+ if (!msg.newAgentId || !msg.oldAgentId) break;
262
+ set((s) => {
263
+ const chatHistory = { ...s.chatHistory };
264
+ const tokenTimeline = { ...s.tokenTimeline };
265
+ const activityLog = { ...s.activityLog };
266
+ const chatInputs = { ...s.chatInputs };
267
+ if (chatHistory[msg.oldAgentId]?.length) {
268
+ chatHistory[msg.newAgentId] = [...chatHistory[msg.oldAgentId]];
269
+ delete chatHistory[msg.oldAgentId];
270
+ }
271
+ if (tokenTimeline[msg.oldAgentId]?.length) {
272
+ tokenTimeline[msg.newAgentId] = [...tokenTimeline[msg.oldAgentId]];
273
+ delete tokenTimeline[msg.oldAgentId];
274
+ }
275
+ if (activityLog[msg.oldAgentId]?.length) {
276
+ activityLog[msg.newAgentId] = [...activityLog[msg.oldAgentId]];
277
+ delete activityLog[msg.oldAgentId];
278
+ }
279
+ if (chatInputs[msg.oldAgentId]) {
280
+ chatInputs[msg.newAgentId] = chatInputs[msg.oldAgentId];
281
+ delete chatInputs[msg.oldAgentId];
282
+ }
283
+ // Only redirect the detail panel if the user was actively viewing
284
+ // the old agent. Otherwise leave their current view alone.
285
+ const panel = s.detailPanel;
286
+ let detailPanel = panel;
287
+ let teamDetailPanels = s.teamDetailPanels;
288
+ if (panel?.type === 'agent' && panel.agentId === msg.oldAgentId) {
266
289
  const newPanel = { type: 'agent', agentId: msg.newAgentId };
290
+ detailPanel = newPanel;
267
291
  const tid = get().activeTeamId;
268
- return { chatHistory, tokenTimeline, activityLog, detailPanel: newPanel, teamDetailPanels: { ...s.teamDetailPanels, [tid]: newPanel } };
269
- });
270
- }
292
+ teamDetailPanels = { ...s.teamDetailPanels, [tid]: newPanel };
293
+ }
294
+ // Persist the migration to localStorage so it survives a reload
295
+ try { localStorage.setItem('groove:chatHistory', JSON.stringify(chatHistory)); } catch {}
296
+ return { chatHistory, tokenTimeline, activityLog, chatInputs, detailPanel, teamDetailPanels };
297
+ });
271
298
  break;
272
299
  }
273
300