@geminilight/mindos 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -122,9 +122,11 @@ npm link # registers the `mindos` command globally
122
122
  ### 2. Interactive Setup
123
123
 
124
124
  ```bash
125
- mindos onboard --install-daemon # setup + install & start as background OS service
125
+ mindos onboard --install-daemon
126
126
  ```
127
127
 
128
+ > `--install-daemon`: after setup, automatically installs and starts MindOS as a background OS service (survives terminal close, auto-restarts on crash).
129
+
128
130
  The setup wizard will guide you through:
129
131
  1. Knowledge base path → default `~/.mindos/my-mind`
130
132
  2. Choose template language (en / zh)
@@ -132,14 +134,13 @@ The setup wizard will guide you through:
132
134
  4. Configure AI Provider (Anthropic / OpenAI) + API Key — or choose **skip** to configure later via `mindos config set`
133
135
  5. Config saved to `~/.mindos/config.json` automatically
134
136
 
135
- > [!TIP]
136
- > **For Agents:** Before running setup, if the user has not provided LLM configuration, ask them:
137
- > 1. AI Provider`anthropic` or `openai` (compatible)?
138
- > 2. API Keythe key for the chosen provider
139
- > 3. Custom Base URL? only needed for proxies or OpenAI-compatible endpoints; skip if using official API
140
- > 4. Model ID or use the default
141
- >
142
- > Or skip the wizard and edit `~/.mindos/config.json` manually (see Config Reference below).
137
+ <!-- For Agents: Before running setup, if the user has not provided LLM configuration, ask them:
138
+ 1. AI Provider `anthropic` or `openai` (compatible)?
139
+ 2. API Keythe key for the chosen provider
140
+ 3. Custom Base URL? only needed for proxies or OpenAI-compatible endpoints; skip if using official API
141
+ 4. Model ID — or use the default
142
+ Or skip the wizard and edit `~/.mindos/config.json` manually (see Config Reference below).
143
+ -->
143
144
 
144
145
  <details>
145
146
  <summary>Config Reference (~/.mindos/config.json)</summary>
@@ -191,7 +192,7 @@ mindos start # start app + MCP server (production, auto-rebuilds when a new v
191
192
  On startup, MindOS prints your Web UI URL, MCP config snippet, and auth token — ready to copy into your Agent.
192
193
 
193
194
  > [!TIP]
194
- > **Upgrading?** Run `mindos update` it installs the latest version and triggers a rebuild automatically on next start.
195
+ > **Upgrading?** Run `mindos update` to install the latest version.
195
196
 
196
197
  > [!TIP]
197
198
  > If the port is already in use, set a different port during `mindos onboard` or update `~/.mindos/config.json`:
@@ -213,8 +214,9 @@ On startup, MindOS prints your Web UI URL, MCP config snippet, and auth token
213
214
 
214
215
  #### 5.1 Configure MindOS MCP
215
216
 
217
+ <!-- For Agents: Register MindOS MCP as global (user-level) config by default, so all projects share the same knowledge base. -->
218
+
216
219
  > [!TIP]
