@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,173 @@
1
+ import { assertKnownFlags, booleanFlag, parseArgs } from "./args.js";
2
+ import { CONFIG_FLAGS, GLOBAL_FLAGS, TESTNET_CHAIN_IDS, resolveConfig, } from "./config.js";
3
+ import { CliError, describeError, usageError } from "./errors.js";
4
+ import { createPrinter } from "./output.js";
5
+ import { startHeartbeat } from "./progress.js";
6
+ import { defaultCliDependencies } from "./deps.js";
7
+ import { packageVersion } from "./version.js";
8
+ import { CDP_ENV_VARS, PRIVATE_KEY_ENV } from "./wallet.js";
9
+ import { claimCommand } from "./commands/claim.js";
10
+ import { closeCommand } from "./commands/close.js";
11
+ import { discoverCommand } from "./commands/discover.js";
12
+ import { invokeCommand } from "./commands/invoke.js";
13
+ import { mcpCommand } from "./commands/mcp.js";
14
+ import { openCommand } from "./commands/open.js";
15
+ import { reclaimCommand } from "./commands/reclaim.js";
16
+ import { reclaimUnverifiedCommand } from "./commands/reclaim-unverified.js";
17
+ import { statusCommand } from "./commands/status.js";
18
+ import { streamsCommand } from "./commands/streams.js";
19
+ import { watchCommand } from "./commands/watch.js";
20
+ /**
21
+ * The command surface, in the order the product loop runs:
22
+ * discover -> open -> invoke -> watch/status -> close -> reclaim, then the
23
+ * operator's own redemption (`claim`) and the buyer's last-resort exit
24
+ * (`reclaim-unverified`). `streams` (which of them are mine?) sits inside that
25
+ * loop; `mcp` (run the same loop from an MCP host) sits after it.
26
+ */
27
+ export const COMMANDS = [
28
+ discoverCommand,
29
+ openCommand,
30
+ statusCommand,
31
+ streamsCommand,
32
+ watchCommand,
33
+ invokeCommand,
34
+ closeCommand,
35
+ reclaimCommand,
36
+ reclaimUnverifiedCommand,
37
+ claimCommand,
38
+ mcpCommand,
39
+ ];
40
+ /**
41
+ * Runs one CLI invocation and returns the process exit code. Pure in its
42
+ * inputs: argv, env, output sinks and side-effecting dependencies are all
43
+ * injected, so the whole surface is testable without a key or an RPC.
44
+ */
45
+ export async function runCli(options) {
46
+ const env = options.env ?? process.env;
47
+ const streams = options.streams ?? {
48
+ stdout: (line) => process.stdout.write(`${line}\n`),
49
+ stderr: (line) => process.stderr.write(`${line}\n`),
50
+ };
51
+ const deps = options.deps ?? defaultCliDependencies;
52
+ let json = false;
53
+ try {
54
+ const args = parseArgs(options.argv);
55
+ json = booleanFlag(args, "json");
56
+ const out = createPrinter(streams, json);
57
+ // `--version` is checked before the bare-invocation help branch: `metrik
58
+ // --version` parses to no command at all.
59
+ if (args.command === "version" || booleanFlag(args, "version")) {
60
+ streams.stdout(packageVersion());
61
+ return 0;
62
+ }
63
+ if (args.command === null || args.command === "help") {
64
+ // A misspelled TOP-LEVEL flag must fail like a misspelled per-command one
65
+ // does. Printing help and exiting 0 tells a script the invocation
66
+ // succeeded, which is how a typo goes unnoticed.
67
+ assertKnownFlags(args, [...GLOBAL_FLAGS, "version"]);
68
+ streams.stdout(renderHelp(args.positionals[0]));
69
+ return 0;
70
+ }
71
+ const command = COMMANDS.find((spec) => spec.name === args.command);
72
+ if (command === undefined) {
73
+ throw usageError(`unknown command: ${args.command}`, `commands: ${COMMANDS.map((spec) => spec.name).join(", ")}`);
74
+ }
75
+ if (booleanFlag(args, "help")) {
76
+ streams.stdout(renderHelp(command.name));
77
+ return 0;
78
+ }
79
+ assertKnownFlags(args, [
80
+ ...GLOBAL_FLAGS,
81
+ ...CONFIG_FLAGS,
82
+ ...command.flags,
83
+ ]);
84
+ const config = resolveConfig(args, env);
85
+ // Every command gets the heartbeat, in one place rather than per command:
86
+ // any of them can be the one waiting on a slow endpoint, and a rule with an
87
+ // exception is a rule someone forgets to apply to the next command.
88
+ const heartbeat = startHeartbeat(out.note, `metrik ${command.name}`);
89
+ try {
90
+ await command.run({ args, config, env, out, deps });
91
+ }
92
+ finally {
93
+ heartbeat.stop();
94
+ }
95
+ return 0;
96
+ }
97
+ catch (error) {
98
+ if (error instanceof CliError) {
99
+ emitFailure(streams, json, error.message, error.hint, error.exitCode);
100
+ return error.exitCode;
101
+ }
102
+ emitFailure(streams, json, describeError(error), undefined, 4);
103
+ return 4;
104
+ }
105
+ }
106
+ function emitFailure(streams, json, message, hint, exitCode) {
107
+ if (json) {
108
+ // The failure goes to stderr even in --json mode so stdout stays either a
109
+ // result document or nothing at all.
110
+ streams.stderr(JSON.stringify({ error: message, hint: hint ?? null, exitCode }));
111
+ return;
112
+ }
113
+ streams.stderr(`error: ${message}`);
114
+ if (hint !== undefined)
115
+ streams.stderr(` ${hint}`);
116
+ }
117
+ export function renderHelp(commandName) {
118
+ const command = COMMANDS.find((spec) => spec.name === commandName);
119
+ if (command !== undefined) {
120
+ return [
121
+ `metrik ${command.name} — ${command.summary}`,
122
+ "",
123
+ `Usage: ${command.usage}`,
124
+ "",
125
+ command.flags.length === 0
126
+ ? "Command flags: (none)"
127
+ : `Command flags: ${command.flags.map((flag) => `--${flag}`).join(" ")}`,
128
+ `Settlement flags: ${CONFIG_FLAGS.map((flag) => `--${flag}`).join(" ")}`,
129
+ "Output flags: --json",
130
+ ...(command.signs
131
+ ? [
132
+ "",
133
+ `Broadcasts a transaction. Requires a wallet in the environment: ${PRIVATE_KEY_ENV}, or ${CDP_ENV_VARS.join(" + ")}.`,
134
+ ]
135
+ : command.requiresKey === true
136
+ ? [
137
+ "",
138
+ `Broadcasts nothing, but signs an off-chain EIP-712 capability, so it requires a wallet in the environment: ${PRIVATE_KEY_ENV}, or ${CDP_ENV_VARS.join(" + ")}.`,
139
+ ]
140
+ : []),
141
+ ].join("\n");
142
+ }
143
+ const width = COMMANDS.reduce((max, spec) => Math.max(max, spec.name.length), 0);
144
+ return [
145
+ `metrik ${packageVersion()} — pay for verified delivery, metered by the second`,
146
+ "",
147
+ "You rent a verified-live endpoint BY TIME, not per call: the oracle probes it and the",
148
+ "meter runs on availability that verified. One request and a thousand cost the same",
149
+ "second, and the clock keeps running while you send none. `metrik close` stops it.",
150
+ "",
151
+ "Usage: metrik <command> [options]",
152
+ "",
153
+ "Commands:",
154
+ ...COMMANDS.map((spec) => ` ${spec.name.padEnd(width)} ${spec.summary}${spec.signs ? " [broadcasts a tx]" : spec.requiresKey === true ? " [needs a key]" : ""}`),
155
+ "",
156
+ "Global flags:",
157
+ " --json machine-readable output on stdout",
158
+ " --help this text, or `metrik <command> --help`",
159
+ "",
160
+ "Settlement flags (all default to Metrik's Base Sepolia deployment):",
161
+ " --chain-id --rpc-url --escrow --usdc --oracle-url --registry-url",
162
+ "",
163
+ "Wallet (read from the environment only; never accepted as a flag):",
164
+ ` ${PRIVATE_KEY_ENV} a Base Sepolia test key. Checked first.`,
165
+ ` ${CDP_ENV_VARS.join(", ")}`,
166
+ " a Coinbase CDP Server Wallet v2 account. Used when no private key is set.",
167
+ " A credential on the command line lands in shell history; these never are.",
168
+ "",
169
+ `TESTNET ONLY: this CLI refuses any chain outside ${TESTNET_CHAIN_IDS.join(", ")} (Base Sepolia),`,
170
+ "and re-checks the chain id the RPC actually serves before signing. There is no override.",
171
+ ].join("\n");
172
+ }
173
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Pure block-range arithmetic for the escrow log scan behind `metrik streams`.
3
+ * No RPC, no clock, no env — so the coverage rules below are unit-testable
4
+ * without a network, which is the point: they decide when an empty result is
5
+ * allowed to be rendered as "you have no streams".
6
+ *
7
+ * ## Why the anchor is the deploy block
8
+ *
9
+ * A fixed lookback ("the last N blocks") cannot describe coverage: a wallet
10
+ * whose stream predates the window is shown an empty list with nothing to
11
+ * distinguish it from a wallet that never opened one. For a payments tool,
12
+ * telling someone their escrowed funds do not exist is the worst failure we
13
+ * have. The escrow has NO history before its deploy block, so that block is the
14
+ * honest anchor — and whether the budget reached it is then a fact the command
15
+ * can state.
16
+ *
17
+ * ## Why the window is 10 000 blocks
18
+ *
19
+ * `buyer` and `operator` are INDEXED on `StreamOpened`, so a per-wallet scan is
20
+ * a server-side topic filter whose response is tiny regardless of range. What
21
+ * public RPCs cap is the per-call BLOCK RANGE, and a topic filter does not lift
22
+ * it: `sepolia.base.org` answers a wider range with `-32614 "eth_getLogs is
23
+ * limited to a 10,000 range"`. So the page size is the cap, not a guess below
24
+ * it.
25
+ */
26
+ /**
27
+ * getLogs page size. The window is `chunk + 1` blocks (bounds inclusive), so
28
+ * 9 999 is the largest page `sepolia.base.org` accepts.
29
+ */
30
+ export declare const LOG_SCAN_CHUNK = 9999n;
31
+ /**
32
+ * Window budget for one scan. 400 x 10 000 = 4 000 000 blocks, comfortably more
33
+ * than the live escrow's history (~1.06M blocks on 2026-09-17), so the default
34
+ * scan is complete rather than merely large. It is a CEILING, not a fixed cost:
35
+ * windows are built for the actual anchor-to-head span. Exceeding it is not an
36
+ * error — it is reported as `degraded`.
37
+ */
38
+ export declare const LOG_SCAN_MAX_WINDOWS = 400;
39
+ export interface ScanRange {
40
+ readonly fromBlock: bigint;
41
+ readonly toBlock: bigint;
42
+ /** Inclusive `[from, to]` windows, in ascending order. */
43
+ readonly windows: readonly (readonly [bigint, bigint])[];
44
+ /** True iff the budget could NOT reach `anchor`, i.e. the scan is partial. */
45
+ readonly degraded: boolean;
46
+ }
47
+ /**
48
+ * Page `[anchor, head]` into non-overlapping inclusive windows.
49
+ *
50
+ * An RPC that is behind the deployment yields an empty-but-valid range rather
51
+ * than a negative one, and an anchor past the head is clamped: a node still
52
+ * syncing must not produce a nonsense scan.
53
+ */
54
+ export declare function escrowScanRange(head: bigint, anchorBlock: bigint, chunk?: bigint, maxWindows?: number): ScanRange;
55
+ //# sourceMappingURL=scan-range.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-range.d.ts","sourceRoot":"","sources":["../../src/cli/scan-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAS,CAAC;AAErC;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;IACzD,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,MAAuB,EAC9B,UAAU,GAAE,MAA6B,GACxC,SAAS,CAaX"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Pure block-range arithmetic for the escrow log scan behind `metrik streams`.
3
+ * No RPC, no clock, no env — so the coverage rules below are unit-testable
4
+ * without a network, which is the point: they decide when an empty result is
5
+ * allowed to be rendered as "you have no streams".
6
+ *
7
+ * ## Why the anchor is the deploy block
8
+ *
9
+ * A fixed lookback ("the last N blocks") cannot describe coverage: a wallet
10
+ * whose stream predates the window is shown an empty list with nothing to
11
+ * distinguish it from a wallet that never opened one. For a payments tool,
12
+ * telling someone their escrowed funds do not exist is the worst failure we
13
+ * have. The escrow has NO history before its deploy block, so that block is the
14
+ * honest anchor — and whether the budget reached it is then a fact the command
15
+ * can state.
16
+ *
17
+ * ## Why the window is 10 000 blocks
18
+ *
19
+ * `buyer` and `operator` are INDEXED on `StreamOpened`, so a per-wallet scan is
20
+ * a server-side topic filter whose response is tiny regardless of range. What
21
+ * public RPCs cap is the per-call BLOCK RANGE, and a topic filter does not lift
22
+ * it: `sepolia.base.org` answers a wider range with `-32614 "eth_getLogs is
23
+ * limited to a 10,000 range"`. So the page size is the cap, not a guess below
24
+ * it.
25
+ */
26
+ /**
27
+ * getLogs page size. The window is `chunk + 1` blocks (bounds inclusive), so
28
+ * 9 999 is the largest page `sepolia.base.org` accepts.
29
+ */
30
+ export const LOG_SCAN_CHUNK = 9999n;
31
+ /**
32
+ * Window budget for one scan. 400 x 10 000 = 4 000 000 blocks, comfortably more
33
+ * than the live escrow's history (~1.06M blocks on 2026-09-17), so the default
34
+ * scan is complete rather than merely large. It is a CEILING, not a fixed cost:
35
+ * windows are built for the actual anchor-to-head span. Exceeding it is not an
36
+ * error — it is reported as `degraded`.
37
+ */
38
+ export const LOG_SCAN_MAX_WINDOWS = 400;
39
+ /**
40
+ * Page `[anchor, head]` into non-overlapping inclusive windows.
41
+ *
42
+ * An RPC that is behind the deployment yields an empty-but-valid range rather
43
+ * than a negative one, and an anchor past the head is clamped: a node still
44
+ * syncing must not produce a nonsense scan.
45
+ */
46
+ export function escrowScanRange(head, anchorBlock, chunk = LOG_SCAN_CHUNK, maxWindows = LOG_SCAN_MAX_WINDOWS) {
47
+ const anchor = anchorBlock < 0n ? 0n : anchorBlock > head ? head : anchorBlock;
48
+ const maxSpan = (chunk + 1n) * BigInt(maxWindows);
49
+ const degraded = head - anchor > maxSpan;
50
+ const fromBlock = degraded ? head - maxSpan : anchor;
51
+ const windows = [];
52
+ for (let start = fromBlock; start <= head; start += chunk + 1n) {
53
+ windows.push([start, start + chunk > head ? head : start + chunk]);
54
+ }
55
+ return { fromBlock, toBlock: head, windows, degraded };
56
+ }
57
+ //# sourceMappingURL=scan-range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-range.js","sourceRoot":"","sources":["../../src/cli/scan-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAM,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAWxC;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,WAAmB,EACnB,QAAgB,cAAc,EAC9B,aAAqB,oBAAoB;IAEzC,MAAM,MAAM,GACV,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;IAClE,MAAM,OAAO,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC;IACzC,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAErD,MAAM,OAAO,GAAkC,EAAE,CAAC;IAClD,KAAK,IAAI,KAAK,GAAG,SAAS,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AACzD,CAAC"}
@@ -0,0 +1,90 @@
1
+ import type { CheckpointProof, StreamV2 } from "@absol-labs/sdk";
2
+ import { type AttesterSet } from "./attesters.js";
3
+ import { type EscapeHatchWindow } from "./escape-hatch.js";
4
+ import type { CliReadClient } from "./deps.js";
5
+ /**
6
+ * Whether the accrual figures on this screen are FINAL.
7
+ *
8
+ * `reclaimableFor` is answered against a checkpoint's cumulative, and the
9
+ * escrow's own `reclaimWithProof` refuses until a checkpoint's `checkedAt`
10
+ * reaches the stream's stop time (`SettlementWindowOpen`). Between closing a
11
+ * stream and the first checkpoint that covers the close, the latest checkpoint
12
+ * therefore describes a SHORTER stream than the one that exists — so the
13
+ * reclaimable figure computed from it is larger than the amount that can
14
+ * actually be reclaimed, and shrinks when the covering checkpoint lands.
15
+ *
16
+ * A live acceptance run read `reclaimable: 1400` immediately after `close`, `0`
17
+ * two minutes later, and got `NothingToReclaim()` from the reclaim in between.
18
+ * Nobody reads "buyer reclaimable 0.0014 USDC" as "a provisional figure that
19
+ * may fall to zero" — they read it as money they have. So while this is
20
+ * pending, the CLI prints no settled-looking number at all.
21
+ */
22
+ export interface SettlementCoverage {
23
+ /**
24
+ * The instant accrual stops: `closedAt`, or `expiresAt` once it has passed.
25
+ * `null` while the stream is still running, where there is nothing to cover.
26
+ */
27
+ readonly stopAt: number | null;
28
+ /** How far the oracle has published. `null` when it could not be read. */
29
+ readonly coveredUpTo: number | null;
30
+ /** True when a stop time exists and no known checkpoint reaches it. */
31
+ readonly pending: boolean;
32
+ }
33
+ /**
34
+ * Coverage from the three facts that decide it. Pure, so the rule is testable
35
+ * without an RPC.
36
+ *
37
+ * Unknown coverage counts as PENDING, not as covered: the buyer-favouring error
38
+ * is to withhold a number we cannot stand behind, never to print one we cannot.
39
+ */
40
+ export declare function settlementCoverage(stream: Pick<StreamV2, "closedAt" | "expiresAt">, latestCheckpointCheckedAt: number | null, nowSeconds: number): SettlementCoverage;
41
+ /**
42
+ * A stream as the CLI reports it.
43
+ *
44
+ * The accrual figures come from the ORACLE's checkpoint proof, not from the
45
+ * stream tuple. `StreamEscrowV2.getStream` reports `claimedCumulative = 0` and
46
+ * `settledCumulative = 0` for a stream's whole active life — `settledCumulative`
47
+ * is written by `reclaim` — so a status built from stream fields would print
48
+ * "earned: 0" for a stream that had been delivering for an hour.
49
+ */
50
+ export interface StreamReport {
51
+ readonly streamId: `0x${string}`;
52
+ readonly stream: StreamV2;
53
+ /** `null` until the oracle has published a checkpoint covering this stream. */
54
+ readonly proof: CheckpointProof | null;
55
+ /** Why there is no proof yet, when applicable. */
56
+ readonly proofUnavailable: string | null;
57
+ readonly claimable: bigint | null;
58
+ readonly reclaimable: bigint | null;
59
+ readonly protocolFeeBps: number | null;
60
+ /**
61
+ * When the buyer's no-proof escape hatch opens, and whether it already has.
62
+ * `null` only when the escrow would not answer.
63
+ *
64
+ * Without this a buyer had no command that could tell them "the proof path is
65
+ * blocked, but the no-proof path opens at T+grace" — the two facts they need
66
+ * together when the oracle has stopped answering.
67
+ */
68
+ readonly escapeHatch: EscapeHatchWindow | null;
69
+ /**
70
+ * How far the oracle has published (`latestCheckpointCheckedAt`). A stale
71
+ * value beside a blocked reclaim IS the explanation for the blocked reclaim.
72
+ */
73
+ readonly latestCheckpointCheckedAt: number | null;
74
+ readonly nowSeconds: number;
75
+ /** `local` when the chain's clock could not be read and the caller's was used. */
76
+ readonly clockSource: "chain" | "local";
77
+ /** Whether `claimable` / `reclaimable` are final. See {@link SettlementCoverage}. */
78
+ readonly settlement: SettlementCoverage;
79
+ /**
80
+ * The escrow's oracle signer set, and therefore whether this stream's
81
+ * operator is also one of the parties attesting to its own delivery.
82
+ * `signers: null` means the set could not be read — which is UNKNOWN, not
83
+ * "no overlap".
84
+ */
85
+ readonly attesters: AttesterSet;
86
+ }
87
+ export declare function readStreamReport(read: CliReadClient, streamId: `0x${string}`, nowSeconds: number): Promise<StreamReport>;
88
+ export declare function streamReportJson(report: StreamReport): unknown;
89
+ export declare function streamReportRows(report: StreamReport): (readonly [string, string])[];
90
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGjE,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAG,WAAW,CAAC,EAChD,yBAAyB,EAAE,MAAM,GAAG,IAAI,EACxC,UAAU,EAAE,MAAM,GACjB,kBAAkB,CAgBpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IACvC,kDAAkD;IAClD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/C;;;OAGG;IACH,QAAQ,CAAC,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,CAAC;IACxC,qFAAqF;IACrF,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;CACjC;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,aAAa,EACnB,QAAQ,EAAE,KAAK,MAAM,EAAE,EACvB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,CAAC,CAwEvB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAgE9D;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,GACnB,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAuF/B"}
@@ -0,0 +1,252 @@
1
+ import { formatDuration, formatUsdc } from "./amounts.js";
2
+ import { operatorAttestsOwnDelivery, readAttesterSet, } from "./attesters.js";
3
+ import { describeError } from "./errors.js";
4
+ import { describeEscapeHatch, escapeHatchWindow, formatTimestamp, readChainNow, } from "./escape-hatch.js";
5
+ /**
6
+ * Coverage from the three facts that decide it. Pure, so the rule is testable
7
+ * without an RPC.
8
+ *
9
+ * Unknown coverage counts as PENDING, not as covered: the buyer-favouring error
10
+ * is to withhold a number we cannot stand behind, never to print one we cannot.
11
+ */
12
+ export function settlementCoverage(stream, latestCheckpointCheckedAt, nowSeconds) {
13
+ const stopAt = stream.closedAt > 0
14
+ ? stream.closedAt
15
+ : nowSeconds >= stream.expiresAt
16
+ ? stream.expiresAt
17
+ : null;
18
+ const coveredUpTo = latestCheckpointCheckedAt !== null && latestCheckpointCheckedAt > 0
19
+ ? latestCheckpointCheckedAt
20
+ : null;
21
+ return {
22
+ stopAt,
23
+ coveredUpTo,
24
+ pending: stopAt !== null && (coveredUpTo === null || coveredUpTo < stopAt),
25
+ };
26
+ }
27
+ export async function readStreamReport(read, streamId, nowSeconds) {
28
+ const stream = await read.getStreamV2(streamId);
29
+ // Timing is answered against the chain, because every deadline on this screen
30
+ // — expiry, and the escape hatch in particular — is compared against
31
+ // `block.timestamp` by the escrow, not against this machine's clock.
32
+ const now = await readChainNow(read, nowSeconds);
33
+ let proof = null;
34
+ let proofUnavailable = null;
35
+ try {
36
+ proof = await read.checkpointProof(streamId);
37
+ }
38
+ catch (error) {
39
+ proofUnavailable = describeError(error);
40
+ }
41
+ let claimable = null;
42
+ let reclaimable = null;
43
+ if (proof !== null) {
44
+ [claimable, reclaimable] = await Promise.all([
45
+ read.claimableForV2(streamId, proof.cumulativeAmount),
46
+ read.reclaimableForV2(streamId, proof.cumulativeAmount),
47
+ ]);
48
+ }
49
+ let protocolFeeBps = null;
50
+ try {
51
+ protocolFeeBps = await read.protocolFeeBps();
52
+ }
53
+ catch {
54
+ protocolFeeBps = null;
55
+ }
56
+ let escapeHatch = null;
57
+ try {
58
+ escapeHatch = escapeHatchWindow(stream, await read.escapeGraceSeconds(), now.seconds);
59
+ }
60
+ catch {
61
+ escapeHatch = null;
62
+ }
63
+ let latestCheckpointCheckedAt = null;
64
+ try {
65
+ latestCheckpointCheckedAt = await read.latestCheckpointCheckedAt();
66
+ }
67
+ catch {
68
+ latestCheckpointCheckedAt = null;
69
+ }
70
+ const settlement = settlementCoverage(stream, latestCheckpointCheckedAt, now.seconds);
71
+ const attesters = await readAttesterSet(read);
72
+ return {
73
+ streamId,
74
+ stream,
75
+ proof,
76
+ proofUnavailable,
77
+ claimable,
78
+ reclaimable,
79
+ protocolFeeBps,
80
+ escapeHatch,
81
+ latestCheckpointCheckedAt,
82
+ nowSeconds: now.seconds,
83
+ clockSource: now.source,
84
+ settlement,
85
+ attesters,
86
+ };
87
+ }
88
+ export function streamReportJson(report) {
89
+ const { stream, proof } = report;
90
+ return {
91
+ streamId: report.streamId,
92
+ // StreamEscrowV2 has exactly two states. There is no "paused".
93
+ status: stream.status,
94
+ reclaimed: stream.reclaimed,
95
+ buyer: stream.buyer,
96
+ operator: stream.operator,
97
+ serviceRef: stream.serviceRef,
98
+ deposit: stream.deposit,
99
+ ratePerSecond: stream.ratePerSecond,
100
+ claimedCumulative: stream.claimedCumulative,
101
+ settledCumulative: stream.settledCumulative,
102
+ feesPaid: stream.feesPaid,
103
+ openedAt: stream.openedAt,
104
+ expiresAt: stream.expiresAt,
105
+ closedAt: stream.closedAt,
106
+ protocolFeeBps: report.protocolFeeBps,
107
+ verifiedAccrual: proof === null
108
+ ? null
109
+ : {
110
+ cumulativeAmount: proof.cumulativeAmount,
111
+ checkpointId: proof.checkpointId,
112
+ checkedAt: proof.checkedAt,
113
+ root: proof.root,
114
+ },
115
+ verifiedAccrualUnavailable: report.proofUnavailable,
116
+ // `null` while settlement is pending. A consumer that reads this field gets
117
+ // either an amount that can actually be obtained or nothing — never a
118
+ // settled-looking number derived from a checkpoint that predates the
119
+ // stream's stop time. The superseded figure is still available, explicitly
120
+ // labelled, under `settlement.provisionalReclaimable`.
121
+ claimable: report.claimable,
122
+ reclaimable: report.settlement.pending ? null : report.reclaimable,
123
+ settlement: {
124
+ pending: report.settlement.pending,
125
+ stopAt: report.settlement.stopAt,
126
+ coveredUpTo: report.settlement.coveredUpTo,
127
+ provisionalReclaimable: report.settlement.pending
128
+ ? report.reclaimable
129
+ : null,
130
+ provisionalClaimable: report.settlement.pending ? report.claimable : null,
131
+ },
132
+ // Who attests. `operatorIsOracleSigner: null` means the signer set could
133
+ // not be read — UNKNOWN, never "no overlap".
134
+ oracleSigners: report.attesters.signers,
135
+ oracleSignersUnavailable: report.attesters.unavailable,
136
+ operatorIsOracleSigner: operatorAttestsOwnDelivery(report.attesters, stream.operator),
137
+ latestCheckpointCheckedAt: report.latestCheckpointCheckedAt,
138
+ escapeHatch: report.escapeHatch === null
139
+ ? null
140
+ : {
141
+ escapeGraceSeconds: report.escapeHatch.graceSeconds,
142
+ readyAt: report.escapeHatch.readyAt,
143
+ ready: report.escapeHatch.ready,
144
+ secondsUntilReady: report.escapeHatch.secondsRemaining,
145
+ },
146
+ };
147
+ }
148
+ export function streamReportRows(report) {
149
+ const { stream, proof } = report;
150
+ const rows = [
151
+ [
152
+ "status",
153
+ stream.reclaimed ? `${stream.status} (reclaimed)` : stream.status,
154
+ ],
155
+ ["buyer", stream.buyer],
156
+ ["operator", stream.operator],
157
+ ["serviceRef", stream.serviceRef],
158
+ ["deposit", formatUsdc(stream.deposit)],
159
+ ["rate", `${formatUsdc(stream.ratePerSecond)} / second`],
160
+ ["opened", formatTimestamp(stream.openedAt)],
161
+ ["expires", describeDeadline(stream.expiresAt, report.nowSeconds)],
162
+ ];
163
+ if (stream.closedAt > 0) {
164
+ rows.push(["closed", formatTimestamp(stream.closedAt)]);
165
+ }
166
+ rows.push([
167
+ "verified accrual",
168
+ proof === null
169
+ ? `not checkpointed yet (${report.proofUnavailable ?? "no proof"})`
170
+ : `${formatUsdc(proof.cumulativeAmount)} @ checkpoint ${proof.checkpointId} (${formatTimestamp(Number(proof.checkedAt))})`,
171
+ ]);
172
+ // `claim` accepts ANY retained root, so the operator's balance is obtainable
173
+ // now — it is merely not FINAL until the covering checkpoint lands, and it
174
+ // can only grow. `reclaim` requires the LATEST root to reach the stop time,
175
+ // so the buyer's figure is not obtainable at all while that is pending: it is
176
+ // withheld rather than printed as money the buyer does not have.
177
+ rows.push([
178
+ "operator claimable",
179
+ report.claimable === null
180
+ ? "-"
181
+ : report.settlement.pending
182
+ ? `${formatUsdc(report.claimable)} so far — not final until the checkpoint covering the stop time lands`
183
+ : formatUsdc(report.claimable),
184
+ ]);
185
+ rows.push([
186
+ "buyer reclaimable",
187
+ report.settlement.pending
188
+ ? describePendingSettlement(report.settlement)
189
+ : report.reclaimable === null
190
+ ? "-"
191
+ : formatUsdc(report.reclaimable),
192
+ ]);
193
+ rows.push(["fees paid", formatUsdc(stream.feesPaid)]);
194
+ rows.push([
195
+ "oracle checkpoint",
196
+ report.latestCheckpointCheckedAt === null
197
+ ? "-"
198
+ : report.latestCheckpointCheckedAt <= 0
199
+ ? "none posted yet"
200
+ : `latest covers up to ${formatTimestamp(report.latestCheckpointCheckedAt)}`,
201
+ ]);
202
+ // The no-proof path. Printed for every stream, not only blocked ones: a buyer
203
+ // should learn that this exists before they need it.
204
+ rows.push([
205
+ "escape hatch",
206
+ report.escapeHatch === null
207
+ ? "-"
208
+ : `${describeEscapeHatch(report.escapeHatch)} — no-proof reclaim, forfeits the operator's unclaimed earnings`,
209
+ ]);
210
+ // The same row, read from the seller's side. `reclaimUnverified` pays the
211
+ // buyer the WHOLE remaining deposit with no proof, so an operator who has
212
+ // earned but not claimed loses it the moment that window opens. The window is
213
+ // `expiresAt + escapeGraceSeconds` and the grace is immutable on the live
214
+ // escrow, so the only thing an operator can do about it is claim in time —
215
+ // which they cannot do if nothing tells them the deadline exists.
216
+ if (report.escapeHatch !== null &&
217
+ report.claimable !== null &&
218
+ report.claimable > 0n) {
219
+ rows.push([
220
+ "operator deadline",
221
+ report.escapeHatch.ready
222
+ ? `${formatUsdc(report.claimable)} is unclaimed and the buyer's no-proof reclaim is ALREADY open — it would take this amount from the operator`
223
+ : `${formatUsdc(report.claimable)} is unclaimed; \`metrik claim\` it before ${formatTimestamp(report.escapeHatch.readyAt)}, after which a buyer's no-proof reclaim can take it`,
224
+ ]);
225
+ }
226
+ if (report.protocolFeeBps !== null) {
227
+ rows.push([
228
+ "protocol fee",
229
+ `${report.protocolFeeBps} bps (read from the escrow)`,
230
+ ]);
231
+ }
232
+ return rows;
233
+ }
234
+ /**
235
+ * What is being waited for, in the place a number used to be. Names the two
236
+ * timestamps whose ordering decides it, so the reader can see the wait end.
237
+ */
238
+ function describePendingSettlement(settlement) {
239
+ const stopAt = settlement.stopAt === null ? "unknown" : formatTimestamp(settlement.stopAt);
240
+ const covered = settlement.coveredUpTo === null
241
+ ? "unknown (the escrow would not answer)"
242
+ : formatTimestamp(settlement.coveredUpTo);
243
+ return `pending final checkpoint — the stream stopped at ${stopAt}, the oracle has published only to ${covered}. Reclaim reverts until a checkpoint reaches the stop time (~15-22s apart).`;
244
+ }
245
+ function describeDeadline(expiresAt, nowSeconds) {
246
+ const remaining = expiresAt - nowSeconds;
247
+ const suffix = remaining > 0
248
+ ? `in ${formatDuration(remaining)}`
249
+ : `${formatDuration(-remaining)} ago`;
250
+ return `${formatTimestamp(expiresAt)} — ${suffix}`;
251
+ }
252
+ //# sourceMappingURL=status.js.map