@geminilight/mindos 0.6.14 → 0.6.16
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 +49 -2
- package/app/app/page.tsx +1 -19
- package/app/components/CreateSpaceModal.tsx +3 -3
- package/app/components/CustomSelect.tsx +228 -0
- package/app/components/DirPicker.tsx +110 -63
- package/app/components/FileTree.tsx +54 -32
- package/app/components/HomeContent.tsx +69 -13
- package/app/components/ImportModal.tsx +92 -39
- package/app/components/Panel.tsx +87 -21
- package/app/components/SidebarLayout.tsx +18 -5
- package/app/components/changes/ChangesContentPage.tsx +34 -23
- package/app/components/renderers/csv/ConfigPanel.tsx +10 -7
- package/app/components/settings/KnowledgeTab.tsx +38 -12
- package/app/components/settings/McpAgentInstall.tsx +14 -30
- package/app/components/settings/McpSkillsSection.tsx +43 -27
- package/app/components/settings/McpTab.tsx +30 -37
- package/app/components/settings/UninstallTab.tsx +1 -1
- package/app/components/setup/StepAgents.tsx +1 -1
- package/app/lib/core/create-space.ts +12 -0
- package/app/lib/i18n-en.ts +19 -2
- package/app/lib/i18n-zh.ts +21 -4
- package/bin/cli.js +37 -14
- package/package.json +1 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { useState, useMemo, useRef, useEffect } from 'react';
|
|
2
|
-
import { Loader2,
|
|
2
|
+
import { Loader2, Copy, Check, Monitor, Globe, AlertCircle, RotateCcw, RefreshCw } from 'lucide-react';
|
|
3
3
|
import { useMcpDataOptional } from '@/hooks/useMcpData';
|
|
4
4
|
import { generateSnippet } from '@/lib/mcp-snippets';
|
|
5
5
|
import { copyToClipboard } from '@/lib/clipboard';
|
|
6
6
|
import { apiFetch } from '@/lib/api';
|
|
7
|
+
import CustomSelect from '@/components/CustomSelect';
|
|
8
|
+
import type { SelectItem } from '@/components/CustomSelect';
|
|
7
9
|
import type { McpTabProps, McpStatus, AgentInfo } from './types';
|
|
8
10
|
import AgentInstall from './McpAgentInstall';
|
|
9
11
|
import SkillsSection from './McpSkillsSection';
|
|
@@ -179,42 +181,33 @@ function AgentConfigViewer({ connectedAgents, detectedAgents, notFoundAgents, cu
|
|
|
179
181
|
return (
|
|
180
182
|
<div className="rounded-xl border border-border bg-card p-4 space-y-3">
|
|
181
183
|
{/* Agent selector */}
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
{
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
<option key={a.key} value={a.key}>
|
|
210
|
-
· {a.name}
|
|
211
|
-
</option>
|
|
212
|
-
))}
|
|
213
|
-
</optgroup>
|
|
214
|
-
)}
|
|
215
|
-
</select>
|
|
216
|
-
<ChevronDown size={14} className="absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none" />
|
|
217
|
-
</div>
|
|
184
|
+
<CustomSelect
|
|
185
|
+
value={selectedAgent}
|
|
186
|
+
onChange={onSelectAgent}
|
|
187
|
+
options={[
|
|
188
|
+
...(connectedAgents.length > 0 ? [{
|
|
189
|
+
label: m?.connectedGroup ?? 'Connected',
|
|
190
|
+
options: connectedAgents.map(a => ({
|
|
191
|
+
value: a.key,
|
|
192
|
+
label: `${a.name} — ${a.transport ?? 'stdio'} · ${a.scope ?? 'global'}`,
|
|
193
|
+
})),
|
|
194
|
+
}] : []),
|
|
195
|
+
...(detectedAgents.length > 0 ? [{
|
|
196
|
+
label: m?.detectedGroup ?? 'Detected (not configured)',
|
|
197
|
+
options: detectedAgents.map(a => ({
|
|
198
|
+
value: a.key,
|
|
199
|
+
label: `${a.name} — ${m?.notConfigured ?? 'not configured'}`,
|
|
200
|
+
})),
|
|
201
|
+
}] : []),
|
|
202
|
+
...(notFoundAgents.length > 0 ? [{
|
|
203
|
+
label: m?.notFoundGroup ?? 'Not Installed',
|
|
204
|
+
options: notFoundAgents.map(a => ({
|
|
205
|
+
value: a.key,
|
|
206
|
+
label: a.name,
|
|
207
|
+
})),
|
|
208
|
+
}] : []),
|
|
209
|
+
] as SelectItem[]}
|
|
210
|
+
/>
|
|
218
211
|
|
|
219
212
|
{currentAgent && (
|
|
220
213
|
<>
|
|
@@ -70,7 +70,7 @@ export function UninstallTab() {
|
|
|
70
70
|
checked={checked}
|
|
71
71
|
onChange={e => !disabled && onChange(e.target.checked)}
|
|
72
72
|
disabled={disabled}
|
|
73
|
-
className="mt-0.5
|
|
73
|
+
className="mt-0.5 form-check"
|
|
74
74
|
/>
|
|
75
75
|
<div>
|
|
76
76
|
<p className="text-xs font-medium text-foreground">{label}</p>
|
|
@@ -101,7 +101,7 @@ export default function StepAgents({
|
|
|
101
101
|
type="checkbox"
|
|
102
102
|
checked={selectedAgents.has(agent.key)}
|
|
103
103
|
onChange={() => toggleAgent(agent.key)}
|
|
104
|
-
|
|
104
|
+
className="form-check"
|
|
105
105
|
disabled={agentStatuses[agent.key]?.state === 'installing'}
|
|
106
106
|
/>
|
|
107
107
|
<span className="text-sm flex-1" style={{ color: 'var(--foreground)' }}>{agent.name}</span>
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
1
3
|
import { MindOSError, ErrorCodes } from '@/lib/errors';
|
|
2
4
|
import { createFile } from './fs-ops';
|
|
5
|
+
import { INSTRUCTION_TEMPLATE, cleanDirName } from './space-scaffold';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Generate the template README.md content for a new space.
|
|
@@ -39,5 +42,14 @@ export function createSpaceFilesystem(
|
|
|
39
42
|
const readmeContent = generateReadmeTemplate(fullPath, trimmed, description);
|
|
40
43
|
|
|
41
44
|
createFile(mindRoot, `${fullPath}/README.md`, readmeContent);
|
|
45
|
+
|
|
46
|
+
// Explicitly create INSTRUCTION.md for ALL spaces (including nested ones).
|
|
47
|
+
// scaffoldIfNewSpace only handles top-level dirs; nested spaces need this.
|
|
48
|
+
const absDir = path.resolve(mindRoot, fullPath);
|
|
49
|
+
const instructionPath = path.join(absDir, 'INSTRUCTION.md');
|
|
50
|
+
if (!fs.existsSync(instructionPath)) {
|
|
51
|
+
fs.writeFileSync(instructionPath, INSTRUCTION_TEMPLATE(cleanDirName(trimmed)), 'utf-8');
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
return { path: fullPath };
|
|
43
55
|
}
|
package/app/lib/i18n-en.ts
CHANGED
|
@@ -26,7 +26,7 @@ export const en = {
|
|
|
26
26
|
rootLevel: 'Root',
|
|
27
27
|
optional: 'optional',
|
|
28
28
|
aiInit: 'AI initialize content',
|
|
29
|
-
aiInitHint: 'AI will generate
|
|
29
|
+
aiInitHint: 'AI will generate a description and guidelines for this space',
|
|
30
30
|
aiInitNoKey: 'Configure an API key in Settings → AI to enable',
|
|
31
31
|
aiInitGenerating: (name: string) => `Generating content for ${name}`,
|
|
32
32
|
aiInitReady: (name: string) => `${name} ready`,
|
|
@@ -37,10 +37,21 @@ export const en = {
|
|
|
37
37
|
cancelCreate: 'Cancel',
|
|
38
38
|
continueEditing: 'Continue editing',
|
|
39
39
|
newNote: 'New Notes',
|
|
40
|
-
builtinFeatures: '
|
|
40
|
+
builtinFeatures: 'Tools',
|
|
41
41
|
builtinActive: 'Active',
|
|
42
42
|
builtinInactive: 'Not active',
|
|
43
|
+
toolName: {
|
|
44
|
+
'agent-inspector': 'Agent Inspector',
|
|
45
|
+
'config-panel': 'Config Panel',
|
|
46
|
+
'todo': 'TODO Board',
|
|
47
|
+
} as Record<string, string>,
|
|
48
|
+
toolDesc: {
|
|
49
|
+
'agent-inspector': 'View agent tool-call logs and audit trail',
|
|
50
|
+
'config-panel': 'Edit and manage global configuration',
|
|
51
|
+
'todo': 'Manage tasks as an interactive kanban board',
|
|
52
|
+
} as Record<string, string>,
|
|
43
53
|
plugins: 'Extensions',
|
|
54
|
+
changeHistory: 'Change History',
|
|
44
55
|
showMore: 'Show more',
|
|
45
56
|
showLess: 'Show less',
|
|
46
57
|
viewAll: 'View all',
|
|
@@ -78,9 +89,13 @@ export const en = {
|
|
|
78
89
|
collapseTitle: 'Collapse sidebar',
|
|
79
90
|
expandTitle: 'Expand sidebar',
|
|
80
91
|
collapseLevel: 'Collapse one level',
|
|
92
|
+
collapseLevelHint: 'Collapse one level (double-click: all)',
|
|
81
93
|
expandLevel: 'Expand one level',
|
|
94
|
+
expandLevelHint: 'Expand one level (double-click: all)',
|
|
82
95
|
importFile: 'Import file',
|
|
96
|
+
new: 'New',
|
|
83
97
|
newFile: 'New file',
|
|
98
|
+
newSpace: 'New Space',
|
|
84
99
|
sync: {
|
|
85
100
|
synced: 'Synced',
|
|
86
101
|
unpushed: 'awaiting push',
|
|
@@ -738,6 +753,8 @@ export const en = {
|
|
|
738
753
|
},
|
|
739
754
|
arrowTo: '→',
|
|
740
755
|
remove: 'Remove',
|
|
756
|
+
aiRecommended: 'Recommended',
|
|
757
|
+
aiRecommendedHint: 'Auto-matched by filename',
|
|
741
758
|
conflictsFound: (n: number) => `${n} file${n !== 1 ? 's' : ''} already exist${n === 1 ? 's' : ''}`,
|
|
742
759
|
organizeTitle: 'AI Organizing',
|
|
743
760
|
organizeProcessing: 'AI is analyzing and organizing your files...',
|
package/app/lib/i18n-zh.ts
CHANGED
|
@@ -51,7 +51,7 @@ export const zh = {
|
|
|
51
51
|
rootLevel: '根目录',
|
|
52
52
|
optional: '可选',
|
|
53
53
|
aiInit: 'AI 初始化内容',
|
|
54
|
-
aiInitHint: 'AI
|
|
54
|
+
aiInitHint: 'AI 将自动生成空间说明和操作指南',
|
|
55
55
|
aiInitNoKey: '在 设置 → AI 中配置 API 密钥以启用',
|
|
56
56
|
aiInitGenerating: (name: string) => `正在为「${name}」生成内容`,
|
|
57
57
|
aiInitReady: (name: string) => `「${name}」已就绪`,
|
|
@@ -62,14 +62,25 @@ export const zh = {
|
|
|
62
62
|
cancelCreate: '取消',
|
|
63
63
|
continueEditing: '继续编辑',
|
|
64
64
|
newNote: '新建笔记',
|
|
65
|
-
builtinFeatures: '
|
|
65
|
+
builtinFeatures: '工具面板',
|
|
66
66
|
builtinActive: '已启用',
|
|
67
67
|
builtinInactive: '未激活',
|
|
68
|
-
|
|
68
|
+
toolName: {
|
|
69
|
+
'agent-inspector': '审计面板',
|
|
70
|
+
'config-panel': '配置面板',
|
|
71
|
+
'todo': '待办面板',
|
|
72
|
+
} as Record<string, string>,
|
|
73
|
+
toolDesc: {
|
|
74
|
+
'agent-inspector': '查看 Agent 操作日志与调用轨迹',
|
|
75
|
+
'config-panel': '编辑和管理全局配置项',
|
|
76
|
+
'todo': '以看板形式管理待办事项',
|
|
77
|
+
} as Record<string, string>,
|
|
78
|
+
plugins: '扩展',
|
|
79
|
+
changeHistory: '变更历史',
|
|
69
80
|
showMore: '查看更多',
|
|
70
81
|
showLess: '收起',
|
|
71
82
|
viewAll: '查看全部',
|
|
72
|
-
createToActivate: '创建 {file}
|
|
83
|
+
createToActivate: '创建 {file} 以启用',
|
|
73
84
|
shortcuts: {
|
|
74
85
|
searchFiles: '搜索文件',
|
|
75
86
|
askAI: 'MindOS Agent',
|
|
@@ -103,9 +114,13 @@ export const zh = {
|
|
|
103
114
|
collapseTitle: '收起侧栏',
|
|
104
115
|
expandTitle: '展开侧栏',
|
|
105
116
|
collapseLevel: '折叠一级',
|
|
117
|
+
collapseLevelHint: '折叠一级(双击:全部折叠)',
|
|
106
118
|
expandLevel: '展开一级',
|
|
119
|
+
expandLevelHint: '展开一级(双击:全部展开)',
|
|
107
120
|
importFile: '导入文件',
|
|
121
|
+
new: '新建',
|
|
108
122
|
newFile: '新建文件',
|
|
123
|
+
newSpace: '新建空间',
|
|
109
124
|
sync: {
|
|
110
125
|
synced: '已同步',
|
|
111
126
|
unpushed: '待推送',
|
|
@@ -762,6 +777,8 @@ export const zh = {
|
|
|
762
777
|
},
|
|
763
778
|
arrowTo: '→',
|
|
764
779
|
remove: '移除',
|
|
780
|
+
aiRecommended: '推荐',
|
|
781
|
+
aiRecommendedHint: '根据文件名自动匹配',
|
|
765
782
|
conflictsFound: (n: number) => `${n} 个文件已存在`,
|
|
766
783
|
organizeTitle: 'AI 整理中',
|
|
767
784
|
organizeProcessing: 'AI 正在分析和整理你的文件...',
|
package/bin/cli.js
CHANGED
|
@@ -771,16 +771,19 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
771
771
|
|
|
772
772
|
// Stage 3: Rebuild
|
|
773
773
|
writeUpdateStatus('rebuilding', vOpts);
|
|
774
|
-
|
|
774
|
+
let daemonBuildFailed = '';
|
|
775
|
+
try {
|
|
776
|
+
buildIfNeeded(updatedRoot);
|
|
777
|
+
} catch (err) {
|
|
778
|
+
daemonBuildFailed = err instanceof Error ? err.message : String(err);
|
|
779
|
+
console.error(yellow(`\n Pre-build failed: ${daemonBuildFailed}`));
|
|
780
|
+
console.error(yellow(' Daemon will attempt to rebuild on startup...\n'));
|
|
781
|
+
}
|
|
775
782
|
|
|
776
|
-
// Stage 4: Restart
|
|
783
|
+
// Stage 4: Restart — always attempt, even if pre-build failed
|
|
784
|
+
// (daemon has auto-restart; `mindos start` retries the build)
|
|
777
785
|
writeUpdateStatus('restarting', vOpts);
|
|
778
786
|
await runGatewayCommand('install');
|
|
779
|
-
// install() starts the service:
|
|
780
|
-
// - systemd: daemon-reload + enable + start
|
|
781
|
-
// - launchd: bootstrap (RunAtLoad=true auto-starts)
|
|
782
|
-
// Do NOT call start() again — on macOS kickstart -k would kill the
|
|
783
|
-
// just-started process, causing a port-conflict race with KeepAlive.
|
|
784
787
|
const updateConfig = (() => {
|
|
785
788
|
try { return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8')); } catch { return {}; }
|
|
786
789
|
})();
|
|
@@ -799,8 +802,11 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
799
802
|
console.log(`${'─'.repeat(53)}\n`);
|
|
800
803
|
writeUpdateStatus('done', vOpts);
|
|
801
804
|
} else {
|
|
802
|
-
|
|
803
|
-
|
|
805
|
+
const failMsg = daemonBuildFailed
|
|
806
|
+
? `Build failed (${daemonBuildFailed}), server did not come back up`
|
|
807
|
+
: 'Server did not come back up in time';
|
|
808
|
+
writeUpdateFailed('restarting', failMsg, vOpts);
|
|
809
|
+
console.error(red(`✘ ${failMsg}. Check logs: mindos logs\n`));
|
|
804
810
|
process.exit(1);
|
|
805
811
|
}
|
|
806
812
|
} else {
|
|
@@ -828,9 +834,17 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
828
834
|
|
|
829
835
|
// Stage 3: Rebuild
|
|
830
836
|
writeUpdateStatus('rebuilding', vOpts);
|
|
831
|
-
|
|
837
|
+
let buildFailed = '';
|
|
838
|
+
try {
|
|
839
|
+
buildIfNeeded(updatedRoot);
|
|
840
|
+
} catch (err) {
|
|
841
|
+
buildFailed = err instanceof Error ? err.message : String(err);
|
|
842
|
+
console.error(yellow(`\n Pre-build failed: ${buildFailed}`));
|
|
843
|
+
console.error(yellow(' Starting server anyway (it will retry the build)...\n'));
|
|
844
|
+
}
|
|
832
845
|
|
|
833
|
-
// Stage 4: Restart
|
|
846
|
+
// Stage 4: Restart — always attempt, even if pre-build failed
|
|
847
|
+
// (`mindos start` has its own build-on-startup logic)
|
|
834
848
|
writeUpdateStatus('restarting', vOpts);
|
|
835
849
|
const newCliPath = resolve(updatedRoot, 'bin', 'cli.js');
|
|
836
850
|
const childEnv = { ...process.env };
|
|
@@ -858,13 +872,22 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
858
872
|
console.log(`${'─'.repeat(53)}\n`);
|
|
859
873
|
writeUpdateStatus('done', vOpts);
|
|
860
874
|
} else {
|
|
861
|
-
|
|
862
|
-
|
|
875
|
+
const failMsg = buildFailed
|
|
876
|
+
? `Build failed (${buildFailed}), server did not come back up`
|
|
877
|
+
: 'Server did not come back up in time';
|
|
878
|
+
writeUpdateFailed('restarting', failMsg, vOpts);
|
|
879
|
+
console.error(red(`✘ ${failMsg}. Check logs: mindos logs\n`));
|
|
863
880
|
process.exit(1);
|
|
864
881
|
}
|
|
865
882
|
} else {
|
|
866
883
|
// No running instance — just build and tell user to start manually
|
|
867
|
-
|
|
884
|
+
try {
|
|
885
|
+
buildIfNeeded(updatedRoot);
|
|
886
|
+
} catch (err) {
|
|
887
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
888
|
+
console.error(yellow(`\n Pre-build failed: ${msg}`));
|
|
889
|
+
console.error(dim(' The build will be retried when you run `mindos start`.'));
|
|
890
|
+
}
|
|
868
891
|
console.log(`\n${green('✔')} ${bold(`Updated: ${currentVersion} → ${newVersion}`)}`);
|
|
869
892
|
console.log(dim(' Run `mindos start` to start the updated version.'));
|
|
870
893
|
console.log(` ${dim('View changelog:')} ${cyan('https://github.com/GeminiLight/MindOS/releases')}\n`);
|
package/package.json
CHANGED