@kernel.chat/kbot 2.5.0 → 2.8.0

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 (79) hide show
  1. package/README.md +98 -42
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +140 -21
  4. package/dist/agent.js.map +1 -1
  5. package/dist/architect.d.ts +44 -0
  6. package/dist/architect.d.ts.map +1 -0
  7. package/dist/architect.js +403 -0
  8. package/dist/architect.js.map +1 -0
  9. package/dist/auth.d.ts +11 -1
  10. package/dist/auth.d.ts.map +1 -1
  11. package/dist/auth.js +165 -7
  12. package/dist/auth.js.map +1 -1
  13. package/dist/cli.js +251 -22
  14. package/dist/cli.js.map +1 -1
  15. package/dist/graph-memory.d.ts +98 -0
  16. package/dist/graph-memory.d.ts.map +1 -0
  17. package/dist/graph-memory.js +926 -0
  18. package/dist/graph-memory.js.map +1 -0
  19. package/dist/ide/acp-server.js +2 -2
  20. package/dist/ide/mcp-server.js +1 -1
  21. package/dist/lsp-client.d.ts +167 -0
  22. package/dist/lsp-client.d.ts.map +1 -0
  23. package/dist/lsp-client.js +679 -0
  24. package/dist/lsp-client.js.map +1 -0
  25. package/dist/matrix.d.ts +6 -0
  26. package/dist/matrix.d.ts.map +1 -1
  27. package/dist/matrix.js +98 -0
  28. package/dist/matrix.js.map +1 -1
  29. package/dist/mcp-plugins.d.ts +62 -0
  30. package/dist/mcp-plugins.d.ts.map +1 -0
  31. package/dist/mcp-plugins.js +551 -0
  32. package/dist/mcp-plugins.js.map +1 -0
  33. package/dist/planner.d.ts.map +1 -1
  34. package/dist/planner.js +29 -0
  35. package/dist/planner.js.map +1 -1
  36. package/dist/provider-fallback.d.ts +51 -0
  37. package/dist/provider-fallback.d.ts.map +1 -0
  38. package/dist/provider-fallback.js +237 -0
  39. package/dist/provider-fallback.js.map +1 -0
  40. package/dist/repo-map.d.ts +9 -0
  41. package/dist/repo-map.d.ts.map +1 -0
  42. package/dist/repo-map.js +280 -0
  43. package/dist/repo-map.js.map +1 -0
  44. package/dist/self-eval.d.ts +45 -0
  45. package/dist/self-eval.d.ts.map +1 -0
  46. package/dist/self-eval.js +232 -0
  47. package/dist/self-eval.js.map +1 -0
  48. package/dist/streaming.d.ts.map +1 -1
  49. package/dist/streaming.js +22 -2
  50. package/dist/streaming.js.map +1 -1
  51. package/dist/task-ledger.d.ts +71 -0
  52. package/dist/task-ledger.d.ts.map +1 -0
  53. package/dist/task-ledger.js +282 -0
  54. package/dist/task-ledger.js.map +1 -0
  55. package/dist/tools/computer.js +3 -3
  56. package/dist/tools/computer.js.map +1 -1
  57. package/dist/tools/e2b-sandbox.d.ts +2 -0
  58. package/dist/tools/e2b-sandbox.d.ts.map +1 -0
  59. package/dist/tools/e2b-sandbox.js +460 -0
  60. package/dist/tools/e2b-sandbox.js.map +1 -0
  61. package/dist/tools/index.d.ts.map +1 -1
  62. package/dist/tools/index.js +15 -1
  63. package/dist/tools/index.js.map +1 -1
  64. package/dist/tools/lsp-tools.d.ts +2 -0
  65. package/dist/tools/lsp-tools.d.ts.map +1 -0
  66. package/dist/tools/lsp-tools.js +268 -0
  67. package/dist/tools/lsp-tools.js.map +1 -0
  68. package/dist/tools/memory-tools.d.ts +2 -0
  69. package/dist/tools/memory-tools.d.ts.map +1 -0
  70. package/dist/tools/memory-tools.js +228 -0
  71. package/dist/tools/memory-tools.js.map +1 -0
  72. package/dist/tools/quality.d.ts +2 -0
  73. package/dist/tools/quality.d.ts.map +1 -0
  74. package/dist/tools/quality.js +313 -0
  75. package/dist/tools/quality.js.map +1 -0
  76. package/dist/ui.d.ts.map +1 -1
  77. package/dist/ui.js +33 -18
  78. package/dist/ui.js.map +1 -1
  79. package/package.json +27 -3
