@t2000/cli 10.13.4 → 10.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/{chunk-M3VP3LAY.js → chunk-3ZC3KARI.js} +108 -1
- package/dist/chunk-3ZC3KARI.js.map +1 -0
- package/dist/{dist-4BBYOHH2.js → dist-K6ZK2ZFY.js} +16 -2
- package/dist/{dist-DTKT6EKV.js → dist-ZATHFBVY.js} +244 -22
- package/dist/{dist-DTKT6EKV.js.map → dist-ZATHFBVY.js.map} +1 -1
- package/dist/index.js +271 -49
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-M3VP3LAY.js.map +0 -1
- /package/dist/{dist-4BBYOHH2.js.map → dist-K6ZK2ZFY.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -11,9 +11,13 @@ import {
|
|
|
11
11
|
assertBuyerRequirements,
|
|
12
12
|
buildPublishAgentCoinTx,
|
|
13
13
|
buildTokenizeTx,
|
|
14
|
+
cancelOpenJob,
|
|
15
|
+
claimOpenJob,
|
|
14
16
|
clearLimits,
|
|
17
|
+
createOpenJob,
|
|
15
18
|
fetchService,
|
|
16
19
|
formatUsd,
|
|
20
|
+
fundOpenJob,
|
|
17
21
|
generateKeypair,
|
|
18
22
|
getAddress,
|
|
19
23
|
getJob,
|
|
@@ -24,17 +28,19 @@ import {
|
|
|
24
28
|
jobActionsFor,
|
|
25
29
|
keypairFromPrivateKey,
|
|
26
30
|
listModels,
|
|
31
|
+
listOpenJobs,
|
|
27
32
|
putJobSpec,
|
|
28
33
|
saveBech32,
|
|
29
34
|
saveKey,
|
|
30
35
|
setLimits,
|
|
31
36
|
truncateAddress,
|
|
37
|
+
unclaimOpenJob,
|
|
32
38
|
validateAddress,
|
|
33
39
|
validateAgentCoinParams,
|
|
34
40
|
verifyJobForSeller,
|
|
35
41
|
verifyReceipt,
|
|
36
42
|
walletExists
|
|
37
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-3ZC3KARI.js";
|
|
38
44
|
import "./chunk-634W6JCI.js";
|
|
39
45
|
import "./chunk-3ZUWXUSN.js";
|
|
40
46
|
import "./chunk-QSITA6GU.js";
|
|
@@ -22287,7 +22293,7 @@ async function runEstimate(url, opts) {
|
|
|
22287
22293
|
let req = accepts.find((a) => a.scheme === "exact" && a.network?.startsWith("sui:")) ?? accepts[0];
|
|
22288
22294
|
let dialect = "x402";
|
|
22289
22295
|
if (!req) {
|
|
22290
|
-
const { parseMppSuiChallenge } = await import("./dist-
|
|
22296
|
+
const { parseMppSuiChallenge } = await import("./dist-K6ZK2ZFY.js");
|
|
22291
22297
|
const challenge = await parseMppSuiChallenge(response);
|
|
22292
22298
|
if (!challenge) {
|
|
22293
22299
|
throw new Error(
|
|
@@ -23391,7 +23397,7 @@ function registerMcpStart(parent) {
|
|
|
23391
23397
|
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) => {
|
|
23392
23398
|
let mod;
|
|
23393
23399
|
try {
|
|
23394
|
-
mod = await import("./dist-
|
|
23400
|
+
mod = await import("./dist-ZATHFBVY.js");
|
|
23395
23401
|
} catch {
|
|
23396
23402
|
console.error("MCP server not installed. Run:\n npm install -g @t2000/mcp");
|
|
23397
23403
|
process.exit(1);
|
|
@@ -24799,9 +24805,218 @@ function registerCheck(program3) {
|
|
|
24799
24805
|
}
|
|
24800
24806
|
|
|
24801
24807
|
// src/commands/job.ts
|
|
24802
|
-
var
|
|
24808
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
24803
24809
|
import { createHash } from "crypto";
|
|
24810
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
24811
|
+
|
|
24812
|
+
// src/commands/open.ts
|
|
24813
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
24804
24814
|
import { readFile as readFile3 } from "fs/promises";
|
|
24815
|
+
var DEFAULT_API_BASE5 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
24816
|
+
var MAX_BRIEF_BYTES = 16 * 1024;
|
|
24817
|
+
async function resolveBrief(input) {
|
|
24818
|
+
let bytes;
|
|
24819
|
+
try {
|
|
24820
|
+
bytes = await readFile3(input);
|
|
24821
|
+
} catch {
|
|
24822
|
+
bytes = Buffer.from(input, "utf8");
|
|
24823
|
+
}
|
|
24824
|
+
if (bytes.length > MAX_BRIEF_BYTES) {
|
|
24825
|
+
throw new Error(
|
|
24826
|
+
`Brief is ${bytes.length} bytes \u2014 open-job briefs cap at 16 KiB. Keep it short and link out for more.`
|
|
24827
|
+
);
|
|
24828
|
+
}
|
|
24829
|
+
try {
|
|
24830
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes).trim();
|
|
24831
|
+
} catch {
|
|
24832
|
+
throw new Error("Brief is not UTF-8 text \u2014 the board holds text only.");
|
|
24833
|
+
}
|
|
24834
|
+
}
|
|
24835
|
+
function statusColor(status) {
|
|
24836
|
+
if (status === "open") return import_picocolors15.default.green(status);
|
|
24837
|
+
if (status === "claimed") return import_picocolors15.default.cyan(status);
|
|
24838
|
+
if (status === "funded") return import_picocolors15.default.dim(status);
|
|
24839
|
+
return import_picocolors15.default.yellow(status);
|
|
24840
|
+
}
|
|
24841
|
+
function fmtLeft(ms) {
|
|
24842
|
+
if (ms == null) return "";
|
|
24843
|
+
const left = ms - Date.now();
|
|
24844
|
+
if (left <= 0) return "now";
|
|
24845
|
+
const hours = Math.floor(left / 36e5);
|
|
24846
|
+
if (hours >= 48) return `${Math.floor(hours / 24)}d`;
|
|
24847
|
+
if (hours >= 1) return `${hours}h`;
|
|
24848
|
+
return `${Math.max(1, Math.floor(left / 6e4))}m`;
|
|
24849
|
+
}
|
|
24850
|
+
function printOpenJob(row) {
|
|
24851
|
+
printKeyValue("Open job", row.id);
|
|
24852
|
+
printKeyValue("Status", statusColor(row.status));
|
|
24853
|
+
printKeyValue("Title", row.title);
|
|
24854
|
+
printKeyValue("Budget", `$${row.maxUsdc.toFixed(2)} USDC`);
|
|
24855
|
+
printKeyValue("Deliver in", `${row.slaMinutes} min (once funded)`);
|
|
24856
|
+
if (row.status === "open") {
|
|
24857
|
+
printKeyValue("Open for", fmtLeft(row.openUntilMs));
|
|
24858
|
+
}
|
|
24859
|
+
if (row.buyerAgent) {
|
|
24860
|
+
printKeyValue("Buyer", `${row.buyerAgent.name} (#${row.buyerAgent.agentId})`);
|
|
24861
|
+
}
|
|
24862
|
+
if (row.seller) {
|
|
24863
|
+
printKeyValue(
|
|
24864
|
+
"Claimed by",
|
|
24865
|
+
row.sellerAgent ? `${row.sellerAgent.name} (${row.seller})` : row.seller
|
|
24866
|
+
);
|
|
24867
|
+
if (row.status === "claimed") {
|
|
24868
|
+
printKeyValue("Claim lapses", fmtLeft(row.claimExpiresAtMs));
|
|
24869
|
+
}
|
|
24870
|
+
}
|
|
24871
|
+
if (row.jobId) {
|
|
24872
|
+
printKeyValue("Job", row.jobId);
|
|
24873
|
+
}
|
|
24874
|
+
}
|
|
24875
|
+
function registerOpenVerbs(group) {
|
|
24876
|
+
group.command("open").description("Open \u2014 post the job to the public board with no ASP picked (buyer); holds no USDC, first claim wins").requiredOption("--title <text>", "The job's public name (up to 80 chars)").requiredOption("--brief <file-or-text>", "What you want delivered \u2014 PUBLIC, every ASP on the board reads it").requiredOption("--max <usdc>", `Budget escrowed at fund time (max ${MAX_JOB_USDC})`).option("--sla <duration>", "Delivery window once funded (e.g. 30m, 24h, 7d)", "24h").option("--open-for <duration>", "How long the posting stays claimable", "24h").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(
|
|
24877
|
+
async (opts) => {
|
|
24878
|
+
try {
|
|
24879
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
24880
|
+
const maxUsdc = Number(opts.max);
|
|
24881
|
+
if (!Number.isFinite(maxUsdc) || maxUsdc <= 0 || maxUsdc > MAX_JOB_USDC) {
|
|
24882
|
+
throw new Error(`--max must be between 0.01 and ${MAX_JOB_USDC} USDC.`);
|
|
24883
|
+
}
|
|
24884
|
+
const brief = await resolveBrief(opts.brief);
|
|
24885
|
+
const agent = await withAgent({ keyPath: opts.key });
|
|
24886
|
+
const row = await createOpenJob(base, agent.signer, {
|
|
24887
|
+
title: opts.title.trim(),
|
|
24888
|
+
brief,
|
|
24889
|
+
maxUsdc,
|
|
24890
|
+
slaMinutes: Math.round(parseDuration(opts.sla) / 6e4),
|
|
24891
|
+
openHours: parseDuration(opts.openFor) / 36e5
|
|
24892
|
+
});
|
|
24893
|
+
if (isJsonMode()) {
|
|
24894
|
+
printJson({ openJob: row });
|
|
24895
|
+
return;
|
|
24896
|
+
}
|
|
24897
|
+
printBlank();
|
|
24898
|
+
printSuccess("Posted \u2014 your open job is on the board (no USDC moved).");
|
|
24899
|
+
printBlank();
|
|
24900
|
+
printOpenJob(row);
|
|
24901
|
+
printBlank();
|
|
24902
|
+
printInfo("When an ASP claims it: t2 job fund " + row.id);
|
|
24903
|
+
printBlank();
|
|
24904
|
+
} catch (error) {
|
|
24905
|
+
handleError(error);
|
|
24906
|
+
}
|
|
24907
|
+
}
|
|
24908
|
+
);
|
|
24909
|
+
group.command("board").argument("[query]", "Free-text filter across titles + briefs").description("Read the open board \u2014 claimable postings first (public, no wallet)").option("--status <status>", "open | claimed | funded | expired | cancelled", "open").option("--limit <n>", "Max rows (default 24)", "24").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (query, opts) => {
|
|
24910
|
+
try {
|
|
24911
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
24912
|
+
const rows = await listOpenJobs(base, {
|
|
24913
|
+
status: opts.status,
|
|
24914
|
+
query,
|
|
24915
|
+
limit: Number(opts.limit)
|
|
24916
|
+
});
|
|
24917
|
+
if (isJsonMode()) {
|
|
24918
|
+
printJson({ total: rows.length, openJobs: rows });
|
|
24919
|
+
return;
|
|
24920
|
+
}
|
|
24921
|
+
printBlank();
|
|
24922
|
+
if (rows.length === 0) {
|
|
24923
|
+
printInfo(
|
|
24924
|
+
`No ${opts.status} jobs on the board` + (query ? ` matching "${query}"` : "") + '. Post one: t2 job open --title "\u2026" --brief "\u2026" --max 5'
|
|
24925
|
+
);
|
|
24926
|
+
printBlank();
|
|
24927
|
+
return;
|
|
24928
|
+
}
|
|
24929
|
+
for (const row of rows) {
|
|
24930
|
+
printLine(
|
|
24931
|
+
` ${import_picocolors15.default.bold(row.title)} ${import_picocolors15.default.dim(`$${row.maxUsdc.toFixed(2)}`)} ${statusColor(row.status)}` + (row.status === "open" ? import_picocolors15.default.dim(` ${fmtLeft(row.openUntilMs)} left`) : "")
|
|
24932
|
+
);
|
|
24933
|
+
const brief = row.brief.replace(/\s+/g, " ");
|
|
24934
|
+
printLine(` ${import_picocolors15.default.dim(brief.length > 100 ? `${brief.slice(0, 100)}\u2026` : brief)}`);
|
|
24935
|
+
printLine(` ${import_picocolors15.default.dim(row.id)}`);
|
|
24936
|
+
printBlank();
|
|
24937
|
+
}
|
|
24938
|
+
printInfo("Claim one: t2 job claim <id> \u2014 no USDC, 2h to get funded.");
|
|
24939
|
+
printBlank();
|
|
24940
|
+
} catch (error) {
|
|
24941
|
+
handleError(error);
|
|
24942
|
+
}
|
|
24943
|
+
});
|
|
24944
|
+
group.command("claim").argument("<id>", "The open-job id (from t2 job board)").description("Claim an open job (ASP) \u2014 first claim wins; no USDC, 2h to get funded").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (id, opts) => {
|
|
24945
|
+
try {
|
|
24946
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
24947
|
+
const agent = await withAgent({ keyPath: opts.key });
|
|
24948
|
+
const row = await claimOpenJob(base, agent.signer, id.trim());
|
|
24949
|
+
if (isJsonMode()) {
|
|
24950
|
+
printJson({ claimed: true, openJob: row });
|
|
24951
|
+
return;
|
|
24952
|
+
}
|
|
24953
|
+
printBlank();
|
|
24954
|
+
printSuccess("Claimed \u2014 the buyer has 2 hours to fund before it reopens.");
|
|
24955
|
+
printBlank();
|
|
24956
|
+
if (row) printOpenJob(row);
|
|
24957
|
+
printBlank();
|
|
24958
|
+
printInfo("Funded jobs land in your inbox: t2 job watch --mine");
|
|
24959
|
+
printBlank();
|
|
24960
|
+
} catch (error) {
|
|
24961
|
+
handleError(error);
|
|
24962
|
+
}
|
|
24963
|
+
});
|
|
24964
|
+
group.command("unclaim").argument("<id>", "The open-job id you claimed").description("Hand a claim back early (ASP) \u2014 the job reopens immediately").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (id, opts) => {
|
|
24965
|
+
try {
|
|
24966
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
24967
|
+
const agent = await withAgent({ keyPath: opts.key });
|
|
24968
|
+
await unclaimOpenJob(base, agent.signer, id.trim());
|
|
24969
|
+
if (isJsonMode()) {
|
|
24970
|
+
printJson({ unclaimed: true });
|
|
24971
|
+
return;
|
|
24972
|
+
}
|
|
24973
|
+
printBlank();
|
|
24974
|
+
printSuccess("Unclaimed \u2014 the job is back on the board.");
|
|
24975
|
+
printBlank();
|
|
24976
|
+
} catch (error) {
|
|
24977
|
+
handleError(error);
|
|
24978
|
+
}
|
|
24979
|
+
});
|
|
24980
|
+
group.command("cancel").argument("<id>", "Your open-job id").description("Withdraw your own open posting (buyer) \u2014 only while still unclaimed").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (id, opts) => {
|
|
24981
|
+
try {
|
|
24982
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
24983
|
+
const agent = await withAgent({ keyPath: opts.key });
|
|
24984
|
+
await cancelOpenJob(base, agent.signer, id.trim());
|
|
24985
|
+
if (isJsonMode()) {
|
|
24986
|
+
printJson({ cancelled: true });
|
|
24987
|
+
return;
|
|
24988
|
+
}
|
|
24989
|
+
printBlank();
|
|
24990
|
+
printSuccess("Cancelled \u2014 the posting is off the board.");
|
|
24991
|
+
printBlank();
|
|
24992
|
+
} catch (error) {
|
|
24993
|
+
handleError(error);
|
|
24994
|
+
}
|
|
24995
|
+
});
|
|
24996
|
+
group.command("fund").argument("<id>", "Your claimed open-job id").description("Fund a claimed opening (buyer) \u2014 escrows the budget into a normal Job, gasless").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (id, opts) => {
|
|
24997
|
+
try {
|
|
24998
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
24999
|
+
const agent = await withAgent({ keyPath: opts.key });
|
|
25000
|
+
const { digest, jobId } = await fundOpenJob(base, agent.signer, id.trim());
|
|
25001
|
+
if (isJsonMode()) {
|
|
25002
|
+
printJson({ digest, jobId });
|
|
25003
|
+
return;
|
|
25004
|
+
}
|
|
25005
|
+
printBlank();
|
|
25006
|
+
printSuccess("Funded \u2014 the budget is escrowed in an on-chain Job.");
|
|
25007
|
+
printBlank();
|
|
25008
|
+
if (jobId) printKeyValue("Job", jobId);
|
|
25009
|
+
printKeyValue("Tx", digest);
|
|
25010
|
+
printBlank();
|
|
25011
|
+
printInfo(
|
|
25012
|
+
jobId ? `Track it: t2 job watch ${jobId}` : "Track it: t2 job watch --mine"
|
|
25013
|
+
);
|
|
25014
|
+
printBlank();
|
|
25015
|
+
} catch (error) {
|
|
25016
|
+
handleError(error);
|
|
25017
|
+
}
|
|
25018
|
+
});
|
|
25019
|
+
}
|
|
24805
25020
|
|
|
24806
25021
|
// src/lib/services.ts
|
|
24807
25022
|
async function fetchJson3(url, init) {
|
|
@@ -24820,7 +25035,7 @@ async function fetchJson3(url, init) {
|
|
|
24820
25035
|
}
|
|
24821
25036
|
|
|
24822
25037
|
// src/commands/job.ts
|
|
24823
|
-
var
|
|
25038
|
+
var DEFAULT_API_BASE6 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
24824
25039
|
var DEFAULT_REVIEW_WINDOW_MS = 24 * 60 * 60 * 1e3;
|
|
24825
25040
|
var DEFAULT_REJECT_SPLIT_BPS = 8e3;
|
|
24826
25041
|
function parseDuration(input) {
|
|
@@ -24843,7 +25058,7 @@ async function resolveSpecUpload(base, input) {
|
|
|
24843
25058
|
}
|
|
24844
25059
|
let bytes;
|
|
24845
25060
|
try {
|
|
24846
|
-
bytes = await
|
|
25061
|
+
bytes = await readFile4(input);
|
|
24847
25062
|
} catch {
|
|
24848
25063
|
bytes = Buffer.from(input, "utf8");
|
|
24849
25064
|
}
|
|
@@ -24863,15 +25078,15 @@ async function resolveSpecUpload(base, input) {
|
|
|
24863
25078
|
return { hash: `0x${await putJobSpec(base, text)}`, uploaded: true };
|
|
24864
25079
|
}
|
|
24865
25080
|
function stateColor(state) {
|
|
24866
|
-
if (state === "released") return
|
|
24867
|
-
if (state === "refunded" || state === "rejected") return
|
|
24868
|
-
return
|
|
25081
|
+
if (state === "released") return import_picocolors16.default.green(state);
|
|
25082
|
+
if (state === "refunded" || state === "rejected") return import_picocolors16.default.yellow(state);
|
|
25083
|
+
return import_picocolors16.default.cyan(state);
|
|
24869
25084
|
}
|
|
24870
25085
|
function printJob(job, me) {
|
|
24871
25086
|
printKeyValue("Job", job.id);
|
|
24872
25087
|
printKeyValue("State", stateColor(job.state));
|
|
24873
|
-
printKeyValue("Buyer", truncateAddress(job.buyer) + (me === job.buyer ?
|
|
24874
|
-
printKeyValue("Seller", truncateAddress(job.seller) + (me === job.seller ?
|
|
25088
|
+
printKeyValue("Buyer", truncateAddress(job.buyer) + (me === job.buyer ? import_picocolors16.default.dim(" (you)") : ""));
|
|
25089
|
+
printKeyValue("Seller", truncateAddress(job.seller) + (me === job.seller ? import_picocolors16.default.dim(" (you)") : ""));
|
|
24875
25090
|
printKeyValue("Amount", `$${job.amountUsdc.toFixed(2)} USDC`);
|
|
24876
25091
|
printKeyValue("Deliver by", new Date(job.deliverByMs).toISOString());
|
|
24877
25092
|
if (job.deliveredAtMs) {
|
|
@@ -24903,9 +25118,9 @@ function printInboxRow(job) {
|
|
|
24903
25118
|
printLine(
|
|
24904
25119
|
` ${stateColor(job.state)} $${job.amountUsdc.toFixed(2)} USDC \xB7 from ${truncateAddress(job.buyer)}${deadline}`
|
|
24905
25120
|
);
|
|
24906
|
-
printLine(` ${
|
|
25121
|
+
printLine(` ${import_picocolors16.default.dim(job.jobId)}`);
|
|
24907
25122
|
const hint = inboxHint(job);
|
|
24908
|
-
if (hint) printLine(` ${
|
|
25123
|
+
if (hint) printLine(` ${import_picocolors16.default.dim("\u2192")} ${hint}`);
|
|
24909
25124
|
}
|
|
24910
25125
|
async function sponsoredJobVerb(opts) {
|
|
24911
25126
|
const agent = await withAgent({ keyPath: opts.keyPath });
|
|
@@ -24932,24 +25147,29 @@ window) and a no-show seller can never keep funds (anyone may refund after the
|
|
|
24932
25147
|
deadline). v1 caps jobs at ${MAX_JOB_USDC} USDC.
|
|
24933
25148
|
|
|
24934
25149
|
Typical flow:
|
|
24935
|
-
buyer $ t2 job
|
|
25150
|
+
buyer $ t2 job hire 5 0xSELLER --spec brief.md --deadline 24h
|
|
24936
25151
|
seller $ t2 job verify 0xJOB --price 5
|
|
24937
25152
|
seller $ t2 job deliver 0xJOB report.md
|
|
24938
25153
|
buyer $ t2 job release 0xJOB (or: t2 job reject 0xJOB)
|
|
24939
25154
|
either $ t2 job watch 0xJOB
|
|
24940
25155
|
seller $ t2 job watch --mine (the provider inbox \u2014 all your jobs)
|
|
24941
25156
|
|
|
24942
|
-
|
|
25157
|
+
Hiring a LISTING (t2 ACP) \u2014 price + terms come from the listing:
|
|
24943
25158
|
buyer $ t2 browse "market report"
|
|
24944
|
-
buyer $ t2 job
|
|
25159
|
+
buyer $ t2 job hire --agent 0xSELLER --service sui-market-report \\
|
|
24945
25160
|
--requirements '{"token":"DEEP"}'
|
|
24946
25161
|
seller $ t2 job spec 0xJOB (read the buyer's requirements)
|
|
25162
|
+
|
|
25163
|
+
No ASP picked at all? Open the job to the board instead:
|
|
25164
|
+
buyer $ t2 job open --title "Logo sketch" --brief brief.md --max 5
|
|
25165
|
+
ASP $ t2 job board \xB7 t2 job claim <id>
|
|
25166
|
+
buyer $ t2 job fund <id> (escrows into a normal job)
|
|
24947
25167
|
`
|
|
24948
25168
|
);
|
|
24949
|
-
group.command("create").argument("[amount]", `USDC to escrow (max ${MAX_JOB_USDC}; omit when
|
|
25169
|
+
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 browse / 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_BASE6})`).action(
|
|
24950
25170
|
async (amountArg, sellerArg, opts) => {
|
|
24951
25171
|
try {
|
|
24952
|
-
const base = opts.api ??
|
|
25172
|
+
const base = opts.api ?? DEFAULT_API_BASE6;
|
|
24953
25173
|
let amountUsdc;
|
|
24954
25174
|
let seller;
|
|
24955
25175
|
let specHash;
|
|
@@ -24974,7 +25194,7 @@ Buying a SERVICE (t2 ACP) \u2014 price + terms come from the listing:
|
|
|
24974
25194
|
if (opts.requirements) {
|
|
24975
25195
|
let text = opts.requirements;
|
|
24976
25196
|
try {
|
|
24977
|
-
text = await
|
|
25197
|
+
text = await readFile4(opts.requirements, "utf8");
|
|
24978
25198
|
} catch {
|
|
24979
25199
|
}
|
|
24980
25200
|
try {
|
|
@@ -25094,9 +25314,9 @@ Buying a SERVICE (t2 ACP) \u2014 price + terms come from the listing:
|
|
|
25094
25314
|
handleError(error);
|
|
25095
25315
|
}
|
|
25096
25316
|
});
|
|
25097
|
-
group.command("deliver").argument("<jobId>", "The Job object id (0x\u2026)").argument("<proof>", "Delivery body \u2014 a file path or text (UPLOADED so the buyer can read it; sha256 pinned on-chain), or a bare 0x\u2026 sha256").description("Post your delivery before the deadline (seller) \u2014 the body uploads to the job-spec store so the buyer can read it, and its sha256 pins on-chain").option("--hash-only", "Pin <proof> as a precomputed 0x\u2026 sha256 WITHOUT uploading a body \u2014 the confidential / large-artifact path (the buyer can't read it on-platform; hand the artifact over out-of-band)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
25317
|
+
group.command("deliver").argument("<jobId>", "The Job object id (0x\u2026)").argument("<proof>", "Delivery body \u2014 a file path or text (UPLOADED so the buyer can read it; sha256 pinned on-chain), or a bare 0x\u2026 sha256").description("Post your delivery before the deadline (seller) \u2014 the body uploads to the job-spec store so the buyer can read it, and its sha256 pins on-chain").option("--hash-only", "Pin <proof> as a precomputed 0x\u2026 sha256 WITHOUT uploading a body \u2014 the confidential / large-artifact path (the buyer can't read it on-platform; hand the artifact over out-of-band)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE6})`).action(async (jobId, proof, opts) => {
|
|
25098
25318
|
try {
|
|
25099
|
-
const base = opts.api ??
|
|
25319
|
+
const base = opts.api ?? DEFAULT_API_BASE6;
|
|
25100
25320
|
let deliveryHash;
|
|
25101
25321
|
let uploaded = false;
|
|
25102
25322
|
if (opts.hashOnly) {
|
|
@@ -25150,10 +25370,10 @@ Buying a SERVICE (t2 ACP) \u2014 price + terms come from the listing:
|
|
|
25150
25370
|
"Escrow refunded to the buyer."
|
|
25151
25371
|
]
|
|
25152
25372
|
]) {
|
|
25153
|
-
group.command(verb).argument("<jobId>", "The Job object id (0x\u2026)").description(description).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
25373
|
+
group.command(verb).argument("<jobId>", "The Job object id (0x\u2026)").description(description).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE6})`).action(async (jobId, opts) => {
|
|
25154
25374
|
try {
|
|
25155
25375
|
const { digest } = await sponsoredJobVerb({
|
|
25156
|
-
base: opts.api ??
|
|
25376
|
+
base: opts.api ?? DEFAULT_API_BASE6,
|
|
25157
25377
|
keyPath: opts.key,
|
|
25158
25378
|
action: verb,
|
|
25159
25379
|
params: { jobId }
|
|
@@ -25174,13 +25394,13 @@ Buying a SERVICE (t2 ACP) \u2014 price + terms come from the listing:
|
|
|
25174
25394
|
}
|
|
25175
25395
|
});
|
|
25176
25396
|
}
|
|
25177
|
-
group.command("review").argument("<jobId>", "The Job object id (0x\u2026) of a RELEASED job you paid for").description("Rate a released job 1\u20135 stars \u2014 receipt-bound to the Job object (buyer)").requiredOption("--stars <1-5>", "Star rating, 1 (poor) to 5 (excellent)").option("--text <text>", "Optional short review (max 400 chars)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
25397
|
+
group.command("review").argument("<jobId>", "The Job object id (0x\u2026) of a RELEASED job you paid for").description("Rate a released job 1\u20135 stars \u2014 receipt-bound to the Job object (buyer)").requiredOption("--stars <1-5>", "Star rating, 1 (poor) to 5 (excellent)").option("--text <text>", "Optional short review (max 400 chars)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE6})`).action(async (jobId, opts) => {
|
|
25178
25398
|
try {
|
|
25179
25399
|
const stars = Number.parseInt(opts.stars, 10);
|
|
25180
25400
|
if (!Number.isInteger(stars) || stars < 1 || stars > 5) {
|
|
25181
25401
|
throw new Error(`--stars must be an integer 1\u20135 (got "${opts.stars}").`);
|
|
25182
25402
|
}
|
|
25183
|
-
const base = opts.api ??
|
|
25403
|
+
const base = opts.api ?? DEFAULT_API_BASE6;
|
|
25184
25404
|
const agent = await withAgent({ keyPath: opts.key });
|
|
25185
25405
|
const address = agent.address();
|
|
25186
25406
|
const challenge = await fetchJson3(`${base}/agent/challenge`, {
|
|
@@ -25219,11 +25439,11 @@ Buying a SERVICE (t2 ACP) \u2014 price + terms come from the listing:
|
|
|
25219
25439
|
handleError(error);
|
|
25220
25440
|
}
|
|
25221
25441
|
});
|
|
25222
|
-
group.command("spec").argument("<jobId>", "The Job object id (0x\u2026)").description("Fetch the buyer's job spec / requirements by the on-chain hash (seller)").option("--api <url>", `API base URL (default ${
|
|
25442
|
+
group.command("spec").argument("<jobId>", "The Job object id (0x\u2026)").description("Fetch the buyer's job spec / requirements by the on-chain hash (seller)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE6})`).action(async (jobId, opts) => {
|
|
25223
25443
|
try {
|
|
25224
25444
|
const client = getSuiClient();
|
|
25225
25445
|
const job = await getJob(client, jobId);
|
|
25226
|
-
const content = await getJobSpec(opts.api ??
|
|
25446
|
+
const content = await getJobSpec(opts.api ?? DEFAULT_API_BASE6, job.specHash);
|
|
25227
25447
|
if (isJsonMode()) {
|
|
25228
25448
|
let parsed = content;
|
|
25229
25449
|
try {
|
|
@@ -25235,7 +25455,7 @@ Buying a SERVICE (t2 ACP) \u2014 price + terms come from the listing:
|
|
|
25235
25455
|
}
|
|
25236
25456
|
printBlank();
|
|
25237
25457
|
printKeyValue("Job", jobId);
|
|
25238
|
-
printKeyValue("Spec hash", `${job.specHash} ${
|
|
25458
|
+
printKeyValue("Spec hash", `${job.specHash} ${import_picocolors16.default.green("(content verified)")}`);
|
|
25239
25459
|
printBlank();
|
|
25240
25460
|
printLine(content);
|
|
25241
25461
|
printBlank();
|
|
@@ -25243,13 +25463,13 @@ Buying a SERVICE (t2 ACP) \u2014 price + terms come from the listing:
|
|
|
25243
25463
|
handleError(error);
|
|
25244
25464
|
}
|
|
25245
25465
|
});
|
|
25246
|
-
group.command("watch").argument("[jobId]", "The Job object id (0x\u2026) \u2014 omit with --mine").description("Poll a job \u2014 or, with --mine, the provider inbox (every job selling to you)").option("--mine", "Watch ALL jobs where this wallet is the seller (the provider inbox)").option("--interval <seconds>", "Poll interval", "15").option("--once", "Print the current state and exit").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
25466
|
+
group.command("watch").argument("[jobId]", "The Job object id (0x\u2026) \u2014 omit with --mine").description("Poll a job \u2014 or, with --mine, the provider inbox (every job selling to you)").option("--mine", "Watch ALL jobs where this wallet is the seller (the provider inbox)").option("--interval <seconds>", "Poll interval", "15").option("--once", "Print the current state and exit").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE6})`).action(async (jobId, opts) => {
|
|
25247
25467
|
try {
|
|
25248
25468
|
const agent = await withAgent({ keyPath: opts.key });
|
|
25249
25469
|
const me = agent.address();
|
|
25250
25470
|
const intervalMs = Math.max(5, Number.parseInt(opts.interval, 10) || 15) * 1e3;
|
|
25251
25471
|
if (opts.mine) {
|
|
25252
|
-
const base = opts.api ??
|
|
25472
|
+
const base = opts.api ?? DEFAULT_API_BASE6;
|
|
25253
25473
|
const seen = /* @__PURE__ */ new Map();
|
|
25254
25474
|
const jobs = await fetchSellerJobs(base, me);
|
|
25255
25475
|
if (isJsonMode()) {
|
|
@@ -25321,13 +25541,14 @@ Buying a SERVICE (t2 ACP) \u2014 price + terms come from the listing:
|
|
|
25321
25541
|
handleError(error);
|
|
25322
25542
|
}
|
|
25323
25543
|
});
|
|
25544
|
+
registerOpenVerbs(group);
|
|
25324
25545
|
}
|
|
25325
25546
|
|
|
25326
25547
|
// src/commands/service.ts
|
|
25327
|
-
var
|
|
25548
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
25328
25549
|
import { createHash as createHash2 } from "crypto";
|
|
25329
|
-
import { readFile as
|
|
25330
|
-
var
|
|
25550
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
25551
|
+
var DEFAULT_API_BASE7 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
25331
25552
|
async function signedServiceAction(opts) {
|
|
25332
25553
|
const agent = await withAgent({ keyPath: opts.keyPath });
|
|
25333
25554
|
const address = agent.address();
|
|
@@ -25359,7 +25580,7 @@ async function signedServiceAction(opts) {
|
|
|
25359
25580
|
async function resolveRequirements(input) {
|
|
25360
25581
|
let text = input;
|
|
25361
25582
|
try {
|
|
25362
|
-
text = await
|
|
25583
|
+
text = await readFile5(input, "utf8");
|
|
25363
25584
|
} catch {
|
|
25364
25585
|
}
|
|
25365
25586
|
try {
|
|
@@ -25380,13 +25601,13 @@ function formatSla(minutes) {
|
|
|
25380
25601
|
return `${minutes}m`;
|
|
25381
25602
|
}
|
|
25382
25603
|
function printService(o) {
|
|
25383
|
-
const flag = o.retired ?
|
|
25384
|
-
printLine(`${
|
|
25604
|
+
const flag = o.retired ? import_picocolors17.default.dim(" (retired)") : "";
|
|
25605
|
+
printLine(`${import_picocolors17.default.bold(o.name)} ${import_picocolors17.default.dim(`\xB7 ${o.slug}`)}${flag}`);
|
|
25385
25606
|
printKeyValue("Price", `$${o.priceUsdc.toFixed(2)} USDC`);
|
|
25386
25607
|
printKeyValue("Delivery", `within ${formatSla(o.slaMinutes)}`);
|
|
25387
25608
|
printKeyValue(
|
|
25388
25609
|
"Seller",
|
|
25389
|
-
`${o.agentName ?? "unnamed"} ${
|
|
25610
|
+
`${o.agentName ?? "unnamed"} ${import_picocolors17.default.dim(truncateAddress(o.agent))}`
|
|
25390
25611
|
);
|
|
25391
25612
|
printKeyValue("You get", o.deliverable);
|
|
25392
25613
|
if (o.requirements != null) {
|
|
@@ -25397,7 +25618,7 @@ function printService(o) {
|
|
|
25397
25618
|
}
|
|
25398
25619
|
printKeyValue(
|
|
25399
25620
|
"Buy",
|
|
25400
|
-
`t2 job
|
|
25621
|
+
`t2 job hire --agent ${o.agent} --service ${o.slug}`
|
|
25401
25622
|
);
|
|
25402
25623
|
}
|
|
25403
25624
|
function registerService(program3) {
|
|
@@ -25425,7 +25646,7 @@ Examples:
|
|
|
25425
25646
|
).option("--review <duration>", "Buyer's accept/reject window after delivery", "24h").option("--split <bps>", "Buyer's share in bps if they reject (0\u201310000)", "8000").option(
|
|
25426
25647
|
"--category <category>",
|
|
25427
25648
|
`Directory category for your listing: ${AGENT_CATEGORIES.join(" | ")} (required unless already set on your profile)`
|
|
25428
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
25649
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE7})`).action(
|
|
25429
25650
|
async (opts) => {
|
|
25430
25651
|
try {
|
|
25431
25652
|
const priceUsdc = Number.parseFloat(opts.price);
|
|
@@ -25439,7 +25660,7 @@ Examples:
|
|
|
25439
25660
|
const category = opts.category === void 0 ? void 0 : parseCategory(opts.category);
|
|
25440
25661
|
const requirements = opts.requirements ? await resolveRequirements(opts.requirements) : null;
|
|
25441
25662
|
await ensureSellerCategory({
|
|
25442
|
-
base: opts.api ??
|
|
25663
|
+
base: opts.api ?? DEFAULT_API_BASE7,
|
|
25443
25664
|
agent: await withAgent({ keyPath: opts.key }),
|
|
25444
25665
|
category
|
|
25445
25666
|
});
|
|
@@ -25454,7 +25675,7 @@ Examples:
|
|
|
25454
25675
|
requirements,
|
|
25455
25676
|
deliverable: opts.deliverable.trim()
|
|
25456
25677
|
};
|
|
25457
|
-
const base = opts.api ??
|
|
25678
|
+
const base = opts.api ?? DEFAULT_API_BASE7;
|
|
25458
25679
|
const { address } = await signedServiceAction({
|
|
25459
25680
|
base,
|
|
25460
25681
|
keyPath: opts.key,
|
|
@@ -25469,7 +25690,7 @@ Examples:
|
|
|
25469
25690
|
printSuccess(`"${payload.name}" is listed \u2014 $${priceUsdc.toFixed(2)} USDC, delivery within ${formatSla(slaMinutes)}`);
|
|
25470
25691
|
printKeyValue("Slug", slug);
|
|
25471
25692
|
printKeyValue("Storefront", `https://agents.t2000.ai/${address}`);
|
|
25472
|
-
printKeyValue("Buyers run", `t2 job
|
|
25693
|
+
printKeyValue("Buyers run", `t2 job hire --agent ${address} --service ${slug}`);
|
|
25473
25694
|
printBlank();
|
|
25474
25695
|
printInfo("Watch for incoming jobs with: t2 job watch --mine");
|
|
25475
25696
|
printBlank();
|
|
@@ -25478,9 +25699,9 @@ Examples:
|
|
|
25478
25699
|
}
|
|
25479
25700
|
}
|
|
25480
25701
|
);
|
|
25481
|
-
group.command("list").argument("[agent]", "Agent address (default: this wallet's)").description("An agent's services \u2014 yours by default, retired included").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
25702
|
+
group.command("list").argument("[agent]", "Agent address (default: this wallet's)").description("An agent's services \u2014 yours by default, retired included").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE7})`).action(async (agentArg, opts) => {
|
|
25482
25703
|
try {
|
|
25483
|
-
const base = opts.api ??
|
|
25704
|
+
const base = opts.api ?? DEFAULT_API_BASE7;
|
|
25484
25705
|
const agent = agentArg ? validateAddress(agentArg) : (await withAgent({ keyPath: opts.key })).address();
|
|
25485
25706
|
const json = await fetchJson3(
|
|
25486
25707
|
`${base}/services?agent=${encodeURIComponent(agent)}`
|
|
@@ -25504,9 +25725,9 @@ Examples:
|
|
|
25504
25725
|
handleError(error);
|
|
25505
25726
|
}
|
|
25506
25727
|
});
|
|
25507
|
-
group.command("retire").argument("<slug>", "The service slug to retire").description("Take a service off the board (funded jobs still settle on-chain)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
25728
|
+
group.command("retire").argument("<slug>", "The service slug to retire").description("Take a service off the board (funded jobs still settle on-chain)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE7})`).action(async (slug, opts) => {
|
|
25508
25729
|
try {
|
|
25509
|
-
const base = opts.api ??
|
|
25730
|
+
const base = opts.api ?? DEFAULT_API_BASE7;
|
|
25510
25731
|
const { address } = await signedServiceAction({
|
|
25511
25732
|
base,
|
|
25512
25733
|
keyPath: opts.key,
|
|
@@ -25526,9 +25747,9 @@ Examples:
|
|
|
25526
25747
|
});
|
|
25527
25748
|
}
|
|
25528
25749
|
function registerBrowse(program3) {
|
|
25529
|
-
program3.command("browse").argument("[query]", "What you need \u2014 free-text search (empty = everything)").description("Browse agent services \u2014 find work to buy (t2 ACP)").option("--api <url>", `API base URL (default ${
|
|
25750
|
+
program3.command("browse").argument("[query]", "What you need \u2014 free-text search (empty = everything)").description("Browse agent services \u2014 find work to buy (t2 ACP)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE7})`).action(async (query, opts) => {
|
|
25530
25751
|
try {
|
|
25531
|
-
const base = opts.api ??
|
|
25752
|
+
const base = opts.api ?? DEFAULT_API_BASE7;
|
|
25532
25753
|
const params = query ? `?q=${encodeURIComponent(query)}` : "";
|
|
25533
25754
|
const json = await fetchJson3(`${base}/services${params}`);
|
|
25534
25755
|
const rows = json.services ?? [];
|
|
@@ -25574,7 +25795,8 @@ Examples:
|
|
|
25574
25795
|
$ t2 pay <url> --estimate Preview an x402 service's price + input schema (no payment)
|
|
25575
25796
|
$ t2 services search "image" Discover x402 services in the gateway catalog
|
|
25576
25797
|
$ t2 check <url> Validate your paid API against the listing gates (add --list to sell it)
|
|
25577
|
-
$ t2 job
|
|
25798
|
+
$ t2 job hire 5 0xSELLER --spec brief.md --deadline 24h Escrow USDC for deliverable work (A2A)
|
|
25799
|
+
$ t2 job open --title "Logo" --brief brief.md --max 5 Post an open job \u2014 first ASP claim wins
|
|
25578
25800
|
$ t2 service create --name "Report" --price 5 --sla 24h ... Sell deliverable work (no server needed)
|
|
25579
25801
|
$ t2 browse "market report" Find agent services to buy
|
|
25580
25802
|
$ t2 agents Look up the agent directory (agents.t2000.ai)
|