/**
 * AutonomousSessions — multi-session autonomy control surface.
 *
 * Each autonomous job has its own state file at
 * `<stateDir>/autonomous/<topicId>.local.md`. A legacy single-file job at
 * `<stateDir>/autonomous-state.local.md` is also recognized for back-compat.
 *
 * This module is the read/control layer over those files: list active jobs,
 * enforce the concurrency cap + quota at start, and stop jobs (all or one).
 * The stop hook (`autonomous-stop-hook.sh`) is the per-session enforcer; this
 * module is what the server routes, the start path, and the stop-everything
 * path call. It never traps a session itself — it only reports and clears state.
 */
import type { JobPriority } from './types.js';
/** Default concurrent autonomous-job cap when config doesn't specify one. */
export declare const DEFAULT_MAX_CONCURRENT_AUTONOMOUS = 5;
export interface AutonomousJobSummary {
    topic: string | null;
    file: string;
    active: boolean;
    paused: boolean;
    goal: string | null;
    iteration: number | null;
    startedAt: string | null;
    /** duration_seconds front-matter field; null when absent/unparseable (unbounded run). */
    durationSeconds: number | null;
    reportChannel: string | null;
}
/** All autonomous jobs (per-topic files + a legacy single file if present). */
export declare function listAutonomousJobs(stateDir: string): AutonomousJobSummary[];
/** Active (and not paused) autonomous jobs — what counts against the cap. */
export declare function activeAutonomousJobs(stateDir: string): AutonomousJobSummary[];
/**
 * Honest-recycle helper (honest-session-recycle-spec): the ACTIVE autonomous run
 * for `topic` with the seconds remaining on its window — or null when there is no
 * active run for the topic, or its window is already over. This is the single
 * place the run-window remaining is computed, so the recycle copy (and any future
 * caller) agree on "is this an in-flight run, and how long is left?". The reaper's
 * per-session age cap is a SEPARATE, shorter clock; this answers the run clock.
 */
export declare function autonomousRunRemainingForTopic(stateDir: string, topic: string | number, nowMs?: number): {
    active: true;
    remainingSeconds: number;
} | null;
/**
 * Run-state markers the AutonomousProgressHeartbeat reads for its cheap-first
 * predicates (autonomous-progress-heartbeat spec §predicates #2 + #3):
 *   - `movedTo` / `moveSuspendedAt`: a mid-handoff marker (predicate #2 — this
 *     machine must stay silent on a run about to fire from the destination).
 *   - `startedAtMs`: the run's start wall-clock (predicate #3 — destination
 *     warmup elapsed when the run has been active ON THIS MACHINE ≥ one window).
 *
 * Returns null when there is no per-topic run file (the heartbeat already
 * gates on `autonomousRunRemainingForTopic` first; this is a SECOND read of the
 * same file's markers, isolated here so all run-state file-format knowledge
 * stays in this module). Reading fails CLOSED via the caller: a null return on
 * a topic the run-active predicate already passed means the markers couldn't be
 * read → the heartbeat suppresses.
 */
export interface AutonomousRunMarkers {
    /** The target machine of an in-flight move, or null when not mid-move. */
    movedTo: string | null;
    /** Whether a `move_suspended_at` breadcrumb is present (mid-handoff). */
    moveSuspended: boolean;
    /** started_at parsed to epoch ms, or null when absent/unparseable. */
    startedAtMs: number | null;
}
export declare function readAutonomousRunMarkers(stateDir: string, topic: string | number): AutonomousRunMarkers | null;
export interface CanStartDeps {
    stateDir: string;
    maxConcurrent: number;
    quotaCanStart?: (priority?: JobPriority) => {
        allowed: boolean;
        reason: string;
    };
    priority?: JobPriority;
}
export interface CanStartResult {
    allowed: boolean;
    reason: string;
    activeCount: number;
    maxConcurrent: number;
}
/**
 * Decide whether a new autonomous job may start: concurrency cap first
 * (refuse-new at the cap), then quota (refuse-new under budget pressure).
 * Never preempts a running job — that's the pause path, handled elsewhere.
 */
export declare function canStartAutonomousJob(deps: CanStartDeps): CanStartResult;
/** Stop exactly one topic's job (removes its state file). Returns true if removed. */
/**
 * Minimal journal seam (COHERENCE-JOURNAL-SPEC §3.3): the stop funnels emit
 * `stopped` directly when a handle is threaded by the caller. Callers without
 * the handle still get coverage from the journal scanner's observed-stopped
 * (≤ one scan interval later); op-key dedupe collapses the two.
 */
export interface AutonomousJournalSeam {
    emitAutonomousRun(topic: number, data: {
        action: 'started' | 'stopped';
        runId: string;
        artifactPaths: string[];
    }): void;
}
/** The stable runId formula shared by the scanner and the stop funnels. */
export declare function autonomousRunId(startedAt: string | null, topic: string): string;
/**
 * WS1.4 (MULTI-MACHINE-SEAMLESSNESS-SPEC): suspend a topic's autonomous run
 * for a CONFIRMED topic move — distinct from stop in exactly one way: the
 * state file SURVIVES so it can ride the working-set carrier to the new
 * owner. Setting `active: false` makes the stop hook release the session at
 * its next turn boundary (the spec's "stops at a turn boundary"); the
 * `moved_to` + `move_suspended_at` markers are the honest breadcrumb for
 * whoever resumes it. The rewrite is ATOMIC (temp + fsync + rename) so the
 * carrier can never ship a half-rewritten file, and the journal `stopped`
 * emit is what re-fires the receiving machine's working-set pull
 * (WorkingSetManifest §3.4 liveSource re-fire).
 *
 * Idempotent: re-suspending an already-suspended file refreshes the markers
 * and returns true; a missing file returns false.
 */
export declare function suspendAutonomousTopicForMove(stateDir: string, topic: string, targetMachine: string, journal?: AutonomousJournalSeam): {
    suspended: boolean;
    file?: string;
};
/**
 * Stamp a (move-suspended) run file `interrupted_mid_task: true` — the honest
 * marker that the drain bound forced the close before the session reached a
 * turn boundary (WS1.2). The resuming machine surfaces it so the run knows its
 * final turn may be partial. Idempotent; missing file is a no-op (the drain
 * may have closed a session with no run).
 */
export declare function markAutonomousInterruptedMidTask(stateDir: string, topic: string): boolean;
export declare function stopAutonomousTopic(stateDir: string, topic: string, journal?: AutonomousJournalSeam): boolean;
export interface StopAllResult {
    stoppedTopics: string[];
    stoppedLegacy: boolean;
}
/**
 * Stop every autonomous job. Removes all per-topic files + the legacy file and
 * writes the emergency-stop flag so any session whose hook fires before its file
 * is gone also stands down. The flag is the belt; removing files is the suspenders.
 */
export declare function stopAllAutonomousJobs(stateDir: string, journal?: AutonomousJournalSeam): StopAllResult;
/** Pause one topic's job (hook will allow exit until resumed). Returns true if updated. */
export declare function pauseAutonomousTopic(stateDir: string, topic: string): boolean;
//# sourceMappingURL=AutonomousSessions.d.ts.map