735287774f
When the user pressed ESC (or Deny / Abort) on an approval prompt, the TUI correctly told the engine to deny the call. But the model would often retry the same command — same name, same args, same approval fingerprint — and the user would see the dialog again, frustrating in the same way the equivalent yes-yes-yes loop would be. Symmetric to the existing `approval_session_approved` "always approve" cache: add `approval_session_denied: HashSet<String>` populated when the user denies (not when the timeout fired — a timeout might mean the user stepped away rather than refused). Subsequent ApprovalRequired events whose approval_key or tool_name match the cache auto-deny via `engine.deny_tool_call(...)` without re-showing the dialog. Logged via `tool.approval.auto_deny_session` so the audit log captures the silent denial. Closes #360. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>