Skip to content

Extract cmux settings into SPM packages - #4921

Closed
azooz2003-bit wants to merge 4 commits into
mainfrom
feat-settings-spm-packages
Closed

azooz2003-bit wants to merge 4 commits into
mainfrom
feat-settings-spm-packages

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented May 28, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • add zero-dependency CmuxSettings package for settings catalog paths, schema metadata, file reads/writes, and AsyncStream file observation
  • add CmuxSettingsUI package for settings navigation/search UI primitives, JSON path list modeling, and the package-owned settings root shell
  • split settings UI package types into focused files, remove mutable cross-actor search alias state, and use an async notification sequence for settings navigation
  • wire the app target and workspace to both packages while preserving current settings behavior through app-specific detail content and compatibility aliases

Verification

  • swift test --package-path Packages/CmuxSettings
  • swift test --package-path Packages/CmuxSettingsUI
  • ./scripts/check-pbxproj.sh
  • ./scripts/reload.sh --tag settings-spm6

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced settings search with improved organization and navigation capabilities
    • Implemented automatic settings file watching to reflect configuration changes in real-time
    • Strengthened settings management system with better persistence support
  • Refactor

    • Reorganized settings infrastructure for improved maintainability
  • Tests

    • Added test coverage for settings components

Review Change Stack

@vercel

vercel Bot commented May 28, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled May 28, 2026 4:15am
cmux-staging Building Building Preview, Comment May 28, 2026 4:15am

@coderabbitai

coderabbitai Bot commented May 28, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces two new local Swift packages—CmuxSettings and CmuxSettingsUI—to modularize settings I/O and UI. CmuxSettings provides a file-based store with async file-watching and a JSON-path catalog. CmuxSettingsUI implements searchable settings navigation with keyword-normalized filtering, visual highlighting, and lazy-load infrastructure. The main app refactors to use the catalog as the source of truth for settings paths and re-exports UI types from the new packages.

Changes

CmuxSettings and CmuxSettingsUI Packages

Layer / File(s) Summary
Settings catalog and API
Packages/CmuxSettings/Package.swift, Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsCatalog.swift, Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsCatalogTests.swift
Package manifest; JSON-path descriptors with derived sections; schema metadata and URL helpers (primary, legacy, application-support paths); supported-paths list; tests verify membership and default-URL construction.
Store with file watching
Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsStore.swift, Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsStoreTests.swift
Actor-based store: reads/writes snapshots, selects active URL (primary then fallback), emits file changes via AsyncStream; private O_EVTONLY watcher dispatches filesystem events; tests verify snapshot persistence and fallback selection.
JSON-path models and list
Packages/CmuxSettingsUI/Package.swift, Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsJSONPathModel.swift, Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift
UI package manifest with CmuxSettings dependency; model wraps path/section; list provides sorted array and contains lookup; view renders as SwiftUI List; tests verify sort order and section derivation.
Navigation targets and requests
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationTarget.swift, Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationRequest.swift, Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchEntry.swift
NavigationTarget enum with localized titles, symbols, and search keywords; NotificationCenter-based request posting with target/anchor/highlight; SearchEntry and EntryKind value types with normalized search text.
Search indexing and highlighting
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchIndex.swift, Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchHighlight.swift, Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchAliases.swift
Search index builds section/setting entries, normalizes/tokenizes queries, filters by token membership; highlight state and TimelineView-based opacity animation over elapsed time; alias index provides localized keywords and keyboard-shortcut action injection.
Settings views and components
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsCardNote.swift, Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsLazyLoadHelpers.swift, Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsRootView.swift
SettingsCardNote: caption/secondary styled text view; lazy-load preference key, marker, and View extension for frame observation; CmuxSettingsRootView: NavigationSplitView with searchable sidebar, scene-persisted selection, keyboard-shortcut aliases, pending-target callback, notification-driven navigation.
Catalog as source of truth
Sources/CmuxSettingsJSONPathSupport.swift, Sources/KeyboardShortcutSettingsFileStore.swift
CmuxSettingsJSONPathSupport now sources supported paths from CmuxSettingsCatalog; KeyboardShortcutSettingsFileStore imports catalog and derives schema version, URL strings, and path helpers from it instead of hardcoded values.
Main app integration and re-exports
Sources/SettingsCardNote.swift, Sources/SettingsLazyLoadHelpers.swift, Sources/SettingsNavigation.swift, Sources/SettingsSearchAliases.swift, Sources/cmuxApp.swift
Local implementations replaced with typealiases to CmuxSettingsUI equivalents; cmuxApp.swift swaps SettingsRootView for CmuxSettingsRootView with draft-state bindings, presenter callbacks, and alias injection.
Project and workspace setup
cmux.xcodeproj/project.pbxproj, cmux.xcworkspace/contents.xcworkspacedata
Adds CmuxSettings and CmuxSettingsUI to build phases, package dependencies, local package references; workspace includes both packages as FileRef groups.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • manaflow-ai/cmux#4849: Extends the newly-introduced SettingsSearchIndex to cover custom search-engine JSON paths via searchText and settingsPathAnchorIDs.
  • manaflow-ai/cmux#4165: Adds new terminal.agentHibernation.* paths to the supported-settings allowlist that now derives from CmuxSettingsCatalog.supportedJSONPaths.
  • manaflow-ai/cmux#4834: Introduces cmux.xcworkspace structure alongside Packages/*, directly referenced by this PR's workspace-update changes.

Poem

