@jinn-network/client 0.1.6 → 0.1.7-canary.17a8ecb8

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 (351) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +67 -1
  3. package/deployments/deployment-jinn-mvi-l1-sepolia-fast.json +23 -4
  4. package/deployments/deployment-jinn-mvi-l1-sepolia.json +23 -4
  5. package/deployments/deployment-jinn-mvi-l2-baseSepolia.json +5 -4
  6. package/dist/adapters/mech/adapter.d.ts +38 -1
  7. package/dist/adapters/mech/adapter.js +268 -57
  8. package/dist/adapters/mech/adapter.js.map +1 -1
  9. package/dist/adapters/mech/contracts.d.ts +17 -4
  10. package/dist/adapters/mech/contracts.js +8 -2
  11. package/dist/adapters/mech/contracts.js.map +1 -1
  12. package/dist/adapters/mech/safe-revert.d.ts +20 -0
  13. package/dist/adapters/mech/safe-revert.js +12 -4
  14. package/dist/adapters/mech/safe-revert.js.map +1 -1
  15. package/dist/adapters/mech/safe.d.ts +6 -2
  16. package/dist/adapters/mech/safe.js +32 -11
  17. package/dist/adapters/mech/safe.js.map +1 -1
  18. package/dist/adapters/mech/types.d.ts +6 -1
  19. package/dist/adapters/mech/types.js.map +1 -1
  20. package/dist/adapters/mech/verdict-code.d.ts +1 -0
  21. package/dist/adapters/mech/verdict-code.js +18 -0
  22. package/dist/adapters/mech/verdict-code.js.map +1 -1
  23. package/dist/api/activity-events-endpoint.d.ts +14 -0
  24. package/dist/api/activity-events-endpoint.js +59 -0
  25. package/dist/api/activity-events-endpoint.js.map +1 -0
  26. package/dist/api/admin-endpoint.d.ts +15 -3
  27. package/dist/api/admin-endpoint.js +24 -2
  28. package/dist/api/admin-endpoint.js.map +1 -1
  29. package/dist/api/bootstrap-endpoint.d.ts +1 -2
  30. package/dist/api/bootstrap-endpoint.js +49 -1
  31. package/dist/api/bootstrap-endpoint.js.map +1 -1
  32. package/dist/api/codex-doctor-endpoint.d.ts +73 -0
  33. package/dist/api/codex-doctor-endpoint.js +177 -0
  34. package/dist/api/codex-doctor-endpoint.js.map +1 -0
  35. package/dist/api/discovery-endpoint.d.ts +1 -0
  36. package/dist/api/discovery-endpoint.js +26 -0
  37. package/dist/api/discovery-endpoint.js.map +1 -1
  38. package/dist/api/fleet-build.d.ts +1 -0
  39. package/dist/api/fleet-build.js +2 -1
  40. package/dist/api/fleet-build.js.map +1 -1
  41. package/dist/api/gather-status.d.ts +14 -0
  42. package/dist/api/gather-status.js +494 -19
  43. package/dist/api/gather-status.js.map +1 -1
  44. package/dist/api/hermes-doctor-endpoint.d.ts +117 -0
  45. package/dist/api/hermes-doctor-endpoint.js +229 -23
  46. package/dist/api/hermes-doctor-endpoint.js.map +1 -1
  47. package/dist/api/launcher-status.d.ts +22 -17
  48. package/dist/api/launcher-status.js +13 -11
  49. package/dist/api/launcher-status.js.map +1 -1
  50. package/dist/api/launcher-tasks.d.ts +1 -1
  51. package/dist/api/launcher-tasks.js +12 -8
  52. package/dist/api/launcher-tasks.js.map +1 -1
  53. package/dist/api/portfolio-v0-build.d.ts +10 -0
  54. package/dist/api/portfolio-v0-build.js +24 -5
  55. package/dist/api/portfolio-v0-build.js.map +1 -1
  56. package/dist/api/prediction-v1-build.d.ts +10 -0
  57. package/dist/api/prediction-v1-build.js +7 -1
  58. package/dist/api/prediction-v1-build.js.map +1 -1
  59. package/dist/api/server.d.ts +31 -1
  60. package/dist/api/server.js +72 -1
  61. package/dist/api/server.js.map +1 -1
  62. package/dist/api/setup-endpoints.d.ts +16 -0
  63. package/dist/api/setup-endpoints.js +89 -135
  64. package/dist/api/setup-endpoints.js.map +1 -1
  65. package/dist/api/setup-retry-endpoint.d.ts +19 -0
  66. package/dist/api/setup-retry-endpoint.js +32 -0
  67. package/dist/api/setup-retry-endpoint.js.map +1 -0
  68. package/dist/api/solvernets-endpoints.d.ts +8 -0
  69. package/dist/api/solvernets-endpoints.js +71 -43
  70. package/dist/api/solvernets-endpoints.js.map +1 -1
  71. package/dist/api/status-build.d.ts +112 -0
  72. package/dist/api/status-build.js +98 -18
  73. package/dist/api/status-build.js.map +1 -1
  74. package/dist/api/task-run-routing.d.ts +7 -0
  75. package/dist/api/task-run-routing.js +12 -0
  76. package/dist/api/task-run-routing.js.map +1 -0
  77. package/dist/api/task-runs-build.d.ts +21 -0
  78. package/dist/api/task-runs-build.js +14 -1
  79. package/dist/api/task-runs-build.js.map +1 -1
  80. package/dist/build-info.json +4 -4
  81. package/dist/build-meta.json +1 -1
  82. package/dist/chain-read-errors.d.ts +10 -0
  83. package/dist/chain-read-errors.js +15 -0
  84. package/dist/chain-read-errors.js.map +1 -1
  85. package/dist/cli/commands/auth.js +1 -1
  86. package/dist/cli/commands/auth.js.map +1 -1
  87. package/dist/cli/commands/create.js +3 -2
  88. package/dist/cli/commands/create.js.map +1 -1
  89. package/dist/cli/commands/doctor.d.ts +2 -0
  90. package/dist/cli/commands/doctor.js +2 -0
  91. package/dist/cli/commands/doctor.js.map +1 -1
  92. package/dist/cli/commands/rewards.js +11 -7
  93. package/dist/cli/commands/rewards.js.map +1 -1
  94. package/dist/cli/commands/solver-nets.js +101 -15
  95. package/dist/cli/commands/solver-nets.js.map +1 -1
  96. package/dist/cli/commands/solver-plugins-block.d.ts +33 -0
  97. package/dist/cli/commands/solver-plugins-block.js +118 -0
  98. package/dist/cli/commands/solver-plugins-block.js.map +1 -0
  99. package/dist/cli/commands/solver-plugins-feedback.d.ts +72 -0
  100. package/dist/cli/commands/solver-plugins-feedback.js +262 -0
  101. package/dist/cli/commands/solver-plugins-feedback.js.map +1 -0
  102. package/dist/cli/commands/solver-plugins-read.d.ts +54 -0
  103. package/dist/cli/commands/solver-plugins-read.js +259 -0
  104. package/dist/cli/commands/solver-plugins-read.js.map +1 -0
  105. package/dist/cli/commands/solver-plugins.d.ts +35 -0
  106. package/dist/cli/commands/solver-plugins.js +399 -2
  107. package/dist/cli/commands/solver-plugins.js.map +1 -1
  108. package/dist/cli/commands/status.js +1 -1
  109. package/dist/cli/commands/status.js.map +1 -1
  110. package/dist/cli/commands/tasks.js +101 -11
  111. package/dist/cli/commands/tasks.js.map +1 -1
  112. package/dist/cli/commands/update.d.ts +10 -0
  113. package/dist/cli/commands/update.js +36 -0
  114. package/dist/cli/commands/update.js.map +1 -1
  115. package/dist/cli/introspection-context.js +5 -0
  116. package/dist/cli/introspection-context.js.map +1 -1
  117. package/dist/cli/task-native-readiness.d.ts +10 -1
  118. package/dist/cli/task-native-readiness.js +30 -6
  119. package/dist/cli/task-native-readiness.js.map +1 -1
  120. package/dist/config.d.ts +273 -235
  121. package/dist/config.js +305 -114
  122. package/dist/config.js.map +1 -1
  123. package/dist/daemon/checkpoint-loop.d.ts +48 -0
  124. package/dist/daemon/checkpoint-loop.js +76 -0
  125. package/dist/daemon/checkpoint-loop.js.map +1 -0
  126. package/dist/daemon/creator.d.ts +1 -1
  127. package/dist/daemon/creator.js +7 -3
  128. package/dist/daemon/creator.js.map +1 -1
  129. package/dist/daemon/daemon.d.ts +22 -0
  130. package/dist/daemon/daemon.js +156 -23
  131. package/dist/daemon/daemon.js.map +1 -1
  132. package/dist/daemon/eviction-loop.d.ts +40 -0
  133. package/dist/daemon/eviction-loop.js +67 -0
  134. package/dist/daemon/eviction-loop.js.map +1 -0
  135. package/dist/daemon/gate-logger.d.ts +9 -0
  136. package/dist/daemon/gate-logger.js +2 -0
  137. package/dist/daemon/gate-logger.js.map +1 -0
  138. package/dist/daemon/jinn-claim-loop-wiring.d.ts +33 -0
  139. package/dist/daemon/jinn-claim-loop-wiring.js +40 -0
  140. package/dist/daemon/jinn-claim-loop-wiring.js.map +1 -0
  141. package/dist/daemon/jinn-claim-loop.d.ts +24 -17
  142. package/dist/daemon/jinn-claim-loop.js +77 -23
  143. package/dist/daemon/jinn-claim-loop.js.map +1 -1
  144. package/dist/daemon/readiness-gate.d.ts +1 -4
  145. package/dist/daemon/readiness-gate.js.map +1 -1
  146. package/dist/daemon/skip-log-dedup.d.ts +69 -0
  147. package/dist/daemon/skip-log-dedup.js +106 -0
  148. package/dist/daemon/skip-log-dedup.js.map +1 -0
  149. package/dist/daemon/spend-cap-gate.d.ts +40 -0
  150. package/dist/daemon/spend-cap-gate.js +46 -0
  151. package/dist/daemon/spend-cap-gate.js.map +1 -0
  152. package/dist/dashboard/assets/index-8yHQgi7p.js +345 -0
  153. package/dist/dashboard/assets/index-BOBhJ76-.css +32 -0
  154. package/dist/dashboard/index.html +2 -2
  155. package/dist/discovery/factory.d.ts +17 -5
  156. package/dist/discovery/factory.js +46 -18
  157. package/dist/discovery/factory.js.map +1 -1
  158. package/dist/discovery/http.js +142 -3
  159. package/dist/discovery/http.js.map +1 -1
  160. package/dist/discovery/onchain.d.ts +5 -0
  161. package/dist/discovery/onchain.js +407 -15
  162. package/dist/discovery/onchain.js.map +1 -1
  163. package/dist/discovery/types.d.ts +45 -1
  164. package/dist/discovery/types.js +8 -10
  165. package/dist/discovery/types.js.map +1 -1
  166. package/dist/discovery/with-fallback.d.ts +7 -0
  167. package/dist/discovery/with-fallback.js +10 -0
  168. package/dist/discovery/with-fallback.js.map +1 -1
  169. package/dist/earning/bootstrap.d.ts +92 -1
  170. package/dist/earning/bootstrap.js +203 -63
  171. package/dist/earning/bootstrap.js.map +1 -1
  172. package/dist/earning/contracts.d.ts +14 -0
  173. package/dist/earning/contracts.js +17 -5
  174. package/dist/earning/contracts.js.map +1 -1
  175. package/dist/earning/funding-plan.js +27 -18
  176. package/dist/earning/funding-plan.js.map +1 -1
  177. package/dist/earning/jinn-rewards.d.ts +46 -0
  178. package/dist/earning/jinn-rewards.js +32 -0
  179. package/dist/earning/jinn-rewards.js.map +1 -1
  180. package/dist/earning/safe-adapter.d.ts +2 -0
  181. package/dist/earning/safe-adapter.js +37 -11
  182. package/dist/earning/safe-adapter.js.map +1 -1
  183. package/dist/earning/store.d.ts +8 -0
  184. package/dist/earning/store.js.map +1 -1
  185. package/dist/earning/testnet-setup-migration.d.ts +12 -0
  186. package/dist/earning/testnet-setup-migration.js +27 -1
  187. package/dist/earning/testnet-setup-migration.js.map +1 -1
  188. package/dist/earning/types.d.ts +21 -6
  189. package/dist/earning/viem-clients.d.ts +11 -4
  190. package/dist/earning/viem-clients.js +14 -5
  191. package/dist/earning/viem-clients.js.map +1 -1
  192. package/dist/erc8004/reputation.d.ts +8 -0
  193. package/dist/erc8004/reputation.js +22 -3
  194. package/dist/erc8004/reputation.js.map +1 -1
  195. package/dist/events/types.d.ts +2 -2
  196. package/dist/harnesses/cost-estimates.d.ts +145 -0
  197. package/dist/harnesses/cost-estimates.js +297 -0
  198. package/dist/harnesses/cost-estimates.js.map +1 -0
  199. package/dist/harnesses/engine/engine.d.ts +72 -0
  200. package/dist/harnesses/engine/engine.js +118 -8
  201. package/dist/harnesses/engine/engine.js.map +1 -1
  202. package/dist/harnesses/engine/persistence.d.ts +51 -1
  203. package/dist/harnesses/engine/persistence.js +118 -5
  204. package/dist/harnesses/engine/persistence.js.map +1 -1
  205. package/dist/harnesses/engine/work-dir-reaper.d.ts +65 -0
  206. package/dist/harnesses/engine/work-dir-reaper.js +100 -0
  207. package/dist/harnesses/engine/work-dir-reaper.js.map +1 -0
  208. package/dist/harnesses/impls/hermes-agent/adapter.js +40 -0
  209. package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -1
  210. package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +20 -0
  211. package/dist/harnesses/impls/hermes-agent/bootstrap.js +40 -6
  212. package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
  213. package/dist/harnesses/impls/hermes-agent/harness.d.ts +59 -1
  214. package/dist/harnesses/impls/hermes-agent/harness.js +104 -0
  215. package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
  216. package/dist/harnesses/impls/index.d.ts +7 -0
  217. package/dist/harnesses/impls/index.js +16 -1
  218. package/dist/harnesses/impls/index.js.map +1 -1
  219. package/dist/harnesses/impls/learner/harness.d.ts +38 -4
  220. package/dist/harnesses/impls/learner/harness.js +96 -2
  221. package/dist/harnesses/impls/learner/harness.js.map +1 -1
  222. package/dist/harnesses/impls/learner/plugin-path.d.ts +0 -13
  223. package/dist/harnesses/impls/learner/plugin-path.js +35 -15
  224. package/dist/harnesses/impls/learner/plugin-path.js.map +1 -1
  225. package/dist/harnesses/impls/learner/types.d.ts +11 -0
  226. package/dist/harnesses/impls/stub.d.ts +58 -0
  227. package/dist/harnesses/impls/stub.js +89 -0
  228. package/dist/harnesses/impls/stub.js.map +1 -0
  229. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.d.ts +69 -50
  230. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +178 -93
  231. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
  232. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.d.ts +12 -1
  233. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +121 -7
  234. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
  235. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +88 -4
  236. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +143 -22
  237. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
  238. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.d.ts +6 -0
  239. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js +1 -1
  240. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js.map +1 -1
  241. package/dist/harnesses/readiness-registry.js +9 -1
  242. package/dist/harnesses/readiness-registry.js.map +1 -1
  243. package/dist/main.js +413 -111
  244. package/dist/main.js.map +1 -1
  245. package/dist/observability/emit-event.d.ts +3 -2
  246. package/dist/observability/emit-event.js +22 -1
  247. package/dist/observability/emit-event.js.map +1 -1
  248. package/dist/operator-errors.d.ts +7 -0
  249. package/dist/operator-errors.js +13 -1
  250. package/dist/operator-errors.js.map +1 -1
  251. package/dist/plugins/learner/.claude-plugin/plugin.json +9 -0
  252. package/dist/plugins/learner/.codex-plugin/plugin.json +39 -0
  253. package/dist/plugins/learner/AGENTS.md +40 -0
  254. package/dist/plugins/learner/CLAUDE.md +33 -0
  255. package/dist/plugins/learner/README.md +59 -0
  256. package/dist/plugins/learner/hooks/hooks.json +16 -0
  257. package/dist/plugins/learner/hooks/session-start +38 -0
  258. package/dist/plugins/learner/skills/learn/SKILL.md +412 -0
  259. package/dist/plugins/learner/skills/learn/analyst-prompt.md +68 -0
  260. package/dist/plugins/learner/skills/learn/consolidator-prompt.md +94 -0
  261. package/dist/plugins/learner/skills/learn/explorer-prompt.md +53 -0
  262. package/dist/plugins/learner/skills/learn/planner-prompt.md +87 -0
  263. package/dist/plugins/learner/skills/learn/promoter-prompt.md +113 -0
  264. package/dist/plugins/learner/skills/learn/step-worker-prompt.md +47 -0
  265. package/dist/plugins/learner/skills/learn/strategist-prompt.md +85 -0
  266. package/dist/preflight/rpc-network.d.ts +40 -0
  267. package/dist/preflight/rpc-network.js +67 -1
  268. package/dist/preflight/rpc-network.js.map +1 -1
  269. package/dist/restart-daemon.d.ts +90 -0
  270. package/dist/restart-daemon.js +95 -0
  271. package/dist/restart-daemon.js.map +1 -0
  272. package/dist/rpc/transport.d.ts +109 -0
  273. package/dist/rpc/transport.js +220 -0
  274. package/dist/rpc/transport.js.map +1 -0
  275. package/dist/scripts/donation-consumption-acceptance.js +7 -28
  276. package/dist/scripts/donation-consumption-acceptance.js.map +1 -1
  277. package/dist/setup/halt-mode.d.ts +14 -0
  278. package/dist/setup/halt-mode.js +17 -0
  279. package/dist/setup/halt-mode.js.map +1 -0
  280. package/dist/solver-nets/prediction-operator-ux.d.ts +1 -2
  281. package/dist/solver-nets/prediction-operator-ux.js +90 -47
  282. package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
  283. package/dist/solver-nets/registry.d.ts +20 -1
  284. package/dist/solver-nets/registry.js +38 -25
  285. package/dist/solver-nets/registry.js.map +1 -1
  286. package/dist/solver-types/_swe-rebench-v2-pool-cache.d.ts +58 -0
  287. package/dist/solver-types/_swe-rebench-v2-pool-cache.js +87 -0
  288. package/dist/solver-types/_swe-rebench-v2-pool-cache.js.map +1 -0
  289. package/dist/solver-types/_swe-rebench-v2-pool.d.ts +9 -2
  290. package/dist/solver-types/_swe-rebench-v2-pool.js +15 -20
  291. package/dist/solver-types/_swe-rebench-v2-pool.js.map +1 -1
  292. package/dist/solver-types/_swe-rebench-v2-substrate.d.ts +1 -0
  293. package/dist/solver-types/_swe-rebench-v2-substrate.js +10 -0
  294. package/dist/solver-types/_swe-rebench-v2-substrate.js.map +1 -1
  295. package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +94 -1
  296. package/dist/solver-types/_swe-rebench-v2-validated-pool.js +305 -39
  297. package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
  298. package/dist/solver-types/swe-rebench-v2-auto.d.ts +22 -7
  299. package/dist/solver-types/swe-rebench-v2-auto.js +45 -20
  300. package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
  301. package/dist/solver-types/swe-rebench-v2.d.ts +13 -2
  302. package/dist/solver-types/swe-rebench-v2.js +237 -95
  303. package/dist/solver-types/swe-rebench-v2.js.map +1 -1
  304. package/dist/solvernets/daemon-init.d.ts +10 -2
  305. package/dist/solvernets/daemon-init.js +22 -2
  306. package/dist/solvernets/daemon-init.js.map +1 -1
  307. package/dist/solvernets/launched-record-dispatcher.js +35 -7
  308. package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
  309. package/dist/solvernets/store.d.ts +5 -0
  310. package/dist/solvernets/store.js +1 -0
  311. package/dist/solvernets/store.js.map +1 -1
  312. package/dist/spend/credential.d.ts +8 -0
  313. package/dist/spend/credential.js +30 -0
  314. package/dist/spend/credential.js.map +1 -0
  315. package/dist/spend/daemon-config.d.ts +13 -0
  316. package/dist/spend/daemon-config.js +24 -0
  317. package/dist/spend/daemon-config.js.map +1 -0
  318. package/dist/spend/pricing.d.ts +16 -0
  319. package/dist/spend/pricing.js +26 -0
  320. package/dist/spend/pricing.js.map +1 -0
  321. package/dist/spend/record.d.ts +13 -0
  322. package/dist/spend/record.js +30 -0
  323. package/dist/spend/record.js.map +1 -0
  324. package/dist/spend/usage.d.ts +27 -0
  325. package/dist/spend/usage.js +113 -0
  326. package/dist/spend/usage.js.map +1 -0
  327. package/dist/store/store.d.ts +43 -0
  328. package/dist/store/store.js +236 -7
  329. package/dist/store/store.js.map +1 -1
  330. package/dist/tasks/sources.d.ts +18 -1
  331. package/dist/tasks/sources.js +33 -5
  332. package/dist/tasks/sources.js.map +1 -1
  333. package/dist/trajectory/transcript-parsers/types.d.ts +8 -8
  334. package/dist/tx-retry.d.ts +166 -19
  335. package/dist/tx-retry.js +310 -32
  336. package/dist/tx-retry.js.map +1 -1
  337. package/dist/types/payloads/prediction-apy-v0.d.ts +5 -5
  338. package/dist/types/payloads/prediction-v0.d.ts +5 -5
  339. package/dist/types/task-document.d.ts +392 -0
  340. package/dist/types/task-document.js +10 -0
  341. package/dist/types/task-document.js.map +1 -1
  342. package/dist/types/task.d.ts +28 -0
  343. package/dist/util/extract-tx-hash.d.ts +14 -0
  344. package/dist/util/extract-tx-hash.js +19 -0
  345. package/dist/util/extract-tx-hash.js.map +1 -0
  346. package/dist/vendor/@jinn-network/sdk/dist/contracts.js +1 -1
  347. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.d.ts +3 -0
  348. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.js +1 -0
  349. package/package.json +30 -12
  350. package/dist/dashboard/assets/index-DOlzFN8a.css +0 -32
  351. package/dist/dashboard/assets/index-NkZ7CTAT.js +0 -140
