Skip to content

Honor Settings rebinding of Global Search (parse package object-form cmux.json bindings) - #5143

Merged
austinywang merged 3 commits into
mainfrom
issue-5137-global-search-shortcut-configurable
Jun 1, 2026
Merged

austinywang merged 3 commits into
mainfrom
issue-5137-global-search-shortcut-configurable

Conversation

@austinywang

@austinywang austinywang commented Jun 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #5137 — pressing ⌥⌘F kept opening Global Search even after rebinding the Global Search shortcut in Settings → Keyboard Shortcuts, so the binding was effectively hardcoded.

Root cause (dual source of truth, divergent on-disk schema)

The keyboard-shortcut system is mid-migration into the CmuxSettings/CmuxSettingsUI packages, and the in-app Settings UI now lives in the package. When you rebind a shortcut, the package persists it to ~/.config/cmux/cmux.json under shortcuts.bindings.<action> as a nested StoredShortcut object:

{ "shortcuts": { "bindings": { "globalSearch": { "first": { "key": "j", "command": true, "control": true } } } } }

But SystemWideHotkeyController (the Carbon RegisterEventHotKey owner for the system-wide hotkeys) resolves its shortcut through the legacy KeyboardShortcutSettings → KeyboardShortcutSettingsFileStore, whose parseShortcutBindingValue only understood the human-editable string form ("cmd+opt+f") and string-array chords. It returned nil for the object form and logged "ignoring invalid shortcut binding", so the rebinding never reached the store — the controller kept the built-in ⌥⌘F default registered.

This is a class of bug, not a one-off: every action resolved through the legacy file store (the two system-wide Carbon hotkeys globalSearch and showHideAllWindows) silently ignored any rebinding made in the package Settings UI. globalSearch is the visible victim because it is always enabled; showHideAllWindows is off by default so the same gap went unnoticed.

Reproduced + verified locally (running Debug app)

Driving the real Carbon hotkey via synthesized CGEvents and reading the in-app globalHotkey.* debug log:

shortcuts.bindings.globalSearch in cmux.json legacy reader ⌥⌘F fires? ⌃⌘J fires?
{"first":{"key":"j","command":true,"control":true}} (what the Settings UI writes) — before fix dropped → stays ⌥⌘F YES (bug) no
"ctrl+cmd+j" (legacy string form) parsed → re-registers ⌃⌘J no yes
object form — after fix parsed → re-registers ⌃⌘J no yes

Fix

Teach KeyboardShortcutSettingsFileStore to decode the package's nested object form ({ "first": { stroke }, "second": { stroke }? }), including the empty-first-key "unbound" marker and two-stroke chords. The legacy reader now understands every form that can legitimately appear in cmux.json, converging both cmux.json readers on one on-disk contract instead of patching a single shortcut.

Tests

Two-commit structure (failing test → fix). Added behavior-level regression coverage to cmuxTests/GlobalSearchShortcutSettingsTests.swift that exercises KeyboardShortcutSettingsFileStore.override(for:) through cmux.json:

  • testSettingsFileStoreParsesPackageObjectFormGlobalSearchShortcut — fails before the fix (returns the default instead of the rebinding), passes after.
  • testSettingsFileStoreParsesPackageObjectFormChordShortcut — a non-system-wide action, proving the fix is general.
  • testSettingsFileStoreParsesPackageObjectFormUnboundShortcut — the explicit "no shortcut" marker.

🤖 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
Localized settings-file parsing with strict validation and broad test coverage; no auth or data-path changes.

Overview
The legacy KeyboardShortcutSettingsFileStore path only accepted string / string-array shortcut bindings in cmux.json, so rebinding in the CmuxSettings Settings UI (nested {"first": {...}, "second": {...}?} objects under shortcuts.bindings) was dropped and system-wide shortcuts like Global Search kept their built-in defaults.

This PR adds object-form decoding in parseShortcutBindingValue, including unbound (empty first.key), two-stroke chords, and the same validation as the string parser (bare keys for modifier-required actions, reject malformed second instead of degrading to a single stroke, strict keyCode handling). Regression tests in GlobalSearchShortcutSettingsTests cover global search, chords, unbound, and rejection cases.

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


Summary by cubic

