@targlobal/mission-control 1.5.7 → 1.5.9

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/dist/index.js CHANGED
@@ -503,7 +503,7 @@ const showDashboard = async () => {
503
503
  console.log(chalk_1.default.cyan('┌─────────────────────────────┐'));
504
504
  console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.bgCyan.black('TASKS')} ${chalk_1.default.bold.white(String(stats.my_tasks).padStart(3))} ${chalk_1.default.bgRed.white('CRIT')} ${chalk_1.default.bold.red(String(stats.critical_count).padStart(2))} ${chalk_1.default.bgYellow.black('OVR')} ${chalk_1.default.bold.yellow(String(stats.overdue_tasks).padStart(2))} ` + chalk_1.default.cyan('│'));
505
505
  console.log(chalk_1.default.cyan('├─────────────────────────────┤'));
506
- console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.cyan('[1]')}Tasks ${chalk_1.default.cyan('[2]')}New ${chalk_1.default.cyan('[3]')}Pay ${chalk_1.default.cyan('[4]')}Urg ${chalk_1.default.cyan('[5]')}Q ` + chalk_1.default.cyan('│'));
506
+ console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.cyan('[1]')}Tasks ${chalk_1.default.cyan('[2]')}New ${chalk_1.default.cyan('[3]')}Pay ${chalk_1.default.cyan('[4]')}Urg ${chalk_1.default.cyan('[5]')}Smart ` + chalk_1.default.cyan('│'));
507
507
  console.log(chalk_1.default.cyan('└─────────────────────────────┘'));
508
508
  console.log('');
509
509
  // Show urgent count only in compact mode
@@ -525,7 +525,7 @@ const showDashboard = async () => {
525
525
  console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
526
526
  console.log(chalk_1.default.cyan('╠══════════════════════════════════════════════════════════════════════╣'));
527
527
  console.log(chalk_1.default.cyan('║') + chalk_1.default.dim(' Quick Actions: ') + chalk_1.default.cyan('║'));
528
- console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.cyan('[1]')} My Tasks ${chalk_1.default.cyan('[2]')} New Task ${chalk_1.default.cyan('[3]')} Payouts ${chalk_1.default.cyan('[4]')} Urgent ${chalk_1.default.cyan('[5]')} Queue ` + chalk_1.default.cyan('║'));
528
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.cyan('[1]')} My Tasks ${chalk_1.default.cyan('[2]')} New Task ${chalk_1.default.cyan('[3]')} Payouts ${chalk_1.default.cyan('[4]')} Urgent ${chalk_1.default.cyan('[5]')} Smart ` + chalk_1.default.cyan('║'));
529
529
  console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
530
530
  console.log(chalk_1.default.cyan('╚══════════════════════════════════════════════════════════════════════╝'));
531
531
  console.log('');
@@ -545,115 +545,68 @@ const showDashboard = async () => {
545
545
  // Silently fail - show basic prompt
546
546
  }
547
547
  };
548
- const runSmartQueueDirect = async () => {
549
- setTitle('Smart Queue');
550
- const spinner = (0, ora_1.default)('Loading queue...').start();
548
+ const runSuperSmartDirect = async () => {
549
+ setTitle('Super Smart');
550
+ const spinner = (0, ora_1.default)('Loading all pending payouts...').start();
551
551
  try {
552
- // Fetch metrics + all pending payouts in parallel
553
- const [metricsRes, payoutsRes, tarPayRes] = await Promise.all([
554
- api_1.api.getPayoutMetrics(),
552
+ // Fetch all pending payouts in parallel across all plans
553
+ const [payoutsRes, tarPayRes] = await Promise.all([
555
554
  api_1.api.listPayouts({ status: 'pending', limit: 500 }),
556
555
  api_1.api.getTarPayPayouts({ status: 'pending_review', limit: 500 }),
557
556
  ]);
558
- const metrics = metricsRes.data;
559
557
  const payouts = payoutsRes.data || [];
560
558
  const tarPayPayouts = tarPayRes.results || [];
561
559
  spinner.stop();
562
- // Build plan summary from regular payouts
563
- const byPlan = {};
564
- payouts.forEach((p) => {
565
- byPlan[p.plan] = (byPlan[p.plan] || 0) + 1;
566
- });
567
- // Add TarPay payouts
568
- tarPayPayouts.forEach((p) => {
569
- byPlan[p.plan] = (byPlan[p.plan] || 0) + 1;
570
- });
571
- const totalCount = payouts.length + tarPayPayouts.length;
572
- const planSummary = Object.entries(byPlan)
573
- .map(([plan, count]) => `${(PLAN_ICONS[plan] || '📋')} ${plan.toUpperCase()} ${count}`)
574
- .join(' ');
575
- // Show overview
576
- console.log('');
577
- console.log(chalk_1.default.cyan('╔═══ SMART QUEUE ═══╗'));
578
- console.log(chalk_1.default.cyan('║') + ` Pending: ${chalk_1.default.bold.yellow(String(totalCount))} payouts (${chalk_1.default.green('$' + metrics.pending_amount.toLocaleString())})`);
579
- console.log(chalk_1.default.cyan('║') + ` ${planSummary}`);
580
- console.log(chalk_1.default.cyan('╚═══════════════════╝'));
581
- console.log('');
582
- if (totalCount === 0) {
583
- console.log(chalk_1.default.green(' ✓ No pending payouts\n'));
584
- return;
585
- }
586
- // Step 1: Select plan (with back option)
587
- const planChoices = [
588
- { name: chalk_1.default.dim('← Back'), value: '__back__' },
589
- ...Object.entries(byPlan).map(([plan, count]) => ({
590
- name: `${PLAN_ICONS[plan] || '📋'} ${plan.charAt(0).toUpperCase() + plan.slice(1)} (${count})`,
591
- value: plan,
592
- })),
593
- { name: '📋 All Plans', value: '__all__' },
594
- ];
595
- const { selectedPlan } = await inquirer_1.default.prompt([
596
- {
597
- type: 'list',
598
- name: 'selectedPlan',
599
- message: 'Select plan:',
600
- choices: planChoices,
601
- },
602
- ]);
603
- if (selectedPlan === '__back__')
604
- return;
605
- const isTarPayPlan = selectedPlan === 'christmas';
606
- const planFilter = selectedPlan === '__all__' ? undefined : selectedPlan;
607
- let smartItems = [];
608
- if (isTarPayPlan) {
609
- smartItems = tarPayPayouts
610
- .filter((p) => !planFilter || p.plan === planFilter)
611
- .map((p) => ({
560
+ // Build unified list from both sources
561
+ const allItems = [
562
+ ...payouts.map((p) => ({
612
563
  id: p.id,
613
564
  user_email: p.user_email,
614
- crypto: p.currency,
615
- amount: parseFloat(p.amount),
616
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
565
+ crypto: p.crypto_type,
566
+ amount: p.amount,
567
+ remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
617
568
  has_partial_payments: p.has_partial_payments || false,
618
569
  paid_percentage: p.paid_percentage || 0,
619
- }));
620
- }
621
- else {
622
- smartItems = payouts
623
- .filter((p) => !planFilter || p.plan === planFilter)
624
- .map((p) => ({
570
+ plan: p.plan,
571
+ source: 'regular',
572
+ })),
573
+ ...tarPayPayouts.map((p) => ({
625
574
  id: p.id,
626
575
  user_email: p.user_email,
627
- crypto: p.crypto_type,
628
- amount: p.amount,
629
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
576
+ crypto: p.currency,
577
+ amount: parseFloat(p.amount),
578
+ remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
630
579
  has_partial_payments: p.has_partial_payments || false,
631
580
  paid_percentage: p.paid_percentage || 0,
632
- }));
633
- }
634
- if (smartItems.length === 0) {
635
- console.log(chalk_1.default.green('\n ✓ No pending payouts for this plan\n'));
636
- return;
637
- }
638
- // Group by currency
581
+ plan: p.plan,
582
+ source: 'tarpay',
583
+ })),
584
+ ];
585
+ // Group by currency across ALL plans
639
586
  const byCurrency = {};
640
- smartItems.forEach((p) => {
587
+ allItems.forEach((p) => {
641
588
  if (!byCurrency[p.crypto])
642
589
  byCurrency[p.crypto] = [];
643
590
  byCurrency[p.crypto].push(p);
644
591
  });
645
- const currencies = Object.keys(byCurrency);
646
- const planLabel = planFilter ? planFilter.toUpperCase() : 'ALL PLANS';
647
- const planColor = planFilter ? (PLAN_COLORS[planFilter] || chalk_1.default.white) : chalk_1.default.white;
648
- console.log('\n' + planColor(` 📋 ${planLabel} - Pending Payouts`));
649
- console.log(chalk_1.default.dim(' ─────────────────────────────'));
650
- currencies.forEach((crypto) => {
651
- const items = byCurrency[crypto];
652
- const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
653
- console.log(` ${chalk_1.default.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk_1.default.green(formatAmount(total, crypto))}`);
654
- });
592
+ const totalCount = allItems.length;
593
+ const totalAmount = allItems.reduce((sum, p) => sum + p.remaining_amount, 0);
594
+ const currencySummary = Object.entries(byCurrency)
595
+ .map(([crypto, items]) => `${chalk_1.default.bold(crypto)} ${items.length}`)
596
+ .join(' ');
597
+ // Show overview
598
+ console.log('');
599
+ console.log(chalk_1.default.cyan('╔═══ SUPER SMART ═══╗'));
600
+ console.log(chalk_1.default.cyan('║') + ` Pending: ${chalk_1.default.bold.yellow(String(totalCount))} payouts (${chalk_1.default.green('$' + Math.round(totalAmount).toLocaleString())})`);
601
+ console.log(chalk_1.default.cyan('║') + ` ${currencySummary}`);
602
+ console.log(chalk_1.default.cyan('╚════════════════════╝'));
655
603
  console.log('');
656
- // Step 2: Select currency (with back, skip if only one)
604
+ if (totalCount === 0) {
605
+ console.log(chalk_1.default.green(' ✓ No pending payouts\n'));
606
+ return;
607
+ }
608
+ // Step 1: Select currency (with back option)
609
+ const currencies = Object.keys(byCurrency);
657
610
  let selectedCurrency;
658
611
  if (currencies.length === 1) {
659
612
  selectedCurrency = currencies[0];
@@ -671,7 +624,7 @@ const runSmartQueueDirect = async () => {
671
624
  {
672
625
  type: 'list',
673
626
  name: 'currency',
674
- message: 'Which currency to process?',
627
+ message: 'Select currency:',
675
628
  choices: currencyChoices,
676
629
  },
677
630
  ]);
@@ -680,8 +633,23 @@ const runSmartQueueDirect = async () => {
680
633
  selectedCurrency = currency;
681
634
  }
682
635
  const currencyItems = byCurrency[selectedCurrency];
636
+ // Show plan breakdown for selected currency
637
+ const byPlan = {};
638
+ currencyItems.forEach((p) => {
639
+ if (!byPlan[p.plan])
640
+ byPlan[p.plan] = [];
641
+ byPlan[p.plan].push(p);
642
+ });
643
+ console.log(`\n ${chalk_1.default.bold(selectedCurrency)} - ${currencyItems.length} payouts:`);
644
+ Object.entries(byPlan).forEach(([plan, items]) => {
645
+ const planTotal = items.reduce((sum, p) => sum + p.remaining_amount, 0);
646
+ const icon = PLAN_ICONS[plan] || '📋';
647
+ const color = PLAN_COLORS[plan] || chalk_1.default.white;
648
+ console.log(` ${icon} ${color(plan.toUpperCase().padEnd(12))} ${String(items.length).padStart(2)} │ ${chalk_1.default.green(formatAmount(planTotal, selectedCurrency))}`);
649
+ });
650
+ console.log('');
683
651
  const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
684
- // Step 3: Ask available amount (with back)
652
+ // Step 2: Ask available amount (with back)
685
653
  const { availableAmount } = await inquirer_1.default.prompt([
686
654
  {
687
655
  type: 'input',
@@ -700,36 +668,94 @@ const runSmartQueueDirect = async () => {
700
668
  if (availableAmount.toLowerCase() === 'back' || availableAmount.toLowerCase() === 'q')
701
669
  return;
702
670
  const available = parseFloat(availableAmount);
703
- const smartPercentage = Math.min((available / totalPending) * 100, 100);
704
- const roundedPct = Math.round(smartPercentage * 100) / 100;
671
+ const equalShare = available / currencyItems.length;
672
+ // Plan abbreviations for preview
673
+ const PLAN_ABBREV = {
674
+ hermes: 'HRM',
675
+ alpha: 'ALP',
676
+ mematic: 'MEM',
677
+ validator_v2: 'V2',
678
+ booster: 'BST',
679
+ dumpster: 'DMP',
680
+ christmas: 'XMS',
681
+ recovery: 'RCV',
682
+ };
683
+ // Smart equal distribution preview (mirrors backend logic)
684
+ // Capped users get only their remaining, surplus redistributed
685
+ let previewTotal = 0;
686
+ const allocations = [];
687
+ let pool = available;
688
+ let unallocated = [...currencyItems];
689
+ while (unallocated.length > 0 && pool > 0.001) {
690
+ const share = pool / unallocated.length;
691
+ const capped = [];
692
+ const uncapped = [];
693
+ for (const p of unallocated) {
694
+ const existing = allocations.find((a) => a.item.id === p.id);
695
+ const alreadyAllocated = existing ? existing.willPay : 0;
696
+ const remaining = p.remaining_amount - alreadyAllocated;
697
+ if (remaining <= share) {
698
+ capped.push(p);
699
+ const amt = remaining;
700
+ if (existing)
701
+ existing.willPay += amt;
702
+ else
703
+ allocations.push({ item: p, willPay: amt });
704
+ pool -= amt;
705
+ }
706
+ else {
707
+ uncapped.push(p);
708
+ }
709
+ }
710
+ if (capped.length === 0) {
711
+ // No one capped, give everyone the equal share
712
+ for (const p of uncapped) {
713
+ const existing = allocations.find((a) => a.item.id === p.id);
714
+ if (existing)
715
+ existing.willPay += share;
716
+ else
717
+ allocations.push({ item: p, willPay: share });
718
+ pool -= share;
719
+ }
720
+ break;
721
+ }
722
+ unallocated = uncapped;
723
+ }
705
724
  // Show preview
706
- console.log('\n' + chalk_1.default.cyan(` Processing ${chalk_1.default.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
725
+ console.log('\n' + chalk_1.default.cyan(` Equal distribution: ${chalk_1.default.bold(formatAmount(available, selectedCurrency))} across ${currencyItems.length} ${selectedCurrency} payouts`));
707
726
  console.log(chalk_1.default.dim(' ─────────────────────────────'));
708
- let previewTotal = 0;
709
- currencyItems.forEach((p) => {
710
- const willPay = p.remaining_amount * (smartPercentage / 100);
711
- previewTotal += willPay;
712
- const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
713
- console.log(` ${chalk_1.default.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(16)} → pays ${chalk_1.default.green(formatAmount(willPay, selectedCurrency))}`);
714
- });
727
+ for (const alloc of allocations) {
728
+ previewTotal += alloc.willPay;
729
+ const p = alloc.item;
730
+ const email = p.user_email.length > 20 ? p.user_email.substring(0, 18) + '..' : p.user_email;
731
+ const abbrev = PLAN_ABBREV[p.plan] || p.plan.substring(0, 3).toUpperCase();
732
+ const planColor = PLAN_COLORS[p.plan] || chalk_1.default.white;
733
+ const capped = alloc.willPay < equalShare - 0.01 ? chalk_1.default.dim(' (capped)') : '';
734
+ console.log(` ${chalk_1.default.dim('#' + p.id)} ${planColor('[' + abbrev + ']')} ${email.padEnd(20)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(14)} → pays ${chalk_1.default.green(formatAmount(alloc.willPay, selectedCurrency))}${capped}`);
735
+ }
715
736
  console.log(chalk_1.default.dim(' ─────────────────────────────'));
716
737
  console.log(chalk_1.default.bold(` Total to send: ${chalk_1.default.green(formatAmount(previewTotal, selectedCurrency))}\n`));
717
- // Step 4: Confirm
738
+ // Step 3: Confirm
718
739
  const { confirmSmart } = await inquirer_1.default.prompt([
719
740
  {
720
741
  type: 'confirm',
721
742
  name: 'confirmSmart',
722
- message: chalk_1.default.yellow(`⚠️ Pay ${roundedPct}% of ${currencyItems.length} payout(s)?`),
743
+ message: chalk_1.default.yellow(`⚠️ Equal distribute ${formatAmount(available, selectedCurrency)} across ${currencyItems.length} payout(s)?`),
723
744
  default: false,
724
745
  },
725
746
  ]);
726
747
  if (confirmSmart) {
727
- const smartIds = currencyItems.map((p) => p.id);
728
- if (isTarPayPlan) {
729
- await processChristmasPayoutsWithProgress(smartIds, 'partial', roundedPct);
748
+ // Split by source for correct API calls
749
+ const regularIds = currencyItems.filter((p) => p.source === 'regular').map((p) => p.id);
750
+ const tarPayIds = currencyItems.filter((p) => p.source === 'tarpay').map((p) => p.id);
751
+ if (regularIds.length > 0) {
752
+ await processPayoutsWithProgress(regularIds, 'equal', available);
730
753
  }
731
- else {
732
- await processPayoutsWithProgress(smartIds, 'partial', roundedPct);
754
+ if (tarPayIds.length > 0) {
755
+ // TarPay still uses percentage-based for now (christmas payouts)
756
+ const smartPercentage = Math.min((available / totalPending) * 100, 100);
757
+ const roundedPct = Math.round(smartPercentage * 100) / 100;
758
+ await processChristmasPayoutsWithProgress(tarPayIds, 'partial', roundedPct);
733
759
  }
734
760
  }
735
761
  else {
@@ -785,8 +811,8 @@ const runInteractiveShell = async () => {
785
811
  setTitle('Urgent');
786
812
  await showUrgentCmd();
787
813
  }
788
- else if (cmd === '5' || cmd === 'queue' || cmd === 'sq') {
789
- await runSmartQueueDirect();
814
+ else if (cmd === '5' || cmd === 'queue' || cmd === 'sq' || cmd === 'super' || cmd === 'ss') {
815
+ await runSuperSmartDirect();
790
816
  await showDashboard();
791
817
  }
792
818
  else {
@@ -1350,8 +1376,8 @@ const selectPayoutsInteractive = async (plan) => {
1350
1376
  return [];
1351
1377
  }
1352
1378
  };
1353
- const processPayoutsWithProgress = async (ids, action, percentage) => {
1354
- const actionLabel = action === 'partial' ? `PARTIAL ${percentage}%` : action.toUpperCase();
1379
+ const processPayoutsWithProgress = async (ids, action, percentageOrAmount) => {
1380
+ const actionLabel = action === 'partial' ? `PARTIAL ${percentageOrAmount}%` : action === 'equal' ? `EQUAL DIST $${percentageOrAmount}` : action.toUpperCase();
1355
1381
  console.log('\n' + chalk_1.default.cyan('╔══════════════════════════════════════════════════════════════╗'));
1356
1382
  console.log(chalk_1.default.cyan('║') + chalk_1.default.bold.white(` 🔄 ${actionLabel} - ${ids.length} PAYOUT(S)... `.substring(0, 60)) + chalk_1.default.cyan('║'));
1357
1383
  console.log(chalk_1.default.cyan('╠══════════════════════════════════════════════════════════════╣'));
@@ -1375,7 +1401,10 @@ const processPayoutsWithProgress = async (ids, action, percentage) => {
1375
1401
  result = await api_1.api.batchApprovePayouts(ids);
1376
1402
  }
1377
1403
  else if (action === 'partial') {
1378
- result = await api_1.api.batchPartialPayouts(ids, percentage);
1404
+ result = await api_1.api.batchPartialPayouts(ids, percentageOrAmount);
1405
+ }
1406
+ else if (action === 'equal') {
1407
+ result = await api_1.api.batchEqualPartialPayouts(ids, percentageOrAmount);
1379
1408
  }
1380
1409
  else {
1381
1410
  result = await api_1.api.batchCancelPayouts(ids);
@@ -1393,7 +1422,11 @@ const processPayoutsWithProgress = async (ids, action, percentage) => {
1393
1422
  }
1394
1423
  else if (action === 'partial') {
1395
1424
  icon = '%';
1396
- verb = `PARTIAL ${percentage}% SENT`;
1425
+ verb = `PARTIAL ${percentageOrAmount}% SENT`;
1426
+ }
1427
+ else if (action === 'equal') {
1428
+ icon = '⚖';
1429
+ verb = 'EQUAL DISTRIBUTION SENT';
1397
1430
  }
1398
1431
  else {
1399
1432
  icon = '↩';
@@ -1807,107 +1840,11 @@ const runChristmasPayoutsShell = async () => {
1807
1840
  }
1808
1841
  break;
1809
1842
  case 'smart':
1810
- case 'sp': {
1811
- // Smart partial: pay by available balance for Christmas
1812
- const xmasSmartSpinner = (0, ora_1.default)('Loading Christmas payouts...').start();
1813
- try {
1814
- const xmasData = await api_1.api.getTarPayPayouts({
1815
- plan: 'christmas',
1816
- status: 'pending_review',
1817
- limit: 500,
1818
- });
1819
- const xmasPayouts = xmasData.results || [];
1820
- xmasSmartSpinner.stop();
1821
- if (xmasPayouts.length === 0) {
1822
- console.log(chalk_1.default.green('\n ✓ No pending Christmas payouts\n'));
1823
- break;
1824
- }
1825
- // Group by currency
1826
- const xmasByCurrency = {};
1827
- xmasPayouts.forEach((p) => {
1828
- if (!xmasByCurrency[p.currency])
1829
- xmasByCurrency[p.currency] = [];
1830
- xmasByCurrency[p.currency].push(p);
1831
- });
1832
- const xmasCurrencies = Object.keys(xmasByCurrency);
1833
- console.log('\n' + chalk_1.default.red(` 🎄 CHRISTMAS - Pending Payouts`));
1834
- console.log(chalk_1.default.dim(' ─────────────────────────────'));
1835
- xmasCurrencies.forEach((crypto) => {
1836
- const items = xmasByCurrency[crypto];
1837
- const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1838
- console.log(` ${chalk_1.default.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk_1.default.green(formatAmount(total, crypto))}`);
1839
- });
1840
- console.log('');
1841
- let xmasCurrency;
1842
- if (xmasCurrencies.length === 1) {
1843
- xmasCurrency = xmasCurrencies[0];
1844
- }
1845
- else {
1846
- const { currency } = await inquirer_1.default.prompt([
1847
- {
1848
- type: 'list',
1849
- name: 'currency',
1850
- message: 'Which currency to process?',
1851
- choices: xmasCurrencies.map((c) => {
1852
- const items = xmasByCurrency[c];
1853
- const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1854
- return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
1855
- }),
1856
- },
1857
- ]);
1858
- xmasCurrency = currency;
1859
- }
1860
- const xmasCurrencyPayouts = xmasByCurrency[xmasCurrency];
1861
- const xmasTotalPending = xmasCurrencyPayouts.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
1862
- const { xmasAvailable } = await inquirer_1.default.prompt([
1863
- {
1864
- type: 'input',
1865
- name: 'xmasAvailable',
1866
- message: `How much ${xmasCurrency} do you have available? (total pending: ${formatAmount(xmasTotalPending, xmasCurrency)})`,
1867
- validate: (input) => {
1868
- const num = parseFloat(input);
1869
- if (isNaN(num) || num <= 0)
1870
- return 'Please enter a positive number';
1871
- return true;
1872
- },
1873
- },
1874
- ]);
1875
- const xmasAvailNum = parseFloat(xmasAvailable);
1876
- const xmasPct = Math.min((xmasAvailNum / xmasTotalPending) * 100, 100);
1877
- const xmasRoundedPct = Math.round(xmasPct * 100) / 100;
1878
- console.log('\n' + chalk_1.default.cyan(` Processing ${chalk_1.default.bold(xmasRoundedPct + '%')} of ${xmasCurrencyPayouts.length} ${xmasCurrency} payouts (${formatAmount(xmasAvailNum, xmasCurrency)} / ${formatAmount(xmasTotalPending, xmasCurrency)})`));
1879
- console.log(chalk_1.default.dim(' ─────────────────────────────'));
1880
- let xmasPreviewTotal = 0;
1881
- xmasCurrencyPayouts.forEach((p) => {
1882
- const displayAmt = p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount);
1883
- const willPay = displayAmt * (xmasPct / 100);
1884
- xmasPreviewTotal += willPay;
1885
- const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
1886
- console.log(` ${chalk_1.default.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(displayAmt, xmasCurrency).padStart(16)} → pays ${chalk_1.default.green(formatAmount(willPay, xmasCurrency))}`);
1887
- });
1888
- console.log(chalk_1.default.dim(' ─────────────────────────────'));
1889
- console.log(chalk_1.default.bold(` Total to send: ${chalk_1.default.green(formatAmount(xmasPreviewTotal, xmasCurrency))}\n`));
1890
- const { confirmXmasSmart } = await inquirer_1.default.prompt([
1891
- {
1892
- type: 'confirm',
1893
- name: 'confirmXmasSmart',
1894
- message: chalk_1.default.yellow(`⚠️ Pay ${xmasRoundedPct}% of ${xmasCurrencyPayouts.length} payout(s)?`),
1895
- default: false,
1896
- },
1897
- ]);
1898
- if (confirmXmasSmart) {
1899
- const xmasSmartIds = xmasCurrencyPayouts.map((p) => p.id);
1900
- await processChristmasPayoutsWithProgress(xmasSmartIds, 'partial', xmasRoundedPct);
1901
- }
1902
- else {
1903
- console.log(chalk_1.default.dim('\n Cancelled\n'));
1904
- }
1905
- }
1906
- catch (e) {
1907
- xmasSmartSpinner.fail(chalk_1.default.red('Failed to load Christmas payouts'));
1908
- }
1843
+ case 'sp':
1844
+ case 'super':
1845
+ case 'ss':
1846
+ await runSuperSmartDirect();
1909
1847
  break;
1910
- }
1911
1848
  case 'help':
1912
1849
  case '?':
1913
1850
  console.log(chalk_1.default.red('\n 🎄 Christmas Payout Commands:'));
@@ -1920,7 +1857,7 @@ const runChristmasPayoutsShell = async () => {
1920
1857
  console.log(' select, s Interactive selection mode');
1921
1858
  console.log(' approve, a Select & approve payouts');
1922
1859
  console.log(chalk_1.default.cyan(' partial, p Select & pay partial %'));
1923
- console.log(chalk_1.default.cyan(' smart, sp Smart partial: pay by available balance'));
1860
+ console.log(chalk_1.default.cyan(' smart, sp, ss Super Smart: pay by currency across all plans'));
1924
1861
  console.log(' reject Select & reject payouts');
1925
1862
  console.log(' back, q Return to main payouts');
1926
1863
  console.log(chalk_1.default.dim('\n Note: Payouts > $50 need approval, < $50 auto-sent'));
@@ -2106,162 +2043,9 @@ const runPayoutsShell = async () => {
2106
2043
  break;
2107
2044
  case 'smart':
2108
2045
  case 'sp':
2109
- // Smart partial: pay by available balance
2110
- const { smartPlan } = await inquirer_1.default.prompt([
2111
- {
2112
- type: 'list',
2113
- name: 'smartPlan',
2114
- message: 'Select plan:',
2115
- choices: [
2116
- { name: `${PLAN_ICONS.hermes || '⚡'} Hermes`, value: 'hermes' },
2117
- { name: `${PLAN_ICONS.alpha || '🔷'} Alpha`, value: 'alpha' },
2118
- { name: `${PLAN_ICONS.mematic || '💎'} Mematic`, value: 'mematic' },
2119
- { name: `${PLAN_ICONS.validator_v2 || '🔐'} Validator V2`, value: 'validator_v2' },
2120
- { name: `${PLAN_ICONS.booster || '🚀'} Booster`, value: 'booster' },
2121
- { name: `${PLAN_ICONS.christmas || '🎄'} Christmas`, value: 'christmas' },
2122
- { name: '🔄 Recovery', value: 'recovery' },
2123
- { name: '📋 All Plans', value: undefined },
2124
- ],
2125
- },
2126
- ]);
2127
- const isTarPayPlan = smartPlan === 'christmas';
2128
- const smartSpinner = (0, ora_1.default)('Loading pending payouts...').start();
2129
- try {
2130
- let smartItems = [];
2131
- if (isTarPayPlan) {
2132
- // TarPay payouts (Christmas, etc.)
2133
- const tarData = await api_1.api.getTarPayPayouts({
2134
- plan: smartPlan,
2135
- status: 'pending_review',
2136
- limit: 500,
2137
- });
2138
- const tarPayouts = tarData.results || [];
2139
- smartItems = tarPayouts.map((p) => ({
2140
- id: p.id,
2141
- user_email: p.user_email,
2142
- crypto: p.currency,
2143
- amount: parseFloat(p.amount),
2144
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
2145
- has_partial_payments: p.has_partial_payments || false,
2146
- paid_percentage: p.paid_percentage || 0,
2147
- }));
2148
- }
2149
- else {
2150
- // Regular payouts
2151
- const smartParams = { status: 'pending', limit: 500 };
2152
- if (smartPlan)
2153
- smartParams.plan = smartPlan;
2154
- const smartData = await api_1.api.listPayouts(smartParams);
2155
- const smartPayouts = smartData.data || [];
2156
- smartItems = smartPayouts.map((p) => ({
2157
- id: p.id,
2158
- user_email: p.user_email,
2159
- crypto: p.crypto_type,
2160
- amount: p.amount,
2161
- remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
2162
- has_partial_payments: p.has_partial_payments || false,
2163
- paid_percentage: p.paid_percentage || 0,
2164
- }));
2165
- }
2166
- smartSpinner.stop();
2167
- if (smartItems.length === 0) {
2168
- console.log(chalk_1.default.green('\n ✓ No pending payouts found\n'));
2169
- break;
2170
- }
2171
- // Group by crypto
2172
- const byCurrency = {};
2173
- smartItems.forEach((p) => {
2174
- if (!byCurrency[p.crypto])
2175
- byCurrency[p.crypto] = [];
2176
- byCurrency[p.crypto].push(p);
2177
- });
2178
- const currencies = Object.keys(byCurrency);
2179
- const planLabel = smartPlan ? smartPlan.toUpperCase() : 'ALL PLANS';
2180
- const planColor = smartPlan ? (PLAN_COLORS[smartPlan] || chalk_1.default.white) : chalk_1.default.white;
2181
- console.log('\n' + planColor(` 📋 ${planLabel} - Pending Payouts`));
2182
- console.log(chalk_1.default.dim(' ─────────────────────────────'));
2183
- currencies.forEach((crypto) => {
2184
- const items = byCurrency[crypto];
2185
- const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
2186
- console.log(` ${chalk_1.default.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk_1.default.green(formatAmount(total, crypto))}`);
2187
- });
2188
- console.log('');
2189
- // Select currency
2190
- let selectedCurrency;
2191
- if (currencies.length === 1) {
2192
- selectedCurrency = currencies[0];
2193
- }
2194
- else {
2195
- const { currency } = await inquirer_1.default.prompt([
2196
- {
2197
- type: 'list',
2198
- name: 'currency',
2199
- message: 'Which currency to process?',
2200
- choices: currencies.map((c) => {
2201
- const items = byCurrency[c];
2202
- const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
2203
- return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
2204
- }),
2205
- },
2206
- ]);
2207
- selectedCurrency = currency;
2208
- }
2209
- const currencyItems = byCurrency[selectedCurrency];
2210
- const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
2211
- // Ask available amount
2212
- const { availableAmount } = await inquirer_1.default.prompt([
2213
- {
2214
- type: 'input',
2215
- name: 'availableAmount',
2216
- message: `How much ${selectedCurrency} do you have available? (total pending: ${formatAmount(totalPending, selectedCurrency)})`,
2217
- validate: (input) => {
2218
- const num = parseFloat(input);
2219
- if (isNaN(num) || num <= 0)
2220
- return 'Please enter a positive number';
2221
- return true;
2222
- },
2223
- },
2224
- ]);
2225
- const available = parseFloat(availableAmount);
2226
- const smartPercentage = Math.min((available / totalPending) * 100, 100);
2227
- const roundedPct = Math.round(smartPercentage * 100) / 100;
2228
- // Show breakdown
2229
- console.log('\n' + chalk_1.default.cyan(` Processing ${chalk_1.default.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
2230
- console.log(chalk_1.default.dim(' ─────────────────────────────'));
2231
- let previewTotal = 0;
2232
- currencyItems.forEach((p) => {
2233
- const willPay = p.remaining_amount * (smartPercentage / 100);
2234
- previewTotal += willPay;
2235
- const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
2236
- console.log(` ${chalk_1.default.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(16)} → pays ${chalk_1.default.green(formatAmount(willPay, selectedCurrency))}`);
2237
- });
2238
- console.log(chalk_1.default.dim(' ─────────────────────────────'));
2239
- console.log(chalk_1.default.bold(` Total to send: ${chalk_1.default.green(formatAmount(previewTotal, selectedCurrency))}\n`));
2240
- // Confirm
2241
- const { confirmSmart } = await inquirer_1.default.prompt([
2242
- {
2243
- type: 'confirm',
2244
- name: 'confirmSmart',
2245
- message: chalk_1.default.yellow(`⚠️ Pay ${roundedPct}% of ${currencyItems.length} payout(s)?`),
2246
- default: false,
2247
- },
2248
- ]);
2249
- if (confirmSmart) {
2250
- const smartIds = currencyItems.map((p) => p.id);
2251
- if (isTarPayPlan) {
2252
- await processChristmasPayoutsWithProgress(smartIds, 'partial', roundedPct);
2253
- }
2254
- else {
2255
- await processPayoutsWithProgress(smartIds, 'partial', roundedPct);
2256
- }
2257
- }
2258
- else {
2259
- console.log(chalk_1.default.dim('\n Cancelled\n'));
2260
- }
2261
- }
2262
- catch (e) {
2263
- smartSpinner.fail(chalk_1.default.red('Failed to load payouts'));
2264
- }
2046
+ case 'super':
2047
+ case 'ss':
2048
+ await runSuperSmartDirect();
2265
2049
  break;
2266
2050
  case 'hermes':
2267
2051
  case 'alpha':
@@ -2349,7 +2133,7 @@ const runPayoutsShell = async () => {
2349
2133
  console.log(' select [plan] Interactive payout selection');
2350
2134
  console.log(' approve [ids] Approve payouts (interactive if no IDs)');
2351
2135
  console.log(chalk_1.default.cyan(' partial, p Pay partial % (repayment mode)'));
2352
- console.log(chalk_1.default.cyan(' smart, sp Smart partial: pay by available balance'));
2136
+ console.log(chalk_1.default.cyan(' smart, sp, ss Super Smart: pay by currency across all plans'));
2353
2137
  console.log(chalk_1.default.yellow(' all Approve ALL pending payouts'));
2354
2138
  console.log(' cancel [ids] Cancel payouts (interactive if no IDs)');
2355
2139
  console.log(' process Process payouts by plan (interactive)');