Skip to content

Add setting actions, setting presets, and cmux config set - #14868

Merged
teamleaderleo merged 35 commits into
manaflow-ai:mainfrom
teamleaderleo:setting-actions
Sep 30, 2026
Merged

teamleaderleo merged 35 commits into
manaflow-ai:mainfrom
teamleaderleo:setting-actions

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

Tools that tweak cmux settings today rewrite ~/.config/cmux/cmux.json with jq or plutil and then call cmux reload-config. That drops comments, can race the Settings window, and skips schema validation. This adds native ways to make those edits.

Setting actions and presets

Two new action types in the actions registry:

{
  "actions": {
    "scroll.cycle":  { "type": "setting", "title": "Cycle Scroll Speed", "path": "terminal.scrollSpeed", "cycle": [1.0, 1.4, 1.8] },
    "editor.wrap":   { "type": "setting", "title": "Toggle Editor Wrap", "path": "fileEditor.wordWrap", "toggle": true },
    "sidebar.quiet": { "type": "settingPreset", "title": "Quiet Sidebar", "preset": "sidebar.quiet", "confirm": true }
  },
  "settingPresets": {
    "sidebar.quiet": { "sidebar": { "showPorts": false, "showPullRequests": false, "showLog": false } }
  }
}
  • A setting action takes a path plus exactly one of set, toggle: true, cycle, or unset: true.
  • toggle and cycle start from the value cmux is using. That's the cmux.json value if the file sets the key; otherwise the value the Settings window stored in UserDefaults; otherwise the schema default. A value that isn't in the cycle list moves to the first entry.
  • unset removes the key from cmux.json, so the Settings window's value (or the default) applies again.
  • A settingPreset action applies settingPresets.<name>, a new global-only top-level key holding a partial cmux.json. Nested objects merge key by key, so a preset only changes the keys it names.
  • These actions work anywhere other actions do: tab bar buttons (by action reference), shortcuts, and the Command Palette. With "confirm": true, cmux asks before saving and shows the equivalent cmux config command.

cmux config get|set|unset|toggle|cycle|preset

cmux config set terminal.scrollSpeed 1.4, cmux config toggle fileEditor.wordWrap, cmux config preset sidebar.quiet, and so on.

  • <value> is parsed as JSON; plain text is stored as a string.
  • get says where the value came from: cmux.json, (set in Settings, not cmux.json), or (default). --json prints path, file, value, configured, source, and default; the write commands print ok, file, and paths.
  • The CLI reads Settings-window values from the enclosing cmux app's defaults domain, the same way it finds that app's socket.
  • The existing sidebar-font-size and surface-tab-bar-font-size keys keep their Ghostty-config behavior.
  • These commands don't need a socket. The running app picks up the change through its file watcher, so there's no new v2 socket method and nothing for the remote relay policy.

One mutation path

The actions and the CLI both call JSONConfigStore.apply(_:liveValues:) in CmuxSettings. JSONConfigStore's internal mutateRoot takes a list of edits computed under the cooperative writer lock, so toggle, cycle, and a preset read and rewrite the same document in one atomic publication. The existing single-path set, reset, and undo go through it unchanged.

Each change is validated before anything is written:

  • The path must be declared by the schema. CmuxConfigSchemaPathLookup in CmuxFoundation walks the embedded schema and also supplies defaults and allowed types.
  • The path must be outside the non-setting sections (actions, commands, ui, settingPresets, ...).
  • The complete result must add no schema issues.

Comments and unrelated keys survive, as with Settings-window writes. Fractions are written as typed (1.4, not the 1.3999999999999999 JSONSerialization prints for a Double), and re-setting the value already stored is a no-op. The validator learned "$ref": "#", so each settingPresets entry validates as a partial cmux.json in cmux config validate and in editors.

Live values. Most settings are stored in UserDefaults and only overridden by cmux.json, so an absent key's "current value" comes from there (CmuxSettingLiveValues). A stored value is only used when it's a scalar of a type the schema allows at that path; lists and maps are often stored as text, so they fall back to the default. Three keys store a different form and have explicit mappings: app.minimalMode (a mode string), app.keepWorkspaceOpenWhenClosingLastSurface (the inverse flag), and terminal.sessionContentMaxWidth (-1 for false). A catalog-wide test fails if another key the resolver accepts stores a default that disagrees with the schema default, so a new transformed key has to get a mapping.

Design choices

  • Trust. A setting action rewrites the global config, so it only runs when declared in the global cmux.json or a pack that config references (the user chose those packs; they inherit its source path). Project configs and project packs can't declare one: the registry drops them and the runner checks the source again before writing. A project config also can't retitle, rebind, or drop the confirm of a global setting action, through an actions override or a tab bar button. Without this, a repository's .cmux/cmux.json could ship a harmless-looking button that sets automation.socketControlMode.
  • confirm is honored on setting and settingPreset actions like other action types. The project-action trust prompt never covers the global config, so this dialog is the only prompt these actions get.
  • Keys containing . (for example a workspaceGroups.byCwd entry for ~/src/app.web) can't be addressed, because paths split on every .; there's deliberately no escaping syntax. Such a path is refused with an error that says so (keyContainsDot) instead of "isn't a cmux setting", when the rejoined key exists in the file or looks like a path. The docs, CLI contract, and cmux-settings skill say this.

If a write is refused or fails, the palette, shortcut, or button shows an alert with the reason, for example an unknown path, a non-boolean toggle, a value outside the schema, or cmux.json that can't be read.

Tests

  • Package (CmuxSettings CmuxSettingChangeTests/CmuxSettingReadingTests, CmuxFoundation CmuxConfigSchemaPathLookupTests): comment and unrelated-key preservation; toggle and cycle from configured, live, and default values; refusals that leave the file byte-identical; preset merge and refusals; dotted keys versus typos; short-form fractions and the no-op re-set; the stored-value mappings; and the catalog-wide identity check.
  • App host (cmuxTests/CmuxConfigSettingActionTests): decoding and round-trip, the global-only registry rule, global packs allowed and project packs dropped, confirm reaching both the palette action and the button, a project config unable to relabel or unconfirm a global setting action, and the confirmation dialog's text.

Verification

  • CI on 5456a4a (run https://github.com/manaflow-ai/cmux/actions/runs/36321836181): macOS compile admission passed; the app-host changed-suites job passed, including CmuxConfigSettingActionTests. In swift-package-tests every suite this PR adds or changes passed ("Setting changes applied through JSONConfigStore", "Setting readings", "cmux.json schema path lookup"). The job failed once on SimulatorWorkerClientReplayTests ("Restart releases held input before replaying camera state…"), a package that only runs here because it depends on CmuxFoundation. That test passed in main's last three CI runs and passed when the job was rerun on the same head, so it's a flake. After the rerun, every check in that run is green. Guards, localization, schema parity, and web checks passed.
  • CI on an earlier head (run https://github.com/manaflow-ai/cmux/actions/runs/36310670056) caught the 1.3999999999999999 serialization through the new command-description tests, and run https://github.com/manaflow-ai/cmux/actions/runs/36318285721 caught the sessionContentMaxWidth sentinel through the catalog test; both are fixed above.
  • Fleet build of 5456a4a: job 0828a893ed7bde939cc6757d, tag pr-14868-setting-actions-v4, bundle cmux DEV pr-14868-setting-actions-v4.app, artifact sha256:6a11b6d38c8af36d2cb24b2bc8fad7a8f0e73f9a0e00bbac82aef11d3571da46. Built with --backend-mode local, because the shared dev backend isn't reachable from this machine; nothing here touches the backend. publish-hq refuses local-backend builds, so there's no HQ link; the zip and receipts are kept locally.
  • Review: two subagent passes (a full review and a pass over the fixes). Fixed from them: toggle/cycle/get ignoring Settings-window values; project overrides of a global setting action; opaque store errors in the alert; keyContainsDot firing on typos; get --json field names; the schema text that said confirm doesn't apply; the transformed UserDefaults keys; and the no-op re-set of fractions.
  • Before merging: GitHub reports a conflict with main in Resources/Localizable.xcstrings that it can't resolve because it doesn't run the repo's .xcstrings merge driver; scripts/merge-main.sh merges it cleanly (it did for this head). Run it right before merge; the catch-up bot skips fork branches.
  • Localization: 12 new macOS strings (7 in the CmuxFoundation catalog, 5 in the app catalog) in all nine required locales (localization_catalog.py check: 0 parity errors). The six custom-commands docs keys are in all 20 web locales.

Dogfood (not run yet)

GUI dogfood on a fleet or cloud Mac was blocked: the cloud-mac lease joins the tailnet as tag:cmux-loader, which this account's ACL can't reach, and no other GUI host is designated. Checks to run on cmux DEV pr-14868-setting-actions-v4.app (or a newer tag for a later head), with the example config above plus a comment in the file:

  1. Add { "action": "editor.wrap" } and { "action": "scroll.cycle" } to ui.surfaceTabBar.buttons. Click each: word wrap flips in an open file editor, and scroll speed steps 1.0 → 1.4 → 1.8 → 1.0 (check with cmux config get terminal.scrollSpeed). The file keeps its comment and other keys, and writes 1.4, not 1.3999999999999999.
  2. Turn word wrap on in Settings (so cmux.json doesn't set it), then run the toggle from the Command Palette: wrap turns off on the first press.
  3. Run Quiet Sidebar from the palette: the confirm dialog shows cmux config preset sidebar.quiet; Cancel changes nothing, Change hides ports, PRs, and the log in the sidebar.
  4. With the tagged app's bundled CLI: cmux config set terminal.scrollSpeed 1.4, get, toggle fileEditor.wordWrap, cycle terminal.scrollSpeed 1 1.4 1.8, preset sidebar.quiet, unset terminal.scrollSpeed. Each updates the running app without a reload. cmux config set terminal.scrollSpeeed 1 and cmux config set actions.x 1 are refused and the file is byte-identical.
  5. Add a project .cmux/cmux.json with a setting action and an override of editor.wrap ("title": "Run Tests", "confirm": false): the project action isn't offered, and the global one keeps its title and confirm.

Screenshots

CI dogfood tour on merged head e82d0862894: run 36742715771.

Command palette showing the setting action and preset

Dark appearance after running the setting action

Command palette showing the setting preset

Light minimal presentation after running the preset

CLI config get and set output

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added configuration actions for setting, toggling, cycling, and unsetting values, plus applying named presets from tab-bar buttons, shortcuts, and the Command Palette.
    • Added matching cmux config commands to read and change settings. Changes are schema-validated, and existing comments and unrelated configuration are preserved.
    • Setting actions can prompt for confirmation before saving.
  • Documentation
    • Updated CLI and custom-action guides with supported operations, presets, and usage limitations.

teamleaderleo and others added 2 commits September 26, 2026 12:08
cmux.json actions can now change settings: "type": "setting" with a
path and one of set, toggle, cycle, or unset, and "type": "settingPreset"
to apply a named partial settings object from the new top-level
settingPresets. `cmux config get|set|unset|toggle|cycle|preset` drive the
same JSONConfigStore.apply path, so every entrypoint validates against
the schema, keeps comments and unrelated keys, and publishes one atomic
write under the cooperative writer lock.

Setting actions only run when the global cmux.json declares them; project
configs and packs can't ship a button that rewrites global settings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- A preset's empty nested object merges nothing instead of replacing
  the whole section; a preset that sets nothing is refused.
- A setting action with no source path fails closed.
- Docs, schema, and comments say packs referenced by the global config
  may declare setting actions (they inherit its source path), and that
  confirm doesn't apply.
- Move the CLI help note below the subcommand list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 7 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: e851afd3-914f-4404-bfcf-771394edfbb7

📥 Commits

Reviewing files that changed from the base of the PR and between b028d06 and 0044788.

⛔ Files ignored due to path filters (1)
  • Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift is excluded by !**/*.generated.*
📒 Files selected for processing (53)
  • CLI/CMUXCLI+Config.swift
  • Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchemaPathLookup.swift
  • Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSemanticValidator.swift
  • Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Resources/Localizable.xcstrings
  • Packages/macOS/CmuxFoundation/Tests/CmuxFoundationTests/CmuxConfigSchemaPathLookupTests.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/AnySettingKey.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/SettingChanges/CmuxSettingChange.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/SettingChanges/CmuxSettingChangeError.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/SettingChanges/CmuxSettingChangePlanner.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/SettingChanges/CmuxSettingLiveValues.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/SettingChanges/CmuxSettingReading.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/SettingChanges/CmuxSettingValue.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Stores/JSONConfigAtomicPublisher.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Stores/JSONConfigMutationReceipt.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Stores/JSONConfigStore.swift
  • Packages/macOS/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingChangeTests.swift
  • Resources/Localizable.xcstrings
  • Sources/AppDelegate.swift
  • Sources/CmuxConfig.swift
  • Sources/CmuxConfigActionDefinition.swift
  • Sources/CmuxConfigExecutor.swift
  • Sources/CmuxSettingActionRunner.swift
  • Sources/ContentView.swift
  • Sources/SurfaceTabBarButtonConfiguration.swift
  • Sources/TabManager.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/CmuxConfigSettingActionTests.swift
  • docs/cli-contract.md
  • dogfood/scenarios/setting-actions-tour.json
  • skills/cmux-settings/SKILL.md
  • web/app/[locale]/(landing)/docs/custom-commands/page.tsx
  • web/data/cmux.schema.json
  • web/messages/ar.json
  • web/messages/bs.json
  • web/messages/da.json
  • web/messages/de.json
  • web/messages/en.json
  • web/messages/es.json
  • web/messages/fr.json
  • web/messages/it.json
  • web/messages/ja.json
  • web/messages/km.json
  • web/messages/ko.json
  • web/messages/no.json
  • web/messages/pl.json
  • web/messages/pt-BR.json
  • web/messages/ru.json
  • web/messages/th.json
  • web/messages/tr.json
  • web/messages/uk.json
  • web/messages/zh-CN.json
  • web/messages/zh-TW.json
📝 Walkthrough

Walkthrough

The change adds setting and preset operations to the configuration store and CLI. It also adds setting actions for global configuration and referenced packs, with optional confirmation. Schema lookup, value conversion, path validation, configuration loading, tests, and documentation support these operations.

Changes

Setting changes and presets

Layer / File(s) Summary
Setting values and schema resolution
Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/*, Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/AnySettingKey.swift, Packages/macOS/CmuxSettings/Sources/CmuxSettings/SettingChanges/CmuxSettingValue.swift, CmuxSettingLiveValues.swift, Packages/macOS/CmuxFoundation/Tests/CmuxFoundationTests/CmuxConfigSchemaPathLookupTests.swift
Adds schema path lookup and JSON setting values. Reads supported live values from UserDefaults and converts them to setting values.
Plan, validate, and persist setting changes
Packages/macOS/CmuxSettings/Sources/CmuxSettings/SettingChanges/*, Packages/macOS/CmuxSettings/Sources/CmuxSettings/Stores/JSONConfigStore.swift, JSONConfigMutationReceipt.swift, Packages/macOS/CmuxSettings/Tests/CmuxSettingsTests/CmuxSettingChangeTests.swift, Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Resources/Localizable.xcstrings
Plans set, unset, toggle, cycle, and preset edits; reports configured, live, and default values; and applies multiple edits with receipts. Tests cover validation, file preservation, and rejected changes.
Declare setting actions and presets
Sources/CmuxConfig.swift, Sources/CmuxConfigActionDefinition.swift, web/data/cmux.schema.json, cmuxTests/CmuxConfigSettingActionTests.swift
Adds action decoding and encoding, named presets, global-source restrictions, and project-override rules. Tests cover action forms, configuration loading, and trust constraints.
Execute setting actions from app surfaces
Sources/CmuxSettingActionRunner.swift, Sources/CmuxConfigExecutor.swift, Sources/Workspace.swift, Sources/TabManager.swift, Sources/SurfaceTabBarButtonConfiguration.swift, Sources/AppDelegate.swift, Sources/ContentView.swift, cmux.xcodeproj/project.pbxproj
Connects setting actions to app execution paths and tab-bar buttons. The runner checks the source, optionally requests confirmation, and applies edits through JSONConfigStore.
Expose and document setting commands
CLI/CMUXCLI+Config.swift, docs/cli-contract.md, skills/cmux-settings/SKILL.md, CHANGELOG.md, dogfood/scenarios/setting-actions-tour.json, web/app/[locale]/(landing)/docs/custom-commands/page.tsx, web/messages/*, Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Resources/Localizable.xcstrings
Adds CLI reads and mutations, command documentation, localized descriptions, and a dogfood scenario for setting actions, presets, and CLI operations.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~50 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant TabBarButton
  participant Workspace
  participant CmuxSettingActionRunner
  participant JSONConfigStore
  participant GlobalConfig as Global cmux.json
  TabBarButton->>Workspace: Select setting action
  Workspace->>CmuxSettingActionRunner: Pass action and configuration metadata
  CmuxSettingActionRunner->>CmuxSettingActionRunner: Check source and request confirmation if needed
  CmuxSettingActionRunner->>JSONConfigStore: Apply setting change
  JSONConfigStore->>GlobalConfig: Validate and write edits
Loading

Suggested reviewers: austinywang, lawrencecchen, azooz2003-bit

Merge Risk: 🔵 Low · up to b028d

The new setting actions and config commands appear sound. The dogfood tour, however, overwrites the global cmux.json of whoever runs it and makes no backup. Add a backup or use an isolated config location in the scenario; this does not affect shipped app behavior.

Security Architecture Review

Security architecture risk: 🔵 Low · up to b028d

Project-controlled menu labels can disguise an existing global setting action. Exploitation requires the user to have configured that action and select the misleading menu entry. Global-source checks, retained confirmation settings, schema validation, and guarded writes limit the impact.

Retained concerns

  • Low · security · observed: Project-owned context-menu entries can replace the displayed title, icon, and tooltip of a global setting action while retaining its trusted execution identity. The presentation mechanism already existed, but this PR extends it to global setting mutations, bypassing the intent of the new global-only retitling protection. A misleading selection can execute a predeclared global mutation; projects cannot invent its mutation payload or suppress its retained confirmation.
Security review details

Security Blast Radius

  • inferred — The directly attackable scope is the user's global configuration through existing globally declared setting or preset actions. A project can reference and disguise such an action, but cannot supply arbitrary mutation payloads through this path. Downstream security exposure depends on the actions the user configured; activation still requires a user selection and honors retained confirmation.

Security Findings and Attack Paths

  • observed — The retained authorization-bypass finding concerns deceptive presentation, not takeover of the mutation definition. An attacker-controlled project menu references a global setting action under misleading metadata; both new-workspace and workspace-group menu paths dispatch the retained action to the shared setting executor. Adding setting mutations gives this pre-existing presentation path a new global-state outcome.

Trust Boundaries and Controls

  • observed — The registry rejects project-declared setting actions and project overrides of existing setting actions. The runner independently requires the standardized action-source path to match the global configuration path and fails closed for a missing source. Cancellation prevents the write, and enabled confirmation displays the retained action title and equivalent configuration command.
  • observed — The new CLI setting mutations write the user's configuration through JSONConfigStore without using the socket-backed reload route. Their effective authority is local file-writing authority; the absence of socket authentication on these operations is not itself evidence of a remote authorization bypass.

Resilience and Maintainability Implications

  • observed — Participating file writers serialize before their authoritative read, and publication checks target identity and source bytes. Post-exchange recovery is ownership-checked; publisher errors invalidate cached state and notify subscribers. These are file-state containment controls, not proof of transactional runtime application or crash recovery.
  • observed — The runner's successful return and onExecuted callback acknowledge initiation, even when confirmation is later cancelled or persistence fails. The inspected consumers perform workspace placement and selection bookkeeping. No security-sensitive completion dependency was established, so this lifecycle distinction is not retained as an additional security concern.

Hardening Proposals

  • proposed — Extend trusted presentation policy to context-menu wrappers for global setting actions: preserve the authoritative action label or provide an unambiguous trusted mutation disclosure that project metadata cannot replace.

Important

Pre-merge checks failed

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

❌ Failed checks (8 errors, 1 inconclusive)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error The diff adds a direct call to the @MainActor-isolated CmuxSettingActionRunner.run from Workspace.executeSurfaceTabBarCommandButton at Sources/Workspace.swift:14903-14912. Workspace and its … Add an explicit MainActor boundary for the complete surface-button handling path. Prefer marking executeSurfaceTabBarCommandButton and its splitTabBar(_:didRequestCustomAction:inPane:) entry point @MainActor when the Bonsplit delegate…
Cmux Swift Blocking Runtime ❌ Error The PR adds production blocking synchronization in CLI/CMUXCLI+Config.swift. runConfigSettingsBlocking starts Task { try await store.apply(...) } and then calls DispatchSemaphore.wait() at lin… Remove the semaphore bridge. Make the config command path async, or use an async completion/continuation-based CLI entry point that keeps the process alive until JSONConfigStore.apply completes. Return the result and errors from that comp…
Cmux Algorithmic Complexity ❌ Error The new batch mutation path rescans the full JSONC document for every preset leaf edit. Packages/macOS/CmuxSettings/Sources/CmuxSettings/Stores/JSONConfigStore.swift:562-572 calls sourceEditor.set… Add a batch JSONC source-edit operation. Parse and index the source once, plan all edit ranges against that snapshot, and apply the non-overlapping replacements in one pass, or group edits by parsed object and rewrite each object once. Keep…
Cmux Swift Concurrency ❌ Error The new Sources/CmuxSettingActionRunner.swift introduces an unstructured fire-and-forget Task for the setting write. CmuxSettingActionRunner.run and apply are synchronous, while apply starts… Make setting-action execution asynchronous and propagate async throws through CmuxSettingActionRunner, CmuxConfigExecutor, and their cmux-owned callers. Await JSONConfigStore.apply and report completion or failure before returning a…
Cmux Swift Logging ❌ Error The PR adds three unguarded NSLog calls in production app code: Sources/CmuxConfig.swift:2670 and :2683 for rejected setting actions, and Sources/CmuxSettingActionRunner.swift:122 for apply fa… Replace the three added NSLog calls with the existing cmux debug log or an os.Logger destination. Use appropriate warning/error levels. Declare any file-scoped logger as nonisolated private let when required by MainActor isolation, an…
Cmux User-Facing Error Privacy ❌ Error The new product CLI and app alert paths can expose a credential. The schema declares automation.socketPassword as a password setting, and the new planner permits the automation section. `cmux conf… Classify credential-bearing settings, including automation.socketPassword, as sensitive. Never print their values in CLI text or JSON output, and do not include them in confirmation alerts. Show only the path and a redacted value or a gen…
Cmux Full Internationalization ❌ Error The PR introduces untranslated production text. Resources/Localizable.xcstrings already supports 20 locales, but the five new settingAction.* entries contain translations for only 9 locales; bs,… Add translated catalog entries for all 20 locales supported by Resources/Localizable.xcstrings for every new settingAction.* key. Route all new CLI usage, help, status, and source-label text through a localized API and matching catalog …
Cmux Architecture Rethink ❌ Error The new CmuxSettingActionRunner adds a mutable static store cache at Sources/CmuxSettingActionRunner.swift:27-28,128-134. Each global path gets a new JSONConfigStore, while the app composition r… Make the app-owned SettingsRuntime.jsonStore the single source of truth for setting actions. Inject that actor, or an action coordinator that owns it, into CmuxSettingActionRunner and thread the dependency through CmuxConfigExecutor a…
Docstring Coverage ❓ Inconclusive Docstring coverage is 27.03% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 111 functions across 22 files. (30 skippe… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (16 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Cloud Persistent Session And Early Input ✅ Passed PASS. The authoritative PR diff changes configuration settings, schema validation, setting actions, and CLI behavior. It adds no Cloud terminal, cmux-tui, PTY, transport, attachment, renderer, or inpu…
Cmux Browser Automation Off-Main ✅ Passed The pull request does not modify Sources/TerminalController.swift or ControlCommandExecutionPolicy.swift, the files covered by the rule. The authoritative diff contains no browser socket commands,…
Cmux Expensive Synchronous Load ✅ Passed The pull request adds no agent-history loader or agent-owned file parsing. The new @MainActor setting-action runner only starts an asynchronous Task and awaits the actor-isolated JSONConfigStore.apply…
Cmux Cache Substitution Correctness ✅ Passed PASS: The diff does not replace an authoritative read with a cached value. New setting mutations and undo use readDocument(at:) under the writer lock, and reading(at:) uses the new `snapshotRoot()…
Cmux No Hacky Sleeps ✅ Passed PASS. The only changed non-Swift source file is the documentation page web/app/[locale]/(landing)/docs/custom-commands/page.tsx; its diff adds rendered documentation and contains no sleeps, timers, …
Cmux Swift @Concurrent ✅ Passed PASS. The diff adds no @concurrent annotations and no new nonisolated async functions. JSONConfigStore.apply and mutateRoot are actor-isolated async methods, so their file and parsing work run…
Cmux Swift Package Boundaries ✅ Passed The diff keeps the setting domain behind existing SwiftPM targets. Schema lookup and validation are in CmuxFoundation, while CmuxSettingChange, live-value resolution, planning, reading, value conversi…
Cmux Swiftpm Lockfiles ✅ Passed PASS: The pull request changes cmux.xcodeproj/project.pbxproj only to add Swift source and test file references. It does not change Xcode SwiftPM package references. No Package.swift, package-loca…
Cmux Swiftui State Layout ✅ Passed The PR does not introduce a prohibited SwiftUI state or layout pattern. The changed SwiftUI-facing files only pass setting presets through existing CmuxConfigStore, ContentView, TabManager, and …
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: The PR does not add or materially change a standalone cmux-owned window. Sources/CmuxSettingActionRunner.swift adds only NSAlert confirmation and failure dialogs, shown as sheets or modal al…
Cmux Source Artifacts ✅ Passed The 54 changed paths are source files, tests, configuration/schema files, localization catalogs, documentation, or a dogfood scenario. No changed path is under a scratch, cache, build, DerivedData, de…
Cmux No Test Or Debug Seam In Production Source ✅ Passed No new test or debug seam appears in changed production Swift sources. The diff adds no DEBUG/TEST-guarded members, no seam-named members such as debug… or …ForTesting, and no visibility-widening …
Title check ✅ Passed The title clearly summarizes the main changes: setting actions, setting presets, and new cmux config commands.
Description check ✅ Passed The description is complete and directly supports review. It explains the problem, behavior, design, trust rules, testing, verification results, localization, documentation, screenshots, and remaining…
Full details: Docstring Coverage

Explanation

Docstring coverage is 27.03% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 111 functions across 22 files. (30 skipped: 27 unsupported, 3 too large.)

Full details: Cmux Swift Actor Isolation

Explanation

The diff adds a direct call to the @MainActor-isolated CmuxSettingActionRunner.run from Workspace.executeSurfaceTabBarCommandButton at Sources/Workspace.swift:14903-14912. Workspace and its BonsplitDelegate callback are not explicitly @MainActor, so this UI-bound path has no actor boundary. This introduces a Swift 6 isolation error and can access the setting-action runner from a non-main context.

Resolution

Add an explicit MainActor boundary for the complete surface-button handling path. Prefer marking executeSurfaceTabBarCommandButton and its splitTabBar(_:didRequestCustomAction:inPane:) entry point @MainActor when the Bonsplit delegate contract permits it. Otherwise enqueue the callback with Task { @MainActor [weak self] in ... } and keep all Workspace state, NSApp/window access, and CmuxSettingActionRunner.run calls inside that hop. Do not read the UI-bound setting configuration before entering the MainActor.

Full details: Cmux Swift Blocking Runtime

Explanation

The PR adds production blocking synchronization in CLI/CMUXCLI+Config.swift. runConfigSettingsBlocking starts Task { try await store.apply(...) } and then calls DispatchSemaphore.wait() at lines 352–363. The new setting-change commands call this helper, so the diff blocks a thread while waiting for async JSONConfigStore work. This is explicitly disallowed by swift-blocking-runtime.md and is not test-only scaffolding.

Resolution

Remove the semaphore bridge. Make the config command path async, or use an async completion/continuation-based CLI entry point that keeps the process alive until JSONConfigStore.apply completes. Return the result and errors from that completion point instead of blocking a thread with DispatchSemaphore.wait().

Full details: Cmux Algorithmic Complexity

Explanation

The new batch mutation path rescans the full JSONC document for every preset leaf edit. Packages/macOS/CmuxSettings/Sources/CmuxSettings/Stores/JSONConfigStore.swift:562-572 calls sourceEditor.set or sourceEditor.remove inside for edit in edits. Each call reparses the source from its root (JSONCPathEditor.swift:30-34, 315-354), so a preset with K edits over a document of size S costs about O(K·S), not one linear pass. Presets can include scalable workspaceGroups.byCwd map entries, so K can reach about 1000 user-owned records. The batch feature introduces this repeated scan; it is not unchanged single-edit debt.

Resolution

Add a batch JSONC source-edit operation. Parse and index the source once, plan all edit ranges against that snapshot, and apply the non-overlapping replacements in one pass, or group edits by parsed object and rewrite each object once. Keep the existing single-edit path for single edits if needed. Add a test or benchmark with about 1000 preset leaf edits to verify linear behavior in document size plus edit count.

Full details: Cmux Swift Concurrency

Explanation

The new Sources/CmuxSettingActionRunner.swift introduces an unstructured fire-and-forget Task for the setting write. CmuxSettingActionRunner.run and apply are synchronous, while apply starts Task { @MainActor ... await store.apply(...) } at lines 112-127. The task is not stored or cancelled, and run returns before the file mutation finishes. CmuxConfigExecutor also calls onExecuted immediately after run returns. The AppKit alert completion handler is an allowed framework boundary, but the mutation task is cmux-owned lifecycle work.

Resolution

Make setting-action execution asynchronous and propagate async throws through CmuxSettingActionRunner, CmuxConfigExecutor, and their cmux-owned callers. Await JSONConfigStore.apply and report completion or failure before returning and invoking onExecuted. If a synchronous UI boundary must remain, store the task handle in an action-lifecycle owner and cancel or await it during replacement and teardown.

Full details: Cmux Swift Logging

Explanation

The PR adds three unguarded NSLog calls in production app code: Sources/CmuxConfig.swift:2670 and :2683 for rejected setting actions, and Sources/CmuxSettingActionRunner.swift:122 for apply failures. The diff confirms these statements are new, and none is inside #if DEBUG. The rule requires unified logging for these runtime diagnostics. The CLI print calls are allowed user-facing command output.

Resolution

Replace the three added NSLog calls with the existing cmux debug log or an os.Logger destination. Use appropriate warning/error levels. Declare any file-scoped logger as nonisolated private let when required by MainActor isolation, and redact dynamic values if they can contain sensitive data.

Full details: Cmux User-Facing Error Privacy

Explanation

The new product CLI and app alert paths can expose a credential. The schema declares automation.socketPassword as a password setting, and the new planner permits the automation section. cmux config get &lt;setting.path&gt; prints reading.effective directly, while mutation output includes value in both text and --json modes. A confirmed setting action also embeds value.jsonText in the confirmation alert. Therefore commands such as cmux config get automation.socketPassword or a setting action for that path can display the socket password to the end user. These paths are introduced by the PR, which expands config get/set from two font-size keys to arbitrary schema-declared settings.

Resolution

Classify credential-bearing settings, including automation.socketPassword, as sensitive. Never print their values in CLI text or JSON output, and do not include them in confirmation alerts. Show only the path and a redacted value or a generic changed status. Keep detailed values and raw errors in sanitized logs only. Add regression tests for config get, config set, --json, and confirmed setting actions using automation.socketPassword.

Full details: Cmux Full Internationalization

Explanation

The PR introduces untranslated production text. Resources/Localizable.xcstrings already supports 20 locales, but the five new settingAction.* entries contain translations for only 9 locales; bs, da, it, km, nb, pl, pt-BR, ru, th, tr, and uk are missing. Sources/CmuxSettingActionRunner.swift uses these entries for confirmation and failure alerts. The new CLI usage, help, and status text in CLI/CMUXCLI+Config.swift is also hard-coded English user-facing Swift text. The web page uses localized next-intl keys for the new custom-command section in all 20 routing locales, but the changed web/data/cmux.schema.json adds English descriptions for actions and settingPresets; the configuration page renders actions.description directly when no descriptionKey exists, so the new action documentation is not locale-specific. The PR also adds an English-only user-facing changelog entry.

Resolution

Add translated catalog entries for all 20 locales supported by Resources/Localizable.xcstrings for every new settingAction.* key. Route all new CLI usage, help, status, and source-label text through a localized API and matching catalog entries, or remove it from the localized user-facing surface. Move the changed schema descriptions to locale-keyed translations such as descriptionKey, and add matching web/messages/ entries for every locale in web/i18n/routing.ts; ensure the new preset description is localized wherever it is rendered. Localize the new changelog content through the project’s locale-specific release-note source, or do not expose it as a user-facing changelog entry.

Full details: Cmux Architecture Rethink

Explanation

The new CmuxSettingActionRunner adds a mutable static store cache at Sources/CmuxSettingActionRunner.swift:27-28,128-134. Each global path gets a new JSONConfigStore, while the app composition root already owns SettingsRuntime.jsonStore for the same ~/.config/cmux/cmux.json (Sources/cmuxApp.swift:191-195). This creates two actor caches and watcher lifecycles for one persisted document. The current writer lock reduces write races, but it does not remove the duplicate ownership or make stale in-memory state unrepresentable. The highest-impact issue is the new cache, not the documented CLI semaphore bridge or the shared runner calls.

Resolution

Make the app-owned SettingsRuntime.jsonStore the single source of truth for setting actions. Inject that actor, or an action coordinator that owns it, into CmuxSettingActionRunner and thread the dependency through CmuxConfigExecutor and the surface-tab-bar path. Remove CmuxSettingActionRunner.stores and store(for:). Keep the CLI bridge process-local, but route its operations through the same persistence abstraction and writer invariant rather than introducing another app-side store owner.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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

❤️ Share

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

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

teamleaderleo and others added 6 commits September 27, 2026 03:24
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631).
Merged by scripts/merge-main.sh: mf/main at b1daa44.

Resolved generated files:
- Resources/Localizable.xcstrings: xcstrings key-level union
- cmux.xcodeproj/project.pbxproj: union of added entries, then normalize-pbxproj.py
- Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift: generate-cmux-config-schema.py, regenerated from the merged schema

Catch-up-previous-head: ba012db
Catch-up-base: b1daa44
A setting or settingPreset action with "confirm": true now asks before
saving and shows the equivalent `cmux config` command. The project-action
trust prompt never covers the global config, so this is the only prompt
these actions get.

A path that only resolves when one of its keys contains "." (for example
a workspaceGroups.byCwd entry for ~/src/app.web) is refused with a
keyContainsDot error that says so, instead of "isn't a cmux setting".
Such keys stay unsupported; there is no escaping syntax. Docs, the CLI
contract, and the cmux-settings skill say so.

Adds a test that packs the global config references may declare setting
actions while a project config's packs may not, and that confirm reaches
both the palette action and the tab bar button.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
JSONSerialization prints a Double with 17 significant digits, so
`cmux config set terminal.scrollSpeed 1.4`, a cycle entry, or a preset
leaf wrote 1.3999999999999999 into cmux.json and the CLI echoed it.
CmuxSettingValue now hands JSONSerialization an NSDecimalNumber built
from Swift's shortest round-trip text, and preset leaves are re-encoded
through CmuxSettingValue so every path writes 1.4.

CI run 36310670056 on e478696 caught this through the new
commandLineDescriptions and confirmationDialogShowsTheEquivalentCommand
tests; this adds a file-text assertion for set and preset.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review fixes:

- Most settings live in UserDefaults, and cmux.json only overrides them.
  toggle, cycle, and get now read a key the file doesn't set from the
  app's UserDefaults (CmuxSettingLiveValues, backed by the setting
  catalog) before the schema default, so the first press after changing
  a setting in the Settings window flips what the user sees. The app
  reads its own defaults; the CLI reads the enclosing app's domain.
  `cmux config get` says where the value came from, and `unset` is
  described as removing the key from cmux.json.
- A project config could override a global setting action's title,
  shortcut, or confirm through an actions entry or a tab bar button.
  Both overrides are now ignored for setting actions unless they come
  from the global config.
- The failure alert falls back to a localized "couldn't read or save
  cmux.json" message for store errors that have no description.
- keyContainsDot only fires when the rejoined key exists in the file or
  looks like a path, so a typo under a map keyed by names stays an
  unknown path.
- `cmux config get --json` uses `path` and `file` like the other
  subcommands, plus `source`.
- The schema no longer says confirm doesn't apply to setting actions.
- The setting-action docs keys are translated into the 18 other web
  locales, and CHANGELOG has a line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Second review pass:

- Some UserDefaults values aren't stored the way cmux.json spells them:
  app.minimalMode is a presentation-mode string, and
  app.keepWorkspaceOpenWhenClosingLastSurface is stored as the opposite
  flag. Lists and maps are often stored as text. The live resolver now
  maps those two explicitly and otherwise accepts only a scalar whose
  type the schema allows at that path (CmuxConfigSchemaPathLookup gains
  declaredTypes(at:)). A catalog-wide test fails if a key the resolver
  accepts stores a default that disagrees with the schema default, so a
  new transformed key has to get a mapping.
- Re-setting a fraction that's already in the file is no longer reported
  as a change: receipts and the no-op check compare numbers in the same
  short form they are written in.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631).
Merged by scripts/merge-main.sh: origin/main at 5c68499.

Resolved generated files:
- Resources/Localizable.xcstrings: xcstrings key-level union

Catch-up-previous-head: 7fb4665
Catch-up-base: 5c68499
@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

CI failure attribution

CI failed on 2cc8f3d8e6 (run 36698504830 attempt 2): 1 code.

Job Verdict Why
macos / macOS compile admission code a compile error
Matched log lines
macos / macOS compile admission: /tmp/cmux-ci/src/Sources/CmuxConfigExecutor.swift:76:34: error: cannot find type 'CmuxSettingValue' in scope

Not re-run automatically: macos / macOS compile admission is not a machine failure.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's.

The catalog test caught terminal.sessionContentMaxWidth: UserDefaults
stores -1 for "no cap", which cmux.json spells false. The live resolver
now maps widths under the minimum to false.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631).
Merged by scripts/merge-main.sh: origin/main at f5c179f.

Catch-up-previous-head: 81bda19
Catch-up-base: f5c179f
@vercel

vercel Bot commented Sep 27, 2026

Copy link
Copy Markdown

Deployment failed for project cmux with the following error:

The provided GitHub repository does not contain the requested branch or commit reference. Please ensure the repository is not empty.

teamleaderleo and others added 2 commits September 27, 2026 06:16
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	CHANGELOG.md
#	Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift
#	cmux.xcodeproj/project.pbxproj
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631).
Merged by scripts/merge-main.sh: origin/main at 478e323.

Resolved conflicts:
- Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Resources/Localizable.xcstrings: xcstrings key-level union
- Resources/Localizable.xcstrings: xcstrings key-level union
- Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift: generate-cmux-config-schema.py, regenerated from the merged schema (both sides changed the schema)

Catch-up-previous-head: 13aaffb
Catch-up-base: 478e323

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@teamleaderleo
teamleaderleo marked this pull request as ready for review September 30, 2026 07:54
@teamleaderleo
teamleaderleo enabled auto-merge (squash) September 30, 2026 07:54
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 30, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

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

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review: Global configuration packs could declare setting presets, but setting actions only passed the action registry to the mutation path, so pack presets failed as unknown presets.

Fixed: Resolved trusted global-pack presets with direct global configuration precedence, passed them through command palette and surface tab actions without persisting pack metadata, and added regression coverage.

Left: No findings.

Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631).
Merged by scripts/merge-main.sh: origin/main at d87c3be, the newest commit with green CI fast guards (2 newer skipped).

Resolved conflicts:
- Resources/Localizable.xcstrings: xcstrings key-level union
- cmux.xcodeproj/project.pbxproj: union of added entries, then normalize-pbxproj.py

Catch-up-previous-head: 97d8ac9
Catch-up-base: d87c3be

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 30, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

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

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

teamleaderleo and others added 3 commits September 30, 2026 11:22
Prefer current global presets, guard symlink retargets during publication, and keep tour cleanup isolated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merge-main commit by scripts/merge-main.sh.
Merged by scripts/merge-main.sh: origin/main at fc3e6e3, the newest commit with green CI fast guards (8 newer skipped).

Merge-main-previous-head: 74c3a5f
Merge-main-base: fc3e6e3
Merge-main commit by scripts/merge-main.sh.
Merged by scripts/merge-main.sh: origin/main at a6c098a.

Resolved conflicts:
- Resources/Localizable.xcstrings: xcstrings key-level union
- cmux.xcodeproj/project.pbxproj: union of added entries, then normalize-pbxproj.py

Merge-main-previous-head: a70f1fb
Merge-main-base: a6c098a
@teamleaderleo
teamleaderleo merged commit 10e78b5 into manaflow-ai:main Sep 30, 2026
21 of 22 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for 0044788624, merged 2026-09-30 19:03:57 UTC

  • Not verified at merge: ci-status (not reported), detect-ios-changes (in progress), Fast static checks (in progress), guest-install (in progress), Testbox broker trust boundary (in progress), Web complexity (in progress), Web complexity candidate (in progress)
  • Verified: browser-skill, catalog-structure, runner, web-validation
  • Skipped by policy: web-build, web-database-tests, web-tests
  • Full suite: runs on main after merge.

Labeled merged-unverified: if main breaks near this merge, look here first.

@github-actions github-actions Bot added the merged-unverified A judging check was not green at merge; see the merge receipt comment label Sep 30, 2026
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

main no longer compiles after this merge

@teamleaderleo: after 10e78b5cf6 landed on main, the app-host test product (the app and cmuxTests, build-for-testing) stops compiling. The compile of the commit before it (a6c098abf2) passed and its own merge commit 10e78b5cf6 fails, so this pull request is the cause (possibly with a semantic conflict against something merged earlier that its own CI did not see).

Evidence: https://github.com/manaflow-ai/cmux/actions/runs/36763044007/job/110050533736

Packages/macOS/CmuxSettings/Sources/CmuxSettings/Stores/JSONConfigAtomicPublisher.swift:74: error: call can throw but is not marked with 'try'
Packages/macOS/CmuxSettings/Sources/CmuxSettings/Stores/JSONConfigStore.swift:601: error: reference to property 'fileURL' in closure requires explicit use of 'self' to make capture semantics explicit

Nothing blocks merging meanwhile. A fix-forward (or, failing that, a revert) is attempted automatically unless an open pull request already fixes this.

main_compile_attribution.py: post-merge, nothing here gates a merge.

austinywang added a commit that referenced this pull request Sep 30, 2026
#14868 merged 74c3a5f after its compile admission failed, so
CmuxSettings, and with it the app, no longer builds on main:

  JSONConfigAtomicPublisher.swift:74: call can throw but is not marked
  with 'try'
  JSONConfigStore.swift:601: reference to property 'fileURL' in closure
  requires explicit use of 'self' to make capture semantics explicit

The post-exchange rollback now uses `if try`, like the publisher's two
other rollback call sites, so a failed rollback still reports
sourceChangedRollbackFailed. The isTargetCurrent closure captures the
store's nonisolated fileURL by value instead of the actor.

Refs #15488

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

Copy link
Copy Markdown
Contributor

@teamleaderleo main doesn't compile since this merge. 74c3a5f's compile admission failed at 19:03:11Z, and the PR merged at 19:03:57Z:

JSONConfigAtomicPublisher.swift:74:16: error: call can throw but is not marked with 'try'
JSONConfigStore.swift:601:63: error: reference to property 'fileURL' in closure requires explicit use of 'self' to make capture semantics explicit

#16094 fixes both, together with the bonsplit pin that #15942 moved back. It adds if try rollbackIfStillOwned(...), matching the other two call sites, and captures [fileURL] in isTargetCurrent.

Separately, CmuxSettingActionRunner.confirmationAlert shows "Apply setting preset \"\(name)\"" as a raw, unlocalized string. The rest of that alert uses String(localized:).

lawrencecchen added a commit that referenced this pull request Sep 30, 2026
#14868 left an untried call to the throwing rollbackIfStillOwned and an
implicit self capture in the isTargetCurrent closure. Xcode 26.6 accepts
both, Xcode 26.3 (the macOS 15 CI lane) rejects both, so every
blacksmith-6vcpu-macos-15 run fails at TEST BUILD.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lawrencecchen added a commit that referenced this pull request Sep 30, 2026
#14868 left an untried call to the throwing rollbackIfStillOwned and an
implicit self capture in the isTargetCurrent closure. Xcode 26.6 accepts
both, Xcode 26.3 (the macOS 15 CI lane) rejects both, so every
blacksmith-6vcpu-macos-15 run fails at TEST BUILD.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
austinywang added a commit that referenced this pull request Sep 30, 2026
main doesn't compile since #13232 (ef75ca7) and #14868 (10e78b5)
merged 13 minutes apart:

  Sources/CmuxConfig.swift:2816:51: error: missing argument for parameter
  'actionReferenceID' in call

#13232 added the required actionReferenceID field to
ResolvedSurfaceTabBarButtonEntry. #14868 added a new return of that
struct for a project button that shows a global setting action, without
the field. That button still shows and runs the referenced action, like
the ordinary resolved path below it, so it reports the same
resolvedIdentifier. Actions & Launchers discovery then lists the action
as placed on the tab bar. The argument shares a line to keep the file
within its length budget.

Refs #15488

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
austinywang added a commit that referenced this pull request Sep 30, 2026
#13232 made `actionReferenceID` a required field of
ResolvedSurfaceTabBarButtonEntry; #14868, merged 13 minutes earlier, added
a return of that entry for a project button showing an untrusted global
setting action. Each compiled against its own base, together they don't:

  Sources/CmuxConfig.swift:2816:51: error: missing argument for parameter
  'actionReferenceID' in call

That branch renders the referenced action itself (its own title and
confirm), so it carries the referenced action's identity, as the normal
resolved branch below it does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 2546c91)
lawrencecchen added a commit that referenced this pull request Sep 30, 2026
#13232 added an exhaustive switch over CmuxSurfaceTabBarButtonAction for
the Actions discovery dialog; #14868 added the .setting case. Each passed
CI alone, and main has failed to compile since both landed (switch must
be exhaustive at AppDelegate+WorkspaceActionSave.swift:126). Setting and
setting-preset actions are now listed with the type "setting".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lawrencecchen added a commit that referenced this pull request Sep 30, 2026
#13232 added an exhaustive switch over CmuxSurfaceTabBarButtonAction for
the Actions discovery dialog; #14868 added the .setting case. Each passed
CI alone, and main has failed to compile since both landed (switch must
be exhaustive at AppDelegate+WorkspaceActionSave.swift:126). Setting and
setting-preset actions are now listed with the type "setting".

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
austinywang pushed a commit that referenced this pull request Sep 30, 2026
#13232 added an exhaustive switch over CmuxSurfaceTabBarButtonAction for
the Actions discovery dialog; #14868 added the .setting case. Each passed
CI alone, and main has failed to compile since both landed (switch must
be exhaustive at AppDelegate+WorkspaceActionSave.swift:126). Setting and
setting-preset actions are now listed with the type "setting".

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit d01e8ce)
austinywang added a commit that referenced this pull request Sep 30, 2026
The second compile error from #13232 and #14868 merging 13 minutes apart,
hidden behind the first:

  Sources/AppDelegate+WorkspaceActionSave.swift:126:9: error: switch must be
  exhaustive

#14868 added CmuxSurfaceTabBarButtonAction.setting, and #13232's
Actions & Launchers summary switched over the enum without it. The
summary's type token follows each action's cmux.json "type", so a
setting preset shows "settingPreset" and any other setting change
"setting". The switch is now one case per line, which keeps the file
within its length budget. Every other exhaustive switch over the enum
already handles .setting.

Refs #15488

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lawrencecchen added a commit that referenced this pull request Sep 30, 2026
…16223)

#14868 added a branch that resolves a project tab-bar button to a global
setting action without relabeling it. #13232 then made
ResolvedSurfaceTabBarButtonEntry require actionReferenceID. The two
merged without a combined build, so main fails with "missing argument
for parameter 'actionReferenceID'". The branch still places a button
that runs the registered action, so it reports that action's id for
Actions discovery like the trusted branch does.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lawrencecchen added a commit that referenced this pull request Sep 30, 2026
#14868 added a branch that resolves a project tab-bar button to a global
setting action without relabeling it. #13232 then made
ResolvedSurfaceTabBarButtonEntry require actionReferenceID. The two
merged without a combined build, so main fails with "missing argument
for parameter 'actionReferenceID'". The branch still places a button
that runs the registered action, so it reports that action's id for
Actions discovery like the trusted branch does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
austinywang added a commit that referenced this pull request Sep 30, 2026
main fixed both compile errors from #13232 and #14868 itself: #16223
passes actionReferenceID on the setting-action trust path, and the
actions discovery summary now handles .setting. Both conflicting files
resolve to main's versions, so this branch no longer changes them.
austinywang added a commit that referenced this pull request Oct 1, 2026
… guard fetch history (#16094)

* fix: pin bonsplit main with the deallocating-window hint fix

main's app-host shards still abort with "objc: Cannot form weak reference
to instance ... of class NSKVONotifying_NSWindow" (shard 3 of #15488
validation run 36732010954 on cmux14). manaflow-ai/bonsplit#261 (bb03f7d)
fixes it, but main pins bd340ad, the hint-pill branch from #15821, which
predates it.

Pin bonsplit main's head, 7e5598e: it merges the hint-pill branch over
bf5f051 (#268) and bb03f7d (#261), so main keeps #15821's bonsplit changes
and gains the fix. The two app edits are #15942's adaptation to the
performance changes that come with bf5f051: read pane tab ids through
tabIds(inPane:), and correct the title-refresh comment now that bonsplit
observes each tab item.

Refs #15488

Co-authored-by: Leo Li <cheerleaderleo@outlook.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: say a title frame wakes only its tab's views

With bonsplit observing each tab item, a title-only refresh no longer
invalidates the whole tab bar subtree; the comment at the call site still
said it did, contradicting the doc comment on refreshTabLabel.

Refs #15488

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

* fix(settings): add the missing try and capture that break main's compile

#14868 merged 74c3a5f after its compile admission failed, so
CmuxSettings, and with it the app, no longer builds on main:

  JSONConfigAtomicPublisher.swift:74: call can throw but is not marked
  with 'try'
  JSONConfigStore.swift:601: reference to property 'fileURL' in closure
  requires explicit use of 'self' to make capture semantics explicit

The post-exchange rollback now uses `if try`, like the publisher's two
other rollback call sites, so a failed rollback still reports
sourceChangedRollbackFailed. The isTargetCurrent closure captures the
store's nonisolated fileURL by value instead of the actor.

Refs #15488

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

* test: expect the cancelled-run message from the tests gate

The same change as #16168 (108bd10), carried here so this PR's Linux
guards pass and its macOS jobs are not declined while main is red. #16150
made the ci.yml tests gate report a cancelled linux-preflight as
"cancelled: linux-preflight"; the test kept the old text.

Refs #15488

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci: let the submodule guard fetch history when GitHub can't answer

The forward-only guard checks submodules out two commits deep. When an
old pin sits deeper than that, it asks the GitHub compare API, which
fails whenever the repository's shared Actions token is out of quota.
The guard then reports "could not determine ancestry". It did so on
every run of this PR (bf5f051 -> 7544622, three commits deep) and of
#15942, although GitHub's compare says behind_by=10, ahead_by=0.

As a last resort after the compare, the guard now fetches the missing
history (commits and trees, no blobs) and decides locally. It never runs
when the local check or GitHub already answered, so passing and
rejected moves keep their current path. A shallow bonsplit clone at
7544622, as CI makes it, now resolves bf5f051 as forward.

Refs #15488

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

* fix(web): apply migrations the way production does everywhere

#15423 added a CREATE INDEX CONCURRENTLY migration and taught the
production migrator (migrate-planetscale.mjs) to run it outside a
transaction. CI, web-validation and local databases still ran
`drizzle-kit migrate`, which wraps every migration in one transaction,
so main's web-db-migrations job fails with
"CREATE INDEX CONCURRENTLY cannot run inside a transaction block", and
`bun run db:migrate` fails for anyone with a fresh local database.

The production migrator's loop moves unchanged into
scripts/cloud-vm/apply-migrations.mjs, and a new scripts/db-migrate.mjs
runs it against DIRECT_DATABASE_URL or DATABASE_URL. Every caller of
`drizzle-kit migrate` now uses it: ci-web, web-validation,
cloud-vm-guest-install, ios-streamed-validate, db-local.sh, and
dev-local.sh through db-local.sh. CI now exercises the code path
production runs.

Checked on a scratch Postgres 14: all 93 migrations apply, a second run
applies none, and cloud_vms_observed_destroy_cleanup_idx is valid.

Refs #15488

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

* fix(web): use the transaction's json helper in the outbox test

main's web typecheck fails since #15423:

  tests/vm-workflows.test.ts(6219,37): error TS18047: 'sql' is possibly 'null'.

The test narrows the file's `let sql` at its start, but TypeScript drops
that narrowing inside the `sql.begin` callback. The insert there now
uses the transaction's own `tx.json`, which is also the connection that
runs the insert.

Refs #15488

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

* Document the French Actions discovery titles as invariant

The same change as #16175 (ee38771), carried so this PR's static
checks pass while main is red. #13232 added actions.discovery.menuTitle
and actions.discovery.dialogTitle, whose French text is identical to the
English, and the localization parity check fails on main.

Refs #15488

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): insert a real JSON null in the malformed cleanup-row test

"Cloud VM database schema > rejects malformed transferred cleanup rows"
(#15423) never ran on main, because main's migrations failed before the
database behavior tests. With migrations fixed it fails:

  expect((insertError)?.code).toBe("23514")
  Expected: "23514"  Received: "23502"

Its first malformed value is `null`, and postgres.js binds
`sql.json(null)` as SQL NULL. The NOT NULL column rejects that (23502)
before the check constraint the test is about. The row under test is a
JSON null document, so that case now inserts `'null'::jsonb`, and the
check rejects it with 23514 like the other nine.

Checked on a scratch Postgres 14 with postgres.js: sql.json(null) gives
23502, the JSON null gives 23514, all ten malformed values give 23514,
and {modelPlane: true} and {homeVolume: "v"} are accepted.

Refs #15488

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

* fix(config): pass actionReferenceID on the setting-action trust path

main doesn't compile since #13232 (ef75ca7) and #14868 (10e78b5)
merged 13 minutes apart:

  Sources/CmuxConfig.swift:2816:51: error: missing argument for parameter
  'actionReferenceID' in call

#13232 added the required actionReferenceID field to
ResolvedSurfaceTabBarButtonEntry. #14868 added a new return of that
struct for a project button that shows a global setting action, without
the field. That button still shows and runs the referenced action, like
the ordinary resolved path below it, so it reports the same
resolvedIdentifier. Actions & Launchers discovery then lists the action
as placed on the tab bar. The argument shares a line to keep the file
within its length budget.

Refs #15488

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

* fix(actions): name setting actions in the discovery summary

The second compile error from #13232 and #14868 merging 13 minutes apart,
hidden behind the first:

  Sources/AppDelegate+WorkspaceActionSave.swift:126:9: error: switch must be
  exhaustive

#14868 added CmuxSurfaceTabBarButtonAction.setting, and #13232's
Actions & Launchers summary switched over the enum without it. The
summary's type token follows each action's cmux.json "type", so a
setting preset shows "settingPreset" and any other setting change
"setting". The switch is now one case per line, which keeps the file
within its length budget. Every other exhaustive switch over the enum
already handles .setting.

Refs #15488

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

* Keep Workspace+TitleOwnership.swift as main has it

The title-frame comment tweak is cosmetic and was the only Swift change
left in this PR. Without it the PR is web and CI only, so its checks
don't wait on main's cmuxTests build.

Refs #15488

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

* test(web): pin the seats-follow-membership billing copy

The billing panel's over-seat line is asserted here, and this test has
been red on main since the dashboard SPA port: it already checks that no
add-seats link is offered, and the port brought one back. Widen it to the
copy the rule actually calls for, so both halves of the regression are
covered.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Leo Li <cheerleaderleo@outlook.com>

* fix(web): restore the seats-follow-membership copy the dashboard port dropped

The Team subscription quantity follows the member count, so an over-seat
line has nothing for an admin to act on: the reconciler updates Stripe on
the next membership fact. That was settled in 06f4a7c, which reworded
the line in all 20 locales, removed the add-seats link beside it, and
dropped the members-page seat nudge.

The dashboard SPA port rebuilt the billing panel from the pre-06f4a7c
version at a new path, so git saw no conflict and the link came back, and
the locale files went back to the soft-seat wording. `web/tests/
dashboard-billing-screen.test.tsx` has been red on main ever since, which
fails the required `ci-status` on every web pull request.

Restores the wording and drops the link. `seatNudge` and
`seatNudgeAction` go too: the nudge they belonged to is gone from the
members page and nothing reads them. `docs/team-settings-and-invites.md`
already records the rule, and the stale "seats are soft" comment left
hanging over an unrelated type in `team-members.tsx` is removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Leo Li <cheerleaderleo@outlook.com>

* test(web): pin the new-team seat copy too

The same merge-resolution path that reverted the billing panel's copy also
reverted this line, and nothing asserted on it. Pin the sentence and the
old wording's absence so a stale merge side fails the shard instead of
shipping.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Leo Li <cheerleaderleo@outlook.com>

* test(coderouter): close pinned proxy test connections

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>

* fix(coderouter): handle pinned proxy body failures without hanging

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>

* fix(ci): address follow-up review findings

* merge: keep main's current bonsplit pin

* fix(ci): harden locale and migration review follow-ups

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>

* fix(ci): finish migration and locale follow-ups

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>

* fix(web): preserve locale cookies during RSC navigation

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>

* test(web): remove duplicate locale race case

---------

Co-authored-by: Leo Li <cheerleaderleo@outlook.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
rustybret pushed a commit to rustybret/bmux that referenced this pull request Oct 2, 2026
70e997f Merge pull request manaflow-ai#16199 from manaflow-ai/16189-cloud-sidebar-icons
5e4a6f5 Fix terminal scrollback follow after accepted input (manaflow-ai#16529)
ae5c960 switch account, cmux sign-in page, and saved sessions like gmail (manaflow-ai#16364)
5610998 test: pin Flash While Typing off in the typing-dismiss no-flash test (manaflow-ai#16625)
db21906 Fix sidebar template catalog and Cloud machine-row tests; drop stale preview generator (manaflow-ai#16595)
2ec0306 ci: pin Xcode 26.6 for macOS 27 runners (manaflow-ai#16547)
dc56459 fix: make Cloud command palette actions follow workspace capabilities (manaflow-ai#16273)
638b468 Fix mobile Feed notification duplicates and update warning (manaflow-ai#16352)
49d798e test: use deterministic Cloud header sizing
e2fc8fc Merge remote-tracking branch 'upstream/main' into 16189-cloud-sidebar-icons
4b2db7c test: allow Cloud header controls to settle
80ca30f Merge remote-tracking branch 'upstream/main' into 16189-cloud-sidebar-icons
e2f2b7d fix: constrain Cloud header action layout
75990f6 fix: remove duplicate pane test binding
8738ba2 fix: restore custom sidebar preview resources
2c6819a Merge remote-tracking branch 'upstream/main' into 16189-cloud-sidebar-icons
017b63b fix: use local SSH command quoting
ac5eba5 fix: compile sidebar usage owner selection
90b0655 fix: make custom upload endpoint policy explicit
82ddf7c fix: pass remote paste policy to custom uploads
77ec507 Merge remote-tracking branch 'upstream/main' into 16189-cloud-sidebar-icons
eaceb98 Merge remote-tracking branch 'upstream/main' into 16189-cloud-sidebar-icons
8436277 Merge main (4e9d779) into 16189-cloud-sidebar-icons
c17fa5d Merge main (488eaf7) into 16189-cloud-sidebar-icons
9672805 Cloud sidebar tests: import CmuxFoundation for GlobalFontMagnification
eae5972 fix(tests): restore PaneResizeShortcutTests' controller binding
dd91af2 fix(tests): allow bounded main queue drain timeout
aff65ce test: check the vm ready poll interval in cmuxCLITests so cmuxTests compiles
91d743a Merge commit '5e83d8029eedca144c10096fa8b3664a940092b3' into 16189-cloud-sidebar-icons
022502a Merge main (7ba9740) into 16189-cloud-sidebar-icons
7f1297d fix: list setting actions in Actions discovery so main compiles (manaflow-ai#16222)
aa5e7e8 Merge main (b3ca418) into 16189-cloud-sidebar-icons
b53c137 Merge main (1831681) into 16189-cloud-sidebar-icons
4400412 Cloud sidebar: withhold New Workspace while the fleet read is failing
71ac098 fix: restore main's build after manaflow-ai#14868 and manaflow-ai#13232 crossed in CmuxConfig
d9dfb3e Cloud workspace targeting: never resolve New Workspace to a locked machine
73f59e7 Merge main (c12e934) into 16189-cloud-sidebar-icons
5a43fcb Cloud sidebar: move section icons to headers and guard create rows
9d32421 Cloud sidebar: test section identity icons and guarded create rows
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged-unverified A judging check was not green at merge; see the merge receipt comment needs a call Finished and held for a team design or product decision (see #13742 and the gallery in #15427)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants