Add first-class Hermes restore and lifecycle support - #9540
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR adds first-class Hermes support with persisted-session restoration, cwd-aware indexing, configurable hooks, generic agent command shims, wrapper execution, and integration coverage. ChangesHermes support integration
Estimated code review effort: 5 (Critical) | ~100 minutes Possibly related PRs
Suggested reviewers: Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (5 errors, 2 warnings)
✅ Passed checks (18 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmuxTests/HermesFirstClassSupportTests.swift`:
- Around line 414-421: The fixture currently writes cwd twice, with rewriteCwds
overwriting per-row values. Update makeFixture and its call sites to pass each
row’s cwd into StateRow, insert it during fixture creation, and remove the
rewriteCwds helper and all calls to it so StateRow.cwd is the sole owner of the
value.
- Around line 437-456: Update runProcess so it reads the combined stdout and
stderr pipe before calling process.waitUntilExit(), preventing the child from
blocking when output exceeds the pipe buffer; retain the existing status and
decoded output return behavior.
- Line 215: Update the socketPath initialization in the test fixture to derive
its value from the per-run root directory instead of using the fixed /tmp path.
Keep the resulting path consistent with the config.yaml and consent allowlist
assertions so concurrent test runs remain isolated.
In
`@Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/Vault/Providers/HermesAgent/HermesAgentIndexTests.swift`:
- Around line 70-86: Implement cwdFilter handling in
HermesAgentIndex.loadSessions so non-nil filters return matching sessions
instead of an empty result, using canonical-path comparison to support symlinked
repository paths. Apply this production-loader change for
Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/Vault/Providers/HermesAgent/HermesAgentIndexTests.swift
lines 70-86 (direct repository-path filter) and lines 105-113 (canonicalized
symlink-path filter); both test sites require no direct changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: faf94b9e-8ad0-436a-a788-8916e19d31b0
📒 Files selected for processing (3)
Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/Vault/Providers/HermesAgent/HermesAgentIndexTests.swiftcmux.xcodeproj/project.pbxprojcmuxTests/HermesFirstClassSupportTests.swift
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CLI/CMUXCLI`+AgentHookCatalog.swift:
- Line 177: Update the Hermes agent hook installation around the .pinned
dispatch and pinnedAgentHookSocketPath() so it requires CMUX_SOCKET_PATH or
CMUX_TAG before enabling pinned routing. Fail installation when neither variable
is available, or retain ambient dispatch until the installer explicitly supplies
one, ensuring Hermes callbacks cannot run without the intended CMUX socket.
In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/HermesAgentHookConfig.swift`:
- Around line 371-374: Update isCmuxOwnedCommand to use boundary-aware matching
for the expected cmux-hermes-agent-hook-v2 and hooks hermes-agent command forms
instead of arbitrary substring checks. Include the cmux hooks feed --source
hermes-agent --event <value> form in the uninstall owner classification so feed
approvals are removed during cleanup.
In `@Sources/VaultPersistedSessionResolver.swift`:
- Around line 21-51: Refactor registerFreshProcesses so it reuses the scanner’s
existing derivation of VaultObservedAgentProcess, normalized cwd, and matched
registry registration instead of recomputing them. Update the scanner/resolver
interface to pass those derived values into registerFreshProcesses, or extract a
shared helper used by both paths; remove the duplicate Self.normalized logic and
preserve identical matching and uniqueness behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 680ab72e-709f-4dc5-9121-3b92d71a398f
📒 Files selected for processing (14)
CLI/CMUXCLI+AgentHookCatalog.swiftCLI/CMUXCLI+AgentHookDefinitions.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/HermesAgentHookConfig.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/Vault/Providers/HermesAgent/HermesAgentIndex.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/Vault/Providers/HermesAgent/HermesAgentStateDBResolver.swiftSources/CmuxVaultAgentPersistedSessionStore.swiftSources/CmuxVaultAgentRegistration+Hermes.swiftSources/CmuxVaultAgentRegistry+ProcessMatching.swiftSources/HermesAgentIndex.swiftSources/SessionIndexRegisteredAgents.swiftSources/VaultAgentProcessScanner.swiftSources/VaultAgentRegistry.swiftSources/VaultPersistedSessionResolver.swiftcmux.xcodeproj/project.pbxproj
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
CLI/CMUXCLI+AgentHookCatalog.swift (1)
162-180: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winRestore pinned Hermes Agent dispatch.
AgentHookDefdefaultsdispatchto.ambient. The shared generator now selects routing only from this field. Hermes Agent omits the field.The installed Hermes command therefore uses the ambient branch. When Hermes does not preserve
CMUX_SURFACE_ID, that branch returns the no-op. The install also bypassesvalidateHookInstallDispatch(for:), so it can write hooks without a target socket.Set Hermes Agent to
.pinnedwith its stable marker. Keep coverage that rejects a no-target install before configuration mutation. This regresses the previously addressed Hermes routing issue.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@CLI/CMUXCLI`+AgentHookCatalog.swift around lines 162 - 180, Update the Hermes Agent definition in AgentHookCatalog to set dispatch to .pinned and provide its stable hook marker, rather than relying on AgentHookDef’s ambient default. Ensure the Hermes installation path invokes validateHookInstallDispatch(for:) and rejects missing target sockets before mutating configuration, preserving coverage for that no-target failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CLI/cmux.swift`:
- Around line 29559-29561: The unconditional validateHookInstallDispatch call in
installAgentHooks currently aborts runSetupHooks for the first missing pinned
socket and prevents later agents from being processed. Update the validation
flow so a pinned-socket failure is handled only for the affected agent without
propagating the error to the overall setup command, while preserving
installation and per-agent status processing for agents with .noSocket or .any
policies.
In `@Resources/bin/cmux-hermes-agent-wrapper`:
- Around line 195-203: Bound the synchronous hooks hermes-agent install
invocation in the wrapper so it cannot delay exec "$REAL_HERMES" indefinitely.
Inspect Resources/bin/cmux-claude-wrapper for the existing timeout pattern and
apply the same mechanism to both CMUX_SOCKET_PATH branches around the installer
command, preserving the existing non-blocking failure behavior.
- Around line 89-111: Align hermes_known_subcommand and
hermes_option_consumes_value with the documented Hermes CLI v0.19.0 surface:
remove acp, console, serve, desktop, gui, and lsp from the administrative
subcommand list, and remove -m, --model, --provider, -t, --toolsets, and -s from
value-consuming options while retaining supported entries. Add a reference to
the v0.19.0 CLI documentation above both functions for future auditing.
In `@Resources/Localizable.xcstrings`:
- Around line 40263-40279: Expand the localizations for
cli.hooks.error.pinnedTargetMissing to include translated stringUnit entries for
every locale already supported in Resources/Localizable.xcstrings, preserving
the existing English and Japanese translations and matching the catalog’s
established locale set and formatting.
In `@Sources/VaultPersistedSessionResolver.swift`:
- Around line 26-33: Update the persisted-store owner counting logic around
freshProcessCountByKey so matching processes are counted regardless of whether
explicitSessionID returns a value; retain explicit flags for that process’s
session-resolution behavior. Add a regression test covering one explicit-session
process, one bare Hermes process, and one active state.db row, asserting the
bare process fails closed.
In `@tests/test_hermes_wrapper_hooks.py`:
- Around line 168-178: Update the WrapperResult construction to guard the
real_env_log read just like cmux_env_log, returning an empty environment when
the log file is absent. Preserve normal read_environment behavior when
real_env_log exists so wrapper failures produce a result with captured stderr
instead of raising FileNotFoundError.
---
Outside diff comments:
In `@CLI/CMUXCLI`+AgentHookCatalog.swift:
- Around line 162-180: Update the Hermes Agent definition in AgentHookCatalog to
set dispatch to .pinned and provide its stable hook marker, rather than relying
on AgentHookDef’s ambient default. Ensure the Hermes installation path invokes
validateHookInstallDispatch(for:) and rejects missing target sockets before
mutating configuration, preserving coverage for that no-target failure.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e5e5e52e-0330-4ce9-a568-d21391e30ca2
📒 Files selected for processing (43)
.github/workflows/ci.ymlCLI/CMUXCLI+AgentHookCatalog.swiftCLI/CMUXCLI+AgentHookDefinitions.swiftCLI/CMUXCLI+ExecutableResolution.swiftCLI/CMUXCLI+HermesAgentHooks.swiftCLI/cmux.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/HermesAgentHookCommandOwnership.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/HermesAgentHookConfig.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/HermesAgentHookConfigTests.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Runtime/TerminalSurfaceRuntimeFilesystem.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurface+AgentCommandShims.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurface+StartupEnvironment.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurfaceAgentCommandShimDefinition.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+AgentCommandShimLifecycle.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+ClaudeCommandShimLifecycle.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+RuntimeLifecycle.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+RuntimeSurfaceCreation.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/ManualAgentCommandShimInstaller.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceCloseConfirmationTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceCommandShimPermissionsTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceExplicitInputTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceFontSizeLineageTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfacePortalHostVacancyTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceRendererPresentationTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceRestoreSpawnSchedulerTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceTeardownCallbackLifetimeTests.swiftPackages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceAgentCommandShim.swiftPackages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceAgentCommandShimSet.swiftPackages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceClaudeCommandShim.swiftPackages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceCodexCommandShim.swiftResources/Localizable.xcstringsResources/bin/cmux-hermes-agent-wrapperSources/AgentExecutableResolver.swiftSources/TerminalSurfaceRuntimeWiring.swiftSources/VaultAgentProcessScanner.swiftSources/VaultPersistedSessionResolver.swiftcmux.xcodeproj/project.pbxprojcmuxTests/AgentExecutableResolverTests.swiftcmuxTests/CLIGenericHookPersistenceTests.swiftcmuxTests/GhosttyTerminalStartupEnvironmentTests.swiftcmuxTests/HermesFirstClassSupportTests.swifttests/test_hermes_wrapper_hooks.py
💤 Files with no reviewable changes (4)
- Packages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceCodexCommandShim.swift
- Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+ClaudeCommandShimLifecycle.swift
- Packages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceClaudeCommandShim.swift
- Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurface+StartupEnvironment.swift
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/test_hermes_wrapper_hooks.py`:
- Around line 67-68: Replace timing-based assertions in the installer-delay
regression tests with synchronization on a test-controlled installer signal and
a deadline-bounded poll of real_args_log or another Hermes-launch predicate.
Start the wrapper asynchronously, assert the launch signal rather than
elapsed_seconds, then release or clean up the blocked installer and await
completion. Update the related cases around installer_delay_seconds, timeout
handling, and the referenced test blocks consistently, without fixed sleeps or
latency-based correctness checks.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d3e97702-0519-47ad-b936-3acf8659fd4b
📒 Files selected for processing (2)
cmuxTests/HermesFirstClassSupportTests.swifttests/test_hermes_wrapper_hooks.py
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
|
Addressing the outside-diff Hermes dispatch finding: Hermes intentionally remains |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CLI/CMUXCLI`+HermesAgentHooks.swift:
- Around line 82-85: Update the createDirectory error handling in the
config-directory setup to throw a distinct user-facing CLIError for directory
creation failures, directing the user to check parent-directory permissions or
read-only filesystem conditions. Keep configDirectoryFileError unchanged for the
existing Lines 77-80 file-conflict path.
In
`@Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurface`+AgentCommandShims.swift:
- Around line 96-111: Disable pathname expansion around the PATH-splitting loop
in the generated shell shim, while preserving the intentional IFS-based word
splitting of ${PATH:-}. Update the shell state surrounding the `for cmux_entry
in ${PATH:-}` loop in the command shim generation flow, then restore the
previous globbing state afterward so subsequent command execution is unaffected.
In `@Resources/bin/cmux-hermes-agent-wrapper`:
- Around line 93-96: Update the timeout validation in the
CMUX_HERMES_AGENT_HOOK_INSTALL_TIMEOUT_SECONDS handling to reject zero and other
non-positive values, including decimal representations such as 0.0, while
preserving acceptance of valid positive timeouts and the existing best-effort
skip behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 2b885252-e05d-45c2-a26e-2eb169921ffb
📒 Files selected for processing (52)
.github/workflows/ci.ymlCLI/CMUXCLI+AgentHookCatalog.swiftCLI/CMUXCLI+AgentHookDefinitions.swiftCLI/CMUXCLI+ExecutableResolution.swiftCLI/CMUXCLI+HermesAgentHooks.swiftCLI/cmux.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/HermesAgentHookCommandOwnership.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/HermesAgentHookConfig.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/Vault/Providers/HermesAgent/HermesAgentIndex.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/Vault/Providers/HermesAgent/HermesAgentStateDBResolver.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/HermesAgentHookConfigTests.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/Vault/Providers/HermesAgent/HermesAgentIndexTests.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Runtime/TerminalSurfaceRuntimeFilesystem.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurface+AgentCommandShims.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurface+StartupEnvironment.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurfaceAgentCommandShimDefinition.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+AgentCommandShimLifecycle.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+ClaudeCommandShimLifecycle.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+RuntimeLifecycle.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+RuntimeSurfaceCreation.swiftPackages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/ManualAgentCommandShimInstaller.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceCloseConfirmationTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceCommandShimPermissionsTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceExplicitInputTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceFontSizeLineageTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfacePortalHostVacancyTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceRendererPresentationTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceRestoreSpawnSchedulerTests.swiftPackages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceTeardownCallbackLifetimeTests.swiftPackages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceAgentCommandShim.swiftPackages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceAgentCommandShimSet.swiftPackages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceClaudeCommandShim.swiftPackages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceCodexCommandShim.swiftResources/Localizable.xcstringsResources/bin/cmux-hermes-agent-wrapperSources/AgentExecutableResolver.swiftSources/CmuxVaultAgentPersistedSessionStore.swiftSources/CmuxVaultAgentRegistration+Hermes.swiftSources/CmuxVaultAgentRegistry+ProcessMatching.swiftSources/HermesAgentIndex.swiftSources/SessionIndexRegisteredAgents.swiftSources/TerminalSurfaceRuntimeWiring.swiftSources/VaultAgentProcessScanner.swiftSources/VaultAgentRegistry.swiftSources/VaultPersistedSessionResolver.swiftcmux.xcodeproj/project.pbxprojcmuxTests/AgentExecutableResolverTests.swiftcmuxTests/CLIGenericHookPersistenceTests.swiftcmuxTests/GhosttyTerminalStartupEnvironmentTests.swiftcmuxTests/HermesFirstClassSupportTests.swifttests/test_hermes_wrapper_hooks.py
💤 Files with no reviewable changes (4)
- Packages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceClaudeCommandShim.swift
- Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurface+StartupEnvironment.swift
- Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+ClaudeCommandShimLifecycle.swift
- Packages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceCodexCommandShim.swift
|
Review closeout for
The remaining inline findings are also fixed: Hermes mkdir failures now distinguish permissions from a conflicting file, shim PATH splitting preserves literal glob characters and caller shell state, and zero installer timeouts cannot disable the deadline. Warning triage:
Validation: tagged Debug build, |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0ff8b44. Configure here.
|
Verified on HEAD e5cdb71 with the tagged hermes-resume-final app: the actual Vault context-menu action for the top Hermes row resumed the existing durable session through the managed wrapper, restored the live transcript, and emitted a fresh Hermes session-start hook. The standalone Hermes wrapper regression harness also passes. Prior verification covered 41 Hermes CMUXAgentLaunch tests and two clean quit/relaunch autoresume cycles. No session-not-found marker appeared on the current build. |

Closes #9520
Summary
Hook architecture
Hermes 0.20.0 shell hooks remain the single consent-controlled event path for CLI/TUI and Gateway sessions. They expose the lifecycle, LLM, tool, and approval events cmux needs and are governed by shell-hooks-allowlist.json, so this PR does not add a duplicate Python plugin or Gateway-only HOOK.yaml bridge.
The TUI has one process-boundary exception: Hermes's Python launcher creates
hermes-tui-active-session-*.jsononly after the outer cmux wrapper execs Hermes, and the fresh TUI gateway cannot inherit the launcher's process-local hook registry. Interactive TUI launches therefore receive an invocation-privateTMPDIRplus a scopedHERMES_PYTHONbootstrap. The bootstrap activates only fortui_gateway.entryandtui_gateway.compute_host, registering prompt, response, approval, feed, and turn-end callbacks inside the processes that execute every turn. It filters the cmux lifecycle callbacks owned by the watcher, which accepts exactly one non-symlink active-session file, validates its session ID, and feeds the initial session,/newtransitions, and finalization into the sharedcmux hooks hermes-agentlifecycle path with the launch's workspace, surface, and tagged socket attribution. Classic--clilaunches skip both bridges.The watcher blocks on an anonymous pipe driven by one persistent 100 ms ticker, which is compatible with macOS Bash 3.2. It uses neither fractional
read -tnor a filesystem FIFO; if the ticker fails, cleanup waits until Hermes has exited so a liveTMPDIRis never removed.Safety
The state.db lookup is read-only, bounded to two rows, and fails closed for missing cwd/schema, database errors, multiple active rows, or multiple fresh panes sharing one state-store/cwd key. Custom Vault registrations cannot acquire the built-in Hermes persisted-store capability.
Validation
20fe7baa8a; fixes:65e56c4f543d3a4e16acfails without the bridge; fix7d6ba1fc58passesbbbc36769crecords 1.24 CPU-seconds while idle; anonymous-pipe ticker fix3e263ff6dapasses656823b0bdfails when fresh gateway processes lack callbacks; scoped gateway bootstrapf568ecb99bpassesprompt-submit,agent-response,session-end,agentHook.stop.notify, and a notification-store recordcmux-unitscheme build succeeded with the GlobalISel workaroundCMUXAgentLaunch: 285/285 tests passedgit diff --checkpassedNeed help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Adds first‑class Hermes restore and lifecycle with durable
state.dbindexing, a TUI gateway bridge, profile‑pinned resumes, and shared agent command shims. Restores are routed through the managed wrapper for deterministic hooks and now keep older snapshots compatible by decoding persisted Hermes registrations. Addresses #9520.New Features
hermesStateDB(cwd-aware when available); only interactive CLI/TUI runs are restorable; resumes are pinned to the owning profile/HERMES_HOME.cmux-hermes-agent-wrapper,cmux-hermes-python-wrapper, andcmux-hermes-sitecustomize.py; watcher keeps active-session IDs correct and dedupes Hermes notifications.hermes,claude, andcodex; routes Hermes~/.local/binprofile aliases through the wrapper using a cached alias catalog.CMUX_HERMES_AGENT_WRAPPER_SHIM, ensuring hook reinstallation and deterministic profile pinning.Bug Fixes
-r<session>).Written for commit e5cdb71. Summary will update on new commits.
Summary by CodeRabbit
New Features
Improvements
Tests
Note
High Risk
Large surface area touching session identity, restore/exec paths, hook subprocess routing, and SQLite-backed recovery; mistakes could break resume or mis-attribute hooks across workspaces, though changes are heavily tested.
Overview
Adds first-class Hermes Agent support across hooks, Vault indexing, terminal shims, and restore—so cmux can attribute lifecycle events, persist resumable checkpoints, and relaunch through the managed wrapper like Claude and Codex.
Hooks and routing generalize agent hook dispatch via
HookDispatch(ambient vs pinned CLI/socket); Grok and Antigravity move to pinned markers. Hermes gets YAML hook install with config-dir creation, locked allowlist updates, deduped notifications, session-end as a turn boundary, and safer session-ID resolution (approval payloads, TUI active-session file in privateTMPDIR, never treating the surface UUID as Hermes identity). Pinned hook install now fails clearly when no running app/socket is available.Restore and durability extend
AgentRestoreLaunch/AgentRestorePlannerfor Hermes (wrapper shim env, profile/HERMES_HOMEpinning, Codex preflights).cmux restorecan repair corrupt Hermes checkpoints viaHermesLegacySessionIdentityRecoveryagainst hook state and read-onlystate.dbsnapshots; resume bindings validate session existence before pinning.Vault / indexing adds cwd-aware Hermes session search, batched recovery inspection, WAL-safe snapshot reads, and explicit
--resume/-rparsing on the persisted session store.Terminal replaces Claude-only PATH shims with a shared agent command shim set (
claude,codex,hermes) plus Hermes profile-alias discovery through a cached catalog; CLI executable resolution skips shim paths generically.Reviewed by Cursor Bugbot for commit 12ea44f. Bugbot is set up for automated code reviews on this repo. Configure here.