@jinn-network/client 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/deployments/deployment-jinn-mvi-l1-sepolia-fast.json +23 -4
  3. package/deployments/deployment-jinn-mvi-l1-sepolia.json +23 -4
  4. package/deployments/deployment-jinn-mvi-l2-baseSepolia.json +5 -4
  5. package/dist/adapters/mech/adapter.d.ts +38 -1
  6. package/dist/adapters/mech/adapter.js +241 -54
  7. package/dist/adapters/mech/adapter.js.map +1 -1
  8. package/dist/adapters/mech/contracts.d.ts +17 -4
  9. package/dist/adapters/mech/contracts.js +8 -2
  10. package/dist/adapters/mech/contracts.js.map +1 -1
  11. package/dist/adapters/mech/safe-revert.d.ts +20 -0
  12. package/dist/adapters/mech/safe-revert.js +12 -4
  13. package/dist/adapters/mech/safe-revert.js.map +1 -1
  14. package/dist/adapters/mech/safe.d.ts +5 -1
  15. package/dist/adapters/mech/safe.js +27 -8
  16. package/dist/adapters/mech/safe.js.map +1 -1
  17. package/dist/adapters/mech/verdict-code.d.ts +1 -0
  18. package/dist/adapters/mech/verdict-code.js +18 -0
  19. package/dist/adapters/mech/verdict-code.js.map +1 -1
  20. package/dist/api/admin-endpoint.d.ts +15 -3
  21. package/dist/api/admin-endpoint.js +24 -2
  22. package/dist/api/admin-endpoint.js.map +1 -1
  23. package/dist/api/bootstrap-endpoint.js +49 -0
  24. package/dist/api/bootstrap-endpoint.js.map +1 -1
  25. package/dist/api/codex-doctor-endpoint.d.ts +73 -0
  26. package/dist/api/codex-doctor-endpoint.js +177 -0
  27. package/dist/api/codex-doctor-endpoint.js.map +1 -0
  28. package/dist/api/discovery-endpoint.d.ts +1 -0
  29. package/dist/api/discovery-endpoint.js +26 -0
  30. package/dist/api/discovery-endpoint.js.map +1 -1
  31. package/dist/api/fleet-build.d.ts +1 -0
  32. package/dist/api/fleet-build.js +2 -1
  33. package/dist/api/fleet-build.js.map +1 -1
  34. package/dist/api/gather-status.d.ts +11 -0
  35. package/dist/api/gather-status.js +400 -4
  36. package/dist/api/gather-status.js.map +1 -1
  37. package/dist/api/hermes-doctor-endpoint.d.ts +117 -0
  38. package/dist/api/hermes-doctor-endpoint.js +229 -23
  39. package/dist/api/hermes-doctor-endpoint.js.map +1 -1
  40. package/dist/api/launcher-status.d.ts +21 -16
  41. package/dist/api/launcher-status.js +2 -1
  42. package/dist/api/launcher-status.js.map +1 -1
  43. package/dist/api/portfolio-v0-build.d.ts +10 -0
  44. package/dist/api/portfolio-v0-build.js +24 -5
  45. package/dist/api/portfolio-v0-build.js.map +1 -1
  46. package/dist/api/prediction-v1-build.d.ts +10 -0
  47. package/dist/api/prediction-v1-build.js +7 -1
  48. package/dist/api/prediction-v1-build.js.map +1 -1
  49. package/dist/api/server.d.ts +31 -1
  50. package/dist/api/server.js +68 -1
  51. package/dist/api/server.js.map +1 -1
  52. package/dist/api/setup-endpoints.d.ts +16 -0
  53. package/dist/api/setup-endpoints.js +78 -4
  54. package/dist/api/setup-endpoints.js.map +1 -1
  55. package/dist/api/setup-retry-endpoint.d.ts +19 -0
  56. package/dist/api/setup-retry-endpoint.js +32 -0
  57. package/dist/api/setup-retry-endpoint.js.map +1 -0
  58. package/dist/api/solvernets-endpoints.d.ts +8 -0
  59. package/dist/api/solvernets-endpoints.js +71 -43
  60. package/dist/api/solvernets-endpoints.js.map +1 -1
  61. package/dist/api/status-build.d.ts +72 -0
  62. package/dist/api/status-build.js +73 -18
  63. package/dist/api/status-build.js.map +1 -1
  64. package/dist/api/task-run-routing.d.ts +7 -0
  65. package/dist/api/task-run-routing.js +12 -0
  66. package/dist/api/task-run-routing.js.map +1 -0
  67. package/dist/api/task-runs-build.d.ts +21 -0
  68. package/dist/api/task-runs-build.js +14 -1
  69. package/dist/api/task-runs-build.js.map +1 -1
  70. package/dist/build-info.json +4 -4
  71. package/dist/build-meta.json +1 -1
  72. package/dist/chain-read-errors.d.ts +10 -0
  73. package/dist/chain-read-errors.js +15 -0
  74. package/dist/chain-read-errors.js.map +1 -1
  75. package/dist/cli/commands/auth.js +1 -1
  76. package/dist/cli/commands/auth.js.map +1 -1
  77. package/dist/cli/commands/create.js +3 -2
  78. package/dist/cli/commands/create.js.map +1 -1
  79. package/dist/cli/commands/doctor.d.ts +2 -0
  80. package/dist/cli/commands/doctor.js +2 -0
  81. package/dist/cli/commands/doctor.js.map +1 -1
  82. package/dist/cli/commands/rewards.js +11 -7
  83. package/dist/cli/commands/rewards.js.map +1 -1
  84. package/dist/cli/commands/solver-nets.js +24 -9
  85. package/dist/cli/commands/solver-nets.js.map +1 -1
  86. package/dist/cli/commands/status.js +1 -1
  87. package/dist/cli/commands/status.js.map +1 -1
  88. package/dist/cli/commands/tasks.js +86 -9
  89. package/dist/cli/commands/tasks.js.map +1 -1
  90. package/dist/cli/commands/update.d.ts +10 -0
  91. package/dist/cli/commands/update.js +36 -0
  92. package/dist/cli/commands/update.js.map +1 -1
  93. package/dist/cli/introspection-context.js +5 -0
  94. package/dist/cli/introspection-context.js.map +1 -1
  95. package/dist/cli/task-native-readiness.d.ts +3 -1
  96. package/dist/cli/task-native-readiness.js +28 -6
  97. package/dist/cli/task-native-readiness.js.map +1 -1
  98. package/dist/config.d.ts +106 -5
  99. package/dist/config.js +97 -18
  100. package/dist/config.js.map +1 -1
  101. package/dist/daemon/checkpoint-loop.d.ts +48 -0
  102. package/dist/daemon/checkpoint-loop.js +76 -0
  103. package/dist/daemon/checkpoint-loop.js.map +1 -0
  104. package/dist/daemon/creator.d.ts +1 -1
  105. package/dist/daemon/creator.js +7 -3
  106. package/dist/daemon/creator.js.map +1 -1
  107. package/dist/daemon/daemon.d.ts +19 -0
  108. package/dist/daemon/daemon.js +68 -1
  109. package/dist/daemon/daemon.js.map +1 -1
  110. package/dist/daemon/eviction-loop.d.ts +40 -0
  111. package/dist/daemon/eviction-loop.js +67 -0
  112. package/dist/daemon/eviction-loop.js.map +1 -0
  113. package/dist/daemon/jinn-claim-loop-wiring.d.ts +33 -0
  114. package/dist/daemon/jinn-claim-loop-wiring.js +40 -0
  115. package/dist/daemon/jinn-claim-loop-wiring.js.map +1 -0
  116. package/dist/daemon/jinn-claim-loop.d.ts +24 -17
  117. package/dist/daemon/jinn-claim-loop.js +77 -23
  118. package/dist/daemon/jinn-claim-loop.js.map +1 -1
  119. package/dist/daemon/skip-log-dedup.d.ts +69 -0
  120. package/dist/daemon/skip-log-dedup.js +106 -0
  121. package/dist/daemon/skip-log-dedup.js.map +1 -0
  122. package/dist/dashboard/assets/index-BUlE8F3Y.js +330 -0
  123. package/dist/dashboard/assets/index-blqc7eqq.css +32 -0
  124. package/dist/dashboard/index.html +2 -2
  125. package/dist/discovery/factory.d.ts +17 -5
  126. package/dist/discovery/factory.js +46 -18
  127. package/dist/discovery/factory.js.map +1 -1
  128. package/dist/discovery/http.js +142 -3
  129. package/dist/discovery/http.js.map +1 -1
  130. package/dist/discovery/onchain.d.ts +5 -0
  131. package/dist/discovery/onchain.js +407 -15
  132. package/dist/discovery/onchain.js.map +1 -1
  133. package/dist/discovery/types.d.ts +45 -1
  134. package/dist/discovery/types.js +8 -10
  135. package/dist/discovery/types.js.map +1 -1
  136. package/dist/discovery/with-fallback.d.ts +7 -0
  137. package/dist/discovery/with-fallback.js +10 -0
  138. package/dist/discovery/with-fallback.js.map +1 -1
  139. package/dist/earning/bootstrap.d.ts +92 -1
  140. package/dist/earning/bootstrap.js +203 -63
  141. package/dist/earning/bootstrap.js.map +1 -1
  142. package/dist/earning/contracts.d.ts +14 -0
  143. package/dist/earning/contracts.js +17 -5
  144. package/dist/earning/contracts.js.map +1 -1
  145. package/dist/earning/funding-plan.js +27 -18
  146. package/dist/earning/funding-plan.js.map +1 -1
  147. package/dist/earning/jinn-rewards.d.ts +46 -0
  148. package/dist/earning/jinn-rewards.js +32 -0
  149. package/dist/earning/jinn-rewards.js.map +1 -1
  150. package/dist/earning/safe-adapter.d.ts +2 -0
  151. package/dist/earning/safe-adapter.js +26 -12
  152. package/dist/earning/safe-adapter.js.map +1 -1
  153. package/dist/earning/store.d.ts +8 -0
  154. package/dist/earning/store.js.map +1 -1
  155. package/dist/earning/testnet-setup-migration.d.ts +12 -0
  156. package/dist/earning/testnet-setup-migration.js +27 -1
  157. package/dist/earning/testnet-setup-migration.js.map +1 -1
  158. package/dist/earning/types.d.ts +15 -0
  159. package/dist/erc8004/reputation.d.ts +8 -0
  160. package/dist/erc8004/reputation.js +22 -3
  161. package/dist/erc8004/reputation.js.map +1 -1
  162. package/dist/harnesses/cost-estimates.d.ts +145 -0
  163. package/dist/harnesses/cost-estimates.js +297 -0
  164. package/dist/harnesses/cost-estimates.js.map +1 -0
  165. package/dist/harnesses/engine/engine.d.ts +72 -0
  166. package/dist/harnesses/engine/engine.js +105 -8
  167. package/dist/harnesses/engine/engine.js.map +1 -1
  168. package/dist/harnesses/engine/persistence.d.ts +51 -1
  169. package/dist/harnesses/engine/persistence.js +118 -5
  170. package/dist/harnesses/engine/persistence.js.map +1 -1
  171. package/dist/harnesses/engine/work-dir-reaper.d.ts +65 -0
  172. package/dist/harnesses/engine/work-dir-reaper.js +100 -0
  173. package/dist/harnesses/engine/work-dir-reaper.js.map +1 -0
  174. package/dist/harnesses/impls/hermes-agent/adapter.js +40 -0
  175. package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -1
  176. package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +20 -0
  177. package/dist/harnesses/impls/hermes-agent/bootstrap.js +40 -6
  178. package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
  179. package/dist/harnesses/impls/hermes-agent/harness.d.ts +59 -1
  180. package/dist/harnesses/impls/hermes-agent/harness.js +104 -0
  181. package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
  182. package/dist/harnesses/impls/index.d.ts +7 -0
  183. package/dist/harnesses/impls/index.js +16 -1
  184. package/dist/harnesses/impls/index.js.map +1 -1
  185. package/dist/harnesses/impls/learner/harness.d.ts +38 -4
  186. package/dist/harnesses/impls/learner/harness.js +96 -2
  187. package/dist/harnesses/impls/learner/harness.js.map +1 -1
  188. package/dist/harnesses/impls/learner/plugin-path.d.ts +0 -13
  189. package/dist/harnesses/impls/learner/plugin-path.js +35 -15
  190. package/dist/harnesses/impls/learner/plugin-path.js.map +1 -1
  191. package/dist/harnesses/impls/learner/types.d.ts +11 -0
  192. package/dist/harnesses/impls/stub.d.ts +58 -0
  193. package/dist/harnesses/impls/stub.js +89 -0
  194. package/dist/harnesses/impls/stub.js.map +1 -0
  195. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.d.ts +69 -50
  196. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +178 -93
  197. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
  198. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.d.ts +12 -1
  199. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +121 -7
  200. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
  201. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +15 -0
  202. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +54 -4
  203. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
  204. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.d.ts +6 -0
  205. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js +1 -1
  206. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js.map +1 -1
  207. package/dist/harnesses/readiness-registry.js +9 -1
  208. package/dist/harnesses/readiness-registry.js.map +1 -1
  209. package/dist/main.js +371 -82
  210. package/dist/main.js.map +1 -1
  211. package/dist/observability/emit-event.d.ts +1 -1
  212. package/dist/observability/emit-event.js.map +1 -1
  213. package/dist/operator-errors.d.ts +7 -0
  214. package/dist/operator-errors.js +13 -1
  215. package/dist/operator-errors.js.map +1 -1
  216. package/dist/plugins/learner/.claude-plugin/plugin.json +9 -0
  217. package/dist/plugins/learner/.codex-plugin/plugin.json +39 -0
  218. package/dist/plugins/learner/AGENTS.md +40 -0
  219. package/dist/plugins/learner/CLAUDE.md +33 -0
  220. package/dist/plugins/learner/README.md +59 -0
  221. package/dist/plugins/learner/hooks/hooks.json +16 -0
  222. package/dist/plugins/learner/hooks/session-start +38 -0
  223. package/dist/plugins/learner/skills/learn/SKILL.md +412 -0
  224. package/dist/plugins/learner/skills/learn/analyst-prompt.md +68 -0
  225. package/dist/plugins/learner/skills/learn/consolidator-prompt.md +94 -0
  226. package/dist/plugins/learner/skills/learn/explorer-prompt.md +53 -0
  227. package/dist/plugins/learner/skills/learn/planner-prompt.md +87 -0
  228. package/dist/plugins/learner/skills/learn/promoter-prompt.md +113 -0
  229. package/dist/plugins/learner/skills/learn/step-worker-prompt.md +47 -0
  230. package/dist/plugins/learner/skills/learn/strategist-prompt.md +85 -0
  231. package/dist/restart-daemon.d.ts +90 -0
  232. package/dist/restart-daemon.js +95 -0
  233. package/dist/restart-daemon.js.map +1 -0
  234. package/dist/setup/halt-mode.d.ts +14 -0
  235. package/dist/setup/halt-mode.js +17 -0
  236. package/dist/setup/halt-mode.js.map +1 -0
  237. package/dist/solver-nets/prediction-operator-ux.js +43 -3
  238. package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
  239. package/dist/solver-nets/registry.d.ts +1 -0
  240. package/dist/solver-nets/registry.js +1 -1
  241. package/dist/solver-nets/registry.js.map +1 -1
  242. package/dist/solver-types/_swe-rebench-v2-pool-cache.d.ts +58 -0
  243. package/dist/solver-types/_swe-rebench-v2-pool-cache.js +87 -0
  244. package/dist/solver-types/_swe-rebench-v2-pool-cache.js.map +1 -0
  245. package/dist/solver-types/_swe-rebench-v2-substrate.d.ts +1 -0
  246. package/dist/solver-types/_swe-rebench-v2-substrate.js +10 -0
  247. package/dist/solver-types/_swe-rebench-v2-substrate.js.map +1 -1
  248. package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +65 -0
  249. package/dist/solver-types/_swe-rebench-v2-validated-pool.js +243 -26
  250. package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
  251. package/dist/solver-types/swe-rebench-v2-auto.d.ts +22 -7
  252. package/dist/solver-types/swe-rebench-v2-auto.js +45 -20
  253. package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
  254. package/dist/solver-types/swe-rebench-v2.d.ts +13 -2
  255. package/dist/solver-types/swe-rebench-v2.js +233 -94
  256. package/dist/solver-types/swe-rebench-v2.js.map +1 -1
  257. package/dist/solvernets/daemon-init.d.ts +10 -2
  258. package/dist/solvernets/daemon-init.js +22 -2
  259. package/dist/solvernets/daemon-init.js.map +1 -1
  260. package/dist/solvernets/launched-record-dispatcher.js +35 -7
  261. package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
  262. package/dist/solvernets/store.d.ts +5 -0
  263. package/dist/solvernets/store.js +1 -0
  264. package/dist/solvernets/store.js.map +1 -1
  265. package/dist/store/store.d.ts +15 -0
  266. package/dist/store/store.js +118 -3
  267. package/dist/store/store.js.map +1 -1
  268. package/dist/tasks/sources.d.ts +18 -1
  269. package/dist/tasks/sources.js +33 -5
  270. package/dist/tasks/sources.js.map +1 -1
  271. package/dist/tx-retry.d.ts +151 -19
  272. package/dist/tx-retry.js +286 -32
  273. package/dist/tx-retry.js.map +1 -1
  274. package/dist/types/payloads/prediction-apy-v0.d.ts +5 -5
  275. package/dist/types/payloads/prediction-v0.d.ts +5 -5
  276. package/dist/types/task-document.d.ts +392 -0
  277. package/dist/types/task-document.js +10 -0
  278. package/dist/types/task-document.js.map +1 -1
  279. package/dist/types/task.d.ts +28 -0
  280. package/dist/util/extract-tx-hash.d.ts +14 -0
  281. package/dist/util/extract-tx-hash.js +19 -0
  282. package/dist/util/extract-tx-hash.js.map +1 -0
  283. package/dist/vendor/@jinn-network/sdk/dist/contracts.js +1 -1
  284. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.d.ts +3 -0
  285. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.js +1 -0
  286. package/package.json +29 -12
  287. package/dist/dashboard/assets/index-DOlzFN8a.css +0 -32
  288. package/dist/dashboard/assets/index-NkZ7CTAT.js +0 -140
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,7 @@ 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 { buildJinnClaimLoopConfig, shouldWireJinnClaimL1Signer, } from './daemon/jinn-claim-loop-wiring.js';
51
54
  import { createJinnPublicClient, createJinnWalletClient, createJinnL1PublicClient, createJinnL1WalletClient } from './earning/viem-clients.js';
52
55
  import { privateKeyToAccount } from 'viem/accounts';
53
56
  import { getAddress } from 'viem';
@@ -56,6 +59,7 @@ import { joinedSolverNetsViewFromConfig } from './harnesses/engine/engine.js';
56
59
  import { buildHarnesses } from './harnesses/impls/index.js';
57
60
  import { loadExternalImpl } from './harnesses/external-impls/index.js';
58
61
  import { CLAUDE_CODE_HARNESS, CODEX_HARNESS, HERMES_AGENT_HARNESS, harnessStateDirName } from './harnesses/names.js';
62
+ import { resolveContractFromSolverNetId } from './solvernets/launched-record-dispatcher.js';
59
63
  import { HarnessReadinessRegistry } from './harnesses/readiness-registry.js';
60
64
  import { createClients } from './adapters/mech/safe.js';
61
65
  import { loadSolverNets } from './solver-nets/registry.js';
@@ -76,10 +80,11 @@ import { GeminiSessionParser } from './trajectory/transcript-parsers/gemini-sess
76
80
  import { CursorSqliteParser } from './trajectory/transcript-parsers/cursor-sqlite.js';
77
81
  import { buildInfo } from './build-info.js';
78
82
  import { BASE_FEEDS } from './venues/chainlink/feeds.js';
