/**
 * Drift pattern catalog — known anti-patterns opensquid intercepts at
 * the Claude Code PreToolUse hook before the agent commits the action.
 *
 * Each pattern has:
 *  - `id` — stable identifier for the rule
 *  - `trigger` — matcher against tool call input
 *  - `lesson` — short reference to the lesson that owns this rule
 *  - `message` — what the agent sees in stderr when intercepted
 *  - `severity` — "block" (exit 2 stops the call) or "warn" (stderr
 *    only, call proceeds)
 *
 * Patterns are CONSERVATIVE on purpose: we'd rather miss a drift than
 * spam false positives. The catalog grows lesson-by-lesson as new
 * drifts are observed and the user endorses the rule.
 */
export type DriftSeverity = "block" | "warn";
export interface DriftPattern {
    id: string;
    /** Tool name to match. "*" matches any tool; specific names match
     * one exact tool. 0.7.24 / D2: broadened from a fixed union to
     * `string` so MCP tool names like `mcp__plugin_telegram_telegram__reply`
     * can be matched directly. */
    tool: string;
    /** Matcher applied to the relevant tool input field. */
    trigger: DriftTrigger;
    /** Lesson id (in the workflow codex) that owns this rule. */
    lesson: string;
    /** Short, agent-facing explanation surfaced when triggered. */
    message: string;
    severity: DriftSeverity;
}
export type DriftTrigger = {
    kind: "bash_contains";
    needle: string;
    strip_quotes?: boolean;
} | {
    kind: "bash_regex";
    pattern: string;
    strip_quotes?: boolean;
} | {
    kind: "text_regex";
    pattern: string;
    field: string;
};
export declare const DRIFT_PATTERNS: DriftPattern[];
export interface ToolCallInput {
    tool: string;
    input: Record<string, unknown>;
}
export interface DriftHit {
    pattern: DriftPattern;
}
/**
 * Run the catalog against a tool call. Returns every matching pattern;
 * caller decides block-vs-warn based on highest severity.
 */
export declare function findDrifts(call: ToolCallInput): DriftHit[];
/**
 * Strip HEREDOC bodies (`<<DELIM ... DELIM` and variants) from a
 * shell command.
 *
 * Recognizes:
 *   <<EOF ... \nEOF        (unquoted delimiter, expansion-allowing)
 *   <<'EOF' ... \nEOF      (single-quoted, literal body)
 *   <<"EOF" ... \nEOF      (double-quoted, literal body)
 *   <<-EOF ... \nEOF       (tab-stripping mode)
 *   <<-'EOF' ... \nEOF     (combined)
 *
 * Delimiter is any word-char sequence (EOF, END, HERE, MARKER, etc.).
 * Lazy `[\s\S]*?` matches across newlines; `\b` after the backref
 * ensures `EOFX` doesn't close an `<<EOF` block.
 *
 * If a HEREDOC has no closing delimiter (truncated input), regex
 * doesn't match and the body stays intact — fail-open behavior.
 *
 * Exported for direct unit testing.
 */
export declare function stripHeredocBodies(s: string): string;
/**
 * Decide the final exit code + message from a list of hits.
 *
 * - Any "block" hit → exit 2 with all blocking messages
 * - Only "warn" hits → exit 0, print warnings to stderr
 * - No hits → exit 0 silently
 *
 * Emergency bypass: `OPENSQUID_SKIP_DRIFT=1` downgrades every block to
 * an audit-trail warning (exit 0, stderr explains the bypass). Two ways
 * to set it:
 *
 *   1. Parent process env — useful for whole-session bypass (e.g. set
 *      before launching Claude Code).
 *   2. Inline command prefix — e.g. `OPENSQUID_SKIP_DRIFT=1 git push`.
 *      The hook reads the COMMAND STRING from the Bash tool input and
 *      sees the prefix even though the env var never reaches the hook's
 *      own process.env (the hook is a sibling subprocess spawned by
 *      Claude Code, not a child of the would-be Bash subprocess).
 *
 * Matches the shape of the version-gate (`OPENSQUID_SKIP_VERSION_GATE=1`)
 * and workflow-gate (`OPENSQUID_SKIP_WORKFLOW_GATE=1`) bypasses so the
 * operator only has one mental model — except those two only check
 * process.env (their hooks happen before any command runs); drift-
 * patterns additionally checks the command-string prefix so the bypass
 * can be requested per-command from within an existing session.
 */
export declare function decide(hits: DriftHit[], call?: ToolCallInput): {
    exit: 0 | 2;
    stderr: string;
};
//# sourceMappingURL=drift-patterns.d.ts.map