Skip to content

Wire bundled sidebar example providers into cmux - #4933

Closed
lawrencecchen wants to merge 4 commits into
mainfrom
feat-sidebar-extensions
Closed

lawrencecchen wants to merge 4 commits into
mainfrom
feat-sidebar-extensions

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Wire `Examples/CmuxExtensionSidebarExamples` into `cmux.xcodeproj` as a local Swift Package dependency (mirrors how `CmuxExtensionKit` is wired).
  • Register the six bundled providers (`ProjectWorktree`, `AttentionQueue`, `DevServer`, `LastPrompt`, `SuperCompact`, `BrowserStack`) in `CmuxExtensionSidebarSelection.providers` so they show up in the sidebar provider menu.
  • Add a doc comment showing where to drop a vibe-coded provider (full Swift API available, no script sandbox).

End-user workflow for a custom sidebar:

  1. Add a file under `Examples/CmuxExtensionSidebarExamples/Sources/CmuxExtensionSidebarExamples/` implementing `CmuxExtensionSidebarProvider`, `CmuxExtensionSidebarContextualProvider`, or `CmuxExtensionSidebarMutableProvider`.
  2. Append it to `SidebarExamples.providers`.
  3. `./scripts/reload.sh --tag ` and pick it from the provider menu.

Test plan

  • Tagged build (`sb-ext`) compiles
  • Sidebar provider menu shows seven options (Default Workspaces plus the six bundled examples)
  • Each provider renders without crashing when selected
  • BrowserStack provider (mutable) still handles selection / drag

🤖 Generated with Claude Code


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


Note

Low Risk
UI-only wiring and a timing fix for sidebar refresh; no auth, data, or security-sensitive paths.

Overview
The cmux app now depends on CmuxExtensionSidebarExamples and exposes its six example sidebar providers in CmuxExtensionSidebarSelection.providers (instead of an empty list), with a short comment on how to add custom providers. ContentView listens for BrowserStackSidebar.stateDidLoadNotification and triggers refreshExtensionSidebarSnapshot() so persisted Browser Stack layout appears after async load.

BrowserStackSidebar.postStateDidLoadNotification() posts on the main queue asynchronously so SwiftUI .onReceive handlers are installed before the notification fires when state loads in the same render pass.

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


Summary by cubic

Wired CmuxExtensionSidebarExamples into the app and exposed its six bundled sidebar providers. Sidebar snapshot now refreshes immediately and reliably when BrowserStackSidebar loads its saved layout.

  • New Features

    • Registered six providers—ProjectWorktree, AttentionQueue, DevServer, LastPrompt, SuperCompact, BrowserStack—via CmuxExtensionSidebarSelection.providers = SidebarExamples.providers, so they show alongside default workspaces.
    • Added inline docs on adding a custom CmuxExtensionSidebarProvider and rebuilding with ./scripts/reload.sh --tag <tag>.
  • Bug Fixes

    • Observed BrowserStackSidebar.stateDidLoadNotification and call refreshExtensionSidebarSnapshot() so Browser Stack shows the persisted layout immediately after selection or relaunch.
    • Post stateDidLoadNotification on DispatchQueue.main.async to prevent missed notifications during SwiftUI subscription install.

Written for commit 4ad1718. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Sidebar provider examples are now available for selection via the sidebar provider menu.
  • Improvements

    • Sidebar refreshes automatically when the app's sidebar state finishes loading, improving reliability of provider selection.
    • Notification delivery for sidebar state loading was made more robust to prevent missed updates.
  • Documentation

    • Inline guidance added on implementing and registering additional sidebar provider examples.

Review Change Stack

Add the bundled example providers (ProjectWorktree, AttentionQueue,
DevServer, LastPrompt, SuperCompact, BrowserStack) so users can pick
custom sidebars from the provider menu, and document where to drop a
vibe-coded provider in Swift.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@vercel

vercel Bot commented May 28, 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 May 28, 2026 8:36am
cmux-staging Building Building Preview, Comment May 28, 2026 8:36am

@coderabbitai

coderabbitai Bot commented May 28, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a local Swift package dependency (CmuxExtensionSidebarExamples) to the Xcode project, imports it in ContentView to expose SidebarExamples.providers, and refreshes the extension sidebar snapshot when the BrowserStackSidebar state-load notification is posted (now dispatched asynchronously).

Changes

Sidebar Provider Package Integration

