stelagent 0.0.4 → 0.0.5

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.mjs +244 -41
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -324,7 +324,7 @@ z.enum(["asc", "desc"]).default("desc");
324
324
  z.coerce.number().int().min(6e4);
325
325
  //#endregion
326
326
  //#region src/commands/wallet-login.ts
327
- function formatZodError$11(e) {
327
+ function formatZodError$12(e) {
328
328
  return e.issues.map((issue) => issue.message).join(", ");
329
329
  }
330
330
  const walletLogin = defineCommand({
@@ -355,7 +355,7 @@ const walletLogin = defineCommand({
355
355
  catch: (e) => e
356
356
  });
357
357
  if (Result.isError(validation)) {
358
- const msg = validation.error instanceof z.ZodError ? formatZodError$11(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
358
+ const msg = validation.error instanceof z.ZodError ? formatZodError$12(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
359
359
  printResult(Result.err(msg), format);
360
360
  return;
361
361
  }
@@ -534,7 +534,7 @@ const walletAddress = defineCommand({
534
534
  });
535
535
  //#endregion
536
536
  //#region src/services/stellar.ts
537
- const HORIZON_URLS$1 = {
537
+ const HORIZON_URLS$2 = {
538
538
  testnet: process.env.STELAGENT_HORIZON_TESTNET_URL ?? "https://horizon-testnet.stellar.org",
539
539
  pubnet: process.env.STELAGENT_HORIZON_PUBNET_URL ?? "https://horizon-mainnet.stellar.org"
540
540
  };
@@ -574,7 +574,7 @@ async function getBalances(publicKey, network) {
574
574
  return Result.tryPromise({
575
575
  try: async () => {
576
576
  const { Horizon } = await import("@stellar/stellar-sdk");
577
- return (await new Horizon.Server(HORIZON_URLS$1[network]).loadAccount(publicKey)).balances.map((b) => ({
577
+ return (await new Horizon.Server(HORIZON_URLS$2[network]).loadAccount(publicKey)).balances.map((b) => ({
578
578
  assetType: b.asset_type,
579
579
  assetCode: b.asset_type === "native" ? "XLM" : "asset_code" in b && typeof b.asset_code === "string" ? b.asset_code : "",
580
580
  balance: b.balance
@@ -587,7 +587,7 @@ async function transferXlm(sourceSecret, destination, amount, network) {
587
587
  return Result.tryPromise({
588
588
  try: async () => {
589
589
  const { Keypair, Asset, Operation, TransactionBuilder, Horizon } = await import("@stellar/stellar-sdk");
590
- const server = new Horizon.Server(HORIZON_URLS$1[network]);
590
+ const server = new Horizon.Server(HORIZON_URLS$2[network]);
591
591
  const sourceKp = Keypair.fromSecret(sourceSecret);
592
592
  let sourceAccount;
593
593
  try {
@@ -624,7 +624,7 @@ async function sendPayment(sourceSecret, destination, amount, assetStr, network,
624
624
  return Result.tryPromise({
625
625
  try: async () => {
626
626
  const { Keypair, Operation, TransactionBuilder, Horizon, Memo } = await import("@stellar/stellar-sdk");
627
- const server = new Horizon.Server(HORIZON_URLS$1[network]);
627
+ const server = new Horizon.Server(HORIZON_URLS$2[network]);
628
628
  const sourceKp = Keypair.fromSecret(sourceSecret);
629
629
  let sourceAccount;
630
630
  try {
@@ -686,7 +686,7 @@ const walletBalance = defineCommand({
686
686
  });
687
687
  //#endregion
688
688
  //#region src/commands/wallet-transfer.ts
689
- function formatZodError$10(e) {
689
+ function formatZodError$11(e) {
690
690
  return e.issues.map((issue) => issue.message).join(", ");
691
691
  }
692
692
  //#endregion
@@ -733,7 +733,7 @@ const walletCommand = defineCommand({
733
733
  catch: (e) => e
734
734
  });
735
735
  if (Result.isError(validation)) {
736
- const msg = validation.error instanceof z.ZodError ? formatZodError$10(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
736
+ const msg = validation.error instanceof z.ZodError ? formatZodError$11(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
737
737
  printResult(Result.err(msg), format);
738
738
  return;
739
739
  }
@@ -843,7 +843,7 @@ async function pay(url) {
843
843
  }
844
844
  //#endregion
845
845
  //#region src/commands/pay.ts
846
- function formatZodError$9(e) {
846
+ function formatZodError$10(e) {
847
847
  return e.issues.map((issue) => issue.message).join(", ");
848
848
  }
849
849
  const payCommand = defineCommand({
@@ -867,7 +867,7 @@ const payCommand = defineCommand({
867
867
  catch: (e) => e
868
868
  });
869
869
  if (Result.isError(validation)) {
870
- const msg = validation.error instanceof z.ZodError ? formatZodError$9(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
870
+ const msg = validation.error instanceof z.ZodError ? formatZodError$10(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
871
871
  printResult(Result.err(msg), format);
872
872
  return;
873
873
  }
@@ -880,12 +880,12 @@ const payCommand = defineCommand({
880
880
  });
881
881
  //#endregion
882
882
  //#region src/services/horizon.ts
883
- const HORIZON_URLS = {
883
+ const HORIZON_URLS$1 = {
884
884
  testnet: process.env.STELAGENT_HORIZON_TESTNET_URL ?? "https://horizon-testnet.stellar.org",
885
885
  pubnet: process.env.STELAGENT_HORIZON_PUBNET_URL ?? "https://horizon-mainnet.stellar.org"
886
886
  };
887
887
  function horizonServer(network) {
888
- return new Horizon.Server(HORIZON_URLS[network]);
888
+ return new Horizon.Server(HORIZON_URLS$1[network]);
889
889
  }
890
890
  function classifyHorizonError(e, address) {
891
891
  const message = e instanceof Error ? e.message : String(e);
@@ -1114,7 +1114,7 @@ function streamEffects(publicKey, network, opts, onMessage, onError) {
1114
1114
  }
1115
1115
  //#endregion
1116
1116
  //#region src/commands/account-details.ts
1117
- function formatZodError$8(e) {
1117
+ function formatZodError$9(e) {
1118
1118
  return e.issues.map((issue) => issue.message).join(", ");
1119
1119
  }
1120
1120
  const accountDetails = defineCommand({
@@ -1145,7 +1145,7 @@ const accountDetails = defineCommand({
1145
1145
  catch: (e) => e
1146
1146
  });
1147
1147
  if (Result.isError(validation)) {
1148
- const msg = validation.error instanceof z.ZodError ? formatZodError$8(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1148
+ const msg = validation.error instanceof z.ZodError ? formatZodError$9(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1149
1149
  printResult(Result.err(msg), format);
1150
1150
  return;
1151
1151
  }
@@ -1158,7 +1158,7 @@ const accountDetails = defineCommand({
1158
1158
  });
1159
1159
  //#endregion
1160
1160
  //#region src/commands/account-transactions.ts
1161
- function formatZodError$7(e) {
1161
+ function formatZodError$8(e) {
1162
1162
  return e.issues.map((issue) => issue.message).join(", ");
1163
1163
  }
1164
1164
  const accountTransactions = defineCommand({
@@ -1206,7 +1206,7 @@ const accountTransactions = defineCommand({
1206
1206
  catch: (e) => e
1207
1207
  });
1208
1208
  if (Result.isError(validation)) {
1209
- const msg = validation.error instanceof z.ZodError ? formatZodError$7(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1209
+ const msg = validation.error instanceof z.ZodError ? formatZodError$8(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1210
1210
  printResult(Result.err(msg), format);
1211
1211
  return;
1212
1212
  }
@@ -1227,7 +1227,7 @@ const accountTransactions = defineCommand({
1227
1227
  });
1228
1228
  //#endregion
1229
1229
  //#region src/commands/account-payments.ts
1230
- function formatZodError$6(e) {
1230
+ function formatZodError$7(e) {
1231
1231
  return e.issues.map((issue) => issue.message).join(", ");
1232
1232
  }
1233
1233
  const accountPayments = defineCommand({
@@ -1275,7 +1275,7 @@ const accountPayments = defineCommand({
1275
1275
  catch: (e) => e
1276
1276
  });
1277
1277
  if (Result.isError(validation)) {
1278
- const msg = validation.error instanceof z.ZodError ? formatZodError$6(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1278
+ const msg = validation.error instanceof z.ZodError ? formatZodError$7(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1279
1279
  printResult(Result.err(msg), format);
1280
1280
  return;
1281
1281
  }
@@ -1296,7 +1296,7 @@ const accountPayments = defineCommand({
1296
1296
  });
1297
1297
  //#endregion
1298
1298
  //#region src/commands/account-effects.ts
1299
- function formatZodError$5(e) {
1299
+ function formatZodError$6(e) {
1300
1300
  return e.issues.map((issue) => issue.message).join(", ");
1301
1301
  }
1302
1302
  //#endregion
@@ -1349,7 +1349,7 @@ const accountCommand = defineCommand({
1349
1349
  catch: (e) => e
1350
1350
  });
1351
1351
  if (Result.isError(validation)) {
1352
- const msg = validation.error instanceof z.ZodError ? formatZodError$5(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1352
+ const msg = validation.error instanceof z.ZodError ? formatZodError$6(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1353
1353
  printResult(Result.err(msg), format);
1354
1354
  return;
1355
1355
  }
@@ -1371,7 +1371,7 @@ const accountCommand = defineCommand({
1371
1371
  });
1372
1372
  //#endregion
1373
1373
  //#region src/commands/assets-search.ts
1374
- function formatZodError$4(e) {
1374
+ function formatZodError$5(e) {
1375
1375
  return e.issues.map((issue) => issue.message).join(", ");
1376
1376
  }
1377
1377
  //#endregion
@@ -1420,7 +1420,7 @@ const assetsCommand = defineCommand({
1420
1420
  catch: (e) => e
1421
1421
  });
1422
1422
  if (Result.isError(validation)) {
1423
- const msg = validation.error instanceof z.ZodError ? formatZodError$4(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1423
+ const msg = validation.error instanceof z.ZodError ? formatZodError$5(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1424
1424
  printResult(Result.err(msg), format);
1425
1425
  return;
1426
1426
  }
@@ -1507,7 +1507,7 @@ const assetsCommand = defineCommand({
1507
1507
  });
1508
1508
  //#endregion
1509
1509
  //#region src/commands/send.ts
1510
- function formatZodError$3(e) {
1510
+ function formatZodError$4(e) {
1511
1511
  return e.issues.map((issue) => issue.message).join(", ");
1512
1512
  }
1513
1513
  const sendCommand = defineCommand({
@@ -1562,7 +1562,7 @@ const sendCommand = defineCommand({
1562
1562
  catch: (e) => e
1563
1563
  });
1564
1564
  if (Result.isError(validation)) {
1565
- const msg = validation.error instanceof z.ZodError ? formatZodError$3(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1565
+ const msg = validation.error instanceof z.ZodError ? formatZodError$4(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1566
1566
  printResult(Result.err(msg), format);
1567
1567
  return;
1568
1568
  }
@@ -1610,7 +1610,7 @@ const feeCommand = defineCommand({
1610
1610
  });
1611
1611
  //#endregion
1612
1612
  //#region src/commands/monitor-transactions.ts
1613
- function formatZodError$2(e) {
1613
+ function formatZodError$3(e) {
1614
1614
  return e.issues.map((issue) => issue.message).join(", ");
1615
1615
  }
1616
1616
  const monitorTransactions = defineCommand({
@@ -1647,7 +1647,7 @@ const monitorTransactions = defineCommand({
1647
1647
  catch: (e) => e
1648
1648
  });
1649
1649
  if (Result.isError(validation)) {
1650
- const msg = validation.error instanceof z.ZodError ? formatZodError$2(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1650
+ const msg = validation.error instanceof z.ZodError ? formatZodError$3(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1651
1651
  printResult(Result.err(msg), format);
1652
1652
  return;
1653
1653
  }
@@ -1687,7 +1687,7 @@ const monitorTransactions = defineCommand({
1687
1687
  });
1688
1688
  //#endregion
1689
1689
  //#region src/commands/monitor-payments.ts
1690
- function formatZodError$1(e) {
1690
+ function formatZodError$2(e) {
1691
1691
  return e.issues.map((issue) => issue.message).join(", ");
1692
1692
  }
1693
1693
  const monitorPayments = defineCommand({
@@ -1724,7 +1724,7 @@ const monitorPayments = defineCommand({
1724
1724
  catch: (e) => e
1725
1725
  });
1726
1726
  if (Result.isError(validation)) {
1727
- const msg = validation.error instanceof z.ZodError ? formatZodError$1(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1727
+ const msg = validation.error instanceof z.ZodError ? formatZodError$2(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1728
1728
  printResult(Result.err(msg), format);
1729
1729
  return;
1730
1730
  }
@@ -1764,7 +1764,7 @@ const monitorPayments = defineCommand({
1764
1764
  });
1765
1765
  //#endregion
1766
1766
  //#region src/commands/monitor-effects.ts
1767
- function formatZodError(e) {
1767
+ function formatZodError$1(e) {
1768
1768
  return e.issues.map((issue) => issue.message).join(", ");
1769
1769
  }
1770
1770
  //#endregion
@@ -1811,7 +1811,7 @@ const monitorCommand = defineCommand({
1811
1811
  catch: (e) => e
1812
1812
  });
1813
1813
  if (Result.isError(validation)) {
1814
- const msg = validation.error instanceof z.ZodError ? formatZodError(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1814
+ const msg = validation.error instanceof z.ZodError ? formatZodError$1(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
1815
1815
  printResult(Result.err(msg), format);
1816
1816
  return;
1817
1817
  }
@@ -2174,6 +2174,126 @@ function registerAssetTools(server) {
2174
2174
  });
2175
2175
  }
2176
2176
  //#endregion
2177
+ //#region src/services/preflight.ts
2178
+ const HORIZON_URLS = {
2179
+ testnet: process.env.STELAGENT_HORIZON_TESTNET_URL ?? "https://horizon-testnet.stellar.org",
2180
+ pubnet: process.env.STELAGENT_HORIZON_PUBNET_URL ?? "https://horizon-mainnet.stellar.org"
2181
+ };
2182
+ const BASE_RESERVE = "1";
2183
+ const LINE_RESERVE = "0.5";
2184
+ async function preflightSend(destination, amount, assetStr, network) {
2185
+ const walletResult = await fetchWallet();
2186
+ if (Result.isError(walletResult)) return Result.err(walletResult.error);
2187
+ const wallet = walletResult.value;
2188
+ const sender = wallet.publicKey;
2189
+ const server = new Horizon.Server(HORIZON_URLS[network]);
2190
+ let senderAccount;
2191
+ let senderFunded = true;
2192
+ let destinationFunded = true;
2193
+ let destinationFundingRequired = false;
2194
+ const warnings = [];
2195
+ try {
2196
+ senderAccount = await server.loadAccount(sender);
2197
+ } catch {
2198
+ senderFunded = false;
2199
+ const msg = wallet.network === "testnet" ? `Sender account ${sender.slice(0, 8)}... is not funded. Use wallet login to auto-fund on testnet.` : `Sender account ${sender.slice(0, 8)}... is not funded. Send at least 1 XLM to activate it.`;
2200
+ return Result.ok({
2201
+ canProceed: false,
2202
+ sender,
2203
+ destination,
2204
+ amount,
2205
+ asset: assetStr === "native" ? "XLM" : assetStr,
2206
+ network,
2207
+ senderFunded,
2208
+ destinationFunded: true,
2209
+ destinationFundingRequired: false,
2210
+ balances: [],
2211
+ estimatedFee: "0",
2212
+ baseReserve: BASE_RESERVE,
2213
+ warnings: [msg]
2214
+ });
2215
+ }
2216
+ let feeStatsResult;
2217
+ try {
2218
+ const stats = await server.feeStats();
2219
+ feeStatsResult = {
2220
+ feeCharged: { mode: stats.fee_charged.mode },
2221
+ maxFee: { mode: stats.max_fee.mode }
2222
+ };
2223
+ } catch {
2224
+ feeStatsResult = {
2225
+ feeCharged: { mode: "100" },
2226
+ maxFee: { mode: "100" }
2227
+ };
2228
+ }
2229
+ const estimatedFee = feeStatsResult.feeCharged.mode;
2230
+ const balances = [];
2231
+ let sufficientOverall = true;
2232
+ for (const b of senderAccount.balances) {
2233
+ const code = b.asset_type === "native" ? "XLM" : "asset_code" in b ? String(b.asset_code) : "";
2234
+ const available = Number(b.balance);
2235
+ if (b.asset_type === "native") {
2236
+ const subentryCount = senderAccount.subentry_count;
2237
+ const effectiveAvailable = available - (Number(BASE_RESERVE) + Number(LINE_RESERVE) * subentryCount);
2238
+ const needed = Number(amount) + Number(estimatedFee) / 1e7;
2239
+ const sufficient = effectiveAvailable >= needed;
2240
+ if (!sufficient) sufficientOverall = false;
2241
+ balances.push({
2242
+ asset: "XLM",
2243
+ available: effectiveAvailable.toFixed(7),
2244
+ needed: needed.toFixed(7),
2245
+ sufficient
2246
+ });
2247
+ } else if (assetStr !== "native" && code === assetStr.split(":")[0] || assetStr === code) {
2248
+ const needed = Number(amount);
2249
+ const sufficient = available >= needed;
2250
+ if (!sufficient) sufficientOverall = false;
2251
+ balances.push({
2252
+ asset: code,
2253
+ available: available.toFixed(7),
2254
+ needed: needed.toFixed(7),
2255
+ sufficient
2256
+ });
2257
+ }
2258
+ }
2259
+ try {
2260
+ await server.loadAccount(destination);
2261
+ } catch {
2262
+ destinationFunded = false;
2263
+ destinationFundingRequired = true;
2264
+ if (assetStr === "native") warnings.push(`Destination ${destination.slice(0, 8)}... is not funded. The transaction will create the account if amount >= 1 XLM.`);
2265
+ else {
2266
+ warnings.push(`Destination ${destination.slice(0, 8)}... is not funded. Cannot send custom assets to an unfunded account. The destination must first receive XLM.`);
2267
+ sufficientOverall = false;
2268
+ }
2269
+ }
2270
+ if (assetStr === "native") {
2271
+ const totalNeeded = Number(amount) + Number(estimatedFee) / 1e7;
2272
+ const xlmBalance = senderAccount.balances.find((b) => b.asset_type === "native");
2273
+ if (xlmBalance) {
2274
+ const subentryCount = senderAccount.subentry_count;
2275
+ const minReserve = Number(BASE_RESERVE) + Number(LINE_RESERVE) * subentryCount;
2276
+ if (Number(xlmBalance.balance) - totalNeeded - minReserve < 0) warnings.push(`After sending ${amount} XLM + fees, remaining balance would fall below minimum reserve (${minReserve} XLM).`);
2277
+ }
2278
+ }
2279
+ const canProceed = senderFunded && sufficientOverall;
2280
+ return Result.ok({
2281
+ canProceed,
2282
+ sender,
2283
+ destination,
2284
+ amount,
2285
+ asset: assetStr === "native" ? "XLM" : assetStr,
2286
+ network,
2287
+ senderFunded,
2288
+ destinationFunded,
2289
+ destinationFundingRequired,
2290
+ balances,
2291
+ estimatedFee,
2292
+ baseReserve: BASE_RESERVE,
2293
+ warnings
2294
+ });
2295
+ }
2296
+ //#endregion
2177
2297
  //#region src/mcp/payment-tools.ts
2178
2298
  function ok(data) {
2179
2299
  return { content: [{
@@ -2231,6 +2351,25 @@ function registerPaymentTools(server) {
2231
2351
  if (Result.isError(result)) return err(formatPaymentError(result.error));
2232
2352
  return ok(result.value);
2233
2353
  });
2354
+ server.registerTool("preflight_check", {
2355
+ description: "Validate a payment before sending. Checks if the sender has sufficient balance, estimates fees, and verifies the destination account. Returns whether the transaction can proceed, along with detailed balance info and warnings.",
2356
+ inputSchema: {
2357
+ destination: z.string().describe("Destination public key (G...)"),
2358
+ amount: z.string().describe("Amount to validate (up to 7 decimal places)"),
2359
+ asset: z.string().default("native").describe("Asset: 'native' for XLM, or 'CODE:ISSUER' for custom assets"),
2360
+ network: z.enum(["testnet", "pubnet"]).default("testnet").describe("Stellar network")
2361
+ }
2362
+ }, async ({ destination, amount, asset, network }) => {
2363
+ const destValidation = stellarPublicKey.safeParse(destination);
2364
+ if (!destValidation.success) return err(`Invalid destination: ${destValidation.error.issues.map((i) => i.message).join(", ")}`);
2365
+ const amountValidation = amountSchema.safeParse(amount);
2366
+ if (!amountValidation.success) return err(`Invalid amount: ${amountValidation.error.issues.map((i) => i.message).join(", ")}`);
2367
+ const assetValidation = assetSchema.safeParse(asset);
2368
+ if (!assetValidation.success) return err(`Invalid asset: ${assetValidation.error.issues.map((i) => i.message).join(", ")}`);
2369
+ const result = await preflightSend(destination, amount, asset, network === "pubnet" ? "pubnet" : "testnet");
2370
+ if (Result.isError(result)) return err(formatWalletError(result.error));
2371
+ return ok(result.value);
2372
+ });
2234
2373
  }
2235
2374
  //#endregion
2236
2375
  //#region src/mcp/mod.ts
@@ -2253,6 +2392,29 @@ async function startMcpServer() {
2253
2392
  await server.connect(transport);
2254
2393
  }
2255
2394
  //#endregion
2395
+ //#region src/commands/mcp.ts
2396
+ const mcpCommand = defineCommand({
2397
+ meta: {
2398
+ name: "mcp",
2399
+ description: "Start the MCP server on stdio"
2400
+ },
2401
+ args: {},
2402
+ async run() {
2403
+ try {
2404
+ await startMcpServer();
2405
+ } catch (e) {
2406
+ const message = e instanceof Error ? e.message : String(e);
2407
+ console.error(`Failed to start MCP server: ${message}`);
2408
+ process.exit(1);
2409
+ }
2410
+ }
2411
+ });
2412
+ //#endregion
2413
+ //#region src/commands/preflight.ts
2414
+ function formatZodError(e) {
2415
+ return e.issues.map((issue) => issue.message).join(", ");
2416
+ }
2417
+ //#endregion
2256
2418
  //#region src/index.ts
2257
2419
  runMain(defineCommand({
2258
2420
  meta: {
@@ -2268,20 +2430,61 @@ runMain(defineCommand({
2268
2430
  send: sendCommand,
2269
2431
  fee: feeCommand,
2270
2432
  monitor: monitorCommand,
2271
- mcp: defineCommand({
2433
+ mcp: mcpCommand,
2434
+ preflight: defineCommand({
2272
2435
  meta: {
2273
- name: "mcp",
2274
- description: "Start the MCP server on stdio"
2436
+ name: "preflight",
2437
+ description: "Validate a payment before sending: check balances, fees, and destination"
2275
2438
  },
2276
- args: {},
2277
- async run() {
2278
- try {
2279
- await startMcpServer();
2280
- } catch (e) {
2281
- const message = e instanceof Error ? e.message : String(e);
2282
- console.error(`Failed to start MCP server: ${message}`);
2283
- process.exit(1);
2439
+ args: {
2440
+ destination: {
2441
+ type: "positional",
2442
+ description: "Destination public key (G...)",
2443
+ required: true
2444
+ },
2445
+ amount: {
2446
+ type: "string",
2447
+ alias: ["a"],
2448
+ description: "Amount to validate",
2449
+ required: true
2450
+ },
2451
+ asset: {
2452
+ type: "string",
2453
+ alias: ["s"],
2454
+ description: "Asset: 'native' (default) or 'CODE:ISSUER'",
2455
+ default: "native"
2456
+ },
2457
+ network: networkArg,
2458
+ format: formatArg
2459
+ },
2460
+ async run({ args }) {
2461
+ const networkResult = parseNetwork$4(String(args.network ?? "testnet"));
2462
+ const format = parseFormat(String(args.format ?? "json"));
2463
+ if (Result.isError(networkResult)) {
2464
+ printResult(Result.err(networkResult.error._tag), "json");
2465
+ return;
2466
+ }
2467
+ const destination = String(args.destination ?? "");
2468
+ const amount = String(args.amount ?? "");
2469
+ const asset = String(args.asset ?? "native");
2470
+ const validation = Result.try({
2471
+ try: () => {
2472
+ stellarPublicKey.parse(destination);
2473
+ amountSchema.parse(amount);
2474
+ assetSchema.parse(asset);
2475
+ },
2476
+ catch: (e) => e
2477
+ });
2478
+ if (Result.isError(validation)) {
2479
+ const msg = validation.error instanceof z.ZodError ? formatZodError(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
2480
+ printResult(Result.err(msg), format);
2481
+ return;
2284
2482
  }
2483
+ await runCommand(async () => {
2484
+ const result = await preflightSend(destination, amount, asset, networkResult.value);
2485
+ if (Result.isError(result)) return Result.err(formatWalletError(result.error));
2486
+ return Result.ok(result.value);
2487
+ }, format);
2285
2488
  }
2286
2489
  })
2287
2490
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stelagent",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Modular, agent-first CLI for Stellar — wallet, payments, markets, and DeFi",
5
5
  "license": "MIT",
6
6
  "bin": {