@absol-labs/agent 0.11.0 → 0.12.0-rc.2

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 (366) hide show
  1. package/README.md +43 -51
  2. package/dist/capability/invocation-capability.d.ts +2 -2
  3. package/dist/capability/probe-capability.d.ts +225 -0
  4. package/dist/capability/probe-capability.d.ts.map +1 -0
  5. package/dist/capability/probe-capability.js +248 -0
  6. package/dist/capability/probe-capability.js.map +1 -0
  7. package/dist/cli/args.d.ts +11 -0
  8. package/dist/cli/args.d.ts.map +1 -1
  9. package/dist/cli/args.js +23 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/commands/claim.d.ts +32 -0
  12. package/dist/cli/commands/claim.d.ts.map +1 -1
  13. package/dist/cli/commands/claim.js +116 -28
  14. package/dist/cli/commands/claim.js.map +1 -1
  15. package/dist/cli/commands/close.d.ts.map +1 -1
  16. package/dist/cli/commands/close.js +35 -3
  17. package/dist/cli/commands/close.js.map +1 -1
  18. package/dist/cli/commands/invoke.d.ts +2 -0
  19. package/dist/cli/commands/invoke.d.ts.map +1 -1
  20. package/dist/cli/commands/invoke.js +2 -2
  21. package/dist/cli/commands/invoke.js.map +1 -1
  22. package/dist/cli/commands/mcp.d.ts.map +1 -1
  23. package/dist/cli/commands/mcp.js +15 -2
  24. package/dist/cli/commands/mcp.js.map +1 -1
  25. package/dist/cli/commands/open.d.ts.map +1 -1
  26. package/dist/cli/commands/open.js +58 -4
  27. package/dist/cli/commands/open.js.map +1 -1
  28. package/dist/cli/commands/pay.d.ts +34 -0
  29. package/dist/cli/commands/pay.d.ts.map +1 -0
  30. package/dist/cli/commands/pay.js +479 -0
  31. package/dist/cli/commands/pay.js.map +1 -0
  32. package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -1
  33. package/dist/cli/commands/reclaim-unverified.js +3 -2
  34. package/dist/cli/commands/reclaim-unverified.js.map +1 -1
  35. package/dist/cli/commands/reclaim.d.ts +23 -2
  36. package/dist/cli/commands/reclaim.d.ts.map +1 -1
  37. package/dist/cli/commands/reclaim.js +204 -20
  38. package/dist/cli/commands/reclaim.js.map +1 -1
  39. package/dist/cli/commands/refund.d.ts +31 -0
  40. package/dist/cli/commands/refund.d.ts.map +1 -0
  41. package/dist/cli/commands/refund.js +397 -0
  42. package/dist/cli/commands/refund.js.map +1 -0
  43. package/dist/cli/commands/status.d.ts.map +1 -1
  44. package/dist/cli/commands/status.js +21 -2
  45. package/dist/cli/commands/status.js.map +1 -1
  46. package/dist/cli/commands/streams.js +8 -12
  47. package/dist/cli/commands/streams.js.map +1 -1
  48. package/dist/cli/commands/watch.d.ts.map +1 -1
  49. package/dist/cli/commands/watch.js +4 -1
  50. package/dist/cli/commands/watch.js.map +1 -1
  51. package/dist/cli/config.d.ts +44 -26
  52. package/dist/cli/config.d.ts.map +1 -1
  53. package/dist/cli/config.js +88 -38
  54. package/dist/cli/config.js.map +1 -1
  55. package/dist/cli/context.d.ts +19 -0
  56. package/dist/cli/context.d.ts.map +1 -1
  57. package/dist/cli/deps.d.ts +53 -0
  58. package/dist/cli/deps.d.ts.map +1 -1
  59. package/dist/cli/deps.js +51 -1
  60. package/dist/cli/deps.js.map +1 -1
  61. package/dist/cli/errors.d.ts.map +1 -1
  62. package/dist/cli/errors.js +21 -1
  63. package/dist/cli/errors.js.map +1 -1
  64. package/dist/cli/escape-hatch.d.ts +6 -4
  65. package/dist/cli/escape-hatch.d.ts.map +1 -1
  66. package/dist/cli/escape-hatch.js +6 -2
  67. package/dist/cli/escape-hatch.js.map +1 -1
  68. package/dist/cli/listings.d.ts +18 -0
  69. package/dist/cli/listings.d.ts.map +1 -1
  70. package/dist/cli/listings.js +22 -12
  71. package/dist/cli/listings.js.map +1 -1
  72. package/dist/cli/preflight.d.ts +20 -14
  73. package/dist/cli/preflight.d.ts.map +1 -1
  74. package/dist/cli/preflight.js +34 -20
  75. package/dist/cli/preflight.js.map +1 -1
  76. package/dist/cli/privy.d.ts.map +1 -1
  77. package/dist/cli/privy.js +4 -2
  78. package/dist/cli/privy.js.map +1 -1
  79. package/dist/cli/progress.d.ts +13 -1
  80. package/dist/cli/progress.d.ts.map +1 -1
  81. package/dist/cli/progress.js +7 -1
  82. package/dist/cli/progress.js.map +1 -1
  83. package/dist/cli/reclaimability.d.ts +82 -0
  84. package/dist/cli/reclaimability.d.ts.map +1 -0
  85. package/dist/cli/reclaimability.js +80 -0
  86. package/dist/cli/reclaimability.js.map +1 -0
  87. package/dist/cli/run.d.ts +2 -1
  88. package/dist/cli/run.d.ts.map +1 -1
  89. package/dist/cli/run.js +62 -21
  90. package/dist/cli/run.js.map +1 -1
  91. package/dist/cli/scan-range.d.ts +2 -2
  92. package/dist/cli/scan-range.js +2 -2
  93. package/dist/cli/status.d.ts +106 -1
  94. package/dist/cli/status.d.ts.map +1 -1
  95. package/dist/cli/status.js +325 -44
  96. package/dist/cli/status.js.map +1 -1
  97. package/dist/cli/wallet.d.ts +2 -2
  98. package/dist/cli/wallet.d.ts.map +1 -1
  99. package/dist/cli/wallet.js +29 -5
  100. package/dist/cli/wallet.js.map +1 -1
  101. package/dist/discovery/rate-band.d.ts +74 -0
  102. package/dist/discovery/rate-band.d.ts.map +1 -0
  103. package/dist/discovery/rate-band.js +114 -0
  104. package/dist/discovery/rate-band.js.map +1 -0
  105. package/dist/escrow-generation.d.ts +81 -0
  106. package/dist/escrow-generation.d.ts.map +1 -0
  107. package/dist/escrow-generation.js +76 -0
  108. package/dist/escrow-generation.js.map +1 -0
  109. package/dist/frameworks/agentkit.d.ts +8 -4
  110. package/dist/frameworks/agentkit.d.ts.map +1 -1
  111. package/dist/frameworks/agentkit.js +27 -10
  112. package/dist/frameworks/agentkit.js.map +1 -1
  113. package/dist/frameworks/eliza.d.ts +3 -3
  114. package/dist/frameworks/eliza.d.ts.map +1 -1
  115. package/dist/frameworks/eliza.js +15 -6
  116. package/dist/frameworks/eliza.js.map +1 -1
  117. package/dist/frameworks/langchain.d.ts.map +1 -1
  118. package/dist/frameworks/langchain.js +8 -0
  119. package/dist/frameworks/langchain.js.map +1 -1
  120. package/dist/gateway/caller-auth-gateway.d.ts +83 -31
  121. package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
  122. package/dist/gateway/caller-auth-gateway.js +180 -27
  123. package/dist/gateway/caller-auth-gateway.js.map +1 -1
  124. package/dist/gateway/http-server.d.ts +128 -44
  125. package/dist/gateway/http-server.d.ts.map +1 -1
  126. package/dist/gateway/http-server.js +506 -155
  127. package/dist/gateway/http-server.js.map +1 -1
  128. package/dist/gateway/probe-auth.d.ts +112 -0
  129. package/dist/gateway/probe-auth.d.ts.map +1 -0
  130. package/dist/gateway/probe-auth.js +127 -0
  131. package/dist/gateway/probe-auth.js.map +1 -0
  132. package/dist/gateway/signed-rate-bounds.d.ts +51 -0
  133. package/dist/gateway/signed-rate-bounds.d.ts.map +1 -0
  134. package/dist/gateway/signed-rate-bounds.js +94 -0
  135. package/dist/gateway/signed-rate-bounds.js.map +1 -0
  136. package/dist/gateway/x402-opener-mode.d.ts +252 -0
  137. package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
  138. package/dist/gateway/x402-opener-mode.js +772 -0
  139. package/dist/gateway/x402-opener-mode.js.map +1 -0
  140. package/dist/index.d.ts +6 -2
  141. package/dist/index.d.ts.map +1 -1
  142. package/dist/index.js +10 -5
  143. package/dist/index.js.map +1 -1
  144. package/dist/mcp/server.d.ts +64 -1
  145. package/dist/mcp/server.d.ts.map +1 -1
  146. package/dist/mcp/server.js +247 -37
  147. package/dist/mcp/server.js.map +1 -1
  148. package/dist/mcp/x402-tools.d.ts +109 -0
  149. package/dist/mcp/x402-tools.d.ts.map +1 -0
  150. package/dist/mcp/x402-tools.js +554 -0
  151. package/dist/mcp/x402-tools.js.map +1 -0
  152. package/dist/network.d.ts +119 -0
  153. package/dist/network.d.ts.map +1 -0
  154. package/dist/network.js +199 -0
  155. package/dist/network.js.map +1 -0
  156. package/dist/sdk/client.d.ts +13 -0
  157. package/dist/sdk/client.d.ts.map +1 -1
  158. package/dist/sdk/client.js +15 -0
  159. package/dist/sdk/client.js.map +1 -1
  160. package/dist/sdk/invoke.d.ts +4 -0
  161. package/dist/sdk/invoke.d.ts.map +1 -1
  162. package/dist/sdk/invoke.js +2 -5
  163. package/dist/sdk/invoke.js.map +1 -1
  164. package/dist/wallet/autonomous-wallet-broker.d.ts +3 -0
  165. package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -1
  166. package/dist/wallet/autonomous-wallet-broker.js +27 -23
  167. package/dist/wallet/autonomous-wallet-broker.js.map +1 -1
  168. package/dist/wallet/autonomous-wallet-protocol.d.ts +8 -2
  169. package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -1
  170. package/dist/wallet/autonomous-wallet-protocol.js +9 -2
  171. package/dist/wallet/autonomous-wallet-protocol.js.map +1 -1
  172. package/dist/wallet/autonomous-wallet.d.ts.map +1 -1
  173. package/dist/wallet/autonomous-wallet.js +3 -2
  174. package/dist/wallet/autonomous-wallet.js.map +1 -1
  175. package/dist/wallet/broker-escrows.d.ts +222 -0
  176. package/dist/wallet/broker-escrows.d.ts.map +1 -0
  177. package/dist/wallet/broker-escrows.js +36 -0
  178. package/dist/wallet/broker-escrows.js.map +1 -0
  179. package/dist/wallet/lifecycle.d.ts +21 -5
  180. package/dist/wallet/lifecycle.d.ts.map +1 -1
  181. package/dist/wallet/lifecycle.js +32 -12
  182. package/dist/wallet/lifecycle.js.map +1 -1
  183. package/dist/wallet/privy-broker-server.d.ts.map +1 -1
  184. package/dist/wallet/privy-broker-server.js +31 -26
  185. package/dist/wallet/privy-broker-server.js.map +1 -1
  186. package/dist/wallet/privy-session-broker.d.ts +14 -5
  187. package/dist/wallet/privy-session-broker.d.ts.map +1 -1
  188. package/dist/wallet/privy-session-broker.js +29 -17
  189. package/dist/wallet/privy-session-broker.js.map +1 -1
  190. package/dist/wallet/privy-session-provider.d.ts +3 -1
  191. package/dist/wallet/privy-session-provider.d.ts.map +1 -1
  192. package/dist/wallet/privy-session-provider.js +5 -3
  193. package/dist/wallet/privy-session-provider.js.map +1 -1
  194. package/dist/wallet/provider.d.ts.map +1 -1
  195. package/dist/wallet/provider.js +15 -8
  196. package/dist/wallet/provider.js.map +1 -1
  197. package/dist/x402/facilitator.d.ts +3 -30
  198. package/dist/x402/facilitator.d.ts.map +1 -1
  199. package/dist/x402/facilitator.js +0 -27
  200. package/dist/x402/facilitator.js.map +1 -1
  201. package/dist/x402-buyer/guarded-fetch.d.ts +51 -0
  202. package/dist/x402-buyer/guarded-fetch.d.ts.map +1 -0
  203. package/dist/x402-buyer/guarded-fetch.js +147 -0
  204. package/dist/x402-buyer/guarded-fetch.js.map +1 -0
  205. package/dist/x402-buyer/index.d.ts +10 -0
  206. package/dist/x402-buyer/index.d.ts.map +1 -0
  207. package/dist/x402-buyer/index.js +10 -0
  208. package/dist/x402-buyer/index.js.map +1 -0
  209. package/dist/x402-buyer/pay.d.ts +157 -0
  210. package/dist/x402-buyer/pay.d.ts.map +1 -0
  211. package/dist/x402-buyer/pay.js +366 -0
  212. package/dist/x402-buyer/pay.js.map +1 -0
  213. package/dist/x402-opener/abi.d.ts +684 -0
  214. package/dist/x402-opener/abi.d.ts.map +1 -0
  215. package/dist/x402-opener/abi.js +880 -0
  216. package/dist/x402-opener/abi.js.map +1 -0
  217. package/dist/x402-opener/facilitator-entry.d.ts +3 -0
  218. package/dist/x402-opener/facilitator-entry.d.ts.map +1 -0
  219. package/dist/x402-opener/facilitator-entry.js +40 -0
  220. package/dist/x402-opener/facilitator-entry.js.map +1 -0
  221. package/dist/x402-opener/facilitator-server.d.ts +209 -0
  222. package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
  223. package/dist/x402-opener/facilitator-server.js +762 -0
  224. package/dist/x402-opener/facilitator-server.js.map +1 -0
  225. package/dist/x402-opener/index.d.ts +14 -0
  226. package/dist/x402-opener/index.d.ts.map +1 -0
  227. package/dist/x402-opener/index.js +14 -0
  228. package/dist/x402-opener/index.js.map +1 -0
  229. package/dist/x402-opener/listing-resolver.d.ts +55 -0
  230. package/dist/x402-opener/listing-resolver.d.ts.map +1 -0
  231. package/dist/x402-opener/listing-resolver.js +125 -0
  232. package/dist/x402-opener/listing-resolver.js.map +1 -0
  233. package/dist/x402-opener/refund-relay.d.ts +266 -0
  234. package/dist/x402-opener/refund-relay.d.ts.map +1 -0
  235. package/dist/x402-opener/refund-relay.js +1341 -0
  236. package/dist/x402-opener/refund-relay.js.map +1 -0
  237. package/dist/x402-opener/relayer-queue.d.ts +14 -0
  238. package/dist/x402-opener/relayer-queue.d.ts.map +1 -0
  239. package/dist/x402-opener/relayer-queue.js +18 -0
  240. package/dist/x402-opener/relayer-queue.js.map +1 -0
  241. package/dist/x402-opener/scheme.d.ts +296 -0
  242. package/dist/x402-opener/scheme.d.ts.map +1 -0
  243. package/dist/x402-opener/scheme.js +1035 -0
  244. package/dist/x402-opener/scheme.js.map +1 -0
  245. package/dist/x402-opener/terms.d.ts +165 -0
  246. package/dist/x402-opener/terms.d.ts.map +1 -0
  247. package/dist/x402-opener/terms.js +304 -0
  248. package/dist/x402-opener/terms.js.map +1 -0
  249. package/dist/zktls/reclaim.d.ts +2 -2
  250. package/dist/zktls/t2-delivery-proof.d.ts +6 -6
  251. package/docs/agent-layer.md +3 -2
  252. package/docs/autonomous-privy-wallet.md +188 -0
  253. package/docs/cli.md +265 -34
  254. package/docs/langchain.md +5 -0
  255. package/docs/mcp-reference.md +91 -5
  256. package/docs/probe-capability.md +191 -0
  257. package/docs/quickstart.md +39 -4
  258. package/docs/threat-model.md +20 -0
  259. package/docs/x402.md +766 -593
  260. package/package.json +19 -17
  261. package/src/capability/probe-capability.ts +355 -0
  262. package/src/cli/args.ts +29 -0
  263. package/src/cli/commands/claim.ts +168 -33
  264. package/src/cli/commands/close.ts +36 -3
  265. package/src/cli/commands/invoke.ts +5 -2
  266. package/src/cli/commands/mcp.ts +18 -2
  267. package/src/cli/commands/open.ts +75 -4
  268. package/src/cli/commands/pay.ts +584 -0
  269. package/src/cli/commands/reclaim-unverified.ts +8 -2
  270. package/src/cli/commands/reclaim.ts +277 -19
  271. package/src/cli/commands/refund.ts +475 -0
  272. package/src/cli/commands/status.ts +28 -2
  273. package/src/cli/commands/streams.ts +10 -14
  274. package/src/cli/commands/watch.ts +11 -1
  275. package/src/cli/config.ts +139 -52
  276. package/src/cli/context.ts +16 -0
  277. package/src/cli/deps.ts +111 -1
  278. package/src/cli/errors.ts +24 -1
  279. package/src/cli/escape-hatch.ts +19 -5
  280. package/src/cli/listings.ts +43 -10
  281. package/src/cli/preflight.ts +36 -21
  282. package/src/cli/privy.ts +4 -2
  283. package/src/cli/progress.ts +21 -2
  284. package/src/cli/reclaimability.ts +154 -0
  285. package/src/cli/run.ts +77 -21
  286. package/src/cli/scan-range.ts +2 -2
  287. package/src/cli/status.ts +454 -44
  288. package/src/cli/wallet.ts +45 -8
  289. package/src/discovery/rate-band.ts +172 -0
  290. package/src/escrow-generation.ts +135 -0
  291. package/src/frameworks/agentkit.ts +45 -11
  292. package/src/frameworks/eliza.ts +27 -5
  293. package/src/frameworks/langchain.ts +14 -0
  294. package/src/gateway/caller-auth-gateway.ts +320 -68
  295. package/src/gateway/http-server.ts +717 -220
  296. package/src/gateway/probe-auth.ts +191 -0
  297. package/src/gateway/signed-rate-bounds.ts +164 -0
  298. package/src/gateway/x402-opener-mode.ts +1171 -0
  299. package/src/index.ts +82 -19
  300. package/src/mcp/server.ts +351 -42
  301. package/src/mcp/x402-tools.ts +785 -0
  302. package/src/network.ts +302 -0
  303. package/src/sdk/client.ts +25 -0
  304. package/src/sdk/invoke.ts +6 -5
  305. package/src/wallet/autonomous-wallet-broker.ts +46 -20
  306. package/src/wallet/autonomous-wallet-protocol.ts +11 -2
  307. package/src/wallet/autonomous-wallet.ts +4 -2
  308. package/src/wallet/broker-escrows.ts +66 -0
  309. package/src/wallet/lifecycle.ts +53 -18
  310. package/src/wallet/privy-broker-server.ts +35 -25
  311. package/src/wallet/privy-session-broker.ts +58 -25
  312. package/src/wallet/privy-session-provider.ts +7 -3
  313. package/src/wallet/provider.ts +20 -15
  314. package/src/x402/facilitator.ts +3 -43
  315. package/src/x402-buyer/guarded-fetch.ts +213 -0
  316. package/src/x402-buyer/index.ts +9 -0
  317. package/src/x402-buyer/pay.ts +555 -0
  318. package/src/x402-opener/abi.ts +881 -0
  319. package/src/x402-opener/facilitator-entry.ts +48 -0
  320. package/src/x402-opener/facilitator-server.ts +1114 -0
  321. package/src/x402-opener/index.ts +13 -0
  322. package/src/x402-opener/listing-resolver.ts +202 -0
  323. package/src/x402-opener/refund-relay.ts +1873 -0
  324. package/src/x402-opener/relayer-queue.ts +18 -0
  325. package/src/x402-opener/scheme.ts +1551 -0
  326. package/src/x402-opener/terms.ts +453 -0
  327. package/dist/gateway/x402-mode.d.ts +0 -123
  328. package/dist/gateway/x402-mode.d.ts.map +0 -1
  329. package/dist/gateway/x402-mode.js +0 -212
  330. package/dist/gateway/x402-mode.js.map +0 -1
  331. package/dist/x402/delivery-oracle.d.ts +0 -108
  332. package/dist/x402/delivery-oracle.d.ts.map +0 -1
  333. package/dist/x402/delivery-oracle.js +0 -174
  334. package/dist/x402/delivery-oracle.js.map +0 -1
  335. package/dist/x402/facilitator-server-entry.d.ts +0 -3
  336. package/dist/x402/facilitator-server-entry.d.ts.map +0 -1
  337. package/dist/x402/facilitator-server-entry.js +0 -27
  338. package/dist/x402/facilitator-server-entry.js.map +0 -1
  339. package/dist/x402/facilitator-server.d.ts +0 -73
  340. package/dist/x402/facilitator-server.d.ts.map +0 -1
  341. package/dist/x402/facilitator-server.js +0 -305
  342. package/dist/x402/facilitator-server.js.map +0 -1
  343. package/dist/x402/payment-requirements.d.ts +0 -106
  344. package/dist/x402/payment-requirements.d.ts.map +0 -1
  345. package/dist/x402/payment-requirements.js +0 -138
  346. package/dist/x402/payment-requirements.js.map +0 -1
  347. package/dist/x402/relayer.d.ts +0 -41
  348. package/dist/x402/relayer.d.ts.map +0 -1
  349. package/dist/x402/relayer.js +0 -64
  350. package/dist/x402/relayer.js.map +0 -1
  351. package/dist/x402/resource-index.d.ts +0 -75
  352. package/dist/x402/resource-index.d.ts.map +0 -1
  353. package/dist/x402/resource-index.js +0 -126
  354. package/dist/x402/resource-index.js.map +0 -1
  355. package/dist/x402/verified-delivery-facilitator.d.ts +0 -285
  356. package/dist/x402/verified-delivery-facilitator.d.ts.map +0 -1
  357. package/dist/x402/verified-delivery-facilitator.js +0 -423
  358. package/dist/x402/verified-delivery-facilitator.js.map +0 -1
  359. package/src/gateway/x402-mode.ts +0 -350
  360. package/src/x402/delivery-oracle.ts +0 -285
  361. package/src/x402/facilitator-server-entry.ts +0 -35
  362. package/src/x402/facilitator-server.ts +0 -445
  363. package/src/x402/payment-requirements.ts +0 -231
  364. package/src/x402/relayer.ts +0 -122
  365. package/src/x402/resource-index.ts +0 -228
  366. package/src/x402/verified-delivery-facilitator.ts +0 -744
