@geminilight/mindos 0.6.25 → 0.6.28

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.
Files changed (45) hide show
  1. package/README.md +19 -3
  2. package/README_zh.md +19 -3
  3. package/app/app/api/a2a/discover/route.ts +23 -0
  4. package/app/components/CreateSpaceModal.tsx +1 -0
  5. package/app/components/ImportModal.tsx +3 -0
  6. package/app/components/OnboardingView.tsx +1 -0
  7. package/app/components/RightAskPanel.tsx +4 -2
  8. package/app/components/SidebarLayout.tsx +11 -2
  9. package/app/components/agents/AgentDetailContent.tsx +48 -1
  10. package/app/components/agents/AgentsContentPage.tsx +3 -0
  11. package/app/components/agents/AgentsOverviewSection.tsx +11 -0
  12. package/app/components/agents/DiscoverAgentModal.tsx +149 -0
  13. package/app/components/ask/AskContent.tsx +29 -9
  14. package/app/components/ask/SessionTabBar.tsx +70 -0
  15. package/app/components/echo/EchoInsightCollapsible.tsx +4 -0
  16. package/app/components/help/HelpContent.tsx +65 -9
  17. package/app/components/panels/AgentsPanel.tsx +25 -2
  18. package/app/components/panels/AgentsPanelAgentListRow.tsx +10 -1
  19. package/app/components/renderers/workflow/WorkflowRenderer.tsx +5 -0
  20. package/app/components/settings/AiTab.tsx +1 -0
  21. package/app/components/settings/KnowledgeTab.tsx +2 -0
  22. package/app/components/settings/SyncTab.tsx +2 -0
  23. package/app/components/setup/StepDots.tsx +5 -1
  24. package/app/data/skills/mindos/SKILL.md +186 -0
  25. package/app/data/skills/mindos-zh/SKILL.md +185 -0
  26. package/app/hooks/useA2aRegistry.ts +53 -0
  27. package/app/hooks/useAskSession.ts +44 -25
  28. package/app/lib/a2a/a2a-tools.ts +212 -0
  29. package/app/lib/a2a/client.ts +207 -0
  30. package/app/lib/a2a/index.ts +8 -0
  31. package/app/lib/a2a/orchestrator.ts +255 -0
  32. package/app/lib/a2a/types.ts +54 -0
  33. package/app/lib/agent/tools.ts +6 -4
  34. package/app/lib/i18n-en.ts +52 -0
  35. package/app/lib/i18n-zh.ts +52 -0
  36. package/app/next-env.d.ts +1 -1
  37. package/bin/cli.js +180 -171
  38. package/bin/commands/agent.js +110 -18
  39. package/bin/commands/api.js +5 -3
  40. package/bin/commands/ask.js +3 -3
  41. package/bin/commands/file.js +13 -13
  42. package/bin/commands/search.js +2 -2
  43. package/bin/commands/space.js +64 -10
  44. package/bin/lib/command.js +10 -0
  45. package/package.json +1 -1
@@ -1,18 +1,110 @@
1
- import{bold,dim,cyan,green,red,yellow}from"../lib/colors.js";import{MCP_AGENTS,detectAgentPresence}from"../lib/mcp-agents.js";import{existsSync,readFileSync}from"node:fs";import{resolve}from"node:path";import{homedir}from"node:os";import{output,isJsonMode}from"../lib/command.js";function expandHome(p){return p.startsWith("~/")?resolve(homedir(),p.slice(2)):p}export const meta={name:"agent",group:"Knowledge",summary:"AI Agent management (list/info)",usage:"mindos agent <subcommand>"};export async function run(a,f){const s=a[0];if(!s||f.help||f.h){console.log(bold("mindos agent")+" — AI Agent management
2
-
3
- Subcommands:
4
- list List detected AI agents
5
- info Show agent details
6
-
7
- Agent Keys: "+Object.keys(MCP_AGENTS).join(", "));return}if(s==="list"||s==="ls")return agentList(f);if(s==="info")return agentInfo(a[1],f);console.error(red("Unknown: "+s));process.exit(1)}function hasMindosConfig(agent){const paths=[agent.global,agent.project].filter(Boolean).map(expandHome);for(const p of paths){try{if(!existsSync(p))continue;const raw=readFileSync(p,"utf-8").replace(///.*$/gm,"").replace(//*[\s\S]*?*//g,"");const data=JSON.parse(raw);const servers=data[agent.key]||{};if(Object.keys(servers).some(k=>k.toLowerCase().includes("mindos")))return true}catch{}}return false}function agentList(f){const agents=[];for(const[key,agent]of Object.entries(MCP_AGENTS)){if(!detectAgentPresence(key))continue;agents.push({key,name:agent.name,installed:true,mindosConnected:hasMindosConfig(agent)})}if(isJsonMode(f)){output({count:agents.length,agents},f);return}if(agents.length===0){console.log(dim("No AI agents detected."));return}console.log("
8
- "+bold("Detected Agents ("+agents.length+"):")+"
9
- ");for(const a of agents){console.log(" "+a.name.padEnd(20)+" "+(a.mindosConnected?green("● connected"):dim("○ not connected")))}console.log("
10
- "+dim("Connect: mindos mcp install <agent-key>")+"
11
- ")}function agentInfo(key,f){if(!key){console.error(red("Usage: mindos agent info <key>"));process.exit(1)}const agent=MCP_AGENTS[key];if(!agent){console.error(red("Unknown: "+key));process.exit(1)}const installed=detectAgentPresence(key);const connected=installed?hasMindosConfig(agent):false;const info={key,name:agent.name,installed,mindosConnected:connected,transport:agent.preferredTransport};if(isJsonMode(f)){output(info,f);return}console.log("
12
- "+bold(agent.name)+"
13
- Key: "+key+"
14
- Installed: "+(installed?green("yes"):red("no"))+"
15
- MindOS: "+(connected?green("connected"):yellow("not connected"))+"
16
- Transport: "+agent.preferredTransport+(agent.global?"
17
- Config: "+expandHome(agent.global):"")+"
18
- ")}
1
+ import { bold, dim, cyan, green, red, yellow } from '../lib/colors.js';
2
+ import { MCP_AGENTS, detectAgentPresence } from '../lib/mcp-agents.js';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { resolve } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+ import { output, isJsonMode, EXIT } from '../lib/command.js';
7
+
8
+ function expandHome(p) {
9
+ return p.startsWith('~/') ? resolve(homedir(), p.slice(2)) : p;
10
+ }
11
+
12
+ export const meta = {
13
+ name: 'agent',
14
+ group: 'Knowledge',
15
+ summary: 'AI Agent management (list/info)',
16
+ usage: 'mindos agent <subcommand>',
17
+ };
18
+
19
+ export async function run(args, flags) {
20
+ const sub = args[0];
21
+ if (!sub || flags.help || flags.h) {
22
+ console.log(bold('mindos agent') + ' — AI Agent management\n');
23
+ console.log('Subcommands:');
24
+ console.log(' list List detected AI agents');
25
+ console.log(' info <agent-key> Show agent details\n');
26
+ console.log('Keys: ' + Object.keys(MCP_AGENTS).join(', '));
27
+ return;
28
+ }
29
+ if (sub === 'list' || sub === 'ls') return agentList(flags);
30
+ if (sub === 'info') return agentInfo(args[1], flags);
31
+ console.error(red('Unknown subcommand: ' + sub));
32
+ process.exit(EXIT.ARGS);
33
+ }
34
+
35
+ function hasMindosConfig(agent) {
36
+ const paths = [agent.global, agent.project].filter(Boolean).map(expandHome);
37
+ for (const p of paths) {
38
+ try {
39
+ if (!existsSync(p)) continue;
40
+ const raw = readFileSync(p, 'utf-8')
41
+ .replace(/\/\/.*$/gm, '')
42
+ .replace(/\/\*[\s\S]*?\*\//g, '');
43
+ const data = JSON.parse(raw);
44
+ const servers = data[agent.key] || {};
45
+ if (Object.keys(servers).some(k => k.toLowerCase().includes('mindos'))) return true;
46
+ } catch { /* skip */ }
47
+ }
48
+ return false;
49
+ }
50
+
51
+ function agentList(flags) {
52
+ const agents = [];
53
+ for (const [key, agent] of Object.entries(MCP_AGENTS)) {
54
+ if (!detectAgentPresence(key)) continue;
55
+ agents.push({ key, name: agent.name, installed: true, mindosConnected: hasMindosConfig(agent) });
56
+ }
57
+
58
+ if (isJsonMode(flags)) {
59
+ output({ count: agents.length, agents }, flags);
60
+ return;
61
+ }
62
+
63
+ if (agents.length === 0) {
64
+ console.log(dim('No AI agents detected.'));
65
+ return;
66
+ }
67
+
68
+ console.log('\n' + bold('Detected Agents (' + agents.length + '):') + '\n');
69
+ for (const a of agents) {
70
+ const st = a.mindosConnected ? green('● connected') : dim('○ not connected');
71
+ console.log(' ' + a.name.padEnd(20) + ' ' + st);
72
+ }
73
+ console.log('\n' + dim('Connect: mindos mcp install <agent-key>') + '\n');
74
+ }
75
+
76
+ function agentInfo(key, flags) {
77
+ if (!key) {
78
+ console.error(red('Usage: mindos agent info <agent-key>'));
79
+ process.exit(EXIT.ERROR);
80
+ }
81
+ const agent = MCP_AGENTS[key];
82
+ if (!agent) {
83
+ console.error(red('Unknown agent: ' + key));
84
+ process.exit(EXIT.ERROR);
85
+ }
86
+
87
+ const installed = detectAgentPresence(key);
88
+ const connected = installed ? hasMindosConfig(agent) : false;
89
+ const info = {
90
+ key,
91
+ name: agent.name,
92
+ installed,
93
+ mindosConnected: connected,
94
+ transport: agent.preferredTransport,
95
+ };
96
+
97
+ if (isJsonMode(flags)) {
98
+ output(info, flags);
99
+ return;
100
+ }
101
+
102
+ console.log('\n' + bold(agent.name));
103
+ console.log(' Key: ' + key);
104
+ console.log(' Installed: ' + (installed ? green('yes') : red('no')));
105
+ console.log(' MindOS: ' + (connected ? green('connected') : yellow('not connected')));
106
+ console.log(' Transport: ' + agent.preferredTransport);
107
+ if (agent.global) console.log(' Config: ' + expandHome(agent.global));
108
+ if (!connected && installed) console.log('\n Connect: mindos mcp install ' + key);
109
+ console.log('');
110
+ }
@@ -1,5 +1,6 @@
1
1
  import { bold, dim, cyan, red } from '../lib/colors.js';
2
2
  import { loadConfig } from '../lib/config.js';
3
+ import { EXIT } from '../lib/command.js';
3
4
 
4
5
  export const meta = {
5
6
  name: 'api',
@@ -23,7 +24,7 @@ export async function run(args, flags) {
23
24
  const method = args[0].toUpperCase();
24
25
  if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
25
26
  console.error(red('Invalid method: ' + args[0]));
26
- process.exit(1);
27
+ process.exit(EXIT.ARGS);
27
28
  }
28
29
 
29
30
  let apiPath = args[1];
@@ -46,13 +47,14 @@ export async function run(args, flags) {
46
47
  } else {
47
48
  console.log(await res.text());
48
49
  }
49
- if (!res.ok) process.exit(1);
50
+ if (!res.ok) process.exit(EXIT.ERROR);
50
51
  } catch (err) {
51
52
  if (err.cause && err.cause.code === 'ECONNREFUSED') {
52
53
  console.error(red('Connection refused. Start with: mindos start'));
54
+ process.exit(EXIT.CONNECT);
53
55
  } else {
54
56
  console.error(red('Request failed: ' + err.message));
57
+ process.exit(EXIT.ERROR);
55
58
  }
56
- process.exit(1);
57
59
  }
58
60
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { bold, dim, cyan, green, red } from '../lib/colors.js';
6
6
  import { loadConfig } from '../lib/config.js';
7
- import { output, isJsonMode } from '../lib/command.js';
7
+ import { output, isJsonMode, EXIT } from '../lib/command.js';
8
8
 
9
9
  export const meta = {
10
10
  name: 'ask',
@@ -52,7 +52,7 @@ ${bold('Note:')} MindOS must be running (mindos start).
52
52
  if (!healthRes.ok) throw new Error();
53
53
  } catch {
54
54
  console.error(red('MindOS is not running. Start it with: mindos start'));
55
- process.exit(1);
55
+ process.exit(EXIT.ERROR);
56
56
  }
57
57
 
58
58
  if (!isJsonMode(flags)) {
@@ -96,6 +96,6 @@ ${bold('Note:')} MindOS must be running (mindos start).
96
96
  process.stdout.write('\r' + ' '.repeat(40) + '\r');
97
97
  }
98
98
  console.error(red(err.message));
99
- process.exit(1);
99
+ process.exit(EXIT.ERROR);
100
100
  }
101
101
  }
@@ -9,14 +9,14 @@ import { existsSync, readFileSync, writeFileSync, unlinkSync, renameSync, mkdirS
9
9
  import { resolve, basename, dirname, relative } from 'node:path';
10
10
  import { bold, dim, cyan, green, red, yellow } from '../lib/colors.js';
11
11
  import { loadConfig } from '../lib/config.js';
12
- import { output, isJsonMode } from '../lib/command.js';
12
+ import { output, isJsonMode, EXIT } from '../lib/command.js';
13
13
 
14
14
  function getMindRoot() {
15
15
  loadConfig();
16
16
  const root = process.env.MIND_ROOT;
17
17
  if (!root || !existsSync(root)) {
18
18
  console.error(red('Mind root not configured. Run `mindos onboard` first.'));
19
- process.exit(1);
19
+ process.exit(EXIT.ERROR);
20
20
  }
21
21
  return root;
22
22
  }
@@ -71,7 +71,7 @@ export async function run(args, flags) {
71
71
  default:
72
72
  console.error(red(`Unknown subcommand: ${sub}`));
73
73
  console.error(dim('Available: list, read, create, delete, rename, move, search'));
74
- process.exit(1);
74
+ process.exit(EXIT.ERROR);
75
75
  }
76
76
  }
77
77
 
@@ -150,12 +150,12 @@ function fileList(root, _args, flags) {
150
150
  function fileRead(root, filePath, flags) {
151
151
  if (!filePath) {
152
152
  console.error(red('Usage: mindos file read <path>'));
153
- process.exit(1);
153
+ process.exit(EXIT.ERROR);
154
154
  }
155
155
  const full = resolvePath(root, filePath);
156
156
  if (!existsSync(full)) {
157
157
  console.error(red(`File not found: ${filePath}`));
158
- process.exit(1);
158
+ process.exit(EXIT.ERROR);
159
159
  }
160
160
  const content = readFileSync(full, 'utf-8');
161
161
 
@@ -169,13 +169,13 @@ function fileRead(root, filePath, flags) {
169
169
  function fileCreate(root, filePath, flags) {
170
170
  if (!filePath) {
171
171
  console.error(red('Usage: mindos file create <path> --content "..."'));
172
- process.exit(1);
172
+ process.exit(EXIT.ERROR);
173
173
  }
174
174
  const full = resolvePath(root, filePath);
175
175
  if (existsSync(full) && !flags.force) {
176
176
  console.error(red(`File already exists: ${filePath}`));
177
177
  console.error(dim('Use --force to overwrite.'));
178
- process.exit(1);
178
+ process.exit(EXIT.ERROR);
179
179
  }
180
180
 
181
181
  const content = flags.content || `# ${basename(filePath, '.md')}\n`;
@@ -192,12 +192,12 @@ function fileCreate(root, filePath, flags) {
192
192
  function fileDelete(root, filePath, flags) {
193
193
  if (!filePath) {
194
194
  console.error(red('Usage: mindos file delete <path>'));
195
- process.exit(1);
195
+ process.exit(EXIT.ERROR);
196
196
  }
197
197
  const full = resolvePath(root, filePath);
198
198
  if (!existsSync(full)) {
199
199
  console.error(red(`File not found: ${filePath}`));
200
- process.exit(1);
200
+ process.exit(EXIT.ERROR);
201
201
  }
202
202
 
203
203
  unlinkSync(full);
@@ -212,18 +212,18 @@ function fileDelete(root, filePath, flags) {
212
212
  function fileRename(root, oldPath, newPath, flags) {
213
213
  if (!oldPath || !newPath) {
214
214
  console.error(red('Usage: mindos file rename <old-path> <new-path>'));
215
- process.exit(1);
215
+ process.exit(EXIT.ERROR);
216
216
  }
217
217
  const fullOld = resolvePath(root, oldPath);
218
218
  const fullNew = resolvePath(root, newPath);
219
219
 
220
220
  if (!existsSync(fullOld)) {
221
221
  console.error(red(`File not found: ${oldPath}`));
222
- process.exit(1);
222
+ process.exit(EXIT.ERROR);
223
223
  }
224
224
  if (existsSync(fullNew) && !flags.force) {
225
225
  console.error(red(`Target already exists: ${newPath}`));
226
- process.exit(1);
226
+ process.exit(EXIT.ERROR);
227
227
  }
228
228
 
229
229
  mkdirSync(dirname(fullNew), { recursive: true });
@@ -239,7 +239,7 @@ function fileRename(root, oldPath, newPath, flags) {
239
239
  function fileSearch(root, query, flags) {
240
240
  if (!query) {
241
241
  console.error(red('Usage: mindos file search <query>'));
242
- process.exit(1);
242
+ process.exit(EXIT.ERROR);
243
243
  }
244
244
 
245
245
  const files = walkFiles(root, root);
@@ -1,6 +1,6 @@
1
1
  import { bold, dim, cyan, red } from '../lib/colors.js';
2
2
  import { loadConfig } from '../lib/config.js';
3
- import { output, isJsonMode } from '../lib/command.js';
3
+ import { output, isJsonMode, EXIT } from '../lib/command.js';
4
4
 
5
5
  export const meta = {
6
6
  name: 'search', group: 'Knowledge',
@@ -46,6 +46,6 @@ export async function run(args, flags) {
46
46
  } catch (err) {
47
47
  if (err.cause && err.cause.code === 'ECONNREFUSED') { console.error(red('MindOS not running. Offline: mindos file search "' + query + '"')); }
48
48
  else { console.error(red(err.message)); }
49
- process.exit(1);
49
+ process.exit(EXIT.ERROR);
50
50
  }
51
51
  }
@@ -2,18 +2,18 @@
2
2
  * mindos space — Mind Space management
3
3
  */
4
4
 
5
- import { existsSync, readdirSync, statSync, mkdirSync, writeFileSync } from 'node:fs';
5
+ import { existsSync, readdirSync, statSync, mkdirSync, writeFileSync, rmSync, renameSync } from 'node:fs';
6
6
  import { resolve, relative } from 'node:path';
7
7
  import { bold, dim, cyan, green, red } from '../lib/colors.js';
8
8
  import { loadConfig } from '../lib/config.js';
9
- import { output, isJsonMode } from '../lib/command.js';
9
+ import { output, isJsonMode, EXIT } from '../lib/command.js';
10
10
 
11
11
  function getMindRoot() {
12
12
  loadConfig();
13
13
  const root = process.env.MIND_ROOT;
14
14
  if (!root || !existsSync(root)) {
15
15
  console.error(red('Mind root not configured. Run `mindos onboard` first.'));
16
- process.exit(1);
16
+ process.exit(EXIT.ERROR);
17
17
  }
18
18
  return root;
19
19
  }
@@ -21,12 +21,14 @@ function getMindRoot() {
21
21
  export const meta = {
22
22
  name: 'space',
23
23
  group: 'Knowledge',
24
- summary: 'Mind Space management (list, create, info)',
24
+ summary: 'Mind Space management (list, create, delete, rename, info)',
25
25
  usage: 'mindos space <subcommand>',
26
26
  examples: [
27
27
  'mindos space list',
28
28
  'mindos space list --json',
29
29
  'mindos space create "Research"',
30
+ 'mindos space delete "Old Project"',
31
+ 'mindos space rename "Old" "New"',
30
32
  'mindos space info "Work"',
31
33
  ],
32
34
  };
@@ -42,11 +44,15 @@ ${bold('mindos space')} — Mind Space management
42
44
  ${bold('Subcommands:')}
43
45
  ${cyan('list'.padEnd(20))}${dim('List all spaces')}
44
46
  ${cyan('create <name>'.padEnd(20))}${dim('Create a new space')}
47
+ ${cyan('delete <name>'.padEnd(20))}${dim('Delete a space and all its files')}
48
+ ${cyan('rename <old> <new>'.padEnd(20))}${dim('Rename a space')}
45
49
  ${cyan('info <name>'.padEnd(20))}${dim('Show space details')}
46
50
 
47
51
  ${bold('Examples:')}
48
52
  ${dim('mindos space list')}
49
53
  ${dim('mindos space create "Research"')}
54
+ ${dim('mindos space delete "Old Project"')}
55
+ ${dim('mindos space rename "Old" "New"')}
50
56
  `);
51
57
  return;
52
58
  }
@@ -55,11 +61,13 @@ ${bold('Examples:')}
55
61
  case 'list': return spaceList(root, flags);
56
62
  case 'ls': return spaceList(root, flags);
57
63
  case 'create': return spaceCreate(root, args[1], flags);
64
+ case 'delete': case 'rm': return spaceDelete(root, args[1], flags);
65
+ case 'rename': case 'mv': return spaceRename(root, args[1], args[2], flags);
58
66
  case 'info': return spaceInfo(root, args[1], flags);
59
67
  default:
60
68
  console.error(red(`Unknown subcommand: ${sub}`));
61
- console.error(dim('Available: list, create, info'));
62
- process.exit(1);
69
+ console.error(dim('Available: list, create, delete, rename, info'));
70
+ process.exit(EXIT.ERROR);
63
71
  }
64
72
  }
65
73
 
@@ -114,12 +122,12 @@ function spaceList(root, flags) {
114
122
  function spaceCreate(root, name, flags) {
115
123
  if (!name) {
116
124
  console.error(red('Usage: mindos space create <name>'));
117
- process.exit(1);
125
+ process.exit(EXIT.ERROR);
118
126
  }
119
127
  const dir = resolve(root, name);
120
128
  if (existsSync(dir)) {
121
129
  console.error(red(`Space already exists: ${name}`));
122
- process.exit(1);
130
+ process.exit(EXIT.ERROR);
123
131
  }
124
132
 
125
133
  mkdirSync(dir, { recursive: true });
@@ -132,15 +140,61 @@ function spaceCreate(root, name, flags) {
132
140
  console.log(`${green('✔')} Created space: ${cyan(name)}`);
133
141
  }
134
142
 
143
+ function spaceDelete(root, name, flags) {
144
+ if (!name) {
145
+ console.error(red('Usage: mindos space delete <name>'));
146
+ process.exit(EXIT.ERROR);
147
+ }
148
+ const dir = resolve(root, name);
149
+ if (!existsSync(dir)) {
150
+ console.error(red(`Space not found: ${name}`));
151
+ process.exit(EXIT.ERROR);
152
+ }
153
+
154
+ const fileCount = countFiles(dir);
155
+ rmSync(dir, { recursive: true, force: true });
156
+
157
+ if (isJsonMode(flags)) {
158
+ output({ ok: true, name, deletedFiles: fileCount }, flags);
159
+ return;
160
+ }
161
+ console.log(`${green('✔')} Deleted space: ${cyan(name)} (${fileCount} files removed)`);
162
+ }
163
+
164
+ function spaceRename(root, oldName, newName, flags) {
165
+ if (!oldName || !newName) {
166
+ console.error(red('Usage: mindos space rename <old-name> <new-name>'));
167
+ process.exit(EXIT.ERROR);
168
+ }
169
+ const oldDir = resolve(root, oldName);
170
+ const newDir = resolve(root, newName);
171
+ if (!existsSync(oldDir)) {
172
+ console.error(red(`Space not found: ${oldName}`));
173
+ process.exit(EXIT.ERROR);
174
+ }
175
+ if (existsSync(newDir)) {
176
+ console.error(red(`Target already exists: ${newName}`));
177
+ process.exit(EXIT.ERROR);
178
+ }
179
+
180
+ renameSync(oldDir, newDir);
181
+
182
+ if (isJsonMode(flags)) {
183
+ output({ ok: true, from: oldName, to: newName }, flags);
184
+ return;
185
+ }
186
+ console.log(`${green('✔')} Renamed space: ${cyan(oldName)} → ${cyan(newName)}`);
187
+ }
188
+
135
189
  function spaceInfo(root, name, flags) {
136
190
  if (!name) {
137
191
  console.error(red('Usage: mindos space info <name>'));
138
- process.exit(1);
192
+ process.exit(EXIT.ERROR);
139
193
  }
140
194
  const dir = resolve(root, name);
141
195
  if (!existsSync(dir)) {
142
196
  console.error(red(`Space not found: ${name}`));
143
- process.exit(1);
197
+ process.exit(EXIT.ERROR);
144
198
  }
145
199
 
146
200
  const fileCount = countFiles(dir);
@@ -16,6 +16,16 @@ import { ROOT } from './constants.js';
16
16
  import { readFileSync } from 'node:fs';
17
17
  import { resolve } from 'node:path';
18
18
 
19
+ // ── Exit codes ────────────────────────────────────────────────────────────────
20
+ // Standardized exit codes for CLI commands. Use these instead of raw numbers.
21
+ export const EXIT = {
22
+ OK: 0, // Success
23
+ ERROR: 1, // General error
24
+ ARGS: 2, // Invalid arguments or usage
25
+ CONNECT: 3, // Connection refused / service not running
26
+ NOT_FOUND: 4, // Resource not found (file, agent, etc.)
27
+ };
28
+
19
29
  /** @type {Map<string, { meta: object, run: function }>} */
20
30
  const registry = new Map();
21
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.6.25",
3
+ "version": "0.6.28",
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",