agentstore 1.0.2 → 1.0.3

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.
Files changed (2) hide show
  1. package/dist/index.js +156 -86
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import * as keytar from 'keytar';
13
13
  const __filename = fileURLToPath(import.meta.url);
14
14
  const __dirname = path.dirname(__filename);
15
15
  const API_BASE = 'https://api.agentstore.tools';
16
- const MEV_COMMIT_RPC = 'https://fastrpc.mev-commit.xyz';
16
+ const ETHEREUM_RPC = 'https://ethereum-rpc.publicnode.com';
17
17
  const KEYCHAIN_SERVICE = 'agentstore-wallet';
18
18
  const KEYCHAIN_ACCOUNT = 'encryption-key';
19
19
  // USDC contract on Ethereum mainnet
@@ -53,7 +53,7 @@ const TX_HISTORY_FILE = path.join(AGENTSTORE_DIR, 'tx_history.json');
53
53
  // Create public client for reading blockchain state
54
54
  const publicClient = createPublicClient({
55
55
  chain: mainnet,
56
- transport: http(MEV_COMMIT_RPC),
56
+ transport: http(ETHEREUM_RPC),
57
57
  });
58
58
  // Ensure directories exist
59
59
  function ensureDirectories() {
@@ -214,7 +214,7 @@ async function createNewWallet() {
214
214
  address: account.address,
215
215
  createdAt: new Date().toISOString(),
216
216
  network: 'mainnet',
217
- rpcEndpoint: MEV_COMMIT_RPC,
217
+ rpcEndpoint: ETHEREUM_RPC,
218
218
  spendLimits: {
219
219
  perTransaction: 100,
220
220
  daily: 500,
@@ -243,7 +243,7 @@ async function ensureWalletExists() {
243
243
  address: account.address,
244
244
  createdAt: new Date().toISOString(),
245
245
  network: 'mainnet',
246
- rpcEndpoint: MEV_COMMIT_RPC,
246
+ rpcEndpoint: ETHEREUM_RPC,
247
247
  spendLimits: {
248
248
  perTransaction: 100,
249
249
  daily: 500,
@@ -413,6 +413,42 @@ function prompt(question) {
413
413
  });
414
414
  });
415
415
  }
416
+ // Prompt for secret input (masked)
417
+ function promptSecret(question) {
418
+ return new Promise((resolve) => {
419
+ process.stdout.write(question);
420
+ const stdin = process.stdin;
421
+ const wasRaw = stdin.isRaw;
422
+ stdin.setRawMode?.(true);
423
+ stdin.resume();
424
+ stdin.setEncoding('utf8');
425
+ let input = '';
426
+ const onData = (ch) => {
427
+ if (ch === '\n' || ch === '\r') {
428
+ stdin.setRawMode?.(wasRaw ?? false);
429
+ stdin.pause();
430
+ stdin.removeListener('data', onData);
431
+ process.stdout.write('\n');
432
+ resolve(input);
433
+ }
434
+ else if (ch === '\u0003') {
435
+ // Ctrl+C
436
+ process.exit(0);
437
+ }
438
+ else if (ch === '\u007f' || ch === '\b') {
439
+ if (input.length > 0) {
440
+ input = input.slice(0, -1);
441
+ process.stdout.write('\b \b');
442
+ }
443
+ }
444
+ else {
445
+ input += ch;
446
+ process.stdout.write('*');
447
+ }
448
+ };
449
+ stdin.on('data', onData);
450
+ });
451
+ }
416
452
  // Check agent access — returns entitlement if already purchased, or 402 payment params
417
453
  async function getPaymentRequired(agentId, walletAddress) {
418
454
  try {
@@ -490,6 +526,18 @@ async function submitX402Payment(agentId, walletAddress, payment, authorization)
490
526
  });
491
527
  if (!response.ok) {
492
528
  const error = await response.json();
529
+ if (response.status === 409) {
530
+ // Already purchased — re-check /access for the entitlement
531
+ console.log('Agent already purchased. Retrieving entitlement...');
532
+ const access = await getPaymentRequired(agentId, walletAddress);
533
+ if (access.status === 'granted' && access.entitlement) {
534
+ return {
535
+ entitlement_token: access.entitlement.token,
536
+ install: access.install,
537
+ proof: null,
538
+ };
539
+ }
540
+ }
493
541
  console.error(`Payment failed: ${error.error || response.statusText}`);
494
542
  return null;
495
543
  }
@@ -575,6 +623,9 @@ This is a prompt-based agent. Reference it by asking Claude to follow the instru
575
623
  }
