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
14 changes: 10 additions & 4 deletions hermes_cli/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -2108,24 +2108,30 @@ def _build_service_path_dirs(project_root: Path | None = None) -> list[str]:
if project_root is None:
project_root = PROJECT_ROOT

def _is_dir(path: Path) -> bool:
try:
return path.is_dir()
except OSError:
return False

candidates = []

venv_bin = project_root / "venv" / "bin"
if venv_bin.is_dir():
if _is_dir(venv_bin):
candidates.append(str(venv_bin))
elif sys.prefix != sys.base_prefix:
candidates.append(str(Path(sys.prefix) / "bin"))

node_bin = project_root / "node_modules" / ".bin"
if node_bin.is_dir():
if _is_dir(node_bin):
candidates.append(str(node_bin))

hermes_home = get_hermes_home()
hermes_node = hermes_home / "node" / "bin"
if hermes_node.is_dir():
if _is_dir(hermes_node):
candidates.append(str(hermes_node))
hermes_nm = hermes_home / "node_modules" / ".bin"
if hermes_nm.is_dir():
if _is_dir(hermes_nm):
candidates.append(str(hermes_nm))

return candidates
Expand Down
22 changes: 12 additions & 10 deletions plugins/kanban/dashboard/dist/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
.hermes-kanban {
width: 100%;
}
.hermes-kanban,
.hermes-kanban-drawer {
/* The dashboard shell uses uppercase as part of its visual language.
* Kanban displays case-sensitive task IDs, profile IDs, paths, and user
* content, so reset inherited casing at the plugin boundary. */
text-transform: none;
}

/* ---- Code/pre reset (theme-immune default) --------------------------- *
*
Expand Down Expand Up @@ -457,8 +464,7 @@
.hermes-kanban-section-head {
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.07em;
letter-spacing: 0.03em;
color: var(--color-muted-foreground);
}

Expand Down Expand Up @@ -603,8 +609,7 @@
}
.hermes-kanban-deps-label {
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.08em;
letter-spacing: 0.03em;
color: var(--color-muted-foreground);
min-width: 4rem;
}
Expand Down Expand Up @@ -683,8 +688,7 @@
border: 0;
color: var(--color-muted-foreground);
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.05em;
letter-spacing: 0.02em;
cursor: pointer;
padding: 0;
}
Expand Down Expand Up @@ -861,8 +865,7 @@
.hermes-kanban-run-outcome {
font-family: var(--font-mono, ui-monospace, monospace);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
letter-spacing: 0.02em;
color: var(--color-foreground);
}
.hermes-kanban-run-profile {
Expand Down Expand Up @@ -921,8 +924,7 @@
.hermes-kanban-run-meta-label {
font-size: 0.65rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
letter-spacing: 0.03em;
color: var(--color-muted-foreground);
padding-bottom: 0.15rem;
}
Expand Down
26 changes: 26 additions & 0 deletions tests/plugins/test_kanban_dashboard_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,32 @@ def test_dashboard_client_side_filtering_includes_tenant_filter():
assert "[boardData, tenantFilter, assigneeFilter, search]" in js


def _css_block(css: str, selector: str) -> str:
start = css.index(selector)
open_brace = css.index("{", start)
close_brace = css.index("}", open_brace)
Comment on lines +168 to +170
return css[open_brace:close_brace]


def test_dashboard_kanban_preserves_user_entered_case():
"""Kanban must opt out of dashboard-wide uppercase styling."""

repo_root = Path(__file__).resolve().parents[2]
css = (repo_root / "plugins" / "kanban" / "dashboard" / "dist" / "style.css").read_text()

assert ".hermes-kanban,\n.hermes-kanban-drawer" in css
assert "text-transform: none;" in _css_block(css, ".hermes-kanban,")

for selector in (
".hermes-kanban-section-head",
".hermes-kanban-deps-label",
".hermes-kanban-edit-link",
".hermes-kanban-run-outcome",
".hermes-kanban-run-meta-label",
):
assert "text-transform: uppercase" not in _css_block(css, selector)


# ---------------------------------------------------------------------------
# GET /tasks/:id returns body + comments + events + links
# ---------------------------------------------------------------------------
Expand Down
22 changes: 18 additions & 4 deletions tests/run_agent/test_provider_parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,12 @@ def test_original_messages_not_mutated(self, monkeypatch):
assert messages[0]["role"] == "system"

def test_developer_role_via_nous_portal(self, monkeypatch):
agent = _make_agent(monkeypatch, "nous", base_url="https://inference-api.nousresearch.com/v1")
agent.model = "gpt-5"
agent = _make_agent(
monkeypatch,
"nous",
base_url="https://inference-api.nousresearch.com/v1",
model="gpt-5",
)
messages = [
{"role": "system", "content": "You are helpful."},
{"role": "user", "content": "hi"},
Expand Down Expand Up @@ -346,14 +350,24 @@ def test_includes_tools(self, monkeypatch):
class TestBuildApiKwargsNousPortal:
def test_includes_nous_product_tags(self, monkeypatch):
from agent.portal_tags import nous_portal_tags
agent = _make_agent(monkeypatch, "nous", base_url="https://inference-api.nousresearch.com/v1")
agent = _make_agent(
monkeypatch,
"nous",
base_url="https://inference-api.nousresearch.com/v1",
model="gpt-5",
)
messages = [{"role": "user", "content": "hi"}]
kwargs = agent._build_api_kwargs(messages)
extra = kwargs.get("extra_body", {})
assert extra.get("tags") == nous_portal_tags()

def test_uses_chat_completions_format(self, monkeypatch):
agent = _make_agent(monkeypatch, "nous", base_url="https://inference-api.nousresearch.com/v1")
agent = _make_agent(
monkeypatch,
"nous",
base_url="https://inference-api.nousresearch.com/v1",
model="gpt-5",
)
messages = [{"role": "user", "content": "hi"}]
kwargs = agent._build_api_kwargs(messages)
assert "messages" in kwargs
Expand Down
Loading