@cpretzinger/boss-claude 1.0.0 → 1.0.2

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 (87) hide show
  1. package/README.md +304 -1
  2. package/bin/boss-claude.js +1138 -0
  3. package/bin/commands/mode.js +250 -0
  4. package/bin/onyx-guard.js +259 -0
  5. package/bin/onyx-guard.sh +251 -0
  6. package/bin/prompts.js +284 -0
  7. package/bin/rollback.js +85 -0
  8. package/bin/setup-wizard.js +492 -0
  9. package/config/.env.example +17 -0
  10. package/lib/README.md +83 -0
  11. package/lib/agent-logger.js +61 -0
  12. package/lib/agents/memory-engineers/github-memory-engineer.js +251 -0
  13. package/lib/agents/memory-engineers/postgres-memory-engineer.js +633 -0
  14. package/lib/agents/memory-engineers/qdrant-memory-engineer.js +358 -0
  15. package/lib/agents/memory-engineers/redis-memory-engineer.js +383 -0
  16. package/lib/agents/memory-supervisor.js +526 -0
  17. package/lib/agents/registry.js +135 -0
  18. package/lib/auto-monitor.js +131 -0
  19. package/lib/checkpoint-hook.js +112 -0
  20. package/lib/checkpoint.js +319 -0
  21. package/lib/commentator.js +213 -0
  22. package/lib/context-scribe.js +120 -0
  23. package/lib/delegation-strategies.js +326 -0
  24. package/lib/hierarchy-validator.js +643 -0
  25. package/lib/index.js +15 -0
  26. package/lib/init-with-mode.js +261 -0
  27. package/lib/init.js +44 -6
  28. package/lib/memory-result-aggregator.js +252 -0
  29. package/lib/memory.js +35 -7
  30. package/lib/mode-enforcer.js +473 -0
  31. package/lib/onyx-banner.js +169 -0
  32. package/lib/onyx-identity.js +214 -0
  33. package/lib/onyx-monitor.js +381 -0
  34. package/lib/onyx-reminder.js +188 -0
  35. package/lib/onyx-tool-interceptor.js +341 -0
  36. package/lib/onyx-wrapper.js +315 -0
  37. package/lib/orchestrator-gate.js +334 -0
  38. package/lib/output-formatter.js +296 -0
  39. package/lib/postgres.js +1 -1
  40. package/lib/prompt-injector.js +220 -0
  41. package/lib/prompts.js +532 -0
  42. package/lib/session.js +153 -6
  43. package/lib/setup/README.md +187 -0
  44. package/lib/setup/env-manager.js +785 -0
  45. package/lib/setup/error-recovery.js +630 -0
  46. package/lib/setup/explain-scopes.js +385 -0
  47. package/lib/setup/github-instructions.js +333 -0
  48. package/lib/setup/github-repo.js +254 -0
  49. package/lib/setup/import-credentials.js +498 -0
  50. package/lib/setup/index.js +62 -0
  51. package/lib/setup/init-postgres.js +785 -0
  52. package/lib/setup/init-redis.js +456 -0
  53. package/lib/setup/integration-test.js +652 -0
  54. package/lib/setup/progress.js +357 -0
  55. package/lib/setup/rollback.js +670 -0
  56. package/lib/setup/rollback.test.js +452 -0
  57. package/lib/setup/setup-with-rollback.example.js +351 -0
  58. package/lib/setup/summary.js +400 -0
  59. package/lib/setup/test-github-setup.js +10 -0
  60. package/lib/setup/test-postgres-init.js +98 -0
  61. package/lib/setup/verify-setup.js +102 -0
  62. package/lib/task-agent-worker.js +235 -0
  63. package/lib/token-monitor.js +466 -0
  64. package/lib/tool-wrapper-integration.js +369 -0
  65. package/lib/tool-wrapper.js +387 -0
  66. package/lib/validators/README.md +497 -0
  67. package/lib/validators/config.js +583 -0
  68. package/lib/validators/config.test.js +175 -0
  69. package/lib/validators/github.js +310 -0
  70. package/lib/validators/github.test.js +61 -0
  71. package/lib/validators/index.js +15 -0
  72. package/lib/validators/postgres.js +525 -0
  73. package/package.json +98 -13
  74. package/scripts/benchmark-memory.js +433 -0
  75. package/scripts/check-secrets.sh +12 -0
  76. package/scripts/fetch-todos.mjs +148 -0
  77. package/scripts/graceful-shutdown.sh +156 -0
  78. package/scripts/install-onyx-hooks.js +373 -0
  79. package/scripts/install.js +119 -18
  80. package/scripts/redis-monitor.js +284 -0
  81. package/scripts/redis-setup.js +412 -0
  82. package/scripts/test-memory-retrieval.js +201 -0
  83. package/scripts/validate-exports.js +68 -0
  84. package/scripts/validate-package.js +120 -0
  85. package/scripts/verify-onyx-deployment.js +309 -0
  86. package/scripts/verify-redis-deployment.js +354 -0
  87. package/scripts/verify-redis-init.js +219 -0
@@ -6,6 +6,54 @@ import { loadIdentity, updateIdentity } from '../lib/identity.js';
6
6
  import { loadSession, saveSession } from '../lib/session.js';
7
7
  import { searchMemory, saveMemory } from '../lib/memory.js';
8
8
  import { getStatus } from '../lib/init.js';
9
+ import { importCredentials, validateCredentials, listSources } from '../lib/setup/import-credentials.js';
10
+ import {
11
+ getRedisStats,
12
+ resetRedis,
13
+ verifyRedis,
14
+ initializeRedis,
15
+ printInitResults
16
+ } from '../lib/setup/init-redis.js';
17
+ import { runIntegrationTests } from '../lib/setup/integration-test.js';
18
+ import { validateConfig, printReport } from '../lib/validators/config.js';
19
+ import { LOG_FILE } from '../lib/agent-logger.js';
20
+ import { formatLogDetails } from '../lib/output-formatter.js';
21
+ import hierarchyValidator from '../lib/hierarchy-validator.js';
22
+ import { AGENT_HIERARCHY } from '../lib/agents/registry.js';
23
+ import onyxReminder from '../lib/onyx-reminder.js';
24
+ import {
25
+ trackDelegation,
26
+ trackDirectAction,
27
+ getDelegationStats,
28
+ getRecentEvents,
29
+ setAlertThreshold,
30
+ getAlertThreshold,
31
+ resetTracking,
32
+ generateReport,
33
+ getFormattedStatus,
34
+ ALERT_LOG
35
+ } from '../lib/onyx-monitor.js';
36
+ import {
37
+ getCheckpointStatus,
38
+ recordCheckpoint,
39
+ getCheckpointHistory,
40
+ getDelegationEfficiency,
41
+ resetCheckpoint,
42
+ exportCheckpointData,
43
+ formatCheckpointPrompt
44
+ } from '../lib/checkpoint.js';
45
+ import { modeCommand } from './commands/mode.js';
46
+ import { spawn } from 'child_process';
47
+ import dotenv from 'dotenv';
48
+ import { join } from 'path';
49
+ import os from 'os';
50
+ import { existsSync } from 'fs';
51
+
52
+ // Load environment variables
53
+ const envPath = join(os.homedir(), '.boss-claude', '.env');
54
+ if (existsSync(envPath)) {
55
+ dotenv.config({ path: envPath });
56
+ }
9
57
 
10
58
  const program = new Command();
11
59
 
