import { useRef, useState } from "react"; import { XIcon, WarningIcon, CheckCircleIcon, CaretRightIcon } from "@phosphor-icons/react"; import { copyTextToClipboard } from "../utils/clipboard"; import { useDialogBehavior } from "./ui/useDialogBehavior"; export interface LintFinding { severity: "error" | "warning"; message: string; file?: string; fixHint?: string; } export function LintModal({ findings, projectId, projectDir, title = "HyperFrame Lint Results", promptIntro = "Fix these HyperFrames lint issues", onClose, }: { findings: LintFinding[]; projectId: string; /** Real on-disk project directory for the agent prompt (not the browser URL). */ projectDir?: string | null; /** Header subtitle — parameterize so console errors don't masquerade as lint results. */ title?: string; /** First line of the copied agent prompt. */ promptIntro?: string; onClose: () => void; }) { const errors = findings.filter((f) => f.severity === "error"); const warnings = findings.filter((f) => f.severity === "warning"); const hasIssues = findings.length > 0; const [copied, setCopied] = useState(false); const [copyFailed, setCopyFailed] = useState(false); const containerRef = useRef(null); const { requestClose } = useDialogBehavior({ open: true, onClose, containerRef }); const handleCopyToAgent = async () => { const lines = findings.map((f) => { let line = `[${f.severity}] ${f.message}`; if (f.file) line += `\n File: ${f.file}`; if (f.fixHint) line += `\n Fix: ${f.fixHint}`; return line; }); const pathLine = projectDir ? `Project path: ${projectDir}\n\n` : ""; const text = `${promptIntro} for project "${projectId}":\n\n${pathLine}${lines.join("\n\n")}`; const copiedText = await copyTextToClipboard(text); if (copiedText) { setCopied(true); setCopyFailed(false); setTimeout(() => setCopied(false), 2000); } else { setCopyFailed(true); setTimeout(() => setCopyFailed(false), 3000); } }; return (
e.stopPropagation()} > {/* Header */}
{hasIssues ? (
) : (
)}

{hasIssues ? `${errors.length} error${errors.length !== 1 ? "s" : ""}, ${warnings.length} warning${warnings.length !== 1 ? "s" : ""}` : "All checks passed"}

{title}

{/* Copy to agent + findings */} {hasIssues && (
)}
{!hasIssues && (
No errors or warnings found. Your composition looks good!
)} {errors.map((f, i) => (

{f.message}

{f.file &&

{f.file}

} {f.fixHint && (

{f.fixHint}

)}
))} {warnings.map((f, i) => (

{f.message}

{f.file &&

{f.file}

} {f.fixHint && (

{f.fixHint}

)}
))}
); }