@t2000/cli 5.32.0 → 6.0.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/dist/index.js
CHANGED
|
@@ -10784,7 +10784,7 @@ var require_lib2 = __commonJS({
|
|
|
10784
10784
|
return matches;
|
|
10785
10785
|
};
|
|
10786
10786
|
exports.analyse = analyse;
|
|
10787
|
-
var detectFile = (filepath, opts = {}) => new Promise((
|
|
10787
|
+
var detectFile = (filepath, opts = {}) => new Promise((resolve2, reject) => {
|
|
10788
10788
|
let fd;
|
|
10789
10789
|
const fs = (0, node_1.default)();
|
|
10790
10790
|
const handler = (err, buffer) => {
|
|
@@ -10794,7 +10794,7 @@ var require_lib2 = __commonJS({
|
|
|
10794
10794
|
if (err) {
|
|
10795
10795
|
reject(err);
|
|
10796
10796
|
} else if (buffer) {
|
|
10797
|
-
|
|
10797
|
+
resolve2((0, exports.detect)(buffer));
|
|
10798
10798
|
} else {
|
|
10799
10799
|
reject(new Error("No error and no buffer received"));
|
|
10800
10800
|
}
|
|
@@ -18970,10 +18970,10 @@ var require_browser = __commonJS({
|
|
|
18970
18970
|
text = canvas;
|
|
18971
18971
|
canvas = void 0;
|
|
18972
18972
|
}
|
|
18973
|
-
return new Promise(function(
|
|
18973
|
+
return new Promise(function(resolve2, reject) {
|
|
18974
18974
|
try {
|
|
18975
18975
|
const data = QRCode.create(text, opts);
|
|
18976
|
-
|
|
18976
|
+
resolve2(renderFunc(data, canvas, opts));
|
|
18977
18977
|
} catch (e) {
|
|
18978
18978
|
reject(e);
|
|
18979
18979
|
}
|
|
@@ -19055,11 +19055,11 @@ var require_server = __commonJS({
|
|
|
19055
19055
|
}
|
|
19056
19056
|
function render(renderFunc, text, params) {
|
|
19057
19057
|
if (!params.cb) {
|
|
19058
|
-
return new Promise(function(
|
|
19058
|
+
return new Promise(function(resolve2, reject) {
|
|
19059
19059
|
try {
|
|
19060
19060
|
const data = QRCode.create(text, params.opts);
|
|
19061
19061
|
return renderFunc(data, params.opts, function(err, data2) {
|
|
19062
|
-
return err ? reject(err) :
|
|
19062
|
+
return err ? reject(err) : resolve2(data2);
|
|
19063
19063
|
});
|
|
19064
19064
|
} catch (e) {
|
|
19065
19065
|
reject(e);
|
|
@@ -30298,13 +30298,13 @@ var PromisePolyfill = class extends Promise {
|
|
|
30298
30298
|
// Available starting from Node 22
|
|
30299
30299
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
|
30300
30300
|
static withResolver() {
|
|
30301
|
-
let
|
|
30301
|
+
let resolve2;
|
|
30302
30302
|
let reject;
|
|
30303
30303
|
const promise = new Promise((res, rej) => {
|
|
30304
|
-
|
|
30304
|
+
resolve2 = res;
|
|
30305
30305
|
reject = rej;
|
|
30306
30306
|
});
|
|
30307
|
-
return { promise, resolve:
|
|
30307
|
+
return { promise, resolve: resolve2, reject };
|
|
30308
30308
|
}
|
|
30309
30309
|
};
|
|
30310
30310
|
|
|
@@ -30338,7 +30338,7 @@ function createPrompt(view) {
|
|
|
30338
30338
|
output
|
|
30339
30339
|
});
|
|
30340
30340
|
const screen = new ScreenManager(rl);
|
|
30341
|
-
const { promise, resolve:
|
|
30341
|
+
const { promise, resolve: resolve2, reject } = PromisePolyfill.withResolver();
|
|
30342
30342
|
const cancel = () => reject(new CancelPromptError());
|
|
30343
30343
|
if (signal) {
|
|
30344
30344
|
const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
|
|
@@ -30365,7 +30365,7 @@ function createPrompt(view) {
|
|
|
30365
30365
|
cycle(() => {
|
|
30366
30366
|
try {
|
|
30367
30367
|
const nextView = view(config, (value) => {
|
|
30368
|
-
setImmediate(() =>
|
|
30368
|
+
setImmediate(() => resolve2(value));
|
|
30369
30369
|
});
|
|
30370
30370
|
if (nextView === void 0) {
|
|
30371
30371
|
const callerFilename = callSites[1]?.getFileName();
|
|
@@ -33122,7 +33122,7 @@ function registerMcpStart(parent) {
|
|
|
33122
33122
|
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) => {
|
|
33123
33123
|
let mod3;
|
|
33124
33124
|
try {
|
|
33125
|
-
mod3 = await import("./dist-
|
|
33125
|
+
mod3 = await import("./dist-DYYYQUW7.js");
|
|
33126
33126
|
} catch {
|
|
33127
33127
|
console.error("MCP server not installed. Run:\n npm install -g @t2000/mcp");
|
|
33128
33128
|
process.exit(1);
|
|
@@ -33595,7 +33595,7 @@ For MCP-aware clients (Claude Desktop, Cursor, Windsurf), prefer
|
|
|
33595
33595
|
}
|
|
33596
33596
|
|
|
33597
33597
|
// src/commands/agent/index.ts
|
|
33598
|
-
import { createHash as
|
|
33598
|
+
import { createHash as createHash2 } from "crypto";
|
|
33599
33599
|
|
|
33600
33600
|
// src/commands/agent/create.ts
|
|
33601
33601
|
var DEFAULT_API_BASE3 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
@@ -33754,98 +33754,11 @@ function registerAgentCreate(group) {
|
|
|
33754
33754
|
});
|
|
33755
33755
|
}
|
|
33756
33756
|
|
|
33757
|
-
// src/commands/agent/review.ts
|
|
33758
|
-
import { createHash } from "crypto";
|
|
33759
|
-
var DEFAULT_GATEWAY = "https://x402.t2000.ai";
|
|
33760
|
-
async function fetchJson2(url, init) {
|
|
33761
|
-
const res = await fetch(url, {
|
|
33762
|
-
method: init?.method ?? "GET",
|
|
33763
|
-
headers: init?.body ? { "Content-Type": "application/json" } : void 0,
|
|
33764
|
-
body: init?.body ? JSON.stringify(init.body) : void 0
|
|
33765
|
-
});
|
|
33766
|
-
const json = await res.json().catch(() => ({}));
|
|
33767
|
-
if (!res.ok) {
|
|
33768
|
-
const err = json.error;
|
|
33769
|
-
throw new Error(typeof err === "string" ? err : `HTTP ${res.status}`);
|
|
33770
|
-
}
|
|
33771
|
-
return json;
|
|
33772
|
-
}
|
|
33773
|
-
function reviewMessage(digest, stars, text, timestamp) {
|
|
33774
|
-
const hash = createHash("sha256").update(text, "utf8").digest("hex");
|
|
33775
|
-
return `t2000-review:${digest}:${stars}:${hash}:${timestamp}`;
|
|
33776
|
-
}
|
|
33777
|
-
function registerAgentReview(agent) {
|
|
33778
|
-
agent.command("review").description(
|
|
33779
|
-
"Review a purchase (1-5 stars + optional text). Binds to your latest settled receipt with the seller, or --digest for a specific one. Re-run to edit. [Store v2]"
|
|
33780
|
-
).argument("<seller>", "Seller address (0x\u2026)").requiredOption("--stars <n>", "Rating 1-5").option("--text <text>", "Review text (\u2264400 chars)").option("--digest <digest>", "Collect digest of the specific purchase").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
|
|
33781
|
-
async (seller, opts) => {
|
|
33782
|
-
try {
|
|
33783
|
-
const stars = Number(opts.stars);
|
|
33784
|
-
if (!Number.isInteger(stars) || stars < 1 || stars > 5) {
|
|
33785
|
-
throw new Error("--stars must be an integer 1-5.");
|
|
33786
|
-
}
|
|
33787
|
-
const text = (opts.text ?? "").trim();
|
|
33788
|
-
if (text.length > 400) {
|
|
33789
|
-
throw new Error("--text must be \u2264 400 chars.");
|
|
33790
|
-
}
|
|
33791
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY;
|
|
33792
|
-
const agentW = await withAgent({ keyPath: opts.key });
|
|
33793
|
-
const buyer = agentW.address();
|
|
33794
|
-
let digest = (opts.digest ?? "").trim();
|
|
33795
|
-
if (!digest) {
|
|
33796
|
-
const res = await fetchJson2(
|
|
33797
|
-
`${gateway}/commerce/review?buyer=${buyer}&seller=${encodeURIComponent(seller)}`
|
|
33798
|
-
);
|
|
33799
|
-
const reviewable = res.reviewable ?? [];
|
|
33800
|
-
if (reviewable.length === 0) {
|
|
33801
|
-
throw new Error(
|
|
33802
|
-
"No settled purchase from this wallet to that seller \u2014 buy first (`t2 agent pay`), then review."
|
|
33803
|
-
);
|
|
33804
|
-
}
|
|
33805
|
-
digest = reviewable[0].digest;
|
|
33806
|
-
}
|
|
33807
|
-
const timestamp = Date.now();
|
|
33808
|
-
const message = new TextEncoder().encode(
|
|
33809
|
-
reviewMessage(digest, stars, text, timestamp)
|
|
33810
|
-
);
|
|
33811
|
-
const { signature } = await agentW.keypair.signPersonalMessage(message);
|
|
33812
|
-
await fetchJson2(`${gateway}/commerce/review`, {
|
|
33813
|
-
method: "POST",
|
|
33814
|
-
body: { digest, stars, text, timestamp, signature }
|
|
33815
|
-
});
|
|
33816
|
-
if (isJsonMode()) {
|
|
33817
|
-
printJson({ ok: true, digest, stars, text: text || null });
|
|
33818
|
-
return;
|
|
33819
|
-
}
|
|
33820
|
-
printBlank();
|
|
33821
|
-
printSuccess(
|
|
33822
|
-
`Review posted \u2014 ${"\u2605".repeat(stars)}${"\u2606".repeat(5 - stars)}${text ? ` "${text}"` : ""}`
|
|
33823
|
-
);
|
|
33824
|
-
printKeyValue("Receipt", digest);
|
|
33825
|
-
printKeyValue(
|
|
33826
|
-
"Listing",
|
|
33827
|
-
`https://agents.t2000.ai/${seller.startsWith("0x") ? seller : ""}`
|
|
33828
|
-
);
|
|
33829
|
-
printBlank();
|
|
33830
|
-
} catch (e) {
|
|
33831
|
-
handleError(e);
|
|
33832
|
-
}
|
|
33833
|
-
}
|
|
33834
|
-
);
|
|
33835
|
-
}
|
|
33836
|
-
|
|
33837
|
-
// src/commands/agent/serve.ts
|
|
33838
|
-
import { createHash as createHash3 } from "crypto";
|
|
33839
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
33840
|
-
import { createServer } from "http";
|
|
33841
|
-
import { join as join8, resolve as resolve2 } from "path";
|
|
33842
|
-
import { pathToFileURL } from "url";
|
|
33843
|
-
|
|
33844
33757
|
// src/commands/agent/services.ts
|
|
33845
|
-
import { createHash
|
|
33758
|
+
import { createHash } from "crypto";
|
|
33846
33759
|
import { readFileSync as readFileSync3 } from "fs";
|
|
33847
33760
|
var SLUG_RE = /^[a-z0-9][a-z0-9-]{1,39}$/;
|
|
33848
|
-
async function
|
|
33761
|
+
async function fetchJson2(url, init) {
|
|
33849
33762
|
const res = await fetch(url, {
|
|
33850
33763
|
method: init?.method ?? "GET",
|
|
33851
33764
|
headers: init?.body ? { "Content-Type": "application/json" } : void 0,
|
|
@@ -33869,7 +33782,7 @@ function canonicalServicesJson(services) {
|
|
|
33869
33782
|
);
|
|
33870
33783
|
}
|
|
33871
33784
|
async function getCatalog(base, address) {
|
|
33872
|
-
const res = await
|
|
33785
|
+
const res = await fetchJson2(
|
|
33873
33786
|
`${base}/agent/services?address=${encodeURIComponent(address)}`
|
|
33874
33787
|
);
|
|
33875
33788
|
return Array.isArray(res.services) ? res.services : [];
|
|
@@ -33877,7 +33790,7 @@ async function getCatalog(base, address) {
|
|
|
33877
33790
|
async function putCatalog(opts) {
|
|
33878
33791
|
const agent = await withAgent({ keyPath: opts.keyPath });
|
|
33879
33792
|
const address = agent.address();
|
|
33880
|
-
const challenge = await
|
|
33793
|
+
const challenge = await fetchJson2(`${opts.base}/agent/challenge`, {
|
|
33881
33794
|
method: "POST",
|
|
33882
33795
|
body: { address }
|
|
33883
33796
|
});
|
|
@@ -33885,12 +33798,12 @@ async function putCatalog(opts) {
|
|
|
33885
33798
|
if (!nonce) {
|
|
33886
33799
|
throw new Error("Failed to get a challenge nonce.");
|
|
33887
33800
|
}
|
|
33888
|
-
const digest =
|
|
33801
|
+
const digest = createHash("sha256").update(canonicalServicesJson(opts.services)).digest("hex");
|
|
33889
33802
|
const message = new TextEncoder().encode(
|
|
33890
33803
|
`t2000-agent-services:${nonce}:${digest}`
|
|
33891
33804
|
);
|
|
33892
33805
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
33893
|
-
const res = await
|
|
33806
|
+
const res = await fetchJson2(`${opts.base}/agent/services`, {
|
|
33894
33807
|
method: "POST",
|
|
33895
33808
|
body: { address, nonce, signature, services: opts.services }
|
|
33896
33809
|
});
|
|
@@ -34069,513 +33982,9 @@ function registerAgentServices(agentGroup, defaults) {
|
|
|
34069
33982
|
});
|
|
34070
33983
|
}
|
|
34071
33984
|
|
|
34072
|
-
// src/commands/agent/serve.ts
|
|
34073
|
-
var DEFAULT_API_BASE4 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
34074
|
-
var DEFAULT_GATEWAY2 = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
|
|
34075
|
-
var SLUG_RE2 = /^[a-z0-9][a-z0-9-]{1,39}$/;
|
|
34076
|
-
var MANIFEST = "t2serve.json";
|
|
34077
|
-
var HANDLER = "handler.mjs";
|
|
34078
|
-
var HANDLER_TEMPLATE = `// t2000 hosted handler (R1). Deploys with: t2 agent serve deploy
|
|
34079
|
-
//
|
|
34080
|
-
// Contract: one self-contained ES module (no imports \u2014 fetch/crypto/URL are
|
|
34081
|
-
// available as Workers globals). The gateway calls this ONLY for paid,
|
|
34082
|
-
// escrowed deliveries; on a 2xx your wallet is paid, on failure the buyer is
|
|
34083
|
-
// auto-refunded. Keep it fast (15s delivery timeout, 5s CPU cap).
|
|
34084
|
-
//
|
|
34085
|
-
// input \u2014 the buyer's request body (parsed JSON, or a raw string)
|
|
34086
|
-
// ctx \u2014 { agent, slug, buyer, secrets }
|
|
34087
|
-
// secrets = your vault (t2 agent serve secrets set KEY=value)
|
|
34088
|
-
export default async function handle(input, ctx) {
|
|
34089
|
-
// Example: compose public data and return a result.
|
|
34090
|
-
// const res = await fetch('https://api.example.com/data');
|
|
34091
|
-
// const data = await res.json();
|
|
34092
|
-
return {
|
|
34093
|
-
echo: input,
|
|
34094
|
-
from: ctx.slug,
|
|
34095
|
-
note: 'Replace this with your service logic.',
|
|
34096
|
-
};
|
|
34097
|
-
}
|
|
34098
|
-
`;
|
|
34099
|
-
var PROXY_TEMPLATE = `// t2000 hosted handler \u2014 "Proxy an API" template. You hold a key to an
|
|
34100
|
-
// API; this resells calls to it per-call, with your key never leaving the
|
|
34101
|
-
// t2000 vault. Setup:
|
|
34102
|
-
// 1. Edit UPSTREAM below.
|
|
34103
|
-
// 2. t2 agent serve secrets set UPSTREAM_KEY=<your api key>
|
|
34104
|
-
// 3. t2 agent serve deploy
|
|
34105
|
-
const UPSTREAM = 'https://api.example.com/v1/endpoint';
|
|
34106
|
-
|
|
34107
|
-
export default async function handle(input, ctx) {
|
|
34108
|
-
const res = await fetch(UPSTREAM, {
|
|
34109
|
-
method: 'POST',
|
|
34110
|
-
headers: {
|
|
34111
|
-
'content-type': 'application/json',
|
|
34112
|
-
// Adjust the auth scheme to your upstream (x-api-key, basic, \u2026).
|
|
34113
|
-
...(ctx.secrets?.UPSTREAM_KEY
|
|
34114
|
-
? { authorization: \`Bearer \${ctx.secrets.UPSTREAM_KEY}\` }
|
|
34115
|
-
: {}),
|
|
34116
|
-
},
|
|
34117
|
-
body: JSON.stringify(input ?? {}),
|
|
34118
|
-
});
|
|
34119
|
-
if (!res.ok) {
|
|
34120
|
-
// Throwing fails the delivery \u2192 the buyer is auto-refunded.
|
|
34121
|
-
throw new Error(\`Upstream error \${res.status}\`);
|
|
34122
|
-
}
|
|
34123
|
-
return await res.json();
|
|
34124
|
-
}
|
|
34125
|
-
`;
|
|
34126
|
-
var TEMPLATES = {
|
|
34127
|
-
default: HANDLER_TEMPLATE,
|
|
34128
|
-
proxy: PROXY_TEMPLATE
|
|
34129
|
-
};
|
|
34130
|
-
function readManifest(dir) {
|
|
34131
|
-
const p = join8(dir, MANIFEST);
|
|
34132
|
-
if (!existsSync4(p)) {
|
|
34133
|
-
throw new Error(
|
|
34134
|
-
`No ${MANIFEST} here \u2014 run \`t2 agent serve init\` first (or --dir <path>).`
|
|
34135
|
-
);
|
|
34136
|
-
}
|
|
34137
|
-
const m = JSON.parse(readFileSync4(p, "utf8"));
|
|
34138
|
-
const slug = String(m.slug ?? "").trim().toLowerCase();
|
|
34139
|
-
if (!SLUG_RE2.test(slug)) {
|
|
34140
|
-
throw new Error(`${MANIFEST}: slug must match [a-z0-9-], 2-40 chars.`);
|
|
34141
|
-
}
|
|
34142
|
-
if (!m.title?.trim() || !m.description?.trim()) {
|
|
34143
|
-
throw new Error(`${MANIFEST}: title and description are required.`);
|
|
34144
|
-
}
|
|
34145
|
-
const price = Number(m.price);
|
|
34146
|
-
if (!Number.isFinite(price) || price <= 0) {
|
|
34147
|
-
throw new Error(`${MANIFEST}: price must be a positive USDC amount.`);
|
|
34148
|
-
}
|
|
34149
|
-
return { ...m, slug };
|
|
34150
|
-
}
|
|
34151
|
-
function readHandler(dir) {
|
|
34152
|
-
const p = join8(dir, HANDLER);
|
|
34153
|
-
if (!existsSync4(p)) {
|
|
34154
|
-
throw new Error(`No ${HANDLER} here \u2014 run \`t2 agent serve init\` first.`);
|
|
34155
|
-
}
|
|
34156
|
-
const src = readFileSync4(p, "utf8");
|
|
34157
|
-
if (!src.trim()) {
|
|
34158
|
-
throw new Error(`${HANDLER} is empty.`);
|
|
34159
|
-
}
|
|
34160
|
-
if (/^\s*import\s.+from\s/m.test(src)) {
|
|
34161
|
-
throw new Error(
|
|
34162
|
-
`${HANDLER} must be self-contained (no imports) \u2014 fetch, crypto, and URL are available as globals.`
|
|
34163
|
-
);
|
|
34164
|
-
}
|
|
34165
|
-
return src;
|
|
34166
|
-
}
|
|
34167
|
-
async function fetchJson4(url, init) {
|
|
34168
|
-
const res = await fetch(url, {
|
|
34169
|
-
method: init?.method ?? "GET",
|
|
34170
|
-
headers: init?.body ? { "Content-Type": "application/json" } : void 0,
|
|
34171
|
-
body: init?.body ? JSON.stringify(init.body) : void 0
|
|
34172
|
-
});
|
|
34173
|
-
const json = await res.json().catch(() => ({}));
|
|
34174
|
-
if (!res.ok) {
|
|
34175
|
-
const err = json.error;
|
|
34176
|
-
const msg = typeof err === "string" ? err : err?.message ?? `HTTP ${res.status}`;
|
|
34177
|
-
throw new Error(msg);
|
|
34178
|
-
}
|
|
34179
|
-
return json;
|
|
34180
|
-
}
|
|
34181
|
-
function registerAgentServe(agentGroup) {
|
|
34182
|
-
const group = agentGroup.command("serve").description(
|
|
34183
|
-
"Hosted handlers \u2014 deploy a function to t2000 compute and sell it per call. No server, no wrap. [R1]"
|
|
34184
|
-
);
|
|
34185
|
-
group.command("init").description(`Scaffold ${HANDLER} + ${MANIFEST} in the current directory.`).option("--slug <slug>", "Service slug (in the buy URL)", "my-service").option(
|
|
34186
|
-
"--template <name>",
|
|
34187
|
-
`Handler template: ${Object.keys(TEMPLATES).join(" | ")} (proxy = resell a keyed API)`,
|
|
34188
|
-
"default"
|
|
34189
|
-
).option("--dir <path>", "Target directory (default: cwd)").action((opts) => {
|
|
34190
|
-
try {
|
|
34191
|
-
const dir = resolve2(opts.dir ?? ".");
|
|
34192
|
-
mkdirSync2(dir, { recursive: true });
|
|
34193
|
-
const slug = opts.slug.trim().toLowerCase();
|
|
34194
|
-
if (!SLUG_RE2.test(slug)) {
|
|
34195
|
-
throw new Error("--slug must match [a-z0-9-], 2-40 chars.");
|
|
34196
|
-
}
|
|
34197
|
-
const template = TEMPLATES[opts.template];
|
|
34198
|
-
if (!template) {
|
|
34199
|
-
throw new Error(
|
|
34200
|
-
`Unknown --template "${opts.template}" \u2014 use: ${Object.keys(TEMPLATES).join(", ")}.`
|
|
34201
|
-
);
|
|
34202
|
-
}
|
|
34203
|
-
const manifestPath = join8(dir, MANIFEST);
|
|
34204
|
-
const handlerPath = join8(dir, HANDLER);
|
|
34205
|
-
if (existsSync4(manifestPath) || existsSync4(handlerPath)) {
|
|
34206
|
-
throw new Error(`${MANIFEST} or ${HANDLER} already exists here.`);
|
|
34207
|
-
}
|
|
34208
|
-
writeFileSync3(
|
|
34209
|
-
manifestPath,
|
|
34210
|
-
`${JSON.stringify(
|
|
34211
|
-
{
|
|
34212
|
-
slug,
|
|
34213
|
-
title: "My service",
|
|
34214
|
-
description: "What the buyer gets, in one or two sentences. Provide: 1. \u2026",
|
|
34215
|
-
price: "0.02",
|
|
34216
|
-
input: "JSON body with your parameters"
|
|
34217
|
-
},
|
|
34218
|
-
null,
|
|
34219
|
-
2
|
|
34220
|
-
)}
|
|
34221
|
-
`
|
|
34222
|
-
);
|
|
34223
|
-
writeFileSync3(handlerPath, template);
|
|
34224
|
-
if (isJsonMode()) {
|
|
34225
|
-
printJson({ dir, files: [MANIFEST, HANDLER] });
|
|
34226
|
-
return;
|
|
34227
|
-
}
|
|
34228
|
-
printBlank();
|
|
34229
|
-
printSuccess("Scaffolded a hosted handler");
|
|
34230
|
-
printKeyValue("Handler", handlerPath);
|
|
34231
|
-
printKeyValue("Manifest", manifestPath);
|
|
34232
|
-
printBlank();
|
|
34233
|
-
printLine("Next:");
|
|
34234
|
-
printLine(" t2 agent serve dev # try it locally");
|
|
34235
|
-
printLine(" t2 agent serve deploy # deploy + list it for sale");
|
|
34236
|
-
printBlank();
|
|
34237
|
-
} catch (error) {
|
|
34238
|
-
handleError(error);
|
|
34239
|
-
}
|
|
34240
|
-
});
|
|
34241
|
-
group.command("dev").description(
|
|
34242
|
-
"Run the handler locally against the delivery contract (POST {input} to :8787)."
|
|
34243
|
-
).option("--dir <path>", "Handler directory (default: cwd)").option("--port <port>", "Port (default 8787)", "8787").option("--input <json>", "One-shot: invoke once with this input and exit").action(async (opts) => {
|
|
34244
|
-
try {
|
|
34245
|
-
const dir = resolve2(opts.dir ?? ".");
|
|
34246
|
-
const manifest = readManifest(dir);
|
|
34247
|
-
readHandler(dir);
|
|
34248
|
-
const mod3 = await import(pathToFileURL(join8(dir, HANDLER)).href);
|
|
34249
|
-
const fn = mod3.default;
|
|
34250
|
-
if (typeof fn !== "function") {
|
|
34251
|
-
throw new Error(`${HANDLER} must default-export a function.`);
|
|
34252
|
-
}
|
|
34253
|
-
const ctx = {
|
|
34254
|
-
agent: "0xLOCAL",
|
|
34255
|
-
slug: manifest.slug,
|
|
34256
|
-
buyer: "0xBUYER"
|
|
34257
|
-
};
|
|
34258
|
-
if (opts.input !== void 0) {
|
|
34259
|
-
let input = opts.input;
|
|
34260
|
-
try {
|
|
34261
|
-
input = JSON.parse(opts.input);
|
|
34262
|
-
} catch {
|
|
34263
|
-
}
|
|
34264
|
-
const out = await fn(input, ctx);
|
|
34265
|
-
printJson({ ok: true, output: out });
|
|
34266
|
-
return;
|
|
34267
|
-
}
|
|
34268
|
-
const port = Number(opts.port) || 8787;
|
|
34269
|
-
const server = createServer(async (req, res) => {
|
|
34270
|
-
const chunks = [];
|
|
34271
|
-
for await (const c of req) {
|
|
34272
|
-
chunks.push(c);
|
|
34273
|
-
}
|
|
34274
|
-
const raw = Buffer.concat(chunks).toString("utf8");
|
|
34275
|
-
let input = raw;
|
|
34276
|
-
try {
|
|
34277
|
-
input = raw ? JSON.parse(raw) : {};
|
|
34278
|
-
} catch {
|
|
34279
|
-
}
|
|
34280
|
-
try {
|
|
34281
|
-
const out = await fn(input, ctx);
|
|
34282
|
-
res.writeHead(200, { "content-type": "application/json" });
|
|
34283
|
-
res.end(JSON.stringify(out));
|
|
34284
|
-
} catch (e) {
|
|
34285
|
-
res.writeHead(500, { "content-type": "application/json" });
|
|
34286
|
-
res.end(
|
|
34287
|
-
JSON.stringify({ error: e instanceof Error ? e.message : String(e) })
|
|
34288
|
-
);
|
|
34289
|
-
}
|
|
34290
|
-
});
|
|
34291
|
-
server.listen(port, () => {
|
|
34292
|
-
printBlank();
|
|
34293
|
-
printSuccess(`Local handler running \u2014 slug "${manifest.slug}"`);
|
|
34294
|
-
printLine(` curl -X POST http://localhost:${port} -d '{"hello":"world"}'`);
|
|
34295
|
-
printLine(" Ctrl-C to stop.");
|
|
34296
|
-
printBlank();
|
|
34297
|
-
});
|
|
34298
|
-
} catch (error) {
|
|
34299
|
-
handleError(error);
|
|
34300
|
-
}
|
|
34301
|
-
});
|
|
34302
|
-
group.command("deploy").description(
|
|
34303
|
-
"Deploy the handler to t2000 compute + list the SKU in your catalog. Sponsored listing, per-call earnings to your wallet."
|
|
34304
|
-
).option("--dir <path>", "Handler directory (default: cwd)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).option("--gateway <url>", `Gateway URL (default ${DEFAULT_GATEWAY2})`).action(
|
|
34305
|
-
async (opts) => {
|
|
34306
|
-
try {
|
|
34307
|
-
const dir = resolve2(opts.dir ?? ".");
|
|
34308
|
-
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34309
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
|
|
34310
|
-
const manifest = readManifest(dir);
|
|
34311
|
-
const script = readHandler(dir);
|
|
34312
|
-
const scriptB64 = Buffer.from(script, "utf8").toString("base64");
|
|
34313
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
34314
|
-
const address = agent.address();
|
|
34315
|
-
const ts = Date.now();
|
|
34316
|
-
const bodyHash = createHash3("sha256").update(`${manifest.slug}|${scriptB64}`).digest("hex");
|
|
34317
|
-
const message = new TextEncoder().encode(
|
|
34318
|
-
`t2000-serve:${ts}:${bodyHash}`
|
|
34319
|
-
);
|
|
34320
|
-
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34321
|
-
const deployed = await fetchJson4(`${gateway}/serve/deploy`, {
|
|
34322
|
-
method: "POST",
|
|
34323
|
-
body: {
|
|
34324
|
-
address,
|
|
34325
|
-
slug: manifest.slug,
|
|
34326
|
-
script: scriptB64,
|
|
34327
|
-
timestamp: ts,
|
|
34328
|
-
signature
|
|
34329
|
-
}
|
|
34330
|
-
});
|
|
34331
|
-
const catalog = await getCatalog(base, address);
|
|
34332
|
-
const entry = {
|
|
34333
|
-
slug: manifest.slug,
|
|
34334
|
-
title: manifest.title,
|
|
34335
|
-
description: manifest.description,
|
|
34336
|
-
priceUsdc: String(manifest.price),
|
|
34337
|
-
input: manifest.input ?? null,
|
|
34338
|
-
endpoint: null,
|
|
34339
|
-
method: "POST",
|
|
34340
|
-
active: true
|
|
34341
|
-
};
|
|
34342
|
-
const next = [
|
|
34343
|
-
...catalog.filter((s) => s.slug !== manifest.slug),
|
|
34344
|
-
entry
|
|
34345
|
-
];
|
|
34346
|
-
await putCatalog({ base, keyPath: opts.key, services: next });
|
|
34347
|
-
const buyUrl = String(
|
|
34348
|
-
deployed.buyUrl ?? `https://x402.t2000.ai/commerce/pay/${address}/${manifest.slug}`
|
|
34349
|
-
);
|
|
34350
|
-
if (isJsonMode()) {
|
|
34351
|
-
printJson({
|
|
34352
|
-
address,
|
|
34353
|
-
slug: manifest.slug,
|
|
34354
|
-
sizeBytes: deployed.sizeBytes,
|
|
34355
|
-
listed: true,
|
|
34356
|
-
buyUrl
|
|
34357
|
-
});
|
|
34358
|
-
return;
|
|
34359
|
-
}
|
|
34360
|
-
printBlank();
|
|
34361
|
-
printSuccess(`Deployed "${manifest.slug}" to t2000 compute`);
|
|
34362
|
-
printKeyValue("Buy URL", buyUrl);
|
|
34363
|
-
printKeyValue("Price", `$${manifest.price} per call`);
|
|
34364
|
-
printKeyValue("Store", `https://agents.t2000.ai/${address}`);
|
|
34365
|
-
printBlank();
|
|
34366
|
-
printLine(" t2 agent serve logs # invocations");
|
|
34367
|
-
printLine(" t2 agent serve undeploy --slug " + manifest.slug);
|
|
34368
|
-
printBlank();
|
|
34369
|
-
} catch (error) {
|
|
34370
|
-
handleError(error);
|
|
34371
|
-
}
|
|
34372
|
-
}
|
|
34373
|
-
);
|
|
34374
|
-
const secrets = group.command("secrets").description(
|
|
34375
|
-
"This agent's handler secrets vault \u2014 encrypted at t2000, injected as ctx.secrets on paid deliveries only. Values are write-only."
|
|
34376
|
-
);
|
|
34377
|
-
secrets.command("set").argument("<pairs...>", "NAME=value pairs (e.g. UPSTREAM_KEY=sk-\u2026)").description("Set (or overwrite) vault secrets. NAME: A-Z, 0-9, _.").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--gateway <url>", `Gateway URL (default ${DEFAULT_GATEWAY2})`).action(
|
|
34378
|
-
async (pairs, opts) => {
|
|
34379
|
-
try {
|
|
34380
|
-
const updates = {};
|
|
34381
|
-
for (const pair of pairs) {
|
|
34382
|
-
const eq = pair.indexOf("=");
|
|
34383
|
-
if (eq <= 0) {
|
|
34384
|
-
throw new Error(`"${pair}" is not NAME=value.`);
|
|
34385
|
-
}
|
|
34386
|
-
updates[pair.slice(0, eq).trim()] = pair.slice(eq + 1);
|
|
34387
|
-
}
|
|
34388
|
-
const res = await postSecrets(opts, "set", updates);
|
|
34389
|
-
if (isJsonMode()) {
|
|
34390
|
-
printJson({ names: res.names });
|
|
34391
|
-
return;
|
|
34392
|
-
}
|
|
34393
|
-
printBlank();
|
|
34394
|
-
printSuccess("Vault updated");
|
|
34395
|
-
printKeyValue("Secrets", res.names.join(", ") || "(none)");
|
|
34396
|
-
printInfo("Handlers read them as ctx.secrets.NAME on paid deliveries.");
|
|
34397
|
-
printBlank();
|
|
34398
|
-
} catch (error) {
|
|
34399
|
-
handleError(error);
|
|
34400
|
-
}
|
|
34401
|
-
}
|
|
34402
|
-
);
|
|
34403
|
-
secrets.command("unset").argument("<names...>", "Secret names to delete").description("Delete vault secrets.").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--gateway <url>", `Gateway URL (default ${DEFAULT_GATEWAY2})`).action(
|
|
34404
|
-
async (names, opts) => {
|
|
34405
|
-
try {
|
|
34406
|
-
const updates = {};
|
|
34407
|
-
for (const n of names) {
|
|
34408
|
-
updates[n.trim()] = "";
|
|
34409
|
-
}
|
|
34410
|
-
const res = await postSecrets(opts, "set", updates);
|
|
34411
|
-
if (isJsonMode()) {
|
|
34412
|
-
printJson({ names: res.names });
|
|
34413
|
-
return;
|
|
34414
|
-
}
|
|
34415
|
-
printBlank();
|
|
34416
|
-
printSuccess("Vault updated");
|
|
34417
|
-
printKeyValue("Secrets", res.names.join(", ") || "(none)");
|
|
34418
|
-
printBlank();
|
|
34419
|
-
} catch (error) {
|
|
34420
|
-
handleError(error);
|
|
34421
|
-
}
|
|
34422
|
-
}
|
|
34423
|
-
);
|
|
34424
|
-
secrets.command("list").description("List vault secret NAMES (values never leave the gateway).").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--gateway <url>", `Gateway URL (default ${DEFAULT_GATEWAY2})`).action(async (opts) => {
|
|
34425
|
-
try {
|
|
34426
|
-
const res = await postSecrets(opts, "list");
|
|
34427
|
-
if (isJsonMode()) {
|
|
34428
|
-
printJson({ names: res.names });
|
|
34429
|
-
return;
|
|
34430
|
-
}
|
|
34431
|
-
const names = res.names;
|
|
34432
|
-
printBlank();
|
|
34433
|
-
if (names.length === 0) {
|
|
34434
|
-
printLine("Vault is empty. Set one: t2 agent serve secrets set NAME=value");
|
|
34435
|
-
} else {
|
|
34436
|
-
for (const n of names) {
|
|
34437
|
-
printLine(` ${n}`);
|
|
34438
|
-
}
|
|
34439
|
-
}
|
|
34440
|
-
printBlank();
|
|
34441
|
-
} catch (error) {
|
|
34442
|
-
handleError(error);
|
|
34443
|
-
}
|
|
34444
|
-
});
|
|
34445
|
-
async function postSecrets(opts, op, updates) {
|
|
34446
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
|
|
34447
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
34448
|
-
const address = agent.address();
|
|
34449
|
-
const ts = Date.now();
|
|
34450
|
-
const payload = op === "list" ? "list" : JSON.stringify(
|
|
34451
|
-
Object.fromEntries(
|
|
34452
|
-
Object.entries(updates ?? {}).sort(
|
|
34453
|
-
([a], [b]) => a.localeCompare(b)
|
|
34454
|
-
)
|
|
34455
|
-
)
|
|
34456
|
-
);
|
|
34457
|
-
const bodyHash = createHash3("sha256").update(payload).digest("hex");
|
|
34458
|
-
const message = new TextEncoder().encode(
|
|
34459
|
-
`t2000-serve-secrets:${ts}:${bodyHash}`
|
|
34460
|
-
);
|
|
34461
|
-
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34462
|
-
return await fetchJson4(`${gateway}/serve/secrets`, {
|
|
34463
|
-
method: "POST",
|
|
34464
|
-
body: {
|
|
34465
|
-
address,
|
|
34466
|
-
op,
|
|
34467
|
-
...op === "set" ? { updates } : {},
|
|
34468
|
-
timestamp: ts,
|
|
34469
|
-
signature
|
|
34470
|
-
}
|
|
34471
|
-
});
|
|
34472
|
-
}
|
|
34473
|
-
group.command("status").description("Deployed handlers + invocation stats.").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--gateway <url>", `Gateway URL (default ${DEFAULT_GATEWAY2})`).action(async (opts) => {
|
|
34474
|
-
try {
|
|
34475
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
|
|
34476
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
34477
|
-
const address = agent.address();
|
|
34478
|
-
const res = await fetchJson4(
|
|
34479
|
-
`${gateway}/serve/status?address=${encodeURIComponent(address)}`
|
|
34480
|
-
);
|
|
34481
|
-
if (isJsonMode()) {
|
|
34482
|
-
printJson(res);
|
|
34483
|
-
return;
|
|
34484
|
-
}
|
|
34485
|
-
const handlers = res.handlers ?? [];
|
|
34486
|
-
printBlank();
|
|
34487
|
-
if (handlers.length === 0) {
|
|
34488
|
-
printLine("No hosted handlers. Start one: t2 agent serve init");
|
|
34489
|
-
printBlank();
|
|
34490
|
-
return;
|
|
34491
|
-
}
|
|
34492
|
-
for (const h of handlers) {
|
|
34493
|
-
printLine(
|
|
34494
|
-
` ${h.slug} ${h.active ? "live" : "undeployed"} \xB7 ${(h.sizeBytes / 1024).toFixed(1)} KB \xB7 ${h.invocations} invocation${h.invocations === 1 ? "" : "s"}${h.lastInvocation ? ` \xB7 last ${h.lastInvocation.status} @ ${h.lastInvocation.at}` : ""}`
|
|
34495
|
-
);
|
|
34496
|
-
}
|
|
34497
|
-
printBlank();
|
|
34498
|
-
} catch (error) {
|
|
34499
|
-
handleError(error);
|
|
34500
|
-
}
|
|
34501
|
-
});
|
|
34502
|
-
group.command("logs").description("Recent invocations (status \xB7 duration \xB7 error).").option("--slug <slug>", "Filter to one handler").option("--limit <n>", "Rows (default 50)", "50").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--gateway <url>", `Gateway URL (default ${DEFAULT_GATEWAY2})`).action(
|
|
34503
|
-
async (opts) => {
|
|
34504
|
-
try {
|
|
34505
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
|
|
34506
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
34507
|
-
const address = agent.address();
|
|
34508
|
-
const params = new URLSearchParams({
|
|
34509
|
-
address,
|
|
34510
|
-
limit: opts.limit
|
|
34511
|
-
});
|
|
34512
|
-
if (opts.slug) {
|
|
34513
|
-
params.set("slug", opts.slug);
|
|
34514
|
-
}
|
|
34515
|
-
const res = await fetchJson4(`${gateway}/serve/logs?${params}`);
|
|
34516
|
-
if (isJsonMode()) {
|
|
34517
|
-
printJson(res);
|
|
34518
|
-
return;
|
|
34519
|
-
}
|
|
34520
|
-
const rows = res.invocations ?? [];
|
|
34521
|
-
printBlank();
|
|
34522
|
-
if (rows.length === 0) {
|
|
34523
|
-
printLine("No invocations yet.");
|
|
34524
|
-
printBlank();
|
|
34525
|
-
return;
|
|
34526
|
-
}
|
|
34527
|
-
for (const r of rows) {
|
|
34528
|
-
printLine(
|
|
34529
|
-
` ${r.at} ${r.slug} ${r.status} ${r.durationMs}ms${r.error ? ` ${r.error}` : ""}`
|
|
34530
|
-
);
|
|
34531
|
-
}
|
|
34532
|
-
printBlank();
|
|
34533
|
-
} catch (error) {
|
|
34534
|
-
handleError(error);
|
|
34535
|
-
}
|
|
34536
|
-
}
|
|
34537
|
-
);
|
|
34538
|
-
group.command("undeploy").description(
|
|
34539
|
-
"Remove a hosted handler (the SKU stays in the catalog \u2014 deactivate it with `t2 agent services update --slug \u2026 --inactive` if wanted)."
|
|
34540
|
-
).requiredOption("--slug <slug>", "Handler slug to remove").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--gateway <url>", `Gateway URL (default ${DEFAULT_GATEWAY2})`).action(
|
|
34541
|
-
async (opts) => {
|
|
34542
|
-
try {
|
|
34543
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY2;
|
|
34544
|
-
const slug = opts.slug.trim().toLowerCase();
|
|
34545
|
-
if (!SLUG_RE2.test(slug)) {
|
|
34546
|
-
throw new Error("--slug must match [a-z0-9-], 2-40 chars.");
|
|
34547
|
-
}
|
|
34548
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
34549
|
-
const address = agent.address();
|
|
34550
|
-
const ts = Date.now();
|
|
34551
|
-
const message = new TextEncoder().encode(
|
|
34552
|
-
`t2000-serve-remove:${ts}:${slug}`
|
|
34553
|
-
);
|
|
34554
|
-
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34555
|
-
await fetchJson4(`${gateway}/serve/undeploy`, {
|
|
34556
|
-
method: "POST",
|
|
34557
|
-
body: { address, slug, timestamp: ts, signature }
|
|
34558
|
-
});
|
|
34559
|
-
if (isJsonMode()) {
|
|
34560
|
-
printJson({ address, slug, undeployed: true });
|
|
34561
|
-
return;
|
|
34562
|
-
}
|
|
34563
|
-
printBlank();
|
|
34564
|
-
printSuccess(`Undeployed "${slug}"`);
|
|
34565
|
-
printInfo(
|
|
34566
|
-
"Buys against it now fail closed (auto-refund). Redeploy anytime: t2 agent serve deploy"
|
|
34567
|
-
);
|
|
34568
|
-
printBlank();
|
|
34569
|
-
} catch (error) {
|
|
34570
|
-
handleError(error);
|
|
34571
|
-
}
|
|
34572
|
-
}
|
|
34573
|
-
);
|
|
34574
|
-
}
|
|
34575
|
-
|
|
34576
33985
|
// src/commands/agent/index.ts
|
|
34577
|
-
var
|
|
34578
|
-
var
|
|
33986
|
+
var DEFAULT_API_BASE4 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
33987
|
+
var DEFAULT_GATEWAY = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
|
|
34579
33988
|
var DEFAULT_RAIL = process.env.T2000_RAIL_URL ?? "https://x402.t2000.ai";
|
|
34580
33989
|
var AGENT_CATEGORIES2 = [
|
|
34581
33990
|
"ai-models",
|
|
@@ -34614,19 +34023,19 @@ async function fundCredit(agent, base, amountStr, assetOpt) {
|
|
|
34614
34023
|
throw new Error(`amount must be a positive number (got "${amountStr}").`);
|
|
34615
34024
|
}
|
|
34616
34025
|
const asset = normalizeTopupAsset(assetOpt);
|
|
34617
|
-
const cfg = await
|
|
34026
|
+
const cfg = await fetchJson3(`${base}/agent/topup`, { method: "GET" });
|
|
34618
34027
|
const treasury = cfg.treasury;
|
|
34619
34028
|
if (!treasury) {
|
|
34620
34029
|
throw new Error("Could not resolve the t2000 treasury address.");
|
|
34621
34030
|
}
|
|
34622
34031
|
const sent = await agent.send({ to: treasury, amount, asset });
|
|
34623
|
-
const topup = await
|
|
34032
|
+
const topup = await fetchJson3(`${base}/agent/topup`, {
|
|
34624
34033
|
method: "POST",
|
|
34625
34034
|
body: { address: agent.address(), digest: sent.tx }
|
|
34626
34035
|
});
|
|
34627
34036
|
return { amount, asset, balanceUsd: topup.balanceUsd };
|
|
34628
34037
|
}
|
|
34629
|
-
async function
|
|
34038
|
+
async function fetchJson3(url, init) {
|
|
34630
34039
|
const res = await fetch(url, {
|
|
34631
34040
|
method: init.method,
|
|
34632
34041
|
headers: init.body ? { "Content-Type": "application/json" } : void 0,
|
|
@@ -34654,15 +34063,13 @@ Subcommands:
|
|
|
34654
34063
|
`
|
|
34655
34064
|
);
|
|
34656
34065
|
registerAgentCreate(group);
|
|
34657
|
-
registerAgentServices(group, { apiBase:
|
|
34658
|
-
registerAgentServe(group);
|
|
34659
|
-
registerAgentReview(group);
|
|
34066
|
+
registerAgentServices(group, { apiBase: DEFAULT_API_BASE4 });
|
|
34660
34067
|
group.command("onboard").description(
|
|
34661
34068
|
"Buy-side setup: fund credit (gasless USDC/USDsui) + mint a Private API key. Registering an Agent ID is free and separate \u2014 `t2 init` / `t2 agent register`."
|
|
34662
|
-
).option("--fund <amount>", "Stablecoin amount to deposit as credit (omit if already funded)").option("--asset <asset>", "USDC (default) or USDsui", "USDC").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34069
|
+
).option("--fund <amount>", "Stablecoin amount to deposit as credit (omit if already funded)").option("--asset <asset>", "USDC (default) or USDsui", "USDC").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(
|
|
34663
34070
|
async (opts) => {
|
|
34664
34071
|
try {
|
|
34665
|
-
const base = opts.api ??
|
|
34072
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34666
34073
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34667
34074
|
const address = agent.address();
|
|
34668
34075
|
if (opts.fund !== void 0) {
|
|
@@ -34673,7 +34080,7 @@ Subcommands:
|
|
|
34673
34080
|
);
|
|
34674
34081
|
}
|
|
34675
34082
|
}
|
|
34676
|
-
const challenge = await
|
|
34083
|
+
const challenge = await fetchJson3(`${base}/agent/challenge`, {
|
|
34677
34084
|
method: "POST",
|
|
34678
34085
|
body: { address }
|
|
34679
34086
|
});
|
|
@@ -34683,7 +34090,7 @@ Subcommands:
|
|
|
34683
34090
|
}
|
|
34684
34091
|
const message = new TextEncoder().encode(`t2000-agent-keys:${nonce}`);
|
|
34685
34092
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34686
|
-
const minted = await
|
|
34093
|
+
const minted = await fetchJson3(`${base}/agent/keys`, {
|
|
34687
34094
|
method: "POST",
|
|
34688
34095
|
body: { address, nonce, signature }
|
|
34689
34096
|
});
|
|
@@ -34720,10 +34127,10 @@ Subcommands:
|
|
|
34720
34127
|
);
|
|
34721
34128
|
group.command("topup").argument("<amount>", "Stablecoin amount to deposit as credit").description(
|
|
34722
34129
|
"Top up this wallet's t2000 credit with gasless USDC/USDsui (no new key). The 'never runs dry' primitive \u2014 call it on a 402 or a schedule."
|
|
34723
|
-
).option("--asset <asset>", "USDC (default) or USDsui", "USDC").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34130
|
+
).option("--asset <asset>", "USDC (default) or USDsui", "USDC").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(
|
|
34724
34131
|
async (amount, opts) => {
|
|
34725
34132
|
try {
|
|
34726
|
-
const base = opts.api ??
|
|
34133
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34727
34134
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34728
34135
|
const funded = await fundCredit(agent, base, amount, opts.asset);
|
|
34729
34136
|
if (isJsonMode()) {
|
|
@@ -34747,9 +34154,9 @@ Subcommands:
|
|
|
34747
34154
|
);
|
|
34748
34155
|
group.command("register").description(
|
|
34749
34156
|
"Register this wallet on-chain as an Agent ID (sponsored, gasless). Idempotent \u2014 safe to re-run."
|
|
34750
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34157
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(async (opts) => {
|
|
34751
34158
|
try {
|
|
34752
|
-
const base = opts.api ??
|
|
34159
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34753
34160
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34754
34161
|
const address = agent.address();
|
|
34755
34162
|
const reg = await registerWallet({ keypair: agent.keypair, address, base });
|
|
@@ -34777,9 +34184,9 @@ Subcommands:
|
|
|
34777
34184
|
});
|
|
34778
34185
|
group.command("link").argument("<owner>", "The owner's Sui address (Passport) to propose").description(
|
|
34779
34186
|
"Propose an owner for this agent (two-sided \u2014 the owner must then confirm). Sponsored, gasless."
|
|
34780
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34187
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(async (owner, opts) => {
|
|
34781
34188
|
try {
|
|
34782
|
-
const base = opts.api ??
|
|
34189
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34783
34190
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34784
34191
|
const address = agent.address();
|
|
34785
34192
|
if (!isValidSuiAddress(owner)) {
|
|
@@ -34816,9 +34223,9 @@ Subcommands:
|
|
|
34816
34223
|
});
|
|
34817
34224
|
group.command("confirm").argument("<agent>", "The agent Sui address to confirm ownership of").description(
|
|
34818
34225
|
"Confirm ownership of an agent that proposed you as its owner. Sponsored, gasless."
|
|
34819
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34226
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(async (agentAddress, opts) => {
|
|
34820
34227
|
try {
|
|
34821
|
-
const base = opts.api ??
|
|
34228
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34822
34229
|
const owner = await withAgent({ keyPath: opts.key });
|
|
34823
34230
|
const address = owner.address();
|
|
34824
34231
|
const { digest } = await runSponsoredTx({
|
|
@@ -34842,9 +34249,9 @@ Subcommands:
|
|
|
34842
34249
|
});
|
|
34843
34250
|
group.command("unlink").argument("<agent>", "The agent Sui address to renounce ownership of").description(
|
|
34844
34251
|
"Renounce ownership of an agent you own \u2014 the record returns to autonomous (public, on-chain). Sponsored, gasless. Re-link = the agent proposes again."
|
|
34845
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34252
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(async (agentAddress, opts) => {
|
|
34846
34253
|
try {
|
|
34847
|
-
const base = opts.api ??
|
|
34254
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34848
34255
|
const owner = await withAgent({ keyPath: opts.key });
|
|
34849
34256
|
const address = owner.address();
|
|
34850
34257
|
const { digest } = await runSponsoredTx({
|
|
@@ -34869,7 +34276,7 @@ Subcommands:
|
|
|
34869
34276
|
});
|
|
34870
34277
|
group.command("profile").description(
|
|
34871
34278
|
"Set this agent's public profile (name \xB7 image \xB7 description \xB7 links). Signed, no gas \u2014 shows in the directory."
|
|
34872
|
-
).option("--name <name>", "Display name").option("--image <url>", "Image URL (https)").option("--description <text>", "Short description").option("--website <url>", "Website link (https)").option("--twitter <url>", "X / Twitter link (https)").option("--github <url>", "GitHub link (https)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34279
|
+
).option("--name <name>", "Display name").option("--image <url>", "Image URL (https)").option("--description <text>", "Short description").option("--website <url>", "Website link (https)").option("--twitter <url>", "X / Twitter link (https)").option("--github <url>", "GitHub link (https)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(
|
|
34873
34280
|
async (opts) => {
|
|
34874
34281
|
try {
|
|
34875
34282
|
if (!(opts.name || opts.image || opts.description || opts.website || opts.twitter || opts.github)) {
|
|
@@ -34877,10 +34284,10 @@ Subcommands:
|
|
|
34877
34284
|
"Provide at least one of --name, --image, --description, --website, --twitter, --github."
|
|
34878
34285
|
);
|
|
34879
34286
|
}
|
|
34880
|
-
const base = opts.api ??
|
|
34287
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34881
34288
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34882
34289
|
const address = agent.address();
|
|
34883
|
-
const challenge = await
|
|
34290
|
+
const challenge = await fetchJson3(`${base}/agent/challenge`, {
|
|
34884
34291
|
method: "POST",
|
|
34885
34292
|
body: { address }
|
|
34886
34293
|
});
|
|
@@ -34890,7 +34297,7 @@ Subcommands:
|
|
|
34890
34297
|
}
|
|
34891
34298
|
const message = new TextEncoder().encode(`t2000-agent-profile:${nonce}`);
|
|
34892
34299
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34893
|
-
await
|
|
34300
|
+
await fetchJson3(`${base}/agent/profile`, {
|
|
34894
34301
|
method: "POST",
|
|
34895
34302
|
body: {
|
|
34896
34303
|
address,
|
|
@@ -34924,7 +34331,7 @@ Subcommands:
|
|
|
34924
34331
|
).option("--price <usdc>", "Price per call in USDC (e.g. 0.02) \u2014 buyers pay this").option(
|
|
34925
34332
|
"--category <category>",
|
|
34926
34333
|
`Storefront category: ${AGENT_CATEGORIES2.join(" | ")}`
|
|
34927
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34334
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(
|
|
34928
34335
|
async (opts) => {
|
|
34929
34336
|
try {
|
|
34930
34337
|
if (opts.mcpEndpoint === void 0 && opts.paymentMethods === void 0 && opts.price === void 0 && opts.category === void 0) {
|
|
@@ -34939,7 +34346,7 @@ Subcommands:
|
|
|
34939
34346
|
}
|
|
34940
34347
|
}
|
|
34941
34348
|
const category = normalizeCategory(opts.category);
|
|
34942
|
-
const base = opts.api ??
|
|
34349
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34943
34350
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34944
34351
|
const address = agent.address();
|
|
34945
34352
|
const prepareBody = { address };
|
|
@@ -35000,11 +34407,11 @@ Subcommands:
|
|
|
35000
34407
|
).option("--remove", "Take down the deployed service").option(
|
|
35001
34408
|
"--service <slug>",
|
|
35002
34409
|
"Catalog service slug \u2014 wrap config for ONE SKU (Store v2; omit = the default service)"
|
|
35003
|
-
).option("--gateway <url>", `Gateway base URL (default ${
|
|
34410
|
+
).option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(
|
|
35004
34411
|
async (opts) => {
|
|
35005
34412
|
try {
|
|
35006
|
-
const base = opts.api ??
|
|
35007
|
-
const gateway = opts.gateway ??
|
|
34413
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34414
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY;
|
|
35008
34415
|
const category = normalizeCategory(opts.category);
|
|
35009
34416
|
const slug = opts.service?.trim().toLowerCase() || void 0;
|
|
35010
34417
|
const agent = await withAgent({ keyPath: opts.key });
|
|
@@ -35015,7 +34422,7 @@ Subcommands:
|
|
|
35015
34422
|
const { signature: signature2 } = await agent.keypair.signPersonalMessage(
|
|
35016
34423
|
new TextEncoder().encode(msg2)
|
|
35017
34424
|
);
|
|
35018
|
-
await
|
|
34425
|
+
await fetchJson3(`${gateway}/deploy/config`, {
|
|
35019
34426
|
method: "DELETE",
|
|
35020
34427
|
body: { address, timestamp: ts2, signature: signature2, ...slug ? { slug } : {} }
|
|
35021
34428
|
});
|
|
@@ -35047,14 +34454,14 @@ Subcommands:
|
|
|
35047
34454
|
const method = (opts.method ?? "POST").toUpperCase() === "GET" ? "GET" : "POST";
|
|
35048
34455
|
const headers = opts.header ?? {};
|
|
35049
34456
|
const ts = Date.now();
|
|
35050
|
-
const bodyHash =
|
|
34457
|
+
const bodyHash = createHash2("sha256").update(
|
|
35051
34458
|
`${opts.upstream}|${method}|${JSON.stringify(headers)}${slug ? `|${slug}` : ""}`
|
|
35052
34459
|
).digest("hex");
|
|
35053
34460
|
const msg = `t2000-deploy:${ts}:${bodyHash}`;
|
|
35054
34461
|
const { signature } = await agent.keypair.signPersonalMessage(
|
|
35055
34462
|
new TextEncoder().encode(msg)
|
|
35056
34463
|
);
|
|
35057
|
-
await
|
|
34464
|
+
await fetchJson3(`${gateway}/deploy/config`, {
|
|
35058
34465
|
method: "POST",
|
|
35059
34466
|
body: {
|
|
35060
34467
|
address,
|
|
@@ -35123,7 +34530,7 @@ Subcommands:
|
|
|
35123
34530
|
"Catalog service slug \u2014 buys ONE SKU of the seller's catalog (Store v2)"
|
|
35124
34531
|
).option(
|
|
35125
34532
|
"--gateway <url>",
|
|
35126
|
-
`Gateway base URL (default ${
|
|
34533
|
+
`Gateway base URL (default ${DEFAULT_GATEWAY})`
|
|
35127
34534
|
).option("--force", "Override spending limits for this call (see `t2 limit`)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
|
|
35128
34535
|
async (seller, opts) => {
|
|
35129
34536
|
try {
|
|
@@ -35134,7 +34541,7 @@ Subcommands:
|
|
|
35134
34541
|
}
|
|
35135
34542
|
}
|
|
35136
34543
|
const maxPrice = opts.maxPrice ? Number.parseFloat(opts.maxPrice) : opts.amount ? Number.parseFloat(opts.amount) : 1;
|
|
35137
|
-
const gateway = opts.gateway ??
|
|
34544
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY;
|
|
35138
34545
|
const agent = await withAgent({ keyPath: opts.key });
|
|
35139
34546
|
const resolvedSeller = seller.startsWith("0x") ? seller : (await agent.resolveRecipient(seller)).address;
|
|
35140
34547
|
const slugPath = opts.service ? `/${opts.service.trim().toLowerCase()}` : "";
|
|
@@ -35202,12 +34609,12 @@ Subcommands:
|
|
|
35202
34609
|
);
|
|
35203
34610
|
group.command("earnings").description(
|
|
35204
34611
|
"Your sales as a seller \u2014 count, USDC earned (net), and unique buyers, from the on-chain settlement ledger. [Agent Commerce]"
|
|
35205
|
-
).option("--gateway <url>", `Gateway base URL (default ${
|
|
34612
|
+
).option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
|
|
35206
34613
|
try {
|
|
35207
|
-
const gateway = opts.gateway ??
|
|
34614
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY;
|
|
35208
34615
|
const agent = await withAgent({ keyPath: opts.key });
|
|
35209
34616
|
const address = agent.address();
|
|
35210
|
-
const stats = await
|
|
34617
|
+
const stats = await fetchJson3(
|
|
35211
34618
|
`${gateway}/commerce/stats/${address}`,
|
|
35212
34619
|
{ method: "GET" }
|
|
35213
34620
|
);
|
|
@@ -35230,13 +34637,13 @@ Subcommands:
|
|
|
35230
34637
|
});
|
|
35231
34638
|
group.command("handle").argument("<label>", "Handle label (3\u201320 chars: lowercase a\u2013z, 0\u20139, hyphens)").description(
|
|
35232
34639
|
"Claim <label>.agent-id.sui \u2192 this wallet (custody-minted, gasless). Use --release to give it up."
|
|
35233
|
-
).option("--release", "Release (revoke) this handle instead of claiming it").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34640
|
+
).option("--release", "Release (revoke) this handle instead of claiming it").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE4})`).action(
|
|
35234
34641
|
async (label, opts) => {
|
|
35235
34642
|
try {
|
|
35236
|
-
const base = opts.api ??
|
|
34643
|
+
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
35237
34644
|
const agent = await withAgent({ keyPath: opts.key });
|
|
35238
34645
|
const address = agent.address();
|
|
35239
|
-
const challenge = await
|
|
34646
|
+
const challenge = await fetchJson3(`${base}/agent/challenge`, {
|
|
35240
34647
|
method: "POST",
|
|
35241
34648
|
body: { address }
|
|
35242
34649
|
});
|
|
@@ -35248,7 +34655,7 @@ Subcommands:
|
|
|
35248
34655
|
const message = new TextEncoder().encode(`${action}:${nonce}:${label}`);
|
|
35249
34656
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
35250
34657
|
const path2 = opts.release ? "/agent/handle/release" : "/agent/handle";
|
|
35251
|
-
const res = await
|
|
34658
|
+
const res = await fetchJson3(`${base}${path2}`, {
|
|
35252
34659
|
method: "POST",
|
|
35253
34660
|
body: { address, label, nonce, signature }
|
|
35254
34661
|
});
|
|
@@ -35274,7 +34681,7 @@ Subcommands:
|
|
|
35274
34681
|
}
|
|
35275
34682
|
|
|
35276
34683
|
// src/commands/agents.ts
|
|
35277
|
-
var
|
|
34684
|
+
var DEFAULT_API_BASE5 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
35278
34685
|
async function getJson(url) {
|
|
35279
34686
|
const res = await fetch(url, { headers: { accept: "application/json" } });
|
|
35280
34687
|
if (!res.ok) {
|
|
@@ -35289,10 +34696,10 @@ function firstLine(text, max = 76) {
|
|
|
35289
34696
|
function registerAgents(program3) {
|
|
35290
34697
|
program3.command("agents").argument("[address]", "Show one agent\u2019s full listing (profile + reputation)").description(
|
|
35291
34698
|
"Browse the agent store (agents.t2000.ai): priced services from the live directory, or one agent\u2019s full listing. Buy with `t2 agent pay <address>`. [Agent Commerce]"
|
|
35292
|
-
).option("--category <category>", "Filter the list by store category").option("--all", "Include agents without a priced service").option("--limit <n>", "Max rows (default: all)").option("--api <url>", `API base URL (default ${
|
|
34699
|
+
).option("--category <category>", "Filter the list by store category").option("--all", "Include agents without a priced service").option("--limit <n>", "Max rows (default: all)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(
|
|
35293
34700
|
async (address, opts) => {
|
|
35294
34701
|
try {
|
|
35295
|
-
const base = opts.api ??
|
|
34702
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
35296
34703
|
if (address) {
|
|
35297
34704
|
const profile = await getJson(`${base}/agents/${address}`);
|
|
35298
34705
|
if (isJsonMode()) {
|
|
@@ -35364,256 +34771,6 @@ function registerAgents(program3) {
|
|
|
35364
34771
|
);
|
|
35365
34772
|
}
|
|
35366
34773
|
|
|
35367
|
-
// src/commands/task/index.ts
|
|
35368
|
-
var DEFAULT_GATEWAY4 = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
|
|
35369
|
-
async function getJson2(url) {
|
|
35370
|
-
const res = await fetch(url, { headers: { accept: "application/json" } });
|
|
35371
|
-
const json = await res.json().catch(() => ({}));
|
|
35372
|
-
if (!res.ok) {
|
|
35373
|
-
throw new Error(json.error ?? `Request failed (${res.status}).`);
|
|
35374
|
-
}
|
|
35375
|
-
return json;
|
|
35376
|
-
}
|
|
35377
|
-
async function postJson2(url, body2) {
|
|
35378
|
-
const res = await fetch(url, {
|
|
35379
|
-
method: "POST",
|
|
35380
|
-
headers: { "content-type": "application/json" },
|
|
35381
|
-
body: JSON.stringify(body2)
|
|
35382
|
-
});
|
|
35383
|
-
const json = await res.json().catch(() => ({}));
|
|
35384
|
-
if (!res.ok) {
|
|
35385
|
-
throw new Error(json.error ?? `Request failed (${res.status}).`);
|
|
35386
|
-
}
|
|
35387
|
-
return json;
|
|
35388
|
-
}
|
|
35389
|
-
function registerTask(program3) {
|
|
35390
|
-
const group = program3.command("task").description(
|
|
35391
|
-
"Earn from t2000 reward tasks and work (or post) community board tasks \u2014 all paid through the rail. [Agent Commerce]"
|
|
35392
|
-
);
|
|
35393
|
-
group.command("list").description("Live tasks: t2000 rewards (auto-verified) + the community board (poster-approved)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY4})`).action(async (opts) => {
|
|
35394
|
-
try {
|
|
35395
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35396
|
-
const [rewards, board] = await Promise.all([
|
|
35397
|
-
getJson2(`${gateway}/tasks/stats`),
|
|
35398
|
-
getJson2(`${gateway}/tasks/board`)
|
|
35399
|
-
]);
|
|
35400
|
-
if (isJsonMode()) {
|
|
35401
|
-
printJson({ rewards: rewards.tasks, board: board.tasks });
|
|
35402
|
-
return;
|
|
35403
|
-
}
|
|
35404
|
-
printBlank();
|
|
35405
|
-
printHeader("t2000 reward tasks (auto-verified, one per wallet)");
|
|
35406
|
-
for (const t of rewards.tasks) {
|
|
35407
|
-
printLine(
|
|
35408
|
-
` ${formatUsd(t.rewardNetUsd).padStart(6)} ${t.id.padEnd(20)} ${t.kind.padEnd(8)} ${t.status === "live" ? "live" : "budget spent"}`
|
|
35409
|
-
);
|
|
35410
|
-
}
|
|
35411
|
-
printBlank();
|
|
35412
|
-
printHeader(`Community board (${board.tasks.length} live, poster approves)`);
|
|
35413
|
-
if (board.tasks.length === 0) {
|
|
35414
|
-
printLine(" (none live \u2014 post one: t2 task post --help)");
|
|
35415
|
-
}
|
|
35416
|
-
for (const t of board.tasks) {
|
|
35417
|
-
const days = Math.max(0, Math.ceil((Date.parse(t.expiresAt) - Date.now()) / 864e5));
|
|
35418
|
-
printLine(
|
|
35419
|
-
` ${formatUsd(t.rewardUsd).padStart(6)} ${t.title.slice(0, 44).padEnd(44)} ${t.remainingCompletions}/${t.maxCompletions} spots \xB7 ${days}d ${t.id}`
|
|
35420
|
-
);
|
|
35421
|
-
}
|
|
35422
|
-
printBlank();
|
|
35423
|
-
printInfo("Claim a reward: t2 task claim <task> \xB7 Work the board: t2 task submit <taskId>");
|
|
35424
|
-
printBlank();
|
|
35425
|
-
} catch (error) {
|
|
35426
|
-
handleError(error);
|
|
35427
|
-
}
|
|
35428
|
-
});
|
|
35429
|
-
group.command("claim").argument("<task>", "Reward task id (e.g. buy-sui, share-a-read) \u2014 see `t2 task list`").description("Claim a t2000 reward task (verified in one request; also retries automated tasks)").option("--tx <digest>", "Swap tx digest (buy-manifest / buy-sui)").option("--post <url>", "Your X post URL (X-proof tasks)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY4})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
|
|
35430
|
-
async (task, opts) => {
|
|
35431
|
-
try {
|
|
35432
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35433
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
35434
|
-
const result = await postJson2(`${gateway}/tasks/claim`, {
|
|
35435
|
-
task,
|
|
35436
|
-
address: agent.address(),
|
|
35437
|
-
...opts.tx ? { txDigest: opts.tx } : {},
|
|
35438
|
-
...opts.post ? { postUrl: opts.post } : {}
|
|
35439
|
-
});
|
|
35440
|
-
if (isJsonMode()) {
|
|
35441
|
-
printJson(result);
|
|
35442
|
-
return;
|
|
35443
|
-
}
|
|
35444
|
-
printBlank();
|
|
35445
|
-
if (result.paid) {
|
|
35446
|
-
printSuccess(`Paid ${formatUsd(result.netUsd ?? 0)} to your agent.`);
|
|
35447
|
-
if (result.suiscan) {
|
|
35448
|
-
printKeyValue("Receipt", result.suiscan);
|
|
35449
|
-
}
|
|
35450
|
-
} else {
|
|
35451
|
-
printWarning(result.note ?? "Not paid.");
|
|
35452
|
-
}
|
|
35453
|
-
printBlank();
|
|
35454
|
-
} catch (error) {
|
|
35455
|
-
handleError(error);
|
|
35456
|
-
}
|
|
35457
|
-
}
|
|
35458
|
-
);
|
|
35459
|
-
group.command("post").description(
|
|
35460
|
-
"Post a community task \u2014 pays the FULL budget (reward \xD7 completions) into escrow via x402; auto-moderated at post time. SAVE the returned manageKey."
|
|
35461
|
-
).requiredOption("--title <text>", "What needs doing (8+ chars)").requiredOption("--description <text>", "Exactly what the worker must deliver + what proof (30+ chars)").requiredOption("--reward <usdc>", "Reward per approved completion ($0.01\u2013$50)").option("--completions <n>", "Max completions (default 1)", "1").option("--expiry-days <n>", "Days until unspent budget auto-refunds (default 7)", "7").option("--category <category>", "research | data | marketing | dev | creative | other", "other").option("--notify-email <email>", "Email me when submissions arrive + when the refund settles (per-task, one-click stop in every mail)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY4})`).option("--force", "Override spending limits for this call (see `t2 limit`)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
|
|
35462
|
-
async (opts) => {
|
|
35463
|
-
try {
|
|
35464
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35465
|
-
const reward = Number.parseFloat(opts.reward);
|
|
35466
|
-
const completions = Number.parseInt(opts.completions, 10);
|
|
35467
|
-
if (!Number.isFinite(reward) || reward <= 0) {
|
|
35468
|
-
throw new Error(`--reward must be a positive number (got "${opts.reward}").`);
|
|
35469
|
-
}
|
|
35470
|
-
const budget = Math.round(reward * completions * 1e6) / 1e6;
|
|
35471
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
35472
|
-
const result = await agent.pay({
|
|
35473
|
-
url: `${gateway}/tasks/board`,
|
|
35474
|
-
method: "POST",
|
|
35475
|
-
body: JSON.stringify({
|
|
35476
|
-
title: opts.title,
|
|
35477
|
-
description: opts.description,
|
|
35478
|
-
rewardUsd: reward,
|
|
35479
|
-
maxCompletions: completions,
|
|
35480
|
-
expiryDays: Number.parseInt(opts.expiryDays, 10),
|
|
35481
|
-
category: opts.category,
|
|
35482
|
-
...opts.notifyEmail ? { notifyEmail: opts.notifyEmail } : {}
|
|
35483
|
-
}),
|
|
35484
|
-
maxPrice: budget,
|
|
35485
|
-
force: opts.force
|
|
35486
|
-
});
|
|
35487
|
-
const body2 = result.body;
|
|
35488
|
-
if (isJsonMode()) {
|
|
35489
|
-
printJson(body2 ?? result);
|
|
35490
|
-
return;
|
|
35491
|
-
}
|
|
35492
|
-
printBlank();
|
|
35493
|
-
if (body2?.ok && body2.manageKey) {
|
|
35494
|
-
printSuccess(body2.moderation ?? "Task posted.");
|
|
35495
|
-
printKeyValue("Task", body2.task?.id ?? "\u2014");
|
|
35496
|
-
printKeyValue("Escrow", formatUsd(budget));
|
|
35497
|
-
printBlank();
|
|
35498
|
-
printWarning("SAVE THIS manageKey \u2014 shown once. It approves/rejects/closes this task:");
|
|
35499
|
-
printLine(` ${body2.manageKey}`);
|
|
35500
|
-
printBlank();
|
|
35501
|
-
printInfo(`Review: t2 task review ${body2.task?.id ?? "<taskId>"} --manage-key <key>`);
|
|
35502
|
-
} else {
|
|
35503
|
-
printWarning(
|
|
35504
|
-
`${body2?.error ?? "Posting failed."}${body2?.refunded ? " (Budget refunded.)" : ""}`
|
|
35505
|
-
);
|
|
35506
|
-
}
|
|
35507
|
-
printBlank();
|
|
35508
|
-
} catch (error) {
|
|
35509
|
-
handleError(error);
|
|
35510
|
-
}
|
|
35511
|
-
}
|
|
35512
|
-
);
|
|
35513
|
-
group.command("submit").argument("<taskId>", "Board task id (see `t2 task list`)").description("Submit proof of completion to a board task (one submission per wallet)").requiredOption("--proof <text>", "What you did + how the poster can verify it (10+ chars)").option("--url <url>", "Proof link (https)").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY4})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
|
|
35514
|
-
async (taskId, opts) => {
|
|
35515
|
-
try {
|
|
35516
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35517
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
35518
|
-
const result = await postJson2(
|
|
35519
|
-
`${gateway}/tasks/board/${taskId}/submit`,
|
|
35520
|
-
{
|
|
35521
|
-
address: agent.address(),
|
|
35522
|
-
proof: opts.proof,
|
|
35523
|
-
...opts.url ? { url: opts.url } : {}
|
|
35524
|
-
}
|
|
35525
|
-
);
|
|
35526
|
-
if (isJsonMode()) {
|
|
35527
|
-
printJson(result);
|
|
35528
|
-
return;
|
|
35529
|
-
}
|
|
35530
|
-
printBlank();
|
|
35531
|
-
printSuccess(result.note ?? "Submitted \u2014 the poster reviews next.");
|
|
35532
|
-
printBlank();
|
|
35533
|
-
} catch (error) {
|
|
35534
|
-
handleError(error);
|
|
35535
|
-
}
|
|
35536
|
-
}
|
|
35537
|
-
);
|
|
35538
|
-
group.command("review").argument("<taskId>", "Your board task id").description("List submissions on your board task (poster view \u2014 needs the manageKey)").requiredOption("--manage-key <key>", "The manageKey returned when you posted").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY4})`).action(async (taskId, opts) => {
|
|
35539
|
-
try {
|
|
35540
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35541
|
-
const result = await getJson2(`${gateway}/tasks/board/${taskId}?manageKey=${encodeURIComponent(opts.manageKey)}`);
|
|
35542
|
-
if (!result.posterView) {
|
|
35543
|
-
throw new Error(result.error ?? "manageKey not accepted for this task.");
|
|
35544
|
-
}
|
|
35545
|
-
if (isJsonMode()) {
|
|
35546
|
-
printJson(result);
|
|
35547
|
-
return;
|
|
35548
|
-
}
|
|
35549
|
-
const subs = result.submissions ?? [];
|
|
35550
|
-
printBlank();
|
|
35551
|
-
printHeader(`${result.task?.title ?? taskId} \u2014 ${subs.length} submission${subs.length === 1 ? "" : "s"}`);
|
|
35552
|
-
for (const s of subs) {
|
|
35553
|
-
printLine(` [${s.status.padEnd(8)}] ${s.id} ${truncateAddress(s.worker)}`);
|
|
35554
|
-
if (s.proof) {
|
|
35555
|
-
printLine(` ${s.proof.slice(0, 90)}`);
|
|
35556
|
-
}
|
|
35557
|
-
if (s.url) {
|
|
35558
|
-
printLine(` ${s.url}`);
|
|
35559
|
-
}
|
|
35560
|
-
}
|
|
35561
|
-
printBlank();
|
|
35562
|
-
printInfo(`Pay: t2 task approve ${taskId} --manage-key <key> --submissions <id,id,\u2026>`);
|
|
35563
|
-
printBlank();
|
|
35564
|
-
} catch (error) {
|
|
35565
|
-
handleError(error);
|
|
35566
|
-
}
|
|
35567
|
-
});
|
|
35568
|
-
group.command("approve").argument("<taskId>", "Your board task id").description("Approve (pay) or reject submissions on your board task \u2014 batch up to 50").requiredOption("--manage-key <key>", "The manageKey returned when you posted").requiredOption("--submissions <ids>", "Comma-separated submission ids").option("--reject", "Reject instead of approving").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY4})`).action(
|
|
35569
|
-
async (taskId, opts) => {
|
|
35570
|
-
try {
|
|
35571
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35572
|
-
const result = await postJson2(`${gateway}/tasks/board/${taskId}/approve`, {
|
|
35573
|
-
manageKey: opts.manageKey,
|
|
35574
|
-
submissionIds: opts.submissions.split(",").map((s) => s.trim()).filter(Boolean),
|
|
35575
|
-
action: opts.reject ? "reject" : "approve"
|
|
35576
|
-
});
|
|
35577
|
-
if (isJsonMode()) {
|
|
35578
|
-
printJson(result);
|
|
35579
|
-
return;
|
|
35580
|
-
}
|
|
35581
|
-
printBlank();
|
|
35582
|
-
for (const r of result.results ?? []) {
|
|
35583
|
-
if (r.status === "paid") {
|
|
35584
|
-
printSuccess(`${r.submissionId} paid${r.payoutTx ? ` (tx ${r.payoutTx.slice(0, 10)}\u2026)` : ""}`);
|
|
35585
|
-
} else if (r.error) {
|
|
35586
|
-
printWarning(`${r.submissionId}: ${r.error}`);
|
|
35587
|
-
} else {
|
|
35588
|
-
printLine(` ${r.submissionId}: ${r.status}`);
|
|
35589
|
-
}
|
|
35590
|
-
}
|
|
35591
|
-
printBlank();
|
|
35592
|
-
} catch (error) {
|
|
35593
|
-
handleError(error);
|
|
35594
|
-
}
|
|
35595
|
-
}
|
|
35596
|
-
);
|
|
35597
|
-
group.command("close").argument("<taskId>", "Your board task id").description("Close your board task early \u2014 the unspent budget refunds to your wallet").requiredOption("--manage-key <key>", "The manageKey returned when you posted").option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY4})`).action(async (taskId, opts) => {
|
|
35598
|
-
try {
|
|
35599
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35600
|
-
const result = await postJson2(`${gateway}/tasks/board/${taskId}/close`, { manageKey: opts.manageKey });
|
|
35601
|
-
if (isJsonMode()) {
|
|
35602
|
-
printJson(result);
|
|
35603
|
-
return;
|
|
35604
|
-
}
|
|
35605
|
-
printBlank();
|
|
35606
|
-
printSuccess(`Task closed${result.refunded ? " \u2014 unspent budget refunded" : ""}.`);
|
|
35607
|
-
if (result.suiscan) {
|
|
35608
|
-
printKeyValue("Refund", result.suiscan);
|
|
35609
|
-
}
|
|
35610
|
-
printBlank();
|
|
35611
|
-
} catch (error) {
|
|
35612
|
-
handleError(error);
|
|
35613
|
-
}
|
|
35614
|
-
});
|
|
35615
|
-
}
|
|
35616
|
-
|
|
35617
34774
|
// src/program.ts
|
|
35618
34775
|
var require3 = createRequire2(import.meta.url);
|
|
35619
34776
|
var { version: CLI_VERSION2 } = require3("../package.json");
|
|
@@ -35637,8 +34794,6 @@ Examples:
|
|
|
35637
34794
|
$ t2 services search "image" Discover x402 services in the gateway catalog
|
|
35638
34795
|
$ t2 agents Browse the agent store (agents.t2000.ai)
|
|
35639
34796
|
$ t2 agent pay <address> Buy an agent's service (escrowed, auto-refund on failure)
|
|
35640
|
-
$ t2 task list Live reward tasks + the community board
|
|
35641
|
-
$ t2 task claim share-a-read --post <url> Claim an X-proof reward
|
|
35642
34797
|
$ t2 limit set --daily 100 Change the daily spend cap (default $100/day)
|
|
35643
34798
|
$ t2 mcp install Connect Claude / Cursor / Windsurf
|
|
35644
34799
|
$ t2 skills install Install skills as local SKILL.md files`);
|
|
@@ -35659,7 +34814,6 @@ Examples:
|
|
|
35659
34814
|
registerSkills(program3);
|
|
35660
34815
|
registerAgent(program3);
|
|
35661
34816
|
registerAgents(program3);
|
|
35662
|
-
registerTask(program3);
|
|
35663
34817
|
return program3;
|
|
35664
34818
|
}
|
|
35665
34819
|
|