diff --git a/hermes_cli/kanban_db.py b/hermes_cli/kanban_db.py index 9ed9f512b1..e39808546f 100644 --- a/hermes_cli/kanban_db.py +++ b/hermes_cli/kanban_db.py @@ -3277,30 +3277,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 ``/profiles//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]: diff --git a/tests/hermes_cli/test_kanban_core_functionality.py b/tests/hermes_cli/test_kanban_core_functionality.py index 3c5454b35c..3fe09086e5 100644 --- a/tests/hermes_cli/test_kanban_core_functionality.py +++ b/tests/hermes_cli/test_kanban_core_functionality.py @@ -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" @@ -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): @@ -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): @@ -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