@kernel.chat/kbot 3.17.2 → 3.19.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.
package/dist/cli.js CHANGED
@@ -395,6 +395,66 @@ async function main() {
395
395
  process.stderr.write('\n');
396
396
  process.exit(0);
397
397
  });
398
+ program
399
+ .command('observe')
400
+ .description('Ingest observations from Claude Code sessions — kbot learns from what Claude does')
401
+ .option('--stats', 'Show observer statistics')
402
+ .option('--reset', 'Reset the observer log and cursor')
403
+ .action(async (opts) => {
404
+ const { ingestObservations, getObserverStats, getLogPath } = await import('./observer.js');
405
+ const chalk = (await import('chalk')).default;
406
+ if (opts.reset) {
407
+ const { existsSync, unlinkSync } = await import('node:fs');
408
+ const { join } = await import('node:path');
409
+ const { homedir } = await import('node:os');
410
+ const dir = join(homedir(), '.kbot', 'observer');
411
+ for (const f of ['session.jsonl', 'cursor.json', 'stats.json']) {
412
+ const p = join(dir, f);
413
+ if (existsSync(p))
414
+ unlinkSync(p);
415
+ }
416
+ printSuccess('Observer log reset.');
417
+ process.exit(0);
418
+ }
419
+ if (opts.stats) {
420
+ const stats = getObserverStats();
421
+ console.log();
422
+ console.log(chalk.hex('#6B5B95')(' ◉ kbot Observer'));
423
+ console.log(chalk.dim(` Log: ${getLogPath()}`));
424
+ console.log();
425
+ console.log(` Total observed: ${stats.totalObserved}`);
426
+ console.log(` Sessions observed: ${stats.sessionsObserved}`);
427
+ console.log(` Sequences learned: ${stats.sequencesLearned}`);
428
+ console.log(` Facts learned: ${stats.factsLearned}`);
429
+ console.log(` Last ingested: ${stats.lastIngested || 'never'}`);
430
+ if (Object.keys(stats.toolFrequency).length > 0) {
431
+ console.log();
432
+ console.log(chalk.bold(' Tool frequency:'));
433
+ const sorted = Object.entries(stats.toolFrequency).sort((a, b) => b[1] - a[1]).slice(0, 10);
434
+ for (const [tool, count] of sorted) {
435
+ console.log(` ${String(count).padStart(4)}x ${tool}`);
436
+ }
437
+ }
438
+ console.log();
439
+ process.exit(0);
440
+ }
441
+ // Default: ingest new observations
442
+ printInfo('Ingesting observations from Claude Code sessions...');
443
+ const result = await ingestObservations();
444
+ if (result.processed === 0) {
445
+ printInfo('No new observations to ingest.');
446
+ printInfo(`Log file: ${getLogPath()}`);
447
+ printInfo('The Claude Code PostToolUse hook writes here after every tool call.');
448
+ }
449
+ else {
450
+ printSuccess(`Ingested ${result.processed} tool calls from ${result.sessions.length} session(s)`);
451
+ if (result.patterns > 0)
452
+ printInfo(` Sequences learned: ${result.patterns}`);
453
+ if (result.facts > 0)
454
+ printInfo(` Facts learned: ${result.facts}`);
455
+ }
456
+ process.exit(0);
457
+ });
398
458
  program
399
459
  .command('doctor')
400
460
  .description('Diagnose your kbot setup — check everything is working')
@@ -1985,7 +2045,7 @@ async function main() {
1985
2045
  if (opts.quiet)
1986
2046
  setQuiet(true);
1987
2047
  // If a sub-command was run, we're done
1988
- if (['byok', 'auth', 'ide', 'local', 'ollama', 'kbot-local', 'pull', 'doctor', 'serve', 'agents', 'watch', 'voice', 'export', 'plugins', 'changelog', 'completions', 'automate', 'status', 'spec', 'a2a', 'init', 'email-agent', 'imessage-agent', 'consultation'].includes(program.args[0]))
2048
+ if (['byok', 'auth', 'ide', 'local', 'ollama', 'kbot-local', 'pull', 'doctor', 'serve', 'agents', 'watch', 'voice', 'export', 'plugins', 'changelog', 'completions', 'automate', 'status', 'spec', 'a2a', 'init', 'email-agent', 'imessage-agent', 'consultation', 'observe'].includes(program.args[0]))
1989
2049
  return;
1990
2050
  // Check for API key (BYOK or local provider)
1991
2051
  let byokActive = isByokEnabled();
@@ -2669,6 +2729,17 @@ async function startRepl(agentOpts, context, tier, byokActive = false, localActi
2669
2729
  printInfo(`${p.name}`);
2670
2730
  }
2671
2731
  const sessionCount = incrementSessions();
2732
+ // Seed knowledge on first run — give new users a head start
2733
+ if (sessionCount <= 2) {
2734
+ try {
2735
+ const { loadSeedKnowledge } = await import('./seed-knowledge.js');
2736
+ const seed = await loadSeedKnowledge();
2737
+ if (seed.seeded) {
2738
+ printInfo(`Loaded ${seed.patterns} patterns + ${seed.facts} knowledge entries from seed data`);
2739
+ }
2740
+ }
2741
+ catch { /* seed loading is non-critical */ }
2742
+ }
2672
2743
  // Three-tier memory: run synthesis on every 10th session (or first time with enough data)
2673
2744
  if (sessionCount % 10 === 0 || sessionCount === 1) {
2674
2745
  try {