Skip to content

Allow configurable Dock max width - #4385

Merged
austinywang merged 28 commits into
mainfrom
issue-4375-dock-max-width-config
Jun 15, 2026
Merged

austinywang merged 28 commits into
mainfrom
issue-4375-dock-max-width-config

Conversation

@austinywang

@austinywang austinywang commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add a cmux.json-managed sidebar.rightMaxWidth setting for the Dock/right sidebar width cap
  • Feed the managed setting into the existing ContentView right-sidebar clamp policy
  • Cover the default policy, configured override, available-width cap, minimum clamp, and settings-file wiring in SidebarWidthPolicyTests

Fixes #4375

Verification

  • Not run locally per repo/user instruction; CI will verify.

Note

Medium Risk
Touches main-window layout clamping and live geometry when the cap changes; incorrect clamp math could shrink the terminal or allow oversized Dock panels, though bounds and tests mitigate this.

Overview
Adds a Dock max width preference so the right sidebar can use a user-defined cap (up to 4096pt) instead of only the built-in 1200pt dynamic limit, while still reserving minimum terminal width.

Policy & persistence: New RightSidebarWidthSettings centralizes min/max, clamping, and “override off” (-1) vs active values; catalog keys sidebar.rightMaxWidth and a remembered width support re-enabling the toggle. cmux.json accepts sidebar.rightMaxWidth (validated/clamped on import); schema and locale strings are updated.

Runtime: ContentView reads the setting via @AppStorage and passes an optional configured cap into clampedRightSidebarWidth; changing the setting re-clamps the Dock and syncs geometry.

Settings UI: Sidebar Appearance gets a switch plus numeric field; disabling override stores the last custom value for restore.

Refactor: Settings JSON parsing gains shared boolean/string/array mapping tables (app, notifications, terminal, sidebar, automation, browser) used when applying cmux.json.

Tests: Unit tests for width policy and settings-file import; expanded sidebar width clamp tests.

Reviewed by Cursor Bugbot for commit c6a3fc8. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds a configurable max width for the Dock/right sidebar that can exceed the old cap while preserving terminal space. Also updates settings import/UI and removes unstable drop-target code for steadier layouts.

  • New Features

    • sidebar.rightMaxWidth (>0) in cmux.json and Settings UI; clamps to 276–4096pt; invalid inputs logged; schema, i18n, and settings search/anchors updated.
    • Central RightSidebarWidthSettings used by JSON import, Settings UI, and runtime; can exceed the 1200pt cap while reserving 360pt for the terminal; applies live and restores your last custom width when re-enabled.
  • Bug Fixes

    • Fixed CGFloat conversion and consistent clamping; exposed the width policy via the app module; aligned settings JSON mappings so sidebar.rightMaxWidth imports correctly.
    • Bounded sidebar workspace text/metadata rendering and removed unused drop-metrics code, tests, and header drop-height constants to prevent oversized drop regions and layout thrash; updated to BrowserSearchSettingsStore after a main rename.
    • Resolved automation settings parsing against feat: opt-in AI auto-naming of workspaces and tabs from agent conversations #5547: kept data-driven mapping and added workspaceAutoNaming and autoNamingAgent keys.

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

Review in cubic

Summary by CodeRabbit

  • New Features

    • Configurable, persisted maximum width for the right/Dock sidebar with immediate application when changed.
    • Settings UI: enable toggle and numeric editor for the sidebar max-width; resize respects the configured value and falls back to dynamic caps when unset.
    • Configuration schema updated to include optional numeric sidebar.rightMaxWidth (>0).
  • Tests

    • Added tests covering right‑sidebar clamping across configured, missing, and boundary scenarios.
  • Documentation

    • Added localized strings and settings search entries for the new sidebar max‑width setting.

Review Change Stack

@vercel

vercel Bot commented May 19, 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 15, 2026 3:35am
cmux-staging Building Building Preview, Comment Jun 15, 2026 3:35am

@coderabbitai

coderabbitai Bot commented May 19, 2026 •

Copy link
Copy Markdown

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

Adds a persisted sidebar.rightMaxWidth setting (schema + mapping), exposes it via AppStorage and Settings UI, threads a configured maximum into ContentView's sidebar clamping (with immediate reclamp on change), refactors settings parsing to mapping-driven helpers, and adds tests and localization.

Changes

Configurable Sidebar Width

Layer / File(s) Summary
Settings contract and schema
Sources/CmuxSettingsJSONPathSupport.swift, web/data/cmux.schema.json
RightSidebarWidthSettings helper validates finite positive widths, JSON schema adds optional sidebar.rightMaxWidth (number, >0), and supportedSettingsJSONPaths registers the new path.
Mapping infrastructure for settings parsing
Sources/CmuxSettingsJSONPathSupport.swift
Generic mapping helper types and enums (SettingsFileBooleanMapping, SettingsFileStringMapping, SettingsFileStringArrayMapping, AppSettingsFileMapping, NotificationSettingsFileMapping, TerminalSettingsFileMapping, SidebarSettingsFileMapping, AutomationSettingsFileMapping, BrowserSettingsFileMapping) associate JSON keys with UserDefaults keys and optional invalid-path metadata.
Settings file parsing with mapping-driven helpers
Sources/KeyboardShortcutSettingsFileStore.swift
Refactors multiple parse*Section implementations to apply boolean/string/string-array settings via applyBooleanSettings, applyStringSettings, and applyNormalizedStringArraySettings while preserving bespoke validation for a few fields (notification sound, branchLayout, right-sidebar jsonDouble, browser theme, automation socketPassword).
View state, AppStorage, UI and clamping logic
Sources/ContentView.swift, Sources/cmuxApp.swift, Sources/SettingsNavigation.swift, Sources/SettingsSearchAliases.swift, Resources/Localizable.xcstrings
New @AppStorage property binds the configured max width; Settings UI adds a toggle and numeric editor bound to clamped editor value; clampedRightSidebarWidth overload accepts optional configuredMaximumWidth and uses it when finite; onChange re-clamps and refreshes resizer/portal state; search aliases/index and localizations added.
Tests for clamping behavior and settings persistence
cmuxTests/SidebarWidthPolicyTests.swift
UserDefaults key constants backup/restore test state; tests cover missing setting and multiple configured-max clamping scenarios; integration test writes a temporary cmux.json and asserts the settings store persists the managed UserDefaults key and that RightSidebarWidthSettings.configuredMaximumWidth(from:) reads the persisted value.

Sequence Diagram(s)

sequenceDiagram
  participant SettingsFile
  participant SettingsStore
  participant ApplyHelpers
  participant UserDefaults
  SettingsFile->>SettingsStore: provide JSON sections (sidebar, browser, etc.)
  SettingsStore->>ApplyHelpers: apply mappings for booleans/strings/arrays
  ApplyHelpers->>UserDefaults: persist normalized values
  ApplyHelpers->>SettingsStore: log invalid-path when present with wrong type
Loading
sequenceDiagram
  participant AppStorage
  participant ContentView
  participant ClampLogic
  participant SettingsUI
  AppStorage->>ContentView: rightSidebarMaxWidthSetting value
  SettingsUI->>AppStorage: user toggles / edits max width
  ContentView->>ClampLogic: request clamped width (availableWidth, configuredMaximum)
  ClampLogic->>ContentView: return clamped width (min..max)
  AppStorage->>ContentView: onChange triggers reclamp and portal sync
Loading

Estimated code review effort:
🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs:

  • manaflow-ai/cmux#4245: Touches settings parsing/wiring similarly (browser discard keys vs. this PR's mapping-driven refactor), potentially overlapping in parsing helpers.

"🐰 I nibble at keys and JSON lines,
A Dock grows wide where sunlight shines,
Parsers hum, the toggle sings,
Tests verify the bigger things,
Hop—settings applied, the sidebar grins."


Important

Pre-merge checks failed

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

❌ Failed checks (2 errors, 1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Cmux Swift Concurrency ❌ Error Introduces KeyboardShortcutSettingsObserver with @Published/@observableobject Combine patterns and DispatchQueue.main, violating concurrency modernization rules. Replace Combine @Published pattern with @Observable and async/await, or defer KeyboardShortcutSettingsObserver to separate PR not in scope of Dock width feature.
Cmux Swift Logging ❌ Error logInvalid() helper uses NSLog without DEBUG guards; handleNotificationPermissionAction() also logs NSLog in production app code, violating swift-logging.md rules for NSLog in app/runtime code. Replace NSLog with Logger(subsystem:category:) or guard with #if DEBUG. logInvalid should use a Logger instance instead of NSLog.
Docstring Coverage ⚠️ Warning Docstring coverage is 3.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Cmux Architecture Rethink ❓ Inconclusive No result was produced after verification. Marking as INCONCLUSIVE. Re-run the check or adjust instructions to produce a final result.
Description check ❓ Inconclusive The PR description includes a summary of changes and verification approach, but is missing the required structured sections. Align the description with the template: add explicit 'Testing' and 'Demo Video' sections, include a demo video link, copy the review trigger block, and complete the checklist with status checks for local testing and bot review requests.
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Allow configurable Dock max width' is clear and concise and accurately reflects the main feature: adding the ability to configure the maximum width for the Dock/right sidebar.
Linked Issues check ✅ Passed The PR addresses all primary objectives from #4375: exposing a sidebar.rightMaxWidth setting, wiring it into ContentView's clamp policy, enforcing bounds (available width, minimum), ignoring invalid values, and applying changes live via @AppStorage.
Out of Scope Changes check ✅ Passed All changes are scoped to the linked issue: sidebar.rightMaxWidth setting addition, settings file parsing/mapping refactoring, ContentView integration, Settings UI, localization, schema updates, and comprehensive tests covering the new feature and existing behavior.
Cmux Swift Actor Isolation ✅ Passed CmuxSettingsFileStore is explicitly @MainActor; ContentView/cmuxApp implicitly @MainActor; new value structs are pure types used only in MainActor; file watchers dispatch to main thread.
Cmux Swift Blocking Runtime ✅ Passed PR introduces Dock max-width settings via AppStorage, clamping logic, and parsing helpers with no new blocking synchronization, Task.sleep, semaphores, locks, or polling patterns.
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift files and data files; the rule applies to TypeScript, JavaScript, shell, and build/runtime scripts, which are not modified here.
Cmux Swift @Concurrent ✅ Passed PR adds only synchronous code; all nonisolated keywords are on pure synchronous functions. No async functions added that require @concurrent, and DispatchQueue usage is intentionally UI-bound.
Cmux Swift File And Package Boundaries ✅ Passed File sizes within thresholds: CmuxSettingsJSONPathSupport 358 lines (single responsibility), KeyboardShortcutSettingsFileStore -97 lines (refactored), UI changes <250 lines on oversized files.
Cmux User-Facing Error Privacy ✅ Passed All user-facing strings and error messages comply with privacy rules. No vendor names, credentials, tokens, or sensitive data are exposed in UI labels, descriptions, error logs, or schema definitions.
Cmux Full Internationalization ✅ Passed All user-facing Swift strings use String(localized:defaultValue:) with matching Localizable.xcstrings entries translated across all 21 supported locales.
Cmux Swiftui State Layout ✅ Passed PR uses @AppStorage for state and Binding.set for mutations in event handlers, complying with SwiftUI state layout rules.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds UI elements to the existing Settings window (cmux.settings), which already has required cmux.* identifier and close-shortcut ownership. No new standalone windows introduced.
✨ 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-4375-dock-max-width-config

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.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 5 files

Re-trigger cubic

@greptile-apps

greptile-apps Bot commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a user-configurable max width for the right Dock sidebar via a new RightSidebarWidthSettings value type and a sidebar.rightMaxWidth setting in cmux.json, with live geometry re-clamping and a Settings UI toggle+field. It also replaces static drop-target height estimates with actual GeometryReader measurements in sidebar row views, bounds workspace title/description rendering, and refactors settings-JSON parsing into shared mapping tables.

  • New RightSidebarWidthSettings policy type centralises sentinel values, min/max bounds (276–4096 pt), clamping, and enable/disable semantics; ContentView reads it via @AppStorage and re-clamps on change. cmux.json import validates and clamps the value before persisting.
  • Drop-target height now comes from a GeometryReader background probe (rowHeight) instead of a ~200-line static estimator; SidebarWorkspaceRowDropMetrics and TabItemViewDropSupport are removed.
  • Settings-JSON parsing is refactored into SettingsFileBooleanMapping / SettingsFileStringMapping / SettingsFileStringArrayMapping tables and three shared helpers (applyBooleanSettings, applyStringSettings, applyNormalizedStringArraySettings), reducing repetition across the app/notification/terminal/automation/browser sections.

Confidence Score: 5/5

Safe to merge — clamping math is well-tested, live geometry re-sync is correctly wired, and the settings-JSON refactor uses verified matching UserDefaults keys.

The clamp logic is exercised by five new unit tests covering defaults, configured override, available-width cap, minimum clamp, and settings-file round-trips. The AutomationCatalogSection keys share the same userDefaultsKey slots as the old IntegrationsCatalogSection calls they replace, so no settings are silently dropped. The only findings are a committed local lock file and a one-character API inconsistency in a rowHeightProbe closure — neither affects runtime behaviour.

No files require special attention; .claude/scheduled_tasks.lock should be gitignored to prevent future noise.

Important Files Changed

Filename Overview
Packages/CmuxSettings/Sources/CmuxSettings/Policies/RightSidebarWidthSettings.swift New stateless value type centralizing min/max constants, clamping, sentinel value, and enable/disable helpers for the right sidebar width override. Well-structured with clear invariants.
Sources/ContentView.swift Adds @AppStorage binding for rightSidebarMaxWidthSetting, passes configuredMaximumWidth into clampedRightSidebarWidth, and triggers re-clamp/geometry-sync on setting changes. The rowHeightProbe added here uses the deprecated single-parameter onChange form inconsistently with SidebarWorkspaceGroupHeaderView.
Sources/CmuxSettingsJSONPathSupport.swift Adds shared mapping table types and per-section enums consumed by the new applyBooleanSettings/applyStringSettings helpers. rightMaxWidth JSON key correctly wired with clamping.
Sources/KeyboardShortcutSettingsFileStore.swift Refactors repetitive inline if-let blocks into shared helpers. AutomationCatalogSection keys verified to share the same UserDefaults slot as the old IntegrationsCatalogSection calls they replace.
Sources/SidebarWorkspaceGroupHeaderView.swift Replaces static dropTargetHeight() estimate with GeometryReader-measured rowHeight via .background; correctly uses two-parameter onChange.
Sources/SidebarWorkspaceRowDropMetrics.swift Deleted: complex static height-estimation logic replaced by actual GeometryReader measurement in each row view.
.claude/scheduled_tasks.lock Machine-local Claude Code session lock file accidentally committed alongside PR changes. Should be gitignored.
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/SidebarSection.swift Adds toggle + numeric field for the right max width override with correct enable/disable/remember logic. Localized strings correctly routed through String(localized:defaultValue:).
cmuxTests/SidebarWidthPolicyTests.swift Adds coverage for default cap, configured override, available-width clamp, minimum clamp, and settings-file import/clamping round-trips with proper teardown.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[cmux.json sidebar.rightMaxWidth] -->|parse and clamp| B[KeyboardShortcutSettingsFileStore parseSidebarSection]
    B -->|UserDefaults write| C[rightSidebarMaxWidth key]
    D[Settings UI SidebarSection toggle+field] -->|write| C
    C -->|AppStorage| E[ContentView rightSidebarMaxWidthSetting]
    E -->|configuredMaximumWidth| F[rightSidebarConfiguredMaximumWidth Optional CGFloat]
    F -->|passed into| G[clampedRightSidebarWidth]
    G --> H[min configuredOrDefaultCap availableWidthCap]
    H --> I[fileExplorerWidth clamped sidebar width]
    E -->|onChange| J[clampRightSidebarWidthIfNeeded and schedulePortalGeometrySynchronize]
    J --> I
Loading

Reviews (23): Last reviewed commit: "merge: resolve automation settings parsi..." | Re-trigger Greptile

Comment thread Sources/KeyboardShortcutSettingsFileStore.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 19, 2026

@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: 2

🤖 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 `@Sources/ContentView.swift`:
- Around line 1661-1671: When a configuredMaximumWidth is present the code must
still reserve the terminal minimum width; change the configured branch to cap
configuredMaximumWidth by sanitizedAvailableWidth -
Self.minimumTerminalWidthWithRightSidebar before applying min/max. In other
words, compute an availableWidthCap = min(configuredMaximumWidth,
sanitizedAvailableWidth - Self.minimumTerminalWidthWithRightSidebar) (while
keeping the configuredMaximumWidth.isFinite check), then set maximumWidth =
min(sanitizedAvailableWidth, max(minimumWidth, availableWidthCap)) so the right
sidebar can never consume the terminal's reserved minimum width (references:
configuredMaximumWidth, Self.minimumTerminalWidthWithRightSidebar,
sanitizedAvailableWidth, maximumWidth, minimumWidth).

