arc402-cli 1.0.0-rc.1 → 1.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/README.md +41 -2
- package/dist/abis.d.ts +1 -0
- package/dist/abis.d.ts.map +1 -1
- package/dist/abis.js +29 -1
- package/dist/abis.js.map +1 -1
- package/dist/commands/backup.d.ts +3 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +106 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/compute.d.ts +14 -0
- package/dist/commands/compute.d.ts.map +1 -0
- package/dist/commands/compute.js +466 -0
- package/dist/commands/compute.js.map +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +11 -1
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +67 -0
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/discover.d.ts.map +1 -1
- package/dist/commands/discover.js +60 -15
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +205 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +299 -65
- package/dist/commands/wallet.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +146 -9
- package/dist/commands/watch.js.map +1 -1
- package/dist/commands/workroom.d.ts.map +1 -1
- package/dist/commands/workroom.js +112 -6
- package/dist/commands/workroom.js.map +1 -1
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +41 -4
- package/dist/config.js.map +1 -1
- package/dist/daemon/compute-metering.d.ts +61 -0
- package/dist/daemon/compute-metering.d.ts.map +1 -0
- package/dist/daemon/compute-metering.js +299 -0
- package/dist/daemon/compute-metering.js.map +1 -0
- package/dist/daemon/compute-session.d.ts +100 -0
- package/dist/daemon/compute-session.d.ts.map +1 -0
- package/dist/daemon/compute-session.js +231 -0
- package/dist/daemon/compute-session.js.map +1 -0
- package/dist/daemon/config.d.ts +33 -1
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +69 -0
- package/dist/daemon/config.js.map +1 -1
- package/dist/daemon/credentials.d.ts +24 -0
- package/dist/daemon/credentials.d.ts.map +1 -0
- package/dist/daemon/credentials.js +80 -0
- package/dist/daemon/credentials.js.map +1 -0
- package/dist/daemon/delivery-client.d.ts +35 -0
- package/dist/daemon/delivery-client.d.ts.map +1 -0
- package/dist/daemon/delivery-client.js +231 -0
- package/dist/daemon/delivery-client.js.map +1 -0
- package/dist/daemon/file-delivery.d.ts +98 -0
- package/dist/daemon/file-delivery.d.ts.map +1 -0
- package/dist/daemon/file-delivery.js +461 -0
- package/dist/daemon/file-delivery.js.map +1 -0
- package/dist/daemon/index.d.ts +1 -0
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +793 -227
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/notify.d.ts +35 -6
- package/dist/daemon/notify.d.ts.map +1 -1
- package/dist/daemon/notify.js +176 -48
- package/dist/daemon/notify.js.map +1 -1
- package/dist/daemon/worker-executor.d.ts +71 -0
- package/dist/daemon/worker-executor.d.ts.map +1 -0
- package/dist/daemon/worker-executor.js +382 -0
- package/dist/daemon/worker-executor.js.map +1 -0
- package/dist/drain-v4.js +2 -2
- package/dist/drain-v4.js.map +1 -1
- package/dist/endpoint-notify.d.ts +9 -1
- package/dist/endpoint-notify.d.ts.map +1 -1
- package/dist/endpoint-notify.js +116 -3
- package/dist/endpoint-notify.js.map +1 -1
- package/dist/index.js +81 -1
- package/dist/index.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +6 -0
- package/dist/program.js.map +1 -1
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +69 -486
- package/dist/repl.js.map +1 -1
- package/dist/tui/App.d.ts +12 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +154 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/Footer.d.ts +11 -0
- package/dist/tui/Footer.d.ts.map +1 -0
- package/dist/tui/Footer.js +13 -0
- package/dist/tui/Footer.js.map +1 -0
- package/dist/tui/Header.d.ts +14 -0
- package/dist/tui/Header.d.ts.map +1 -0
- package/dist/tui/Header.js +19 -0
- package/dist/tui/Header.js.map +1 -0
- package/dist/tui/InputLine.d.ts +11 -0
- package/dist/tui/InputLine.d.ts.map +1 -0
- package/dist/tui/InputLine.js +145 -0
- package/dist/tui/InputLine.js.map +1 -0
- package/dist/tui/Viewport.d.ts +14 -0
- package/dist/tui/Viewport.d.ts.map +1 -0
- package/dist/tui/Viewport.js +48 -0
- package/dist/tui/Viewport.js.map +1 -0
- package/dist/tui/WalletConnectPairing.d.ts +23 -0
- package/dist/tui/WalletConnectPairing.d.ts.map +1 -0
- package/dist/tui/WalletConnectPairing.js +61 -0
- package/dist/tui/WalletConnectPairing.js.map +1 -0
- package/dist/tui/components/Button.d.ts +7 -0
- package/dist/tui/components/Button.d.ts.map +1 -0
- package/dist/tui/components/Button.js +21 -0
- package/dist/tui/components/Button.js.map +1 -0
- package/dist/tui/components/CeremonyView.d.ts +13 -0
- package/dist/tui/components/CeremonyView.d.ts.map +1 -0
- package/dist/tui/components/CeremonyView.js +10 -0
- package/dist/tui/components/CeremonyView.js.map +1 -0
- package/dist/tui/components/CompletionDropdown.d.ts +7 -0
- package/dist/tui/components/CompletionDropdown.d.ts.map +1 -0
- package/dist/tui/components/CompletionDropdown.js +23 -0
- package/dist/tui/components/CompletionDropdown.js.map +1 -0
- package/dist/tui/components/ConfirmPrompt.d.ts +9 -0
- package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
- package/dist/tui/components/ConfirmPrompt.js +10 -0
- package/dist/tui/components/ConfirmPrompt.js.map +1 -0
- package/dist/tui/components/CustomTextInput.d.ts +15 -0
- package/dist/tui/components/CustomTextInput.d.ts.map +1 -0
- package/dist/tui/components/CustomTextInput.js +99 -0
- package/dist/tui/components/CustomTextInput.js.map +1 -0
- package/dist/tui/components/InteractiveTable.d.ts +14 -0
- package/dist/tui/components/InteractiveTable.d.ts.map +1 -0
- package/dist/tui/components/InteractiveTable.js +61 -0
- package/dist/tui/components/InteractiveTable.js.map +1 -0
- package/dist/tui/components/StepSpinner.d.ts +11 -0
- package/dist/tui/components/StepSpinner.d.ts.map +1 -0
- package/dist/tui/components/StepSpinner.js +32 -0
- package/dist/tui/components/StepSpinner.js.map +1 -0
- package/dist/tui/components/Toast.d.ts +18 -0
- package/dist/tui/components/Toast.d.ts.map +1 -0
- package/dist/tui/components/Toast.js +29 -0
- package/dist/tui/components/Toast.js.map +1 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +55 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/useChat.d.ts +11 -0
- package/dist/tui/useChat.d.ts.map +1 -0
- package/dist/tui/useChat.js +91 -0
- package/dist/tui/useChat.js.map +1 -0
- package/dist/tui/useCommand.d.ts +12 -0
- package/dist/tui/useCommand.d.ts.map +1 -0
- package/dist/tui/useCommand.js +137 -0
- package/dist/tui/useCommand.js.map +1 -0
- package/dist/tui/useNotifications.d.ts +9 -0
- package/dist/tui/useNotifications.d.ts.map +1 -0
- package/dist/tui/useNotifications.js +17 -0
- package/dist/tui/useNotifications.js.map +1 -0
- package/dist/tui/useScroll.d.ts +17 -0
- package/dist/tui/useScroll.d.ts.map +1 -0
- package/dist/tui/useScroll.js +46 -0
- package/dist/tui/useScroll.js.map +1 -0
- package/dist/ui/format.d.ts.map +1 -1
- package/dist/ui/format.js +2 -0
- package/dist/ui/format.js.map +1 -1
- package/dist/ui/qr-render.d.ts +25 -0
- package/dist/ui/qr-render.d.ts.map +1 -0
- package/dist/ui/qr-render.js +90 -0
- package/dist/ui/qr-render.js.map +1 -0
- package/dist/ui/rpc-fallback.d.ts +11 -0
- package/dist/ui/rpc-fallback.d.ts.map +1 -0
- package/dist/ui/rpc-fallback.js +58 -0
- package/dist/ui/rpc-fallback.js.map +1 -0
- package/dist/walletconnect.d.ts +4 -0
- package/dist/walletconnect.d.ts.map +1 -1
- package/dist/walletconnect.js.map +1 -1
- package/package.json +10 -2
- package/scripts/authorize-machine-key.ts +0 -43
- package/scripts/drain-wallet.ts +0 -149
- package/scripts/execute-spend-only.ts +0 -81
- package/scripts/register-agent-userop.ts +0 -186
- package/src/abis.ts +0 -187
- package/src/bundler.ts +0 -235
- package/src/client.ts +0 -36
- package/src/coinbase-smart-wallet.ts +0 -51
- package/src/commands/accept.ts +0 -64
- package/src/commands/agent-handshake.ts +0 -72
- package/src/commands/agent.ts +0 -691
- package/src/commands/agreements.ts +0 -350
- package/src/commands/arbitrator.ts +0 -180
- package/src/commands/arena-handshake.ts +0 -257
- package/src/commands/arena.ts +0 -122
- package/src/commands/cancel.ts +0 -35
- package/src/commands/channel.ts +0 -218
- package/src/commands/coldstart.ts +0 -165
- package/src/commands/config.ts +0 -58
- package/src/commands/contract-interaction.ts +0 -166
- package/src/commands/daemon.ts +0 -978
- package/src/commands/deliver.ts +0 -148
- package/src/commands/discover.ts +0 -297
- package/src/commands/dispute.ts +0 -375
- package/src/commands/endpoint.ts +0 -620
- package/src/commands/feed.ts +0 -229
- package/src/commands/hire.ts +0 -245
- package/src/commands/migrate.ts +0 -177
- package/src/commands/negotiate.ts +0 -271
- package/src/commands/openshell.ts +0 -1055
- package/src/commands/owner.ts +0 -35
- package/src/commands/policy.ts +0 -263
- package/src/commands/relay.ts +0 -273
- package/src/commands/remediate.ts +0 -24
- package/src/commands/reputation.ts +0 -79
- package/src/commands/setup.ts +0 -343
- package/src/commands/trust.ts +0 -27
- package/src/commands/verify.ts +0 -91
- package/src/commands/wallet.ts +0 -3280
- package/src/commands/watch.ts +0 -23
- package/src/commands/watchtower.ts +0 -248
- package/src/commands/workroom.ts +0 -959
- package/src/config.ts +0 -174
- package/src/daemon/config.ts +0 -308
- package/src/daemon/hire-listener.ts +0 -226
- package/src/daemon/index.ts +0 -955
- package/src/daemon/job-lifecycle.ts +0 -215
- package/src/daemon/notify.ts +0 -157
- package/src/daemon/token-metering.ts +0 -183
- package/src/daemon/userops.ts +0 -119
- package/src/daemon/wallet-monitor.ts +0 -90
- package/src/drain-v4.ts +0 -159
- package/src/endpoint-config.ts +0 -83
- package/src/endpoint-notify.ts +0 -46
- package/src/index.ts +0 -26
- package/src/openshell-runtime.ts +0 -277
- package/src/program.ts +0 -83
- package/src/repl.ts +0 -680
- package/src/signing.ts +0 -28
- package/src/telegram-notify.ts +0 -88
- package/src/ui/banner.ts +0 -51
- package/src/ui/colors.ts +0 -30
- package/src/ui/format.ts +0 -77
- package/src/ui/spinner.ts +0 -56
- package/src/ui/tree.ts +0 -16
- package/src/utils/format.ts +0 -48
- package/src/utils/hash.ts +0 -5
- package/src/utils/time.ts +0 -15
- package/src/wallet-router.ts +0 -178
- package/src/walletconnect-session.ts +0 -27
- package/src/walletconnect.ts +0 -294
- package/test/time.test.js +0 -11
- package/tsconfig.json +0 -19
package/src/commands/agent.ts
DELETED
|
@@ -1,691 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { AgentRegistryClient } from "@arc402/sdk";
|
|
3
|
-
import { buildMetadata, uploadMetadata, decodeMetadata } from "@arc402/sdk";
|
|
4
|
-
import { ethers } from "ethers";
|
|
5
|
-
import { loadConfig, NETWORK_DEFAULTS } from "../config";
|
|
6
|
-
import { requireSigner } from "../client";
|
|
7
|
-
import { formatDate, getTrustTier } from "../utils/format";
|
|
8
|
-
import { AGENT_REGISTRY_ABI } from "../abis";
|
|
9
|
-
import { executeContractWriteViaWallet } from "../wallet-router";
|
|
10
|
-
import { getClient } from "../client";
|
|
11
|
-
import prompts from "prompts";
|
|
12
|
-
import chalk from "chalk";
|
|
13
|
-
import { startSpinner } from "../ui/spinner";
|
|
14
|
-
import { renderTree } from "../ui/tree";
|
|
15
|
-
import { c } from "../ui/colors";
|
|
16
|
-
|
|
17
|
-
// ─── helpers ──────────────────────────────────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
/** Resolve the real AgentRegistry address (agentRegistryV2Address > NETWORK_DEFAULTS fallback). */
|
|
20
|
-
function getAgentRegistryAddress(config: ReturnType<typeof loadConfig>): string {
|
|
21
|
-
const addr =
|
|
22
|
-
config.agentRegistryV2Address ??
|
|
23
|
-
NETWORK_DEFAULTS[config.network]?.agentRegistryV2Address;
|
|
24
|
-
if (!addr) throw new Error("agentRegistryV2Address missing in config — run `arc402 config set agentRegistryV2Address <address>`");
|
|
25
|
-
return addr;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// ─── commands ─────────────────────────────────────────────────────────────────
|
|
29
|
-
|
|
30
|
-
export function registerAgentCommands(program: Command): void {
|
|
31
|
-
const agent = program
|
|
32
|
-
.command("agent")
|
|
33
|
-
.description("Agent registry operations");
|
|
34
|
-
|
|
35
|
-
// ─── register ───────────────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
agent
|
|
38
|
-
.command("register")
|
|
39
|
-
.requiredOption("--name <name>", "Agent name (e.g. GigaBrain)")
|
|
40
|
-
.requiredOption("--service-type <type>", "Service type (e.g. ai.assistant)")
|
|
41
|
-
.option("--capability <caps>", "Comma-separated capability list")
|
|
42
|
-
.option("--endpoint <url>", "Canonical public endpoint URL for discovery/ingress. This does not grant sandbox outbound permission.", "")
|
|
43
|
-
.option("--metadata-uri <uri>", "Metadata URI (IPFS or data:)", "")
|
|
44
|
-
.option("--set-metadata", "Interactively build and upload metadata during registration")
|
|
45
|
-
.option("--claim-subdomain <subdomain>", "Claim a <subdomain>.arc402.xyz after registration (launch default: host-managed public ingress outside the sandbox)")
|
|
46
|
-
.option("--tunnel-target <url>", "Host ingress target URL for the claimed subdomain (required with --claim-subdomain)")
|
|
47
|
-
.action(async (opts) => {
|
|
48
|
-
const config = loadConfig();
|
|
49
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
50
|
-
|
|
51
|
-
let metadataUri = opts.metadataUri ?? "";
|
|
52
|
-
if (opts.setMetadata) {
|
|
53
|
-
metadataUri = await runSetMetadataWizard(
|
|
54
|
-
opts.name,
|
|
55
|
-
opts.capability ? opts.capability.split(",").map((v: string) => v.trim()) : [],
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const capabilities: string[] = opts.capability
|
|
60
|
-
? opts.capability.split(",").map((v: string) => v.trim())
|
|
61
|
-
: [];
|
|
62
|
-
|
|
63
|
-
if (opts.endpoint) {
|
|
64
|
-
console.log(chalk.dim(`ℹ Registering public endpoint: ${opts.endpoint}`));
|
|
65
|
-
console.log(chalk.dim(" This publishes discovery / ingress metadata only. Sandbox outbound access remains controlled separately by OpenShell policy."));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (config.walletContractAddress) {
|
|
69
|
-
// ── wallet contract path (machine key signs, wallet is msg.sender) ──
|
|
70
|
-
// Pre-flight: check machine key is authorized (J5-03)
|
|
71
|
-
if (config.privateKey) {
|
|
72
|
-
const machineKeyAddr = new ethers.Wallet(config.privateKey).address;
|
|
73
|
-
const { provider: agentProvider } = await getClient(config);
|
|
74
|
-
const mkCheck = new ethers.Contract(
|
|
75
|
-
config.walletContractAddress,
|
|
76
|
-
["function authorizedMachineKeys(address) external view returns (bool)"],
|
|
77
|
-
agentProvider,
|
|
78
|
-
);
|
|
79
|
-
let isAuthorized = true;
|
|
80
|
-
try {
|
|
81
|
-
isAuthorized = await mkCheck.authorizedMachineKeys(machineKeyAddr);
|
|
82
|
-
} catch { /* older wallet — assume authorized */ }
|
|
83
|
-
if (!isAuthorized) {
|
|
84
|
-
console.error(`Machine key ${machineKeyAddr} is not authorized on wallet ${config.walletContractAddress}.`);
|
|
85
|
-
console.error(`Run \`arc402 wallet authorize-machine-key ${machineKeyAddr}\` first.`);
|
|
86
|
-
process.exit(1);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
console.log(`Registering via ARC402Wallet: ${config.walletContractAddress}`);
|
|
91
|
-
const { signer, provider: regProvider } = await requireSigner(config);
|
|
92
|
-
{
|
|
93
|
-
const walletBalance = await regProvider.getBalance(config.walletContractAddress);
|
|
94
|
-
if (walletBalance < ethers.parseEther("0.0001")) {
|
|
95
|
-
console.warn(chalk.yellow(`⚠️ Low wallet balance: ${ethers.formatEther(walletBalance)} ETH. Registration may fail due to insufficient gas. Fund your wallet with at least 0.0001 ETH first.`));
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
const regSpinner = startSpinner("Registering agent...");
|
|
99
|
-
const tx = await executeContractWriteViaWallet(
|
|
100
|
-
config.walletContractAddress,
|
|
101
|
-
signer,
|
|
102
|
-
registryAddress,
|
|
103
|
-
AGENT_REGISTRY_ABI,
|
|
104
|
-
"register",
|
|
105
|
-
[opts.name, capabilities, opts.serviceType, opts.endpoint ?? "", metadataUri],
|
|
106
|
-
);
|
|
107
|
-
const receipt = await tx.wait();
|
|
108
|
-
regSpinner.succeed("Registered in AgentRegistry");
|
|
109
|
-
renderTree([
|
|
110
|
-
{ label: "Wallet", value: config.walletContractAddress },
|
|
111
|
-
{ label: "Tx", value: receipt?.hash ?? "", last: !metadataUri },
|
|
112
|
-
...(metadataUri ? [{ label: "Metadata", value: metadataUri, last: true }] : []),
|
|
113
|
-
]);
|
|
114
|
-
} else {
|
|
115
|
-
// ── EOA fallback ──
|
|
116
|
-
console.warn(chalk.yellow("⚠ No walletContractAddress in config — registering from EOA key (msg.sender = hot key)."));
|
|
117
|
-
const { signer, address: regAddress, provider: regProvider } = await requireSigner(config);
|
|
118
|
-
{
|
|
119
|
-
const walletBalance = await regProvider.getBalance(regAddress);
|
|
120
|
-
if (walletBalance < ethers.parseEther("0.0001")) {
|
|
121
|
-
console.warn(chalk.yellow(`⚠️ Low wallet balance: ${ethers.formatEther(walletBalance)} ETH. Registration may fail due to insufficient gas. Fund your wallet with at least 0.0001 ETH first.`));
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const client = new AgentRegistryClient(registryAddress, signer);
|
|
125
|
-
const eoaSpinner = startSpinner("Registering agent...");
|
|
126
|
-
await client.register({ name: opts.name, serviceType: opts.serviceType, capabilities, endpoint: opts.endpoint ?? "", metadataURI: metadataUri });
|
|
127
|
-
eoaSpinner.succeed("Registered in AgentRegistry");
|
|
128
|
-
if (metadataUri) {
|
|
129
|
-
renderTree([{ label: "Metadata", value: metadataUri, last: true }]);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// ── optional subdomain claim ──────────────────────────────────────────
|
|
134
|
-
if (opts.claimSubdomain) {
|
|
135
|
-
if (!opts.tunnelTarget) {
|
|
136
|
-
console.error(chalk.red("--tunnel-target <url> is required with --claim-subdomain"));
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
const walletAddress = config.walletContractAddress ?? new ethers.Wallet(config.privateKey!).address;
|
|
140
|
-
await claimSubdomain(opts.claimSubdomain, walletAddress, opts.tunnelTarget);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
// ─── update ─────────────────────────────────────────────────────────────────
|
|
145
|
-
|
|
146
|
-
agent
|
|
147
|
-
.command("update")
|
|
148
|
-
.requiredOption("--name <name>")
|
|
149
|
-
.requiredOption("--service-type <type>")
|
|
150
|
-
.option("--capability <caps>")
|
|
151
|
-
.option("--endpoint <url>", "Endpoint", "")
|
|
152
|
-
.option("--metadata-uri <uri>", "Metadata URI", "")
|
|
153
|
-
.action(async (opts) => {
|
|
154
|
-
const config = loadConfig();
|
|
155
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
156
|
-
const capabilities: string[] = opts.capability
|
|
157
|
-
? opts.capability.split(",").map((v: string) => v.trim())
|
|
158
|
-
: [];
|
|
159
|
-
|
|
160
|
-
if (config.walletContractAddress) {
|
|
161
|
-
const { signer } = await requireSigner(config);
|
|
162
|
-
const tx = await executeContractWriteViaWallet(
|
|
163
|
-
config.walletContractAddress,
|
|
164
|
-
signer,
|
|
165
|
-
registryAddress,
|
|
166
|
-
AGENT_REGISTRY_ABI,
|
|
167
|
-
"update",
|
|
168
|
-
[opts.name, capabilities, opts.serviceType, opts.endpoint ?? "", opts.metadataUri ?? ""],
|
|
169
|
-
);
|
|
170
|
-
const receipt = await tx.wait();
|
|
171
|
-
console.log(chalk.green(`✓ Agent updated`));
|
|
172
|
-
console.log(` Tx: ${receipt?.hash}`);
|
|
173
|
-
} else {
|
|
174
|
-
const { signer } = await requireSigner(config);
|
|
175
|
-
const client = new AgentRegistryClient(registryAddress, signer);
|
|
176
|
-
await client.update({ name: opts.name, serviceType: opts.serviceType, capabilities, endpoint: opts.endpoint, metadataURI: opts.metadataUri });
|
|
177
|
-
console.log("updated");
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// ─── claim-subdomain ────────────────────────────────────────────────────────
|
|
182
|
-
|
|
183
|
-
agent
|
|
184
|
-
.command("claim-subdomain <subdomain>")
|
|
185
|
-
.description("Claim <subdomain>.arc402.xyz for this wallet (wallet must be registered in AgentRegistry)")
|
|
186
|
-
.requiredOption("--tunnel-target <url>", "Tunnel target URL (must start with https://)")
|
|
187
|
-
.action(async (subdomain, opts) => {
|
|
188
|
-
const config = loadConfig();
|
|
189
|
-
const walletAddress = config.walletContractAddress ?? new ethers.Wallet(config.privateKey!).address;
|
|
190
|
-
await claimSubdomain(subdomain, walletAddress, opts.tunnelTarget);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// ─── transfer-subdomain ──────────────────────────────────────────────────────
|
|
194
|
-
|
|
195
|
-
agent
|
|
196
|
-
.command("transfer-subdomain <subdomain>")
|
|
197
|
-
.description("Transfer a subdomain to a new wallet. Both wallets must share the same master key (owner EOA). Used during wallet migration.")
|
|
198
|
-
.requiredOption("--new-wallet <address>", "New wallet address to transfer the subdomain to")
|
|
199
|
-
.action(async (subdomain, opts) => {
|
|
200
|
-
const normalized = subdomain.toLowerCase();
|
|
201
|
-
let newWallet: string;
|
|
202
|
-
try {
|
|
203
|
-
newWallet = ethers.getAddress(opts.newWallet);
|
|
204
|
-
} catch {
|
|
205
|
-
console.error(chalk.red(`Invalid address: ${opts.newWallet}`));
|
|
206
|
-
process.exit(1);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
console.log(`\nTransferring subdomain: ${normalized}.arc402.xyz`);
|
|
210
|
-
console.log(` New wallet: ${newWallet}`);
|
|
211
|
-
console.log(` Verifying master key ownership onchain...`);
|
|
212
|
-
|
|
213
|
-
const res = await fetch("https://api.arc402.xyz/transfer", {
|
|
214
|
-
method: "POST",
|
|
215
|
-
headers: { "Content-Type": "application/json" },
|
|
216
|
-
body: JSON.stringify({ subdomain: normalized, newWalletAddress: newWallet }),
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
const body = await res.json() as Record<string, unknown>;
|
|
220
|
-
|
|
221
|
-
if (!res.ok) {
|
|
222
|
-
console.error(chalk.red(`\n✗ Transfer failed (${res.status}): ${body["error"] ?? JSON.stringify(body)}`));
|
|
223
|
-
process.exit(1);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
console.log(chalk.green(`\n✓ Subdomain transferred: ${body["subdomain"]}`));
|
|
227
|
-
console.log(` New owner: ${body["newWalletAddress"]}`);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// ─── set-metadata ───────────────────────────────────────────────────────────
|
|
231
|
-
|
|
232
|
-
agent
|
|
233
|
-
.command("set-metadata")
|
|
234
|
-
.description("Interactively build and upload ARC-402 agent metadata, then update the registry")
|
|
235
|
-
.action(async () => {
|
|
236
|
-
const config = loadConfig();
|
|
237
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
238
|
-
const { signer, address } = await requireSigner(config);
|
|
239
|
-
const client = new AgentRegistryClient(registryAddress, signer);
|
|
240
|
-
|
|
241
|
-
// Resolve the on-chain identity (wallet contract or EOA)
|
|
242
|
-
const agentAddress = config.walletContractAddress ?? address;
|
|
243
|
-
|
|
244
|
-
let existingName = "";
|
|
245
|
-
let existingCaps: string[] = [];
|
|
246
|
-
try {
|
|
247
|
-
const existing = await client.getAgent(agentAddress);
|
|
248
|
-
existingName = existing.name;
|
|
249
|
-
existingCaps = existing.capabilities;
|
|
250
|
-
} catch { /* not yet registered — fine */ }
|
|
251
|
-
|
|
252
|
-
const uri = await runSetMetadataWizard(existingName, existingCaps);
|
|
253
|
-
if (!uri) return;
|
|
254
|
-
|
|
255
|
-
let name = existingName; let serviceType = "general"; let endpoint = "";
|
|
256
|
-
try {
|
|
257
|
-
const a = await client.getAgent(agentAddress);
|
|
258
|
-
name = a.name; serviceType = a.serviceType; endpoint = a.endpoint;
|
|
259
|
-
} catch { /* not yet registered */ }
|
|
260
|
-
|
|
261
|
-
if (config.walletContractAddress) {
|
|
262
|
-
const tx = await executeContractWriteViaWallet(
|
|
263
|
-
config.walletContractAddress,
|
|
264
|
-
signer,
|
|
265
|
-
registryAddress,
|
|
266
|
-
AGENT_REGISTRY_ABI,
|
|
267
|
-
"update",
|
|
268
|
-
[name, existingCaps, serviceType, endpoint, uri],
|
|
269
|
-
);
|
|
270
|
-
const receipt = await tx.wait();
|
|
271
|
-
console.log(chalk.green("✓ Metadata URI saved to registry"));
|
|
272
|
-
console.log(` ${uri}`);
|
|
273
|
-
console.log(` Tx: ${receipt?.hash}`);
|
|
274
|
-
} else {
|
|
275
|
-
await client.update({ name, serviceType, capabilities: existingCaps, endpoint, metadataURI: uri });
|
|
276
|
-
console.log(chalk.green("✓ Metadata URI saved to registry"));
|
|
277
|
-
console.log(` ${uri}`);
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
// ─── show-metadata ──────────────────────────────────────────────────────────
|
|
282
|
-
|
|
283
|
-
agent
|
|
284
|
-
.command("show-metadata <address>")
|
|
285
|
-
.description("Fetch and display metadata for any registered agent")
|
|
286
|
-
.action(async (address) => {
|
|
287
|
-
const config = loadConfig();
|
|
288
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
289
|
-
const { provider } = await getClient(config);
|
|
290
|
-
const client = new AgentRegistryClient(registryAddress, provider);
|
|
291
|
-
const info = await client.getAgent(address);
|
|
292
|
-
if (!info.metadataURI) {
|
|
293
|
-
console.log(chalk.yellow("No metadata URI set for this agent."));
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
console.log(chalk.dim(`Fetching metadata from: ${info.metadataURI}\n`));
|
|
297
|
-
let meta;
|
|
298
|
-
try {
|
|
299
|
-
meta = await decodeMetadata(info.metadataURI);
|
|
300
|
-
} catch (err) {
|
|
301
|
-
console.error(chalk.red(`Failed to fetch or parse metadata: ${err instanceof Error ? err.message : String(err)}`));
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
console.log(chalk.bold("Agent Metadata") + chalk.dim(` (${meta.schema})`));
|
|
305
|
-
if (meta.name) console.log(` name: ${meta.name}`);
|
|
306
|
-
if (meta.description) console.log(` description: ${meta.description}`);
|
|
307
|
-
if (meta.capabilities?.length) console.log(` capabilities: ${meta.capabilities.join(", ")}`);
|
|
308
|
-
if (meta.model) {
|
|
309
|
-
console.log(` model:`);
|
|
310
|
-
if (meta.model.family) console.log(` family: ${meta.model.family}`);
|
|
311
|
-
if (meta.model.version) console.log(` version: ${meta.model.version}`);
|
|
312
|
-
if (meta.model.provider) console.log(` provider: ${meta.model.provider}`);
|
|
313
|
-
if (meta.model.contextWindow) console.log(` contextWindow: ${meta.model.contextWindow}`);
|
|
314
|
-
if (meta.model.multimodal !== undefined) console.log(` multimodal: ${meta.model.multimodal}`);
|
|
315
|
-
}
|
|
316
|
-
if (meta.pricing) {
|
|
317
|
-
console.log(` pricing: ${meta.pricing.base ?? "?"} ${meta.pricing.currency ?? ""} per ${meta.pricing.per ?? "job"}`);
|
|
318
|
-
}
|
|
319
|
-
if (meta.sla) {
|
|
320
|
-
const parts: string[] = [];
|
|
321
|
-
if (meta.sla.turnaroundHours) parts.push(`${meta.sla.turnaroundHours}h turnaround`);
|
|
322
|
-
if (meta.sla.availability) parts.push(meta.sla.availability);
|
|
323
|
-
if (meta.sla.maxConcurrentJobs) parts.push(`max ${meta.sla.maxConcurrentJobs} concurrent jobs`);
|
|
324
|
-
if (parts.length) console.log(` sla: ${parts.join(", ")}`);
|
|
325
|
-
}
|
|
326
|
-
if (meta.contact) {
|
|
327
|
-
if (meta.contact.endpoint) console.log(` contact.endpoint: ${meta.contact.endpoint}`);
|
|
328
|
-
if (meta.contact.relay) console.log(` contact.relay: ${meta.contact.relay}`);
|
|
329
|
-
}
|
|
330
|
-
if (meta.security) {
|
|
331
|
-
console.log(` security: injection=${meta.security.injectionProtection ?? false} envLeak=${meta.security.envLeakProtection ?? false} attested=${meta.security.attestedSecurityPolicy ?? false}`);
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
// ─── deactivate / reactivate ───────────────────────────────────────────────
|
|
336
|
-
|
|
337
|
-
agent
|
|
338
|
-
.command("deactivate")
|
|
339
|
-
.description("Deactivate your agent registration (preserves history/trust)")
|
|
340
|
-
.action(async () => {
|
|
341
|
-
const config = loadConfig();
|
|
342
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
343
|
-
const { signer } = await requireSigner(config);
|
|
344
|
-
const client = new AgentRegistryClient(registryAddress, signer);
|
|
345
|
-
await client.deactivate();
|
|
346
|
-
console.log("agent deactivated");
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
agent
|
|
350
|
-
.command("reactivate")
|
|
351
|
-
.description("Reactivate your agent registration")
|
|
352
|
-
.action(async () => {
|
|
353
|
-
const config = loadConfig();
|
|
354
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
355
|
-
const { signer } = await requireSigner(config);
|
|
356
|
-
const client = new AgentRegistryClient(registryAddress, signer);
|
|
357
|
-
await client.reactivate();
|
|
358
|
-
console.log("agent reactivated");
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
// ─── heartbeat ──────────────────────────────────────────────────────────────
|
|
362
|
-
|
|
363
|
-
agent
|
|
364
|
-
.command("heartbeat")
|
|
365
|
-
.description("Submit self-reported heartbeat data")
|
|
366
|
-
.option("--latency-ms <n>", "Observed latency", "0")
|
|
367
|
-
.action(async (opts) => {
|
|
368
|
-
const config = loadConfig();
|
|
369
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
370
|
-
const { signer } = await requireSigner(config);
|
|
371
|
-
const client = new AgentRegistryClient(registryAddress, signer);
|
|
372
|
-
await client.submitHeartbeat(Number(opts.latencyMs));
|
|
373
|
-
console.log("heartbeat submitted");
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
agent
|
|
377
|
-
.command("heartbeat-policy")
|
|
378
|
-
.description("Configure self-reported heartbeat timing metadata")
|
|
379
|
-
.requiredOption("--interval <seconds>")
|
|
380
|
-
.requiredOption("--grace <seconds>")
|
|
381
|
-
.action(async (opts) => {
|
|
382
|
-
const config = loadConfig();
|
|
383
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
384
|
-
const { signer } = await requireSigner(config);
|
|
385
|
-
const client = new AgentRegistryClient(registryAddress, signer);
|
|
386
|
-
await client.setHeartbeatPolicy(Number(opts.interval), Number(opts.grace));
|
|
387
|
-
console.log("heartbeat policy updated");
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
// ─── info ───────────────────────────────────────────────────────────────────
|
|
391
|
-
|
|
392
|
-
agent
|
|
393
|
-
.command("info <address>")
|
|
394
|
-
.option("--json")
|
|
395
|
-
.action(async (address, opts) => {
|
|
396
|
-
const config = loadConfig();
|
|
397
|
-
const registryAddress = getAgentRegistryAddress(config);
|
|
398
|
-
const { provider } = await getClient(config);
|
|
399
|
-
const client = new AgentRegistryClient(registryAddress, provider);
|
|
400
|
-
const [info, ops] = await Promise.all([
|
|
401
|
-
client.getAgent(address),
|
|
402
|
-
client.getOperationalMetrics(address),
|
|
403
|
-
]);
|
|
404
|
-
if (opts.json) {
|
|
405
|
-
return console.log(JSON.stringify({
|
|
406
|
-
...info,
|
|
407
|
-
registeredAt: Number(info.registeredAt),
|
|
408
|
-
endpointChangedAt: Number(info.endpointChangedAt),
|
|
409
|
-
endpointChangeCount: Number(info.endpointChangeCount),
|
|
410
|
-
trustScore: Number(info.trustScore ?? 0n),
|
|
411
|
-
operational: Object.fromEntries(Object.entries(ops).map(([k, v]) => [k, Number(v)])),
|
|
412
|
-
}, null, 2));
|
|
413
|
-
}
|
|
414
|
-
console.log(`${info.name} ${info.wallet}\nservice=${info.serviceType}\ntrust=${Number(info.trustScore ?? 0n)} (${getTrustTier(Number(info.trustScore ?? 0n))})\nregistered=${formatDate(Number(info.registeredAt))}\nheartbeatCount=${Number(ops.heartbeatCount)} uptimeScore=${Number(ops.uptimeScore)} responseScore=${Number(ops.responseScore)}`);
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
agent
|
|
418
|
-
.command("me")
|
|
419
|
-
.action(async () => {
|
|
420
|
-
const config = loadConfig();
|
|
421
|
-
const address = config.walletContractAddress ?? (await getClient(config)).address;
|
|
422
|
-
if (!address) throw new Error("No wallet configured");
|
|
423
|
-
await program.parseAsync([process.argv[0], process.argv[1], "agent", "info", address], { from: "user" });
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
// ─── profile (subgraph view) ─────────────────────────────────────────────
|
|
427
|
-
|
|
428
|
-
agent
|
|
429
|
-
.command("profile <address>")
|
|
430
|
-
.description("Show detailed agent profile from the Arena subgraph")
|
|
431
|
-
.option("--json", "Output as JSON")
|
|
432
|
-
.action(async (address: string, opts: { json?: boolean }) => {
|
|
433
|
-
const normalizedAddr = address.toLowerCase();
|
|
434
|
-
try {
|
|
435
|
-
const data = await agentSubgraphQuery(`{
|
|
436
|
-
agent(id: "${normalizedAddr}") {
|
|
437
|
-
id name serviceType endpoint active
|
|
438
|
-
trustScore { globalScore }
|
|
439
|
-
capabilities(where: { active: true }) { capability active }
|
|
440
|
-
handshakesSent(first: 100, orderBy: timestamp, orderDirection: desc) {
|
|
441
|
-
id to { id name } hsType note timestamp
|
|
442
|
-
}
|
|
443
|
-
handshakesReceived(first: 100, orderBy: timestamp, orderDirection: desc) {
|
|
444
|
-
id from { id name } hsType note timestamp
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
clientAgreements: agreements(where: { client: "${normalizedAddr}", state: 1 }, first: 10) {
|
|
448
|
-
id serviceType price state
|
|
449
|
-
}
|
|
450
|
-
providerAgreements: agreements(where: { provider: "${normalizedAddr}", state: 1 }, first: 10) {
|
|
451
|
-
id serviceType price state
|
|
452
|
-
}
|
|
453
|
-
vouchedFor: vouches(where: { voucher: "${normalizedAddr}", active: true }, first: 100) {
|
|
454
|
-
id newAgent { id name } stakeAmount
|
|
455
|
-
}
|
|
456
|
-
vouchedBy: vouches(where: { newAgent: "${normalizedAddr}", active: true }, first: 100) {
|
|
457
|
-
id voucher { id name } stakeAmount
|
|
458
|
-
}
|
|
459
|
-
}`);
|
|
460
|
-
|
|
461
|
-
const agentData = data["agent"] as Record<string, unknown> | null;
|
|
462
|
-
|
|
463
|
-
if (!agentData) {
|
|
464
|
-
if (opts.json) {
|
|
465
|
-
console.log(JSON.stringify({ error: "Agent not registered", address }));
|
|
466
|
-
} else {
|
|
467
|
-
console.log(chalk.red(`Agent not registered: ${address}`));
|
|
468
|
-
}
|
|
469
|
-
process.exit(1);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (opts.json) {
|
|
473
|
-
console.log(JSON.stringify(data, null, 2));
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const sent = (agentData["handshakesSent"] as Record<string, unknown>[]) ?? [];
|
|
478
|
-
const received = (agentData["handshakesReceived"] as Record<string, unknown>[]) ?? [];
|
|
479
|
-
const sentToIds = new Set(sent.map((h) => (h["to"] as Record<string, string>)["id"]));
|
|
480
|
-
const receivedFromIds = new Set(received.map((h) => (h["from"] as Record<string, string>)["id"]));
|
|
481
|
-
const mutual = [...sentToIds].filter((id) => receivedFromIds.has(id)).length;
|
|
482
|
-
|
|
483
|
-
const trustScore =
|
|
484
|
-
((agentData["trustScore"] as Record<string, unknown> | null)?.["globalScore"] as number | undefined) ?? 0;
|
|
485
|
-
const caps = (agentData["capabilities"] as Record<string, unknown>[]) ?? [];
|
|
486
|
-
|
|
487
|
-
const allAgreements = [
|
|
488
|
-
...((data["clientAgreements"] as unknown[]) ?? []),
|
|
489
|
-
...((data["providerAgreements"] as unknown[]) ?? []),
|
|
490
|
-
] as Record<string, unknown>[];
|
|
491
|
-
|
|
492
|
-
const hsTypeLabels: Record<number, string> = {
|
|
493
|
-
0: "Respected",
|
|
494
|
-
1: "Curious",
|
|
495
|
-
2: "Endorsed",
|
|
496
|
-
3: "Thanked",
|
|
497
|
-
4: "Collaborated",
|
|
498
|
-
5: "Challenged",
|
|
499
|
-
6: "Referred",
|
|
500
|
-
7: "Hello",
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
const recentActivity = [
|
|
504
|
-
...sent.slice(0, 3).map((h) => {
|
|
505
|
-
const to = h["to"] as Record<string, string>;
|
|
506
|
-
const label = hsTypeLabels[Number(h["hsType"])] ?? `Type${h["hsType"]}`;
|
|
507
|
-
const note = h["note"] ? ` — "${h["note"]}"` : "";
|
|
508
|
-
return {
|
|
509
|
-
ts: Number(h["timestamp"]),
|
|
510
|
-
line: ` [${profileDate(Number(h["timestamp"]))}] ${label} ${to["name"] || shortAddress(to["id"])}${note}`,
|
|
511
|
-
};
|
|
512
|
-
}),
|
|
513
|
-
...received.slice(0, 3).map((h) => {
|
|
514
|
-
const from = h["from"] as Record<string, string>;
|
|
515
|
-
const label = hsTypeLabels[Number(h["hsType"])] ?? `Type${h["hsType"]}`;
|
|
516
|
-
const note = h["note"] ? ` — "${h["note"]}"` : "";
|
|
517
|
-
return {
|
|
518
|
-
ts: Number(h["timestamp"]),
|
|
519
|
-
line: ` [${profileDate(Number(h["timestamp"]))}] Received ${label} from ${from["name"] || shortAddress(from["id"])}${note}`,
|
|
520
|
-
};
|
|
521
|
-
}),
|
|
522
|
-
]
|
|
523
|
-
.sort((a, b) => b.ts - a.ts)
|
|
524
|
-
.slice(0, 5);
|
|
525
|
-
|
|
526
|
-
const vouchedFor = (data["vouchedFor"] as unknown[]) ?? [];
|
|
527
|
-
const vouchedBy = (data["vouchedBy"] as unknown[]) ?? [];
|
|
528
|
-
|
|
529
|
-
const line = "═".repeat(43);
|
|
530
|
-
console.log(chalk.bold(line));
|
|
531
|
-
console.log(` ${chalk.bold((agentData["name"] as string) || "(unnamed)")}`);
|
|
532
|
-
console.log(` ${agentData["id"]}`);
|
|
533
|
-
console.log(chalk.bold(line));
|
|
534
|
-
console.log();
|
|
535
|
-
console.log(` Service Type: ${agentData["serviceType"]}`);
|
|
536
|
-
console.log(` Endpoint: ${agentData["endpoint"] || chalk.dim("(none)")}`);
|
|
537
|
-
console.log(
|
|
538
|
-
` Status: ${agentData["active"] ? chalk.green("✅ Active") : chalk.red("❌ Inactive")}`,
|
|
539
|
-
);
|
|
540
|
-
console.log(` Trust Score: ${trustScore}`);
|
|
541
|
-
console.log();
|
|
542
|
-
|
|
543
|
-
if (caps.length > 0) {
|
|
544
|
-
console.log(" Capabilities:");
|
|
545
|
-
for (const cap of caps) {
|
|
546
|
-
console.log(` ✓ ${(cap as Record<string, unknown>)["capability"]}`);
|
|
547
|
-
}
|
|
548
|
-
console.log();
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
console.log(
|
|
552
|
-
` Handshakes: ${sent.length} sent • ${received.length} received • ${mutual} mutual connections`,
|
|
553
|
-
);
|
|
554
|
-
console.log();
|
|
555
|
-
|
|
556
|
-
if (recentActivity.length > 0) {
|
|
557
|
-
console.log(" Recent Activity:");
|
|
558
|
-
for (const a of recentActivity) {
|
|
559
|
-
console.log(a.line);
|
|
560
|
-
}
|
|
561
|
-
console.log();
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
console.log(" Active Agreements:");
|
|
565
|
-
if (allAgreements.length === 0) {
|
|
566
|
-
console.log(" None");
|
|
567
|
-
} else {
|
|
568
|
-
for (const a of allAgreements.slice(0, 5)) {
|
|
569
|
-
console.log(` #${(a["id"] as string).slice(0, 8)} ${a["serviceType"]}`);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
console.log();
|
|
573
|
-
|
|
574
|
-
console.log(" Vouches:");
|
|
575
|
-
console.log(` Vouched for: ${vouchedFor.length} agents`);
|
|
576
|
-
console.log(` Vouched by: ${vouchedBy.length} agents`);
|
|
577
|
-
} catch (err) {
|
|
578
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
579
|
-
if (opts.json) {
|
|
580
|
-
console.log(JSON.stringify({ error: "Subgraph unavailable", details: msg }));
|
|
581
|
-
} else {
|
|
582
|
-
console.error(chalk.red(`Subgraph unavailable: ${msg}`));
|
|
583
|
-
}
|
|
584
|
-
process.exit(1);
|
|
585
|
-
}
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// ─── subgraph helpers (used by agent profile) ────────────────────────────────
|
|
590
|
-
|
|
591
|
-
const AGENT_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/1744310/arc-402/v0.2.0";
|
|
592
|
-
|
|
593
|
-
async function agentSubgraphQuery(query: string): Promise<Record<string, unknown>> {
|
|
594
|
-
const res = await fetch(AGENT_SUBGRAPH_URL, {
|
|
595
|
-
method: "POST",
|
|
596
|
-
headers: { "Content-Type": "application/json" },
|
|
597
|
-
body: JSON.stringify({ query }),
|
|
598
|
-
});
|
|
599
|
-
if (!res.ok) throw new Error(`Subgraph HTTP ${res.status}`);
|
|
600
|
-
const json = (await res.json()) as { data?: Record<string, unknown>; errors?: unknown[] };
|
|
601
|
-
if (json.errors?.length) throw new Error(`Subgraph error: ${JSON.stringify(json.errors[0])}`);
|
|
602
|
-
return json.data ?? {};
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
function shortAddress(addr: string): string {
|
|
606
|
-
return addr.length > 12 ? `${addr.slice(0, 6)}...${addr.slice(-4)}` : addr;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
function profileDate(ts: number): string {
|
|
610
|
-
const d = new Date(ts * 1000);
|
|
611
|
-
return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// ─── subdomain claim ──────────────────────────────────────────────────────────
|
|
615
|
-
|
|
616
|
-
async function claimSubdomain(subdomain: string, walletAddress: string, tunnelTarget: string): Promise<void> {
|
|
617
|
-
const normalized = subdomain.toLowerCase();
|
|
618
|
-
console.log(`\nClaiming subdomain: ${normalized}.arc402.xyz`);
|
|
619
|
-
console.log(` Wallet: ${walletAddress}`);
|
|
620
|
-
console.log(` Target: ${tunnelTarget}`);
|
|
621
|
-
|
|
622
|
-
const res = await fetch("https://api.arc402.xyz/register-subdomain", {
|
|
623
|
-
method: "POST",
|
|
624
|
-
headers: { "Content-Type": "application/json" },
|
|
625
|
-
body: JSON.stringify({ subdomain: normalized, walletAddress, tunnelTarget }),
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
const body = await res.json() as Record<string, unknown>;
|
|
629
|
-
|
|
630
|
-
if (!res.ok) {
|
|
631
|
-
console.error(chalk.red(`✗ Subdomain claim failed (${res.status}): ${body["error"] ?? JSON.stringify(body)}`));
|
|
632
|
-
process.exit(1);
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
console.log(chalk.green(`✓ Subdomain claimed: ${body["subdomain"]}`));
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
// ─── metadata wizard ──────────────────────────────────────────────────────────
|
|
639
|
-
|
|
640
|
-
async function runSetMetadataWizard(defaultName: string, defaultCapabilities: string[]): Promise<string> {
|
|
641
|
-
console.log(chalk.bold("\nARC-402 Agent Metadata Wizard\n"));
|
|
642
|
-
|
|
643
|
-
const answers = await prompts([
|
|
644
|
-
{ type: "text", name: "name", message: "Agent name:", initial: defaultName },
|
|
645
|
-
{ type: "text", name: "description", message: "Short description (what does this agent do?):" },
|
|
646
|
-
{ type: "text", name: "capabilities", message: "Capabilities (comma-separated, e.g. legal.patent-analysis.us.v1):", initial: defaultCapabilities.join(", ") },
|
|
647
|
-
{ type: "text", name: "modelFamily", message: "Model family (e.g. claude, gpt, gemini, llama — leave blank to omit):" },
|
|
648
|
-
{ type: "text", name: "modelVersion", message: "Model version (e.g. claude-sonnet-4-6 — leave blank to omit):" },
|
|
649
|
-
{ type: "text", name: "modelProvider", message: "Model provider (e.g. anthropic — leave blank to omit):" },
|
|
650
|
-
{ type: "text", name: "contactEndpoint", message: "Contact endpoint URL (leave blank to omit):" },
|
|
651
|
-
{ type: "confirm", name: "injectionProtection", message: "Does this agent have prompt injection protection?", initial: false },
|
|
652
|
-
{ type: "confirm", name: "envLeakProtection", message: "Does this agent have env/key leak protection in its instructions?", initial: false },
|
|
653
|
-
]);
|
|
654
|
-
|
|
655
|
-
if (!answers.name) {
|
|
656
|
-
console.log(chalk.dim("Cancelled."));
|
|
657
|
-
return "";
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
const capabilities = answers.capabilities
|
|
661
|
-
? answers.capabilities.split(",").map((v: string) => v.trim()).filter(Boolean)
|
|
662
|
-
: [];
|
|
663
|
-
|
|
664
|
-
const meta = buildMetadata({
|
|
665
|
-
name: answers.name || undefined,
|
|
666
|
-
description: answers.description || undefined,
|
|
667
|
-
capabilities: capabilities.length ? capabilities : undefined,
|
|
668
|
-
model: (answers.modelFamily || answers.modelVersion || answers.modelProvider) ? {
|
|
669
|
-
family: answers.modelFamily || undefined,
|
|
670
|
-
version: answers.modelVersion || undefined,
|
|
671
|
-
provider: answers.modelProvider || undefined,
|
|
672
|
-
} : undefined,
|
|
673
|
-
contact: answers.contactEndpoint ? { endpoint: answers.contactEndpoint } : undefined,
|
|
674
|
-
security: {
|
|
675
|
-
injectionProtection: answers.injectionProtection,
|
|
676
|
-
envLeakProtection: answers.envLeakProtection,
|
|
677
|
-
},
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
const pinataJwt = process.env["PINATA_JWT"];
|
|
681
|
-
if (!pinataJwt) {
|
|
682
|
-
console.log(chalk.dim("\nNo PINATA_JWT env var found — metadata will be stored as a data URI."));
|
|
683
|
-
console.log(chalk.dim("To pin to IPFS: export PINATA_JWT=<your-jwt> and re-run.\n"));
|
|
684
|
-
} else {
|
|
685
|
-
console.log(chalk.dim("\nUploading to IPFS via Pinata…"));
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
const uri = await uploadMetadata(meta, pinataJwt);
|
|
689
|
-
console.log(chalk.green(`✓ Metadata URI: ${uri}`));
|
|
690
|
-
return uri;
|
|
691
|
-
}
|