import type { RepoMeshDaemonRole } from '../repo-mesh-types.js';
import { MeshRuntimeStore } from './mesh-runtime-store.js';
export type MeshTaskStatus = 'pending' | 'assigned' | 'completed' | 'failed' | 'cancelled';
export type MeshActiveTaskStatus = Extract<MeshTaskStatus, 'pending' | 'assigned'>;
export type MeshHistoricalTaskStatus = Extract<MeshTaskStatus, 'completed' | 'failed' | 'cancelled'>;
export type MeshTaskMode = 'code_change' | 'validation' | 'live_debug_readonly' | 'launch_app' | 'convergence';
/** G6: task-level scheduling priority. Ranks which task a node pulls first (created_at tie-break). */
export type MeshTaskPriority = 'low' | 'normal' | 'high';
export declare const ACTIVE_MESH_QUEUE_STATUSES: MeshActiveTaskStatus[];
export declare const HISTORICAL_MESH_QUEUE_STATUSES: MeshHistoricalTaskStatus[];
export declare const MESH_TASK_MODES: MeshTaskMode[];
export declare const MESH_TASK_PRIORITIES: MeshTaskPriority[];
/**
 * G6: numeric rank of a task priority (higher = pulled first). Absent/unknown → 'normal' (1).
 * Shared by the claim-candidate ordering and any surface that must sort by task priority.
 */
export declare function meshTaskPriorityRank(priority: unknown): number;
/** G6: coerce an arbitrary input to a valid MeshTaskPriority, or undefined when not one of the three. */
export declare function normalizeMeshTaskPriority(value: unknown): MeshTaskPriority | undefined;
/**
 * G7: resolve a not_before input to a stored ISO string (or undefined when absent/invalid).
 * Accepts an ISO/date string, an absolute epoch-ms number, or a small relative-ms offset from
 * `nowMs`. Disambiguation for numbers: a value below {@link NOT_BEFORE_RELATIVE_THRESHOLD_MS}
 * (~1 year in ms) is treated as a relative offset added to now; a larger value is an absolute
 * epoch-ms timestamp. A past/negative result is normalized to now (immediately claimable).
 */
export declare const NOT_BEFORE_RELATIVE_THRESHOLD_MS: number;
export declare function resolveNotBefore(value: unknown, nowMs?: number): string | undefined;
/** G7: is a task claimable now, or is it still held back by its notBefore gate? */
export declare function meshTaskNotBeforeReady(task: {
    notBefore?: string;
} | null | undefined, nowMs?: number): boolean;
/**
 * QUEUE-NODE-SERIALIZATION: single source of truth for "is this task read-only?".
 *
 * Read-only classification used to be inlined as `task.taskMode === 'live_debug_readonly'`
 * at every enforcement site (node-conflict claim gate, auto-launch isolation, the
 * write/readonly cap counters, the write guardrail). That spread-out comparison is the
 * exact recurring-defect class — one site drifting from the others silently makes the same
 * task read-only at some gates and write at others, i.e. partial serialization. All sites
 * MUST call this predicate so the classification is decided in exactly one place.
 *
 * Two orthogonal inputs feed the same boolean axis (kept backward-compatible):
 *   • `readonly === true` — the explicit boolean axis (new API surface).
 *   • `taskMode === 'live_debug_readonly'` — the original enum value, preserved as an
 *     OR-fallback so existing live_debug_readonly tasks keep behaving identically.
 *
 * Accepts any task-like shape (full {@link MeshWorkQueueEntry} or a bare
 * `{ readonly?, taskMode? }`) so the daemon-core and mcp-server boundaries can share it.
 */
export declare function isTaskReadonly(task: {
    readonly?: boolean;
    taskMode?: MeshTaskMode | string;
} | null | undefined): boolean;
export interface MeshTaskModeValidationResult {
    valid: boolean;
    taskMode?: MeshTaskMode;
    violations: string[];
    allowedOperations?: string[];
}
export declare function normalizeMeshTaskMode(value: unknown): MeshTaskMode | undefined;
export declare function validateMeshTaskModeRequest(mode: unknown, message: string, readonly?: boolean): MeshTaskModeValidationResult;
export interface MeshWorkQueueEntry {
    id: string;
    meshId: string;
    message: string;
    status: MeshTaskStatus;
    taskMode?: MeshTaskMode;
    /**
     * QUEUE-NODE-SERIALIZATION: explicit read-only axis, orthogonal to taskMode. When
     * true the task is treated as read-only by every scheduling gate (no node-busy
     * isolation, counted under the read-only cap, write commands rejected) regardless of
     * its taskMode. Decided exclusively through {@link isTaskReadonly}; `taskMode ===
     * 'live_debug_readonly'` remains an OR-fallback so legacy rows behave unchanged.
     */
    readonly?: boolean;
    /** If specified, only this node can claim the task (used by legacy mesh_send_task) */
    targetNodeId?: string;
    /** If specified, only this runtime session can claim the task */
    targetSessionId?: string;
    /** If specified, a node must expose all tags before it can claim the task. */
    requiredTags?: string[];
    /**
     * G6 (task-level scheduling priority): 'low' | 'normal' | 'high'. Orders the
     * claim candidate list so a high-priority task is pulled ahead of an older
     * normal/low task within the same claim tier (created_at is the tie-break).
     * Absent → treated as 'normal'. This is the TASK-level priority, distinct from
     * the NODE-level schedulingPriority (resolveNodeSchedulingPriority), which ranks
     * which node a task goes to, not which task a node pulls first.
     */
    priority?: MeshTaskPriority;
    /**
     * G7 (delayed execution): ISO timestamp before which the task is NOT claimable.
     * The claim gate holds the task pending while now < notBefore; once the wall
     * clock passes it the task becomes a normal claim candidate. A pure time gate —
     * cron/webhook triggers are out of scope. Absent → immediately claimable.
     */
    notBefore?: string;
    /**
     * M1: ids of tasks that must reach 'completed' before this task is claimable.
     * Forward references (ids not yet enqueued) are allowed for batch flows and
     * simply keep the task waiting until the referenced task exists and completes.
     */
    dependsOn?: string[];
    /** M1/M3: mission this task belongs to (joins mesh_missions). */
    missionId?: string;
    /**
     * MAGI: consensus group id shared by every replica of one mesh_magi_review
     * fan-out. Marks the task as part of an INTENTIONAL same-prompt quorum so the
     * completion-event dedup (mesh-events-pending) never collapses grouped
     * replicas. Absent on ordinary tasks. Rides in the payload JSON (no column).
     */
    consensusGroupId?: string;
    /**
     * MAGI-KIND-PANEL (model axis): model override for the session that executes this
     * task. When the task auto-launches a session, this is passed to launch_cli as
     * `initialModel` (ACP → setConfigOption; CLI → modelLaunchArgs template). Absent on
     * ordinary tasks. Rides in the payload JSON (no column). Best-effort — a provider
     * that cannot honor the model still runs the task (never a fatal launch error).
     */
    model?: string;
    /**
     * BRAIN-ROUTING (thinking axis): standard reasoning level ('low'|'medium'|'high')
     * for the session that executes this task. When the task auto-launches, this is
     * passed to launch_cli as `initialThinkingLevel` (CLI → thinkingLaunchArgs; ACP →
     * setConfigOption('thought_level')). Rides in payload JSON. Best-effort like model.
     */
    thinkingLevel?: string;
    /**
     * SLOT-ROUTING (ORCHESTRATION_NODE_SLOTS.md): the coordinator's difficulty
     * classification for this task ('easy'|'medium'|'difficult'|'freeform'),
     * PERSISTED on the entry so the scheduler can match it against node capability
     * slots at assignment time. Previously an enqueue-only option consumed to
     * resolve model/thinkingLevel and then discarded; keeping it lets task→node
     * fitness matching run. Absent on tasks enqueued without a difficulty.
     */
    difficulty?: string;
    /**
     * M1: why this task is held back (e.g. "dependency_failed:<taskId>").
     * Only set by the system on dependency failure under the 'block' policy;
     * waiting-on-dependency state is computed at view time, not stored.
     */
    blockedReason?: string;
    /** The node that actually claimed and is executing the task */
    assignedNodeId?: string;
    /** The session currently executing the task */
    assignedSessionId?: string;
    /**
     * Provider type of the session that claimed the task. Recorded so the queue
     * can enforce per-(node, provider) maxParallel caps (summed slots[].maxParallel)
     * by counting active assignments grouped by node + provider.
     */
    assignedProviderType?: string;
    /** Human/operator reason for terminal cancellation. */
    cancelReason?: string;
    cancelledAt?: string;
    /** Human/operator reason for manually requeueing a task. */
    requeueReason?: string;
    requeuedAt?: string;
    requeueCount?: number;
    /** Max automatic requeue attempts. When requeueCount reaches this, task is auto-failed. */
    maxRetries?: number;
    /**
     * Bug B: number of times the reconcile assigned-stranded watchdog has reclaimed this
     * row from 'assigned' back to 'pending' because its dispatch was never confirmed
     * delivered. Separate from requeueCount (operator/execution retries) and bounded by
     * MAX_STRANDED_RECLAIMS so a permanently-undeliverable target auto-fails rather than
     * cycling reclaim→re-dispatch→strand forever.
     */
    strandedReclaimCount?: number;
    /** Last automatic queue session spin-up attempt, for mesh_view_queue/debug visibility. */
    autoLaunch?: {
        status: 'skipped' | 'started' | 'failed' | 'completed';
        reason?: string;
        nodeId?: string;
        providerType?: string;
        sessionId?: string;
        updatedAt: string;
    };
    /** ISO timestamp when the task was dispatched (assigned) to a node/session. Used for precise matching on completion. */
    dispatchTimestamp?: string;
    /**
     * REDRIVE-DUP: monotonic per-task dispatch nonce. Bumped on every (re)dispatch of
     * this task (assignQueueTask) AND on every reclaim (reclaimStrandedAssignedTask), and
     * carried to the worker in meshContext.dispatchNonce. The worker echoes it back on
     * agent:generating_started (metadataEvent.dispatchNonce). When a delivered-not-consumed
     * task is reclaimed and re-dispatched to a different node, the ORIGINAL inject to the
     * first node still carries the now-stale nonce; the coordinator rejects that node's
     * generating_started ack (and stops it) so the SAME taskId is never executed twice.
     * Absent on legacy rows → the coordinator skips the stale-nonce guard (backward safe).
     */
    dispatchNonce?: number;
    /**
     * (3) The ORIGINATING coordinator session that enqueued this task. Stamped onto the
     * worker at dispatch (meshCoordinatorSessionId) so the task's completion routes back to
     * the exact coordinator session — even when several coordinator sessions share one
     * daemon. Rides in the queue payload JSON (no column migration); absent on legacy rows
     * → daemon-level routing fallback (backward + version-skew safe).
     */
    sourceCoordinatorSessionId?: string;
    createdAt: string;
    updatedAt: string;
}
export interface MeshQueueMutationOptions {
    ownerRole?: RepoMeshDaemonRole;
}
export declare function normalizeMeshCapabilityTags(value: unknown): string[];
export declare function buildMeshNodeCapabilityTags(node: {
    capabilities?: unknown;
    policy?: unknown;
    isLocalWorktree?: unknown;
    worktreeBranch?: unknown;
    userOverrides?: unknown;
    reportedPlatform?: unknown;
    reportedArch?: unknown;
} | undefined, providerType?: string): string[];
export declare function nodeSatisfiesRequiredTags(requiredTags: unknown, capabilityTags: unknown): boolean;
/**
 * Convergence-aware required-tags resolution (load-balancing scheduler, opt-in).
 *
 * When the mesh enables policy.autoConvergeCodeChange, a `converge=refine` required
 * tag is merged into a code_change task's required tags at enqueue time, so the
 * scheduler hard-filters the task onto refine-capable worktree nodes only (on any
 * machine — refine_mesh_node forwards to the owning daemon). Because the tag is
 * persisted on the queue entry, BOTH the eligibility scan (maybeAutoLaunchOneQueueSession)
 * and the claim transaction (claimNextQueueTask → nodeSatisfiesRequiredTags) enforce
 * it consistently.
 *
 * Strict backward compatibility — the injection is skipped (returns the explicit tags
 * unchanged) when ANY of:
 *   - the mesh does not opt in (autoConvergeCodeChange !== true), or
 *   - the task is not code_change (validation / live_debug_readonly / launch_app /
 *     convergence carry no merge cost and may run anywhere), or
 *   - the task is explicitly targeted (targetNodeId): the operator chose the node, so
 *     we do not second-guess it by filtering on convergence capability.
 * Idempotent: normalizeMeshCapabilityTags dedupes, so re-injection is a no-op.
 */
