arc402-cli 1.0.0-rc.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) 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 +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/wallet.d.ts.map +1 -1
  28. package/dist/commands/wallet.js +299 -65
  29. package/dist/commands/wallet.js.map +1 -1
  30. package/dist/commands/watch.d.ts.map +1 -1
  31. package/dist/commands/watch.js +146 -9
  32. package/dist/commands/watch.js.map +1 -1
  33. package/dist/commands/workroom.d.ts.map +1 -1
  34. package/dist/commands/workroom.js +112 -6
  35. package/dist/commands/workroom.js.map +1 -1
  36. package/dist/config.d.ts +12 -0
  37. package/dist/config.d.ts.map +1 -1
  38. package/dist/config.js +41 -4
  39. package/dist/config.js.map +1 -1
  40. package/dist/daemon/compute-metering.d.ts +61 -0
  41. package/dist/daemon/compute-metering.d.ts.map +1 -0
  42. package/dist/daemon/compute-metering.js +299 -0
  43. package/dist/daemon/compute-metering.js.map +1 -0
  44. package/dist/daemon/compute-session.d.ts +100 -0
  45. package/dist/daemon/compute-session.d.ts.map +1 -0
  46. package/dist/daemon/compute-session.js +231 -0
  47. package/dist/daemon/compute-session.js.map +1 -0
  48. package/dist/daemon/config.d.ts +33 -1
  49. package/dist/daemon/config.d.ts.map +1 -1
  50. package/dist/daemon/config.js +69 -0
  51. package/dist/daemon/config.js.map +1 -1
  52. package/dist/daemon/credentials.d.ts +24 -0
  53. package/dist/daemon/credentials.d.ts.map +1 -0
  54. package/dist/daemon/credentials.js +80 -0
  55. package/dist/daemon/credentials.js.map +1 -0
  56. package/dist/daemon/delivery-client.d.ts +35 -0
  57. package/dist/daemon/delivery-client.d.ts.map +1 -0
  58. package/dist/daemon/delivery-client.js +231 -0
  59. package/dist/daemon/delivery-client.js.map +1 -0
  60. package/dist/daemon/file-delivery.d.ts +98 -0
  61. package/dist/daemon/file-delivery.d.ts.map +1 -0
  62. package/dist/daemon/file-delivery.js +461 -0
  63. package/dist/daemon/file-delivery.js.map +1 -0
  64. package/dist/daemon/index.d.ts +1 -0
  65. package/dist/daemon/index.d.ts.map +1 -1
  66. package/dist/daemon/index.js +793 -227
  67. package/dist/daemon/index.js.map +1 -1
  68. package/dist/daemon/notify.d.ts +35 -6
  69. package/dist/daemon/notify.d.ts.map +1 -1
  70. package/dist/daemon/notify.js +176 -48
  71. package/dist/daemon/notify.js.map +1 -1
  72. package/dist/daemon/worker-executor.d.ts +71 -0
  73. package/dist/daemon/worker-executor.d.ts.map +1 -0
  74. package/dist/daemon/worker-executor.js +382 -0
  75. package/dist/daemon/worker-executor.js.map +1 -0
  76. package/dist/drain-v4.js +2 -2
  77. package/dist/drain-v4.js.map +1 -1
  78. package/dist/endpoint-notify.d.ts +9 -1
  79. package/dist/endpoint-notify.d.ts.map +1 -1
  80. package/dist/endpoint-notify.js +116 -3
  81. package/dist/endpoint-notify.js.map +1 -1
  82. package/dist/index.js +81 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/program.d.ts.map +1 -1
  85. package/dist/program.js +6 -0
  86. package/dist/program.js.map +1 -1
  87. package/dist/repl.d.ts.map +1 -1
  88. package/dist/repl.js +69 -486
  89. package/dist/repl.js.map +1 -1
  90. package/dist/tui/App.d.ts +12 -0
  91. package/dist/tui/App.d.ts.map +1 -0
  92. package/dist/tui/App.js +154 -0
  93. package/dist/tui/App.js.map +1 -0
  94. package/dist/tui/Footer.d.ts +11 -0
  95. package/dist/tui/Footer.d.ts.map +1 -0
  96. package/dist/tui/Footer.js +13 -0
  97. package/dist/tui/Footer.js.map +1 -0
  98. package/dist/tui/Header.d.ts +14 -0
  99. package/dist/tui/Header.d.ts.map +1 -0
  100. package/dist/tui/Header.js +19 -0
  101. package/dist/tui/Header.js.map +1 -0
  102. package/dist/tui/InputLine.d.ts +11 -0
  103. package/dist/tui/InputLine.d.ts.map +1 -0
  104. package/dist/tui/InputLine.js +145 -0
  105. package/dist/tui/InputLine.js.map +1 -0
  106. package/dist/tui/Viewport.d.ts +14 -0
  107. package/dist/tui/Viewport.d.ts.map +1 -0
  108. package/dist/tui/Viewport.js +48 -0
  109. package/dist/tui/Viewport.js.map +1 -0
  110. package/dist/tui/WalletConnectPairing.d.ts +23 -0
  111. package/dist/tui/WalletConnectPairing.d.ts.map +1 -0
  112. package/dist/tui/WalletConnectPairing.js +61 -0
  113. package/dist/tui/WalletConnectPairing.js.map +1 -0
  114. package/dist/tui/components/Button.d.ts +7 -0
  115. package/dist/tui/components/Button.d.ts.map +1 -0
  116. package/dist/tui/components/Button.js +21 -0
  117. package/dist/tui/components/Button.js.map +1 -0
  118. package/dist/tui/components/CeremonyView.d.ts +13 -0
  119. package/dist/tui/components/CeremonyView.d.ts.map +1 -0
  120. package/dist/tui/components/CeremonyView.js +10 -0
  121. package/dist/tui/components/CeremonyView.js.map +1 -0
  122. package/dist/tui/components/CompletionDropdown.d.ts +7 -0
  123. package/dist/tui/components/CompletionDropdown.d.ts.map +1 -0
  124. package/dist/tui/components/CompletionDropdown.js +23 -0
  125. package/dist/tui/components/CompletionDropdown.js.map +1 -0
  126. package/dist/tui/components/ConfirmPrompt.d.ts +9 -0
  127. package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
  128. package/dist/tui/components/ConfirmPrompt.js +10 -0
  129. package/dist/tui/components/ConfirmPrompt.js.map +1 -0
  130. package/dist/tui/components/CustomTextInput.d.ts +15 -0
  131. package/dist/tui/components/CustomTextInput.d.ts.map +1 -0
  132. package/dist/tui/components/CustomTextInput.js +99 -0
  133. package/dist/tui/components/CustomTextInput.js.map +1 -0
  134. package/dist/tui/components/InteractiveTable.d.ts +14 -0
  135. package/dist/tui/components/InteractiveTable.d.ts.map +1 -0
  136. package/dist/tui/components/InteractiveTable.js +61 -0
  137. package/dist/tui/components/InteractiveTable.js.map +1 -0
  138. package/dist/tui/components/StepSpinner.d.ts +11 -0
  139. package/dist/tui/components/StepSpinner.d.ts.map +1 -0
  140. package/dist/tui/components/StepSpinner.js +32 -0
  141. package/dist/tui/components/StepSpinner.js.map +1 -0
  142. package/dist/tui/components/Toast.d.ts +18 -0
  143. package/dist/tui/components/Toast.d.ts.map +1 -0
  144. package/dist/tui/components/Toast.js +29 -0
  145. package/dist/tui/components/Toast.js.map +1 -0
  146. package/dist/tui/index.d.ts +2 -0
  147. package/dist/tui/index.d.ts.map +1 -0
  148. package/dist/tui/index.js +55 -0
  149. package/dist/tui/index.js.map +1 -0
  150. package/dist/tui/useChat.d.ts +11 -0
  151. package/dist/tui/useChat.d.ts.map +1 -0
  152. package/dist/tui/useChat.js +91 -0
  153. package/dist/tui/useChat.js.map +1 -0
  154. package/dist/tui/useCommand.d.ts +12 -0
  155. package/dist/tui/useCommand.d.ts.map +1 -0
  156. package/dist/tui/useCommand.js +137 -0
  157. package/dist/tui/useCommand.js.map +1 -0
  158. package/dist/tui/useNotifications.d.ts +9 -0
  159. package/dist/tui/useNotifications.d.ts.map +1 -0
  160. package/dist/tui/useNotifications.js +17 -0
  161. package/dist/tui/useNotifications.js.map +1 -0
  162. package/dist/tui/useScroll.d.ts +17 -0
  163. package/dist/tui/useScroll.d.ts.map +1 -0
  164. package/dist/tui/useScroll.js +46 -0
  165. package/dist/tui/useScroll.js.map +1 -0
  166. package/dist/ui/format.d.ts.map +1 -1
  167. package/dist/ui/format.js +2 -0
  168. package/dist/ui/format.js.map +1 -1
  169. package/dist/ui/qr-render.d.ts +25 -0
  170. package/dist/ui/qr-render.d.ts.map +1 -0
  171. package/dist/ui/qr-render.js +90 -0
  172. package/dist/ui/qr-render.js.map +1 -0
  173. package/dist/ui/rpc-fallback.d.ts +11 -0
  174. package/dist/ui/rpc-fallback.d.ts.map +1 -0
  175. package/dist/ui/rpc-fallback.js +58 -0
  176. package/dist/ui/rpc-fallback.js.map +1 -0
  177. package/dist/walletconnect.d.ts +4 -0
  178. package/dist/walletconnect.d.ts.map +1 -1
  179. package/dist/walletconnect.js.map +1 -1
  180. package/package.json +10 -2
  181. package/scripts/authorize-machine-key.ts +0 -43
  182. package/scripts/drain-wallet.ts +0 -149
  183. package/scripts/execute-spend-only.ts +0 -81
  184. package/scripts/register-agent-userop.ts +0 -186
  185. package/src/abis.ts +0 -187
  186. package/src/bundler.ts +0 -235
  187. package/src/client.ts +0 -36
  188. package/src/coinbase-smart-wallet.ts +0 -51
  189. package/src/commands/accept.ts +0 -64
  190. package/src/commands/agent-handshake.ts +0 -72
  191. package/src/commands/agent.ts +0 -691
  192. package/src/commands/agreements.ts +0 -350
  193. package/src/commands/arbitrator.ts +0 -180
  194. package/src/commands/arena-handshake.ts +0 -257
  195. package/src/commands/arena.ts +0 -122
  196. package/src/commands/cancel.ts +0 -35
  197. package/src/commands/channel.ts +0 -218
  198. package/src/commands/coldstart.ts +0 -165
  199. package/src/commands/config.ts +0 -58
  200. package/src/commands/contract-interaction.ts +0 -166
  201. package/src/commands/daemon.ts +0 -978
  202. package/src/commands/deliver.ts +0 -148
  203. package/src/commands/discover.ts +0 -297
  204. package/src/commands/dispute.ts +0 -375
  205. package/src/commands/endpoint.ts +0 -620
  206. package/src/commands/feed.ts +0 -229
  207. package/src/commands/hire.ts +0 -245
  208. package/src/commands/migrate.ts +0 -177
  209. package/src/commands/negotiate.ts +0 -271
  210. package/src/commands/openshell.ts +0 -1055
  211. package/src/commands/owner.ts +0 -35
  212. package/src/commands/policy.ts +0 -263
  213. package/src/commands/relay.ts +0 -273
  214. package/src/commands/remediate.ts +0 -24
  215. package/src/commands/reputation.ts +0 -79
  216. package/src/commands/setup.ts +0 -343
  217. package/src/commands/trust.ts +0 -27
  218. package/src/commands/verify.ts +0 -91
  219. package/src/commands/wallet.ts +0 -3280
  220. package/src/commands/watch.ts +0 -23
  221. package/src/commands/watchtower.ts +0 -248
  222. package/src/commands/workroom.ts +0 -959
  223. package/src/config.ts +0 -174
  224. package/src/daemon/config.ts +0 -308
  225. package/src/daemon/hire-listener.ts +0 -226
  226. package/src/daemon/index.ts +0 -955
  227. package/src/daemon/job-lifecycle.ts +0 -215
  228. package/src/daemon/notify.ts +0 -157
  229. package/src/daemon/token-metering.ts +0 -183
  230. package/src/daemon/userops.ts +0 -119
  231. package/src/daemon/wallet-monitor.ts +0 -90
  232. package/src/drain-v4.ts +0 -159
  233. package/src/endpoint-config.ts +0 -83
  234. package/src/endpoint-notify.ts +0 -46
  235. package/src/index.ts +0 -26
  236. package/src/openshell-runtime.ts +0 -277
  237. package/src/program.ts +0 -83
  238. package/src/repl.ts +0 -680
  239. package/src/signing.ts +0 -28
  240. package/src/telegram-notify.ts +0 -88
  241. package/src/ui/banner.ts +0 -51
  242. package/src/ui/colors.ts +0 -30
  243. package/src/ui/format.ts +0 -77
  244. package/src/ui/spinner.ts +0 -56
  245. package/src/ui/tree.ts +0 -16
  246. package/src/utils/format.ts +0 -48
  247. package/src/utils/hash.ts +0 -5
  248. package/src/utils/time.ts +0 -15
  249. package/src/wallet-router.ts +0 -178
  250. package/src/walletconnect-session.ts +0 -27
  251. package/src/walletconnect.ts +0 -294
  252. package/test/time.test.js +0 -11
  253. package/tsconfig.json +0 -19