217
- > **For Agents:** Register MindOS MCP as global (user-level) config by default, so all projects share the same knowledge base.
218
220
  > Each Agent stores MCP config in a different file — see the **MCP Config Path** column in the [Supported Agents](#-supported-agents) table below for exact paths.
219
221
 
220
222
  Register the MindOS MCP Server in your Agent client:
package/README_zh.md CHANGED
@@ -122,9 +122,11 @@ npm link # 将 mindos 命令注册为全局命令
122
122
  ### 2. 交互式配置
123
123
 
124
124
  ```bash
125
- mindos onboard --install-daemon # 初始化 + 安装并启动后台服务
125
+ mindos onboard --install-daemon
126
126
  ```
127
127
 
128
+ > `--install-daemon`:配置完成后,自动将 MindOS 安装为后台 OS 服务(关闭终端仍运行,崩溃自动重启)。
129
+
128
130
  配置向导将引导你完成:
129
131
  1. 知识库路径 → 默认 `~/.mindos/my-mind`
130
132
  2. 选择模板语言(en / zh / empty)
@@ -132,14 +134,13 @@ mindos onboard --install-daemon # 初始化 + 安装并启动后台服务
132
134
  4. 配置 AI Provider(Anthropic / OpenAI)+ API Key — 或选择 **skip**,稍后通过 `mindos config set` 补填
133
135
  5. 配置自动保存到 `~/.mindos/config.json`
134
136
 
135
- > [!TIP]
136
- > **For Agents:** 运行 onboard 前,如果用户未提供 LLM 配置,请询问:
137
- > 1. AI Provider`anthropic` 还是 `openai`(兼容)?
138
- > 2. API Key 对应 Provider 的密钥
139
- > 3. 自定义 Base URL?— 仅代理或 OpenAI 兼容端点需要;使用官方 API 则跳过
140
- > 4. Model ID — 或使用默认值
141
- >
142
- > 或跳过向导,手动编辑 `~/.mindos/config.json`(参考下方配置参考)。
137
+ <!-- For Agents: 运行 onboard 前,如果用户未提供 LLM 配置,请询问:
138
+ 1. AI Provider `anthropic` 还是 `openai`(兼容)?
139
+ 2. API Key对应 Provider 的密钥
140
+ 3. 自定义 Base URL?— 仅代理或 OpenAI 兼容端点需要;使用官方 API 则跳过
141
+ 4. Model ID 或使用默认值
142
+ 或跳过向导,手动编辑 `~/.mindos/config.json`(参考下方配置参考)。
143
+ -->
143
144
 
144
145
  <details>
145
146
  <summary>配置参考(~/.mindos/config.json)</summary>
@@ -191,7 +192,7 @@ mindos start # 启动 app + MCP 服务(生产模式,检测到新版本时
191
192
  启动后,MindOS 会自动打印 Web UI 地址、MCP 配置片段和 Auth token,直接复制到你的 Agent 即可。
192
193
 
193
194
  > [!TIP]
194
- > **升级?** 运行 `mindos update` — 自动安装最新版本,下次 start 时触发重建。
195
+ > **升级?** 运行 `mindos update` 安装最新版本。
195
196
 
196
197
  > [!TIP]
197
198
  > 如果端口被占用,在 `mindos onboard` 时指定其他端口,或更新 `~/.mindos/config.json`,也可通过环境变量临时覆盖:
@@ -213,8 +214,9 @@ mindos start # 启动 app + MCP 服务(生产模式,检测到新版本时
213
214
 
214
215
  #### 5.1 配置 MindOS MCP
215
216
 
217
+ <!-- For Agents: MindOS MCP 默认注册为全局(user-level)配置,使所有项目共享同一知识库。-->
218
+
216
219
  > [!TIP]
217
- > **For Agents:** MindOS MCP 默认注册为全局(user-level)配置,使所有项目共享同一知识库。
218
220
  > 每个 Agent 的 MCP 配置文件路径不同——详见下方 [支持的 Agent](#-支持的-agent) 表格中的 **MCP 配置文件路径** 列。
219
221
 
220
222
  将 MindOS MCP Server 注册到你的 Agent 客户端:
@@ -5,6 +5,9 @@ const nextConfig: NextConfig = {
5
5
  transpilePackages: ['github-slugger'],
6
6
  serverExternalPackages: ['pdfjs-dist', 'pdf-parse'],
7
7
  outputFileTracingRoot: path.join(__dirname),
8
+ turbopack: {
9
+ root: path.join(__dirname),
10
+ },
8
11
  };
9
12
 
10
13
  export default nextConfig;
package/bin/cli.js CHANGED
@@ -119,6 +119,26 @@ function writeBuildStamp() {
119
119
  writeFileSync(BUILD_STAMP, version, 'utf-8');
120
120
  }
121
121
 
122
+ function clearBuildLock() {
123
+ const lockFile = resolve(ROOT, 'app', '.next', 'lock');
124
+ if (existsSync(lockFile)) {
125
+ rmSync(lockFile, { force: true });
126
+ }
127
+ }
128
+
129
+ function ensureAppDeps() {
130
+ // When installed as a global npm package, app/node_modules may not exist.
131
+ // next (and other deps) must be resolvable from app/ for Turbopack to work.
132
+ const appNext = resolve(ROOT, 'app', 'node_modules', 'next', 'package.json');
133
+ if (!existsSync(appNext)) {
134
+ console.log(yellow('Installing app dependencies (first run)...\n'));
135
+ // --no-workspaces: prevent npm from hoisting deps to monorepo root.
136
+ // When globally installed, deps must live in app/node_modules/ so that
137
+ // Turbopack can resolve next/package.json from the app/ project directory.
138
+ run('npm install --prefer-offline --no-workspaces', resolve(ROOT, 'app'));
139
+ }
140
+ }
141
+
122
142
  // ── Port check ────────────────────────────────────────────────────────────────
123
143
 
124
144
  function isPortInUse(port) {
@@ -230,8 +250,20 @@ const systemd = {
230
250
  console.log(green('✔ Service installed and enabled'));
231
251
  },
232
252
 
233
- start() {
253
+ async start() {
234
254
  execSync('systemctl --user start mindos', { stdio: 'inherit' });
255
+ // Wait up to 10s for the service to become active
256
+ const ok = await waitForService(() => {
257
+ try {
258
+ const out = execSync('systemctl --user is-active mindos', { encoding: 'utf-8' }).trim();
259
+ return out === 'active';
260
+ } catch { return false; }
261
+ });
262
+ if (!ok) {
263
+ console.error(red('\n✘ Service failed to start. Last log output:'));
264
+ try { execSync(`journalctl --user -u mindos -n 30 --no-pager`, { stdio: 'inherit' }); } catch {}
265
+ process.exit(1);
266
+ }
235
267
  console.log(green('✔ Service started'));
236
268
  },
237
269
 
@@ -307,8 +339,20 @@ const launchd = {
307
339
  console.log(green('✔ Service installed'));
308
340
  },
309
341
 
310
- start() {
342
+ async start() {
311
343
  execSync(`launchctl kickstart -k gui/${launchctlUid()}/${LAUNCHD_LABEL}`, { stdio: 'inherit' });
344
+ // Wait up to 10s for the service to become active
345
+ const ok = await waitForService(() => {
346
+ try {
347
+ const out = execSync(`launchctl print gui/${launchctlUid()}/${LAUNCHD_LABEL}`, { encoding: 'utf-8' });
348
+ return out.includes('state = running');
349
+ } catch { return false; }
350
+ });
351
+ if (!ok) {
352
+ console.error(red('\n✘ Service failed to start. Last log output:'));
353
+ try { execSync(`tail -n 30 ${LOG_PATH}`, { stdio: 'inherit' }); } catch {}
354
+ process.exit(1);
355
+ }
312
356
  console.log(green('✔ Service started'));
313
357
  },
314
358
 
@@ -345,6 +389,14 @@ const launchd = {
345
389
 
346
390
  // ── gateway dispatcher ────────────────────────────────────────────────────────
347
391
 
392
+ async function waitForService(check, { retries = 10, intervalMs = 1000 } = {}) {
393
+ for (let i = 0; i < retries; i++) {
394
+ if (check()) return true;
395
+ await new Promise(r => setTimeout(r, intervalMs));
396
+ }
397
+ return check();
398
+ }
399
+
348
400
  async function runGatewayCommand(sub) {
349
401
  const platform = getPlatform();
350
402
  if (!platform) {
@@ -389,7 +441,11 @@ function printStartupInfo(webPort, mcpPort) {
389
441
  console.log(`\n${'─'.repeat(53)}`);
390
442
  console.log(`${bold('🧠 MindOS is starting')}\n`);
391
443
  console.log(` ${green('●')} Web UI ${cyan(`http://localhost:${webPort}`)}`);
392
- console.log(` ${green('●')} MCP ${cyan(`http://localhost:${mcpPort}/mcp`)}\n`);
444
+ if (localIP) console.log(` ${cyan(`http://${localIP}:${webPort}`)}`);
445
+ console.log(` ${green('●')} MCP ${cyan(`http://localhost:${mcpPort}/mcp`)}`);
446
+ if (localIP) console.log(` ${cyan(`http://${localIP}:${mcpPort}/mcp`)}`);
447
+ if (localIP) console.log(dim(`\n 💡 Running on a remote server? Open the Network URL (${localIP}) in your browser,\n or use SSH port forwarding: ssh -L ${webPort}:localhost:${webPort} user@${localIP}`));
448
+ console.log();
393
449
  console.log(bold('Configure MCP in your Agent:'));
394
450
  console.log(dim(' Local (same machine):'));
395
451
  console.log(block('localhost'));
@@ -443,21 +499,8 @@ const extra = process.argv.slice(3).filter(a => a !== '--daemon' && a !== '-
443
499
  const commands = {
444
500
  // ── onboard ────────────────────────────────────────────────────────────────
445
501
  onboard: async () => {
446
- run(`node ${resolve(ROOT, 'scripts/setup.js')}`);
447
- if (process.argv.includes('--install-daemon')) {
448
- const platform = getPlatform();
449
- if (!platform) {
450
- console.warn(yellow('Warning: daemon mode not supported on this platform. Skipping service install.'));
451
- return;
452
- }
453
- console.log(cyan(`\nInstalling MindOS as a background service (${platform})...`));
454
- await runGatewayCommand('install');
455
- await runGatewayCommand('start');
456
- console.log(`\n${green('✔ MindOS is running as a background service')}`);
457
- console.log(dim(' View logs: mindos logs'));
458
- console.log(dim(' Stop: mindos gateway stop'));
459
- console.log(dim(' Uninstall: mindos gateway uninstall\n'));
460
- }
502
+ const daemonFlag = process.argv.includes('--install-daemon') ? ' --install-daemon' : '';
503
+ run(`node ${resolve(ROOT, 'scripts/setup.js')}${daemonFlag}`);
461
504
  },
462
505
  init: () => run(`node ${resolve(ROOT, 'scripts/setup.js')}`),
463
506
  setup: () => run(`node ${resolve(ROOT, 'scripts/setup.js')}`),
@@ -487,6 +530,7 @@ const commands = {
487
530
  const mcpPort = process.env.MINDOS_MCP_PORT || '8787';
488
531
  await assertPortFree(Number(webPort), 'web');
489
532
  await assertPortFree(Number(mcpPort), 'mcp');
533
+ ensureAppDeps();
490
534
  const mcp = spawnMcp(isVerbose);
491
535
  savePids(process.pid, mcp.pid);
492
536
  process.on('exit', clearPids);
@@ -501,10 +545,14 @@ const commands = {
501
545
  if (!platform) {
502
546
  console.warn(yellow('Warning: daemon mode not supported on this platform. Falling back to foreground.'));
503
547
  } else {
548
+ loadConfig();
549
+ const webPort = process.env.MINDOS_WEB_PORT || '3000';
550
+ const mcpPort = process.env.MINDOS_MCP_PORT || '8787';
504
551
  console.log(cyan(`Installing MindOS as a background service (${platform})...`));
505
552
  await runGatewayCommand('install');
506
553
  await runGatewayCommand('start');
507
- console.log(`\n${green('✔ MindOS is running as a background service')}`);
554
+ printStartupInfo(webPort, mcpPort);
555
+ console.log(`${green('✔ MindOS is running as a background service')}`);
508
556
  console.log(dim(' View logs: mindos logs'));
509
557
  console.log(dim(' Stop: mindos gateway stop'));
510
558
  console.log(dim(' Uninstall: mindos gateway uninstall\n'));
@@ -516,8 +564,10 @@ const commands = {
516
564
  const mcpPort = process.env.MINDOS_MCP_PORT || '8787';
517
565
  await assertPortFree(Number(webPort), 'web');
518
566
  await assertPortFree(Number(mcpPort), 'mcp');
567
+ ensureAppDeps();
519
568
  if (needsBuild()) {
520
569
  console.log(yellow('Building MindOS (first run or new version detected)...\n'));
570
+ clearBuildLock();
521
571
  run('npx next build', resolve(ROOT, 'app'));
522
572
  writeBuildStamp();
523
573
  }
@@ -530,6 +580,8 @@ const commands = {
530
580
 
531
581
  // ── build ──────────────────────────────────────────────────────────────────
532
582
  build: () => {
583
+ ensureAppDeps();
584
+ clearBuildLock();
533
585
  run(`npx next build ${extra}`, resolve(ROOT, 'app'));
534
586
  writeBuildStamp();
535
587
  },
package/mcp/src/index.ts CHANGED
@@ -470,7 +470,8 @@ async function main() {
470
470
  }
471
471
 
472
472
  expressApp.all(MCP_ENDPOINT, async (req, res) => {
473
- await transport.handleRequest(req, res);
473
+ // Pass pre-parsed body: express.json() already parsed it, SDK >= 1.7 expects it as 3rd arg
474
+ await transport.handleRequest(req, res, req.body);
474
475
  });
475
476
 
476
477
  await server.connect(transport);
package/package.json CHANGED
@@ -1,8 +1,15 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "MindOS — Human-Agent Collaborative Mind System. Local-first knowledge base that syncs your mind to all AI Agents via MCP.",
5
- "keywords": ["mindos", "mcp", "knowledge-base", "ai-agent", "local-first", "second-brain"],
5
+ "keywords": [
6
+ "mindos",
7
+ "mcp",
8
+ "knowledge-base",
9
+ "ai-agent",
10
+ "local-first",
11
+ "second-brain"
12
+ ],
6
13
  "type": "module",
7
14
  "license": "MIT",
8
15
  "author": "GeminiLight",
@@ -13,7 +20,10 @@
13
20
  "bin": {
14
21
  "mindos": "bin/cli.js"
15
22
  },
16
- "workspaces": ["app", "mcp"],
23
+ "workspaces": [
24
+ "app",
25
+ "mcp"
26
+ ],
17
27
  "files": [
18
28
  "app/",
19
29
  "mcp/",
package/scripts/setup.js CHANGED
@@ -642,7 +642,8 @@ async function main() {
642
642
  writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n');
643
643
  console.log(`\n${c.green(t('cfgSaved'))}: ${c.dim(CONFIG_PATH)}`);
644
644
 
645
- finish(mindDir, config.startMode, config.mcpPort, config.authToken);
645
+ const installDaemon = process.argv.includes('--install-daemon');
646
+ finish(mindDir, config.startMode, config.mcpPort, config.authToken, installDaemon);
646
647
  }
647
648
 
648
649
  function getLocalIP() {
@@ -654,8 +655,8 @@ function getLocalIP() {
654
655
  return null;
655
656
  }
656
657
 
657
- async function finish(mindDir, startMode = 'start', mcpPort = 8787, authToken = '') {
658
- const startCmd = startMode === 'dev' ? 'mindos dev' : 'mindos start';
658
+ async function finish(mindDir, startMode = 'start', mcpPort = 8787, authToken = '', installDaemon = false) {
659
+ const startCmd = installDaemon ? 'mindos start --daemon' : (startMode === 'dev' ? 'mindos dev' : 'mindos start');
659
660
  const lines = T.nextSteps[uiLang](startCmd);
660
661
  console.log('');
661
662
  lines.forEach((l) => console.log(l));
@@ -664,7 +665,12 @@ async function finish(mindDir, startMode = 'start', mcpPort = 8787, authToken =
664
665
  if (doStart) {
665
666
  const { execSync } = await import('node:child_process');
666
667
  const cliPath = resolve(__dirname, '../bin/cli.js');
667
- execSync(`node "${cliPath}" ${startMode}`, { stdio: 'inherit' });
668
+ if (installDaemon) {
669
+ // Install and start as background service — returns immediately
670
+ execSync(`node "${cliPath}" start --daemon`, { stdio: 'inherit' });
671
+ } else {
672
+ execSync(`node "${cliPath}" ${startMode}`, { stdio: 'inherit' });
673
+ }
668
674
  }
669
675
  }
670
676