@kernel.chat/kbot 3.16.0 → 3.17.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
@@ -360,6 +360,40 @@ async function main() {
360
360
  printInfo('Download: kbot models pull <name>');
361
361
  printInfo('Or use any HuggingFace GGUF: kbot models pull hf:user/repo:file.gguf');
362
362
  });
363
+ program
364
+ .command('init')
365
+ .description('Set up kbot for this project — detects stack, creates tools, writes config (60 seconds)')
366
+ .option('--force', 'Overwrite existing .kbot.json')
367
+ .action(async (opts) => {
368
+ const { existsSync } = await import('node:fs');
369
+ const { join } = await import('node:path');
370
+ const { initProject, formatInitReport } = await import('./init.js');
371
+ const chalk = (await import('chalk')).default;
372
+ const AMETHYST = chalk.hex('#6B5B95');
373
+ const root = process.cwd();
374
+ // Check for existing config
375
+ if (!opts.force && existsSync(join(root, '.kbot.json'))) {
376
+ printWarn('This project already has a .kbot.json. Use --force to overwrite.');
377
+ return;
378
+ }
379
+ process.stderr.write('\n');
380
+ process.stderr.write(` ${AMETHYST('◉')} ${chalk.bold('kbot init')} — scanning project...\n\n`);
381
+ const config = await initProject(root);
382
+ process.stderr.write(formatInitReport(config) + '\n');
383
+ process.stderr.write('\n');
384
+ process.stderr.write(` ${chalk.green('✓')} Config written to ${chalk.dim('.kbot.json')}\n`);
385
+ if (config.forgedTools.length > 0) {
386
+ process.stderr.write(` ${chalk.green('✓')} ${config.forgedTools.length} tools forged: ${chalk.dim(config.forgedTools.join(', '))}\n`);
387
+ }
388
+ process.stderr.write('\n');
389
+ process.stderr.write(` ${chalk.bold('Try now:')}\n`);
390
+ process.stderr.write(` ${chalk.cyan('kbot')} "explain this project"\n`);
391
+ process.stderr.write(` ${chalk.cyan('kbot')} "find the top bug"\n`);
392
+ if (config.commands.test) {
393
+ process.stderr.write(` ${chalk.cyan('kbot')} "run the tests and fix any failures"\n`);
394
+ }
395
+ process.stderr.write('\n');
396
+ });
363
397
  program
364
398
  .command('doctor')
365
399
  .description('Diagnose your kbot setup — check everything is working')
@@ -1402,7 +1436,8 @@ async function main() {
1402
1436
  .description('Start the email agent — polls for new emails and responds via Ollama')
1403
1437
  .option('--model <model>', 'Ollama model to use', 'qwen2.5-coder:32b')
1404
1438
  .option('--interval <ms>', 'Poll interval in milliseconds', '15000')
1405
- .option('--users <emails>', 'Comma-separated list of email addresses to monitor')
1439
+ .option('--users <emails>', 'Comma-separated email addresses to monitor (omit for open mode — all inbound)')
1440
+ .option('--open', 'Open mode — respond to ALL inbound emails (no whitelist)')
1406
1441
  .action(async (opts) => {
1407
1442
  const { startEmailAgent } = await import('./email-agent.js');
1408
1443
  const { existsSync, readFileSync } = await import('node:fs');
@@ -1428,15 +1463,16 @@ async function main() {
1428
1463
  return;
1429
1464
  }
1430
1465
  const agentUsers = opts.users?.split(',').map(e => e.trim()) || [];
1431
- if (agentUsers.length === 0) {
1432
- printError('No users specified. Use --users email1,email2 to set monitored addresses.');
1466
+ if (agentUsers.length === 0 && !opts.open) {
1467
+ printError('No users specified. Use --users email1,email2 or --open for all inbound.');
1433
1468
  return;
1434
1469
  }
1435
1470
  const chalk = (await import('chalk')).default;
1471
+ const mode = agentUsers.length === 0 ? 'OPEN (all inbound)' : `${agentUsers.length} users`;
1436
1472
  console.log();
1437
1473
  console.log(chalk.hex('#6B5B95')(' ◉ Kernel Email Agent'));
1438
1474
  console.log(chalk.dim(` Model: ${opts.model || 'qwen2.5-coder:32b'}`));
1439
- console.log(chalk.dim(` Monitoring: ${agentUsers.join(', ')}`));
1475
+ console.log(chalk.dim(` Mode: ${mode}`));
1440
1476
  console.log(chalk.dim(` Poll interval: ${Number(opts.interval || 15000) / 1000}s`));
1441
1477
  console.log();
1442
1478
  await startEmailAgent({
@@ -1469,7 +1505,7 @@ async function main() {
1469
1505
  }
1470
1506
  }
1471
1507
  else {
1472
- printInfo('Email agent is not running. Start with: kbot email-agent start --users email1,email2');
1508
+ printInfo('Email agent is not running. Start with: kbot email-agent start --open');
1473
1509
  }
1474
1510
  });
1475
1511
  // ── iMessage Agent ──
@@ -1627,24 +1663,40 @@ async function main() {
1627
1663
  });
1628
1664
  program
1629
1665
  .command('audit <repo>')
1630
- .description('Full audit of any GitHub repository — security, quality, docs, DevOps')
1631
- .option('--share', 'Share the audit report as a GitHub Gist')
1666
+ .description('Full audit of any GitHub repository — security, quality, docs, DevOps. Generates shareable report with badge.')
1667
+ .option('--share', 'Auto-share the report as a public GitHub Gist')
1668
+ .option('--json', 'Output raw JSON')
1669
+ .option('--badge', 'Print only the badge markdown (for adding to READMEs)')
1632
1670
  .action(async (repo, auditOpts) => {
1633
1671
  const { auditRepo, formatAuditReport } = await import('./tools/audit.js');
1634
1672
  printInfo(`Auditing ${repo}...`);
1635
1673
  try {
1636
1674
  const result = await auditRepo(repo);
1675
+ if (auditOpts.json) {
1676
+ console.log(JSON.stringify(result, null, 2));
1677
+ return;
1678
+ }
1679
+ if (auditOpts.badge) {
1680
+ const pct = Math.round((result.score / result.maxScore) * 100);
1681
+ const badgeColor = pct >= 80 ? 'brightgreen' : pct >= 60 ? 'yellow' : 'red';
1682
+ console.log(`[![kbot audit: ${result.grade}](https://img.shields.io/badge/kbot_audit-${result.grade}_(${pct}%25)-${badgeColor})](https://www.npmjs.com/package/@kernel.chat/kbot)`);
1683
+ return;
1684
+ }
1637
1685
  const report = formatAuditReport(result);
1638
1686
  console.log(report);
1687
+ // Auto-share as gist
1639
1688
  if (auditOpts.share) {
1640
- const { shareConversation } = await import('./share.js');
1641
- // Save as a pseudo-conversation for sharing
1642
1689
  printInfo('Sharing audit report...');
1643
1690
  try {
1644
1691
  const { createGist } = await import('./share.js');
1645
- const url = createGist(report, `kbot-audit-${repo.replace('/', '-')}.md`, `kbot Audit: ${repo}`, true);
1646
- if (url?.startsWith('http'))
1692
+ const url = createGist(report, `kbot-audit-${repo.replace('/', '-')}.md`, `kbot Audit: ${repo} — Grade ${result.grade}`, true);
1693
+ if (url?.startsWith('http')) {
1647
1694
  printSuccess(`Shared! ${url}`);
1695
+ printInfo(`Badge for ${repo}'s README:`);
1696
+ const pct = Math.round((result.score / result.maxScore) * 100);
1697
+ const badgeColor = pct >= 80 ? 'brightgreen' : pct >= 60 ? 'yellow' : 'red';
1698
+ printInfo(` [![kbot audit: ${result.grade}](https://img.shields.io/badge/kbot_audit-${result.grade}_(${pct}%25)-${badgeColor})](${url})`);
1699
+ }
1648
1700
  }
1649
1701
  catch {
1650
1702
  printInfo('Could not create Gist. Install GitHub CLI: brew install gh');