/** * public/history.ts — resume a past Claude Code session (O2). * * A 🕘 toolbar button opens a list of past sessions (GET /sessions); clicking * "Resume" opens a new tab in that project's directory and runs * `claude --resume `. */ export interface HistoryHooks { resume: (cwd: string, id: string) => void } interface HistorySession { id: string cwd: string project: string mtimeMs: number preview: string } function relTime(ms: number): string { const s = Math.max(0, (Date.now() - ms) / 1000) if (s < 60) return 'just now' if (s < 3600) return `${Math.floor(s / 60)}m ago` if (s < 86400) return `${Math.floor(s / 3600)}h ago` return `${Math.floor(s / 86400)}d ago` } export function mountHistory(toolbar: HTMLElement, hooks: HistoryHooks): void { const overlay = document.createElement('div') overlay.id = 'historymodal' overlay.style.display = 'none' const card = document.createElement('div') card.className = 'hist-card' overlay.appendChild(card) document.body.appendChild(overlay) const hide = (): void => { overlay.style.display = 'none' } overlay.addEventListener('click', (e) => { if (e.target === overlay) hide() }) const open = async (): Promise => { card.replaceChildren() const title = document.createElement('div') title.className = 'hist-title' title.textContent = 'Resume a Claude session' card.appendChild(title) const status = document.createElement('div') status.className = 'hist-empty' status.textContent = 'Loading…' card.appendChild(status) overlay.style.display = 'flex' let sessions: HistorySession[] try { const res = await fetch('/sessions') sessions = (await res.json()) as HistorySession[] } catch { status.textContent = 'Failed to load sessions.' return } if (sessions.length === 0) { status.textContent = 'No past Claude sessions found.' return } status.remove() for (const s of sessions) { const row = document.createElement('div') row.className = 'hist-row' const main = document.createElement('div') main.className = 'hist-main' const proj = document.createElement('div') proj.className = 'hist-proj' proj.textContent = `${s.project} · ${relTime(s.mtimeMs)}` const prev = document.createElement('div') prev.className = 'hist-prev' prev.textContent = s.preview || '(no preview)' prev.title = s.cwd main.append(proj, prev) const btn = document.createElement('button') btn.className = 'hist-resume' btn.textContent = 'Resume' btn.addEventListener('click', () => { hooks.resume(s.cwd, s.id) hide() }) row.append(main, btn) card.appendChild(row) } } const toggle = document.createElement('button') toggle.className = 'toolbtn' toggle.textContent = '🕘' toggle.title = 'Resume a past Claude session' toggle.setAttribute('aria-label', 'Session history') toggle.addEventListener('click', () => { if (overlay.style.display === 'none') void open() else hide() }) toolbar.appendChild(toggle) }