package/dist/cli.js CHANGED
@@ -16,20 +16,20 @@ import { gatherContext } from './context.js';
16
16
  import { registerAllTools } from './tools/index.js';
17
17
  import { clearHistory, clearMemory, compactHistory, restoreHistory } from './memory.js';
18
18
  import { saveSession, loadSession, listSessions, deleteSession, formatSessionList, } from './sessions.js';
19
- import { createAgent, removeAgent, getAgent, formatAgentList, formatAgentDetail, PRESETS, getMatrixAgentIds, activateMimic, listMimicProfiles, getMimicProfile, } from './matrix.js';
19
+ import { createAgent, removeAgent, getAgent, formatAgentList, formatAgentDetail, PRESETS, getMatrixAgentIds, activateMimic, listMimicProfiles, getMimicProfile, registerBuiltinAgents, formatBuiltinAgentList, formatBuiltinAgentDetail, } from './matrix.js';
20
20
  import { getExtendedStats, incrementSessions, learnFact, selfTrain, getTrainingLog, flushPendingWrites } from './learning.js';
21
21
  import { banner, bannerCompact, bannerAuth, prompt as kbotPrompt, printError, printSuccess, printInfo, printResponse, printHelp, printGoodbye, setQuiet, } from './ui.js';
22
22
  import { checkForUpdate, selfUpdate } from './updater.js';
23
23
  import { syncOnStartup, schedulePush, flushCloudSync, isCloudSyncEnabled, setCloudToken, getCloudToken } from './cloud-sync.js';
24
24
  import chalk from 'chalk';
25
- const VERSION = '2.5.0';
25
+ const VERSION = '2.8.0';
26
26
  async function main() {
27
27
  const program = new Command();
28
28
  program
29
29
  .name('kbot')
30
30
  .description('K:BOT — Open-source terminal AI agent. Bring your own key, pick your model, run locally.')
31
31
  .version(VERSION)
32
- .option('-a, --agent <agent>', 'Force a specific agent (kernel, researcher, coder, writer, analyst)')
32
+ .option('-a, --agent <agent>', 'Force a specific agent (kernel, researcher, coder, writer, analyst, hacker, operator, dreamer)')
33
33
  .option('-m, --model <model>', 'Override AI model (auto, sonnet, haiku)')
34
34
  .option('-s, --stream', 'Stream the response')
35
35
  .option('-p, --pipe', 'Pipe mode — raw text output for scripting')
@@ -40,6 +40,8 @@ async function main() {
40
40
  .option('--computer-use', 'Enable computer use tools')
41
41
  .option('-t, --thinking', 'Show AI reasoning steps')
42
42
  .option('--thinking-budget <tokens>', 'Thinking token budget (default: 10000)')
43
+ .option('--self-eval', 'Enable self-evaluation loop (score and retry low-quality responses)')
44
+ .option('--architect', 'Architect mode — plan-review-implement with dual agents')
43
45
  .option('--safe', 'Confirm destructive operations')
44
46
  .option('--strict', 'Confirm ALL operations')
45
47
  .argument('[prompt...]', 'One-shot prompt')
@@ -86,7 +88,7 @@ async function main() {
86
88
  });
87
89
  program
88
90
  .command('byok')
89
- .description('Bring Your Own Key — configure your LLM API key (14 providers)')
91
+ .description('Bring Your Own Key — configure your LLM API key (19 providers)')
90
92
  .option('--off', 'Disable BYOK mode')
91
93
  .action(async (opts) => {
92
94
  if (opts.off) {
@@ -370,7 +372,7 @@ async function main() {
370
372
  });
371
373
  program
372
374
  .command('serve')
373
- .description('Start HTTP server — expose all 60+ tools for kernel.chat or any client')
375
+ .description('Start HTTP server — expose all 119 tools for kernel.chat or any client')
374
376
  .option('-p, --port <port>', 'Port to listen on', '7437')
375
377
  .option('--token <token>', 'Require auth token for all requests')
376
378
  .option('--computer-use', 'Enable computer use tools')
@@ -401,6 +403,27 @@ async function main() {
401
403
  printError('Cannot connect to OpenClaw gateway. Start it first.');
402
404
  }
403
405
  });
406
+ program
407
+ .command('agents [name]')
408
+ .description('List all available agents, or show details for one')
409
+ .action(async (name) => {
410
+ registerBuiltinAgents();
411
+ if (name) {
412
+ const detail = formatBuiltinAgentDetail(name);
413
+ if (detail) {
414
+ console.log(detail);
415
+ }
416
+ else {
417
+ printError(`Agent "${name}" not found.`);
418
+ printInfo('Run `kbot agents` to see all available agents.');
419
+ }
420
+ }
421
+ else {
422
+ console.log(formatBuiltinAgentList());
423
+ console.log();
424
+ printInfo('Use: kbot --agent <name> "prompt"');
425
+ }
426
+ });
404
427
  program.parse(process.argv);
405
428
  const opts = program.opts();
406
429
  const promptArgs = program.args;
@@ -408,7 +431,7 @@ async function main() {
408
431
  if (opts.quiet)
409
432
  setQuiet(true);
410
433
  // If a sub-command was run, we're done
411
- if (['byok', 'auth', 'ide', 'ollama', 'openclaw', 'pull', 'doctor', 'serve'].includes(program.args[0]))
434
+ if (['byok', 'auth', 'ide', 'ollama', 'openclaw', 'pull', 'doctor', 'serve', 'agents'].includes(program.args[0]))
412
435
  return;
413
436
  // Check for API key (BYOK or local provider)
414
437
  let byokActive = isByokEnabled();
@@ -422,9 +445,10 @@ async function main() {
422
445
  localActive = isLocalProvider(envDetected);
423
446
  printSuccess(`Auto-detected ${PROVIDERS[envDetected].name} from environment.`);
424
447
  }
425
- // Priority 2: Check local providers in PARALLEL (both at once, use whichever responds first)
448
+ // Priority 2: Check local providers in PARALLEL (all at once, use whichever responds first)
426
449
  if (!byokActive) {
427
- const [ollamaResult, openclawResult] = await Promise.allSettled([
450
+ const { isLmStudioRunning, isJanRunning, setupLmStudio, setupJan } = await import('./auth.js');
451
+ const [ollamaResult, lmstudioResult, janResult, openclawResult] = await Promise.allSettled([
428
452
  // Check Ollama
429
453
  (async () => {
430
454
  const up = await isOllamaRunning();
@@ -436,6 +460,22 @@ async function main() {
436
460
  const ok = await setupOllama();
437
461
  return ok ? { provider: 'ollama', models: models.length } : null;
438
462
  })(),
463
+ // Check LM Studio
464
+ (async () => {
465
+ const up = await isLmStudioRunning();
466
+ if (!up)
467
+ return null;
468
+ const ok = await setupLmStudio();
469
+ return ok ? { provider: 'lmstudio' } : null;
470
+ })(),
471
+ // Check Jan
472
+ (async () => {
473
+ const up = await isJanRunning();
474
+ if (!up)
475
+ return null;
476
+ const ok = await setupJan();
477
+ return ok ? { provider: 'jan' } : null;
478
+ })(),
439
479
  // Check OpenClaw
440
480
  (async () => {
441
481
  try {
@@ -450,14 +490,26 @@ async function main() {
450
490
  }
451
491
  })(),
452
492
  ]);
453
- // Prefer Ollama if both available (more models, more control)
493
+ // Prefer Ollama > LM Studio > Jan > OpenClaw
454
494
  const ollamaOk = ollamaResult.status === 'fulfilled' && ollamaResult.value;
495
+ const lmstudioOk = lmstudioResult.status === 'fulfilled' && lmstudioResult.value;
496
+ const janOk = janResult.status === 'fulfilled' && janResult.value;
455
497
  const openclawOk = openclawResult.status === 'fulfilled' && openclawResult.value;
456
498
  if (ollamaOk) {
457
499
  byokActive = true;
458
500
  localActive = true;
459
501
  printSuccess(`Auto-configured Ollama (${ollamaOk.models} models). Ready — $0 cost!`);
460
502
  }
503
+ else if (lmstudioOk) {
504
+ byokActive = true;
505
+ localActive = true;
506
+ printSuccess('Auto-configured LM Studio. Ready — $0 cost!');
507
+ }
508
+ else if (janOk) {
509
+ byokActive = true;
510
+ localActive = true;
511
+ printSuccess('Auto-configured Jan. Ready — $0 cost!');
512
+ }
461
513
  else if (openclawOk) {
462
514
  byokActive = true;
463
515
  localActive = true;
@@ -488,6 +540,9 @@ async function main() {
488
540
  { env: 'PERPLEXITY_API_KEY', provider: 'perplexity' },
489
541
  { env: 'COHERE_API_KEY', provider: 'cohere' },
490
542
  { env: 'NVIDIA_API_KEY', provider: 'nvidia' },
543
+ { env: 'SAMBANOVA_API_KEY', provider: 'sambanova' },
544
+ { env: 'CEREBRAS_API_KEY', provider: 'cerebras' },
545
+ { env: 'OPENROUTER_API_KEY', provider: 'openrouter' },
491
546
  ];
492
547
  for (const { env, provider } of envKeys) {
493
548
  if (process.env[env])
@@ -513,6 +568,8 @@ async function main() {
513
568
  setPermissionMode('permissive');
514
569
  }
515
570
  }
571
+ // Register built-in agents (hacker, operator, dreamer) so --agent flag works
572
+ registerBuiltinAgents();
516
573
  // Parallel startup: register tools, gather context, check updates, and cloud sync
517
574
  const [, context, , syncMsg] = await Promise.all([
518
575
  registerAllTools({ computerUse: opts.computerUse }),
@@ -542,6 +599,11 @@ async function main() {
542
599
  thinking: opts.thinking || false,
543
600
  thinkingBudget: opts.thinkingBudget ? (parseInt(opts.thinkingBudget, 10) || 10000) : undefined,
544
601
  };
602
+ // Enable self-evaluation if requested
603
+ if (opts.selfEval) {
604
+ const { setSelfEvalEnabled } = await import('./self-eval.js');
605
+ setSelfEvalEnabled(true);
606
+ }
545
607
  // Pipe mode: echo "prompt" | kbot -p OR kbot -p "prompt"
546
608
  if (opts.pipe) {
547
609
  let message = promptArgs.join(' ');
@@ -639,6 +701,12 @@ async function main() {
639
701
  }) + '\n');
640
702
  return;
641
703
  }
704
+ // Architect mode: plan-review-implement with dual agents
705
+ if (opts.architect) {
706
+ const { runArchitectMode } = await import('./architect.js');
707
+ await runArchitectMode(message, agentOpts);
708
+ return;
709
+ }
642
710
  agentOpts.stream = true; // Force streaming for faster one-shot
643
711
  await runAndPrint(message, agentOpts);
644
712
  return;
@@ -739,12 +807,13 @@ async function byokFlow() {
739
807
  async function guidedSetup() {
740
808
  console.log(banner(VERSION));
741
809
  console.log();
742
- console.log(chalk.bold(' Welcome! Let\'s get you set up.'));
810
+ console.log(chalk.bold(' Hey! I\'m K:BOT your AI assistant for the terminal.'));
743
811
  console.log();
744
- console.log(chalk.dim(' K:BOT needs an AI brain to work. You have two options:'));
812
+ console.log(chalk.dim(' I can write code, answer questions, search the web, manage git,'));
813
+ console.log(chalk.dim(' and a lot more. First, I need an AI brain. Pick one:'));
745
814
  console.log();
746
- console.log(` ${chalk.bold('1.')} ${chalk.hex('#6B8E6B')('Free & Private')} — Run AI on your computer (no account needed)`);
747
- console.log(` ${chalk.bold('2.')} ${chalk.hex('#5B8BA0')('Cloud AI')} — Use an API key from OpenAI, Google, Anthropic, etc.`);
815
+ console.log(` ${chalk.bold('1.')} ${chalk.hex('#6B8E6B')('Free & Private')} — Run AI on your computer (no account, no cost)`);
816
+ console.log(` ${chalk.bold('2.')} ${chalk.hex('#5B8BA0')('Cloud AI')} — Use an API key (OpenAI, Google, Anthropic, etc.)`);
748
817
  console.log();
749
818
  const rl = createInterface({ input: process.stdin, output: process.stdout });
750
819
  const choice = await new Promise((resolve) => {
@@ -885,14 +954,48 @@ async function startRepl(agentOpts, context, tier, byokActive = false, localActi
885
954
  printInfo(`${p.name}`);
886
955
  }
887
956
  const sessionCount = incrementSessions();
957
+ // Return-visit greeting — show kbot's growth
958
+ if (sessionCount > 1) {
959
+ const stats = getExtendedStats();
960
+ const parts = [];
961
+ if (stats.patternsCount > 0)
962
+ parts.push(`${stats.patternsCount} patterns learned`);
963
+ if (stats.solutionsCount > 0)
964
+ parts.push(`${stats.solutionsCount} solutions cached`);
965
+ if (stats.knowledgeCount > 0)
966
+ parts.push(`${stats.knowledgeCount} facts remembered`);
967
+ if (parts.length > 0) {
968
+ printInfo(`Session ${stats.sessions} · ${parts.join(' · ')}`);
969
+ }
970
+ }
888
971
  const rl = createInterface({
889
972
  input: process.stdin,
890
973
  output: process.stdout,
891
974
  prompt: kbotPrompt(),
892
975
  });
893
- // First time? Show a gentle hint
976
+ // First time? Show a friendly walkthrough
894
977
  if (sessionCount <= 1) {
895
- printInfo('Try: "hello" or "create a python script" or /help');
978
+ console.log();
979
+ console.log(chalk.dim(' ┌─────────────────────────────────────────────┐'));
980
+ console.log(chalk.dim(' │') + chalk.bold(' Welcome! Here are some things you can try: ') + chalk.dim(' │'));
981
+ console.log(chalk.dim(' │ │'));
982
+ console.log(chalk.dim(' │') + ' "explain this project" ' + chalk.dim(' │'));
983
+ console.log(chalk.dim(' │') + ' "write a function that sorts names" ' + chalk.dim(' │'));
984
+ console.log(chalk.dim(' │') + ' "find all TODO comments in this repo" ' + chalk.dim(' │'));
985
+ console.log(chalk.dim(' │') + ' "what files are in this directory?" ' + chalk.dim(' │'));
986
+ console.log(chalk.dim(' │ │'));
987
+ console.log(chalk.dim(' │') + chalk.dim(' Type /help for more commands. ') + chalk.dim(' │'));
988
+ console.log(chalk.dim(' └─────────────────────────────────────────────┘'));
989
+ console.log();
990
+ }
991
+ else if (sessionCount <= 3) {
992
+ // Second and third time — show a quick tip they might not know
993
+ const tips = [
994
+ 'Tip: kbot picks the right specialist for you. Try asking about science, code, or writing.',
995
+ 'Tip: Type /save to keep this conversation. /resume to pick it up later.',
996
+ 'Tip: kbot learns from you. The more you use it, the better it gets.',
997
+ ];
998
+ printInfo(tips[Math.min(sessionCount - 1, tips.length - 1)]);
896
999
  }
897
1000
  console.log();
898
1001
  rl.prompt();
@@ -929,12 +1032,28 @@ async function startRepl(agentOpts, context, tier, byokActive = false, localActi
929
1032
  if (!response.streamed) {
930
1033
  printResponse(response.agent, response.content);
931
1034
  }
932
- // Usage footer — subtle, compact like Claude Code
933
- if (response.usage) {
934
- const tokens = response.usage.input_tokens + response.usage.output_tokens;
935
- const cost = response.usage.cost_usd === 0 ? 'free' : `$${response.usage.cost_usd.toFixed(4)}`;
936
- const tools = response.toolCalls > 0 ? ` · ${response.toolCalls} tools` : '';
937
- printInfo(`${tokens} tokens${tools} · ${cost}`);
1035
+ // Mentor footer — teach the user what kbot did (agent, tools, cost)
1036
+ {
1037
+ const parts = [];
1038
+ // Show which agent handled it (teaches routing)
1039
+ if (response.agent && response.agent !== 'kernel') {
1040
+ parts.push(`${response.agent} agent`);
1041
+ }
1042
+ if (response.toolCalls > 0) {
1043
+ parts.push(`${response.toolCalls} tool${response.toolCalls > 1 ? 's' : ''} used`);
1044
+ }
1045
+ if (response.usage) {
1046
+ const tokens = response.usage.input_tokens + response.usage.output_tokens;
1047
+ const cost = response.usage.cost_usd === 0 ? 'free' : `$${response.usage.cost_usd.toFixed(4)}`;
1048
+ parts.push(`${tokens} tokens · ${cost}`);
1049
+ }
1050
+ if (parts.length > 0) {
1051
+ printInfo(parts.join(' · '));
1052
+ }
1053
+ // On first 5 sessions, teach what just happened
1054
+ if (sessionCount <= 5 && response.agent && response.agent !== 'kernel') {
1055
+ printInfo(chalk.dim(` I picked the ${response.agent} agent for this. You can also say /agent ${response.agent} to use it directly.`));
1056
+ }
938
1057
  }
939
1058
  // Schedule cloud sync push (debounced — batches writes)
940
1059
  schedulePush();
@@ -1071,6 +1190,47 @@ async function handleSlashCommand(input, opts, rl) {
1071
1190
  case 'help':
1072
1191
  printHelp();
1073
1192
  break;
1193
+ case 'tutorial': {
1194
+ console.log();
1195
+ console.log(chalk.bold(' Let\'s build something together. Pick a track:'));
1196
+ console.log();
1197
+ console.log(` ${chalk.bold('1.')} ${chalk.hex('#4ADE80')('Build a website')} — Create an HTML page from scratch`);
1198
+ console.log(` ${chalk.bold('2.')} ${chalk.hex('#60A5FA')('Fix a bug')} — Find and fix a problem in code`);
1199
+ console.log(` ${chalk.bold('3.')} ${chalk.hex('#FB923C')('Write a script')} — Automate something with Python or JavaScript`);
1200
+ console.log(` ${chalk.bold('4.')} ${chalk.hex('#F472B6')('Research a topic')} — Deep-dive into any subject`);
1201
+ console.log(` ${chalk.bold('5.')} ${chalk.hex('#A78BFA')('Explore this project')} — Understand the code in this folder`);
1202
+ console.log();
1203
+ console.log(chalk.dim(' Pick a number, or just type what you want to build.'));
1204
+ console.log();
1205
+ const tutorialInput = await new Promise((resolve) => {
1206
+ rl.question(' Your choice: ', (answer) => resolve(answer.trim()));
1207
+ });
1208
+ const tutorialPrompts = {
1209
+ '1': 'Create a simple, beautiful HTML page with a heading, a paragraph about me, and some CSS styling. Save it as index.html. Walk me through what each part does.',
1210
+ '2': 'Look at the files in this directory. Find any issues, bugs, or things that could be improved. Explain what you found and fix the most important one.',
1211
+ '3': 'Write a short script that lists all files in the current directory, sorted by size. Use the language that makes the most sense for this project. Explain each line.',
1212
+ '4': 'I want to understand how AI agents work. Research this topic and explain it simply — what are agents, how do they think, and what tools do they use? Give real examples.',
1213
+ '5': 'Explore this project directory. What language is it written in? What does it do? What are the most important files? Give me a quick tour.',
1214
+ };
1215
+ const prompt = tutorialPrompts[tutorialInput] || tutorialInput;
1216
+ if (prompt) {
1217
+ console.log();
1218
+ printInfo('Great choice! Let me work on that...');
1219
+ console.log();
1220
+ try {
1221
+ const response = await runAgent(prompt, opts);
1222
+ if (!response.streamed) {
1223
+ printResponse(response.agent, response.content);
1224
+ }
1225
+ console.log();
1226
+ printInfo(chalk.dim('That\'s the basics! Keep asking questions — I learn from every conversation.'));
1227
+ }
1228
+ catch (err) {
1229
+ printError(err instanceof Error ? err.message : String(err));
1230
+ }
1231
+ }
1232
+ break;
1233
+ }
1074
1234
  case 'agent':
1075
1235
  if (args[0]) {
1076
1236
  opts.agent = args[0];
@@ -1241,6 +1401,74 @@ async function handleSlashCommand(input, opts, rl) {
1241
1401
  if (opts.thinking)
1242
1402
  printInfo('AI will show reasoning steps before responding.');
1243
1403
  break;
1404
+ case 'self-eval':
1405
+ case 'selfeval': {
1406
+ const { isSelfEvalEnabled, setSelfEvalEnabled } = await import('./self-eval.js');
1407
+ const newState = !isSelfEvalEnabled();
1408
+ setSelfEvalEnabled(newState);
1409
+ printSuccess(`Self-evaluation: ${newState ? 'ON' : 'OFF'}`);
1410
+ if (newState)
1411
+ printInfo('Responses will be scored for quality and retried if below threshold.');
1412
+ break;
1413
+ }
1414
+ case 'health':
1415
+ case 'providers': {
1416
+ const { getProviderHealth } = await import('./provider-fallback.js');
1417
+ const health = getProviderHealth();
1418
+ const active = health.filter(h => h.lastSuccess || h.lastFailure);
1419
+ if (active.length === 0) {
1420
+ printInfo('No provider calls recorded yet.');
1421
+ }
1422
+ else {
1423
+ console.log();
1424
+ printInfo('Provider Health:');
1425
+ for (const h of active) {
1426
+ const status = h.isHealthy ? chalk.green('healthy') : chalk.red('unhealthy');
1427
+ const latency = h.avgLatencyMs ? `${h.avgLatencyMs}ms` : '-';
1428
+ const failures = h.consecutiveFailures > 0 ? chalk.yellow(` (${h.consecutiveFailures} failures)`) : '';
1429
+ printInfo(` ${h.provider}: ${status} · ${latency}${failures}`);
1430
+ }
1431
+ console.log();
1432
+ }
1433
+ break;
1434
+ }
1435
+ case 'architect': {
1436
+ const archTask = args.join(' ');
1437
+ if (!archTask) {
1438
+ printError('Usage: /architect <task description>');
1439
+ printInfo('Example: /architect refactor the auth system to use JWT');
1440
+ }
1441
+ else {
1442
+ const { runArchitectMode } = await import('./architect.js');
1443
+ await runArchitectMode(archTask, opts);
1444
+ }
1445
+ break;
1446
+ }
1447
+ case 'graph': {
1448
+ const graphArgs = args.join(' ');
1449
+ if (!graphArgs) {
1450
+ const { getGraph } = await import('./graph-memory.js');
1451
+ const graph = getGraph();
1452
+ printInfo(`Graph: ${graph.nodes.size} nodes, ${graph.edges.length} edges`);
1453
+ if (graph.nodes.size > 0) {
1454
+ const { toContext } = await import('./graph-memory.js');
1455
+ printInfo(toContext(500));
1456
+ }
1457
+ }
1458
+ else {
1459
+ const { findNode } = await import('./graph-memory.js');
1460
+ const results = findNode(graphArgs);
1461
+ if (results.length === 0) {
1462
+ printInfo('No matching nodes found.');
1463
+ }
1464
+ else {
1465
+ for (const n of results.slice(0, 10)) {
1466
+ printInfo(` [${n.type}:${n.name}] (${n.accessCount} accesses)`);
1467
+ }
1468
+ }
1469
+ }
1470
+ break;
1471
+ }
1244
1472
  case 'plan': {
1245
1473
  const planTask = args.join(' ');
1246
1474
  if (!planTask) {
@@ -1513,7 +1741,8 @@ async function handleSlashCommand(input, opts, rl) {
1513
1741
  rl.close();
1514
1742
  break;
1515
1743
  default:
1516
- printError(`Unknown command: /${cmd}. Type /help for available commands.`);
1744
+ printError(`I don't know "/${cmd}". Here are some you can try:`);
1745
+ printInfo(' /save — save this chat | /agent — pick a specialist | /help — see everything');
1517
1746
  }
1518
1747
  }
1519
1748
  // Prevent unhandled rejections from killing the process