arc402-cli 0.9.18 → 0.10.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 (358) hide show
  1. package/README.md +41 -2
  2. package/dist/abis.d.ts +1 -0
  3. package/dist/abis.d.ts.map +1 -1
  4. package/dist/abis.js +45 -14
  5. package/dist/abis.js.map +1 -1
  6. package/dist/bundler.d.ts +1 -1
  7. package/dist/bundler.d.ts.map +1 -1
  8. package/dist/bundler.js +61 -27
  9. package/dist/bundler.js.map +1 -1
  10. package/dist/client.d.ts +1 -1
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +9 -5
  13. package/dist/client.js.map +1 -1
  14. package/dist/coinbase-smart-wallet.js +4 -1
  15. package/dist/coinbase-smart-wallet.js.map +1 -1
  16. package/dist/commands/accept.js +28 -25
  17. package/dist/commands/accept.js.map +1 -1
  18. package/dist/commands/agent-handshake.js +18 -15
  19. package/dist/commands/agent-handshake.js.map +1 -1
  20. package/dist/commands/agent.js +104 -98
  21. package/dist/commands/agent.js.map +1 -1
  22. package/dist/commands/agreements.js +98 -62
  23. package/dist/commands/agreements.js.map +1 -1
  24. package/dist/commands/arbitrator.js +81 -45
  25. package/dist/commands/arbitrator.js.map +1 -1
  26. package/dist/commands/arena-handshake.d.ts.map +1 -1
  27. package/dist/commands/arena-handshake.js +35 -53
  28. package/dist/commands/arena-handshake.js.map +1 -1
  29. package/dist/commands/arena.js +18 -12
  30. package/dist/commands/arena.js.map +1 -1
  31. package/dist/commands/backup.js +36 -30
  32. package/dist/commands/backup.js.map +1 -1
  33. package/dist/commands/cancel.js +18 -15
  34. package/dist/commands/cancel.js.map +1 -1
  35. package/dist/commands/channel.js +81 -45
  36. package/dist/commands/channel.js.map +1 -1
  37. package/dist/commands/coldstart.js +34 -31
  38. package/dist/commands/coldstart.js.map +1 -1
  39. package/dist/commands/compute.d.ts +14 -0
  40. package/dist/commands/compute.d.ts.map +1 -0
  41. package/dist/commands/compute.js +466 -0
  42. package/dist/commands/compute.js.map +1 -0
  43. package/dist/commands/config.js +30 -24
  44. package/dist/commands/config.js.map +1 -1
  45. package/dist/commands/contract-interaction.js +15 -12
  46. package/dist/commands/contract-interaction.js.map +1 -1
  47. package/dist/commands/daemon.d.ts.map +1 -1
  48. package/dist/commands/daemon.js +135 -98
  49. package/dist/commands/daemon.js.map +1 -1
  50. package/dist/commands/deliver.js +76 -37
  51. package/dist/commands/deliver.js.map +1 -1
  52. package/dist/commands/discover.js +27 -24
  53. package/dist/commands/discover.js.map +1 -1
  54. package/dist/commands/dispute.js +110 -104
  55. package/dist/commands/dispute.js.map +1 -1
  56. package/dist/commands/doctor.js +55 -16
  57. package/dist/commands/doctor.js.map +1 -1
  58. package/dist/commands/endpoint.js +95 -56
  59. package/dist/commands/endpoint.js.map +1 -1
  60. package/dist/commands/feed.js +18 -11
  61. package/dist/commands/feed.js.map +1 -1
  62. package/dist/commands/hire.js +40 -37
  63. package/dist/commands/hire.js.map +1 -1
  64. package/dist/commands/migrate.js +33 -30
  65. package/dist/commands/migrate.js.map +1 -1
  66. package/dist/commands/negotiate.d.ts.map +1 -1
  67. package/dist/commands/negotiate.js +36 -34
  68. package/dist/commands/negotiate.js.map +1 -1
  69. package/dist/commands/openshell.js +104 -68
  70. package/dist/commands/openshell.js.map +1 -1
  71. package/dist/commands/owner.js +20 -17
  72. package/dist/commands/owner.js.map +1 -1
  73. package/dist/commands/policy.js +43 -41
  74. package/dist/commands/policy.js.map +1 -1
  75. package/dist/commands/relay.d.ts.map +1 -1
  76. package/dist/commands/relay.js +51 -18
  77. package/dist/commands/relay.js.map +1 -1
  78. package/dist/commands/remediate.js +23 -20
  79. package/dist/commands/remediate.js.map +1 -1
  80. package/dist/commands/reputation.js +27 -25
  81. package/dist/commands/reputation.js.map +1 -1
  82. package/dist/commands/setup.js +104 -65
  83. package/dist/commands/setup.js.map +1 -1
  84. package/dist/commands/trust.js +20 -17
  85. package/dist/commands/trust.js.map +1 -1
  86. package/dist/commands/verify.js +21 -18
  87. package/dist/commands/verify.js.map +1 -1
  88. package/dist/commands/wallet.d.ts.map +1 -1
  89. package/dist/commands/wallet.js +645 -679
  90. package/dist/commands/wallet.js.map +1 -1
  91. package/dist/commands/watch.js +36 -33
  92. package/dist/commands/watch.js.map +1 -1
  93. package/dist/commands/watchtower.js +73 -37
  94. package/dist/commands/watchtower.js.map +1 -1
  95. package/dist/commands/workroom.d.ts.map +1 -1
  96. package/dist/commands/workroom.js +282 -143
  97. package/dist/commands/workroom.js.map +1 -1
  98. package/dist/config.d.ts +3 -0
  99. package/dist/config.d.ts.map +1 -1
  100. package/dist/config.js +71 -22
  101. package/dist/config.js.map +1 -1
  102. package/dist/daemon/compute-metering.d.ts +61 -0
  103. package/dist/daemon/compute-metering.d.ts.map +1 -0
  104. package/dist/daemon/compute-metering.js +299 -0
  105. package/dist/daemon/compute-metering.js.map +1 -0
  106. package/dist/daemon/compute-session.d.ts +100 -0
  107. package/dist/daemon/compute-session.d.ts.map +1 -0
  108. package/dist/daemon/compute-session.js +231 -0
  109. package/dist/daemon/compute-session.js.map +1 -0
  110. package/dist/daemon/config.d.ts +19 -1
  111. package/dist/daemon/config.d.ts.map +1 -1
  112. package/dist/daemon/config.js +90 -16
  113. package/dist/daemon/config.js.map +1 -1
  114. package/dist/daemon/credentials.d.ts +24 -0
  115. package/dist/daemon/credentials.d.ts.map +1 -0
  116. package/dist/daemon/credentials.js +80 -0
  117. package/dist/daemon/credentials.js.map +1 -0
  118. package/dist/daemon/delivery-client.d.ts +35 -0
  119. package/dist/daemon/delivery-client.d.ts.map +1 -0
  120. package/dist/daemon/delivery-client.js +231 -0
  121. package/dist/daemon/delivery-client.js.map +1 -0
  122. package/dist/daemon/file-delivery.d.ts +98 -0
  123. package/dist/daemon/file-delivery.d.ts.map +1 -0
  124. package/dist/daemon/file-delivery.js +461 -0
  125. package/dist/daemon/file-delivery.js.map +1 -0
  126. package/dist/daemon/hire-listener.d.ts +3 -3
  127. package/dist/daemon/hire-listener.d.ts.map +1 -1
  128. package/dist/daemon/hire-listener.js +47 -13
  129. package/dist/daemon/hire-listener.js.map +1 -1
  130. package/dist/daemon/index.d.ts +2 -1
  131. package/dist/daemon/index.d.ts.map +1 -1
  132. package/dist/daemon/index.js +526 -53
  133. package/dist/daemon/index.js.map +1 -1
  134. package/dist/daemon/job-lifecycle.d.ts +1 -1
  135. package/dist/daemon/job-lifecycle.d.ts.map +1 -1
  136. package/dist/daemon/job-lifecycle.js +51 -11
  137. package/dist/daemon/job-lifecycle.js.map +1 -1
  138. package/dist/daemon/notify.d.ts +1 -1
  139. package/dist/daemon/notify.d.ts.map +1 -1
  140. package/dist/daemon/notify.js +53 -19
  141. package/dist/daemon/notify.js.map +1 -1
  142. package/dist/daemon/token-metering.js +47 -8
  143. package/dist/daemon/token-metering.js.map +1 -1
  144. package/dist/daemon/userops.d.ts +2 -2
  145. package/dist/daemon/userops.d.ts.map +1 -1
  146. package/dist/daemon/userops.js +27 -23
  147. package/dist/daemon/userops.js.map +1 -1
  148. package/dist/daemon/wallet-monitor.d.ts +1 -1
  149. package/dist/daemon/wallet-monitor.d.ts.map +1 -1
  150. package/dist/daemon/wallet-monitor.js +12 -8
  151. package/dist/daemon/wallet-monitor.js.map +1 -1
  152. package/dist/daemon/worker-executor.d.ts +71 -0
  153. package/dist/daemon/worker-executor.d.ts.map +1 -0
  154. package/dist/daemon/worker-executor.js +382 -0
  155. package/dist/daemon/worker-executor.js.map +1 -0
  156. package/dist/drain-v4.js +64 -26
  157. package/dist/drain-v4.js.map +1 -1
  158. package/dist/endpoint-config.js +63 -20
  159. package/dist/endpoint-config.js.map +1 -1
  160. package/dist/endpoint-notify.js +48 -9
  161. package/dist/endpoint-notify.js.map +1 -1
  162. package/dist/index.js +50 -18
  163. package/dist/index.js.map +1 -1
  164. package/dist/openshell-runtime.d.ts.map +1 -1
  165. package/dist/openshell-runtime.js +82 -38
  166. package/dist/openshell-runtime.js.map +1 -1
  167. package/dist/program.d.ts.map +1 -1
  168. package/dist/program.js +85 -78
  169. package/dist/program.js.map +1 -1
  170. package/dist/repl.js +31 -25
  171. package/dist/repl.js.map +1 -1
  172. package/dist/signing.js +6 -3
  173. package/dist/signing.js.map +1 -1
  174. package/dist/telegram-notify.js +40 -3
  175. package/dist/telegram-notify.js.map +1 -1
  176. package/dist/tui/App.d.ts.map +1 -1
  177. package/dist/tui/App.js +56 -89
  178. package/dist/tui/App.js.map +1 -1
  179. package/dist/tui/Footer.js +7 -4
  180. package/dist/tui/Footer.js.map +1 -1
  181. package/dist/tui/Header.d.ts +1 -1
  182. package/dist/tui/Header.d.ts.map +1 -1
  183. package/dist/tui/Header.js +14 -9
  184. package/dist/tui/Header.js.map +1 -1
  185. package/dist/tui/InputLine.d.ts +2 -1
  186. package/dist/tui/InputLine.d.ts.map +1 -1
  187. package/dist/tui/InputLine.js +47 -97
  188. package/dist/tui/InputLine.js.map +1 -1
  189. package/dist/tui/Viewport.d.ts +1 -2
  190. package/dist/tui/Viewport.d.ts.map +1 -1
  191. package/dist/tui/Viewport.js +26 -6
  192. package/dist/tui/Viewport.js.map +1 -1
  193. package/dist/tui/WalletConnectPairing.js +19 -16
  194. package/dist/tui/WalletConnectPairing.js.map +1 -1
  195. package/dist/tui/components/Button.js +9 -6
  196. package/dist/tui/components/Button.js.map +1 -1
  197. package/dist/tui/components/CeremonyView.js +8 -5
  198. package/dist/tui/components/CeremonyView.js.map +1 -1
  199. package/dist/tui/components/CompletionDropdown.js +9 -6
  200. package/dist/tui/components/CompletionDropdown.js.map +1 -1
  201. package/dist/tui/components/ConfirmPrompt.js +8 -5
  202. package/dist/tui/components/ConfirmPrompt.js.map +1 -1
  203. package/dist/tui/components/CustomTextInput.js +14 -11
  204. package/dist/tui/components/CustomTextInput.js.map +1 -1
  205. package/dist/tui/components/InteractiveTable.js +12 -9
  206. package/dist/tui/components/InteractiveTable.js.map +1 -1
  207. package/dist/tui/components/StepSpinner.js +13 -10
  208. package/dist/tui/components/StepSpinner.js.map +1 -1
  209. package/dist/tui/components/Toast.js +12 -8
  210. package/dist/tui/components/Toast.js.map +1 -1
  211. package/dist/tui/index.d.ts.map +1 -1
  212. package/dist/tui/index.js +21 -28
  213. package/dist/tui/index.js.map +1 -1
  214. package/dist/tui/useChat.js +19 -13
  215. package/dist/tui/useChat.js.map +1 -1
  216. package/dist/tui/useCommand.d.ts +2 -3
  217. package/dist/tui/useCommand.d.ts.map +1 -1
  218. package/dist/tui/useCommand.js +24 -100
  219. package/dist/tui/useCommand.js.map +1 -1
  220. package/dist/tui/useNotifications.js +8 -5
  221. package/dist/tui/useNotifications.js.map +1 -1
  222. package/dist/tui/useScroll.d.ts.map +1 -1
  223. package/dist/tui/useScroll.js +12 -15
  224. package/dist/tui/useScroll.js.map +1 -1
  225. package/dist/ui/banner.d.ts +0 -12
  226. package/dist/ui/banner.d.ts.map +1 -1
  227. package/dist/ui/banner.js +19 -35
  228. package/dist/ui/banner.js.map +1 -1
  229. package/dist/ui/colors.js +19 -13
  230. package/dist/ui/colors.js.map +1 -1
  231. package/dist/ui/format.js +14 -6
  232. package/dist/ui/format.js.map +1 -1
  233. package/dist/ui/qr-render.js +11 -4
  234. package/dist/ui/qr-render.js.map +1 -1
  235. package/dist/ui/rpc-fallback.js +11 -6
  236. package/dist/ui/rpc-fallback.js.map +1 -1
  237. package/dist/ui/spinner.js +12 -6
  238. package/dist/ui/spinner.js.map +1 -1
  239. package/dist/ui/tree.js +6 -3
  240. package/dist/ui/tree.js.map +1 -1
  241. package/dist/utils/format.js +41 -27
  242. package/dist/utils/format.js.map +1 -1
  243. package/dist/utils/hash.js +42 -4
  244. package/dist/utils/hash.js.map +1 -1
  245. package/dist/utils/time.js +6 -2
  246. package/dist/utils/time.js.map +1 -1
  247. package/dist/wallet-router.d.ts +1 -1
  248. package/dist/wallet-router.d.ts.map +1 -1
  249. package/dist/wallet-router.js +19 -12
  250. package/dist/wallet-router.js.map +1 -1
  251. package/dist/walletconnect-session.d.ts +1 -1
  252. package/dist/walletconnect-session.d.ts.map +1 -1
  253. package/dist/walletconnect-session.js +11 -6
  254. package/dist/walletconnect-session.js.map +1 -1
  255. package/dist/walletconnect.d.ts +5 -6
  256. package/dist/walletconnect.d.ts.map +1 -1
  257. package/dist/walletconnect.js +35 -32
  258. package/dist/walletconnect.js.map +1 -1
  259. package/package.json +11 -10
  260. package/INK6-UX-SPEC.md +0 -446
  261. package/MIGRATION-SPEC.md +0 -108
  262. package/TUI-SPEC.md +0 -214
  263. package/scripts/authorize-machine-key.ts +0 -43
  264. package/scripts/drain-wallet.ts +0 -149
  265. package/scripts/execute-spend-only.ts +0 -81
  266. package/scripts/register-agent-userop.ts +0 -186
  267. package/src/abis.ts +0 -187
  268. package/src/bundler.ts +0 -235
  269. package/src/client.ts +0 -36
  270. package/src/coinbase-smart-wallet.ts +0 -51
  271. package/src/commands/accept.ts +0 -64
  272. package/src/commands/agent-handshake.ts +0 -72
  273. package/src/commands/agent.ts +0 -691
  274. package/src/commands/agreements.ts +0 -350
  275. package/src/commands/arbitrator.ts +0 -180
  276. package/src/commands/arena-handshake.ts +0 -274
  277. package/src/commands/arena.ts +0 -122
  278. package/src/commands/backup.ts +0 -117
  279. package/src/commands/cancel.ts +0 -35
  280. package/src/commands/channel.ts +0 -218
  281. package/src/commands/coldstart.ts +0 -165
  282. package/src/commands/config.ts +0 -68
  283. package/src/commands/contract-interaction.ts +0 -166
  284. package/src/commands/daemon.ts +0 -1054
  285. package/src/commands/deliver.ts +0 -148
  286. package/src/commands/discover.ts +0 -350
  287. package/src/commands/dispute.ts +0 -375
  288. package/src/commands/doctor.ts +0 -172
  289. package/src/commands/endpoint.ts +0 -620
  290. package/src/commands/feed.ts +0 -229
  291. package/src/commands/hire.ts +0 -245
  292. package/src/commands/migrate.ts +0 -177
  293. package/src/commands/negotiate.ts +0 -272
  294. package/src/commands/openshell.ts +0 -1055
  295. package/src/commands/owner.ts +0 -35
  296. package/src/commands/policy.ts +0 -263
  297. package/src/commands/relay.ts +0 -277
  298. package/src/commands/remediate.ts +0 -24
  299. package/src/commands/reputation.ts +0 -79
  300. package/src/commands/setup.ts +0 -343
  301. package/src/commands/trust.ts +0 -27
  302. package/src/commands/verify.ts +0 -91
  303. package/src/commands/wallet.ts +0 -3548
  304. package/src/commands/watch.ts +0 -220
  305. package/src/commands/watchtower.ts +0 -248
  306. package/src/commands/workroom.ts +0 -963
  307. package/src/config.ts +0 -220
  308. package/src/daemon/config.ts +0 -344
  309. package/src/daemon/hire-listener.ts +0 -226
  310. package/src/daemon/index.ts +0 -1089
  311. package/src/daemon/job-lifecycle.ts +0 -215
  312. package/src/daemon/notify.ts +0 -297
  313. package/src/daemon/token-metering.ts +0 -183
  314. package/src/daemon/userops.ts +0 -119
  315. package/src/daemon/wallet-monitor.ts +0 -90
  316. package/src/drain-v4.ts +0 -159
  317. package/src/endpoint-config.ts +0 -83
  318. package/src/endpoint-notify.ts +0 -129
  319. package/src/index.ts +0 -74
  320. package/src/openshell-runtime.ts +0 -281
  321. package/src/program.ts +0 -88
  322. package/src/repl.ts +0 -178
  323. package/src/signing.ts +0 -28
  324. package/src/telegram-notify.ts +0 -88
  325. package/src/tui/App.tsx +0 -263
  326. package/src/tui/Footer.tsx +0 -18
  327. package/src/tui/Header.tsx +0 -45
  328. package/src/tui/InputLine.tsx +0 -243
  329. package/src/tui/Viewport.tsx +0 -51
  330. package/src/tui/WalletConnectPairing.tsx +0 -114
  331. package/src/tui/components/Button.tsx +0 -38
  332. package/src/tui/components/CeremonyView.tsx +0 -39
  333. package/src/tui/components/CompletionDropdown.tsx +0 -56
  334. package/src/tui/components/ConfirmPrompt.tsx +0 -36
  335. package/src/tui/components/CustomTextInput.tsx +0 -132
  336. package/src/tui/components/InteractiveTable.tsx +0 -106
  337. package/src/tui/components/StepSpinner.tsx +0 -84
  338. package/src/tui/components/Toast.tsx +0 -59
  339. package/src/tui/index.tsx +0 -90
  340. package/src/tui/useChat.ts +0 -103
  341. package/src/tui/useCommand.ts +0 -238
  342. package/src/tui/useNotifications.ts +0 -28
  343. package/src/tui/useScroll.ts +0 -69
  344. package/src/ui/banner.ts +0 -78
  345. package/src/ui/colors.ts +0 -30
  346. package/src/ui/format.ts +0 -78
  347. package/src/ui/qr-render.ts +0 -92
  348. package/src/ui/rpc-fallback.ts +0 -59
  349. package/src/ui/spinner.ts +0 -56
  350. package/src/ui/tree.ts +0 -16
  351. package/src/utils/format.ts +0 -48
  352. package/src/utils/hash.ts +0 -5
  353. package/src/utils/time.ts +0 -15
  354. package/src/wallet-router.ts +0 -178
  355. package/src/walletconnect-session.ts +0 -27
  356. package/src/walletconnect.ts +0 -309
  357. package/test/time.test.js +0 -11
  358. package/tsconfig.json +0 -33
@@ -1,148 +0,0 @@
1
- import { Command } from "commander";
2
- import { ServiceAgreementClient, uploadEncryptedIPFS } from "@arc402/sdk";
3
- import { ethers } from "ethers";
4
- import { loadConfig } from "../config.js";
5
- import { getClient, requireSigner } from "../client.js";
6
- import { hashFile, hashString } from "../utils/hash.js";
7
- import { printSenderInfo, executeContractWriteViaWallet } from "../wallet-router.js";
8
- import { SERVICE_AGREEMENT_ABI } from "../abis.js";
9
- import { readFile } from "fs/promises";
10
- import prompts from "prompts";
11
- import { resolveAgentEndpoint, notifyAgent, DEFAULT_REGISTRY_ADDRESS } from "../endpoint-notify.js";
12
- import { c } from '../ui/colors.js';
13
- import { startSpinner } from '../ui/spinner.js';
14
- import { renderTree } from '../ui/tree.js';
15
-
16
- export function registerDeliverCommand(program: Command): void {
17
- program
18
- .command("deliver <id>")
19
- .description("Provider commits a deliverable for verification; legacy fulfill mode is compatibility-only")
20
- .option("--output <filepath>")
21
- .option("--message <text>")
22
- .option("--fulfill", "Use legacy trusted-only fulfill() instead of commitDeliverable()", false)
23
- .option("--encrypt", "Encrypt the deliverable before uploading to IPFS (prompts for recipient public key)", false)
24
- .action(async (id, opts) => {
25
- const config = loadConfig();
26
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
27
- const { signer, address: signerAddress } = await requireSigner(config);
28
- printSenderInfo(config);
29
-
30
- // Pre-flight: check deadline and legacyFulfillEnabled (J3-01, J3-02)
31
- let clientAddress = "";
32
- {
33
- const { provider: prefProvider } = await getClient(config);
34
- const saAbi = [
35
- "function getAgreement(uint256 id) external view returns (tuple(uint256 id, address client, address provider, string serviceType, string description, uint256 price, address token, uint256 deadline, bytes32 deliverablesHash, uint8 status, uint256 createdAt, uint256 resolvedAt, uint256 verifyWindowEnd, bytes32 committedHash))",
36
- "function legacyFulfillEnabled() external view returns (bool)",
37
- "function legacyFulfillProviders(address) external view returns (bool)",
38
- ];
39
- const saContract = new ethers.Contract(config.serviceAgreementAddress!, saAbi, prefProvider);
40
- try {
41
- const ag = await saContract.getAgreement(BigInt(id));
42
- const deadline = Number(ag.deadline);
43
- const nowSec = Math.floor(Date.now() / 1000);
44
- if (nowSec > deadline) {
45
- const deadlineDate = new Date(deadline * 1000).toISOString();
46
- console.error(`Delivery deadline has passed (${deadlineDate}). This transaction will revert.`);
47
- console.error(`Contact the client to open a new agreement.`);
48
- process.exit(1);
49
- }
50
- clientAddress = String(ag.client ?? "");
51
- } catch (e) {
52
- // If it's a contract read failure, skip the check (let the tx reveal the error)
53
- if (e instanceof Error && !e.message.includes("CALL_EXCEPTION") && !e.message.includes("could not decode")) throw e;
54
- }
55
-
56
- if (opts.fulfill) {
57
- let legacyEnabled = false;
58
- try {
59
- legacyEnabled = await saContract.legacyFulfillEnabled();
60
- } catch { /* assume enabled if read fails */ legacyEnabled = true; }
61
- if (!legacyEnabled) {
62
- console.error("Legacy fulfill is disabled on this deployment. Use `arc402 deliver <id>` (without --fulfill) to deliver via the standard flow.");
63
- process.exit(1);
64
- }
65
- let isLegacyProvider = false;
66
- try {
67
- isLegacyProvider = await saContract.legacyFulfillProviders(signerAddress);
68
- } catch { /* assume allowed if read fails */ isLegacyProvider = true; }
69
- if (!isLegacyProvider) {
70
- console.error("You are not in the legacy fulfill providers list for this agreement.");
71
- process.exit(1);
72
- }
73
- }
74
- }
75
-
76
- if (opts.encrypt) {
77
- if (!opts.output) throw new Error("--encrypt requires --output <filepath>");
78
-
79
- const { recipientPubKeyHex } = await prompts({
80
- type: "text",
81
- name: "recipientPubKeyHex",
82
- message: "Recipient NaCl box public key (32 bytes, hex):",
83
- validate: (v: string) => /^[0-9a-fA-F]{64}$/.test(v.trim()) || "Must be 64 hex characters (32 bytes)",
84
- });
85
- if (!recipientPubKeyHex) throw new Error("Recipient public key is required for encrypted delivery");
86
-
87
- const recipientPublicKey = Uint8Array.from(Buffer.from(recipientPubKeyHex.trim(), "hex"));
88
- const buffer = await readFile(opts.output);
89
- const { cid, uri } = await uploadEncryptedIPFS(buffer, recipientPublicKey);
90
- // Hash plaintext so recipient can verify integrity after decryption
91
- const { ethers } = await import("ethers");
92
- const hash = ethers.keccak256(buffer);
93
-
94
- console.log(' ' + c.dim('Encrypted upload:') + ' ' + c.white(uri));
95
-
96
- const encSpinner = startSpinner('Committing deliverable…');
97
- if (config.walletContractAddress) {
98
- await executeContractWriteViaWallet(
99
- config.walletContractAddress, signer, config.serviceAgreementAddress,
100
- SERVICE_AGREEMENT_ABI, "commitDeliverable", [BigInt(id), hash],
101
- );
102
- } else {
103
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
104
- await client.commitDeliverable(BigInt(id), hash);
105
- }
106
- encSpinner.succeed(` Delivered — agreement #${id}`);
107
- renderTree([
108
- { label: 'Hash', value: hash },
109
- { label: 'CID', value: cid },
110
- { label: 'URI', value: uri, last: true },
111
- ]);
112
- return;
113
- }
114
-
115
- const hash = opts.output ? hashFile(opts.output) : hashString(opts.message ?? `agreement:${id}`);
116
- const deliverSpinner = startSpinner(`${opts.fulfill ? 'Fulfilling' : 'Committing deliverable for'} agreement #${id}…`);
117
- if (config.walletContractAddress) {
118
- const fn = opts.fulfill ? "fulfill" : "commitDeliverable";
119
- await executeContractWriteViaWallet(
120
- config.walletContractAddress, signer, config.serviceAgreementAddress,
121
- SERVICE_AGREEMENT_ABI, fn, [BigInt(id), hash],
122
- );
123
- } else {
124
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
125
- if (opts.fulfill) await client.fulfill(BigInt(id), hash); else await client.commitDeliverable(BigInt(id), hash);
126
- }
127
- deliverSpinner.succeed(` ${opts.fulfill ? 'Fulfilled' : 'Delivered'} — agreement #${id}`);
128
- renderTree([
129
- { label: 'Hash', value: hash, last: true },
130
- ]);
131
-
132
- // Notify client's HTTP endpoint (non-blocking)
133
- if (clientAddress) {
134
- try {
135
- const notifyProvider = new ethers.JsonRpcProvider(config.rpcUrl);
136
- const registryAddress = config.agentRegistryV2Address ?? config.agentRegistryAddress ?? DEFAULT_REGISTRY_ADDRESS;
137
- const endpoint = await resolveAgentEndpoint(clientAddress, notifyProvider, registryAddress);
138
- await notifyAgent(endpoint, "/delivery", {
139
- agreementId: id,
140
- deliverableHash: hash,
141
- from: signerAddress,
142
- });
143
- } catch (err) {
144
- console.warn(`Warning: could not notify client endpoint: ${err instanceof Error ? err.message : String(err)}`);
145
- }
146
- }
147
- });
148
- }
@@ -1,350 +0,0 @@
1
- import { Command } from "commander";
2
- import { ethers } from "ethers";
3
- import { AgentRegistryClient, CapabilityRegistryClient, ReputationOracleClient, SponsorshipAttestationClient } from "@arc402/sdk";
4
- import { loadConfig } from "../config.js";
5
- import { getClient } from "../client.js";
6
- import { getTrustTier, printTable, truncateAddress } from "../utils/format.js";
7
- import { c } from '../ui/colors.js';
8
- import { renderTree } from '../ui/tree.js';
9
-
10
- // Minimal ABI for the new getAgentsWithCapability function (Spec 18)
11
- const CAPABILITY_REGISTRY_EXTRA_ABI = [
12
- "function getAgentsWithCapability(string calldata capability) external view returns (address[])",
13
- ];
14
-
15
- // ─── Composite scoring helpers ────────────────────────────────────────────────
16
-
17
- interface ScoredAgent {
18
- wallet: string;
19
- name: string;
20
- serviceType: string;
21
- endpoint: string;
22
- metadataURI: string;
23
- capabilities: string[];
24
- canonicalCapabilities: string[];
25
- trustScore: number;
26
- stake: bigint;
27
- completedJobs: number;
28
- priceUsd: number | null;
29
- compositeScore: number;
30
- rank: number;
31
- operational: { uptimeScore: number; responseScore: number };
32
- highestTier?: unknown;
33
- reputation?: unknown;
34
- }
35
-
36
- function normalise(values: number[]): number[] {
37
- const min = Math.min(...values);
38
- const max = Math.max(...values);
39
- const range = max - min;
40
- if (range === 0) return values.map(() => 1);
41
- return values.map((v) => (v - min) / range);
42
- }
43
-
44
- function computeCompositeScores(agents: Omit<ScoredAgent, "compositeScore" | "rank">[]): ScoredAgent[] {
45
- if (agents.length === 0) return [];
46
-
47
- const trustVals = normalise(agents.map((a) => a.trustScore));
48
- const stakeVals = normalise(agents.map((a) => Number(a.stake)));
49
- const jobsVals = normalise(agents.map((a) => a.completedJobs));
50
-
51
- // Price: lower is better — invert. Missing price gets neutral 0.5.
52
- const rawPrices = agents.map((a) => (a.priceUsd !== null ? a.priceUsd : -1));
53
- const validPrices = rawPrices.filter((p) => p >= 0);
54
- const maxPrice = validPrices.length > 0 ? Math.max(...validPrices) : 1;
55
- const priceInvVals = rawPrices.map((p) =>
56
- p < 0 ? 0.5 : maxPrice > 0 ? 1 - p / maxPrice : 1
57
- );
58
-
59
- return agents.map((agent, i) => ({
60
- ...agent,
61
- compositeScore:
62
- trustVals[i] * 0.5 +
63
- stakeVals[i] * 0.2 +
64
- jobsVals[i] * 0.2 +
65
- priceInvVals[i] * 0.1,
66
- rank: 0, // filled after sort
67
- }));
68
- }
69
-
70
- // ─── Endpoint health check ────────────────────────────────────────────────────
71
-
72
- async function pingEndpoint(endpoint: string): Promise<"online" | "offline"> {
73
- if (!endpoint || !/^https?:\/\//.test(endpoint)) return "offline";
74
- try {
75
- const ctrl = new AbortController();
76
- const tid = setTimeout(() => ctrl.abort(), 3000);
77
- const resp = await fetch(`${endpoint.replace(/\/$/, "")}/health`, { signal: ctrl.signal });
78
- clearTimeout(tid);
79
- return resp.ok ? "online" : "offline";
80
- } catch {
81
- return "offline";
82
- }
83
- }
84
-
85
- // ─── Command ──────────────────────────────────────────────────────────────────
86
-
87
- export function registerDiscoverCommand(program: Command): void {
88
- program
89
- .command("discover")
90
- .description(
91
- "Discover agents by capability with trust/price/stake filters and composite ranking (Specs 16, 18)"
92
- )
93
- .option("--capability <cap>", "Exact canonical capability (e.g. legal.patent-analysis.us.v1)")
94
- .option("--capability-prefix <pfx>", "Prefix match against registered capabilities")
95
- .option("--service-type <type>", "Filter by serviceType substring")
96
- .option("--type <type>", "Filter by serviceType substring (alias for --service-type)")
97
- .option("--min-trust <score>", "Minimum trust score", "0")
98
- .option("--max-price <usd>", "Maximum price in USD (from agent metadataURI, best-effort)", "0")
99
- .option("--min-stake <wei>", "Minimum stake in wei", "0")
100
- .option("--top <n>", "Show top N agents by trust score")
101
- .option("--sort <field>", "Sort by: trust | price | jobs | stake | composite", "composite")
102
- .option("--limit <n>", "Max results", "20")
103
- .option("--online", "Only show agents whose /health endpoint responds")
104
- .option("--json", "Machine-parseable output")
105
- .action(async (opts) => {
106
- const config = loadConfig();
107
- if (!config.agentRegistryAddress) throw new Error("agentRegistryAddress missing in config");
108
- const { provider } = await getClient(config);
109
-
110
- const registry = new AgentRegistryClient(config.agentRegistryAddress, provider);
111
- const capabilitySDK = config.capabilityRegistryAddress
112
- ? new CapabilityRegistryClient(config.capabilityRegistryAddress, provider)
113
- : null;
114
- const sponsorship = config.sponsorshipAttestationAddress
115
- ? new SponsorshipAttestationClient(config.sponsorshipAttestationAddress, provider)
116
- : null;
117
- const reputation = config.reputationOracleAddress
118
- ? new ReputationOracleClient(config.reputationOracleAddress, provider)
119
- : null;
120
-
121
- // --top <n> sets sort to trust and overrides limit
122
- const effectiveSort = opts.top ? "trust" : opts.sort;
123
- const limit = opts.top ? Number(opts.top) : Number(opts.limit);
124
- const minTrust = Number(opts.minTrust);
125
- const maxPriceUsd = Number(opts.maxPrice); // 0 = no filter
126
- const minStakeWei = BigInt(opts.minStake);
127
- // --type is an alias for --service-type
128
- if (opts.type && !opts.serviceType) opts.serviceType = opts.type;
129
-
130
- // ── Step 1: Get candidate addresses ─────────────────────────────────────
131
-
132
- let candidateAddresses: string[] | null = null;
133
-
134
- if (opts.capability && config.capabilityRegistryAddress) {
135
- // Use the reverse index for O(1) exact-match (Spec 18: getAgentsWithCapability)
136
- const capContract = new ethers.Contract(
137
- config.capabilityRegistryAddress,
138
- CAPABILITY_REGISTRY_EXTRA_ABI,
139
- provider
140
- );
141
- try {
142
- const addrs: string[] = await capContract.getAgentsWithCapability(opts.capability);
143
- candidateAddresses = addrs;
144
- } catch {
145
- // Contract may not have been upgraded yet; fall through to listAgents
146
- }
147
- }
148
-
149
- // ── Step 2: Load agent data ───────────────────────────────────────────
150
-
151
- let agentInfos: Awaited<ReturnType<typeof registry.listAgents>>;
152
-
153
- if (candidateAddresses !== null) {
154
- const results = await Promise.allSettled(
155
- candidateAddresses.map((addr) => registry.getAgent(addr))
156
- );
157
- agentInfos = results
158
- .filter((r): r is PromiseFulfilledResult<typeof agentInfos[number]> => r.status === "fulfilled")
159
- .map((r) => r.value);
160
- } else {
161
- agentInfos = await registry.listAgents(limit * 10);
162
- }
163
-
164
- // ── Step 3: Apply filters ────────────────────────────────────────────
165
-
166
- let filtered = agentInfos.filter((a) => a.active !== false);
167
-
168
- if (opts.capability) {
169
- filtered = filtered.filter((a) =>
170
- a.capabilities.some((c: string) => c === opts.capability)
171
- );
172
- }
173
-
174
- if (opts.capabilityPrefix) {
175
- filtered = filtered.filter((a) =>
176
- a.capabilities.some((c: string) => c.startsWith(opts.capabilityPrefix as string))
177
- );
178
- }
179
-
180
- if (opts.serviceType) {
181
- filtered = filtered.filter((a) =>
182
- a.serviceType.toLowerCase().includes(String(opts.serviceType).toLowerCase())
183
- );
184
- }
185
-
186
- filtered = filtered.filter((a) => Number(a.trustScore ?? 0n) >= minTrust);
187
-
188
- if (minStakeWei > 0n) {
189
- filtered = filtered.filter((a) => {
190
- const stake = (a as unknown as { stake?: bigint }).stake ?? 0n;
191
- return BigInt(stake) >= minStakeWei;
192
- });
193
- }
194
-
195
- // ── Step 4: Enrich ──────────────────────────────────────────────────
196
-
197
- const enriched = await Promise.all(
198
- filtered.slice(0, limit * 5).map(async (agent) => {
199
- const [operational, canonicalCapabilities, highestTier, rep] = await Promise.all([
200
- registry.getOperationalMetrics(agent.wallet),
201
- capabilitySDK ? capabilitySDK.getCapabilities(agent.wallet) : Promise.resolve([]),
202
- sponsorship ? sponsorship.getHighestTier(agent.wallet) : Promise.resolve(undefined),
203
- reputation ? reputation.getReputation(agent.wallet) : Promise.resolve(undefined),
204
- ]);
205
-
206
- // Best-effort metadata fetch for priceUsd
207
- let priceUsd: number | null = null;
208
- if (agent.metadataURI && /^https?:\/\//.test(agent.metadataURI)) {
209
- try {
210
- const ctrl = new AbortController();
211
- const tid = setTimeout(() => ctrl.abort(), 2000);
212
- const resp = await fetch(agent.metadataURI, { signal: ctrl.signal });
213
- clearTimeout(tid);
214
- if (resp.ok) {
215
- const meta = await resp.json() as { pricing?: { priceUsd?: number } };
216
- if (meta.pricing?.priceUsd != null) priceUsd = meta.pricing.priceUsd;
217
- }
218
- } catch { /* ignore — advisory only */ }
219
- }
220
-
221
- // Apply max-price filter post-enrichment
222
- if (maxPriceUsd > 0 && priceUsd !== null && priceUsd > maxPriceUsd) {
223
- return null;
224
- }
225
-
226
- const repObj = rep && typeof rep === "object" ? (rep as unknown) as Record<string, unknown> : {};
227
-
228
- return {
229
- wallet: agent.wallet,
230
- name: agent.name,
231
- serviceType: agent.serviceType,
232
- endpoint: agent.endpoint,
233
- metadataURI: agent.metadataURI,
234
- capabilities: agent.capabilities as string[],
235
- canonicalCapabilities: canonicalCapabilities as string[],
236
- trustScore: Number(agent.trustScore ?? 0n),
237
- stake: (agent as unknown as { stake?: bigint }).stake ?? 0n,
238
- completedJobs: Number(repObj.completedJobs ?? 0),
239
- priceUsd,
240
- compositeScore: 0,
241
- rank: 0,
242
- operational: {
243
- uptimeScore: Number(operational.uptimeScore),
244
- responseScore: Number(operational.responseScore),
245
- },
246
- highestTier,
247
- reputation: rep,
248
- } as Omit<ScoredAgent, "compositeScore" | "rank">;
249
- })
250
- );
251
-
252
- const validAgents = enriched.filter((a): a is Omit<ScoredAgent, "compositeScore" | "rank"> => a !== null);
253
-
254
- // ── Step 5: Score ──────────────────────────────────────────────────────
255
-
256
- let scored = computeCompositeScores(validAgents);
257
-
258
- // Sort
259
- switch (effectiveSort) {
260
- case "trust":
261
- scored.sort((a, b) => b.trustScore - a.trustScore);
262
- break;
263
- case "price":
264
- scored.sort((a, b) => {
265
- if (a.priceUsd === null && b.priceUsd === null) return 0;
266
- if (a.priceUsd === null) return 1;
267
- if (b.priceUsd === null) return -1;
268
- return a.priceUsd - b.priceUsd;
269
- });
270
- break;
271
- case "jobs":
272
- scored.sort((a, b) => b.completedJobs - a.completedJobs);
273
- break;
274
- case "stake":
275
- scored.sort((a, b) => (b.stake > a.stake ? 1 : b.stake < a.stake ? -1 : 0));
276
- break;
277
- default: // "composite"
278
- scored.sort((a, b) => b.compositeScore - a.compositeScore);
279
- }
280
-
281
- // Assign 1-based ranks after sort
282
- scored = scored.slice(0, limit).map((a, i) => ({ ...a, rank: i + 1 }));
283
-
284
- // ── Step 6: Endpoint health checks ────────────────────────────────────
285
-
286
- type ScoredWithStatus = ScoredAgent & { endpointStatus: "online" | "offline" | "unknown" };
287
-
288
- let withStatus: ScoredWithStatus[];
289
-
290
- if (opts.online || /* always ping for tree display */ true) {
291
- const statuses = await Promise.all(
292
- scored.map(async (agent) => {
293
- if (!agent.endpoint) return "unknown" as const;
294
- return pingEndpoint(agent.endpoint);
295
- })
296
- );
297
- withStatus = scored.map((agent, i) => ({ ...agent, endpointStatus: statuses[i] as "online" | "offline" | "unknown" }));
298
- } else {
299
- withStatus = scored.map((agent) => ({ ...agent, endpointStatus: "unknown" as const }));
300
- }
301
-
302
- // Apply --online filter
303
- if (opts.online) {
304
- withStatus = withStatus.filter((a) => a.endpointStatus === "online");
305
- if (withStatus.length === 0) {
306
- console.log(`\n ${c.warning} No agents with responding /health endpoints found.`);
307
- return;
308
- }
309
- }
310
-
311
- // ── Step 7: Output ─────────────────────────────────────────────────────
312
-
313
- if (opts.json) {
314
- return console.log(JSON.stringify(
315
- withStatus,
316
- (_k, value) => typeof value === "bigint" ? value.toString() : value,
317
- 2
318
- ));
319
- }
320
-
321
- const onlineCount = withStatus.filter((a) => a.endpointStatus === "online").length;
322
- console.log('\n ' + c.mark + c.white(' Discover Results') + c.dim(` — ${withStatus.length} agent${withStatus.length !== 1 ? 's' : ''} found, ${onlineCount} online`));
323
-
324
- // Tree output per agent
325
- for (const agent of withStatus) {
326
- const caps = (agent.canonicalCapabilities.length
327
- ? agent.canonicalCapabilities
328
- : agent.capabilities
329
- ).slice(0, 3).join(", ") || c.dim("none");
330
-
331
- const statusIcon = agent.endpointStatus === "online"
332
- ? c.green("● online")
333
- : agent.endpointStatus === "offline"
334
- ? c.red("○ offline")
335
- : c.dim("? unknown");
336
-
337
- const tierStr = getTrustTier(agent.trustScore);
338
-
339
- console.log(`\n ${c.dim(`#${agent.rank}`)} ${c.white(agent.name)} ${c.dim(truncateAddress(agent.wallet))}`);
340
- renderTree([
341
- { label: "service", value: agent.serviceType },
342
- { label: "trust", value: `${agent.trustScore} ${tierStr}` },
343
- { label: "score", value: agent.compositeScore.toFixed(3) },
344
- { label: "caps", value: caps },
345
- { label: "endpoint", value: statusIcon, last: true },
346
- ]);
347
- }
348
- console.log();
349
- });
350
- }