Skip to content

cmux-next sidebar: the footer becomes Back on a destination page - #18326

Merged
teamleaderleo merged 21 commits into
feat-cmux-nextfrom
op-next-sidebar-footer-back
Oct 7, 2026
Merged

teamleaderleo merged 21 commits into
feat-cmux-nextfrom
op-next-sidebar-footer-back

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

While a window shows a full-page destination, the sidebar's footer becomes one wide Back button in the same spot, a universal way back to where you were (Leo's T3 Code reference).

  • Before: the footer (account avatar and Settings gear) stayed the same on a destination page. The way back was the title bar's Back, the trail, or picking a workspace again.
  • Now: opening a destination (a top page other than Home, such as the App Store) swaps the footer band for a full-width "← Back" button. Clicking it leaves the page for the workspace the window showed. On the workspace the footer's items come back.
  • Home keeps the footer: it is where you land, not a destination.
  • The destination tiles at the top of the sidebar stay as they are. This only adds the Back affordance.

How it works:

  • SidebarModel.showsBack and onBack. The sidebar view lays Back over the footer band's spot (SidebarView+Back).
  • The window root reports each content swap (onContentChange). WindowController sets showsBack from the shown top page, so Back follows pages, workspace switches and a restored page alike. Back runs leaveTopPage().

Testing

  • SidebarFooterBackTests:
    • the footer shows its items until a destination opens;
    • a destination turns the footer into one wide Back button in the footer's spot, and leaving restores the items;
    • a click runs onBack.
  • SidebarFooterBackWiringTests:
    • a destination page shows Back, and Back returns to the workspace the window showed;
    • Home keeps the footer.
  • Red at test commit 3320d1a (fleet suite result in a comment). Green comes from this PR's CI swift test.
  • check-no-godfiles, check-concurrency, check-crash-safety and check-l10n pass locally.
  • Localization: one new string, sidebar.footer.back ("Back"), in all 21 locales, copied from the existing "Back" translations.
  • Captures come later: the reserved recording mini isn't named yet.

Changelog

  • Added: On a full-page destination, the sidebar footer becomes a Back button that returns to your workspace.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Turns the sidebar footer into a wide "← Back" button while a window shows a full-page destination, giving a universal way back to where you were.

  • Before, the footer (account avatar and Settings gear) stayed the same on a destination page; now the footer band gives way to a Back button in the same spot.
  • Back leaves the page for the workspace the window showed; Home keeps the footer since it's where you land, not a destination.
  • The window root reports each content swap, so Back follows pages, workspace switches, and restored pages alike.
  • Adds one new localizable string (sidebar.footer.back, "Back") in all 21 locales, and tests cover layout, wiring, Home keeping the footer, and the button staying clean after drawing.

Bug Fixes

  • Fixed the Back button redrawing every frame, which hung the test run; styling now happens on init, window moves, and appearance changes instead of in updateLayer.

Written for commit 1a93db0. Summary will update on new commits.

Review in cubic Turn on auto-fix


Note

Medium Risk
Proxy policy changes affect how remote browser profiles route traffic (including loopback); behavior is tested but still network-isolation sensitive. Removing Cmd-K search chats is a user-visible regression unless another entry point replaces it.

Overview
This PR bundles three unrelated areas: CEF remote-store proxy policy, recent-chat project scoping, and removal of the agent pane’s Cmd-K “Search chats” sheet.

CEF shim: Per-profile Chromium proxy settings (fixed_servers to http://127.0.0.1:<port> with bypass_list <-loopback>) move into a CEF-free context_proxy_policy.h. shim_proxy.mm applies that helper and uses ContextProxyPortValid for port checks. A standalone context_proxy_test.cpp locks the behavior in.

Agent recents: AcpmuxRecentChats.newest gains an optional in project: filter (applied before the limit), plus a projects list derived from chat folders ordered by recent activity—supporting project-scoped recents in the app feed.

Agent pane search: The dedicated search-chats overlay is dropped: showSearchChats() / searchChats bridge command, ~160 lines of .acpmux-search* CSS in index.html, and search.* strings from locale bundles. Native action catalog entries for search chats may still exist elsewhere in the repo.

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

teamleaderleo and others added 3 commits October 7, 2026 02:14
Leo's T3 Code ref: while the window shows a full-page destination, the
footer becomes one wide Back button in the same spot, and Back returns
to the workspace the window showed. Home keeps the footer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While the window shows a full-page destination (a top page other than
Home), the sidebar's footer band gives way to one wide Back button in
the same spot. Back leaves the page for the workspace the window showed.
The window root reports each content swap, so Back follows pages,
workspaces and a restored page alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 30695b7e-6cdf-4c8a-92e6-e379193189d9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Not verified: macOS jobs did not run: compile and app tests were skipped on 1a93db017f; ci-status is green without them.

CI passes on 1a93db017f (run 37616023633 attempt 1).
macOS jobs did not run: compile and app tests were skipped: Fast static checks skipped (the macos job needs both to succeed). Re-run CI once they pass, before merging.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

@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 using default effort and found 1 potential issue.

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 3d63ba6. Configure here.

action = #selector(pressed)
refusesFirstResponder = true
_ = hover
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Back button hover never appears

Low Severity

SidebarBackButton creates a ChromeHover for the chrome hover look, but it never installs tracking areas or forwards mouse entered, exited, or pressed into that hover. The fill stays idle, so the wide Back control has no hover or pressed feedback.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3d63ba6. Configure here.

teamleaderleo and others added 4 commits October 7, 2026 03:06
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PaneController (all extensions) had grown to 1013 lines, over the 1000-line
god-type budget, failing the cmux-next godfile check on feat-cmux-next.
PaneBrowserTabOpener now owns opening a browser tab in a pane: engine
resolution, opener placement, popup adoption and the session-local WebKit
fallback guard (allowsSessionLocalTab). PaneController.newBrowserTab stays
the entry point and forwards to it, so callers and behavior are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
updateLayer set the image and title, which marked the button for display
again, so every Core Animation commit drew it again and the test run hung.
Style it on init, window moves and appearance changes instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Red/green for the swift test hang on dacfb46:

  • Red: hosted cmux-next swift test (run 37605227811) never finished: 2110 tests started, exit 143, test helper at 52.3 GB. The hang sample shows the main thread looping in SidebarBackButton.updateLayer() (SidebarView+Back.swift:67). It set the image and title there, which marks the button for display again, so every Core Animation commit drew it again.
  • Regression test: 3e8b415 drawingTheBackButtonLeavesItClean (needsDisplay stays false after updateLayer).
  • Fix: b952964 styles the button on init, window moves and appearance changes. updateLayer only sets the corner radius.
  • Green: hosted PR CI on b952964.

The earlier fleet red step for this PR failed on the since-fixed base compile break in PageWebView+Lifecycle.swift, so it doesn't count as evidence.

lawrencecchen and others added 14 commits October 7, 2026 04:25
…calhost (red)

browser.tab.open from the Cloud page: only CEF, only the local HTTP proxy on
127.0.0.1, only from the Cloud page, a derived store key, typed refusal
codes, and the store kept across wake, reroute and relaunch. WebKit and the
engine registry refuse a machine store with a typed error. C++: the
per-profile proxy is fixed_servers on http://127.0.0.1:<port> with
bypass_list exactly "<-loopback>" (scripts/cmux-next/test-context-proxy-cpp.sh).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nly through its proxy, only in CEF

- browser.tab.open, a host action of the Cloud page (cmux.app.action.run):
  {url, machineStore: {machine, machineName, proxy: {kind, host, port}},
  engine: "cef"}. Only the Cloud page may hand over a proxy (the page id
  comes from the page host); only CEF; only an HTTP proxy on exactly
  127.0.0.1 with a port 1..65535; only an http(s) loopback URL. The store
  key is derived in the app: 16 lowercase hex digits of SHA-256 over
  "cmux.cloud.browser-store.v1:" + machine id. Typed refusals:
  cmux.browser.proxy_requires_cef, proxy_invalid, proxy_origin_refused,
  cef_unavailable, invalid_url, no_window. No fallback: the Chromium page is
  made with its store (navigation guard loopbackOnly), then a blank daemon tab
  adopts it.
- ProxiedBrowserTabs keeps the store with the tab for its whole life: wake,
  store reroute and history-page exit get it back through the cache's
  configuration hook; popups with the same store are recorded; WebKit pages
  of a proxied tab load nothing; Open in WebKit is refused; after a relaunch
  (proxy gone) the tab stays blank.
- Fail closed in the engine layer: WebKitEngine.makeTab and
  makeWebKitTab(_ configuration:) throw
  BrowserEngineError.machineStoreRequiresChromium for a machine store, the
  engine registry opens a machine store only in CEF, and the WebKit call
  sites use makeWebKitTab(id:profile:initialURL:zoom:), which cannot carry
  one.
- The shim's per-profile proxy values come from context_proxy_policy.h
  (fixed_servers, http://127.0.0.1:<port>, bypass_list "<-loopback>").

Ported from feat-cmux-next-tabopen (cf70cac) onto the current
feat-cmux-next: shim_proxy.mm includes both agent_url_policy.h (added on
the trunk since) and context_proxy_policy.h. Test call sites the trunk added since
(CertificateRecheckBeforeCommit, CertificateWarningRevoke, LinkClickDisposition,
SaveAsFailure, WebKitFrameRate, WebKitPasskeyAuthorization) use
makeWebKitTab(id:profile:initialURL:zoom:), like the branch's own call sites.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…is Mac's localhost

debug.page gains a `call` action: one call message through the page's
router, exactly as the page's bridge sends it (the host sets the calling
page's id); with page cmux.cloud and no live Cloud page, a hidden one is
made first (the app has no Cloud page entry yet). DEBUG builds only.

scripts/cmux-next/proxied-tab-e2e.py (fleet GUI host only) starts a
listener on 127.0.0.1 and ::1 and a stand-in machine proxy, launches the
tagged app without activation, checks the typed refusals, opens
browser.tab.open on http://localhost:<listener port>/ through the proxy, and
passes when the proxy saw the request and the listener saw no connection.

Ported from feat-cmux-next-tabopen (8352bcd) onto the current
feat-cmux-next: debug.page keeps the trunk's `click` and `type` actions
beside the new `call` action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rectly

The bundled cmux CLI is the Rust binary and has no --socket option.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on from this Mac (red)

The live check (scripts/cmux-next/proxied-tab-e2e.py on cmux-lawrence-2) saw
GET /favicon.ico on this Mac's ::1 listener: the page and its favicon went
through the machine proxy, then the app's own favicon fetch went to this Mac.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…is Mac

BrowserFaviconPolicy: a tab with a machine store (remote localhost or a Cloud
proxied tab) names loopback icons of that machine, so neither the CEF tab's
own favicon fetch nor the tab strip's fetch loads them in the app process
(the tab shows a globe). Other icons load as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…b.open

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Recents filters its chats by project

Leo's T3 Code ref: one filter button (a filter glyph) over Recents opens a
menu with All projects, then each project with a colored two-letter badge,
and no search field of its own. The filter applies before the chat limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: Recents filters its chats by project

Once Recents' chats span two projects, a filter row above them names the
shown project, and its filter button (a filter glyph) opens a menu of All
projects and each project with a colored two-letter badge. There is no
search field of its own. The filter is per window, applies before the
chat limit, and clears when its folder has no chats left. The feed now
notifies on any chat change, so a filtered list stays current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci: retrigger cmux-next on the fixed base

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: import the agent pane module for Recents' chat type

Release builds without member import visibility leaks; AgentRecentsSection
names AcpmuxRecentChat, so it imports CmuxNextAgentPane itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…8178)

* test(cmux-next): the agent pane has no chat search of its own

Decision K1: one palette. The page's Search chats overlay still opens
on the searchChats command, so this fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(cmux-next): remove the agent pane's own chat search; Show all opens the palette

Decision K1, one palette: the page's Search chats overlay is gone, and
its Show all chats buttons run agentPane.searchChats, the command
palette's chats page. The unused AgentPaneView.showSearchChats goes too.
The agent pane bundle is rebuilt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: drop the removed Search chats overlay from the web test lists

SearchChats.tsx is gone, so it leaves the ui-rules pending list and the
gallery coverage allowlist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci: retrigger cmux-next

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: regenerate the agent pane bundle after merging feat-cmux-next

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci: retrigger on the fixed base

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: regenerate the agent pane bundle after merging feat-cmux-next

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@blacksmith-sh

This comment has been minimized.

@teamleaderleo
teamleaderleo merged commit 00c4896 into feat-cmux-next Oct 7, 2026
75 of 90 checks passed
@teamleaderleo
teamleaderleo deleted the op-next-sidebar-footer-back branch October 7, 2026 13:04
teamleaderleo added a commit that referenced this pull request Oct 7, 2026
…before a feat-cmux-next merge

#18326 grew a type past the god-file limit while an unrelated lint red hid the
god-file step. Before a feat-cmux-next merge, gh-merge-green now merges the
PR head into the current base locally and runs, on that merged tree:
- the Swift god-file check (--only swift --base <base>) when the PR changes
  Packages/macOS/CmuxNext, using the base branch's copy of the script and
  baseline so a PR cannot loosen its own check;
- vp check in webviews/ (bun install --frozen-lockfile --ignore-scripts) when
  the PR changes webviews/.
A fork PR, a failed fetch, a moved head or a merge conflict refuses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 9, 2026
…l for feat-cmux-next merges (#18378)

* test(gh-merge-green): a feat-cmux-next merge must refuse frozen paths (red)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(gh-merge-green): refuse feat-cmux-next merges into frozen paths

Before merging into feat-cmux-next, gh-merge-green reads the coordinator's
WINDOW (cmux-lawrence:~/agent-mailbox/WINDOW) and refuses a PR that changes a
path under any `FREEZE: <prefix> token=<t>` line. Only the freeze's holder
merges into it, with --freeze-token; --override never lifts a freeze. A WINDOW
that cannot be read refuses and says to check with the coordinator. Tests read
a local WINDOW through GH_MERGE_GREEN_WINDOW_FILE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(gh-merge-green): the merged head must pass the god-file check and vp check (red)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(gh-merge-green): check the merged head's god files and vp check before a feat-cmux-next merge

#18326 grew a type past the god-file limit while an unrelated lint red hid the
god-file step. Before a feat-cmux-next merge, gh-merge-green now merges the
PR head into the current base locally and runs, on that merged tree:
- the Swift god-file check (--only swift --base <base>) when the PR changes
  Packages/macOS/CmuxNext, using the base branch's copy of the script and
  baseline so a PR cannot loosen its own check;
- vp check in webviews/ (bun install --frozen-lockfile --ignore-scripts) when
  the PR changes webviews/.
A fork PR, a failed fetch, a moved head or a merge conflict refuses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(gh-merge-green): a vp check red already on the base must not block a web PR (red)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(gh-merge-green): a vp check red the base already has does not block a web PR

When the merged head fails vp check, gh-merge-green checks the base tree with
the same install and refuses only for files the base does not flag. A red
already on the base is printed as a note naming its files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(gh-merge-green): a WINDOW token merge must mail RELEASE with the landed SHA (red)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(gh-merge-green): mail RELEASE <AREA> with the landed SHA after a WINDOW token merge

--window-token TOKEN (repeatable) and --freeze-token name the WINDOW tokens a
merge lands under. Before merging, each must be current: an [AREA] section's
token: or a hold line's token= (PKG ...). Right after the merge gh-merge-green
reads the merge commit and writes a RELEASE <AREA>: #N landed <sha> mail to
cmux-lawrence:~/agent-mailbox/inbox/lawrence-coordinator (atomic tmp + mv).
If the mail fails, it exits non-zero and prints the text to send by hand.
Lawrence's coordinator had missed a manual RELEASE mail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(gh-merge-green): a test run must never mail the real coordinator inbox (red)

Two runs of the freeze-token test mailed fake RELEASE FREEZE: #42 into the
real lawrence-coordinator inbox. Under test, or with a local WINDOW file, a
token merge without GH_MERGE_GREEN_MAILBOX_DIR must refuse before merging and
never run ssh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(gh-merge-green): tests can never mail the real coordinator inbox

The freeze-token test ran with no mailbox override, so each run mailed a fake
RELEASE FREEZE: #42 to the real lawrence-coordinator inbox over ssh. Now:
- under GH_MERGE_GREEN_TEST, or with a local GH_MERGE_GREEN_WINDOW_FILE, a
  token merge without GH_MERGE_GREEN_MAILBOX_DIR refuses before merging, and
  the send site refuses again (fail closed);
- under GH_MERGE_GREEN_TEST the WINDOW is never read over ssh;
- the test module sets GH_MERGE_GREEN_TEST and a temp mailbox for every run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(gh-merge-green): a test helper crash the base also has is base-owned (red)

A swift test whose test helper dies on a signal names different in-flight
tests and crashed-thread frames each run, so the head's crash never
matched the base's and gh-merge-green refused it without --override.
Same signal on the base's latest verdict run means the base owns it; a
crash the base lacks, another signal, or a pre-crash red the base lacks
still blocks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(gh-merge-green): excuse a test helper crash the base also has

base_red_excuse.py reads the signal a test helper died on from SwiftPM's
"exited with unexpected signal code N" line or the hang sampler's
"the test helper died on signal N" error. Those crash lines and the
unfinished-test list are no longer compared, since they differ run to
run; instead the base's job must have died on the same signal. Failed
steps and any test red before the crash are still compared, and the
audit line names the signal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants