@paysponge/sdk 0.1.75 → 0.1.88

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 (87) hide show
  1. package/README.md +5 -0
  2. package/dist/api/generated/openapi/apis/default-api.d.ts +180 -1
  3. package/dist/api/generated/openapi/apis/default-api.d.ts.map +1 -1
  4. package/dist/api/generated/openapi/apis/default-api.js +179 -1
  5. package/dist/api/generated/openapi/apis/default-api.js.map +1 -1
  6. package/dist/api/generated/openapi/models/index.d.ts +2 -0
  7. package/dist/api/generated/openapi/models/index.d.ts.map +1 -1
  8. package/dist/api/generated/openapi/models/index.js +2 -0
  9. package/dist/api/generated/openapi/models/index.js.map +1 -1
  10. package/dist/api/generated/openapi/models/post-api-bank-onboard-request.d.ts +6 -0
  11. package/dist/api/generated/openapi/models/post-api-bank-onboard-request.d.ts.map +1 -1
  12. package/dist/api/generated/openapi/models/post-api-bank-onboard-request.js +2 -0
  13. package/dist/api/generated/openapi/models/post-api-bank-onboard-request.js.map +1 -1
  14. package/dist/api/generated/openapi/models/post-api-hackathon-claim-request.d.ts +45 -0
  15. package/dist/api/generated/openapi/models/post-api-hackathon-claim-request.d.ts.map +1 -0
  16. package/dist/api/generated/openapi/models/post-api-hackathon-claim-request.js +52 -0
  17. package/dist/api/generated/openapi/models/post-api-hackathon-claim-request.js.map +1 -0
  18. package/dist/api/generated/openapi/models/post-api-hackathon-validate-request.d.ts +39 -0
  19. package/dist/api/generated/openapi/models/post-api-hackathon-validate-request.d.ts.map +1 -0
  20. package/dist/api/generated/openapi/models/post-api-hackathon-validate-request.js +48 -0
  21. package/dist/api/generated/openapi/models/post-api-hackathon-validate-request.js.map +1 -0
  22. package/dist/api/generated/openapi/models/post-api-mpp-fetch-request.d.ts +1 -1
  23. package/dist/api/generated/openapi/models/post-api-mpp-fetch-request.js +2 -2
  24. package/dist/api/generated/openapi/models/post-api-mpp-fetch-request.js.map +1 -1
  25. package/dist/api/generated/openapi/models/post-api-mpp-session-start-request.d.ts +1 -1
  26. package/dist/api/generated/openapi/models/post-api-mpp-session-start-request.js +2 -2
  27. package/dist/api/generated/openapi/models/post-api-mpp-session-start-request.js.map +1 -1
  28. package/dist/api/generated/openapi/models/post-api-onramp-crypto-request.d.ts +1 -1
  29. package/dist/api/generated/openapi/models/post-api-onramp-crypto-request.js +1 -1
  30. package/dist/api/generated/openapi/models/post-api-onramp-crypto-request.js.map +1 -1
  31. package/dist/api/generated/openapi/models/post-api-paid-fetch-request.d.ts +14 -0
  32. package/dist/api/generated/openapi/models/post-api-paid-fetch-request.d.ts.map +1 -1
  33. package/dist/api/generated/openapi/models/post-api-paid-fetch-request.js +9 -0
  34. package/dist/api/generated/openapi/models/post-api-paid-fetch-request.js.map +1 -1
  35. package/dist/api/generated/openapi/models/post-api-sponge-card-contracts-by-contract-id-fund-request.d.ts +6 -0
  36. package/dist/api/generated/openapi/models/post-api-sponge-card-contracts-by-contract-id-fund-request.d.ts.map +1 -1
  37. package/dist/api/generated/openapi/models/post-api-sponge-card-contracts-by-contract-id-fund-request.js +2 -0
  38. package/dist/api/generated/openapi/models/post-api-sponge-card-contracts-by-contract-id-fund-request.js.map +1 -1
  39. package/dist/api/generated/openapi/models/post-api-sponge-card-onboard-request.d.ts +11 -5
  40. package/dist/api/generated/openapi/models/post-api-sponge-card-onboard-request.d.ts.map +1 -1
  41. package/dist/api/generated/openapi/models/post-api-sponge-card-onboard-request.js +7 -15
  42. package/dist/api/generated/openapi/models/post-api-sponge-card-onboard-request.js.map +1 -1
  43. package/dist/api/generated/openapi/models/post-api-transactions-bridge-request.d.ts +14 -14
  44. package/dist/api/generated/openapi/models/post-api-transactions-bridge-request.js +15 -15
  45. package/dist/api/generated/openapi/models/post-api-transactions-bridge-request.js.map +1 -1
  46. package/dist/api/generated/openapi/models/post-api-transfers-evm-request.d.ts +1 -0
  47. package/dist/api/generated/openapi/models/post-api-transfers-evm-request.d.ts.map +1 -1
  48. package/dist/api/generated/openapi/models/post-api-transfers-evm-request.js +1 -0
  49. package/dist/api/generated/openapi/models/post-api-transfers-evm-request.js.map +1 -1
  50. package/dist/api/http.d.ts +10 -0
  51. package/dist/api/http.d.ts.map +1 -1
  52. package/dist/api/http.js +26 -0
  53. package/dist/api/http.js.map +1 -1
  54. package/dist/api/public-tools.d.ts +1 -0
  55. package/dist/api/public-tools.d.ts.map +1 -1
  56. package/dist/api/public-tools.js.map +1 -1
  57. package/dist/api/transactions.js +1 -1
  58. package/dist/api/transactions.js.map +1 -1
  59. package/dist/auth/device-flow.d.ts.map +1 -1
  60. package/dist/auth/device-flow.js +6 -0
  61. package/dist/auth/device-flow.js.map +1 -1
  62. package/dist/cli.d.ts.map +1 -1
  63. package/dist/cli.js +484 -2
  64. package/dist/cli.js.map +1 -1
  65. package/dist/client.d.ts +3 -2
  66. package/dist/client.d.ts.map +1 -1
  67. package/dist/client.js.map +1 -1
  68. package/dist/platform.d.ts +5 -5
  69. package/dist/platform.d.ts.map +1 -1
  70. package/dist/platform.js +90 -38
  71. package/dist/platform.js.map +1 -1
  72. package/dist/registration.d.ts.map +1 -1
  73. package/dist/registration.js +4 -0
  74. package/dist/registration.js.map +1 -1
  75. package/dist/tools/definitions.d.ts.map +1 -1
  76. package/dist/tools/definitions.js +450 -10
  77. package/dist/tools/definitions.js.map +1 -1
  78. package/dist/tools/executor.d.ts.map +1 -1
  79. package/dist/tools/executor.js +116 -0
  80. package/dist/tools/executor.js.map +1 -1
  81. package/dist/types/schemas.d.ts +38 -23
  82. package/dist/types/schemas.d.ts.map +1 -1
  83. package/dist/types/schemas.js +20 -4
  84. package/dist/types/schemas.js.map +1 -1
  85. package/dist/version.d.ts +1 -1
  86. package/dist/version.js +1 -1
  87. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,16 +1,32 @@