576
624
  // Install command
577
625
  async function installAgent(agentId, options) {
626
+ // --pay is a true alias for --yes
627
+ if (options.pay)
628
+ options.yes = true;
578
629
  ensureDirectories();
579
630
  console.log(`Fetching agent: ${agentId}...`);
580
631
  const agent = await fetchAgent(agentId);
@@ -622,93 +673,112 @@ async function installAgent(agentId, options) {
622
673
  console.log('\n💰 Payment Required:');
623
674
  console.log(` Price: $${priceUsd.toFixed(2)} USDC`);
624
675
  console.log(` Your wallet: ${walletAddress}`);
625
- // Check access status (entitlement or 402)
626
- const accessResult = await getPaymentRequired(agent.agent_id, walletAddress);
627
- if (accessResult.status === 'error') {
628
- console.log(`\n❌ Access check failed: ${accessResult.error}`);
629
- process.exit(1);
630
- }
631
- if (accessResult.status === 'granted' && accessResult.entitlement) {
676
+ // Check local entitlements first (skip API call if already purchased)
677
+ const localEntitlements = loadEntitlements();
678
+ const localEntitlement = localEntitlements.find((e) => e.agentId === agent.agent_id);
679
+ if (localEntitlement) {
632
680
  console.log('\n✓ Already purchased! Using existing entitlement.');
633
- entitlementToken = accessResult.entitlement.token;
634
- expiresAt = accessResult.entitlement.expires_at;
635
- }
636
- else if (accessResult.status === 'payment_required') {
637
- const paymentRequired = accessResult.payment;
638
- // Check USDC balance
639
- try {
640
- const balance = await getWalletBalance();
641
- const requiredRaw = parseUsdc(paymentRequired.amount);
642
- console.log(` Your USDC balance: $${balance.usdc}`);
643
- if (balance.usdcRaw < requiredRaw) {
644
- console.log(`\n⚠️ Insufficient USDC. Need $${paymentRequired.amount}, have $${balance.usdc}`);
645
- const funded = await triggerFundingFlow(priceUsd);
646
- if (!funded) {
647
- process.exit(1);
648
- }
649
- // Re-check balance after funding
650
- const newBalance = await getWalletBalance();
651
- console.log(` New USDC balance: $${newBalance.usdc}`);
652
- if (newBalance.usdcRaw < requiredRaw) {
653
- console.log(`\n❌ Still insufficient. Need $${paymentRequired.amount}, have $${newBalance.usdc}`);
654
- process.exit(1);
655
- }
656
- }
657
- }
658
- catch (error) {
659
- console.log(`\n❌ Could not check balance: ${error instanceof Error ? error.message : error}`);
681
+ entitlementToken = localEntitlement.token;
682
+ expiresAt = localEntitlement.expiresAt;
683
+ }
684
+ // If no local entitlement, check server
685
+ if (!entitlementToken) {
686
+ const accessResult = await getPaymentRequired(agent.agent_id, walletAddress);
687
+ if (accessResult.status === 'error') {
688
+ console.log(`\n❌ Access check failed: ${accessResult.error}`);
660
689
  process.exit(1);
661
690
  }
662
- // Check spend limits
663
- const config = loadWalletConfig();
664
- const txHistory = loadTxHistory();
665
- const limitCheck = checkSpendLimit(priceUsd, config, txHistory);
666
- if (!limitCheck.allowed) {
667
- console.log(`\n❌ Spend limit exceeded: ${limitCheck.reason}`);
668
- process.exit(1);
691
+ if (accessResult.status === 'granted' && accessResult.entitlement) {
692
+ console.log('\n✓ Already purchased! Using existing entitlement.');
693
+ entitlementToken = accessResult.entitlement.token;
694
+ expiresAt = accessResult.entitlement.expires_at;
669
695
  }
670
- // Confirm payment (skip with --yes or --pay)
671
- if (!options.yes && !options.pay) {
672
- const confirm = await prompt(`\nPay $${paymentRequired.amount} USDC for "${agent.name}"? (y/n) `);
673
- if (confirm !== 'y' && confirm !== 'yes') {
674
- console.log('Payment cancelled.');
675
- process.exit(0);
696
+ }
697
+ if (!entitlementToken) {
698
+ // Need to pay fetch 402 details
699
+ const accessResult = await getPaymentRequired(agent.agent_id, walletAddress);
700
+ if (accessResult.status !== 'payment_required') {
701
+ if (accessResult.status === 'granted') {
702
+ console.log('\n✓ Access granted (no payment needed).');
703
+ }
704
+ else {
705
+ console.log(`\n❌ Unexpected access status: ${accessResult.status}`);
706
+ process.exit(1);
676
707
  }
677
708
  }
678
- // Sign the EIP-3009 authorization
679
- const privateKey = await loadPrivateKey();
680
- if (!privateKey) {
681
- console.log('\n❌ Could not load wallet private key');
682
- process.exit(1);
683
- }
684
- console.log('\n🔐 Signing USDC authorization...');
685
- const authorization = await signTransferAuthorization(paymentRequired, privateKey, walletAddress);
686
- // Submit to API for facilitator relay
687
- console.log('🔄 Processing payment via x402...');
688
- const result = await submitX402Payment(agent.agent_id, walletAddress, paymentRequired, authorization);
689
- if (!result) {
690
- console.log('❌ Payment processing failed.');
691
- process.exit(1);
709
+ else {
710
+ const paymentRequired = accessResult.payment;
711
+ // Check USDC balance
712
+ try {
713
+ const balance = await getWalletBalance();
714
+ const requiredRaw = parseUsdc(paymentRequired.amount);
715
+ console.log(` Your USDC balance: $${balance.usdc}`);
716
+ if (balance.usdcRaw < requiredRaw) {
717
+ console.log(`\n⚠️ Insufficient USDC. Need $${paymentRequired.amount}, have $${balance.usdc}`);
718
+ const funded = await triggerFundingFlow(priceUsd);
719
+ if (!funded) {
720
+ process.exit(1);
721
+ }
722
+ // Re-check balance after funding
723
+ const newBalance = await getWalletBalance();
724
+ console.log(` New USDC balance: $${newBalance.usdc}`);
725
+ if (newBalance.usdcRaw < requiredRaw) {
726
+ console.log(`\n❌ Still insufficient. Need $${paymentRequired.amount}, have $${newBalance.usdc}`);
727
+ process.exit(1);
728
+ }
729
+ }
730
+ }
731
+ catch (error) {
732
+ console.log(`\n❌ Could not check balance: ${error instanceof Error ? error.message : error}`);
733
+ process.exit(1);
734
+ }
735
+ // Check spend limits
736
+ const config = loadWalletConfig();
737
+ const txHistory = loadTxHistory();
738
+ const limitCheck = checkSpendLimit(priceUsd, config, txHistory);
739
+ if (!limitCheck.allowed) {
740
+ console.log(`\n❌ Spend limit exceeded: ${limitCheck.reason}`);
741
+ process.exit(1);
742
+ }
743
+ // Confirm payment (skip with --yes or --pay)
744
+ if (!options.yes) {
745
+ const confirm = await prompt(`\nPay $${paymentRequired.amount} USDC for "${agent.name}"? (y/n) `);
746
+ if (confirm !== 'y' && confirm !== 'yes') {
747
+ console.log('Payment cancelled.');
748
+ process.exit(0);
749
+ }
750
+ }
751
+ // Sign the EIP-3009 authorization
752
+ const privateKey = await loadPrivateKey();
753
+ if (!privateKey) {
754
+ console.log('\n❌ Could not load wallet private key');
755
+ process.exit(1);
756
+ }
757
+ console.log('\n🔐 Signing USDC authorization...');
758
+ const authorization = await signTransferAuthorization(paymentRequired, privateKey, walletAddress);
759
+ // Submit to API for facilitator relay
760
+ console.log('🔄 Processing payment via x402...');
761
+ const result = await submitX402Payment(agent.agent_id, walletAddress, paymentRequired, authorization);
762
+ if (!result) {
763
+ console.log('❌ Payment processing failed.');
764
+ process.exit(1);
765
+ }
766
+ entitlementToken = result.entitlement_token;
767
+ expiresAt = null;
768
+ console.log('✓ Payment confirmed! (gasless USDC via x402)');
769
+ // Record in local tx history
770
+ const txProof = result.proof;
771
+ txHistory.push({
772
+ txHash: txProof?.tx_hash || 'x402-' + Date.now(),
773
+ to: paymentRequired.payTo,
774
+ amountUsdc: paymentRequired.amount,
775
+ amountUsd: priceUsd,
776
+ agentId: agent.agent_id,
777
+ timestamp: new Date().toISOString(),
778
+ status: 'confirmed',
779
+ });
780
+ saveTxHistory(txHistory);
692
781
  }
693
- entitlementToken = result.entitlement_token;
694
- expiresAt = null;
695
- console.log('✓ Payment confirmed! (gasless USDC via x402)');
696
- // Record in local tx history
697
- const txProof = result.proof;
698
- txHistory.push({
699
- txHash: txProof?.tx_hash || 'x402-' + Date.now(),
700
- to: paymentRequired.payTo,
701
- amountUsdc: paymentRequired.amount,
702
- amountUsd: priceUsd,
703
- agentId: agent.agent_id,
704
- timestamp: new Date().toISOString(),
705
- status: 'confirmed',
706
- });
707
- saveTxHistory(txHistory);
708
- }
709
- else if (accessResult.status === 'granted') {
710
- // Free agent via access route (model says free)
711
- console.log('\n✓ Access granted (no payment needed).');
712
782
  }
713
783
  }
714
784
  console.log('\nInstalling...');
@@ -1097,7 +1167,7 @@ walletCmd
1097
1167
  console.log('Wallet already exists. Delete ~/.agentstore/wallet.* files to import a new one.');
1098
1168
  process.exit(1);
1099
1169
  }
1100
- const key = await prompt('Enter private key (0x...): ');
1170
+ const key = await promptSecret('Enter private key (0x...): ');
1101
1171
  if (!key.startsWith('0x') || key.length !== 66) {
1102
1172
  console.log('Invalid private key format. Must be a 0x-prefixed 64-character hex string.');
1103
1173
  process.exit(1);
@@ -1108,7 +1178,7 @@ walletCmd
1108
1178
  address: account.address,
1109
1179
  createdAt: new Date().toISOString(),
1110
1180
  network: 'mainnet',
1111
- rpcEndpoint: MEV_COMMIT_RPC,
1181
+ rpcEndpoint: ETHEREUM_RPC,
1112
1182
  spendLimits: { perTransaction: 100, daily: 500, weekly: 2000 },
1113
1183
  allowedPublishers: [],
1114
1184
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentstore",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "AgentStore CLI - Browse, install, and pay for Claude Code agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",