/**
 * WorktreeManager — Topic-bound parallel-dev isolation (PARALLEL-DEV-ISOLATION-SPEC.md iter 4).
 *
 * Source of truth for: topic→worktree bindings, exclusive locks, fencing tokens,
 * commit-trailer signing, force-take protocol, state reconciliation matrix.
 *
 * Two storage layers:
 *   - Machine-local (gitignored): bindings, locks, fencing, binding-history.db, snapshots/
 *   - Git-synced (signed): topic-branch-map (path-free), binding-history-log.jsonl
 *
 * Authority model:
 *   - Local advisory: pre-commit gate (cwd-vs-binding, lock-owner)
 *   - Local authoritative-on-trailer: commit-msg hook (Ed25519 sign tree+nonce+parent)
 *   - Origin authoritative: GitHub Repository Ruleset + workflow check (Ed25519 verify offline)
 *
 * Same-topic concurrency: EXCLUSIVE — one session per topic worktree.
 */
import { EventEmitter } from 'node:events';
export type WorktreeMode = 'dev' | 'read-only' | 'doc-fix' | 'platform';
export interface WorktreeBinding {
    topicId: number | 'platform';
    slug: string;
    branch: string;
    worktreePath: string;
    mode: WorktreeMode;
    status: 'active' | 'merged' | 'abandoned' | 'lost' | 'quarantined';
    createdAt: string;
    createdBy: string;
    machineId: string;
    fencingToken: string;
    serverSignature: string;
}
export interface SessionLock {
    schema: 'v2';
    machineId: string;
    bootId: string;
    pid: number;
    processStartTime: number;
    sessionId: string;
    fencingToken: string;
    topicId: number | 'platform';
    acquiredAt: string;
    heartbeatAt: string;
    serverSignature: string;
}
export interface ResolveResult {
    cwd: string;
    branch: string;
    fencingToken: string;
    sessionContextPath: string;
    mode: WorktreeMode;
    binding: WorktreeBinding;
}
export interface SignedTrailerResult {
    trailers: string[];
    nonce: string;
    issued: number;
    maxPushDelay: number;
    keyVersion: number;
}
export interface WorktreeManagerOptions {
    projectDir: string;
    stateDir: string;
    signingKey: {
        privateKeyPem: string;
        publicKeyPem: string;
        keyVersion: number;
    };
    hmacKey: Buffer;
    machineId: string;
    bootId: string;
    repoOriginUrl: string;
    fsTypeProbe?: () => Promise<FsType>;
    maxPushDelaySeconds?: number;
}
type FsType = 'apfs' | 'btrfs' | 'xfs' | 'ext4' | 'hfs+' | 'ntfs' | 'tmpfs' | 'unknown';
export declare class WorktreeManager extends EventEmitter {
    private opts;
    private bindings;
    private locks;
    private fencingCounter;
    private bindingsFile;
    private fencingFile;
    private bindingHistoryLog;
    private worktreesRoot;
    private snapshotsDir;
    private quarantineDir;
    constructor(options: WorktreeManagerOptions);
    /**
     * Load persistent state from disk. Idempotent.
     */
    initialize(): void;
    private loadBindings;
    private saveBindings;
    private loadFencing;
    private saveFencing;
    private loadLocks;
    private hmacHex;
    private signBinding;
    private verifySignature;
    private signLock;
    private verifyLockSignature;
    private nextFencingToken;
    /**
     * Atomically: ensure binding for (topicId, mode) exists, ensure worktree exists,
     * acquire exclusive lock, return the cwd to spawn into.
     *
     * Throws on lock contention with `code: 'LOCK_HELD'`.
     */
    resolve(args: {
        topicId: number | 'platform';
        mode: WorktreeMode;
        sessionId: string;
        pid: number;
        processStartTime: number;
        slug?: string;
    }): Promise<ResolveResult>;
    /**
     * Release the lock held by (sessionId, fencingToken). No-op if not the holder.
     */
    release(args: {
        sessionId: string;
        fencingToken: string;
    }): {
        released: boolean;
    };
    /**
     * Server-stamped heartbeat. Validates fencing token before accepting.
     */
    heartbeat(args: {
        sessionId: string;
        fencingToken: string;
    }): {
        ok: boolean;
        reason?: string;
    };
    /**
     * Force-take an existing lock (per spec section "Force-take protocol iter 4").
     * Performs FS snapshot + scoped stash (no --include-ignored), then bumps fencing token.
     */
    forceTake(args: {
        topicId: number | 'platform';
        mode: WorktreeMode;
        bySessionId: string;
        pid: number;
        processStartTime: number;
    }): Promise<{
        snapshotPath: string;
        stashRef: string | null;
        previousLock: SessionLock | null;
    }>;
    /**
     * Issue a signed trailer set for a new commit.
     * The hook calls this after computing treeHash + parents.
     */
    signTrailer(args: {
        sessionId: string;
        fencingToken: string;
        treeHash: string;
        parents: string[];
    }): SignedTrailerResult;
    /**
     * Verify a trailer set (used by GH check via /gh-check/verify-nonce).
     * Returns ok plus a reason on failure (uniform error for oracle protection).
     */
    verifyTrailer(args: {
        trailers: Record<string, string>;
        pushReceivedAt?: number;
    }): {
        ok: boolean;
        reason?: string;
    };
    /**
     * Append-only signed log with Merkle chain (K3 hardening).
     *
     * Each entry includes `prevEntrySha = sha256(previousLine)`, so a malicious
     * `git rebase -i` that drops or reorders entries breaks the chain — detectable
     * by `verifyHistoryChain()`. The chain head is periodically anchored to a
     * GitHub Repo Variable for cross-machine tamper detection.
     */
    private appendHistoryEvent;
    /**
     * Compute SHA-256 of the most recent log line (Merkle chain head).
     * Returns null on empty log.
     */
    computeChainHead(): string | null;
    /**
     * Walk the entire log and verify (a) HMAC of each line, and (b) prevEntrySha
     * chain integrity. Returns null on success, or the first detected breach.
     */
    verifyHistoryChain(): {
        lineNumber: number;
        reason: string;
    } | null;
    /**
     * Check whether nonce was previously used for a different commit.
     * Idempotent: returns 'unseen' or 'seen-for-same-commit' (allowed retry) or 'seen-for-different-commit'.
     */
    checkNonceUnique(args: {
        nonce: string;
        commitSha: string;
    }): 'unseen' | 'seen-for-same-commit' | 'seen-for-different-commit';
    /**
     * Bind a commit SHA to a previously-issued trailer (called post-push).
     */
    recordCommitForNonce(args: {
        nonce: string;
        commitSha: string;
    }): void;
    private createBinding;
    /**
     * Decide whether to create a self-contained clone instead of a git
     * worktree. True when the source `projectDir` is outside agent home —
     * which is when the sandbox-revocation hazard applies. Set
     * `INSTAR_WORKTREE_FORCE_CLONE=1` to force clone regardless (for tests +
     * unusual deployments); set `INSTAR_WORKTREE_FORCE_WORKTREE=1` to force
     * the legacy worktree path (rollback escape hatch).
     *
     * Spec: docs/specs/silently-stopped-trio.md
     */
    private shouldCloneInsteadOfWorktree;
    private fastCopyDeps;
    private snapshotWorktree;
    private writeLockAtomic;
    private isLockLive;
    /**
     * Walk worktree state from three sources (bindings ∪ filesystem ∪ git worktree list)
     * and return the rows that need action per the matrix.
     */
    reconcile(): Array<{
        row: string;
        binding: WorktreeBinding | null;
        gitWorktree: {
            path: string;
        } | null;
        fsPath: string | null;
        action: string;
    }>;
    private bindingKey;
    getBinding(topicId: number | 'platform', mode: WorktreeMode): WorktreeBinding | undefined;
    listBindings(): WorktreeBinding[];
    getLock(worktreePath: string): SessionLock | undefined;
}
/**
 * Build a WorktreeManager from an instar agent config + machine identity.
 * Generates an HMAC key on first start; persists to keychain (or flat file fallback).
 */
export declare function createWorktreeManager(args: {
    projectDir: string;
    stateDir: string;
    signingKey: {
        privateKeyPem: string;
        publicKeyPem: string;
        keyVersion: number;
    };
    hmacKey: Buffer;
    machineId: string;
    repoOriginUrl: string;
}): WorktreeManager;
export {};
//# sourceMappingURL=WorktreeManager.d.ts.map