import { Dialog } from "@astryxdesign/core/Dialog"; import { RefreshCw, X } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import type { WebBackgroundTerminalDetail } from "../../../../../extensions/shared/web-observer-registry.ts"; import type { WebProjectTrustStatus } from "../../../../runtime/trust-status.ts"; import type { WebProviderAuthProjection } from "../../../../runtime/types.ts"; import { WebClient } from "../../protocol/client.ts"; export interface InspectionTarget { sessionId: string; sessionPath: string; cwd: string; model: string; modelKey?: string; terminalId?: string; } interface InspectionData { thinking?: { level: string; available: readonly string[] }; trust?: WebProjectTrustStatus; auth?: WebProviderAuthProjection; terminal?: WebBackgroundTerminalDetail; errors: string[]; } export function InspectionPanel({ target, onClose, }: { target: InspectionTarget; onClose: () => void; }) { const { t } = useTranslation(); const client = useMemo(() => new WebClient(), []); const [revision, refresh] = useState(0); const [data, setData] = useState(null); const [updatedAt, setUpdatedAt] = useState(null); // biome-ignore lint/correctness/useExhaustiveDependencies: revision explicitly triggers a manual refresh. useEffect(() => { const controller = new AbortController(); setData(null); setUpdatedAt(null); const read = async () => { const next: InspectionData = { errors: [] }; if (target.terminalId) { try { const response = await client.terminalDetail( target.sessionId, target.terminalId, controller.signal, ); if ( response.sessionId !== target.sessionId || response.detail.id !== target.terminalId ) { throw new Error(t("inspectionChanged")); } next.terminal = response.detail; } catch (error) { next.errors.push( error instanceof Error ? error.message : t("inspectionUnavailable"), ); } } else { const [thinking, trust, auth] = await Promise.allSettled([ client.thinking(target.sessionId, controller.signal), client.trust(target.sessionId, controller.signal), client.providerAuth(target.sessionId, controller.signal), ]); if ( thinking.status === "fulfilled" && thinking.value.sessionId === target.sessionId ) next.thinking = thinking.value; else next.errors.push(t("thinkingUnavailable")); if ( trust.status === "fulfilled" && (trust.value.workspace === undefined || trust.value.workspace === target.cwd) ) next.trust = trust.value; else next.errors.push(t("trustUnavailable")); if (auth.status === "fulfilled") next.auth = auth.value; else next.errors.push(t("authUnavailable")); } if (controller.signal.aborted) return; setData(next); setUpdatedAt(new Date().toLocaleTimeString()); }; void read(); return () => controller.abort(); }, [client, target, revision, t]); const title = target.terminalId ? t("terminalDetails") : t("runtimeStatus"); const terminal = data?.terminal; return ( !open && onClose()} width={640} aria-label={title} >

{title}

{target.cwd}

{!data ? (

{t("inspectionLoading")}

) : ( <> {data.errors.map((error) => (

{error}

))} {terminal ? ( <>

{terminal.title || terminal.id}

{t("executionState")}
{t(`execution_${terminal.status}`, { defaultValue: terminal.status, })}
{t("terminalCommand")}
{terminal.command}
{t("terminalDirectory")}
{terminal.cwd}
{t("startedAt")}
{new Date(terminal.createdAt).toLocaleString()}
{terminal.exitCode !== undefined && ( <>
{t("exitCode")}
{terminal.exitCode}
)}
{terminal.errorText && (

{terminal.errorText}

)} {terminal.truncated && (

{t("detailTruncated")}

)}
{(["stdout", "stderr"] as const).map((stream) => (

{stream === "stdout" ? t("standardOutput") : t("standardError")}

                      {terminal[stream].text || t("noOutput")}
                    
{terminal[stream].truncated && (

{t("outputTruncated", { count: terminal[stream].omittedBytes, })}

)} {terminal[stream].recoveryAvailable && (

{t("outputRecovery")}

)}
))} ) : ( !target.terminalId && ( <>

{t("modelAndThinking")}

{t("selectedModel")}
{target.model || t("noModels")}
{t("thinkingLevel")}
{data.thinking?.level ?? t("unknownState")}
{Boolean(data.thinking?.available.length) && ( <>
{t("availableThinking")}
{data.thinking?.available.join(" ยท ")}
)}

{t("projectTrust")}

{t(`trust_${data.trust?.state ?? "unknown"}`)}

{data.trust?.refreshRequired === true && (

{t("trustRefreshNeeded")}

)}

{t("providerAvailability")}

{data.auth?.providers.map((provider) => (
{provider.name || provider.id} {provider.configured ? t("credentialConfigured") : t("credentialMissing")}
))} {data.auth && !data.auth.providers.length && (

{t("noProviders")}

)} {data.auth?.truncation.truncated && (

{t("providersBounded")}

)}

{t("authNotVerified")}

{t("configurationViaPi")}

) )}

{t("statusCaptured", { time: updatedAt })}

)}
); }