In `@web/data/cmux.schema.json`:
- Line 503: The new user-facing "description" string added in
web/data/cmux.schema.json must be added to the localized message sets for every
locale defined in web/i18n/routing.ts; update the locale message files (the
per-locale JSON/TS files referenced by routing.ts) with a new key for this
Dock/right sidebar description (use a clear key tied to cmux.schema.json, e.g.,
cmux.sidebarMaxWidth.description) and provide translations for all locales, then
replace the inline description in cmux.schema.json with a reference to that
message key so the schema uses the i18n copy used across the app.
🪄 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: a99b224f-e434-4322-b527-5092f9bfc058

📥 Commits

Reviewing files that changed from the base of the PR and between 28669e4 and 33675a0.

📒 Files selected for processing (7)
  • Sources/CmuxSettingsFileStore+CompactSectionParsing.swift
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/ContentView.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/SidebarWidthPolicyTests.swift
  • web/data/cmux.schema.json

Comment thread Sources/ContentView.swift Outdated
Comment thread web/data/cmux.schema.json Outdated
Allow sidebar.rightMaxWidth from cmux.json to override the right sidebar dynamic cap while preserving the existing default policy.
@austinywang
austinywang force-pushed the issue-4375-dock-max-width-config branch from 3c3759b to 1b2ae13 Compare May 19, 2026 21:37
coderabbitai[bot]
coderabbitai Bot previously requested changes May 19, 2026

@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: 2

🤖 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 `@Sources/ContentView.swift`:
- Around line 3122-3125: The right-sidebar onChange observer (watching
rightSidebarMaxWidthSetting) adjusts sizes via clampRightSidebarWidthIfNeeded()
and updateSidebarResizerBandState() but doesn't resync portal geometry; after
those calls (inside the same observer) call schedulePortalGeometrySynchronize()
when the right sidebar is visible so portal-hosted content gets updated to the
new width immediately—i.e., add a call to schedulePortalGeometrySynchronize() in
the rightSidebarMaxWidthSetting onChange handler (conditional on the sidebar
being visible if such a visibility check exists).

In `@web/data/cmux.schema.json`:
- Around line 499-503: Add a missing JSON Schema "description" for the sidebar
property "rightMaxWidth": update the schema entry for "rightMaxWidth" (the
property name) to include a description string consistent with other sidebar
properties, e.g. a concise tooltip like "Maximum width in points for the right
sidebar/Dock. When omitted, the built-in cap applies." so editors show
autocompletion help for this property.
🪄 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: 16c1f53f-f9e6-4330-ab4a-778b7a84bd21

📥 Commits

Reviewing files that changed from the base of the PR and between 33675a0 and 1b2ae13.

📒 Files selected for processing (5)
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/ContentView.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • cmuxTests/SidebarWidthPolicyTests.swift
  • web/data/cmux.schema.json

Comment thread Sources/ContentView.swift Outdated
Comment thread web/data/cmux.schema.json

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

♻️ Duplicate comments (2)
web/data/cmux.schema.json (1)

500-504: ⚠️ Potential issue | 🟠 Major

User-facing description requires localization.

The description at line 503 is user-facing (appears in editor tooltips) and requires localization coverage for all supported locales. This issue has already been flagged in a previous review.

As per coding guidelines: web/data/**/*.json: "Verify user-facing schema titles, descriptions, and data copy have matching localized message coverage for every locale listed in web/i18n/routing.ts."

🤖 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 `@web/data/cmux.schema.json` around lines 500 - 504, The schema property
"rightMaxWidth" in web/data/cmux.schema.json has a user-facing description that
must be localized; replace the inline description with a reference key (e.g.,
"description": "cmux.rightMaxWidth.description") and add the corresponding
localized message entries for that key in each locale file referenced by
web/i18n/routing.ts, ensuring message IDs match and content mirrors the original
English text so editor tooltips display correctly for all supported locales.
Sources/ContentView.swift (1)

1661-1673: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Treat the configured max as an extra cap, not a replacement.

This branch drops both minimumTerminalWidthWithRightSidebar and maximumRightSidebarWidth whenever sidebar.rightMaxWidth is set. In a 900pt content area with sidebar.rightMaxWidth = 800, the sidebar can now grow to ~800pt and leave the terminal at ~100pt, which makes the new setting behave like a full override instead of a maximum.

💡 Suggested fix
         let minimumWidth = Self.minimumRightSidebarWidth
         let sanitizedCandidate = candidate.isFinite ? candidate : 220
         let sanitizedAvailableWidth = availableWidth.isFinite && availableWidth > 0 ? availableWidth : 1920
