import type { MeshLedgerEntry } from './mesh-ledger.js';
import type { MeshWorkQueueEntry, DirectDispatchRecord } from './mesh-work-queue.js';
export type MeshActiveWorkSource = 'queue' | 'direct';
export type MeshActiveWorkStatus = 'pending' | 'assigned' | 'generating' | 'idle' | 'failed' | 'awaiting_approval';
export interface MeshActiveWorkRecord {
    taskId: string;
    source: MeshActiveWorkSource;
    status: MeshActiveWorkStatus;
    nodeId?: string;
    sessionId?: string;
    providerType?: string;
    taskTitle: string;
    taskSummary: string;
    message?: string;
    taskMode?: string;
    createdAt: string;
    updatedAt: string;
    dispatchedAt?: string;
    elapsedMs: number;
    terminal?: boolean;
    terminalKind?: string;
    terminalAt?: string;
    staleReason?: string;
    /**
     * When true, the session targeted by this direct dispatch still exists in the live mesh
     * but did not transition to generating — the dispatch was not acknowledged by the provider.
     * Distinct from historical/orphaned stale entries where the node/session is gone.
     */
    staleDispatchUnacknowledged?: boolean;
}
export interface MeshActiveWorkSummary {
    totalActiveCount: number;
    queueActiveCount: number;
    directActiveCount: number;
    awaitingApprovalCount: number;
    generatingCount: number;
    failedCount: number;
    idleCount: number;
    sourceCounts: Record<MeshActiveWorkSource, number>;
    statusCounts: Record<MeshActiveWorkStatus, number>;
    staleDirectCount: number;
    /**
     * Count of stale direct entries where the target session still exists in the live mesh
     * but never transitioned to generating — these are fresh dispatch failures, not historical orphans.
     * Requires immediate recovery: launch a fresh session and retry the task.
     */
    staleDirectUnacknowledgedCount?: number;
    /**
     * When staleDirectCount > 0, this note clarifies what kind of stale records exist.
     * Fresh unacknowledged dispatches carry an actionable recovery note; orphaned historical
     * entries carry the "historical evidence only" note. Both may coexist.
     */
    staleDirectNote?: string;
}
export interface MeshStaleDirectWorkSummary {
    count: number;
    sampleLimit: number;
    sample: Array<Pick<MeshActiveWorkRecord, 'taskId' | 'status' | 'nodeId' | 'sessionId' | 'taskTitle' | 'createdAt' | 'staleReason'>>;
    reasonCounts: Record<string, number>;
    detailHint: string;
    note?: string;
}
export interface BuildMeshActiveWorkOptions {
    meshId: string;
    queue?: MeshWorkQueueEntry[];
    ledgerEntries?: MeshLedgerEntry[];
    /**
     * Active direct dispatches from MeshRuntimeStore. When provided, these are used instead of
     * scanning ledger entries for direct dispatches — eliminates the O(n_ledger) scan.
     * Falls back to ledger scanning when not provided.
     */
    directDispatches?: DirectDispatchRecord[];
    nodes?: any[];
    now?: number;
    /** Include terminal direct rows (idle/failed) for handoff/recent-work surfaces. Defaults false. */
    includeTerminalDirect?: boolean;
}
export declare function sessionStatusFromNodes(nodes: any[] | undefined, nodeId?: string, sessionId?: string): {
    status?: MeshActiveWorkStatus;
    staleReason?: string;
};
/**
 * One session awaiting an approval decision — the derived row `mesh_list_pending_approvals`
 * returns and the UI approvals inbox renders. A thin projection of the `awaiting_approval`
 * MeshActiveWorkRecord: it carries exactly what a coordinator needs to route a follow-up
 * mesh_approve(node_id, session_id) and what the inbox needs to label the item. No new
 * store or data source — derived from the same buildMeshActiveWork records.
 */
export interface MeshPendingApproval {
    nodeId?: string;
    sessionId?: string;
    providerType?: string;
    taskId: string;
    taskTitle: string;
    /** Always 'awaiting_approval' — kept explicit so consumers can render/assert on it. */
    status: 'awaiting_approval';
    /** ISO timestamp the underlying task was created/dispatched — the "waiting since" anchor. */
    waitingSince: string;
    /** Milliseconds the record has been outstanding (elapsed from dispatch/create). */
    waitingMs: number;
}
/**
 * Derive the mesh-wide pending-approval inbox from already-built active-work records.
 * Pure filter+projection over `status === 'awaiting_approval'` — no new store, no probe;
 * the caller supplies the records (typically buildMeshActiveWork(...).activeWork so the
 * enumeration reuses the exact classification `mesh_status` already computes). Records
 * without a node/session are skipped: an approval that cannot be routed to a live
 * node+session via mesh_approve is not actionable inbox content.
 */
export declare function collectPendingApprovals(activeWork: MeshActiveWorkRecord[]): MeshPendingApproval[];
export declare function buildMeshActiveWorkSummary(activeWork: MeshActiveWorkRecord[]): MeshActiveWorkSummary;
export declare function buildMeshActiveWork(opts: BuildMeshActiveWorkOptions): {
    activeWork: MeshActiveWorkRecord[];
    staleDirectWork: MeshActiveWorkRecord[];
    staleDirectWorkNote?: string;
    terminalDirectWork: MeshActiveWorkRecord[];
    summary: MeshActiveWorkSummary;
};
/**
 * staleReason strings (produced by sessionStatusFromNodes above) that indicate the original
 * node/session is GONE from the live mesh — i.e. the staleDirect record is an orphaned ledger
 * artifact, not active or recoverable work. These are the only reasons safe to prune from the
 * active staleDirect surface. The "no provider acknowledgement" reason is deliberately excluded:
 * those entries have a still-live node/session (staleDispatchUnacknowledged) and represent
 * recoverable dispatch failures, never orphans.
 */
