groove-dev 0.27.155 → 0.27.156

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.
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <link rel="icon" type="image/png" href="/favicon.png" />
8
8
  <title>Groove GUI</title>
9
- <script type="module" crossorigin src="/assets/index-BTLb6zTD.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-COQYX12F.js"></script>
10
10
  <link rel="modulepreload" crossorigin href="/assets/vendor-26L3JoZv.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/reactflow-DoBZjiHE.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/codemirror-BYKpdS2W.js">
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.27.155",
3
+ "version": "0.27.156",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -106,10 +106,10 @@ function ContextMenu({ x, y, items, onClose }) {
106
106
  );
107
107
  }
108
108
 
109
- function downloadFile(path) {
109
+ function downloadFile(path, isDir) {
110
110
  const a = document.createElement('a');
111
111
  a.href = `/api/files/download?path=${encodeURIComponent(path)}`;
112
- a.download = path.split('/').pop();
112
+ a.download = isDir ? `${path.split('/').pop()}.zip` : path.split('/').pop();
113
113
  document.body.appendChild(a);
114
114
  a.click();
115
115
  a.remove();
@@ -138,8 +138,8 @@ function TreeEntry({ entry, depth, onOpen, expandedDirs, onToggleDir, onContextM
138
138
  onDragStartEntry(entry.path);
139
139
  }}
140
140
  onDragEnd={onDragEndEntry}
141
- onDragOver={isDir ? (e) => { e.preventDefault(); e.stopPropagation(); onSetDragOver(entry.path); } : undefined}
142
- onDrop={isDir ? (e) => onDropOnDir(entry.path, e) : undefined}
141
+ onDragOver={(e) => { e.preventDefault(); if (isDir) { e.stopPropagation(); onSetDragOver(entry.path); } }}
142
+ onDrop={(e) => onDropOnDir(isDir ? entry.path : (entry.path.includes('/') ? entry.path.split('/').slice(0, -1).join('/') : ''), e)}
143
143
  onClick={() => isDir ? onToggleDir(entry.path) : onOpen(entry.path)}
144
144
  onDoubleClick={handleCtxMenu}
145
145
  onContextMenu={handleCtxMenu}
@@ -500,11 +500,9 @@ export function AgentFileTree({ agentId, onCollapse }) {
500
500
  if (isDir) {
501
501
  items.push({ icon: FilePlus, label: 'New File', action: () => handleNewFileIn(entry.path) });
502
502
  items.push({ icon: FolderPlus, label: 'New Folder', action: () => handleNewFolderIn(entry.path) });
503
- items.push({ separator: true });
504
- } else {
505
- items.push({ icon: Download, label: 'Download', action: () => downloadFile(entry.path) });
506
- items.push({ separator: true });
507
503
  }
504
+ items.push({ icon: Download, label: isDir ? 'Download as ZIP' : 'Download', action: () => downloadFile(entry.path, isDir) });
505
+ items.push({ separator: true });
508
506
  items.push({ icon: Pencil, label: 'Rename', action: () => handleRename(entry) });
509
507
  items.push({ icon: Trash2, label: 'Delete', danger: true, action: () => handleDelete(entry) });
510
508
  return items;
@@ -533,7 +531,11 @@ export function AgentFileTree({ agentId, onCollapse }) {
533
531
  )}
534
532
  </div>
535
533
  <ScrollArea className="flex-1 min-h-0">
536
- <div className="py-2">
534
+ <div
535
+ className="py-2 min-h-full"
536
+ onDragOver={(e) => { e.preventDefault(); if (dragState.draggingPath) setDragOverDir(null); }}
537
+ onDrop={(e) => handleDropOnDir('', e)}
538
+ >
537
539
  {inlineInput && (
538
540
  <InlineInput
539
541
  placeholder={inlineInput.type === 'file' ? 'filename.ext' : 'folder-name'}
@@ -595,11 +597,7 @@ export function AgentFileTree({ agentId, onCollapse }) {
595
597
  No files in scope
596
598
  </div>
597
599
  ) : (
598
- <div
599
- className="px-1"
600
- onDragOver={(e) => { e.preventDefault(); if (dragState.draggingPath) setDragOverDir(null); }}
601
- onDrop={(e) => handleDropOnDir('', e)}
602
- >
600
+ <div className="px-1">
603
601
  <div className="flex items-center gap-1.5 px-2 py-1.5 text-2xs font-semibold text-text-3 uppercase tracking-wider">
604
602
  <Folder size={10} />
605
603
  Scope
@@ -107,10 +107,10 @@ function GitDot({ status }) {
107
107
  return <span className={cn('w-1.5 h-1.5 rounded-full flex-shrink-0', color)} />;
108
108
  }
109
109
 
110
- function downloadFile(path) {
110
+ function downloadFile(path, isDir) {
111
111
  const a = document.createElement('a');
112
112
  a.href = `/api/files/download?path=${encodeURIComponent(path)}`;
113
- a.download = path.split('/').pop();
113
+ a.download = isDir ? `${path.split('/').pop()}.zip` : path.split('/').pop();
114
114
  document.body.appendChild(a);
115
115
  a.click();
116
116
  a.remove();
@@ -140,8 +140,8 @@ function TreeNode({ entry, depth = 0, activePath, onFileClick, onDirToggle, expa
140
140
  onDragStartEntry(entry.path);
141
141
  }}
142
142
  onDragEnd={onDragEndEntry}
143
- onDragOver={isDir ? (e) => { e.preventDefault(); e.stopPropagation(); onSetDragOver(entry.path); } : undefined}
144
- onDrop={isDir ? (e) => onDropOnDir(entry.path, e) : undefined}
143
+ onDragOver={(e) => { e.preventDefault(); if (isDir) { e.stopPropagation(); onSetDragOver(entry.path); } }}
144
+ onDrop={(e) => onDropOnDir(isDir ? entry.path : (entry.path.includes('/') ? entry.path.split('/').slice(0, -1).join('/') : ''), e)}
145
145
  onClick={() => isDir ? onDirToggle(entry.path) : onFileClick(entry.path)}
146
146
  onDoubleClick={handleContextMenu}
147
147
  onContextMenu={handleContextMenu}
@@ -455,9 +455,7 @@ export function FileTree({ rootDir, onCollapse }) {
455
455
  }
456
456
 
457
457
  if (entry.name !== 'root') {
458
- if (!isDir) {
459
- items.push({ icon: Download, label: 'Download', action: () => downloadFile(entry.path) });
460
- }
458
+ items.push({ icon: Download, label: isDir ? 'Download as ZIP' : 'Download', action: () => downloadFile(entry.path, isDir) });
461
459
  if (items.length > 0) items.push({ separator: true });
462
460
  items.push({ icon: Pencil, label: 'Rename', action: () => handleRename(entry) });
463
461
  items.push({ icon: Trash2, label: 'Delete', danger: true, action: () => handleDelete(entry) });
@@ -527,7 +525,7 @@ export function FileTree({ rootDir, onCollapse }) {
527
525
  {/* Tree */}
528
526
  <ScrollArea className="flex-1">
529
527
  <div
530
- className="py-1"
528
+ className="py-1 min-h-full"
531
529
  onDragOver={(e) => { e.preventDefault(); if (dragState.draggingPath) setDragOverDir(null); }}
532
530
  onDrop={(e) => handleDropOnDir('', e)}
533
531
  >