@targlobal/mission-control 1.5.7 → 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.7",
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('[5]')}Q ` + 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('[5]')} Queue ` + 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,78 +549,24 @@ const showDashboard = async () => {
549
549
  }
550
550
  };
551
551
 
552
- const runSmartQueueDirect = async () => {
553
- setTitle('Smart Queue');
554
- const spinner = ora('Loading queue...').start();
552
+ const runSuperSmartDirect = async () => {
553
+ setTitle('Super Smart');
554
+ const spinner = ora('Loading all pending payouts...').start();
555
555
 
556
556
  try {
557
- // Fetch metrics + all pending payouts in parallel
558
- const [metricsRes, payoutsRes, tarPayRes] = await Promise.all([
559
- api.getPayoutMetrics(),
557
+ // Fetch all pending payouts in parallel across all plans
558
+ const [payoutsRes, tarPayRes] = await Promise.all([
560
559
  api.listPayouts({ status: 'pending', limit: 500 }),
561
560
  api.getTarPayPayouts({ status: 'pending_review', limit: 500 }),
562
561
  ]);
563
562
 
564
- const metrics: PayoutMetrics = metricsRes.data;
565
563
  const payouts: Payout[] = payoutsRes.data || [];
566
564
  const tarPayPayouts: TarPayPayout[] = tarPayRes.results || [];
567
565
 
568
566
  spinner.stop();
569
567
 
570
- // Build plan summary from regular payouts
571
- const byPlan: Record<string, number> = {};
572
- payouts.forEach((p) => {
573
- byPlan[p.plan] = (byPlan[p.plan] || 0) + 1;
574
- });
575
- // Add TarPay payouts
576
- tarPayPayouts.forEach((p) => {
577
- byPlan[p.plan] = (byPlan[p.plan] || 0) + 1;
578
- });
579
-
580
- const totalCount = payouts.length + tarPayPayouts.length;
581
- const planSummary = Object.entries(byPlan)
582
- .map(([plan, count]) => `${(PLAN_ICONS[plan] || '📋')} ${plan.toUpperCase()} ${count}`)
583
- .join(' ');
584
-
585
- // Show overview
586
- console.log('');
587
- console.log(chalk.cyan('╔═══ SMART QUEUE ═══╗'));
588
- console.log(chalk.cyan('║') + ` Pending: ${chalk.bold.yellow(String(totalCount))} payouts (${chalk.green('$' + metrics.pending_amount.toLocaleString())})` );
589
- console.log(chalk.cyan('║') + ` ${planSummary}`);
590
- console.log(chalk.cyan('╚═══════════════════╝'));
591
- console.log('');
592
-
593
- if (totalCount === 0) {
594
- console.log(chalk.green(' ✓ No pending payouts\n'));
595
- return;
596
- }
597
-
598
- // Step 1: Select plan (with back option)
599
- const planChoices = [
600
- { name: chalk.dim('← Back'), value: '__back__' },
601
- ...Object.entries(byPlan).map(([plan, count]) => ({
602
- name: `${PLAN_ICONS[plan] || '📋'} ${plan.charAt(0).toUpperCase() + plan.slice(1)} (${count})`,
603
- value: plan,
604
- })),
605
- { name: '📋 All Plans', value: '__all__' },
606
- ];
607
-
608
- const { selectedPlan } = await inquirer.prompt([
609
- {
610
- type: 'list',
611
- name: 'selectedPlan',
612
- message: 'Select plan:',
613
- choices: planChoices,
614
- },
615
- ]);
616
-
617
- if (selectedPlan === '__back__') return;
618
-
619
- const isTarPayPlan = selectedPlan === 'christmas';
620
- const planFilter = selectedPlan === '__all__' ? undefined : selectedPlan;
621
-
622
- // Unified payout items
623
- interface SmartPayoutItem {
568
+ // Unified payout item with plan + source tracking
569
+ interface SuperSmartItem {
624
570
  id: number;
625
571
  user_email: string;
626
572
  crypto: string;
@@ -628,63 +574,66 @@ const runSmartQueueDirect = async () => {
628
574
  remaining_amount: number;
629
575
  has_partial_payments: boolean;
630
576
  paid_percentage: number;
631
- }
632
-
633
- let smartItems: SmartPayoutItem[] = [];
634
-
635
- if (isTarPayPlan) {
636
- smartItems = tarPayPayouts
637
- .filter((p) => !planFilter || p.plan === planFilter)
638
- .map((p) => ({
639
- id: p.id,
640
- user_email: p.user_email,
641
- crypto: p.currency,
642
- amount: parseFloat(p.amount),
643
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
644
- has_partial_payments: p.has_partial_payments || false,
645
- paid_percentage: p.paid_percentage || 0,
646
- }));
647
- } else {
648
- smartItems = payouts
649
- .filter((p) => !planFilter || p.plan === planFilter)
650
- .map((p) => ({
651
- id: p.id,
652
- user_email: p.user_email,
653
- crypto: p.crypto_type,
654
- amount: p.amount,
655
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
656
- has_partial_payments: p.has_partial_payments || false,
657
- paid_percentage: p.paid_percentage || 0,
658
- }));
659
- }
660
-
661
- if (smartItems.length === 0) {
662
- console.log(chalk.green('\n ✓ No pending payouts for this plan\n'));
663
- return;
664
- }
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
+ ];
665
606
 
666
- // Group by currency
667
- const byCurrency: Record<string, SmartPayoutItem[]> = {};
668
- smartItems.forEach((p) => {
607
+ // Group by currency across ALL plans
608
+ const byCurrency: Record<string, SuperSmartItem[]> = {};
609
+ allItems.forEach((p) => {
669
610
  if (!byCurrency[p.crypto]) byCurrency[p.crypto] = [];
670
611
  byCurrency[p.crypto].push(p);
671
612
  });
672
613
 
673
- const currencies = Object.keys(byCurrency);
674
- const planLabel = planFilter ? planFilter.toUpperCase() : 'ALL PLANS';
675
- const planColor = planFilter ? (PLAN_COLORS[planFilter] || chalk.white) : chalk.white;
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(' ');
676
619
 
677
- console.log('\n' + planColor(` 📋 ${planLabel} - Pending Payouts`));
678
- console.log(chalk.dim(' ─────────────────────────────'));
679
- currencies.forEach((crypto) => {
680
- const items = byCurrency[crypto];
681
- const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
682
- console.log(` ${chalk.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk.green(formatAmount(total, crypto))}`);
683
- });
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('╚════════════════════╝'));
684
626
  console.log('');
685
627
 
686
- // Step 2: Select currency (with back, skip if only one)
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);
687
635
  let selectedCurrency: string;
636
+
688
637
  if (currencies.length === 1) {
689
638
  selectedCurrency = currencies[0];
690
639
  } else {
@@ -701,7 +650,7 @@ const runSmartQueueDirect = async () => {
701
650
  {
702
651
  type: 'list',
703
652
  name: 'currency',
704
- message: 'Which currency to process?',
653
+ message: 'Select currency:',
705
654
  choices: currencyChoices,
706
655
  },
707
656
  ]);
@@ -711,9 +660,26 @@ const runSmartQueueDirect = async () => {
711
660
  }
712
661
 
713
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
+
714
680
  const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
715
681
 
716
- // Step 3: Ask available amount (with back)
682
+ // Step 2: Ask available amount (with back)
717
683
  const { availableAmount } = await inquirer.prompt([
718
684
  {
719
685
  type: 'input',
@@ -734,7 +700,19 @@ const runSmartQueueDirect = async () => {
734
700
  const smartPercentage = Math.min((available / totalPending) * 100, 100);
735
701
  const roundedPct = Math.round(smartPercentage * 100) / 100;
736
702
 
737
- // Show preview
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
738
716
  console.log('\n' + chalk.cyan(` Processing ${chalk.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
739
717
  console.log(chalk.dim(' ─────────────────────────────'));
740
718
 
@@ -742,14 +720,16 @@ const runSmartQueueDirect = async () => {
742
720
  currencyItems.forEach((p) => {
743
721
  const willPay = p.remaining_amount * (smartPercentage / 100);
744
722
  previewTotal += willPay;
745
- const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
746
- console.log(` ${chalk.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(16)} → pays ${chalk.green(formatAmount(willPay, selectedCurrency))}`);
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))}`);
747
727
  });
748
728
 
749
729
  console.log(chalk.dim(' ─────────────────────────────'));
750
730
  console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(previewTotal, selectedCurrency))}\n`));
751
731
 
752
- // Step 4: Confirm
732
+ // Step 3: Confirm
753
733
  const { confirmSmart } = await inquirer.prompt([
754
734
  {
755
735
  type: 'confirm',
@@ -760,11 +740,15 @@ const runSmartQueueDirect = async () => {
760
740
  ]);
761
741
 
762
742
  if (confirmSmart) {
763
- const smartIds = currencyItems.map((p) => p.id);
764
- if (isTarPayPlan) {
765
- await processChristmasPayoutsWithProgress(smartIds, 'partial', roundedPct);
766
- } else {
767
- await processPayoutsWithProgress(smartIds, 'partial', roundedPct);
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);
768
752
  }
769
753
  } else {
770
754
  console.log(chalk.dim('\n Cancelled\n'));
@@ -821,8 +805,8 @@ const runInteractiveShell = async () => {
821
805
  } else if (cmd === '4') {
822
806
  setTitle('Urgent');
823
807
  await showUrgentCmd();
824
- } else if (cmd === '5' || cmd === 'queue' || cmd === 'sq') {
825
- await runSmartQueueDirect();
808
+ } else if (cmd === '5' || cmd === 'queue' || cmd === 'sq' || cmd === 'super' || cmd === 'ss') {
809
+ await runSuperSmartDirect();
826
810
  await showDashboard();
827
811
  } else {
828
812
  // Regular commands
@@ -1908,114 +1892,11 @@ const runChristmasPayoutsShell = async () => {
1908
1892
  }
1909
1893
  break;
1910
1894
  case 'smart':
1911
- case 'sp': {
1912
- // Smart partial: pay by available balance for Christmas
1913
- const xmasSmartSpinner = ora('Loading Christmas payouts...').start();
1914
- try {
1915
- const xmasData = await api.getTarPayPayouts({
1916
- plan: 'christmas',
1917
- status: 'pending_review',
1918
- limit: 500,
1919
- });
1920
- const xmasPayouts: TarPayPayout[] = xmasData.results || [];
1921
- xmasSmartSpinner.stop();
1922
-
1923
- if (xmasPayouts.length === 0) {
1924
- console.log(chalk.green('\n ✓ No pending Christmas payouts\n'));
1925
- break;
1926
- }
1927
-
1928
- // Group by currency
1929
- const xmasByCurrency: Record<string, TarPayPayout[]> = {};
1930
- xmasPayouts.forEach((p) => {
1931
- if (!xmasByCurrency[p.currency]) xmasByCurrency[p.currency] = [];
1932
- xmasByCurrency[p.currency].push(p);
1933
- });
1934
-
1935
- const xmasCurrencies = Object.keys(xmasByCurrency);
1936
- console.log('\n' + chalk.red(` 🎄 CHRISTMAS - Pending Payouts`));
1937
- console.log(chalk.dim(' ─────────────────────────────'));
1938
- xmasCurrencies.forEach((crypto) => {
1939
- const items = xmasByCurrency[crypto];
1940
- const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1941
- console.log(` ${chalk.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk.green(formatAmount(total, crypto))}`);
1942
- });
1943
- console.log('');
1944
-
1945
- let xmasCurrency: string;
1946
- if (xmasCurrencies.length === 1) {
1947
- xmasCurrency = xmasCurrencies[0];
1948
- } else {
1949
- const { currency } = await inquirer.prompt([
1950
- {
1951
- type: 'list',
1952
- name: 'currency',
1953
- message: 'Which currency to process?',
1954
- choices: xmasCurrencies.map((c) => {
1955
- const items = xmasByCurrency[c];
1956
- const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1957
- return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
1958
- }),
1959
- },
1960
- ]);
1961
- xmasCurrency = currency;
1962
- }
1963
-
1964
- const xmasCurrencyPayouts = xmasByCurrency[xmasCurrency];
1965
- const xmasTotalPending = xmasCurrencyPayouts.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1966
-
1967
- const { xmasAvailable } = await inquirer.prompt([
1968
- {
1969
- type: 'input',
1970
- name: 'xmasAvailable',
1971
- message: `How much ${xmasCurrency} do you have available? (total pending: ${formatAmount(xmasTotalPending, xmasCurrency)})`,
1972
- validate: (input: string) => {
1973
- const num = parseFloat(input);
1974
- if (isNaN(num) || num <= 0) return 'Please enter a positive number';
1975
- return true;
1976
- },
1977
- },
1978
- ]);
1979
-
1980
- const xmasAvailNum = parseFloat(xmasAvailable);
1981
- const xmasPct = Math.min((xmasAvailNum / xmasTotalPending) * 100, 100);
1982
- const xmasRoundedPct = Math.round(xmasPct * 100) / 100;
1983
-
1984
- console.log('\n' + chalk.cyan(` Processing ${chalk.bold(xmasRoundedPct + '%')} of ${xmasCurrencyPayouts.length} ${xmasCurrency} payouts (${formatAmount(xmasAvailNum, xmasCurrency)} / ${formatAmount(xmasTotalPending, xmasCurrency)})`));
1985
- console.log(chalk.dim(' ─────────────────────────────'));
1986
-
1987
- let xmasPreviewTotal = 0;
1988
- xmasCurrencyPayouts.forEach((p) => {
1989
- const displayAmt = p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount);
1990
- const willPay = displayAmt * (xmasPct / 100);
1991
- xmasPreviewTotal += willPay;
1992
- const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
1993
- console.log(` ${chalk.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(displayAmt, xmasCurrency).padStart(16)} → pays ${chalk.green(formatAmount(willPay, xmasCurrency))}`);
1994
- });
1995
-
1996
- console.log(chalk.dim(' ─────────────────────────────'));
1997
- console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(xmasPreviewTotal, xmasCurrency))}\n`));
1998
-
1999
- const { confirmXmasSmart } = await inquirer.prompt([
2000
- {
2001
- type: 'confirm',
2002
- name: 'confirmXmasSmart',
2003
- message: chalk.yellow(`⚠️ Pay ${xmasRoundedPct}% of ${xmasCurrencyPayouts.length} payout(s)?`),
2004
- default: false,
2005
- },
2006
- ]);
2007
-
2008
- if (confirmXmasSmart) {
2009
- const xmasSmartIds = xmasCurrencyPayouts.map((p) => p.id);
2010
- await processChristmasPayoutsWithProgress(xmasSmartIds, 'partial', xmasRoundedPct);
2011
- } else {
2012
- console.log(chalk.dim('\n Cancelled\n'));
2013
- }
2014
- } catch (e: any) {
2015
- xmasSmartSpinner.fail(chalk.red('Failed to load Christmas payouts'));
2016
- }
1895
+ case 'sp':
1896
+ case 'super':
1897
+ case 'ss':
1898
+ await runSuperSmartDirect();
2017
1899
  break;
2018
- }
2019
1900
  case 'help':
2020
1901
  case '?':
2021
1902
  console.log(chalk.red('\n 🎄 Christmas Payout Commands:'));
@@ -2028,7 +1909,7 @@ const runChristmasPayoutsShell = async () => {
2028
1909
  console.log(' select, s Interactive selection mode');
2029
1910
  console.log(' approve, a Select & approve payouts');
2030
1911
  console.log(chalk.cyan(' partial, p Select & pay partial %'));
2031
- 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'));
2032
1913
  console.log(' reject Select & reject payouts');
2033
1914
  console.log(' back, q Return to main payouts');
2034
1915
  console.log(chalk.dim('\n Note: Payouts > $50 need approval, < $50 auto-sent'));
@@ -2218,180 +2099,9 @@ const runPayoutsShell = async () => {
2218
2099
  break;
2219
2100
  case 'smart':
2220
2101
  case 'sp':
2221
- // Smart partial: pay by available balance
2222
- const { smartPlan } = await inquirer.prompt([
2223
- {
2224
- type: 'list',
2225
- name: 'smartPlan',
2226
- message: 'Select plan:',
2227
- choices: [
2228
- { name: `${PLAN_ICONS.hermes || '⚡'} Hermes`, value: 'hermes' },
2229
- { name: `${PLAN_ICONS.alpha || '🔷'} Alpha`, value: 'alpha' },
2230
- { name: `${PLAN_ICONS.mematic || '💎'} Mematic`, value: 'mematic' },
2231
- { name: `${PLAN_ICONS.validator_v2 || '🔐'} Validator V2`, value: 'validator_v2' },
2232
- { name: `${PLAN_ICONS.booster || '🚀'} Booster`, value: 'booster' },
2233
- { name: `${PLAN_ICONS.christmas || '🎄'} Christmas`, value: 'christmas' },
2234
- { name: '🔄 Recovery', value: 'recovery' },
2235
- { name: '📋 All Plans', value: undefined },
2236
- ],
2237
- },
2238
- ]);
2239
-
2240
- const isTarPayPlan = smartPlan === 'christmas';
2241
- const smartSpinner = ora('Loading pending payouts...').start();
2242
- try {
2243
- // Unified payout items with common shape
2244
- interface SmartPayoutItem {
2245
- id: number;
2246
- user_email: string;
2247
- crypto: string;
2248
- amount: number;
2249
- remaining_amount: number;
2250
- has_partial_payments: boolean;
2251
- paid_percentage: number;
2252
- }
2253
-
2254
- let smartItems: SmartPayoutItem[] = [];
2255
-
2256
- if (isTarPayPlan) {
2257
- // TarPay payouts (Christmas, etc.)
2258
- const tarData = await api.getTarPayPayouts({
2259
- plan: smartPlan,
2260
- status: 'pending_review',
2261
- limit: 500,
2262
- });
2263
- const tarPayouts: TarPayPayout[] = tarData.results || [];
2264
- smartItems = tarPayouts.map((p) => ({
2265
- id: p.id,
2266
- user_email: p.user_email,
2267
- crypto: p.currency,
2268
- amount: parseFloat(p.amount),
2269
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
2270
- has_partial_payments: p.has_partial_payments || false,
2271
- paid_percentage: p.paid_percentage || 0,
2272
- }));
2273
- } else {
2274
- // Regular payouts
2275
- const smartParams: any = { status: 'pending', limit: 500 };
2276
- if (smartPlan) smartParams.plan = smartPlan;
2277
- const smartData = await api.listPayouts(smartParams);
2278
- const smartPayouts: Payout[] = smartData.data || [];
2279
- smartItems = smartPayouts.map((p) => ({
2280
- id: p.id,
2281
- user_email: p.user_email,
2282
- crypto: p.crypto_type,
2283
- amount: p.amount,
2284
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
2285
- has_partial_payments: p.has_partial_payments || false,
2286
- paid_percentage: p.paid_percentage || 0,
2287
- }));
2288
- }
2289
- smartSpinner.stop();
2290
-
2291
- if (smartItems.length === 0) {
2292
- console.log(chalk.green('\n ✓ No pending payouts found\n'));
2293
- break;
2294
- }
2295
-
2296
- // Group by crypto
2297
- const byCurrency: Record<string, SmartPayoutItem[]> = {};
2298
- smartItems.forEach((p) => {
2299
- if (!byCurrency[p.crypto]) byCurrency[p.crypto] = [];
2300
- byCurrency[p.crypto].push(p);
2301
- });
2302
-
2303
- const currencies = Object.keys(byCurrency);
2304
- const planLabel = smartPlan ? smartPlan.toUpperCase() : 'ALL PLANS';
2305
- const planColor = smartPlan ? (PLAN_COLORS[smartPlan] || chalk.white) : chalk.white;
2306
-
2307
- console.log('\n' + planColor(` 📋 ${planLabel} - Pending Payouts`));
2308
- console.log(chalk.dim(' ─────────────────────────────'));
2309
- currencies.forEach((crypto) => {
2310
- const items = byCurrency[crypto];
2311
- const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
2312
- console.log(` ${chalk.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk.green(formatAmount(total, crypto))}`);
2313
- });
2314
- console.log('');
2315
-
2316
- // Select currency
2317
- let selectedCurrency: string;
2318
- if (currencies.length === 1) {
2319
- selectedCurrency = currencies[0];
2320
- } else {
2321
- const { currency } = await inquirer.prompt([
2322
- {
2323
- type: 'list',
2324
- name: 'currency',
2325
- message: 'Which currency to process?',
2326
- choices: currencies.map((c) => {
2327
- const items = byCurrency[c];
2328
- const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
2329
- return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
2330
- }),
2331
- },
2332
- ]);
2333
- selectedCurrency = currency;
2334
- }
2335
-
2336
- const currencyItems = byCurrency[selectedCurrency];
2337
- const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
2338
-
2339
- // Ask available amount
2340
- const { availableAmount } = await inquirer.prompt([
2341
- {
2342
- type: 'input',
2343
- name: 'availableAmount',
2344
- message: `How much ${selectedCurrency} do you have available? (total pending: ${formatAmount(totalPending, selectedCurrency)})`,
2345
- validate: (input: string) => {
2346
- const num = parseFloat(input);
2347
- if (isNaN(num) || num <= 0) return 'Please enter a positive number';
2348
- return true;
2349
- },
2350
- },
2351
- ]);
2352
-
2353
- const available = parseFloat(availableAmount);
2354
- const smartPercentage = Math.min((available / totalPending) * 100, 100);
2355
- const roundedPct = Math.round(smartPercentage * 100) / 100;
2356
-
2357
- // Show breakdown
2358
- console.log('\n' + chalk.cyan(` Processing ${chalk.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
2359
- console.log(chalk.dim(' ─────────────────────────────'));
2360
-
2361
- let previewTotal = 0;
2362
- currencyItems.forEach((p) => {
2363
- const willPay = p.remaining_amount * (smartPercentage / 100);
2364
- previewTotal += willPay;
2365
- const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
2366
- console.log(` ${chalk.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(16)} → pays ${chalk.green(formatAmount(willPay, selectedCurrency))}`);
2367
- });
2368
-
2369
- console.log(chalk.dim(' ─────────────────────────────'));
2370
- console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(previewTotal, selectedCurrency))}\n`));
2371
-
2372
- // Confirm
2373
- const { confirmSmart } = await inquirer.prompt([
2374
- {
2375
- type: 'confirm',
2376
- name: 'confirmSmart',
2377
- message: chalk.yellow(`⚠️ Pay ${roundedPct}% of ${currencyItems.length} payout(s)?`),
2378
- default: false,
2379
- },
2380
- ]);
2381
-
2382
- if (confirmSmart) {
2383
- const smartIds = currencyItems.map((p) => p.id);
2384
- if (isTarPayPlan) {
2385
- await processChristmasPayoutsWithProgress(smartIds, 'partial', roundedPct);
2386
- } else {
2387
- await processPayoutsWithProgress(smartIds, 'partial', roundedPct);
2388
- }
2389
- } else {
2390
- console.log(chalk.dim('\n Cancelled\n'));
2391
- }
2392
- } catch (e: any) {
2393
- smartSpinner.fail(chalk.red('Failed to load payouts'));
2394
- }
2102
+ case 'super':
2103
+ case 'ss':
2104
+ await runSuperSmartDirect();
2395
2105
  break;
2396
2106
  case 'hermes':
2397
2107
  case 'alpha':
@@ -2481,7 +2191,7 @@ const runPayoutsShell = async () => {
2481
2191
  console.log(' select [plan] Interactive payout selection');
2482
2192
  console.log(' approve [ids] Approve payouts (interactive if no IDs)');
2483
2193
  console.log(chalk.cyan(' partial, p Pay partial % (repayment mode)'));
2484
- 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'));
2485
2195
  console.log(chalk.yellow(' all Approve ALL pending payouts'));
2486
2196
  console.log(' cancel [ids] Cancel payouts (interactive if no IDs)');
2487
2197
  console.log(' process Process payouts by plan (interactive)');