import { useEffect, useState } from 'react'; import type { DiffResult } from '../../lib/orchestratorApi'; /** * Overlay showing a run's branch diff against main — the commits it would * bring in, a `--stat` summary, and the full (size-capped) patch — so the * operator can review an agent's work before merging it. */ interface DiffModalProps { /** Fetch the diff; throws on a missing worktree. */ load: () => Promise; onClose: () => void; } export function DiffModal({ load, onClose }: DiffModalProps) { const [diff, setDiff] = useState(null); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; setError(null); setDiff(null); load() .then((d) => { if (!cancelled) setDiff(d); }) .catch((e) => { if (!cancelled) setError(e instanceof Error ? e.message : 'Failed to load diff'); }); return () => { cancelled = true; }; }, [load]); return (
e.stopPropagation()} style={{ display: 'flex', flexDirection: 'column' }} >

Branch Diff

{error && (

{error}

)} {!error && !diff && (

Loading diff…

)} {diff && (
{diff.branch && (
{diff.branch} → main
)}

Commits ({diff.commits.length})

{diff.commits.length === 0 ? (

No commits ahead — already merged or empty.

) : (
    {diff.commits.map((c) => (
  • {c.sha}{' '} {c.subject}
  • ))}
)}
{diff.stat && (

Changes

                  {diff.stat}
                
)}

Patch {diff.truncated && (truncated)}

                {diff.patch || '(no textual changes)'}
              
)}
); } const overlayStyle: React.CSSProperties = { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', backdropFilter: 'blur(2px)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 50, padding: 'var(--sp-4)', };