@t2000/cli 6.0.0 → 7.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
|
@@ -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-Q2GGV3W4.js");
|
|
33126
33126
|
} catch {
|
|
33127
33127
|
console.error("MCP server not installed. Run:\n npm install -g @t2000/mcp");
|
|
33128
33128
|
process.exit(1);
|
|
@@ -33594,9 +33594,6 @@ For MCP-aware clients (Claude Desktop, Cursor, Windsurf), prefer
|
|
|
33594
33594
|
registerSkillsUninstall(group);
|
|
33595
33595
|
}
|
|
33596
33596
|
|
|
33597
|
-
// src/commands/agent/index.ts
|
|
33598
|
-
import { createHash as createHash2 } from "crypto";
|
|
33599
|
-
|
|
33600
33597
|
// src/commands/agent/create.ts
|
|
33601
33598
|
var DEFAULT_API_BASE3 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
33602
33599
|
var STORE_BASE = "https://agents.t2000.ai";
|
|
@@ -33745,236 +33742,7 @@ function registerAgentCreate(group) {
|
|
|
33745
33742
|
printBlank();
|
|
33746
33743
|
printLine("Next:");
|
|
33747
33744
|
printLine(" t2 fund # add USDC (QR / card link)");
|
|
33748
|
-
printLine(" t2 agent
|
|
33749
|
-
printLine(" t2 agent deploy ... # wrap an API behind x402");
|
|
33750
|
-
printBlank();
|
|
33751
|
-
} catch (error) {
|
|
33752
|
-
handleError(error);
|
|
33753
|
-
}
|
|
33754
|
-
});
|
|
33755
|
-
}
|
|
33756
|
-
|
|
33757
|
-
// src/commands/agent/services.ts
|
|
33758
|
-
import { createHash } from "crypto";
|
|
33759
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
33760
|
-
var SLUG_RE = /^[a-z0-9][a-z0-9-]{1,39}$/;
|
|
33761
|
-
async function fetchJson2(url, init) {
|
|
33762
|
-
const res = await fetch(url, {
|
|
33763
|
-
method: init?.method ?? "GET",
|
|
33764
|
-
headers: init?.body ? { "Content-Type": "application/json" } : void 0,
|
|
33765
|
-
body: init?.body ? JSON.stringify(init.body) : void 0
|
|
33766
|
-
});
|
|
33767
|
-
const json = await res.json().catch(() => ({}));
|
|
33768
|
-
if (!res.ok) {
|
|
33769
|
-
const err = json.error;
|
|
33770
|
-
const msg = typeof err === "string" ? err : err?.message ?? `HTTP ${res.status}`;
|
|
33771
|
-
throw new Error(msg);
|
|
33772
|
-
}
|
|
33773
|
-
return json;
|
|
33774
|
-
}
|
|
33775
|
-
function canonicalServicesJson(services) {
|
|
33776
|
-
return JSON.stringify(
|
|
33777
|
-
services.map(
|
|
33778
|
-
(s) => Object.fromEntries(
|
|
33779
|
-
Object.entries(s).sort(([a], [b]) => a.localeCompare(b))
|
|
33780
|
-
)
|
|
33781
|
-
)
|
|
33782
|
-
);
|
|
33783
|
-
}
|
|
33784
|
-
async function getCatalog(base, address) {
|
|
33785
|
-
const res = await fetchJson2(
|
|
33786
|
-
`${base}/agent/services?address=${encodeURIComponent(address)}`
|
|
33787
|
-
);
|
|
33788
|
-
return Array.isArray(res.services) ? res.services : [];
|
|
33789
|
-
}
|
|
33790
|
-
async function putCatalog(opts) {
|
|
33791
|
-
const agent = await withAgent({ keyPath: opts.keyPath });
|
|
33792
|
-
const address = agent.address();
|
|
33793
|
-
const challenge = await fetchJson2(`${opts.base}/agent/challenge`, {
|
|
33794
|
-
method: "POST",
|
|
33795
|
-
body: { address }
|
|
33796
|
-
});
|
|
33797
|
-
const nonce = challenge.nonce;
|
|
33798
|
-
if (!nonce) {
|
|
33799
|
-
throw new Error("Failed to get a challenge nonce.");
|
|
33800
|
-
}
|
|
33801
|
-
const digest = createHash("sha256").update(canonicalServicesJson(opts.services)).digest("hex");
|
|
33802
|
-
const message = new TextEncoder().encode(
|
|
33803
|
-
`t2000-agent-services:${nonce}:${digest}`
|
|
33804
|
-
);
|
|
33805
|
-
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
33806
|
-
const res = await fetchJson2(`${opts.base}/agent/services`, {
|
|
33807
|
-
method: "POST",
|
|
33808
|
-
body: { address, nonce, signature, services: opts.services }
|
|
33809
|
-
});
|
|
33810
|
-
return { address, count: Number(res.count ?? opts.services.length) };
|
|
33811
|
-
}
|
|
33812
|
-
function entryFromFlags(opts) {
|
|
33813
|
-
const slug = String(opts.slug ?? "").trim().toLowerCase();
|
|
33814
|
-
if (!SLUG_RE.test(slug)) {
|
|
33815
|
-
throw new Error("--slug is required: [a-z0-9-], 2-40 chars.");
|
|
33816
|
-
}
|
|
33817
|
-
const out = { slug };
|
|
33818
|
-
if (opts.title !== void 0) {
|
|
33819
|
-
out.title = opts.title;
|
|
33820
|
-
}
|
|
33821
|
-
if (opts.description !== void 0) {
|
|
33822
|
-
out.description = opts.description;
|
|
33823
|
-
}
|
|
33824
|
-
if (opts.price !== void 0) {
|
|
33825
|
-
out.priceUsdc = opts.price;
|
|
33826
|
-
}
|
|
33827
|
-
if (opts.input !== void 0) {
|
|
33828
|
-
out.input = opts.input || null;
|
|
33829
|
-
}
|
|
33830
|
-
if (opts.endpoint !== void 0) {
|
|
33831
|
-
out.endpoint = opts.endpoint || null;
|
|
33832
|
-
}
|
|
33833
|
-
if (opts.method !== void 0) {
|
|
33834
|
-
out.method = opts.method.toUpperCase() === "GET" ? "GET" : "POST";
|
|
33835
|
-
}
|
|
33836
|
-
return out;
|
|
33837
|
-
}
|
|
33838
|
-
function registerAgentServices(agentGroup, defaults) {
|
|
33839
|
-
const group = agentGroup.command("services").description(
|
|
33840
|
-
"Manage this agent's service CATALOG (one agent, many services). Buy URLs: commerce/pay/<agent>/<slug>. [Store v2]"
|
|
33841
|
-
);
|
|
33842
|
-
group.command("list").argument("[address]", "Agent address (default: your wallet)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).description("List the catalog (public read).").action(async (addressArg, opts) => {
|
|
33843
|
-
try {
|
|
33844
|
-
const base = opts.api ?? defaults.apiBase;
|
|
33845
|
-
const address = addressArg ?? (await withAgent({ keyPath: opts.key })).address();
|
|
33846
|
-
const services = await getCatalog(base, address);
|
|
33847
|
-
if (isJsonMode()) {
|
|
33848
|
-
printJson({ address, services });
|
|
33849
|
-
return;
|
|
33850
|
-
}
|
|
33851
|
-
printBlank();
|
|
33852
|
-
if (services.length === 0) {
|
|
33853
|
-
printLine("No services in the catalog. Add one: t2 agent services add --slug <slug> --title \u2026 --description \u2026 --price \u2026");
|
|
33854
|
-
printBlank();
|
|
33855
|
-
return;
|
|
33856
|
-
}
|
|
33857
|
-
for (const s of services) {
|
|
33858
|
-
printKeyValue(
|
|
33859
|
-
s.slug,
|
|
33860
|
-
`$${s.priceUsdc} \u2014 ${s.title}${s.active === false ? " (inactive)" : ""}`
|
|
33861
|
-
);
|
|
33862
|
-
}
|
|
33863
|
-
printBlank();
|
|
33864
|
-
} catch (error) {
|
|
33865
|
-
handleError(error);
|
|
33866
|
-
}
|
|
33867
|
-
});
|
|
33868
|
-
group.command("add").description("Add one service to the catalog.").requiredOption("--slug <slug>", "Service slug ([a-z0-9-], 2-40 chars)").requiredOption("--title <title>", "Service title (\u226480 chars)").requiredOption("--description <text>", "Listing copy (\u2264480 chars)").requiredOption("--price <usdc>", "Price per call in USDC (e.g. 0.02)").option("--input <hint>", 'Input hint, e.g. "Provide: 1. address 2. chain"').option("--endpoint <url>", "Self-hosted https endpoint (omit for wrap/payment-only)").option("--method <method>", "Wrap delivery method: GET or POST").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).action(async (opts) => {
|
|
33869
|
-
try {
|
|
33870
|
-
const base = opts.api ?? defaults.apiBase;
|
|
33871
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
33872
|
-
const current = await getCatalog(base, agent.address());
|
|
33873
|
-
const entry = entryFromFlags(opts);
|
|
33874
|
-
if (current.some((s) => s.slug === entry.slug)) {
|
|
33875
|
-
throw new Error(
|
|
33876
|
-
`Slug "${entry.slug}" already exists \u2014 use: t2 agent services update --slug ${entry.slug}`
|
|
33877
|
-
);
|
|
33878
|
-
}
|
|
33879
|
-
const next = {
|
|
33880
|
-
title: "",
|
|
33881
|
-
description: "",
|
|
33882
|
-
priceUsdc: "0",
|
|
33883
|
-
active: true,
|
|
33884
|
-
...entry
|
|
33885
|
-
};
|
|
33886
|
-
const { count } = await putCatalog({
|
|
33887
|
-
base,
|
|
33888
|
-
keyPath: opts.key,
|
|
33889
|
-
services: [...current, next]
|
|
33890
|
-
});
|
|
33891
|
-
if (isJsonMode()) {
|
|
33892
|
-
printJson({ added: entry.slug, count });
|
|
33893
|
-
return;
|
|
33894
|
-
}
|
|
33895
|
-
printBlank();
|
|
33896
|
-
printSuccess(`Service "${entry.slug}" added \u2014 catalog now ${count} service${count === 1 ? "" : "s"}.`);
|
|
33897
|
-
printLine(`Buy URL: https://x402.t2000.ai/commerce/pay/${agent.address()}/${entry.slug}`);
|
|
33898
|
-
printBlank();
|
|
33899
|
-
} catch (error) {
|
|
33900
|
-
handleError(error);
|
|
33901
|
-
}
|
|
33902
|
-
});
|
|
33903
|
-
group.command("update").description("Update one service (only the provided fields change).").requiredOption("--slug <slug>", "Service slug to update").option("--title <title>", "Service title (\u226480 chars)").option("--description <text>", "Listing copy (\u2264480 chars)").option("--price <usdc>", "Price per call in USDC").option("--input <hint>", 'Input hint ("" to clear)').option("--endpoint <url>", 'Self-hosted https endpoint ("" to clear \u2192 wrap mode)').option("--method <method>", "Wrap delivery method: GET or POST").option("--active <bool>", "true | false \u2014 per-service kill switch").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).action(async (opts) => {
|
|
33904
|
-
try {
|
|
33905
|
-
const base = opts.api ?? defaults.apiBase;
|
|
33906
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
33907
|
-
const current = await getCatalog(base, agent.address());
|
|
33908
|
-
const entry = entryFromFlags(opts);
|
|
33909
|
-
const idx = current.findIndex((s) => s.slug === entry.slug);
|
|
33910
|
-
if (idx === -1) {
|
|
33911
|
-
throw new Error(`No service "${entry.slug}" in the catalog.`);
|
|
33912
|
-
}
|
|
33913
|
-
const merged = { ...current[idx], ...entry };
|
|
33914
|
-
if (opts.active !== void 0) {
|
|
33915
|
-
merged.active = String(opts.active).toLowerCase() !== "false";
|
|
33916
|
-
}
|
|
33917
|
-
const services = [...current];
|
|
33918
|
-
services[idx] = merged;
|
|
33919
|
-
const { count } = await putCatalog({ base, keyPath: opts.key, services });
|
|
33920
|
-
if (isJsonMode()) {
|
|
33921
|
-
printJson({ updated: entry.slug, count });
|
|
33922
|
-
return;
|
|
33923
|
-
}
|
|
33924
|
-
printBlank();
|
|
33925
|
-
printSuccess(`Service "${entry.slug}" updated.`);
|
|
33926
|
-
printBlank();
|
|
33927
|
-
} catch (error) {
|
|
33928
|
-
handleError(error);
|
|
33929
|
-
}
|
|
33930
|
-
});
|
|
33931
|
-
group.command("remove").description("Remove one service from the catalog.").requiredOption("--slug <slug>", "Service slug to remove").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).action(async (opts) => {
|
|
33932
|
-
try {
|
|
33933
|
-
const base = opts.api ?? defaults.apiBase;
|
|
33934
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
33935
|
-
const slug = String(opts.slug ?? "").trim().toLowerCase();
|
|
33936
|
-
const current = await getCatalog(base, agent.address());
|
|
33937
|
-
const services = current.filter((s) => s.slug !== slug);
|
|
33938
|
-
if (services.length === current.length) {
|
|
33939
|
-
throw new Error(`No service "${slug}" in the catalog.`);
|
|
33940
|
-
}
|
|
33941
|
-
const { count } = await putCatalog({ base, keyPath: opts.key, services });
|
|
33942
|
-
if (isJsonMode()) {
|
|
33943
|
-
printJson({ removed: slug, count });
|
|
33944
|
-
return;
|
|
33945
|
-
}
|
|
33946
|
-
printBlank();
|
|
33947
|
-
printSuccess(`Service "${slug}" removed \u2014 catalog now ${count} service${count === 1 ? "" : "s"}.`);
|
|
33948
|
-
printBlank();
|
|
33949
|
-
} catch (error) {
|
|
33950
|
-
handleError(error);
|
|
33951
|
-
}
|
|
33952
|
-
});
|
|
33953
|
-
group.command("sync").description(
|
|
33954
|
-
"Declarative catalog sync \u2014 the manifest file IS the catalog (adds/updates/removes to match). The catalog-scale path."
|
|
33955
|
-
).argument("<file>", "Path to a JSON manifest: [{ slug, title, description, priceUsdc, input?, endpoint?, method?, active? }]").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").option("--api <url>", `API base URL (default ${defaults.apiBase})`).action(async (file, opts) => {
|
|
33956
|
-
try {
|
|
33957
|
-
const base = opts.api ?? defaults.apiBase;
|
|
33958
|
-
const raw = JSON.parse(readFileSync3(file, "utf8"));
|
|
33959
|
-
const list = Array.isArray(raw) ? raw : raw?.services ?? null;
|
|
33960
|
-
if (!Array.isArray(list)) {
|
|
33961
|
-
throw new Error(
|
|
33962
|
-
'Manifest must be a JSON array of services (or { "services": [...] }).'
|
|
33963
|
-
);
|
|
33964
|
-
}
|
|
33965
|
-
const services = list.map((s) => {
|
|
33966
|
-
const entry = s;
|
|
33967
|
-
return { ...entry, active: entry.active !== false };
|
|
33968
|
-
});
|
|
33969
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
33970
|
-
const before = await getCatalog(base, agent.address());
|
|
33971
|
-
const { count } = await putCatalog({ base, keyPath: opts.key, services });
|
|
33972
|
-
if (isJsonMode()) {
|
|
33973
|
-
printJson({ synced: count, before: before.length });
|
|
33974
|
-
return;
|
|
33975
|
-
}
|
|
33976
|
-
printBlank();
|
|
33977
|
-
printSuccess(`Catalog synced \u2014 ${before.length} \u2192 ${count} services.`);
|
|
33745
|
+
printLine(" t2 agent service ... # declare a paid endpoint (sell per call)");
|
|
33978
33746
|
printBlank();
|
|
33979
33747
|
} catch (error) {
|
|
33980
33748
|
handleError(error);
|
|
@@ -33985,7 +33753,6 @@ function registerAgentServices(agentGroup, defaults) {
|
|
|
33985
33753
|
// src/commands/agent/index.ts
|
|
33986
33754
|
var DEFAULT_API_BASE4 = process.env.T2000_API_URL ?? "https://api.t2000.ai/v1";
|
|
33987
33755
|
var DEFAULT_GATEWAY = process.env.T2000_GATEWAY_URL ?? "https://mpp.t2000.ai";
|
|
33988
|
-
var DEFAULT_RAIL = process.env.T2000_RAIL_URL ?? "https://x402.t2000.ai";
|
|
33989
33756
|
var AGENT_CATEGORIES2 = [
|
|
33990
33757
|
"ai-models",
|
|
33991
33758
|
"data-feeds",
|
|
@@ -34007,13 +33774,6 @@ function normalizeCategory(input) {
|
|
|
34007
33774
|
}
|
|
34008
33775
|
return c;
|
|
34009
33776
|
}
|
|
34010
|
-
function collectHeader(value, previous) {
|
|
34011
|
-
const [key, ...rest] = value.split("=");
|
|
34012
|
-
if (key && rest.length > 0) {
|
|
34013
|
-
previous[key.trim()] = rest.join("=").trim();
|
|
34014
|
-
}
|
|
34015
|
-
return previous;
|
|
34016
|
-
}
|
|
34017
33777
|
function normalizeTopupAsset(input) {
|
|
34018
33778
|
return input?.toLowerCase() === "usdsui" ? "USDsui" : "USDC";
|
|
34019
33779
|
}
|
|
@@ -34023,19 +33783,19 @@ async function fundCredit(agent, base, amountStr, assetOpt) {
|
|
|
34023
33783
|
throw new Error(`amount must be a positive number (got "${amountStr}").`);
|
|
34024
33784
|
}
|
|
34025
33785
|
const asset = normalizeTopupAsset(assetOpt);
|
|
34026
|
-
const cfg = await
|
|
33786
|
+
const cfg = await fetchJson2(`${base}/agent/topup`, { method: "GET" });
|
|
34027
33787
|
const treasury = cfg.treasury;
|
|
34028
33788
|
if (!treasury) {
|
|
34029
33789
|
throw new Error("Could not resolve the t2000 treasury address.");
|
|
34030
33790
|
}
|
|
34031
33791
|
const sent = await agent.send({ to: treasury, amount, asset });
|
|
34032
|
-
const topup = await
|
|
33792
|
+
const topup = await fetchJson2(`${base}/agent/topup`, {
|
|
34033
33793
|
method: "POST",
|
|
34034
33794
|
body: { address: agent.address(), digest: sent.tx }
|
|
34035
33795
|
});
|
|
34036
33796
|
return { amount, asset, balanceUsd: topup.balanceUsd };
|
|
34037
33797
|
}
|
|
34038
|
-
async function
|
|
33798
|
+
async function fetchJson2(url, init) {
|
|
34039
33799
|
const res = await fetch(url, {
|
|
34040
33800
|
method: init.method,
|
|
34041
33801
|
headers: init.body ? { "Content-Type": "application/json" } : void 0,
|
|
@@ -34058,12 +33818,10 @@ Subcommands:
|
|
|
34058
33818
|
$ t2 agent onboard --fund 5 Fund 5 USDC \u2192 mint an API key (ready to call)
|
|
34059
33819
|
$ t2 agent onboard --fund 5 --asset USDsui
|
|
34060
33820
|
$ t2 agent onboard Already funded \u2192 just mint a key
|
|
34061
|
-
$ t2 agent
|
|
34062
|
-
$ t2 agent services sync ./services.json Manifest IS the catalog (catalog-scale sellers)
|
|
33821
|
+
$ t2 agent pay <address> Pay another agent's declared service
|
|
34063
33822
|
`
|
|
34064
33823
|
);
|
|
34065
33824
|
registerAgentCreate(group);
|
|
34066
|
-
registerAgentServices(group, { apiBase: DEFAULT_API_BASE4 });
|
|
34067
33825
|
group.command("onboard").description(
|
|
34068
33826
|
"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`."
|
|
34069
33827
|
).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(
|
|
@@ -34080,7 +33838,7 @@ Subcommands:
|
|
|
34080
33838
|
);
|
|
34081
33839
|
}
|
|
34082
33840
|
}
|
|
34083
|
-
const challenge = await
|
|
33841
|
+
const challenge = await fetchJson2(`${base}/agent/challenge`, {
|
|
34084
33842
|
method: "POST",
|
|
34085
33843
|
body: { address }
|
|
34086
33844
|
});
|
|
@@ -34090,7 +33848,7 @@ Subcommands:
|
|
|
34090
33848
|
}
|
|
34091
33849
|
const message = new TextEncoder().encode(`t2000-agent-keys:${nonce}`);
|
|
34092
33850
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34093
|
-
const minted = await
|
|
33851
|
+
const minted = await fetchJson2(`${base}/agent/keys`, {
|
|
34094
33852
|
method: "POST",
|
|
34095
33853
|
body: { address, nonce, signature }
|
|
34096
33854
|
});
|
|
@@ -34287,7 +34045,7 @@ Subcommands:
|
|
|
34287
34045
|
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34288
34046
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34289
34047
|
const address = agent.address();
|
|
34290
|
-
const challenge = await
|
|
34048
|
+
const challenge = await fetchJson2(`${base}/agent/challenge`, {
|
|
34291
34049
|
method: "POST",
|
|
34292
34050
|
body: { address }
|
|
34293
34051
|
});
|
|
@@ -34297,7 +34055,7 @@ Subcommands:
|
|
|
34297
34055
|
}
|
|
34298
34056
|
const message = new TextEncoder().encode(`t2000-agent-profile:${nonce}`);
|
|
34299
34057
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34300
|
-
await
|
|
34058
|
+
await fetchJson2(`${base}/agent/profile`, {
|
|
34301
34059
|
method: "POST",
|
|
34302
34060
|
body: {
|
|
34303
34061
|
address,
|
|
@@ -34394,141 +34152,9 @@ Subcommands:
|
|
|
34394
34152
|
}
|
|
34395
34153
|
}
|
|
34396
34154
|
);
|
|
34397
|
-
group.command("deploy").description(
|
|
34398
|
-
"Deploy a paid service by wrapping any HTTP API \u2014 t2000 hosts the proxy (your key stays server-side, encrypted), lists it, and settles payments. No server needed. Use --remove to take it down. [Agent Commerce]"
|
|
34399
|
-
).option("--upstream <url>", "The upstream API URL to wrap (https)").option(
|
|
34400
|
-
"--header <k=v>",
|
|
34401
|
-
"Header to inject into upstream calls (repeatable; e.g. your API key)",
|
|
34402
|
-
collectHeader,
|
|
34403
|
-
{}
|
|
34404
|
-
).option("--method <method>", "Upstream method: GET or POST (default POST)").option("--price <usdc>", "Price per call in USDC (e.g. 0.02)").option(
|
|
34405
|
-
"--category <category>",
|
|
34406
|
-
`Storefront category: ${AGENT_CATEGORIES2.join(" | ")}`
|
|
34407
|
-
).option("--remove", "Take down the deployed service").option(
|
|
34408
|
-
"--service <slug>",
|
|
34409
|
-
"Catalog service slug \u2014 wrap config for ONE SKU (Store v2; omit = the default service)"
|
|
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(
|
|
34411
|
-
async (opts) => {
|
|
34412
|
-
try {
|
|
34413
|
-
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34414
|
-
const gateway = opts.gateway ?? DEFAULT_GATEWAY;
|
|
34415
|
-
const category = normalizeCategory(opts.category);
|
|
34416
|
-
const slug = opts.service?.trim().toLowerCase() || void 0;
|
|
34417
|
-
const agent = await withAgent({ keyPath: opts.key });
|
|
34418
|
-
const address = agent.address();
|
|
34419
|
-
if (opts.remove) {
|
|
34420
|
-
const ts2 = Date.now();
|
|
34421
|
-
const msg2 = `t2000-deploy-remove:${ts2}${slug ? `:${slug}` : ""}`;
|
|
34422
|
-
const { signature: signature2 } = await agent.keypair.signPersonalMessage(
|
|
34423
|
-
new TextEncoder().encode(msg2)
|
|
34424
|
-
);
|
|
34425
|
-
await fetchJson3(`${gateway}/deploy/config`, {
|
|
34426
|
-
method: "DELETE",
|
|
34427
|
-
body: { address, timestamp: ts2, signature: signature2, ...slug ? { slug } : {} }
|
|
34428
|
-
});
|
|
34429
|
-
if (!slug) {
|
|
34430
|
-
await runSponsoredTx({
|
|
34431
|
-
keypair: agent.keypair,
|
|
34432
|
-
actor: address,
|
|
34433
|
-
prepareUrl: `${base}/agent/service/prepare`,
|
|
34434
|
-
prepareBody: { address, mcpEndpoint: "" },
|
|
34435
|
-
submitUrl: `${base}/agent/service/submit`
|
|
34436
|
-
}).catch(() => void 0);
|
|
34437
|
-
}
|
|
34438
|
-
if (isJsonMode()) {
|
|
34439
|
-
printJson({ address, removed: true });
|
|
34440
|
-
return;
|
|
34441
|
-
}
|
|
34442
|
-
printBlank();
|
|
34443
|
-
printSuccess("Service taken down.");
|
|
34444
|
-
printBlank();
|
|
34445
|
-
return;
|
|
34446
|
-
}
|
|
34447
|
-
if (!(opts.upstream && opts.price)) {
|
|
34448
|
-
throw new Error("Both --upstream and --price are required (or use --remove).");
|
|
34449
|
-
}
|
|
34450
|
-
const price = Number.parseFloat(opts.price);
|
|
34451
|
-
if (Number.isNaN(price) || price <= 0) {
|
|
34452
|
-
throw new Error(`--price must be a positive number (got "${opts.price}").`);
|
|
34453
|
-
}
|
|
34454
|
-
const method = (opts.method ?? "POST").toUpperCase() === "GET" ? "GET" : "POST";
|
|
34455
|
-
const headers = opts.header ?? {};
|
|
34456
|
-
const ts = Date.now();
|
|
34457
|
-
const bodyHash = createHash2("sha256").update(
|
|
34458
|
-
`${opts.upstream}|${method}|${JSON.stringify(headers)}${slug ? `|${slug}` : ""}`
|
|
34459
|
-
).digest("hex");
|
|
34460
|
-
const msg = `t2000-deploy:${ts}:${bodyHash}`;
|
|
34461
|
-
const { signature } = await agent.keypair.signPersonalMessage(
|
|
34462
|
-
new TextEncoder().encode(msg)
|
|
34463
|
-
);
|
|
34464
|
-
await fetchJson3(`${gateway}/deploy/config`, {
|
|
34465
|
-
method: "POST",
|
|
34466
|
-
body: {
|
|
34467
|
-
address,
|
|
34468
|
-
timestamp: ts,
|
|
34469
|
-
signature,
|
|
34470
|
-
upstreamUrl: opts.upstream,
|
|
34471
|
-
method,
|
|
34472
|
-
headers,
|
|
34473
|
-
...slug ? { slug } : {}
|
|
34474
|
-
}
|
|
34475
|
-
});
|
|
34476
|
-
if (slug) {
|
|
34477
|
-
if (isJsonMode()) {
|
|
34478
|
-
printJson({ address, slug, upstream: opts.upstream, price });
|
|
34479
|
-
return;
|
|
34480
|
-
}
|
|
34481
|
-
printBlank();
|
|
34482
|
-
printSuccess(`Wrap config stored for service "${slug}".`);
|
|
34483
|
-
printKeyValue("Wraps", opts.upstream);
|
|
34484
|
-
printKeyValue("Buy URL", `${DEFAULT_RAIL}/commerce/pay/${address}/${slug}`);
|
|
34485
|
-
printInfo(
|
|
34486
|
-
`List it in the catalog: t2 agent services add --slug ${slug} --title \u2026 --description \u2026 --price ${opts.price}`
|
|
34487
|
-
);
|
|
34488
|
-
printBlank();
|
|
34489
|
-
return;
|
|
34490
|
-
}
|
|
34491
|
-
const { digest } = await runSponsoredTx({
|
|
34492
|
-
keypair: agent.keypair,
|
|
34493
|
-
actor: address,
|
|
34494
|
-
prepareUrl: `${base}/agent/service/prepare`,
|
|
34495
|
-
prepareBody: {
|
|
34496
|
-
address,
|
|
34497
|
-
// The real, x402-callable buy endpoint (GET → 402 + requirements,
|
|
34498
|
-
// pay → collect/deliver/forward). `/deploy/<addr>` was a phantom
|
|
34499
|
-
// (no route → 404). Any x402 client can hit this URL.
|
|
34500
|
-
mcpEndpoint: `${DEFAULT_RAIL}/commerce/pay/${address}`,
|
|
34501
|
-
paymentMethods: ["x402"],
|
|
34502
|
-
priceUsdc: opts.price,
|
|
34503
|
-
...category ? { category } : {}
|
|
34504
|
-
},
|
|
34505
|
-
submitUrl: `${base}/agent/service/submit`
|
|
34506
|
-
});
|
|
34507
|
-
if (isJsonMode()) {
|
|
34508
|
-
printJson({ address, upstream: opts.upstream, price, digest });
|
|
34509
|
-
return;
|
|
34510
|
-
}
|
|
34511
|
-
printBlank();
|
|
34512
|
-
printSuccess("Service deployed \u2014 live + listed in the directory.");
|
|
34513
|
-
printKeyValue("Wraps", opts.upstream);
|
|
34514
|
-
printKeyValue("Price", `$${opts.price} USDC`);
|
|
34515
|
-
if (category) {
|
|
34516
|
-
printKeyValue("Category", category);
|
|
34517
|
-
}
|
|
34518
|
-
printKeyValue("Tx", String(digest));
|
|
34519
|
-
printInfo(`Buyers: t2 agent pay ${truncateAddress(address)}`);
|
|
34520
|
-
printBlank();
|
|
34521
|
-
} catch (error) {
|
|
34522
|
-
handleError(error);
|
|
34523
|
-
}
|
|
34524
|
-
}
|
|
34525
|
-
);
|
|
34526
34155
|
group.command("pay").argument("<seller>", "The seller agent's Sui address").description(
|
|
34527
34156
|
"Pay a seller agent for a service (gateway-mediated, USDC). t2000 collects, keeps a small fee, and forwards the rest to the seller \u2014 with a receipt. [Agent Commerce]"
|
|
34528
34157
|
).option("--amount <usdc>", "Override the price (default: the seller's declared price)").option("--data <json>", "Service input forwarded to the seller's endpoint").option("--max-price <usdc>", "Max USDC to auto-approve (default 1.00, or --amount)").option(
|
|
34529
|
-
"--service <slug>",
|
|
34530
|
-
"Catalog service slug \u2014 buys ONE SKU of the seller's catalog (Store v2)"
|
|
34531
|
-
).option(
|
|
34532
34158
|
"--gateway <url>",
|
|
34533
34159
|
`Gateway base URL (default ${DEFAULT_GATEWAY})`
|
|
34534
34160
|
).option("--force", "Override spending limits for this call (see `t2 limit`)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(
|
|
@@ -34544,8 +34170,7 @@ Subcommands:
|
|
|
34544
34170
|
const gateway = opts.gateway ?? DEFAULT_GATEWAY;
|
|
34545
34171
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34546
34172
|
const resolvedSeller = seller.startsWith("0x") ? seller : (await agent.resolveRecipient(seller)).address;
|
|
34547
|
-
const
|
|
34548
|
-
const url = opts.amount ? `${gateway}/commerce/pay/${resolvedSeller}${slugPath}?amount=${encodeURIComponent(opts.amount)}` : `${gateway}/commerce/pay/${resolvedSeller}${slugPath}`;
|
|
34173
|
+
const url = opts.amount ? `${gateway}/commerce/pay/${resolvedSeller}?amount=${encodeURIComponent(opts.amount)}` : `${gateway}/commerce/pay/${resolvedSeller}`;
|
|
34549
34174
|
const result = await agent.pay({
|
|
34550
34175
|
url,
|
|
34551
34176
|
method: "POST",
|
|
@@ -34614,7 +34239,7 @@ Subcommands:
|
|
|
34614
34239
|
const gateway = opts.gateway ?? DEFAULT_GATEWAY;
|
|
34615
34240
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34616
34241
|
const address = agent.address();
|
|
34617
|
-
const stats = await
|
|
34242
|
+
const stats = await fetchJson2(
|
|
34618
34243
|
`${gateway}/commerce/stats/${address}`,
|
|
34619
34244
|
{ method: "GET" }
|
|
34620
34245
|
);
|
|
@@ -34643,7 +34268,7 @@ Subcommands:
|
|
|
34643
34268
|
const base = opts.api ?? DEFAULT_API_BASE4;
|
|
34644
34269
|
const agent = await withAgent({ keyPath: opts.key });
|
|
34645
34270
|
const address = agent.address();
|
|
34646
|
-
const challenge = await
|
|
34271
|
+
const challenge = await fetchJson2(`${base}/agent/challenge`, {
|
|
34647
34272
|
method: "POST",
|
|
34648
34273
|
body: { address }
|
|
34649
34274
|
});
|
|
@@ -34655,7 +34280,7 @@ Subcommands:
|
|
|
34655
34280
|
const message = new TextEncoder().encode(`${action}:${nonce}:${label}`);
|
|
34656
34281
|
const { signature } = await agent.keypair.signPersonalMessage(message);
|
|
34657
34282
|
const path2 = opts.release ? "/agent/handle/release" : "/agent/handle";
|
|
34658
|
-
const res = await
|
|
34283
|
+
const res = await fetchJson2(`${base}${path2}`, {
|
|
34659
34284
|
method: "POST",
|
|
34660
34285
|
body: { address, label, nonce, signature }
|
|
34661
34286
|
});
|
|
@@ -34695,8 +34320,8 @@ function firstLine(text, max = 76) {
|
|
|
34695
34320
|
}
|
|
34696
34321
|
function registerAgents(program3) {
|
|
34697
34322
|
program3.command("agents").argument("[address]", "Show one agent\u2019s full listing (profile + reputation)").description(
|
|
34698
|
-
"
|
|
34699
|
-
).option("--category <category>", "Filter the list by
|
|
34323
|
+
"Look up the agent directory (agents.t2000.ai): priced services from the live registry, or one agent\u2019s full listing. Buy with `t2 agent pay <address>`. [Agent Commerce]"
|
|
34324
|
+
).option("--category <category>", "Filter the list by 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(
|
|
34700
34325
|
async (address, opts) => {
|
|
34701
34326
|
try {
|
|
34702
34327
|
const base = opts.api ?? DEFAULT_API_BASE5;
|
|
@@ -34752,7 +34377,7 @@ function registerAgents(program3) {
|
|
|
34752
34377
|
}
|
|
34753
34378
|
printBlank();
|
|
34754
34379
|
printHeader(
|
|
34755
|
-
`Agent
|
|
34380
|
+
`Agent directory \u2014 ${agents.length} ${opts.all ? "agents" : "priced services"}${opts.category ? ` in ${opts.category}` : ""}`
|
|
34756
34381
|
);
|
|
34757
34382
|
for (const a of agents) {
|
|
34758
34383
|
const price = a.priceUsdc ? formatUsd(Number.parseFloat(a.priceUsdc)).padStart(6) : " \u2014";
|
|
@@ -34792,7 +34417,7 @@ Examples:
|
|
|
34792
34417
|
$ t2 models List the Private API model catalog
|
|
34793
34418
|
$ t2 pay <url> --estimate Preview an x402 service's price + input schema (no payment)
|
|
34794
34419
|
$ t2 services search "image" Discover x402 services in the gateway catalog
|
|
34795
|
-
$ t2 agents
|
|
34420
|
+
$ t2 agents Look up the agent directory (agents.t2000.ai)
|
|
34796
34421
|
$ t2 agent pay <address> Buy an agent's service (escrowed, auto-refund on failure)
|
|
34797
34422
|
$ t2 limit set --daily 100 Change the daily spend cap (default $100/day)
|
|
34798
34423
|
$ t2 mcp install Connect Claude / Cursor / Windsurf
|