Fixes #5137 by making Global Search honor the shortcut set in Settings. The legacy reader now parses the object-form bindings the CmuxSettings UI writes to cmux.json, so ⌥⌘F no longer triggers after a rebind.

  • Bug Fixes
    • Parse nested object form {"first": {...}, "second": {...}?} in KeyboardShortcutSettingsFileStore, including the empty "unbound" marker, two-stroke chords, and validation (reject malformed second, out-of-range keyCode, and bare first-stroke when a modifier is required).
    • Ensure system-wide hotkeys (globalSearch, showHideAllWindows) use the updated bindings.
    • Add regression tests for object-form parsing: chords, explicit unbinding, malformed chords, and bare-key rejection.

Written for commit 00ca077. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Enhanced keyboard shortcut parsing to support nested object-style bindings in settings files, enabling two-stroke chords and explicit unbound overrides.
  • Bug Fixes

    • Stricter validation: malformed or out-of-range stroke data and invalid bare-stroke actions are rejected to prevent incorrect bindings.
  • Tests

    • Added unit tests covering object-form parsing, chord handling, unbound overrides, and rejection cases.

austinywang and others added 2 commits June 1, 2026 15:44
… dropped

The in-app Settings UI (CmuxSettings package) persists shortcut rebindings
to cmux.json under shortcuts.bindings.<action> as nested StoredShortcut
objects ({"first": {key, command, ...}}), but the legacy
KeyboardShortcutSettingsFileStore parser — which feeds KeyboardShortcutSettings
and thus the system-wide Carbon hotkeys (globalSearch, showHideAllWindows) —
only understands the human-editable "cmd+opt+f" string form. The object form is
silently dropped, so SystemWideHotkeyController never sees a Global Search
rebinding and the default ⌥⌘F keeps opening Global Search.

This commit adds the regression coverage only (red); the parser fix follows.

Issue: #5137

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eader

KeyboardShortcutSettingsFileStore is the parser that feeds
KeyboardShortcutSettings.shortcut(for:) and therefore SystemWideHotkeyController.
It understood only the human-editable string ("cmd+opt+f") and string-array
chord forms of a cmux.json shortcut binding. But the in-app Settings UI lives in
the CmuxSettings package, which serializes each binding as a nested StoredShortcut
object ({"first": {key, command, ...}, "second": {...}?}) under
shortcuts.bindings.<action>. Those objects were silently dropped, so a rebinding
made in Settings never reached the store: the global-search Carbon hotkey kept
its built-in ⌥⌘F default and Global Search kept opening on ⌥⌘F after a rebind
(and showHideAllWindows had the same latent gap).

Teach the reader to decode the package object form (including the empty-first-key
"unbound" marker and two-stroke chords) so every action resolved through this
store honors a Settings rebinding. This converges the two cmux.json readers on a
single on-disk contract instead of patching one shortcut.

Fixes #5137

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

vercel Bot commented Jun 1, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 1, 2026 11:37pm
cmux-staging Building Building Preview, Comment Jun 1, 2026 11:37pm

@coderabbitai

coderabbitai Bot commented Jun 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

KeyboardShortcutSettingsFileStore now decodes shortcut bindings encoded as dictionaries with nested first and optional second stroke objects. The parser maps an empty first.key to .unbound, enforces action-specific bare-first-stroke rules, rejects malformed second strokes, and converts keyCode to UInt16 only when representable. Tests cover valid single and two-stroke objects, explicit unbound, and rejection cases.

Changes

Object-form shortcut binding support

