/**
 * Idle-active-mission reminder.
 *
 * When a coordinator session becomes fully idle — no queue/direct work in flight,
 * no pending coordinator events to drain — yet the mesh still carries `active`
 * missions, inject a one-shot "[System] Coordinator idle with N active mission(s)"
 * reminder into that coordinator session. This nudges the coordinator to decide a
 * lingering mission's real outcome (close it, or continue it) rather than leaving it
 * drifting in `active` after its work is actually done.
 *
 * Precedent: mesh-missions.ts `maybeEmitMissionCloseCandidate` — a terminal-edge,
 * once-per-edge coordinator nudge with an idempotency marker. This mirrors that
 * shape, but the "edge" is the coordinator's idle transition (fired by the fast-path
 * in mesh-event-forwarding and the slow-path idle tick in mesh-reconcile-loop) and
 * the idempotency marker is a time+mission-set debounce held in MeshRuntimeStore
 * (getIdleReminderState / setIdleReminderState). Fully best-effort: a throw here must
 * never break the drain/injection path that called it.
 *
 * Design invariants:
 *  - Only fires when the mesh has ≥1 `active` mission AND is fully idle. Fully idle =
 *    buildMeshActiveWork over queue + direct dispatches reports totalActiveCount === 0
 *    && generatingCount === 0 AND no async refine job is accepted/running. We intentionally
 *    do NOT probe remote node sessions here (expensive per-tick RPC): any non-terminal
 *    queue/direct work already makes totalActiveCount > 0, so the idle check is
 *    conservative — it suppresses the reminder whenever any work is outstanding, which is
 *    the safe direction. Async refine jobs (`mesh_refine_node`) are a separate class that
 *    buildMeshActiveWork does not count, so they are checked explicitly from the ledger.
 *  - NEVER transitions a mission's status. It only surfaces a hint; the coordinator
 *    decides via mesh_mission_upsert.
 *  - Debounced per mission-set. Re-fires only when the debounce window has elapsed OR
 *    the set of active mission ids changed (a mission was closed/added), so a mesh that
 *    stays idle with the same active missions is nudged at most once per window.
 *  - Opt-out via policy.idleActiveMissionReminder === false.
 */
import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
import type { RepoMeshPolicy } from '../repo-mesh-types.js';
import { type MeshMissionRecord } from './mesh-missions.js';
/** Coordinator instance the reminder is injected into (the idle CLI session). */
type CoordinatorInstance = ReturnType<DaemonComponents['instanceManager']['getInstance']>;
/**
 * Debounce window: while the mesh stays idle with the SAME active-mission set, re-fire
 * the reminder at most once per this interval. A changed mission set bypasses the window.
 */
export declare const IDLE_REMINDER_DEBOUNCE_MS = 300000;
/** Stable hash of the active-mission id set (sorted, joined) for debounce comparison. */
export declare function missionSetHash(missions: MeshMissionRecord[]): string;
/**
 * Decide whether a reminder should fire this call, given the debounce marker. Pure so it
 * is independently testable. Re-fires when there is no prior marker, the debounce window
 * has elapsed, or the active-mission set changed since the last reminder.
 */
export declare function shouldFireIdleReminder(last: {
    emittedAt: number;
    missionSetHash: string;
} | null, hash: string, now: number, debounceMs?: number): boolean;
/**
 * Build the coordinator-facing reminder text. Deliberately terse — one line per mission
 * (`title (id)`), NEVER the full goal (goals can be thousands of chars). When there are
 * more than MISSION_LIST_CAP missions, name the first N and fold the remainder.
 */
export declare function buildIdleReminderMessage(missions: MeshMissionRecord[]): string;
/**
 * Fire-and-forget idle-active-mission reminder. Call this at a coordinator idle edge
 * once the pending-event queue is empty (nothing else to inject). `coordinator` is the
 * idle CLI session to inject into; `policy` is the mesh's policy (for the opt-out flag).
 *
 * Returns true iff a reminder was injected on this call.
 */
export declare function maybeInjectIdleActiveMissionReminder(meshId: string, coordinator: CoordinatorInstance, policy: RepoMeshPolicy | undefined, now?: number): boolean;
export {};
