@geminilight/mindos 0.6.8 → 0.6.12

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 (78) hide show
  1. package/README.md +2 -0
  2. package/README_zh.md +2 -0
  3. package/app/app/api/mcp/install/route.ts +4 -1
  4. package/app/app/api/setup/check-path/route.ts +2 -7
  5. package/app/app/api/setup/ls/route.ts +3 -9
  6. package/app/app/api/setup/path-utils.ts +8 -0
  7. package/app/app/api/setup/route.ts +2 -7
  8. package/app/app/api/uninstall/route.ts +47 -0
  9. package/app/app/globals.css +11 -0
  10. package/app/components/ActivityBar.tsx +10 -3
  11. package/app/components/AskFab.tsx +7 -3
  12. package/app/components/CreateSpaceModal.tsx +1 -1
  13. package/app/components/DirView.tsx +1 -1
  14. package/app/components/FileTree.tsx +30 -23
  15. package/app/components/GuideCard.tsx +1 -1
  16. package/app/components/HomeContent.tsx +137 -109
  17. package/app/components/ImportModal.tsx +16 -477
  18. package/app/components/MarkdownView.tsx +3 -0
  19. package/app/components/OnboardingView.tsx +1 -1
  20. package/app/components/OrganizeToast.tsx +386 -0
  21. package/app/components/Panel.tsx +23 -2
  22. package/app/components/Sidebar.tsx +1 -1
  23. package/app/components/SidebarLayout.tsx +44 -1
  24. package/app/components/agents/AgentDetailContent.tsx +33 -12
  25. package/app/components/agents/AgentsMcpSection.tsx +1 -1
  26. package/app/components/agents/AgentsOverviewSection.tsx +3 -4
  27. package/app/components/agents/AgentsPrimitives.tsx +2 -2
  28. package/app/components/agents/AgentsSkillsSection.tsx +2 -2
  29. package/app/components/agents/SkillDetailPopover.tsx +24 -8
  30. package/app/components/ask/AskContent.tsx +124 -75
  31. package/app/components/ask/HighlightMatch.tsx +14 -0
  32. package/app/components/ask/MentionPopover.tsx +5 -3
  33. package/app/components/ask/MessageList.tsx +39 -11
  34. package/app/components/ask/SlashCommandPopover.tsx +4 -2
  35. package/app/components/changes/ChangesBanner.tsx +20 -2
  36. package/app/components/changes/ChangesContentPage.tsx +10 -2
  37. package/app/components/echo/EchoHero.tsx +1 -1
  38. package/app/components/echo/EchoInsightCollapsible.tsx +1 -1
  39. package/app/components/echo/EchoPageSections.tsx +1 -1
  40. package/app/components/explore/UseCaseCard.tsx +1 -1
  41. package/app/components/panels/DiscoverPanel.tsx +29 -25
  42. package/app/components/panels/ImportHistoryPanel.tsx +195 -0
  43. package/app/components/panels/PluginsPanel.tsx +2 -2
  44. package/app/components/settings/AiTab.tsx +24 -0
  45. package/app/components/settings/KnowledgeTab.tsx +1 -1
  46. package/app/components/settings/McpSkillCreateForm.tsx +1 -1
  47. package/app/components/settings/McpSkillRow.tsx +1 -1
  48. package/app/components/settings/McpSkillsSection.tsx +2 -2
  49. package/app/components/settings/McpTab.tsx +2 -2
  50. package/app/components/settings/PluginsTab.tsx +1 -1
  51. package/app/components/settings/Primitives.tsx +118 -6
  52. package/app/components/settings/SettingsContent.tsx +5 -2
  53. package/app/components/settings/UninstallTab.tsx +179 -0
  54. package/app/components/settings/UpdateTab.tsx +17 -5
  55. package/app/components/settings/types.ts +2 -1
  56. package/app/components/ui/dialog.tsx +1 -1
  57. package/app/hooks/useAiOrganize.ts +122 -10
  58. package/app/hooks/useMention.ts +21 -3
  59. package/app/hooks/useSlashCommand.ts +18 -4
  60. package/app/lib/agent/reconnect.ts +40 -0
  61. package/app/lib/core/backlinks.ts +2 -2
  62. package/app/lib/core/git.ts +14 -10
  63. package/app/lib/fs.ts +2 -1
  64. package/app/lib/i18n-en.ts +46 -2
  65. package/app/lib/i18n-zh.ts +46 -2
  66. package/app/lib/organize-history.ts +74 -0
  67. package/app/lib/settings.ts +2 -0
  68. package/app/lib/types.ts +2 -0
  69. package/app/next.config.ts +23 -5
  70. package/bin/cli.js +6 -9
  71. package/bin/lib/mcp-build.js +74 -0
  72. package/bin/lib/mcp-spawn.js +8 -5
  73. package/bin/lib/port.js +17 -2
  74. package/bin/lib/stop.js +12 -2
  75. package/mcp/dist/index.cjs +43 -43
  76. package/mcp/src/index.ts +58 -12
  77. package/package.json +1 -1
  78. package/scripts/setup.js +2 -2