Layer / File(s) Summary
Project configuration and package wiring
cmux.xcodeproj/project.pbxproj
Xcode project declares a local Swift package reference at Examples/CmuxExtensionSidebarExamples, registers it in packageReferences, adds the package product dependency to the cmux target, creates a PBXBuildFile entry, and links the product in the target's Frameworks build phase.
ContentView sidebar provider integration
Sources/ContentView.swift
Imports CmuxExtensionSidebarExamples, updates CmuxExtensionSidebarSelection.providers to return SidebarExamples.providers with inline instructions for adding example providers, and adds an onReceive handler for BrowserStackSidebar.stateDidLoadNotification to refresh the extension sidebar snapshot.
BrowserStackSidebar notification dispatch
Examples/CmuxExtensionSidebarExamples/Sources/CmuxExtensionSidebarExamples/BrowserStackSidebar.swift
postStateDidLoadNotification() now posts CmuxBrowserStackSidebarStateDidLoad asynchronously on DispatchQueue.main so SwiftUI .onReceive handlers are likely registered before delivery.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • manaflow-ai/cmux#4662: Reintroduces CmuxExtensionSidebarExamples to supply SidebarExamples.providers in ContentView.swift, while the retrieved PR removes that linkage and sets providers to [].
  • manaflow-ai/cmux#4309: Related changes adding the CmuxExtensionSidebarExamples package and its SidebarExamples/BrowserStackSidebar provider code that this PR wires into the app.

Poem

🐰 A tiny package hops on board,
Sidebar examples now explored,
Import, append, then rebuild bright,
State-load pings refresh the sight,
Hooray — the sidebar springs to light!


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error New BrowserStackSidebarStateCache class uses NSLock for shared mutable state without documenting why an actor cannot be used, violating swift-blocking-runtime.md. Replace NSLock with actor-based design or document why an actor/MainActor cannot protect statesByScope. DispatchQueue.main.async change is correct.
Cmux Full Internationalization ❌ Error 27 new example.sidebar user-facing strings added with only en+ja translations, missing 18 other supported locales: ar, bs, da, de, es, fr, it, km, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant. Add translations for all 20 supported locales to Resources/Localizable.xcstrings example.sidebar entries.
Cmux Architecture Rethink ❌ Error PR introduces DispatchQueue.main.async timing repair in notification posting to work around SwiftUI lifecycle race where notification arrives before .onReceive subscription installs. Replace notification pattern with proper async state exposure or defer subscriptions after async load completes, eliminating the render-time race dependency.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: wiring bundled sidebar example providers into the cmux app, which is the primary objective of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed All Sendable types properly declared; shared mutable state protected with NSLock; async dispatch pattern correct; no implicit MainActor issues; UI updates in MainActor context as intended.
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift code and Xcode project config changes; rule scope explicitly excludes Swift. No TypeScript, JavaScript, shell, or non-Swift runtime scripts were modified.
Cmux Algorithmic Complexity ✅ Passed Fixed-size collections (7 providers, 3 sections) with optimal algorithms: dictionary lookups, single-pass filters, no nested collection scans over scalable data.
Cmux Swift Concurrency ✅ Passed DispatchQueue.main.async usage in postStateDidLoadNotification() is allowed for crossing SwiftUI notification boundaries from Task.detached background completion.
Cmux Swift @Concurrent ✅ Passed The changed function postStateDidLoadNotification() is synchronous and correctly uses DispatchQueue.main.async for explicit main queue hopping—intentional UI-bound work per allowed cases.
Cmux Swift File And Package Boundaries ✅ Passed PR touches oversized ContentView.swift incidentally (~15 lines added, allowed case). BrowserStackSidebar (546 lines) properly isolated in separate local SwiftPM package with focused responsibility.
Cmux Swift Logging ✅ Passed No logging violations found. Changes only add imports, notification listeners, and modify notification posting to async dispatch without introducing print, NSLog, or ad hoc file/stdout logging.
Cmux User-Facing Error Privacy ✅ Passed PR changes include developer documentation, build configuration, and implementation details only. No user-facing errors, alerts, or sensitive information are exposed in the changes.
Cmux Swiftui State Layout ✅ Passed PR adds notification subscription via proper .onReceive pattern; no new @Published/@observable violations, no render-time state mutation, no lazy/list row store references.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds sidebar providers and notification handling with no NSWindow/NSPanel/NSWindowController/Window/WindowGroup creation; lint script passes with no violations.
Description check ✅ Passed PR description includes comprehensive summary, test plan with checkboxes, and clear workflow. However, Testing section lacks specific details on how changes were tested locally.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-sidebar-extensions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR wires CmuxExtensionSidebarExamples into cmux.xcodeproj as a local Swift Package dependency and makes the six bundled example sidebar providers (ProjectWorktree, AttentionQueue, DevServer, LastPrompt, SuperCompact, BrowserStack) visible in the sidebar provider menu.

  • CmuxExtensionSidebarSelection.providers now delegates to SidebarExamples.providers instead of returning an empty array, and inline documentation explains where to drop additional providers.
  • BrowserStackSidebar.postStateDidLoadNotification() wraps its NotificationCenter.post in DispatchQueue.main.async to defer the post until after the current SwiftUI render pass, and VerticalTabsSidebar adds a matching .onReceive handler so the sidebar refreshes immediately once persisted state finishes loading.

