Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Add navigation suggestion and file skeleton for view command - #41

Closed
ryanhoangt wants to merge 4 commits into
ht/refactor-nav-commandsfrom
ht/refactor-context-suggestion
Closed

Add navigation suggestion and file skeleton for view command#41
ryanhoangt wants to merge 4 commits into
ht/refactor-nav-commandsfrom
ht/refactor-context-suggestion

Conversation

@ryanhoangt

Copy link
Copy Markdown
Member

Description

This PR is to:

  • Improve upon the existing view command implementation.

Some remaining TODOs:

  • Max token control
  • Symbol ranking to choose what to show

view command on a file path

{
    "command": "view", 
    "path": "/home/hoang/openhands-aci/openhands_aci/utils/shell.py"
}
New output with navigation suggestion
Here's the result of running `cat -n` on /home/hoang/openhands-aci/openhands_aci/
utils/shell.py:
     1  import os
     2  import subprocess
     3  import time
     4
     5  from openhands_aci.editor.config import MAX_RESPONSE_LEN_CHAR
     6  from openhands_aci.editor.results import maybe_truncate
     7
     8
     9  def run_shell_cmd(
    10      cmd: str,
    11      timeout: float | None = 120.0,  # seconds
    12      truncate_after: int | None = MAX_RESPONSE_LEN_CHAR,
    13  ) -> tuple[int, str, str]:
    14      """Run a shell command synchronously with a timeout.
    15
    16      Args:
    17          cmd: The shell command to run.
    18          timeout: The maximum time to wait for the command to complete.
    19          truncate_after: The maximum number of characters to return for stdout and stderr.
    20
    21      Returns:
    22          A tuple containing the return code, stdout, and stderr.
    23      """
    24
    25      start_time = time.time()
    26
    27      try:
    28          process = subprocess.Popen(
    29              cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
    30          )
    31
    32          stdout, stderr = process.communicate(timeout=timeout)
    33
    34          return (
    35              process.returncode or 0,
    36              maybe_truncate(stdout, truncate_after=truncate_after),
    37              maybe_truncate(stderr, truncate_after=truncate_after),
    38          )
    39      except subprocess.TimeoutExpired:
    40          process.kill()
    41          elapsed_time = time.time() - start_time
    42          raise TimeoutError(
    43              f"Command '{cmd}' timed out after {elapsed_time:.2f} seconds"
    44          )
    45
    46
    47  def check_tool_installed(tool_name: str) -> bool:
    48      """Check if a tool is installed."""
    49      try:
    50          subprocess.run(
    51              [tool_name, '--version'],
    52              check=True,
    53              cwd=os.getcwd(),
    54              stdout=subprocess.PIPE,
    55              stderr=subprocess.PIPE,
    56          )
    57          return True
    58      except (subprocess.CalledProcessError, FileNotFoundError):
    59          return False
    60

Files that this file uses:
- openhands_aci/editor/results.py (via `maybe_truncate`)

Files that refer to this file:
- tests/unit/test_shell_utils.py (via `run_shell_cmd`, `check_tool_installed`)
- openhands_aci/linter/impl/python.py (via `run_shell_cmd`)
- openhands_aci/editor/editor.py (via `run_shell_cmd`)
<TIP>Use the `jump_to_definition` and `find_references` commands to understand 
more about those class, function/method and how they are used in the codebase.</TIP>

view command on a directory path

{
    "command": "view", 
    "path": "/home/hoang/openhands-aci/openhands_aci/utils"
}
New output with file skeleton
Here's the files with its skeleton (i.e., class, function/method signatures) and 
directories up to 2 levels deep in /home/hoang/openhands-aci/openhands_aci/utils, 
excluding hidden items:
/home/hoang/openhands-aci/openhands_aci/utils
/home/hoang/openhands-aci/openhands_aci/utils/file.py
...⋮...
  7│class GitRepoUtils:
  8│    def __init__(self, abs_repo_path: str) -> None:
  9│        from git import Repo
 10│
 11│        if not Path(abs_repo_path).is_absolute():
 12│            raise ValueError('The path must be absolute')
 13│
 14│        self.repo_path = Path(abs_repo_path)
 15│        try:
 16│            self.repo = Repo(self.repo_path)
 17│        except Exception:
...⋮...
 23│    def get_all_absolute_tracked_files(self, depth: int | None = None) -> list[str]:
...⋮...
 31│    def get_all_relative_tracked_files(self, depth: int | None = None) -> list[str]:
...⋮...
 39│    def get_all_absolute_staged_files(self) -> list[str]:
...⋮...
 44│    def get_absolute_tracked_files_in_directory(
 45│        self, rel_dir_path: str, depth: int | None = None
...⋮...
 57│def get_modified_time(abs_path: str) -> int:
...⋮...
 64│def read_text(abs_path: str) -> str:
...⋮...
/home/hoang/openhands-aci/openhands_aci/utils/shell.py
...⋮...
  9│def run_shell_cmd(
 10│    cmd: str,
 11│    timeout: float | None = 120.0,  # seconds
 12│    truncate_after: int | None = MAX_RESPONSE_LEN_CHAR,
...⋮...
 47│def check_tool_installed(tool_name: str) -> bool:
...⋮...
/home/hoang/openhands-aci/openhands_aci/utils/logger.py

/home/hoang/openhands-aci/openhands_aci/utils/diff.py
...⋮...
  6│def get_diff(old_contents: str, new_contents: str, filepath: str = 'file') -> str:
...⋮...
 21│def parse_diff(diff_patch: str) -> list[whatthepatch.patch.Change]:
...⋮...
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/path.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/shell.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/diff.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/file.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/logger.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/path.py
...⋮...
  4│class PathUtils:
  5│    def __init__(self, root: str) -> None:
...⋮...
  8│    def get_absolute_path_str(self, rel_path: str) -> str:
...⋮...
 11│    def get_relative_path_str(self, abs_path: str) -> str:
...⋮...
 14│    def get_depth_from_root(self, abs_path: str) -> int:
...⋮...
 18│def has_image_extension(path: str) -> bool:
...⋮...
 23│def get_depth_of_rel_path(rel_path: str) -> int:
...⋮...

Related Issue

This can be seen as an alternative to the original RepoMap. Progress towards OpenHands/OpenHands#2185

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants