@geminilight/mindos 0.6.25 → 0.6.27
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 +19 -3
- package/README_zh.md +19 -3
- package/app/app/api/a2a/discover/route.ts +23 -0
- package/app/components/CreateSpaceModal.tsx +1 -0
- package/app/components/ImportModal.tsx +3 -0
- package/app/components/OnboardingView.tsx +1 -0
- package/app/components/RightAskPanel.tsx +4 -2
- package/app/components/SidebarLayout.tsx +11 -2
- package/app/components/agents/DiscoverAgentModal.tsx +149 -0
- package/app/components/ask/AskContent.tsx +21 -9
- package/app/components/ask/SessionTabBar.tsx +70 -0
- package/app/components/echo/EchoInsightCollapsible.tsx +4 -0
- package/app/components/panels/AgentsPanel.tsx +25 -2
- package/app/components/renderers/workflow/WorkflowRenderer.tsx +5 -0
- package/app/components/settings/AiTab.tsx +1 -0
- package/app/components/settings/KnowledgeTab.tsx +2 -0
- package/app/components/settings/SyncTab.tsx +2 -0
- package/app/components/setup/StepDots.tsx +5 -1
- package/app/data/skills/mindos/SKILL.md +186 -0
- package/app/data/skills/mindos-zh/SKILL.md +185 -0
- package/app/hooks/useA2aRegistry.ts +53 -0
- package/app/hooks/useAskSession.ts +44 -25
- package/app/lib/a2a/a2a-tools.ts +212 -0
- package/app/lib/a2a/client.ts +207 -0
- package/app/lib/a2a/index.ts +8 -0
- package/app/lib/a2a/orchestrator.ts +255 -0
- package/app/lib/a2a/types.ts +54 -0
- package/app/lib/agent/tools.ts +6 -4
- package/app/lib/i18n-en.ts +52 -0
- package/app/lib/i18n-zh.ts +52 -0
- package/app/next-env.d.ts +1 -1
- package/bin/cli.js +180 -171
- package/bin/commands/agent.js +110 -18
- package/bin/commands/api.js +5 -3
- package/bin/commands/ask.js +3 -3
- package/bin/commands/file.js +13 -13
- package/bin/commands/search.js +2 -2
- package/bin/commands/space.js +64 -10
- package/bin/lib/command.js +10 -0
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -54,13 +54,35 @@ import { needsBuild, writeBuildStamp, cleanNextDir, ensureAppDeps } from './lib/
|
|
|
54
54
|
import { isPortInUse, assertPortFree } from './lib/port.js';
|
|
55
55
|
import { savePids, clearPids } from './lib/pid.js';
|
|
56
56
|
import { stopMindos } from './lib/stop.js';
|
|
57
|
-
import { getPlatform, ensureMindosDir, waitForHttp, waitForPortFree, runGatewayCommand } from './lib/gateway.js';
|
|
58
57
|
import { printStartupInfo, getLocalIP } from './lib/startup.js';
|
|
59
58
|
import { spawnMcp } from './lib/mcp-spawn.js';
|
|
60
|
-
import { ensureMcpBundle } from './lib/mcp-build.js';
|
|
61
|
-
import { mcpInstall } from './lib/mcp-install.js';
|
|
62
|
-
import { initSync, startSyncDaemon, stopSyncDaemon, getSyncStatus, manualSync, listConflicts, setSyncEnabled } from './lib/sync.js';
|
|
63
59
|
import { parseArgs } from './lib/command.js';
|
|
60
|
+
import { MCP_AGENTS, detectAgentPresence } from './lib/mcp-agents.js';
|
|
61
|
+
|
|
62
|
+
// Heavy modules — loaded lazily inside command handlers to speed up CLI cold start
|
|
63
|
+
// gateway.js (426 lines), mcp-install.js (335), sync.js (472), mcp-build.js (74)
|
|
64
|
+
const lazy = {
|
|
65
|
+
gateway: () => import('./lib/gateway.js'),
|
|
66
|
+
mcpInstall: () => import('./lib/mcp-install.js'),
|
|
67
|
+
sync: () => import('./lib/sync.js'),
|
|
68
|
+
mcpBuild: () => import('./lib/mcp-build.js'),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Thin wrappers for lazy modules — same API as before, but loaded on first call
|
|
72
|
+
async function getPlatform() { return (await lazy.gateway()).getPlatform(); }
|
|
73
|
+
async function runGatewayCommand(sub) { return (await lazy.gateway()).runGatewayCommand(sub); }
|
|
74
|
+
async function waitForHttp(...a) { return (await lazy.gateway()).waitForHttp(...a); }
|
|
75
|
+
async function waitForPortFree(...a) { return (await lazy.gateway()).waitForPortFree(...a); }
|
|
76
|
+
async function ensureMindosDir() { return (await lazy.gateway()).ensureMindosDir(); }
|
|
77
|
+
async function ensureMcpBundle() { return (await lazy.mcpBuild()).ensureMcpBundle(); }
|
|
78
|
+
async function mcpInstall() { return (await lazy.mcpInstall()).mcpInstall(); }
|
|
79
|
+
async function initSync(...a) { return (await lazy.sync()).initSync(...a); }
|
|
80
|
+
async function startSyncDaemon(...a) { return (await lazy.sync()).startSyncDaemon(...a); }
|
|
81
|
+
async function stopSyncDaemon() { return (await lazy.sync()).stopSyncDaemon(); }
|
|
82
|
+
async function getSyncStatus(...a) { return (await lazy.sync()).getSyncStatus(...a); }
|
|
83
|
+
async function manualSync(...a) { return (await lazy.sync()).manualSync(...a); }
|
|
84
|
+
async function listConflicts(...a) { return (await lazy.sync()).listConflicts(...a); }
|
|
85
|
+
async function setSyncEnabled(...a) { return (await lazy.sync()).setSyncEnabled(...a); }
|
|
64
86
|
|
|
65
87
|
// ── New modular commands ──────────────────────────────────────────────────────
|
|
66
88
|
import * as fileCmd from './commands/file.js';
|
|
@@ -139,24 +161,24 @@ function buildIfNeeded(newRoot) {
|
|
|
139
161
|
|
|
140
162
|
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
141
163
|
|
|
142
|
-
|
|
164
|
+
// ── Unified arg parsing ────────────────────────────────────────────────────
|
|
165
|
+
const { command: cmd, args: cliArgs, flags: cliFlags } = parseArgs(process.argv.slice(2));
|
|
143
166
|
|
|
144
|
-
|
|
145
|
-
// --help / -h is handled at entry section (resolvedCmd = null → help block)
|
|
146
|
-
if (cmd === '--version' || cmd === '-v') {
|
|
167
|
+
if (cliFlags.version || cliFlags.v) {
|
|
147
168
|
const version = JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf-8')).version;
|
|
148
169
|
console.log(`mindos/${version} node/${process.version} ${process.platform}-${process.arch}`);
|
|
149
170
|
process.exit(0);
|
|
150
171
|
}
|
|
151
172
|
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
const
|
|
173
|
+
// Backward compat: derive legacy variables from unified flags
|
|
174
|
+
const isDaemon = cliFlags.daemon === true || (!cmd && isDaemonMode());
|
|
175
|
+
const isVerbose = cliFlags.verbose === true;
|
|
176
|
+
const extra = cliArgs.filter(a => !a.startsWith('-')).join(' ');
|
|
155
177
|
|
|
156
178
|
const commands = {
|
|
157
179
|
// ── onboard ────────────────────────────────────────────────────────────────
|
|
158
180
|
onboard: async () => {
|
|
159
|
-
const daemonFlag =
|
|
181
|
+
const daemonFlag = cliFlags['install-daemon'] ? ' --install-daemon' : '';
|
|
160
182
|
run(`node ${resolve(ROOT, 'scripts/setup.js')}${daemonFlag}`);
|
|
161
183
|
},
|
|
162
184
|
init: async () => commands.onboard(),
|
|
@@ -204,74 +226,48 @@ const commands = {
|
|
|
204
226
|
}
|
|
205
227
|
const mcpPort = config.mcpPort || 8781;
|
|
206
228
|
const localIP = getLocalIP();
|
|
207
|
-
|
|
208
229
|
const localUrl = `http://localhost:${mcpPort}/mcp`;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
},
|
|
241
|
-
}, null, 2));
|
|
242
|
-
|
|
243
|
-
// Cursor
|
|
244
|
-
console.log(`\n${sep}`);
|
|
245
|
-
console.log(`${bold('Cursor')}`);
|
|
246
|
-
console.log(`${sep}`);
|
|
247
|
-
console.log(dim('Quick install:') + ` mindos mcp install cursor -g -y`);
|
|
248
|
-
console.log(dim('\nManual config (~/.cursor/mcp.json):'));
|
|
249
|
-
console.log(JSON.stringify({
|
|
250
|
-
mcpServers: {
|
|
251
|
-
mindos: {
|
|
252
|
-
url: localUrl,
|
|
253
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
}, null, 2));
|
|
257
|
-
|
|
258
|
-
// Remote
|
|
230
|
+
|
|
231
|
+
if (cliFlags.json) {
|
|
232
|
+
const data = { token, mcpPort, localUrl, remoteUrl: localIP ? `http://${localIP}:${mcpPort}/mcp` : null };
|
|
233
|
+
console.log(JSON.stringify(data, null, 2));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const sep = dim('━'.repeat(40));
|
|
238
|
+
const snippet = (url) => JSON.stringify({
|
|
239
|
+
mcpServers: { mindos: { url, headers: { Authorization: `Bearer ${token}` } } },
|
|
240
|
+
}, null, 2);
|
|
241
|
+
|
|
242
|
+
console.log(`\n${bold('Auth token:')} ${cyan(token)}\n`);
|
|
243
|
+
|
|
244
|
+
// Show installed agents, then up to 3 uninstalled popular ones
|
|
245
|
+
const installed = [];
|
|
246
|
+
const others = [];
|
|
247
|
+
for (const [key, agent] of Object.entries(MCP_AGENTS)) {
|
|
248
|
+
(detectAgentPresence(key) ? installed : others).push([key, agent]);
|
|
249
|
+
}
|
|
250
|
+
const toShow = [...installed.slice(0, 8), ...others.slice(0, Math.max(0, 3 - installed.length))];
|
|
251
|
+
|
|
252
|
+
for (const [key, agent] of toShow) {
|
|
253
|
+
console.log(sep);
|
|
254
|
+
console.log(bold(agent.name));
|
|
255
|
+
console.log(dim('Install:') + ` mindos mcp install ${key} -g -y`);
|
|
256
|
+
if (agent.global) console.log(dim(`Config: ${agent.global}`));
|
|
257
|
+
console.log(snippet(localUrl));
|
|
258
|
+
console.log();
|
|
259
|
+
}
|
|
260
|
+
|
|
259
261
|
if (localIP) {
|
|
260
|
-
|
|
261
|
-
console.log(
|
|
262
|
-
console.log(
|
|
263
|
-
console.log(
|
|
264
|
-
console.log(`URL: ${cyan(remoteUrl)}`);
|
|
265
|
-
console.log(JSON.stringify({
|
|
266
|
-
mcpServers: {
|
|
267
|
-
mindos: {
|
|
268
|
-
url: remoteUrl,
|
|
269
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
}, null, 2));
|
|
262
|
+
console.log(sep);
|
|
263
|
+
console.log(bold('Remote (other devices)'));
|
|
264
|
+
console.log(`URL: ${cyan(`http://${localIP}:${mcpPort}/mcp`)}`);
|
|
265
|
+
console.log(snippet(`http://${localIP}:${mcpPort}/mcp`));
|
|
273
266
|
}
|
|
274
267
|
|
|
268
|
+
if (toShow.length < installed.length) {
|
|
269
|
+
console.log(dim(`\n +${installed.length - toShow.length} more agents detected. Run \`mindos agent list\` to see all.`));
|
|
270
|
+
}
|
|
275
271
|
console.log(dim('\nRun `mindos onboard` to regenerate.\n'));
|
|
276
272
|
},
|
|
277
273
|
|
|
@@ -289,8 +285,7 @@ const commands = {
|
|
|
289
285
|
ensureAppDeps();
|
|
290
286
|
const mcp = spawnMcp(isVerbose);
|
|
291
287
|
savePids(process.pid, mcp.pid);
|
|
292
|
-
process.on('exit', () => { stopSyncDaemon(); clearPids(); });
|
|
293
|
-
// Start sync daemon if enabled
|
|
288
|
+
process.on('exit', () => { stopSyncDaemon().catch(() => {}); clearPids(); });
|
|
294
289
|
const devMindRoot = process.env.MIND_ROOT;
|
|
295
290
|
if (devMindRoot) {
|
|
296
291
|
startSyncDaemon(devMindRoot).catch(() => {});
|
|
@@ -311,7 +306,7 @@ const commands = {
|
|
|
311
306
|
} catch {}
|
|
312
307
|
}
|
|
313
308
|
if (isDaemon) {
|
|
314
|
-
const platform = getPlatform();
|
|
309
|
+
const platform = await getPlatform();
|
|
315
310
|
if (!platform) {
|
|
316
311
|
console.warn(yellow('Warning: daemon mode not supported on this platform. Falling back to foreground.'));
|
|
317
312
|
} else {
|
|
@@ -404,7 +399,7 @@ const commands = {
|
|
|
404
399
|
}
|
|
405
400
|
const mcp = spawnMcp(isVerbose);
|
|
406
401
|
savePids(process.pid, mcp.pid);
|
|
407
|
-
process.on('exit', () => { stopSyncDaemon(); clearPids(); });
|
|
402
|
+
process.on('exit', () => { stopSyncDaemon().catch(() => {}); clearPids(); });
|
|
408
403
|
// Start sync daemon if enabled
|
|
409
404
|
const mindRoot = process.env.MIND_ROOT;
|
|
410
405
|
if (mindRoot) {
|
|
@@ -428,12 +423,12 @@ const commands = {
|
|
|
428
423
|
},
|
|
429
424
|
|
|
430
425
|
mcp: async () => {
|
|
431
|
-
const sub =
|
|
432
|
-
const restArgs =
|
|
426
|
+
const sub = cliArgs[0];
|
|
427
|
+
const restArgs = cliArgs;
|
|
433
428
|
const hasInstallFlags = restArgs.some(a => ['-g', '--global', '-y', '--yes'].includes(a));
|
|
434
429
|
if (sub === 'install' || hasInstallFlags) { await mcpInstall(); return; }
|
|
435
430
|
loadConfig();
|
|
436
|
-
ensureMcpBundle();
|
|
431
|
+
await ensureMcpBundle();
|
|
437
432
|
// `mindos mcp` is the entry point for MCP clients (Claude Code, Cursor, etc.)
|
|
438
433
|
// which communicate over stdin/stdout. Default to stdio; HTTP is handled by
|
|
439
434
|
// `mindos start` via spawnMcp(). Callers can still override via env.
|
|
@@ -493,7 +488,7 @@ const commands = {
|
|
|
493
488
|
|
|
494
489
|
// ── gateway ────────────────────────────────────────────────────────────────
|
|
495
490
|
gateway: async () => {
|
|
496
|
-
const sub =
|
|
491
|
+
const sub = cliArgs[0];
|
|
497
492
|
if (!sub) {
|
|
498
493
|
const row = (c, d) => ` ${cyan(c.padEnd(32))}${dim(d)}`;
|
|
499
494
|
console.log(`
|
|
@@ -556,25 +551,28 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
556
551
|
|
|
557
552
|
// ── doctor ─────────────────────────────────────────────────────────────────
|
|
558
553
|
doctor: async () => {
|
|
559
|
-
const
|
|
560
|
-
const
|
|
561
|
-
const
|
|
554
|
+
const jsonMode = cliFlags.json === true;
|
|
555
|
+
const checks = [];
|
|
556
|
+
const ok = (msg, key) => { checks.push({ status: 'ok', key, msg }); if (!jsonMode) console.log(` ${green('✔')} ${msg}`); };
|
|
557
|
+
const err = (msg, key) => { checks.push({ status: 'error', key, msg }); if (!jsonMode) console.log(` ${red('✘')} ${msg}`); };
|
|
558
|
+
const warn= (msg, key) => { checks.push({ status: 'warn', key, msg }); if (!jsonMode) console.log(` ${yellow('!')} ${msg}`); };
|
|
562
559
|
|
|
563
|
-
console.log(`\n${bold('
|
|
560
|
+
if (!jsonMode) console.log(`\n${bold('MindOS Doctor')}\n`);
|
|
564
561
|
let hasError = false;
|
|
565
562
|
|
|
566
563
|
// 1. config file
|
|
567
564
|
if (!existsSync(CONFIG_PATH)) {
|
|
568
|
-
err(`Config not found at ${dim(CONFIG_PATH)}
|
|
569
|
-
console.log(`\n ${dim('Run `mindos onboard` to create it.')}\n`);
|
|
565
|
+
err(`Config not found at ${dim(CONFIG_PATH)}`, 'config');
|
|
566
|
+
if (!jsonMode) { console.log(`\n ${dim('Run `mindos onboard` to create it.')}\n`); }
|
|
567
|
+
if (jsonMode) { console.log(JSON.stringify({ ok: false, checks }, null, 2)); }
|
|
570
568
|
process.exit(1);
|
|
571
569
|
}
|
|
572
570
|
let config;
|
|
573
571
|
try {
|
|
574
572
|
config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
|
|
575
|
-
ok(`Config file found and valid JSON ${dim(CONFIG_PATH)}
|
|
573
|
+
ok(`Config file found and valid JSON ${dim(CONFIG_PATH)}`, 'config');
|
|
576
574
|
} catch {
|
|
577
|
-
err(`Config file exists but failed to parse ${dim(CONFIG_PATH)}
|
|
575
|
+
err(`Config file exists but failed to parse ${dim(CONFIG_PATH)}`, 'config');
|
|
578
576
|
hasError = true;
|
|
579
577
|
}
|
|
580
578
|
|
|
@@ -657,7 +655,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
657
655
|
}
|
|
658
656
|
|
|
659
657
|
// 7. Daemon status
|
|
660
|
-
const platform = getPlatform();
|
|
658
|
+
const platform = await getPlatform();
|
|
661
659
|
if (platform === 'systemd') {
|
|
662
660
|
try {
|
|
663
661
|
execSync('systemctl --user is-active mindos', { stdio: 'pipe' });
|
|
@@ -678,7 +676,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
678
676
|
// 8. Sync status
|
|
679
677
|
if (config?.mindRoot) {
|
|
680
678
|
try {
|
|
681
|
-
const syncStatus = getSyncStatus(config.mindRoot);
|
|
679
|
+
const syncStatus = await getSyncStatus(config.mindRoot);
|
|
682
680
|
if (!syncStatus.enabled) {
|
|
683
681
|
warn(`Cross-device sync is not configured ${dim('(run `mindos sync init` to set up)')}`);
|
|
684
682
|
} else if (syncStatus.lastError) {
|
|
@@ -713,9 +711,14 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
713
711
|
warn('Could not check for updates');
|
|
714
712
|
}
|
|
715
713
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
:
|
|
714
|
+
if (jsonMode) {
|
|
715
|
+
const hasErr = checks.some(c => c.status === 'error');
|
|
716
|
+
console.log(JSON.stringify({ ok: !hasErr, checks }, null, 2));
|
|
717
|
+
} else {
|
|
718
|
+
console.log(hasError
|
|
719
|
+
? `\n${red('Some checks failed.')} Run ${cyan('mindos onboard')} to reconfigure.\n`
|
|
720
|
+
: `\n${green('All checks passed.')}\n`);
|
|
721
|
+
}
|
|
719
722
|
if (hasError) process.exit(1);
|
|
720
723
|
},
|
|
721
724
|
|
|
@@ -763,7 +766,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
763
766
|
return;
|
|
764
767
|
}
|
|
765
768
|
|
|
766
|
-
const updatePlatform = getPlatform();
|
|
769
|
+
const updatePlatform = await getPlatform();
|
|
767
770
|
let daemonRunning = false;
|
|
768
771
|
if (updatePlatform === 'systemd') {
|
|
769
772
|
try { execSync('systemctl --user is-active mindos', { stdio: 'pipe' }); daemonRunning = true; } catch {}
|
|
@@ -977,7 +980,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
977
980
|
try { stopMindos(); } catch { /* may not be running */ }
|
|
978
981
|
|
|
979
982
|
// 2. Remove daemon (skip if platform unsupported)
|
|
980
|
-
if (getPlatform()) {
|
|
983
|
+
if (await getPlatform()) {
|
|
981
984
|
try {
|
|
982
985
|
await runGatewayCommand('uninstall');
|
|
983
986
|
} catch {
|
|
@@ -1040,14 +1043,14 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
1040
1043
|
},
|
|
1041
1044
|
|
|
1042
1045
|
// ── logs ───────────────────────────────────────────────────────────────────
|
|
1043
|
-
logs: () => {
|
|
1044
|
-
ensureMindosDir();
|
|
1046
|
+
logs: async () => {
|
|
1047
|
+
await ensureMindosDir();
|
|
1045
1048
|
if (!existsSync(LOG_PATH)) {
|
|
1046
1049
|
console.log(dim(`No log file yet at ${LOG_PATH}`));
|
|
1047
1050
|
console.log(dim('Logs are created when starting MindOS (mindos start, mindos onboard, or daemon mode).'));
|
|
1048
1051
|
process.exit(0);
|
|
1049
1052
|
}
|
|
1050
|
-
const noFollow =
|
|
1053
|
+
const noFollow = cliFlags['no-follow'] === true;
|
|
1051
1054
|
if (noFollow) {
|
|
1052
1055
|
execSync(`tail -n 100 ${LOG_PATH}`, { stdio: 'inherit' });
|
|
1053
1056
|
} else {
|
|
@@ -1057,7 +1060,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
1057
1060
|
|
|
1058
1061
|
// ── config ─────────────────────────────────────────────────────────────────
|
|
1059
1062
|
config: () => {
|
|
1060
|
-
const sub =
|
|
1063
|
+
const sub = cliArgs[0];
|
|
1061
1064
|
|
|
1062
1065
|
function maskKey(val) {
|
|
1063
1066
|
if (!val) return val;
|
|
@@ -1088,7 +1091,11 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
1088
1091
|
display.authToken = maskKey(display.authToken);
|
|
1089
1092
|
if (display.webPassword)
|
|
1090
1093
|
display.webPassword = maskKey(display.webPassword);
|
|
1091
|
-
|
|
1094
|
+
if (cliFlags.json) {
|
|
1095
|
+
console.log(JSON.stringify(display, null, 2));
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
console.log(`\n${bold('MindOS Config')} ${dim(`v${(() => { try { return JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf-8')).version; } catch { return '?'; } })()}`)} ${dim(CONFIG_PATH)}\n`);
|
|
1092
1099
|
console.log(JSON.stringify(display, null, 2));
|
|
1093
1100
|
console.log();
|
|
1094
1101
|
return;
|
|
@@ -1128,8 +1135,8 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
1128
1135
|
}
|
|
1129
1136
|
|
|
1130
1137
|
if (sub === 'set') {
|
|
1131
|
-
const key =
|
|
1132
|
-
const val =
|
|
1138
|
+
const key = cliArgs[1];
|
|
1139
|
+
const val = cliArgs[2];
|
|
1133
1140
|
if (!key || val === undefined) {
|
|
1134
1141
|
console.error(red('Usage: mindos config set <key> <value>'));
|
|
1135
1142
|
console.error(dim(' Examples:'));
|
|
@@ -1170,7 +1177,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
|
|
|
1170
1177
|
}
|
|
1171
1178
|
|
|
1172
1179
|
if (sub === 'unset') {
|
|
1173
|
-
const key =
|
|
1180
|
+
const key = cliArgs[1];
|
|
1174
1181
|
if (!key) {
|
|
1175
1182
|
console.error(red('Usage: mindos config unset <key>'));
|
|
1176
1183
|
process.exit(1);
|
|
@@ -1218,13 +1225,13 @@ ${bold('Examples:')}
|
|
|
1218
1225
|
|
|
1219
1226
|
// ── sync ──────────────────────────────────────────────────────────────────
|
|
1220
1227
|
sync: async () => {
|
|
1221
|
-
const sub =
|
|
1228
|
+
const sub = cliArgs[0];
|
|
1222
1229
|
loadConfig();
|
|
1223
1230
|
const mindRoot = process.env.MIND_ROOT;
|
|
1224
1231
|
|
|
1225
1232
|
if (sub === 'init') {
|
|
1226
1233
|
// Parse --non-interactive --remote <url> --branch <branch> --token <token>
|
|
1227
|
-
const args =
|
|
1234
|
+
const args = cliArgs.slice(1);
|
|
1228
1235
|
const flagIdx = (flag) => args.indexOf(flag);
|
|
1229
1236
|
const flagVal = (flag) => { const i = flagIdx(flag); return i >= 0 && i + 1 < args.length ? args[i + 1] : ''; };
|
|
1230
1237
|
const nonInteractive = args.includes('--non-interactive');
|
|
@@ -1245,7 +1252,7 @@ ${bold('Examples:')}
|
|
|
1245
1252
|
if (sub === 'now') {
|
|
1246
1253
|
try {
|
|
1247
1254
|
console.log(dim('Pulling...'));
|
|
1248
|
-
manualSync(mindRoot);
|
|
1255
|
+
await manualSync(mindRoot);
|
|
1249
1256
|
console.log(green('✔ Sync complete'));
|
|
1250
1257
|
} catch (err) {
|
|
1251
1258
|
console.error(red(err.message));
|
|
@@ -1255,18 +1262,18 @@ ${bold('Examples:')}
|
|
|
1255
1262
|
}
|
|
1256
1263
|
|
|
1257
1264
|
if (sub === 'conflicts') {
|
|
1258
|
-
listConflicts(mindRoot);
|
|
1265
|
+
await listConflicts(mindRoot);
|
|
1259
1266
|
return;
|
|
1260
1267
|
}
|
|
1261
1268
|
|
|
1262
1269
|
if (sub === 'on') {
|
|
1263
|
-
setSyncEnabled(true);
|
|
1270
|
+
await setSyncEnabled(true);
|
|
1264
1271
|
return;
|
|
1265
1272
|
}
|
|
1266
1273
|
|
|
1267
1274
|
if (sub === 'off') {
|
|
1268
|
-
setSyncEnabled(false);
|
|
1269
|
-
stopSyncDaemon();
|
|
1275
|
+
await setSyncEnabled(false);
|
|
1276
|
+
await stopSyncDaemon();
|
|
1270
1277
|
return;
|
|
1271
1278
|
}
|
|
1272
1279
|
|
|
@@ -1281,9 +1288,15 @@ ${bold('Examples:')}
|
|
|
1281
1288
|
}
|
|
1282
1289
|
|
|
1283
1290
|
// default: sync status
|
|
1284
|
-
const status = getSyncStatus(mindRoot);
|
|
1291
|
+
const status = await getSyncStatus(mindRoot);
|
|
1292
|
+
|
|
1293
|
+
if (cliFlags.json) {
|
|
1294
|
+
console.log(JSON.stringify(status, null, 2));
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1285
1298
|
if (!status.enabled) {
|
|
1286
|
-
console.log(`\n${bold('
|
|
1299
|
+
console.log(`\n${bold('Sync Status')}`);
|
|
1287
1300
|
console.log(dim(' Not configured. Run `mindos sync init` to set up.\n'));
|
|
1288
1301
|
return;
|
|
1289
1302
|
}
|
|
@@ -1296,7 +1309,7 @@ ${bold('Examples:')}
|
|
|
1296
1309
|
})()
|
|
1297
1310
|
: 'never';
|
|
1298
1311
|
|
|
1299
|
-
console.log(`\n${bold('
|
|
1312
|
+
console.log(`\n${bold('Sync Status')}`);
|
|
1300
1313
|
console.log(` ${dim('Provider:')} ${cyan(`${status.provider} (${status.remote})`)}`);
|
|
1301
1314
|
console.log(` ${dim('Branch:')} ${cyan(status.branch)}`);
|
|
1302
1315
|
console.log(` ${dim('Last sync:')} ${ago}`);
|
|
@@ -1310,68 +1323,64 @@ ${bold('Examples:')}
|
|
|
1310
1323
|
},
|
|
1311
1324
|
|
|
1312
1325
|
// ── New modular commands (knowledge operations) ──────────────────────────
|
|
1313
|
-
file: async () =>
|
|
1314
|
-
space: async () =>
|
|
1315
|
-
ask: async () =>
|
|
1316
|
-
status: async () =>
|
|
1317
|
-
api: async () =>
|
|
1318
|
-
agent: async () =>
|
|
1319
|
-
search: async () =>
|
|
1326
|
+
file: async () => fileCmd.run(cliArgs, cliFlags),
|
|
1327
|
+
space: async () => spaceCmd.run(cliArgs, cliFlags),
|
|
1328
|
+
ask: async () => askCmd.run(cliArgs, cliFlags),
|
|
1329
|
+
status: async () => statusCmd.run(cliArgs, cliFlags),
|
|
1330
|
+
api: async () => apiCmd.run(cliArgs, cliFlags),
|
|
1331
|
+
agent: async () => agentCmd.run(cliArgs, cliFlags),
|
|
1332
|
+
search: async () => searchCmd.run(cliArgs, cliFlags),
|
|
1320
1333
|
};
|
|
1321
1334
|
|
|
1322
1335
|
// ── Entry ─────────────────────────────────────────────────────────────────────
|
|
1323
1336
|
|
|
1324
|
-
const resolvedCmd = (
|
|
1337
|
+
const resolvedCmd = (cliFlags.help || cliFlags.h) ? null : (cmd || (existsSync(CONFIG_PATH) ? getStartMode() : null));
|
|
1325
1338
|
|
|
1326
1339
|
if (!resolvedCmd || !commands[resolvedCmd]) {
|
|
1327
1340
|
const pkgVersion = (() => { try { return JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf-8')).version; } catch { return '?'; } })();
|
|
1328
1341
|
const row = (c, d) => ` ${cyan(c.padEnd(36))}${dim(d)}`;
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
${
|
|
1368
|
-
|
|
1369
|
-
${bold('Global Flags:')}
|
|
1370
|
-
|
|
1371
|
-
${row('--help, -h', 'Show help')}
|
|
1372
|
-
${row('--version, -v', 'Show version')}
|
|
1373
|
-
`);
|
|
1374
|
-
const isHelp = (cmd === '--help' || cmd === '-h');
|
|
1342
|
+
|
|
1343
|
+
// Command registry — help is generated entirely from this array.
|
|
1344
|
+
// Modular commands provide meta via their exports; inline commands define meta here.
|
|
1345
|
+
const helpRegistry = [
|
|
1346
|
+
{ group: 'Core', usage: 'mindos onboard', summary: 'Interactive setup (aliases: init, setup)' },
|
|
1347
|
+
{ group: 'Core', usage: 'mindos start', summary: 'Start app + MCP server (production)' },
|
|
1348
|
+
{ group: 'Core', usage: 'mindos start --daemon', summary: 'Start as background OS service' },
|
|
1349
|
+
{ group: 'Core', usage: 'mindos dev', summary: 'Start in dev mode' },
|
|
1350
|
+
{ group: 'Core', usage: 'mindos stop', summary: 'Stop running processes' },
|
|
1351
|
+
{ group: 'Core', usage: 'mindos restart', summary: 'Stop then start again' },
|
|
1352
|
+
{ group: 'Core', usage: 'mindos build', summary: 'Build for production' },
|
|
1353
|
+
statusCmd.meta,
|
|
1354
|
+
{ group: 'Core', usage: 'mindos open', summary: 'Open Web UI in browser' },
|
|
1355
|
+
fileCmd.meta, spaceCmd.meta, searchCmd.meta, askCmd.meta, agentCmd.meta, apiCmd.meta,
|
|
1356
|
+
{ group: 'MCP', usage: 'mindos mcp', summary: 'Start MCP server only' },
|
|
1357
|
+
{ group: 'MCP', usage: 'mindos mcp install [agent]', summary: 'Install MCP config into Agent' },
|
|
1358
|
+
{ group: 'MCP', usage: 'mindos token', summary: 'Show auth token and MCP config' },
|
|
1359
|
+
{ group: 'Sync', usage: 'mindos sync', summary: 'Show sync status (init/now/conflicts/on/off)' },
|
|
1360
|
+
{ group: 'Gateway', usage: 'mindos gateway <sub>', summary: 'Manage service (install/start/stop/status/logs)' },
|
|
1361
|
+
{ group: 'Config', usage: 'mindos config <sub>', summary: 'View/update config (show/set/unset/validate)' },
|
|
1362
|
+
{ group: 'Config', usage: 'mindos doctor', summary: 'Health check' },
|
|
1363
|
+
{ group: 'Config', usage: 'mindos update', summary: 'Update to latest version' },
|
|
1364
|
+
{ group: 'Config', usage: 'mindos uninstall', summary: 'Fully uninstall MindOS' },
|
|
1365
|
+
{ group: 'Config', usage: 'mindos logs', summary: 'Tail service logs' },
|
|
1366
|
+
];
|
|
1367
|
+
|
|
1368
|
+
const groupLabels = [
|
|
1369
|
+
['Core', 'Core'], ['Knowledge', 'Knowledge'], ['MCP', 'MCP'],
|
|
1370
|
+
['Sync', 'Sync'], ['Gateway', 'Gateway (Background Service)'], ['Config', 'Config & Diagnostics'],
|
|
1371
|
+
];
|
|
1372
|
+
const groups = {};
|
|
1373
|
+
for (const e of helpRegistry) {
|
|
1374
|
+
const g = e.group || 'Other';
|
|
1375
|
+
if (!groups[g]) groups[g] = [];
|
|
1376
|
+
groups[g].push(row(e.usage || `mindos ${e.name}`, e.summary));
|
|
1377
|
+
}
|
|
1378
|
+
const sections = groupLabels
|
|
1379
|
+
.filter(([k]) => groups[k])
|
|
1380
|
+
.map(([k, label]) => `${bold(`${label}:`)}\n${groups[k].join('\n')}`);
|
|
1381
|
+
|
|
1382
|
+
console.log(`\n${bold('MindOS CLI')} ${dim(`v${pkgVersion}`)}\n\n${sections.join('\n\n')}\n\n${bold('Global Flags:')}\n${row('--json', 'Output in JSON (for AI agents)')}\n${row('--help, -h', 'Show help')}\n${row('--version, -v', 'Show version')}\n`);
|
|
1383
|
+
const isHelp = cliFlags.help || cliFlags.h;
|
|
1375
1384
|
process.exit((cmd && !isHelp) ? 1 : 0);
|
|
1376
1385
|
}
|
|
1377
1386
|
|