export declare const PRUNABLE_ORPHAN_STALE_REASONS: ReadonlySet<string>;
export type StaleDirectPruneClassification = 'prunable_orphan' | 'prunable_terminal' | 'preserve_unacknowledged' | 'preserve_active';
/**
 * Classify a direct-work record for the staleDirect prune path. Pure function — the prune tool
 * uses this so the safety rules (never touch active work or recoverable unacknowledged dispatches)
 * live next to the staleReason producers and are independently testable.
 */
export declare function classifyStaleDirectForPrune(record: Pick<MeshActiveWorkRecord, 'staleReason' | 'staleDispatchUnacknowledged' | 'terminal'>, opts?: {
    includeTerminal?: boolean;
}): StaleDirectPruneClassification;
/**
 * Outcome of one staleDirect prune pass. Pure data — callers (the MCP tool, the
 * daemon reconcile loop) format/log this however they need. The MCP tool wraps it in
 * its JSON response; the reconcile loop logs prunedCount when > 0.
 */
export interface StaleDirectPruneResult {
    mode: 'execute' | 'dry_run';
    includeTerminal: boolean;
    /** Total staleDirect (+terminal when included) candidates surfaced this pass. */
    candidateCount: number;
    /** Records classified prunable AND (when minAgeMs > 0) old enough to auto-prune. */
    prunable: MeshActiveWorkRecord[];
    prunedCount: number;
    /** Prunable by classification but younger than the age gate — only populated when minAgeMs > 0. */
    skippedTooYoung: MeshActiveWorkRecord[];
    preservedUnacknowledged: MeshActiveWorkRecord[];
    /** Prunable orphans/terminals with no store-backed row to delete (ledger-only audit). */
    preservedLedgerOnly: MeshActiveWorkRecord[];
    preservedNotOrphan: MeshActiveWorkRecord[];
}
export interface PruneStaleDirectDispatchesOptions {
    meshId: string;
    /** Active direct dispatches from MeshRuntimeStore (getActiveDirectDispatches). */
    directDispatches: DirectDispatchRecord[];
    /** Ledger tail used to attribute remote/terminal dispatches (readLedgerEntries). */
    ledgerEntries?: MeshLedgerEntry[];
    queue?: MeshWorkQueueEntry[];
    /** Live mesh nodes (decorated with live session details) — drives orphan detection. */
    nodes?: any[];
    /** When true, actually delete + append the audit ledger entry. Default false (dry run). */
    execute?: boolean;
    /** Include terminal (idle/failed) direct rows as prune candidates. Default false. */
    includeTerminal?: boolean;
    /**
     * Minimum age (ms, measured from createdAt/dispatchedAt) before a prunable orphan is
     * eligible. 0 (default) prunes immediately regardless of age — the manual prune behavior.
     * The daemon auto-prune passes a conservative threshold so a node/session that is only
     * transiently invisible is never pruned on the spot.
     */
    minAgeMs?: number;
    /** Audit source string written into the direct_dispatch_pruned ledger payload. */
    source?: string;
    now?: number;
}
/**
 * Shared staleDirect prune core. Single source of truth for the prune decision + the
 * mutation (store-row delete + audit-ledger append) used by BOTH the manual MCP tool
 * (mesh_prune_stale_direct, minAgeMs=0) and the daemon reconcile loop's auto-prune
 * PHASE (minAgeMs > 0). Pure decision logic via buildMeshActiveWork + classifyStaleDirectForPrune;
 * the only side effects (on execute) are deleteDirectDispatchesByTaskId and a single
 * direct_dispatch_pruned ledger entry — never touching the append-only audit history of the
 * pruned dispatches themselves.
 *
 * Safety rules (identical for manual + auto):
 *  - Only records classified as staleDirectWork against the CURRENT live mesh are eligible.
 *  - Of those, only orphans (node/session gone) — and terminals when includeTerminal — are prunable.
 *    Fresh unacknowledged dispatch failures (node/session still live) are always preserved.
 *  - Only store-backed rows (taskId present in MeshRuntimeStore) are deleted; ledger-only remote
 *    entries are preserved.
 *  - When minAgeMs > 0, a prunable orphan younger than the gate is held back (skippedTooYoung).
 *    This applies ONLY to the auto path; the manual path passes minAgeMs=0 (immediate).
 *
 * Idempotent: a deleted row no longer appears in getActiveDirectDispatches, so a second pass
 * over the same orphan finds nothing to prune.
 */
export declare function pruneStaleDirectDispatches(opts: PruneStaleDirectDispatchesOptions): StaleDirectPruneResult;
export declare function buildCompactStaleDirectWorkSummary(staleDirectWork: MeshActiveWorkRecord[], opts?: {
    sampleLimit?: number;
    detailHint?: string;
    note?: string;
}): MeshStaleDirectWorkSummary;
