export type H2ALoopStatus = "created" | "running" | "waiting-human" | "waiting-agent" | "stalled" | "degraded" | "done" | "failed" | "cancelled" | "active" | "stopped" | "blocked"; export type H2ALoopAgentStatus = "planned" | "launching" | "running" | "idle" | "working" | "blocked" | "awaiting-decision" | "rate-limited" | "out-of-tokens" | "dead" | "done" | "failed" | "cancelled"; export interface H2ALoopLaunchSpec { readonly profile: "claude" | "codex"; readonly workspace: string; readonly prompt: string; readonly model: string; readonly name: string; readonly effort?: "low" | "medium" | "high" | "xhigh"; readonly gateway?: "auto" | "required" | "off"; } export interface H2ALoopTrackRef { readonly system: "track"; readonly repoKey: string; readonly workspace: string; readonly aggregateKind: "item" | "decision" | "blocker" | "criterion" | "evidence" | "wp"; readonly aggregateId: string; readonly role: string; /** * Owner-facing payload for a decision gate. Only refs with * `role:"decision-gate"` use this; ordinary Track refs stay unchanged. * The loop engine turns an open gate into one pending Track decision, but * this declaration does not opt a loop into supervisor ticks. */ readonly decisionGate?: H2ALoopDecisionGate; readonly baselineCommit?: string; } /** A native Track decision option declared by a loop decision gate. */ export interface H2ALoopDecisionGateOption { readonly id: string; readonly title: string; readonly summary: string; readonly pros?: readonly string[]; readonly cons?: readonly string[]; } /** An optional question that accompanies an owner-facing decision gate. */ export interface H2ALoopDecisionGateQuestion { readonly id: string; readonly question: string; readonly answer?: string; } /** * Structured data needed to turn an open loop ref into a well-formed pending * Track decision. The explicit target avoids guessing which tracked item the * owner is being asked to unblock. */ export interface H2ALoopDecisionGate { /** Stable identity for this gate within the loop. */ readonly id: string; readonly decisionKind: "orientation" | "commitment"; readonly title: string; readonly context: string; readonly options: readonly H2ALoopDecisionGateOption[]; readonly qa?: readonly H2ALoopDecisionGateQuestion[]; readonly recommendation: { readonly optionId: string; readonly rationale: string; }; readonly target: { readonly itemId: string; readonly workspace: string; }; } export interface H2ALoopRepoRef { readonly path: string; readonly role?: string; readonly remotePath?: string; } export interface H2ALoopAgent { readonly id: string; readonly host: "claude" | "codex" | "agy" | "gemini" | "mistral" | "hermes" | "opencode" | "shell"; readonly driver?: string; readonly role: string; readonly placement: "local" | "remote" | "auto" | "headless-local" | "headless-remote" | "interactive-local" | "interactive-remote"; readonly status: H2ALoopAgentStatus; readonly h2aInstance?: string; readonly required?: boolean; readonly joinedAt?: string; readonly remoteAgentId?: string; readonly remoteJobId?: string; readonly trackRefs?: H2ALoopTrackRef[]; /** Complete opt-in specification for a canonical `h2a run` relaunch. */ readonly launch?: H2ALoopLaunchSpec; } export interface H2ALoopPolicy { readonly tickMs: number; readonly idleMs: number; readonly maxRelaunches: number; readonly requireHumanTypingGuard: true; /** * Per-loop opt-in for durable, server-driven auto-ticking (L1). Default * false: a loop is NEVER auto-ticked unless it explicitly opts in, so * enabling the supervisor does not resurrect every existing loop at once * (the measured blast radius the double-opus review flagged). The global * kill-switch `H2A_LOOP_AUTOTICK_OFF` overrides this to off everywhere. * Optional for backward-compat: loops persisted before this field are read * as not-opted-in. */ readonly autoTick?: boolean; readonly closeWhenRefsSatisfied: boolean; readonly successCriteria: "explicit-done" | "all-targets-accepted" | "all-targets-done-or-waived" | "policy-expression"; readonly decisionGatePolicy: "all-go-or-waived" | "advisory-only"; } export interface H2AObjectiveLoop { readonly id: string; readonly ownerSystem: "h2a"; readonly name: string; readonly goal: string; readonly status: H2ALoopStatus; readonly repos: H2ALoopRepoRef[]; readonly refs: H2ALoopTrackRef[]; readonly agents: H2ALoopAgent[]; readonly policy: H2ALoopPolicy; readonly createdAt: string; readonly updatedAt: string; } export interface H2ALoopEvent { readonly type: string; readonly loopId: string; readonly at: string; readonly payload?: unknown; } export interface CreateObjectiveLoopInput { readonly id?: string; readonly name?: string; readonly goal: string; readonly repos?: H2ALoopRepoRef[]; readonly refs?: H2ALoopTrackRef[]; readonly agents?: H2ALoopAgent[]; readonly policy?: Partial; } export interface LoopJoinInput { readonly instance: string; readonly agentId?: string; readonly role?: string; readonly required?: boolean; readonly launch?: H2ALoopLaunchSpec; } export interface LoopReportInput { readonly instance?: string; readonly agentId?: string; readonly note: string; readonly artifacts?: unknown[]; /** Explicit recovery for a legacy/staged empty loop. Never inferred. */ readonly autoJoin?: boolean; } export interface LoopDoneInput { readonly instance?: string; readonly agentId?: string; readonly note?: string; readonly overrideRefs?: boolean; readonly human?: boolean; } export interface LoopStopInput { readonly reason?: string; } export declare const H2A_DEFAULT_LOOP_POLICY: H2ALoopPolicy; /** Strict validation at every persistence/action boundary; returns a plain copy. */ export declare function validateLoopLaunchSpec(value: unknown): H2ALoopLaunchSpec; export declare function createLoopId(now?: number): string; export declare function appendLoopEvent(root: string, event: H2ALoopEvent): H2ALoopEvent; export declare function createObjectiveLoop(root: string, input: CreateObjectiveLoopInput, now?: number): H2AObjectiveLoop; export declare function readObjectiveLoop(root: string, loopId: string): H2AObjectiveLoop; export interface H2AObjectiveLoopListResult { readonly loops: H2AObjectiveLoop[]; readonly warnings: string[]; } export declare function listObjectiveLoopsWithDiagnostics(root: string): H2AObjectiveLoopListResult; export declare function listObjectiveLoops(root: string): H2AObjectiveLoop[]; /** * Loop statuses that are terminal for AUTOMATIC wake (§7.3). This is the SINGLE * source of truth: the tick engine (`engine/tick.ts`) imports this constant for * its terminal / no-action gates, so the auto-tick eligibility gate below and * the executor can never disagree about what "terminal" means. `blocked` is * included deliberately — a blocked loop must not be woken by a tick; recovery * is explicit + CLI-only. */ export declare const H2A_TERMINAL_LOOP_STATUSES: ReadonlySet; /** * Fail-closed allow-list: the ONLY statuses a durable executor may auto-tick. * Eligibility is decided by MEMBERSHIP here, not by "not terminal" — so an * unknown / future / on-disk-corrupt status (never enumerated) is NOT eligible * by default. Together with {@link H2A_TERMINAL_LOOP_STATUSES} this partitions * the known `H2ALoopStatus` union (7 live + 5 terminal = 12). `waiting-human` is * live only as a RE-EVALUATION tick (so the loop notices the human acted); the * decision engine + `requireHumanTypingGuard` — not this projection — guarantee * no relaunch is issued while a human is the blocker. */ export declare const H2A_AUTOTICK_LIVE_STATUSES: ReadonlySet; /** True once a loop has reached a status terminal for automatic wake. */ export declare function isLoopTerminal(loop: Pick): boolean; /** * Global kill-switch for durable auto-ticking. When `H2A_LOOP_AUTOTICK_OFF` is * set to any non-empty, non-"0"/"false" value, NO loop is auto-ticked anywhere, * regardless of per-loop opt-in. This is the single lever to freeze the * supervisor without editing any loop. */ export declare function autoTickGloballyDisabled(env?: NodeJS.ProcessEnv): boolean; /** * True when this loop is eligible for durable auto-ticking right now. Fail-closed * on every axis: the loop must (1) explicitly opt in — `policy?.autoTick === true`, * so a legacy/missing policy or missing field reads as not-opted-in and a shape- * corrupt on-disk loop never throws here; (2) be in an explicitly LIVE status * (unknown / terminal / corrupt status ⇒ not eligible); and (3) not be globally * frozen by the kill-switch. */ export declare function isLoopAutoTickEligible(loop: Pick, env?: NodeJS.ProcessEnv): boolean; /** * The loops the durable supervisor may auto-tick: opted-in (`policy.autoTick`), * in a LIVE status, and not globally disabled. Empty when the kill-switch is on. * Never throws on a shape-corrupt store: `listObjectiveLoops` skips unparsable * loop dirs, and the eligibility predicate is fail-closed on missing policy / * status (so a partially-written `state.json` is simply excluded, never a crash * that would hide every healthy loop). Read-only projection — acquiring the * per-loop executor lease and ticking is the supervisor's job (a later lot). */ export declare function listAutoTickLoops(root: string, env?: NodeJS.ProcessEnv): H2AObjectiveLoop[]; export declare function listLoopEvents(root: string, loopId: string): H2ALoopEvent[]; /** * Transition a loop to a new status. IDEMPOTENT: if the loop is already at * `status`, nothing is written and `changed:false` is returned. On a real * change, rewrites `state.json` (status + updatedAt) and appends `loop.closed` * (for "done") or `loop.status-changed`. This is the ONLY store write the * objective-loop tick executor performs for the `close` action — no injection. */ export declare function updateObjectiveLoopStatus(root: string, loopId: string, status: H2ALoopStatus, opts?: { now?: number; reason?: string; }): { changed: boolean; loop: H2AObjectiveLoop; }; /** Explicitly opt one persisted loop into durable supervisor ticks. */ export declare function enableObjectiveLoopAutoTick(root: string, loopId: string, now?: number): H2AObjectiveLoop; export declare function joinObjectiveLoop(root: string, loopId: string, input: LoopJoinInput, now?: number): H2AObjectiveLoop; export declare function reportObjectiveLoop(root: string, loopId: string, input: LoopReportInput, now?: number): H2AObjectiveLoop; export declare function declareObjectiveLoopDone(root: string, loopId: string, input?: LoopDoneInput, now?: number): H2AObjectiveLoop; export declare function stopObjectiveLoop(root: string, loopId: string, input?: LoopStopInput, now?: number): H2AObjectiveLoop; //# sourceMappingURL=index.d.ts.map