@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 +13 -11
- package/README_zh.md +13 -11
- package/app/next.config.ts +3 -0
- package/bin/cli.js +71 -19
- package/mcp/src/index.ts +2 -1
- package/package.json +13 -3
- package/scripts/setup.js +10 -4
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
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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 Key — the 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`
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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`
|
|
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 客户端:
|
package/app/next.config.ts
CHANGED
|
@@ -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(`
|
|
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
|
-
|
|
447
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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": [
|
|
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": [
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|