'use client' import { useCallback, useEffect, useState } from 'react' import { apiFetch } from '@/lib/csrf' async function fetchDiff(repoPath: string): Promise { const res = await apiFetch('/api/agent/exec', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ command_key: 'git_diff', args: [repoPath] }), }) if (!res.ok) { const text = await res.text() throw new Error(`agent ${res.status}: ${text}`) } const reader = res.body?.getReader() if (!reader) throw new Error('no response body') const decoder = new TextDecoder() let buffer = '' let output = '' while (true) { const { done, value } = await reader.read() if (done) break buffer += decoder.decode(value, { stream: true }) const lines = buffer.split('\n') buffer = lines.pop() ?? '' for (const line of lines) { if (line.startsWith('data:')) { try { const parsed = JSON.parse(line.slice(5).trim()) as { data?: string } if (parsed.data !== undefined) output += parsed.data } catch { // ignore malformed } } } } return output } function DiffLine({ line }: { line: string }) { if (line.startsWith('+++') || line.startsWith('---')) { return {line}{'\n'} } if (line.startsWith('+')) { return ( {line}{'\n'} ) } if (line.startsWith('-')) { return ( {line}{'\n'} ) } if (line.startsWith('@@')) { return {line}{'\n'} } if (line.startsWith('diff ') || line.startsWith('index ')) { return {line}{'\n'} } return {line}{'\n'} } type Props = { repoPath: string initialDiff: string initialError: string | null } export default function DiffViewer({ repoPath, initialDiff, initialError }: Props) { const [diff, setDiff] = useState(initialDiff) const [error, setError] = useState(initialError) const [refreshing, setRefreshing] = useState(false) const refresh = useCallback(async () => { setRefreshing(true) try { const data = await fetchDiff(repoPath) setDiff(data) setError(null) } catch (err) { setError(err instanceof Error ? err.message : 'failed') } finally { setRefreshing(false) } }, [repoPath]) useEffect(() => { const id = setInterval(refresh, 30000) return () => clearInterval(id) }, [refresh]) if (error) { return (
{error}
) } return (
git diff HEAD
{refreshing && ( refreshing… )}
{diff.trim() === '' ? (
No uncommitted changes
) : (
          {diff.split('\n').map((line, i) => (
            
          ))}
        
)}
) }