@@ -65,13 +65,12 @@ function groupBySpace(recent: RecentFile[], spaces: SpaceInfo[]): { groups: Spac
65
65
  return { groups, rootFiles };
66
66
  }
67
67
 
68
- /* ── Section Title component (shared across all three sections) ── */
68
+ /* ── Shared small components ── */
69
+
69
70
  interface SectionTitleProps {
70
71
  icon: React.ReactNode;
71
72
  children: React.ReactNode;
72
- /** Item count badge — only rendered when > 0 */
73
73
  count?: number;
74
- /** Right-aligned action slot (e.g. "View all" button) */
75
74
  action?: React.ReactNode;
76
75
  }
77
76
 
@@ -90,8 +89,83 @@ function SectionTitle({ icon, children, count, action }: SectionTitleProps) {
90
89
  );
91
90
  }
92
91
 
92
+ /** Reusable "Show more / Show less" toggle */
93
+ function ToggleButton({ expanded, onToggle, showLabel, hideLabel, className = '' }: {
94
+ expanded: boolean;
95
+ onToggle: () => void;
96
+ showLabel: string;
97
+ hideLabel: string;
98
+ className?: string;
99
+ }) {
100
+ return (
101
+ <button
102
+ onClick={onToggle}
103
+ aria-expanded={expanded}
104
+ className={`flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer font-display ${className}`}
105
+ >
106
+ <ChevronDown size={12} className={`transition-transform duration-200 ${expanded ? 'rotate-180' : ''}`} />
107
+ <span>{expanded ? hideLabel : showLabel}</span>
108
+ </button>
109
+ );
110
+ }
111
+
112
+ /** Reusable file row for recent-file lists */
113
+ function FileRow({ filePath, mtime, formatTime, subPath }: {
114
+ filePath: string;
115
+ mtime: number;
116
+ formatTime: (t: number) => string;
117
+ subPath?: string;
118
+ }) {
119
+ const isCSV = filePath.endsWith('.csv');
120
+ const name = filePath.split('/').pop() || filePath;
121
+ return (
122
+ <Link
123
+ href={`/view/${encodePath(filePath)}`}
124
+ 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"
125
+ >
126
+ {isCSV
127
+ ? <Table size={12} className="shrink-0 text-success" />
128
+ : <FileText size={12} className="shrink-0 text-muted-foreground" />
129
+ }
130
+ <div className="flex-1 min-w-0">
131
+ <span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
132
+ {subPath && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{subPath}</span>}
133
+ </div>
134
+ <span className="text-xs shrink-0 tabular-nums font-display text-muted-foreground opacity-40" suppressHydrationWarning>
135
+ {formatTime(mtime)}
136
+ </span>
137
+ </Link>
138
+ );
139
+ }
140
+
141
+ /** Reusable chip for builtin features / plugins */
142
+ function FeatureChip({ id, icon, name, entryPath, active, inactiveTitle }: {
143
+ id: string;
144
+ icon: string;
145
+ name: string;
146
+ entryPath?: string;
147
+ active: boolean;
148
+ inactiveTitle?: string;
149
+ }) {
150
+ const cls = active
151
+ ? 'inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border text-xs transition-all duration-150 hover:border-[var(--amber)]/30 hover:bg-muted/60'
152
+ : 'inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-dashed border-border text-xs text-muted-foreground opacity-70';
153
+
154
+ const inner = (
155
+ <>
156
+ <span className="text-sm leading-none" suppressHydrationWarning>{icon}</span>
157
+ <span className={`font-medium ${active ? 'text-foreground' : ''}`}>{name}</span>
158
+ </>
159
+ );
160
+
161
+ if (active && entryPath) {
162
+ return <Link key={id} href={`/view/${encodePath(entryPath)}`}><span className={cls}>{inner}</span></Link>;
163
+ }
164
+ return <span key={id} className={cls} title={inactiveTitle}>{inner}</span>;
165
+ }
166
+
93
167
  const FILES_PER_GROUP = 3;
