@t2000/cli 2.18.1 → 2.19.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.
@@ -16,6 +16,7 @@ import {
16
16
  HF_CRITICAL_THRESHOLD,
17
17
  HF_WARN_THRESHOLD,
18
18
  IKA_TYPE,
19
+ InvalidAddressError,
19
20
  KNOWN_TARGETS,
20
21
  KeypairSigner,
21
22
  LABEL_PATTERNS,
@@ -31,11 +32,16 @@ import {
31
32
  SAVE_FEE_BPS,
32
33
  SPONSORED_PYTH_DEPENDENT_PROVIDERS,
33
34
  STABLE_ASSETS,
35
+ SUINS_NAME_REGEX,
36
+ SUI_ADDRESS_REGEX,
37
+ SUI_ADDRESS_STRICT_REGEX,
34
38
  SUI_DECIMALS,
35
39
  SUI_TYPE,
36
40
  SUPPORTED_ASSETS,
37
41
  SafeguardEnforcer,
38
42
  SafeguardError,
43
+ SuinsNotRegisteredError,
44
+ SuinsRpcError,
39
45
  T2000,
40
46
  T2000Error,
41
47
  T2000_OVERLAY_FEE_WALLET,
@@ -111,10 +117,12 @@ import {
111
117
  isTier2,
112
118
  keypairFromPrivateKey,
113
119
  loadKey,
120
+ looksLikeSuiNs,
114
121
  mapMoveAbortCode,
115
122
  mapWalletError,
116
123
  mistToSui,
117
124
  naviDescriptor,
125
+ normalizeAddressInput,
118
126
  normalizeAsset,
119
127
  normalizeCoinType,
120
128
  parseSuiRpcTx,
@@ -123,6 +131,8 @@ import {
123
131
  rawToStable,
124
132
  rawToUsdc,
125
133
  refineLendingLabel,
134
+ resolveAddressToSuinsViaRpc,
135
+ resolveSuinsViaRpc,
126
136
  resolveSymbol,
127
137
  resolveTokenType,
128
138
  saveKey,
@@ -139,7 +149,7 @@ import {
139
149
  validateLabel,
140
150
  verifyCetusRouteCoinMatch,
141
151
  walletExists
142
- } from "./chunk-ZNZ4MOY2.js";
152
+ } from "./chunk-R7KXQRHQ.js";
143
153
  import "./chunk-ZRPJE7U5.js";
144
154
  import "./chunk-OCLKPYUU.js";
145
155
  import "./chunk-SI54PO2N.js";
@@ -167,6 +177,7 @@ export {
167
177
  HF_CRITICAL_THRESHOLD,
168
178
  HF_WARN_THRESHOLD,
169
179
  IKA_TYPE,
180
+ InvalidAddressError,
170
181
  KNOWN_TARGETS,
171
182
  KeypairSigner,
172
183
  LABEL_PATTERNS,
@@ -182,11 +193,16 @@ export {
182
193
  SAVE_FEE_BPS,
183
194
  SPONSORED_PYTH_DEPENDENT_PROVIDERS,
184
195
  STABLE_ASSETS,
196
+ SUINS_NAME_REGEX,
197
+ SUI_ADDRESS_REGEX,
198
+ SUI_ADDRESS_STRICT_REGEX,
185
199
  SUI_DECIMALS,
186
200
  SUI_TYPE,
187
201
  SUPPORTED_ASSETS,
188
202
  SafeguardEnforcer,
189
203
  SafeguardError,
204
+ SuinsNotRegisteredError,
205
+ SuinsRpcError,
190
206
  T2000,
191
207
  T2000Error,
192
208
  T2000_OVERLAY_FEE_WALLET,
@@ -262,10 +278,12 @@ export {
262
278
  isTier2,
263
279
  keypairFromPrivateKey,
264
280
  loadKey,
281
+ looksLikeSuiNs,
265
282
  mapMoveAbortCode,
266
283
  mapWalletError,
267
284
  mistToSui,
268
285
  naviDescriptor,
286
+ normalizeAddressInput,
269
287
  normalizeAsset,
270
288
  normalizeCoinType,
271
289
  parseSuiRpcTx,
@@ -274,6 +292,8 @@ export {
274
292
  rawToStable,
275
293
  rawToUsdc,
276
294
  refineLendingLabel,
295
+ resolveAddressToSuinsViaRpc,
296
+ resolveSuinsViaRpc,
277
297
  resolveSymbol,
278
298
  resolveTokenType,
279
299
  saveKey,
@@ -291,4 +311,4 @@ export {
291
311
  verifyCetusRouteCoinMatch,
292
312
  walletExists
293
313
  };
294
- //# sourceMappingURL=dist-EFTMN6BY.js.map
314
+ //# sourceMappingURL=dist-A7D5R6SM.js.map
@@ -134943,6 +134943,76 @@ function extractCommands(txBlock) {
134943
134943
  return result;
134944
134944
  }
134945
134945
  init_token_registry();
134946
+ var SUI_MAINNET_URL = "https://fullnode.mainnet.sui.io:443";
134947
+ var SUI_ADDRESS_REGEX = /^0x[a-fA-F0-9]{1,64}$/i;
134948
+ var SUINS_NAME_REGEX = /^[a-z0-9-]+(\.[a-z0-9-]+)*\.sui$/;
134949
+ var InvalidAddressError4 = class extends Error {
134950
+ constructor(raw) {
134951
+ super(
134952
+ `"${raw}" isn't a valid Sui address or SuiNS name. Pass a 0x-prefixed hex address (e.g. 0x40cd\u20263e62) or a SuiNS name ending in .sui (e.g. alex.sui).`
134953
+ );
134954
+ this.raw = raw;
134955
+ this.name = "InvalidAddressError";
134956
+ }
134957
+ };
134958
+ var SuinsNotRegisteredError = class extends Error {
134959
+ constructor(name_) {
134960
+ super(
134961
+ `"${name_}" isn't a registered SuiNS name. Double-check the spelling, or paste the full Sui address (0x\u2026 64 hex characters).`
134962
+ );
134963
+ this.name_ = name_;
134964
+ this.name = "SuinsNotRegisteredError";
134965
+ }
134966
+ };
134967
+ var SuinsRpcError = class extends Error {
134968
+ constructor(name_, detail) {
134969
+ super(`SuiNS lookup failed for "${name_}" (${detail}). Try again, or paste the full Sui address.`);
134970
+ this.name_ = name_;
134971
+ this.name = "SuinsRpcError";
134972
+ }
134973
+ };
134974
+ function looksLikeSuiNs(value) {
134975
+ if (!value) return false;
134976
+ return SUINS_NAME_REGEX.test(value.trim().toLowerCase());
134977
+ }
134978
+ async function resolveSuinsViaRpc(rawName, ctx = {}) {
134979
+ const name = rawName.trim().toLowerCase();
134980
+ if (!SUINS_NAME_REGEX.test(name)) {
134981
+ throw new InvalidAddressError4(rawName);
134982
+ }
134983
+ const url3 = ctx.suiRpcUrl || SUI_MAINNET_URL;
134984
+ let res;
134985
+ try {
134986
+ res = await fetch(url3, {
134987
+ method: "POST",
134988
+ headers: { "Content-Type": "application/json" },
134989
+ body: JSON.stringify({
134990
+ jsonrpc: "2.0",
134991
+ id: 1,
134992
+ method: "suix_resolveNameServiceAddress",
134993
+ params: [name]
134994
+ }),
134995
+ signal: ctx.signal ?? AbortSignal.timeout(8e3)
134996
+ });
134997
+ } catch (err) {
134998
+ const msg = err instanceof Error ? err.message : String(err);
134999
+ throw new SuinsRpcError(name, msg);
135000
+ }
135001
+ if (!res.ok) {
135002
+ throw new SuinsRpcError(name, `HTTP ${res.status}`);
135003
+ }
135004
+ let body;
135005
+ try {
135006
+ body = await res.json();
135007
+ } catch (err) {
135008
+ const msg = err instanceof Error ? err.message : String(err);
135009
+ throw new SuinsRpcError(name, `JSON parse failed: ${msg}`);
135010
+ }
135011
+ if (body.error) {
135012
+ throw new SuinsRpcError(name, body.error.message);
135013
+ }
135014
+ return body.result ?? null;
135015
+ }
134946
135016
  function ulebEncode2(num2) {
134947
135017
  let bigNum = BigInt(num2);
134948
135018
  const arr = [];
@@ -139313,6 +139383,14 @@ var SafeguardEnforcer = class {
139313
139383
  };
139314
139384
  init_errors9();
139315
139385
  var RESERVED_NAMES = /* @__PURE__ */ new Set(["to", "all", "address"]);
139386
+ var deprecationWarned = false;
139387
+ function warnContactsDeprecation() {
139388
+ if (deprecationWarned) return;
139389
+ deprecationWarned = true;
139390
+ console.warn(
139391
+ "[t2000] DEPRECATION: ~/.t2000/contacts.json alias resolution is deprecated and will be removed in the next major release. Use SuiNS names instead (e.g. `t2000 send alex.sui 10 USDC`). Register a SuiNS name at https://suins.io if you need a memorable handle."
139392
+ );
139393
+ }
139316
139394
  var ContactManager = class {
139317
139395
  contacts = {};
139318
139396
  filePath;
@@ -139342,6 +139420,7 @@ var ContactManager = class {
139342
139420
  const existed = key in this.contacts;
139343
139421
  this.contacts[key] = { name, address: normalized };
139344
139422
  this.save();
139423
+ warnContactsDeprecation();
139345
139424
  return { action: existed ? "updated" : "added" };
139346
139425
  }
139347
139426
  remove(name) {
@@ -139366,12 +139445,15 @@ var ContactManager = class {
139366
139445
  }
139367
139446
  const contact = this.contacts[nameOrAddress.toLowerCase()];
139368
139447
  if (contact) {
139448
+ warnContactsDeprecation();
139369
139449
  return { address: contact.address, contactName: contact.name };
139370
139450
  }
139371
139451
  throw new T2000Error(
139372
139452
  "CONTACT_NOT_FOUND",
139373
139453
  `"${nameOrAddress}" is not a valid Sui address or saved contact.
139374
- Add it: t2000 contacts add ${nameOrAddress} 0x...`
139454
+ Use a SuiNS name (e.g. alex.sui \u2014 register at https://suins.io)
139455
+ or paste the full Sui address (0x... 64 hex characters).
139456
+ Legacy contact aliases: \`t2000 contacts add ${nameOrAddress} 0x...\` (deprecated).`
139375
139457
  );
139376
139458
  }
139377
139459
  validateName(name) {
@@ -139741,7 +139823,7 @@ var T2000 = class _T2000 extends import_index2.default {
139741
139823
  if (!(asset in SUPPORTED_ASSETS)) {
139742
139824
  throw new T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
139743
139825
  }
139744
- const resolved = this.contacts.resolve(params.to);
139826
+ const resolved = await this.resolveRecipient(params.to);
139745
139827
  const sendAmount = params.amount;
139746
139828
  const sendTo = resolved.address;
139747
139829
  const gasResult = await executeTx(
@@ -139758,11 +139840,63 @@ var T2000 = class _T2000 extends import_index2.default {
139758
139840
  amount: sendAmount,
139759
139841
  to: resolved.address,
139760
139842
  contactName: resolved.contactName,
139843
+ suinsName: resolved.suinsName,
139761
139844
  gasCost: gasResult.gasCostSui,
139762
139845
  gasCostUnit: "SUI",
139763
139846
  balance
139764
139847
  };
139765
139848
  }
139849
+ /**
139850
+ * [S.279 / CLI-CONTACTS-CLEANUP — 2026-05-23] Resolve a recipient
139851
+ * string into a canonical 0x address, trying each shape in priority
139852
+ * order:
139853
+ * 1. **hex** — `0x…` is used directly (no RPC round-trip).
139854
+ * 2. **SuiNS** — `alex.sui` resolves via `suix_resolveNameServiceAddress`.
139855
+ * 3. **saved contact** — `ContactManager.resolve()` falls back to the
139856
+ * legacy `~/.t2000/contacts.json` alias map. Deprecated; the
139857
+ * manager surfaces a one-time `console.warn` when this path fires.
139858
+ *
139859
+ * Returns `{ address, suinsName?, contactName? }` so `send()` can stamp
139860
+ * the name source on the receipt without re-resolving.
139861
+ *
139862
+ * Throws `T2000Error('SUINS_NOT_REGISTERED', …)` for well-formed but
139863
+ * unregistered SuiNS names (vs. propagating the engine-style
139864
+ * `SuinsNotRegisteredError` — keeps the SDK's error surface
139865
+ * `T2000Error`-only, consistent with every other write helper).
139866
+ *
139867
+ * [S.279.1 / 2026-05-23 — patch v2.19.1] Promoted from `private` to
139868
+ * `public` so MCP's `t2000_send` dryRun preview path can share the
139869
+ * same resolution logic as the live execute path. Pre-2.19.1 the
139870
+ * MCP dryRun called `agent.contacts.resolve(to)` directly, which
139871
+ * rejected SuiNS names — preview-then-execute flows broke for
139872
+ * `alex.sui`-style recipients. SSOT: never let preview and execute
139873
+ * resolve the same input differently.
139874
+ */
139875
+ async resolveRecipient(input) {
139876
+ const trimmed = input.trim();
139877
+ if (SUI_ADDRESS_REGEX.test(trimmed)) {
139878
+ return { address: trimmed.toLowerCase() };
139879
+ }
139880
+ if (looksLikeSuiNs(trimmed)) {
139881
+ try {
139882
+ const name = trimmed.toLowerCase();
139883
+ const address2 = await resolveSuinsViaRpc(name);
139884
+ if (!address2) {
139885
+ throw new SuinsNotRegisteredError(name);
139886
+ }
139887
+ return { address: address2.toLowerCase(), suinsName: name };
139888
+ } catch (err) {
139889
+ if (err instanceof SuinsNotRegisteredError) {
139890
+ throw new T2000Error(
139891
+ "SUINS_NOT_REGISTERED",
139892
+ err.message
139893
+ );
139894
+ }
139895
+ throw err;
139896
+ }
139897
+ }
139898
+ return this.contacts.resolve(input);
139899
+ }
139766
139900
  async balance() {
139767
139901
  const bal = await queryBalance(this.client, this._address);
139768
139902
  let chainTotal = bal.available + bal.gasReserve.usdEquiv;
@@ -140862,7 +140996,7 @@ Call t2000_services first to discover the right endpoint, then t2000_pay to exec
140862
140996
  );
140863
140997
  server.tool(
140864
140998
  "t2000_contacts",
140865
- "List saved contacts (name \u2192 address mappings). Use contact names with t2000_send instead of raw addresses. Use t2000_contact_add to save new contacts.",
140999
+ "DEPRECATED \u2014 List saved local contacts (~/.t2000/contacts.json name \u2192 address mappings). The local contact map is being sunset; the canonical name system is SuiNS (e.g. alex.sui \u2014 resolved by t2000_send automatically). This tool will be removed in the next major SDK release. Prefer pasting 0x addresses or using SuiNS names directly with t2000_send.",
140866
141000
  {},
140867
141001
  async () => {
140868
141002
  try {
@@ -140911,16 +141045,16 @@ function registerWriteTools(server, agent) {
140911
141045
  const mutex = new TxMutex();
140912
141046
  server.tool(
140913
141047
  "t2000_send",
140914
- "Send USDC to a Sui address or contact name. Amount is in dollars. Subject to per-transaction and daily send limits. Set dryRun: true to preview without signing.",
141048
+ "Send USDC (or another supported asset) to a 0x Sui address, a SuiNS name (e.g. alex.sui), or a saved contact alias. Amount is in dollars. Subject to per-transaction and daily send limits. Set dryRun: true to preview without signing. SuiNS is the preferred name path; saved contacts (~/.t2000/contacts.json) are deprecated and will be removed in the next major SDK release.",
140915
141049
  {
140916
- to: external_exports.string().describe("Recipient Sui address (0x...) or contact name (e.g. 'Tom')"),
141050
+ to: external_exports.string().describe("Recipient: 0x Sui address, SuiNS name like 'alex.sui', or saved contact name. SuiNS preferred; contact aliases are deprecated."),
140917
141051
  amount: external_exports.number().describe("Amount in dollars to send"),
140918
141052
  asset: external_exports.string().optional().describe("Asset to send (default: USDC)"),
140919
141053
  dryRun: external_exports.boolean().optional().describe("Preview without signing (default: false)")
140920
141054
  },
140921
141055
  async ({ to: to2, amount: amount2, asset, dryRun }) => {
140922
141056
  try {
140923
- const resolved = agent.contacts.resolve(to2);
141057
+ const resolved = await agent.resolveRecipient(to2);
140924
141058
  if (dryRun) {
140925
141059
  agent.enforcer.check({ operation: "send", amount: amount2 });
140926
141060
  const balance = await agent.balance();
@@ -140934,6 +141068,7 @@ function registerWriteTools(server, agent) {
140934
141068
  amount: amount2,
140935
141069
  to: resolved.address,
140936
141070
  contactName: resolved.contactName,
141071
+ suinsName: resolved.suinsName,
140937
141072
  asset: asset ?? "USDC",
140938
141073
  currentBalance: balance.available,
140939
141074
  balanceAfter: balance.available - amount2,
@@ -141224,7 +141359,7 @@ ${text}`;
141224
141359
  );
141225
141360
  server.tool(
141226
141361
  "t2000_contact_add",
141227
- 'Save a contact name \u2192 Sui address mapping. After saving, use the name with t2000_send instead of pasting addresses. Example: save "Tom" as 0x1234... then send to "Tom".',
141362
+ "DEPRECATED \u2014 Save a contact name \u2192 Sui address mapping to ~/.t2000/contacts.json. The local-file contact map is being sunset; the canonical name system is SuiNS (register your-name.sui at https://suins.io once and every Sui app resolves it). Use this tool only if the recipient has no SuiNS name AND you need a memorable local alias. Will be removed in the next major SDK release.",
141228
141363
  {
141229
141364
  name: external_exports.string().describe('Contact name (e.g. "Tom", "Alice")'),
141230
141365
  address: external_exports.string().describe("Sui wallet address (0x...)")
@@ -141240,7 +141375,7 @@ ${text}`;
141240
141375
  );
141241
141376
  server.tool(
141242
141377
  "t2000_contact_remove",
141243
- "Remove a saved contact by name.",
141378
+ "DEPRECATED \u2014 Remove a saved local contact by name. The local-file contact map is being sunset; will be removed entirely in the next major SDK release.",
141244
141379
  {
141245
141380
  name: external_exports.string().describe("Contact name to remove")
141246
141381
  },
@@ -142008,7 +142143,7 @@ ${context}
142008
142143
  })
142009
142144
  );
142010
142145
  }
142011
- var PKG_VERSION = "2.18.1";
142146
+ var PKG_VERSION = "2.19.1";
142012
142147
  console.log = (...args) => console.error("[log]", ...args);
142013
142148
  console.warn = (...args) => console.error("[warn]", ...args);
142014
142149
  async function startMcpServer(opts) {
@@ -142099,4 +142234,4 @@ axios/dist/node/axios.cjs:
142099
142234
  @scure/bip39/index.js:
142100
142235
  (*! scure-bip39 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
142101
142236
  */
142102
- //# sourceMappingURL=dist-APKOY2VV.js.map
142237
+ //# sourceMappingURL=dist-EUGE6UAA.js.map