Skip to content

Add configurable browser engine selection - #8163

Closed
austinywang wants to merge 42 commits into
mainfrom
feat-browser-engine-choice
Closed

austinywang wants to merge 42 commits into
mainfrom
feat-browser-engine-choice

Conversation

@austinywang

@austinywang austinywang commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add a Browser Engine setting with Auto, Safari (WebKit), and Chromium choices for newly created browser panes.
  • Resolve Auto from the macOS default browser while keeping remote-proxied panes and cmux internal pages on WebKit.
  • Introduce engine-neutral navigation, JavaScript, screenshot, recovery, persistence, and socket automation paths, backed by WebKit or a Chromium CDP session.
  • Preserve the selected engine when restoring recently closed browser panes and expose the engine through browser socket payloads.
  • Document the config key and localize all new user-facing strings across the supported app and web locales.

Testing

  • xcodebuild -project cmux.xcodeproj -scheme cmux-unit -configuration Debug -destination "platform=macOS" -derivedDataPath /tmp/cmux-feat-browser-engine-choice -jobs 4 build
  • swift test in Packages/macOS/CmuxBrowser — 171 tests passed.
  • Native arm64 swift test --skip-build in Packages/macOS/CmuxSettings — 252 tests passed.
  • Native arm64 swift test --skip-build in Packages/macOS/CmuxSettingsUI — 112 tests passed.
  • ./scripts/reload.sh --tag feat-browser-engine-choice
  • Localization audit: 14 app keys populated in all 20 app locales; schema description populated in all 20 web catalogs; JSON and %@ placeholder checks passed.
  • Workspace package grouping, Package.resolved policy, pbxproj normalization/check, and diff whitespace checks passed.

Demo Video

  • Video URL or attachment: Pending dogfood recording.

Review Trigger (Copy/Paste as PR comment)

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

Checklist

  • I tested the change locally
  • I added or updated tests for behavior changes
  • I updated docs/changelog if needed
  • I requested bot reviews after my latest commit (copy/paste block above or equivalent)
  • All code review bot comments are resolved
  • All human review comments are resolved

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


Summary by cubic

Adds a configurable browser engine for new panes (Auto, WebKit, Chromium) with a unified, engine‑agnostic session layer. Engine choice persists across restores; topology reports the engine and PID; and Chromium’s viewport/input, control‑event buffering, process lifecycles, and main‑frame loading state are complete and bounded.

  • New Features

    • New setting browser.engine (auto | webkit | chromium) with a Settings picker; Auto resolves via LaunchServices and selects Chromium only for known Chromium‑family apps; explicit picks bypass system defaults.
    • Unified engine API across WebKit and CDP‑controlled Chromium: navigation, JavaScript (page/isolated worlds with Promise await), screenshots, cookies, state, zoom. Find‑in‑page and automation init/style scripts run via the active engine with clear timeout errors.
    • Chromium streams to a local viewport with bounded resolution/cadence, suspends offscreen, coalesces pointer input without reordering, fences drag begin/end, forwards IME/composition/paste as committed text, preserves page exception text, enforces pre‑commit navigation policy, and uses per‑profile dirs to avoid lock conflicts. Zoom changes the page engine without scaling the canvas transport.
    • Engine selection applies to user‑created tabs and dock‑browser flows and persists across restores/recently closed; if Chromium isn’t available, restores downgrade to WebKit and keep the URL. Terminal topology payloads include browser_engine and resolve the correct content‑process PID per engine. Settings schema/docs/localizations updated.
  • Bug Fixes

    • Chromium: record history once per completed top‑level navigation (title updates no longer double‑log).
    • Chromium: bound control‑event buffering and process shutdown/termination; kept the engine alive under input backpressure, isolated input ordering, and corrected drag input and topology reporting.
    • Chromium: track main‑frame loading state; subframe events no longer toggle pane loading.
    • Fixed live title/zoom state and enforced navigation‑policy invariants; added tests to prevent regressions in engine event routing and user script handling.

Written for commit 5bd81fd. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added selectable Chromium engine support alongside WebKit for browser panes, including engine-aware automation, cookies, screenshots, and JavaScript evaluation.
    • Introduced a new browser.engine setting (Auto/WebKit/Chromium) and surfaced it in the settings UI and configuration schema.
    • Engine selection is now preserved across restores and propagated to newly created surfaces (including dock-browser and restored panels).
  • Bug Fixes
    • Improved browser automation reliability when switching and restoring engine modes.
  • Documentation
    • Added localized help text for the new browser-engine setting.
  • Tests
    • Added coverage for engine resolution/selection, Chromium protocol behavior, and selection persistence.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

Review Change Stack

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

The PR adds selectable WebKit and Chromium browser engines, shared browser-session contracts, Chromium CDP and viewport integration, engine-aware panels and automation, persisted engine selection, settings UI, tests, localization, and configuration schema updates.

Changes

Browser engine contracts and selection

Layer / File(s) Summary
Engine types, discovery, and selection
Packages/macOS/CmuxCore/..., Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/...
Adds engine kinds and preferences, LaunchServices discovery, automatic Chromium detection, restored-engine precedence, and Chromium application selection.
Session contracts and implementations
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/...
Defines shared session state, navigation, JavaScript worlds and values, cookies, screenshots, initialization scripts, lifecycle, state streams, and WebKit/Chromium implementations.

Chromium transport and integration

Layer / File(s) Summary
Chromium process, CDP, and viewport transport
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/...
Adds Chromium launch, profile isolation, CDP request/event transport, JSON and cookie conversion, viewport rendering, and forwarded input.
Engine-aware browser panel
Sources/Panels/BrowserPanel.swift, Sources/Panels/BrowserPanel+AutomationRecovery.swift, Sources/Find/BrowserFindWebViewEvaluator.swift
Routes navigation, history, reload, stop, JavaScript, screenshots, automation probes, scripts, and lifecycle replacement through the selected engine session, with WebKit fallback where required.

Persistence and automation

