import { Host } from './InstallFlow';
export interface HostInstallOptions {
    /** Project root where the host CLI artifacts get written (typically the user's project dir). */
    targetRoot: string;
    /** Source root for templates (defaults to dist-templates/ shipped in the package). */
    templatesRoot?: string;
}
export interface HostInstallFileAction {
    source: string;
    destination: string;
    action: 'created' | 'updated' | 'skipped-identical' | 'skipped-not-found';
    backupPath?: string;
}
export interface HostInstallResult {
    host: Host;
    targetRoot: string;
    files: HostInstallFileAction[];
    mcpSnippetPath?: string;
    notes: string[];
}
export interface HostUninstallOptions {
    /** Project root where the host CLI artifacts were written. Same shape as HostInstallOptions. */
    targetRoot: string;
}
export interface HostUninstallFileAction {
    destination: string;
    action: 'removed' | 'restored-from-bak' | 'skipped-not-found';
    /** When action='restored-from-bak', path of the .bak that was renamed back over the destination. */
    backupPath?: string;
}
export interface HostUninstallResult {
    host: Host;
    targetRoot: string;
    files: HostUninstallFileAction[];
    notes: string[];
}
export declare class HostNotYetSupportedError extends Error {
    readonly host: string;
    readonly code = "HOST_NOT_YET_SUPPORTED";
    constructor(host: string);
}
export declare class HostInstaller {
    private readonly templatesRoot;
    constructor(opts?: {
        templatesRoot?: string;
    });
    /**
     * Resolves the dist-templates/ directory relative to this compiled file.
     * Source: src/cli/HostInstaller.ts → compiled: dist/cli/HostInstaller.js
     * Going up twice from dist/cli/ lands on the package root where dist-templates/ lives.
     * Works in both repo-dev (npm run build) and consumer-installed (node_modules/@openlife/cli/) layouts.
     */
    static defaultTemplatesRoot(): string;
    /**
     * Dispatch on validated Host. Throws HostNotYetSupportedError for hosts without an installer.
     */
    install(host: Host, options: HostInstallOptions): HostInstallResult;
    installForClaudeCode(options: HostInstallOptions): HostInstallResult;
    /**
     * Story 9.3 — Real implementation for the `gemini-cli` host.
     *
     * Mirrors `installForClaudeCode` exactly, swapping `.claude/` for
     * `.gemini/` and the source template directory for
     * `dist-templates/gemini-cli/`. Same uninstall pattern.
     */
    installForGeminiCli(options: HostInstallOptions): HostInstallResult;
    /**
     * Story 9.4 — Real implementation for the `codex` host.
     *
     * Mirrors `installForClaudeCode`, swapping `.claude/` for `.codex/`
     * and template root for `dist-templates/codex/`.
     */
    installForCodex(options: HostInstallOptions): HostInstallResult;
    /**
     * Shared implementation extracted so gemini-cli and codex don't drift
     * from the claude-code pattern. Same shape as installForClaudeCode.
     */
    private installForHost;
    /**
     * Dispatch on validated Host for uninstall. Throws HostNotYetSupportedError for hosts
     * without an uninstaller (currently only claude-code is supported, mirroring install).
     */
    uninstall(host: Host, options: HostUninstallOptions): HostUninstallResult;
    uninstallForClaudeCode(options: HostUninstallOptions): HostUninstallResult;
    /** Story 9.3 uninstall — mirrors uninstallForClaudeCode for `.gemini/`. */
    uninstallForGeminiCli(options: HostUninstallOptions): HostUninstallResult;
    /** Story 9.4 uninstall — mirrors uninstallForClaudeCode for `.codex/`. */
    uninstallForCodex(options: HostUninstallOptions): HostUninstallResult;
    private uninstallForHost;
    /**
     * Recursively remove our slash-command files under a commands/openlife/ tree
     * and rmdir any now-empty directories — including the nested agents/ and flow/
     * subnamespaces the recursive installer (copyDir) now creates. Symmetric with
     * install: what copyDir writes, this removes. User-edited files restored from
     * .bak keep their directory alive (so the namespace dir is only removed when
     * fully ours). Pushes one action per file into `files`. Returns whether the
     * top-level namespace directory ended up removed.
     */
    private cleanCommandsNamespace;
    private copyDir;
    /**
     * Story 3.4 — Remove a file installed by Story 3.3, restoring the user's edit
     * from .bak if one exists. Returns the action descriptor for the result envelope.
     *
     * Behavior:
     *   - dst exists, dst.bak exists: rename dst.bak → dst (user's edit survives), action='restored-from-bak'
     *   - dst exists, no .bak: unlink dst, action='removed'
     *   - dst missing: action='skipped-not-found'
     */
    private removeFileWithBakRestore;
    private copyFile;
}
