@kernel.chat/kbot 3.20.1 → 3.21.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 +141 -1
- package/dist/cli.js.map +1 -1
- package/dist/discovery.d.ts +58 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +364 -0
- package/dist/discovery.js.map +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -360,6 +360,146 @@ 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
|
+
// ── Discovery Agent ──
|
|
364
|
+
const discoveryCmd = program
|
|
365
|
+
.command('discovery')
|
|
366
|
+
.description('Autonomous outreach agent — finds conversations, drafts responses, posts for you');
|
|
367
|
+
discoveryCmd
|
|
368
|
+
.command('start')
|
|
369
|
+
.description('Start the discovery loop — scans HN, GitHub, Reddit and posts autonomously')
|
|
370
|
+
.option('--dry-run', 'Find and draft but don\'t post')
|
|
371
|
+
.option('--interval <minutes>', 'Poll interval in minutes', '60')
|
|
372
|
+
.option('--model <model>', 'Ollama model for analysis', 'qwen2.5-coder:32b')
|
|
373
|
+
.action(async (opts) => {
|
|
374
|
+
const { loadConfig, saveConfig, runDiscoveryCycle } = await import('./discovery.js');
|
|
375
|
+
const chalk = (await import('chalk')).default;
|
|
376
|
+
const readline = await import('node:readline');
|
|
377
|
+
let config = loadConfig();
|
|
378
|
+
// First run — interactive setup
|
|
379
|
+
if (!config) {
|
|
380
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
381
|
+
const ask = (q) => new Promise(r => rl.question(q, r));
|
|
382
|
+
console.log();
|
|
383
|
+
console.log(chalk.hex('#6B5B95')(' ◉ kbot Discovery — First Time Setup'));
|
|
384
|
+
console.log();
|
|
385
|
+
const name = await ask(' Project name: ');
|
|
386
|
+
const desc = await ask(' One-line description: ');
|
|
387
|
+
const topicsRaw = await ask(' Topics to search (comma-separated): ');
|
|
388
|
+
const hnUser = await ask(' HN username (leave blank to skip): ');
|
|
389
|
+
let hnCookie = '';
|
|
390
|
+
if (hnUser) {
|
|
391
|
+
hnCookie = await ask(' HN cookie string (from browser dev tools): ');
|
|
392
|
+
}
|
|
393
|
+
rl.close();
|
|
394
|
+
config = {
|
|
395
|
+
projectName: name || 'my-project',
|
|
396
|
+
projectDescription: desc || '',
|
|
397
|
+
topics: topicsRaw.split(',').map(t => t.trim()).filter(Boolean),
|
|
398
|
+
hnUsername: hnUser || undefined,
|
|
399
|
+
hnCookie: hnCookie || undefined,
|
|
400
|
+
githubToken: undefined,
|
|
401
|
+
maxPostsPerCycle: 2,
|
|
402
|
+
pollIntervalMinutes: Number(opts.interval || 60),
|
|
403
|
+
dryRun: opts.dryRun || false,
|
|
404
|
+
ollamaModel: opts.model || 'qwen2.5-coder:32b',
|
|
405
|
+
ollamaUrl: 'http://localhost:11434',
|
|
406
|
+
};
|
|
407
|
+
saveConfig(config);
|
|
408
|
+
printSuccess('Config saved to ~/.kbot/discovery/config.json');
|
|
409
|
+
}
|
|
410
|
+
// Override with flags
|
|
411
|
+
config.dryRun = opts.dryRun || false;
|
|
412
|
+
config.pollIntervalMinutes = Number(opts.interval || config.pollIntervalMinutes);
|
|
413
|
+
config.ollamaModel = opts.model || config.ollamaModel;
|
|
414
|
+
console.log();
|
|
415
|
+
console.log(chalk.hex('#6B5B95')(' ◉ kbot Discovery Agent'));
|
|
416
|
+
console.log(chalk.dim(` Project: ${config.projectName}`));
|
|
417
|
+
console.log(chalk.dim(` Topics: ${config.topics.join(', ')}`));
|
|
418
|
+
console.log(chalk.dim(` Model: ${config.ollamaModel}`));
|
|
419
|
+
console.log(chalk.dim(` Mode: ${config.dryRun ? 'DRY RUN (no posting)' : 'LIVE (will post)'}`));
|
|
420
|
+
console.log(chalk.dim(` Interval: ${config.pollIntervalMinutes}m`));
|
|
421
|
+
console.log();
|
|
422
|
+
// Initial cycle
|
|
423
|
+
await runDiscoveryCycle(config);
|
|
424
|
+
// Poll
|
|
425
|
+
setInterval(() => runDiscoveryCycle(config), config.pollIntervalMinutes * 60 * 1000);
|
|
426
|
+
console.log(`Polling every ${config.pollIntervalMinutes}m. Ctrl+C to stop.`);
|
|
427
|
+
await new Promise(() => { }); // keep alive
|
|
428
|
+
});
|
|
429
|
+
discoveryCmd
|
|
430
|
+
.command('status')
|
|
431
|
+
.description('Show discovery agent status and stats')
|
|
432
|
+
.action(async () => {
|
|
433
|
+
const { getDiscoveryState, loadConfig } = await import('./discovery.js');
|
|
434
|
+
const chalk = (await import('chalk')).default;
|
|
435
|
+
const config = loadConfig();
|
|
436
|
+
const state = getDiscoveryState();
|
|
437
|
+
console.log();
|
|
438
|
+
console.log(chalk.hex('#6B5B95')(' ◉ kbot Discovery Status'));
|
|
439
|
+
if (config) {
|
|
440
|
+
console.log(chalk.dim(` Project: ${config.projectName}`));
|
|
441
|
+
console.log(chalk.dim(` Topics: ${config.topics.join(', ')}`));
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
printWarn(' Not configured. Run: kbot discovery start');
|
|
445
|
+
}
|
|
446
|
+
console.log();
|
|
447
|
+
console.log(` Scans: ${state.totalScans}`);
|
|
448
|
+
console.log(` Found: ${state.totalFound}`);
|
|
449
|
+
console.log(` Posted: ${state.totalPosted}`);
|
|
450
|
+
console.log(` Skipped: ${state.totalSkipped}`);
|
|
451
|
+
console.log(` Last: ${state.lastScan || 'never'}`);
|
|
452
|
+
if (state.posts.length > 0) {
|
|
453
|
+
console.log();
|
|
454
|
+
console.log(chalk.bold(' Recent posts:'));
|
|
455
|
+
for (const p of state.posts.slice(-5).reverse()) {
|
|
456
|
+
const icon = p.success ? chalk.green('✓') : chalk.red('✗');
|
|
457
|
+
console.log(` ${icon} [${p.platform}] ${p.title.slice(0, 50)}`);
|
|
458
|
+
if (p.error)
|
|
459
|
+
console.log(chalk.dim(` ${p.error}`));
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
console.log();
|
|
463
|
+
process.exit(0);
|
|
464
|
+
});
|
|
465
|
+
discoveryCmd
|
|
466
|
+
.command('log')
|
|
467
|
+
.description('Show recent discovery activity')
|
|
468
|
+
.option('-n, --lines <n>', 'Number of lines to show', '20')
|
|
469
|
+
.action(async (opts) => {
|
|
470
|
+
const { getRecentLog } = await import('./discovery.js');
|
|
471
|
+
console.log(getRecentLog(Number(opts.lines || 20)));
|
|
472
|
+
process.exit(0);
|
|
473
|
+
});
|
|
474
|
+
discoveryCmd
|
|
475
|
+
.command('auth')
|
|
476
|
+
.description('Configure platform credentials for posting')
|
|
477
|
+
.action(async () => {
|
|
478
|
+
const { loadConfig, saveConfig } = await import('./discovery.js');
|
|
479
|
+
const readline = await import('node:readline');
|
|
480
|
+
let config = loadConfig();
|
|
481
|
+
if (!config) {
|
|
482
|
+
printError('Run `kbot discovery start` first to create config.');
|
|
483
|
+
process.exit(1);
|
|
484
|
+
}
|
|
485
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
486
|
+
const ask = (q) => new Promise(r => rl.question(q, r));
|
|
487
|
+
console.log();
|
|
488
|
+
printInfo('Configure platform credentials');
|
|
489
|
+
console.log();
|
|
490
|
+
const hnUser = await ask(` HN username [${config.hnUsername || 'none'}]: `);
|
|
491
|
+
if (hnUser)
|
|
492
|
+
config.hnUsername = hnUser;
|
|
493
|
+
if (config.hnUsername) {
|
|
494
|
+
const hnCookie = await ask(' HN cookie (from browser): ');
|
|
495
|
+
if (hnCookie)
|
|
496
|
+
config.hnCookie = hnCookie;
|
|
497
|
+
}
|
|
498
|
+
rl.close();
|
|
499
|
+
saveConfig(config);
|
|
500
|
+
printSuccess('Credentials updated.');
|
|
501
|
+
process.exit(0);
|
|
502
|
+
});
|
|
363
503
|
program
|
|
364
504
|
.command('init')
|
|
365
505
|
.description('Set up kbot for this project — detects stack, creates tools, writes config (60 seconds)')
|
|
@@ -2045,7 +2185,7 @@ async function main() {
|
|
|
2045
2185
|
if (opts.quiet)
|
|
2046
2186
|
setQuiet(true);
|
|
2047
2187
|
// If a sub-command was run, we're done
|
|
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]))
|
|
2188
|
+
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', 'discovery'].includes(program.args[0]))
|
|
2049
2189
|
return;
|
|
2050
2190
|
// Check for API key (BYOK or local provider)
|
|
2051
2191
|
let byokActive = isByokEnabled();
|