@absol-labs/agent 0.9.0 → 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 (216) hide show
  1. package/README.md +77 -3
  2. package/dist/cli/amounts.d.ts +26 -0
  3. package/dist/cli/amounts.d.ts.map +1 -0
  4. package/dist/cli/amounts.js +71 -0
  5. package/dist/cli/amounts.js.map +1 -0
  6. package/dist/cli/args.d.ts +32 -0
  7. package/dist/cli/args.d.ts.map +1 -0
  8. package/dist/cli/args.js +119 -0
  9. package/dist/cli/args.js.map +1 -0
  10. package/dist/cli/attesters.d.ts +51 -0
  11. package/dist/cli/attesters.d.ts.map +1 -0
  12. package/dist/cli/attesters.js +58 -0
  13. package/dist/cli/attesters.js.map +1 -0
  14. package/dist/cli/bin.d.ts +3 -0
  15. package/dist/cli/bin.d.ts.map +1 -0
  16. package/dist/cli/bin.js +5 -0
  17. package/dist/cli/bin.js.map +1 -0
  18. package/dist/cli/commands/claim.d.ts +13 -0
  19. package/dist/cli/commands/claim.d.ts.map +1 -0
  20. package/dist/cli/commands/claim.js +86 -0
  21. package/dist/cli/commands/claim.js.map +1 -0
  22. package/dist/cli/commands/close.d.ts +3 -0
  23. package/dist/cli/commands/close.d.ts.map +1 -0
  24. package/dist/cli/commands/close.js +43 -0
  25. package/dist/cli/commands/close.js.map +1 -0
  26. package/dist/cli/commands/discover.d.ts +3 -0
  27. package/dist/cli/commands/discover.d.ts.map +1 -0
  28. package/dist/cli/commands/discover.js +183 -0
  29. package/dist/cli/commands/discover.js.map +1 -0
  30. package/dist/cli/commands/invoke.d.ts +3 -0
  31. package/dist/cli/commands/invoke.d.ts.map +1 -0
  32. package/dist/cli/commands/invoke.js +141 -0
  33. package/dist/cli/commands/invoke.js.map +1 -0
  34. package/dist/cli/commands/mcp.d.ts +3 -0
  35. package/dist/cli/commands/mcp.d.ts.map +1 -0
  36. package/dist/cli/commands/mcp.js +113 -0
  37. package/dist/cli/commands/mcp.js.map +1 -0
  38. package/dist/cli/commands/open.d.ts +3 -0
  39. package/dist/cli/commands/open.d.ts.map +1 -0
  40. package/dist/cli/commands/open.js +279 -0
  41. package/dist/cli/commands/open.js.map +1 -0
  42. package/dist/cli/commands/reclaim-unverified.d.ts +3 -0
  43. package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -0
  44. package/dist/cli/commands/reclaim-unverified.js +164 -0
  45. package/dist/cli/commands/reclaim-unverified.js.map +1 -0
  46. package/dist/cli/commands/reclaim.d.ts +33 -0
  47. package/dist/cli/commands/reclaim.d.ts.map +1 -0
  48. package/dist/cli/commands/reclaim.js +297 -0
  49. package/dist/cli/commands/reclaim.js.map +1 -0
  50. package/dist/cli/commands/status.d.ts +3 -0
  51. package/dist/cli/commands/status.d.ts.map +1 -0
  52. package/dist/cli/commands/status.js +43 -0
  53. package/dist/cli/commands/status.js.map +1 -0
  54. package/dist/cli/commands/streams.d.ts +3 -0
  55. package/dist/cli/commands/streams.d.ts.map +1 -0
  56. package/dist/cli/commands/streams.js +257 -0
  57. package/dist/cli/commands/streams.js.map +1 -0
  58. package/dist/cli/commands/watch.d.ts +3 -0
  59. package/dist/cli/commands/watch.d.ts.map +1 -0
  60. package/dist/cli/commands/watch.js +55 -0
  61. package/dist/cli/commands/watch.js.map +1 -0
  62. package/dist/cli/config.d.ts +61 -0
  63. package/dist/cli/config.d.ts.map +1 -0
  64. package/dist/cli/config.js +140 -0
  65. package/dist/cli/config.js.map +1 -0
  66. package/dist/cli/context.d.ts +29 -0
  67. package/dist/cli/context.d.ts.map +1 -0
  68. package/dist/cli/context.js +2 -0
  69. package/dist/cli/context.js.map +1 -0
  70. package/dist/cli/deps.d.ts +145 -0
  71. package/dist/cli/deps.d.ts.map +1 -0
  72. package/dist/cli/deps.js +227 -0
  73. package/dist/cli/deps.js.map +1 -0
  74. package/dist/cli/descriptor.d.ts +61 -0
  75. package/dist/cli/descriptor.d.ts.map +1 -0
  76. package/dist/cli/descriptor.js +78 -0
  77. package/dist/cli/descriptor.js.map +1 -0
  78. package/dist/cli/errors.d.ts +48 -0
  79. package/dist/cli/errors.d.ts.map +1 -0
  80. package/dist/cli/errors.js +129 -0
  81. package/dist/cli/errors.js.map +1 -0
  82. package/dist/cli/escape-hatch.d.ts +50 -0
  83. package/dist/cli/escape-hatch.d.ts.map +1 -0
  84. package/dist/cli/escape-hatch.js +45 -0
  85. package/dist/cli/escape-hatch.js.map +1 -0
  86. package/dist/cli/index.d.ts +8 -0
  87. package/dist/cli/index.d.ts.map +1 -0
  88. package/dist/cli/index.js +7 -0
  89. package/dist/cli/index.js.map +1 -0
  90. package/dist/cli/listings.d.ts +15 -0
  91. package/dist/cli/listings.d.ts.map +1 -0
  92. package/dist/cli/listings.js +56 -0
  93. package/dist/cli/listings.js.map +1 -0
  94. package/dist/cli/mandate.d.ts +66 -0
  95. package/dist/cli/mandate.d.ts.map +1 -0
  96. package/dist/cli/mandate.js +61 -0
  97. package/dist/cli/mandate.js.map +1 -0
  98. package/dist/cli/output.d.ts +33 -0
  99. package/dist/cli/output.d.ts.map +1 -0
  100. package/dist/cli/output.js +34 -0
  101. package/dist/cli/output.js.map +1 -0
  102. package/dist/cli/preflight.d.ts +38 -0
  103. package/dist/cli/preflight.d.ts.map +1 -0
  104. package/dist/cli/preflight.js +72 -0
  105. package/dist/cli/preflight.js.map +1 -0
  106. package/dist/cli/progress.d.ts +36 -0
  107. package/dist/cli/progress.d.ts.map +1 -0
  108. package/dist/cli/progress.js +40 -0
  109. package/dist/cli/progress.js.map +1 -0
  110. package/dist/cli/run.d.ts +25 -0
  111. package/dist/cli/run.d.ts.map +1 -0
  112. package/dist/cli/run.js +173 -0
  113. package/dist/cli/run.js.map +1 -0
  114. package/dist/cli/scan-range.d.ts +55 -0
  115. package/dist/cli/scan-range.d.ts.map +1 -0
  116. package/dist/cli/scan-range.js +57 -0
  117. package/dist/cli/scan-range.js.map +1 -0
  118. package/dist/cli/status.d.ts +90 -0
  119. package/dist/cli/status.d.ts.map +1 -0
  120. package/dist/cli/status.js +252 -0
  121. package/dist/cli/status.js.map +1 -0
  122. package/dist/cli/timeout.d.ts +30 -0
  123. package/dist/cli/timeout.d.ts.map +1 -0
  124. package/dist/cli/timeout.js +55 -0
  125. package/dist/cli/timeout.js.map +1 -0
  126. package/dist/cli/version.d.ts +12 -0
  127. package/dist/cli/version.d.ts.map +1 -0
  128. package/dist/cli/version.js +22 -0
  129. package/dist/cli/version.js.map +1 -0
  130. package/dist/cli/wallet.d.ts +95 -0
  131. package/dist/cli/wallet.d.ts.map +1 -0
  132. package/dist/cli/wallet.js +169 -0
  133. package/dist/cli/wallet.js.map +1 -0
  134. package/dist/frameworks/agentkit.d.ts.map +1 -1
  135. package/dist/frameworks/agentkit.js +8 -4
  136. package/dist/frameworks/agentkit.js.map +1 -1
  137. package/dist/frameworks/crewai.d.ts +10 -0
  138. package/dist/frameworks/crewai.d.ts.map +1 -1
  139. package/dist/frameworks/crewai.js +12 -2
  140. package/dist/frameworks/crewai.js.map +1 -1
  141. package/dist/frameworks/eliza.d.ts.map +1 -1
  142. package/dist/frameworks/eliza.js +14 -3
  143. package/dist/frameworks/eliza.js.map +1 -1
  144. package/dist/frameworks/langchain.d.ts.map +1 -1
  145. package/dist/frameworks/langchain.js +14 -3
  146. package/dist/frameworks/langchain.js.map +1 -1
  147. package/dist/gateway/server-entry.d.ts +1 -0
  148. package/dist/gateway/server-entry.js +1 -0
  149. package/dist/gateway/server-entry.js.map +1 -1
  150. package/dist/index.d.ts +1 -1
  151. package/dist/index.d.ts.map +1 -1
  152. package/dist/index.js +1 -1
  153. package/dist/index.js.map +1 -1
  154. package/dist/mcp/http-server.d.ts +1 -0
  155. package/dist/mcp/http-server.js +1 -0
  156. package/dist/mcp/http-server.js.map +1 -1
  157. package/dist/mcp/server.d.ts.map +1 -1
  158. package/dist/mcp/server.js +46 -6
  159. package/dist/mcp/server.js.map +1 -1
  160. package/dist/mcp/stdio.d.ts +1 -0
  161. package/dist/mcp/stdio.js +1 -0
  162. package/dist/mcp/stdio.js.map +1 -1
  163. package/dist/sdk/client.d.ts +44 -3
  164. package/dist/sdk/client.d.ts.map +1 -1
  165. package/dist/sdk/client.js +38 -3
  166. package/dist/sdk/client.js.map +1 -1
  167. package/docs/agent-layer.md +2 -1
  168. package/docs/cli.md +569 -0
  169. package/docs/crewai.md +6 -2
  170. package/docs/eliza.md +6 -1
  171. package/docs/mcp-hosted.md +3 -2
  172. package/docs/quickstart.md +18 -5
  173. package/package.json +17 -5
  174. package/src/cli/amounts.ts +102 -0
  175. package/src/cli/args.ts +150 -0
  176. package/src/cli/attesters.ts +86 -0
  177. package/src/cli/bin.ts +5 -0
  178. package/src/cli/commands/claim.ts +100 -0
  179. package/src/cli/commands/close.ts +53 -0
  180. package/src/cli/commands/discover.ts +228 -0
  181. package/src/cli/commands/invoke.ts +177 -0
  182. package/src/cli/commands/mcp.ts +135 -0
  183. package/src/cli/commands/open.ts +331 -0
  184. package/src/cli/commands/reclaim-unverified.ts +206 -0
  185. package/src/cli/commands/reclaim.ts +360 -0
  186. package/src/cli/commands/status.ts +56 -0
  187. package/src/cli/commands/streams.ts +344 -0
  188. package/src/cli/commands/watch.ts +70 -0
  189. package/src/cli/config.ts +208 -0
  190. package/src/cli/context.ts +30 -0
  191. package/src/cli/deps.ts +437 -0
  192. package/src/cli/descriptor.ts +133 -0
  193. package/src/cli/errors.ts +162 -0
  194. package/src/cli/escape-hatch.ts +92 -0
  195. package/src/cli/index.ts +27 -0
  196. package/src/cli/listings.ts +77 -0
  197. package/src/cli/mandate.ts +126 -0
  198. package/src/cli/output.ts +63 -0
  199. package/src/cli/preflight.ts +88 -0
  200. package/src/cli/progress.ts +75 -0
  201. package/src/cli/run.ts +209 -0
  202. package/src/cli/scan-range.ts +76 -0
  203. package/src/cli/status.ts +381 -0
  204. package/src/cli/timeout.ts +64 -0
  205. package/src/cli/version.ts +21 -0
  206. package/src/cli/wallet.ts +241 -0
  207. package/src/frameworks/agentkit.ts +8 -3
  208. package/src/frameworks/crewai.ts +13 -2
  209. package/src/frameworks/eliza.ts +14 -3
  210. package/src/frameworks/langchain.ts +14 -3
  211. package/src/gateway/server-entry.ts +1 -0
  212. package/src/index.ts +2 -0
  213. package/src/mcp/http-server.ts +1 -0
  214. package/src/mcp/server.ts +51 -6
  215. package/src/mcp/stdio.ts +1 -0
  216. package/src/sdk/client.ts +71 -4
@@ -0,0 +1,45 @@
1
+ import { formatDuration } from "./amounts.js";
2
+ export function escapeHatchWindow(stream, graceSeconds, nowSeconds) {
3
+ const readyAt = stream.expiresAt + graceSeconds;
4
+ const secondsRemaining = readyAt - nowSeconds;
5
+ return {
6
+ graceSeconds,
7
+ readyAt,
8
+ ready: secondsRemaining <= 0,
9
+ secondsRemaining: secondsRemaining > 0 ? secondsRemaining : 0,
10
+ };
11
+ }
12
+ /** `2026-09-17T09:15:00.000Z (1789…)`, or `-` for an unset timestamp. */
13
+ export function formatTimestamp(seconds) {
14
+ if (seconds <= 0)
15
+ return "-";
16
+ return `${new Date(seconds * 1000).toISOString()} (${seconds})`;
17
+ }
18
+ /** One line describing where the escape hatch stands, for humans. */
19
+ export function describeEscapeHatch(window) {
20
+ return window.ready
21
+ ? `open since ${formatTimestamp(window.readyAt)}`
22
+ : `opens ${formatTimestamp(window.readyAt)} — in ${formatDuration(window.secondsRemaining)}`;
23
+ }
24
+ /**
25
+ * The time the ESCROW will compare against, not the time this machine thinks it
26
+ * is. `reclaimUnverified` reverts on `block.timestamp`, so a readiness answer
27
+ * computed from a skewed laptop clock could tell a buyer to spend gas on a
28
+ * guaranteed revert — or tell them to wait when the hatch is already open.
29
+ *
30
+ * A failed read is not fatal: the caller's clock is the fallback, and the
31
+ * `source` field is reported so the difference is never hidden.
32
+ */
33
+ export async function readChainNow(read, fallbackSeconds) {
34
+ try {
35
+ const seconds = await read.latestBlockTimestamp();
36
+ if (Number.isFinite(seconds) && seconds > 0) {
37
+ return { seconds, source: "chain" };
38
+ }
39
+ }
40
+ catch {
41
+ // fall through to the caller's clock
42
+ }
43
+ return { seconds: fallbackSeconds, source: "local" };
44
+ }
45
+ //# sourceMappingURL=escape-hatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape-hatch.js","sourceRoot":"","sources":["../../src/cli/escape-hatch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AA+B9C,MAAM,UAAU,iBAAiB,CAC/B,MAAmC,EACnC,YAAoB,EACpB,UAAkB;IAElB,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,GAAG,YAAY,CAAC;IAChD,MAAM,gBAAgB,GAAG,OAAO,GAAG,UAAU,CAAC;IAC9C,OAAO;QACL,YAAY;QACZ,OAAO;QACP,KAAK,EAAE,gBAAgB,IAAI,CAAC;QAC5B,gBAAgB,EAAE,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;KAC9D,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAC7B,OAAO,GAAG,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,GAAG,CAAC;AAClE,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,mBAAmB,CAAC,MAAyB;IAC3D,OAAO,MAAM,CAAC,KAAK;QACjB,CAAC,CAAC,cAAc,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;QACjD,CAAC,CAAC,SAAS,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,cAAc,CAC7D,MAAM,CAAC,gBAAgB,CACxB,EAAE,CAAC;AACV,CAAC;AAQD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAiD,EACjD,eAAuB;IAEvB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAClD,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QACtC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qCAAqC;IACvC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACvD,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { runCli, renderHelp, COMMANDS, type RunCliOptions } from "./run.js";
2
+ export { parseArgs, type ParsedArgs } from "./args.js";
3
+ export { TESTNET_CHAIN_IDS, assertTestnetChainId, assertTestnetRpc, resolveConfig, type CliConfig, } from "./config.js";
4
+ export { CliError, describeError } from "./errors.js";
5
+ export { defaultCliDependencies, type CliDependencies, type CliReadClient, type CliWriteClient, type OpenedStream, type StreamOpenedQuery, } from "./deps.js";
6
+ export { CDP_ENV_VARS, PRIVATE_KEY_ENV, optionalCliWallet, resolveCliWallet, type CliWallet, type CliWalletSource, } from "./wallet.js";
7
+ export type { CommandContext, CommandSpec } from "./context.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,KAAK,SAAS,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EACL,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { runCli, renderHelp, COMMANDS } from "./run.js";
2
+ export { parseArgs } from "./args.js";
3
+ export { TESTNET_CHAIN_IDS, assertTestnetChainId, assertTestnetRpc, resolveConfig, } from "./config.js";
4
+ export { CliError, describeError } from "./errors.js";
5
+ export { defaultCliDependencies, } from "./deps.js";
6
+ export { CDP_ENV_VARS, PRIVATE_KEY_ENV, optionalCliWallet, resolveCliWallet, } from "./wallet.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAsB,MAAM,UAAU,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAmB,MAAM,WAAW,CAAC;AACvD,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,GAEd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EACL,sBAAsB,GAMvB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GAGjB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { CommandContext } from "./context.js";
2
+ import type { ServiceListing } from "./deps.js";
3
+ /**
4
+ * Finds the verified listing for a `serviceRef`.
5
+ *
6
+ * The registry is an untrusted transport: `discoverServices` re-derives every
7
+ * `serviceRef` from the signed record and recovers the operator signature, so a
8
+ * compromised registry can neither invent an operator to pay nor redirect an
9
+ * invocation URL. That verification is the reason the CLI routes through
10
+ * discovery instead of taking a `--url`.
11
+ */
12
+ export declare function resolveListing(context: CommandContext, serviceRef: `0x${string}`, options: {
13
+ readonly required: boolean;
14
+ }): Promise<ServiceListing | null>;
15
+ //# sourceMappingURL=listings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listings.d.ts","sourceRoot":"","sources":["../../src/cli/listings.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,KAAK,MAAM,EAAE,EACzB,OAAO,EAAE;IAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACtC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAyDhC"}
@@ -0,0 +1,56 @@
1
+ import { RegistryUnavailableError } from "../discovery/registry.js";
2
+ import { CliError } from "./errors.js";
3
+ /**
4
+ * Finds the verified listing for a `serviceRef`.
5
+ *
6
+ * The registry is an untrusted transport: `discoverServices` re-derives every
7
+ * `serviceRef` from the signed record and recovers the operator signature, so a
8
+ * compromised registry can neither invent an operator to pay nor redirect an
9
+ * invocation URL. That verification is the reason the CLI routes through
10
+ * discovery instead of taking a `--url`.
11
+ */
12
+ export async function resolveListing(context, serviceRef, options) {
13
+ const { config, out, deps } = context;
14
+ let services;
15
+ try {
16
+ services = (await deps.discover({
17
+ registryUrl: config.registryUrl,
18
+ logger: { warn: (...parts) => out.note(parts.map(String).join(" ")) },
19
+ })).services;
20
+ }
21
+ catch (error) {
22
+ if (error instanceof RegistryUnavailableError && !options.required) {
23
+ out.note(`warning: the registry at ${config.registryUrl} is unreachable; continuing without a verified listing.`);
24
+ return null;
25
+ }
26
+ throw new CliError(`the service registry at ${config.registryUrl} could not be read`, { exitCode: 4, cause: error });
27
+ }
28
+ const wanted = serviceRef.toLowerCase();
29
+ const match = services.find((service) => service.serviceRef.toLowerCase() === wanted);
30
+ if (match === undefined) {
31
+ if (!options.required)
32
+ return null;
33
+ throw new CliError(`no verified listing in the registry matches serviceRef ${serviceRef}`, {
34
+ exitCode: 4,
35
+ hint: "run `metrik discover` to see what is listed. A listing that fails signature verification is dropped, so it will not appear here.",
36
+ });
37
+ }
38
+ if (match.accessUrl === null) {
39
+ if (!options.required)
40
+ return null;
41
+ throw new CliError(`listing ${serviceRef} carries no signed invocation URL`, {
42
+ exitCode: 4,
43
+ hint: "the CLI refuses to call an origin that the operator did not sign.",
44
+ });
45
+ }
46
+ return {
47
+ serviceRef: match.serviceRef,
48
+ operator: match.operator,
49
+ publicUrl: match.publicUrl,
50
+ access: match.access,
51
+ accessUrl: match.accessUrl,
52
+ signed: match.signed,
53
+ category: match.category,
54
+ };
55
+ }
56
+ //# sourceMappingURL=listings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listings.js","sourceRoot":"","sources":["../../src/cli/listings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIvC;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAuB,EACvB,UAAyB,EACzB,OAAuC;IAEvC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACtC,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,CACT,MAAM,IAAI,CAAC,QAAQ,CAAC;YAClB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE;SACtE,CAAC,CACH,CAAC,QAAQ,CAAC;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,wBAAwB,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnE,GAAG,CAAC,IAAI,CACN,4BAA4B,MAAM,CAAC,WAAW,yDAAyD,CACxG,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,IAAI,QAAQ,CAChB,2BAA2B,MAAM,CAAC,WAAW,oBAAoB,EACjE,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAC9B,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CACzB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,MAAM,CACzD,CAAC;IACF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,IAAI,QAAQ,CAChB,0DAA0D,UAAU,EAAE,EACtE;YACE,QAAQ,EAAE,CAAC;YACX,IAAI,EAAE,kIAAkI;SACzI,CACF,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,IAAI,QAAQ,CAChB,WAAW,UAAU,mCAAmC,EACxD;YACE,QAAQ,EAAE,CAAC;YACX,IAAI,EAAE,mEAAmE;SAC1E,CACF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,66 @@
1
+ import type { Account } from "viem";
2
+ import { type ServerMandateCaps } from "../mandates/env.js";
3
+ import type { SignedSpendMandate } from "../mandates/mandate.js";
4
+ /**
5
+ * Spend mandates in the CLI.
6
+ *
7
+ * Every fund-moving path in this package goes through `checkMandate()` — that is
8
+ * a golden rule of the agent layer, and the CLI is not exempt. The CLI's twist
9
+ * is that the person typing the command IS the mandate owner: they hold the key
10
+ * and they just stated the exact spend on the command line. So the mandate is
11
+ * self-signed from the same wallet that funds the stream, exactly as the MCP
12
+ * server does (`signServerMandate`).
13
+ *
14
+ * Two sources, in priority order:
15
+ *
16
+ * 1. `METRIK_AGENT_MANDATE_*` in the environment — an explicit standing ceiling.
17
+ * If the requested hire exceeds it, `checkMandate` DENIES it. This is the
18
+ * path to use when a CLI runs unattended under a policy.
19
+ * 2. No env caps configured — the mandate is sized to exactly this hire and
20
+ * scoped to exactly this operator. It authorizes the command that was typed
21
+ * and nothing wider.
22
+ *
23
+ * Neither path is an unbounded mandate.
24
+ */
25
+ export interface RequestedSpend {
26
+ readonly operator: `0x${string}`;
27
+ readonly budgetUsdc: bigint;
28
+ readonly ratePerSecondUsdc: bigint;
29
+ readonly durationSeconds: number;
30
+ }
31
+ export interface CliMandate {
32
+ readonly signed: SignedSpendMandate;
33
+ /** Where the caps came from, for the human-readable output. */
34
+ readonly source: "env" | "request";
35
+ }
36
+ /**
37
+ * The caps this hire would be authorized under, WITHOUT signing anything. Split
38
+ * out so `open --dry-run` can report the mandate it would use even when there is
39
+ * no key to sign it with.
40
+ */
41
+ export declare function cliMandateCaps(request: RequestedSpend, env: NodeJS.ProcessEnv): {
42
+ readonly caps: ServerMandateCaps;
43
+ readonly source: "env" | "request";
44
+ };
45
+ export declare function signCliMandate(account: Account, request: RequestedSpend, options: {
46
+ readonly chainId: number;
47
+ readonly env: NodeJS.ProcessEnv;
48
+ }): Promise<CliMandate>;
49
+ /**
50
+ * The operator's claim is not a SPEND: it redeems value the stream already
51
+ * earned under an oracle-verified checkpoint, and the escrow pays it to the
52
+ * stream's operator and nobody else. But `checkMandate()` gates every
53
+ * fund-moving path in this package without exception, so the claim carries a
54
+ * mandate too. The caps below are placeholders that satisfy the schema against a
55
+ * zero-valued request; the real gate is the escrow's own `NotOperator()`.
56
+ */
57
+ export declare function signClaimMandate(account: Account, chainId: number): Promise<SignedSpendMandate>;
58
+ /**
59
+ * Close and reclaim are BUYER-RECOVERY actions: they stop payment or return
60
+ * unspent funds to the buyer, and `VerifiedStreamAgentClient` authorizes them on
61
+ * the mandate owner's signature alone — never on caps or expiry, so a lapsed
62
+ * mandate can never strand a buyer's own money. The caps below are therefore
63
+ * placeholders that satisfy the schema; they gate nothing.
64
+ */
65
+ export declare function signRecoveryMandate(account: Account, chainId: number): Promise<SignedSpendMandate>;
66
+ //# sourceMappingURL=mandate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mandate.d.ts","sourceRoot":"","sources":["../../src/cli/mandate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,CAAA;CAAE,CAc1E;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,GACrE,OAAO,CAAC,UAAU,CAAC,CAMrB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,kBAAkB,CAAC,CAE7B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,kBAAkB,CAAC,CAE7B"}
@@ -0,0 +1,61 @@
1
+ import { parseServerMandateCapsEnv, signServerMandate, DEFAULT_SERVER_MANDATE_TTL_SECONDS, } from "../mandates/env.js";
2
+ /**
3
+ * The caps this hire would be authorized under, WITHOUT signing anything. Split
4
+ * out so `open --dry-run` can report the mandate it would use even when there is
5
+ * no key to sign it with.
6
+ */
7
+ export function cliMandateCaps(request, env) {
8
+ const envCaps = parseServerMandateCapsEnv(env);
9
+ if (envCaps !== null)
10
+ return { caps: envCaps, source: "env" };
11
+ return {
12
+ caps: {
13
+ maxPerStreamUsdc: request.budgetUsdc,
14
+ maxTotalUsdc: request.budgetUsdc,
15
+ maxRatePerSecondUsdc: request.ratePerSecondUsdc,
16
+ maxDurationSeconds: request.durationSeconds,
17
+ allowedOperators: [request.operator],
18
+ ttlSeconds: DEFAULT_SERVER_MANDATE_TTL_SECONDS,
19
+ },
20
+ source: "request",
21
+ };
22
+ }
23
+ export async function signCliMandate(account, request, options) {
24
+ const { caps, source } = cliMandateCaps(request, options.env);
25
+ const signed = await signServerMandate(account, caps, {
26
+ chainId: options.chainId,
27
+ });
28
+ return { signed, source };
29
+ }
30
+ /**
31
+ * The operator's claim is not a SPEND: it redeems value the stream already
32
+ * earned under an oracle-verified checkpoint, and the escrow pays it to the
33
+ * stream's operator and nobody else. But `checkMandate()` gates every
34
+ * fund-moving path in this package without exception, so the claim carries a
35
+ * mandate too. The caps below are placeholders that satisfy the schema against a
36
+ * zero-valued request; the real gate is the escrow's own `NotOperator()`.
37
+ */
38
+ export async function signClaimMandate(account, chainId) {
39
+ return await signPlaceholderMandate(account, chainId);
40
+ }
41
+ /**
42
+ * Close and reclaim are BUYER-RECOVERY actions: they stop payment or return
43
+ * unspent funds to the buyer, and `VerifiedStreamAgentClient` authorizes them on
44
+ * the mandate owner's signature alone — never on caps or expiry, so a lapsed
45
+ * mandate can never strand a buyer's own money. The caps below are therefore
46
+ * placeholders that satisfy the schema; they gate nothing.
47
+ */
48
+ export async function signRecoveryMandate(account, chainId) {
49
+ return await signPlaceholderMandate(account, chainId);
50
+ }
51
+ async function signPlaceholderMandate(account, chainId) {
52
+ return await signServerMandate(account, {
53
+ maxPerStreamUsdc: 1n,
54
+ maxTotalUsdc: 1n,
55
+ maxRatePerSecondUsdc: 1n,
56
+ maxDurationSeconds: 1,
57
+ allowedOperators: [],
58
+ ttlSeconds: DEFAULT_SERVER_MANDATE_TTL_SECONDS,
59
+ }, { chainId });
60
+ }
61
+ //# sourceMappingURL=mandate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mandate.js","sourceRoot":"","sources":["../../src/cli/mandate.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,kCAAkC,GAEnC,MAAM,oBAAoB,CAAC;AAqC5B;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAuB,EACvB,GAAsB;IAEtB,MAAM,OAAO,GAAG,yBAAyB,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC9D,OAAO;QACL,IAAI,EAAE;YACJ,gBAAgB,EAAE,OAAO,CAAC,UAAU;YACpC,YAAY,EAAE,OAAO,CAAC,UAAU;YAChC,oBAAoB,EAAE,OAAO,CAAC,iBAAiB;YAC/C,kBAAkB,EAAE,OAAO,CAAC,eAAe;YAC3C,gBAAgB,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;YACpC,UAAU,EAAE,kCAAkC;SAC/C;QACD,MAAM,EAAE,SAAS;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAgB,EAChB,OAAuB,EACvB,OAAsE;IAEtE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,IAAI,EAAE;QACpD,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAgB,EAChB,OAAe;IAEf,OAAO,MAAM,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAgB,EAChB,OAAe;IAEf,OAAO,MAAM,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,OAAgB,EAChB,OAAe;IAEf,OAAO,MAAM,iBAAiB,CAC5B,OAAO,EACP;QACE,gBAAgB,EAAE,EAAE;QACpB,YAAY,EAAE,EAAE;QAChB,oBAAoB,EAAE,EAAE;QACxB,kBAAkB,EAAE,CAAC;QACrB,gBAAgB,EAAE,EAAE;QACpB,UAAU,EAAE,kCAAkC;KAC/C,EACD,EAAE,OAAO,EAAE,CACZ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Output shape. Human-readable by default; `--json` emits one JSON object on
3
+ * stdout per command so a script can pipe it into `jq` without parsing prose.
4
+ *
5
+ * Warnings and progress go to stderr in BOTH modes, so `--json` stdout stays a
6
+ * single parseable document even when discovery drops a row or a reclaim
7
+ * retries.
8
+ */
9
+ export interface CliStreams {
10
+ readonly stdout: (line: string) => void;
11
+ readonly stderr: (line: string) => void;
12
+ }
13
+ export interface Printer extends CliStreams {
14
+ readonly json: boolean;
15
+ /** Human-readable body. Suppressed entirely in `--json` mode. */
16
+ readonly print: (line: string) => void;
17
+ /** Key/value block, aligned. Suppressed in `--json` mode. */
18
+ readonly table: (rows: readonly (readonly [string, string])[]) => void;
19
+ /** Progress / warnings. Always stderr, always shown. */
20
+ readonly note: (line: string) => void;
21
+ /** The machine-readable result. Emitted only in `--json` mode. */
22
+ readonly result: (value: unknown) => void;
23
+ /**
24
+ * One COMPACT JSON object on a single stdout line — JSON Lines. Used by
25
+ * commands that emit a record per tick (`watch`), where every line must parse
26
+ * standalone so a consumer can react as each one lands. `result` is the
27
+ * pretty-printed single-document form and is wrong for a stream: a multi-line
28
+ * object means not one of its lines parses on its own.
29
+ */
30
+ readonly resultLine: (value: unknown) => void;
31
+ }
32
+ export declare function createPrinter(streams: CliStreams, json: boolean): Printer;
33
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,OAAQ,SAAQ,UAAU;IACzC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;IACvE,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAwBzE"}
@@ -0,0 +1,34 @@
1
+ export function createPrinter(streams, json) {
2
+ return {
3
+ ...streams,
4
+ json,
5
+ print(line) {
6
+ if (!json)
7
+ streams.stdout(line);
8
+ },
9
+ table(rows) {
10
+ if (json)
11
+ return;
12
+ const width = rows.reduce((max, [key]) => Math.max(max, key.length), 0);
13
+ for (const [key, value] of rows) {
14
+ streams.stdout(` ${key.padEnd(width)} ${value}`);
15
+ }
16
+ },
17
+ note(line) {
18
+ streams.stderr(line);
19
+ },
20
+ result(value) {
21
+ if (json)
22
+ streams.stdout(JSON.stringify(value, jsonReplacer, 2));
23
+ },
24
+ resultLine(value) {
25
+ if (json)
26
+ streams.stdout(JSON.stringify(value, jsonReplacer));
27
+ },
28
+ };
29
+ }
30
+ /** bigints are the natural amount type here; JSON has no bigint. */
31
+ function jsonReplacer(_key, value) {
32
+ return typeof value === "bigint" ? value.toString() : value;
33
+ }
34
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAiCA,MAAM,UAAU,aAAa,CAAC,OAAmB,EAAE,IAAa;IAC9D,OAAO;QACL,GAAG,OAAO;QACV,IAAI;QACJ,KAAK,CAAC,IAAI;YACR,IAAI,CAAC,IAAI;gBAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,KAAK,CAAC,IAAI;YACR,IAAI,IAAI;gBAAE,OAAO;YACjB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YACxE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;gBAChC,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI;YACP,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QACD,MAAM,CAAC,KAAK;YACV,IAAI,IAAI;gBAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,UAAU,CAAC,KAAK;YACd,IAAI,IAAI;gBAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;QAChE,CAAC;KACF,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,SAAS,YAAY,CAAC,IAAY,EAAE,KAAc;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { CliReadClient } from "./deps.js";
2
+ /** Where a Base Sepolia test wallet gets its gas. */
3
+ export declare const BASE_SEPOLIA_FAUCET_URL = "https://www.alchemy.com/faucets/base-sepolia";
4
+ /** Where a Base Sepolia test wallet gets the USDC it escrows. */
5
+ export declare const CIRCLE_USDC_FAUCET_URL = "https://faucet.circle.com";
6
+ /**
7
+ * Refuse to broadcast from a wallet that cannot pay for gas.
8
+ *
9
+ * Without this, the first thing an unfunded wallet sees is the node's own
10
+ * phrasing — `USDC approve transaction failed: Execution reverted with reason:
11
+ * gas required exceeds allowance (0)` — which reads like a USDC allowance
12
+ * problem and sends the reader looking at approvals. The actual fact is "this
13
+ * address holds no ETH", and it is knowable with one read before anything is
14
+ * signed.
15
+ *
16
+ * Deliberately only a ZERO check, not an estimate: predicting the gas a hire
17
+ * will cost means simulating it, and a wallet with a little ETH that still runs
18
+ * short should get the real revert rather than a guess from this CLI.
19
+ */
20
+ export declare function assertCanPayGas(read: CliReadClient, address: `0x${string}`): Promise<void>;
21
+ /**
22
+ * Refuse to broadcast a hire the wallet cannot fund.
23
+ *
24
+ * The sibling of `assertCanPayGas`, for the OTHER balance. Gas is ETH and the
25
+ * deposit is USDC: they are separate balances on separate tokens, so a wallet
26
+ * that passes the gas check can still hold no USDC at all. Without this the
27
+ * `open` path sends the USDC approval FIRST — which succeeds, because approving
28
+ * an amount you do not hold is legal — and then reverts inside `transferFrom`,
29
+ * having already spent gas to learn something that was one `balanceOf` away.
30
+ *
31
+ * Deliberately NOT an allowance check. The CLI's own open path grants the
32
+ * bounded approval it needs (`approveTxHash` in the result), so a missing
33
+ * allowance is a step of the command, not a precondition for it; gating on it
34
+ * would refuse a hire that was about to work. Balance is the fact the CLI
35
+ * cannot fix for you.
36
+ */
37
+ export declare function assertCanFundStream(read: CliReadClient, address: `0x${string}`, budgetUsdc: bigint): Promise<void>;
38
+ //# sourceMappingURL=preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../../src/cli/preflight.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,qDAAqD;AACrD,eAAO,MAAM,uBAAuB,iDACY,CAAC;AAEjD,iEAAiE;AACjE,eAAO,MAAM,sBAAsB,8BAA8B,CAAC;AAElE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,KAAK,MAAM,EAAE,GACrB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,KAAK,MAAM,EAAE,EACtB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAmBf"}
@@ -0,0 +1,72 @@
1
+ import { formatUsdc } from "./amounts.js";
2
+ import { CliError } from "./errors.js";
3
+ /** Where a Base Sepolia test wallet gets its gas. */
4
+ export const BASE_SEPOLIA_FAUCET_URL = "https://www.alchemy.com/faucets/base-sepolia";
5
+ /** Where a Base Sepolia test wallet gets the USDC it escrows. */
6
+ export const CIRCLE_USDC_FAUCET_URL = "https://faucet.circle.com";
7
+ /**
8
+ * Refuse to broadcast from a wallet that cannot pay for gas.
9
+ *
10
+ * Without this, the first thing an unfunded wallet sees is the node's own
11
+ * phrasing — `USDC approve transaction failed: Execution reverted with reason:
12
+ * gas required exceeds allowance (0)` — which reads like a USDC allowance
13
+ * problem and sends the reader looking at approvals. The actual fact is "this
14
+ * address holds no ETH", and it is knowable with one read before anything is
15
+ * signed.
16
+ *
17
+ * Deliberately only a ZERO check, not an estimate: predicting the gas a hire
18
+ * will cost means simulating it, and a wallet with a little ETH that still runs
19
+ * short should get the real revert rather than a guess from this CLI.
20
+ */
21
+ export async function assertCanPayGas(read, address) {
22
+ let balance;
23
+ try {
24
+ balance = await read.nativeBalance(address);
25
+ }
26
+ catch {
27
+ // A balance read is a courtesy, not a gate. If the RPC will not answer it,
28
+ // let the command proceed and fail with the real error.
29
+ return;
30
+ }
31
+ if (balance > 0n)
32
+ return;
33
+ throw new CliError(`wallet ${address} has 0 ETH on Base Sepolia, so it cannot pay for gas`, {
34
+ exitCode: 3,
35
+ hint: `fund it at ${BASE_SEPOLIA_FAUCET_URL}, then re-run. (Gas is ETH; the stream itself is escrowed in USDC, which is a separate balance.)`,
36
+ });
37
+ }
38
+ /**
39
+ * Refuse to broadcast a hire the wallet cannot fund.
40
+ *
41
+ * The sibling of `assertCanPayGas`, for the OTHER balance. Gas is ETH and the
42
+ * deposit is USDC: they are separate balances on separate tokens, so a wallet
43
+ * that passes the gas check can still hold no USDC at all. Without this the
44
+ * `open` path sends the USDC approval FIRST — which succeeds, because approving
45
+ * an amount you do not hold is legal — and then reverts inside `transferFrom`,
46
+ * having already spent gas to learn something that was one `balanceOf` away.
47
+ *
48
+ * Deliberately NOT an allowance check. The CLI's own open path grants the
49
+ * bounded approval it needs (`approveTxHash` in the result), so a missing
50
+ * allowance is a step of the command, not a precondition for it; gating on it
51
+ * would refuse a hire that was about to work. Balance is the fact the CLI
52
+ * cannot fix for you.
53
+ */
54
+ export async function assertCanFundStream(read, address, budgetUsdc) {
55
+ let balance;
56
+ try {
57
+ balance = await read.usdcBalance(address);
58
+ }
59
+ catch {
60
+ // Same courtesy rule as the gas check: an RPC that will not answer a
61
+ // balance read must not become this command's failure mode. Proceed and let
62
+ // the real error surface.
63
+ return;
64
+ }
65
+ if (balance >= budgetUsdc)
66
+ return;
67
+ throw new CliError(`wallet ${address} holds ${formatUsdc(balance)} but --budget is ${formatUsdc(budgetUsdc)}`, {
68
+ exitCode: 3,
69
+ hint: `the deposit is escrowed in USDC — fund the wallet at ${CIRCLE_USDC_FAUCET_URL} (Base Sepolia), then re-run. (Gas is a separate ETH balance.)`,
70
+ });
71
+ }
72
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/cli/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,qDAAqD;AACrD,MAAM,CAAC,MAAM,uBAAuB,GAClC,8CAA8C,CAAC;AAEjD,iEAAiE;AACjE,MAAM,CAAC,MAAM,sBAAsB,GAAG,2BAA2B,CAAC;AAElE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAmB,EACnB,OAAsB;IAEtB,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;QAC3E,wDAAwD;QACxD,OAAO;IACT,CAAC;IACD,IAAI,OAAO,GAAG,EAAE;QAAE,OAAO;IAEzB,MAAM,IAAI,QAAQ,CAChB,UAAU,OAAO,sDAAsD,EACvE;QACE,QAAQ,EAAE,CAAC;QACX,IAAI,EAAE,cAAc,uBAAuB,kGAAkG;KAC9I,CACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAmB,EACnB,OAAsB,EACtB,UAAkB;IAElB,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;QACrE,4EAA4E;QAC5E,0BAA0B;QAC1B,OAAO;IACT,CAAC;IACD,IAAI,OAAO,IAAI,UAAU;QAAE,OAAO;IAElC,MAAM,IAAI,QAAQ,CAChB,UAAU,OAAO,UAAU,UAAU,CAAC,OAAO,CAAC,oBAAoB,UAAU,CAAC,UAAU,CAAC,EAAE,EAC1F;QACE,QAAQ,EAAE,CAAC;QACX,IAAI,EAAE,wDAAwD,sBAAsB,gEAAgE;KACrJ,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * A heartbeat on stderr for commands that can take a while.
3
+ *
4
+ * A live acceptance run saw `close` take 8s once and 142s the next time, and
5
+ * `status` calls run past two minutes with nothing on screen. With no output at
6
+ * all, a slow RPC and a wedged process look identical, and the only safe reading
7
+ * of that ambiguity — on a command that may have already broadcast a
8
+ * transaction — is the expensive one: wait, or kill it and risk double-sending.
9
+ *
10
+ * So the CLI narrates. Not progress towards a known total (there isn't one), but
11
+ * proof of life plus elapsed time, which is what distinguishes "slow" from
12
+ * "stuck". stderr in BOTH modes, so `--json` stdout stays a single parseable
13
+ * document.
14
+ */
15
+ export interface Heartbeat {
16
+ /** Stops the ticker. Safe to call more than once. */
17
+ readonly stop: () => void;
18
+ }
19
+ /** Silence before the first tick — below this, a command is simply fast. */
20
+ export declare const HEARTBEAT_DELAY_MS = 8000;
21
+ /** Gap between ticks once it has started. */
22
+ export declare const HEARTBEAT_INTERVAL_MS = 10000;
23
+ export interface HeartbeatOptions {
24
+ readonly delayMs?: number;
25
+ readonly intervalMs?: number;
26
+ /** Injectable for tests; defaults to the global timers. */
27
+ readonly setTimer?: typeof setTimeout;
28
+ readonly clearTimer?: typeof clearTimeout;
29
+ readonly now?: () => number;
30
+ }
31
+ /**
32
+ * Start narrating `label`. Nothing is printed unless the work outlasts
33
+ * `delayMs`, so a fast command is silent and a slow one is legible.
34
+ */
35
+ export declare function startHeartbeat(note: (line: string) => void, label: string, options?: HeartbeatOptions): Heartbeat;
36
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/cli/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,SAAS;IACxB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,OAAQ,CAAC;AACxC,6CAA6C;AAC7C,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,UAAU,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,YAAY,CAAC;IAC1C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC5B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,gBAAqB,GAC7B,SAAS,CAiCX"}
@@ -0,0 +1,40 @@
1
+ /** Silence before the first tick — below this, a command is simply fast. */
2
+ export const HEARTBEAT_DELAY_MS = 8_000;
3
+ /** Gap between ticks once it has started. */
4
+ export const HEARTBEAT_INTERVAL_MS = 10_000;
5
+ /**
6
+ * Start narrating `label`. Nothing is printed unless the work outlasts
7
+ * `delayMs`, so a fast command is silent and a slow one is legible.
8
+ */
9
+ export function startHeartbeat(note, label, options = {}) {
10
+ const delayMs = options.delayMs ?? HEARTBEAT_DELAY_MS;
11
+ const intervalMs = options.intervalMs ?? HEARTBEAT_INTERVAL_MS;
12
+ const setTimer = options.setTimer ?? setTimeout;
13
+ const clearTimer = options.clearTimer ?? clearTimeout;
14
+ const now = options.now ?? Date.now;
15
+ const startedAt = now();
16
+ let timer;
17
+ let stopped = false;
18
+ const tick = () => {
19
+ if (stopped)
20
+ return;
21
+ const elapsed = Math.round((now() - startedAt) / 1000);
22
+ note(`… still working: ${label} (${elapsed}s elapsed). Slow RPC or oracle, not a hang — nothing is retried silently.`);
23
+ schedule(intervalMs);
24
+ };
25
+ const schedule = (ms) => {
26
+ timer = setTimer(tick, ms);
27
+ // Never hold the process open on account of the narration.
28
+ timer.unref?.();
29
+ };
30
+ schedule(delayMs);
31
+ return {
32
+ stop() {
33
+ stopped = true;
34
+ if (timer !== undefined)
35
+ clearTimer(timer);
36
+ timer = undefined;
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/cli/progress.ts"],"names":[],"mappings":"AAmBA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACxC,6CAA6C;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAW5C;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,IAA4B,EAC5B,KAAa,EACb,UAA4B,EAAE;IAE9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,kBAAkB,CAAC;IACtD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,qBAAqB,CAAC;IAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC;IAChD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,YAAY,CAAC;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IAEpC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC;IACxB,IAAI,KAAgD,CAAC;IACrD,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,IAAI,GAAG,GAAS,EAAE;QACtB,IAAI,OAAO;YAAE,OAAO;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;QACvD,IAAI,CACF,oBAAoB,KAAK,KAAK,OAAO,2EAA2E,CACjH,CAAC;QACF,QAAQ,CAAC,UAAU,CAAC,CAAC;IACvB,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAQ,EAAE;QACpC,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC3B,2DAA2D;QAC1D,KAAgC,CAAC,KAAK,EAAE,EAAE,CAAC;IAC9C,CAAC,CAAC;IACF,QAAQ,CAAC,OAAO,CAAC,CAAC;IAElB,OAAO;QACL,IAAI;YACF,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,KAAK,KAAK,SAAS;gBAAE,UAAU,CAAC,KAAK,CAAC,CAAC;YAC3C,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { type CliStreams } from "./output.js";
2
+ import { type CliDependencies } from "./deps.js";
3
+ import type { CommandSpec } from "./context.js";
4
+ /**
5
+ * The command surface, in the order the product loop runs:
6
+ * discover -> open -> invoke -> watch/status -> close -> reclaim, then the
7
+ * operator's own redemption (`claim`) and the buyer's last-resort exit
8
+ * (`reclaim-unverified`). `streams` (which of them are mine?) sits inside that
9
+ * loop; `mcp` (run the same loop from an MCP host) sits after it.
10
+ */
11
+ export declare const COMMANDS: readonly CommandSpec[];
12
+ export interface RunCliOptions {
13
+ readonly argv: readonly string[];
14
+ readonly env?: NodeJS.ProcessEnv;
15
+ readonly streams?: CliStreams;
16
+ readonly deps?: CliDependencies;
17
+ }
18
+ /**
19
+ * Runs one CLI invocation and returns the process exit code. Pure in its
20
+ * inputs: argv, env, output sinks and side-effecting dependencies are all
21
+ * injected, so the whole surface is testable without a key or an RPC.
22
+ */
23
+ export declare function runCli(options: RunCliOptions): Promise<number>;
24
+ export declare function renderHelp(commandName?: string): string;
25
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAQA,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAGzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAchD;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,WAAW,EAY1C,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,eAAe,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAiEpE;AAqBD,wBAAgB,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CA8DvD"}