Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions code_puppy/cli_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,12 +395,17 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
if initial_command:
from code_puppy.command_line.shell_passthrough import (
execute_shell_passthrough,
is_known_cli_command,
is_shell_passthrough,
)

if is_shell_passthrough(initial_command):
execute_shell_passthrough(initial_command)
initial_command = None
elif is_known_cli_command(initial_command):
# Auto-detect known CLI commands — bypass AI agent, zero tokens
execute_shell_passthrough(f"!{initial_command.strip()}")
initial_command = None

# Initialize the runtime agent manager
if initial_command:
Expand Down Expand Up @@ -597,13 +602,20 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
# Shell pass-through: !<command> executes directly, bypassing the agent
from code_puppy.command_line.shell_passthrough import (
execute_shell_passthrough,
is_known_cli_command,
is_shell_passthrough,
)

if is_shell_passthrough(task):
execute_shell_passthrough(task)
continue

# Auto-detect known CLI commands (e.g. `ls`, `git status`, `grep …`)
# and route them directly to the shell — zero tokens consumed.
if is_known_cli_command(task):
execute_shell_passthrough(f"!{task.strip()}")
continue

# Check for exit commands (plain text or command form)
if task.strip().lower() in ["exit", "quit"] or task.strip().lower() in [
"/exit",
Expand Down Expand Up @@ -1014,13 +1026,19 @@ async def execute_single_prompt(prompt: str, message_renderer) -> None:
# Shell pass-through: !<cmd> bypasses the agent even in -p mode
from code_puppy.command_line.shell_passthrough import (
execute_shell_passthrough,
is_known_cli_command,
is_shell_passthrough,
)

if is_shell_passthrough(prompt):
execute_shell_passthrough(prompt)
return

# Auto-detect known CLI commands — bypass AI agent, zero tokens consumed
if is_known_cli_command(prompt):
execute_shell_passthrough(f"!{prompt.strip()}")
return

from code_puppy.messaging import emit_info

emit_info(f"Executing prompt: {prompt}")
Expand Down
250 changes: 250 additions & 0 deletions code_puppy/command_line/shell_passthrough.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@
Prepend a prompt with `!` to execute it as a shell command directly,
bypassing the agent entirely. Inspired by Claude Code's `!` prefix.

Also auto-detects well-known CLI commands (e.g. ``ls``, ``git``, ``grep``)
so users can type them without the ``!`` prefix and still bypass the AI agent
— consuming zero tokens.

Examples:
!ls -la
!git status
!python --version
ls -la ← auto-detected, no tokens used
git status ← auto-detected, no tokens used
ls | grep test ← auto-detected, no tokens used
"""

import os
import re
import shutil
import subprocess
import sys
import time
Expand All @@ -25,6 +34,247 @@
# Banner identifier — matches the key in DEFAULT_BANNER_COLORS
_BANNER_NAME = "shell_passthrough"

# ---------------------------------------------------------------------------
# Auto-detection: known CLI commands that should bypass the AI agent
# ---------------------------------------------------------------------------
# When a user types one of these commands directly (without the ``!`` prefix),
# Code Puppy automatically routes the input to the shell — no tokens consumed.
#
# Extend this set to add more commands. Keep it sorted for readability.
KNOWN_CLI_COMMANDS: frozenset[str] = frozenset(
{
# ── Archives ──────────────────────────────────────────────────────
"bzip2",
"gunzip",
"gzip",
"tar",
"unzip",
"xz",
"zip",
# ── Build / package managers ──────────────────────────────────────
"cargo",
"cmake",
"gradle",
"make",
"maven",
"mvn",
"npm",
"npx",
"pip",
"pip3",
"poetry",
"pnpm",
"yarn",
# ── Containers / orchestration ────────────────────────────────────
"docker",
"docker-compose",
"helm",
"kubectl",
"podman",
# ── File system ───────────────────────────────────────────────────
"cat",
"cd",
"chmod",
"chown",
"cp",
"dir",
"du",
"file",
"find",
"head",
"la",
"less",
"ll",
"ln",
"locate",
"ls",
"mkdir",
"more",
"mv",
"popd",
"pushd",
"pwd",
"rm",
"rmdir",
"tail",
"touch",
"tree",
"wc",
# ── Language runtimes ─────────────────────────────────────────────
"go",
"java",
"javac",
"node",
"python",
"python3",
"ruby",
"rustc",
# ── Misc utilities ────────────────────────────────────────────────
"alias",
"cal",
"date",
"df",
"echo",
"env",
"export",
"free",
"history",
"id",
"info",
"man",
"open",
"pbcopy",
"pbpaste",
"printf",
"type",
"uname",
"unalias",
"uptime",
"which",
"whereis",
"whoami",
"xclip",
"xsel",
# ── Network ───────────────────────────────────────────────────────
"curl",
"dig",
"host",
"ifconfig",
"ip",
"nc",
"netstat",
"nslookup",
"ping",
"rsync",
"scp",
"ssh",
"wget",
# ── Process / system ──────────────────────────────────────────────
"bg",
"fg",
"htop",
"jobs",
"kill",
"killall",
"ps",
"top",
"who",
# ── System package managers ───────────────────────────────────────
"apt",
"apt-get",
"dnf",
"pacman",
"snap",
"systemctl",
"yum",
# ── Text processing ───────────────────────────────────────────────
"awk",
"cut",
"diff",
"egrep",
"fgrep",
"grep",
"jq",
"patch",
"rg",
"ripgrep",
"sed",
"sort",
"tee",
"tr",
"uniq",
"xargs",
# ── Version control ───────────────────────────────────────────────
"git",
"hg",
"svn",
}
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Commands that double as common English words and frequently appear at the
# start of natural-language prompts (e.g. "find memory leak in parser",
# "open the config file", "type the password"). For these we require stronger
# shell intent evidence before auto-routing.
_AMBIGUOUS_CLI_COMMANDS: frozenset[str] = frozenset(
{
"date",
"find",
"history",
"id",
"info",
"man",
"open",
"type",
"which",
"who",
}
)

# Patterns that strongly indicate the user intends a real shell invocation:
# | & ; < > ` $ ( ) — shell operators / substitution
# -flag — a CLI flag (-v, --verbose, -la …)
# ./path ../path /abs/path — explicit filesystem paths
_SHELL_INTENT_RE = re.compile(r"[|&;<>`$()]|(?:^|\s)-\w|(?:^|\s)(\.{1,2}/|/)")

# Pre-compiled regex: first "word" of the input (handles leading whitespace)
_FIRST_WORD_RE = re.compile(r"^\s*(\S+)")


def is_known_cli_command(task: str) -> bool:
"""Return True when *task* starts with a well-known CLI command name **and**
the overall input looks like a real shell invocation rather than natural
language.

Three-stage filter (conservative by design):

1. **Known list** — first token must be in ``KNOWN_CLI_COMMANDS``.
2. **PATH check** — the executable must actually exist on ``$PATH``
(via ``shutil.which``). This rejects invented commands that happen to
share a name with a list entry on this machine.
3. **Ambiguity guard** — for commands that are also common English words
(``find``, ``open``, ``date`` …) the rest of the input must show at
least one strong shell-intent signal: a flag (``-v``), a path
(``./src``), or a shell operator (``|``, ``>``, etc.).

Single-word inputs (``pwd``, ``git``) skip stage 3 — they're unambiguous.

Args:
task: Raw user input string.

Returns:
True if the input should be routed directly to the shell.
"""
stripped = task.strip()

# Already handled by other code paths — skip early.
if stripped.startswith(SHELL_PASSTHROUGH_PREFIX) or stripped.startswith("/"):
return False

match = _FIRST_WORD_RE.match(stripped)
if not match:
return False

first_word = match.group(1).lower()

# Stage 1: must be a known CLI command.
if first_word not in KNOWN_CLI_COMMANDS:
return False

# Stage 2: executable must exist on PATH (prevents false positives on
# machines where the command isn't installed, and catches typos).
if shutil.which(first_word) is None:
return False

# Single-word commands are unambiguous — accept immediately.
if " " not in stripped:
return True

# Stage 3: ambiguous English words require explicit shell-intent evidence.
if first_word in _AMBIGUOUS_CLI_COMMANDS and not _SHELL_INTENT_RE.search(stripped):
return False

return True


def _get_console() -> Console:
"""Get a Rich console for direct output.
Expand Down
Loading