aicodeman 1.16.2 → 1.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/README.md +11 -10
  2. package/dist/claude-credentials.d.ts +50 -0
  3. package/dist/claude-credentials.d.ts.map +1 -0
  4. package/dist/claude-credentials.js +102 -0
  5. package/dist/claude-credentials.js.map +1 -0
  6. package/dist/config/voice.d.ts +43 -0
  7. package/dist/config/voice.d.ts.map +1 -0
  8. package/dist/config/voice.js +48 -0
  9. package/dist/config/voice.js.map +1 -0
  10. package/dist/search-service.d.ts +9 -1
  11. package/dist/search-service.d.ts.map +1 -1
  12. package/dist/search-service.js +13 -3
  13. package/dist/search-service.js.map +1 -1
  14. package/dist/services/unified-session-service.d.ts +9 -0
  15. package/dist/services/unified-session-service.d.ts.map +1 -1
  16. package/dist/services/unified-session-service.js +4 -1
  17. package/dist/services/unified-session-service.js.map +1 -1
  18. package/dist/types/search.d.ts +17 -3
  19. package/dist/types/search.d.ts.map +1 -1
  20. package/dist/web/ports/config-port.d.ts +2 -0
  21. package/dist/web/ports/config-port.d.ts.map +1 -1
  22. package/dist/web/public/admin-ui.js +35 -20
  23. package/dist/web/public/admin-ui.js.br +0 -0
  24. package/dist/web/public/admin-ui.js.gz +0 -0
  25. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  26. package/dist/web/public/{app.4d006245.js → app.f9c6aadd.js} +18 -18
  27. package/dist/web/public/app.f9c6aadd.js.br +0 -0
  28. package/dist/web/public/app.f9c6aadd.js.gz +0 -0
  29. package/dist/web/public/approvals-ui.js.gz +0 -0
  30. package/dist/web/public/{constants.7d0f4047.js → constants.53dc0fa1.js} +43 -0
  31. package/dist/web/public/constants.53dc0fa1.js.br +0 -0
  32. package/dist/web/public/constants.53dc0fa1.js.gz +0 -0
  33. package/dist/web/public/cron-ui.js.gz +0 -0
  34. package/dist/web/public/entrance-animations.js.gz +0 -0
  35. package/dist/web/public/home-sessions.js +132 -10
  36. package/dist/web/public/home-sessions.js.br +0 -0
  37. package/dist/web/public/home-sessions.js.gz +0 -0
  38. package/dist/web/public/i18n.89097ff5.js +1 -0
  39. package/dist/web/public/i18n.89097ff5.js.br +0 -0
  40. package/dist/web/public/i18n.89097ff5.js.gz +0 -0
  41. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  42. package/dist/web/public/index.html +1335 -1000
  43. package/dist/web/public/index.html.br +0 -0
  44. package/dist/web/public/index.html.gz +0 -0
  45. package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
  46. package/dist/web/public/{keyboard-accessory.1f35b482.js → keyboard-accessory.0f524637.js} +207 -5
  47. package/dist/web/public/keyboard-accessory.0f524637.js.br +0 -0
  48. package/dist/web/public/keyboard-accessory.0f524637.js.gz +0 -0
  49. package/dist/web/public/mobile-handlers.32fdd57f.js.gz +0 -0
  50. package/dist/web/public/mobile-overview.js.gz +0 -0
  51. package/dist/web/public/mobile.4f875962.css +1 -0
  52. package/dist/web/public/mobile.4f875962.css.br +0 -0
  53. package/dist/web/public/mobile.4f875962.css.gz +0 -0
  54. package/dist/web/public/notification-manager.5d229063.js.gz +0 -0
  55. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  56. package/dist/web/public/{panels-ui.3df9cd95.js → panels-ui.54b0d004.js} +1 -1
  57. package/dist/web/public/panels-ui.54b0d004.js.br +0 -0
  58. package/dist/web/public/panels-ui.54b0d004.js.gz +0 -0
  59. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  60. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  61. package/dist/web/public/readmymind-ui.js +98 -18
  62. package/dist/web/public/readmymind-ui.js.br +0 -0
  63. package/dist/web/public/readmymind-ui.js.gz +0 -0
  64. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  65. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  66. package/dist/web/public/{session-ui.f4fed187.js → session-ui.46a0993c.js} +5 -5
  67. package/dist/web/public/session-ui.46a0993c.js.br +0 -0
  68. package/dist/web/public/session-ui.46a0993c.js.gz +0 -0
  69. package/dist/web/public/settings-ui.63be4178.js +67 -0
  70. package/dist/web/public/settings-ui.63be4178.js.br +0 -0
  71. package/dist/web/public/settings-ui.63be4178.js.gz +0 -0
  72. package/dist/web/public/styles.9e04378d.css +1 -0
  73. package/dist/web/public/styles.9e04378d.css.br +0 -0
  74. package/dist/web/public/styles.9e04378d.css.gz +0 -0
  75. package/dist/web/public/subagent-windows.4cc8b005.js.gz +0 -0
  76. package/dist/web/public/sw.js.gz +0 -0
  77. package/dist/web/public/terminal-ui.ae776405.js +4 -0
  78. package/dist/web/public/terminal-ui.ae776405.js.br +0 -0
  79. package/dist/web/public/terminal-ui.ae776405.js.gz +0 -0
  80. package/dist/web/public/ultracode-panel.js.gz +0 -0
  81. package/dist/web/public/ultracode-windows.js.gz +0 -0
  82. package/dist/web/public/upload.html.gz +0 -0
  83. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  84. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  85. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  86. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  87. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  88. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  89. package/dist/web/public/vendor/xterm-predictive-echo.6cec0fba.js.gz +0 -0
  90. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  91. package/dist/web/public/vendor/xterm.css.gz +0 -0
  92. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  93. package/dist/web/public/{voice-input.e5461859.js → voice-input.4ec670b0.js} +421 -13
  94. package/dist/web/public/voice-input.4ec670b0.js.br +0 -0
  95. package/dist/web/public/voice-input.4ec670b0.js.gz +0 -0
  96. package/dist/web/public/voice-pcm-worklet.js +57 -0
  97. package/dist/web/public/voice-pcm-worklet.js.br +0 -0
  98. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  99. package/dist/web/public/webview-tabs.js.gz +0 -0
  100. package/dist/web/routes/index.d.ts +1 -0
  101. package/dist/web/routes/index.d.ts.map +1 -1
  102. package/dist/web/routes/index.js +1 -0
  103. package/dist/web/routes/index.js.map +1 -1
  104. package/dist/web/routes/search-routes.d.ts +3 -1
  105. package/dist/web/routes/search-routes.d.ts.map +1 -1
  106. package/dist/web/routes/search-routes.js +34 -1
  107. package/dist/web/routes/search-routes.js.map +1 -1
  108. package/dist/web/routes/session-routes.d.ts.map +1 -1
  109. package/dist/web/routes/session-routes.js +151 -9
  110. package/dist/web/routes/session-routes.js.map +1 -1
  111. package/dist/web/routes/voice-routes.d.ts +45 -0
  112. package/dist/web/routes/voice-routes.d.ts.map +1 -0
  113. package/dist/web/routes/voice-routes.js +172 -0
  114. package/dist/web/routes/voice-routes.js.map +1 -0
  115. package/dist/web/schemas.d.ts +2 -0
  116. package/dist/web/schemas.d.ts.map +1 -1
  117. package/dist/web/schemas.js +12 -0
  118. package/dist/web/schemas.js.map +1 -1
  119. package/dist/web/server.d.ts +1 -0
  120. package/dist/web/server.d.ts.map +1 -1
  121. package/dist/web/server.js +11 -1
  122. package/dist/web/server.js.map +1 -1
  123. package/dist/web/session-history-index.d.ts +108 -0
  124. package/dist/web/session-history-index.d.ts.map +1 -0
  125. package/dist/web/session-history-index.js +118 -0
  126. package/dist/web/session-history-index.js.map +1 -0
  127. package/dist/web/voice-stream.d.ts +96 -0
  128. package/dist/web/voice-stream.d.ts.map +1 -0
  129. package/dist/web/voice-stream.js +268 -0
  130. package/dist/web/voice-stream.js.map +1 -0
  131. package/package.json +1 -1
  132. package/dist/web/public/app.4d006245.js.br +0 -0
  133. package/dist/web/public/app.4d006245.js.gz +0 -0
  134. package/dist/web/public/constants.7d0f4047.js.br +0 -0
  135. package/dist/web/public/constants.7d0f4047.js.gz +0 -0
  136. package/dist/web/public/i18n.ef50083f.js +0 -1
  137. package/dist/web/public/i18n.ef50083f.js.br +0 -0
  138. package/dist/web/public/i18n.ef50083f.js.gz +0 -0
  139. package/dist/web/public/keyboard-accessory.1f35b482.js.br +0 -0
  140. package/dist/web/public/keyboard-accessory.1f35b482.js.gz +0 -0
  141. package/dist/web/public/mobile.5d8c896c.css +0 -1
  142. package/dist/web/public/mobile.5d8c896c.css.br +0 -0
  143. package/dist/web/public/mobile.5d8c896c.css.gz +0 -0
  144. package/dist/web/public/panels-ui.3df9cd95.js.br +0 -0
  145. package/dist/web/public/panels-ui.3df9cd95.js.gz +0 -0
  146. package/dist/web/public/session-ui.f4fed187.js.br +0 -0
  147. package/dist/web/public/session-ui.f4fed187.js.gz +0 -0
  148. package/dist/web/public/settings-ui.1c15649c.js +0 -67
  149. package/dist/web/public/settings-ui.1c15649c.js.br +0 -0
  150. package/dist/web/public/settings-ui.1c15649c.js.gz +0 -0
  151. package/dist/web/public/styles.0024c22e.css +0 -1
  152. package/dist/web/public/styles.0024c22e.css.br +0 -0
  153. package/dist/web/public/styles.0024c22e.css.gz +0 -0
  154. package/dist/web/public/terminal-ui.e7c5d233.js +0 -4
  155. package/dist/web/public/terminal-ui.e7c5d233.js.br +0 -0
  156. package/dist/web/public/terminal-ui.e7c5d233.js.gz +0 -0
  157. package/dist/web/public/voice-input.e5461859.js.br +0 -0
  158. package/dist/web/public/voice-input.e5461859.js.gz +0 -0
@@ -16,16 +16,16 @@
16
16
  <link rel="manifest" href="manifest.json">
17
17
  <title>Codeman</title>
18
18
  <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">
19
- <link rel="stylesheet" href="styles.0024c22e.css">
20
- <link rel="stylesheet" href="mobile.5d8c896c.css" media="(max-width: 1023px)">
19
+ <link rel="stylesheet" href="styles.9e04378d.css">
20
+ <link rel="stylesheet" href="mobile.4f875962.css" media="(max-width: 1023px)">
21
21
  <!-- xterm.css loaded async — terminal won't display until xterm.js runs anyway -->
22
22
  <link rel="preload" href="vendor/xterm.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
23
23
  <noscript><link rel="stylesheet" href="vendor/xterm.css"></noscript>
24
24
  <!-- Preload critical resources — lets browser discover these during HTML parse
25
25
  instead of waiting until <script> tags at bottom-of-body are reached. -->
26
26
  <link rel="preload" href="vendor/xterm.min.js" as="script">
27
- <link rel="preload" href="constants.7d0f4047.js" as="script">
28
- <link rel="preload" href="app.4d006245.js" as="script">
27
+ <link rel="preload" href="constants.53dc0fa1.js" as="script">
28
+ <link rel="preload" href="app.f9c6aadd.js" as="script">
29
29
  <!-- Self-hosted xterm.js — eliminates CDN DNS/TLS latency (~100ms).
30
30
  'defer' preserves execution order (xterm loads before fit addon). -->
31
31
  <script defer src="vendor/xterm.min.js"></script>
@@ -323,9 +323,9 @@
323
323
 
324
324
  <!-- Welcome Overlay (shown when no session active) -->
325
325
  <div class="welcome-overlay" id="welcomeOverlay">
326
- <!-- Open tabs as a vertical column in the left gutter (home-sessions.js).
326
+ <!-- Open tabs as a rail docked to the left edge (home-sessions.js).
327
327
  Absolutely positioned so the centered content below never moves, and
328
- therefore only rendered where the gutter is wider than the column;
328
+ therefore only rendered where the gutter is wider than the rail;
329
329
  ships `hidden` and only that module reveals it. -->
330
330
  <aside class="home-sessions" id="homeSessions" hidden></aside>
331
331
  <div class="welcome-content">
@@ -397,7 +397,27 @@
397
397
  </div>
398
398
  <div class="search-results" id="searchResults" hidden></div>
399
399
  </div>
400
- <h3 class="history-title" id="historyTitle">Resume Conversation</h3>
400
+ <div class="history-header" id="historyHeader">
401
+ <h3 class="history-title" id="historyTitle">Resume Conversation</h3>
402
+ <span class="history-count" id="historyCount" data-i18n-skip></span>
403
+ <div class="history-controls">
404
+ <input
405
+ type="search"
406
+ id="historyFilter"
407
+ class="history-filter"
408
+ placeholder="Filter…"
409
+ autocomplete="off"
410
+ spellcheck="false"
411
+ maxlength="100"
412
+ aria-label="Filter past conversations"
413
+ />
414
+ <select id="historySort" class="search-select history-sort" aria-label="Sort past conversations">
415
+ <option value="recent">Recent</option>
416
+ <option value="name">Name A–Z</option>
417
+ <option value="folder">Folder A–Z</option>
418
+ </select>
419
+ </div>
420
+ </div>
401
421
  <div class="history-list" id="historyList"></div>
402
422
  </div>
403
423
  <p class="welcome-hint">Or click Run to start</p>
@@ -963,282 +983,382 @@
963
983
  </div>
964
984
 
965
985
  <!-- Session Options Modal (includes Respawn Settings) -->
986
+ <!-- Session Options: same `set-*` surface as App Settings, but the rail is a
987
+ real switcher (one .set-section at a time) rather than a table of
988
+ contents — see the settings-surface block in styles.css. -->
966
989
  <div class="modal" id="sessionOptionsModal">
967
990
  <div class="modal-backdrop" onclick="app.closeSessionOptions()"></div>
968
- <div class="modal-content">
969
- <div class="modal-header">
991
+ <div class="modal-content modal-lg set-shell">
992
+ <div class="modal-header set-shell-head">
970
993
  <h3>Session Options</h3>
971
- <button class="modal-close" onclick="app.closeSessionOptions()" aria-label="Close session options">&times;</button>
972
- </div>
973
- <!-- Modal Tabs -->
974
- <div class="modal-tabs">
975
- <button class="modal-tab-btn active" data-tab="respawn" data-claude-only onclick="app.switchOptionsTab('respawn')">Respawn</button>
976
- <button class="modal-tab-btn" data-tab="context" onclick="app.switchOptionsTab('context')">Context</button>
977
- <button class="modal-tab-btn" data-tab="ralph" data-claude-only onclick="app.switchOptionsTab('ralph')">Ralph / Todo</button>
978
- <button class="modal-tab-btn" data-tab="summary" onclick="app.switchOptionsTab('summary')">Summary</button>
994
+ <div class="set-head-actions">
995
+ <button class="modal-close" onclick="app.closeSessionOptions()" aria-label="Close session options">&times;</button>
996
+ </div>
979
997
  </div>
980
- <div class="modal-body">
981
- <!-- Respawn Tab Content -->
982
- <div class="modal-tab-content" id="respawn-tab">
983
- <!-- Respawn Settings Section -->
984
- <div class="session-respawn-section" id="sessionRespawnSection">
985
- <div class="auto-resume-box">
986
- <label class="checkbox-inline">
987
- <input type="checkbox" id="modalAutoResumeEnabled" onchange="app.autoSaveAutoResume()">
988
- <span>Auto-resume when usage limit resets</span>
989
- </label>
990
- <span class="auto-resume-status" id="autoResumeStatus"></span>
991
- <span class="form-hint">If Claude pauses on a usage limit ("limit reached &middot; resets 3pm"), Codeman waits for the reset time and automatically continues the work. Independent of the respawn loop below.</span>
998
+ <div class="set-body">
999
+ <nav class="set-rail" id="sessionOptionsRail" aria-label="Session option sections">
1000
+ <div class="set-rail-items">
1001
+ <button type="button" class="set-rail-item active" data-tab="respawn" data-claude-only onclick="app.switchOptionsTab('respawn')">
1002
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
1003
+ <span>Respawn</span>
1004
+ </button>
1005
+ <button type="button" class="set-rail-item" data-tab="context" onclick="app.switchOptionsTab('context')">
1006
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v6c0 1.7 3.6 3 8 3s8-1.3 8-3V6"/><path d="M4 12v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6"/></svg>
1007
+ <span>Session</span>
1008
+ </button>
1009
+ <button type="button" class="set-rail-item" data-tab="ralph" data-claude-only onclick="app.switchOptionsTab('ralph')">
1010
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 6h11"/><path d="M9 12h11"/><path d="M9 18h11"/><polyline points="3 6 4 7 6 5"/><polyline points="3 12 4 13 6 11"/><polyline points="3 18 4 19 6 17"/></svg>
1011
+ <span>Ralph / Todo</span>
1012
+ </button>
1013
+ <button type="button" class="set-rail-item" data-tab="summary" onclick="app.switchOptionsTab('summary')">
1014
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3v18h18"/><polyline points="7 14 11 10 14 13 20 7"/></svg>
1015
+ <span>Summary</span>
1016
+ </button>
992
1017
  </div>
1018
+ <p class="set-rail-foot">These options belong to the selected session and save as you change them.</p>
1019
+ </nav>
1020
+
1021
+ <div class="set-doc" id="sessionOptionsDoc">
1022
+ <!-- ══ Respawn ══════════════════════════════════════════════════ -->
1023
+ <section class="set-section" id="respawn-tab" data-label="Respawn">
1024
+ <div class="set-section-head">
1025
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
1026
+ <h2>Respawn</h2>
1027
+ </div>
1028
+ <p class="set-section-blurb">One autonomous work cycle, plus what to do when a usage limit pauses the session.</p>
1029
+
1030
+ <!-- The one setting on this tab worth reading before anything
1031
+ else, so it is a callout rather than the first row of a list:
1032
+ it is what turns a limit-halted overnight run back on. -->
1033
+ <label class="set-callout">
1034
+ <span class="set-callout-ico" aria-hidden="true">
1035
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 14"/></svg>
1036
+ </span>
1037
+ <span class="set-callout-text">
1038
+ <span class="set-callout-title">Auto-resume when the usage limit resets</span>
1039
+ <span class="set-callout-desc">Claude stops on a subscription limit ("limit reached &middot; resets 3pm") and sits there until you come back. Switch this on and Codeman waits out the reset, then continues the work on its own. Independent of the respawn loop below.</span>
1040
+ <span class="auto-resume-status" id="autoResumeStatus"></span>
1041
+ </span>
1042
+ <span class="switch switch-sm set-callout-switch"><input type="checkbox" id="modalAutoResumeEnabled" onchange="app.autoSaveAutoResume()"><span class="slider"></span></span>
1043
+ </label>
993
1044
 
994
- <div class="respawn-loop-box">
995
- <div class="respawn-loop-title">Respawn loop</div>
996
- <span class="form-hint respawn-loop-hint">One autonomous work cycle: whenever Claude goes idle, Codeman sends the update prompt, optionally runs /clear + /init, and kickstarts the next round &mdash; repeating for the chosen duration. All settings below belong to this loop; configure them, then press Enable.</span>
1045
+ <!-- Hidden wholesale for non-claude sessions and for a session with
1046
+ no live process (session-ui.js: openSessionOptions). -->
1047
+ <div id="sessionRespawnSection">
1048
+ <div class="set-group">
1049
+ <div class="set-group-head"><h4>Loop control</h4></div>
1050
+ <div class="set-group-body">
1051
+ <div class="set-row">
1052
+ <div class="set-row-text">
1053
+ <span class="set-row-label">Status</span>
1054
+ <div class="session-respawn-status" id="sessionRespawnStatus">
1055
+ <span class="respawn-status-indicator"></span>
1056
+ <span class="respawn-status-text">Not active</span>
1057
+ </div>
1058
+ </div>
1059
+ <div class="set-row-actions">
1060
+ <button class="btn-toolbar btn-success btn-sm" onclick="app.enableRespawnFromModal()" id="modalEnableRespawnBtn">Enable</button>
1061
+ <button class="btn-toolbar btn-danger btn-sm" onclick="app.stopRespawnFromModal()" id="modalStopRespawnBtn" style="display: none;">Stop</button>
1062
+ </div>
1063
+ </div>
1064
+ </div>
1065
+ </div>
997
1066
 
998
- <div class="form-row">
999
- <label>Duration</label>
1000
- <div class="duration-presets">
1001
- <button type="button" class="duration-preset-btn" data-minutes="30" onclick="app.selectDurationPreset('30')">30m</button>
1002
- <button type="button" class="duration-preset-btn" data-minutes="60" onclick="app.selectDurationPreset('60')">1h</button>
1003
- <button type="button" class="duration-preset-btn" data-minutes="120" onclick="app.selectDurationPreset('120')">2h</button>
1004
- <button type="button" class="duration-preset-btn" data-minutes="240" onclick="app.selectDurationPreset('240')">4h</button>
1005
- <button type="button" class="duration-preset-btn" data-minutes="480" onclick="app.selectDurationPreset('480')">8h</button>
1006
- <button type="button" class="duration-preset-btn active" data-minutes="" onclick="app.selectDurationPreset('')">∞</button>
1007
- <div class="duration-custom">
1008
- <button type="button" class="duration-preset-btn" data-minutes="custom" onclick="app.selectDurationPreset('custom')">Custom</button>
1009
- <div class="input-suffix input-suffix-sm duration-custom-input">
1010
- <input type="number" id="modalRespawnDuration" value="" min="1" placeholder="min">
1011
- <span>min</span>
1067
+ <div class="set-group">
1068
+ <div class="set-group-head"><h4>Respawn loop</h4></div>
1069
+ <p class="set-group-hint">Whenever Claude goes idle, Codeman sends the update prompt, optionally runs /clear + /init, and kickstarts the next round &mdash; repeating for the chosen duration. Configure it here, then press Enable.</p>
1070
+ <div class="set-group-body">
1071
+ <div class="set-row set-row-block">
1072
+ <div class="set-row-text">
1073
+ <span class="set-row-label">Duration</span>
1074
+ <span class="set-row-desc">How long the loop keeps cycling before it stops on its own.</span>
1075
+ </div>
1076
+ <div class="duration-presets">
1077
+ <button type="button" class="duration-preset-btn" data-minutes="30" onclick="app.selectDurationPreset('30')">30m</button>
1078
+ <button type="button" class="duration-preset-btn" data-minutes="60" onclick="app.selectDurationPreset('60')">1h</button>
1079
+ <button type="button" class="duration-preset-btn" data-minutes="120" onclick="app.selectDurationPreset('120')">2h</button>
1080
+ <button type="button" class="duration-preset-btn" data-minutes="240" onclick="app.selectDurationPreset('240')">4h</button>
1081
+ <button type="button" class="duration-preset-btn" data-minutes="480" onclick="app.selectDurationPreset('480')">8h</button>
1082
+ <button type="button" class="duration-preset-btn active" data-minutes="" onclick="app.selectDurationPreset('')">&#8734;</button>
1083
+ <div class="duration-custom">
1084
+ <button type="button" class="duration-preset-btn" data-minutes="custom" onclick="app.selectDurationPreset('custom')">Custom</button>
1085
+ <div class="input-suffix input-suffix-sm duration-custom-input">
1086
+ <input type="number" id="modalRespawnDuration" value="" min="1" placeholder="min">
1087
+ <span>min</span>
1088
+ </div>
1089
+ </div>
1090
+ </div>
1091
+ </div>
1092
+
1093
+ <div class="set-row set-row-block">
1094
+ <div class="set-row-text">
1095
+ <span class="set-row-label">Preset</span>
1096
+ <span class="set-row-desc">Load a saved loop configuration, or store the current one under a name.</span>
1097
+ </div>
1098
+ <div class="set-row-actions set-row-actions-wide">
1099
+ <select id="respawnPresetSelect" class="set-select" onchange="app.updatePresetDescription()">
1100
+ <option value="">-- Select preset --</option>
1101
+ <optgroup label="Built-in" id="builtinPresetsGroup">
1102
+ </optgroup>
1103
+ <optgroup label="Custom" id="customPresetsGroup">
1104
+ </optgroup>
1105
+ </select>
1106
+ <button type="button" class="btn-toolbar btn-sm" onclick="app.loadRespawnPreset()" title="Apply preset">Apply</button>
1107
+ <button type="button" class="btn-toolbar btn-sm" onclick="app.saveCurrentAsPreset()" title="Save current config as preset">Save As&hellip;</button>
1108
+ </div>
1109
+ <!-- Filled by updatePresetDescription() and CLEARED on every
1110
+ open, so it can never hold the row's own description. -->
1111
+ <span class="set-row-desc set-row-note" id="presetDescriptionHint"></span>
1112
+ </div>
1012
1113
  </div>
1013
1114
  </div>
1014
- </div>
1015
- </div>
1016
1115
 
1017
- <div class="form-section-header">Presets</div>
1018
- <div class="form-row">
1019
- <label>Load Preset</label>
1020
- <div class="preset-selector">
1021
- <select id="respawnPresetSelect" onchange="app.updatePresetDescription()">
1022
- <option value="">-- Select preset --</option>
1023
- <optgroup label="Built-in" id="builtinPresetsGroup">
1024
- </optgroup>
1025
- <optgroup label="Custom" id="customPresetsGroup">
1026
- </optgroup>
1027
- </select>
1028
- <button type="button" class="btn btn-sm" onclick="app.loadRespawnPreset()" title="Apply preset">Apply</button>
1029
- <button type="button" class="btn btn-sm btn-secondary" onclick="app.saveCurrentAsPreset()" title="Save current config as preset">Save As...</button>
1030
- </div>
1031
- <p class="form-hint" id="presetDescriptionHint"></p>
1032
- </div>
1116
+ <div class="set-group">
1117
+ <div class="set-group-head"><h4>Cycle steps</h4></div>
1118
+ <div class="set-group-body">
1119
+ <div class="set-row set-row-block">
1120
+ <div class="set-row-text">
1121
+ <span class="set-row-label">1. Update prompt</span>
1122
+ <span class="set-row-desc">Sent as soon as the session goes idle.</span>
1123
+ </div>
1124
+ <textarea id="modalRespawnPrompt" class="set-textarea" rows="1" placeholder="Prompt to send when idle" onchange="app.autoSaveRespawnConfig()">update all the docs and CLAUDE.md</textarea>
1125
+ </div>
1033
1126
 
1034
- <div class="form-section-header">Cycle Steps</div>
1035
- <div class="form-row">
1036
- <label>1. Update Prompt</label>
1037
- <textarea id="modalRespawnPrompt" rows="1" placeholder="Prompt to send when idle" onchange="app.autoSaveRespawnConfig()" style="resize: vertical; min-height: 30px;">update all the docs and CLAUDE.md</textarea>
1038
- </div>
1127
+ <!-- Real checkboxes, deliberately: these are numbered steps of
1128
+ one cycle, not a set of independent tags. -->
1129
+ <div class="set-row set-checks">
1130
+ <label class="set-check"><input type="checkbox" id="modalRespawnSendClear" checked onchange="app.autoSaveRespawnConfig()"><span>2. Send /clear</span></label>
1131
+ <label class="set-check"><input type="checkbox" id="modalRespawnSendInit" checked onchange="app.autoSaveRespawnConfig()"><span>3. Send /init</span></label>
1132
+ <label class="set-check" title="Presses Enter for plan approvals and default question options"><input type="checkbox" id="modalRespawnAutoAccept" checked onchange="app.autoSaveRespawnConfig()"><span>Auto-accept prompts</span></label>
1133
+ </div>
1039
1134
 
1040
- <div class="respawn-options-row" style="margin: 8px 0;">
1041
- <label class="checkbox-inline">
1042
- <input type="checkbox" id="modalRespawnSendClear" checked onchange="app.autoSaveRespawnConfig()">
1043
- <span>2. Send /clear</span>
1044
- </label>
1045
- <label class="checkbox-inline">
1046
- <input type="checkbox" id="modalRespawnSendInit" checked onchange="app.autoSaveRespawnConfig()">
1047
- <span>3. Send /init</span>
1048
- </label>
1049
- <label class="checkbox-inline" title="Presses Enter for plan approvals and default question options">
1050
- <input type="checkbox" id="modalRespawnAutoAccept" checked onchange="app.autoSaveRespawnConfig()">
1051
- <span>Auto-accept prompts</span>
1052
- </label>
1053
- </div>
1135
+ <div class="set-row set-row-block">
1136
+ <div class="set-row-text">
1137
+ <span class="set-row-label">4. Kickstart prompt</span>
1138
+ <span class="set-row-desc">Sent only when /init finishes but Claude stays idle. Optional.</span>
1139
+ </div>
1140
+ <textarea id="modalRespawnKickstart" class="set-textarea" rows="1" placeholder="Optional: prompt if /init doesn't trigger work" onchange="app.autoSaveRespawnConfig()"></textarea>
1141
+ </div>
1142
+ </div>
1143
+ </div>
1054
1144
 
1055
- <div class="form-row">
1056
- <label>4. Kickstart Prompt</label>
1057
- <textarea id="modalRespawnKickstart" rows="1" placeholder="Optional: prompt if /init doesn't trigger work" onchange="app.autoSaveRespawnConfig()" style="resize: vertical; min-height: 30px;"></textarea>
1058
- <span class="form-hint">Sent only when /init completes but Claude stays idle &middot; Auto-accept presses Enter for plan approvals and default options</span>
1059
- </div>
1145
+ </div><!-- End sessionRespawnSection -->
1146
+ </section>
1060
1147
 
1061
- <div class="respawn-header">
1062
- <div class="session-respawn-status" id="sessionRespawnStatus">
1063
- <span class="respawn-status-indicator"></span>
1064
- <span class="respawn-status-text">Not active</span>
1065
- </div>
1066
- <div class="respawn-actions">
1067
- <button class="btn-toolbar btn-success btn-sm" onclick="app.enableRespawnFromModal()" id="modalEnableRespawnBtn">Enable</button>
1068
- <button class="btn-toolbar btn-danger btn-sm" onclick="app.stopRespawnFromModal()" id="modalStopRespawnBtn" style="display: none;">Stop</button>
1148
+ <!-- ══ Context ══════════════════════════════════════════════════ -->
1149
+ <section class="set-section hidden" id="context-tab" data-label="Session">
1150
+ <div class="set-section-head">
1151
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v6c0 1.7 3.6 3 8 3s8-1.3 8-3V6"/><path d="M4 12v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6"/></svg>
1152
+ <h2>Session</h2>
1069
1153
  </div>
1070
- </div>
1071
- </div><!-- End respawn-loop-box -->
1072
- </div>
1073
- </div><!-- End respawn-tab -->
1154
+ <p class="set-section-blurb">What this tab is called, how its context window is kept from filling up, and what it watches.</p>
1074
1155
 
1075
- <!-- Context Management Tab Content -->
1076
- <div class="modal-tab-content hidden" id="context-tab">
1077
- <div class="form-section-header">Appearance</div>
1078
- <div class="form-row">
1079
- <label>Session Name</label>
1080
- <div style="display: flex; align-items: center; gap: 4px;">
1081
- <span id="modalSessionPrefix" style="color: var(--text-muted); white-space: nowrap; display: none;"></span>
1082
- <input type="text" id="modalSessionName" maxlength="128" placeholder="Auto (directory name)" onblur="app.saveSessionName()" style="flex: 1;">
1083
- </div>
1084
- <span class="form-hint">Custom name shown in the tab (right-click tab to rename inline)</span>
1085
- </div>
1086
- <div class="form-row">
1087
- <label>Session Color</label>
1088
- <div class="color-picker" id="sessionColorPicker">
1089
- <button type="button" class="color-swatch" data-color="default" title="Default">
1090
- <span class="swatch-inner" style="background: var(--bg-hover)"></span>
1091
- </button>
1092
- <button type="button" class="color-swatch" data-color="red" title="Red">
1093
- <span class="swatch-inner" style="background: var(--session-red)"></span>
1094
- </button>
1095
- <button type="button" class="color-swatch" data-color="orange" title="Orange">
1096
- <span class="swatch-inner" style="background: var(--session-orange)"></span>
1097
- </button>
1098
- <button type="button" class="color-swatch" data-color="yellow" title="Yellow">
1099
- <span class="swatch-inner" style="background: var(--session-yellow)"></span>
1100
- </button>
1101
- <button type="button" class="color-swatch" data-color="green" title="Green">
1102
- <span class="swatch-inner" style="background: var(--session-green)"></span>
1103
- </button>
1104
- <button type="button" class="color-swatch" data-color="blue" title="Blue">
1105
- <span class="swatch-inner" style="background: var(--session-blue)"></span>
1106
- </button>
1107
- <button type="button" class="color-swatch" data-color="purple" title="Purple">
1108
- <span class="swatch-inner" style="background: var(--session-purple)"></span>
1109
- </button>
1110
- <button type="button" class="color-swatch" data-color="pink" title="Pink">
1111
- <span class="swatch-inner" style="background: var(--session-pink)"></span>
1112
- </button>
1113
- </div>
1114
- </div>
1115
-
1116
- <div class="form-section-header">Token Management</div>
1117
- <div class="context-settings-grid">
1118
- <div class="context-setting">
1119
- <div class="context-setting-header">
1120
- <label class="checkbox-inline">
1121
- <input type="checkbox" id="modalAutoCompactEnabled" onchange="app.autoSaveAutoCompact()">
1122
- <span>Auto-Compact</span>
1123
- </label>
1124
- <div class="input-suffix input-suffix-sm">
1125
- <input type="number" id="modalAutoCompactThreshold" value="110000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoCompact()">
1126
- <span>tokens</span>
1156
+ <div class="set-group">
1157
+ <div class="set-group-head"><h4>Identity</h4></div>
1158
+ <div class="set-group-body">
1159
+ <div class="set-row has-field">
1160
+ <div class="set-row-text">
1161
+ <span class="set-row-label">Session name</span>
1162
+ <span class="set-row-desc">Shown in the tab. Right-click a tab to rename it inline.</span>
1163
+ </div>
1164
+ <div class="set-row-actions">
1165
+ <span id="modalSessionPrefix" class="set-static" style="display: none; white-space: nowrap;"></span>
1166
+ <input type="text" id="modalSessionName" class="set-input" maxlength="128" placeholder="Auto (directory name)" onblur="app.saveSessionName()">
1167
+ </div>
1168
+ </div>
1169
+ <div class="set-row set-row-block">
1170
+ <div class="set-row-text">
1171
+ <span class="set-row-label">Session color</span>
1172
+ <span class="set-row-desc">Tints the tab so a session is findable at a glance.</span>
1173
+ </div>
1174
+ <div class="color-picker" id="sessionColorPicker">
1175
+ <button type="button" class="color-swatch" data-color="default" title="Default">
1176
+ <span class="swatch-inner" style="background: var(--bg-hover)"></span>
1177
+ </button>
1178
+ <button type="button" class="color-swatch" data-color="red" title="Red">
1179
+ <span class="swatch-inner" style="background: var(--session-red)"></span>
1180
+ </button>
1181
+ <button type="button" class="color-swatch" data-color="orange" title="Orange">
1182
+ <span class="swatch-inner" style="background: var(--session-orange)"></span>
1183
+ </button>
1184
+ <button type="button" class="color-swatch" data-color="yellow" title="Yellow">
1185
+ <span class="swatch-inner" style="background: var(--session-yellow)"></span>
1186
+ </button>
1187
+ <button type="button" class="color-swatch" data-color="green" title="Green">
1188
+ <span class="swatch-inner" style="background: var(--session-green)"></span>
1189
+ </button>
1190
+ <button type="button" class="color-swatch" data-color="blue" title="Blue">
1191
+ <span class="swatch-inner" style="background: var(--session-blue)"></span>
1192
+ </button>
1193
+ <button type="button" class="color-swatch" data-color="purple" title="Purple">
1194
+ <span class="swatch-inner" style="background: var(--session-purple)"></span>
1195
+ </button>
1196
+ <button type="button" class="color-swatch" data-color="pink" title="Pink">
1197
+ <span class="swatch-inner" style="background: var(--session-pink)"></span>
1198
+ </button>
1199
+ </div>
1127
1200
  </div>
1128
1201
  </div>
1129
- <input type="text" id="modalAutoCompactPrompt" value="" placeholder="Focus prompt (optional)" onchange="app.autoSaveAutoCompact()">
1130
- <span class="form-hint">Summarizes context while preserving key information</span>
1131
1202
  </div>
1132
1203
 
1133
- <div class="context-setting">
1134
- <div class="context-setting-header">
1135
- <label class="checkbox-inline">
1136
- <input type="checkbox" id="modalAutoClearEnabled" onchange="app.autoSaveAutoClear()">
1137
- <span>Auto-Clear</span>
1138
- </label>
1139
- <div class="input-suffix input-suffix-sm">
1140
- <input type="number" id="modalAutoClearThreshold" value="140000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoClear()">
1141
- <span>tokens</span>
1204
+ <div class="set-group">
1205
+ <div class="set-group-head"><h4>Context window</h4></div>
1206
+ <div class="set-group-body">
1207
+ <div class="set-row">
1208
+ <div class="set-row-text">
1209
+ <span class="set-row-label">Auto-compact</span>
1210
+ <span class="set-row-desc">Summarizes the context at the threshold while preserving key information.</span>
1211
+ </div>
1212
+ <div class="set-row-actions">
1213
+ <input type="number" id="modalAutoCompactThreshold" class="set-num set-num-wide" value="110000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoCompact()">
1214
+ <span class="set-unit">tokens</span>
1215
+ <label class="switch switch-sm"><input type="checkbox" id="modalAutoCompactEnabled" onchange="app.autoSaveAutoCompact()"><span class="slider"></span></label>
1216
+ </div>
1217
+ </div>
1218
+ <div class="set-row has-field">
1219
+ <div class="set-row-text">
1220
+ <span class="set-row-label">Compact focus prompt</span>
1221
+ <span class="set-row-desc">Optional: what the summary should hold on to.</span>
1222
+ </div>
1223
+ <input type="text" id="modalAutoCompactPrompt" class="set-input" value="" placeholder="Focus prompt (optional)" onchange="app.autoSaveAutoCompact()">
1224
+ </div>
1225
+ <div class="set-row">
1226
+ <div class="set-row-text">
1227
+ <span class="set-row-label">Auto-clear</span>
1228
+ <span class="set-row-desc">Full context reset at the threshold. Keep it higher than auto-compact.</span>
1229
+ </div>
1230
+ <div class="set-row-actions">
1231
+ <input type="number" id="modalAutoClearThreshold" class="set-num set-num-wide" value="140000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoClear()">
1232
+ <span class="set-unit">tokens</span>
1233
+ <label class="switch switch-sm"><input type="checkbox" id="modalAutoClearEnabled" onchange="app.autoSaveAutoClear()"><span class="slider"></span></label>
1234
+ </div>
1142
1235
  </div>
1143
1236
  </div>
1144
- <span class="form-hint">Full context reset at threshold (use higher than compact)</span>
1145
1237
  </div>
1146
- </div>
1147
-
1148
- <div class="form-section-header">File Watching</div>
1149
- <div class="form-row form-row-switch">
1150
- <label>Image Watcher</label>
1151
- <label class="switch">
1152
- <input type="checkbox" id="modalImageWatcherEnabled" checked onchange="app.toggleSessionImageWatcher()">
1153
- <span class="slider"></span>
1154
- </label>
1155
- <span class="form-hint">Auto-popup new images (screenshots, generated files) in this session's directory</span>
1156
- </div>
1157
-
1158
- <div class="form-section-header">Performance</div>
1159
- <div class="form-row form-row-switch">
1160
- <label>Flicker Filter</label>
1161
- <label class="switch">
1162
- <input type="checkbox" id="modalFlickerFilterEnabled" onchange="app.toggleFlickerFilter()">
1163
- <span class="slider"></span>
1164
- </label>
1165
- <span class="form-hint">Buffers output after screen clears to reduce Ink UI flickering (adds ~50ms latency)</span>
1166
- </div>
1167
- </div><!-- End context-tab -->
1168
-
1169
- <!-- Ralph Wiggum Tab Content -->
1170
- <div class="modal-tab-content hidden" id="ralph-tab">
1171
- <div class="form-row form-row-switch">
1172
- <label>Enable Tracker</label>
1173
- <label class="switch">
1174
- <input type="checkbox" id="modalRalphEnabled">
1175
- <span class="slider"></span>
1176
- </label>
1177
- <span class="form-hint">Auto-detects loops and todos in Claude output</span>
1178
- </div>
1179
1238
 
