Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
44 changes: 26 additions & 18 deletions hermes_cli/kanban_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -3213,30 +3213,38 @@ def read_worker_log(
# ---------------------------------------------------------------------------

def list_profiles_on_disk() -> list[str]:
"""Return the set of named profiles discovered on disk.
"""Return the set of assignee/profile names discovered on disk.

Reads ``~/.hermes/profiles/`` directly so this module has no import
dependency on ``hermes_cli.profiles`` (which pulls in a large chunk
of the CLI startup path). Only returns directories that contain a
``config.yaml`` — a bare dir without config isn't a real profile.
Includes:
- named profiles under ``<default-root>/profiles/<name>/config.yaml``
- the implicit ``default`` profile when the default Hermes root exists

Reads profile paths directly so this module has no import dependency on
``hermes_cli.profiles`` (which pulls in a large chunk of the CLI startup
path).
"""
try:
from hermes_constants import get_default_hermes_root
home = get_default_hermes_root() / "profiles"
default_root = get_default_hermes_root()
profiles_dir = default_root / "profiles"
except Exception:
return []
if not home.is_dir():
return []
names: list[str] = []
try:
for entry in sorted(home.iterdir()):
if not entry.is_dir():
continue
if (entry / "config.yaml").is_file():
names.append(entry.name)
except OSError:
return names
return names

names: set[str] = set()
if default_root.exists():
names.add("default")

if profiles_dir.is_dir():
try:
for entry in sorted(profiles_dir.iterdir()):
if not entry.is_dir():
continue
if (entry / "config.yaml").is_file():
names.add(entry.name)
except OSError:
pass

return sorted(names)


def known_assignees(conn: sqlite3.Connection) -> list[dict]:
Expand Down
10 changes: 6 additions & 4 deletions tests/hermes_cli/test_kanban_core_functionality.py
Original file line number Diff line number Diff line change
Expand Up @@ -899,8 +899,8 @@ def test_migration_renames_legacy_event_kinds(tmp_path, monkeypatch):
# ---------------------------------------------------------------------------

def test_list_profiles_on_disk(tmp_path, monkeypatch):
"""list_profiles_on_disk returns directories under ~/.hermes/profiles/
that contain a config.yaml."""
"""list_profiles_on_disk returns the implicit default profile plus
named profiles under ~/.hermes/profiles/ that contain a config.yaml."""
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.delenv("HERMES_HOME", raising=False)
profiles = tmp_path / ".hermes" / "profiles"
Expand All @@ -914,7 +914,7 @@ def test_list_profiles_on_disk(tmp_path, monkeypatch):
(profiles / "stray.txt").write_text("noise")

names = kb.list_profiles_on_disk()
assert names == ["researcher", "writer"]
assert names == ["default", "researcher", "writer"]


def test_list_profiles_on_disk_custom_root(tmp_path, monkeypatch):
Expand All @@ -928,7 +928,7 @@ def test_list_profiles_on_disk_custom_root(tmp_path, monkeypatch):
(d / "config.yaml").write_text("model: {}\n")

names = kb.list_profiles_on_disk()
assert names == ["researcher", "writer"]
assert names == ["default", "researcher", "writer"]


def test_known_assignees_merges_disk_and_board(tmp_path, monkeypatch):
Expand All @@ -955,6 +955,8 @@ def test_known_assignees_merges_disk_and_board(tmp_path, monkeypatch):
conn.close()

by_name = {d["name"]: d for d in data}
assert by_name["default"]["on_disk"] is True
assert by_name["default"]["counts"] == {}
assert by_name["researcher"]["on_disk"] is True
assert by_name["researcher"]["counts"] == {}
assert by_name["writer"]["on_disk"] is True
Expand Down