groove-dev 0.27.73 → 0.27.75

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 (73) hide show
  1. package/node_modules/@groove-dev/cli/package.json +1 -1
  2. package/node_modules/@groove-dev/daemon/package.json +1 -1
  3. package/node_modules/@groove-dev/daemon/src/api.js +256 -4
  4. package/node_modules/@groove-dev/daemon/src/conversations.js +16 -0
  5. package/node_modules/@groove-dev/daemon/src/index.js +41 -1
  6. package/node_modules/@groove-dev/daemon/src/preview.js +18 -2
  7. package/node_modules/@groove-dev/daemon/src/process.js +6 -1
  8. package/node_modules/@groove-dev/daemon/src/providers/base.js +4 -0
  9. package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +2 -1
  10. package/node_modules/@groove-dev/daemon/src/providers/codex.js +41 -1
  11. package/node_modules/@groove-dev/daemon/src/providers/gemini.js +2 -1
  12. package/node_modules/@groove-dev/daemon/src/providers/grok.js +156 -0
  13. package/node_modules/@groove-dev/daemon/src/providers/index.js +26 -9
  14. package/node_modules/@groove-dev/daemon/src/providers/nano-banana.js +103 -0
  15. package/node_modules/@groove-dev/gui/dist/assets/index-CAT9SCJi.js +8620 -0
  16. package/node_modules/@groove-dev/gui/dist/assets/index-CVzz6zyb.css +1 -0
  17. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  18. package/node_modules/@groove-dev/gui/package.json +1 -1
  19. package/node_modules/@groove-dev/gui/src/app.css +29 -0
  20. package/node_modules/@groove-dev/gui/src/app.jsx +2 -0
  21. package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +16 -5
  22. package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +40 -7
  23. package/node_modules/@groove-dev/gui/src/components/chat/chat-messages.jsx +149 -31
  24. package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +26 -2
  25. package/node_modules/@groove-dev/gui/src/components/chat/model-picker.jsx +105 -52
  26. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +5 -2
  27. package/node_modules/@groove-dev/gui/src/components/layout/welcome-splash.jsx +215 -88
  28. package/node_modules/@groove-dev/gui/src/components/preview/preview-toolbar.jsx +81 -0
  29. package/node_modules/@groove-dev/gui/src/components/preview/preview-workspace.jsx +263 -0
  30. package/node_modules/@groove-dev/gui/src/components/preview/screenshot-overlay.jsx +203 -0
  31. package/node_modules/@groove-dev/gui/src/components/ui/toast.jsx +6 -2
  32. package/node_modules/@groove-dev/gui/src/stores/groove.js +149 -9
  33. package/node_modules/@groove-dev/gui/src/views/preview.jsx +6 -0
  34. package/node_modules/@groove-dev/gui/src/views/settings.jsx +278 -123
  35. package/package.json +1 -1
  36. package/packages/cli/package.json +1 -1
  37. package/packages/daemon/package.json +1 -1
  38. package/packages/daemon/src/api.js +256 -4
  39. package/packages/daemon/src/conversations.js +16 -0
  40. package/packages/daemon/src/index.js +41 -1
  41. package/packages/daemon/src/preview.js +18 -2
  42. package/packages/daemon/src/process.js +6 -1
  43. package/packages/daemon/src/providers/base.js +4 -0
  44. package/packages/daemon/src/providers/claude-code.js +2 -1
  45. package/packages/daemon/src/providers/codex.js +41 -1
  46. package/packages/daemon/src/providers/gemini.js +2 -1
  47. package/packages/daemon/src/providers/grok.js +156 -0
  48. package/packages/daemon/src/providers/index.js +26 -9
  49. package/packages/daemon/src/providers/nano-banana.js +103 -0
  50. package/packages/gui/dist/assets/index-CAT9SCJi.js +8620 -0
  51. package/packages/gui/dist/assets/index-CVzz6zyb.css +1 -0
  52. package/packages/gui/dist/index.html +2 -2
  53. package/packages/gui/package.json +1 -1
  54. package/packages/gui/src/app.css +29 -0
  55. package/packages/gui/src/app.jsx +2 -0
  56. package/packages/gui/src/components/chat/chat-header.jsx +16 -5
  57. package/packages/gui/src/components/chat/chat-input.jsx +40 -7
  58. package/packages/gui/src/components/chat/chat-messages.jsx +149 -31
  59. package/packages/gui/src/components/chat/chat-view.jsx +26 -2
  60. package/packages/gui/src/components/chat/model-picker.jsx +105 -52
  61. package/packages/gui/src/components/layout/activity-bar.jsx +5 -2
  62. package/packages/gui/src/components/layout/welcome-splash.jsx +215 -88
  63. package/packages/gui/src/components/preview/preview-toolbar.jsx +81 -0
  64. package/packages/gui/src/components/preview/preview-workspace.jsx +263 -0
  65. package/packages/gui/src/components/preview/screenshot-overlay.jsx +203 -0
  66. package/packages/gui/src/components/ui/toast.jsx +6 -2
  67. package/packages/gui/src/stores/groove.js +149 -9
  68. package/packages/gui/src/views/preview.jsx +6 -0
  69. package/packages/gui/src/views/settings.jsx +278 -123
  70. package/node_modules/@groove-dev/gui/dist/assets/index-BFc7Ov6v.css +0 -1
  71. package/node_modules/@groove-dev/gui/dist/assets/index-Deza1S0i.js +0 -8615
  72. package/packages/gui/dist/assets/index-BFc7Ov6v.css +0 -1
  73. package/packages/gui/dist/assets/index-Deza1S0i.js +0 -8615
