/** * Declare a hook's failure posture. Called at module scope by each hook, so * importing the hook is what makes its posture reachable. * @param {string} hook a member of {@link FAULT_POLICY_HOOKS} * @param {FaultPolicy} policy * @returns {void} */ export function registerFaultPolicy(hook: string, policy: FaultPolicy): void; /** * The registered policy for `hook`. Throws rather than defaulting: a hook whose * posture nobody declared has no defensible default — guessing OPEN would let * the guarded action through on a hook an operator believed was strict, and * guessing CLOSED would block a session on a wiring bug. * @param {string} hook * @returns {FaultPolicy} */ export function faultPolicy(hook: string): FaultPolicy; /** * The default OPEN rendering: no verdict, and a non-empty `additionalContext` * recording that the guarded content passed through unsanitized. Non-empty * matters — an empty stdout is recorded by Claude Code as a CLEAN run rather * than a degraded one, so the posture would give up visibility as well as * enforcement. Exported so a policy that declares its own `open` arm for a * carve-out can still route its non-carve-out path through THIS rendering * instead of restating it — a hand-copied body would silently drift the day * this one changes, which is the per-hook re-derivation this module exists to * end. * @param {FaultContext} ctx * @returns {FaultParts} */ export function defaultOpen(ctx: FaultContext): FaultParts; /** * Resolve `hook`'s response to its own failure under the caller's posture. This * is the ONLY place {@link failOpenEnabled} is consulted on a hook fault, so the * knob cannot be honored in three hooks and skipped in the fourth. * @param {string} hook * @param {unknown} err * @param {Record & { * env?: NodeJS.ProcessEnv | Record, * }} [ctx] hook-specific inputs threaded to the builders (a message table, the * parsed input, a remedy). `env` selects the posture; it is threaded to the * builders along with the rest, though none reads it — the posture is resolved * here precisely so a builder never has to. * @returns {FaultOutcome} */ export function hookFaultOutcome(hook: string, err: unknown, ctx?: Record & { env?: NodeJS.ProcessEnv | Record; }): FaultOutcome; /** * Render an outcome's stdout/stderr halves and return its exit code. The caller * decides what to do with the code (a hook that must keep running ignores it), * and performs `armAlert` itself — persisting the alert needs the hook's own * report text, which this module has no view of. * @param {FaultOutcome} outcome * @param {(chunk: string) => void} [write] * @param {(chunk: string) => void} [writeErr] * @returns {number} */ export function writeFaultOutcome(outcome: FaultOutcome, write?: (chunk: string) => void, writeErr?: (chunk: string) => void): number; /** * The hook modules that must register a fault policy — every CLI entry point in * `claude-hooks/*.mjs`. Declared here rather than discovered so registering an * unknown name is an error instead of a typo nobody notices. * @type {readonly string[]} */ export const FAULT_POLICY_HOOKS: readonly string[]; /** * What a hook's fault renders to. `fields`/`envelope` are the stdout response * (`fields` is the `hookSpecificOutput` body, wrapped with the policy's event; * `envelope` is a hook that answers with a top-level shape instead, like * UserPromptSubmit's `{decision:"block"}`); `stderr` and `exitCode` are the * process-level halves a hook with no stdout channel uses; `armAlert` asks the * caller to persist its cross-hook alert so a LATER gate carries the closed * posture the faulting hook could not express itself. */ export type FaultOutcome = { posture: "open" | "closed"; fields: Record | null; fallbackFields: Record | null; envelope: object | null; stderr: string | null; exitCode: number; armAlert: boolean; }; /** * What a policy's `open`/`closed` builder returns: any subset of a * {@link FaultOutcome}'s renderable slots. Everything omitted takes its default * (no output, exit 0, no alert). */ export type FaultParts = { fields?: Record; fallbackFields?: Record; envelope?: object; stderr?: string; exitCode?: number; armAlert?: boolean; }; /** * The context a builder is handed: the caller's own inputs (whatever it passed * to {@link hookFaultOutcome}) plus the three values every hook derived by hand * before — the hook name, the scrubbed error message, and the model-facing * open-posture warning. */ export type FaultContext = Record & { hook: string; err: unknown; message: string; openContext: string; }; /** * A hook's declared posture. */ export type FaultPolicy = { event: string | null; guarded: string; open?: (ctx: FaultContext) => FaultParts; closed: (ctx: FaultContext) => FaultParts; };