mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
feat: show workspace status in cli banner
This commit is contained in:
parent
bff650559e
commit
7ad10183ae
2 changed files with 127 additions and 0 deletions
|
|
@ -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"]
|
||||
|
|
|
|||
77
tests/hermes_cli/test_banner_workspace.py
Normal file
77
tests/hermes_cli/test_banner_workspace.py
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue