mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(gateway): let @ completion find folders by name
The fuzzy branch of `complete.path` ranked basenames from `_list_repo_files`, which lists files only, so a directory was only ever reachable by typing a `/` — `@Desktop` returned nothing at all. Rank each ancestor directory alongside the files, and break same-tier ties toward the folder so `@docs` leads with `docs/` rather than `docs.md`. Outside a git repo the fallback `os.walk` compounded this: it can spend the whole `_FUZZY_CACHE_MAX_FILES` budget inside one deep subtree before reaching a sibling, hiding top-level folders entirely. Seed the scan with a `listdir` of the root so immediate children are always candidates.
This commit is contained in:
parent
5646fed97e
commit
b378cc0a72
2 changed files with 120 additions and 14 deletions
|
|
@ -277,3 +277,79 @@ def test_fuzzy_paths_relative_to_cwd_inside_subdir(tmp_path, monkeypatch):
|
|||
readme_texts = [t for t, _, _ in _items("@README")]
|
||||
|
||||
assert not any("README.md" in t for t in readme_texts), readme_texts
|
||||
|
||||
|
||||
# ── Fuzzy DIRECTORY matching ─────────────────────────────────────────────
|
||||
# `@Desktop` used to return nothing: the fuzzy scanner ranks basenames from
|
||||
# `_list_repo_files`, which lists FILES only, so a directory whose name no
|
||||
# file inside it happens to match was unreachable without typing a `/`.
|
||||
|
||||
|
||||
def test_fuzzy_finds_directory_by_name(tmp_path, monkeypatch):
|
||||
"""A folder is reachable by bare name, with no trailing slash typed."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "Desktop" / "nested").mkdir(parents=True)
|
||||
# Deliberately named so NO file basename fuzzy-matches "Desktop".
|
||||
(tmp_path / "Desktop" / "nested" / "zzz.txt").write_text("x")
|
||||
|
||||
entries = _items("@Desktop")
|
||||
texts = [t for t, _, _ in entries]
|
||||
|
||||
assert "@folder:Desktop/" in texts, texts
|
||||
|
||||
row = next(r for r in entries if r[0] == "@folder:Desktop/")
|
||||
assert row[1] == "Desktop/"
|
||||
assert row[2] == "dir"
|
||||
|
||||
|
||||
def test_fuzzy_directory_prefix_match(tmp_path, monkeypatch):
|
||||
"""Partial folder names match too — `@Desk` finds `Desktop/`."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "Desktop").mkdir()
|
||||
(tmp_path / "Desktop" / "zzz.txt").write_text("x")
|
||||
|
||||
assert "@folder:Desktop/" in [t for t, _, _ in _items("@Desk")]
|
||||
|
||||
|
||||
def test_fuzzy_ranks_folder_above_file_at_same_tier(tmp_path, monkeypatch):
|
||||
"""At an equal match tier the folder leads: `@docs` means the directory."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "docs").mkdir()
|
||||
(tmp_path / "docs" / "intro.md").write_text("x")
|
||||
(tmp_path / "docs.md").write_text("x")
|
||||
|
||||
texts = [t for t, _, _ in _items("@docs")]
|
||||
|
||||
assert texts[0] == "@folder:docs/", texts
|
||||
assert "@file:docs.md" in texts
|
||||
|
||||
|
||||
def test_fuzzy_hides_dot_directories_unless_asked(tmp_path, monkeypatch):
|
||||
"""Dot-folders follow the same rule as dotfiles."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".config").mkdir()
|
||||
(tmp_path / ".config" / "zzz.txt").write_text("x")
|
||||
|
||||
assert not any(".config" in t for t, _, _ in _items("@config"))
|
||||
assert any(t.startswith("@folder:.config") for t, _, _ in _items("@.config"))
|
||||
|
||||
|
||||
def test_fuzzy_finds_top_level_entries_outside_a_git_repo(tmp_path, monkeypatch):
|
||||
"""Outside a repo the fallback walk can exhaust its file budget on one
|
||||
deep subtree before reaching a sibling, hiding top-level folders. The
|
||||
root listdir seed guarantees immediate children are always candidates.
|
||||
"""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
monkeypatch.setattr(server, "_FUZZY_CACHE_MAX_FILES", 5)
|
||||
|
||||
# A deep subtree that soaks up the entire (patched) file budget...
|
||||
deep = tmp_path / "aaa_hog"
|
||||
deep.mkdir()
|
||||
for i in range(40):
|
||||
(deep / f"f{i:03d}.txt").write_text("x")
|
||||
|
||||
# ...and the folder the user actually wants, sorted after it.
|
||||
(tmp_path / "Desktop").mkdir()
|
||||
(tmp_path / "Desktop" / "note.txt").write_text("x")
|
||||
|
||||
assert "@folder:Desktop/" in [t for t, _, _ in _items("@Desktop")]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue