@jinn-network/client 0.1.7-canary.d4e4e183 → 0.1.7-canary.e68c8f43

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 (297) hide show
  1. package/README.md +67 -1
  2. package/dist/adapters/mech/adapter.d.ts +19 -1
  3. package/dist/adapters/mech/adapter.js +130 -14
  4. package/dist/adapters/mech/adapter.js.map +1 -1
  5. package/dist/adapters/mech/contracts.js +11 -2
  6. package/dist/adapters/mech/contracts.js.map +1 -1
  7. package/dist/adapters/mech/safe.d.ts +1 -1
  8. package/dist/adapters/mech/safe.js +5 -3
  9. package/dist/adapters/mech/safe.js.map +1 -1
  10. package/dist/adapters/mech/types.d.ts +6 -1
  11. package/dist/adapters/mech/types.js.map +1 -1
  12. package/dist/agent/operator-claude.js +8 -0
  13. package/dist/agent/operator-claude.js.map +1 -1
  14. package/dist/api/activity-events-endpoint.d.ts +14 -0
  15. package/dist/api/activity-events-endpoint.js +59 -0
  16. package/dist/api/activity-events-endpoint.js.map +1 -0
  17. package/dist/api/bootstrap-endpoint.d.ts +1 -2
  18. package/dist/api/bootstrap-endpoint.js +42 -24
  19. package/dist/api/bootstrap-endpoint.js.map +1 -1
  20. package/dist/api/codex-doctor-endpoint.d.ts +22 -5
  21. package/dist/api/codex-doctor-endpoint.js +136 -17
  22. package/dist/api/codex-doctor-endpoint.js.map +1 -1
  23. package/dist/api/debug-report-endpoint.d.ts +27 -0
  24. package/dist/api/debug-report-endpoint.js +157 -0
  25. package/dist/api/debug-report-endpoint.js.map +1 -0
  26. package/dist/api/gather-status.d.ts +33 -0
  27. package/dist/api/gather-status.js +210 -26
  28. package/dist/api/gather-status.js.map +1 -1
  29. package/dist/api/hermes-doctor-endpoint.d.ts +15 -7
  30. package/dist/api/hermes-doctor-endpoint.js +56 -19
  31. package/dist/api/hermes-doctor-endpoint.js.map +1 -1
  32. package/dist/api/launcher-status.d.ts +4 -2
  33. package/dist/api/launcher-status.js +11 -10
  34. package/dist/api/launcher-status.js.map +1 -1
  35. package/dist/api/launcher-tasks.d.ts +1 -1
  36. package/dist/api/launcher-tasks.js +12 -8
  37. package/dist/api/launcher-tasks.js.map +1 -1
  38. package/dist/api/operator-artifacts-endpoint.js +73 -6
  39. package/dist/api/operator-artifacts-endpoint.js.map +1 -1
  40. package/dist/api/server.d.ts +17 -0
  41. package/dist/api/server.js +40 -1
  42. package/dist/api/server.js.map +1 -1
  43. package/dist/api/setup-endpoints.d.ts +0 -9
  44. package/dist/api/setup-endpoints.js +11 -153
  45. package/dist/api/setup-endpoints.js.map +1 -1
  46. package/dist/api/solvernets-endpoints.js +30 -63
  47. package/dist/api/solvernets-endpoints.js.map +1 -1
  48. package/dist/api/status-build.d.ts +115 -2
  49. package/dist/api/status-build.js +47 -11
  50. package/dist/api/status-build.js.map +1 -1
  51. package/dist/api/status-harness-rollup.d.ts +35 -0
  52. package/dist/api/status-harness-rollup.js +45 -0
  53. package/dist/api/status-harness-rollup.js.map +1 -0
  54. package/dist/build-info.json +4 -4
  55. package/dist/build-meta.json +1 -1
  56. package/dist/captures/live-publisher.js +24 -4
  57. package/dist/captures/live-publisher.js.map +1 -1
  58. package/dist/captures/publish.d.ts +1 -1
  59. package/dist/chain-read-errors.d.ts +12 -0
  60. package/dist/chain-read-errors.js +26 -1
  61. package/dist/chain-read-errors.js.map +1 -1
  62. package/dist/cli/commands/codedigest-revert-check.d.ts +33 -0
  63. package/dist/cli/commands/codedigest-revert-check.js +249 -0
  64. package/dist/cli/commands/codedigest-revert-check.js.map +1 -0
  65. package/dist/cli/commands/solver-nets.d.ts +1 -0
  66. package/dist/cli/commands/solver-nets.js +170 -22
  67. package/dist/cli/commands/solver-nets.js.map +1 -1
  68. package/dist/cli/commands/solver-plugins-block.d.ts +33 -0
  69. package/dist/cli/commands/solver-plugins-block.js +118 -0
  70. package/dist/cli/commands/solver-plugins-block.js.map +1 -0
  71. package/dist/cli/commands/solver-plugins-feedback.d.ts +72 -0
  72. package/dist/cli/commands/solver-plugins-feedback.js +262 -0
  73. package/dist/cli/commands/solver-plugins-feedback.js.map +1 -0
  74. package/dist/cli/commands/solver-plugins-read.d.ts +54 -0
  75. package/dist/cli/commands/solver-plugins-read.js +259 -0
  76. package/dist/cli/commands/solver-plugins-read.js.map +1 -0
  77. package/dist/cli/commands/solver-plugins.d.ts +35 -0
  78. package/dist/cli/commands/solver-plugins.js +399 -2
  79. package/dist/cli/commands/solver-plugins.js.map +1 -1
  80. package/dist/cli/commands/tasks.js +15 -2
  81. package/dist/cli/commands/tasks.js.map +1 -1
  82. package/dist/cli/index.js +2 -0
  83. package/dist/cli/index.js.map +1 -1
  84. package/dist/cli/task-native-readiness.d.ts +7 -0
  85. package/dist/cli/task-native-readiness.js +7 -5
  86. package/dist/cli/task-native-readiness.js.map +1 -1
  87. package/dist/config.d.ts +183 -232
  88. package/dist/config.js +232 -107
  89. package/dist/config.js.map +1 -1
  90. package/dist/daemon/ai-units-gate.d.ts +54 -0
  91. package/dist/daemon/ai-units-gate.js +82 -0
  92. package/dist/daemon/ai-units-gate.js.map +1 -0
  93. package/dist/daemon/creator.js +13 -0
  94. package/dist/daemon/creator.js.map +1 -1
  95. package/dist/daemon/daemon.d.ts +10 -0
  96. package/dist/daemon/daemon.js +203 -30
  97. package/dist/daemon/daemon.js.map +1 -1
  98. package/dist/daemon/gate-logger.d.ts +9 -0
  99. package/dist/daemon/gate-logger.js +2 -0
  100. package/dist/daemon/gate-logger.js.map +1 -0
  101. package/dist/daemon/readiness-gate.d.ts +1 -4
  102. package/dist/daemon/readiness-gate.js.map +1 -1
  103. package/dist/daemon/spend-cap-gate.d.ts +40 -0
  104. package/dist/daemon/spend-cap-gate.js +46 -0
  105. package/dist/daemon/spend-cap-gate.js.map +1 -0
  106. package/dist/dashboard/assets/index-CvQbxjxy.js +351 -0
  107. package/dist/dashboard/assets/index-CzKxvMcU.css +32 -0
  108. package/dist/dashboard/index.html +2 -2
  109. package/dist/discovery/http.js +328 -1
  110. package/dist/discovery/http.js.map +1 -1
  111. package/dist/discovery/onchain.js +42 -4
  112. package/dist/discovery/onchain.js.map +1 -1
  113. package/dist/discovery/types.d.ts +129 -0
  114. package/dist/discovery/types.js.map +1 -1
  115. package/dist/discovery/with-fallback.js +27 -0
  116. package/dist/discovery/with-fallback.js.map +1 -1
  117. package/dist/earning/bootstrap.d.ts +8 -3
  118. package/dist/earning/bootstrap.js +36 -13
  119. package/dist/earning/bootstrap.js.map +1 -1
  120. package/dist/earning/safe-adapter.js +23 -11
  121. package/dist/earning/safe-adapter.js.map +1 -1
  122. package/dist/earning/types.d.ts +6 -6
  123. package/dist/earning/viem-clients.d.ts +11 -4
  124. package/dist/earning/viem-clients.js +14 -5
  125. package/dist/earning/viem-clients.js.map +1 -1
  126. package/dist/erc8004/identity.d.ts +19 -3
  127. package/dist/erc8004/identity.js +21 -6
  128. package/dist/erc8004/identity.js.map +1 -1
  129. package/dist/erc8004/index.d.ts +1 -1
  130. package/dist/erc8004/index.js.map +1 -1
  131. package/dist/events/types.d.ts +2 -2
  132. package/dist/harnesses/cost-estimates.d.ts +10 -31
  133. package/dist/harnesses/cost-estimates.js +11 -43
  134. package/dist/harnesses/cost-estimates.js.map +1 -1
  135. package/dist/harnesses/engine/engine.d.ts +9 -3
  136. package/dist/harnesses/engine/engine.js +51 -6
  137. package/dist/harnesses/engine/engine.js.map +1 -1
  138. package/dist/harnesses/impls/hermes-agent/bootstrap.js +4 -2
  139. package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
  140. package/dist/harnesses/impls/hermes-agent/config-builder.d.ts +1 -1
  141. package/dist/harnesses/impls/hermes-agent/config-builder.js +4 -2
  142. package/dist/harnesses/impls/hermes-agent/config-builder.js.map +1 -1
  143. package/dist/harnesses/impls/hermes-agent/harness.js +2 -2
  144. package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
  145. package/dist/harnesses/impls/hermes-agent/prompt.d.ts +6 -6
  146. package/dist/harnesses/impls/hermes-agent/prompt.js +6 -6
  147. package/dist/harnesses/impls/learner/adapters/claude-code.d.ts +17 -0
  148. package/dist/harnesses/impls/learner/adapters/claude-code.js +113 -14
  149. package/dist/harnesses/impls/learner/adapters/claude-code.js.map +1 -1
  150. package/dist/harnesses/impls/learner/adapters/codex-code.d.ts +9 -0
  151. package/dist/harnesses/impls/learner/adapters/codex-code.js +30 -8
  152. package/dist/harnesses/impls/learner/adapters/codex-code.js.map +1 -1
  153. package/dist/harnesses/impls/learner/harness.d.ts +9 -0
  154. package/dist/harnesses/impls/learner/harness.js +12 -3
  155. package/dist/harnesses/impls/learner/harness.js.map +1 -1
  156. package/dist/harnesses/impls/learner/harvest.d.ts +1 -1
  157. package/dist/harnesses/impls/learner/harvest.js +23 -5
  158. package/dist/harnesses/impls/learner/harvest.js.map +1 -1
  159. package/dist/harnesses/impls/learner/restoration-patch.d.ts +2 -2
  160. package/dist/harnesses/impls/learner/restoration-patch.js +25 -6
  161. package/dist/harnesses/impls/learner/restoration-patch.js.map +1 -1
  162. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +21 -1
  163. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
  164. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +74 -5
  165. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +103 -32
  166. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
  167. package/dist/harnesses/readiness-registry.d.ts +7 -0
  168. package/dist/harnesses/readiness-registry.js +9 -0
  169. package/dist/harnesses/readiness-registry.js.map +1 -1
  170. package/dist/learner/revert-decision.d.ts +59 -0
  171. package/dist/learner/revert-decision.js +53 -0
  172. package/dist/learner/revert-decision.js.map +1 -0
  173. package/dist/learner/revert-stats.d.ts +24 -0
  174. package/dist/learner/revert-stats.js +44 -0
  175. package/dist/learner/revert-stats.js.map +1 -0
  176. package/dist/main.js +177 -104
  177. package/dist/main.js.map +1 -1
  178. package/dist/mcp/get-codedigest-reward.d.ts +13 -0
  179. package/dist/mcp/get-codedigest-reward.js +23 -0
  180. package/dist/mcp/get-codedigest-reward.js.map +1 -0
  181. package/dist/mcp/server.js +23 -0
  182. package/dist/mcp/server.js.map +1 -1
  183. package/dist/observability/debug-report-assemble.d.ts +43 -0
  184. package/dist/observability/debug-report-assemble.js +80 -0
  185. package/dist/observability/debug-report-assemble.js.map +1 -0
  186. package/dist/observability/emit-event.d.ts +9 -2
  187. package/dist/observability/emit-event.js +36 -2
  188. package/dist/observability/emit-event.js.map +1 -1
  189. package/dist/observability/file-logger.d.ts +69 -0
  190. package/dist/observability/file-logger.js +177 -0
  191. package/dist/observability/file-logger.js.map +1 -0
  192. package/dist/observability/redact-secrets.d.ts +65 -0
  193. package/dist/observability/redact-secrets.js +300 -0
  194. package/dist/observability/redact-secrets.js.map +1 -0
  195. package/dist/observability/tar.d.ts +30 -0
  196. package/dist/observability/tar.js +102 -0
  197. package/dist/observability/tar.js.map +1 -0
  198. package/dist/plugins/learner/skills/learn/consolidator-prompt.md +18 -1
  199. package/dist/plugins/learner/skills/learn/promoter-prompt.md +72 -1
  200. package/dist/preflight/pidfile-liveness.d.ts +44 -0
  201. package/dist/preflight/pidfile-liveness.js +103 -0
  202. package/dist/preflight/pidfile-liveness.js.map +1 -0
  203. package/dist/preflight/rpc-network.d.ts +40 -0
  204. package/dist/preflight/rpc-network.js +67 -1
  205. package/dist/preflight/rpc-network.js.map +1 -1
  206. package/dist/rpc/transport.d.ts +109 -0
  207. package/dist/rpc/transport.js +220 -0
  208. package/dist/rpc/transport.js.map +1 -0
  209. package/dist/scripts/donation-consumption-acceptance.js +7 -28
  210. package/dist/scripts/donation-consumption-acceptance.js.map +1 -1
  211. package/dist/scripts/swe-rebench-v2-pytest-missing.json +16 -0
  212. package/dist/solver-nets/prediction-operator-ux.d.ts +1 -2
  213. package/dist/solver-nets/prediction-operator-ux.js +56 -53
  214. package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
  215. package/dist/solver-nets/registry.d.ts +19 -1
  216. package/dist/solver-nets/registry.js +37 -24
  217. package/dist/solver-nets/registry.js.map +1 -1
  218. package/dist/solver-types/_swe-rebench-v2-pool.d.ts +9 -2
  219. package/dist/solver-types/_swe-rebench-v2-pool.js +15 -20
  220. package/dist/solver-types/_swe-rebench-v2-pool.js.map +1 -1
  221. package/dist/solver-types/_swe-rebench-v2-state.d.ts +15 -0
  222. package/dist/solver-types/_swe-rebench-v2-state.js +19 -0
  223. package/dist/solver-types/_swe-rebench-v2-state.js.map +1 -1
  224. package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +80 -2
  225. package/dist/solver-types/_swe-rebench-v2-validated-pool.js +242 -21
  226. package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
  227. package/dist/solver-types/swe-rebench-v2-auto.d.ts +20 -11
  228. package/dist/solver-types/swe-rebench-v2-auto.js +64 -19
  229. package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
  230. package/dist/solver-types/swe-rebench-v2.d.ts +8 -2
  231. package/dist/solver-types/swe-rebench-v2.js +127 -11
  232. package/dist/solver-types/swe-rebench-v2.js.map +1 -1
  233. package/dist/solvernets/launched-record-dispatcher.d.ts +4 -0
  234. package/dist/solvernets/launched-record-dispatcher.js +10 -4
  235. package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
  236. package/dist/solvernets/registry-client-erc8004.js +11 -0
  237. package/dist/solvernets/registry-client-erc8004.js.map +1 -1
  238. package/dist/solvernets/store.d.ts +2 -2
  239. package/dist/spend/ai-units-config.d.ts +37 -0
  240. package/dist/spend/ai-units-config.js +26 -0
  241. package/dist/spend/ai-units-config.js.map +1 -0
  242. package/dist/spend/ai-units.d.ts +86 -0
  243. package/dist/spend/ai-units.js +163 -0
  244. package/dist/spend/ai-units.js.map +1 -0
  245. package/dist/spend/cost-surface-status.d.ts +10 -0
  246. package/dist/spend/cost-surface-status.js +22 -0
  247. package/dist/spend/cost-surface-status.js.map +1 -0
  248. package/dist/spend/credential.d.ts +8 -0
  249. package/dist/spend/credential.js +30 -0
  250. package/dist/spend/credential.js.map +1 -0
  251. package/dist/spend/daemon-config.d.ts +13 -0
  252. package/dist/spend/daemon-config.js +24 -0
  253. package/dist/spend/daemon-config.js.map +1 -0
  254. package/dist/spend/pricing.d.ts +16 -0
  255. package/dist/spend/pricing.js +26 -0
  256. package/dist/spend/pricing.js.map +1 -0
  257. package/dist/spend/record.d.ts +13 -0
  258. package/dist/spend/record.js +36 -0
  259. package/dist/spend/record.js.map +1 -0
  260. package/dist/spend/usage.d.ts +27 -0
  261. package/dist/spend/usage.js +113 -0
  262. package/dist/spend/usage.js.map +1 -0
  263. package/dist/store/store.d.ts +101 -0
  264. package/dist/store/store.js +304 -4
  265. package/dist/store/store.js.map +1 -1
  266. package/dist/trajectory/transcript-parsers/codex-session.d.ts +12 -6
  267. package/dist/trajectory/transcript-parsers/codex-session.js +114 -13
  268. package/dist/trajectory/transcript-parsers/codex-session.js.map +1 -1
  269. package/dist/trajectory/transcript-parsers/types.d.ts +8 -8
  270. package/dist/trajectory/transcript-session-dirs.d.ts +18 -0
  271. package/dist/trajectory/transcript-session-dirs.js +85 -0
  272. package/dist/trajectory/transcript-session-dirs.js.map +1 -0
  273. package/dist/trajectory/transcript-watcher.d.ts +20 -1
  274. package/dist/trajectory/transcript-watcher.js +98 -32
  275. package/dist/trajectory/transcript-watcher.js.map +1 -1
  276. package/dist/tx-retry.d.ts +15 -0
  277. package/dist/tx-retry.js +37 -7
  278. package/dist/tx-retry.js.map +1 -1
  279. package/dist/types/payloads/portfolio-v0.d.ts +3 -3
  280. package/dist/types/payloads/prediction-apy-v0.d.ts +3 -3
  281. package/dist/types/payloads/prediction-v0.d.ts +12 -12
  282. package/package.json +10 -3
  283. package/plugins/learner/skills/learn/consolidator-prompt.md +18 -1
  284. package/plugins/learner/skills/learn/promoter-prompt.md +72 -1
  285. package/plugins/swe-rebench-v2-diffmin/README.md +10 -9
  286. package/plugins/swe-rebench-v2-diffmin/jinn.plugin.json +1 -1
  287. package/plugins/swe-rebench-v2-diffmin/skills/diffmin/SKILL.md +15 -10
  288. package/plugins/swe-rebench-v2-diffmin/skills/test-map/SKILL.md +10 -12
  289. package/plugins/swe-rebench-v2-runtime/.claude-plugin/plugin.json +1 -1
  290. package/plugins/swe-rebench-v2-runtime/.codex-plugin/plugin.json +3 -3
  291. package/plugins/swe-rebench-v2-runtime/README.md +6 -6
  292. package/plugins/swe-rebench-v2-runtime/jinn.plugin.json +2 -3
  293. package/plugins/swe-rebench-v2-runtime/skills/task/SKILL.md +81 -0
  294. package/dist/dashboard/assets/index-BUlE8F3Y.js +0 -330
  295. package/dist/dashboard/assets/index-blqc7eqq.css +0 -32
  296. package/plugins/swe-rebench-v2-runtime/skills/orient/SKILL.md +0 -29
  297. package/plugins/swe-rebench-v2-runtime/skills/plan/SKILL.md +0 -53
@@ -0,0 +1,113 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { CLAUDE_CODE_HARNESS, CODEX_HARNESS, canonicalHarnessName } from '../harnesses/names.js';
4
+ import { estimateModelCost } from '../harnesses/cost-estimates.js';
5
+ import { priceTokens } from './pricing.js';
6
+ /** USD attributed to a task whose model has no known price. */
7
+ export const UNKNOWN_MODEL_FALLBACK_USD = 1.0;
8
+ /** Parse Claude Code `--output-format stream-json` output for the terminal result. */
9
+ export function parseClaudeCodeUsage(stdoutJsonl) {
10
+ let result = null;
11
+ for (const line of stdoutJsonl.split('\n')) {
12
+ const trimmed = line.trim();
13
+ if (!trimmed)
14
+ continue;
15
+ let obj;
16
+ try {
17
+ obj = JSON.parse(trimmed);
18
+ }
19
+ catch {
20
+ continue;
21
+ }
22
+ if (obj['type'] === 'result' && typeof obj['total_cost_usd'] === 'number') {
23
+ const usage = obj['usage'];
24
+ result = {
25
+ costUsd: obj['total_cost_usd'],
26
+ inputTokens: typeof usage?.['input_tokens'] === 'number' ? usage['input_tokens'] : undefined,
27
+ outputTokens: typeof usage?.['output_tokens'] === 'number' ? usage['output_tokens'] : undefined,
28
+ };
29
+ }
30
+ }
31
+ return result;
32
+ }
33
+ /** Parse Codex `--json` output for the last turn.completed token usage. */
34
+ export function parseCodexUsage(stdoutJsonl) {
35
+ let result = null;
36
+ for (const line of stdoutJsonl.split('\n')) {
37
+ const trimmed = line.trim();
38
+ if (!trimmed)
39
+ continue;
40
+ let obj;
41
+ try {
42
+ obj = JSON.parse(trimmed);
43
+ }
44
+ catch {
45
+ continue;
46
+ }
47
+ if (obj['type'] === 'turn.completed' && obj['usage']) {
48
+ const usage = obj['usage'];
49
+ const inT = usage['input_tokens'];
50
+ const outT = usage['output_tokens'];
51
+ if (typeof inT === 'number' && typeof outT === 'number') {
52
+ result = { inputTokens: inT, outputTokens: outT };
53
+ }
54
+ }
55
+ }
56
+ return result;
57
+ }
58
+ function heuristicUsage(model) {
59
+ const est = model ? estimateModelCost(model) : null;
60
+ return {
61
+ model: model ?? 'unknown',
62
+ costUsd: est?.usd ?? UNKNOWN_MODEL_FALLBACK_USD,
63
+ estimated: true,
64
+ };
65
+ }
66
+ /**
67
+ * Determine the USD cost of a finished harness run. Reads the harness's own
68
+ * output file for observed usage; falls back to a heuristic on any failure.
69
+ * Always returns a HarnessUsage — never throws.
70
+ */
71
+ export function harvestHarnessUsage(harness, workingDir, model) {
72
+ try {
73
+ const canonical = canonicalHarnessName(harness);
74
+ if (canonical === CLAUDE_CODE_HARNESS) {
75
+ const raw = readFileSync(join(workingDir, '.claude-code', 'stdout.jsonl'), 'utf8');
76
+ const parsed = parseClaudeCodeUsage(raw);
77
+ if (parsed) {
78
+ return {
79
+ model: model ?? 'unknown',
80
+ costUsd: parsed.costUsd,
81
+ estimated: false,
82
+ inputTokens: parsed.inputTokens,
83
+ outputTokens: parsed.outputTokens,
84
+ };
85
+ }
86
+ return heuristicUsage(model);
87
+ }
88
+ if (canonical === CODEX_HARNESS) {
89
+ const raw = readFileSync(join(workingDir, '.codex-code', 'stdout.jsonl'), 'utf8');
90
+ const parsed = parseCodexUsage(raw);
91
+ // When there is no model id, parsed token counts cannot be priced —
92
+ // discard them and fall back to the heuristic (per spec).
93
+ if (parsed && model) {
94
+ const usd = priceTokens(model, parsed);
95
+ if (usd != null) {
96
+ return {
97
+ model,
98
+ costUsd: usd,
99
+ estimated: false,
100
+ inputTokens: parsed.inputTokens,
101
+ outputTokens: parsed.outputTokens,
102
+ };
103
+ }
104
+ }
105
+ return heuristicUsage(model);
106
+ }
107
+ return heuristicUsage(model);
108
+ }
109
+ catch {
110
+ return heuristicUsage(model);
111
+ }
112
+ }
113
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/spend/usage.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,17 @@ export interface ActivityEventInput {
10
10
  solverType?: string | null;
11
11
  outcome?: string | null;
12
12
  detail?: string | null;
13
+ credentialId?: string | null;
14
+ costUsdMicros?: number | null;
15
+ model?: string | null;
16
+ /** Projected AI units debited at claim time (issue #815). Estimates are the gate input; never recomputed. */
17
+ aiUnits?: number | null;
18
+ /** Lifecycle stamp on the per-request row: 'claimed' | 'claim_failed' | 'delivered'. */
19
+ claimStatus?: string | null;
20
+ /** USD estimate captured at claim time (micros). Distinct from `actualCostUsdMicros` filled on completion. */
21
+ estimatedCostUsdMicros?: number | null;
22
+ /** USD actually billed (micros) — filled by the completion path; null until then. */
23
+ actualCostUsdMicros?: number | null;
13
24
  }
