/** * `ProjectContextPanel` — edits the shared project context stored in * `.ideai/CONTEXT.md`. * * This context is injected into every agent launch before the agent persona, * regardless of the selected AI profile/model. */ import { useEffect, useState } from "react"; import type { GatewayError } from "@/domain"; import { Button, Panel, Spinner, cn } from "@/shared"; import { useGateways } from "@/app/di"; export interface ProjectContextPanelProps { /** Project whose `.ideai/CONTEXT.md` should be edited. */ projectId: string; } function describe(e: unknown): string { if (e && typeof e === "object" && "message" in e) { return String((e as GatewayError).message); } return String(e); } export function ProjectContextPanel({ projectId }: ProjectContextPanelProps) { const { project } = useGateways(); const [content, setContent] = useState(""); const [savedContent, setSavedContent] = useState(""); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; setBusy(true); setError(null); project .readProjectContext(projectId) .then((text) => { if (!cancelled) { setContent(text); setSavedContent(text); } }) .catch((e) => { if (!cancelled) setError(describe(e)); }) .finally(() => { if (!cancelled) setBusy(false); }); return () => { cancelled = true; }; }, [project, projectId]); async function save() { setBusy(true); setError(null); try { await project.updateProjectContext(projectId, content); setSavedContent(content); } catch (e) { setError(describe(e)); } finally { setBusy(false); } } const dirty = content !== savedContent; return ( {error && (

{error}

)}
.ideai/CONTEXT.md