dual-brain 3.2.0 โ†’ 3.4.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/install.mjs CHANGED
@@ -39,34 +39,34 @@ if (flag('--version') || flag('-v')) {
39
39
 
40
40
  if (flag('--help') || flag('-h')) {
41
41
  console.log(`
42
- dual-brain v${VERSION} โ€” Dual-provider orchestrator for Claude Code
42
+ ๐Ÿง  dual-brain v${VERSION} โ€” Dual-provider orchestrator for Claude Code
43
43
 
44
44
  Usage: npx -y dual-brain [command] [options]
45
45
 
46
- Commands:
47
- (none) Auto-detect and install/update orchestrator
48
- status Live view of mode, spend, pressure, profile
49
- mode Show or switch profile (balanced, cost-saver, quality-first)
50
- budget Set session/daily spend limits
51
- explain Show why the last routing decision was made
52
- init Alias for default install (backward compat)
46
+ โŒจ๏ธ Commands:
47
+ (none) ๐Ÿง  Auto-detect and install/update orchestrator
48
+ status ๐ŸŸข Open live control panel
49
+ mode ๐ŸŽ›๏ธ Show or switch profile
50
+ budget ๐Ÿ’ต Set session/daily spend limits
51
+ explain ๐Ÿงญ Explain last routing decision
52
+ init Alias for default install
53
53
 
54
54
  Options:
55
- --force Overwrite all existing config (keeps review-rules.md)
56
- --dry-run Detect environment only, don't install
57
- --json Output detection as JSON (implies --dry-run)
55
+ --force Overwrite all existing config
56
+ --dry-run Detect environment only
57
+ --json Output detection as JSON
58
58
  --help Show this help
59
59
 
60
- Profiles:
61
- balanced Standard routing โ€” best model for each tier
62
- cost-saver Minimize spend โ€” prefer cheaper models
63
- quality-first Maximum quality โ€” dual-brain for medium+ risk
60
+ ๐ŸŽ›๏ธ Profiles:
61
+ โš–๏ธ balanced Standard routing โ€” best model per tier
62
+ ๐Ÿ’ธ cost-saver Minimize spend โ€” prefer cheaper models
63
+ ๐Ÿ’Ž quality-first Maximum quality โ€” dual-brain for medium+
64
64
 
65
- Examples:
65
+ ๐Ÿš€ Examples:
66
66
  ${cmd('npx dual-brain')} # install or update
67
- ${cmd('npx dual-brain status')} # live dashboard
67
+ ${cmd('npx dual-brain status')} # open control panel
68
68
  ${cmd('npx dual-brain mode cost-saver')} # switch profile
69
- ${cmd('npx dual-brain budget 8 25')} # $8 session / $25 daily
69
+ ${cmd('npx dual-brain budget 8 25')} # \$8 session / \$25 daily
70
70
  ${cmd('npx dual-brain explain')} # last routing decision
71
71
  `);
72
72
  process.exit(0);
@@ -334,7 +334,7 @@ function install(workspace, env, mode) {
334
334
  'test-orchestrator.mjs', 'setup-wizard.mjs', 'health-check.mjs',
335
335
  'install-git-hooks.mjs', 'session-report.mjs', 'budget-balancer.mjs',
336
336
  'gpt-work-dispatcher.mjs', 'profiles.mjs',
337
- 'summary-checkpoint.mjs', 'decision-ledger.mjs',
337
+ 'summary-checkpoint.mjs', 'decision-ledger.mjs', 'control-panel.mjs',
338
338
  ];
339
339
  for (const h of HOOKS) cpSync(join(__dirname, 'hooks', h), join(target, 'hooks', h));
340
340
  actions.push(`โœ“ ${HOOKS.length} hook scripts`);
@@ -381,106 +381,36 @@ function install(workspace, env, mode) {
381
381
 
382
382
  // โ”€โ”€โ”€ Status Report โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
383
383
 
384
- function statusIcon(val) { return val ? 'โœ“' : 'โœ—'; }
385
-
386
- function printReport(env, mode, actions) {
384
+ function printReport(env, mode, actions, isDryRun) {
387
385
  const lines = [];
388
386
 
389
387
  lines.push(br('โ•”', 'โ•—'));
390
- lines.push(ln(`Dual-Brain Orchestrator v${VERSION}`));
388
+ lines.push(ln(`๐Ÿง  Dual-Brain v${VERSION}`));
391
389
  lines.push(sep());
392
390
 
393
- lines.push(ln('Environment'));
391
+ const cAuth = env.claude.authed ? 'โœ…' : env.claude.installed ? 'โš ๏ธ' : 'โŒ';
392
+ const xAuth = env.codex.authed ? 'โœ…' : env.codex.installed ? 'โš ๏ธ' : 'โŒ';
393
+ lines.push(ln(` ๐ŸŸ  Claude ${cAuth} ๐ŸŸข Codex ${xAuth}`));
394
+
394
395
  if (env.isReplit) {
395
- lines.push(ln(` Platform: Replit${env.hasReplitTools ? ' (replit-tools detected)' : ''}`));
396
- } else {
397
- lines.push(ln(' Platform: standalone'));
396
+ lines.push(ln(` ๐ŸŒ€ Replit${env.hasReplitTools ? ' + replit-tools' : ''}`));
398
397
  }
399
398
 
400
- const cVer = env.claude.version ? ` ${env.claude.version}` : '';
401
- const cAuth = env.claude.authed ? 'authenticated' : env.claude.installed ? 'not authenticated' : 'not found';
402
- lines.push(ln(` Claude CLI: ${statusIcon(env.claude.authed)} ${cAuth}${cVer}`));
403
-
404
- const xVer = env.codex.version ? ` ${env.codex.version}` : '';
405
- const xAuth = env.codex.authed ? 'authenticated' : env.codex.installed ? 'not authenticated' : 'not found';
406
- lines.push(ln(` Codex CLI: ${statusIcon(env.codex.authed)} ${xAuth}${xVer}`));
407
-
408
- lines.push(sep());
409
- lines.push(ln(`Mode: ${MODE_LABELS[mode.mode]}`));
410
-
411
399
  if (actions) {
412
400
  lines.push(sep());
413
- lines.push(ln('Installed'));
414
401
  for (const a of actions) lines.push(ln(` ${a}`));
415
- }
416
-
417
- const needsAction = !env.claude.authed || !env.codex.authed;
418
- if (needsAction && mode.mode !== 'dual') {
419
402
  lines.push(sep());
420
- lines.push(ln('To unlock full features:'));
421
- if (!env.claude.installed) {
422
- lines.push(ln(' curl -fsSL https://claude.ai/install.sh | sh'));
423
- }
424
- if (!env.claude.authed) {
425
- lines.push(ln(' claude login'));
426
- }
427
- if (!env.codex.installed) {
428
- lines.push(ln(' npm i -g @openai/codex'));
429
- }
430
- if (!env.codex.authed && env.codex.installed) {
431
- lines.push(ln(' codex login'));
432
- }
433
- lines.push(ln(' Then run: npx dual-brain'));
434
- }
435
-
436
- lines.push(sep());
437
- if (actions) {
438
- lines.push(ln(mode.mode === 'dual'
439
- ? 'Ready โ€” both providers active, no restart needed'
440
- : 'Ready โ€” hooks active, run commands above for full power'));
441
- } else {
403
+ lines.push(ln('โœ… Installed โ€” launching session manager...'));
404
+ } else if (isDryRun) {
405
+ lines.push(sep());
442
406
  lines.push(ln('Dry run โ€” no files written'));
443
407
  }
408
+
444
409
  lines.push(br('โ•š', 'โ•'));
445
410
 
446
411
  console.log('');
447
412
  for (const l of lines) console.log(` ${l}`);
448
413
  console.log('');
449
-
450
- if (actions) {
451
- console.log(' What just happened:');
452
- console.log(' Every Claude Code session in this project now auto-routes');
453
- console.log(' agent work by complexity โ€” cheap models for search, mid-tier');
454
- console.log(' for execution, best models for thinking. Cost is tracked.');
455
- if (mode.mode === 'dual') {
456
- console.log(' Both Claude and GPT are available as work providers.');
457
- }
458
- console.log('');
459
- if (IS_REPLIT) {
460
- console.log(' Try these in your Replit shell (paste with ! prefix):');
461
- console.log(` ${cmd('npx dual-brain status')} # live dashboard`);
462
- console.log(` ${cmd('npx dual-brain mode cost-saver')} # switch profile`);
463
- console.log(` ${cmd('npx dual-brain budget 8 25')} # set limits`);
464
- } else {
465
- console.log(' Try these in your next Claude Code session:');
466
- console.log(' npx dual-brain status # live dashboard');
467
- console.log(' npx dual-brain mode cost-saver # switch profile');
468
- console.log(' npx dual-brain budget 8 25 # set limits');
469
- }
470
- console.log('');
471
- console.log(' In-session tools (ask Claude to run these):');
472
- console.log(' node .claude/hooks/health-check.mjs # verify setup');
473
- console.log(' node .claude/hooks/cost-report.mjs # see activity');
474
- console.log(' node .claude/hooks/budget-balancer.mjs # provider balance');
475
- if (mode.openaiEnabled) {
476
- console.log(' node .claude/hooks/dual-brain-review.mjs # GPT code review');
477
- }
478
- console.log('');
479
- console.log(' Customize:');
480
- console.log(' .claude/review-rules.md # your project\'s review rules');
481
- console.log(' .claude/orchestrator.json # routing, budgets, tiers');
482
- console.log('');
483
- }
484
414
  }
485
415
 
486
416
  // โ”€โ”€โ”€ Profile System โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@@ -541,70 +471,13 @@ function saveProfile(workspace, name, customOverrides) {
541
471
 
542
472
  // โ”€โ”€โ”€ Subcommand: status โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
543
473
 
544
- function cmdStatus() {
545
- const workspace = resolve(process.cwd());
546
- const env = detectEnvironment();
547
- const mode = resolveMode(env);
548
- const profile = loadProfile(workspace);
549
-
550
- const lines = [];
551
- lines.push(br('โ•”', 'โ•—'));
552
- lines.push(ln(`Dual-Brain Status โ€” v${VERSION}`));
553
- lines.push(sep());
554
-
555
- lines.push(ln(`Mode: ${MODE_LABELS[mode.mode]}`));
556
- lines.push(ln(`Profile: ${profile.name}`));
557
- lines.push(ln(` ${PROFILES[profile.name]?.description || ''}`));
558
- if (profile.switched_at) {
559
- lines.push(ln(` Set: ${profile.switched_at.slice(0, 16).replace('T', ' ')}`));
560
- }
561
-
562
- lines.push(sep());
563
-
564
- lines.push(ln('Budget Limits'));
565
- lines.push(ln(` Session: warn $${profile.budgets.session_warn_usd} / limit $${profile.budgets.session_limit_usd}`));
566
- lines.push(ln(` Daily: warn $${profile.budgets.daily_warn_usd} / limit $${profile.budgets.daily_limit_usd}`));
567
-
568
- lines.push(sep());
569
-
570
- lines.push(ln('Providers'));
571
- const cAuth = env.claude.authed ? 'authenticated' : 'not authenticated';
572
- const xAuth = env.codex.authed ? 'authenticated' : env.codex.installed ? 'not authenticated' : 'not found';
573
- lines.push(ln(` Claude: ${statusIcon(env.claude.authed)} ${cAuth}`));
574
- lines.push(ln(` Codex: ${statusIcon(env.codex.authed)} ${xAuth}`));
575
-
576
- lines.push(sep());
577
-
578
- lines.push(ln('Quality Gate'));
579
- lines.push(ln(` Reviews from: ${profile.quality_gate.sensitivity_floor} risk+`));
580
- lines.push(ln(` Dual-brain at: ${profile.quality_gate.dual_brain_minimum} risk+`));
581
-
582
- const balancer = join(workspace, '.claude', 'hooks', 'budget-balancer.mjs');
583
- if (existsSync(balancer)) {
584
- const proc = run(process.execPath, [balancer]);
585
- if (proc.status === 0 && proc.stdout.trim()) {
586
- lines.push(sep());
587
- lines.push(ln('Provider Pressure (5hr rolling)'));
588
- for (const l of proc.stdout.trim().split('\n')) {
589
- if (l.includes('โ–ˆ') || l.includes('โ–‘') || l.includes('Recommendation')) {
590
- const cleaned = l.replace(/[โ•‘โ•”โ•—โ• โ•ฃโ•šโ•โ•]/g, '').trim();
591
- if (cleaned) lines.push(ln(` ${cleaned}`));
592
- }
593
- }
594
- }
595
- }
596
-
597
- lines.push(br('โ•š', 'โ•'));
598
-
599
- console.log('');
600
- for (const l of lines) console.log(` ${l}`);
601
- console.log('');
602
-
603
- if (IS_REPLIT) {
604
- console.log(' Quick actions (paste into shell):');
605
- console.log(` ${cmd('npx dual-brain mode cost-saver')} # switch profile`);
606
- console.log(` ${cmd('npx dual-brain budget 8 25')} # set limits`);
607
- console.log('');
474
+ function launchPanel() {
475
+ const panelPath = join(resolve(process.cwd()), '.claude', 'hooks', 'control-panel.mjs');
476
+ const pkgPanel = join(__dirname, 'hooks', 'control-panel.mjs');
477
+ const panel = existsSync(panelPath) ? panelPath : existsSync(pkgPanel) ? pkgPanel : null;
478
+ if (panel) {
479
+ const { status } = spawnSync(process.execPath, [panel], { stdio: 'inherit' });
480
+ process.exit(status || 0);
608
481
  }
609
482
  }
610
483
 
@@ -616,12 +489,13 @@ function cmdMode() {
616
489
 
617
490
  if (!modeArg || modeArg === 'list') {
618
491
  const current = loadProfile(workspace);
492
+ const PEMOJIS = { balanced: 'โš–๏ธ ', 'cost-saver': '๐Ÿ’ธ', 'quality-first': '๐Ÿ’Ž' };
619
493
  console.log('');
620
- console.log(' Available profiles:');
494
+ console.log(' ๐ŸŽ›๏ธ Profiles:');
621
495
  console.log('');
622
496
  for (const [name, p] of Object.entries(PROFILES)) {
623
- const active = name === current.name ? ' โ† active' : '';
624
- console.log(` ${name.padEnd(15)} ${p.description}${active}`);
497
+ const active = name === current.name ? ' โœ… active' : '';
498
+ console.log(` ${PEMOJIS[name] || ' '} ${name.padEnd(15)} ${p.description}${active}`);
625
499
  }
626
500
  console.log('');
627
501
  console.log(` Switch: ${cmd('npx dual-brain mode <profile>')}`);
@@ -647,17 +521,18 @@ function cmdMode() {
647
521
 
648
522
  saveProfile(workspace, modeArg, customOverrides);
649
523
 
524
+ const PEMOJIS = { balanced: 'โš–๏ธ ', 'cost-saver': '๐Ÿ’ธ', 'quality-first': '๐Ÿ’Ž' };
650
525
  console.log('');
651
- console.log(` Profile switched to: ${modeArg}`);
526
+ console.log(` โœ… Profile switched: ${PEMOJIS[modeArg] || ''} ${modeArg}`);
652
527
  console.log(` ${profile.description}`);
653
528
  console.log('');
654
- console.log(' What changed:');
655
- console.log(` Routing: ${profile.routing.prefer_provider}`);
656
- console.log(` Budget: $${profile.budgets.session_limit_usd}/session, $${profile.budgets.daily_limit_usd}/day`);
657
- console.log(` Reviews from: ${profile.quality_gate.sensitivity_floor} risk+`);
658
- console.log(` Dual-brain: ${profile.quality_gate.dual_brain_minimum} risk+`);
529
+ console.log(' ๐Ÿงญ Routing changes:');
530
+ console.log(` Provider: ${profile.routing.prefer_provider}`);
531
+ console.log(` ๐Ÿ’ต Budget: $${profile.budgets.session_limit_usd}/session, $${profile.budgets.daily_limit_usd}/day`);
532
+ console.log(` ๐Ÿ›ก๏ธ Reviews: ${profile.quality_gate.sensitivity_floor} risk+`);
533
+ console.log(` ๐Ÿง  Dual-brain: ${profile.quality_gate.dual_brain_minimum} risk+`);
659
534
  console.log('');
660
- console.log(' Active immediately โ€” no restart needed.');
535
+ console.log(' ๐ŸŸข Active immediately, no restart needed.');
661
536
  console.log('');
662
537
  }
663
538
 
@@ -671,9 +546,9 @@ function cmdBudget() {
671
546
  if (sessionArg == null) {
672
547
  const profile = loadProfile(workspace);
673
548
  console.log('');
674
- console.log(' Current budget limits:');
675
- console.log(` Session: warn $${profile.budgets.session_warn_usd} / limit $${profile.budgets.session_limit_usd}`);
676
- console.log(` Daily: warn $${profile.budgets.daily_warn_usd} / limit $${profile.budgets.daily_limit_usd}`);
549
+ console.log(' ๐Ÿ’ต Current budget:');
550
+ console.log(` Session: โš ๏ธ $${profile.budgets.session_warn_usd} warn ยท ๐Ÿ›‘ $${profile.budgets.session_limit_usd} limit`);
551
+ console.log(` Daily: โš ๏ธ $${profile.budgets.daily_warn_usd} warn ยท ๐Ÿ›‘ $${profile.budgets.daily_limit_usd} limit`);
677
552
  console.log('');
678
553
  console.log(` Set limits: ${cmd('npx dual-brain budget <session$> [daily$]')}`);
679
554
  console.log(` Example: ${cmd('npx dual-brain budget 8 25')}`);
@@ -710,11 +585,11 @@ function cmdBudget() {
710
585
  renameSync(budgetTmp, budgetTarget);
711
586
 
712
587
  console.log('');
713
- console.log(' Budget limits updated:');
714
- console.log(` Session: warn $${customOverrides.budgets.session_warn_usd} / limit $${sessionArg}`);
715
- console.log(` Daily: warn $${customOverrides.budgets.daily_warn_usd} / limit $${daily}`);
588
+ console.log(' โœ… Budget updated:');
589
+ console.log(` Session: โš ๏ธ $${customOverrides.budgets.session_warn_usd} warn ยท ๐Ÿ›‘ $${sessionArg} limit`);
590
+ console.log(` Daily: โš ๏ธ $${customOverrides.budgets.daily_warn_usd} warn ยท ๐Ÿ›‘ $${daily} limit`);
716
591
  console.log('');
717
- console.log(' Active immediately โ€” no restart needed.');
592
+ console.log(' ๐ŸŸข Active immediately, no restart needed.');
718
593
  console.log('');
719
594
  }
720
595
 
@@ -728,7 +603,7 @@ function cmdExplain() {
728
603
 
729
604
  if (!existsSync(logFile)) {
730
605
  console.log('');
731
- console.log(' No routing decisions recorded today.');
606
+ console.log(' ๐Ÿ’ค No routing decisions recorded today.');
732
607
  console.log(' Start a Claude Code session and the tier enforcer will log decisions.');
733
608
  console.log('');
734
609
  return;
@@ -752,7 +627,7 @@ function cmdExplain() {
752
627
 
753
628
  if (!lastRec) {
754
629
  console.log('');
755
- console.log(' No routing decisions found in today\'s log.');
630
+ console.log(' ๐Ÿ’ค No routing decisions found in today\'s log.');
756
631
  console.log(' The tier enforcer logs decisions when Agent tool is used.');
757
632
  console.log('');
758
633
  return;
@@ -761,23 +636,23 @@ function cmdExplain() {
761
636
  const profile = loadProfile(workspace);
762
637
 
763
638
  console.log('');
764
- console.log(' Last Routing Decision');
639
+ console.log(' ๐Ÿงญ Last Routing Decision');
765
640
  console.log(' ' + 'โ”€'.repeat(40));
766
- console.log(` Time: ${lastRec.timestamp?.slice(11, 19) || 'unknown'}`);
767
- console.log(` Detected: ${lastRec.detected_tier || 'unknown'} tier`);
768
- console.log(` Recommended: ${lastRec.recommended_model || 'unknown'}`);
769
- console.log(` Actual: ${lastRec.actual_model || 'unknown'}`);
770
- console.log(` Followed: ${lastRec.followed ? 'yes' : 'no'}`);
771
- console.log(` Profile: ${profile.name}`);
641
+ console.log(` ๐Ÿ• Time: ${lastRec.timestamp?.slice(11, 19) || 'unknown'}`);
642
+ console.log(` ๐Ÿ”Ž Detected: ${lastRec.detected_tier || 'unknown'} tier`);
643
+ console.log(` ๐Ÿง  Recommended: ${lastRec.recommended_model || 'unknown'}`);
644
+ console.log(` ๐ŸŽฏ Actual: ${lastRec.actual_model || 'unknown'}`);
645
+ console.log(` ${lastRec.followed ? 'โœ…' : 'โš ๏ธ'} Followed: ${lastRec.followed ? 'yes' : 'no'}`);
646
+ console.log(` ๐ŸŽ›๏ธ Profile: ${profile.name}`);
772
647
  console.log('');
773
648
 
774
649
  if (!lastRec.followed) {
775
- console.log(' The recommendation was not followed. This may mean:');
650
+ console.log(' โš ๏ธ Recommendation was overridden. This may mean:');
776
651
  console.log(' - The task needed a different model (valid override)');
777
652
  console.log(' - The subagent_type forced a specific tier');
778
653
  console.log(` - Profile "${profile.name}" adjusted the threshold`);
779
654
  } else {
780
- console.log(' The recommendation was followed โ€” routing worked as expected.');
655
+ console.log(' โœ… Routing matched the recommendation.');
781
656
  }
782
657
 
783
658
  let total = 0, followed = 0;
@@ -796,7 +671,10 @@ function cmdExplain() {
796
671
  // โ”€โ”€โ”€ Main โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
797
672
 
798
673
  function main() {
799
- if (subcommand === 'status') { cmdStatus(); return; }
674
+ if (subcommand === 'status') {
675
+ launchPanel();
676
+ return;
677
+ }
800
678
  if (subcommand === 'mode') { cmdMode(); return; }
801
679
  if (subcommand === 'budget') { cmdBudget(); return; }
802
680
  if (subcommand === 'explain') { cmdExplain(); return; }
@@ -808,13 +686,29 @@ function main() {
808
686
  if (jsonOut) {
809
687
  console.log(JSON.stringify({ version: VERSION, env, mode }, null, 2));
810
688
  } else {
811
- printReport(env, mode, null);
689
+ printReport(env, mode, null, true);
812
690
  }
813
691
  process.exit(0);
814
692
  }
815
693
 
694
+ // Check for replit-tools on Replit
695
+ if (env.isReplit && !env.hasReplitTools) {
696
+ console.log('');
697
+ console.log(' โš ๏ธ replit-tools not found โ€” recommended for Replit environments.');
698
+ console.log(' Dual-brain works best alongside replit-tools for persistent auth,');
699
+ console.log(' session management, and shell integration.');
700
+ console.log('');
701
+ console.log(` Install: ${cmd('npx -y data-tools')}`);
702
+ console.log('');
703
+ }
704
+
816
705
  const actions = install(env.workspace, env, mode);
817
706
  printReport(env, mode, actions);
707
+
708
+ // After install, launch the session manager (interactive TTY only)
709
+ if (process.stdin.isTTY && process.stdout.isTTY && !process.env.CI) {
710
+ launchPanel();
711
+ }
818
712
  }
819
713
 
820
714
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dual-brain",
3
- "version": "3.2.0",
3
+ "version": "3.4.0",
4
4
  "description": "Dual-provider orchestration for Claude Code โ€” tiered routing, budget balancing, and GPT dual-brain review across Claude + OpenAI subscriptions",
5
5
  "type": "module",
6
6
  "bin": {