Skip to content

fix(run-mode): gate dropdown entries on CLI availability - #201

Merged
Ark0N merged 1 commit into
Ark0N:masterfrom
timkjr:pr/gate-run-mode-dropdown
Aug 4, 2026
Merged

fix(run-mode): gate dropdown entries on CLI availability#201
Ark0N merged 1 commit into
Ark0N:masterfrom
timkjr:pr/gate-run-mode-dropdown

Conversation

@timkjr

Copy link
Copy Markdown

Summary

Follow-up to #200 (welcome-screen buttons). The run-mode dropdown (gear icon next to Run) has the same problem: Claude/Opencode/Codex/Gemini entries are always shown regardless of whether the CLI is actually installed, so picking one can spawn a session that immediately errors out.

  • Adds _refreshRunModeAvailability() in session-ui.js, called each time the dropdown opens; hides an entry whose /api/<cli>/status reports available: false.
  • Shell is intentionally left unconditional — no external CLI dependency.

Depends on #200: isClaudeAvailable() / GET /api/claude/status don't exist on master yet, so this branch duplicates that small addition from #200 to stay self-contained and independently reviewable/mergeable. Once #200 lands, this branch should be rebased onto master, which will cleanly collapse the duplicate (trivial conflict, or none if git dedupes it).

Test plan

  • tsc --noEmit clean
  • eslint clean on touched .ts files
  • check:frontend-syntax and check:public-assets pass
  • Verified all four /api/*/status endpoints via curl against a throwaway dev server
  • Verified dropdown gating via Playwright: claude/opencode/shell visible, codex/gemini hidden (matches local install state), no console errors

Follow-up to the welcome-screen gating (Ark0N#200): the run-mode dropdown
(gear menu next to Run) had the same problem — Claude/Opencode/Codex/
Gemini entries were always shown regardless of whether the CLI is
actually installed, so picking one could spawn a session that
immediately errors out.
- Add _refreshRunModeAvailability() (session-ui.js), called each time
the dropdown opens; hides entries whose /api/<cli>/status reports
unavailable.
- Shell is intentionally never gated (no external CLI dependency).
Depends on isClaudeAvailable()/GET /api/claude/status, which don't
exist on upstream/master yet — duplicated here from Ark0N#200 so this PR
is self-contained and independently mergeable. Once Ark0N#200 lands this
branch should be rebased onto master, which will collapse the
duplicate cleanly.
@timkjr
timkjrforce-pushed the pr/gate-run-mode-dropdown branch from d4a24b5 to 660b320CompareAugust 4, 2026 21:21
@Ark0N
Ark0N merged commit 8facd5e into Ark0N:masterAug 4, 2026
Ark0N pushed a commit that referenced this pull request Aug 4, 2026
…over antigravity
Follow-up to #200 and #201, which gate the welcome buttons and the run-mode
dropdown on whether the CLI is actually installed. Four corrections:
1. #200 also DELETED the Cloudflare Tunnel welcome button and the QR widget
outright. Its rationale is right (offering a tunnel where cloudflared is not
installed is a bad default) but the conclusion overshoots: the welcome QR is
the whole scan-to-connect-from-your-phone flow, and deleting it left a large
block of live tunnel code in settings-ui.js driving elements that no longer
existed. Both are restored and the button is gated on cloudflared, which is
what the stated rationale actually asks for. New cloudflared-resolver.ts
mirrors the CLI resolvers, and TunnelManager now shares its search path so
the button and the spawn can never disagree about where cloudflared lives.
2. Antigravity was missing from the run-mode gating, the one run mode LEAST
likely to be installed. It slipped past because #201 predates it. Covered
now, plus a static test that fails if a sixth mode reaches the dropdown
without being gated, so the next one cannot slip the same way.
3. The per-surface fetches are replaced by the injected availability object
already used for the Codex settings tab, so the codebase has one mechanism
rather than two. The status routes buy nothing as a gating source: every
resolver memoizes its PATH probe server-side, so a fetch is exactly as stale
as an injected value while costing a round trip every time the dropdown opens
and leaving the welcome buttons to flicker in after paint. The routes
themselves stay, including the /api/claude/status that #200 adds.
4. Unknown availability now reads as AVAILABLE for run buttons. Both PRs hid the
button on a failed fetch, so a blip left a working install with nothing to
click; a genuinely missing CLI only ever produced an error toast. The Codex
settings TAB keeps the opposite default, since hiding it costs nothing.
The dropdown query is also scoped to the menu: `.run-mode-option` is the class
the saved-dashboard and history rows use too, and a document-wide querySelector
would have found whichever came first in the DOM.
Fixes a latent environment-sensitivity in 816d900 while here: the index-title
test asserted the template was untouched apart from the title, which held only
on a machine with no codex installed.
Verified end-to-end against a real server on an isolated instance+socket, with
Playwright: gemini/codex hidden and claude/opencode/antigravity/shell shown,
matching this host, tunnel button back, Codex settings tab still hidden, no
console errors. Full test:ci sweep green (3902 tests).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Ark0N

Ark0N commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Merged, thank you! And thanks for splitting it out of #200 with the duplication called out explicitly, git deduped the shared hunk on merge exactly as you predicted, so this cost nothing to land.

Follow-up in 5d28999 with three changes.

Antigravity was missing. It is a run mode like the rest and agy is the least likely of the five to be installed, so it is the one that most needed gating. Not your fault, it landed after this branch. Added a static test that fails if a sixth mode reaches the dropdown without being gated, so the next one cannot slip the same way.

The query is scoped to menu now..run-mode-option is also the class used by the saved-dashboard rows (webview-tabs.js) and the history rows, so document.querySelector('.run-mode-option[data-mode=...]') would find whichever comes first in the DOM rather than the menu entry.

Availability comes from the injected object rather than four fetches per open, same change as on #200: the server-side resolvers memoize, so a fetch is no fresher than an injected value while costing four round trips every single time the gear menu opens. Also failing open on unknown now, since the catch hiding an entry meant a blip could leave only Shell in the menu.

Keeping Shell ungated was the right call, incidentally, it is what guarantees the menu is never empty on a box with nothing installed. Kept and pinned in a test.

Thanks again!

timkjr pushed a commit to timkjr/Codeman that referenced this pull request Aug 5, 2026
MOBILE_OVERVIEW_RUN_MODES / _buildMobileOverviewRunMenu is a separate,
hardcoded duplicate of the toolbar's #runModeMenu (mobile-overview.js
is a newer feature that mirrors the toolbar menu's look/behavior
rather than reusing its render), so it never picked up Ark0N#201's
isCliAvailable() gating and offered every backend regardless of what
the server actually has installed.
Gate it the same way: skip an entry unless isCliAvailable(mode),
shell always exempt. Added functional + static regression tests
mirroring the toolbar menu's own test pattern.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ark0N pushed a commit that referenced this pull request Aug 5, 2026
MOBILE_OVERVIEW_RUN_MODES / _buildMobileOverviewRunMenu is a separate,
hardcoded duplicate of the toolbar's #runModeMenu (mobile-overview.js
is a newer feature that mirrors the toolbar menu's look/behavior
rather than reusing its render), so it never picked up #201's
isCliAvailable() gating and offered every backend regardless of what
the server actually has installed.
Gate it the same way: skip an entry unless isCliAvailable(mode),
shell always exempt. Added functional + static regression tests
mirroring the toolbar menu's own test pattern.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
dignfei pushed a commit to dignfei/Codeman that referenced this pull request Aug 30, 2026
The run-mode dropdown hides CLIs that are not installed on the HOST (Ark0N#201). That
is right for local sessions and wrong for a container case, whose agents run
inside the container: a host with no claude installed hides the mode while the
container ships one, which is exactly what happened on a real deployment.
The adoption preflight already probes what the container has, so that result is
persisted on the case and surfaced through CaseInfo. Docker cases gate on it;
every other case keeps the host probe unchanged.
An absent list reads as "do not gate" rather than "nothing available": an owned
container runs our base image, which ships every CLI, and treating unknown as
empty would leave the menu with Shell alone.
Sign up for freeto 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

@timkjr@Ark0N