@t2000/cli 10.26.0 → 10.27.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.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { createRequire as __createRequire } from 'module'; import { fileURLToPat
3
3
  import {
4
4
  AggregatorClient,
5
5
  Env
6
- } from "./chunk-PRKQVMED.js";
6
+ } from "./chunk-TVD4WMBT.js";
7
7
  import {
8
8
  BalanceChange,
9
9
  BaseClient,
@@ -16,11 +16,11 @@ import {
16
16
  parseTransactionEffectsBcs,
17
17
  transactionDataToGrpcTransaction,
18
18
  transactionToGrpcJson
19
- } from "./chunk-R6QER65C.js";
19
+ } from "./chunk-SHZC6TMU.js";
20
20
  import {
21
21
  Transaction,
22
22
  coinWithBalance
23
- } from "./chunk-JEIOQF6Q.js";
23
+ } from "./chunk-CNTCUDEZ.js";
24
24
  import {
25
25
  ObjectError,
26
26
  SUI_TYPE_ARG,
@@ -31,7 +31,7 @@ import {
31
31
  fromBase64 as fromBase642,
32
32
  suiBcs,
33
33
  toBase64 as toBase642
34
- } from "./chunk-5MAY6SK7.js";
34
+ } from "./chunk-T32A4PV6.js";
35
35
  import {
36
36
  SIGNATURE_FLAG_TO_SCHEME,
37
37
  SIGNATURE_SCHEME_TO_FLAG,
@@ -79,7 +79,7 @@ import {
79
79
  split,
80
80
  toBase64,
81
81
  toHex
82
- } from "./chunk-D3DUYZYR.js";
82
+ } from "./chunk-BX4V52TZ.js";
83
83
  import {
84
84
  require_bn,
85
85
  require_safer
@@ -3390,79 +3390,6 @@ var require_commander = __commonJS({
3390
3390
  }
3391
3391
  });
3392
3392
 
3393
- // ../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js
3394
- var require_picocolors = __commonJS({
3395
- "../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js"(exports, module) {
3396
- "use strict";
3397
- var p = process || {};
3398
- var argv = p.argv || [];
3399
- var env = p.env || {};
3400
- var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
3401
- var formatter = (open, close, replace = open) => (input) => {
3402
- let string = "" + input, index = string.indexOf(close, open.length);
3403
- return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
3404
- };
3405
- var replaceClose = (string, close, replace, index) => {
3406
- let result = "", cursor = 0;
3407
- do {
3408
- result += string.substring(cursor, index) + replace;
3409
- cursor = index + close.length;
3410
- index = string.indexOf(close, cursor);
3411
- } while (~index);
3412
- return result + string.substring(cursor);
3413
- };
3414
- var createColors = (enabled = isColorSupported) => {
3415
- let f = enabled ? formatter : () => String;
3416
- return {
3417
- isColorSupported: enabled,
3418
- reset: f("\x1B[0m", "\x1B[0m"),
3419
- bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
3420
- dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
3421
- italic: f("\x1B[3m", "\x1B[23m"),
3422
- underline: f("\x1B[4m", "\x1B[24m"),
3423
- inverse: f("\x1B[7m", "\x1B[27m"),
3424
- hidden: f("\x1B[8m", "\x1B[28m"),
3425
- strikethrough: f("\x1B[9m", "\x1B[29m"),
3426
- black: f("\x1B[30m", "\x1B[39m"),
3427
- red: f("\x1B[31m", "\x1B[39m"),
3428
- green: f("\x1B[32m", "\x1B[39m"),
3429
- yellow: f("\x1B[33m", "\x1B[39m"),
3430
- blue: f("\x1B[34m", "\x1B[39m"),
3431
- magenta: f("\x1B[35m", "\x1B[39m"),
3432
- cyan: f("\x1B[36m", "\x1B[39m"),
3433
- white: f("\x1B[37m", "\x1B[39m"),
3434
- gray: f("\x1B[90m", "\x1B[39m"),
3435
- bgBlack: f("\x1B[40m", "\x1B[49m"),
3436
- bgRed: f("\x1B[41m", "\x1B[49m"),
3437
- bgGreen: f("\x1B[42m", "\x1B[49m"),
3438
- bgYellow: f("\x1B[43m", "\x1B[49m"),
3439
- bgBlue: f("\x1B[44m", "\x1B[49m"),
3440
- bgMagenta: f("\x1B[45m", "\x1B[49m"),
3441
- bgCyan: f("\x1B[46m", "\x1B[49m"),
3442
- bgWhite: f("\x1B[47m", "\x1B[49m"),
3443
- blackBright: f("\x1B[90m", "\x1B[39m"),
3444
- redBright: f("\x1B[91m", "\x1B[39m"),
3445
- greenBright: f("\x1B[92m", "\x1B[39m"),
3446
- yellowBright: f("\x1B[93m", "\x1B[39m"),
3447
- blueBright: f("\x1B[94m", "\x1B[39m"),
3448
- magentaBright: f("\x1B[95m", "\x1B[39m"),
3449
- cyanBright: f("\x1B[96m", "\x1B[39m"),
3450
- whiteBright: f("\x1B[97m", "\x1B[39m"),
3451
- bgBlackBright: f("\x1B[100m", "\x1B[49m"),
3452
- bgRedBright: f("\x1B[101m", "\x1B[49m"),
3453
- bgGreenBright: f("\x1B[102m", "\x1B[49m"),
3454
- bgYellowBright: f("\x1B[103m", "\x1B[49m"),
3455
- bgBlueBright: f("\x1B[104m", "\x1B[49m"),
3456
- bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
3457
- bgCyanBright: f("\x1B[106m", "\x1B[49m"),
3458
- bgWhiteBright: f("\x1B[107m", "\x1B[49m")
3459
- };
3460
- };
3461
- module.exports = createColors();
3462
- module.exports.createColors = createColors;
3463
- }
3464
- });
3465
-
3466
3393
  // ../../node_modules/.pnpm/eventemitter3@5.0.4/node_modules/eventemitter3/index.js
