@geminilight/mindos 0.6.60 → 0.6.61

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 (161) hide show
  1. package/_standalone/.mindos-build-version +1 -1
  2. package/_standalone/.next/BUILD_ID +1 -1
  3. package/_standalone/.next/app-path-routes-manifest.json +22 -22
  4. package/_standalone/.next/build-manifest.json +2 -2
  5. package/_standalone/.next/cache/.previewinfo +1 -1
  6. package/_standalone/.next/cache/.rscinfo +1 -1
  7. package/_standalone/.next/cache/config.json +3 -3
  8. package/_standalone/.next/prerender-manifest.json +3 -3
  9. package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
  10. package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/_standalone/.next/server/app/_global-error.html +2 -2
  12. package/_standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/_standalone/.next/server/app/_not-found/page.js +1 -1
  20. package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/_standalone/.next/server/app/agents/[agentKey]/page.js +1 -1
  23. package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
  24. package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
  25. package/_standalone/.next/server/app/agents/page.js +1 -1
  26. package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
  27. package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  28. package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
  29. package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
  30. package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
  31. package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
  32. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  33. package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
  34. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
  35. package/_standalone/.next/server/app/api/acp/registry/route.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  37. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  38. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  39. package/_standalone/.next/server/app/api/agents/copy-skill/route_client-reference-manifest.js +1 -1
  40. package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
  41. package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
  42. package/_standalone/.next/server/app/api/ask/route.js +3 -3
  43. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  44. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  45. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  46. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  47. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  48. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  49. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  50. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  51. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  52. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  54. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  55. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  56. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  57. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  59. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  60. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  61. package/_standalone/.next/server/app/api/mcp/install/route.js +1 -1
  62. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  63. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  65. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  66. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  68. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  69. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  70. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  72. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  73. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  74. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  75. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  76. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  77. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  78. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  79. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  81. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  82. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  83. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  86. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  87. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  88. package/_standalone/.next/server/app/changes/page.js +1 -1
  89. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  90. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  91. package/_standalone/.next/server/app/echo/[segment]/page.js +1 -1
  92. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  93. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  94. package/_standalone/.next/server/app/echo/page.js +1 -1
  95. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  96. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  97. package/_standalone/.next/server/app/explore/page.js +1 -1
  98. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  99. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  100. package/_standalone/.next/server/app/help/page.js +1 -1
  101. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  102. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  103. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  104. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  105. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  106. package/_standalone/.next/server/app/login/page.js +1 -1
  107. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  108. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  109. package/_standalone/.next/server/app/page.js +1 -1
  110. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  111. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  112. package/_standalone/.next/server/app/setup/page.js +1 -1
  113. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  114. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  115. package/_standalone/.next/server/app/trash/page.js +3 -3
  116. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  117. package/_standalone/.next/server/app/view/[...path]/page.js +2 -2
  118. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  119. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  120. package/_standalone/.next/server/app/wiki/page.js +1 -1
  121. package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
  122. package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
  123. package/_standalone/.next/server/app-paths-manifest.json +22 -22
  124. package/_standalone/.next/server/chunks/1550.js +1 -1
  125. package/_standalone/.next/server/chunks/1750.js +1 -1
  126. package/_standalone/.next/server/chunks/530.js +31 -31
  127. package/_standalone/.next/server/chunks/6539.js +1 -1
  128. package/_standalone/.next/server/chunks/{9753.js → 8955.js} +3 -3
  129. package/_standalone/.next/server/pages/500.html +2 -2
  130. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  131. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  132. package/_standalone/.next/static/chunks/{5581-974dfb26d1d1b38f.js → 5581-0c700c20718bd916.js} +2 -2
  133. package/_standalone/.next/static/chunks/app/{layout-6a0169582db11a08.js → layout-a5d5925b47e87cc3.js} +10 -10
  134. package/_standalone/.next/static/chunks/app/trash/page-40bc7316806acd62.js +1 -0
  135. package/_standalone/.next/static/chunks/app/view/[...path]/page-6fbb14b8f322d0f0.js +12 -0
  136. package/_standalone/.next/static/chunks/app/wiki/page-ba36eccf4fe62cfe.js +1 -0
  137. package/_standalone/.next/static/css/{9c558c42831fae58.css → b57c4eb3cc88308b.css} +1 -1
  138. package/_standalone/.next/trace +65 -65
  139. package/_standalone/__tests__/api/mcp-install.test.ts +3 -2
  140. package/_standalone/components/Panel.tsx +14 -0
  141. package/_standalone/components/home/InboxSection.tsx +148 -32
  142. package/_standalone/tsconfig.tsbuildinfo +1 -1
  143. package/app/app/api/ask/route.ts +2 -2
  144. package/app/app/api/mcp/install/route.ts +17 -1
  145. package/app/components/Panel.tsx +14 -0
  146. package/app/components/home/InboxSection.tsx +148 -32
  147. package/app/lib/acp/agent-descriptors.ts +3 -0
  148. package/app/lib/acp/subprocess.ts +56 -8
  149. package/app/lib/i18n/modules/knowledge.ts +10 -0
  150. package/app/lib/mcp-agents.ts +9 -0
  151. package/bin/lib/mcp-agents.js +34 -1
  152. package/bin/lib/mcp-install.js +94 -20
  153. package/bin/lib/toml.js +125 -0
  154. package/package.json +1 -1
  155. package/scripts/build-runtime-archive.sh +5 -1
  156. package/scripts/setup.js +19 -0
  157. package/_standalone/.next/static/chunks/app/trash/page-ed7ba3b0b50223a6.js +0 -1
  158. package/_standalone/.next/static/chunks/app/view/[...path]/page-678139779971cfcb.js +0 -12
  159. package/_standalone/.next/static/chunks/app/wiki/page-194ae9af2d461481.js +0 -1
  160. /package/_standalone/.next/static/{K3wZNf5bj_AFYwtqcRXIf → 5GmVArEG8OX03azKICsGq}/_buildManifest.js +0 -0
  161. /package/_standalone/.next/static/{K3wZNf5bj_AFYwtqcRXIf → 5GmVArEG8OX03azKICsGq}/_ssgManifest.js +0 -0
@@ -254,11 +254,11 @@ describe('POST /api/mcp/install', () => {
254
254
  });
255
255
 
256
256
  describe('GET /api/mcp/agents', () => {
257
- it('returns all 23 agents (1 builtin + 20 registry + 2 new)', async () => {
257
+ it('returns all 24 agents (1 builtin + 21 registry + 2 new)', async () => {
258
258
  const { GET } = await importAgentsRoute();
259
259
  const res = await GET();
260
260
  const body = await res.json();
261
- expect(body.agents).toHaveLength(23);
261
+ expect(body.agents).toHaveLength(24);
262
262
  const keys = body.agents.map((a: { key: string }) => a.key);
263
263
  expect(keys).toContain('mindos');
264
264
  expect(keys).toContain('claude-code');
@@ -278,6 +278,7 @@ describe('GET /api/mcp/agents', () => {
278
278
  expect(keys).toContain('antigravity');
279
279
  expect(keys).toContain('qclaw');
280
280
  expect(keys).toContain('workbuddy');
281
+ expect(keys).toContain('lingma');
281
282
  });
282
283
 
283
284
  it('detects installed agent from config file', async () => {
@@ -324,6 +324,20 @@ export default function Panel({
324
324
  >
325
325
  <FileTree nodes={fileTree} onNavigate={onNavigate} maxOpenDepth={maxOpenDepth} onImport={onImport} />
326
326
  </div>
327
+ {/* Inbox quick entry — always visible above sync bar */}
328
+ <button
329
+ type="button"
330
+ onClick={() => router.push('/view/Inbox/')}
331
+ className="flex items-center gap-2 mx-2 px-2 py-1.5 text-sm rounded-md transition-colors hover:bg-muted group border-t border-border/40 shrink-0"
332
+ >
333
+ <Inbox size={14} className="shrink-0 text-[var(--amber)]" />
334
+ <span className="flex-1 text-left text-muted-foreground group-hover:text-foreground transition-colors text-xs">
335
+ {t.sidebar.capture}
336
+ </span>
337
+ {inboxCount > 0 && (
338
+ <span className="text-xs font-medium text-[var(--amber)] tabular-nums">{inboxCount}</span>
339
+ )}
340
+ </button>
327
341
  <SyncStatusBar collapsed={false} onOpenSyncSettings={onOpenSyncSettings} />
328
342
  </div>
329
343
 
@@ -15,7 +15,13 @@ import {
15
15
  Check,
16
16
  Clock,
17
17
  ChevronDown,
18
+ X,
19
+ ExternalLink,
20
+ Copy,
21
+ Trash2,
18
22
  } from 'lucide-react';
23
+ import { useRouter } from 'next/navigation';
24
+ import { toast } from '@/lib/toast';
19
25
  import { useLocale } from '@/lib/stores/locale-store';
20
26
  import { encodePath } from '@/lib/utils';
21
27
  import { quickDropToInbox } from '@/lib/inbox-upload';
@@ -55,6 +61,22 @@ export function InboxSection({ isOrganizing: externalOrganizing = false }: Inbox
55
61
  );
56
62
  }, [files, isOrganizing]);
57
63
 
64
+ const handleDeleteFile = useCallback(async (name: string) => {
65
+ try {
66
+ const res = await fetch('/api/inbox', {
67
+ method: 'DELETE',
68
+ headers: { 'Content-Type': 'application/json' },
69
+ body: JSON.stringify({ names: [name] }),
70
+ });
71
+ if (!res.ok) throw new Error('Failed to delete');
72
+ setFiles(prev => prev.filter(f => f.name !== name));
73
+ window.dispatchEvent(new Event('mindos:inbox-updated'));
74
+ toast.success(t.inbox.fileRemoved);
75
+ } catch {
76
+ toast.error(t.inbox.fileRemoveFailed);
77
+ }
78
+ }, [t]);
79
+
58
80
  const handleUpload = useCallback((selected: FileList | null) => {
59
81
  if (!selected || selected.length === 0) return;
60
82
  quickDropToInbox(Array.from(selected), t);
@@ -208,7 +230,7 @@ export function InboxSection({ isOrganizing: externalOrganizing = false }: Inbox
208
230
  <>
209
231
  <div className="flex flex-col gap-0.5 mb-3">
210
232
  {visibleFiles.map((file) => (
211
- <InboxFileRow key={file.path} file={file} />
233
+ <InboxFileRow key={file.path} file={file} onDelete={handleDeleteFile} />
212
234
  ))}
213
235
  </div>
214
236
  {overflowCount > 0 && (
@@ -312,45 +334,139 @@ export function InboxSection({ isOrganizing: externalOrganizing = false }: Inbox
312
334
  );
313
335
  }
314
336
 
315
- function InboxFileRow({ file }: { file: InboxFile }) {
337
+ function InboxFileRow({ file, onDelete }: { file: InboxFile; onDelete: (name: string) => void }) {
316
338
  const { t } = useLocale();
339
+ const router = useRouter();
317
340
  const isCSV = file.name.endsWith('.csv');
318
341
  const age = formatRelativeTime(file.modifiedAt, t.home.relativeTime);
342
+ const [ctxMenu, setCtxMenu] = useState<{ x: number; y: number } | null>(null);
343
+
344
+ const handleNavigate = () => {
345
+ router.push(`/view/${encodePath(file.path)}`);
346
+ };
347
+
348
+ const handleDelete = (e: React.MouseEvent) => {
349
+ e.stopPropagation();
350
+ e.preventDefault();
351
+ onDelete(file.name);
352
+ };
353
+
354
+ const handleContextMenu = (e: React.MouseEvent) => {
355
+ e.preventDefault();
356
+ e.stopPropagation();
357
+ setCtxMenu({ x: e.clientX, y: e.clientY });
358
+ };
319
359
 
320
360
  return (
321
- <Link
322
- href={`/view/${encodePath(file.path)}`}
323
- className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted group"
324
- >
325
- <span
326
- className={`w-1.5 h-1.5 rounded-full shrink-0 ${
327
- file.isAging ? 'bg-[var(--amber)]/60' : 'bg-[var(--amber)]'
328
- }`}
329
- />
330
- {isCSV ? (
331
- <Table size={12} className="shrink-0 text-success" />
332
- ) : (
333
- <FileText size={12} className="shrink-0 text-muted-foreground" />
334
- )}
335
- <span
336
- className="text-sm truncate flex-1 text-foreground"
337
- title={file.name}
338
- suppressHydrationWarning
361
+ <>
362
+ <div
363
+ role="button"
364
+ tabIndex={0}
365
+ onClick={handleNavigate}
366
+ onKeyDown={(e) => { if (e.key === 'Enter') handleNavigate(); }}
367
+ onContextMenu={handleContextMenu}
368
+ className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted group cursor-pointer"
339
369
  >
340
- {file.name}
341
- </span>
342
- <span className="text-2xs text-muted-foreground/50 tabular-nums shrink-0">
343
- {age}
344
- </span>
345
- {file.isAging && (
346
- <span title="7+ days">
347
- <AlertCircle
348
- size={11}
349
- className="shrink-0 text-[var(--amber)]/60"
350
- />
370
+ <span
371
+ className={`w-1.5 h-1.5 rounded-full shrink-0 ${
372
+ file.isAging ? 'bg-[var(--amber)]/60' : 'bg-[var(--amber)]'
373
+ }`}
374
+ />
375
+ {isCSV ? (
376
+ <Table size={12} className="shrink-0 text-success" />
377
+ ) : (
378
+ <FileText size={12} className="shrink-0 text-muted-foreground" />
379
+ )}
380
+ <span
381
+ className="text-sm truncate flex-1 text-foreground"
382
+ title={file.name}
383
+ suppressHydrationWarning
384
+ >
385
+ {file.name}
386
+ </span>
387
+ <span className="text-2xs text-muted-foreground/50 tabular-nums shrink-0 group-hover:hidden">
388
+ {age}
351
389
  </span>
390
+ {file.isAging && (
391
+ <span title="7+ days" className="group-hover:hidden">
392
+ <AlertCircle
393
+ size={11}
394
+ className="shrink-0 text-[var(--amber)]/60"
395
+ />
396
+ </span>
397
+ )}
398
+ {/* Hover delete button */}
399
+ <button
400
+ type="button"
401
+ onClick={handleDelete}
402
+ className="hidden group-hover:flex items-center justify-center w-5 h-5 rounded shrink-0 text-muted-foreground/50 hover:text-destructive hover:bg-destructive/10 transition-colors"
403
+ title={t.inbox.removeFile}
404
+ >
405
+ <X size={12} />
406
+ </button>
407
+ </div>
408
+ {ctxMenu && (
409
+ <InboxFileContextMenu
410
+ x={ctxMenu.x}
411
+ y={ctxMenu.y}
412
+ file={file}
413
+ onDelete={() => { setCtxMenu(null); onDelete(file.name); }}
414
+ onClose={() => setCtxMenu(null)}
415
+ />
352
416
  )}
353
- </Link>
417
+ </>
418
+ );
419
+ }
420
+
421
+ /** Right-click context menu for Inbox file items */
422
+ function InboxFileContextMenu({ x, y, file, onDelete, onClose }: {
423
+ x: number; y: number; file: InboxFile; onDelete: () => void; onClose: () => void;
424
+ }) {
425
+ const menuRef = useRef<HTMLDivElement>(null);
426
+ const router = useRouter();
427
+ const { t } = useLocale();
428
+
429
+ useEffect(() => {
430
+ const handleClick = (e: MouseEvent) => {
431
+ if (menuRef.current && !menuRef.current.contains(e.target as Node)) onClose();
432
+ };
433
+ const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
434
+ document.addEventListener('mousedown', handleClick);
435
+ document.addEventListener('keydown', handleKey);
436
+ return () => { document.removeEventListener('mousedown', handleClick); document.removeEventListener('keydown', handleKey); };
437
+ }, [onClose]);
438
+
439
+ const adjX = typeof window !== 'undefined' ? Math.min(x, window.innerWidth - 200) : x;
440
+ const adjY = typeof window !== 'undefined' ? Math.min(y, window.innerHeight - 120) : y;
441
+
442
+ const menuItemClass = 'w-full flex items-center gap-2 px-3 py-1.5 text-sm text-foreground hover:bg-muted transition-colors text-left';
443
+
444
+ return (
445
+ <div
446
+ ref={menuRef}
447
+ className="fixed z-50 min-w-[160px] bg-card border border-border rounded-lg shadow-lg py-1"
448
+ style={{ top: adjY, left: adjX }}
449
+ >
450
+ <button
451
+ className={menuItemClass}
452
+ onClick={() => { router.push(`/view/${encodePath(file.path)}`); onClose(); }}
453
+ >
454
+ <ExternalLink size={14} className="shrink-0" /> {t.inbox.openFile}
455
+ </button>
456
+ <button
457
+ className={menuItemClass}
458
+ onClick={() => { navigator.clipboard.writeText(file.name); toast.copy(); onClose(); }}
459
+ >
460
+ <Copy size={14} className="shrink-0" /> {t.inbox.copyName}
461
+ </button>
462
+ <div className="border-t border-border my-1" />
463
+ <button
464
+ className={`${menuItemClass} text-destructive hover:text-destructive`}
465
+ onClick={onDelete}
466
+ >
467
+ <Trash2 size={14} className="shrink-0" /> {t.inbox.removeFile}
468
+ </button>
469
+ </div>
354
470
  );
355
471
  }
356
472