import type { CoderResult, AuditorResult, TesterResult, Finding } from "../types"; import type { DiffLine } from "../utils/diff"; import type { ArtifactTab } from "../App"; const C = { bg: "#0d1117", surface: "#161b22", border: "#21262d", text: "#c9d1d9", muted: "#8b949e", dim: "#484f58", accent: "#58a6ff", green: "#3fb950", red: "#f85149", yellow: "#d29922", orange: "#db6d28", addedBg: "rgba(46, 160, 67, 0.1)", removedBg: "rgba(248, 81, 73, 0.09)", }; const SEVERITY_COLOR: Record = { high: C.red, medium: C.yellow, low: "#58a6ff", }; interface Props { coder: CoderResult | null; auditor: AuditorResult | null; tester: TesterResult | null; contractDiff: DiffLine[] | null; pocDiff: DiffLine[] | null; selectedTab: ArtifactTab; onSelectTab: (tab: ArtifactTab) => void; diffMode: Record; onToggleDiff: (key: string) => void; } export function ArtifactPanel({ coder, auditor, tester, contractDiff, pocDiff, selectedTab, onSelectTab, diffMode, onToggleDiff, }: Props) { const findingCount = auditor?.findings?.length ?? 0; const hasPoc = !!tester?.pocCode; const treeItems: { id: ArtifactTab; icon: string; name: string; badge?: string; badgeColor?: string; available: boolean; }[] = [ { id: "contract", icon: "◈", name: "Contract.sol", badge: coder ? "sol" : undefined, badgeColor: C.accent, available: !!coder, }, { id: "findings", icon: "⚑", name: "findings/", badge: auditor ? (findingCount > 0 ? `${findingCount} issue${findingCount > 1 ? "s" : ""}` : "clean") : undefined, badgeColor: auditor ? (findingCount > 0 ? C.red : C.green) : C.dim, available: !!auditor, }, { id: "poc", icon: "◈", name: "ExploitTest.t.sol", badge: tester ? tester.status : undefined, badgeColor: tester?.status === "success" ? C.green : tester?.status === "failed" ? C.red : C.yellow, available: hasPoc, }, ]; return (
{/* Panel titlebar */}
explorer
{/* File tree */}
artifacts
{treeItems.map((item) => { const selected = selectedTab === item.id; return ( ); })}
{/* Content area */}
{selectedTab === "contract" && coder && contractDiff ? ( onToggleDiff("contract")} /> ) : selectedTab === "findings" && auditor ? ( ) : selectedTab === "poc" && tester?.pocCode && pocDiff ? ( onToggleDiff("poc")} status={tester.status} iterations={tester.iterations} /> ) : ( )}
); } function CodeViewer({ title, diff, showDiff, onToggleDiff, status, iterations, }: { title: string; diff: DiffLine[]; showDiff: boolean; onToggleDiff: () => void; status?: string; iterations?: number; }) { const addedCount = diff.filter((l) => l.type === "added").length; const removedCount = diff.filter((l) => l.type === "removed").length; const totalLines = diff.filter((l) => l.type !== "removed").length; const hasDiff = addedCount > 0 || removedCount > 0; const hasChanges = diff.some((l) => l.type === "removed") || diff.some((l) => l.type === "added" && diff.some((x) => x.type === "unchanged")); return (
{/* Toolbar */}
{title} {status && ( {status} )} {iterations !== undefined && iterations > 0 && ( {iterations} iter )} {hasDiff && ( <> {hasChanges && ( +{addedCount}{" "} -{removedCount} )} )} {totalLines}L
{/* Code */}
{diff.map((dl, idx) => { if (!showDiff && dl.type === "removed") return null; const isAdded = showDiff && dl.type === "added"; const isRemoved = showDiff && dl.type === "removed"; return ( {showDiff && ( )} ); })}
{isAdded ? "+" : isRemoved ? "−" : " "} {dl.lineNo > 0 ? dl.lineNo : ""} {dl.line}
); } function FindingsViewer({ findings, reviewSummary }: { findings: Finding[]; reviewSummary?: string }) { return (
{/* Review summary */} {reviewSummary && (
coder / security-review
{reviewSummary}
)} {/* Findings */}
auditor / findings — {findings.length} issue{findings.length !== 1 ? "s" : ""}
{findings.length === 0 ? (
✓ Nenhuma vulnerabilidade encontrada.
) : ( findings.map((f, i) => ) )}
); } function FindingCard({ finding, index }: { finding: Finding; index: number }) { const color = SEVERITY_COLOR[finding.severity] ?? C.muted; return (
{/* Header */}
{finding.severity.toUpperCase()} [{index + 1}] {finding.title} {finding.location && {finding.location}}
{/* Body */}

{finding.description}

{finding.codeSnippet && (
{finding.codeSnippet}
)}
recomendação: {finding.recommendation}
confiança: {Math.round(finding.judgeReview.confidence)}% — {finding.judgeReview.review}
); } function EmptyState() { return (
aguardando execução do pipeline
); }