/** * declared-env.ts — resolve and assemble the declared test environment * (Features A + B) for the experimenter spawn. * * Feature A (passEnv): forward named host env vars if present. * Feature B (env): inject explicit key→value pairs whose values support * stage-time interpolation tokens. An unknown token is a hard preflight error. * * The security-critical union (protected-key collisions, redaction) lives in * `applyDeclaredEnv`/`formatForwardedEnvLine` (utils); this module owns the * agent-skills-specific concerns: token computation, interpolation, and gluing * the result onto the plugin-root env. */ /** * Resolved stage-time interpolation tokens (all absolute, forward-slash). * * `fixturesDir` is optional because it is PER-EVAL: it names the eval's own staged * input workspace, which exists only when that eval declares input `files`. Every * other token is run-scoped. */ export interface EnvInterpolationTokens { fixturesDir?: string; stagedSkillDir: string; harnessRoot: string; resultsDir: string; } /** * A declared `env` value referenced an unknown `${token}`. Exit 2 (preflight): * fail loud naming the offending token rather than forwarding a literal `${x}`. */ export declare class UnknownEnvTokenError extends Error { readonly token: string; readonly key: string; readonly exitCode: 2; constructor(token: string, key: string); } /** * A declared `env` value used `${fixturesDir}` for an eval that has no staged * input workspace, so the token names nothing. Exit 2 (preflight): fail loud * rather than hand the executor a path that does not exist. * * This is the failure mode that made the token's own regression invisible — * `interpolateEnvValue` is a plain string substitution, so a token resolving to a * deleted directory produced a dead path the skill only discovered at runtime, * where it read as a skill bug rather than a harness one. */ export declare class UnresolvableEnvTokenError extends Error { readonly token: string; readonly key: string; readonly exitCode: 2; constructor(token: string, key: string); } export interface EnvTokenInputs { subjectStagedDir: string; harnessRoot: string; resultsDir: string; /** Evals subpath (e.g. `evals/evals.json`). Retained for the run-scoped tokens. */ evalsSubpath: string; /** * The eval's staged input workspace, when it declares input `files`. `fixtures/` * beneath it is what `${fixturesDir}` names. */ workspaceDir?: string; } /** * Compute the interpolation tokens from the known staged dirs. * * `fixturesDir` used to be `//fixtures`. Eval-suite isolation * DELETES that directory from every staged subject — it holds the answer key, and * `fixtures/` is its child — so the old token named a path that provably does not * exist. Each eval's declared input `files` are now staged into the eval's own * workspace, which is also the executor's working directory, so that workspace's * `fixtures/` is what the token means. An eval with no declared `files` has no * workspace and therefore no fixtures dir: the token stays undefined and * interpolating it throws {@link UnresolvableEnvTokenError} rather than silently * producing a dead path. * * Pointing this back at the staged (or held) suite directory would hand the * executor a sibling path to `evals.json` and reopen the answer-key leak. */ export declare function computeEnvTokens(inputs: EnvTokenInputs): EnvInterpolationTokens; /** Interpolate every `${token}` in `value`. Throws UnknownEnvTokenError on an unknown token. */ export declare function interpolateEnvValue(value: string, key: string, tokens: EnvInterpolationTokens): string; /** * Preflight check for token NAMES only, with no resolution. * * `${fixturesDir}` cannot be resolved run-scoped — it names a per-eval workspace — * but a TYPO in any token should still fail before the run spends a cent. This * runs once at preflight; {@link resolveInjectEnv} then resolves per eval. */ export declare function assertKnownEnvTokens(injectEnv: Record | undefined): void; /** Resolve every value in a declared `env` map. undefined in → undefined out. */ export declare function resolveInjectEnv(injectEnv: Record | undefined, tokens: EnvInterpolationTokens): Record | undefined; export interface AssembleChildEnvInput { /** The scrubbed, auth-resolved forwarded env (the deny-all base). */ base: NodeJS.ProcessEnv; /** Parent env to read Feature-A pass-through values from. */ source: NodeJS.ProcessEnv; /** Feature A names. */ passEnv?: readonly string[]; /** Feature B values, already interpolated. */ injectEnv?: Record; /** Subject's staged plugin root (null = standalone). */ subjectPluginRoot: string | null; } export interface AssembledChildEnv { env: NodeJS.ProcessEnv; warnings: string[]; /** Single-line stderr transparency summary (no trailing newline). */ line: string; } /** * Union the declared test env onto `base`, add the plugin-root var, and render * the transparency line. Protected-key collisions surface as warnings; secrets * and pass-through values are redacted in the line. */ export declare function assembleChildEnv(input: AssembleChildEnvInput): AssembledChildEnv; //# sourceMappingURL=declared-env.d.ts.map