1import { TerminalIcon } from "lucide-react";
2
3import type { ContextPresentationCapability } from "../contextPresentationRegistry";
4import { ContextChipPopover, ContextChipShell } from "../contextChipParts";
5
6interface TerminalContextInlineChipProps {
7 label: string;
8 terminalLabel: string;
9 lineStart: number;
10 lineEnd: number;
11 text: string;
12 detailsMode: ContextPresentationCapability["details"];
13 expired?: boolean;
14}
15
16export function TerminalContextInlineChip(props: TerminalContextInlineChipProps) {
17 const { label, terminalLabel, lineStart, lineEnd, text, detailsMode, expired = false } = props;
18
19 if (!expired && text.length > 0 && detailsMode === "popover") {
20 return (
21 <ContextChipPopover
22 kind="terminal"
23 icon={<TerminalIcon />}
24 label={label}
25 accessibleLabel={`Terminal excerpt, ${label}`}
26 >
27 <div className="overflow-hidden rounded-md border border-border/70 bg-background/80">
28 <div className="flex items-center gap-2 border-b border-border/70 px-3 py-2">
29 <TerminalIcon className="size-4 shrink-0 text-success" aria-hidden />
30 <span className="min-w-0 truncate text-sm font-medium text-foreground">
31 {terminalLabel}
32 </span>
33 <span className="ml-auto shrink-0 text-secondary-label text-xs">
34 {lineStart === lineEnd ? `Line ${lineStart}` : `Lines ${lineStart}–${lineEnd}`}
35 </span>
36 </div>
37 <pre
38 className="max-h-80 overflow-auto whitespace-pre bg-muted p-3 font-mono text-foreground text-xs leading-relaxed outline-none [tab-size:4] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
39 aria-label="Captured terminal output"
40 tabIndex={0}
41 >
42 {text}
43 </pre>
44 </div>
45 </ContextChipPopover>
46 );
47 }
48
49 return (
50 <ContextChipShell
51 kind="terminal"
52 {...(expired ? { state: "invalid" as const } : {})}
53 icon={<TerminalIcon />}
54 label={label}
55 aria-label={`Terminal excerpt, ${label}${expired ? ", expired" : ""}`}
56 data-terminal-context-expired={expired ? "true" : undefined}
57 tooltip={
58 expired
59 ? `Terminal context expired. Remove and re-add ${label} to include it in your message.`
60 : detailsMode === "none"
61 ? undefined
62 : text
63 }
64 />
65 );
66}