feat: plumb /sf autonomous full + add docstrings on the auto-command path
`/sf autonomous full` (or `--full`) plumbs through to AutoSession.fullAutonomy, to be consumed at milestone-complete to skip the human-review pause and auto-merge + chain to the next milestone. Git revert is the safety net (see ADR-019/021 conversation on autonomy and reversibility). Plumbing path: - commands/handlers/auto.ts: parses `full` / `--full` modifier, threads fullAutonomy through launchAuto options - commands/catalog.ts: completion entries for `full` and `--full` - auto.ts: startAuto and startAutoDetached accept fullAutonomy in options; startAuto pins it on the session up-front so resume paths preserve it - auto/session.ts: AutoSession.fullAutonomy field with full docstring Behavior change is staged: the milestone-complete consumer that auto-merges and chains is intentionally not in this commit (parallel session is active in auto-post-unit.ts and auto/loop.ts; will land in a follow-up). Also adds JSDoc to the functions on the touched path: - handleAutoCommand (full command-family doc) - launchAuto (headless vs detached routing) - startAutoDetached (fire-and-forget rationale, why it diverges from startAuto) - AutoSession.fullAutonomy (full inline doc) Typecheck clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
356d1d1f99
commit
ed85252fc5
4 changed files with 77 additions and 1 deletions
|
|
@ -307,6 +307,23 @@ function normalizeSessionFilePath(raw: unknown): string | null {
|
|||
return candidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire-and-forget wrapper around {@link startAuto} for the interactive shell.
|
||||
*
|
||||
* The interactive REPL cannot block on the long-running auto loop, so the
|
||||
* command handler calls this synchronously: the loop runs in the background,
|
||||
* UI events fire through `ctx.ui.notify`, and any startup failure surfaces as
|
||||
* an error notification rather than an unhandled rejection.
|
||||
*
|
||||
* The headless code path uses {@link startAuto} directly because `sf headless`
|
||||
* needs to await loop completion to set its exit code.
|
||||
*
|
||||
* @param ctx Extension command context (for notify, status, widgets)
|
||||
* @param pi Extension API (for engine calls and sessions)
|
||||
* @param base Project root path
|
||||
* @param verboseMode Verbose execution output
|
||||
* @param options Optional run modifiers — see {@link startAuto}
|
||||
*/
|
||||
export function startAutoDetached(
|
||||
ctx: ExtensionCommandContext,
|
||||
pi: ExtensionAPI,
|
||||
|
|
@ -316,6 +333,11 @@ export function startAutoDetached(
|
|||
step?: boolean;
|
||||
interrupted?: InterruptedSessionAssessment;
|
||||
milestoneLock?: string | null;
|
||||
/**
|
||||
* Full-autonomy mode: auto-merge milestone branches and chain to the
|
||||
* next milestone without pausing for human review. See `/sf autonomous full`.
|
||||
*/
|
||||
fullAutonomy?: boolean;
|
||||
},
|
||||
): void {
|
||||
void startAuto(ctx, pi, base, verboseMode, options).catch((err) => {
|
||||
|
|
@ -1467,6 +1489,11 @@ export async function startAuto(
|
|||
step?: boolean;
|
||||
interrupted?: InterruptedSessionAssessment;
|
||||
milestoneLock?: string | null;
|
||||
/**
|
||||
* Full-autonomy mode: auto-merge milestone branches and chain to the
|
||||
* next milestone without pausing for human review. See `/sf autonomous full`.
|
||||
*/
|
||||
fullAutonomy?: boolean;
|
||||
},
|
||||
): Promise<void> {
|
||||
if (s.active) {
|
||||
|
|
@ -1485,6 +1512,11 @@ export async function startAuto(
|
|||
|
||||
const requestedStepMode = options?.step ?? false;
|
||||
const interruptedAssessment = options?.interrupted ?? null;
|
||||
// Pin full-autonomy on the session up-front. The branches below that set
|
||||
// stepMode never override fullAutonomy — it carries through resume paths,
|
||||
// fresh starts, and crash recovery so the milestone-complete code path can
|
||||
// consult it without re-reading command-line options.
|
||||
s.fullAutonomy = options?.fullAutonomy === true;
|
||||
if (options?.milestoneLock !== undefined) {
|
||||
s.sessionMilestoneLock = options.milestoneLock ?? null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,13 @@ export class AutoSession {
|
|||
active = false;
|
||||
paused = false;
|
||||
stepMode = false;
|
||||
/**
|
||||
* Full-autonomy mode: auto-merge milestone branches and chain to the next
|
||||
* milestone without pausing for human review. Set from the `/sf autonomous full`
|
||||
* command line. Consumed at milestone-complete to skip the review pause and
|
||||
* auto-trigger merge + next-milestone dispatch. Git revert is the safety net.
|
||||
*/
|
||||
fullAutonomy = false;
|
||||
verbose = false;
|
||||
activeEngineId: string | null = null;
|
||||
activeRunDir: string | null = null;
|
||||
|
|
|
|||
|
|
@ -163,10 +163,14 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly SfCommandDefinition[] = [
|
|||
|
||||
const NESTED_COMPLETIONS: CompletionMap = {
|
||||
autonomous: [
|
||||
{ cmd: "full", desc: "Auto-merge milestones; chain end-to-end without review" },
|
||||
{ cmd: "--full", desc: "Auto-merge milestones; chain end-to-end without review" },
|
||||
{ cmd: "--verbose", desc: "Show detailed execution output" },
|
||||
{ cmd: "--debug", desc: "Enable debug logging" },
|
||||
],
|
||||
auto: [
|
||||
{ cmd: "full", desc: "Auto-merge milestones; chain end-to-end without review" },
|
||||
{ cmd: "--full", desc: "Auto-merge milestones; chain end-to-end without review" },
|
||||
{ cmd: "--verbose", desc: "Show detailed execution output" },
|
||||
{ cmd: "--debug", desc: "Enable debug logging" },
|
||||
],
|
||||
|
|
|
|||
|
|
@ -60,6 +60,24 @@ export function parseMilestoneTarget(input: string): {
|
|||
return { milestoneId: match[1], rest };
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch entry point for the auto-mode command family.
|
||||
*
|
||||
* Handles `/sf auto`, `/sf autonomous`, `/sf next`, `/sf stop`, `/sf pause`, and
|
||||
* their flag variants. Returns `true` when the command was recognised and
|
||||
* routed (caller stops searching), `false` when the command isn't auto-related.
|
||||
*
|
||||
* Recognised flags on autonomous/auto:
|
||||
* - `full` or `--full` — full-autonomy mode (auto-merge + chain milestones)
|
||||
* - `--verbose` — verbose execution output
|
||||
* - `--debug` — enable debug logging via SF_DEBUG
|
||||
* - `M001` (positional) — milestone target lock (only run that milestone)
|
||||
* - `--yolo=<file>` — yolo seed; bootstraps a fresh milestone from a brief
|
||||
*
|
||||
* The handler validates milestone targets exist, gates remote sessions, then
|
||||
* dispatches via `launchAuto` (which routes between headless and detached
|
||||
* spawn paths).
|
||||
*/
|
||||
export async function handleAutoCommand(
|
||||
trimmed: string,
|
||||
ctx: ExtensionCommandContext,
|
||||
|
|
@ -71,11 +89,20 @@ export async function handleAutoCommand(
|
|||
trimmed === "autonomous" ||
|
||||
trimmed.startsWith("autonomous ");
|
||||
|
||||
/**
|
||||
* Route an auto-mode launch through either the headless (in-process) or
|
||||
* detached (spawned subprocess) entry point depending on `SF_HEADLESS`.
|
||||
*
|
||||
* Headless mode runs the auto loop in the current process (used by CI,
|
||||
* tests, and `sf headless`); detached mode forks a long-running child so
|
||||
* the interactive shell stays responsive while auto-mode runs.
|
||||
*/
|
||||
const launchAuto = async (
|
||||
verboseMode: boolean,
|
||||
options?: {
|
||||
step?: boolean;
|
||||
milestoneLock?: string | null;
|
||||
fullAutonomy?: boolean;
|
||||
},
|
||||
): Promise<void> => {
|
||||
if (process.env.SF_HEADLESS === "1") {
|
||||
|
|
@ -123,6 +150,11 @@ export async function handleAutoCommand(
|
|||
parseMilestoneTarget(afterYolo);
|
||||
const verboseMode = afterMilestone.includes("--verbose");
|
||||
const debugMode = afterMilestone.includes("--debug");
|
||||
// `/sf autonomous full` (or `--full`): full-autonomy mode — auto-merges
|
||||
// milestone branches and chains to the next milestone without pausing
|
||||
// for human review. Git revert is the safety net.
|
||||
const fullAutonomy =
|
||||
/\bfull\b/.test(afterMilestone) || afterMilestone.includes("--full");
|
||||
if (debugMode) enableDebug(projectRoot());
|
||||
if (!(await guardRemoteSession(ctx, pi))) return true;
|
||||
|
||||
|
|
@ -159,9 +191,10 @@ export async function handleAutoCommand(
|
|||
} else if (milestoneId) {
|
||||
await launchAuto(verboseMode, {
|
||||
milestoneLock: milestoneId,
|
||||
fullAutonomy,
|
||||
});
|
||||
} else {
|
||||
await launchAuto(verboseMode);
|
||||
await launchAuto(verboseMode, fullAutonomy ? { fullAutonomy } : undefined);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue