import React, { useEffect, useState } from "react"; import { ChevronDown, RefreshCw, RotateCcw } from "lucide-react"; import { useI18n } from "../../../../application/i18n/I18nProvider"; import { Button } from "../../../ui/button"; import { cn } from "../../../../lib/utils"; import type { AgentPathInfo } from "./types"; import { parseEnvLines, serializeEnvLines } from "./claudeConfigEnv"; export const ClaudeCodeCard: React.FC<{ pathInfo: AgentPathInfo | null; isResolvingPath: boolean; customPath: string; onCustomPathChange: (path: string) => void; onRecheckPath: () => void; onResetPath: () => void; configDir: string; onConfigDirChange: (value: string) => void; settingsPath: string; onSettingsPathChange: (value: string) => void; envText: string; onEnvTextChange: (value: string) => void; }> = ({ pathInfo, isResolvingPath, customPath, onCustomPathChange, onRecheckPath, onResetPath, configDir, onConfigDirChange, settingsPath, onSettingsPathChange, envText, onEnvTextChange, }) => { const { t } = useI18n(); const found = pathInfo?.available; // Collapsed by default; auto-expand when the user already has config so it // isn't hidden. Local UI state — not persisted. const [configOpen, setConfigOpen] = useState( () => Boolean(configDir.trim() || settingsPath.trim() || envText.trim()), ); // The env editor keeps the raw text the user types. Persisting parses it into // a record (dropping incomplete lines), so binding the textarea directly to // the persisted value would erase a key the moment it's typed before its "=". // Only resync from the persisted value when it changes for some reason other // than our own parse→serialize round-trip. const [envDraft, setEnvDraft] = useState(envText); useEffect(() => { setEnvDraft((prev) => serializeEnvLines(parseEnvLines(prev)) === envText ? prev : envText, ); }, [envText]); const statusText = isResolvingPath ? t('ai.claude.detecting') : found ? t('ai.claude.detected') : t('ai.claude.notFound'); const statusClassName = isResolvingPath ? "text-muted-foreground" : found ? "text-emerald-500" : "text-amber-500"; return (

{t('ai.claude.description')}

{statusText}
{found && (
{t('ai.claude.path')} {pathInfo.path} {pathInfo.version && ( <> | {pathInfo.version} )}
)} {!isResolvingPath && (
{!found && (

{t('ai.claude.notFoundHint')}

)}
onCustomPathChange(e.target.value)} placeholder={t('ai.claude.customPathPlaceholder')} className="flex-1 h-8 rounded-md border border-input bg-background px-3 text-sm font-mono placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" />
)} {/* Authentication & config (optional, collapsible) */}
{configOpen && (
onConfigDirChange(e.target.value)} placeholder={t('ai.claude.configDir.placeholder')} className="w-full h-8 rounded-md border border-input bg-background px-3 text-sm font-mono placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" />

{t('ai.claude.configDir.hint')}

onSettingsPathChange(e.target.value)} placeholder={t('ai.claude.settings.placeholder')} className="w-full h-8 rounded-md border border-input bg-background px-3 text-sm font-mono placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" />

{t('ai.claude.settings.hint')}