import { QueryClient, QueryClientProvider, useQueryClient } from "@tanstack/react-query"; import { useEffect, useRef } from "react"; import ChatView from "./components/ChatView"; import DiffPanel from "./components/DiffPanel"; import Sidebar from "./components/Sidebar"; import { isElectron } from "./env"; import { DEFAULT_MODEL } from "./model-logic"; import { StoreProvider, useStore } from "./store"; import { DEFAULT_THREAD_TERMINAL_HEIGHT, DEFAULT_THREAD_TERMINAL_ID } from "./types"; import { onServerWelcome } from "./wsNativeApi"; import { useNativeApi } from "./hooks/useNativeApi"; import { AnchoredToastProvider, ToastProvider } from "./components/ui/toast"; import { invalidateGitQueries } from "./lib/gitReactQuery"; function EventRouter() { const api = useNativeApi(); const { dispatch } = useStore(); const queryClient = useQueryClient(); const activeAssistantItemRef = useRef(null); useEffect(() => { if (!api) return; return api.providers.onEvent((event) => { if (event.method === "turn/completed") { void invalidateGitQueries(queryClient); } dispatch({ type: "APPLY_EVENT", event, activeAssistantItemRef, }); }); }, [api, dispatch, queryClient]); useEffect(() => { if (!api) return; return api.terminal.onEvent((event) => { dispatch({ type: "APPLY_TERMINAL_EVENT", event, }); }); }, [api, dispatch]); return null; } function AutoProjectBootstrap() { const { state, dispatch } = useStore(); const bootstrappedRef = useRef(false); useEffect(() => { // Browser mode bootstraps from server welcome. // Electron bootstraps from persisted projects via DesktopProjectBootstrap. if (isElectron) return; return onServerWelcome((payload) => { if (bootstrappedRef.current) return; // Don't create duplicate projects for the same cwd const existing = state.projects.find((p) => p.cwd === payload.cwd); if (existing) { bootstrappedRef.current = true; // Ensure a thread is active const existingThread = state.threads.find((t) => t.projectId === existing.id); if (existingThread && !state.activeThreadId) { dispatch({ type: "SET_ACTIVE_THREAD", threadId: existingThread.id, }); } return; } bootstrappedRef.current = true; // Create project + thread from server cwd const projectId = crypto.randomUUID(); dispatch({ type: "ADD_PROJECT", project: { id: projectId, name: payload.projectName, cwd: payload.cwd, model: DEFAULT_MODEL, expanded: true, }, }); dispatch({ type: "ADD_THREAD", thread: { id: crypto.randomUUID(), codexThreadId: null, projectId, title: "New thread", model: DEFAULT_MODEL, terminalOpen: false, terminalHeight: DEFAULT_THREAD_TERMINAL_HEIGHT, terminalIds: [DEFAULT_THREAD_TERMINAL_ID], runningTerminalIds: [], activeTerminalId: DEFAULT_THREAD_TERMINAL_ID, terminalGroups: [ { id: `group-${DEFAULT_THREAD_TERMINAL_ID}`, terminalIds: [DEFAULT_THREAD_TERMINAL_ID], }, ], activeTerminalGroupId: `group-${DEFAULT_THREAD_TERMINAL_ID}`, session: null, messages: [], events: [], error: null, createdAt: new Date().toISOString(), branch: null, worktreePath: null, }, }); }); }, [state.projects, state.threads, state.activeThreadId, dispatch]); return null; } function DesktopProjectBootstrap() { const api = useNativeApi(); const { dispatch } = useStore(); const bootstrappedRef = useRef(false); useEffect(() => { if (!isElectron || !api || bootstrappedRef.current) return; let disposed = false; let retryDelayMs = 500; let retryTimer: ReturnType | null = null; const attemptBootstrap = async () => { try { const projects = await api.projects.list(); if (disposed) return; dispatch({ type: "SYNC_PROJECTS", projects: projects.map((project) => ({ id: project.id, name: project.name, cwd: project.cwd, model: DEFAULT_MODEL, expanded: true, })), }); bootstrappedRef.current = true; } catch { if (disposed) return; retryTimer = setTimeout(() => { retryTimer = null; void attemptBootstrap(); }, retryDelayMs); retryDelayMs = Math.min(retryDelayMs * 2, 5_000); } }; void attemptBootstrap(); return () => { disposed = true; if (retryTimer) { clearTimeout(retryTimer); } }; }, [api, dispatch]); return null; } function Layout() { const api = useNativeApi(); const { state } = useStore(); if (!api) { return (

Connecting to T3 Code server...

); } return (
{state.diffOpen && }
); } const queryClient = new QueryClient(); export default function App() { return ( ); }