/** * Codex-style auto-approval classifier for the /approval auto mode. * * This is a UX heuristic, not a security boundary. The contract mirrors * Codex's unattended posture: allow-shaped commands (reads, builds, tests, * git reads) approve automatically, danger-shaped commands are REJECTED with * the model informed (it adapts instead of paging the human), and only * genuinely unrecognized shapes fall through to a prompt — which detaches to * a rejection when nobody is watching. Real damage containment still comes * from the sandbox preset and git. */ export type AutoApprovalMode = 'off' | 'auto'; export type ApprovalDecision = 'allow' | 'deny' | 'ask'; export type AutoApprovalRisk = 'low' | 'medium' | 'high'; export interface ClassifiedApproval { decision: ApprovalDecision; risk: AutoApprovalRisk; /** Short stable id for i18n / model feedback. */ reasonKey: string; } /** * Whole-command danger patterns, checked before anything else. A match * auto-rejects. This is a UX heuristic, not a security boundary: obfuscated * or interpreter-wrapped damage still has to be contained by the sandbox. * * Interpreter `-c`/`-e` is NOT here: the table cannot see the payload, so * those shapes ask (AI review) instead of a blanket deny. */ export declare const DANGER_PATTERNS: RegExp[]; /** * Segment-level allow patterns: low-risk, high-frequency reads, builds, and * tests. A command auto-approves only when EVERY segment matches one of these. * `env`/`printenv` stay off this list — process env often holds keys. */ export declare const ALLOW_SEGMENT_PATTERNS: RegExp[]; /** * Split a shell command into segments at &&, ||, ; and | boundaries, * skipping those operators when they sit inside quotes or a here-doc * terminator. Nested quoting is best-effort — the sandbox still owns * real damage containment. */ export declare function segments(command: string): string[]; export declare function touchesSensitivePath(text: string): boolean; /** * Classify one shell command line. Danger anywhere auto-rejects; otherwise * the command auto-approves only when every segment is a recognized low-risk * pattern — unknown shapes ask (and detach to a rejection when unattended). */ export declare function classifyCommand(command: string): ApprovalDecision; /** * Whether a command is an opaque interpreter payload (`bash -c …`, `python -e …`). * * The rule table asks about these instead of denying them (a quoted `rm -rf` * must not match `DANGER_PATTERNS`), and the AI reviewer judges the script it is * shown — so its verdict says nothing about the next invocation of the same * wrapper. The approval cache uses this to refuse to remember them. * @param command - the command string a request carried. * @returns whether the payload, not the command line, decides the risk. */ export declare function isOpaqueInterpreterCommand(command: string): boolean; export declare function classifyCommandDetailed(command: string): ClassifiedApproval; export interface ClassifyApprovalInput { toolName: string; command?: string; args?: string; reason?: string; workspaceCwd?: string; } /** * Classify one approval request. `command` is the decoded shell command when * the pending call is a shell tool. 'deny' auto-rejects (the model reads the * rejection and adapts); 'ask' falls through to the interactive prompt. */ export declare function classifyApproval(toolName: string, command: string | undefined): ApprovalDecision; export declare function classifyApprovalDetailed(input: ClassifyApprovalInput): ClassifiedApproval; /** * Decode the shell command of a streamed tool call from its raw JSON args. * Returns undefined for non-shell tools or unparseable args. */ export declare function commandFromArgs(toolName: string, args: string): string | undefined; /** * Pull a shell command out of an approval-request `reason` when the * classifier never saw the tool-call JSON (sandbox escalation, missing * callId, or a card whose args were not recorded). */ export declare function commandFromApprovalReason(reason: string | undefined): string | undefined; /** * Resolve the command the classifier should see for one approval request. * Prefer the streamed bash/pwsh card, then a command already decoded on the * card, then the request's reason text. */ export declare function commandForApprovalRequest(input: { toolName: string; reason?: string; row?: { name: string; args: string; command?: string; }; }): string | undefined; /** Parse the /approval argument into a mode. */ export declare function parseAutoApprovalMode(raw: string): AutoApprovalMode | undefined; /** True when `/approval ` should print the current mode and counters. */ export declare function isApprovalStatusArg(raw: string): boolean;