14
25
  export interface ActivityEventRow {
15
26
  id: number;
@@ -21,6 +32,13 @@ export interface ActivityEventRow {
21
32
  solverType: string | null;
22
33
  outcome: string | null;
23
34
  detail: string | null;
35
+ credentialId: string | null;
36
+ costUsdMicros: number | null;
37
+ model: string | null;
38
+ aiUnits: number | null;
39
+ claimStatus: string | null;
40
+ estimatedCostUsdMicros: number | null;
41
+ actualCostUsdMicros: number | null;
24
42
  }
25
43
  export interface RewardClaimInput {
26
44
  ts: string;
@@ -148,6 +166,22 @@ export interface NetworkArtifactMetadataRow {
148
166
  lastUsedAt: string;
149
167
  peerCatalogId: string | null;
150
168
  }
169
+ export interface Erc8004AnchorInput {
170
+ envelopeId: string;
171
+ envelopeCid: string;
172
+ contentKind: string;
173
+ metadataKey: string;
174
+ agentId: string;
175
+ chainId: number;
176
+ identityRegistryAddress: string;
177
+ txHash: string;
178
+ blockNumber: number | null;
179
+ payloadHex: string;
180
+ anchoredAt: number;
181
+ }
182
+ export interface Erc8004AnchorRow extends Erc8004AnchorInput {
183
+ id: number;
184
+ }
151
185
  export type TaskPostingPolicyType = 'once_per_safe' | 'once_per_bucket' | 'interval';
152
186
  type LauncherTaskProjectionState = 'open' | 'claims-in-flight' | 'fully-claimed' | 'settled' | 'failed';
153
187
  export interface TaskPostRecord {
@@ -185,6 +219,8 @@ export declare class Store {
185
219
  private ensureTaskPostsTaskCoordinatorColumns;
186
220
  /** Older local DBs may have the projection table from before Task grouping fields landed. */
187
221
  private ensureEnvelopeProjectionColumns;
222
+ /** Older local DBs predate the per-credential spend-ledger columns on activity_events. */
223
+ private ensureActivityEventCostColumns;
188
224
  /**
189
225
  * Task-native startup ignores the retired request-first `restoration_intents`
190
226
  * table. Keep a one-time local marker when old in-flight rows are present so
@@ -194,6 +230,14 @@ export declare class Store {
194
230
  /** Idempotent: older DBs before idx_reward_claims_tx may lack the unique index. */
195
231
  private ensureRewardClaimsTxIndex;
196
232
  recordOwnActivity(requestId: string, role: 'created' | 'claimed' | 'delivered' | 'evaluated'): void;
233
+ /**
234
+ * Membership-only variant of `recordOwnActivity`: writes the
235
+ * `own_activity` row but does NOT emit a generic `activity_events`
236
+ * row. Used by paths that emit their own enriched activity event
237
+ * (e.g. issue #815's claim path attaches credentialId / aiUnits /
238
+ * estimatedCostUsdMicros / claimStatus to the row).
239
+ */
240
+ markOwnActivity(requestId: string, role: 'created' | 'claimed' | 'delivered' | 'evaluated'): void;
197
241
  isOwnActivity(requestId: string): boolean;
198
242
  setShutdownState(state: 'clean' | 'running'): void;
199
243
  getShutdownState(): string | null;
@@ -279,8 +323,63 @@ export declare class Store {
279
323
  since?: string;
280
324
  cursor?: string;
281
325
  }): ActivityEventRow[];
326
+ /**
327
+ * Total cost in micro-dollars recorded against a credential since the most
328
+ * recent UTC midnight. Backs the daily spend cap.
329
+ */
330
+ spentTodayMicros(credentialId: string, now?: Date): number;
331
+ /**
332
+ * Sum of `ai_units` for a credential within the current 6h UTC-aligned
333
+ * block (00:00 / 06:00 / 12:00 / 18:00 boundaries). Reads only rows whose
334
+ * `claim_status = 'claimed'` or `'delivered'` so failed-claim rows
335
+ * (`ai_units = 0`, `claim_status = 'claim_failed'`) don't muddy the sum
336
+ * even though their contribution is already zero.
337
+ *
338
+ * Issue #815. Backs the per-block AI-units ceiling gate.
339
+ */
340
+ aiUnitsThisBlock(credentialId: string, now?: Date): number;
341
+ /**
342
+ * Sum of `ai_units` for a credential within the trailing 7-day rolling
343
+ * window from `now`. Backs the per-week AI-units safety-net ceiling.
344
+ * Issue #815.
345
+ */
346
+ aiUnitsThisWeek(credentialId: string, now?: Date): number;
347
+ /**
348
+ * True iff an `ai_units_cap_reached` row exists for the given
349
+ * (credentialId, window, blockId). Used by the daemon to hydrate the
350
+ * AI-units gate's in-memory pause memo across restarts so the
351
+ * "exactly one event per (credential, window, block-id)" guarantee
352
+ * holds across process boundaries (issue #815, finding 1).
353
+ *
354
+ * Lookup is by `credential_id` + `kind` + the `[block=...][window=...]`
355
+ * markers that `daemon.ts` embeds in the row's `detail` string.
356
+ */
357
+ hasAiUnitsCapReachedFor(credentialId: string, window: 'block' | 'week', blockId: string): boolean;
358
+ /**
359
+ * Mark the per-request `claimed` row as `delivered` and record
360
+ * `actual_cost_usd_micros`. The `ai_units` projection captured at
361
+ * claim time is intentionally NOT recomputed — the issue spec says
362
+ * "estimates are the gate input, never recomputed". Idempotent: a
363
+ * no-op when no `claimed` row exists.
364
+ */
365
+ finalizeClaimDelivered(requestId: string, actualCostUsdMicros: number): void;
282
366
  /** Newer events first, then ascending id for `jinn logs --follow` (oldest in batch printed first in caller). */
283
367
  getActivityEventsAfterId(afterId: number, limit: number): ActivityEventRow[];
368
+ /**
369
+ * Filtered, id-cursored page of activity events for the dedicated Events
370
+ * page. Newest-first.
371
+ *
372
+ * Cursors on `id` rather than `ts` so startup/shutdown rows with null
373
+ * timestamps remain reachable.
374
+ */
375
+ getActivityEventsPage(opts?: {
376
+ kinds?: string[];
377
+ outcome?: string;
378
+ requestId?: string;
379
+ beforeId?: number;
380
+ limit?: number;
381
+ }): ActivityEventRow[];
382
+ getActivityEventById(id: number): ActivityEventRow | null;
284
383
  getActivityCountsByKind(): Record<string, number>;
285
384
  getLastEventAtForService(serviceIndex: number): string | null;
286
385
  getActivityCountsForService(serviceIndex: number): Record<string, number>;
@@ -398,6 +497,8 @@ export declare class Store {
398
497
  }>;
399
498
  saveEnvelopeProjection(projection: EnvelopeProjection): void;
400
499
  queryEnvelopeProjections(query?: EnvelopeProjectionQuery): EnvelopeProjection[];
500
+ saveErc8004Anchor(input: Erc8004AnchorInput): void;
501
+ listErc8004AnchorsByEnvelopeCids(envelopeCids: readonly string[]): Erc8004AnchorRow[];
401
502
  close(): void;
402
503
  }
403
504
  export {};
@@ -228,6 +228,23 @@ CREATE TABLE IF NOT EXISTS envelope_projection_metadata (
228
228
  CREATE INDEX IF NOT EXISTS idx_envelope_projection_metadata_key_value
229
229
  ON envelope_projection_metadata (key, value_text);
230
230
 
231
+ CREATE TABLE IF NOT EXISTS erc8004_anchors (
232
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
233
+ envelope_id TEXT NOT NULL,
234
+ envelope_cid TEXT NOT NULL,
235
+ content_kind TEXT NOT NULL,
236
+ metadata_key TEXT NOT NULL,
237
+ agent_id TEXT NOT NULL,
238
+ chain_id INTEGER NOT NULL,
239
+ identity_registry_address TEXT NOT NULL,
240
+ tx_hash TEXT NOT NULL,
241
+ block_number INTEGER,
242
+ payload_hex TEXT NOT NULL,
243
+ anchored_at INTEGER NOT NULL
244
+ );
245
+ CREATE INDEX IF NOT EXISTS idx_erc8004_anchors_envelope_cid ON erc8004_anchors(envelope_cid);
246
+ CREATE INDEX IF NOT EXISTS idx_erc8004_anchors_envelope_id ON erc8004_anchors(envelope_id);
247
+
231
248
  CREATE TABLE IF NOT EXISTS task_post_locks (
232
249
  creator_safe_address TEXT NOT NULL,
233
250
  source_key TEXT NOT NULL,
@@ -299,6 +316,7 @@ export class Store {
299
316
  this.ensureNetworkArtifactsPeerCatalogId();
300
317
  this.ensureTaskPostsTaskCoordinatorColumns();
301
318
  this.ensureEnvelopeProjectionColumns();
319
+ this.ensureActivityEventCostColumns();
302
320
  this.backfillActivityEvents();
303
321
  this.recordLegacyRestorationIntentsIgnored();
304
322
  }
@@ -363,6 +381,30 @@ export class Store {
363
381
  this.db.exec(`CREATE INDEX IF NOT EXISTS idx_envelope_projections_solution_ref ON envelope_projections (solution_envelope_ref)`);
364
382
  this.db.exec(`CREATE INDEX IF NOT EXISTS idx_envelope_projections_generated ON envelope_projections (generated_at DESC)`);
365
383
  }
384
+ /** Older local DBs predate the per-credential spend-ledger columns on activity_events. */
385
+ ensureActivityEventCostColumns() {
386
+ const activityCols = new Set(this.db.prepare(`PRAGMA table_info(activity_events)`).all()
387
+ .map(c => c.name));
388
+ const addActivityColumn = (name, ddl) => {
389
+ if (!activityCols.has(name))
390
+ this.db.exec(`ALTER TABLE activity_events ADD COLUMN ${ddl}`);
391
+ };
392
+ addActivityColumn('credential_id', 'credential_id TEXT');
393
+ addActivityColumn('cost_usd_micros', 'cost_usd_micros INTEGER');
394
+ addActivityColumn('model', 'model TEXT');
395
+ // Issue #815 — AI-units ceiling. ai_units is the gate-input projection
396
+ // captured at claim time; claim_status tracks the per-request lifecycle
397
+ // (claimed / claim_failed / delivered); the cost pair splits the
398
+ // estimated-at-claim-time vs actual-at-completion telemetry.
399
+ addActivityColumn('ai_units', 'ai_units REAL');
400
+ addActivityColumn('claim_status', 'claim_status TEXT');
401
+ addActivityColumn('estimated_cost_usd_micros', 'estimated_cost_usd_micros INTEGER');
402
+ addActivityColumn('actual_cost_usd_micros', 'actual_cost_usd_micros INTEGER');
403
+ this.db.exec(`CREATE INDEX IF NOT EXISTS idx_activity_events_credential ON activity_events (credential_id, ts)`);
404
+ // Per-request lookup for the completion-time update path that fills
405
+ // actualCostUsdMicros / sets claim_status='delivered'.
406
+ this.db.exec(`CREATE INDEX IF NOT EXISTS idx_activity_events_req_claim ON activity_events (request_id, claim_status)`);
407
+ }
366
408
  /**
367
409
  * Task-native startup ignores the retired request-first `restoration_intents`
368
410
  * table. Keep a one-time local marker when old in-flight rows are present so
@@ -417,6 +459,16 @@ export class Store {
417
459
  const ts = new Date().toISOString();
418
460
  this.recordActivityEvent({ ts, kind: role, requestId });
419
461
  }
462
+ /**
463
+ * Membership-only variant of `recordOwnActivity`: writes the
464
+ * `own_activity` row but does NOT emit a generic `activity_events`
465
+ * row. Used by paths that emit their own enriched activity event
466
+ * (e.g. issue #815's claim path attaches credentialId / aiUnits /
467
+ * estimatedCostUsdMicros / claimStatus to the row).
468
+ */
469
+ markOwnActivity(requestId, role) {
470
+ this.db.prepare(`INSERT OR REPLACE INTO own_activity (request_id, role) VALUES (?, ?)`).run(requestId, role);
471
+ }
420
472
  isOwnActivity(requestId) {
421
473
  const row = this.db.prepare('SELECT 1 FROM own_activity WHERE request_id = ?').get(requestId);
422
474
  return row !== undefined;
@@ -746,8 +798,14 @@ export class Store {
746
798
  return legacyRows.map(r => ({ requestId: r.request_id, role: r.role }));
747
799
  }
748
800
  recordActivityEvent(event) {
749
- this.db.prepare(`INSERT INTO activity_events (ts, kind, request_id, service_index, tx_hash, solver_type, outcome, detail)
750
- VALUES (@ts, @kind, @requestId, @serviceIndex, @txHash, @solverType, @outcome, @detail)`).run({
801
+ this.db.prepare(`INSERT INTO activity_events
802
+ (ts, kind, request_id, service_index, tx_hash, solver_type, outcome, detail,
803
+ credential_id, cost_usd_micros, model,
804
+ ai_units, claim_status, estimated_cost_usd_micros, actual_cost_usd_micros)
805
+ VALUES
806
+ (@ts, @kind, @requestId, @serviceIndex, @txHash, @solverType, @outcome, @detail,
807
+ @credentialId, @costUsdMicros, @model,
808
+ @aiUnits, @claimStatus, @estimatedCostUsdMicros, @actualCostUsdMicros)`).run({
751
809
  ts: event.ts ?? null,
752
810
  kind: event.kind,
753
811
  requestId: event.requestId ?? null,
@@ -756,6 +814,13 @@ export class Store {
756
814
  solverType: event.solverType ?? null,
757
815
  outcome: event.outcome ?? null,
758
816
  detail: event.detail ?? null,
817
+ credentialId: event.credentialId ?? null,
818
+ costUsdMicros: event.costUsdMicros ?? null,
819
+ model: event.model ?? null,
820
+ aiUnits: event.aiUnits ?? null,
821
+ claimStatus: event.claimStatus ?? null,
822
+ estimatedCostUsdMicros: event.estimatedCostUsdMicros ?? null,
823
+ actualCostUsdMicros: event.actualCostUsdMicros ?? null,
759
824
  });
760
825
  }
761
826
  getRecentActivityEvents(limit, opts = {}) {
@@ -771,7 +836,9 @@ export class Store {
771
836
  params['cursor'] = opts.cursor;
772
837
  }
773
838
  const where = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';
774
- const rows = this.db.prepare(`SELECT id, ts, kind, request_id, service_index, tx_hash, solver_type, outcome, detail
839
+ const rows = this.db.prepare(`SELECT id, ts, kind, request_id, service_index, tx_hash, solver_type, outcome, detail,
840
+ credential_id, cost_usd_micros, model,
841
+ ai_units, claim_status, estimated_cost_usd_micros, actual_cost_usd_micros
775
842
  FROM activity_events
776
843
  ${where}
777
844
  ORDER BY id DESC
@@ -786,13 +853,106 @@ export class Store {
786
853
  solverType: r.solver_type,
787
854
  outcome: r.outcome,
788
855
  detail: r.detail,
856
+ credentialId: r.credential_id,
857
+ costUsdMicros: r.cost_usd_micros,
858
+ model: r.model,
859
+ aiUnits: r.ai_units,
860
+ claimStatus: r.claim_status,
861
+ estimatedCostUsdMicros: r.estimated_cost_usd_micros,
862
+ actualCostUsdMicros: r.actual_cost_usd_micros,
789
863
  }));
790
864
  }
865
+ /**
866
+ * Total cost in micro-dollars recorded against a credential since the most
867
+ * recent UTC midnight. Backs the daily spend cap.
868
+ */
869
+ spentTodayMicros(credentialId, now = new Date()) {
870
+ const midnight = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())).toISOString();
871
+ const row = this.db.prepare(`SELECT COALESCE(SUM(cost_usd_micros), 0) AS total
872
+ FROM activity_events
873
+ WHERE credential_id = @cid AND ts IS NOT NULL AND ts >= @midnight`).get({ cid: credentialId, midnight });
874
+ return row.total;
875
+ }
876
+ /**
877
+ * Sum of `ai_units` for a credential within the current 6h UTC-aligned
878
+ * block (00:00 / 06:00 / 12:00 / 18:00 boundaries). Reads only rows whose
879
+ * `claim_status = 'claimed'` or `'delivered'` so failed-claim rows
880
+ * (`ai_units = 0`, `claim_status = 'claim_failed'`) don't muddy the sum
881
+ * even though their contribution is already zero.
882
+ *
883
+ * Issue #815. Backs the per-block AI-units ceiling gate.
884
+ */
885
+ aiUnitsThisBlock(credentialId, now = new Date()) {
886
+ const startOfDay = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
887
+ const sinceDayStart = now.getTime() - startOfDay;
888
+ const sixHoursMs = 6 * 60 * 60 * 1_000;
889
+ // Cap at 3 — there are 4 blocks per day (indices 0..3). Edge cases
890
+ // where sinceDayStart ≈ 24h (millisecond rounding) would otherwise
891
+ // overshoot into a non-existent 5th block in the *next* day.
892
+ const blocksIn = Math.min(Math.floor(sinceDayStart / sixHoursMs), 3);
893
+ const blockStart = new Date(startOfDay + blocksIn * sixHoursMs).toISOString();
894
+ const blockEnd = new Date(startOfDay + (blocksIn + 1) * sixHoursMs).toISOString();
895
+ const row = this.db.prepare(`SELECT COALESCE(SUM(ai_units), 0) AS total
896
+ FROM activity_events
897
+ WHERE credential_id = @cid
898
+ AND ts IS NOT NULL AND ts >= @blockStart AND ts < @blockEnd
899
+ AND claim_status IN ('claimed', 'delivered')`).get({ cid: credentialId, blockStart, blockEnd });
900
+ return row.total ?? 0;
901
+ }
902
+ /**
903
+ * Sum of `ai_units` for a credential within the trailing 7-day rolling
904
+ * window from `now`. Backs the per-week AI-units safety-net ceiling.
905
+ * Issue #815.
906
+ */
907
+ aiUnitsThisWeek(credentialId, now = new Date()) {
908
+ const weekStart = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1_000).toISOString();
909
+ const row = this.db.prepare(`SELECT COALESCE(SUM(ai_units), 0) AS total
910
+ FROM activity_events
911
+ WHERE credential_id = @cid
912
+ AND ts IS NOT NULL AND ts >= @weekStart
913
+ AND claim_status IN ('claimed', 'delivered')`).get({ cid: credentialId, weekStart });
914
+ return row.total ?? 0;
915
+ }
916
+ /**
917
+ * True iff an `ai_units_cap_reached` row exists for the given
918
+ * (credentialId, window, blockId). Used by the daemon to hydrate the
919
+ * AI-units gate's in-memory pause memo across restarts so the
920
+ * "exactly one event per (credential, window, block-id)" guarantee
921
+ * holds across process boundaries (issue #815, finding 1).
922
+ *
923
+ * Lookup is by `credential_id` + `kind` + the `[block=...][window=...]`
924
+ * markers that `daemon.ts` embeds in the row's `detail` string.
925
+ */
926
+ hasAiUnitsCapReachedFor(credentialId, window, blockId) {
927
+ const marker = `[block=${blockId}][window=${window}]`;
928
+ const row = this.db.prepare(`SELECT 1 AS hit
929
+ FROM activity_events
930
+ WHERE kind = 'ai_units_cap_reached'
931
+ AND credential_id = @cid
932
+ AND detail LIKE @marker
933
+ LIMIT 1`).get({ cid: credentialId, marker: `${marker}%` });
934
+ return row !== undefined;
935
+ }
936
+ /**
937
+ * Mark the per-request `claimed` row as `delivered` and record
938
+ * `actual_cost_usd_micros`. The `ai_units` projection captured at
939
+ * claim time is intentionally NOT recomputed — the issue spec says
940
+ * "estimates are the gate input, never recomputed". Idempotent: a
941
+ * no-op when no `claimed` row exists.
942
+ */
943
+ finalizeClaimDelivered(requestId, actualCostUsdMicros) {
944
+ this.db.prepare(`UPDATE activity_events
945
+ SET claim_status = 'delivered',
946
+ actual_cost_usd_micros = @actual
947
+ WHERE request_id = @req AND claim_status = 'claimed'`).run({ req: requestId, actual: actualCostUsdMicros });
948
+ }
791
949
  /** Newer events first, then ascending id for `jinn logs --follow` (oldest in batch printed first in caller). */
792
950
  getActivityEventsAfterId(afterId, limit) {
793
951
  const effectiveLimit = Math.max(0, Math.min(limit, 1000));
794
952
  const rows = this.db
795
- .prepare(`SELECT id, ts, kind, request_id, service_index, tx_hash, solver_type, outcome, detail
953
+ .prepare(`SELECT id, ts, kind, request_id, service_index, tx_hash, solver_type, outcome, detail,
954
+ credential_id, cost_usd_micros, model,
955
+ ai_units, claim_status, estimated_cost_usd_micros, actual_cost_usd_micros
796
956
  FROM activity_events
797
957
  WHERE id > @afterId
798
958
  ORDER BY id ASC
@@ -808,8 +968,99 @@ export class Store {
808
968
  solverType: r.solver_type,
809
969
  outcome: r.outcome,
810
970
  detail: r.detail,
971
+ credentialId: r.credential_id,
972
+ costUsdMicros: r.cost_usd_micros,
973
+ model: r.model,
974
+ aiUnits: r.ai_units,
975
+ claimStatus: r.claim_status,
976
+ estimatedCostUsdMicros: r.estimated_cost_usd_micros,
977
+ actualCostUsdMicros: r.actual_cost_usd_micros,
978
+ }));
979
+ }
980
+ /**
981
+ * Filtered, id-cursored page of activity events for the dedicated Events
982
+ * page. Newest-first.
983
+ *
984
+ * Cursors on `id` rather than `ts` so startup/shutdown rows with null
985
+ * timestamps remain reachable.
986
+ */
987
+ getActivityEventsPage(opts = {}) {
988
+ const effectiveLimit = Math.max(1, Math.min(opts.limit ?? 50, 200));
989
+ const clauses = [];
990
+ const params = { limit: effectiveLimit };
991
+ if (opts.kinds && opts.kinds.length > 0) {
992
+ const placeholders = opts.kinds.map((_, i) => `@kind${i}`);
993
+ clauses.push(`kind IN (${placeholders.join(', ')})`);
994
+ opts.kinds.forEach((k, i) => {
995
+ params[`kind${i}`] = k;
996
+ });
997
+ }
998
+ if (opts.outcome) {
999
+ clauses.push('outcome = @outcome');
1000
+ params['outcome'] = opts.outcome;
1001
+ }
1002
+ if (opts.requestId) {
1003
+ clauses.push('request_id = @requestId');
1004
+ params['requestId'] = opts.requestId;
1005
+ }
1006
+ if (opts.beforeId !== undefined) {
1007
+ clauses.push('id < @beforeId');
1008
+ params['beforeId'] = opts.beforeId;
1009
+ }
1010
+ const where = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';
1011
+ const rows = this.db.prepare(`SELECT id, ts, kind, request_id, service_index, tx_hash, solver_type, outcome, detail,
1012
+ credential_id, cost_usd_micros, model,
1013
+ ai_units, claim_status, estimated_cost_usd_micros, actual_cost_usd_micros
1014
+ FROM activity_events
1015
+ ${where}
1016
+ ORDER BY id DESC
1017
+ LIMIT @limit`).all(params);
1018
+ return rows.map((r) => ({
1019
+ id: r.id,
1020
+ ts: r.ts,
1021
+ kind: r.kind,
1022
+ requestId: r.request_id,
1023
+ serviceIndex: r.service_index,
1024
+ txHash: r.tx_hash,
1025
+ solverType: r.solver_type,
1026
+ outcome: r.outcome,
1027
+ detail: r.detail,
1028
+ credentialId: r.credential_id,
1029
+ costUsdMicros: r.cost_usd_micros,
1030
+ model: r.model,
1031
+ aiUnits: r.ai_units,
1032
+ claimStatus: r.claim_status,
1033
+ estimatedCostUsdMicros: r.estimated_cost_usd_micros,
1034
+ actualCostUsdMicros: r.actual_cost_usd_micros,
811
1035
  }));
812
1036
  }
1037
+ getActivityEventById(id) {
1038
+ const r = this.db.prepare(`SELECT id, ts, kind, request_id, service_index, tx_hash, solver_type, outcome, detail,
1039
+ credential_id, cost_usd_micros, model,
1040
+ ai_units, claim_status, estimated_cost_usd_micros, actual_cost_usd_micros
1041
+ FROM activity_events
1042
+ WHERE id = ?`).get(id);
1043
+ if (!r)
1044
+ return null;
1045
+ return {
1046
+ id: r.id,
1047
+ ts: r.ts,
1048
+ kind: r.kind,
1049
+ requestId: r.request_id,
1050
+ serviceIndex: r.service_index,
1051
+ txHash: r.tx_hash,
1052
+ solverType: r.solver_type,
1053
+ outcome: r.outcome,
1054
+ detail: r.detail,
1055
+ credentialId: r.credential_id,
1056
+ costUsdMicros: r.cost_usd_micros,
1057
+ model: r.model,
1058
+ aiUnits: r.ai_units,
1059
+ claimStatus: r.claim_status,
1060
+ estimatedCostUsdMicros: r.estimated_cost_usd_micros,
1061
+ actualCostUsdMicros: r.actual_cost_usd_micros,
1062
+ };
1063
+ }
813
1064
  getActivityCountsByKind() {
814
1065
  const rows = this.db.prepare(`SELECT kind, COUNT(*) as c FROM activity_events GROUP BY kind`).all();
815
1066
  const out = {};
@@ -1519,6 +1770,55 @@ export class Store {
1519
1770
  LIMIT @limit`).all(params);
1520
1771
  return rows.map(rowToEnvelopeProjection);
1521
1772
  }
1773
+ saveErc8004Anchor(input) {
1774
+ this.db.prepare(`INSERT INTO erc8004_anchors
1775
+ (envelope_id, envelope_cid, content_kind, metadata_key, agent_id,
1776
+ chain_id, identity_registry_address, tx_hash, block_number,
1777
+ payload_hex, anchored_at)
1778
+ VALUES
1779
+ (@envelopeId, @envelopeCid, @contentKind, @metadataKey, @agentId,
1780
+ @chainId, @identityRegistryAddress, @txHash, @blockNumber,
1781
+ @payloadHex, @anchoredAt)`).run({
1782
+ envelopeId: input.envelopeId,
1783
+ envelopeCid: input.envelopeCid,
1784
+ contentKind: input.contentKind,
1785
+ metadataKey: input.metadataKey,
1786
+ agentId: input.agentId,
1787
+ chainId: input.chainId,
1788
+ identityRegistryAddress: input.identityRegistryAddress,
1789
+ txHash: input.txHash,
1790
+ blockNumber: input.blockNumber,
1791
+ payloadHex: input.payloadHex,
1792
+ anchoredAt: input.anchoredAt,
1793
+ });
1794
+ }
1795
+ listErc8004AnchorsByEnvelopeCids(envelopeCids) {
1796
+ if (envelopeCids.length === 0)
1797
+ return [];
1798
+ const placeholders = envelopeCids.map((_, i) => `@cid${i}`).join(', ');
1799
+ const params = {};
1800
+ envelopeCids.forEach((cid, i) => { params[`cid${i}`] = cid; });
1801
+ const rows = this.db.prepare(`SELECT id, envelope_id, envelope_cid, content_kind, metadata_key, agent_id,
1802
+ chain_id, identity_registry_address, tx_hash, block_number,
1803
+ payload_hex, anchored_at
1804
+ FROM erc8004_anchors
1805
+ WHERE envelope_cid IN (${placeholders})
1806
+ ORDER BY anchored_at ASC, id ASC`).all(params);
1807
+ return rows.map((r) => ({
1808
+ id: r.id,
1809
+ envelopeId: r.envelope_id,
1810
+ envelopeCid: r.envelope_cid,
1811
+ contentKind: r.content_kind,
1812
+ metadataKey: r.metadata_key,
1813
+ agentId: r.agent_id,
1814
+ chainId: r.chain_id,
1815
+ identityRegistryAddress: r.identity_registry_address,
1816
+ txHash: r.tx_hash,
1817
+ blockNumber: r.block_number,
1818
+ payloadHex: r.payload_hex,
1819
+ anchoredAt: r.anchored_at,
1820
+ }));
1821
+ }
1522
1822
  close() {
1523
1823
  this.db.close();
1524
1824
  }