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,35 +0,0 @@
1
- import { Command } from "commander";
2
- import { DisputeArbitrationClient } from "@arc402/sdk";
3
- import { loadConfig } from "../config.js";
4
- import { requireSigner } from "../client.js";
5
- import { c } from '../ui/colors.js';
6
- import { startSpinner } from '../ui/spinner.js';
7
- import { formatAddress } from '../ui/format.js';
8
-
9
- export function registerOwnerCommands(program: Command): void {
10
- const owner = program.command("owner").description("Protocol ownership management (DisputeArbitration two-step transfer)");
11
-
12
- owner.command("propose-transfer <newOwner>")
13
- .description("Step 1: Propose ownership transfer of DisputeArbitration to a new address. New owner must call accept-transfer to complete.")
14
- .action(async (newOwner, _opts) => {
15
- const config = loadConfig();
16
- if (!config.disputeArbitrationAddress) throw new Error("disputeArbitrationAddress missing in config");
17
- const { signer } = await requireSigner(config);
18
- const client = new DisputeArbitrationClient(config.disputeArbitrationAddress, signer);
19
- const spinner = startSpinner('Proposing ownership transfer…');
20
- await client.proposeOwner(newOwner);
21
- spinner.succeed(c.success + c.white(' Ownership transfer proposed to ' + formatAddress(newOwner)));
22
- });
23
-
24
- owner.command("accept-transfer")
25
- .description("Step 2: Accept pending ownership of DisputeArbitration. Must be called from the pending owner's key.")
26
- .action(async (_opts) => {
27
- const config = loadConfig();
28
- if (!config.disputeArbitrationAddress) throw new Error("disputeArbitrationAddress missing in config");
29
- const { signer } = await requireSigner(config);
30
- const client = new DisputeArbitrationClient(config.disputeArbitrationAddress, signer);
31
- const spinner = startSpinner('Accepting ownership…');
32
- await client.acceptOwnership();
33
- spinner.succeed(c.success + c.white(' Ownership accepted'));
34
- });
35
- }
@@ -1,263 +0,0 @@
1
- import { Command } from "commander";
2
- import { ethers } from "ethers";
3
- import { loadConfig } from "../config.js";
4
- import { getClient, requireSigner } from "../client.js";
5
- import { c } from '../ui/colors.js';
6
- import { startSpinner } from '../ui/spinner.js';
7
- import { formatAddress } from '../ui/format.js';
8
-
9
- const POLICY_ENGINE_EXTENDED_ABI = [
10
- "function addToBlocklist(address wallet, address provider) external",
11
- "function removeFromBlocklist(address wallet, address provider) external",
12
- "function isBlocked(address wallet, address provider) external view returns (bool)",
13
- "function addPreferred(address wallet, string capability, address provider) external",
14
- "function removePreferred(address wallet, string capability, address provider) external",
15
- "function getPreferred(address wallet, string capability) external view returns (address[])",
16
- "function isPreferred(address wallet, string capability, address provider) external view returns (bool)",
17
- "event ProviderBlocked(address indexed wallet, address indexed provider)",
18
- "event ProviderUnblocked(address indexed wallet, address indexed provider)",
19
- "event ProviderPreferred(address indexed wallet, address indexed provider, string capability)",
20
- "event ProviderUnpreferred(address indexed wallet, address indexed provider, string capability)",
21
- ] as const;
22
-
23
- function getPolicyEngine(address: string, runner: ethers.ContractRunner) {
24
- return new ethers.Contract(address, POLICY_ENGINE_EXTENDED_ABI, runner);
25
- }
26
-
27
- const policy = new Command("policy").description("Personal policy enforcement: blocklist and shortlist");
28
-
29
- // ─── blocklist ────────────────────────────────────────────────────────────────
30
-
31
- const blocklist = policy.command("blocklist").description("Hard-stop blocklist: addresses your agent will never accept work from");
32
-
33
- blocklist
34
- .command("add <address>")
35
- .description("Block a provider address")
36
- .option("--json")
37
- .action(async (address, opts) => {
38
- const config = loadConfig();
39
- if (!config.policyEngineAddress) {
40
- console.error("policyEngineAddress not configured. Run `arc402 config set policyEngineAddress <address>`.");
41
- process.exit(1);
42
- }
43
- const { signer, address: wallet } = await requireSigner(config);
44
- const contract = getPolicyEngine(config.policyEngineAddress, signer);
45
- const already = await contract.isBlocked(wallet, address);
46
- if (already) {
47
- if (opts.json) return console.log(JSON.stringify({ address, blocked: true, alreadyBlocked: true }));
48
- return console.log(' ' + c.dim('Already blocked: ' + formatAddress(address)));
49
- }
50
- await (await contract.addToBlocklist(wallet, address)).wait();
51
- if (opts.json) return console.log(JSON.stringify({ address, blocked: true }));
52
- console.log(' ' + c.success + c.white(' Blocked: ' + formatAddress(address)));
53
- });
54
-
55
- blocklist
56
- .command("remove <address>")
57
- .description("Remove a provider from your blocklist")
58
- .option("--json")
59
- .action(async (address, opts) => {
60
- const config = loadConfig();
61
- if (!config.policyEngineAddress) {
62
- console.error("policyEngineAddress not configured. Run `arc402 config set policyEngineAddress <address>`.");
63
- process.exit(1);
64
- }
65
- const { signer, address: wallet } = await requireSigner(config);
66
- const contract = getPolicyEngine(config.policyEngineAddress, signer);
67
- const isBlockedNow = await contract.isBlocked(wallet, address);
68
- if (!isBlockedNow) {
69
- if (opts.json) return console.log(JSON.stringify({ address, blocked: false, notBlocked: true }));
70
- return console.log(' ' + c.dim('Not on blocklist: ' + formatAddress(address)));
71
- }
72
- await (await contract.removeFromBlocklist(wallet, address)).wait();
73
- if (opts.json) return console.log(JSON.stringify({ address, blocked: false }));
74
- console.log(' ' + c.success + c.white(' Unblocked: ' + formatAddress(address)));
75
- });
76
-
77
- blocklist
78
- .command("check <address>")
79
- .description("Check if an address is on your blocklist")
80
- .option("--json")
81
- .action(async (address, opts) => {
82
- const config = loadConfig();
83
- if (!config.policyEngineAddress) {
84
- console.error("policyEngineAddress not configured.");
85
- process.exit(1);
86
- }
87
- const { provider } = await getClient(config);
88
- const { address: wallet } = await requireSigner(config);
89
- const contract = getPolicyEngine(config.policyEngineAddress, provider);
90
- const blocked = await contract.isBlocked(wallet, address);
91
- if (opts.json) return console.log(JSON.stringify({ address, blocked }));
92
- if (blocked) {
93
- console.log(' ' + c.warning + c.white(' ' + formatAddress(address) + ' is BLOCKED'));
94
- } else {
95
- console.log(' ' + c.success + c.white(' ' + formatAddress(address) + ' is not blocked'));
96
- }
97
- });
98
-
99
- blocklist
100
- .command("list")
101
- .description("List all addresses on your blocklist (scans on-chain events)")
102
- .option("--from-block <n>", "Start block for event log query (default: latest-9000 to stay within public RPC limits)")
103
- .option("--json")
104
- .action(async (opts) => {
105
- const config = loadConfig();
106
- if (!config.policyEngineAddress) {
107
- console.error("policyEngineAddress not configured.");
108
- process.exit(1);
109
- }
110
- const { provider } = await getClient(config);
111
- const { address: wallet } = await requireSigner(config);
112
- const contract = getPolicyEngine(config.policyEngineAddress, provider);
113
-
114
- const latestBlock = await provider.getBlockNumber();
115
- const fromBlock = opts.fromBlock !== undefined ? parseInt(opts.fromBlock, 10) : Math.max(0, latestBlock - 9000);
116
-
117
- const [blockedEvents, unblockedEvents] = await Promise.all([
118
- contract.queryFilter(contract.filters.ProviderBlocked(wallet), fromBlock),
119
- contract.queryFilter(contract.filters.ProviderUnblocked(wallet), fromBlock),
120
- ]);
121
- const unblocked = new Set(
122
- unblockedEvents.map((e) => (e as ethers.EventLog).args.provider.toLowerCase())
123
- );
124
- const addresses = blockedEvents
125
- .map((e) => (e as ethers.EventLog).args.provider as string)
126
- .filter((p) => !unblocked.has(p.toLowerCase()));
127
-
128
- if (opts.json) return console.log(JSON.stringify({ wallet, blocked: addresses }, null, 2));
129
- if (addresses.length === 0) return console.log("No addresses on your blocklist");
130
- addresses.forEach((a) => console.log(a));
131
- });
132
-
133
- // ─── shortlist ────────────────────────────────────────────────────────────────
134
-
135
- const shortlist = policy.command("shortlist").description("Preferred providers per capability (preferred or exclusive)");
136
-
137
- shortlist
138
- .command("add <address>")
139
- .description("Add a provider to your shortlist for a capability")
140
- .requiredOption("--capability <name>", "Capability name (e.g. code.review)")
141
- .option("--note <text>", "Optional note (stored off-chain only)")
142
- .option("--json")
143
- .action(async (address, opts) => {
144
- const config = loadConfig();
145
- if (!config.policyEngineAddress) {
146
- console.error("policyEngineAddress not configured. Run `arc402 config set policyEngineAddress <address>`.");
147
- process.exit(1);
148
- }
149
- const { signer, address: wallet } = await requireSigner(config);
150
- const contract = getPolicyEngine(config.policyEngineAddress, signer);
151
- const alreadyPreferred = await contract.isPreferred(wallet, opts.capability, address);
152
- if (alreadyPreferred) {
153
- if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: true, alreadyPreferred: true }));
154
- return console.log(' ' + c.dim('Already shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
155
- }
156
- await (await contract.addPreferred(wallet, opts.capability, address)).wait();
157
- if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: true }));
158
- console.log(' ' + c.success + c.white(' Shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
159
- });
160
-
161
- shortlist
162
- .command("remove <address>")
163
- .description("Remove a provider from your shortlist for a capability")
164
- .requiredOption("--capability <name>", "Capability name")
165
- .option("--json")
166
- .action(async (address, opts) => {
167
- const config = loadConfig();
168
- if (!config.policyEngineAddress) {
169
- console.error("policyEngineAddress not configured. Run `arc402 config set policyEngineAddress <address>`.");
170
- process.exit(1);
171
- }
172
- const { signer, address: wallet } = await requireSigner(config);
173
- const contract = getPolicyEngine(config.policyEngineAddress, signer);
174
- const isPreferredNow = await contract.isPreferred(wallet, opts.capability, address);
175
- if (!isPreferredNow) {
176
- if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: false, notPreferred: true }));
177
- return console.log(' ' + c.dim('Not shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
178
- }
179
- await (await contract.removePreferred(wallet, opts.capability, address)).wait();
180
- if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: false }));
181
- console.log(' ' + c.success + c.white(' Removed from shortlist: ' + formatAddress(address) + ' for ' + opts.capability));
182
- });
183
-
184
- shortlist
185
- .command("check <address>")
186
- .description("Check if an address is shortlisted for a capability")
187
- .requiredOption("--capability <name>", "Capability name")
188
- .option("--json")
189
- .action(async (address, opts) => {
190
- const config = loadConfig();
191
- if (!config.policyEngineAddress) {
192
- console.error("policyEngineAddress not configured.");
193
- process.exit(1);
194
- }
195
- const { provider } = await getClient(config);
196
- const { address: wallet } = await requireSigner(config);
197
- const contract = getPolicyEngine(config.policyEngineAddress, provider);
198
- const preferred = await contract.isPreferred(wallet, opts.capability, address);
199
- if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred }));
200
- if (preferred) {
201
- console.log(' ' + c.success + c.white(' ' + formatAddress(address) + ' is shortlisted for ' + opts.capability));
202
- } else {
203
- console.log(' ' + c.warning + c.white(' ' + formatAddress(address) + ' is NOT shortlisted for ' + opts.capability));
204
- }
205
- });
206
-
207
- shortlist
208
- .command("list")
209
- .description("List shortlisted providers, optionally filtered by capability")
210
- .option("--capability <name>", "Filter by capability name")
211
- .option("--from-block <n>", "Start block for event log query (default: latest-9000 to stay within public RPC limits)")
212
- .option("--json")
213
- .action(async (opts) => {
214
- const config = loadConfig();
215
- if (!config.policyEngineAddress) {
216
- console.error("policyEngineAddress not configured.");
217
- process.exit(1);
218
- }
219
- const { provider } = await getClient(config);
220
- const { address: wallet } = await requireSigner(config);
221
- const contract = getPolicyEngine(config.policyEngineAddress, provider);
222
-
223
- if (opts.capability) {
224
- const addresses = await contract.getPreferred(wallet, opts.capability) as string[];
225
- if (opts.json) return console.log(JSON.stringify({ wallet, capability: opts.capability, preferred: addresses }, null, 2));
226
- if (addresses.length === 0) return console.log(`No providers shortlisted for ${opts.capability}`);
227
- addresses.forEach((a) => console.log(a));
228
- return;
229
- }
230
-
231
- // No capability filter — reconstruct from events
232
- const latestBlock = await provider.getBlockNumber();
233
- const fromBlock = opts.fromBlock !== undefined ? parseInt(opts.fromBlock, 10) : Math.max(0, latestBlock - 9000);
234
- const [preferredEvents, unpreferredEvents] = await Promise.all([
235
- contract.queryFilter(contract.filters.ProviderPreferred(wallet), fromBlock),
236
- contract.queryFilter(contract.filters.ProviderUnpreferred(wallet), fromBlock),
237
- ]);
238
- const removed = new Set(
239
- unpreferredEvents.map((e) => {
240
- const args = (e as ethers.EventLog).args;
241
- return `${(args.provider as string).toLowerCase()}::${args.capability as string}`;
242
- })
243
- );
244
- const byCapability: Record<string, string[]> = {};
245
- for (const e of preferredEvents) {
246
- const args = (e as ethers.EventLog).args;
247
- const addr = args.provider as string;
248
- const cap = args.capability as string;
249
- if (removed.has(`${addr.toLowerCase()}::${cap}`)) continue;
250
- if (!byCapability[cap]) byCapability[cap] = [];
251
- if (!byCapability[cap].includes(addr)) byCapability[cap].push(addr);
252
- }
253
-
254
- if (opts.json) return console.log(JSON.stringify({ wallet, shortlist: byCapability }, null, 2));
255
- const caps = Object.keys(byCapability);
256
- if (caps.length === 0) return console.log("No providers on your shortlist");
257
- for (const cap of caps) {
258
- console.log(`${cap}:`);
259
- byCapability[cap].forEach((a) => console.log(` ${a}`));
260
- }
261
- });
262
-
263
- export default policy;
@@ -1,277 +0,0 @@
1
- import { Command } from "commander";
2
- import * as fs from "fs";
3
- import * as path from "path";
4
- import * as os from "os";
5
- import * as http from "http";
6
- import * as https from "https";
7
- import { spawn } from "child_process";
8
- import { c } from '../ui/colors.js';
9
-
10
- import { fileURLToPath } from "node:url";
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
13
-
14
- const PID_FILE = path.join(os.homedir(), ".arc402", "relay.pid");
15
-
16
- // ─── HTTP helper (no external deps) ──────────────────────────────────────────
17
-
18
- function relayRequest(
19
- relayUrl: string,
20
- method: string,
21
- urlPath: string,
22
- body?: object
23
- ): Promise<{ status: number; data: unknown }> {
24
- return new Promise((resolve, reject) => {
25
- const parsed = new URL(urlPath, relayUrl);
26
- const isHttps = parsed.protocol === "https:";
27
- const mod = isHttps ? https : http;
28
- const bodyStr = body ? JSON.stringify(body) : undefined;
29
- const options: http.RequestOptions = {
30
- hostname: parsed.hostname,
31
- port: parsed.port || (isHttps ? 443 : 80),
32
- path: parsed.pathname + (parsed.search || ""),
33
- method,
34
- headers: {
35
- "Content-Type": "application/json",
36
- ...(bodyStr ? { "Content-Length": String(Buffer.byteLength(bodyStr)) } : {}),
37
- },
38
- };
39
- const req = mod.request(options, (res) => {
40
- let raw = "";
41
- res.on("data", (c: Buffer) => { raw += c.toString(); });
42
- res.on("end", () => {
43
- try {
44
- resolve({ status: res.statusCode ?? 0, data: JSON.parse(raw) });
45
- } catch {
46
- resolve({ status: res.statusCode ?? 0, data: raw });
47
- }
48
- });
49
- });
50
- req.on("error", reject);
51
- if (bodyStr) req.write(bodyStr);
52
- req.end();
53
- });
54
- }
55
-
56
- // ─── Daemon loop (runs in-process when spawned with ARC402_RELAY_DAEMON=1) ───
57
-
58
- async function runDaemonLoop(opts: {
59
- relayUrl: string;
60
- address: string;
61
- pollInterval: number;
62
- onMessage: string;
63
- }): Promise<void> {
64
- let lastSeen: string | null = null;
65
-
66
- const poll = async () => {
67
- try {
68
- const qs = `?address=${encodeURIComponent(opts.address)}` +
69
- (lastSeen ? `&since=${encodeURIComponent(lastSeen)}` : "");
70
- const result = await relayRequest(opts.relayUrl, "GET", `/poll${qs}`);
71
- const data = result.data as { messages?: Array<{ messageId: string; payload: unknown }> };
72
- const messages = data.messages || [];
73
- for (const msg of messages) {
74
- lastSeen = msg.messageId;
75
- // Spawn the handler script with message JSON on stdin
76
- const child = spawn(opts.onMessage, [], {
77
- stdio: ["pipe", "inherit", "inherit"],
78
- shell: true,
79
- });
80
- child.stdin.write(JSON.stringify(msg));
81
- child.stdin.end();
82
- }
83
- } catch {
84
- // Silent retry — relay may be temporarily unreachable
85
- }
86
- };
87
-
88
- // Initial poll immediately, then on interval
89
- await poll();
90
- setInterval(poll, opts.pollInterval);
91
-
92
- // Keep process alive
93
- process.stdin.resume();
94
- }
95
-
96
- // ─── Command registration ─────────────────────────────────────────────────────
97
-
98
- export function registerRelayCommands(program: Command): void {
99
- const relay = program
100
- .command("relay")
101
- .description("Send and receive messages via an ARC-402 relay (Spec 21)");
102
-
103
- // ── relay send ──────────────────────────────────────────────────────────────
104
- relay
105
- .command("send")
106
- .description("Send a message to an address via the relay")
107
- .requiredOption("--to <address>", "Recipient address")
108
- .requiredOption("--payload <json>", "JSON payload string")
109
- .requiredOption("--relay <url>", "Relay server URL")
110
- .option("--json", "Machine-parseable output")
111
- .action(async (opts) => {
112
- let payload: unknown;
113
- try {
114
- payload = JSON.parse(opts.payload);
115
- } catch {
116
- console.error("Error: --payload must be valid JSON");
117
- process.exit(1);
118
- }
119
-
120
- const result = await relayRequest(opts.relay, "POST", "/send", {
121
- to: opts.to,
122
- payload,
123
- });
124
-
125
- if (result.status !== 200) {
126
- console.error(`Relay error (${result.status}): ${JSON.stringify(result.data)}`);
127
- process.exit(1);
128
- }
129
-
130
- if (opts.json) {
131
- console.log(JSON.stringify(result.data));
132
- } else {
133
- const d = result.data as { messageId?: string };
134
- console.log(' ' + c.success + c.white(' Sent — messageId: ' + d.messageId));
135
- }
136
- });
137
-
138
- // ── relay poll ──────────────────────────────────────────────────────────────
139
- relay
140
- .command("poll")
141
- .description("Poll for messages addressed to an address")
142
- .requiredOption("--address <address>", "Address to poll for")
143
- .requiredOption("--relay <url>", "Relay server URL")
144
- .option("--since <messageId>", "Only return messages after this messageId")
145
- .option("--json", "Machine-parseable output")
146
- .action(async (opts) => {
147
- const qs = `?address=${encodeURIComponent(opts.address)}` +
148
- (opts.since ? `&since=${encodeURIComponent(opts.since)}` : "");
149
-
150
- const result = await relayRequest(opts.relay, "GET", `/poll${qs}`);
151
-
152
- if (result.status !== 200) {
153
- console.error(`Relay error (${result.status}): ${JSON.stringify(result.data)}`);
154
- process.exit(1);
155
- }
156
-
157
- const data = result.data as { messages?: unknown[] };
158
- const messages = data.messages || [];
159
-
160
- if (opts.json) {
161
- console.log(JSON.stringify(data));
162
- return;
163
- }
164
-
165
- if (messages.length === 0) {
166
- console.log(' ' + c.dim('No messages.'));
167
- return;
168
- }
169
-
170
- for (const msg of messages as Array<{ messageId: string; from: string; timestamp: number }>) {
171
- const ts = new Date(msg.timestamp).toISOString();
172
- console.log(`[${ts}] ${msg.messageId.slice(0, 12)}... from=${msg.from}`);
173
- }
174
- });
175
-
176
- // ── relay daemon ────────────────────────────────────────────────────────────
177
- const daemon = relay
178
- .command("daemon")
179
- .description("Persistent relay polling daemon");
180
-
181
- daemon
182
- .command("start")
183
- .description("Start the relay daemon in the background")
184
- .requiredOption("--relay <url>", "Relay server URL")
185
- .requiredOption("--address <address>", "Address to poll for messages")
186
- .requiredOption("--poll-interval <ms>", "Polling interval in milliseconds", "2000")
187
- .requiredOption("--on-message <script>", "Script to invoke for each incoming message (receives JSON on stdin)")
188
- .option("--json", "Machine-parseable output")
189
- .action((opts) => {
190
- // Check if already running
191
- if (fs.existsSync(PID_FILE)) {
192
- try {
193
- const existingPid = parseInt(fs.readFileSync(PID_FILE, "utf8").trim(), 10);
194
- process.kill(existingPid, 0); // Check if alive
195
- console.error(`Daemon already running (PID ${existingPid}). Run 'arc402 relay daemon stop' first.`);
196
- process.exit(1);
197
- } catch {
198
- // PID file is stale — clean it up
199
- fs.unlinkSync(PID_FILE);
200
- }
201
- }
202
-
203
- // Spawn a detached child process
204
- const child = spawn(process.execPath, [__filename], {
205
- detached: true,
206
- stdio: "ignore",
207
- env: {
208
- ...process.env,
209
- ARC402_RELAY_DAEMON: "1",
210
- ARC402_RELAY_URL: opts.relay,
211
- ARC402_RELAY_ADDRESS: opts.address,
212
- ARC402_RELAY_INTERVAL: opts.pollInterval,
213
- ARC402_RELAY_HANDLER: opts.onMessage,
214
- },
215
- });
216
- child.unref();
217
-
218
- fs.mkdirSync(path.dirname(PID_FILE), { recursive: true });
219
- fs.writeFileSync(PID_FILE, String(child.pid), { mode: 0o600 });
220
-
221
- if (opts.json) {
222
- console.log(JSON.stringify({ started: true, pid: child.pid, pidFile: PID_FILE }));
223
- } else {
224
- console.log(' ' + c.success + c.white(' Daemon started (PID ' + child.pid + ')'));
225
- }
226
- });
227
-
228
- daemon
229
- .command("stop")
230
- .description("Stop the relay daemon")
231
- .option("--json", "Machine-parseable output")
232
- .action((opts) => {
233
- if (!fs.existsSync(PID_FILE)) {
234
- if (opts.json) {
235
- console.log(JSON.stringify({ stopped: false, reason: "no pid file" }));
236
- } else {
237
- console.log(' ' + c.dim('No running daemon found.'));
238
- }
239
- return;
240
- }
241
-
242
- const pid = parseInt(fs.readFileSync(PID_FILE, "utf8").trim(), 10);
243
- try {
244
- process.kill(pid, "SIGTERM");
245
- fs.unlinkSync(PID_FILE);
246
- if (opts.json) {
247
- console.log(JSON.stringify({ stopped: true, pid }));
248
- } else {
249
- console.log(' ' + c.success + c.white(' Daemon stopped (PID ' + pid + ')'));
250
- }
251
- } catch (err: unknown) {
252
- const msg = err instanceof Error ? err.message : String(err);
253
- if (opts.json) {
254
- console.log(JSON.stringify({ stopped: false, pid, error: msg }));
255
- } else {
256
- console.error(`Failed to stop daemon: ${msg}`);
257
- // Clean up stale PID file
258
- fs.unlinkSync(PID_FILE);
259
- }
260
- }
261
- });
262
- }
263
-
264
- // ─── Daemon entry point ───────────────────────────────────────────────────────
265
- // When spawned as a background process via daemon start
266
-
267
- if (process.env.ARC402_RELAY_DAEMON === "1") {
268
- runDaemonLoop({
269
- relayUrl: process.env.ARC402_RELAY_URL || "",
270
- address: process.env.ARC402_RELAY_ADDRESS || "",
271
- pollInterval: parseInt(process.env.ARC402_RELAY_INTERVAL || "2000", 10),
272
- onMessage: process.env.ARC402_RELAY_HANDLER || "echo",
273
- }).catch((err) => {
274
- process.stderr.write(`Daemon error: ${err}\n`);
275
- process.exit(1);
276
- });
277
- }
@@ -1,24 +0,0 @@
1
- import { Command } from "commander";
2
- import { ProviderResponseType, ServiceAgreementClient } from "@arc402/sdk";
3
- import { loadConfig } from "../config.js";
4
- import { getClient, requireSigner } from "../client.js";
5
- import { hashFile, hashString } from "../utils/hash.js";
6
- import { c } from '../ui/colors.js';
7
- import { startSpinner } from '../ui/spinner.js';
8
-
9
- export function registerRemediateCommands(program: Command): void {
10
- const remediate = program.command("remediate").description("Negotiated remediation before formal dispute");
11
- remediate.command("request <id>").requiredOption("--text <feedback>").option("--uri <uri>", "Structured feedback URI", "").option("--file <path>").option("--previous <hash>", "Previous transcript hash", "0x0000000000000000000000000000000000000000000000000000000000000000").action(async (id, opts) => {
12
- const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { signer } = await requireSigner(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
13
- const hash = opts.file ? hashFile(opts.file) : hashString(opts.text); await client.requestRevision(BigInt(id), hash, opts.uri, opts.previous); console.log(' ' + c.success + c.white(' Revision requested — agreement #' + id));
14
- });
15
- remediate.command("respond <id>").requiredOption("--type <type>", "revise|defend|counter|partial-settlement|human-review|escalate").requiredOption("--text <response>").option("--uri <uri>", "Structured response URI", "").option("--file <path>").option("--previous <hash>", "Previous transcript hash", "0x0000000000000000000000000000000000000000000000000000000000000000").option("--provider-payout <amount>", "Wei/token units for partial settlement", "0").action(async (id, opts) => {
16
- const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { signer } = await requireSigner(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
17
- const map: Record<string, ProviderResponseType> = { revise: ProviderResponseType.REVISE, defend: ProviderResponseType.DEFEND, counter: ProviderResponseType.COUNTER, 'partial-settlement': ProviderResponseType.PARTIAL_SETTLEMENT, 'human-review': ProviderResponseType.REQUEST_HUMAN_REVIEW, escalate: ProviderResponseType.ESCALATE };
18
- const hash = opts.file ? hashFile(opts.file) : hashString(opts.text); await client.respondToRevision(BigInt(id), map[String(opts.type)], hash, opts.uri, opts.previous, BigInt(opts.providerPayout)); console.log(' ' + c.success + c.white(' Response recorded — agreement #' + id));
19
- });
20
- remediate.command("status <id>").option("--json").action(async (id, opts) => {
21
- const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { provider } = await getClient(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, provider);
22
- const remediation = await client.getRemediationCase(BigInt(id)); const out = { remediation }; console.log(JSON.stringify(out, (_k, value) => typeof value === 'bigint' ? value.toString() : value, opts.json ? 2 : 2));
23
- });
24
- }