Skip to content

Extract workspace session restore policy service - #6146

Merged
azooz2003-bit merged 4 commits into
mainfrom
feat-workspace-decomp
Jun 16, 2026
Merged

azooz2003-bit merged 4 commits into
mainfrom
feat-workspace-decomp

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Extract workspace session restore policy into WorkspaceSessionRestorePolicyService in CmuxSession.
  • Keep app-owned DTOs, prompt UI, approval storage, Hermes defaults, and persistence wire formats in the app target behind narrow injected seams.
  • Add behavior tests for stored approval, prompt gating, agent-hook resume gating, Hermes Codex bootstrap rewrite, remote reconnect policy, scrollback replay, and OMX HUD tmux detection.
  • Ratchet .github/swift-file-length-budget.tsv for Sources/Workspace.swift from 12223 to 11868 lines.

Domain rationale

I selected the workspace session restore policy / surface-resume launch planning cluster because it was the largest clean non-latency domain in Sources/Workspace.swift: it decides restore scrollback policy, remote reconnect behavior, surface resume approval, Hermes Codex bootstrap rewriting, tmux HUD restoration, and startup launch payloads. It does not touch Ghostty terminal rendering, TabItemView, ContentView's equatable ForEach, WindowTerminalHostView.hitTest, or recorder-coupled debug UI paths.

Moved methods and types

  • resolvedSnapshotTerminalScrollback
  • shouldReplaySessionScrollback
  • shouldAutoConnectRestoredRemote
  • surfaceResumeStartupInput
  • surfaceResumeStartupLaunch
  • approvedSurfaceResumeBinding
  • restorableTmuxStartCommand
  • shouldPersistSessionScrollback
  • Hermes agent command provider rewrite, bootstrap removal/insertion, shell word parsing, quoting, assignment detection, OMX HUD command detection
  • SurfaceResumeStartupLaunch moved as WorkspaceSurfaceResumeStartupLaunch

Injected seams

  • Surface resume approval storage: applyStoredApproval
  • Prompt UI decision: shouldRunPromptedSurfaceResume
  • Automated-test detection: isRunningUnderAutomatedTests
  • Scrollback truncation policy: truncateScrollback
  • Hermes Codex defaults: WorkspaceHermesCodexEnvironment
  • Filesystem launcher-script dependencies: FileManager and temporaryDirectory
  • App restore DTOs: WorkspaceSurfaceResumeBinding, WorkspaceSessionRemoteRestoreSnapshot, WorkspaceSessionRemoteRestorePanelSnapshot, WorkspaceSessionRemoteRestoreTerminalSnapshot

Verification

  • swift build in Packages/CmuxSession
  • swift test in Packages/CmuxSession, 19 tests passed
  • scripts/lint-ios-package-conventions.sh, no unjustified convention violations
  • xcodebuild -project cmux.xcodeproj -scheme cmux -configuration Debug -destination 'platform=macOS' -derivedDataPath /tmp/cmux-workspacedecomp build > /tmp/cmux-workspacedecomp-build.log 2>&1
  • grep '** BUILD SUCCEEDED **' /tmp/cmux-workspacedecomp-build.log

Notes

Sources/Workspace.swift changed from 12223 to 11868 lines, a 355-line net reduction. I kept the scope to the coherent restore-policy domain rather than moving unrelated singleton or latency-sensitive paths just to inflate the line count.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Extracted workspace session restore policy into WorkspaceSessionRestorePolicyService in CmuxSession and wired Workspace to it. Also made the composer dictation text merger injectable; Workspace.swift drops by 357 lines.

  • Refactors
    • Added WorkspaceSessionRestorePolicyService with seams for approval storage, prompt UI, test detection, scrollback truncation, Hermes Codex defaults, and filesystem paths.
    • Introduced protocol seams: WorkspaceSurfaceResumeBinding, WorkspaceSessionRemoteRestoreSnapshot (+ panel/terminal), and WorkspaceSurfaceResumeStartupLaunch.
    • Implemented WorkspaceHermesAgentCommandBootstrapper to strip old bootstrap, replace --provider openai-codex, and insert Codex bootstrap only when allowed.
    • Conformed app DTOs (SurfaceResumeBindingSnapshot, Session*Snapshot) to the new protocols; Workspace now delegates auto-connect, scrollback replay/persist, tmux HUD detection, and resume approval/launch to the service.
    • Fixed restore gates: prompt approval and agent-hook auto-resume now respect the new service decisions.
    • Renamed ComposerDictationTextMerge to ComposerDictationTextMerger, injected it into ComposerDictationController, and updated tests.
    • Added behavior tests for stored approval, prompt gating, agent-hook auto-resume, remote reconnect policy, scrollback resolution/replay, and OMX HUD tmux detection.

