Skip to content

Fix fish resume cwd guard - #6891

Closed
austinywang wants to merge 24 commits into
mainfrom
issue-6285-fish-resume-cwd-guard
Closed

austinywang wants to merge 24 commits into
mainfrom
issue-6285-fish-resume-cwd-guard

Conversation

@austinywang

@austinywang austinywang commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #6285.

Summary

  • add behavior coverage for fish-safe generated resume cwd guards
  • wrap generated cwd guards in /bin/sh -c so fish login shells launch one external command instead of parsing POSIX brace grouping
  • strip persisted /bin/sh -c and older /bin/sh -lc wrappers to avoid nested startup commands
  • sanitize fish PR-cache variable names before universal-variable writes

Regression structure

  • Commit 1 adds fish-safe regression coverage only
  • Commit 2 implements the shared formatter fix and updates exact command expectations through the shared helper

Validation

  • git merge origin/main completed cleanly
  • git diff --check
  • fish -n Resources/shell-integration/fish/config.fish
  • direct fish runtime proof for existing cwd and missing-cwd fallback

Summary by cubic

Makes resume working-directory guards fish-safe by replacing legacy brace guards with a parent cd, running the payload directly or via /bin/sh -c only when needed. Safely rewrites portable-shell payloads (literal single-quoted only), preserves nonliteral quoting, bootstraps Hermes inside cwd wrappers, and repairs stale executables and legacy Codex provider names. Fixes #6285.

  • Bug Fixes

    • Replace legacy brace guards with a parent cd; detect and unwrap /bin/sh -c/-lc to edit only the inner payload, then rewrap with the original option; choose direct exec vs portable shell based on the payload.
    • Rewrite portable-shell payloads only when the inner command is literal single-quoted; skip double-quoted and mixed-quoted payloads; preserve original/nonliteral quoting when unchanged.
    • Normalize shell-wrapped legacy cwd guards; keep shell-specific commands in the parent shell; preserve explicit portable wrappers and repair their inner commands (Hermes bootstrap order: cd → bootstrap → run; stale agent executables inside portable cwd wrappers; launcher-script payloads). Add fish _cmux_pr_cache_variable_name to sanitize PR-cache variable names.
  • Refactors

    • Consolidate startup shell quoting and portable-shell parsing for parent-cd guards and payloads into TerminalStartupShellQuoting helpers.

Written for commit 53539ea. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added a Fish helper to generate safe cache variable names from branch names.
  • Bug Fixes
    • Improved startup-command rewriting for portable /bin/sh -c and /bin/sh -lc wrappers, including more reliable working-directory prefixing/stripping and shell quoting.
    • Fixed Hermes agent binding bootstrap and resume command generation when wrapped in portable shell commands.
    • Improved canonicalization of portable agent executable handling inside these wrappers.
  • Tests
    • Expanded and updated unit/integration tests to validate portable-shell payload extraction, working-directory wrapper behavior, and resume/binding expectations across multiple agent types.

@vercel

vercel Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 27, 2026 5:40am
cmux-staging Building Building Preview, Comment Jun 27, 2026 5:40am

@coderabbitai

coderabbitai Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Portable shell wrapping is added for restorable startup commands and Hermes bootstrapping. Related tests now assert the new command shapes, and a Fish helper adds sanitized cache-variable naming with integration coverage.

Changes

Portable startup command rendering

Layer / File(s) Summary
Working-directory prefix helpers
Sources/RestorableAgentSession.swift
TerminalStartupWorkingDirectoryPrefix now builds portable /bin/sh -c wrappers from workingDirectory, strips portable wrappers before legacy parsing, and uses extracted legacy quoting helpers.
Hermes startup rewriting
Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Session/WorkspaceHermesAgentCommandBootstrapper.swift
Hermes agent startup commands now detect portable shell wrappers, rewrite the inner command, and reconstruct the wrapper around the updated payload.
Portable wrapper validation
Packages/macOS/CmuxWorkspaces/Tests/CmuxWorkspacesTests/Session/WorkspaceSessionRestorePolicyServiceTests.swift, cmuxTests/AgentSessionAutoResumeSwiftTests.swift, cmuxTests/SessionPersistenceResumeBindingTests.swift, cmuxTests/FishShellIntegrationTests.swift
New tests assert Hermes bootstrap ordering inside portable shell wrappers, validate resume-command shapes and portable payload extraction, check legacy guard normalization, and exercise the shared prefix helper under fish.
Resume expectation updates
cmuxTests/AgentHibernationTests.swift, cmuxTests/CLIGenericHookPersistenceTests.swift, cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift, cmuxTests/PiVaultAgentPersistenceTests.swift, cmuxTests/RestorableAgentHookProviderHermesTests.swift, cmuxTests/RestorableAgentHookProviderResumeTests.swift, cmuxTests/RovoDevSessionIndexTests.swift
Resume-binding assertions across agent persistence, hook-provider, and session-index tests now build the startup prefix with TerminalStartupWorkingDirectoryPrefix.prefix(...) instead of inline cd-guard shell snippets.
SessionPersistence resume updates
cmuxTests/SessionPersistenceTests.swift
SessionPersistenceTests now expects the shared working-directory prefix for resume and fork commands across Antigravity, Claude, Codex, Codex Teams, Hermes, and OpenCode cases, and adds portable payload extraction helpers.
Fork and launch inputs
cmuxTests/WorkspaceUnitTests.swift
Fork-command assertions and workspace launch inputs now use TerminalStartupWorkingDirectoryPrefix.prefix(...) for fallback-directory and local or remote workspace cases.

Fish cache variable helper

Layer / File(s) Summary
Cache variable naming
Resources/shell-integration/fish/config.fish, cmuxTests/FishShellIntegrationTests.swift
_cmux_pr_cache_variable_name sanitizes branch names for Fish universal variables, falls back to unknown when needed, and the fish integration test exercises the generated identifier.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • manaflow-ai/cmux#4237: Shares the resume-command wrapping and portable startup payload handling that this PR extends across restore and hook flows.
  • manaflow-ai/cmux#6146: Also changes Hermes startup-command rewriting in WorkspaceHermesAgentCommandBootstrapper.swift.
  • manaflow-ai/cmux#6582: Covers portable shell command parsing and executable repair logic that aligns with the new /bin/sh -c handling here.

Poem

I hop through shells where prompts now glide,
With /bin/sh -c as my fluffy ride.
I nibble cache names, neat and bright,
And launch the resume path just right.
Hooray for tabs that wake and hop! 🐇


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 3 warnings)

