/** * 24h mode B3 trigger evaluation + attempts counter. * * primitive: it increments the per-key counter and escalates with a * `B3Escalation` when the count reaches `B3_THRESHOLD` (3). The * counter is **per-key** — AC-T3 mandates B1 and B2 retries do not * share a global counter. The T3/T4 auto-24H_ACTIVE path is encoded * in `isAutoEngageTrigger` (BRAINSTORM is bypassed for these * triggers so an offline-resumed session does not deadlock in * WAITING_USER — proposal §1 T3/T4 exception). */ import { type DecisionKey, type State } from './state.js'; import type { AutoCompactMode } from '../code/auto-compact-modes.js'; export type AttemptsMap = Record; export declare const B3_TRIGGER_REASONS: readonly ["prd_direction_change", "blocker_3_consecutive_slices", "registry_affecting_failure", "destructive_irreversible_op", "any_B1_B2_failure_3x_non_converging", "runtime_or_shared_version_mismatch", "sub-agent_stale_5min_x3"]; export type B3Reason = (typeof B3_TRIGGER_REASONS)[number]; export declare class B3Escalation extends Error { readonly reason: B3Reason; readonly attempts: number; constructor(reason: B3Reason, attempts: number); } /** * Result envelope for `fireB3`. We return a discriminated union * (instead of throwing) so callers can branch on `kind` without * try/catch ceremony. The B3Escalation class is still exported for * backward compatibility with callers that prefer the throw style. */ export type FireB3Result = { kind: 'continue'; reason: B3Reason; attempts: number; } | { kind: 'escalate'; reason: B3Reason; attempts: number; }; export declare function isB3Reason(value: string): value is B3Reason; export declare function isValidReason(value: string): value is DecisionKey; export declare function freshAttempts(): AttemptsMap; /** * Per AC-T1 (attempts=1 continue, no B3) and AC-T2 (attempts=3 * escalate), the 3rd call escalates. The threshold is intentionally * NOT configurable — the proposal pins the constant so QA v3 can * assert it. Returns a FireB3Result instead of throwing so test * code can read the `attempts` field via plain property access * (Error-subclass property access through vitest 4.1.10 matchers * is unreliable; the discriminated union sidesteps that). */ export declare function fireB3(reason: B3Reason, attempts: AttemptsMap): FireB3Result; /** * T3 (runaway recovery) and T4 (offline resume) auto-engage * `24H_ACTIVE` without forcing `USER_CONFIRM` — the deferred * AskUserQuestion fires at the first 10min checkpoint instead, so * a T4 session does not deadlock in `WAITING_USER` while the * user is offline (proposal §1 T3/T4 exception). */ export declare const AUTO_ENGAGE_TRIGGERS: readonly ["T3", "T4"]; export type AutoEngageTrigger = (typeof AUTO_ENGAGE_TRIGGERS)[number]; export declare function isAutoEngageTrigger(t: string): t is AutoEngageTrigger; /** * Five trigger conditions (T1-T5) from proposal §1 + companion * trigger-and-decision-autonomy sediment. T1/T2/T5 flow through * BRAINSTORM; T3/T4 auto-engage and skip the gate. */ export interface TriggerCheck { triggered: boolean; trigger: 'T1' | 'T2' | 'T3' | 'T4' | 'T5' | null; reason: string; } export declare const T1_KEYWORDS: string[]; export declare const T2_MIN_SLICES = 30; export declare const T2_MIN_WALL_HOURS = 6; export declare const T3_MIN_MONOTONIC_GUARDS = 3; export declare const T3_MIN_REMAINING_SLICES = 10; export declare const T4_SESSION_GAP_HOURS = 4; export declare const T5_MIN_ACTIVE_SLICES = 3; export declare function checkTriggers(input: { userMessage: string; sliceListSize: number; estimatedWallHours: number; monotonicGuards: number; remainingSlices: number; sessionGapHours: number; activeSlicesAcrossServices: number; }): TriggerCheck; /** * HANDOFF is reachable via three exit conditions per proposal §1: * - user abort * - all-trigger-resolved * - B3 unresolvable (B3Escalation that the user dismisses) */ export declare const HANDOFF_EXIT_CONDITIONS: readonly ["user_abort", "all_triggers_resolved", "b3_unresolvable"]; export type HandoffExitCondition = (typeof HANDOFF_EXIT_CONDITIONS)[number]; export declare function isHandoffExitCondition(s: string): s is HandoffExitCondition; export declare function isHandoffState(s: State): boolean; /** * the PRESENCE MODE, not the 24h state machine. Returns `'partial'` * when the mode is `24h`, otherwise `'standard'`. This is the CLI-side * default; the explicit `--mode` flag in `peaks code auto-compact` * overrides it. * * `sessionId` is retained in the signature for callers that still pass * it; the resolution itself is project-scoped (the presence lease is * per project + caller). */ export declare function getAutoCompactMode(projectRoot: string, _sessionId?: string): AutoCompactMode;