@jinn-network/client 0.1.8 → 0.1.9-canary.144d87d2
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/README.md +6 -0
- package/dist/adapters/mech/adapter.d.ts +21 -1
- package/dist/adapters/mech/adapter.js +77 -10
- package/dist/adapters/mech/adapter.js.map +1 -1
- package/dist/adapters/mech/contracts.js +62 -28
- package/dist/adapters/mech/contracts.js.map +1 -1
- package/dist/adapters/mech/safe-revert.d.ts +4 -0
- package/dist/adapters/mech/safe-revert.js +5 -1
- package/dist/adapters/mech/safe-revert.js.map +1 -1
- package/dist/adapters/mech/safe.js +5 -1
- package/dist/adapters/mech/safe.js.map +1 -1
- package/dist/adapters/mech/verdict-code.js +1 -1
- package/dist/adapters/mech/verdict-code.js.map +1 -1
- package/dist/api/bootstrap-endpoint.d.ts +1 -0
- package/dist/api/bootstrap-endpoint.js +1 -0
- package/dist/api/bootstrap-endpoint.js.map +1 -1
- package/dist/api/discovery-endpoint.d.ts +1 -0
- package/dist/api/discovery-endpoint.js +24 -0
- package/dist/api/discovery-endpoint.js.map +1 -1
- package/dist/api/fleet-build.d.ts +1 -7
- package/dist/api/fleet-build.js +0 -7
- package/dist/api/fleet-build.js.map +1 -1
- package/dist/api/gather-status.d.ts +8 -2
- package/dist/api/gather-status.js +29 -117
- package/dist/api/gather-status.js.map +1 -1
- package/dist/api/loop-completion-build.d.ts +79 -0
- package/dist/api/loop-completion-build.js +155 -0
- package/dist/api/loop-completion-build.js.map +1 -0
- package/dist/api/operator-artifacts-endpoint.js +1 -1
- package/dist/api/operator-artifacts-endpoint.js.map +1 -1
- package/dist/api/peers.js +2 -0
- package/dist/api/peers.js.map +1 -1
- package/dist/api/setup-endpoints.d.ts +32 -0
- package/dist/api/setup-endpoints.js +94 -24
- package/dist/api/setup-endpoints.js.map +1 -1
- package/dist/api/solvernets-endpoints.js +4 -1
- package/dist/api/solvernets-endpoints.js.map +1 -1
- package/dist/api/status-build.d.ts +43 -33
- package/dist/api/status-build.js +3 -26
- package/dist/api/status-build.js.map +1 -1
- package/dist/api/status-rollup-build.d.ts +0 -4
- package/dist/api/status-rollup-build.js +0 -4
- package/dist/api/status-rollup-build.js.map +1 -1
- package/dist/api/stop-hook.d.ts +1 -1
- package/dist/api/stop-hook.js +1 -1
- package/dist/api/stop-hook.js.map +1 -1
- package/dist/build-info.json +4 -4
- package/dist/build-meta.json +1 -1
- package/dist/cli/commands/codedigest-revert-check.js +6 -2
- package/dist/cli/commands/codedigest-revert-check.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +3 -0
- package/dist/cli/commands/doctor.js +37 -2
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/eval.d.ts +87 -0
- package/dist/cli/commands/eval.js +481 -0
- package/dist/cli/commands/eval.js.map +1 -0
- package/dist/cli/commands/rewards.d.ts +2 -0
- package/dist/cli/commands/rewards.js +30 -3
- package/dist/cli/commands/rewards.js.map +1 -1
- package/dist/cli/commands/solver-nets.js +68 -0
- package/dist/cli/commands/solver-nets.js.map +1 -1
- package/dist/cli/commands/status.js +0 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/config.d.ts +102 -15
- package/dist/config.js +166 -19
- package/dist/config.js.map +1 -1
- package/dist/daemon/ai-units-gate.d.ts +6 -6
- package/dist/daemon/ai-units-gate.js +11 -10
- package/dist/daemon/ai-units-gate.js.map +1 -1
- package/dist/daemon/balance-topup-loop.js +3 -0
- package/dist/daemon/balance-topup-loop.js.map +1 -1
- package/dist/daemon/checkpoint-loop.js +2 -2
- package/dist/daemon/creator.d.ts +1 -0
- package/dist/daemon/creator.js +26 -14
- package/dist/daemon/creator.js.map +1 -1
- package/dist/daemon/daemon.d.ts +15 -0
- package/dist/daemon/daemon.js +78 -22
- package/dist/daemon/daemon.js.map +1 -1
- package/dist/daemon/eviction-loop.d.ts +7 -0
- package/dist/daemon/eviction-loop.js +19 -3
- package/dist/daemon/eviction-loop.js.map +1 -1
- package/dist/daemon/jinn-claim-loop.js +3 -0
- package/dist/daemon/jinn-claim-loop.js.map +1 -1
- package/dist/daemon/join-applier.d.ts +35 -0
- package/dist/daemon/join-applier.js +49 -0
- package/dist/daemon/join-applier.js.map +1 -0
- package/dist/daemon/loop-heartbeat.d.ts +34 -0
- package/dist/daemon/loop-heartbeat.js +39 -0
- package/dist/daemon/loop-heartbeat.js.map +1 -0
- package/dist/daemon/reward-claim-loop.js +4 -1
- package/dist/daemon/reward-claim-loop.js.map +1 -1
- package/dist/daemon/watchdog-loop.d.ts +84 -0
- package/dist/daemon/watchdog-loop.js +91 -0
- package/dist/daemon/watchdog-loop.js.map +1 -0
- package/dist/dashboard/assets/index-8tAiMbUV.css +1 -0
- package/dist/dashboard/assets/index-D6a-DfaM.js +171 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/discovery/http.d.ts +17 -0
- package/dist/discovery/http.js +295 -25
- package/dist/discovery/http.js.map +1 -1
- package/dist/discovery/onchain.js +155 -1
- package/dist/discovery/onchain.js.map +1 -1
- package/dist/discovery/types.d.ts +106 -0
- package/dist/discovery/types.js +40 -0
- package/dist/discovery/types.js.map +1 -1
- package/dist/discovery/with-fallback.js +14 -0
- package/dist/discovery/with-fallback.js.map +1 -1
- package/dist/earning/bootstrap.d.ts +25 -0
- package/dist/earning/bootstrap.js +79 -28
- package/dist/earning/bootstrap.js.map +1 -1
- package/dist/earning/faucet.d.ts +1 -1
- package/dist/earning/faucet.js +2 -2
- package/dist/earning/faucet.js.map +1 -1
- package/dist/earning/safe-adapter.js +11 -0
- package/dist/earning/safe-adapter.js.map +1 -1
- package/dist/earning/stolas-claim.js +5 -5
- package/dist/earning/types.d.ts +1 -1
- package/dist/earning/types.js +1 -1
- package/dist/earning/types.js.map +1 -1
- package/dist/eval/eval-harness-run.d.ts +63 -0
- package/dist/eval/eval-harness-run.js +123 -0
- package/dist/eval/eval-harness-run.js.map +1 -0
- package/dist/eval/orchestrator.d.ts +224 -0
- package/dist/eval/orchestrator.js +250 -0
- package/dist/eval/orchestrator.js.map +1 -0
- package/dist/eval/paired.d.ts +68 -0
- package/dist/eval/paired.js +93 -0
- package/dist/eval/paired.js.map +1 -0
- package/dist/eval/resolve-slate-tasks.d.ts +35 -0
- package/dist/eval/resolve-slate-tasks.js +56 -0
- package/dist/eval/resolve-slate-tasks.js.map +1 -0
- package/dist/eval/screen-discovery.d.ts +22 -0
- package/dist/eval/screen-discovery.js +71 -0
- package/dist/eval/screen-discovery.js.map +1 -0
- package/dist/eval/screen-progress.d.ts +41 -0
- package/dist/eval/screen-progress.js +60 -0
- package/dist/eval/screen-progress.js.map +1 -0
- package/dist/eval/screen-runner.d.ts +30 -0
- package/dist/eval/screen-runner.js +289 -0
- package/dist/eval/screen-runner.js.map +1 -0
- package/dist/eval/screen.d.ts +107 -0
- package/dist/eval/screen.js +159 -0
- package/dist/eval/screen.js.map +1 -0
- package/dist/eval/slope.d.ts +29 -0
- package/dist/eval/slope.js +46 -0
- package/dist/eval/slope.js.map +1 -0
- package/dist/eval/train-sequence.d.ts +35 -0
- package/dist/eval/train-sequence.js +59 -0
- package/dist/eval/train-sequence.js.map +1 -0
- package/dist/eval/wilson.d.ts +45 -0
- package/dist/eval/wilson.js +48 -0
- package/dist/eval/wilson.js.map +1 -0
- package/dist/events/types.d.ts +1 -1
- package/dist/events/types.js +1 -1
- package/dist/events/types.js.map +1 -1
- package/dist/harnesses/engine/canonical-json.js +5 -3
- package/dist/harnesses/engine/canonical-json.js.map +1 -1
- package/dist/harnesses/engine/engine.d.ts +24 -0
- package/dist/harnesses/engine/engine.js +72 -9
- package/dist/harnesses/engine/engine.js.map +1 -1
- package/dist/harnesses/engine/packaging.js +1 -1
- package/dist/harnesses/engine/packaging.js.map +1 -1
- package/dist/harnesses/engine/persistence.d.ts +17 -0
- package/dist/harnesses/engine/persistence.js +28 -0
- package/dist/harnesses/engine/persistence.js.map +1 -1
- package/dist/harnesses/impls/claude-mcp-hyperliquid/mcp-tools.d.ts +1 -1
- package/dist/harnesses/impls/claude-mcp-hyperliquid/mcp-tools.js +1 -1
- package/dist/harnesses/impls/claude-mcp-hyperliquid/mcp-tools.js.map +1 -1
- package/dist/harnesses/impls/hermes-agent/adapter.d.ts +2 -0
- package/dist/harnesses/impls/hermes-agent/adapter.js +8 -5
- package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -1
- package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +1 -0
- package/dist/harnesses/impls/hermes-agent/bootstrap.js +6 -1
- package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
- package/dist/harnesses/impls/hermes-agent/harness.d.ts +17 -3
- package/dist/harnesses/impls/hermes-agent/harness.js +68 -5
- package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
- package/dist/harnesses/impls/index.d.ts +2 -0
- package/dist/harnesses/impls/index.js +9 -0
- package/dist/harnesses/impls/index.js.map +1 -1
- package/dist/harnesses/impls/jinn-repo-evaluator/eval-runner.d.ts +34 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/eval-runner.js +111 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/eval-runner.js.map +1 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/evaluator.d.ts +24 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/evaluator.js +19 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/evaluator.js.map +1 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/harness.d.ts +64 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/harness.js +125 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/harness.js.map +1 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/repro.d.ts +32 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/repro.js +73 -0
- package/dist/harnesses/impls/jinn-repo-evaluator/repro.js.map +1 -0
- package/dist/harnesses/impls/learner/adapters/claude-code.js +5 -0
- package/dist/harnesses/impls/learner/adapters/claude-code.js.map +1 -1
- package/dist/harnesses/impls/learner/harness.d.ts +17 -1
- package/dist/harnesses/impls/learner/harness.js +51 -1
- package/dist/harnesses/impls/learner/harness.js.map +1 -1
- package/dist/harnesses/impls/learner/harvest.d.ts +2 -0
- package/dist/harnesses/impls/learner/harvest.js +51 -1
- package/dist/harnesses/impls/learner/harvest.js.map +1 -1
- package/dist/harnesses/impls/learner/plugin-path.js +1 -0
- package/dist/harnesses/impls/learner/plugin-path.js.map +1 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +3 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.d.ts +2 -2
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js +3 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js.map +1 -1
- package/dist/harnesses/readiness-registry.d.ts +10 -0
- package/dist/harnesses/readiness-registry.js +13 -0
- package/dist/harnesses/readiness-registry.js.map +1 -1
- package/dist/harnesses/types.d.ts +14 -0
- package/dist/learner/revert-decision.d.ts +16 -1
- package/dist/learner/revert-decision.js +38 -18
- package/dist/learner/revert-decision.js.map +1 -1
- package/dist/learner/revert-stats.d.ts +14 -0
- package/dist/learner/revert-stats.js +42 -0
- package/dist/learner/revert-stats.js.map +1 -1
- package/dist/local-provider-url.d.ts +3 -0
- package/dist/local-provider-url.js +28 -0
- package/dist/local-provider-url.js.map +1 -0
- package/dist/main.js +94 -25
- package/dist/main.js.map +1 -1
- package/dist/mcp/operator-server.js +1 -1
- package/dist/mcp/operator-server.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/plugins/learner/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/learner/.codex-plugin/plugin.json +1 -1
- package/dist/plugins/learner/hooks/session-start +30 -1
- package/dist/plugins/learner/skills/learn/consolidator-prompt.md +4 -0
- package/dist/preflight/deployment-readiness.d.ts +147 -0
- package/dist/preflight/deployment-readiness.js +366 -0
- package/dist/preflight/deployment-readiness.js.map +1 -0
- package/dist/preflight/pidfile-liveness.d.ts +7 -1
- package/dist/preflight/pidfile-liveness.js +14 -0
- package/dist/preflight/pidfile-liveness.js.map +1 -1
- package/dist/rpc/transport.d.ts +43 -5
- package/dist/rpc/transport.js +131 -30
- package/dist/rpc/transport.js.map +1 -1
- package/dist/scripts/swe-rebench-v2-seed-pool.json +2 -1
- package/dist/solver-nets/registry.d.ts +19 -0
- package/dist/solver-nets/registry.js +95 -66
- package/dist/solver-nets/registry.js.map +1 -1
- package/dist/solver-types/_jinn-repo-pool.d.ts +27 -0
- package/dist/solver-types/_jinn-repo-pool.js +27 -0
- package/dist/solver-types/_jinn-repo-pool.js.map +1 -0
- package/dist/solver-types/_swe-rebench-v2-held-out-slate.d.ts +76 -0
- package/dist/solver-types/_swe-rebench-v2-held-out-slate.js +156 -0
- package/dist/solver-types/_swe-rebench-v2-held-out-slate.js.map +1 -0
- package/dist/solver-types/_swe-rebench-v2-pool-recovery.d.ts +81 -0
- package/dist/solver-types/_swe-rebench-v2-pool-recovery.js +116 -0
- package/dist/solver-types/_swe-rebench-v2-pool-recovery.js.map +1 -0
- package/dist/solver-types/_swe-rebench-v2-state.d.ts +9 -0
- package/dist/solver-types/_swe-rebench-v2-state.js +14 -0
- package/dist/solver-types/_swe-rebench-v2-state.js.map +1 -1
- package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +30 -0
- package/dist/solver-types/_swe-rebench-v2-validated-pool.js +40 -0
- package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
- package/dist/solver-types/index.js +2 -0
- package/dist/solver-types/index.js.map +1 -1
- package/dist/solver-types/jinn-repo-admit.d.ts +17 -0
- package/dist/solver-types/jinn-repo-admit.js +16 -0
- package/dist/solver-types/jinn-repo-admit.js.map +1 -0
- package/dist/solver-types/jinn-repo-auto.d.ts +60 -0
- package/dist/solver-types/jinn-repo-auto.js +163 -0
- package/dist/solver-types/jinn-repo-auto.js.map +1 -0
- package/dist/solver-types/jinn-repo-definition.d.ts +15 -0
- package/dist/solver-types/jinn-repo-definition.js +34 -0
- package/dist/solver-types/jinn-repo-definition.js.map +1 -0
- package/dist/solver-types/jinn-repo-extract.d.ts +16 -0
- package/dist/solver-types/jinn-repo-extract.js +32 -0
- package/dist/solver-types/jinn-repo-extract.js.map +1 -0
- package/dist/solver-types/jinn-repo.d.ts +21 -0
- package/dist/solver-types/jinn-repo.js +23 -0
- package/dist/solver-types/jinn-repo.js.map +1 -0
- package/dist/solver-types/learner-loop-test.js +1 -1
- package/dist/solver-types/learner-loop-test.js.map +1 -1
- package/dist/solver-types/slates/held-out-slate.swe-rebench-v2.v1.json +20 -0
- package/dist/solver-types/slates/held-out-slate.swe-rebench-v2.v2.json +19 -0
- package/dist/solver-types/slates/held-out-slate.swe-rebench-v2.v2.screening-report.json +628 -0
- package/dist/solver-types/solver-type.d.ts +8 -0
- package/dist/solver-types/swe-rebench-v2.d.ts +2 -0
- package/dist/solver-types/swe-rebench-v2.js +115 -10
- package/dist/solver-types/swe-rebench-v2.js.map +1 -1
- package/dist/solvernets/launched-record-dispatcher.d.ts +5 -0
- package/dist/solvernets/launched-record-dispatcher.js +8 -1
- package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
- package/dist/solvernets/registry-client-erc8004.js +29 -37
- package/dist/solvernets/registry-client-erc8004.js.map +1 -1
- package/dist/solvernets/registry-client.d.ts +6 -0
- package/dist/solvernets/store.d.ts +1 -1
- package/dist/solvernets/store.js +8 -3
- package/dist/solvernets/store.js.map +1 -1
- package/dist/spend/ai-units-config.d.ts +10 -0
- package/dist/spend/ai-units-config.js +7 -1
- package/dist/spend/ai-units-config.js.map +1 -1
- package/dist/spend/ai-units.d.ts +51 -0
- package/dist/spend/ai-units.js +73 -0
- package/dist/spend/ai-units.js.map +1 -1
- package/dist/spend/record.js +12 -5
- package/dist/spend/record.js.map +1 -1
- package/dist/store/store.d.ts +91 -5
- package/dist/store/store.js +170 -7
- package/dist/store/store.js.map +1 -1
- package/dist/trajectory/harness-bundle-schema.d.ts +1 -1
- package/dist/trajectory/harness-bundle-schema.js +1 -1
- package/dist/trajectory/harness-bundle-schema.js.map +1 -1
- package/dist/trajectory/schema.d.ts +1 -1
- package/dist/trajectory/schema.js +1 -1
- package/dist/trajectory/schema.js.map +1 -1
- package/dist/trajectory/transcript-parsers/types.d.ts +1 -1
- package/dist/trajectory/transcript-parsers/types.js +1 -1
- package/dist/trajectory/transcript-parsers/types.js.map +1 -1
- package/dist/types/envelope.d.ts +1 -1
- package/dist/types/envelope.js +1 -1
- package/dist/types/envelope.js.map +1 -1
- package/dist/types/payloads/index.d.ts +1 -1
- package/dist/types/payloads/index.js +7 -1
- package/dist/types/payloads/index.js.map +1 -1
- package/dist/types/payloads/portfolio-v0.d.ts +1 -1
- package/dist/types/payloads/portfolio-v0.js +1 -1
- package/dist/types/payloads/portfolio-v0.js.map +1 -1
- package/dist/types/payloads/prediction-apy-v0.d.ts +1 -1
- package/dist/types/payloads/prediction-apy-v0.js +1 -1
- package/dist/types/payloads/prediction-apy-v0.js.map +1 -1
- package/dist/types/payloads/prediction-v0.d.ts +1 -1
- package/dist/types/payloads/prediction-v0.js +1 -1
- package/dist/types/payloads/prediction-v0.js.map +1 -1
- package/dist/types/portfolio.d.ts +1 -1
- package/dist/types/portfolio.js +1 -1
- package/dist/types/portfolio.js.map +1 -1
- package/dist/types/prediction-apy.d.ts +1 -1
- package/dist/types/prediction-apy.js +1 -1
- package/dist/types/prediction-apy.js.map +1 -1
- package/dist/types/prediction.d.ts +1 -1
- package/dist/types/prediction.js +1 -1
- package/dist/types/prediction.js.map +1 -1
- package/dist/types/session-provenance.d.ts +1 -1
- package/dist/types/session-provenance.js +1 -1
- package/dist/types/session-provenance.js.map +1 -1
- package/dist/types/task-document.d.ts +1 -1
- package/dist/types/task-document.js +1 -1
- package/dist/types/task-document.js.map +1 -1
- package/dist/types/task.d.ts +1 -1
- package/dist/types/task.js +1 -1
- package/dist/types/task.js.map +1 -1
- package/dist/types/window.d.ts +1 -1
- package/dist/types/window.js +1 -1
- package/dist/types/window.js.map +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/checkpoint.d.ts +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/checkpoint.js +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/contracts.d.ts +3 -2
- package/dist/vendor/@jinn-network/sdk/dist/contracts.js +49 -0
- package/dist/vendor/@jinn-network/sdk/dist/jinn-repo.d.ts +44 -0
- package/dist/vendor/@jinn-network/sdk/dist/jinn-repo.js +25 -0
- package/dist/vendor/@jinn-network/sdk/dist/json-schema.d.ts +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/json-schema.js +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/payloads/jinn-repo.d.ts +38 -0
- package/dist/vendor/@jinn-network/sdk/dist/payloads/jinn-repo.js +22 -0
- package/dist/vendor/@jinn-network/sdk/dist/payloads/prediction-v1.d.ts +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/payloads/prediction-v1.js +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/payloads/session-derived.d.ts +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/payloads/session-derived.js +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/payloads/swe-rebench-v2.d.ts +109 -2
- package/dist/vendor/@jinn-network/sdk/dist/payloads/swe-rebench-v2.js +26 -2
- package/dist/vendor/@jinn-network/sdk/dist/prediction-v1.d.ts +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/prediction-v1.js +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/jinn-repo.d.ts +4 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/jinn-repo.js +2 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.d.ts +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.js +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/swe-rebench-v2-held-out-slate.d.ts +65 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/swe-rebench-v2-held-out-slate.js +123 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/swe-rebench-v2.d.ts +2 -2
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/swe-rebench-v2.js +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/swe-rebench-v2.d.ts +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/swe-rebench-v2.js +1 -1
- package/dist/vendor/@jinn-network/sdk/package.json +9 -1
- package/docker-compose.yml +3 -2
- package/package.json +23 -20
- package/plugins/jinn-repo-runtime/.claude-plugin/plugin.json +5 -0
- package/plugins/jinn-repo-runtime/.codex-plugin/plugin.json +39 -0
- package/plugins/jinn-repo-runtime/README.md +27 -0
- package/plugins/jinn-repo-runtime/hooks/hooks.json +16 -0
- package/plugins/jinn-repo-runtime/hooks/session-start +73 -0
- package/plugins/jinn-repo-runtime/jinn.plugin.json +11 -0
- package/plugins/jinn-repo-runtime/skills/task/SKILL.md +92 -0
- package/plugins/learner/.claude-plugin/plugin.json +1 -1
- package/plugins/learner/.codex-plugin/plugin.json +1 -1
- package/plugins/learner/hooks/session-start +30 -1
- package/plugins/learner/skills/learn/consolidator-prompt.md +4 -0
- package/plugins/swe-rebench-v2-runtime/hooks/hooks.json +16 -0
- package/plugins/swe-rebench-v2-runtime/hooks/session-start +74 -0
- package/dist/dashboard/assets/index-CzKxvMcU.css +0 -32
- package/dist/dashboard/assets/index-yVemxHot.js +0 -351
|
@@ -35,4 +35,33 @@ fi
|
|
|
35
35
|
git config user.name "claude-code-learner"
|
|
36
36
|
git config user.email "claude-code-learner@local"
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
# Operational readiness goes to STDERR. Claude Code parses a SessionStart hook's
|
|
39
|
+
# STDOUT as JSON for `hookSpecificOutput`; any stray stdout would break that parse,
|
|
40
|
+
# so stdout below carries nothing but the additionalContext payload.
|
|
41
|
+
echo "session-start: implStateDir ready at $(pwd) (HEAD=$(git rev-parse HEAD))" >&2
|
|
42
|
+
|
|
43
|
+
# Steer skill-selection toward this plugin's OWN learn loop. This is the agnostic,
|
|
44
|
+
# plugin-owned mechanism: the learner plugin asserts its own behaviour from its own
|
|
45
|
+
# SessionStart hook, without any other plugin or the harness prompt knowing it exists.
|
|
46
|
+
#
|
|
47
|
+
# It is delivered via the documented `hookSpecificOutput.additionalContext` contract,
|
|
48
|
+
# which is injected into the model's context at session start. The previous plain
|
|
49
|
+
# `echo` was logged as a hook event (visible to the harness via --include-hook-events)
|
|
50
|
+
# but NEVER entered the model context — which is why, despite the learn skill being
|
|
51
|
+
# projected and available, the model kept selecting a direct-solve skill and the loop
|
|
52
|
+
# ran 0% of the time. (Verified: additionalContext reaches the model in headless
|
|
53
|
+
# `-p` / stream-json mode on claude 2.1.x.)
|
|
54
|
+
#
|
|
55
|
+
# MODE-AWARE (extends the original train-only steer for the held-out exam): in
|
|
56
|
+
# `frozen` mode the harness freeze-fences implStateDir, so running the learn loop's
|
|
57
|
+
# Improve/Memory phases would WRITE implStateDir and trip the fence → the eval
|
|
58
|
+
# aborts with a violation. The frozen steer therefore tells the model to CONSULT
|
|
59
|
+
# the accumulated knowledge (read-only) and solve directly — which is exactly how
|
|
60
|
+
# prior learning should raise the frozen score — and to NOT run the loop or modify
|
|
61
|
+
# implStateDir. `JINN_HARNESS_MODE` is set by the harness adapter (default train).
|
|
62
|
+
if [[ "${JINN_HARNESS_MODE:-train}" == "frozen" ]]; then
|
|
63
|
+
STEER="This is a FROZEN evaluation run. Before solving, CONSULT the accumulated learner knowledge under implStateDir (notes/, skills/, strategies/, patterns/, tests/) and apply any relevant strategy or pattern to this task. Then solve the task and call submit_typed_payload. Do NOT run the learn loop (no Orient/Improve/Memory phases) and do NOT create, edit, or commit anything under implStateDir — the harness verifies implStateDir is unchanged and will discard this run if it is modified."
|
|
64
|
+
else
|
|
65
|
+
STEER="A seven-phase self-improvement loop is available as the learn skill (claude-code-learner:learn): Orient, Strategize, Plan, Execute, Debrief, Improve, then Memory consolidation. For this session your FIRST action MUST be to invoke the learn skill (via the Skill tool) and run the full loop end-to-end, instead of solving the task directly or selecting another skill first. The Execute phase still performs the actual task work and still calls submit_typed_payload; the surrounding phases capture reusable strategy and persist it to implStateDir so future runs improve. Do not skip the loop."
|
|
66
|
+
fi
|
|
67
|
+
printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"%s"}}\n' "$STEER"
|
|
@@ -18,6 +18,10 @@ Anything that writes to `implStateDir` happens here, including:
|
|
|
18
18
|
- **Unused skills / hooks / tools** — anything not invoked in the last N runs (default 20; check policy override). Move to `implStateDir/.archive/<ts>/` or delete per policy.
|
|
19
19
|
- **Regressed promotions** — revert an Improve commit only when it actually made things worse. There are two triggers; act on either:
|
|
20
20
|
1. **Qualitative trigger** — if the trend in `analysisPath` (the Debrief signal) indicates a recent change made things worse, `git revert <commit-sha>` it. Be specific: revert the exact commit identified, not a bulk rollback. The target sha is `improvePromotionsDir/<n>.json`'s `implStateDirShaAfter`.
|
|
21
|
+
> The graded score (Tier 2) lowers the variance of the keep/revert decision only.
|
|
22
|
+
> It never overrules the binary verdict, and it MUST NOT be used to size on-chain
|
|
23
|
+
> reward — that path is gated on the withheld-test challenge (#1019, design §5.5).
|
|
24
|
+
|
|
21
25
|
2. **Quantitative trigger (#764)** — for each candidate Improve commit on recent `implStateDir` git history (the commits since `implStateDirShaBefore`, identified from each `improvePromotionsDir/<n>.json` `implStateDirShaAfter`), ask the network-truth indexer whether the commit's per-codeDigest pass rate is significantly worse than its parent's. **Do not hand-roll the codeDigest hash or the statistics — shell out to the CLI**, which exports each commit's tree (`git archive`, no `.git`) and hashes it the way production stamps codeDigest, then runs the documented test:
|
|
22
26
|
|
|
23
27
|
```bash
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment-readiness preflight (issue #958).
|
|
3
|
+
*
|
|
4
|
+
* Hosted deploys have no boot-time guard that the environment is fit to run;
|
|
5
|
+
* misconfig fails silently or mid-run. This module adds a set of checks that
|
|
6
|
+
* answer "is this environment fit to run the daemon?" and a boot gate that
|
|
7
|
+
* **fails loud — but only in a deployment context**.
|
|
8
|
+
*
|
|
9
|
+
* Load-bearing constraint: a plain local `jinn run` (no `JINN_STATE_DIR`,
|
|
10
|
+
* running as the user, no relayer configured) must NEVER be newly gated. The
|
|
11
|
+
* fail-loud boot gate fires only when `isDeploymentContext()` is true; outside
|
|
12
|
+
* that, every check is advisory (surfaced in `doctor`, never boot-fatal). The
|
|
13
|
+
* `doctor` command runs all checks regardless of context.
|
|
14
|
+
*
|
|
15
|
+
* The checks compose existing primitives where possible:
|
|
16
|
+
* - `writable_volume` — the one genuinely new primitive (write+fsync+unlink probe)
|
|
17
|
+
* - `state_on_volume` — assert resolved state lives on the configured volume
|
|
18
|
+
* - `credentials_resolvable` — reuses `detectAuthContext`; presence-only, NEVER echoes secrets
|
|
19
|
+
* - `relayer_reachable` — cheap probe; skip-ok when no relayer endpoint is configured
|
|
20
|
+
* - `agent_cli_non_root` — uid 0 is unfit (the agent CLI refuses to run as root)
|
|
21
|
+
*
|
|
22
|
+
* Every check is side-effect-light and NEVER throws — a failure becomes a
|
|
23
|
+
* structured fail result, not an exception. The aggregate is the safe caller
|
|
24
|
+
* surface; the gate adds the fail-loud envelope on top.
|
|
25
|
+
*/
|
|
26
|
+
import { type EnvelopeSinks } from '../errors/envelope.js';
|
|
27
|
+
import { detectAuthContext as defaultDetectAuthContext, type AuthContext } from './claude-auth.js';
|
|
28
|
+
export interface DeploymentCheckResult {
|
|
29
|
+
name: 'writable_volume' | 'state_on_volume' | 'credentials_resolvable' | 'relayer_reachable' | 'agent_cli_non_root';
|
|
30
|
+
ok: boolean;
|
|
31
|
+
detail: string;
|
|
32
|
+
remedy?: string;
|
|
33
|
+
}
|
|
34
|
+
/** Inputs that come from the resolved config / process — never secret values. */
|
|
35
|
+
export interface DeploymentReadinessInputs {
|
|
36
|
+
/** `config.stateDir` — the volume root, when set (S3, JINN_STATE_DIR). */
|
|
37
|
+
stateDir: string | undefined;
|
|
38
|
+
/** `config.earningDir` — the resolved earning/state directory. */
|
|
39
|
+
earningDir: string;
|
|
40
|
+
/**
|
|
41
|
+
* Optional relayer endpoint. No config field plumbs this today (the
|
|
42
|
+
* claim-relayer is referenced only as a contract-level concept), so this is
|
|
43
|
+
* `undefined` in production and the relayer check degrades to skip-ok. The DI
|
|
44
|
+
* surface keeps it injectable so the reachability path stays testable and so
|
|
45
|
+
* a future relayer-URL config can wire straight in.
|
|
46
|
+
*/
|
|
47
|
+
relayerUrl: string | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* `config.runtimeMode` — a persisted runtime mode (`'docker-compose'` /
|
|
50
|
+
* `'container'`) declared by the operator (via `jinn auth --mode` or the app
|
|
51
|
+
* setup) rather than via env / `/.dockerenv`. Threaded into
|
|
52
|
+
* `detectAuthContext` as `configuredMode` so a config-declared compose /
|
|
53
|
+
* container operator is detected as a deployment context (and the boot gate
|
|
54
|
+
* arms) even with no `JINN_RUNTIME_MODE` env var and no `/.dockerenv`.
|
|
55
|
+
* `undefined` leaves detection on env / filesystem signals only — preserving
|
|
56
|
+
* the bare-local regression guarantee.
|
|
57
|
+
*/
|
|
58
|
+
runtimeMode: AuthContext | undefined;
|
|
59
|
+
}
|
|
60
|
+
/** Injectable dependencies — tests pass doubles; production uses the defaults. */
|
|
61
|
+
export interface DeploymentReadinessDeps {
|
|
62
|
+
env: NodeJS.ProcessEnv;
|
|
63
|
+
/** `process.getuid` (undefined on platforms without it, e.g. Windows). */
|
|
64
|
+
getuid: (() => number) | undefined;
|
|
65
|
+
detectAuthContext: typeof defaultDetectAuthContext;
|
|
66
|
+
fetch: typeof fetch;
|
|
67
|
+
}
|
|
68
|
+
export interface DeploymentReadinessReport {
|
|
69
|
+
/** True when we are in a deployment context (gate is armed). */
|
|
70
|
+
deployment: boolean;
|
|
71
|
+
/** The auth context detected for this run. */
|
|
72
|
+
authContext: AuthContext;
|
|
73
|
+
checks: DeploymentCheckResult[];
|
|
74
|
+
/**
|
|
75
|
+
* True when the daemon must refuse to boot: deployment context AND at least
|
|
76
|
+
* one HARD check failed. Always false outside a deployment context.
|
|
77
|
+
*/
|
|
78
|
+
bootFatal: boolean;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Deployment context = `JINN_STATE_DIR` set OR `config.stateDir` set OR the
|
|
82
|
+
* auth context is a container / docker-compose. A plain local operator (bare
|
|
83
|
+
* context, no state-dir) is NOT a deployment context, so the boot gate stays
|
|
84
|
+
* disarmed for them.
|
|
85
|
+
*/
|
|
86
|
+
export declare function isDeploymentContext(input: {
|
|
87
|
+
env: NodeJS.ProcessEnv;
|
|
88
|
+
authContext: AuthContext;
|
|
89
|
+
stateDir: string | undefined;
|
|
90
|
+
}): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Attempt to write + fsync + unlink a temp file under `dir`. ok when it
|
|
93
|
+
* succeeds; structured fail (never throws) on EACCES / EROFS / ENOSPC / missing
|
|
94
|
+
* dir / any other fs error.
|
|
95
|
+
*/
|
|
96
|
+
export declare function checkWritableVolume(dir: string): Promise<DeploymentCheckResult>;
|
|
97
|
+
/**
|
|
98
|
+
* In a deployment context, assert resolved state lives on the configured
|
|
99
|
+
* volume — i.e. `stateDir` is set AND `earningDir` resolves under it. Advisory
|
|
100
|
+
* (always ok) outside a deployment context.
|
|
101
|
+
*/
|
|
102
|
+
export declare function checkStateOnVolume(input: {
|
|
103
|
+
deployment: boolean;
|
|
104
|
+
stateDir: string | undefined;
|
|
105
|
+
earningDir: string;
|
|
106
|
+
}): DeploymentCheckResult;
|
|
107
|
+
/**
|
|
108
|
+
* Presence-only credential check. In a bare context the operator authenticates
|
|
109
|
+
* the agent CLI interactively (claude session auth), so credentials are not
|
|
110
|
+
* env-resolvable and that is fine. In a container / compose context there is no
|
|
111
|
+
* interactive login, so SOME agent-CLI auth signal must be present in the env.
|
|
112
|
+
*
|
|
113
|
+
* NEVER returns or logs a secret value — only presence + context.
|
|
114
|
+
*/
|
|
115
|
+
export declare function checkCredentialsResolvable(input: {
|
|
116
|
+
context: AuthContext;
|
|
117
|
+
env: NodeJS.ProcessEnv;
|
|
118
|
+
}): DeploymentCheckResult;
|
|
119
|
+
/**
|
|
120
|
+
* If a relayer endpoint is configured, probe it (short-timeout HEAD/GET). If
|
|
121
|
+
* not configured, skip-ok. Never throws.
|
|
122
|
+
*
|
|
123
|
+
* Production passes `relayerUrl: undefined` today — no config field plumbs a
|
|
124
|
+
* relayer URL (the claim-relayer is a contract-level / off-process concept), so
|
|
125
|
+
* this degrades to skip-ok. The injectable surface keeps the reachable /
|
|
126
|
+
* unreachable paths testable.
|
|
127
|
+
*/
|
|
128
|
+
export declare function checkRelayerReachable(relayerUrl: string | undefined, fetchImpl: typeof fetch): Promise<DeploymentCheckResult>;
|
|
129
|
+
/**
|
|
130
|
+
* ok when uid !== 0 (or no getuid on the platform). Fail when running as root —
|
|
131
|
+
* the agent CLI refuses to run as root, so a root daemon is unfit. Never throws.
|
|
132
|
+
*/
|
|
133
|
+
export declare function checkAgentCliNonRoot(getuid: (() => number) | undefined): DeploymentCheckResult;
|
|
134
|
+
/**
|
|
135
|
+
* Run every deployment-readiness check and assemble a report. Detects the
|
|
136
|
+
* deployment context internally and decides `bootFatal` accordingly. Never
|
|
137
|
+
* throws — each check degrades to a structured fail.
|
|
138
|
+
*/
|
|
139
|
+
export declare function runDeploymentReadinessChecks(inputs: DeploymentReadinessInputs, deps: DeploymentReadinessDeps): Promise<DeploymentReadinessReport>;
|
|
140
|
+
/**
|
|
141
|
+
* Boot gate for `jinn run`. Runs the readiness aggregate; in a deployment
|
|
142
|
+
* context, fail loud (emit `invalid_invocation` envelope + non-zero exit) when
|
|
143
|
+
* a hard check fails. Outside a deployment context, log advisories for any
|
|
144
|
+
* failing check and proceed. Mirrors `applyPidfileLivenessGate`'s contract:
|
|
145
|
+
* `emitEnvelope` does not return in production (it `process.exit`s).
|
|
146
|
+
*/
|
|
147
|
+
export declare function applyDeploymentReadinessGate(inputs: DeploymentReadinessInputs, deps: DeploymentReadinessDeps, sinks?: EnvelopeSinks): Promise<void>;
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment-readiness preflight (issue #958).
|
|
3
|
+
*
|
|
4
|
+
* Hosted deploys have no boot-time guard that the environment is fit to run;
|
|
5
|
+
* misconfig fails silently or mid-run. This module adds a set of checks that
|
|
6
|
+
* answer "is this environment fit to run the daemon?" and a boot gate that
|
|
7
|
+
* **fails loud — but only in a deployment context**.
|
|
8
|
+
*
|
|
9
|
+
* Load-bearing constraint: a plain local `jinn run` (no `JINN_STATE_DIR`,
|
|
10
|
+
* running as the user, no relayer configured) must NEVER be newly gated. The
|
|
11
|
+
* fail-loud boot gate fires only when `isDeploymentContext()` is true; outside
|
|
12
|
+
* that, every check is advisory (surfaced in `doctor`, never boot-fatal). The
|
|
13
|
+
* `doctor` command runs all checks regardless of context.
|
|
14
|
+
*
|
|
15
|
+
* The checks compose existing primitives where possible:
|
|
16
|
+
* - `writable_volume` — the one genuinely new primitive (write+fsync+unlink probe)
|
|
17
|
+
* - `state_on_volume` — assert resolved state lives on the configured volume
|
|
18
|
+
* - `credentials_resolvable` — reuses `detectAuthContext`; presence-only, NEVER echoes secrets
|
|
19
|
+
* - `relayer_reachable` — cheap probe; skip-ok when no relayer endpoint is configured
|
|
20
|
+
* - `agent_cli_non_root` — uid 0 is unfit (the agent CLI refuses to run as root)
|
|
21
|
+
*
|
|
22
|
+
* Every check is side-effect-light and NEVER throws — a failure becomes a
|
|
23
|
+
* structured fail result, not an exception. The aggregate is the safe caller
|
|
24
|
+
* surface; the gate adds the fail-loud envelope on top.
|
|
25
|
+
*/
|
|
26
|
+
import { promises as fs } from 'node:fs';
|
|
27
|
+
import { join, resolve } from 'node:path';
|
|
28
|
+
import { randomBytes } from 'node:crypto';
|
|
29
|
+
import { emitEnvelope } from '../errors/envelope.js';
|
|
30
|
+
import { emitStructured } from '../events/emitter.js';
|
|
31
|
+
/** Hard checks — failing one of these in a deployment context refuses the boot. */
|
|
32
|
+
const HARD_CHECK_NAMES = new Set([
|
|
33
|
+
'writable_volume',
|
|
34
|
+
'state_on_volume',
|
|
35
|
+
'agent_cli_non_root',
|
|
36
|
+
]);
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// isDeploymentContext
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
/**
|
|
41
|
+
* Deployment context = `JINN_STATE_DIR` set OR `config.stateDir` set OR the
|
|
42
|
+
* auth context is a container / docker-compose. A plain local operator (bare
|
|
43
|
+
* context, no state-dir) is NOT a deployment context, so the boot gate stays
|
|
44
|
+
* disarmed for them.
|
|
45
|
+
*/
|
|
46
|
+
export function isDeploymentContext(input) {
|
|
47
|
+
if (typeof input.env['JINN_STATE_DIR'] === 'string' && input.env['JINN_STATE_DIR'].length > 0) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (typeof input.stateDir === 'string' && input.stateDir.length > 0)
|
|
51
|
+
return true;
|
|
52
|
+
return input.authContext === 'container' || input.authContext === 'docker-compose';
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// writable_volume — the new primitive
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
/**
|
|
58
|
+
* Attempt to write + fsync + unlink a temp file under `dir`. ok when it
|
|
59
|
+
* succeeds; structured fail (never throws) on EACCES / EROFS / ENOSPC / missing
|
|
60
|
+
* dir / any other fs error.
|
|
61
|
+
*/
|
|
62
|
+
export async function checkWritableVolume(dir) {
|
|
63
|
+
const probePath = join(dir, `.jinn-writeprobe-${process.pid}-${randomBytes(4).toString('hex')}`);
|
|
64
|
+
let handle;
|
|
65
|
+
try {
|
|
66
|
+
handle = await fs.open(probePath, 'w', 0o600);
|
|
67
|
+
await handle.write('jinn-writable-volume-probe');
|
|
68
|
+
await handle.sync();
|
|
69
|
+
await handle.close();
|
|
70
|
+
handle = undefined;
|
|
71
|
+
await fs.unlink(probePath);
|
|
72
|
+
return {
|
|
73
|
+
name: 'writable_volume',
|
|
74
|
+
ok: true,
|
|
75
|
+
detail: `${dir} is writable`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
// Best-effort cleanup; ignore whatever it throws.
|
|
80
|
+
if (handle)
|
|
81
|
+
await handle.close().catch(() => undefined);
|
|
82
|
+
await fs.unlink(probePath).catch(() => undefined);
|
|
83
|
+
const code = err.code;
|
|
84
|
+
return {
|
|
85
|
+
name: 'writable_volume',
|
|
86
|
+
ok: false,
|
|
87
|
+
detail: `${dir} is not writable${code ? ` (${code})` : ''}`,
|
|
88
|
+
remedy: 'Ensure the daemon process can write to the state directory. In hosted deploys, mount a writable ' +
|
|
89
|
+
'persistent volume at the path pointed to by JINN_STATE_DIR (or earningDir) and give the daemon user write access.',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// state_on_volume
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
/**
|
|
97
|
+
* In a deployment context, assert resolved state lives on the configured
|
|
98
|
+
* volume — i.e. `stateDir` is set AND `earningDir` resolves under it. Advisory
|
|
99
|
+
* (always ok) outside a deployment context.
|
|
100
|
+
*/
|
|
101
|
+
export function checkStateOnVolume(input) {
|
|
102
|
+
if (!input.deployment) {
|
|
103
|
+
return {
|
|
104
|
+
name: 'state_on_volume',
|
|
105
|
+
ok: true,
|
|
106
|
+
detail: 'not a deployment context — state location is advisory only',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (!input.stateDir) {
|
|
110
|
+
return {
|
|
111
|
+
name: 'state_on_volume',
|
|
112
|
+
ok: false,
|
|
113
|
+
detail: 'deployment context but JINN_STATE_DIR / stateDir is unset — state would land on the ephemeral ~/.jinn-client default and be lost on redeploy',
|
|
114
|
+
remedy: 'Set JINN_STATE_DIR to the mounted persistent volume (e.g. JINN_STATE_DIR=/data).',
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const root = resolve(input.stateDir);
|
|
118
|
+
const earning = resolve(input.earningDir);
|
|
119
|
+
const under = earning === root || earning.startsWith(root + '/');
|
|
120
|
+
if (!under) {
|
|
121
|
+
return {
|
|
122
|
+
name: 'state_on_volume',
|
|
123
|
+
ok: false,
|
|
124
|
+
detail: `earningDir (${earning}) does not resolve under the configured volume (${root})`,
|
|
125
|
+
remedy: 'Remove the per-key earningDir/dbPath override so state derives under JINN_STATE_DIR, or point them at the volume.',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
name: 'state_on_volume',
|
|
130
|
+
ok: true,
|
|
131
|
+
detail: `state resolves under the configured volume ${root}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// credentials_resolvable
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
/**
|
|
138
|
+
* Presence-only credential check. In a bare context the operator authenticates
|
|
139
|
+
* the agent CLI interactively (claude session auth), so credentials are not
|
|
140
|
+
* env-resolvable and that is fine. In a container / compose context there is no
|
|
141
|
+
* interactive login, so SOME agent-CLI auth signal must be present in the env.
|
|
142
|
+
*
|
|
143
|
+
* NEVER returns or logs a secret value — only presence + context.
|
|
144
|
+
*/
|
|
145
|
+
export function checkCredentialsResolvable(input) {
|
|
146
|
+
// Env vars that, if present and non-empty, indicate the agent CLI can resolve
|
|
147
|
+
// credentials non-interactively. Presence only — values are never read out.
|
|
148
|
+
const AUTH_ENV_KEYS = [
|
|
149
|
+
'ANTHROPIC_API_KEY',
|
|
150
|
+
'CLAUDE_CODE_OAUTH_TOKEN',
|
|
151
|
+
'OPENROUTER_API_KEY',
|
|
152
|
+
'OPENAI_API_KEY',
|
|
153
|
+
];
|
|
154
|
+
const present = AUTH_ENV_KEYS.filter((k) => {
|
|
155
|
+
const v = input.env[k];
|
|
156
|
+
return typeof v === 'string' && v.trim().length > 0;
|
|
157
|
+
});
|
|
158
|
+
if (input.context === 'bare') {
|
|
159
|
+
return {
|
|
160
|
+
name: 'credentials_resolvable',
|
|
161
|
+
ok: true,
|
|
162
|
+
detail: present.length > 0
|
|
163
|
+
? `bare context; agent-CLI auth env present (${present.length} key(s))`
|
|
164
|
+
: 'bare context; agent CLI uses interactive session auth',
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// container / docker-compose: no interactive login path — need an env signal.
|
|
168
|
+
if (present.length > 0) {
|
|
169
|
+
return {
|
|
170
|
+
name: 'credentials_resolvable',
|
|
171
|
+
ok: true,
|
|
172
|
+
detail: `${input.context} context; agent-CLI auth env present (${present.length} key(s))`,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
name: 'credentials_resolvable',
|
|
177
|
+
ok: false,
|
|
178
|
+
detail: `${input.context} context but no agent-CLI auth credential is resolvable from the environment`,
|
|
179
|
+
remedy: 'Provide the agent CLI credentials the harness needs (e.g. ANTHROPIC_API_KEY / CLAUDE_CODE_OAUTH_TOKEN, ' +
|
|
180
|
+
'or OPENROUTER_API_KEY for the hermes harness) as a secret in the deploy environment.',
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
// relayer_reachable
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
/**
|
|
187
|
+
* If a relayer endpoint is configured, probe it (short-timeout HEAD/GET). If
|
|
188
|
+
* not configured, skip-ok. Never throws.
|
|
189
|
+
*
|
|
190
|
+
* Production passes `relayerUrl: undefined` today — no config field plumbs a
|
|
191
|
+
* relayer URL (the claim-relayer is a contract-level / off-process concept), so
|
|
192
|
+
* this degrades to skip-ok. The injectable surface keeps the reachable /
|
|
193
|
+
* unreachable paths testable.
|
|
194
|
+
*/
|
|
195
|
+
export async function checkRelayerReachable(relayerUrl, fetchImpl) {
|
|
196
|
+
if (!relayerUrl) {
|
|
197
|
+
return {
|
|
198
|
+
name: 'relayer_reachable',
|
|
199
|
+
ok: true,
|
|
200
|
+
detail: 'no claim-relayer endpoint configured — skipped',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const controller = new AbortController();
|
|
204
|
+
const timer = setTimeout(() => controller.abort(), 3000);
|
|
205
|
+
try {
|
|
206
|
+
const res = (await fetchImpl(relayerUrl, {
|
|
207
|
+
method: 'HEAD',
|
|
208
|
+
signal: controller.signal,
|
|
209
|
+
}));
|
|
210
|
+
const status = typeof res.status === 'number' ? res.status : undefined;
|
|
211
|
+
const reachable = res.ok === true || (status !== undefined && status >= 200 && status < 400);
|
|
212
|
+
if (reachable) {
|
|
213
|
+
return {
|
|
214
|
+
name: 'relayer_reachable',
|
|
215
|
+
ok: true,
|
|
216
|
+
detail: `claim-relayer responded${status !== undefined ? ` (${status})` : ''}`,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
name: 'relayer_reachable',
|
|
221
|
+
ok: false,
|
|
222
|
+
detail: `claim-relayer responded with a non-success status${status !== undefined ? ` (${status})` : ''}`,
|
|
223
|
+
remedy: 'Check the relayer service health and the configured endpoint.',
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
228
|
+
return {
|
|
229
|
+
name: 'relayer_reachable',
|
|
230
|
+
ok: false,
|
|
231
|
+
detail: `claim-relayer unreachable: ${msg}`,
|
|
232
|
+
remedy: 'Verify the relayer service is running and the endpoint/network path is reachable.',
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
clearTimeout(timer);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// agent_cli_non_root
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
/**
|
|
243
|
+
* ok when uid !== 0 (or no getuid on the platform). Fail when running as root —
|
|
244
|
+
* the agent CLI refuses to run as root, so a root daemon is unfit. Never throws.
|
|
245
|
+
*/
|
|
246
|
+
export function checkAgentCliNonRoot(getuid) {
|
|
247
|
+
if (typeof getuid !== 'function') {
|
|
248
|
+
return {
|
|
249
|
+
name: 'agent_cli_non_root',
|
|
250
|
+
ok: true,
|
|
251
|
+
detail: 'platform has no uid concept — non-root assumption holds',
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
let uid;
|
|
255
|
+
try {
|
|
256
|
+
uid = getuid();
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
// Can't determine uid: don't crash, treat as non-fatal (conservative ok —
|
|
260
|
+
// we'd rather not falsely gate a boot on an unreadable uid).
|
|
261
|
+
return {
|
|
262
|
+
name: 'agent_cli_non_root',
|
|
263
|
+
ok: true,
|
|
264
|
+
detail: 'could not read process uid — assuming non-root',
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
if (uid === 0) {
|
|
268
|
+
return {
|
|
269
|
+
name: 'agent_cli_non_root',
|
|
270
|
+
ok: false,
|
|
271
|
+
detail: 'daemon is running as root (uid 0); the agent CLI refuses to run as root',
|
|
272
|
+
remedy: 'Run the daemon as a non-root user. In containers, create and drop to a non-root user (e.g. via gosu) before launching.',
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
name: 'agent_cli_non_root',
|
|
277
|
+
ok: true,
|
|
278
|
+
detail: `running as non-root (uid ${uid})`,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
// runDeploymentReadinessChecks — the aggregate
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
/**
|
|
285
|
+
* Run every deployment-readiness check and assemble a report. Detects the
|
|
286
|
+
* deployment context internally and decides `bootFatal` accordingly. Never
|
|
287
|
+
* throws — each check degrades to a structured fail.
|
|
288
|
+
*/
|
|
289
|
+
export async function runDeploymentReadinessChecks(inputs, deps) {
|
|
290
|
+
const authContext = (() => {
|
|
291
|
+
try {
|
|
292
|
+
return deps.detectAuthContext({
|
|
293
|
+
cwd: process.cwd(),
|
|
294
|
+
env: deps.env,
|
|
295
|
+
configuredMode: inputs.runtimeMode,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
return 'bare';
|
|
300
|
+
}
|
|
301
|
+
})();
|
|
302
|
+
const deployment = isDeploymentContext({
|
|
303
|
+
env: deps.env,
|
|
304
|
+
authContext,
|
|
305
|
+
stateDir: inputs.stateDir,
|
|
306
|
+
});
|
|
307
|
+
// The writable-volume probe targets the volume root when set, else earningDir.
|
|
308
|
+
const probeDir = inputs.stateDir ?? inputs.earningDir;
|
|
309
|
+
const checks = [
|
|
310
|
+
await checkWritableVolume(probeDir),
|
|
311
|
+
checkStateOnVolume({ deployment, stateDir: inputs.stateDir, earningDir: inputs.earningDir }),
|
|
312
|
+
checkCredentialsResolvable({ context: authContext, env: deps.env }),
|
|
313
|
+
await checkRelayerReachable(inputs.relayerUrl, deps.fetch),
|
|
314
|
+
checkAgentCliNonRoot(deps.getuid),
|
|
315
|
+
];
|
|
316
|
+
const bootFatal = deployment && checks.some((c) => !c.ok && HARD_CHECK_NAMES.has(c.name));
|
|
317
|
+
return { deployment, authContext, checks, bootFatal };
|
|
318
|
+
}
|
|
319
|
+
// ---------------------------------------------------------------------------
|
|
320
|
+
// applyDeploymentReadinessGate — the boot gate (fail-loud only in deployment)
|
|
321
|
+
// ---------------------------------------------------------------------------
|
|
322
|
+
/**
|
|
323
|
+
* Boot gate for `jinn run`. Runs the readiness aggregate; in a deployment
|
|
324
|
+
* context, fail loud (emit `invalid_invocation` envelope + non-zero exit) when
|
|
325
|
+
* a hard check fails. Outside a deployment context, log advisories for any
|
|
326
|
+
* failing check and proceed. Mirrors `applyPidfileLivenessGate`'s contract:
|
|
327
|
+
* `emitEnvelope` does not return in production (it `process.exit`s).
|
|
328
|
+
*/
|
|
329
|
+
export async function applyDeploymentReadinessGate(inputs, deps, sinks = {}) {
|
|
330
|
+
const report = await runDeploymentReadinessChecks(inputs, deps);
|
|
331
|
+
const failed = report.checks.filter((c) => !c.ok);
|
|
332
|
+
if (report.bootFatal) {
|
|
333
|
+
const hardFailures = failed.filter((c) => HARD_CHECK_NAMES.has(c.name));
|
|
334
|
+
const summary = hardFailures.map((c) => `${c.name}: ${c.detail}`).join('; ');
|
|
335
|
+
emitEnvelope({
|
|
336
|
+
code: 'invalid_invocation',
|
|
337
|
+
message: `Environment is not fit to run the daemon in this deployment — ${summary}`,
|
|
338
|
+
hint: 'Run `jinn doctor --human` for the full readiness report. Fix the failing check(s) and restart.',
|
|
339
|
+
exampleCli: 'jinn doctor --human',
|
|
340
|
+
details: {
|
|
341
|
+
field: 'deployment_readiness',
|
|
342
|
+
authContext: report.authContext,
|
|
343
|
+
// Names + ok only — no secret material, no raw env values.
|
|
344
|
+
failed: hardFailures.map((c) => ({ name: c.name, detail: c.detail })),
|
|
345
|
+
},
|
|
346
|
+
}, sinks);
|
|
347
|
+
// emitEnvelope calls process.exit in production; in tests the injected exit
|
|
348
|
+
// is a no-op. Either way, do not fall through to "proceed" logging.
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
// Advisory path (local operator, or non-hard failures in a deployment ctx):
|
|
352
|
+
// surface each failing check but never gate the boot.
|
|
353
|
+
for (const c of failed) {
|
|
354
|
+
emitStructured({
|
|
355
|
+
kind: 'system',
|
|
356
|
+
message: `deployment-readiness advisory — ${c.name}: ${c.detail}`,
|
|
357
|
+
details: {
|
|
358
|
+
phase: 'preflight',
|
|
359
|
+
check: c.name,
|
|
360
|
+
deployment: report.deployment,
|
|
361
|
+
...(c.remedy ? { remedy: c.remedy } : {}),
|
|
362
|
+
},
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
//# sourceMappingURL=deployment-readiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-readiness.js","sourceRoot":"","sources":["../../src/preflight/deployment-readiness.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,11 +6,17 @@
|
|
|
6
6
|
* Branches (load-bearing — see #649 acceptance criteria):
|
|
7
7
|
* - File missing → { decision: 'proceed' }
|
|
8
8
|
* - File malformed (NaN/empty) → { decision: 'unlink-stale', reason: 'malformed' }
|
|
9
|
+
* - PID 1 or our own pid → { decision: 'unlink-stale', reason: 'self-or-pid1-container' }
|
|
9
10
|
* - process.kill(pid, 0) ESRCH → { decision: 'unlink-stale', reason: 'esrch' }
|
|
10
11
|
* - process.kill(pid, 0) ok → { decision: 'refuse', reason: 'alive' }
|
|
11
12
|
* - process.kill(pid, 0) EPERM → { decision: 'refuse', reason: 'eperm' }
|
|
12
13
|
* - any other errno → { decision: 'refuse', reason: 'unknown' }
|
|
13
14
|
*
|
|
15
|
+
* The PID-1/self branch classifies *before* the `process.kill` probe (#805): in
|
|
16
|
+
* a container the daemon is PID 1, whose pidfile outlives the container on the
|
|
17
|
+
* persistent volume; `process.kill(1, 0)` always succeeds, so a probe-first
|
|
18
|
+
* order would mis-classify the stale record as a live sibling and crash-loop.
|
|
19
|
+
*
|
|
14
20
|
* `.trim()` before `parseInt` is required: `main.ts` writes the PID with a
|
|
15
21
|
* trailing `\n` (see `client/src/main.ts` writeFileSync near the pidfile site).
|
|
16
22
|
*/
|
|
@@ -21,7 +27,7 @@ export type PidfileLivenessDecision = {
|
|
|
21
27
|
decision: 'unlink-stale';
|
|
22
28
|
pid: number | null;
|
|
23
29
|
pidfilePath: string;
|
|
24
|
-
reason: 'malformed' | 'esrch';
|
|
30
|
+
reason: 'malformed' | 'esrch' | 'self-or-pid1-container';
|
|
25
31
|
} | {
|
|
26
32
|
decision: 'refuse';
|
|
27
33
|
pid: number;
|
|
@@ -6,11 +6,17 @@
|
|
|
6
6
|
* Branches (load-bearing — see #649 acceptance criteria):
|
|
7
7
|
* - File missing → { decision: 'proceed' }
|
|
8
8
|
* - File malformed (NaN/empty) → { decision: 'unlink-stale', reason: 'malformed' }
|
|
9
|
+
* - PID 1 or our own pid → { decision: 'unlink-stale', reason: 'self-or-pid1-container' }
|
|
9
10
|
* - process.kill(pid, 0) ESRCH → { decision: 'unlink-stale', reason: 'esrch' }
|
|
10
11
|
* - process.kill(pid, 0) ok → { decision: 'refuse', reason: 'alive' }
|
|
11
12
|
* - process.kill(pid, 0) EPERM → { decision: 'refuse', reason: 'eperm' }
|
|
12
13
|
* - any other errno → { decision: 'refuse', reason: 'unknown' }
|
|
13
14
|
*
|
|
15
|
+
* The PID-1/self branch classifies *before* the `process.kill` probe (#805): in
|
|
16
|
+
* a container the daemon is PID 1, whose pidfile outlives the container on the
|
|
17
|
+
* persistent volume; `process.kill(1, 0)` always succeeds, so a probe-first
|
|
18
|
+
* order would mis-classify the stale record as a live sibling and crash-loop.
|
|
19
|
+
*
|
|
14
20
|
* `.trim()` before `parseInt` is required: `main.ts` writes the PID with a
|
|
15
21
|
* trailing `\n` (see `client/src/main.ts` writeFileSync near the pidfile site).
|
|
16
22
|
*/
|
|
@@ -35,6 +41,14 @@ export function checkPidfileLiveness(input) {
|
|
|
35
41
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
36
42
|
return { decision: 'unlink-stale', pid: null, pidfilePath: pidPath, reason: 'malformed' };
|
|
37
43
|
}
|
|
44
|
+
// #805: in a container the daemon is PID 1; the pidfile on the persistent
|
|
45
|
+
// volume outlives the container, and `process.kill(1, 0)` always succeeds, so
|
|
46
|
+
// we must classify the self/PID-1 record as stale *before* the liveness probe
|
|
47
|
+
// below — otherwise the probe reports it alive and the daemon crash-loops. A
|
|
48
|
+
// record of our own pid is likewise self, never a live sibling.
|
|
49
|
+
if (parsed === 1 || parsed === process.pid) {
|
|
50
|
+
return { decision: 'unlink-stale', pid: parsed, pidfilePath: pidPath, reason: 'self-or-pid1-container' };
|
|
51
|
+
}
|
|
38
52
|
try {
|
|
39
53
|
process.kill(parsed, 0);
|
|
40
54
|
return { decision: 'refuse', pid: parsed, pidfilePath: pidPath, reason: 'alive' };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pidfile-liveness.js","sourceRoot":"","sources":["../../src/preflight/pidfile-liveness.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pidfile-liveness.js","sourceRoot":"","sources":["../../src/preflight/pidfile-liveness.ts"],"names":[],"mappings":"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"}
|