@t2000/cli 10.27.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 +126 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -30545,6 +30545,8 @@ var A2A_ESCROW_FEE_CONFIG_VERSION = Number(
|
|
|
30545
30545
|
);
|
|
30546
30546
|
var MODULE2 = "escrow";
|
|
30547
30547
|
var MAX_JOB_USDC = 50;
|
|
30548
|
+
var MAX_REVIEW_WINDOW_MS = 2592e6;
|
|
30549
|
+
var MAX_DELIVER_HORIZON_MS = 31536e6;
|
|
30548
30550
|
var JOB_STATES = [
|
|
30549
30551
|
"funded",
|
|
30550
30552
|
"delivered",
|
|
@@ -30552,12 +30554,57 @@ var JOB_STATES = [
|
|
|
30552
30554
|
"refunded",
|
|
30553
30555
|
"rejected"
|
|
30554
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
|
+
}
|
|
30555
30571
|
function bytesToHex3(bytes) {
|
|
30556
30572
|
const arr = typeof bytes === "string" ? Array.from(atob(bytes), (c) => c.charCodeAt(0)) : bytes;
|
|
30557
30573
|
let s = "0x";
|
|
30558
30574
|
for (const b of arr) s += b.toString(16).padStart(2, "0");
|
|
30559
30575
|
return s;
|
|
30560
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
|
+
}
|
|
30561
30608
|
async function getJob(client, jobId) {
|
|
30562
30609
|
const resp = await client.core.getObject({ objectId: jobId, include: { json: true } }).catch((e) => {
|
|
30563
30610
|
throw new T2000Error(
|
|
@@ -35874,6 +35921,40 @@ function recordSpendIfLanded(amountUsdc, digest) {
|
|
|
35874
35921
|
}
|
|
35875
35922
|
}
|
|
35876
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
|
+
|
|
35877
35958
|
// src/lib/agent-ref.ts
|
|
35878
35959
|
var HASH_ID_RE = /^#\d{1,10}$/;
|
|
35879
35960
|
var BARE_DIGITS_RE = /^\d{1,10}$/;
|
|
@@ -36343,6 +36424,36 @@ no fund step; unclaimed openings refund fee-free):
|
|
|
36343
36424
|
reviewWindowMs = opts.review ? parseDuration(opts.review) : DEFAULT_REVIEW_WINDOW_MS;
|
|
36344
36425
|
rejectSplitBps = Number.parseInt(opts.split, 10);
|
|
36345
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
|
+
}
|
|
36346
36457
|
const { address, digest } = await sponsoredJobVerb({
|
|
36347
36458
|
base,
|
|
36348
36459
|
keyPath: opts.key,
|
|
@@ -36368,7 +36479,7 @@ no fund step; unclaimed openings refund fee-free):
|
|
|
36368
36479
|
}
|
|
36369
36480
|
}
|
|
36370
36481
|
if (isJsonMode()) {
|
|
36371
|
-
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 } : {} });
|
|
36372
36483
|
return;
|
|
36373
36484
|
}
|
|
36374
36485
|
printBlank();
|
|
@@ -36376,6 +36487,7 @@ no fund step; unclaimed openings refund fee-free):
|
|
|
36376
36487
|
if (jobId) printKeyValue("Job", jobId);
|
|
36377
36488
|
printKeyValue("Spec hash", specHash);
|
|
36378
36489
|
printKeyValue("Deliver by", new Date(deliverByMs).toISOString());
|
|
36490
|
+
printKeyValue("Seller receives", sellerReceivesLine(amountUsdc));
|
|
36379
36491
|
if (digest) printKeyValue("Tx", digest);
|
|
36380
36492
|
printBlank();
|
|
36381
36493
|
if (jobId) {
|
|
@@ -36675,8 +36787,8 @@ no fund step; unclaimed openings refund fee-free):
|
|
|
36675
36787
|
}
|
|
36676
36788
|
|
|
36677
36789
|
// src/commands/service.ts
|
|
36678
|
-
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
36679
36790
|
import { createHash as createHash2 } from "crypto";
|
|
36791
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
36680
36792
|
import { readFile as readFile5 } from "fs/promises";
|
|
36681
36793
|
var DEFAULT_API_BASE8 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
36682
36794
|
async function signedServiceAction(opts) {
|
|
@@ -36733,7 +36845,10 @@ function formatSla(minutes) {
|
|
|
36733
36845
|
function printService(o) {
|
|
36734
36846
|
const flag = o.retired ? import_picocolors14.default.dim(" (retired)") : "";
|
|
36735
36847
|
printLine(`${import_picocolors14.default.bold(o.name)} ${import_picocolors14.default.dim(`\xB7 ${o.slug}`)}${flag}`);
|
|
36736
|
-
printKeyValue(
|
|
36848
|
+
printKeyValue(
|
|
36849
|
+
"Price",
|
|
36850
|
+
`$${o.priceUsdc.toFixed(2)} USDC ${import_picocolors14.default.dim(`\xB7 seller receives ${settlementSplit(o.priceUsdc).payout}`)}`
|
|
36851
|
+
);
|
|
36737
36852
|
printKeyValue("Delivery", `within ${formatSla(o.slaMinutes)}`);
|
|
36738
36853
|
printKeyValue(
|
|
36739
36854
|
"Seller",
|
|
@@ -36813,15 +36928,22 @@ Examples:
|
|
|
36813
36928
|
payload
|
|
36814
36929
|
});
|
|
36815
36930
|
if (isJsonMode()) {
|
|
36816
|
-
printJson({
|
|
36931
|
+
printJson({
|
|
36932
|
+
address,
|
|
36933
|
+
...payload,
|
|
36934
|
+
feeBps: SERVICES_SETTLE_FEE_BPS,
|
|
36935
|
+
sellerReceiveUsdc: settlementSplit(priceUsdc).payoutMicro / 1e6
|
|
36936
|
+
});
|
|
36817
36937
|
return;
|
|
36818
36938
|
}
|
|
36819
36939
|
printBlank();
|
|
36820
36940
|
printSuccess(`"${payload.name}" is listed \u2014 $${priceUsdc.toFixed(2)} USDC, delivery within ${formatSla(slaMinutes)}`);
|
|
36941
|
+
printKeyValue("You receive", sellerReceivesLine(priceUsdc));
|
|
36821
36942
|
printKeyValue("Slug", slug);
|
|
36822
36943
|
printKeyValue("Storefront", `https://t2000.ai/${address}`);
|
|
36823
36944
|
printKeyValue("Buyers run", `t2 job hire --agent ${address} --service ${slug}`);
|
|
36824
36945
|
printBlank();
|
|
36946
|
+
printInfo(SETTLE_FEE_NOTE);
|
|
36825
36947
|
printInfo("Watch for incoming jobs with: t2 job watch --mine");
|
|
36826
36948
|
printBlank();
|
|
36827
36949
|
} catch (error) {
|