feat(approvals): make dangerous command approval timeout configurable (#3886)

* feat(approvals): make dangerous command approval timeout configurable

Read `approvals.timeout` from config.yaml (default 60s) instead of
hardcoding 60 seconds in both the fallback CLI prompt and the TUI
prompt_toolkit callback.

Follows the same pattern as `clarify.timeout` which is already
configurable via CLI_CONFIG.

Closes #3765

* fix: add timeout default to approvals section in DEFAULT_CONFIG

---------

Co-authored-by: acsezen <asezen@icloud.com>
This commit is contained in:
Teknium
2026-03-30 00:02:02 -07:00
committed by GitHub
parent c288bbfb57
commit 947faed3bc
3 changed files with 25 additions and 7 deletions

View File

@@ -241,7 +241,7 @@ def save_permanent_allowlist(patterns: set):
# =========================================================================
def prompt_dangerous_approval(command: str, description: str,
timeout_seconds: int = 60,
timeout_seconds: int | None = None,
allow_permanent: bool = True,
approval_callback=None) -> str:
"""Prompt the user to approve a dangerous command (CLI only).
@@ -256,6 +256,9 @@ def prompt_dangerous_approval(command: str, description: str,
Returns: 'once', 'session', 'always', or 'deny'
"""
if timeout_seconds is None:
timeout_seconds = _get_approval_timeout()
if approval_callback is not None:
try:
return approval_callback(command, description,
@@ -336,15 +339,28 @@ def _normalize_approval_mode(mode) -> str:
return "manual"
def _get_approval_mode() -> str:
"""Read the approval mode from config. Returns 'manual', 'smart', or 'off'."""
def _get_approval_config() -> dict:
"""Read the approvals config block. Returns a dict with 'mode', 'timeout', etc."""
try:
from hermes_cli.config import load_config
config = load_config()
mode = config.get("approvals", {}).get("mode", "manual")
return _normalize_approval_mode(mode)
return config.get("approvals", {}) or {}
except Exception:
return "manual"
return {}
def _get_approval_mode() -> str:
"""Read the approval mode from config. Returns 'manual', 'smart', or 'off'."""
mode = _get_approval_config().get("mode", "manual")
return _normalize_approval_mode(mode)
def _get_approval_timeout() -> int:
"""Read the approval timeout from config. Defaults to 60 seconds."""
try:
return int(_get_approval_config().get("timeout", 60))
except (ValueError, TypeError):
return 60
def _smart_approve(command: str, description: str) -> str: