import { type ChildProcess } from 'child_process';
import { type TemplateBundle } from './templates/viteReactTs';
import type { DesignContextEntry } from '../mcp/agent-variants/contracts';
import type { SourceContextInput } from '../mcp/agent-variants/contracts';
export declare const FRESH_WORKTREES_DIRNAME = ".rivet-variants";
export declare const INSTANCE_PREFIX: string;
export declare class WorktreeManager {
    private readonly resolveProjectPath;
    /**
     * Accepts either a static path, null, or a lazy getter. The getter form
     * lets long-lived callers (e.g. the agent-variants orchestrator) defer the
     * project path until each operation, since `bridge.getProjectPath()`
     * isn't known until `open_visual_editor` runs. A null projectPath is
     * allowed for fresh-project sessions that scaffold from scratch and
     * therefore have no source repo; methods that need a real project path
     * throw a clear error in that case.
     */
    constructor(projectPath: string | null | (() => string | null));
    private get projectPath();
    /**
     * Return the absolute git root for the repo containing this.projectPath.
     * When projectPath is a subdirectory (e.g. examples/microsoft-paint inside
     * rivet-core), this returns the repo root — not the subdirectory.
     */
    getGitRoot(): Promise<string>;
    /**
     * Ensure `this.projectPath` is inside a git repo, bootstrapping one if not.
     *
     * Fresh / blank projects (an empty folder, or a plain HTML preview) that the
     * user opens outside any repo would otherwise fail at `git worktree add`
     * (and `getGitRoot`'s `rev-parse --show-toplevel`) with "expected a git
     * workspace". We `git init` the folder and create an EMPTY initial commit so
     * `HEAD` exists — `git worktree add HEAD` requires a commit to point at, so a
     * bare `git init` on a blank folder isn't enough. `add -A` first captures
     * whatever is already there (e.g. an `index.html`) as the starting point.
     *
     * No-op when an enclosing repo already exists — we never nest a repo inside
     * another. Best-effort: a failure here surfaces at the subsequent worktree
     * step rather than masking the original operation.
     */
    ensureGitRepo(): Promise<void>;
    /**
     * Return the path to the project within a worktree.
     * When projectPath == gitRoot this is just worktreePath.
     * When projectPath is a subdirectory (e.g. rivet-core/examples/microsoft-paint),
     * this returns worktreePath/examples/microsoft-paint so the dev server starts
     * from the right directory.
     */
    getProjectCwdInWorktree(worktreePath: string): Promise<string>;
    /**
     * Translate an absolute path that lives inside the main project tree to its
     * equivalent path inside a worktree.  Paths outside the git root are returned
     * unchanged so the method is safe to call on arbitrary strings.
     */
    translateToWorktreePath(absPath: string, worktreePath: string): Promise<string>;
    /** Get diff of all uncommitted changes (staged + unstaged) vs HEAD */
    getUncommittedPatch(): Promise<string>;
    /**
     * Return untracked, non-ignored file paths relative to the git root.
     * These are files present in the working tree but not yet in any commit,
     * so `git diff HEAD` won't include them.
     */
    private getUntrackedFiles;
    /** Copy untracked files from the source repo into a worktree */
    private copyUntrackedFiles;
    /**
     * @effect Links an existing dependency install into a worktree location when the destination is absent.
     */
    private symlinkNodeModulesIfAvailable;
    /** Apply a patch string via stdin to the given cwd using git apply */
    private applyPatchViaStdin;
    /** Create N worktrees for a session, apply uncommitted patch to each, return paths */
    createWorktrees(sessionId: string, count: number): Promise<string[]>;
    /** Get git diff of all changes made in a worktree vs HEAD.
     *
     * `git diff HEAD` only covers tracked files. New files created by the agent
     * are untracked and would be silently omitted, breaking imports/styles when
     * the diff is applied to the main tree. `git add --intent-to-add .` marks
     * every untracked file in the index as a zero-length blob so `git diff HEAD`
     * includes them as pure additions without actually staging their content.
     */
    getDiff(worktreePath: string): Promise<string>;
    /**
     * Apply or revert a diff to the main project working tree.
     *
     * Because getDiff now diffs against the worktree baseline commit (HEAD +
     * user's uncommitted changes), the codeDiff contains only the agent's delta.
     * This means git apply --reverse reliably restores to the baseline state
     * (user's uncommitted changes intact) without touching git checkout HEAD,
     * which would wipe the user's pre-existing work.
     */
    applyDiff(diff: string, reverse: boolean): Promise<void>;
    /**
     * Apply a unified diff to the repository that contains the target project path.
     */
    applyDiffToProject(diff: string, projectPath: string): Promise<void>;
    /** Bind port 0 to get an OS-assigned free port */
    getFreePort(): Promise<number>;
    /** Validate a diff via `git apply --check` without modifying files */
    validateDiff(diff: string, reverse: boolean): Promise<void>;
    /**
     * Spawn a dev server and poll until it responds with a non-502 HTTP status
     * (max 30s). Throws on timeout.
     */
    startDevServer(worktreePath: string, port: number, cmd: string, args: string[], env: Record<string, string>): Promise<ChildProcess>;
    /** Stop a dev server with SIGTERM + SIGKILL fallback */
    stopDevServer(proc: ChildProcess, timeoutMs?: number): Promise<void>;
    /** Remove all worktrees for a session.
     *
     *  For existing-project sessions, asks git to unregister the worktree
     *  (handles `.git/worktrees/*` cleanup) and falls back to plain rm. For
     *  fresh-project sessions (no projectPath) the worktrees are detached
     *  directories with their own `.git` under `<destinationParent>/.rivet-variants/`
     *  — git registry cleanup is a no-op and we just rm the matching dirs.
     *
     *  `freshDestinationParent` is required when the session was fresh; pass
     *  `path.dirname(projectContext.workspacePath)` so we know which
     *  `.rivet-variants/` root to sweep.
     */
    cleanupSession(sessionId: string, freshDestinationParent?: string): Promise<void>;
    /**
     * Create N worktrees for a fresh-project session by writing a template
     * bundle into each `<destinationParent>/.rivet-variants/rivet-variants-pid<PID>-<sessionId>-<i>`
     * directory, optionally writing a DESIGN.md per slot, and committing a
     * baseline.
     *
     * Worktrees live under the user's destinationParent (not /tmp) so commit
     * time can be a same-volume rename instead of a cross-volume copy. The
     * destinationParent is registered to a small JSON file so a future MCP
     * startup can sweep orphans even when the original process crashed.
     *
     * Does NOT run `npm install` — the orchestrator dispatches that as a
     * background task so failures surface via work-item state without blocking
     * the MCP tool response.
     *
     * @effect Creates directories under destinationParent, writes template
     *         files, runs git init/add/commit, appends destinationParent to
     *         the fresh-worktree-roots registry.
     */
    createFreshWorktrees(sessionId: string, count: number, template: TemplateBundle, designContext: ReadonlyArray<DesignContextEntry | undefined> | undefined, sourceContext: SourceContextInput | undefined, destinationParent: string): Promise<string[]>;
    /**
     * Write SOURCE_CONTEXT.md when source context exists for the session.
     *
     * @effect Writes SOURCE_CONTEXT.md for source-grounded fresh worktrees.
     */
    private writeSourceContext;
    /**
     * Write the per-slot DESIGN.md for a fresh worktree.
     *
     * @effect Writes DESIGN.md when a design context is available.
     */
    private writeDesignContext;
    /**
     * Move a worktree to its history location preserving contents. Used by the
     * orchestrator at commit time so unchosen variants survive on disk as
     * runnable references (siblings of the chosen project).
     *
     * Returns the destination path (`<historyDir>/<folderName>`).
     *
     * @effect renames `srcWorktreePath` → `<historyDir>/<folderName>`, creating
     *         the historyDir if needed.
     */
    moveWorktreeToHistory(srcWorktreePath: string, historyDir: string, folderName: string): string;
    /**
     * Repoint a worktree's `node_modules` at a relative symlink so it tracks
     * the chosen variant's real install after both have moved into their new
     * permanent homes. Idempotent — removes any existing entry first.
     */
    repointNodeModulesSymlink(worktreePath: string, sharedNodeModulesAbsPath: string): void;
    /** Remove all fresh worktrees for a session.
     *
     *  @effect Removes directories under <destinationParent>/.rivet-variants/
     *          matching ${INSTANCE_PREFIX}-<sessionId>-*. Also removes the
     *          .rivet-variants/ parent if it becomes empty so the editor file
     *          tree doesn't accumulate noise.
     *
     *  When `preserve` is provided, entries whose basenames are in the set are
     *  skipped — used by the orchestrator after a vite_app commit, where the
     *  unchosen variant worktrees have already been moved to a sibling history
     *  dir and must not be re-deleted.
     */
    cleanupFreshWorktrees(sessionId: string, destinationParent: string, preserve?: ReadonlySet<string>): void;
    private assertSafeSessionId;
}
/**
 * Append a freshRoot path to the registry (de-duped). Called by
 * createFreshWorktrees so future MCP startups can sweep orphans even if
 * the original process crashed before teardown ran.
 */
export declare const registerFreshWorktreeRoot: (freshRoot: string) => void;
/**
 * Sweep orphan worktrees from /tmp (existing-project flow) and from every
 * registered fresh-worktree root (fresh-project flow). Filters by
 * INSTANCE_PREFIX (includes PID) so each server instance only removes its
 * own worktrees and never touches those of sibling instances. Prunes
 * registry entries whose directory no longer exists so the file stays small.
 */
export declare const cleanupOrphanedWorktrees: () => void;
/**
 * Prune stale worktree registry entries for a project (`.git/worktrees/<name>`
 * entries where the referenced directory no longer exists). Safe to call at
 * startup — only removes entries for directories that are already gone.
 */
export declare const pruneWorktrees: (projectPath: string) => Promise<void>;
//# sourceMappingURL=WorktreeManager.d.ts.map