Skip to content

feat(settings): add Developer Mode section gating Feature Releases#3039

Open
harshitsinghbhandari wants to merge 2 commits into
AgentWrapper:mainfrom
harshitsinghbhandari:ao/agent-orchestrator-111/developer-mode
Open

feat(settings): add Developer Mode section gating Feature Releases#3039
harshitsinghbhandari wants to merge 2 commits into
AgentWrapper:mainfrom
harshitsinghbhandari:ao/agent-orchestrator-111/developer-mode

Conversation

@harshitsinghbhandari

Copy link
Copy Markdown
Collaborator

Summary

Adds a Developer Mode section to the global app Settings and gates the Feature Releases update channel behind it.

  • New Developer Mode section in Global Settings: a single Switch toggle, default off, persisted via the existing ui-store + localStorage pattern (same one the Theme/sidebar preferences use; localStorage resolves under ~/.ao/electron, respecting the ~/.ao-only state rule).
  • When Developer Mode is off, the Feature Releases option is removed entirely from the Updates channel dropdown and the feature-build picker is hidden (hidden, not disabled). When on, Updates behaves exactly as before.
  • The Updates "you are on PR #N's build" banner is intentionally left outside the gate, so a user who pinned a build and later turns Developer Mode off still has a "Return to Stable/Nightly" escape hatch.

Note on scope

The pre-existing "Feature Releases" surface is the feature channel option inside UpdatesSection (plus its FeatureBuildsSelect picker). There is no separate top-level Feature Releases page in main, so this gates that entry point. Feature Releases itself is unchanged.

Changes

  • stores/ui-store.ts — add developerMode state + setDeveloperMode, initialized from and persisted to localStorage.
  • settings/DeveloperModeSection.tsx — new section with a single shadcn Switch.
  • GlobalSettingsForm.tsx — render the new section.
  • settings/UpdatesSection.tsx — hide the feature channel option / picker unless Developer Mode is on.

Tests

  • npx vitest run GlobalSettingsForm.test.tsx — 21 passing, including two new gating tests (option hidden when off, revealed when toggled on) plus a section-render assertion.
  • Renderer production build (vite build) passes.
  • Verified in-app via ao preview on /settings.

Known risks / follow-ups

  • Purely a UI gate; the main-process auto-updater is untouched.
  • Pre-existing tsc errors in src/renderer/lib/command-palette.ts are unrelated (that file is byte-identical to main).

@harshitsinghbhandari harshitsinghbhandari left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Review: ready to merge (posting as COMMENT since GitHub blocks self-approval).

Clean, tightly-scoped UI gate. developerMode follows the existing ui-store + localStorage pattern; the feature channel option and FeatureBuildsSelect picker are fully hidden (not disabled) when off; and the primaryValue fallback correctly avoids showing a selection with no matching option. The activeBuild banner is deliberately left ungated as an escape hatch, so a user who pinned a build and later disables Developer Mode keeps a Return-to-Stable/Nightly path. Verified npx vitest run GlobalSettingsForm.test.tsx (21 passing) and the tests exercise both gated states. The stray frontend/node_modules file removal is a legitimate cleanup of a broken symlink that had been committed as text.

One minor, non-blocking UX note inline. No changes required.

const primaryValue: PrimaryValue = form.feature != null || showFeature ? "feature" : form.channel;
// With Developer Mode off the "feature" value has no matching option, so fall
// back to the home channel to keep the dropdown showing a valid selection.
const primaryValue: PrimaryValue = developerMode && (form.feature != null || showFeature) ? "feature" : form.channel;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Non-blocking: when a feature build is pinned (form.feature != null) and Developer Mode is then turned off, the channel dropdown shows form.channel (e.g. "Stable (Latest)") as the selected value while the app is actually running the pinned feature build. The activeBuild banner mitigates this and it is a documented tradeoff, so this is fine as-is; just flagging the dropdown/banner divergence for awareness.

Adds a Developer Mode toggle (single Switch, default off) to global Settings,
persisted via the ui-store + localStorage pattern under ~/.ao/electron. When off,
the Feature Releases update channel option and its build picker are hidden entirely;
when on, Updates behaves as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@harshitsinghbhandari
harshitsinghbhandari force-pushed the ao/agent-orchestrator-111/developer-mode branch from fa59ec7 to 9552566 Compare July 23, 2026 16:55

@illegalcall illegalcall left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviews

  1. [P1] A persisted feature pin can remain effective while Developer Mode hides every indication of it.

    Pinning writes feature: { pr } before checking availability (auto-updater.ts:470). If that check fails, the app can remain on Stable while the pin persists and future manual/automatic checks continue using the pr<N> feed.

    With Developer Mode off, UpdatesSection then displays the home channel, hides the picker, and renders no banner or Return action because getActive() is still null. The concealed pin can later install a feature build.

    Please render an escape/status action whenever form.feature exists, independently of whether the feature build is already running, or explicitly clear the pin when Developer Mode is disabled.

  2. [P1] Return can overwrite unrelated update preferences after a settings-load failure.

    If active-build detection succeeds but updateSettings.get() fails, the banner renders while formRef still contains DEFAULT_SETTINGS. Clicking Return submits { enabled: false, channel: "latest", ... }, potentially replacing enabled/Nightly preferences instead of only clearing the feature pin.

    Please disable Return until update settings have loaded, or clear the feature pin atomically against main-process state.

  3. The new tests do not exercise the meaningful picker-gating state.

    The off test starts with feature: null and showFeature: false, so the picker was already absent before this change; it still passes if the new developerMode && guard around primaryValue is removed. Please cover a persisted pin with Developer Mode off and toggling Developer Mode off after transiently selecting Feature Releases. Persistence also needs coverage for default-off, localStorage restoration/write, and reload.

  4. frontend/docs/desktop-release.md is now stale.

    Its user workflow directs people straight to Settings → Updates → Feature Releases, which is impossible by default. It should first instruct users to enable Developer Mode.

Minor naming note: STABLE_CHANNEL_OPTIONS contains both Stable and Nightly; NON_FEATURE_CHANNEL_OPTIONS would be clearer.

I reproduced the two runtime failure paths with temporary characterization tests; the existing focused suite and GitHub checks remain green.

Address review on PR AgentWrapper#3039:
- Show the Return-to-home banner whenever a feature build is pinned in settings
  (not only when one is already running), so a pin that stays effective in the
  main-process updater is never hidden while Developer Mode is off.
- Disable Return until update settings load, avoiding a clobber of enabled/channel
  prefs with defaults when settings failed to load.
- Rename STABLE_CHANNEL_OPTIONS to NON_FEATURE_CHANNEL_OPTIONS (it includes Nightly).
- Cover persisted-pin gating, the primaryValue guard on toggle-off, and localStorage
  persistence with tests (24 passing).
- Update desktop-release.md: Feature Releases now requires enabling Developer Mode.

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

Copy link
Copy Markdown
Collaborator Author

Thanks @illegalcall, verified each against the code. Pushed 07a7e17.

  1. [P1] Concealed effective pin confirmed: confirmPinBuild persists feature:{pr} via checkForUpdatesNow (writeUpdateSettings runs before the availability check), so the pr<N> feed stays live in the main process regardless of the renderer-only Developer Mode flag. Fixed by surfacing the banner + Return whenever form.feature != null (not just when a build is already running): pinnedPr = activeBuild?.pr ?? form.feature?.pr. A concealed pin now always shows a "PR #N is pinned but not yet installed." row with a Return action.

  2. [P1] Return clobbers prefs after a settings-load failure is real but pre-existing (the formRef/DEFAULT_SETTINGS race lives in banner logic untouched by this PR). I hardened the one line I was already editing: Return is now disabled until updateSettings.get() succeeds, so it can't submit defaults. A full atomic clear-against-main-process fix is out of scope here; happy to file a follow-up.

  3. Tests added: persisted-pin gating with Developer Mode off (picker hidden, Return shown, clears the pin), the primaryValue guard when toggling Developer Mode off after selecting Feature Releases, and localStorage default-off + write. 24 passing.

  4. Docs desktop-release.md now instructs enabling Developer Mode first.

Naming: renamed STABLE_CHANNEL_OPTIONS -> NON_FEATURE_CHANNEL_OPTIONS.

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.

2 participants