export declare function resolveConvergeRequiredTags(meshId: string, taskMode: MeshTaskMode | undefined, explicitRequiredTags: string[], opts?: {
    targetNodeId?: string;
}): string[];
/**
 * M1: detect dependency cycles before enqueue. Walks the dependency graph of
 * existing queue entries plus the new task's edges. Fail-closed: a cycle
 * rejects the enqueue entirely. Synchronous and bounded by queue size.
 */
export declare function assertNoDependencyCycle(meshId: string, newTaskId: string, dependsOn: string[]): void;
/**
 * Add a new task to the mesh queue.
 */
export declare function enqueueTask(meshId: string, message: string, opts?: {
    targetNodeId?: string;
    targetSessionId?: string;
    taskMode?: MeshTaskMode | string;
    /** QUEUE-NODE-SERIALIZATION: explicit read-only axis (orthogonal to taskMode). */
    readonly?: boolean;
    requiredTags?: string[];
    /** M1: tasks that must complete before this one is claimable. */
    dependsOn?: string[];
    /** G6: task-level scheduling priority ('low' | 'normal' | 'high'). Absent → 'normal'. */
    priority?: MeshTaskPriority | string;
    /** G7: hold the task pending until this time. ISO string, absolute epoch-ms, or relative-ms offset from now. */
    notBefore?: string | number;
    /** P3: max automatic requeue attempts before the task auto-fails. Absent → policy default (1). */
    maxRetries?: number;
    /** M1/M3: mission this task belongs to. */
    missionId?: string;
    /** MAGI: consensus group id shared by every replica of a mesh_magi_review fan-out. */
    consensusGroupId?: string;
    /** MAGI-KIND-PANEL: model override forwarded to the executing session's launch (initialModel). */
    model?: string;
    /** BRAIN-ROUTING: standard thinking level forwarded to launch (initialThinkingLevel). */
    thinkingLevel?: string;
    /**
     * BRAIN-ROUTING: task execution difficulty ('easy'|'medium'|'difficult'|
     * 'freeform'). When set, the mesh's difficulty→brain preset fills in model /
     * thinkingLevel that were not passed explicitly (an explicit model/thinkingLevel
     * wins). Purely a convenience resolver — the stored task still carries the
     * resolved model/thinkingLevel, so downstream launch is unchanged.
     */
    difficulty?: string;
    /** Explicit task id for batch/template flows (M5). Random UUID when omitted. */
    id?: string;
    /** (3) Originating coordinator session id (for session-anchored completion routing). */
    sourceCoordinatorSessionId?: string;
} & MeshQueueMutationOptions): MeshWorkQueueEntry;
/**
 * Record a direct-dispatch task (mesh_send_task) as an already-assigned queue
 * entry so it is attributable to a mission.
 *
 * Direct dispatch normally bypasses the queue entirely — the task lives only in
 * the ledger + mesh_direct_dispatches table, neither of which carries a
 * missionId, so {@link summarizeMissionTasks}/{@link computeMeshTaskStats}
 * (which both scan the queue for `task.missionId`) count it as 0. When a
 * mission is attached, we materialise the same queue entry shape an enqueued
 * task would have, but pre-assigned to the dispatched node/session and stamped
 * with the dispatch timestamp. The terminal event path (updateSessionTaskStatus
 * → findAssignedBySession) then flips it to completed/failed exactly like a
 * pulled task, so mission total + completed aggregates work with no extra wiring.
 *
 * Intentionally separate from {@link enqueueTask}: enqueue creates `pending`
 * work for the queue to assign, whereas this records work already dispatched
 * out-of-band. They share the missionId stamping rule and mode validation.
 */
export declare function recordDirectDispatchTask(meshId: string, message: string, opts: {
    id: string;
    missionId: string;
    assignedNodeId?: string;
    assignedSessionId?: string;
    taskMode?: MeshTaskMode | string;
    /** QUEUE-NODE-SERIALIZATION: explicit read-only axis (orthogonal to taskMode). */
    readonly?: boolean;
    dispatchedAt?: string;
}): MeshWorkQueueEntry | null;
/**
 * Get all tasks in the queue, optionally filtered by status.
 */
export declare function getQueue(meshId: string, opts?: {
    status?: MeshTaskStatus[];
}): MeshWorkQueueEntry[];
export declare function getMeshQueueRevision(meshId: string): string;
/**
 * Find the next pending task that this node is allowed to claim, and mark it as assigned.
 *
 * `opts.providerType` is stamped onto the claimed entry (assignedProviderType) so
 * per-(node, provider) caps can be counted. `opts.providerMaxParallel`, when set,
 * is the enforced per-(node, provider) cap (summed slots[].maxParallel):
 * a task is not assigned to this (node, provider) once it already has that many
 * active assignments. This composes with the global/taskMode caps (stricter wins).
 */
export declare function claimNextTask(meshId: string, nodeId: string, sessionId: string, capabilityTags?: string[], opts?: {
    providerType?: string;
    providerMaxParallel?: number;
    nodeIsWorktree?: boolean;
}): MeshWorkQueueEntry | null;
export type DependencyFailurePolicy = 'block' | 'cancel';
/**
 * Update the status of a specific task.
 * Used when a session completes, fails, or stalls.
 */
export declare function updateTaskStatus(meshId: string, taskId: string, status: MeshTaskStatus, opts?: MeshQueueMutationOptions): MeshWorkQueueEntry | null;
export declare function recordTaskAutoLaunch(meshId: string, taskId: string, autoLaunch: Omit<NonNullable<MeshWorkQueueEntry['autoLaunch']>, 'updatedAt'>): MeshWorkQueueEntry | null;
/**
 * Mark a queue task as manually cancelled without deleting audit history.
 */
export declare function cancelTask(meshId: string, taskId: string, opts?: {
    reason?: string;
} & MeshQueueMutationOptions): MeshWorkQueueEntry | null;
/**
 * Return a queue task to pending for retry. By default, dead session targeting
 * and assigned ownership are cleared so stale assignments do not strand again.
 */
export type RequeueResult = {
    status: 'requeued';
    entry: MeshWorkQueueEntry;
} | {
    status: 'failed_max_retries';
    entry: MeshWorkQueueEntry;
    maxRetries: number;
    requeueCount: number;
} | {
    status: 'not_found';
};
export declare function requeueTask(meshId: string, taskId: string, opts?: {
    reason?: string;
    targetNodeId?: string;
    targetSessionId?: string;
    clearTargetNode?: boolean;
    clearTargetSession?: boolean;
    /**
     * Override the retry cap for this call. Use only for explicit operator actions.
     * If true, the task is requeued even when requeueCount >= maxRetries.
     */
    force?: boolean;
    /** Per-task retry cap override. Falls back to mesh policy maxTaskRetries (default 1). */
    maxRetries?: number;
} & MeshQueueMutationOptions): MeshWorkQueueEntry | null;
/**
 * TASK-PROMPT-REDRIVE-AFTER-COMPLETE: the reclaim reasons the assigned-stranded watchdog
 * uses when it RE-DRIVES a delivered-but-not-terminal task (returns it to 'pending' so the
 * SAME prompt is re-dispatched). These are distinct from `assigned_stranded_dispatch_unconfirmed`
 * (a dispatch that was NEVER handed off — nothing ran, so a late completion is impossible).
 *
 * A re-drive assumes the worker never finished. But for an autoLaunch/worktree worker the
 * turn-lifecycle events (agent:generating_started/completed) do NOT reliably reach the
 * coordinator ledger, so the deadline can elapse and re-drive fire while the worker's genuine
 * completion is merely LATE (observed live: it lands 0.9s–98s AFTER the reclaim). The late
 * completion must then SUPERSEDE the re-drive rather than be dropped — the completion handler's
 * flip-miss safety net checks a row reclaimed for one of these reasons within
 * {@link REDRIVE_SUPERSEDE_WINDOW_MS} of its `requeuedAt`.
 */
export declare const REDRIVE_RECLAIM_REASONS: ReadonlySet<string>;
/**
 * How long after a re-drive reclaim's `requeuedAt` a late completion still supersedes the
 * re-dispatch. Comfortably covers the observed 0.9s–98s completion-vs-reclaim race with margin,
 * while staying far short of the time it would take a genuinely fresh re-dispatched turn to
 * produce its OWN completion — so a real second turn is never mistaken for the superseded one.
 */
export declare const REDRIVE_SUPERSEDE_WINDOW_MS: number;
/**
 * Bug B: reclaim a task stuck in 'assigned' because its dispatch was never confirmed.
 *
 * claimNextTask atomically marks a row 'assigned' BEFORE the fire-and-forget dispatch
 * runs. If that dispatch neither rejects (→ no .catch requeue) nor is confirmed
 * delivered — a relay that hangs without acking, or a confirm timer lost across a
 * daemon restart — the row stays 'assigned' forever, contributing 0 pending so PHASE 3
 * reconcile never re-examines it. This returns such a row to 'pending' and clears its
 * dead assignment ownership (node / session / provider / dispatchTimestamp) — the same
 * ownership-clear requeueTask applies — so PHASE 3 can re-dispatch it onto a fresh idle
 * session.
 *
 * Guarded to 'assigned' rows only (a completion/cancel that already moved the row off
 * 'assigned' must never be resurrected) and bounded by MAX_STRANDED_RECLAIMS (beyond
 * which the task is failed so dependents unblock).
 */
export declare function reclaimStrandedAssignedTask(meshId: string, taskId: string, opts?: {
    reason?: string;
    ageMs?: number;
} & MeshQueueMutationOptions): MeshWorkQueueEntry | null;
/**
 * Update the status of the task currently assigned to a specific session.
 */
export declare function updateSessionTaskStatus(meshId: string, sessionId: string, status: MeshTaskStatus, opts?: {
    occurredAt?: string;
    taskId?: string;
}): MeshWorkQueueEntry | null;
/**
 * M1-3: true when at least one pending task is waiting on the given task.
 * Used by the completion event path to decide whether to wake the queue.
 */
export declare function hasPendingDependents(meshId: string, taskId: string): boolean;
/**
 * M1: THE single dependency-gate predicate. A task is claimable from a
 * dependency standpoint iff it carries no system block (`blockedReason`) AND
 * every id in `dependsOn` has reached 'completed'.
 *
 * DEPENDSON-GATE-SYMMETRY: every scheduler surface that decides whether a
 * pending task may run MUST route through this one predicate — the queue claim
 * (claimNextQueueTask), the auto-launch candidate filter
 * (maybeAutoLaunchOneQueueSession), and the cloud eager P2P push
 * (enqueue-and-push). If any surface computes dependency readiness on its own,
 * the gate goes asymmetric and a task blocked from the pull path can still be
 * eager-pushed straight to an idle session, silently bypassing its
 * prerequisites. The semantics here (all deps completed && !blocked) are the
 * invariant — do not fork them.
 */
export declare function taskDependenciesSatisfied(entry: Pick<MeshWorkQueueEntry, 'dependsOn' | 'blockedReason'>, statusById: Map<string, MeshTaskStatus | string>): boolean;
/**
 * M1-4: view-time dependency state for a task — unmet dependency ids and
 * whether the task is currently claimable from a dependency standpoint.
 * Not stored (truth stays in task statuses). The `dependenciesSatisfied` field
 * is derived from {@link taskDependenciesSatisfied} so the view and the
 * scheduler gates can never disagree.
 */
export declare function describeTaskDependencyState(entry: Pick<MeshWorkQueueEntry, 'dependsOn' | 'blockedReason'>, statusById: Map<string, MeshTaskStatus | string>): {
    waitingOn: string[];
    dependenciesSatisfied: boolean;
};
export interface MeshWorkQueueStats {
    total: number;
    active: number;
    historical: number;
    pending: number;
    assigned: number;
    completed: number;
    failed: number;
    cancelled: number;
    /** Source-of-truth active queue counters; only pending/assigned are live work. */
    activeCounts: Record<MeshActiveTaskStatus, number>;
    /** Terminal ledger records kept for audit/history; never count as active work. */
    historicalCounts: Record<MeshHistoricalTaskStatus, number>;
    activeAssignments: Array<{
        id: string;
        nodeId?: string;
        sessionId?: string;
        message: string;
    }>;
}
/**
 * Return aggregate queue statistics for the given mesh.
 */
export declare function getMeshQueueStats(meshId: string): MeshWorkQueueStats;
export declare function __replaceMeshQueueForTests(meshId: string, queue: MeshWorkQueueEntry[]): void;
export declare function __clearMeshQueueForTests(meshId: string): void;
export declare function __clearDirectDispatchesForTests(meshId: string): void;
export declare function __resetMeshRuntimeStoreForTests(): void;
export type DirectDispatchRecord = ReturnType<MeshRuntimeStore['getActiveDirectDispatches']>[number];
export declare function insertDirectDispatch(meshId: string, data: {
    taskId: string;
    nodeId?: string;
    sessionId?: string;
    providerType?: string;
    message: string;
    taskMode?: string;
    via: string;
    dispatchedToIdleSession?: boolean;
    dispatchedAt: string;
}): void;
export declare function getActiveDirectDispatches(meshId: string): DirectDispatchRecord[];
export declare function updateDirectDispatchStatus(meshId: string, sessionId: string, status: 'acked' | 'completed' | 'failed' | 'stale', taskId?: string): void;
export declare function cleanupTerminalDirectDispatches(olderThanMs?: number): void;
export declare function markStaleDirectDispatches(meshId: string, olderThanMs?: number): void;
/**
 * Delete specific direct dispatch rows by taskId. Returns the number of rows deleted.
 * Used by the staleDirect prune path to evict orphaned/terminal dispatch records from the
 * active staleDirect surface while leaving the append-only mesh ledger (audit history) intact.
 */
export declare function deleteDirectDispatchesByTaskId(meshId: string, taskIds: string[]): number;
export type MeshToolCallRateResult = {
    rateLimitExceeded: boolean;
    callsInWindow: number;
    advisory: string | null;
};
/**
 * Record a coordinator tool call and return a rate-limit advisory when the
 * call rate for that tool exceeds the allowed threshold.
 *
 * Defaults: 10-second sliding window, max 5 calls before advisory is raised.
 * Returns { rateLimitExceeded: false } on any store error so callers are not blocked.
 */
export declare function recordMeshToolCall(opts: {
    meshId: string;
    tool: string;
    sessionId?: string | null;
    windowMs?: number;
    maxCalls?: number;
}): MeshToolCallRateResult;
