@palmyr/cli 1.7.0 → 1.8.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/dist/cli.js CHANGED
@@ -376,6 +376,15 @@ const WALLET_HELP = {
376
376
  { flag: '--src-decimals <n>', desc: 'Source token decimals', hint: 'default 18' },
377
377
  { flag: '--dst-decimals <n>', desc: 'Dest token decimals', hint: 'default 6 (USDC-like)' },
378
378
  ],
379
+ 'pay-preflight': [
380
+ { flag: '--chain <c>', desc: 'Override the default pay chain', hint: 'solana | base (default: config.defaultPayChain)' },
381
+ { flag: '--wallet <ID>', desc: 'Override the wallet to check', hint: 'default: config.defaultPayWalletId / PALMYR_PAY_WALLET / auto-pick' },
382
+ { flag: '--min-usdc <N>', desc: 'Required USDC balance to pass (default 0 — just check the wallet exists)' },
383
+ { flag: '--passphrase <p>', desc: 'Wallet passphrase if no OS-keychain session secret', hint: 'or PALMYR_WALLET_PASSPHRASE env' },
384
+ { flag: '(price)', desc: 'Free — one RPC call to read USDC balance' },
385
+ { flag: '(example)', desc: 'palmyr wallet pay-preflight --chain base --min-usdc 3 --json' },
386
+ { flag: '(note)', desc: 'Local-only version runs automatically before every paid command (set PALMYR_NO_PREFLIGHT=1 to disable)' },
387
+ ],
379
388
  };
380
389
  const PHONE_HELP = {
381
390
  search: [
@@ -1032,6 +1041,13 @@ async function main() {
1032
1041
  case 'search': {
1033
1042
  const country = flags.country || 'US';
1034
1043
  const data = await ao.phoneSearch(country, flags.limit ? parseInt(flags.limit) : undefined);
1044
+ // Empty result is a valid response but `{numbers: []}` alone made it
1045
+ // ambiguous whether the API failed or the country has no inventory.
1046
+ // Add a non-breaking `note` field — agents that already key off
1047
+ // `.numbers.length` keep working; new readers get a clear signal.
1048
+ if (data && Array.isArray(data.numbers) && data.numbers.length === 0 && !data.note) {
1049
+ data.note = `No numbers available for ${country}. Try a different country code (US, GB, CA, DE, etc.).`;
1050
+ }
1035
1051
  return print(data);
1036
1052
  render(React.createElement(RecordsScreen, {
1037
1053
  version: VERSION,
@@ -2153,6 +2169,7 @@ async function main() {
2153
2169
  { name: 'watch', description: 'Maintain a watchlist of CAs to monitor', hint: 'add <CA> --trigger "..." | list' },
2154
2170
  { name: 'brief', description: 'Show thesis + PnL brief for a position', hint: '<CA>' },
2155
2171
  { name: 'doctor', description: 'Health check for the wallet-trading subsystem', hint: '[--wallet <ref>]' },
2172
+ { name: 'pay-preflight', description: 'Check the x402 pay flow is ready (chain, wallet, signing, USDC balance)', hint: '[--chain solana|base] [--min-usdc N]' },
2156
2173
  { name: 'smoke-test', description: 'End-to-end validation of wallet trading on Solana + Base', hint: '--wallet <ref> [--chain solana|base|all]' },
2157
2174
  { name: 'readiness', description: 'Go/no-go autonomous-trading readiness — sign, gas, quotes, daemon, open positions', hint: '--wallet <ref>' },
2158
2175
  { name: 'live-test', description: 'Execute tiny real round trips on Solana + Base, verify no leftover positions', hint: '--wallet <ref> --budget Nusdc [--chain ...]' },
@@ -3806,6 +3823,59 @@ async function main() {
3806
3823
  process.exit(EXIT.GENERAL);
3807
3824
  break;
3808
3825
  }
3826
+ case 'pay-preflight': {
3827
+ // Five-question readiness check for the x402 pay flow. Local-only
3828
+ // siblings of this same module run automatically before every paid
3829
+ // command (see paidRequest/paidStreamRequest); this command is the
3830
+ // explicit, full-fat version with the RPC USDC balance check.
3831
+ const ppChain = flags.chain?.toLowerCase();
3832
+ if (ppChain && ppChain !== 'solana' && ppChain !== 'base') {
3833
+ err(`--chain must be solana or base (got ${ppChain})`, EXIT.BAD_INPUT);
3834
+ }
3835
+ const ppWallet = flags.wallet || undefined;
3836
+ const ppMinUsdcRaw = flags['min-usdc'];
3837
+ const ppMinUsdc = typeof ppMinUsdcRaw === 'string' ? Number(ppMinUsdcRaw) : undefined;
3838
+ if (ppMinUsdc !== undefined && (!Number.isFinite(ppMinUsdc) || ppMinUsdc < 0)) {
3839
+ err(`--min-usdc must be a non-negative number (got ${String(ppMinUsdcRaw)})`, EXIT.BAD_INPUT);
3840
+ }
3841
+ const { fullPreflight } = await import('./pay-preflight.js');
3842
+ const report = await fullPreflight({
3843
+ ...(ppChain ? { chain: ppChain } : {}),
3844
+ ...(ppWallet ? { walletRef: ppWallet } : {}),
3845
+ ...(ppMinUsdc !== undefined ? { minUsdc: ppMinUsdc } : {}),
3846
+ ...(passphrase ? { passphrase } : {}),
3847
+ });
3848
+ if (AGENT_MODE) {
3849
+ print(report);
3850
+ if (!report.ok)
3851
+ process.exit(EXIT.GENERAL);
3852
+ break;
3853
+ }
3854
+ // TTY rendering — mirrors the doctor command's layout.
3855
+ console.log();
3856
+ section('Pay preflight');
3857
+ kv('Verdict', report.ok ? `${t.success}ready${t.reset}` : `${t.error}not ready${t.reset}`);
3858
+ kv('Pay chain', report.payChain);
3859
+ kv('Wallet ID', report.walletId || `${t.muted}(none)${t.reset}`);
3860
+ kv('Address', report.walletAddress || `${t.muted}(unknown)${t.reset}`);
3861
+ kv('Can sign', report.canSign ? `${t.success}yes${t.reset}` : `${t.error}no${t.reset}`);
3862
+ if (report.usdc) {
3863
+ const bal = report.usdc.balance;
3864
+ kv('USDC balance', bal === null ? `${t.muted}(unknown)${t.reset}` : `${bal.toFixed(6)} USDC`);
3865
+ if (report.usdc.requiredMin > 0)
3866
+ kv('Required min', `${report.usdc.requiredMin.toFixed(6)} USDC`);
3867
+ if (report.usdc.ataStatus)
3868
+ kv('Solana ATA', report.usdc.ataStatus);
3869
+ }
3870
+ if (report.fix) {
3871
+ console.log();
3872
+ console.log(` ${t.warn}Fix:${t.reset} ${report.fix}`);
3873
+ }
3874
+ console.log();
3875
+ if (!report.ok)
3876
+ process.exit(EXIT.GENERAL);
3877
+ break;
3878
+ }
3809
3879
  case 'smoke-test': {
3810
3880
  const smokeWalletRef = flags.wallet || undefined;
3811
3881
  if (!smokeWalletRef)