agstell-cli 0.1.0 → 0.2.1

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
@@ -42,7 +42,11 @@ function readRegistryCache() {
42
42
  try {
43
43
  if (!fs.existsSync(REGISTRY_CACHE_FILE)) return null;
44
44
  const data = fs.readFileSync(REGISTRY_CACHE_FILE, "utf-8");
45
- return JSON.parse(data);
45
+ const parsed = JSON.parse(data);
46
+ if (parsed.apis?.length > 0 && !("priceXlm" in parsed.apis[0])) {
47
+ return null;
48
+ }
49
+ return parsed;
46
50
  } catch {
47
51
  return null;
48
52
  }
@@ -64,11 +68,11 @@ var CONTRACTS = {
64
68
  }
65
69
  };
66
70
  var DEFAULT_CONFIG = {
67
- stellarNetwork: "testnet",
68
- marketplaceUrl: "https://agentmarket.xyz",
71
+ stellarNetwork: "mainnet",
72
+ marketplaceUrl: "https://steller-web.vercel.app",
69
73
  budgetLimit: 10,
70
- // 10 USDC default
71
- contractId: CONTRACTS.testnet.budgetEnforcer
74
+ // 10 XLM default
75
+ contractId: CONTRACTS.mainnet.budgetEnforcer
72
76
  };
