@t2000/cli 5.25.0 → 5.27.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-QE7NG5LG.js");
33118
+ mod3 = await import("./dist-JCY6PNWP.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,9 +33455,319 @@ For MCP-aware clients (Claude Desktop, Cursor, Windsurf), prefer
33449
33455
  }
33450
33456
 
33451
33457
  // src/commands/agent/index.ts
33458
+ import { createHash as createHash3 } from "crypto";
33459
+
33460
+ // src/commands/agent/review.ts
33452
33461
  import { createHash } from "crypto";
33462
+ var DEFAULT_GATEWAY = "https://x402.t2000.ai";
33463
+ async function fetchJson(url, init) {
33464
+ const res = await fetch(url, {
33465
+ method: init?.method ?? "GET",
33466
+ headers: init?.body ? { "Content-Type": "application/json" } : void 0,
33467
+ body: init?.body ? JSON.stringify(init.body) : void 0
33468
+ });
33469
+ const json = await res.json().catch(() => ({}));
33470
+ if (!res.ok) {
33471
+ const err = json.error;
33472
+ throw new Error(typeof err === "string" ? err : `HTTP ${res.status}`);
33473
+ }
33474
+ return json;
33475
+ }
33476
+ function reviewMessage(digest, stars, text, timestamp) {
33477
+ const hash = createHash("sha256").update(text, "utf8").digest("hex");
33478
+ return `t2000-review:${digest}:${stars}:${hash}:${timestamp}`;
33479
+ }
33480
+ function registerAgentReview(agent) {
33481
+ agent.command("review").description(
33482
+ "Review a purchase (1-5 stars + optional text). Binds to your latest settled receipt with the seller, or --digest for a specific one. Re-run to edit. [Store v2]"
33483
+ ).argument("<seller>", "Seller address (0x\u2026)").requiredOption("--stars <n>", "Rating 1-5").option("--text <text>", "Review text (\u2264400 chars)").option("--digest <digest>", "Collect digest of the specific purchase").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
33484
+ async (seller, opts) => {
33485
+ try {
33486
+ const stars = Number(opts.stars);
33487
+ if (!Number.isInteger(stars) || stars < 1 || stars > 5) {
33488
+ throw new Error("--stars must be an integer 1-5.");
33489
+ }
33490
+ const text = (opts.text ?? "").trim();
33491
+ if (text.length > 400) {
33492
+ throw new Error("--text must be \u2264 400 chars.");
33493
+ }
33494
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY;
33495
+ const agentW = await withAgent({ keyPath: opts.key });
33496
+ const buyer = agentW.address();
33497
+ let digest = (opts.digest ?? "").trim();
33498
+ if (!digest) {
33499
+ const res = await fetchJson(
33500
+ `${gateway}/commerce/review?buyer=${buyer}&seller=${encodeURIComponent(seller)}`
33501
+ );
33502
+ const reviewable = res.reviewable ?? [];
33503
+ if (reviewable.length === 0) {
33504
+ throw new Error(
33505
+ "No settled purchase from this wallet to that seller \u2014 buy first (`t2 agent pay`), then review."
33506
+ );
33507
+ }
33508
+ digest = reviewable[0].digest;
33509
+ }
33510
+ const timestamp = Date.now();
33511
+ const message = new TextEncoder().encode(
33512
+ reviewMessage(digest, stars, text, timestamp)
33513
+ );
33514
+ const { signature } = await agentW.keypair.signPersonalMessage(message);
33515
+ await fetchJson(`${gateway}/commerce/review`, {
33516
+ method: "POST",
33517
+ body: { digest, stars, text, timestamp, signature }
33518
+ });
33519
+ if (isJsonMode()) {
33520
+ printJson({ ok: true, digest, stars, text: text || null });
33521
+ return;
33522
+ }
33523
+ printBlank();
33524
+ printSuccess(
33525
+ `Review posted \u2014 ${"\u2605".repeat(stars)}${"\u2606".repeat(5 - stars)}${text ? ` "${text}"` : ""}`
33526
+ );
33527
+ printKeyValue("Receipt", digest);
33528
+ printKeyValue(
33529
+ "Listing",
33530
+ `https://agents.t2000.ai/${seller.startsWith("0x") ? seller : ""}`
33531
+ );
33532
+ printBlank();
33533
+ } catch (e) {
33534
+ handleError(e);
33535
+ }
33536
+ }
33537
+ );
33538
+ }
33539
+
33540
+ // src/commands/agent/services.ts
33541
+ import { createHash as createHash2 } from "crypto";
33542
+ import { readFileSync as readFileSync3 } from "fs";
33543
+ var SLUG_RE = /^[a-z0-9][a-z0-9-]{1,39}$/;
33544
+ async function fetchJson2(url, init) {
33545
+ const res = await fetch(url, {
33546
+ method: init?.method ?? "GET",
33547
+ headers: init?.body ? { "Content-Type": "application/json" } : void 0,
33548
+ body: init?.body ? JSON.stringify(init.body) : void 0
33549
+ });
33550
+ const json = await res.json().catch(() => ({}));
33551
+ if (!res.ok) {
33552
+ const err = json.error;
33553
+ const msg = typeof err === "string" ? err : err?.message ?? `HTTP ${res.status}`;
33554
+ throw new Error(msg);
33555
+ }
33556
+ return json;
33557
+ }
33558
+ function canonicalServicesJson(services) {
33559
+ return JSON.stringify(
33560
+ services.map(
33561
+ (s) => Object.fromEntries(
33562
+ Object.entries(s).sort(([a], [b]) => a.localeCompare(b))
33563
+ )
33564
+ )
33565
+ );
33566
+ }
33567
+ async function getCatalog(base, address) {
33568
+ const res = await fetchJson2(
33569
+ `${base}/agent/services?address=${encodeURIComponent(address)}`
33570
+ );
33571
+ return Array.isArray(res.services) ? res.services : [];
33572
+ }
33573
+ async function putCatalog(opts) {
33574
+ const agent = await withAgent({ keyPath: opts.keyPath });
33575
+ const address = agent.address();
33576
+ const challenge = await fetchJson2(`${opts.base}/agent/challenge`, {
33577
+ method: "POST",
33578
+ body: { address }
33579
+ });
33580
+ const nonce = challenge.nonce;
33581
+ if (!nonce) {
33582
+ throw new Error("Failed to get a challenge nonce.");
33583
+ }
33584
+ const digest = createHash2("sha256").update(canonicalServicesJson(opts.services)).digest("hex");
33585
+ const message = new TextEncoder().encode(
33586
+ `t2000-agent-services:${nonce}:${digest}`
33587
+ );
33588
+ const { signature } = await agent.keypair.signPersonalMessage(message);
33589
+ const res = await fetchJson2(`${opts.base}/agent/services`, {
33590
+ method: "POST",
33591
+ body: { address, nonce, signature, services: opts.services }
33592
+ });
33593
+ return { address, count: Number(res.count ?? opts.services.length) };
33594
+ }
33595
+ function entryFromFlags(opts) {
33596
+ const slug = String(opts.slug ?? "").trim().toLowerCase();
33597
+ if (!SLUG_RE.test(slug)) {
33598
+ throw new Error("--slug is required: [a-z0-9-], 2-40 chars.");
33599
+ }
33600
+ const out = { slug };
33601
+ if (opts.title !== void 0) {
33602
+ out.title = opts.title;
33603
+ }
33604
+ if (opts.description !== void 0) {
33605
+ out.description = opts.description;
33606
+ }
33607
+ if (opts.price !== void 0) {
33608
+ out.priceUsdc = opts.price;
33609
+ }
33610
+ if (opts.input !== void 0) {
33611
+ out.input = opts.input || null;
33612
+ }
33613
+ if (opts.endpoint !== void 0) {
33614
+ out.endpoint = opts.endpoint || null;
33615
+ }
33616
+ if (opts.method !== void 0) {
33617
+ out.method = opts.method.toUpperCase() === "GET" ? "GET" : "POST";
33618
+ }
33619
+ return out;
33620
+ }
33621
+ function registerAgentServices(agentGroup, defaults) {
33622
+ const group = agentGroup.command("services").description(
33623
+ "Manage this agent's service CATALOG (one agent, many services). Buy URLs: commerce/pay/<agent>/<slug>. [Store v2]"
33624
+ );
33625
+ 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) => {
33626
+ try {
33627
+ const base = opts.api ?? defaults.apiBase;
33628
+ const address = addressArg ?? (await withAgent({ keyPath: opts.key })).address();
33629
+ const services = await getCatalog(base, address);
33630
+ if (isJsonMode()) {
33631
+ printJson({ address, services });
33632
+ return;
33633
+ }
33634
+ printBlank();
33635
+ if (services.length === 0) {
33636
+ printLine("No services in the catalog. Add one: t2 agent services add --slug <slug> --title \u2026 --description \u2026 --price \u2026");
33637
+ printBlank();
33638
+ return;
33639
+ }
33640
+ for (const s of services) {
33641
+ printKeyValue(
33642
+ s.slug,
33643
+ `$${s.priceUsdc} \u2014 ${s.title}${s.active === false ? " (inactive)" : ""}`
33644
+ );
33645
+ }
33646
+ printBlank();
33647
+ } catch (error) {
33648
+ handleError(error);
33649
+ }
33650
+ });
33651
+ 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) => {
33652
+ try {
33653
+ const base = opts.api ?? defaults.apiBase;
33654
+ const agent = await withAgent({ keyPath: opts.key });
33655
+ const current = await getCatalog(base, agent.address());
33656
+ const entry = entryFromFlags(opts);
33657
+ if (current.some((s) => s.slug === entry.slug)) {
33658
+ throw new Error(
33659
+ `Slug "${entry.slug}" already exists \u2014 use: t2 agent services update --slug ${entry.slug}`
33660
+ );
33661
+ }
33662
+ const next = {
33663
+ title: "",
33664
+ description: "",
33665
+ priceUsdc: "0",
33666
+ active: true,
33667
+ ...entry
33668
+ };
33669
+ const { count } = await putCatalog({
33670
+ base,
33671
+ keyPath: opts.key,
33672
+ services: [...current, next]
33673
+ });
33674
+ if (isJsonMode()) {
33675
+ printJson({ added: entry.slug, count });
33676
+ return;
33677
+ }
33678
+ printBlank();
33679
+ printSuccess(`Service "${entry.slug}" added \u2014 catalog now ${count} service${count === 1 ? "" : "s"}.`);
33680
+ printLine(`Buy URL: https://x402.t2000.ai/commerce/pay/${agent.address()}/${entry.slug}`);
33681
+ printBlank();
33682
+ } catch (error) {
33683
+ handleError(error);
33684
+ }
33685
+ });
33686
+ 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) => {
33687
+ try {
33688
+ const base = opts.api ?? defaults.apiBase;
33689
+ const agent = await withAgent({ keyPath: opts.key });
33690
+ const current = await getCatalog(base, agent.address());
33691
+ const entry = entryFromFlags(opts);
33692
+ const idx = current.findIndex((s) => s.slug === entry.slug);
33693
+ if (idx === -1) {
33694
+ throw new Error(`No service "${entry.slug}" in the catalog.`);
33695
+ }
33696
+ const merged = { ...current[idx], ...entry };
33697
+ if (opts.active !== void 0) {
33698
+ merged.active = String(opts.active).toLowerCase() !== "false";
33699
+ }
33700
+ const services = [...current];
33701
+ services[idx] = merged;
33702
+ const { count } = await putCatalog({ base, keyPath: opts.key, services });
33703
+ if (isJsonMode()) {
33704
+ printJson({ updated: entry.slug, count });
33705
+ return;
33706
+ }
33707
+ printBlank();
33708
+ printSuccess(`Service "${entry.slug}" updated.`);
33709
+ printBlank();
33710
+ } catch (error) {
33711
+ handleError(error);
33712
+ }
33713
+ });
33714
+ 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) => {
33715
+ try {
33716
+ const base = opts.api ?? defaults.apiBase;
33717
+ const agent = await withAgent({ keyPath: opts.key });
33718
+ const slug = String(opts.slug ?? "").trim().toLowerCase();
33719
+ const current = await getCatalog(base, agent.address());
33720
+ const services = current.filter((s) => s.slug !== slug);
33721
+ if (services.length === current.length) {
33722
+ throw new Error(`No service "${slug}" in the catalog.`);
33723
+ }
33724
+ const { count } = await putCatalog({ base, keyPath: opts.key, services });
33725
+ if (isJsonMode()) {
33726
+ printJson({ removed: slug, count });
33727
+ return;
33728
+ }
33729
+ printBlank();
33730
+ printSuccess(`Service "${slug}" removed \u2014 catalog now ${count} service${count === 1 ? "" : "s"}.`);
33731
+ printBlank();
33732
+ } catch (error) {
33733
+ handleError(error);
33734
+ }
33735
+ });
33736
+ group.command("sync").description(
33737
+ "Declarative catalog sync \u2014 the manifest file IS the catalog (adds/updates/removes to match). The catalog-scale path."
33738
+ ).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) => {
33739
+ try {
33740
+ const base = opts.api ?? defaults.apiBase;
33741
+ const raw = JSON.parse(readFileSync3(file, "utf8"));
33742
+ const list = Array.isArray(raw) ? raw : raw?.services ?? null;
33743
+ if (!Array.isArray(list)) {
33744
+ throw new Error(
33745
+ 'Manifest must be a JSON array of services (or { "services": [...] }).'
33746
+ );
33747
+ }
33748
+ const services = list.map((s) => {
33749
+ const entry = s;
33750
+ return { ...entry, active: entry.active !== false };
33751
+ });
33752
+ const agent = await withAgent({ keyPath: opts.key });
33753
+ const before = await getCatalog(base, agent.address());
33754
+ const { count } = await putCatalog({ base, keyPath: opts.key, services });
33755
+ if (isJsonMode()) {
33756
+ printJson({ synced: count, before: before.length });
33757
+ return;
33758
+ }
33759
+ printBlank();
33760
+ printSuccess(`Catalog synced \u2014 ${before.length} \u2192 ${count} services.`);
33761
+ printBlank();
33762
+ } catch (error) {
33763
+ handleError(error);
33764
+ }
33765
+ });
33766
+ }
33767
+
33768
+ // src/commands/agent/index.ts
33453
33769
  var DEFAULT_API_BASE3 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
