import * as React from "react"; import type { OAuthStatus } from "../api/client"; import { api } from "../api/client"; const { useState, useEffect } = React; function formatBuildTime(isoString: string): string { const d = new Date(isoString); const year = d.getUTCFullYear(); const month = String(d.getUTCMonth() + 1).padStart(2, "0"); const day = String(d.getUTCDate()).padStart(2, "0"); const hours = String(d.getUTCHours()).padStart(2, "0"); const minutes = String(d.getUTCMinutes()).padStart(2, "0"); return `Built: ${year}-${month}-${day} ${hours}:${minutes}`; } interface ContextUsage { used: number; total: number; percentage: number; } interface ChatHeaderProps { projectPath: string; onCloseProject: () => void; contextUsage: ContextUsage; onClearSession: () => void; model: string; availableModels: string[]; claudeModels: string[]; hasAnthropicKey: boolean; onModelChange: (model: string) => void; enableTools: boolean; onToggleTools: (enabled: boolean) => void; wsConnected: boolean; oauthStatus?: OAuthStatus | null; } const getContextEmoji = (percentage: number): string => { if (percentage >= 90) return "🔴"; if (percentage >= 75) return "🟡"; return "🟢"; }; type RebuildStatus = "idle" | "building" | "reconnecting" | "error"; export function ChatHeader({ projectPath, onCloseProject, contextUsage, onClearSession, model, availableModels, claudeModels, hasAnthropicKey, onModelChange, enableTools, onToggleTools, wsConnected, oauthStatus = null, }: ChatHeaderProps) { const hasModelOptions = availableModels.length > 0 || claudeModels.length > 0; const [showConfirm, setShowConfirm] = useState(false); const [rebuildStatus, setRebuildStatus] = useState("idle"); const [rebuildError, setRebuildError] = useState(null); // When WS reconnects after a rebuild, clear the reconnecting status. useEffect(() => { if (rebuildStatus === "reconnecting" && wsConnected) { setRebuildStatus("idle"); } }, [wsConnected, rebuildStatus]); function handleRebuildClick() { setRebuildError(null); setShowConfirm(true); } function handleRebuildConfirm() { setShowConfirm(false); setRebuildStatus("building"); api .rebuildAndRestart() .then((result) => { // Got a response = build failed (server still running). setRebuildStatus("error"); setRebuildError(result || "Rebuild failed"); }) .catch(() => { // Network error = server is restarting (build succeeded). setRebuildStatus("reconnecting"); }); } function handleRebuildCancel() { setShowConfirm(false); } function handleDismissError() { setRebuildStatus("idle"); setRebuildError(null); } const rebuildButtonLabel = rebuildStatus === "building" ? "Building..." : rebuildStatus === "reconnecting" ? "Reconnecting..." : rebuildStatus === "error" ? "⚠ Rebuild Failed" : "↺ Rebuild"; const rebuildButtonDisabled = rebuildStatus === "building" || rebuildStatus === "reconnecting"; return ( <> {/* Confirmation dialog overlay */} {showConfirm && (
Rebuild and restart?
This will run cargo build and replace the running server. All agents will be stopped. The page will reconnect automatically when the new server is ready.
)} {/* Error toast */} {rebuildStatus === "error" && rebuildError && (
âš  Rebuild failed
								{rebuildError}
							
)}
Huskies
{projectPath}
{oauthStatus !== null && (!oauthStatus.authenticated || oauthStatus.expired) && ( )} {oauthStatus?.authenticated && !oauthStatus.expired && ( ✓ Claude )}
{formatBuildTime(__BUILD_TIME__)}
{getContextEmoji(contextUsage.percentage)} {contextUsage.percentage} %
{hasModelOptions ? ( ) : ( onModelChange(e.target.value)} placeholder="Model" style={{ padding: "6px 12px", borderRadius: "99px", border: "none", fontSize: "0.9em", background: "#2f2f2f", color: "#ececec", outline: "none", }} /> )}
); }