94
- const SPACES_PER_ROW = 6; // 3 cols × 2 rows on desktop, show 1 row initially
168
+ const SPACES_PER_ROW = 6;
95
169
  const PLUGINS_INITIAL = 4;
96
170
 
97
171
  export default function HomeContent({ recent, existingFiles, spaces, dirPaths }: { recent: RecentFile[]; existingFiles?: string[]; spaces?: SpaceInfo[]; dirPaths?: string[] }) {
@@ -148,18 +222,18 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
148
222
  </p>
149
223
 
150
224
  {/* AI-first command bar */}
151
- <div className="w-full max-w-[620px] flex flex-col sm:flex-row items-stretch sm:items-center gap-2 ml-4">
225
+ <div className="w-full max-w-xl flex flex-col sm:flex-row items-stretch sm:items-center gap-2 ml-4">
152
226
  <button
153
227
  onClick={triggerAsk}
154
228
  title="⌘/"
155
229
  data-walkthrough="ask-button"
156
- className="flex-1 flex items-center gap-3 px-4 py-3 rounded-xl border border-border bg-card transition-all duration-150 hover:border-[var(--amber)]/50 hover:bg-[var(--amber)]/8"
230
+ className="flex-1 flex items-center gap-3 px-4 py-3 rounded-xl border border-border bg-card transition-all duration-150 hover:border-[var(--amber)]/50 hover:bg-[var(--amber-dim)]"
157
231
  >
158
232
  <Sparkles size={15} className="shrink-0 text-[var(--amber)]" />
159
233
  <span className="text-sm flex-1 text-left text-foreground">
160
234
  {suggestions[suggestionIdx]}
161
235
  </span>
162
- <kbd className="hidden sm:inline-flex items-center gap-0.5 px-2 py-0.5 rounded text-xs font-mono font-medium bg-[var(--amber-dim)] text-[var(--amber)]">
236
+ <kbd className="hidden sm:inline-flex items-center gap-0.5 px-2 py-0.5 rounded text-xs font-mono font-medium bg-[var(--amber-dim)] text-[var(--amber-text)]">
163
237
  ⌘/
164
238
  </kbd>
165
239
  </button>
@@ -180,14 +254,15 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
180
254
  <div className="flex flex-wrap gap-2.5 mt-4 pl-4">
181
255
  <button
182
256
  onClick={() => window.dispatchEvent(new CustomEvent('mindos:open-import'))}
183
- className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-all duration-150 hover:translate-x-0.5 bg-[var(--amber-dim)] text-[var(--amber)]"
257
+ className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-all duration-150 hover:translate-x-0.5 bg-[var(--amber-dim)] text-[var(--amber-text)]"
184
258
  >
185
259
  <FolderInput size={14} />
186
260
  <span>{t.fileTree.importFile}</span>
261
+ <ArrowRight size={13} className="opacity-50" />
187
262
  </button>
188
263
  <Link
189
264
  href="/view/Untitled.md"
190
- className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors bg-muted text-muted-foreground"
265
+ className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-all duration-150 hover:translate-x-0.5 bg-muted text-muted-foreground hover:text-foreground"
191
266
  >
192
267
  <FilePlus size={14} />
193
268
  <span>{t.home.newNote}</span>
@@ -199,7 +274,7 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
199
274
  >
200
275
  <ArrowRight size={14} />
201
276
  <span>{t.home.continueEditing}</span>
202
- <span className="text-xs opacity-50 truncate max-w-[140px]" suppressHydrationWarning>
277
+ <span className="text-xs opacity-50 truncate max-w-36" suppressHydrationWarning>
203
278
  {lastFile.path.split('/').pop()}
204
279
  </span>
205
280
  </Link>
@@ -259,13 +334,13 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
259
334
  })}
260
335
  </div>
261
336
  {spaceList.length > SPACES_PER_ROW && (
262
- <button
263
- onClick={() => setShowAllSpaces(v => !v)}
264
- className="flex items-center gap-1.5 mt-2 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer font-display"
265
- >
266
- <ChevronDown size={12} className={`transition-transform duration-200 ${showAllSpaces ? 'rotate-180' : ''}`} />
267
- <span>{showAllSpaces ? t.home.showLess : t.home.showMore}</span>
268
- </button>
337
+ <ToggleButton
338
+ expanded={showAllSpaces}
339
+ onToggle={() => setShowAllSpaces(v => !v)}
340
+ showLabel={t.home.showMore}
341
+ hideLabel={t.home.showLess}
342
+ className="mt-2"
343
+ />
269
344
  )}
270
345
  </>
271
346
  ) : (
@@ -285,25 +360,16 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
285
360
  <div className="flex flex-wrap gap-2">
286
361
  {builtinFeatures.map((r) => {
287
362
  const active = !!r.entryPath && existingSet.has(r.entryPath);
288
- if (active && r.entryPath) {
289
- return (
290
- <Link key={r.id} href={`/view/${encodePath(r.entryPath)}`}>
291
- <span className="inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border text-xs transition-all duration-150 hover:border-[var(--amber)]/30 hover:bg-muted/60">
292
- <span className="text-sm leading-none" suppressHydrationWarning>{r.icon}</span>
293
- <span className="font-medium text-foreground">{r.name}</span>
294
- </span>
295
- </Link>
296
- );
297
- }
298
363
  return (
299
- <span
364
+ <FeatureChip
300
365
  key={r.id}
301
- className="inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-dashed border-border text-xs text-muted-foreground opacity-70"
302
- title={r.entryPath ? t.home.createToActivate.replace('{file}', r.entryPath) : t.home.builtinInactive}
303
- >
304
- <span className="text-sm leading-none" suppressHydrationWarning>{r.icon}</span>
305
- <span className="font-medium">{r.name}</span>
306
- </span>
366
+ id={r.id}
367
+ icon={r.icon}
368
+ name={r.name}
369
+ entryPath={r.entryPath}
370
+ active={active}
371
+ inactiveTitle={r.entryPath ? t.home.createToActivate.replace('{file}', r.entryPath) : t.home.builtinInactive}
372
+ />
307
373
  );
308
374
  })}
309
375
  </div>
@@ -318,13 +384,12 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
318
384
  count={availablePlugins.length}
319
385
  action={
320
386
  availablePlugins.length > PLUGINS_INITIAL ? (
321
- <button
322
- onClick={() => setShowAllPlugins(v => !v)}
323
- className="flex items-center gap-1 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer font-display"
324
- >
325
- <span>{showAllPlugins ? t.home.showLess : t.home.viewAll}</span>
326
- <ChevronDown size={12} className={`transition-transform duration-200 ${showAllPlugins ? 'rotate-180' : ''}`} />
327
- </button>
387
+ <ToggleButton
388
+ expanded={showAllPlugins}
389
+ onToggle={() => setShowAllPlugins(v => !v)}
390
+ showLabel={t.home.viewAll}
391
+ hideLabel={t.home.showLess}
392
+ />
328
393
  ) : undefined
329
394
  }
330
395
  >
@@ -332,14 +397,7 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
332
397
  </SectionTitle>
333
398
  <div className="flex flex-wrap gap-2">
334
399
  {(showAllPlugins ? availablePlugins : availablePlugins.slice(0, PLUGINS_INITIAL)).map(r => (
335
- <Link
336
- key={r.id}
337
- href={`/view/${encodePath(r.entryPath!)}`}
338
- className="inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border text-xs transition-all duration-150 hover:border-[var(--amber)]/30 hover:bg-muted/60"
339
- >
340
- <span className="text-sm leading-none" suppressHydrationWarning>{r.icon}</span>
341
- <span className="font-medium text-foreground">{r.name}</span>
342
- </Link>
400
+ <FeatureChip key={r.id} id={r.id} icon={r.icon} name={r.name} entryPath={r.entryPath} active />
343
401
  ))}
344
402
  </div>
345
403
  </section>
@@ -376,30 +434,15 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
376
434
  )}
