import { type SpawnOptions } from "node:child_process";
/** The managed TTS venv root, e.g. <dataDir>/tts-venv. Honours
 *  AUTOVIRAL_DATA_DIR via dataDir, so tests stay isolated. */
export declare function ttsVenvDir(): string;
/** Platform-correct path to a console-script inside the venv (venv layout
 *  differs on Windows: Scripts/<name>.exe vs bin/<name>). */
export declare function venvBinPath(name: string): string;
/** Absolute path to the venv's Python interpreter (used to import stable_whisper
 *  for ASR — the import must run under the SAME interpreter pip installed into).
 *  Falls back to bare "python3" when the venv hasn't been provisioned yet, so a
 *  caller that skips ensureTtsVenv() still degrades to the host interpreter. */
export declare function venvPythonPath(): string;
/** True once the venv has BOTH managed deps — the edge-tts console-script AND
 *  the stable-ts (`stable_whisper`) package — i.e. a previous ensureTtsVenv()
 *  fully provisioned it. Pure read; safe to call anywhere.
 *
 *  WHY BOTH (live-reproduced bug): a venv created by an early edge-tts-only path
 *  (TTS used before ASR) has edge-tts but NOT stable-ts. If readiness probed
 *  edge-tts alone, ensureTtsVenv() would short-circuit "already provisioned" and
 *  the captions/ingest ASR path would 503 forever with a manual pip hint. Gating
 *  on both deps forces ensureTtsVenv() to re-run the (idempotent, --upgrade) pip
 *  step and back-fill the missing dep. */
export declare function ttsVenvReady(): boolean;
/** Result of a single spawned command. */
export interface SpawnResult {
    code: number | null;
    stderr: string;
    stdout: string;
}
/** Run a command, capturing exit code + stdio. Injectable so tests can mock the
 *  whole child_process layer without ever creating a venv or hitting PyPI. */
export type Spawner = (cmd: string, args: string[], opts?: SpawnOptions) => Promise<SpawnResult>;
/** Raised when python3 itself is unavailable — distinct from a pip failure so
 *  the caller can surface the right "install Python" vs "install failed" hint.
 *  errorCode mirrors the audio router's PYTHON_DEP_MISSING contract. */
export declare class PythonMissingError extends Error {
    readonly errorCode = "PYTHON_DEP_MISSING";
    constructor(message: string);
}
export interface EnsureTtsVenvOptions {
    /** Injected for tests — defaults to the real promisified spawn. */
    spawner?: Spawner;
    /** Force a re-provision even if the venv looks ready (default false). */
    force?: boolean;
}
/**
 * Idempotently provision <dataDir>/tts-venv with edge-tts + stable-ts.
 *
 * Steps (each skipped when already satisfied):
 *   1. if edge-tts AND stable-ts are both already present → no-op (idempotent).
 *      NB readiness requires BOTH deps, so a venv with only edge-tts (an early
 *      TTS-before-ASR machine) does NOT short-circuit here — it falls through to
 *      the pip step and back-fills stable-ts.
 *   2. verify python3 is runnable; if not → throw PythonMissingError with a
 *      copy-paste-able install hint (we cannot bundle a system Python here).
 *   3. `python3 -m venv <dataDir>/tts-venv` (skipped if the venv python exists).
 *   4. `<venv>/bin/python -m pip install --upgrade edge-tts stable-ts` — RUN
 *      whenever stable-ts isn't importable under the venv interpreter (probed
 *      via `import stable_whisper`), even if edge-tts already exists. --upgrade
 *      makes the re-run safe + idempotent on already-satisfied deps.
 *
 * Best-effort: a pip failure throws (so the caller can surface a real error to
 * the user) but creation NEVER runs twice concurrently — a burst of TTS calls
 * shares one in-flight promise. Returns once the venv is ready (or throws).
 *
 * LAZY by contract: callers invoke this right before the first TTS/ASR use, not
 * at daemon boot — `python3 -m venv` + pip download can take many seconds and
 * must never block the server starting.
 */
export declare function ensureTtsVenv(opts?: EnsureTtsVenvOptions): Promise<void>;
/** Progress sink for the chromium download — the trends scrape route can wire
 *  this to a UI toast / log line so a ~150MB download isn't a blank stall. */
export type ProgressReporter = (line: string) => void;
export interface EnsurePlaywrightOptions {
    spawner?: Spawner;
    /** Surfaced progress lines (download %, "browser already installed", …). */
    onProgress?: ProgressReporter;
    /** Force a re-install even if a cached browser looks present. */
    force?: boolean;
}
/**
 * Lazily ensure Playwright's chromium browser is installed (first trends-scrape
 * use). Short-circuits to a no-op when chromium is already in the browsers
 * cache; otherwise runs `playwright install chromium`, downloading ~150MB.
 * NEVER called at install/boot — only on first use, per PRD-0003 §1's layered
 * strategy (heavy optional deps download on first use, with progress, not at
 * install time).
 *
 * The CLI is resolved to its absolute bundled path (not bare `npx`) so a
 * stripped PATH can't break the spawn — consistent with deps.ts. If the path
 * can't be resolved we fall back to `npx playwright …`.
 *
 * Progress is surfaced line-by-line via opts.onProgress so the caller can show
 * the user a download indicator instead of a frozen blank.
 *
 * Best-effort + coalesced: concurrent scrapes share one in-flight install.
 * A failure throws so the caller can fall back / report; it does not retry here.
 */
export declare function ensurePlaywrightChromium(opts?: EnsurePlaywrightOptions): Promise<void>;
export declare function whisperModelLazyDownloadNote(): string;
/** Clear in-flight guards so idempotency / concurrency tests can re-run under a
 *  freshly mutated env / filesystem. */
export declare function _resetPythonEnvForTests(): void;
//# sourceMappingURL=python-env.d.ts.map