|
1 | | -/* Welcome view — open-repo CTA wired to the dialog plugin + open_repo command. */ |
| 1 | +/* Welcome view — open-repo CTA wired to the dialog plugin + open_repo command, |
| 2 | + * plus the Claude CLI health check (ok / broken / notFound, named states). */ |
2 | 3 |
|
3 | | -import { Show } from "solid-js"; |
| 4 | +import { Show, Switch, Match, createSignal, onMount } from "solid-js"; |
4 | 5 | import { open } from "@tauri-apps/plugin-dialog"; |
5 | 6 | import { appStore } from "../stores/app-store"; |
| 7 | +import { claudeCliStatus } from "../ipc"; |
| 8 | +import type { ClaudeCliStatus } from "../types"; |
6 | 9 |
|
7 | 10 | export function Welcome() { |
8 | 11 | const { store } = appStore; |
| 12 | + const [cli, setCli] = createSignal<ClaudeCliStatus | null>(null); |
| 13 | + |
| 14 | + onMount(() => { |
| 15 | + claudeCliStatus() |
| 16 | + .then(setCli) |
| 17 | + .catch((e) => appStore.pushError(`Claude CLI check failed: ${String(e)}`)); |
| 18 | + }); |
9 | 19 |
|
10 | 20 | async function pickRepo() { |
11 | 21 | const dir = await open({ directory: true, multiple: false, title: "Open a repository" }); |
@@ -45,6 +55,43 @@ export function Welcome() { |
45 | 55 | <Show when={store.lastError}> |
46 | 56 | <div class="welcome-error">{store.lastError}</div> |
47 | 57 | </Show> |
| 58 | + |
| 59 | + <Switch> |
| 60 | + <Match when={cli()?.state === "ok" && cli()}> |
| 61 | + {(ok) => { |
| 62 | + const s = ok() as Extract<ClaudeCliStatus, { state: "ok" }>; |
| 63 | + return <div class="welcome-cli-ok">{s.version} · {s.path}</div>; |
| 64 | + }} |
| 65 | + </Match> |
| 66 | + <Match when={cli()?.state === "notFound" && cli()}> |
| 67 | + {(missing) => ( |
| 68 | + <div class="welcome-cli-warn"> |
| 69 | + <div class="welcome-cli-warn-title">Claude Code CLI not found</div> |
| 70 | + <div>Sessions and indexing need it. Install with either:</div> |
| 71 | + <code>brew install --cask claude-code</code> |
| 72 | + <code>curl -fsSL https://claude.ai/install.sh | bash</code> |
| 73 | + <Show when={!missing().shellEnvResolved}> |
| 74 | + <div class="welcome-cli-warn-note"> |
| 75 | + Your login-shell PATH could not be read, so an existing install outside the |
| 76 | + standard locations may also be invisible to CodeForge. |
| 77 | + </div> |
| 78 | + </Show> |
| 79 | + </div> |
| 80 | + )} |
| 81 | + </Match> |
| 82 | + <Match when={cli()?.state === "broken" && cli()}> |
| 83 | + {(broken) => { |
| 84 | + const s = broken() as Extract<ClaudeCliStatus, { state: "broken" }>; |
| 85 | + return ( |
| 86 | + <div class="welcome-cli-warn"> |
| 87 | + <div class="welcome-cli-warn-title">Claude Code CLI found but not runnable</div> |
| 88 | + <code>{s.path}</code> |
| 89 | + <div class="welcome-cli-warn-note">{s.detail}</div> |
| 90 | + </div> |
| 91 | + ); |
| 92 | + }} |
| 93 | + </Match> |
| 94 | + </Switch> |
48 | 95 | </div> |
49 | 96 |
|
50 | 97 | <style>{` |
@@ -121,6 +168,31 @@ export function Welcome() { |
121 | 168 | word-break: break-word; |
122 | 169 | user-select: text; -webkit-user-select: text; |
123 | 170 | } |
| 171 | + .welcome-cli-ok { |
| 172 | + margin-top: var(--space-5); |
| 173 | + font-size: 10px; font-family: var(--font-mono); |
| 174 | + color: var(--text-tertiary); |
| 175 | + } |
| 176 | + .welcome-cli-warn { |
| 177 | + margin-top: var(--space-5); |
| 178 | + text-align: left; |
| 179 | + display: flex; flex-direction: column; gap: 6px; |
| 180 | + font-size: 11px; |
| 181 | + padding: 10px 12px; border-radius: var(--radius-sm); |
| 182 | + background: rgba(var(--amber-rgb), 0.08); |
| 183 | + border: 1px solid rgba(var(--amber-rgb), 0.2); |
| 184 | + color: var(--text-secondary); |
| 185 | + } |
| 186 | + .welcome-cli-warn-title { color: var(--amber); font-weight: 600; } |
| 187 | + .welcome-cli-warn code { |
| 188 | + font-family: var(--font-mono); font-size: 10.5px; |
| 189 | + padding: 3px 6px; border-radius: var(--radius-sm); |
| 190 | + background: var(--bg-muted); border: 1px solid var(--border); |
| 191 | + color: var(--text); |
| 192 | + user-select: text; -webkit-user-select: text; |
| 193 | + width: fit-content; |
| 194 | + } |
| 195 | + .welcome-cli-warn-note { color: var(--text-tertiary); word-break: break-word; } |
124 | 196 | `}</style> |
125 | 197 | </div> |
126 | 198 | ); |
|
0 commit comments