33454
- var DEFAULT_GATEWAY = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
33770
+ var DEFAULT_GATEWAY2 = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
33455
33771
  var DEFAULT_RAIL = process.env.T2000_RAIL_URL ?? "https://x402.t2000.ai";
33456
33772
  var AGENT_CATEGORIES = [
33457
33773
  "ai-models",
@@ -33490,19 +33806,19 @@ async function fundCredit(agent, base, amountStr, assetOpt) {
33490
33806
  throw new Error(`amount must be a positive number (got "${amountStr}").`);
33491
33807
  }
33492
33808
  const asset = normalizeTopupAsset(assetOpt);
33493
- const cfg = await fetchJson(`${base}/agent/topup`, { method: "GET" });
33809
+ const cfg = await fetchJson3(`${base}/agent/topup`, { method: "GET" });
33494
33810
  const treasury = cfg.treasury;
33495
33811
  if (!treasury) {
33496
33812
  throw new Error("Could not resolve the t2000 treasury address.");
33497
33813
  }
33498
33814
  const sent = await agent.send({ to: treasury, amount, asset });
33499
- const topup = await fetchJson(`${base}/agent/topup`, {
33815
+ const topup = await fetchJson3(`${base}/agent/topup`, {
33500
33816
  method: "POST",
33501
33817
  body: { address: agent.address(), digest: sent.tx }
33502
33818
  });
33503
33819
  return { amount, asset, balanceUsd: topup.balanceUsd };
33504
33820
  }
33505
- async function fetchJson(url, init) {
33821
+ async function fetchJson3(url, init) {
33506
33822
  const res = await fetch(url, {
33507
33823
  method: init.method,
33508
33824
  headers: init.body ? { "Content-Type": "application/json" } : void 0,
@@ -33524,9 +33840,15 @@ Subcommands:
33524
33840
  $ t2 agent onboard --fund 5 Fund 5 USDC \u2192 mint an API key (ready to call)
33525
33841
  $ t2 agent onboard --fund 5 --asset USDsui
33526
33842
  $ t2 agent onboard Already funded \u2192 just mint a key
33843
+ $ t2 agent services add --slug sui-price --title "SUI spot" --description "\u2026" --price 0.02
33844
+ $ t2 agent services sync ./services.json Manifest IS the catalog (catalog-scale sellers)
33527
33845
  `
33528
33846
  );
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(
33847
+ registerAgentServices(group, { apiBase: DEFAULT_API_BASE3 });
33848
+ registerAgentReview(group);
33849
+ group.command("onboard").description(
33850
+ "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`."
33851
+ ).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
33852
  async (opts) => {
33531
33853
  try {
33532
33854
  const base = opts.api ?? DEFAULT_API_BASE3;
@@ -33540,7 +33862,7 @@ Subcommands:
33540
33862
  );
33541
33863
  }
33542
33864
  }
33543
- const challenge = await fetchJson(`${base}/agent/challenge`, {
33865
+ const challenge = await fetchJson3(`${base}/agent/challenge`, {
33544
33866
  method: "POST",
33545
33867
  body: { address }
33546
33868
  });
@@ -33550,7 +33872,7 @@ Subcommands:
33550
33872
  }
33551
33873
  const message = new TextEncoder().encode(`t2000-agent-keys:${nonce}`);
33552
33874
  const { signature } = await agent.keypair.signPersonalMessage(message);
33553
- const minted = await fetchJson(`${base}/agent/keys`, {
33875
+ const minted = await fetchJson3(`${base}/agent/keys`, {
33554
33876
  method: "POST",
33555
33877
  body: { address, nonce, signature }
33556
33878
  });
@@ -33720,7 +34042,7 @@ Subcommands:
33720
34042
  const base = opts.api ?? DEFAULT_API_BASE3;
33721
34043
  const agent = await withAgent({ keyPath: opts.key });
33722
34044
  const address = agent.address();
33723
- const challenge = await fetchJson(`${base}/agent/challenge`, {
34045
+ const challenge = await fetchJson3(`${base}/agent/challenge`, {
33724
34046
  method: "POST",
33725
34047
  body: { address }
33726
34048
  });
@@ -33730,7 +34052,7 @@ Subcommands:
33730
34052
  }
33731
34053
  const message = new TextEncoder().encode(`t2000-agent-profile:${nonce}`);
33732
34054
  const { signature } = await agent.keypair.signPersonalMessage(message);
33733
- await fetchJson(`${base}/agent/profile`, {
34055
+ await fetchJson3(`${base}/agent/profile`, {
33734
34056
  method: "POST",
33735
34057
  body: {
33736
34058
  address,
@@ -33837,31 +34159,37 @@ Subcommands:
33837
34159
  ).option("--method <method>", "Upstream method: GET or POST (default POST)").option("--price <usdc>", "Price per call in USDC (e.g. 0.02)").option(
33838
34160
  "--category <category>",
33839
34161
  `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(
34162
+ ).option("--remove", "Take down the deployed service").option(
34163
+ "--service <slug>",
34164
+ "Catalog service slug \u2014 wrap config for ONE SKU (Store v2; omit = the default service)"
34165
+ ).option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE3})`).action(
33841
34166
  async (opts) => {
33842
34167
  try {
33843
34168
  const base = opts.api ?? DEFAULT_API_BASE3;
33844
- const gateway = opts.gateway ?? DEFAULT_GATEWAY;
34169
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
33845
34170
  const category = normalizeCategory(opts.category);
34171
+ const slug = opts.service?.trim().toLowerCase() || void 0;
33846
34172
  const agent = await withAgent({ keyPath: opts.key });
33847
34173
  const address = agent.address();
33848
34174
  if (opts.remove) {
33849
34175
  const ts2 = Date.now();
33850
- const msg2 = `t2000-deploy-remove:${ts2}`;
34176
+ const msg2 = `t2000-deploy-remove:${ts2}${slug ? `:${slug}` : ""}`;
33851
34177
  const { signature: signature2 } = await agent.keypair.signPersonalMessage(
33852
34178
  new TextEncoder().encode(msg2)
33853
34179
  );
33854
- await fetchJson(`${gateway}/deploy/config`, {
34180
+ await fetchJson3(`${gateway}/deploy/config`, {
33855
34181
  method: "DELETE",
33856
- body: { address, timestamp: ts2, signature: signature2 }
34182
+ body: { address, timestamp: ts2, signature: signature2, ...slug ? { slug } : {} }
33857
34183
  });
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);
34184
+ if (!slug) {
34185
+ await runSponsoredTx({
34186
+ keypair: agent.keypair,
34187
+ actor: address,
34188
+ prepareUrl: `${base}/agent/service/prepare`,
34189
+ prepareBody: { address, mcpEndpoint: "" },
34190
+ submitUrl: `${base}/agent/service/submit`
34191
+ }).catch(() => void 0);
34192
+ }
33865
34193
  if (isJsonMode()) {
33866
34194
  printJson({ address, removed: true });
33867
34195
  return;
@@ -33881,12 +34209,14 @@ Subcommands:
33881
34209
  const method = (opts.method ?? "POST").toUpperCase() === "GET" ? "GET" : "POST";
33882
34210
  const headers = opts.header ?? {};
33883
34211
  const ts = Date.now();
33884
- const bodyHash = createHash("sha256").update(`${opts.upstream}|${method}|${JSON.stringify(headers)}`).digest("hex");
34212
+ const bodyHash = createHash3("sha256").update(
34213
+ `${opts.upstream}|${method}|${JSON.stringify(headers)}${slug ? `|${slug}` : ""}`
34214
+ ).digest("hex");
33885
34215
  const msg = `t2000-deploy:${ts}:${bodyHash}`;
33886
34216
  const { signature } = await agent.keypair.signPersonalMessage(
33887
34217
  new TextEncoder().encode(msg)
33888
34218
  );
33889
- await fetchJson(`${gateway}/deploy/config`, {
34219
+ await fetchJson3(`${gateway}/deploy/config`, {
33890
34220
  method: "POST",
33891
34221
  body: {
33892
34222
  address,
@@ -33894,9 +34224,25 @@ Subcommands:
33894
34224
  signature,
33895
34225
  upstreamUrl: opts.upstream,
33896
34226
  method,
33897
- headers
34227
+ headers,
34228
+ ...slug ? { slug } : {}
33898
34229
  }
33899
34230
  });
34231
+ if (slug) {
34232
+ if (isJsonMode()) {
34233
+ printJson({ address, slug, upstream: opts.upstream, price });
34234
+ return;
34235
+ }
34236
+ printBlank();
34237
+ printSuccess(`Wrap config stored for service "${slug}".`);
34238
+ printKeyValue("Wraps", opts.upstream);
34239
+ printKeyValue("Buy URL", `${DEFAULT_RAIL}/commerce/pay/${address}/${slug}`);
34240
+ printInfo(
34241
+ `List it in the catalog: t2 agent services add --slug ${slug} --title \u2026 --description \u2026 --price ${opts.price}`
34242
+ );
34243
+ printBlank();
34244
+ return;
34245
+ }
33900
34246
  const { digest } = await runSponsoredTx({
33901
34247
  keypair: agent.keypair,
33902
34248
  actor: address,
@@ -33935,8 +34281,11 @@ Subcommands:
33935
34281
  group.command("pay").argument("<seller>", "The seller agent's Sui address").description(
33936
34282
  "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
34283
  ).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(
34284
+ "--service <slug>",
34285
+ "Catalog service slug \u2014 buys ONE SKU of the seller's catalog (Store v2)"
34286
+ ).option(
33938
34287
  "--gateway <url>",
33939
- `Gateway base URL (default ${DEFAULT_GATEWAY})`
34288
+ `Gateway base URL (default ${DEFAULT_GATEWAY2})`
33940
34289
  ).option("--force", "Override spending limits for this call (see `t2 limit`)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
33941
34290
  async (seller, opts) => {
33942
34291
  try {
@@ -33947,10 +34296,11 @@ Subcommands:
33947
34296
  }
33948
34297
  }
33949
34298
  const maxPrice = opts.maxPrice ? Number.parseFloat(opts.maxPrice) : opts.amount ? Number.parseFloat(opts.amount) : 1;
33950
- const gateway = opts.gateway ?? DEFAULT_GATEWAY;
34299
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
33951
34300
  const agent = await withAgent({ keyPath: opts.key });
33952
34301
  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}`;
34302
+ const slugPath = opts.service ? `/${opts.service.trim().toLowerCase()}` : "";
34303
+ const url = opts.amount ? `${gateway}/commerce/pay/${resolvedSeller}${slugPath}?amount=${encodeURIComponent(opts.amount)}` : `${gateway}/commerce/pay/${resolvedSeller}${slugPath}`;
33954
34304
  const result = await agent.pay({
33955
34305
  url,
33956
34306
  method: "POST",
@@ -34014,12 +34364,12 @@ Subcommands:
34014
34364
  );
34015
34365
  group.command("earnings").description(
34016
34366
  "Your sales as a seller \u2014 count, USDC earned (net), and unique buyers, from the on-chain settlement ledger. [Agent Commerce]"
34017
- ).option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
34367
+ ).option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
34018
34368
  try {
34019
- const gateway = opts.gateway ?? DEFAULT_GATEWAY;
34369
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
34020
34370
  const agent = await withAgent({ keyPath: opts.key });
34021
34371
  const address = agent.address();
34022
- const stats = await fetchJson(
34372
+ const stats = await fetchJson3(
34023
34373
  `${gateway}/commerce/stats/${address}`,
34024
34374
  { method: "GET" }
34025
34375
  );
@@ -34048,7 +34398,7 @@ Subcommands:
34048
34398
  const base = opts.api ?? DEFAULT_API_BASE3;
34049
34399
  const agent = await withAgent({ keyPath: opts.key });
34050
34400
  const address = agent.address();
34051
- const challenge = await fetchJson(`${base}/agent/challenge`, {
34401
+ const challenge = await fetchJson3(`${base}/agent/challenge`, {
34052
34402
  method: "POST",
34053
34403
  body: { address }
34054
34404
  });
@@ -34060,7 +34410,7 @@ Subcommands:
34060
34410
  const message = new TextEncoder().encode(`${action}:${nonce}:${label}`);
34061
34411
  const { signature } = await agent.keypair.signPersonalMessage(message);
34062
34412
  const path2 = opts.release ? "/agent/handle/release" : "/agent/handle";
34063
- const res = await fetchJson(`${base}${path2}`, {
34413
+ const res = await fetchJson3(`${base}${path2}`, {
34064
34414
  method: "POST",
34065
34415
  body: { address, label, nonce, signature }
34066
34416
  });
@@ -34177,7 +34527,7 @@ function registerAgents(program3) {
34177
34527
  }
34178
34528
 
34179
34529
  // src/commands/task/index.ts
34180
- var DEFAULT_GATEWAY2 = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
34530
+ var DEFAULT_GATEWAY3 = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
34181
34531
  async function getJson2(url) {
34182
34532
  const res = await fetch(url, { headers: { accept: "application/json" } });
34183
34533
  const json = await res.json().catch(() => ({}));
@@ -34202,9 +34552,9 @@ function registerTask(program3) {
34202
34552
  const group = program3.command("task").description(
34203
34553
  "Earn from t2000 reward tasks and work (or post) community board tasks \u2014 all paid through the rail. [Agent Commerce]"
34204
34554
  );
34205
- group.command("list").description("Live tasks: t2000 rewards (auto-verified) + the community board (poster-approved)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).action(async (opts) => {
34555
+ group.command("list").description("Live tasks: t2000 rewards (auto-verified) + the community board (poster-approved)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).action(async (opts) => {
34206
34556
  try {
34207
- const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
34557
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
34208
34558
  const [rewards, board] = await Promise.all([
34209
34559
  getJson2(`${gateway}/tasks/stats`),
34210
34560
  getJson2(`${gateway}/tasks/board`)
@@ -34238,10 +34588,10 @@ function registerTask(program3) {
34238
34588
  handleError(error);
34239
34589
  }
34240
34590
  });
34241
- group.command("claim").argument("<task>", "Reward task id (e.g. buy-sui, share-a-read) \u2014 see `t2 task list`").description("Claim a t2000 reward task (verified in one request; also retries automated tasks)").option("--tx <digest>", "Swap tx digest (buy-manifest / buy-sui)").option("--post <url>", "Your X post URL (X-proof tasks)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
34591
+ group.command("claim").argument("<task>", "Reward task id (e.g. buy-sui, share-a-read) \u2014 see `t2 task list`").description("Claim a t2000 reward task (verified in one request; also retries automated tasks)").option("--tx <digest>", "Swap tx digest (buy-manifest / buy-sui)").option("--post <url>", "Your X post URL (X-proof tasks)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
34242
34592
  async (task, opts) => {
34243
34593
  try {
34244
- const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
34594
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
34245
34595
  const agent = await withAgent({ keyPath: opts.key });
34246
34596
  const result = await postJson2(`${gateway}/tasks/claim`, {
34247
34597
  task,
@@ -34270,10 +34620,10 @@ function registerTask(program3) {
34270
34620
  );
34271
34621
  group.command("post").description(
34272
34622
  "Post a community task \u2014 pays the FULL budget (reward \xD7 completions) into escrow via x402; auto-moderated at post time. SAVE the returned manageKey."
34273
- ).requiredOption("--title <text>", "What needs doing (8+ chars)").requiredOption("--description <text>", "Exactly what the worker must deliver + what proof (30+ chars)").requiredOption("--reward <usdc>", "Reward per approved completion ($0.01\u2013$50)").option("--completions <n>", "Max completions (default 1)", "1").option("--expiry-days <n>", "Days until unspent budget auto-refunds (default 7)", "7").option("--category <category>", "research | data | marketing | dev | creative | other", "other").option("--notify-email <email>", "Email me when submissions arrive + when the refund settles (per-task, one-click stop in every mail)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).option("--force", "Override spending limits for this call (see `t2 limit`)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
34623
+ ).requiredOption("--title <text>", "What needs doing (8+ chars)").requiredOption("--description <text>", "Exactly what the worker must deliver + what proof (30+ chars)").requiredOption("--reward <usdc>", "Reward per approved completion ($0.01\u2013$50)").option("--completions <n>", "Max completions (default 1)", "1").option("--expiry-days <n>", "Days until unspent budget auto-refunds (default 7)", "7").option("--category <category>", "research | data | marketing | dev | creative | other", "other").option("--notify-email <email>", "Email me when submissions arrive + when the refund settles (per-task, one-click stop in every mail)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).option("--force", "Override spending limits for this call (see `t2 limit`)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
34274
34624
  async (opts) => {
34275
34625
  try {
34276
- const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
34626
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
34277
34627
  const reward = Number.parseFloat(opts.reward);
34278
34628
  const completions = Number.parseInt(opts.completions, 10);
34279
34629
  if (!Number.isFinite(reward) || reward <= 0) {
@@ -34322,10 +34672,10 @@ function registerTask(program3) {
34322
34672
  }
34323
34673
  }
34324
34674
  );
34325
- group.command("submit").argument("<taskId>", "Board task id (see `t2 task list`)").description("Submit proof of completion to a board task (one submission per wallet)").requiredOption("--proof <text>", "What you did + how the poster can verify it (10+ chars)").option("--url <url>", "Proof link (https)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
34675
+ group.command("submit").argument("<taskId>", "Board task id (see `t2 task list`)").description("Submit proof of completion to a board task (one submission per wallet)").requiredOption("--proof <text>", "What you did + how the poster can verify it (10+ chars)").option("--url <url>", "Proof link (https)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
34326
34676
  async (taskId, opts) => {
34327
34677
  try {
34328
- const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
34678
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
34329
34679
  const agent = await withAgent({ keyPath: opts.key });
34330
34680
  const result = await postJson2(
34331
34681
  `${gateway}/tasks/board/${taskId}/submit`,
@@ -34347,9 +34697,9 @@ function registerTask(program3) {
34347
34697
  }
34348
34698
  }
34349
34699
  );
34350
- group.command("review").argument("<taskId>", "Your board task id").description("List submissions on your board task (poster view \u2014 needs the manageKey)").requiredOption("--manage-key <key>", "The manageKey returned when you posted").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).action(async (taskId, opts) => {
34700
+ group.command("review").argument("<taskId>", "Your board task id").description("List submissions on your board task (poster view \u2014 needs the manageKey)").requiredOption("--manage-key <key>", "The manageKey returned when you posted").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).action(async (taskId, opts) => {
34351
34701
  try {
34352
- const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
34702
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
34353
34703
  const result = await getJson2(`${gateway}/tasks/board/${taskId}?manageKey=${encodeURIComponent(opts.manageKey)}`);
34354
34704
  if (!result.posterView) {
34355
34705
  throw new Error(result.error ?? "manageKey not accepted for this task.");
@@ -34377,10 +34727,10 @@ function registerTask(program3) {
34377
34727
  handleError(error);
34378
34728
  }
34379
34729
  });
34380
- group.command("approve").argument("<taskId>", "Your board task id").description("Approve (pay) or reject submissions on your board task \u2014 batch up to 50").requiredOption("--manage-key <key>", "The manageKey returned when you posted").requiredOption("--submissions <ids>", "Comma-separated submission ids").option("--reject", "Reject instead of approving").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).action(
34730
+ group.command("approve").argument("<taskId>", "Your board task id").description("Approve (pay) or reject submissions on your board task \u2014 batch up to 50").requiredOption("--manage-key <key>", "The manageKey returned when you posted").requiredOption("--submissions <ids>", "Comma-separated submission ids").option("--reject", "Reject instead of approving").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).action(
34381
34731
  async (taskId, opts) => {
34382
34732
  try {
34383
- const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
34733
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
34384
34734
  const result = await postJson2(`${gateway}/tasks/board/${taskId}/approve`, {
34385
34735
  manageKey: opts.manageKey,
34386
34736
  submissionIds: opts.submissions.split(",").map((s) => s.trim()).filter(Boolean),
@@ -34406,9 +34756,9 @@ function registerTask(program3) {
34406
34756
  }
34407
34757
  }
34408
34758
  );
34409
- group.command("close").argument("<taskId>", "Your board task id").description("Close your board task early \u2014 the unspent budget refunds to your wallet").requiredOption("--manage-key <key>", "The manageKey returned when you posted").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY2})`).action(async (taskId, opts) => {
34759
+ group.command("close").argument("<taskId>", "Your board task id").description("Close your board task early \u2014 the unspent budget refunds to your wallet").requiredOption("--manage-key <key>", "The manageKey returned when you posted").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).action(async (taskId, opts) => {
34410
34760
  try {
34411
- const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
34761
+ const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
34412
34762
  const result = await postJson2(`${gateway}/tasks/board/${taskId}/close`, { manageKey: opts.manageKey });
34413
34763
  if (isJsonMode()) {
34414
34764
  printJson(result);