@jinn-network/client 0.1.6 → 0.1.7-canary.0a586ca9

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 (434) 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 +57 -2
  7. package/dist/adapters/mech/adapter.js +366 -63
  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 +19 -4
  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/agent/operator-claude.js +8 -0
  24. package/dist/agent/operator-claude.js.map +1 -1
  25. package/dist/api/activity-events-endpoint.d.ts +14 -0
  26. package/dist/api/activity-events-endpoint.js +59 -0
  27. package/dist/api/activity-events-endpoint.js.map +1 -0
  28. package/dist/api/admin-endpoint.d.ts +15 -3
  29. package/dist/api/admin-endpoint.js +24 -2
  30. package/dist/api/admin-endpoint.js.map +1 -1
  31. package/dist/api/bootstrap-endpoint.d.ts +1 -2
  32. package/dist/api/bootstrap-endpoint.js +85 -18
  33. package/dist/api/bootstrap-endpoint.js.map +1 -1
  34. package/dist/api/codex-doctor-endpoint.d.ts +90 -0
  35. package/dist/api/codex-doctor-endpoint.js +296 -0
  36. package/dist/api/codex-doctor-endpoint.js.map +1 -0
  37. package/dist/api/discovery-endpoint.d.ts +1 -0
  38. package/dist/api/discovery-endpoint.js +26 -0
  39. package/dist/api/discovery-endpoint.js.map +1 -1
  40. package/dist/api/fleet-build.d.ts +1 -0
  41. package/dist/api/fleet-build.js +2 -1
  42. package/dist/api/fleet-build.js.map +1 -1
  43. package/dist/api/gather-status.d.ts +37 -0
  44. package/dist/api/gather-status.js +572 -19
  45. package/dist/api/gather-status.js.map +1 -1
  46. package/dist/api/hermes-doctor-endpoint.d.ts +128 -3
  47. package/dist/api/hermes-doctor-endpoint.js +265 -22
  48. package/dist/api/hermes-doctor-endpoint.js.map +1 -1
  49. package/dist/api/launcher-status.d.ts +24 -17
  50. package/dist/api/launcher-status.js +13 -11
  51. package/dist/api/launcher-status.js.map +1 -1
  52. package/dist/api/launcher-tasks.d.ts +1 -1
  53. package/dist/api/launcher-tasks.js +12 -8
  54. package/dist/api/launcher-tasks.js.map +1 -1
  55. package/dist/api/operator-artifacts-endpoint.js +73 -6
  56. package/dist/api/operator-artifacts-endpoint.js.map +1 -1
  57. package/dist/api/portfolio-v0-build.d.ts +10 -0
  58. package/dist/api/portfolio-v0-build.js +24 -5
  59. package/dist/api/portfolio-v0-build.js.map +1 -1
  60. package/dist/api/prediction-v1-build.d.ts +10 -0
  61. package/dist/api/prediction-v1-build.js +7 -1
  62. package/dist/api/prediction-v1-build.js.map +1 -1
  63. package/dist/api/server.d.ts +31 -1
  64. package/dist/api/server.js +95 -2
  65. package/dist/api/server.js.map +1 -1
  66. package/dist/api/setup-endpoints.d.ts +7 -0
  67. package/dist/api/setup-endpoints.js +67 -135
  68. package/dist/api/setup-endpoints.js.map +1 -1
  69. package/dist/api/setup-retry-endpoint.d.ts +19 -0
  70. package/dist/api/setup-retry-endpoint.js +32 -0
  71. package/dist/api/setup-retry-endpoint.js.map +1 -0
  72. package/dist/api/solvernets-endpoints.d.ts +8 -0
  73. package/dist/api/solvernets-endpoints.js +100 -105
  74. package/dist/api/solvernets-endpoints.js.map +1 -1
  75. package/dist/api/status-build.d.ts +167 -2
  76. package/dist/api/status-build.js +118 -27
  77. package/dist/api/status-build.js.map +1 -1
  78. package/dist/api/status-harness-rollup.d.ts +35 -0
  79. package/dist/api/status-harness-rollup.js +45 -0
  80. package/dist/api/status-harness-rollup.js.map +1 -0
  81. package/dist/api/task-run-routing.d.ts +7 -0
  82. package/dist/api/task-run-routing.js +12 -0
  83. package/dist/api/task-run-routing.js.map +1 -0
  84. package/dist/api/task-runs-build.d.ts +21 -0
  85. package/dist/api/task-runs-build.js +14 -1
  86. package/dist/api/task-runs-build.js.map +1 -1
  87. package/dist/build-info.json +4 -4
  88. package/dist/build-meta.json +1 -1
  89. package/dist/captures/live-publisher.js +24 -4
  90. package/dist/captures/live-publisher.js.map +1 -1
  91. package/dist/captures/publish.d.ts +1 -1
  92. package/dist/chain-read-errors.d.ts +22 -0
  93. package/dist/chain-read-errors.js +41 -1
  94. package/dist/chain-read-errors.js.map +1 -1
  95. package/dist/cli/commands/auth.js +1 -1
  96. package/dist/cli/commands/auth.js.map +1 -1
  97. package/dist/cli/commands/codedigest-revert-check.d.ts +33 -0
  98. package/dist/cli/commands/codedigest-revert-check.js +249 -0
  99. package/dist/cli/commands/codedigest-revert-check.js.map +1 -0
  100. package/dist/cli/commands/create.js +3 -2
  101. package/dist/cli/commands/create.js.map +1 -1
  102. package/dist/cli/commands/doctor.d.ts +2 -0
  103. package/dist/cli/commands/doctor.js +2 -0
  104. package/dist/cli/commands/doctor.js.map +1 -1
  105. package/dist/cli/commands/rewards.js +11 -7
  106. package/dist/cli/commands/rewards.js.map +1 -1
  107. package/dist/cli/commands/solver-nets.d.ts +1 -0
  108. package/dist/cli/commands/solver-nets.js +179 -16
  109. package/dist/cli/commands/solver-nets.js.map +1 -1
  110. package/dist/cli/commands/solver-plugins-block.d.ts +33 -0
  111. package/dist/cli/commands/solver-plugins-block.js +118 -0
  112. package/dist/cli/commands/solver-plugins-block.js.map +1 -0
  113. package/dist/cli/commands/solver-plugins-feedback.d.ts +72 -0
  114. package/dist/cli/commands/solver-plugins-feedback.js +262 -0
  115. package/dist/cli/commands/solver-plugins-feedback.js.map +1 -0
  116. package/dist/cli/commands/solver-plugins-read.d.ts +54 -0
  117. package/dist/cli/commands/solver-plugins-read.js +259 -0
  118. package/dist/cli/commands/solver-plugins-read.js.map +1 -0
  119. package/dist/cli/commands/solver-plugins.d.ts +35 -0
  120. package/dist/cli/commands/solver-plugins.js +399 -2
  121. package/dist/cli/commands/solver-plugins.js.map +1 -1
  122. package/dist/cli/commands/status.js +1 -1
  123. package/dist/cli/commands/status.js.map +1 -1
  124. package/dist/cli/commands/tasks.js +101 -11
  125. package/dist/cli/commands/tasks.js.map +1 -1
  126. package/dist/cli/commands/update.d.ts +10 -0
  127. package/dist/cli/commands/update.js +36 -0
  128. package/dist/cli/commands/update.js.map +1 -1
  129. package/dist/cli/index.js +2 -0
  130. package/dist/cli/index.js.map +1 -1
  131. package/dist/cli/introspection-context.js +5 -0
  132. package/dist/cli/introspection-context.js.map +1 -1
  133. package/dist/cli/task-native-readiness.d.ts +10 -1
  134. package/dist/cli/task-native-readiness.js +30 -6
  135. package/dist/cli/task-native-readiness.js.map +1 -1
  136. package/dist/config.d.ts +287 -235
  137. package/dist/config.js +318 -114
  138. package/dist/config.js.map +1 -1
  139. package/dist/daemon/checkpoint-loop.d.ts +48 -0
  140. package/dist/daemon/checkpoint-loop.js +76 -0
  141. package/dist/daemon/checkpoint-loop.js.map +1 -0
  142. package/dist/daemon/creator.d.ts +1 -1
  143. package/dist/daemon/creator.js +20 -3
  144. package/dist/daemon/creator.js.map +1 -1
  145. package/dist/daemon/daemon.d.ts +22 -0
  146. package/dist/daemon/daemon.js +174 -31
  147. package/dist/daemon/daemon.js.map +1 -1
  148. package/dist/daemon/eviction-loop.d.ts +40 -0
  149. package/dist/daemon/eviction-loop.js +67 -0
  150. package/dist/daemon/eviction-loop.js.map +1 -0
  151. package/dist/daemon/gate-logger.d.ts +9 -0
  152. package/dist/daemon/gate-logger.js +2 -0
  153. package/dist/daemon/gate-logger.js.map +1 -0
  154. package/dist/daemon/jinn-claim-loop-wiring.d.ts +33 -0
  155. package/dist/daemon/jinn-claim-loop-wiring.js +40 -0
  156. package/dist/daemon/jinn-claim-loop-wiring.js.map +1 -0
  157. package/dist/daemon/jinn-claim-loop.d.ts +24 -17
  158. package/dist/daemon/jinn-claim-loop.js +77 -23
  159. package/dist/daemon/jinn-claim-loop.js.map +1 -1
  160. package/dist/daemon/readiness-gate.d.ts +1 -4
  161. package/dist/daemon/readiness-gate.js.map +1 -1
  162. package/dist/daemon/skip-log-dedup.d.ts +69 -0
  163. package/dist/daemon/skip-log-dedup.js +106 -0
  164. package/dist/daemon/skip-log-dedup.js.map +1 -0
  165. package/dist/daemon/spend-cap-gate.d.ts +40 -0
  166. package/dist/daemon/spend-cap-gate.js +46 -0
  167. package/dist/daemon/spend-cap-gate.js.map +1 -0
  168. package/dist/dashboard/assets/index-BNs_ewI6.js +345 -0
  169. package/dist/dashboard/assets/index-C4huIsUW.css +32 -0
  170. package/dist/dashboard/index.html +2 -2
  171. package/dist/discovery/factory.d.ts +17 -5
  172. package/dist/discovery/factory.js +46 -18
  173. package/dist/discovery/factory.js.map +1 -1
  174. package/dist/discovery/http.js +469 -3
  175. package/dist/discovery/http.js.map +1 -1
  176. package/dist/discovery/onchain.d.ts +5 -0
  177. package/dist/discovery/onchain.js +448 -18
  178. package/dist/discovery/onchain.js.map +1 -1
  179. package/dist/discovery/types.d.ts +174 -1
  180. package/dist/discovery/types.js +8 -10
  181. package/dist/discovery/types.js.map +1 -1
  182. package/dist/discovery/with-fallback.d.ts +7 -0
  183. package/dist/discovery/with-fallback.js +37 -0
  184. package/dist/discovery/with-fallback.js.map +1 -1
  185. package/dist/earning/bootstrap.d.ts +100 -4
  186. package/dist/earning/bootstrap.js +239 -76
  187. package/dist/earning/bootstrap.js.map +1 -1
  188. package/dist/earning/contracts.d.ts +14 -0
  189. package/dist/earning/contracts.js +17 -5
  190. package/dist/earning/contracts.js.map +1 -1
  191. package/dist/earning/funding-plan.js +27 -18
  192. package/dist/earning/funding-plan.js.map +1 -1
  193. package/dist/earning/jinn-rewards.d.ts +46 -0
  194. package/dist/earning/jinn-rewards.js +32 -0
  195. package/dist/earning/jinn-rewards.js.map +1 -1
  196. package/dist/earning/safe-adapter.d.ts +2 -0
  197. package/dist/earning/safe-adapter.js +37 -11
  198. package/dist/earning/safe-adapter.js.map +1 -1
  199. package/dist/earning/store.d.ts +8 -0
  200. package/dist/earning/store.js.map +1 -1
  201. package/dist/earning/testnet-setup-migration.d.ts +12 -0
  202. package/dist/earning/testnet-setup-migration.js +27 -1
  203. package/dist/earning/testnet-setup-migration.js.map +1 -1
  204. package/dist/earning/types.d.ts +21 -6
  205. package/dist/earning/viem-clients.d.ts +11 -4
  206. package/dist/earning/viem-clients.js +14 -5
  207. package/dist/earning/viem-clients.js.map +1 -1
  208. package/dist/erc8004/identity.d.ts +19 -3
  209. package/dist/erc8004/identity.js +21 -6
  210. package/dist/erc8004/identity.js.map +1 -1
  211. package/dist/erc8004/index.d.ts +1 -1
  212. package/dist/erc8004/index.js.map +1 -1
  213. package/dist/erc8004/reputation.d.ts +8 -0
  214. package/dist/erc8004/reputation.js +22 -3
  215. package/dist/erc8004/reputation.js.map +1 -1
  216. package/dist/events/types.d.ts +2 -2
  217. package/dist/harnesses/cost-estimates.d.ts +124 -0
  218. package/dist/harnesses/cost-estimates.js +265 -0
  219. package/dist/harnesses/cost-estimates.js.map +1 -0
  220. package/dist/harnesses/engine/engine.d.ts +78 -0
  221. package/dist/harnesses/engine/engine.js +153 -11
  222. package/dist/harnesses/engine/engine.js.map +1 -1
  223. package/dist/harnesses/engine/persistence.d.ts +51 -1
  224. package/dist/harnesses/engine/persistence.js +118 -5
  225. package/dist/harnesses/engine/persistence.js.map +1 -1
  226. package/dist/harnesses/engine/work-dir-reaper.d.ts +65 -0
  227. package/dist/harnesses/engine/work-dir-reaper.js +100 -0
  228. package/dist/harnesses/engine/work-dir-reaper.js.map +1 -0
  229. package/dist/harnesses/impls/hermes-agent/adapter.js +40 -0
  230. package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -1
  231. package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +20 -0
  232. package/dist/harnesses/impls/hermes-agent/bootstrap.js +44 -8
  233. package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
  234. package/dist/harnesses/impls/hermes-agent/config-builder.d.ts +1 -1
  235. package/dist/harnesses/impls/hermes-agent/config-builder.js +4 -2
  236. package/dist/harnesses/impls/hermes-agent/config-builder.js.map +1 -1
  237. package/dist/harnesses/impls/hermes-agent/harness.d.ts +59 -1
  238. package/dist/harnesses/impls/hermes-agent/harness.js +104 -0
  239. package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
  240. package/dist/harnesses/impls/hermes-agent/prompt.d.ts +6 -6
  241. package/dist/harnesses/impls/hermes-agent/prompt.js +6 -6
  242. package/dist/harnesses/impls/index.d.ts +7 -0
  243. package/dist/harnesses/impls/index.js +16 -1
  244. package/dist/harnesses/impls/index.js.map +1 -1
  245. package/dist/harnesses/impls/learner/adapters/codex-code.d.ts +9 -0
  246. package/dist/harnesses/impls/learner/adapters/codex-code.js +30 -8
  247. package/dist/harnesses/impls/learner/adapters/codex-code.js.map +1 -1
  248. package/dist/harnesses/impls/learner/harness.d.ts +47 -4
  249. package/dist/harnesses/impls/learner/harness.js +105 -2
  250. package/dist/harnesses/impls/learner/harness.js.map +1 -1
  251. package/dist/harnesses/impls/learner/harvest.d.ts +1 -1
  252. package/dist/harnesses/impls/learner/harvest.js +23 -5
  253. package/dist/harnesses/impls/learner/harvest.js.map +1 -1
  254. package/dist/harnesses/impls/learner/plugin-path.d.ts +0 -13
  255. package/dist/harnesses/impls/learner/plugin-path.js +35 -15
  256. package/dist/harnesses/impls/learner/plugin-path.js.map +1 -1
  257. package/dist/harnesses/impls/learner/restoration-patch.d.ts +2 -2
  258. package/dist/harnesses/impls/learner/restoration-patch.js +25 -6
  259. package/dist/harnesses/impls/learner/restoration-patch.js.map +1 -1
  260. package/dist/harnesses/impls/learner/types.d.ts +11 -0
  261. package/dist/harnesses/impls/stub.d.ts +58 -0
  262. package/dist/harnesses/impls/stub.js +89 -0
  263. package/dist/harnesses/impls/stub.js.map +1 -0
  264. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.d.ts +69 -50
  265. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +199 -94
  266. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
  267. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.d.ts +12 -1
  268. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +121 -7
  269. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
  270. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +88 -4
  271. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +143 -22
  272. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
  273. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.d.ts +6 -0
  274. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js +1 -1
  275. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js.map +1 -1
  276. package/dist/harnesses/readiness-registry.d.ts +7 -0
  277. package/dist/harnesses/readiness-registry.js +18 -1
  278. package/dist/harnesses/readiness-registry.js.map +1 -1
  279. package/dist/learner/revert-decision.d.ts +59 -0
  280. package/dist/learner/revert-decision.js +53 -0
  281. package/dist/learner/revert-decision.js.map +1 -0
  282. package/dist/learner/revert-stats.d.ts +24 -0
  283. package/dist/learner/revert-stats.js +44 -0
  284. package/dist/learner/revert-stats.js.map +1 -0
  285. package/dist/main.js +470 -142
  286. package/dist/main.js.map +1 -1
  287. package/dist/mcp/get-codedigest-reward.d.ts +13 -0
  288. package/dist/mcp/get-codedigest-reward.js +23 -0
  289. package/dist/mcp/get-codedigest-reward.js.map +1 -0
  290. package/dist/mcp/server.js +23 -0
  291. package/dist/mcp/server.js.map +1 -1
  292. package/dist/observability/emit-event.d.ts +3 -2
  293. package/dist/observability/emit-event.js +22 -1
  294. package/dist/observability/emit-event.js.map +1 -1
  295. package/dist/operator-errors.d.ts +7 -0
  296. package/dist/operator-errors.js +13 -1
  297. package/dist/operator-errors.js.map +1 -1
  298. package/dist/plugins/learner/.claude-plugin/plugin.json +9 -0
  299. package/dist/plugins/learner/.codex-plugin/plugin.json +39 -0
  300. package/dist/plugins/learner/AGENTS.md +40 -0
  301. package/dist/plugins/learner/CLAUDE.md +33 -0
  302. package/dist/plugins/learner/README.md +59 -0
  303. package/dist/plugins/learner/hooks/hooks.json +16 -0
  304. package/dist/plugins/learner/hooks/session-start +38 -0
  305. package/dist/plugins/learner/skills/learn/SKILL.md +412 -0
  306. package/dist/plugins/learner/skills/learn/analyst-prompt.md +68 -0
  307. package/dist/plugins/learner/skills/learn/consolidator-prompt.md +111 -0
  308. package/dist/plugins/learner/skills/learn/explorer-prompt.md +53 -0
  309. package/dist/plugins/learner/skills/learn/planner-prompt.md +87 -0
  310. package/dist/plugins/learner/skills/learn/promoter-prompt.md +184 -0
  311. package/dist/plugins/learner/skills/learn/step-worker-prompt.md +47 -0
  312. package/dist/plugins/learner/skills/learn/strategist-prompt.md +85 -0
  313. package/dist/preflight/pidfile-liveness.d.ts +44 -0
  314. package/dist/preflight/pidfile-liveness.js +103 -0
  315. package/dist/preflight/pidfile-liveness.js.map +1 -0
  316. package/dist/preflight/rpc-network.d.ts +40 -0
  317. package/dist/preflight/rpc-network.js +67 -1
  318. package/dist/preflight/rpc-network.js.map +1 -1
  319. package/dist/restart-daemon.d.ts +90 -0
  320. package/dist/restart-daemon.js +95 -0
  321. package/dist/restart-daemon.js.map +1 -0
  322. package/dist/rpc/transport.d.ts +109 -0
  323. package/dist/rpc/transport.js +220 -0
  324. package/dist/rpc/transport.js.map +1 -0
  325. package/dist/scripts/donation-consumption-acceptance.js +7 -28
  326. package/dist/scripts/donation-consumption-acceptance.js.map +1 -1
  327. package/dist/scripts/swe-rebench-v2-pytest-missing.json +16 -0
  328. package/dist/setup/halt-mode.d.ts +14 -0
  329. package/dist/setup/halt-mode.js +17 -0
  330. package/dist/setup/halt-mode.js.map +1 -0
  331. package/dist/solver-nets/prediction-operator-ux.d.ts +1 -2
  332. package/dist/solver-nets/prediction-operator-ux.js +90 -47
  333. package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
  334. package/dist/solver-nets/registry.d.ts +20 -1
  335. package/dist/solver-nets/registry.js +38 -25
  336. package/dist/solver-nets/registry.js.map +1 -1
  337. package/dist/solver-types/_swe-rebench-v2-pool-cache.d.ts +58 -0
  338. package/dist/solver-types/_swe-rebench-v2-pool-cache.js +87 -0
  339. package/dist/solver-types/_swe-rebench-v2-pool-cache.js.map +1 -0
  340. package/dist/solver-types/_swe-rebench-v2-pool.d.ts +9 -2
  341. package/dist/solver-types/_swe-rebench-v2-pool.js +15 -20
  342. package/dist/solver-types/_swe-rebench-v2-pool.js.map +1 -1
  343. package/dist/solver-types/_swe-rebench-v2-state.d.ts +15 -0
  344. package/dist/solver-types/_swe-rebench-v2-state.js +19 -0
  345. package/dist/solver-types/_swe-rebench-v2-state.js.map +1 -1
  346. package/dist/solver-types/_swe-rebench-v2-substrate.d.ts +1 -0
  347. package/dist/solver-types/_swe-rebench-v2-substrate.js +10 -0
  348. package/dist/solver-types/_swe-rebench-v2-substrate.js.map +1 -1
  349. package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +145 -2
  350. package/dist/solver-types/_swe-rebench-v2-validated-pool.js +482 -44
  351. package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
  352. package/dist/solver-types/swe-rebench-v2-auto.d.ts +38 -14
  353. package/dist/solver-types/swe-rebench-v2-auto.js +87 -28
  354. package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
  355. package/dist/solver-types/swe-rebench-v2.d.ts +19 -2
  356. package/dist/solver-types/swe-rebench-v2.js +351 -96
  357. package/dist/solver-types/swe-rebench-v2.js.map +1 -1
  358. package/dist/solvernets/daemon-init.d.ts +10 -2
  359. package/dist/solvernets/daemon-init.js +22 -2
  360. package/dist/solvernets/daemon-init.js.map +1 -1
  361. package/dist/solvernets/launched-record-dispatcher.d.ts +4 -0
  362. package/dist/solvernets/launched-record-dispatcher.js +41 -7
  363. package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
  364. package/dist/solvernets/registry-client-erc8004.js +11 -0
  365. package/dist/solvernets/registry-client-erc8004.js.map +1 -1
  366. package/dist/solvernets/store.d.ts +7 -2
  367. package/dist/solvernets/store.js +1 -0
  368. package/dist/solvernets/store.js.map +1 -1
  369. package/dist/spend/cost-surface-status.d.ts +10 -0
  370. package/dist/spend/cost-surface-status.js +22 -0
  371. package/dist/spend/cost-surface-status.js.map +1 -0
  372. package/dist/spend/credential.d.ts +8 -0
  373. package/dist/spend/credential.js +30 -0
  374. package/dist/spend/credential.js.map +1 -0
  375. package/dist/spend/daemon-config.d.ts +13 -0
  376. package/dist/spend/daemon-config.js +24 -0
  377. package/dist/spend/daemon-config.js.map +1 -0
  378. package/dist/spend/pricing.d.ts +16 -0
  379. package/dist/spend/pricing.js +26 -0
  380. package/dist/spend/pricing.js.map +1 -0
  381. package/dist/spend/record.d.ts +13 -0
  382. package/dist/spend/record.js +30 -0
  383. package/dist/spend/record.js.map +1 -0
  384. package/dist/spend/usage.d.ts +27 -0
  385. package/dist/spend/usage.js +113 -0
  386. package/dist/spend/usage.js.map +1 -0
  387. package/dist/store/store.d.ts +61 -0
  388. package/dist/store/store.js +302 -7
  389. package/dist/store/store.js.map +1 -1
  390. package/dist/tasks/sources.d.ts +18 -1
  391. package/dist/tasks/sources.js +33 -5
  392. package/dist/tasks/sources.js.map +1 -1
  393. package/dist/trajectory/transcript-parsers/codex-session.d.ts +12 -6
  394. package/dist/trajectory/transcript-parsers/codex-session.js +114 -13
  395. package/dist/trajectory/transcript-parsers/codex-session.js.map +1 -1
  396. package/dist/trajectory/transcript-parsers/types.d.ts +8 -8
  397. package/dist/trajectory/transcript-session-dirs.d.ts +18 -0
  398. package/dist/trajectory/transcript-session-dirs.js +85 -0
  399. package/dist/trajectory/transcript-session-dirs.js.map +1 -0
  400. package/dist/trajectory/transcript-watcher.d.ts +20 -1
  401. package/dist/trajectory/transcript-watcher.js +98 -32
  402. package/dist/trajectory/transcript-watcher.js.map +1 -1
  403. package/dist/tx-retry.d.ts +166 -19
  404. package/dist/tx-retry.js +310 -32
  405. package/dist/tx-retry.js.map +1 -1
  406. package/dist/types/payloads/portfolio-v0.d.ts +3 -3
  407. package/dist/types/payloads/prediction-apy-v0.d.ts +8 -8
  408. package/dist/types/payloads/prediction-v0.d.ts +17 -17
  409. package/dist/types/task-document.d.ts +392 -0
  410. package/dist/types/task-document.js +10 -0
  411. package/dist/types/task-document.js.map +1 -1
  412. package/dist/types/task.d.ts +28 -0
  413. package/dist/util/extract-tx-hash.d.ts +14 -0
  414. package/dist/util/extract-tx-hash.js +19 -0
  415. package/dist/util/extract-tx-hash.js.map +1 -0
  416. package/dist/vendor/@jinn-network/sdk/dist/contracts.js +1 -1
  417. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.d.ts +3 -0
  418. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.js +1 -0
  419. package/package.json +37 -13
  420. package/plugins/learner/skills/learn/consolidator-prompt.md +18 -1
  421. package/plugins/learner/skills/learn/promoter-prompt.md +72 -1
  422. package/plugins/swe-rebench-v2-diffmin/README.md +10 -9
  423. package/plugins/swe-rebench-v2-diffmin/jinn.plugin.json +1 -1
  424. package/plugins/swe-rebench-v2-diffmin/skills/diffmin/SKILL.md +15 -10
  425. package/plugins/swe-rebench-v2-diffmin/skills/test-map/SKILL.md +10 -12
  426. package/plugins/swe-rebench-v2-runtime/.claude-plugin/plugin.json +1 -1
  427. package/plugins/swe-rebench-v2-runtime/.codex-plugin/plugin.json +3 -3
  428. package/plugins/swe-rebench-v2-runtime/README.md +6 -6
  429. package/plugins/swe-rebench-v2-runtime/jinn.plugin.json +2 -3
  430. package/plugins/swe-rebench-v2-runtime/skills/task/SKILL.md +69 -0
  431. package/dist/dashboard/assets/index-DOlzFN8a.css +0 -32
  432. package/dist/dashboard/assets/index-NkZ7CTAT.js +0 -140
  433. package/plugins/swe-rebench-v2-runtime/skills/orient/SKILL.md +0 -29
  434. package/plugins/swe-rebench-v2-runtime/skills/plan/SKILL.md +0 -53
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,12 @@ 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 { applyPidfileLivenessGate } from './preflight/pidfile-liveness.js';
45
+ import { FleetBootstrapper, recoverEvictedService as recoverEvictedServiceFn } from './earning/bootstrap.js';
43
46
  import { DEFAULT_TESTNET_ARTIFACTS, applyChainGasOverrides, getChainConfig, loadJinnMviConfig } from './earning/contracts.js';
44
47
  import { runLegacyAgentIdMigration } from './earning/migrate-agent-id.js';
45
48
  import { FleetStateStore } from './earning/store.js';
@@ -48,6 +51,8 @@ import { decryptMnemonic, deriveMasterSigner, walletPrivateKeyAtIndex } from './
48
51
  import { MechAdapter } from './adapters/mech/adapter.js';
49
52
  import { ClaudeRunner } from './runner/claude.js';
50
53
  import { Daemon } from './daemon/daemon.js';
54
+ import { buildSpendCapConfig } from './spend/daemon-config.js';
55
+ import { buildJinnClaimLoopConfig, shouldWireJinnClaimL1Signer, } from './daemon/jinn-claim-loop-wiring.js';
51
56
  import { createJinnPublicClient, createJinnWalletClient, createJinnL1PublicClient, createJinnL1WalletClient } from './earning/viem-clients.js';
52
57
  import { privateKeyToAccount } from 'viem/accounts';
53
58
  import { getAddress } from 'viem';
@@ -56,9 +61,10 @@ import { joinedSolverNetsViewFromConfig } from './harnesses/engine/engine.js';
56
61
  import { buildHarnesses } from './harnesses/impls/index.js';
57
62
  import { loadExternalImpl } from './harnesses/external-impls/index.js';