🐰 A catalog now holds the settings true,
Each JSON path gets its destined view,
File watchers listen with async delight,
Search glows bright as highlights ignite,
Two packages dance where the main app once stood.


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (4 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux Algorithmic Complexity ❌ Error SettingsSearchIndex.entries() rebuilds 108-entry list per keystroke with nested contains() filtering—O(entries×tokens×text_len) on hot UI path without caching. Cache allEntries or use inverted index keyed by normalized tokens for O(tokens) lookup instead of rescanning all entries per search.
Cmux Swift Logging ❌ Error PR adds unguarded NSLog calls in Sources/cmuxApp.swift: terminateForMissingLaunchTag() and handleNotificationPermissionAction(), violating swift-logging.md prohibition on NSLog in app/runtime code. Remove both NSLog calls or guard them with #if DEBUG, as they don't qualify as CLI output, tests, provider diags, or sanctioned permanent diagnostics.
Cmux Full Internationalization ❌ Error New user-facing strings "settings.search.noResults" and "settings.search.prompt" lack translations for 17 of 19 supported locales (only en/ja present). Add translations for both strings to all 19 supported locales in Resources/Localizable.xcstrings before merging.
Cmux Architecture Rethink ❌ Error CmuxSettingsRootView uses NotificationCenter as side channel to update @SceneStorage state, creating split ownership between user selection and external notifications. Use single ownership via state binding instead of notifications, or document invariants with strict guards preventing state inconsistency.
Description check ⚠️ Warning The description covers the summary of changes and verification steps, but does not follow the provided template structure. Missing testing details, demo video, review trigger, and a complete checklist. Restructure the description to follow the template: add a 'Testing' section with explicit testing steps, include 'Demo Video' section (if applicable), add the 'Review Trigger' block, and complete the 'Checklist' with checkboxes marked.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Extract cmux settings into SPM packages' clearly and accurately summarizes the main objective of the changeset: extracting settings functionality into two new Swift Package Manager packages (CmuxSettings and CmuxSettingsUI).
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 CmuxSettingsStore is actor-isolated with nonisolated methods. Value models are Sendable. Static enums have no mutable state. SwiftUI Views are MainActor. No actor isolation violations.
Cmux Swift Blocking Runtime ✅ Passed PR introduces no blocking synchronization patterns. NSLock in CmuxSettingsFileWatcher protects cleanup race (allowed exception); SettingsSearchHighlight uses TimelineView (allowed UI timing).
Cmux No Hacky Sleeps ✅ Passed PR modifies only Swift packages and Xcode config files; does not introduce TypeScript, JavaScript, shell, or non-Swift runtime script changes covered by runtime-no-hacky-sleeps rule.
Cmux Swift Concurrency ✅ Passed DispatchSource for file monitoring in CmuxSettingsStore is a justified OS callback boundary; the legacy pattern is properly encapsulated as private and exposed via modern AsyncStream APIs.
Cmux Swift @Concurrent ✅ Passed No Swift @concurrent annotation violations found. nonisolated AsyncStream-returning methods properly inherit caller context; .task modifier is intentionally MainActor-bound.
Cmux Swift File And Package Boundaries ✅ Passed New files under 400 lines with clear single responsibility; no oversized file additions exceed 250 lines; feature logic properly moved to SwiftPM packages; clean architecture with no mixed concerns.
Cmux User-Facing Error Privacy ✅ Passed CmuxSettingsStoreError is library code only used in tests, not exposed to users. No LocalizedError conformance exists.
Cmux Swiftui State Layout ✅ Passed No ObservableObject/@Published/StateObject patterns. GeometryReader used only for measurement in background (non-layout). List rows use immutable value snapshots. No render-time state mutations.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR does not introduce new NSWindow, NSPanel, NSWindowController, Window, or WindowGroup declarations; it only refactors existing settings UI into SPM packages.
✨ 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-settings-spm-packages

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

❤️ Share

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

@greptile-apps

greptile-apps Bot commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extracts settings model and UI into two zero-dependency SwiftPM packages (CmuxSettings and CmuxSettingsUI), wires the app target to them via typealias compatibility shims, and adds tests for catalog path resolution and store persistence. The extraction is clean: the app's heavy KeyboardShortcutSettingsFileStore and SettingsNavigation files are reduced to thin forwarding layers while all independently testable logic moves into the packages.

  • CmuxSettings adds CmuxSettingsCatalog (path registry, schema metadata, default URL helpers) and CmuxSettingsStore (actor-based file read/write + AsyncStream change observation via CmuxSettingsFileWatcher).
  • CmuxSettingsUI adds the sidebar search index, navigation target/request types, alias index, highlight helpers, lazy-load utilities, and CmuxSettingsRootView — the new settings window shell with searchable sidebar and navigation.
  • The app target wires both packages and preserves existing settings behavior through app-specific detail content and compatibility typealias aliases.

Confidence Score: 4/5

Safe to merge for existing settings behavior; the file watcher issues flagged in prior threads are the main correctness risks if consumers of the new CmuxSettingsStore AsyncStream API rely on it in production.

The app-side compatibility shims and the KeyboardShortcutSettingsFileStore (which uses the pre-existing ShortcutSettingsFileWatcher with correct restart logic) are unchanged in behavior. The new CmuxSettingsStore and its CmuxSettingsFileWatcher have confirmed defects — silent stream death after atomic writes and a nil stream on fresh install — that have been flagged in earlier review rounds but not yet addressed. The settings search double-allocation is a quality issue in the new package code but does not affect correctness.

Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsStore.swift (CmuxSettingsFileWatcher restart and missing-file fallback), Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsRootView.swift and SettingsSearchIndex.swift (double sidebarEntries evaluation).

Important Files Changed

Filename Overview
Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsCatalog.swift New catalog of settings paths, schema metadata, and default file URL helpers; all values are static lets/constants with no concurrency concerns.
Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsStore.swift New actor-based settings store with async file watcher; CmuxSettingsFileWatcher does not restart after atomic writes/renames and silently returns no stream when the file doesn't yet exist (both flagged in prior review threads).
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchIndex.swift Central search index with ~120 setting entries; settingEntries() is a function that re-allocates all entries on each search keystroke, and is called twice per body render via sidebarEntries.
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsRootView.swift New settings root view with sidebar/search split; sidebarEntries is evaluated twice per body render triggering double settingEntries() allocation; global alias provider mutation flagged in prior thread.
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchAliases.swift Alias index with localized strings; settingAliases is a static let (correct). nonisolated(unsafe) provider pattern flagged in prior thread on the app-side file.
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsJSONPathModel.swift JSON path model with list view; CmuxSettingsJSONPathList.all is a static var that re-sorts on every call (flagged in prior thread).
Sources/SettingsNavigation.swift Trimmed to compatibility typealiases forwarding to the new CmuxSettingsUI package types; straightforward refactor with no new logic.
Sources/KeyboardShortcutSettingsFileStore.swift Large store now imports CmuxSettings for catalog/path helpers; paths delegate to CmuxSettingsCatalog static funcs; no behavior change in the parser itself.
Sources/SettingsSearchAliases.swift Reduced to a typealias forwarding to CmuxSettingsUI.SettingsSearchAliasIndex.
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationTarget.swift Navigation target enum with localized titles and search text; uses String(localized:defaultValue:) throughout.
Sources/cmuxApp.swift App entry point unchanged in structure; wiring to new packages preserved existing startup sequence.

Sequence Diagram

sequenceDiagram
    participant App as cmuxApp
    participant RootView as CmuxSettingsRootView
    participant Index as SettingsSearchIndex
    participant Store as CmuxSettingsStore
    participant Watcher as CmuxSettingsFileWatcher
    participant FS as FileSystem

    App->>Store: primaryChanges() → AsyncStream
    Store->>Watcher: init(url:onChange:)
    Watcher->>FS: open(O_EVTONLY)
    FS-->>Watcher: fd
    Watcher->>Watcher: DispatchSource.resume()
    FS-->>Watcher: kqueue event (write/delete/rename)
    Watcher->>Store: onChange()
    Store->>App: yield(CmuxSettingsFileSnapshot)

    App->>RootView: body render
    RootView->>Index: entries(matching: searchText)
    Index->>Index: allEntries() → settingEntries() [120+ allocs]
    Index-->>RootView: [SettingsSearchEntry]
    RootView->>Index: sidebarEntries.isEmpty check (second call)
    Index->>Index: allEntries() → settingEntries() [120+ allocs again]
    Index-->>RootView: [SettingsSearchEntry]
Loading

Reviews (4): Last reviewed commit: "Clean up settings UI package boundaries" | Re-trigger Greptile

Comment on lines +82 to +92
private let onChange: @Sendable () -> Void
private let lock = NSLock()
private var isCancelled = false

init(url: URL, onChange: @escaping @Sendable () -> Void) {
self.queue = DispatchQueue(label: "com.cmux.settings.file-watcher.\(UUID().uuidString)")
self.onChange = onChange

let descriptor = open(url.path, O_EVTONLY)
guard descriptor >= 0 else {
fileDescriptor = -1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Stream silently goes dead after atomic write or file deletion

CmuxSettingsFileWatcher's event handler calls onChange() unconditionally on every event but never restarts the watcher. When writePrimaryContents writes atomically (temp file + rename), the .rename event fires once and the DispatchSource continues watching the now-stale file descriptor of the original inode — all subsequent writes are missed. The same happens after an external editor's atomic save or a plain .delete. ShortcutSettingsFileWatcher (the pre-existing watcher) avoids this by calling self.start() inside the handler on .delete/.rename events to re-attach to the new inode. Without equivalent restart logic here, any consumer of primaryChanges() or fileChanges(at:) will silently stop receiving events after the first atomic write.

Comment on lines +99 to +111
fileDescriptor: descriptor,
eventMask: [.write, .delete, .rename, .revoke],
queue: queue
)
self.source = source
source.setEventHandler { [weak self] in
self?.onChange()
}
source.setCancelHandler {
close(descriptor)
}
source.resume()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Stream delivers zero events when watched file does not yet exist

If the cmux.json file does not exist when primaryChanges() is first observed (e.g., on a fresh install before bootstrapPrimaryTemplateIfNeeded runs), open(url.path, O_EVTONLY) returns -1, source is nil, and no DispatchSource is ever installed. The stream will never deliver an event, even if the file is created moments later. The pre-existing ShortcutSettingsFileWatcher handles this case by falling back to watching the parent directory and calling start() once the file appears. CmuxSettingsFileWatcher has no such directory fallback.

Comment on lines +17 to +21
public static var all: [CmuxSettingsJSONPathModel] {
CmuxSettingsCatalog.supportedJSONPathDescriptors
.sorted { $0.path < $1.path }
.map(CmuxSettingsJSONPathModel.init(descriptor:))
}

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 CmuxSettingsJSONPathList.all is a static var that re-sorts all ~100 descriptors on every call. The source array is a static let, so the result is always the same — computing and sorting it once as a static let eliminates redundant O(n log n) work on every access, including from SwiftUI view bodies that call it through init.

Suggested change
public static var all: [CmuxSettingsJSONPathModel] {
CmuxSettingsCatalog.supportedJSONPathDescriptors
.sorted { $0.path < $1.path }
.map(CmuxSettingsJSONPathModel.init(descriptor:))
}
public static let all: [CmuxSettingsJSONPathModel] =
CmuxSettingsCatalog.supportedJSONPathDescriptors
.sorted { $0.path < $1.path }
.map(CmuxSettingsJSONPathModel.init(descriptor:))

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

Comment on lines +64 to +66
static var supportedSettingsJSONPaths: Set<String> {
CmuxSettingsCatalog.supportedJSONPaths
}

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 supportedSettingsJSONPaths was a static let constant before this PR; changing it to a static var computed property signals mutability where there is none and forces an indirect call on each access. Since CmuxSettingsCatalog.supportedJSONPaths is itself a static let, the forwarded value is always identical — assigning it directly as a static let preserves the constant-access semantics.

Suggested change
static var supportedSettingsJSONPaths: Set<String> {
CmuxSettingsCatalog.supportedJSONPaths
}
static let supportedSettingsJSONPaths: Set<String> = CmuxSettingsCatalog.supportedJSONPaths

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

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

🤖 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/CmuxSettings/Sources/CmuxSettings/CmuxSettingsCatalog.swift`:
- Around line 3-46: Add Swift-DocC triple-slash comments to every public symbol
in this file: document the CmuxSettingsJSONPathDescriptor type (describe its
purpose), its stored properties path and section, and its public
init(path:section:) (explain behavior when section is nil); document the
CmuxSettingsCatalog enum and each public member: currentSchemaVersion,
schemaURLString, defaultPrimaryURL(_:), defaultLegacyURL(_:),
defaultApplicationSupportLegacyURL(applicationSupportDirectoryURL:releaseBundleIdentifier:),
supportedJSONPathDescriptors, and supportedJSONPaths — each comment should
briefly explain what the symbol represents, its parameters/return value and any
important behavior or defaults so the package meets the DocC requirement.

In `@Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsStore.swift`:
- Around line 4-76: Add Swift-DocC triple-slash documentation to every public
symbol in this file: CmuxSettingsFileSnapshot (describe purpose and fields url,
contents), CmuxSettingsStoreError (document the unreadableData case and when it
is thrown), CmuxSettingsStore (summary of the actor’s responsibility and
threading/Sendable behavior) and each public method:
init(primaryURL:fallbackURLs:fileManager:), readActiveSnapshot(),
readPrimarySnapshot(), writePrimaryContents(_:), primaryChanges(),
fileChanges(at:). For each method include a brief summary, parameters, return
value, and documented errors/behavior (e.g., when
CmuxSettingsStoreError.unreadableData is thrown, that fileChanges returns an
AsyncStream of CmuxSettingsFileSnapshot, and that primaryChanges is
nonisolated). Keep comments concise and use triple-slash (///) Swift-DocC style
directly above each public declaration.
- Around line 57-64: The fileChanges watcher currently ignores missing or
deleted files and fails to notify subscribers on create/rename because
CmuxSettingsFileWatcher aborts if open(url.path, O_EVTONLY) fails and the
closure drops events when String(contentsOf:) fails; update
CmuxSettingsStore.fileChanges to watch the parent directory (not just the file)
via CmuxSettingsFileWatcher, emit an initial CmuxSettingsFileSnapshot reflecting
the current readSnapshot (empty contents when missing), and in the watch
callback attempt to read the file and on failure (file not found) yield a
CmuxSettingsFileSnapshot(url: url, contents: "") so create/rename/delete events
produce an empty/cleared snapshot; also make the watcher re-arm or retry opening
when the initial open fails so post-subscription creates trigger updates (keep
continuation.onTermination to call watcher.cancel()).

In
`@Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsCatalogTests.swift`:
- Around line 1-19: Replace XCTest usage with Swift Testing: change `import
XCTest` to `import Testing`, mark the test container `CmuxSettingsCatalogTests`
with `@Suite` and annotate each test function
(`testSupportedJSONPathsContainCurrentSettingsSurface` and
`testDefaultPrimaryURLUsesCmuxJSON`) with `@Test`; replace
`XCTAssertTrue(CmuxSettingsCatalog.supportedJSONPaths.contains(...))` with `try
`#expect`(CmuxSettingsCatalog.supportedJSONPaths.contains(...)).toBeTrue()` and
replace `XCTAssertEqual(CmuxSettingsCatalog.defaultPrimaryURL(homeDirectoryURL:
home).path, "...")` with `try
`#expect`(CmuxSettingsCatalog.defaultPrimaryURL(homeDirectoryURL:
home).path).toEqual("...")`; apply the same changes for the other file
`CmuxSettingsStoreTests.swift` (import, `@Suite/`@Test annotations, and replace
XCTAssert* with `try `#expect``/`try `#require`` as appropriate).

In `@Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsStoreTests.swift`:
- Around line 1-33: Tests currently use XCTest APIs; replace XCTest with the
project's Swift Testing style by changing import XCTest to import Testing,
convert the CmuxSettingsStoreTests XCTestCase subclass into a `@Suite` (or
top-level struct/class per project convention) and convert each test method
(testWriteAndReadPrimarySnapshot,
testActiveSnapshotFallsBackWhenPrimaryIsMissing) into `@Test` functions that use
`#expect`(...) assertions instead of XCTAssertEqual; ensure async/throws
signatures are preserved and that CmuxSettingsStore, writePrimaryContents,
readPrimarySnapshot, and readActiveSnapshot are invoked the same way, and update
assertion calls to `#expect`(snapshot.url).toBe(primaryURL) and
`#expect`(snapshot.contents).toBe(...) (or equivalent `#expect` syntax used in the
codebase).

In
`@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsJSONPathModel.swift`:
- Around line 5-46: Add Swift-DocC triple‑slash comments for every public symbol
in this file: document CmuxSettingsJSONPathModel (describe the model), its
public properties id, path, section and the initializer init(descriptor:
CmuxSettingsJSONPathDescriptor); document CmuxSettingsJSONPathList and its
static members all and contains(_:); and document CmuxSettingsJSONPathListView
plus its public init(paths:) and body. For each comment include a brief summary
sentence and where appropriate a Parameters/Returns note that references the
parameter names (e.g., descriptor, path, paths). Ensure all comments use ///
Swift-DocC style immediately above the symbol declarations.

In
`@Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift`:
- Around line 1-16: Replace the XCTest-based test with Swift Testing: remove
"import XCTest" and instead "import Testing"; convert the final class
CmuxSettingsJSONPathModelTests : XCTestCase into a `@Suite` (e.g., annotate a
struct or enum with `@Suite`) and change the test method
testPathModelsAreSortedAndSectioned into a `@Test` function; replace
XCTAssertEqual assertions with the Swift Testing expectation macro (`#expect`)
comparing values (use
`#expect`(paths.map(\.path)).toEqual(paths.map(\.path).sorted()) and
`#expect`(CmuxSettingsJSONPathModel(descriptor: .init(path:
"terminal.showScrollBar")).section).toEqual("terminal") or the equivalent
`#expect`(...) form); keep references to CmuxSettingsJSONPathList.all and
CmuxSettingsJSONPathModel(descriptor: ...) so the same logic is preserved.
🪄 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: e8c09a25-d9f0-4e08-9dd9-d2a2b52c4b98

📥 Commits

Reviewing files that changed from the base of the PR and between 21b9fdc and 6cbe5b5.

📒 Files selected for processing (11)
  • Packages/CmuxSettings/Package.swift
  • Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsCatalog.swift
  • Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsStore.swift
  • Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsCatalogTests.swift
  • Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsStoreTests.swift
  • Packages/CmuxSettingsUI/Package.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsJSONPathModel.swift
  • Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • cmux.xcodeproj/project.pbxproj

Comment on lines +3 to +46
public struct CmuxSettingsJSONPathDescriptor: Equatable, Hashable, Sendable {
public let path: String
public let section: String

public init(path: String, section: String? = nil) {
self.path = path
self.section = section ?? path.split(separator: ".", maxSplits: 1).first.map(String.init) ?? path
}
}

public enum CmuxSettingsCatalog {
public static let currentSchemaVersion = 1

public static let schemaURLString =
"https://raw.githubusercontent.com/manaflow-ai/cmux/main/web/data/cmux.schema.json"

public static func defaultPrimaryURL(homeDirectoryURL: URL = FileManager.default.homeDirectoryForCurrentUser) -> URL {
homeDirectoryURL
.appendingPathComponent(".config", isDirectory: true)
.appendingPathComponent("cmux", isDirectory: true)
.appendingPathComponent("cmux.json", isDirectory: false)
}

public static func defaultLegacyURL(homeDirectoryURL: URL = FileManager.default.homeDirectoryForCurrentUser) -> URL {
homeDirectoryURL
.appendingPathComponent(".config", isDirectory: true)
.appendingPathComponent("cmux", isDirectory: true)
.appendingPathComponent("settings.json", isDirectory: false)
}

public static func defaultApplicationSupportLegacyURL(
applicationSupportDirectoryURL: URL,
releaseBundleIdentifier: String = "com.cmuxterm.app"
) -> URL {
applicationSupportDirectoryURL
.appendingPathComponent(releaseBundleIdentifier, isDirectory: true)
.appendingPathComponent("settings.json", isDirectory: false)
}

public static let supportedJSONPathDescriptors: [CmuxSettingsJSONPathDescriptor] =
supportedJSONPathValues.map { CmuxSettingsJSONPathDescriptor(path: $0) }

public static let supportedJSONPaths: Set<String> = Set(supportedJSONPathValues)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add DocC comments for all public API in this package file.

This new package source exports public types/members without /// documentation, which violates the package API documentation requirement.

As per coding guidelines: Packages/**/Sources/**/*.swift: “Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment…”.

🤖 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/CmuxSettings/Sources/CmuxSettings/CmuxSettingsCatalog.swift` around
lines 3 - 46, Add Swift-DocC triple-slash comments to every public symbol in
this file: document the CmuxSettingsJSONPathDescriptor type (describe its
purpose), its stored properties path and section, and its public
init(path:section:) (explain behavior when section is nil); document the
CmuxSettingsCatalog enum and each public member: currentSchemaVersion,
schemaURLString, defaultPrimaryURL(_:), defaultLegacyURL(_:),
defaultApplicationSupportLegacyURL(applicationSupportDirectoryURL:releaseBundleIdentifier:),
supportedJSONPathDescriptors, and supportedJSONPaths — each comment should
briefly explain what the symbol represents, its parameters/return value and any
important behavior or defaults so the package meets the DocC requirement.

Comment on lines +4 to +76
public struct CmuxSettingsFileSnapshot: Equatable, Sendable {
public var url: URL
public var contents: String

public init(url: URL, contents: String) {
self.url = url
self.contents = contents
}
}

public enum CmuxSettingsStoreError: Error, Equatable {
case unreadableData(URL)
}

public actor CmuxSettingsStore {
public let primaryURL: URL
public let fallbackURLs: [URL]

private let fileManager: FileManager

public init(
primaryURL: URL = CmuxSettingsCatalog.defaultPrimaryURL(),
fallbackURLs: [URL] = [CmuxSettingsCatalog.defaultLegacyURL()],
fileManager: FileManager = .default
) {
self.primaryURL = primaryURL
self.fallbackURLs = fallbackURLs
self.fileManager = fileManager
}

public func readActiveSnapshot() throws -> CmuxSettingsFileSnapshot {
let activeURL = ([primaryURL] + fallbackURLs).first { url in
fileManager.fileExists(atPath: url.path)
} ?? primaryURL
return try readSnapshot(at: activeURL)
}

public func readPrimarySnapshot() throws -> CmuxSettingsFileSnapshot {
try readSnapshot(at: primaryURL)
}

public func writePrimaryContents(_ contents: String) throws {
try fileManager.createDirectory(
at: primaryURL.deletingLastPathComponent(),
withIntermediateDirectories: true
)
try contents.write(to: primaryURL, atomically: true, encoding: .utf8)
}

public nonisolated func primaryChanges() -> AsyncStream<CmuxSettingsFileSnapshot> {
fileChanges(at: primaryURL)
}

public nonisolated func fileChanges(at url: URL) -> AsyncStream<CmuxSettingsFileSnapshot> {
AsyncStream { continuation in
let watcher = CmuxSettingsFileWatcher(url: url) {
guard let contents = try? String(contentsOf: url, encoding: .utf8) else { return }
continuation.yield(CmuxSettingsFileSnapshot(url: url, contents: contents))
}
continuation.onTermination = { _ in watcher.cancel() }
}
}

private func readSnapshot(at url: URL) throws -> CmuxSettingsFileSnapshot {
guard fileManager.fileExists(atPath: url.path) else {
return CmuxSettingsFileSnapshot(url: url, contents: "")
}
guard let contents = try? String(contentsOf: url, encoding: .utf8) else {
throw CmuxSettingsStoreError.unreadableData(url)
}
return CmuxSettingsFileSnapshot(url: url, contents: contents)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Document the public store API with Swift-DocC comments.

All exported symbols in this new package source file need /// docs (summary + callouts where applicable).

As per coding guidelines: Packages/**/Sources/**/*.swift: “Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment…”.

🤖 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/CmuxSettings/Sources/CmuxSettings/CmuxSettingsStore.swift` around
lines 4 - 76, Add Swift-DocC triple-slash documentation to every public symbol
in this file: CmuxSettingsFileSnapshot (describe purpose and fields url,
contents), CmuxSettingsStoreError (document the unreadableData case and when it
is thrown), CmuxSettingsStore (summary of the actor’s responsibility and
threading/Sendable behavior) and each public method:
init(primaryURL:fallbackURLs:fileManager:), readActiveSnapshot(),
readPrimarySnapshot(), writePrimaryContents(_:), primaryChanges(),
fileChanges(at:). For each method include a brief summary, parameters, return
value, and documented errors/behavior (e.g., when
CmuxSettingsStoreError.unreadableData is thrown, that fileChanges returns an
AsyncStream of CmuxSettingsFileSnapshot, and that primaryChanges is
nonisolated). Keep comments concise and use triple-slash (///) Swift-DocC style
directly above each public declaration.

Comment on lines +57 to +64
public nonisolated func fileChanges(at url: URL) -> AsyncStream<CmuxSettingsFileSnapshot> {
AsyncStream { continuation in
let watcher = CmuxSettingsFileWatcher(url: url) {
guard let contents = try? String(contentsOf: url, encoding: .utf8) else { return }
continuation.yield(CmuxSettingsFileSnapshot(url: url, contents: contents))
}
continuation.onTermination = { _ in watcher.cancel() }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the watcher implementation and the store method
rg -n "class CmuxSettingsFileWatcher|struct CmuxSettingsFileWatcher|CmuxSettingsFileWatcher" -S Packages/CmuxSettings/Sources/CmuxSettings || true
rg -n "nonisolated func fileChanges\\(at url: URL\\)" -S Packages/CmuxSettings/Sources/CmuxSettings || true

# Show the cited regions
sed -n '1,140p' Packages/CmuxSettings/Sources/CmuxSettings/CmuxSettingsStore.swift | cat -n

# If the watcher is in another file, print that too
WATCHER_FILE="$(rg -l "CmuxSettingsFileWatcher" Packages/CmuxSettings/Sources/CmuxSettings | head -n 20)"
echo "Watcher files:"
echo "$WATCHER_FILE"
for f in $WATCHER_FILE; do
  echo "---- $f ----"
  # Avoid huge output: print first ~220 lines or until match region
  sed -n '1,220p' "$f" | cat -n
done

# Also inspect around lines mentioned "Also applies to: 90-111"
# (These are within the same file; we already printed to 140 with line numbers.)

Repository: manaflow-ai/cmux

Length of output: 10504


Fix CmuxSettingsStore fileChanges watcher to emit cleared/created states (missing-at-subscription + delete/rename)

  • CmuxSettingsFileWatcher returns immediately when open(url.path, O_EVTONLY) fails, so create/recreate after subscription produces no updates.
  • For .delete/.rename events, the handler runs but the try? String(contentsOf:) + guard drops the event, so consumers never receive the “missing/cleared” snapshot (unlike readSnapshot, which returns contents: "" when absent).
  • Update the watcher to observe the parent directory and (re)arm or retry reading on create/rename/delete, yielding an empty snapshot when the file is missing.
Suggested direction
- let descriptor = open(url.path, O_EVTONLY)
+ // Watch parent directory when file may not exist yet, and (re)arm file-specific watch
+ // after create/rename. Emit an empty snapshot when file is missing/deleted.
🤖 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/CmuxSettings/Sources/CmuxSettings/CmuxSettingsStore.swift` around
lines 57 - 64, The fileChanges watcher currently ignores missing or deleted
files and fails to notify subscribers on create/rename because
CmuxSettingsFileWatcher aborts if open(url.path, O_EVTONLY) fails and the
closure drops events when String(contentsOf:) fails; update
CmuxSettingsStore.fileChanges to watch the parent directory (not just the file)
via CmuxSettingsFileWatcher, emit an initial CmuxSettingsFileSnapshot reflecting
the current readSnapshot (empty contents when missing), and in the watch
callback attempt to read the file and on failure (file not found) yield a
CmuxSettingsFileSnapshot(url: url, contents: "") so create/rename/delete events
produce an empty/cleared snapshot; also make the watcher re-arm or retry opening
when the initial open fails so post-subscription creates trigger updates (keep
continuation.onTermination to call watcher.cancel()).

Comment on lines +1 to +19
import XCTest
@testable import CmuxSettings

final class CmuxSettingsCatalogTests: XCTestCase {
func testSupportedJSONPathsContainCurrentSettingsSurface() {
XCTAssertTrue(CmuxSettingsCatalog.supportedJSONPaths.contains("app.appearance"))
XCTAssertTrue(CmuxSettingsCatalog.supportedJSONPaths.contains("terminal.autoResumeAgentSessions"))
XCTAssertTrue(CmuxSettingsCatalog.supportedJSONPaths.contains("browser.defaultSearchEngine"))
XCTAssertTrue(CmuxSettingsCatalog.supportedJSONPaths.contains("shortcuts.bindings"))
}

func testDefaultPrimaryURLUsesCmuxJSON() {
let home = URL(fileURLWithPath: "/tmp/cmux-settings-home", isDirectory: true)
XCTAssertEqual(
CmuxSettingsCatalog.defaultPrimaryURL(homeDirectoryURL: home).path,
"/tmp/cmux-settings-home/.config/cmux/cmux.json"
)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsCatalogTests.swift"

echo "=== File exists? ==="
ls -la "$FILE" || true

echo "=== First 120 lines of file ==="
sed -n '1,120p' "$FILE" | cat -n

echo "=== Search for XCTest usage in Packages/CmuxSettings/Tests ==="
rg -n --hidden --glob 'Packages/CmuxSettings/Tests/**/*.swift' 'import XCTest|XCTestCase|XCTAssert' || true

echo "=== Search for Swift Testing usage in Packages/CmuxSettings/Tests ==="
rg -n --hidden --glob 'Packages/CmuxSettings/Tests/**/*.swift' 'import Testing|`@Suite`|`@Test`|`#expect`|`#require`' || true

echo "=== Locate review-bot rules for Swift Testing guidance ==="
ls -la .github/review-bot-rules || true
rg -n --hidden 'Swift Testing framework|import Testing|`@Suite`|`@Test`|`#expect`|`#require`' .github/review-bot-rules || true

Repository: manaflow-ai/cmux

Length of output: 4406


Migrate package tests from XCTest to Swift Testing

Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsCatalogTests.swift still uses import XCTest / XCTestCase and XCTAssert* APIs; switch it to Swift Testing (import Testing, @Suite, @Test, #expect, try #require``). The same issue exists in Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsStoreTests.swift.

🧰 Tools
🪛 SwiftLint (0.63.2)

[Warning] 4-4: Classes should have an explicit deinit method

(required_deinit)

🤖 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/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsCatalogTests.swift`
around lines 1 - 19, Replace XCTest usage with Swift Testing: change `import
XCTest` to `import Testing`, mark the test container `CmuxSettingsCatalogTests`
with `@Suite` and annotate each test function
(`testSupportedJSONPathsContainCurrentSettingsSurface` and
`testDefaultPrimaryURLUsesCmuxJSON`) with `@Test`; replace
`XCTAssertTrue(CmuxSettingsCatalog.supportedJSONPaths.contains(...))` with `try
`#expect`(CmuxSettingsCatalog.supportedJSONPaths.contains(...)).toBeTrue()` and
replace `XCTAssertEqual(CmuxSettingsCatalog.defaultPrimaryURL(homeDirectoryURL:
home).path, "...")` with `try
`#expect`(CmuxSettingsCatalog.defaultPrimaryURL(homeDirectoryURL:
home).path).toEqual("...")`; apply the same changes for the other file
`CmuxSettingsStoreTests.swift` (import, `@Suite/`@Test annotations, and replace
XCTAssert* with `try `#expect``/`try `#require`` as appropriate).

Comment on lines +1 to +33
import XCTest
@testable import CmuxSettings

final class CmuxSettingsStoreTests: XCTestCase {
func testWriteAndReadPrimarySnapshot() async throws {
let directory = FileManager.default.temporaryDirectory
.appendingPathComponent("cmux-settings-\(UUID().uuidString)", isDirectory: true)
let primaryURL = directory.appendingPathComponent("cmux.json", isDirectory: false)
let store = CmuxSettingsStore(primaryURL: primaryURL, fallbackURLs: [])

try await store.writePrimaryContents("{\"schemaVersion\":1}")
let snapshot = try await store.readPrimarySnapshot()

XCTAssertEqual(snapshot.url, primaryURL)
XCTAssertEqual(snapshot.contents, "{\"schemaVersion\":1}")
}

func testActiveSnapshotFallsBackWhenPrimaryIsMissing() async throws {
let directory = FileManager.default.temporaryDirectory
.appendingPathComponent("cmux-settings-\(UUID().uuidString)", isDirectory: true)
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)

let primaryURL = directory.appendingPathComponent("cmux.json", isDirectory: false)
let fallbackURL = directory.appendingPathComponent("settings.json", isDirectory: false)
try "{\"legacy\":true}".write(to: fallbackURL, atomically: true, encoding: .utf8)

let store = CmuxSettingsStore(primaryURL: primaryURL, fallbackURLs: [fallbackURL])
let snapshot = try await store.readActiveSnapshot()

XCTAssertEqual(snapshot.url, fallbackURL)
XCTAssertEqual(snapshot.contents, "{\"legacy\":true}")
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsStoreTests.swift"
echo "=== File: $FILE ==="
if [ -f "$FILE" ]; then
  wc -l "$FILE"
  sed -n '1,200p' "$FILE" | cat -n
else
  echo "Missing: $FILE"
  exit 1
fi

echo
echo "=== Search for Swift Testing usage in Packages/CmuxSettings/Tests ==="
rg -n --hidden --no-ignore-vcs "import Testing|`#expect`\\(|`@Test`|`@Suite`" Packages/CmuxSettings/Tests || true

echo
echo "=== Search for XCTest usage in Packages/CmuxSettings/Tests ==="
rg -n --hidden --no-ignore-vcs "import XCTest|XCTestCase|XCTAssert" Packages/CmuxSettings/Tests || true

echo
echo "=== Search for Swift Testing usage across repo tests (quick check) ==="
rg -n --hidden --no-ignore-vcs "import Testing" Packages/**/Tests/**/*.swift | head -n 50 || true

Repository: manaflow-ai/cmux

Length of output: 5164


Replace XCTest with Swift Testing in CmuxSettings package tests

Packages/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsStoreTests.swift uses import XCTest, subclasses XCTestCase, and calls XCTAssertEqual. Update it to Swift Testing (import Testing, @Test/@Suite, and #expect(...)).

🧰 Tools
🪛 SwiftLint (0.63.2)

[Warning] 4-4: Classes should have an explicit deinit method

(required_deinit)

🤖 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/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingsStoreTests.swift`
around lines 1 - 33, Tests currently use XCTest APIs; replace XCTest with the
project's Swift Testing style by changing import XCTest to import Testing,
convert the CmuxSettingsStoreTests XCTestCase subclass into a `@Suite` (or
top-level struct/class per project convention) and convert each test method
(testWriteAndReadPrimarySnapshot,
testActiveSnapshotFallsBackWhenPrimaryIsMissing) into `@Test` functions that use
`#expect`(...) assertions instead of XCTAssertEqual; ensure async/throws
signatures are preserved and that CmuxSettingsStore, writePrimaryContents,
readPrimarySnapshot, and readActiveSnapshot are invoked the same way, and update
assertion calls to `#expect`(snapshot.url).toBe(primaryURL) and
`#expect`(snapshot.contents).toBe(...) (or equivalent `#expect` syntax used in the
codebase).

Comment on lines +5 to +46
public struct CmuxSettingsJSONPathModel: Identifiable, Equatable, Sendable {
public var id: String { path }
public let path: String
public let section: String

public init(descriptor: CmuxSettingsJSONPathDescriptor) {
path = descriptor.path
section = descriptor.section
}
}

public enum CmuxSettingsJSONPathList {
public static var all: [CmuxSettingsJSONPathModel] {
CmuxSettingsCatalog.supportedJSONPathDescriptors
.sorted { $0.path < $1.path }
.map(CmuxSettingsJSONPathModel.init(descriptor:))
}

public static func contains(_ path: String) -> Bool {
CmuxSettingsCatalog.supportedJSONPaths.contains(path)
}
}

public struct CmuxSettingsJSONPathListView: View {
private let paths: [CmuxSettingsJSONPathModel]

public init(paths: [CmuxSettingsJSONPathModel] = CmuxSettingsJSONPathList.all) {
self.paths = paths
}

public var body: some View {
List(paths) { path in
VStack(alignment: .leading, spacing: 2) {
Text(verbatim: path.path)
.font(.system(.body, design: .monospaced))
Text(verbatim: path.section)
.font(.caption)
.foregroundStyle(.secondary)
}
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add Swift-DocC comments to all public symbols in this package source.

The new public model/list/view API is currently undocumented.

As per coding guidelines: Packages/**/Sources/**/*.swift: “Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment…”.

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsJSONPathModel.swift`
around lines 5 - 46, Add Swift-DocC triple‑slash comments for every public
symbol in this file: document CmuxSettingsJSONPathModel (describe the model),
its public properties id, path, section and the initializer init(descriptor:
CmuxSettingsJSONPathDescriptor); document CmuxSettingsJSONPathList and its
static members all and contains(_:); and document CmuxSettingsJSONPathListView
plus its public init(paths:) and body. For each comment include a brief summary
sentence and where appropriate a Parameters/Returns note that references the
parameter names (e.g., descriptor, path, paths). Ensure all comments use ///
Swift-DocC style immediately above the symbol declarations.

Comment on lines +1 to +16
import XCTest
@testable import CmuxSettingsUI

final class CmuxSettingsJSONPathModelTests: XCTestCase {
func testPathModelsAreSortedAndSectioned() {
let paths = CmuxSettingsJSONPathList.all

XCTAssertEqual(paths.map(\.path), paths.map(\.path).sorted())
XCTAssertEqual(
CmuxSettingsJSONPathModel(
descriptor: .init(path: "terminal.showScrollBar")
).section,
"terminal"
)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift"
echo "== Exists? =="
ls -la "$FILE" || exit 1
echo
echo "== Lines (1-200) =="
nl -ba "$FILE" | sed -n '1,200p'

Repository: manaflow-ai/cmux

Length of output: 291


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift"
echo "== Content (1-200) =="
cat -n "$FILE" | sed -n '1,200p'

Repository: manaflow-ai/cmux

Length of output: 660


Convert this package test to Swift Testing (remove XCTest)

Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift imports XCTest, subclasses XCTestCase, and uses XCTAssertEqual. Switch to import Testing with @Suite/@Test and replace assertions with #expect(...).

🧰 Tools
🪛 SwiftLint (0.63.2)

[Warning] 4-4: Classes should have an explicit deinit method

(required_deinit)

🤖 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/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift`
around lines 1 - 16, Replace the XCTest-based test with Swift Testing: remove
"import XCTest" and instead "import Testing"; convert the final class
CmuxSettingsJSONPathModelTests : XCTestCase into a `@Suite` (e.g., annotate a
struct or enum with `@Suite`) and change the test method
testPathModelsAreSortedAndSectioned into a `@Test` function; replace
XCTAssertEqual assertions with the Swift Testing expectation macro (`#expect`)
comparing values (use
`#expect`(paths.map(\.path)).toEqual(paths.map(\.path).sorted()) and
`#expect`(CmuxSettingsJSONPathModel(descriptor: .init(path:
"terminal.showScrollBar")).section).toEqual("terminal") or the equivalent
`#expect`(...) form); keep references to CmuxSettingsJSONPathList.all and
CmuxSettingsJSONPathModel(descriptor: ...) so the same logic is preserved.

@azooz2003-bit azooz2003-bit changed the title Extract cmux settings package foundation Extract cmux settings into SPM packages May 28, 2026

@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

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsRootView.swift`:
- Around line 3-22: Add Swift-DocC triple-slash comments to all public symbols
in this file: document the CmuxSettingsRootView type with a brief summary and
usage notes, and add /// comments for public members and init parameters
(mention columnVisibility, searchText, minimumSize,
keyboardShortcutActionAliases, consumePendingNavigationTarget, and detail) so
each parameter is described; also document stored SceneStorage properties
selectedSectionRaw and selectedSidebarEntryID if they are intended to be part of
the public API (or mark them fileprivate/private if not) to satisfy the package
guideline requiring every public symbol have a /// summary and any relevant
callouts.

In `@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsCardNote.swift`:
- Around line 3-17: Add Swift-DocC triple-slash comments for the public API of
SettingsCardNote: document the public struct SettingsCardNote with a short
description, document the public property text (what it contains), document the
public init(_ text: String) with a brief "Parameters" note describing the text
argument, and add a short comment for the public var body describing the view
output; ensure all comments use /// style and are placed immediately above the
respective declarations.

In
`@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsLazyLoadHelpers.swift`:
- Around line 3-5: Add Swift-DocC triple-slash documentation for every public
symbol added in SettingsLazyLoadHelpers.swift — e.g., document the public enum
SettingsScrollCoordinateSpace and its static let name, and likewise add ///
comments for all other public helpers shown in the file (the public types,
functions, and properties between the indicated ranges such as the symbols
around lines 7–10, 12–21, 23–38, and 40–43). For each symbol include a brief
one-line summary and, where helpful, a short parameter/return description for
public functions so the docs satisfy the package guideline that every public API
under Packages/**/Sources/** is documented at creation.

In `@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigation.swift`:
- Around line 3-559: Add Swift-DocC triple-slash comments to every public symbol
introduced in this file: summarize each type and its purpose for
SettingsNavigationTarget, SettingsNavigationRequest (document
post(_:anchorID:highlight:)), SettingsNavigationDestination,
SettingsSearchHighlightState, the EnvironmentValues extension
(settingsSearchHighlightState), the View extension helpers
(settingsSearchAnchor(_:), settingsSearchAnchors(_:)), SettingsSearchEntry, and
the SettingsSearchIndex API (document public constants and functions such as
defaultSelectionID, entries(matching:), entry(withID:), sectionEntry(for:),
sectionID(_:), settingID(_:idSuffix:), anchorID(forSettingsPath:), and
normalized(_:)), providing a one-line summary for types, and for
functions/methods include parameter and return descriptions (and any
error/behavior notes) using /// - Parameters: and /// - Returns: where
applicable so the public API is fully DocC-documented.

In `@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchAliases.swift`:
- Around line 1-41: Add Swift-DocC triple‑slash comments for every public symbol
in this file: document the enum SettingsSearchAliasIndex, the nonisolated static
var keyboardShortcutActionAliasesProvider, the static method
sectionAliases(for:) and the static method aliases(target:idSuffix:). For each
comment include a one‑sentence summary of purpose, parameters (for
sectionAliases(for:) and aliases(target:idSuffix:)), and the return value;
ensure visibility and behavior notes (e.g.,
keyboardShortcutActionAliasesProvider is a replaceable provider) are included so
the public API is fully documented per package guidelines.
🪄 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: d6c776cf-ea77-44f5-9421-0ae1873e0ac5

📥 Commits

Reviewing files that changed from the base of the PR and between 6cbe5b5 and 2b5bc68.

📒 Files selected for processing (11)
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsRootView.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsCardNote.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsLazyLoadHelpers.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigation.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchAliases.swift
  • Sources/SettingsCardNote.swift
  • Sources/SettingsLazyLoadHelpers.swift
  • Sources/SettingsNavigation.swift
  • Sources/SettingsSearchAliases.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj

Comment on lines +3 to +22
public struct CmuxSettingsRootView<Detail: View>: View {
@Binding private var columnVisibility: NavigationSplitViewVisibility
@Binding private var searchText: String

private let minimumSize: CGSize
private let keyboardShortcutActionAliases: () -> String
private let consumePendingNavigationTarget: () -> SettingsNavigationTarget?
private let detail: () -> Detail

@SceneStorage("selectedSettingsSection") private var selectedSectionRaw = SettingsNavigationTarget.account.rawValue
@SceneStorage("selectedSettingsSidebarEntry") private var selectedSidebarEntryID = SettingsSearchIndex.defaultSelectionID

public init(
columnVisibility: Binding<NavigationSplitViewVisibility>,
searchText: Binding<String>,
minimumSize: CGSize,
keyboardShortcutActionAliases: @escaping () -> String = { "" },
consumePendingNavigationTarget: @escaping () -> SettingsNavigationTarget? = { nil },
@ViewBuilder detail: @escaping () -> Detail
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Add Swift-DocC comments for public API in this new package file.

CmuxSettingsRootView and its public members are missing required /// documentation blocks (summary, and callouts where applicable).

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

Also applies to: 51-51

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsRootView.swift`
around lines 3 - 22, Add Swift-DocC triple-slash comments to all public symbols
in this file: document the CmuxSettingsRootView type with a brief summary and
usage notes, and add /// comments for public members and init parameters
(mention columnVisibility, searchText, minimumSize,
keyboardShortcutActionAliases, consumePendingNavigationTarget, and detail) so
each parameter is described; also document stored SceneStorage properties
selectedSectionRaw and selectedSidebarEntryID if they are intended to be part of
the public API (or mark them fileprivate/private if not) to satisfy the package
guideline requiring every public symbol have a /// summary and any relevant
callouts.

Comment on lines +3 to +17
public struct SettingsCardNote: View {
public let text: String

public init(_ text: String) {
self.text = text
}

public var body: some View {
Text(text)
.font(.caption)
.foregroundColor(.secondary)
.padding(.horizontal, 14)
.padding(.vertical, 8)
.frame(maxWidth: .infinity, alignment: .leading)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Public view API needs DocC coverage.

SettingsCardNote public symbols are missing required /// documentation.

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsCardNote.swift` around
lines 3 - 17, Add Swift-DocC triple-slash comments for the public API of
SettingsCardNote: document the public struct SettingsCardNote with a short
description, document the public property text (what it contains), document the
public init(_ text: String) with a brief "Parameters" note describing the text
argument, and add a short comment for the public var body describing the view
output; ensure all comments use /// style and are placed immediately above the
respective declarations.

Comment on lines +3 to +5
public enum SettingsScrollCoordinateSpace {
public static let name = "SettingsScrollCoordinateSpace"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Document all public lazy-load helper symbols with Swift-DocC.

This file adds several public APIs without required /// docs.

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

Also applies to: 7-10, 12-21, 23-38, 40-43

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsLazyLoadHelpers.swift`
around lines 3 - 5, Add Swift-DocC triple-slash documentation for every public
symbol added in SettingsLazyLoadHelpers.swift — e.g., document the public enum
SettingsScrollCoordinateSpace and its static let name, and likewise add ///
comments for all other public helpers shown in the file (the public types,
functions, and properties between the indicated ranges such as the symbols
around lines 7–10, 12–21, 23–38, and 40–43). For each symbol include a brief
one-line summary and, where helpful, a short parameter/return description for
public functions so the docs satisfy the package guideline that every public API
under Packages/**/Sources/** is documented at creation.

Comment on lines +3 to +559
public enum SettingsNavigationTarget: String, CaseIterable, Identifiable, Sendable {
case account
case app
case terminal
case sidebarAppearance
case betaFeatures
case automation
case browser
case browserImport
case globalHotkey
case keyboardShortcuts
case workspaceColors
case settingsJSON
case reset

public var id: Self { self }

public var title: String {
switch self {
case .account:
return String(localized: "settings.section.account", defaultValue: "Account")
case .app:
return String(localized: "settings.section.app", defaultValue: "App")
case .terminal:
return String(localized: "settings.section.terminal", defaultValue: "Terminal")
case .workspaceColors:
return String(localized: "settings.section.workspaceColors", defaultValue: "Workspace Colors")
case .sidebarAppearance:
return String(localized: "settings.section.sidebarAppearance", defaultValue: "Sidebar")
case .betaFeatures:
return String(localized: "settings.section.betaFeatures", defaultValue: "Beta Features")
case .automation:
return String(localized: "settings.section.automation", defaultValue: "Automation")
case .browser:
return String(localized: "settings.section.browser", defaultValue: "Browser")
case .browserImport:
return String(localized: "settings.browser.import", defaultValue: "Import Browser Data")
case .globalHotkey:
return String(localized: "settings.section.globalHotkey", defaultValue: "Global Hotkey")
case .keyboardShortcuts:
return String(localized: "settings.section.keyboardShortcuts", defaultValue: "Keyboard Shortcuts")
case .settingsJSON:
return String(localized: "settings.section.settingsJSON", defaultValue: "cmux.json")
case .reset:
return String(localized: "settings.section.reset", defaultValue: "Reset")
}
}

public var symbolName: String {
switch self {
case .account:
return "person.crop.circle"
case .app:
return "gearshape"
case .terminal:
return "terminal"
case .workspaceColors:
return "paintpalette"
case .sidebarAppearance:
return "sidebar.left"
case .betaFeatures:
return "exclamationmark.triangle"
case .automation:
return "wand.and.sparkles"
case .browser:
return "globe"
case .browserImport:
return "square.and.arrow.down"
case .globalHotkey:
return "keyboard.badge.ellipsis"
case .keyboardShortcuts:
return "keyboard"
case .settingsJSON:
return "doc.text"
case .reset:
return "arrow.counterclockwise"
}
}

public var searchText: String {
switch self {
case .account:
return "\(title) sign in team sync"
case .app:
return "\(title) appearance language workspace notifications menu bar telemetry"
case .terminal:
return "\(title) scrollbar auto resume restore reopen relaunch quit sessions agents claude codex opencode rovodev hibernation idle suspend commands approvals prefixes toggle"
case .workspaceColors:
return "\(title) palette tabs"
case .sidebarAppearance:
return "\(title) sidebar details branches badges material terminal background"
case .betaFeatures:
return "\(title) beta experimental unstable feed dock right sidebar"
case .automation:
return "\(title) socket integrations hooks ports claude cursor gemini"
case .browser:
return "\(title) search engine links history theme"
case .browserImport:
return "\(title) browser import data bookmarks history cookies"
case .globalHotkey:
return "\(title) system wide shortcut"
case .keyboardShortcuts:
return "\(title) keybindings commands chords"
case .settingsJSON:
return "\(title) config file preferences editor documentation schema jsonc reload"
case .reset:
return "\(title) defaults"
}
}
}

public enum SettingsNavigationRequest {
public static let notificationName = Notification.Name("cmux.settings.navigate")
private static let targetKey = "target"
private static let anchorKey = "anchor"
private static let highlightKey = "highlight"

public static func post(_ target: SettingsNavigationTarget, anchorID: String? = nil, highlight: Bool = false) {
NotificationCenter.default.post(
name: notificationName,
object: nil,
userInfo: [
targetKey: target.rawValue,
anchorKey: anchorID ?? SettingsSearchIndex.sectionID(for: target),
highlightKey: highlight
]
)
}

public static func target(from notification: Notification) -> SettingsNavigationTarget? {
destination(from: notification)?.target
}

public static func destination(from notification: Notification) -> SettingsNavigationDestination? {
guard
let rawValue = notification.userInfo?[targetKey] as? String,
let target = SettingsNavigationTarget(rawValue: rawValue)
else {
return nil
}
let anchorID = notification.userInfo?[anchorKey] as? String
let shouldHighlight = notification.userInfo?[highlightKey] as? Bool ?? false
return SettingsNavigationDestination(
target: target,
anchorID: anchorID ?? SettingsSearchIndex.sectionID(for: target),
shouldHighlight: shouldHighlight
)
}
}

public struct SettingsNavigationDestination: Sendable {
public let target: SettingsNavigationTarget
public let anchorID: String
public let shouldHighlight: Bool

public init(target: SettingsNavigationTarget, anchorID: String, shouldHighlight: Bool) {
self.target = target
self.anchorID = anchorID
self.shouldHighlight = shouldHighlight
}
}

public struct SettingsSearchHighlightState: Equatable, Sendable {
public let anchorID: String?
public let token: Int
public let startedAt: Date?

public init(anchorID: String?, token: Int, startedAt: Date?) {
self.anchorID = anchorID
self.token = token
self.startedAt = startedAt
}
}

private struct SettingsSearchHighlightStateKey: EnvironmentKey {
static let defaultValue = SettingsSearchHighlightState(anchorID: nil, token: 0, startedAt: nil)
}

public extension EnvironmentValues {
var settingsSearchHighlightState: SettingsSearchHighlightState {
get { self[SettingsSearchHighlightStateKey.self] }
set { self[SettingsSearchHighlightStateKey.self] = newValue }
}
}

public extension View {
@ViewBuilder
func settingsSearchAnchor(_ anchorID: String?) -> some View {
if let anchorID {
settingsSearchAnchors([anchorID])
} else {
self
}
}

@ViewBuilder
func settingsSearchAnchors(_ anchorIDs: [String]) -> some View {
let filteredAnchorIDs = anchorIDs.filter { !$0.isEmpty }
if let primaryAnchorID = filteredAnchorIDs.first {
self
.id(primaryAnchorID)
.modifier(SettingsSearchHighlightModifier(anchorIDs: filteredAnchorIDs))
} else {
self
}
}
}

private struct SettingsSearchHighlightModifier: ViewModifier {
@Environment(\.settingsSearchHighlightState) private var highlightState
let anchorIDs: [String]

private func matches(_ state: SettingsSearchHighlightState) -> Bool {
guard let anchorID = state.anchorID else { return false }
return anchorIDs.contains(anchorID)
}

func body(content: Content) -> some View {
content
.background {
if matches(highlightState) {
TimelineView(.animation) { context in
let opacity = highlightOpacity(at: context.date, for: highlightState)
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(Color.accentColor.opacity(opacity * 0.24))
.overlay(
RoundedRectangle(cornerRadius: 8, style: .continuous)
.stroke(Color.accentColor.opacity(opacity), lineWidth: 2.5)
)
.shadow(color: Color.accentColor.opacity(opacity * 0.24), radius: 8, x: 0, y: 0)
}
}
}
}

private func highlightOpacity(at date: Date, for state: SettingsSearchHighlightState) -> Double {
guard matches(state), let startedAt = state.startedAt else { return 0 }
let elapsed = date.timeIntervalSince(startedAt)
if elapsed < 0.14 {
return max(0, min(1, elapsed / 0.14))
}
if elapsed < 5 {
return 1
}
if elapsed < 5.9 {
return max(0, 1 - ((elapsed - 5) / 0.9))
}
return 0
}
}

public enum SettingsSearchEntryKind: Sendable {
case section
case setting
}

public struct SettingsSearchEntry: Identifiable, Sendable {
public let id: String
public let kind: SettingsSearchEntryKind
public let target: SettingsNavigationTarget
public let title: String
public let subtitle: String?
public let symbolName: String
public let normalizedSearchText: String

public init(
id: String,
kind: SettingsSearchEntryKind,
target: SettingsNavigationTarget,
title: String,
subtitle: String?,
symbolName: String,
searchText: String
) {
self.id = id
self.kind = kind
self.target = target
self.title = title
self.subtitle = subtitle
self.symbolName = symbolName
normalizedSearchText = SettingsSearchIndex.normalized("\(title) \(subtitle ?? "") \(searchText)")
}
}

public enum SettingsSearchIndex {
public static let defaultSelectionID = sectionID(for: .account)

private static let sectionEntries: [SettingsSearchEntry] = SettingsNavigationTarget.allCases.map { target in
SettingsSearchEntry(
id: sectionID(for: target),
kind: .section,
target: target,
title: target.title,
subtitle: nil,
symbolName: target.symbolName,
searchText: "\(target.rawValue) \(target.searchText) \(SettingsSearchAliasIndex.sectionAliases(for: target))"
)
}

private static let settingEntries: [SettingsSearchEntry] = [
setting(.account, "account", String(localized: "settings.section.account", defaultValue: "Account"), "sign in login team sync user profile"),
setting(.app, "language", String(localized: "settings.app.language", defaultValue: "Language"), "locale translation japanese english restart"),
setting(.app, "appearance", String(localized: "settings.app.appearance", defaultValue: "Appearance"), "theme light dark system"),
setting(.app, "app-icon", String(localized: "settings.app.appIcon", defaultValue: "App Icon"), "dock icon alternate"),
setting(.app, "new-workspace-placement", String(localized: "settings.app.newWorkspacePlacement", defaultValue: "New Workspace Placement"), "workspace order position"),
setting(.app, "workspace-inherit-working-directory", String(localized: "settings.app.workspaceInheritWorkingDirectory", defaultValue: "Inherit Workspace Working Directory"), "workspace cwd directory current ghostty working-directory"),
setting(.app, "minimal-mode", String(localized: "settings.app.minimalMode", defaultValue: "Minimal Mode"), "presentation compact chrome"),
setting(.app, "keep-workspace-open", String(localized: "settings.app.closeWorkspaceOnLastSurfaceShortcut", defaultValue: "Keep Workspace Open When Closing Last Surface"), "close last surface shortcut"),
setting(.app, "focus-pane-first-click", String(localized: "settings.app.paneFirstClickFocus", defaultValue: "Focus Pane on First Click"), "mouse click focus"),
setting(.app, "file-drops", String(localized: "settings.app.fileDrop.defaultBehavior", defaultValue: "File Drops"), "drag drop files finder path text terminal editor split preview shift"),
setting(.app, "preferred-editor", String(localized: "settings.app.preferredEditor", defaultValue: "Open Files With"), "editor code zed subl cmd click file"),
setting(.app, "supported-file-previews", String(localized: "settings.app.openSupportedFilesInCmux", defaultValue: "Open Supported Files in cmux"), "cmd click file preview pdf image audio video quick look editor"),
setting(.app, "terminal-config", String(localized: "settings.app.configWindow", defaultValue: "Terminal Config"), "ghostty config merged preview"),
setting(.app, "markdown-viewer", String(localized: "settings.app.openMarkdownInCmuxViewer", defaultValue: "Open Markdown in cmux Viewer"), "md markdown viewer"),
setting(.app, "imessage-mode", String(localized: "settings.app.iMessageMode", defaultValue: "iMessage Mode"), "message messages imessage chat prompt prompts submitted message send agent workspace reorder move top"),
setting(.app, "reorder-notification", String(localized: "settings.app.reorderOnNotification", defaultValue: "Reorder on Notification"), "workspace notification order"),
setting(.app, "dock-badge", String(localized: "settings.app.dockBadge", defaultValue: "Dock Badge"), "unread count app icon"),
setting(.app, "menu-bar-only", String(localized: "settings.app.menuBarOnly", defaultValue: "Menu Bar Only"), "dock icon cmd tab"),
setting(.app, "show-menu-bar", String(localized: "settings.app.showInMenuBar", defaultValue: "Show in Menu Bar"), "menu extra status item"),
setting(.app, "unread-pane-ring", String(localized: "settings.notifications.paneRing.title", defaultValue: "Unread Pane Ring"), "notification blue ring pane"),
setting(.app, "pane-flash", String(localized: "settings.notifications.paneFlash.title", defaultValue: "Pane Flash"), "notification flash highlight"),
setting(.app, "desktop-notifications", String(localized: "settings.notifications.desktop", defaultValue: "Desktop Notifications"), "permission alerts test notification"),
setting(.app, "notification-sound", String(localized: "settings.notifications.sound.title", defaultValue: "Notification Sound"), "custom sound alert audio"),
setting(.app, "notification-command", String(localized: "settings.notifications.command", defaultValue: "Notification Command"), "shell command environment variables"),
setting(.app, "telemetry", String(localized: "settings.app.telemetry", defaultValue: "Send anonymous telemetry"), "analytics crash usage"),
setting(.app, "warn-before-quit", String(localized: "settings.app.warnBeforeQuit", defaultValue: "Warn Before Quit"), "cmd q confirmation confirmQuit"),
setting(.app, "warn-before-closing-tab", String(localized: "settings.app.warnBeforeClosingTab", defaultValue: "Warn Before Closing Tab"), "cmd w close tab confirmation"),
setting(
.app,
"warn-before-closing-tab-x-button",
String(localized: "settings.app.warnBeforeClosingTabXButton", defaultValue: "Warn Before Tab Close Button"),
"x button close tab confirmation"
),
setting(
.app,
"hide-tab-close-button",
String(localized: "settings.app.hideTabCloseButton", defaultValue: "Hide Tab Close Button"),
"hide x button close tab"
),
setting(.app, "rename-selects-name", String(localized: "settings.app.renameSelectsName", defaultValue: "Rename Selects Existing Name"), "command palette rename text selection"),
setting(.app, "palette-search-all", String(localized: "settings.app.commandPaletteSearchAllSurfaces", defaultValue: "Command Palette Searches All Surfaces"), "cmd p search terminal browser markdown"),
setting(.terminal, "scrollbar", String(localized: "settings.terminal.scrollBar", defaultValue: "Show Terminal Scroll Bar"), "terminal shell scrollback"),
setting(.terminal, "textbox-max-lines", String(localized: "settings.terminal.textBoxMaxLines", defaultValue: "TextBox Max Lines"), "terminal textbox text box rich input prompt max height lines grow scroll"),
setting(.terminal, "copy-on-select", String(localized: "settings.terminal.copyOnSelect", defaultValue: "Copy on Selection"), "terminal.copyOnSelect clipboard selection mouse double click triple click"),
setting(.terminal, "agent-auto-resume", String(localized: "settings.terminal.agentAutoResume", defaultValue: "Resume Agent Sessions on Reopen"), "terminal.autoResumeAgentSessions auto resume restore reopen relaunch quit sessions agents claude code codex opencode rovo dev rovodev toggle"),
setting(.terminal, "agent-hibernation", String(localized: "settings.terminal.agentHibernation", defaultValue: "Agent Hibernation"), "terminal.agentHibernation idle hibernate suspend background agents claude code codex opencode live terminals"),
setting(.terminal, "resume-commands", String(localized: "settings.terminal.resumeCommands", defaultValue: "Resume Commands"), "surface resume command approvals prefixes auto restore prompt manual tmux hibernation"),
setting(.sidebarAppearance, "match-terminal", String(localized: "settings.sidebarAppearance.matchTerminalBackground", defaultValue: "Match Terminal Background"), "sidebar material transparency"),
setting(.sidebarAppearance, "hide-sidebar-details", String(localized: "settings.app.hideAllSidebarDetails", defaultValue: "Hide All Sidebar Details"), "workspace sidebar compact"),
setting(.sidebarAppearance, "wrap-workspace-titles", String(localized: "settings.app.wrapWorkspaceTitles", defaultValue: "Wrap Workspace Titles in Sidebar"), "workspace title wrap multiline pr pull request"),
setting(.sidebarAppearance, "show-workspace-description", String(localized: "settings.app.showWorkspaceDescription", defaultValue: "Show Workspace Description in Sidebar"), "workspace description notes markdown"),
setting(.sidebarAppearance, "sidebar-branch-layout", String(localized: "settings.app.sidebarBranchLayout", defaultValue: "Sidebar Branch Layout"), "branch directory vertical inline"),
setting(.sidebarAppearance, "stack-branch-directory", String(localized: "settings.app.stackBranchDirectory", defaultValue: "Stack Branch and Directory"), "branch directory cwd path stack two rows separate lines"),
setting(.sidebarAppearance, "path-last-segment-only", String(localized: "settings.app.pathLastSegmentOnly", defaultValue: "Truncate Path From Start"), "cwd path directory truncate last segment basename viewport"),
setting(.sidebarAppearance, "show-notification-message", String(localized: "settings.app.showNotificationMessage", defaultValue: "Show Notification Message in Sidebar"), "workspace latest notification"),
setting(.sidebarAppearance, "show-branch-directory", String(localized: "settings.app.showBranchDirectory", defaultValue: "Show Branch + Directory in Sidebar"), "git cwd path"),
setting(.sidebarAppearance, "show-pull-requests", String(localized: "settings.app.showPullRequests", defaultValue: "Show Pull Requests in Sidebar"), "review pr mr link"),
setting(.sidebarAppearance, "watch-git-status", String(localized: "settings.app.watchGitStatus", defaultValue: "Watch Git Status in Sidebar"), "git status branch watcher index lock"),
setting(.sidebarAppearance, "make-pr-clickable", String(localized: "settings.app.makeSidebarPullRequestClickable", defaultValue: "Make Sidebar PR Clickable"), "pull requests pull request pr mr review clickable links select workspace row"),
setting(.sidebarAppearance, "open-pr-links", String(localized: "settings.app.openSidebarPRLinks", defaultValue: "Open Sidebar PR Links in cmux Browser"), "pull request link browser"),
setting(.sidebarAppearance, "open-port-links", String(localized: "settings.app.openSidebarPortLinks", defaultValue: "Open Sidebar Port Links in cmux Browser"), "port link browser"),
setting(.sidebarAppearance, "show-ssh", String(localized: "settings.app.showSSH", defaultValue: "Show SSH in Sidebar"), "remote target"),
setting(.sidebarAppearance, "show-ports", String(localized: "settings.app.showPorts", defaultValue: "Show Listening Ports in Sidebar"), "localhost port"),
setting(.sidebarAppearance, "show-log", String(localized: "settings.app.showLog", defaultValue: "Show Latest Log in Sidebar"), "status message"),
setting(.sidebarAppearance, "show-progress", String(localized: "settings.app.showProgress", defaultValue: "Show Progress in Sidebar"), "progress bar"),
setting(.sidebarAppearance, "show-metadata", String(localized: "settings.app.showMetadata", defaultValue: "Show Custom Metadata in Sidebar"), "report meta status block"),
setting(.betaFeatures, "dock", String(localized: "settings.betaFeatures.dock", defaultValue: "Dock"), "dock right sidebar terminal controls tui"),
setting(.automation, "socket-mode", String(localized: "settings.automation.socketMode", defaultValue: "Socket Control Mode"), "unix socket api access password auth"),
setting(.automation, "socket-password", String(localized: "settings.automation.socketPassword", defaultValue: "Socket Password"), "socket auth credential"),
setting(.automation, "claude-code", String(localized: "settings.automation.claudeCode", defaultValue: "Claude Code Integration"), "agent hooks notifications"),
setting(.automation, "claude-path", String(localized: "settings.automation.claudeCode.customPath", defaultValue: "Claude Binary Path"), "custom claude executable"),
setting(.automation, "ripgrep-path", String(localized: "settings.automation.ripgrep.customPath", defaultValue: "Ripgrep Binary Path"), "custom ripgrep rg executable find search nix"),
setting(.automation, "subagent-notifications", String(localized: "settings.automation.suppressSubagentNotifications", defaultValue: "Suppress Subagent Notifications"), "nested child agent codex claude hooks notifications"),
setting(.automation, "cursor", String(localized: "settings.automation.cursor", defaultValue: "Cursor Integration"), "agent hooks notifications"),
setting(.automation, "gemini", String(localized: "settings.automation.gemini", defaultValue: "Gemini CLI Integration"), "agent hooks notifications"),
setting(.automation, "port-base", String(localized: "settings.automation.portBase", defaultValue: "Port Base"), "CMUX_PORT start"),
setting(.automation, "port-range", String(localized: "settings.automation.portRange", defaultValue: "Port Range Size"), "CMUX_PORT_END workspace ports"),
setting(.browser, "search-engine", String(localized: "settings.browser.searchEngine", defaultValue: "Default Search Engine"), "address bar query google duckduckgo bing kagi brave startpage perplexity exa yahoo ecosia qwant mojeek wikipedia github baidu yandex custom search provider"),
setting(.browser, "enable-browser", String(localized: "settings.browser.enabled", defaultValue: "Enable cmux Browser"), "webview tabs links"),
setting(.browser, "search-suggestions", String(localized: "settings.browser.searchSuggestions", defaultValue: "Show Search Suggestions"), "browser address bar suggestions"),
setting(.browser, "theme", String(localized: "settings.browser.theme", defaultValue: "Browser Theme"), "web appearance light dark system"),
setting(.browser, "hidden-webview-discard", String(localized: "settings.browser.hiddenWebViewDiscard", defaultValue: "Discard Hidden Browser WebViews"), "memory hidden tabs webview discard unload"),
setting(.browser, "hidden-webview-discard-delay", String(localized: "settings.browser.hiddenWebViewDiscardDelay", defaultValue: "Hidden WebView Discard Delay"), "memory hidden tabs delay seconds discard"),
setting(.browser, "terminal-links", String(localized: "settings.browser.openTerminalLinks", defaultValue: "Open Terminal Links in cmux Browser"), "click links browser"),
setting(.browser, "intercept-open", String(localized: "settings.browser.interceptOpen", defaultValue: "Intercept open http(s) in Terminal"), "open command urls"),
setting(.browser, "host-whitelist", String(localized: "settings.browser.hostWhitelist", defaultValue: "Hosts to Open in Embedded Browser"), "hosts wildcard terminal links"),
setting(.browser, "external-patterns", String(localized: "settings.browser.externalPatterns", defaultValue: "URLs to Always Open Externally"), "regex url rules default browser"),
setting(.browser, "http-allowlist", String(localized: "settings.browser.httpAllowlist", defaultValue: "HTTP Hosts Allowed in Embedded Browser"), "localhost non https warning"),
setting(.browserImport, "import-data", String(localized: "settings.browser.import", defaultValue: "Import Browser Data"), "bookmarks history cookies profiles"),
setting(.browserImport, "import-hint", String(localized: "settings.browser.import.hint.show", defaultValue: "Show import hint on blank browser tabs"), "blank tab browser import"),
setting(.browser, "react-grab", String(localized: "settings.browser.reactGrabVersion", defaultValue: "React Grab Version"), "npm react grab toolbar"),
setting(.browser, "history", String(localized: "settings.browser.history", defaultValue: "Browsing History"), "clear visited suggestions"),
setting(.globalHotkey, "enable-hotkey", String(localized: "settings.globalHotkey.enable", defaultValue: "Enable System-Wide Hotkey"), "global shortcut show hide windows"),
setting(.globalHotkey, "shortcut", String(localized: "settings.section.globalHotkey", defaultValue: "Global Hotkey"), "keyboard recorder command option control"),
setting(.keyboardShortcuts, "shortcut-chords", String(localized: "settings.shortcuts.chords", defaultValue: "Shortcut Chords"), "tmux multi step keybindings"),
setting(.keyboardShortcuts, "reset-defaults", String(localized: "settings.shortcuts.resetDefaults", defaultValue: "Reset Default Shortcuts"), "restore built in builtin defaults keybindings hotkeys chords commands"),
setting(.keyboardShortcuts, "shortcuts", String(localized: "settings.section.keyboardShortcuts", defaultValue: "Keyboard Shortcuts"), "keybindings commands"),
setting(.workspaceColors, "indicator", String(localized: "settings.workspaceColors.indicator", defaultValue: "Workspace Color Indicator"), "tab color indicator"),
setting(.workspaceColors, "selection", String(localized: "settings.workspaceColors.selectionColor", defaultValue: "Selection Highlight"), "selected workspace background"),
setting(.workspaceColors, "badge", String(localized: "settings.workspaceColors.notificationBadgeColor", defaultValue: "Notification Badge"), "unread notification color"),
setting(.workspaceColors, "palette", String(localized: "settings.workspaceColors.resetPalette", defaultValue: "Reset Palette"), "named colors palette"),
setting(.settingsJSON, "open-file", String(localized: "settings.settingsJSON.openFile", defaultValue: "Open cmux.json"), "config json file editor dotfiles"),
setting(.settingsJSON, "documentation", String(localized: "settings.settingsJSON.documentation", defaultValue: "Documentation"), "cmux json schema reference docs"),
setting(.reset, "reset-all", String(localized: "settings.reset.resetAll", defaultValue: "Reset All Settings"), "restore defaults")
]

private static let allEntries = sectionEntries + settingEntries

private static let entriesByID: [String: SettingsSearchEntry] = Dictionary(
uniqueKeysWithValues: allEntries.map { ($0.id, $0) }
)

private static let settingsPathAnchorIDs: [String: String] = [
"rightSidebar.beta.dock.enabled": settingID(for: .betaFeatures, idSuffix: "dock"),
"app.language": settingID(for: .app, idSuffix: "language"),
"app.appearance": settingID(for: .app, idSuffix: "appearance"),
"app.appIcon": settingID(for: .app, idSuffix: "app-icon"),
"app.newWorkspacePlacement": settingID(for: .app, idSuffix: "new-workspace-placement"),
"app.workspaceInheritWorkingDirectory": settingID(for: .app, idSuffix: "workspace-inherit-working-directory"),
"app.minimalMode": settingID(for: .app, idSuffix: "minimal-mode"),
"app.keepWorkspaceOpenWhenClosingLastSurface": settingID(for: .app, idSuffix: "keep-workspace-open"),
"app.focusPaneOnFirstClick": settingID(for: .app, idSuffix: "focus-pane-first-click"),
"fileDrop.defaultBehavior": settingID(for: .app, idSuffix: "file-drops"),
"app.fileDropDefaultBehavior": settingID(for: .app, idSuffix: "file-drops"),
"app.preferredEditor": settingID(for: .app, idSuffix: "preferred-editor"),
"app.openSupportedFilesInCmux": settingID(for: .app, idSuffix: "supported-file-previews"),
"app.openMarkdownInCmuxViewer": settingID(for: .app, idSuffix: "markdown-viewer"),
"app.iMessageMode": settingID(for: .app, idSuffix: "imessage-mode"),
"app.reorderOnNotification": settingID(for: .app, idSuffix: "reorder-notification"),
"notifications.dockBadge": settingID(for: .app, idSuffix: "dock-badge"),
"app.menuBarOnly": settingID(for: .app, idSuffix: "menu-bar-only"),
"notifications.showInMenuBar": settingID(for: .app, idSuffix: "show-menu-bar"),
"notifications.unreadPaneRing": settingID(for: .app, idSuffix: "unread-pane-ring"),
"notifications.paneFlash": settingID(for: .app, idSuffix: "pane-flash"),
"notifications.sound": settingID(for: .app, idSuffix: "notification-sound"),
"notifications.customSoundFilePath": settingID(for: .app, idSuffix: "notification-sound"),
"notifications.command": settingID(for: .app, idSuffix: "notification-command"),
"app.sendAnonymousTelemetry": settingID(for: .app, idSuffix: "telemetry"),
"app.confirmQuit": settingID(for: .app, idSuffix: "warn-before-quit"),
"app.warnBeforeQuit": settingID(for: .app, idSuffix: "warn-before-quit"),
"app.warnBeforeClosingTab": settingID(for: .app, idSuffix: "warn-before-closing-tab"),
"app.warnBeforeClosingTabXButton": settingID(for: .app, idSuffix: "warn-before-closing-tab-x-button"),
"app.hideTabCloseButton": settingID(for: .app, idSuffix: "hide-tab-close-button"),
"app.renameSelectsExistingName": settingID(for: .app, idSuffix: "rename-selects-name"),
"app.commandPaletteSearchesAllSurfaces": settingID(for: .app, idSuffix: "palette-search-all"),
"sidebar.hideAllDetails": settingID(for: .sidebarAppearance, idSuffix: "hide-sidebar-details"),
"sidebar.wrapWorkspaceTitles": settingID(for: .sidebarAppearance, idSuffix: "wrap-workspace-titles"),
"sidebar.showWorkspaceDescription": settingID(for: .sidebarAppearance, idSuffix: "show-workspace-description"),
"sidebar.branchLayout": settingID(for: .sidebarAppearance, idSuffix: "sidebar-branch-layout"),
"sidebar.stackBranchDirectory": settingID(for: .sidebarAppearance, idSuffix: "stack-branch-directory"),
"sidebar.pathLastSegmentOnly": settingID(for: .sidebarAppearance, idSuffix: "path-last-segment-only"),
"sidebar.showNotificationMessage": settingID(for: .sidebarAppearance, idSuffix: "show-notification-message"),
"sidebar.showBranchDirectory": settingID(for: .sidebarAppearance, idSuffix: "show-branch-directory"),
"sidebar.showPullRequests": settingID(for: .sidebarAppearance, idSuffix: "show-pull-requests"),
"sidebar.watchGitStatus": settingID(for: .sidebarAppearance, idSuffix: "watch-git-status"),
"sidebar.makePullRequestsClickable": settingID(for: .sidebarAppearance, idSuffix: "make-pr-clickable"),
"sidebar.openPullRequestLinksInCmuxBrowser": settingID(for: .sidebarAppearance, idSuffix: "open-pr-links"),
"sidebar.openPortLinksInCmuxBrowser": settingID(for: .sidebarAppearance, idSuffix: "open-port-links"),
"sidebar.showSSH": settingID(for: .sidebarAppearance, idSuffix: "show-ssh"),
"sidebar.showPorts": settingID(for: .sidebarAppearance, idSuffix: "show-ports"),
"sidebar.showLog": settingID(for: .sidebarAppearance, idSuffix: "show-log"),
"sidebar.showProgress": settingID(for: .sidebarAppearance, idSuffix: "show-progress"),
"sidebar.showCustomMetadata": settingID(for: .sidebarAppearance, idSuffix: "show-metadata"),
"terminal.showScrollBar": settingID(for: .terminal, idSuffix: "scrollbar"),
"terminal.textBoxMaxLines": settingID(for: .terminal, idSuffix: "textbox-max-lines"),
"terminal.copyOnSelect": settingID(for: .terminal, idSuffix: "copy-on-select"),
"terminal.autoResumeAgentSessions": settingID(for: .terminal, idSuffix: "agent-auto-resume"),
"terminal.agentHibernation.enabled": settingID(for: .terminal, idSuffix: "agent-hibernation"),
"terminal.agentHibernation.idleSeconds": settingID(for: .terminal, idSuffix: "agent-hibernation"),
"terminal.agentHibernation.maxLiveTerminals": settingID(for: .terminal, idSuffix: "agent-hibernation"),
"workspaceColors.indicatorStyle": settingID(for: .workspaceColors, idSuffix: "indicator"),
"workspaceColors.selectionColor": settingID(for: .workspaceColors, idSuffix: "selection"),
"workspaceColors.notificationBadgeColor": settingID(for: .workspaceColors, idSuffix: "badge"),
"sidebarAppearance.matchTerminalBackground": settingID(for: .sidebarAppearance, idSuffix: "match-terminal"),
"automation.socketControlMode": settingID(for: .automation, idSuffix: "socket-mode"),
"automation.socketPassword": settingID(for: .automation, idSuffix: "socket-password"),
"automation.claudeCodeIntegration": settingID(for: .automation, idSuffix: "claude-code"),
"automation.claudeBinaryPath": settingID(for: .automation, idSuffix: "claude-path"),
"automation.ripgrepBinaryPath": settingID(for: .automation, idSuffix: "ripgrep-path"),
"automation.suppressSubagentNotifications": settingID(for: .automation, idSuffix: "subagent-notifications"),
"automation.cursorIntegration": settingID(for: .automation, idSuffix: "cursor"),
"automation.geminiIntegration": settingID(for: .automation, idSuffix: "gemini"),
"automation.portBase": settingID(for: .automation, idSuffix: "port-base"),
"automation.portRange": settingID(for: .automation, idSuffix: "port-range"),
"browser.enabled": settingID(for: .browser, idSuffix: "enable-browser"),
"browser.defaultSearchEngine": settingID(for: .browser, idSuffix: "search-engine"),
"browser.customSearchEngineName": settingID(for: .browser, idSuffix: "search-engine"),
"browser.customSearchEngineURLTemplate": settingID(for: .browser, idSuffix: "search-engine"),
"browser.showSearchSuggestions": settingID(for: .browser, idSuffix: "search-suggestions"),
"browser.theme": settingID(for: .browser, idSuffix: "theme"),
"browser.discardHiddenWebViews": settingID(for: .browser, idSuffix: "hidden-webview-discard"),
"browser.hiddenWebViewDiscardDelaySeconds": settingID(for: .browser, idSuffix: "hidden-webview-discard-delay"),
"browser.openTerminalLinksInCmuxBrowser": settingID(for: .browser, idSuffix: "terminal-links"),
"browser.interceptTerminalOpenCommandInCmuxBrowser": settingID(for: .browser, idSuffix: "intercept-open"),
"browser.hostsToOpenInEmbeddedBrowser": settingID(for: .browser, idSuffix: "host-whitelist"),
"browser.urlsToAlwaysOpenExternally": settingID(for: .browser, idSuffix: "external-patterns"),
"browser.insecureHttpHostsAllowedInEmbeddedBrowser": settingID(for: .browser, idSuffix: "http-allowlist"),
"browser.showImportHintOnBlankTabs": settingID(for: .browserImport, idSuffix: "import-hint"),
"browser.reactGrabVersion": settingID(for: .browser, idSuffix: "react-grab"),
"shortcuts.bindings": settingID(for: .keyboardShortcuts, idSuffix: "shortcuts")
]

public static func entries(matching query: String) -> [SettingsSearchEntry] {
let tokens = normalizedTokens(for: query)
guard !tokens.isEmpty else { return sectionEntries }
return allEntries.filter { entry in
tokens.allSatisfy { token in entry.normalizedSearchText.contains(token) }
}
}

public static func entry(withID id: String) -> SettingsSearchEntry? {
entriesByID[id]
}

public static func sectionEntry(for target: SettingsNavigationTarget) -> SettingsSearchEntry {
entriesByID[sectionID(for: target)] ?? sectionEntries[0]
}

public static func sectionID(for target: SettingsNavigationTarget) -> String { "section:\(target.rawValue)" }
public static func settingID(for target: SettingsNavigationTarget, idSuffix: String) -> String { "setting:\(target.rawValue):\(idSuffix)" }

public static func anchorID(forSettingsPath path: String) -> String? {
settingsPathAnchorIDs[path]
}

public static func normalized(_ text: String) -> String {
text.folding(options: [.caseInsensitive, .diacriticInsensitive], locale: .current)
}

private static func setting(
_ target: SettingsNavigationTarget,
_ idSuffix: String,
_ title: String,
_ searchText: String
) -> SettingsSearchEntry {
SettingsSearchEntry(
id: settingID(for: target, idSuffix: idSuffix),
kind: .setting,
target: target,
title: title,
subtitle: target.title,
symbolName: target.symbolName,
searchText: "\(target.rawValue) \(idSuffix) \(target.searchText) \(searchText) \(SettingsSearchAliasIndex.aliases(target: target, idSuffix: idSuffix))"
)
}

private static func normalizedTokens(for query: String) -> [String] {
normalized(query)
.split { character in
character.unicodeScalars.allSatisfy { scalar in
CharacterSet.whitespacesAndNewlines.contains(scalar)
|| CharacterSet.punctuationCharacters.contains(scalar)
}
}
.map(String.init)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

This new public navigation/search API surface must be DocC-documented.

The file exposes many public symbols without required triple-slash docs. Please add API docs (summary + parameter/returns/throws where relevant) before merge.

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigation.swift`
around lines 3 - 559, Add Swift-DocC triple-slash comments to every public
symbol introduced in this file: summarize each type and its purpose for
SettingsNavigationTarget, SettingsNavigationRequest (document
post(_:anchorID:highlight:)), SettingsNavigationDestination,
SettingsSearchHighlightState, the EnvironmentValues extension
(settingsSearchHighlightState), the View extension helpers
(settingsSearchAnchor(_:), settingsSearchAnchors(_:)), SettingsSearchEntry, and
the SettingsSearchIndex API (document public constants and functions such as
defaultSelectionID, entries(matching:), entry(withID:), sectionEntry(for:),
sectionID(_:), settingID(_:idSuffix:), anchorID(forSettingsPath:), and
normalized(_:)), providing a one-line summary for types, and for
functions/methods include parameter and return descriptions (and any
error/behavior notes) using /// - Parameters: and /// - Returns: where
applicable so the public API is fully DocC-documented.

Comment on lines +1 to +41
public enum SettingsSearchAliasIndex {
public nonisolated(unsafe) static var keyboardShortcutActionAliasesProvider: () -> String = { "" }

public static func sectionAliases(for target: SettingsNavigationTarget) -> String {
switch target {
case .account:
return localized("settings.search.alias.section.account", defaultValue: "auth authentication login logout sign in sign out email user profile team")
case .app:
return localized("settings.search.alias.section.app", defaultValue: "general preferences prefs behavior chrome dock menubar menu bar status notifications telemetry")
case .terminal:
return localized("settings.search.alias.section.terminal", defaultValue: "shell scrollback scrollbar scroll bar ghostty tty pty")
case .sidebarAppearance:
return localized("settings.search.alias.section.sidebarAppearance", defaultValue: "sidebar left rail navigation details branches badges material terminal background")
case .betaFeatures:
return localized("settings.search.alias.section.betaFeatures", defaultValue: "beta experimental unstable preview dock right sidebar")
case .automation:
return localized("settings.search.alias.section.automation", defaultValue: "api cli control socket mcp agents hooks ports")
case .browser:
return localized("settings.search.alias.section.browser", defaultValue: "web webview address bar omnibar links urls embedded default browser")
case .browserImport:
return localized("settings.search.alias.section.browserImport", defaultValue: "chrome safari firefox brave edge arc bookmarks history cookies profiles")
case .globalHotkey:
return localized("settings.search.alias.section.globalHotkey", defaultValue: "system shortcut global keyboard show hide bring forward")
case .keyboardShortcuts:
return localized("settings.search.alias.section.keyboardShortcuts", defaultValue: "keybinds key bindings hotkeys chords accelerators commands")
case .workspaceColors:
return localized("settings.search.alias.section.workspaceColors", defaultValue: "tab colors palette accent badge selected highlight")
case .settingsJSON:
return localized("settings.search.alias.section.settingsJSON", defaultValue: "configuration config file json jsonc dotfile ~/.config schema docs")
case .reset:
return localized("settings.search.alias.section.reset", defaultValue: "factory defaults restore clear preferences")
}
}

public static func aliases(target: SettingsNavigationTarget, idSuffix: String) -> String {
let aliases = settingAliases["\(target.rawValue):\(idSuffix)"] ?? ""
if target == .keyboardShortcuts, idSuffix == "shortcuts" {
return "\(aliases) \(keyboardShortcutActionAliases)"
}
return aliases
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add required Swift-DocC comments to exported alias-index API.

Public declarations in this new package file are undocumented.

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchAliases.swift`
around lines 1 - 41, Add Swift-DocC triple‑slash comments for every public
symbol in this file: document the enum SettingsSearchAliasIndex, the nonisolated
static var keyboardShortcutActionAliasesProvider, the static method
sectionAliases(for:) and the static method aliases(target:idSuffix:). For each
comment include a one‑sentence summary of purpose, parameters (for
sectionAliases(for:) and aliases(target:idSuffix:)), and the return value;
ensure visibility and behavior notes (e.g.,
keyboardShortcutActionAliasesProvider is a replaceable provider) are included so
the public API is fully documented per package guidelines.

Comment on lines +35 to +38
private var sidebarEntries: [SettingsSearchEntry] {
SettingsSearchAliasIndex.keyboardShortcutActionAliasesProvider = keyboardShortcutActionAliases
return SettingsSearchIndex.entries(matching: searchText)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Global state mutation inside SwiftUI body

sidebarEntries is a computed property called directly from body (at the sidebarEntries.isEmpty guard), yet its first statement writes to a shared global: SettingsSearchAliasIndex.keyboardShortcutActionAliasesProvider = keyboardShortcutActionAliases. SwiftUI can call body speculatively during diffing and animation passes, causing this assignment to fire repeatedly and unpredictably. Any reader of keyboardShortcutActionAliasesProvider from a non-main-actor context (e.g., a background search or the static let settingEntries lazy initialiser) races against these writes.

@@ -0,0 +1,149 @@
public enum SettingsSearchAliasIndex {
public nonisolated(unsafe) static var keyboardShortcutActionAliasesProvider: () -> String = { "" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 nonisolated(unsafe) shared mutable closure without actor protection

keyboardShortcutActionAliasesProvider is assigned from the SwiftUI render path (main actor, via sidebarEntries) and read from aliases(target:idSuffix:), which is also called during static let settingEntries lazy initialisation. The nonisolated(unsafe) annotation opts out of all Swift Concurrency data-race protection, meaning a concurrent reader (e.g., if settingEntries triggers from a non-main context) and a body-time writer can race. A @MainActor-isolated stored property or an actor-owned injection point would give the same capability without the unsafe bypass.

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

Caution

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

⚠️ Outside diff range comments (1)
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchIndex.swift (1)

2-3: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Public SettingsSearchIndex API needs Swift-DocC documentation.

Line 2 and Lines 230-257 add public API (defaultSelectionID, query/lookup/id/normalize helpers) without required /// documentation blocks.

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

Also applies to: 230-257

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchIndex.swift`
around lines 2 - 3, Add Swift-DocC triple-slash documentation for every public
symbol introduced in this file: the SettingsSearchIndex enum itself and all
public members such as defaultSelectionID and the public helper functions
referenced in the comment (e.g., sectionID(for:), query/..., lookup/..., id/...,
normalize/...). For each public property/function add a concise /// summary; for
functions include /// - Parameters: and /// - Returns: entries as appropriate
and a short example or discussion if behavior is non-obvious, ensuring every
public declaration has a triple-slash comment per the Packages/**/Sources/**
guideline.
♻️ Duplicate comments (1)
Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift (1)

17-47: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stop adding XCTest-based tests in package test targets; migrate this file to Swift Testing.

Line 17 onward adds more XCTest assertions/helpers in Packages/**/Tests, which violates the package-test standard and compounds existing non-compliance. Convert this file to import Testing, @Suite, @Test, and #expect(...)/try #require(...).

#!/bin/bash
set -euo pipefail

# Verify package tests are using Swift Testing (and not XCTest)
rg -n --type=swift 'import XCTest|:\s*XCTestCase\b|XCTAssert' Packages -g '**/Tests/**/*.swift'

As per coding guidelines: Packages/**/Tests/**/*.swift: "Use Swift Testing framework for all unit and integration tests in packages. Annotate tests with @Test, group with @Suite, assert with #expect(...) and try #require(...). Use import Testing, not import XCTest."

🤖 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/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift`
around lines 17 - 47, Replace the XCTest-based test with Swift Testing: remove
"import XCTest" and add "import Testing", convert the
testKeyboardShortcutAliasesAreInjectedPerSearch() XCTestCase-style test into a
top-level `@Suite` with an `@Test` annotated function, replace XCTAssertFalse/
XCTAssertTrue assertions with `#expect`(...) (and use try `#require`(...) if any
throwing setup is needed), and keep the helper
searchResultIDs(query:keyboardShortcutActionAliases:) (make it top-level or
internal so the test can call it) while still invoking
SettingsSearchIndex.entries(matching:keyboardShortcutActionAliases:) and mapping
.id for assertions; ensure the test uses
`#expect`(searchResultIDs(...).contains(...)).toBeFalse/True semantics per the
Swift Testing matcher style.
🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationRequest.swift`:
- Around line 3-52: Add Swift-DocC triple-slash documentation for all public
symbols introduced here: document SettingsNavigationRequest.notificationName,
the SettingsNavigationRequest.post(_:anchorID:highlight:) method,
SettingsNavigationRequest.target(from:),
SettingsNavigationRequest.destination(from:), and the
SettingsNavigationDestination type including its public properties (target,
anchorID, shouldHighlight) and init. For each symbol add a concise ///
description explaining its purpose, parameters and return value (where
applicable) and any default behavior (e.g., how anchorID is derived and what
highlight means) so the public API meets the package documentation guideline.

In
`@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationTarget.swift`:
- Around line 3-112: Add Swift-DocC triple-slash comments for the public API
introduced here: document the public enum SettingsNavigationTarget with a brief
overview of its purpose, and add /// comments for each public member: the id
property, the title computed property, the symbolName computed property, and the
searchText computed property; ensure each comment is a single-line DocC summary
(optionally follow with a short note if needed) so all public symbols in this
file satisfy the package documentation guideline.

In `@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchEntry.swift`:
- Around line 3-34: Add Swift-DocC triple-slash comments for all public API in
this file: add a /// comment explaining the purpose of the
SettingsSearchEntryKind enum and each case, add a /// comment for the
SettingsSearchEntry struct describing the model, and add /// comments for the
public initializer (documenting parameters) and each public property (id, kind,
target, title, subtitle, symbolName, normalizedSearchText); ensure comments use
Swift-DocC style (///) and include brief descriptions for the initializer
parameters and the meaning of normalizedSearchText so the public API is fully
documented.

In
`@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchHighlight.swift`:
- Around line 3-47: Add Swift-DocC triple-slash comments to each public symbol
so they are documented: document the SettingsSearchHighlightState struct
(describe what anchorID, token, and startedAt represent and their semantics),
the EnvironmentValues.settingsSearchHighlightState property (explain it stores
the current highlight state in the environment), and the View extensions
settingsSearchAnchor(_:) and settingsSearchAnchors(_:) (describe their behavior,
parameters, and effect on the view, e.g., assigning id and applying
SettingsSearchHighlightModifier). Ensure comments use /// and mention
lifetime/usage notes where relevant to meet package documentation guidelines.

---

Outside diff comments:
In `@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchIndex.swift`:
- Around line 2-3: Add Swift-DocC triple-slash documentation for every public
symbol introduced in this file: the SettingsSearchIndex enum itself and all
public members such as defaultSelectionID and the public helper functions
referenced in the comment (e.g., sectionID(for:), query/..., lookup/..., id/...,
normalize/...). For each public property/function add a concise /// summary; for
functions include /// - Parameters: and /// - Returns: entries as appropriate
and a short example or discussion if behavior is non-obvious, ensuring every
public declaration has a triple-slash comment per the Packages/**/Sources/**
guideline.

---

Duplicate comments:
In
`@Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift`:
- Around line 17-47: Replace the XCTest-based test with Swift Testing: remove
"import XCTest" and add "import Testing", convert the
testKeyboardShortcutAliasesAreInjectedPerSearch() XCTestCase-style test into a
top-level `@Suite` with an `@Test` annotated function, replace XCTAssertFalse/
XCTAssertTrue assertions with `#expect`(...) (and use try `#require`(...) if any
throwing setup is needed), and keep the helper
searchResultIDs(query:keyboardShortcutActionAliases:) (make it top-level or
internal so the test can call it) while still invoking
SettingsSearchIndex.entries(matching:keyboardShortcutActionAliases:) and mapping
.id for assertions; ensure the test uses
`#expect`(searchResultIDs(...).contains(...)).toBeFalse/True semantics per the
Swift Testing matcher style.
🪄 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: 32bba8f0-362d-45c7-8bd3-fda3329e21e7

📥 Commits

Reviewing files that changed from the base of the PR and between ca0dfbb and ff6e9eb.

📒 Files selected for processing (8)
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/CmuxSettingsRootView.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationRequest.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationTarget.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchAliases.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchEntry.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchHighlight.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchIndex.swift
  • Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/CmuxSettingsJSONPathModelTests.swift

Comment on lines +3 to +52
public enum SettingsNavigationRequest {
public static let notificationName = Notification.Name("cmux.settings.navigate")
private static let targetKey = "target"
private static let anchorKey = "anchor"
private static let highlightKey = "highlight"

public static func post(_ target: SettingsNavigationTarget, anchorID: String? = nil, highlight: Bool = false) {
NotificationCenter.default.post(
name: notificationName,
object: nil,
userInfo: [
targetKey: target.rawValue,
anchorKey: anchorID ?? SettingsSearchIndex.sectionID(for: target),
highlightKey: highlight
]
)
}

public static func target(from notification: Notification) -> SettingsNavigationTarget? {
destination(from: notification)?.target
}

public static func destination(from notification: Notification) -> SettingsNavigationDestination? {
guard
let rawValue = notification.userInfo?[targetKey] as? String,
let target = SettingsNavigationTarget(rawValue: rawValue)
else {
return nil
}
let anchorID = notification.userInfo?[anchorKey] as? String
let shouldHighlight = notification.userInfo?[highlightKey] as? Bool ?? false
return SettingsNavigationDestination(
target: target,
anchorID: anchorID ?? SettingsSearchIndex.sectionID(for: target),
shouldHighlight: shouldHighlight
)
}
}

public struct SettingsNavigationDestination: Sendable {
public let target: SettingsNavigationTarget
public let anchorID: String
public let shouldHighlight: Bool

public init(target: SettingsNavigationTarget, anchorID: String, shouldHighlight: Bool) {
self.target = target
self.anchorID = anchorID
self.shouldHighlight = shouldHighlight
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Document the public navigation request and destination API with Swift-DocC.

Line 3 and Line 42 introduce public types and members without /// docs (notificationName, post, target(from:), destination(from:), SettingsNavigationDestination properties/init).

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationRequest.swift`
around lines 3 - 52, Add Swift-DocC triple-slash documentation for all public
symbols introduced here: document SettingsNavigationRequest.notificationName,
the SettingsNavigationRequest.post(_:anchorID:highlight:) method,
SettingsNavigationRequest.target(from:),
SettingsNavigationRequest.destination(from:), and the
SettingsNavigationDestination type including its public properties (target,
anchorID, shouldHighlight) and init. For each symbol add a concise ///
description explaining its purpose, parameters and return value (where
applicable) and any default behavior (e.g., how anchorID is derived and what
highlight means) so the public API meets the package documentation guideline.

Comment on lines +3 to +112
public enum SettingsNavigationTarget: String, CaseIterable, Identifiable, Sendable {
case account
case app
case terminal
case sidebarAppearance
case betaFeatures
case automation
case browser
case browserImport
case globalHotkey
case keyboardShortcuts
case workspaceColors
case settingsJSON
case reset

public var id: Self { self }

public var title: String {
switch self {
case .account:
return String(localized: "settings.section.account", defaultValue: "Account")
case .app:
return String(localized: "settings.section.app", defaultValue: "App")
case .terminal:
return String(localized: "settings.section.terminal", defaultValue: "Terminal")
case .workspaceColors:
return String(localized: "settings.section.workspaceColors", defaultValue: "Workspace Colors")
case .sidebarAppearance:
return String(localized: "settings.section.sidebarAppearance", defaultValue: "Sidebar")
case .betaFeatures:
return String(localized: "settings.section.betaFeatures", defaultValue: "Beta Features")
case .automation:
return String(localized: "settings.section.automation", defaultValue: "Automation")
case .browser:
return String(localized: "settings.section.browser", defaultValue: "Browser")
case .browserImport:
return String(localized: "settings.browser.import", defaultValue: "Import Browser Data")
case .globalHotkey:
return String(localized: "settings.section.globalHotkey", defaultValue: "Global Hotkey")
case .keyboardShortcuts:
return String(localized: "settings.section.keyboardShortcuts", defaultValue: "Keyboard Shortcuts")
case .settingsJSON:
return String(localized: "settings.section.settingsJSON", defaultValue: "cmux.json")
case .reset:
return String(localized: "settings.section.reset", defaultValue: "Reset")
}
}

public var symbolName: String {
switch self {
case .account:
return "person.crop.circle"
case .app:
return "gearshape"
case .terminal:
return "terminal"
case .workspaceColors:
return "paintpalette"
case .sidebarAppearance:
return "sidebar.left"
case .betaFeatures:
return "exclamationmark.triangle"
case .automation:
return "wand.and.sparkles"
case .browser:
return "globe"
case .browserImport:
return "square.and.arrow.down"
case .globalHotkey:
return "keyboard.badge.ellipsis"
case .keyboardShortcuts:
return "keyboard"
case .settingsJSON:
return "doc.text"
case .reset:
return "arrow.counterclockwise"
}
}

public var searchText: String {
switch self {
case .account:
return "\(title) sign in team sync"
case .app:
return "\(title) appearance language workspace notifications menu bar telemetry"
case .terminal:
return "\(title) scrollbar auto resume restore reopen relaunch quit sessions agents claude codex opencode rovodev hibernation idle suspend commands approvals prefixes toggle"
case .workspaceColors:
return "\(title) palette tabs"
case .sidebarAppearance:
return "\(title) sidebar details branches badges material terminal background"
case .betaFeatures:
return "\(title) beta experimental unstable feed dock right sidebar"
case .automation:
return "\(title) socket integrations hooks ports claude cursor gemini"
case .browser:
return "\(title) search engine links history theme"
case .browserImport:
return "\(title) browser import data bookmarks history cookies"
case .globalHotkey:
return "\(title) system wide shortcut"
case .keyboardShortcuts:
return "\(title) keybindings commands chords"
case .settingsJSON:
return "\(title) config file preferences editor documentation schema jsonc reload"
case .reset:
return "\(title) defaults"
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add Swift-DocC comments for the public enum and computed properties.

Line 3 and Lines 18-82 expose public API (SettingsNavigationTarget, id, title, symbolName, searchText) without required /// documentation in this new package source file.

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsNavigationTarget.swift`
around lines 3 - 112, Add Swift-DocC triple-slash comments for the public API
introduced here: document the public enum SettingsNavigationTarget with a brief
overview of its purpose, and add /// comments for each public member: the id
property, the title computed property, the symbolName computed property, and the
searchText computed property; ensure each comment is a single-line DocC summary
(optionally follow with a short note if needed) so all public symbols in this
file satisfy the package documentation guideline.

Comment on lines +3 to +34
public enum SettingsSearchEntryKind: Sendable {
case section
case setting
}

public struct SettingsSearchEntry: Identifiable, Sendable {
public let id: String
public let kind: SettingsSearchEntryKind
public let target: SettingsNavigationTarget
public let title: String
public let subtitle: String?
public let symbolName: String
public let normalizedSearchText: String

public init(
id: String,
kind: SettingsSearchEntryKind,
target: SettingsNavigationTarget,
title: String,
subtitle: String?,
symbolName: String,
searchText: String
) {
self.id = id
self.kind = kind
self.target = target
self.title = title
self.subtitle = subtitle
self.symbolName = symbolName
normalizedSearchText = SettingsSearchIndex.normalized("\(title) \(subtitle ?? "") \(searchText)")
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add required Swift-DocC docs for public search entry models.

Lines 3-34 expose public package API (SettingsSearchEntryKind, SettingsSearchEntry, and its initializer/properties) without /// documentation.

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchEntry.swift`
around lines 3 - 34, Add Swift-DocC triple-slash comments for all public API in
this file: add a /// comment explaining the purpose of the
SettingsSearchEntryKind enum and each case, add a /// comment for the
SettingsSearchEntry struct describing the model, and add /// comments for the
public initializer (documenting parameters) and each public property (id, kind,
target, title, subtitle, symbolName, normalizedSearchText); ensure comments use
Swift-DocC style (///) and include brief descriptions for the initializer
parameters and the meaning of normalizedSearchText so the public API is fully
documented.

Comment on lines +3 to +47
public struct SettingsSearchHighlightState: Equatable, Sendable {
public let anchorID: String?
public let token: Int
public let startedAt: Date?

public init(anchorID: String?, token: Int, startedAt: Date?) {
self.anchorID = anchorID
self.token = token
self.startedAt = startedAt
}
}

private struct SettingsSearchHighlightStateKey: EnvironmentKey {
static let defaultValue = SettingsSearchHighlightState(anchorID: nil, token: 0, startedAt: nil)
}

public extension EnvironmentValues {
var settingsSearchHighlightState: SettingsSearchHighlightState {
get { self[SettingsSearchHighlightStateKey.self] }
set { self[SettingsSearchHighlightStateKey.self] = newValue }
}
}

public extension View {
@ViewBuilder
func settingsSearchAnchor(_ anchorID: String?) -> some View {
if let anchorID {
settingsSearchAnchors([anchorID])
} else {
self
}
}

@ViewBuilder
func settingsSearchAnchors(_ anchorIDs: [String]) -> some View {
let filteredAnchorIDs = anchorIDs.filter { !$0.isEmpty }
if let primaryAnchorID = filteredAnchorIDs.first {
self
.id(primaryAnchorID)
.modifier(SettingsSearchHighlightModifier(anchorIDs: filteredAnchorIDs))
} else {
self
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Document public highlight state and view/environment extensions.

Lines 3-47 define public symbols (SettingsSearchHighlightState, EnvironmentValues.settingsSearchHighlightState, settingsSearchAnchor, settingsSearchAnchors) without required Swift-DocC comments.

As per coding guidelines, Packages/**/Sources/**/*.swift: Every public symbol in any new Swift package under Packages/ must be documented with a Swift-DocC triple-slash comment at the time of writing.

🤖 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/CmuxSettingsUI/Sources/CmuxSettingsUI/SettingsSearchHighlight.swift`
around lines 3 - 47, Add Swift-DocC triple-slash comments to each public symbol
so they are documented: document the SettingsSearchHighlightState struct
(describe what anchorID, token, and startedAt represent and their semantics),
the EnvironmentValues.settingsSearchHighlightState property (explain it stores
the current highlight state in the environment), and the View extensions
settingsSearchAnchor(_:) and settingsSearchAnchors(_:) (describe their behavior,
parameters, and effect on the view, e.g., assigning id and applying
SettingsSearchHighlightModifier). Ensure comments use /// and mention
lifetime/usage notes where relevant to meet package documentation guidelines.

This branch was successfully deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant