Skip to content

Adopt macOS 26 Liquid Glass design - #2647

Open
rodchristiansen wants to merge 2260 commits into
manaflow-ai:mainfrom
rodchristiansen:liquid-glass-design
Open

rodchristiansen wants to merge 2260 commits into
manaflow-ai:mainfrom
rodchristiansen:liquid-glass-design

Conversation

@rodchristiansen

@rodchristiansen rodchristiansen commented Apr 6, 2026 •

Copy link
Copy Markdown

Summary

  • NavigationSplitView with native glass sidebar and system titlebar on macOS 26
  • SwiftUI .toolbar for bell and new-tab buttons with .accessoryBarAction style
  • 8pt external padding around terminal detail content for Liquid Glass spacing
  • 6pt internal terminal content inset keeps text within safe zone
  • Leading corners (top-left, bottom-left) rounded at AppKit portal level when sidebar visible
  • Bonsplit tab bar hidden for single-tab panes on macOS 26
  • Old titlebar accessory controllers and custom titlebar overlay skipped on macOS 26
  • App icon auto-set skipped on macOS 26 (system handles dark variants)

Known limitations

  • Terminal corner rounding (right side): CAMetalLayer ignores Core Animation clipping (cornerRadius, masksToBounds, layer.mask on parent views). Left corners work because the sidebar glass provides contrast. Full corner rounding deferred to follow-up.
  • Light mode sidebar tint: NavigationSplitView's glass material adds a subtle gray tint in light mode. This matches native apps (Finder, Mail) and is the expected system behavior.

