mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-07 16:09:43 +02:00
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:
@@ -26,6 +26,15 @@ const CLAUDE_SEARCH_DIRS = [
|
|||||||
/** Cached directory containing the claude binary (empty string = searched but not found) */
|
/** Cached directory containing the claude binary (empty string = searched but not found) */
|
||||||
let _claudeDir: string | null = null;
|
let _claudeDir: string | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the Claude CLI binary can be located (via `which` or one of
|
||||||
|
* the common install directories). Mirrors `isGeminiAvailable`/`isOpenCodeAvailable`/
|
||||||
|
* `isCodexAvailable` in the sibling resolvers.
|
||||||
|
*/
|
||||||
|
export function isClaudeAvailable(): boolean {
|
||||||
|
return findClaudeDir() !== null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the directory containing the `claude` binary.
|
* Finds the directory containing the `claude` binary.
|
||||||
* Checks `which claude` first, then falls back to common install locations.
|
* Checks `which claude` first, then falls back to common install locations.
|
||||||
|
|||||||
@@ -311,11 +311,11 @@
|
|||||||
<h1 class="welcome-title">Codeman</h1>
|
<h1 class="welcome-title">Codeman</h1>
|
||||||
<p class="welcome-desc">Manage AI Coding tools in persistent tmux sessions.</p>
|
<p class="welcome-desc">Manage AI Coding tools in persistent tmux sessions.</p>
|
||||||
<div class="welcome-actions">
|
<div class="welcome-actions">
|
||||||
<button class="welcome-btn welcome-btn-claude" onclick="app.setRunMode('claude'); app.runClaude()">
|
<button class="welcome-btn welcome-btn-claude" id="welcomeClaudeBtn" style="display: none;" onclick="app.setRunMode('claude'); app.runClaude()">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
||||||
Run Claude Code
|
Run Claude Code
|
||||||
</button>
|
</button>
|
||||||
<button class="welcome-btn welcome-btn-opencode" onclick="app.setRunMode('opencode'); app.runOpenCode()">
|
<button class="welcome-btn welcome-btn-opencode" id="welcomeOpencodeBtn" style="display: none;" onclick="app.setRunMode('opencode'); app.runOpenCode()">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
||||||
Run OpenCode
|
Run OpenCode
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -695,10 +695,22 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async loadGeminiAvailability() {
|
async loadGeminiAvailability() {
|
||||||
const btn = document.getElementById('welcomeGeminiBtn');
|
await this._loadCliAvailability('welcomeGeminiBtn', '/api/gemini/status');
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadClaudeAvailability() {
|
||||||
|
await this._loadCliAvailability('welcomeClaudeBtn', '/api/claude/status');
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadOpencodeAvailability() {
|
||||||
|
await this._loadCliAvailability('welcomeOpencodeBtn', '/api/opencode/status');
|
||||||
|
},
|
||||||
|
|
||||||
|
async _loadCliAvailability(buttonId, statusUrl) {
|
||||||
|
const btn = document.getElementById(buttonId);
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/gemini/status');
|
const res = await fetch(statusUrl);
|
||||||
const env = await res.json();
|
const env = await res.json();
|
||||||
const status = env?.success === true ? env.data : env;
|
const status = env?.success === true ? env.data : env;
|
||||||
btn.style.display = status?.available ? 'flex' : 'none';
|
btn.style.display = status?.available ? 'flex' : 'none';
|
||||||
|
|||||||
@@ -1195,6 +1195,8 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
if (overlay) {
|
if (overlay) {
|
||||||
overlay.classList.add('visible');
|
overlay.classList.add('visible');
|
||||||
this.loadTunnelStatus();
|
this.loadTunnelStatus();
|
||||||
|
this.loadClaudeAvailability();
|
||||||
|
this.loadOpencodeAvailability();
|
||||||
this.loadGeminiAvailability();
|
this.loadGeminiAvailability();
|
||||||
this.loadHistorySessions();
|
this.loadHistorySessions();
|
||||||
this.initSearchPanel();
|
this.initSearchPanel();
|
||||||
|
|||||||
@@ -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 ==========
|
// ========== OpenCode ==========
|
||||||
|
|
||||||
app.get('/api/opencode/status', async () => {
|
app.get('/api/opencode/status', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user