Confidence Score: 5/5

Safe to merge; changes are confined to example provider wiring and a UI-layer notification subscription with no impact on auth, persistence, or core data paths.

The xcodeproj linkage mirrors the existing CmuxExtensionKit pattern and introduces no new build risk. The SidebarExamples.providers substitution is straightforward and the providers were already shipping as dead code. The DispatchQueue.main.async wrapper and the BrowserStackSidebar-specific .onReceive are architectural patterns worth revisiting, but they do not introduce a current defect or crash path.

No files require special attention for merge safety. The two architectural observations in BrowserStackSidebar.swift and ContentView.swift are worth tracking as the provider ecosystem grows but do not block this change.

Important Files Changed

Filename Overview
Examples/CmuxExtensionSidebarExamples/Sources/CmuxExtensionSidebarExamples/BrowserStackSidebar.swift Added DispatchQueue.main.async wrapper to postStateDidLoadNotification to paper over a render-pass race between SwiftUI subscription install and notification delivery; flags architectural-rethink rule.
Sources/ContentView.swift Wires SidebarExamples.providers into CmuxExtensionSidebarSelection.providers and adds a BrowserStackSidebar-specific .onReceive handler in VerticalTabsSidebar, coupling the main app view to one concrete example provider.
cmux.xcodeproj/project.pbxproj Adds CmuxExtensionSidebarExamples as an XCLocalSwiftPackageReference and links it as a framework dependency, mirroring the existing CmuxExtensionKit wiring pattern correctly.

Sequence Diagram

sequenceDiagram
    participant V as VerticalTabsSidebar (Main)
    participant BS as BrowserStackSidebar
    participant Cache as BrowserStackSidebarStateCache
    participant BG as Task.detached (utility)
    participant NC as NotificationCenter

    V->>V: .onReceive subscribed (BrowserStackSidebar.stateDidLoadNotification)
    V->>BS: render(snapshot:)
    BS->>Cache: state(for: snapshot)
    Cache->>Cache: startLoadIfNeeded
    Cache->>BG: Task.detached — store.load(scopeKey:)
    BG-->>Cache: applyLoadedState(loaded)
    Cache->>Cache: onAsyncStateLoaded?()
    Cache->>BS: postStateDidLoadNotification()
    BS->>NC: "DispatchQueue.main.async { post(stateDidLoadNotification) }"
    NC-->>V: onReceive fires
    V->>V: refreshExtensionSidebarSnapshot()
Loading

Reviews (4): Last reviewed commit: "Defer BrowserStack stateDidLoad post to ..." | Re-trigger Greptile

Comment thread Sources/ContentView.swift
Comment on lines 9533 to 9535
static var providers: [any CmuxExtensionSidebarProvider] {
[]
SidebarExamples.providers
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Missing locale translations for all 18 non-ja locales

Localizable.xcstrings carries translations for 20 locales (ar, bs, da, de, en, es, fr, it, ja, km, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant), but every example.sidebar.* key — all 27 of them covering provider titles, subtitles, and section headings — is only translated for en and ja. Before this PR, SidebarExamples.providers was dead code ([]); wiring it in here makes these strings live in the provider menu for all locale users. On any non-English, non-Japanese device, every provider name and section header will fall back to the English default value instead of a translated string.

The fix is to add translated entries for all 18 remaining locales to each example.sidebar.* key in Resources/Localizable.xcstrings before shipping.

Rule Used: Flag production user-facing text that is not fully... (source)

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Declining: per CLAUDE.md, the policy is "All user-facing strings must be localized [...] for all supported languages (currently English and Japanese)". The example.sidebar.* keys already match that policy with en+ja entries. These are clearly-labeled demo providers (com.example.cmux.sidebar.* IDs, subtitle "User extension") meant as templates for users vibe-coding their own sidebars, not first-class shipping features.

lawrencecchen and others added 2 commits May 28, 2026 01:31
BrowserStackSidebar posts stateDidLoadNotification after its persisted
layout finishes loading, but nothing observed it, so selecting Browser
Stack or relaunching showed the default layout until the next 30s tick
or workspace event. Observe the notification and refresh the snapshot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The async load can finish on a background thread during the same render
pass that subscribed via .onReceive, so the synchronous notification
could arrive before SwiftUI installs the subscription. Hop to the main
queue so the post lands on a later run-loop turn after the subscription
is live.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants