mirror of
https://github.com/langchain-ai/deepagents.git
synced 2026-07-21 17:25:26 -04:00
81797312c7
Add a `dcode doctor` command that prints install diagnostics (versions, platform, update status, config locations), with `--json` support. --- Adds a `dcode doctor` subcommand to `deepagents-code`, inspired by `claude doctor`. It prints a grouped, tree-style summary of the install (versions, platform, install method, path), update status, and on-disk config locations, with a `--json` mode for machine-readable output. It deliberately runs offline — the update section reads only the local cache via `get_cached_update_available` and never contacts PyPI — and reuses existing helpers (`detect_install_method`, `is_auto_update_enabled`, editable-install detection, config paths) so the output stays consistent with `dcode --version` and `dcode update`. All rendered values go through `rich.markup.escape` with `highlight=False`. The new command is a leaf subcommand (like `update`), so it is intentionally not registered in `_HELP_SPECS`. `ui.show_doctor_help` backs `dcode doctor -h`, and the command is listed in the top-level help usage. Made by [Open SWE](https://openswe.vercel.app/agents/74c251d7-548f-ee57-6e48-c76e1bd66a1a) --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
"""Filesystem-path classification shared by the diagnostic CLI commands.
|
|
|
|
`dcode doctor` and `dcode config path` both probe whether config locations
|
|
exist. `Path.exists()` can report `False` for `OSError` cases such as EACCES
|
|
when a parent directory denies traversal, so a bare `.exists()` can hide the
|
|
very permissions problem these commands should diagnose. `classify_path`
|
|
centralizes the guard and reports an unreadable path as a distinct state instead
|
|
of conflating it with "missing".
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import errno
|
|
import logging
|
|
from enum import StrEnum
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_MISSING_ERRNOS = {errno.ENOENT, errno.ENOTDIR}
|
|
|
|
|
|
class PathState(StrEnum):
|
|
"""Whether a probed path exists, is absent, or could not be read.
|
|
|
|
A `StrEnum` so the value serializes directly to JSON without a custom
|
|
encoder.
|
|
"""
|
|
|
|
EXISTS = "exists"
|
|
"""The path is present on disk."""
|
|
|
|
MISSING = "missing"
|
|
"""The path is absent (and its parents are readable)."""
|
|
|
|
UNREADABLE = "unreadable"
|
|
"""Existence could not be determined because `Path.stat()` raised.
|
|
|
|
Typically EACCES when a parent directory denies traversal. Kept distinct
|
|
from `MISSING` so diagnostics can flag it as a genuine problem rather than
|
|
a not-yet-created path.
|
|
"""
|
|
|
|
|
|
def classify_path(path: Path) -> PathState:
|
|
"""Classify a path as existing, missing, or unreadable.
|
|
|
|
Args:
|
|
path: Filesystem path to probe.
|
|
|
|
Returns:
|
|
`PathState.EXISTS` for a present path, `PathState.MISSING` for expected
|
|
absent-path errors, and `PathState.UNREADABLE` when `Path.stat()`
|
|
raises another `OSError` (e.g. a parent directory denies traversal).
|
|
The error is logged at debug level so an unreadable path is never
|
|
silently indistinguishable from a missing one.
|
|
"""
|
|
try:
|
|
path.stat()
|
|
except OSError as exc:
|
|
if exc.errno in _MISSING_ERRNOS:
|
|
return PathState.MISSING
|
|
logger.debug("Could not stat %s", path, exc_info=True)
|
|
return PathState.UNREADABLE
|
|
else:
|
|
return PathState.EXISTS
|