package/dist/main.js CHANGED
@@ -26,7 +26,8 @@ import { dirname, join } from 'node:path';
26
26
  import { fileURLToPath } from 'node:url';
27
27
  import { loadConfig, getConfigPathFromArgs, DEFAULT_CONFIG_PATH } from './config.js';
28
28
  import { Store } from './store/store.js';
29
- import { startApiServer } from './api/server.js';
29
+ import { startApiServer, isEmbeddedAgentEnabled } from './api/server.js';
30
+ import { setDefaultTxSubmissionLedger } from './tx-retry.js';
30
31
  // addHarnessReadinessRoutes is wired through startApiServer's holder ref now
31
32
  // (jinn-mono-u34i). No direct import needed.
32
33
  import { CapturePublishUnavailableError } from './api/captures.js';
@@ -36,10 +37,11 @@ import { hashImplStateDir } from './harnesses/freeze.js';
36
37
  import { readModeState } from './harnesses/mode-state.js';
37
38
  import { attachAgentWs, updateAgentClaudePath } from './agent/agent-ws.js';
38
39
  import { createSetupModeController } from './setup-mode.js';
40
+ import { requestDaemonRestart } from './restart-daemon.js';
39
41
  import { buildEnvelope, emitEnvelope } from './errors/envelope.js';
40
42
  import { clearBootstrapError, persistBootstrapError, } from './errors/persisted-bootstrap-error.js';
41
43
  import { emitStructured } from './events/emitter.js';
42
- import { FleetBootstrapper } from './earning/bootstrap.js';
44
+ import { FleetBootstrapper, recoverEvictedService as recoverEvictedServiceFn } from './earning/bootstrap.js';
43
45
  import { DEFAULT_TESTNET_ARTIFACTS, applyChainGasOverrides, getChainConfig, loadJinnMviConfig } from './earning/contracts.js';
44
46
  import { runLegacyAgentIdMigration } from './earning/migrate-agent-id.js';
45
47
  import { FleetStateStore } from './earning/store.js';
@@ -48,6 +50,8 @@ import { decryptMnemonic, deriveMasterSigner, walletPrivateKeyAtIndex } from './
48
50
  import { MechAdapter } from './adapters/mech/adapter.js';
49
51
  import { ClaudeRunner } from './runner/claude.js';
50
52
  import { Daemon } from './daemon/daemon.js';
53
+ import { buildSpendCapConfig } from './spend/daemon-config.js';
54
+ import { buildJinnClaimLoopConfig, shouldWireJinnClaimL1Signer, } from './daemon/jinn-claim-loop-wiring.js';
51
55
  import { createJinnPublicClient, createJinnWalletClient, createJinnL1PublicClient, createJinnL1WalletClient } from './earning/viem-clients.js';
52
56
  import { privateKeyToAccount } from 'viem/accounts';
53
57
  import { getAddress } from 'viem';
@@ -56,9 +60,10 @@ import { joinedSolverNetsViewFromConfig } from './harnesses/engine/engine.js';
56
60
  import { buildHarnesses } from './harnesses/impls/index.js';
57
61
  import { loadExternalImpl } from './harnesses/external-impls/index.js';
58
62
  import { CLAUDE_CODE_HARNESS, CODEX_HARNESS, HERMES_AGENT_HARNESS, harnessStateDirName } from './harnesses/names.js';
63
+ import { resolveContractFromSolverNetId } from './solvernets/launched-record-dispatcher.js';
59
64
  import { HarnessReadinessRegistry } from './harnesses/readiness-registry.js';
60
65
  import { createClients } from './adapters/mech/safe.js';
61
- import { loadSolverNets } from './solver-nets/registry.js';
66
+ import { findJoinedByName, loadSolverNets, solverTypeFromJoinedContract, } from './solver-nets/registry.js';
62
67
  import { createCorpus } from './corpus/index.js';
63
68
  import { DEFAULT_EXECUTION_DISCOVERY_FROM_BLOCK } from './corpus/onchain-query.js';
64
69
  import { CapturesStore } from './store/captures.js';
@@ -76,10 +81,11 @@ import { GeminiSessionParser } from './trajectory/transcript-parsers/gemini-sess
76
81
  import { CursorSqliteParser } from './trajectory/transcript-parsers/cursor-sqlite.js';
77
82
  import { buildInfo } from './build-info.js';
78
83
  import { BASE_FEEDS } from './venues/chainlink/feeds.js';
79
- import { GeneratedTaskSource, StaticConfiguredTaskSource } from './tasks/sources.js';
80
- import { checkRpcNetwork, logRpcLocalDevToStderr, rpcNetworkFailureHint } from './preflight/rpc-network.js';
84
+ import { GeneratedTaskSource, StaticConfiguredTaskSource, filterBindableTasks } from './tasks/sources.js';
85
+ import { checkRpcNetwork, logRpcLocalDevToStderr, probeFallbackChain, rpcNetworkFailureHint, summarizeFallbackChain, } from './preflight/rpc-network.js';
81
86
  import { apiPortFailureMessage, checkApiPortAvailable } from './preflight/api-port.js';
82
87
  import { openBrowser } from './cli/open-browser.js';
88
+ import { keepSetupUiOnBootstrapError } from './setup/halt-mode.js';
83
89
  if (process.env['JINN_LOAD_DEV_ENV'] === '1' || process.env['NODE_ENV'] === 'development') {
84
90
  dotenvConfig({ path: join(dirname(fileURLToPath(import.meta.url)), '..', '.env') });
85
91
  }
@@ -132,8 +138,19 @@ const config = loadConfig(CONFIG_PATH);
132
138
  if (config.network === 'mainnet' && process.env['JINN_ENABLE_MAINNET'] !== '1') {
133
139
  console.warn('[main] Mainnet is disabled before launch; using testnet defaults.');
134
140
  config.network = 'testnet';
135
- config.rpcUrl = 'https://base-sepolia.gateway.tenderly.co/75tyLMQuD8EHpXxMwINIKu';
141
+ config.rpcUrl = 'https://base-sepolia-rpc.publicnode.com';
136
142
  }
143
+ // Issue #326: the embedded Claude agent chat surface (right rail + onboarding
144
+ // "Ask Claude" panel + /api/agent/ws bridge) is hidden by default while its
145
+ // action-authority / plugin-scope shape is still in design. Set
146
+ // `JINN_ENABLE_EMBEDDED_AGENT=1` to re-enable it for development. This does
147
+ // NOT affect Claude-Code-as-a-solver-harness — that path is independent.
148
+ //
149
+ // Issue #367: the SPA reads this flag via the injected `window.__JINN_FEATURES__`
150
+ // (`resolveFeatureFlags` in api/server.ts) like every other operator-app flag.
151
+ // This `embeddedAgentEnabled` const is the daemon-side consumer only — it gates
152
+ // whether the `/api/agent/ws` bridge is mounted below.
153
+ const embeddedAgentEnabled = isEmbeddedAgentEnabled();
137
154
  let activeClaudePath = config.claudePath ?? 'claude';
138
155
  const selectClaudePath = (claudePath) => {
139
156
  activeClaudePath = claudePath;
@@ -484,11 +501,17 @@ async function bootstrap() {
484
501
  hint: 'Fund the listed address and re-run this command.',
485
502
  exampleCli: 'jinn fund-requirements --json',
486
503
  details: {
487
- role: 'master',
504
+ // jinn-mono-hjex.6: structured envelope so SPA can render the
505
+ // specific address + amount instead of a prose disjunction.
506
+ category: 'insufficient_funds',
507
+ step: 'awaiting_funding',
488
508
  address: result.funding.master_address,
509
+ requiredWei: result.funding.eth_required,
510
+ haveWei: result.funding.eth_balance,
511
+ // Legacy aliases kept for any external consumers that read these.
512
+ role: 'master',
489
513
  asset: 'native',
490
514
  needWei: result.funding.eth_required,
491
- haveWei: result.funding.eth_balance,
492
515
  },
493
516
  });
494
517
  }
@@ -503,11 +526,17 @@ async function bootstrap() {
503
526
  hint: 'Bootstrap failed before the fleet reached a runnable state.',
504
527
  details: {
505
528
  cause: result.message,
529
+ // jinn-mono-hjex.6: propagate structured category from the bootstrapper
530
+ // so the SPA can render category-specific UI (e.g. funding shortfall).
531
+ ...(result.errorCategory !== undefined ? { category: result.errorCategory } : {}),
506
532
  // Preserve the raw underlying error so a misclassified summary can
507
533
  // be diagnosed without re-running with JINN_DEBUG. See jinn-mono-jz9f.
508
534
  ...(result.rawErrorMessage && result.rawErrorMessage !== result.message
509
535
  ? { rawErrorMessage: result.rawErrorMessage }
510
536
  : {}),
537
+ // jinn-mono-hjex reviewer fix: propagate tx hash so the SPA can render
538
+ // a block-explorer link for failed on-chain revert transactions.
539
+ ...(result.txHash != null ? { txHash: result.txHash } : {}),
511
540
  },
512
541
  });
513
542
  }
@@ -592,7 +621,9 @@ class SetupBootstrapHalted extends Error {
592
621
  this.name = 'SetupBootstrapHalted';
593
622
  }
594
623
  }
595
- const keepSetupUiOnBootstrapError = () => process.env['JINN_NO_UI'] !== '1' && process.env['JINN_NO_DAEMON'] !== '1';
624
+ // hjex.6: gate for the halt-and-resume loop. Lives in ./setup/halt-mode.ts
625
+ // so it can be unit-tested without dragging main.ts's top-level side
626
+ // effects (password resolution, config load) into the test.
596
627
  // ── Main ────────────────────────────────────────────────────────────────────
597
628
  /**
598
629
  * --json-progress: emit NDJSON progress envelopes on stdout during long
@@ -651,6 +682,15 @@ export async function main() {
651
682
  else {
652
683
  logRpcLocalDevToStderr(rpcPreflight);
653
684
  }
685
+ // Boot-time RPC fallback-chain probe (issue #592, AC7 + AC9). Log-only —
686
+ // per-slot 429s/5xx never gate startup. checkRpcNetwork above already
687
+ // fail-loud on chain-id mismatch against the head provider.
688
+ await probeFallbackChain(config.rpcUrls, config.network, 'L2');
689
+ console.error(summarizeFallbackChain('L2', config.rpcUrls));
690
+ if (config.jinnClaimLoopEnabled && config.ethereumRpcUrls) {
691
+ await probeFallbackChain(config.ethereumRpcUrls, config.network, 'L1');
692
+ console.error(summarizeFallbackChain('L1', config.ethereumRpcUrls));
693
+ }
654
694
  const portPreflight = await checkApiPortAvailable(config.apiPort);
655
695
  if (!portPreflight.ok) {
656
696
  emitEnvelope({
@@ -679,6 +719,7 @@ export async function main() {
679
719
  // /v1/bootstrap + /v1/events + /v1/status here. The same Store instance is
680
720
  // later passed into Daemon so we don't double-open the SQLite file.
681
721
  const sharedStore = new Store(config.dbPath);
722
+ setDefaultTxSubmissionLedger(sharedStore);
682
723
  const capturesStore = new CapturesStore(sharedStore);
683
724
  let captureReceiver;
684
725
  try {
@@ -759,6 +800,18 @@ export async function main() {
759
800
  // builder-artifacts. Holder ref lets the routes register eagerly and
760
801
  // start returning real data the moment main.ts assigns holder.current.
761
802
  const discoveryApiHolder = { current: undefined };
803
+ // hjex.3: holder for the restake callback. Populated in running mode after
804
+ // bootstrap completes (when mnemonic + distributorAddress are available).
805
+ const restakeCallbackRef = {
806
+ current: undefined,
807
+ };
808
+ // hjex.6: retry signal for the bootstrap halt-and-resume loop.
809
+ // When a SetupBootstrapHalted is caught (fatal non-funding error or funding
810
+ // timeout), main() waits on this promise instead of returning, so the setup
811
+ // API stays alive and the operator can click Retry in the SPA.
812
+ // The retry endpoint resolves this promise to trigger a re-run.
813
+ let retryBootstrapResolve = null;
814
+ let retryBootstrapReject = null;
762
815
  let setupApiServer;
763
816
  try {
764
817
  setupApiServer = await startApiServer({
@@ -772,11 +825,32 @@ export async function main() {
772
825
  hermesPath: config.hermesPath,
773
826
  hermesDoctorTimeoutMs: config.hermesDoctorTimeoutMs,
774
827
  },
828
+ codexDoctor: {
829
+ codexPath: config.codexPath,
830
+ codexDoctorTimeoutMs: config.codexDoctorTimeoutMs,
831
+ },
775
832
  admin: {
776
- onRestartRequested: () => {
777
- console.log('[main] Restart requested via operator MCP. Exiting...');
778
- process.exit(0);
779
- },
833
+ // jinn-mono #289: in interactive mode (the dashboard SPA case),
834
+ // spawn a detached replacement before exiting so the panel reconnects
835
+ // to a live daemon instead of seeing a 502 + terminal prompt. In
836
+ // headless mode (`JINN_NO_UI=1`), exit without respawning so the
837
+ // supervisor / systemd / docker entrypoint decides what to do.
838
+ // Stop: pure exit, never respawn. The operator clicked Stop; they
839
+ // want the daemon down until they explicitly start it again.
840
+ onStopRequested: () => process.exit(0),
841
+ onRestartRequested: (opts) => requestDaemonRestart({
842
+ forceRespawn: opts.forceRespawn,
843
+ // jinn-mono #561: close the API + OTLP listeners before the
844
+ // replacement spawns, so the child binds without an
845
+ // EADDRINUSE race. Errors are swallowed inside
846
+ // requestDaemonRestart so the operator is never stranded.
847
+ preSpawnCleanup: async () => {
848
+ await setupApiServer.close().catch(() => undefined);
849
+ if (captureReceiver) {
850
+ await captureReceiver.shutdown().catch(() => undefined);
851
+ }
852
+ },
853
+ }),
780
854
  },
781
855
  harnessStatus: {
782
856
  getStatus: async () => {
@@ -830,7 +904,6 @@ export async function main() {
830
904
  configReader: () => ({
831
905
  rpcUrl: config.rpcUrl,
832
906
  defaultRpcUrl: CHAIN_CONFIG.rpcUrl,
833
- solverNets: config.solverNets,
834
907
  joinedSolverNets: config.joinedSolverNets,
835
908
  }),
836
909
  },
@@ -953,19 +1026,49 @@ export async function main() {
953
1026
  configPath: CONFIG_PATH ?? DEFAULT_CONFIG_PATH,
954
1027
  defaultRpcUrlForChain: () => CHAIN_CONFIG.rpcUrl,
955
1028
  onClaudePathSelected: selectClaudePath,
956
- onSolverNetsUpdated: (solverNets) => {
957
- config.solverNets = solverNets;
958
- // The prediction operator status is memoised per-`JinnConfig`
959
- // reference; mutating in place leaves the cache pointing at the
960
- // pre-edit snapshot. Drop the entry so the next /v1/status read
961
- // (and thus Overview's `solverNet.enabled` gating) reflects the
962
- // toggle immediately. (jinn-mono-l2zl.15.4.12)
1029
+ // Issue #421 retired the legacy `solverNets` write target. Setup
1030
+ // endpoints no longer call back into the daemon to mutate operator
1031
+ // SolverNet config; the canonical join flow is
1032
+ // `POST /v1/operator/join/:cid`, which mutates
1033
+ // `config.joinedSolverNets` directly via its own write path.
1034
+ // The cache-invalidation hook is no longer needed here.
1035
+ onSolverNetsUpdated: () => {
963
1036
  invalidatePredictionOperatorStatusCache(config);
964
1037
  },
1038
+ // hjex.3: delegate to the live callback populated once running mode starts.
1039
+ restake: (serviceId) => {
1040
+ if (!restakeCallbackRef.current) {
1041
+ return Promise.resolve({ ok: false, error: 'restake_not_available_in_setup_mode' });
1042
+ }
1043
+ return restakeCallbackRef.current(serviceId);
1044
+ },
1045
+ // hjex.6: re-trigger the bootstrap state machine from the SPA Retry button.
1046
+ // Resolves the halt-and-resume promise; main() will loop back and call
1047
+ // bootstrap() again. Rejects if the daemon is not currently halted.
1048
+ retryBootstrap: () => {
1049
+ return new Promise((resolve, reject) => {
1050
+ if (!retryBootstrapResolve) {
1051
+ reject(new Error('daemon_not_halted'));
1052
+ return;
1053
+ }
1054
+ const prevResolve = retryBootstrapResolve;
1055
+ // The resolve will unblock the main loop's await. When bootstrap
1056
+ // completes (success or new halt), the caller receives the result
1057
+ // via the /v1/bootstrap polling endpoint.
1058
+ prevResolve();
1059
+ resolve();
1060
+ });
1061
+ },
965
1062
  },
966
1063
  status: {
967
1064
  earningDir: config.earningDir,
968
1065
  rpcUrl: config.rpcUrl,
1066
+ // tJINN identity comes from the bundled JINN MVI L1 artifact
1067
+ // (`JINN_MVI_CONFIG`) — one source of truth. The Sepolia RPC endpoint
1068
+ // is read from `config.ethereumRpcUrl` via the threaded `config`.
1069
+ tjinnTokenAddress: JINN_MVI_CONFIG.jinn,
1070
+ tjinnChainId: JINN_MVI_CONFIG.l1ChainId,
1071
+ tjinnDistributorAddress: JINN_MVI_CONFIG.distributor,
969
1072
  network: config.network,
970
1073
  pollIntervalMs: config.pollIntervalMs,
971
1074
  masterEthDailyEstimateWei: config.masterEthDailyEstimateWei,
@@ -1000,29 +1103,30 @@ export async function main() {
1000
1103
  // TODO(jinn-mono launcher Task 8): real `getReservedBudgetWei`
1001
1104
  // (sum of unconsumed claim payments across open Tasks).
1002
1105
  launcher: {
1003
- getConfig: () => ({ solverNets: config.solverNets }),
1106
+ getConfig: () => ({ joinedSolverNets: config.joinedSolverNets }),
1004
1107
  configPath: CONFIG_PATH ?? DEFAULT_CONFIG_PATH,
1005
- // Cache-invalidation hook retained for the operator-mode
1006
- // setup-endpoints flow; the launcher-mode PATCH route was retired
1007
- // by Task 22, so this currently fires only when operator mode
1008
- // mutates `solverNets`.
1009
- onSolverNetsUpdated: (solverNets) => {
1010
- config.solverNets = solverNets;
1108
+ // Issue #421 retired the legacy `solverNets` write target. The hook
1109
+ // only needs to invalidate the prediction-operator status cache when
1110
+ // operator mode mutates joinedSolverNets via setup endpoints.
1111
+ onSolverNetsUpdated: () => {
1011
1112
  invalidatePredictionOperatorStatusCache(config);
1012
1113
  },
1013
1114
  getGeneratorState: (netName) => {
1014
1115
  if (netName === 'prediction') {
1015
1116
  return predictionGeneratorRef?.getState();
1016
1117
  }
1017
- const solverType = config.solverNets?.[netName]?.solverType;
1118
+ const joined = findJoinedByName(config.joinedSolverNets, netName);
1119
+ const solverType = joined ? solverTypeFromJoinedContract(joined) : undefined;
1018
1120
  if (!solverType)
1019
1121
  return undefined;
1020
1122
  return launchedGeneratorStateBySolverType.get(solverType)?.();
1021
1123
  },
1022
1124
  getOpenTaskCount: (netName) => {
1023
- const net = config.solverNets?.[netName];
1024
- const solverType = net?.solverType;
1025
- if (!solverType || !safeAddressForLauncher)
1125
+ if (!safeAddressForLauncher)
1126
+ return 0;
1127
+ const joined = findJoinedByName(config.joinedSolverNets, netName);
1128
+ const solverType = joined ? solverTypeFromJoinedContract(joined) : undefined;
1129
+ if (!solverType)
1026
1130
  return 0;
1027
1131
  return sharedStore.countPostedTasksByCreatorAndSolverType({
1028
1132
  creatorSafeAddress: safeAddressForLauncher,
@@ -1114,30 +1218,41 @@ export async function main() {
1114
1218
  // can attach to a long-lived embedded `claude` subprocess. The embedded
1115
1219
  // session reads MCP config we materialise to disk so it can reach the
1116
1220
  // operator MCP server (`jinn mcp`) for tool calls.
1117
- const operatorMcpConfigPath = join(homedir(), '.jinn-client', 'operator-mcp-config.json');
1118
- try {
1119
- mkdirSync(dirname(operatorMcpConfigPath), { recursive: true });
1120
- writeFileSyncMain(operatorMcpConfigPath, JSON.stringify({
1121
- mcpServers: {
1122
- 'jinn-operator': {
1123
- command: 'jinn',
1124
- args: ['mcp'],
1221
+ //
1222
+ // Issue #326: the embedded agent chat surface is hidden by default. The WS
1223
+ // bridge mounts only when `JINN_ENABLE_EMBEDDED_AGENT=1` so the dev-time
1224
+ // path stays end-to-end; with the flag off there is no /api/agent/ws route
1225
+ // and the SPA never renders the chat panel. Claude-Code-as-solver-harness
1226
+ // is independent of this bridge and unaffected.
1227
+ if (embeddedAgentEnabled) {
1228
+ const operatorMcpConfigPath = join(homedir(), '.jinn-client', 'operator-mcp-config.json');
1229
+ try {
1230
+ mkdirSync(dirname(operatorMcpConfigPath), { recursive: true });
1231
+ writeFileSyncMain(operatorMcpConfigPath, JSON.stringify({
1232
+ mcpServers: {
1233
+ 'jinn-operator': {
1234
+ command: 'jinn',
1235
+ args: ['mcp'],
1236
+ },
1125
1237
  },
1126
- },
1127
- }, null, 2));
1238
+ }, null, 2));
1239
+ }
1240
+ catch (err) {
1241
+ console.warn(`[main] Failed to write operator MCP config at ${operatorMcpConfigPath}: ` +
1242
+ (err instanceof Error ? err.message : String(err)));
1243
+ }
1244
+ attachAgentWs({
1245
+ httpServer: setupApiServer.server,
1246
+ uiToken,
1247
+ claudePath: activeClaudePath,
1248
+ cwd: process.cwd(),
1249
+ mcpConfigPath: operatorMcpConfigPath,
1250
+ });
1251
+ console.log(`[main] Agent WS bridge mounted at ws://127.0.0.1:${setupApiServer.port}/api/agent/ws`);
1128
1252
  }
1129
- catch (err) {
1130
- console.warn(`[main] Failed to write operator MCP config at ${operatorMcpConfigPath}: ` +
1131
- (err instanceof Error ? err.message : String(err)));
1253
+ else {
1254
+ console.log('[main] Embedded agent surface disabled (set JINN_ENABLE_EMBEDDED_AGENT=1 to enable).');
1132
1255
  }
1133
- attachAgentWs({
1134
- httpServer: setupApiServer.server,
1135
- uiToken,
1136
- claudePath: activeClaudePath,
1137
- cwd: process.cwd(),
1138
- mcpConfigPath: operatorMcpConfigPath,
1139
- });
1140
- console.log(`[main] Agent WS bridge mounted at ws://127.0.0.1:${setupApiServer.port}/api/agent/ws`);
1141
1256
  // ── Init-if-missing ──────────────────────────────────────────────────────
1142
1257
  // If the keystore is missing but we have a password, run `jinn init` now so
1143
1258
  // bootstrap has something to decrypt. Idempotent: init is a no-op when the
@@ -1178,30 +1293,96 @@ export async function main() {
1178
1293
  // keystore is on disk and we're transitioning into bootstrap.
1179
1294
  setupController.refresh({ keystoreExists: true, allComplete: false });
1180
1295
  }
1296
+ // hjex.6: halt-and-resume loop for bootstrap retries.
1297
+ // When failBootstrap() throws SetupBootstrapHalted, we wait for the operator
1298
+ // to click Retry in the SPA (which resolves retryBootstrapResolve) rather
1299
+ // than returning and exiting. On each retry, we loop back and call bootstrap()
1300
+ // again. bootstrap() is idempotent — completed steps are no-ops.
1181
1301
  let bootstrapResult;
1182
- try {
1183
- bootstrapResult = await bootstrap();
1184
- }
1185
- catch (err) {
1186
- if (err instanceof SetupBootstrapHalted) {
1187
- return {
1188
- schemaVersion: 1,
1189
- generatedAt: new Date().toISOString(),
1190
- kind: 'setup_halted',
1191
- pid: process.pid,
1192
- network: config.network,
1193
- phase: config.network === 'testnet' ? 'phase-1b' : 'phase-0',
1194
- apiPort: setupApiServer.port,
1195
- dashboardUrl: `http://127.0.0.1:${setupApiServer.port}`,
1196
- error: err.envelope,
1197
- };
1302
+ // eslint-disable-next-line no-constant-condition
1303
+ while (true) {
1304
+ try {
1305
+ bootstrapResult = await bootstrap();
1306
+ break; // success exit the retry loop
1307
+ }
1308
+ catch (err) {
1309
+ if (err instanceof SetupBootstrapHalted) {
1310
+ // Install the retry signal so the endpoint can unblock us.
1311
+ const retrySignal = new Promise((resolve, reject) => {
1312
+ retryBootstrapResolve = resolve;
1313
+ retryBootstrapReject = reject;
1314
+ });
1315
+ console.log('[main] Bootstrap halted. Waiting for retry signal from the dashboard...');
1316
+ // hjex.6: Auto-resume funding poller.
1317
+ // When the halt is a funding shortfall, poll the master EOA balance
1318
+ // every JINN_FUNDING_POLL_INTERVAL_MS (default 15s). When the balance
1319
+ // meets or exceeds the required amount, auto-signal the retry loop.
1320
+ // Only runs while the halt signal is pending; stops on any signal.
1321
+ let fundingPollHandle = null;
1322
+ const isHaltedOnFunding = err.envelope.code === 'funding_required';
1323
+ const haltDetails = err.envelope.details;
1324
+ const haltAddress = typeof haltDetails?.['address'] === 'string'
1325
+ ? haltDetails['address']
1326
+ : null;
1327
+ const haltRequired = typeof haltDetails?.['requiredWei'] === 'string'
1328
+ ? BigInt(haltDetails['requiredWei'])
1329
+ : typeof haltDetails?.['needWei'] === 'string'
1330
+ ? BigInt(haltDetails['needWei'])
1331
+ : null;
1332
+ const fundingPollIntervalMs = (() => {
1333
+ const raw = process.env['JINN_FUNDING_POLL_INTERVAL_MS'];
1334
+ if (!raw)
1335
+ return 15_000;
1336
+ const n = Number.parseInt(raw, 10);
1337
+ return Number.isFinite(n) && n > 0 ? n : 15_000;
1338
+ })();
1339
+ if (isHaltedOnFunding && haltAddress && haltRequired !== null) {
1340
+ const publicClient = createJinnPublicClient(config.rpcUrls, NETWORK_CHAIN);
1341
+ const schedulePoll = () => {
1342
+ fundingPollHandle = setTimeout(async () => {
1343
+ // Guard: if the signal was already fired, stop polling.
1344
+ if (!retryBootstrapResolve)
1345
+ return;
1346
+ try {
1347
+ const balance = await publicClient.getBalance({ address: haltAddress });
1348
+ if (balance >= haltRequired) {
1349
+ console.log(`[main] Funding shortfall cleared (have ${balance}, required ${haltRequired}). ` +
1350
+ `Auto-resuming bootstrap...`);
1351
+ retryBootstrapResolve?.();
1352
+ return; // don't schedule the next poll
1353
+ }
1354
+ }
1355
+ catch (pollErr) {
1356
+ // Balance read failed — not fatal, just skip this tick.
1357
+ const msg = pollErr instanceof Error ? pollErr.message : String(pollErr);
1358
+ console.log(`[main] Funding poller balance read failed (will retry): ${msg}`);
1359
+ }
1360
+ schedulePoll(); // reschedule
1361
+ }, fundingPollIntervalMs);
1362
+ };
1363
+ schedulePoll();
1364
+ }
1365
+ try {
1366
+ await retrySignal;
1367
+ }
1368
+ finally {
1369
+ retryBootstrapResolve = null;
1370
+ retryBootstrapReject = null;
1371
+ if (fundingPollHandle !== null) {
1372
+ clearTimeout(fundingPollHandle);
1373
+ fundingPollHandle = null;
1374
+ }
1375
+ }
1376
+ console.log('[main] Retry triggered — re-running bootstrap...');
1377
+ continue; // loop back to the bootstrap() call
1378
+ }
1379
+ // If bootstrap throws an unexpected error (vs. SetupBootstrapHalted),
1380
+ // tear down the API we just started so we don't leave a dangling listener.
1381
+ await setupApiServer.close().catch(() => undefined);
1382
+ await closeCaptureReceiver();
1383
+ sharedStore.close();
1384
+ throw err;
1198
1385
  }
1199
- // If bootstrap throws (vs. emitEnvelope-exits), tear down the API we
1200
- // just started so we don't leave a dangling listener on the port.
1201
- await setupApiServer.close().catch(() => undefined);
1202
- await closeCaptureReceiver();
1203
- sharedStore.close();
1204
- throw err;
1205
1386
  }
1206
1387
  // Bootstrap completed — flip the controller into 'running' so any waiters
1207
1388
  // (future loops gated on this) unblock.
@@ -1254,9 +1435,36 @@ export async function main() {
1254
1435
  const earningStore = new FleetStateStore(config.earningDir);
1255
1436
  const mnemonicForMaster = await decryptMnemonic(await earningStore.loadMnemonicKeystore(), PASSWORD);
1256
1437
  const masterAccount = deriveMasterSigner(mnemonicForMaster);
1257
- const publicClient = createJinnPublicClient(config.rpcUrl, NETWORK_CHAIN);
1438
+ const publicClient = createJinnPublicClient(config.rpcUrls, NETWORK_CHAIN);
1258
1439
  publicClientForLauncher = publicClient;
1259
- const masterWallet = createJinnWalletClient(config.rpcUrl, NETWORK_CHAIN, masterAccount);
1440
+ const masterWallet = createJinnWalletClient(config.rpcUrls, NETWORK_CHAIN, masterAccount);
1441
+ // hjex.3: populate the restake callback now that mnemonic is available.
1442
+ if (config.stakingMode === 'standard' && CHAIN_CONFIG.distributorAddress) {
1443
+ const fleetStore = earningStore;
1444
+ restakeCallbackRef.current = async (serviceId) => {
1445
+ try {
1446
+ const state = await fleetStore.load(NETWORK_CHAIN);
1447
+ const svc = state.services.find(s => s.service_id === serviceId);
1448
+ if (!svc)
1449
+ return { ok: false, error: `service_not_found:${serviceId}` };
1450
+ if (!svc.staking_address)
1451
+ return { ok: false, error: 'staking_address_missing' };
1452
+ await recoverEvictedServiceFn({
1453
+ serviceDisplayIndex: Math.max(0, svc.index - 1),
1454
+ serviceId,
1455
+ stakingAddress: svc.staking_address,
1456
+ distributorAddress: CHAIN_CONFIG.distributorAddress,
1457
+ rpcUrl: config.rpcUrl,
1458
+ chain: NETWORK_CHAIN,
1459
+ mnemonic: mnemonicForMaster,
1460
+ });
1461
+ return { ok: true };
1462
+ }
1463
+ catch (err) {
1464
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
1465
+ }
1466
+ };
1467
+ }
1260
1468
  const evictionRecovery = config.stakingMode === 'standard' &&
1261
1469
  serviceId !== null &&
1262
1470
  stakingAddress &&
@@ -1315,7 +1523,7 @@ export async function main() {
1315
1523
  // the /build page rendered "Discovery unavailable" permanently.
1316
1524
  discoveryApiHolder.current = sharedDiscoveryApi;
1317
1525
  const adapter = new MechAdapter({
1318
- rpcUrl: config.rpcUrl,
1526
+ rpcUrl: config.rpcUrls,
1319
1527
  mechMarketplaceAddress: MARKETPLACE_ADDRESS,
1320
1528
  routerAddress: ROUTER_ADDRESS,
1321
1529
  mechContractAddress: mechAddress,
@@ -1353,26 +1561,52 @@ export async function main() {
1353
1561
  const agentChainContracts = agentChain.contracts;
1354
1562
  const optimismPortalAddress = agentChainContracts?.portal?.[l1Chain.id]?.address;
1355
1563
  const disputeGameFactoryAddress = agentChainContracts?.disputeGameFactory?.[l1Chain.id]?.address;
1356
- const l2ProofClient = config.l2ProofRpcUrl
1357
- ? createJinnPublicClient(config.l2ProofRpcUrl, NETWORK_CHAIN)
1564
+ const l2ProofClient = config.l2ProofRpcUrls
1565
+ ? createJinnPublicClient(config.l2ProofRpcUrls, NETWORK_CHAIN)
1358
1566
  : undefined;
1359
- const agentClients = createClients(config.rpcUrl, agentPrivateKey, agentChain);
1567
+ const agentClients = createClients(config.rpcUrls, agentPrivateKey, agentChain);
1360
1568
  // ── L1 (Sepolia / Ethereum mainnet) clients for cross-chain JINN claim loop ──
1361
1569
  // Uses the agent EOA because MockMessenger.owner is the agent on testnet.
1362
1570
  // Same key as L2; only the chain differs.
1363
- const l1ClientsForJinnClaim = JINN_MVI_CONFIG.distributor && config.ethereumRpcUrl
1571
+ const shouldWireJinnClaimL1 = shouldWireJinnClaimL1Signer({
1572
+ enabled: config.jinnClaimLoopEnabled,
1573
+ intervalMs: config.jinnClaimLoopIntervalMs,
1574
+ submissionMode: config.jinnClaimSubmissionMode,
1575
+ distributorAddress: JINN_MVI_CONFIG.distributor,
1576
+ ethereumRpcUrl: config.ethereumRpcUrl,
1577
+ });
1578
+ const l1ClientsForJinnClaim = shouldWireJinnClaimL1 && config.ethereumRpcUrls
1364
1579
  ? {
1365
- public: createJinnL1PublicClient(config.ethereumRpcUrl, config.jinnL1Network),
1366
- wallet: createJinnL1WalletClient(config.ethereumRpcUrl, config.jinnL1Network, privateKeyToAccount(agentPrivateKey)),
1580
+ public: createJinnL1PublicClient(config.ethereumRpcUrls, config.jinnL1Network),
1581
+ wallet: createJinnL1WalletClient(config.ethereumRpcUrls, config.jinnL1Network, privateKeyToAccount(agentPrivateKey)),
1367
1582
  }
1368
1583
  : undefined;
1369
- if (l1ClientsForJinnClaim) {
1370
- console.log(`[main] JinnClaimLoop: enabled (mode=${JINN_CLAIM_MESSENGER_MODE}, ` +
1584
+ const jinnClaimLoopConfig = buildJinnClaimLoopConfig({
1585
+ enabled: config.jinnClaimLoopEnabled,
1586
+ intervalMs: config.jinnClaimLoopIntervalMs,
1587
+ submissionMode: config.jinnClaimSubmissionMode,
1588
+ messengerMode: JINN_CLAIM_MESSENGER_MODE,
1589
+ mvi: JINN_MVI_CONFIG,
1590
+ l2Client: agentClients.publicClient,
1591
+ l2ProofClient,
1592
+ l2Wallet: agentClients.walletClient,
1593
+ l1Clients: l1ClientsForJinnClaim,
1594
+ store: earningStore,
1595
+ chain: NETWORK_CHAIN,
1596
+ optimismPortalAddress,
1597
+ disputeGameFactoryAddress,
1598
+ });
1599
+ if (jinnClaimLoopConfig) {
1600
+ console.log(`[main] JinnClaimLoop: enabled (submission=${config.jinnClaimSubmissionMode}, ` +
1601
+ `mode=${JINN_CLAIM_MESSENGER_MODE}, ` +
1371
1602
  `interval=${config.jinnClaimLoopIntervalMs}ms, distributor=${JINN_MVI_CONFIG.distributor}, ` +
1372
1603
  `emitter=${JINN_MVI_CONFIG.claimEmitter})`);
1373
1604
  }
1605
+ else if (!config.jinnClaimLoopEnabled) {
1606
+ console.log('[main] JinnClaimLoop: disabled (jinnClaimLoopEnabled=false)');
1607
+ }
1374
1608
  else {
1375
- console.log(`[main] JinnClaimLoop: disabled (JinnDistributor artifact/override or JINN_ETHEREUM_RPC_URL not set)`);
1609
+ console.log(`[main] JinnClaimLoop: disabled (missing claim-loop artifacts, interval disabled, or L1 submit wiring)`);
1376
1610
  }
1377
1611
  // ── Harness registry ─────────────────────────────────────────────────────────
1378
1612
  const solverNetRegistry = await loadSolverNets(config);
@@ -1464,6 +1698,9 @@ export async function main() {
1464
1698
  hermesPath: config.hermesPath,
1465
1699
  hermesModel: config.hermesModel,
1466
1700
  hermesProvider: config.hermesProvider,
1701
+ hermesDoctorTimeoutMs: config.hermesDoctorTimeoutMs,
1702
+ codexPath: config.codexPath,
1703
+ codexDoctorTimeoutMs: config.codexDoctorTimeoutMs,
1467
1704
  })) {
1468
1705
  implRegistry.register(impl);
1469
1706
  }
@@ -1733,11 +1970,19 @@ export async function main() {
1733
1970
  if (!safeAddressForLauncher) {
1734
1971
  throw new Error('[main] safeAddressForLauncher missing at SolverNet endpoints registration');
1735
1972
  }
1973
+ const getGeneratorState = (solverNetId) => {
1974
+ const entry = pendingGeneratorsRef.current.find((g) => g.recordRef.current.solverNetId === solverNetId);
1975
+ const resolved = resolveContractFromSolverNetId(entry?.recordRef.current.solverNetId ?? solverNetId);
1976
+ if (!resolved)
1977
+ return undefined;
1978
+ return launchedGeneratorStateBySolverType.get(resolved.solverType)?.();
1979
+ };
1736
1980
  solverNetEndpointsDepsHolder.current = {
1737
1981
  store: solverNetStore,
1738
1982
  launch: {
1739
1983
  launchAction,
1740
1984
  lifecycleTransition,
1985
+ getGeneratorState,
1741
1986
  pendingGenerators: pendingGeneratorsRef,
1742
1987
  signer: launcherSigner,
1743
1988
  network: 'base-sepolia',
@@ -1812,9 +2057,23 @@ export async function main() {
1812
2057
  if (config.network === 'mainnet' && !autoTasksDisabled && BASE_FEEDS['ETH / USD']) {
1813
2058
  // Mainnet auto-task opt-in only; default is OFF. Reserved for a future flag.
1814
2059
  }
2060
+ // filterBindableTasks (issue #415): drop config-level tasks[] entries without
2061
+ // solverNetManifestCid before they enter the creator loop. Such entries would
2062
+ // throw a PermanentError on every attempt and retry every 30 min indefinitely.
2063
+ const bindableConfigTasks = filterBindableTasks(config.tasks);
1815
2064
  const taskSources = [
1816
- new StaticConfiguredTaskSource(config.tasks),
1817
- ...launchedRecordGenerators.map(({ solverType, generator }, idx) => new GeneratedTaskSource(`launched:${solverType}:${idx}`, generator)),
2065
+ new StaticConfiguredTaskSource(bindableConfigTasks),
2066
+ ...launchedRecordGenerators.map(({ solverType, generator }, idx) => new GeneratedTaskSource(`launched:${solverType}:${idx}`, generator, {
2067
+ bucketKeyForTask: (task) => {
2068
+ if (task.solverType !== 'swe-rebench-v2.v1')
2069
+ return undefined;
2070
+ const instanceId = task.spec?.['instance_id'];
2071
+ const postedCount = task.eligibility?.['posted_count_after_record'];
2072
+ if (typeof instanceId !== 'string' || typeof postedCount !== 'number')
2073
+ return undefined;
2074
+ return `swe-rebench-v2:${instanceId}:${postedCount}`;
2075
+ },
2076
+ })),
1818
2077
  ];
1819
2078
  // ── Corpus (daemon-side, jinn-mono-vy37.1.6) ─────────────────────────────
1820
2079
  //
@@ -1847,6 +2106,7 @@ export async function main() {
1847
2106
  console.warn('[main] Corpus disabled (no DiscoveryAPI or on-chain identity registry); ' +
1848
2107
  'MCP record lookup and artifact acquisition network branches will be unavailable.');
1849
2108
  }
2109
+ const spendCap = buildSpendCapConfig(config, process.env);
1850
2110
  const daemon = new Daemon({
1851
2111
  adapter,
1852
2112
  runner,
@@ -1863,9 +2123,16 @@ export async function main() {
1863
2123
  creatorSafeAddress: safeAddress,
1864
2124
  corpusFactory,
1865
2125
  harnessReadinessRegistry,
2126
+ spendCap,
1866
2127
  status: {
1867
2128
  earningDir: config.earningDir,
1868
2129
  rpcUrl: config.rpcUrl,
2130
+ // tJINN identity comes from the bundled JINN MVI L1 artifact
2131
+ // (`JINN_MVI_CONFIG`) — one source of truth. The Sepolia RPC endpoint
2132
+ // is read from `config.ethereumRpcUrl` via the threaded `config`.
2133
+ tjinnTokenAddress: JINN_MVI_CONFIG.jinn,
2134
+ tjinnChainId: JINN_MVI_CONFIG.l1ChainId,
2135
+ tjinnDistributorAddress: JINN_MVI_CONFIG.distributor,
1869
2136
  network: config.network,
1870
2137
  pollIntervalMs: config.pollIntervalMs,
1871
2138
  masterEthDailyEstimateWei: config.masterEthDailyEstimateWei,
@@ -1877,6 +2144,7 @@ export async function main() {
1877
2144
  engine: config.engine,
1878
2145
  config,
1879
2146
  configPath: CONFIG_PATH ?? DEFAULT_CONFIG_PATH,
2147
+ spendCaps: spendCap?.caps,
1880
2148
  },
1881
2149
  rewardClaim: config.rewardClaimIntervalMs > 0
1882
2150
  ? {
@@ -1888,28 +2156,7 @@ export async function main() {
1888
2156
  distributorAddress: CHAIN_CONFIG.distributorAddress,
1889
2157
  }
1890
2158
  : undefined,
1891
- jinnClaim: l1ClientsForJinnClaim &&
1892
- JINN_MVI_CONFIG.claimEmitter &&
1893
- JINN_MVI_CONFIG.messenger &&
1894
- JINN_MVI_CONFIG.distributor &&
1895
- config.jinnClaimLoopIntervalMs > 0
1896
- ? {
1897
- intervalMs: config.jinnClaimLoopIntervalMs,
1898
- l2Client: agentClients.publicClient,
1899
- l2ProofClient,
1900
- l2Wallet: agentClients.walletClient,
1901
- l1Client: l1ClientsForJinnClaim.public,
1902
- l1Wallet: l1ClientsForJinnClaim.wallet,
1903
- store: earningStore,
1904
- chain: NETWORK_CHAIN,
1905
- claimEmitterAddress: JINN_MVI_CONFIG.claimEmitter,
1906
- distributorAddress: JINN_MVI_CONFIG.distributor,
1907
- messengerAddress: JINN_MVI_CONFIG.messenger,
1908
- messengerMode: JINN_CLAIM_MESSENGER_MODE,
1909
- optimismPortalAddress,
1910
- disputeGameFactoryAddress,
1911
- }
1912
- : undefined,
2159
+ jinnClaim: jinnClaimLoopConfig,
1913
2160
  restorationEngine: {
1914
2161
  paths: {
1915
2162
  workingDirRoot: config.engine.workingDirRoot,
@@ -1954,6 +2201,61 @@ export async function main() {
1954
2201
  safeTopupTarget: CHAIN_CONFIG.minSafeEth,
1955
2202
  }
1956
2203
  : undefined,
2204
+ // Eviction-check loop — only in standard staking mode (requires distributorAddress).
2205
+ // Running mode only: setup-halted daemons must not try to restake services that
2206
+ // haven't been staked yet (hjex.3).
2207
+ evictionCheck: config.evictionCheckIntervalMs > 0 &&
2208
+ config.stakingMode === 'standard' &&
2209
+ CHAIN_CONFIG.distributorAddress
2210
+ ? {
2211
+ intervalMs: config.evictionCheckIntervalMs,
2212
+ store: earningStore,
2213
+ chain: NETWORK_CHAIN,
2214
+ readContract: (opts) => publicClient.readContract(opts),
2215
+ recoverEvictedService: async (svc) => {
2216
+ if (!svc.service_id || !svc.staking_address)
2217
+ return;
2218
+ await recoverEvictedServiceFn({
2219
+ serviceDisplayIndex: Math.max(0, svc.index - 1),
2220
+ serviceId: svc.service_id,
2221
+ stakingAddress: svc.staking_address,
2222
+ distributorAddress: CHAIN_CONFIG.distributorAddress,
2223
+ rpcUrl: config.rpcUrl,
2224
+ chain: NETWORK_CHAIN,
2225
+ mnemonic: mnemonicForMaster,
2226
+ });
2227
+ },
2228
+ }
2229
+ : undefined,
2230
+ // Checkpoint loop — proactively advances `tsCheckpoint` on each staked
2231
+ // proxy so the activity-rate window stays narrow (issue #505).
2232
+ // `checkpoint()` is permissionless; master EOA pays gas. No-op for
2233
+ // non-standard staking modes.
2234
+ checkpoint: config.checkpointIntervalMs > 0 && config.stakingMode === 'standard'
2235
+ ? {
2236
+ intervalMs: config.checkpointIntervalMs,
2237
+ store: earningStore,
2238
+ chain: NETWORK_CHAIN,
2239
+ writeCheckpoint: async ({ stakingProxy }) => {
2240
+ const txHash = await masterWallet.writeContract({
2241
+ address: stakingProxy,
2242
+ abi: [
2243
+ {
2244
+ type: 'function',
2245
+ name: 'checkpoint',
2246
+ stateMutability: 'nonpayable',
2247
+ inputs: [],
2248
+ outputs: [],
2249
+ },
2250
+ ],
2251
+ functionName: 'checkpoint',
2252
+ account: masterAccount,
2253
+ chain: null,
2254
+ });
2255
+ return { txHash };
2256
+ },
2257
+ }
2258
+ : undefined,
1957
2259
  });
1958
2260
  // Write pidfile so `jinn stop` can find us.
1959
2261
  const pidPath = join(config.earningDir, 'daemon.pid');