/**
 * ProjectSandbox — One long-lived Docker container per project.
 *
 * Replaces the per-agent SandboxPool with a single container that persists
 * across gateway restarts. Agents work inside the container using standard
 * git worktrees — the same isolation model as non-sandbox mode.
 *
 * Key properties:
 * - Named Docker volume (`bobbit-workspace-<projectId>`) for /workspace
 * - `--restart unless-stopped` survives Docker daemon restarts
 * - Host .bobbit/state bind-mounted so session logs are never lost
 * - Container label `bobbit-project=<projectId>` for discovery on reconnect
 * - Init sequence (clone, npm ci, build) runs only on first create
 */
import type { PreferencesStore } from "./preferences-store.js";
import type { ToolManager } from "./tool-manager.js";
import type { Component } from "./project-config-store.js";
import type { SandboxCloneSource } from "./sandbox-clone-source.js";
interface DockerResourceLimits {
    cpus: number;
    memBytes: number;
}
/**
 * Query Docker daemon's available CPU and memory.
 * Cached for the process lifetime (Docker resource limits don't change mid-session).
 * Returns null if `docker info` fails (caller should fall back to host values).
 */
export declare function getDockerResourceLimits(): Promise<DockerResourceLimits | null>;
/**
 * Pure computation of container resource limits — easy to unit-test.
 * Takes host values and optional Docker-reported limits; returns { cpus, memoryGB }.
 */
export declare function computeResourceLimits(hostCpus: number, hostMemBytes: number, dockerCpus?: number, dockerMemBytes?: number): {
    cpus: number;
    memoryGB: number;
};
/** @internal — exported for testing only. Resets the cached Docker limits. */
export declare function _resetDockerLimitsCache(): void;
export interface ProjectSandboxOptions {
    projectId: string;
    projectDir: string;
    repoUrl: string;
    /**
     * Resolved clone source for the single-repo clone. When `kind === "mounted"`
     * the host repo is bind-mounted read-only into the container and cloned via
     * `file://`, never a raw host path. Falls back to `repoUrl` when absent.
     * See `resolveSandboxCloneSource` and `docs/design/...`.
     */
    cloneSource?: SandboxCloneSource;
    image: string;
    sandboxNetwork?: string;
    sandboxMounts?: string[];
    sandboxCredentials?: Record<string, string>;
    sandboxAgentAuthAllowed?: boolean;
    sandboxAgentAuthPrefs?: PreferencesStore | null;
    githubToken?: string;
    /** Tool manager for resolving builtin tools directory in Docker mounts. */
    toolManager?: ToolManager;
    /**
     * Multi-repo: components driving worktree-set creation. When present and any
     * component has `repo !== "."`, the sandbox enters multi-repo mode — each
     * distinct repo gets its own clone under `/workspace/<repo>` and worktrees
     * land at `/workspace-wt/<branchSlug>/<repo>`.
     * Single-repo (omitted, empty, or all `repo === "."`) is unchanged.
     */
    components?: Component[];
    /**
     * Multi-repo: optional per-repo clone URLs. Falls back to `repoUrl` if a
     * mapping is missing for a given repo (useful when all repos share a
     * remote prefix and the host can resolve them via `git remote get-url`).
     */
    repoUrlByName?: Record<string, string>;
    /**
     * Multi-repo: optional per-repo resolved clone sources. When a repo has no
     * `origin`, the resolver yields a `mounted` source so the container clones
     * via `file://` instead of an unreachable host path. Each `mounted` source's
     * host path is bind-mounted read-only at its `mountPath`.
     */
    cloneSourceByName?: Record<string, SandboxCloneSource>;
    /**
     * Live resolver for the project's `base_ref` setting. Called fresh on every
     * `createWorktree` / `createWorktreeSet` so the container path adopts the
     * current setting without sandbox recreation. Empty/undefined preserves
     * today's `symbolic-ref refs/remotes/origin/HEAD` fallback inside the
     * container. See `docs/design/base-ref.md` §6.
     */
    baseRefResolver?: () => string | undefined;
}
export interface ContainerState {
    containerId: string;
    status: "starting" | "ready" | "error";
    projectId: string;
}
export type SandboxHealthEvent = {
    type: "container-died";
    projectId: string;
    containerId: string;
} | {
    type: "container-recovered";
    projectId: string;
    containerId: string;
};
export declare class ProjectSandbox {
    private options;
    private containerId;
    private _status;
    private _readyPromise;
    private _readyResolve;
    private _readyReject;
    private _healthInterval;
    private _healthListeners;
    private _recovering;
    constructor(options: ProjectSandboxOptions);
    /** Create or reconnect to the project container. */
    init(): Promise<void>;
    /** Get the container ID (waits for init if not ready). */
    getContainerId(): Promise<string>;
    /** Get container status. */
    getStatus(): ContainerState;
    /** Create a git worktree inside the container. Returns the container-internal path. */
    createWorktree(name: string, branch: string, baseBranch?: string): Promise<string>;
    /**
     * Multi-repo aware worktree creation. Single-repo (one component with
     * `repo === "."`) collapses to today's `createWorktree(name, branch,
     * baseBranch)`. Multi-repo creates one worktree per distinct `repo` under
     * `/workspace-wt/<name>/<repo>` from sources at `/workspace/<repo>` and
     * runs each component's `worktree_setup_command` inside the container.
     *
     * See docs/design/multi-repo-components.md §7.2.
     */
    createWorktreeSet(name: string, branch: string, components: Component[], baseBranch?: string): Promise<{
        container: string;
        worktrees: Array<{
            repo: string;
            worktreePath: string;
        }>;
    }>;
    /** Remove a git worktree inside the container. */
    removeWorktree(name: string): Promise<void>;
    /** Execute a command inside the container. Returns stdout. */
    exec(args: string[], opts?: {
        cwd?: string;
        env?: Record<string, string>;
        timeout?: number;
    }): Promise<string>;
    /** Start periodic health checks. Safe to call multiple times. */
    startHealthMonitor(intervalMs?: number): void;
    /** Stop periodic health checks. */
    stopHealthMonitor(): void;
    /** Subscribe to health events. Returns unsubscribe function. */
    onHealthEvent(listener: (event: SandboxHealthEvent) => void): () => void;
    private _emitHealthEvent;
    private _healthCheck;
    /** Graceful shutdown: stop the container (don't remove — named volume persists). */
    shutdown(): Promise<void>;
    /** Full destroy: remove container AND volume. */
    destroy(): Promise<void>;
    private _initContainer;
    private _createContainer;
    private _runInitSequence;
    /**
     * Multi-repo init: clone each declared repo into `/workspace/<repo>/`.
     * Idempotent — a repo with `.git` already present is skipped.
     * Component setup commands are NOT run here; they run on each
     * worktree-set creation via `runComponentSetups`.
     */
    private _runInitSequenceMultiRepo;
    private _publishBranchToOrigin;
    private _installPostCommitHook;
    private _findContainerByLabel;
    /**
     * Returns true if the container was created from an image whose ID no
     * longer matches the current image tag — i.e. the image has been rebuilt
     * (or retagged) since the container was created. Such containers still
     * have the *old* layers installed (e.g. older pi-coding-agent version),
     * so reconnecting would fail at first RPC invocation. Conservative: on
     * any inspect error, returns false (stick with reconnect attempt rather
     * than nuking a possibly-working container).
     */
    private _isContainerImageStale;
    private _isContainerRunning;
    private _removeContainer;
    private _dockerExec;
    private _volumeName;
}
export {};
//# sourceMappingURL=project-sandbox.d.ts.map