@jinn-network/client 0.1.5 → 0.1.6-canary.107ea271
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.
- package/CHANGELOG.md +131 -0
- package/dist/adapters/mech/adapter.d.ts +23 -1
- package/dist/adapters/mech/adapter.js +169 -33
- package/dist/adapters/mech/adapter.js.map +1 -1
- package/dist/adapters/mech/contracts.d.ts +1 -0
- package/dist/adapters/mech/contracts.js +1 -0
- package/dist/adapters/mech/contracts.js.map +1 -1
- package/dist/adapters/mech/ipfs-pinfile.d.ts +22 -0
- package/dist/adapters/mech/ipfs-pinfile.js +54 -0
- package/dist/adapters/mech/ipfs-pinfile.js.map +1 -0
- package/dist/adapters/mech/ipfs.d.ts +1 -0
- package/dist/adapters/mech/ipfs.js +24 -1
- package/dist/adapters/mech/ipfs.js.map +1 -1
- package/dist/adapters/mech/verdict-code.d.ts +1 -0
- package/dist/adapters/mech/verdict-code.js +18 -0
- package/dist/adapters/mech/verdict-code.js.map +1 -1
- package/dist/api/bootstrap-endpoint.js +63 -1
- package/dist/api/bootstrap-endpoint.js.map +1 -1
- package/dist/api/codex-doctor-endpoint.d.ts +73 -0
- package/dist/api/codex-doctor-endpoint.js +158 -0
- package/dist/api/codex-doctor-endpoint.js.map +1 -0
- package/dist/api/discovery-endpoint.d.ts +31 -0
- package/dist/api/discovery-endpoint.js +78 -0
- package/dist/api/discovery-endpoint.js.map +1 -0
- package/dist/api/fleet-build.d.ts +8 -0
- package/dist/api/fleet-build.js +8 -2
- package/dist/api/fleet-build.js.map +1 -1
- package/dist/api/gather-status.js +90 -4
- package/dist/api/gather-status.js.map +1 -1
- package/dist/api/harness-readiness-endpoint.d.ts +25 -0
- package/dist/api/harness-readiness-endpoint.js +24 -0
- package/dist/api/harness-readiness-endpoint.js.map +1 -0
- package/dist/api/hermes-doctor-endpoint.d.ts +66 -0
- package/dist/api/hermes-doctor-endpoint.js +75 -0
- package/dist/api/hermes-doctor-endpoint.js.map +1 -0
- package/dist/api/portfolio-v0-build.d.ts +10 -0
- package/dist/api/portfolio-v0-build.js +24 -5
- package/dist/api/portfolio-v0-build.js.map +1 -1
- package/dist/api/prediction-v1-build.d.ts +9 -0
- package/dist/api/prediction-v1-build.js +6 -1
- package/dist/api/prediction-v1-build.js.map +1 -1
- package/dist/api/server.d.ts +70 -0
- package/dist/api/server.js +107 -1
- package/dist/api/server.js.map +1 -1
- package/dist/api/setup-endpoints.d.ts +21 -0
- package/dist/api/setup-endpoints.js +101 -8
- package/dist/api/setup-endpoints.js.map +1 -1
- package/dist/api/setup-retry-endpoint.d.ts +19 -0
- package/dist/api/setup-retry-endpoint.js +32 -0
- package/dist/api/setup-retry-endpoint.js.map +1 -0
- package/dist/api/solvernets-endpoints.js +8 -1
- package/dist/api/solvernets-endpoints.js.map +1 -1
- package/dist/api/status-build.d.ts +14 -0
- package/dist/api/status-build.js +23 -18
- package/dist/api/status-build.js.map +1 -1
- package/dist/api/task-run-routing.d.ts +7 -0
- package/dist/api/task-run-routing.js +12 -0
- package/dist/api/task-run-routing.js.map +1 -0
- package/dist/api/task-runs-build.d.ts +20 -0
- package/dist/api/task-runs-build.js +4 -0
- package/dist/api/task-runs-build.js.map +1 -1
- package/dist/build-info.json +4 -4
- package/dist/build-meta.json +1 -1
- package/dist/chain-read-errors.d.ts +10 -0
- package/dist/chain-read-errors.js +15 -0
- package/dist/chain-read-errors.js.map +1 -1
- package/dist/cli/commands/auth.js +3 -1
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/create.d.ts +5 -3
- package/dist/cli/commands/create.js +102 -36
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/solver-nets.d.ts +19 -0
- package/dist/cli/commands/solver-nets.js +164 -11
- package/dist/cli/commands/solver-nets.js.map +1 -1
- package/dist/cli/commands/solver-plugins-publish.d.ts +31 -0
- package/dist/cli/commands/solver-plugins-publish.js +169 -0
- package/dist/cli/commands/solver-plugins-publish.js.map +1 -0
- package/dist/cli/commands/solver-plugins-revoke.d.ts +15 -0
- package/dist/cli/commands/solver-plugins-revoke.js +91 -0
- package/dist/cli/commands/solver-plugins-revoke.js.map +1 -0
- package/dist/cli/commands/solver-plugins.d.ts +50 -6
- package/dist/cli/commands/solver-plugins.js +205 -68
- package/dist/cli/commands/solver-plugins.js.map +1 -1
- package/dist/cli/commands/update.d.ts +10 -0
- package/dist/cli/commands/update.js +36 -0
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/config.d.ts +51 -0
- package/dist/config.js +49 -2
- package/dist/config.js.map +1 -1
- package/dist/conformance/checks/hash-signature.js +6 -2
- package/dist/conformance/checks/hash-signature.js.map +1 -1
- package/dist/conformance/checks/payload.js +4 -2
- package/dist/conformance/checks/payload.js.map +1 -1
- package/dist/conformance/checks/verdict.d.ts +10 -10
- package/dist/conformance/checks/verdict.js +16 -15
- package/dist/conformance/checks/verdict.js.map +1 -1
- package/dist/conformance/harness.d.ts +1 -1
- package/dist/conformance/harness.js +16 -9
- package/dist/conformance/harness.js.map +1 -1
- package/dist/conformance/types.d.ts +10 -3
- package/dist/conformance/types.js.map +1 -1
- package/dist/corpus/acquire.d.ts +1 -3
- package/dist/corpus/acquire.js.map +1 -1
- package/dist/corpus/envelope-projection.d.ts +1 -1
- package/dist/corpus/envelope-projection.js +14 -7
- package/dist/corpus/envelope-projection.js.map +1 -1
- package/dist/corpus/index.d.ts +2 -1
- package/dist/corpus/index.js.map +1 -1
- package/dist/corpus/prediction-brier-scoreboard-report.js +1 -1
- package/dist/corpus/prediction-brier-scoreboard-report.js.map +1 -1
- package/dist/corpus/prediction-brier-scoreboard.js +3 -1
- package/dist/corpus/prediction-brier-scoreboard.js.map +1 -1
- package/dist/corpus/types.d.ts +2 -2
- package/dist/daemon/daemon.d.ts +26 -1
- package/dist/daemon/daemon.js +63 -1
- package/dist/daemon/daemon.js.map +1 -1
- package/dist/daemon/eviction-loop.d.ts +40 -0
- package/dist/daemon/eviction-loop.js +67 -0
- package/dist/daemon/eviction-loop.js.map +1 -0
- package/dist/daemon/freeze-fence.js +6 -3
- package/dist/daemon/freeze-fence.js.map +1 -1
- package/dist/daemon/readiness-gate.d.ts +30 -0
- package/dist/daemon/readiness-gate.js +31 -0
- package/dist/daemon/readiness-gate.js.map +1 -0
- package/dist/daemon/skip-log-dedup.d.ts +69 -0
- package/dist/daemon/skip-log-dedup.js +106 -0
- package/dist/daemon/skip-log-dedup.js.map +1 -0
- package/dist/dashboard/assets/{index-D_NMfDfV.css → index-DE4qUnzV.css} +1 -1
- package/dist/dashboard/assets/index-Di7xA4eB.js +170 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/discovery/http.js +121 -0
- package/dist/discovery/http.js.map +1 -1
- package/dist/discovery/onchain.d.ts +5 -0
- package/dist/discovery/onchain.js +292 -7
- package/dist/discovery/onchain.js.map +1 -1
- package/dist/discovery/types.d.ts +127 -1
- package/dist/discovery/types.js +8 -10
- package/dist/discovery/types.js.map +1 -1
- package/dist/discovery/with-fallback.js +9 -0
- package/dist/discovery/with-fallback.js.map +1 -1
- package/dist/earning/agent-wallet-binding.d.ts +20 -1
- package/dist/earning/agent-wallet-binding.js +54 -16
- package/dist/earning/agent-wallet-binding.js.map +1 -1
- package/dist/earning/bootstrap.d.ts +178 -0
- package/dist/earning/bootstrap.js +628 -57
- package/dist/earning/bootstrap.js.map +1 -1
- package/dist/earning/contracts.d.ts +12 -0
- package/dist/earning/contracts.js +16 -1
- package/dist/earning/contracts.js.map +1 -1
- package/dist/earning/funding-plan.js +15 -2
- package/dist/earning/funding-plan.js.map +1 -1
- package/dist/earning/jinn-rewards.d.ts +46 -0
- package/dist/earning/jinn-rewards.js +32 -0
- package/dist/earning/jinn-rewards.js.map +1 -1
- package/dist/earning/store.d.ts +8 -0
- package/dist/earning/store.js +48 -1
- package/dist/earning/store.js.map +1 -1
- package/dist/earning/testnet-setup-migration.d.ts +12 -0
- package/dist/earning/testnet-setup-migration.js +27 -1
- package/dist/earning/testnet-setup-migration.js.map +1 -1
- package/dist/earning/types.d.ts +45 -0
- package/dist/earning/types.js +37 -0
- package/dist/earning/types.js.map +1 -1
- package/dist/erc8004/abis.d.ts +64 -0
- package/dist/erc8004/abis.js +48 -0
- package/dist/erc8004/abis.js.map +1 -1
- package/dist/erc8004/plugin-registry.d.ts +102 -0
- package/dist/erc8004/plugin-registry.js +165 -0
- package/dist/erc8004/plugin-registry.js.map +1 -0
- package/dist/erc8004/reputation.d.ts +8 -0
- package/dist/erc8004/reputation.js +22 -3
- package/dist/erc8004/reputation.js.map +1 -1
- package/dist/events/types.d.ts +2 -2
- package/dist/harnesses/cost-estimates.d.ts +145 -0
- package/dist/harnesses/cost-estimates.js +297 -0
- package/dist/harnesses/cost-estimates.js.map +1 -0
- package/dist/harnesses/engine/engine.d.ts +40 -0
- package/dist/harnesses/engine/engine.js +69 -8
- package/dist/harnesses/engine/engine.js.map +1 -1
- package/dist/harnesses/engine/envelope-assembly.d.ts +2 -2
- package/dist/harnesses/engine/envelope-assembly.js +4 -2
- package/dist/harnesses/engine/envelope-assembly.js.map +1 -1
- package/dist/harnesses/engine/persistence.d.ts +21 -0
- package/dist/harnesses/engine/persistence.js +39 -0
- package/dist/harnesses/engine/persistence.js.map +1 -1
- package/dist/harnesses/engine/work-dir-reaper.d.ts +65 -0
- package/dist/harnesses/engine/work-dir-reaper.js +100 -0
- package/dist/harnesses/engine/work-dir-reaper.js.map +1 -0
- package/dist/harnesses/freeze.d.ts +4 -1
- package/dist/harnesses/freeze.js +12 -2
- package/dist/harnesses/freeze.js.map +1 -1
- package/dist/harnesses/impls/claude-mcp-prediction/index.d.ts +4 -1
- package/dist/harnesses/impls/claude-mcp-prediction/index.js +7 -2
- package/dist/harnesses/impls/claude-mcp-prediction/index.js.map +1 -1
- package/dist/harnesses/impls/claude-mcp-prediction-apy/index.d.ts +4 -1
- package/dist/harnesses/impls/claude-mcp-prediction-apy/index.js +7 -2
- package/dist/harnesses/impls/claude-mcp-prediction-apy/index.js.map +1 -1
- package/dist/harnesses/impls/evaluation-context.d.ts +15 -4
- package/dist/harnesses/impls/evaluation-context.js +24 -8
- package/dist/harnesses/impls/evaluation-context.js.map +1 -1
- package/dist/harnesses/impls/hermes-agent/adapter.d.ts +34 -0
- package/dist/harnesses/impls/hermes-agent/adapter.js +205 -0
- package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -0
- package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +18 -0
- package/dist/harnesses/impls/hermes-agent/bootstrap.js +231 -0
- package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -0
- package/dist/harnesses/impls/hermes-agent/config-builder.d.ts +49 -0
- package/dist/harnesses/impls/hermes-agent/config-builder.js +132 -0
- package/dist/harnesses/impls/hermes-agent/config-builder.js.map +1 -0
- package/dist/harnesses/impls/hermes-agent/harness.d.ts +58 -0
- package/dist/harnesses/impls/hermes-agent/harness.js +118 -0
- package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -0
- package/dist/harnesses/impls/hermes-agent/index.d.ts +5 -0
- package/dist/harnesses/impls/hermes-agent/index.js +7 -0
- package/dist/harnesses/impls/hermes-agent/index.js.map +1 -0
- package/dist/harnesses/impls/hermes-agent/prompt.d.ts +15 -0
- package/dist/harnesses/impls/hermes-agent/prompt.js +37 -0
- package/dist/harnesses/impls/hermes-agent/prompt.js.map +1 -0
- package/dist/harnesses/impls/index.d.ts +13 -0
- package/dist/harnesses/impls/index.js +32 -4
- package/dist/harnesses/impls/index.js.map +1 -1
- package/dist/harnesses/impls/learner/adapters/claude-code.js.map +1 -0
- package/dist/harnesses/impls/{claude-code-learner → learner}/adapters/codex-code.js +13 -34
- package/dist/harnesses/impls/learner/adapters/codex-code.js.map +1 -0
- package/dist/harnesses/impls/learner/adapters/codex-workspace.js.map +1 -0
- package/dist/harnesses/impls/learner/harness.d.ts +62 -0
- package/dist/harnesses/impls/learner/harness.js +179 -0
- package/dist/harnesses/impls/learner/harness.js.map +1 -0
- package/dist/harnesses/impls/{claude-code-learner → learner}/harvest.js +15 -3
- package/dist/harnesses/impls/learner/harvest.js.map +1 -0
- package/dist/harnesses/impls/{claude-code-learner → learner}/index.d.ts +5 -5
- package/dist/harnesses/impls/{claude-code-learner → learner}/index.js +4 -4
- package/dist/harnesses/impls/learner/index.js.map +1 -0
- package/dist/harnesses/impls/{claude-code-learner → learner}/plugin-path.d.ts +4 -4
- package/dist/harnesses/impls/{claude-code-learner → learner}/plugin-path.js +7 -7
- package/dist/harnesses/impls/learner/plugin-path.js.map +1 -0
- package/dist/harnesses/impls/{claude-code-learner → learner}/restoration-patch.js +3 -1
- package/dist/harnesses/impls/learner/restoration-patch.js.map +1 -0
- package/dist/harnesses/impls/learner/test-utils/fake-plugin-outputs.js.map +1 -0
- package/dist/harnesses/impls/learner/test-utils/noop-adapter.js.map +1 -0
- package/dist/harnesses/impls/{claude-code-learner → learner}/types.d.ts +23 -2
- package/dist/harnesses/impls/learner/types.js.map +1 -0
- package/dist/harnesses/impls/portfolio-v0-evaluator/index.js +13 -12
- package/dist/harnesses/impls/portfolio-v0-evaluator/index.js.map +1 -1
- package/dist/harnesses/impls/prediction-apy-v0-evaluator/index.js +7 -7
- package/dist/harnesses/impls/prediction-apy-v0-evaluator/index.js.map +1 -1
- package/dist/harnesses/impls/prediction-apy-v0-evaluator/parse-submission.d.ts +3 -3
- package/dist/harnesses/impls/prediction-apy-v0-evaluator/parse-submission.js +7 -6
- package/dist/harnesses/impls/prediction-apy-v0-evaluator/parse-submission.js.map +1 -1
- package/dist/harnesses/impls/prediction-v0-evaluator/checks/integrity.js +1 -1
- package/dist/harnesses/impls/prediction-v0-evaluator/checks/integrity.js.map +1 -1
- package/dist/harnesses/impls/prediction-v0-evaluator/index.js +11 -10
- package/dist/harnesses/impls/prediction-v0-evaluator/index.js.map +1 -1
- package/dist/harnesses/impls/prediction-v1-evaluator/index.js +11 -10
- package/dist/harnesses/impls/prediction-v1-evaluator/index.js.map +1 -1
- package/dist/harnesses/impls/stub.d.ts +58 -0
- package/dist/harnesses/impls/stub.js +89 -0
- package/dist/harnesses/impls/stub.js.map +1 -0
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.d.ts +1 -0
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +10 -2
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.d.ts +24 -5
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +104 -4
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +9 -0
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +25 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
- package/dist/harnesses/names.d.ts +1 -0
- package/dist/harnesses/names.js +3 -0
- package/dist/harnesses/names.js.map +1 -1
- package/dist/harnesses/readiness-registry.d.ts +48 -0
- package/dist/harnesses/readiness-registry.js +144 -0
- package/dist/harnesses/readiness-registry.js.map +1 -0
- package/dist/harnesses/types.d.ts +7 -0
- package/dist/main.d.ts +14 -0
- package/dist/main.js +372 -90
- package/dist/main.js.map +1 -1
- package/dist/mcp/server.js +14 -13
- package/dist/mcp/server.js.map +1 -1
- package/dist/operator-errors.d.ts +7 -0
- package/dist/operator-errors.js +26 -2
- package/dist/operator-errors.js.map +1 -1
- package/dist/preflight/claude-auth.d.ts +18 -0
- package/dist/preflight/claude-auth.js +38 -0
- package/dist/preflight/claude-auth.js.map +1 -1
- package/dist/restart-daemon.d.ts +71 -0
- package/dist/restart-daemon.js +82 -0
- package/dist/restart-daemon.js.map +1 -0
- package/dist/scripts/donation-consumption-acceptance.js +1 -1
- package/dist/scripts/donation-consumption-acceptance.js.map +1 -1
- package/dist/scripts/swe-rebench-v2-known-bad.json +12 -0
- package/dist/scripts/swe-rebench-v2-seed-pool.json +26 -0
- package/dist/setup/halt-mode.d.ts +14 -0
- package/dist/setup/halt-mode.js +17 -0
- package/dist/setup/halt-mode.js.map +1 -0
- package/dist/solver-nets/prediction-operator-ux.js +43 -3
- package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
- package/dist/solver-nets/registry.d.ts +1 -0
- package/dist/solver-nets/registry.js +1 -1
- package/dist/solver-nets/registry.js.map +1 -1
- package/dist/solver-types/_swe-rebench-v2-substrate.d.ts +52 -0
- package/dist/solver-types/_swe-rebench-v2-substrate.js +76 -0
- package/dist/solver-types/_swe-rebench-v2-substrate.js.map +1 -0
- package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +38 -12
- package/dist/solver-types/_swe-rebench-v2-validated-pool.js +136 -27
- package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
- package/dist/solver-types/swe-rebench-v2-auto.d.ts +6 -0
- package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
- package/dist/solver-types/swe-rebench-v2.d.ts +1 -0
- package/dist/solver-types/swe-rebench-v2.js +19 -6
- package/dist/solver-types/swe-rebench-v2.js.map +1 -1
- package/dist/solvernets/daemon-init.d.ts +10 -2
- package/dist/solvernets/daemon-init.js +22 -2
- package/dist/solvernets/daemon-init.js.map +1 -1
- package/dist/store/store.js +12 -4
- package/dist/store/store.js.map +1 -1
- package/dist/templates/plugins/runtime-plugin/.mcp.json.tmpl +8 -0
- package/dist/templates/plugins/runtime-plugin/README.md.tmpl +30 -0
- package/dist/templates/plugins/runtime-plugin/gitignore.tmpl +3 -0
- package/dist/templates/plugins/runtime-plugin/jinn.plugin.json.tmpl +21 -0
- package/dist/templates/plugins/runtime-plugin/mcp/server.mjs.tmpl +33 -0
- package/dist/templates/plugins/runtime-plugin/package.json.tmpl +15 -0
- package/dist/templates/plugins/runtime-plugin/test/plugin.test.ts.tmpl +35 -0
- package/dist/templates/plugins/runtime-plugin/tsconfig.json.tmpl +11 -0
- package/dist/templates/plugins/solver-type-plugin/README.md.tmpl +35 -0
- package/dist/templates/plugins/solver-type-plugin/gitignore.tmpl +3 -0
- package/dist/templates/plugins/solver-type-plugin/jinn.plugin.json.tmpl +11 -0
- package/dist/templates/plugins/solver-type-plugin/package.json.tmpl +15 -0
- package/dist/templates/plugins/solver-type-plugin/skills/example/SKILL.md.tmpl +10 -0
- package/dist/templates/plugins/solver-type-plugin/test/plugin.test.ts.tmpl +25 -0
- package/dist/templates/plugins/solver-type-plugin/tsconfig.json.tmpl +11 -0
- package/dist/tx-retry.d.ts +13 -0
- package/dist/tx-retry.js +22 -0
- package/dist/tx-retry.js.map +1 -1
- package/dist/types/envelope.d.ts +28 -21
- package/dist/types/envelope.js +8 -3
- package/dist/types/envelope.js.map +1 -1
- package/dist/types/payloads/index.d.ts +2 -2
- package/dist/types/payloads/index.js +13 -12
- package/dist/types/payloads/index.js.map +1 -1
- package/dist/types/payloads/portfolio-v0.d.ts +60 -10
- package/dist/types/payloads/portfolio-v0.js +16 -6
- package/dist/types/payloads/portfolio-v0.js.map +1 -1
- package/dist/types/payloads/prediction-apy-v0.d.ts +56 -14
- package/dist/types/payloads/prediction-apy-v0.js +16 -6
- package/dist/types/payloads/prediction-apy-v0.js.map +1 -1
- package/dist/types/payloads/prediction-v0.d.ts +53 -14
- package/dist/types/payloads/prediction-v0.js +16 -6
- package/dist/types/payloads/prediction-v0.js.map +1 -1
- package/dist/util/extract-tx-hash.d.ts +14 -0
- package/dist/util/extract-tx-hash.js +19 -0
- package/dist/util/extract-tx-hash.js.map +1 -0
- package/dist/vendor/@jinn-network/sdk/dist/payloads/prediction-v1.d.ts +45 -6
- package/dist/vendor/@jinn-network/sdk/dist/payloads/prediction-v1.js +16 -6
- package/dist/x402/handler.js +51 -20
- package/dist/x402/handler.js.map +1 -1
- package/package.json +38 -13
- package/plugins/swe-rebench-v2-diffmin/.claude-plugin/plugin.json +5 -0
- package/plugins/swe-rebench-v2-diffmin/.mcp.json +8 -0
- package/plugins/swe-rebench-v2-diffmin/README.md +69 -0
- package/plugins/swe-rebench-v2-diffmin/jinn.plugin.json +12 -0
- package/plugins/swe-rebench-v2-diffmin/mcp/diff-stats-server.mjs +72 -0
- package/plugins/swe-rebench-v2-diffmin/mcp/diff-stats.mjs +48 -0
- package/plugins/swe-rebench-v2-diffmin/package.json +19 -0
- package/plugins/swe-rebench-v2-diffmin/skills/diffmin/SKILL.md +116 -0
- package/plugins/swe-rebench-v2-diffmin/skills/test-map/SKILL.md +126 -0
- package/plugins/swe-rebench-v2-diffmin/test/diff-stats.test.ts +62 -0
- package/plugins/swe-rebench-v2-diffmin/test/manifest.test.ts +53 -0
- package/plugins/swe-rebench-v2-diffmin/tsconfig.json +12 -0
- package/plugins/swe-rebench-v2-runtime/README.md +13 -0
- package/plugins/swe-rebench-v2-runtime/skills/orient/SKILL.md +7 -3
- package/plugins/swe-rebench-v2-runtime/skills/plan/SKILL.md +6 -17
- package/templates/plugins/runtime-plugin/.mcp.json.tmpl +8 -0
- package/templates/plugins/runtime-plugin/README.md.tmpl +30 -0
- package/templates/plugins/runtime-plugin/gitignore.tmpl +3 -0
- package/templates/plugins/runtime-plugin/jinn.plugin.json.tmpl +21 -0
- package/templates/plugins/runtime-plugin/mcp/server.mjs.tmpl +33 -0
- package/templates/plugins/runtime-plugin/package.json.tmpl +15 -0
- package/templates/plugins/runtime-plugin/test/plugin.test.ts.tmpl +35 -0
- package/templates/plugins/runtime-plugin/tsconfig.json.tmpl +11 -0
- package/templates/plugins/solver-type-plugin/README.md.tmpl +35 -0
- package/templates/plugins/solver-type-plugin/gitignore.tmpl +3 -0
- package/templates/plugins/solver-type-plugin/jinn.plugin.json.tmpl +11 -0
- package/templates/plugins/solver-type-plugin/package.json.tmpl +15 -0
- package/templates/plugins/solver-type-plugin/skills/example/SKILL.md.tmpl +10 -0
- package/templates/plugins/solver-type-plugin/test/plugin.test.ts.tmpl +25 -0
- package/templates/plugins/solver-type-plugin/tsconfig.json.tmpl +11 -0
- package/dist/dashboard/assets/index-BjtltOGc.js +0 -76
- package/dist/harnesses/impls/claude-code-learner/adapters/claude-code.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/adapters/codex-code.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/adapters/codex-workspace.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/harness.d.ts +0 -22
- package/dist/harnesses/impls/claude-code-learner/harness.js +0 -62
- package/dist/harnesses/impls/claude-code-learner/harness.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/harvest.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/index.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/plugin-path.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/restoration-patch.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/test-utils/fake-plugin-outputs.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/test-utils/noop-adapter.js.map +0 -1
- package/dist/harnesses/impls/claude-code-learner/types.js.map +0 -1
- package/dist/preflight/claude-required.d.ts +0 -8
- package/dist/preflight/claude-required.js +0 -17
- package/dist/preflight/claude-required.js.map +0 -1
- /package/dist/harnesses/impls/{claude-code-learner → learner}/adapters/claude-code.d.ts +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/adapters/claude-code.js +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/adapters/codex-code.d.ts +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/adapters/codex-workspace.d.ts +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/adapters/codex-workspace.js +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/harvest.d.ts +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/restoration-patch.d.ts +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/test-utils/fake-plugin-outputs.d.ts +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/test-utils/fake-plugin-outputs.js +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/test-utils/noop-adapter.d.ts +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/test-utils/noop-adapter.js +0 -0
- /package/dist/harnesses/impls/{claude-code-learner → learner}/types.js +0 -0
- /package/plugins/{claude-code-learner → learner}/.claude-plugin/plugin.json +0 -0
- /package/plugins/{claude-code-learner → learner}/.codex-plugin/plugin.json +0 -0
- /package/plugins/{claude-code-learner → learner}/AGENTS.md +0 -0
- /package/plugins/{claude-code-learner → learner}/CLAUDE.md +0 -0
- /package/plugins/{claude-code-learner → learner}/README.md +0 -0
- /package/plugins/{claude-code-learner → learner}/hooks/hooks.json +0 -0
- /package/plugins/{claude-code-learner → learner}/hooks/session-start +0 -0
- /package/plugins/{claude-code-learner → learner}/skills/learn/SKILL.md +0 -0
- /package/plugins/{claude-code-learner → learner}/skills/learn/analyst-prompt.md +0 -0
- /package/plugins/{claude-code-learner → learner}/skills/learn/consolidator-prompt.md +0 -0
- /package/plugins/{claude-code-learner → learner}/skills/learn/explorer-prompt.md +0 -0
- /package/plugins/{claude-code-learner → learner}/skills/learn/planner-prompt.md +0 -0
- /package/plugins/{claude-code-learner → learner}/skills/learn/promoter-prompt.md +0 -0
- /package/plugins/{claude-code-learner → learner}/skills/learn/step-worker-prompt.md +0 -0
- /package/plugins/{claude-code-learner → learner}/skills/learn/strategist-prompt.md +0 -0
|
@@ -15,20 +15,121 @@ import { formatBootstrapOperatorMessage, isJinnDebug, } from '../operator-errors
|
|
|
15
15
|
import { reconcileServiceAgainstChain, } from './reconcile.js';
|
|
16
16
|
import { previousSafeBeingAbandoned, sweepOrphanedServiceFunds, } from './orphan-sweep.js';
|
|
17
17
|
import { DEFAULT_FAUCET_LOOP_TIMEOUT_MS, computeFaucetDripCap, requestTestnetFunding, } from './faucet.js';
|
|
18
|
-
import { flattenErrorMessage, viemSendTransactionWithRetry, waitForTransactionReceiptWithRetry, } from '../tx-retry.js';
|
|
18
|
+
import { flattenErrorMessage, sleep, viemSendTransactionWithRetry, waitForContractCode, waitForTransactionReceiptWithRetry, } from '../tx-retry.js';
|
|
19
19
|
import { isUnauthorizedAccountError } from '../errors/unauthorized-account.js';
|
|
20
20
|
import { createJinnPublicClient, createJinnWalletClient } from './viem-clients.js';
|
|
21
21
|
import { isTransientEthReadError } from '../chain-read-errors.js';
|
|
22
22
|
import { nextFleetServiceIndex } from './next-service-index.js';
|
|
23
|
+
import { displayFleetServiceIndex } from './fleet-display-index.js';
|
|
23
24
|
import { rpcHostForDisplay } from '../preflight/rpc-network.js';
|
|
24
25
|
import { detectDeprecatedTestnetSetup, migrateDeprecatedTestnetSetup, } from './testnet-setup-migration.js';
|
|
25
26
|
const addr = (value) => getAddress(value);
|
|
26
27
|
const SAFE_TOKEN_BOOTSTRAP_MULTIPLIER = 2n;
|
|
27
|
-
|
|
28
|
+
/**
|
|
29
|
+
* 2× cold-start headroom for master ETH target on a fresh bootstrap.
|
|
30
|
+
*
|
|
31
|
+
* Gas accounting for a single standard-mode service on first run:
|
|
32
|
+
* ~1.3M gas for the Safe deploy + stake + mech (at 2 gwei ≈ 0.0026 ETH)
|
|
33
|
+
* + 0.002 ETH Safe seed (sent to the Safe so it can pay mech fees)
|
|
34
|
+
* ≈ 0.0046 ETH minimum; 2× gives ≈ 0.009–0.010 ETH — the bootstrap
|
|
35
|
+
* `minEoaGasEth` default.
|
|
36
|
+
*
|
|
37
|
+
* The multiplier only applies when no service has a persisted `service_id`
|
|
38
|
+
* on-chain (i.e. the fleet is truly cold — OR migration-wiped, where
|
|
39
|
+
* services exist in shape but lost their on-chain anchor). Once any service
|
|
40
|
+
* has committed a `service_id`, the fleet is past the cold-start cliff and
|
|
41
|
+
* 1× suffices.
|
|
42
|
+
*
|
|
43
|
+
* Single source of truth: imported by funding-plan.ts.
|
|
44
|
+
*/
|
|
45
|
+
export const STANDARD_MASTER_BOOTSTRAP_MULTIPLIER = 2n;
|
|
46
|
+
/**
|
|
47
|
+
* Compute the required master ETH gate for the standard staking mode.
|
|
48
|
+
*
|
|
49
|
+
* @param services Persisted service states
|
|
50
|
+
* @param minEoaGasEth Configured minimum EOA gas target (wei)
|
|
51
|
+
* @param standardMultiplier Cold-start multiplier (defaults to {@link STANDARD_MASTER_BOOTSTRAP_MULTIPLIER})
|
|
52
|
+
* @param pendingSetupMigration True when deprecated testnet setup detected
|
|
53
|
+
* @param targetServices How many services the fleet is aiming for
|
|
54
|
+
*/
|
|
55
|
+
export function computeRequiredMasterEth({ services, minEoaGasEth, standardMultiplier = STANDARD_MASTER_BOOTSTRAP_MULTIPLIER, pendingSetupMigration = false, targetServices = 1, }) {
|
|
56
|
+
const completedCount = services.filter(s => s.step !== undefined && isOperationalServiceStep(s.step)).length;
|
|
57
|
+
const standardFleetAlreadyComplete = !pendingSetupMigration && completedCount >= targetServices;
|
|
58
|
+
if (standardFleetAlreadyComplete)
|
|
59
|
+
return 0n;
|
|
60
|
+
// "Cold in liability" = no service has an on-chain anchor yet.
|
|
61
|
+
// This includes:
|
|
62
|
+
// 1. Fresh fleet (services array is empty)
|
|
63
|
+
// 2. Migration-wiped fleet (services exist in shape but service_id === null)
|
|
64
|
+
// Apply the 2× headroom multiplier in both cases.
|
|
65
|
+
const hasPersistedOnChain = services.some(s => s.service_id != null);
|
|
66
|
+
return minEoaGasEth * (hasPersistedOnChain ? 1n : standardMultiplier);
|
|
67
|
+
}
|
|
68
|
+
/** Master ETH required to FINISH the whole bootstrap from a fresh start (not
|
|
69
|
+
* just to enter Stage 1). Centralized so the daemon's ensureStage1 gate,
|
|
70
|
+
* the read-side funding-plan, gather-status, and the panel faucet target
|
|
71
|
+
* all agree on a single "one-shot fund the operator" number.
|
|
72
|
+
*
|
|
73
|
+
* Components for a 1-service standard-mode bootstrap:
|
|
74
|
+
* - STAGE1_AGENT_ETH (0.010 ETH): master → HD-1 fleet-agent transfer.
|
|
75
|
+
* HD-1 pays for its own Safe deploy + register + setAgentWallet out
|
|
76
|
+
* of this; leftover covers service 1's Stage 2 work (mech deploy +
|
|
77
|
+
* rebind). May get a conditional minEoaGasEth top-up from master if
|
|
78
|
+
* Stage 1's gas eats too much of the original transfer.
|
|
79
|
+
* - minEoaGasEth × STANDARD_MASTER_BOOTSTRAP_MULTIPLIER (0.010 ETH):
|
|
80
|
+
* master gas budget across both stages. Real spend (~0.0025 ETH at
|
|
81
|
+
* typical 6 gwei Base Sepolia) leaves room for ~4× gas-spike margin
|
|
82
|
+
* plus the conditional HD-1 top-up.
|
|
83
|
+
* - minEoaGasEth × (targetServices - 1): per-extra-service top-up for
|
|
84
|
+
* services 2..N. Service 1 piggybacks on HD-1's Stage 1 funding.
|
|
85
|
+
*
|
|
86
|
+
* Total for N=1: 0.010 + 0.010 = 0.020 ETH.
|
|
87
|
+
* Total for N=2: 0.025 ETH.
|
|
88
|
+
* Total for N=3: 0.030 ETH.
|
|
89
|
+
*
|
|
90
|
+
* This number works ONLY when Stage 2's internal gate is `minEoaGasEth ×
|
|
91
|
+
* 1n` (0.005 ETH) — not the historic `× 2n`. After Stage 1 transfers 0.010
|
|
92
|
+
* out, master sits at ~0.0099 ETH (0.020 minus transfer minus Stage 1
|
|
93
|
+
* funding-tx gas). The 0.005 gate clears that with margin; the 0.010 gate
|
|
94
|
+
* did not. See the Stage 2 gate at ensureStage1And2 line ~484.
|
|
95
|
+
*
|
|
96
|
+
* Operator may see a "low runway" warning after bootstrap — that's
|
|
97
|
+
* intentional. The operator-facing 0.020 ETH covers bootstrap completion,
|
|
98
|
+
* not multi-week post-bootstrap runway. Top-up is a separate concern.
|
|
99
|
+
*/
|
|
100
|
+
export const STAGE1_AGENT_ETH = 10000000000000000n; // 0.01 ETH (moved out of stepFleetSafeDeploy)
|
|
101
|
+
export function stage1MinMasterEth(config, targetServices = 1) {
|
|
102
|
+
const extraServiceTransfers = config.minEoaGasEth * BigInt(Math.max(0, targetServices - 1));
|
|
103
|
+
return (STAGE1_AGENT_ETH +
|
|
104
|
+
config.minEoaGasEth * STANDARD_MASTER_BOOTSTRAP_MULTIPLIER +
|
|
105
|
+
extraServiceTransfers);
|
|
106
|
+
}
|
|
28
107
|
/** Conservative default: ~0.001 ETH/day master gas if not configured. */
|
|
29
108
|
const DEFAULT_MASTER_ETH_DAILY_WEI = 1000000000000000n;
|
|
30
109
|
/** Warn when ETH above the minimum would last fewer than this many days at the daily estimate. */
|
|
31
110
|
const MASTER_ETH_RUNWAY_WARN_DAYS = 7n;
|
|
111
|
+
/**
|
|
112
|
+
* Safe → ERC-8004 agent NFT binding retry (jinn-mono-h74p).
|
|
113
|
+
*
|
|
114
|
+
* Empirical observation against fresh Base Sepolia 1/1 Safes: the first
|
|
115
|
+
* `IdentityRegistry.setAgentWallet` attempt reverts with a generic
|
|
116
|
+
* "Execution reverted for an unknown reason" — but the same Safe + same
|
|
117
|
+
* agentId + a freshly-signed message a few seconds later succeeds. The
|
|
118
|
+
* race window is likely freshly-deployed-Safe state lag on the public RPC
|
|
119
|
+
* (the simulator can't read the Safe's storage yet in the same block /
|
|
120
|
+
* eventual-consistency between sibling RPC nodes). A short bounded retry
|
|
121
|
+
* makes the operator-visible behaviour deterministic instead of relying on
|
|
122
|
+
* the "daemon exits → operator restarts → resume at safe_binding_pending"
|
|
123
|
+
* accidental safety net (which goes away when jinn-mono-vh74.2 removes the
|
|
124
|
+
* Claude-auth post-bootstrap exit gate).
|
|
125
|
+
*
|
|
126
|
+
* Defaults: 3 attempts × 3 s delay = at most ~6 s of in-process retry budget
|
|
127
|
+
* before falling through to the existing `safe_binding_pending` persisted
|
|
128
|
+
* state. Real (non-transient) failures still surface — just with a slightly
|
|
129
|
+
* higher latency tax for the diagnostic.
|
|
130
|
+
*/
|
|
131
|
+
const DEFAULT_SAFE_BINDING_MAX_ATTEMPTS = 3;
|
|
132
|
+
const DEFAULT_SAFE_BINDING_RETRY_DELAY_MS = 3_000;
|
|
32
133
|
export class FleetBootstrapper {
|
|
33
134
|
store;
|
|
34
135
|
config;
|
|
@@ -43,6 +144,8 @@ export class FleetBootstrapper {
|
|
|
43
144
|
faucetLoopTimeoutMs;
|
|
44
145
|
now;
|
|
45
146
|
autoTestnetFaucet;
|
|
147
|
+
safeBindingMaxAttempts;
|
|
148
|
+
safeBindingRetryDelayMs;
|
|
46
149
|
constructor(options = {}) {
|
|
47
150
|
this.store = new FleetStateStore(options.earningDir);
|
|
48
151
|
this.chain = options.chain ?? 'base';
|
|
@@ -55,6 +158,10 @@ export class FleetBootstrapper {
|
|
|
55
158
|
this.now = options.now ?? Date.now;
|
|
56
159
|
this.autoTestnetFaucet =
|
|
57
160
|
options.autoTestnetFaucet ?? this.env['JINN_DISABLE_TESTNET_FAUCET'] !== '1';
|
|
161
|
+
this.safeBindingMaxAttempts =
|
|
162
|
+
options.safeBindingMaxAttempts ?? DEFAULT_SAFE_BINDING_MAX_ATTEMPTS;
|
|
163
|
+
this.safeBindingRetryDelayMs =
|
|
164
|
+
options.safeBindingRetryDelayMs ?? DEFAULT_SAFE_BINDING_RETRY_DELAY_MS;
|
|
58
165
|
const dailyOpt = options.masterEthDailyEstimateWei;
|
|
59
166
|
this.masterEthDailyEstimateWei =
|
|
60
167
|
dailyOpt !== undefined
|
|
@@ -77,6 +184,71 @@ export class FleetBootstrapper {
|
|
|
77
184
|
async getStatus() {
|
|
78
185
|
return this.store.load(this.chain);
|
|
79
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Run `bindAgentWalletToSafe` with the freshly-deployed-Safe race retry
|
|
189
|
+
* (jinn-mono-h74p, corrected in jinn-mono-k1ng).
|
|
190
|
+
*
|
|
191
|
+
* The race: against a fresh 1/1 Safe on Base Sepolia, the first
|
|
192
|
+
* setAgentWallet attempt reverts with "Execution reverted for an unknown
|
|
193
|
+
* reason"; the same Safe + same agentId a few seconds later succeeds.
|
|
194
|
+
*
|
|
195
|
+
* The h74p version of the retry only wrapped the call in a try/catch.
|
|
196
|
+
* In production, `bindAgentWalletToSafe` doesn't throw on revert — it
|
|
197
|
+
* returns a `{ ok: false, error }` outcome — so the catch never fired
|
|
198
|
+
* and the retry was dead code. The per-service path "worked" anyway
|
|
199
|
+
* because it persists `safe_binding_pending` and the next bootstrap
|
|
200
|
+
* resumes the bind. Stage 1 had no equivalent safety net, so a single
|
|
201
|
+
* `ok: false` halted bootstrap (the 2026-05-18 canary failure).
|
|
202
|
+
*
|
|
203
|
+
* This wrapper:
|
|
204
|
+
* - Retries on returned `ok: false` (the way the race actually
|
|
205
|
+
* manifests in production).
|
|
206
|
+
* - Also retries on thrown exceptions (defense-in-depth in case viem
|
|
207
|
+
* error handling changes).
|
|
208
|
+
* - Returns the final outcome; callers decide whether to throw, mark
|
|
209
|
+
* pending, or proceed.
|
|
210
|
+
*
|
|
211
|
+
* Single attempt budget: `safeBindingMaxAttempts` × `safeBindingRetryDelayMs`
|
|
212
|
+
* (defaults: 3 × 3 s = ~9 s).
|
|
213
|
+
*/
|
|
214
|
+
async bindAgentWalletWithRetry(args, label) {
|
|
215
|
+
const maxAttempts = Math.max(1, this.safeBindingMaxAttempts);
|
|
216
|
+
let lastResult;
|
|
217
|
+
let lastThrowError;
|
|
218
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
219
|
+
try {
|
|
220
|
+
lastResult = await bindAgentWalletToSafe(args);
|
|
221
|
+
if (lastResult.ok)
|
|
222
|
+
return lastResult;
|
|
223
|
+
if (attempt < maxAttempts) {
|
|
224
|
+
console.error(`[fleet-bootstrap] ${label}: setAgentWallet attempt ` +
|
|
225
|
+
`${attempt}/${maxAttempts} returned ok=false (${lastResult.error.shortMessage}); ` +
|
|
226
|
+
`retrying in ${this.safeBindingRetryDelayMs}ms...`);
|
|
227
|
+
if (this.safeBindingRetryDelayMs > 0) {
|
|
228
|
+
await sleep(this.safeBindingRetryDelayMs);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
lastThrowError = err;
|
|
234
|
+
if (attempt < maxAttempts) {
|
|
235
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
236
|
+
console.error(`[fleet-bootstrap] ${label}: setAgentWallet attempt ` +
|
|
237
|
+
`${attempt}/${maxAttempts} threw (${reason}); retrying in ` +
|
|
238
|
+
`${this.safeBindingRetryDelayMs}ms...`);
|
|
239
|
+
if (this.safeBindingRetryDelayMs > 0) {
|
|
240
|
+
await sleep(this.safeBindingRetryDelayMs);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (lastResult)
|
|
246
|
+
return lastResult; // final ok:false propagated to caller
|
|
247
|
+
// Only thrown all the way through — no successful response or returned outcome.
|
|
248
|
+
throw lastThrowError instanceof Error
|
|
249
|
+
? lastThrowError
|
|
250
|
+
: new Error(String(lastThrowError));
|
|
251
|
+
}
|
|
80
252
|
/**
|
|
81
253
|
* Conservative daily master gas (wei): max(DEFAULT, rough tx count from poll interval × cost).
|
|
82
254
|
*/
|
|
@@ -112,16 +284,149 @@ export class FleetBootstrapper {
|
|
|
112
284
|
const mnemonic = await this.loadExistingMnemonic(state, password);
|
|
113
285
|
return this.stepRegisterAgent(state, mnemonic, serviceIndex);
|
|
114
286
|
}
|
|
115
|
-
|
|
116
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Stage 1 — Identity (universal). Walks: wallet → predict Safe (from
|
|
289
|
+
* HD-index-1 agent EOA) → ETH funding gate → deploy Safe → mint agentId
|
|
290
|
+
* + setAgentWallet via ERC-1271. Idempotent and re-entrant. Does NOT
|
|
291
|
+
* touch service rows or staking — those belong to Stage 2.
|
|
292
|
+
*
|
|
293
|
+
* Fleet-level fields written:
|
|
294
|
+
* - fleet_safe_address (after predict)
|
|
295
|
+
* - fleet_agent_id, fleet_identity_registry, fleet_stage='stage1'
|
|
296
|
+
* (after mint + bind)
|
|
297
|
+
*
|
|
298
|
+
* Funding gate: requires ETH on the master EOA only (no OLAS). On testnet,
|
|
299
|
+
* the existing CDP faucet loop drains as usual when `autoTestnetFaucet`
|
|
300
|
+
* is enabled.
|
|
301
|
+
*
|
|
302
|
+
* See docs/superpowers/specs/2026-05-13-plug-in-builder-entry-point-design.md §5.1.
|
|
303
|
+
*/
|
|
304
|
+
async ensureStage1(password) {
|
|
305
|
+
// Legacy keystore migration (same as bootstrap()).
|
|
117
306
|
if (!this.store.hasMnemonicKeystore() && this.store.hasLegacyKeystore()) {
|
|
118
307
|
await this.store.migrateLegacyFiles();
|
|
119
308
|
}
|
|
120
309
|
let state = await this.store.load(this.chain);
|
|
310
|
+
// Short-circuit if Stage 1 is already complete (or beyond).
|
|
311
|
+
if (state.fleet_stage === 'stage1' || state.fleet_stage === 'stage1_and_2') {
|
|
312
|
+
// Even when stage marker says complete, fleet identity may be empty for
|
|
313
|
+
// pre-j07 operators (`stage1_and_2` is set by the migration for
|
|
314
|
+
// services-complete-but-no-agent_id operators). In that case we leave
|
|
315
|
+
// Stage 1 alone — the legacy backfill in main.ts handles those rows
|
|
316
|
+
// and a future ensureStage1 call after backfill will promote.
|
|
317
|
+
return {
|
|
318
|
+
ok: true,
|
|
319
|
+
fleet_state: state,
|
|
320
|
+
message: state.fleet_agent_id !== null
|
|
321
|
+
? `Stage 1 already complete (fleet_agent_id=${state.fleet_agent_id}, fleet_safe=${state.fleet_safe_address}).`
|
|
322
|
+
: 'Stage 1 marker present but fleet identity is empty (legacy operator). Skipping.',
|
|
323
|
+
};
|
|
324
|
+
}
|
|
121
325
|
try {
|
|
122
|
-
// Phase 1: Master wallet setup
|
|
123
326
|
state = await this.ensureMasterWallet(state, password);
|
|
124
|
-
//
|
|
327
|
+
// Stage 1 funding gate — ETH only (no OLAS). Stage 1 needs
|
|
328
|
+
// STAGE1_AGENT_ETH (0.01) for the master → agent transfer plus
|
|
329
|
+
// minEoaGasEth (0.005) reserved for the master's own gas to send that
|
|
330
|
+
// transfer. The agent EOA then pays for Safe deploy + ERC-8004 register
|
|
331
|
+
// + setAgentWallet out of the funds it just received.
|
|
332
|
+
// See jinn-mono-u34i: pre-fix this gate was 2×minEoaGasEth (= 0.01 ETH),
|
|
333
|
+
// which equaled the transfer amount and left no gas headroom, so a
|
|
334
|
+
// master holding the gate's minimum would fail eth_estimateGas with
|
|
335
|
+
// "gas required exceeds allowance (0)".
|
|
336
|
+
const requiredMasterEth = stage1MinMasterEth(this.config, this.targetServices);
|
|
337
|
+
const masterAddress = state.master_address;
|
|
338
|
+
const masterBalance = await this.publicClient.getBalance({
|
|
339
|
+
address: masterAddress,
|
|
340
|
+
});
|
|
341
|
+
if (masterBalance < requiredMasterEth) {
|
|
342
|
+
const shortfall = requiredMasterEth - masterBalance;
|
|
343
|
+
return {
|
|
344
|
+
ok: false,
|
|
345
|
+
fleet_state: state,
|
|
346
|
+
message: `Your master wallet needs more ETH (currently ${formatEther(masterBalance)} ETH, need ${formatEther(shortfall)} ETH more) to complete Stage 1. Please send ETH to: ${masterAddress}`,
|
|
347
|
+
funding: {
|
|
348
|
+
master_address: masterAddress,
|
|
349
|
+
eth_required: shortfall.toString(),
|
|
350
|
+
eth_balance: masterBalance.toString(),
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
const mnemonic = await this.loadExistingMnemonic(state, password);
|
|
355
|
+
// Step 1: predict fleet Safe from HD-index-1 agent EOA.
|
|
356
|
+
if (!state.fleet_safe_address) {
|
|
357
|
+
state = await this.stepFleetSafePredict(state, mnemonic);
|
|
358
|
+
}
|
|
359
|
+
// Step 2: deploy fleet Safe if bytecode absent.
|
|
360
|
+
const safeCode = await this.publicClient.getCode({
|
|
361
|
+
address: getAddress(state.fleet_safe_address),
|
|
362
|
+
});
|
|
363
|
+
if (safeCode === undefined || safeCode === '0x') {
|
|
364
|
+
state = await this.stepFleetSafeDeploy(state, mnemonic);
|
|
365
|
+
}
|
|
366
|
+
// Step 3: mint agentId + bind Safe via setAgentWallet.
|
|
367
|
+
if (!state.fleet_agent_id) {
|
|
368
|
+
state = await this.stepFleetIdentityRegister(state, mnemonic);
|
|
369
|
+
}
|
|
370
|
+
else if (state.fleet_stage !== 'stage1' && state.fleet_stage !== 'stage1_and_2') {
|
|
371
|
+
// Identity was minted but stage marker is stale; advance it.
|
|
372
|
+
state = await this.store.patchFleet({ fleet_stage: 'stage1' });
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
ok: true,
|
|
376
|
+
fleet_state: state,
|
|
377
|
+
message: `Stage 1 complete. fleet_agent_id=${state.fleet_agent_id}, fleet_safe=${state.fleet_safe_address}.`,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
const { summary, hint, rawMessage } = formatBootstrapOperatorMessage(error);
|
|
382
|
+
const userMessage = hint !== undefined ? `${summary}\nHint: ${hint}` : summary;
|
|
383
|
+
if (this.debug) {
|
|
384
|
+
console.error(`[fleet-bootstrap] ensureStage1 failed:`, error);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
console.error(`[fleet-bootstrap] ${summary}`);
|
|
388
|
+
if (hint !== undefined)
|
|
389
|
+
console.error(`Hint: ${hint}`);
|
|
390
|
+
if (rawMessage && rawMessage !== summary) {
|
|
391
|
+
console.error(`[fleet-bootstrap] raw: ${rawMessage.split('\n')[0]}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
ok: false,
|
|
396
|
+
fleet_state: state,
|
|
397
|
+
message: userMessage,
|
|
398
|
+
rawErrorMessage: rawMessage,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Stage 1 + Stage 2 — full operator bootstrap. Calls `ensureStage1`
|
|
404
|
+
* first; on success, walks Stage 2 per service. Builder-only users who
|
|
405
|
+
* have completed Stage 1 and call this method later begin Stage 2 from
|
|
406
|
+
* `awaiting_stake` for the first service row (created lazily here).
|
|
407
|
+
*
|
|
408
|
+
* Two-Safe topology in standard mode: `fleet_safe_address !==
|
|
409
|
+
* services[0].safe_address` because Stage 2's `distributor.stake()`
|
|
410
|
+
* creates its own Safe. In self-bond mode the two converge (both
|
|
411
|
+
* derived from HD-index-1).
|
|
412
|
+
*
|
|
413
|
+
* See docs/superpowers/specs/2026-05-13-plug-in-builder-entry-point-design.md §5.1.
|
|
414
|
+
*/
|
|
415
|
+
async ensureStage1And2(password) {
|
|
416
|
+
// Stage 1 first — establishes fleet identity. Short-circuits if already done.
|
|
417
|
+
const stage1Result = await this.ensureStage1(password);
|
|
418
|
+
if (!stage1Result.ok) {
|
|
419
|
+
return stage1Result;
|
|
420
|
+
}
|
|
421
|
+
// Original bootstrap body — copied verbatim from the previous bootstrap()
|
|
422
|
+
// method, with two changes:
|
|
423
|
+
// (a) the legacy-keystore migration and master-wallet-ensure are no-ops
|
|
424
|
+
// because ensureStage1 already ran them.
|
|
425
|
+
// (b) at the end, if any service reached `complete`/`safe_binding_pending`
|
|
426
|
+
// we advance `fleet_stage` to `'stage1_and_2'`.
|
|
427
|
+
let state = stage1Result.fleet_state;
|
|
428
|
+
try {
|
|
429
|
+
// Phase 1b: Check master funding for the full operator path.
|
|
125
430
|
const masterAddress = state.master_address;
|
|
126
431
|
let masterBalance = await this.publicClient.getBalance({ address: masterAddress });
|
|
127
432
|
// Self-bond mode needs much more ETH than standard mode because the master
|
|
@@ -151,15 +456,24 @@ export class FleetBootstrapper {
|
|
|
151
456
|
stakingMode: this.stakingMode,
|
|
152
457
|
currentStakingContract: this.config.stakingContract,
|
|
153
458
|
}).services.length > 0;
|
|
154
|
-
const completedCountBeforeFunding = state.services.filter(s => isOperationalServiceStep(s.step)).length;
|
|
155
459
|
const standardFleetAlreadyComplete = this.stakingMode === 'standard' &&
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
460
|
+
state.services.length >= this.targetServices &&
|
|
461
|
+
state.services.every(svc => svc.step !== undefined && isOperationalServiceStep(svc.step)) &&
|
|
462
|
+
!pendingSetupMigration;
|
|
159
463
|
const requiredMasterEth = this.stakingMode === 'standard'
|
|
160
464
|
? (standardFleetAlreadyComplete
|
|
161
465
|
? 0n
|
|
162
|
-
|
|
466
|
+
// Stage 2 master gas budget — covers distributor.stake() (~0.003
|
|
467
|
+
// ETH at typical 6 gwei Base Sepolia) plus per-extra-service
|
|
468
|
+
// top-up transfers. Previously this was `× 2` for fresh fleets,
|
|
469
|
+
// which double-counted a service-1 transfer that doesn't actually
|
|
470
|
+
// fire (HD-1 carries Stage 1 leftover, gets a conditional top-up
|
|
471
|
+
// only if needed). See jinn-mono-u34i: the `× 2` figure also
|
|
472
|
+
// exceeded the post-Stage-1 master balance at the operator-facing
|
|
473
|
+
// 0.020 ETH budget by ~127k gwei of Stage 1 gas burn, causing a
|
|
474
|
+
// second funding prompt.
|
|
475
|
+
: this.config.minEoaGasEth +
|
|
476
|
+
this.config.minEoaGasEth * BigInt(Math.max(0, this.targetServices - 1)))
|
|
163
477
|
: SELF_BOND_ETH_PER_SERVICE * BigInt(this.targetServices);
|
|
164
478
|
const autoFaucetEnabled = this.autoTestnetFaucet;
|
|
165
479
|
// Re-sum system ETH (master + agent/safe balances for self-bond mode).
|
|
@@ -291,6 +605,11 @@ export class FleetBootstrapper {
|
|
|
291
605
|
const nextIndex = nextFleetServiceIndex(state.services);
|
|
292
606
|
state = await this.bootstrapService(state, mnemonic, nextIndex);
|
|
293
607
|
}
|
|
608
|
+
// Advance fleet_stage to 'stage1_and_2' if any service is operational.
|
|
609
|
+
const anyOperationalAfter = state.services.some(s => isOperationalServiceStep(s.step));
|
|
610
|
+
if (anyOperationalAfter && state.fleet_stage !== 'stage1_and_2') {
|
|
611
|
+
state = await this.store.patchFleet({ fleet_stage: 'stage1_and_2' });
|
|
612
|
+
}
|
|
294
613
|
return {
|
|
295
614
|
ok: true,
|
|
296
615
|
fleet_state: state,
|
|
@@ -298,7 +617,7 @@ export class FleetBootstrapper {
|
|
|
298
617
|
};
|
|
299
618
|
}
|
|
300
619
|
catch (error) {
|
|
301
|
-
const { summary, hint, rawMessage } = formatBootstrapOperatorMessage(error);
|
|
620
|
+
const { summary, hint, rawMessage, category } = formatBootstrapOperatorMessage(error);
|
|
302
621
|
const userMessage = hint !== undefined ? `${summary}\nHint: ${hint}` : summary;
|
|
303
622
|
if (this.debug) {
|
|
304
623
|
console.error(`[fleet-bootstrap] Bootstrap failed:`, error);
|
|
@@ -314,14 +633,32 @@ export class FleetBootstrapper {
|
|
|
314
633
|
console.error(`[fleet-bootstrap] raw: ${rawMessage.split('\n')[0]}`);
|
|
315
634
|
}
|
|
316
635
|
}
|
|
636
|
+
// Extract a tx hash embedded in the error message by the on-chain revert
|
|
637
|
+
// paths (format: "...tx failed for service N: 0x<hash>" or
|
|
638
|
+
// "...tx reverted: 0x<hash>"). Surfaced in the fatal envelope so the SPA
|
|
639
|
+
// can render a block-explorer link. jinn-mono-hjex reviewer fix.
|
|
640
|
+
const txHashMatch = /(0x[a-fA-F0-9]{64})/.exec(rawMessage);
|
|
641
|
+
const txHash = txHashMatch ? txHashMatch[1] : null;
|
|
317
642
|
return {
|
|
318
643
|
ok: false,
|
|
319
644
|
fleet_state: state,
|
|
320
645
|
message: userMessage,
|
|
321
646
|
rawErrorMessage: rawMessage,
|
|
647
|
+
// Preserve the structured category so the error envelope in main.ts
|
|
648
|
+
// can surface it in `details.category` for SPA consumers. jinn-mono-hjex.6
|
|
649
|
+
...(category !== undefined ? { errorCategory: category } : {}),
|
|
650
|
+
...(txHash !== null ? { txHash } : {}),
|
|
322
651
|
};
|
|
323
652
|
}
|
|
324
653
|
}
|
|
654
|
+
/**
|
|
655
|
+
* Back-compat alias. Existing call sites in `client/src/cli/commands/bootstrap.ts`
|
|
656
|
+
* and `client/src/cli/commands/fleet-scale.ts` continue to call `bootstrap()`;
|
|
657
|
+
* forwarding to `ensureStage1And2` preserves their semantics without churn.
|
|
658
|
+
*/
|
|
659
|
+
async bootstrap(password) {
|
|
660
|
+
return this.ensureStage1And2(password);
|
|
661
|
+
}
|
|
325
662
|
/**
|
|
326
663
|
* If the master is only slightly above the minimum, warn about gas runway (heuristic days).
|
|
327
664
|
*/
|
|
@@ -382,6 +719,133 @@ export class FleetBootstrapper {
|
|
|
382
719
|
return freshMnemonic;
|
|
383
720
|
}
|
|
384
721
|
}
|
|
722
|
+
// ── Stage 1: fleet-level identity steps (nghf) ────────────────────────
|
|
723
|
+
/** Deterministic Safe predict from the HD-index-1 agent EOA. */
|
|
724
|
+
async stepFleetSafePredict(state, mnemonic) {
|
|
725
|
+
const agentAddress = deriveAgentAddress(mnemonic, 1);
|
|
726
|
+
const agentKey = walletPrivateKeyAtIndex(mnemonic, 1);
|
|
727
|
+
console.error(`[fleet-bootstrap] Stage 1: predicting fleet Safe (owner=${agentAddress})`);
|
|
728
|
+
const { address } = await initPredictedSafe({
|
|
729
|
+
rpcUrl: this.config.rpcUrl,
|
|
730
|
+
signerKey: agentKey,
|
|
731
|
+
owners: [agentAddress],
|
|
732
|
+
threshold: 1,
|
|
733
|
+
});
|
|
734
|
+
void state;
|
|
735
|
+
return this.store.patchFleet({ fleet_safe_address: getAddress(address) });
|
|
736
|
+
}
|
|
737
|
+
/** Deploy the predicted fleet Safe. Funds the agent EOA from master if needed. */
|
|
738
|
+
async stepFleetSafeDeploy(state, mnemonic) {
|
|
739
|
+
const agentAddress = deriveAgentAddress(mnemonic, 1);
|
|
740
|
+
const agentKey = walletPrivateKeyAtIndex(mnemonic, 1);
|
|
741
|
+
const agentSigner = deriveAgentSigner(mnemonic, 1);
|
|
742
|
+
const fleetSafe = state.fleet_safe_address;
|
|
743
|
+
// Fund agent EOA so it can pay for Safe deploy + setAgentWallet gas.
|
|
744
|
+
// 0.01 ETH covers Safe deploy (~250k gas) + register (~80k) + setAgentWallet
|
|
745
|
+
// (~200k) at testnet gas prices comfortably. STAGE1_AGENT_ETH is the
|
|
746
|
+
// module-level constant used both here and in `stage1MinMasterEth` so the
|
|
747
|
+
// gate and the transfer agree (jinn-mono-u34i).
|
|
748
|
+
const masterAccount = deriveMasterSigner(mnemonic);
|
|
749
|
+
const masterWallet = createJinnWalletClient(this.config.rpcUrl, this.chain, masterAccount);
|
|
750
|
+
const agentBalance = await this.publicClient.getBalance({
|
|
751
|
+
address: getAddress(agentAddress),
|
|
752
|
+
});
|
|
753
|
+
if (agentBalance < STAGE1_AGENT_ETH) {
|
|
754
|
+
const fundAmount = STAGE1_AGENT_ETH - agentBalance;
|
|
755
|
+
console.error(`[fleet-bootstrap] Stage 1: funding fleet agent EOA with ${fundAmount} wei from master`);
|
|
756
|
+
const fundHash = await viemSendTransactionWithRetry(masterWallet, this.publicClient, {
|
|
757
|
+
account: masterAccount,
|
|
758
|
+
to: addr(agentAddress),
|
|
759
|
+
value: fundAmount,
|
|
760
|
+
});
|
|
761
|
+
await waitForTransactionReceiptWithRetry(this.publicClient, fundHash);
|
|
762
|
+
}
|
|
763
|
+
console.error(`[fleet-bootstrap] Stage 1: deploying fleet Safe at ${fleetSafe}`);
|
|
764
|
+
const { safe } = await initPredictedSafe({
|
|
765
|
+
rpcUrl: this.config.rpcUrl,
|
|
766
|
+
signerKey: agentKey,
|
|
767
|
+
owners: [agentAddress],
|
|
768
|
+
threshold: 1,
|
|
769
|
+
});
|
|
770
|
+
const deployTx = await safe.createSafeDeploymentTransaction();
|
|
771
|
+
const agentWallet = createJinnWalletClient(this.config.rpcUrl, this.chain, agentSigner);
|
|
772
|
+
const deployHash = await viemSendTransactionWithRetry(agentWallet, this.publicClient, {
|
|
773
|
+
account: agentSigner,
|
|
774
|
+
to: deployTx.to,
|
|
775
|
+
value: BigInt(deployTx.value),
|
|
776
|
+
data: deployTx.data,
|
|
777
|
+
});
|
|
778
|
+
const receipt = await waitForTransactionReceiptWithRetry(this.publicClient, deployHash);
|
|
779
|
+
if (receipt.status !== 'success') {
|
|
780
|
+
throw new Error(`Fleet Safe deployment tx failed: ${deployHash}`);
|
|
781
|
+
}
|
|
782
|
+
try {
|
|
783
|
+
await waitForContractCode(this.publicClient, getAddress(fleetSafe));
|
|
784
|
+
}
|
|
785
|
+
catch {
|
|
786
|
+
throw new Error(`Fleet Safe deployment succeeded but no code at ${fleetSafe}`);
|
|
787
|
+
}
|
|
788
|
+
console.error(`[fleet-bootstrap] Stage 1: fleet Safe deployed (tx=${deployHash})`);
|
|
789
|
+
return this.store.load(this.chain);
|
|
790
|
+
}
|
|
791
|
+
/** Mint the fleet agentId + bind Safe via setAgentWallet (ERC-1271). */
|
|
792
|
+
async stepFleetIdentityRegister(state, mnemonic) {
|
|
793
|
+
const identityRegistry = this.config.identityRegistry ?? IDENTITY_REGISTRY_ADDRESSES[this.config.chainId];
|
|
794
|
+
if (!identityRegistry) {
|
|
795
|
+
throw new Error(`IdentityRegistry address not configured for chainId=${this.config.chainId}.`);
|
|
796
|
+
}
|
|
797
|
+
const fleetSafe = state.fleet_safe_address;
|
|
798
|
+
const agentSigner = deriveAgentSigner(mnemonic, 1);
|
|
799
|
+
const agentWallet = createJinnWalletClient(this.config.rpcUrl, this.chain, agentSigner);
|
|
800
|
+
// Mint agentId — empty agent URI for v0 (matches stepRegisterAgent §6.1 in spec).
|
|
801
|
+
const registerData = encodeFunctionData({
|
|
802
|
+
abi: IDENTITY_REGISTRY_ABI,
|
|
803
|
+
functionName: 'register',
|
|
804
|
+
args: [''],
|
|
805
|
+
});
|
|
806
|
+
console.error(`[fleet-bootstrap] Stage 1: minting fleet agentId ` +
|
|
807
|
+
`(IdentityRegistry=${identityRegistry}, agentEOA=${agentSigner.address})`);
|
|
808
|
+
const mintTxHash = await viemSendTransactionWithRetry(agentWallet, this.publicClient, {
|
|
809
|
+
account: agentSigner,
|
|
810
|
+
to: addr(identityRegistry),
|
|
811
|
+
data: registerData,
|
|
812
|
+
});
|
|
813
|
+
const mintReceipt = await waitForTransactionReceiptWithRetry(this.publicClient, mintTxHash);
|
|
814
|
+
if (mintReceipt.status !== 'success') {
|
|
815
|
+
throw new Error(`Fleet IdentityRegistry.register() failed: ${mintTxHash}`);
|
|
816
|
+
}
|
|
817
|
+
const fleetAgentId = this.parseAgentIdFromReceipt(mintReceipt, identityRegistry);
|
|
818
|
+
if (fleetAgentId === null) {
|
|
819
|
+
throw new Error(`Fleet IdentityRegistry.register() succeeded but Registered event missing (tx=${mintTxHash})`);
|
|
820
|
+
}
|
|
821
|
+
// Persist agentId IMMEDIATELY so a crash between mint and bind doesn't lose it.
|
|
822
|
+
await this.store.patchFleet({
|
|
823
|
+
fleet_agent_id: fleetAgentId,
|
|
824
|
+
fleet_identity_registry: getAddress(identityRegistry),
|
|
825
|
+
});
|
|
826
|
+
// Bind the Safe via setAgentWallet (ERC-1271).
|
|
827
|
+
// Wrapped in the freshly-deployed-Safe retry (jinn-mono-k1ng). The
|
|
828
|
+
// pre-k1ng single-attempt version halted bootstrap when the documented
|
|
829
|
+
// race fired on the first attempt — exactly the 2026-05-18 canary's
|
|
830
|
+
// second-time-around failure mode.
|
|
831
|
+
console.error(`[fleet-bootstrap] Stage 1: binding fleet Safe ${fleetSafe} to agentId=${fleetAgentId}`);
|
|
832
|
+
const bindResult = await this.bindAgentWalletWithRetry({
|
|
833
|
+
identityRegistryAddress: addr(identityRegistry),
|
|
834
|
+
agentId: BigInt(fleetAgentId),
|
|
835
|
+
safeAddress: addr(fleetSafe),
|
|
836
|
+
agentEoaAccount: agentSigner,
|
|
837
|
+
agentEoaWalletClient: agentWallet,
|
|
838
|
+
publicClient: this.publicClient,
|
|
839
|
+
chainId: this.config.chainId,
|
|
840
|
+
}, 'Stage 1');
|
|
841
|
+
if (!bindResult.ok) {
|
|
842
|
+
const bindErr = bindResult.error;
|
|
843
|
+
throw new Error(`Fleet setAgentWallet failed after ${this.safeBindingMaxAttempts} attempts: ${bindErr.shortMessage}` +
|
|
844
|
+
(bindErr.revertReason ? ` (revert: ${bindErr.revertReason})` : ''));
|
|
845
|
+
}
|
|
846
|
+
console.error(`[fleet-bootstrap] Stage 1: setAgentWallet succeeded (tx=${bindResult.txHash})`);
|
|
847
|
+
return this.store.patchFleet({ fleet_stage: 'stage1' });
|
|
848
|
+
}
|
|
385
849
|
// ── Phase 2: Per-service bootstrap ───────────────────────────────────
|
|
386
850
|
async bootstrapService(state, mnemonic, index) {
|
|
387
851
|
const agentAddress = deriveAgentAddress(mnemonic, index);
|
|
@@ -629,6 +1093,39 @@ export class FleetBootstrapper {
|
|
|
629
1093
|
return this.store.updateService(index, { step: 'staked' });
|
|
630
1094
|
}
|
|
631
1095
|
}
|
|
1096
|
+
// Pre-stake precondition: if migration cleared service_id but kept agent_address,
|
|
1097
|
+
// check the EOA is not already registered on-chain as an agent instance. If it is,
|
|
1098
|
+
// calling stake() again would revert with AgentInstanceRegistered (selector 0x631695bd)
|
|
1099
|
+
// and there is nothing useful the operator can do without rotating the agent EOA.
|
|
1100
|
+
// Fail fast with a typed error instead of letting the contract revert.
|
|
1101
|
+
//
|
|
1102
|
+
// ServiceRegistryL2 exposes the `mapAgentInstanceOperators(address) → address` mapping:
|
|
1103
|
+
// it returns the operator address that registered the given agent instance, or the
|
|
1104
|
+
// zero address when no operator has bound that instance. A non-zero return means the
|
|
1105
|
+
// EOA is already bound. (There is no `mapAgentInstances(address) → uint256` getter on
|
|
1106
|
+
// the deployed registry — an earlier draft of this guard referenced one and was a
|
|
1107
|
+
// permanent no-op.)
|
|
1108
|
+
if (svc.agent_address && svc.service_id === null && this.config.serviceRegistry) {
|
|
1109
|
+
let alreadyBound = false;
|
|
1110
|
+
try {
|
|
1111
|
+
const boundOperator = (await this.publicClient.readContract({
|
|
1112
|
+
address: getAddress(this.config.serviceRegistry),
|
|
1113
|
+
abi: SERVICE_REGISTRY_L2_ABI,
|
|
1114
|
+
functionName: 'mapAgentInstanceOperators',
|
|
1115
|
+
args: [getAddress(svc.agent_address)],
|
|
1116
|
+
}));
|
|
1117
|
+
alreadyBound = boundOperator !== '0x0000000000000000000000000000000000000000';
|
|
1118
|
+
}
|
|
1119
|
+
catch {
|
|
1120
|
+
// Registry read failure is non-fatal — proceed and let stake() surface
|
|
1121
|
+
// the error if the agent really is bound.
|
|
1122
|
+
}
|
|
1123
|
+
if (alreadyBound) {
|
|
1124
|
+
throw new Error(`agent_already_bound: agent EOA ${svc.agent_address} is already registered as an agent instance on-chain. ` +
|
|
1125
|
+
`The previous setup retirement may have been incomplete. ` +
|
|
1126
|
+
`Contact support or rotate the agent EOA to continue.`);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
632
1129
|
// Fresh distributor stake() creates a new on-chain service. If state still
|
|
633
1130
|
// references an old Safe (e.g. hand-edited JSON), sweep it before replacing.
|
|
634
1131
|
if (svc.service_id === null && svc.safe_address && state.master_address) {
|
|
@@ -694,42 +1191,19 @@ export class FleetBootstrapper {
|
|
|
694
1191
|
const svc = state.services.find(s => s.index === index);
|
|
695
1192
|
const serviceId = svc.service_id;
|
|
696
1193
|
const stakingAddress = this.stakingAddressForService(svc);
|
|
697
|
-
|
|
698
|
-
//
|
|
699
|
-
//
|
|
700
|
-
//
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
1194
|
+
const di = displayFleetServiceIndex(svc);
|
|
1195
|
+
// Delegate to the standalone exported helper (shared with EvictionLoop /
|
|
1196
|
+
// the dashboard "Re-stake now" CTA). This eliminates the duplicate
|
|
1197
|
+
// implementation (jinn-mono-hjex.3).
|
|
1198
|
+
await recoverEvictedService({
|
|
1199
|
+
serviceDisplayIndex: di,
|
|
1200
|
+
serviceId,
|
|
1201
|
+
stakingAddress: stakingAddress,
|
|
1202
|
+
distributorAddress: this.config.distributorAddress,
|
|
1203
|
+
rpcUrl: this.config.rpcUrl,
|
|
1204
|
+
chain: this.chain,
|
|
1205
|
+
mnemonic,
|
|
707
1206
|
});
|
|
708
|
-
console.error(`[fleet-bootstrap] Service ${index}: calling distributor.reStake() for evicted service ${serviceId}`);
|
|
709
|
-
let reStakeHash;
|
|
710
|
-
try {
|
|
711
|
-
reStakeHash = await viemSendTransactionWithRetry(masterWallet, this.publicClient, {
|
|
712
|
-
account: masterAccount,
|
|
713
|
-
to: addr(this.config.distributorAddress),
|
|
714
|
-
data: reStakeData,
|
|
715
|
-
gas: 1500000n,
|
|
716
|
-
});
|
|
717
|
-
}
|
|
718
|
-
catch (err) {
|
|
719
|
-
const message = flattenErrorMessage(err);
|
|
720
|
-
if (isUnauthorizedAccountError(message)) {
|
|
721
|
-
throw new Error(`Service ${index} (service_id ${serviceId}) is evicted on the staking proxy, but master EOA ${masterAccount.address} is not authorized to reStake it. ` +
|
|
722
|
-
`The distributor only permits the recorded service operator, a managing agent, or the owner. ` +
|
|
723
|
-
`Verify JINN_EARNING_DIR and JINN_PASSWORD derive the original master EOA for this service, then re-run jinn bootstrap; otherwise request owner / managing-agent recovery or abandon-and-rebootstrap. ` +
|
|
724
|
-
`reStake revert: ${message}`);
|
|
725
|
-
}
|
|
726
|
-
throw err;
|
|
727
|
-
}
|
|
728
|
-
const receipt = await waitForTransactionReceiptWithRetry(this.publicClient, reStakeHash);
|
|
729
|
-
if (receipt.status !== 'success') {
|
|
730
|
-
throw new Error(`reStake failed for service ${index}: ${reStakeHash}`);
|
|
731
|
-
}
|
|
732
|
-
console.error(`[fleet-bootstrap] Service ${index}: reStake confirmed (tx: ${reStakeHash})`);
|
|
733
1207
|
// Service is now Staked again with the same service_id, safe_address, and mech_address.
|
|
734
1208
|
// Step back to `mech_deployed` so the resume loop advances through
|
|
735
1209
|
// `stepRegisterAgent` (idempotent — short-circuits if `agent_id` is
|
|
@@ -837,6 +1311,7 @@ export class FleetBootstrapper {
|
|
|
837
1311
|
let svc = (await this.store.load(this.chain)).services.find(s => s.index === index);
|
|
838
1312
|
if (!svc)
|
|
839
1313
|
throw new Error(`Service ${index} not found in state`);
|
|
1314
|
+
const fleetSnapshot = await this.store.load(this.chain);
|
|
840
1315
|
const identityRegistry = this.config.identityRegistry
|
|
841
1316
|
?? IDENTITY_REGISTRY_ADDRESSES[this.config.chainId];
|
|
842
1317
|
if (!identityRegistry) {
|
|
@@ -845,7 +1320,7 @@ export class FleetBootstrapper {
|
|
|
845
1320
|
}
|
|
846
1321
|
const agentSigner = deriveAgentSigner(mnemonic, index);
|
|
847
1322
|
const agentWallet = createJinnWalletClient(this.config.rpcUrl, this.chain, agentSigner);
|
|
848
|
-
// ── Sub-step A: mint NFT (skip if agent_id is already set).
|
|
1323
|
+
// ── Sub-step A: mint NFT (skip if agent_id is already set OR fleet identity exists). ─
|
|
849
1324
|
let agentId;
|
|
850
1325
|
if (svc.agent_id) {
|
|
851
1326
|
console.error(`[fleet-bootstrap] Service ${index}: ERC-8004 agent already registered ` +
|
|
@@ -856,6 +1331,22 @@ export class FleetBootstrapper {
|
|
|
856
1331
|
step: svc.step === 'safe_binding_pending' ? 'safe_binding_pending' : 'agent_registered',
|
|
857
1332
|
});
|
|
858
1333
|
}
|
|
1334
|
+
else if (fleetSnapshot.fleet_agent_id) {
|
|
1335
|
+
// nghf: reuse the fleet-level agentId minted by ensureStage1 instead of
|
|
1336
|
+
// minting a second one. This collapses the "one agentId per user"
|
|
1337
|
+
// invariant in spec §5.1 for the standard-mode two-Safe topology.
|
|
1338
|
+
console.error(`[fleet-bootstrap] Service ${index}: reusing fleet agentId=${fleetSnapshot.fleet_agent_id} ` +
|
|
1339
|
+
`(no second mint needed).`);
|
|
1340
|
+
agentId = fleetSnapshot.fleet_agent_id;
|
|
1341
|
+
svc = await this.firstServiceUpdate(index, {
|
|
1342
|
+
agent_id: fleetSnapshot.fleet_agent_id,
|
|
1343
|
+
agent_uri: '',
|
|
1344
|
+
identity_registry_address: fleetSnapshot.fleet_identity_registry ?? getAddress(identityRegistry),
|
|
1345
|
+
agent_registered_tx: null,
|
|
1346
|
+
step: 'agent_registered',
|
|
1347
|
+
error: null,
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
859
1350
|
else {
|
|
860
1351
|
// v0: empty agentURI. The richer agent card (per §6 of the spec) is
|
|
861
1352
|
// future work — operators may later call `setAgentURI`.
|
|
@@ -924,8 +1415,18 @@ export class FleetBootstrapper {
|
|
|
924
1415
|
step: 'safe_binding_pending',
|
|
925
1416
|
error: null,
|
|
926
1417
|
});
|
|
1418
|
+
// Unified retry policy (jinn-mono-k1ng — supersedes h74p's throw-only
|
|
1419
|
+
// retry): retry on `ok: false` and on thrown exceptions. The h74p
|
|
1420
|
+
// version only caught throws, but `bindAgentWalletToSafe` returns
|
|
1421
|
+
// `ok: false` for the documented freshly-deployed-Safe revert race —
|
|
1422
|
+
// so the retry was dead code under real RPC. Per-service "worked"
|
|
1423
|
+
// anyway because the next bootstrap resumes from `safe_binding_pending`;
|
|
1424
|
+
// k1ng makes the in-process retry actually do its job so we don't
|
|
1425
|
+
// depend on the operator restarting the daemon.
|
|
1426
|
+
let bindResult;
|
|
1427
|
+
let lastBindError;
|
|
927
1428
|
try {
|
|
928
|
-
|
|
1429
|
+
bindResult = await this.bindAgentWalletWithRetry({
|
|
929
1430
|
identityRegistryAddress: addr(identityRegistry),
|
|
930
1431
|
agentId: BigInt(agentId),
|
|
931
1432
|
safeAddress: addr(safeAddress),
|
|
@@ -933,23 +1434,45 @@ export class FleetBootstrapper {
|
|
|
933
1434
|
agentEoaWalletClient: agentWallet,
|
|
934
1435
|
publicClient: this.publicClient,
|
|
935
1436
|
chainId: this.config.chainId,
|
|
936
|
-
});
|
|
1437
|
+
}, `Service ${index}`);
|
|
1438
|
+
}
|
|
1439
|
+
catch (err) {
|
|
1440
|
+
lastBindError = err;
|
|
1441
|
+
}
|
|
1442
|
+
if (bindResult?.ok === true) {
|
|
937
1443
|
console.error(`[fleet-bootstrap] Service ${index}: setAgentWallet succeeded ` +
|
|
938
|
-
`(tx=${
|
|
1444
|
+
`(tx=${bindResult.txHash}, safe=${safeAddress}).`);
|
|
939
1445
|
svc = await this.firstServiceUpdate(index, {
|
|
940
1446
|
safe_bound_to_agent: true,
|
|
941
1447
|
step: 'complete',
|
|
942
1448
|
error: null,
|
|
1449
|
+
error_revert_reason: null,
|
|
1450
|
+
error_short_message: null,
|
|
943
1451
|
});
|
|
944
1452
|
}
|
|
945
|
-
|
|
946
|
-
const
|
|
947
|
-
console.error(`[fleet-bootstrap] Service ${index}: setAgentWallet failed
|
|
948
|
-
`safe_bound_to_agent=false (${
|
|
1453
|
+
else if (bindResult && !bindResult.ok) {
|
|
1454
|
+
const bindErr = bindResult.error;
|
|
1455
|
+
console.error(`[fleet-bootstrap] Service ${index}: setAgentWallet failed after retries; ` +
|
|
1456
|
+
`continuing with safe_bound_to_agent=false (${bindErr.shortMessage}` +
|
|
1457
|
+
`${bindErr.revertReason ? `, revert: ${bindErr.revertReason}` : ''}).`);
|
|
1458
|
+
svc = await this.firstServiceUpdate(index, {
|
|
1459
|
+
safe_bound_to_agent: false,
|
|
1460
|
+
step: 'safe_binding_pending',
|
|
1461
|
+
error: `safe_binding_failed: ${bindErr.shortMessage}`,
|
|
1462
|
+
error_revert_reason: bindErr.revertReason,
|
|
1463
|
+
error_short_message: bindErr.shortMessage,
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
else {
|
|
1467
|
+
const reason = lastBindError instanceof Error ? lastBindError.message : String(lastBindError);
|
|
1468
|
+
console.error(`[fleet-bootstrap] Service ${index}: setAgentWallet threw on every attempt; ` +
|
|
1469
|
+
`continuing with safe_bound_to_agent=false (${reason}).`);
|
|
949
1470
|
svc = await this.firstServiceUpdate(index, {
|
|
950
1471
|
safe_bound_to_agent: false,
|
|
951
1472
|
step: 'safe_binding_pending',
|
|
952
1473
|
error: `safe_binding_failed: ${reason}`,
|
|
1474
|
+
error_revert_reason: null,
|
|
1475
|
+
error_short_message: null,
|
|
953
1476
|
});
|
|
954
1477
|
}
|
|
955
1478
|
}
|
|
@@ -1066,8 +1589,10 @@ export class FleetBootstrapper {
|
|
|
1066
1589
|
if (receipt.status !== 'success') {
|
|
1067
1590
|
throw new Error(`Safe deployment tx failed for service ${index}: ${deployHash}`);
|
|
1068
1591
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1592
|
+
try {
|
|
1593
|
+
await waitForContractCode(this.publicClient, getAddress(safeAddress));
|
|
1594
|
+
}
|
|
1595
|
+
catch {
|
|
1071
1596
|
throw new Error(`Safe deployment succeeded but no code at ${safeAddress}`);
|
|
1072
1597
|
}
|
|
1073
1598
|
console.error(`[fleet-bootstrap] Service ${index}: Safe deployed (tx: ${deployHash})`);
|
|
@@ -1431,4 +1956,50 @@ export class FleetBootstrapper {
|
|
|
1431
1956
|
}
|
|
1432
1957
|
/** @deprecated Use FleetBootstrapper */
|
|
1433
1958
|
export const EarningBootstrapper = FleetBootstrapper;
|
|
1959
|
+
/**
|
|
1960
|
+
* Re-stake an evicted service by calling `distributor.reStake(stakingProxy, serviceId)`.
|
|
1961
|
+
*
|
|
1962
|
+
* Extracted from `FleetBootstrapper.recoverEvictedService` so it can be called
|
|
1963
|
+
* from the in-process `EvictionLoop` without requiring a full bootstrapper
|
|
1964
|
+
* context (jinn-mono-hjex.3).
|
|
1965
|
+
*
|
|
1966
|
+
* The caller is responsible for advancing the local service step back to
|
|
1967
|
+
* `mech_deployed` after this returns (just like the bootstrapper resume path does).
|
|
1968
|
+
*/
|
|
1969
|
+
export async function recoverEvictedService(opts) {
|
|
1970
|
+
const { serviceDisplayIndex, serviceId, stakingAddress, distributorAddress, rpcUrl, chain, mnemonic, } = opts;
|
|
1971
|
+
const masterAccount = deriveMasterSigner(mnemonic);
|
|
1972
|
+
const publicClient = createJinnPublicClient(rpcUrl, chain);
|
|
1973
|
+
const masterWallet = createJinnWalletClient(rpcUrl, chain, masterAccount);
|
|
1974
|
+
const reStakeData = encodeFunctionData({
|
|
1975
|
+
abi: STOLAS_DISTRIBUTOR_ABI,
|
|
1976
|
+
functionName: 'reStake',
|
|
1977
|
+
args: [addr(stakingAddress), BigInt(serviceId)],
|
|
1978
|
+
});
|
|
1979
|
+
console.error(`[eviction-recovery] Service ${serviceDisplayIndex}: calling distributor.reStake() for evicted service ${serviceId}`);
|
|
1980
|
+
let reStakeHash;
|
|
1981
|
+
try {
|
|
1982
|
+
reStakeHash = await viemSendTransactionWithRetry(masterWallet, publicClient, {
|
|
1983
|
+
account: masterAccount,
|
|
1984
|
+
to: addr(distributorAddress),
|
|
1985
|
+
data: reStakeData,
|
|
1986
|
+
gas: 1500000n,
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
catch (err) {
|
|
1990
|
+
const message = flattenErrorMessage(err);
|
|
1991
|
+
if (isUnauthorizedAccountError(message)) {
|
|
1992
|
+
throw new Error(`Service ${serviceDisplayIndex} (service_id ${serviceId}) is evicted on the staking proxy, but master EOA ` +
|
|
1993
|
+
`${masterAccount.address} is not authorized to reStake it. ` +
|
|
1994
|
+
`Verify JINN_EARNING_DIR and JINN_PASSWORD derive the original master EOA for this service. ` +
|
|
1995
|
+
`reStake revert: ${message}`);
|
|
1996
|
+
}
|
|
1997
|
+
throw err;
|
|
1998
|
+
}
|
|
1999
|
+
const receipt = await waitForTransactionReceiptWithRetry(publicClient, reStakeHash);
|
|
2000
|
+
if (receipt.status !== 'success') {
|
|
2001
|
+
throw new Error(`reStake failed for service ${serviceDisplayIndex}: ${reStakeHash}`);
|
|
2002
|
+
}
|
|
2003
|
+
console.error(`[eviction-recovery] Service ${serviceDisplayIndex}: reStake confirmed (tx: ${reStakeHash})`);
|
|
2004
|
+
}
|
|
1434
2005
|
//# sourceMappingURL=bootstrap.js.map
|