@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.
@@ -1,9 +1,11 @@
1
1
  import { useState, useMemo, useRef, useEffect } from 'react';
2
- import { Loader2, ChevronDown, Copy, Check, Monitor, Globe, AlertCircle, RotateCcw, RefreshCw } from 'lucide-react';
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
- <div className="relative">
183
- <select
184
- value={selectedAgent}
185
- onChange={(e) => onSelectAgent(e.target.value)}
186
- className="w-full appearance-none px-3 py-2 pr-8 text-xs rounded-lg border border-border bg-background text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
187
- >
188
- {connectedAgents.length > 0 && (
189
- <optgroup label={m?.connectedGroup ?? 'Connected'}>
190
- {connectedAgents.map(a => (
191
- <option key={a.key} value={a.key}>
192
- ✓ {a.name} {a.transport ?? 'stdio'} · {a.scope ?? 'global'}
193
- </option>
194
- ))}
195
- </optgroup>
196
- )}
197
- {detectedAgents.length > 0 && (
198
- <optgroup label={m?.detectedGroup ?? 'Detected (not configured)'}>
199
- {detectedAgents.map(a => (
200
- <option key={a.key} value={a.key}>
201
- {a.name} — {m?.notConfigured ?? 'not configured'}
202
- </option>
203
- ))}
204
- </optgroup>
205
- )}
206
- {notFoundAgents.length > 0 && (
207
- <optgroup label={m?.notFoundGroup ?? 'Not Installed'}>
208
- {notFoundAgents.map(a => (
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 accent-[var(--amber)] focus-visible:ring-1 focus-visible:ring-ring"
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
- style={{ accentColor: 'var(--amber)' }}
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
  }
@@ -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 README and INSTRUCTION for this space',
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: 'Built-in capabilities',
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...',
@@ -51,7 +51,7 @@ export const zh = {
51
51
  rootLevel: '根目录',
52
52
  optional: '可选',
53
53
  aiInit: 'AI 初始化内容',
54
- aiInitHint: 'AI 将为此空间生成 README 和 INSTRUCTION',
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
- plugins: '插件扩展',
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
- buildIfNeeded(updatedRoot);
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
- writeUpdateFailed('restarting', 'Server did not come back up in time', vOpts);
803
- console.error(red('✘ MindOS did not come back up in time. Check logs: mindos logs\n'));
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
- buildIfNeeded(updatedRoot);
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
- writeUpdateFailed('restarting', 'Server did not come back up in time', vOpts);
862
- console.error(red('✘ MindOS did not come back up in time. Check logs: mindos logs\n'));
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
- buildIfNeeded(updatedRoot);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.6.14",
3
+ "version": "0.6.16",
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",