79
- import { GeneratedTaskSource, StaticConfiguredTaskSource } from './tasks/sources.js';
83
+ import { GeneratedTaskSource, StaticConfiguredTaskSource, filterBindableTasks } from './tasks/sources.js';
80
84
  import { checkRpcNetwork, logRpcLocalDevToStderr, rpcNetworkFailureHint } from './preflight/rpc-network.js';
81
85
  import { apiPortFailureMessage, checkApiPortAvailable } from './preflight/api-port.js';
82
86
  import { openBrowser } from './cli/open-browser.js';
87
+ import { keepSetupUiOnBootstrapError } from './setup/halt-mode.js';
83
88
  if (process.env['JINN_LOAD_DEV_ENV'] === '1' || process.env['NODE_ENV'] === 'development') {
84
89
  dotenvConfig({ path: join(dirname(fileURLToPath(import.meta.url)), '..', '.env') });
85
90
  }
@@ -132,8 +137,19 @@ const config = loadConfig(CONFIG_PATH);
132
137
  if (config.network === 'mainnet' && process.env['JINN_ENABLE_MAINNET'] !== '1') {
133
138
  console.warn('[main] Mainnet is disabled before launch; using testnet defaults.');
134
139
  config.network = 'testnet';
135
- config.rpcUrl = 'https://base-sepolia.gateway.tenderly.co/75tyLMQuD8EHpXxMwINIKu';
140
+ config.rpcUrl = 'https://base-sepolia-rpc.publicnode.com';
136
141
  }