Layer / File(s) Summary
Creation and restoration
Sources/Workspace.swift, Sources/Workspace+DockBrowserLookup.swift, Sources/DockSplitStore.swift, Sources/TabManager.swift, Sources/SessionPersistence.swift, Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/RecentlyClosed/*
Propagates engine selection through new surfaces, dock links, session snapshots, closed-panel restoration, and browser-panel replacement paths.
Automation API boundaries
Sources/TerminalController.swift, Sources/TerminalController+BrowserAutomationRecovery.swift, Sources/TerminalController+WindowDockBrowserRouting.swift
Adds engine fields to browser payloads, uses engine-neutral JavaScript, cookies, state, screenshots, and initialization-script helpers, and reports engine-aware errors.

Settings and validation

Layer / File(s) Summary
Browser engine setting
Packages/macOS/CmuxSettings/..., Packages/macOS/CmuxSettingsUI/..., Sources/CmuxSettingsJSONPathSupport.swift, Sources/KeyboardShortcutSettingsFileStore*.swift
Adds the persisted browser.engine setting with automatic, WebKit, and Chromium values, decoding, templates, and a SwiftUI picker.
Tests and distribution support
Packages/macOS/CmuxBrowser/Tests/..., Resources/Localizable.xcstrings, web/data/cmux.schema.json, web/messages/*, skills/cmux-settings/*, cmux.xcodeproj/project.pbxproj
Tests selection, resolution, JavaScript conversion, CDP behavior, cookie conversion, profile cleanup, Chromium session behavior, and viewport input; adds translations, schema documentation, configuration references, and Xcode registration.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs


Important

Pre-merge checks failed

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

❌ Failed checks (5 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error Production CDPConnection and ChromiumProcessController now use bounded sleep tasks for request/launch timeouts, adding timing-based synchronization in shipped runtime code. Replace the timeout sleeps with a timer/cancellation signal or async state transition owned by the actor, so request and launch deadlines are callback-driven.
Cmux Cache Substitution Correctness ❌ Error Closed-browser snapshots now persist currentURL, which the code says can lag; reopen/history later trusts it, and Chromium snapshot gating also treats nil as safe without freshness checks. Use a live read (webView.url/engine state) or a freshness-checked cache when staging/serializing browser snapshots, with a cold-cache fallback before trusting currentURL.
Cmux Swift Concurrency ❌ Error BrowserPanel.deleteProfile now fires an untracked Task to close Chromium and delete profile data, creating uncancelled lifecycle work. Make the cleanup async/awaited or store and cancel/observe the task; don’t launch profile deletion cleanup as fire-and-forget.
Cmux User-Facing Error Privacy ❌ Error Raw DevTools and JS upstream text is surfaced via localizedDescription/socket replies (chromiumJavaScriptEvaluation, remote CDP message, timeout method names). Replace raw upstream messages with generic cmux-facing errors; keep protocol details and script exceptions in logs/telemetry, not user-visible copy.
Cmux Architecture Rethink ❌ Error ChromiumProfileRuntime.acquireTarget can fail after Target.createTarget/attachToTarget without closing the created target, leaving orphan Chromium state. Make target acquisition transactional: close the newly created target on any failure/cancellation until it is committed into activeTargetIDs.
Docstring Coverage ⚠️ Warning Docstring coverage is 21.20% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (19 passed)
Check name Status Explanation
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 PASS: The new main-actor types are UI-bound by design, value models stay nonisolated Sendable, and the new transport/session ownership is actor-scoped.
Cmux Browser Automation Off-Main ✅ Passed Waitful browser.* methods stay on the socket worker with explicit v2MainSync/Task @MainActor`` hops, and policy tests cover the worker set.
Cmux Expensive Synchronous Load ✅ Passed The PR doesn’t add a new agent-history load path; the only load found is a nil-guarded cold-cache fallback using SharedLiveAgentIndex.shared ?? RestorableAgentSessionIndex.load(), which the rule...
Cmux No Hacky Sleeps ✅ Passed The PR changes only Swift, docs, and localization JSON; no TS/JS/shell/build runtime files or fixed sleeps/timers/polling were introduced.
Cmux Algorithmic Complexity ✅ Passed PASS: The new scans/sorts are over fixed-size LaunchServices/browser-descriptor lists; no nested rescans or repeated sorting on scalable workspaces/panes/users.
Cmux Swift @Concurrent ✅ Passed Changed async browser work is either @MainActor/UI-bound or actor-isolated; I found no new nonisolated async helper that should be marked @concurrent.
Cmux Swift Package Boundaries ✅ Passed Core browser-engine logic was extracted to CmuxBrowser/CmuxCore; app-target edits are UI, workspace, session, and socket glue/composition.
Cmux Swiftpm Lockfiles ✅ Passed Package.swift only adds local path deps to CmuxCore, and the pbxproj diff only adds a source file; no package-reference or external pin changes require a Package.resolved update.
Cmux Swift Logging ✅ Passed No added or changed print/debugPrint/dump/NSLog/Logger calls appear in the diff; the matched log sites are preexisting and untouched.
Cmux Full Internationalization ✅ Passed All new user-facing Swift copy uses localized APIs, the app catalog has full translations across its 20 locales, and every web locale includes the new browser.engine entry.
Cmux Swiftui State Layout ✅ Passed The new browser-engine row uses an existing @Observable DefaultsValueModel in @State, with no GeometryReader, lazy-row store refs, or render-time mutation found.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No new standalone NSWindow/NSPanel/NSWindowController/WindowGroup code or cmux.* identifier changes were introduced; the PR only touches existing browser/session logic and tests.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/config/docs/localization/test files; no logs, caches, build output, temp dirs, or other artifact-only paths were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No new debug/test-only seams appear in the touched production sources; matched markers are pre-existing helpers, not PR-introduced test hooks.
Cmux No Ambient Global State ✅ Passed The patch adds constructable, injectable types; no new file-scope mutable state or new singleton-style runtime ownership was introduced.
Title check ✅ Passed The title is concise and accurately summarizes the main change: configurable browser engine selection.
Description check ✅ Passed The description follows the template with summary, testing, demo video, review trigger, and checklist sections.
✨ 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-browser-engine-choice

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.

@vercel

vercel Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled Jul 15, 2026 6:29pm

@greptile-apps

greptile-apps Bot commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a configurable browser engine setting (Auto/WebKit/Chromium) for new browser panes, backed by a full CDP-over-WebSocket Chromium integration. It introduces an engine-neutral BrowserEngineSession protocol covering navigation, JavaScript evaluation, screenshots, cookies, and initialization scripts, with WebKit and Chromium implementations. Previously reported issues — JS error text preservation, resolvedBrowserContentProcessIdentifier dispatch, and WebKit async JS evaluation — are resolved in this HEAD commit.

  • Engine-neutral automation layer: TerminalController socket commands now route through v2RunEngineJavaScript/browserPanel.evaluateJavaScript and engine-agnostic cookie/screenshot paths, eliminating WKWebView-specific code from most automation handlers.
  • Chromium CDP integration: ChromiumBrowserEngineSession, CDPConnection, ChromiumProcessController, ChromiumProfileRuntime, and the screencast viewport form the new Chromium stack; session persistence, recently-closed restore, and topology payloads all propagate engineKind.
  • Settings and localization: browser.engine preference key is wired through CmuxSettings/CmuxSettingsUI, schema description is added to all 20 web locale catalogs, and 14 new Swift string-catalog keys are populated across all 20 app locales.

Confidence Score: 4/5

Safe to merge with one open item: CDPConnection introduces an inline ContinuousClock().sleep timeout that the repository policy requires to be a shared, testable abstraction.

The core engine-neutral abstraction, CDP integration, session persistence, and localization are all well-executed. CDPConnection.swift introduces the same inline Task.sleep timeout pattern that ChromiumProcessController already has open — the cmux policy asks for a shared, test-covered timeout utility. That is the only structural concern remaining.

CDPConnection.swift (timing timeout pattern) and TerminalController.swift (dead helper methods).

Important Files Changed

Filename Overview
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/CDPConnection.swift New CDP WebSocket actor; well-structured but uses inline ContinuousClock().sleep for request timeouts instead of a shared cancellation-aware timeout abstraction with tests.
Sources/TerminalController.swift Engine-neutral JS evaluation, screenshot, cookie, and navigation paths are correctly wired; v2WebKitView and v2WebKitOnlyError helpers are added but never called.
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift Full Chromium CDP session implementation; JS error text preserved via chromiumJavaScriptEvaluation; creates a new isolated world per isolated-world evaluation call.
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProcessController.swift Process lifecycle actor; real-signal path (stderr DevTools URL) is correct; the inline ContinuousClock().sleep fallback was previously flagged and remains unabstracted.
Sources/Panels/BrowserPanel.swift Engine session lifecycle, viewport visibility sync, profile/remote-workspace downgrade path, and automation recovery integration look correct.
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineSessionError.swift JS exception text preserved via chromiumJavaScriptEvaluation case; chromiumProtocol and chromiumLaunch cases redact internal details correctly.
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineResolver.swift Clean LaunchServices-based engine resolution; hardcoded prefix list plus BrowserImportBrowserDescriptor lookup for Chromium family detection.
Sources/Panels/BrowserEngineSelection+Current.swift Production @mainactor wrapper that reads settings and resolves the current engine selection via LaunchServices; clean and correctly isolated.
Sources/SessionPersistence.swift Adds optional engineKind field to SessionBrowserPanelSnapshot with decodeIfPresent — backward-compatible with sessions saved before this change.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant TC as TerminalController (socket worker)
    participant BP as BrowserPanel (MainActor)
    participant WK as WebKitBrowserEngineSession
    participant CH as ChromiumBrowserEngineSession
    participant CDP as CDPConnection (actor)
    participant CR as Chromium process

    TC->>BP: v2RunEngineJavaScript(browserPanel, script, world)
    BP->>BP: "Task @MainActor evaluateJavaScript"
    alt WebKit engine
        BP->>WK: evaluateJavaScript
        WK->>WK: callAsyncJavaScript awaits Promise
        WK-->>BP: BrowserJavaScriptValue
    else Chromium engine
        BP->>CH: evaluateJavaScript
        CH->>CDP: send Runtime.evaluate awaitPromise true
        CDP->>CR: WebSocket CDP message
        CR-->>CDP: CDP response
        CDP-->>CH: CDPJSONValue result
        CH-->>BP: BrowserJavaScriptValue
    end
    BP-->>TC: finish callback
    TC-->>TC: v2AwaitCallback resolves
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant TC as TerminalController (socket worker)
    participant BP as BrowserPanel (MainActor)
    participant WK as WebKitBrowserEngineSession
    participant CH as ChromiumBrowserEngineSession
    participant CDP as CDPConnection (actor)
    participant CR as Chromium process

    TC->>BP: v2RunEngineJavaScript(browserPanel, script, world)
    BP->>BP: "Task @MainActor evaluateJavaScript"
    alt WebKit engine
        BP->>WK: evaluateJavaScript
        WK->>WK: callAsyncJavaScript awaits Promise
        WK-->>BP: BrowserJavaScriptValue
    else Chromium engine
        BP->>CH: evaluateJavaScript
        CH->>CDP: send Runtime.evaluate awaitPromise true
        CDP->>CR: WebSocket CDP message
        CR-->>CDP: CDP response
        CDP-->>CH: CDPJSONValue result
        CH-->>BP: BrowserJavaScriptValue
    end
    BP-->>TC: finish callback
    TC-->>TC: v2AwaitCallback resolves
Loading

Reviews (11): Last reviewed commit: "Preserve Chromium JavaScript exception t..." | Re-trigger Greptile

Comment on lines 6195 to +6201
surfaceId: UUID,
timeout: TimeInterval = 3.0
) -> Bool {
let engineKind = v2MainSync { browserPanel.engineKind }
if engineKind == .chromium {
return v2MainSync { ObjectIdentifier(browserPanel.webView) == ObjectIdentifier(webView) }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Chromium pane skips page-readiness check before JS evaluation

For Chromium panes v2EnsureBrowserDocumentLoaded returns as soon as the viewport WKWebView object identity matches — it never probes the actual Chromium page's document.readyState. The WebKit path uses this gate to prevent script execution against an uninteractive page (blank/provisional navigation), but Chromium gets no equivalent guard. Automation commands like browser.eval or browser.get.text that arrive immediately after a browser.navigate will succeed (because CDP Runtime.evaluate works in any load state) but may observe partially-constructed DOM, missing scripts, or stale content — a correctness difference a user cannot distinguish from a timing error. Consider awaiting Page.loadEventFired or Page.frameStoppedLoading in the Chromium path, or at least checking document.readyState via a CDP Runtime.evaluate before returning true.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
Sources/TerminalController.swift (1)

3129-3149: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Do not report the viewport transport PID as Chromium’s content PID.

For Chromium, browserPanel.webView is only the canvas transport, so browser_web_content_pid identifies the wrong process. Return the actual Chromium content PID, or null until one is available.

🤖 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/TerminalController.swift` around lines 3129 - 3149, Update the
browser metadata construction around webContentPID and browser_web_content_pid
so Chromium does not use CmuxWebContentProcessIdentifier.pid(for:
browserPanel.webView), which is only the viewport transport process. Resolve and
report the actual Chromium content PID, returning null when unavailable, while
preserving the existing PID behavior for non-Chromium engines and keeping the
nested webviews metadata consistent.
Sources/Workspace.swift (1)

7889-7938: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use browser.engine when no engine was explicitly requested.

Falling back to the selected sibling’s engine means changing the setting has no effect when creating a new tab or split beside an existing browser. Only restoration, duplication, or link-opening callers should pass an explicit engine.

Proposed fix
-        let inheritedEngineKind = browserEngineKind ?? (panels[panelId] as? BrowserPanel)?.engineKind
+        let inheritedEngineKind = browserEngineKind
-        let inheritedEngineKind = browserEngineKind ?? sourcePanelId.flatMap {
-            (panels[$0] as? BrowserPanel)?.engineKind
-        }
+        let inheritedEngineKind = browserEngineKind

As per path instructions, engine choice and routing must come from a single authoritative source.

Also applies to: 8007-8052

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/Workspace.swift` around lines 7889 - 7938, Update the browser panel
creation flow around inheritedEngineKind and the BrowserPanel initializer to use
the current browser.engine setting when no browserEngineKind is explicitly
supplied, rather than deriving the engine from the source panel. Preserve
explicit engine values for restoration, duplication, and link-opening callers,
and apply the same change to the corresponding creation path near the other
referenced call site.

Source: Path instructions

Sources/Panels/BrowserPanel+AutomationRecovery.swift (1)

42-100: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Give these callback bridges a cancellation handle.
Task { @mainactor ... } is still fire-and-forget here, so a timeout or teardown can leave JS, screenshot, or init-script work running after the socket reply has already failed. Store the task and cancel it when socketAwaitCallback returns nil, or make the async operation itself own the lifecycle:

  • Sources/Panels/BrowserPanel+AutomationRecovery.swift#L42-L100
  • Sources/TerminalController.swift#L5957-L5977
  • Sources/TerminalController.swift#L6013-L6034
  • Sources/Panels/BrowserPanel.swift#L7252-L7265
  • Sources/Panels/BrowserPanel.swift#L11590-L11594
🤖 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/Panels/BrowserPanel`+AutomationRecovery.swift around lines 42 - 100,
Give every fire-and-forget callback bridge a cancellation handle so timed-out or
failed socket replies stop in-flight async work. Update the probe Tasks in
Sources/Panels/BrowserPanel+AutomationRecovery.swift:42-100 and the
corresponding callback bridges in Sources/TerminalController.swift:5952-5976,
Sources/TerminalController.swift:6012-6034,
Sources/Panels/BrowserPanel.swift:7252-7265, and
Sources/Panels/BrowserPanel.swift:11590-11594 to retain and cancel their Task
when socketAwaitCallback returns nil, or move lifecycle ownership into the async
operation; preserve the existing JavaScript, screenshot, and init-script
behavior otherwise.

Source: Coding guidelines

🤖 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
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserApplicationProviding.swift`:
- Around line 2-9: Make the LaunchServices methods defaultBrowserApplications()
and installedChromiumApplications() asynchronous, and update
BrowserApplicationProviding isolation/conformance as needed so implementations
can execute queries off the main actor. Propagate async changes through all
conforming implementations and callers, including browser-pane creation, while
preserving the existing returned application results.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserJavaScriptValue.swift`:
- Around line 53-54: Remove the unnecessary `@MainActor` isolation from the
foundationValue computed property in BrowserJavaScriptValue, leaving it
nonisolated because it only performs value conversion and does not access
main-actor state.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/CDPConnection.swift`:
- Around line 78-121: Update receiveMessages and handleMessage so malformed
message decoding is caught and logged per message, then skipped while the
receive loop continues; reserve the existing connection teardown path for
webSocketTask.receive failures. Also reuse shared JSONDecoder and JSONEncoder
instances across send and handleMessage instead of allocating them for each
message.
- Around line 34-59: Add a bounded timeout to the CDPConnection.send method so
every request fails when Chromium does not respond, rather than leaving its
continuation and pendingRequests entry indefinitely. Race the existing
webSocketTask.send/request continuation against a timeout, remove the request
from pendingRequests, and resume it with an appropriate Chromium protocol error;
preserve normal replies and send failures.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift`:
- Around line 336-337: Update the frame delivery code around
ChromiumViewportDocumentJSONLiteral().encode and window.cmuxChromiumFrame so it
passes the base64 data as a bridged JavaScript argument instead of interpolating
it into a newly built script string. Keep the viewport script fixed and prepend
the data-URI prefix inside that script, avoiding full-frame escaping and
intermediate string construction on the MainActor.
- Around line 257-269: Update the startupTask catch path around connect(to:) to
invoke the existing teardown flow before presentLaunchFailure(). Ensure the
teardown cancels eventTask, clears connection and cdpSessionID, closes the CDP
connection, and stops processController, covering failures after Chromium
launches or partial session state is assigned.
- Line 194: Remove the "grantUniveralAccess": .bool(true) entry from the
parameters used by Page.createIsolatedWorld in ChromiumBrowserEngineSession,
leaving the option unset so the API default of false applies.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProcessController.swift`:
- Around line 45-58: Update the continuation-based launch flow around endpoint
resolution to use withTaskCancellationHandler, ensuring cancellation immediately
terminates the Chromium process and resumes or fails the pending continuation.
Coordinate this with endpointContinuation, timeoutTask, and stderrTask so
cancellation cannot leave the caller waiting or background tasks/processes
running.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumViewportDocument.swift`:
- Around line 80-92: Update the viewport event handlers in
ChromiumViewportDocument so mousemove derives the reported button from the
event.buttons bitmask, keydown treats a single Unicode grapheme such as an emoji
as text while excluding named keys, and the canvas suppresses the native
contextmenu event while preserving proxying to Chromium.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift`:
- Around line 106-112: Update the screenshot method in
WebKitBrowserEngineSession to extract the underlying CGImage, then perform
NSBitmapImageRep PNG encoding inside a Task.detached block so the `@MainActor`
remains responsive. Preserve the existing emptyScreenshot error behavior when
image extraction or encoding fails, and return the detached task’s encoded PNG
result.

In `@Resources/Localizable.xcstrings`:
- Around line 238050-238052: Update the affected localized string values in
Resources/Localizable.xcstrings for the es, fr, pl, th, and tr locales to
preserve “Chromium” as the product name, replacing translations that render it
as “Chrome” or the chemical element while leaving unrelated localization text
unchanged.

In `@Sources/KeyboardShortcutSettingsFileStore.swift`:
- Around line 903-909: Update the browser-section parsing flow around
BrowserEnginePreference and logInvalid so an invalid browser.engine value is
logged without returning from the enclosing parser. Skip only the invalid engine
assignment, then continue processing subsequent browser settings such as search
engine and theme.

In `@Sources/Panels/BrowserPanel.swift`:
- Around line 4705-4718: Update the Chromium replacement flows around
replaceWebViewPreservingState, including the paths at the referenced
workspace/profile transitions, to capture engineSession.state.url ?? currentURL
before closing the old session and pass that URL explicitly into restoration.
Ensure restoreURL no longer relies on oldWebView.url for Chromium transport
views, while preserving existing restoration behavior for other engines.

In `@Sources/TerminalController.swift`:
- Around line 5979-5999: Remove the Chromium rejection paths in the
browser.cookies.* and browser.state.* handlers that rely on v2WebKitOnlyError.
Route Chromium operations through the existing CDP cookie and storage APIs,
while retaining WebKit implementations, so both engines expose equivalent
cookie/state automation behavior.

---

Outside diff comments:
In `@Sources/Panels/BrowserPanel`+AutomationRecovery.swift:
- Around line 42-100: Give every fire-and-forget callback bridge a cancellation
handle so timed-out or failed socket replies stop in-flight async work. Update
the probe Tasks in Sources/Panels/BrowserPanel+AutomationRecovery.swift:42-100
and the corresponding callback bridges in
Sources/TerminalController.swift:5952-5976,
Sources/TerminalController.swift:6012-6034,
Sources/Panels/BrowserPanel.swift:7252-7265, and
Sources/Panels/BrowserPanel.swift:11590-11594 to retain and cancel their Task
when socketAwaitCallback returns nil, or move lifecycle ownership into the async
operation; preserve the existing JavaScript, screenshot, and init-script
behavior otherwise.

In `@Sources/TerminalController.swift`:
- Around line 3129-3149: Update the browser metadata construction around
webContentPID and browser_web_content_pid so Chromium does not use
CmuxWebContentProcessIdentifier.pid(for: browserPanel.webView), which is only
the viewport transport process. Resolve and report the actual Chromium content
PID, returning null when unavailable, while preserving the existing PID behavior
for non-Chromium engines and keeping the nested webviews metadata consistent.

In `@Sources/Workspace.swift`:
- Around line 7889-7938: Update the browser panel creation flow around
inheritedEngineKind and the BrowserPanel initializer to use the current
browser.engine setting when no browserEngineKind is explicitly supplied, rather
than deriving the engine from the source panel. Preserve explicit engine values
for restoration, duplication, and link-opening callers, and apply the same
change to the corresponding creation path near the other referenced call site.
🪄 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: d9d64e56-9f48-4cd9-8d7d-012a21b2eb1a

📥 Commits

Reviewing files that changed from the base of the PR and between d3dbd21 and 29423c6.

📒 Files selected for processing (76)
  • Packages/macOS/CmuxBrowser/Package.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserApplication.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserApplicationProviding.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineResolver.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineSelection.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineSelectionService.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineSessionError.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineState.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserJavaScriptValue.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserJavaScriptWorld.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/BrowserChromiumProfileDirectory.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/CDPConnection.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/CDPEvent.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/CDPJSONValue.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession+Viewport.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProcessController.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumViewportDocument.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumViewportDocumentJSONLiteral.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumViewportMessageHandler.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/LaunchServicesBrowserApplicationProvider.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/RecentlyClosed/ClosedBrowserPanelRestoreSnapshot.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/BrowserApplicationProviderFake.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/BrowserEngineResolverTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/BrowserEngineSelectionServiceTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/BrowserJavaScriptValueTests.swift
  • Packages/macOS/CmuxCore/Sources/CmuxCore/Browser/BrowserEngineKind.swift
  • Packages/macOS/CmuxCore/Sources/CmuxCore/Browser/BrowserEnginePreference.swift
  • Packages/macOS/CmuxSettings/Package.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Codable/BrowserEnginePreference+SettingCodable.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/BrowserCatalogSection.swift
  • Packages/macOS/CmuxSettingsUI/Package.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/BrowserEngineSettingRow.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/BrowserSection.swift
  • Resources/Localizable.xcstrings
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/DockSplitStore.swift
  • Sources/Find/BrowserFindWebViewEvaluator.swift
  • Sources/KeyboardShortcutSettingsFileStore+Template.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/Panels/BrowserEngineSelection+Current.swift
  • Sources/Panels/BrowserPanel+AutomationRecovery.swift
  • Sources/Panels/BrowserPanel.swift
  • Sources/SessionPersistence.swift
  • Sources/TabManager.swift
  • Sources/TerminalController+BrowserAutomationRecovery.swift
  • Sources/TerminalController+WindowDockBrowserRouting.swift
  • Sources/TerminalController.swift
  • Sources/Workspace+DockBrowserLookup.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • skills/cmux-settings/SKILL.md
  • skills/cmux-settings/references/all-keys.md
  • web/data/cmux.schema.json
  • 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

Comment on lines +2 to +9
@MainActor
public protocol BrowserApplicationProviding: AnyObject {
/// Returns the applications LaunchServices selects for representative HTTPS and HTTP URLs.
func defaultBrowserApplications() -> [BrowserApplication]

/// Returns installed Chromium-family applications that cmux knows how to launch.
func installedChromiumApplications() -> [BrowserApplication]
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Make LaunchServices queries asynchronous to avoid blocking the main thread.

LaunchServices queries (such as resolving default browsers or installed applications) involve IPC and can occasionally hang or block. As per coding guidelines, do not add expensive synchronous syscalls to the main actor or latency-sensitive interactive paths.

Consider making these requirements async (and the protocol Sendable/nonisolated) so that implementations can perform the queries on a background actor, preventing potential UI freezes when creating a new browser pane.

♻️ Proposed refactor
-@MainActor
-public protocol BrowserApplicationProviding: AnyObject {
+public protocol BrowserApplicationProviding: AnyObject, Sendable {
     /// Returns the applications LaunchServices selects for representative HTTPS and HTTP URLs.
-    func defaultBrowserApplications() -> [BrowserApplication]
+    func defaultBrowserApplications() async -> [BrowserApplication]
 
     /// Returns installed Chromium-family applications that cmux knows how to launch.
-    func installedChromiumApplications() -> [BrowserApplication]
+    func installedChromiumApplications() async -> [BrowserApplication]
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@MainActor
public protocol BrowserApplicationProviding: AnyObject {
/// Returns the applications LaunchServices selects for representative HTTPS and HTTP URLs.
func defaultBrowserApplications() -> [BrowserApplication]
/// Returns installed Chromium-family applications that cmux knows how to launch.
func installedChromiumApplications() -> [BrowserApplication]
}
public protocol BrowserApplicationProviding: AnyObject, Sendable {
/// Returns the applications LaunchServices selects for representative HTTPS and HTTP URLs.
func defaultBrowserApplications() async -> [BrowserApplication]
/// Returns installed Chromium-family applications that cmux knows how to launch.
func installedChromiumApplications() async -> [BrowserApplication]
}
🤖 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
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserApplicationProviding.swift`
around lines 2 - 9, Make the LaunchServices methods defaultBrowserApplications()
and installedChromiumApplications() asynchronous, and update
BrowserApplicationProviding isolation/conformance as needed so implementations
can execute queries off the main actor. Propagate async changes through all
conforming implementations and callers, including browser-pane creation, while
preserving the existing returned application results.

Source: Coding guidelines

Comment on lines +106 to +112
guard let tiff = image.tiffRepresentation,
let bitmap = NSBitmapImageRep(data: tiff),
let png = bitmap.representation(using: NSBitmapImageRep.FileType.png, properties: [:]) else {
throw BrowserEngineSessionError.emptyScreenshot
}
return png
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Hop off the main actor for CPU-heavy image encoding.

Generating the PNG representation via NSBitmapImageRep is a CPU-heavy operation. Because WebKitBrowserEngineSession is @MainActor-isolated, performing this synchronously will block the main thread and cause UI stuttering, especially for large viewports.

As per coding guidelines, expensive parsing and CPU-heavy loads should be explicitly hopped off UI isolation. Consider moving the encoding work to a Task.detached block by extracting the underlying CGImage.

🛠 Proposed fix
-        guard let tiff = image.tiffRepresentation,
-              let bitmap = NSBitmapImageRep(data: tiff),
-              let png = bitmap.representation(using: NSBitmapImageRep.FileType.png, properties: [:]) else {
-            throw BrowserEngineSessionError.emptyScreenshot
-        }
-        return png
+        guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
+            throw BrowserEngineSessionError.emptyScreenshot
+        }
+        
+        return try await Task.detached {
+            let bitmap = NSBitmapImageRep(cgImage: cgImage)
+            guard let png = bitmap.representation(using: .png, properties: [:]) else {
+                throw BrowserEngineSessionError.emptyScreenshot
+            }
+            return png
+        }.value
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
guard let tiff = image.tiffRepresentation,
let bitmap = NSBitmapImageRep(data: tiff),
let png = bitmap.representation(using: NSBitmapImageRep.FileType.png, properties: [:]) else {
throw BrowserEngineSessionError.emptyScreenshot
}
return png
}
guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
throw BrowserEngineSessionError.emptyScreenshot
}
return try await Task.detached {
let bitmap = NSBitmapImageRep(cgImage: cgImage)
guard let png = bitmap.representation(using: .png, properties: [:]) else {
throw BrowserEngineSessionError.emptyScreenshot
}
return png
}.value
🤖 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
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift`
around lines 106 - 112, Update the screenshot method in
WebKitBrowserEngineSession to extract the underlying CGImage, then perform
NSBitmapImageRep PNG encoding inside a Task.detached block so the `@MainActor`
remains responsive. Preserve the existing emptyScreenshot error behavior when
image extraction or encoding fails, and return the detached task’s encoded PNG
result.

Source: Coding guidelines

Comment thread Resources/Localizable.xcstrings Outdated
Comment on lines +903 to +909
if let raw = jsonString(section["engine"]) {
guard let preference = BrowserEnginePreference(rawValue: raw) else {
logInvalid("browser.engine", sourcePath: sourcePath)
return
}
snapshot.managedUserDefaults[SettingCatalog().browser.engine.userDefaultsKey] = .string(preference.rawValue)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not abort parsing the entire browser section for an invalid engine.

The return skips valid settings that follow browser.engine—including search engine, theme, and other browser options. Log the invalid engine and continue parsing the remaining fields.

Proposed fix
 if let raw = jsonString(section["engine"]) {
-    guard let preference = BrowserEnginePreference(rawValue: raw) else {
+    if let preference = BrowserEnginePreference(rawValue: raw) {
+        snapshot.managedUserDefaults[SettingCatalog().browser.engine.userDefaultsKey] = .string(preference.rawValue)
+    } else {
         logInvalid("browser.engine", sourcePath: sourcePath)
-        return
     }
-    snapshot.managedUserDefaults[SettingCatalog().browser.engine.userDefaultsKey] = .string(preference.rawValue)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if let raw = jsonString(section["engine"]) {
guard let preference = BrowserEnginePreference(rawValue: raw) else {
logInvalid("browser.engine", sourcePath: sourcePath)
return
}
snapshot.managedUserDefaults[SettingCatalog().browser.engine.userDefaultsKey] = .string(preference.rawValue)
}
if let raw = jsonString(section["engine"]) {
if let preference = BrowserEnginePreference(rawValue: raw) {
snapshot.managedUserDefaults[SettingCatalog().browser.engine.userDefaultsKey] = .string(preference.rawValue)
} else {
logInvalid("browser.engine", sourcePath: sourcePath)
}
}
🤖 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/KeyboardShortcutSettingsFileStore.swift` around lines 903 - 909,
Update the browser-section parsing flow around BrowserEnginePreference and
logInvalid so an invalid browser.engine value is logged without returning from
the enclosing parser. Skip only the invalid engine assignment, then continue
processing subsequent browser settings such as search engine and theme.

Comment thread Sources/Panels/BrowserPanel.swift
Comment thread Sources/TerminalController.swift
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

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

🤖 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
`@Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumViewportInputQueueTests.swift`:
- Around line 44-67: Update ChromiumViewportInputQueue.enqueue(_:) or the
saturatedOrderedInputKeepsTheNewestCompleteKeyGesture test so they share the
same contract: a full queue containing only non-coalescible key commands must
either evict the oldest ordered command and retain the complete NewestKey
gesture, or the test must assert that the new gesture is dropped. Preserve the
existing maximum queue count and complete key-pair expectations.
🪄 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: 373cb3b7-41f0-46cd-a3ad-8ce5952addcd

📥 Commits

Reviewing files that changed from the base of the PR and between 799dcfc and 2c2700d.

📒 Files selected for processing (1)
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumViewportInputQueueTests.swift

@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@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
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift`:
- Around line 532-546: Update failViewportInput() and its callers in the
viewport input flow so it is used only for genuine I/O failures, not transient
local backpressure. Preserve the session connection and recovery path for local
queue saturation, while retaining the existing shutdown behavior for actual
connection failures. Ensure viewportInputFailed is not permanently set for
recoverable conditions.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession`+Viewport.swift:
- Around line 236-242: Update enqueueViewportInput and the related
viewport-input draining call site so queue backpressure is handled without
invoking the session-ending failViewportInput(). Reserve failViewportInput() for
actual I/O failures, while preserving the existing enqueue and draining behavior
for successfully accepted commands.
🪄 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: de75b4b9-096a-4657-8349-302240ba0c30

📥 Commits

Reviewing files that changed from the base of the PR and between 2c2700d and a3efcdb.

📒 Files selected for processing (13)
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineCookie.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/BrowserChromiumProfileDirectory.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/CDPConnection.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserCookieCodec.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession+Viewport.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumBrowserCookieCodecTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumViewportInputQueueTests.swift
  • Resources/Localizable.xcstrings
  • Sources/Panels/BrowserPanel.swift
  • Sources/TerminalController.swift

Comment thread Sources/TerminalController.swift
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
Sources/Panels/BrowserPanel.swift (1)

428-439: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Stale Chromium runtime stays cached after clearing profile data.

clearProfileData reads chromiumRuntimes[id] but never removes it from the cache before closing the runtime and deleting its directory. Every later chromiumRuntime(for: id) lookup (new panel init, switchToProfile, reloadChromium) returns the same now-closed instance instead of a fresh one, breaking Chromium browsing for that profile until app restart.

🐛 Proposed fix
     func clearProfileData(id: UUID) async -> BrowserProfileClearOutcome? {
         guard repository.profileDefinition(id: id) != nil else { return nil }
-        let runtime = chromiumRuntimes[id]
+        let runtime = chromiumRuntimes.removeValue(forKey: id)
         if let runtime {
             await runtime.close()
         }
         let directory = chromiumProfileDirectory.url(profileID: id)
         await fileRemover.removeItemIfExists(at: directory)
         let result = await repository.clearProfileData(id: id)
         mirrorPublishedState()
         return result
     }
🤖 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/Panels/BrowserPanel.swift` around lines 428 - 439, Update
clearProfileData(id:) to remove the profile’s entry from chromiumRuntimes before
closing the runtime and deleting its directory. Ensure subsequent
chromiumRuntime(for:), switchToProfile, and reloadChromium lookups create a
fresh runtime while preserving the existing cleanup and repository-clearing
flow.
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift (1)

149-161: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Own and serialize browser operations instead of spawning fire-and-forget tasks.

These tasks survive close() and can execute after newer actions. For example, a delayed Page.stopLoading can stop a subsequent navigation, while an older failure task can overwrite newer viewport state.

Route navigation/control operations through stored, cancellable tasks or one serialized action owner, and cancel them during teardown or replacement.

As per coding guidelines, “Do not create fire-and-forget Task { ... } work with meaningful lifecycle unless it is stored, cancellable, or tied to a caller-owned operation.”

Also applies to: 177-180, 685-719, 807-815

🤖 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
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift`
around lines 149 - 161, Replace the unowned fire-and-forget Task operations in
the navigation and related control paths, including Page.navigate, the
operations around lines 177-180, and the flows in the viewport/state methods
around 685-719 and 807-815, with stored cancellable tasks or a single serialized
action owner. Ensure each task is cancelled when replaced and during session
teardown in close(), preventing stale operations and failures from affecting
newer browser actions.

Source: Coding guidelines

♻️ Duplicate comments (3)
Sources/KeyboardShortcutSettingsFileStore.swift (1)

909-915: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not abort parsing the entire browser section for an invalid engine.

The return statement skips valid settings that follow browser.engine—including search engine, theme, and other browser options. Log the invalid engine and continue parsing the remaining fields.

🐛 Proposed fix
         if let raw = jsonString(section["engine"]) {
-            guard let preference = BrowserEnginePreference(rawValue: raw) else {
+            if let preference = BrowserEnginePreference(rawValue: raw) {
+                snapshot.managedUserDefaults[SettingCatalog().browser.engine.userDefaultsKey] = .string(preference.rawValue)
+            } else {
                 logInvalid("browser.engine", sourcePath: sourcePath)
-                return
             }
-            snapshot.managedUserDefaults[SettingCatalog().browser.engine.userDefaultsKey] = .string(preference.rawValue)
         }
🤖 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/KeyboardShortcutSettingsFileStore.swift` around lines 909 - 915, In
the browser engine parsing guard block, remove the return statement that follows
the logInvalid call for an invalid BrowserEnginePreference. Keep the logInvalid
logging in place to record the invalid engine value, but allow execution to
continue past this block so that subsequent browser settings (search engine,
theme, and other options) are still parsed from the section.
Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift (1)

171-177: ⚠️ Potential issue | 🟠 Major

Hop off the main actor for CPU-heavy image encoding.

Generating the PNG representation via NSBitmapImageRep is a CPU-heavy operation. Because WebKitBrowserEngineSession is @MainActor-isolated, performing this synchronously will block the main thread and cause UI stuttering, especially for large viewports.

As per coding guidelines, explicitly hop CPU-heavy, file-I/O-heavy, parsing-heavy, or network-heavy async helpers called from UI isolation away from the main actor. Consider moving the encoding work to a Task.detached block by extracting the underlying CGImage.

🛠 Proposed fix
-        guard let tiff = image.tiffRepresentation,
-              let bitmap = NSBitmapImageRep(data: tiff),
-              let png = bitmap.representation(using: NSBitmapImageRep.FileType.png, properties: [:]) else {
-            throw BrowserEngineSessionError.emptyScreenshot
-        }
-        return png
+        guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
+            throw BrowserEngineSessionError.emptyScreenshot
+        }
+        
+        return try await Task.detached {
+            let bitmap = NSBitmapImageRep(cgImage: cgImage)
+            guard let png = bitmap.representation(using: .png, properties: [:]) else {
+                throw BrowserEngineSessionError.emptyScreenshot
+            }
+            return png
+        }.value
🤖 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
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift`
around lines 171 - 177, Move the PNG encoding work out of the main actor in the
screenshot method by extracting the underlying CGImage and performing
NSBitmapImageRep creation and PNG representation inside a Task.detached
operation. Preserve the existing BrowserEngineSessionError.emptyScreenshot
failure behavior and return the encoded PNG data after awaiting the detached
task.

Source: Coding guidelines

Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProcessController.swift (1)

63-76: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle task cancellation to prevent hanging and leaking the process.

If the calling task is cancelled, withCheckedThrowingContinuation does not automatically resume or propagate cancellation to unstructured tasks. The caller will hang until the 10-second timeoutTask completes, and the Chromium process will remain running during that time.

Wrap the continuation in withTaskCancellationHandler to immediately terminate the process and resume the continuation upon cancellation.

🛠 Proposed fix
-        return try await withCheckedThrowingContinuation { continuation in
-            endpointContinuation = continuation
-            stderrTask = Task { [weak self] in
-                await self?.consumeStandardError(stderrPipe.fileHandleForReading)
-            }
-            timeoutTask = Task { [weak self, launchTimeout] in
-                // A bounded launch deadline is intentional behavior; never leave a pane waiting forever for DevTools.
-                try? await ContinuousClock().sleep(for: launchTimeout)
-                guard !Task.isCancelled else { return }
-                await self?.failUnresolvedEndpoint(
-                    BrowserEngineSessionError.chromiumLaunch("Chromium timed out before opening its DevTools endpoint.")
-                )
-            }
+        return try await withTaskCancellationHandler {
+            try await withCheckedThrowingContinuation { continuation in
+                endpointContinuation = continuation
+                stderrTask = Task { [weak self] in
+                    await self?.consumeStandardError(stderrPipe.fileHandleForReading)
+                }
+                timeoutTask = Task { [weak self, launchTimeout] in
+                    // A bounded launch deadline is intentional behavior; never leave a pane waiting forever for DevTools.
+                    try? await ContinuousClock().sleep(for: launchTimeout)
+                    guard !Task.isCancelled else { return }
+                    await self?.failUnresolvedEndpoint(
+                        BrowserEngineSessionError.chromiumLaunch("Chromium timed out before opening its DevTools endpoint.")
+                    )
+                }
+            }
+        } onCancel: {
+            Task { await self.close() }
         }
🤖 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
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProcessController.swift`
around lines 63 - 76, Update the continuation flow around the Chromium endpoint
wait to use withTaskCancellationHandler, so cancellation immediately terminates
the Chromium process, cancels the stderr and timeout tasks, and resumes the
pending continuation with cancellation rather than waiting for launchTimeout.
Keep the existing endpoint success and timeout behavior unchanged for
non-cancelled launches, using the surrounding process-controller cleanup symbols
such as failUnresolvedEndpoint and the stored continuation.
🤖 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
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/CDPConnection.swift`:
- Around line 90-95: Update CDPConnection.events so Page.screencastFrame traffic
cannot evict control events such as Fetch.requestPaused or
Target.attachedToTarget. Replace the indiscriminate bufferingNewest policy with
separate delivery paths or equivalent classification that preserves control
events losslessly while coalescing only replaceable screencast frames.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProfileRuntime.swift`:
- Around line 29-88: Update acquireTarget so ownership of the
Target.createTarget result transfers to the runtime immediately after creation
and remains tracked until the target is successfully inserted into
activeTargetIDs. Ensure every subsequent failure, including attach errors and
cancellation after creation, closes the created target before propagating the
error; only relinquish cleanup responsibility once the lease is committed
successfully.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift`:
- Around line 90-97: Update the JavaScript wrapper in the async evaluation
method around functionBody and callAsyncJavaScript: pass the original script as
an argument and execute it through eval() within the async function, then await
its result. Remove the parenthesized interpolation so scripts containing
trailing semicolons or multiple statements remain valid while preserving
implicit return behavior and promise awaiting.

In
`@Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/CDPConnectionTests.swift`:
- Around line 103-114: Update deliverAndWaitUntilConsumed to distinguish
immediate delivery from buffered delivery: when receiveContinuation is absent
and data is appended to bufferedData, wait for the subsequent receive/process
completion signal rather than receiveCount + 1, ensuring handleMessage has
broadcast the payload before the test continues. Preserve the existing
continuation-resume path for an actively waiting receiver.

In `@Sources/Panels/BrowserPanel.swift`:
- Around line 460-480: The cleanup started by removeChromiumRuntimeAndData must
no longer run in an untracked fire-and-forget Task. Make this operation
asynchronous and await runtime.close() and fileRemover.removeItemIfExists(at:)
from the caller, updating deleteProfile and any other callers to propagate
completion and errors through the existing lifecycle flow.

---

Outside diff comments:
In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift`:
- Around line 149-161: Replace the unowned fire-and-forget Task operations in
the navigation and related control paths, including Page.navigate, the
operations around lines 177-180, and the flows in the viewport/state methods
around 685-719 and 807-815, with stored cancellable tasks or a single serialized
action owner. Ensure each task is cancelled when replaced and during session
teardown in close(), preventing stale operations and failures from affecting
newer browser actions.

In `@Sources/Panels/BrowserPanel.swift`:
- Around line 428-439: Update clearProfileData(id:) to remove the profile’s
entry from chromiumRuntimes before closing the runtime and deleting its
directory. Ensure subsequent chromiumRuntime(for:), switchToProfile, and
reloadChromium lookups create a fresh runtime while preserving the existing
cleanup and repository-clearing flow.

---

Duplicate comments:
In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProcessController.swift`:
- Around line 63-76: Update the continuation flow around the Chromium endpoint
wait to use withTaskCancellationHandler, so cancellation immediately terminates
the Chromium process, cancels the stderr and timeout tasks, and resumes the
pending continuation with cancellation rather than waiting for launchTimeout.
Keep the existing endpoint success and timeout behavior unchanged for
non-cancelled launches, using the surrounding process-controller cleanup symbols
such as failUnresolvedEndpoint and the stored continuation.

In
`@Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift`:
- Around line 171-177: Move the PNG encoding work out of the main actor in the
screenshot method by extracting the underlying CGImage and performing
NSBitmapImageRep creation and PNG representation inside a Task.detached
operation. Preserve the existing BrowserEngineSessionError.emptyScreenshot
failure behavior and return the encoded PNG data after awaiting the detached
task.

In `@Sources/KeyboardShortcutSettingsFileStore.swift`:
- Around line 909-915: In the browser engine parsing guard block, remove the
return statement that follows the logInvalid call for an invalid
BrowserEnginePreference. Keep the logInvalid logging in place to record the
invalid engine value, but allow execution to continue past this block so that
subsequent browser settings (search engine, theme, and other options) are still
parsed from the section.
🪄 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: 739347d6-a641-48ce-a969-2dbcdc193335

📥 Commits

Reviewing files that changed from the base of the PR and between a3efcdb and e4ad3a9.

📒 Files selected for processing (58)
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineNavigationDecision.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineNavigationDisposition.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineNavigationPolicyHandler.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineNavigationRequest.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineResolver.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/BrowserEngineSessionError.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/BrowserChromiumProfileDirectory.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/CDPConnection.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession+Viewport.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumBrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumDocumentTitleObservation.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumNavigationInterceptor.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProcessController.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProfileRuntime.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProfileRuntimeConnection.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumProfileRuntimeLease.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/Chromium/ChromiumViewportDocument.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Engine/WebKitBrowserEngineSession.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/BrowserChromiumProfileDirectoryTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/BrowserEngineResolverTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/CDPConnectionTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumBrowserEngineSessionTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumNavigationInterceptorTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumViewportDocumentLoadDelegate.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumViewportDocumentTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumViewportInputQueueTests.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/ChromiumViewportNoOpMessageHandler.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/NavigationTestCDPTransport.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/WebKitBrowserEngineSessionTests.swift
  • Resources/Localizable.xcstrings
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/Panels/BrowserPanel.swift
  • Sources/TerminalController.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/BrowserWebContentProcessTests.swift
  • cmuxTests/WorkspaceUnitTests.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

Comment thread Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/Engine/CDPConnectionTests.swift Outdated
Comment thread Sources/Panels/BrowserPanel.swift Outdated
@greptile-apps

greptile-apps Bot commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

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

Bypass the limit by tagging @greptile-apps to review.

@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

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

3 participants