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/CLAUDE.md +20 -1
- package/hooks/control-panel.mjs +534 -0
- package/hooks/dual-brain-review.mjs +106 -17
- package/hooks/dual-brain-think.mjs +81 -17
- package/install.mjs +88 -194
- package/package.json +1 -1
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
|
|
49
|
-
mode Show or switch profile
|
|
50
|
-
budget Set session/daily spend limits
|
|
51
|
-
explain
|
|
52
|
-
init Alias for default install
|
|
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
|
|
56
|
-
--dry-run Detect environment only
|
|
57
|
-
--json Output detection as JSON
|
|
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
|
|
62
|
-
cost-saver Minimize spend โ prefer cheaper models
|
|
63
|
-
quality-first Maximum quality โ dual-brain for medium+
|
|
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')} #
|
|
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')} #
|
|
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
|
|
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(
|
|
388
|
+
lines.push(ln(`๐ง Dual-Brain v${VERSION}`));
|
|
391
389
|
lines.push(sep());
|
|
392
390
|
|
|
393
|
-
|
|
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(`
|
|
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('
|
|
421
|
-
|
|
422
|
-
|
|
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
|
|
545
|
-
const
|
|
546
|
-
const
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
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('
|
|
494
|
+
console.log(' ๐๏ธ Profiles:');
|
|
621
495
|
console.log('');
|
|
622
496
|
for (const [name, p] of Object.entries(PROFILES)) {
|
|
623
|
-
const active = name === current.name ? '
|
|
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
|
|
526
|
+
console.log(` โ
Profile switched: ${PEMOJIS[modeArg] || ''} ${modeArg}`);
|
|
652
527
|
console.log(` ${profile.description}`);
|
|
653
528
|
console.log('');
|
|
654
|
-
console.log('
|
|
655
|
-
console.log(`
|
|
656
|
-
console.log(` Budget:
|
|
657
|
-
console.log(` Reviews
|
|
658
|
-
console.log(` Dual-brain:
|
|
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
|
|
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
|
|
675
|
-
console.log(` Session:
|
|
676
|
-
console.log(` Daily:
|
|
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
|
|
714
|
-
console.log(` Session:
|
|
715
|
-
console.log(` 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
|
|
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:
|
|
767
|
-
console.log(` Detected:
|
|
768
|
-
console.log(` Recommended:
|
|
769
|
-
console.log(` Actual:
|
|
770
|
-
console.log(` Followed:
|
|
771
|
-
console.log(` Profile:
|
|
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('
|
|
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('
|
|
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')
|
|
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