142
+ // Issue #326: the embedded Claude agent chat surface (right rail + onboarding
143
+ // "Ask Claude" panel + /api/agent/ws bridge) is hidden by default while its
144
+ // action-authority / plugin-scope shape is still in design. Set
145
+ // `JINN_ENABLE_EMBEDDED_AGENT=1` to re-enable it for development. This does
146
+ // NOT affect Claude-Code-as-a-solver-harness — that path is independent.
147
+ //
148
+ // Issue #367: the SPA reads this flag via the injected `window.__JINN_FEATURES__`
149
+ // (`resolveFeatureFlags` in api/server.ts) like every other operator-app flag.
150
+ // This `embeddedAgentEnabled` const is the daemon-side consumer only — it gates
151
+ // whether the `/api/agent/ws` bridge is mounted below.
152
+ const embeddedAgentEnabled = isEmbeddedAgentEnabled();
137
153
  let activeClaudePath = config.claudePath ?? 'claude';
138
154
  const selectClaudePath = (claudePath) => {
139
155
  activeClaudePath = claudePath;
@@ -484,11 +500,17 @@ async function bootstrap() {
484
500
  hint: 'Fund the listed address and re-run this command.',
485
501
  exampleCli: 'jinn fund-requirements --json',
486
502
  details: {
487
- role: 'master',
503
+ // jinn-mono-hjex.6: structured envelope so SPA can render the
504
+ // specific address + amount instead of a prose disjunction.
505
+ category: 'insufficient_funds',
506
+ step: 'awaiting_funding',
488
507
  address: result.funding.master_address,
508
+ requiredWei: result.funding.eth_required,
509
+ haveWei: result.funding.eth_balance,
510
+ // Legacy aliases kept for any external consumers that read these.
511
+ role: 'master',
489
512
  asset: 'native',
490
513
  needWei: result.funding.eth_required,
491
- haveWei: result.funding.eth_balance,
492
514
  },
493
515
  });
494
516
  }
@@ -503,11 +525,17 @@ async function bootstrap() {
503
525
  hint: 'Bootstrap failed before the fleet reached a runnable state.',
504
526
  details: {
505
527
  cause: result.message,
528
+ // jinn-mono-hjex.6: propagate structured category from the bootstrapper
529
+ // so the SPA can render category-specific UI (e.g. funding shortfall).
530
+ ...(result.errorCategory !== undefined ? { category: result.errorCategory } : {}),
506
531
  // Preserve the raw underlying error so a misclassified summary can
507
532
  // be diagnosed without re-running with JINN_DEBUG. See jinn-mono-jz9f.
508
533
  ...(result.rawErrorMessage && result.rawErrorMessage !== result.message
509
534
  ? { rawErrorMessage: result.rawErrorMessage }
510
535
  : {}),
536
+ // jinn-mono-hjex reviewer fix: propagate tx hash so the SPA can render
537
+ // a block-explorer link for failed on-chain revert transactions.
538
+ ...(result.txHash != null ? { txHash: result.txHash } : {}),
511
539
  },
512
540
  });
513
541
  }
@@ -592,7 +620,9 @@ class SetupBootstrapHalted extends Error {
592
620
  this.name = 'SetupBootstrapHalted';
593
621
  }
594
622
  }
595
- const keepSetupUiOnBootstrapError = () => process.env['JINN_NO_UI'] !== '1' && process.env['JINN_NO_DAEMON'] !== '1';
623
+ // hjex.6: gate for the halt-and-resume loop. Lives in ./setup/halt-mode.ts
624
+ // so it can be unit-tested without dragging main.ts's top-level side
625
+ // effects (password resolution, config load) into the test.
596
626
  // ── Main ────────────────────────────────────────────────────────────────────
597
627
  /**
598
628
  * --json-progress: emit NDJSON progress envelopes on stdout during long
@@ -679,6 +709,7 @@ export async function main() {
679
709
  // /v1/bootstrap + /v1/events + /v1/status here. The same Store instance is
680
710
  // later passed into Daemon so we don't double-open the SQLite file.
681
711
  const sharedStore = new Store(config.dbPath);
712
+ setDefaultTxSubmissionLedger(sharedStore);
682
713
  const capturesStore = new CapturesStore(sharedStore);
683
714
  let captureReceiver;
684
715
  try {
@@ -759,6 +790,18 @@ export async function main() {
759
790
  // builder-artifacts. Holder ref lets the routes register eagerly and
760
791
  // start returning real data the moment main.ts assigns holder.current.
761
792
  const discoveryApiHolder = { current: undefined };
793
+ // hjex.3: holder for the restake callback. Populated in running mode after
794
+ // bootstrap completes (when mnemonic + distributorAddress are available).
795
+ const restakeCallbackRef = {
796
+ current: undefined,
797
+ };
798
+ // hjex.6: retry signal for the bootstrap halt-and-resume loop.
799
+ // When a SetupBootstrapHalted is caught (fatal non-funding error or funding
800
+ // timeout), main() waits on this promise instead of returning, so the setup
801
+ // API stays alive and the operator can click Retry in the SPA.
802
+ // The retry endpoint resolves this promise to trigger a re-run.
803
+ let retryBootstrapResolve = null;
804
+ let retryBootstrapReject = null;
762
805
  let setupApiServer;
763
806
  try {
764
807
  setupApiServer = await startApiServer({
@@ -772,11 +815,32 @@ export async function main() {
772
815
  hermesPath: config.hermesPath,
773
816
  hermesDoctorTimeoutMs: config.hermesDoctorTimeoutMs,
774
817
  },
818
+ codexDoctor: {
819
+ codexPath: config.codexPath,
820
+ codexDoctorTimeoutMs: config.codexDoctorTimeoutMs,
821
+ },
775
822
  admin: {
776
- onRestartRequested: () => {
777
- console.log('[main] Restart requested via operator MCP. Exiting...');
778
- process.exit(0);
779
- },
823
+ // jinn-mono #289: in interactive mode (the dashboard SPA case),
824
+ // spawn a detached replacement before exiting so the panel reconnects
825
+ // to a live daemon instead of seeing a 502 + terminal prompt. In
826
+ // headless mode (`JINN_NO_UI=1`), exit without respawning so the
827
+ // supervisor / systemd / docker entrypoint decides what to do.
828
+ // Stop: pure exit, never respawn. The operator clicked Stop; they
829
+ // want the daemon down until they explicitly start it again.
830
+ onStopRequested: () => process.exit(0),
831
+ onRestartRequested: (opts) => requestDaemonRestart({
832
+ forceRespawn: opts.forceRespawn,
833
+ // jinn-mono #561: close the API + OTLP listeners before the
834
+ // replacement spawns, so the child binds without an
835
+ // EADDRINUSE race. Errors are swallowed inside
836
+ // requestDaemonRestart so the operator is never stranded.
837
+ preSpawnCleanup: async () => {
838
+ await setupApiServer.close().catch(() => undefined);
839
+ if (captureReceiver) {
840
+ await captureReceiver.shutdown().catch(() => undefined);
841
+ }
842
+ },
843
+ }),
780
844
  },
781
845
  harnessStatus: {
782
846
  getStatus: async () => {
@@ -962,10 +1026,40 @@ export async function main() {
962
1026
  // toggle immediately. (jinn-mono-l2zl.15.4.12)
963
1027
  invalidatePredictionOperatorStatusCache(config);
964
1028
  },
1029
+ // hjex.3: delegate to the live callback populated once running mode starts.
1030
+ restake: (serviceId) => {
1031
+ if (!restakeCallbackRef.current) {
1032
+ return Promise.resolve({ ok: false, error: 'restake_not_available_in_setup_mode' });
1033
+ }
1034
+ return restakeCallbackRef.current(serviceId);
1035
+ },
1036
+ // hjex.6: re-trigger the bootstrap state machine from the SPA Retry button.
1037
+ // Resolves the halt-and-resume promise; main() will loop back and call
1038
+ // bootstrap() again. Rejects if the daemon is not currently halted.
1039
+ retryBootstrap: () => {
1040
+ return new Promise((resolve, reject) => {
1041
+ if (!retryBootstrapResolve) {
1042
+ reject(new Error('daemon_not_halted'));
1043
+ return;
1044
+ }
1045
+ const prevResolve = retryBootstrapResolve;
1046
+ // The resolve will unblock the main loop's await. When bootstrap
1047
+ // completes (success or new halt), the caller receives the result
1048
+ // via the /v1/bootstrap polling endpoint.
1049
+ prevResolve();
1050
+ resolve();
1051
+ });
1052
+ },
965
1053
  },
966
1054
  status: {
967
1055
  earningDir: config.earningDir,
968
1056
  rpcUrl: config.rpcUrl,
1057
+ // tJINN identity comes from the bundled JINN MVI L1 artifact
1058
+ // (`JINN_MVI_CONFIG`) — one source of truth. The Sepolia RPC endpoint
1059
+ // is read from `config.ethereumRpcUrl` via the threaded `config`.
1060
+ tjinnTokenAddress: JINN_MVI_CONFIG.jinn,
1061
+ tjinnChainId: JINN_MVI_CONFIG.l1ChainId,
1062
+ tjinnDistributorAddress: JINN_MVI_CONFIG.distributor,
969
1063
  network: config.network,
970
1064
  pollIntervalMs: config.pollIntervalMs,
971
1065
  masterEthDailyEstimateWei: config.masterEthDailyEstimateWei,
@@ -1114,30 +1208,41 @@ export async function main() {
1114
1208
  // can attach to a long-lived embedded `claude` subprocess. The embedded
1115
1209
  // session reads MCP config we materialise to disk so it can reach the
1116
1210
  // 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'],
1211
+ //
1212
+ // Issue #326: the embedded agent chat surface is hidden by default. The WS
1213
+ // bridge mounts only when `JINN_ENABLE_EMBEDDED_AGENT=1` so the dev-time
1214
+ // path stays end-to-end; with the flag off there is no /api/agent/ws route
1215
+ // and the SPA never renders the chat panel. Claude-Code-as-solver-harness
1216
+ // is independent of this bridge and unaffected.
1217
+ if (embeddedAgentEnabled) {
1218
+ const operatorMcpConfigPath = join(homedir(), '.jinn-client', 'operator-mcp-config.json');
1219
+ try {
1220
+ mkdirSync(dirname(operatorMcpConfigPath), { recursive: true });
1221
+ writeFileSyncMain(operatorMcpConfigPath, JSON.stringify({
1222
+ mcpServers: {
1223
+ 'jinn-operator': {
1224
+ command: 'jinn',
1225
+ args: ['mcp'],
1226
+ },
1125
1227
  },
1126
- },
1127
- }, null, 2));
1228
+ }, null, 2));
1229
+ }
1230
+ catch (err) {
1231
+ console.warn(`[main] Failed to write operator MCP config at ${operatorMcpConfigPath}: ` +
1232
+ (err instanceof Error ? err.message : String(err)));
1233
+ }
1234
+ attachAgentWs({
1235
+ httpServer: setupApiServer.server,
1236
+ uiToken,
1237
+ claudePath: activeClaudePath,
1238
+ cwd: process.cwd(),
1239
+ mcpConfigPath: operatorMcpConfigPath,
1240
+ });
1241
+ console.log(`[main] Agent WS bridge mounted at ws://127.0.0.1:${setupApiServer.port}/api/agent/ws`);
1128
1242
  }
1129
- catch (err) {
1130
- console.warn(`[main] Failed to write operator MCP config at ${operatorMcpConfigPath}: ` +
1131
- (err instanceof Error ? err.message : String(err)));
1243
+ else {
1244
+ console.log('[main] Embedded agent surface disabled (set JINN_ENABLE_EMBEDDED_AGENT=1 to enable).');
1132
1245
  }
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
1246
  // ── Init-if-missing ──────────────────────────────────────────────────────
1142
1247
  // If the keystore is missing but we have a password, run `jinn init` now so
1143
1248
  // bootstrap has something to decrypt. Idempotent: init is a no-op when the
@@ -1178,30 +1283,96 @@ export async function main() {
1178
1283
  // keystore is on disk and we're transitioning into bootstrap.
1179
1284
  setupController.refresh({ keystoreExists: true, allComplete: false });
1180
1285
  }
1286
+ // hjex.6: halt-and-resume loop for bootstrap retries.
1287
+ // When failBootstrap() throws SetupBootstrapHalted, we wait for the operator
1288
+ // to click Retry in the SPA (which resolves retryBootstrapResolve) rather
1289
+ // than returning and exiting. On each retry, we loop back and call bootstrap()
1290
+ // again. bootstrap() is idempotent — completed steps are no-ops.
1181
1291
  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
- };
1292
+ // eslint-disable-next-line no-constant-condition
1293
+ while (true) {
1294
+ try {
1295
+ bootstrapResult = await bootstrap();
1296
+ break; // success exit the retry loop
1297
+ }
1298
+ catch (err) {
1299
+ if (err instanceof SetupBootstrapHalted) {
1300
+ // Install the retry signal so the endpoint can unblock us.
1301
+ const retrySignal = new Promise((resolve, reject) => {
1302
+ retryBootstrapResolve = resolve;
1303
+ retryBootstrapReject = reject;
1304
+ });
1305
+ console.log('[main] Bootstrap halted. Waiting for retry signal from the dashboard...');
1306
+ // hjex.6: Auto-resume funding poller.
1307
+ // When the halt is a funding shortfall, poll the master EOA balance
1308
+ // every JINN_FUNDING_POLL_INTERVAL_MS (default 15s). When the balance
1309
+ // meets or exceeds the required amount, auto-signal the retry loop.
1310
+ // Only runs while the halt signal is pending; stops on any signal.
1311
+ let fundingPollHandle = null;
1312
+ const isHaltedOnFunding = err.envelope.code === 'funding_required';
1313
+ const haltDetails = err.envelope.details;
1314
+ const haltAddress = typeof haltDetails?.['address'] === 'string'
1315
+ ? haltDetails['address']
1316
+ : null;
1317
+ const haltRequired = typeof haltDetails?.['requiredWei'] === 'string'
1318
+ ? BigInt(haltDetails['requiredWei'])
1319
+ : typeof haltDetails?.['needWei'] === 'string'
1320
+ ? BigInt(haltDetails['needWei'])
1321
+ : null;
1322
+ const fundingPollIntervalMs = (() => {
1323
+ const raw = process.env['JINN_FUNDING_POLL_INTERVAL_MS'];
1324
+ if (!raw)
1325
+ return 15_000;
1326
+ const n = Number.parseInt(raw, 10);
1327
+ return Number.isFinite(n) && n > 0 ? n : 15_000;
1328
+ })();
1329
+ if (isHaltedOnFunding && haltAddress && haltRequired !== null) {
1330
+ const publicClient = createJinnPublicClient(config.rpcUrl, NETWORK_CHAIN);
1331
+ const schedulePoll = () => {
1332
+ fundingPollHandle = setTimeout(async () => {
1333
+ // Guard: if the signal was already fired, stop polling.
1334
+ if (!retryBootstrapResolve)
1335
+ return;
1336
+ try {
1337
+ const balance = await publicClient.getBalance({ address: haltAddress });
1338
+ if (balance >= haltRequired) {
1339
+ console.log(`[main] Funding shortfall cleared (have ${balance}, required ${haltRequired}). ` +
1340
+ `Auto-resuming bootstrap...`);
1341
+ retryBootstrapResolve?.();
1342
+ return; // don't schedule the next poll
1343
+ }
1344
+ }
1345
+ catch (pollErr) {
1346
+ // Balance read failed — not fatal, just skip this tick.
1347
+ const msg = pollErr instanceof Error ? pollErr.message : String(pollErr);
1348
+ console.log(`[main] Funding poller balance read failed (will retry): ${msg}`);
1349
+ }
1350
+ schedulePoll(); // reschedule
1351
+ }, fundingPollIntervalMs);
1352
+ };
1353
+ schedulePoll();
1354
+ }
1355
+ try {
1356
+ await retrySignal;
1357
+ }
1358
+ finally {
1359
+ retryBootstrapResolve = null;
1360
+ retryBootstrapReject = null;
1361
+ if (fundingPollHandle !== null) {
1362
+ clearTimeout(fundingPollHandle);
1363
+ fundingPollHandle = null;
1364
+ }
1365
+ }
1366
+ console.log('[main] Retry triggered — re-running bootstrap...');
1367
+ continue; // loop back to the bootstrap() call
1368
+ }
1369
+ // If bootstrap throws an unexpected error (vs. SetupBootstrapHalted),
1370
+ // tear down the API we just started so we don't leave a dangling listener.
1371
+ await setupApiServer.close().catch(() => undefined);
1372
+ await closeCaptureReceiver();
1373
+ sharedStore.close();
1374
+ throw err;
1198
1375
  }
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
1376
  }
1206
1377
  // Bootstrap completed — flip the controller into 'running' so any waiters
1207
1378
  // (future loops gated on this) unblock.
@@ -1257,6 +1428,33 @@ export async function main() {
1257
1428
  const publicClient = createJinnPublicClient(config.rpcUrl, NETWORK_CHAIN);
1258
1429
  publicClientForLauncher = publicClient;
1259
1430
  const masterWallet = createJinnWalletClient(config.rpcUrl, NETWORK_CHAIN, masterAccount);
1431
+ // hjex.3: populate the restake callback now that mnemonic is available.
1432
+ if (config.stakingMode === 'standard' && CHAIN_CONFIG.distributorAddress) {
1433
+ const fleetStore = earningStore;
1434
+ restakeCallbackRef.current = async (serviceId) => {
1435
+ try {
1436
+ const state = await fleetStore.load(NETWORK_CHAIN);
1437
+ const svc = state.services.find(s => s.service_id === serviceId);
1438
+ if (!svc)
1439
+ return { ok: false, error: `service_not_found:${serviceId}` };
1440
+ if (!svc.staking_address)
1441
+ return { ok: false, error: 'staking_address_missing' };
1442
+ await recoverEvictedServiceFn({
1443
+ serviceDisplayIndex: Math.max(0, svc.index - 1),
1444
+ serviceId,
1445
+ stakingAddress: svc.staking_address,
1446
+ distributorAddress: CHAIN_CONFIG.distributorAddress,
1447
+ rpcUrl: config.rpcUrl,
1448
+ chain: NETWORK_CHAIN,
1449
+ mnemonic: mnemonicForMaster,
1450
+ });
1451
+ return { ok: true };
1452
+ }
1453
+ catch (err) {
1454
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
1455
+ }
1456
+ };
1457
+ }
1260
1458
  const evictionRecovery = config.stakingMode === 'standard' &&
1261
1459
  serviceId !== null &&
1262
1460
  stakingAddress &&
@@ -1360,19 +1558,45 @@ export async function main() {
1360
1558
  // ── L1 (Sepolia / Ethereum mainnet) clients for cross-chain JINN claim loop ──
1361
1559
  // Uses the agent EOA because MockMessenger.owner is the agent on testnet.
1362
1560
  // Same key as L2; only the chain differs.
1363
- const l1ClientsForJinnClaim = JINN_MVI_CONFIG.distributor && config.ethereumRpcUrl
1561
+ const shouldWireJinnClaimL1 = shouldWireJinnClaimL1Signer({
1562
+ enabled: config.jinnClaimLoopEnabled,
1563
+ intervalMs: config.jinnClaimLoopIntervalMs,
1564
+ submissionMode: config.jinnClaimSubmissionMode,
1565
+ distributorAddress: JINN_MVI_CONFIG.distributor,
1566
+ ethereumRpcUrl: config.ethereumRpcUrl,
1567
+ });
1568
+ const l1ClientsForJinnClaim = shouldWireJinnClaimL1 && config.ethereumRpcUrl
1364
1569
  ? {
1365
1570
  public: createJinnL1PublicClient(config.ethereumRpcUrl, config.jinnL1Network),
1366
1571
  wallet: createJinnL1WalletClient(config.ethereumRpcUrl, config.jinnL1Network, privateKeyToAccount(agentPrivateKey)),
1367
1572
  }
1368
1573
  : undefined;
1369
- if (l1ClientsForJinnClaim) {
1370
- console.log(`[main] JinnClaimLoop: enabled (mode=${JINN_CLAIM_MESSENGER_MODE}, ` +
1574
+ const jinnClaimLoopConfig = buildJinnClaimLoopConfig({
1575
+ enabled: config.jinnClaimLoopEnabled,
1576
+ intervalMs: config.jinnClaimLoopIntervalMs,
1577
+ submissionMode: config.jinnClaimSubmissionMode,
1578
+ messengerMode: JINN_CLAIM_MESSENGER_MODE,
1579
+ mvi: JINN_MVI_CONFIG,
1580
+ l2Client: agentClients.publicClient,
1581
+ l2ProofClient,
1582
+ l2Wallet: agentClients.walletClient,
1583
+ l1Clients: l1ClientsForJinnClaim,
1584
+ store: earningStore,
1585
+ chain: NETWORK_CHAIN,
1586
+ optimismPortalAddress,
1587
+ disputeGameFactoryAddress,
1588
+ });
1589
+ if (jinnClaimLoopConfig) {
1590
+ console.log(`[main] JinnClaimLoop: enabled (submission=${config.jinnClaimSubmissionMode}, ` +
1591
+ `mode=${JINN_CLAIM_MESSENGER_MODE}, ` +
1371
1592
  `interval=${config.jinnClaimLoopIntervalMs}ms, distributor=${JINN_MVI_CONFIG.distributor}, ` +
1372
1593
  `emitter=${JINN_MVI_CONFIG.claimEmitter})`);
1373
1594
  }
1595
+ else if (!config.jinnClaimLoopEnabled) {
1596
+ console.log('[main] JinnClaimLoop: disabled (jinnClaimLoopEnabled=false)');
1597
+ }
1374
1598
  else {
1375
- console.log(`[main] JinnClaimLoop: disabled (JinnDistributor artifact/override or JINN_ETHEREUM_RPC_URL not set)`);
1599
+ console.log(`[main] JinnClaimLoop: disabled (missing claim-loop artifacts, interval disabled, or L1 submit wiring)`);
1376
1600
  }
1377
1601
  // ── Harness registry ─────────────────────────────────────────────────────────
1378
1602
  const solverNetRegistry = await loadSolverNets(config);
@@ -1464,6 +1688,9 @@ export async function main() {
1464
1688
  hermesPath: config.hermesPath,
1465
1689
  hermesModel: config.hermesModel,
1466
1690
  hermesProvider: config.hermesProvider,
1691
+ hermesDoctorTimeoutMs: config.hermesDoctorTimeoutMs,
1692
+ codexPath: config.codexPath,
1693
+ codexDoctorTimeoutMs: config.codexDoctorTimeoutMs,
1467
1694
  })) {
1468
1695
  implRegistry.register(impl);
1469
1696
  }
@@ -1733,11 +1960,19 @@ export async function main() {
1733
1960
  if (!safeAddressForLauncher) {
1734
1961
  throw new Error('[main] safeAddressForLauncher missing at SolverNet endpoints registration');
1735
1962
  }
1963
+ const getGeneratorState = (solverNetId) => {
1964
+ const entry = pendingGeneratorsRef.current.find((g) => g.recordRef.current.solverNetId === solverNetId);
1965
+ const resolved = resolveContractFromSolverNetId(entry?.recordRef.current.solverNetId ?? solverNetId);
1966
+ if (!resolved)
1967
+ return undefined;
1968
+ return launchedGeneratorStateBySolverType.get(resolved.solverType)?.();
1969
+ };
1736
1970
  solverNetEndpointsDepsHolder.current = {
1737
1971
  store: solverNetStore,
1738
1972
  launch: {
1739
1973
  launchAction,
1740
1974
  lifecycleTransition,
1975
+ getGeneratorState,
1741
1976
  pendingGenerators: pendingGeneratorsRef,
1742
1977
  signer: launcherSigner,
1743
1978
  network: 'base-sepolia',
@@ -1812,9 +2047,23 @@ export async function main() {
1812
2047
  if (config.network === 'mainnet' && !autoTasksDisabled && BASE_FEEDS['ETH / USD']) {
1813
2048
  // Mainnet auto-task opt-in only; default is OFF. Reserved for a future flag.
1814
2049
  }
2050
+ // filterBindableTasks (issue #415): drop config-level tasks[] entries without
2051
+ // solverNetManifestCid before they enter the creator loop. Such entries would
2052
+ // throw a PermanentError on every attempt and retry every 30 min indefinitely.
2053
+ const bindableConfigTasks = filterBindableTasks(config.tasks);
1815
2054
  const taskSources = [
1816
- new StaticConfiguredTaskSource(config.tasks),
1817
- ...launchedRecordGenerators.map(({ solverType, generator }, idx) => new GeneratedTaskSource(`launched:${solverType}:${idx}`, generator)),
2055
+ new StaticConfiguredTaskSource(bindableConfigTasks),
2056
+ ...launchedRecordGenerators.map(({ solverType, generator }, idx) => new GeneratedTaskSource(`launched:${solverType}:${idx}`, generator, {
2057
+ bucketKeyForTask: (task) => {
2058
+ if (task.solverType !== 'swe-rebench-v2.v1')
2059
+ return undefined;
2060
+ const instanceId = task.spec?.['instance_id'];
2061
+ const postedCount = task.eligibility?.['posted_count_after_record'];
2062
+ if (typeof instanceId !== 'string' || typeof postedCount !== 'number')
2063
+ return undefined;
2064
+ return `swe-rebench-v2:${instanceId}:${postedCount}`;
2065
+ },
2066
+ })),
1818
2067
  ];
1819
2068
  // ── Corpus (daemon-side, jinn-mono-vy37.1.6) ─────────────────────────────
1820
2069
  //
@@ -1866,6 +2115,12 @@ export async function main() {
1866
2115
  status: {
1867
2116
  earningDir: config.earningDir,
1868
2117
  rpcUrl: config.rpcUrl,
2118
+ // tJINN identity comes from the bundled JINN MVI L1 artifact
2119
+ // (`JINN_MVI_CONFIG`) — one source of truth. The Sepolia RPC endpoint
2120
+ // is read from `config.ethereumRpcUrl` via the threaded `config`.
2121
+ tjinnTokenAddress: JINN_MVI_CONFIG.jinn,
2122
+ tjinnChainId: JINN_MVI_CONFIG.l1ChainId,
2123
+ tjinnDistributorAddress: JINN_MVI_CONFIG.distributor,
1869
2124
  network: config.network,
1870
2125
  pollIntervalMs: config.pollIntervalMs,
1871
2126
  masterEthDailyEstimateWei: config.masterEthDailyEstimateWei,
@@ -1888,28 +2143,7 @@ export async function main() {
1888
2143
  distributorAddress: CHAIN_CONFIG.distributorAddress,
1889
2144
  }
1890
2145
  : 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,
2146
+ jinnClaim: jinnClaimLoopConfig,
1913
2147
  restorationEngine: {
1914
2148
  paths: {
1915
2149
  workingDirRoot: config.engine.workingDirRoot,
@@ -1954,6 +2188,61 @@ export async function main() {
1954
2188
  safeTopupTarget: CHAIN_CONFIG.minSafeEth,
1955
2189
  }
1956
2190
  : undefined,
2191
+ // Eviction-check loop — only in standard staking mode (requires distributorAddress).
2192
+ // Running mode only: setup-halted daemons must not try to restake services that
2193
+ // haven't been staked yet (hjex.3).
2194
+ evictionCheck: config.evictionCheckIntervalMs > 0 &&
2195
+ config.stakingMode === 'standard' &&
2196
+ CHAIN_CONFIG.distributorAddress
2197
+ ? {
2198
+ intervalMs: config.evictionCheckIntervalMs,
2199
+ store: earningStore,
2200
+ chain: NETWORK_CHAIN,
2201
+ readContract: (opts) => publicClient.readContract(opts),
2202
+ recoverEvictedService: async (svc) => {
2203
+ if (!svc.service_id || !svc.staking_address)
2204
+ return;
2205
+ await recoverEvictedServiceFn({
2206
+ serviceDisplayIndex: Math.max(0, svc.index - 1),
2207
+ serviceId: svc.service_id,
2208
+ stakingAddress: svc.staking_address,
2209
+ distributorAddress: CHAIN_CONFIG.distributorAddress,
2210
+ rpcUrl: config.rpcUrl,
2211
+ chain: NETWORK_CHAIN,
2212
+ mnemonic: mnemonicForMaster,
2213
+ });
2214
+ },
2215
+ }
2216
+ : undefined,
2217
+ // Checkpoint loop — proactively advances `tsCheckpoint` on each staked
2218
+ // proxy so the activity-rate window stays narrow (issue #505).
2219
+ // `checkpoint()` is permissionless; master EOA pays gas. No-op for
2220
+ // non-standard staking modes.
2221
+ checkpoint: config.checkpointIntervalMs > 0 && config.stakingMode === 'standard'
2222
+ ? {
2223
+ intervalMs: config.checkpointIntervalMs,
2224
+ store: earningStore,
2225
+ chain: NETWORK_CHAIN,
2226
+ writeCheckpoint: async ({ stakingProxy }) => {
2227
+ const txHash = await masterWallet.writeContract({
2228
+ address: stakingProxy,
2229
+ abi: [
2230
+ {
2231
+ type: 'function',
2232
+ name: 'checkpoint',
2233
+ stateMutability: 'nonpayable',
2234
+ inputs: [],
2235
+ outputs: [],
2236
+ },
2237
+ ],
2238
+ functionName: 'checkpoint',
2239
+ account: masterAccount,
2240
+ chain: null,
2241
+ });
2242
+ return { txHash };
2243
+ },
2244
+ }
2245
+ : undefined,
1957
2246
  });
1958
2247
  // Write pidfile so `jinn stop` can find us.
1959
2248
  const pidPath = join(config.earningDir, 'daemon.pid');