/** 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 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 const AUTOPILOT_INJECTION_PREAMBLE = "[Autopilot] This turn was triggered by Ken, GG Coder's automated reviewer — " +
    "not by a human, and no human is watching it land. So:\n" +
    "- Prove your work before finishing: run the tests/build or screenshot the UI. " +
    'Don\'t end on "should work" — nobody is here to catch a mistake, so verify it ' +
    "yourself.\n" +
    "- Don't stop to ask permission for work that's already implied by the original " +
    "request and safe to do. Just do it and keep going.\n" +
    "- Only surface a question when it needs a real human decision (a product/taste " +
    "call, a destructive or irreversible action, a missing secret or external " +
    "access). State it plainly and stop; Ken routes it to the user.\n\n" +
    "Your instruction:";
/** 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 function frameAutopilotInjection(body) {
    return `${AUTOPILOT_INJECTION_PREAMBLE}\n\n${body}`;
}
/** 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 function buildPlanRevisionPrompt(feedback) {
    return (`The plan was not approved. Feedback from Ken (automated reviewer):\n\n` +
        `${feedback}\n\n` +
        `Revise the plan based on this feedback, then call exit_plan again for review.`);
}
/**
 * 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 async function driveAutopilotCycle(deps) {
    if (deps.isCancelled())
        return;
    await deps.resetReviewer();
    for (let round = 1; round <= deps.maxRounds; round++) {
        if (deps.isCancelled())
            return;
        if (deps.planPending()) {
            const verdict = await deps.reviewPlan();
            if (!verdict || deps.isCancelled())
                return;
            if (verdict.kind === "human") {
                deps.emit({ type: "autopilot_human", data: { reason: verdict.reason } });
                return;
            }
            if (verdict.kind === "prompt") {
                // Rejection with feedback: inject a revision prompt. The sidecar's
                // acceptPlan-side state clears pendingPlanPath on injection; if the
                // run resubmits (exit_plan), planPending() is true again next round;
                // if not, the loop falls through to a normal work review of whatever
                // the run actually did.
                const body = buildPlanRevisionPrompt(verdict.body);
                deps.onInjected(body, round);
                await deps.runPrompt(body);
                continue;
            }
            // all_clear — and ignore mapped to approve ("nothing to object to" on a
            // plan means it's sound; plans never get a silent-ignore user blocker).
            const ok = await deps.acceptPlan();
            if (!ok)
                return; // generation went stale — the user's manual action won
            await deps.runImplement();
            // Next round: normal work review of the implementation.
            continue;
        }
        // The gate blocks a still-in-plan-mode turn up front, so hitting this
        // means an injected run entered plan mode mid-cycle WITHOUT submitting a
        // plan: halt — Ken can't prompt a read-only session.
        if (deps.isPlanMode()) {
            deps.emit({ type: "autopilot_human", data: { reason: AUTOPILOT_PLAN_DRAFTING_REASON } });
            return;
        }
        const verdict = await deps.review();
        if (!verdict || deps.isCancelled())
            return;
        if (verdict.kind === "all_clear") {
            deps.emit({ type: "autopilot_done", data: {} });
            return;
        }
        if (verdict.kind === "ignore") {
            deps.emit({ type: "autopilot_ignored", data: {} });
            return;
        }
        if (verdict.kind === "human") {
            deps.emit({ type: "autopilot_human", data: { reason: verdict.reason } });
            return;
        }
        deps.onInjected(verdict.body, round);
        await deps.runPrompt(verdict.body);
        if (deps.isCancelled())
            return;
    }
    deps.emit({ type: "autopilot_capped", data: { rounds: deps.maxRounds } });
}
//# sourceMappingURL=autopilot-cycle.js.map