| 1 | import { TerminalIcon } from "lucide-react"; |
| 2 | |
| 3 | import type { ContextPresentationCapability } from "../contextPresentationRegistry"; |
| 4 | import { ContextChipPopover, ContextChipShell } from "../contextChipParts"; |
| 5 | |
| 6 | interface 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 | |
| 16 | export 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 | } |