@@ -10,6 +10,9 @@ import {
10
10
  resolveCliWallet,
11
11
  } from "../wallet.js";
12
12
  import type { CommandContext, CommandSpec } from "../context.js";
13
+ import type { CliReadClient } from "../deps.js";
14
+ import { escrowGenerationFor } from "../../escrow-generation.js";
15
+ import type { StreamV2 } from "@absol-labs/sdk";
13
16
 
14
17
  /**
15
18
  * The seller's side of the loop.
@@ -52,7 +55,7 @@ export const claimCommand: CommandSpec = {
52
55
  }
53
56
  const read = deps.createReadClient(config);
54
57
  await assertTestnetRpc(config, () => read.getChainId());
55
- await assertCanPayGas(read, account.address);
58
+ await assertCanPayGas(read, account.address, config.network);
56
59
 
57
60
  const stream = await read.getStreamV2(streamId);
58
61
  if (stream.operator.toLowerCase() !== account.address.toLowerCase()) {
@@ -65,40 +68,20 @@ export const claimCommand: CommandSpec = {
65
68
  );
66
69
  }
67
70
 
68
- // Accrual lives in the oracle's checkpoint proof, never in the stream tuple.
69
- // No proof means no claim is possible yet, and saying that is better than
70
- // paying gas for a `NothingToClaim()` revert.
71
- let cumulativeAmount: bigint;
72
- try {
73
- cumulativeAmount = (await read.checkpointProof(streamId))
74
- .cumulativeAmount;
75
- } catch (error) {
76
- throw new CliError(
77
- "no checkpoint covers this stream yet, so there is nothing provable to claim",
78
- {
79
- exitCode: 4,
80
- hint: `the oracle publishes roughly every 15-22s and pays only for intervals that verified; ${describeError(
81
- error,
82
- )}`,
83
- cause: error,
84
- },
85
- );
86
- }
87
-
88
- const claimable = await read.claimableForV2(streamId, cumulativeAmount);
89
- if (claimable === 0n) {
90
- throw new CliError("this stream has nothing claimable right now", {
91
- exitCode: 4,
92
- hint: `everything checkpointed so far has already been claimed. See where it stands: metrik status ${streamId}`,
93
- });
94
- }
71
+ const plan = await planClaim(
72
+ read,
73
+ streamId,
74
+ stream,
75
+ escrowGenerationFor(config.chainId, config.escrow),
76
+ );
77
+ if (plan.kind === "nothing") throw plan.error;
95
78
 
96
79
  const write = deps.createWriteClient(
97
80
  config,
98
81
  account,
99
82
  writeClientOptions(wallet),
100
83
  );
101
- const result = await write.claimStream({
84
+ const action = {
102
85
  streamId,
103
86
  // `null` for a policy-enforced wallet — see `../spend-policy.ts`.
104
87
  signedMandate: isPolicyEnforced(wallet)
@@ -106,21 +89,173 @@ export const claimCommand: CommandSpec = {
106
89
  : await signClaimMandate(account, config.chainId),
107
90
  spentSoFarUsdc: 0n,
108
91
  nowSeconds: deps.nowSeconds(),
109
- });
92
+ };
93
+ let result: { readonly txHash: `0x${string}` };
94
+ if (plan.kind === "claimWithProof") {
95
+ result = await write.claimStream(action);
96
+ } else {
97
+ if (write.claimProvenStream === undefined) {
98
+ throw new CliError(
99
+ "this write client cannot send claimProven, which is the only way to collect this stream's proven value",
100
+ {
101
+ exitCode: 3,
102
+ hint: "no current checkpoint proof pays it, so a proof claim would revert NothingToClaim",
103
+ },
104
+ );
105
+ }
106
+ result = await write.claimProvenStream(action);
107
+ }
110
108
 
111
109
  out.result({
112
110
  streamId,
113
111
  txHash: result.txHash,
114
112
  operator: stream.operator,
115
- claimed: claimable,
116
- verifiedCumulative: cumulativeAmount,
113
+ claimed: plan.claimable,
114
+ method: plan.kind,
115
+ verifiedCumulative: plan.verifiedCumulative,
116
+ provenCumulative: plan.provenCumulative,
117
117
  });
118
118
  out.print("Claimed.");
119
119
  out.table([
120
120
  ["streamId", streamId],
121
121
  ["tx", result.txHash],
122
122
  ["operator", stream.operator],
123
- ["claimed", `${formatUsdc(claimable)} (net of protocol fee)`],
123
+ ["claimed", `${formatUsdc(plan.claimable)} (net of protocol fee)`],
124
+ [
125
+ "via",
126
+ plan.kind === "claimWithProof"
127
+ ? "claimWithProof (the oracle's current checkpoint proof)"
128
+ : `claimProven (the on-chain proven high-water, ${formatUsdc(plan.provenCumulative ?? 0n)} gross — no current checkpoint proof pays more)`,
129
+ ],
124
130
  ]);
125
131
  },
126
132
  };
133
+
134
+ /**
135
+ * Which claim, if any, `metrik claim` would send. Reads only, so it is
136
+ * testable (and checkable against a live stream) without a key.
137
+ *
138
+ * - `claimWithProof` pays `min(proofCumulative, deposit) − claimed` against ANY
139
+ * retained checkpoint root.
140
+ * - `claimProven` (StreamEscrowV3) pays `min(provenCumulative, deposit) −
141
+ * claimed` with NO proof: the high-water was itself proven against a signed
142
+ * root when it was recorded. It is the only way to collect proven value whose
143
+ * root has rotated out of the retained set, or that a later root regressed.
144
+ *
145
+ * Both are asked of the escrow (`claimableFor` at each cumulative; the escrow
146
+ * pays a claim with exactly that math), and the larger is chosen. A proof
147
+ * claim wins a tie, because it also raises the proven high-water. Nothing is
148
+ * chosen when both pay zero, so no gas is spent to learn `NothingToClaim`.
149
+ */
150
+ export type ClaimPlan =
151
+ | {
152
+ readonly kind: "claimWithProof" | "claimProven";
153
+ /** What the operator receives, net of the protocol fee. */
154
+ readonly claimable: bigint;
155
+ /** The current proof's cumulative; `null` when no proof was available. */
156
+ readonly verifiedCumulative: bigint | null;
157
+ /** V3 proven high-water; `null` on V2 or when unreadable. */
158
+ readonly provenCumulative: bigint | null;
159
+ }
160
+ | { readonly kind: "nothing"; readonly error: CliError };
161
+
162
+ export async function planClaim(
163
+ read: CliReadClient,
164
+ streamId: `0x${string}`,
165
+ stream: Pick<StreamV2, "claimedCumulative">,
166
+ escrowGeneration: string,
167
+ ): Promise<ClaimPlan> {
168
+ let verifiedCumulative: bigint | null = null;
169
+ let proofError: unknown = null;
170
+ try {
171
+ verifiedCumulative = (await read.checkpointProof(streamId))
172
+ .cumulativeAmount;
173
+ } catch (error) {
174
+ proofError = error;
175
+ }
176
+
177
+ let provenCumulative: bigint | null = null;
178
+ let provenError: string | null = null;
179
+ if (escrowGeneration === "v3") {
180
+ if (read.provenCumulativeOf === undefined) {
181
+ provenError = "this read client cannot read provenCumulativeOf";
182
+ } else {
183
+ try {
184
+ provenCumulative = await read.provenCumulativeOf(streamId);
185
+ } catch (error) {
186
+ provenError = describeError(error);
187
+ }
188
+ }
189
+ }
190
+
191
+ const [proofClaimable, provenClaimable] = await Promise.all([
192
+ verifiedCumulative === null
193
+ ? 0n
194
+ : read.claimableForV2(streamId, verifiedCumulative),
195
+ // `claimProven` pays at the high-water, so it is worth asking only when
196
+ // the high-water is above what has already been claimed.
197
+ provenCumulative === null || provenCumulative <= stream.claimedCumulative
198
+ ? 0n
199
+ : read.claimableForV2(streamId, provenCumulative),
200
+ ]);
201
+
202
+ if (proofClaimable > 0n && proofClaimable >= provenClaimable) {
203
+ return {
204
+ kind: "claimWithProof",
205
+ claimable: proofClaimable,
206
+ verifiedCumulative,
207
+ provenCumulative,
208
+ };
209
+ }
210
+ if (provenClaimable > 0n) {
211
+ return {
212
+ kind: "claimProven",
213
+ claimable: provenClaimable,
214
+ verifiedCumulative,
215
+ provenCumulative,
216
+ };
217
+ }
218
+
219
+ if (provenCumulative !== null && provenCumulative > 0n) {
220
+ return {
221
+ kind: "nothing",
222
+ error: new CliError("this stream has nothing to claim", {
223
+ exitCode: 4,
224
+ hint: `everything proven on-chain for it (${formatUsdc(provenCumulative)} gross) has already been claimed${
225
+ verifiedCumulative === null
226
+ ? ", and the latest checkpoint no longer contains it"
227
+ : ""
228
+ }. See where it stands: metrik status ${streamId}`,
229
+ }),
230
+ };
231
+ }
232
+ if (verifiedCumulative === null) {
233
+ // Accrual lives in the oracle's checkpoint proof (and, on V3, the proven
234
+ // high-water), never in the stream tuple. Saying so is better than paying
235
+ // gas for a `NothingToClaim()` revert.
236
+ return {
237
+ kind: "nothing",
238
+ error: new CliError(
239
+ "no checkpoint covers this stream yet, so there is nothing provable to claim",
240
+ {
241
+ exitCode: 4,
242
+ hint: `the oracle publishes roughly every 15-22s and pays only for intervals that verified; ${describeError(
243
+ proofError,
244
+ )}${
245
+ provenError === null
246
+ ? ""
247
+ : `; the on-chain proven high-water could not be read either (${provenError})`
248
+ }`,
249
+ cause: proofError,
250
+ },
251
+ ),
252
+ };
253
+ }
254
+ return {
255
+ kind: "nothing",
256
+ error: new CliError("this stream has nothing claimable right now", {
257
+ exitCode: 4,
258
+ hint: `everything checkpointed so far has already been claimed. See where it stands: metrik status ${streamId}`,
259
+ }),
260
+ };
261
+ }
@@ -1,5 +1,5 @@
1
1
  import { assertTestnetRpc, parseBytes32 } from "../config.js";
2
- import { usageError } from "../errors.js";
2
+ import { CliError, usageError } from "../errors.js";
3
3
  import { signRecoveryMandate } from "../mandate.js";
4
4
  import { assertCanPayGas } from "../preflight.js";
5
5
  import { writeClientOptions } from "../deps.js";
@@ -27,7 +27,28 @@ export const closeCommand: CommandSpec = {
27
27
  const { account } = wallet;
28
28
  const read = deps.createReadClient(config);
29
29
  await assertTestnetRpc(config, () => read.getChainId());
30
- await assertCanPayGas(read, account.address);
30
+ // An x402 opener stream is closed through the opener, by its PAYER. Say so
31
+ // up front: the escrow would answer anyone else with NotBuyer, and the SDK
32
+ // refuses a non-payer before anything is sent.
33
+ const stream = await read.getStreamV2(streamId).catch(() => null);
34
+ const opener = stream?.opener ?? null;
35
+ if (opener !== null && stream !== null) {
36
+ out.note(
37
+ `x402 stream: closing through the opener ${opener}; only its payer ${stream.payer} may close it.`,
38
+ );
39
+ }
40
+ try {
41
+ await assertCanPayGas(read, account.address, config.network);
42
+ } catch (error) {
43
+ if (opener !== null && error instanceof CliError) {
44
+ throw new CliError(error.message, {
45
+ exitCode: error.exitCode,
46
+ hint: `${error.hint ?? ""} This stream was bought over x402: a payer with no gas can close it through the seller's refund relay instead — \`metrik refund ${streamId} --refund-url <url> --close\`.`.trim(),
47
+ cause: error,
48
+ });
49
+ }
50
+ throw error;
51
+ }
31
52
 
32
53
  // A policy-enforced wallet signs no mandate of its own: this is a
33
54
  // buyer-recovery action, the escrow gates it on the buyer address and the
@@ -49,11 +70,23 @@ export const closeCommand: CommandSpec = {
49
70
  nowSeconds: deps.nowSeconds(),
50
71
  });
51
72
 
52
- out.result({ streamId, txHash: result.txHash, closed: true });
73
+ out.result({
74
+ streamId,
75
+ txHash: result.txHash,
76
+ closed: true,
77
+ opener,
78
+ payer: stream?.payer ?? null,
79
+ });
53
80
  out.print("Stream closed.");
54
81
  out.table([
55
82
  ["streamId", streamId],
56
83
  ["tx", result.txHash],
84
+ ...(opener === null
85
+ ? []
86
+ : ([
87
+ ["via opener", opener],
88
+ ["payer", stream?.payer ?? "-"],
89
+ ] as const)),
57
90
  ]);
58
91
  out.print("");
59
92
  out.print(
@@ -157,7 +157,7 @@ function explainInvokeFailure(error: unknown, signer: string): unknown {
157
157
  return error;
158
158
  }
159
159
 
160
- function parseHeaders(raw: readonly string[]): Record<string, string> {
160
+ export function parseHeaders(raw: readonly string[]): Record<string, string> {
161
161
  const headers: Record<string, string> = {};
162
162
  for (const entry of raw) {
163
163
  const separator = entry.indexOf(":");
@@ -171,7 +171,10 @@ function parseHeaders(raw: readonly string[]): Record<string, string> {
171
171
  return headers;
172
172
  }
173
173
 
174
- function hasHeader(headers: Record<string, string>, name: string): boolean {
174
+ export function hasHeader(
175
+ headers: Record<string, string>,
176
+ name: string,
177
+ ): boolean {
175
178
  return Object.keys(headers).some(
176
179
  (key) => key.toLowerCase() === name.toLowerCase(),
177
180
  );
@@ -1,6 +1,6 @@
1
1
  import { booleanFlag, stringFlag } from "../args.js";
2
2
  import { packageVersion } from "../version.js";
3
- import { CDP_ENV_VARS, PRIVATE_KEY_ENV } from "../wallet.js";
3
+ import { CDP_ENV_VARS, PRIVATE_KEY_ENV, PRIVY_ENV_VARS } from "../wallet.js";
4
4
  import type { CommandContext, CommandSpec } from "../context.js";
5
5
 
6
6
  /** The published executable an MCP host starts. Declared in `package.json#bin`. */
@@ -82,6 +82,17 @@ export const mcpCommand: CommandSpec = {
82
82
  },
83
83
  };
84
84
 
85
+ // Honesty about the one wallet source this block cannot carry. The CLI
86
+ // resolves a Privy wallet (step 3), but the MCP server's own resolver,
87
+ // `parseAgentWalletEnv()`, reads a raw key or CDP and nothing else — there
88
+ // is no Privy path from the environment there. Printing Privy variables
89
+ // into a config the server would ignore is the failure this says out loud.
90
+ if (PRIVY_ENV_VARS.some((variable) => (env[variable] ?? "").length > 0)) {
91
+ out.note(
92
+ `note: this environment configures a Privy wallet, which the CLI can use but \`${MCP_BIN}\` cannot — its wallet resolver reads ${PRIVATE_KEY_ENV} or the CDP variables only. The block below therefore carries a key placeholder; give the MCP server a raw key or a CDP account.`,
93
+ );
94
+ }
95
+
85
96
  out.result(document);
86
97
  out.print(
87
98
  `Paste this into your MCP client's config (Claude Desktop: claude_desktop_config.json), then replace every <…> placeholder:`,
@@ -102,6 +113,11 @@ export const mcpCommand: CommandSpec = {
102
113
  * Wallet variables, shaped to match how the environment running this command is
103
114
  * already configured — CDP if that is what is set, a raw key otherwise.
104
115
  *
116
+ * Privy is deliberately absent: `parseAgentWalletEnv()`, which is what the MCP
117
+ * server resolves its wallet with, has no Privy branch. A Privy block here
118
+ * would print a config that cannot start the server. The command says so on
119
+ * stderr instead.
120
+ *
105
121
  * Values are ALWAYS placeholders. `metrik` prints derived addresses and never
106
122
  * echoes a credential, and a config block is the single most likely thing to be
107
123
  * pasted into a chat window or an issue.
@@ -116,7 +132,7 @@ function walletEnv(env: NodeJS.ProcessEnv): Record<string, string> {
116
132
  );
117
133
  }
118
134
  return {
119
- [PRIVATE_KEY_ENV]: "<0x… a funded Base Sepolia test key>",
135
+ [PRIVATE_KEY_ENV]: "<0x… a funded testnet key>",
120
136
  };
121
137
  }
122
138
 
@@ -23,7 +23,12 @@ import {
23
23
  resolveCliWallet,
24
24
  PRIVATE_KEY_ENV,
25
25
  } from "../wallet.js";
26
- import { resolveListing } from "../listings.js";
26
+ import { resolveListingRecord } from "../listings.js";
27
+ import {
28
+ listingRateBand,
29
+ rateBandRefusal,
30
+ SignedRateBoundsError,
31
+ } from "../../discovery/rate-band.js";
27
32
  import type { CommandContext, CommandSpec } from "../context.js";
28
33
 
29
34
  export const openCommand: CommandSpec = {
@@ -89,14 +94,21 @@ export const openCommand: CommandSpec = {
89
94
  if (account !== null && !dryRun) {
90
95
  // Both balances, before anything is signed. Gas first: a wallet with no
91
96
  // ETH cannot send the approval that the USDC check exists to protect.
92
- await assertCanPayGas(read, account.address);
93
- await assertCanFundStream(read, account.address, budgetUsdc);
97
+ await assertCanPayGas(read, account.address, config.network);
98
+ await assertCanFundStream(
99
+ read,
100
+ account.address,
101
+ budgetUsdc,
102
+ config.network,
103
+ );
94
104
  }
95
105
 
96
106
  const operatorOverride = stringFlag(args, "operator");
97
- const listing = await resolveListing(context, serviceRef, {
107
+ const resolution = await resolveListingRecord(context, serviceRef, {
98
108
  required: operatorOverride === undefined,
99
109
  });
110
+ const listing = resolution.listing;
111
+ await assertRateInSignedBand(context, resolution, ratePerSecondUsdc);
100
112
  const operator = (operatorOverride ?? listing?.operator) as
101
113
  | `0x${string}`
102
114
  | undefined;
@@ -348,6 +360,65 @@ export const openCommand: CommandSpec = {
348
360
  },
349
361
  };
350
362
 
363
+ /**
364
+ * Refuse a `--rate` outside the band the operator SIGNED, before anything is
365
+ * signed or broadcast — dry run included, because the rate is an invalid input
366
+ * for this service exactly like `--rate 0` is.
367
+ *
368
+ * The escrow accepts any non-zero rate; the seller's capability gateway does
369
+ * not, and answers every request on an out-of-band stream with
370
+ * `403 stream-rate-out-of-bounds`. Without this check the CLI locked a buyer's
371
+ * deposit in a stream that could never be served, and said nothing.
372
+ *
373
+ * - Listing found: its signed descriptor is re-verified and the band enforced.
374
+ * A descriptor that does not verify is a refusal (exit 4), never "no band".
375
+ * A legacy binding signs no commercial terms, so there is nothing to enforce.
376
+ * - No listing: only reachable with `--operator`, the CLI's existing,
377
+ * explicit escape hatch for a service the registry cannot vouch for. The
378
+ * check cannot run, so it is skipped LOUDLY rather than silently. Without
379
+ * `--operator` an unreachable registry or a missing listing has already
380
+ * failed the command before this point (`resolveListingRecord`).
381
+ */
382
+ async function assertRateInSignedBand(
383
+ context: CommandContext,
384
+ resolution: Awaited<ReturnType<typeof resolveListingRecord>>,
385
+ ratePerSecondUsdc: bigint,
386
+ ): Promise<void> {
387
+ const { out } = context;
388
+ if (resolution.record === null) {
389
+ out.note(
390
+ resolution.registryUnreachable
391
+ ? "warning: the operator-signed rate band could NOT be checked because the registry is unreachable. If --rate is outside the band the operator signed, the service's gateway will refuse every request while the deposit stays escrowed. Re-run when the registry answers to have it checked."
392
+ : "note: this serviceRef has no verified listing, so there is no operator-signed rate band to check --rate against.",
393
+ );
394
+ return;
395
+ }
396
+ let bounds;
397
+ try {
398
+ bounds = await listingRateBand(resolution.record);
399
+ } catch (error) {
400
+ if (error instanceof SignedRateBoundsError) {
401
+ throw new CliError(
402
+ `the listing's operator-signed rate band could not be verified: ${error.message}`,
403
+ {
404
+ exitCode: 4,
405
+ hint: "nothing was broadcast. The CLI will not open a stream against a rate band it cannot verify.",
406
+ cause: error,
407
+ },
408
+ );
409
+ }
410
+ throw error;
411
+ }
412
+ if (bounds === null) return;
413
+ const refusal = rateBandRefusal(ratePerSecondUsdc, bounds, "--rate");
414
+ if (refusal !== undefined) {
415
+ throw new CliError(refusal, {
416
+ exitCode: 2,
417
+ hint: "pick a --rate inside the signed band (`--units atomic` takes base units; see `metrik discover` for each listing's band).",
418
+ });
419
+ }
420
+ }
421
+
351
422
  /**
352
423
  * What the buyer is actually paying for.
353
424
  *