@@ -56,8 +56,13 @@ export const useGrooveStore = create((set, get) => ({
56
56
  selectedPeerId: null,
57
57
  },
58
58
 
59
+ // ── Preview ───────────────────────────────────────────────
60
+ previewState: { url: null, teamId: null, kind: null, deviceSize: 'desktop', screenshotMode: false },
61
+ previewChat: [],
62
+ previewIterating: false,
63
+
59
64
  // ── Navigation ────────────────────────────────────────────
60
- activeView: 'agents', // 'agents' | 'editor' | 'dashboard' | 'marketplace' | 'teams' | 'settings'
65
+ activeView: 'agents', // 'agents' | 'editor' | 'dashboard' | 'marketplace' | 'teams' | 'settings' | 'preview'
61
66
  detailPanel: null, // null | { type: 'agent', agentId } | { type: 'spawn' } | { type: 'journalist' }
62
67
  teamDetailPanels: {}, // { [teamId]: detailPanel } — persists panel state per team
63
68
  commandPaletteOpen: false,
@@ -455,21 +460,30 @@ export const useGrooveStore = create((set, get) => ({
455
460
  'success',
456
461
  'Project ready to preview',
457
462
  msg.url,
458
- { label: 'View Site', url: msg.url },
463
+ { label: 'Open Preview', onClick: () => get().openPreview(msg.url, msg.teamId, msg.kind) },
459
464
  { persistent: true },
460
465
  );
461
466
  break;
462
467
 
463
- case 'preview:failed':
464
- get().addToast(
465
- 'warning',
466
- 'Preview could not launch',
467
- msg.reason ? String(msg.reason).slice(0, 200) : 'Unknown error',
468
- );
468
+ case 'preview:failed': {
469
+ const failKind = msg.kind || '';
470
+ if (failKind !== 'no_preview' && failKind !== 'cli' && failKind !== 'none') {
471
+ get().addToast(
472
+ 'warning',
473
+ 'Preview could not launch',
474
+ msg.reason ? String(msg.reason).slice(0, 200) : 'Unknown error',
475
+ );
476
+ }
469
477
  break;
478
+ }
470
479
 
471
- case 'preview:stopped':
480
+ case 'preview:stopped': {
481
+ const ps = get().previewState;
482
+ if (ps.teamId && ps.teamId === msg.teamId) {
483
+ set({ previewState: { url: null, teamId: null, kind: null, deviceSize: 'desktop', screenshotMode: false }, previewChat: [], previewIterating: false });
484
+ }
472
485
  break;
486
+ }
473
487
 
474
488
  case 'agent:stalled': {
475
489
  const name = msg.agentName || msg.agentId;
@@ -899,6 +913,55 @@ export const useGrooveStore = create((set, get) => ({
899
913
  break;
900
914
  }
901
915
 
916
+ case 'conversation:image': {
917
+ const { conversationId, prompt, url, b64_json, mimeType, model: imgModel, provider: imgProvider } = msg.data || msg;
918
+ if (!conversationId) break;
919
+ const imageUrl = url || (b64_json ? `data:${mimeType || 'image/png'};base64,${b64_json}` : null);
920
+ set((s) => {
921
+ const msgs = { ...s.conversationMessages };
922
+ if (!msgs[conversationId]) msgs[conversationId] = [];
923
+ const arr = [...msgs[conversationId]];
924
+ const loadingIdx = arr.findLastIndex((m) => m.type === 'image-loading' && m.prompt === prompt);
925
+ if (loadingIdx >= 0) {
926
+ arr[loadingIdx] = { from: 'assistant', type: 'image', imageUrl, prompt, model: imgModel, provider: imgProvider, timestamp: Date.now() };
927
+ } else {
928
+ arr.push({ from: 'assistant', type: 'image', imageUrl, prompt, model: imgModel, provider: imgProvider, timestamp: Date.now() });
929
+ }
930
+ msgs[conversationId] = arr.slice(-200);
931
+ persistJSON('groove:conversationMessages', msgs);
932
+ const isActive = s.streamingConversationId === conversationId;
933
+ return { conversationMessages: msgs, sendingMessage: isActive ? false : s.sendingMessage, streamingConversationId: isActive ? null : s.streamingConversationId };
934
+ });
935
+ break;
936
+ }
937
+
938
+ case 'conversation:image-progress': {
939
+ const { conversationId, status, prompt: imgPrompt, error: imgError } = msg.data || msg;
940
+ if (!conversationId) break;
941
+ if (status === 'generating') {
942
+ set((s) => {
943
+ const msgs = { ...s.conversationMessages };
944
+ if (!msgs[conversationId]) msgs[conversationId] = [];
945
+ msgs[conversationId] = [...msgs[conversationId], { from: 'assistant', type: 'image-loading', prompt: imgPrompt, timestamp: Date.now() }];
946
+ return { conversationMessages: msgs, streamingConversationId: conversationId };
947
+ });
948
+ } else if (status === 'error') {
949
+ set((s) => {
950
+ const msgs = { ...s.conversationMessages };
951
+ if (!msgs[conversationId]) msgs[conversationId] = [];
952
+ const arr = [...msgs[conversationId]];
953
+ const loadingIdx = arr.findLastIndex((m) => m.type === 'image-loading');
954
+ if (loadingIdx >= 0) arr.splice(loadingIdx, 1);
955
+ arr.push({ from: 'system', text: `Image generation failed: ${imgError || 'Unknown error'}`, timestamp: Date.now() });
956
+ msgs[conversationId] = arr;
957
+ persistJSON('groove:conversationMessages', msgs);
958
+ const isActive = s.streamingConversationId === conversationId;
959
+ return { conversationMessages: msgs, sendingMessage: isActive ? false : s.sendingMessage, streamingConversationId: isActive ? null : s.streamingConversationId };
960
+ });
961
+ }
962
+ break;
963
+ }
964
+
902
965
  case 'conversation:error': {
903
966
  const { conversationId, error } = msg.data || msg;
904
967
  if (conversationId) {
@@ -1107,6 +1170,50 @@ export const useGrooveStore = create((set, get) => ({
1107
1170
  persistJSON('groove:expandedNodes', expanded);
1108
1171
  },
1109
1172
 
1173
+ // ── Preview ──────────────────────────────────────────────
1174
+
1175
+ openPreview(url, teamId, kind) {
1176
+ set({ previewState: { url, teamId, kind, deviceSize: 'desktop', screenshotMode: false }, previewChat: [], activeView: 'preview' });
1177
+ },
1178
+ closePreview() {
1179
+ const { previewState } = get();
1180
+ if (previewState.teamId) {
1181
+ api.delete(`/preview/${previewState.teamId}`).catch(() => {});
1182
+ }
1183
+ set({ previewState: { url: null, teamId: null, kind: null, deviceSize: 'desktop', screenshotMode: false }, previewChat: [], previewIterating: false, activeView: 'agents' });
1184
+ },
1185
+ setPreviewDevice(size) {
1186
+ set((s) => ({ previewState: { ...s.previewState, deviceSize: size } }));
1187
+ },
1188
+ toggleScreenshotMode() {
1189
+ set((s) => ({ previewState: { ...s.previewState, screenshotMode: !s.previewState.screenshotMode } }));
1190
+ },
1191
+ async iteratePreview(message, screenshotBase64) {
1192
+ const { previewState } = get();
1193
+ if (!previewState.teamId) return;
1194
+
1195
+ const userMsg = { role: 'user', content: message, screenshot: screenshotBase64 || null, timestamp: Date.now() };
1196
+ set((s) => ({ previewChat: [...s.previewChat, userMsg], previewIterating: true }));
1197
+
1198
+ try {
1199
+ const body = { message };
1200
+ if (screenshotBase64) body.screenshot = screenshotBase64;
1201
+ const res = await api.post(`/preview/${previewState.teamId}/iterate`, body);
1202
+ const assistantMsg = { role: 'assistant', content: res.response || res.message || 'Changes routed to planner.', timestamp: Date.now() };
1203
+ set((s) => ({ previewChat: [...s.previewChat, assistantMsg], previewIterating: false }));
1204
+ } catch (err) {
1205
+ const errMsg = { role: 'assistant', content: `Failed to iterate: ${err.message}`, timestamp: Date.now() };
1206
+ set((s) => ({ previewChat: [...s.previewChat, errMsg], previewIterating: false }));
1207
+ }
1208
+ },
1209
+ addPreviewChatMessage(role, content, screenshot) {
1210
+ const msg = { role, content, screenshot: screenshot || null, timestamp: Date.now() };
1211
+ set((s) => ({ previewChat: [...s.previewChat, msg] }));
1212
+ },
1213
+ clearPreviewChat() {
1214
+ set({ previewChat: [] });
1215
+ },
1216
+
1110
1217
  // ── Toasts ────────────────────────────────────────────────
1111
1218
 
1112
1219
  addToast(type, message, detail, action, options = {}) {
@@ -1488,6 +1595,13 @@ export const useGrooveStore = create((set, get) => ({
1488
1595
  get().fetchTreeDir('');
1489
1596
  },
1490
1597
 
1598
+ async removeRecentProject(path) {
1599
+ try {
1600
+ await api.delete('/projects/recent', { path });
1601
+ } catch {}
1602
+ get().fetchProjectDir();
1603
+ },
1604
+
1491
1605
  toggleProjectPicker() {
1492
1606
  set((s) => ({ showProjectPicker: !s.showProjectPicker }));
1493
1607
  },
@@ -1977,6 +2091,32 @@ export const useGrooveStore = create((set, get) => ({
1977
2091
  }
1978
2092
  },
1979
2093
 
2094
+ async sendImageMessage(conversationId, prompt, { model, size, quality } = {}) {
2095
+ const conv = get().conversations.find((c) => c.id === conversationId);
2096
+ if (!conv) return;
2097
+
2098
+ set((s) => {
2099
+ const msgs = { ...s.conversationMessages };
2100
+ if (!msgs[conversationId]) msgs[conversationId] = [];
2101
+ msgs[conversationId] = [...msgs[conversationId], { from: 'user', text: prompt, timestamp: Date.now() }];
2102
+ persistJSON('groove:conversationMessages', msgs);
2103
+ return { conversationMessages: msgs, sendingMessage: true, streamingConversationId: conversationId };
2104
+ });
2105
+
2106
+ try {
2107
+ await api.post(`/conversations/${encodeURIComponent(conversationId)}/generate-image`, { prompt, model, size, quality });
2108
+ } catch (err) {
2109
+ set((s) => {
2110
+ const msgs = { ...s.conversationMessages };
2111
+ if (!msgs[conversationId]) msgs[conversationId] = [];
2112
+ msgs[conversationId] = [...msgs[conversationId], { from: 'system', text: `Image failed: ${err.message}`, timestamp: Date.now() }];
2113
+ persistJSON('groove:conversationMessages', msgs);
2114
+ return { conversationMessages: msgs, sendingMessage: false, streamingConversationId: null };
2115
+ });
2116
+ get().addToast('error', 'Image generation failed', err.message);
2117
+ }
2118
+ },
2119
+
1980
2120
  // ── Editor ────────────────────────────────────────────────
1981
2121
 
1982
2122
  async openFile(path) {
@@ -0,0 +1,6 @@
1
+ // FSL-1.1-Apache-2.0 — see LICENSE
2
+ import { PreviewWorkspace } from '../components/preview/preview-workspace';
3
+
4
+ export default function PreviewView() {
5
+ return <PreviewWorkspace />;
6
+ }