@t2000/cli 5.30.0 → 5.32.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((resolve3, 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
|
+
resolve3((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(resolve3, reject) {
|
|
18974
18974
|
try {
|
|
18975
18975
|
const data = QRCode.create(text, opts);
|
|
18976
|
-
|
|
18976
|
+
resolve3(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(resolve3, 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) : resolve3(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 resolve3;
|
|
30302
30302
|
let reject;
|
|
30303
30303
|
const promise = new Promise((res, rej) => {
|
|
30304
|
-
|
|
30304
|
+
resolve3 = res;
|
|
30305
30305
|
reject = rej;
|
|
30306
30306
|
});
|
|
30307
|
-
return { promise, resolve:
|
|
30307
|
+
return { promise, resolve: resolve3, 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: resolve3, 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(() => resolve3(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-VB42REWC.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 createHash4 } 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";
|
|
@@ -33834,6 +33834,13 @@ function registerAgentReview(agent) {
|
|
|
33834
33834
|
);
|
|
33835
33835
|
}
|
|
33836
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
|
+
|
|
33837
33844
|
// src/commands/agent/services.ts
|
|
33838
33845
|
import { createHash as createHash2 } from "crypto";
|
|
33839
33846
|
import { readFileSync as readFileSync3 } from "fs";
|
|
@@ -34062,9 +34069,513 @@ function registerAgentServices(agentGroup, defaults) {
|
|
|
34062
34069
|
});
|
|
34063
34070
|
}
|
|
34064
34071
|
|
|
34065
|
-
// src/commands/agent/
|
|
34072
|
+
// src/commands/agent/serve.ts
|
|
34066
34073
|
var DEFAULT_API_BASE4 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
34067
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
|
+
// src/commands/agent/index.ts
|
|
34577
|
+
var DEFAULT_API_BASE5 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
34578
|
+
var DEFAULT_GATEWAY3 = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
|
|
34068
34579
|
var DEFAULT_RAIL = process.env.T2000_RAIL_URL ?? "https://x402.t2000.ai";
|
|
34069
34580
|
var AGENT_CATEGORIES2 = [
|
|
34070
34581
|
"ai-models",
|
|
@@ -34103,19 +34614,19 @@ async function fundCredit(agent, base, amountStr, assetOpt) {
|
|
|
34103
34614
|
throw new Error(`amount must be a positive number (got "${amountStr}").`);
|
|
34104
34615
|
}
|
|
34105
34616
|
const asset = normalizeTopupAsset(assetOpt);
|
|
34106
|
-
const cfg = await
|
|
34617
|
+
const cfg = await fetchJson5(`${base}/agent/topup`, { method: "GET" });
|
|
34107
34618
|
const treasury = cfg.treasury;
|
|
34108
34619
|
if (!treasury) {
|
|
34109
34620
|
throw new Error("Could not resolve the t2000 treasury address.");
|
|
34110
34621
|
}
|
|
34111
34622
|
const sent = await agent.send({ to: treasury, amount, asset });
|
|
34112
|
-
const topup = await
|
|
34623
|
+
const topup = await fetchJson5(`${base}/agent/topup`, {
|
|
34113
34624
|
method: "POST",
|
|
34114
34625
|
body: { address: agent.address(), digest: sent.tx }
|
|
34115
34626
|
});
|
|
34116
34627
|
return { amount, asset, balanceUsd: topup.balanceUsd };
|
|
34117
34628
|
}
|
|
34118
|
-
async function
|
|
34629
|
+
async function fetchJson5(url, init) {
|
|
34119
34630
|
const res = await fetch(url, {
|
|
34120
34631
|
method: init.method,
|
|
34121
34632
|
headers: init.body ? { "Content-Type": "application/json" } : void 0,
|
|
@@ -34143,14 +34654,15 @@ Subcommands:
|
|
|
34143
34654
|
`
|
|
34144
34655
|
);
|
|
34145
34656
|
registerAgentCreate(group);
|
|
34146
|
-
registerAgentServices(group, { apiBase:
|
|
34657
|
+
registerAgentServices(group, { apiBase: DEFAULT_API_BASE5 });
|
|
34658
|
+
registerAgentServe(group);
|
|
34147
34659
|
registerAgentReview(group);
|
|
34148
34660
|
group.command("onboard").description(
|
|
34149
34661
|
"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`."
|
|
34150
|
-
).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 ${
|
|
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 ${DEFAULT_API_BASE5})`).action(
|
|
34151
34663
|
async (opts) => {
|
|
34152
34664
|
try {
|
|
34153
|
-
const base = opts.api ??
|
|
34665
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34154
34666
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34155
34667
|
const address = agent.address();
|
|
34156
34668
|
if (opts.fund !== void 0) {
|
|
@@ -34161,7 +34673,7 @@ Subcommands:
|
|
|
34161
34673
|
);
|
|
34162
34674
|
}
|
|
34163
34675
|
}
|
|
34164
|
-
const challenge = await
|
|
34676
|
+
const challenge = await fetchJson5(`${base}/agent/challenge`, {
|
|
34165
34677
|
method: "POST",
|
|
34166
34678
|
body: { address }
|
|
34167
34679
|
});
|
|
@@ -34171,7 +34683,7 @@ Subcommands:
|
|
|
34171
34683
|
}
|
|
34172
34684
|
const message = new TextEncoder().encode(`t2000-agent-keys:${nonce}`);
|
|
34173
34685
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34174
|
-
const minted = await
|
|
34686
|
+
const minted = await fetchJson5(`${base}/agent/keys`, {
|
|
34175
34687
|
method: "POST",
|
|
34176
34688
|
body: { address, nonce, signature }
|
|
34177
34689
|
});
|
|
@@ -34208,10 +34720,10 @@ Subcommands:
|
|
|
34208
34720
|
);
|
|
34209
34721
|
group.command("topup").argument("<amount>", "Stablecoin amount to deposit as credit").description(
|
|
34210
34722
|
"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."
|
|
34211
|
-
).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 ${
|
|
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 ${DEFAULT_API_BASE5})`).action(
|
|
34212
34724
|
async (amount, opts) => {
|
|
34213
34725
|
try {
|
|
34214
|
-
const base = opts.api ??
|
|
34726
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34215
34727
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34216
34728
|
const funded = await fundCredit(agent, base, amount, opts.asset);
|
|
34217
34729
|
if (isJsonMode()) {
|
|
@@ -34235,9 +34747,9 @@ Subcommands:
|
|
|
34235
34747
|
);
|
|
34236
34748
|
group.command("register").description(
|
|
34237
34749
|
"Register this wallet on-chain as an Agent ID (sponsored, gasless). Idempotent \u2014 safe to re-run."
|
|
34238
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34750
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (opts) => {
|
|
34239
34751
|
try {
|
|
34240
|
-
const base = opts.api ??
|
|
34752
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34241
34753
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34242
34754
|
const address = agent.address();
|
|
34243
34755
|
const reg = await registerWallet({ keypair: agent.keypair, address, base });
|
|
@@ -34265,9 +34777,9 @@ Subcommands:
|
|
|
34265
34777
|
});
|
|
34266
34778
|
group.command("link").argument("<owner>", "The owner's Sui address (Passport) to propose").description(
|
|
34267
34779
|
"Propose an owner for this agent (two-sided \u2014 the owner must then confirm). Sponsored, gasless."
|
|
34268
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34780
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (owner, opts) => {
|
|
34269
34781
|
try {
|
|
34270
|
-
const base = opts.api ??
|
|
34782
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34271
34783
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34272
34784
|
const address = agent.address();
|
|
34273
34785
|
if (!isValidSuiAddress(owner)) {
|
|
@@ -34304,9 +34816,9 @@ Subcommands:
|
|
|
34304
34816
|
});
|
|
34305
34817
|
group.command("confirm").argument("<agent>", "The agent Sui address to confirm ownership of").description(
|
|
34306
34818
|
"Confirm ownership of an agent that proposed you as its owner. Sponsored, gasless."
|
|
34307
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34819
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (agentAddress, opts) => {
|
|
34308
34820
|
try {
|
|
34309
|
-
const base = opts.api ??
|
|
34821
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34310
34822
|
const owner = await withAgent({ keyPath: opts.key });
|
|
34311
34823
|
const address = owner.address();
|
|
34312
34824
|
const { digest } = await runSponsoredTx({
|
|
@@ -34330,9 +34842,9 @@ Subcommands:
|
|
|
34330
34842
|
});
|
|
34331
34843
|
group.command("unlink").argument("<agent>", "The agent Sui address to renounce ownership of").description(
|
|
34332
34844
|
"Renounce ownership of an agent you own \u2014 the record returns to autonomous (public, on-chain). Sponsored, gasless. Re-link = the agent proposes again."
|
|
34333
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34845
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(async (agentAddress, opts) => {
|
|
34334
34846
|
try {
|
|
34335
|
-
const base = opts.api ??
|
|
34847
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34336
34848
|
const owner = await withAgent({ keyPath: opts.key });
|
|
34337
34849
|
const address = owner.address();
|
|
34338
34850
|
const { digest } = await runSponsoredTx({
|
|
@@ -34357,7 +34869,7 @@ Subcommands:
|
|
|
34357
34869
|
});
|
|
34358
34870
|
group.command("profile").description(
|
|
34359
34871
|
"Set this agent's public profile (name \xB7 image \xB7 description \xB7 links). Signed, no gas \u2014 shows in the directory."
|
|
34360
|
-
).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 ${
|
|
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 ${DEFAULT_API_BASE5})`).action(
|
|
34361
34873
|
async (opts) => {
|
|
34362
34874
|
try {
|
|
34363
34875
|
if (!(opts.name || opts.image || opts.description || opts.website || opts.twitter || opts.github)) {
|
|
@@ -34365,10 +34877,10 @@ Subcommands:
|
|
|
34365
34877
|
"Provide at least one of --name, --image, --description, --website, --twitter, --github."
|
|
34366
34878
|
);
|
|
34367
34879
|
}
|
|
34368
|
-
const base = opts.api ??
|
|
34880
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34369
34881
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34370
34882
|
const address = agent.address();
|
|
34371
|
-
const challenge = await
|
|
34883
|
+
const challenge = await fetchJson5(`${base}/agent/challenge`, {
|
|
34372
34884
|
method: "POST",
|
|
34373
34885
|
body: { address }
|
|
34374
34886
|
});
|
|
@@ -34378,7 +34890,7 @@ Subcommands:
|
|
|
34378
34890
|
}
|
|
34379
34891
|
const message = new TextEncoder().encode(`t2000-agent-profile:${nonce}`);
|
|
34380
34892
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34381
|
-
await
|
|
34893
|
+
await fetchJson5(`${base}/agent/profile`, {
|
|
34382
34894
|
method: "POST",
|
|
34383
34895
|
body: {
|
|
34384
34896
|
address,
|
|
@@ -34412,7 +34924,7 @@ Subcommands:
|
|
|
34412
34924
|
).option("--price <usdc>", "Price per call in USDC (e.g. 0.02) \u2014 buyers pay this").option(
|
|
34413
34925
|
"--category <category>",
|
|
34414
34926
|
`Storefront category: ${AGENT_CATEGORIES2.join(" | ")}`
|
|
34415
|
-
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${
|
|
34927
|
+
).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(
|
|
34416
34928
|
async (opts) => {
|
|
34417
34929
|
try {
|
|
34418
34930
|
if (opts.mcpEndpoint === void 0 && opts.paymentMethods === void 0 && opts.price === void 0 && opts.category === void 0) {
|
|
@@ -34427,7 +34939,7 @@ Subcommands:
|
|
|
34427
34939
|
}
|
|
34428
34940
|
}
|
|
34429
34941
|
const category = normalizeCategory(opts.category);
|
|
34430
|
-
const base = opts.api ??
|
|
34942
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34431
34943
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34432
34944
|
const address = agent.address();
|
|
34433
34945
|
const prepareBody = { address };
|
|
@@ -34488,11 +35000,11 @@ Subcommands:
|
|
|
34488
35000
|
).option("--remove", "Take down the deployed service").option(
|
|
34489
35001
|
"--service <slug>",
|
|
34490
35002
|
"Catalog service slug \u2014 wrap config for ONE SKU (Store v2; omit = the default service)"
|
|
34491
|
-
).option("--gateway <url>", `Gateway base URL (default ${
|
|
35003
|
+
).option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${DEFAULT_API_BASE5})`).action(
|
|
34492
35004
|
async (opts) => {
|
|
34493
35005
|
try {
|
|
34494
|
-
const base = opts.api ??
|
|
34495
|
-
const gateway = opts.gateway ??
|
|
35006
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
35007
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
|
|
34496
35008
|
const category = normalizeCategory(opts.category);
|
|
34497
35009
|
const slug = opts.service?.trim().toLowerCase() || void 0;
|
|
34498
35010
|
const agent = await withAgent({ keyPath: opts.key });
|
|
@@ -34503,7 +35015,7 @@ Subcommands:
|
|
|
34503
35015
|
const { signature: signature2 } = await agent.keypair.signPersonalMessage(
|
|
34504
35016
|
new TextEncoder().encode(msg2)
|
|
34505
35017
|
);
|
|
34506
|
-
await
|
|
35018
|
+
await fetchJson5(`${gateway}/deploy/config`, {
|
|
34507
35019
|
method: "DELETE",
|
|
34508
35020
|
body: { address, timestamp: ts2, signature: signature2, ...slug ? { slug } : {} }
|
|
34509
35021
|
});
|
|
@@ -34535,14 +35047,14 @@ Subcommands:
|
|
|
34535
35047
|
const method = (opts.method ?? "POST").toUpperCase() === "GET" ? "GET" : "POST";
|
|
34536
35048
|
const headers = opts.header ?? {};
|
|
34537
35049
|
const ts = Date.now();
|
|
34538
|
-
const bodyHash =
|
|
35050
|
+
const bodyHash = createHash4("sha256").update(
|
|
34539
35051
|
`${opts.upstream}|${method}|${JSON.stringify(headers)}${slug ? `|${slug}` : ""}`
|
|
34540
35052
|
).digest("hex");
|
|
34541
35053
|
const msg = `t2000-deploy:${ts}:${bodyHash}`;
|
|
34542
35054
|
const { signature } = await agent.keypair.signPersonalMessage(
|
|
34543
35055
|
new TextEncoder().encode(msg)
|
|
34544
35056
|
);
|
|
34545
|
-
await
|
|
35057
|
+
await fetchJson5(`${gateway}/deploy/config`, {
|
|
34546
35058
|
method: "POST",
|
|
34547
35059
|
body: {
|
|
34548
35060
|
address,
|
|
@@ -34611,7 +35123,7 @@ Subcommands:
|
|
|
34611
35123
|
"Catalog service slug \u2014 buys ONE SKU of the seller's catalog (Store v2)"
|
|
34612
35124
|
).option(
|
|
34613
35125
|
"--gateway <url>",
|
|
34614
|
-
`Gateway base URL (default ${
|
|
35126
|
+
`Gateway base URL (default ${DEFAULT_GATEWAY3})`
|
|
34615
35127
|
).option("--force", "Override spending limits for this call (see `t2 limit`)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
|
|
34616
35128
|
async (seller, opts) => {
|
|
34617
35129
|
try {
|
|
@@ -34622,7 +35134,7 @@ Subcommands:
|
|
|
34622
35134
|
}
|
|
34623
35135
|
}
|
|
34624
35136
|
const maxPrice = opts.maxPrice ? Number.parseFloat(opts.maxPrice) : opts.amount ? Number.parseFloat(opts.amount) : 1;
|
|
34625
|
-
const gateway = opts.gateway ??
|
|
35137
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
|
|
34626
35138
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34627
35139
|
const resolvedSeller = seller.startsWith("0x") ? seller : (await agent.resolveRecipient(seller)).address;
|
|
34628
35140
|
const slugPath = opts.service ? `/${opts.service.trim().toLowerCase()}` : "";
|
|
@@ -34690,12 +35202,12 @@ Subcommands:
|
|
|
34690
35202
|
);
|
|
34691
35203
|
group.command("earnings").description(
|
|
34692
35204
|
"Your sales as a seller \u2014 count, USDC earned (net), and unique buyers, from the on-chain settlement ledger. [Agent Commerce]"
|
|
34693
|
-
).option("--gateway <url>", `Gateway base URL (default ${
|
|
35205
|
+
).option("--gateway <url>", `Gateway base URL (default ${DEFAULT_GATEWAY3})`).option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
|
|
34694
35206
|
try {
|
|
34695
|
-
const gateway = opts.gateway ??
|
|
35207
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY3;
|
|
34696
35208
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34697
35209
|
const address = agent.address();
|
|
34698
|
-
const stats = await
|
|
35210
|
+
const stats = await fetchJson5(
|
|
34699
35211
|
`${gateway}/commerce/stats/${address}`,
|
|
34700
35212
|
{ method: "GET" }
|
|
34701
35213
|
);
|
|
@@ -34718,13 +35230,13 @@ Subcommands:
|
|
|
34718
35230
|
});
|
|
34719
35231
|
group.command("handle").argument("<label>", "Handle label (3\u201320 chars: lowercase a\u2013z, 0\u20139, hyphens)").description(
|
|
34720
35232
|
"Claim <label>.agent-id.sui \u2192 this wallet (custody-minted, gasless). Use --release to give it up."
|
|
34721
|
-
).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 ${
|
|
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 ${DEFAULT_API_BASE5})`).action(
|
|
34722
35234
|
async (label, opts) => {
|
|
34723
35235
|
try {
|
|
34724
|
-
const base = opts.api ??
|
|
35236
|
+
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
34725
35237
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34726
35238
|
const address = agent.address();
|
|
34727
|
-
const challenge = await
|
|
35239
|
+
const challenge = await fetchJson5(`${base}/agent/challenge`, {
|
|
34728
35240
|
method: "POST",
|
|
34729
35241
|
body: { address }
|
|
34730
35242
|
});
|
|
@@ -34736,7 +35248,7 @@ Subcommands:
|
|
|
34736
35248
|
const message = new TextEncoder().encode(`${action}:${nonce}:${label}`);
|
|
34737
35249
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34738
35250
|
const path2 = opts.release ? "/agent/handle/release" : "/agent/handle";
|
|
34739
|
-
const res = await
|
|
35251
|
+
const res = await fetchJson5(`${base}${path2}`, {
|
|
34740
35252
|
method: "POST",
|
|
34741
35253
|
body: { address, label, nonce, signature }
|
|
34742
35254
|
});
|
|
@@ -34762,7 +35274,7 @@ Subcommands:
|
|
|
34762
35274
|
}
|
|
34763
35275
|
|
|
34764
35276
|
// src/commands/agents.ts
|
|
34765
|
-
var
|
|
35277
|
+
var DEFAULT_API_BASE6 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
34766
35278
|
async function getJson(url) {
|
|
34767
35279
|
const res = await fetch(url, { headers: { accept: "application/json" } });
|
|
34768
35280
|
if (!res.ok) {
|
|
@@ -34777,10 +35289,10 @@ function firstLine(text, max = 76) {
|
|
|
34777
35289
|
function registerAgents(program3) {
|
|
34778
35290
|
program3.command("agents").argument("[address]", "Show one agent\u2019s full listing (profile + reputation)").description(
|
|
34779
35291
|
"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]"
|
|
34780
|
-
).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 ${
|
|
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 ${DEFAULT_API_BASE6})`).action(
|
|
34781
35293
|
async (address, opts) => {
|
|
34782
35294
|
try {
|
|
34783
|
-
const base = opts.api ??
|
|
35295
|
+
const base = opts.api ?? DEFAULT_API_BASE6;
|
|
34784
35296
|
if (address) {
|
|
34785
35297
|
const profile = await getJson(`${base}/agents/${address}`);
|
|
34786
35298
|
if (isJsonMode()) {
|
|
@@ -34853,7 +35365,7 @@ function registerAgents(program3) {
|
|
|
34853
35365
|
}
|
|
34854
35366
|
|
|
34855
35367
|
// src/commands/task/index.ts
|
|
34856
|
-
var
|
|
35368
|
+
var DEFAULT_GATEWAY4 = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
|
|
34857
35369
|
async function getJson2(url) {
|
|
34858
35370
|
const res = await fetch(url, { headers: { accept: "application/json" } });
|
|
34859
35371
|
const json = await res.json().catch(() => ({}));
|
|
@@ -34878,9 +35390,9 @@ function registerTask(program3) {
|
|
|
34878
35390
|
const group = program3.command("task").description(
|
|
34879
35391
|
"Earn from t2000 reward tasks and work (or post) community board tasks \u2014 all paid through the rail. [Agent Commerce]"
|
|
34880
35392
|
);
|
|
34881
|
-
group.command("list").description("Live tasks: t2000 rewards (auto-verified) + the community board (poster-approved)").option("--gateway <url>", `Gateway base URL (default ${
|
|
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) => {
|
|
34882
35394
|
try {
|
|
34883
|
-
const gateway = opts.gateway ??
|
|
35395
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
34884
35396
|
const [rewards, board] = await Promise.all([
|
|
34885
35397
|
getJson2(`${gateway}/tasks/stats`),
|
|
34886
35398
|
getJson2(`${gateway}/tasks/board`)
|
|
@@ -34914,10 +35426,10 @@ function registerTask(program3) {
|
|
|
34914
35426
|
handleError(error);
|
|
34915
35427
|
}
|
|
34916
35428
|
});
|
|
34917
|
-
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 ${
|
|
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(
|
|
34918
35430
|
async (task, opts) => {
|
|
34919
35431
|
try {
|
|
34920
|
-
const gateway = opts.gateway ??
|
|
35432
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
34921
35433
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34922
35434
|
const result = await postJson2(`${gateway}/tasks/claim`, {
|
|
34923
35435
|
task,
|
|
@@ -34946,10 +35458,10 @@ function registerTask(program3) {
|
|
|
34946
35458
|
);
|
|
34947
35459
|
group.command("post").description(
|
|
34948
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."
|
|
34949
|
-
).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 ${
|
|
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(
|
|
34950
35462
|
async (opts) => {
|
|
34951
35463
|
try {
|
|
34952
|
-
const gateway = opts.gateway ??
|
|
35464
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
34953
35465
|
const reward = Number.parseFloat(opts.reward);
|
|
34954
35466
|
const completions = Number.parseInt(opts.completions, 10);
|
|
34955
35467
|
if (!Number.isFinite(reward) || reward <= 0) {
|
|
@@ -34998,10 +35510,10 @@ function registerTask(program3) {
|
|
|
34998
35510
|
}
|
|
34999
35511
|
}
|
|
35000
35512
|
);
|
|
35001
|
-
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 ${
|
|
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(
|
|
35002
35514
|
async (taskId, opts) => {
|
|
35003
35515
|
try {
|
|
35004
|
-
const gateway = opts.gateway ??
|
|
35516
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35005
35517
|
const agent = await withAgent({ keyPath: opts.key });
|
|
35006
35518
|
const result = await postJson2(
|
|
35007
35519
|
`${gateway}/tasks/board/${taskId}/submit`,
|
|
@@ -35023,9 +35535,9 @@ function registerTask(program3) {
|
|
|
35023
35535
|
}
|
|
35024
35536
|
}
|
|
35025
35537
|
);
|
|
35026
|
-
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 ${
|
|
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) => {
|
|
35027
35539
|
try {
|
|
35028
|
-
const gateway = opts.gateway ??
|
|
35540
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35029
35541
|
const result = await getJson2(`${gateway}/tasks/board/${taskId}?manageKey=${encodeURIComponent(opts.manageKey)}`);
|
|
35030
35542
|
if (!result.posterView) {
|
|
35031
35543
|
throw new Error(result.error ?? "manageKey not accepted for this task.");
|
|
@@ -35053,10 +35565,10 @@ function registerTask(program3) {
|
|
|
35053
35565
|
handleError(error);
|
|
35054
35566
|
}
|
|
35055
35567
|
});
|
|
35056
|
-
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 ${
|
|
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(
|
|
35057
35569
|
async (taskId, opts) => {
|
|
35058
35570
|
try {
|
|
35059
|
-
const gateway = opts.gateway ??
|
|
35571
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35060
35572
|
const result = await postJson2(`${gateway}/tasks/board/${taskId}/approve`, {
|
|
35061
35573
|
manageKey: opts.manageKey,
|
|
35062
35574
|
submissionIds: opts.submissions.split(",").map((s) => s.trim()).filter(Boolean),
|
|
@@ -35082,9 +35594,9 @@ function registerTask(program3) {
|
|
|
35082
35594
|
}
|
|
35083
35595
|
}
|
|
35084
35596
|
);
|
|
35085
|
-
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 ${
|
|
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) => {
|
|
35086
35598
|
try {
|
|
35087
|
-
const gateway = opts.gateway ??
|
|
35599
|
+
const gateway = opts.gateway ?? DEFAULT_GATEWAY4;
|
|
35088
35600
|
const result = await postJson2(`${gateway}/tasks/board/${taskId}/close`, { manageKey: opts.manageKey });
|
|
35089
35601
|
if (isJsonMode()) {
|
|
35090
35602
|
printJson(result);
|