import React, { useEffect, useMemo, useState } from "react"; import { createRoot } from "react-dom/client"; import { api } from "./api"; import "./styles.css"; function getSessionId() { const existing = localStorage.getItem("kyr_session_id"); if (existing) return existing; const created = `session:${crypto.randomUUID()}`; localStorage.setItem("kyr_session_id", created); return created; } function formatTtl(seconds) { if (!seconds) return "temporary"; const minutes = Math.round(seconds / 60); return `${minutes} min`; } function shortSessionId(sessionId) { return sessionId?.replace("session:", "").slice(0, 8) || "unknown"; } function clearStoredAuth() { localStorage.removeItem("kyr_access_token"); localStorage.removeItem("kyr_refresh_token"); localStorage.removeItem("kyr_user"); } function groundednessLabel(status) { if (status === "grounded") return "Grounded"; if (status === "partially_grounded") return "Partially grounded"; return "Insufficient evidence"; } function App() { const [sessionId, setSessionId] = useState(getSessionId); const [config, setConfig] = useState(null); const [status, setStatus] = useState(null); const [user, setUser] = useState(() => { const raw = localStorage.getItem("kyr_user"); return raw ? JSON.parse(raw) : null; }); const [authMode, setAuthMode] = useState("sign-in"); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [sourceUrl, setSourceUrl] = useState(""); const [files, setFiles] = useState([]); const [query, setQuery] = useState(""); const [topK, setTopK] = useState(5); const [threshold, setThreshold] = useState(0.3); const [documents, setDocuments] = useState([]); const [chunks, setChunks] = useState([]); const [chatQuestion, setChatQuestion] = useState(""); const [answer, setAnswer] = useState(""); const [message, setMessage] = useState(""); const [busy, setBusy] = useState(""); const [activeJob, setActiveJob] = useState(null); const signedIn = Boolean(user); useEffect(() => { bootstrapSession(); }, []); async function bootstrapSession() { const token = localStorage.getItem("kyr_access_token"); if (token) { try { const current = await api.me(); const currentUser = current.user || current; localStorage.setItem("kyr_user", JSON.stringify(currentUser)); setUser(currentUser); } catch { clearStoredAuth(); setUser(null); setMessage("Your saved sign-in expired. Please sign in again."); } } await refreshBasics(); } async function refreshBasics() { const [configData, statusData] = await Promise.all([api.config(), api.status(sessionId).catch(() => null)]); setConfig(configData); setStatus(statusData); } async function runAction(label, action) { setBusy(label); setMessage(""); try { await action(); await refreshBasics(); } catch (error) { setMessage(error.message); } finally { setBusy(""); } } async function waitForJob(jobId) { let latest = null; for (;;) { latest = await api.job(jobId, sessionId); setActiveJob(latest); if (latest.status === "completed") { setMessage( `${latest.message}. ${latest.chunks_indexed} chunks indexed. Vectors expire in ${formatTtl(config?.session_ttl_seconds)}.`, ); return latest; } if (latest.status === "failed") { throw new Error(latest.error || latest.message || "Ingestion failed."); } await new Promise((resolve) => setTimeout(resolve, 1500)); } } async function handleAuth(event) { event.preventDefault(); await runAction(authMode === "sign-in" ? "Signing in" : "Creating account", async () => { const redirectTo = window.location.origin; const result = authMode === "sign-in" ? await api.signIn(email, password) : await api.signUp(email, password, redirectTo); const session = result.session || result; if (session?.access_token) { localStorage.setItem("kyr_access_token", session.access_token); localStorage.setItem("kyr_refresh_token", session.refresh_token || ""); localStorage.setItem("kyr_user", JSON.stringify(session.user)); setUser(session.user); setMessage("Signed in."); } else if (result.confirmation_required) { setMessage("Account created. Check your email if Supabase requires confirmation, then sign in."); } }); } async function handleSignOut() { await runAction("Signing out", async () => { await api.signOut().catch(() => null); clearStoredAuth(); setUser(null); setDocuments([]); setChunks([]); setAnswer(""); }); } function handleNewSession() { const created = `session:${crypto.randomUUID()}`; localStorage.setItem("kyr_session_id", created); setSessionId(created); setDocuments([]); setChunks([]); setAnswer(""); setActiveJob(null); api.status(created).then(setStatus).catch(() => null); setMessage("Started a fresh anonymous workspace. Re-index your source before searching."); } async function handleIngestSource(event) { event.preventDefault(); if (!sourceUrl.trim()) { setMessage("Paste a public source link first."); return; } await runAction("Indexing source", async () => { const result = await api.ingestSource(sourceUrl.trim(), sessionId); setMessage("Ingestion job queued. You can keep using the page while it runs."); await waitForJob(result.job_id); }); } async function handleUpload(event) { event.preventDefault(); if (!files.length) { setMessage("Choose at least one file first."); return; } await runAction("Indexing uploads", async () => { const result = await api.uploadFiles(files, sessionId); setMessage("Upload ingestion job queued. You can keep using the page while it runs."); setFiles([]); await waitForJob(result.job_id); }); } async function handleSearch(event) { event.preventDefault(); if (!query.trim()) { setMessage("Enter a search question first."); return; } await runAction("Searching", async () => { const result = await api.search({ query: query.trim(), sessionId, topK, similarityThreshold: threshold, }); setDocuments(result.documents || []); setChunks(result.chunks || []); setAnswer(""); setMessage(result.count ? `Found ${result.count} relevant documents.` : "No matching documents found."); }); } async function handleChat(event) { event.preventDefault(); if (!chatQuestion.trim()) { setMessage("Ask a follow-up question first."); return; } await runAction("Asking model", async () => { const result = await api.chat(chatQuestion.trim(), chunks); setAnswer(result); }); } const metrics = useMemo( () => [ ["Indexed chunks", status?.total_chunks ?? "..."], ["Vector DB", config?.vector_backend ?? "..."], ["Embeddings", config?.embedding_provider ?? "..."], ["Chat", config?.chat_provider ?? "..."], ], [config, status], ); return (
K
KnowYourRepo Retrieval workspace
{signedIn ? user.email || "Signed in" : "Anonymous session"} Workspace {shortSessionId(sessionId)} {config?.session_ttl_seconds ? `${formatTtl(config.session_ttl_seconds)} vector TTL` : "Temporary vectors"}
Session workspace

Repository Intelligence

Index a source, search its chunks, and ask grounded follow-up questions.

{metrics.map(([label, value]) => (
{label} {value}
))}
{!signedIn && (
Anonymous Workspace

Search scope: {shortSessionId(sessionId)}

)}
{message &&
{message}
} {busy &&
{busy}...
} {activeJob && }
Sources

Build the temporary index

Anonymous GitHub repositories up to {config?.anonymous_repo_limit_mb ?? 100} MB do not require sign-in.

Public GitHub repository or Google Drive link

setSourceUrl(event.target.value)} placeholder="https://github.com/owner/repo or Drive folder link" />

PDF, TXT, DOCX, or Markdown

setFiles(Array.from(event.target.files || []))} />
Search

Find relevant files

setQuery(event.target.value)} placeholder="Ask about a feature, class, topic, policy, or concept..." />
Chat

Ask retrieved context

setChatQuestion(event.target.value)} placeholder="What should I know from the returned documents?" />
{answer && }
Results

Retrieved files

{documents.length} documents
); } function AnswerPanel({ answer }) { const payload = typeof answer === "string" ? { answer, confidence: "medium", groundedness: { status: "partially_grounded" } } : answer; const status = payload?.groundedness?.status || "insufficient_evidence"; const unsupported = payload?.groundedness?.unsupported_claims || []; const citations = payload?.citations || []; return (
{groundednessLabel(status)} Confidence: {payload?.confidence || "low"} {payload?.corrected && Self-corrected}

{payload?.answer || "No answer returned."}

{citations.length > 0 && (
Evidence {citations.map((citation, index) => (
{citation.filename} ยท chunk {citation.chunk_index} {citation.quote &&

{citation.quote}

}
))}
)} {unsupported.length > 0 && (
Unsupported claims removed
)}
); } function AccountCard({ signedIn, user, authMode, setAuthMode, email, setEmail, password, setPassword, onAuth, onSignOut, config, }) { if (signedIn) { return ( ); } return ( ); } function JobCard({ job }) { const statusText = job.status.charAt(0).toUpperCase() + job.status.slice(1); return (
Ingestion Job

{statusText}

{job.message}

{job.progress}%
{job.files_indexed || 0} files {job.chunks_indexed || 0} chunks {job.kind}
{job.error &&
{job.error}
}
); } function Results({ documents }) { if (!documents.length) return null; return (
{documents.map((doc) => (

{doc.filename}

relevance {Number(doc.relevance_score).toFixed(3)} - {doc.num_matching_chunks} matching chunks

{doc.metadata?.source_url && ( Open source )}
{(doc.chunks || []).map((chunk, index) => (
excerpt {index + 1} - similarity {Number(chunk.similarity).toFixed(3)}

{chunk.text}

))}
))}
); } createRoot(document.getElementById("root")).render();