diff --git a/CLAUDE.md b/CLAUDE.md
index 19523d04..758bb65d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -129,7 +129,7 @@ Codeman is a Claude Code session manager with web interface and autonomous Ralph
| **Infra** | `src/hooks-config.ts`, `src/push-store.ts`, `src/tunnel-manager.ts`, `src/image-watcher.ts`, `src/file-stream-manager.ts` | |
| **Plan** | `src/plan-orchestrator.ts`, `src/prompts/*.ts`, `src/templates/` (`claude-md.ts` + `case-template.md`, the CLAUDE.md scaffold generated into new cases) | |
| **Web** | `src/web/server.ts` ★, `src/web/sse-events.ts`, `src/web/routes/*.ts` (15 route modules + barrel; `session-routes.ts` ★), `src/web/route-helpers.ts`, `src/web/ports/*.ts`, `src/web/middleware/auth.ts`, `src/web/schemas.ts`, `src/web/self-update.ts` | |
-| **Frontend** | `src/web/public/app.js` (~3.6K lines, core) + 5 infra modules (`constants.js`, `mobile-handlers.js`, `voice-input.js`, `notification-manager.js`, `keyboard-accessory.js`) + 7 domain modules (`terminal-ui.js`, `respawn-ui.js`, `ralph-panel.js`, `orchestrator-panel.js`, `settings-ui.js`, `panels-ui.js`, `session-ui.js`) + 5 feature modules (`ralph-wizard.js`, `api-client.js`, `subagent-windows.js`, `input-cjk.js`, `image-input.js`) + `sw.js` | |
+| **Frontend** | `src/web/public/app.js` (~3.7K lines, core) + 5 infra modules (`constants.js`, `mobile-handlers.js`, `voice-input.js`, `notification-manager.js`, `keyboard-accessory.js`) + 7 domain modules (`terminal-ui.js`, `respawn-ui.js`, `ralph-panel.js`, `orchestrator-panel.js`, `settings-ui.js`, `panels-ui.js`, `session-ui.js`) + 5 feature modules (`ralph-wizard.js`, `api-client.js`, `subagent-windows.js`, `input-cjk.js`, `image-input.js`) + `sw.js` | |
| **Types** | `src/types/index.ts` (barrel) → 15 domain files; also `src/types.ts` root re-export | See `@fileoverview` in index.ts |
★ = Large, central file (>50KB) — read its `@fileoverview` first. All files have `@fileoverview` JSDoc — read that before diving in. Discovery aid: `grep -l '@fileoverview' src/web/routes/*.ts` lists all route modules; same grep works for `src/types/`, `src/web/public/*.js`.
diff --git a/src/web/public/index.html b/src/web/public/index.html
index 6abd82ab..420d64b3 100644
--- a/src/web/public/index.html
+++ b/src/web/public/index.html
@@ -604,17 +604,6 @@
-
-
-
- Not active
-
-
-
-
-
-
-
+
+
Respawn loop
+ One autonomous work cycle: whenever Claude goes idle, Codeman sends the update prompt, optionally runs /clear + /init, and kickstarts the next round — repeating for the chosen duration. All settings below belong to this loop; configure them, then press Enable.
+
@@ -660,7 +653,7 @@
-
Respawn Cycle
+
Cycle Steps
@@ -686,6 +679,18 @@
Sent only when /init completes but Claude stays idle · Auto-accept presses Enter for plan approvals and default options
+
+
+
+
+ Not active
+
+
+
+
+
+
+
diff --git a/src/web/public/mobile.css b/src/web/public/mobile.css
index 8b2f251b..435b3bc7 100644
--- a/src/web/public/mobile.css
+++ b/src/web/public/mobile.css
@@ -36,6 +36,13 @@ html.mobile-init .file-browser-panel {
html {
touch-action: manipulation;
}
+
+ /* No "open in new window" (detach) on phones/tablets — popped-out browser
+ windows aren't usable there. !important beats the hover/detached reveal
+ rules in styles.css */
+ .session-tab .tab-detach {
+ display: none !important;
+ }
}
/* ============================================================================
@@ -200,6 +207,12 @@ html.mobile-init .file-browser-panel {
/* ---- Settings Modal: Tablet Optimizations ---- */
+ /* Modals must stack above the fixed tablet header (z-index 1200) so the
+ modal header with the close button stays visible */
+ .modal {
+ z-index: 1300;
+ }
+
.modal-tabs {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
@@ -1215,6 +1228,13 @@ html.mobile-init .file-browser-panel {
max-height: 35vh;
}
+ /* Modals must stack above the fixed mobile header (z-index 1200), or the
+ modal header with the close button is buried underneath it and the
+ full-screen modal cannot be dismissed */
+ .modal {
+ z-index: 1300;
+ }
+
/* Full-screen modals on phones */
.modal-content {
width: 100%;
@@ -1528,42 +1548,36 @@ html.mobile-init .file-browser-panel {
border-radius: 5px;
}
- /* Duration preset buttons — grid layout, 4 columns for even spacing */
+ /* Duration preset buttons — one compact row */
.duration-presets {
- display: grid;
- grid-template-columns: repeat(4, 1fr);
+ display: flex;
+ flex-wrap: wrap;
gap: 0.2rem;
}
.duration-preset-btn {
- min-height: 32px;
- padding: 0.2rem 0.25rem;
- font-size: 0.65rem;
- border-radius: 5px;
+ min-height: 24px;
+ padding: 0.1rem 0.4rem;
+ font-size: 0.6rem;
+ border-radius: 4px;
text-align: center;
}
- /* Custom duration — spans full row below */
.duration-custom {
- grid-column: 1 / -1;
display: flex;
- gap: 0.25rem;
+ gap: 0.2rem;
align-items: center;
}
- .duration-custom .duration-preset-btn {
- flex: 0 0 auto;
- min-width: 50px;
- }
-
.duration-custom-input.visible {
- flex: 1;
+ flex: 0 1 auto;
}
.duration-custom-input input {
- width: 100%;
- min-height: 28px;
+ width: 64px;
+ min-height: 24px;
font-size: 16px; /* Prevents iOS zoom */
+ padding: 0.1rem 0.3rem;
}
/* Preset selector row — full-width dropdown, buttons below */
@@ -1622,6 +1636,16 @@ html.mobile-init .file-browser-panel {
height: 18px;
}
+ /* Respawn-loop box title matches the auto-resume title; its cycle-step
+ checkboxes match the step labels */
+ #sessionOptionsModal .respawn-loop-title {
+ font-size: 0.75rem;
+ }
+
+ #sessionOptionsModal .respawn-loop-box .checkbox-inline {
+ font-size: 0.65rem;
+ }
+
/* Respawn options row — stack if needed */
#sessionOptionsModal .respawn-options-row {
gap: 0.5rem;
diff --git a/src/web/public/styles.css b/src/web/public/styles.css
index a27a99fd..2b5a0e91 100644
--- a/src/web/public/styles.css
+++ b/src/web/public/styles.css
@@ -4645,15 +4645,16 @@ body.solo-mode .btn-lifecycle-log {
width: 60px;
}
-/* Respawn header with status and actions */
+/* Respawn status + Enable/Stop row — sits at the bottom of the Respawn tab,
+ below the settings it acts on */
.respawn-header {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
- margin-bottom: 0.75rem;
- padding-bottom: 0.75rem;
- border-bottom: 1px solid var(--border);
+ margin-top: 0.75rem;
+ padding-top: 0.75rem;
+ border-top: 1px solid rgba(34, 197, 94, 0.2);
}
.respawn-header .respawn-actions {
@@ -4692,6 +4693,39 @@ body.solo-mode .btn-lifecycle-log {
margin-top: 0;
}
+/* Respawn loop box — groups every setting that belongs to the autonomous
+ respawn cycle (duration, presets, cycle prompts, enable). Green like its
+ Enable button; a visual sibling of the standalone auto-resume option above */
+.respawn-loop-box {
+ margin: 0.75rem 0;
+ padding: 0.6rem 0.75rem;
+ background: rgba(34, 197, 94, 0.05);
+ border: 1px solid rgba(34, 197, 94, 0.3);
+ border-radius: 6px;
+}
+
+.respawn-loop-title {
+ font-size: 0.85rem;
+ font-weight: 500;
+ color: var(--text);
+ margin-bottom: 0.3rem;
+}
+
+.respawn-loop-hint {
+ display: block;
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+}
+
+.respawn-loop-box .form-section-header {
+ border-bottom-color: rgba(34, 197, 94, 0.2);
+}
+
+/* Match the cycle-step checkboxes (2./3.) to the step labels (1./4.) */
+.respawn-loop-box .checkbox-inline {
+ font-size: 0.7rem;
+}
+
.auto-resume-status {
display: none;
font-size: 0.7rem;