73
77
  function ensureConfigDir() {
74
78
  if (!fs.existsSync(CONFIG_DIR)) {
@@ -122,22 +126,18 @@ var StellarSdk = __toESM(require("@stellar/stellar-sdk"));
122
126
  var NETWORKS = {
123
127
  testnet: {
124
128
  networkPassphrase: StellarSdk.Networks.TESTNET,
125
- horizonUrl: "https://horizon-testnet.stellar.org",
126
- sorobanUrl: "https://soroban-testnet.stellar.org"
129
+ horizonUrl: "https://horizon-testnet.stellar.org"
127
130
  },
128
131
  mainnet: {
129
132
  networkPassphrase: StellarSdk.Networks.PUBLIC,
130
- horizonUrl: "https://horizon.stellar.org",
131
- sorobanUrl: "https://mainnet.stellar.org"
133
+ horizonUrl: "https://horizon.stellar.org"
132
134
  }
133
135
  };
134
- var USDC_TESTNET_ISSUER = "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5";
135
- var USDC_MAINNET_ISSUER = "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN";
136
136
  var StellarClient = class {
137
137
  network;
138
138
  server;
139
139
  keypair = null;
140
- constructor(network = "testnet") {
140
+ constructor(network = "mainnet") {
141
141
  this.network = network;
142
142
  const config2 = NETWORKS[network];
143
143
  this.server = new StellarSdk.Horizon.Server(config2.horizonUrl);
@@ -153,27 +153,21 @@ var StellarClient = class {
153
153
  try {
154
154
  const account = await this.server.loadAccount(this.keypair.publicKey());
155
155
  let xlmBalance = "0";
156
- let usdcBalance = "0";
157
- const usdcIssuer = this.network === "testnet" ? USDC_TESTNET_ISSUER : USDC_MAINNET_ISSUER;
158
156
  for (const balance of account.balances) {
159
157
  if (balance.asset_type === "native") {
160
158
  xlmBalance = balance.balance;
161
- } else if (balance.asset_type !== "liquidity_pool_shares" && balance.asset_code === "USDC" && balance.asset_issuer === usdcIssuer) {
162
- usdcBalance = balance.balance;
163
159
  }
164
160
  }
165
161
  return {
166
162
  publicKey: this.keypair.publicKey(),
167
163
  network: this.network,
168
- xlmBalance,
169
- usdcBalance
164
+ xlmBalance
170
165
  };
171
166
  } catch (error) {
172
167
  return {
173
168
  publicKey: this.keypair.publicKey(),
174
169
  network: this.network,
175
- xlmBalance: "0",
176
- usdcBalance: "0"
170
+ xlmBalance: "0"
177
171
  };
178
172
  }
179
173
  }
@@ -190,26 +184,25 @@ var StellarClient = class {
190
184
  }
191
185
  return null;
192
186
  }
187
+ /** Send native XLM payment */
193
188
  async sendPayment(destination, amount, memo) {
194
189
  if (!this.keypair) return null;
195
190
  try {
196
191
  const account = await this.server.loadAccount(this.keypair.publicKey());
197
- const usdcIssuer = this.network === "testnet" ? USDC_TESTNET_ISSUER : USDC_MAINNET_ISSUER;
198
- const usdcAsset = new StellarSdk.Asset("USDC", usdcIssuer);
199
- const transaction = new StellarSdk.TransactionBuilder(account, {
192
+ const transactionBuilder = new StellarSdk.TransactionBuilder(account, {
200
193
  fee: StellarSdk.BASE_FEE,
201
194
  networkPassphrase: NETWORKS[this.network].networkPassphrase
202
195
  }).addOperation(
203
196
  StellarSdk.Operation.payment({
204
197
  destination,
205
- asset: usdcAsset,
198
+ asset: StellarSdk.Asset.native(),
206
199
  amount
207
200
  })
208
201
  ).setTimeout(30);
209
202
  if (memo) {
210
- transaction.addMemo(StellarSdk.Memo.text(memo.substring(0, 28)));
203
+ transactionBuilder.addMemo(StellarSdk.Memo.text(memo.substring(0, 28)));
211
204
  }
212
- const builtTx = transaction.build();
205
+ const builtTx = transactionBuilder.build();
213
206
  builtTx.sign(this.keypair);
214
207
  const result = await this.server.submitTransaction(builtTx);
215
208
  return {
@@ -217,8 +210,10 @@ var StellarClient = class {
217
210
  success: true
218
211
  };
219
212
  } catch (error) {
220
- console.error("Payment failed:", error);
221
- return null;
213
+ const axiosLike = error;
214
+ const resultCodes = axiosLike?.response?.data?.extras?.result_codes;
215
+ const detail = resultCodes ? `Horizon rejected tx: ${JSON.stringify(resultCodes)}` : error instanceof Error ? error.message : "Unknown error";
216
+ throw new Error(detail);
222
217
  }
223
218
  }
224
219
  async verifyTransaction(txHash) {
@@ -242,64 +237,24 @@ var StellarClient = class {
242
237
  var REGISTRY_TTL_MS = 60 * 60 * 1e3;
243
238
  var FALLBACK_REGISTRY = [
244
239
  {
245
- name: "Weather",
246
- slug: "weather",
247
- description: "Get current weather data for any city worldwide",
248
- category: "Data",
249
- priceUsdc: 1e-3,
250
- endpoint: "/api/proxy/weather",
251
- method: "GET",
252
- provider: "AgentMarket"
253
- },
254
- {
255
- name: "Air Quality",
256
- slug: "air-quality",
257
- description: "Get real-time air quality index and pollution data",
258
- category: "Data",
259
- priceUsdc: 1e-3,
260
- endpoint: "/api/proxy/air-quality",
261
- method: "GET",
262
- provider: "AgentMarket"
263
- },
264
- {
265
- name: "News",
266
- slug: "news",
267
- description: "Fetch latest news headlines by topic",
268
- category: "Data",
269
- priceUsdc: 2e-3,
270
- endpoint: "/api/proxy/news",
271
- method: "GET",
272
- provider: "AgentMarket"
273
- },
274
- {
275
- name: "Currency Exchange",
276
- slug: "currency",
277
- description: "Convert between currencies with live rates",
240
+ name: "Stock Analyst",
241
+ slug: "stock-analyst",
242
+ description: "Live Yahoo Finance data + Gemini sentiment analysis",
278
243
  category: "Finance",
279
- priceUsdc: 1e-3,
280
- endpoint: "/api/proxy/currency",
244
+ priceXlm: 0.1,
245
+ endpoint: "/api/proxy/stock-analyst",
281
246
  method: "GET",
282
247
  provider: "AgentMarket"
283
248
  },
284
249
  {
285
- name: "Geolocation",
286
- slug: "geolocation",
287
- description: "Get location data from IP address",
288
- category: "Geo",
289
- priceUsdc: 1e-3,
290
- endpoint: "/api/proxy/geolocation",
250
+ name: "Trading Advisor",
251
+ slug: "trading-advisor",
252
+ description: "Two-stage Gemini reasoning \u2192 BUY/HOLD/SELL with targets",
253
+ category: "Finance",
254
+ priceXlm: 0.5,
255
+ endpoint: "/api/proxy/trading-advisor",
291
256
  method: "GET",
292
257
  provider: "AgentMarket"
293
- },
294
- {
295
- name: "AI Inference",
296
- slug: "ai",
297
- description: "Run AI inference queries (GPT, Claude)",
298
- category: "AI",
299
- priceUsdc: 5e-3,
300
- endpoint: "/api/proxy/ai",
301
- method: "POST",
302
- provider: "AgentMarket"
303
258
  }
304
259
  ];
305
260
  var _registry = [...FALLBACK_REGISTRY];
@@ -309,10 +264,11 @@ function toApiInfo(entry) {
309
264
  slug: entry.slug,
310
265
  description: entry.description,
311
266
  category: entry.category,
312
- priceUsdc: entry.price.amount,
267
+ priceXlm: entry.price.amount,
313
268
  endpoint: entry.endpoint,
314
269
  method: entry.method,
315
- provider: entry.provider.name
270
+ provider: entry.provider.name,
271
+ params: Array.isArray(entry.input?.params) ? entry.input.params : []
316
272
  };
317
273
  }
318
274
  async function refreshRegistry(marketplaceUrl) {
@@ -375,13 +331,25 @@ async function callApi(slug, params, stellarClient) {
375
331
  if (!wallet) {
376
332
  return { success: false, error: "Wallet not configured. Run: agentmarket init" };
377
333
  }
378
- const usdcBalance = parseFloat(wallet.usdcBalance);
379
- if (usdcBalance < api.priceUsdc) {
334
+ const xlmBalance = parseFloat(wallet.xlmBalance);
335
+ const STELLAR_MIN_RESERVE = 1;
336
+ const spendable = Math.max(0, xlmBalance - STELLAR_MIN_RESERVE);
337
+ if (spendable < api.priceXlm) {
380
338
  return {
381
339
  success: false,
382
- error: `Insufficient USDC balance. Need ${api.priceUsdc}, have ${usdcBalance}`
340
+ error: `Insufficient spendable XLM. Need ${api.priceXlm} XLM (balance: ${xlmBalance} XLM, ${STELLAR_MIN_RESERVE} XLM reserved by Stellar \u2014 spendable: ${spendable.toFixed(4)} XLM)`
383
341
  };
384
342
  }
343
+ if (api.params?.length) {
344
+ const missing = api.params.filter((p) => p.required && (params[p.name] === void 0 || params[p.name] === null || params[p.name] === "")).map((p) => ` --${p.name} (${p.type}): ${p.description}`);
345
+ if (missing.length > 0) {
346
+ return {
347
+ success: false,
348
+ error: `Missing required params \u2014 no payment made:
349
+ ${missing.join("\n")}`
350
+ };
351
+ }
352
+ }
385
353
  const baseUrl = config2.marketplaceUrl;
386
354
  const initialRequest = buildRequest(api, baseUrl, params);
387
355
  try {
@@ -394,7 +362,12 @@ async function callApi(slug, params, stellarClient) {
394
362
  const recipient = paymentDetails.payment.recipient;
395
363
  const amount = paymentDetails.payment.amount;
396
364
  const memo = paymentDetails.payment?.memo || `am:${slug}:${Date.now()}`;
397
- const paymentResult = await stellarClient.sendPayment(recipient, amount, memo);
365
+ let paymentResult;
366
+ try {
367
+ paymentResult = await stellarClient.sendPayment(recipient, amount, memo);
368
+ } catch (err) {
369
+ return { success: false, error: err instanceof Error ? err.message : "Payment failed" };
370
+ }
398
371
  if (!paymentResult?.success) {
399
372
  return { success: false, error: "Payment failed" };
400
373
  }
@@ -414,7 +387,7 @@ async function callApi(slug, params, stellarClient) {
414
387
  success: false,
415
388
  error: `API call failed: ${retryResponse.status}`,
416
389
  txHash: paymentResult.txHash,
417
- amountPaid: api.priceUsdc
390
+ amountPaid: api.priceXlm
418
391
  };
419
392
  }
420
393
  const data = await retryResponse.json();
@@ -422,10 +395,10 @@ async function callApi(slug, params, stellarClient) {
422
395
  appendHistory({
423
396
  api: slug,
424
397
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
425
- amount: api.priceUsdc,
398
+ amount: api.priceXlm,
426
399
  txHash: paymentResult.txHash
427
400
  });
428
- return { success: true, data, txHash: paymentResult.txHash, amountPaid: api.priceUsdc, latencyMs };
401
+ return { success: true, data, txHash: paymentResult.txHash, amountPaid: api.priceXlm, latencyMs };
429
402
  }
430
403
  if (initialResponse.ok) {
431
404
  const data = await initialResponse.json();
@@ -444,15 +417,15 @@ async function callApi(slug, params, stellarClient) {
444
417
  dotenv.config();
445
418
  var program = new import_commander.Command();
446
419
  var banner = `
447
- _ _ __ __ _ _
448
- / \\ __ _ ___ _ __ | |_| \\/ | __ _ _ __| | _____| |_
420
+ _ _ __ __ _ _
421
+ / \\ __ _ ___ _ __ | |_| \\/ | __ _ _ __| | _____| |_
449
422
  / _ \\ / _\` |/ _ \\ '_ \\| __| |\\/| |/ _\` | '__| |/ / _ \\ __|
450
- / ___ \\ (_| | __/ | | | |_| | | | (_| | | | < __/ |_
423
+ / ___ \\ (_| | __/ | | | |_| | | | (_| | | | < __/ |_
451
424
  /_/ \\_\\__, |\\___|_| |_|\\__|_| |_|\\__,_|_| |_|\\_\\___|\\__|
452
- |___/
425
+ |___/
453
426
  `;
454
- program.name("agentmarket").description("AgentMarket CLI - Payment IS Authentication").version("0.1.0").addHelpText("beforeAll", import_chalk.default.cyan(banner));
455
- program.command("init").description("Initialize AgentMarket CLI with your wallet").option("-k, --key <secret>", "Stellar secret key").option("-n, --network <network>", "Stellar network (testnet/mainnet)", "testnet").option("--generate", "Generate a new Stellar keypair").action(async (options) => {
427
+ program.name("agentmarket").description("AgentMarket CLI - Payment IS Authentication").version("0.2.0").addHelpText("beforeAll", import_chalk.default.cyan(banner));
428
+ program.command("init").description("Initialize AgentMarket CLI with your wallet").option("-k, --key <secret>", "Stellar secret key").option("-n, --network <network>", "Stellar network (testnet/mainnet)", "mainnet").option("--generate", "Generate a new Stellar keypair").action(async (options) => {
456
429
  console.log(import_chalk.default.cyan(banner));
457
430
  console.log(import_chalk.default.bold("\nAgentMarket CLI Setup\n"));
458
431
  let secretKey = options.key;
@@ -499,8 +472,7 @@ program.command("init").description("Initialize AgentMarket CLI with your wallet
499
472
  const wallet = await stellarClient.getWalletInfo();
500
473
  if (wallet) {
501
474
  spinner.succeed("Wallet connected!");
502
- console.log(import_chalk.default.bold(` XLM Balance: `) + wallet.xlmBalance + " XLM");
503
- console.log(import_chalk.default.bold(` USDC Balance:`) + wallet.usdcBalance + " USDC");
475
+ console.log(import_chalk.default.bold(` XLM Balance: `) + import_chalk.default.cyan(wallet.xlmBalance + " XLM"));
504
476
  if (parseFloat(wallet.xlmBalance) === 0 && network === "testnet") {
505
477
  console.log(import_chalk.default.yellow("\nAccount not funded. Run: agentmarket fund"));
506
478
  }
@@ -535,8 +507,6 @@ program.command("fund").description("Fund testnet account using Friendbot").acti
535
507
  if (wallet) {
536
508
  console.log(import_chalk.default.bold(` XLM Balance: `) + wallet.xlmBalance + " XLM");
537
509
  }
538
- console.log(import_chalk.default.yellow("\nNote: You also need testnet USDC to make API calls."));
539
- console.log(import_chalk.default.dim(" Get testnet USDC from: https://laboratory.stellar.org"));
540
510
  } else {
541
511
  spinner.fail("Failed to fund account");
542
512
  }
@@ -557,12 +527,11 @@ program.command("balance").alias("bal").description("Check wallet balance").acti
557
527
  console.log(import_chalk.default.bold(" Network: ") + wallet.network);
558
528
  console.log(import_chalk.default.bold(" Address: ") + wallet.publicKey);
559
529
  console.log(import_chalk.default.bold(" XLM: ") + import_chalk.default.cyan(wallet.xlmBalance + " XLM"));
560
- console.log(import_chalk.default.bold(" USDC: ") + import_chalk.default.green(wallet.usdcBalance + " USDC"));
561
530
  } else {
562
531
  spinner.fail("Failed to fetch balance");
563
532
  }
564
533
  });
565
- program.command("list").alias("ls").description("List available APIs").option("-c, --category <category>", "Filter by category (Data, Finance, Geo, AI)").action(async (options) => {
534
+ program.command("list").alias("ls").description("List available APIs").option("-c, --category <category>", "Filter by category").action(async (options) => {
566
535
  const config2 = loadConfig();
567
536
  await refreshRegistry(config2.marketplaceUrl);
568
537
  const apis = listApis(options.category);
@@ -584,15 +553,15 @@ program.command("list").alias("ls").description("List available APIs").option("-
584
553
  console.log(import_chalk.default.bold.blue(`
585
554
  ${category}`));
586
555
  for (const api of categoryApis) {
587
- const price = import_chalk.default.green(`$${api.priceUsdc.toFixed(4)}`);
588
- console.log(` ${import_chalk.default.bold(api.slug.padEnd(15))} ${price.padEnd(15)} ${import_chalk.default.dim(api.description)}`);
556
+ const price = import_chalk.default.green(`${api.priceXlm} XLM`);
557
+ console.log(` ${import_chalk.default.bold(api.slug.padEnd(20))} ${price.padEnd(15)} ${import_chalk.default.dim(api.description)}`);
589
558
  }
590
559
  }
591
560
  console.log(import_chalk.default.dim("\n\u2500".repeat(70)));
592
- console.log(import_chalk.default.dim(` ${apis.length} APIs available | Prices in USDC per call
561
+ console.log(import_chalk.default.dim(` ${apis.length} APIs available | Prices in XLM per call
593
562
  `));
594
563
  });
595
- program.command("call <api>").description("Call an API with x402 payment").option("-p, --params <json>", "Parameters as JSON string").option("--city <city>", "City name (for weather/air-quality)").option("--topic <topic>", "Topic (for news)").option("--from <currency>", "Source currency (for currency)").option("--to <currency>", "Target currency (for currency)").option("--amount <amount>", "Amount to convert (for currency)").option("--ip <ip>", "IP address (for geolocation)").option("--prompt <prompt>", "Prompt (for ai)").option("--dry-run", "Show what would be called without making payment").action(async (apiSlug, options) => {
564
+ program.command("call <api>").description("Call an API with x402 payment").option("-p, --params <json>", "Parameters as JSON string").option("--symbol <symbol>", "Stock symbol (for stock-analyst/trading-advisor)").option("--dry-run", "Show what would be called without making payment").action(async (apiSlug, options) => {
596
565
  const config2 = loadConfig();
597
566
  await refreshRegistry(config2.marketplaceUrl);
598
567
  if (!config2.secretKey) {
@@ -614,19 +583,13 @@ program.command("call <api>").description("Call an API with x402 payment").optio
614
583
  process.exit(1);
615
584
  }
616
585
  } else {
617
- if (options.city) params.city = options.city;
618
- if (options.topic) params.topic = options.topic;
619
- if (options.from) params.from = options.from;
620
- if (options.to) params.to = options.to;
621
- if (options.amount) params.amount = parseFloat(options.amount);
622
- if (options.ip) params.ip = options.ip;
623
- if (options.prompt) params.prompt = options.prompt;
586
+ if (options.symbol) params.symbol = options.symbol;
624
587
  }
625
588
  console.log(import_chalk.default.bold(`
626
- Calling ${api.name} API
589
+ Calling ${api.name}
627
590
  `));
628
591
  console.log(import_chalk.default.dim(` Endpoint: ${api.endpoint}`));
629
- console.log(import_chalk.default.dim(` Price: ${api.priceUsdc} USDC`));
592
+ console.log(import_chalk.default.dim(` Price: ${api.priceXlm} XLM`));
630
593
  console.log(import_chalk.default.dim(` Params: ${JSON.stringify(params)}`));
631
594
  if (options.dryRun) {
632
595
  console.log(import_chalk.default.yellow("\n [DRY RUN] No payment made"));
@@ -634,7 +597,7 @@ Calling ${api.name} API
634
597
  }
635
598
  const stellarClient = new StellarClient(config2.stellarNetwork);
636
599
  stellarClient.setSecretKey(config2.secretKey);
637
- const spinner = (0, import_ora.default)("Making payment and calling API...").start();
600
+ const spinner = (0, import_ora.default)("Paying XLM and calling API...").start();
638
601
  const result = await callApi(apiSlug, params, stellarClient);
639
602
  if (result.success) {
640
603
  spinner.succeed("API call successful!");
@@ -644,7 +607,7 @@ Calling ${api.name} API
644
607
  console.log(import_chalk.default.dim(` Explorer: ${explorerUrl}`));
645
608
  }
646
609
  if (result.amountPaid) {
647
- console.log(import_chalk.default.dim(` Paid: ${result.amountPaid} USDC`));
610
+ console.log(import_chalk.default.dim(` Paid: ${result.amountPaid} XLM`));
648
611
  }
649
612
  if (result.latencyMs) {
650
613
  console.log(import_chalk.default.dim(` Latency: ${result.latencyMs}ms`));
@@ -668,26 +631,26 @@ program.command("history").alias("hist").description("Show call history").option
668
631
  console.log(import_chalk.default.dim(" No calls made yet"));
669
632
  return;
670
633
  }
671
- console.log(import_chalk.default.dim(" " + "Time".padEnd(20) + "API".padEnd(15) + "Amount".padEnd(12) + "Transaction"));
634
+ console.log(import_chalk.default.dim(" " + "Time".padEnd(20) + "API".padEnd(20) + "Amount".padEnd(12) + "Transaction"));
672
635
  console.log(import_chalk.default.dim(" " + "\u2500".repeat(70)));
673
636
  for (const call of recent) {
674
637
  const time = new Date(call.timestamp).toLocaleString();
675
- const amount = import_chalk.default.green(`$${call.amount.toFixed(4)}`);
638
+ const amount = import_chalk.default.green(`${call.amount.toFixed(1)} XLM`);
676
639
  const txShort = call.txHash.substring(0, 16) + "...";
677
- console.log(` ${time.padEnd(20)} ${call.api.padEnd(15)} ${amount.padEnd(12)} ${import_chalk.default.dim(txShort)}`);
640
+ console.log(` ${time.padEnd(20)} ${call.api.padEnd(20)} ${amount.padEnd(12)} ${import_chalk.default.dim(txShort)}`);
678
641
  }
679
642
  const totalSpent = history.calls.reduce((sum, c) => sum + c.amount, 0);
680
643
  console.log(import_chalk.default.dim(" " + "\u2500".repeat(70)));
681
- console.log(import_chalk.default.bold(` Total: ${history.calls.length} calls, ${import_chalk.default.green("$" + totalSpent.toFixed(4))} USDC spent`));
644
+ console.log(import_chalk.default.bold(` Total: ${history.calls.length} calls, ${import_chalk.default.green(totalSpent.toFixed(4) + " XLM")} spent`));
682
645
  });
683
- program.command("config").description("View or update configuration").option("--show", "Show current config").option("--network <network>", "Set network (testnet/mainnet)").option("--budget <amount>", "Set budget limit (USDC)").option("--marketplace <url>", "Set marketplace URL").action((options) => {
646
+ program.command("config").description("View or update configuration").option("--show", "Show current config").option("--network <network>", "Set network (testnet/mainnet)").option("--budget <amount>", "Set budget limit (XLM)").option("--marketplace <url>", "Set marketplace URL").action((options) => {
684
647
  const config2 = loadConfig();
685
- if (options.show || Object.keys(options).length === 1) {
648
+ if (options.show || !options.network && !options.budget && !options.marketplace) {
686
649
  console.log(import_chalk.default.bold("\nConfiguration\n"));
687
650
  console.log(import_chalk.default.dim(` Config file: ${getConfigPath()}`));
688
651
  console.log("");
689
652
  console.log(import_chalk.default.bold(" Network: ") + config2.stellarNetwork);
690
- console.log(import_chalk.default.bold(" Budget: ") + config2.budgetLimit + " USDC");
653
+ console.log(import_chalk.default.bold(" Budget: ") + config2.budgetLimit + " XLM");
691
654
  console.log(import_chalk.default.bold(" Marketplace: ") + config2.marketplaceUrl);
692
655
  console.log(import_chalk.default.bold(" Public Key: ") + (config2.publicKey || "Not set"));
693
656
  console.log(import_chalk.default.bold(" Secret Key: ") + (config2.secretKey ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : "Not set"));
@@ -727,31 +690,22 @@ ${api.name}
727
690
  console.log(import_chalk.default.bold(" Slug: ") + api.slug);
728
691
  console.log(import_chalk.default.bold(" Description: ") + api.description);
729
692
  console.log(import_chalk.default.bold(" Category: ") + api.category);
730
- console.log(import_chalk.default.bold(" Price: ") + import_chalk.default.green(`$${api.priceUsdc.toFixed(4)} USDC`));
693
+ console.log(import_chalk.default.bold(" Price: ") + import_chalk.default.green(`${api.priceXlm} XLM`));
731
694
  console.log(import_chalk.default.bold(" Provider: ") + api.provider);
732
695
  console.log(import_chalk.default.bold(" Endpoint: ") + api.endpoint);
696
+ if (api.params?.length) {
697
+ console.log(import_chalk.default.bold("\n Parameters:\n"));
698
+ for (const p of api.params) {
699
+ const req = p.required ? import_chalk.default.red("required") : import_chalk.default.dim("optional");
700
+ console.log(` ${import_chalk.default.bold(p.name.padEnd(15))} ${p.type.padEnd(10)} ${req.padEnd(18)} ${import_chalk.default.dim(p.description)}`);
701
+ }
702
+ }
703
+ const exampleParams = api.params?.filter((p) => p.required).map((p) => `"${p.name}": "<${p.type}>"`).join(", ") ?? "";
733
704
  console.log(import_chalk.default.bold("\n Example:\n"));
734
- switch (api.slug) {
735
- case "weather":
736
- console.log(import_chalk.default.cyan(' agentmarket call weather --city "New York"'));
737
- break;
738
- case "air-quality":
739
- console.log(import_chalk.default.cyan(' agentmarket call air-quality --city "Delhi"'));
740
- break;
741
- case "news":
742
- console.log(import_chalk.default.cyan(' agentmarket call news --topic "technology"'));
743
- break;
744
- case "currency":
745
- console.log(import_chalk.default.cyan(" agentmarket call currency --from USD --to EUR --amount 100"));
746
- break;
747
- case "geolocation":
748
- console.log(import_chalk.default.cyan(' agentmarket call geolocation --ip "8.8.8.8"'));
749
- break;
750
- case "ai":
751
- console.log(import_chalk.default.cyan(' agentmarket call ai --prompt "Explain quantum computing"'));
752
- break;
753
- default:
754
- console.log(import_chalk.default.cyan(` agentmarket call ${api.slug} -p '{"key": "value"}'`));
705
+ if (exampleParams) {
706
+ console.log(import_chalk.default.cyan(` agentmarket call ${api.slug} -p '{${exampleParams}}'`));
707
+ } else {
708
+ console.log(import_chalk.default.cyan(` agentmarket call ${api.slug}`));
755
709
  }
756
710
  });
757
711
  program.parse();
package/dist/index.d.ts CHANGED
@@ -9,21 +9,27 @@ interface Config {
9
9
  budgetLimit: number;
10
10
  contractId?: string;
11
11
  }
12
+ interface ApiParam {
13
+ name: string;
14
+ type: string;
15
+ required: boolean;
16
+ description: string;
17
+ }
12
18
  interface ApiInfo {
13
19
  name: string;
14
20
  slug: string;
15
21
  description: string;
16
22
  category: string;
17
- priceUsdc: number;
23
+ priceXlm: number;
18
24
  endpoint: string;
19
25
  method: 'GET' | 'POST';
20
26
  provider: string;
27
+ params?: ApiParam[];
21
28
  }
22
29
  interface WalletInfo {
23
30
  publicKey: string;
24
31
  network: 'testnet' | 'mainnet';
25
32
  xlmBalance: string;
26
- usdcBalance: string;
27
33
  }
28
34
  interface CallResult {
29
35
  success: boolean;
@@ -50,6 +56,7 @@ interface TransactionRecord {
50
56
 
51
57
  /**
52
58
  * AgentMarket CLI - Stellar Client
59
+ * Native XLM payments only
53
60
  */
54
61
 
55
62
  declare class StellarClient {
@@ -61,6 +68,7 @@ declare class StellarClient {
61
68
  getPublicKey(): string | null;
62
69
  getWalletInfo(): Promise<WalletInfo | null>;
63
70
  fundTestnetAccount(): Promise<string | null>;
71
+ /** Send native XLM payment */
64
72
  sendPayment(destination: string, amount: string, memo?: string): Promise<{
65
73
  txHash: string;
66
74
  success: boolean;
@@ -74,6 +82,7 @@ declare class StellarClient {
74
82
 
75
83
  /**
76
84
  * AgentMarket CLI - API Client
85
+ * Native XLM payments on Stellar mainnet
77
86
  */
78
87
 
79
88
  declare function listApis(category?: string): ApiInfo[];
@@ -97,4 +106,4 @@ declare function appendHistory(call: {
97
106
  txHash: string;
98
107
  }): void;
99
108
 
100
- export { type ApiInfo, type BudgetStatus, type CallResult, type Config, StellarClient, type TransactionRecord, type WalletInfo, appendHistory, callApi, getApiInfo, listApis, loadConfig, loadHistory, saveConfig };
109
+ export { type ApiInfo, type ApiParam, type BudgetStatus, type CallResult, type Config, StellarClient, type TransactionRecord, type WalletInfo, appendHistory, callApi, getApiInfo, listApis, loadConfig, loadHistory, saveConfig };
package/dist/index.js CHANGED
@@ -46,22 +46,18 @@ var StellarSdk = __toESM(require("@stellar/stellar-sdk"));
46
46
  var NETWORKS = {
47
47
  testnet: {
48
48
  networkPassphrase: StellarSdk.Networks.TESTNET,
49
- horizonUrl: "https://horizon-testnet.stellar.org",
50
- sorobanUrl: "https://soroban-testnet.stellar.org"
49
+ horizonUrl: "https://horizon-testnet.stellar.org"
51
50
  },
52
51
  mainnet: {
53
52
  networkPassphrase: StellarSdk.Networks.PUBLIC,
54
- horizonUrl: "https://horizon.stellar.org",
55
- sorobanUrl: "https://mainnet.stellar.org"
53
+ horizonUrl: "https://horizon.stellar.org"
56
54
  }
57
55
  };
58
- var USDC_TESTNET_ISSUER = "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5";
59
- var USDC_MAINNET_ISSUER = "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN";
60
56
  var StellarClient = class {
61
57
  network;
62
58
  server;
63
59
  keypair = null;
64
- constructor(network = "testnet") {
60
+ constructor(network = "mainnet") {
65
61
  this.network = network;
66
62
  const config = NETWORKS[network];
67
63
  this.server = new StellarSdk.Horizon.Server(config.horizonUrl);
@@ -77,27 +73,21 @@ var StellarClient = class {
77
73
  try {
78
74
  const account = await this.server.loadAccount(this.keypair.publicKey());
79
75
  let xlmBalance = "0";
80
- let usdcBalance = "0";
81
- const usdcIssuer = this.network === "testnet" ? USDC_TESTNET_ISSUER : USDC_MAINNET_ISSUER;
82
76
  for (const balance of account.balances) {
83
77
  if (balance.asset_type === "native") {
84
78
  xlmBalance = balance.balance;
85
- } else if (balance.asset_type !== "liquidity_pool_shares" && balance.asset_code === "USDC" && balance.asset_issuer === usdcIssuer) {
86
- usdcBalance = balance.balance;
87
79
  }
88
80
  }
89
81
  return {
90
82
  publicKey: this.keypair.publicKey(),
91
83
  network: this.network,
92
- xlmBalance,
93
- usdcBalance
84
+ xlmBalance
94
85
  };
95
86
  } catch (error) {
96
87
  return {
97
88
  publicKey: this.keypair.publicKey(),
98
89
  network: this.network,
99
- xlmBalance: "0",
100
- usdcBalance: "0"
90
+ xlmBalance: "0"
101
91
  };
102
92
  }
103
93
  }
@@ -114,26 +104,25 @@ var StellarClient = class {
114
104
  }
115
105
  return null;
116
106
  }
107
+ /** Send native XLM payment */
117
108
  async sendPayment(destination, amount, memo) {
118
109
  if (!this.keypair) return null;
119
110
  try {
120
111
  const account = await this.server.loadAccount(this.keypair.publicKey());
121
- const usdcIssuer = this.network === "testnet" ? USDC_TESTNET_ISSUER : USDC_MAINNET_ISSUER;
122
- const usdcAsset = new StellarSdk.Asset("USDC", usdcIssuer);
123
- const transaction = new StellarSdk.TransactionBuilder(account, {
112
+ const transactionBuilder = new StellarSdk.TransactionBuilder(account, {
124
113
  fee: StellarSdk.BASE_FEE,
125
114
  networkPassphrase: NETWORKS[this.network].networkPassphrase
126
115
  }).addOperation(
127
116
  StellarSdk.Operation.payment({
128
117
  destination,
129
- asset: usdcAsset,
118
+ asset: StellarSdk.Asset.native(),
130
119
  amount
131
120
  })
132
121
  ).setTimeout(30);
133
122
  if (memo) {
134
- transaction.addMemo(StellarSdk.Memo.text(memo.substring(0, 28)));
123
+ transactionBuilder.addMemo(StellarSdk.Memo.text(memo.substring(0, 28)));
135
124
  }
136
- const builtTx = transaction.build();
125
+ const builtTx = transactionBuilder.build();
137
126
  builtTx.sign(this.keypair);
138
127
  const result = await this.server.submitTransaction(builtTx);
139
128
  return {
@@ -141,8 +130,10 @@ var StellarClient = class {
141
130
  success: true
142
131
  };
143
132
  } catch (error) {
144
- console.error("Payment failed:", error);
145
- return null;
133
+ const axiosLike = error;
134
+ const resultCodes = axiosLike?.response?.data?.extras?.result_codes;
135
+ const detail = resultCodes ? `Horizon rejected tx: ${JSON.stringify(resultCodes)}` : error instanceof Error ? error.message : "Unknown error";
136
+ throw new Error(detail);
146
137
  }
147
138
  }
148
139
  async verifyTransaction(txHash) {
@@ -179,11 +170,11 @@ var CONTRACTS = {
179
170
  }
180
171
  };
181
172
  var DEFAULT_CONFIG = {
182
- stellarNetwork: "testnet",
183
- marketplaceUrl: "https://agentmarket.xyz",
173
+ stellarNetwork: "mainnet",
174
+ marketplaceUrl: "https://steller-web.vercel.app",
184
175
  budgetLimit: 10,
185
- // 10 USDC default
186
- contractId: CONTRACTS.testnet.budgetEnforcer
176
+ // 10 XLM default
177
+ contractId: CONTRACTS.mainnet.budgetEnforcer
187
178
  };
188
179
  function ensureConfigDir() {
189
180
  if (!fs.existsSync(CONFIG_DIR)) {
@@ -233,64 +224,24 @@ function appendHistory(call) {
233
224
  var REGISTRY_TTL_MS = 60 * 60 * 1e3;
234
225
  var FALLBACK_REGISTRY = [
235
226
  {
236
- name: "Weather",
237
- slug: "weather",
238
- description: "Get current weather data for any city worldwide",
239
- category: "Data",
240
- priceUsdc: 1e-3,
241
- endpoint: "/api/proxy/weather",
242
- method: "GET",
243
- provider: "AgentMarket"
244
- },
245
- {
246
- name: "Air Quality",
247
- slug: "air-quality",
248
- description: "Get real-time air quality index and pollution data",
249
- category: "Data",
250
- priceUsdc: 1e-3,
251
- endpoint: "/api/proxy/air-quality",
252
- method: "GET",
253
- provider: "AgentMarket"
254
- },
255
- {
256
- name: "News",
257
- slug: "news",
258
- description: "Fetch latest news headlines by topic",
259
- category: "Data",
260
- priceUsdc: 2e-3,
261
- endpoint: "/api/proxy/news",
262
- method: "GET",
263
- provider: "AgentMarket"
264
- },
265
- {
266
- name: "Currency Exchange",
267
- slug: "currency",
268
- description: "Convert between currencies with live rates",
227
+ name: "Stock Analyst",
228
+ slug: "stock-analyst",
229
+ description: "Live Yahoo Finance data + Gemini sentiment analysis",
269
230
  category: "Finance",
270
- priceUsdc: 1e-3,
271
- endpoint: "/api/proxy/currency",
231
+ priceXlm: 0.1,
232
+ endpoint: "/api/proxy/stock-analyst",
272
233
  method: "GET",
273
234
  provider: "AgentMarket"
274
235
  },
275
236
  {
276
- name: "Geolocation",
277
- slug: "geolocation",
278
- description: "Get location data from IP address",
279
- category: "Geo",
280
- priceUsdc: 1e-3,
281
- endpoint: "/api/proxy/geolocation",
237
+ name: "Trading Advisor",
238
+ slug: "trading-advisor",
239
+ description: "Two-stage Gemini reasoning \u2192 BUY/HOLD/SELL with targets",
240
+ category: "Finance",
241
+ priceXlm: 0.5,
242
+ endpoint: "/api/proxy/trading-advisor",
282
243
  method: "GET",
283
244
  provider: "AgentMarket"
284
- },
285
- {
286
- name: "AI Inference",
287
- slug: "ai",
288
- description: "Run AI inference queries (GPT, Claude)",
289
- category: "AI",
290
- priceUsdc: 5e-3,
291
- endpoint: "/api/proxy/ai",
292
- method: "POST",
293
- provider: "AgentMarket"
294
245
  }
295
246
  ];
296
247
  var _registry = [...FALLBACK_REGISTRY];
@@ -335,13 +286,25 @@ async function callApi(slug, params, stellarClient) {
335
286
  if (!wallet) {
336
287
  return { success: false, error: "Wallet not configured. Run: agentmarket init" };
337
288
  }
338
- const usdcBalance = parseFloat(wallet.usdcBalance);
339
- if (usdcBalance < api.priceUsdc) {
289
+ const xlmBalance = parseFloat(wallet.xlmBalance);
290
+ const STELLAR_MIN_RESERVE = 1;
291
+ const spendable = Math.max(0, xlmBalance - STELLAR_MIN_RESERVE);
292
+ if (spendable < api.priceXlm) {
340
293
  return {
341
294
  success: false,
342
- error: `Insufficient USDC balance. Need ${api.priceUsdc}, have ${usdcBalance}`
295
+ error: `Insufficient spendable XLM. Need ${api.priceXlm} XLM (balance: ${xlmBalance} XLM, ${STELLAR_MIN_RESERVE} XLM reserved by Stellar \u2014 spendable: ${spendable.toFixed(4)} XLM)`
343
296
  };
344
297
  }
298
+ if (api.params?.length) {
299
+ const missing = api.params.filter((p) => p.required && (params[p.name] === void 0 || params[p.name] === null || params[p.name] === "")).map((p) => ` --${p.name} (${p.type}): ${p.description}`);
300
+ if (missing.length > 0) {
301
+ return {
302
+ success: false,
303
+ error: `Missing required params \u2014 no payment made:
304
+ ${missing.join("\n")}`
305
+ };
306
+ }
307
+ }
345
308
  const baseUrl = config.marketplaceUrl;
346
309
  const initialRequest = buildRequest(api, baseUrl, params);
347
310
  try {
@@ -354,7 +317,12 @@ async function callApi(slug, params, stellarClient) {
354
317
  const recipient = paymentDetails.payment.recipient;
355
318
  const amount = paymentDetails.payment.amount;
356
319
  const memo = paymentDetails.payment?.memo || `am:${slug}:${Date.now()}`;
357
- const paymentResult = await stellarClient.sendPayment(recipient, amount, memo);
320
+ let paymentResult;
321
+ try {
322
+ paymentResult = await stellarClient.sendPayment(recipient, amount, memo);
323
+ } catch (err) {
324
+ return { success: false, error: err instanceof Error ? err.message : "Payment failed" };
325
+ }
358
326
  if (!paymentResult?.success) {
359
327
  return { success: false, error: "Payment failed" };
360
328
  }
@@ -374,7 +342,7 @@ async function callApi(slug, params, stellarClient) {
374
342
  success: false,
375
343
  error: `API call failed: ${retryResponse.status}`,
376
344
  txHash: paymentResult.txHash,
377
- amountPaid: api.priceUsdc
345
+ amountPaid: api.priceXlm
378
346
  };
379
347
  }
380
348
  const data = await retryResponse.json();
@@ -382,10 +350,10 @@ async function callApi(slug, params, stellarClient) {
382
350
  appendHistory({
383
351
  api: slug,
384
352
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
385
- amount: api.priceUsdc,
353
+ amount: api.priceXlm,
386
354
  txHash: paymentResult.txHash
387
355
  });
388
- return { success: true, data, txHash: paymentResult.txHash, amountPaid: api.priceUsdc, latencyMs };
356
+ return { success: true, data, txHash: paymentResult.txHash, amountPaid: api.priceXlm, latencyMs };
389
357
  }
390
358
  if (initialResponse.ok) {
391
359
  const data = await initialResponse.json();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agstell-cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "CLI for AgentMarket — discover and call APIs with x402 micropayments on Stellar",
5
5
  "main": "dist/index.js",
6
6
  "files": [