@geminilight/mindos 0.5.36 → 0.5.37

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.
@@ -75,7 +75,7 @@ body {
75
75
  --ring: var(--amber);
76
76
  --radius: 0.5rem;
77
77
  --amber: #c8873a;
78
- --amber-dim: rgba(200, 135, 58, 0.12);
78
+ --amber-dim: rgba(200, 135, 58, 0.18);
79
79
  --amber-subtle: rgba(200, 135, 30, 0.08);
80
80
  --amber-foreground: #131210;
81
81
  --success: #7aad80;
@@ -110,7 +110,7 @@ body {
110
110
  --input: rgba(232, 228, 220, 0.1);
111
111
  --ring: var(--amber);
112
112
  --amber: #d4954a;
113
- --amber-dim: rgba(212, 149, 74, 0.12);
113
+ --amber-dim: rgba(212, 149, 74, 0.20);
114
114
  --amber-subtle: rgba(212, 149, 74, 0.10);
115
115
  --amber-foreground: #131210;
116
116
  --success: #7aad80;
@@ -300,6 +300,10 @@ body {
300
300
  backdrop-filter: blur(8px);
301
301
  -webkit-backdrop-filter: blur(8px);
302
302
  }
303
+ .dark .modal-backdrop {
304
+ background: rgba(0, 0, 0, 0.65);
305
+ }
306
+ }
303
307
 
304
308
  /* Micro type scale: text-2xs = 10px (between nothing and text-xs 12px) */
305
309
  @layer utilities {
@@ -1,6 +1,8 @@
1
1
  'use client';
2
2
 
3
+ import { AlertCircle } from 'lucide-react';
3
4
  import AskContent from '@/components/ask/AskContent';
5
+ import ErrorBoundary from '@/components/ErrorBoundary';
4
6
  import { useResizeDrag } from '@/hooks/useResizeDrag';
5
7
 
6
8
  const DEFAULT_WIDTH = 380;
@@ -47,16 +49,29 @@ export default function RightAskPanel({
47
49
  role="complementary"
48
50
  aria-label="MindOS Agent panel"
49
51
  >
50
- <AskContent
51
- visible={open}
52
- variant="panel"
53
- currentFile={open ? currentFile : undefined}
54
- initialMessage={initialMessage}
55
- onFirstMessage={onFirstMessage}
56
- onClose={onClose}
57
- askMode={askMode}
58
- onModeSwitch={onModeSwitch}
59
- />
52
+ <ErrorBoundary fallback={
53
+ <div className="flex flex-col items-center justify-center h-full gap-3 px-6 text-center">
54
+ <AlertCircle size={20} className="text-muted-foreground" />
55
+ <p className="text-sm text-muted-foreground">AI panel encountered an error.</p>
56
+ <button
57
+ onClick={() => window.location.reload()}
58
+ className="text-xs px-3 py-1.5 rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
59
+ >
60
+ Reload page
61
+ </button>
62
+ </div>
63
+ }>
64
+ <AskContent
65
+ visible={open}
66
+ variant="panel"
67
+ currentFile={open ? currentFile : undefined}
68
+ initialMessage={initialMessage}
69
+ onFirstMessage={onFirstMessage}
70
+ onClose={onClose}
71
+ askMode={askMode}
72
+ onModeSwitch={onModeSwitch}
73
+ />
74
+ </ErrorBoundary>
60
75
 
61
76
  {/* Drag resize handle — LEFT edge */}
62
77
  <div
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useState, useEffect, useCallback } from 'react';
3
+ import { useState, useEffect, useCallback, useRef } from 'react';
4
4
  import { useRouter } from 'next/navigation';
5
5
  import { getAllRenderers, isRendererEnabled, setRendererEnabled, loadDisabledState } from '@/lib/renderers/registry';
6
6
  import { Toggle } from '../settings/Primitives';
@@ -27,25 +27,25 @@ export default function PluginsPanel({ active, maximized, onMaximize }: PluginsP
27
27
  setMounted(true);
28
28
  }, []);
29
29
 
30
- // Check which entry files exist (once on mount + when active)
30
+ // Check which entry files exist — fetch once on mount, cache result
31
+ const fetchedRef = useRef(false);
31
32
  useEffect(() => {
32
- if (!mounted || !active) return;
33
+ if (!mounted || fetchedRef.current) return;
34
+ fetchedRef.current = true;
33
35
  const entryPaths = getAllRenderers()
34
36
  .map(r => r.entryPath)
35
37
  .filter((p): p is string => !!p);
36
38
  if (entryPaths.length === 0) return;
37
39
 
38
- // Check each file via HEAD-like GET lightweight
39
- Promise.all(
40
- entryPaths.map(path =>
41
- fetch(`/api/file?path=${encodeURIComponent(path)}`, { method: 'GET' })
42
- .then(r => r.ok ? path : null)
43
- .catch(() => null)
44
- )
45
- ).then(results => {
46
- setExistingFiles(new Set(results.filter((p): p is string => p !== null)));
47
- });
48
- }, [mounted, active]);
40
+ // Single request: fetch all file paths and check which entry paths exist
41
+ fetch('/api/files')
42
+ .then(r => r.ok ? r.json() : [])
43
+ .then((allPaths: string[]) => {
44
+ const pathSet = new Set(allPaths);
45
+ setExistingFiles(new Set(entryPaths.filter(p => pathSet.has(p))));
46
+ })
47
+ .catch(() => {});
48
+ }, [mounted]);
49
49
 
50
50
  const renderers = mounted ? getAllRenderers() : [];
51
51
  const enabledCount = mounted ? renderers.filter(r => isRendererEnabled(r.id)).length : 0;
@@ -86,7 +86,9 @@ export default function PluginsPanel({ active, maximized, onMaximize }: PluginsP
86
86
  ${!enabled ? 'opacity-50' : ''}
87
87
  `}
88
88
  onClick={canOpen ? () => handleOpen(r.entryPath!) : undefined}
89
+ onKeyDown={canOpen ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleOpen(r.entryPath!); } } : undefined}
89
90
  role={canOpen ? 'link' : undefined}
91
+ tabIndex={canOpen ? 0 : undefined}
90
92
  >
91
93
  {/* Top row: status dot + icon + name + toggle */}
92
94
  <div className="flex items-center justify-between gap-2">
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useState, useEffect, useCallback, useSyncExternalStore, useRef } from 'react';
4
- import { Copy, Check, RefreshCw, Trash2, Sparkles, ChevronDown, ChevronRight, Loader2, Cpu, Zap, Database as DatabaseIcon, HardDrive } from 'lucide-react';
4
+ import { Copy, Check, RefreshCw, Trash2, Sparkles, ChevronDown, ChevronRight, Loader2, Cpu, Zap, Database as DatabaseIcon, HardDrive, RotateCcw } from 'lucide-react';
5
5
  import type { KnowledgeTabProps } from './types';
6
6
  import { Field, Input, EnvBadge, SectionLabel, Toggle } from './Primitives';
7
7
  import { apiFetch } from '@/lib/api';
@@ -49,6 +49,27 @@ export function KnowledgeTab({ data, setData, t }: KnowledgeTabProps) {
49
49
  });
50
50
  }, [guideDismissed]);
51
51
 
52
+ const handleRestartWalkthrough = useCallback(() => {
53
+ apiFetch('/api/setup', {
54
+ method: 'PATCH',
55
+ headers: { 'Content-Type': 'application/json' },
56
+ body: JSON.stringify({
57
+ guideState: {
58
+ active: true,
59
+ dismissed: false,
60
+ walkthroughStep: 0,
61
+ walkthroughDismissed: false,
62
+ },
63
+ }),
64
+ })
65
+ .then(() => {
66
+ setGuideActive(true);
67
+ setGuideDismissed(false);
68
+ window.dispatchEvent(new Event('guide-state-updated'));
69
+ })
70
+ .catch(err => console.error('Failed to restart walkthrough:', err));
71
+ }, []);
72
+
52
73
  const origin = useSyncExternalStore(
53
74
  () => () => {},
54
75
  () => `${window.location.protocol}//${window.location.hostname}`,
@@ -207,6 +228,13 @@ export function KnowledgeTab({ data, setData, t }: KnowledgeTabProps) {
207
228
  </div>
208
229
  <Toggle checked={!guideDismissed} onChange={() => handleGuideToggle()} />
209
230
  </div>
231
+ <button
232
+ onClick={handleRestartWalkthrough}
233
+ className="flex items-center gap-1.5 mt-2 px-3 py-1.5 text-xs rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
234
+ >
235
+ <RotateCcw size={12} />
236
+ {k.restartWalkthrough ?? 'Restart walkthrough'}
237
+ </button>
210
238
  </div>
211
239
  )}
212
240
 
@@ -234,6 +234,7 @@ export const en = {
234
234
  authTokenClear: 'Clear token',
235
235
  authTokenResetConfirm: 'Regenerate token? All existing MCP clients will need to update their config.',
236
236
  authTokenMcpPort: 'MCP port',
237
+ restartWalkthrough: 'Restart walkthrough',
237
238
  },
238
239
  sync: {
239
240
  emptyTitle: 'Cross-device Sync',
@@ -259,6 +259,7 @@ export const zh = {
259
259
  authTokenClear: '清除令牌',
260
260
  authTokenResetConfirm: '重新生成令牌?所有 MCP 客户端配置都需要更新。',
261
261
  authTokenMcpPort: 'MCP 端口',
262
+ restartWalkthrough: '重新开始引导',
262
263
  },
263
264
  sync: {
264
265
  emptyTitle: '跨设备同步',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.5.36",
3
+ "version": "0.5.37",
4
4
  "description": "MindOS — Human-Agent Collaborative Mind System. Local-first knowledge base that syncs your mind to all AI Agents via MCP.",
5
5
  "keywords": [
6
6
  "mindos",