/** * Resolve the runtime version a repo *pins* (Node / Python / Bun) from its * version files, so the sandbox harness can RECORD pinned-vs-actual and a * reviewer can discount environment-caused failures. This phase only * **detects** the pin — it does NOT switch runtimes (switching needs a version * manager baked into the parity-locked sandbox image; deferred follow-up). * * OyasumiVR's tests failed on the sandbox's baked Node 20 but pass on Node 22; * nothing read `.nvmrc` / `.node-version` / `engines.node`, so the reviewer saw * "confidence 0, blocked" with no hint of a runtime mismatch. This resolver is * the single tested source of truth; it is mirrored verbatim into a * `resolve_pinned_runtime` node-heredoc in `ralph-run.sh` (kept in sync exactly * like `classify_environment_failure` mirrors `environment-failure.ts`). * * Deterministic and pure: it takes already-read file CONTENTS (never touches the * filesystem or the network), validates every value against a strict pattern * before returning it, and falls through a fixed precedence. House style mirrors * `environment-failure.ts`: small helpers, a precedence list (no `switch`). */ /** Node precedence: a version file wins over the next in this order. */ export type NodeSource = '.nvmrc' | '.node-version' | 'engines.node' | '.tool-versions'; /** Python precedence source. */ export type PythonSource = '.python-version' | '.tool-versions'; /** Bun precedence source. */ export type BunSource = '.bun-version' | '.tool-versions'; /** A resolved pin for one runtime. `pinned`/`source` are null when nothing matched. */ export interface PinnedRuntime { /** The validated version/range string the repo pins, or null when none/invalid. */ pinned: string | null; /** Which file the pin came from, or null when no pin was found. */ source: string | null; } /** The pins resolved for every supported runtime. */ export interface ResolvedRuntimes { node: PinnedRuntime; python: PinnedRuntime; bun: PinnedRuntime; } /** * Already-read contents of the version files (any may be absent → undefined/null). * The resolver never reads the filesystem itself, keeping it pure and testable. */ export interface RuntimeFileContents { /** `.nvmrc` */ nvmrc?: string | null; /** `.node-version` */ nodeVersion?: string | null; /** Raw `package.json` text (parsed for `engines.node`). */ packageJson?: string | null; /** `.python-version` */ pythonVersion?: string | null; /** `.bun-version` */ bunVersion?: string | null; /** `.tool-versions` (asdf/mise format: `tool version` per line). */ toolVersions?: string | null; } /** * Resolve pinned Node/Python/Bun versions from the given file contents. * * - Node precedence: `.nvmrc` > `.node-version` > `engines.node` > `.tool-versions`. * - Python precedence: `.python-version` > `.tool-versions`. * - Bun precedence: `.bun-version` > `.tool-versions`. * * Every candidate is validated first (exact for version files, range for * `engines.node`); a missing / malformed value falls through to the next source, * and when nothing matches the runtime resolves to `{ pinned: null, source: null }` * (the caller then uses the sandbox default — no switching this phase). */ export declare function resolveRuntimeVersions(files: RuntimeFileContents): ResolvedRuntimes; //# sourceMappingURL=runtime-version.d.ts.map