@targlobal/mission-control 1.5.6 → 1.5.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@targlobal/mission-control",
3
- "version": "1.5.6",
3
+ "version": "1.5.8",
4
4
  "description": "CLI tool for TAR Global Mission Control - Internal task management",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -506,7 +506,7 @@ const showDashboard = async () => {
506
506
  console.log(chalk.cyan('┌─────────────────────────────┐'));
507
507
  console.log(chalk.cyan('│') + ` ${chalk.bgCyan.black('TASKS')} ${chalk.bold.white(String(stats.my_tasks).padStart(3))} ${chalk.bgRed.white('CRIT')} ${chalk.bold.red(String(stats.critical_count).padStart(2))} ${chalk.bgYellow.black('OVR')} ${chalk.bold.yellow(String(stats.overdue_tasks).padStart(2))} ` + chalk.cyan('│'));
508
508
  console.log(chalk.cyan('├─────────────────────────────┤'));
509
- console.log(chalk.cyan('│') + ` ${chalk.cyan('[1]')}Tasks ${chalk.cyan('[2]')}New ${chalk.cyan('[3]')}Pay ${chalk.cyan('[4]')}Urg ` + chalk.cyan('│'));
509
+ console.log(chalk.cyan('│') + ` ${chalk.cyan('[1]')}Tasks ${chalk.cyan('[2]')}New ${chalk.cyan('[3]')}Pay ${chalk.cyan('[4]')}Urg ${chalk.cyan('[5]')}Smart ` + chalk.cyan('│'));
510
510
  console.log(chalk.cyan('└─────────────────────────────┘'));
511
511
  console.log('');
512
512
 
@@ -528,7 +528,7 @@ const showDashboard = async () => {
528
528
  console.log(chalk.cyan('║') + ' ' + chalk.cyan('║'));
529
529
  console.log(chalk.cyan('╠══════════════════════════════════════════════════════════════════════╣'));
530
530
  console.log(chalk.cyan('║') + chalk.dim(' Quick Actions: ') + chalk.cyan('║'));
531
- console.log(chalk.cyan('║') + ` ${chalk.cyan('[1]')} My Tasks ${chalk.cyan('[2]')} New Task ${chalk.cyan('[3]')} Payouts ${chalk.cyan('[4]')} Urgent ` + chalk.cyan('║'));
531
+ console.log(chalk.cyan('║') + ` ${chalk.cyan('[1]')} My Tasks ${chalk.cyan('[2]')} New Task ${chalk.cyan('[3]')} Payouts ${chalk.cyan('[4]')} Urgent ${chalk.cyan('[5]')} Smart ` + chalk.cyan('║'));
532
532
  console.log(chalk.cyan('║') + ' ' + chalk.cyan('║'));
533
533
  console.log(chalk.cyan('╚══════════════════════════════════════════════════════════════════════╝'));
534
534
  console.log('');
@@ -549,6 +549,216 @@ const showDashboard = async () => {
549
549
  }
550
550
  };
551
551
 
552
+ const runSuperSmartDirect = async () => {
553
+ setTitle('Super Smart');
554
+ const spinner = ora('Loading all pending payouts...').start();
555
+
556
+ try {
557
+ // Fetch all pending payouts in parallel across all plans
558
+ const [payoutsRes, tarPayRes] = await Promise.all([
559
+ api.listPayouts({ status: 'pending', limit: 500 }),
560
+ api.getTarPayPayouts({ status: 'pending_review', limit: 500 }),
561
+ ]);
562
+
563
+ const payouts: Payout[] = payoutsRes.data || [];
564
+ const tarPayPayouts: TarPayPayout[] = tarPayRes.results || [];
565
+
566
+ spinner.stop();
567
+
568
+ // Unified payout item with plan + source tracking
569
+ interface SuperSmartItem {
570
+ id: number;
571
+ user_email: string;
572
+ crypto: string;
573
+ amount: number;
574
+ remaining_amount: number;
575
+ has_partial_payments: boolean;
576
+ paid_percentage: number;
577
+ plan: string;
578
+ source: 'regular' | 'tarpay';
579
+ }
580
+
581
+ // Build unified list from both sources
582
+ const allItems: SuperSmartItem[] = [
583
+ ...payouts.map((p) => ({
584
+ id: p.id,
585
+ user_email: p.user_email,
586
+ crypto: p.crypto_type,
587
+ amount: p.amount,
588
+ remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
589
+ has_partial_payments: p.has_partial_payments || false,
590
+ paid_percentage: p.paid_percentage || 0,
591
+ plan: p.plan,
592
+ source: 'regular' as const,
593
+ })),
594
+ ...tarPayPayouts.map((p) => ({
595
+ id: p.id,
596
+ user_email: p.user_email,
597
+ crypto: p.currency,
598
+ amount: parseFloat(p.amount),
599
+ remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
600
+ has_partial_payments: p.has_partial_payments || false,
601
+ paid_percentage: p.paid_percentage || 0,
602
+ plan: p.plan,
603
+ source: 'tarpay' as const,
604
+ })),
605
+ ];
606
+
607
+ // Group by currency across ALL plans
608
+ const byCurrency: Record<string, SuperSmartItem[]> = {};
609
+ allItems.forEach((p) => {
610
+ if (!byCurrency[p.crypto]) byCurrency[p.crypto] = [];
611
+ byCurrency[p.crypto].push(p);
612
+ });
613
+
614
+ const totalCount = allItems.length;
615
+ const totalAmount = allItems.reduce((sum, p) => sum + p.remaining_amount, 0);
616
+ const currencySummary = Object.entries(byCurrency)
617
+ .map(([crypto, items]) => `${chalk.bold(crypto)} ${items.length}`)
618
+ .join(' ');
619
+
620
+ // Show overview
621
+ console.log('');
622
+ console.log(chalk.cyan('╔═══ SUPER SMART ═══╗'));
623
+ console.log(chalk.cyan('║') + ` Pending: ${chalk.bold.yellow(String(totalCount))} payouts (${chalk.green('$' + Math.round(totalAmount).toLocaleString())})`);
624
+ console.log(chalk.cyan('║') + ` ${currencySummary}`);
625
+ console.log(chalk.cyan('╚════════════════════╝'));
626
+ console.log('');
627
+
628
+ if (totalCount === 0) {
629
+ console.log(chalk.green(' ✓ No pending payouts\n'));
630
+ return;
631
+ }
632
+
633
+ // Step 1: Select currency (with back option)
634
+ const currencies = Object.keys(byCurrency);
635
+ let selectedCurrency: string;
636
+
637
+ if (currencies.length === 1) {
638
+ selectedCurrency = currencies[0];
639
+ } else {
640
+ const currencyChoices = [
641
+ { name: chalk.dim('← Back'), value: '__back__' },
642
+ ...currencies.map((c) => {
643
+ const items = byCurrency[c];
644
+ const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
645
+ return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
646
+ }),
647
+ ];
648
+
649
+ const { currency } = await inquirer.prompt([
650
+ {
651
+ type: 'list',
652
+ name: 'currency',
653
+ message: 'Select currency:',
654
+ choices: currencyChoices,
655
+ },
656
+ ]);
657
+
658
+ if (currency === '__back__') return;
659
+ selectedCurrency = currency;
660
+ }
661
+
662
+ const currencyItems = byCurrency[selectedCurrency];
663
+
664
+ // Show plan breakdown for selected currency
665
+ const byPlan: Record<string, SuperSmartItem[]> = {};
666
+ currencyItems.forEach((p) => {
667
+ if (!byPlan[p.plan]) byPlan[p.plan] = [];
668
+ byPlan[p.plan].push(p);
669
+ });
670
+
671
+ console.log(`\n ${chalk.bold(selectedCurrency)} - ${currencyItems.length} payouts:`);
672
+ Object.entries(byPlan).forEach(([plan, items]) => {
673
+ const planTotal = items.reduce((sum, p) => sum + p.remaining_amount, 0);
674
+ const icon = PLAN_ICONS[plan] || '📋';
675
+ const color = PLAN_COLORS[plan] || chalk.white;
676
+ console.log(` ${icon} ${color(plan.toUpperCase().padEnd(12))} ${String(items.length).padStart(2)} │ ${chalk.green(formatAmount(planTotal, selectedCurrency))}`);
677
+ });
678
+ console.log('');
679
+
680
+ const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
681
+
682
+ // Step 2: Ask available amount (with back)
683
+ const { availableAmount } = await inquirer.prompt([
684
+ {
685
+ type: 'input',
686
+ name: 'availableAmount',
687
+ message: `How much ${selectedCurrency} available? (pending: ${formatAmount(totalPending, selectedCurrency)})`,
688
+ validate: (input: string) => {
689
+ if (input.toLowerCase() === 'back' || input.toLowerCase() === 'q') return true;
690
+ const num = parseFloat(input);
691
+ if (isNaN(num) || num <= 0) return 'Enter a positive number (or "back" to go back)';
692
+ return true;
693
+ },
694
+ },
695
+ ]);
696
+
697
+ if (availableAmount.toLowerCase() === 'back' || availableAmount.toLowerCase() === 'q') return;
698
+
699
+ const available = parseFloat(availableAmount);
700
+ const smartPercentage = Math.min((available / totalPending) * 100, 100);
701
+ const roundedPct = Math.round(smartPercentage * 100) / 100;
702
+
703
+ // Plan abbreviations for preview
704
+ const PLAN_ABBREV: Record<string, string> = {
705
+ hermes: 'HRM',
706
+ alpha: 'ALP',
707
+ mematic: 'MEM',
708
+ validator_v2: 'V2',
709
+ booster: 'BST',
710
+ dumpster: 'DMP',
711
+ christmas: 'XMS',
712
+ recovery: 'RCV',
713
+ };
714
+
715
+ // Show preview with plan labels
716
+ console.log('\n' + chalk.cyan(` Processing ${chalk.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
717
+ console.log(chalk.dim(' ─────────────────────────────'));
718
+
719
+ let previewTotal = 0;
720
+ currencyItems.forEach((p) => {
721
+ const willPay = p.remaining_amount * (smartPercentage / 100);
722
+ previewTotal += willPay;
723
+ const email = p.user_email.length > 20 ? p.user_email.substring(0, 18) + '..' : p.user_email;
724
+ const abbrev = PLAN_ABBREV[p.plan] || p.plan.substring(0, 3).toUpperCase();
725
+ const planColor = PLAN_COLORS[p.plan] || chalk.white;
726
+ console.log(` ${chalk.dim('#' + p.id)} ${planColor('[' + abbrev + ']')} ${email.padEnd(20)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(14)} → pays ${chalk.green(formatAmount(willPay, selectedCurrency))}`);
727
+ });
728
+
729
+ console.log(chalk.dim(' ─────────────────────────────'));
730
+ console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(previewTotal, selectedCurrency))}\n`));
731
+
732
+ // Step 3: Confirm
733
+ const { confirmSmart } = await inquirer.prompt([
734
+ {
735
+ type: 'confirm',
736
+ name: 'confirmSmart',
737
+ message: chalk.yellow(`⚠️ Pay ${roundedPct}% of ${currencyItems.length} payout(s)?`),
738
+ default: false,
739
+ },
740
+ ]);
741
+
742
+ if (confirmSmart) {
743
+ // Split by source for correct API calls
744
+ const regularIds = currencyItems.filter((p) => p.source === 'regular').map((p) => p.id);
745
+ const tarPayIds = currencyItems.filter((p) => p.source === 'tarpay').map((p) => p.id);
746
+
747
+ if (regularIds.length > 0) {
748
+ await processPayoutsWithProgress(regularIds, 'partial', roundedPct);
749
+ }
750
+ if (tarPayIds.length > 0) {
751
+ await processChristmasPayoutsWithProgress(tarPayIds, 'partial', roundedPct);
752
+ }
753
+ } else {
754
+ console.log(chalk.dim('\n Cancelled\n'));
755
+ }
756
+ } catch (e: any) {
757
+ spinner.stop();
758
+ console.log(chalk.red(` Error: ${e.message}\n`));
759
+ }
760
+ };
761
+
552
762
  const runInteractiveShell = async () => {
553
763
  setTitle('Mission Control');
554
764
  await showDashboard();
@@ -595,6 +805,9 @@ const runInteractiveShell = async () => {
595
805
  } else if (cmd === '4') {
596
806
  setTitle('Urgent');
597
807
  await showUrgentCmd();
808
+ } else if (cmd === '5' || cmd === 'queue' || cmd === 'sq' || cmd === 'super' || cmd === 'ss') {
809
+ await runSuperSmartDirect();
810
+ await showDashboard();
598
811
  } else {
599
812
  // Regular commands
600
813
  switch (mainCmd) {
@@ -1679,114 +1892,11 @@ const runChristmasPayoutsShell = async () => {
1679
1892
  }
1680
1893
  break;
1681
1894
  case 'smart':
1682
- case 'sp': {
1683
- // Smart partial: pay by available balance for Christmas
1684
- const xmasSmartSpinner = ora('Loading Christmas payouts...').start();
1685
- try {
1686
- const xmasData = await api.getTarPayPayouts({
1687
- plan: 'christmas',
1688
- status: 'pending_review',
1689
- limit: 500,
1690
- });
1691
- const xmasPayouts: TarPayPayout[] = xmasData.results || [];
1692
- xmasSmartSpinner.stop();
1693
-
1694
- if (xmasPayouts.length === 0) {
1695
- console.log(chalk.green('\n ✓ No pending Christmas payouts\n'));
1696
- break;
1697
- }
1698
-
1699
- // Group by currency
1700
- const xmasByCurrency: Record<string, TarPayPayout[]> = {};
1701
- xmasPayouts.forEach((p) => {
1702
- if (!xmasByCurrency[p.currency]) xmasByCurrency[p.currency] = [];
1703
- xmasByCurrency[p.currency].push(p);
1704
- });
1705
-
1706
- const xmasCurrencies = Object.keys(xmasByCurrency);
1707
- console.log('\n' + chalk.red(` 🎄 CHRISTMAS - Pending Payouts`));
1708
- console.log(chalk.dim(' ─────────────────────────────'));
1709
- xmasCurrencies.forEach((crypto) => {
1710
- const items = xmasByCurrency[crypto];
1711
- const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1712
- console.log(` ${chalk.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk.green(formatAmount(total, crypto))}`);
1713
- });
1714
- console.log('');
1715
-
1716
- let xmasCurrency: string;
1717
- if (xmasCurrencies.length === 1) {
1718
- xmasCurrency = xmasCurrencies[0];
1719
- } else {
1720
- const { currency } = await inquirer.prompt([
1721
- {
1722
- type: 'list',
1723
- name: 'currency',
1724
- message: 'Which currency to process?',
1725
- choices: xmasCurrencies.map((c) => {
1726
- const items = xmasByCurrency[c];
1727
- const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1728
- return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
1729
- }),
1730
- },
1731
- ]);
1732
- xmasCurrency = currency;
1733
- }
1734
-
1735
- const xmasCurrencyPayouts = xmasByCurrency[xmasCurrency];
1736
- const xmasTotalPending = xmasCurrencyPayouts.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1737
-
1738
- const { xmasAvailable } = await inquirer.prompt([
1739
- {
1740
- type: 'input',
1741
- name: 'xmasAvailable',
1742
- message: `How much ${xmasCurrency} do you have available? (total pending: ${formatAmount(xmasTotalPending, xmasCurrency)})`,
1743
- validate: (input: string) => {
1744
- const num = parseFloat(input);
1745
- if (isNaN(num) || num <= 0) return 'Please enter a positive number';
1746
- return true;
1747
- },
1748
- },
1749
- ]);
1750
-
1751
- const xmasAvailNum = parseFloat(xmasAvailable);
1752
- const xmasPct = Math.min((xmasAvailNum / xmasTotalPending) * 100, 100);
1753
- const xmasRoundedPct = Math.round(xmasPct * 100) / 100;
1754
-
1755
- console.log('\n' + chalk.cyan(` Processing ${chalk.bold(xmasRoundedPct + '%')} of ${xmasCurrencyPayouts.length} ${xmasCurrency} payouts (${formatAmount(xmasAvailNum, xmasCurrency)} / ${formatAmount(xmasTotalPending, xmasCurrency)})`));
1756
- console.log(chalk.dim(' ─────────────────────────────'));
1757
-
1758
- let xmasPreviewTotal = 0;
1759
- xmasCurrencyPayouts.forEach((p) => {
1760
- const displayAmt = p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount);
1761
- const willPay = displayAmt * (xmasPct / 100);
1762
- xmasPreviewTotal += willPay;
1763
- const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
1764
- console.log(` ${chalk.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(displayAmt, xmasCurrency).padStart(16)} → pays ${chalk.green(formatAmount(willPay, xmasCurrency))}`);
1765
- });
1766
-
1767
- console.log(chalk.dim(' ─────────────────────────────'));
1768
- console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(xmasPreviewTotal, xmasCurrency))}\n`));
1769
-
1770
- const { confirmXmasSmart } = await inquirer.prompt([
1771
- {
1772
- type: 'confirm',
1773
- name: 'confirmXmasSmart',
1774
- message: chalk.yellow(`⚠️ Pay ${xmasRoundedPct}% of ${xmasCurrencyPayouts.length} payout(s)?`),
1775
- default: false,
1776
- },
1777
- ]);
1778
-
1779
- if (confirmXmasSmart) {
1780
- const xmasSmartIds = xmasCurrencyPayouts.map((p) => p.id);
1781
- await processChristmasPayoutsWithProgress(xmasSmartIds, 'partial', xmasRoundedPct);
1782
- } else {
1783
- console.log(chalk.dim('\n Cancelled\n'));
1784
- }
1785
- } catch (e: any) {
1786
- xmasSmartSpinner.fail(chalk.red('Failed to load Christmas payouts'));
1787
- }
1895
+ case 'sp':
1896
+ case 'super':
1897
+ case 'ss':
1898
+ await runSuperSmartDirect();
1788
1899
  break;
1789
- }
1790
1900
  case 'help':
1791
1901
  case '?':
1792
1902
  console.log(chalk.red('\n 🎄 Christmas Payout Commands:'));
@@ -1799,7 +1909,7 @@ const runChristmasPayoutsShell = async () => {
1799
1909
  console.log(' select, s Interactive selection mode');
1800
1910
  console.log(' approve, a Select & approve payouts');
1801
1911
  console.log(chalk.cyan(' partial, p Select & pay partial %'));
1802
- console.log(chalk.cyan(' smart, sp Smart partial: pay by available balance'));
1912
+ console.log(chalk.cyan(' smart, sp, ss Super Smart: pay by currency across all plans'));
1803
1913
  console.log(' reject Select & reject payouts');
1804
1914
  console.log(' back, q Return to main payouts');
1805
1915
  console.log(chalk.dim('\n Note: Payouts > $50 need approval, < $50 auto-sent'));
@@ -1989,180 +2099,9 @@ const runPayoutsShell = async () => {
1989
2099
  break;
1990
2100
  case 'smart':
1991
2101
  case 'sp':
1992
- // Smart partial: pay by available balance
1993
- const { smartPlan } = await inquirer.prompt([
1994
- {
1995
- type: 'list',
1996
- name: 'smartPlan',
1997
- message: 'Select plan:',
1998
- choices: [
1999
- { name: `${PLAN_ICONS.hermes || '⚡'} Hermes`, value: 'hermes' },
2000
- { name: `${PLAN_ICONS.alpha || '🔷'} Alpha`, value: 'alpha' },
2001
- { name: `${PLAN_ICONS.mematic || '💎'} Mematic`, value: 'mematic' },
2002
- { name: `${PLAN_ICONS.validator_v2 || '🔐'} Validator V2`, value: 'validator_v2' },
2003
- { name: `${PLAN_ICONS.booster || '🚀'} Booster`, value: 'booster' },
2004
- { name: `${PLAN_ICONS.christmas || '🎄'} Christmas`, value: 'christmas' },
2005
- { name: '🔄 Recovery', value: 'recovery' },
2006
- { name: '📋 All Plans', value: undefined },
2007
- ],
2008
- },
2009
- ]);
2010
-
2011
- const isTarPayPlan = smartPlan === 'christmas';
2012
- const smartSpinner = ora('Loading pending payouts...').start();
2013
- try {
2014
- // Unified payout items with common shape
2015
- interface SmartPayoutItem {
2016
- id: number;
2017
- user_email: string;
2018
- crypto: string;
2019
- amount: number;
2020
- remaining_amount: number;
2021
- has_partial_payments: boolean;
2022
- paid_percentage: number;
2023
- }
2024
-
2025
- let smartItems: SmartPayoutItem[] = [];
2026
-
2027
- if (isTarPayPlan) {
2028
- // TarPay payouts (Christmas, etc.)
2029
- const tarData = await api.getTarPayPayouts({
2030
- plan: smartPlan,
2031
- status: 'pending_review',
2032
- limit: 500,
2033
- });
2034
- const tarPayouts: TarPayPayout[] = tarData.results || [];
2035
- smartItems = tarPayouts.map((p) => ({
2036
- id: p.id,
2037
- user_email: p.user_email,
2038
- crypto: p.currency,
2039
- amount: parseFloat(p.amount),
2040
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
2041
- has_partial_payments: p.has_partial_payments || false,
2042
- paid_percentage: p.paid_percentage || 0,
2043
- }));
2044
- } else {
2045
- // Regular payouts
2046
- const smartParams: any = { status: 'pending', limit: 500 };
2047
- if (smartPlan) smartParams.plan = smartPlan;
2048
- const smartData = await api.listPayouts(smartParams);
2049
- const smartPayouts: Payout[] = smartData.data || [];
2050
- smartItems = smartPayouts.map((p) => ({
2051
- id: p.id,
2052
- user_email: p.user_email,
2053
- crypto: p.crypto_type,
2054
- amount: p.amount,
2055
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
2056
- has_partial_payments: p.has_partial_payments || false,
2057
- paid_percentage: p.paid_percentage || 0,
2058
- }));
2059
- }
2060
- smartSpinner.stop();
2061
-
2062
- if (smartItems.length === 0) {
2063
- console.log(chalk.green('\n ✓ No pending payouts found\n'));
2064
- break;
2065
- }
2066
-
2067
- // Group by crypto
2068
- const byCurrency: Record<string, SmartPayoutItem[]> = {};
2069
- smartItems.forEach((p) => {
2070
- if (!byCurrency[p.crypto]) byCurrency[p.crypto] = [];
2071
- byCurrency[p.crypto].push(p);
2072
- });
2073
-
2074
- const currencies = Object.keys(byCurrency);
2075
- const planLabel = smartPlan ? smartPlan.toUpperCase() : 'ALL PLANS';
2076
- const planColor = smartPlan ? (PLAN_COLORS[smartPlan] || chalk.white) : chalk.white;
2077
-
2078
- console.log('\n' + planColor(` 📋 ${planLabel} - Pending Payouts`));
2079
- console.log(chalk.dim(' ─────────────────────────────'));
2080
- currencies.forEach((crypto) => {
2081
- const items = byCurrency[crypto];
2082
- const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
2083
- console.log(` ${chalk.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk.green(formatAmount(total, crypto))}`);
2084
- });
2085
- console.log('');
2086
-
2087
- // Select currency
2088
- let selectedCurrency: string;
2089
- if (currencies.length === 1) {
2090
- selectedCurrency = currencies[0];
2091
- } else {
2092
- const { currency } = await inquirer.prompt([
2093
- {
2094
- type: 'list',
2095
- name: 'currency',
2096
- message: 'Which currency to process?',
2097
- choices: currencies.map((c) => {
2098
- const items = byCurrency[c];
2099
- const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
2100
- return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
2101
- }),
2102
- },
2103
- ]);
2104
- selectedCurrency = currency;
2105
- }
2106
-
2107
- const currencyItems = byCurrency[selectedCurrency];
2108
- const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
2109
-
2110
- // Ask available amount
2111
- const { availableAmount } = await inquirer.prompt([
2112
- {
2113
- type: 'input',
2114
- name: 'availableAmount',
2115
- message: `How much ${selectedCurrency} do you have available? (total pending: ${formatAmount(totalPending, selectedCurrency)})`,
2116
- validate: (input: string) => {
2117
- const num = parseFloat(input);
2118
- if (isNaN(num) || num <= 0) return 'Please enter a positive number';
2119
- return true;
2120
- },
2121
- },
2122
- ]);
2123
-
2124
- const available = parseFloat(availableAmount);
2125
- const smartPercentage = Math.min((available / totalPending) * 100, 100);
2126
- const roundedPct = Math.round(smartPercentage * 100) / 100;
2127
-
2128
- // Show breakdown
2129
- console.log('\n' + chalk.cyan(` Processing ${chalk.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
2130
- console.log(chalk.dim(' ─────────────────────────────'));
2131
-
2132
- let previewTotal = 0;
2133
- currencyItems.forEach((p) => {
2134
- const willPay = p.remaining_amount * (smartPercentage / 100);
2135
- previewTotal += willPay;
2136
- const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
2137
- console.log(` ${chalk.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(16)} → pays ${chalk.green(formatAmount(willPay, selectedCurrency))}`);
2138
- });
2139
-
2140
- console.log(chalk.dim(' ─────────────────────────────'));
2141
- console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(previewTotal, selectedCurrency))}\n`));
2142
-
2143
- // Confirm
2144
- const { confirmSmart } = await inquirer.prompt([
2145
- {
2146
- type: 'confirm',
2147
- name: 'confirmSmart',
2148
- message: chalk.yellow(`⚠️ Pay ${roundedPct}% of ${currencyItems.length} payout(s)?`),
2149
- default: false,
2150
- },
2151
- ]);
2152
-
2153
- if (confirmSmart) {
2154
- const smartIds = currencyItems.map((p) => p.id);
2155
- if (isTarPayPlan) {
2156
- await processChristmasPayoutsWithProgress(smartIds, 'partial', roundedPct);
2157
- } else {
2158
- await processPayoutsWithProgress(smartIds, 'partial', roundedPct);
2159
- }
2160
- } else {
2161
- console.log(chalk.dim('\n Cancelled\n'));
2162
- }
2163
- } catch (e: any) {
2164
- smartSpinner.fail(chalk.red('Failed to load payouts'));
2165
- }
2102
+ case 'super':
2103
+ case 'ss':
2104
+ await runSuperSmartDirect();
2166
2105
  break;
2167
2106
  case 'hermes':
2168
2107
  case 'alpha':
@@ -2252,7 +2191,7 @@ const runPayoutsShell = async () => {
2252
2191
  console.log(' select [plan] Interactive payout selection');
2253
2192
  console.log(' approve [ids] Approve payouts (interactive if no IDs)');
2254
2193
  console.log(chalk.cyan(' partial, p Pay partial % (repayment mode)'));
2255
- console.log(chalk.cyan(' smart, sp Smart partial: pay by available balance'));
2194
+ console.log(chalk.cyan(' smart, sp, ss Super Smart: pay by currency across all plans'));
2256
2195
  console.log(chalk.yellow(' all Approve ALL pending payouts'));
2257
2196
  console.log(' cancel [ids] Cancel payouts (interactive if no IDs)');
2258
2197
  console.log(' process Process payouts by plan (interactive)');