3467
3394
  var require_eventemitter3 = __commonJS({
3468
3395
  "../../node_modules/.pnpm/eventemitter3@5.0.4/node_modules/eventemitter3/index.js"(exports, module) {
@@ -3625,6 +3552,79 @@ var require_eventemitter3 = __commonJS({
3625
3552
  }
3626
3553
  });
3627
3554
 
3555
+ // ../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js
3556
+ var require_picocolors = __commonJS({
3557
+ "../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js"(exports, module) {
3558
+ "use strict";
3559
+ var p = process || {};
3560
+ var argv = p.argv || [];
3561
+ var env = p.env || {};
3562
+ var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
3563
+ var formatter = (open, close, replace = open) => (input) => {
3564
+ let string = "" + input, index = string.indexOf(close, open.length);
3565
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
3566
+ };
3567
+ var replaceClose = (string, close, replace, index) => {
3568
+ let result = "", cursor = 0;
3569
+ do {
3570
+ result += string.substring(cursor, index) + replace;
3571
+ cursor = index + close.length;
3572
+ index = string.indexOf(close, cursor);
3573
+ } while (~index);
3574
+ return result + string.substring(cursor);
3575
+ };
3576
+ var createColors = (enabled = isColorSupported) => {
3577
+ let f = enabled ? formatter : () => String;
3578
+ return {
3579
+ isColorSupported: enabled,
3580
+ reset: f("\x1B[0m", "\x1B[0m"),
3581
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
3582
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
3583
+ italic: f("\x1B[3m", "\x1B[23m"),
3584
+ underline: f("\x1B[4m", "\x1B[24m"),
3585
+ inverse: f("\x1B[7m", "\x1B[27m"),
3586
+ hidden: f("\x1B[8m", "\x1B[28m"),
3587
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
3588
+ black: f("\x1B[30m", "\x1B[39m"),
3589
+ red: f("\x1B[31m", "\x1B[39m"),
3590
+ green: f("\x1B[32m", "\x1B[39m"),
3591
+ yellow: f("\x1B[33m", "\x1B[39m"),
3592
+ blue: f("\x1B[34m", "\x1B[39m"),
3593
+ magenta: f("\x1B[35m", "\x1B[39m"),
3594
+ cyan: f("\x1B[36m", "\x1B[39m"),
3595
+ white: f("\x1B[37m", "\x1B[39m"),
3596
+ gray: f("\x1B[90m", "\x1B[39m"),
3597
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
3598
+ bgRed: f("\x1B[41m", "\x1B[49m"),
3599
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
3600
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
3601
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
3602
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
3603
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
3604
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
3605
+ blackBright: f("\x1B[90m", "\x1B[39m"),
3606
+ redBright: f("\x1B[91m", "\x1B[39m"),
3607
+ greenBright: f("\x1B[92m", "\x1B[39m"),
3608
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
3609
+ blueBright: f("\x1B[94m", "\x1B[39m"),
3610
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
3611
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
3612
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
3613
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
3614
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
3615
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
3616
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
3617
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
3618
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
3619
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
3620
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
3621
+ };
3622
+ };
3623
+ module.exports = createColors();
3624
+ module.exports.createColors = createColors;
3625
+ }
3626
+ });
3627
+
3628
3628
  // ../../node_modules/.pnpm/yoctocolors-cjs@2.1.3/node_modules/yoctocolors-cjs/index.js
3629
3629
  var require_yoctocolors_cjs = __commonJS({
3630
3630
  "../../node_modules/.pnpm/yoctocolors-cjs@2.1.3/node_modules/yoctocolors-cjs/index.js"(exports, module) {
@@ -19144,80 +19144,6 @@ var {
19144
19144
  Help
19145
19145
  } = import_index.default;
19146
19146
 
19147
- // src/program.ts
19148
- import { createRequire as createRequire2 } from "module";
19149
-
19150
- // src/output.ts
19151
- var import_picocolors = __toESM(require_picocolors(), 1);
19152
- var jsonMode = false;
19153
- function setJsonMode(enabled) {
19154
- jsonMode = enabled;
19155
- }
19156
- function isJsonMode() {
19157
- return jsonMode;
19158
- }
19159
- function printJson(data) {
19160
- console.log(JSON.stringify(data, null, 2));
19161
- }
19162
- function printSuccess(message) {
19163
- if (jsonMode) return;
19164
- console.log(` ${import_picocolors.default.green("\u2713")} ${message}`);
19165
- }
19166
- function printError(message) {
19167
- if (jsonMode) return;
19168
- console.error(` ${import_picocolors.default.red("\u2717")} ${message}`);
19169
- }
19170
- function printWarning(message) {
19171
- if (jsonMode) return;
19172
- console.log(` ${import_picocolors.default.yellow("\u26A0")} ${message}`);
19173
- }
19174
- function printInfo(message) {
19175
- if (jsonMode) return;
19176
- console.log(` ${import_picocolors.default.dim(message)}`);
19177
- }
19178
- function printHeader(title) {
19179
- if (jsonMode) return;
19180
- console.log();
19181
- console.log(` ${import_picocolors.default.bold(title)}`);
19182
- console.log();
19183
- }
19184
- function printKeyValue(key, value, indent2 = 2) {
19185
- if (jsonMode) return;
19186
- const pad = " ".repeat(indent2);
19187
- console.log(`${pad}${import_picocolors.default.dim(key + ":")} ${value}`);
19188
- }
19189
- function printBlank() {
19190
- if (jsonMode) return;
19191
- console.log();
19192
- }
19193
- function printDivider(width = 53) {
19194
- if (jsonMode) return;
19195
- console.log(` ${import_picocolors.default.dim("\u2500".repeat(width))}`);
19196
- }
19197
- function printLine(text) {
19198
- if (jsonMode) return;
19199
- console.log(` ${text}`);
19200
- }
19201
- function printSeparator() {
19202
- if (jsonMode) return;
19203
- console.log(` ${import_picocolors.default.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}`);
19204
- }
19205
- function explorerUrl(txHash, network = "mainnet") {
19206
- const base = network === "testnet" ? "https://suiscan.xyz/testnet/tx" : "https://suiscan.xyz/mainnet/tx";
19207
- const suffix = "";
19208
- return `${base}/${txHash}${suffix}`;
19209
- }
19210
- function handleError(error) {
19211
- if (jsonMode) {
19212
- const data = error instanceof Error && "toJSON" in error ? error.toJSON() : { error: "UNKNOWN", message: String(error) };
19213
- printJson(data);
19214
- } else {
19215
- const msg = error instanceof Error ? error.message : String(error);
19216
- printError(msg);
19217
- }
19218
- process.exit(1);
19219
- }
19220
-
19221
19147
  // ../sdk/dist/index.js
19222
19148
  var import_bn = __toESM(require_bn(), 1);
19223
19149
 
@@ -28638,7 +28564,7 @@ async function probeX402(args) {
28638
28564
  BigInt(requirements.maxAmountRequired),
28639
28565
  await assetDecimals(requirements.asset)
28640
28566
  );
28641
- const { isX402EscrowRequirements } = await import("./dist-VUHPQJYY.js");
28567
+ const { isX402EscrowRequirements } = await import("./dist-RTAF2SWN.js");
28642
28568
  if (isX402EscrowRequirements(requirements)) {
28643
28569
  return {
28644
28570
  kind: "escrow",
@@ -28709,7 +28635,7 @@ async function payWithX402(args) {
28709
28635
  const pick = await pickSuiExactRequirements(probe, client.network);
28710
28636
  if (pick.kind === "payable") {
28711
28637
  const requirements = pick.requirements;
28712
- const { isX402EscrowRequirements } = await import("./dist-VUHPQJYY.js");
28638
+ const { isX402EscrowRequirements } = await import("./dist-RTAF2SWN.js");
28713
28639
  if (isX402EscrowRequirements(requirements)) {
28714
28640
  const escrow = requirements.extra.escrow;
28715
28641
  const price = atomicToHuman(
@@ -28755,7 +28681,7 @@ async function pickSuiExactRequirements(response, network) {
28755
28681
  const want = `sui:${network === "testnet" ? "testnet" : "mainnet"}`;
28756
28682
  const entry = body2.accepts?.find((a) => a.scheme === "exact" && a.network === want);
28757
28683
  if (!entry) return { kind: "none" };
28758
- const { isX402EscrowRequirements } = await import("./dist-VUHPQJYY.js");
28684
+ const { isX402EscrowRequirements } = await import("./dist-RTAF2SWN.js");
28759
28685
  if (hasCompleteSuimppChallenge(entry) || isX402EscrowRequirements(entry)) {
28760
28686
  return { kind: "payable", requirements: entry };
28761
28687
  }
@@ -28773,7 +28699,7 @@ async function payViaX402(args) {
28773
28699
  { reason: "incomplete-x402-accepts" }
28774
28700
  );
28775
28701
  }
28776
- const { buildX402SignedPayment, X402_PAYMENT_HEADER, X402_PAYMENT_RESPONSE_HEADER } = await import("./dist-VUHPQJYY.js");
28702
+ const { buildX402SignedPayment, X402_PAYMENT_HEADER, X402_PAYMENT_RESPONSE_HEADER } = await import("./dist-RTAF2SWN.js");
28777
28703
  const amountRaw = BigInt(requirements.maxAmountRequired);
28778
28704
  assertWithinMaxPrice(atomicToHuman(amountRaw, await assetDecimals(requirements.asset)), options.maxPrice);
28779
28705
  const migrationGasSui = await ensureAddressBalanceCovers({
@@ -28904,7 +28830,7 @@ async function finalize(response, opts) {
28904
28830
  return { status: response.status, body: body2, paid: opts.paid };
28905
28831
  }
28906
28832
  async function makeGrpcBuildClient(client) {
28907
- const { SuiGrpcClient: SuiGrpcClient3 } = await import("./grpc-G3RQE2L5.js");
28833
+ const { SuiGrpcClient: SuiGrpcClient3 } = await import("./grpc-AJNSMQ2Y.js");
28908
28834
  const network = client.network === "testnet" ? "testnet" : "mainnet";
28909
28835
  const baseUrl = network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
28910
28836
  return new SuiGrpcClient3({ baseUrl, network });
@@ -28933,7 +28859,7 @@ var ZkLoginSigner = class {
28933
28859
  return this.userAddress;
28934
28860
  }
28935
28861
  async signTransaction(txBytes) {
28936
- const { getZkLoginSignature } = await import("./esm-ZKAIHFAJ.js");
28862
+ const { getZkLoginSignature } = await import("./esm-JVUVZX3G.js");
28937
28863
  const ephSig = await this.ephemeralKeypair.signTransaction(txBytes);
28938
28864
  return {
28939
28865
  signature: getZkLoginSignature({
@@ -28944,7 +28870,7 @@ var ZkLoginSigner = class {
28944
28870
  };
28945
28871
  }
28946
28872
  async signPersonalMessage(messageBytes) {
28947
- const { getZkLoginSignature } = await import("./esm-ZKAIHFAJ.js");
28873
+ const { getZkLoginSignature } = await import("./esm-JVUVZX3G.js");
28948
28874
  const { signature: ephSig, bytes } = await this.ephemeralKeypair.signPersonalMessage(messageBytes);
28949
28875
  return {
28950
28876
  signature: getZkLoginSignature({
@@ -30609,14 +30535,18 @@ init_coinSelection();
30609
30535
  init_errors();
30610
30536
  init_token_registry();
30611
30537
  init_coinSelection();
30612
- var A2A_ESCROW_OPENING_PACKAGE_ID = process.env.A2A_ESCROW_OPENING_PACKAGE_ID ?? "0x69ad93c555519de520a5c7f7f2963ad6f8b91cefc098fc2eed75942dcb5bcbe7";
30613
- var A2A_ESCROW_PACKAGE_ID = process.env.A2A_ESCROW_PACKAGE_ID ?? "0x358a819c1c016e2cc84ef5fbea81cba90c31f7f8a62bf45cb5e5276acf198bdd";
30538
+ var MAINNET_A2A_ESCROW_OPENING_PACKAGE_ID = "0x69ad93c555519de520a5c7f7f2963ad6f8b91cefc098fc2eed75942dcb5bcbe7";
30539
+ var A2A_ESCROW_OPENING_PACKAGE_ID = process.env.A2A_ESCROW_OPENING_PACKAGE_ID ?? MAINNET_A2A_ESCROW_OPENING_PACKAGE_ID;
30540
+ var MAINNET_A2A_ESCROW_PACKAGE_ID = "0x358a819c1c016e2cc84ef5fbea81cba90c31f7f8a62bf45cb5e5276acf198bdd";
30541
+ var A2A_ESCROW_PACKAGE_ID = process.env.A2A_ESCROW_PACKAGE_ID ?? MAINNET_A2A_ESCROW_PACKAGE_ID;
30614
30542
  var A2A_ESCROW_FEE_CONFIG_ID = process.env.A2A_ESCROW_FEE_CONFIG_ID ?? "0xddaa25570950b7484dbf20797ebcf75707be9c87cd67bef2a06ed2e81d2c494b";
30615
30543
  var A2A_ESCROW_FEE_CONFIG_VERSION = Number(
30616
30544
  process.env.A2A_ESCROW_FEE_CONFIG_VERSION ?? 931861903
30617
30545
  );
30618
30546
  var MODULE2 = "escrow";
30619
30547
  var MAX_JOB_USDC = 50;
30548
+ var MAX_REVIEW_WINDOW_MS = 2592e6;
30549
+ var MAX_DELIVER_HORIZON_MS = 31536e6;
30620
30550
  var JOB_STATES = [
30621
30551
  "funded",
30622
30552
  "delivered",
@@ -30624,12 +30554,57 @@ var JOB_STATES = [
30624
30554
  "refunded",
30625
30555
  "rejected"
30626
30556
  ];
30557
+ function hexToBytes3(hex) {
30558
+ const clean4 = hex.startsWith("0x") ? hex.slice(2) : hex;
30559
+ if (clean4.length === 0 || clean4.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean4)) {
30560
+ throw new T2000Error(
30561
+ "INVALID_AMOUNT",
30562
+ `Expected a hex hash (0x\u2026), got "${hex.slice(0, 32)}"`
30563
+ );
30564
+ }
30565
+ const out = [];
30566
+ for (let i = 0; i < clean4.length; i += 2) {
30567
+ out.push(Number.parseInt(clean4.slice(i, i + 2), 16));
30568
+ }
30569
+ return out;
30570
+ }
30627
30571
  function bytesToHex3(bytes) {
30628
30572
  const arr = typeof bytes === "string" ? Array.from(atob(bytes), (c) => c.charCodeAt(0)) : bytes;
30629
30573
  let s = "0x";
30630
30574
  for (const b of arr) s += b.toString(16).padStart(2, "0");
30631
30575
  return s;
30632
30576
  }
30577
+ function preflightCreateJob(terms) {
30578
+ const addressCheck = checkSuiAddress(terms.seller);
30579
+ if (!addressCheck.valid) return addressCheck;
30580
+ if (!Number.isFinite(terms.amountUsdc) || terms.amountUsdc <= 0) {
30581
+ return preflightFail("INVALID_AMOUNT", `Amount must be positive. Got ${terms.amountUsdc}.`);
30582
+ }
30583
+ if (terms.amountUsdc > MAX_JOB_USDC) {
30584
+ return preflightFail(
30585
+ "INVALID_AMOUNT",
30586
+ `v1 caps escrow jobs at ${MAX_JOB_USDC} USDC (no-arbitration split only stays fair at small sizes). Got ${terms.amountUsdc}.`
30587
+ );
30588
+ }
30589
+ if (terms.deliverByMs <= Date.now()) {
30590
+ return preflightFail("INVALID_AMOUNT", "deliverByMs must be in the future.");
30591
+ }
30592
+ if (terms.deliverByMs > Date.now() + MAX_DELIVER_HORIZON_MS) {
30593
+ return preflightFail("INVALID_AMOUNT", "deliverByMs is more than 365 days out.");
30594
+ }
30595
+ if (terms.reviewWindowMs < 0 || terms.reviewWindowMs > MAX_REVIEW_WINDOW_MS) {
30596
+ return preflightFail("INVALID_AMOUNT", "reviewWindowMs must be 0\u201330 days.");
30597
+ }
30598
+ if (!Number.isInteger(terms.rejectSplitBps) || terms.rejectSplitBps < 0 || terms.rejectSplitBps > 1e4) {
30599
+ return preflightFail("INVALID_AMOUNT", "rejectSplitBps must be an integer 0\u201310000.");
30600
+ }
30601
+ try {
30602
+ hexToBytes3(terms.specHash);
30603
+ } catch (e) {
30604
+ return preflightFail("INVALID_AMOUNT", e.message);
30605
+ }
30606
+ return PREFLIGHT_OK;
30607
+ }
30633
30608
  async function getJob(client, jobId) {
30634
30609
  const resp = await client.core.getObject({ objectId: jobId, include: { json: true } }).catch((e) => {
30635
30610
  throw new T2000Error(
@@ -30849,6 +30824,10 @@ async function fetchJson(url, init) {
30849
30824
  }
30850
30825
  return json;
30851
30826
  }
30827
+ var sponsoredTxGuard = null;
30828
+ function setSponsoredTxGuard(guard) {
30829
+ sponsoredTxGuard = guard;
30830
+ }
30852
30831
  async function listOpenJobs(base, filter = {}) {
30853
30832
  const params = new URLSearchParams();
30854
30833
  if (filter.status) params.set("status", filter.status);
@@ -30861,6 +30840,7 @@ async function listOpenJobs(base, filter = {}) {
30861
30840
  }
30862
30841
  async function sponsoredOpeningVerb(base, signer, action, params) {
30863
30842
  const address = signer.getAddress();
30843
+ sponsoredTxGuard?.({ base, action });
30864
30844
  const prep = await fetchJson(`${base}/job/prepare`, {
30865
30845
  method: "POST",
30866
30846
  body: { address, action, params }
@@ -30870,6 +30850,7 @@ async function sponsoredOpeningVerb(base, signer, action, params) {
30870
30850
  if (!(nonce && txBytes)) {
30871
30851
  throw new Error("Failed to prepare the transaction.");
30872
30852
  }
30853
+ sponsoredTxGuard?.({ base, action, txBytes });
30873
30854
  const { signature } = await signer.signTransaction(fromBase64(txBytes));
30874
30855
  const json = await fetchJson(`${base}/job/submit`, {
30875
30856
  method: "POST",
@@ -30920,6 +30901,247 @@ init_cetus_swap();
30920
30901
  init_token_registry();
30921
30902
  init_preflight();
30922
30903
 
30904
+ // src/lib/tx-guard.ts
30905
+ var CANONICAL_API_ORIGIN = "https://api.t2000.ai";
30906
+ var ALLOW_UNTRUSTED_FLAG = "--allow-untrusted-api";
30907
+ var ACTION_TARGETS = {
30908
+ // v1 escrow package.
30909
+ create: {
30910
+ pkg: MAINNET_A2A_ESCROW_PACKAGE_ID,
30911
+ module: "escrow",
30912
+ functions: ["create"]
30913
+ },
30914
+ deliver: {
30915
+ pkg: MAINNET_A2A_ESCROW_PACKAGE_ID,
30916
+ module: "escrow",
30917
+ functions: ["deliver"]
30918
+ },
30919
+ release: {
30920
+ pkg: MAINNET_A2A_ESCROW_PACKAGE_ID,
30921
+ module: "escrow",
30922
+ functions: ["release"]
30923
+ },
30924
+ reject: {
30925
+ pkg: MAINNET_A2A_ESCROW_PACKAGE_ID,
30926
+ module: "escrow",
30927
+ functions: ["reject"]
30928
+ },
30929
+ refund: {
30930
+ pkg: MAINNET_A2A_ESCROW_PACKAGE_ID,
30931
+ module: "escrow",
30932
+ functions: ["refund"]
30933
+ },
30934
+ // v3 opening package — note the `escrow` module.
30935
+ decline: {
30936
+ pkg: MAINNET_A2A_ESCROW_OPENING_PACKAGE_ID,
30937
+ module: "escrow",
30938
+ functions: ["decline"]
30939
+ },
30940
+ // Open board.
30941
+ "open-create": {
30942
+ pkg: MAINNET_A2A_ESCROW_OPENING_PACKAGE_ID,
30943
+ module: "opening",
30944
+ functions: ["create_open"]
30945
+ },
30946
+ "open-claim": {
30947
+ pkg: MAINNET_A2A_ESCROW_OPENING_PACKAGE_ID,
30948
+ module: "opening",
30949
+ functions: ["claim"]
30950
+ },
30951
+ "open-cancel": {
30952
+ pkg: MAINNET_A2A_ESCROW_OPENING_PACKAGE_ID,
30953
+ module: "opening",
30954
+ functions: ["cancel_open"]
30955
+ },
30956
+ "open-refund": {
30957
+ pkg: MAINNET_A2A_ESCROW_OPENING_PACKAGE_ID,
30958
+ module: "opening",
30959
+ functions: ["refund_unclaimed"]
30960
+ }
30961
+ };
30962
+ var HOST_PINNED_ONLY = /* @__PURE__ */ new Set(["register", "link", "confirm"]);
30963
+ var allowUntrustedApi = false;
30964
+ function setAllowUntrustedApi(value) {
30965
+ allowUntrustedApi = value;
30966
+ }
30967
+ function isAllowUntrustedApi() {
30968
+ return allowUntrustedApi;
30969
+ }
30970
+ var UntrustedHostError = class extends Error {
30971
+ };
30972
+ var IntentMismatchError = class extends Error {
30973
+ };
30974
+ function apiOrigin(base) {
30975
+ try {
30976
+ return new URL(base).origin;
30977
+ } catch {
30978
+ return base;
30979
+ }
30980
+ }
30981
+ function isDefaultApiHost(base) {
30982
+ return apiOrigin(base) === CANONICAL_API_ORIGIN;
30983
+ }
30984
+ function assertSigningHostAllowed(base, allowUntrusted) {
30985
+ if (isDefaultApiHost(base) || allowUntrusted) {
30986
+ return;
30987
+ }
30988
+ throw new UntrustedHostError(
30989
+ `Refusing to sign transactions built by ${apiOrigin(base)}.
30990
+ Only ${CANONICAL_API_ORIGIN} is trusted by default. If you really mean to use
30991
+ another host (a local or staging API), re-run with ${ALLOW_UNTRUSTED_FLAG}.
30992
+ If you did not set T2000_API_URL or --api yourself, treat this as an attack.`
30993
+ );
30994
+ }
30995
+ function assertTxMatchesIntent(txBytes, intent, opts = {}) {
30996
+ if (opts.allowUntrusted) {
30997
+ return;
30998
+ }
30999
+ if (HOST_PINNED_ONLY.has(intent.action)) {
31000
+ return;
31001
+ }
31002
+ const expected = ACTION_TARGETS[intent.action];
31003
+ if (!expected) {
31004
+ throw new IntentMismatchError(
31005
+ `Refusing to sign: "${intent.action}" is not a verb this wallet knows how to verify.`
31006
+ );
31007
+ }
31008
+ let calls;
31009
+ try {
31010
+ const tx = Transaction.from(
31011
+ new Uint8Array(Buffer.from(txBytes, "base64"))
31012
+ );
31013
+ calls = tx.getData().commands.flatMap(
31014
+ (c) => c.$kind === "MoveCall" && c.MoveCall ? [
31015
+ {
31016
+ pkg: c.MoveCall.package,
31017
+ module: c.MoveCall.module,
31018
+ fn: c.MoveCall.function
31019
+ }
31020
+ ] : []
31021
+ );
31022
+ } catch (e) {
31023
+ throw new IntentMismatchError(
31024
+ `Refusing to sign: could not decode the prepared transaction (${e instanceof Error ? e.message : "unreadable"}).`
31025
+ );
31026
+ }
31027
+ if (calls.length === 0) {
31028
+ throw new IntentMismatchError(
31029
+ "Refusing to sign: the prepared transaction contains no Move calls."
31030
+ );
31031
+ }
31032
+ for (const call of calls) {
31033
+ if (call.pkg !== expected.pkg) {
31034
+ throw new IntentMismatchError(
31035
+ `Refusing to sign: "${intent.action}" targets package ${expected.pkg}, but the transaction calls ${call.pkg}.`
31036
+ );
31037
+ }
31038
+ if (call.module !== expected.module) {
31039
+ throw new IntentMismatchError(
31040
+ `Refusing to sign: "${intent.action}" should call ${expected.module}, but the transaction calls ${call.module}.`
31041
+ );
31042
+ }
31043
+ if (!expected.functions.includes(call.fn)) {
31044
+ throw new IntentMismatchError(
31045
+ `Refusing to sign: "${intent.action}" should call ${expected.module}::${expected.functions.join("|")}, but the transaction calls ${call.module}::${call.fn}.`
31046
+ );
31047
+ }
31048
+ }
31049
+ }
31050
+ function describeIntent(intent, base) {
31051
+ const bits = [intent.action];
31052
+ if (intent.amountUsdc !== void 0) {
31053
+ bits.push(`$${intent.amountUsdc}`);
31054
+ }
31055
+ if (intent.seller) {
31056
+ bits.push(`\u2192 ${intent.seller.slice(0, 6)}\u2026${intent.seller.slice(-4)}`);
31057
+ }
31058
+ return `About to sign: ${bits.join(" ")} (${apiOrigin(base).replace("https://", "")})`;
31059
+ }
31060
+ function installSponsoredTxGuard() {
31061
+ setSponsoredTxGuard(({ base, action, txBytes }) => {
31062
+ const allowUntrusted = isAllowUntrustedApi();
31063
+ if (txBytes === void 0) {
31064
+ assertSigningHostAllowed(base, allowUntrusted);
31065
+ return;
31066
+ }
31067
+ assertTxMatchesIntent(txBytes, { action }, { allowUntrusted });
31068
+ });
31069
+ }
31070
+
31071
+ // src/program.ts
31072
+ import { createRequire as createRequire2 } from "module";
31073
+
31074
+ // src/output.ts
31075
+ var import_picocolors = __toESM(require_picocolors(), 1);
31076
+ var jsonMode = false;
31077
+ function setJsonMode(enabled) {
31078
+ jsonMode = enabled;
31079
+ }
31080
+ function isJsonMode() {
31081
+ return jsonMode;
31082
+ }
31083
+ function printJson(data) {
31084
+ console.log(JSON.stringify(data, null, 2));
31085
+ }
31086
+ function printSuccess(message) {
31087
+ if (jsonMode) return;
31088
+ console.log(` ${import_picocolors.default.green("\u2713")} ${message}`);
31089
+ }
31090
+ function printError(message) {
31091
+ if (jsonMode) return;
31092
+ console.error(` ${import_picocolors.default.red("\u2717")} ${message}`);
31093
+ }
31094
+ function printWarning(message) {
31095
+ if (jsonMode) return;
31096
+ console.log(` ${import_picocolors.default.yellow("\u26A0")} ${message}`);
31097
+ }
31098
+ function printInfo(message) {
31099
+ if (jsonMode) return;
31100
+ console.log(` ${import_picocolors.default.dim(message)}`);
31101
+ }
31102
+ function printHeader(title) {
31103
+ if (jsonMode) return;
31104
+ console.log();
31105
+ console.log(` ${import_picocolors.default.bold(title)}`);
31106
+ console.log();
31107
+ }
31108
+ function printKeyValue(key, value, indent2 = 2) {
31109
+ if (jsonMode) return;
31110
+ const pad = " ".repeat(indent2);
31111
+ console.log(`${pad}${import_picocolors.default.dim(key + ":")} ${value}`);
31112
+ }
31113
+ function printBlank() {
31114
+ if (jsonMode) return;
31115
+ console.log();
31116
+ }
31117
+ function printDivider(width = 53) {
31118
+ if (jsonMode) return;
31119
+ console.log(` ${import_picocolors.default.dim("\u2500".repeat(width))}`);
31120
+ }
31121
+ function printLine(text) {
31122
+ if (jsonMode) return;
31123
+ console.log(` ${text}`);
31124
+ }
31125
+ function printSeparator() {
31126
+ if (jsonMode) return;
31127
+ console.log(` ${import_picocolors.default.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}`);
31128
+ }
31129
+ function explorerUrl(txHash, network = "mainnet") {
31130
+ const base = network === "testnet" ? "https://suiscan.xyz/testnet/tx" : "https://suiscan.xyz/mainnet/tx";
31131
+ const suffix = "";
31132
+ return `${base}/${txHash}${suffix}`;
31133
+ }
31134
+ function handleError(error) {
31135
+ if (jsonMode) {
31136
+ const data = error instanceof Error && "toJSON" in error ? error.toJSON() : { error: "UNKNOWN", message: String(error) };
31137
+ printJson(data);
31138
+ } else {
31139
+ const msg = error instanceof Error ? error.message : String(error);
31140
+ printError(msg);
31141
+ }
31142
+ process.exit(1);
31143
+ }
31144
+
30923
31145
  // ../../node_modules/.pnpm/@inquirer+core@10.3.2_@types+node@20.19.37/node_modules/@inquirer/core/dist/esm/lib/key.js
30924
31146
  var isUpKey = (key, keybindings = []) => (
30925
31147
  // The up key
@@ -33346,12 +33568,16 @@ async function postJson(url, body2) {
33346
33568
  return json;
33347
33569
  }
33348
33570
  async function runSponsoredTx(opts) {
33571
+ const allowUntrusted = isAllowUntrustedApi();
33572
+ assertSigningHostAllowed(opts.prepareUrl, allowUntrusted);
33349
33573
  const prep = await postJson(opts.prepareUrl, opts.prepareBody);
33350
33574
  const nonce = prep.nonce;
33351
33575
  const txBytes = prep.txBytes;
33352
33576
  if (!(nonce && txBytes)) {
33353
33577
  throw new Error("Failed to prepare the transaction.");
33354
33578
  }
33579
+ assertTxMatchesIntent(txBytes, opts.intent, { allowUntrusted });
33580
+ printLine(describeIntent(opts.intent, opts.prepareUrl));
33355
33581
  const bytes = new Uint8Array(Buffer.from(txBytes, "base64"));
33356
33582
  const { signature } = await opts.keypair.signTransaction(bytes);
33357
33583
  const res = await postJson(opts.submitUrl, {
@@ -33362,6 +33588,8 @@ async function runSponsoredTx(opts) {
33362
33588
  return { digest: res.digest };
33363
33589
  }
33364
33590
  async function registerWallet(opts) {
33591
+ const allowUntrusted = isAllowUntrustedApi();
33592
+ assertSigningHostAllowed(opts.base, allowUntrusted);
33365
33593
  const prep = await postJson(`${opts.base}/agent/register/prepare`, {
33366
33594
  address: opts.address
33367
33595
  });
@@ -33373,6 +33601,7 @@ async function registerWallet(opts) {
33373
33601
  if (!(regNonce && txBytes)) {
33374
33602
  throw new Error("Failed to prepare registration.");
33375
33603
  }
33604
+ assertTxMatchesIntent(txBytes, { action: "register" }, { allowUntrusted });
33376
33605
  const bytes = new Uint8Array(Buffer.from(txBytes, "base64"));
33377
33606
  const { signature } = await opts.keypair.signTransaction(bytes);
33378
33607
  const res = await postJson(`${opts.base}/agent/register/submit`, {
@@ -33475,7 +33704,15 @@ function registerInit(program3) {
33475
33704
  }
33476
33705
 
33477
33706
  // src/lib/with-agent.ts
33707
+ function assertEnvApiHostTrusted() {
33708
+ const envBase = process.env.T2000_API_URL;
33709
+ if (!envBase) {
33710
+ return;
33711
+ }
33712
+ assertSigningHostAllowed(envBase, isAllowUntrustedApi());
33713
+ }
33478
33714
  async function withAgent(options = {}) {
33715
+ assertEnvApiHostTrusted();
33479
33716
  return T2000.create({
33480
33717
  keyPath: options.keyPath,
33481
33718
  rpcUrl: options.rpcUrl
@@ -33483,6 +33720,7 @@ async function withAgent(options = {}) {
33483
33720
  }
33484
33721
  async function tryWithAgent(options = {}) {
33485
33722
  try {
33723
+ assertEnvApiHostTrusted();
33486
33724
  const agent = await T2000.create({
33487
33725
  keyPath: options.keyPath,
33488
33726
  rpcUrl: options.rpcUrl
@@ -35207,7 +35445,8 @@ function registerAgentCreate(group) {
35207
35445
  actor: address,
35208
35446
  prepareUrl: `${base}/agent/owner/propose`,
35209
35447
  prepareBody: { address, owner },
35210
- submitUrl: `${base}/agent/owner/submit`
35448
+ submitUrl: `${base}/agent/owner/submit`,
35449
+ intent: { action: "link" }
35211
35450
  });
35212
35451
  ownerProposed = true;
35213
35452
  }
@@ -35330,7 +35569,8 @@ Subcommands:
35330
35569
  actor: address,
35331
35570
  prepareUrl: `${base}/agent/owner/propose`,
35332
35571
  prepareBody: { address, owner },
35333
- submitUrl: `${base}/agent/owner/submit`
35572
+ submitUrl: `${base}/agent/owner/submit`,
35573
+ intent: { action: "link" }
35334
35574
  });
35335
35575
  if (isJsonMode()) {
35336
35576
  printJson({ agent: address, pendingOwner: owner, digest });
@@ -35359,7 +35599,8 @@ Subcommands:
35359
35599
  actor: address,
35360
35600
  prepareUrl: `${base}/agent/owner/confirm`,
35361
35601
  prepareBody: { owner: address, agent: agentAddress },
35362
- submitUrl: `${base}/agent/owner/submit`
35602
+ submitUrl: `${base}/agent/owner/submit`,
35603
+ intent: { action: "confirm" }
35363
35604
  });
35364
35605
  if (isJsonMode()) {
35365
35606
  printJson({ owner: address, agent: agentAddress, digest });
@@ -35385,7 +35626,8 @@ Subcommands:
35385
35626
  actor: address,
35386
35627
  prepareUrl: `${base}/agent/owner/renounce`,
35387
35628
  prepareBody: { owner: address, agent: agentAddress },
35388
- submitUrl: `${base}/agent/owner/submit`
35629
+ submitUrl: `${base}/agent/owner/submit`,
35630
+ intent: { action: "confirm" }
35389
35631
  });
35390
35632
  if (isJsonMode()) {
35391
35633
  printJson({ owner: address, agent: agentAddress, unlinked: true, digest });
@@ -35481,6 +35723,7 @@ Subcommands:
35481
35723
  if (!opts.remove) {
35482
35724
  await ensureSellerCategory({ base, agent, category });
35483
35725
  }
35726
+ assertSigningHostAllowed(base, isAllowUntrustedApi());
35484
35727
  const prepRes = await fetch(`${base}/agent/endpoint/prepare`, {
35485
35728
  method: "POST",
35486
35729
  headers: { "Content-Type": "application/json" },
@@ -35647,13 +35890,133 @@ function registerAgents(program3) {
35647
35890
  }
35648
35891
 
35649
35892
  // src/commands/job.ts
35650
- var import_picocolors13 = __toESM(require_picocolors(), 1);
35651
35893
  import { createHash } from "crypto";
35894
+
35895
+ // src/lib/spend-gate.ts
35896
+ var FORCE_HINT_RE = /\s*Use --force[^.]*\.\s*$/;
35897
+ function assertSpendAllowed(amountUsdc, force) {
35898
+ if (!(Number.isFinite(amountUsdc) && amountUsdc > 0)) {
35899
+ return;
35900
+ }
35901
+ try {
35902
+ assertLimitConfig({
35903
+ limits: getLimits(),
35904
+ spentTodayUsd: dailySpentToday(),
35905
+ operation: "send",
35906
+ amountUsd: amountUsdc,
35907
+ force
35908
+ });
35909
+ } catch (e) {
35910
+ if (e instanceof LimitExceededError) {
35911
+ throw new Error(
35912
+ `${e.message.replace(FORCE_HINT_RE, "")} Raise the cap with \`t2 limit set\` \u2014 job verbs have no --force.`
35913
+ );
35914
+ }
35915
+ throw e;
35916
+ }
35917
+ }
35918
+ function recordSpendIfLanded(amountUsdc, digest) {
35919
+ if (digest && Number.isFinite(amountUsdc) && amountUsdc > 0) {
35920
+ recordDailySpend(amountUsdc);
35921
+ }
35922
+ }
35923
+
35924
+ // src/lib/settle-fee.ts
35925
+ var SERVICES_SETTLE_FEE_BPS = 500;
35926
+ var MICRO = 1e6;
35927
+ var TRAILING_ZEROS = /0+$/;
35928
+ function formatUsdMicro(micro) {
35929
+ if (!Number.isFinite(micro) || micro < 0) {
35930
+ return "\u2014";
35931
+ }
35932
+ const m = Math.floor(micro);
35933
+ const whole = Math.floor(m / MICRO);
35934
+ const frac = String(m % MICRO).padStart(6, "0");
35935
+ const dp = Math.max(2, frac.replace(TRAILING_ZEROS, "").length);
35936
+ return `$${whole}.${frac.slice(0, dp)}`;
35937
+ }
35938
+ function settlementSplit(priceUsdc, feeBps = SERVICES_SETTLE_FEE_BPS) {
35939
+ const escrowMicro = Math.floor(priceUsdc * MICRO);
35940
+ const feeMicro = Math.floor(escrowMicro * feeBps / 1e4);
35941
+ const payoutMicro = escrowMicro - feeMicro;
35942
+ return {
35943
+ escrowUsdc: priceUsdc,
35944
+ feeBps,
35945
+ feeMicro,
35946
+ payoutMicro,
35947
+ escrow: formatUsdMicro(escrowMicro),
35948
+ fee: formatUsdMicro(feeMicro),
35949
+ payout: formatUsdMicro(payoutMicro)
35950
+ };
35951
+ }
35952
+ function sellerReceivesLine(priceUsdc) {
35953
+ const s = settlementSplit(priceUsdc);
35954
+ return `${s.payout} after the ${s.feeBps / 100}% settle fee (${s.fee})`;
35955
+ }
35956
+ var SETTLE_FEE_NOTE = `Services settle at ${SERVICES_SETTLE_FEE_BPS / 100}% from the seller's payout \u2014 never added to the buyer's escrow. Refunds, cancels and declines are fee-free.`;
35957
+
35958
+ // src/lib/agent-ref.ts
35959
+ var HASH_ID_RE = /^#\d{1,10}$/;
35960
+ var BARE_DIGITS_RE = /^\d{1,10}$/;
35961
+ var HANDLE_REF_RE = /^@[a-z0-9_-]{1,20}$/i;
35962
+ var HEX_REF_RE = /^0x[0-9a-fA-F]+$/;
35963
+ var AGENT_REF_KEY_RE = /agent|address|wallet|subject|recipient|pay[_-]?to|target/i;
35964
+ var FALLBACK_MISS = "Use an Agent ID (#93), @handle, or full 0x\u2026 address.";
35965
+ function looksLikeAgentRefValue(value) {
35966
+ const v = value.trim();
35967
+ return HASH_ID_RE.test(v) || HANDLE_REF_RE.test(v) || HEX_REF_RE.test(v);
35968
+ }
35969
+ function looksLikeAgentRefKey(key) {
35970
+ return AGENT_REF_KEY_RE.test(key);
35971
+ }
35972
+ function isAgentRefField(key, value) {
35973
+ const v = value.trim();
35974
+ if (looksLikeAgentRefValue(v)) {
35975
+ return true;
35976
+ }
35977
+ return BARE_DIGITS_RE.test(v) && looksLikeAgentRefKey(key);
35978
+ }
35979
+ function agentRefFields(requirements) {
35980
+ if (requirements == null || typeof requirements !== "object" || Array.isArray(requirements)) {
35981
+ return [];
35982
+ }
35983
+ return Object.entries(requirements).filter((e) => typeof e[1] === "string").filter(([k, v]) => isAgentRefField(k, v));
35984
+ }
35985
+ async function resolveAgentRef(base, q) {
35986
+ const res = await fetch(
35987
+ `${base}/agents/resolve?q=${encodeURIComponent(q.trim())}`
35988
+ );
35989
+ const json = await res.json().catch(() => ({}));
35990
+ if (!(res.ok && json.address)) {
35991
+ throw new Error(json.error ?? FALLBACK_MISS);
35992
+ }
35993
+ return { address: json.address, numericId: json.numericId, name: json.name };
35994
+ }
35995
+ async function expandAgentRefs(base, requirements) {
35996
+ const fields = agentRefFields(requirements);
35997
+ if (fields.length === 0) {
35998
+ return requirements;
35999
+ }
36000
+ const out = { ...requirements };
36001
+ for (const [key, raw] of fields) {
36002
+ try {
36003
+ out[key] = (await resolveAgentRef(base, raw)).address;
36004
+ } catch (e) {
36005
+ throw new Error(
36006
+ `${key}: ${e instanceof Error ? e.message : FALLBACK_MISS}`
36007
+ );
36008
+ }
36009
+ }
36010
+ return out;
36011
+ }
36012
+
36013
+ // src/commands/job.ts
36014
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
35652
36015
  import { readFile as readFile4 } from "fs/promises";
35653
36016
 
35654
36017
  // src/commands/open.ts
35655
- var import_picocolors12 = __toESM(require_picocolors(), 1);
35656
36018
  import { readFile as readFile3 } from "fs/promises";
36019
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
35657
36020
  var DEFAULT_API_BASE6 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
35658
36021
  var MAX_BRIEF_BYTES = 16 * 1024;
35659
36022
  async function resolveBrief(input) {
@@ -35701,6 +36064,7 @@ function registerOpenVerbs(group) {
35701
36064
  throw new Error(`--max must be between 0.01 and ${MAX_JOB_USDC} USDC.`);
35702
36065
  }
35703
36066
  const brief = await resolveBrief(opts.brief);
36067
+ assertSpendAllowed(maxUsdc);
35704
36068
  const agent = await withAgent({ keyPath: opts.key });
35705
36069
  const digest = await postOpenJob(base, agent.signer, {
35706
36070
  title: opts.title.trim(),
@@ -35709,6 +36073,7 @@ function registerOpenVerbs(group) {
35709
36073
  slaMinutes: Math.round(parseDuration(opts.sla) / 6e4),
35710
36074
  openHours: parseDuration(opts.openFor) / 36e5
35711
36075
  });
36076
+ recordSpendIfLanded(maxUsdc, digest);
35712
36077
  const openingId = await resolveCreated(digest, "::opening::Opening<");
35713
36078
  if (isJsonMode()) {
35714
36079
  printJson({ digest, openingId });
@@ -35923,13 +36288,22 @@ function printInboxRow(job) {
35923
36288
  async function sponsoredJobVerb(opts) {
35924
36289
  const agent = await withAgent({ keyPath: opts.keyPath });
35925
36290
  const address = agent.address();
36291
+ if (opts.spendUsdc !== void 0) {
36292
+ assertSpendAllowed(opts.spendUsdc, opts.force);
36293
+ }
35926
36294
  const { digest } = await runSponsoredTx({
35927
36295
  keypair: agent.keypair,
35928
36296
  actor: address,
35929
36297
  prepareUrl: `${opts.base}/job/prepare`,
35930
36298
  prepareBody: { address, action: opts.action, params: opts.params },
35931
- submitUrl: `${opts.base}/job/submit`
36299
+ submitUrl: `${opts.base}/job/submit`,
36300
+ intent: {
36301
+ action: opts.action,
36302
+ amountUsdc: opts.spendUsdc,
36303
+ seller: opts.seller
36304
+ }
35932
36305
  });
36306
+ recordSpendIfLanded(opts.spendUsdc ?? 0, digest);
35933
36307
  return { address, digest };
35934
36308
  }
35935
36309
  function registerJob(program3) {
@@ -35965,7 +36339,10 @@ no fund step; unclaimed openings refund fee-free):
35965
36339
  ASP $ t2 job board \xB7 t2 job claim <openingId>
35966
36340
  `
35967
36341
  );
35968
- group.command("hire").alias("create").argument("[amount]", `USDC to escrow (max ${MAX_JOB_USDC}; omit when hiring a --service listing)`).argument("[seller]", "The ASP's Sui address (omit when hiring a --service listing)").description("Hire \u2014 fund an escrow job in one transaction (buyer): a listing (--agent + --service) or your own terms (amount + seller + --spec)").option("--spec <file-or-text>", "Job spec \u2014 a file path or inline text (UPLOADED so the seller can read it; sha256 pinned on-chain), or a bare 0x\u2026 sha256 (confidential: pins without uploading)").option("--agent <address>", "Hire a listing: the ASP's agent address").option("--service <slug>", "The service slug (see t2 services / t2 service list <agent>)").option("--requirements <file-or-json-or-text>", "What the seller asked buyers to provide \u2014 if the listing lists JSON keys, fill EVERY key (JSON object; extra keys OK)").option("--deadline <duration>", "Time the seller has to deliver (e.g. 30m, 24h, 7d)", "24h").option("--review <duration>", "Your accept/reject window after delivery", "24h").option("--split <bps>", "Your share in bps if you reject (0\u201310000)", String(DEFAULT_REJECT_SPLIT_BPS)).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE7})`).action(
36342
+ group.command("hire").alias("create").argument("[amount]", `USDC to escrow (max ${MAX_JOB_USDC}; omit when hiring a --service listing)`).argument("[seller]", "The ASP's Sui address (omit when hiring a --service listing)").description("Hire \u2014 fund an escrow job in one transaction (buyer): a listing (--agent + --service) or your own terms (amount + seller + --spec)").option("--spec <file-or-text>", "Job spec \u2014 a file path or inline text (UPLOADED so the seller can read it; sha256 pinned on-chain), or a bare 0x\u2026 sha256 (confidential: pins without uploading)").option(
36343
+ "--agent <address|#id|@handle>",
36344
+ "Hire a listing: the ASP's agent address, #id, or @handle"
36345
+ ).option("--service <slug>", "The service slug (see t2 services / t2 service list <agent>)").option("--requirements <file-or-json-or-text>", "What the seller asked buyers to provide \u2014 if the listing lists JSON keys, fill EVERY key (JSON object; extra keys OK)").option("--deadline <duration>", "Time the seller has to deliver (e.g. 30m, 24h, 7d)", "24h").option("--review <duration>", "Your accept/reject window after delivery", "24h").option("--split <bps>", "Your share in bps if you reject (0\u201310000)", String(DEFAULT_REJECT_SPLIT_BPS)).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE7})`).action(
35969
36346
  async (amountArg, sellerArg, opts) => {
35970
36347
  try {
35971
36348
  const base = opts.api ?? DEFAULT_API_BASE7;
@@ -35986,7 +36363,9 @@ no fund step; unclaimed openings refund fee-free):
35986
36363
  "Omit the amount/seller arguments when buying a service \u2014 the listing sets the price and the seller."
35987
36364
  );
35988
36365
  }
35989
- const sellerAgent = validateAddress(opts.agent);
36366
+ const sellerAgent = validateAddress(
36367
+ (await resolveAgentRef(base, opts.agent)).address
36368
+ );
35990
36369
  const service = await fetchService(base, sellerAgent, serviceSlugOpt);
35991
36370
  serviceSlug = service.slug;
35992
36371
  let requirements = null;
@@ -36002,6 +36381,7 @@ no fund step; unclaimed openings refund fee-free):
36002
36381
  requirements = text.trim();
36003
36382
  }
36004
36383
  }
36384
+ requirements = await expandAgentRefs(base, requirements);
36005
36385
  assertBuyerRequirements(service.requirements, requirements);
36006
36386
  const buyer = (await withAgent({ keyPath: opts.key })).address();
36007
36387
  const spec = JSON.stringify({
@@ -36036,17 +36416,52 @@ no fund step; unclaimed openings refund fee-free):
36036
36416
  if (!Number.isFinite(amountUsdc) || amountUsdc <= 0) {
36037
36417
  throw new Error(`Amount must be a positive number (got "${amountArg}").`);
36038
36418
  }
36039
- seller = validateAddress(sellerArg);
36419
+ seller = validateAddress(
36420
+ (await resolveAgentRef(base, sellerArg)).address
36421
+ );
36040
36422
  ({ hash: specHash } = await resolveSpecUpload(base, opts.spec));
36041
36423
  deliverByMs = Date.now() + parseDuration(opts.deadline);
36042
36424
  reviewWindowMs = opts.review ? parseDuration(opts.review) : DEFAULT_REVIEW_WINDOW_MS;
36043
36425
  rejectSplitBps = Number.parseInt(opts.split, 10);
36044
36426
  }
36427
+ const pre = preflightCreateJob({
36428
+ seller,
36429
+ amountUsdc,
36430
+ specHash,
36431
+ deliverByMs,
36432
+ reviewWindowMs,
36433
+ rejectSplitBps
36434
+ });
36435
+ if (!pre.valid) {
36436
+ throw new Error(pre.error);
36437
+ }
36438
+ const preAgent = await withAgent({ keyPath: opts.key });
36439
+ const bal = await preAgent.balance();
36440
+ const usdc = bal.stables.USDC ?? 0;
36441
+ if (usdc < amountUsdc) {
36442
+ throw new Error(
36443
+ `Insufficient USDC \u2014 need ${formatUsdMicro(Math.floor(amountUsdc * 1e6))}, wallet has ${formatUsdMicro(Math.floor(usdc * 1e6))}. Fund it: t2 fund`
36444
+ );
36445
+ }
36446
+ assertSpendAllowed(amountUsdc);
36447
+ const split4 = settlementSplit(amountUsdc);
36448
+ if (!isJsonMode()) {
36449
+ printBlank();
36450
+ printInfo("Hire preflight");
36451
+ printKeyValue(" Escrow", `${split4.escrow} USDC (leaves your wallet on sign)`);
36452
+ printKeyValue(" Seller", truncateAddress(seller));
36453
+ if (serviceSlug) printKeyValue(" Service", serviceSlug);
36454
+ printKeyValue(" Deliver by", new Date(deliverByMs).toISOString());
36455
+ printKeyValue(" Settle fee", `${split4.fee} from the seller's payout \u2014 not added to your escrow`);
36456
+ }
36045
36457
  const { address, digest } = await sponsoredJobVerb({
36046
36458
  base,
36047
36459
  keyPath: opts.key,
36048
36460
  action: "create",
36049
- params: { seller, amountUsdc, specHash, deliverByMs, reviewWindowMs, rejectSplitBps }
36461
+ params: { seller, amountUsdc, specHash, deliverByMs, reviewWindowMs, rejectSplitBps },
36462
+ // The buyer's USDC leaves here — the one job verb that spends.
36463
+ spendUsdc: amountUsdc,
36464
+ seller
36050
36465
  });
36051
36466
  const client = getSuiClient();
36052
36467
  let jobId;
@@ -36064,7 +36479,7 @@ no fund step; unclaimed openings refund fee-free):
36064
36479
  }
36065
36480
  }
36066
36481
  if (isJsonMode()) {
36067
- printJson({ jobId, digest, buyer: address, seller, amountUsdc, specHash, deliverByMs, reviewWindowMs, rejectSplitBps, ...serviceSlug ? { service: serviceSlug } : {} });
36482
+ printJson({ jobId, digest, buyer: address, seller, amountUsdc, specHash, deliverByMs, reviewWindowMs, rejectSplitBps, feeBps: split4.feeBps, sellerReceiveUsdc: split4.payoutMicro / 1e6, ...serviceSlug ? { service: serviceSlug } : {} });
36068
36483
  return;
36069
36484
  }
36070
36485
  printBlank();
@@ -36072,6 +36487,7 @@ no fund step; unclaimed openings refund fee-free):
36072
36487
  if (jobId) printKeyValue("Job", jobId);
36073
36488
  printKeyValue("Spec hash", specHash);
36074
36489
  printKeyValue("Deliver by", new Date(deliverByMs).toISOString());
36490
+ printKeyValue("Seller receives", sellerReceivesLine(amountUsdc));
36075
36491
  if (digest) printKeyValue("Tx", digest);
36076
36492
  printBlank();
36077
36493
  if (jobId) {
@@ -36371,8 +36787,8 @@ no fund step; unclaimed openings refund fee-free):
36371
36787
  }
36372
36788
 
36373
36789
  // src/commands/service.ts
36374
- var import_picocolors14 = __toESM(require_picocolors(), 1);
36375
36790
  import { createHash as createHash2 } from "crypto";
36791
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
36376
36792
  import { readFile as readFile5 } from "fs/promises";
36377
36793
  var DEFAULT_API_BASE8 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
36378
36794
  async function signedServiceAction(opts) {
@@ -36429,7 +36845,10 @@ function formatSla(minutes) {
36429
36845
  function printService(o) {
36430
36846
  const flag = o.retired ? import_picocolors14.default.dim(" (retired)") : "";
36431
36847
  printLine(`${import_picocolors14.default.bold(o.name)} ${import_picocolors14.default.dim(`\xB7 ${o.slug}`)}${flag}`);
36432
- printKeyValue("Price", `$${o.priceUsdc.toFixed(2)} USDC`);
36848
+ printKeyValue(
36849
+ "Price",
36850
+ `$${o.priceUsdc.toFixed(2)} USDC ${import_picocolors14.default.dim(`\xB7 seller receives ${settlementSplit(o.priceUsdc).payout}`)}`
36851
+ );
36433
36852
  printKeyValue("Delivery", `within ${formatSla(o.slaMinutes)}`);
36434
36853
  printKeyValue(
36435
36854
  "Seller",
@@ -36509,15 +36928,22 @@ Examples:
36509
36928
  payload
36510
36929
  });
36511
36930
  if (isJsonMode()) {
36512
- printJson({ address, ...payload });
36931
+ printJson({
36932
+ address,
36933
+ ...payload,
36934
+ feeBps: SERVICES_SETTLE_FEE_BPS,
36935
+ sellerReceiveUsdc: settlementSplit(priceUsdc).payoutMicro / 1e6
36936
+ });
36513
36937
  return;
36514
36938
  }
36515
36939
  printBlank();
36516
36940
  printSuccess(`"${payload.name}" is listed \u2014 $${priceUsdc.toFixed(2)} USDC, delivery within ${formatSla(slaMinutes)}`);
36941
+ printKeyValue("You receive", sellerReceivesLine(priceUsdc));
36517
36942
  printKeyValue("Slug", slug);
36518
36943
  printKeyValue("Storefront", `https://t2000.ai/${address}`);
36519
36944
  printKeyValue("Buyers run", `t2 job hire --agent ${address} --service ${slug}`);
36520
36945
  printBlank();
36946
+ printInfo(SETTLE_FEE_NOTE);
36521
36947
  printInfo("Watch for incoming jobs with: t2 job watch --mine");
36522
36948
  printBlank();
36523
36949
  } catch (error) {
@@ -36619,9 +37045,24 @@ var require3 = createRequire2(import.meta.url);
36619
37045
  var { version: CLI_VERSION2 } = require3("../package.json");
36620
37046
  function createProgram() {
36621
37047
  const program3 = new Command();
36622
- program3.name("t2").description("Agent Wallet \u2014 autonomous Sui USDC + USDsui wallet for AI agents").version(`${CLI_VERSION2}`).option("--json", "Output in JSON format").hook("preAction", (thisCommand) => {
37048
+ program3.name("t2").description("Agent Wallet \u2014 autonomous Sui USDC + USDsui wallet for AI agents").version(`${CLI_VERSION2}`).option("--json", "Output in JSON format").option(
37049
+ "--allow-untrusted-api",
37050
+ `Permit signing transactions built by a non-default API host (${CANONICAL_API_ORIGIN} is the only trusted host). Only for local/staging work \u2014 a host you did not choose can propose any transaction.`
37051
+ ).hook("preAction", (thisCommand) => {
36623
37052
  const opts = thisCommand.optsWithGlobals();
36624
37053
  if (opts.json) setJsonMode(true);
37054
+ setAllowUntrustedApi(Boolean(opts.allowUntrustedApi));
37055
+ installSponsoredTxGuard();
37056
+ if (process.env.T2000_API_URL) {
37057
+ try {
37058
+ assertSigningHostAllowed(
37059
+ process.env.T2000_API_URL,
37060
+ Boolean(opts.allowUntrustedApi)
37061
+ );
37062
+ } catch (e) {
37063
+ handleError(e);
37064
+ }
37065
+ }
36625
37066
  }).addHelpText("after", `
36626
37067
  Setup:
36627
37068
  $ t2 init Create a new Agent Wallet