Check name Status Explanation Resolution
Cmux No Ambient Global State ❌ Error Sources/RestorableAgentSession.swift adds top-level static-namespace enums (TerminalStartupShellQuoting/WorkingDirectoryPrefix), which this rule treats as ambient helper bags. Move the quoting/prefix behavior onto an owning constructable type (or fileprivate pure funcs) instead of new caseless enum namespaces.
Out of Scope Changes check ⚠️ Warning The PR also adds an unrelated fish PR-cache variable sanitizer, which is outside the cwd-guard issue scope. Split the PR or remove the PR-cache variable-name sanitizer unless it is required by #6285.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description covers summary and validation, but it omits the required Demo Video, Review Trigger, and Checklist sections from the template. Add the missing template sections, including a demo video placeholder, the review trigger block, and a completed checklist.
✅ Passed checks (21 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main fish cwd-guard fix.
Linked Issues check ✅ Passed The changes wrap the resume cwd guard in a portable shell command and add tests, matching #6285's fish-login-shell requirement.
Cmux Swift Actor Isolation ✅ Passed The Swift changes are pure nonisolated utilities/value types; no new MainActor-bound models, service protocols, or Sendable mutable reference types were introduced.
Cmux Swift Blocking Runtime ✅ Passed Production Swift changes only add portable shell parsing/rewriting; no waits, sleeps, locks, or sync blocking were introduced, and blocking primitives appear only in tests.
Cmux Browser Automation Off-Main ✅ Passed No browser automation code changed: the submodule diff only touches include/ghostty.h, src/Surface.zig, and src/apprt/embedded.zig, with no browser/WebKit routing or policy-test changes.
Cmux Expensive Synchronous Load ✅ Passed The PR only changes portable-shell startup string handling; the expensive RestorableAgentSessionIndex.load() remains in its existing off-main cache/Task.detached path.
Cmux Cache Substitution Correctness ✅ Passed Touched production code only rewrites startup commands; it doesn’t replace any fresh persistence/snapshot read with a cached value.
Cmux No Hacky Sleeps ✅ Passed Diff only moves submodule pointers; the ghostty submodule changes are Zig/C files and the keyword scan found no sleeps/delays/timers/polling.
Cmux Algorithmic Complexity ✅ Passed PASS: The changes only add single-command token parsing and tiny fixed-size scans; no nested rescans, batch per-item rescans, or hot-path workspace-scale sorting/filtering.
Cmux Swift Concurrency ✅ Passed Production Swift changes only rewrite shell commands; no new DispatchQueue, Combine, completion-handler, or fire-and-forget Task patterns were added.
Cmux Swift @Concurrent ✅ Passed PR adds only synchronous shell/fixture helpers and tests; no changed Swift diff introduces async work or @concurrent annotations.
Cmux Swift File And Package Boundaries ✅ Passed Existing files only; additions are small (34–52 lines) and stay in focused shell/command parsing helpers, not mixed UI/state/network code.
Cmux Swiftpm Lockfiles ✅ Passed Diff only updates vendored submodule gitlinks (ghostty, vendor/bonsplit); no cmux Package.resolved, .gitignore, Xcode, or workflow changes appear.
Cmux Swift Logging ✅ Passed No added production Swift logging APIs or Logger constants were found; only shell printf strings in command builders/tests changed.
Cmux User-Facing Error Privacy ✅ Passed The diff only changes internal command-building and tests; it adds no user-facing error, alert, or recovery copy exposing private implementation details.
Cmux Full Internationalization ✅ Passed The PR only changes command/config logic, shell helpers, and tests; no user-facing Swift/web copy or locale catalogs were added or modified.
Cmux Swiftui State Layout ✅ Passed Touched files are command/config/test code; no new SwiftUI state, GeometryReader layout measurement, lazy-row store refs, or render-time state mutation appear.
Cmux Architecture Rethink ✅ Passed PASS: Small correctness fix in shared shell-command helpers; no sleeps, locks, observers, side channels, or split ownership, and /bin/sh -c is the required platform bridge.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only touches startup-command rewriting, fish config, and tests; no standalone window/controller code or cmuxAuxiliaryWindowIdentifiers changes, so the rule isn’t triggered.
Cmux Source Artifacts ✅ Passed Changed paths are submodule gitlinks to source/test commits only; no logs, caches, build output, or scratch dirs were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Production diffs add portable-shell/quoting helpers only; no new DEBUG/test-only members or test seam accessors appear in Sources/.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-6285-fish-resume-cwd-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes fish shell incompatibility with resume working-directory guards by replacing POSIX brace groups ({ cd ... }) with a fish-safe parent-cd form (cd -- 'path' 2>/dev/null || [ ! -d 'path' ] && command), and adds backward-compat migration logic to strip and rewrite persisted guards in legacy formats.

  • Core guard format change (RestorableAgentSession.swift): TerminalStartupWorkingDirectoryPrefix.prefix now generates the brace-free form; strippedLegacyChangeDirectoryPrefix recognises both old and new formats and strippedPortableChangeDirectoryCommand migrates /bin/sh -lc 'old-guard-payload' wrappers in place.
  • Portable-shell unpack/repack (SurfaceResumeCommandCanonicalizer, WorkspaceHermesAgentCommandBootstrapper): executable repair and hermes bootstrap insertion now detect … && /bin/sh -c 'payload' wrappers, operate on the inner command only, and re-quote it — skipping non-literal (double-quoted or mixed-quoted) payloads.
  • Fish variable sanitizer (config.fish): new _cmux_pr_cache_variable_name replaces non-identifier characters in branch names before writing fish universal variables.

Confidence Score: 5/5

Safe to merge. The guard format change is fully backward-compatible: stripping handles all prior formats, the new format round-trips correctly, and fish runtime tests confirm end-to-end behavior.

All changed production paths are covered by direct unit tests and fish integration tests. The stripping/re-prefixing logic is idempotent and handles the full matrix of old formats. No actor isolation, blocking runtime, or data-loss concerns were introduced.

No files require special attention. The two style notes about duplicated literalSingleQuoted and the inlined regex in portableShellCommandParts are non-blocking cleanup opportunities.

Important Files Changed

Filename Overview
Sources/RestorableAgentSession.swift Core fix: replaces POSIX brace-group cwd guard with fish-safe `cd -- 'path' 2>/dev/null
Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift Adds portable-shell detection to replacingPortableAgentExecutable: unpacks /bin/sh -c 'payload' wrappers, repairs the inner command, and re-quotes — only when the payload is a literal single-quoted word; adds literalSingleQuoted/isLiteralSingleQuotedShellWord helpers that duplicate implementations in the other two production files
Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Session/WorkspaceHermesAgentCommandBootstrapper.swift Refactors hermes startup preparation; adds portableShellCommand detection so bootstrap is inserted inside an existing /bin/sh -c 'payload' wrapper rather than blindly prepended, addressing the previously-flagged guard-blind-to-new-format issue
Resources/shell-integration/fish/config.fish Adds _cmux_pr_cache_variable_name helper that sanitizes branch names before use as fish universal variable names
cmuxTests/FishShellIntegrationTests.swift Adds fish runtime tests for variable name sanitization and generated cwd-prefix command execution against a real fish binary
cmuxTests/RestorableAgentNonInteractiveTests.swift New unit tests cover legacy guard migration, portable shell wrapper preservation, non-literal payload skipping, and shell-specific syntax handling
cmuxTests/AgentSessionAutoResumeSwiftTests.swift Adds test confirming Claude resume command with cwd emits the new brace-free format

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Incoming persisted command"] --> B{"Detect format"}
    B -- "/bin/sh -c|lc 'payload' (3 words)" --> C["portableShellCommandParts\n(strip legacy guard from payload,\nrewrap with new format)"]
    B -- "{ cd ... } && command\n(legacy brace group)" --> D["strippedLegacyChangeDirectoryPrefix\n(matches { cd ... } prefix)"]
    B -- "cd -- 'path' ... ] && command\n(new portable format)" --> E["strippedLegacyChangeDirectoryPrefix\n(matches portableParentCdPrefix)"]
    B -- "no cwd guard" --> F["command unchanged"]
    C --> G["prefix(stripped, cwd)\n→ cd -- 'path' 2>/dev/null || [ ! -d 'path' ] && /bin/sh -c|lc 'payload'"]
    D --> G2["prefix(stripped, cwd)\n→ cd -- 'path' 2>/dev/null || [ ! -d 'path' ] && command"]
    E --> G2
    subgraph "New guard format (fish-safe)"
    G
    G2
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["Incoming persisted command"] --> B{"Detect format"}
    B -- "/bin/sh -c|lc 'payload' (3 words)" --> C["portableShellCommandParts\n(strip legacy guard from payload,\nrewrap with new format)"]
    B -- "{ cd ... } && command\n(legacy brace group)" --> D["strippedLegacyChangeDirectoryPrefix\n(matches { cd ... } prefix)"]
    B -- "cd -- 'path' ... ] && command\n(new portable format)" --> E["strippedLegacyChangeDirectoryPrefix\n(matches portableParentCdPrefix)"]
    B -- "no cwd guard" --> F["command unchanged"]
    C --> G["prefix(stripped, cwd)\n→ cd -- 'path' 2>/dev/null || [ ! -d 'path' ] && /bin/sh -c|lc 'payload'"]
    D --> G2["prefix(stripped, cwd)\n→ cd -- 'path' 2>/dev/null || [ ! -d 'path' ] && command"]
    E --> G2
    subgraph "New guard format (fish-safe)"
    G
    G2
    end
Loading

Reviews (18): Last reviewed commit: "Merge branch 'main' of https://github.co..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@cmuxTests/SessionPersistenceResumeBindingTests.swift`:
- Around line 408-413: The oversized restore test is assuming restoredInput is
always in the “/bin/sh -c <payload>” shape, but the startup-input path can emit
a launcher script such as “/bin/zsh '<script>'” for long commands. Update the
restore assertion flow around restoredInput and portableShellCommandPayload so
it can extract and validate the launcher-script payload before checking the
portable-wrapper contents, or keep the fixture within the inline limit; apply
the same handling in the duplicate restore assertions referenced by the
SessionPersistenceResumeBindingTests helper.
🪄 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

Run ID: cf5a1904-4f4f-4dc1-818a-3d536ce27c86

📥 Commits

Reviewing files that changed from the base of the PR and between 3d94421 and a8457a7.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (2)
  • Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift
  • cmuxTests/SessionPersistenceResumeBindingTests.swift

Comment thread cmuxTests/SessionPersistenceResumeBindingTests.swift
@austinywang
austinywang force-pushed the issue-6285-fish-resume-cwd-guard branch from a8457a7 to 46154bc Compare June 26, 2026 17:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@cmuxTests/SessionPersistenceResumeBindingTests.swift`:
- Around line 555-560: The test helper in SessionPersistenceResumeBindingTests
is parsing launcher-script content with a hardcoded dropFirst(2), which is
fragile if SurfaceResumeBindingScriptStore.writeLauncherScript changes its
header layout or returnToLoginShell behavior. Update the parsing in the
inlineInput extraction path to identify the actual command section via a
sentinel or other structure-aware logic instead of relying on a fixed line
count, while keeping the /bin/zsh branch and portableShellCommandPayload(from:)
flow intact.
🪄 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

Run ID: 09796850-5ca0-4b28-a034-4ea4b2d90f43

📥 Commits

Reviewing files that changed from the base of the PR and between 46154bc and db26a7f.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (1)
  • cmuxTests/SessionPersistenceResumeBindingTests.swift

Comment thread cmuxTests/SessionPersistenceResumeBindingTests.swift

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmuxTests/SessionPersistenceTests.swift (1)

4426-4438: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the cwd invariant in this regression test.

This now passes even if normalization drops the working-directory hop entirely; /bin/sh -c 'codex resume session' still satisfies all three assertions. Reuse the existing leadingCdCommand/assertZshCommandChangesDirectory helpers here so the test still proves the issue’s cwd-preservation contract.

Suggested tightening
-func testAgentHookSurfaceResumeBindingNormalizesLegacyGuardToSingleExternalCommand() {
+func testAgentHookSurfaceResumeBindingNormalizesLegacyGuardToSingleExternalCommand() throws {
     let binding = SurfaceResumeBindingSnapshot(
         command: "{ cd -- '/tmp/project' 2>/dev/null || [ ! -d '/tmp/project' ]; } && codex resume session",
         cwd: "/tmp/project",
         source: "agent-hook",
         updatedAt: 1
     )

     XCTAssertTrue(binding.command.hasPrefix("/bin/sh -c "), binding.command)
     XCTAssertFalse(binding.command.hasPrefix("{ "), binding.command)
     XCTAssertTrue(binding.command.contains("codex resume session"), binding.command)
+    let cdCommand = try leadingCdCommand(from: binding.command)
+    try assertZshCommandChangesDirectory(cdCommand, expectedPath: "/tmp/project")
 }

As per coding guidelines, "When a user says tests missed a bug, add or adjust behavior-level coverage around the exact repro path before claiming the fix is complete."

🤖 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 `@cmuxTests/SessionPersistenceTests.swift` around lines 4426 - 4438, The
regression test for SurfaceResumeBindingSnapshot normalization is too weak
because it only checks the command prefix and resume text, so it can still pass
when the cwd-preserving hop is removed. Tighten
testAgentHookSurfaceResumeBindingNormalizesLegacyGuardToSingleExternalCommand by
reusing the existing leadingCdCommand and assertZshCommandChangesDirectory
helpers to assert the command still performs the directory change before
invoking codex resume session, ensuring the cwd invariant remains part of the
behavior-level coverage.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In `@cmuxTests/SessionPersistenceTests.swift`:
- Around line 4426-4438: The regression test for SurfaceResumeBindingSnapshot
normalization is too weak because it only checks the command prefix and resume
text, so it can still pass when the cwd-preserving hop is removed. Tighten
testAgentHookSurfaceResumeBindingNormalizesLegacyGuardToSingleExternalCommand by
reusing the existing leadingCdCommand and assertZshCommandChangesDirectory
helpers to assert the command still performs the directory change before
invoking codex resume session, ensuring the cwd invariant remains part of the
behavior-level coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 39097329-0763-4d66-91f1-76ea454cfb2d

📥 Commits

Reviewing files that changed from the base of the PR and between db26a7f and c40428b.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (1)
  • cmuxTests/SessionPersistenceTests.swift

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — 53539ea1 Deployed Jun 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resume binding cwd-guard uses POSIX { cd ...; } grouping that fish cannot parse (persists after #5678)

3 participants