/**
 * `agents run --lease` orchestrator.
 *
 * Acquire a box → provision the picked runtime(s) + their credentials → run the
 * agent on the box (via `crabbox run`, which owns the SSH) → tear the box down.
 * Acquisition is reuse-first against the shared warm pool (a ready box carrying
 * the lease profile + netMode labels is reused and kept; `--fresh` opts out and
 * always leases a new, torn-down box). Concurrent callers run from separate
 * `~/workspaces/<repo>-<run>` directories on that box. The whole box-side
 * sequence rides a single `--script-stdin` body so token contents never touch argv.
 *
 * ── Command-layer contract (RUSH-1920/1921/1924) ─────────────────────────────
 * Exports the commands layer (exec.ts / lease.ts / ssh.ts) consumes:
 *   • `buildBootstrapScript(opts)` — `opts.copySetup` (default TRUE; clear for
 *     --bare) gates the `copy-setup` progress sentinel; `opts.netMode`
 *     ('public' | 'tailscale', default 'public') adds the `joined-tailnet` step.
 *   • `LeaseRunOptions.copySetup` / `LeaseRunOptions.netMode` — forwarded by
 *     `leaseAndRun` (netMode → `crabboxWarmup`). `LeaseRunOptions.fresh`
 *     (`--fresh`) skips the warm profile-pool reuse check and always leases a
 *     new box, torn down after the run.
 *   • `crabboxWarmup(opts.netMode)` — 'tailscale' leases onto the tailnet
 *     (`--network tailscale -tailscale-tags tag:crabbox`); auth key rides the
 *     child env as `CRABBOX_TAILSCALE_AUTH_KEY` (crabboxEnv, cli.ts).
 *   • `CrabboxBox.tailscaleIPv4` / `CrabboxBox.tailscaleFQDN` — populated from
 *     the box labels by `normalizeBox` (cli.ts).
 *   • Step stream (progress.ts): `type LeaseStep`, the `onStep` router option,
 *     and the self-contained `renderStepLine(step)` helper (the lib never prints).
 *   • Setup-copy (setup-copy.ts): `copySetupToBox({ host, user?, port?,
 *     secretsBundle?, userAgentsDir?, onData? }): Promise<CopySetupResult>` — the
 *     push-from-local the command layer runs before the box run.
 */
import type { AgentId } from '../types.js';
import { type CrabboxBox } from './cli.js';
import { type DetectedRuntime } from './runtimes.js';
/** Phase signal for a lease run, so the command layer can drive a progress UI. */
export type LeasePhase = {
    kind: 'warmup';
    backend?: string;
} | {
    kind: 'reuse';
    slug: string;
} | {
    kind: 'ready';
    box: CrabboxBox;
    elapsedMs: number;
} | {
    kind: 'teardown';
};
export interface LeaseRunOptions {
    agent: string;
    prompt: string;
    mode?: string;
    model?: string;
    /** Cloud backend crabbox provisions on (hetzner/aws/do/…). */
    backend?: string;
    boxClass?: string;
    profile?: string;
    /** Per-run directory under ~/workspaces; isolates concurrent runs on one box. */
    workspaceId?: string;
    /** Runtimes to install on the box. */
    runtimes: AgentId[];
    /** Runtime credentials to copy; defaults to `runtimes`. */
    credentialRuntimes?: AgentId[];
    detected: DetectedRuntime[];
    /** Profile-dispatch config to materialize on the leased box before the run. */
    dispatchProfile?: LeaseDispatchProfile;
    /** Secrets bundle providing crabbox's provider token. */
    secretsBundle?: string;
    /**
     * Push the git-tracked subset of the local `~/.agents` onto the box before the
     * run (default TRUE). The command layer sets `false` for `--bare`. When true,
     * `buildBootstrapScript` emits the `copy-setup` progress sentinel; the actual
     * push-from-local is `copySetupToBox` (setup-copy.ts), which the command layer
     * runs before the box run.
     */
    copySetup?: boolean;
    /**
     * Network mode threaded to `crabboxWarmup` (default `'public'`). `'tailscale'`
     * leases the box onto the tailnet and adds a `joined-tailnet` progress step.
     * The command layer decides WHEN to enable it — this is plumbing only.
     */
    netMode?: 'public' | 'tailscale';
    onData?: (s: string) => void;
    /** Progress phases (warmup → ready → teardown) for a command-layer spinner. */
    onPhase?: (phase: LeasePhase) => void;
    /** Keep the box after the run instead of stopping it. */
    keep?: boolean;
    /** Existing warm crabbox slug to reuse instead of provisioning a new lease. */
    reuseBox?: string;
    /**
     * Force a brand-new box: skip the warm profile-pool reuse check and tear the
     * box down after the run (the pre-pool `--lease` behavior). `--fresh` at the
     * command layer.
     */
    fresh?: boolean;
    /**
     * Raw wrapped Claude OAuth payload (from `resolveClaudeCredentialsBlob`), written
     * to `~/.claude/.credentials.json` on the box. The command layer resolves it
     * (after consent) so this module stays free of Keychain I/O and unit-testable.
     */
    claudeCredentialsJson?: string | null;
}
export interface LeaseDispatchProfile {
    name: string;
    agent: AgentId;
    version?: string;
    env: Record<string, string>;
    description?: string;
    preset?: string;
    provider?: string;
    fallbackModel?: string;
}
export interface LeaseRunResult {
    box: CrabboxBox;
    exitCode: number | null;
    toreDown: boolean;
}
/**
 * Exit code the box-side bootstrap raises when `agents setup` did not leave a
 * usable install (`~/.agents/.system` is still not a git repo). The run-side gate
 * (`ensureInitialized`, commands/setup.ts) refuses `agents run` with "agents-cli
 * is not set up" in exactly that state, so the bootstrap aborts with this code
 * instead of running the agent into that refusal. `leaseAndRun` reads it to stop
 * a box THIS run provisioned — a newly created box that can't run is pure cost.
 */
export declare const LEASE_BOOTSTRAP_FAILED_CODE = 97;
/** Build a shell-safe, collision-resistant workspace id for one lease run. */
export declare function leaseWorkspaceId(repoRoot: string, startedAtMs?: number, pid?: number): string;
/** Isolated box-home path for one run, relative to the shared box user's home. */
export declare function leaseHomeDir(workspaceId: string): string;
/**
 * Build the single bootstrap script run on the box: ensure agents-cli, install
 * the picked runtime CLIs, write their credentials, run the agent, then shred
 * the credential files. Best-effort install steps never abort the run.
 */
export declare function buildBootstrapScript(opts: LeaseRunOptions): string;
/** Untouched-for-this-long ⇒ no active run holds the box, so an expired one is a stray. */
export declare const STRAY_GRACE_SECS = 600;
export interface StrayMatchOptions {
    /** Pool the lease belongs to (defaults to DEFAULT_CRABBOX_PROFILE). */
    profile?: string;
    /** Network mode of the lease (default 'public'); a box is partitioned by it. */
    netMode?: 'public' | 'tailscale';
    /** The box this run is using — never a stray. */
    keepSlug: string;
    /** Injectable clock (unix seconds). */
    nowSecs?: number;
    /** Idle grace window (defaults to {@link STRAY_GRACE_SECS}). */
    graceSecs?: number;
}
/**
 * Whether `box` is an EXPIRED, idle stray in this run's pool — the boxes that
 * accumulate cost. An expired box can never be reused (`poolReusableBoxes` gates
 * on an unexpired lease), yet `keep:true` leaves it running, so without a sweep a
 * fresh provision leaves the old one billing until `gc`'s 1h-idle window. Only a
 * box that is running, in the SAME profile+netMode pool, has an EXPIRED lease, and
 * has been untouched for the grace window is a stray — a mid-boot or in-use box
 * (recent `lastTouchedAt`, or an unexpired lease) is never one. Pure — testable
 * without a shell.
 */
export declare function isExpiredPoolStray(box: CrabboxBox, opts: StrayMatchOptions): boolean;
export declare function leaseAndRun(opts: LeaseRunOptions): Promise<LeaseRunResult>;