Layer / File(s) Summary
Object-form shortcut binding parser
Sources/KeyboardShortcutSettingsFileStore.swift
parseShortcutBindingValue detects dictionary-form bindings and delegates to parseShortcutObjectForm(_:), which decodes { "first": ..., "second"?: ... } into StoredShortcut. parseShortcutStrokeObject(_:) extracts stroke fields (key, command/modifier booleans, optional keyCode → UInt16 when representable). Empty first.key maps to .unbound. A malformed or missing second invalidates the whole binding; bare-first strokes that violate action rules are rejected.
Object-form parsing test coverage
cmuxTests/GlobalSearchShortcutSettingsTests.swift
Five tests added: single-stroke globalSearch in object form, two-stroke newTab chord in object form, explicit unbound via empty first.key, rejection when second is malformed/incomplete, and rejection when a bare-first stroke violates modifier requirements.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A rabbit nibbles keys and codes so bright,
Parses first and second in the moonlight,
Empty first becomes a hush, unbound,
Malformed seconds tumble to the ground,
Tests hop in place to make the parsing right.


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift File And Package Boundaries ❌ Error KeyboardShortcutSettingsFileStore.swift is 1977 lines vs 1595-line budget (382 lines over), exceeding 250-line growth threshold on oversized file. Budget.tsv not updated. Update .github/swift-file-length-budget.tsv to 1977, or extract shortcut parsing logic into a package and reduce main file >200 lines.
Cmux Swiftui State Layout ❌ Error PR introduces KeyboardShortcutSettingsObserver with @Published (ObservableObject) instead of modern @Observable pattern per swiftui-state-layout.md rules. Replace ObservableObject with @Observable macro for KeyboardShortcutSettingsObserver and remove @Published decorator on revision property.
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (15 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR fully addresses issue #5137: the parser now handles object-form bindings so rebindings persist correctly, regression tests verify the fix (failing before, passing after), and both system-wide and general shortcuts are covered.
Out of Scope Changes check ✅ Passed All changes are scoped to the linked issue #5137: object-form parsing in KeyboardShortcutSettingsFileStore and regression tests in GlobalSearchShortcutSettingsTests, with no unrelated modifications.
Cmux Swift Actor Isolation ✅ Passed PR adds pure parsing helpers returning value types with no state mutation or actor isolation issues; tests properly marked @MainActor; logger correctly nonisolated.
Cmux Swift Blocking Runtime ✅ Passed PR adds object-form shortcut parsing functions without introducing blocking/timing synchronization. New code performs synchronous JSON parsing and validation only.
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift code changes (.swift files), which are explicitly out of scope for the "cmux no hacky sleeps" check that covers only TypeScript, JavaScript, shell, and build/runtime scripts.
Cmux Algorithmic Complexity ✅ Passed Parsing methods are O(1) per binding on fixed ~83 keyboard actions. No nested loops, filtering, or sorting. Not in hot paths. Tests allowed.
Cmux Swift Concurrency ✅ Passed Added synchronous parsing methods for shortcut bindings. No legacy async patterns (DispatchQueue.global, Combine, completion handlers, or fire-and-forget Tasks) were introduced.
Cmux Swift @Concurrent ✅ Passed All new functions are synchronous parsing helpers with no async, @concurrent, or actor isolation violations. No file I/O, network, or CPU-heavy operations detected.
Cmux Swift Logging ✅ Passed Production code uses Apple's unified Logger with proper nonisolated declaration and privacy redaction; no prohibited patterns (print/debugPrint/dump/NSLog) found; test file has no logging violations.
Cmux User-Facing Error Privacy ✅ Passed Production changes add internal parsing functions with no user-facing errors, alerts, or sensitive information exposure. Test additions are developer-only code. All logging uses privacy masking.
Cmux Full Internationalization ✅ Passed PR adds only internal data parsing logic and tests with no user-facing text, no localization API calls, and no string catalog modifications.
Cmux Architecture Rethink ✅ Passed PR adds pure data parsing for object-form keyboard shortcuts without timing repairs, dispatch patterns, locks, observers, or split architecture—a small correctness fix with clear ownership.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR contains only keyboard shortcut parsing code with zero window-related declarations (NSWindow, NSPanel, NSWindowController, Window, WindowGroup). No auxiliary windows are created or modified.
Title check ✅ Passed The title accurately summarizes the main change: extending the legacy reader to parse package object-form bindings so Global Search honors Settings rebindings.
Description check ✅ Passed PR description comprehensively covers the bug, root cause, fix, and testing approach with clear context and verification details.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-5137-global-search-shortcut-configurable

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 Jun 1, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Teaches KeyboardShortcutSettingsFileStore.parseShortcutBindingValue to decode the nested-object binding format ({ "first": { stroke }, "second": { stroke }? }) that the CmuxSettings package UI writes to cmux.json, so system-wide Carbon hotkey rebindings (global search, show/hide all windows) are no longer silently dropped.

  • parseShortcutObjectForm is added to handle the object shape, mirroring all existing validation rules from the string parser: bare-first-stroke guard, the empty-key unbound marker, and chord invalidation on a malformed second stroke.
  • parseShortcutStrokeObject uses UInt16(exactly:) to reject out-of-range keyCode values instead of wrapping them, and jsonBool is used to distinguish JSON booleans from numbers.
  • Five regression tests in GlobalSearchShortcutSettingsTests cover the new object form: single-stroke rebind, chord, explicit unbound, malformed-second-stroke rejection, and bare-key-without-modifier rejection.

Confidence Score: 5/5

Safe to merge — the change is a pure additive parsing branch in the settings file store with no effect on existing string or array shortcut forms, and the previous-round issues (chord degradation and UInt16 wrapping) are confirmed fixed in this commit.

The fix is a self-contained parser addition inside parseShortcutBindingValue. It adds a new dictionary branch after the existing string and string-array paths, so pre-existing JSON forms are completely unaffected. All edge cases in the new path — missing first, malformed strokes, empty-key unbound marker, bare-key rejection, chord invalidation on a bad second stroke, and out-of-range keyCode — are explicitly handled and covered by the five new regression tests.

No files require special attention.

Important Files Changed

Filename Overview
Sources/KeyboardShortcutSettingsFileStore.swift Adds parseShortcutObjectForm and parseShortcutStrokeObject to decode the package's nested-object binding shape; all edge cases (unbound marker, chord invalidation, out-of-range keyCode) are correctly handled.
cmuxTests/GlobalSearchShortcutSettingsTests.swift Adds five well-scoped regression tests exercising the new object-form parser; each test writes a real cmux.json to a temp directory, constructs the file store, and asserts the expected StoredShortcut or nil result.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[cmux.json shortcuts.bindings.action] --> B{parseShortcutBindingValue}
    B -->|NSNull| C[.unbound]
    B -->|String e.g. cmd+opt+f| D[StoredShortcut.parseConfig string]
    B -->|String array e.g. ctrl+b n| E[StoredShortcut.parseConfig strokes]
    B -->|Dictionary object form| F[parseShortcutObjectForm]
    F --> G{first key exists?}
    G -->|no| H[nil — log ignored]
    G -->|yes| I{parseShortcutStrokeObject first}
    I -->|nil / malformed| H
    I -->|key empty| C
    I -->|valid| J{bare key allowed?}
    J -->|no: action requires modifier| H
    J -->|yes| K{second key in object?}
    K -->|absent or null| L[StoredShortcut first only]
    K -->|present| M{parseShortcutStrokeObject second}
    M -->|nil / malformed| H
    M -->|valid| N[StoredShortcut first + second chord]
    L --> O[normalizedSettingsFileShortcut]
    N --> O
    O --> P[SystemWideHotkeyController registers Carbon hotkey]
Loading

Reviews (2): Last reviewed commit: "Harden object-form shortcut parsing (rev..." | Re-trigger Greptile

Comment on lines +1040 to +1041
let second = object["second"].flatMap(parseShortcutStrokeObject)
return StoredShortcut(first: first, second: second)

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 Silent chord degradation on malformed "second" stroke

If object["second"] exists but parseShortcutStrokeObject returns nil (e.g., the dict is missing its "key" field), second silently becomes nil and parseShortcutObjectForm returns a single-stroke StoredShortcut. The outer caller in parseShortcutBindingValue sees a non-nil result and skips the "ignoring invalid shortcut binding" log, so an intended chord binding quietly degrades to a single key with no diagnostic. Consider logging a warning when object["second"] != nil but the stroke couldn't be decoded.

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.

Fixed in 00ca077 — a present-but-malformed second stroke now invalidates the whole binding instead of degrading the chord to a single stroke.

— Claude Code

shift: jsonBool(dict["shift"]) ?? false,
option: jsonBool(dict["option"]) ?? false,
control: jsonBool(dict["control"]) ?? false,
keyCode: jsonInt(dict["keyCode"]).map { UInt16(truncatingIfNeeded: $0) }

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 UInt16(truncatingIfNeeded:) silently bit-pattern wraps any Int outside 0…65535. If cmux.json ever carries a negative or oversized keyCode (e.g., hand-edited or written by a future schema change), the result is a quietly wrong hardware key code that gets registered with Carbon — potentially stealing an unrelated hotkey. flatMap { UInt16(exactly: $0) } keeps the same nil-for-missing behaviour while rejecting out-of-range values cleanly.

Suggested change
keyCode: jsonInt(dict["keyCode"]).map { UInt16(truncatingIfNeeded: $0) }
keyCode: jsonInt(dict["keyCode"]).flatMap { UInt16(exactly: $0) }

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.

Fixed in 00ca077 — switched to UInt16(exactly:); an out-of-range keyCode now rejects the binding instead of bit-wrapping to a different key.

— Claude Code

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

4 issues found across 2 files

Prompt for AI agents (unresolved issues)

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


<file name="cmuxTests/GlobalSearchShortcutSettingsTests.swift">

<violation number="1" location="cmuxTests/GlobalSearchShortcutSettingsTests.swift:97">
P3: New unit tests use XCTest. Repo rule says new non-UI tests should use Swift Testing. Migrate these cases to `@Test` style.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread Sources/KeyboardShortcutSettingsFileStore.swift Outdated
Comment thread Sources/KeyboardShortcutSettingsFileStore.swift Outdated
Comment thread Sources/KeyboardShortcutSettingsFileStore.swift Outdated
)
}

func testSettingsFileStoreParsesPackageObjectFormGlobalSearchShortcut() throws {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: New unit tests use XCTest. Repo rule says new non-UI tests should use Swift Testing. Migrate these cases to @Test style.

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

<comment>New unit tests use XCTest. Repo rule says new non-UI tests should use Swift Testing. Migrate these cases to `@Test` style.</comment>

<file context>
@@ -94,6 +94,121 @@ final class GlobalSearchShortcutSettingsTests: XCTestCase {
         )
     }
 
+    func testSettingsFileStoreParsesPackageObjectFormGlobalSearchShortcut() throws {
+        // Regression for https://github.com/manaflow-ai/cmux/issues/5137.
+        // The in-app Settings UI (CmuxSettings package) persists every
</file context>

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.

Intentional: this extends the existing XCTest suite GlobalSearchShortcutSettingsTests (an XCTestCase). The repo rule migrates files to Swift Testing incrementally when edited and says not to bulk-rewrite untouched tests; mixing @test into an existing XCTestCase isn't possible, so new methods match the file's framework.

— Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Address greptile/cubic review findings on the new cmux.json object-form parser:

- Reject a present-but-malformed `second` stroke instead of silently degrading
  a chord to a single-stroke binding.
- Reject an out-of-range `keyCode` (UInt16(exactly:)) instead of bit-pattern
  wrapping it into a different physical key.
- Apply the same bare-first-stroke rule the string parser uses
  (StoredShortcut.parseConfig): an action that requires a modifier rejects a
  bare key in the object form too.

Adds regression coverage for the malformed-chord and bare-key rejections.

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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Prompt for AI agents (unresolved issues)

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


<file name="cmuxTests/GlobalSearchShortcutSettingsTests.swift">

<violation number="1" location="cmuxTests/GlobalSearchShortcutSettingsTests.swift:212">
P2: New tests use XCTest instead of Swift Testing. Project policy requires Swift Testing for new non-CLI unit tests.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

XCTAssertEqual(store.override(for: .globalSearch), .unbound)
}

func testSettingsFileStoreRejectsObjectFormChordWithMalformedSecondStroke() throws {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: New tests use XCTest instead of Swift Testing. Project policy requires Swift Testing for new non-CLI unit tests.

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

<comment>New tests use XCTest instead of Swift Testing. Project policy requires Swift Testing for new non-CLI unit tests.</comment>

<file context>
@@ -209,6 +209,66 @@ final class GlobalSearchShortcutSettingsTests: XCTestCase {
         XCTAssertEqual(store.override(for: .globalSearch), .unbound)
     }
 
+    func testSettingsFileStoreRejectsObjectFormChordWithMalformedSecondStroke() throws {
+        // A present-but-malformed `second` stroke must invalidate the whole
+        // binding rather than silently degrading the chord to a single stroke
</file context>

This branch was successfully deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

⌥⌘F always opens Global Search even after rebinding the Global Search shortcut in Settings

1 participant