@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.
- package/app/app/globals.css +0 -1
- package/app/components/SidebarLayout.tsx +70 -235
- package/app/components/settings/McpSkillCreateForm.tsx +178 -0
- package/app/components/settings/McpSkillRow.tsx +145 -0
- package/app/components/settings/McpSkillsSection.tsx +71 -307
- package/app/hooks/useAskPanel.ts +117 -0
- package/app/hooks/useLeftPanel.ts +81 -0
- package/package.json +1 -1
- package/scripts/release.sh +18 -4
|
@@ -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
package/scripts/release.sh
CHANGED
|
@@ -18,7 +18,21 @@ echo "🧪 Running tests..."
|
|
|
18
18
|
npm test
|
|
19
19
|
echo ""
|
|
20
20
|
|
|
21
|
-
# 3.
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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..."
|