@@ -14,6 +62,39 @@ program
14
62
  .description('Boss Claude - Gamified AI assistant with persistent memory')
15
63
  .version('1.0.0');
16
64
 
65
+ program
66
+ .command('setup')
67
+ .description('Auto-detect and import credentials')
68
+ .option('-l, --list', 'List all credential sources without importing')
69
+ .option('-v, --validate', 'Validate existing credentials')
70
+ .action(async (options) => {
71
+ try {
72
+ if (options.list) {
73
+ // List all sources
74
+ await listSources();
75
+ } else if (options.validate) {
76
+ // Validate existing credentials
77
+ console.log(chalk.blue('\n🔐 Validating credentials...\n'));
78
+ const result = await validateCredentials();
79
+
80
+ if (result.valid) {
81
+ console.log(chalk.green('✅ All credentials are valid!\n'));
82
+ } else {
83
+ console.log(chalk.red('❌ Credential validation failed:\n'));
84
+ result.errors.forEach(error => console.log(chalk.red(` • ${error}`)));
85
+ console.log();
86
+ process.exit(1);
87
+ }
88
+ } else {
89
+ // Import credentials
90
+ await importCredentials();
91
+ }
92
+ } catch (error) {
93
+ console.error(chalk.red('❌ Setup failed:'), error.message);
94
+ process.exit(1);
95
+ }
96
+ });
97
+
17
98
  program
18
99
  .command('init')
19
100
  .description('Initialize Boss Claude in current repository')
@@ -110,6 +191,18 @@ program
110
191
  console.log(` XP Earned: ${chalk.cyan('+' + session.xp_earned)}`);
111
192
  console.log(` Tokens Banked: ${chalk.magenta('+' + session.tokens_earned.toLocaleString())}\n`);
112
193
 
194
+ // Show efficiency breakdown if available
195
+ if (session.efficiency) {
196
+ const eff = session.efficiency;
197
+ console.log(chalk.bold('⚡ Efficiency Breakdown:'));
198
+ console.log(` 🎺 ONYX Tokens: ${chalk.dim(eff.onyx_tokens.toLocaleString())}`);
199
+ console.log(` 🎻 Agent Tokens: ${chalk.green(eff.agent_tokens.toLocaleString())}`);
200
+ console.log(` 📈 Efficiency Ratio: ${chalk.yellow(eff.ratio)}`);
201
+ console.log(` 🎯 Delegations: ${chalk.blue(eff.delegations)}`);
202
+ console.log(chalk.bold(' 💎 Bonus XP: ') + chalk.cyan(`+${eff.efficiency_bonus}`) + chalk.dim(' (efficiency) ') +
203
+ chalk.cyan(`+${eff.delegation_bonus}`) + chalk.dim(' (delegation)\n'));
204
+ }
205
+
113
206
  } catch (error) {
114
207
  console.error(chalk.red('❌ Error saving session:'), error.message);
115
208
  process.exit(1);
@@ -147,4 +240,1049 @@ program
147
240
  }
148
241
  });
149
242
 
