/**
 * Owner phone notification on routine FAILURE (RUSH-2288).
 *
 * The desktop lifecycle notifications (routine-notify.ts) never leave the
 * machine, so a failed scheduled routine on a headless fleet box was invisible
 * until someone happened to look. The per-routine prompt pattern (a prompt that
 * ends by shelling `agents notify`) does not close the gap either: when the
 * routine's OWN agent fails to spawn (`auth_failed`) that prompt never runs, so
 * the one failure most worth surfacing is the one that goes unheard.
 *
 * So the DAEMON delivers on failure, from the SAME owner channel stack `agents
 * notify` uses (humans.yaml owner channels, or the legacy `notify.owner`),
 * calling the channel providers IN-PROCESS — no shelling out to `ssh mac-mini
 * agents notify`. When the primary owner channel cannot deliver from this box it
 * walks the remaining configured owner channels as fallbacks (OpenClaw, a second
 * channel, …). Telegram is never used.
 *
 * Only failures notify. A green routine of any kind stays silent — this is an
 * ADDITIONAL failures-only lane, and the desktop thresholds (which still ping a
 * green agent/workflow finish on the local screen) are unchanged. Delivery is
 * deduped per job+runId so a run is announced to the owner at most once.
 *
 * The message BUILDERS (`routineFinishOwnerText` / `routineStartFailedOwnerText`)
 * are pure and unit-tested; `notifyOwnerRoutineFinish` /
 * `notifyOwnerRoutineStartFailed` are the daemon glue that reads config and
 * delivers.
 */
import type { Meta } from './types.js';
import type { JobConfig, RunMeta } from './scheduling/routines.js';
/**
 * Owner-phone text for a routine FINISH, or null when the run did NOT fail. Only
 * `failed` and `timeout` are failures worth an owner ping — a `completed` run
 * (any kind) is silent, and `running`/`missed` never reach this path from the
 * daemon's finish hook. The text is a short, phone-sized pointer: what failed,
 * why, and on which box (so the owner knows where to look), well under the
 * `user-message-guard` length ceiling.
 */
export declare function routineFinishOwnerText(meta: Pick<RunMeta, 'jobName' | 'status' | 'exitCode' | 'errorMessage' | 'agent' | 'workflow' | 'command'>, host: string): string | null;
/**
 * Owner-phone text for a routine that failed to even START (the daemon's
 * pre-spawn catch — `executeJobDetached` threw before a child existed, e.g.
 * `auth_failed`). Never null: a broken start is always a failure worth the ping,
 * for every routine kind, and it is exactly the case the per-routine `agents
 * notify` prompt can never cover because that prompt never ran.
 */
export declare function routineStartFailedOwnerText(config: Pick<JobConfig, 'name' | 'agent' | 'workflow' | 'command'>, error: string, host: string): string;
/** One resolved owner destination to attempt, in plan order. */
export interface OwnerDest {
    channel: string;
    to: string;
}
/**
 * Ordered owner delivery plan for a failure ping: the primary owner destination
 * (the same one `agents notify` resolves) first, then every other configured
 * owner channel as a fallback. Deduped by (channel, to). Telegram channels and
 * intrusive channels (a voice call is too much for a routine failure) are
 * excluded entirely — so an owner whose ONLY channel is Telegram gets an empty
 * plan and no ping, which is the intended "silence beats Telegram" outcome.
 *
 * The same filters apply to the primary and the fallback list — a policy that
 * points normal severity at a voice channel must not auto-call the owner on
 * every routine failure.
 */
export declare function ownerFailureDeliveryPlan(meta: Meta): OwnerDest[];
/** Outcome of one delivery attempt, for logging/telemetry. */
export interface OwnerDeliveryAttempt {
    channel: string;
    ok: boolean;
    error?: string;
}
export interface OwnerDeliveryResult {
    /** True once any channel in the plan accepted the message. */
    delivered: boolean;
    /** The channel that delivered, when `delivered`. */
    channel?: string;
    /** Every attempt made, in order — empty when no owner channel is configured. */
    attempts: OwnerDeliveryAttempt[];
}
/**
 * Deliver `text` to the owner over the failure plan, in-process, trying each
 * channel until one accepts. Uses the non-dying `lookupTransport` (never
 * `resolveTransport`, which `die()`s the process) so a daemon survives a bad
 * channel name. Best-effort by contract: the daemon wraps this in try/catch, but
 * it also never throws for a delivery failure — it returns the attempt log.
 */
export declare function deliverOwnerFailure(text: string, meta: Meta): Promise<OwnerDeliveryResult>;
/** Test-only: reset the dedup set so cases don't leak state into each other. */
export declare function __resetOwnerFailureDedup(): void;
/**
 * Daemon glue: on a routine FINISH, ping the owner IFF the run failed. Green
 * runs return early (no ping). Deduped per job+runId — claimed for the
 * in-flight window so two finish hooks don't double-text, released when no
 * channel accepted so a later sweep can retry. Best-effort.
 */
export declare function notifyOwnerRoutineFinish(meta: RunMeta): Promise<OwnerDeliveryResult>;
/**
 * Daemon glue: on a pre-spawn failure (no run record, so no finish hook and no
 * runId), ping the owner. Not deduped — a pre-spawn failure is one scheduled
 * fire on the cron cadence (never a per-second storm), and each such fire is a
 * distinct failure the owner should hear about. Best-effort.
 */
export declare function notifyOwnerRoutineStartFailed(config: JobConfig, error: string): Promise<OwnerDeliveryResult>;
