@geminilight/mindos 0.5.37 → 0.5.38

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.
@@ -0,0 +1,117 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useCallback } from 'react';
4
+ import { RIGHT_ASK_DEFAULT_WIDTH, RIGHT_ASK_MIN_WIDTH, RIGHT_ASK_MAX_WIDTH } from '@/components/RightAskPanel';
5
+ import { useAskModal } from './useAskModal';
6
+
7
+ export interface AskPanelState {
8
+ askPanelOpen: boolean;
9
+ askPanelWidth: number;
10
+ askMode: 'panel' | 'popup';
11
+ desktopAskPopupOpen: boolean;
12
+ askInitialMessage: string;
13
+ askOpenSource: 'user' | 'guide' | 'guide-next';
14
+ toggleAskPanel: () => void;
15
+ closeAskPanel: () => void;
16
+ closeDesktopAskPopup: () => void;
17
+ handleAskWidthChange: (w: number) => void;
18
+ handleAskWidthCommit: (w: number) => void;
19
+ handleAskModeSwitch: () => void;
20
+ }
21
+
22
+ /**
23
+ * Manages right-side Ask AI panel state: open/close, width, panel/popup mode, initial message.
24
+ * Extracted from SidebarLayout to reduce its state complexity.
25
+ */
26
+ export function useAskPanel(): AskPanelState {
27
+ const [askPanelOpen, setAskPanelOpen] = useState(false);
28
+ const [askPanelWidth, setAskPanelWidth] = useState(RIGHT_ASK_DEFAULT_WIDTH);
29
+ const [askMode, setAskMode] = useState<'panel' | 'popup'>('panel');
30
+ const [desktopAskPopupOpen, setDesktopAskPopupOpen] = useState(false);
31
+ const [askInitialMessage, setAskInitialMessage] = useState('');
32
+ const [askOpenSource, setAskOpenSource] = useState<'user' | 'guide' | 'guide-next'>('user');
33
+
34
+ const askModal = useAskModal();
35
+
36
+ // Load persisted width + mode
37
+ useEffect(() => {
38
+ try {
39
+ const stored = localStorage.getItem('right-ask-panel-width');
40
+ if (stored) {
41
+ const w = parseInt(stored, 10);
42
+ if (w >= RIGHT_ASK_MIN_WIDTH && w <= RIGHT_ASK_MAX_WIDTH) setAskPanelWidth(w);
43
+ }
44
+ const mode = localStorage.getItem('ask-mode');
45
+ if (mode === 'popup') setAskMode('popup');
46
+ } catch {}
47
+
48
+ const onStorage = (e: StorageEvent) => {
49
+ if (e.key === 'ask-mode' && (e.newValue === 'panel' || e.newValue === 'popup')) {
50
+ setAskMode(e.newValue);
51
+ }
52
+ };
53
+ window.addEventListener('storage', onStorage);
54
+ return () => window.removeEventListener('storage', onStorage);
55
+ }, []);
56
+
57
+ // Bridge useAskModal store → right Ask panel or popup
58
+ useEffect(() => {
59
+ if (askModal.open) {
60
+ setAskInitialMessage(askModal.initialMessage);
61
+ setAskOpenSource(askModal.source);
62
+ if (askMode === 'popup') {
63
+ setDesktopAskPopupOpen(true);
64
+ } else {
65
+ setAskPanelOpen(true);
66
+ }
67
+ askModal.close();
68
+ }
69
+ }, [askModal.open, askModal.initialMessage, askModal.source, askModal.close, askMode]);
70
+
71
+ const toggleAskPanel = useCallback(() => {
72
+ if (askMode === 'popup') {
73
+ setDesktopAskPopupOpen(v => {
74
+ if (!v) { setAskInitialMessage(''); setAskOpenSource('user'); }
75
+ return !v;
76
+ });
77
+ } else {
78
+ setAskPanelOpen(v => {
79
+ if (!v) { setAskInitialMessage(''); setAskOpenSource('user'); }
80
+ return !v;
81
+ });
82
+ }
83
+ }, [askMode]);
84
+
85
+ const closeAskPanel = useCallback(() => setAskPanelOpen(false), []);
86
+ const closeDesktopAskPopup = useCallback(() => setDesktopAskPopupOpen(false), []);
87
+
88
+ const handleAskWidthChange = useCallback((w: number) => setAskPanelWidth(w), []);
89
+ const handleAskWidthCommit = useCallback((w: number) => {
90
+ try { localStorage.setItem('right-ask-panel-width', String(w)); } catch {}
91
+ }, []);
92
+
93
+ const handleAskModeSwitch = useCallback(() => {
94
+ setAskMode(prev => {
95
+ const next = prev === 'panel' ? 'popup' : 'panel';
96
+ try {
97
+ localStorage.setItem('ask-mode', next);
98
+ window.dispatchEvent(new StorageEvent('storage', { key: 'ask-mode', newValue: next }));
99
+ } catch {}
100
+ if (next === 'popup') {
101
+ setAskPanelOpen(false);
102
+ setDesktopAskPopupOpen(true);
103
+ } else {
104
+ setDesktopAskPopupOpen(false);
105
+ setAskPanelOpen(true);
106
+ }
107
+ return next;
108
+ });
109
+ }, []);
110
+
111
+ return {
112
+ askPanelOpen, askPanelWidth, askMode, desktopAskPopupOpen,
113
+ askInitialMessage, askOpenSource,
114
+ toggleAskPanel, closeAskPanel, closeDesktopAskPopup,
115
+ handleAskWidthChange, handleAskWidthCommit, handleAskModeSwitch,
116
+ };
117
+ }
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useCallback } from 'react';
4
+ import { MIN_PANEL_WIDTH, MAX_PANEL_WIDTH_ABS, PANEL_WIDTH } from '@/components/Panel';
5
+ import type { PanelId } from '@/components/ActivityBar';
6
+ import { RAIL_WIDTH_COLLAPSED, RAIL_WIDTH_EXPANDED } from '@/components/ActivityBar';
7
+
8
+ export interface LeftPanelState {
9
+ activePanel: PanelId | null;
10
+ setActivePanel: (p: PanelId | null | ((prev: PanelId | null) => PanelId | null)) => void;
11
+ panelWidth: number | null;
12
+ panelMaximized: boolean;
13
+ railExpanded: boolean;
14
+ railWidth: number;
15
+ panelOpen: boolean;
16
+ effectivePanelWidth: number;
17
+ handlePanelWidthChange: (w: number) => void;
18
+ handlePanelWidthCommit: (w: number) => void;
19
+ handlePanelMaximize: () => void;
20
+ handleExpandedChange: (expanded: boolean) => void;
21
+ }
22
+
23
+ /**
24
+ * Manages left panel state: active panel, width, maximize, rail expansion.
25
+ * Extracted from SidebarLayout to reduce its state complexity.
26
+ */
27
+ export function useLeftPanel(): LeftPanelState {
28
+ const [activePanel, setActivePanel] = useState<PanelId | null>('files');
29
+ const [panelWidth, setPanelWidth] = useState<number | null>(null);
30
+ const [panelMaximized, setPanelMaximized] = useState(false);
31
+ const [railExpanded, setRailExpanded] = useState(false);
32
+
33
+ // Load persisted rail state
34
+ useEffect(() => {
35
+ try {
36
+ if (localStorage.getItem('rail-expanded') === 'true') setRailExpanded(true);
37
+ } catch {}
38
+ }, []);
39
+
40
+ // Load persisted panel width when activePanel changes
41
+ useEffect(() => {
42
+ if (!activePanel) return;
43
+ try {
44
+ const stored = localStorage.getItem('left-panel-width');
45
+ if (stored) {
46
+ const w = parseInt(stored, 10);
47
+ if (w >= MIN_PANEL_WIDTH && w <= MAX_PANEL_WIDTH_ABS) {
48
+ setPanelWidth(w);
49
+ return;
50
+ }
51
+ }
52
+ } catch {}
53
+ setPanelWidth(280);
54
+ }, [activePanel]);
55
+
56
+ // Exit maximize when switching panels
57
+ useEffect(() => { setPanelMaximized(false); }, [activePanel]);
58
+
59
+ const handlePanelWidthChange = useCallback((w: number) => setPanelWidth(w), []);
60
+ const handlePanelWidthCommit = useCallback((w: number) => {
61
+ try { localStorage.setItem('left-panel-width', String(w)); } catch {}
62
+ }, []);
63
+ const handlePanelMaximize = useCallback(() => setPanelMaximized(v => !v), []);
64
+
65
+ const handleExpandedChange = useCallback((expanded: boolean) => {
66
+ setRailExpanded(expanded);
67
+ try { localStorage.setItem('rail-expanded', String(expanded)); } catch {}
68
+ }, []);
69
+
70
+ const railWidth = railExpanded ? RAIL_WIDTH_EXPANDED : RAIL_WIDTH_COLLAPSED;
71
+ const panelOpen = activePanel !== null;
72
+ const effectivePanelWidth = panelWidth ?? (activePanel ? PANEL_WIDTH[activePanel] : 280);
73
+
74
+ return {
75
+ activePanel, setActivePanel,
76
+ panelWidth, panelMaximized, railExpanded, railWidth,
77
+ panelOpen, effectivePanelWidth,
78
+ handlePanelWidthChange, handlePanelWidthCommit, handlePanelMaximize,
79
+ handleExpandedChange,
80
+ };
81
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.5.37",
3
+ "version": "0.5.38",
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",
@@ -18,7 +18,21 @@ echo "🧪 Running tests..."
18
18
  npm test
19
19
  echo ""
20
20
 
21
- # 3. Smoke test: pack → install in temp dir → verify CLI works
21
+ # 3. Verify Next.js build
22
+ echo "🔨 Verifying Next.js build..."
23
+ cd app
24
+ if npx next build 2>&1 | tail -5; then
25
+ echo " ✅ Next.js build succeeded"
26
+ else
27
+ echo "❌ Next.js build failed"
28
+ exit 1
29
+ fi
30
+ cd ..
31
+ # Restore any files modified by next build (e.g. next-env.d.ts)
32
+ git checkout -- . 2>/dev/null || true
33
+ echo ""
34
+
35
+ # 4. Smoke test: pack → install in temp dir → verify CLI works
22
36
  echo "🔍 Smoke testing package..."
23
37
  SMOKE_DIR=$(mktemp -d)
24
38
  TARBALL=$(npm pack --pack-destination "$SMOKE_DIR" 2>/dev/null | tail -1)
@@ -79,20 +93,20 @@ cd - >/dev/null
79
93
  echo " 🟢 Smoke test passed"
80
94
  echo ""
81
95
 
82
- # 3. Bump version (creates commit + tag automatically)
96
+ # 5. Bump version (creates commit + tag automatically)
83
97
  echo "📦 Bumping version ($BUMP)..."
84
98
  npm version "$BUMP" -m "%s"
85
99
  VERSION="v$(node -p "require('./package.json').version")"
86
100
  echo " Version: $VERSION"
87
101
  echo ""
88
102
 
89
- # 4. Push commit + tag
103
+ # 6. Push commit + tag
90
104
  echo "🚀 Pushing to origin..."
91
105
  git push origin main
92
106
  git push origin "$VERSION"
93
107
  echo ""
94
108
 
95
- # 5. Wait for CI
109
+ # 7. Wait for CI
96
110
  # Flow: tag push → sync-to-mindos (syncs code + tag to public repo) → public repo publish-npm
97
111
  if command -v gh &>/dev/null; then
98
112
  echo "⏳ Waiting for sync → publish pipeline..."