Skip to content

fix(cli): Correct /tools display alignment and truncation - #116

Closed
Bartok9 wants to merge 1 commit into
NousResearch:mainfrom
Bartok9:fix-tools-display
Closed

fix(cli): Correct /tools display alignment and truncation#116
Bartok9 wants to merge 1 commit into
NousResearch:mainfrom
Bartok9:fix-tools-display

Conversation

@Bartok9

@Bartok9 Bartok9 commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #37

Issues Fixed

1. Header alignment off by 1 space

The header line had incorrect padding:

# Before: 25 + 22 + 30 = 77 chars (box interior is 78)
print("|" + " " * 25 + "(^_^)/ Available Tools" + " " * 30 + "|")

# After: 28 + 22 + 28 = 78 chars (properly centered)
print("|" + " " * 28 + "(^_^)/ Available Tools" + " " * 28 + "|")

2. Tool descriptions overflow terminal width

On 80-column terminals, long descriptions would get cut off. Added truncation:

  • Line prefix: * (6 chars)
  • Tool name: 20 chars (padded)
  • Separator: - (3 chars)
  • Available for description: ~48 chars

Descriptions longer than 48 chars are now truncated with ...

Before

+------------------------------------------------------------------------------+
|                         (^_^)/ Available Tools                              |   <- off by 1
+------------------------------------------------------------------------------+

  [clarify]
    * clarify              - Ask the user a question when you need clarification, feedbac

After

+------------------------------------------------------------------------------+
|                            (^_^)/ Available Tools                            |   <- centered
+------------------------------------------------------------------------------+

  [clarify]
    * clarify              - Ask the user a question when you need clari...

Testing

  • Verified Python syntax is valid
  • Confirmed header alignment: border and header both 80 chars
  • Truncation tested on long descriptions

Fixes NousResearch#37

Issues fixed:
1. Header was off by 1 space (25+22+30=77 vs 78-char box interior)
   Changed to 28+22+28=78 for proper centering

2. Tool descriptions could overflow the 80-char terminal width
   Added truncation to 48 chars with '...' suffix

The display now renders correctly on standard 80-column terminals.
@Bartok9

Bartok9 commented Feb 27, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of #109 which provides a more comprehensive fix handling all slash commands and wide characters. Great work @antoaenono!

@Bartok9 Bartok9 closed this Feb 27, 2026
jarvis-stark-ops added a commit to 1Team-Engineering/hermes-agent that referenced this pull request Jun 16, 2026
* feat(mcp): scaffold hermes-tools-mcp stdio server with initialize

NousResearch#109

Minimal stdio JSON-RPC server that responds to MCP 'initialize' with
the expected protocol version + capabilities. Tools surface comes in
follow-up commits. Env-bound to (profile, project) scope.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(mcp): tools/list returns filtered Hermes tool surface

NousResearch#109

Filters the live Hermes tool registry to the v1 surface defined in
spec §4.1. Includes special hermes_set_task tool for per-turn task
context updates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(mcp): tools/call dispatches to Hermes tool registry

NousResearch#109

hermes_set_task updates per-turn task context (task_id, workspace).
All other tools/call requests filter through ALLOWED_TOOLS, then
dispatch via registry.dispatch() which handles both sync and async
tools. Denied tools (kanban_dispatch etc.) return isError=true.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(kanban): add task_sessions table for relay scope tracking

NousResearch#113

Per spec §4.7 — tracks (profile, project) → tmux session, claude
session_id, FIFO path, MCP config path, project root, scope cwd,
task count, timestamps. Helpers: upsert_session, get_session,
touch_session, mark_compacted, evict_session, list_idle_sessions.

* feat(relay): project derivation + task header builder

NousResearch#114

derive_project maps a kanban workspace to its 'project' key:
  - scratch workspaces -> 'scratch'
  - git workspaces -> basename of git root
  - else raises ProviderError (B11: no silent default)

build_task_header prepends '[task_id=... workspace=...]' to each
user prompt so claude knows the current task without an MCP roundtrip.

* feat(provider): register claude-code-relay ProviderProfile

NousResearch#112

Registers the provider via the existing bundled-plugin pattern under
plugins/model-providers/claude-code-relay/__init__.py. api_mode=
'claude_code_relay' is a new tag for the transport defined in the
next commit. auth_type='none' because the claude binary handles its
own OAuth — the relay just shells out.

* feat(transport): scope spawn + send turn helpers

NousResearch#112

ScopeContext bundles (profile, project, workspace). ensure_scope
either finds a live tmux or invokes relay-spawn-scope.sh (writing
the MCP config first). send_turn prepends the task header and
relays through relay-send.sh, returning the captured response.
Also added monkeypatch for derive_project_root in spawn test since
tmp_path is not a git repo.

* feat(transport): OpenAI-compat ChatCompletion response shape

NousResearch#112

chat_completion() returns the standard OpenAI ChatCompletion object.
Only the latest user message is forwarded — prior conversation rides
on claude's in-session memory. Usage fields left null; /compact hook
in next task captures /usage and backfills.

* feat(kanban): /compact between-task hook for relay scopes

NousResearch#115

After a task with provider=claude-code-relay completes or blocks,
send /compact to its (profile, project) scope. Per B10, failures
are logged but never block the completion. Records last_compacted_at
on task_sessions.

Also: add tasks.provider column to SCHEMA_SQL + additive ALTER migration;
set conn.row_factory=sqlite3.Row in init_db test-fixture shortcut so
complete_task works correctly in :memory: tests.

Spike 2 (2026-06-15) confirmed /compact returns 'Not enough messages
to compact' on short sessions; that's handled cleanly via the timeout
in relay-send.sh slash-command extension.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(relay): idle-eviction cron step

NousResearch#116

evict_idle_scopes deletes task_sessions rows whose last_used_at is
older than HERMES_RELAY_IDLE_EVICT_SECS (default 86400 = 24h),
and tears down the tmux session via relay-kill-scope.sh.

Wire into nightly-hermes-maintenance follows separately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(relay): boot-check that Hermes Stop hook is installed

NousResearch#109

B3: Stop hook is mandatory for the relay to detect turn-end via FIFO.
Boot-check raises ProviderError with installer path if the hook is
missing — fail loud instead of silently hanging 180s per turn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(relay): validate ScopeContext.profile + project against B8 regex

Per code review on PR #20 — the shell relay-spawn-scope.sh validates
^[a-zA-Z0-9_-]+$ but Python-side _write_mcp_config writes /tmp/hermes-mcp-{slug}.json
BEFORE invoking the shell. Slugs containing / or .. would have allowed
path traversal out of /tmp.

Add same regex check in ScopeContext.__post_init__. Closes B8 (spec §3).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(relay): chmod 0o600 on /tmp MCP config files

Defense-in-depth: prevent workspace paths in the MCP config from leaking
to other users sharing /tmp. Per code review on PR #20.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(kanban): honor HERMES_RELAY_BIN in /compact hook for consistency

Transport reads HERMES_RELAY_BIN; the kanban_db /compact hook should
too. Per code review on PR #20.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(relay): preserve task_sessions row when relay-kill-scope.sh fails

Per code review on PR #20 — previously evicted the DB row even on kill
failure, orphaning the tmux session with no record to retry. Now check
rc; only evict DB row on rc=0. Failed scopes get retried on next cron tick.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(relay): log WARNING when relay-send exits 4 (Stop-hook timeout)

Per code review on PR #20 — exit 4 means partial response, but callers
had no signal. Add a logger.warning so operators see the partial in logs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Jarvis <jarvis@Kaipos-Mac-mini.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Meraniya pushed a commit to Meraniya/hermes-agent that referenced this pull request Aug 6, 2026
* ci: add diff-scoped gitleaks secret scanning

This repo had no secret scanning of any kind — no gitleaks/trufflehog
workflow, no pre-commit config — while shipping 1Password and Bitwarden
credential-bootstrap paths. supply-chain-audit.yml covers attack-pattern
indicators only (.pth files, base64+exec) and is pull_request-scoped.

The scan is diff-scoped: it never rescans history, so pre-existing
placeholder credentials in test fixtures don't fire on unrelated changes.
gitleaks is pinned by version and tarball SHA256; checkout is SHA-pinned
per the dependency pinning policy.

Two things worth flagging:

gitleaks' stock ruleset has no Anthropic rule at all — a well-formed
sk-ant-api03 canary passes straight through the default config. For an
agent framework whose primary job is calling Claude, that is the most
likely credential to leak, so anthropic-api-key, anthropic-admin-key and
openrouter-api-key are added explicitly. OpenRouter otherwise falls to
the entropy-based generic-api-key, which misses a key appearing without
a nearby keyword.

No committed credentials exist. A full-tree scan surfaced 647 findings
in tracked files; all were triaged and all are benign — ~534 in two
vendored upstream unsloth reference docs, the rest published OAuth
client IDs, gemini-cli's public desktop client secret, Discord and
Mattermost IDs in docs examples, and test fixtures.

Verification: allowlist tuning takes the tracked tree 647 -> 82, all 82
residual being unmarked placeholders in tests/ that a diff scan never
reaches. A canary with seven well-formed provider credentials is caught
7/7. End-to-end against the real CI command: clean commit exits 0,
canary commit exits 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012689txgT12g2hjRczcUZi8

* docs(system-log): retract the RELEASE_v0.15.0.md finding

All 13 RELEASE_*.md files landed in one commit (3beff00) — they are upstream
NousResearch release notes vendored into this fork, not documents authored
here. This fork's 0.15.0 is a local CVE bump, not an upstream release, so
there is no missing artifact and authoring one would fabricate an upstream
release document.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012689txgT12g2hjRczcUZi8

---------

Co-authored-by: Claude <noreply@anthropic.com>
Meraniya pushed a commit to Meraniya/hermes-agent that referenced this pull request Aug 6, 2026
…ousResearch#126)

Clears the two follow-ups named in NousResearch#116.

.pre-commit-config.yaml runs the same gitleaks against the staged diff,
pinned to the upstream repo at a commit SHA per the Dependency Pinning
Policy. Opt-in — nothing runs until a contributor runs `pre-commit
install`. CI remains the enforcement boundary; this only moves the check
to where the remedy is an amend rather than a history rewrite plus a
credential rotation.

ci-auto-healer.yml drops from */30 to hourly at :23. The workflow_run
triggers already fire the moment a watched workflow completes, so the
cron is only a backstop for missed completion events. At */30 it ran
~48x/day almost always to print "No failed runs found", which is what
buried the real Tests/Lint history in the run list during the scan that
prompted this work. Off-minute is deliberate: :00 is GitHub's most
contended scheduler slot.

Verified the hook rather than just linting it: staged canary of seven
well-formed provider credentials exits 1 and reports all seven,
including the custom Anthropic and OpenRouter rules — confirming it
reads .gitleaks.toml and not the built-in default. Clean tree exits 0.
Both edited workflows re-parsed; the pinned rev came from
`git ls-remote --tags`, not from memory.


Claude-Session: https://claude.ai/code/session_012689txgT12g2hjRczcUZi8

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

consistent slash command content

1 participant