Files
Codeman/src/web/public/index.html
T
2026-01-29 11:27:44 +01:00

1333 lines
70 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Claude Code session manager with web interface">
<meta name="theme-color" content="#0a0a0a">
<title>Claudeman</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%2360a5fa'/%3E%3Cstop offset='100%25' stop-color='%233b82f6'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='32' height='32' rx='6' fill='%230a0a0a'/%3E%3Cpath d='M18 4L8 18h6l-2 10 10-14h-6z' fill='url(%23g)'/%3E%3C/svg%3E">
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css">
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.min.js"></script>
</head>
<body>
<div class="app">
<!-- Compact Header with Session Tabs -->
<header class="header">
<div class="header-brand">
<span class="logo" onclick="app.goHome()" title="Go to main page">Claudeman</span>
</div>
<!-- Session Tabs -->
<div class="session-tabs" id="sessionTabs">
</div>
<div class="header-right">
<div class="header-font-controls">
<button class="btn-icon-header btn-sm" onclick="app.decreaseFontSize()" title="Decrease font (Ctrl+-)">A-</button>
<span class="font-size-display" id="fontSizeDisplay">14</span>
<button class="btn-icon-header btn-sm" onclick="app.increaseFontSize()" title="Increase font (Ctrl++)">A+</button>
</div>
<div class="header-system-stats" id="headerSystemStats" title="System resource usage">
<div class="stat-item">
<span class="stat-label">CPU</span>
<div class="stat-bar">
<div class="stat-bar-fill stat-bar-cpu" id="statCpuBar"></div>
</div>
<span class="stat-value" id="statCpu">--%</span>
</div>
<div class="stat-item">
<span class="stat-label">MEM</span>
<div class="stat-bar">
<div class="stat-bar-fill stat-bar-mem" id="statMemBar"></div>
</div>
<span class="stat-value" id="statMem">--</span>
</div>
</div>
<button class="btn-icon-header btn-notifications" onclick="app.toggleNotifications()" title="Notifications">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
<span class="notification-badge" id="notifBadge" style="display:none;">0</span>
</button>
<button class="btn-icon-header btn-settings" onclick="app.openAppSettings()" title="App Settings"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></button>
<div class="header-tokens" id="headerTokens" title="Total tokens across all sessions">0 tokens</div>
</div>
</header>
<!-- Timer Banner (shown when timed run is active) -->
<div class="timer-banner" id="timerBanner" style="display: none;">
<div class="timer-content">
<span class="timer-value" id="timerValue">00:00:00</span>
<div class="timer-progress"><div class="timer-progress-fill" id="timerProgress"></div></div>
<span class="timer-meta" id="timerMeta">0 tasks | $0.00</span>
</div>
<button class="btn-icon-only" onclick="app.stopCurrentRun()" title="Stop">&#x25A0;</button>
</div>
<!-- Respawn Banner - Compact 2-column layout -->
<div class="respawn-banner" id="respawnBanner" style="display: none;">
<div class="respawn-compact-layout">
<div class="respawn-status-col">
<div class="respawn-status-row1">
<span class="respawn-indicator">&#x21BB;</span>
<span class="respawn-state" id="respawnState">Watching</span>
<span class="detection-confidence" id="detectionConfidence"></span>
<span class="respawn-cycles">#<span id="respawnCycleCount">0</span></span>
<span class="respawn-timer" id="respawnTimer" style="display: none;"></span>
<span class="respawn-tokens" id="respawnTokens" style="display: none;"></span>
<button class="btn-icon-only" onclick="app.stopRespawn()" title="Stop Respawn">&#x25A0;</button>
</div>
<div class="respawn-status-row2" id="respawnStatusRow2">
<span class="detection-hook" id="detectionHook" style="display: none;"></span>
<span class="detection-ai-check" id="detectionAiCheck" style="display: none;"></span>
<span class="detection-status" id="detectionStatus"></span>
<span class="detection-waiting" id="detectionWaiting" style="display: none;"></span>
<div class="respawn-countdown-timers" id="respawnCountdownTimers"></div>
</div>
</div>
<div class="respawn-action-log" id="respawnActionLog"></div>
</div>
</div>
<!-- Ralph / Todo Tracker Panel -->
<div class="ralph-panel collapsed" id="ralphStatePanel" style="display: none;">
<!-- Collapsed Summary Bar -->
<div class="ralph-summary" id="ralphSummary">
<div class="ralph-summary-content" onclick="app.toggleRalphStatePanel()">
<div class="ralph-ring-mini" id="ralphRingMini">
<svg viewBox="0 0 36 36" class="ralph-ring-svg">
<defs>
<linearGradient id="ralphGradientMini" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6" />
<stop offset="100%" stop-color="#22c55e" />
</linearGradient>
</defs>
<circle class="ralph-ring-bg" cx="18" cy="18" r="15.9" />
<circle class="ralph-ring-progress-mini" cx="18" cy="18" r="15.9" id="ralphRingMiniProgress" style="stroke-dashoffset: 100" />
</svg>
<span class="ralph-ring-text" id="ralphRingMiniText">0%</span>
</div>
<div class="ralph-summary-info">
<span class="ralph-title">Ralph / Todo Tracker</span>
<span class="ralph-status-badge" id="ralphStatusBadge">
<span class="ralph-status-dot"></span>
<span class="ralph-status-text">Idle</span>
</span>
</div>
<div class="ralph-summary-stats">
<span class="ralph-stat"><span class="ralph-stat-icon">&#x23F1;</span><span id="ralphStatTime">0m</span></span>
<span class="ralph-stat"><span class="ralph-stat-icon">&#x2713;</span><span id="ralphStatTasks">0/0</span></span>
</div>
<span class="ralph-toggle" id="ralphToggle">&#x25BC;</span>
</div>
<div class="ralph-controls">
<div class="ralph-menu-container">
<button class="btn-icon-sm" onclick="event.stopPropagation(); app.toggleRalphMenu()" title="Fix Plan Menu" id="ralphMenuBtn">&#x2630;</button>
<div class="ralph-dropdown" id="ralphDropdown">
<button onclick="event.stopPropagation(); app.showFixPlan(); app.closeRalphMenu()">View Fix Plan</button>
<button onclick="event.stopPropagation(); app.writeFixPlanToFile(); app.closeRalphMenu()">Write to File</button>
<button onclick="event.stopPropagation(); app.importFixPlanFromFile(); app.closeRalphMenu()">Import from File</button>
<hr>
<button onclick="event.stopPropagation(); app.resetCircuitBreaker(); app.closeRalphMenu()">Reset Circuit Breaker</button>
</div>
</div>
<button class="btn-icon-sm" onclick="event.stopPropagation(); app.toggleRalphDetach()" title="Detach/Attach panel" id="ralphDetachBtn">&#x29C9;</button>
<button class="btn-icon-sm" onclick="event.stopPropagation(); app.closeRalphTracker()" title="Close tracker">&times;</button>
</div>
</div>
<!-- Expanded Detail View - Compact horizontal layout -->
<div class="ralph-detail" id="ralphDetail">
<div class="ralph-detail-row">
<!-- Progress Ring -->
<div class="ralph-ring-compact">
<svg viewBox="0 0 100 100" class="ralph-ring-svg-large">
<defs>
<linearGradient id="ralphGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6" />
<stop offset="100%" stop-color="#22c55e" />
</linearGradient>
</defs>
<circle class="ralph-ring-track" cx="50" cy="50" r="42" />
<circle class="ralph-ring-fill" cx="50" cy="50" r="42" id="ralphRingProgress" style="stroke-dashoffset: 264" />
</svg>
<div class="ralph-ring-center">
<div class="ralph-ring-percent" id="ralphRingPercent">0%</div>
<div class="ralph-ring-label">Complete</div>
</div>
</div>
<!-- Meta Info + Tasks unified -->
<div class="ralph-info-unified">
<div class="ralph-info-labels">
<div class="ralph-info-row">
<span class="ralph-info-label">Tasks</span>
<span class="ralph-tasks-count" id="ralphTasksCount">0/0</span>
</div>
<div class="ralph-info-row">
<span class="ralph-info-label">Phrase</span>
<code id="ralphPhrase">--</code>
</div>
<div class="ralph-info-row">
<span class="ralph-info-label">Elapsed</span>
<span id="ralphElapsed">0m</span>
</div>
<div class="ralph-info-row" id="ralphVersionRow" style="display: none;">
<span class="ralph-info-label">Plan</span>
<div class="ralph-version-info">
<span class="version-badge" id="ralphPlanVersion">v1</span>
<button class="rollback-btn" id="ralphRollbackBtn" onclick="app.showPlanHistory()" title="View history">history</button>
</div>
</div>
</div>
<div class="ralph-tasks-grid" id="ralphTasksGrid"></div>
</div>
</div>
</div>
</div>
<!-- Main Terminal Area -->
<main class="main">
<div class="terminal-container" id="terminalContainer"></div>
</main>
<!-- Project Insights Panel (shows file-viewing Bash commands) -->
<div class="project-insights-panel" id="projectInsightsPanel">
<div class="project-insights-header">
<span class="project-insights-title">Project Insights</span>
<button class="btn-icon-sm" onclick="app.closeProjectInsightsPanel()" title="Close">&times;</button>
</div>
<div class="project-insights-body" id="projectInsightsList"></div>
<div class="project-insights-resize-handle"></div>
</div>
<!-- File Browser Panel -->
<div class="file-browser-panel" id="fileBrowserPanel">
<div class="file-browser-header">
<span class="file-browser-title">Files</span>
<div class="file-browser-actions">
<button class="btn-icon-sm" onclick="app.refreshFileBrowser()" title="Refresh">&#x21BB;</button>
<button class="btn-icon-sm" onclick="app.toggleFileBrowserExpand()" title="Expand/Collapse All" id="fileBrowserExpandBtn">&#x229E;</button>
<button class="btn-icon-sm" onclick="app.closeFileBrowserPanel()" title="Close">&times;</button>
</div>
</div>
<div class="file-browser-search">
<input type="text" id="fileBrowserSearch" placeholder="Filter files..." oninput="app.filterFileBrowser(this.value)">
</div>
<div class="file-browser-body" id="fileBrowserTree">
<div class="file-browser-empty">Select a session to view files</div>
</div>
<div class="file-browser-status" id="fileBrowserStatus"></div>
</div>
<!-- File Preview Overlay -->
<div class="file-preview-overlay" id="filePreviewOverlay">
<div class="file-preview-window">
<div class="file-preview-header">
<span class="file-preview-title" id="filePreviewTitle">file.ts</span>
<div class="file-preview-actions">
<button class="btn-icon-sm" onclick="app.copyFilePreviewContent()" title="Copy content">&#x2398;</button>
<button class="btn-icon-sm" onclick="app.closeFilePreview()" title="Close">&times;</button>
</div>
</div>
<div class="file-preview-body" id="filePreviewBody"></div>
<div class="file-preview-footer" id="filePreviewFooter"></div>
</div>
</div>
<!-- Bottom Toolbar -->
<footer class="toolbar">
<div class="toolbar-left">
<!-- Run Claude -->
<div class="toolbar-group">
<button class="btn-toolbar btn-claude" onclick="app.runClaude()" title="Run Claude (Ctrl+Enter)">
Run Claude
</button>
<div class="tab-count-group" title="Instance count">
<button class="tab-count-btn" onclick="app.decrementTabCount()" title="Instance count">−</button>
<input type="number" id="tabCount" class="tab-count-input" value="1" min="1" max="20" readonly title="Instance count">
<button class="tab-count-btn" onclick="app.incrementTabCount()" title="Instance count">+</button>
</div>
<button class="btn-toolbar btn-shell" onclick="app.runShell()" title="Run Shell">
Run Shell
</button>
<div class="tab-count-group" title="Instance count">
<button class="tab-count-btn" onclick="app.decrementShellCount()" title="Instance count">−</button>
<input type="number" id="shellCount" class="tab-count-input" value="1" min="1" max="20" readonly title="Instance count">
<button class="tab-count-btn" onclick="app.incrementShellCount()" title="Instance count">+</button>
</div>
<button class="btn-toolbar btn-ralph" onclick="app.showRalphWizard()" title="Start Ralph Loop">
Ralph Loop
</button>
<div class="case-select-group">
<select id="quickStartCase" class="toolbar-select" title="Select case">
<option value="testcase">testcase</option>
</select>
<button class="btn-case-add" onclick="app.showCreateCaseModal()" title="Create new case">+</button>
</div>
</div>
<!-- Directory (hidden) -->
<div class="toolbar-group" style="display: none;">
<button class="btn-toolbar" onclick="app.toggleDirInput()" title="Set working directory">
<span id="dirDisplay">No directory</span>
</button>
<input type="text" id="dirInput" class="toolbar-input hidden" placeholder="Working directory..." onblur="app.hideDirInput()">
</div>
</div>
<div class="toolbar-center">
<span class="version-display" id="versionDisplay" title="Claudeman version">v0.0.0</span>
</div>
<div class="toolbar-right">
</div>
</footer>
<!-- Help Modal -->
<div class="modal" id="helpModal">
<div class="modal-backdrop" onclick="app.closeHelp()"></div>
<div class="modal-content">
<div class="modal-header">
<h3>Keyboard Shortcuts</h3>
<button class="modal-close" onclick="app.closeHelp()">&times;</button>
</div>
<div class="modal-body">
<div class="shortcuts-grid">
<div><kbd>Ctrl</kbd>+<kbd>Enter</kbd></div><div>Run Claude</div>
<div><kbd>Ctrl</kbd>+<kbd>W</kbd></div><div>Close Session</div>
<div><kbd>Ctrl</kbd>+<kbd>Tab</kbd></div><div>Next Session</div>
<div><kbd>Ctrl</kbd>+<kbd>K</kbd></div><div>Kill All Sessions + Screens</div>
<div><kbd>Ctrl</kbd>+<kbd>L</kbd></div><div>Clear Terminal</div>
<div><kbd>Ctrl</kbd>+<kbd>+</kbd></div><div>Increase Font</div>
<div><kbd>Ctrl</kbd>+<kbd>-</kbd></div><div>Decrease Font</div>
<div><kbd>Ctrl</kbd>+<kbd>?</kbd></div><div>Show Help</div>
<div><kbd>Escape</kbd></div><div>Close Panels</div>
</div>
</div>
</div>
</div>
<!-- Monitor Panel (Screen Sessions + Background Tasks) -->
<div class="monitor-panel" id="monitorPanel">
<div class="monitor-panel-header" id="monitorPanelHeader">
<div class="monitor-panel-title">Monitor</div>
<div class="monitor-panel-actions">
<button class="btn-toolbar btn-sm btn-danger" onclick="app.killAllSessions()" title="Kill all sessions and their screen processes">Kill All</button>
<button class="btn-icon-sm" onclick="app.reconcileScreens()" title="Refresh screens">&#x21BB;</button>
<button class="btn-icon-sm" onclick="app.toggleMonitorDetach()" title="Detach panel" id="monitorDetachBtn">&#x29C9;</button>
<button class="btn-icon-sm" onclick="app.toggleMonitorPanel()" title="Toggle panel" id="monitorToggleBtn">&#x25B2;</button>
<button class="btn-icon-sm" onclick="app.closeMonitor()" title="Close monitor">&times;</button>
</div>
</div>
<div class="monitor-resize-handle" id="monitorResizeHandle"></div>
<div class="monitor-panel-body" id="monitorTabContent">
<div class="monitor-section">
<div class="monitor-section-header">
<span>Screen Sessions</span>
</div>
<div class="monitor-section-body" id="screenSessionsBody">
<div class="monitor-empty">No screen sessions</div>
</div>
</div>
<div class="monitor-section" id="monitorPlanAgentsSection" style="display: none;">
<div class="monitor-section-header">
<span>Plan Wizard Agents</span>
<span class="task-stats" id="monitorPlanAgentStats">0 active</span>
<button class="btn-toolbar btn-sm btn-danger" onclick="app.cancelPlanFromMonitor()" title="Cancel plan generation">Cancel</button>
</div>
<div class="monitor-section-body" id="monitorPlanAgentsBody">
<div class="monitor-empty">No plan agents</div>
</div>
</div>
<div class="monitor-section" id="monitorSubagentsSection">
<div class="monitor-section-header">
<span>Background Agents</span>
<span class="task-stats" id="monitorSubagentStats">0 tracked</span>
<button class="btn-toolbar btn-sm btn-danger" onclick="app.clearAllSubagents()" title="Clear all">Clear</button>
</div>
<div class="monitor-section-body" id="monitorSubagentsBody">
<div class="monitor-empty">No background agents</div>
</div>
</div>
<div class="monitor-section" id="backgroundTasksSection" style="display: none;">
<div class="monitor-section-header">
<span>Background Tasks</span>
<span class="task-stats" id="taskPanelStats">0 running</span>
</div>
<div class="monitor-section-body" id="backgroundTasksBody">
</div>
</div>
</div>
</div>
<!-- Subagents Panel (separate from Monitor) -->
<div class="subagents-panel" id="subagentsPanel">
<div class="subagents-panel-header" id="subagentsPanelHeader">
<div class="subagents-panel-title">
Subagents <span id="subagentCountBadge" class="subagent-badge"></span>
</div>
<div class="subagents-panel-actions">
<button class="btn-toolbar btn-sm btn-danger" onclick="app.clearAllSubagents()" title="Clear all tracked subagents">Clear All</button>
<button class="btn-icon-sm" onclick="app.toggleSubagentsDetach()" title="Detach panel" id="subagentsDetachBtn">&#x29C9;</button>
<button class="btn-icon-sm" onclick="app.toggleSubagentsPanel()" title="Toggle panel" id="subagentsToggleBtn">&#x25B2;</button>
<button class="btn-icon-sm" onclick="app.closeSubagentsPanel()" title="Close">&times;</button>
</div>
</div>
<div class="subagents-resize-handle" id="subagentsResizeHandle"></div>
<div class="subagents-panel-body" id="subagentsTabContent">
<div class="subagent-container">
<div class="subagent-list" id="subagentList">
<div class="subagent-empty">No background agents detected</div>
</div>
<div class="subagent-detail" id="subagentDetail">
<div class="subagent-empty">Select an agent to view details</div>
</div>
</div>
</div>
</div>
<!-- Session Options Modal (includes Respawn Settings) -->
<div class="modal" id="sessionOptionsModal">
<div class="modal-backdrop" onclick="app.closeSessionOptions()"></div>
<div class="modal-content">
<div class="modal-header">
<h3>Session Options</h3>
<button class="modal-close" onclick="app.closeSessionOptions()">&times;</button>
</div>
<!-- Modal Tabs -->
<div class="modal-tabs">
<button class="modal-tab-btn active" data-tab="respawn" onclick="app.switchOptionsTab('respawn')">Respawn</button>
<button class="modal-tab-btn" data-tab="context" onclick="app.switchOptionsTab('context')">Context</button>
<button class="modal-tab-btn" data-tab="ralph" onclick="app.switchOptionsTab('ralph')">Ralph / Todo</button>
<button class="modal-tab-btn" data-tab="summary" onclick="app.switchOptionsTab('summary')">Summary</button>
</div>
<div class="modal-body">
<!-- Respawn Tab Content -->
<div class="modal-tab-content" id="respawn-tab">
<!-- Respawn Settings Section -->
<div class="session-respawn-section" id="sessionRespawnSection">
<div class="section-divider">
<div class="session-respawn-status" id="sessionRespawnStatus">
<span class="respawn-status-indicator"></span>
<span class="respawn-status-text">Not active</span>
</div>
</div>
<div class="form-row">
<label>Run Duration</label>
<div class="duration-presets">
<button type="button" class="duration-preset-btn" data-minutes="30" onclick="app.selectDurationPreset('30')">30m</button>
<button type="button" class="duration-preset-btn" data-minutes="60" onclick="app.selectDurationPreset('60')">1h</button>
<button type="button" class="duration-preset-btn" data-minutes="120" onclick="app.selectDurationPreset('120')">2h</button>
<button type="button" class="duration-preset-btn" data-minutes="240" onclick="app.selectDurationPreset('240')">4h</button>
<button type="button" class="duration-preset-btn" data-minutes="480" onclick="app.selectDurationPreset('480')">8h</button>
<button type="button" class="duration-preset-btn active" data-minutes="" onclick="app.selectDurationPreset('')">∞</button>
<div class="duration-custom">
<button type="button" class="duration-preset-btn" data-minutes="custom" onclick="app.selectDurationPreset('custom')">Custom</button>
<div class="input-suffix input-suffix-sm duration-custom-input">
<input type="number" id="modalRespawnDuration" value="" min="1" placeholder="min">
<span>min</span>
</div>
</div>
</div>
<span class="form-hint">How long to run the respawn loop</span>
</div>
<div class="form-row">
<label>Update Prompt</label>
<input type="text" id="modalRespawnPrompt" value="update all the docs and CLAUDE.md" placeholder="Prompt to send when idle" onchange="app.autoSaveRespawnConfig()">
</div>
<div class="form-row">
<label>After Update Prompt</label>
<div class="checkbox-group-inline">
<label class="checkbox-inline">
<input type="checkbox" id="modalRespawnSendClear" checked onchange="app.autoSaveRespawnConfig()">
<span>Send /clear</span>
</label>
<label class="checkbox-inline">
<input type="checkbox" id="modalRespawnSendInit" checked onchange="app.autoSaveRespawnConfig()">
<span>Send /init</span>
</label>
</div>
</div>
<div class="form-row">
<label>Kickstart Prompt</label>
<input type="text" id="modalRespawnKickstart" value="" placeholder="Optional: prompt if /init doesn't trigger work" onchange="app.autoSaveRespawnConfig()">
<span class="form-hint">Sent only when /init completes but Claude stays idle</span>
</div>
<div class="form-row">
<label>Auto-Accept Plan Mode</label>
<div class="checkbox-group-inline">
<label class="checkbox-inline">
<input type="checkbox" id="modalRespawnAutoAccept" checked onchange="app.autoSaveRespawnConfig()">
<span>Accept plan mode approvals</span>
</label>
</div>
<span class="form-hint">Presses Enter to accept plan approvals and default question options when Claude is waiting</span>
</div>
<div class="respawn-actions">
<button class="btn-toolbar btn-success" onclick="app.enableRespawnFromModal()" id="modalEnableRespawnBtn">Enable Respawn</button>
<button class="btn-toolbar btn-danger" onclick="app.stopRespawnFromModal()" id="modalStopRespawnBtn" style="display: none;">Stop Respawn</button>
</div>
</div>
</div><!-- End respawn-tab -->
<!-- Context Management Tab Content -->
<div class="modal-tab-content hidden" id="context-tab">
<div class="form-row">
<label>Auto-Compact Context</label>
<div class="auto-clear-row">
<label class="checkbox-inline">
<input type="checkbox" id="modalAutoCompactEnabled" onchange="app.autoSaveAutoCompact()">
<span>Enable at</span>
</label>
<div class="input-suffix input-suffix-sm">
<input type="number" id="modalAutoCompactThreshold" value="110000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoCompact()">
<span>tokens</span>
</div>
</div>
<input type="text" id="modalAutoCompactPrompt" value="" placeholder="Optional: focus prompt for compact" class="mt-sm" onchange="app.autoSaveAutoCompact()">
<span class="form-hint">Summarizes context while preserving key information</span>
</div>
<div class="form-row">
<label>Auto-Clear Context</label>
<div class="auto-clear-row">
<label class="checkbox-inline">
<input type="checkbox" id="modalAutoClearEnabled" onchange="app.autoSaveAutoClear()">
<span>Enable at</span>
</label>
<div class="input-suffix input-suffix-sm">
<input type="number" id="modalAutoClearThreshold" value="140000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoClear()">
<span>tokens</span>
</div>
</div>
<span class="form-hint">Completely resets context (use higher threshold than compact)</span>
</div>
<div class="form-row form-row-switch">
<label>Image Watcher</label>
<label class="switch">
<input type="checkbox" id="modalImageWatcherEnabled" checked onchange="app.toggleSessionImageWatcher()">
<span class="slider"></span>
</label>
<span class="form-hint">Auto-popup new images (screenshots, etc.) in this session's directory</span>
</div>
</div><!-- End context-tab -->
<!-- Ralph Wiggum Tab Content -->
<div class="modal-tab-content hidden" id="ralph-tab">
<div class="form-row form-row-switch">
<label>Enable Tracker</label>
<label class="switch">
<input type="checkbox" id="modalRalphEnabled">
<span class="slider"></span>
</label>
<span class="form-hint">Enable Ralph / Todo tracker for this session (auto-detects loops and todos)</span>
</div>
<div class="form-row">
<label>Completion Phrase</label>
<input type="text" id="modalRalphPhrase" placeholder="e.g., COMPLETE, DONE, FINISHED">
<span class="form-hint">The phrase Claude outputs when the loop is complete (without &lt;promise&gt; tags)</span>
</div>
<div class="form-row">
<label>Max Iterations</label>
<input type="number" id="modalRalphMaxIterations" value="0" min="0" max="1000">
<span class="form-hint">Maximum respawn cycles (0 = unlimited)</span>
</div>
<div class="form-row">
<label>Max Todos</label>
<input type="number" id="modalRalphMaxTodos" value="50" min="1" max="500">
<span class="form-hint">Maximum todos to track per session</span>
</div>
<div class="form-row">
<label>Todo Expiration</label>
<div class="input-suffix input-suffix-sm">
<input type="number" id="modalRalphTodoExpiration" value="60" min="1" max="1440">
<span>min</span>
</div>
<span class="form-hint">Minutes before todos auto-expire</span>
</div>
<div class="ralph-config-actions">
<button class="btn-toolbar btn-primary" onclick="app.saveRalphConfig()">Save Ralph Config</button>
</div>
</div><!-- End ralph-tab -->
<!-- Summary Tab Content -->
<div class="modal-tab-content hidden" id="summary-tab">
<!-- Stats Cards -->
<div class="run-summary-stats" id="runSummaryStats">
<div class="stat-card">
<div class="stat-value" id="rsStat-cycles">0</div>
<div class="stat-label">Respawn Cycles</div>
</div>
<div class="stat-card">
<div class="stat-value" id="rsStat-tokens">0</div>
<div class="stat-label">Tokens Used</div>
</div>
<div class="stat-card">
<div class="stat-value" id="rsStat-active">0m</div>
<div class="stat-label">Active Time</div>
</div>
<div class="stat-card">
<div class="stat-value" id="rsStat-issues">0</div>
<div class="stat-label">Issues</div>
</div>
</div>
<!-- Filter Buttons -->
<div class="run-summary-filters">
<button class="filter-btn active" data-filter="all" onclick="app.filterRunSummary('all')">All</button>
<button class="filter-btn" data-filter="errors" onclick="app.filterRunSummary('errors')">Errors</button>
<button class="filter-btn" data-filter="warnings" onclick="app.filterRunSummary('warnings')">Warnings</button>
<button class="filter-btn" data-filter="respawn" onclick="app.filterRunSummary('respawn')">Respawn</button>
<button class="filter-btn" data-filter="idle" onclick="app.filterRunSummary('idle')">Idle/Working</button>
</div>
<!-- Timeline -->
<div class="run-summary-timeline" id="runSummaryTimeline">
<p class="empty-message">Select a session to view summary</p>
</div>
<!-- Footer with actions -->
<div class="run-summary-footer">
<span class="run-summary-session-info" id="runSummarySessionInfo"></span>
<div class="run-summary-actions">
<label class="auto-refresh-label">
<input type="checkbox" id="runSummaryAutoRefresh" onchange="app.toggleRunSummaryAutoRefresh()">
Auto-refresh
</label>
<button class="btn-toolbar btn-sm" onclick="app.refreshRunSummary()" title="Refresh summary">&#x21BB; Refresh</button>
<button class="btn-toolbar btn-sm" onclick="app.exportRunSummary('json')" title="Export as JSON">Export JSON</button>
<button class="btn-toolbar btn-sm" onclick="app.exportRunSummary('md')" title="Export as Markdown">Export MD</button>
</div>
</div>
</div><!-- End summary-tab -->
</div>
</div>
</div>
<!-- Run Summary Modal (legacy, kept for backwards compatibility) -->
<div class="modal" id="runSummaryModal">
<div class="modal-backdrop" onclick="app.closeRunSummary()"></div>
<div class="modal-content modal-lg">
<div class="modal-header">
<h3>Run Summary</h3>
<button class="modal-close" onclick="app.closeRunSummary()">&times;</button>
</div>
<div class="modal-body">
<!-- Stats Cards -->
<div class="run-summary-stats" id="runSummaryStats">
<div class="stat-card">
<div class="stat-value" id="rsStat-cycles">0</div>
<div class="stat-label">Respawn Cycles</div>
</div>
<div class="stat-card">
<div class="stat-value" id="rsStat-tokens">0</div>
<div class="stat-label">Tokens Used</div>
</div>
<div class="stat-card">
<div class="stat-value" id="rsStat-active">0m</div>
<div class="stat-label">Active Time</div>
</div>
<div class="stat-card">
<div class="stat-value" id="rsStat-issues">0</div>
<div class="stat-label">Issues</div>
</div>
</div>
<!-- Filter Buttons -->
<div class="run-summary-filters">
<button class="filter-btn active" data-filter="all" onclick="app.filterRunSummary('all')">All</button>
<button class="filter-btn" data-filter="errors" onclick="app.filterRunSummary('errors')">Errors</button>
<button class="filter-btn" data-filter="warnings" onclick="app.filterRunSummary('warnings')">Warnings</button>
<button class="filter-btn" data-filter="respawn" onclick="app.filterRunSummary('respawn')">Respawn</button>
<button class="filter-btn" data-filter="idle" onclick="app.filterRunSummary('idle')">Idle/Working</button>
</div>
<!-- Timeline -->
<div class="run-summary-timeline" id="runSummaryTimeline">
<p class="empty-message">Loading summary...</p>
</div>
</div>
<div class="modal-footer">
<span class="run-summary-session-info" id="runSummarySessionInfo"></span>
<div class="modal-footer-actions">
<label class="auto-refresh-label">
<input type="checkbox" id="runSummaryAutoRefresh" onchange="app.toggleRunSummaryAutoRefresh()">
Auto-refresh
</label>
<button class="btn-toolbar btn-sm" onclick="app.refreshRunSummary()" title="Refresh summary">&#x21BB; Refresh</button>
<button class="btn-toolbar btn-sm" onclick="app.exportRunSummary('json')" title="Export as JSON">Export JSON</button>
<button class="btn-toolbar btn-sm" onclick="app.exportRunSummary('md')" title="Export as Markdown">Export MD</button>
<button class="btn-toolbar btn-sm" onclick="app.closeRunSummary()">Close</button>
</div>
</div>
</div>
</div>
<!-- Close Session Confirmation Modal -->
<div class="modal" id="closeConfirmModal">
<div class="modal-backdrop" onclick="app.cancelCloseSession()"></div>
<div class="modal-content modal-sm">
<div class="modal-header">
<h3>Close Session</h3>
<button class="modal-close" onclick="app.cancelCloseSession()">&times;</button>
</div>
<div class="modal-body">
<p class="modal-session-name" id="closeConfirmSessionName"></p>
</div>
<div class="close-options">
<button class="close-option" onclick="app.confirmCloseSession(false)">
<span class="close-option-title">Remove Tab</span>
<span class="close-option-desc">Screen session keeps running in background</span>
</button>
<button class="close-option close-option-danger" onclick="app.confirmCloseSession(true)">
<span class="close-option-title">Kill Claude</span>
<span class="close-option-desc">Terminate the session completely</span>
</button>
</div>
<div class="modal-footer-cancel">
<button class="btn-toolbar btn-sm" onclick="app.cancelCloseSession()">Cancel</button>
</div>
</div>
</div>
<!-- App Settings Modal -->
<div class="modal" id="appSettingsModal">
<div class="modal-backdrop" onclick="app.closeAppSettings()"></div>
<div class="modal-content modal-lg">
<div class="modal-header">
<h3>App Settings</h3>
<button class="modal-close" onclick="app.closeAppSettings()">&times;</button>
</div>
<div class="modal-tabs">
<button class="modal-tab-btn active" data-tab="settings-display">Display</button>
<button class="modal-tab-btn" data-tab="settings-claude">Claude CLI</button>
<button class="modal-tab-btn" data-tab="settings-models">Models</button>
<button class="modal-tab-btn" data-tab="settings-paths">Paths</button>
<button class="modal-tab-btn" data-tab="settings-notifications">Notifications</button>
</div>
<div class="modal-body">
<!-- Display Tab -->
<div class="modal-tab-content" id="settings-display">
<div class="settings-grid">
<!-- Header Displays Section -->
<div class="settings-section-header">Header Displays</div>
<div class="settings-item" title="Show A-/A+ font size buttons in header">
<span class="settings-item-label">Font Controls</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsShowFontControls" checked>
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Show CPU and memory usage in header">
<span class="settings-item-label">System Stats</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsShowSystemStats" checked>
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Show total token count in header">
<span class="settings-item-label">Token Count</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsShowTokenCount" checked>
<span class="slider"></span>
</label>
</div>
<!-- Panels Section -->
<div class="settings-section-header">Panels</div>
<div class="settings-item" title="Show Monitor panel at bottom right">
<span class="settings-item-label">Monitor</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsShowMonitor" checked>
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Show active tools and file viewers in a floating panel">
<span class="settings-item-label">Project Insights</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsShowProjectInsights" checked>
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Show file browser panel on the right side">
<span class="settings-item-label">File Browser</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsShowFileBrowser">
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Show the Subagents panel (independent from Monitor)">
<span class="settings-item-label">Subagents</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsShowSubagents" checked>
<span class="slider"></span>
</label>
</div>
<!-- Subagent Options Section -->
<div class="settings-section-header">Subagent Options</div>
<div class="settings-item" title="Monitor Claude Code background agents in real-time">
<span class="settings-item-label">Enable Tracking</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsSubagentTracking" checked>
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Only show subagent windows when their parent tab is selected">
<span class="settings-item-label">Active Tab Only</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsSubagentActiveTabOnly">
<span class="slider"></span>
</label>
</div>
<!-- Image Watcher Options Section -->
<div class="settings-section-header">Image Watcher</div>
<div class="settings-item" title="Automatically detect and popup new images in session directories">
<span class="settings-item-label">Enable Globally</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsImageWatcherEnabled" checked>
<span class="slider"></span>
</label>
</div>
</div>
</div>
<!-- Claude CLI Tab -->
<div class="modal-tab-content hidden" id="settings-claude">
<div class="form-row">
<label>Startup Mode</label>
<select id="appSettingsClaudeMode" class="form-select">
<option value="dangerously-skip-permissions">Skip Permissions (default)</option>
<option value="normal">Normal (with prompts)</option>
<option value="allowedTools">Allowed Tools Only</option>
</select>
<span class="form-hint">How Claude CLI is started in screen sessions</span>
</div>
<div class="form-row" id="allowedToolsRow" style="display: none;">
<label>Allowed Tools</label>
<input type="text" id="appSettingsAllowedTools" placeholder="Read,Glob,Grep,Bash">
<span class="form-hint">Comma-separated list of tools to allow</span>
</div>
<div class="form-row form-row-switch">
<label>Enable Ralph / Todo Tracker</label>
<label class="switch">
<input type="checkbox" id="appSettingsRalphEnabled">
<span class="slider"></span>
</label>
<span class="form-hint">Auto-enable for new sessions (otherwise auto-enables on Ralph pattern detection)</span>
</div>
<!-- Nice Priority Section -->
<div class="form-section-header">Nice Priority</div>
<div class="form-row form-row-switch">
<label>Enable Nice Priority Reduction</label>
<label class="switch">
<input type="checkbox" id="appSettingsNiceEnabled">
<span class="slider"></span>
</label>
<span class="form-hint">Lower priority of Claude sessions (reduces system impact, only affects new sessions)</span>
</div>
<div class="form-row" id="niceValueRow">
<label>Nice Value</label>
<input type="number" id="appSettingsNiceValue" min="-20" max="19" value="10" style="width: 80px;">
<span class="form-hint">Process priority (-20 to 19, higher = lower priority, default: 10)</span>
</div>
</div>
<!-- Models Tab -->
<div class="modal-tab-content hidden" id="settings-models">
<div class="form-row">
<label>Default Model</label>
<select id="appSettingsDefaultModel" class="form-select">
<option value="sonnet">Sonnet (Recommended - balanced)</option>
<option value="opus">Opus (Most capable)</option>
<option value="haiku">Haiku (Fast & cheap)</option>
</select>
<span class="form-hint">Model used for execution tasks. Optimizer suggestions are advisory only.</span>
</div>
<div class="form-row form-row-switch">
<label>Show Optimizer Recommendations</label>
<label class="switch">
<input type="checkbox" id="appSettingsShowModelRecommendations" checked>
<span class="slider"></span>
</label>
<span class="form-hint">Show what the optimizer recommends (doesn't override your choice)</span>
</div>
<div class="form-section-header">Agent Type Overrides</div>
<p class="form-hint" style="margin: 0 0 12px 0;">Optionally set specific models for each task type. Leave as "Use Default" to use your default model.</p>
<div class="form-row">
<label>Explore Tasks</label>
<select id="appSettingsModelExplore" class="form-select">
<option value="">Use Default</option>
<option value="haiku">Haiku</option>
<option value="sonnet">Sonnet</option>
<option value="opus">Opus</option>
</select>
<span class="form-hint">Quick searches, codebase exploration</span>
</div>
<div class="form-row">
<label>Implement Tasks</label>
<select id="appSettingsModelImplement" class="form-select">
<option value="">Use Default</option>
<option value="haiku">Haiku</option>
<option value="sonnet">Sonnet</option>
<option value="opus">Opus</option>
</select>
<span class="form-hint">Code writing, feature implementation</span>
</div>
<div class="form-row">
<label>Test Tasks</label>
<select id="appSettingsModelTest" class="form-select">
<option value="">Use Default</option>
<option value="haiku">Haiku</option>
<option value="sonnet">Sonnet</option>
<option value="opus">Opus</option>
</select>
<span class="form-hint">Writing and running tests</span>
</div>
<div class="form-row">
<label>Review Tasks</label>
<select id="appSettingsModelReview" class="form-select">
<option value="">Use Default</option>
<option value="haiku">Haiku</option>
<option value="sonnet">Sonnet</option>
<option value="opus">Opus</option>
</select>
<span class="form-hint">Code review, quality checks</span>
</div>
</div>
<!-- Paths Tab -->
<div class="modal-tab-content hidden" id="settings-paths">
<div class="form-row">
<label>Default CLAUDE.md Template</label>
<input type="text" id="appSettingsClaudeMdPath" placeholder="/path/to/CLAUDE.md template">
<span class="form-hint">Used when creating new cases. Leave empty for built-in template.</span>
</div>
<div class="form-row">
<label>Default Working Directory</label>
<input type="text" id="appSettingsDefaultDir" placeholder="~/projects">
<span class="form-hint">Default directory for new sessions.</span>
</div>
</div>
<!-- Notifications Tab -->
<div class="modal-tab-content hidden" id="settings-notifications">
<div class="settings-grid">
<!-- Master Control Section -->
<div class="settings-section-header">Master Control</div>
<div class="settings-item" title="Master toggle for all notification layers">
<span class="settings-item-label">Enable Notifications</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsNotifEnabled" checked>
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Show OS-level notifications when tab is hidden">
<span class="settings-item-label">Browser</span>
<div class="settings-item-actions">
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsNotifBrowser">
<span class="slider"></span>
</label>
<button class="btn-toolbar btn-sm" onclick="app.notificationManager?.requestPermission()" title="Request browser notification permission">Ask</button>
<span class="settings-status" id="notifPermissionStatus">?</span>
</div>
</div>
<!-- Alerts Section -->
<div class="settings-section-header">Alerts</div>
<div class="settings-item" title="Play a short beep for critical events">
<span class="settings-item-label">Audio Alerts</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsNotifAudio">
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Notify when a session is idle longer than this">
<span class="settings-item-label">Idle Threshold</span>
<div class="settings-item-actions">
<input type="number" id="appSettingsNotifStuckMins" class="settings-item-input" value="10" min="1" max="120">
<span style="font-size: 0.65rem; color: var(--text-muted);">min</span>
</div>
</div>
<!-- Notification Levels Section -->
<div class="settings-section-header">Notification Levels</div>
</div>
<div class="settings-grid settings-grid-3col">
<div class="settings-item" title="Errors, crashes, agent failures">
<span class="settings-item-label">Critical</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsNotifCritical" checked>
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Completions, budget warnings, stuck sessions">
<span class="settings-item-label">Warning</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsNotifWarning" checked>
<span class="slider"></span>
</label>
</div>
<div class="settings-item" title="Auto-accepts, auto-clears, agent completions">
<span class="settings-item-label">Info</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsNotifInfo" checked>
<span class="slider"></span>
</label>
</div>
</div>
</div>
</div>
<div class="form-actions">
<button class="btn-toolbar" onclick="app.closeAppSettings()">Cancel</button>
<button class="btn-toolbar btn-primary" onclick="app.saveAppSettings()">Save</button>
</div>
</div>
</div>
<!-- Create Case Modal -->
<div class="modal" id="createCaseModal">
<div class="modal-backdrop" onclick="app.closeCreateCaseModal()"></div>
<div class="modal-content modal-lg">
<div class="modal-header">
<h3>Add Case</h3>
<button class="modal-close" onclick="app.closeCreateCaseModal()">&times;</button>
</div>
<div class="modal-tabs">
<button class="modal-tab-btn active" data-tab="case-create">Create New</button>
<button class="modal-tab-btn" data-tab="case-link">Link Existing</button>
</div>
<div class="modal-body">
<!-- Create New Tab -->
<div class="modal-tab-content" id="case-create">
<div class="form-row">
<label>Case Name</label>
<input type="text" id="newCaseName" placeholder="my-project" pattern="[a-zA-Z0-9_-]+">
<span class="form-hint">Letters, numbers, hyphens, underscores only. Created in ~/claudeman-cases/</span>
</div>
<div class="form-row">
<label>Description (optional)</label>
<input type="text" id="newCaseDescription" placeholder="A brief description...">
</div>
</div>
<!-- Link Existing Tab -->
<div class="modal-tab-content hidden" id="case-link">
<div class="form-row">
<label>Case Name</label>
<input type="text" id="linkCaseName" placeholder="my-project" pattern="[a-zA-Z0-9_-]+">
<span class="form-hint">Name to identify this case in Claudeman</span>
</div>
<div class="form-row">
<label>Folder Path</label>
<input type="text" id="linkCasePath" placeholder="/home/user/projects/my-project">
<span class="form-hint">Absolute path to an existing project folder</span>
</div>
</div>
</div>
<div class="form-actions">
<button class="btn-toolbar" onclick="app.closeCreateCaseModal()">Cancel</button>
<button class="btn-toolbar btn-primary" id="caseModalSubmit" onclick="app.submitCaseModal()">Create</button>
</div>
</div>
</div>
<!-- Ralph Loop Wizard Modal -->
<div class="modal" id="ralphWizardModal">
<div class="modal-backdrop"></div>
<div class="modal-content modal-wizard">
<div class="modal-header">
<h3>Start Ralph Loop</h3>
<div class="modal-header-actions">
<button class="wizard-minimize-agents" id="wizardMinimizeAgentsBtn" onclick="app.togglePlanAgentsMinimized()" style="display: none;">
<span class="icon">🤖</span>
<span class="agent-count" id="wizardAgentCount">0</span>
</button>
<button class="btn-icon-only wizard-minimize-btn" id="wizardMinimizeBtn" onclick="app.minimizeRalphWizard()" title="Minimize wizard">&#x2012;</button>
<button class="modal-close" onclick="app.closeRalphWizard()">&times;</button>
</div>
</div>
<!-- Wizard Progress Steps -->
<div class="wizard-progress">
<div class="wizard-step active" data-step="1">
<span class="wizard-step-number">1</span>
<span class="wizard-step-label">Describe</span>
</div>
<div class="wizard-step" data-step="2">
<span class="wizard-step-number">2</span>
<span class="wizard-step-label">Plan</span>
</div>
<div class="wizard-step" data-step="3">
<span class="wizard-step-number">3</span>
<span class="wizard-step-label">Launch</span>
</div>
</div>
<div class="modal-body">
<!-- Step 1: Task & Completion Setup -->
<div class="wizard-page wizard-page-compact" id="ralphWizardStep1">
<div class="wizard-step-intro">
<p>Describe your task below. Claude will generate an implementation plan with testing steps.</p>
</div>
<div class="form-row">
<label>What do you want to build?</label>
<div class="textarea-with-assist">
<textarea
id="ralphTaskDescription"
rows="3"
placeholder="Build a REST API for user authentication with JWT tokens, login/logout endpoints, and password reset flow."></textarea>
</div>
</div>
<div class="wizard-inline-row">
<div class="wizard-inline-field">
<label>Working Directory <span id="existingPlanBadge" class="existing-plan-badge" style="display:none"></span></label>
<div class="case-select-inline">
<select id="ralphCaseSelect" class="form-select" onchange="app.onRalphCaseChange()"></select>
<button class="btn-toolbar btn-sm" onclick="app.showCreateCaseModal()">+</button>
</div>
</div>
<div class="wizard-inline-field wizard-inline-field-small">
<label>Iterations</label>
<div class="iteration-presets-compact">
<button type="button" class="iteration-preset-btn active" data-iterations="10" onclick="app.selectIterationPreset(10)">10</button>
<button type="button" class="iteration-preset-btn" data-iterations="25" onclick="app.selectIterationPreset(25)">25</button>
<button type="button" class="iteration-preset-btn" data-iterations="50" onclick="app.selectIterationPreset(50)">50</button>
<button type="button" class="iteration-preset-btn" data-iterations="0" onclick="app.selectIterationPreset(0)">&infin;</button>
</div>
</div>
</div>
<!-- Hidden completion phrase with default -->
<input type="hidden" id="ralphCompletionPhrase" value="COMPLETE">
</div>
<!-- Step 2: Plan Generation -->
<div class="wizard-page wizard-page-compact hidden" id="ralphWizardStep2">
<!-- Existing plan detected (shown when @fix_plan.md exists) -->
<div id="existingPlanSection" class="plan-section hidden">
<!-- Content populated by app.updateExistingPlanUI() -->
</div>
<!-- Loading state (shown during generation) -->
<div id="planGenerationLoading" class="plan-loading-state hidden">
<div class="plan-loading-content">
<div class="plan-spinner"></div>
<div class="plan-loading-text">
<span class="plan-loading-title" id="planLoadingTitle">Starting Opus 4.5...</span>
<span class="plan-loading-time" id="planLoadingTime">0s</span>
</div>
</div>
<p class="plan-loading-hint" id="planLoadingHint">Initializing deep reasoning model</p>
<div class="plan-loading-actions">
<button class="btn-toolbar btn-sm plan-cancel-btn" onclick="app.cancelPlanGeneration()">Stop</button>
<button class="btn-toolbar btn-sm" onclick="app.regeneratePlan()">Regenerate</button>
</div>
<!-- Auto-start toggle visible during generation -->
<div class="plan-autostart-toggle">
<label class="plan-autostart-label">
<input type="checkbox" id="ralphAutoStartStep2" onchange="app.syncAutoStartCheckbox(this)">
<span class="plan-autostart-text">Auto-launch when plan completes</span>
</label>
</div>
</div>
<!-- Stopped/Error state -->
<div id="planGenerationError" class="plan-section hidden">
<div class="plan-stopped-indicator" id="planStoppedIndicator">
<span class="plan-stopped-icon">&#x25A0;</span>
<span class="plan-stopped-text">Stopped</span>
</div>
<p class="plan-error-msg" id="planErrorMsg"></p>
<div class="plan-actions">
<button class="btn-toolbar btn-primary" onclick="app.generatePlan()">Regenerate Plan</button>
</div>
<p class="plan-skip-hint">Use <strong>Back</strong> to edit your task, or <strong>Next</strong> to continue without a plan</p>
</div>
<!-- Editor state -->
<div id="planEditor" class="plan-section hidden">
<div class="plan-editor-header">
<span>Implementation Plan <span class="plan-stats" id="planStats"></span></span>
<div class="plan-editor-actions">
<div class="plan-option-group">
<label>Detail:</label>
<div class="plan-detail-btns">
<button type="button" class="plan-detail-btn" data-detail="brief" onclick="app.setPlanDetail('brief')" title="High-level milestones only">Brief</button>
<button type="button" class="plan-detail-btn" data-detail="standard" onclick="app.setPlanDetail('standard')" title="Single-pass generation with Opus 4.5">Standard</button>
<button type="button" class="plan-detail-btn active" data-detail="detailed" onclick="app.setPlanDetail('detailed')" title="Enhanced: 4 parallel subagents + verification (slower but more thorough)">Enhanced</button>
</div>
</div>
<button class="btn-toolbar btn-sm" onclick="app.regeneratePlan()">Regenerate</button>
</div>
</div>
<div id="planWarnings" class="hidden"></div>
<div id="planItemsList" class="plan-items-list"></div>
<div class="plan-editor-footer">
<button class="btn-toolbar btn-sm" onclick="app.addPlanItem()">+ Add Step</button>
<div class="plan-view-toggle">
<button type="button" class="plan-view-btn active" data-view="list" onclick="app.setPlanViewMode('list')" title="Flat list">&#x2630;</button>
<button type="button" class="plan-view-btn" data-view="grouped" onclick="app.setPlanViewMode('grouped')" title="Group by TDD phase">&#x229E;</button>
</div>
</div>
</div>
</div>
<!-- Step 3: Preview & Launch -->
<div class="wizard-page hidden" id="ralphWizardStep3">
<div class="ralph-preview-section">
<label>Prompt Preview</label>
<div class="ralph-prompt-preview" id="ralphPromptPreview"></div>
</div>
<div class="ralph-config-summary">
<div class="config-summary-row">
<span class="config-label">Completion Phrase:</span>
<code id="summaryPhrase">COMPLETE</code>
</div>
<div class="config-summary-row">
<span class="config-label">Max Iterations:</span>
<span id="summaryIterations">10</span>
</div>
<div class="config-summary-row">
<span class="config-label">Case:</span>
<span id="summaryCase">testcase</span>
</div>
<div class="config-summary-row" style="display: none;">
<span class="config-label">Plan:</span>
<span id="summaryPlan">-</span>
</div>
</div>
<!-- Advanced Options (Collapsible) -->
<details class="advanced-options">
<summary>Advanced Options</summary>
<div class="advanced-options-content">
<div class="form-row form-row-switch">
<label>Auto-Start After Plan</label>
<label class="switch">
<input type="checkbox" id="ralphAutoStart">
<span class="slider"></span>
</label>
<span class="form-hint">Automatically start the loop when plan generation completes</span>
</div>
<div class="form-row form-row-switch">
<label>Enable Respawn</label>
<label class="switch">
<input type="checkbox" id="ralphEnableRespawn">
<span class="slider"></span>
</label>
<span class="form-hint">Auto-restart sessions when context fills up (usually not needed)</span>
</div>
</div>
</details>
</div>
</div>
<!-- Wizard Footer -->
<div class="wizard-footer">
<button class="btn-toolbar" id="ralphBackBtn" onclick="app.ralphWizardBack()" style="display: none;">Back</button>
<div class="wizard-footer-right">
<button class="btn-toolbar" onclick="app.closeRalphWizard()">Cancel</button>
<button class="btn-toolbar btn-primary" id="ralphNextBtn" onclick="app.ralphWizardNext()">Next</button>
<button class="btn-toolbar btn-success" id="ralphStartBtn" onclick="app.startRalphLoop()" style="display: none;">Start Loop</button>
</div>
</div>
</div>
</div>
<!-- Ralph Wizard Minimized Indicator -->
<div class="wizard-minimized-indicator" id="wizardMinimizedIndicator" onclick="app.restoreRalphWizard()">
<span class="wizard-minimized-icon">🔄</span>
<span class="wizard-minimized-text">Ralph Wizard</span>
<span class="wizard-minimized-time" id="wizardMinimizedTime">0s</span>
</div>
<!-- Kill All Confirmation Modal -->
<div class="modal" id="killAllModal">
<div class="modal-backdrop" onclick="app.closeKillAllModal()"></div>
<div class="modal-content modal-sm">
<div class="modal-header">
<h3>Kill All Sessions</h3>
<button class="modal-close" onclick="app.closeKillAllModal()">&times;</button>
</div>
<div class="modal-body">
<p class="modal-warning-text">Choose how to close <span id="killAllCount">0</span> session(s):</p>
</div>
<div class="close-options">
<button class="close-option" onclick="app.confirmKillAll(false)">
<span class="close-option-title">Remove All Tabs</span>
<span class="close-option-desc">Screen sessions keep running in background</span>
</button>
<button class="close-option close-option-danger" onclick="app.confirmKillAll(true)">
<span class="close-option-title">Kill All Claude + Screens</span>
<span class="close-option-desc">Terminate everything completely</span>
</button>
</div>
<div class="modal-footer-cancel">
<button class="btn-toolbar btn-sm" onclick="app.closeKillAllModal()">Cancel</button>
</div>
</div>
</div>
<!-- Notification Drawer -->
<div class="notification-drawer" id="notifDrawer">
<div class="notif-drawer-header">
<span class="notif-drawer-title">Notifications</span>
<div class="notif-drawer-actions">
<button class="btn-notif-action" onclick="app.notificationManager?.markAllRead()" title="Mark all read">&#x2713;</button>
<button class="btn-notif-action" onclick="app.notificationManager?.clearAll()" title="Clear all">&#x1F5D1;</button>
<button class="btn-notif-action" onclick="app.toggleNotifications()" title="Close">&times;</button>
</div>
</div>
<div class="notif-drawer-list" id="notifList"></div>
<div class="notif-drawer-empty" id="notifEmpty">No notifications</div>
</div>
<!-- Help Button -->
<button class="help-btn" onclick="app.showHelp()" title="Keyboard shortcuts (Ctrl+?)">?</button>
<!-- Token Stats Modal -->
<div class="modal" id="tokenStatsModal">
<div class="modal-backdrop" onclick="app.closeTokenStats()"></div>
<div class="modal-content token-stats-modal">
<div class="modal-header">
<h3>Token Usage Statistics</h3>
<button class="modal-close" onclick="app.closeTokenStats()">&times;</button>
</div>
<div class="modal-body">
<div class="stats-summary" id="statsSummary"></div>
<div class="stats-chart-container">
<div class="stats-chart-label">Last 7 Days</div>
<div class="stats-chart" id="statsChart"></div>
<div class="stats-chart-days" id="statsChartDays"></div>
</div>
<div class="stats-table-container">
<div class="stats-table-label">Daily Breakdown</div>
<div class="stats-table" id="statsTable"></div>
</div>
</div>
</div>
</div>
</div>
<!-- SVG Overlay for Subagent Connection Lines -->
<svg id="connectionLines" class="connection-lines-svg">
<!-- Lines drawn dynamically -->
</svg>
<script src="app.js"></script>
</body>
</html>