import type { ReactNode } from "react"; import { useState } from "react"; import { useExternalStoreSnapshot } from "@tutti-os/ui-react-hooks"; import { Button, CheckIcon, CopyIcon, RefreshIcon, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, cn } from "@tutti-os/ui-system"; import { AgentSetupDialog, AgentSetupStepIcon, type AgentSetupStepStatus } from "../../../shared/agentEnv/AgentSetupDialog.tsx"; import { useAgentTargetSetupController } from "../../../shared/agentEnv/agentTargetSetupController.tsx"; import { resolveAgentErrorPresentation } from "../../../shared/agentEnv/agentErrorPresentation.ts"; import { useAgentVisibleErrorPresentation } from "../../../shared/visibleError/AgentVisibleErrorPresentationContext.tsx"; import { useAgentHostApi } from "../../../agentActivityHost.tsx"; import type { AgentHostAgentTargetSetupSnapshot } from "../../../host/agentHostApi.ts"; import { useTranslation } from "../../../i18n/index.ts"; import styles from "../AgentGUINode.styles.ts"; export interface AgentTargetSetupGateProps { children?: ReactNode; carouselMountedExternally: boolean; dialogOwner?: boolean; gateVisible?: boolean; } export function AgentTargetSetupGate({ children, carouselMountedExternally, dialogOwner = false, gateVisible = true }: AgentTargetSetupGateProps): React.JSX.Element { const controller = useAgentTargetSetupController(); const { scope } = useAgentVisibleErrorPresentation(); const { terminalLogin } = useAgentHostApi(); const { t } = useTranslation(); const state = useExternalStoreSnapshot(controller); const { agentTarget, agentTargetId, authenticatePending, dialogOpen, enabled, installPending, selectedAuthMethodId, setup, terminalLoginAvailable, terminalLoginError, terminalLoginPhase } = state; const { snapshot, loading, failed } = setup; const authMethods = snapshot?.authMethods ?? []; const account = snapshot?.account ?? null; const effectiveAuthMethodId = authMethods.some( (method) => method.id === selectedAuthMethodId ) ? (selectedAuthMethodId ?? "") : authMethods.some((method) => method.id === account?.authMethodId) ? (account?.authMethodId ?? "") : (authMethods[0]?.id ?? ""); const effectiveAuthMethod = authMethods.find( (method) => method.id === effectiveAuthMethodId ); const terminalLoginCommand = effectiveAuthMethod?.type === "terminal" ? (effectiveAuthMethod.terminalCommand?.trim() ?? "") || null : null; const terminalStartupAction = effectiveAuthMethod?.type === "terminal" ? (effectiveAuthMethod.terminalStartupAction ?? null) : null; // A shared caller can observe the Owner target's readiness, but must never // be routed into this device's setup/login/install workflow. Shared hosts // own their separate availability presentation and execution errors. if (!enabled || scope === "shared_caller") { return <>{children}>; } const setupChecking = !snapshot && !failed; const setupBlocked = failed || !snapshot || snapshot.status !== "ready"; const handleInstall = async () => { const plan = snapshot?.plan; if (plan) await controller.install(plan.planDigest); }; const handleAuthenticate = async () => { if (!effectiveAuthMethodId) return; await controller.authenticate(effectiveAuthMethodId); }; const terminalLoginLaunchAvailable = terminalLoginAvailable && Boolean(terminalLoginCommand) && (!terminalStartupAction || Boolean( terminalLogin?.supportedStartupActionTypes?.includes( terminalStartupAction.type ) )); const handleTerminalLoginStart = async () => { if (!terminalLoginCommand) return; await controller.startTerminalLogin({ command: terminalLoginCommand, startupAction: terminalStartupAction }); }; const handleTerminalLoginCancel = () => controller.cancelTerminalLogin(); const actionRunning = isSetupActionRunning(snapshot?.action?.status); const actionFailed = isSetupActionFailed(snapshot?.action?.status); const installRetryAvailable = snapshot?.status === "failed" && snapshot.action?.kind === "install" && actionFailed && Boolean(snapshot.plan); const phase = actionRunning ? (snapshot?.action?.phase ?? null) : null; const statusLabel = phase ? targetSetupPhaseLabel(t, phase) : loading ? t("agentHost.agentGui.targetSetupChecking") : null; const detectionStatus: AgentSetupStepStatus = failed ? "error" : loading || !snapshot ? "running" : snapshot ? "ok" : "pending"; const installStatus = resolveInstallStepStatus(snapshot); const loginStatus = resolveLoginStepStatus(snapshot); const providerLabel = agentTarget?.label ?? agentTargetId; const setupFailurePresentation = snapshot?.status === "failed" ? resolveAgentErrorPresentation(snapshot.reason) : null; const setupFailureMessage = setupFailurePresentation?.messageKey ? t(setupFailurePresentation.messageKey, { provider: providerLabel }) : null; const accountDetail = account ? [account.displayName, account.organization].filter(Boolean).join(" · ") : undefined; const setupDescription = setupChecking ? t("agentHost.agentGui.targetSetupChecking") : snapshot?.status === "auth_required" ? t("agentHost.agentGui.targetSetupAuthRequired") : snapshot?.status === "ready" ? t("agentHost.agentGui.targetSetupReady") : (setupFailureMessage ?? t("agentHost.agentGui.targetSetupDescription")); const authenticationAvailable = snapshot?.status === "auth_required" || snapshot?.status === "ready"; const signInApplicable = authMethods.length > 0 || account !== null || snapshot?.status === "auth_required" || snapshot?.status === "authenticating"; // Prefer setup projection over the local authenticate promise. OAuth can mark // the account ready before the host login call settles. const loginActionPending = authenticatePending && snapshot?.status !== "ready"; return ( <> {gateVisible && setupBlocked ? (
{setupDescription}
{!setupChecking ? ( ) : null}{statusLabel ?? (snapshot?.status === "ready" ? t("agentHost.agentGui.targetSetupComplete", { provider: providerLabel }) : t("agentHost.agentGui.targetSetupRemaining", { provider: providerLabel }))}
{t("agentHost.agentGui.targetSetupNoAuthMethods")}
) : null}{snapshot?.action?.kind === "authenticate" ? t("agentHost.agentGui.targetSetupAuthFailed") : t("agentHost.agentGui.targetSetupFailed")} {setupFailureMessage ? ( {setupFailureMessage} ) : snapshot?.action?.errorMessage?.trim() ? ( {snapshot.action.errorMessage.trim()} ) : null}
) : null}{waiting ? t("agentHost.agentGui.targetSetupTerminalLoginWaiting") : t("agentHost.agentGui.targetSetupTerminalAuthHint")}
{command}
{error}
) : null}