# TUI — Shell Danger Detection

The shell safety subsystem detects dangerous command patterns before execution
in the TUI shell mode (`!` prefix). When a dangerous pattern is matched, the
TUI surfaces a warning overlay so the user can confirm or abort before the
command runs.

Introduced in the [Unreleased] milestone (issue #1003).
See also [`tui.md`](tui.md) for the overall TUI architecture.

**Module**: `cleveragents.tui.shell_safety`

---

## Overview

When the user types a shell command in the TUI (prefixed with `!`), the
`DangerousPatternDetector` scans the command against a configurable registry
of patterns before execution. If any patterns match, a warning is displayed
with the danger level and a description of the risk.

```
┌─────────────────────────────────────────────────────────────────┐
│  ⚠  Dangerous command detected                                  │
│                                                                 │
│  [Critical] rm -rf / recursively deletes the entire filesystem  │
│  root. This will destroy the operating system and all data.     │
│                                                                 │
│  Command: rm -rf /                                              │
│                                                                 │
│  [c] Cancel  [p] Proceed anyway                                 │
└─────────────────────────────────────────────────────────────────┘
```

---

## Domain Models

### `ShellDangerLevel`

**Module**: `cleveragents.tui.shell_safety.danger_level`

`IntEnum` classifying the severity of a dangerous shell command. Levels are
ordered so that numeric comparisons work naturally
(`level >= ShellDangerLevel.HIGH`).

| Value | Int | Description |
|-------|-----|-------------|
| `LOW` | 1 | Minor risk — generally recoverable side-effects (e.g. `chmod 777` on a single file) |
| `MEDIUM` | 2 | Moderate risk — can cause data loss or security exposure in common scenarios |
| `HIGH` | 3 | High risk — significant, hard-to-reverse damage (e.g. `dd if=`, `mkfs`) |
| `CRITICAL` | 4 | Critical risk — can destroy the entire system or create a fork bomb |

### `DangerousPattern`

**Module**: `cleveragents.tui.shell_safety.dangerous_pattern`

Immutable frozen dataclass describing a single dangerous shell pattern.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | `str` | — | Short human-readable identifier (e.g. `"rm_rf_root"`) |
| `pattern` | `str` | — | Regular expression matching the dangerous command text |
| `level` | `ShellDangerLevel` | — | Danger severity classification |
| `description` | `str` | — | Human-readable explanation of the risk |
| `case_sensitive` | `bool` | `False` | When `True`, the regex is compiled without `re.IGNORECASE` |

**Methods:**

| Method | Returns | Description |
|--------|---------|-------------|
| `matches(command)` | `bool` | `True` if `command` matches this pattern |

### `DangerousCommandWarning`

**Module**: `cleveragents.tui.shell_safety.warning`

Immutable frozen dataclass produced by `DangerousPatternDetector` when a
dangerous command is detected.

| Field | Type | Description |
|-------|------|-------------|
| `command` | `str` | The original command string that triggered the warning |
| `matched_pattern` | `DangerousPattern` | The pattern that matched |
| `danger_level` | `ShellDangerLevel` | Convenience alias for `matched_pattern.level` |
| `message` | `str` | Human-readable warning message for display |

**Class methods:**

| Method | Returns | Description |
|--------|---------|-------------|
| `from_pattern(command, pattern)` | `DangerousCommandWarning` | Construct a warning from a command and the matching pattern |

---

## `DangerousPatternDetector`

**Module**: `cleveragents.tui.shell_safety.pattern_detector`

Domain service that checks shell commands against a configurable registry of
dangerous patterns. Ships with built-in `DEFAULT_PATTERNS` but supports full
customisation.

### Constructor

```python
DangerousPatternDetector(patterns: list[DangerousPattern] | None = None)
```

When `patterns` is `None`, the built-in `DEFAULT_PATTERNS` are used.

### Registry Management

| Method | Returns | Description |
|--------|---------|-------------|
| `add_pattern(pattern)` | `None` | Append a pattern to the registry (checked in insertion order) |
| `remove_pattern(name)` | `bool` | Remove the pattern with the given name; returns `True` if removed |
| `replace_patterns(patterns)` | `None` | Replace the entire registry with a new list |
| `patterns` *(property)* | `tuple[DangerousPattern, ...]` | Read-only view of the current registry |

### Detection

| Method | Returns | Description |
|--------|---------|-------------|
| `check(command)` | `list[DangerousCommandWarning]` | All warnings for `command` (may be empty); ordered by insertion order |
| `check_first(command)` | `DangerousCommandWarning \| None` | First (highest-priority) warning, or `None` |
| `is_dangerous(command)` | `bool` | `True` if `command` matches any registered pattern |
| `max_danger_level(command)` | `ShellDangerLevel \| None` | Highest danger level matched, or `None` |

---

## Default Pattern Registry

**Module**: `cleveragents.tui.shell_safety.pattern_registry`

The `DEFAULT_PATTERNS` tuple ships with the following built-in patterns:

### Critical

| Name | Pattern | Description |
|------|---------|-------------|
| `rm_rf_root` | `rm -rf /` | Recursively deletes the entire filesystem root |
| `rm_rf_wildcard` | `rm -rf /*` or `rm -rf *` | Deletes large portions of the filesystem |
| `fork_bomb` | `:(){ :|:& };:` | Exhausts the process table, requiring a hard reboot |

### High

| Name | Pattern | Description |
|------|---------|-------------|
| `dd_if_device` | `dd if=` | Can overwrite disk devices or fill storage |
| `mkfs` | `mkfs` | Formats a filesystem, permanently erasing all data |
| `shred_device` | `shred /dev/` or `shred --remove` | Overwrites data in an unrecoverable way |

### Medium

| Name | Pattern | Description |
|------|---------|-------------|
| `chmod_777` | `chmod 777` | Grants world-readable/writable/executable permissions |
| `sudo_rm` | `sudo rm` | Runs `rm` with elevated privileges |
| `wget_pipe_sh` | `wget … \| sh` | Executes arbitrary remote code without inspection |
| `curl_pipe_sh` | `curl … \| sh` | Executes arbitrary remote code without inspection |
| `wget_pipe_bash` | `wget … \| bash` | Executes arbitrary remote code without inspection |
| `curl_pipe_bash` | `curl … \| bash` | Executes arbitrary remote code without inspection |

### Low

| Name | Pattern | Description |
|------|---------|-------------|
| `git_push_force` | `git push --force` | Overwrites remote history, causing data loss for collaborators |
| `chmod_recursive_permissive` | `chmod -R 6xx/7xx` | Exposes sensitive files to unintended access |

---

## Usage Examples

### Basic detection

```python
from cleveragents.tui.shell_safety.pattern_detector import DangerousPatternDetector

detector = DangerousPatternDetector()

# Check a command
warnings = detector.check("rm -rf /")
if warnings:
    print(warnings[0].message)
    # [Critical] Dangerous command detected: rm -rf / recursively deletes ...

# Quick boolean check
if detector.is_dangerous("sudo rm -rf /var/log"):
    print("Dangerous!")

# Highest danger level
level = detector.max_danger_level("wget http://example.com/script.sh | bash")
print(level)  # ShellDangerLevel.MEDIUM
```

### Custom patterns

```python
from cleveragents.tui.shell_safety.danger_level import ShellDangerLevel
from cleveragents.tui.shell_safety.dangerous_pattern import DangerousPattern
from cleveragents.tui.shell_safety.pattern_detector import DangerousPatternDetector

detector = DangerousPatternDetector()

# Add a custom pattern
detector.add_pattern(
    DangerousPattern(
        name="drop_database",
        pattern=r"\bDROP\s+DATABASE\b",
        level=ShellDangerLevel.CRITICAL,
        description="DROP DATABASE permanently deletes the entire database.",
        case_sensitive=False,
    )
)

# Remove a built-in pattern
detector.remove_pattern("git_push_force")
```

---

## Integration with Shell Mode

The `DangerousPatternDetector` is invoked by the TUI shell mode handler
(`cleveragents.tui.input.shell_exec`) before any subprocess is started.
If `check_first()` returns a warning, the TUI presents a confirmation
overlay before proceeding.

The shell mode is entered by typing `!` at the prompt. See
[Shell Mode](tui.md#shell-mode) in the TUI reference for the full
shell mode documentation.

---

## Related Documentation

- [TUI Reference](tui.md) — overall TUI architecture and shell mode
- [TUI Permissions Screen](tui_permissions.md) — full-screen permission overlay
- [TUI Permission Question Widget](tui_permission_question.md) — inline permission widget
