import type { AgentId } from '../types.js';
import type { Installation, UpdateStrategyId } from './types.js';
export interface UpdateContext {
    agent: AgentId;
    installation: Installation;
    /** What the user asked for: `latest`, `oldest`, or a concrete release. */
    requested: string;
    onProgress?: (message: string) => void;
}
/** A release fetched but not yet live. */
export interface StagedRelease {
    release: string;
    /** Extensionless launch target to probe. Windows appends `.cmd` (see verifyBinaryLaunches). */
    binary: string;
    /** HOME the probe runs under — always the installation's own home. */
    home: string;
    /** Scratch dir to delete once the run finishes, or null when nothing was staged. */
    stagingDir: string | null;
}
/** Undo/finish handles returned by a commit, so update.ts owns the transaction. */
export interface CommitHandles {
    /** Put the previous release back. Must be safe to call once, immediately after commit. */
    undo: () => void;
    /** Discard the undo material. Called only once the update is durable. */
    finalize: () => void;
}
/**
 * How one class of harness replaces the release inside a frozen installation.
 *
 * Chosen from the registry's declared capabilities — never from an agent id — so
 * a harness added to `AGENTS` is covered the day it lands. See
 * {@link selectUpdateStrategy}.
 */
export interface UpdateStrategy {
    readonly id: UpdateStrategyId;
    /**
     * True only when `undo` can restore the PREVIOUS RELEASE in full — i.e. the
     * vendor artifact lives inside this installation's own directory and was
     * fetched without mutating anything global.
     *
     * It is not a switch for whether the orchestrator rolls back: `undo` always
     * runs on a post-commit failure, because every strategy that displaces
     * something must put it back. What this flag changes is what the user is
     * told, since for an installer-driven harness the global binary the vendor
     * replaced is not ours to restore.
     */
    readonly transactional: boolean;
    /** True when several installations of this agent share one binary on disk. */
    readonly sharedBinary: boolean;
    /** Turn `requested` into the concrete release this run will install. */
    resolveTarget(ctx: UpdateContext): Promise<string>;
    /** Fetch the target release into a place that is not yet live. */
    stage(ctx: UpdateContext, target: string): Promise<StagedRelease>;
    /** Make the staged release the live one. */
    commit(ctx: UpdateContext, staged: StagedRelease): Promise<CommitHandles>;
}
/**
 * Pick the update strategy for an agent from the registry's declared shape.
 *
 * The ordering mirrors `installVersion`: an npm package wins whenever one is
 * declared (kimi declares both a package and a script, and its package is what
 * `agents add` installs), then a single shared global binary, then a per-install
 * script. Anything else is an integration boundary we do not handle — it throws
 * rather than silently no-opping and reporting success.
 */
export declare function selectUpdateStrategy(agent: AgentId): UpdateStrategy;
/**
 * Whether a concrete release can be requested for this agent at all. False for
 * every self-updating harness — their installers carry no version token.
 */
export declare function supportsPinnedUpdate(agent: AgentId): boolean;
/** Guard a user-supplied release token before it reaches a path or a package spec. */
export declare function assertValidRelease(requested: string): void;
