/** * Autopilot cycle — the review→prompt→review loop as pure orchestration logic. * * The sidecar wires the real dependencies (kenAuto session, runAgent, SSE * broadcast); this module owns the loop's control flow so every exit path is * unit-testable without booting the sidecar. * * Two branches share one loop: * - PLAN branch (planPending): GG Coder submitted a plan via exit_plan. Ken * reviews the PLAN itself — approve (auto-accept + implement, then the next * round work-reviews the implementation), send revision feedback, or hand a * genuine user-level decision to the human. Verdict mapping for plans: * `all_clear` ⇒ approve, and `ignore` ALSO maps to approve — "nothing to * object to" on a plan means it's sound (autopilot has no user blocker for * plans by design). Unparseable output still stops as HUMAN upstream (the * verdict parser returns HUMAN for garbage) — never a blind loop. * - WORK branch: the classic review of a finished turn (ALL_CLEAR / IGNORE / * HUMAN / PROMPT), unchanged. * * A mid-cycle enter_plan WITHOUT exit_plan (isPlanMode() true, no pending * plan) still halts as HUMAN — Ken must never prompt into a read-only * plan-mode session. */ import type { AutopilotVerdict } from "./autopilot-verdict.js"; /** Reason shown in the Ken bubble when the build session is still INSIDE plan * mode (enter_plan without exit_plan) when the cycle checks in — there is no * submitted plan to review and the session is read-only, so the loop halts * and hands control to the user. */ export declare const AUTOPILOT_PLAN_DRAFTING_REASON = "GG Coder is still drafting a plan (plan mode is active with nothing submitted). Finish or cancel the plan yourself; autopilot can't prompt a read-only session."; /** Situational-awareness preamble prepended to EVERY build-session run that * Autopilot Ken injects (fix prompts, plan-revision prompts, the post-approval * "implement it now" run). GG Coder otherwise can't tell an autopilot-injected * prompt from a human one — it lands as a plain user message — so it behaves as * if someone is watching: it may stop to ask permission for safe, already- * implied work (which only burns a review round, since no human is there) and * it may end a turn on "should work" instead of proving it. This tells it the * turn came from the automated reviewer, that no human is watching, so it must * self-verify and only surface genuine user-level decisions. NEVER prepended to * human-typed prompts — the sidecar applies it only at the autopilot cycle's * injection sites. */ export declare const AUTOPILOT_INJECTION_PREAMBLE: string; /** Prepend {@link AUTOPILOT_INJECTION_PREAMBLE} to a body destined for the build * session during an autopilot cycle. Deterministic so the sidecar can compute * the same framed string both when it runs the prompt AND when it records the * match-string Ken's digest uses to label the message as injected. */ export declare function frameAutopilotInjection(body: string): string; /** Prompt injected into the build session when Ken rejects a plan with * feedback. Mirrors the webview's manual "Feedback" wording in spirit: the * plan was not approved, revise it, resubmit via exit_plan. */ export declare function buildPlanRevisionPrompt(feedback: string): string; /** SSE frame types the cycle can emit (matched by the webview). */ export type AutopilotCycleEmit = { type: "autopilot_done"; data: Record; } | { type: "autopilot_ignored"; data: Record; } | { type: "autopilot_human"; data: { reason: string; }; } | { type: "autopilot_capped"; data: { rounds: number; }; } | { type: "autopilot_plan_accepted"; data: Record; }; export interface AutopilotCycleDeps { /** Hard cap on review→prompt rounds per user turn (loop safety). The sidecar * widens this by +2 when the cycle starts plan-pending (approve+implement * and the post-implement review each consume a round). */ maxRounds: number; /** True once /cancel fires — checked between every step. */ isCancelled: () => boolean; /** Live plan-mode state of the BUILD session. */ isPlanMode: () => boolean; /** True while a submitted plan (exit_plan) awaits a verdict. */ planPending: () => boolean; /** Wipe the reviewer's history so each user turn starts cheap (within one * cycle the review messages persist so Ken remembers what he asked). */ resetReviewer: () => Promise; /** Run one work review; resolves to the parsed verdict or null on failure * (failure is already surfaced by the sidecar as autopilot_error). */ review: () => Promise; /** Run one PLAN review (plan digest, not work digest); null on failure OR * when the review went stale (user acted mid-review) — both stop silently. */ reviewPlan: () => Promise; /** Auto-accept the pending plan (fresh session + approved-plan prompt). * Resolves false when the plan generation went stale (a user Accept/Reject * raced the review and won) — the cycle stops silently. */ acceptPlan: () => Promise; /** Run the "plan approved — implement it now" prompt on the fresh session. */ runImplement: () => Promise; /** Feed a PROMPT verdict's body to GG Coder as an injected run. */ runPrompt: (body: string) => Promise; /** Called BEFORE runPrompt: record the injected body (digest labeling) and * broadcast the autopilot_prompted marker. */ onInjected: (body: string, round: number) => void; /** Broadcast one of the cycle's terminal SSE frames. */ emit: (event: AutopilotCycleEmit) => void; } /** * Drive one full autopilot cycle for a finished user turn. Every exit is * explicit: * - cancelled → silent stop (the /cancel path already broadcast) * - plan mode, no submission → autopilot_human with the drafting reason * - review failed (null) → silent stop (autopilot_error already broadcast) * - plan approve, stale accept→ silent stop (user's manual action won) * - ALL_CLEAR → autopilot_done * - IGNORE (work) → autopilot_ignored (renders nothing) * - HUMAN → autopilot_human * - rounds exhausted → autopilot_capped */ export declare function driveAutopilotCycle(deps: AutopilotCycleDeps): Promise; //# sourceMappingURL=autopilot-cycle.d.ts.map