@t2000/cli 5.24.3 → 5.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32124,7 +32124,13 @@ function withoutMcpEntry(config) {
32124
32124
 
32125
32125
  // src/commands/status.ts
32126
32126
  var require2 = createRequire(import.meta.url);
32127
- var { version: CLI_VERSION } = require2("../package.json");
32127
+ var { version: CLI_VERSION } = (() => {
32128
+ try {
32129
+ return require2("../package.json");
32130
+ } catch {
32131
+ return require2("../../package.json");
32132
+ }
32133
+ })();
32128
32134
  var GATEWAY_URL = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
32129
32135
  var GATEWAY_TIMEOUT_MS = 3e3;
32130
32136
  async function checkGateway() {
@@ -33109,7 +33115,7 @@ function registerMcpStart(parent) {
33109
33115
  parent.command("start", { isDefault: true }).description("Start MCP server (stdio transport \u2014 for AI client integration)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
33110
33116
  let mod3;
33111
33117
  try {
33112
- mod3 = await import("./dist-UCB5RASG.js");
33118
+ mod3 = await import("./dist-BJOELEAN.js");
33113
33119
  } catch {
33114
33120
  console.error("MCP server not installed. Run:\n npm install -g @t2000/mcp");
33115
33121
  process.exit(1);
@@ -33449,7 +33455,237 @@ For MCP-aware clients (Claude Desktop, Cursor, Windsurf), prefer
33449
33455
  }
33450
33456
 
33451
33457
  // src/commands/agent/index.ts
33458
+ import { createHash as createHash2 } from "crypto";
33459
+
33460
+ // src/commands/agent/services.ts
33452
33461
  import { createHash } from "crypto";
33462
+ import { readFileSync as readFileSync3 } from "fs";
33463
+ var SLUG_RE = /^[a-z0-9][a-z0-9-]{1,39}$/;
33464
+ async function fetchJson(url, init) {
33465
+ const res = await fetch(url, {
33466
+ method: init?.method ?? "GET",
33467
+ headers: init?.body ? { "Content-Type": "application/json" } : void 0,
33468
+ body: init?.body ? JSON.stringify(init.body) : void 0
33469
+ });
33470
+ const json = await res.json().catch(() => ({}));
33471
+ if (!res.ok) {
33472
+ const err = json.error;
33473
+ const msg = typeof err === "string" ? err : err?.message ?? `HTTP ${res.status}`;
33474
+ throw new Error(msg);
33475
+ }
33476
+ return json;
33477
+ }
33478
+ function canonicalServicesJson(services) {
33479
+ return JSON.stringify(
33480
+ services.map(
33481
+ (s) => Object.fromEntries(
33482
+ Object.entries(s).sort(([a], [b]) => a.localeCompare(b))
33483
+ )
33484
+ )
33485
+ );
33486
+ }
33487
+ async function getCatalog(base, address) {
33488
+ const res = await fetchJson(
33489
+ `${base}/agent/services?address=${encodeURIComponent(address)}`
33490
+ );
33491
+ return Array.isArray(res.services) ? res.services : [];
33492
+ }
33493
+ async function putCatalog(opts) {
33494
+ const agent = await withAgent({ keyPath: opts.keyPath });
33495
+ const address = agent.address();
33496
+ const challenge = await fetchJson(`${opts.base}/agent/challenge`, {
33497
+ method: "POST",
33498
+ body: { address }
33499
+ });
33500
+ const nonce = challenge.nonce;
33501
+ if (!nonce) {
33502
+ throw new Error("Failed to get a challenge nonce.");
33503
+ }
33504
+ const digest = createHash("sha256").update(canonicalServicesJson(opts.services)).digest("hex");
33505
+ const message = new TextEncoder().encode(
33506
+ `t2000-agent-services:${nonce}:${digest}`
33507
+ );
33508
+ const { signature } = await agent.keypair.signPersonalMessage(message);
33509
+ const res = await fetchJson(`${opts.base}/agent/services`, {
33510
+ method: "POST",
33511
+ body: { address, nonce, signature, services: opts.services }
33512
+ });
33513
+ return { address, count: Number(res.count ?? opts.services.length) };
33514
+ }
33515
+ function entryFromFlags(opts) {
33516
+ const slug = String(opts.slug ?? "").trim().toLowerCase();
33517
+ if (!SLUG_RE.test(slug)) {
33518
+ throw new Error("--slug is required: [a-z0-9-], 2-40 chars.");
33519
+ }
33520
+ const out = { slug };
33521
+ if (opts.title !== void 0) {
33522
+ out.title = opts.title;
33523
+ }
33524
+ if (opts.description !== void 0) {
33525
+ out.description = opts.description;
33526
+ }
33527
+ if (opts.price !== void 0) {
33528
+ out.priceUsdc = opts.price;
33529
+ }
33530
+ if (opts.input !== void 0) {
33531
+ out.input = opts.input || null;
33532
+ }
33533
+ if (opts.endpoint !== void 0) {
33534
+ out.endpoint = opts.endpoint || null;
33535
+ }
33536
+ if (opts.method !== void 0) {
33537
+ out.method = opts.method.toUpperCase() === "GET" ? "GET" : "POST";
33538
+ }
33539
+ return out;
33540
+ }
33541
+ function registerAgentServices(agentGroup, defaults) {
33542
+ const group = agentGroup.command("services").description(
33543
+ "Manage this agent's service CATALOG (one agent, many services). Buy URLs: commerce/pay/<agent>/<slug>. [Store v2]"
33544
+ );
33545
+ group.command("list").argument("[address]", "Agent address (default: your wallet)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).description("List the catalog (public read).").action(async (addressArg, opts) => {
33546
+ try {
33547
+ const base = opts.api ?? defaults.apiBase;
33548
+ const address = addressArg ?? (await withAgent({ keyPath: opts.key })).address();
33549
+ const services = await getCatalog(base, address);
33550
+ if (isJsonMode()) {
33551
+ printJson({ address, services });
33552
+ return;
33553
+ }
33554
+ printBlank();
33555
+ if (services.length === 0) {
33556
+ printLine("No services in the catalog. Add one: t2 agent services add --slug <slug> --title \u2026 --description \u2026 --price \u2026");
33557
+ printBlank();
33558
+ return;
33559
+ }
33560
+ for (const s of services) {
33561
+ printKeyValue(
33562
+ s.slug,
33563
+ `$${s.priceUsdc} \u2014 ${s.title}${s.active === false ? " (inactive)" : ""}`
33564
+ );
33565
+ }
33566
+ printBlank();
33567
+ } catch (error) {
33568
+ handleError(error);
33569
+ }
33570
+ });
33571
+ group.command("add").description("Add one service to the catalog.").requiredOption("--slug <slug>", "Service slug ([a-z0-9-], 2-40 chars)").requiredOption("--title <title>", "Service title (\u226480 chars)").requiredOption("--description <text>", "Listing copy (\u2264480 chars)").requiredOption("--price <usdc>", "Price per call in USDC (e.g. 0.02)").option("--input <hint>", 'Input hint, e.g. "Provide: 1. address 2. chain"').option("--endpoint <url>", "Self-hosted https endpoint (omit for wrap/payment-only)").option("--method <method>", "Wrap delivery method: GET or POST").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).action(async (opts) => {
33572
+ try {
33573
+ const base = opts.api ?? defaults.apiBase;
33574
+ const agent = await withAgent({ keyPath: opts.key });
33575
+ const current = await getCatalog(base, agent.address());
33576
+ const entry = entryFromFlags(opts);
33577
+ if (current.some((s) => s.slug === entry.slug)) {
33578
+ throw new Error(
33579
+ `Slug "${entry.slug}" already exists \u2014 use: t2 agent services update --slug ${entry.slug}`
33580
+ );
33581
+ }
33582
+ const next = {
33583
+ title: "",
33584
+ description: "",
33585
+ priceUsdc: "0",
33586
+ active: true,
33587
+ ...entry
33588
+ };
33589
+ const { count } = await putCatalog({
33590
+ base,
33591
+ keyPath: opts.key,
33592
+ services: [...current, next]
33593
+ });
33594
+ if (isJsonMode()) {
33595
+ printJson({ added: entry.slug, count });
33596
+ return;
33597
+ }
33598
+ printBlank();
33599
+ printSuccess(`Service "${entry.slug}" added \u2014 catalog now ${count} service${count === 1 ? "" : "s"}.`);
33600
+ printLine(`Buy URL: https://x402.t2000.ai/commerce/pay/${agent.address()}/${entry.slug}`);
33601
+ printBlank();
33602
+ } catch (error) {
33603
+ handleError(error);
33604
+ }
33605
+ });
33606
+ group.command("update").description("Update one service (only the provided fields change).").requiredOption("--slug <slug>", "Service slug to update").option("--title <title>", "Service title (\u226480 chars)").option("--description <text>", "Listing copy (\u2264480 chars)").option("--price <usdc>", "Price per call in USDC").option("--input <hint>", 'Input hint ("" to clear)').option("--endpoint <url>", 'Self-hosted https endpoint ("" to clear \u2192 wrap mode)').option("--method <method>", "Wrap delivery method: GET or POST").option("--active <bool>", "true | false \u2014 per-service kill switch").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).action(async (opts) => {
33607
+ try {
33608
+ const base = opts.api ?? defaults.apiBase;
33609
+ const agent = await withAgent({ keyPath: opts.key });
33610
+ const current = await getCatalog(base, agent.address());
33611
+ const entry = entryFromFlags(opts);
33612
+ const idx = current.findIndex((s) => s.slug === entry.slug);
33613
+ if (idx === -1) {
33614
+ throw new Error(`No service "${entry.slug}" in the catalog.`);
33615
+ }
33616
+ const merged = { ...current[idx], ...entry };
33617
+ if (opts.active !== void 0) {
33618
+ merged.active = String(opts.active).toLowerCase() !== "false";
33619
+ }
33620
+ const services = [...current];
33621
+ services[idx] = merged;
33622
+ const { count } = await putCatalog({ base, keyPath: opts.key, services });
33623
+ if (isJsonMode()) {
33624
+ printJson({ updated: entry.slug, count });
33625
+ return;
33626
+ }
33627
+ printBlank();
33628
+ printSuccess(`Service "${entry.slug}" updated.`);
33629
+ printBlank();
33630
+ } catch (error) {
33631
+ handleError(error);
33632
+ }
33633
+ });
33634
+ group.command("remove").description("Remove one service from the catalog.").requiredOption("--slug <slug>", "Service slug to remove").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).action(async (opts) => {
33635
+ try {
33636
+ const base = opts.api ?? defaults.apiBase;
33637
+ const agent = await withAgent({ keyPath: opts.key });
33638
+ const slug = String(opts.slug ?? "").trim().toLowerCase();
33639
+ const current = await getCatalog(base, agent.address());
33640
+ const services = current.filter((s) => s.slug !== slug);
33641
+ if (services.length === current.length) {
33642
+ throw new Error(`No service "${slug}" in the catalog.`);
33643
+ }
33644
+ const { count } = await putCatalog({ base, keyPath: opts.key, services });
33645
+ if (isJsonMode()) {
33646
+ printJson({ removed: slug, count });
33647
+ return;
33648
+ }
33649
+ printBlank();
33650
+ printSuccess(`Service "${slug}" removed \u2014 catalog now ${count} service${count === 1 ? "" : "s"}.`);
33651
+ printBlank();
33652
+ } catch (error) {
33653
+ handleError(error);
33654
+ }
33655
+ });
33656
+ group.command("sync").description(
33657
+ "Declarative catalog sync \u2014 the manifest file IS the catalog (adds/updates/removes to match). The catalog-scale path."
33658
+ ).argument("<file>", "Path to a JSON manifest: [{ slug, title, description, priceUsdc, input?, endpoint?, method?, active? }]").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).action(async (file, opts) => {
33659
+ try {
33660
+ const base = opts.api ?? defaults.apiBase;
33661
+ const raw = JSON.parse(readFileSync3(file, "utf8"));
33662
+ const list = Array.isArray(raw) ? raw : raw?.services ?? null;
33663
+ if (!Array.isArray(list)) {
33664
+ throw new Error(
33665
+ 'Manifest must be a JSON array of services (or { "services": [...] }).'
33666
+ );
33667
+ }
33668
+ const services = list.map((s) => {
33669
+ const entry = s;
33670
+ return { ...entry, active: entry.active !== false };
33671
+ });
33672
+ const agent = await withAgent({ keyPath: opts.key });
33673
+ const before = await getCatalog(base, agent.address());
33674
+ const { count } = await putCatalog({ base, keyPath: opts.key, services });
33675
+ if (isJsonMode()) {
33676
+ printJson({ synced: count, before: before.length });
33677
+ return;
33678
+ }
33679
+ printBlank();
33680
+ printSuccess(`Catalog synced \u2014 ${before.length} \u2192 ${count} services.`);
33681
+ printBlank();
33682
+ } catch (error) {
33683
+ handleError(error);
33684
+ }
33685
+ });
33686
+ }
33687
+
33688
+ // src/commands/agent/index.ts
33453
33689
  var DEFAULT_API_BASE3 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