Written for commit e4dc531. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Refactor
    • Reworked session restoration into an injectable restore policy service, improving remote reconnection eligibility, restorable command selection, and scrollback restore/replay decisions.
    • Introduced structured “remote restore snapshot” seams and a standardized surface resume startup launch representation.
  • New Features
    • Added Hermes Codex environment configuration and agent-hook command bootstrapping for restoring Codex settings.
  • Tests
    • Added/expanded session restore policy coverage.
  • Chores
    • Refactored dictation text merging to a dedicated merger instance; updated dictation tests accordingly.

@vercel

vercel Bot commented Jun 15, 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 16, 2026 4:17am
cmux-staging Building Building Preview, Comment Jun 16, 2026 4:17am

@coderabbitai

coderabbitai Bot commented Jun 15, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5dc03022-ee3a-44ec-8210-01b1a01142b1

📥 Commits

Reviewing files that changed from the base of the PR and between dc5ada1 and e4dc531.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (6)
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/ComposerDictationController.swift
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/ComposerDictationTextMerge.swift
  • Packages/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/ComposerDictationTests.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceHermesAgentCommandBootstrapper.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRestorePolicyService.swift
  • Packages/CmuxSession/Tests/CmuxSessionTests/WorkspaceSessionRestorePolicyServiceTests.swift
💤 Files with no reviewable changes (6)
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/ComposerDictationTextMerge.swift
  • Packages/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/ComposerDictationTests.swift
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/ComposerDictationController.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRestorePolicyService.swift
  • Packages/CmuxSession/Tests/CmuxSessionTests/WorkspaceSessionRestorePolicyServiceTests.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceHermesAgentCommandBootstrapper.swift

📝 Walkthrough

Walkthrough

Extracts all session-restore policy decisions from static helpers in Workspace into a new injectable WorkspaceSessionRestorePolicyService in the CmuxSession package. Introduces supporting protocols for remote restore snapshots and surface resume bindings, a WorkspaceHermesCodexEnvironment struct for Codex configuration, and a WorkspaceSurfaceResumeStartupLaunch enum. Workspace is updated to delegate through the service, and SessionPersistence types receive protocol conformances. Additionally refactors ComposerDictationTextMerge from static enum to instance-backed struct for testability.

Changes

Session Restore Policy Service

Layer / File(s) Summary
Remote restore snapshot protocol hierarchy
Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRemoteRestoreTerminalSnapshot.swift, WorkspaceSessionRemoteRestorePanelSnapshot.swift, WorkspaceSessionRemoteRestoreSnapshot.swift
Three composable Sendable protocols form a nested hierarchy: terminal defines optional isRemoteTerminal and remotePTYSessionID; panel associates a TerminalSnapshot and exposes optional terminal; workspace provides panels array of PanelSnapshot values.
Surface resume binding protocol and startup launch enum
Packages/CmuxSession/Sources/CmuxSession/WorkspaceSurfaceResumeBinding.swift, WorkspaceSurfaceResumeStartupLaunch.swift
WorkspaceSurfaceResumeBinding defines the Sendable contract for restored binding metadata (source, kind, command, environment, policy flags) and provides launcher-script methods. WorkspaceSurfaceResumeStartupLaunch is an Equatable/Sendable enum with .command and .input cases and computed initialCommand/initialInput accessors.
WorkspaceHermesCodexEnvironment struct
Packages/CmuxSession/Sources/CmuxSession/WorkspaceHermesCodexEnvironment.swift
A Sendable struct holding Codex configuration strings (customBaseURLEnvironmentKey, defaultProvider, codexResponsesAPIMode) and two injected @Sendable closures; exposes applyDefaultCodexBaseURL(to:) and defaultCodexModel(environment:) as public delegates.
Policy service initialization and decision methods
Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRestorePolicyService.swift (init + 8 public methods)
WorkspaceSessionRestorePolicyService is a generic Sendable struct initialized with injected closures and WorkspaceHermesCodexEnvironment. Implements scrollback resolution/replay, remote auto-connect decisions, approved binding approval, surface resume startup input/launch, restorable tmux command detection, and scrollback persistence policies.
Hermes agent command bootstrapper
Packages/CmuxSession/Sources/CmuxSession/WorkspaceHermesAgentCommandBootstrapper.swift
Prepares and rewrites Hermes agent startup commands: normalizes Codex base URL in environment, removes existing bootstrap prefix, replaces --provider openai-codex arguments, and injects generated bootstrap config. Backed by a shell-word tokenizer supporting quoted strings and escape sequences, plus helpers for command identification, bootstrap boundary detection, and OMX HUD filtering.
SessionPersistence protocol conformances
Sources/SessionPersistence.swift
SurfaceResumeBindingSnapshot conforms to WorkspaceSurfaceResumeBinding with requiresPromptApproval derived from approval policy. SessionTerminalPanelSnapshot, SessionPanelSnapshot, and SessionWorkspaceSnapshot receive empty conformances to the corresponding remote restore snapshot protocols.
Workspace delegation to policy service
Sources/Workspace.swift
Adds sessionRestorePolicy stored property, makeSessionRestorePolicyService factory, and optional initializer parameter. All previously-static restore helpers (auto-connect, tmux command, surface resume input/launch, scrollback persistence/replay/resolution, approved binding) are replaced with delegations to sessionRestorePolicy.
Policy service unit tests
Packages/CmuxSession/Tests/CmuxSessionTests/WorkspaceSessionRestorePolicyServiceTests.swift
Tests cover stored approval injection and forwarding, prompt-approval gating, agent-hook auto-resume gating, Hermes command generation with Codex provider/model rewriting, remote auto-connect based on PTY session ID presence, scrollback resolution/fallback, scrollback replay skip conditions, and OMX HUD command filtering.

ComposerDictation Instance Refactoring

Layer / File(s) Summary
ComposerDictationTextMerger struct
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/ComposerDictationTextMerge.swift
Refactors ComposerDictationTextMerge enum to ComposerDictationTextMerger struct. The merged(base:transcript:) method changes from static to instance. Text-joining behavior (whitespace trimming, spacing insertion) is unchanged.
ComposerDictationController instance integration
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/ComposerDictationController.swift
Stores a ComposerDictationTextMerger instance (textMerger) with initializer accepting optional parameter (defaulting to new ComposerDictationTextMerger()). Recognition callback uses self.textMerger.merged() instead of static call. Documentation updated to reference the struct type.
ComposerDictation test suite updates
Packages/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/ComposerDictationTests.swift
Adds suite-scoped textMerger property initialized with ComposerDictationTextMerger(). All "Text merge" test implementations call textMerger.merged() instead of ComposerDictationTextMerge.merged(), preserving assertion logic.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(173, 216, 230, 0.5)
    note over Workspace: Session Restore Approval Flow
    participant Workspace
    participant WorkspaceSessionRestorePolicyService as Service
    participant applyStoredApproval
    participant shouldRunPromptedSurfaceResume
  end

  Workspace->>Service: approvedSurfaceResumeBinding(binding, autoResumeAgentSessions)
  Service->>applyStoredApproval: apply stored approval
  applyStoredApproval-->>Service: updated Binding
  Service->>Service: rewrite Hermes agent command (provider, bootstrap)
  Service->>shouldRunPromptedSurfaceResume: check prompt gate
  shouldRunPromptedSurfaceResume-->>Service: Bool (approved/denied)
  Service-->>Workspace: Binding? (approved or nil)
  alt Approved Binding
    Workspace->>Service: surfaceResumeStartupLaunch(forApprovedBinding:)
    Service-->>Workspace: WorkspaceSurfaceResumeStartupLaunch (.command or .input)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • manaflow-ai/cmux#4777: Both PRs update session/agent restore to route restored work through Workspace.SurfaceResumeStartupLaunch and use launcher scripts for startup commands, with the main PR's new service wiring directly overlapping with that PR's launcher-script startup-command changes.
  • manaflow-ai/cmux#4851: Both PRs are connected through Hermes Codex resume/bootstrapping: they add/use Codex environment helpers that apply/derive CUSTOM_BASE_URL/HERMES_CODEX_BASE_URL and rewrite the Codex provider when generating Hermes agent resume/launch commands.
  • manaflow-ai/cmux#4237: The main PR introduces the new WorkspaceSurfaceResumeBinding protocol and wires SurfaceResumeBindingSnapshot into session-restore/policy flows, building directly on the surface-resume binding structures and restore behaviors added in the retrieved PR.

