@geminilight/mindos 0.6.27 → 0.6.29

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 (67) hide show
  1. package/app/app/api/a2a/agents/route.ts +9 -0
  2. package/app/app/api/a2a/delegations/route.ts +9 -0
  3. package/app/app/api/a2a/discover/route.ts +2 -0
  4. package/app/app/api/a2a/route.ts +6 -6
  5. package/app/app/api/acp/detect/route.ts +91 -0
  6. package/app/app/api/acp/registry/route.ts +31 -0
  7. package/app/app/api/acp/session/route.ts +55 -0
  8. package/app/app/layout.tsx +2 -0
  9. package/app/components/DirView.tsx +64 -2
  10. package/app/components/FileTree.tsx +19 -0
  11. package/app/components/GuideCard.tsx +7 -17
  12. package/app/components/MarkdownView.tsx +2 -0
  13. package/app/components/SearchModal.tsx +234 -80
  14. package/app/components/agents/AgentDetailContent.tsx +51 -6
  15. package/app/components/agents/AgentsContentPage.tsx +24 -6
  16. package/app/components/agents/AgentsOverviewSection.tsx +11 -0
  17. package/app/components/agents/AgentsPanelA2aTab.tsx +445 -0
  18. package/app/components/agents/SkillDetailPopover.tsx +4 -9
  19. package/app/components/agents/agents-content-model.ts +2 -2
  20. package/app/components/ask/AskContent.tsx +8 -0
  21. package/app/components/help/HelpContent.tsx +74 -18
  22. package/app/components/panels/AgentsPanel.tsx +1 -0
  23. package/app/components/panels/AgentsPanelAgentDetail.tsx +5 -8
  24. package/app/components/panels/AgentsPanelAgentListRow.tsx +10 -1
  25. package/app/components/panels/AgentsPanelHubNav.tsx +8 -1
  26. package/app/components/panels/EchoPanel.tsx +5 -1
  27. package/app/components/panels/EchoSidebarStats.tsx +136 -0
  28. package/app/components/settings/KnowledgeTab.tsx +3 -6
  29. package/app/components/settings/McpSkillsSection.tsx +4 -5
  30. package/app/components/settings/McpTab.tsx +6 -8
  31. package/app/components/setup/StepSecurity.tsx +4 -5
  32. package/app/components/setup/index.tsx +5 -11
  33. package/app/components/ui/Toaster.tsx +39 -0
  34. package/app/hooks/useA2aRegistry.ts +6 -1
  35. package/app/hooks/useAcpDetection.ts +65 -0
  36. package/app/hooks/useAcpRegistry.ts +51 -0
  37. package/app/hooks/useDelegationHistory.ts +49 -0
  38. package/app/lib/a2a/client.ts +49 -5
  39. package/app/lib/a2a/orchestrator.ts +0 -1
  40. package/app/lib/a2a/task-handler.ts +4 -4
  41. package/app/lib/a2a/types.ts +15 -0
  42. package/app/lib/acp/acp-tools.ts +93 -0
  43. package/app/lib/acp/bridge.ts +138 -0
  44. package/app/lib/acp/index.ts +24 -0
  45. package/app/lib/acp/registry.ts +135 -0
  46. package/app/lib/acp/session.ts +264 -0
  47. package/app/lib/acp/subprocess.ts +209 -0
  48. package/app/lib/acp/types.ts +136 -0
  49. package/app/lib/agent/tools.ts +2 -1
  50. package/app/lib/i18n/_core.ts +22 -0
  51. package/app/lib/i18n/index.ts +35 -0
  52. package/app/lib/i18n/modules/ai-chat.ts +215 -0
  53. package/app/lib/i18n/modules/common.ts +71 -0
  54. package/app/lib/i18n/modules/features.ts +153 -0
  55. package/app/lib/i18n/modules/knowledge.ts +425 -0
  56. package/app/lib/i18n/modules/navigation.ts +151 -0
  57. package/app/lib/i18n/modules/onboarding.ts +523 -0
  58. package/app/lib/i18n/modules/panels.ts +1052 -0
  59. package/app/lib/i18n/modules/settings.ts +585 -0
  60. package/app/lib/i18n-en.ts +2 -1518
  61. package/app/lib/i18n-zh.ts +2 -1542
  62. package/app/lib/i18n.ts +3 -6
  63. package/app/lib/toast.ts +79 -0
  64. package/bin/cli.js +25 -25
  65. package/bin/commands/file.js +29 -2
  66. package/bin/commands/space.js +249 -91
  67. package/package.json +1 -1
package/app/lib/i18n.ts CHANGED
@@ -1,6 +1,3 @@
1
- import { en } from './i18n-en';
2
- import { zh } from './i18n-zh';
3
-
4
- export type Locale = 'en' | 'zh';
5
- export const messages = { en, zh } as const;
6
- export type Messages = typeof messages['en'];
1
+ // Re-exports from modular i18n system.
2
+ // All translations are now organized in ./i18n/modules/*.ts
3
+ export { en, zh, messages, type Locale, type Messages } from './i18n/index';
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Global toast notification store.
3
+ * Uses module-level state + useSyncExternalStore (no Context/Provider needed).
4
+ *
5
+ * Usage:
6
+ * import { toast } from '@/lib/toast';
7
+ * toast.success('Saved!');
8
+ * toast.error('Something went wrong');
9
+ * toast.copy(); // "Copied" with check icon
10
+ * toast('Custom message'); // info type
11
+ */
12
+
13
+ export interface Toast {
14
+ id: string;
15
+ message: string;
16
+ type: 'success' | 'error' | 'info';
17
+ duration: number;
18
+ }
19
+
20
+ type ToastInput = { message: string; type?: Toast['type']; duration?: number };
21
+
22
+ const DEFAULT_DURATION = 2000;
23
+ const MAX_TOASTS = 3;
24
+
25
+ let toasts: Toast[] = [];
26
+ let listeners: Array<() => void> = [];
27
+ let nextId = 0;
28
+
29
+ function emit() {
30
+ for (const fn of listeners) fn();
31
+ }
32
+
33
+ export function subscribe(listener: () => void) {
34
+ listeners = [...listeners, listener];
35
+ return () => { listeners = listeners.filter((l) => l !== listener); };
36
+ }
37
+
38
+ export function getSnapshot(): Toast[] {
39
+ return toasts;
40
+ }
41
+
42
+ export function dismiss(id: string) {
43
+ toasts = toasts.filter((t) => t.id !== id);
44
+ emit();
45
+ }
46
+
47
+ function addToast(input: ToastInput) {
48
+ const id = `toast-${++nextId}`;
49
+ const t: Toast = {
50
+ id,
51
+ message: input.message,
52
+ type: input.type ?? 'info',
53
+ duration: input.duration ?? DEFAULT_DURATION,
54
+ };
55
+ toasts = [...toasts, t].slice(-MAX_TOASTS);
56
+ emit();
57
+ if (t.duration > 0) {
58
+ setTimeout(() => dismiss(id), t.duration);
59
+ }
60
+ }
61
+
62
+ /** Show an info toast */
63
+ function toast(message: string, opts?: { type?: Toast['type']; duration?: number }) {
64
+ addToast({ message, ...opts });
65
+ }
66
+
67
+ /** Show a success toast */
68
+ toast.success = (message: string, duration?: number) =>
69
+ addToast({ message, type: 'success', duration });
70
+
71
+ /** Show an error toast */
72
+ toast.error = (message: string, duration?: number) =>
73
+ addToast({ message, type: 'error', duration });
74
+
75
+ /** Show a "Copied" success toast */
76
+ toast.copy = (message = 'Copied') =>
77
+ addToast({ message, type: 'success', duration: 1500 });
78
+
79
+ export { toast };
package/bin/cli.js CHANGED
@@ -56,7 +56,7 @@ import { savePids, clearPids } from './lib/pid.js';
56
56
  import { stopMindos } from './lib/stop.js';
57
57
  import { printStartupInfo, getLocalIP } from './lib/startup.js';
58
58
  import { spawnMcp } from './lib/mcp-spawn.js';
59
- import { parseArgs } from './lib/command.js';
59
+ import { parseArgs, EXIT } from './lib/command.js';
60
60
  import { MCP_AGENTS, detectAgentPresence } from './lib/mcp-agents.js';
61
61
 
62
62
  // Heavy modules — loaded lazily inside command handlers to speed up CLI cold start
@@ -215,7 +215,7 @@ const commands = {
215
215
  token: () => {
216
216
  if (!existsSync(CONFIG_PATH)) {
217
217
  console.error(red('No config found. Run `mindos onboard` first.'));
218
- process.exit(1);
218
+ process.exit(EXIT.ERROR);
219
219
  }
220
220
  let config = {};
221
221
  try { config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8')); } catch {}
@@ -325,7 +325,7 @@ const commands = {
325
325
  if (!ready) {
326
326
  console.error(red('\n✘ Service started but Web UI did not become ready in time.'));
327
327
  console.error(dim(' Check logs with: mindos logs\n'));
328
- process.exit(1);
328
+ process.exit(EXIT.ERROR);
329
329
  }
330
330
  await printStartupInfo(webPort, mcpPort);
331
331
  // System notification
@@ -381,7 +381,7 @@ const commands = {
381
381
  const mcpOk = await waitForPortFree(Number(mcpPort), { retries: 60, intervalMs: 500 });
382
382
  if (!webOk || !mcpOk) {
383
383
  console.error('Ports still in use after 30s, exiting.');
384
- process.exit(1); // KeepAlive will retry after ThrottleInterval
384
+ process.exit(EXIT.ERROR); // KeepAlive will retry after ThrottleInterval
385
385
  }
386
386
  } else {
387
387
  await assertPortFree(Number(webPort), 'web');
@@ -515,19 +515,19 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
515
515
 
516
516
  if (!existsSync(CONFIG_PATH)) {
517
517
  console.log(` ${red('✘')} Config not found. Run ${cyan('mindos onboard')} first.\n`);
518
- process.exit(1);
518
+ process.exit(EXIT.ERROR);
519
519
  }
520
520
  let config;
521
521
  try {
522
522
  config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
523
523
  } catch {
524
524
  console.log(` ${red('✘')} Failed to parse config at ${dim(CONFIG_PATH)}\n`);
525
- process.exit(1);
525
+ process.exit(EXIT.ERROR);
526
526
  }
527
527
  const mindRoot = config.mindRoot;
528
528
  if (!mindRoot || !existsSync(mindRoot)) {
529
529
  console.log(` ${red('✘')} Knowledge base not found: ${dim(mindRoot || '(not set)')}\n`);
530
- process.exit(1);
530
+ process.exit(EXIT.ERROR);
531
531
  }
532
532
 
533
533
  // Skill operating rules are now built into SKILL.md (shipped with the app).
@@ -565,7 +565,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
565
565
  err(`Config not found at ${dim(CONFIG_PATH)}`, 'config');
566
566
  if (!jsonMode) { console.log(`\n ${dim('Run `mindos onboard` to create it.')}\n`); }
567
567
  if (jsonMode) { console.log(JSON.stringify({ ok: false, checks }, null, 2)); }
568
- process.exit(1);
568
+ process.exit(EXIT.ERROR);
569
569
  }
570
570
  let config;
571
571
  try {
@@ -719,7 +719,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
719
719
  ? `\n${red('Some checks failed.')} Run ${cyan('mindos onboard')} to reconfigure.\n`
720
720
  : `\n${green('All checks passed.')}\n`);
721
721
  }
722
- if (hasError) process.exit(1);
722
+ if (hasError) process.exit(EXIT.ERROR);
723
723
  },
724
724
 
725
725
  // ── update ─────────────────────────────────────────────────────────────────
@@ -737,7 +737,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
737
737
  } catch {
738
738
  writeUpdateFailed('downloading', 'npm install failed', { fromVersion: currentVersion });
739
739
  console.error(red('Update failed. Try: npm install -g @geminilight/mindos@latest'));
740
- process.exit(1);
740
+ process.exit(EXIT.ERROR);
741
741
  }
742
742
  if (existsSync(BUILD_STAMP)) rmSync(BUILD_STAMP);
743
743
 
@@ -820,7 +820,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
820
820
  : 'Server did not come back up in time';
821
821
  writeUpdateFailed('restarting', failMsg, vOpts);
822
822
  console.error(red(`✘ ${failMsg}. Check logs: mindos logs\n`));
823
- process.exit(1);
823
+ process.exit(EXIT.ERROR);
824
824
  }
825
825
  } else {
826
826
  // Non-daemon mode: check if a MindOS instance is currently running
@@ -890,7 +890,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
890
890
  : 'Server did not come back up in time';
891
891
  writeUpdateFailed('restarting', failMsg, vOpts);
892
892
  console.error(red(`✘ ${failMsg}. Check logs: mindos logs\n`));
893
- process.exit(1);
893
+ process.exit(EXIT.ERROR);
894
894
  }
895
895
  } else {
896
896
  // No running instance — just build and tell user to start manually
@@ -1071,12 +1071,12 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
1071
1071
  if (sub === 'show') {
1072
1072
  if (!existsSync(CONFIG_PATH)) {
1073
1073
  console.error(red('No config found. Run `mindos onboard` first.'));
1074
- process.exit(1);
1074
+ process.exit(EXIT.ERROR);
1075
1075
  }
1076
1076
  let config;
1077
1077
  try { config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8')); } catch {
1078
1078
  console.error(red('Failed to parse config file.'));
1079
- process.exit(1);
1079
+ process.exit(EXIT.ERROR);
1080
1080
  }
1081
1081
  const display = JSON.parse(JSON.stringify(config));
1082
1082
  if (display.ai?.providers?.anthropic?.apiKey)
@@ -1104,14 +1104,14 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
1104
1104
  if (sub === 'validate') {
1105
1105
  if (!existsSync(CONFIG_PATH)) {
1106
1106
  console.error(red('No config found. Run `mindos onboard` first.'));
1107
- process.exit(1);
1107
+ process.exit(EXIT.ERROR);
1108
1108
  }
1109
1109
  let config;
1110
1110
  try {
1111
1111
  config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
1112
1112
  } catch (e) {
1113
1113
  console.error(red(`✘ Invalid JSON: ${e.message}`));
1114
- process.exit(1);
1114
+ process.exit(EXIT.ERROR);
1115
1115
  }
1116
1116
  const issues = [];
1117
1117
  if (!config.mindRoot) issues.push('missing required field: mindRoot');
@@ -1128,7 +1128,7 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
1128
1128
  console.error(`\n${red('✘ Config has issues:')}`);
1129
1129
  issues.forEach(i => console.error(` ${red('•')} ${i}`));
1130
1130
  console.error(`\n ${dim('Run `mindos onboard` to fix.\n')}`);
1131
- process.exit(1);
1131
+ process.exit(EXIT.ERROR);
1132
1132
  }
1133
1133
  console.log(`\n${green('✔ Config is valid')}\n`);
1134
1134
  return;
@@ -1143,16 +1143,16 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
1143
1143
  console.error(dim(' mindos config set port 3002'));
1144
1144
  console.error(dim(' mindos config set mcpPort 8788'));
1145
1145
  console.error(dim(' mindos config set ai.provider openai'));
1146
- process.exit(1);
1146
+ process.exit(EXIT.ARGS);
1147
1147
  }
1148
1148
  if (!existsSync(CONFIG_PATH)) {
1149
1149
  console.error(red('No config found. Run `mindos onboard` first.'));
1150
- process.exit(1);
1150
+ process.exit(EXIT.ERROR);
1151
1151
  }
1152
1152
  let config;
1153
1153
  try { config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8')); } catch {
1154
1154
  console.error(red('Failed to parse config file.'));
1155
- process.exit(1);
1155
+ process.exit(EXIT.ERROR);
1156
1156
  }
1157
1157
  const parts = key.split('.');
1158
1158
  let obj = config;
@@ -1180,16 +1180,16 @@ ${dim('Shortcut: mindos start --daemon → install + start in one step')}
1180
1180
  const key = cliArgs[1];
1181
1181
  if (!key) {
1182
1182
  console.error(red('Usage: mindos config unset <key>'));
1183
- process.exit(1);
1183
+ process.exit(EXIT.ARGS);
1184
1184
  }
1185
1185
  if (!existsSync(CONFIG_PATH)) {
1186
1186
  console.error(red('No config found. Run `mindos onboard` first.'));
1187
- process.exit(1);
1187
+ process.exit(EXIT.ERROR);
1188
1188
  }
1189
1189
  let config;
1190
1190
  try { config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8')); } catch {
1191
1191
  console.error(red('Failed to parse config file.'));
1192
- process.exit(1);
1192
+ process.exit(EXIT.ERROR);
1193
1193
  }
1194
1194
  const parts = key.split('.');
1195
1195
  let obj = config;
@@ -1256,7 +1256,7 @@ ${bold('Examples:')}
1256
1256
  console.log(green('✔ Sync complete'));
1257
1257
  } catch (err) {
1258
1258
  console.error(red(err.message));
1259
- process.exit(1);
1259
+ process.exit(EXIT.ERROR);
1260
1260
  }
1261
1261
  return;
1262
1262
  }
@@ -1283,7 +1283,7 @@ ${bold('Examples:')}
1283
1283
  if (!validSubs.includes(sub)) {
1284
1284
  console.error(red(`Unknown sync subcommand: ${sub}`));
1285
1285
  console.error(dim(`Available: ${validSubs.join(' | ')}`));
1286
- process.exit(1);
1286
+ process.exit(EXIT.ARGS);
1287
1287
  }
1288
1288
  }
1289
1289
 
@@ -30,7 +30,7 @@ function resolvePath(root, filePath) {
30
30
  export const meta = {
31
31
  name: 'file',
32
32
  group: 'Knowledge',
33
- summary: 'Knowledge base file operations (list, read, create, delete, search)',
33
+ summary: 'File content operations (list, read, create, delete, rename, search)',
34
34
  usage: 'mindos file <subcommand>',
35
35
  flags: {
36
36
  '--space <name>': 'Filter by space name',
@@ -68,9 +68,12 @@ export async function run(args, flags) {
68
68
  case 'mv': return fileRename(root, args[1], args[2], flags);
69
69
  case 'move': return fileRename(root, args[1], args[2], flags);
70
70
  case 'search': return fileSearch(root, args.slice(1).join(' '), flags);
71
+ case 'mkdir':
72
+ console.log(dim('Moved to: mindos space mkdir <path>'));
73
+ process.exit(EXIT.ARGS);
71
74
  default:
72
75
  console.error(red(`Unknown subcommand: ${sub}`));
73
- console.error(dim('Available: list, read, create, delete, rename, move, search'));
76
+ console.error(dim('Available: list, read, create, delete, rename, move, mkdir, search'));
74
77
  process.exit(EXIT.ERROR);
75
78
  }
76
79
  }
@@ -284,3 +287,27 @@ function fileSearch(root, query, flags) {
284
287
  }
285
288
  console.log();
286
289
  }
290
+
291
+ function fileMkdir(root, dirPath, flags) {
292
+ if (!dirPath) {
293
+ console.error(red('Usage: mindos file mkdir <path>'));
294
+ process.exit(EXIT.ERROR);
295
+ }
296
+ const full = resolve(root, dirPath);
297
+ if (existsSync(full)) {
298
+ if (isJsonMode(flags)) {
299
+ output({ ok: true, path: dirPath, created: false, message: 'already exists' }, flags);
300
+ return;
301
+ }
302
+ console.log(dim(`Directory already exists: ${dirPath}`));
303
+ return;
304
+ }
305
+
306
+ mkdirSync(full, { recursive: true });
307
+
308
+ if (isJsonMode(flags)) {
309
+ output({ ok: true, path: dirPath, created: true }, flags);
310
+ return;
311
+ }
312
+ console.log(`${green('✔')} Created directory: ${cyan(dirPath)}`);
313
+ }