@t2000/cli 5.7.0 → 5.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -80332,7 +80332,7 @@ Through this wallet you can reach essentially any major external API, billed to
80332
80332
  CRITICAL: When the user asks to use any external or paid API, names a provider (e.g. "via fal.ai", "with ElevenLabs"), or requests a capability one of the services above provides, DO NOT say you cannot reach that service, that it isn't on an allowlist, or that there's no connector \u2014 and do NOT fall back to writing a script for the user to run. You CAN do it directly through this wallet. Use t2000_services to discover the endpoint and request shape, then t2000_pay to execute, then show the user the result (display image/audio URLs returned in the response).
80333
80333
 
80334
80334
  Spending is the user's own USDC and every t2000_pay call is bounded by maxPrice. For larger or multi-step spends, state the estimated cost first and proceed once the user is happy. Use t2000_balance to check funds. The v4 wallet is payments-only; savings / lending live on audric.ai.`;
80335
- var PKG_VERSION = "5.7.0";
80335
+ var PKG_VERSION = "5.7.1";
80336
80336
  console.log = (...args) => console.error("[log]", ...args);
80337
80337
  console.warn = (...args) => console.error("[warn]", ...args);
80338
80338
  async function startMcpServer(opts) {
@@ -80398,4 +80398,4 @@ mime-types/index.js:
80398
80398
  @scure/bip39/index.js:
80399
80399
  (*! scure-bip39 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
80400
80400
  */
80401
- //# sourceMappingURL=dist-HTKRHJBX.js.map
80401
+ //# sourceMappingURL=dist-IBS23LR5.js.map
package/dist/index.js CHANGED
@@ -31313,7 +31313,49 @@ async function askHidden(message) {
31313
31313
  return esm_default9({ message });
31314
31314
  }
31315
31315
 
31316
+ // src/lib/agent-register.ts
31317
+ async function postJson(url, body) {
31318
+ const res = await fetch(url, {
31319
+ method: "POST",
31320
+ headers: { "Content-Type": "application/json" },
31321
+ body: JSON.stringify(body)
31322
+ });
31323
+ const json = await res.json().catch(() => ({}));
31324
+ if (!res.ok) {
31325
+ const err = json.error;
31326
+ const msg = typeof err === "string" ? err : err?.message ?? `HTTP ${res.status}`;
31327
+ throw new Error(msg);
31328
+ }
31329
+ return json;
31330
+ }
31331
+ async function registerWallet(opts) {
31332
+ const prep = await postJson(`${opts.base}/agent/register/prepare`, {
31333
+ address: opts.address
31334
+ });
31335
+ if (prep.alreadyRegistered === true) {
31336
+ return { alreadyRegistered: true };
31337
+ }
31338
+ const regNonce = prep.regNonce;
31339
+ const txBytes = prep.txBytes;
31340
+ if (!(regNonce && txBytes)) {
31341
+ throw new Error("Failed to prepare registration.");
31342
+ }
31343
+ const bytes = new Uint8Array(Buffer.from(txBytes, "base64"));
31344
+ const { signature } = await opts.keypair.signTransaction(bytes);
31345
+ const res = await postJson(`${opts.base}/agent/register/submit`, {
31346
+ regNonce,
31347
+ address: opts.address,
31348
+ agentSignature: signature
31349
+ });
31350
+ return {
31351
+ digest: res.digest,
31352
+ alreadyRegistered: Boolean(res.alreadyRegistered)
31353
+ };
31354
+ }
31355
+
31316
31356
  // src/commands/init.ts
31357
+ var DEFAULT_API_BASE = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
31358
+ var REGISTER_TIMEOUT_MS = 1e4;
31317
31359
  var DEFAULT_PER_TX_USD = 25;
31318
31360
  var DEFAULT_DAILY_USD = 100;
31319
31361
  var limitsFooter = (perTx, daily) => `Spending limits ON: $${perTx}/tx, $${daily}/day (cumulative). Change with \`t2 limit set\`, or override a single call with --force.`;
@@ -31321,6 +31363,9 @@ function registerInit(program3) {
31321
31363
  program3.command("init").description("Create a new Agent Wallet (no PIN; plain Bech32 key file with 0o600 perms)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option(
31322
31364
  "--import [secret]",
31323
31365
  "Import an existing wallet via Bech32 secret. Omit the value for an interactive hidden-input prompt."
31366
+ ).option(
31367
+ "--no-register",
31368
+ "Skip the best-effort on-chain Agent ID registration (offline/CI)."
31324
31369
  ).action(async (opts) => {
31325
31370
  try {
31326
31371
  if (await walletExists(opts.key)) {
@@ -31330,18 +31375,35 @@ function registerInit(program3) {
31330
31375
  }
31331
31376
  let address;
31332
31377
  let imported = false;
31378
+ let signingKeypair;
31333
31379
  if (opts.import !== void 0) {
31334
31380
  const secret = typeof opts.import === "string" && opts.import.length > 0 ? opts.import : await askHidden("Paste your suiprivkey1... secret:");
31335
31381
  if (typeof opts.import === "string" && opts.import.length > 0) {
31336
31382
  printWarning("Private key passed as a CLI flag will be in shell history. Prefer the interactive prompt: `t2 init --import` (no value).");
31337
31383
  }
31384
+ const kp = keypairFromPrivateKey(secret);
31338
31385
  await saveBech32(secret, opts.key);
31339
- address = getAddress(keypairFromPrivateKey(secret));
31386
+ address = getAddress(kp);
31387
+ signingKeypair = kp;
31340
31388
  imported = true;
31341
31389
  } else {
31342
31390
  const keypair = generateKeypair();
31343
31391
  await saveKey(keypair, void 0, opts.key);
31344
31392
  address = getAddress(keypair);
31393
+ signingKeypair = keypair;
31394
+ }
31395
+ let registered = false;
31396
+ if (opts.register !== false) {
31397
+ try {
31398
+ await Promise.race([
31399
+ registerWallet({ keypair: signingKeypair, address, base: DEFAULT_API_BASE }),
31400
+ new Promise(
31401
+ (_, reject) => setTimeout(() => reject(new Error("timeout")), REGISTER_TIMEOUT_MS)
31402
+ )
31403
+ ]);
31404
+ registered = true;
31405
+ } catch {
31406
+ }
31345
31407
  }
31346
31408
  if (!hasLimits()) {
31347
31409
  setLimits({ perTxUsd: DEFAULT_PER_TX_USD, dailyUsd: DEFAULT_DAILY_USD });
@@ -31350,6 +31412,7 @@ function registerInit(program3) {
31350
31412
  printJson({
31351
31413
  address,
31352
31414
  imported,
31415
+ registered,
31353
31416
  configPath: opts.key ?? "~/.t2000/wallet.key",
31354
31417
  limits: { perTxUsd: DEFAULT_PER_TX_USD, dailyUsd: DEFAULT_DAILY_USD }
31355
31418
  });
@@ -31359,6 +31422,12 @@ function registerInit(program3) {
31359
31422
  printSuccess(imported ? "Wallet imported" : "Wallet created");
31360
31423
  printKeyValue("Address", address);
31361
31424
  printKeyValue("Path", opts.key ?? "~/.t2000/wallet.key");
31425
+ if (opts.register !== false) {
31426
+ printKeyValue(
31427
+ "Agent ID",
31428
+ registered ? "registered" : "pending (run: t2 agent register)"
31429
+ );
31430
+ }
31362
31431
  printBlank();
31363
31432
  printLine(`\u26A0 ${limitsFooter(DEFAULT_PER_TX_USD, DEFAULT_DAILY_USD)}`);
31364
31433
  printBlank();
@@ -32495,7 +32564,7 @@ function registerMcpStart(parent) {
32495
32564
  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) => {
32496
32565
  let mod2;
32497
32566
  try {
32498
- mod2 = await import("./dist-HTKRHJBX.js");
32567
+ mod2 = await import("./dist-IBS23LR5.js");
32499
32568
  } catch {
32500
32569
  console.error("MCP server not installed. Run:\n npm install -g @t2000/mcp");
32501
32570
  process.exit(1);
@@ -32835,7 +32904,7 @@ For MCP-aware clients (Claude Desktop, Cursor, Windsurf), prefer
32835
32904
  }
32836
32905
 
32837
32906
  // src/commands/agent/index.ts
32838
- var DEFAULT_API_BASE = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
32907
+ var DEFAULT_API_BASE2 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
32839
32908
  function normalizeTopupAsset(input) {
32840
32909
  return input?.toLowerCase() === "usdsui" ? "USDsui" : "USDC";
32841
32910
  }
@@ -32881,10 +32950,10 @@ Subcommands:
32881
32950
  $ t2 agent onboard Already funded \u2192 just mint a key
32882
32951
  `
32883
32952
  );
32884
- 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_BASE})`).action(
32953
+ 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_BASE2})`).action(
32885
32954
  async (opts) => {
32886
32955
  try {
32887
- const base = opts.api ?? DEFAULT_API_BASE;
32956
+ const base = opts.api ?? DEFAULT_API_BASE2;
32888
32957
  const agent = await withAgent({ keyPath: opts.key });
32889
32958
  const address = agent.address();
32890
32959
  if (opts.fund !== void 0) {
@@ -32913,14 +32982,24 @@ Subcommands:
32913
32982
  if (!key) {
32914
32983
  throw new Error("Failed to mint an API key.");
32915
32984
  }
32985
+ let registered = false;
32986
+ try {
32987
+ await registerWallet({ keypair: agent.keypair, address, base });
32988
+ registered = true;
32989
+ } catch {
32990
+ }
32916
32991
  if (isJsonMode()) {
32917
- printJson({ address, apiKey: key, baseUrl: base });
32992
+ printJson({ address, apiKey: key, baseUrl: base, registered });
32918
32993
  return;
32919
32994
  }
32920
32995
  printBlank();
32921
32996
  printSuccess("Agent onboarded \u2014 API key minted (shown once, store it now)");
32922
32997
  printKeyValue("Address", truncateAddress(address));
32923
32998
  printKeyValue("API key", key);
32999
+ printKeyValue(
33000
+ "Agent ID",
33001
+ registered ? "registered" : "pending (retry: t2 agent register)"
33002
+ );
32924
33003
  printKeyValue("Base URL", base);
32925
33004
  printBlank();
32926
33005
  printInfo(`export OPENAI_BASE_URL=${base} OPENAI_API_KEY=${key}`);
@@ -32932,10 +33011,10 @@ Subcommands:
32932
33011
  );
32933
33012
  group.command("topup").argument("<amount>", "Stablecoin amount to deposit as credit").description(
32934
33013
  "Top up this wallet's t2000 credit with gasless USDC/USDsui (no new key). The 'never runs dry' primitive \u2014 call it on a 402 or a schedule."
32935
- ).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_BASE})`).action(
33014
+ ).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_BASE2})`).action(
32936
33015
  async (amount, opts) => {
32937
33016
  try {
32938
- const base = opts.api ?? DEFAULT_API_BASE;
33017
+ const base = opts.api ?? DEFAULT_API_BASE2;
32939
33018
  const agent = await withAgent({ keyPath: opts.key });
32940
33019
  const funded = await fundCredit(agent, base, amount, opts.asset);
32941
33020
  if (isJsonMode()) {
@@ -32957,12 +33036,42 @@ Subcommands:
32957
33036
  }
32958
33037
  }
32959
33038
  );
32960
- group.command("handle").argument("<label>", "Desired handle (3\u201320 chars: lowercase a\u2013z, 0\u20139, hyphens)").description(
32961
- "Claim <label>.agent-id.sui \u2192 this wallet \u2014 a human-readable Agent ID handle (custody-minted, gasless for you)."
32962
- ).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE})`).action(
33039
+ group.command("register").description(
33040
+ "Register this wallet on-chain as an Agent ID (sponsored, gasless). Idempotent \u2014 safe to re-run."
33041
+ ).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE2})`).action(async (opts) => {
33042
+ try {
33043
+ const base = opts.api ?? DEFAULT_API_BASE2;
33044
+ const agent = await withAgent({ keyPath: opts.key });
33045
+ const address = agent.address();
33046
+ const reg = await registerWallet({ keypair: agent.keypair, address, base });
33047
+ if (isJsonMode()) {
33048
+ printJson({
33049
+ address,
33050
+ registered: true,
33051
+ alreadyRegistered: reg.alreadyRegistered,
33052
+ digest: reg.digest
33053
+ });
33054
+ return;
33055
+ }
33056
+ printBlank();
33057
+ printSuccess(
33058
+ reg.alreadyRegistered ? "Already registered as an Agent ID" : "Registered as an Agent ID"
33059
+ );
33060
+ printKeyValue("Address", truncateAddress(address));
33061
+ if (reg.digest) {
33062
+ printKeyValue("Tx", reg.digest);
33063
+ }
33064
+ printBlank();
33065
+ } catch (error) {
33066
+ handleError(error);
33067
+ }
33068
+ });
33069
+ group.command("handle").argument("<label>", "Handle label (3\u201320 chars: lowercase a\u2013z, 0\u20139, hyphens)").description(
33070
+ "Claim <label>.agent-id.sui \u2192 this wallet (custody-minted, gasless). Use --release to give it up."
33071
+ ).option("--release", "Release (revoke) this handle instead of claiming it").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE2})`).action(
32963
33072
  async (label, opts) => {
32964
33073
  try {
32965
- const base = opts.api ?? DEFAULT_API_BASE;
33074
+ const base = opts.api ?? DEFAULT_API_BASE2;
32966
33075
  const agent = await withAgent({ keyPath: opts.key });
32967
33076
  const address = agent.address();
32968
33077
  const challenge = await fetchJson(`${base}/agent/challenge`, {
@@ -32973,25 +33082,26 @@ Subcommands:
32973
33082
  if (!nonce) {
32974
33083
  throw new Error("Failed to get a challenge nonce.");
32975
33084
  }
32976
- const message = new TextEncoder().encode(`t2000-agent-handle:${nonce}:${label}`);
33085
+ const action = opts.release ? "t2000-agent-handle-release" : "t2000-agent-handle";
33086
+ const message = new TextEncoder().encode(`${action}:${nonce}:${label}`);
32977
33087
  const { signature } = await agent.keypair.signPersonalMessage(message);
32978
- const res = await fetchJson(`${base}/agent/handle`, {
33088
+ const path2 = opts.release ? "/agent/handle/release" : "/agent/handle";
33089
+ const res = await fetchJson(`${base}${path2}`, {
32979
33090
  method: "POST",
32980
33091
  body: { address, label, nonce, signature }
32981
33092
  });
32982
33093
  if (isJsonMode()) {
32983
- printJson({
32984
- address,
32985
- handle: res.handle,
32986
- display: res.display,
32987
- digest: res.digest
32988
- });
33094
+ printJson({ address, ...res });
32989
33095
  return;
32990
33096
  }
32991
33097
  printBlank();
32992
- printSuccess(`Handle claimed: ${res.display}`);
33098
+ if (opts.release) {
33099
+ printSuccess(`Handle released: ${String(res.handle)}`);
33100
+ } else {
33101
+ printSuccess(`Handle claimed: ${String(res.display)}`);
33102
+ printKeyValue("Handle", String(res.handle));
33103
+ }
32993
33104
  printKeyValue("Address", truncateAddress(address));
32994
- printKeyValue("Handle", String(res.handle));
32995
33105
  printKeyValue("Tx", String(res.digest));
32996
33106
  printBlank();
32997
33107
  } catch (error) {