1180
- <div class="form-row">
1181
- <label>Completion Phrase</label>
1182
- <input type="text" id="modalRalphPhrase" placeholder="e.g., COMPLETE, DONE, FINISHED">
1183
- <span class="form-hint">Phrase Claude outputs when loop is complete (without &lt;promise&gt; tags)</span>
1184
- </div>
1185
-
1186
- <div class="form-section-header">Limits</div>
1187
- <div class="ralph-limits-grid">
1188
- <div class="form-col">
1189
- <label>Max Iterations</label>
1190
- <input type="number" id="modalRalphMaxIterations" value="0" min="0" max="1000">
1191
- <span class="form-hint">0 = unlimited</span>
1192
- </div>
1193
- <div class="form-col">
1194
- <label>Max Todos</label>
1195
- <input type="number" id="modalRalphMaxTodos" value="50" min="1" max="500">
1196
- <span class="form-hint">Per session</span>
1197
- </div>
1198
- <div class="form-col">
1199
- <label>Todo Expiration</label>
1200
- <div class="input-suffix input-suffix-sm">
1201
- <input type="number" id="modalRalphTodoExpiration" value="60" min="1" max="1440">
1202
- <span>min</span>
1239
+ <div class="set-group">
1240
+ <div class="set-group-head"><h4>Behavior</h4></div>
1241
+ <div class="set-group-body">
1242
+ <div class="set-row">
1243
+ <div class="set-row-text">
1244
+ <span class="set-row-label">Image watcher</span>
1245
+ <span class="set-row-desc">Pops up new images (screenshots, generated files) found in this session's directory.</span>
1246
+ </div>
1247
+ <label class="switch switch-sm"><input type="checkbox" id="modalImageWatcherEnabled" checked onchange="app.toggleSessionImageWatcher()"><span class="slider"></span></label>
1248
+ </div>
1249
+ <div class="set-row">
1250
+ <div class="set-row-text">
1251
+ <span class="set-row-label">Flicker filter</span>
1252
+ <span class="set-row-desc">Buffers output after screen clears to reduce Ink UI flickering. Adds ~50ms latency.</span>
1253
+ </div>
1254
+ <label class="switch switch-sm"><input type="checkbox" id="modalFlickerFilterEnabled" onchange="app.toggleFlickerFilter()"><span class="slider"></span></label>
1255
+ </div>
1203
1256
  </div>
1204
1257
  </div>
1205
- </div>
1258
+ </section>
1206
1259
 
1207
- <div class="ralph-config-actions">
1208
- <button class="btn-toolbar btn-primary" onclick="app.saveRalphConfig()">Save Ralph Config</button>
1209
- </div>
1210
- </div><!-- End ralph-tab -->
1211
-
1212
- <!-- Summary Tab Content -->
1213
- <div class="modal-tab-content hidden" id="summary-tab">
1214
- <!-- Filter Buttons -->
1215
- <div class="run-summary-filters">
1216
- <button class="filter-btn active" data-filter="all" onclick="app.filterRunSummary('all')">All</button>
1217
- <button class="filter-btn" data-filter="errors" onclick="app.filterRunSummary('errors')">Errors</button>
1218
- <button class="filter-btn" data-filter="warnings" onclick="app.filterRunSummary('warnings')">Warnings</button>
1219
- <button class="filter-btn" data-filter="respawn" onclick="app.filterRunSummary('respawn')">Respawn</button>
1220
- <button class="filter-btn" data-filter="idle" onclick="app.filterRunSummary('idle')">Idle/Working</button>
1221
- </div>
1260
+ <!-- ══ Ralph / Todo ═════════════════════════════════════════════ -->
1261
+ <section class="set-section hidden" id="ralph-tab" data-label="Ralph / Todo">
1262
+ <div class="set-section-head">
1263
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 6h11"/><path d="M9 12h11"/><path d="M9 18h11"/><polyline points="3 6 4 7 6 5"/><polyline points="3 12 4 13 6 11"/><polyline points="3 18 4 19 6 17"/></svg>
1264
+ <h2>Ralph / Todo</h2>
1265
+ </div>
1266
+ <p class="set-section-blurb">Loop and todo tracking read out of this session's output.</p>
1222
1267
 
1223
- <!-- Timeline -->
1224
- <div class="run-summary-timeline" id="runSummaryTimeline">
1225
- <p class="empty-message">Select a session to view summary</p>
1226
- </div>
1268
+ <div class="set-group">
1269
+ <div class="set-group-head"><h4>Tracker</h4></div>
1270
+ <div class="set-group-body">
1271
+ <div class="set-row">
1272
+ <div class="set-row-text">
1273
+ <span class="set-row-label">Enable tracker</span>
1274
+ <span class="set-row-desc">Auto-detects loops and todos in Claude's output.</span>
1275
+ </div>
1276
+ <label class="switch switch-sm"><input type="checkbox" id="modalRalphEnabled"><span class="slider"></span></label>
1277
+ </div>
1278
+ <div class="set-row has-field">
1279
+ <div class="set-row-text">
1280
+ <span class="set-row-label">Completion phrase</span>
1281
+ <span class="set-row-desc">What Claude prints when the loop is done, without &lt;promise&gt; tags.</span>
1282
+ </div>
1283
+ <input type="text" id="modalRalphPhrase" class="set-input" placeholder="e.g. COMPLETE, DONE, FINISHED">
1284
+ </div>
1285
+ </div>
1286
+ </div>
1227
1287
 
1228
- <!-- Footer with actions -->
1229
- <div class="run-summary-footer">
1230
- <span class="run-summary-session-info" id="runSummarySessionInfo"></span>
1231
- <div class="run-summary-actions">
1232
- <label class="auto-refresh-label">
1233
- <input type="checkbox" id="runSummaryAutoRefresh" onchange="app.toggleRunSummaryAutoRefresh()">
1234
- Auto-refresh
1235
- </label>
1236
- <button class="btn-toolbar btn-sm" onclick="app.refreshRunSummary()" title="Refresh summary">&#x21BB; Refresh</button>
1237
- <button class="btn-toolbar btn-sm" onclick="app.exportRunSummary('json')" title="Export as JSON">Export JSON</button>
1238
- <button class="btn-toolbar btn-sm" onclick="app.exportRunSummary('md')" title="Export as Markdown">Export MD</button>
1288
+ <div class="set-group">
1289
+ <div class="set-group-head"><h4>Limits</h4></div>
1290
+ <div class="set-group-body">
1291
+ <div class="set-row">
1292
+ <div class="set-row-text">
1293
+ <span class="set-row-label">Max iterations</span>
1294
+ <span class="set-row-desc">0 = unlimited.</span>
1295
+ </div>
1296
+ <input type="number" id="modalRalphMaxIterations" class="set-num" value="0" min="0" max="1000">
1297
+ </div>
1298
+ <div class="set-row">
1299
+ <div class="set-row-text">
1300
+ <span class="set-row-label">Max todos</span>
1301
+ <span class="set-row-desc">Per session; the oldest are evicted first.</span>
1302
+ </div>
1303
+ <input type="number" id="modalRalphMaxTodos" class="set-num" value="50" min="1" max="500">
1304
+ </div>
1305
+ <div class="set-row">
1306
+ <div class="set-row-text">
1307
+ <span class="set-row-label">Todo expiration</span>
1308
+ <span class="set-row-desc">How long an untouched todo survives.</span>
1309
+ </div>
1310
+ <div class="set-row-actions">
1311
+ <input type="number" id="modalRalphTodoExpiration" class="set-num" value="60" min="1" max="1440">
1312
+ <span class="set-unit">min</span>
1313
+ </div>
1314
+ </div>
1315
+ <div class="set-row">
1316
+ <div class="set-row-text">
1317
+ <span class="set-row-label">Apply</span>
1318
+ <span class="set-row-desc">Ralph settings are the one group here that does not save on change.</span>
1319
+ </div>
1320
+ <button class="btn-toolbar btn-primary btn-sm" onclick="app.saveRalphConfig()">Save Ralph config</button>
1321
+ </div>
1322
+ </div>
1239
1323
  </div>
1240
- </div>
1241
- </div><!-- End summary-tab -->
1324
+ </section>
1325
+
1326
+ <!-- ══ Summary ══════════════════════════════════════════════════ -->
1327
+ <section class="set-section hidden" id="summary-tab" data-label="Summary">
1328
+ <div class="set-section-head">
1329
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3v18h18"/><polyline points="7 14 11 10 14 13 20 7"/></svg>
1330
+ <h2>Summary</h2>
1331
+ </div>
1332
+ <p class="set-section-blurb">What this session has done: respawns, errors, idle stretches.</p>
1333
+
1334
+ <div class="set-group">
1335
+ <div class="set-group-head"><h4>Timeline</h4><span class="set-scope" id="runSummarySessionInfo"></span></div>
1336
+ <div class="set-group-body">
1337
+ <div class="run-summary-filters">
1338
+ <button class="filter-btn active" data-filter="all" onclick="app.filterRunSummary('all')">All</button>
1339
+ <button class="filter-btn" data-filter="errors" onclick="app.filterRunSummary('errors')">Errors</button>
1340
+ <button class="filter-btn" data-filter="warnings" onclick="app.filterRunSummary('warnings')">Warnings</button>
1341
+ <button class="filter-btn" data-filter="respawn" onclick="app.filterRunSummary('respawn')">Respawn</button>
1342
+ <button class="filter-btn" data-filter="idle" onclick="app.filterRunSummary('idle')">Idle/Working</button>
1343
+ </div>
1344
+ <div class="run-summary-timeline" id="runSummaryTimeline">
1345
+ <p class="empty-message">Select a session to view summary</p>
1346
+ </div>
1347
+ <div class="run-summary-footer">
1348
+ <label class="auto-refresh-label">
1349
+ <input type="checkbox" id="runSummaryAutoRefresh" onchange="app.toggleRunSummaryAutoRefresh()">
1350
+ Auto-refresh
1351
+ </label>
1352
+ <div class="run-summary-actions">
1353
+ <button class="btn-toolbar btn-sm" onclick="app.refreshRunSummary()" title="Refresh summary">&#x21BB; Refresh</button>
1354
+ <button class="btn-toolbar btn-sm" onclick="app.exportRunSummary('json')" title="Export as JSON">Export JSON</button>
1355
+ <button class="btn-toolbar btn-sm" onclick="app.exportRunSummary('md')" title="Export as Markdown">Export MD</button>
1356
+ </div>
1357
+ </div>
1358
+ </div>
1359
+ </div>
1360
+ </section>
1361
+ </div>
1242
1362
  </div>
1243
1363
  </div>
1244
1364
  </div>
@@ -1273,778 +1393,924 @@
1273
1393
  <!-- App Settings Modal -->
1274
1394
  <div class="modal" id="appSettingsModal">
1275
1395
  <div class="modal-backdrop" onclick="app.closeAppSettings()"></div>
1276
- <div class="modal-content modal-lg">
1277
- <div class="modal-header">
1278
- <h3>App Settings</h3>
1279
- <button class="modal-close" onclick="app.closeAppSettings()" aria-label="Close app settings">&times;</button>
1280
- </div>
1281
- <div class="modal-tabs">
1282
- <button class="modal-tab-btn active" data-tab="settings-display">Display</button>
1283
- <button class="modal-tab-btn" data-tab="settings-claude">Claude CLI</button>
1284
- <button class="modal-tab-btn" data-tab="settings-codex">Codex CLI</button>
1285
- <button class="modal-tab-btn" data-tab="settings-models">Models</button>
1286
- <button class="modal-tab-btn" data-tab="settings-paths">Paths</button>
1287
- <button class="modal-tab-btn" data-tab="settings-notifications">Notifications</button>
1288
- <button class="modal-tab-btn" data-tab="settings-voice">Voice</button>
1289
- <button class="modal-tab-btn" data-tab="settings-shortcuts">Shortcuts</button>
1290
- </div>
1291
- <div class="modal-body">
1292
- <!-- Display Tab -->
1293
- <div class="modal-tab-content" id="settings-display">
1294
- <div class="settings-grid">
1295
- <!-- Branding & Language Section -->
1296
- <div class="settings-section-header">Branding &amp; Language</div>
1297
- <div class="settings-item" title="Name shown in the browser UI and window title. Supports Unicode, including Chinese.">
1298
- <span class="settings-item-label">Display Name</span>
1299
- <input type="text" id="appSettingsDisplayName" class="settings-inline-input" maxlength="40" placeholder="Codeman" autocomplete="off">
1300
- </div>
1301
- <div class="settings-item" title="Language for this device. Dynamic status messages and dialogs use the same language.">
1302
- <span class="settings-item-label">Interface Language</span>
1303
- <select id="appSettingsLanguage" class="form-select settings-inline-select">
1304
- <option value="en">English</option>
1305
- <option value="zh-CN">简体中文</option>
1306
- </select>
1307
- </div>
1396
+ <div class="modal-content modal-lg set-shell">
1397
+ <div class="modal-header set-shell-head">
1398
+ <h3>Settings</h3>
1399
+ <!-- Close first in the DOM so the focus trap still lands on it, not on
1400
+ Save; row-reverse keeps Save to the left of it on phones. -->
1401
+ <div class="set-head-actions">
1402
+ <button class="modal-close" onclick="app.closeAppSettings()" aria-label="Close app settings">&times;</button>
1403
+ <button class="set-head-save" onclick="app.saveAppSettings()">Save</button>
1404
+ </div>
1405
+ </div>
1406
+ <div class="set-body">
1407
+ <!-- Left rail: a table of contents over the single scrolling document on
1408
+ the right. On phones it collapses and #appSettingsJump takes over. -->
1409
+ <nav class="set-rail" id="appSettingsRail" aria-label="Settings sections">
1410
+ <div class="set-search">
1411
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>
1412
+ <input type="search" id="appSettingsSearch" placeholder="Search settings" autocomplete="off" aria-label="Search settings">
1413
+ </div>
1414
+ <div class="set-rail-items" id="appSettingsRailItems">
1415
+ <button type="button" class="set-rail-item active" data-section="settings-updates">
1416
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M4 20h16"/></svg>
1417
+ <span>Updates</span>
1418
+ </button>
1419
+ <button type="button" class="set-rail-item" data-section="settings-terminal">
1420
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17l6-6-6-6"/><path d="M12 19h8"/></svg>
1421
+ <span>Terminal &amp; Input</span>
1422
+ </button>
1423
+ <button type="button" class="set-rail-item" data-section="settings-layout">
1424
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
1425
+ <span>Header &amp; Panels</span>
1426
+ </button>
1427
+ <button type="button" class="set-rail-item" data-section="settings-appearance">
1428
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 0 0 18 4.5 4.5 0 0 0 0-9 4.5 4.5 0 0 1 0-9z"/></svg>
1429
+ <span>Appearance</span>
1430
+ </button>
1431
+ <button type="button" class="set-rail-item" data-section="settings-models">
1432
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3z"/><path d="M12 12l8-4.5M12 12v9M12 12L4 7.5"/></svg>
1433
+ <span>Models</span>
1434
+ </button>
1435
+ <button type="button" class="set-rail-item" data-section="settings-clis">
1436
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h2"/><path d="M16 3h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-2"/><circle cx="12" cy="12" r="2.5"/></svg>
1437
+ <span>Agents &amp; CLIs</span>
1438
+ </button>
1439
+ <button type="button" class="set-rail-item" data-section="settings-notifications">
1440
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></svg>
1441
+ <span>Notifications</span>
1442
+ </button>
1443
+ <button type="button" class="set-rail-item" data-section="settings-voice">
1444
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M5 11a7 7 0 0 0 14 0"/><path d="M12 18v4"/></svg>
1445
+ <span>Voice</span>
1446
+ </button>
1447
+ <button type="button" class="set-rail-item" data-section="settings-shortcuts">
1448
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M6 9h.01M10 9h.01M14 9h.01M18 9h.01M6 13h.01M18 13h.01M9 13h6"/></svg>
1449
+ <span>Shortcuts</span>
1450
+ </button>
1451
+ <button type="button" class="set-rail-item" data-section="settings-system">
1452
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><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 1 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 1 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 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.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 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.26.6.86 1 1.51 1H21a2 2 0 0 1 0 4h-.09c-.65 0-1.25.4-1.51 1z"/></svg>
1453
+ <span>System</span>
1454
+ </button>
1455
+ </div>
1456
+ <p class="set-rail-foot">Settings marked <b>device</b> stay on this browser. The rest sync to every device.</p>
1457
+ </nav>
1308
1458
 
1309
- <!-- Appearance Section -->
1310
- <div class="settings-section-header">Appearance</div>
1311
- <div class="settings-item settings-item-skin" title="Visual theme for this device (not synced)">
1312
- <span class="settings-item-label">Skin</span>
1313
- <select id="appSettingsSkin" class="form-select">
1314
- <optgroup label="Light">
1315
- <option value="paper-gray">Paper Gray</option>
1316
- <option value="solarized-light">Solarized Light</option>
1317
- <option value="catppuccin-latte">Catppuccin Latte</option>
1318
- <option value="rose-pine-dawn">Rosé Pine Dawn</option>
1319
- </optgroup>
1320
- <optgroup label="Dark">
1321
- <option value="daylight-blue">Daylight Blue</option>
1322
- <option value="daylight-green">Daylight Green</option>
1323
- <option value="og">OG Codeman</option>
1324
- </optgroup>
1325
- </select>
1326
- </div>
1327
- <div class="settings-item settings-item-multiline" title="How new session tabs, the terminal pane, agent windows and their connection lines appear. This device only. For per-surface control and a live preview, add ?animlab=1 to the URL.">
1328
- <div class="settings-item-text">
1329
- <span class="settings-item-label">Entrance Animations</span>
1330
- <span class="settings-item-desc">How new tabs, panes and agent windows arrive</span>
1459
+ <div class="set-doc" id="appSettingsDoc">
1460
+ <!-- Phone only: names the section you are in and opens the jump list -->
1461
+ <button type="button" class="set-jump" id="appSettingsJump" aria-haspopup="menu" aria-expanded="false">
1462
+ <svg class="set-jump-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17l6-6-6-6"/><path d="M12 19h8"/></svg>
1463
+ <span class="set-jump-label">Terminal &amp; Input</span>
1464
+ <svg class="set-jump-chev" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
1465
+ </button>
1466
+ <div class="set-jump-veil" id="appSettingsJumpVeil"></div>
1467
+ <div class="set-jump-menu" id="appSettingsJumpMenu" role="menu"></div>
1468
+
1469
+ <p class="set-empty" id="appSettingsSearchEmpty" hidden>No settings match that search.</p>
1470
+
1471
+ <!-- ══ Updates ══════════════════════════════════════════════════
1472
+ First in the document on purpose: what this install is running,
1473
+ and whether a newer release is waiting, before any preference. -->
1474
+ <section class="set-section" id="settings-updates" data-label="Updates">
1475
+ <div class="set-section-head">
1476
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M4 20h16"/></svg>
1477
+ <h2>Updates</h2>
1478
+ </div>
1479
+ <p class="set-section-blurb">The version this install is running, and the one-click update.</p>
1480
+
1481
+ <div class="set-group">
1482
+ <div class="set-group-body">
1483
+ <div class="set-row" data-search="version current release">
1484
+ <div class="set-row-text"><span class="set-row-label">Current version</span></div>
1485
+ <span class="set-static set-static-strong mono" id="updateCurrentVersion">&mdash;</span>
1486
+ </div>
1487
+ <div class="set-row" id="updateCheckRow" data-search="check for updates github release">
1488
+ <div class="set-row-text">
1489
+ <span class="set-row-label">Check for updates</span>
1490
+ <span class="set-row-desc">Looks at GitHub for a newer Codeman release.</span>
1491
+ </div>
1492
+ <button class="btn-toolbar btn-sm" id="updateCheckBtn" onclick="app.checkForUpdate()">Check now</button>
1493
+ </div>
1494
+ <div id="updateResult" class="set-note" style="display:none"></div>
1495
+ <div class="set-row" id="updateActionRow" style="display:none">
1496
+ <div class="set-row-text"><span class="set-row-label" id="updateActionLabel">Update available</span></div>
1497
+ <button class="btn-toolbar btn-sm btn-primary" id="updateNowBtn" onclick="app.startSelfUpdate()">Update now</button>
1498
+ </div>
1499
+ <div id="updateNotes" class="set-notes" style="display:none"></div>
1500
+ <div id="updateProgress" class="set-progress" style="display:none"></div>
1331
1501
  </div>
1332
- <select id="appSettingsEntranceAnim" class="form-select settings-inline-select">
1333
- <option value="legacy">Off (default)</option>
1334
- <option value="terminal">Terminal (CRT)</option>
1335
- <option value="beamdown">Beam down</option>
1336
- <option value="quiet">Quiet</option>
1337
- <option value="playful">Playful</option>
1338
- <option value="custom">Custom (set in the lab)</option>
1339
- </select>
1340
1502
  </div>
1341
- <div class="settings-item" id="appSettingsWebglRendererItem" title="Use the GPU-accelerated WebGL terminal renderer (desktop only). Turn off to force the DOM renderer if you hit GPU glitches. Codeman also auto-falls-back to the DOM renderer after repeated GPU stalls.">
1342
- <span class="settings-item-label">WebGL Renderer</span>
1343
- <label class="switch switch-sm">
1344
- <input type="checkbox" id="appSettingsWebglRenderer">
1345
- <span class="slider"></span>
1346
- </label>
1503
+ </section>
1504
+
1505
+ <!-- ══ Terminal &amp; Input ══════════════════════════════════════ -->
1506
+ <section class="set-section" id="settings-terminal" data-label="Terminal &amp; Input">
1507
+ <div class="set-section-head">
1508
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17l6-6-6-6"/><path d="M12 19h8"/></svg>
1509
+ <h2>Terminal &amp; Input</h2>
1347
1510
  </div>
1348
- <!-- Input Section -->
1349
- <div class="settings-section-header">Input</div>
1350
- <div class="settings-item settings-item-multiline" title="Scroll the terminal's own local scrollback with a plain mouse wheel / two-finger swipe, instead of forwarding the wheel to the CLI's transcript. Only Claude sessions forward, so this setting only affects them: Claude redraws the screen in place and keeps almost no local scrollback, so with this ON the wheel has little to scroll and Codeman falls back to paging Claude's own transcript. Codex, Gemini, shell and OpenCode sessions always scroll local scrollback. Shift+wheel always reaches local scrollback regardless.">
1351
- <div class="settings-item-text">
1352
- <span class="settings-item-label">Wheel Scrolls Local History</span>
1353
- <span class="settings-item-desc">Plain wheel/trackpad pages the terminal scrollback</span>
1511
+ <p class="set-section-blurb">How keystrokes reach the agent, and how the terminal draws.</p>
1512
+
1513
+ <div class="set-group">
1514
+ <div class="set-group-head"><h4>Typing</h4><span class="set-scope">device</span></div>
1515
+ <div class="set-group-body">
1516
+ <div class="set-row" data-search="local echo typing latency mobile">
1517
+ <div class="set-row-text">
1518
+ <span class="set-row-label">Local Echo</span>
1519
+ <span class="set-row-desc">Paint keystrokes instantly instead of waiting for the round trip. Recommended on phones and high-latency links.</span>
1520
+ </div>
1521
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsLocalEcho"><span class="slider"></span></label>
1522
+ </div>
1523
+ <div class="set-row" data-search="cjk input ime chinese japanese korean">
1524
+ <div class="set-row-text">
1525
+ <span class="set-row-label">CJK Input</span>
1526
+ <span class="set-row-desc">Dedicated IME field for Chinese, Japanese and Korean composition.</span>
1527
+ </div>
1528
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsCjkInput"><span class="slider"></span></label>
1529
+ </div>
1530
+ <div class="set-row" data-search="extended keyboard bar tab esc arrows phone">
1531
+ <div class="set-row-text">
1532
+ <span class="set-row-label">Extended Keyboard Bar <span class="set-tag">phone</span></span>
1533
+ <span class="set-row-desc">Extra phone keys: Tab, Shift+Tab, Esc, arrows, Ctrl+O.</span>
1534
+ </div>
1535
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsExtendedKeyboardBar"><span class="slider"></span></label>
1536
+ </div>
1354
1537
  </div>
1355
- <label class="switch switch-sm">
1356
- <input type="checkbox" id="appSettingsTerminalWheelLocal">
1357
- <span class="slider"></span>
1358
- </label>
1359
1538
  </div>
1360
- <div class="settings-item settings-item-multiline" title="Shows typed characters instantly via overlay while forwarding keystrokes to the server in the background. Enables Tab completion, preserves input across tab switches, and protects against session crashes. Recommended for mobile and high-latency connections.">
1361
- <div class="settings-item-text">
1362
- <span class="settings-item-label">Local Echo</span>
1363
- <span class="settings-item-desc">Instant typing feedback with local echo</span>
1539
+
1540
+ <div class="set-group">
1541
+ <div class="set-group-head"><h4>Scrolling &amp; rendering</h4></div>
1542
+ <div class="set-group-body">
1543
+ <div class="set-row" data-search="wheel scroll local history scrollback transcript">
1544
+ <div class="set-row-text">
1545
+ <span class="set-row-label">Wheel Scrolls Local History <span class="set-scope">device</span></span>
1546
+ <span class="set-row-desc">Plain wheel or two-finger swipe pages the terminal's own scrollback instead of the CLI transcript. Shift+wheel always reaches local scrollback.</span>
1547
+ </div>
1548
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsTerminalWheelLocal"><span class="slider"></span></label>
1549
+ </div>
1550
+ <div class="set-row" id="appSettingsWebglRendererItem" data-search="webgl renderer gpu terminal">
1551
+ <div class="set-row-text">
1552
+ <span class="set-row-label">WebGL Renderer <span class="set-tag">desktop</span> <span class="set-scope">device</span></span>
1553
+ <span class="set-row-desc">GPU-accelerated terminal drawing. Codeman falls back to the DOM renderer after repeated GPU stalls.</span>
1554
+ </div>
1555
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsWebglRenderer"><span class="slider"></span></label>
1556
+ </div>
1557
+ <div class="set-row" id="appSettingsGestureControlItem" data-search="gesture control camera hand tracking">
1558
+ <div class="set-row-text">
1559
+ <span class="set-row-label">Gesture Control <span class="set-tag set-tag-beta">beta</span> <span class="set-scope">synced</span></span>
1560
+ <span class="set-row-desc">Camera hand-tracking overlay. Applied on reload; the instance must run with CODEMAN_GESTURE=1.</span>
1561
+ </div>
1562
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsGestureControl"><span class="slider"></span></label>
1563
+ </div>
1364
1564
  </div>
1365
- <label class="switch switch-sm">
1366
- <input type="checkbox" id="appSettingsLocalEcho">
1367
- <span class="slider"></span>
1368
- </label>
1369
1565
  </div>
1370
- <div class="settings-item settings-item-multiline" title="Show a dedicated input field below the terminal for CJK (Chinese/Japanese/Korean) IME composition. Recommended for mobile devices with Chinese input methods where xterm's native input handling may drop characters.">
1371
- <div class="settings-item-text">
1372
- <span class="settings-item-label">CJK Input</span>
1373
- <span class="settings-item-desc">Dedicated IME input field for CJK languages</span>
1566
+ </section>
1567
+
1568
+ <!-- ══ Header &amp; Panels ═══════════════════════════════════════ -->
1569
+ <section class="set-section" id="settings-layout" data-label="Header &amp; Panels">
1570
+ <div class="set-section-head">
1571
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
1572
+ <h2>Header &amp; Panels</h2>
1573
+ </div>
1574
+ <p class="set-section-blurb">Pick the buttons and panels you actually use. Everything else stays out of the way.</p>
1575
+
1576
+ <!-- Live preview: a scale model of the app that redraws from the
1577
+ chips below on every change, so "what does this add" is answered
1578
+ in place instead of after a save. Icons are CLONED from the
1579
+ chips (settings-ui.js: _syncLayoutPreview), so each icon has
1580
+ exactly one copy in this file and the two can never drift. -->
1581
+ <div class="set-preview" id="appSettingsLayoutPreview">
1582
+ <div class="set-preview-head">
1583
+ <span class="set-preview-title">Live preview</span>
1584
+ <span class="set-preview-hint">Updates as you pick, before you save.</span>
1585
+ </div>
1586
+ <div class="set-preview-frame" data-i18n-skip>
1587
+ <div class="set-preview-bar">
1588
+ <span class="set-preview-logo">C</span>
1589
+ <span class="set-preview-tab">w1-codeman</span>
1590
+ <span class="set-preview-tab set-preview-tab-dim">w2-docs</span>
1591
+ <span class="set-preview-gap"></span>
1592
+ <span class="set-preview-btns" id="appSettingsPreviewHeader"></span>
1593
+ <span class="set-preview-btn set-preview-btn-fixed" title="App Settings"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><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></span>
1594
+ </div>
1595
+ <div class="set-preview-stage">
1596
+ <div class="set-preview-term"><span class="set-preview-caret">&#10095;</span> npm run dev</div>
1597
+ <div class="set-preview-panels" id="appSettingsPreviewPanels"></div>
1598
+ <div class="set-preview-floats" id="appSettingsPreviewFloats"></div>
1599
+ </div>
1600
+ <div class="set-preview-tray">
1601
+ <span class="set-preview-run">Run</span>
1602
+ <span class="set-preview-tools" id="appSettingsPreviewToolbar"></span>
1603
+ </div>
1604
+ </div>
1605
+ <p class="set-preview-empty" id="appSettingsPreviewEmpty" hidden>Nothing extra switched on: header keeps the gear only.</p>
1606
+ </div>
1607
+
1608
+ <div class="set-group">
1609
+ <div class="set-group-head"><h4>Header buttons</h4><span class="set-scope">device</span></div>
1610
+ <p class="set-group-hint">Tap to show a control in the header. Multi-monitor is the one entry here that syncs across devices.</p>
1611
+ <div class="set-group-body">
1612
+ <div class="set-chips" data-search="header buttons plan usage font stats lifecycle response file viewer attachments monitor session away cron redraw">
1613
+ <label class="set-chip" data-preview="header" data-preview-order="1" data-preview-text="A+"><input type="checkbox" id="appSettingsShowFontControls"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20 10 5l6 15"/><path d="M6.5 15h7"/><path d="M18 12h4M20 10v4"/></svg><span>Font Size</span></label>
1614
+ <label class="set-chip" data-preview="header" data-preview-order="2" data-preview-text="CPU 12%"><input type="checkbox" id="appSettingsShowSystemStats" checked><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l2.5-7 4 14L16 12h5"/></svg><span>System Stats</span></label>
1615
+ <label class="set-chip" data-preview="header" data-preview-order="3"><input type="checkbox" id="appSettingsShowRedrawButton"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="1 4 1 10 7 10"/><polyline points="23 20 23 14 17 14"/><path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"/></svg><span>Redraw Terminal</span></label>
1616
+ <label class="set-chip" data-preview="header" data-preview-order="4"><input type="checkbox" id="appSettingsShowResponseViewer"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg><span>Response Viewer</span></label>
1617
+ <label class="set-chip" data-preview="header" data-preview-order="5"><input type="checkbox" id="appSettingsShowAwayDigestButton"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 6h13"/><path d="M8 12h13"/><path d="M8 18h13"/><path d="M3 6h.01"/><path d="M3 12h.01"/><path d="M3 18h.01"/></svg><span>Away Digest</span></label>
1618
+ <label class="set-chip" data-preview="header" data-preview-order="6"><input type="checkbox" id="appSettingsShowSessionButton"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg><span>Session Manager</span></label>
1619
+ <label class="set-chip" data-preview="header" data-preview-order="9"><input type="checkbox" id="appSettingsShowAttachmentsButton"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg><span>Attachments</span></label>
1620
+ <label class="set-chip" data-preview="header" data-preview-order="10"><input type="checkbox" id="appSettingsShowFileViewerButton"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg><span>File Viewer</span></label>
1621
+ <label class="set-chip" data-preview="header" data-preview-order="11"><input type="checkbox" id="appSettingsShowMultiMonitorButton"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="13" height="9" rx="1.5"/><rect x="11" y="9" width="11" height="8" rx="1.5"/></svg><span>Multi-monitor</span></label>
1622
+ <label class="set-chip" data-preview="header" data-preview-order="13" data-preview-text="42%"><input type="checkbox" id="appSettingsShowPlanUsageLimits"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 18a8 8 0 1 1 16 0"/><path d="M12 18l4.5-5"/></svg><span>Plan Usage</span></label>
1623
+ <label class="set-chip" data-preview="header" data-preview-order="14"><input type="checkbox" id="appSettingsShowLifecycleLog"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg><span>Lifecycle Log</span></label>
1624
+ </div>
1374
1625
  </div>
1375
- <label class="switch switch-sm">
1376
- <input type="checkbox" id="appSettingsCjkInput">
1377
- <span class="slider"></span>
1378
- </label>
1379
1626
  </div>
1380
1627
 
1381
- <div class="settings-item settings-item-multiline" title="Show additional buttons (Tab, Shift+Tab, Ctrl+O, Esc, Alt+Enter, left/right arrows) in the mobile keyboard accessory bar.">
1382
- <div class="settings-item-text">
1383
- <span class="settings-item-label">Extended Keyboard Bar</span>
1384
- <span class="settings-item-desc">Extra keys: Tab, Esc, arrows, Ctrl+O</span>
1628
+ <div class="set-group">
1629
+ <div class="set-group-head"><h4>Panels</h4><span class="set-scope">device</span></div>
1630
+ <div class="set-group-body">
1631
+ <div class="set-chips" data-search="panels monitor project insights file browser subagents">
1632
+ <label class="set-chip" data-preview="panel" data-preview-order="1"><input type="checkbox" id="appSettingsShowMonitor" checked><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l2.5-7 4 14L16 12h5"/></svg><span>Monitor</span></label>
1633
+ <label class="set-chip" data-preview="panel" data-preview-order="2"><input type="checkbox" id="appSettingsShowProjectInsights"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 19V9"/><path d="M10 19V5"/><path d="M16 19v-7"/><path d="M22 19H2"/></svg><span>Project Insights</span></label>
1634
+ <label class="set-chip" data-preview="panel" data-preview-order="3"><input type="checkbox" id="appSettingsShowFileBrowser"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg><span>File Browser</span></label>
1635
+ <label class="set-chip" data-preview="panel" data-preview-order="4"><input type="checkbox" id="appSettingsShowSubagents"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="12" r="2.5"/><path d="M8.2 7.2 15.6 11M8.2 16.8 15.6 13"/></svg><span>Subagents</span></label>
1636
+ </div>
1385
1637
  </div>
1386
- <label class="switch switch-sm">
1387
- <input type="checkbox" id="appSettingsExtendedKeyboardBar">
1388
- <span class="slider"></span>
1389
- </label>
1390
1638
  </div>
1391
- <div class="settings-item settings-item-multiline" id="appSettingsGestureControlItem" title="Enable the camera hand-tracking gesture overlay (applied on reload). The instance must run with CODEMAN_GESTURE=1.">
1392
- <div class="settings-item-text">
1393
- <span class="settings-item-label">Gesture Control (beta)</span>
1394
- <span class="settings-item-desc">Camera hand-tracking overlay (applied on reload)</span>
1639
+
1640
+ <div class="set-group">
1641
+ <div class="set-group-head"><h4>Cross-session features</h4><span class="set-scope">synced</span></div>
1642
+ <p class="set-group-hint">Approvals answers prompts from any session in one place. Read My Mind captures your prompts and predicts the next one on demand; both cost tokens and never auto-send.</p>
1643
+ <div class="set-group-body">
1644
+ <div class="set-chips" data-search="approvals inbox read my mind ultracode agents floating windows workflow">
1645
+ <label class="set-chip" data-preview="header" data-preview-order="7"><input type="checkbox" id="appSettingsApprovalsInbox"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><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>Approvals Inbox</span></label>
1646
+ <label class="set-chip" data-preview="header" data-preview-order="8"><input type="checkbox" id="appSettingsReadMyMind"><span class="set-chip-ico set-chip-emoji" aria-hidden="true">🧠</span><span>Read My Mind</span></label>
1647
+ <label class="set-chip" data-preview="header" data-preview-order="12"><input type="checkbox" id="appSettingsShowUltracodeAgents"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="12" r="2.5"/><path d="M8.2 7.2 15.6 11M8.2 16.8 15.6 13"/></svg><span>Ultracode Agents</span></label>
1648
+ <label class="set-chip" data-preview="float" data-preview-order="1"><input type="checkbox" id="appSettingsUltracodeFloatingWindows"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18"/><circle cx="6" cy="6.5" r="0.6"/></svg><span>Ultracode Windows</span></label>
1649
+ </div>
1395
1650
  </div>
1396
- <label class="switch switch-sm">
1397
- <input type="checkbox" id="appSettingsGestureControl">
1398
- <span class="slider"></span>
1399
- </label>
1400
1651
  </div>
1401
1652
 
1402
- <!-- Header Displays Section -->
1403
- <div class="settings-section-header">Header Displays</div>
1404
- <div class="settings-item" title="Show Claude plan usage limits (5-hour & weekly) in the header. Applies to newly created sessions.">
1405
- <span class="settings-item-label">Plan Usage Limits</span>
1406
- <label class="switch switch-sm">
1407
- <input type="checkbox" id="appSettingsShowPlanUsageLimits">
1408
- <span class="slider"></span>
1409
- </label>
1410
- </div>
1411
- <div class="settings-item" title="Show A-/A+ font size buttons in header">
1412
- <span class="settings-item-label">Font Controls</span>
1413
- <label class="switch switch-sm">
1414
- <input type="checkbox" id="appSettingsShowFontControls">
1415
- <span class="slider"></span>
1416
- </label>
1417
- </div>
1418
- <div class="settings-item" title="Show CPU and memory usage in header">
1419
- <span class="settings-item-label">System Stats</span>
1420
- <label class="switch switch-sm">
1421
- <input type="checkbox" id="appSettingsShowSystemStats" checked>
1422
- <span class="slider"></span>
1423
- </label>
1424
- </div>
1425
- <div class="settings-item" title="Show session lifecycle log button in header">
1426
- <span class="settings-item-label">Lifecycle Log</span>
1427
- <label class="switch switch-sm">
1428
- <input type="checkbox" id="appSettingsShowLifecycleLog">
1429
- <span class="slider"></span>
1430
- </label>
1431
- </div>
1432
- <div class="settings-item" title="Show the response viewer (eye) button in header">
1433
- <span class="settings-item-label">Response Viewer</span>
1434
- <label class="switch switch-sm">
1435
- <input type="checkbox" id="appSettingsShowResponseViewer">
1436
- <span class="slider"></span>
1437
- </label>
1438
- </div>
1439
- <div class="settings-item" title="Show the file viewer button in header (opens the file browser panel for the active session)">
1440
- <span class="settings-item-label">File Viewer</span>
1441
- <label class="switch switch-sm">
1442
- <input type="checkbox" id="appSettingsShowFileViewerButton">
1443
- <span class="slider"></span>
1444
- </label>
1445
- </div>
1446
- <div class="settings-item" title="Show the attachments button in header (opens the attachment history drawer)">
1447
- <span class="settings-item-label">Attachments Button</span>
1448
- <label class="switch switch-sm">
1449
- <input type="checkbox" id="appSettingsShowAttachmentsButton">
1450
- <span class="slider"></span>
1451
- </label>
1452
- </div>
1453
- <div class="settings-item" title="Show the multi-monitor button in the header (opens Codeman spanned across all displays)">
1454
- <span class="settings-item-label">Multi-monitor Button</span>
1455
- <label class="switch switch-sm">
1456
- <input type="checkbox" id="appSettingsShowMultiMonitorButton">
1457
- <span class="slider"></span>
1458
- </label>
1459
- </div>
1460
- <div class="settings-item" title="Show the session manager button in the header (opens the session manager — sessions also stay reachable via the Ctrl+K palette)">
1461
- <span class="settings-item-label">Session Manager Button</span>
1462
- <label class="switch switch-sm">
1463
- <input type="checkbox" id="appSettingsShowSessionButton">
1464
- <span class="slider"></span>
1465
- </label>
1466
- </div>
1467
- <div class="settings-item" title="Show the away digest button in the header (opens the 'what happened while you were away' summary)">
1468
- <span class="settings-item-label">Away Digest Button</span>
1469
- <label class="switch switch-sm">
1470
- <input type="checkbox" id="appSettingsShowAwayDigestButton">
1471
- <span class="slider"></span>
1472
- </label>
1473
- </div>
1474
- <div class="settings-item" title="Show the Cron button in the footer toolbar (opens the cron jobs manager)">
1475
- <span class="settings-item-label">Cron Button</span>
1476
- <label class="switch switch-sm">
1477
- <input type="checkbox" id="appSettingsShowCronButton">
1478
- <span class="slider"></span>
1479
- </label>
1480
- </div>
1481
- <div class="settings-item" title="Show a terminal redraw button in the header — refit the terminal to the current screen size (useful when switching between devices)">
1482
- <span class="settings-item-label">Redraw Terminal Button</span>
1483
- <label class="switch switch-sm">
1484
- <input type="checkbox" id="appSettingsShowRedrawButton">
1485
- <span class="slider"></span>
1486
- </label>
1653
+ <div class="set-group">
1654
+ <div class="set-group-head"><h4>Scheduling</h4><span class="set-scope">device</span></div>
1655
+ <div class="set-group-body">
1656
+ <div class="set-chips" data-search="cron scheduled jobs toolbar">
1657
+ <label class="set-chip" data-preview="toolbar" data-preview-order="1"><input type="checkbox" id="appSettingsShowCronButton"><svg class="set-chip-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 14"/></svg><span>Cron</span></label>
1658
+ </div>
1659
+ </div>
1487
1660
  </div>
1488
1661
 
1489
- <!-- Phone Section (only meaningful under 430px, hidden elsewhere by settings-ui.js) -->
1490
- <div class="settings-section-header" id="appSettingsPhoneSection">Phone</div>
1491
- <div class="settings-item" id="appSettingsMobileOverviewItem" title="On phones, the C logo opens a session overview (needs you / spaces / idle) instead of the welcome screen">
1492
- <span class="settings-item-label">Overview Home Screen</span>
1493
- <label class="switch switch-sm">
1494
- <input type="checkbox" id="appSettingsMobileOverview" checked>
1495
- <span class="slider"></span>
1496
- </label>
1662
+ <div class="set-group">
1663
+ <div class="set-group-head"><h4>Subagent windows</h4></div>
1664
+ <div class="set-group-body">
1665
+ <div class="set-row" data-search="subagent tracking background agents">
1666
+ <div class="set-row-text">
1667
+ <span class="set-row-label">Track background agents <span class="set-scope">synced</span></span>
1668
+ <span class="set-row-desc">Follow Claude Code subagents in real time.</span>
1669
+ </div>
1670
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsSubagentTracking" checked><span class="slider"></span></label>
1671
+ </div>
1672
+ <div class="set-row" data-search="subagent active tab only windows">
1673
+ <div class="set-row-text">
1674
+ <span class="set-row-label">Active tab only <span class="set-scope">device</span></span>
1675
+ <span class="set-row-desc">Only show agent windows for the selected session.</span>
1676
+ </div>
1677
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsSubagentActiveTabOnly" checked><span class="slider"></span></label>
1678
+ </div>
1679
+ </div>
1497
1680
  </div>
1681
+ </section>
1498
1682
 
1499
- <!-- Tab Bar Section -->
1500
- <div class="settings-section-header">Tab Bar</div>
1501
- <div class="settings-item" title="Show folder path below tab name and allow tab bar to wrap into multiple rows">
1502
- <span class="settings-item-label">Tall Tabs (Name + Folder)</span>
1503
- <label class="switch switch-sm">
1504
- <input type="checkbox" id="appSettingsTabTwoRows">
1505
- <span class="slider"></span>
1506
- </label>
1507
- </div>
1508
- <div class="settings-item" title="Show the open-in-new-window (pop-out) button when hovering a session tab">
1509
- <span class="settings-item-label">Pop-out Button on Tabs</span>
1510
- <label class="switch switch-sm">
1511
- <input type="checkbox" id="appSettingsShowTabDetachButton">
1512
- <span class="slider"></span>
1513
- </label>
1683
+ <!-- ══ Appearance ═══════════════════════════════════════════════ -->
1684
+ <section class="set-section" id="settings-appearance" data-label="Appearance">
1685
+ <div class="set-section-head">
1686
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 0 0 18 4.5 4.5 0 0 0 0-9 4.5 4.5 0 0 1 0-9z"/></svg>
1687
+ <h2>Appearance</h2>
1514
1688
  </div>
1689
+ <p class="set-section-blurb">Theme, motion, and what this install calls itself.</p>
1515
1690
 
1516
- <!-- Panels Section -->
1517
- <div class="settings-section-header">Panels</div>
1518
- <div class="settings-item" title="Show Monitor panel at bottom right">
1519
- <span class="settings-item-label">Monitor</span>
1520
- <label class="switch switch-sm">
1521
- <input type="checkbox" id="appSettingsShowMonitor" checked>
1522
- <span class="slider"></span>
1523
- </label>
1524
- </div>
1525
- <div class="settings-item" title="Show active tools and file viewers in a floating panel">
1526
- <span class="settings-item-label">Project Insights</span>
1527
- <label class="switch switch-sm">
1528
- <input type="checkbox" id="appSettingsShowProjectInsights">
1529
- <span class="slider"></span>
1530
- </label>
1531
- </div>
1532
- <div class="settings-item" title="Show file browser panel on the right side">
1533
- <span class="settings-item-label">File Browser</span>
1534
- <label class="switch switch-sm">
1535
- <input type="checkbox" id="appSettingsShowFileBrowser">
1536
- <span class="slider"></span>
1537
- </label>
1538
- </div>
1539
- <div class="settings-item" title="Show the Subagents panel (independent from Monitor)">
1540
- <span class="settings-item-label">Subagents</span>
1541
- <label class="switch switch-sm">
1542
- <input type="checkbox" id="appSettingsShowSubagents">
1543
- <span class="slider"></span>
1544
- </label>
1545
- </div>
1546
- <div class="settings-item" title="Cross-session inbox of prompts waiting on you (permission dialogs, questions, idle prompts) with answer-in-place buttons; the header bell appears only while something is pending">
1547
- <span class="settings-item-label">Approvals Inbox</span>
1548
- <label class="switch switch-sm">
1549
- <input type="checkbox" id="appSettingsApprovalsInbox">
1550
- <span class="slider"></span>
1551
- </label>
1691
+ <div class="set-group">
1692
+ <div class="set-group-head"><h4>Theme</h4><span class="set-scope">device</span></div>
1693
+ <div class="set-group-body">
1694
+ <div class="set-row has-field" data-search="skin theme palette colors dark light">
1695
+ <div class="set-row-text">
1696
+ <span class="set-row-label">Skin</span>
1697
+ <span class="set-row-desc">Palette for the terminal and the UI.</span>
1698
+ </div>
1699
+ <select id="appSettingsSkin" class="set-select">
1700
+ <optgroup label="Light">
1701
+ <option value="paper-gray">Paper Gray</option>
1702
+ <option value="solarized-light">Solarized Light</option>
1703
+ <option value="catppuccin-latte">Catppuccin Latte</option>
1704
+ <option value="rose-pine-dawn">Rosé Pine Dawn</option>
1705
+ </optgroup>
1706
+ <optgroup label="Dark">
1707
+ <option value="daylight-blue">Daylight Blue</option>
1708
+ <option value="daylight-green">Daylight Green</option>
1709
+ <option value="og">OG Codeman</option>
1710
+ </optgroup>
1711
+ </select>
1712
+ </div>
1713
+ <div class="set-row has-field" data-search="entrance animations motion tabs windows">
1714
+ <div class="set-row-text">
1715
+ <span class="set-row-label">Entrance Animations</span>
1716
+ <span class="set-row-desc">How new tabs, panes and agent windows arrive. Add ?animlab=1 to the URL for per-surface control.</span>
1717
+ </div>
1718
+ <select id="appSettingsEntranceAnim" class="set-select">
1719
+ <option value="legacy">Off (default)</option>
1720
+ <option value="terminal">Terminal (CRT)</option>
1721
+ <option value="beamdown">Beam down</option>
1722
+ <option value="quiet">Quiet</option>
1723
+ <option value="playful">Playful</option>
1724
+ <option value="custom">Custom (set in the lab)</option>
1725
+ </select>
1726
+ </div>
1727
+ </div>
1552
1728
  </div>
1553
- <div class="settings-item" title="Read My Mind: capture your submitted prompts into a per-case intent profile and predict your next prompt on demand (header 🧠 button on Claude sessions). Predictions cost tokens and are never auto-sent">
1554
- <span class="settings-item-label">Read My Mind</span>
1555
- <label class="switch switch-sm">
1556
- <input type="checkbox" id="appSettingsReadMyMind">
1557
- <span class="slider"></span>
1558
- </label>
1729
+
1730
+ <div class="set-group">
1731
+ <div class="set-group-head"><h4>Identity</h4></div>
1732
+ <div class="set-group-body">
1733
+ <div class="set-row has-field" data-search="display name branding title">
1734
+ <div class="set-row-text">
1735
+ <span class="set-row-label">Display Name <span class="set-scope">synced</span></span>
1736
+ <span class="set-row-desc">Shown in the browser UI and the window title. Unicode is fine.</span>
1737
+ </div>
1738
+ <input type="text" id="appSettingsDisplayName" class="set-input" maxlength="40" placeholder="Codeman" autocomplete="off">
1739
+ </div>
1740
+ <div class="set-row has-field" data-search="language interface chinese english">
1741
+ <div class="set-row-text">
1742
+ <span class="set-row-label">Interface Language <span class="set-scope">device</span></span>
1743
+ <span class="set-row-desc">Dialogs and status messages use the same language.</span>
1744
+ </div>
1745
+ <select id="appSettingsLanguage" class="set-select">
1746
+ <option value="en">English</option>
1747
+ <option value="zh-CN">简体中文</option>
1748
+ </select>
1749
+ </div>
1750
+ </div>
1559
1751
  </div>
1560
- <div class="settings-item" title="Show ultracode / Workflow runs as a master-detail tab (tasks on the left, agents with tokens + tool calls on the right)">
1561
- <span class="settings-item-label">Ultracode Agents</span>
1562
- <label class="switch switch-sm">
1563
- <input type="checkbox" id="appSettingsShowUltracodeAgents">
1564
- <span class="slider"></span>
1565
- </label>
1752
+
1753
+ <div class="set-group">
1754
+ <div class="set-group-head"><h4>Tabs</h4><span class="set-scope">device</span></div>
1755
+ <div class="set-group-body">
1756
+ <div class="set-row" data-search="tall tabs folder name two rows">
1757
+ <div class="set-row-text">
1758
+ <span class="set-row-label">Tall Tabs</span>
1759
+ <span class="set-row-desc">Show the folder under the session name and let the tab bar wrap.</span>
1760
+ </div>
1761
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsTabTwoRows"><span class="slider"></span></label>
1762
+ </div>
1763
+ <div class="set-row" data-search="pop out detach tab window">
1764
+ <div class="set-row-text">
1765
+ <span class="set-row-label">Pop-out Button on Tabs</span>
1766
+ <span class="set-row-desc">Open a session in its own window from the tab.</span>
1767
+ </div>
1768
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsShowTabDetachButton"><span class="slider"></span></label>
1769
+ </div>
1770
+ <div class="set-row" id="appSettingsMobileOverviewItem" data-search="overview home screen phone logo">
1771
+ <div class="set-row-text">
1772
+ <span class="set-row-label">Overview Home Screen <span class="set-tag">phone</span></span>
1773
+ <span class="set-row-desc">The C logo opens the session overview instead of the welcome screen.</span>
1774
+ </div>
1775
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsMobileOverview" checked><span class="slider"></span></label>
1776
+ </div>
1777
+ </div>
1566
1778
  </div>
1567
- <div class="settings-item" title="Pop a floating window for each active ultracode / Workflow run, connected by a line to its session tab (additional to the Ultracode Agents panel)">
1568
- <span class="settings-item-label">Ultracode Floating Windows</span>
1569
- <label class="switch switch-sm">
1570
- <input type="checkbox" id="appSettingsUltracodeFloatingWindows">
1571
- <span class="slider"></span>
1572
- </label>
1779
+ </section>
1780
+
1781
+ <!-- ══ Models ═══════════════════════════════════════════════════ -->
1782
+ <section class="set-section" id="settings-models" data-label="Models">
1783
+ <div class="set-section-head">
1784
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3z"/><path d="M12 12l8-4.5M12 12v9M12 12L4 7.5"/></svg>
1785
+ <h2>Models</h2>
1786
+ </div>
1787
+ <p class="set-section-blurb">One place for what new sessions run on, and what background tasks are routed to.</p>
1788
+
1789
+ <div class="set-group">
1790
+ <div class="set-group-head"><h4>New Claude sessions</h4><span class="set-scope">synced</span></div>
1791
+ <p class="set-group-hint">A soft default, pinned via the case's .claude/settings.local.json. /model still switches inside a running session.</p>
1792
+ <div class="set-group-body">
1793
+ <!-- Cards are built from the select below by settings-ui.js, which keeps
1794
+ the select as the single source of truth for load/save. -->
1795
+ <div class="set-modelgrid" id="appSettingsModelCards" role="radiogroup" aria-label="Model for new Claude sessions" data-search="model opus sonnet haiku fable claude"></div>
1796
+ <select id="appSettingsClaudeModel" class="set-select set-field-hidden" aria-hidden="true" tabindex="-1">
1797
+ <option value="" data-meta="Whatever the CLI picks">Default (CLI setting)</option>
1798
+ <option value="claude-fable-5" data-meta="Most powerful" data-base="claude-fable-5" data-ctx="1">Fable 5</option>
1799
+ <option value="claude-fable-5[1m]" data-variant="1m" data-base="claude-fable-5">Fable 5 (1M context)</option>
1800
+ <option value="opus" data-meta="Most capable" data-base="opus" data-ctx="1">Opus</option>
1801
+ <option value="opus[1m]" data-variant="1m" data-base="opus">Opus (1M context)</option>
1802
+ <option value="claude-opus-4-6" data-meta="Previous generation" data-base="claude-opus-4-6" data-ctx="1">Opus 4.6</option>
1803
+ <option value="claude-opus-4-6[1m]" data-variant="1m" data-base="claude-opus-4-6">Opus 4.6 (1M context)</option>
1804
+ <option value="sonnet" data-meta="Balanced" data-base="sonnet">Sonnet</option>
1805
+ <option value="haiku" data-meta="Fast &amp; cheap" data-base="haiku">Haiku</option>
1806
+ </select>
1807
+ <div class="set-row" id="appSettingsContextRow" data-search="1m context window opus long">
1808
+ <div class="set-row-text">
1809
+ <span class="set-row-label">1M context window</span>
1810
+ <span class="set-row-desc" id="appSettingsContextDesc">Available for Fable 5, Opus and Opus 4.6.</span>
1811
+ </div>
1812
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsOpusContext1m"><span class="slider"></span></label>
1813
+ </div>
1814
+ <div class="set-row set-row-block" data-search="thinking effort ultracode xhigh max reasoning">
1815
+ <div class="set-row-text">
1816
+ <span class="set-row-label">Thinking effort</span>
1817
+ <span class="set-row-desc">Switchable in-session with /effort. Ultracode runs multi-agent workflows.</span>
1818
+ </div>
1819
+ <div class="set-segment" id="appSettingsEffortSegment" role="radiogroup" aria-label="Thinking effort"></div>
1820
+ <select id="appSettingsThinkingEffort" class="set-select set-field-hidden" aria-hidden="true" tabindex="-1">
1821
+ <option value="">Default</option>
1822
+ <option value="low">Low</option>
1823
+ <option value="medium">Medium</option>
1824
+ <option value="high">High</option>
1825
+ <option value="xhigh">XHigh</option>
1826
+ <option value="max">Max</option>
1827
+ <option value="ultracode">Ultracode</option>
1828
+ </select>
1829
+ </div>
1830
+ </div>
1573
1831
  </div>
1574
1832
 
1575
- <!-- Subagent Options Section -->
1576
- <div class="settings-section-header">Subagent Options</div>
1577
- <div class="settings-item" title="Monitor Claude Code background agents in real-time">
1578
- <span class="settings-item-label">Enable Tracking</span>
1579
- <label class="switch switch-sm">
1580
- <input type="checkbox" id="appSettingsSubagentTracking" checked>
1581
- <span class="slider"></span>
1582
- </label>
1583
- </div>
1584
- <div class="settings-item" title="Only show subagent windows when their parent tab is selected">
1585
- <span class="settings-item-label">Active Tab Only</span>
1586
- <label class="switch switch-sm">
1587
- <input type="checkbox" id="appSettingsSubagentActiveTabOnly" checked>
1588
- <span class="slider"></span>
1589
- </label>
1833
+ <div class="set-group set-group-advanced" id="appSettingsTaskRouting">
1834
+ <div class="set-group-head set-group-head-toggle" role="button" tabindex="0" aria-expanded="false">
1835
+ <h4>Task routing</h4>
1836
+ <span class="set-scope">synced</span>
1837
+ <span class="set-adv">Advanced
1838
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
1839
+ </span>
1840
+ </div>
1841
+ <p class="set-group-hint">Models for orchestrator and background work. Leave on the default unless you are tuning cost.</p>
1842
+ <div class="set-group-body">
1843
+ <div class="set-row has-field" data-search="default model tasks orchestrator">
1844
+ <div class="set-row-text">
1845
+ <span class="set-row-label">Default for tasks</span>
1846
+ <span class="set-row-desc">Used for execution tasks. Optimizer suggestions stay advisory.</span>
1847
+ </div>
1848
+ <select id="appSettingsDefaultModel" class="set-select">
1849
+ <option value="">Default (CLI default)</option>
1850
+ <option value="claude-fable-5">Fable 5 (Most powerful)</option>
1851
+ <option value="opus">Opus (Most capable)</option>
1852
+ <option value="sonnet">Sonnet (Balanced)</option>
1853
+ <option value="haiku">Haiku (Fast &amp; cheap)</option>
1854
+ </select>
1855
+ </div>
1856
+ <div class="set-minigrid" data-search="explore implement test review agent type overrides">
1857
+ <div class="set-mini">
1858
+ <span class="set-mini-label">Explore</span>
1859
+ <select id="appSettingsModelExplore" class="set-select">
1860
+ <option value="">Use default</option>
1861
+ <option value="haiku">Haiku</option>
1862
+ <option value="sonnet">Sonnet</option>
1863
+ <option value="opus">Opus</option>
1864
+ <option value="claude-fable-5">Fable 5</option>
1865
+ </select>
1866
+ </div>
1867
+ <div class="set-mini">
1868
+ <span class="set-mini-label">Implement</span>
1869
+ <select id="appSettingsModelImplement" class="set-select">
1870
+ <option value="">Use default</option>
1871
+ <option value="haiku">Haiku</option>
1872
+ <option value="sonnet">Sonnet</option>
1873
+ <option value="opus">Opus</option>
1874
+ <option value="claude-fable-5">Fable 5</option>
1875
+ </select>
1876
+ </div>
1877
+ <div class="set-mini">
1878
+ <span class="set-mini-label">Test</span>
1879
+ <select id="appSettingsModelTest" class="set-select">
1880
+ <option value="">Use default</option>
1881
+ <option value="haiku">Haiku</option>
1882
+ <option value="sonnet">Sonnet</option>
1883
+ <option value="opus">Opus</option>
1884
+ <option value="claude-fable-5">Fable 5</option>
1885
+ </select>
1886
+ </div>
1887
+ <div class="set-mini">
1888
+ <span class="set-mini-label">Review</span>
1889
+ <select id="appSettingsModelReview" class="set-select">
1890
+ <option value="">Use default</option>
1891
+ <option value="haiku">Haiku</option>
1892
+ <option value="sonnet">Sonnet</option>
1893
+ <option value="opus">Opus</option>
1894
+ <option value="claude-fable-5">Fable 5</option>
1895
+ </select>
1896
+ </div>
1897
+ </div>
1898
+ <div class="set-row" data-search="optimizer recommendations advisory">
1899
+ <div class="set-row-text">
1900
+ <span class="set-row-label">Show optimizer recommendations</span>
1901
+ <span class="set-row-desc">Advisory only. Never overrides your choice.</span>
1902
+ </div>
1903
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsShowModelRecommendations" checked><span class="slider"></span></label>
1904
+ </div>
1905
+ </div>
1590
1906
  </div>
1907
+ </section>
1591
1908
 
1592
- <!-- Image Watcher Options Section -->
1593
- <div class="settings-section-header">Image Watcher</div>
1594
- <div class="settings-item" title="Automatically detect and popup new images in session directories">
1595
- <span class="settings-item-label">Enable Globally</span>
1596
- <label class="switch switch-sm">
1597
- <input type="checkbox" id="appSettingsImageWatcherEnabled">
1598
- <span class="slider"></span>
1599
- </label>
1909
+ <!-- ══ Agents &amp; CLIs ═════════════════════════════════════════ -->
1910
+ <section class="set-section" id="settings-clis" data-label="Agents &amp; CLIs">
1911
+ <div class="set-section-head">
1912
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h2"/><path d="M16 3h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-2"/><circle cx="12" cy="12" r="2.5"/></svg>
1913
+ <h2>Agents &amp; CLIs</h2>
1600
1914
  </div>
1915
+ <p class="set-section-blurb">Launch flags for the CLIs Codeman spawns.</p>
1601
1916
 
