import type { CommandConfirmation } from "./agent-loop.js"; import type { AppConfig } from "../config.js"; import type { ExecInput } from "./sandbox/interface.js"; import type { ApplyPatchCommand, ApprovalPolicy } from "../../approvals.js"; import type { ResponseInputItem } from "openai/resources/responses/responses.mjs"; import { exec, execApplyPatch } from "./exec.js"; import { ReviewDecision } from "./review.js"; import { FullAutoErrorMode } from "../auto-approval-mode.js"; import { SandboxType } from "./sandbox/interface.js"; import { canAutoApprove } from "../../approvals.js"; import { formatCommandForDisplay } from "../../format-command.js"; import { isLoggingEnabled, log } from "../logger/log.js"; import { access } from "fs/promises"; // --------------------------------------------------------------------------- // Session‑level cache of commands that the user has chosen to always approve. // // The values are derived via `deriveCommandKey()` which intentionally ignores // volatile arguments (for example the patch text passed to `apply_patch`). // Storing *generalised* keys means that once a user selects "always approve" // for a given class of command we will genuinely stop prompting them for // subsequent, equivalent invocations during the same CLI session. // --------------------------------------------------------------------------- const alwaysApprovedCommands = new Set(); // --------------------------------------------------------------------------- // Helper: Given the argv-style representation of a command, return a stable // string key that can be used for equality checks. // // The key space purposefully abstracts away parts of the command line that // are expected to change between invocations while still retaining enough // information to differentiate *meaningfully distinct* operations. See the // extensive inline documentation for details. // --------------------------------------------------------------------------- function deriveCommandKey(cmd: Array): string { // pull off only the bits you care about const [ maybeShell, maybeFlag, coreInvocation, /* …ignore the rest… */ ] = cmd; if (coreInvocation?.startsWith("apply_patch")) { return "apply_patch"; } if (maybeShell === "bash" && maybeFlag === "-lc") { // If the command was invoked through `bash -lc "