58
63
  import { CLAUDE_CODE_HARNESS, CODEX_HARNESS, HERMES_AGENT_HARNESS, harnessStateDirName } from './harnesses/names.js';
64
+ import { resolveContractFromSolverNetId } from './solvernets/launched-record-dispatcher.js';
59
65
  import { HarnessReadinessRegistry } from './harnesses/readiness-registry.js';
60
66
  import { createClients } from './adapters/mech/safe.js';
61
- import { loadSolverNets } from './solver-nets/registry.js';
67
+ import { findJoinedByName, loadSolverNets, solverTypeFromJoinedContract, } from './solver-nets/registry.js';
62
68
  import { createCorpus } from './corpus/index.js';
63
69
  import { DEFAULT_EXECUTION_DISCOVERY_FROM_BLOCK } from './corpus/onchain-query.js';
64
70
  import { CapturesStore } from './store/captures.js';
@@ -74,12 +80,15 @@ import { ClaudeCodeJsonlParser } from './trajectory/transcript-parsers/claude-co
74
80
  import { CodexSessionParser } from './trajectory/transcript-parsers/codex-session.js';
75
81
  import { GeminiSessionParser } from './trajectory/transcript-parsers/gemini-session.js';
76
82
  import { CursorSqliteParser } from './trajectory/transcript-parsers/cursor-sqlite.js';
83
+ import { startTranscriptWatcher, } from './trajectory/transcript-watcher.js';
84
+ import { defaultTranscriptWatchDirectories } from './trajectory/transcript-session-dirs.js';
77
85
  import { buildInfo } from './build-info.js';
78
86
  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';
87
+ import { GeneratedTaskSource, StaticConfiguredTaskSource, filterBindableTasks } from './tasks/sources.js';
88
+ import { checkRpcNetwork, logRpcLocalDevToStderr, probeFallbackChain, rpcNetworkFailureHint, summarizeFallbackChain, } from './preflight/rpc-network.js';
81
89
  import { apiPortFailureMessage, checkApiPortAvailable } from './preflight/api-port.js';
82
90
  import { openBrowser } from './cli/open-browser.js';
91
+ import { keepSetupUiOnBootstrapError } from './setup/halt-mode.js';
83
92
  if (process.env['JINN_LOAD_DEV_ENV'] === '1' || process.env['NODE_ENV'] === 'development') {
84
93
  dotenvConfig({ path: join(dirname(fileURLToPath(import.meta.url)), '..', '.env') });
85
94
  }
@@ -132,8 +141,19 @@ const config = loadConfig(CONFIG_PATH);
132
141
  if (config.network === 'mainnet' && process.env['JINN_ENABLE_MAINNET'] !== '1') {
133
142
  console.warn('[main] Mainnet is disabled before launch; using testnet defaults.');
134
143
  config.network = 'testnet';
135
- config.rpcUrl = 'https://base-sepolia.gateway.tenderly.co/75tyLMQuD8EHpXxMwINIKu';
144
+ config.rpcUrl = 'https://base-sepolia-rpc.publicnode.com';
136
145
  }
146
+ // Issue #326: the embedded Claude agent chat surface (right rail + onboarding
147
+ // "Ask Claude" panel + /api/agent/ws bridge) is hidden by default while its
148
+ // action-authority / plugin-scope shape is still in design. Set
149
+ // `JINN_ENABLE_EMBEDDED_AGENT=1` to re-enable it for development. This does
150
+ // NOT affect Claude-Code-as-a-solver-harness — that path is independent.
151
+ //
152
+ // Issue #367: the SPA reads this flag via the injected `window.__JINN_FEATURES__`
153
+ // (`resolveFeatureFlags` in api/server.ts) like every other operator-app flag.
154
+ // This `embeddedAgentEnabled` const is the daemon-side consumer only — it gates
155
+ // whether the `/api/agent/ws` bridge is mounted below.
156
+ const embeddedAgentEnabled = isEmbeddedAgentEnabled();
137
157
  let activeClaudePath = config.claudePath ?? 'claude';
138
158
  const selectClaudePath = (claudePath) => {
139
159
  activeClaudePath = claudePath;
@@ -187,25 +207,15 @@ class EnsurePendingCaptureProcessor {
187
207
  onStart() { }
188
208
  onEnd(span) {
189
209
  const sessionId = stringAttribute(span.attributes['jinn.session.id']);
190
- if (!sessionId || this.captures.getBySession(sessionId))
210
+ if (!sessionId)
191
211
  return;
192
- try {
193
- this.captures.savePending({
194
- sessionId,
195
- capturedAt: hrTimeToIso(span.startTime),
196
- originatingTool: { name: inferCaptureTool(span) },
197
- capturePath: 'A',
198
- status: 'pending',
199
- spanCount: 0,
200
- durationMs: 0,
201
- redactedSpanCount: 0,
202
- ...repoMetadataFromSpan(span),
203
- });
204
- }
205
- catch (err) {
206
- if (!this.captures.getBySession(sessionId))
207
- throw err;
208
- }
212
+ ensurePendingCapture(this.captures, {
213
+ sessionId,
214
+ capturedAt: hrTimeToIso(span.startTime),
215
+ tool: inferCaptureTool(span),
216
+ capturePath: inferCapturePath(span),
217
+ ...repoMetadataFromSpan(span),
218
+ });
209
219
  }
210
220
  }
211
221
  function stringAttribute(value) {
@@ -220,6 +230,11 @@ function inferCaptureTool(span) {
220
230
  ?? stringAttribute(span.resource.attributes['service.name'])
221
231
  ?? 'otel';
222
232
  }
233
+ function inferCapturePath(span) {
234
+ if (stringAttribute(span.attributes['transcript.tool']))
235
+ return 'B';
236
+ return 'A';
237
+ }
223
238
  function repoMetadataFromSpan(span) {
224
239
  const attrs = span.attributes;
225
240
  const repoRemoteUrl = stringAttribute(attrs['repo.remote_url'])
@@ -249,28 +264,35 @@ function parserForStopHookTool(tool) {
249
264
  }
250
265
  }
251
266
  }
252
- function ensurePendingStopHookCapture(captures, payload) {
253
- if (captures.getBySession(payload.sessionId))
267
+ function ensurePendingCapture(captures, params) {
268
+ if (captures.getBySession(params.sessionId))
254
269
  return;
255
270
  try {
256
271
  captures.savePending({
257
- sessionId: payload.sessionId,
258
- capturedAt: payload.stoppedAt,
259
- originatingTool: { name: payload.tool },
260
- capturePath: 'D',
272
+ sessionId: params.sessionId,
273
+ capturedAt: params.capturedAt,
274
+ originatingTool: { name: params.tool },
275
+ capturePath: params.capturePath,
261
276
  status: 'pending',
262
277
  spanCount: 0,
263
278
  durationMs: 0,
264
279
  redactedSpanCount: 0,
280
+ ...(params.repoRemoteUrl ? { repoRemoteUrl: params.repoRemoteUrl } : {}),
281
+ ...(params.repoCommitHash ? { repoCommitHash: params.repoCommitHash } : {}),
265
282
  });
266
283
  }
267
284
  catch (err) {
268
- if (!captures.getBySession(payload.sessionId))
285
+ if (!captures.getBySession(params.sessionId))
269
286
  throw err;
270
287
  }
271
288
  }
272
289
  async function ingestStopHookCapture(captures, receiver, payload) {
273
- ensurePendingStopHookCapture(captures, payload);
290
+ ensurePendingCapture(captures, {
291
+ sessionId: payload.sessionId,
292
+ capturedAt: payload.stoppedAt,
293
+ tool: payload.tool,
294
+ capturePath: 'D',
295
+ });
274
296
  if (!payload.transcriptPath)
275
297
  return;
276
298
  if (!receiver) {
@@ -484,11 +506,17 @@ async function bootstrap() {
484
506
  hint: 'Fund the listed address and re-run this command.',
485
507
  exampleCli: 'jinn fund-requirements --json',
486
508
  details: {
487
- role: 'master',
509
+ // jinn-mono-hjex.6: structured envelope so SPA can render the
510
+ // specific address + amount instead of a prose disjunction.
511
+ category: 'insufficient_funds',
512
+ step: 'awaiting_funding',
488
513
  address: result.funding.master_address,
514
+ requiredWei: result.funding.eth_required,
515
+ haveWei: result.funding.eth_balance,
516
+ // Legacy aliases kept for any external consumers that read these.
517
+ role: 'master',
489
518
  asset: 'native',
490
519
  needWei: result.funding.eth_required,
491
- haveWei: result.funding.eth_balance,
492
520
  },
493
521
  });
494
522
  }
@@ -503,11 +531,17 @@ async function bootstrap() {
503
531
  hint: 'Bootstrap failed before the fleet reached a runnable state.',
504
532
  details: {
505
533
  cause: result.message,
534
+ // jinn-mono-hjex.6: propagate structured category from the bootstrapper
535
+ // so the SPA can render category-specific UI (e.g. funding shortfall).
536
+ ...(result.errorCategory !== undefined ? { category: result.errorCategory } : {}),
506
537
  // Preserve the raw underlying error so a misclassified summary can
507
538
  // be diagnosed without re-running with JINN_DEBUG. See jinn-mono-jz9f.
508
539
  ...(result.rawErrorMessage && result.rawErrorMessage !== result.message
509
540
  ? { rawErrorMessage: result.rawErrorMessage }
510
541
  : {}),
542
+ // jinn-mono-hjex reviewer fix: propagate tx hash so the SPA can render
543
+ // a block-explorer link for failed on-chain revert transactions.
544
+ ...(result.txHash != null ? { txHash: result.txHash } : {}),
511
545
  },
512
546
  });
513
547
  }
@@ -592,7 +626,9 @@ class SetupBootstrapHalted extends Error {
592
626
  this.name = 'SetupBootstrapHalted';
593
627
  }
594
628
  }
595
- const keepSetupUiOnBootstrapError = () => process.env['JINN_NO_UI'] !== '1' && process.env['JINN_NO_DAEMON'] !== '1';
629
+ // hjex.6: gate for the halt-and-resume loop. Lives in ./setup/halt-mode.ts
630
+ // so it can be unit-tested without dragging main.ts's top-level side
631
+ // effects (password resolution, config load) into the test.
596
632
  // ── Main ────────────────────────────────────────────────────────────────────
597
633
  /**
598
634
  * --json-progress: emit NDJSON progress envelopes on stdout during long
@@ -651,6 +687,15 @@ export async function main() {
651
687
  else {
652
688
  logRpcLocalDevToStderr(rpcPreflight);
653
689
  }
690
+ // Boot-time RPC fallback-chain probe (issue #592, AC7 + AC9). Log-only —
691
+ // per-slot 429s/5xx never gate startup. checkRpcNetwork above already
692
+ // fail-loud on chain-id mismatch against the head provider.
693
+ await probeFallbackChain(config.rpcUrls, config.network, 'L2');
694
+ console.error(summarizeFallbackChain('L2', config.rpcUrls));
695
+ if (config.jinnClaimLoopEnabled && config.ethereumRpcUrls) {
696
+ await probeFallbackChain(config.ethereumRpcUrls, config.network, 'L1');
697
+ console.error(summarizeFallbackChain('L1', config.ethereumRpcUrls));
698
+ }
654
699
  const portPreflight = await checkApiPortAvailable(config.apiPort);
655
700
  if (!portPreflight.ok) {
656
701
  emitEnvelope({
@@ -679,6 +724,7 @@ export async function main() {
679
724
  // /v1/bootstrap + /v1/events + /v1/status here. The same Store instance is
680
725
  // later passed into Daemon so we don't double-open the SQLite file.
681
726
  const sharedStore = new Store(config.dbPath);
727
+ setDefaultTxSubmissionLedger(sharedStore);
682
728
  const capturesStore = new CapturesStore(sharedStore);
683
729
  let captureReceiver;
684
730
  try {
@@ -703,11 +749,56 @@ export async function main() {
703
749
  console.warn('[main] Capture OTLP receiver disabled; path-A telemetry capture unavailable: ' +
704
750
  `${err instanceof Error ? err.message : String(err)}`);
705
751
  }
752
+ let transcriptWatcher;
753
+ let pathBSyntheticSpanProvider;
754
+ const closePathBTranscriptWatcher = async () => {
755
+ const watcher = transcriptWatcher;
756
+ const provider = pathBSyntheticSpanProvider;
757
+ transcriptWatcher = undefined;
758
+ pathBSyntheticSpanProvider = undefined;
759
+ await Promise.all([
760
+ watcher?.shutdown().catch(() => undefined),
761
+ provider?.shutdown().catch(() => undefined),
762
+ ]);
763
+ };
706
764
  const closeCaptureReceiver = async () => {
765
+ await closePathBTranscriptWatcher();
707
766
  const receiver = captureReceiver;
708
767
  captureReceiver = undefined;
709
768
  await receiver?.shutdown().catch(() => undefined);
710
769
  };
770
+ if (captureReceiver) {
771
+ try {
772
+ const watchDirectories = defaultTranscriptWatchDirectories();
773
+ if (watchDirectories.length > 0) {
774
+ pathBSyntheticSpanProvider = startSyntheticSpanProvider({
775
+ otlpHttpEndpoint: `http://127.0.0.1:${captureReceiver.httpPort}/v1/traces`,
776
+ });
777
+ transcriptWatcher = await startTranscriptWatcher({
778
+ directories: watchDirectories,
779
+ onEvent: (envelope) => {
780
+ ensurePendingCapture(capturesStore, {
781
+ sessionId: envelope.sessionId,
782
+ capturedAt: new Date().toISOString(),
783
+ tool: envelope.tool,
784
+ capturePath: 'B',
785
+ });
786
+ emitSyntheticSpan(pathBSyntheticSpanProvider, envelope);
787
+ },
788
+ });
789
+ console.log('[main] Path-B transcript watcher started for ' +
790
+ watchDirectories.map((d) => `${d.tool}@${d.directory}`).join(', '));
791
+ }
792
+ else {
793
+ console.log('[main] Path-B transcript watcher skipped — no Codex/Claude session directories on disk yet');
794
+ }
795
+ }
796
+ catch (err) {
797
+ await closePathBTranscriptWatcher();
798
+ console.warn('[main] Path-B transcript watcher disabled: ' +
799
+ `${err instanceof Error ? err.message : String(err)}`);
800
+ }
801
+ }
711
802
  const capturePublishRef = { current: undefined };
712
803
  const earningStateStore = new FleetStateStore(config.earningDir);
713
804
  const initialFleet = await earningStateStore.tryLoadExisting();
@@ -759,6 +850,13 @@ export async function main() {
759
850
  // builder-artifacts. Holder ref lets the routes register eagerly and
760
851
  // start returning real data the moment main.ts assigns holder.current.
761
852
  const discoveryApiHolder = { current: undefined };
853
+ // hjex.6: retry signal for the bootstrap halt-and-resume loop.
854
+ // When a SetupBootstrapHalted is caught (fatal non-funding error or funding
855
+ // timeout), main() waits on this promise instead of returning, so the setup
856
+ // API stays alive and the operator can click Retry in the SPA.
857
+ // The retry endpoint resolves this promise to trigger a re-run.
858
+ let retryBootstrapResolve = null;
859
+ let retryBootstrapReject = null;
762
860
  let setupApiServer;
763
861
  try {
764
862
  setupApiServer = await startApiServer({
@@ -772,11 +870,30 @@ export async function main() {
772
870
  hermesPath: config.hermesPath,
773
871
  hermesDoctorTimeoutMs: config.hermesDoctorTimeoutMs,
774
872
  },
873
+ codexDoctor: {
874
+ codexPath: config.codexPath,
875
+ codexDoctorTimeoutMs: config.codexDoctorTimeoutMs,
876
+ },
775
877
  admin: {
776
- onRestartRequested: () => {
777
- console.log('[main] Restart requested via operator MCP. Exiting...');
778
- process.exit(0);
779
- },
878
+ // jinn-mono #289: in interactive mode (the dashboard SPA case),
879
+ // spawn a detached replacement before exiting so the panel reconnects
880
+ // to a live daemon instead of seeing a 502 + terminal prompt. In
881
+ // headless mode (`JINN_NO_UI=1`), exit without respawning so the
882
+ // supervisor / systemd / docker entrypoint decides what to do.
883
+ // Stop: pure exit, never respawn. The operator clicked Stop; they
884
+ // want the daemon down until they explicitly start it again.
885
+ onStopRequested: () => process.exit(0),
886
+ onRestartRequested: (opts) => requestDaemonRestart({
887
+ forceRespawn: opts.forceRespawn,
888
+ // jinn-mono #561: close the API + OTLP listeners before the
889
+ // replacement spawns, so the child binds without an
890
+ // EADDRINUSE race. Errors are swallowed inside
891
+ // requestDaemonRestart so the operator is never stranded.
892
+ preSpawnCleanup: async () => {
893
+ await setupApiServer.close().catch(() => undefined);
894
+ await closeCaptureReceiver();
895
+ },
896
+ }),
780
897
  },
781
898
  harnessStatus: {
782
899
  getStatus: async () => {
@@ -830,7 +947,6 @@ export async function main() {
830
947
  configReader: () => ({
831
948
  rpcUrl: config.rpcUrl,
832
949
  defaultRpcUrl: CHAIN_CONFIG.rpcUrl,
833
- solverNets: config.solverNets,
834
950
  joinedSolverNets: config.joinedSolverNets,
835
951
  }),
836
952
  },
@@ -953,19 +1069,42 @@ export async function main() {
953
1069
  configPath: CONFIG_PATH ?? DEFAULT_CONFIG_PATH,
954
1070
  defaultRpcUrlForChain: () => CHAIN_CONFIG.rpcUrl,
955
1071
  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)
1072
+ // Issue #421 retired the legacy `solverNets` write target. Setup
1073
+ // endpoints no longer call back into the daemon to mutate operator
1074
+ // SolverNet config; the canonical join flow is
1075
+ // `POST /v1/operator/join/:cid`, which mutates
1076
+ // `config.joinedSolverNets` directly via its own write path.
1077
+ // The cache-invalidation hook is no longer needed here.
1078
+ onSolverNetsUpdated: () => {
963
1079
  invalidatePredictionOperatorStatusCache(config);
964
1080
  },
1081
+ // hjex.6: re-trigger the bootstrap state machine from the SPA Retry button.
1082
+ // Resolves the halt-and-resume promise; main() will loop back and call
1083
+ // bootstrap() again. Rejects if the daemon is not currently halted.
1084
+ retryBootstrap: () => {
1085
+ return new Promise((resolve, reject) => {
1086
+ if (!retryBootstrapResolve) {
1087
+ reject(new Error('daemon_not_halted'));
1088
+ return;
1089
+ }
1090
+ const prevResolve = retryBootstrapResolve;
1091
+ // The resolve will unblock the main loop's await. When bootstrap
1092
+ // completes (success or new halt), the caller receives the result
1093
+ // via the /v1/bootstrap polling endpoint.
1094
+ prevResolve();
1095
+ resolve();
1096
+ });
1097
+ },
965
1098
  },
966
1099
  status: {
967
1100
  earningDir: config.earningDir,
968
1101
  rpcUrl: config.rpcUrl,
1102
+ // tJINN identity comes from the bundled JINN MVI L1 artifact
1103
+ // (`JINN_MVI_CONFIG`) — one source of truth. The Sepolia RPC endpoint
1104
+ // is read from `config.ethereumRpcUrl` via the threaded `config`.
1105
+ tjinnTokenAddress: JINN_MVI_CONFIG.jinn,
1106
+ tjinnChainId: JINN_MVI_CONFIG.l1ChainId,
1107
+ tjinnDistributorAddress: JINN_MVI_CONFIG.distributor,
969
1108
  network: config.network,
970
1109
  pollIntervalMs: config.pollIntervalMs,
971
1110
  masterEthDailyEstimateWei: config.masterEthDailyEstimateWei,
@@ -1000,29 +1139,30 @@ export async function main() {
1000
1139
  // TODO(jinn-mono launcher Task 8): real `getReservedBudgetWei`
1001
1140
  // (sum of unconsumed claim payments across open Tasks).
1002
1141
  launcher: {
1003
- getConfig: () => ({ solverNets: config.solverNets }),
1142
+ getConfig: () => ({ joinedSolverNets: config.joinedSolverNets }),
1004
1143
  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;
1144
+ // Issue #421 retired the legacy `solverNets` write target. The hook
1145
+ // only needs to invalidate the prediction-operator status cache when
1146
+ // operator mode mutates joinedSolverNets via setup endpoints.
1147
+ onSolverNetsUpdated: () => {
1011
1148
  invalidatePredictionOperatorStatusCache(config);
1012
1149
  },
1013
1150
  getGeneratorState: (netName) => {
1014
1151
  if (netName === 'prediction') {
1015
1152
  return predictionGeneratorRef?.getState();
1016
1153
  }
1017
- const solverType = config.solverNets?.[netName]?.solverType;
1154
+ const joined = findJoinedByName(config.joinedSolverNets, netName);
1155
+ const solverType = joined ? solverTypeFromJoinedContract(joined) : undefined;
1018
1156
  if (!solverType)
1019
1157
  return undefined;
1020
1158
  return launchedGeneratorStateBySolverType.get(solverType)?.();
1021
1159
  },
1022
1160
  getOpenTaskCount: (netName) => {
1023
- const net = config.solverNets?.[netName];
1024
- const solverType = net?.solverType;
1025
- if (!solverType || !safeAddressForLauncher)
1161
+ if (!safeAddressForLauncher)
1162
+ return 0;
1163
+ const joined = findJoinedByName(config.joinedSolverNets, netName);
1164
+ const solverType = joined ? solverTypeFromJoinedContract(joined) : undefined;
1165
+ if (!solverType)
1026
1166
  return 0;
1027
1167
  return sharedStore.countPostedTasksByCreatorAndSolverType({
1028
1168
  creatorSafeAddress: safeAddressForLauncher,
@@ -1114,30 +1254,41 @@ export async function main() {
1114
1254
  // can attach to a long-lived embedded `claude` subprocess. The embedded
1115
1255
  // session reads MCP config we materialise to disk so it can reach the
1116
1256
  // 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'],
1257
+ //
1258
+ // Issue #326: the embedded agent chat surface is hidden by default. The WS
1259
+ // bridge mounts only when `JINN_ENABLE_EMBEDDED_AGENT=1` so the dev-time
1260
+ // path stays end-to-end; with the flag off there is no /api/agent/ws route
1261
+ // and the SPA never renders the chat panel. Claude-Code-as-solver-harness
1262
+ // is independent of this bridge and unaffected.
1263
+ if (embeddedAgentEnabled) {
1264
+ const operatorMcpConfigPath = join(homedir(), '.jinn-client', 'operator-mcp-config.json');
1265
+ try {
1266
+ mkdirSync(dirname(operatorMcpConfigPath), { recursive: true });
1267
+ writeFileSyncMain(operatorMcpConfigPath, JSON.stringify({
1268
+ mcpServers: {
1269
+ 'jinn-operator': {
1270
+ command: 'jinn',
1271
+ args: ['mcp'],
1272
+ },
1125
1273
  },
1126
- },
1127
- }, null, 2));
1274
+ }, null, 2));
1275
+ }
1276
+ catch (err) {
1277
+ console.warn(`[main] Failed to write operator MCP config at ${operatorMcpConfigPath}: ` +
1278
+ (err instanceof Error ? err.message : String(err)));
1279
+ }
1280
+ attachAgentWs({
1281
+ httpServer: setupApiServer.server,
1282
+ uiToken,
1283
+ claudePath: activeClaudePath,
1284
+ cwd: process.cwd(),
1285
+ mcpConfigPath: operatorMcpConfigPath,
1286
+ });
1287
+ console.log(`[main] Agent WS bridge mounted at ws://127.0.0.1:${setupApiServer.port}/api/agent/ws`);
1128
1288
  }
1129
- catch (err) {
1130
- console.warn(`[main] Failed to write operator MCP config at ${operatorMcpConfigPath}: ` +
1131
- (err instanceof Error ? err.message : String(err)));
1289
+ else {
1290
+ console.log('[main] Embedded agent surface disabled (set JINN_ENABLE_EMBEDDED_AGENT=1 to enable).');
1132
1291
  }
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
1292
  // ── Init-if-missing ──────────────────────────────────────────────────────
1142
1293
  // If the keystore is missing but we have a password, run `jinn init` now so
1143
1294
  // bootstrap has something to decrypt. Idempotent: init is a no-op when the
@@ -1178,30 +1329,96 @@ export async function main() {
1178
1329
  // keystore is on disk and we're transitioning into bootstrap.
1179
1330
  setupController.refresh({ keystoreExists: true, allComplete: false });
1180
1331
  }
1332
+ // hjex.6: halt-and-resume loop for bootstrap retries.
1333
+ // When failBootstrap() throws SetupBootstrapHalted, we wait for the operator
1334
+ // to click Retry in the SPA (which resolves retryBootstrapResolve) rather
1335
+ // than returning and exiting. On each retry, we loop back and call bootstrap()
1336
+ // again. bootstrap() is idempotent — completed steps are no-ops.
1181
1337
  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
- };
1338
+ // eslint-disable-next-line no-constant-condition
1339
+ while (true) {
1340
+ try {
1341
+ bootstrapResult = await bootstrap();
1342
+ break; // success exit the retry loop
1343
+ }
1344
+ catch (err) {
1345
+ if (err instanceof SetupBootstrapHalted) {
1346
+ // Install the retry signal so the endpoint can unblock us.
1347
+ const retrySignal = new Promise((resolve, reject) => {
1348
+ retryBootstrapResolve = resolve;
1349
+ retryBootstrapReject = reject;
1350
+ });
1351
+ console.log('[main] Bootstrap halted. Waiting for retry signal from the dashboard...');
1352
+ // hjex.6: Auto-resume funding poller.
1353
+ // When the halt is a funding shortfall, poll the master EOA balance
1354
+ // every JINN_FUNDING_POLL_INTERVAL_MS (default 15s). When the balance
1355
+ // meets or exceeds the required amount, auto-signal the retry loop.
1356
+ // Only runs while the halt signal is pending; stops on any signal.
1357
+ let fundingPollHandle = null;
1358
+ const isHaltedOnFunding = err.envelope.code === 'funding_required';
1359
+ const haltDetails = err.envelope.details;
1360
+ const haltAddress = typeof haltDetails?.['address'] === 'string'
1361
+ ? haltDetails['address']
1362
+ : null;
1363
+ const haltRequired = typeof haltDetails?.['requiredWei'] === 'string'
1364
+ ? BigInt(haltDetails['requiredWei'])
1365
+ : typeof haltDetails?.['needWei'] === 'string'
1366
+ ? BigInt(haltDetails['needWei'])
1367
+ : null;
1368
+ const fundingPollIntervalMs = (() => {
1369
+ const raw = process.env['JINN_FUNDING_POLL_INTERVAL_MS'];
1370
+ if (!raw)
1371
+ return 15_000;
1372
+ const n = Number.parseInt(raw, 10);
1373
+ return Number.isFinite(n) && n > 0 ? n : 15_000;
1374
+ })();
1375
+ if (isHaltedOnFunding && haltAddress && haltRequired !== null) {
1376
+ const publicClient = createJinnPublicClient(config.rpcUrls, NETWORK_CHAIN);
1377
+ const schedulePoll = () => {
1378
+ fundingPollHandle = setTimeout(async () => {
1379
+ // Guard: if the signal was already fired, stop polling.
1380
+ if (!retryBootstrapResolve)
1381
+ return;
1382
+ try {
1383
+ const balance = await publicClient.getBalance({ address: haltAddress });
1384
+ if (balance >= haltRequired) {
1385
+ console.log(`[main] Funding shortfall cleared (have ${balance}, required ${haltRequired}). ` +
1386
+ `Auto-resuming bootstrap...`);
1387
+ retryBootstrapResolve?.();
1388
+ return; // don't schedule the next poll
1389
+ }
1390
+ }
1391
+ catch (pollErr) {
1392
+ // Balance read failed — not fatal, just skip this tick.
1393
+ const msg = pollErr instanceof Error ? pollErr.message : String(pollErr);
1394
+ console.log(`[main] Funding poller balance read failed (will retry): ${msg}`);
1395
+ }
1396
+ schedulePoll(); // reschedule
1397
+ }, fundingPollIntervalMs);
1398
+ };
1399
+ schedulePoll();
1400
+ }
1401
+ try {
1402
+ await retrySignal;
1403
+ }
1404
+ finally {
1405
+ retryBootstrapResolve = null;
1406
+ retryBootstrapReject = null;
1407
+ if (fundingPollHandle !== null) {
1408
+ clearTimeout(fundingPollHandle);
1409
+ fundingPollHandle = null;
1410
+ }
1411
+ }
1412
+ console.log('[main] Retry triggered — re-running bootstrap...');
1413
+ continue; // loop back to the bootstrap() call
1414
+ }
1415
+ // If bootstrap throws an unexpected error (vs. SetupBootstrapHalted),
1416
+ // tear down the API we just started so we don't leave a dangling listener.
1417
+ await setupApiServer.close().catch(() => undefined);
1418
+ await closeCaptureReceiver();
1419
+ sharedStore.close();
1420
+ throw err;
1198
1421
  }
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
1422
  }
1206
1423
  // Bootstrap completed — flip the controller into 'running' so any waiters
1207
1424
  // (future loops gated on this) unblock.
@@ -1254,9 +1471,9 @@ export async function main() {
1254
1471
  const earningStore = new FleetStateStore(config.earningDir);
1255
1472
  const mnemonicForMaster = await decryptMnemonic(await earningStore.loadMnemonicKeystore(), PASSWORD);
1256
1473
  const masterAccount = deriveMasterSigner(mnemonicForMaster);
1257
- const publicClient = createJinnPublicClient(config.rpcUrl, NETWORK_CHAIN);
1474
+ const publicClient = createJinnPublicClient(config.rpcUrls, NETWORK_CHAIN);
1258
1475
  publicClientForLauncher = publicClient;
1259
- const masterWallet = createJinnWalletClient(config.rpcUrl, NETWORK_CHAIN, masterAccount);
1476
+ const masterWallet = createJinnWalletClient(config.rpcUrls, NETWORK_CHAIN, masterAccount);
1260
1477
  const evictionRecovery = config.stakingMode === 'standard' &&
1261
1478
  serviceId !== null &&
1262
1479
  stakingAddress &&
@@ -1315,7 +1532,7 @@ export async function main() {
1315
1532
  // the /build page rendered "Discovery unavailable" permanently.
1316
1533
  discoveryApiHolder.current = sharedDiscoveryApi;
1317
1534
  const adapter = new MechAdapter({
1318
- rpcUrl: config.rpcUrl,
1535
+ rpcUrl: config.rpcUrls,
1319
1536
  mechMarketplaceAddress: MARKETPLACE_ADDRESS,
1320
1537
  routerAddress: ROUTER_ADDRESS,
1321
1538
  mechContractAddress: mechAddress,
@@ -1331,12 +1548,18 @@ export async function main() {
1331
1548
  ? {
1332
1549
  discoveryApi: sharedDiscoveryApi,
1333
1550
  solverNetManifestCids: taskDiscoveryManifestCids,
1334
- // No explicit `onchainFromBlock` — let `MechAdapter`'s
1551
+ // No explicit `onchainFromBlock` by default — let `MechAdapter`'s
1335
1552
  // `DEFAULT_TASK_DISCOVERY_FROM_BLOCK` per-chain default flow
1336
1553
  // through. Hardcoding here shadowed the adapter's default and
1337
1554
  // re-introduced the ghost-task floor every release; removing the
1338
1555
  // shadow makes `adapter.ts` the single source of truth. See gh
1339
- // #300.
1556
+ // #300. An operator MAY opt in to a recent floor via
1557
+ // `taskDiscoveryOnchainFromBlock` to bound the canonical getLogs
1558
+ // scan (which otherwise parses a large history on the main thread
1559
+ // and can stall the loop) and lean on the indexer DiscoveryAPI.
1560
+ ...(config.taskDiscoveryOnchainFromBlock !== undefined
1561
+ ? { onchainFromBlock: config.taskDiscoveryOnchainFromBlock }
1562
+ : {}),
1340
1563
  ...(config.taskDiscoveryAllowedTaskIds?.length
1341
1564
  ? { allowedTaskIds: config.taskDiscoveryAllowedTaskIds }
1342
1565
  : {}),
@@ -1353,26 +1576,52 @@ export async function main() {
1353
1576
  const agentChainContracts = agentChain.contracts;
1354
1577
  const optimismPortalAddress = agentChainContracts?.portal?.[l1Chain.id]?.address;
1355
1578
  const disputeGameFactoryAddress = agentChainContracts?.disputeGameFactory?.[l1Chain.id]?.address;
1356
- const l2ProofClient = config.l2ProofRpcUrl
1357
- ? createJinnPublicClient(config.l2ProofRpcUrl, NETWORK_CHAIN)
1579
+ const l2ProofClient = config.l2ProofRpcUrls
1580
+ ? createJinnPublicClient(config.l2ProofRpcUrls, NETWORK_CHAIN)
1358
1581
  : undefined;
1359
- const agentClients = createClients(config.rpcUrl, agentPrivateKey, agentChain);
1582
+ const agentClients = createClients(config.rpcUrls, agentPrivateKey, agentChain);
1360
1583
  // ── L1 (Sepolia / Ethereum mainnet) clients for cross-chain JINN claim loop ──
1361
1584
  // Uses the agent EOA because MockMessenger.owner is the agent on testnet.
1362
1585
  // Same key as L2; only the chain differs.
1363
- const l1ClientsForJinnClaim = JINN_MVI_CONFIG.distributor && config.ethereumRpcUrl
1586
+ const shouldWireJinnClaimL1 = shouldWireJinnClaimL1Signer({
1587
+ enabled: config.jinnClaimLoopEnabled,
1588
+ intervalMs: config.jinnClaimLoopIntervalMs,
1589
+ submissionMode: config.jinnClaimSubmissionMode,
1590
+ distributorAddress: JINN_MVI_CONFIG.distributor,
1591
+ ethereumRpcUrl: config.ethereumRpcUrl,
1592
+ });
1593
+ const l1ClientsForJinnClaim = shouldWireJinnClaimL1 && config.ethereumRpcUrls
1364
1594
  ? {
1365
- public: createJinnL1PublicClient(config.ethereumRpcUrl, config.jinnL1Network),
1366
- wallet: createJinnL1WalletClient(config.ethereumRpcUrl, config.jinnL1Network, privateKeyToAccount(agentPrivateKey)),
1595
+ public: createJinnL1PublicClient(config.ethereumRpcUrls, config.jinnL1Network),
1596
+ wallet: createJinnL1WalletClient(config.ethereumRpcUrls, config.jinnL1Network, privateKeyToAccount(agentPrivateKey)),
1367
1597
  }
1368
1598
  : undefined;
1369
- if (l1ClientsForJinnClaim) {
1370
- console.log(`[main] JinnClaimLoop: enabled (mode=${JINN_CLAIM_MESSENGER_MODE}, ` +
1599
+ const jinnClaimLoopConfig = buildJinnClaimLoopConfig({
1600
+ enabled: config.jinnClaimLoopEnabled,
1601
+ intervalMs: config.jinnClaimLoopIntervalMs,
1602
+ submissionMode: config.jinnClaimSubmissionMode,
1603
+ messengerMode: JINN_CLAIM_MESSENGER_MODE,
1604
+ mvi: JINN_MVI_CONFIG,
1605
+ l2Client: agentClients.publicClient,
1606
+ l2ProofClient,
1607
+ l2Wallet: agentClients.walletClient,
1608
+ l1Clients: l1ClientsForJinnClaim,
1609
+ store: earningStore,
1610
+ chain: NETWORK_CHAIN,
1611
+ optimismPortalAddress,
1612
+ disputeGameFactoryAddress,
1613
+ });
1614
+ if (jinnClaimLoopConfig) {
1615
+ console.log(`[main] JinnClaimLoop: enabled (submission=${config.jinnClaimSubmissionMode}, ` +
1616
+ `mode=${JINN_CLAIM_MESSENGER_MODE}, ` +
1371
1617
  `interval=${config.jinnClaimLoopIntervalMs}ms, distributor=${JINN_MVI_CONFIG.distributor}, ` +
1372
1618
  `emitter=${JINN_MVI_CONFIG.claimEmitter})`);
1373
1619
  }
1620
+ else if (!config.jinnClaimLoopEnabled) {
1621
+ console.log('[main] JinnClaimLoop: disabled (jinnClaimLoopEnabled=false)');
1622
+ }
1374
1623
  else {
1375
- console.log(`[main] JinnClaimLoop: disabled (JinnDistributor artifact/override or JINN_ETHEREUM_RPC_URL not set)`);
1624
+ console.log(`[main] JinnClaimLoop: disabled (missing claim-loop artifacts, interval disabled, or L1 submit wiring)`);
1376
1625
  }
1377
1626
  // ── Harness registry ─────────────────────────────────────────────────────────
1378
1627
  const solverNetRegistry = await loadSolverNets(config);
@@ -1464,6 +1713,9 @@ export async function main() {
1464
1713
  hermesPath: config.hermesPath,
1465
1714
  hermesModel: config.hermesModel,
1466
1715
  hermesProvider: config.hermesProvider,
1716
+ hermesDoctorTimeoutMs: config.hermesDoctorTimeoutMs,
1717
+ codexPath: config.codexPath,
1718
+ codexDoctorTimeoutMs: config.codexDoctorTimeoutMs,
1467
1719
  })) {
1468
1720
  implRegistry.register(impl);
1469
1721
  }
@@ -1733,11 +1985,19 @@ export async function main() {
1733
1985
  if (!safeAddressForLauncher) {
1734
1986
  throw new Error('[main] safeAddressForLauncher missing at SolverNet endpoints registration');
1735
1987
  }
1988
+ const getGeneratorState = (solverNetId) => {
1989
+ const entry = pendingGeneratorsRef.current.find((g) => g.recordRef.current.solverNetId === solverNetId);
1990
+ const resolved = resolveContractFromSolverNetId(entry?.recordRef.current.solverNetId ?? solverNetId);
1991
+ if (!resolved)
1992
+ return undefined;
1993
+ return launchedGeneratorStateBySolverType.get(resolved.solverType)?.();
1994
+ };
1736
1995
  solverNetEndpointsDepsHolder.current = {
1737
1996
  store: solverNetStore,
1738
1997
  launch: {
1739
1998
  launchAction,
1740
1999
  lifecycleTransition,
2000
+ getGeneratorState,
1741
2001
  pendingGenerators: pendingGeneratorsRef,
1742
2002
  signer: launcherSigner,
1743
2003
  network: 'base-sepolia',
@@ -1794,6 +2054,7 @@ export async function main() {
1794
2054
  agentEoa: agentEoaAddress,
1795
2055
  safeAddress,
1796
2056
  agentPrivateKey,
2057
+ ...(sharedDiscoveryApi ? { discoveryApi: sharedDiscoveryApi } : {}),
1797
2058
  },
1798
2059
  logger: {
1799
2060
  info: (message) => console.log(message),
@@ -1812,9 +2073,23 @@ export async function main() {
1812
2073
  if (config.network === 'mainnet' && !autoTasksDisabled && BASE_FEEDS['ETH / USD']) {
1813
2074
  // Mainnet auto-task opt-in only; default is OFF. Reserved for a future flag.
1814
2075
  }
2076
+ // filterBindableTasks (issue #415): drop config-level tasks[] entries without
2077
+ // solverNetManifestCid before they enter the creator loop. Such entries would
2078
+ // throw a PermanentError on every attempt and retry every 30 min indefinitely.
2079
+ const bindableConfigTasks = filterBindableTasks(config.tasks);
1815
2080
  const taskSources = [
1816
- new StaticConfiguredTaskSource(config.tasks),
1817
- ...launchedRecordGenerators.map(({ solverType, generator }, idx) => new GeneratedTaskSource(`launched:${solverType}:${idx}`, generator)),
2081
+ new StaticConfiguredTaskSource(bindableConfigTasks),
2082
+ ...launchedRecordGenerators.map(({ solverType, generator }, idx) => new GeneratedTaskSource(`launched:${solverType}:${idx}`, generator, {
2083
+ bucketKeyForTask: (task) => {
2084
+ if (task.solverType !== 'swe-rebench-v2.v1')
2085
+ return undefined;
2086
+ const instanceId = task.spec?.['instance_id'];
2087
+ const postedCount = task.eligibility?.['posted_count_after_record'];
2088
+ if (typeof instanceId !== 'string' || typeof postedCount !== 'number')
2089
+ return undefined;
2090
+ return `swe-rebench-v2:${instanceId}:${postedCount}`;
2091
+ },
2092
+ })),
1818
2093
  ];
1819
2094
  // ── Corpus (daemon-side, jinn-mono-vy37.1.6) ─────────────────────────────
1820
2095
  //
@@ -1847,6 +2122,7 @@ export async function main() {
1847
2122
  console.warn('[main] Corpus disabled (no DiscoveryAPI or on-chain identity registry); ' +
1848
2123
  'MCP record lookup and artifact acquisition network branches will be unavailable.');
1849
2124
  }
2125
+ const spendCap = buildSpendCapConfig(config, process.env);
1850
2126
  const daemon = new Daemon({
1851
2127
  adapter,
1852
2128
  runner,
@@ -1863,9 +2139,21 @@ export async function main() {
1863
2139
  creatorSafeAddress: safeAddress,
1864
2140
  corpusFactory,
1865
2141
  harnessReadinessRegistry,
2142
+ spendCap,
1866
2143
  status: {
1867
2144
  earningDir: config.earningDir,
1868
2145
  rpcUrl: config.rpcUrl,
2146
+ // tJINN identity comes from the bundled JINN MVI L1 artifact
2147
+ // (`JINN_MVI_CONFIG`) — one source of truth. The Sepolia RPC endpoint
2148
+ // is read from `config.ethereumRpcUrl` via the threaded `config`.
2149
+ tjinnTokenAddress: JINN_MVI_CONFIG.jinn,
2150
+ tjinnChainId: JINN_MVI_CONFIG.l1ChainId,
2151
+ tjinnDistributorAddress: JINN_MVI_CONFIG.distributor,
2152
+ // stOLAS L2 distributor — mirrors `CHAIN_CONFIG.distributorAddress`
2153
+ // used to gate the EvictionLoop (issue #651). Threaded through so the
2154
+ // SPA's autoRestake predicate keys off the same on-chain artifact as
2155
+ // the daemon's `evictionCheck` predicate (~line 2520 below).
2156
+ stOlasDistributorAddress: CHAIN_CONFIG.distributorAddress,
1869
2157
  network: config.network,
1870
2158
  pollIntervalMs: config.pollIntervalMs,
1871
2159
  masterEthDailyEstimateWei: config.masterEthDailyEstimateWei,
@@ -1877,6 +2165,7 @@ export async function main() {
1877
2165
  engine: config.engine,
1878
2166
  config,
1879
2167
  configPath: CONFIG_PATH ?? DEFAULT_CONFIG_PATH,
2168
+ spendCaps: spendCap?.caps,
1880
2169
  },
1881
2170
  rewardClaim: config.rewardClaimIntervalMs > 0
1882
2171
  ? {
@@ -1888,28 +2177,7 @@ export async function main() {
1888
2177
  distributorAddress: CHAIN_CONFIG.distributorAddress,
1889
2178
  }
1890
2179
  : 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,
2180
+ jinnClaim: jinnClaimLoopConfig,
1913
2181
  restorationEngine: {
1914
2182
  paths: {
1915
2183
  workingDirRoot: config.engine.workingDirRoot,
@@ -1954,11 +2222,71 @@ export async function main() {
1954
2222
  safeTopupTarget: CHAIN_CONFIG.minSafeEth,
1955
2223
  }
1956
2224
  : undefined,
2225
+ // Eviction-check loop — only in standard staking mode (requires distributorAddress).
2226
+ // Running mode only: setup-halted daemons must not try to restake services that
2227
+ // haven't been staked yet (hjex.3).
2228
+ evictionCheck: config.evictionCheckIntervalMs > 0 &&
2229
+ config.stakingMode === 'standard' &&
2230
+ CHAIN_CONFIG.distributorAddress
2231
+ ? {
2232
+ intervalMs: config.evictionCheckIntervalMs,
2233
+ store: earningStore,
2234
+ chain: NETWORK_CHAIN,
2235
+ readContract: (opts) => publicClient.readContract(opts),
2236
+ recoverEvictedService: async (svc) => {
2237
+ if (!svc.service_id || !svc.staking_address)
2238
+ return;
2239
+ await recoverEvictedServiceFn({
2240
+ serviceDisplayIndex: Math.max(0, svc.index - 1),
2241
+ serviceId: svc.service_id,
2242
+ stakingAddress: svc.staking_address,
2243
+ distributorAddress: CHAIN_CONFIG.distributorAddress,
2244
+ rpcUrl: config.rpcUrl,
2245
+ chain: NETWORK_CHAIN,
2246
+ mnemonic: mnemonicForMaster,
2247
+ });
2248
+ },
2249
+ }
2250
+ : undefined,
2251
+ // Checkpoint loop — proactively advances `tsCheckpoint` on each staked
2252
+ // proxy so the activity-rate window stays narrow (issue #505).
2253
+ // `checkpoint()` is permissionless; master EOA pays gas. No-op for
2254
+ // non-standard staking modes.
2255
+ checkpoint: config.checkpointIntervalMs > 0 && config.stakingMode === 'standard'
2256
+ ? {
2257
+ intervalMs: config.checkpointIntervalMs,
2258
+ store: earningStore,
2259
+ chain: NETWORK_CHAIN,
2260
+ writeCheckpoint: async ({ stakingProxy }) => {
2261
+ const txHash = await masterWallet.writeContract({
2262
+ address: stakingProxy,
2263
+ abi: [
2264
+ {
2265
+ type: 'function',
2266
+ name: 'checkpoint',
2267
+ stateMutability: 'nonpayable',
2268
+ inputs: [],
2269
+ outputs: [],
2270
+ },
2271
+ ],
2272
+ functionName: 'checkpoint',
2273
+ account: masterAccount,
2274
+ chain: null,
2275
+ });
2276
+ return { txHash };
2277
+ },
2278
+ }
2279
+ : undefined,
1957
2280
  });
1958
- // Write pidfile so `jinn stop` can find us.
2281
+ // Write pidfile so `jinn stop` can find us. First, refuse the run if another
2282
+ // daemon already owns this earning directory — see issue #649. The gate
2283
+ // handles all three branches (refuse-and-exit, unlink-stale-and-continue,
2284
+ // proceed); the writeFileSync below MUST stay outside the helper so the
2285
+ // "// DO NOT add store mutations above this line — see #649" invariant is
2286
+ // visible right here at the call site.
1959
2287
  const pidPath = join(config.earningDir, 'daemon.pid');
1960
- const { writeFileSync, unlinkSync } = await import('node:fs');
1961
- writeFileSync(pidPath, String(process.pid) + '\n', 'utf-8');
2288
+ applyPidfileLivenessGate(pidPath);
2289
+ writeFileSyncMain(pidPath, String(process.pid) + '\n', 'utf-8');
1962
2290
  const removePidfile = () => {
1963
2291
  try {
1964
2292
  unlinkSync(pidPath);