@jinn-network/client 0.1.6 → 0.1.7

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 (288) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/deployments/deployment-jinn-mvi-l1-sepolia-fast.json +23 -4
  3. package/deployments/deployment-jinn-mvi-l1-sepolia.json +23 -4
  4. package/deployments/deployment-jinn-mvi-l2-baseSepolia.json +5 -4
  5. package/dist/adapters/mech/adapter.d.ts +38 -1
  6. package/dist/adapters/mech/adapter.js +241 -54
  7. package/dist/adapters/mech/adapter.js.map +1 -1
  8. package/dist/adapters/mech/contracts.d.ts +17 -4
  9. package/dist/adapters/mech/contracts.js +8 -2
  10. package/dist/adapters/mech/contracts.js.map +1 -1
  11. package/dist/adapters/mech/safe-revert.d.ts +20 -0
  12. package/dist/adapters/mech/safe-revert.js +12 -4
  13. package/dist/adapters/mech/safe-revert.js.map +1 -1
  14. package/dist/adapters/mech/safe.d.ts +5 -1
  15. package/dist/adapters/mech/safe.js +27 -8
  16. package/dist/adapters/mech/safe.js.map +1 -1
  17. package/dist/adapters/mech/verdict-code.d.ts +1 -0
  18. package/dist/adapters/mech/verdict-code.js +18 -0
  19. package/dist/adapters/mech/verdict-code.js.map +1 -1
  20. package/dist/api/admin-endpoint.d.ts +15 -3
  21. package/dist/api/admin-endpoint.js +24 -2
  22. package/dist/api/admin-endpoint.js.map +1 -1
  23. package/dist/api/bootstrap-endpoint.js +49 -0
  24. package/dist/api/bootstrap-endpoint.js.map +1 -1
  25. package/dist/api/codex-doctor-endpoint.d.ts +73 -0
  26. package/dist/api/codex-doctor-endpoint.js +177 -0
  27. package/dist/api/codex-doctor-endpoint.js.map +1 -0
  28. package/dist/api/discovery-endpoint.d.ts +1 -0
  29. package/dist/api/discovery-endpoint.js +26 -0
  30. package/dist/api/discovery-endpoint.js.map +1 -1
  31. package/dist/api/fleet-build.d.ts +1 -0
  32. package/dist/api/fleet-build.js +2 -1
  33. package/dist/api/fleet-build.js.map +1 -1
  34. package/dist/api/gather-status.d.ts +11 -0
  35. package/dist/api/gather-status.js +400 -4
  36. package/dist/api/gather-status.js.map +1 -1
  37. package/dist/api/hermes-doctor-endpoint.d.ts +117 -0
  38. package/dist/api/hermes-doctor-endpoint.js +229 -23
  39. package/dist/api/hermes-doctor-endpoint.js.map +1 -1
  40. package/dist/api/launcher-status.d.ts +21 -16
  41. package/dist/api/launcher-status.js +2 -1
  42. package/dist/api/launcher-status.js.map +1 -1
  43. package/dist/api/portfolio-v0-build.d.ts +10 -0
  44. package/dist/api/portfolio-v0-build.js +24 -5
  45. package/dist/api/portfolio-v0-build.js.map +1 -1
  46. package/dist/api/prediction-v1-build.d.ts +10 -0
  47. package/dist/api/prediction-v1-build.js +7 -1
  48. package/dist/api/prediction-v1-build.js.map +1 -1
  49. package/dist/api/server.d.ts +31 -1
  50. package/dist/api/server.js +68 -1
  51. package/dist/api/server.js.map +1 -1
  52. package/dist/api/setup-endpoints.d.ts +16 -0
  53. package/dist/api/setup-endpoints.js +78 -4
  54. package/dist/api/setup-endpoints.js.map +1 -1
  55. package/dist/api/setup-retry-endpoint.d.ts +19 -0
  56. package/dist/api/setup-retry-endpoint.js +32 -0
  57. package/dist/api/setup-retry-endpoint.js.map +1 -0
  58. package/dist/api/solvernets-endpoints.d.ts +8 -0
  59. package/dist/api/solvernets-endpoints.js +71 -43
  60. package/dist/api/solvernets-endpoints.js.map +1 -1
  61. package/dist/api/status-build.d.ts +72 -0
  62. package/dist/api/status-build.js +73 -18
  63. package/dist/api/status-build.js.map +1 -1
  64. package/dist/api/task-run-routing.d.ts +7 -0
  65. package/dist/api/task-run-routing.js +12 -0
  66. package/dist/api/task-run-routing.js.map +1 -0
  67. package/dist/api/task-runs-build.d.ts +21 -0
  68. package/dist/api/task-runs-build.js +14 -1
  69. package/dist/api/task-runs-build.js.map +1 -1
  70. package/dist/build-info.json +4 -4
  71. package/dist/build-meta.json +1 -1
  72. package/dist/chain-read-errors.d.ts +10 -0
  73. package/dist/chain-read-errors.js +15 -0
  74. package/dist/chain-read-errors.js.map +1 -1
  75. package/dist/cli/commands/auth.js +1 -1
  76. package/dist/cli/commands/auth.js.map +1 -1
  77. package/dist/cli/commands/create.js +3 -2
  78. package/dist/cli/commands/create.js.map +1 -1
  79. package/dist/cli/commands/doctor.d.ts +2 -0
  80. package/dist/cli/commands/doctor.js +2 -0
  81. package/dist/cli/commands/doctor.js.map +1 -1
  82. package/dist/cli/commands/rewards.js +11 -7
  83. package/dist/cli/commands/rewards.js.map +1 -1
  84. package/dist/cli/commands/solver-nets.js +24 -9
  85. package/dist/cli/commands/solver-nets.js.map +1 -1
  86. package/dist/cli/commands/status.js +1 -1
  87. package/dist/cli/commands/status.js.map +1 -1
  88. package/dist/cli/commands/tasks.js +86 -9
  89. package/dist/cli/commands/tasks.js.map +1 -1
  90. package/dist/cli/commands/update.d.ts +10 -0
  91. package/dist/cli/commands/update.js +36 -0
  92. package/dist/cli/commands/update.js.map +1 -1
  93. package/dist/cli/introspection-context.js +5 -0
  94. package/dist/cli/introspection-context.js.map +1 -1
  95. package/dist/cli/task-native-readiness.d.ts +3 -1
  96. package/dist/cli/task-native-readiness.js +28 -6
  97. package/dist/cli/task-native-readiness.js.map +1 -1
  98. package/dist/config.d.ts +106 -5
  99. package/dist/config.js +97 -18
  100. package/dist/config.js.map +1 -1
  101. package/dist/daemon/checkpoint-loop.d.ts +48 -0
  102. package/dist/daemon/checkpoint-loop.js +76 -0
  103. package/dist/daemon/checkpoint-loop.js.map +1 -0
  104. package/dist/daemon/creator.d.ts +1 -1
  105. package/dist/daemon/creator.js +7 -3
  106. package/dist/daemon/creator.js.map +1 -1
  107. package/dist/daemon/daemon.d.ts +19 -0
  108. package/dist/daemon/daemon.js +68 -1
  109. package/dist/daemon/daemon.js.map +1 -1
  110. package/dist/daemon/eviction-loop.d.ts +40 -0
  111. package/dist/daemon/eviction-loop.js +67 -0
  112. package/dist/daemon/eviction-loop.js.map +1 -0
  113. package/dist/daemon/jinn-claim-loop-wiring.d.ts +33 -0
  114. package/dist/daemon/jinn-claim-loop-wiring.js +40 -0
  115. package/dist/daemon/jinn-claim-loop-wiring.js.map +1 -0
  116. package/dist/daemon/jinn-claim-loop.d.ts +24 -17
  117. package/dist/daemon/jinn-claim-loop.js +77 -23
  118. package/dist/daemon/jinn-claim-loop.js.map +1 -1
  119. package/dist/daemon/skip-log-dedup.d.ts +69 -0
  120. package/dist/daemon/skip-log-dedup.js +106 -0
  121. package/dist/daemon/skip-log-dedup.js.map +1 -0
  122. package/dist/dashboard/assets/index-BUlE8F3Y.js +330 -0
  123. package/dist/dashboard/assets/index-blqc7eqq.css +32 -0
  124. package/dist/dashboard/index.html +2 -2
  125. package/dist/discovery/factory.d.ts +17 -5
  126. package/dist/discovery/factory.js +46 -18
  127. package/dist/discovery/factory.js.map +1 -1
  128. package/dist/discovery/http.js +142 -3
  129. package/dist/discovery/http.js.map +1 -1
  130. package/dist/discovery/onchain.d.ts +5 -0
  131. package/dist/discovery/onchain.js +407 -15
  132. package/dist/discovery/onchain.js.map +1 -1
  133. package/dist/discovery/types.d.ts +45 -1
  134. package/dist/discovery/types.js +8 -10
  135. package/dist/discovery/types.js.map +1 -1
  136. package/dist/discovery/with-fallback.d.ts +7 -0
  137. package/dist/discovery/with-fallback.js +10 -0
  138. package/dist/discovery/with-fallback.js.map +1 -1
  139. package/dist/earning/bootstrap.d.ts +92 -1
  140. package/dist/earning/bootstrap.js +203 -63
  141. package/dist/earning/bootstrap.js.map +1 -1
  142. package/dist/earning/contracts.d.ts +14 -0
  143. package/dist/earning/contracts.js +17 -5
  144. package/dist/earning/contracts.js.map +1 -1
  145. package/dist/earning/funding-plan.js +27 -18
  146. package/dist/earning/funding-plan.js.map +1 -1
  147. package/dist/earning/jinn-rewards.d.ts +46 -0
  148. package/dist/earning/jinn-rewards.js +32 -0
  149. package/dist/earning/jinn-rewards.js.map +1 -1
  150. package/dist/earning/safe-adapter.d.ts +2 -0
  151. package/dist/earning/safe-adapter.js +26 -12
  152. package/dist/earning/safe-adapter.js.map +1 -1
  153. package/dist/earning/store.d.ts +8 -0
  154. package/dist/earning/store.js.map +1 -1
  155. package/dist/earning/testnet-setup-migration.d.ts +12 -0
  156. package/dist/earning/testnet-setup-migration.js +27 -1
  157. package/dist/earning/testnet-setup-migration.js.map +1 -1
  158. package/dist/earning/types.d.ts +15 -0
  159. package/dist/erc8004/reputation.d.ts +8 -0
  160. package/dist/erc8004/reputation.js +22 -3
  161. package/dist/erc8004/reputation.js.map +1 -1
  162. package/dist/harnesses/cost-estimates.d.ts +145 -0
  163. package/dist/harnesses/cost-estimates.js +297 -0
  164. package/dist/harnesses/cost-estimates.js.map +1 -0
  165. package/dist/harnesses/engine/engine.d.ts +72 -0
  166. package/dist/harnesses/engine/engine.js +105 -8
  167. package/dist/harnesses/engine/engine.js.map +1 -1
  168. package/dist/harnesses/engine/persistence.d.ts +51 -1
  169. package/dist/harnesses/engine/persistence.js +118 -5
  170. package/dist/harnesses/engine/persistence.js.map +1 -1
  171. package/dist/harnesses/engine/work-dir-reaper.d.ts +65 -0
  172. package/dist/harnesses/engine/work-dir-reaper.js +100 -0
  173. package/dist/harnesses/engine/work-dir-reaper.js.map +1 -0
  174. package/dist/harnesses/impls/hermes-agent/adapter.js +40 -0
  175. package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -1
  176. package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +20 -0
  177. package/dist/harnesses/impls/hermes-agent/bootstrap.js +40 -6
  178. package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
  179. package/dist/harnesses/impls/hermes-agent/harness.d.ts +59 -1
  180. package/dist/harnesses/impls/hermes-agent/harness.js +104 -0
  181. package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
  182. package/dist/harnesses/impls/index.d.ts +7 -0
  183. package/dist/harnesses/impls/index.js +16 -1
  184. package/dist/harnesses/impls/index.js.map +1 -1
  185. package/dist/harnesses/impls/learner/harness.d.ts +38 -4
  186. package/dist/harnesses/impls/learner/harness.js +96 -2
  187. package/dist/harnesses/impls/learner/harness.js.map +1 -1
  188. package/dist/harnesses/impls/learner/plugin-path.d.ts +0 -13
  189. package/dist/harnesses/impls/learner/plugin-path.js +35 -15
  190. package/dist/harnesses/impls/learner/plugin-path.js.map +1 -1
  191. package/dist/harnesses/impls/learner/types.d.ts +11 -0
  192. package/dist/harnesses/impls/stub.d.ts +58 -0
  193. package/dist/harnesses/impls/stub.js +89 -0
  194. package/dist/harnesses/impls/stub.js.map +1 -0
  195. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.d.ts +69 -50
  196. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +178 -93
  197. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
  198. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.d.ts +12 -1
  199. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +121 -7
  200. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
  201. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +15 -0
  202. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +54 -4
  203. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
  204. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.d.ts +6 -0
  205. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js +1 -1
  206. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js.map +1 -1
  207. package/dist/harnesses/readiness-registry.js +9 -1
  208. package/dist/harnesses/readiness-registry.js.map +1 -1
  209. package/dist/main.js +371 -82
  210. package/dist/main.js.map +1 -1
  211. package/dist/observability/emit-event.d.ts +1 -1
  212. package/dist/observability/emit-event.js.map +1 -1
  213. package/dist/operator-errors.d.ts +7 -0
  214. package/dist/operator-errors.js +13 -1
  215. package/dist/operator-errors.js.map +1 -1
  216. package/dist/plugins/learner/.claude-plugin/plugin.json +9 -0
  217. package/dist/plugins/learner/.codex-plugin/plugin.json +39 -0
  218. package/dist/plugins/learner/AGENTS.md +40 -0
  219. package/dist/plugins/learner/CLAUDE.md +33 -0
  220. package/dist/plugins/learner/README.md +59 -0
  221. package/dist/plugins/learner/hooks/hooks.json +16 -0
  222. package/dist/plugins/learner/hooks/session-start +38 -0
  223. package/dist/plugins/learner/skills/learn/SKILL.md +412 -0
  224. package/dist/plugins/learner/skills/learn/analyst-prompt.md +68 -0
  225. package/dist/plugins/learner/skills/learn/consolidator-prompt.md +94 -0
  226. package/dist/plugins/learner/skills/learn/explorer-prompt.md +53 -0
  227. package/dist/plugins/learner/skills/learn/planner-prompt.md +87 -0
  228. package/dist/plugins/learner/skills/learn/promoter-prompt.md +113 -0
  229. package/dist/plugins/learner/skills/learn/step-worker-prompt.md +47 -0
  230. package/dist/plugins/learner/skills/learn/strategist-prompt.md +85 -0
  231. package/dist/restart-daemon.d.ts +90 -0
  232. package/dist/restart-daemon.js +95 -0
  233. package/dist/restart-daemon.js.map +1 -0
  234. package/dist/setup/halt-mode.d.ts +14 -0
  235. package/dist/setup/halt-mode.js +17 -0
  236. package/dist/setup/halt-mode.js.map +1 -0
  237. package/dist/solver-nets/prediction-operator-ux.js +43 -3
  238. package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
  239. package/dist/solver-nets/registry.d.ts +1 -0
  240. package/dist/solver-nets/registry.js +1 -1
  241. package/dist/solver-nets/registry.js.map +1 -1
  242. package/dist/solver-types/_swe-rebench-v2-pool-cache.d.ts +58 -0
  243. package/dist/solver-types/_swe-rebench-v2-pool-cache.js +87 -0
  244. package/dist/solver-types/_swe-rebench-v2-pool-cache.js.map +1 -0
  245. package/dist/solver-types/_swe-rebench-v2-substrate.d.ts +1 -0
  246. package/dist/solver-types/_swe-rebench-v2-substrate.js +10 -0
  247. package/dist/solver-types/_swe-rebench-v2-substrate.js.map +1 -1
  248. package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +65 -0
  249. package/dist/solver-types/_swe-rebench-v2-validated-pool.js +243 -26
  250. package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
  251. package/dist/solver-types/swe-rebench-v2-auto.d.ts +22 -7
  252. package/dist/solver-types/swe-rebench-v2-auto.js +45 -20
  253. package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
  254. package/dist/solver-types/swe-rebench-v2.d.ts +13 -2
  255. package/dist/solver-types/swe-rebench-v2.js +233 -94
  256. package/dist/solver-types/swe-rebench-v2.js.map +1 -1
  257. package/dist/solvernets/daemon-init.d.ts +10 -2
  258. package/dist/solvernets/daemon-init.js +22 -2
  259. package/dist/solvernets/daemon-init.js.map +1 -1
  260. package/dist/solvernets/launched-record-dispatcher.js +35 -7
  261. package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
  262. package/dist/solvernets/store.d.ts +5 -0
  263. package/dist/solvernets/store.js +1 -0
  264. package/dist/solvernets/store.js.map +1 -1
  265. package/dist/store/store.d.ts +15 -0
  266. package/dist/store/store.js +118 -3
  267. package/dist/store/store.js.map +1 -1
  268. package/dist/tasks/sources.d.ts +18 -1
  269. package/dist/tasks/sources.js +33 -5
  270. package/dist/tasks/sources.js.map +1 -1
  271. package/dist/tx-retry.d.ts +151 -19
  272. package/dist/tx-retry.js +286 -32
  273. package/dist/tx-retry.js.map +1 -1
  274. package/dist/types/payloads/prediction-apy-v0.d.ts +5 -5
  275. package/dist/types/payloads/prediction-v0.d.ts +5 -5
  276. package/dist/types/task-document.d.ts +392 -0
  277. package/dist/types/task-document.js +10 -0
  278. package/dist/types/task-document.js.map +1 -1
  279. package/dist/types/task.d.ts +28 -0
  280. package/dist/util/extract-tx-hash.d.ts +14 -0
  281. package/dist/util/extract-tx-hash.js +19 -0
  282. package/dist/util/extract-tx-hash.js.map +1 -0
  283. package/dist/vendor/@jinn-network/sdk/dist/contracts.js +1 -1
  284. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.d.ts +3 -0
  285. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.js +1 -0
  286. package/package.json +29 -12
  287. package/dist/dashboard/assets/index-DOlzFN8a.css +0 -32
  288. package/dist/dashboard/assets/index-NkZ7CTAT.js +0 -140
@@ -11,6 +11,10 @@
11
11
  * `installed: false` means the binary was not found (ENOENT or equivalent).
12
12
  * `exitCode !== 0` (with `installed: true`) means the binary exists but
13
13
  * reports a config problem.
14
+ *
15
+ * The probe logic is exported as `probeHermesDoctor` so the Hermes harness
16
+ * can reuse it from `isReady()` — same source of truth for the SPA
17
+ * precheck panel and the daemon's claim-readiness gate (#330).
14
18
  */
15
19
  import type { Hono } from 'hono';
16
20
  export interface HermesDoctorResponse {
@@ -23,4 +27,117 @@ export interface HermesDoctorConfig {
23
27
  hermesPath?: string;
24
28
  hermesDoctorTimeoutMs?: number;
25
29
  }
30
+ /**
31
+ * Synchronously runs `hermes doctor` and classifies the result. Pure (no
32
+ * Hono dependency) so the harness layer can call it without pulling the API
33
+ * server in.
34
+ */
35
+ export declare function probeHermesDoctor(config?: HermesDoctorConfig): HermesDoctorResponse;
36
+ /**
37
+ * Result of probing a single Hermes model provider's auth state.
38
+ */
39
+ export interface HermesAuthStatus {
40
+ /** Provider name probed, e.g. `openrouter`. */
41
+ provider: string;
42
+ /** True only when the provider has a usable credential. */
43
+ authed: boolean;
44
+ /** Raw `hermes auth list <provider>` stdout (trimmed, truncated). */
45
+ raw: string;
46
+ }
47
+ /**
48
+ * Synchronously runs `hermes auth list <provider>` and classifies whether the
49
+ * provider has a usable credential (API-key OR OAuth) in Hermes's credential
50
+ * pool.
51
+ *
52
+ * WHY `auth list`, not `auth status`: `hermes auth status <provider>` only
53
+ * reflects interactive-OAuth-login state (the `providers` block in
54
+ * `~/.hermes/auth.json`). It prints `<provider>: logged out` whenever there
55
+ * is no OAuth session — even when an API-key credential is present and
56
+ * working. An operator who authenticated to OpenRouter the normal way
57
+ * (`OPENROUTER_API_KEY` env var, or `hermes auth add`) would be wrongly
58
+ * reported not-ready and gated out of every claim. `hermes auth list` reads
59
+ * the `credential_pool`, so it sees api_key credentials too.
60
+ *
61
+ * Parsing (`auth list <provider>` output, see `auth_list_command` in
62
+ * hermes_cli/auth_commands.py):
63
+ * - empty stdout → no credential of any kind → not authed
64
+ * - a `<provider> (N credentials):` header followed by ` #<idx> ...` lines,
65
+ * one per pooled credential → authed iff at least one line is *usable*
66
+ * (not exhausted with a wait window still open, not a hard auth failure)
67
+ * - ENOENT / spawn error → not authed (binary not on PATH)
68
+ *
69
+ * `hermes auth list` exits 0 in all of these cases; the signal is entirely in
70
+ * stdout. Pure (no Hono dependency) so the harness layer can call it without
71
+ * pulling the API server in. This is the third readiness gate for Hermes:
72
+ * `hermes doctor` exits 0 even when every provider is logged out (it treats
73
+ * missing providers as warnings), so the harness must probe auth directly.
74
+ */
75
+ export declare function probeHermesAuthStatus(provider: string, config?: HermesDoctorConfig): HermesAuthStatus;
26
76
  export declare function addHermesDoctorRoutes(app: Hono, config?: HermesDoctorConfig): void;
77
+ /**
78
+ * Result of probing OpenRouter's `/api/v1/key` endpoint for spendable credit.
79
+ *
80
+ * `state` is the verdict we feed into readiness:
81
+ * - `ok` → remaining credit is at or above the floor → ready
82
+ * - `exhausted` → remaining credit is below the floor → NOT ready (clear
83
+ * actionable signal: operator must top up)
84
+ * - `unknown` → couldn't determine — network error, non-200, malformed
85
+ * JSON, missing API key. Readiness MUST treat this as
86
+ * fail-safe (ready=true) so a transient OpenRouter outage
87
+ * does not shut every operator down (#332 / production
88
+ * bug 2026-05-23: false-positive ready when credit
89
+ * exhausted, but we explicitly do NOT want the inverse
90
+ * false-negative).
91
+ *
92
+ * `remainingUsd` and `floorUsd` are populated when known (state=`ok` or
93
+ * `exhausted`) so the readiness `nextStep` can show the operator how short
94
+ * they are. `raw` carries the truncated response body for diagnostics.
95
+ */
96
+ export interface OpenRouterCreditStatus {
97
+ state: 'ok' | 'exhausted' | 'unknown';
98
+ remainingUsd?: number;
99
+ limitUsd?: number | null;
100
+ usageUsd?: number;
101
+ floorUsd: number;
102
+ reason?: string;
103
+ raw?: string;
104
+ }
105
+ export interface OpenRouterCreditConfig {
106
+ /**
107
+ * Per-task credit floor in USD. The default is generous enough to cover a
108
+ * single SWE-rebench solve with `max_tokens=32000` against the priciest
109
+ * frontier models at typical 2026 OpenRouter rates ($3-$5 / Mtok output =
110
+ * $0.10-$0.16 per solve), with headroom for input-token cost and the
111
+ * occasional retry. Tune via the env override below if a SolverNet pins
112
+ * a different model class.
113
+ */
114
+ floorUsd?: number;
115
+ /** Override the OpenRouter API key (defaults to `process.env.OPENROUTER_API_KEY`). */
116
+ apiKey?: string;
117
+ /** Inject a custom fetch for tests; defaults to global `fetch`. */
118
+ fetchFn?: typeof fetch;
119
+ /** HTTP timeout in ms. Defaults to 5s — readiness probes must not stall the daemon. */
120
+ timeoutMs?: number;
121
+ }
122
+ export declare const DEFAULT_OPENROUTER_CREDIT_FLOOR_USD: number;
123
+ /**
124
+ * Probes `GET https://openrouter.ai/api/v1/key` to determine whether the
125
+ * operator's OpenRouter credential has spendable credit above the per-task
126
+ * floor.
127
+ *
128
+ * WHY this gate exists (production bug, 2026-05-23): the existing readiness
129
+ * gates — `hermes doctor` + `hermes auth list openrouter` — verify that a
130
+ * credential is *present* and pool-healthy, but say nothing about whether
131
+ * the credential's *credit balance* is sufficient to run a task. On
132
+ * 2026-05-23 every solve attempt for the day returned `HTTP 402` from
133
+ * OpenRouter ("This request requires more credits, or fewer max_tokens.")
134
+ * while readiness reported ready=true — the harness silently burned 12
135
+ * sessions. This probe closes that gap.
136
+ *
137
+ * Fail-safe philosophy: a clearly-confirmed insufficient-credit signal flips
138
+ * `ready=false`; anything ambiguous (network failure, non-200, missing key)
139
+ * returns `state=unknown` so the caller treats the harness as ready. The
140
+ * inverse false-negative — shutting every operator down because OpenRouter
141
+ * is transiently down — is worse than the original bug.
142
+ */
143
+ export declare function probeOpenRouterCredit(config?: OpenRouterCreditConfig): Promise<OpenRouterCreditStatus>;
@@ -1,29 +1,235 @@
1
1
  import { spawnSync } from 'node:child_process';
2
+ /**
3
+ * Shared `hermes <args>` spawn scaffolding for both probes: resolves the binary
4
+ * and timeout from config, runs `spawnSync`, and extracts the spawn-error code.
5
+ * Each probe applies its own classification/parsing to the returned result.
6
+ */
7
+ function runHermes(args, config) {
8
+ const hermesBin = config.hermesPath ?? 'hermes';
9
+ const timeoutMs = config.hermesDoctorTimeoutMs ?? 30_000;
10
+ const result = spawnSync(hermesBin, args, {
11
+ timeout: timeoutMs,
12
+ encoding: 'utf8',
13
+ });
14
+ const errorCode = result.error?.code;
15
+ return { result, errorCode };
16
+ }
17
+ /**
18
+ * Synchronously runs `hermes doctor` and classifies the result. Pure (no
19
+ * Hono dependency) so the harness layer can call it without pulling the API
20
+ * server in.
21
+ */
22
+ export function probeHermesDoctor(config = {}) {
23
+ const { result, errorCode } = runHermes(['doctor'], config);
24
+ // installed=true means we found the binary on disk. ENOENT is the only
25
+ // definitive not-installed signal. Other errors (EACCES = wrong
26
+ // permissions; ETIMEDOUT = ran but didn't finish in time) indicate the
27
+ // binary exists but couldn't be exercised cleanly — surface those as
28
+ // config-issue, not missing.
29
+ const notFound = errorCode === 'ENOENT';
30
+ const installed = !notFound && (result.status !== null
31
+ || result.signal !== null
32
+ || (errorCode != null && errorCode !== 'ENOENT'));
33
+ return {
34
+ installed,
35
+ exitCode: result.status,
36
+ stdout: (result.stdout ?? '').slice(0, 4000),
37
+ stderr: (result.stderr ?? '').slice(0, 4000),
38
+ };
39
+ }
40
+ /**
41
+ * Detects whether a single `hermes auth list` credential line is currently
42
+ * *unusable* — i.e. the credential pool has flagged it exhausted with retry
43
+ * time still on the clock, or marked it as a hard auth failure.
44
+ *
45
+ * `hermes auth list` annotates exhausted entries via
46
+ * `_format_exhausted_status` (hermes_cli/auth_commands.py). The annotation
47
+ * forms we treat as still-usable:
48
+ * - no annotation at all → healthy credential
49
+ * - `... (ready to retry)` → exhaustion window has elapsed; usable
50
+ * The forms we treat as unusable:
51
+ * - `... rate-limited ... (12m 3s left)` / `... exhausted ... (1h 4m left)`
52
+ * - `... auth failed ... (re-auth may be required)`
53
+ *
54
+ * A line that carries an exhaustion keyword but no `(ready to retry)` and no
55
+ * `re-auth` hint (e.g. exhausted with a wait window still open) is unusable.
56
+ */
57
+ function isCredentialLineUnusable(line) {
58
+ // `(ready to retry)` means the exhaustion window has elapsed — usable.
59
+ if (/\(ready to retry\)/i.test(line))
60
+ return false;
61
+ // A hard auth failure or any still-open exhaustion window → unusable.
62
+ return /\bauth failed\b|\(re-auth may be required\)|\brate-limited\b|\bexhausted\b/i.test(line);
63
+ }
64
+ /**
65
+ * Synchronously runs `hermes auth list <provider>` and classifies whether the
66
+ * provider has a usable credential (API-key OR OAuth) in Hermes's credential
67
+ * pool.
68
+ *
69
+ * WHY `auth list`, not `auth status`: `hermes auth status <provider>` only
70
+ * reflects interactive-OAuth-login state (the `providers` block in
71
+ * `~/.hermes/auth.json`). It prints `<provider>: logged out` whenever there
72
+ * is no OAuth session — even when an API-key credential is present and
73
+ * working. An operator who authenticated to OpenRouter the normal way
74
+ * (`OPENROUTER_API_KEY` env var, or `hermes auth add`) would be wrongly
75
+ * reported not-ready and gated out of every claim. `hermes auth list` reads
76
+ * the `credential_pool`, so it sees api_key credentials too.
77
+ *
78
+ * Parsing (`auth list <provider>` output, see `auth_list_command` in
79
+ * hermes_cli/auth_commands.py):
80
+ * - empty stdout → no credential of any kind → not authed
81
+ * - a `<provider> (N credentials):` header followed by ` #<idx> ...` lines,
82
+ * one per pooled credential → authed iff at least one line is *usable*
83
+ * (not exhausted with a wait window still open, not a hard auth failure)
84
+ * - ENOENT / spawn error → not authed (binary not on PATH)
85
+ *
86
+ * `hermes auth list` exits 0 in all of these cases; the signal is entirely in
87
+ * stdout. Pure (no Hono dependency) so the harness layer can call it without
88
+ * pulling the API server in. This is the third readiness gate for Hermes:
89
+ * `hermes doctor` exits 0 even when every provider is logged out (it treats
90
+ * missing providers as warnings), so the harness must probe auth directly.
91
+ */
92
+ export function probeHermesAuthStatus(provider, config = {}) {
93
+ const { result, errorCode } = runHermes(['auth', 'list', provider], config);
94
+ const raw = (result.stdout ?? '').trim().slice(0, 4000);
95
+ // Binary not found, or any other spawn error, or no output → not authed.
96
+ // Empty stdout means `auth_list_command` skipped the provider section
97
+ // because the credential pool has zero entries for it.
98
+ if (errorCode != null || raw.length === 0) {
99
+ return { provider, authed: false, raw };
100
+ }
101
+ // Credential lines are the ` #<idx> ...` rows under the provider header.
102
+ // A provider is usable when at least one of its pooled credentials is not
103
+ // currently exhausted / hard-failed.
104
+ const credentialLines = raw
105
+ .split('\n')
106
+ .filter((line) => /^\s*#\d+\b/.test(line));
107
+ if (credentialLines.length === 0) {
108
+ // Header present but no credential rows parsed — treat as not authed
109
+ // rather than guess.
110
+ return { provider, authed: false, raw };
111
+ }
112
+ const hasUsableCredential = credentialLines.some((line) => !isCredentialLineUnusable(line));
113
+ return { provider, authed: hasUsableCredential, raw };
114
+ }
2
115
  export function addHermesDoctorRoutes(app, config = {}) {
3
116
  app.get('/api/hermes/doctor', (c) => {
4
- const hermesBin = config.hermesPath ?? 'hermes';
5
- const timeoutMs = config.hermesDoctorTimeoutMs ?? 30_000;
6
- const result = spawnSync(hermesBin, ['doctor'], {
7
- timeout: timeoutMs,
8
- encoding: 'utf8',
9
- });
10
- const errorCode = result.error?.code;
11
- // installed=true means we found the binary on disk. ENOENT is the only
12
- // definitive not-installed signal. Other errors (EACCES = wrong
13
- // permissions; ETIMEDOUT = ran but didn't finish in time) indicate the
14
- // binary exists but couldn't be exercised cleanly — surface those as
15
- // config-issue, not missing.
16
- const notFound = errorCode === 'ENOENT';
17
- const installed = !notFound && (result.status !== null
18
- || result.signal !== null
19
- || (errorCode != null && errorCode !== 'ENOENT'));
20
- const body = {
21
- installed,
22
- exitCode: result.status,
23
- stdout: (result.stdout ?? '').slice(0, 4000),
24
- stderr: (result.stderr ?? '').slice(0, 4000),
25
- };
26
- return c.json(body);
117
+ return c.json(probeHermesDoctor(config));
27
118
  });
28
119
  }
120
+ /**
121
+ * Default per-task credit floor (USD). See {@link OpenRouterCreditConfig}.
122
+ *
123
+ * Sized to comfortably cover one solve on a cheap routed model (e.g.
124
+ * `deepseek/deepseek-v4-flash` — typical solve costs ~$0.01-0.02 with the
125
+ * `JINN_HERMES_MAX_TOKENS_CAP` of 32000). An operator using a premium model
126
+ * (Sonnet, GPT-5) should override via the `JINN_HERMES_CREDIT_FLOOR_USD`
127
+ * env var (or pass `floorUsd` explicitly).
128
+ *
129
+ * History: a too-conservative initial default of $0.50 — sized for Sonnet —
130
+ * silently gated out deepseek operators with $0.43 remaining (enough for
131
+ * ~25 solves) on 2026-05-23. The right size is the cost of *one* task with
132
+ * comfortable headroom, not a Sonnet-class reserve.
133
+ */
134
+ const DEFAULT_OPENROUTER_CREDIT_FLOOR_USD_FALLBACK = 0.02;
135
+ const envFloor = process.env['JINN_HERMES_CREDIT_FLOOR_USD'];
136
+ const envFloorParsed = envFloor !== undefined ? Number(envFloor) : NaN;
137
+ export const DEFAULT_OPENROUTER_CREDIT_FLOOR_USD = Number.isFinite(envFloorParsed) && envFloorParsed > 0
138
+ ? envFloorParsed
139
+ : DEFAULT_OPENROUTER_CREDIT_FLOOR_USD_FALLBACK;
140
+ /**
141
+ * Probes `GET https://openrouter.ai/api/v1/key` to determine whether the
142
+ * operator's OpenRouter credential has spendable credit above the per-task
143
+ * floor.
144
+ *
145
+ * WHY this gate exists (production bug, 2026-05-23): the existing readiness
146
+ * gates — `hermes doctor` + `hermes auth list openrouter` — verify that a
147
+ * credential is *present* and pool-healthy, but say nothing about whether
148
+ * the credential's *credit balance* is sufficient to run a task. On
149
+ * 2026-05-23 every solve attempt for the day returned `HTTP 402` from
150
+ * OpenRouter ("This request requires more credits, or fewer max_tokens.")
151
+ * while readiness reported ready=true — the harness silently burned 12
152
+ * sessions. This probe closes that gap.
153
+ *
154
+ * Fail-safe philosophy: a clearly-confirmed insufficient-credit signal flips
155
+ * `ready=false`; anything ambiguous (network failure, non-200, missing key)
156
+ * returns `state=unknown` so the caller treats the harness as ready. The
157
+ * inverse false-negative — shutting every operator down because OpenRouter
158
+ * is transiently down — is worse than the original bug.
159
+ */
160
+ export async function probeOpenRouterCredit(config = {}) {
161
+ const floorUsd = config.floorUsd ?? DEFAULT_OPENROUTER_CREDIT_FLOOR_USD;
162
+ const apiKey = config.apiKey ?? process.env['OPENROUTER_API_KEY'];
163
+ const fetchFn = config.fetchFn ?? fetch;
164
+ const timeoutMs = config.timeoutMs ?? 5_000;
165
+ // No API key → unknown (fail-safe). The auth-list gate would have caught
166
+ // a missing credential already; if we somehow get here without one, do
167
+ // not flip the operator into not-ready on a probe we can't even run.
168
+ if (!apiKey) {
169
+ return { state: 'unknown', floorUsd, reason: 'OPENROUTER_API_KEY not set' };
170
+ }
171
+ const controller = new AbortController();
172
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
173
+ try {
174
+ const response = await fetchFn('https://openrouter.ai/api/v1/key', {
175
+ method: 'GET',
176
+ headers: { Authorization: `Bearer ${apiKey}` },
177
+ signal: controller.signal,
178
+ });
179
+ if (!response.ok) {
180
+ // Non-200 (including 401/403/5xx) — unknown, not exhausted. A 401
181
+ // would imply the credential is broken, but the auth-list gate
182
+ // already covered presence; treating an auth-broken state here as
183
+ // "exhausted" would mis-classify it. Fail-safe to unknown.
184
+ const raw = await safeReadResponse(response);
185
+ return {
186
+ state: 'unknown',
187
+ floorUsd,
188
+ reason: `OpenRouter /api/v1/key returned HTTP ${response.status}`,
189
+ raw,
190
+ };
191
+ }
192
+ const body = (await response.json());
193
+ const data = body?.data;
194
+ if (!data || typeof data !== 'object') {
195
+ return { state: 'unknown', floorUsd, reason: 'OpenRouter /api/v1/key returned malformed body' };
196
+ }
197
+ const usageUsd = typeof data.usage === 'number' ? data.usage : 0;
198
+ // `limit` can be `null` for unlimited keys — treat that as plenty of credit.
199
+ // `undefined` means the field was absent from the response body, which is
200
+ // ambiguous (API schema drift?) — return `unknown` so a future shape
201
+ // change does not silently pass readiness.
202
+ if (data.limit === null) {
203
+ return { state: 'ok', floorUsd, limitUsd: null, usageUsd };
204
+ }
205
+ if (data.limit === undefined) {
206
+ return { state: 'unknown', floorUsd, reason: 'OpenRouter /api/v1/key response missing `data.limit`' };
207
+ }
208
+ const limitUsd = data.limit;
209
+ // Prefer the API's `data.limit_remaining` (authoritative for the current
210
+ // billing window when the key has a periodic reset) over `limit - usage`
211
+ // (which is all-time and underestimates remaining credit on resetting
212
+ // keys). Fall back to the subtraction when `limit_remaining` is absent.
213
+ const remainingUsd = typeof data.limit_remaining === 'number' ? data.limit_remaining : limitUsd - usageUsd;
214
+ const state = remainingUsd >= floorUsd ? 'ok' : 'exhausted';
215
+ return { state, floorUsd, remainingUsd, limitUsd, usageUsd };
216
+ }
217
+ catch (err) {
218
+ // Network error, timeout, abort, JSON parse failure — unknown (fail-safe).
219
+ const reason = err instanceof Error ? err.message : String(err);
220
+ return { state: 'unknown', floorUsd, reason };
221
+ }
222
+ finally {
223
+ clearTimeout(timer);
224
+ }
225
+ }
226
+ async function safeReadResponse(response) {
227
+ try {
228
+ const text = await response.text();
229
+ return text.slice(0, 4000);
230
+ }
231
+ catch {
232
+ return '';
233
+ }
234
+ }
29
235
  //# sourceMappingURL=hermes-doctor-endpoint.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hermes-doctor-endpoint.js","sourceRoot":"","sources":["../../src/api/hermes-doctor-endpoint.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAc/C,MAAM,UAAU,qBAAqB,CAAC,GAAS,EAAE,SAA6B,EAAE;IAC9E,GAAG,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC,CAAC,EAAE,EAAE;QAClC,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,IAAI,QAAQ,CAAC;QAChD,MAAM,SAAS,GAAG,MAAM,CAAC,qBAAqB,IAAI,MAAM,CAAC;QAEzD,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE;YAC9C,OAAO,EAAE,SAAS;YAClB,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;QAEH,MAAM,SAAS,GAAI,MAAM,CAAC,KAA2C,EAAE,IAAI,CAAC;QAC5E,uEAAuE;QACvE,gEAAgE;QAChE,uEAAuE;QACvE,qEAAqE;QACrE,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,SAAS,KAAK,QAAQ,CAAC;QACxC,MAAM,SAAS,GAAG,CAAC,QAAQ,IAAI,CAC7B,MAAM,CAAC,MAAM,KAAK,IAAI;eACnB,MAAM,CAAC,MAAM,KAAK,IAAI;eACtB,CAAC,SAAS,IAAI,IAAI,IAAI,SAAS,KAAK,QAAQ,CAAC,CACjD,CAAC;QACF,MAAM,IAAI,GAAyB;YACjC,SAAS;YACT,QAAQ,EAAE,MAAM,CAAC,MAAM;YACvB,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;YAC5C,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;SAC7C,CAAC;QAEF,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"hermes-doctor-endpoint.js","sourceRoot":"","sources":["../../src/api/hermes-doctor-endpoint.ts"],"names":[],"mappings":"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"}
@@ -8,10 +8,10 @@
8
8
  * spec/2026-05-05-solvernet-creation-and-launch.md dropped that enum value);
9
9
  * the launched-record subsystem owns that signal now.
10
10
  *
11
- * Stale-poll detection is computed here from the generator's reported
12
- * `lastPollAt` and `cadenceMs`: a poll is stale when the wall clock has
13
- * advanced past `lastPollAt + 2 * cadenceMs`. The factor matches
14
- * spec/2026-05-05-launcher-role-and-mode.md §5.3.
11
+ * Stale-poll detection is computed here when a generator reports a cadence:
12
+ * a poll is stale when the wall clock has advanced past `lastPollAt + 2 *
13
+ * cadenceMs`. Fill-the-pool generators may omit cadence and are never marked
14
+ * stale by this generic status surface.
15
15
  *
16
16
  * The deps shape is intentionally narrow — every external surface is a
17
17
  * function so tests can inject deterministic state without standing up the
@@ -23,18 +23,27 @@ import type { JinnConfig } from '../config.js';
23
23
  export interface LauncherStatusGeneratorView {
24
24
  state: 'active' | 'paused' | 'errored';
25
25
  lastPollAt?: string;
26
- lastPollSummary?: {
27
- evaluated: number;
28
- posted: number;
29
- skipped: number;
30
- };
26
+ lastPollSummary?: LauncherGeneratorPollSummary;
31
27
  lastError?: {
32
28
  message: string;
33
29
  at: string;
34
30
  };
35
- cadenceMs: number;
31
+ cadenceMs?: number;
36
32
  stale: boolean;
37
33
  }
34
+ export type LauncherGeneratorPollSummary = {
35
+ evaluated: number;
36
+ posted: number;
37
+ skipped: number;
38
+ } | {
39
+ poolSize: number;
40
+ posted: number;
41
+ unposted: number;
42
+ live: number;
43
+ repostable: number;
44
+ saturated: number;
45
+ abandoned: number;
46
+ };
38
47
  export interface LauncherStatusBudgetView {
39
48
  safeAddress: string;
40
49
  safeBalanceWei: string;
@@ -60,16 +69,12 @@ export interface LauncherStatusResponse {
60
69
  */
61
70
  export interface LauncherGeneratorStateSnapshot {
62
71
  lastPollAt?: string;
63
- lastPollSummary?: {
64
- evaluated: number;
65
- posted: number;
66
- skipped: number;
67
- };
72
+ lastPollSummary?: LauncherGeneratorPollSummary;
68
73
  lastError?: {
69
74
  message: string;
70
75
  at: string;
71
76
  };
72
- cadenceMs: number;
77
+ cadenceMs?: number;
73
78
  }
74
79
  export interface GatherLauncherStatusDeps {
75
80
  config: Pick<JinnConfig, 'solverNets'>;
@@ -52,9 +52,10 @@ export async function gatherLauncherStatus(deps) {
52
52
  ]);
53
53
  const generator = {
54
54
  state: generatorState,
55
- cadenceMs: snapshot?.cadenceMs ?? 0,
56
55
  stale,
57
56
  };
57
+ if (snapshot?.cadenceMs !== undefined)
58
+ generator.cadenceMs = snapshot.cadenceMs;
58
59
  if (snapshot?.lastPollAt)
59
60
  generator.lastPollAt = snapshot.lastPollAt;
60
61
  if (snapshot?.lastPollSummary)
@@ -1 +1 @@
1
- {"version":3,"file":"launcher-status.js","sourceRoot":"","sources":["../../src/api/launcher-status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"launcher-status.js","sourceRoot":"","sources":["../../src/api/launcher-status.ts"],"names":[],"mappings":"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"}
@@ -64,7 +64,17 @@ export interface PortfolioV0Status {
64
64
  totals: {
65
65
  /** Tasks that reached terminal success and delivered their result. */
66
66
  delivered: number;
67
+ /**
68
+ * Sum of `settledFailed` and `localErrors`. Retained for callers that
69
+ * still want a single failure count; new surfaces should prefer the
70
+ * split fields to distinguish on-chain settled fails from local
71
+ * engine errors.
72
+ */
67
73
  failed: number;
74
+ /** FAILED runs whose delivery tx landed on-chain (settled failure). */
75
+ settledFailed: number;
76
+ /** FAILED runs that never reached the marketplace (local engine error). */
77
+ localErrors: number;
68
78
  active: number;
69
79
  };
70
80
  /** Tasks currently being processed (not in a terminal state). */
@@ -12,6 +12,7 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs';
12
12
  import { homedir } from 'node:os';
13
13
  import { join } from 'node:path';
14
14
  import { TaskRunPersistence } from '../harnesses/engine/persistence.js';
15
+ import { taskRunRoutingKey } from './task-run-routing.js';
15
16
  /** Default per-task engine work root; kept in sync with `config.engine.workingDirRoot`. */
16
17
  export const DEFAULT_ENGINE_WORKING_DIR_ROOT = join(homedir(), '.jinn-client', 'engine', 'work');
17
18
  const RECENT_CLAUDE_OUTCOMES_LIMIT = 10;
@@ -52,16 +53,25 @@ function toVerdict(task) {
52
53
  */
53
54
  export function gatherPortfolioV0Status(store, workingDirRoot = DEFAULT_ENGINE_WORKING_DIR_ROOT) {
54
55
  const persistence = new TaskRunPersistence(store.db);
55
- // In-flight: all non-terminal task runs
56
- const inFlight = persistence.getInFlight().map(toInFlightTask);
56
+ // portfolio.v0 is a solver-specific status payload — filter task_runs by
57
+ // the daemon's internal routing key so other SolverNets' runs don't leak
58
+ // into these counters (jinn-mono-0t6p) while historical rows can still be
59
+ // classified from canonical `contractId` / `contractVersion` or the legacy
60
+ // `task_payload.solverType` alias.
61
+ const inFlight = persistence.getInFlight().filter(isPortfolioV0Run);
62
+ const complete = persistence.getByState('COMPLETE').filter(isPortfolioV0Run);
63
+ const failed = persistence.getByState('FAILED').filter(isPortfolioV0Run);
64
+ const inFlightSummaries = inFlight.map(toInFlightTask);
57
65
  // Recent verdicts: last N COMPLETE + FAILED task runs combined, newest first
58
- const complete = persistence.getByState('COMPLETE');
59
- const failed = persistence.getByState('FAILED');
60
66
  const allTerminal = [...complete, ...failed].sort((a, b) => b.stateUpdatedAt - a.stateUpdatedAt);
61
67
  const recentVerdicts = allTerminal.slice(0, RECENT_VERDICTS_LIMIT).map(toVerdict);
68
+ const settledFailed = failed.filter((task) => task.deliveryTxHash !== null);
69
+ const localErrors = failed.filter((task) => task.deliveryTxHash === null);
62
70
  const totals = {
63
71
  delivered: complete.length,
64
72
  failed: failed.length,
73
+ settledFailed: settledFailed.length,
74
+ localErrors: localErrors.length,
65
75
  active: inFlight.length,
66
76
  };
67
77
  // Recent system_snapshot artifacts (tagged with 'system_snapshot')
@@ -84,7 +94,16 @@ export function gatherPortfolioV0Status(store, workingDirRoot = DEFAULT_ENGINE_W
84
94
  recentSnapshots = [];
85
95
  }
86
96
  const recentClaudeOutcomes = gatherRecentClaudeOutcomes(workingDirRoot);
87
- return { totals, inFlight, recentVerdicts, recentSnapshots, recentClaudeOutcomes };
97
+ return {
98
+ totals,
99
+ inFlight: inFlightSummaries,
100
+ recentVerdicts,
101
+ recentSnapshots,
102
+ recentClaudeOutcomes,
103
+ };
104
+ }
105
+ function isPortfolioV0Run(run) {
106
+ return taskRunRoutingKey(run) === 'portfolio.v0';
88
107
  }
89
108
  /**
90
109
  * Scan session outcome files: each task dir under `workingDirRoot` may contain
@@ -1 +1 @@
1
- {"version":3,"file":"portfolio-v0-build.js","sourceRoot":"","sources":["../../src/api/portfolio-v0-build.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAGxE,2FAA2F;AAC3F,MAAM,CAAC,MAAM,+BAA+B,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AACjG,MAAM,4BAA4B,GAAG,EAAE,CAAC;AA+ExC,iFAAiF;AAEjF,MAAM,qBAAqB,GAAG,EAAE,CAAC;AACjC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAEjC,SAAS,cAAc,CAAC,IAAsB;IAC5C,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,SAAS,EAAE,IAAI,CAAC,aAAa;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,IAAsB;IACvC,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE,IAAI,CAAC,KAA8B;QAC1C,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,cAAc,EAAE,IAAI,CAAC,cAAc;KACpC,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAY,EACZ,iBAAyB,+BAA+B;IAExD,MAAM,WAAW,GAAG,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAErD,wCAAwC;IACxC,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAE/D,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,CAAC,IAAI,CAC/C,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,cAAc,CAC9C,CAAC;IACF,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG;QACb,SAAS,EAAE,QAAQ,CAAC,MAAM;QAC1B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;KACxB,CAAC;IAEF,mEAAmE;IACnE,IAAI,eAAe,GAAsB,EAAE,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,iBAAiB,GAAG,KAAK,CAAC,eAAe,CAAC;YAC9C,IAAI,EAAE,CAAC,iBAAiB,CAAC;YACzB,KAAK,EAAE,sBAAsB;SAC9B,CAAC,CAAC;QACH,eAAe,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9C,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,SAAS,EAAE,CAAC,CAAC,UAAU;YACvB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS,EAAE,CAAC,CAAC,UAAU;SACxB,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,4DAA4D;QAC5D,eAAe,GAAG,EAAE,CAAC;IACvB,CAAC;IAED,MAAM,oBAAoB,GAAG,0BAA0B,CAAC,cAAc,CAAC,CAAC;IAExE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,oBAAoB,EAAE,CAAC;AACrF,CAAC;AAED;;;;GAIG;AACH,SAAS,0BAA0B,CAAC,cAAsB;IACxD,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAE5C,IAAI,UAAoB,CAAC;IACzB,IAAI,CAAC;QACH,UAAU,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,SAAS;QACvC,IAAI,WAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;YAClE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;gBAAE,SAAS;YACvC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkC,CAAC;gBAChE,IACE,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;oBACpC,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;oBACpC,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;oBACpC,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAClC,CAAC;oBACD,QAAQ,CAAC,IAAI,CAAC;wBACZ,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC;wBACpE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK;wBAChC,oBAAoB,EAAE,MAAM,CAAC,oBAAoB,IAAI,CAAC;wBACtD,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;wBACnC,GAAG,CAAC,MAAM,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC7F,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,iCAAiC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;AACzD,CAAC"}
1
+ {"version":3,"file":"portfolio-v0-build.js","sourceRoot":"","sources":["../../src/api/portfolio-v0-build.ts"],"names":[],"mappings":"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"}
@@ -34,6 +34,7 @@ export interface PredictionV1TaskRunSummary {
34
34
  implName: string | null;
35
35
  windowStartTs: number;
36
36
  windowEndTs: number;
37
+ runStartedAt: number | null;
37
38
  stateUpdatedAt: number;
38
39
  manifestCid: string | null;
39
40
  deliveryTxHash: string | null;
@@ -47,7 +48,16 @@ export interface PredictionV1Status {
47
48
  activeTaskRuns: number;
48
49
  solutions: number;
49
50
  verdicts: number;
51
+ /**
52
+ * Sum of `settledFailed` and `localErrors`. Retained for callers that
53
+ * still want the rolled-up count; new surfaces should prefer the split
54
+ * fields to align with the public explorer.
55
+ */
50
56
  failed: number;
57
+ /** FAILED runs whose delivery tx landed on-chain (settled failure). */
58
+ settledFailed: number;
59
+ /** FAILED runs that never reached the marketplace (local engine error). */
60
+ localErrors: number;
51
61
  };
52
62
  latest: {
53
63
  taskAt: number | null;