import { invoke, initializeDesktopSurface, isNativeDesktop, isDesktopSurface, isCaptureSurface, prepareMediaURL, } from "./desktop-api"; import { listen } from "@tauri-apps/api/event"; import { AutomaticIndexGate, emptySearchState, LatestLane, semanticAvailable, scopedFilters, SEMANTIC_SETTLE_MS, } from "./search-state"; import type { SemanticPhase, SearchFilters } from "./search-state"; import { fileIcon, icon } from "./icons"; import { SearchMeasurement, measuredFailure, spanDepth, briefMs, } from "./search-performance"; import type { MeasuredResponse, SearchLane } from "./search-performance"; import { displayPath } from "./path-display"; import { AiRevision, aiConfigurationProblem, aiQuestionProblem, aiEndpointLabel, aiSourceEligible, } from "./ai-state"; import type { AiConfiguration } from "./ai-state"; import { literalQuery, renderHighlighted, displayExcerpt, matchExplanation, } from "./match-display"; import "@fontsource-variable/inter/wght.css"; import "./style.css"; import { mediaKind, matchLabel, sourceLabel, seekSeconds, PreviewRevision, } from "./media-display"; interface SearchResult { path: string; filename: string; snippet: string; score: number; match_kind: string; source?: { kind: string; number: number; matched_query?: string }; extraction_error?: string; } interface IndexReport { discovered: number; indexed: number; removed: number; skipped: number; } interface IndexStats { files: number; content_files: number; } interface Settings { version: number; roots: string[]; cpu_threads: number; } interface DesktopStatus { settings: Settings; indexing: boolean; shortcut_status: string; } interface SemanticStatus { model: string; ready: boolean; model_directory: string; worker_ready: boolean; downloading: boolean; embedding: boolean; device_policy: "auto" | "cpu"; error: string | null; downloaded_bytes: number; total_bytes: number; generation: number | null; chunks: number; stale: boolean; pending: number; warming: boolean; media_tools_ready?: boolean; media_setup_error?: string | null; media_failures?: { path: string; message: string }[]; worker_info?: { model?: string; device?: string; runtime?: string; threads?: number; dimensions?: number; media_supported?: boolean; } | null; } interface SearchRequest { id: number; query: string; filters: SearchFilters; started: number; measurement: SearchMeasurement; } document.querySelector("#app")!.innerHTML = `
searchi
Loading your index…
${icon("filter")}All files${icon("chevron")}

Filter your search

${icon("settings")}

Folders & resources

Search automatically uses supported acceleration with CPU fallback.

    Local timing diagnostics for new searches. Queries and file paths are excluded from copied reports.

    Optional AI answers

    Disabled by default. Only an explicit action sends the shown passage to your configured endpoint.

    Endpoint, model and key stay in this app session. The key authenticates requests to your endpoint.

    ${icon("sparkles")}Preparing local semantic search…Local model${icon("chevron")}
    Google EmbeddingGemma 2

    The verified local model downloads automatically on first launch (865 MB). Your files stay on this device.

    READY WHEN YOU ARE

      ${icon("search")}

      Find what matters. Locally.

      Index a folder, then search a filename, phrase, or what you remember.

      `; const element = (id: string) => document.getElementById(id) as T; const query = element("query"); const list = element("results"); const notice = element("notice"); try { element("performance-toggle").checked = localStorage.getItem("searchi-performance-details") === "true"; } catch { /* Diagnostics remain opt-in when storage is unavailable. */ } let results: SearchResult[] = []; let displayedLiteralQuery = literalQuery(""); let displayedCodeScope = false; let explainedSelection = ""; let selected = -1; let requestId = 0; let timer: ReturnType; let indexingActive = false; let semanticStatus: SemanticStatus | null = null; let semanticJobActive = false; let semanticRefreshActive = false; let semanticTimer: ReturnType | undefined; let hybridTimer: ReturnType | undefined; let latestSearch: SearchRequest | null = null; let shownLane: "lexical" | "hybrid" = "lexical"; let folderRevision = 0; let localSemanticError: string | null = null; let querySemanticFailed = false; let previewPath: string | null = null; const previewRevision = new PreviewRevision(); interface PreviewRequest { revision: number; result: SearchResult; } function unloadMedia() { element("media-preview") .querySelectorAll("audio,video") .forEach((player) => { player.pause(); player.removeAttribute("src"); player.load(); }); element("media-preview").replaceChildren(); element("media-preview").hidden = true; element("media-preview-status").hidden = true; } function clearMedia() { previewRevision.clear(); mediaLane.clear(); unloadMedia(); } const mediaLane = new LatestLane( async (request) => { const prepared = await invoke<{ path: string; kind: "image" | "audio" | "video"; }>("prepare_media_preview", { path: request.result.path }); if (!previewRevision.accepts(request.revision)) return; const host = element("media-preview"); const status = element("media-preview-status"); const failed = () => { if (!previewRevision.accepts(request.revision)) return; status.hidden = false; status.textContent = "This format cannot be previewed here. Use Open file to view it in your default application."; }; if (prepared.kind === "image") { const image = document.createElement("img"); image.alt = request.result.filename; image.addEventListener("error", failed, { once: true }); image.src = prepareMediaURL(prepared.path); host.append(image); } else { const player = document.createElement(prepared.kind); player.controls = true; player.preload = "metadata"; player.addEventListener("error", failed, { once: true }); player.addEventListener( "loadedmetadata", () => { if (!previewRevision.accepts(request.revision)) return; const target = seekSeconds(request.result.source); if (target !== undefined) { if (!Number.isFinite(player.duration) || target > player.duration) { status.hidden = false; status.textContent = "The matched timestamp is unavailable in this preview. Use Open file to check the recording."; } else { try { player.currentTime = target; } catch { failed(); } } } }, { once: true }, ); player.src = prepareMediaURL(prepared.path); host.append(player); } host.hidden = false; status.hidden = true; }, (request) => previewRevision.accepts(request.revision), (request, error) => { if (!previewRevision.accepts(request.revision)) return; element("media-preview-status").hidden = false; element("media-preview-status").textContent = `Preview unavailable: ${String(error)}. Use Open file.`; }, ); let displayedRequestId: number | null = null; let expandedError: string | null = null; const reducedMotion = matchMedia("(prefers-reduced-motion: reduce)"); const resultRows = new Map< string, { row: HTMLLIElement; button: HTMLButtonElement; title: HTMLElement; path: HTMLElement; snippet: HTMLElement; kind: HTMLElement; file: HTMLElement; } >(); const automaticIndex = new AutomaticIndexGate(); function refreshEmptySearchState() { if (!latestSearch || latestSearch.id !== requestId || results.length) return; let phase: SemanticPhase; if (querySemanticFailed || localSemanticError || semanticStatus?.error) phase = "unavailable"; else if ( semanticStatus?.embedding || semanticJobActive || indexingActive || (semanticStatus?.ready && semanticStatus.stale && semanticStatus.pending > 0) ) phase = "indexing"; else if (!semanticStatus?.ready) phase = "preparing"; else if (semanticStatus.generation === null) phase = "no-content"; else phase = shownLane === "hybrid" ? "complete" : "pending"; const state = emptySearchState(shownLane, phase); element("empty").querySelector("h2")!.textContent = state.title; element("empty").querySelector("p")!.textContent = state.detail; } function canSearchSemantically() { return semanticAvailable(semanticStatus); } function queueSemanticRefresh(delay = 1000) { clearTimeout(semanticTimer); semanticTimer = setTimeout(() => { void refreshSemanticStatus(); }, delay); } async function buildSemanticIndex() { if (semanticJobActive || indexingActive) return; semanticJobActive = true; localSemanticError = null; element("semantic-status").textContent = "Building your semantic index… Keyword search remains available."; element("semantic-progress").removeAttribute("value"); element("semantic-progress").hidden = false; queueSemanticRefresh(); try { const report = await invoke<{ passages: number; chunks: number }>( "index_embeddings", ); element("semantic-status").textContent = `Semantic search indexed ${report.chunks.toLocaleString()} content segments.`; } catch (error) { localSemanticError = String(error); } finally { semanticJobActive = false; queueSemanticRefresh(0); } } async function refreshSemanticStatus() { if (semanticRefreshActive) { queueSemanticRefresh(); return; } semanticRefreshActive = true; try { const previousReady = canSearchSemantically(); const previousGeneration = semanticStatus?.generation; const status = await invoke("semantic_status"); semanticStatus = status; refreshEmptySearchState(); const error = localSemanticError || status.error; if (error && error !== expandedError) { element("semantic-panel").open = true; expandedError = error; } if (!error) expandedError = null; const progress = element("semantic-progress"); const working = status.downloading || status.warming || status.embedding || semanticJobActive; progress.hidden = !working; progress.removeAttribute("value"); if ( status.downloading && status.total_bytes > 0 && status.downloaded_bytes < status.total_bytes ) { progress.max = status.total_bytes; progress.value = status.downloaded_bytes; } const actualDevice = status.worker_info?.device || (status.device_policy === "cpu" ? "CPU" : "Automatic acceleration"); element("privacy").textContent = `Local · ${actualDevice}`; element("semantic-device").textContent = actualDevice; let message: string; if (error) message = error; else if (status.warming) message = "Preparing Google semantic search on your device…"; else if (status.downloading) message = status.downloaded_bytes >= status.total_bytes ? "Verifying the downloaded Google model…" : `Downloading Google model · ${Math.round(status.downloaded_bytes / 1_000_000)} of ${Math.round(status.total_bytes / 1_000_000)} MB`; else if (status.embedding || semanticJobActive) message = "Building your semantic index… Keyword search remains available."; else if (status.ready && status.chunks > 0) message = `Semantic search ready · ${status.chunks.toLocaleString()} content segments${status.stale ? " · Updates pending" : ""}${status.media_failures?.length ? ` · ${status.media_failures.length} files could not be indexed` : ""}`; else if (status.ready) message = "Google model ready. Index a folder to search by meaning."; else message = "Preparing local semantic search… Keyword search remains available."; element("semantic-status").textContent = message; element("semantic-status").classList.toggle("error", Boolean(error)); element("semantic-detail").textContent = status.worker_info ? `${status.model} · ${status.worker_info.runtime || "Local inference"} · Your files stay on this device.` : "The verified Google model downloads automatically once (865 MB). After setup, inference runs locally."; const mediaDetail = status.media_setup_error ? `Media decoder setup needs attention: ${status.media_setup_error}. Text search remains available.` : status.worker_info && !status.worker_info.media_supported ? "The installed worker needs a media-capable runtime update. Text search remains available." : status.media_tools_ready && status.worker_info?.media_supported ? "Image, audio, and video encoders are available locally." : "Preparing local image, audio, and video support."; element("semantic-detail").textContent += ` ${mediaDetail}`; if (status.media_failures?.length) { element("semantic-detail").textContent += ` ${status.media_failures.length} files could not be indexed. The first issue: ${status.media_failures[0].path}: ${status.media_failures[0].message}. Filename search remains available; rebuild after fixing the file.`; } const retry = element("retry-model"); retry.hidden = !error || status.ready; retry.disabled = working || isCaptureSurface(); const rebuild = element("rebuild-semantic"); rebuild.hidden = !status.ready || (!status.chunks && !status.pending); rebuild.disabled = working || indexingActive || isCaptureSurface(); element("cpu-threads").disabled = working || indexingActive || isCaptureSurface(); if ( !isCaptureSurface() && status.ready && status.stale && status.pending > 0 && !working && !indexingActive ) { const key = `${status.generation}:${status.pending}:${folderRevision}`; if (automaticIndex.claim(key)) { void buildSemanticIndex(); return; } } if ( (!previousReady || previousGeneration !== status.generation) && canSearchSemantically() && latestSearch?.id === requestId ) submitSearch(latestSearch, "hybrid"); if (working || (!status.ready && !error)) queueSemanticRefresh(); } catch (error) { element("semantic-status").textContent = `Semantic search unavailable: ${String(error)}`; element("semantic-status").classList.add("error"); element("retry-model").hidden = false; } finally { semanticRefreshActive = false; } } async function refreshDesktopStatus() { const status = await invoke("desktop_status"); indexingActive = status.indexing; element("shortcut-status").textContent = status.shortcut_status; element("focus-shortcut").textContent = status.shortcut_status.includes( "Super", ) ? "Cmd K" : "Ctrl K"; const threads = element("cpu-threads"); threads.value = String(status.settings.cpu_threads); threads.disabled = isCaptureSurface() || status.indexing || semanticJobActive || Boolean( semanticStatus?.downloading || semanticStatus?.warming || semanticStatus?.embedding, ); element("add-folder").disabled = status.indexing || isCaptureSurface(); const roots = element("roots"); roots.replaceChildren(); for (const root of status.settings.roots) { const item = document.createElement("li"); const path = document.createElement("span"); path.textContent = displayPath(root); path.className = "path"; const reindex = document.createElement("button"); reindex.type = "button"; reindex.textContent = "Reindex"; reindex.disabled = status.indexing || isCaptureSurface(); reindex.addEventListener("click", () => { element("folder-form").hidden = false; element("folder").value = root; element("folder").focus(); }); item.append(path, reindex); roots.append(item); } if (!status.settings.roots.length) { const item = document.createElement("li"); item.textContent = "No folders selected yet."; roots.append(item); } if (status.indexing) element("index-status").textContent = "Indexing active · Search remains available"; return status; } function showError(error: unknown) { notice.textContent = String(error); notice.className = "error"; } interface AiPreview { id: string; text: string; location: string; } interface AiAnswer { text: string; citations: string[]; model: string; } const aiRevision = new AiRevision(); let aiSelectionKey = ""; let aiPrepared: AiPreview | null = null; let aiRunning = false; function aiConfiguration(): AiConfiguration { return { enabled: element("ai-enabled").checked, base_url: element("ai-endpoint").value.trim(), model: element("ai-model").value.trim(), api_key: element("ai-key").value || null, }; } function clearAiAnswer() { element("ai-answer").textContent = ""; element("ai-answer-label").textContent = ""; element("ai-citation").hidden = true; } function updateAiControls() { const config = aiConfiguration(); const panel = element("ai-panel"); panel.hidden = !config.enabled; const result = results[selected]; const eligible = aiSourceEligible( result?.source, Boolean(result && mediaKind(result.filename)), ); const problem = aiConfigurationProblem(config); const blocked = !isNativeDesktop() || Boolean(problem) || !eligible || !aiPrepared || aiRunning; element("ai-summarize").disabled = blocked; element("ai-ask").disabled = blocked || Boolean(aiQuestionProblem(element("ai-question").value)); element("ai-disclosure").textContent = !isNativeDesktop() ? "Optional AI actions are available only in the desktop app." : !eligible ? "Select a result with an indexed text passage to summarize or ask a question." : problem ? `${problem} Configuration stays in this app session.` : `Clicking Summarize or Ask sends the exact passage shown below and, for Ask, your question to ${aiEndpointLabel(config.base_url)}. File names and folder paths aren't added. Your session key authenticates that endpoint.`; element("privacy-summary").textContent = aiRunning && !config.enabled ? "Local search. An earlier optional AI request is finishing." : config.enabled ? "Local search. Optional AI shares the shown passage only when requested." : "Private search. Everything stays on your device."; } const aiPreparation = new LatestLane<{ revision: number; path: string; source: { kind: string; number: number }; }>( async (request) => { const preview = await invoke("prepare_ai_source", { enabled: true, path: request.path, source: request.source, revision: request.revision, }); if (!aiRevision.accepts(request.revision)) return; aiPrepared = preview; element("ai-source-text").textContent = preview.text; element("ai-status").textContent = `Review the passage beginning from ${preview.location}. Only this shown excerpt will be sent.`; updateAiControls(); }, (request) => aiRevision.accepts(request.revision), (_request, error) => { element("ai-status").textContent = String(error); updateAiControls(); }, ); function prepareAiSource() { const result = results[selected]; if ( !aiConfiguration().enabled || !isNativeDesktop() || !result?.source || !aiSourceEligible(result.source, Boolean(mediaKind(result.filename))) ) return; element("ai-status").textContent = "Preparing the selected local passage. Nothing is sent to the endpoint."; aiPreparation.submit({ revision: aiRevision.current(), path: result.path, source: { kind: result.source.kind, number: result.source.number }, }); } function updateAiSelection(key: string) { if (aiSelectionKey !== key) { aiSelectionKey = key; aiRevision.select(key); aiPreparation.clear(); aiPrepared = null; element("ai-source-text").textContent = ""; element("ai-question").value = ""; element("ai-status").textContent = ""; clearAiAnswer(); updateAiControls(); if (element("ai-panel").open) prepareAiSource(); } } async function requestAi(mode: "summary" | "question") { const config = aiConfiguration(); const question = element("ai-question").value.trim(); const problem = aiConfigurationProblem(config) || (mode === "question" ? aiQuestionProblem(question) : null); if (problem || !aiPrepared || !isNativeDesktop() || aiRunning) { element("ai-status").textContent = problem || "Prepare and review the current selected passage first."; return; } const revision = aiRevision.current(); const source = aiPrepared; aiRunning = true; clearAiAnswer(); updateAiControls(); element("ai-status").textContent = `Sending the shown passage${mode === "question" ? " and question" : ""} to ${aiEndpointLabel(config.base_url)}…`; const started = performance.now(); try { const answer = await invoke("generate_ai", { input: { enabled: true, config: { base_url: config.base_url, model: config.model, api_key: config.api_key, }, source_id: source.id, mode, question: mode === "question" ? question : null, }, }); if (!aiRevision.accepts(revision)) return; element("ai-answer").textContent = answer.text; element("ai-answer-label").textContent = `Model-generated ${answer.citations.length ? "draft" : "uncited draft"} · ${answer.model} · ${briefMs(performance.now() - started)} ms. Verify against the passage.`; element("ai-status").textContent = ""; const citation = element("ai-citation"); citation.hidden = !answer.citations.includes("selected"); citation.textContent = `Source: ${source.location}`; } catch (error) { if (aiRevision.accepts(revision)) element("ai-status").textContent = String(error); } finally { aiRunning = false; updateAiControls(); } } element("ai-panel").addEventListener("toggle", () => { if (element("ai-panel").open && !aiPrepared) prepareAiSource(); }); for (const id of ["ai-enabled", "ai-endpoint", "ai-model", "ai-key"]) { element(id).addEventListener("input", () => { aiRevision.invalidate(); aiPreparation.clear(); aiPrepared = null; clearAiAnswer(); element("ai-source-text").textContent = ""; updateAiControls(); if (element("ai-panel").open) prepareAiSource(); }); } element("ai-question").addEventListener("input", () => { aiRevision.invalidate(); clearAiAnswer(); updateAiControls(); if (!aiPrepared && element("ai-panel").open) prepareAiSource(); }); element("ai-clear-key").addEventListener("click", () => { element("ai-key").value = ""; element("ai-key").dispatchEvent(new Event("input")); }); element("ai-summarize").addEventListener("click", () => { void requestAi("summary"); }); element("ai-ask").addEventListener("click", () => { void requestAi("question"); }); element("ai-citation").addEventListener("click", () => { element("ai-source-text").scrollIntoView({ behavior: reducedMotion.matches ? "auto" : "smooth", block: "nearest", }); }); function select(index: number, focus = false) { if (!results.length) return; selected = Math.max(0, Math.min(index, results.length - 1)); const result = results[selected]; list.querySelectorAll("button").forEach((button, i) => { button.classList.toggle("selected", i === selected); button.setAttribute("aria-current", String(i === selected)); button.tabIndex = i === selected ? 0 : -1; if (i === selected && focus) button.focus(); }); element("preview").hidden = false; const selectedIcon = fileIcon(result.filename); element("preview-icon").innerHTML = selectedIcon.html; element("preview-icon").dataset.type = selectedIcon.type; renderHighlighted( element("preview-title"), result.filename, displayedLiteralQuery, ); renderHighlighted( element("preview-path"), displayPath(result.path), displayedLiteralQuery, ); element("preview-kind").textContent = `${matchLabel(result.match_kind)}${result.source ? ` · ${sourceLabel(result.source)}` : ""}`; const media = mediaKind(result.filename); const explanation = matchExplanation(result); const semanticMedia = [ "semantic_image", "semantic_video", "semantic_audio", ].includes(result.match_kind); element("passage-label").textContent = semanticMedia ? "MATCHED MEDIA" : explanation.semanticPassage ? "MATCHED PASSAGE" : "EXTRACTED PASSAGE"; const passageText = result.snippet || (result.extraction_error ? `Content could not be extracted: ${result.extraction_error}` : media ? "Preview the matched media below." : "No extracted text is available for this file."); element("preview-text").classList.toggle("code-passage", displayedCodeScope); renderHighlighted( element("preview-text"), passageText, semanticMedia ? literalQuery("") : displayedLiteralQuery, ); document .querySelector(".passage")! .classList.toggle("semantic-passage", explanation.semanticPassage); element("match-reason").textContent = explanation.reason; element("match-legend").textContent = explanation.legend; const explanationKey = JSON.stringify([ result.path, result.match_kind, result.source?.kind, result.source?.number, displayedLiteralQuery.query, ]); if (explanationKey !== explainedSelection) element("match-details").open = false; explainedSelection = explanationKey; updateAiSelection(explanationKey); element("open-result").title = result.source ? `Open in your default application. The matched location ${sourceLabel(result.source)} is shown in Searchi; default application opening starts at its own location.` : "Open in your default application"; const selection = previewRevision.select( JSON.stringify([result.path, result.source?.kind, result.source?.number]), ); if (selection.changed) { mediaLane.clear(); unloadMedia(); if (media && isDesktopSurface()) { element("media-preview-status").hidden = false; element("media-preview-status").textContent = "Preparing media preview…"; mediaLane.submit({ revision: selection.revision, result }); } } if (previewPath !== result.path) { const passage = document.querySelector(".passage")!; passage.scrollTop = 0; if (!reducedMotion.matches) { passage.getAnimations().forEach((animation) => animation.cancel()); passage.animate( [ { opacity: 0.65, transform: "translateY(3px)" }, { opacity: 1, transform: "translateY(0)" }, ], { duration: 150, easing: "ease-out" }, ); } previewPath = result.path; } } function render() { const scrollTop = list.scrollTop; const retained = new Set(results.map((result) => result.path)); for (const [key, entry] of resultRows) { if (!retained.has(key)) { entry.row.remove(); resultRows.delete(key); } } element("empty").hidden = results.length > 0; if (!results.length) { element("preview").hidden = true; previewPath = null; clearMedia(); updateAiSelection(""); } results.forEach((result, i) => { let entry = resultRows.get(result.path); if (!entry) { const row = document.createElement("li"); if (i < 8) row.className = "new-row"; const button = document.createElement("button"); button.className = "result"; button.type = "button"; const file = document.createElement("span"); file.className = "file-icon"; const title = document.createElement("strong"); const path = document.createElement("span"); path.className = "path"; const snippet = document.createElement("span"); snippet.className = "snippet"; const kind = document.createElement("span"); kind.className = "kind"; button.append(file, title, kind, snippet, path); button.addEventListener("click", () => select(Number(button.dataset.index)), ); row.append(button); entry = { row, button, file, title, path, snippet, kind }; resultRows.set(result.path, entry); } entry.button.dataset.index = String(i); entry.button.title = displayPath(result.path); renderHighlighted(entry.title, result.filename, displayedLiteralQuery); renderHighlighted( entry.path, displayPath(result.path), displayedLiteralQuery, ); const semanticMedia = [ "semantic_image", "semantic_video", "semantic_audio", ].includes(result.match_kind); entry.snippet.classList.toggle("code-snippet", displayedCodeScope); renderHighlighted( entry.snippet, displayExcerpt(result.snippet, displayedLiteralQuery), semanticMedia ? literalQuery("") : displayedLiteralQuery, ); entry.kind.textContent = `${matchLabel(result.match_kind)}${result.source ? ` · ${sourceLabel(result.source)}` : ""}`; const asset = fileIcon(result.filename); if (entry.file.dataset.type !== asset.type) { entry.file.innerHTML = asset.html; entry.file.dataset.type = asset.type; } const positioned = list.children.item(i); if (positioned !== entry.row) list.insertBefore(entry.row, positioned); }); list.scrollTop = scrollTop; } function captureFilters() { const input = (id: string) => element(id).value.trim(); const size = (id: string) => { const text = input(id); if (!text) return null; const value = Number(text); if (!Number.isSafeInteger(value) || value < 0) throw new Error("File size must be a nonnegative whole number of bytes."); return value; }; const duration = (id: string) => { const text = input(id); if (!text) return null; const ms = Math.round(Number(text) * 1000); if (!Number.isFinite(ms) || ms < 0 || ms > 4_294_967_295) throw new Error("Enter a valid nonnegative media duration in seconds."); return ms; }; // Date controls represent the user's local calendar day, including its end. const date = (id: string, end: boolean) => { const text = input(id); if (!text) return null; const stamp = new Date( `${text}T${end ? "23:59:59.999" : "00:00:00"}`, ).getTime(); if (!Number.isFinite(stamp)) throw new Error("Enter a valid modification date."); return stamp; }; return scopedFilters(element("filter-scope").value, { folder: input("filter-folder") || null, extension: input("filter-extension") || null, min_duration_ms: duration("filter-duration-min"), max_duration_ms: duration("filter-duration-max"), min_size: size("filter-min"), max_size: size("filter-max"), modified_after_unix_ms: date("filter-after", false), modified_before_unix_ms: date("filter-before", true), }); } function applyResults( found: SearchResult[], request: SearchRequest, lane: "lexical" | "hybrid", ) { if ( request.id !== requestId || (lane === "lexical" && shownLane === "hybrid") ) return; const renderStarted = performance.now(); const selectedPath = results[selected]?.path; const resultsHadFocus = list.contains(document.activeElement); shownLane = lane; displayedRequestId = request.id; displayedLiteralQuery = literalQuery(request.query); displayedCodeScope = request.filters.code_only === true; results = found; selected = -1; render(); const preserved = results.findIndex((result) => result.path === selectedPath); if (preserved >= 0) select(preserved, resultsHadFocus); else if (results.length) select(0, resultsHadFocus); if (!found.length) refreshEmptySearchState(); request.measurement.displayed( lane, renderStarted, performance.now(), found.length, ); const metric = request.measurement.latestNative(lane); const trace = request.measurement.export(); element("result-summary").textContent = `${found.length} RESULTS · ${lane === "hybrid" ? "KEYWORD + MEANING" : "KEYWORD"} · SEARCH ${briefMs(metric?.total_ms ?? 0)} MS · SHOWN ${briefMs(trace.latest_displayed_ms ?? 0)} MS`; refreshPerformance(request); } function refreshPerformance(request: SearchRequest) { if (request.id !== requestId) return; const panel = element("performance-panel"); panel.hidden = !request.measurement.debug; if (!request.measurement.debug) return; const body = element("performance-detail"); body.replaceChildren(); const report = request.measurement.export(); const append = (text: string, className = "") => { const row = document.createElement("p"); row.textContent = text; row.className = className; body.append(row); return row; }; append( "Times below use separate UI and native clocks. Nested spans and parallel lanes must not be added together. DOM update measures synchronous changes, not paint or deferred media preview loading.", "hint", ); append( `Input debounce ${report.debounce_ms.toFixed(1)} ms · First displayed response ${report.first_results_ms?.toFixed(1) ?? "pending"} ms · Latest displayed ${report.latest_displayed_ms?.toFixed(1) ?? "pending"} ms · Hybrid final ${report.hybrid_final_results_ms?.toFixed(1) ?? "pending / unavailable"} ms`, ); for (const [lane, delay] of Object.entries(report.lane_schedule_ms)) append( `${lane}: scheduled ${delay.toFixed(1)} ms after debounce${lane === "hybrid" ? ` (includes intentional ${SEMANTIC_SETTLE_MS} ms semantic delay or waiting for readiness)` : ""}`, ); for (const attempt of report.attempts) { append( `${attempt.lane} attempt ${attempt.attempt}${attempt.failed ? " · FAILED" : ""}: pending queue ${attempt.queued_ms.toFixed(1)} ms · retry wait ${attempt.retry_wait_ms.toFixed(1)} ms · invoke ${attempt.invoke_ms.toFixed(1)} ms`, "performance-attempt", ); if (!attempt.native) { append("Native timing unavailable for this failure.", "hint"); continue; } append( `Native command ${attempt.native.total_ms.toFixed(1)} ms · ${attempt.native.result_count} results · estimated transport / serialization / scheduling ${attempt.transport_estimate_ms?.toFixed(1)} ms`, "hint", ); if (attempt.native.trace === null) append("Detailed native trace unavailable for this attempt.", "hint"); const spans = attempt.native.trace ?? []; spans.forEach((span, index) => { const counts = Object.entries(span.counters) .map(([name, value]) => name.endsWith("_us") ? `${name.slice(0, -3).replaceAll("_", " ")}: ${(value / 1000).toFixed(3)} ms` : `${name.replaceAll("_", " ")}: ${value}`, ) .join(" · "); const row = append( `${span.name}: ${span.duration_ms.toFixed(2)} ms · starts +${span.start_ms.toFixed(2)} ms${counts ? ` · ${counts}` : ""}`, "performance-span", ); row.style.paddingLeft = `${spanDepth(spans, index) * 14}px`; }); if (attempt.native.dropped_spans) append(`${attempt.native.dropped_spans} native spans dropped.`, "hint"); } for (const display of report.displays) append( `${display.lane} synchronous DOM update ${display.dom_update_ms.toFixed(2)} ms · ${display.count} displayed results`, "hint", ); if (report.dropped_attempts || report.dropped_displays) append( `History capped: ${report.dropped_attempts} attempts and ${report.dropped_displays} displays dropped.`, "hint", ); } async function invokeMeasured(request: SearchRequest, lane: SearchLane) { const attempt = request.measurement.begin(lane, performance.now()); try { const response = await invoke>( lane === "lexical" ? "search_measured" : "hybrid_search_measured", { query: request.query, filters: request.filters, debugPerformance: request.measurement.debug, }, ); request.measurement.completed( attempt, performance.now(), response.metrics, false, ); return response.results; } catch (error) { const failure = measuredFailure(error); request.measurement.completed( attempt, performance.now(), failure?.metrics ?? null, true, ); refreshPerformance(request); throw failure ? new Error(failure.message) : error; } } function submitSearch(request: SearchRequest, lane: SearchLane) { request.measurement.submitted(lane, performance.now()); (lane === "lexical" ? lexicalLane : hybridLane).submit(request); } const isCurrent = (request: SearchRequest) => request.id === requestId; const lexicalLane = new LatestLane( async (request) => { const found = await invokeMeasured(request, "lexical"); applyResults(found, request, "lexical"); }, isCurrent, (_request, error) => { if (shownLane !== "hybrid") { showError(error); element("result-summary").textContent = "KEYWORD SEARCH UNAVAILABLE"; } }, ); const hybridLane = new LatestLane( async (request) => { if (!canSearchSemantically()) return; const found = await invokeMeasured(request, "hybrid"); applyResults(found, request, "hybrid"); }, isCurrent, (_request, error) => { querySemanticFailed = true; refreshEmptySearchState(); element("semantic-status").textContent = `Semantic results unavailable: ${String(error)}. Keyword results remain available.`; queueSemanticRefresh(); }, ); function invalidateSearch() { ++requestId; clearTimeout(timer); clearTimeout(hybridTimer); lexicalLane.clear(); hybridLane.clear(); latestSearch = null; } async function search(inputAt = performance.now()) { invalidateSearch(); querySemanticFailed = false; shownLane = "lexical"; const value = query.value.trim(); if (!value) { element("performance-panel").hidden = true; results = []; displayedLiteralQuery = literalQuery(""); displayedRequestId = null; selected = -1; render(); element("result-summary").textContent = "READY WHEN YOU ARE"; element("empty").querySelector("h2")!.textContent = "Find what matters. Locally."; element("empty").querySelector("p")!.textContent = "Index a folder, then search a filename, phrase, or what you remember."; return; } try { const request: SearchRequest = { id: requestId, query: value, filters: captureFilters(), started: performance.now(), measurement: new SearchMeasurement( inputAt, performance.now(), element("performance-toggle").checked, { model: semanticStatus?.worker_info?.model ?? null, device: semanticStatus?.worker_info?.device ?? null, runtime: semanticStatus?.worker_info?.runtime ?? null, threads: semanticStatus?.worker_info?.threads ?? null, dimensions: semanticStatus?.worker_info?.dimensions ?? null, semantic_ready: canSearchSemantically(), indexed_chunks: semanticStatus?.chunks ?? null, }, ), }; latestSearch = request; refreshPerformance(request); element("result-summary").textContent = "SEARCHING…"; submitSearch(request, "lexical"); hybridTimer = setTimeout(() => { if (isCurrent(request) && canSearchSemantically()) submitSearch(request, "hybrid"); }, SEMANTIC_SETTLE_MS); } catch (error) { showError(error); } } async function refreshStats() { const stats = await invoke("stats"); element("index-status").textContent = `${stats.files.toLocaleString()} files · ${stats.content_files.toLocaleString()} with extracted text`; } query.addEventListener("input", () => { const inputAt = performance.now(); invalidateSearch(); timer = setTimeout(() => void search(inputAt), 60); }); element("performance-toggle").addEventListener("change", () => { const enabled = element("performance-toggle").checked; try { localStorage.setItem("searchi-performance-details", String(enabled)); } catch { /* Session preference still works. */ } void search(); }); element("copy-performance").addEventListener("click", () => { if (!latestSearch?.measurement.debug) return; if (!navigator.clipboard) { element("copy-performance-status").textContent = "Clipboard unavailable. Timings remain visible here."; return; } const report = JSON.stringify(latestSearch.measurement.export(), null, 2); void navigator.clipboard.writeText(report).then( () => { element("copy-performance-status").textContent = "Timing report copied. No query or file paths included."; }, () => { element("copy-performance-status").textContent = "Clipboard unavailable. Timings remain visible here."; }, ); }); element("search-form").addEventListener("submit", (event) => { event.preventDefault(); clearTimeout(timer); void search(); }); element("clear-query").addEventListener("click", () => { query.value = ""; void search(); query.focus(); }); document.querySelectorAll(".popover").forEach((popover) => { popover.addEventListener("toggle", () => { if (popover.open) document .querySelectorAll(".popover") .forEach((other) => { if (other !== popover) other.open = false; }); }); }); document.addEventListener("pointerdown", (event) => { document .querySelectorAll(".popover[open]") .forEach((popover) => { if (!popover.contains(event.target as Node)) popover.open = false; }); }); element("add-folder").addEventListener("click", () => { element("folder-form").hidden = false; element("folder").focus(); }); element("cancel-folder").addEventListener("click", () => { element("folder-form").hidden = true; query.focus(); }); element("browse-folder").addEventListener("click", async () => { try { const folder = await invoke("pick_folder"); if (folder) element("folder").value = folder; } catch (error) { showError(error); } }); element("filters").addEventListener("change", () => { element("scope-label").textContent = element("filter-scope").value === "code" ? "Code" : "All files"; void search(); }); element("retry-model").addEventListener("click", async () => { const button = element("retry-model"); button.disabled = true; localSemanticError = null; element("semantic-status").textContent = "Retrying Google model setup…"; queueSemanticRefresh(); try { await invoke("setup_model"); } catch (error) { localSemanticError = String(error); } finally { button.disabled = false; queueSemanticRefresh(0); } }); element("rebuild-semantic").addEventListener("click", () => { void buildSemanticIndex(); }); async function openSelected(reveal: boolean) { if (selected < 0 || !results[selected]) return; try { await invoke("open_result", { path: results[selected].path, reveal }); } catch (error) { showError(error); } } element("open-result").addEventListener("click", () => { void openSelected(false); }); element("reveal-result").addEventListener("click", () => { void openSelected(true); }); element("cpu-threads").addEventListener("change", async () => { try { await invoke("set_cpu_threads", { threads: Number(element("cpu-threads").value), }); await refreshDesktopStatus(); queueSemanticRefresh(0); } catch (error) { showError(error); await refreshDesktopStatus().catch(showError); } }); element("folder-form").addEventListener("submit", async (event) => { event.preventDefault(); const input = element("folder"); const buttons = element("folder-form").querySelectorAll("button"); buttons.forEach((button) => { button.disabled = true; }); element("add-folder").disabled = true; element("cpu-threads").disabled = true; indexingActive = true; element("index-status").textContent = "Indexing active · Search remains available"; notice.className = ""; notice.textContent = "Indexing folder… Search remains available."; try { const report = await invoke("index_folder", { root: input.value.trim(), }); notice.textContent = `Indexed ${report.indexed} files. ${report.removed} removed; ${report.skipped} skipped.`; element("folder-form").hidden = true; folderRevision++; localSemanticError = null; await refreshStats(); await search(); } catch (error) { showError(error); } finally { buttons.forEach((button) => { button.disabled = false; }); element("add-folder").disabled = false; await refreshDesktopStatus().catch(showError); await refreshStats().catch(showError); queueSemanticRefresh(0); } }); document.addEventListener("keydown", (event) => { if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "k") { event.preventDefault(); query.focus(); query.select(); } if (event.key === "Escape") { clearMedia(); document .querySelectorAll(".popover[open]") .forEach((popover) => { popover.open = false; }); ++requestId; query.value = ""; void search(); query.focus(); } if (event.target === query || list.contains(event.target as Node)) { if ( event.key === "Enter" && results[selected] && displayedRequestId === requestId ) { event.preventDefault(); void openSelected(false); } if (event.key === "ArrowDown" || event.key === "ArrowUp") { event.preventDefault(); select(selected + (event.key === "ArrowDown" ? 1 : -1), true); } } }); async function initializeSurface() { await initializeDesktopSurface(); if (isDesktopSurface()) { if (isCaptureSurface()) { for (const id of [ "add-folder", "open-result", "reveal-result", "browse-folder", "retry-model", "rebuild-semantic", "cpu-threads", "ai-enabled", "ai-endpoint", "ai-model", "ai-key", ]) { const control = element(id); control.disabled = true; control.title = "Unavailable in the read-only documentation capture"; } } void refreshStats().catch(showError); void refreshDesktopStatus().catch(showError); void refreshSemanticStatus(); if (isNativeDesktop()) void listen("focus-search", () => { query.focus(); query.select(); void refreshDesktopStatus().catch(showError); queueSemanticRefresh(0); }).catch(showError); // Poll only during a user-triggered job; idle indexing status does no work. setInterval(() => { if (indexingActive) void refreshDesktopStatus().catch(showError); }, 2000); query.focus(); } else { element("index-status").textContent = "Desktop preview"; element("semantic-status").textContent = "Native semantic search runs in the desktop app."; element("semantic-progress").hidden = true; element("semantic-detail").textContent = "This browser preview does not download models or return simulated search results."; showError("Run the Tauri desktop app to index and search real files."); } } void initializeSurface().catch((error) => { element("index-status").textContent = "Capture unavailable"; element("semantic-status").textContent = "The real local capture engine could not initialize."; showError(error); });