@@ -1,375 +0,0 @@
1
- import { Command } from "commander";
2
- import { ethers } from "ethers";
3
- import prompts from "prompts";
4
- import { ArbitrationVote, DirectDisputeReason, DisputeClass, DisputeMode, DisputeOutcome, EvidenceType, ServiceAgreementClient, DisputeArbitrationClient } from "@arc402/sdk";
5
- import { loadConfig } from "../config";
6
- import { getClient, requireSigner } from "../client";
7
- import { hashFile, hashString } from "../utils/hash";
8
- import { printSenderInfo, executeContractWriteViaWallet } from "../wallet-router";
9
- import { SERVICE_AGREEMENT_ABI } from "../abis";
10
- import { c } from '../ui/colors';
11
- import { startSpinner } from '../ui/spinner';
12
-
13
- export function registerDisputeCommand(program: Command): void {
14
- const dispute = program.command("dispute").description("Formal dispute workflow; remediation-first by default, with narrow hard-fail direct-dispute exceptions");
15
-
16
- // Fee quote (requires DisputeArbitration configured) — read-only, no wallet routing needed
17
- dispute.command("fee-quote <agreementId>")
18
- .description("Get dispute fee quote for an agreement")
19
- .requiredOption("--price <price>", "Agreement price in wei/token units")
20
- .requiredOption("--token <token>", "Token address (0x0 for ETH)")
21
- .requiredOption("--mode <mode>", "unilateral|mutual")
22
- .requiredOption("--class <class>", "hard-failure|ambiguity|high-sensitivity")
23
- .action(async (agreementId, opts) => {
24
- const config = loadConfig();
25
- if (!config.disputeArbitrationAddress) throw new Error("disputeArbitrationAddress missing in config");
26
- const { provider } = await getClient(config);
27
- const client = new DisputeArbitrationClient(config.disputeArbitrationAddress, provider);
28
- const modeMap: Record<string, DisputeMode> = { unilateral: DisputeMode.UNILATERAL, mutual: DisputeMode.MUTUAL };
29
- const classMap: Record<string, DisputeClass> = {
30
- 'hard-failure': DisputeClass.HARD_FAILURE,
31
- 'ambiguity': DisputeClass.AMBIGUITY_QUALITY,
32
- 'high-sensitivity': DisputeClass.HIGH_SENSITIVITY,
33
- };
34
- const mode = modeMap[String(opts.mode).toLowerCase()];
35
- const disputeClass = classMap[String(opts.class).toLowerCase()];
36
- if (!mode || !disputeClass) throw new Error("Invalid --mode or --class");
37
- const feeInTokens = await client.getFeeQuote(BigInt(opts.price), opts.token, mode, disputeClass);
38
- console.log(' ' + c.mark + c.white(` Fee quote — agreement #${agreementId}: ${feeInTokens.toString()} tokens`));
39
- });
40
-
41
- // Open with explicit mode/class
42
- dispute.command("open-with-mode <agreementId>")
43
- .description("Open dispute with specific mode and class (requires fee in msg.value for ETH)")
44
- .requiredOption("--mode <mode>", "unilateral|mutual")
45
- .requiredOption("--class <class>", "hard-failure|ambiguity|high-sensitivity")
46
- .requiredOption("--reason <reason>")
47
- .option("--fee <fee>", "Fee in wei (for ETH agreements)", "0")
48
- .action(async (agreementId, opts) => {
49
- const config = loadConfig();
50
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
51
- const { signer } = await requireSigner(config);
52
- const modeMap: Record<string, DisputeMode> = { unilateral: DisputeMode.UNILATERAL, mutual: DisputeMode.MUTUAL };
53
- const classMap: Record<string, DisputeClass> = {
54
- 'hard-failure': DisputeClass.HARD_FAILURE,
55
- 'ambiguity': DisputeClass.AMBIGUITY_QUALITY,
56
- 'high-sensitivity': DisputeClass.HIGH_SENSITIVITY,
57
- };
58
- const mode = modeMap[String(opts.mode).toLowerCase()];
59
- const disputeClass = classMap[String(opts.class).toLowerCase()];
60
- if (!mode || !disputeClass) throw new Error("Invalid --mode or --class");
61
- printSenderInfo(config);
62
- if (config.walletContractAddress) {
63
- await executeContractWriteViaWallet(
64
- config.walletContractAddress, signer, config.serviceAgreementAddress,
65
- SERVICE_AGREEMENT_ABI, "openDisputeWithMode",
66
- [BigInt(agreementId), mode, disputeClass, opts.reason],
67
- BigInt(opts.fee),
68
- );
69
- } else {
70
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
71
- await client.openDisputeWithMode(BigInt(agreementId), mode, disputeClass, opts.reason, BigInt(opts.fee));
72
- }
73
- console.log(' ' + c.success + c.white(` Dispute opened — agreement #${agreementId}`));
74
- });
75
-
76
- // Join mutual dispute (respondent pays their half) — DisputeArbitration contract, no wallet routing
77
- dispute.command("join <agreementId>")
78
- .description("Join a mutual dispute as respondent (pays half the fee)")
79
- .option("--fee <fee>", "Half-fee in wei (for ETH agreements)", "0")
80
- .action(async (agreementId, opts) => {
81
- const config = loadConfig();
82
- if (!config.disputeArbitrationAddress) throw new Error("disputeArbitrationAddress missing in config");
83
- const { signer } = await requireSigner(config);
84
- const client = new DisputeArbitrationClient(config.disputeArbitrationAddress, signer);
85
- await client.joinMutualDispute(BigInt(agreementId), BigInt(opts.fee));
86
- console.log(' ' + c.success + c.white(` Joined mutual dispute — agreement #${agreementId}`));
87
- });
88
-
89
- dispute.command("open <id>")
90
- .requiredOption("--reason <reason>")
91
- .option("--escalated", "Use escalateToDispute after remediation", false)
92
- .option("--direct <type>", "Direct-dispute hard-fail reason: no-delivery|deadline-breach|invalid-deliverable|safety-critical")
93
- .action(async (id, opts) => {
94
- const config = loadConfig();
95
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
96
-
97
- // Pre-flight: check disputeModule is configured (J4-01)
98
- {
99
- const { provider: dpProvider } = await getClient(config);
100
- const saCheck = new ethers.Contract(
101
- config.serviceAgreementAddress,
102
- ["function disputeModule() external view returns (address)"],
103
- dpProvider,
104
- );
105
- let disputeModuleAddr: string = ethers.ZeroAddress;
106
- try {
107
- disputeModuleAddr = await saCheck.disputeModule();
108
- } catch { /* assume not configured */ }
109
- if (disputeModuleAddr === ethers.ZeroAddress) {
110
- console.error(`No dispute module configured on this ServiceAgreement.`);
111
- console.error(`Disputes require a DisputeModule to be set by the SA owner.`);
112
- console.error(`This protocol deployment may not support formal disputes.`);
113
- process.exit(1);
114
- }
115
- }
116
-
117
- // Pre-flight: read dispute fee and prompt user (J4-02)
118
- if (config.disputeArbitrationAddress) {
119
- const { provider: feeProvider } = await getClient(config);
120
- const daCheck = new ethers.Contract(
121
- config.disputeArbitrationAddress,
122
- ["function getDisputeFee() external view returns (uint256)"],
123
- feeProvider,
124
- );
125
- let feeWei = 0n;
126
- try {
127
- feeWei = await daCheck.getDisputeFee();
128
- } catch { /* fee getter may not exist — assume 0 */ }
129
- if (feeWei > 0n) {
130
- const feeEth = ethers.formatEther(feeWei);
131
- console.log(`\nDispute fee: ${feeEth} ETH. This will be deducted from your wallet.`);
132
- const { proceed } = await prompts({
133
- type: "confirm",
134
- name: "proceed",
135
- message: "Continue?",
136
- initial: true,
137
- });
138
- if (!proceed) { console.log("Aborted."); process.exit(0); }
139
- }
140
- }
141
-
142
- const { signer } = await requireSigner(config);
143
- const directMap: Record<string, DirectDisputeReason> = {
144
- 'no-delivery': DirectDisputeReason.NO_DELIVERY,
145
- 'deadline-breach': DirectDisputeReason.HARD_DEADLINE_BREACH,
146
- 'invalid-deliverable': DirectDisputeReason.INVALID_OR_FRAUDULENT_DELIVERABLE,
147
- 'safety-critical': DirectDisputeReason.SAFETY_CRITICAL_VIOLATION,
148
- };
149
- if (opts.escalated && opts.direct) throw new Error('Choose either --escalated or --direct, not both');
150
- printSenderInfo(config);
151
- if (config.walletContractAddress) {
152
- if (opts.direct) {
153
- const directReason = directMap[String(opts.direct).toLowerCase()];
154
- if (directReason === undefined) throw new Error('Unsupported --direct reason');
155
- await executeContractWriteViaWallet(
156
- config.walletContractAddress, signer, config.serviceAgreementAddress,
157
- SERVICE_AGREEMENT_ABI, "directDispute", [BigInt(id), directReason, opts.reason],
158
- );
159
- } else if (opts.escalated) {
160
- await executeContractWriteViaWallet(
161
- config.walletContractAddress, signer, config.serviceAgreementAddress,
162
- SERVICE_AGREEMENT_ABI, "escalateToDispute", [BigInt(id), opts.reason],
163
- );
164
- } else {
165
- await executeContractWriteViaWallet(
166
- config.walletContractAddress, signer, config.serviceAgreementAddress,
167
- SERVICE_AGREEMENT_ABI, "dispute", [BigInt(id), opts.reason],
168
- );
169
- }
170
- } else {
171
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
172
- if (opts.direct) {
173
- const directReason = directMap[String(opts.direct).toLowerCase()];
174
- if (directReason === undefined) throw new Error('Unsupported --direct reason');
175
- await client.directDispute(BigInt(id), directReason, opts.reason);
176
- } else if (opts.escalated) {
177
- await client.escalateToDispute(BigInt(id), opts.reason);
178
- } else {
179
- await client.dispute(BigInt(id), opts.reason);
180
- }
181
- }
182
- console.log(' ' + c.success + c.white(` Dispute opened — agreement #${id}`));
183
-
184
- // J4-04: Display arbitration selection window deadline
185
- try {
186
- const { provider: dpAW } = await getClient(config);
187
- const saAW = new ethers.Contract(
188
- config.serviceAgreementAddress,
189
- ["function ARBITRATION_SELECTION_WINDOW() external view returns (uint256)"],
190
- dpAW,
191
- );
192
- const selectionWindow: bigint = await saAW.ARBITRATION_SELECTION_WINDOW();
193
- const deadlineDate = new Date(Date.now() + Number(selectionWindow) * 1000);
194
- console.log(`Arbitration selection window closes: ${deadlineDate.toLocaleString()}. An arbitrator must be assigned before then.`);
195
- } catch { /* not available on this deployment */ }
196
- });
197
-
198
- dispute.command("evidence <id>").requiredOption("--type <type>", "transcript|deliverable|acceptance|communication|external|other").option("--file <path>").option("--text <text>").option("--uri <uri>", "External evidence URI", "").action(async (id, opts) => {
199
- const config = loadConfig();
200
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
201
- const { signer } = await requireSigner(config);
202
- const mapping: Record<string, EvidenceType> = { transcript: EvidenceType.TRANSCRIPT, deliverable: EvidenceType.DELIVERABLE, acceptance: EvidenceType.ACCEPTANCE_CRITERIA, communication: EvidenceType.COMMUNICATION, external: EvidenceType.EXTERNAL_REFERENCE, other: EvidenceType.OTHER };
203
- const hash = opts.file ? hashFile(opts.file) : hashString(opts.text ?? opts.uri ?? `evidence:${id}`);
204
- const evidenceType = mapping[String(opts.type).toLowerCase()] ?? EvidenceType.OTHER;
205
- printSenderInfo(config);
206
- if (config.walletContractAddress) {
207
- await executeContractWriteViaWallet(
208
- config.walletContractAddress, signer, config.serviceAgreementAddress,
209
- SERVICE_AGREEMENT_ABI, "submitDisputeEvidence", [BigInt(id), evidenceType, hash, opts.uri],
210
- );
211
- } else {
212
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
213
- await client.submitDisputeEvidence(BigInt(id), evidenceType, hash, opts.uri);
214
- }
215
- console.log(' ' + c.success + c.white(` Evidence submitted — agreement #${id}`));
216
- });
217
-
218
- // status — read-only, no wallet routing needed
219
- dispute.command("status <id>").option("--json").action(async (id, opts) => {
220
- const config = loadConfig();
221
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
222
- const { provider } = await getClient(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, provider);
223
- const result = {
224
- case: await client.getDisputeCase(BigInt(id)),
225
- arbitration: await client.getArbitrationCase(BigInt(id)),
226
- evidence: await client.getDisputeEvidenceAll(BigInt(id)),
227
- };
228
- console.log(JSON.stringify(result, (_k, value) => typeof value === 'bigint' ? value.toString() : value, opts.json ? 2 : 2));
229
- });
230
-
231
- dispute.command("nominate <id>")
232
- .description("Nominate an arbitrator during the on-chain arbitration phase")
233
- .requiredOption("--arbitrator <address>")
234
- .action(async (id, opts) => {
235
- const config = loadConfig();
236
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
237
-
238
- // Pre-flight: check arbitrator is approved (J4-03)
239
- if (config.disputeArbitrationAddress) {
240
- const { provider: arbProvider } = await getClient(config);
241
- const daCheck = new ethers.Contract(
242
- config.disputeArbitrationAddress,
243
- ["function isApprovedArbitrator(address arbitrator) external view returns (bool)"],
244
- arbProvider,
245
- );
246
- let isApproved = true;
247
- try {
248
- isApproved = await daCheck.isApprovedArbitrator(opts.arbitrator);
249
- } catch { /* assume approved if read fails */ }
250
- if (!isApproved) {
251
- console.error(`Arbitrator ${opts.arbitrator} is not approved.`);
252
- console.error(`Use \`arc402 dispute list-arbitrators\` to see approved arbitrators.`);
253
- process.exit(1);
254
- }
255
- }
256
-
257
- const { signer } = await requireSigner(config);
258
- printSenderInfo(config);
259
- if (config.walletContractAddress) {
260
- await executeContractWriteViaWallet(
261
- config.walletContractAddress, signer, config.serviceAgreementAddress,
262
- SERVICE_AGREEMENT_ABI, "nominateArbitrator", [BigInt(id), opts.arbitrator],
263
- );
264
- } else {
265
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
266
- await client.nominateArbitrator(BigInt(id), opts.arbitrator);
267
- }
268
- console.log(' ' + c.success + c.white(` Arbitrator nominated — agreement #${id}`));
269
- });
270
-
271
- dispute.command("vote <id>")
272
- .description("Cast an arbitration vote on-chain")
273
- .requiredOption("--vote <vote>", "provider|refund|split|human-review")
274
- .option("--provider-award <amount>", "Wei/token units", "0")
275
- .option("--client-award <amount>", "Wei/token units", "0")
276
- .action(async (id, opts) => {
277
- const config = loadConfig();
278
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
279
- const { signer, address: voterAddress, provider: voteProvider } = await requireSigner(config);
280
-
281
- // J4-05: Pre-flight — verify caller is on the arbitration panel
282
- try {
283
- const saClient = new ServiceAgreementClient(config.serviceAgreementAddress, voteProvider);
284
- const arbCase = await saClient.getArbitrationCase(BigInt(id));
285
- const onPanel = arbCase.arbitrators.map((a: string) => a.toLowerCase()).includes(voterAddress.toLowerCase());
286
- if (!onPanel) {
287
- console.error(`You are not on the arbitration panel for agreement ${id}. Only assigned arbitrators can vote.`);
288
- process.exit(1);
289
- }
290
- } catch (e) {
291
- if ((e as NodeJS.ErrnoException)?.code === 'ERR_USE_AFTER_CLOSE' || String(e).includes('process.exit')) throw e;
292
- // If read fails, skip the check and let the transaction reveal the error
293
- }
294
-
295
- const mapping: Record<string, ArbitrationVote> = {
296
- provider: ArbitrationVote.PROVIDER_WINS,
297
- refund: ArbitrationVote.CLIENT_REFUND,
298
- split: ArbitrationVote.SPLIT,
299
- 'human-review': ArbitrationVote.HUMAN_REVIEW_REQUIRED,
300
- };
301
- const vote = mapping[String(opts.vote).toLowerCase()];
302
- if (vote === undefined) throw new Error('Unsupported --vote value');
303
- printSenderInfo(config);
304
- if (config.walletContractAddress) {
305
- await executeContractWriteViaWallet(
306
- config.walletContractAddress, signer, config.serviceAgreementAddress,
307
- SERVICE_AGREEMENT_ABI, "castArbitrationVote",
308
- [BigInt(id), vote, BigInt(opts.providerAward), BigInt(opts.clientAward)],
309
- );
310
- } else {
311
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
312
- await client.castArbitrationVote(BigInt(id), vote, BigInt(opts.providerAward), BigInt(opts.clientAward));
313
- }
314
- console.log(' ' + c.success + c.white(` Vote recorded — agreement #${id}`));
315
- });
316
-
317
- dispute.command("human <id>")
318
- .description("Request human escalation when arbitration stalls or requires human backstop")
319
- .requiredOption("--reason <reason>")
320
- .action(async (id, opts) => {
321
- const config = loadConfig();
322
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
323
- const { signer } = await requireSigner(config);
324
- printSenderInfo(config);
325
- if (config.walletContractAddress) {
326
- await executeContractWriteViaWallet(
327
- config.walletContractAddress, signer, config.serviceAgreementAddress,
328
- SERVICE_AGREEMENT_ABI, "requestHumanEscalation", [BigInt(id), opts.reason],
329
- );
330
- } else {
331
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
332
- await client.requestHumanEscalation(BigInt(id), opts.reason);
333
- }
334
- console.log(' ' + c.success + c.white(` Escalated to human — agreement #${id}`));
335
- });
336
-
337
- dispute.command("resolve <id>").description("Owner-only admin path if you are operating the dispute contract").requiredOption("--outcome <outcome>", "provider|refund|partial-provider|partial-client|mutual-cancel|human-review").option("--provider-award <amount>", "Wei/token units", "0").option("--client-award <amount>", "Wei/token units", "0").action(async (id, opts) => {
338
- const config = loadConfig();
339
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
340
- const { signer } = await requireSigner(config);
341
- const mapping: Record<string, DisputeOutcome> = { provider: DisputeOutcome.PROVIDER_WINS, refund: DisputeOutcome.CLIENT_REFUND, 'partial-provider': DisputeOutcome.PARTIAL_PROVIDER, 'partial-client': DisputeOutcome.PARTIAL_CLIENT, 'mutual-cancel': DisputeOutcome.MUTUAL_CANCEL, 'human-review': DisputeOutcome.HUMAN_REVIEW_REQUIRED };
342
- printSenderInfo(config);
343
- if (config.walletContractAddress) {
344
- await executeContractWriteViaWallet(
345
- config.walletContractAddress, signer, config.serviceAgreementAddress,
346
- SERVICE_AGREEMENT_ABI, "resolveDisputeDetailed",
347
- [BigInt(id), mapping[String(opts.outcome)], BigInt(opts.providerAward), BigInt(opts.clientAward)],
348
- );
349
- } else {
350
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
351
- await client.resolveDisputeDetailed(BigInt(id), mapping[String(opts.outcome)], BigInt(opts.providerAward), BigInt(opts.clientAward));
352
- }
353
- console.log(' ' + c.success + c.white(` Resolved — agreement #${id}`));
354
- });
355
-
356
- dispute.command("owner-resolve <agreementId>")
357
- .description("Owner-only: resolve a dispute directly in favor of provider or client. Requires DISPUTED or ESCALATED_TO_HUMAN status.")
358
- .option("--favor-provider", "Resolve in favor of the provider (default: false = favor client)", false)
359
- .action(async (agreementId, opts) => {
360
- const config = loadConfig();
361
- if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
362
- const { signer } = await requireSigner(config);
363
- printSenderInfo(config);
364
- if (config.walletContractAddress) {
365
- await executeContractWriteViaWallet(
366
- config.walletContractAddress, signer, config.serviceAgreementAddress,
367
- SERVICE_AGREEMENT_ABI, "ownerResolveDispute", [BigInt(agreementId), !!opts.favorProvider],
368
- );
369
- } else {
370
- const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
371
- await client.ownerResolveDispute(BigInt(agreementId), !!opts.favorProvider);
372
- }
373
- console.log(' ' + c.success + c.white(` Owner resolved — agreement #${agreementId}`));
374
- });
375
- }