Test plan

  • Verify glass sidebar renders correctly in light and dark mode
  • Verify toolbar buttons (bell, +) appear and function
  • Verify 8pt padding around terminal on all sides
  • Verify terminal text has internal padding (doesn't touch edges)
  • Verify left corners are rounded when sidebar is visible
  • Toggle sidebar visibility — padding and corners adapt
  • Test fullscreen transitions
  • Test split panes and workspace switching
  • Test drag/drop reordering in sidebar

🤖 Generated with Claude Code


Summary by cubic

Adopts macOS 26 Liquid Glass and updates cmux’s current app and CLI baseline. On macOS 26, custom AppKit titlebar/sidebar handling is replaced with native NavigationSplitView, system titlebar behavior, and SwiftUI toolbar actions; older macOS versions keep the legacy path.

App changes

  • Restores the right sidebar, persists its width, and uses the system sidebar toggle when visible with a custom leading toggle when hidden.
  • Adds window-scoped notification popovers, pane actions, new-tab controls, updated shortcut ⌃⌘S, and native window dragging.
  • Adds Liquid Glass spacing, hover states, terminal insets, sidebar-aware corner rounding, single-tab bar hiding, scrollbar fixes, and terminal/browser focus and selection regressions fixes.
  • Updates app icon assets for light and dark variants; macOS 26 uses the system icon handling.
  • The terminal’s right corners remain unclipped because CAMetalLayer does not honor parent view clipping.

CLI, integrations, and delivery

  • Replaces cmuxterm with the Swift cmux CLI and adds cmux omx/cmux omc integrations.
  • Adds generic setup-hooks and uninstall-hooks support for Codex, Cursor, Gemini, Copilot, CodeBuddy, Factory, and Qoder.
  • Adds the system-wide hotkey, shared shortcut matching, zsh TERM handoff, user zshenv opt-outs, and printable shifted-punctuation input fixes.
  • Adds macOS 15/26 compatibility CI, GhosttyKit builds and checksum guards, nightly/release workflows, and post-release Homebrew updates.

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

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added toolbar items for sidebar, notifications, and creating a new workspace.
    • Notifications can appear in a dedicated popover and via system notification on newer macOS.
  • Improvements

    • Modern split-view navigation with constrained sidebar widths and hidden dividers on newer macOS.
    • Updated titlebar/window appearance and enabled window movability on newer macOS.
    • Reduced terminal top padding, refined corner rounding and scroll insets, removed sidebar scrim.
    • Subtle glass hover effects for tabs and footer buttons.
  • Other

    • Default sidebar shortcut changed; app icon resource explicitly included.

Note

Medium Risk
Medium risk because it changes core window/layout behavior and notification popover handling with macOS-version branching (including some AppKit toolbar/view hierarchy manipulation) that could regress multi-window UI interactions.

Overview
On macOS 26+, the main window layout switches to NavigationSplitView to get native Liquid Glass sidebar/titlebar behavior, adds an 8pt padded detail area, disables custom titlebar overlays/accessories, and relies on system safe areas/window dragging instead of the previous "immovable window" approach.

Notifications UI is reworked for macOS 26: the bell button becomes a SwiftUI toolbar item with a per-window SwiftUI popover, plus new AppDelegate notification broadcasts/state tracking so menu/command invocations toggle/dismiss the correct window’s popover.

Additional macOS 26 polish includes Liquid Glass hover/active effects in the sidebar, hiding bonsplit’s single-tab tab bar, insetting terminal scroll content for rounded-corner safe zones, rounding terminal leading corners based on actual split-view sidebar visibility, and avoiding manual WindowGlassEffect insertion so it doesn’t fight system glass. Separately, the default Toggle Sidebar shortcut changes and project wiring/resources are updated (including bundling AppIcon.icon and updating the vendor/bonsplit submodule URL).

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

lawrencecchen and others added 30 commits April 5, 2026 18:26
…i#2447)

* test: cover printable shift punctuation key equivalents

* fix: bypass key equivalents for printable shifted punctuation

* Fix terminal test host lifetime
…256color

Keep prompt colors when switching local TERM to xterm-256color
…ve (manaflow-ai#2579)

* Suppress cmd hover path highlight during selection

* Fix cmd-hover links during selection

* Strip cmd hover state during selection

* Add cmd-click regression UI tests

* Resolve escaped-space cmd-click paths

* Stabilize cmd-click regression coverage

* fix: resolve raw-space cmd-click paths

* test: retry cmd-click token geometry capture

* test: cover quicklook mismatch cmd-click regression

* fix: prefer snapshot path over mismatched quicklook

* test: cover viewport-offset cmd-click regression

* fix: prefer click-point snapshot over viewport offsets

* Add logged path cmd-click regression matrix

* Strengthen ls cmd-click cell coverage

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
* Add regression test for lost terminal key routing

* Repair focused terminal key routing after responder drift

* Address PR review feedback

* fix: coerce search focus debug token to String

* chore: retrigger PR workflows

* fix: address review feedback on focus repair
lawrencecchen and others added 3 commits April 22, 2026 04:49
* Split AppDelegate support code into focused files

* Drain privileged installer output before waiting

* Clear pipe readers at EOF

* Avoid overlapping privileged output reads

* Deduplicate resolved Finder directories

* Harden shortcut routing edge cases

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
Rebased onto current upstream main (resolves PR manaflow-ai#2647 merge conflicts).

Summary of the Liquid Glass pass, all gated on #available(macOS 26.0, *):
- NavigationSplitView with native glass sidebar and system titlebar
- SwiftUI .toolbar with .accessoryBarAction style for bell + new-tab;
  pane actions (terminal/browser/split) as a ControlGroup
- Notifications popover via SwiftUI .popover, scoped to the owning
  window via a windowId-tagged NotificationCenter broadcast
- Unread notification badge on the toolbar bell button
- 8pt external padding around terminal detail content; 6pt internal
  scroll inset so text stays within the safe zone
- Leading corners rounded at AppKit portal level when sidebar is visible
- SplitViewDividerHider clears NSSplitView divider color
- Tab bar collapses to 0 height on macOS 26 (hides for single-tab panes
  once the matching bonsplit change lands)
- System handles app icon appearance on macOS 26
  (AppIcon.icon now wired into Resources with folder.iconcomposer.icon
  type so actool emits Aqua/Dark/Tintable variants)
- Legacy titlebar accessory controllers and custom titlebar overlay
  skipped on macOS 26
- Toggle Sidebar default shortcut changed to ⌃⌘S (system standard)
- System sidebar chevron + injected tracking separator stripped

Rebase notes for reviewers:
- Squashed the original 10-commit PR into one commit while rebasing
  onto current manaflow-ai/main. No behavior change vs prior tip.
- Upstream refactor "Split AppDelegate support code" reconciled by
  taking the new file layout; Liquid Glass edits move with it.
- Submodule vendor/bonsplit pinned at upstream SHA. The single-tab
  tab bar hiding needs a bonsplit-side change; tracked separately.

Known limitations (unchanged from prior tip):
- Terminal right-side corner rounding: CAMetalLayer ignores Core
  Animation clipping; deferred to follow-up.
- Light mode sidebar has a subtle glass tint from NavigationSplitView,
  matching Finder/Mail.
rodchristiansen added a commit to rodchristiansen/cmux that referenced this pull request Apr 22, 2026
Rebased onto current upstream main (resolves PR manaflow-ai#2647 merge conflicts).

Summary of the Liquid Glass pass, all gated on #available(macOS 26.0, *):
- NavigationSplitView with native glass sidebar and system titlebar
- SwiftUI .toolbar with .accessoryBarAction style for bell + new-tab;
  pane actions (terminal/browser/split) as a ControlGroup
- Notifications popover via SwiftUI .popover, scoped to the owning
  window via a windowId-tagged NotificationCenter broadcast
- Unread notification badge on the toolbar bell button
- 8pt external padding around terminal detail content; 6pt internal
  scroll inset so text stays within the safe zone
- Leading corners rounded at AppKit portal level when sidebar is visible
- SplitViewDividerHider clears NSSplitView divider color
- Tab bar collapses to 0 height on macOS 26 (hides for single-tab panes
  once the matching bonsplit change lands)
- System handles app icon appearance on macOS 26
  (AppIcon.icon now wired into Resources with folder.iconcomposer.icon
  type so actool emits Aqua/Dark/Tintable variants)
- Legacy titlebar accessory controllers and custom titlebar overlay
  skipped on macOS 26
- Toggle Sidebar default shortcut changed to ⌃⌘S (system standard)
- System sidebar chevron + injected tracking separator stripped

Rebase notes for reviewers:
- Squashed the original 10-commit PR into one commit while rebasing
  onto current manaflow-ai/main. No behavior change vs prior tip.
- Upstream refactor "Split AppDelegate support code" reconciled by
  taking the new file layout; Liquid Glass edits move with it.
- Submodule vendor/bonsplit pinned at upstream SHA. The single-tab
  tab bar hiding needs a bonsplit-side change; tracked separately.

Known limitations (unchanged from prior tip):
- Terminal right-side corner rounding: CAMetalLayer ignores Core
  Animation clipping; deferred to follow-up.
- Light mode sidebar has a subtle glass tint from NavigationSplitView,
  matching Finder/Mail.
@rodchristiansen

Copy link
Copy Markdown
Author

Rebased onto current manaflow-ai/main (tip 03a0c14b) and squashed to a single commit to keep the diff clean against the "Split AppDelegate support code" refactor.

Reconciliation notes:

  • Sources/cmuxApp.swift: kept the mainWindowContent extraction; merged in upstream's new .environmentObject(fileExplorerState) and appDelegate.fileExplorerState = fileExplorerState. applyIcon keeps both upstream's isApplicationFinishedLaunching guard and the macOS 26 early return.
  • Sources/ContentView.swift: upstream moved SidebarBackdrop into a helper layer, so the old conditional .background modifier is no longer needed on this path.
  • Sources/Workspace.swift: combined upstream's new tabTitleFontSize parameter with tabBarHeight/showSplitButtons (argument order fixed).
  • project.pbxproj: re-applied the AppIcon.icon wiring (PBXBuildFile entry, folder.iconcomposer.icon type, Resources phase) on top of upstream's current state.
  • vendor/bonsplit: pinned at upstream SHA. The single-tab tab-bar hiding needs the matching bonsplit-side change (PaneContainerView conditional on tabBarHeight > 0 || tabs.count > 1). Happy to open that as a separate bonsplit PR — without it, the tab bar just renders at 0 height on macOS 26 rather than being truly hidden.

Local compile (xcodebuild … Debug) passes on macOS 26. Net diff +605 / -134 across 10 files, unchanged in scope vs the prior tip.

Comment thread Sources/Workspace.swift
Two linked fixes for the macOS 26 NavigationSplitView toolbar:

1) Keep our own sidebar-toggle button in the leading toolbar position
   unconditionally (both states) instead of only when the sidebar is
   hidden. The system-injected toggle was the only affordance to hide
   the sidebar when it was visible, and we want to strip that everywhere.

2) Strengthen SystemSidebarToggleStripperView so the system toggle does
   not leak through when the window is narrow enough to push toolbar
   items into the overflow popover:
   - Also match items by user-facing label ("Hide Sidebar" / "Show
     Sidebar"), since NavigationSplitView re-injects the toggle into
     the overflow with an opaque identifier that does not contain
     "toggleSidebar".
   - Observe NSToolbar.willAddItemNotification and re-strip on every
     item insertion, so SwiftUI cannot silently re-add the toggle
     after our initial strip.
   - Observe NSWindow.didResizeNotification since window resize is
     what triggers the re-layout that shoves items into overflow.

Before: narrowing the window revealed a `»` overflow chevron whose
popover contained a system "Hide Sidebar" button even though we had
stripped the same item from the main toolbar at launch.

After: the overflow popover no longer contains any sidebar toggle in
either state, and the leading sidebar button remains available at all
window widths.
Comment thread Sources/ContentView.swift

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

6 issues found across 10 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/GhosttyTerminalView.swift">

<violation number="1" location="Sources/GhosttyTerminalView.swift:9599">
P2: Fixed 6pt inset is not clamped to current bounds, so transient tiny host sizes can produce zero/negative scroll/surface dimensions.</violation>
</file>

<file name="Sources/AppDelegate.swift">

<violation number="1" location="Sources/AppDelegate.swift:8645">
P2: macOS 26 notification toggle can still broadcast globally when no target window is resolved, causing multiple windows to toggle instead of only the intended one.</violation>

<violation number="2" location="Sources/AppDelegate.swift:8651">
P2: macOS 26 notifications popover toggle is SwiftUI-notification driven, but dismiss/isShown still query only the legacy titlebar accessory controller, causing stale state and potential no-op dismiss behavior.</violation>
</file>

<file name="Sources/ContentView.swift">

<violation number="1" location="Sources/ContentView.swift:14750">
P2: Sidebar-toggle stripping depends on hardcoded English toolbar labels, which can fail on localized macOS and leave duplicate sidebar controls.</violation>

<violation number="2" location="Sources/ContentView.swift:14825">
P2: Divider-hiding logic patches every NSSplitView in the window, not just NavigationSplitView, risking unintended UI regressions in unrelated split-based views.</violation>
</file>

<file name="Sources/TerminalWindowPortal.swift">

<violation number="1" location="Sources/TerminalWindowPortal.swift:1507">
P2: Sidebar detection via `targetFrame.origin.x > 20` is not specific to sidebar visibility and can incorrectly round split panes when sidebar is hidden.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread Sources/GhosttyTerminalView.swift
Comment thread Sources/AppDelegate.swift
Comment thread Sources/AppDelegate.swift
Comment thread Sources/ContentView.swift Outdated
Comment thread Sources/ContentView.swift Outdated
Comment thread Sources/TerminalWindowPortal.swift Outdated
The prior overflow fix matched system-injected toggle items by label
("Hide Sidebar" / "Show Sidebar"), which breaks on localized macOS
builds. Replace the label check with an action-selector check against
toggleSidebar: — the same selector AppKit uses internally for both
NSSplitViewController.toggleSidebar and NavigationSplitView's injected
item, regardless of locale.

Identifier-based matching (items whose itemIdentifier contains
"toggleSidebar" or "splitViewSeparator") remains as the primary path
for items that carry a stable identifier.

Flagged by cursor[bot] and cubic-dev-ai[bot] on PR manaflow-ai#2647.
rodchristiansen added a commit to rodchristiansen/cmux that referenced this pull request Apr 23, 2026
The prior overflow fix matched system-injected toggle items by label
("Hide Sidebar" / "Show Sidebar"), which breaks on localized macOS
builds. Replace the label check with an action-selector check against
toggleSidebar: — the same selector AppKit uses internally for both
NSSplitViewController.toggleSidebar and NavigationSplitView's injected
item, regardless of locale.

Identifier-based matching (items whose itemIdentifier contains
"toggleSidebar" or "splitViewSeparator") remains as the primary path
for items that carry a stable identifier.

Flagged by cursor[bot] and cubic-dev-ai[bot] on PR manaflow-ai#2647.
Comment thread Sources/ContentView.swift
Seven follow-ups flagged by cursor[bot] and cubic-dev-ai[bot] on 4/22–4/23:

1. (HIGH) Restore right sidebar panel on macOS 26 — wrap NavigationSplitView
   detail with terminalContentWithRightSidebarPanel so File Explorer and
   Session Index remain reachable.
2. Bump vendor/bonsplit to cfff8a9 ("Hide tab bar when tabBarHeight is 0")
   so the macOS 26 single-tab pane actually collapses the bar instead of
   rendering at zero height; switch the submodule URL to rodchristiansen/
   bonsplit (same change already on main) since cfff8a9 isn't on a tracked
   branch of manaflow-ai/bonsplit. Drop tabTitleFontSize references from
   Workspace.swift to match the new bonsplit Appearance API.
3. Clamp the macOS 26 6pt scroll-view inset to max(0, bounds-inset) and
   skip it entirely for sub-16pt host bounds so transient tiny layouts
   can't produce zero/negative scroll/surface dimensions.
4. AppDelegate.toggleNotificationsPopover early-returns when no
   targetWindowId resolves (was broadcasting globally to every observer).
5. dismissNotificationsPopoverIfShown / isNotificationsPopoverShown route
   through a per-window state set on macOS 26 so they don't return stale
   results from the legacy titlebar accessory controller.
6. SplitViewDividerHider walks up to the nearest enclosing NSSplitView
   instead of recursing the whole window.contentView, so unrelated
   split-based UI can't be silently mutated.
7. TerminalWindowPortal corner-radius logic asks the enclosing NSSplitView
   whether its sidebar subview is collapsed instead of using the
   origin.x > 20 frame heuristic; falls back to the heuristic when no
   ancestor exists.
rodchristiansen added a commit to rodchristiansen/cmux that referenced this pull request Apr 24, 2026
Seven follow-ups flagged by cursor[bot] and cubic-dev-ai[bot] on 4/22–4/23:

1. (HIGH) Restore right sidebar panel on macOS 26 — wrap NavigationSplitView
   detail with terminalContentWithRightSidebarPanel so File Explorer and
   Session Index remain reachable.
2. Bump vendor/bonsplit to cfff8a9 ("Hide tab bar when tabBarHeight is 0")
   so the macOS 26 single-tab pane actually collapses the bar instead of
   rendering at zero height; switch the submodule URL to rodchristiansen/
   bonsplit (same change already on main) since cfff8a9 isn't on a tracked
   branch of manaflow-ai/bonsplit. Drop tabTitleFontSize references from
   Workspace.swift to match the new bonsplit Appearance API.
3. Clamp the macOS 26 6pt scroll-view inset to max(0, bounds-inset) and
   skip it entirely for sub-16pt host bounds so transient tiny layouts
   can't produce zero/negative scroll/surface dimensions.
4. AppDelegate.toggleNotificationsPopover early-returns when no
   targetWindowId resolves (was broadcasting globally to every observer).
5. dismissNotificationsPopoverIfShown / isNotificationsPopoverShown route
   through a per-window state set on macOS 26 so they don't return stale
   results from the legacy titlebar accessory controller.
6. SplitViewDividerHider walks up to the nearest enclosing NSSplitView
   instead of recursing the whole window.contentView, so unrelated
   split-based UI can't be silently mutated.
7. TerminalWindowPortal corner-radius logic asks the enclosing NSSplitView
   whether its sidebar subview is collapsed instead of using the
   origin.x > 20 frame heuristic; falls back to the heuristic when no
   ancestor exists.

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c89a423. Configure here.

Comment thread .gitmodules
[submodule "vendor/bonsplit"]
path = vendor/bonsplit
url = https://github.com/manaflow-ai/bonsplit.git
url = https://github.com/rodchristiansen/bonsplit.git

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bonsplit submodule URL changed to personal fork

Medium Severity

The bonsplit submodule URL was changed from the organization repo (manaflow-ai/bonsplit.git) to a personal fork (rodchristiansen/bonsplit.git). Merging this to main would make the project depend on a personal fork rather than the canonical organization repository, creating a bus-factor risk and potential access issues for other contributors.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c89a423. Configure here.

Comment thread Sources/WindowToolbarController.swift

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

2 issues found across 7 files (changes from recent commits).

You’re at about 92% of the monthly review limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/Workspace.swift">

<violation number="1" location="Sources/Workspace.swift:6756">
P2: Removing the `surfaceTabBarFontSize` plumbing makes the tab-title font-size setting a no-op for new workspaces and config/theme refreshes.</violation>
</file>

<file name=".gitmodules">

<violation number="1" location=".gitmodules:10">
P2: Point this submodule back to the organization-owned bonsplit repository to avoid relying on a personal fork that can disappear or drift unexpectedly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread Sources/Workspace.swift
)
}

private static func bonsplitAppearance(from config: GhosttyConfig) -> BonsplitConfiguration.Appearance {

@cubic-dev-ai cubic-dev-ai Bot Apr 24, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Removing the surfaceTabBarFontSize plumbing makes the tab-title font-size setting a no-op for new workspaces and config/theme refreshes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/Workspace.swift, line 6756:

<comment>Removing the `surfaceTabBarFontSize` plumbing makes the tab-title font-size setting a no-op for new workspaces and config/theme refreshes.</comment>

<file context>
@@ -6752,8 +6752,7 @@ final class Workspace: Identifiable, ObservableObject {
-            backgroundOpacity: config.backgroundOpacity,
-            tabTitleFontSize: config.surfaceTabBarFontSize
+            backgroundOpacity: config.backgroundOpacity
         )
     }
 
</file context>
Fix with Cubic

Comment thread .gitmodules
[submodule "vendor/bonsplit"]
path = vendor/bonsplit
url = https://github.com/manaflow-ai/bonsplit.git
url = https://github.com/rodchristiansen/bonsplit.git

@cubic-dev-ai cubic-dev-ai Bot Apr 24, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Point this submodule back to the organization-owned bonsplit repository to avoid relying on a personal fork that can disappear or drift unexpectedly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .gitmodules, line 10:

<comment>Point this submodule back to the organization-owned bonsplit repository to avoid relying on a personal fork that can disappear or drift unexpectedly.</comment>

<file context>
@@ -7,4 +7,4 @@
 [submodule "vendor/bonsplit"]
 	path = vendor/bonsplit
-	url = https://github.com/manaflow-ai/bonsplit.git
+	url = https://github.com/rodchristiansen/bonsplit.git
</file context>
Suggested change
url = https://github.com/rodchristiansen/bonsplit.git
url = https://github.com/manaflow-ai/bonsplit.git
Fix with Cubic

Two follow-ups after on-device verification of 2248c67:

1. Vertical line at the sidebar boundary returned because the prior
   ancestor walk in SplitViewDividerHider doesn't find the
   NavigationSplitView's NSSplitView — the hider is mounted as a
   `.background`, which sits as a sibling in SwiftUI's hosting hierarchy
   rather than as a descendant. Walk down from window.contentView and
   patch only the topmost (first) NSSplitView found, which is reliably
   the NavigationSplitView. Still respects cubic[bot]'s concern
   (no recursive patching of every split view in the window).

2. Sidebar-toggle button placement now follows Apple HIG: when the
   sidebar is shown, the toggle sits inside the sidebar column's leading
   edge (matching Mail/Notes); when collapsed, it appears in the leading
   toolbar position. Achieved by removing the custom
   ToolbarItem(placement: .navigation) toggle and the
   SystemSidebarToggleStripper — NavigationSplitView's native toggle
   provides the correct placement automatically. The columnVisibility
   binding wires the native toggle into our SidebarState.
The previous attempt to rely entirely on NavigationSplitView's auto-injected
sidebar toggle backfired: on macOS 26 the system toggle gets pushed into
the toolbar overflow popover when the sidebar is collapsed, leaving no
visible button on the leading edge.

Reinstate the custom ToolbarItem(placement: .navigation) sidebar toggle
so there's always a visible leading-edge button, plus
SystemSidebarToggleStripper to remove the system duplicate. The stripper's
match rules (action == toggleSidebar: or itemIdentifier contains
"toggleSidebar"/"splitViewSeparator") only match AppKit-native items; our
SwiftUI button uses neither, so it survives.
Mail/Notes pattern (Apple HIG): when the sidebar is shown, the toggle
button sits at the top of the sidebar column itself; when the sidebar is
hidden, the toggle appears on the leading edge of the toolbar so the user
can re-open it.

Implementation:

- Add a borderless sidebar.left button at the top of the sidebar VStack
  in the macOS 26 NavigationSplitView. It's only visible when the sidebar
  is shown (because the whole column is collapsed otherwise).
- Make the ToolbarItem(placement: .navigation) toggle conditional on
  sidebarState.isVisible == false. So exactly one toggle is visible in
  every state, in the right place, and the bottom-of-stack
  SystemSidebarToggleStripper continues to drop any system duplicate.
Putting .toolbar on the sidebar view (rather than the NavigationSplitView
root) places the leading-navigation item at title-bar y-level *inside*
the sidebar column — Apple HIG / Mail / Notes pattern. NavigationSplitView
auto-relocates the same item to the leading edge of the detail toolbar
when the sidebar is collapsed, so a single ToolbarItem covers both
states. The SystemSidebarToggleStripper continues to drop any
auto-injected duplicate.
User-observed behavior on macOS 26: the system-injected toggle DOES place
itself correctly (inside the sidebar column at title-bar y-level when
expanded; leading edge of the detail toolbar when collapsed). The
previous SystemSidebarToggleStripper was killing the *good* placement
during sidebar drag, leaving only our custom (wrong-position) toggle.

Drop the stripper and the custom ToolbarItem entirely; let
NavigationSplitView handle sidebar-toggle placement on macOS 26. The
columnVisibility binding still routes the system toggle through
SidebarState.

Reverts both 0d25bbb (system-toggle stripper + custom leading toggle)
and 19a63d7 (re-introduction of the stripper after the prior trial of
this approach), now that the sidebar-internal trial of 27ea2e3/2eb854bc
showed the system toggle was already placing itself in the right spot.
If the overflow regression returns when the window is narrowed, we'll
solve it with toolbar-item priority instead of stripping.
…e when hidden

When the sidebar is shown, NavigationSplitView's auto-injected toggle places
itself correctly inside the sidebar column at title-bar y-level. When the
sidebar is hidden, the same toggle gets shoved into the toolbar overflow
popover instead of the leading edge.

Gate both the SystemSidebarToggleStripper and the custom
ToolbarItem(placement: .navigation) on `!sidebarState.isVisible`. Result:

* Sidebar shown: only the system in-sidebar toggle is visible, in the right
  place.
* Sidebar hidden: stripper kills the overflow duplicate, custom leading
  toolbar item is the user-visible affordance.

Local-only commit (not pushing to PR while iterating).
@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review (1265 files, 100 file limit).

@teamleaderleo teamleaderleo added area: appearance Themes, light and dark mode, window chrome S3: minor Wrong behavior with a workaround labels Sep 30, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: appearance Themes, light and dark mode, window chrome S3: minor Wrong behavior with a workaround

Projects

None yet

Development

Successfully merging this pull request may close these issues.