feat: show workspace status in cli banner

This commit is contained in:
teknium1 2026-03-14 19:39:31 -07:00
parent bff650559e
commit 7ad10183ae
2 changed files with 127 additions and 0 deletions

View file

@ -15,6 +15,8 @@ from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from hermes_cli.config import load_config
from prompt_toolkit import print_formatted_text as _pt_print
from prompt_toolkit.formatted_text import ANSI as _PT_ANSI
@ -124,6 +126,48 @@ def get_available_skills() -> Dict[str, List[str]]:
return skills_by_category
def _workspace_root_labels(config: Dict[str, Any]) -> list[str]:
workspace_cfg = config.get("workspace", {}) or {}
kb_cfg = config.get("knowledgebase", {}) or {}
if not workspace_cfg.get("enabled", True) or not kb_cfg.get("enabled", True):
return []
workspace_path = workspace_cfg.get("path") or str(Path(os.getenv("HERMES_HOME", Path.home() / ".hermes")) / "workspace")
workspace_root = Path(os.path.expandvars(os.path.expanduser(workspace_path))).resolve()
roots = kb_cfg.get("roots") or [str(workspace_root)]
labels: list[str] = []
seen: set[str] = set()
for raw_root in roots:
expanded = Path(os.path.expandvars(os.path.expanduser(str(raw_root)))).resolve()
if expanded == workspace_root:
label = "workspace"
else:
label = expanded.name or str(expanded)
if label == workspace_root.name:
label = str(expanded)
if label in seen:
continue
seen.add(label)
labels.append(label)
return labels
def _get_workspace_banner_line() -> Optional[str]:
try:
config = load_config()
except Exception:
return None
labels = _workspace_root_labels(config)
if not labels:
return None
if len(labels) > 3:
display = ", ".join(labels[:3]) + f" +{len(labels) - 3} more"
else:
display = ", ".join(labels)
return f"Activated Workspace(s): {display}"
# =========================================================================
# Update check
# =========================================================================
@ -352,6 +396,12 @@ def build_welcome_banner(console: Console, model: str, cwd: str,
else:
right_lines.append(f"[dim {dim}]No skills installed[/]")
workspace_line = _get_workspace_banner_line()
if workspace_line:
right_lines.append("")
right_lines.append(f"[bold {accent}]Workspace[/]")
right_lines.append(f"[{text}]{workspace_line}[/]")
right_lines.append("")
mcp_connected = sum(1 for s in mcp_status if s["connected"]) if mcp_status else 0
summary_parts = [f"{len(tools)} tools", f"{total_skills} skills"]

View file

@ -0,0 +1,77 @@
from __future__ import annotations
from io import StringIO
from rich.console import Console
def test_workspace_banner_line_uses_default_workspace_when_enabled(monkeypatch, tmp_path):
from hermes_cli import banner
cfg = {
"workspace": {"enabled": True, "path": str(tmp_path / "workspace")},
"knowledgebase": {"enabled": True, "roots": []},
}
monkeypatch.setattr(banner, "load_config", lambda: cfg)
line = banner._get_workspace_banner_line()
assert line == "Activated Workspace(s): workspace"
def test_workspace_banner_line_lists_multiple_roots(monkeypatch, tmp_path):
from hermes_cli import banner
cfg = {
"workspace": {"enabled": True, "path": str(tmp_path / "workspace")},
"knowledgebase": {
"enabled": True,
"roots": [
str(tmp_path / "workspace"),
str(tmp_path / "notes"),
str(tmp_path / "project-docs"),
],
},
}
monkeypatch.setattr(banner, "load_config", lambda: cfg)
line = banner._get_workspace_banner_line()
assert line == "Activated Workspace(s): workspace, notes, project-docs"
def test_workspace_banner_line_omits_when_disabled(monkeypatch):
from hermes_cli import banner
cfg = {
"workspace": {"enabled": False, "path": ""},
"knowledgebase": {"enabled": False, "roots": []},
}
monkeypatch.setattr(banner, "load_config", lambda: cfg)
assert banner._get_workspace_banner_line() is None
def test_build_welcome_banner_renders_workspace_line(monkeypatch):
from hermes_cli import banner
monkeypatch.setattr(banner, "check_for_updates", lambda: 0)
monkeypatch.setattr(banner, "get_available_skills", lambda: {})
monkeypatch.setattr(banner, "_get_workspace_banner_line", lambda: "Activated Workspace(s): workspace, notes")
buf = StringIO()
console = Console(file=buf, force_terminal=False, width=140, color_system=None)
banner.build_welcome_banner(
console=console,
model="anthropic/claude-sonnet-4.5",
cwd="/tmp/project",
tools=[],
enabled_toolsets=["hermes-cli"],
session_id="sess-1",
get_toolset_for_tool=lambda _: "other",
context_length=200000,
)
rendered = buf.getvalue()
assert "Activated Workspace(s): workspace, notes" in rendered