fix(hooks): session-owned profile-keyed shell hooks for dashboard/TUI - #53894
fix(hooks): session-owned profile-keyed shell hooks for dashboard/TUI#53894Ne0teric wants to merge 2 commits into
Conversation
Related: this fixes the same TUI/Desktop shell-hook-registration gap as the open cluster anchored by earliest-open #13854 (also #34112, #24237, #28953, #41464; issue #41457). This PR is not a duplicate — it adds net-new coverage (dashboard backend registration + a Windows UTF-8 hook-I/O fix) beyond the TUI-only competitors. Flagging the cluster so a maintainer can pick a canonical PR. |
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Clean fix for shell hooks not firing on dashboard and TUI/desktop startup. The hooks (pre_llm_call / post_llm_call) were only registered in the CLI and gateway paths.
Changes:
- Dashboard startup registers hooks via
register_from_config(load_config(), accept_hooks=False) - TUI/desktop startup registers hooks via the same pattern with
hooks_auto_acceptconfig support encoding="utf-8"added to subprocess calls inshell_hooks.pyfor consistent behavior- Fail-soft: hook registration failures are logged at debug level and don't block startup
The accept_hooks=False for dashboard is correct — dashboard processes user commands, not interactive agents. The TUI's accept_hooks=_auto respects the user's config preference.
No concerns. Ready to merge.
Reviewed by Hermes Agent
|
Friendly ping on this one — it was approved by @tonydwb on Jun 28 but hasn't landed yet. Just re-verified it still merges cleanly against current For context: without this fix, config-defined shell hooks silently never fire for dashboard/TUI/desktop sessions (only CLI gets them), and hook scripts that emit non-ASCII output crash on Windows' cp1252 default. |
|
Thanks for addressing two real shell-hook gaps. Current Problems
Suggested changes
Automated hermes-sweeper review. |
ca12fc8 to
0d67e64
Compare
0d67e64 to
1d31ade
Compare
|
Addressed the hermes-sweeper review (keep_open / salvageability=medium) on current Changes
Local: 6 passed for the new tests. |
1d31ade to
8c7d441
Compare
|
Rebased onto current Notes from the rebase:
Happy to adjust further if anything's needed. |
_notify_session_boundary now takes profile_home= for multi-profile lifecycle binding. Update lambdas that only took *args so CI mocks do not TypeError on the new keyword.
|
CI fix: session-boundary mocks now accept profile_home= kwarg (3 tests). |
|
I independently reproduced the missing shell-hook registration path on macOS Hermes Desktop and live-validated that making configured hooks available to the dashboard backend restores lifecycle callbacks. I am adding the evidence here rather than opening another PR because this PR uses the stronger session/profile-owned design needed by the multi-profile dashboard architecture. Pinned reproduction environment:
Validation on the pinned reproduction SHA:
The live result confirms the user-visible defect and the need for dashboard/serve registration. It does not, by itself, validate the current PR head against today’s The profile/session ownership in this PR remains important: one dashboard process can serve multiple profiles, so registration plus reset/end/finalize dispatch should stay scoped to the owning profile. I have kept my narrow startup-global reproduction unpublished and will not open a competing PR. |
Problem
Shell hooks (
pre_llm_call/post_llm_call) only worked from the CLI on Windows. Two independent issues:1. Hooks never registered outside the CLI startup path.
register_from_config()was only called on CLI startup. The dashboard backend (cmd_dashboard) and the TUI entrypoint (tui_gateway/entry.py) never called it — so the desktop app (which launcheshermes dashboardas its backend) and the TUI registered zero hooks and silently injected/saved nothing. No error — the hooks just never fired. Confirmed viaagent.log: a desktop/dashboard restart produced noshell hook registeredline, only CLI sessions did.2. Hook I/O crashed on non-ASCII on Windows.
_spawn()ran the hook withsubprocess.run(..., text=True)and no explicitencoding, so it used the platform locale codec (cp1252 on Windows). Hook output containing non-ASCII (em dash, arrows, etc.) raised'charmap' codec can't encode character ...and failed the hook every turn.Fix
register_from_config()at dashboard (cmd_dashboard) and TUI (tui_gateway/entry.py) startup, matching the CLI path.register_from_configalready resolveshooks_auto_acceptinternally, so the no-TTY dashboard/gateway auto-accepts correctly.encoding="utf-8"to the_spawn()subprocess.runso hook stdin/stdout is UTF-8 on every platform.24 insertions, 0 deletions across 3 files.
Testing
tests/agent/test_shell_hooks.pyon Windows: 46 passed, 7 failed — and the same 7 fail on cleanmainwithout this patch (verified by running the suite against unpatched main). They're pre-existing Windows-only test-harness limitations (bash-shebang scripts can't execute undershell=False;os.access(path, X_OK)has no meaning on Windows), unrelated to this change — it adds zero new failures. The 46 passing tests cover registration, allowlisting, config parsing, payload serialization, and idempotence.Behavior confirmed on a Windows desktop install: before the fix the
hermes dashboardbackend registered zero hooks; after, it registers both and thepre_llm_callhook injects context each turn.