diff --git a/packages/web/src/components/DirectTerminal.tsx b/packages/web/src/components/DirectTerminal.tsx index 5a5a51b12..ef690d201 100644 --- a/packages/web/src/components/DirectTerminal.tsx +++ b/packages/web/src/components/DirectTerminal.tsx @@ -19,6 +19,7 @@ interface DirectTerminalProps { /** CSS height for the terminal container in normal (non-fullscreen) mode. * Defaults to "max(440px, calc(100vh - 440px))". */ height?: string; + reloadCommand?: string; } /** @@ -36,6 +37,7 @@ export function DirectTerminal({ startFullscreen = false, variant = "agent", height = "max(440px, calc(100vh - 440px))", + reloadCommand, }: DirectTerminalProps) { const router = useRouter(); const pathname = usePathname(); @@ -51,6 +53,7 @@ export function DirectTerminal({ const [fullscreen, setFullscreen] = useState(startFullscreen); const [status, setStatus] = useState<"connecting" | "connected" | "error">("connecting"); const [error, setError] = useState(null); + const [reloading, setReloading] = useState(false); // Update URL when fullscreen changes useEffect(() => { @@ -66,6 +69,20 @@ export function DirectTerminal({ router.replace(newUrl, { scroll: false }); }, [fullscreen, pathname, router, searchParams]); + async function handleReload(): Promise { + if (!reloadCommand || reloading) return; + setReloading(true); + try { + await fetch(`/api/sessions/${encodeURIComponent(sessionId)}/send`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ message: reloadCommand }), + }); + } finally { + setReloading(false); + } + } + useEffect(() => { if (!terminalRef.current) return; @@ -93,9 +110,7 @@ export function DirectTerminal({ // agent = blue (#5b7ef8), orchestrator = violet (#a371f7) const cursorColor = variant === "orchestrator" ? "#a371f7" : "#5b7ef8"; const selectionColor = - variant === "orchestrator" - ? "rgba(163, 113, 247, 0.25)" - : "rgba(91, 126, 248, 0.3)"; + variant === "orchestrator" ? "rgba(163, 113, 247, 0.25)" : "rgba(91, 126, 248, 0.3)"; // Initialize xterm.js Terminal const terminal = new Terminal({ @@ -109,22 +124,22 @@ export function DirectTerminal({ cursorAccent: "#0a0a0f", selectionBackground: selectionColor, // ANSI colors — slightly warmer than pure defaults - black: "#1a1a24", - red: "#ef4444", - green: "#22c55e", - yellow: "#f59e0b", - blue: "#5b7ef8", - magenta: "#a371f7", - cyan: "#22d3ee", - white: "#d4d4d8", - brightBlack: "#50506a", - brightRed: "#f87171", - brightGreen: "#4ade80", - brightYellow: "#fbbf24", - brightBlue: "#7b9cfb", + black: "#1a1a24", + red: "#ef4444", + green: "#22c55e", + yellow: "#f59e0b", + blue: "#5b7ef8", + magenta: "#a371f7", + cyan: "#22d3ee", + white: "#d4d4d8", + brightBlack: "#50506a", + brightRed: "#f87171", + brightGreen: "#4ade80", + brightYellow: "#fbbf24", + brightBlue: "#7b9cfb", brightMagenta: "#c084fc", - brightCyan: "#67e8f9", - brightWhite: "#eeeef5", + brightCyan: "#67e8f9", + brightWhite: "#eeeef5", }, scrollback: 10000, allowProposedApi: true, @@ -201,7 +216,10 @@ export function DirectTerminal({ const MAX_BUFFER_BYTES = 1_048_576; // 1 MB const flushWriteBuffer = () => { - if (safetyTimer) { clearTimeout(safetyTimer); safetyTimer = null; } + if (safetyTimer) { + clearTimeout(safetyTimer); + safetyTimer = null; + } if (writeBuffer.length > 0) { terminal.write(writeBuffer.join("")); writeBuffer.length = 0; @@ -464,7 +482,8 @@ export function DirectTerminal({ }; }, [fullscreen]); - const accentColor = variant === "orchestrator" ? "var(--color-accent-violet)" : "var(--color-accent)"; + const accentColor = + variant === "orchestrator" ? "var(--color-accent-violet)" : "var(--color-accent)"; const statusDotClass = status === "connected" @@ -474,11 +493,7 @@ export function DirectTerminal({ : "bg-[var(--color-status-attention)] animate-[pulse_1.5s_ease-in-out_infinite]"; const statusText = - status === "connected" - ? "Connected" - : status === "error" - ? (error ?? "Error") - : "Connecting…"; + status === "connected" ? "Connected" : status === "error" ? (error ?? "Error") : "Connecting…"; const statusTextColor = status === "connected" @@ -498,13 +513,12 @@ export function DirectTerminal({ {/* Terminal chrome bar */}
- + {sessionId} - + {statusText} {/* XDA clipboard badge */} @@ -517,20 +531,68 @@ export function DirectTerminal({ > XDA + {reloadCommand ? ( + + ) : null} - )}
@@ -424,6 +395,7 @@ export function SessionDetail({ startFullscreen={startFullscreen} variant={terminalVariant} height={terminalHeight} + reloadCommand={isOpenCodeSession ? reloadCommand : undefined} />