diff --git a/src/web/public/session-ui.js b/src/web/public/session-ui.js index f13e2043..a2e9d3e1 100644 --- a/src/web/public/session-ui.js +++ b/src/web/public/session-ui.js @@ -441,6 +441,7 @@ Object.assign(CodemanApp.prototype, { // Load history sessions when menu opens if (menu.classList.contains('active')) { this._loadRunModeHistory(); + this._refreshRunModeAvailability(); const close = (ev) => { if (!menu.contains(ev.target)) { menu.classList.remove('active'); @@ -451,6 +452,32 @@ Object.assign(CodemanApp.prototype, { } }, + /** + * Hides run-mode dropdown entries for CLIs that aren't installed, so + * picking one doesn't spawn a session that immediately errors out. + * Shell has no external CLI dependency and is never gated. + */ + async _refreshRunModeAvailability() { + const checks = [ + ['claude', '/api/claude/status'], + ['opencode', '/api/opencode/status'], + ['codex', '/api/codex/status'], + ['gemini', '/api/gemini/status'], + ]; + await Promise.all(checks.map(async ([mode, url]) => { + const btn = document.querySelector(`.run-mode-option[data-mode="${mode}"]`); + if (!btn) return; + try { + const res = await fetch(url); + const env = await res.json(); + const status = env?.success === true ? env.data : env; + btn.style.display = status?.available ? 'flex' : 'none'; + } catch { + btn.style.display = 'none'; + } + })); + }, + async _loadRunModeHistory() { const container = document.getElementById('runModeHistory'); if (!container) return;