243
+ program
244
+ .command('test')
245
+ .description('Run integration tests to verify system health')
246
+ .action(async () => {
247
+ try {
248
+ await runIntegrationTests();
249
+ } catch (error) {
250
+ console.error(chalk.red('❌ Integration tests failed:'), error.message);
251
+ process.exit(1);
252
+ }
253
+ });
254
+
255
+ program
256
+ .command('validate')
257
+ .description('Validate ~/.boss-claude/.env configuration')
258
+ .option('--skip-optional', 'Skip validation of optional variables')
259
+ .action(async (options) => {
260
+ try {
261
+ const report = await validateConfig({
262
+ includeOptional: !options.skipOptional
263
+ });
264
+
265
+ printReport(report);
266
+
267
+ if (!report.valid) {
268
+ process.exit(1);
269
+ }
270
+ } catch (error) {
271
+ console.error(chalk.red('❌ Validation failed:'), error.message);
272
+ process.exit(1);
273
+ }
274
+ });
275
+
276
+ // Redis management commands
277
+ program
278
+ .command('redis:stats')
279
+ .description('Show Redis statistics and key counts')
280
+ .action(async () => {
281
+ try {
282
+ if (!process.env.REDIS_URL) {
283
+ console.error(chalk.red('❌ REDIS_URL not configured. Run: boss-claude setup\n'));
284
+ process.exit(1);
285
+ }
286
+
287
+ console.log(chalk.blue('\n📊 Redis Statistics\n'));
288
+
289
+ const stats = await getRedisStats(process.env.REDIS_URL);
290
+
291
+ if (stats.identity) {
292
+ console.log(chalk.bold('Boss Identity:'));
293
+ console.log(` Level: ${chalk.yellow(stats.identity.level)}`);
294
+ console.log(` XP: ${chalk.cyan(stats.identity.xp)}`);
295
+ console.log(` Token Bank: ${chalk.magenta(stats.identity.token_bank.toLocaleString())}`);
296
+ console.log(` Total Sessions: ${chalk.blue(stats.identity.total_sessions)}`);
297
+ console.log(` Repos Managed: ${chalk.green(stats.identity.repos_managed)}\n`);
298
+ }
299
+
300
+ console.log(chalk.bold('Data Structures:'));
301
+ console.log(` Session History: ${chalk.cyan(stats.totalSessions)} sessions`);
302
+ console.log(` Tracked Repos: ${chalk.green(stats.totalRepos)} repositories`);
303
+ console.log(` Active Sessions: ${chalk.yellow(stats.activeSessions)}`);
304
+ console.log(` Leaderboard Size: ${chalk.blue(stats.leaderboardSize)} users`);
305
+ console.log(` Cache Keys: ${chalk.magenta(stats.cacheKeys)}\n`);
306
+
307
+ if (Object.keys(stats.achievements).length > 0) {
308
+ console.log(chalk.bold('Achievements:'));
309
+ Object.entries(stats.achievements).forEach(([user, achievements]) => {
310
+ console.log(` ${chalk.cyan(user)}: ${achievements.length > 0 ? achievements.join(', ') : chalk.dim('none')}`);
311
+ });
312
+ console.log();
313
+ }
314
+
315
+ } catch (error) {
316
+ console.error(chalk.red('❌ Error fetching Redis stats:'), error.message);
317
+ process.exit(1);
318
+ }
319
+ });
320
+
321
+ program
322
+ .command('redis:verify')
323
+ .description('Verify Redis connection and data structures')
324
+ .action(async () => {
325
+ try {
326
+ if (!process.env.REDIS_URL) {
327
+ console.error(chalk.red('❌ REDIS_URL not configured. Run: boss-claude setup\n'));
328
+ process.exit(1);
329
+ }
330
+
331
+ console.log(chalk.blue('\n🔍 Verifying Redis...\n'));
332
+
333
+ const result = await verifyRedis(process.env.REDIS_URL);
334
+
335
+ if (!result.connected) {
336
+ console.log(chalk.red('✗ Connection Failed'));
337
+ console.log(chalk.dim(` Error: ${result.error}\n`));
338
+ process.exit(1);
339
+ }
340
+
341
+ console.log(chalk.green('✓ Connection Successful'));
342
+ console.log(chalk.dim(` Redis Version: ${result.version}\n`));
343
+
344
+ console.log(chalk.bold('Data Structures:'));
345
+ console.log(result.structures.identity ?
346
+ chalk.green('✓ boss:identity exists') :
347
+ chalk.red('✗ boss:identity missing')
348
+ );
349
+ console.log(` ${result.structures.sessionHistory > 0 ? chalk.green('✓') : chalk.yellow('○')} boss:sessions:history (${result.structures.sessionHistory} sessions)`);
350
+ console.log(` ${result.structures.leaderboard > 0 ? chalk.green('✓') : chalk.yellow('○')} boss:leaderboard:xp (${result.structures.leaderboard} users)\n`);
351
+
352
+ if (result.healthCheck.passed) {
353
+ console.log(chalk.green('✓ All health checks passed\n'));
354
+ } else {
355
+ console.log(chalk.red('✗ Health check failed\n'));
356
+ Object.entries(result.healthCheck.details).forEach(([key, value]) => {
357
+ const status = value === 'OK' ? chalk.green('✓') : chalk.red('✗');
358
+ console.log(` ${status} ${key}: ${chalk.dim(value)}`);
359
+ });
360
+ console.log();
361
+ }
362
+
363
+ } catch (error) {
364
+ console.error(chalk.red('❌ Verification failed:'), error.message);
365
+ process.exit(1);
366
+ }
367
+ });
368
+
369
+ program
370
+ .command('redis:init')
371
+ .description('Initialize or repair Redis data structures')
372
+ .option('-f, --force', 'Force re-initialization even if data exists')
373
+ .action(async (options) => {
374
+ try {
375
+ if (!process.env.REDIS_URL) {
376
+ console.error(chalk.red('❌ REDIS_URL not configured. Run: boss-claude setup\n'));
377
+ process.exit(1);
378
+ }
379
+
380
+ if (!process.env.GITHUB_USER) {
381
+ console.error(chalk.red('❌ GITHUB_USER not configured. Run: boss-claude setup\n'));
382
+ process.exit(1);
383
+ }
384
+
385
+ console.log(chalk.blue('\n🔧 Initializing Redis...\n'));
386
+
387
+ if (options.force) {
388
+ console.log(chalk.yellow('⚠️ Force mode: Will overwrite existing data\n'));
389
+ }
390
+
391
+ const results = await initializeRedis(
392
+ process.env.REDIS_URL,
393
+ process.env.GITHUB_USER,
394
+ options.force
395
+ );
396
+
397
+ printInitResults(results, process.env.GITHUB_USER);
398
+
399
+ if (results.healthCheck.passed) {
400
+ console.log(chalk.green('✓ Redis initialization successful!\n'));
401
+ } else {
402
+ console.log(chalk.yellow('⚠️ Initialization completed with warnings\n'));
403
+ }
404
+
405
+ } catch (error) {
406
+ console.error(chalk.red('❌ Initialization failed:'), error.message);
407
+ process.exit(1);
408
+ }
409
+ });
410
+
411
+ program
412
+ .command('redis:reset')
413
+ .description('Reset Redis to initial state (WARNING: Destructive!)')
414
+ .option('--confirm', 'Skip confirmation prompt')
415
+ .action(async (options) => {
416
+ try {
417
+ if (!process.env.REDIS_URL) {
418
+ console.error(chalk.red('❌ REDIS_URL not configured. Run: boss-claude setup\n'));
419
+ process.exit(1);
420
+ }
421
+
422
+ if (!process.env.GITHUB_USER) {
423
+ console.error(chalk.red('❌ GITHUB_USER not configured. Run: boss-claude setup\n'));
424
+ process.exit(1);
425
+ }
426
+
427
+ console.log(chalk.red('\n⚠️ WARNING: This will delete ALL Boss Claude data in Redis!\n'));
428
+
429
+ if (!options.confirm) {
430
+ const { confirm } = await import('./prompts.js');
431
+ const shouldContinue = await confirm('Are you absolutely sure?', false);
432
+
433
+ if (!shouldContinue) {
434
+ console.log(chalk.yellow('\nReset cancelled\n'));
435
+ process.exit(0);
436
+ }
437
+ }
438
+
439
+ console.log(chalk.blue('\n🔄 Resetting Redis...\n'));
440
+
441
+ const results = await resetRedis(process.env.REDIS_URL, process.env.GITHUB_USER);
442
+
443
+ printInitResults(results, process.env.GITHUB_USER);
444
+
445
+ console.log(chalk.green('✓ Redis reset complete!\n'));
446
+ console.log(chalk.dim('All data has been deleted and structures re-initialized\n'));
447
+
448
+ } catch (error) {
449
+ console.error(chalk.red('❌ Reset failed:'), error.message);
450
+ process.exit(1);
451
+ }
452
+ });
453
+
454
+ program
455
+ .command('watch')
456
+ .description('Watch agent activity in real-time (companion window)')
457
+ .action(() => {
458
+ console.log(chalk.blue('\n👁️ Boss Claude Agent Monitor\n'));
459
+ console.log(chalk.dim(`Watching: ${LOG_FILE}`));
460
+ console.log(chalk.dim('Press Ctrl+C to stop\n'));
461
+ console.log(chalk.gray('─'.repeat(80)));
462
+
463
+ // Use tail -f to follow the log file
464
+ const tail = spawn('tail', ['-f', '-n', '20', LOG_FILE], {
465
+ stdio: ['ignore', 'pipe', 'inherit']
466
+ });
467
+
468
+ // Format and colorize output
469
+ tail.stdout.on('data', (data) => {
470
+ const lines = data.toString().split('\n');
471
+ lines.forEach(line => {
472
+ if (!line.trim()) return;
473
+
474
+ // Parse log format: [timestamp] EVENT: Agent - Details
475
+ const match = line.match(/\[(.*?)\] (.*?): (.*?)(?:\s-\s(.*))?$/);
476
+ if (match) {
477
+ const [, timestamp, event, agent, details] = match;
478
+ const time = new Date(timestamp).toLocaleTimeString();
479
+
480
+ let eventColor = chalk.gray;
481
+ if (event === 'START') eventColor = chalk.cyan;
482
+ else if (event === 'COMPLETE') eventColor = chalk.green;
483
+ else if (event === 'ERROR') eventColor = chalk.red;
484
+
485
+ // Format details with intelligent line wrapping
486
+ let formattedDetails = '';
487
+ if (details) {
488
+ const wrappedDetails = formatLogDetails(details, {
489
+ multiline: true,
490
+ continuationPrefix: ' ' // Align with agent name
491
+ });
492
+ formattedDetails = chalk.dim(' - ' + wrappedDetails);
493
+ }
494
+
495
+ const formatted = `${chalk.dim(time)} ${eventColor(event.padEnd(10))} ${chalk.bold(agent)}${formattedDetails}`;
496
+ console.log(formatted);
497
+ } else {
498
+ // Fallback for non-matching lines
499
+ console.log(chalk.gray(line));
500
+ }
501
+ });
502
+ });
503
+
504
+ tail.on('error', (err) => {
505
+ if (err.code === 'ENOENT') {
506
+ console.error(chalk.red('\n❌ Log file not found. Agent activity will be logged here once tasks start.\n'));
507
+ console.log(chalk.dim(`Expected location: ${LOG_FILE}\n`));
508
+ } else {
509
+ console.error(chalk.red('❌ Error watching log:'), err.message);
510
+ }
511
+ process.exit(1);
512
+ });
513
+
514
+ // Handle graceful shutdown
515
+ process.on('SIGINT', () => {
516
+ console.log(chalk.yellow('\n\n👋 Stopped watching agent activity\n'));
517
+ tail.kill();
518
+ process.exit(0);
519
+ });
520
+ });
521
+
522
+ program
523
+ .command('commentate')
524
+ .description('Live commentary on agent activity')
525
+ .action(async () => {
526
+ const { startCommentator } = await import('../lib/commentator.js');
527
+ startCommentator();
528
+ });
529
+
530
+ // Hierarchy enforcement commands
531
+ program
532
+ .command('compliance-report')
533
+ .description('Generate hierarchy compliance report')
534
+ .option('-q, --quarterly', 'Show quarterly metrics')
535
+ .action(async (options) => {
536
+ try {
537
+ console.log(chalk.blue('\n📊 HIERARCHY COMPLIANCE REPORT\n'));
538
+ console.log(chalk.dim('━'.repeat(80)));
539
+
540
+ const report = hierarchyValidator.getViolationReport();
541
+
542
+ console.log(chalk.bold('\n📈 Overall Metrics:'));
543
+ console.log(` Total Validations: ${chalk.green(report.totalValidations)}`);
544
+ console.log(` Total Violations: ${chalk.red(report.totalViolations)}`);
545
+
546
+ if (report.totalValidations + report.totalViolations > 0) {
547
+ const complianceRate = report.complianceRate.toFixed(1);
548
+ const rateColor = report.complianceRate >= 80 ? chalk.green : report.complianceRate >= 60 ? chalk.yellow : chalk.red;
549
+ console.log(` Compliance Rate: ${rateColor(complianceRate + '%')}`);
550
+ } else {
551
+ console.log(` Compliance Rate: ${chalk.dim('N/A (no data)')}`);
552
+ }
553
+
554
+ if (report.mostViolatedAgents.length > 0) {
555
+ console.log(chalk.bold('\n🚨 Most Violated Agents:'));
556
+ report.mostViolatedAgents.slice(0, 5).forEach((agent, idx) => {
557
+ console.log(` ${idx + 1}. ${chalk.yellow(agent.agent)}: ${chalk.red(agent.violations)} violations`);
558
+ });
559
+ }
560
+
561
+ if (report.violations.length > 0) {
562
+ console.log(chalk.bold('\n📋 Recent Violations:'));
563
+ report.violations.slice(-5).forEach(v => {
564
+ const date = new Date(v.timestamp).toLocaleString();
565
+ console.log(` ${chalk.dim(date)} - ${chalk.yellow(v.agent)}`);
566
+ console.log(` ${chalk.gray(v.reason)}`);
567
+ });
568
+ }
569
+
570
+ console.log(chalk.dim('\n━'.repeat(80)));
571
+ console.log(chalk.dim('💡 Use violations to improve delegation patterns\n'));
572
+
573
+ } catch (error) {
574
+ console.error(chalk.red('❌ Error generating compliance report:'), error.message);
575
+ process.exit(1);
576
+ }
577
+ });
578
+
579
+ program
580
+ .command('validate-agent')
581
+ .description('Validate that an agent follows hierarchy rules')
582
+ .argument('<agent-name>', 'Agent name to validate')
583
+ .option('-t, --task <task>', 'Task description (optional)')
584
+ .action(async (agentName, options) => {
585
+ try {
586
+ console.log(chalk.blue(`\n🔍 Validating agent: ${chalk.bold(agentName)}\n`));
587
+
588
+ // Check if agent exists in registry
589
+ const workerInfo = AGENT_HIERARCHY.workers[agentName];
590
+ const bossInfo = AGENT_HIERARCHY.bosses[agentName];
591
+
592
+ if (!workerInfo && !bossInfo) {
593
+ console.log(chalk.red('❌ Agent not found in hierarchy registry'));
594
+ console.log(chalk.dim('\nRegistered workers:'));
595
+ Object.keys(AGENT_HIERARCHY.workers).forEach(w => {
596
+ console.log(` - ${chalk.cyan(w)}`);
597
+ });
598
+ console.log(chalk.dim('\nRegistered bosses:'));
599
+ Object.keys(AGENT_HIERARCHY.bosses).forEach(b => {
600
+ console.log(` - ${chalk.green(b)}`);
601
+ });
602
+ process.exit(1);
603
+ }
604
+
605
+ if (workerInfo) {
606
+ console.log(chalk.bold('Agent Type:'), chalk.cyan('Worker'));
607
+ console.log(chalk.bold('Domain:'), chalk.green(workerInfo.domain));
608
+ console.log(chalk.bold('Assigned Boss:'), chalk.yellow(workerInfo.boss));
609
+ console.log(chalk.bold('Description:'), chalk.gray(workerInfo.description));
610
+
611
+ const bossInfo = AGENT_HIERARCHY.bosses[workerInfo.boss];
612
+ console.log(chalk.bold('Reports To:'), chalk.magenta(bossInfo.metaBoss));
613
+ console.log(chalk.green('\n✅ Valid worker agent in hierarchy'));
614
+ } else if (bossInfo) {
615
+ console.log(chalk.bold('Agent Type:'), chalk.yellow('Boss'));
616
+ console.log(chalk.bold('Domain:'), chalk.green(bossInfo.domain));
617
+ console.log(chalk.bold('Reports To:'), chalk.magenta(bossInfo.metaBoss));
618
+ console.log(chalk.bold('Description:'), chalk.gray(bossInfo.description));
619
+ console.log(chalk.bold('Manages Workers:'));
620
+ bossInfo.workers.forEach(w => {
621
+ console.log(` - ${chalk.cyan(w)}`);
622
+ });
623
+ console.log(chalk.green('\n✅ Valid boss agent in hierarchy'));
624
+ }
625
+
626
+ console.log();
627
+
628
+ } catch (error) {
629
+ console.error(chalk.red('❌ Error validating agent:'), error.message);
630
+ process.exit(1);
631
+ }
632
+ });
633
+
634
+ program
635
+ .command('hierarchy-tree')
636
+ .description('Display the complete agent hierarchy tree')
637
+ .action(() => {
638
+ try {
639
+ console.log(chalk.bold.blue('\n🌳 AGENT HIERARCHY TREE\n'));
640
+ console.log(chalk.dim('━'.repeat(80)));
641
+
642
+ console.log(chalk.bold('\nTier 3: Meta-Boss'));
643
+ console.log(` ${chalk.magenta('┗━ ' + AGENT_HIERARCHY.metaBoss)} ${chalk.dim('(final security gate)')}`);
644
+
645
+ console.log(chalk.bold('\nTier 2: Domain Bosses'));
646
+ Object.entries(AGENT_HIERARCHY.bosses).forEach(([name, info]) => {
647
+ console.log(` ${chalk.yellow('┣━ ' + name)} ${chalk.dim('(' + info.domain + ')')}`);
648
+ });
649
+
650
+ console.log(chalk.bold('\nTier 1: Worker Agents'));
651
+ Object.entries(AGENT_HIERARCHY.workers).forEach(([name, info], idx, arr) => {
652
+ const isLast = idx === arr.length - 1;
653
+ const prefix = isLast ? '┗━' : '┣━';
654
+ console.log(` ${chalk.cyan(prefix + ' ' + name)} ${chalk.dim('→ ' + info.boss)}`);
655
+ });
656
+
657
+ console.log(chalk.dim('\n━'.repeat(80)));
658
+ console.log(chalk.dim('💡 Use "boss-claude validate-agent <name>" for details\n'));
659
+
660
+ } catch (error) {
661
+ console.error(chalk.red('❌ Error displaying hierarchy:'), error.message);
662
+ process.exit(1);
663
+ }
664
+ });
665
+
666
+ // ONYX Reminder commands
667
+ program
668
+ .command('onyx:show')
669
+ .description('Display ONYX orchestrator reminder')
670
+ .action(async () => {
671
+ try {
672
+ await onyxReminder.showOnyxReminder();
673
+ } catch (error) {
674
+ console.error(chalk.red('❌ Error showing ONYX reminder:'), error.message);
675
+ process.exit(1);
676
+ }
677
+ });
678
+
679
+ program
680
+ .command('onyx:status')
681
+ .description('Show ONYX reminder status and message count')
682
+ .action(async () => {
683
+ try {
684
+ const count = await onyxReminder.getOnyxMessageCount();
685
+ const interval = await onyxReminder.getOnyxInterval();
686
+
687
+ console.log(chalk.blue('\n⚡ ONYX REMINDER STATUS\n'));
688
+ console.log(chalk.bold('Configuration:'));
689
+ console.log(` Message Count: ${chalk.cyan(count)}`);
690
+ console.log(` Reminder Interval: ${chalk.yellow('Every ' + interval + ' messages')}`);
691
+ console.log(` Next Reminder: ${chalk.green('In ' + (interval - (count % interval)) + ' messages')}\n`);
692
+
693
+ if (count % interval === 0 && count > 0) {
694
+ console.log(chalk.yellow('⚡ Reminder is due NOW!\n'));
695
+ await onyxReminder.showOnyxReminder();
696
+ }
697
+
698
+ } catch (error) {
699
+ console.error(chalk.red('❌ Error getting ONYX status:'), error.message);
700
+ process.exit(1);
701
+ }
702
+ });
703
+
704
+ program
705
+ .command('onyx:set-interval')
706
+ .description('Set ONYX reminder interval')
707
+ .argument('<interval>', 'Number of messages between reminders')
708
+ .action(async (interval) => {
709
+ try {
710
+ const num = parseInt(interval, 10);
711
+ if (isNaN(num) || num < 1) {
712
+ console.error(chalk.red('❌ Interval must be a positive number\n'));
713
+ process.exit(1);
714
+ }
715
+
716
+ await onyxReminder.setOnyxInterval(num);
717
+ console.log(chalk.green(`\n✅ ONYX reminder interval set to ${num} messages\n`));
718
+
719
+ } catch (error) {
720
+ console.error(chalk.red('❌ Error setting interval:'), error.message);
721
+ process.exit(1);
722
+ }
723
+ });
724
+
725
+ program
726
+ .command('onyx:reset')
727
+ .description('Reset ONYX message counter to zero')
728
+ .action(async () => {
729
+ try {
730
+ await onyxReminder.resetOnyxCounter();
731
+ console.log(chalk.green('\n✅ ONYX message counter reset to zero\n'));
732
+
733
+ } catch (error) {
734
+ console.error(chalk.red('❌ Error resetting counter:'), error.message);
735
+ process.exit(1);
736
+ }
737
+ });
738
+
739
+ // Checkpoint commands - ONYX delegation accountability
740
+ program
741
+ .command('checkpoint:status')
742
+ .description('Show current checkpoint status and delegation efficiency')
743
+ .action(async () => {
744
+ try {
745
+ const status = await getCheckpointStatus();
746
+ const efficiency = await getDelegationEfficiency();
747
+
748
+ if (!status) {
749
+ console.log(chalk.yellow('\n⚠️ No active checkpoint session\n'));
750
+ console.log(chalk.dim('Checkpoint tracking starts automatically when ONYX begins work\n'));
751
+ return;
752
+ }
753
+
754
+ console.log(chalk.blue('\n⚡ CHECKPOINT STATUS\n'));
755
+ console.log(chalk.dim('━'.repeat(80)));
756
+
757
+ console.log(chalk.bold('\n📊 Session Progress:'));
758
+ console.log(` Repository: ${chalk.cyan(status.repo)}`);
759
+ console.log(` Messages: ${chalk.yellow(status.message_count)}`);
760
+ console.log(` Checkpoints Passed: ${chalk.green(status.checkpoints_passed)}`);
761
+ console.log(` Next Checkpoint: ${chalk.magenta('In ' + (5 - (status.message_count % 5)) + ' messages')}`);
762
+
763
+ console.log(chalk.bold('\n🎯 Delegation Efficiency:'));
764
+ console.log(` Delegation Rate: ${chalk.green(efficiency.delegation_rate + '%')}`);
765
+ console.log(` Delegations: ${chalk.cyan(efficiency.delegations)}`);
766
+ console.log(` Token Burns: ${chalk.red(efficiency.token_burns)}`);
767
+
768
+ console.log(chalk.bold('\n💰 Token Economics:'));
769
+ console.log(` Tokens Saved: ${chalk.green('+' + efficiency.tokens_saved.toLocaleString())}`);
770
+ console.log(` Tokens Burned: ${chalk.red('-' + efficiency.tokens_burned.toLocaleString())}`);
771
+ console.log(` Net Savings: ${chalk.bold(efficiency.net_savings.toLocaleString())}`);
772
+ console.log(` Efficiency Score: ${chalk.yellow(efficiency.efficiency_score + '%')}`);
773
+
774
+ if (status.awaiting_response) {
775
+ console.log(chalk.bold.yellow('\n⏳ CHECKPOINT PENDING - Awaiting delegation decision'));
776
+ }
777
+
778
+ console.log(chalk.dim('\n━'.repeat(80)));
779
+ console.log(chalk.dim('💡 Use "boss-claude checkpoint:history" to see past decisions\n'));
780
+
781
+ } catch (error) {
782
+ console.error(chalk.red('❌ Error getting checkpoint status:'), error.message);
783
+ process.exit(1);
784
+ }
785
+ });
786
+
787
+ program
788
+ .command('checkpoint:record')
789
+ .description('Record checkpoint decision (delegated or burned)')
790
+ .option('-d, --delegated', 'Task was delegated to specialist')
791
+ .option('-b, --burned', 'Task was done directly (tokens burned)')
792
+ .option('-t, --tokens <number>', 'Tokens saved (if delegated) or burned (if not)', '0')
793
+ .option('-s, --specialist <name>', 'Specialist name (if delegated)')
794
+ .option('-j, --justification <text>', 'Justification for decision', '')
795
+ .action(async (options) => {
796
+ try {
797
+ if (!options.delegated && !options.burned) {
798
+ console.error(chalk.red('❌ Must specify either --delegated or --burned\n'));
799
+ process.exit(1);
800
+ }
801
+
802
+ if (options.delegated && options.burned) {
803
+ console.error(chalk.red('❌ Cannot specify both --delegated and --burned\n'));
804
+ process.exit(1);
805
+ }
806
+
807
+ const delegated = options.delegated;
808
+ const tokens = parseInt(options.tokens, 10);
809
+ const specialist = options.specialist || '';
810
+ const justification = options.justification;
811
+
812
+ if (delegated && !specialist) {
813
+ console.error(chalk.red('❌ Specialist name required when delegated\n'));
814
+ process.exit(1);
815
+ }
816
+
817
+ const result = await recordCheckpoint(
818
+ delegated,
819
+ delegated ? tokens : 0,
820
+ delegated ? 0 : tokens,
821
+ justification,
822
+ specialist
823
+ );
824
+
825
+ console.log(chalk.green('\n✅ Checkpoint recorded!\n'));
826
+ console.log(chalk.bold('Decision:'));
827
+ console.log(` Type: ${delegated ? chalk.green('DELEGATED') : chalk.red('BURNED')}`);
828
+ console.log(` Tokens: ${chalk.cyan(tokens.toLocaleString())}`);
829
+ if (specialist) {
830
+ console.log(` Specialist: ${chalk.yellow(specialist)}`);
831
+ }
832
+ if (justification) {
833
+ console.log(` Justification: ${chalk.gray(justification)}`);
834
+ }
835
+
836
+ console.log(chalk.bold('\nUpdated Stats:'));
837
+ console.log(` Total Checkpoints: ${chalk.green(result.checkpoint.checkpoints_passed)}`);
838
+ console.log(` Delegation Rate: ${chalk.cyan(((result.checkpoint.delegation_count / result.checkpoint.checkpoints_passed) * 100).toFixed(1) + '%')}`);
839
+
840
+ console.log();
841
+
842
+ } catch (error) {
843
+ console.error(chalk.red('❌ Error recording checkpoint:'), error.message);
844
+ process.exit(1);
845
+ }
846
+ });
847
+
848
+ program
849
+ .command('checkpoint:history')
850
+ .description('Show checkpoint history')
851
+ .option('-l, --limit <number>', 'Number of records to show', '20')
852
+ .action(async (options) => {
853
+ try {
854
+ const limit = parseInt(options.limit, 10);
855
+ const history = await getCheckpointHistory(limit);
856
+
857
+ if (history.length === 0) {
858
+ console.log(chalk.yellow('\n⚠️ No checkpoint history found\n'));
859
+ return;
860
+ }
861
+
862
+ console.log(chalk.blue(`\n📋 CHECKPOINT HISTORY (Last ${history.length} records)\n`));
863
+ console.log(chalk.dim('━'.repeat(80)));
864
+
865
+ history.forEach((record, idx) => {
866
+ const date = new Date(record.timestamp).toLocaleString();
867
+ const decision = record.delegated ? chalk.green('DELEGATED') : chalk.red('BURNED');
868
+ const tokens = record.delegated ? record.tokens_saved : record.tokens_burned;
869
+
870
+ console.log(chalk.bold(`\n${idx + 1}. ${date}`));
871
+ console.log(` Decision: ${decision}`);
872
+ console.log(` Tokens: ${chalk.cyan(tokens.toLocaleString())}`);
873
+ if (record.specialist) {
874
+ console.log(` Specialist: ${chalk.yellow(record.specialist)}`);
875
+ }
876
+ if (record.justification) {
877
+ console.log(` Justification: ${chalk.gray(record.justification)}`);
878
+ }
879
+ });
880
+
881
+ console.log(chalk.dim('\n━'.repeat(80)));
882
+ console.log(chalk.dim('💡 Use "boss-claude checkpoint:status" for current stats\n'));
883
+
884
+ } catch (error) {
885
+ console.error(chalk.red('❌ Error getting checkpoint history:'), error.message);
886
+ process.exit(1);
887
+ }
888
+ });
889
+
890
+ program
891
+ .command('checkpoint:export')
892
+ .description('Export checkpoint data for analysis')
893
+ .action(async () => {
894
+ try {
895
+ const data = await exportCheckpointData();
896
+
897
+ console.log(chalk.blue('\n📦 CHECKPOINT DATA EXPORT\n'));
898
+ console.log(JSON.stringify(data, null, 2));
899
+ console.log();
900
+
901
+ } catch (error) {
902
+ console.error(chalk.red('❌ Error exporting checkpoint data:'), error.message);
903
+ process.exit(1);
904
+ }
905
+ });
906
+
907
+ program
908
+ .command('checkpoint:reset')
909
+ .description('Reset checkpoint tracking for new session')
910
+ .action(async () => {
911
+ try {
912
+ const newCheckpoint = await resetCheckpoint();
913
+
914
+ console.log(chalk.green('\n✅ Checkpoint reset complete!\n'));
915
+ console.log(chalk.bold('New Session:'));
916
+ console.log(` Repository: ${chalk.cyan(newCheckpoint.repo)}`);
917
+ console.log(` Started: ${chalk.gray(newCheckpoint.started_at)}`);
918
+ console.log(` Checkpoints will trigger every ${chalk.yellow('5 messages')}\n`);
919
+
920
+ } catch (error) {
921
+ console.error(chalk.red('❌ Error resetting checkpoint:'), error.message);
922
+ process.exit(1);
923
+ }
924
+ });
925
+
926
+ // ONYX Delegation Monitoring Commands
927
+ program
928
+ .command('onyx-status')
929
+ .description('Show ONYX delegation ratio and monitoring status')
930
+ .action(async () => {
931
+ try {
932
+ const status = await getFormattedStatus();
933
+ console.log(status);
934
+ } catch (error) {
935
+ console.error(chalk.red('❌ Error getting ONYX status:'), error.message);
936
+ process.exit(1);
937
+ }
938
+ });
939
+
940
+ program
941
+ .command('onyx-report')
942
+ .description('Generate comprehensive ONYX delegation report')
943
+ .option('-e, --events <limit>', 'Number of recent events to include', '50')
944
+ .action(async (options) => {
945
+ try {
946
+ console.log(chalk.blue('\n📊 ONYX DELEGATION REPORT\n'));
947
+ console.log(chalk.dim('━'.repeat(80)));
948
+
949
+ const report = await generateReport({ eventLimit: parseInt(options.events) });
950
+
951
+ console.log(chalk.bold('\n📈 Overall Statistics:'));
952
+ console.log(` Total Actions: ${chalk.cyan(report.overall.total_actions)}`);
953
+ console.log(` Delegations: ${chalk.green(report.overall.total_delegations)}`);
954
+ console.log(` Direct Actions: ${chalk.yellow(report.overall.total_direct_actions)}`);
955
+ console.log(` Delegation Ratio: ${chalk.bold(report.overall.delegation_percentage + '%')}`);
956
+ console.log(` Alert Threshold: ${chalk.gray(report.overall.threshold_percentage + '%')}`);
957
+
958
+ const statusIcon = report.overall.meets_threshold ? chalk.green('✅ PASSING') : chalk.red('⚠️ BELOW THRESHOLD');
959
+ console.log(` Status: ${statusIcon}`);
960
+
961
+ console.log(chalk.bold('\n⏱️ Time-Based Metrics:'));
962
+ console.log(chalk.dim(' Last 24 Hours:'));
963
+ console.log(` Delegations: ${chalk.green(report.time_periods.last_24h.delegations)}`);
964
+ console.log(` Direct Actions: ${chalk.yellow(report.time_periods.last_24h.direct_actions)}`);
965
+ console.log(` Ratio: ${chalk.cyan(report.time_periods.last_24h.percentage + '%')}`);
966
+
967
+ console.log(chalk.dim(' Last 7 Days:'));
968
+ console.log(` Delegations: ${chalk.green(report.time_periods.last_7d.delegations)}`);
969
+ console.log(` Direct Actions: ${chalk.yellow(report.time_periods.last_7d.direct_actions)}`);
970
+ console.log(` Ratio: ${chalk.cyan(report.time_periods.last_7d.percentage + '%')}`);
971
+
972
+ if (Object.keys(report.overall.agent_breakdown).length > 0) {
973
+ console.log(chalk.bold('\n🤖 Agent Delegation Breakdown:'));
974
+ Object.entries(report.overall.agent_breakdown)
975
+ .sort((a, b) => b[1] - a[1])
976
+ .forEach(([agent, count]) => {
977
+ console.log(` ${chalk.cyan(agent)}: ${chalk.green(count)} tasks`);
978
+ });
979
+ }
980
+
981
+ if (Object.keys(report.overall.direct_action_breakdown).length > 0) {
982
+ console.log(chalk.bold('\n⚡ Direct Action Breakdown:'));
983
+ Object.entries(report.overall.direct_action_breakdown)
984
+ .sort((a, b) => b[1] - a[1])
985
+ .forEach(([type, count]) => {
986
+ console.log(` ${chalk.yellow(type)}: ${chalk.red(count)} actions`);
987
+ });
988
+ }
989
+
990
+ if (report.recent_events.length > 0) {
991
+ console.log(chalk.bold('\n📋 Recent Events:'));
992
+ report.recent_events.slice(0, 10).forEach(event => {
993
+ const time = new Date(event.timestamp).toLocaleTimeString();
994
+ if (event.type === 'delegation') {
995
+ console.log(` ${chalk.dim(time)} ${chalk.green('→')} Delegated to ${chalk.cyan(event.agent)}: ${chalk.gray(event.task)}`);
996
+ } else {
997
+ console.log(` ${chalk.dim(time)} ${chalk.red('•')} Direct action ${chalk.yellow(event.action_type)}: ${chalk.gray(event.description)}`);
998
+ }
999
+ });
1000
+ }
1001
+
1002
+ console.log(chalk.dim('\n━'.repeat(80)));
1003
+ console.log(chalk.dim(`Generated: ${new Date(report.generated_at).toLocaleString()}`));
1004
+ console.log(chalk.dim(`Alert Log: ${ALERT_LOG}\n`));
1005
+
1006
+ } catch (error) {
1007
+ console.error(chalk.red('❌ Error generating report:'), error.message);
1008
+ process.exit(1);
1009
+ }
1010
+ });
1011
+
1012
+ program
1013
+ .command('onyx-track-delegation')
1014
+ .description('Track a task delegated to ONYX agent')
1015
+ .argument('<agent>', 'ONYX agent name')
1016
+ .argument('<task>', 'Task description')
1017
+ .action(async (agent, task) => {
1018
+ try {
1019
+ const stats = await trackDelegation(agent, task);
1020
+
1021
+ console.log(chalk.green(`\n✅ Delegation tracked: ${chalk.bold(agent)}`));
1022
+ console.log(` Task: ${chalk.gray(task)}`);
1023
+ console.log(` Current Ratio: ${chalk.cyan(stats.delegation_percentage + '%')} (${stats.total_delegations}/${stats.total_actions})`);
1024
+
1025
+ if (!stats.meets_threshold) {
1026
+ console.log(chalk.yellow(` ⚠️ Below threshold of ${stats.threshold_percentage}%`));
1027
+ }
1028
+
1029
+ console.log();
1030
+ } catch (error) {
1031
+ console.error(chalk.red('❌ Error tracking delegation:'), error.message);
1032
+ process.exit(1);
1033
+ }
1034
+ });
1035
+
1036
+ program
1037
+ .command('onyx-track-direct')
1038
+ .description('Track a direct action (not delegated to ONYX)')
1039
+ .argument('<type>', 'Action type (e.g., file_edit, command_execution)')
1040
+ .argument('<description>', 'Action description')
1041
+ .action(async (type, description) => {
1042
+ try {
1043
+ const stats = await trackDirectAction(type, description);
1044
+
1045
+ console.log(chalk.yellow(`\n⚡ Direct action tracked: ${chalk.bold(type)}`));
1046
+ console.log(` Description: ${chalk.gray(description)}`);
1047
+ console.log(` Current Ratio: ${chalk.cyan(stats.delegation_percentage + '%')} (${stats.total_delegations}/${stats.total_actions})`);
1048
+
1049
+ if (!stats.meets_threshold) {
1050
+ console.log(chalk.red(` ⚠️ ALERT: Below threshold of ${stats.threshold_percentage}%`));
1051
+ }
1052
+
1053
+ console.log();
1054
+ } catch (error) {
1055
+ console.error(chalk.red('❌ Error tracking direct action:'), error.message);
1056
+ process.exit(1);
1057
+ }
1058
+ });
1059
+
1060
+ program
1061
+ .command('onyx-set-threshold')
1062
+ .description('Set ONYX delegation ratio alert threshold')
1063
+ .argument('<threshold>', 'Threshold percentage (e.g., 95 for 95%)')
1064
+ .action(async (threshold) => {
1065
+ try {
1066
+ const num = parseFloat(threshold);
1067
+ if (isNaN(num) || num < 0 || num > 100) {
1068
+ console.error(chalk.red('❌ Threshold must be between 0 and 100\n'));
1069
+ process.exit(1);
1070
+ }
1071
+
1072
+ const newThreshold = await setAlertThreshold(num / 100);
1073
+ console.log(chalk.green(`\n✅ Alert threshold set to ${chalk.bold((newThreshold * 100).toFixed(0) + '%')}\n`));
1074
+ console.log(chalk.dim(' Alerts will trigger when delegation ratio drops below this threshold\n'));
1075
+
1076
+ } catch (error) {
1077
+ console.error(chalk.red('❌ Error setting threshold:'), error.message);
1078
+ process.exit(1);
1079
+ }
1080
+ });
1081
+
1082
+ program
1083
+ .command('onyx-events')
1084
+ .description('Show recent ONYX delegation and direct action events')
1085
+ .option('-l, --limit <number>', 'Number of events to show', '20')
1086
+ .action(async (options) => {
1087
+ try {
1088
+ const events = await getRecentEvents(parseInt(options.limit));
1089
+
1090
+ console.log(chalk.blue(`\n📜 Recent ONYX Events (${events.length})\n`));
1091
+ console.log(chalk.dim('━'.repeat(80)));
1092
+
1093
+ events.forEach((event, idx) => {
1094
+ const time = new Date(event.timestamp).toLocaleString();
1095
+
1096
+ if (event.type === 'delegation') {
1097
+ console.log(`\n${chalk.dim(`${idx + 1}.`)} ${chalk.green('DELEGATION')} ${chalk.dim(time)}`);
1098
+ console.log(` Agent: ${chalk.cyan(event.agent)}`);
1099
+ console.log(` Task: ${chalk.gray(event.task)}`);
1100
+ if (event.metadata && Object.keys(event.metadata).length > 0) {
1101
+ console.log(` Metadata: ${chalk.dim(JSON.stringify(event.metadata))}`);
1102
+ }
1103
+ } else {
1104
+ console.log(`\n${chalk.dim(`${idx + 1}.`)} ${chalk.yellow('DIRECT ACTION')} ${chalk.dim(time)}`);
1105
+ console.log(` Type: ${chalk.yellow(event.action_type)}`);
1106
+ console.log(` Description: ${chalk.gray(event.description)}`);
1107
+ if (event.metadata && Object.keys(event.metadata).length > 0) {
1108
+ console.log(` Metadata: ${chalk.dim(JSON.stringify(event.metadata))}`);
1109
+ }
1110
+ }
1111
+ });
1112
+
1113
+ console.log(chalk.dim('\n━'.repeat(80)));
1114
+ console.log(chalk.dim('💡 Use "boss-claude onyx-report" for comprehensive analysis\n'));
1115
+
1116
+ } catch (error) {
1117
+ console.error(chalk.red('❌ Error fetching events:'), error.message);
1118
+ process.exit(1);
1119
+ }
1120
+ });
1121
+
1122
+ program
1123
+ .command('onyx-reset-tracking')
1124
+ .description('Reset all ONYX delegation tracking data')
1125
+ .option('--confirm', 'Skip confirmation prompt')
1126
+ .action(async (options) => {
1127
+ try {
1128
+ console.log(chalk.yellow('\n⚠️ WARNING: This will reset all ONYX delegation tracking data!\n'));
1129
+
1130
+ if (!options.confirm) {
1131
+ const { default: inquirer } = await import('inquirer');
1132
+ const { confirm } = await inquirer.prompt([
1133
+ {
1134
+ type: 'confirm',
1135
+ name: 'confirm',
1136
+ message: 'Are you sure you want to reset all tracking data?',
1137
+ default: false
1138
+ }
1139
+ ]);
1140
+
1141
+ if (!confirm) {
1142
+ console.log(chalk.yellow('Reset cancelled\n'));
1143
+ process.exit(0);
1144
+ }
1145
+ }
1146
+
1147
+ await resetTracking();
1148
+ console.log(chalk.green('✅ ONYX delegation tracking has been reset\n'));
1149
+
1150
+ } catch (error) {
1151
+ console.error(chalk.red('❌ Error resetting tracking:'), error.message);
1152
+ process.exit(1);
1153
+ }
1154
+ });
1155
+
1156
+ program
1157
+ .command('onyx-banner')
1158
+ .description('Display ONYX MODE banner (for testing and integration)')
1159
+ .option('-c, --compact', 'Display compact version')
1160
+ .option('-s, --stats', 'Display with statistics')
1161
+ .option('--no-color', 'Disable colorization')
1162
+ .action(async (options) => {
1163
+ try {
1164
+ const { displayOnyxBanner, displayOnyxBannerCompact, getBannerWithStats } = await import('../lib/onyx-banner.js');
1165
+
1166
+ if (options.stats) {
1167
+ console.log(getBannerWithStats(true));
1168
+ } else if (options.compact) {
1169
+ console.log(displayOnyxBannerCompact(options.color));
1170
+ } else {
1171
+ console.log(displayOnyxBanner(options.color));
1172
+ }
1173
+
1174
+ } catch (error) {
1175
+ console.error(chalk.red('❌ Error displaying banner:'), error.message);
1176
+ process.exit(1);
1177
+ }
1178
+ });
1179
+
1180
+ // Mode enforcement commands
1181
+ program
1182
+ .command('mode')
1183
+ .description('Manage orchestrator mode enforcement')
1184
+ .argument('[subcommand]', 'Mode command (orchestrator|specialist|worker|review|learning|history|stats|blocked|reset|status)')
1185
+ .allowUnknownOption()
1186
+ .action(async (subcommand, options, command) => {
1187
+ try {
1188
+ // Pass all remaining arguments to mode command handler
1189
+ const args = command.args.slice(1);
1190
+ if (subcommand) {
1191
+ args.unshift(subcommand);
1192
+ }
1193
+ await modeCommand(args);
1194
+ } catch (error) {
1195
+ console.error(chalk.red('❌ Mode command failed:'), error.message);
1196
+ process.exit(1);
1197
+ }
1198
+ });
1199
+
1200
+ // Agent management commands (kill stuck workers)
1201
+ program
1202
+ .command('agent:list')
1203
+ .description('List currently running agents')
1204
+ .action(async () => {
1205
+ try {
1206
+ console.log(chalk.blue('\n🔍 Scanning for running agents...\n'));
1207
+
1208
+ // Check for Claude task processes
1209
+ const { execSync } = await import('child_process');
1210
+ try {
1211
+ const psOutput = execSync('ps aux | grep -E "claude|task" | grep -v grep', { encoding: 'utf8' });
1212
+ const lines = psOutput.trim().split('\n').filter(l => l.trim());
1213
+
1214
+ if (lines.length === 0) {
1215
+ console.log(chalk.gray('No agents currently running.'));
1216
+ } else {
1217
+ console.log(chalk.bold('Running Processes:'));
1218
+ lines.forEach(line => {
1219
+ const parts = line.split(/\s+/);
1220
+ const pid = parts[1];
1221
+ const cmd = parts.slice(10).join(' ').substring(0, 60);
1222
+ console.log(` ${chalk.cyan(pid)} - ${chalk.dim(cmd)}`);
1223
+ });
1224
+ }
1225
+ } catch (e) {
1226
+ console.log(chalk.gray('No agents currently running.'));
1227
+ }
1228
+
1229
+ } catch (error) {
1230
+ console.error(chalk.red('❌ Error listing agents:'), error.message);
1231
+ process.exit(1);
1232
+ }
1233
+ });
1234
+
1235
+ program
1236
+ .command('agent:kill')
1237
+ .description('Kill a stuck agent by PID')
1238
+ .argument('<pid>', 'Process ID to kill')
1239
+ .option('-f, --force', 'Force kill (SIGKILL instead of SIGTERM)')
1240
+ .action(async (pid, options) => {
1241
+ try {
1242
+ const signal = options.force ? 'SIGKILL' : 'SIGTERM';
1243
+ console.log(chalk.yellow(`\n🛑 Sending ${signal} to PID ${pid}...\n`));
1244
+
1245
+ const { execSync } = await import('child_process');
1246
+ execSync(`kill -${signal === 'SIGKILL' ? '9' : '15'} ${pid}`);
1247
+
1248
+ console.log(chalk.green(`✅ Signal sent to process ${pid}`));
1249
+ console.log(chalk.gray(' Agent should terminate shortly.'));
1250
+
1251
+ } catch (error) {
1252
+ if (error.message.includes('No such process')) {
1253
+ console.log(chalk.yellow(`⚠️ Process ${pid} not found (may have already exited)`));
1254
+ } else {
1255
+ console.error(chalk.red('❌ Error killing agent:'), error.message);
1256
+ process.exit(1);
1257
+ }
1258
+ }
1259
+ });
1260
+
1261
+ program
1262
+ .command('agent:kill-all')
1263
+ .description('Kill all stuck agents (nuclear option)')
1264
+ .option('-f, --force', 'Force kill all')
1265
+ .action(async (options) => {
1266
+ try {
1267
+ console.log(chalk.red.bold('\n⚠️ NUCLEAR OPTION: Killing all agent processes...\n'));
1268
+
1269
+ const { execSync } = await import('child_process');
1270
+ const signal = options.force ? '9' : '15';
1271
+
1272
+ try {
1273
+ // Kill claude task-related processes (but not the main Claude process)
1274
+ execSync(`pkill -${signal} -f "claude.*task" 2>/dev/null || true`, { encoding: 'utf8' });
1275
+ console.log(chalk.green('✅ Kill signal sent to all task agents'));
1276
+ } catch (e) {
1277
+ console.log(chalk.yellow('⚠️ No agents found to kill'));
1278
+ }
1279
+
1280
+ console.log(chalk.gray('\nNote: Main Claude process is preserved.'));
1281
+
1282
+ } catch (error) {
1283
+ console.error(chalk.red('❌ Error:'), error.message);
1284
+ process.exit(1);
1285
+ }
1286
+ });
1287
+
150
1288
  program.parse();