1602
- <!-- Remote Access Section -->
1603
- <div class="settings-section-header">Remote Access</div>
1604
- <div class="settings-item" title="Expose Codeman via Cloudflare Tunnel for remote access">
1605
- <span class="settings-item-label">Cloudflare Tunnel</span>
1606
- <label class="switch switch-sm">
1607
- <input type="checkbox" id="appSettingsTunnelEnabled">
1608
- <span class="slider"></span>
1609
- </label>
1917
+ <div class="set-group">
1918
+ <div class="set-group-head"><h4>Claude</h4><span class="set-scope">synced</span></div>
1919
+ <div class="set-group-body">
1920
+ <div class="set-row has-field" data-search="startup mode permissions auto allowed tools">
1921
+ <div class="set-row-text">
1922
+ <span class="set-row-label">Startup Mode</span>
1923
+ <span class="set-row-desc">How the CLI is launched in new sessions. Auto Mode runs without routine prompts behind a background safety classifier.</span>
1924
+ </div>
1925
+ <select id="appSettingsClaudeMode" class="set-select">
1926
+ <option value="dangerously-skip-permissions">Skip Permissions (default)</option>
1927
+ <option value="auto">Auto (classifier-guarded, low prompts)</option>
1928
+ <option value="normal">Normal (with prompts)</option>
1929
+ <option value="allowedTools">Allowed Tools Only</option>
1930
+ </select>
1931
+ </div>
1932
+ <div class="set-row has-field" id="allowedToolsRow" style="display: none;" data-search="allowed tools list">
1933
+ <div class="set-row-text">
1934
+ <span class="set-row-label">Allowed Tools</span>
1935
+ <span class="set-row-desc">Comma-separated list of tools to allow.</span>
1936
+ </div>
1937
+ <input type="text" id="appSettingsAllowedTools" class="set-input" placeholder="Read,Glob,Grep,Bash">
1938
+ </div>
1939
+ <div class="set-row" data-search="ralph todo tracker loop">
1940
+ <div class="set-row-text">
1941
+ <span class="set-row-label">Ralph / Todo Tracker</span>
1942
+ <span class="set-row-desc">Auto-enable for new sessions. Otherwise it enables itself on Ralph pattern detection.</span>
1943
+ </div>
1944
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsRalphEnabled"><span class="slider"></span></label>
1945
+ </div>
1946
+ <div class="set-row" data-search="agent teams experimental">
1947
+ <div class="set-row-text">
1948
+ <span class="set-row-label">Agent Teams</span>
1949
+ <span class="set-row-desc">Experimental multi-agent teams for all new Claude sessions.</span>
1950
+ </div>
1951
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsAgentTeams"><span class="slider"></span></label>
1952
+ </div>
1953
+ <div class="set-row" data-search="agent skill codeman api workers">
1954
+ <div class="set-row-text">
1955
+ <span class="set-row-label">Codeman Agent Skill</span>
1956
+ <span class="set-row-desc">Let new sessions start workers, send prompts and wait for results over the API.</span>
1957
+ </div>
1958
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsAgentSkill"><span class="slider"></span></label>
1959
+ </div>
1960
+ <div class="set-row" data-search="remote auto reconnect ssh">
1961
+ <div class="set-row-text">
1962
+ <span class="set-row-label">Remote auto-reconnect</span>
1963
+ <span class="set-row-desc">Reattach remote SSH sessions to their durable tmux after a dropped link.</span>
1964
+ </div>
1965
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsRemoteAutoReconnect"><span class="slider"></span></label>
1966
+ </div>
1967
+ <div class="set-row" data-search="nice priority cpu">
1968
+ <div class="set-row-text">
1969
+ <span class="set-row-label">Nice priority</span>
1970
+ <span class="set-row-desc">Lower the CPU priority of new sessions to reduce system impact.</span>
1971
+ </div>
1972
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsNiceEnabled"><span class="slider"></span></label>
1973
+ </div>
1974
+ <div class="set-row" id="niceValueRow" data-search="nice value priority number">
1975
+ <div class="set-row-text">
1976
+ <span class="set-row-label">Nice value</span>
1977
+ <span class="set-row-desc">-20 to 19. Higher means lower priority. Default 10.</span>
1978
+ </div>
1979
+ <input type="number" id="appSettingsNiceValue" class="set-num" min="-20" max="19" value="10">
1980
+ </div>
1981
+ </div>
1610
1982
  </div>
1611
- <div class="settings-item" id="tunnelUrlRow" style="display:none">
1612
- <span class="settings-item-label">Tunnel URL</span>
1613
- <div style="display:flex; align-items:center; gap:8px">
1614
- <span id="tunnelUrlDisplay" class="settings-item-value" style="cursor:pointer; text-decoration:underline; font-family:monospace; font-size:12px" title="Click to copy"></span>
1615
- <button class="btn-icon-sm" id="tunnelQrBtn" onclick="app.showTunnelQR()" title="Show QR code" style="font-size:16px; padding:2px 6px; background:none; border:1px solid var(--border); border-radius:4px; cursor:pointer; color:var(--text-secondary)">⊞</button>
1983
+
1984
+ <div class="set-group" id="appSettingsCodexGroup">
1985
+ <div class="set-group-head"><h4>Codex</h4><span class="set-scope">synced</span></div>
1986
+ <div class="set-group-body">
1987
+ <div class="set-row" data-search="codex bypass approvals sandbox">
1988
+ <div class="set-row-text">
1989
+ <span class="set-row-label">Bypass approvals and sandbox</span>
1990
+ <span class="set-row-desc">Start new Codex sessions with --dangerously-bypass-approvals-and-sandbox.</span>
1991
+ </div>
1992
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsCodexDangerouslyBypassApprovals"><span class="slider"></span></label>
1993
+ </div>
1994
+ <div class="set-row" data-search="codex animations status effects">
1995
+ <div class="set-row-text">
1996
+ <span class="set-row-label">Animated status effects</span>
1997
+ <span class="set-row-desc">Decorative Codex TUI motion. Leave off to reduce remote and mobile redraws.</span>
1998
+ </div>
1999
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsCodexAnimations"><span class="slider"></span></label>
2000
+ </div>
1616
2001
  </div>
1617
2002
  </div>
1618
- <div class="settings-item" id="tunnelUploadUrlRow" style="display:none">
1619
- <span class="settings-item-label">Upload URL</span>
1620
- <span id="tunnelUploadUrlDisplay" class="settings-item-value" style="cursor:pointer; text-decoration:underline; font-family:monospace; font-size:12px" title="Click to copy"></span>
2003
+ </section>
2004
+
2005
+ <!-- ══ Notifications ════════════════════════════════════════════ -->
2006
+ <section class="set-section" id="settings-notifications" data-label="Notifications">
2007
+ <div class="set-section-head">
2008
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></svg>
2009
+ <h2>Notifications</h2>
1621
2010
  </div>
2011
+ <p class="set-section-blurb">What reaches you, and on which channel.</p>
1622
2012
 
1623
- <!-- Updates Section -->
1624
- <div class="settings-section-header">Updates</div>
1625
- <div class="settings-item" title="Codeman version currently running">
1626
- <span class="settings-item-label">Current Version</span>
1627
- <span class="settings-item-value" id="updateCurrentVersion" style="font-family:monospace">&mdash;</span>
2013
+ <div class="set-group">
2014
+ <div class="set-group-head"><h4>Channels</h4><span class="set-scope">device</span></div>
2015
+ <div class="set-group-body">
2016
+ <div class="set-row" data-search="enable notifications master">
2017
+ <div class="set-row-text">
2018
+ <span class="set-row-label">Notifications</span>
2019
+ <span class="set-row-desc">Master switch for every layer below.</span>
2020
+ </div>
2021
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsNotifEnabled" checked><span class="slider"></span></label>
2022
+ </div>
2023
+ <div class="set-row" data-search="browser notifications os permission">
2024
+ <div class="set-row-text">
2025
+ <span class="set-row-label">Browser</span>
2026
+ <span class="set-row-desc">OS notifications while the tab is hidden. Remote access needs HTTPS: codeman web --https</span>
2027
+ </div>
2028
+ <div class="set-row-actions">
2029
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsNotifBrowser"><span class="slider"></span></label>
2030
+ <button class="btn-toolbar btn-sm" onclick="app.notificationManager?.requestPermission()" title="Request browser notification permission">Ask</button>
2031
+ <span class="settings-status" id="notifPermissionStatus">?</span>
2032
+ </div>
2033
+ </div>
2034
+ <div class="set-row" data-search="push notifications subscribe pwa">
2035
+ <div class="set-row-text">
2036
+ <span class="set-row-label">Push</span>
2037
+ <span class="set-row-desc">Works with the tab closed, and through a Cloudflare tunnel. Requires HTTPS or localhost; iOS requires the PWA.</span>
2038
+ </div>
2039
+ <div class="set-row-actions">
2040
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsPushEnabled"><span class="slider"></span></label>
2041
+ <button class="btn-toolbar btn-sm" id="pushSubscribeBtn" onclick="app.togglePushSubscription()" title="Subscribe or unsubscribe to push notifications">Subscribe</button>
2042
+ <span class="settings-status" id="pushSubscriptionStatus">off</span>
2043
+ </div>
2044
+ </div>
2045
+ <div class="set-row" data-search="audio alerts beep sound">
2046
+ <div class="set-row-text">
2047
+ <span class="set-row-label">Audio alerts</span>
2048
+ <span class="set-row-desc">Short beep on critical events.</span>
2049
+ </div>
2050
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsNotifAudio"><span class="slider"></span></label>
2051
+ </div>
2052
+ <div class="set-row" data-search="idle threshold stuck minutes">
2053
+ <div class="set-row-text">
2054
+ <span class="set-row-label">Idle threshold</span>
2055
+ <span class="set-row-desc">Notify when a session sits idle longer than this.</span>
2056
+ </div>
2057
+ <div class="set-row-actions">
2058
+ <input type="number" id="appSettingsNotifStuckMins" class="set-num" value="10" min="1" max="120">
2059
+ <span class="set-unit">min</span>
2060
+ </div>
2061
+ </div>
2062
+ </div>
1628
2063
  </div>
1629
- <div class="settings-item" id="updateCheckRow" title="Check GitHub for a newer Codeman release">
1630
- <span class="settings-item-label">Check for Updates</span>
1631
- <button class="btn-toolbar btn-sm" id="updateCheckBtn" onclick="app.checkForUpdate()">Check now</button>
2064
+
2065
+ <div class="set-group">
2066
+ <div class="set-group-head"><h4>Levels</h4><span class="set-scope">device</span></div>
2067
+ <div class="set-group-body">
2068
+ <div class="set-chips" data-search="critical warning info levels">
2069
+ <label class="set-chip"><input type="checkbox" id="appSettingsNotifCritical" checked><span>Critical</span></label>
2070
+ <label class="set-chip"><input type="checkbox" id="appSettingsNotifWarning" checked><span>Warning</span></label>
2071
+ <label class="set-chip"><input type="checkbox" id="appSettingsNotifInfo" checked><span>Info</span></label>
2072
+ </div>
2073
+ </div>
1632
2074
  </div>
1633
- <div id="updateResult" style="display:none; padding:4px 2px 8px; font-size:13px; color:var(--text-secondary)"></div>
1634
- <div class="settings-item" id="updateActionRow" style="display:none">
1635
- <span class="settings-item-label" id="updateActionLabel">Update available</span>
1636
- <button class="btn-toolbar btn-sm btn-primary" id="updateNowBtn" onclick="app.startSelfUpdate()">Update now</button>
2075
+
2076
+ <div class="set-group">
2077
+ <div class="set-group-head"><h4>Per event</h4><span class="set-scope">device</span></div>
2078
+ <div class="set-group-body">
2079
+ <div class="event-type-grid" data-search="per event permission question idle response respawn task subagent">
2080
+ <div class="event-header">Event</div>
2081
+ <div class="event-header">On</div>
2082
+ <div class="event-header">Browser</div>
2083
+ <div class="event-header">Push</div>
2084
+ <div class="event-header">Sound</div>
2085
+
2086
+ <div class="event-label">Permission prompts</div>
2087
+ <input type="checkbox" id="eventPermissionEnabled" checked>
2088
+ <input type="checkbox" id="eventPermissionBrowser" checked>
2089
+ <input type="checkbox" id="eventPermissionPush" checked>
2090
+ <input type="checkbox" id="eventPermissionAudio" checked>
2091
+
2092
+ <div class="event-label">Questions from Claude</div>
2093
+ <input type="checkbox" id="eventQuestionEnabled" checked>
2094
+ <input type="checkbox" id="eventQuestionBrowser" checked>
2095
+ <input type="checkbox" id="eventQuestionPush" checked>
2096
+ <input type="checkbox" id="eventQuestionAudio" checked>
2097
+
2098
+ <div class="event-label">Session idle</div>
2099
+ <input type="checkbox" id="eventIdleEnabled" checked>
2100
+ <input type="checkbox" id="eventIdleBrowser" checked>
2101
+ <input type="checkbox" id="eventIdlePush">
2102
+ <input type="checkbox" id="eventIdleAudio">
2103
+
2104
+ <div class="event-label">Response complete</div>
2105
+ <input type="checkbox" id="eventStopEnabled">
2106
+ <input type="checkbox" id="eventStopBrowser">
2107
+ <input type="checkbox" id="eventStopPush">
2108
+ <input type="checkbox" id="eventStopAudio">
2109
+
2110
+ <div class="event-label">Respawn cycles</div>
2111
+ <input type="checkbox" id="eventRespawnEnabled" checked>
2112
+ <input type="checkbox" id="eventRespawnBrowser">
2113
+ <input type="checkbox" id="eventRespawnPush">
2114
+ <input type="checkbox" id="eventRespawnAudio">
2115
+
2116
+ <div class="event-label">Task complete</div>
2117
+ <input type="checkbox" id="eventRalphEnabled" checked>
2118
+ <input type="checkbox" id="eventRalphBrowser" checked>
2119
+ <input type="checkbox" id="eventRalphPush">
2120
+ <input type="checkbox" id="eventRalphAudio" checked>
2121
+
2122
+ <div class="event-label">Subagent activity</div>
2123
+ <input type="checkbox" id="eventSubagentEnabled">
2124
+ <input type="checkbox" id="eventSubagentBrowser">
2125
+ <input type="checkbox" id="eventSubagentPush">
2126
+ <input type="checkbox" id="eventSubagentAudio">
2127
+ </div>
2128
+ </div>
1637
2129
  </div>
1638
- <div id="updateNotes" style="display:none; max-height:160px; overflow:auto; padding:8px 10px; margin:4px 0 8px; font-size:12px; line-height:1.45; white-space:pre-wrap; word-break:break-word; background:rgba(127,127,127,0.08); border:1px solid var(--border); border-radius:6px"></div>
1639
- <div id="updateProgress" style="display:none; padding:8px 10px; margin:4px 0 8px; font-size:13px; border:1px solid var(--border); border-radius:6px"></div>
2130
+ </section>
1640
2131
 
