// Diff modal + Worktree modal const { useState: useStateM, useEffect: useEffectM } = window.React; // Fake diff hunks per task const DIFF_HUNKS = { t1: [ { file: 'src/middleware/auth.ts', adds: 48, dels: 22, hunks: [ { header: '@@ -12,7 +12,9 @@ export function authMiddleware(', lines: [ { k: 'ctx', n1: 12, n2: 12, t: ' const session = await getSession(req);' }, { k: 'del', n1: 13, n2: null, t: ' if (!session) return unauthorized();' }, { k: 'del', n1: 14, n2: null, t: ' const user = await lookupUser(session.userId);' }, { k: 'add', n1: null, n2: 13, t: ' if (!session || session.expired) {' }, { k: 'add', n1: null, n2: 14, t: ' return unauthorized("expired_or_missing");' }, { k: 'add', n1: null, n2: 15, t: ' }' }, { k: 'add', n1: null, n2: 16, t: ' const user = await pool.withConnection(c => lookupUser(c, session.userId));' }, { k: 'ctx', n1: 15, n2: 17, t: ' req.user = user;' }, { k: 'ctx', n1: 16, n2: 18, t: ' return next();' }, ]}, { header: '@@ -42,4 +44,6 @@ export function guard(', lines: [ { k: 'ctx', n1: 42, n2: 44, t: ' return async (req, res, next) => {' }, { k: 'del', n1: 43, n2: null, t: ' const s = await redis.get(req.cookies.sid);' }, { k: 'add', n1: null, n2: 45, t: ' const s = await store.get(req.cookies.sid);' }, { k: 'add', n1: null, n2: 46, t: ' if (s) store.touch(req.cookies.sid);' }, { k: 'ctx', n1: 44, n2: 47, t: ' next();' }, ]}, ]}, { file: 'src/lib/session/index.ts', adds: 31, dels: 14, hunks: [ { header: '@@ -1,8 +1,14 @@', lines: [ { k: 'del', n1: 1, n2: null, t: 'import { createClient } from "redis";' }, { k: 'add', n1: null, n2: 1, t: 'import { SessionStore } from "./store";' }, { k: 'add', n1: null, n2: 2, t: 'import { Pool } from "./pool";' }, { k: 'ctx', n1: 2, n2: 3, t: '' }, { k: 'del', n1: 3, n2: null, t: 'export const redis = createClient({ url: process.env.REDIS_URL });' }, { k: 'add', n1: null, n2: 4, t: 'export const pool = new Pool({ size: 16 });' }, { k: 'add', n1: null, n2: 5, t: 'export const store = new SessionStore(pool);' }, ]}, ]}, { file: 'src/lib/session/ttl.ts', adds: 12, dels: 4, hunks: [] }, { file: 'src/lib/session/store.ts', adds: 38, dels: 0, hunks: [] }, ], t2: [ { file: 'src/pages/settings.tsx', adds: 32, dels: 2, hunks: [ { header: '@@ -4,6 +4,8 @@ import { Section } from "../ui";', lines: [ { k: 'ctx', n1: 4, n2: 4, t: 'import { useTheme } from "../hooks/useTheme";' }, { k: 'add', n1: null, n2: 5, t: 'import { ThemeToggle } from "../ui/ThemeToggle";' }, { k: 'ctx', n1: 5, n2: 6, t: '' }, { k: 'ctx', n1: 6, n2: 7, t: 'export default function Settings() {' }, { k: 'add', n1: null, n2: 8, t: ' const [theme, setTheme] = useTheme();' }, ]}, ]}, { file: 'src/hooks/useTheme.ts', adds: 24, dels: 0, hunks: [] }, { file: 'src/theme/tokens.css', adds: 10, dels: 8, hunks: [] }, { file: 'src/ui/ThemeToggle.tsx', adds: 26, dels: 2, hunks: [] }, ], }; const DiffModal = ({ task, onClose }) => { useEffectM(() => { const onKey = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [onClose]); const files = DIFF_HUNKS[task.id] || [ { file: 'No diff available yet', adds: 0, dels: 0, hunks: [] } ]; const [activeFile, setActiveFile] = useStateM(0); const current = files[activeFile]; return (
e.stopPropagation()}>
Diff · {task.agent.branch}
{task.agent.worktree} · {files.length} files · +{task.agent.diff.additions} −{task.agent.diff.deletions}
{files.map((f, i) => (
setActiveFile(i)}>
{f.file}
+{f.adds} −{f.dels}
))}
{current.file} +{current.adds} −{current.dels}
{current.hunks.length === 0 ? (
Select a hunk — no detail preview available for this file.
) : current.hunks.map((h, hi) => (
{h.header}
{h.lines.map((ln, li) => (
{ln.n1 ?? ''} {ln.n2 ?? ''} {ln.k === 'add' ? '+' : ln.k === 'del' ? '−' : ' '} {ln.t}
))}
))}
); }; const WorktreeModal = ({ task, onClose }) => { useEffectM(() => { const onKey = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [onClose]); const fakeTree = [ { kind: 'dir', path: 'src', children: [ { kind: 'dir', path: 'middleware', children: [ { kind: 'file', path: 'auth.ts', mod: true }, ]}, { kind: 'dir', path: 'lib/session', children: [ { kind: 'file', path: 'index.ts', mod: true }, { kind: 'file', path: 'ttl.ts', mod: true }, { kind: 'file', path: 'store.ts', added: true }, ]}, ]}, { kind: 'file', path: 'package.json' }, { kind: 'file', path: 'README.md' }, ]; const render = (nodes, depth = 0) => nodes.map((n) => ( n.kind === 'dir' ? (
{n.path}
{render(n.children, depth + 1)}
) : (
{n.path} {n.mod && M} {n.added && A}
) )); return (
e.stopPropagation()}>
{task.agent.worktree}
{task.agent.branch} ← {task.agent.baseBranch}
Filesystem preview — modified files marked M, additions A
{render(fakeTree)}
); }; window.DiffModal = DiffModal; window.WorktreeModal = WorktreeModal;