1
1
  import { Command, Help, Option } from "commander";
2
2
  import * as p from "@clack/prompts";
3
3
  import { SpongeWallet } from "./client.js";
4
+ import { setVersionNoticeHandler } from "./api/http.js";
5
+ import { SDK_VERSION } from "./version.js";
4
6
  import { deviceFlowAuth } from "./auth/device-flow.js";
5
7
  import { deleteCredentials, hasCredentials, getCredentialsPath, loadCredentials, saveCredentials, } from "./auth/credentials.js";
6
8
  import { registerAgentFirst } from "./registration.js";
7
9
  import { captureCliCommandEvent, classifyBaseUrl, sanitizeErrorForTelemetry, shutdownCliTelemetry, } from "./telemetry.js";
8
10
  import { TOOL_DEFINITIONS, } from "./tools/definitions.js";
9
11
  const DEFAULT_BASE_URL = "https://api.wallet.paysponge.com";
12
+ const DEFAULT_APP_URL = "https://wallet.paysponge.com";
13
+ const WALLET_SKILL_NAME = "sponge-wallet";
14
+ const WALLET_SKILL_VERSION = "0.2.2";
15
+ const WALLET_SKILL_URL = "https://wallet.paysponge.com/skill.md";
16
+ const CLI_SKILL_NAME = "spongewallet-cli";
17
+ const CLI_SKILL_VERSION = "0.1.1";
18
+ const CLI_SKILL_URL = "https://docs.paysponge.com/cli-skill.md";
10
19
  // ---------------------------------------------------------------------------
11
20
  // CLI setup
12
21
  // ---------------------------------------------------------------------------
13
22
  export function buildCliProgram(metadata = {}) {
23
+ setVersionNoticeHandler((notice) => {
24
+ const message = notice.message ?? `Sponge SDK status: ${notice.status}`;
25
+ const skill = notice.walletSkillUrl
26
+ ? ` Redownload ${notice.walletSkillUrl}${notice.walletSkillVersion ? ` for skill v${notice.walletSkillVersion}` : ""}.`
27
+ : "";
28
+ console.error(`[spongewallet] ${message}${skill}`);
29
+ });
14
30
  const cmdName = metadata.commandName ?? "spongewallet";
15
31
  const pkgName = metadata.packageName ?? "@paysponge/sdk";
16
32
  const version = metadata.version ?? "0.1.0";
@@ -32,6 +48,7 @@ export function buildCliProgram(metadata = {}) {
32
48
  .description("Create an agent, show wallet addresses, and print MCP config"))
33
49
  .option("--claim-required", "include claim text (default)")
34
50
  .option("--no-claim-required", "disable claim text")
51
+ .option("--switch", "replace cached credentials with a newly created agent")
35
52
  .action((opts) => handleInit(opts, metadata));
36
53
  withAuth(program
37
54
  .command("login")
@@ -43,6 +60,10 @@ export function buildCliProgram(metadata = {}) {
43
60
  shared(program
44
61
  .command("whoami")
45
62
  .description("Show current authentication status")).action((opts) => handleWhoami(opts, metadata));
63
+ shared(program.command("version").description("Show CLI, API header, and skill versions"))
64
+ .option("--json", "print raw JSON")
65
+ .option("--check", "check the Sponge API and npm for newer versions")
66
+ .action((opts) => handleVersion(opts, metadata));
46
67
  const mcpCmd = program
47
68
  .command("mcp")
48
69
  .description("MCP configuration commands");
@@ -100,6 +121,14 @@ async function handleLogin(opts) {
100
121
  });
101
122
  }
102
123
  async function handleInit(opts, meta) {
124
+ const existingCredentials = loadCredentials(opts.credentialsPath);
125
+ if (existingCredentials && !opts.switch) {
126
+ const currentAgent = existingCredentials.agentName
127
+ ? `${existingCredentials.agentName} (${existingCredentials.agentId})`
128
+ : existingCredentials.agentId;
129
+ throw new Error(`Refusing to overwrite existing Sponge credentials for ${currentAgent}. ` +
130
+ "Run `spongewallet whoami` to inspect the current agent, or use `spongewallet init --switch` to create and switch to a new one.");
131
+ }
103
132
  const registration = await registerAgentFirst({
104
133
  name: opts.name ?? defaultAgentName(opts.email),
105
134
  email: opts.email,
@@ -154,6 +183,7 @@ async function printOnboardingSummary(args) {
154
183
  p.note(mcpSnippet, "MCP Config");
155
184
  const cmd = meta.commandName ?? "spongewallet";
156
185
  p.log.step(`Next: ${cmd} mcp print`);
186
+ p.log.step(skillRefreshPrompt());
157
187
  p.log.step("Set SPONGE_API_KEY on other machines for non-interactive access");
158
188
  p.outro("Done!");
159
189
  }
@@ -224,6 +254,70 @@ async function handleMcpPrint(opts) {
224
254
  }
225
255
  p.note(JSON.stringify(config, null, 2), "MCP Config");
226
256
  p.note(JSON.stringify({ mcpServers: { sponge: config } }, null, 2), "Claude Code / Cursor snippet");
257
+ p.log.step(skillRefreshPrompt());
258
+ }
259
+ async function handleVersion(opts, meta) {
260
+ const current = {
261
+ command: meta.commandName ?? "spongewallet",
262
+ packageName: meta.packageName ?? "@paysponge/sdk",
263
+ packageVersion: meta.version ?? "0.1.0",
264
+ apiHeaderVersion: SDK_VERSION,
265
+ walletSkill: {
266
+ name: WALLET_SKILL_NAME,
267
+ version: WALLET_SKILL_VERSION,
268
+ url: WALLET_SKILL_URL,
269
+ },
270
+ cliSkill: {
271
+ name: CLI_SKILL_NAME,
272
+ version: CLI_SKILL_VERSION,
273
+ url: CLI_SKILL_URL,
274
+ },
275
+ };
276
+ const npm = opts.check
277
+ ? {
278
+ sdk: await getNpmLatestVersion("@paysponge/sdk"),
279
+ spongewallet: await getNpmLatestVersion("spongewallet"),
280
+ }
281
+ : undefined;
282
+ const server = opts.check ? await getServerVersionInfo(opts.baseUrl) : undefined;
283
+ const payload = { ...current, server, npm };
284
+ if (opts.json) {
285
+ console.log(JSON.stringify(payload, null, 2));
286
+ return;
287
+ }
288
+ p.log.success(`${current.packageName} v${current.packageVersion}`);
289
+ p.log.info([
290
+ `Command: ${current.command}`,
291
+ `API header: Sponge-Version ${current.apiHeaderVersion}`,
292
+ `Wallet skill: ${current.walletSkill.name} v${current.walletSkill.version}`,
293
+ `CLI skill: ${current.cliSkill.name} v${current.cliSkill.version}`,
294
+ `Wallet URL: ${current.walletSkill.url}`,
295
+ `CLI URL: ${current.cliSkill.url}`,
296
+ ].join("\n"));
297
+ if (npm) {
298
+ const lines = Object.entries(npm).map(([name, latest]) => {
299
+ if (!latest)
300
+ return `${name}: unable to check`;
301
+ const local = name === "sdk"
302
+ ? current.apiHeaderVersion
303
+ : name === "spongewallet" && meta.packageName === "spongewallet"
304
+ ? current.packageVersion
305
+ : undefined;
306
+ const marker = local && compareSemver(latest, local) > 0 ? " update available" : "";
307
+ return `${name}: ${latest}${marker}`;
308
+ });
309
+ p.note(lines.join("\n"), "Published Versions");
310
+ }
311
+ if (server) {
312
+ p.note([
313
+ `status: ${server.status}`,
314
+ `latest SDK: ${server.latestSdkVersion}`,
315
+ `minimum SDK: ${server.minimumSdkVersion}`,
316
+ `wallet skill: ${server.walletSkillVersion}`,
317
+ `message: ${server.message}`,
318
+ ].join("\n"), "API Version Check");
319
+ }
320
+ p.log.step(skillRefreshPrompt());
227
321
  }
228
322
  async function continueClaimFlow(creds, opts) {
229
323
  p.intro("Pending agent claim found");
@@ -465,16 +559,19 @@ function applyHelpTheme(command, metadata) {
465
559
  const CHAIN_VALUES = [
466
560
  "ethereum",
467
561
  "base",
562
+ "arbitrum-one",
468
563
  "polygon",
469
564
  "sepolia",
470
565
  "base-sepolia",
566
+ "arbitrum-sepolia",
567
+ "monad-testnet",
471
568
  "polygon-amoy",
472
569
  "tempo-testnet",
473
570
  "tempo",
474
571
  "solana",
475
572
  "solana-devnet",
476
573
  ];
477
- const EVM_CHAIN_VALUES = ["ethereum", "base", "polygon", "sepolia", "base-sepolia", "polygon-amoy"];
574
+ const EVM_CHAIN_VALUES = ["ethereum", "base", "arbitrum-one", "polygon", "sepolia", "base-sepolia", "arbitrum-sepolia", "polygon-amoy"];
478
575
  const SOLANA_CHAIN_VALUES = ["solana", "solana-devnet"];
479
576
  const TEMPO_CHAIN_VALUES = ["tempo", "tempo-testnet"];
480
577
  const ONRAMP_CHAIN_VALUES = ["base", "solana", "polygon"];
@@ -781,6 +878,7 @@ function registerCuratedCommands(program, shared) {
781
878
  shared(payCmd.command("fetch").description("Fetch with automatic paid API handling"))
782
879
  .requiredOption("--url <url>", "target URL")
783
880
  .addOption(new Option("--chain <chain>", "preferred spend chain").choices(PAY_CHAIN_VALUES))
881
+ .addOption(new Option("--protocol <protocol>", "explicit protocol override").choices(["x402", "mpp"]))
784
882
  .addOption(new Option("--method <method>", "HTTP method").choices(["GET", "POST", "PUT", "DELETE", "PATCH"]).default("GET"))
785
883
  .option("--headers <json>", "headers as JSON", parseJsonObject)
786
884
  .option("--body <json>", "request body as JSON", parseJsonValue)
@@ -789,6 +887,7 @@ function registerCuratedCommands(program, shared) {
789
887
  const data = await wallet.paidFetch({
790
888
  url: String(opts.url),
791
889
  chain: opts.chain,
890
+ protocol: opts.protocol,
792
891
  method: opts.method,
793
892
  headers: opts.headers,
794
893
  body: opts.body,
@@ -887,6 +986,14 @@ function registerCuratedCommands(program, shared) {
887
986
  metadata: opts.metadata,
888
987
  });
889
988
  });
989
+ shared(cardCmd.command("add").description("Open the dashboard flow for adding a user-owned card"))
990
+ .option("--app-url <url>", "custom wallet app URL", DEFAULT_APP_URL)
991
+ .option("--agent-id <id>", "agent ID to preselect in the dashboard")
992
+ .addOption(new Option("--flow <flow>", "card setup flow to open").choices(["choose", "basis-theory", "link"]).default("choose"))
993
+ .option("--no-browser", "print the URL without opening a browser")
994
+ .action(async (opts) => {
995
+ await handleCardAdd(opts);
996
+ });
890
997
  shared(cardCmd.command("virtual").description("Issue a per-transaction virtual card"))
891
998
  .requiredOption("--amount <amount>", "transaction amount")
892
999
  .option("--currency <code>", "ISO currency code")
@@ -894,6 +1001,8 @@ function registerCuratedCommands(program, shared) {
894
1001
  .requiredOption("--merchant-url <url>", "merchant URL")
895
1002
  .option("--merchant-country-code <code>", "merchant country code")
896
1003
  .option("--description <text>", "purchase description")
1004
+ .option("--products <json>", "products array as JSON", parseJsonValue)
1005
+ .option("--shipping-address <json>", "shipping address as JSON", parseJsonObject)
897
1006
  .option("--enrollment-id <id>", "specific enrollment ID")
898
1007
  .action(async (opts) => {
899
1008
  await executeToolCommand(opts, "issue_virtual_card", {
@@ -903,6 +1012,8 @@ function registerCuratedCommands(program, shared) {
903
1012
  merchant_url: opts.merchantUrl,
904
1013
  merchant_country_code: opts.merchantCountryCode,
905
1014
  description: opts.description,
1015
+ products: opts.products,
1016
+ shipping_address: opts.shippingAddress,
906
1017
  enrollment_id: opts.enrollmentId,
907
1018
  });
908
1019
  });
@@ -923,6 +1034,254 @@ function registerCuratedCommands(program, shared) {
923
1034
  merchant_url: opts.merchantUrl,
924
1035
  });
925
1036
  });
1037
+ shared(cardCmd.command("vaulted").description("Fetch a Basis Theory vaulted card session"))
1038
+ .option("--payment-method-id <id>", "specific Basis Theory payment method ID")
1039
+ .option("--amount <amount>", "transaction amount for spending-limit checks")
1040
+ .option("--currency <code>", "ISO currency code")
1041
+ .option("--merchant-name <name>", "merchant name")
1042
+ .option("--merchant-url <url>", "merchant URL")
1043
+ .action(async (opts) => {
1044
+ await executeToolCommand(opts, "get_card", {
1045
+ card_type: "basis_theory_vaulted",
1046
+ payment_method_id: opts.paymentMethodId,
1047
+ amount: opts.amount,
1048
+ currency: opts.currency,
1049
+ merchant_name: opts.merchantName,
1050
+ merchant_url: opts.merchantUrl,
1051
+ });
1052
+ });
1053
+ shared(cardCmd.command("usage").description("Report the outcome of a card purchase attempt"))
1054
+ .requiredOption("--payment-method-id <id>", "payment method ID used for the purchase")
1055
+ .addOption(new Option("--status <status>", "purchase outcome").choices(["success", "failed", "cancelled"]).makeOptionMandatory())
1056
+ .option("--merchant-name <name>", "merchant name")
1057
+ .option("--merchant-domain <domain>", "merchant domain")
1058
+ .option("--amount <amount>", "amount charged or attempted")
1059
+ .option("--currency <code>", "currency code")
1060
+ .option("--failure-reason <reason>", "failure reason when status is failed")
1061
+ .action(async (opts) => {
1062
+ await executeToolCommand(opts, "report_card_usage", {
1063
+ payment_method_id: opts.paymentMethodId,
1064
+ merchant_name: opts.merchantName,
1065
+ merchant_domain: opts.merchantDomain,
1066
+ amount: opts.amount,
1067
+ currency: opts.currency,
1068
+ status: opts.status,
1069
+ failure_reason: opts.failureReason,
1070
+ });
1071
+ });
1072
+ const linkCmd = cardCmd.command("link").description("Link payment method workflows");
1073
+ shared(linkCmd.command("start").description("Start Link login for payment-method connection"))
1074
+ .option("--client-name <name>", "optional Link connection label")
1075
+ .action(async (opts) => {
1076
+ await executeToolCommand(opts, "add_link_payment_method", {
1077
+ client_name: opts.clientName,
1078
+ });
1079
+ });
1080
+ shared(linkCmd.command("save").description("Save a Link payment method after Link login"))
1081
+ .option("--link-payment-method-id <id>", "Link payment method ID; required if multiple methods are available")
1082
+ .option("--set-as-default", "make this the default Link payment method")
1083
+ .option("--no-set-as-default", "do not make this the default Link payment method")
1084
+ .option("--client-name <name>", "optional Link connection label")
1085
+ .requiredOption("--email <email>", "contact email")
1086
+ .requiredOption("--phone <phone>", "contact phone")
1087
+ .requiredOption("--shipping <json>", "shipping address JSON with name, line1, city, state, postalCode, country", parseJsonObject)
1088
+ .option("--billing <json>", "optional billing address JSON", parseJsonObject)
1089
+ .action(async (opts) => {
1090
+ await executeToolCommand(opts, "add_link_payment_method", {
1091
+ link_payment_method_id: opts.linkPaymentMethodId,
1092
+ set_as_default: opts.setAsDefault,
1093
+ client_name: opts.clientName,
1094
+ email: opts.email,
1095
+ phone: opts.phone,
1096
+ shipping: opts.shipping,
1097
+ billing: opts.billing,
1098
+ });
1099
+ });
1100
+ shared(linkCmd.command("credential").description("Generate one-time card credentials from a saved Link payment method"))
1101
+ .option("--link-payment-method-id <id>", "saved Link payment method ID")
1102
+ .option("--spend-request-id <id>", "existing spend request ID returned by approval_required")
1103
+ .option("--amount <amount>", "purchase amount")
1104
+ .option("--currency <code>", "ISO currency code")
1105
+ .option("--merchant-name <name>", "merchant name")
1106
+ .option("--merchant-url <url>", "merchant URL")
1107
+ .option("--context <text>", "optional context shown during Link approval")
1108
+ .action(async (opts) => {
1109
+ await executeToolCommand(opts, "create_link_payment_credential", {
1110
+ link_payment_method_id: opts.linkPaymentMethodId,
1111
+ spend_request_id: opts.spendRequestId,
1112
+ amount: opts.amount,
1113
+ currency: opts.currency,
1114
+ merchant_name: opts.merchantName,
1115
+ merchant_url: opts.merchantUrl,
1116
+ context: opts.context,
1117
+ });
1118
+ });
1119
+ shared(cardCmd.command("status").description("Show Sponge Card onboarding, card, and balance status"))
1120
+ .option("--refresh", "force-refresh issuer status before returning")
1121
+ .option("--no-refresh", "use cached issuer status when available")
1122
+ .action(async (opts) => {
1123
+ await executeToolCommand(opts, "get_sponge_card_status", {
1124
+ refresh: opts.refresh,
1125
+ });
1126
+ });
1127
+ shared(cardCmd.command("onboard").description("Start Sponge Card onboarding or internal KYC verification"))
1128
+ .option("--occupation <occupation>", "occupation or SOC code")
1129
+ .option("--redirect-uri <url>", "redirect URL after KYC completion")
1130
+ .option("--accept-all", "set all required Sponge Card consent acknowledgements to true")
1131
+ .option("--e-sign-consent", "accept E-Sign Consent")
1132
+ .option("--account-opening-privacy-notice", "accept Account Opening Privacy Notice; required for US KYC")
1133
+ .option("--sponge-card-terms", "accept Sponge Card terms and issuer privacy policy")
1134
+ .option("--information-certification", "certify KYC information is accurate")
1135
+ .option("--unauthorized-solicitation-acknowledgement", "acknowledge application is not unauthorized solicitation")
1136
+ .action(async (opts) => {
1137
+ await executeToolCommand(opts, "onboard_sponge_card", {
1138
+ occupation: opts.occupation,
1139
+ redirect_uri: opts.redirectUri,
1140
+ ...spongeCardConsentInput(opts),
1141
+ });
1142
+ });
1143
+ shared(cardCmd.command("terms").description("Accept Sponge Card terms for an existing application"))
1144
+ .option("--accept-all", "set all required Sponge Card consent acknowledgements to true")
1145
+ .option("--e-sign-consent", "accept E-Sign Consent")
1146
+ .option("--account-opening-privacy-notice", "accept Account Opening Privacy Notice; required for US KYC")
1147
+ .option("--sponge-card-terms", "accept Sponge Card terms and issuer privacy policy")
1148
+ .option("--information-certification", "certify KYC information is accurate")
1149
+ .option("--unauthorized-solicitation-acknowledgement", "acknowledge application is not unauthorized solicitation")
1150
+ .action(async (opts) => {
1151
+ await executeToolCommand(opts, "accept_sponge_card_terms", spongeCardConsentInput(opts));
1152
+ });
1153
+ shared(cardCmd.command("create").description("Create a Sponge Card after approval and consent"))
1154
+ .requiredOption("--billing-address <json>", "billing address JSON with line1, city, region, postal_code, country_code")
1155
+ .requiredOption("--email <email>", "contact email")
1156
+ .requiredOption("--phone <phone>", "contact phone")
1157
+ .option("--shipping-address <json>", "optional shipping address JSON", parseJsonObject)
1158
+ .action(async (opts) => {
1159
+ await executeToolCommand(opts, "create_sponge_card", {
1160
+ billing: parseJsonObject(String(opts.billingAddress)),
1161
+ email: opts.email,
1162
+ phone: opts.phone,
1163
+ shipping: opts.shippingAddress,
1164
+ });
1165
+ });
1166
+ shared(cardCmd.command("details").description("Fetch encrypted Sponge Card PAN/CVC and spending power"))
1167
+ .action(async (opts) => {
1168
+ await executeToolCommand(opts, "get_sponge_card_details", {});
1169
+ });
1170
+ shared(cardCmd.command("fund").description("Top up Sponge Card collateral with USDC from the wallet"))
1171
+ .usage("[amount] [options]")
1172
+ .argument("[amount]", "USDC amount")
1173
+ .option("--amount <amount>", "USDC amount")
1174
+ .addOption(new Option("--chain <chain>", "collateral chain").choices(CHAIN_VALUES))
1175
+ .action(async (amountArg, opts, command) => {
1176
+ await executeToolCommand(opts, "fund_sponge_card", {
1177
+ amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
1178
+ chain: opts.chain,
1179
+ });
1180
+ });
1181
+ shared(cardCmd.command("withdraw").description("Withdraw Sponge Card collateral back to the wallet"))
1182
+ .usage("[amount] [options]")
1183
+ .argument("[amount]", "USDC amount")
1184
+ .option("--amount <amount>", "USDC amount")
1185
+ .addOption(new Option("--chain <chain>", "collateral chain").choices(CHAIN_VALUES))
1186
+ .action(async (amountArg, opts, command) => {
1187
+ await executeToolCommand(opts, "withdraw_sponge_card", {
1188
+ amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
1189
+ chain: opts.chain,
1190
+ });
1191
+ });
1192
+ const bankCmd = program.command("bank").description("Bank accounts and USD transfers");
1193
+ shared(bankCmd.command("onboard").description("Start or resume banking KYC onboarding"))
1194
+ .option("--wallet-id <id>", "wallet ID to associate with onboarding")
1195
+ .option("--redirect-uri <url>", "redirect URL after KYC completion")
1196
+ .addOption(new Option("--customer-type <type>", "KYC customer type").choices(["individual", "business"]))
1197
+ .option("--signed-agreement-id <id>", "Bridge signed agreement ID from the terms redirect")
1198
+ .action(async (opts) => {
1199
+ await executeToolCommand(opts, "bank_onboard", {
1200
+ wallet_id: opts.walletId,
1201
+ redirect_uri: opts.redirectUri,
1202
+ customer_type: opts.customerType,
1203
+ signed_agreement_id: opts.signedAgreementId,
1204
+ });
1205
+ });
1206
+ shared(bankCmd.command("status").description("Show banking KYC and capability status"))
1207
+ .action(async (opts) => {
1208
+ await executeToolCommand(opts, "bank_status", {});
1209
+ });
1210
+ const bankVirtualCmd = bankCmd.command("virtual-account").description("Virtual bank accounts for USD deposits");
1211
+ shared(bankVirtualCmd.command("create").description("Create or retrieve a virtual bank account for a wallet"))
1212
+ .usage("[walletId] [options]")
1213
+ .argument("[walletId]", "wallet ID")
1214
+ .option("--wallet-id <id>", "wallet ID")
1215
+ .action(async (walletIdArg, opts, command) => {
1216
+ await executeToolCommand(opts, "bank_create_virtual_account", {
1217
+ wallet_id: requiredInput(command, opts, walletIdArg, "walletId", "--wallet-id"),
1218
+ });
1219
+ });
1220
+ shared(bankVirtualCmd.command("get").description("Get virtual bank account deposit instructions"))
1221
+ .usage("[walletId] [options]")
1222
+ .argument("[walletId]", "wallet ID; omit to list all")
1223
+ .option("--wallet-id <id>", "wallet ID")
1224
+ .action(async (walletIdArg, opts) => {
1225
+ await executeToolCommand(opts, "bank_get_virtual_account", {
1226
+ wallet_id: walletIdArg ?? opts.walletId,
1227
+ });
1228
+ });
1229
+ const bankExternalCmd = bankCmd.command("external-accounts").description("Linked external bank accounts");
1230
+ shared(bankExternalCmd.command("list").description("List linked external bank accounts"))
1231
+ .action(async (opts) => {
1232
+ await executeToolCommand(opts, "bank_list_external_accounts", {});
1233
+ });
1234
+ shared(bankExternalCmd.command("add").description("Link an external US bank account"))
1235
+ .requiredOption("--bank-name <name>", "bank name")
1236
+ .requiredOption("--account-owner-name <name>", "account holder full name")
1237
+ .requiredOption("--routing-number <number>", "9-digit ABA routing number")
1238
+ .requiredOption("--account-number <number>", "bank account number")
1239
+ .addOption(new Option("--checking-or-savings <type>", "account type").choices(["checking", "savings"]).makeOptionMandatory())
1240
+ .requiredOption("--street-line-1 <line>", "account holder street address line 1")
1241
+ .option("--street-line-2 <line>", "account holder street address line 2")
1242
+ .requiredOption("--city <city>", "account holder city")
1243
+ .requiredOption("--state <state>", "account holder US state")
1244
+ .requiredOption("--postal-code <code>", "account holder ZIP code")
1245
+ .action(async (opts) => {
1246
+ await executeToolCommand(opts, "bank_add_external_account", {
1247
+ bank_name: opts.bankName,
1248
+ account_owner_name: opts.accountOwnerName,
1249
+ routing_number: opts.routingNumber,
1250
+ account_number: opts.accountNumber,
1251
+ checking_or_savings: opts.checkingOrSavings,
1252
+ street_line_1: opts.streetLine1,
1253
+ street_line_2: opts.streetLine2,
1254
+ city: opts.city,
1255
+ state: opts.state,
1256
+ postal_code: opts.postalCode,
1257
+ });
1258
+ });
1259
+ shared(bankCmd.command("send").description("Send USD to a linked bank account"))
1260
+ .usage("[walletId] [externalAccountId] [amount] [options]")
1261
+ .argument("[walletId]", "wallet ID to send USDC from")
1262
+ .argument("[externalAccountId]", "external bank account ID")
1263
+ .argument("[amount]", "USD amount")
1264
+ .option("--wallet-id <id>", "wallet ID to send USDC from")
1265
+ .option("--external-account-id <id>", "external bank account ID")
1266
+ .option("--amount <amount>", "USD amount")
1267
+ .addOption(new Option("--payment-rail <rail>", "payout rail").choices(["ach", "wire"]))
1268
+ .action(async (walletIdArg, externalAccountIdArg, amountArg, opts, command) => {
1269
+ await executeToolCommand(opts, "bank_send", {
1270
+ wallet_id: requiredInput(command, opts, walletIdArg, "walletId", "--wallet-id"),
1271
+ external_account_id: requiredInput(command, opts, externalAccountIdArg, "externalAccountId", "--external-account-id"),
1272
+ amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
1273
+ payment_rail: opts.paymentRail,
1274
+ });
1275
+ });
1276
+ shared(bankCmd.command("transfers").description("List bank transfer history"))
1277
+ .usage("[transferId] [options]")
1278
+ .argument("[transferId]", "transfer ID")
1279
+ .option("--transfer-id <id>", "transfer ID")
1280
+ .action(async (transferIdArg, opts) => {
1281
+ await executeToolCommand(opts, "bank_list_transfers", {
1282
+ transfer_id: transferIdArg ?? opts.transferId,
1283
+ });
1284
+ });
926
1285
  const planCmd = program.command("plan").description("Multi-step plan approval flows");
927
1286
  shared(planCmd.command("submit").description("Submit a multi-step plan"))
928
1287
  .requiredOption("--title <title>", "plan title")
@@ -1233,6 +1592,21 @@ function registerCuratedCommands(program, shared) {
1233
1592
  offset: offsetArg !== undefined ? parseInt(offsetArg, 10) : opts.offset,
1234
1593
  });
1235
1594
  });
1595
+ shared(hyperliquidCmd.command("chart").description("Show a Unicode Hyperliquid price chart"))
1596
+ .argument("[symbol]", "market symbol")
1597
+ .option("--symbol <symbol>", "market symbol")
1598
+ .option("--interval <interval>", "candle interval", "15m")
1599
+ .option("--chart-style <style>", "chart style", "sparkline")
1600
+ .addHelpText("after", "\nExamples:\n spongewallet market hyperliquid chart BTC/USDC:USDC\n spongewallet market hyperliquid chart ETH --interval 1h\n")
1601
+ .action(async (symbolArg, opts, command) => {
1602
+ await executeHyperliquidAction(opts, {
1603
+ action: "chart",
1604
+ symbol: requiredInput(command, opts, symbolArg, "symbol", "--symbol"),
1605
+ interval: opts.interval,
1606
+ chart_style: opts.chartStyle,
1607
+ trace_tool_call: false,
1608
+ });
1609
+ });
1236
1610
  shared(hyperliquidCmd.command("fills").description("List recent Hyperliquid fills"))
1237
1611
  .usage("[limit] [offset] [options]")
1238
1612
  .argument("[limit]", "result limit")
@@ -1303,6 +1677,8 @@ function registerCuratedCommands(program, shared) {
1303
1677
  .option("--price <price>", "limit price")
1304
1678
  .option("--leverage <n>", "leverage", parseFloat)
1305
1679
  .option("--order-id <id>", "order ID")
1680
+ .option("--interval <interval>", "candle interval")
1681
+ .option("--chart-style <style>", "chart style")
1306
1682
  .option("--limit <n>", "result limit", parseInt)
1307
1683
  .option("--offset <n>", "result offset", parseInt)
1308
1684
  .option("--json <json>", "additional args as JSON", parseJsonObject)
@@ -1317,6 +1693,8 @@ function registerCuratedCommands(program, shared) {
1317
1693
  price: opts.price,
1318
1694
  leverage: opts.leverage,
1319
1695
  order_id: opts.orderId,
1696
+ interval: opts.interval,
1697
+ chart_style: opts.chartStyle,
1320
1698
  limit: opts.limit,
1321
1699
  offset: opts.offset,
1322
1700
  });
@@ -1371,6 +1749,110 @@ function parseJsonObject(value) {
1371
1749
  }
1372
1750
  return parsed;
1373
1751
  }
1752
+ function spongeCardConsentInput(opts) {
1753
+ const acceptAll = Boolean(opts.acceptAll);
1754
+ return {
1755
+ e_sign_consent: acceptAll || Boolean(opts.eSignConsent),
1756
+ account_opening_privacy_notice: acceptAll || Boolean(opts.accountOpeningPrivacyNotice),
1757
+ sponge_card_terms: acceptAll || Boolean(opts.spongeCardTerms),
1758
+ information_certification: acceptAll || Boolean(opts.informationCertification),
1759
+ unauthorized_solicitation_acknowledgement: acceptAll || Boolean(opts.unauthorizedSolicitationAcknowledgement),
1760
+ };
1761
+ }
1762
+ function skillRefreshPrompt() {
1763
+ return `If this agent has an older Sponge skill installed, redownload ${WALLET_SKILL_URL} so it knows ${WALLET_SKILL_NAME} v${WALLET_SKILL_VERSION}.`;
1764
+ }
1765
+ function buildCardSetupUrl(args) {
1766
+ const url = new URL("/dashboard", args.appUrl ?? DEFAULT_APP_URL);
1767
+ url.searchParams.set("tab", "cards");
1768
+ url.searchParams.set("addCard", "1");
1769
+ if (args.agentId)
1770
+ url.searchParams.set("agentId", args.agentId);
1771
+ if (args.flow && args.flow !== "choose")
1772
+ url.searchParams.set("cardFlow", args.flow);
1773
+ return url.toString();
1774
+ }
1775
+ async function handleCardAdd(opts) {
1776
+ const credentials = loadCredentials(opts.credentialsPath);
1777
+ const agentId = typeof opts.agentId === "string" && opts.agentId.length > 0
1778
+ ? opts.agentId
1779
+ : credentials?.agentId;
1780
+ const flow = typeof opts.flow === "string" ? opts.flow : "choose";
1781
+ const url = buildCardSetupUrl({
1782
+ appUrl: typeof opts.appUrl === "string" ? opts.appUrl : DEFAULT_APP_URL,
1783
+ agentId,
1784
+ flow,
1785
+ });
1786
+ p.log.info([
1787
+ "Open this dashboard flow to add a user-owned card:",
1788
+ url,
1789
+ "",
1790
+ flow === "link"
1791
+ ? "This opens the Link card connection flow."
1792
+ : flow === "basis-theory"
1793
+ ? "This opens the manual card flow backed by Basis Theory Elements tokenization."
1794
+ : "Choose manual Basis Theory tokenization or Link in the dashboard.",
1795
+ ].join("\n"));
1796
+ if (opts.browser === false)
1797
+ return;
1798
+ try {
1799
+ const open = await import("open");
1800
+ await open.default(url);
1801
+ p.log.step("Opened browser for card setup.");
1802
+ }
1803
+ catch {
1804
+ p.log.step("Could not open browser automatically. Open the URL manually.");
1805
+ }
1806
+ }
1807
+ async function getNpmLatestVersion(packageName) {
1808
+ try {
1809
+ const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`, {
1810
+ headers: { Accept: "application/json" },
1811
+ });
1812
+ if (!response.ok)
1813
+ return null;
1814
+ const data = await response.json();
1815
+ return isRecord(data) && typeof data.version === "string" ? data.version : null;
1816
+ }
1817
+ catch {
1818
+ return null;
1819
+ }
1820
+ }
1821
+ async function getServerVersionInfo(baseUrl) {
1822
+ try {
1823
+ const url = new URL("/api/version", baseUrl ?? DEFAULT_BASE_URL);
1824
+ const response = await fetch(url.toString(), {
1825
+ headers: {
1826
+ Accept: "application/json",
1827
+ "Sponge-Version": SDK_VERSION,
1828
+ },
1829
+ });
1830
+ if (!response.ok)
1831
+ return null;
1832
+ const data = await response.json();
1833
+ return isRecord(data) ? data : null;
1834
+ }
1835
+ catch {
1836
+ return null;
1837
+ }
1838
+ }
1839
+ function compareSemver(a, b) {
1840
+ const parse = (value) => value
1841
+ .split(/[.-]/)
1842
+ .slice(0, 3)
1843
+ .map(part => {
1844
+ const parsed = Number.parseInt(part, 10);
1845
+ return Number.isFinite(parsed) ? parsed : 0;
1846
+ });
1847
+ const left = parse(a);
1848
+ const right = parse(b);
1849
+ for (let index = 0; index < 3; index += 1) {
1850
+ const diff = (left[index] ?? 0) - (right[index] ?? 0);
1851
+ if (diff !== 0)
1852
+ return diff > 0 ? 1 : -1;
1853
+ }
1854
+ return 0;
1855
+ }
1374
1856
  function registerToolCommands(program, shared) {
1375
1857
  for (const tool of TOOL_DEFINITIONS) {
1376
1858
  const cmdName = tool.name.replace(/_/g, "-");
@@ -1767,7 +2249,7 @@ function renderTable(title, columns, rows) {
1767
2249
  function renderTxOutput(title, data) {
1768
2250
  if (!isRecord(data))
1769
2251
  return false;
1770
- const hash = getValueByKey(data, ["transactionHash", "txHash", "signature"]);
2252
+ const hash = getValueByKey(data, ["transactionHash", "txHash", "tx_hash", "signature"]);
1771
2253
  const inputAmount = getValueByKey(data, ["inputToken.amount", "input_token.amount"]);
1772
2254
  const inputSymbol = getValueByKey(data, ["inputToken.symbol", "input_token.symbol"]);
1773
2255
  const outputAmount = getValueByKey(data, ["outputToken.amount", "output_token.amount"]);