377
435
  </Link>
378
436
  <div className="flex flex-col gap-0.5 ml-2 border-l border-border pl-3">
379
- {visibleFiles.map(({ path: filePath, mtime }) => {
380
- const isCSV = filePath.endsWith('.csv');
381
- const name = filePath.split('/').pop() || filePath;
382
- const subPath = filePath.split('/').slice(1, -1).join('/');
383
- return (
384
- <Link
385
- key={filePath}
386
- href={`/view/${encodePath(filePath)}`}
387
- 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"
388
- >
389
- {isCSV
390
- ? <Table size={12} className="shrink-0 text-success" />
391
- : <FileText size={12} className="shrink-0 text-muted-foreground" />
392
- }
393
- <div className="flex-1 min-w-0">
394
- <span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
395
- {subPath && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{subPath}</span>}
396
- </div>
397
- <span className="text-xs shrink-0 tabular-nums font-display text-muted-foreground opacity-40" suppressHydrationWarning>
398
- {formatTime(mtime)}
399
- </span>
400
- </Link>
401
- );
402
- })}
437
+ {visibleFiles.map(({ path: filePath, mtime }) => (
438
+ <FileRow
439
+ key={filePath}
440
+ filePath={filePath}
441
+ mtime={mtime}
442
+ formatTime={formatTime}
443
+ subPath={filePath.split('/').slice(1, -1).join('/')}
444
+ />
445
+ ))}
403
446
  </div>
404
447
  </div>
405
448
  );
@@ -416,19 +459,7 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
416
459
  </div>
417
460
  <div className="flex flex-col gap-0.5 ml-2 border-l border-border pl-3">
418
461
  {rootFiles.map(({ path: filePath, mtime }) => (
419
- <Link
420
- key={filePath}
421
- href={`/view/${encodePath(filePath)}`}
422
- className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted"
423
- >
424
- <FileText size={12} className="shrink-0 text-muted-foreground" />
425
- <span className="text-sm flex-1 min-w-0 truncate text-foreground" suppressHydrationWarning>
426
- {filePath.split('/').pop() || filePath}
427
- </span>
428
- <span className="text-xs shrink-0 tabular-nums font-display text-muted-foreground opacity-40" suppressHydrationWarning>
429
- {formatTime(mtime)}
430
- </span>
431
- </Link>
462
+ <FileRow key={filePath} filePath={filePath} mtime={mtime} formatTime={formatTime} />
432
463
  ))}
