Skip to content

Add sidebar.leftMinWidth to cmux.json - #14875

Closed
teamleaderleo wants to merge 11 commits into
manaflow-ai:mainfrom
teamleaderleo:feat/sidebar-minimum-width-setting
Closed

teamleaderleo wants to merge 11 commits into
manaflow-ai:mainfrom
teamleaderleo:feat/sidebar-minimum-width-setting

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

The left sidebar's drag floor could only be changed with defaults write <bundle> sidebarMinimumWidth -float N. It's now a regular setting: sidebar.leftMinWidth in cmux.json, and a Sidebar Minimum Width slider in Settings > Sidebar.

{ "sidebar": { "leftMinWidth": 160 } }
  • Values are clamped to the existing 120–260 pt range, and the default stays 240. The configurable floor doesn't change; Left workspace sidebar minimum width raised to 240pt — request lower/configurable minimum #8253 asks for a lower one, which can be a separate change.
  • The setting is stored under the historical sidebarMinimumWidth UserDefaults key, so existing defaults write overrides keep working.
  • No restart is needed. ContentView already observed that key (@AppStorage + onChange → clampSidebarWidthIfNeeded), so a cmux.json save applies to open windows. Raising the floor widens a narrower sidebar; lowering it lets you drag narrower.
  • Removing the key from cmux.json restores the previous value, through the usual managed-defaults backup.
  • The bounds live in one CmuxSettings.LeftSidebarWidthSettings policy, which mirrors RightSidebarWidthSettings. The catalog key, the cmux.json parser, the Settings row and SessionPersistencePolicy all read it.
  • Schema entry, Settings search, all-keys.md, localized Settings strings (9 locales) and a localized docs description (20 web locales) are included.

This builds on @austinywang's approach in #6875, which has gone stale against main (it also lowered the floor to 100). Austin is credited as co-author.

  • A string-typed legacy value (defaults write <bundle> sidebarMinimumWidth 180, stored as a string without -float) is rewritten as a number at launch, before cmux.json applies. Every reader and the cmux.json backup then see the same value. An unparseable string is removed and resolves to the default.

Verification

  • New tests:
    • cmuxTests/SidebarWidthPolicyTests covers the cmux.json apply, clamping in both directions, restoring on unset, the legacy string rewrite, and an earlier defaults value (number or string) surviving cmux.json setting and then removing the key.
    • CmuxSettingsTests/LeftSidebarWidthSettingsTests covers the policy and the catalog key.
    • The Settings row was added to SettingsRowAnchorResolutionTests.
  • Passed locally (Linux): scripts/ci/guards-local.sh (64 steps), scripts/localization_catalog.py check and scripts/lint-xcstrings.py.
  • Upstream CI on 2ecedb9 (run 36314092517) is green: 78/78 checks.
  • Main was merged in with scripts/merge-main.sh at 6431ac2, with guards green.

Dogfood

  • Fleet build: job a755a3954e059b2df9a04b9c, tag pr-14875-sidebar-min-width-v2, built from faf5805 on cmuxs-Mac-mini (artifact sha256:6f17a1a8…). The app code is identical at 2ecedb9, which only drops a test import.
    • It was built with --backend-mode local, because the dev backend VM isn't reachable from this machine. The change doesn't touch the backend.
    • publish-hq refuses local-backend artifacts, so there is no HQ link.
  • GUI dogfood has not been done. I couldn't get a GUI Mac to drive:
  • Still to check on a GUI Mac:
    • Set sidebar.leftMinWidth, both in cmux.json and with the slider.
    • Drag the divider and confirm the new floor applies without a restart.
    • Remove the key and confirm the previous value comes back.

🤖 Generated with Claude Code

teamleaderleo and others added 2 commits September 26, 2026 11:10
The left sidebar's drag floor was only reachable through the
sidebarMinimumWidth UserDefaults key. It is now a first-class setting:
sidebar.leftMinWidth in cmux.json, a Sidebar Minimum Width slider in
Settings > Sidebar, schema and search entries. Values are clamped to the
existing 120-260 range, the default stays 240, and the historical
UserDefaults key is kept so existing overrides keep working. The layout
already observes the key, so edits apply to open windows immediately.

Adapted from the approach in manaflow-ai#6875.

Co-authored-by: Austin Wang <austinwang115@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Austin Wang <austinwang115@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 26, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

/catch-up

@github-actions

Copy link
Copy Markdown
Contributor

Catch-up only runs on branches in this repository for now, so I left this one alone. A maintainer can merge main in by hand.

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

Resolved generated files:
- 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

Catch-up-previous-head: d190c06
Catch-up-base: 8c9d2c9
@vercel

vercel Bot commented Sep 26, 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.

Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631).
Merged by scripts/merge-main.sh: mf/main at 4d3385b.

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

Catch-up-previous-head: 3519c24
Catch-up-base: 4d3385b
teamleaderleo and others added 5 commits September 27, 2026 02:43
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631).
Merged by scripts/merge-main.sh: origin/main at 6431ac2.

Resolved generated files:
- 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

Catch-up-previous-head: 05ef27b
Catch-up-base: 6431ac2
`defaults write <bundle> sidebarMinimumWidth 180` (without -float) stores a
string. The session sanitizer already parsed it, but the typed settings key
and the Settings slider did not. Rewrite such a value as a number at launch
so every reader agrees. Unparseable strings are left alone and resolve to
the default.

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

Move the string-to-number rewrite of sidebarMinimumWidth ahead of the
settings file store, so a cmux.json backup of the user's earlier value is
the normalized number, and drop unparseable strings instead of letting the
backup record them as 0. Cover an earlier defaults value (number and string)
surviving cmux.json setting and then removing sidebar.leftMinWidth.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s in the test

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

# Conflicts:
#	CHANGELOG.md
#	Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

CI failure attribution

CI passes on 0b38921fef (run 36409605893 attempt 1).

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.

teamleaderleo and others added 2 commits September 28, 2026 01:27
…width-setting

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An earlier merge on this branch reshuffled the whole string catalog, so the
pull request diff showed about 3,000 changed lines for 4 new keys. This
restores main's copy and re-inserts only the sidebar.leftMinWidth keys. The
key set is unchanged: main's 7,160 keys plus the same 4, and no existing
key's value differs from main.

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

Copy link
Copy Markdown
Collaborator Author

Review: read the whole diff with correctness first, and the shape is right. LeftSidebarWidthSettings is the single definition that the catalog key, the cmux.json loader, the Settings row and SessionPersistencePolicy all read, which is what the right sidebar already does with RightSidebarWidthSettings, so the two sides of the window are now described the same way. Reusing the historical sidebarMinimumWidth defaults key means anyone who set it with defaults write before this setting existed keeps their value.

Two things I checked specifically, because they are where this kind of change usually goes wrong.

The legacy-value normalization is correct and it is ordered correctly. defaults write <bundle> sidebarMinimumWidth 180 stores a string unless -float is passed, and a string read as a double is 0, which would clamp to the lower bound and look like the setting ignoring the user. normalizeLegacySidebarMinimumWidthIfNeeded rewrites it as a number, and it runs in cmuxApp.init before the settings file store takes its backups, so the backup records the normalized number rather than the string. An unparseable string is removed rather than written as 0, which is the right call: resolving to the documented default beats persisting a wrong number.

The clamp is in one place. sanitizedMinimumSidebarWidth now delegates to the policy instead of repeating the range, so the restore path, the slider and the cmux.json loader cannot drift apart. The bounds are 120 to 260 with a 240 default, unchanged from what the code already enforced.

Fixed: nothing needed fixing in this pass. The earlier rounds had already dealt with the ambiguous SidebarMaterialOption import in the test and with normalizing before cmux.json applies.

Left: two red checks, and both trace to one commit rather than to the change itself.

CLA Assistant is red because the head commit here is authored as leo@manaflow.ai, an address that is not associated with a signed agreement, while the rest of the branch is authored as cheerleaderleo@outlook.com. This matters beyond a red badge: the diff includes web/data/cmux.schema.json and the 20 message catalogs, web/ is BSL licensed, and the repo's own rule is not to merge a change to those directories while CLA Assistant is red. So this cannot land until that is resolved.

ui-tests is red for a related reason. That same commit adds a dragAt step to cmuxUITests/DogfoodScenarioUITests, and the workflow refuses to run UI tests for a fork pull request that changes UI test classes, since only a same-repository dispatch can run them. ci-status is red purely as a consequence of ui-tests.

The cheapest resolution I can see, and the one I would recommend, is to associate leo@manaflow.ai with the GitHub account: it clears CLA Assistant with no change to history. ui-tests would still need the documented path for this case, which is a maintainer running scripts/run-e2e.sh on the head and adding the no-full-ci label; I can supply that run. The alternative is replacing that one commit, which drops the dragAt step and clears both reds at once, since the tour can use the existing debug.sidebar.simulate_drag socket method instead of a new step type. That is a force-push of a commit I did not write, so it is not mine to do, and it is with Leo.

Staying a draft until one of those lands. Nothing about the code is waiting on review.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Superseded by #15349, which is the same change with the same setting and default: sidebar.leftMinWidth, default 240, clamped to 120 through 260.

Nothing here was wrong. The problem was where the branch lived. The ui-tests job refuses at a step named "Refuse a fork" based on the repository the head branch is in, not on anything in the diff, so this could never go green from a fork no matter how the code changed. The branch now lives on this repository, so that job can actually run and the change can be dogfooded, which was not possible before.

#15349's body records what happened to the history, so the force-push that dropped a stray commit is on the record there rather than only here.

Closing in favour of that one. Thanks for the patience on this :)

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