Poem

🐇 The policies hop from static to service,
With closures injected—each one quite nervous,
Hermes commands get a bootstrap rewrite,
And ComposerDictation merges with new might,
This refactor's a tidier warren! 🌿

🚥 Pre-merge checks | ✅ 20 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the primary change: extracting workspace session restore policy service into a dedicated package/module.
Description check ✅ Passed The description is comprehensive and well-structured, covering summary, testing verification, domain rationale, and moved methods with clear injected seams documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed All new public types are marked Sendable with proper @Sendable closure parameters. Workspace.swift remains @MainActor with sessionRestorePolicy private. Tests use justified @unchecked Sendable only...
Cmux Swift Blocking Runtime ✅ Passed PR introduces no new blocking/timing-based synchronization patterns; all 8 new production files and modified files are free of semaphores, locks, sleeps, delayed dispatch, polling, main-queue sync,...
Cmux Expensive Synchronous Load ✅ Passed PR is a refactor that moves 355 lines of existing session restore logic from Workspace.swift to WorkspaceSessionRestorePolicyService. No RestorableAgentSessionIndex.load() or other expensive synchr...
Cmux Cache Substitution Correctness ✅ Passed PR extracts session restore policy into a service with protocol seams; snapshots remain fresh parameters passed to decision methods, not cached substitutes for disk reads.
Cmux No Hacky Sleeps ✅ Passed Check is not applicable; PR contains only Swift source code changes. The rule explicitly covers non-Swift app/runtime (TypeScript, JavaScript, shell, build scripts); Swift is covered by separate ch...
Cmux Algorithmic Complexity ✅ Passed All operations work on inherently bounded collections: command strings (<10KB), shell words (~50 items), UI panels (<100). No nested scalable-collection scans, no per-target rescans, no hot-path re...
Cmux Swift Concurrency ✅ Passed No legacy async patterns (DispatchQueue for ordinary work, new Combine state, completion handlers where async is available, or fire-and-forget Tasks with lifecycle) introduced. All new closures are...
Cmux Swift @Concurrent ✅ Passed All new public types conform to Sendable; all closure parameters marked @Sendable; no async functions; UI-bound work properly isolated via MainActor.assumeIsolated; service methods are lightweight...
Cmux Swift File And Package Boundaries ✅ Passed PR extracts workspace session restore policy into CmuxSession package with single-responsibility files (191 & 331 lines, both under 400-line threshold), protocol seams for app DTOs, injected closur...
Cmux Swift Logging ✅ Passed All NSLog calls in production code are guarded by #if DEBUG, and no unguarded print/debugPrint/dump found in app/runtime code. No ad hoc logging, no MainActor violations, no exposed secrets.
Cmux User-Facing Error Privacy ✅ Passed No user-facing error messages, alerts, or sensitive information exposed. All new code in CmuxSession package contains only protocol definitions, service logic, and internal shell command constructi...
Cmux Full Internationalization ✅ Passed PR introduces no unlocalized user-facing text. New CmuxSession files contain infrastructure/protocols only; Workspace.swift modifications use String(localized:defaultValue:); refactoring is code-only.
Cmux Swiftui State Layout ✅ Passed PR introduces no new @Published/@StateObject/@EnvironmentObject; uses @Observable (modern pattern) in ComposerDictationController; no GeometryReader/lazy list violations; no render-time state mutat...
Cmux Architecture Rethink ✅ Passed PR extracts session restore policy using immutable dependency injection (no observers, locks, or timing paths); maintains clear single ownership via sessionRestorePolicy instance and protocol seams...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds no new user-visible NSWindow, NSPanel, NSWindowController, or SwiftUI Window/WindowGroup code. Changes are purely business logic extraction into CmuxSession package with protocol seams for...
Cmux Source Artifacts ✅ Passed All 15 changed files are legitimate source code, tests, and configuration files with no source control artifacts (local tool output, generated logs, screenshots, DerivedData, caches, temp folders,...

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feat-workspace-decomp

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 and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 15, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extracts the workspace session restore policy cluster from Sources/Workspace.swift into a new WorkspaceSessionRestorePolicyService<Binding> in Packages/CmuxSession, reducing Workspace.swift by 355 lines. The extraction is seamed by five injected @Sendable closures (approval storage, prompt UI, test detection, scrollback truncation, Hermes Codex defaults), keeping all app-lifecycle-coupled code in the app target while the policy logic becomes package-testable. A companion change renames ComposerDictationTextMerge (enum namespace) to ComposerDictationTextMerger (struct) to make the text-merge logic injectable.

  • Adds WorkspaceSessionRestorePolicyService, WorkspaceHermesAgentCommandBootstrapper, WorkspaceHermesCodexEnvironment, and five protocol seams to CmuxSession; wires Workspace to use the new service via a per-object stored instance and existing nonisolated static wrapper shims.
  • Hermes agent command bootstrapping (provider rewrite, bootstrap prefix removal/insertion, OMX HUD tmux detection) is moved verbatim into the new package where it is unit-tested by 19 new swift test cases.
  • The SurfaceResumeStartupLaunch enum is promoted to public enum WorkspaceSurfaceResumeStartupLaunch in CmuxSession and typealiased back in Workspace.swift for callsite compatibility.

Confidence Score: 5/5

Safe to merge; the extraction is behavior-preserving and all moved code is covered by 19 new package-level tests.

Every policy decision (approval storage, prompt gating, Hermes bootstrap rewrite, remote reconnect, scrollback replay) was moved verbatim into WorkspaceSessionRestorePolicyService with injected seams and a full test suite. The Workspace.swift wrappers delegate directly to the new service using the same arguments; no conditional logic was altered. The two observations are dead code and a file-naming mismatch — neither affects runtime behavior.

No files require special attention; WorkspaceHermesAgentCommandBootstrapper.swift has a minor dead-code note but is otherwise a faithful port.

Important Files Changed

Filename Overview
Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRestorePolicyService.swift New 191-line service struct; all stored state is @sendable closures or Sendable value types; FileManager is not stored (passed per-call); clean Sendable conformance.
Packages/CmuxSession/Sources/CmuxSession/WorkspaceHermesAgentCommandBootstrapper.swift 331-line bootstrapper; shell word parser, provider rewrite, bootstrap removal, and OMX HUD detection faithfully moved from Workspace.swift; one minor issue: commandAllowsCodexBootstrap's openai-codex branch is unreachable at its sole call site.
Packages/CmuxSession/Tests/CmuxSessionTests/WorkspaceSessionRestorePolicyServiceTests.swift 293-line test suite covering stored approval, prompt gating, agent-hook gate, Hermes bootstrap rewrite, remote reconnect, scrollback resolution/replay, and OMX HUD detection; all assertions match documented behavior.
Sources/Workspace.swift ~355 lines removed; wires per-instance sessionRestorePolicy and keeps nonisolated static shims delegating to makeSessionRestorePolicyService(); shouldRunPromptedSurfaceResumeOnMain kept in app target with correct MainActor isolation; no behavioral changes.
Sources/SessionPersistence.swift Three empty conformance extensions and one computed property bridge (requiresPromptApproval) added to wire app DTOs to CmuxSession protocols; no issues.
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/ComposerDictationTextMerge.swift Enum ComposerDictationTextMerge renamed to struct ComposerDictationTextMerger to allow injection; file name not updated to match new type name.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Workspace / static shim] -->|makeSessionRestorePolicyService| B[WorkspaceSessionRestorePolicyService]
    A2[Workspace instance] -->|sessionRestorePolicy| B
    B --> C{approvedSurfaceResumeBinding}
    C --> D[applyStoredApproval closure]
    D --> E[WorkspaceHermesAgentCommandBootstrapper]
    E --> F{source == agent-hook AND autoResumeAgentSessions?}
    F -->|blocked| G[nil]
    F -->|allowed| H{requiresPromptApproval?}
    H -->|yes| I[shouldRunPromptedSurfaceResume closure]
    I -->|denied| G
    I -->|approved| J[Approved Binding]
    H -->|no| K{allowsAutomaticResume?}
    K -->|no| G
    K -->|yes| J
    B --> L{surfaceResumeStartupLaunch}
    J --> L
    L -->|isAgentHookBinding| M[.command]
    L -->|otherwise| N[.input]
    B --> O[shouldAutoConnectRestoredRemote]
    B --> P[resolvedSnapshotTerminalScrollback]
    B --> Q[shouldReplaySessionScrollback]
    B --> R[restorableTmuxStartCommand / OMX HUD]
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[Workspace / static shim] -->|makeSessionRestorePolicyService| B[WorkspaceSessionRestorePolicyService]
    A2[Workspace instance] -->|sessionRestorePolicy| B
    B --> C{approvedSurfaceResumeBinding}
    C --> D[applyStoredApproval closure]
    D --> E[WorkspaceHermesAgentCommandBootstrapper]
    E --> F{source == agent-hook AND autoResumeAgentSessions?}
    F -->|blocked| G[nil]
    F -->|allowed| H{requiresPromptApproval?}
    H -->|yes| I[shouldRunPromptedSurfaceResume closure]
    I -->|denied| G
    I -->|approved| J[Approved Binding]
    H -->|no| K{allowsAutomaticResume?}
    K -->|no| G
    K -->|yes| J
    B --> L{surfaceResumeStartupLaunch}
    J --> L
    L -->|isAgentHookBinding| M[.command]
    L -->|otherwise| N[.input]
    B --> O[shouldAutoConnectRestoredRemote]
    B --> P[resolvedSnapshotTerminalScrollback]
    B --> Q[shouldReplaySessionScrollback]
    B --> R[restorableTmuxStartCommand / OMX HUD]
Loading

Reviews (2): Last reviewed commit: "Fix dictation text merger package lint" | Re-trigger Greptile

private let truncateScrollback: @Sendable (String?) -> String?
private let hermesCodexEnvironment: WorkspaceHermesCodexEnvironment
// Justification: FileManager is documented thread-safe but is not marked Sendable.
private nonisolated(unsafe) let fileManager: FileManager

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 nonisolated(unsafe) disables Swift's Sendable enforcement on fileManager

nonisolated(unsafe) tells the compiler to stop tracking concurrency safety for this stored property. If any future code path on the service changes the FileManager delegate or configures it after construction (common when adding URL session proxies or temporary-directory overrides), the compiler will not catch the resulting race. For a struct that's meant to be fully Sendable, consider instead not storing FileManager at all and accepting it as a local parameter in each method that actually needs it (startupInputWithLauncherScript and startupCommandWithLauncherScript already thread it through), so the Sendable suppression can be removed.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@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)
Sources/Workspace.swift (1)

1132-1141: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Route remote resume startup input through the policy service.

The remote-startup branch still calls the binding DTO’s startupInputWithLauncherScript directly, while the local branch uses sessionRestorePolicy.surfaceResumeStartupLaunch(...). That bypasses the extracted policy-owned Hermes/Codex rewriting for remote restores, so the same approved binding can resume differently depending on whether remoteStartupCommand is present.

Possible direction
             let restoredBindingLaunch: SurfaceResumeStartupLaunch? = if remoteStartupCommand != nil {
-                effectiveResumeBindingForStartup?
-                    .startupInputWithLauncherScript(allowLauncherScript: false)
-                    .map(SurfaceResumeStartupLaunch.input)
+                effectiveResumeBindingForStartup.flatMap { binding in
+                    sessionRestorePolicy
+                        .surfaceResumeStartupLaunch(
+                            forApprovedBinding: binding,
+                            allowLauncherScript: false
+                        )
+                        .initialInput
+                        .map(SurfaceResumeStartupLaunch.input)
+                }
             } else {
                 effectiveResumeBindingForStartup.flatMap {
                     sessionRestorePolicy.surfaceResumeStartupLaunch(

If surfaceResumeStartupLaunch(forApprovedBinding:) can legally return .command here, add a policy-service approved-input helper instead of falling back to the DTO method.

🤖 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 `@Sources/Workspace.swift` around lines 1132 - 1141, The remote-startup branch
(when remoteStartupCommand is not nil) directly calls the binding DTO's
startupInputWithLauncherScript method, bypassing the policy service, while the
local branch routes through sessionRestorePolicy.surfaceResumeStartupLaunch. To
ensure consistent policy-owned Hermes/Codex rewriting for both remote and local
restores, replace the direct DTO call in the if branch with a call to
sessionRestorePolicy instead. If needed, add a new policy-service method
(similar to surfaceResumeStartupLaunch) that handles remote startup input
approval through the policy service, ensuring the same approved binding resumes
consistently regardless of whether remoteStartupCommand is present.
🤖 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 `@Sources/Workspace.swift`:
- Around line 1132-1141: The remote-startup branch (when remoteStartupCommand is
not nil) directly calls the binding DTO's startupInputWithLauncherScript method,
bypassing the policy service, while the local branch routes through
sessionRestorePolicy.surfaceResumeStartupLaunch. To ensure consistent
policy-owned Hermes/Codex rewriting for both remote and local restores, replace
the direct DTO call in the if branch with a call to sessionRestorePolicy
instead. If needed, add a new policy-service method (similar to
surfaceResumeStartupLaunch) that handles remote startup input approval through
the policy service, ensuring the same approved binding resumes consistently
regardless of whether remoteStartupCommand is present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: de4d1f6c-9f16-4500-9212-da650fa71814

📥 Commits

Reviewing files that changed from the base of the PR and between bd80f9e and dc5ada1.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (10)
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceHermesCodexEnvironment.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRemoteRestorePanelSnapshot.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRemoteRestoreSnapshot.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRemoteRestoreTerminalSnapshot.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceSessionRestorePolicyService.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceSurfaceResumeBinding.swift
  • Packages/CmuxSession/Sources/CmuxSession/WorkspaceSurfaceResumeStartupLaunch.swift
  • Packages/CmuxSession/Tests/CmuxSessionTests/WorkspaceSessionRestorePolicyServiceTests.swift
  • Sources/SessionPersistence.swift
  • Sources/Workspace.swift

@azooz2003-bit
azooz2003-bit merged commit a0eeca0 into main Jun 16, 2026
34 of 42 checks passed
@azooz2003-bit
azooz2003-bit deleted the feat-workspace-decomp branch June 16, 2026 07:16

This branch was successfully deployed

1 active deployment
Preview – cmux — e4dc5310 Deployed Jun 16, 2026 by vercel[bot]
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.

1 participant