33454
33690
  var DEFAULT_GATEWAY = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
33455
33691
  var DEFAULT_RAIL = process.env.T2000_RAIL_URL ?? "https://x402.t2000.ai";
@@ -33490,19 +33726,19 @@ async function fundCredit(agent, base, amountStr, assetOpt) {
33490
33726
  throw new Error(`amount must be a positive number (got "${amountStr}").`);
33491
33727
  }
33492
33728
  const asset = normalizeTopupAsset(assetOpt);
33493
- const cfg = await fetchJson(`${base}/agent/topup`, { method: "GET" });
33729
+ const cfg = await fetchJson2(`${base}/agent/topup`, { method: "GET" });
33494
33730
  const treasury = cfg.treasury;
33495
33731
  if (!treasury) {
33496
33732
  throw new Error("Could not resolve the t2000 treasury address.");
33497
33733
  }
33498
33734
  const sent = await agent.send({ to: treasury, amount, asset });
33499
- const topup = await fetchJson(`${base}/agent/topup`, {
33735
+ const topup = await fetchJson2(`${base}/agent/topup`, {
33500
33736
  method: "POST",
33501
33737
  body: { address: agent.address(), digest: sent.tx }
33502
33738
  });
33503
33739
  return { amount, asset, balanceUsd: topup.balanceUsd };
33504
33740
  }
33505
- async function fetchJson(url, init) {
33741
+ async function fetchJson2(url, init) {
33506
33742
  const res = await fetch(url, {
33507
33743
  method: init.method,
33508
33744
  headers: init.body ? { "Content-Type": "application/json" } : void 0,
@@ -33524,9 +33760,14 @@ Subcommands:
33524
33760
  $ t2 agent onboard --fund 5 Fund 5 USDC \u2192 mint an API key (ready to call)
33525
33761
  $ t2 agent onboard --fund 5 --asset USDsui
33526
33762
  $ t2 agent onboard Already funded \u2192 just mint a key
33763
+ $ t2 agent services add --slug sui-price --title "SUI spot" --description "\u2026" --price 0.02
33764
+ $ t2 agent services sync ./services.json Manifest IS the catalog (catalog-scale sellers)
33527
33765
  `
33528
33766
  );
33529
- group.command("onboard").description("Fund credit (gasless USDC/USDsui) + mint an API key for this wallet.").option("--fund <amount>", "Stablecoin amount to deposit as credit (omit if already funded)").option("--asset <asset>", "USDC (default) or USDsui", "USDC").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE3})`).action(
33767
+ registerAgentServices(group, { apiBase: DEFAULT_API_BASE3 });
33768
+ group.command("onboard").description(
33769
+ "Buy-side setup: fund credit (gasless USDC/USDsui) + mint a Private API key. Registering an Agent ID is free and separate \u2014 `t2 init` / `t2 agent register`."
33770
+ ).option("--fund <amount>", "Stablecoin amount to deposit as credit (omit if already funded)").option("--asset <asset>", "USDC (default) or USDsui", "USDC").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE3})`).action(
33530
33771
  async (opts) => {
33531
33772
  try {
33532
33773
  const base = opts.api ?? DEFAULT_API_BASE3;
@@ -33540,7 +33781,7 @@ Subcommands:
33540
33781
  );
33541
33782
  }
33542
33783
  }
33543
- const challenge = await fetchJson(`${base}/agent/challenge`, {
33784
+ const challenge = await fetchJson2(`${base}/agent/challenge`, {
33544
33785
  method: "POST",
33545
33786
  body: { address }
33546
33787
  });
@@ -33550,7 +33791,7 @@ Subcommands:
33550
33791
  }
33551
33792
  const message = new TextEncoder().encode(`t2000-agent-keys:${nonce}`);
33552
33793
  const { signature } = await agent.keypair.signPersonalMessage(message);
33553
- const minted = await fetchJson(`${base}/agent/keys`, {
33794
+ const minted = await fetchJson2(`${base}/agent/keys`, {
33554
33795
  method: "POST",
33555
33796
  body: { address, nonce, signature }
33556
33797
  });
@@ -33720,7 +33961,7 @@ Subcommands:
33720
33961
  const base = opts.api ?? DEFAULT_API_BASE3;
33721
33962
  const agent = await withAgent({ keyPath: opts.key });
33722
33963
  const address = agent.address();
33723
- const challenge = await fetchJson(`${base}/agent/challenge`, {
33964
+ const challenge = await fetchJson2(`${base}/agent/challenge`, {
33724
33965
  method: "POST",
33725
33966
  body: { address }
33726
33967
  });
@@ -33730,7 +33971,7 @@ Subcommands:
33730
33971
  }
33731
33972
  const message = new TextEncoder().encode(`t2000-agent-profile:${nonce}`);
33732
33973
  const { signature } = await agent.keypair.signPersonalMessage(message);
33733
- await fetchJson(`${base}/agent/profile`, {
33974
+ await fetchJson2(`${base}/agent/profile`, {
33734
33975
  method: "POST",
33735
33976
  body: {
33736
33977
  address,
@@ -33837,31 +34078,37 @@ Subcommands:
33837
34078
  ).option("--method <method>", "Upstream method: GET or POST (default POST)").option("--price <usdc>", "Price per call in USDC (e.g. 0.02)").option(
33838
34079
  "--category <category>",
33839
34080
  `Storefront category: ${AGENT_CATEGORIES.join(" | ")}`
33840
- ).option("--remove", "Take down the deployed service").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE3})`).action(
34081
+ ).option("--remove", "Take down the deployed service").option(
34082
+ "--service <slug>",
34083
+ "Catalog service slug \u2014 wrap config for ONE SKU (Store v2; omit = the default service)"
34084
+ ).option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE3})`).action(
33841
34085
  async (opts) => {
33842
34086
  try {
33843
34087
  const base = opts.api ?? DEFAULT_API_BASE3;
33844
34088
  const gateway = opts.gateway ?? DEFAULT_GATEWAY;
33845
34089
  const category = normalizeCategory(opts.category);
34090
+ const slug = opts.service?.trim().toLowerCase() || void 0;
33846
34091
  const agent = await withAgent({ keyPath: opts.key });
33847
34092
  const address = agent.address();
33848
34093
  if (opts.remove) {
33849
34094
  const ts2 = Date.now();
33850
- const msg2 = `t2000-deploy-remove:${ts2}`;
34095
+ const msg2 = `t2000-deploy-remove:${ts2}${slug ? `:${slug}` : ""}`;
33851
34096
  const { signature: signature2 } = await agent.keypair.signPersonalMessage(
33852
34097
  new TextEncoder().encode(msg2)
33853
34098
  );
33854
- await fetchJson(`${gateway}/deploy/config`, {
34099
+ await fetchJson2(`${gateway}/deploy/config`, {
33855
34100
  method: "DELETE",
33856
- body: { address, timestamp: ts2, signature: signature2 }
34101
+ body: { address, timestamp: ts2, signature: signature2, ...slug ? { slug } : {} }
33857
34102
  });
33858
- await runSponsoredTx({
33859
- keypair: agent.keypair,
33860
- actor: address,
33861
- prepareUrl: `${base}/agent/service/prepare`,
33862
- prepareBody: { address, mcpEndpoint: "" },
33863
- submitUrl: `${base}/agent/service/submit`
33864
- }).catch(() => void 0);
34103
+ if (!slug) {
34104
+ await runSponsoredTx({
34105
+ keypair: agent.keypair,
34106
+ actor: address,
34107
+ prepareUrl: `${base}/agent/service/prepare`,
34108
+ prepareBody: { address, mcpEndpoint: "" },
34109
+ submitUrl: `${base}/agent/service/submit`
34110
+ }).catch(() => void 0);
34111
+ }
33865
34112
  if (isJsonMode()) {
33866
34113
  printJson({ address, removed: true });
33867
34114
  return;
@@ -33881,12 +34128,14 @@ Subcommands:
33881
34128
  const method = (opts.method ?? "POST").toUpperCase() === "GET" ? "GET" : "POST";
33882
34129
  const headers = opts.header ?? {};
33883
34130
  const ts = Date.now();
33884
- const bodyHash = createHash("sha256").update(`${opts.upstream}|${method}|${JSON.stringify(headers)}`).digest("hex");
34131
+ const bodyHash = createHash2("sha256").update(
34132
+ `${opts.upstream}|${method}|${JSON.stringify(headers)}${slug ? `|${slug}` : ""}`
34133
+ ).digest("hex");
33885
34134
  const msg = `t2000-deploy:${ts}:${bodyHash}`;
33886
34135
  const { signature } = await agent.keypair.signPersonalMessage(
33887
34136
  new TextEncoder().encode(msg)
33888
34137
  );
33889
- await fetchJson(`${gateway}/deploy/config`, {
34138
+ await fetchJson2(`${gateway}/deploy/config`, {
33890
34139
  method: "POST",
33891
34140
  body: {
33892
34141
  address,
@@ -33894,9 +34143,25 @@ Subcommands:
33894
34143
  signature,
33895
34144
  upstreamUrl: opts.upstream,
33896
34145
  method,
33897
- headers
34146
+ headers,
34147
+ ...slug ? { slug } : {}
33898
34148
  }
33899
34149
  });
34150
+ if (slug) {
34151
+ if (isJsonMode()) {
34152
+ printJson({ address, slug, upstream: opts.upstream, price });
34153
+ return;
34154
+ }
34155
+ printBlank();
34156
+ printSuccess(`Wrap config stored for service "${slug}".`);
34157
+ printKeyValue("Wraps", opts.upstream);
34158
+ printKeyValue("Buy URL", `${DEFAULT_RAIL}/commerce/pay/${address}/${slug}`);
34159
+ printInfo(
34160
+ `List it in the catalog: t2 agent services add --slug ${slug} --title \u2026 --description \u2026 --price ${opts.price}`
34161
+ );
34162
+ printBlank();
34163
+ return;
34164
+ }
33900
34165
  const { digest } = await runSponsoredTx({
33901
34166
  keypair: agent.keypair,
33902
34167
  actor: address,
@@ -33935,6 +34200,9 @@ Subcommands:
33935
34200
  group.command("pay").argument("<seller>", "The seller agent's Sui address").description(
33936
34201
  "Pay a seller agent for a service (gateway-mediated, USDC). t2000 collects, keeps a small fee, and forwards the rest to the seller \u2014 with a receipt. [Agent Commerce]"
33937
34202
  ).option("--amount <usdc>", "Override the price (default: the seller's declared price)").option("--data <json>", "Service input forwarded to the seller's endpoint").option("--max-price <usdc>", "Max USDC to auto-approve (default 1.00, or --amount)").option(
34203
+ "--service <slug>",
34204
+ "Catalog service slug \u2014 buys ONE SKU of the seller's catalog (Store v2)"
34205
+ ).option(
33938
34206
  "--gateway <url>",
33939
34207
  `Gateway base URL (default ${DEFAULT_GATEWAY})`
33940
34208
  ).option("--force", "Override spending limits for this call (see `t2 limit`)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
@@ -33950,7 +34218,8 @@ Subcommands:
33950
34218
  const gateway = opts.gateway ?? DEFAULT_GATEWAY;
33951
34219
  const agent = await withAgent({ keyPath: opts.key });
33952
34220
  const resolvedSeller = seller.startsWith("0x") ? seller : (await agent.resolveRecipient(seller)).address;
33953
- const url = opts.amount ? `${gateway}/commerce/pay/${resolvedSeller}?amount=${encodeURIComponent(opts.amount)}` : `${gateway}/commerce/pay/${resolvedSeller}`;
34221
+ const slugPath = opts.service ? `/${opts.service.trim().toLowerCase()}` : "";
34222
+ const url = opts.amount ? `${gateway}/commerce/pay/${resolvedSeller}${slugPath}?amount=${encodeURIComponent(opts.amount)}` : `${gateway}/commerce/pay/${resolvedSeller}${slugPath}`;
33954
34223
  const result = await agent.pay({
33955
34224
  url,
33956
34225
  method: "POST",
@@ -34019,7 +34288,7 @@ Subcommands:
34019
34288
  const gateway = opts.gateway ?? DEFAULT_GATEWAY;
34020
34289
  const agent = await withAgent({ keyPath: opts.key });
34021
34290
  const address = agent.address();
34022
- const stats = await fetchJson(
34291
+ const stats = await fetchJson2(
34023
34292
  `${gateway}/commerce/stats/${address}`,
34024
34293
  { method: "GET" }
34025
34294
  );
@@ -34048,7 +34317,7 @@ Subcommands:
34048
34317
  const base = opts.api ?? DEFAULT_API_BASE3;
34049
34318
  const agent = await withAgent({ keyPath: opts.key });
34050
34319
  const address = agent.address();
34051
- const challenge = await fetchJson(`${base}/agent/challenge`, {
34320
+ const challenge = await fetchJson2(`${base}/agent/challenge`, {
34052
34321
  method: "POST",
34053
34322
  body: { address }
34054
34323
  });
@@ -34060,7 +34329,7 @@ Subcommands:
34060
34329
  const message = new TextEncoder().encode(`${action}:${nonce}:${label}`);
34061
34330
  const { signature } = await agent.keypair.signPersonalMessage(message);
34062
34331
  const path2 = opts.release ? "/agent/handle/release" : "/agent/handle";
34063
- const res = await fetchJson(`${base}${path2}`, {
34332
+ const res = await fetchJson2(`${base}${path2}`, {
34064
34333
  method: "POST",
34065
34334
  body: { address, label, nonce, signature }
34066
34335
  });