@geminilight/mindos 0.5.51 → 0.5.54

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.
@@ -29,6 +29,7 @@ type UpdateState = 'idle' | 'checking' | 'updating' | 'updated' | 'error' | 'tim
29
29
  const CHANGELOG_URL = 'https://github.com/GeminiLight/MindOS/releases';
30
30
  const POLL_INTERVAL = 3_000;
31
31
  const POLL_TIMEOUT = 5 * 60 * 1000; // 5 minutes
32
+ const UPDATE_STATE_KEY = 'mindos_update_in_progress';
32
33
 
33
34
  const STAGE_LABELS: Record<string, { en: string; zh: string }> = {
34
35
  downloading: { en: 'Downloading update', zh: '下载更新' },
@@ -77,8 +78,6 @@ export function UpdateTab() {
77
78
  }
78
79
  }, [u]);
79
80
 
80
- useEffect(() => { checkUpdate(); }, [checkUpdate]);
81
-
82
81
  const cleanup = useCallback(() => {
83
82
  clearInterval(pollRef.current);
84
83
  clearTimeout(timeoutRef.current);
@@ -91,33 +90,14 @@ export function UpdateTab() {
91
90
  setState('updated');
92
91
  localStorage.removeItem('mindos_update_latest');
93
92
  localStorage.removeItem('mindos_update_dismissed');
93
+ localStorage.removeItem(UPDATE_STATE_KEY);
94
94
  window.dispatchEvent(new Event('mindos:update-dismissed'));
95
95
  setTimeout(() => window.location.reload(), 2000);
96
96
  }, [cleanup]);
97
97
 
98
- useEffect(() => cleanup, [cleanup]);
99
-
100
- const handleUpdate = useCallback(async () => {
101
- setState('updating');
102
- setErrorMsg('');
103
- setUpdateError(null);
104
- setServerDown(false);
105
- setStages([
106
- { id: 'downloading', status: 'pending' },
107
- { id: 'skills', status: 'pending' },
108
- { id: 'rebuilding', status: 'pending' },
109
- { id: 'restarting', status: 'pending' },
110
- ]);
111
-
112
- try {
113
- await apiFetch('/api/update', { method: 'POST' });
114
- } catch {
115
- // Expected — server may die during update
116
- }
117
-
118
- // Poll update-status for stage progress
98
+ /** Start polling for update progress */
99
+ const startPolling = useCallback(() => {
119
100
  pollRef.current = setInterval(async () => {
120
- // Try status endpoint first (may fail when server is restarting)
121
101
  try {
122
102
  const status = await apiFetch<UpdateStatus>('/api/update-status', { timeout: 5000 });
123
103
  setServerDown(false);
@@ -128,13 +108,13 @@ export function UpdateTab() {
128
108
 
129
109
  if (status.stage === 'failed') {
130
110
  cleanup();
111
+ localStorage.removeItem(UPDATE_STATE_KEY);
131
112
  setUpdateError(status.error || 'Update failed');
132
113
  setState('error');
133
114
  return;
134
115
  }
135
116
 
136
117
  if (status.stage === 'done') {
137
- // Verify version actually changed
138
118
  try {
139
119
  const data = await apiFetch<UpdateInfo>('/api/update-check');
140
120
  if (data.current !== originalVersion.current) {
@@ -144,11 +124,11 @@ export function UpdateTab() {
144
124
  } catch { /* new server may not be fully ready */ }
145
125
  }
146
126
  } catch {
147
- // Server restarting — also try update-check as fallback
127
+ // Server restarting — try update-check as fallback
148
128
  setServerDown(true);
149
129
  try {
150
130
  const data = await apiFetch<UpdateInfo>('/api/update-check', { timeout: 5000 });
151
- if (data.current !== originalVersion.current) {
131
+ if (data.current && data.current !== originalVersion.current) {
152
132
  setStages(prev => prev.map(s => ({ ...s, status: 'done' as const })));
153
133
  completeUpdate(data);
154
134
  }
@@ -160,10 +140,68 @@ export function UpdateTab() {
160
140
 
161
141
  timeoutRef.current = setTimeout(() => {
162
142
  cleanup();
143
+ localStorage.removeItem(UPDATE_STATE_KEY);
163
144
  setState('timeout');
164
145
  }, POLL_TIMEOUT);
165
146
  }, [cleanup, completeUpdate]);
166
147
 
148
+ // On mount: check if an update was in progress (survives page reload / white screen)
149
+ useEffect(() => {
150
+ const savedState = localStorage.getItem(UPDATE_STATE_KEY);
151
+ if (savedState) {
152
+ try {
153
+ const { originalVer } = JSON.parse(savedState);
154
+ originalVersion.current = originalVer;
155
+ setState('updating');
156
+ setServerDown(true);
157
+ setStages([
158
+ { id: 'downloading', status: 'done' },
159
+ { id: 'skills', status: 'done' },
160
+ { id: 'rebuilding', status: 'done' },
161
+ { id: 'restarting', status: 'running' },
162
+ ]);
163
+ startPolling();
164
+ } catch {
165
+ localStorage.removeItem(UPDATE_STATE_KEY);
166
+ checkUpdate();
167
+ }
168
+ } else {
169
+ checkUpdate();
170
+ }
171
+ // eslint-disable-next-line react-hooks/exhaustive-deps
172
+ }, []);
173
+
174
+ useEffect(() => cleanup, [cleanup]);
175
+
176
+ const handleUpdate = useCallback(async () => {
177
+ setState('updating');
178
+ setErrorMsg('');
179
+ setUpdateError(null);
180
+ setServerDown(false);
181
+ setStages([
182
+ { id: 'downloading', status: 'pending' },
183
+ { id: 'skills', status: 'pending' },
184
+ { id: 'rebuilding', status: 'pending' },
185
+ { id: 'restarting', status: 'pending' },
186
+ ]);
187
+
188
+ // Persist update state to localStorage — survives process restart / page reload
189
+ localStorage.setItem(UPDATE_STATE_KEY, JSON.stringify({
190
+ originalVer: originalVersion.current || info?.current,
191
+ startedAt: Date.now(),
192
+ }));
193
+ // Notify UpdateOverlay (same-tab, storage event doesn't fire for same-tab writes)
194
+ window.dispatchEvent(new Event('mindos:update-started'));
195
+
196
+ try {
197
+ await apiFetch('/api/update', { method: 'POST' });
198
+ } catch {
199
+ // Expected — server may die during update
200
+ }
201
+
202
+ startPolling();
203
+ }, [startPolling, info]);
204
+
167
205
  const handleRetry = useCallback(() => {
168
206
  setUpdateError(null);
169
207
  handleUpdate();
@@ -59,6 +59,7 @@ export const en = {
59
59
  settingsTitle: 'Settings',
60
60
  plugins: 'Plugins',
61
61
  agents: 'Agents',
62
+ echo: 'Echo',
62
63
  discover: 'Discover',
63
64
  help: 'Help',
64
65
  syncLabel: 'Sync',
@@ -148,6 +149,18 @@ export const en = {
148
149
  newSkill: '+ New',
149
150
  // Footer
150
151
  advancedConfig: 'Advanced Config →',
152
+ // Hub nav (aligned with Discover panel rows)
153
+ navOverview: 'Overview',
154
+ navMcp: 'MCP',
155
+ navSkills: 'Skills',
156
+ rosterLabel: 'Your setup',
157
+ notFoundDetail: 'This agent app was not detected on this machine. Install it, then refresh the list.',
158
+ skillsEmptyHint: 'Enable and edit skills in MCP & Skills settings.',
159
+ backToList: 'Back',
160
+ closeAgentDetail: 'Close',
161
+ agentDetailPanelAria: 'Agent connection configuration',
162
+ agentDetailTransport: 'Transport',
163
+ agentDetailSnippet: 'Config snippet',
151
164
  },
152
165
  plugins: {
153
166
  title: 'Plugins',
@@ -161,6 +174,20 @@ export const en = {
161
174
  noFile: 'Entry file not found',
162
175
  createFile: 'Create {file} to activate',
163
176
  },
177
+ echo: {
178
+ title: 'Echo',
179
+ aboutYouTitle: 'Tied to you',
180
+ aboutYouHint: 'Paths and links in your library that curve back to your name.',
181
+ continuedTitle: 'Still open',
182
+ continuedHint: 'Drafts, half-written lines, todos you never closed.',
183
+ dailyEchoTitle: 'Daily echo',
184
+ dailyEchoHint: 'One quiet line for today—no need to open a full chat.',
185
+ pastYouTitle: 'Who you were',
186
+ pastYouHint: 'Choices and moods you set down at another point on the timeline.',
187
+ intentGrowthTitle: 'Heart & growth',
188
+ intentGrowthHint: 'What you are steering toward, and how it slowly shifts. Stays on device; you can wipe it anytime.',
189
+ comingSoon: 'On its way',
190
+ },
164
191
  discover: {
165
192
  title: 'Discover',
166
193
  useCases: 'Use Cases',
@@ -352,6 +379,8 @@ export const en = {
352
379
  skillBuiltin: 'Built-in',
353
380
  skillUser: 'Custom',
354
381
  addSkill: '+ Add Skill',
382
+ cliInstallHint: 'Install via CLI:',
383
+ skillPathHint: 'Skill files installed at:',
355
384
  deleteSkill: 'Delete',
356
385
  editSkill: 'Edit',
357
386
  saveSkill: 'Save',
@@ -700,7 +729,7 @@ export const en = {
700
729
  c1: {
701
730
  title: 'Inject Your Identity',
702
731
  desc: 'Tell all AI agents who you are — preferences, tech stack, communication style — in one shot.',
703
- prompt: 'Read my MindOS knowledge base and help me write a self-introduction into Profile.',
732
+ prompt: "Here's my resume, read it and organize my info into MindOS.",
704
733
  },
705
734
  c2: {
706
735
  title: 'Save Information',
@@ -803,7 +832,7 @@ export const en = {
803
832
  title: 'Using MindOS with AI Agents',
804
833
  intro: 'Once you connect an agent (Claude Code, Cursor, Windsurf, etc.) via MCP, just talk to it naturally. The agent can read and write your knowledge base directly — no special commands needed. Here are the most common scenarios:',
805
834
  scenarios: [
806
- { emoji: '🪪', title: 'Inject Your Identity', desc: 'Tell all AI agents who you are — preferences, tech stack, communication style — in one shot.', prompt: '"Here is my resume, read it and organize my identity, skills, and preferences into MindOS Profile."' },
835
+ { emoji: '🪪', title: 'Inject Your Identity', desc: 'Tell all AI agents who you are — preferences, tech stack, communication style — in one shot.', prompt: "\"Here's my resume, read it and organize my info into MindOS.\"" },
807
836
  { emoji: '🔄', title: 'Cross-Agent Handoff', desc: 'Brainstorm ideas in GPT, then execute in Claude Code — zero context loss.', prompt: '"Save this conversation to MindOS."\n"Read the plan in MindOS and help me start coding."' },
808
837
  { emoji: '📋', title: 'Experience → SOP', desc: 'Turn hard-won debugging sessions into reusable workflows that prevent future mistakes.', prompt: '"Help me distill this conversation into a reusable workflow in MindOS."' },
809
838
  { emoji: '🚀', title: 'Project Cold Start', desc: 'Spin up a new project in minutes — your profile and SOPs guide the scaffolding automatically.', prompt: '"Help me start a new project following the Startup SOP in MindOS."' },
@@ -84,6 +84,7 @@ export const zh = {
84
84
  settingsTitle: '设置',
85
85
  plugins: '插件',
86
86
  agents: '智能体',
87
+ echo: '回响',
87
88
  discover: '探索',
88
89
  help: '帮助',
89
90
  syncLabel: '同步',
@@ -173,6 +174,17 @@ export const zh = {
173
174
  newSkill: '+ 新建',
174
175
  // Footer
175
176
  advancedConfig: '高级配置 →',
177
+ navOverview: '总览',
178
+ navMcp: 'MCP',
179
+ navSkills: '技能',
180
+ rosterLabel: '当前环境',
181
+ notFoundDetail: '本机未检测到该智能体客户端。请安装后刷新列表。',
182
+ skillsEmptyHint: '请在「MCP 与技能」设置中启用或编辑 Skills。',
183
+ backToList: '返回',
184
+ closeAgentDetail: '关闭',
185
+ agentDetailPanelAria: '智能体连接配置',
186
+ agentDetailTransport: '传输方式',
187
+ agentDetailSnippet: '配置片段',
176
188
  },
177
189
  plugins: {
178
190
  title: '插件',
@@ -186,6 +198,20 @@ export const zh = {
186
198
  noFile: '入口文件不存在',
187
199
  createFile: '创建 {file} 以激活',
188
200
  },
201
+ echo: {
202
+ title: '回响',
203
+ aboutYouTitle: '与你有关',
204
+ aboutYouHint: '路径与链接里,绕回你名下的那几笔。',
205
+ continuedTitle: '未完待续',
206
+ continuedHint: '草稿、写到一半的句子、没收口的待办。',
207
+ dailyEchoTitle: '每日回响',
208
+ dailyEchoHint: '给今天留一行空白;轻到不必为此开一场对话。',
209
+ pastYouTitle: '历史的你',
210
+ pastYouHint: '在另一个时间刻度上,你写下的选择与心情。',
211
+ intentGrowthTitle: '心向生长',
212
+ intentGrowthHint: '你在推的方向,以及它怎样慢慢偏转。只存本机,可随时清空。',
213
+ comingSoon: '随后到来',
214
+ },
189
215
  discover: {
190
216
  title: '探索',
191
217
  useCases: '使用案例',
@@ -377,6 +403,8 @@ export const zh = {
377
403
  skillBuiltin: '内置',
378
404
  skillUser: '自定义',
379
405
  addSkill: '+ 添加 Skill',
406
+ cliInstallHint: '通过命令行安装:',
407
+ skillPathHint: 'Skill 文件安装路径:',
380
408
  deleteSkill: '删除',
381
409
  editSkill: '编辑',
382
410
  saveSkill: '保存',
@@ -725,7 +753,7 @@ export const zh = {
725
753
  c1: {
726
754
  title: '注入身份',
727
755
  desc: '让所有 AI Agent 一次认识你 — 偏好、技术栈、沟通风格。',
728
- prompt: '读一下我的 MindOS 知识库,帮我把自我介绍写进 Profile。',
756
+ prompt: '这是我的简历,读一下,把我的信息整理到 MindOS 里。',
729
757
  },
730
758
  c2: {
731
759
  title: '注入信息',
@@ -828,7 +856,7 @@ export const zh = {
828
856
  title: '在 AI Agent 中使用 MindOS',
829
857
  intro: '通过 MCP 连接 Agent(Claude Code、Cursor、Windsurf 等)后,直接用自然语言对话即可。Agent 能自动读写你的知识库,不需要特殊指令。以下是最常见的使用场景:',
830
858
  scenarios: [
831
- { emoji: '🪪', title: '注入身份', desc: '让所有 AI Agent 一次认识你——偏好、技术栈、沟通风格。', prompt: '"这是我的简历,读一下,帮我把身份、技能和偏好整理到 MindOS Profile 里。"' },
859
+ { emoji: '🪪', title: '注入身份', desc: '让所有 AI Agent 一次认识你——偏好、技术栈、沟通风格。', prompt: '"这是我的简历,读一下,把我的信息整理到 MindOS 里。"' },
832
860
  { emoji: '🔄', title: '跨 Agent 切换', desc: '在 GPT 里聊想法,到 Claude Code 去执行——上下文零丢失。', prompt: '"帮我把刚才的对话整理到 MindOS。"\n"读一下 MindOS 里的方案,帮我开始写代码。"' },
833
861
  { emoji: '📋', title: '经验→SOP', desc: '把踩坑经验沉淀为可复用的工作流,下次 3 分钟搞定。', prompt: '"帮我把这次对话的经验沉淀到 MindOS,形成可复用的工作流。"' },
834
862
  { emoji: '🚀', title: '项目冷启动', desc: '几分钟搭建新项目——Profile 和 SOP 自动引导脚手架。', prompt: '"帮我按 MindOS 里的 Startup SOP 启动一个新项目。"' },
package/app/next-env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/types/routes.d.ts";
3
+ import "./.next/dev/types/routes.d.ts";
4
4
 
5
5
  // NOTE: This file should not be edited
6
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.5.51",
3
+ "version": "0.5.54",
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",