Skip to content

fix(dashboard): give the settings page the launcher's run-option rules - #1098

Merged
suleimansh merged 3 commits into
mainfrom
fix/settings-run-option-rules
Jul 23, 2026
Merged

fix(dashboard): give the settings page the launcher's run-option rules#1098
suleimansh merged 3 commits into
mainfrom
fix/settings-run-option-rules

Conversation

@suleimansh

Copy link
Copy Markdown
Contributor

Stacked on #1097 (Devices) — both touch SettingsPage.tsx, so this targets that branch. Base retargets to main once #1097 merges.

The bug

The settings page shipped in #958/#1096 rendered the run options as flat, independently checkable boxes, while the launcher has real rules between them. That is not just noise, it is wrong:

Launcher rule What the settings page did
transparent overrides autopilot / technical / vanilla / post-merge / browser, and forces them to read off showed them enabled and independently checkable
ecoDisabled = vanilla || transparent — "nothing to trim while the system prompt is off" let you turn Eco on under Vanilla
browser is Claude-only (inert on Codex — it rides Claude Code's MCP config) let you enable it on Codex
ecoMaintenance requires onBeforeMergeableQuality let you enable it standalone, where it trims nothing

So the page could show a box checked that the launcher shows off.

The fix: one table, two renderers

The option table and its rules move out of Composer.tsx into lib/run-option-rows.ts, which both surfaces render. It is pure data (no JSX), so the launcher still renders dropdown items and the settings page renders page rows — neither owns the rules, and a rule cannot hold in one place and not the other.

  • checked is now the effective value, so no surface claims an option is on while the run ignores it.
  • A disabled row is greyed with its reason, not hidden. The settings page is where you go to look for a setting, so a vanished row is worse than a greyed one. (The launcher keeps hiding the Eco drops when Eco is off, exactly as before.)
  • The launcher is behaviourally unchanged — its existing tests pass untouched, which is the point of the extraction.

Two smaller cases of the same mistake, also fixed

  • Notifications now show the delivery capability the bell already showed: permission blocked disables the Browser row, and Discord rows say "Not configured" when DISCORD_WEBHOOK / DISCORD_BOT_TOKEN are unset.
  • Spend offset is bounded to ±MAX_SPEND_OFFSET, the same range as its slider and the sanitizer. It used to accept a typed 9999 that the sanitizer silently clamped to 50 while the box kept showing 9999.

Verification

  • pnpm typecheck 22/22, pnpm build 12/12
  • dashboard 399 pass (+8 new rule tests), framework 1176 pass / 0 fail
  • Driven in a real browser on the settings page: Transparent greys the five rows with "off while Transparent is on"; Vanilla greys Eco with "nothing to trim while the system prompt is off"; agent Codex greys Browser with "only on Claude Code"; typing 9999 into the spend offset lands on 50.

One behaviour I carried over rather than "fixed", flagged for a decision: an unrecognised stored agent falls back to Claude Code for the label but is not treated as Claude for the Browser rule, so Browser stays disabled. That is what the launcher already did; treating an unknown agent as Claude would offer a browser its driver cannot wire up. Pinned by a test so it is now a decision rather than an accident.

Adding and removing a device already worked, but only from the composer's
"Run on" menu, and the composer only exists on a project launcher: from the
Overview or the settings page there was no way to manage the roster at all.

Adds a Devices section to the settings page listing each saved device with its
origin and online/offline status, an Add device button (the existing dialog),
and a remove per row. The "Run on" picker still lists devices, because choosing
a run target is a per-run act; which devices exist is configuration.

Removing from settings applies the same guard the composer already did: a device
that was the selected run target clears the selection, so a run can never point
at a device that is no longer saved.

The presentation is new but the state is not: it reads the existing
useConnectionProfiles / useDeviceStatus hooks and profiles.ts, so there is one
device store, not two. The section says devices are saved in this browser
because, unlike every other setting on the page, a device carries a token and so
never reaches the daemon.
The settings page rendered the run options as flat, independently checkable
boxes while the launcher has real rules between them, so the page could show an
option checked that the launcher shows off, and allowed combinations that mean
nothing: Eco under Vanilla, Browser on Codex, Auto maintenance without
Post-merge cleanup, and anything at all under Transparent.

Move the option table and its rules out of Composer into lib/run-option-rows.ts,
rendered by both surfaces, so a rule cannot hold in one place and not the other.
It is pure data, so the launcher still renders dropdown items and the settings
page renders page rows; neither owns the rules. `checked` is the effective
value, so nothing claims an option is on while the run ignores it.

A disabled row is greyed with its reason rather than hidden: the settings page
is where you go to look for a setting, so a vanished row would be worse than a
greyed one. The launcher is unchanged (it already hid the Eco drops when Eco is
off), and its tests pass untouched.

Two smaller cases of the same mistake, fixed here too:
- the notification rows now show the delivery capability the bell already did
  (permission blocked, DISCORD_WEBHOOK / DISCORD_BOT_TOKEN unset)
- the spend offset is bounded to the same range as its slider and the
  sanitizer, which used to clamp a typed 9999 to 50 while the box kept 9999
@suleimansh suleimansh self-assigned this Jul 23, 2026
@suleimansh
suleimansh marked this pull request as ready for review July 23, 2026 22:07
Base automatically changed from feat/settings-devices to main July 23, 2026 22:17
#1097 was squash-merged, so its commits are not the ones on main and the shared
SettingsPage.tsx conflicted. Resolved in favour of this branch's shared
run-option table, keeping the Devices section main brought in.
@suleimansh
suleimansh merged commit 2f8908c into main Jul 23, 2026
1 check passed
@suleimansh
suleimansh deleted the fix/settings-run-option-rules branch July 23, 2026 22:25
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