/**
 * Device placement for `--device auto`.
 *
 * Explicit auto placement probes live fleet health and harness readiness.
 * Historical affinity remains for generic host resolution callers.
 * Account selection is separate (`--strategy balanced` / rotate.ts).
 */
import { type AffinityRow } from './session/db.js';
import { type DevicePlacementSignal } from './teams/scheduler.js';
import type { AgentType } from './teams/agents.js';
/** Peakiness of usage weights; >1 amplifies the most-used option. */
export declare const DEFAULT_AFFINITY_ALPHA = 1.3;
export interface WeightedCandidate {
    key: string;
    launches: number;
    weight: number;
}
/**
 * Convert affinity rows into positive weights: launches^α (floor 1 for any
 * row with launches > 0 so a single-use host still participates).
 */
export declare function affinityWeights(rows: AffinityRow[], alpha?: number): WeightedCandidate[];
/**
 * Weighted random sample. Returns null when candidates is empty.
 * Pure — inject `rng` for tests.
 */
export declare function sampleWeighted(candidates: WeightedCandidate[], rng?: () => number): string | null;
/**
 * Online device names from the local registry (+ local), narrowed to the
 * automatic-placement pool.
 *
 * The pool rule lives in `devices/pool.ts` and is an allowlist once any device
 * is marked `role=worker`: this is the single place both automatic-placement
 * paths (`resolveDeviceAuto`, `resolveDeviceAffinity`) get their candidates, so
 * marking workers moves every `--device auto` at once instead of one surface.
 *
 * It CAN return an empty list — a fleet where every marked worker is
 * offline, or where this box is the only candidate and is marked `personal`. That is a
 * real answer, and both callers fail loud on it rather than falling back to the
 * local machine (which would be the exact box the operator marked personal to
 * keep agents off).
 */
export declare function listOnlineDeviceNames(localName?: string): string[];
export interface DeviceAffinityOptions {
    sinceDays?: number;
    alpha?: number;
    /**
     * Eligible hosts (normalized). Defaults to the automatic-placement pool
     * (online devices + local, narrowed by device roles). An explicitly empty
     * list falls back to local — the caller supplied it; an empty DEFAULT pool
     * throws, because roles emptied it on purpose.
     */
    eligibleHosts?: string[];
    localMachine?: string;
    /** Injected affinity (tests). When omitted, reads sessions.db. */
    deviceAffinity?: AffinityRow[];
    rng?: () => number;
    project?: string;
}
export interface DeviceAffinityPlan {
    /** null means run locally (do not pass --device). */
    host: string | null;
    deviceCandidates: WeightedCandidate[];
    pickedDeviceKey: string | null;
}
/** Live placement plan used by the explicit `--device auto` surface. */
export interface DeviceAutoPlan {
    /** null means the local machine won the comparison. */
    host: string | null;
    candidates: Array<{
        key: string;
        loadPercent?: number;
        installed?: boolean;
        signedIn?: boolean;
    }>;
    pickedDeviceKey: string;
}
/**
 * The error both automatic-placement resolvers raise when device roles leave no
 * candidate at all. Fail loud: the alternative — quietly running on the local
 * machine — puts the agent on the box the operator marked `personal`.
 */
export declare function formatEmptyAutoPoolError(): string;
export declare function formatNoHealthyDeviceError(pool: string[], signals: Map<string, DevicePlacementSignal>, agent?: string): string;
/**
 * Pick the least-loaded healthy device that can run `agent` when the harness is
 * known. `run auto` omits the agent and treats any ready account on the device
 * as eligible. The local machine participates in the
 * same probe and must pass the same eligibility checks. An empty eligible pool
 * fails loud; automatic placement never silently becomes a local launch.
 */
export declare function resolveDeviceAuto(agent?: string, opts?: {
    eligibleHosts?: string[];
    localMachine?: string;
    /** Route only to devices with a row the interactive account picker can launch. */
    accountPicker?: boolean;
    probe?: (pool: string[], agent?: AgentType) => Promise<Map<string, DevicePlacementSignal>>;
    /**
     * Preferred hosts (`auto-launch.preferred`) that get the ranking boost.
     * Defaults to the stored fleet block resolved over the candidate pool;
     * injectable so a test pins it without touching disk.
     */
    preferred?: ReadonlySet<string>;
}): Promise<DeviceAutoPlan>;
/**
 * Resolve host for `--device auto`. Does NOT pick harness or accounts.
 *
 * Draws from the same automatic-placement pool as {@link resolveDeviceAuto}, so
 * `agents ssh auto`, the generic `--device auto` passthrough, and `matchHost`'s
 * `auto` sentinel honour device roles too. Throws when roles leave the pool
 * empty — a `null` host here means "run locally", which for a box marked
 * `personal` is the outcome the mark exists to prevent.
 */
export declare function resolveDeviceAffinity(opts?: DeviceAffinityOptions): DeviceAffinityPlan;
/** True when a host flag value means affinity pick. */
export declare function isDeviceAuto(value: string | undefined | null): boolean;
export type DeviceAutoHostOptions = {
    host?: string;
    device?: string;
    on?: string;
    computer?: string;
    /** @deprecated Hidden alias for `--device auto`. */
    smart?: boolean;
    balanced?: boolean;
    strategy?: string;
};
export type DeviceAutoApplyResult = {
    /** True when automatic placement ran successfully. */
    attempted: boolean;
    /** True when deprecated `--smart` was seen. */
    deprecationSmart: boolean;
    /** Present when affinity resolved without error. */
    banner?: {
        hostLabel: string;
        deviceHint: string;
        acctNote: string;
    };
};
/**
 * Apply `--device auto` (and deprecated `--smart`) onto run options.
 * Mutates `options` in place. Placement failures propagate without rewriting
 * `auto`, so callers fail loud instead of silently launching locally.
 */
export declare function applyDeviceAutoToOptions(options: DeviceAutoHostOptions, deps?: {
    resolve?: (accountPicker: boolean) => DeviceAutoPlan | Promise<DeviceAutoPlan>;
    agent?: string;
    accountPickerRequested?: boolean;
}): Promise<DeviceAutoApplyResult>;
