import { ChildProcess } from 'node:child_process';

/**
 *
 * Subprocess wrappers for the local coding-harness CLIs installed in the
 * sandbox image (claude-code, codex, opencode). Used by the in-process
 * delegation executor (`createInProcessExecutor`) so a delegated coding task
 * spawns a real harness on a real git worktree instead of provisioning a
 * sibling sandbox.
 *
 * All harness invocations:
 *   - run with `cwd` set to the worktree
 *   - inherit env from the parent (the MCP server inside the sandbox has
 *     the harness's auth already)
 *   - capture stdout/stderr
 *   - support cancellation via AbortSignal
 *   - enforce a wall-clock timeout
 *
 * @experimental
 */

/** Local coding harness available inside the sandbox. */
type LocalHarness = 'claude' | 'codex' | 'opencode';
/** @experimental */
interface RunLocalHarnessOptions {
    harness: LocalHarness;
    /** Working directory for the subprocess (typically a worktree path). */
    cwd: string;
    /** Prompt forwarded as the harness CLI's task argument. */
    taskPrompt: string;
    /**
     * Pre-built command + args (e.g. from `harnessInvocation` so the full authored
     * `AgentProfile` — systemPrompt + model — reaches the harness). When set it OVERRIDES the
     * default prompt-only `buildArgs(taskPrompt)` path; `command` defaults to the harness's
     * default binary when only `args` is supplied. When absent the legacy prompt-only shape
     * is used unchanged.
     */
    invocation?: {
        command?: string;
        args: ReadonlyArray<string>;
    };
    /** Allow autonomous Claude edits without an interactive permission prompt.
     *  Use only when `cwd` is an isolated candidate worktree. */
    dangerouslySkipPermissions?: boolean;
    /** Isolate Codex from ambient configuration/instructions and require JSONL token usage.
     *  The invocation should come from `harnessInvocation(..., { codexReproducible: true })`. */
    codexReproducible?: boolean;
    /** Absolute host paths that reproducible Codex must not read. The normalized set is compiled
     *  into the controlled permission profile and its digest is returned in execution evidence. */
    codexReadDeniedPaths?: ReadonlyArray<string>;
    /** Wall-clock kill deadline (ms). Default 5 min. Subprocess SIGTERMed on expiry. */
    timeoutMs?: number;
    /** Caller cancellation. SIGTERM is sent on abort. */
    signal?: AbortSignal;
    /** Override env (defaults to inheriting from the parent). */
    env?: NodeJS.ProcessEnv;
    /**
     * Test seam — inject a custom spawner so unit tests can mock the
     * subprocess without touching the OS. Defaults to node's `child_process.spawn`.
     */
    spawn?: (command: string, args: ReadonlyArray<string>, opts: {
        cwd: string;
        env: NodeJS.ProcessEnv;
        stdio: 'pipe';
        detached: boolean;
    }) => ChildProcess;
    /** Test seam for locating the native Codex executable before it is staged in the worktree. */
    resolveCodexExecutable?: (command: string, env: NodeJS.ProcessEnv) => Promise<string>;
}
/** Exact aggregate usage emitted by Codex's terminal `turn.completed` JSONL event. */
interface CodexTokenUsage {
    inputTokens: number;
    cachedInputTokens: number;
    outputTokens: number;
    reasoningOutputTokens: number;
}
/** Isolation settings asserted before a reproducible Codex run is allowed to start. */
interface CodexExecutionPolicy {
    sessionPersistence: 'ephemeral';
    userConfig: false;
    rules: false;
    projectInstructions: false;
    skillInstructions: false;
    appInstructions: false;
    toolSuggestions: false;
    multiAgentInstructions: false;
    sandbox: 'workspace-write';
    permissionProfile: 'agent_runtime_reproducible';
    approvalPolicy: 'never';
    shellNetwork: false;
    webSearch: false;
    serviceTier: 'default';
    shellEnvironment: 'core-filtered';
    loginShell: false;
    credentialsReadable: false;
    hostHomeReadable: false;
    procEnvironment: 'private-sanitized';
    sensitiveEnvironmentNamesVisible: false;
    parentRepoRead: false;
    gitMetadata: false;
    temporaryDirectory: 'workspace-private';
    stagedExecutable: 'static-elf-read-only';
    callerReadDeniedPaths: 'enforced';
    containerSockets: false;
}
/** Zero-model-call evidence for the exact Codex process about to run. */
interface CodexExecutionEvidence {
    cliVersion: string;
    executableSha256: string;
    /** SHA-256 of the exact composed prompt argument proved present in the rendered prompt. */
    requestedPromptSha256: string;
    effectivePromptSha256: string;
    nonPromptArgsSha256: string;
    controlledConfigSha256: string;
    /** Sorted normalized paths compiled into the permission profile. */
    readDeniedPaths: string[];
    readDeniedPathsSha256: string;
    readDeniedPathCount: number;
    policy: CodexExecutionPolicy;
}
/** @experimental */
interface LocalHarnessResult {
    /** OS exit code. `null` when killed before exit. */
    exitCode: number | null;
    /** Concatenated stdout. */
    stdout: string;
    /** Concatenated stderr. */
    stderr: string;
    /** Set when the process exited via signal (timeout / abort). */
    killedBySignal: NodeJS.Signals | null;
    /** Wall-clock duration ms (spawn → exit). */
    durationMs: number;
    /** Set when timeoutMs elapsed before exit. */
    timedOut: boolean;
    /** Present for a reproducible Codex run; parsed from the real terminal JSONL event. */
    usage?: CodexTokenUsage;
    /** Present for reproducible Codex runs; generated and checked before model execution. */
    evidence?: CodexExecutionEvidence;
}
/**
 * Spawn a local coding harness CLI as a subprocess + collect its output.
 *
 * NOT responsible for parsing the harness's output or extracting a diff —
 * the in-process executor's `streamPrompt` orchestrates `git diff` against
 * the worktree after this resolves. This function is intentionally narrow:
 * spawn, wait, capture, return.
 *
 * Fails loud — throws when:
 *   - `cwd` doesn't exist (subprocess emits ENOENT; surfaced as Error)
 *   - the harness binary is not on PATH (ENOENT)
 *
 * Does NOT throw when:
 *   - the subprocess exits non-zero (`result.exitCode` carries the code)
 *   - the subprocess is aborted / timed out (`result.killedBySignal` /
 *     `result.timedOut` carries the reason)
 *
 * @experimental
 */
declare function runLocalHarness(options: RunLocalHarnessOptions): Promise<LocalHarnessResult>;
/** Parse and validate the one terminal usage event emitted by `codex exec --json`. */
declare function parseCodexTokenUsage(stdout: string): CodexTokenUsage;

export { type CodexTokenUsage as C, type LocalHarness as L, type RunLocalHarnessOptions as R, type CodexExecutionEvidence as a, type CodexExecutionPolicy as b, type LocalHarnessResult as c, parseCodexTokenUsage as p, runLocalHarness as r };
