diff --git a/src/resources/extensions/sf/auto.js b/src/resources/extensions/sf/auto.js index 33e65a481..168e9bf65 100644 --- a/src/resources/extensions/sf/auto.js +++ b/src/resources/extensions/sf/auto.js @@ -189,6 +189,8 @@ import { setActiveMilestoneId, } from "./worktree.js"; import { WorktreeResolver } from "./worktree-resolver.js"; +import { resolvePreset } from "./operating-model.js"; +import { showConfirm } from "../shared/tui.js"; export { MAX_LIFETIME_DISPATCHES, @@ -1392,6 +1394,27 @@ export async function startAuto(ctx, pi, base, verboseMode, options) { debugLog("startAuto", { phase: "already-active", skipping: true }); return; } + // Gate: if the user is in Ask mode (manual runControl), ask permission to + // switch to Build mode before starting autonomous execution. + if (s.runControl === "manual" && !options?.skipModeGate) { + const confirmed = await showConfirm(ctx, { + title: "Switch to Build mode?", + message: + "You're in Ask mode. Autonomous execution requires Build mode — SF will execute without further prompts.", + confirmLabel: "Switch to Build", + declineLabel: "Stay in Ask", + }); + if (!confirmed) return; + const buildPreset = resolvePreset("build"); + s.setMode({ + workMode: buildPreset.workMode, + runControl: buildPreset.runControl, + modelMode: buildPreset.modelMode, + permissionProfile: buildPreset.permissionProfile, + reason: "ask-to-build-gate", + }); + ctx.ui.notify("Switched to Build mode — starting autonomous execution.", "info"); + } // On a *fresh* start, drop any stale active-tool baseline left by a prior // auto session that didn't run stopAuto cleanly. Skip on resume: pauseAuto // leaves the last provider-trimmed active tools in place, so clearing here