1641
- </div>
1642
- </div>
1643
- <!-- Tab-Switch Tab -->
1644
- <!-- Claude CLI Tab -->
1645
- <div class="modal-tab-content hidden" id="settings-claude">
1646
- <div class="form-row">
1647
- <label>Startup Mode</label>
1648
- <select id="appSettingsClaudeMode" class="form-select">
1649
- <option value="dangerously-skip-permissions">Skip Permissions (default)</option>
1650
- <option value="auto">Auto (classifier-guarded, low prompts)</option>
1651
- <option value="normal">Normal (with prompts)</option>
1652
- <option value="allowedTools">Allowed Tools Only</option>
1653
- </select>
1654
- <span class="form-hint">How Claude CLI is started in screen sessions. Auto Mode runs without routine prompts behind a background safety classifier (needs Claude Code 2.1.207+ and Opus 4.6+/Sonnet 4.6+/Fable 5)</span>
1655
- </div>
1656
- <div class="form-row" id="allowedToolsRow" style="display: none;">
1657
- <label>Allowed Tools</label>
1658
- <input type="text" id="appSettingsAllowedTools" placeholder="Read,Glob,Grep,Bash">
1659
- <span class="form-hint">Comma-separated list of tools to allow</span>
1660
- </div>
1661
- <div class="form-row form-row-switch">
1662
- <label>Enable Ralph / Todo Tracker</label>
1663
- <label class="switch">
1664
- <input type="checkbox" id="appSettingsRalphEnabled">
1665
- <span class="slider"></span>
1666
- </label>
1667
- <span class="form-hint">Auto-enable for new sessions (otherwise auto-enables on Ralph pattern detection)</span>
1668
- </div>
1669
- <!-- Claude Permissions Section -->
1670
- <div class="form-section-header">Claude Permissions</div>
1671
- <div class="form-row form-row-switch">
1672
- <label>Agent Teams</label>
1673
- <label class="switch">
1674
- <input type="checkbox" id="appSettingsAgentTeams">
1675
- <span class="slider"></span>
1676
- </label>
1677
- <span class="form-hint">Enable experimental Agent Teams for all new Claude sessions (disabled by default)</span>
1678
- </div>
1679
- <div class="form-row form-row-switch">
1680
- <label>Agent Skill</label>
1681
- <label class="switch">
1682
- <input type="checkbox" id="appSettingsAgentSkill">
1683
- <span class="slider"></span>
1684
- </label>
1685
- <span class="form-hint">Give new Claude sessions the Codeman skill (start workers, send prompts, wait for results via the API)</span>
1686
- </div>
1687
- <div class="form-row">
1688
- <label>Claude Model</label>
1689
- <select id="appSettingsClaudeModel" class="form-select">
1690
- <option value="">Default (CLI setting)</option>
1691
- <option value="claude-fable-5[1m]">Fable 5 (1M context)</option>
1692
- <option value="claude-fable-5">Fable 5</option>
1693
- <option value="opus[1m]">Opus (1M context)</option>
1694
- <option value="opus">Opus</option>
1695
- <option value="claude-opus-4-6[1m]">Opus 4.6 (1M context)</option>
1696
- <option value="claude-opus-4-6">Opus 4.6</option>
1697
- <option value="sonnet">Sonnet</option>
1698
- <option value="haiku">Haiku</option>
1699
- </select>
1700
- <span class="form-hint">Model for new Claude sessions (pinned via the case's .claude/settings.local.json) — takes precedence over the 1M Opus toggle below</span>
1701
- </div>
1702
- <div class="form-row form-row-switch">
1703
- <label>1M Opus Context</label>
1704
- <label class="switch">
1705
- <input type="checkbox" id="appSettingsOpusContext1m">
1706
- <span class="slider"></span>
1707
- </label>
1708
- <span class="form-hint">Use 1M token context window (model: opus[1m]) for all new sessions — ignored when a Claude Model is selected above</span>
1709
- </div>
1710
- <div class="form-row form-row-switch">
1711
- <label>Remote auto-reconnect</label>
1712
- <label class="switch">
1713
- <input type="checkbox" id="appSettingsRemoteAutoReconnect">
1714
- <span class="slider"></span>
1715
- </label>
1716
- <span class="form-hint">Automatically re-establish remote (SSH) sessions when the connection drops, reattaching to the durable remote tmux session (on by default; bounded backoff)</span>
1717
- </div>
1718
- <div class="form-row">
1719
- <label>Thinking Effort</label>
1720
- <select id="appSettingsThinkingEffort" class="form-select">
1721
- <option value="">Default</option>
1722
- <option value="low">Low</option>
1723
- <option value="medium">Medium</option>
1724
- <option value="high">High</option>
1725
- <option value="xhigh">XHigh</option>
1726
- <option value="max">Max</option>
1727
- <option value="ultracode">Ultracode (multi-agent workflows)</option>
1728
- </select>
1729
- <span class="form-hint">Default effort for new Claude sessions — soft default, switchable anytime in-session via /effort (e.g. /effort ultracode)</span>
1730
- </div>
1731
- <!-- Nice Priority Section -->
1732
- <div class="form-section-header">Nice Priority</div>
1733
- <div class="form-row form-row-switch">
1734
- <label>Enable Nice Priority Reduction</label>
1735
- <label class="switch">
1736
- <input type="checkbox" id="appSettingsNiceEnabled">
1737
- <span class="slider"></span>
1738
- </label>
1739
- <span class="form-hint">Lower priority of Claude sessions (reduces system impact, only affects new sessions)</span>
1740
- </div>
1741
- <div class="form-row" id="niceValueRow">
1742
- <label>Nice Value</label>
1743
- <input type="number" id="appSettingsNiceValue" min="-20" max="19" value="10" style="width: 80px;">
1744
- <span class="form-hint">Process priority (-20 to 19, higher = lower priority, default: 10)</span>
1745
- </div>
1746
- </div>
1747
- <!-- Codex CLI Tab -->
1748
- <div class="modal-tab-content hidden" id="settings-codex">
1749
- <div class="form-section-header">Codex CLI</div>
1750
- <div class="form-row form-row-switch">
1751
- <label>Bypass Approvals and Sandbox</label>
1752
- <label class="switch">
1753
- <input type="checkbox" id="appSettingsCodexDangerouslyBypassApprovals">
1754
- <span class="slider"></span>
1755
- </label>
1756
- <span class="form-hint">Start new Codex sessions with --dangerously-bypass-approvals-and-sandbox</span>
1757
- </div>
1758
- <div class="form-row form-row-switch">
1759
- <label>Animated Status Effects</label>
1760
- <label class="switch">
1761
- <input type="checkbox" id="appSettingsCodexAnimations">
1762
- <span class="slider"></span>
1763
- </label>
1764
- <span class="form-hint">Decorative Codex TUI motion for new local sessions. Leave off to reduce remote and mobile redraws.</span>
1765
- </div>
1766
- </div>
1767
- <!-- Models Tab -->
1768
- <div class="modal-tab-content hidden" id="settings-models">
1769
- <div class="form-row">
1770
- <label>Default Model</label>
1771
- <select id="appSettingsDefaultModel" class="form-select">
1772
- <option value="">Default (CLI default)</option>
1773
- <option value="claude-fable-5">Fable 5 (Most powerful)</option>
1774
- <option value="opus">Opus (Most capable)</option>
1775
- <option value="sonnet">Sonnet (Balanced)</option>
1776
- <option value="haiku">Haiku (Fast & cheap)</option>
1777
- </select>
1778
- <span class="form-hint">Model used for execution tasks. Optimizer suggestions are advisory only.</span>
1779
- </div>
1780
- <div class="form-row form-row-switch">
1781
- <label>Show Optimizer Recommendations</label>
1782
- <label class="switch">
1783
- <input type="checkbox" id="appSettingsShowModelRecommendations" checked>
1784
- <span class="slider"></span>
1785
- </label>
1786
- <span class="form-hint">Show what the optimizer recommends (doesn't override your choice)</span>
1787
- </div>
1788
- <div class="form-section-header">Agent Type Overrides</div>
1789
- <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>
1790
- <div class="form-row">
1791
- <label>Explore Tasks</label>
1792
- <select id="appSettingsModelExplore" class="form-select">
1793
- <option value="">Use Default</option>
1794
- <option value="haiku">Haiku</option>
1795
- <option value="sonnet">Sonnet</option>
1796
- <option value="opus">Opus</option>
1797
- <option value="claude-fable-5">Fable 5</option>
1798
- </select>
1799
- <span class="form-hint">Quick searches, codebase exploration</span>
1800
- </div>
1801
- <div class="form-row">
1802
- <label>Implement Tasks</label>
1803
- <select id="appSettingsModelImplement" class="form-select">
1804
- <option value="">Use Default</option>
1805
- <option value="haiku">Haiku</option>
1806
- <option value="sonnet">Sonnet</option>
1807
- <option value="opus">Opus</option>
1808
- <option value="claude-fable-5">Fable 5</option>
1809
- </select>
1810
- <span class="form-hint">Code writing, feature implementation</span>
1811
- </div>
1812
- <div class="form-row">
1813
- <label>Test Tasks</label>
1814
- <select id="appSettingsModelTest" class="form-select">
1815
- <option value="">Use Default</option>
1816
- <option value="haiku">Haiku</option>
1817
- <option value="sonnet">Sonnet</option>
1818
- <option value="opus">Opus</option>
1819
- <option value="claude-fable-5">Fable 5</option>
1820
- </select>
1821
- <span class="form-hint">Writing and running tests</span>
1822
- </div>
1823
- <div class="form-row">
1824
- <label>Review Tasks</label>
1825
- <select id="appSettingsModelReview" class="form-select">
1826
- <option value="">Use Default</option>
1827
- <option value="haiku">Haiku</option>
1828
- <option value="sonnet">Sonnet</option>
1829
- <option value="opus">Opus</option>
1830
- <option value="claude-fable-5">Fable 5</option>
1831
- </select>
1832
- <span class="form-hint">Code review, quality checks</span>
1833
- </div>
1834
- </div>
1835
- <!-- Paths Tab -->
1836
- <div class="modal-tab-content hidden" id="settings-paths">
1837
- <div class="form-row">
1838
- <label>Default CLAUDE.md Template</label>
1839
- <input type="text" id="appSettingsClaudeMdPath" placeholder="/path/to/CLAUDE.md template">
1840
- <span class="form-hint">Used when creating new cases. Leave empty for built-in template.</span>
1841
- </div>
1842
- <div class="form-row">
1843
- <label>Default Working Directory</label>
1844
- <input type="text" id="appSettingsDefaultDir" placeholder="~/projects">
1845
- <span class="form-hint">Default directory for new sessions.</span>
1846
- </div>
1847
- </div>
1848
- <!-- Notifications Tab -->
1849
- <div class="modal-tab-content hidden" id="settings-notifications">
1850
- <div class="settings-grid">
1851
- <!-- Master Control Section -->
1852
- <div class="settings-section-header">Master Control</div>
1853
- <div class="settings-item" title="Master toggle for all notification layers">
1854
- <span class="settings-item-label">Enable Notifications</span>
1855
- <label class="switch switch-sm">
1856
- <input type="checkbox" id="appSettingsNotifEnabled" checked>
1857
- <span class="slider"></span>
1858
- </label>
2132
+ <!-- ══ Voice ════════════════════════════════════════════════════ -->
2133
+ <section class="set-section" id="settings-voice" data-label="Voice">
2134
+ <div class="set-section-head">
2135
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M5 11a7 7 0 0 0 14 0"/><path d="M12 18v4"/></svg>
2136
+ <h2>Voice</h2>
1859
2137
  </div>
1860
- <div class="settings-item" title="Show OS-level notifications when tab is hidden">
1861
- <span class="settings-item-label">Browser</span>
1862
- <div class="settings-item-actions">
1863
- <label class="switch switch-sm">
1864
- <input type="checkbox" id="appSettingsNotifBrowser">
1865
- <span class="slider"></span>
1866
- </label>
1867
- <button class="btn-toolbar btn-sm" onclick="app.notificationManager?.requestPermission()" title="Request browser notification permission">Ask</button>
1868
- <span class="settings-status" id="notifPermissionStatus">?</span>
2138
+ <p class="set-section-blurb">Dictation into the composer.</p>
2139
+
2140
+ <div class="set-group">
2141
+ <div class="set-group-head"><h4>Provider</h4><span class="set-scope">device</span></div>
2142
+ <div class="set-group-body">
2143
+ <div class="set-row" data-search="voice provider active">
2144
+ <div class="set-row-text"><span class="set-row-label">Active provider</span></div>
2145
+ <span class="voice-provider-status" id="voiceProviderStatus">&mdash;</span>
2146
+ </div>
2147
+ <div class="set-row has-field" data-search="voice provider claude deepgram web speech engine">
2148
+ <div class="set-row-text">
2149
+ <span class="set-row-label">Speech engine</span>
2150
+ <span class="set-row-desc">Auto prefers Claude when this server can transcribe, then Deepgram, then the browser.</span>
2151
+ </div>
2152
+ <select id="voiceProvider" class="set-select">
2153
+ <option value="auto">Auto</option>
2154
+ <option value="claude">Claude</option>
2155
+ <option value="deepgram">Deepgram</option>
2156
+ <option value="webspeech">Browser (Web Speech)</option>
2157
+ </select>
2158
+ </div>
2159
+ <div class="set-row has-field" data-search="voice insert mode compose">
2160
+ <div class="set-row-text">
2161
+ <span class="set-row-label">Insert mode</span>
2162
+ <span class="set-row-desc">Where dictated text lands.</span>
2163
+ </div>
2164
+ <select id="voiceInsertMode" class="set-select">
2165
+ <option value="direct">Direct to input</option>
2166
+ <option value="compose">Compose dialog</option>
2167
+ </select>
2168
+ </div>
2169
+ <div class="set-row has-field" data-search="voice language">
2170
+ <div class="set-row-text">
2171
+ <span class="set-row-label">Language</span>
2172
+ <span class="set-row-desc">Applies to whichever engine is active.</span>
2173
+ </div>
2174
+ <select id="voiceLanguage" class="set-select">
2175
+ <option value="en-US">English (US)</option>
2176
+ <option value="en-GB">English (UK)</option>
2177
+ <option value="es">Spanish</option>
2178
+ <option value="fr">French</option>
2179
+ <option value="de">German</option>
2180
+ <option value="ja">Japanese</option>
2181
+ <option value="multi">Auto-detect (multi)</option>
2182
+ </select>
2183
+ </div>
2184
+ <div class="set-row has-field" data-search="voice keyterms domain keywords">
2185
+ <div class="set-row-text">
2186
+ <span class="set-row-label">Domain keywords</span>
2187
+ <span class="set-row-desc">Comma-separated terms to boost recognition accuracy. Sent to Claude and Deepgram alike.</span>
2188
+ </div>
2189
+ <input type="text" id="voiceKeyterms" class="set-input" placeholder="codeman, tmux, respawn, subagent">
2190
+ </div>
1869
2191
  </div>
1870
2192
  </div>
1871
- <span class="form-hint" style="grid-column: 1 / -1; margin-top: -8px;">For remote access, HTTPS is required. Start with: <code>codeman web --https</code></span>
1872
2193
 
1873
- <div class="settings-item" title="OS-level push notifications — works even when tab is closed">
1874
- <span class="settings-item-label">Push</span>
1875
- <div class="settings-item-actions">
1876
- <label class="switch switch-sm">
1877
- <input type="checkbox" id="appSettingsPushEnabled">
1878
- <span class="slider"></span>
1879
- </label>
1880
- <button class="btn-toolbar btn-sm" id="pushSubscribeBtn" onclick="app.togglePushSubscription()" title="Subscribe/unsubscribe to push notifications">Subscribe</button>
1881
- <span class="settings-status" id="pushSubscriptionStatus">off</span>
2194
+ <div class="set-group">
2195
+ <div class="set-group-head"><h4>Claude</h4><span class="set-scope">synced</span></div>
2196
+ <div class="set-group-body">
2197
+ <div class="set-row" data-search="claude voice dictation subscription no api key">
2198
+ <div class="set-row-text">
2199
+ <span class="set-row-label">Transcribe with this server's Claude login</span>
2200
+ <span class="set-row-desc">Dictation with no API key, through the same service Claude Code's own /voice mode uses. Microphone audio goes to Anthropic and is billed to this machine's Claude subscription, for everyone who can reach this UI.</span>
2201
+ </div>
2202
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsClaudeVoice"><span class="slider"></span></label>
2203
+ </div>
2204
+ <div class="set-row" data-search="claude voice status credentials">
2205
+ <div class="set-row-text"><span class="set-row-label">Server status</span></div>
2206
+ <span class="voice-provider-status" id="voiceClaudeStatus" data-i18n-skip>&mdash;</span>
2207
+ </div>
1882
2208
  </div>
1883
2209
  </div>
1884
- <span class="form-hint" style="grid-column: 1 / -1; margin-top: -8px;">Works through Cloudflare tunnel. Requires HTTPS or localhost. iOS requires PWA (Add to Home Screen).</span>
1885
2210
 
1886
- <!-- Alerts Section -->
1887
- <div class="settings-section-header">Alerts</div>
1888
- <div class="settings-item" title="Play a short beep for critical events">
1889
- <span class="settings-item-label">Audio Alerts</span>
1890
- <label class="switch switch-sm">
1891
- <input type="checkbox" id="appSettingsNotifAudio">
1892
- <span class="slider"></span>
1893
- </label>
1894
- </div>
1895
- <div class="settings-item" title="Notify when a session is idle longer than this">
1896
- <span class="settings-item-label">Idle Threshold</span>
1897
- <div class="settings-item-actions">
1898
- <input type="number" id="appSettingsNotifStuckMins" class="settings-item-input" value="10" min="1" max="120">
1899
- <span style="font-size: 0.65rem; color: var(--text-muted);">min</span>
2211
+ <div class="set-group">
2212
+ <div class="set-group-head"><h4>Deepgram Nova-3</h4><span class="set-scope">device</span></div>
2213
+ <div class="set-group-body">
2214
+ <div class="set-row has-field" data-search="deepgram api key">
2215
+ <div class="set-row-text">
2216
+ <span class="set-row-label">API key</span>
2217
+ <span class="set-row-desc">Stored on this device only, never sent to the server. Get a key at console.deepgram.com</span>
2218
+ </div>
2219
+ <div class="set-row-actions set-row-actions-wide">
2220
+ <input type="password" id="voiceDeepgramKey" class="set-input" placeholder="Enter Deepgram API key" autocomplete="off">
2221
+ <button class="btn-toolbar btn-sm" onclick="app.toggleDeepgramKeyVisibility()" id="voiceKeyToggleBtn" type="button">Show</button>
2222
+ </div>
2223
+ </div>
1900
2224
  </div>
1901
2225
  </div>
2226
+ </section>
1902
2227
 
1903
- <!-- Notification Levels Section -->
1904
- <div class="settings-section-header">Notification Levels</div>
1905
- </div>
1906
- <div class="settings-grid settings-grid-3col">
1907
- <div class="settings-item" title="Errors, crashes, agent failures">
1908
- <span class="settings-item-label">Critical</span>
1909
- <label class="switch switch-sm">
1910
- <input type="checkbox" id="appSettingsNotifCritical" checked>
1911
- <span class="slider"></span>
1912
- </label>
2228
+ <!-- ══ Shortcuts ════════════════════════════════════════════════ -->
2229
+ <section class="set-section" id="settings-shortcuts" data-label="Shortcuts">
2230
+ <div class="set-section-head">
2231
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M6 9h.01M10 9h.01M14 9h.01M18 9h.01M6 13h.01M18 13h.01M9 13h6"/></svg>
2232
+ <h2>Shortcuts</h2>
1913
2233
  </div>
1914
- <div class="settings-item" title="Completions, budget warnings, stuck sessions">
1915
- <span class="settings-item-label">Warning</span>
1916
- <label class="switch switch-sm">
1917
- <input type="checkbox" id="appSettingsNotifWarning" checked>
1918
- <span class="slider"></span>
1919
- </label>
1920
- </div>
1921
- <div class="settings-item" title="Auto-accepts, auto-clears, agent completions">
1922
- <span class="settings-item-label">Info</span>
1923
- <label class="switch switch-sm">
1924
- <input type="checkbox" id="appSettingsNotifInfo" checked>
1925
- <span class="slider"></span>
1926
- </label>
2234
+ <p class="set-section-blurb">Click a binding to capture a new key combination.</p>
2235
+ <div class="set-group">
2236
+ <div class="set-group-head"><h4>Keyboard</h4><span class="set-scope">device</span></div>
2237
+ <div class="set-group-body">
2238
+ <div id="appSettingsShortcutsList" data-search="keyboard shortcuts bindings keys">
2239
+ <!-- Populated by app.renderShortcutSettingsList() -->
2240
+ </div>
2241
+ </div>
1927
2242
  </div>
1928
- </div>
2243
+ </section>
1929
2244
 
1930
- <!-- Event Type Preferences -->
1931
- <div class="settings-grid" style="margin-top: 12px;">
1932
- <div class="settings-section-header">Per-Event Settings</div>
1933
- </div>
1934
- <div class="event-type-grid">
1935
- <div class="event-header">Event</div>
1936
- <div class="event-header">On</div>
1937
- <div class="event-header">Browser</div>
1938
- <div class="event-header">Push</div>
1939
- <div class="event-header">Sound</div>
1940
-
1941
- <div class="event-label">Permission prompts</div>
1942
- <input type="checkbox" id="eventPermissionEnabled" checked>
1943
- <input type="checkbox" id="eventPermissionBrowser" checked>
1944
- <input type="checkbox" id="eventPermissionPush" checked>
1945
- <input type="checkbox" id="eventPermissionAudio" checked>
1946
-
1947
- <div class="event-label">Questions from Claude</div>
1948
- <input type="checkbox" id="eventQuestionEnabled" checked>
1949
- <input type="checkbox" id="eventQuestionBrowser" checked>
1950
- <input type="checkbox" id="eventQuestionPush" checked>
1951
- <input type="checkbox" id="eventQuestionAudio" checked>
1952
-
1953
- <div class="event-label">Session idle</div>
1954
- <input type="checkbox" id="eventIdleEnabled" checked>
1955
- <input type="checkbox" id="eventIdleBrowser" checked>
1956
- <input type="checkbox" id="eventIdlePush">
1957
- <input type="checkbox" id="eventIdleAudio">
1958
-
1959
- <div class="event-label">Response complete</div>
1960
- <input type="checkbox" id="eventStopEnabled">
1961
- <input type="checkbox" id="eventStopBrowser">
1962
- <input type="checkbox" id="eventStopPush">
1963
- <input type="checkbox" id="eventStopAudio">
1964
-
1965
- <div class="event-label">Respawn cycles</div>
1966
- <input type="checkbox" id="eventRespawnEnabled" checked>
1967
- <input type="checkbox" id="eventRespawnBrowser">
1968
- <input type="checkbox" id="eventRespawnPush">
1969
- <input type="checkbox" id="eventRespawnAudio">
1970
-
1971
- <div class="event-label">Task complete</div>
1972
- <input type="checkbox" id="eventRalphEnabled" checked>
1973
- <input type="checkbox" id="eventRalphBrowser" checked>
1974
- <input type="checkbox" id="eventRalphPush">
1975
- <input type="checkbox" id="eventRalphAudio" checked>
1976
-
1977
- <div class="event-label">Subagent activity</div>
1978
- <input type="checkbox" id="eventSubagentEnabled">
1979
- <input type="checkbox" id="eventSubagentBrowser">
1980
- <input type="checkbox" id="eventSubagentPush">
1981
- <input type="checkbox" id="eventSubagentAudio">
1982
- </div>
1983
- </div>
1984
-
1985
- <!-- Voice Tab -->
1986
- <div class="modal-tab-content hidden" id="settings-voice">
1987
- <div class="settings-grid">
1988
- <div class="settings-section-header">Provider</div>
1989
- <div class="settings-item">
1990
- <span class="settings-item-label">Active Provider</span>
1991
- <span class="voice-provider-status" id="voiceProviderStatus">—</span>
1992
- </div>
1993
-
1994
- <div class="settings-section-header">Behavior</div>
1995
- <div class="settings-item" style="grid-column: 1 / -1;">
1996
- <span class="settings-item-label">Insert mode</span>
1997
- <select id="voiceInsertMode" class="form-select" style="width: auto;">
1998
- <option value="direct">Direct to input</option>
1999
- <option value="compose">Compose dialog</option>
2000
- </select>
2245
+
2246
+ <!-- ══ System ═══════════════════════════════════════════════════ -->
2247
+ <section class="set-section" id="settings-system" data-label="System">
2248
+ <div class="set-section-head">
2249
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><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 1 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 1 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 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.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 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.26.6.86 1 1.51 1H21a2 2 0 0 1 0 4h-.09c-.65 0-1.25.4-1.51 1z"/></svg>
2250
+ <h2>System</h2>
2001
2251
  </div>
2252
+ <p class="set-section-blurb">Paths, automation and remote access. Set once, rarely touched.</p>
2002
2253
 
2003
- <div class="settings-section-header">Deepgram Nova-3</div>
2004
- <div class="form-row" style="grid-column: 1 / -1;">
2005
- <label for="voiceDeepgramKey">API Key</label>
2006
- <div style="display: flex; gap: 6px; align-items: center;">
2007
- <input type="password" id="voiceDeepgramKey" placeholder="Enter Deepgram API key" autocomplete="off" style="flex: 1; width: 100%; padding: 0.5rem 0.75rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.8rem; font-family: inherit;">
2008
- <button class="btn-toolbar btn-sm" onclick="app.toggleDeepgramKeyVisibility()" id="voiceKeyToggleBtn" type="button">Show</button>
2254
+ <div class="set-group">
2255
+ <div class="set-group-head"><h4>Paths</h4><span class="set-scope">synced</span></div>
2256
+ <div class="set-group-body">
2257
+ <div class="set-row has-field" data-search="claude.md template path new cases">
2258
+ <div class="set-row-text">
2259
+ <span class="set-row-label">CLAUDE.md template</span>
2260
+ <span class="set-row-desc">Used when creating new cases. Leave empty for the built-in template.</span>
2261
+ </div>
2262
+ <input type="text" id="appSettingsClaudeMdPath" class="set-input" placeholder="/path/to/CLAUDE.md template">
2263
+ </div>
2264
+ <div class="set-row has-field" data-search="default working directory">
2265
+ <div class="set-row-text">
2266
+ <span class="set-row-label">Default working directory</span>
2267
+ <span class="set-row-desc">Starting directory for new sessions.</span>
2268
+ </div>
2269
+ <input type="text" id="appSettingsDefaultDir" class="set-input" placeholder="~/projects">
2270
+ </div>
2009
2271
  </div>
2010
- <span class="form-hint">Stored locally only, never sent to server. Get a key at <a href="https://console.deepgram.com" target="_blank" rel="noopener" style="color: var(--accent);">console.deepgram.com</a></span>
2011
- </div>
2012
-
2013
- <div class="form-row" style="grid-column: 1 / -1;">
2014
- <label for="voiceLanguage">Language</label>
2015
- <select id="voiceLanguage" class="form-select">
2016
- <option value="en-US">English (US)</option>
2017
- <option value="en-GB">English (UK)</option>
2018
- <option value="es">Spanish</option>
2019
- <option value="fr">French</option>
2020
- <option value="de">German</option>
2021
- <option value="ja">Japanese</option>
2022
- <option value="multi">Auto-detect (multi)</option>
2023
- </select>
2024
2272
  </div>
2025
2273
 
2026
- <div class="form-row" style="grid-column: 1 / -1;">
2027
- <label for="voiceKeyterms">Domain Keywords</label>
2028
- <input type="text" id="voiceKeyterms" placeholder="codeman, tmux, respawn, subagent" style="width: 100%; padding: 0.5rem 0.75rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.8rem; font-family: inherit;">
2029
- <span class="form-hint">Comma-separated terms to boost recognition accuracy</span>
2274
+ <div class="set-group">
2275
+ <div class="set-group-head"><h4>Automation</h4><span class="set-scope">synced</span></div>
2276
+ <div class="set-group-body">
2277
+ <div class="set-row" data-search="image watcher popup screenshots">
2278
+ <div class="set-row-text">
2279
+ <span class="set-row-label">Image watcher</span>
2280
+ <span class="set-row-desc">Detect and pop up new images found in session directories.</span>
2281
+ </div>
2282
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsImageWatcherEnabled"><span class="slider"></span></label>
2283
+ </div>
2284
+ </div>
2030
2285
  </div>
2031
- </div>
2032
- </div>
2033
2286
 
2034
- <!-- Shortcuts tab -->
2035
- <div class="modal-tab-content hidden" id="settings-shortcuts">
2036
- <div class="settings-grid">
2037
- <div class="settings-section-header" style="grid-column: 1 / -1;">Keyboard Shortcuts</div>
2038
- <p class="form-hint" style="grid-column: 1 / -1; margin: 0 0 0.5rem;">
2039
- Customize keyboard shortcuts. Click the binding to capture a new key combination.
2040
- </p>
2041
- <div id="appSettingsShortcutsList" style="grid-column: 1 / -1;">
2042
- <!-- Populated by app.renderShortcutSettingsList() -->
2287
+ <div class="set-group">
2288
+ <div class="set-group-head"><h4>Remote access</h4><span class="set-scope">synced</span></div>
2289
+ <div class="set-group-body">
2290
+ <div class="set-row" data-search="cloudflare tunnel remote access url">
2291
+ <div class="set-row-text">
2292
+ <span class="set-row-label">Cloudflare Tunnel</span>
2293
+ <span class="set-row-desc">Expose Codeman on a public URL. Set CODEMAN_PASSWORD first.</span>
2294
+ </div>
2295
+ <label class="switch switch-sm"><input type="checkbox" id="appSettingsTunnelEnabled"><span class="slider"></span></label>
2296
+ </div>
2297
+ <div class="set-row" id="tunnelUrlRow" style="display:none">
2298
+ <div class="set-row-text"><span class="set-row-label">Tunnel URL</span></div>
2299
+ <div class="set-row-actions">
2300
+ <span id="tunnelUrlDisplay" class="set-copy" title="Click to copy"></span>
2301
+ <button class="btn-icon-sm" id="tunnelQrBtn" onclick="app.showTunnelQR()" title="Show QR code">&#x229E;</button>
2302
+ </div>
2303
+ </div>
2304
+ <div class="set-row" id="tunnelUploadUrlRow" style="display:none">
2305
+ <div class="set-row-text"><span class="set-row-label">Upload URL</span></div>
2306
+ <span id="tunnelUploadUrlDisplay" class="set-copy" title="Click to copy"></span>
2307
+ </div>
2308
+ </div>
2043
2309
  </div>
2044
- </div>
2310
+ </section>
2045
2311
  </div>
2046
2312
  </div>
2047
- <div class="form-actions">
2313
+ <div class="form-actions set-foot">
2048
2314
  <button class="btn-toolbar" onclick="app.closeAppSettings()">Cancel</button>
2049
2315
  <button class="btn-toolbar btn-primary" onclick="app.saveAppSettings()">Save</button>
2050
2316
  </div>
@@ -2069,24 +2335,56 @@
2069
2335
  </div>
2070
2336
 
2071
2337
  <!-- Create Case Modal -->
2338
+ <!-- Add Case: same `set-*` surface as App Settings and Session Options; the
2339
+ rail switches panels (switchCaseModalTab in session-ui.js). -->
2072
2340
  <div class="modal" id="createCaseModal">
2073
2341
  <div class="modal-backdrop" onclick="app.closeCreateCaseModal()"></div>
2074
- <div class="modal-content modal-lg">
2075
- <div class="modal-header">
2342
+ <div class="modal-content modal-lg set-shell">
2343
+ <div class="modal-header set-shell-head">
2076
2344
  <h3>Add Case</h3>
2077
- <button class="modal-close" onclick="app.closeCreateCaseModal()" aria-label="Close create case">&times;</button>
2078
- </div>
2079
- <div class="modal-tabs">
2080
- <button class="modal-tab-btn active" data-tab="case-create">Create New</button>
2081
- <button class="modal-tab-btn" data-tab="case-clone" id="caseCloneTabBtn">Clone Repo</button>
2082
- <button class="modal-tab-btn" data-tab="case-link">Link Existing</button>
2083
- <button class="modal-tab-btn" data-tab="case-remote">Remote</button>
2084
- <button class="modal-tab-btn" data-tab="case-docker">Docker</button>
2085
- <button class="modal-tab-btn" data-tab="case-manage">Manage</button>
2345
+ <div class="set-head-actions">
2346
+ <button class="modal-close" onclick="app.closeCreateCaseModal()" aria-label="Close create case">&times;</button>
2347
+ </div>
2086
2348
  </div>
2087
- <div class="modal-body">
2349
+ <div class="set-body">
2350
+ <nav class="set-rail" id="createCaseRail" aria-label="Add case sections">
2351
+ <div class="set-rail-items">
2352
+ <button type="button" class="set-rail-item active" data-tab="case-create">
2353
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M12 8v8M8 12h8"/></svg>
2354
+ <span>Create New</span>
2355
+ </button>
2356
+ <button type="button" class="set-rail-item" data-tab="case-clone" id="caseCloneTabBtn">
2357
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
2358
+ <span>Clone Repo</span>
2359
+ </button>
2360
+ <button type="button" class="set-rail-item" data-tab="case-link">
2361
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
2362
+ <span>Link Existing</span>
2363
+ </button>
2364
+ <button type="button" class="set-rail-item" data-tab="case-remote">
2365
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><path d="M12 3a15 15 0 0 1 0 18a15 15 0 0 1 0-18z"/></svg>
2366
+ <span>Remote</span>
2367
+ </button>
2368
+ <button type="button" class="set-rail-item" data-tab="case-docker">
2369
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h18v4a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3z"/><rect x="6" y="7" width="4" height="4"/><rect x="11" y="7" width="4" height="4"/><rect x="11" y="2.5" width="4" height="4"/></svg>
2370
+ <span>Docker</span>
2371
+ </button>
2372
+ <button type="button" class="set-rail-item" data-tab="case-manage">
2373
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/><circle cx="9" cy="6" r="2"/><circle cx="15" cy="12" r="2"/><circle cx="8" cy="18" r="2"/></svg>
2374
+ <span>Manage</span>
2375
+ </button>
2376
+ </div>
2377
+ <p class="set-rail-foot">A case is a workspace: a directory, its CLAUDE.md, and where its sessions run.</p>
2378
+ </nav>
2379
+
2380
+ <div class="set-doc" id="createCaseDoc">
2088
2381
  <!-- Create New Tab -->
2089
- <div class="modal-tab-content" id="case-create">
2382
+ <div class="set-section" id="case-create">
2383
+ <div class="set-section-head">
2384
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M12 8v8M8 12h8"/></svg>
2385
+ <h2>Create New</h2>
2386
+ </div>
2387
+ <p class="set-section-blurb">A fresh workspace under ~/codeman-cases, scaffolded with its own CLAUDE.md.</p>
2090
2388
  <div class="form-row">
2091
2389
  <label>Case Name</label>
2092
2390
  <input type="text" id="newCaseName" placeholder="my-project" pattern="[a-zA-Z0-9_-]+" autocomplete="off" autocapitalize="off" spellcheck="false">
@@ -2101,7 +2399,7 @@
2101
2399
  <span class="form-hint">Runs this case in a hardened, isolated container. The base image is built automatically on first use. Docker/Podman must be installed.</span>
2102
2400
  </div>
2103
2401
  <details class="advanced-options docker-quick-settings" id="dockerQuickSettings">
2104
- <summary>Container settings (optional, sensible defaults)</summary>
2402
+ <summary><svg class="set-adv-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg><span>Container settings (optional, sensible defaults)</span></summary>
2105
2403
  <div class="advanced-options-content">
2106
2404
  <div class="form-row">
2107
2405
  <label>Template</label>
@@ -2145,7 +2443,12 @@
2145
2443
  </details>
2146
2444
  </div>
2147
2445
  <!-- Clone Repo Tab (issue #236) -->
2148
- <div class="modal-tab-content hidden" id="case-clone">
2446
+ <div class="set-section hidden" id="case-clone">
2447
+ <div class="set-section-head">
2448
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
2449
+ <h2>Clone Repo</h2>
2450
+ </div>
2451
+ <p class="set-section-blurb">Clone a public repository into a new case. Anonymous HTTPS or your own credential helper.</p>
2149
2452
  <div class="form-row">
2150
2453
  <label>Repository URL</label>
2151
2454
  <input type="url" id="cloneRepoUrl" placeholder="https://github.com/owner/repo.git" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" oninput="app.onCloneUrlInput()">
@@ -2176,7 +2479,7 @@
2176
2479
  <span class="form-hint">Which CLI to point the Run button at once the clone finishes. Changeable any time from the Run dropdown.</span>
2177
2480
  </div>
2178
2481
  <details class="advanced-options">
2179
- <summary>Clone options</summary>
2482
+ <summary><svg class="set-adv-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg><span>Clone options</span></summary>
2180
2483
  <div class="advanced-options-content">
2181
2484
  <div class="form-row">
2182
2485
  <label class="checkbox-row"><input type="checkbox" id="cloneShallow"> Shallow clone (--depth 1)</label>
@@ -2190,7 +2493,12 @@
2190
2493
  <span class="form-hint" id="cloneCaseNote" style="margin-top: 8px; display: block;">The clone runs while this request is open, so a large repository takes a while. The case appears as soon as git finishes, even if the browser gave up waiting.</span>
2191
2494
  </div>
2192
2495
  <!-- Link Existing Tab -->
2193
- <div class="modal-tab-content hidden" id="case-link">
2496
+ <div class="set-section hidden" id="case-link">
2497
+ <div class="set-section-head">
2498
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
2499
+ <h2>Link Existing</h2>
2500
+ </div>
2501
+ <p class="set-section-blurb">Point a case at a folder that already exists on this machine.</p>
2194
2502
  <div class="form-row">
2195
2503
  <label>Case Name</label>
2196
2504
  <input type="text" id="linkCaseName" placeholder="my-project" pattern="[a-zA-Z0-9_-]+" autocomplete="off" autocapitalize="off" spellcheck="false">
@@ -2206,7 +2514,12 @@
2206
2514
  </div>
2207
2515
  </div>
2208
2516
  <!-- Remote Tab -->
2209
- <div class="modal-tab-content hidden" id="case-remote">
2517
+ <div class="set-section hidden" id="case-remote">
2518
+ <div class="set-section-head">
2519
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><path d="M12 3a15 15 0 0 1 0 18a15 15 0 0 1 0-18z"/></svg>
2520
+ <h2>Remote</h2>
2521
+ </div>
2522
+ <p class="set-section-blurb">Run the agent on another machine over SSH, from a tab here.</p>
2210
2523
  <div class="form-row">
2211
2524
  <label>Case Name</label>
2212
2525
  <input type="text" id="remoteCaseName" placeholder="gpu-work" pattern="[a-zA-Z0-9_-]+" autocomplete="off" autocapitalize="off" spellcheck="false">
@@ -2240,7 +2553,7 @@
2240
2553
  <span class="form-hint">Optional. Leave blank to use exec codex on the remote host.</span>
2241
2554
  </div>
2242
2555
  <details class="advanced-options">
2243
- <summary>Advanced SSH</summary>
2556
+ <summary><svg class="set-adv-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg><span>Advanced SSH</span></summary>
2244
2557
  <div class="advanced-options-content">
2245
2558
  <div class="form-row">
2246
2559
  <label>Identity File</label>
@@ -2266,7 +2579,7 @@
2266
2579
  </details>
2267
2580
  <!-- COD-105 — discover + attach existing remote tmux sessions this Codeman didn't create. -->
2268
2581
  <details class="advanced-options" id="remoteDiscoverSection">
2269
- <summary>Discover existing sessions</summary>
2582
+ <summary><svg class="set-adv-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg><span>Discover existing sessions</span></summary>
2270
2583
  <div class="advanced-options-content">
2271
2584
  <span class="form-hint">Find <code>codeman-*</code> tmux sessions already running on this host (started by the remote's own Codeman or another instance) and attach to one. Attaching shares the session; closing the tab detaches it — it is never killed.</span>
2272
2585
  <div class="form-row" style="margin-top: 8px;">
@@ -2277,7 +2590,12 @@
2277
2590
  </details>
2278
2591
  </div>
2279
2592
  <!-- Docker Tab -->
2280
- <div class="modal-tab-content hidden" id="case-docker">
2593
+ <div class="set-section hidden" id="case-docker">
2594
+ <div class="set-section-head">
2595
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h18v4a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3z"/><rect x="6" y="7" width="4" height="4"/><rect x="11" y="7" width="4" height="4"/><rect x="11" y="2.5" width="4" height="4"/></svg>
2596
+ <h2>Docker</h2>
2597
+ </div>
2598
+ <p class="set-section-blurb">Run the case inside a container: one per case, shared by all its sessions.</p>
2281
2599
  <div class="form-row">
2282
2600
  <label>Case Name</label>
2283
2601
  <input type="text" id="dockerCaseName" placeholder="sandbox" pattern="[a-zA-Z0-9_-]+" autocomplete="off" autocapitalize="off" spellcheck="false">
@@ -2307,7 +2625,7 @@
2307
2625
  </select>
2308
2626
  </div>
2309
2627
  <details class="advanced-options">
2310
- <summary>Advanced container settings</summary>
2628
+ <summary><svg class="set-adv-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg><span>Advanced container settings</span></summary>
2311
2629
  <div class="advanced-options-content">
2312
2630
  <div class="form-row">
2313
2631
  <label>Memory</label>
@@ -2330,7 +2648,12 @@
2330
2648
  <span class="form-hint" id="dockerLinkStatus" style="margin-top: 8px; display: block;"></span>
2331
2649
  </div>
2332
2650
  <!-- Manage Tab -->
2333
- <div class="modal-tab-content hidden" id="case-manage">
2651
+ <div class="set-section hidden" id="case-manage">
2652
+ <div class="set-section-head">
2653
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/><circle cx="9" cy="6" r="2"/><circle cx="15" cy="12" r="2"/><circle cx="8" cy="18" r="2"/></svg>
2654
+ <h2>Manage</h2>
2655
+ </div>
2656
+ <p class="set-section-blurb">Reorder or remove cases, and pick up anything exported from a docker case.</p>
2334
2657
  <div class="case-manage-list" id="caseManageList">
2335
2658
  <!-- Populated by JS -->
2336
2659
  </div>
@@ -2343,8 +2666,9 @@
2343
2666
  <div class="case-manage-list" id="dockerExportsList"><span class="form-hint">No exports yet. Export a docker case from its tab.</span></div>
2344
2667
  </div>
2345
2668
  </div>
2669
+ </div>
2346
2670
  </div>
2347
- <div class="form-actions">
2671
+ <div class="form-actions set-foot">
2348
2672
  <button class="btn-toolbar" onclick="app.closeCreateCaseModal()">Cancel</button>
2349
2673
  <button class="btn-toolbar btn-primary" id="caseModalSubmit" onclick="app.submitCaseModal()">Create</button>
2350
2674
  </div>
@@ -2813,14 +3137,25 @@
2813
3137
  <input type="text" id="readMyMindPrompt" class="readmymind-prompt-input" data-i18n-skip aria-label="Predicted prompt, editable" onkeydown="if(event.key==='Enter')app.sendReadMyMind(true)">
2814
3138
  </div>
2815
3139
  <div class="readmymind-why" id="readMyMindWhy" data-i18n-skip></div>
3140
+ <div class="readmymind-alternates" id="readMyMindAlternates" data-i18n-skip style="display:none"></div>
3141
+ </div>
3142
+ <div class="readmymind-error" style="display:none">No suggestion this time. Add a steer note and Rethink to try again.</div>
3143
+ <!-- Rethink steer note: the user's own words about what they actually
3144
+ meant, sent as `steer` with the next Rethink. Shown whenever
3145
+ Rethink is live (ready AND empty-result phases), hidden while a
3146
+ prediction runs. -->
3147
+ <div class="readmymind-steer-row" id="readMyMindSteerRow" style="display:none">
3148
+ <input type="text" id="readMyMindSteer" class="readmymind-steer-input" maxlength="2000" placeholder="Steer the rethink, e.g. 'no, I meant the mobile bug'" aria-label="Steer note for Rethink" onkeydown="if(event.key==='Enter')app.rethinkReadMyMind()">
2816
3149
  </div>
2817
- <div class="readmymind-error" style="display:none">No suggestion this time. Rethink to try again.</div>
2818
3150
  </div>
3151
+ <!-- btn-toolbar, not bare "btn btn-*": no .btn/.btn-secondary rule exists
3152
+ in this codebase, so the bare classes render as unstyled UA buttons.
3153
+ btn-toolbar is the convention every other modal footer uses. -->
2819
3154
  <div class="modal-footer">
2820
- <button class="btn btn-secondary" onclick="app.closeReadMyMind()">Dismiss</button>
2821
- <button class="btn btn-secondary" id="readMyMindRethink" onclick="app.rethinkReadMyMind()">Rethink</button>
2822
- <button class="btn btn-secondary" onclick="app.sendReadMyMind(false)" title="Put the text on the session's composer without submitting it">Insert</button>
2823
- <button class="btn btn-primary" onclick="app.sendReadMyMind(true)">Send</button>
3155
+ <button class="btn-toolbar" onclick="app.closeReadMyMind()">Dismiss</button>
3156
+ <button class="btn-toolbar" id="readMyMindRethink" onclick="app.rethinkReadMyMind()">Rethink</button>
3157
+ <button class="btn-toolbar" onclick="app.sendReadMyMind(false)" title="Put the text on the session's composer without submitting it">Insert</button>
3158
+ <button class="btn-toolbar btn-primary" onclick="app.sendReadMyMind(true)">Send</button>
2824
3159
  </div>
2825
3160
  </div>
2826
3161
  </div>
@@ -2836,28 +3171,28 @@
2836
3171
  <div class="approvals-list"></div>
2837
3172
  </div>
2838
3173
 
2839
- <script defer src="constants.7d0f4047.js"></script>
2840
- <script defer src="i18n.ef50083f.js"></script>
3174
+ <script defer src="constants.53dc0fa1.js"></script>
3175
+ <script defer src="i18n.89097ff5.js"></script>
2841
3176
  <script defer src="mobile-handlers.32fdd57f.js"></script>
2842
- <script defer src="voice-input.e5461859.js"></script>
3177
+ <script defer src="voice-input.4ec670b0.js"></script>
2843
3178
  <script defer src="notification-manager.5d229063.js"></script>
2844
- <script defer src="keyboard-accessory.1f35b482.js"></script>
3179
+ <script defer src="keyboard-accessory.0f524637.js"></script>
2845
3180
  <script defer src="input-cjk.63794d0b.js"></script>
2846
3181
  <!-- Hardened markdown HTML sanitizer (wires DOMPurify). Must precede app.js. -->
2847
3182
  <script defer src="sanitize-html.bc7078d6.js"></script>
2848
- <script defer src="app.4d006245.js"></script>
2849
- <script defer src="terminal-ui.e7c5d233.js"></script>
3183
+ <script defer src="app.f9c6aadd.js"></script>
3184
+ <script defer src="terminal-ui.ae776405.js"></script>
2850
3185
  <script defer src="respawn-ui.ff0dae4c.js"></script>
2851
3186
  <script defer src="ralph-panel.6de2d0f8.js"></script>
2852
3187
  <script defer src="orchestrator-panel.js"></script>
2853
3188
  <script defer src="cron-ui.js"></script>
2854
- <script defer src="settings-ui.1c15649c.js"></script>
2855
- <script defer src="panels-ui.3df9cd95.js"></script>
3189
+ <script defer src="settings-ui.63be4178.js"></script>
3190
+ <script defer src="panels-ui.54b0d004.js"></script>
2856
3191
  <script defer src="readmymind-ui.js"></script>
2857
3192
  <script defer src="ultracode-panel.js"></script>
2858
3193
  <script defer src="approvals-ui.js"></script>
2859
3194
  <script defer src="admin-ui.js"></script>
2860
- <script defer src="session-ui.f4fed187.js"></script>
3195
+ <script defer src="session-ui.46a0993c.js"></script>
2861
3196
  <script defer src="webview-tabs.js"></script>
2862
3197
  <script defer src="mobile-overview.js"></script>
2863
3198
  <script defer src="home-sessions.js"></script>