fix(code): eager managed ripgrep install via dcode tools install (#4199)

`dcode tools install` provisions the managed ripgrep binary; the install
script now sets it up by default (opt out with
`DEEPAGENTS_CODE_RIPGREP_INSTALLER=system` or
`DEEPAGENTS_CODE_OFFLINE=1`).

---

Today the pinned, SHA-256-verified ripgrep binary only lands on first
run (via `managed_tools.ensure_ripgrep`), so a fresh user pays a
one-time download the first time they launch. This makes the install
script provision it eagerly so `rg` is ready immediately, without
reaching for `sudo` package managers by default.

Rather than re-encoding the pinned version + checksum table in bash
(drift risk), a new `dcode tools install` verb reuses the existing
managed-install code, and `scripts/install.sh` invokes the freshly
installed binary. The verb is also handy on its own to repair a missing
or stale `rg`.

Power users can keep their own toolchain with
`DEEPAGENTS_CODE_RIPGREP_INSTALLER=system`, which preserves the existing
brew/apt/cargo path in the install script and skips the managed download
at runtime. A system `rg` already on `PATH` is reused under either
setting, and `DEEPAGENTS_CODE_OFFLINE` / `DEEPAGENTS_CODE_SKIP_OPTIONAL`
continue to apply. The default eager install is announced and honors
those opt-outs, per the package's "default shell-outs must announce +
offer a documented opt-out" rule.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
Mason Daugherty
2026-06-25 01:28:38 -04:00
committed by GitHub
parent 37c5fa23e6
commit cf536f3399
17 changed files with 889 additions and 23 deletions
+4 -4
View File
@@ -411,10 +411,10 @@
#### T11: Auto-Installed ripgrep Binary from Upstream Release
- **Flow**: First-run download performed by `managed_tools.ensure_ripgrep` when `rg` is not on `PATH`.
- **Description**: On first invocation without a system `rg`, Deep Agents Code fetches the pinned ripgrep release tarball from `github.com/BurntSushi/ripgrep/releases/...`, verifies it against an in-tree SHA-256 (`RIPGREP_ASSETS`), extracts it under a `TemporaryDirectory`, and atomically moves the binary into `~/.deepagents/bin/rg`. The binary then runs unsandboxed, inheriting the same trust as a user-installed `rg` (the SDK invokes it via `subprocess.run(["rg", ...])`).
- **Mitigations**: (1) SHA-256 verified against the pinned hash table before move — a mismatch aborts the install and leaves `BIN_DIR` clean. (2) Network egress is limited to `github.com`. (3) Opt-out via `DEEPAGENTS_CODE_OFFLINE` for air-gapped environments. (4) Pinned version + checksums are bumped in-tree, so a compromised upstream release is detected on the next Deep Agents Code release rather than silently propagating. (5) Atomic move-into-place avoids partial installs when concurrent CLI invocations race.
- **Preconditions**: User has not installed `rg` via their package manager, `DEEPAGENTS_CODE_OFFLINE` is unset, and the host can reach `github.com`. The pinned SHA-256 in `RIPGREP_ASSETS` would need to be incorrect (a supply-chain compromise of the deepagents-code release) for a tampered binary to be installed.
- **Flow**: Download performed by `managed_tools.ensure_ripgrep` when `rg` is not on `PATH` — either on first run, or eagerly at install time via `dcode tools install` (invoked by `scripts/install.sh`).
- **Description**: Without a system `rg`, Deep Agents Code fetches the pinned ripgrep release tarball from `github.com/BurntSushi/ripgrep/releases/...`, verifies it against an in-tree SHA-256 (`RIPGREP_ASSETS`), extracts it under a `TemporaryDirectory`, and atomically moves the binary into `~/.deepagents/bin/rg`. The binary then runs unsandboxed, inheriting the same trust as a user-installed `rg` (the SDK invokes it via `subprocess.run(["rg", ...])`). The same verified path backs the `dcode tools install` verb, so the install script reuses it rather than re-encoding the version + checksum table in bash.
- **Mitigations**: (1) SHA-256 verified against the pinned hash table before move — a mismatch aborts the install and leaves `BIN_DIR` clean. (2) Network egress is limited to `github.com`. (3) Opt-out via `DEEPAGENTS_CODE_OFFLINE` for air-gapped environments, or `DEEPAGENTS_CODE_RIPGREP_INSTALLER=system` to defer to the OS package manager instead of the managed binary. (4) Pinned version + checksums are bumped in-tree, so a compromised upstream release is detected on the next Deep Agents Code release rather than silently propagating. (5) Atomic move-into-place avoids partial installs when concurrent CLI invocations race. (6) The eager install-script path is non-`sudo` (no system package manager is invoked in the default `managed` mode).
- **Preconditions**: User has not installed `rg` via their package manager, `DEEPAGENTS_CODE_OFFLINE` is unset, `DEEPAGENTS_CODE_RIPGREP_INSTALLER` is not `system`, and the host can reach `github.com`. The pinned SHA-256 in `RIPGREP_ASSETS` would need to be incorrect (a supply-chain compromise of the deepagents-code release) for a tampered binary to be installed.
---
+10
View File
@@ -177,6 +177,16 @@ version), skips auto-updating to break out of an otherwise endless
upgrade/restart loop. Set and read internally across `os.execv`.
"""
RIPGREP_INSTALLER = "DEEPAGENTS_CODE_RIPGREP_INSTALLER"
"""Select how ripgrep is provisioned: `managed` (default) or `system`.
`managed` downloads the pinned, SHA-256-verified upstream binary into
`~/.deepagents/bin` (no sudo). `system` skips that download so power users can
rely on their distro package / existing toolchain instead; the install script's
`system` mode keeps the brew/apt/cargo path. A system `rg` already on `PATH` is
reused under either setting. Unrecognized values fall back to `managed`. See
`managed_tools.ripgrep_installer`."""
SERVER_ENV_PREFIX = "DEEPAGENTS_CODE_SERVER_"
"""Environment variable prefix used to pass CLI config to the server subprocess."""
+7 -4
View File
@@ -2796,9 +2796,10 @@ class DeepAgentsApp(App):
`_ripgrep_ensured` instead of installing again.
Returns:
`True` when a usable managed `rg` is on `PATH`, `False` when the
install was skipped or failed (caller should surface the missing
tool and fall back to the slow path).
`True` when a usable `rg` is resolved the managed binary (with
`BIN_DIR` prepended to `PATH`) or a system `rg` already on `PATH`
`False` when the install was skipped or failed (caller should
surface the missing tool and fall back to the slow path).
"""
async with self._ripgrep_ensure_lock:
if self._ripgrep_ensured.is_set():
@@ -2809,6 +2810,7 @@ class DeepAgentsApp(App):
from deepagents_code.managed_tools import (
ChecksumMismatchError,
ensure_ripgrep,
managed_rg_path,
prepend_managed_bin_to_path,
)
except ImportError:
@@ -2855,7 +2857,8 @@ class DeepAgentsApp(App):
)
if installed is not None:
prepend_managed_bin_to_path()
if installed == managed_rg_path():
prepend_managed_bin_to_path()
self._ripgrep_ensured.set()
return True
@@ -1071,6 +1071,14 @@ _STATIC_OPTIONS: tuple[ConfigOption, ...] = (
default=False,
env_var=_env_vars.OFFLINE,
),
ConfigOption(
key="runtime.ripgrep_installer",
group="Runtime",
summary="Select ripgrep provisioning mode ('managed' or 'system').",
kind=OptionKind.STR,
default="managed",
env_var=_env_vars.RIPGREP_INSTALLER,
),
# --- Debug / Development -------------------------------------------
ConfigOption(
key="debug.enabled",
+31 -5
View File
@@ -695,12 +695,14 @@ def _auto_install_ripgrep_cli(
missing_tools: Tool names reported missing by `check_optional_tools`.
Returns:
`missing_tools` with `"ripgrep"` removed once a usable managed binary
is on `PATH`, otherwise the list unchanged.
`missing_tools` with `"ripgrep"` removed once a usable `rg` is
resolved — the managed binary (with `BIN_DIR` prepended to `PATH`) or a
system `rg` already on `PATH` — otherwise the list unchanged.
"""
from deepagents_code.managed_tools import (
ChecksumMismatchError,
ensure_ripgrep,
managed_rg_path,
prepend_managed_bin_to_path,
)
@@ -727,7 +729,8 @@ def _auto_install_ripgrep_cli(
if installed is None:
return missing_tools
prepend_managed_bin_to_path()
if installed == managed_rg_path():
prepend_managed_bin_to_path()
return [tool for tool in missing_tools if tool != "ripgrep"]
@@ -910,6 +913,7 @@ _HELP_SPECS: dict[str, tuple[str | None, str]] = {
"mcp": ("mcp_command", "show_mcp_help"),
"config": ("config_command", "show_config_help"),
"auth": ("auth_command", "show_auth_help"),
"tools": ("tools_command", "show_tools_help"),
}
"""Maps top-level command names to their startup-fast-path help dispatch.
@@ -933,8 +937,8 @@ def _show_bare_command_group_help(args: argparse.Namespace) -> bool:
Short-circuits before `console`/`settings` are imported so help-only
invocations stay snappy. Mirrors the dispatch in `cli_main` for the
`help`, `agents`, `skills`, `threads`, `mcp`, `config`, and `auth` commands
when no subcommand was given.
`help`, `agents`, `skills`, `threads`, `mcp`, `config`, `auth`, and `tools`
commands when no subcommand was given.
Args:
args: Namespace from `parse_args()`. Only `command` and the per-group
@@ -1212,6 +1216,23 @@ def parse_args() -> argparse.Namespace:
)
add_json_output_arg(doctor_parser)
tools_parser = subparsers.add_parser(
"tools",
help="Manage managed external tools (e.g. ripgrep)",
add_help=False,
parents=help_parent(_lazy_help("show_tools_help")),
)
add_json_output_arg(tools_parser)
tools_sub = tools_parser.add_subparsers(dest="tools_command")
tools_install = tools_sub.add_parser(
"install",
help="Install or repair the managed ripgrep binary",
add_help=False,
parents=help_parent(_lazy_help("show_tools_install_help")),
)
add_json_output_arg(tools_install)
# Default interactive mode — argument order here determines the
# usage line printed by argparse; keep in sync with ui.show_help().
parser.add_argument(
@@ -2293,6 +2314,11 @@ def cli_main() -> None:
sys.exit(run_doctor_command(args))
if command == "tools":
from deepagents_code.tools_commands import run_tools_command
sys.exit(run_tools_command(args))
# Best-effort, idempotent migration. Placed after parse_args and the
# bare-help fast path so --help / --version / `deepagents <group>`
# exit before any I/O. Wrapped broadly so an unexpected non-OSError
+77 -6
View File
@@ -15,9 +15,9 @@ import logging
import os
import sys
from pathlib import Path
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Literal
from deepagents_code._env_vars import OFFLINE, is_env_truthy
from deepagents_code._env_vars import OFFLINE, RIPGREP_INSTALLER, is_env_truthy
if TYPE_CHECKING:
import tarfile
@@ -110,6 +110,49 @@ def is_offline() -> bool:
return is_env_truthy(OFFLINE)
RipgrepInstaller = Literal["managed", "system"]
"""The two recognized ripgrep installer modes."""
INSTALLER_MANAGED: RipgrepInstaller = "managed"
"""Default installer mode: fetch the pinned, checksummed upstream binary."""
INSTALLER_SYSTEM: RipgrepInstaller = "system"
"""Installer mode that defers ripgrep to the system package manager / `PATH`."""
def ripgrep_installer() -> RipgrepInstaller:
"""Return the configured ripgrep installer mode.
Reads `RIPGREP_INSTALLER` and normalizes it to `INSTALLER_MANAGED` or
`INSTALLER_SYSTEM`, falling back to `INSTALLER_MANAGED` for unset or
unrecognized values. The `strip().lower()` normalization must stay in
sync with the `case` block in `scripts/install.sh` so both layers agree
on the parsed mode.
"""
raw = os.environ.get(RIPGREP_INSTALLER, "").strip().lower()
if raw == INSTALLER_SYSTEM:
return INSTALLER_SYSTEM
if raw and raw != INSTALLER_MANAGED:
logger.warning(
"Unrecognized %s=%r; expected %r or %r. Defaulting to %r.",
RIPGREP_INSTALLER,
raw,
INSTALLER_MANAGED,
INSTALLER_SYSTEM,
INSTALLER_MANAGED,
)
return INSTALLER_MANAGED
def prefers_system_ripgrep() -> bool:
"""Return whether the user opted into the `system` ripgrep installer.
In `system` mode ripgrep is provisioned by the OS package manager or an
existing `PATH` entry rather than the managed download.
"""
return ripgrep_installer() == INSTALLER_SYSTEM
def prepend_managed_bin_to_path() -> None:
"""Idempotently prepend `BIN_DIR` to `os.environ["PATH"]`.
@@ -126,6 +169,21 @@ def prepend_managed_bin_to_path() -> None:
os.environ["PATH"] = os.pathsep.join(parts)
def _path_without_managed_bin() -> str | None:
"""Return `PATH` with `BIN_DIR` removed."""
current = os.environ.get("PATH")
if not current:
return None
managed_dir = BIN_DIR.resolve()
parts = [
part
for part in current.split(os.pathsep)
if not part or Path(part).resolve() != managed_dir
]
return os.pathsep.join(parts)
def _managed_binary_is_current(binary: Path) -> bool:
"""Return whether the on-disk managed `rg` matches `RIPGREP_VERSION`.
@@ -369,17 +427,19 @@ async def ensure_ripgrep() -> Path | None:
Resolution order:
1. If a managed `rg` exists *and* matches `RIPGREP_VERSION`, return it.
2. Otherwise, if a system `rg` is on `PATH` and no managed binary
1. If the `system` installer is selected, return a non-managed `rg`
found on `PATH`, or `None` when only the managed binary is present.
2. If a managed `rg` exists *and* matches `RIPGREP_VERSION`, return it.
3. Otherwise, if a system `rg` is on `PATH` and no managed binary
exists, return its resolved path. This is gated on the *absence*
of a managed binary: once a managed `rg` exists, the pinned
version always wins, so a stale managed binary is re-fetched
rather than deferring to a system `rg` and the resolved version
stays deterministic.
3. If offline, on an unsupported platform, or no asset matches the
4. If offline, on an unsupported platform, or no asset matches the
platform/arch, return `None` so callers fall back to the existing
notification + slow path.
4. Otherwise download → SHA-256 verify → extract → install →
5. Otherwise download → SHA-256 verify → extract → install →
prepend `BIN_DIR` to `PATH` → return the installed path. On a
checksum mismatch, raises `ChecksumMismatchError` so callers can
surface a loud notice; other failures log and return `None`.
@@ -402,6 +462,17 @@ async def ensure_ripgrep() -> Path | None:
managed = managed_rg_path()
managed_exists = managed.exists()
if prefers_system_ripgrep():
system_rg = shutil.which("rg", path=_path_without_managed_bin())
if system_rg is not None:
return Path(system_rg)
logger.debug(
"Skipping managed ripgrep download: %s=%s",
RIPGREP_INSTALLER,
INSTALLER_SYSTEM,
)
return None
if managed_exists and _managed_binary_is_current(managed):
return managed
+191
View File
@@ -0,0 +1,191 @@
"""The `dcode tools` command group: provision managed external tools.
Currently this exposes `dcode tools install`, which fetches the pinned,
SHA-256-verified ripgrep binary into `~/.deepagents/bin` (the same managed
path used on first run) and is also handy for repairing a missing or stale
`rg`. The install script calls this verb instead of re-encoding the pinned
version + checksum table in bash.
Help rendering for `dcode tools -h` / `dcode tools install -h` is served by
`ui.show_tools_help` / `ui.show_tools_install_help`, which do not import this
module, so the help path stays light.
"""
from __future__ import annotations
import asyncio
import logging
from typing import TYPE_CHECKING, Literal
from deepagents_code.output import write_json
if TYPE_CHECKING:
import argparse
from deepagents_code.output import OutputFormat
logger = logging.getLogger(__name__)
InstallStatus = Literal["ok", "skipped", "error"]
"""Stable machine token for the `tools install` outcome, surfaced via `--json`.
`ok` (installed or already current), `skipped` (intentional opt-out), and
`error` (an install was expected but failed). Only `error` is unhealthy, so it
alone drives a non-zero exit code."""
def run_tools_command(args: argparse.Namespace) -> int:
"""Dispatch a `dcode tools` subcommand.
Args:
args: Parsed CLI namespace.
Returns:
Process exit code.
"""
subcommand = getattr(args, "tools_command", None)
if subcommand == "install":
return _run_tools_install(args)
# `cli_main`'s bare-group help fast path handles `dcode tools` with no
# subcommand, so this is only reached for an unexpected value.
from deepagents_code import ui
ui.show_tools_help()
return 0
def _run_tools_install(args: argparse.Namespace) -> int:
"""Install or repair the managed ripgrep binary.
Honors the same opt-outs as first-run startup (`DEEPAGENTS_CODE_OFFLINE`
and `DEEPAGENTS_CODE_RIPGREP_INSTALLER=system`) so behavior stays
consistent across entry points.
Args:
args: Parsed CLI namespace. Only `output_format` is read.
Returns:
`0` when a usable `rg` is available (installed, already current, or an
intentional opt-out), `1` when an install was expected but failed.
"""
from deepagents_code.managed_tools import (
RIPGREP_VERSION,
ChecksumMismatchError,
ensure_ripgrep,
is_offline,
managed_rg_path,
prefers_system_ripgrep,
prepend_managed_bin_to_path,
)
output_format: OutputFormat = getattr(args, "output_format", "text")
managed_target = managed_rg_path()
try:
installed = asyncio.run(ensure_ripgrep())
except ChecksumMismatchError:
logger.exception(
"ripgrep install aborted: SHA-256 mismatch on downloaded archive"
)
return _emit_install_result(
output_format,
status="error",
message=(
"ripgrep install aborted: the downloaded archive failed SHA-256 "
"verification. Refusing to install."
),
)
except Exception:
# Backstop for a clean exit instead of a raw traceback.
# `ensure_ripgrep` is defensive internally, but this is the only
# `ensure_ripgrep` caller wired into `scripts/install.sh`, so an
# unexpected escape must degrade to a structured error + exit 1
# (matching the broad backstops in `app.py` / `main.py`) rather than
# dumping a traceback and breaking the `--json` envelope.
logger.warning("ripgrep install failed unexpectedly", exc_info=True)
return _emit_install_result(
output_format,
status="error",
message="ripgrep install failed unexpectedly. See logs for details.",
)
if installed is not None:
if installed == managed_target:
prepend_managed_bin_to_path()
message = f"Managed ripgrep {RIPGREP_VERSION} ready at {installed}"
else:
message = f"Using ripgrep already on PATH at {installed}"
return _emit_install_result(
output_format,
status="ok",
message=message,
path=str(installed),
)
# `ensure_ripgrep` returned `None`: an intentional opt-out is a success
# (nothing to do), while an unexpected failure is reported as an error.
if prefers_system_ripgrep():
return _emit_install_result(
output_format,
status="skipped",
message=(
"Skipped managed ripgrep install: DEEPAGENTS_CODE_RIPGREP_INSTALLER"
"=system. Install ripgrep with your package manager, or unset the "
"variable to use the managed binary."
),
)
if is_offline():
return _emit_install_result(
output_format,
status="skipped",
message=(
"Skipped managed ripgrep install: DEEPAGENTS_CODE_OFFLINE is set. "
"Unset it to download the managed binary."
),
)
return _emit_install_result(
output_format,
status="error",
message=(
"Could not install ripgrep (unsupported platform or download failure). "
"See logs, or install ripgrep manually."
),
)
def _emit_install_result(
output_format: OutputFormat,
*,
status: InstallStatus,
message: str,
path: str | None = None,
) -> int:
"""Print the install outcome as text or JSON and return its exit code.
`ok` is derived from `status` (only `"error"` is unhealthy) so the JSON
envelope and exit code cannot disagree and no illegal `(status, ok)` pair
is representable.
Args:
output_format: `"json"` for machine-readable output, else text.
status: Stable machine token (`"ok"`, `"skipped"`, or `"error"`).
message: Human-readable summary line.
path: Resolved `rg` path when one is available.
Returns:
`0` for `"ok"`/`"skipped"`, `1` for `"error"`.
"""
ok = status != "error"
if output_format == "json":
payload: dict[str, object] = {"status": status, "ok": ok, "message": message}
if path is not None:
payload["path"] = path
write_json("tools install", payload)
else:
from deepagents_code.config import console
style = "green" if ok else "bold red"
console.print(message, style=style, markup=False)
return 0 if ok else 1
+55
View File
@@ -116,6 +116,9 @@ def show_help() -> None:
console.print(
" dcode doctor Print install diagnostics"
)
console.print(
" dcode tools <install> Manage managed tools (ripgrep)"
)
console.print()
console.print("[bold]Options:[/bold]", style=theme.PRIMARY)
@@ -491,6 +494,58 @@ def show_doctor_help() -> None:
console.print()
def show_tools_help() -> None:
"""Show help information for the `tools` subcommand."""
console.print()
console.print("[bold]Usage:[/bold]", style=theme.PRIMARY)
console.print(" dcode tools <command> [options]")
console.print()
console.print("[bold]Commands:[/bold]", style=theme.PRIMARY)
console.print(" install Install or repair the managed ripgrep binary")
console.print()
_print_option_section()
console.print()
console.print("[bold]Examples:[/bold]", style=theme.PRIMARY)
console.print(" dcode tools install")
console.print(" dcode tools install --json")
console.print()
def show_tools_install_help() -> None:
"""Show help information for the `tools install` subcommand."""
console.print()
console.print("[bold]Usage:[/bold]", style=theme.PRIMARY)
console.print(" dcode tools install [options]")
console.print()
console.print(
"Download the pinned, SHA-256-verified ripgrep binary into",
)
console.print(
"~/.deepagents/bin (no sudo). Reuses a system `rg` already on PATH and",
)
console.print(
"is also handy for repairing a missing or stale managed binary.",
)
console.print()
_print_option_section()
console.print()
console.print("[bold]Examples:[/bold]", style=theme.PRIMARY)
console.print(" dcode tools install")
console.print(" dcode tools install --json")
console.print()
console.print(
"Opt out with DEEPAGENTS_CODE_OFFLINE=1 or set",
style=theme.MUTED,
highlight=False,
)
console.print(
"DEEPAGENTS_CODE_RIPGREP_INSTALLER=system to use your package manager.",
style=theme.MUTED,
highlight=False,
)
console.print()
def _print_mcp_discovery_paths() -> None:
"""Print the auto-discovered MCP config paths in precedence order."""
from deepagents_code.mcp_tools import MCP_CONFIG_DISCOVERY_PATHS
+37 -1
View File
@@ -55,6 +55,11 @@
# terminal (CI, wrapper scripts) update instead of stalling at the y/n
# prompt.
# DEEPAGENTS_CODE_SKIP_OPTIONAL — set to 1 to skip optional tool checks
# DEEPAGENTS_CODE_RIPGREP_INSTALLER — how to provision ripgrep:
# "managed" (default) eagerly installs the pinned, SHA-256-verified binary
# into ~/.deepagents/bin (no sudo) via `dcode tools install`; "system"
# keeps the interactive package-manager install (brew/apt/cargo/...). Set
# DEEPAGENTS_CODE_OFFLINE=1 to skip the managed download entirely.
# DEEPAGENTS_CODE_SKIP_XCODE_CHECK — set to 1 to bypass the macOS Xcode
# Command Line Tools preflight check
# DEEPAGENTS_CODE_VERBOSE — set to 1 to show uv's raw stderr (timing lines,
@@ -345,6 +350,22 @@ PYTHON_VERSION="${DEEPAGENTS_CODE_PYTHON:-3.13}"
SKIP_OPTIONAL="${DEEPAGENTS_CODE_SKIP_OPTIONAL:-0}"
VERBOSE="${DEEPAGENTS_CODE_VERBOSE:-0}"
ASSUME_YES="${DEEPAGENTS_CODE_YES:-0}"
# How ripgrep gets provisioned: "managed" (default) eagerly fetches the
# pinned, SHA-256-verified binary into ~/.deepagents/bin via `dcode tools
# install`; "system" keeps the interactive package-manager path below. Any
# value other than "system" normalizes to "managed".
#
# Lowercase and strip whitespace first so this matches the `.strip().lower()`
# normalization in managed_tools.ripgrep_installer(). Without this, a value
# like "System" would parse as "managed" here but "system" in dcode, and the
# eager `dcode tools install` would skip silently while this script also
# skipped the package-manager path — leaving ripgrep unprovisioned.
RIPGREP_INSTALLER="$(printf '%s' "${DEEPAGENTS_CODE_RIPGREP_INSTALLER:-managed}" \
| tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')"
case "$RIPGREP_INSTALLER" in
system) RIPGREP_INSTALLER="system" ;;
*) RIPGREP_INSTALLER="managed" ;;
esac
# PyPI JSON endpoint used to discover the latest published release so we can
# tell whether an existing install is out of date before upgrading it.
@@ -939,7 +960,22 @@ ripgrep_manual_hint() {
}
if [ "$SKIP_OPTIONAL" != "1" ]; then
if command -v rg >/dev/null 2>&1; then
if [ "$RIPGREP_INSTALLER" = "managed" ] && [ "$VERIFY_OK" = true ] && [ -n "$DCODE_BIN" ]; then
# Eager, non-prompting managed install through the freshly installed binary
# — the same pinned, SHA-256-verified path dcode uses on first run
# (downloads into ~/.deepagents/bin, no sudo). Doing it here removes the
# first-run download latency. The binary reuses a system `rg` already on
# PATH and honors DEEPAGENTS_CODE_OFFLINE and
# DEEPAGENTS_CODE_RIPGREP_INSTALLER=system, reporting what it did.
echo ""
log_info "Setting up ripgrep (managed; opt out with DEEPAGENTS_CODE_RIPGREP_INSTALLER=system)..."
if "$DCODE_BIN" tools install; then
fix_owner "${HOME}/.deepagents/bin"
else
log_warn "Managed ripgrep setup did not complete; the grep tool will use a slower fallback."
ripgrep_manual_hint
fi
elif command -v rg >/dev/null 2>&1; then
if [ "$VERBOSE" = "1" ]; then
echo ""
log_info "Checking optional tools..."
@@ -569,6 +569,14 @@ class TestHelpScreenDriftExtended:
show_help()
assert "dcode mcp" in buf.getvalue()
def test_show_help_includes_tools_subcommand(self) -> None:
"""show_help should mention the tools subcommand."""
buf = io.StringIO()
test_console = Console(file=buf, highlight=False, width=200)
with patch("deepagents_code.ui.console", test_console):
show_help()
assert "dcode tools" in buf.getvalue()
def test_show_help_includes_stdin(self) -> None:
"""show_help should mention --stdin."""
buf = io.StringIO()
+42
View File
@@ -16720,6 +16720,10 @@ class TestEnsureManagedRipgrep:
return_value=True,
),
patch("deepagents_code.managed_tools.ensure_ripgrep", ensure),
patch(
"deepagents_code.managed_tools.managed_rg_path",
return_value=Path("/managed/rg"),
),
patch(
"deepagents_code.managed_tools.prepend_managed_bin_to_path",
prepend,
@@ -16733,6 +16737,40 @@ class TestEnsureManagedRipgrep:
assert app._ripgrep_ensured.is_set()
assert app._ripgrep_install_failed is False
async def test_system_rg_resolved_without_prepending(self) -> None:
"""A resolved system `rg` must not prepend the managed bin dir.
`ensure_ripgrep` can return a system `rg` (system-installer mode or a
pre-existing binary). Prepending `BIN_DIR` then would pollute the
langgraph subprocess's `PATH` with a managed dir holding no binary, so
the gate must compare against `managed_rg_path()` before prepending.
"""
app = DeepAgentsApp(agent=MagicMock(), thread_id="t")
ensure = AsyncMock(return_value=Path("/usr/bin/rg"))
prepend = MagicMock()
with (
patch(
"deepagents_code.main._should_ensure_managed_ripgrep",
return_value=True,
),
patch("deepagents_code.managed_tools.ensure_ripgrep", ensure),
patch(
"deepagents_code.managed_tools.managed_rg_path",
return_value=Path("/managed/rg"),
),
patch(
"deepagents_code.managed_tools.prepend_managed_bin_to_path",
prepend,
),
):
assert await app._ensure_managed_ripgrep() is True
ensure.assert_awaited_once()
prepend.assert_not_called()
assert app._ripgrep_ensured.is_set()
assert app._ripgrep_install_failed is False
async def test_installs_when_ripgrep_warning_is_suppressed(self) -> None:
"""Suppressed warning state must not skip managed `rg` installation."""
app = DeepAgentsApp(agent=MagicMock(), thread_id="t")
@@ -16750,6 +16788,10 @@ class TestEnsureManagedRipgrep:
return_value=True,
),
patch("deepagents_code.managed_tools.ensure_ripgrep", ensure),
patch(
"deepagents_code.managed_tools.managed_rg_path",
return_value=Path("/managed/rg"),
),
patch(
"deepagents_code.managed_tools.prepend_managed_bin_to_path",
prepend,
@@ -32,13 +32,16 @@ def _write_fake_tools(
installed_version: str | None = "0.0.1",
latest_version: str | None = None,
curl_fails: bool = False,
dcode_verify_fails: bool = False,
) -> tuple[Path, Path, Path]:
"""Stage fake `uv`, `curl`, and (optionally) `dcode` binaries on `PATH`.
`installed_version` controls whether `dcode -v` reports an existing install
(`None` simulates a fresh machine). `latest_version` is the version the
fake `curl` reports from PyPI; `curl_fails` makes that probe error out so
the script's offline fallback can be exercised.
the script's offline fallback can be exercised. `dcode_verify_fails` makes
`dcode -v` exit non-zero (`VERIFY_OK=false`) so the eager managed-ripgrep
guard can be exercised against a present-but-broken binary.
"""
bin_dir = tmp_path / "bin"
home = tmp_path / "home"
@@ -82,11 +85,17 @@ exit 1
if installed_version is not None:
dcode = bin_dir / "dcode"
tools_log = tmp_path / "dcode-tools.txt"
verify_rc = 1 if dcode_verify_fails else 0
dcode.write_text(
f"""#!/usr/bin/env bash
if [ "${{1:-}}" = "-v" ]; then
printf 'deepagents-code {installed_version}\\n'
exit 0
exit {verify_rc}
fi
if [ "${{1:-}}" = "tools" ]; then
printf '%s\\n' "$*" >> {str(tools_log)!r}
exit "${{FAKE_DCODE_TOOLS_RC:-0}}"
fi
exit 0
"""
@@ -102,12 +111,14 @@ def _env(
installed_version: str | None = "0.0.1",
latest_version: str | None = None,
curl_fails: bool = False,
dcode_verify_fails: bool = False,
) -> dict[str, str]:
bin_dir, home, uv = _write_fake_tools(
tmp_path,
installed_version=installed_version,
latest_version=latest_version,
curl_fails=curl_fails,
dcode_verify_fails=dcode_verify_fails,
)
return {
**os.environ,
@@ -127,6 +138,7 @@ def _invoke(
installed_version: str | None = "0.0.1",
latest_version: str | None = None,
curl_fails: bool = False,
dcode_verify_fails: bool = False,
) -> tuple[subprocess.CompletedProcess[str], Path]:
"""Run `install.sh` non-interactively with the fake tools on `PATH`.
@@ -141,6 +153,7 @@ def _invoke(
installed_version=installed_version,
latest_version=latest_version,
curl_fails=curl_fails,
dcode_verify_fails=dcode_verify_fails,
)
proc = subprocess.run(
["bash", str(SCRIPT)],
@@ -1245,3 +1258,80 @@ def test_install_script_no_path_warning_when_dcode_on_path(tmp_path: Path) -> No
assert proc.returncode == 0
combined = proc.stdout + proc.stderr
assert "isn't on your PATH yet" not in combined
def test_install_script_managed_ripgrep_calls_tools_install(tmp_path: Path) -> None:
"""Default (`managed`) mode eagerly runs `dcode tools install`."""
proc, _ = _invoke(
tmp_path,
{"DEEPAGENTS_CODE_SKIP_OPTIONAL": "0"},
installed_version="0.1.0",
latest_version="0.2.0",
)
assert proc.returncode == 0, proc.stderr
tools_log = tmp_path / "dcode-tools.txt"
assert tools_log.exists(), proc.stdout + proc.stderr
assert "tools install" in tools_log.read_text()
def test_install_script_system_ripgrep_skips_tools_install(tmp_path: Path) -> None:
"""`DEEPAGENTS_CODE_RIPGREP_INSTALLER=system` keeps the package-manager path."""
proc, _ = _invoke(
tmp_path,
{
"DEEPAGENTS_CODE_SKIP_OPTIONAL": "0",
"DEEPAGENTS_CODE_RIPGREP_INSTALLER": "system",
},
installed_version="0.1.0",
latest_version="0.2.0",
)
assert proc.returncode == 0, proc.stderr
assert not (tmp_path / "dcode-tools.txt").exists()
def test_install_script_skip_optional_skips_tools_install(tmp_path: Path) -> None:
"""`DEEPAGENTS_CODE_SKIP_OPTIONAL=1` skips the managed install entirely."""
proc, _ = _invoke(
tmp_path,
{"DEEPAGENTS_CODE_SKIP_OPTIONAL": "1"},
installed_version="0.1.0",
latest_version="0.2.0",
)
assert proc.returncode == 0, proc.stderr
assert not (tmp_path / "dcode-tools.txt").exists()
def test_install_script_managed_ripgrep_failure_warns(tmp_path: Path) -> None:
"""A failed `dcode tools install` falls back with a slow-grep warning."""
proc, _ = _invoke(
tmp_path,
{"DEEPAGENTS_CODE_SKIP_OPTIONAL": "0", "FAKE_DCODE_TOOLS_RC": "1"},
installed_version="0.1.0",
latest_version="0.2.0",
)
assert proc.returncode == 0, proc.stderr
assert "slower fallback" in (proc.stdout + proc.stderr)
def test_install_script_skips_managed_install_when_verify_failed(
tmp_path: Path,
) -> None:
"""A present-but-broken `dcode` (`VERIFY_OK=false`) is not run for `tools`.
The eager managed-ripgrep block is gated on `VERIFY_OK = true`, so a binary
that fails its `-v` probe must not be invoked as `dcode tools install`.
"""
proc, _ = _invoke(
tmp_path,
{"DEEPAGENTS_CODE_SKIP_OPTIONAL": "0"},
installed_version="0.1.0",
latest_version="0.2.0",
dcode_verify_fails=True,
)
assert proc.returncode == 0, proc.stderr
assert not (tmp_path / "dcode-tools.txt").exists(), proc.stdout + proc.stderr
+27
View File
@@ -1444,6 +1444,10 @@ class TestAutoInstallRipgrepCli:
"deepagents_code.managed_tools.ensure_ripgrep",
AsyncMock(return_value=Path("/managed/rg")),
),
patch(
"deepagents_code.managed_tools.managed_rg_path",
return_value=Path("/managed/rg"),
),
patch(
"deepagents_code.managed_tools.prepend_managed_bin_to_path",
prepend,
@@ -1454,6 +1458,29 @@ class TestAutoInstallRipgrepCli:
assert result == ["tavily"]
prepend.assert_called_once()
def test_system_rg_drops_ripgrep_without_prepending(self) -> None:
"""A system `rg` is usable without prepending the managed binary dir."""
console = MagicMock()
prepend = MagicMock()
with (
patch(
"deepagents_code.managed_tools.ensure_ripgrep",
AsyncMock(return_value=Path("/usr/bin/rg")),
),
patch(
"deepagents_code.managed_tools.managed_rg_path",
return_value=Path("/managed/rg"),
),
patch(
"deepagents_code.managed_tools.prepend_managed_bin_to_path",
prepend,
),
):
result = _auto_install_ripgrep_cli(console, ["ripgrep", "tavily"])
assert result == ["tavily"]
prepend.assert_not_called()
def test_install_returns_none_keeps_ripgrep(self) -> None:
"""A skipped/failed install leaves `ripgrep` in the missing list."""
console = MagicMock()
@@ -88,6 +88,10 @@ def test_headless_installs_ripgrep_when_warning_is_suppressed() -> None:
return_value=True,
),
patch("deepagents_code.managed_tools.ensure_ripgrep", ensure),
patch(
"deepagents_code.managed_tools.managed_rg_path",
return_value=Path("/managed/rg"),
),
patch("deepagents_code.managed_tools.prepend_managed_bin_to_path", prepend),
patch(
"deepagents_code.non_interactive.run_non_interactive",
@@ -15,7 +15,7 @@ from unittest import mock
import pytest
from deepagents_code import managed_tools
from deepagents_code._env_vars import OFFLINE
from deepagents_code._env_vars import OFFLINE, RIPGREP_INSTALLER
from deepagents_code.managed_tools import ChecksumMismatchError
_EXPECTED_PLATFORM_ARCHS = {
@@ -120,6 +120,155 @@ async def test_ensure_ripgrep_short_circuits_when_offline(
assert await managed_tools.ensure_ripgrep() is None
def test_ripgrep_installer_defaults_to_managed(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv(RIPGREP_INSTALLER, raising=False)
assert managed_tools.ripgrep_installer() == managed_tools.INSTALLER_MANAGED
assert managed_tools.prefers_system_ripgrep() is False
def test_ripgrep_installer_system(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv(RIPGREP_INSTALLER, "System")
assert managed_tools.ripgrep_installer() == managed_tools.INSTALLER_SYSTEM
assert managed_tools.prefers_system_ripgrep() is True
def test_ripgrep_installer_unrecognized_falls_back_to_managed(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv(RIPGREP_INSTALLER, "bogus")
assert managed_tools.ripgrep_installer() == managed_tools.INSTALLER_MANAGED
async def test_ensure_ripgrep_short_circuits_when_system_installer(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
"""`RIPGREP_INSTALLER=system` skips the managed download (no system rg)."""
monkeypatch.delenv(OFFLINE, raising=False)
monkeypatch.setenv(RIPGREP_INSTALLER, "system")
monkeypatch.setattr(managed_tools, "managed_rg_path", lambda: tmp_path / "absent")
def _no_download(_url: str, _dest: Path) -> None:
msg = "_download_to must not be called in system installer mode"
raise AssertionError(msg)
monkeypatch.setattr(managed_tools, "_download_to", _no_download)
with mock.patch("shutil.which", return_value=None):
assert await managed_tools.ensure_ripgrep() is None
async def test_ensure_ripgrep_system_installer_ignores_current_managed(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
bin_dir = tmp_path / "managed-bin"
bin_dir.mkdir()
managed = bin_dir / "rg"
managed.write_bytes(b"current-managed")
monkeypatch.setattr(managed_tools, "BIN_DIR", bin_dir)
monkeypatch.setattr(managed_tools, "managed_rg_path", lambda: managed)
monkeypatch.delenv(OFFLINE, raising=False)
monkeypatch.setenv(RIPGREP_INSTALLER, "system")
monkeypatch.setenv("PATH", str(bin_dir))
with (
mock.patch("shutil.which", return_value=None),
mock.patch.object(
subprocess,
"run",
side_effect=AssertionError("managed rg must not be version-probed"),
),
):
assert await managed_tools.ensure_ripgrep() is None
async def test_ensure_ripgrep_system_installer_uses_non_managed_path_entry(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
bin_dir = tmp_path / "managed-bin"
system_bin = tmp_path / "system-bin"
bin_dir.mkdir()
system_bin.mkdir()
managed = bin_dir / "rg"
system_rg = system_bin / "rg"
managed.write_bytes(b"current-managed")
monkeypatch.setattr(managed_tools, "BIN_DIR", bin_dir)
monkeypatch.setattr(managed_tools, "managed_rg_path", lambda: managed)
monkeypatch.delenv(OFFLINE, raising=False)
monkeypatch.setenv(RIPGREP_INSTALLER, "system")
monkeypatch.setenv("PATH", f"{bin_dir}{os.pathsep}{system_bin}")
def _which(cmd: str, path: str | None = None) -> str | None:
assert cmd == "rg"
assert path == str(system_bin)
return str(system_rg)
with mock.patch("shutil.which", side_effect=_which):
assert await managed_tools.ensure_ripgrep() == system_rg
def test_path_without_managed_bin_returns_none_when_path_unset(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
"""An unset/empty `PATH` yields `None` so `shutil.which` uses its default."""
monkeypatch.setattr(managed_tools, "BIN_DIR", tmp_path / "managed-bin")
monkeypatch.delenv("PATH", raising=False)
assert managed_tools._path_without_managed_bin() is None
def test_path_without_managed_bin_leaves_other_entries(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
"""A `PATH` without the managed dir is returned unchanged."""
bin_dir = tmp_path / "managed-bin"
other = tmp_path / "usr-bin"
monkeypatch.setattr(managed_tools, "BIN_DIR", bin_dir)
monkeypatch.setenv("PATH", str(other))
assert managed_tools._path_without_managed_bin() == str(other)
def test_path_without_managed_bin_removes_managed_entry(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
"""The managed dir is dropped while sibling entries survive."""
bin_dir = tmp_path / "managed-bin"
other = tmp_path / "usr-bin"
monkeypatch.setattr(managed_tools, "BIN_DIR", bin_dir)
monkeypatch.setenv("PATH", f"{bin_dir}{os.pathsep}{other}")
assert managed_tools._path_without_managed_bin() == str(other)
def test_path_without_managed_bin_removes_non_canonical_alias(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
"""An entry that differs textually but `resolve()`s equal is still removed.
Guards the `Path(part).resolve()` comparison against a regression to a
plain string compare, which would miss `.../managed-bin/.` and friends.
"""
bin_dir = tmp_path / "managed-bin"
other = tmp_path / "usr-bin"
alias = f"{bin_dir}{os.sep}."
monkeypatch.setattr(managed_tools, "BIN_DIR", bin_dir)
monkeypatch.setenv("PATH", f"{alias}{os.pathsep}{other}")
assert managed_tools._path_without_managed_bin() == str(other)
def test_path_without_managed_bin_preserves_empty_entries(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
"""Empty `PATH` components are kept verbatim, not resolved to cwd.
Resolving an empty entry would collapse it to the current directory, which
could spuriously match `BIN_DIR`; the `not part` short-circuit avoids that.
"""
bin_dir = tmp_path / "managed-bin"
other = tmp_path / "usr-bin"
monkeypatch.setattr(managed_tools, "BIN_DIR", bin_dir)
monkeypatch.setenv("PATH", f"{bin_dir}{os.pathsep}{os.pathsep}{other}")
assert managed_tools._path_without_managed_bin() == f"{os.pathsep}{other}"
async def test_ensure_ripgrep_short_circuits_on_android(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
@@ -102,6 +102,7 @@ def _read_marker(stderr: str, prefix: str) -> object:
(["mcp"], "dcode mcp <command>"),
(["config"], "dcode config <command>"),
(["auth"], "dcode auth <command>"),
(["tools"], "dcode tools <command>"),
],
)
def test_help_only_commands_skip_runtime_imports(
@@ -166,6 +167,7 @@ def test_auth_credential_resolution_commands_run_settings_bootstrap() -> None:
["mcp", "login", "example.com"],
["config", "show"],
["auth", "list"],
["tools", "install"],
],
)
def test_subcommands_bypass_fast_path(argv: list[str]) -> None:
@@ -0,0 +1,144 @@
"""Tests for the `dcode tools` command group."""
from __future__ import annotations
import argparse
import io
import json
from pathlib import Path
from unittest.mock import patch
from rich.console import Console
from deepagents_code import managed_tools
from deepagents_code._env_vars import OFFLINE, RIPGREP_INSTALLER
from deepagents_code.tools_commands import run_tools_command
def _run_text(args: argparse.Namespace) -> tuple[int, str]:
buf = io.StringIO()
test_console = Console(file=buf, highlight=False, width=200)
with patch("deepagents_code.config.console", test_console):
code = run_tools_command(args)
return code, buf.getvalue()
class TestToolsInstall:
"""Tests for `dcode tools install` dispatch."""
def test_install_success_text(self, tmp_path: Path) -> None:
installed = tmp_path / "[/green]" / "rg"
args = argparse.Namespace(tools_command="install", output_format="text")
with (
patch.object(managed_tools, "ensure_ripgrep", return_value=installed),
patch.object(managed_tools, "prepend_managed_bin_to_path"),
patch.object(managed_tools, "managed_rg_path", return_value=installed),
):
code, output = _run_text(args)
assert code == 0
assert "Managed ripgrep" in output
assert str(installed) in output
def test_install_reuses_system_rg(self, tmp_path: Path) -> None:
system_rg = Path("/usr/bin/rg")
managed = tmp_path / "rg"
args = argparse.Namespace(tools_command="install", output_format="text")
with (
patch.object(managed_tools, "ensure_ripgrep", return_value=system_rg),
patch.object(managed_tools, "prepend_managed_bin_to_path") as prepend,
patch.object(managed_tools, "managed_rg_path", return_value=managed),
):
code, output = _run_text(args)
assert code == 0
assert "already on PATH" in output
prepend.assert_not_called()
def test_install_json_success(self, tmp_path: Path, capsys) -> None:
installed = tmp_path / "rg"
args = argparse.Namespace(tools_command="install", output_format="json")
with (
patch.object(managed_tools, "ensure_ripgrep", return_value=installed),
patch.object(managed_tools, "prepend_managed_bin_to_path"),
patch.object(managed_tools, "managed_rg_path", return_value=installed),
):
code = run_tools_command(args)
assert code == 0
envelope = json.loads(capsys.readouterr().out)
assert envelope["command"] == "tools install"
assert envelope["data"]["status"] == "ok"
assert envelope["data"]["path"] == str(installed)
def test_install_skipped_system_installer(
self, monkeypatch, tmp_path: Path
) -> None:
monkeypatch.setenv(RIPGREP_INSTALLER, "system")
monkeypatch.delenv(OFFLINE, raising=False)
args = argparse.Namespace(tools_command="install", output_format="text")
with (
patch.object(managed_tools, "ensure_ripgrep", return_value=None),
patch.object(managed_tools, "managed_rg_path", return_value=tmp_path / "x"),
):
code, output = _run_text(args)
assert code == 0
assert "system" in output
def test_install_skipped_offline(self, monkeypatch, tmp_path: Path) -> None:
monkeypatch.setenv(OFFLINE, "1")
monkeypatch.delenv(RIPGREP_INSTALLER, raising=False)
args = argparse.Namespace(tools_command="install", output_format="text")
with (
patch.object(managed_tools, "ensure_ripgrep", return_value=None),
patch.object(managed_tools, "managed_rg_path", return_value=tmp_path / "x"),
):
code, output = _run_text(args)
assert code == 0
assert "OFFLINE" in output
def test_install_failure_returns_nonzero(self, monkeypatch, tmp_path: Path) -> None:
monkeypatch.delenv(OFFLINE, raising=False)
monkeypatch.delenv(RIPGREP_INSTALLER, raising=False)
args = argparse.Namespace(tools_command="install", output_format="text")
with (
patch.object(managed_tools, "ensure_ripgrep", return_value=None),
patch.object(managed_tools, "managed_rg_path", return_value=tmp_path / "x"),
):
code, output = _run_text(args)
assert code == 1
assert "Could not install" in output
def test_install_checksum_mismatch_returns_nonzero(self, tmp_path: Path) -> None:
args = argparse.Namespace(tools_command="install", output_format="text")
with (
patch.object(
managed_tools,
"ensure_ripgrep",
side_effect=managed_tools.ChecksumMismatchError("bad"),
),
patch.object(managed_tools, "managed_rg_path", return_value=tmp_path / "x"),
):
code, output = _run_text(args)
assert code == 1
assert "SHA-256" in output
def test_install_unexpected_error_returns_nonzero(self, tmp_path: Path) -> None:
"""An unexpected exception degrades to a clean error, not a traceback."""
args = argparse.Namespace(tools_command="install", output_format="text")
with (
patch.object(
managed_tools,
"ensure_ripgrep",
side_effect=OSError("boom"),
),
patch.object(managed_tools, "managed_rg_path", return_value=tmp_path / "x"),
):
code, output = _run_text(args)
assert code == 1
assert "unexpectedly" in output
assert "boom" not in output # internals stay in the logs, not stdout
def test_no_subcommand_shows_help(self) -> None:
args = argparse.Namespace(tools_command=None)
with patch("deepagents_code.ui.show_tools_help") as show_help:
code = run_tools_command(args)
assert code == 0
show_help.assert_called_once()