import type { RudderBus } from "./bus.js";
import type { GraphEdge, RudderGraph, TaskNode } from "./types.js";
/**
 * The set of nodes to launch this tick: ready nodes (planned + all hard parents
 * merged) sorted oldest-first, sliced to the remaining parallel capacity.
 */
export declare function selectLaunchable(graph: RudderGraph, runningCount: number, maxParallel: number): TaskNode[];
/**
 * When a node fails or is cancelled, the hard dependents (direct + transitive)
 * that can no longer ever start must become blocked. Soft dependents are
 * unaffected (they only ever received the parent's diff as context).
 */
export declare function computeBlocked(graph: RudderGraph, failedOrCancelledNodeId: string): string[];
/**
 * Build the resolver-agent prompt. Pure: given the conflicted merge change, the
 * two merged titles, and the conflicted files, it instructs the worker to open
 * each file, resolve preserving BOTH intents, and remove all conflict markers.
 */
export declare function buildResolverPrompt(input: {
    mergeChangeId: string;
    intoTitle: string;
    nodeTitle: string;
    conflictedFiles: string[];
}): string;
/**
 * PURE decision: should a completed resolver run finalize its original node?
 * Yes when the run is a resolver (has resolverFor) and no conflicts remain in
 * its workspace. The IO (listConflicts) is supplied by the caller so this stays
 * unit-testable without jj.
 */
export declare function resolverShouldFinalize(input: {
    resolverFor: string | undefined;
    remainingConflicts: string[];
}): boolean;
/**
 * Soft edges whose parent has merged but whose diff has not yet been delivered
 * to the child. The scheduler pipes each parent's diff into the child context.
 */
export declare function undeliveredSoftEdges(graph: RudderGraph): GraphEdge[];
/**
 * Judge edges (fan-out-and-judge) whose variant has REACHED review (or merged)
 * but whose diff has not yet been delivered to the judge node. Like
 * undeliveredSoftEdges but gated on review rather than merge, since the judge
 * compares the variants' finished work before any of them lands.
 */
export declare function undeliveredJudgeEdges(graph: RudderGraph): GraphEdge[];
/**
 * Whether a node is a fan-out variant: the `from` of at least one judge edge.
 * Such a node is never merged on its own; the judge node it feeds produces the
 * winning implementation and merges that. Used to skip variants in auto-merge.
 */
export declare function isJudgedVariant(graph: RudderGraph, id: string): boolean;
/**
 * Sum the node-attributed token usage across the whole graph (running +
 * terminal + merged). This is the number the budget cap compares against.
 */
export declare function sumNodeTokens(graph: RudderGraph): number;
/**
 * Pure budget gate: true when a positive maxTokens cap is set and the spent
 * total has reached it. The scheduler HOLDS new launches when this is true.
 */
export declare function isOverBudget(tokensSpent: number, maxTokens: number | undefined): boolean;
/**
 * Whether `next` token usage is a larger total than `prev` (or prev is unset).
 * Backends report cumulative usage, so the largest value seen is the truth; we
 * only ever raise node.tokens, never lower it.
 */
export declare function tokensNewer(prev: {
    input: number;
    output: number;
} | undefined, next: {
    input: number;
    output: number;
}): boolean;
/**
 * Launch a ready node: create its jj workspace off the scaffolded change (or the
 * integration trunk), create the run record, flip status to "running" INSIDE the
 * updateGraph transaction (the double-launch guard), then spawn the detached
 * worker and publish schedule.launched.
 */
export declare function launchNode(repoRoot: string, graph: RudderGraph, node: TaskNode, bus: RudderBus): Promise<void>;
/**
 * Merge a node's change into the integration trunk. Captures the op id first.
 * Clean -> node "merged" + advance graph.integrationChangeId + exportToGit +
 * merge.merged. Conflict -> node "blocked" + record operationId/conflictedFiles
 * + merge.conflict. The resolver-agent spawn is Phase 5; for now hold it blocked.
 */
export declare function mergeNodeIntoIntegration(repoRoot: string, node: TaskNode, bus: RudderBus): Promise<void>;
/**
 * Deliver a parent's diff to its child as additional context, then mark the
 * edge delivered. Used for both soft edges (parent merged) and judge edges (the
 * variant reached review). Minimal acceptable form: record the parent diff on
 * the child node (the worker re-reads it). Never blocks. Publishes
 * schedule.softDelivered.
 */
export declare function deliverSoftDiff(repoRoot: string, edge: GraphEdge, bus: RudderBus): Promise<void>;
export declare function withSchedulerLock<T>(repoRoot: string, fn: () => Promise<T>): Promise<T>;
/**
 * One scheduler tick. Recompute each scheduled node's status from its run.json,
 * read orchestrator config, hold if at capacity or over budget, else launch the
 * selectable ready nodes and deliver undelivered soft diffs. A node that just
 * reached completed (review) auto-merges when reviewGate==="auto".
 *
 * Public entry point: serialized against all other scheduler ops for this repo.
 * Internal callers that already hold the lock use `scheduleTickCore` directly.
 */
export declare function scheduleTick(repoRoot: string, bus: RudderBus): Promise<void>;
/**
 * Called by the daemon when a run.json changes. Projects the owning node's
 * status: completed -> review (auto-merge if configured); failed/cancelled ->
 * node.failed + propagate blocked to hard dependents. Then ticks the scheduler.
 */
export declare function onRunTransition(repoRoot: string, runId: string, bus: RudderBus): Promise<void>;
/**
 * The single injection chokepoint. A typed task (terminal pane or board
 * composer) becomes a NEW node reconciled against the frontier, never blindly
 * appended. Adds the node (status "planned", source "injection") + inferred
 * edges, scaffolds its empty jj change, publishes plan.reconciled, then ticks.
 */
export declare function reconcileInjection(repoRoot: string, input: {
    prompt: string;
    title?: string;
    backend?: TaskNode["backend"];
    model?: string;
    effort?: TaskNode["effort"];
}, bus: RudderBus): Promise<{
    nodeId: string;
}>;
