fix(welcome): gate Claude and Opencode buttons on CLI availability too

Extends the Gemini gating from bb7fb9e to the other welcome-screen
buttons that had the same problem: shown unconditionally even when the
underlying CLI isn't installed.

- Add isClaudeAvailable() (claude-cli-resolver.ts) and GET
  /api/claude/status, mirroring the existing opencode/codex/gemini
  resolvers and status endpoints.
- Opencode already had a working /api/opencode/status the welcome
  screen just wasn't checking; wire it up the same way.
- Refactor loadGeminiAvailability() into a shared
  _loadCliAvailability(buttonId, statusUrl) helper instead of
  duplicating the fetch/try-catch three times.

Run-mode dropdown entries (Opencode/Codex) are intentionally left
unconditional here — follow-up PR.
This commit is contained in:
timkjr
2026-08-04 16:22:21 -05:00
parent 62008fb408
commit 3ea1ea28f0
5 changed files with 38 additions and 5 deletions
+11 -1
View File
@@ -374,9 +374,19 @@ export function registerSystemRoutes(
});
// ═══════════════════════════════════════════════════════════════
// CLI Integrations (OpenCode, Codex, Gemini, Antigravity)
// CLI Integrations (Claude, OpenCode, Codex, Gemini, Antigravity)
// ═══════════════════════════════════════════════════════════════
// ========== Claude ==========
app.get('/api/claude/status', async () => {
const { isClaudeAvailable, findClaudeDir } = await import('../../utils/claude-cli-resolver.js');
return {
available: isClaudeAvailable(),
path: findClaudeDir(),
};
});
// ========== OpenCode ==========
app.get('/api/opencode/status', async () => {