groove-dev 0.27.156 → 0.27.159

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 (91) 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/journalist.js +61 -16
  4. package/node_modules/@groove-dev/daemon/src/process.js +130 -2
  5. package/node_modules/@groove-dev/daemon/src/rotator.js +2 -1
  6. package/node_modules/@groove-dev/daemon/src/routes/files.js +28 -6
  7. package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +89 -71
  8. package/node_modules/@groove-dev/gui/dist/assets/index-Bij9o_dc.js +1020 -0
  9. package/node_modules/@groove-dev/gui/dist/assets/index-Dzofq3wS.css +1 -0
  10. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  11. package/node_modules/@groove-dev/gui/package.json +1 -2
  12. package/node_modules/@groove-dev/gui/src/app.css +2 -2
  13. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +8 -8
  14. package/node_modules/@groove-dev/gui/src/components/agents/diff-viewer.jsx +2 -2
  15. package/node_modules/@groove-dev/gui/src/components/agents/workspace-mode.jsx +11 -2
  16. package/node_modules/@groove-dev/gui/src/components/dashboard/cache-ring.jsx +2 -2
  17. package/node_modules/@groove-dev/gui/src/components/dashboard/token-chart.jsx +2 -2
  18. package/node_modules/@groove-dev/gui/src/components/editor/terminal.jsx +1 -1
  19. package/node_modules/@groove-dev/gui/src/components/layout/welcome-splash.jsx +8 -1
  20. package/node_modules/@groove-dev/gui/src/components/network/activity-chart.jsx +4 -4
  21. package/node_modules/@groove-dev/gui/src/components/network/performance-dashboard.jsx +1 -1
  22. package/node_modules/@groove-dev/gui/src/components/settings/quick-connect.jsx +18 -6
  23. package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +122 -17
  24. package/node_modules/@groove-dev/gui/src/stores/groove.js +9 -1
  25. package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +69 -38
  26. package/node_modules/@groove-dev/gui/src/views/memory.jsx +121 -49
  27. package/package.json +1 -1
  28. package/packages/cli/package.json +1 -1
  29. package/packages/daemon/package.json +1 -1
  30. package/packages/daemon/src/journalist.js +61 -16
  31. package/packages/daemon/src/process.js +130 -2
  32. package/packages/daemon/src/rotator.js +2 -1
  33. package/packages/daemon/src/routes/files.js +28 -6
  34. package/packages/daemon/src/tunnel-manager.js +89 -71
  35. package/packages/gui/dist/assets/index-Bij9o_dc.js +1020 -0
  36. package/packages/gui/dist/assets/index-Dzofq3wS.css +1 -0
  37. package/packages/gui/dist/index.html +2 -2
  38. package/packages/gui/package.json +1 -2
  39. package/packages/gui/src/app.css +2 -2
  40. package/packages/gui/src/components/agents/agent-feed.jsx +8 -8
  41. package/packages/gui/src/components/agents/diff-viewer.jsx +2 -2
  42. package/packages/gui/src/components/agents/workspace-mode.jsx +11 -2
  43. package/packages/gui/src/components/dashboard/cache-ring.jsx +2 -2
  44. package/packages/gui/src/components/dashboard/token-chart.jsx +2 -2
  45. package/packages/gui/src/components/editor/terminal.jsx +1 -1
  46. package/packages/gui/src/components/layout/welcome-splash.jsx +8 -1
  47. package/packages/gui/src/components/network/activity-chart.jsx +4 -4
  48. package/packages/gui/src/components/network/performance-dashboard.jsx +1 -1
  49. package/packages/gui/src/components/settings/quick-connect.jsx +18 -6
  50. package/packages/gui/src/components/settings/ssh-wizard.jsx +122 -17
  51. package/packages/gui/src/stores/groove.js +9 -1
  52. package/packages/gui/src/stores/slices/agents-slice.js +69 -38
  53. package/packages/gui/src/views/memory.jsx +121 -49
  54. package/ssh/error.png +0 -0
  55. package/node_modules/@fontsource-variable/jetbrains-mono/CHANGELOG.md +0 -2
  56. package/node_modules/@fontsource-variable/jetbrains-mono/LICENSE +0 -93
  57. package/node_modules/@fontsource-variable/jetbrains-mono/README.md +0 -48
  58. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-cyrillic-ext-wght-italic.woff2 +0 -0
  59. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-cyrillic-ext-wght-normal.woff2 +0 -0
  60. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-cyrillic-wght-italic.woff2 +0 -0
  61. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-cyrillic-wght-normal.woff2 +0 -0
  62. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-greek-wght-italic.woff2 +0 -0
  63. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-greek-wght-normal.woff2 +0 -0
  64. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-latin-ext-wght-italic.woff2 +0 -0
  65. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-latin-ext-wght-normal.woff2 +0 -0
  66. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-latin-wght-italic.woff2 +0 -0
  67. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-latin-wght-normal.woff2 +0 -0
  68. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-vietnamese-wght-italic.woff2 +0 -0
  69. package/node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-vietnamese-wght-normal.woff2 +0 -0
  70. package/node_modules/@fontsource-variable/jetbrains-mono/index.css +0 -59
  71. package/node_modules/@fontsource-variable/jetbrains-mono/metadata.json +0 -29
  72. package/node_modules/@fontsource-variable/jetbrains-mono/package.json +0 -47
  73. package/node_modules/@fontsource-variable/jetbrains-mono/scss/metadata.scss +0 -46
  74. package/node_modules/@fontsource-variable/jetbrains-mono/scss/mixins.scss +0 -193
  75. package/node_modules/@fontsource-variable/jetbrains-mono/unicode.json +0 -8
  76. package/node_modules/@fontsource-variable/jetbrains-mono/wght-italic.css +0 -59
  77. package/node_modules/@fontsource-variable/jetbrains-mono/wght.css +0 -59
  78. package/node_modules/@groove-dev/gui/dist/assets/index-COQYX12F.js +0 -1015
  79. package/node_modules/@groove-dev/gui/dist/assets/index-Diw6wDPU.css +0 -1
  80. package/node_modules/@groove-dev/gui/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  81. package/node_modules/@groove-dev/gui/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  82. package/node_modules/@groove-dev/gui/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  83. package/node_modules/@groove-dev/gui/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  84. package/node_modules/@groove-dev/gui/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  85. package/packages/gui/dist/assets/index-COQYX12F.js +0 -1015
  86. package/packages/gui/dist/assets/index-Diw6wDPU.css +0 -1
  87. package/packages/gui/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  88. package/packages/gui/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  89. package/packages/gui/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  90. package/packages/gui/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  91. package/packages/gui/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
@@ -4,7 +4,7 @@ import { useGrooveStore } from '../stores/groove';
4
4
  import { Button } from '../components/ui/button';
5
5
  import { ScrollArea } from '../components/ui/scroll-area';
6
6
  import { Dialog, DialogContent } from '../components/ui/dialog';
7
- import { BookOpen, Plus, Search, Trash2, Pencil, ChevronRight, Hash, FolderOpen, Clock, Save, Link2, FileText, Sparkles, HelpCircle, GripVertical } from 'lucide-react';
7
+ import { BookOpen, Plus, Search, Trash2, Pencil, ChevronRight, Hash, FolderOpen, Clock, Save, Link2, FileText, Sparkles, HelpCircle, GripVertical, CornerLeftUp } from 'lucide-react';
8
8
 
9
9
  const COMMANDS = [
10
10
  { cmd: 'save', args: '#tag', desc: 'Save the message and send it to the agent' },
@@ -114,7 +114,7 @@ function MemoryCard({ item, onEdit, onDelete }) {
114
114
  );
115
115
  }
116
116
 
117
- function EditorModal({ open, onOpenChange, editing, onSave }) {
117
+ function EditorModal({ open, onOpenChange, editing, onSave, onRename }) {
118
118
  const [tag, setTag] = useState('');
119
119
  const [content, setContent] = useState('');
120
120
  const textareaRef = useRef(null);
@@ -132,9 +132,15 @@ function EditorModal({ open, onOpenChange, editing, onSave }) {
132
132
  }
133
133
  }, [open]);
134
134
 
135
- const handleSave = () => {
135
+ const handleSave = async () => {
136
136
  if (!tag.trim() || editing?.readOnly) return;
137
- onSave(tag.trim(), content);
137
+ const originalTag = editing?.tag || '';
138
+ const newTag = tag.trim();
139
+ if (!editing?.isNew && newTag !== originalTag) {
140
+ await onRename(originalTag, newTag, content);
141
+ } else {
142
+ onSave(newTag, content);
143
+ }
138
144
  onOpenChange(false);
139
145
  };
140
146
 
@@ -148,27 +154,30 @@ function EditorModal({ open, onOpenChange, editing, onSave }) {
148
154
  const isNew = editing?.isNew;
149
155
  const readOnly = editing?.readOnly;
150
156
  const title = readOnly ? `#${editing?.tag || ''}` : isNew ? 'New Memory' : `Edit #${editing?.tag || ''}`;
157
+ const tagChanged = !isNew && tag.trim() !== (editing?.tag || '');
151
158
 
152
159
  return (
153
160
  <Dialog open={open} onOpenChange={onOpenChange}>
154
161
  <DialogContent title={title} description="Memory content" className="max-w-2xl">
155
162
  <div className="p-5 space-y-4" onKeyDown={handleKeyDown}>
156
- {isNew && (
157
- <div>
158
- <label className="block text-xs font-medium text-text-2 mb-1.5">Tag</label>
159
- <div className="flex items-center gap-1">
160
- <span className="text-sm text-text-3">#</span>
161
- <input
162
- type="text"
163
- value={tag}
164
- onChange={(e) => setTag(e.target.value.replace(/[^a-zA-Z0-9/_-]/g, '').toLowerCase())}
165
- placeholder="project/feature-name"
166
- className="flex-1 px-2 py-1.5 text-sm font-mono rounded-md bg-surface-0 border border-border text-text-0 placeholder:text-text-4 focus:outline-none focus:ring-1 focus:ring-accent"
167
- />
168
- </div>
169
- <p className="text-2xs text-text-4 mt-1">Use / for hierarchy: groove/memory-system</p>
163
+ <div>
164
+ <label className="block text-xs font-medium text-text-2 mb-1.5">
165
+ {isNew ? 'Tag' : 'Title'}
166
+ {tagChanged && <span className="ml-2 text-2xs text-warning">(will rename)</span>}
167
+ </label>
168
+ <div className="flex items-center gap-1">
169
+ <span className="text-sm text-text-3">#</span>
170
+ <input
171
+ type="text"
172
+ value={tag}
173
+ onChange={(e) => !readOnly && setTag(e.target.value.replace(/[^a-zA-Z0-9/_-]/g, '').toLowerCase())}
174
+ readOnly={readOnly}
175
+ placeholder="project/feature-name"
176
+ className="flex-1 px-2 py-1.5 text-sm font-mono rounded-md bg-surface-0 border border-border text-text-0 placeholder:text-text-4 focus:outline-none focus:ring-1 focus:ring-accent"
177
+ />
170
178
  </div>
171
- )}
179
+ {isNew && <p className="text-2xs text-text-4 mt-1">Use / for hierarchy: groove/memory-system</p>}
180
+ </div>
172
181
  <div>
173
182
  {!readOnly && <label className="block text-xs font-medium text-text-2 mb-1.5">Content</label>}
174
183
  <textarea
@@ -196,7 +205,7 @@ function EditorModal({ open, onOpenChange, editing, onSave }) {
196
205
  {!readOnly && (
197
206
  <Button variant="primary" size="sm" onClick={handleSave} disabled={!tag.trim()}>
198
207
  <Save size={14} />
199
- Save
208
+ {tagChanged ? 'Rename & Save' : 'Save'}
200
209
  </Button>
201
210
  )}
202
211
  </div>
@@ -249,7 +258,7 @@ function InstructModal({ open, onOpenChange }) {
249
258
  );
250
259
  }
251
260
 
252
- function TreeItem({ tag, label, isDoc, indent, isDragOver, onSelect, onDragStart, onDragOver, onDragLeave, onDrop }) {
261
+ function TreeItem({ tag, label, isDoc, indent, isDragOver, onSelect, onEdit, onDelete, onDragStart, onDragOver, onDragLeave, onDrop }) {
253
262
  return (
254
263
  <div
255
264
  draggable
@@ -257,19 +266,34 @@ function TreeItem({ tag, label, isDoc, indent, isDragOver, onSelect, onDragStart
257
266
  onDragOver={(e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; onDragOver?.(tag); }}
258
267
  onDragLeave={() => onDragLeave?.()}
259
268
  onDrop={(e) => { e.preventDefault(); onDrop?.(e.dataTransfer.getData('text/plain'), tag); }}
260
- onClick={() => onSelect({ tag })}
261
269
  className={`flex items-center gap-1.5 w-full px-2 py-1.5 rounded-md text-xs transition-colors cursor-pointer group ${isDragOver ? 'bg-accent/15 border border-accent/30 border-dashed' : 'hover:bg-surface-2'}`}
262
270
  style={indent ? { paddingLeft: `${8 + indent * 16}px` } : undefined}
263
271
  >
264
272
  <GripVertical size={10} className="text-text-4 opacity-0 group-hover:opacity-50 flex-shrink-0 cursor-grab" />
265
273
  <Hash size={11} className="text-text-4 flex-shrink-0" />
266
- <span className="font-medium text-text-2 truncate">{label}</span>
274
+ <span className="font-medium text-text-2 truncate flex-1" onClick={() => onSelect({ tag })}>{label}</span>
267
275
  {isDoc && <Sparkles size={9} className="text-purple flex-shrink-0" />}
276
+ <div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0">
277
+ <button
278
+ onClick={(e) => { e.stopPropagation(); onEdit?.({ tag }); }}
279
+ className="p-1 rounded text-text-4 hover:text-accent hover:bg-accent/10 transition-colors cursor-pointer"
280
+ title="Edit"
281
+ >
282
+ <Pencil size={11} />
283
+ </button>
284
+ <button
285
+ onClick={(e) => { e.stopPropagation(); onDelete?.(tag); }}
286
+ className="p-1 rounded text-text-4 hover:text-danger hover:bg-danger/10 transition-colors cursor-pointer"
287
+ title="Delete"
288
+ >
289
+ <Trash2 size={11} />
290
+ </button>
291
+ </div>
268
292
  </div>
269
293
  );
270
294
  }
271
295
 
272
- function TreeGroup({ node, onSelect, dragOverTag, onDragStart, onDragOver, onDragLeave, onDrop }) {
296
+ function TreeGroup({ node, onSelect, onEdit, onDelete, dragOverTag, onDragStart, onDragOver, onDragLeave, onDrop }) {
273
297
  const [expanded, setExpanded] = useState(true);
274
298
  const hasChildren = node.children && node.children.length > 0;
275
299
 
@@ -278,7 +302,8 @@ function TreeGroup({ node, onSelect, dragOverTag, onDragStart, onDragOver, onDra
278
302
  <TreeItem
279
303
  tag={node.tag} label={node.tag} isDoc={node.type === 'doc'}
280
304
  isDragOver={dragOverTag === node.tag}
281
- onSelect={onSelect} onDragStart={onDragStart} onDragOver={onDragOver} onDragLeave={onDragLeave} onDrop={onDrop}
305
+ onSelect={onSelect} onEdit={onEdit} onDelete={onDelete}
306
+ onDragStart={onDragStart} onDragOver={onDragOver} onDragLeave={onDragLeave} onDrop={onDrop}
282
307
  />
283
308
  );
284
309
  }
@@ -305,14 +330,16 @@ function TreeGroup({ node, onSelect, dragOverTag, onDragStart, onDragOver, onDra
305
330
  <TreeItem
306
331
  tag={node.tag} label={node.tag} isDoc={node.type === 'doc'} indent={1}
307
332
  isDragOver={false}
308
- onSelect={onSelect} onDragStart={onDragStart} onDragOver={onDragOver} onDragLeave={onDragLeave} onDrop={onDrop}
333
+ onSelect={onSelect} onEdit={onEdit} onDelete={onDelete}
334
+ onDragStart={onDragStart} onDragOver={onDragOver} onDragLeave={onDragLeave} onDrop={onDrop}
309
335
  />
310
336
  )}
311
337
  {node.children.map((child) => (
312
338
  <TreeItem
313
339
  key={child.tag} tag={child.tag} label={child.tag.split('/').pop()} isDoc={child.type === 'doc'} indent={1}
314
340
  isDragOver={dragOverTag === child.tag}
315
- onSelect={onSelect} onDragStart={onDragStart} onDragOver={onDragOver} onDragLeave={onDragLeave} onDrop={onDrop}
341
+ onSelect={onSelect} onEdit={onEdit} onDelete={onDelete}
342
+ onDragStart={onDragStart} onDragOver={onDragOver} onDragLeave={onDragLeave} onDrop={onDrop}
316
343
  />
317
344
  ))}
318
345
  </div>
@@ -335,7 +362,7 @@ export default function MemoryView() {
335
362
  const setKeeperEditing = useGrooveStore((s) => s.setKeeperEditing);
336
363
 
337
364
  const [search, setSearch] = useState('');
338
- const [viewMode, setViewMode] = useState('list');
365
+ const [viewMode, setViewMode] = useState('tree');
339
366
  const [editorOpen, setEditorOpen] = useState(false);
340
367
  const [dragOverTag, setDragOverTag] = useState(null);
341
368
  const [draggingTag, setDraggingTag] = useState(null);
@@ -346,10 +373,23 @@ export default function MemoryView() {
346
373
  if (keeperEditing) setEditorOpen(true);
347
374
  }, [keeperEditing]);
348
375
 
349
- const filtered = search
350
- ? keeperItems.filter((item) => item.tag.includes(search.toLowerCase()))
376
+ const searchLower = search.toLowerCase();
377
+ const filtered = searchLower
378
+ ? keeperItems.filter((item) => item.tag.includes(searchLower))
351
379
  : keeperItems;
352
380
 
381
+ const filteredTree = searchLower
382
+ ? keeperTree
383
+ .map((node) => {
384
+ const tagMatch = node.tag.includes(searchLower);
385
+ const matchingChildren = (node.children || []).filter((c) => c.tag.includes(searchLower));
386
+ if (tagMatch) return node;
387
+ if (matchingChildren.length > 0) return { ...node, children: matchingChildren };
388
+ return null;
389
+ })
390
+ .filter(Boolean)
391
+ : keeperTree;
392
+
353
393
  const handleNew = () => {
354
394
  setKeeperEditing({ tag: '', content: '', isNew: true });
355
395
  setEditorOpen(true);
@@ -370,6 +410,12 @@ export default function MemoryView() {
370
410
  setKeeperEditing(null);
371
411
  };
372
412
 
413
+ const handleRename = async (oldTag, newTag, content) => {
414
+ await moveKeeperItem(oldTag, newTag);
415
+ await updateKeeperItem(newTag, content);
416
+ setKeeperEditing(null);
417
+ };
418
+
373
419
  const handleEditorClose = (open) => {
374
420
  setEditorOpen(open);
375
421
  if (!open) setKeeperEditing(null);
@@ -384,10 +430,9 @@ export default function MemoryView() {
384
430
  setDragOverTag(null);
385
431
  setDraggingTag(null);
386
432
  if (!sourceTag || !targetTag || sourceTag === targetTag) return;
387
- // Don't drop onto self or own children
388
433
  if (targetTag.startsWith(sourceTag + '/')) return;
389
434
  const sourceName = sourceTag.split('/').pop();
390
- const newTag = targetTag + '/' + sourceName;
435
+ const newTag = targetTag === '__root__' ? sourceName : targetTag + '/' + sourceName;
391
436
  if (sourceTag === newTag) return;
392
437
  try {
393
438
  await moveKeeperItem(sourceTag, newTag);
@@ -464,24 +509,50 @@ export default function MemoryView() {
464
509
  </div>
465
510
  </div>
466
511
  ) : viewMode === 'tree' ? (
467
- <div className="p-3 space-y-0.5" onDragOver={(e) => e.preventDefault()}>
468
- {keeperTree.map((node) => (
469
- <TreeGroup
470
- key={node.tag} node={node} onSelect={handleTreeSelect}
471
- dragOverTag={dragOverTag}
472
- onDragStart={(tag) => setDraggingTag(tag)}
473
- onDragOver={(tag) => { if (tag !== draggingTag) setDragOverTag(tag); }}
474
- onDragLeave={() => setDragOverTag(null)}
475
- onDrop={handleDrop}
476
- />
477
- ))}
478
- </div>
512
+ filteredTree.length === 0 ? (
513
+ <div className="flex flex-col items-center justify-center h-32 gap-2">
514
+ <Search size={18} className="text-text-4" />
515
+ <p className="text-xs text-text-3">No memories matching &ldquo;{search}&rdquo;</p>
516
+ </div>
517
+ ) : (
518
+ <div className="p-3 space-y-0.5" onDragOver={(e) => e.preventDefault()}>
519
+ {filteredTree.map((node) => (
520
+ <TreeGroup
521
+ key={node.tag} node={node} onSelect={handleTreeSelect}
522
+ onEdit={handleEdit} onDelete={(tag) => deleteKeeperItem(tag)}
523
+ dragOverTag={dragOverTag}
524
+ onDragStart={(tag) => setDraggingTag(tag)}
525
+ onDragOver={(tag) => { if (tag !== draggingTag) setDragOverTag(tag); }}
526
+ onDragLeave={() => setDragOverTag(null)}
527
+ onDrop={handleDrop}
528
+ />
529
+ ))}
530
+ {draggingTag && draggingTag.includes('/') && (
531
+ <div
532
+ onDragOver={(e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; setDragOverTag('__root__'); }}
533
+ onDragLeave={() => setDragOverTag(null)}
534
+ onDrop={(e) => { e.preventDefault(); handleDrop(e.dataTransfer.getData('text/plain'), '__root__'); }}
535
+ className={`flex items-center gap-2 px-3 py-2 mt-2 rounded-md border border-dashed text-xs transition-colors ${dragOverTag === '__root__' ? 'border-accent/50 bg-accent/10 text-accent' : 'border-border text-text-4'}`}
536
+ >
537
+ <CornerLeftUp size={12} />
538
+ <span>Drop here to move to root</span>
539
+ </div>
540
+ )}
541
+ </div>
542
+ )
479
543
  ) : (
480
- <div className="p-3 space-y-2">
481
- {filtered.map((item) => (
482
- <MemoryCard key={item.tag} item={item} onEdit={handleEdit} onDelete={(tag) => deleteKeeperItem(tag)} />
483
- ))}
484
- </div>
544
+ filtered.length === 0 ? (
545
+ <div className="flex flex-col items-center justify-center h-32 gap-2">
546
+ <Search size={18} className="text-text-4" />
547
+ <p className="text-xs text-text-3">No memories matching &ldquo;{search}&rdquo;</p>
548
+ </div>
549
+ ) : (
550
+ <div className="p-3 space-y-2">
551
+ {filtered.map((item) => (
552
+ <MemoryCard key={item.tag} item={item} onEdit={handleEdit} onDelete={(tag) => deleteKeeperItem(tag)} />
553
+ ))}
554
+ </div>
555
+ )
485
556
  )}
486
557
  </ScrollArea>
487
558
 
@@ -491,6 +562,7 @@ export default function MemoryView() {
491
562
  onOpenChange={handleEditorClose}
492
563
  editing={keeperEditing}
493
564
  onSave={handleSave}
565
+ onRename={handleRename}
494
566
  />
495
567
 
496
568
  {/* Instruct Modal (command reference) */}
package/ssh/error.png ADDED
Binary file
@@ -1,2 +0,0 @@
1
- # Changelog
2
- See the [Fontsource CHANGELOG.md](https://github.com/fontsource/fontsource/blob/main/CHANGELOG.md).
@@ -1,93 +0,0 @@
1
- Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) JetBrainsMono-Italic[wght].ttf: Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
2
-
3
- This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
- This license is copied below, and is also available with a FAQ at:
5
- http://scripts.sil.org/OFL
6
-
7
-
8
- -----------------------------------------------------------
9
- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
- -----------------------------------------------------------
11
-
12
- PREAMBLE
13
- The goals of the Open Font License (OFL) are to stimulate worldwide
14
- development of collaborative font projects, to support the font creation
15
- efforts of academic and linguistic communities, and to provide a free and
16
- open framework in which fonts may be shared and improved in partnership
17
- with others.
18
-
19
- The OFL allows the licensed fonts to be used, studied, modified and
20
- redistributed freely as long as they are not sold by themselves. The
21
- fonts, including any derivative works, can be bundled, embedded,
22
- redistributed and/or sold with any software provided that any reserved
23
- names are not used by derivative works. The fonts and derivatives,
24
- however, cannot be released under any other type of license. The
25
- requirement for fonts to remain under this license does not apply
26
- to any document created using the fonts or their derivatives.
27
-
28
- DEFINITIONS
29
- "Font Software" refers to the set of files released by the Copyright
30
- Holder(s) under this license and clearly marked as such. This may
31
- include source files, build scripts and documentation.
32
-
33
- "Reserved Font Name" refers to any names specified as such after the
34
- copyright statement(s).
35
-
36
- "Original Version" refers to the collection of Font Software components as
37
- distributed by the Copyright Holder(s).
38
-
39
- "Modified Version" refers to any derivative made by adding to, deleting,
40
- or substituting -- in part or in whole -- any of the components of the
41
- Original Version, by changing formats or by porting the Font Software to a
42
- new environment.
43
-
44
- "Author" refers to any designer, engineer, programmer, technical
45
- writer or other person who contributed to the Font Software.
46
-
47
- PERMISSION & CONDITIONS
48
- Permission is hereby granted, free of charge, to any person obtaining
49
- a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
- redistribute, and sell modified and unmodified copies of the Font
51
- Software, subject to the following conditions:
52
-
53
- 1) Neither the Font Software nor any of its individual components,
54
- in Original or Modified Versions, may be sold by itself.
55
-
56
- 2) Original or Modified Versions of the Font Software may be bundled,
57
- redistributed and/or sold with any software, provided that each copy
58
- contains the above copyright notice and this license. These can be
59
- included either as stand-alone text files, human-readable headers or
60
- in the appropriate machine-readable metadata fields within text or
61
- binary files as long as those fields can be easily viewed by the user.
62
-
63
- 3) No Modified Version of the Font Software may use the Reserved Font
64
- Name(s) unless explicit written permission is granted by the corresponding
65
- Copyright Holder. This restriction only applies to the primary font name as
66
- presented to the users.
67
-
68
- 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
- Software shall not be used to promote, endorse or advertise any
70
- Modified Version, except to acknowledge the contribution(s) of the
71
- Copyright Holder(s) and the Author(s) or with their explicit written
72
- permission.
73
-
74
- 5) The Font Software, modified or unmodified, in part or in whole,
75
- must be distributed entirely under this license, and must not be
76
- distributed under any other license. The requirement for fonts to
77
- remain under this license does not apply to any document created
78
- using the Font Software.
79
-
80
- TERMINATION
81
- This license becomes null and void if any of the above conditions are
82
- not met.
83
-
84
- DISCLAIMER
85
- THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
- OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
- COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
- INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
- DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
- FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
- OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -1,48 +0,0 @@
1
- # Fontsource JetBrains Mono
2
-
3
- [![npm (scoped)](https://img.shields.io/npm/v/@fontsource-variable/jetbrains-mono?color=brightgreen)](https://www.npmjs.com/package/@fontsource-variable/jetbrains-mono) [![Generic badge](https://img.shields.io/badge/fontsource-passing-brightgreen)](https://github.com/fontsource/fontsource) [![Monthly downloads](https://badgen.net/npm/dm/@fontsource-variable/jetbrains-mono)](https://github.com/fontsource/fontsource) [![Total downloads](https://badgen.net/npm/dt/@fontsource-variable/jetbrains-mono)](https://github.com/fontsource/fontsource) [![GitHub stars](https://img.shields.io/github/stars/fontsource/fontsource.svg?style=social&label=Star)](https://github.com/fontsource/fontsource/stargazers)
4
-
5
- The CSS and web font files to easily self-host the “JetBrains Mono” variable font. Please visit the main [Fontsource website](https://fontsource.org/fonts/jetbrains-mono) to view more details on this package.
6
-
7
- ## Quick Installation
8
-
9
- Fontsource offers multiple methods to import the CSS, including using a bundler like Vite or using SASS. You can find full documentation [here](https://fontsource.org/docs/getting-started/introduction).
10
-
11
- ```javascript
12
- npm install @fontsource-variable/jetbrains-mono
13
- ```
14
-
15
- Within your app entry file or site component, import it in.
16
-
17
- ```javascript
18
- import "@fontsource-variable/jetbrains-mono"; // Defaults to wght axis
19
- import "@fontsource-variable/jetbrains-mono/wght.css"; // Specify axis
20
- import "@fontsource-variable/jetbrains-mono/wght-italic.css"; // Specify axis and style
21
- ```
22
-
23
- Supported variables:
24
- - Weights: `[100,200,300,400,500,600,700,800]`
25
- - Styles: `[italic,normal]`
26
- - Subsets: `[cyrillic,cyrillic-ext,greek,latin,latin-ext,vietnamese]`
27
- - Axes: `[wght]`
28
-
29
- > Note: `italic` may not be supported by all fonts. To learn more about what axes and styles are supported, please visit the [Fontsource website](https://fontsource.org/fonts/jetbrains-mono).
30
-
31
- Finally, you can reference the font name in a CSS stylesheet, CSS Module, or CSS-in-JS.
32
-
33
- ```css
34
- body {
35
- font-family: "JetBrains Mono Variable";
36
- }
37
- ```
38
-
39
- ## Licensing
40
- Always make sure to read the license for each font you use. Most of the fonts in the collection use the SIL Open Font License, v1.1. Some fonts use the Apache 2 license. The Ubuntu fonts use the Ubuntu Font License v1.0.
41
-
42
- Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) JetBrainsMono-Italic[wght].ttf: Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
43
- [OFL-1.1](https://openfontlicense.org)
44
-
45
- ## Other Notes
46
- Font version (provided by source): `v24`.
47
-
48
- If you have any suggestions or ideas to improve the performance of font loading or expand the existing library, feel free to star and contribute to this repository. You can share your suggestions or ideas by creating an [issue](https://github.com/fontsource/fontsource/issues).
@@ -1,59 +0,0 @@
1
- /* jetbrains-mono-cyrillic-ext-wght-normal */
2
- @font-face {
3
- font-family: 'JetBrains Mono Variable';
4
- font-style: normal;
5
- font-display: swap;
6
- font-weight: 100 800;
7
- src: url(./files/jetbrains-mono-cyrillic-ext-wght-normal.woff2) format('woff2-variations');
8
- unicode-range: U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;
9
- }
10
-
11
- /* jetbrains-mono-cyrillic-wght-normal */
12
- @font-face {
13
- font-family: 'JetBrains Mono Variable';
14
- font-style: normal;
15
- font-display: swap;
16
- font-weight: 100 800;
17
- src: url(./files/jetbrains-mono-cyrillic-wght-normal.woff2) format('woff2-variations');
18
- unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
19
- }
20
-
21
- /* jetbrains-mono-greek-wght-normal */
22
- @font-face {
23
- font-family: 'JetBrains Mono Variable';
24
- font-style: normal;
25
- font-display: swap;
26
- font-weight: 100 800;
27
- src: url(./files/jetbrains-mono-greek-wght-normal.woff2) format('woff2-variations');
28
- unicode-range: U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF;
29
- }
30
-
31
- /* jetbrains-mono-vietnamese-wght-normal */
32
- @font-face {
33
- font-family: 'JetBrains Mono Variable';
34
- font-style: normal;
35
- font-display: swap;
36
- font-weight: 100 800;
37
- src: url(./files/jetbrains-mono-vietnamese-wght-normal.woff2) format('woff2-variations');
38
- unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;
39
- }
40
-
41
- /* jetbrains-mono-latin-ext-wght-normal */
42
- @font-face {
43
- font-family: 'JetBrains Mono Variable';
44
- font-style: normal;
45
- font-display: swap;
46
- font-weight: 100 800;
47
- src: url(./files/jetbrains-mono-latin-ext-wght-normal.woff2) format('woff2-variations');
48
- unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
49
- }
50
-
51
- /* jetbrains-mono-latin-wght-normal */
52
- @font-face {
53
- font-family: 'JetBrains Mono Variable';
54
- font-style: normal;
55
- font-display: swap;
56
- font-weight: 100 800;
57
- src: url(./files/jetbrains-mono-latin-wght-normal.woff2) format('woff2-variations');
58
- unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
59
- }
@@ -1,29 +0,0 @@
1
- {
2
- "id": "jetbrains-mono",
3
- "family": "JetBrains Mono",
4
- "subsets": [
5
- "cyrillic",
6
- "cyrillic-ext",
7
- "greek",
8
- "latin",
9
- "latin-ext",
10
- "vietnamese"
11
- ],
12
- "weights": [100, 200, 300, 400, 500, 600, 700, 800],
13
- "styles": ["italic", "normal"],
14
- "defSubset": "latin",
15
- "variable": {
16
- "ital": {"default": "0", "min": "0", "max": "1", "step": "1"},
17
- "wght": {"default": "400", "min": "100", "max": "800", "step": "1"}
18
- },
19
- "lastModified": "2025-09-11",
20
- "version": "v24",
21
- "category": "monospace",
22
- "license": {
23
- "type": "OFL-1.1",
24
- "url": "https://openfontlicense.org",
25
- "attribution": "Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) JetBrainsMono-Italic[wght].ttf: Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)"
26
- },
27
- "source": "https://github.com/google/fonts",
28
- "type": "google"
29
- }
@@ -1,47 +0,0 @@
1
- {
2
- "name": "@fontsource-variable/jetbrains-mono",
3
- "version": "5.2.8",
4
- "description": "Self-host the JetBrains Mono font in a neatly bundled NPM package.",
5
- "main": "index.css",
6
- "publishConfig": {"access": "public"},
7
- "keywords": [
8
- "fontsource",
9
- "font",
10
- "font family",
11
- "google fonts",
12
- "jetbrains-mono",
13
- "JetBrains Mono",
14
- "css",
15
- "sass",
16
- "front-end",
17
- "web",
18
- "typeface",
19
- "variable"
20
- ],
21
- "exports": {
22
- ".": {"sass": "./index.css", "default": "./index.css"},
23
- "./LICENSE": "./LICENSE",
24
- "./*": {"sass": "./*.css", "default": "./*.css"},
25
- "./*.css": {"sass": "./*.css", "default": "./*.css"},
26
- "./files/*": {"sass": "./files/*", "default": "./files/*"},
27
- "./files/*.woff": {"sass": "./files/*.woff", "default": "./files/*.woff"},
28
- "./files/*.woff2": {
29
- "sass": "./files/*.woff2",
30
- "default": "./files/*.woff2"
31
- },
32
- "./package.json": "./package.json",
33
- "./metadata.json": "./metadata.json",
34
- "./unicode.json": "./unicode.json",
35
- "./scss": {"sass": "./scss/metadata.scss"}
36
- },
37
- "author": "Google Inc.",
38
- "license": "OFL-1.1",
39
- "homepage": "https://fontsource.org/fonts/jetbrains-mono",
40
- "funding": "https://github.com/sponsors/ayuhito",
41
- "repository": {
42
- "type": "git",
43
- "url": "git+https://github.com/fontsource/font-files.git",
44
- "directory": "fonts/variable/jetbrains-mono"
45
- },
46
- "publishHash": "e4410b879e39cf1a"
47
- }