arc402-cli 1.0.0-rc.1 → 1.1.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.
Files changed (257) hide show
  1. package/README.md +43 -2
  2. package/dist/abis.d.ts +1 -0
  3. package/dist/abis.d.ts.map +1 -1
  4. package/dist/abis.js +29 -1
  5. package/dist/abis.js.map +1 -1
  6. package/dist/commands/backup.d.ts +3 -0
  7. package/dist/commands/backup.d.ts.map +1 -0
  8. package/dist/commands/backup.js +106 -0
  9. package/dist/commands/backup.js.map +1 -0
  10. package/dist/commands/compute.d.ts +14 -0
  11. package/dist/commands/compute.d.ts.map +1 -0
  12. package/dist/commands/compute.js +466 -0
  13. package/dist/commands/compute.js.map +1 -0
  14. package/dist/commands/config.d.ts.map +1 -1
  15. package/dist/commands/config.js +11 -1
  16. package/dist/commands/config.js.map +1 -1
  17. package/dist/commands/daemon.d.ts.map +1 -1
  18. package/dist/commands/daemon.js +67 -0
  19. package/dist/commands/daemon.js.map +1 -1
  20. package/dist/commands/discover.d.ts.map +1 -1
  21. package/dist/commands/discover.js +60 -15
  22. package/dist/commands/discover.js.map +1 -1
  23. package/dist/commands/doctor.d.ts +3 -0
  24. package/dist/commands/doctor.d.ts.map +1 -0
  25. package/dist/commands/doctor.js +205 -0
  26. package/dist/commands/doctor.js.map +1 -0
  27. package/dist/commands/tunnel.d.ts +3 -0
  28. package/dist/commands/tunnel.d.ts.map +1 -0
  29. package/dist/commands/tunnel.js +281 -0
  30. package/dist/commands/tunnel.js.map +1 -0
  31. package/dist/commands/wallet.d.ts.map +1 -1
  32. package/dist/commands/wallet.js +299 -65
  33. package/dist/commands/wallet.js.map +1 -1
  34. package/dist/commands/watch.d.ts.map +1 -1
  35. package/dist/commands/watch.js +146 -9
  36. package/dist/commands/watch.js.map +1 -1
  37. package/dist/commands/workroom.d.ts.map +1 -1
  38. package/dist/commands/workroom.js +112 -6
  39. package/dist/commands/workroom.js.map +1 -1
  40. package/dist/config.d.ts +13 -0
  41. package/dist/config.d.ts.map +1 -1
  42. package/dist/config.js +41 -4
  43. package/dist/config.js.map +1 -1
  44. package/dist/daemon/compute-metering.d.ts +61 -0
  45. package/dist/daemon/compute-metering.d.ts.map +1 -0
  46. package/dist/daemon/compute-metering.js +299 -0
  47. package/dist/daemon/compute-metering.js.map +1 -0
  48. package/dist/daemon/compute-session.d.ts +100 -0
  49. package/dist/daemon/compute-session.d.ts.map +1 -0
  50. package/dist/daemon/compute-session.js +231 -0
  51. package/dist/daemon/compute-session.js.map +1 -0
  52. package/dist/daemon/config.d.ts +33 -1
  53. package/dist/daemon/config.d.ts.map +1 -1
  54. package/dist/daemon/config.js +69 -0
  55. package/dist/daemon/config.js.map +1 -1
  56. package/dist/daemon/credentials.d.ts +24 -0
  57. package/dist/daemon/credentials.d.ts.map +1 -0
  58. package/dist/daemon/credentials.js +80 -0
  59. package/dist/daemon/credentials.js.map +1 -0
  60. package/dist/daemon/delivery-client.d.ts +35 -0
  61. package/dist/daemon/delivery-client.d.ts.map +1 -0
  62. package/dist/daemon/delivery-client.js +231 -0
  63. package/dist/daemon/delivery-client.js.map +1 -0
  64. package/dist/daemon/file-delivery.d.ts +98 -0
  65. package/dist/daemon/file-delivery.d.ts.map +1 -0
  66. package/dist/daemon/file-delivery.js +461 -0
  67. package/dist/daemon/file-delivery.js.map +1 -0
  68. package/dist/daemon/index.d.ts +1 -0
  69. package/dist/daemon/index.d.ts.map +1 -1
  70. package/dist/daemon/index.js +793 -227
  71. package/dist/daemon/index.js.map +1 -1
  72. package/dist/daemon/notify.d.ts +35 -6
  73. package/dist/daemon/notify.d.ts.map +1 -1
  74. package/dist/daemon/notify.js +176 -48
  75. package/dist/daemon/notify.js.map +1 -1
  76. package/dist/daemon/worker-executor.d.ts +71 -0
  77. package/dist/daemon/worker-executor.d.ts.map +1 -0
  78. package/dist/daemon/worker-executor.js +382 -0
  79. package/dist/daemon/worker-executor.js.map +1 -0
  80. package/dist/drain-v4.js +2 -2
  81. package/dist/drain-v4.js.map +1 -1
  82. package/dist/endpoint-notify.d.ts +9 -1
  83. package/dist/endpoint-notify.d.ts.map +1 -1
  84. package/dist/endpoint-notify.js +116 -3
  85. package/dist/endpoint-notify.js.map +1 -1
  86. package/dist/index.js +81 -1
  87. package/dist/index.js.map +1 -1
  88. package/dist/program.d.ts.map +1 -1
  89. package/dist/program.js +8 -0
  90. package/dist/program.js.map +1 -1
  91. package/dist/repl.d.ts.map +1 -1
  92. package/dist/repl.js +69 -486
  93. package/dist/repl.js.map +1 -1
  94. package/dist/tui/App.d.ts +12 -0
  95. package/dist/tui/App.d.ts.map +1 -0
  96. package/dist/tui/App.js +154 -0
  97. package/dist/tui/App.js.map +1 -0
  98. package/dist/tui/Footer.d.ts +11 -0
  99. package/dist/tui/Footer.d.ts.map +1 -0
  100. package/dist/tui/Footer.js +13 -0
  101. package/dist/tui/Footer.js.map +1 -0
  102. package/dist/tui/Header.d.ts +14 -0
  103. package/dist/tui/Header.d.ts.map +1 -0
  104. package/dist/tui/Header.js +19 -0
  105. package/dist/tui/Header.js.map +1 -0
  106. package/dist/tui/InputLine.d.ts +11 -0
  107. package/dist/tui/InputLine.d.ts.map +1 -0
  108. package/dist/tui/InputLine.js +145 -0
  109. package/dist/tui/InputLine.js.map +1 -0
  110. package/dist/tui/Viewport.d.ts +14 -0
  111. package/dist/tui/Viewport.d.ts.map +1 -0
  112. package/dist/tui/Viewport.js +48 -0
  113. package/dist/tui/Viewport.js.map +1 -0
  114. package/dist/tui/WalletConnectPairing.d.ts +23 -0
  115. package/dist/tui/WalletConnectPairing.d.ts.map +1 -0
  116. package/dist/tui/WalletConnectPairing.js +61 -0
  117. package/dist/tui/WalletConnectPairing.js.map +1 -0
  118. package/dist/tui/components/Button.d.ts +7 -0
  119. package/dist/tui/components/Button.d.ts.map +1 -0
  120. package/dist/tui/components/Button.js +21 -0
  121. package/dist/tui/components/Button.js.map +1 -0
  122. package/dist/tui/components/CeremonyView.d.ts +13 -0
  123. package/dist/tui/components/CeremonyView.d.ts.map +1 -0
  124. package/dist/tui/components/CeremonyView.js +10 -0
  125. package/dist/tui/components/CeremonyView.js.map +1 -0
  126. package/dist/tui/components/CompletionDropdown.d.ts +7 -0
  127. package/dist/tui/components/CompletionDropdown.d.ts.map +1 -0
  128. package/dist/tui/components/CompletionDropdown.js +23 -0
  129. package/dist/tui/components/CompletionDropdown.js.map +1 -0
  130. package/dist/tui/components/ConfirmPrompt.d.ts +9 -0
  131. package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
  132. package/dist/tui/components/ConfirmPrompt.js +10 -0
  133. package/dist/tui/components/ConfirmPrompt.js.map +1 -0
  134. package/dist/tui/components/CustomTextInput.d.ts +15 -0
  135. package/dist/tui/components/CustomTextInput.d.ts.map +1 -0
  136. package/dist/tui/components/CustomTextInput.js +99 -0
  137. package/dist/tui/components/CustomTextInput.js.map +1 -0
  138. package/dist/tui/components/InteractiveTable.d.ts +14 -0
  139. package/dist/tui/components/InteractiveTable.d.ts.map +1 -0
  140. package/dist/tui/components/InteractiveTable.js +61 -0
  141. package/dist/tui/components/InteractiveTable.js.map +1 -0
  142. package/dist/tui/components/StepSpinner.d.ts +11 -0
  143. package/dist/tui/components/StepSpinner.d.ts.map +1 -0
  144. package/dist/tui/components/StepSpinner.js +32 -0
  145. package/dist/tui/components/StepSpinner.js.map +1 -0
  146. package/dist/tui/components/Toast.d.ts +18 -0
  147. package/dist/tui/components/Toast.d.ts.map +1 -0
  148. package/dist/tui/components/Toast.js +29 -0
  149. package/dist/tui/components/Toast.js.map +1 -0
  150. package/dist/tui/index.d.ts +2 -0
  151. package/dist/tui/index.d.ts.map +1 -0
  152. package/dist/tui/index.js +55 -0
  153. package/dist/tui/index.js.map +1 -0
  154. package/dist/tui/useChat.d.ts +11 -0
  155. package/dist/tui/useChat.d.ts.map +1 -0
  156. package/dist/tui/useChat.js +91 -0
  157. package/dist/tui/useChat.js.map +1 -0
  158. package/dist/tui/useCommand.d.ts +12 -0
  159. package/dist/tui/useCommand.d.ts.map +1 -0
  160. package/dist/tui/useCommand.js +137 -0
  161. package/dist/tui/useCommand.js.map +1 -0
  162. package/dist/tui/useNotifications.d.ts +9 -0
  163. package/dist/tui/useNotifications.d.ts.map +1 -0
  164. package/dist/tui/useNotifications.js +17 -0
  165. package/dist/tui/useNotifications.js.map +1 -0
  166. package/dist/tui/useScroll.d.ts +17 -0
  167. package/dist/tui/useScroll.d.ts.map +1 -0
  168. package/dist/tui/useScroll.js +46 -0
  169. package/dist/tui/useScroll.js.map +1 -0
  170. package/dist/ui/format.d.ts.map +1 -1
  171. package/dist/ui/format.js +2 -0
  172. package/dist/ui/format.js.map +1 -1
  173. package/dist/ui/qr-render.d.ts +25 -0
  174. package/dist/ui/qr-render.d.ts.map +1 -0
  175. package/dist/ui/qr-render.js +90 -0
  176. package/dist/ui/qr-render.js.map +1 -0
  177. package/dist/ui/rpc-fallback.d.ts +11 -0
  178. package/dist/ui/rpc-fallback.d.ts.map +1 -0
  179. package/dist/ui/rpc-fallback.js +58 -0
  180. package/dist/ui/rpc-fallback.js.map +1 -0
  181. package/dist/walletconnect.d.ts +4 -0
  182. package/dist/walletconnect.d.ts.map +1 -1
  183. package/dist/walletconnect.js.map +1 -1
  184. package/package.json +11 -3
  185. package/scripts/authorize-machine-key.ts +0 -43
  186. package/scripts/drain-wallet.ts +0 -149
  187. package/scripts/execute-spend-only.ts +0 -81
  188. package/scripts/register-agent-userop.ts +0 -186
  189. package/src/abis.ts +0 -187
  190. package/src/bundler.ts +0 -235
  191. package/src/client.ts +0 -36
  192. package/src/coinbase-smart-wallet.ts +0 -51
  193. package/src/commands/accept.ts +0 -64
  194. package/src/commands/agent-handshake.ts +0 -72
  195. package/src/commands/agent.ts +0 -691
  196. package/src/commands/agreements.ts +0 -350
  197. package/src/commands/arbitrator.ts +0 -180
  198. package/src/commands/arena-handshake.ts +0 -257
  199. package/src/commands/arena.ts +0 -122
  200. package/src/commands/cancel.ts +0 -35
  201. package/src/commands/channel.ts +0 -218
  202. package/src/commands/coldstart.ts +0 -165
  203. package/src/commands/config.ts +0 -58
  204. package/src/commands/contract-interaction.ts +0 -166
  205. package/src/commands/daemon.ts +0 -978
  206. package/src/commands/deliver.ts +0 -148
  207. package/src/commands/discover.ts +0 -297
  208. package/src/commands/dispute.ts +0 -375
  209. package/src/commands/endpoint.ts +0 -620
  210. package/src/commands/feed.ts +0 -229
  211. package/src/commands/hire.ts +0 -245
  212. package/src/commands/migrate.ts +0 -177
  213. package/src/commands/negotiate.ts +0 -271
  214. package/src/commands/openshell.ts +0 -1055
  215. package/src/commands/owner.ts +0 -35
  216. package/src/commands/policy.ts +0 -263
  217. package/src/commands/relay.ts +0 -273
  218. package/src/commands/remediate.ts +0 -24
  219. package/src/commands/reputation.ts +0 -79
  220. package/src/commands/setup.ts +0 -343
  221. package/src/commands/trust.ts +0 -27
  222. package/src/commands/verify.ts +0 -91
  223. package/src/commands/wallet.ts +0 -3280
  224. package/src/commands/watch.ts +0 -23
  225. package/src/commands/watchtower.ts +0 -248
  226. package/src/commands/workroom.ts +0 -959
  227. package/src/config.ts +0 -174
  228. package/src/daemon/config.ts +0 -308
  229. package/src/daemon/hire-listener.ts +0 -226
  230. package/src/daemon/index.ts +0 -955
  231. package/src/daemon/job-lifecycle.ts +0 -215
  232. package/src/daemon/notify.ts +0 -157
  233. package/src/daemon/token-metering.ts +0 -183
  234. package/src/daemon/userops.ts +0 -119
  235. package/src/daemon/wallet-monitor.ts +0 -90
  236. package/src/drain-v4.ts +0 -159
  237. package/src/endpoint-config.ts +0 -83
  238. package/src/endpoint-notify.ts +0 -46
  239. package/src/index.ts +0 -26
  240. package/src/openshell-runtime.ts +0 -277
  241. package/src/program.ts +0 -83
  242. package/src/repl.ts +0 -680
  243. package/src/signing.ts +0 -28
  244. package/src/telegram-notify.ts +0 -88
  245. package/src/ui/banner.ts +0 -51
  246. package/src/ui/colors.ts +0 -30
  247. package/src/ui/format.ts +0 -77
  248. package/src/ui/spinner.ts +0 -56
  249. package/src/ui/tree.ts +0 -16
  250. package/src/utils/format.ts +0 -48
  251. package/src/utils/hash.ts +0 -5
  252. package/src/utils/time.ts +0 -15
  253. package/src/wallet-router.ts +0 -178
  254. package/src/walletconnect-session.ts +0 -27
  255. package/src/walletconnect.ts +0 -294
  256. package/test/time.test.js +0 -11
  257. package/tsconfig.json +0 -19
@@ -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
- }