Both settings on the App Settings "Codex CLI" tab (bypass approvals, animated
status effects) are handed to `codex` at launch, so on an instance where the
binary does not resolve the tab offers choices nothing can act on. Gate it on
availability instead.
renderIndexHtml injects window.__codemanCodexAvailable, mirroring the existing
gesture-availability flag, and settings-ui.js hides the tab button when it is
absent. Injected rather than fetched on modal open so the tab cannot flicker in
and back out; isCodexAvailable() memoizes its PATH probe, so the per-render cost
is nil. Installing codex later needs a restart, exactly like the
/api/codex/status route that already backs the Run menu. Solo popups skip the
probe since they have no settings modal.
Only the tab BUTTON is toggled. The panel already carries
.modal-tab-content.hidden unless it is the selected tab and openAppSettings()
always reopens on Display, so an unreachable button keeps the panel unreachable.
The inputs stay in the DOM and are still populated and read back on save, so a
user without codex cannot silently wipe the codex preferences of an instance
that has it. Animations stay off by default for new local Codex sessions.
Verified in a browser on this host, which has no codex: the flag is absent, the
Codex tab is hidden while the other tabs are unaffected, and saving App Settings
with the tab hidden leaves codexAnimationsEnabled/codexDangerouslyBypassApprovals
untouched. With the flag forced on, the tab appears, its panel opens, and
toggling the visible slider persists. The openAppSettings coupling test was
checked to fail when the call is removed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Fix the gesture enable-reload race: PUT /api/settings writes settings.json
without invalidating WebServer's 2s _settingsCache, and the toggle reloads
~400ms after save — within the TTL — so renderIndexHtml could render the
pre-toggle state (bundle not injected until a 2nd reload). renderIndexHtml
now reads settings via readSettings(true), a fresh read that bypasses the
cache; readSettings gains a forceFresh param.
- Replace the brittle multi-monitor reveal (string match on the button's
aria-label + inline style) with a stable `btn-multimonitor--hidden` class
marker: the template carries the class, the server strips it when the setting
is on, and applyHeaderVisibilitySettings()/solo-mode CSS toggle the same class.
Editing the button's copy no longer silently breaks the reveal.
- Test: test/render-index-html.test.ts (reveal, solo injection + escaping,
gesture availability vs. enablement, fresh-read wiring).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>