/** * Brainstorm Guard Layer (Phase 2) * * Pure functions that return {ok, reason} for the four brainstorm checkpoints. * Every guard is intentionally side-effect-free — callers wire them in at * the right place and surface the reason to the user. * * Guards: * 1. guardSeedInput — refuse /senai-brainstorm with empty seed. * 2. guardBriefContent — refuse finalize when brief still has _TBD_ placeholders. * 3. guardArtifactPath — refuse writes outside the dedicated brainstorm folder. * 4. guardDispatchCount — refuse subagent dispatch when count would exceed cap. */ import { type MissionType, type SenaiState } from "../core/state.js"; /** Result type returned by every guard. `ok: true` means proceed; * `ok: false` means block, with a human-readable reason. */ export interface GuardResult { ok: boolean; reason?: string; /** Optional structured details — used by tests + doctor to surface specifics. */ details?: string[]; } /** Max subagent dispatches allowed per brainstorm. Keeps token spend bounded. */ export declare const BRAINSTORM_DISPATCH_CAP = 3; /** ────────────────────────────────────────────────────────────────────── * 1. Seed input guard * ────────────────────────────────────────────────────────────────────── */ /** Refuse empty seed input at /senai-brainstorm entry. * * The parent LLM needs at least one signal (topic, insight, goal, question) * to anchor the Q&A. Without a seed the parent would guess the user's * intent — exactly the failure mode brainstorm is supposed to prevent. * * Whitespace-only counts as empty. */ export declare function guardSeedInput(args: string): GuardResult; /** ────────────────────────────────────────────────────────────────────── * 2. Brief content guard * ────────────────────────────────────────────────────────────────────── */ /** Refuse to finalize a brief whose sections still carry `_TBD_` placeholders * or empty bodies. Hard reject — the user must fill the gaps before approve * succeeds. The soft "Finalize anyway?" dialog is removed. * * When a missionType is given, the check runs against that type's required * section list (bugfix adds the 4 pack sections) via * validateBriefContentForType; otherwise it delegates to * validateBriefContent against the base 6 — single-arg calls are unchanged. */ export declare function guardBriefContent(brief: string, missionType?: MissionType): GuardResult; /** ────────────────────────────────────────────────────────────────────── * 3. Artifact path guard * ────────────────────────────────────────────────────────────────────── */ /** Refuse to write any artifact outside the dedicated brainstorm folder * for the active run. The path must resolve to a descendant of * `.IDE_Plans/pi-senai/Brainstorm//`. Path traversal * (`..`) is rejected explicitly. */ export declare function guardArtifactPath(artifactPath: string, brainstormRunId: string): GuardResult; /** ────────────────────────────────────────────────────────────────────── * 4. Dispatch count guard * ────────────────────────────────────────────────────────────────────── */ /** Refuse subagent dispatch when the count would exceed the per-brainstorm * cap. The cap protects the parent context from ballooning and keeps the * audit log focused on the most consequential decisions. */ export declare function guardDispatchCount(count: number): GuardResult; /** ────────────────────────────────────────────────────────────────────── * 5. Approve readiness guard (new brainstorm flow lock) * ────────────────────────────────────────────────────────────────────── */ /** Hard-block /senai-brainstorm-approve while the new-flow brainstorm is * unfinished: the user must have confirmed the parent's understanding * (UNDERSTAND → CONFIRM loop) and every question must be in a terminal * state (agreed / not-wanted / replaced). "draft" and "discussing" block. * * Legacy exemption: a brainstorm session that never entered the new flow * (no missionType recorded) keeps the old approve behavior so in-flight * sessions started before this guard existed are never wedged. */ export declare function guardApproveReadiness(state: SenaiState): GuardResult; /** ────────────────────────────────────────────────────────────────────── * 6. Brainstorm mutation gate (hard enforcement, tool_call hook) * ────────────────────────────────────────────────────────────────────── */ /** Block edit/write tool calls outside the active brainstorm folder while a * new-flow brainstorm is still open (brief not finalized). The brainstorm * stages are read-only for the project — the only allowed writes are the * brief, scout-notes, and discussion docs inside Brainstorm//. * * Lifts automatically when: * - no brainstorm is active (no brainstormRunId), or * - the session is legacy (no missionType — old-flow exemption), or * - the brief is finalized (draft marker stripped by approve). * * Bash is intentionally NOT gated (no reliable target path; the spawn * guard already covers subagent misuse). Returns the pi tool_call block * shape ({ block, reason }) or undefined to allow. Fail-open on any I/O * error — a guard bug must never wedge every edit in the session. */ export declare function guardBrainstormMutation(toolName: string, input: Record | undefined, cwd: string): { block: true; reason: string; } | undefined;