433
464
  </div>
434
465
  </div>
@@ -436,14 +467,13 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
436
467
 
437
468
  {/* Show more / less */}
438
469
  {groups.some(g => g.files.length > FILES_PER_GROUP) && (
439
- <button
440
- onClick={() => setShowAll(v => !v)}
441
- aria-expanded={showAll}
442
- className="flex items-center gap-1.5 mt-1 ml-1 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer font-display"
443
- >
444
- <ChevronDown size={12} className={`transition-transform duration-200 ${showAll ? 'rotate-180' : ''}`} />
445
- <span>{showAll ? t.home.showLess : t.home.showMore}</span>
446
- </button>
470
+ <ToggleButton
471
+ expanded={showAll}
472
+ onToggle={() => setShowAll(v => !v)}
473
+ showLabel={t.home.showMore}
474
+ hideLabel={t.home.showLess}
475
+ className="mt-1 ml-1"
476
+ />
447
477
  )}
448
478
  </div>
449
479
  ) : (
@@ -459,11 +489,11 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
459
489
  <div key={filePath} className="relative group">
460
490
  <div
461
491
  aria-hidden="true"
462
- className={`absolute -left-4 top-1/2 -translate-y-1/2 rounded-full transition-all duration-150 group-hover:scale-150 ${idx === 0 ? 'w-2 h-2' : 'w-1.5 h-1.5'}`}
463
- style={{
464
- background: idx === 0 ? 'var(--amber)' : 'var(--border)',
465
- outline: idx === 0 ? '2px solid var(--amber-dim)' : 'none',
466
- }}
492
+ className={`absolute -left-4 top-1/2 -translate-y-1/2 rounded-full transition-all duration-150 group-hover:scale-150 ${
493
+ idx === 0
494
+ ? 'w-2 h-2 bg-[var(--amber)] outline-2 outline-[var(--amber-dim)]'
495
+ : 'w-1.5 h-1.5 bg-border'
496
+ }`}
467
497
  />
468
498
  <Link
469
499
  href={`/view/${encodePath(filePath)}`}
@@ -486,14 +516,13 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
486
516
  })}
487
517
  </div>
488
518
  {recent.length > 5 && (
489
- <button
490
- onClick={() => setShowAll(v => !v)}
491
- aria-expanded={showAll}
492
- className="flex items-center gap-1.5 mt-2 ml-3 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer font-display"
493
- >
494
- <ChevronDown size={12} className={`transition-transform duration-200 ${showAll ? 'rotate-180' : ''}`} />
495
- <span>{showAll ? t.home.showLess : t.home.showMore}</span>
496
- </button>
519
+ <ToggleButton
520
+ expanded={showAll}
521
+ onToggle={() => setShowAll(v => !v)}
522
+ showLabel={t.home.showMore}
523
+ hideLabel={t.home.showLess}
524
+ className="mt-2 ml-3"
525
+ />
497
526
  )}
498
527
  </div>
499
528
  )}
@@ -569,7 +598,7 @@ function ExampleCleanupBanner() {
569
598
  <button
570
599
  onClick={handleCleanup}
571
600
  disabled={cleaning}
572
- className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-lg transition-colors shrink-0 disabled:opacity-50 bg-[var(--amber-dim)] text-[var(--amber)] hover:opacity-80"
601
+ className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-lg transition-colors shrink-0 disabled:opacity-50 bg-[var(--amber-dim)] text-[var(--amber-text)] hover:opacity-80"
573
602
  >
574
603
  {cleaning ? <Loader2 size={11} className="animate-spin" /> : <Trash2 size={11} />}
575
604
  {t.home.cleanupExamplesButton}
@@ -583,4 +612,3 @@ function ExampleCleanupBanner() {
583
612
  </div>
584
613
  );
585
614
  }
586
-