-        let maximumWidth: CGFloat
-        if let configuredMaximumWidth, configuredMaximumWidth.isFinite {
-            // An explicit cmux.json max width replaces the legacy terminal-reservation cap.
-            maximumWidth = min(
-                sanitizedAvailableWidth,
-                max(minimumWidth, configuredMaximumWidth)
-            )
-        } else {
-            let availableWidthCap = sanitizedAvailableWidth - Self.minimumTerminalWidthWithRightSidebar
-            maximumWidth = min(
-                Self.maximumRightSidebarWidth,
-                max(minimumWidth, availableWidthCap)
-            )
-        }
+        let availableWidthCap = max(
+            minimumWidth,
+            sanitizedAvailableWidth - Self.minimumTerminalWidthWithRightSidebar
+        )
+        let derivedMaximumWidth = min(Self.maximumRightSidebarWidth, availableWidthCap)
+        let configuredCap: CGFloat? = {
+            guard let configuredMaximumWidth, configuredMaximumWidth.isFinite else { return nil }
+            return max(minimumWidth, configuredMaximumWidth)
+        }()
+        let maximumWidth = min(derivedMaximumWidth, configuredCap ?? derivedMaximumWidth)
         return max(minimumWidth, min(maximumWidth, sanitizedCandidate))
🤖 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/ContentView.swift` around lines 1661 - 1673, The
configuredMaximumWidth branch currently replaces the legacy caps; instead treat
configuredMaximumWidth as an extra cap on top of existing logic: compute
availableWidthCap = sanitizedAvailableWidth -
Self.minimumTerminalWidthWithRightSidebar and then set maximumWidth to
min(Self.maximumRightSidebarWidth, max(minimumWidth, min(availableWidthCap,
configuredMaximumWidth))). Update the code paths that reference
configuredMaximumWidth (e.g., configuredMaximumWidth,
minimumTerminalWidthWithRightSidebar, maximumRightSidebarWidth,
sanitizedAvailableWidth, maximumWidth, minimumWidth) so the configured value
only further restricts the sidebar width rather than overriding the
terminal-reservation cap.
🤖 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.

Duplicate comments:
In `@Sources/ContentView.swift`:
- Around line 1661-1673: The configuredMaximumWidth branch currently replaces
the legacy caps; instead treat configuredMaximumWidth as an extra cap on top of
existing logic: compute availableWidthCap = sanitizedAvailableWidth -
Self.minimumTerminalWidthWithRightSidebar and then set maximumWidth to
min(Self.maximumRightSidebarWidth, max(minimumWidth, min(availableWidthCap,
configuredMaximumWidth))). Update the code paths that reference
configuredMaximumWidth (e.g., configuredMaximumWidth,
minimumTerminalWidthWithRightSidebar, maximumRightSidebarWidth,
sanitizedAvailableWidth, maximumWidth, minimumWidth) so the configured value
only further restricts the sidebar width rather than overriding the
terminal-reservation cap.

In `@web/data/cmux.schema.json`:
- Around line 500-504: The schema property "rightMaxWidth" in
web/data/cmux.schema.json has a user-facing description that must be localized;
replace the inline description with a reference key (e.g., "description":
"cmux.rightMaxWidth.description") and add the corresponding localized message
entries for that key in each locale file referenced by web/i18n/routing.ts,
ensuring message IDs match and content mirrors the original English text so
editor tooltips display correctly for all supported locales.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f422a895-8ec1-4e9a-8803-f85b408cd04c

📥 Commits

Reviewing files that changed from the base of the PR and between 1b2ae13 and b9357d0.

📒 Files selected for processing (2)
  • Sources/ContentView.swift
  • web/data/cmux.schema.json

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread Resources/Localizable.xcstrings Outdated
@austinywang
austinywang dismissed stale reviews from coderabbitai[bot] and coderabbitai[bot] May 26, 2026 19:11

Stale CodeRabbit changes-requested reviews: all inline findings have been addressed, all review threads are resolved, and the latest CodeRabbit status is passing.

…idth-config

# Conflicts:
#	Resources/Localizable.xcstrings
#	Sources/KeyboardShortcutSettingsFileStore.swift
#	Sources/SettingsNavigation.swift
#	web/messages/ar.json
#	web/messages/bs.json
#	web/messages/da.json
#	web/messages/de.json
#	web/messages/en.json
#	web/messages/es.json
#	web/messages/fr.json
#	web/messages/it.json
#	web/messages/ja.json
#	web/messages/km.json
#	web/messages/ko.json
#	web/messages/no.json
#	web/messages/pl.json
#	web/messages/pt-BR.json
#	web/messages/ru.json
#	web/messages/th.json
#	web/messages/tr.json
#	web/messages/uk.json
#	web/messages/zh-CN.json
#	web/messages/zh-TW.json
…idth-config

# Conflicts:
#	.github/swift-file-length-budget.tsv
…idth-config

# Conflicts:
#	.github/swift-file-length-budget.tsv
…idth-config

# Conflicts:
#	Sources/ContentView.swift
…idth-config

# Conflicts:
#	.github/swift-file-length-budget.tsv
#	web/messages/ar.json
#	web/messages/bs.json
#	web/messages/da.json
#	web/messages/de.json
#	web/messages/en.json
#	web/messages/es.json
#	web/messages/fr.json
#	web/messages/it.json
#	web/messages/ja.json
#	web/messages/km.json
#	web/messages/ko.json
#	web/messages/no.json
#	web/messages/pl.json
#	web/messages/pt-BR.json
#	web/messages/ru.json
#	web/messages/th.json
#	web/messages/tr.json
#	web/messages/uk.json
#	web/messages/zh-CN.json
#	web/messages/zh-TW.json
austinywang and others added 2 commits June 14, 2026 19:44
…idth-config

# Conflicts:
#	.github/swift-file-length-budget.tsv
#	Sources/KeyboardShortcutSettingsFileStore.swift
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…riven mapping, add workspaceAutoNaming/autoNamingAgent)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@austinywang
austinywang merged commit 48c9160 into main Jun 15, 2026
33 of 34 checks passed
@austinywang austinywang mentioned this pull request Jun 15, 2026
hhsw2015 pushed a commit to hhsw2015/cmux that referenced this pull request Jun 15, 2026
Strategy: -X theirs + cherry-pick fork features back

Upstream changes pulled in (highlights):
- Stagger restored terminal surface spawns (manaflow-ai#6149)
- Configurable Dock max width (manaflow-ai#4385)
- Polish canvas minimap navigation (manaflow-ai#6105)
- Opt-in AI auto-naming workspaces (manaflow-ai#6071)
- Dissolve namespace-enums into value types (manaflow-ai#6126)
- Fix stale remote connected state after proxy disconnect (manaflow-ai#4513)
- Surface browser Safari (manaflow-ai#6113)
- Fix terminal top-row mouse (manaflow-ai#4391)
- iOS Shift key support (manaflow-ai#6104)

Fork-only features verified intact post-merge:
- cmux_term socket handlers: surface.snapshot, screen_text, screen_hash,
  wait_for_text, wait_for_idle, wait_for_screen_change, wait_for_kind,
  wait_for_cursor, tui_probe, expect, screen_region (6 handler funcs)
- agent-bus: notification.create with $bus dispatch
- TerminalSurface.visibleSnapshot() + processHasExited() helpers
- skills/cmux-terminal-control/* (13 Python lib files + ORCHESTRATOR_TEMPLATE.md)
- HerdrWorkspaceSync + CustomTitleSource.herdrInbound

Adapter changes (fork-side):
- Drop InternalImportsByDefault from CmuxFeedback/CmuxFeedbackUI packages
  (default-arg parameter types remained internal-only across modules,
   blocking FeedbackComposerBridge() construction from cmux app target)
- Strip .rawValue from SurfaceKind cases (became plain String)
- Add herdrInbound to CustomTitleSource enum
- Delete shadowing local enums in ContentView (CommandPaletteOverlayPromotionPolicy,
  ExtensionSidebarBrowserStackDropPlanner, SidebarDragFailsafePolicy,
  SidebarDragLifecycleNotification, SidebarMarkdownRenderer, SidebarOutsideDropResetPolicy,
  SidebarShortcutHintFreezePolicy, SidebarTrailingAccessoryWidthPolicy,
  SidebarWorkspaceSelectionSyncPolicy, ShortcutHintDebugSettings,
  ShortcutHintModifierPolicy, FeedbackComposerBridge, FeedbackComposerBridgeError,
  ExtensionSidebarBrowserStackDropRow, SidebarTabDropIndicatorPredicate,
  SidebarDropEdge, SidebarDropIndicator)
- Delete local TerminalSurfaceClaudeCommandShim (use package's via typealias)
- Delete local TerminalSurfaceRuntimeTeardownCoordinator + Request stubs
  (use package's enqueueRuntimeTeardown public API directly)
- Adapt static→instance: CmuxGhosttyConfigSettingEditor.X → ().X,
  CmuxApplicationSupportDirectories.userDirectories → init(env:).userDirectories
- newTerminalSurface/TerminalPanel: thread externalIo: parameter for herdr
- Add createReplacementTerminalPanel(in:) overload
- Add attachToViewForInputDemand/requestInputDemandSurfaceStartIfNeeded stubs
- TerminalSurfaceRuntimeFilesystem.live(): wrap installClaudeCommandShim sync→async
- AppDelegate.sortedMainWindowContextsForSessionSnapshot: add includeQuickTerminal param
- Wire BackgroundSessionStore + BackgroundSessionsSidebarSection + SidebarSectionDivider
  in pbxproj (PBXFileReference + PBXBuildFile entries were missing post-merge)
- Add SidebarSectionDivider stub View (was referenced but never created)

Rebuilt clean against /tmp/cmux-p52 derivedData.
lawrencecchen added a commit that referenced this pull request Jul 3, 2026
…ure)

Codex review found the blind spot: the group-header row is assembled by
sidebarWorkspaceGroupHeader(...) in VerticalTabsSidebar+WorkspaceGroups.swift,
where modifiers wrap the header before it enters the LazyVStack — a
GeometryReader or anchorPreference added there defeats laziness exactly
like one inside the row view (the #4385 regression entered through the
header path). The guard now scans that whole file for the row-forbidden
shapes with a rename-protected marker, and the scale fixture groups the
first 20 workspaces into 5 groups so group-header realization and
convergence are asserted by the behavioral backstop (bounds on
groupHeaderBodies at mount and in the quiet check).

Verified on the AWS M4 Pro runner: 3/3 pass in 2.7s, no host restarts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lawrencecchen added a commit that referenced this pull request Jul 3, 2026
…-view guard (#7221)

* Extend sidebar lazy-layout guard to the row views (TabItemView, group header)

The source-scan guard from #6870 protected only the two container
functions, but four of the five historical livelock regressions entered
through the row views: the #2586/#6556 GeometryReader -> @State
rowHeight probes lived in TabItemView and
SidebarWorkspaceGroupHeaderView (removed by #6111, reintroduced by
#4385, removed again by #7117) and shipped in stable v0.64.17, which
livelocked in the wild on 2026-07-02 with exactly that signature
(#2586 (comment)).

Scan the TabItemView region of ContentView.swift and the whole group
header file for per-row geometry feedback: GeometryReader,
onGeometryChange, manual sizeThatFits, ProposedViewSize(nil),
per-row anchorPreference/overlayPreferenceValue, and any discovered
custom Layout. Rows must stay measurement-free; the only sanctioned
geometry path is the container's drag-gated reader. Missing row types
fail loudly so a rename cannot rot the guard into a no-op.

Verified the extended guard retroactively flags both v0.64.17 row
views. New self-test cases (j)-(m) cover clean-pass, the #6556 probe
shape, the #5323 anchorPreference shape, and rename protection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add behavioral scale gate for the sidebar lazy-layout contract

The lazy-layout contract (sidebar layout/diff work stays O(visible
rows), never O(all workspaces)) has regressed five times through five
different mechanisms (#5323 anchorPreference aggregation, #5764 String
ids, #5845 animated height interpolation, #6210 force-measuring custom
Layout, #6556 GeometryReader -> @State feedback), each shipping to
stable before detection because nothing exercises the sidebar at the
100+ workspace scale where O(N) per pass livelocks the main thread
(#2586).

SidebarLazyLayoutScaleTests mounts the real VerticalTabsSidebar with
300 workspaces in an NSHostingView and counts actual row body
evaluations through a DEBUG-only environment probe
(SidebarLazyContractProbe, same pattern as
MinimalModeInvalidationProbe):

- mount must realize only viewport rows (catches any virtualization
  defeat, present or future, regardless of mechanism)
- a 40-burst unread-model storm (the sidebar's highest-frequency
  whole-body invalidation path) must stay row-scoped and go quiet when
  the burst stops (catches feedback loops the way #6556 manifested)
- a harness canary reproduces the GeometryReader -> @State shape in
  divergent form and asserts the harness detects it, so the gate
  cannot silently rot

This is the mechanism-independent backstop behind the source-shape
scan in scripts/check-sidebar-lazy-layout.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix scale-test autorelease avalanche that hung/crashed the app host

Creating 300 workspaces inside one main-actor job accumulated every
autoreleased object from the O(N)-per-add snapshot work into a single
autorelease pool; the closing objc_autoreleasePoolPop then crashed CI
(Signal 11 in AutoreleasePoolPage::releaseUntil, masked as a green run,
see #5641) and hung for hours
when reproduced on an AWS M4 Pro (sampled: main thread pinned in
releaseUntil). The app never does this; real workspace creation happens
one per event-loop turn with AppKit popping the pool between turns.

Make the harness match real cadence: per-iteration autoreleasepool
around addWorkspace and a run-loop turn every 20 creations. Also hoist
the RunLoop.run call into a synchronous helper (fixes the Swift 6
unavailable-from-async warning) wrapped in its own pool.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix harness NSWindow double-release that killed the app host

NSZombies named the corpse: "-[NSKVONotifying_NSWindow release]:
message sent to deallocated instance". The harness windows used the
NSWindow default isReleasedWhenClosed=true, so tearDown's close()
performed AppKit's own release on top of ARC's; the double-release
SEGV'd the host at the next autorelease-pool pop, before the pass was
recorded, and CI masked the crash as a green run
(#5641 (comment)).
With zombies absorbing the over-release, all assertions pass in under
a second, isolating the crash entirely to window teardown.

Set isReleasedWhenClosed = false on both harness windows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Guard --file mode: require container functions only when one is present

Addresses Greptile P2 on the PR: --file against a row-view source (no
workspaceScrollContent/workspaceRows) emitted false could-not-locate
violations that masked real row findings. In --file mode the container
checks now apply only when at least one guarded function exists in the
source, so ad-hoc row-view scans are clean while a fixture that renamed
one function still fails loudly. Self-test cases added for both sides.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Split probe env key + extension into their own files (Aziz policy)

One major type per Swift file, matching the MinimalModeInvalidationProbe
three-file layout exactly. No content changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Cover the group-header row wrapper (guard target + grouped scale fixture)

Codex review found the blind spot: the group-header row is assembled by
sidebarWorkspaceGroupHeader(...) in VerticalTabsSidebar+WorkspaceGroups.swift,
where modifiers wrap the header before it enters the LazyVStack — a
GeometryReader or anchorPreference added there defeats laziness exactly
like one inside the row view (the #4385 regression entered through the
header path). The guard now scans that whole file for the row-forbidden
shapes with a rename-protected marker, and the scale fixture groups the
first 20 workspaces into 5 groups so group-header realization and
convergence are asserted by the behavioral backstop (bounds on
groupHeaderBodies at mount and in the quiet check).

Verified on the AWS M4 Pro runner: 3/3 pass in 2.7s, no host restarts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Make the scale harness hermetic against persisted sidebar provider

Codex review: VerticalTabsSidebar selects between the workspace list and
extension/built-in sidebars via
@AppStorage(CmuxExtensionSidebarSelection.defaultsKey), so a host with a
persisted non-default provider would mount the wrong sidebar and the
probes would never fire. Use a scratch UserDefaults suite pinned to the
default provider via .defaultAppStorage, cleaned in tearDown — the
WorkspaceContentViewVisibilityTests pattern.

Verified on the AWS M4 Pro runner: 3/3 pass in 2.7s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
mochiexists pushed a commit to mochiexists/cmux-mochi that referenced this pull request Jul 7, 2026
…-view guard (manaflow-ai#7221)

* Extend sidebar lazy-layout guard to the row views (TabItemView, group header)

The source-scan guard from manaflow-ai#6870 protected only the two container
functions, but four of the five historical livelock regressions entered
through the row views: the manaflow-ai#2586/manaflow-ai#6556 GeometryReader -> @State
rowHeight probes lived in TabItemView and
SidebarWorkspaceGroupHeaderView (removed by manaflow-ai#6111, reintroduced by
livelocked in the wild on 2026-07-02 with exactly that signature
(manaflow-ai#2586 (comment)).

Scan the TabItemView region of ContentView.swift and the whole group
header file for per-row geometry feedback: GeometryReader,
onGeometryChange, manual sizeThatFits, ProposedViewSize(nil),
per-row anchorPreference/overlayPreferenceValue, and any discovered
custom Layout. Rows must stay measurement-free; the only sanctioned
geometry path is the container's drag-gated reader. Missing row types
fail loudly so a rename cannot rot the guard into a no-op.

Verified the extended guard retroactively flags both v0.64.17 row
views. New self-test cases (j)-(m) cover clean-pass, the manaflow-ai#6556 probe
shape, the manaflow-ai#5323 anchorPreference shape, and rename protection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add behavioral scale gate for the sidebar lazy-layout contract

The lazy-layout contract (sidebar layout/diff work stays O(visible
rows), never O(all workspaces)) has regressed five times through five
different mechanisms (manaflow-ai#5323 anchorPreference aggregation, manaflow-ai#5764 String
ids, manaflow-ai#5845 animated height interpolation, manaflow-ai#6210 force-measuring custom
Layout, manaflow-ai#6556 GeometryReader -> @State feedback), each shipping to
stable before detection because nothing exercises the sidebar at the
100+ workspace scale where O(N) per pass livelocks the main thread
(manaflow-ai#2586).

SidebarLazyLayoutScaleTests mounts the real VerticalTabsSidebar with
300 workspaces in an NSHostingView and counts actual row body
evaluations through a DEBUG-only environment probe
(SidebarLazyContractProbe, same pattern as
MinimalModeInvalidationProbe):

- mount must realize only viewport rows (catches any virtualization
  defeat, present or future, regardless of mechanism)
- a 40-burst unread-model storm (the sidebar's highest-frequency
  whole-body invalidation path) must stay row-scoped and go quiet when
  the burst stops (catches feedback loops the way manaflow-ai#6556 manifested)
- a harness canary reproduces the GeometryReader -> @State shape in
  divergent form and asserts the harness detects it, so the gate
  cannot silently rot

This is the mechanism-independent backstop behind the source-shape
scan in scripts/check-sidebar-lazy-layout.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix scale-test autorelease avalanche that hung/crashed the app host

Creating 300 workspaces inside one main-actor job accumulated every
autoreleased object from the O(N)-per-add snapshot work into a single
autorelease pool; the closing objc_autoreleasePoolPop then crashed CI
(Signal 11 in AutoreleasePoolPage::releaseUntil, masked as a green run,
see manaflow-ai#5641) and hung for hours
when reproduced on an AWS M4 Pro (sampled: main thread pinned in
releaseUntil). The app never does this; real workspace creation happens
one per event-loop turn with AppKit popping the pool between turns.

Make the harness match real cadence: per-iteration autoreleasepool
around addWorkspace and a run-loop turn every 20 creations. Also hoist
the RunLoop.run call into a synchronous helper (fixes the Swift 6
unavailable-from-async warning) wrapped in its own pool.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix harness NSWindow double-release that killed the app host

NSZombies named the corpse: "-[NSKVONotifying_NSWindow release]:
message sent to deallocated instance". The harness windows used the
NSWindow default isReleasedWhenClosed=true, so tearDown's close()
performed AppKit's own release on top of ARC's; the double-release
SEGV'd the host at the next autorelease-pool pop, before the pass was
recorded, and CI masked the crash as a green run
(manaflow-ai#5641 (comment)).
With zombies absorbing the over-release, all assertions pass in under
a second, isolating the crash entirely to window teardown.

Set isReleasedWhenClosed = false on both harness windows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Guard --file mode: require container functions only when one is present

Addresses Greptile P2 on the PR: --file against a row-view source (no
workspaceScrollContent/workspaceRows) emitted false could-not-locate
violations that masked real row findings. In --file mode the container
checks now apply only when at least one guarded function exists in the
source, so ad-hoc row-view scans are clean while a fixture that renamed
one function still fails loudly. Self-test cases added for both sides.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Split probe env key + extension into their own files (Aziz policy)

One major type per Swift file, matching the MinimalModeInvalidationProbe
three-file layout exactly. No content changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Cover the group-header row wrapper (guard target + grouped scale fixture)

Codex review found the blind spot: the group-header row is assembled by
sidebarWorkspaceGroupHeader(...) in VerticalTabsSidebar+WorkspaceGroups.swift,
where modifiers wrap the header before it enters the LazyVStack — a
GeometryReader or anchorPreference added there defeats laziness exactly
like one inside the row view (the manaflow-ai#4385 regression entered through the
header path). The guard now scans that whole file for the row-forbidden
shapes with a rename-protected marker, and the scale fixture groups the
first 20 workspaces into 5 groups so group-header realization and
convergence are asserted by the behavioral backstop (bounds on
groupHeaderBodies at mount and in the quiet check).

Verified on the AWS M4 Pro runner: 3/3 pass in 2.7s, no host restarts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Make the scale harness hermetic against persisted sidebar provider

Codex review: VerticalTabsSidebar selects between the workspace list and
extension/built-in sidebars via
@AppStorage(CmuxExtensionSidebarSelection.defaultsKey), so a host with a
persisted non-default provider would mount the wrong sidebar and the
probes would never fire. Use a scratch UserDefaults suite pinned to the
default provider via .defaultAppStorage, cleaned in tearDown — the
WorkspaceContentViewVisibilityTests pattern.

Verified on the AWS M4 Pro runner: 3/3 pass in 2.7s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 2071529)

This branch was successfully deployed

1 active deployment
Preview – cmux — c61fe606 Deployed Jun 15, 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.

Allow configurable max width for the Dock (right sidebar)

1 participant