import * as React from "react"; import { api } from "./api/client"; import { Chat } from "./components/Chat"; import { SelectionScreen } from "./components/selection/SelectionScreen"; import { usePathCompletion } from "./components/selection/usePathCompletion"; import "./App.css"; function App() { const [projectPath, setProjectPath] = React.useState(null); const [isCheckingProject, setIsCheckingProject] = React.useState(true); const [errorMsg, setErrorMsg] = React.useState(null); const [pathInput, setPathInput] = React.useState(""); const [isOpening, setIsOpening] = React.useState(false); const [knownProjects, setKnownProjects] = React.useState([]); const [homeDir, setHomeDir] = React.useState(null); React.useEffect(() => { api .getCurrentProject() .then((path) => { if (path) { setProjectPath(path); } }) .catch((error) => console.error(error)) .finally(() => { setIsCheckingProject(false); }); }, []); React.useEffect(() => { api .getKnownProjects() .then((projects) => setKnownProjects(projects)) .catch((error) => console.error(error)); }, []); React.useEffect(() => { let active = true; api .getHomeDirectory() .then((home) => { if (!active) return; setHomeDir(home); setPathInput((current) => { if (current.trim()) { return current; } const initial = home.endsWith("/") ? home : `${home}/`; return initial; }); }) .catch((error) => { console.error(error); }); return () => { active = false; }; }, []); const { matchList, selectedMatch, suggestionTail, completionError, currentPartial, setSelectedMatch, acceptSelectedMatch, acceptMatch, closeSuggestions, } = usePathCompletion({ pathInput, setPathInput, homeDir, listDirectoryAbsolute: api.listDirectoryAbsolute, }); async function openProject(path: string) { const trimmedPath = path.trim(); if (!trimmedPath) { setErrorMsg("Please enter a project path."); return; } try { setErrorMsg(null); setIsOpening(true); const confirmedPath = await api.openProject(trimmedPath); setProjectPath(confirmedPath); } catch (e) { console.error(e); const message = e instanceof Error ? e.message : typeof e === "string" ? e : "An error occurred opening the project."; setErrorMsg(message); } finally { setIsOpening(false); } } function handleOpen() { void openProject(pathInput); } async function handleForgetProject(path: string) { try { await api.forgetKnownProject(path); setKnownProjects((prev) => prev.filter((p) => p !== path)); } catch (error) { console.error(error); } } async function closeProject() { try { await api.closeProject(); setProjectPath(null); } catch (e) { console.error(e); } } function handlePathInputKeyDown( event: React.KeyboardEvent, ) { if (event.key === "ArrowDown") { if (matchList.length > 0) { event.preventDefault(); setSelectedMatch((selectedMatch + 1) % matchList.length); } } else if (event.key === "ArrowUp") { if (matchList.length > 0) { event.preventDefault(); setSelectedMatch( (selectedMatch - 1 + matchList.length) % matchList.length, ); } } else if (event.key === "Tab") { if (matchList.length > 0) { event.preventDefault(); acceptSelectedMatch(); } } else if (event.key === "Escape") { event.preventDefault(); closeSuggestions(); } else if (event.key === "Enter") { handleOpen(); } } if (isCheckingProject) { return null; } return (
{!projectPath ? ( ) : (
)} {errorMsg && (

Error: {errorMsg}

)}
); } export default App;