import { useState, useEffect } from "react"; import { Box, Text, useInput } from "ink"; import { getAuthStatus, login, isGhInstalled } from "../../github/auth.ts"; export interface GitHubAuthStepProps { onComplete: (auth: { authenticated: boolean; user?: string; skipped: boolean }) => void; onBack: () => void; onCancel: () => void; } type AuthStatus = "checking" | "authenticated" | "not_authenticated" | "gh_not_installed" | "login_failed"; export function GitHubAuthStep({ onComplete, onBack, onCancel }: GitHubAuthStepProps) { const [status, setStatus] = useState("checking"); const [user, setUser] = useState(); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { checkAuth(); }, []); const checkAuth = async () => { setStatus("checking"); setError(null); const ghInstalled = await isGhInstalled(); if (!ghInstalled) { setStatus("gh_not_installed"); return; } try { const authStatus = await getAuthStatus(); if (authStatus.authenticated) { setStatus("authenticated"); setUser(authStatus.user); } else { setStatus("not_authenticated"); } } catch { setStatus("not_authenticated"); } }; const handleLogin = async () => { setLoading(true); setError(null); try { const result = await login(); if (result.success) { setStatus("authenticated"); setUser(result.user); } else { setStatus("login_failed"); setError(result.error || "Login failed"); } } catch { setStatus("login_failed"); setError("An unexpected error occurred"); } finally { setLoading(false); } }; useInput((input, key) => { if (loading) return; if (key.escape || input === "q" || input === "Q") { onCancel(); return; } if (key.backspace || key.delete) { onBack(); return; } if (key.return) { // Complete with current auth state onComplete({ authenticated: status === "authenticated", user, skipped: false, }); return; } // Login if ((input === "l" || input === "L") && (status === "not_authenticated" || status === "login_failed")) { handleLogin(); return; } // Re-login if ((input === "r" || input === "R") && status === "authenticated") { handleLogin(); return; } // Skip if (input === "s" || input === "S") { onComplete({ authenticated: false, user: undefined, skipped: true, }); return; } }); return ( {/* Title */} GitHub Authentication {/* Description */} GitHub integration is optional but recommended for full functionality. {/* Checking status */} {status === "checking" && ( Checking authentication status... )} {/* Authenticated */} {status === "authenticated" && ( Authenticated{user ? ` as ${user}` : ""} You're all set! GitHub features are ready to use. )} {/* Not authenticated */} {status === "not_authenticated" && !loading && ( Not authenticated GitHub CLI (gh) is installed and ready. )} {/* gh not installed */} {status === "gh_not_installed" && ( GitHub CLI (gh) is not installed To enable GitHub features: 1. Install gh CLI from https://cli.github.com 2. Run 'gitforest login' to authenticate 3. Or set GITHUB_TOKEN environment variable )} {/* Login failed */} {status === "login_failed" && !loading && ( Authentication failed {error && ( {error} )} You can try again or skip for now. )} {/* Loading */} {loading && ( Opening browser for authentication... )} {/* Actions */} {!loading && status !== "checking" && ( {status === "not_authenticated" || status === "login_failed" ? ( Press l Login s Skip Enter Continue ) : status === "authenticated" ? ( Press r Re-login s Skip Enter Continue ) : status === "gh_not_installed" ? ( Press s Skip Enter Continue ) : null} Backspace Back q Quit )} ); }