aicodeman 1.41.0 → 1.42.0

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 (339) hide show
  1. package/README.md +101 -21
  2. package/dist/attachment-registry.d.ts +2 -0
  3. package/dist/attachment-registry.d.ts.map +1 -1
  4. package/dist/attachment-registry.js +14 -3
  5. package/dist/attachment-registry.js.map +1 -1
  6. package/dist/cli-agent.d.ts +2 -0
  7. package/dist/cli-agent.d.ts.map +1 -1
  8. package/dist/cli-agent.js +13 -9
  9. package/dist/cli-agent.js.map +1 -1
  10. package/dist/cli.d.ts +25 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +97 -11
  13. package/dist/cli.js.map +1 -1
  14. package/dist/config/buffer-limits.d.ts +9 -0
  15. package/dist/config/buffer-limits.d.ts.map +1 -1
  16. package/dist/config/buffer-limits.js +9 -0
  17. package/dist/config/buffer-limits.js.map +1 -1
  18. package/dist/config/cli-registry/schema.d.ts +10 -0
  19. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  20. package/dist/config/cli-registry/schema.js +26 -0
  21. package/dist/config/cli-registry/schema.js.map +1 -1
  22. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  23. package/dist/config/cli-registry/stock.js +89 -6
  24. package/dist/config/cli-registry/stock.js.map +1 -1
  25. package/dist/config/cli-registry/types.d.ts +61 -0
  26. package/dist/config/cli-registry/types.d.ts.map +1 -1
  27. package/dist/folder-listing.d.ts +94 -0
  28. package/dist/folder-listing.d.ts.map +1 -0
  29. package/dist/folder-listing.js +241 -0
  30. package/dist/folder-listing.js.map +1 -0
  31. package/dist/git-worktrees.d.ts +292 -0
  32. package/dist/git-worktrees.d.ts.map +1 -0
  33. package/dist/git-worktrees.js +791 -0
  34. package/dist/git-worktrees.js.map +1 -0
  35. package/dist/hooks-config.d.ts +36 -16
  36. package/dist/hooks-config.d.ts.map +1 -1
  37. package/dist/hooks-config.js +45 -20
  38. package/dist/hooks-config.js.map +1 -1
  39. package/dist/html-view-capabilities.d.ts +54 -0
  40. package/dist/html-view-capabilities.d.ts.map +1 -0
  41. package/dist/html-view-capabilities.js +103 -0
  42. package/dist/html-view-capabilities.js.map +1 -0
  43. package/dist/mcp-server.d.ts +114 -0
  44. package/dist/mcp-server.d.ts.map +1 -0
  45. package/dist/mcp-server.js +918 -0
  46. package/dist/mcp-server.js.map +1 -0
  47. package/dist/mcp-sync.d.ts +5 -0
  48. package/dist/mcp-sync.d.ts.map +1 -1
  49. package/dist/mcp-sync.js +51 -5
  50. package/dist/mcp-sync.js.map +1 -1
  51. package/dist/mux-interface.d.ts +36 -1
  52. package/dist/mux-interface.d.ts.map +1 -1
  53. package/dist/remote-files.d.ts +37 -0
  54. package/dist/remote-files.d.ts.map +1 -1
  55. package/dist/remote-files.js +103 -0
  56. package/dist/remote-files.js.map +1 -1
  57. package/dist/remote-pane-history.d.ts +103 -0
  58. package/dist/remote-pane-history.d.ts.map +1 -0
  59. package/dist/remote-pane-history.js +258 -0
  60. package/dist/remote-pane-history.js.map +1 -0
  61. package/dist/remote-ssh-limiter.d.ts +16 -3
  62. package/dist/remote-ssh-limiter.d.ts.map +1 -1
  63. package/dist/remote-ssh-limiter.js +37 -6
  64. package/dist/remote-ssh-limiter.js.map +1 -1
  65. package/dist/services/unified-session-service.d.ts +8 -0
  66. package/dist/services/unified-session-service.d.ts.map +1 -1
  67. package/dist/services/unified-session-service.js +21 -0
  68. package/dist/services/unified-session-service.js.map +1 -1
  69. package/dist/session-activity.d.ts +51 -0
  70. package/dist/session-activity.d.ts.map +1 -1
  71. package/dist/session-activity.js +62 -0
  72. package/dist/session-activity.js.map +1 -1
  73. package/dist/session-submit-verifier.js +1 -1
  74. package/dist/session.d.ts +90 -2
  75. package/dist/session.d.ts.map +1 -1
  76. package/dist/session.js +247 -9
  77. package/dist/session.js.map +1 -1
  78. package/dist/tab-layout-legacy-order.d.ts.map +1 -1
  79. package/dist/tab-layout-legacy-order.js +72 -13
  80. package/dist/tab-layout-legacy-order.js.map +1 -1
  81. package/dist/tab-layout-service.d.ts +33 -2
  82. package/dist/tab-layout-service.d.ts.map +1 -1
  83. package/dist/tab-layout-service.js +102 -7
  84. package/dist/tab-layout-service.js.map +1 -1
  85. package/dist/tab-layout.d.ts +9 -0
  86. package/dist/tab-layout.d.ts.map +1 -1
  87. package/dist/tab-layout.js +15 -2
  88. package/dist/tab-layout.js.map +1 -1
  89. package/dist/tmux-manager.d.ts +130 -7
  90. package/dist/tmux-manager.d.ts.map +1 -1
  91. package/dist/tmux-manager.js +263 -36
  92. package/dist/tmux-manager.js.map +1 -1
  93. package/dist/types/session.d.ts +53 -0
  94. package/dist/types/session.d.ts.map +1 -1
  95. package/dist/types/session.js.map +1 -1
  96. package/dist/usage-telemetry.d.ts +44 -7
  97. package/dist/usage-telemetry.d.ts.map +1 -1
  98. package/dist/usage-telemetry.js +72 -7
  99. package/dist/usage-telemetry.js.map +1 -1
  100. package/dist/utils/deepseek-cli-resolver.d.ts.map +1 -1
  101. package/dist/utils/deepseek-cli-resolver.js +1 -1
  102. package/dist/utils/deepseek-cli-resolver.js.map +1 -1
  103. package/dist/web/approval-inbox.d.ts +24 -2
  104. package/dist/web/approval-inbox.d.ts.map +1 -1
  105. package/dist/web/approval-inbox.js +8 -2
  106. package/dist/web/approval-inbox.js.map +1 -1
  107. package/dist/web/middleware/auth.d.ts.map +1 -1
  108. package/dist/web/middleware/auth.js +33 -0
  109. package/dist/web/middleware/auth.js.map +1 -1
  110. package/dist/web/ports/session-port.d.ts +8 -1
  111. package/dist/web/ports/session-port.d.ts.map +1 -1
  112. package/dist/web/public/admin-ui.js.gz +0 -0
  113. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  114. package/dist/web/public/app.f04bb2a5.js +43 -0
  115. package/dist/web/public/app.f04bb2a5.js.br +0 -0
  116. package/dist/web/public/app.f04bb2a5.js.gz +0 -0
  117. package/dist/web/public/approvals-ui.js +4 -0
  118. package/dist/web/public/approvals-ui.js.br +0 -0
  119. package/dist/web/public/approvals-ui.js.gz +0 -0
  120. package/dist/web/public/{constants.bc9c1f63.js → constants.12b0c247.js} +395 -7
  121. package/dist/web/public/constants.12b0c247.js.br +0 -0
  122. package/dist/web/public/constants.12b0c247.js.gz +0 -0
  123. package/dist/web/public/cron-ui.js.gz +0 -0
  124. package/dist/web/public/entrance-animations.js.gz +0 -0
  125. package/dist/web/public/gesture/gesture-codeman.js +112 -6
  126. package/dist/web/public/git-status-ui.js.gz +0 -0
  127. package/dist/web/public/home-sessions.js.gz +0 -0
  128. package/dist/web/public/host-wake-ui.js.gz +0 -0
  129. package/dist/web/public/i18n.06659676.js +2 -0
  130. package/dist/web/public/i18n.06659676.js.br +0 -0
  131. package/dist/web/public/i18n.06659676.js.gz +0 -0
  132. package/dist/web/public/image-input.fcdcb46c.js +462 -0
  133. package/dist/web/public/image-input.fcdcb46c.js.br +0 -0
  134. package/dist/web/public/image-input.fcdcb46c.js.gz +0 -0
  135. package/dist/web/public/index.html +169 -24
  136. package/dist/web/public/index.html.br +0 -0
  137. package/dist/web/public/index.html.gz +0 -0
  138. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  139. package/dist/web/public/{keyboard-accessory.c1e7c7b7.js → keyboard-accessory.b42f539b.js} +124 -44
  140. package/dist/web/public/keyboard-accessory.b42f539b.js.br +0 -0
  141. package/dist/web/public/keyboard-accessory.b42f539b.js.gz +0 -0
  142. package/dist/web/public/mobile-handlers.0ef9c311.js.gz +0 -0
  143. package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
  144. package/dist/web/public/mobile-overview.js +11 -2
  145. package/dist/web/public/mobile-overview.js.br +0 -0
  146. package/dist/web/public/mobile-overview.js.gz +0 -0
  147. package/dist/web/public/mobile.2dff1580.css +1 -0
  148. package/dist/web/public/mobile.2dff1580.css.br +0 -0
  149. package/dist/web/public/mobile.2dff1580.css.gz +0 -0
  150. package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
  151. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  152. package/dist/web/public/{panels-ui.71846fcb.js → panels-ui.73ec0137.js} +87 -87
  153. package/dist/web/public/panels-ui.73ec0137.js.br +0 -0
  154. package/dist/web/public/panels-ui.73ec0137.js.gz +0 -0
  155. package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
  156. package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
  157. package/dist/web/public/readmymind-ui.js.gz +0 -0
  158. package/dist/web/public/reboot-restore-ui.js.gz +0 -0
  159. package/dist/web/public/{respawn-ui.ff0dae4c.js → respawn-ui.d7adcf6a.js} +1 -1
  160. package/dist/web/public/respawn-ui.d7adcf6a.js.br +0 -0
  161. package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
  162. package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
  163. package/dist/web/public/session-lineage.js.gz +0 -0
  164. package/dist/web/public/session-ui.d52ff6aa.js +100 -0
  165. package/dist/web/public/session-ui.d52ff6aa.js.br +0 -0
  166. package/dist/web/public/session-ui.d52ff6aa.js.gz +0 -0
  167. package/dist/web/public/settings-ui.3a22bd2a.js +97 -0
  168. package/dist/web/public/settings-ui.3a22bd2a.js.br +0 -0
  169. package/dist/web/public/settings-ui.3a22bd2a.js.gz +0 -0
  170. package/dist/web/public/spreadsheet-preview-worker.js +11 -0
  171. package/dist/web/public/spreadsheet-preview-worker.js.br +0 -0
  172. package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
  173. package/dist/web/public/{spreadsheet-preview.af82fa2f.js → spreadsheet-preview.75c751de.js} +1 -1
  174. package/dist/web/public/spreadsheet-preview.75c751de.js.br +0 -0
  175. package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
  176. package/dist/web/public/spreadsheet-xlsx-core.js +110 -0
  177. package/dist/web/public/spreadsheet-xlsx-core.js.br +0 -0
  178. package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
  179. package/dist/web/public/styles.ba6a9b84.css +1 -0
  180. package/dist/web/public/styles.ba6a9b84.css.br +0 -0
  181. package/dist/web/public/styles.ba6a9b84.css.gz +0 -0
  182. package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
  183. package/dist/web/public/sw.js +6 -2
  184. package/dist/web/public/sw.js.br +0 -0
  185. package/dist/web/public/sw.js.gz +0 -0
  186. package/dist/web/public/tab-layout-browser.2d6189f7.js +1 -0
  187. package/dist/web/public/tab-layout-browser.2d6189f7.js.br +0 -0
  188. package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
  189. package/dist/web/public/{tab-rail-resize.a5867793.js → tab-rail-resize.7157e0bd.js} +1 -1
  190. package/dist/web/public/tab-rail-resize.7157e0bd.js.br +0 -0
  191. package/dist/web/public/tab-rail-resize.7157e0bd.js.gz +0 -0
  192. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
  193. package/dist/web/public/terminal-split.js.gz +0 -0
  194. package/dist/web/public/terminal-tile.js +45 -24
  195. package/dist/web/public/terminal-tile.js.br +0 -0
  196. package/dist/web/public/terminal-tile.js.gz +0 -0
  197. package/dist/web/public/terminal-ui.0a7ccc29.js +2 -0
  198. package/dist/web/public/terminal-ui.0a7ccc29.js.br +0 -0
  199. package/dist/web/public/terminal-ui.0a7ccc29.js.gz +0 -0
  200. package/dist/web/public/tile-grid.js +439 -18
  201. package/dist/web/public/tile-grid.js.br +0 -0
  202. package/dist/web/public/tile-grid.js.gz +0 -0
  203. package/dist/web/public/ultracode-panel.js.gz +0 -0
  204. package/dist/web/public/ultracode-windows.js.gz +0 -0
  205. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  206. package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
  207. package/dist/web/public/vendor/fflate.min.js.gz +0 -0
  208. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  209. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  210. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  211. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  212. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  213. package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
  214. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.gz +0 -0
  215. package/dist/web/public/vendor/xterm.css.gz +0 -0
  216. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  217. package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
  218. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  219. package/dist/web/public/webview-tabs.js +12 -0
  220. package/dist/web/public/webview-tabs.js.br +0 -0
  221. package/dist/web/public/webview-tabs.js.gz +0 -0
  222. package/dist/web/public/whats-new.json +13 -0
  223. package/dist/web/route-helpers.d.ts +8 -0
  224. package/dist/web/route-helpers.d.ts.map +1 -1
  225. package/dist/web/route-helpers.js +8 -0
  226. package/dist/web/route-helpers.js.map +1 -1
  227. package/dist/web/routes/admin-routes.d.ts.map +1 -1
  228. package/dist/web/routes/admin-routes.js +4 -1
  229. package/dist/web/routes/admin-routes.js.map +1 -1
  230. package/dist/web/routes/approval-routes.d.ts.map +1 -1
  231. package/dist/web/routes/approval-routes.js +12 -10
  232. package/dist/web/routes/approval-routes.js.map +1 -1
  233. package/dist/web/routes/case-routes.d.ts.map +1 -1
  234. package/dist/web/routes/case-routes.js +10 -3
  235. package/dist/web/routes/case-routes.js.map +1 -1
  236. package/dist/web/routes/file-routes.d.ts +46 -1
  237. package/dist/web/routes/file-routes.d.ts.map +1 -1
  238. package/dist/web/routes/file-routes.js +214 -27
  239. package/dist/web/routes/file-routes.js.map +1 -1
  240. package/dist/web/routes/hook-event-routes.d.ts.map +1 -1
  241. package/dist/web/routes/hook-event-routes.js +8 -1
  242. package/dist/web/routes/hook-event-routes.js.map +1 -1
  243. package/dist/web/routes/html-view-routes.d.ts +60 -0
  244. package/dist/web/routes/html-view-routes.d.ts.map +1 -0
  245. package/dist/web/routes/html-view-routes.js +288 -0
  246. package/dist/web/routes/html-view-routes.js.map +1 -0
  247. package/dist/web/routes/index.d.ts +2 -0
  248. package/dist/web/routes/index.d.ts.map +1 -1
  249. package/dist/web/routes/index.js +2 -0
  250. package/dist/web/routes/index.js.map +1 -1
  251. package/dist/web/routes/ralph-routes.d.ts.map +1 -1
  252. package/dist/web/routes/ralph-routes.js +19 -14
  253. package/dist/web/routes/ralph-routes.js.map +1 -1
  254. package/dist/web/routes/reboot-restore-routes.js +2 -2
  255. package/dist/web/routes/reboot-restore-routes.js.map +1 -1
  256. package/dist/web/routes/session-routes.d.ts +8 -5
  257. package/dist/web/routes/session-routes.d.ts.map +1 -1
  258. package/dist/web/routes/session-routes.js +462 -109
  259. package/dist/web/routes/session-routes.js.map +1 -1
  260. package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -1
  261. package/dist/web/routes/status-telemetry-routes.js +24 -6
  262. package/dist/web/routes/status-telemetry-routes.js.map +1 -1
  263. package/dist/web/routes/system-routes.d.ts +9 -0
  264. package/dist/web/routes/system-routes.d.ts.map +1 -1
  265. package/dist/web/routes/system-routes.js +91 -12
  266. package/dist/web/routes/system-routes.js.map +1 -1
  267. package/dist/web/routes/worktree-routes.d.ts +52 -0
  268. package/dist/web/routes/worktree-routes.d.ts.map +1 -0
  269. package/dist/web/routes/worktree-routes.js +220 -0
  270. package/dist/web/routes/worktree-routes.js.map +1 -0
  271. package/dist/web/schemas.d.ts +45 -0
  272. package/dist/web/schemas.d.ts.map +1 -1
  273. package/dist/web/schemas.js +105 -0
  274. package/dist/web/schemas.js.map +1 -1
  275. package/dist/web/screen-blocked.d.ts +80 -0
  276. package/dist/web/screen-blocked.d.ts.map +1 -0
  277. package/dist/web/screen-blocked.js +106 -0
  278. package/dist/web/screen-blocked.js.map +1 -0
  279. package/dist/web/server.d.ts +6 -1
  280. package/dist/web/server.d.ts.map +1 -1
  281. package/dist/web/server.js +73 -14
  282. package/dist/web/server.js.map +1 -1
  283. package/dist/web/session-listener-wiring.d.ts +1 -0
  284. package/dist/web/session-listener-wiring.d.ts.map +1 -1
  285. package/dist/web/session-listener-wiring.js +20 -0
  286. package/dist/web/session-listener-wiring.js.map +1 -1
  287. package/dist/web/session-wait-registry.d.ts +27 -9
  288. package/dist/web/session-wait-registry.d.ts.map +1 -1
  289. package/dist/web/session-wait-registry.js +36 -13
  290. package/dist/web/session-wait-registry.js.map +1 -1
  291. package/dist/web/sse-events.d.ts +12 -4
  292. package/dist/web/sse-events.d.ts.map +1 -1
  293. package/dist/web/sse-events.js +12 -4
  294. package/dist/web/sse-events.js.map +1 -1
  295. package/package.json +3 -2
  296. package/skills/codeman/SKILL.md +47 -27
  297. package/skills/codeman/preamble.sh +14 -11
  298. package/skills/codeman/reference/endpoints.md +1 -1
  299. package/skills/codeman/reference/recipes.md +12 -9
  300. package/skills/codeman/reference/verbs.md +3 -1
  301. package/dist/web/public/app.6f8552e1.js +0 -43
  302. package/dist/web/public/app.6f8552e1.js.br +0 -0
  303. package/dist/web/public/app.6f8552e1.js.gz +0 -0
  304. package/dist/web/public/constants.bc9c1f63.js.br +0 -0
  305. package/dist/web/public/constants.bc9c1f63.js.gz +0 -0
  306. package/dist/web/public/i18n.a9840ea2.js +0 -2
  307. package/dist/web/public/i18n.a9840ea2.js.br +0 -0
  308. package/dist/web/public/i18n.a9840ea2.js.gz +0 -0
  309. package/dist/web/public/image-input.e00471c6.js +0 -283
  310. package/dist/web/public/image-input.e00471c6.js.br +0 -0
  311. package/dist/web/public/image-input.e00471c6.js.gz +0 -0
  312. package/dist/web/public/keyboard-accessory.c1e7c7b7.js.br +0 -0
  313. package/dist/web/public/keyboard-accessory.c1e7c7b7.js.gz +0 -0
  314. package/dist/web/public/mobile.111b187d.css +0 -1
  315. package/dist/web/public/mobile.111b187d.css.br +0 -0
  316. package/dist/web/public/mobile.111b187d.css.gz +0 -0
  317. package/dist/web/public/panels-ui.71846fcb.js.br +0 -0
  318. package/dist/web/public/panels-ui.71846fcb.js.gz +0 -0
  319. package/dist/web/public/respawn-ui.ff0dae4c.js.br +0 -0
  320. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  321. package/dist/web/public/session-ui.f731602c.js +0 -100
  322. package/dist/web/public/session-ui.f731602c.js.br +0 -0
  323. package/dist/web/public/session-ui.f731602c.js.gz +0 -0
  324. package/dist/web/public/settings-ui.4e33390f.js +0 -97
  325. package/dist/web/public/settings-ui.4e33390f.js.br +0 -0
  326. package/dist/web/public/settings-ui.4e33390f.js.gz +0 -0
  327. package/dist/web/public/spreadsheet-preview.af82fa2f.js.br +0 -0
  328. package/dist/web/public/spreadsheet-preview.af82fa2f.js.gz +0 -0
  329. package/dist/web/public/styles.81a72906.css +0 -1
  330. package/dist/web/public/styles.81a72906.css.br +0 -0
  331. package/dist/web/public/styles.81a72906.css.gz +0 -0
  332. package/dist/web/public/tab-layout-browser.065fcba4.js +0 -1
  333. package/dist/web/public/tab-layout-browser.065fcba4.js.br +0 -0
  334. package/dist/web/public/tab-layout-browser.065fcba4.js.gz +0 -0
  335. package/dist/web/public/tab-rail-resize.a5867793.js.br +0 -0
  336. package/dist/web/public/tab-rail-resize.a5867793.js.gz +0 -0
  337. package/dist/web/public/terminal-ui.b7267005.js +0 -2
  338. package/dist/web/public/terminal-ui.b7267005.js.br +0 -0
  339. package/dist/web/public/terminal-ui.b7267005.js.gz +0 -0
@@ -1 +0,0 @@
1
- html.mobile-init .header-font-controls,html.mobile-init .header-system-stats,html.mobile-init .header-tokens,html.mobile-init .monitor-panel,html.mobile-init .subagents-panel,html.mobile-init .project-insights-panel,html.mobile-init .file-browser-panel{display:none!important}@media(max-width:768px){input,textarea,select{font-size:16px!important}html{touch-action:manipulation}html:not(.host-windows) .session-tab .tab-detach{display:none!important}}@media(max-width:768px)and (min-width:600px){.header{position:fixed;top:0;left:0;right:0;min-height:48px;max-height:48px;padding:.35rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));background:#0a0a0a;border-bottom:1px solid rgba(255,255,255,.08);contain:none;overflow:visible;z-index:1200}.ios-device .header{padding-top:calc(.35rem + var(--safe-area-top));min-height:calc(48px + var(--safe-area-top));max-height:calc(48px + var(--safe-area-top))}.app{padding-top:54px}.ios-device .app{padding-top:calc(54px + var(--safe-area-top))}.header-font-controls{gap:.15rem;padding:.15rem .25rem}.header-font-controls .btn-icon-sm{width:18px;height:18px}.header-system-stats{font-size:.6rem;gap:.25rem}.header-right{gap:.35rem}.btn-icon-header:not(.btn-sm){width:44px;height:44px}.session-tabs,.session-tabs.tabs-two-rows{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scrollbar-width:none;max-height:52px;gap:3px}.session-tabs::-webkit-scrollbar{display:none}.session-tab{padding:.4rem .6rem;font-size:.75rem;min-height:40px}.session-tab .tab-name{max-width:80px}.toolbar{padding:.4rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));gap:.4rem}.tab-count-group{display:none}.btn-toolbar{padding:.4rem .8rem;font-size:.8rem;min-height:40px}.case-select-group{max-width:none}.case-combobox{width:160px}.toolbar-select{font-size:.75rem}.monitor-panel,.subagents-panel{width:100%;max-width:100%;left:0;right:0;border-radius:8px 8px 0 0;max-height:40vh}.project-insights-panel{max-width:280px;font-size:.7rem}.modal{z-index:1300}.command-palette-modal{padding:10vh .75rem 0}.command-palette-shell{width:100%;max-height:74vh}.command-palette-input-row{grid-template-columns:20px minmax(0,1fr)}.command-palette-input-row kbd{display:none}.command-palette-item{min-height:56px}.settings-grid{gap:.4rem .75rem}.settings-item{font-size:.7rem}.event-type-grid{grid-template-columns:1fr 40px 40px 40px;gap:5px 6px}.event-label{font-size:.7rem}.subagent-window{width:320px;height:280px;min-width:240px;min-height:160px}.subagent-window-header{padding:.35rem .5rem}.subagent-window-title .id{font-size:.7rem;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.subagent-window-title .status{font-size:.55rem}.subagent-window-body{font-size:.7rem}.respawn-banner{padding:.25rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));font-size:.65rem}.respawn-compact-layout{gap:.75rem}.respawn-status-row1{gap:.4rem}.respawn-action-log{max-height:2.6em;font-size:.6rem}.respawn-countdown-timer{font-size:.55rem}.respawn-timer-bar{width:24px}.toolbar-center .btn-toolbar.btn-voice{display:flex!important}.toolbar{padding:0 .5rem;gap:.5rem}.toolbar-left,.toolbar-right,.toolbar-group{gap:.5rem}.btn-toolbar{padding:.4rem .75rem;font-size:.75rem;min-height:unset}}@media(min-width:600px)and (max-width:767px){:where(.header) .session-tabs-host>.session-tabs.tabs-clusters>.tab-cluster{display:contents}:where(.header) .tab-cluster-label{display:none}:where(.header) .session-tabs-host>.session-tabs.tabs-clusters .tab-name-case{display:inline}}@property --tab-strip-fade-start{syntax: "<length>"; inherits: false; initial-value: 0px;}@property --tab-strip-fade-end{syntax: "<length>"; inherits: false; initial-value: 0px;}@keyframes tab-strip-edge-fade{0%{--tab-strip-fade-start: 0px;--tab-strip-fade-end: 28px}10%,90%{--tab-strip-fade-start: 28px;--tab-strip-fade-end: 28px}to{--tab-strip-fade-start: 28px;--tab-strip-fade-end: 0px}}@media(max-width:599px){:root{--header-height: 44px}.header-brand{padding-right:0;margin-right:.1rem;border-right:none}.header-brand .logo{display:inline-flex;align-items:center;justify-content:center;min-width:44px;height:var(--header-height);margin-left:-.3rem;font-size:1.15rem;line-height:1;border-radius:8px;-webkit-tap-highlight-color:transparent}.header-brand .logo:active{background:#60a5fa29}.header-brand .logo .logo-text{display:none}.header-brand .logo .logo-compact{display:inline}.header-font-controls{gap:.1rem;padding:.1rem .2rem}.header-font-controls .btn-icon-sm{width:16px;height:16px}.header-font-controls .font-size-display{font-size:.6rem;min-width:14px}.header-system-stats{font-size:.55rem;gap:.15rem}.header-tokens{font-size:.6rem;padding:.1rem .3rem}.header{position:fixed;top:0;left:0;right:0;min-height:var(--header-height);max-height:var(--header-height);align-items:center;padding:.15rem .3rem;padding-left:calc(.3rem + var(--safe-area-left));padding-right:calc(.3rem + var(--safe-area-right));gap:.15rem;overflow:hidden;background:#0a0a0a;border-bottom:1px solid rgba(255,255,255,.08);contain:none;z-index:1200}.ios-device .header{padding-top:calc(.15rem + var(--safe-area-top));min-height:calc(var(--header-height) + var(--safe-area-top));max-height:calc(var(--header-height) + var(--safe-area-top))}.app{padding-top:calc(var(--header-height) + 6px)}.ios-device .app{padding-top:calc(var(--header-height) + 6px + var(--safe-area-top))}.main{padding-bottom:calc(40px + var(--safe-area-bottom))}.ios-device.safari-browser .main{padding-bottom:calc(40px + var(--safe-area-bottom) + var(--chrome-overlap, 0px))}.header-right{padding-left:.2rem;gap:.1rem;flex-shrink:0;border-left:none}.btn-icon-header{width:26px;height:26px;padding:0}.btn-icon-header svg{width:12px;height:12px}html[data-session-list=sidebar] #sidebarToggleBtn{width:44px;height:44px}html[data-session-list=sidebar] #sidebarToggleBtn svg{width:18px;height:18px}.btn-icon-header.btn-settings,.btn-icon-header.btn-lifecycle-log,.btn-icon-header.btn-away-digest,.btn-icon-header.btn-session-manager,.btn-icon-header.btn-file-viewer,.btn-icon-header.btn-approvals,.btn-icon-header.btn-readmymind,.btn-admin-panel{display:none!important}.btn-voice-mobile{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;background:#1a2a3f;border:1px solid rgba(59,130,246,.3);border-radius:4px;color:#93c5fd;cursor:pointer;flex-shrink:0;order:5}.btn-voice-mobile svg{width:13px;height:13px}.btn-voice-mobile:active{background:#2a3a5f}.btn-voice-mobile.recording{background:#ef444440;border-color:#ef444499;color:#ef4444;animation:mobile-voice-pulse 1.2s ease-in-out infinite}@keyframes mobile-voice-pulse{0%,to{box-shadow:inset 0 0 0 1px #ef444459;background:#ef444433}50%{box-shadow:inset 0 0 0 2px #ef4444bf;background:#ef444459}}.btn-settings-mobile{display:inline-flex!important;align-items:center;justify-content:center;width:26px;height:26px;background:transparent;border:1px solid rgba(255,255,255,.2);border-radius:4px;color:#9ca3af;font-size:.85rem;cursor:pointer;flex-shrink:0;order:6;position:relative}.btn-settings-mobile svg{width:13px;height:13px}.btn-settings-mobile:active{background:#ffffff1a;color:#fff}.app{overflow:hidden;position:relative}.keyboard-visible .app{position:fixed;inset:0 0 auto;height:var(--app-height, 100dvh)}.session-tabs,.session-tabs.tabs-two-rows{flex:1;flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scrollbar-width:none;max-height:36px;gap:6px;padding:0}.session-tabs::-webkit-scrollbar{display:none}@supports (animation-timeline: scroll()){.header .session-tabs{-webkit-mask-image:linear-gradient(to right,transparent,#000 var(--tab-strip-fade-start),#000 calc(100% - var(--tab-strip-fade-end)),transparent);mask-image:linear-gradient(to right,transparent,#000 var(--tab-strip-fade-start),#000 calc(100% - var(--tab-strip-fade-end)),transparent);animation:tab-strip-edge-fade linear both;animation-timeline:scroll(self inline)}}.session-tab{flex-shrink:0;min-height:32px;max-height:32px;padding:.35rem .5rem;font-size:.7rem;gap:.25rem;border-radius:4px}:where(.header) .session-tab{border-radius:8px;background:var(--control-bg-hover);border-color:var(--control-border-hover);color:var(--text)}:where(.header) .session-tab .tab-name{font-weight:500}:where(.header) .tab-triage-head{display:none}:where(.header) .session-tabs-host>.session-tabs.tabs-clusters>.tab-cluster{display:contents}:where(.header) .tab-cluster-label{display:none}:where(.header) .session-tabs-host>.session-tabs.tabs-clusters .tab-name-case{display:inline}:where(.header) .session-tab:not(.active) .tab-actions{display:none}:where(.header) .session-tab .tab-number{display:none}.session-tab .tab-status{width:6px;height:6px}.session-tab .tab-status.busy{width:9px;height:9px;box-shadow:0 0 8px 2px color-mix(in srgb,var(--green) 55%,transparent)!important}.session-tab .tab-status.busy:after{display:none}.session-tab.tab-agent-exited:not(.tab-alert-action):not(.tab-alert-idle) .tab-status:not(.error){background:var(--text-muted)!important;box-shadow:none!important;opacity:.5}.session-tab .tab-name{max-width:80px;overflow:hidden;text-overflow:ellipsis}.session-tab.active .tab-name{min-width:44px}.session-tab .tab-close,.session-tab .tab-gear{display:none}.session-tab .tab-detach{display:none!important}.session-tab.active .tab-gear{display:inline-flex;align-items:center;justify-content:center;font-size:.65rem;line-height:1;width:32px;height:32px;margin-left:auto;opacity:.6}.session-tab.active .tab-close{display:inline-flex;align-items:center;justify-content:center;font-size:1.1rem;line-height:1;width:20px;height:18px;margin-left:-2px}.toolbar{position:fixed;bottom:var(--safe-area-bottom);left:0;right:0;height:40px;min-height:40px;max-height:40px;padding:.3rem .4rem;padding-left:calc(.4rem + var(--safe-area-left));padding-right:calc(.4rem + var(--safe-area-right));flex-wrap:nowrap;gap:.3rem;align-items:center;justify-content:space-between;background:#111;border-top:1px solid rgba(255,255,255,.1);z-index:50;transition:transform .15s ease-out;will-change:transform}.ios-device.safari-browser .toolbar{bottom:calc(var(--safe-area-bottom) + var(--chrome-overlap, 0px))}.keyboard-visible.ios-device.safari-browser .toolbar{bottom:var(--safe-area-bottom)}.keyboard-visible.ios-device.safari-browser .keyboard-accessory-bar{bottom:calc(var(--safe-area-bottom) + 40px)}.toolbar-center{display:flex!important;align-items:center}.toolbar-center .btn-toolbar.btn-voice,.toolbar-right,.version-display{display:none!important}.toolbar-left{flex:1 1 0;min-width:0;align-items:center;gap:.3rem}.toolbar-left .toolbar-group{display:flex;flex:1 1 0;min-width:0;align-items:center;gap:.3rem}.toolbar-left .toolbar-group:first-child{flex:1 1 0;min-width:0;justify-content:space-between;gap:.3rem;flex-wrap:nowrap;align-items:center}.tab-count-group{display:none!important}.btn-toolbar{min-height:26px!important;max-height:26px!important;height:26px!important;padding:0 .5rem!important;font-size:.65rem!important;border-radius:4px;line-height:26px;display:inline-flex;align-items:center;justify-content:center;font-weight:500;letter-spacing:.01em;color:#fff}.run-btn-group{display:flex;flex:0 0 auto}.btn-toolbar.btn-run{flex:0 0 auto;padding:0 .6rem!important;font-weight:500;border-radius:4px 0 0 4px!important;border-right:none!important}.btn-toolbar.btn-run svg{width:10px;height:10px;margin-right:3px}.btn-toolbar.btn-run-gear{flex:0 0 auto;padding:0 .35rem!important;min-width:unset!important;border-radius:0 4px 4px 0!important;border-left:1px solid rgba(255,255,255,.15)!important}.btn-toolbar.btn-run-gear svg{width:10px;height:10px}.btn-toolbar.btn-run.mode-claude,.btn-toolbar.btn-run-gear.mode-claude{background:#1e3a5f;border-color:#3b82f64d;color:#93c5fd}.btn-toolbar.btn-run.mode-claude:active,.btn-toolbar.btn-run-gear.mode-claude:active{background:#2563eb;border-color:#3b82f680}.btn-toolbar.btn-run.mode-opencode,.btn-toolbar.btn-run-gear.mode-opencode{background:#0a2e2a;border-color:#10b9814d;color:#6ee7b7}.btn-toolbar.btn-run.mode-opencode:active,.btn-toolbar.btn-run-gear.mode-opencode:active{background:#0d4a40;border-color:#10b98180}.btn-toolbar.btn-run.mode-gemini,.btn-toolbar.btn-run-gear.mode-gemini{background:#10243f!important;border-color:#60a5fa4d!important;color:#dbeafe!important}.btn-toolbar.btn-run.mode-gemini:active,.btn-toolbar.btn-run-gear.mode-gemini:active{background:#174ea6!important;border-color:#60a5fa80!important}.btn-toolbar.btn-run.mode-antigravity,.btn-toolbar.btn-run-gear.mode-antigravity{background:#0b2b33!important;border-color:#22d3ee4d!important;color:#cffafe!important}.btn-toolbar.btn-run.mode-antigravity:active,.btn-toolbar.btn-run-gear.mode-antigravity:active{background:#0e7490!important;border-color:#22d3ee80!important}.btn-toolbar.btn-run.mode-pi,.btn-toolbar.btn-run-gear.mode-pi{background:#33121f!important;border-color:#f472b64d!important;color:#fce7f3!important}.btn-toolbar.btn-run.mode-pi:active,.btn-toolbar.btn-run-gear.mode-pi:active{background:#9d174d!important;border-color:#f472b680!important}.btn-toolbar.btn-run.mode-grok,.btn-toolbar.btn-run-gear.mode-grok{background:#1c1c1f!important;border-color:#d4d4d84d!important;color:#f4f4f5!important}.btn-toolbar.btn-run.mode-grok:active,.btn-toolbar.btn-run-gear.mode-grok:active{background:#3f3f46!important;border-color:#d4d4d880!important}.btn-toolbar.btn-run.mode-deepseek,.btn-toolbar.btn-run-gear.mode-deepseek{background:#16225f!important;border-color:#7c93ff59!important;color:#eef2ff!important}.btn-toolbar.btn-run.mode-deepseek:active,.btn-toolbar.btn-run-gear.mode-deepseek:active{background:#3350e6!important;border-color:#96aaff8c!important}.btn-toolbar.btn-run.mode-omp,.btn-toolbar.btn-run-gear.mode-omp{background:#312e81!important;border-color:#818cf84d!important;color:#e0e7ff!important}.btn-toolbar.btn-run.mode-omp:active,.btn-toolbar.btn-run-gear.mode-omp:active{background:#4f46e5!important;border-color:#818cf880!important}.run-mode-menu{bottom:100%;left:0;margin-bottom:6px;min-width:160px;max-width:80vw}.run-mode-option{padding:10px 12px;font-size:.8rem;cursor:pointer;-webkit-tap-highlight-color:rgba(255,255,255,.1)}.run-mode-row-btn{width:34px;height:34px;font-size:1rem;-webkit-tap-highlight-color:rgba(255,255,255,.1)}.run-mode-webview-delete{font-size:1.2rem}.run-mode-history{-webkit-overflow-scrolling:touch;touch-action:manipulation}.btn-toolbar.btn-stop{display:flex!important;flex:0 0 auto;padding:0 8px!important;min-width:unset;order:3}.btn-toolbar.btn-stop svg{width:10px;height:10px;margin-right:0}.btn-toolbar.btn-shell{display:none!important}.btn-toolbar.btn-enter{display:flex!important;flex:0 0 auto;align-items:center;justify-content:center;min-width:54px;width:54px;white-space:nowrap;padding:0 8px!important;overflow:hidden;font-size:.65rem;font-weight:600;letter-spacing:.01em;background:#1e3a5fd9!important;border:1px solid rgba(59,130,246,.45)!important;color:#dbeafe!important;order:4}.btn-toolbar.btn-enter:hover,.btn-toolbar.btn-enter:active{background:#254a7af2!important;border-color:#3b82f6b3!important;color:#fff!important}.case-select-group{display:none!important}.toolbar-left .toolbar-group:first-child{width:100%;gap:8px}.btn-toolbar.btn-case-mobile{display:flex!important;flex:1 1 0!important;min-width:0;padding:0 8px!important;order:2;overflow:hidden;justify-content:center;gap:4px}.btn-toolbar.btn-case-mobile #mobileCaseName{max-width:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.btn-case-settings-mobile{display:inline-flex!important;align-items:center;justify-content:center;width:26px;height:26px;background:transparent;border:1px solid rgba(255,255,255,.2);border-radius:4px;color:#9ca3af;cursor:pointer;flex-shrink:0;order:1}.btn-case-settings-mobile:active{background:#ffffff1a;color:#fff}@media(max-width:374px){.toolbar{padding:0 2px}.toolbar-left,.toolbar-left .toolbar-group,.toolbar-left .toolbar-group:first-child{gap:2px}}.btn-case-settings-mobile{display:none!important}.case-settings-popover-mobile{position:fixed;bottom:calc(var(--safe-area-bottom) + 46px);left:8px;right:8px;background:#1e1e1e;border:1px solid rgba(255,255,255,.15);border-radius:8px;padding:.6rem .75rem;z-index:1000;box-shadow:0 4px 16px #00000080;display:block}.case-settings-popover-mobile.hidden{display:none!important}.case-settings-popover-mobile .checkbox-inline{display:flex;align-items:center;gap:6px;font-size:.75rem;color:#e5e7eb}.case-settings-popover-mobile .form-hint{display:block;margin-top:.2rem;font-size:.6rem;color:#6b7280}.keyboard-accessory-bar{display:none;position:fixed;bottom:calc(var(--safe-area-bottom) + 40px);left:0;right:0;height:44px;background:#1a1a1a;border-top:1px solid rgba(255,255,255,.1);padding:6px 8px;padding-left:calc(8px + var(--safe-area-left));padding-right:calc(8px + var(--safe-area-right));gap:8px;align-items:center;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;z-index:51;transition:transform .15s ease-out;will-change:transform}.keyboard-accessory-bar.visible{display:flex}.keyboard-accessory-bar::-webkit-scrollbar{display:none}.accessory-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;gap:4px;padding:6px 12px;background:#2a2a2a;border:1px solid rgba(255,255,255,.15);border-radius:6px;color:#e5e5e5;font-size:.65rem;font-weight:500;cursor:pointer;transition:background .15s,border-color .15s}.accessory-btn.confirming{background:#6b4f00;border-color:#b8860b;color:#ffd54f}.accessory-btn.accessory-btn-ctrl.armed{background:#2563eb;border-color:#3b82f6e6;color:#fff;font-weight:700;box-shadow:0 0 0 2px #3b82f673}.accessory-btn:active{background:#3a3a3a}.accessory-btn svg{width:14px;height:14px}.accessory-btn-arrow{padding:6px 10px;background:#2563eb;border-color:#3b82f680;color:#fff}.accessory-btn-arrow:active{background:#1d4ed8}.accessory-btn-dismiss{margin-left:auto;flex:1 1 0;max-width:100px;padding:10px 8px;background:#2563eb;border-color:#3b82f680;color:#fff;font-weight:600}.accessory-btn-dismiss svg{width:22px;height:22px}.accessory-btn-dismiss:active{background:#1d4ed8}.voice-preview{bottom:calc(var(--safe-area-bottom) + 94px);font-size:.8rem;max-width:90%;padding:6px 14px}.toolbar-select{display:none!important}.monitor-panel,.subagents-panel{width:100%;max-width:100%;left:0;right:0;border-radius:8px 8px 0 0;bottom:calc(44px + 2rem + var(--safe-area-bottom));max-height:35vh}.modal{z-index:1300}.modal-content{width:100%;max-width:100%;height:100%;max-height:100%;border-radius:0;margin:0;display:flex;flex-direction:column}.modal-content.modal-sm,.modal-content.readmymind-modal{height:auto;max-height:85vh;border-radius:12px;margin:1rem;width:calc(100% - 2rem)}.readmymind-modal .modal-footer{flex-wrap:wrap}.readmymind-modal .modal-footer .btn-toolbar{flex:1 1 auto;justify-content:center;min-height:38px}.readmymind-alt,.readmymind-steer-input{min-height:38px}.ios-device .modal-content{padding-top:var(--safe-area-top);padding-bottom:var(--safe-area-bottom);padding-left:var(--safe-area-left);padding-right:var(--safe-area-right)}.modal-header{padding:.75rem 1rem}.modal-header h3{font-size:1rem}.modal-body{padding:.75rem 1rem;flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch}.away-digest-modal{width:100%;max-width:100%;height:100%;max-height:100%}.away-digest-ranges{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.4rem}.away-digest-ranges .filter-btn{min-height:38px;padding:.4rem .5rem}.away-digest-custom-range,.away-digest-custom-range.active{grid-template-columns:1fr}.away-digest-summary{grid-template-columns:repeat(2,minmax(0,1fr));gap:.5rem}.away-digest-item{grid-template-columns:1fr;gap:.5rem}.away-digest-action{width:100%;min-height:38px}.modal-footer,.form-actions{padding:.75rem 1rem;padding-bottom:calc(.75rem + var(--safe-area-bottom))}.ios-device .terminal-container{padding-bottom:var(--safe-area-bottom)}.main{flex:1;min-height:0}.cli-info-bar{display:block}.terminal-container{height:100%;min-height:0;position:relative;overflow:visible;touch-action:none}.terminal-container .xterm,.terminal-container .xterm-viewport,.terminal-container .xterm-screen{touch-action:none}.response-viewer{padding-bottom:var(--safe-area-bottom, 0px);max-height:88vh;max-height:92dvh}.response-viewer-body{font-size:14.5px;line-height:1.65;padding:16px 16px 24px;--rv-content-max: 100%}.response-viewer-body .rv-text pre,.response-viewer-body pre{padding:12px 14px;margin-left:-4px;margin-right:-4px;border-radius:6px}.response-viewer-body .rv-text pre code,.response-viewer-body pre code{font-size:11.5px;line-height:1.5}.response-viewer-body .rv-text h1,.response-viewer-body>h1{font-size:1.35em}.response-viewer-body .rv-text h2,.response-viewer-body>h2{font-size:1.2em}.response-viewer-body .rv-text h3,.response-viewer-body>h3{font-size:1.08em}.welcome-content{max-width:calc(100vw - 1.5rem);padding:1rem .75rem}.welcome-title{font-size:1.2rem;margin-bottom:.5rem}.welcome-desc{font-size:.8rem;margin-bottom:.4rem}.welcome-actions{margin-top:1rem}.welcome-primary{width:100%;justify-content:center;min-height:44px;font-size:.9rem}.welcome-chip{height:40px;border-radius:20px}.history-show-more{display:block;margin-bottom:.75rem}.welcome-ralph-link{display:block;margin:.75rem auto 0}.welcome-hint{font-size:.7rem;margin-top:.75rem}.modal-wizard{display:flex;flex-direction:column}.wizard-progress{padding:.5rem}.wizard-step{padding:.3rem}.wizard-step-number{width:24px;height:24px;font-size:.7rem}.wizard-step-label{display:none}.timer-banner{padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right))}.respawn-banner{padding:.3rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));font-size:.65rem}.respawn-compact-layout{flex-direction:column;gap:.15rem}.respawn-status-col{flex-shrink:1;min-width:0;gap:.1rem}.respawn-status-row1{flex-wrap:wrap;gap:.25rem;row-gap:.1rem}.respawn-state{font-size:.6rem;padding:.05rem .3rem}.respawn-banner .detection-confidence{font-size:.5rem;padding:.02rem .2rem}.respawn-cycles{font-size:.55rem}.respawn-timer{font-size:.55rem;padding:0 .25rem}.respawn-tokens{font-size:.55rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:120px}.respawn-indicator{font-size:.65rem}.respawn-banner .btn-icon-only{min-width:36px;min-height:36px;font-size:1rem;display:flex;align-items:center;justify-content:center;margin-left:auto;border-radius:6px;flex-shrink:0}.respawn-status-row2{font-size:.55rem;gap:.3rem;min-height:0;flex-wrap:wrap}.respawn-banner .detection-hook,.respawn-banner .detection-ai-check,.respawn-banner .detection-status{font-size:.55rem;padding:.02rem .2rem}.respawn-countdown-timers{gap:.2rem}.respawn-countdown-timer{font-size:.5rem;padding:.02rem .2rem;gap:.15rem}.respawn-countdown-timer .respawn-timer-bar{display:none}.respawn-action-log{border-left:none;border-top:1px solid rgba(34,197,94,.15);padding-left:0;padding-top:.15rem;max-height:1.4em;font-size:.55rem;overflow:hidden}.respawn-header{flex-direction:row;gap:.4rem;align-items:center}.respawn-header .respawn-actions{display:flex;gap:.3rem;flex-shrink:0}.respawn-header .respawn-actions .btn-toolbar{min-height:28px!important;font-size:.7rem!important;padding:.2rem .5rem!important;border-radius:5px}.duration-presets{display:flex;flex-wrap:wrap;gap:.2rem}.duration-preset-btn{min-height:24px;padding:.1rem .4rem;font-size:.6rem;border-radius:4px;text-align:center}.duration-custom{display:flex;gap:.2rem;align-items:center}.duration-custom-input.visible{flex:0 1 auto}.duration-custom-input input{width:64px;min-height:24px;font-size:16px;padding:.1rem .3rem}.preset-selector{display:grid;grid-template-columns:1fr 1fr;gap:.25rem}.preset-selector select{grid-column:1 / -1;min-height:32px;font-size:16px;border-radius:5px;padding:.2rem .4rem}.preset-selector .btn{min-height:32px;font-size:.65rem;border-radius:5px;padding:.2rem .4rem}#sessionOptionsModal textarea{font-size:16px;min-height:32px!important;max-height:56px;height:auto!important;border-radius:6px;padding:.3rem .5rem}#modalRespawnPrompt{min-height:32px!important;max-height:56px}#modalRespawnKickstart{min-height:32px!important;max-height:48px}#sessionOptionsModal .checkbox-inline{min-height:30px;font-size:.75rem;padding:.15rem 0;gap:.4rem}#sessionOptionsModal .checkbox-inline input[type=checkbox]{width:18px;height:18px}#sessionOptionsModal .respawn-loop-title{font-size:.75rem}#sessionOptionsModal .respawn-loop-box .checkbox-inline{font-size:.65rem}#sessionOptionsModal .respawn-options-row{gap:.5rem}#sessionOptionsModal .form-section-header{margin-top:.75rem;padding-top:.5rem;font-size:.65rem}#sessionOptionsModal .form-row{margin-bottom:.5rem}#sessionOptionsModal .form-row label{font-size:.65rem;margin-bottom:.2rem}#sessionOptionsModal .form-hint{font-size:.6rem;margin-top:.2rem}.context-setting{padding:.625rem}.context-setting-header{flex-wrap:wrap;gap:.4rem}.context-setting-header .input-suffix-sm input{width:60px;font-size:16px;min-height:36px}.context-setting input[type=text]{font-size:16px;min-height:36px;padding:.4rem .6rem;border-radius:6px}.color-picker{gap:8px}.color-swatch{width:36px;height:36px;border-radius:6px}.form-row-switch{min-height:40px;gap:.4rem}.context-settings-grid input[type=number]{font-size:16px;min-height:36px}.ralph-limits-grid{grid-template-columns:1fr 1fr;gap:.5rem}.ralph-limits-grid .form-col input[type=number]{font-size:16px;min-height:36px;padding:.4rem .5rem;border-radius:6px}#modalRalphPhrase{font-size:16px;min-height:40px;border-radius:6px}.ralph-config-actions{margin-top:1rem}.ralph-config-actions .btn-toolbar{width:100%;min-height:44px;font-size:.85rem;border-radius:8px}.run-summary-filters{gap:.3rem;margin-bottom:.5rem}.filter-btn{padding:.35rem .75rem;font-size:.7rem;min-height:32px}.timeline-event{padding:.4rem .5rem;margin-bottom:.25rem;font-size:.7rem}.run-summary-footer{flex-direction:column;gap:.4rem;padding:.5rem 0}.run-summary-actions{flex-wrap:wrap;gap:.3rem}.run-summary-actions .btn-toolbar{flex:1;min-height:36px;font-size:.7rem;white-space:nowrap}.auto-refresh-label{font-size:.7rem}.ralph-panel{font-size:.75rem}.ralph-summary{padding:.4rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right))}.project-insights-panel{max-width:100%;font-size:.65rem;bottom:calc(44px + 2rem + var(--safe-area-bottom))}.file-browser-panel{max-width:100%;max-height:50vh;bottom:calc(44px + 2rem + var(--safe-area-bottom))}.file-preview-window{width:100vw;max-width:100vw;height:var(--app-height, 100vh);max-height:var(--app-height, 100vh);border-radius:0;border-left:none;border-right:none}.file-preview-editbar{padding-bottom:calc(.4rem + var(--safe-area-bottom))}.file-preview-overlay .file-preview-footer{padding-bottom:calc(.35rem + var(--safe-area-bottom))}.file-preview-body textarea.file-preview-editor{font-size:16px}.notification-drawer{width:100%;max-width:100%;right:0;border-radius:0;padding-left:var(--safe-area-left);padding-right:var(--safe-area-right);padding-bottom:var(--safe-area-bottom)}input,textarea,[contenteditable]{scroll-margin-bottom:200px;scroll-margin-top:80px}.keyboard-visible .modal-body{max-height:40vh;overflow-y:auto}.keyboard-visible #createCaseModal .modal-body{max-height:60vh}.mobile-case-picker .modal-backdrop{background:#00000080}.mobile-case-picker-sheet{max-height:80vh;max-height:80dvh;animation:slideUp .2s ease-out}@keyframes slideUp{0%{transform:translateY(100%)}to{transform:translateY(0)}}.mobile-case-picker-header .modal-close{width:32px;height:32px;font-size:1.5rem}.keyboard-visible .mobile-case-picker-sheet{max-height:45vh}.keyboard-visible .mobile-case-picker-body{max-height:28vh}.mobile-case-picker-footer{padding-bottom:calc(12px + var(--safe-area-bottom))}#createCaseModal .form-row{margin-bottom:1rem}#createCaseModal .form-row label{font-size:.8rem;margin-bottom:.4rem;font-weight:500;color:#e5e7eb}#createCaseModal .form-row input[type=text]{min-height:44px;font-size:16px;padding:.5rem .75rem;border-radius:8px}#createCaseModal .form-row .form-hint{font-size:.65rem;margin-top:.35rem;line-height:1.4}#createCaseModal .form-actions{padding:.75rem 1rem;padding-bottom:calc(.75rem + var(--safe-area-bottom));gap:.75rem}#createCaseModal .form-actions .btn-toolbar{min-height:44px!important;max-height:44px!important;height:44px!important;font-size:.85rem!important;font-weight:500;border-radius:8px}#caseModalSubmit.loading{opacity:.6;pointer-events:none}#createCaseModal.from-mobile .modal-content{animation:caseModalSlideUp .25s ease-out}@keyframes caseModalSlideUp{0%{transform:translateY(30px);opacity:0}to{transform:translateY(0);opacity:1}}.btn-case-create-mobile{min-height:48px!important;max-height:48px!important;height:48px!important;font-size:.85rem!important;font-weight:500;border-radius:10px}.settings-grid{grid-template-columns:1fr;gap:.35rem}.settings-grid-3col{grid-template-columns:1fr 1fr 1fr}.settings-item{padding:.35rem .5rem;font-size:.7rem}.settings-item-label{font-size:.7rem}.settings-section-header{font-size:.6rem;padding:.35rem 0 .2rem;margin-top:.5rem}.form-row{margin-bottom:.5rem}.form-row label{font-size:.7rem;margin-bottom:.2rem}.form-row .form-hint{font-size:.6rem}.form-row input[type=text],.form-row input[type=number],.form-row textarea,.form-row .form-select,.form-row select{font-size:.75rem;padding:.35rem .5rem;min-height:32px}.form-row-switch{gap:.3rem}.form-row-switch>label:first-child{font-size:.7rem}.form-section-header{font-size:.6rem;margin-top:.75rem}.event-type-grid{grid-template-columns:1fr 36px 36px 36px;gap:4px 4px;padding:6px;margin-top:6px}.event-header{font-size:.55rem}.event-label{font-size:.65rem}.event-type-grid input[type=checkbox]{width:12px;height:12px}.form-actions{gap:.5rem}.form-actions .btn-toolbar{flex:1;min-height:36px!important;max-height:36px!important;height:36px!important;font-size:.75rem!important}.subagent-window{position:fixed;width:calc(100% - 8px);max-width:calc(100% - 8px);height:110px;min-height:80px;max-height:110px;min-width:200px;border-radius:6px;resize:none;box-shadow:0 2px 8px #0006}.subagent-window:after{display:none}.subagent-window-header{padding:.2rem .4rem;min-height:24px}.subagent-window-title{gap:.2rem;overflow:hidden}.subagent-window-title .icon{font-size:.7rem}.subagent-window-title .id{font-size:.6rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:45vw}.subagent-window-title .status{font-size:.45rem;padding:.05rem .15rem}.subagent-model-badge{font-size:.45rem!important;padding:.05rem .15rem!important}.subagent-window-actions button{font-size:.7rem;padding:.15rem .35rem;min-width:26px;min-height:26px;display:flex;align-items:center;justify-content:center}.subagent-window-body{font-size:.6rem;padding:.2rem .35rem}.subagent-window-body .activity-line{gap:.15rem;padding:.05rem 0}.subagent-window-body .activity-line .time{font-size:.5rem}.subagent-window-body .activity-line .tool-name,.subagent-window-body .activity-line .tool-detail{font-size:.55rem}.subagent-window-parent{display:none}.session-tab .tab-subagent-badge{height:14px;padding:0 3px;border-radius:7px;margin-left:2px}.session-tab .tab-subagent-badge .subagent-label{font-size:.45rem}.subagent-dropdown{position:fixed!important;left:8px!important;right:8px!important;bottom:auto!important;min-width:auto!important;max-width:none!important;border-radius:8px;transform:none!important}.mobile-overview.visible{position:absolute;inset:0;z-index:10;display:flex;flex-direction:column;gap:.75rem;padding:.75rem .6rem calc(1rem + var(--safe-area-bottom));background:var(--bg-dark);overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}.mobile-overview-top{display:flex;align-items:center;justify-content:space-between;gap:.5rem;padding:0}.mobile-overview-brand{display:inline-flex;align-items:center;min-height:48px;font-size:1.5rem;font-weight:800;line-height:1;color:var(--accent-hover);letter-spacing:-.02em}.mobile-overview-header{position:relative;display:flex;flex-direction:column}.mobile-overview-run-group{display:flex;align-items:stretch;flex-shrink:0}.mobile-overview-run-group .mobile-overview-run{display:inline-flex;align-items:center;gap:.4rem;min-height:48px!important;height:48px!important;max-height:48px!important;padding:0 1.15rem!important;font-size:.95rem!important;line-height:1;font-weight:700;font-family:inherit;border-radius:10px 0 0 10px!important}.mobile-overview-run-mode{font-weight:600;font-size:.85rem;opacity:.8}.mobile-overview-run-group .mobile-overview-run-caret{display:inline-flex;align-items:center;justify-content:center;min-height:48px!important;height:48px!important;max-height:48px!important;min-width:48px!important;width:48px!important;padding:0!important;line-height:1;font-family:inherit;border-radius:0 10px 10px 0!important}.mobile-overview-run-group .mobile-overview-run-caret svg{display:block;width:20px!important;height:20px!important;margin:0!important}.mobile-overview-run-menu{display:flex;flex-direction:column;gap:.15rem;margin:.5rem 0 0;padding:.35rem;border:1px solid var(--border);border-radius:12px;background:var(--floating-bg);box-shadow:var(--elevated-shadow)}.mobile-overview-run-option{display:flex;align-items:center;gap:.5rem;min-height:44px;padding:0 .6rem;border:none;border-radius:8px;background:transparent;color:var(--text);font-family:inherit;font-size:.82rem;text-align:left}.mobile-overview-run-option.selected{background:var(--control-bg-hover)}.mobile-overview-run-option:active{background:var(--bg-hover)}.mobile-overview-run-option--add{color:var(--accent)}.mobile-overview-run-header{padding:.4rem .6rem .2rem;font-size:.6rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--text-muted)}.mobile-overview-section{display:flex;flex-direction:column;gap:.4rem}.mobile-overview-heading{display:flex;align-items:center;gap:.35rem;margin:.35rem 0 0;padding:0;font-size:.65rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--text-muted)}.mobile-overview-heading-count{color:var(--text-dim);font-weight:600}.mobile-overview-empty{margin:0;padding:.5rem 0;font-size:.75rem;color:var(--text-muted)}.mobile-overview-row{display:flex;align-items:center;gap:.6rem;width:100%;min-height:56px;padding:.5rem .7rem;border:1px solid var(--border);border-radius:12px;background:var(--bg-card);color:var(--text);font-family:inherit;text-align:left}.mobile-overview-row:active{background:var(--bg-hover)}.mobile-overview-row-wrap{width:100%}.mobile-overview-approval-strip{display:flex;flex-wrap:wrap;gap:.4rem;padding:.4rem .2rem .1rem}.mobile-overview-approval-btn{border:1px solid var(--border);border-radius:8px;background:var(--bg-card);color:var(--text);font-family:inherit;font-size:.72rem;padding:.35rem .6rem;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mobile-overview-approval-btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}.mobile-overview-approval-btn.danger{border-color:var(--error);color:var(--error)}.mobile-overview-row--needs{border-color:var(--red);animation:mobile-overview-blink-red 2.5s ease-in-out infinite}.mobile-overview-row--waiting{border-color:var(--yellow);animation:mobile-overview-blink-yellow 3.5s ease-in-out infinite}.mobile-overview-row--error{border-color:var(--red)}.mobile-overview-row--working{border-color:var(--green);animation:mobile-overview-breathe-green 2.2s ease-in-out infinite}@keyframes mobile-overview-breathe-green{0%,to{background:var(--bg-card);border-color:var(--border)}50%{background:#22c55e1a;border-color:var(--green)}}.mobile-overview-pill--working:after{content:"";display:inline-block;width:.75em;text-align:left;animation:mobile-overview-pill-dots 1.5s steps(1,end) infinite}@keyframes mobile-overview-pill-dots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}@keyframes mobile-overview-blink-red{0%,to{background:var(--bg-card);border-color:var(--border)}50%{background:#ef444424;border-color:var(--red)}}@keyframes mobile-overview-blink-yellow{0%,to{background:var(--bg-card);border-color:var(--border)}50%{background:#eab3081f;border-color:var(--yellow)}}.mobile-overview-row-body{display:flex;flex-direction:column;gap:.15rem;flex:1;min-width:0}.mobile-overview-row-title{display:block;font-size:.9rem;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-overview-row-case{color:var(--text-dim);font-weight:500}.mobile-overview-row-sub{display:block;font-size:.68rem;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-overview-row-meta{display:flex;align-items:center;gap:.3rem;min-width:0;font-family:var(--font-mono, monospace);font-size:.63rem;color:var(--text-muted);white-space:nowrap;overflow:hidden}.mobile-overview-meta-item{min-width:0;overflow:hidden;text-overflow:ellipsis}.mobile-overview-meta-key{margin-right:.3rem;opacity:.6;text-transform:uppercase;letter-spacing:.05em}.mobile-overview-meta-sep{opacity:.45}.mobile-overview-row--working .mobile-overview-meta-since{color:var(--green);opacity:.95}.mobile-overview-dot{flex-shrink:0;width:9px;height:9px;border-radius:50%;background:var(--text-muted)}.mobile-overview-dot--needs,.mobile-overview-dot--error{background:var(--red)}.mobile-overview-dot--waiting{background:var(--yellow)}.mobile-overview-dot--working{background:var(--green);animation:pulse 1.5s infinite;box-shadow:0 0 8px 2px color-mix(in srgb,var(--green) 55%,transparent);will-change:opacity}.mobile-overview-dot{position:relative}.mobile-overview-dot--working:after{content:"";position:absolute;inset:-4px;border:2px solid rgba(34,197,94,.25);border-top-color:var(--green);border-radius:50%;animation:tab-load-spin .7s linear infinite}.mobile-overview-dot--idle{background:var(--green)}.mobile-overview-dot--done{background:var(--text-muted);opacity:.5}.mobile-overview-pill{flex-shrink:0;display:inline-flex;align-items:center;gap:.25rem;padding:.2rem .45rem;border:1px solid var(--border-light);border-radius:999px;font-size:.62rem;font-weight:600;color:var(--text-dim);white-space:nowrap}.mobile-overview-pill--needs,.mobile-overview-pill--error{border-color:var(--red);color:var(--red)}.mobile-overview-pill--waiting{border-color:var(--yellow);color:var(--yellow)}.mobile-overview-pill--idle,.mobile-overview-pill--working{border-color:var(--green);color:var(--green)}.mobile-overview-pill--exited{border-color:var(--text-muted);color:var(--text-muted)}.mobile-overview-pill--watching{border-color:var(--accent);color:var(--accent)}.mobile-overview-chevron{flex-shrink:0;color:var(--text-muted);font-size:1rem;line-height:1}.mobile-overview-row--past{background:transparent;border-style:dashed}.mobile-overview-row--past .mobile-overview-row-title{font-weight:500;color:var(--text-dim)}.mobile-overview-dot--past{background:transparent;border:1px solid var(--border-light)}.mobile-overview-pill--past{border-color:var(--border-light);color:var(--text-muted)}.mobile-overview-more{display:flex;align-items:center;justify-content:center;gap:.35rem;min-height:40px;border:none;border-radius:10px;background:var(--control-bg);color:var(--text-dim);font-family:inherit;font-size:.72rem;font-weight:600}.mobile-overview-more-count{padding:.05rem .35rem;border-radius:999px;background:var(--control-bg-hover);color:var(--text-muted)}}@media(prefers-reduced-motion:reduce){.mobile-overview-row--needs,.mobile-overview-row--waiting{animation:none}.mobile-overview-row--needs{background:#ef444424}.mobile-overview-row--waiting{background:#eab3081f}.mobile-overview-dot--working{animation:none}.mobile-overview-dot--working:after{border-color:var(--green);animation:none}.mobile-overview-row--working{animation:none}.mobile-overview-pill--working:after{content:"...";animation:none}}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.header,.toolbar,.keyboard-accessory-bar){background:var(--glass-bg);border-color:var(--glass-border);color:var(--text)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-voice-mobile,.btn-settings-mobile,.btn-toolbar.btn-shell,.accessory-btn:not(.armed)){background:var(--control-bg);border-color:var(--control-border);color:var(--text-dim)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-voice-mobile:active,.btn-settings-mobile:active,.btn-toolbar.btn-shell:hover,.btn-toolbar.btn-shell:active,.accessory-btn:active){background:var(--control-bg-hover);border-color:var(--control-border-hover);color:var(--text)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-claude,.btn-toolbar.btn-run-gear.mode-claude){background:linear-gradient(135deg,var(--accent-grad-a),var(--accent-grad-b));border-color:var(--accent);color:var(--accent-ink)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-opencode,.btn-toolbar.btn-run-gear.mode-opencode){background:linear-gradient(135deg,var(--accent-d),var(--accent-grad-b));border-color:var(--accent);color:var(--accent-ink)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-gemini,.btn-toolbar.btn-run-gear.mode-gemini){background:linear-gradient(135deg,#174ea6,#4f46e5);border-color:#315fc3;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-antigravity,.btn-toolbar.btn-run-gear.mode-antigravity){background:linear-gradient(135deg,#0e7490,#0891b2);border-color:#155e75;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-pi,.btn-toolbar.btn-run-gear.mode-pi){background:linear-gradient(135deg,#be185d,#db2777);border-color:#9d174d;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-omp,.btn-toolbar.btn-run-gear.mode-omp){background:linear-gradient(135deg,#4f46e5,#6366f1);border-color:#4338ca;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-grok,.btn-toolbar.btn-run-gear.mode-grok){background:linear-gradient(135deg,#27272a,#52525b);border-color:#18181b;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-deepseek,.btn-toolbar.btn-run-gear.mode-deepseek){background:linear-gradient(135deg,#2740c4,#4d6bfe);border-color:#1b2a8f;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) .btn-toolbar.btn-run-gear{border-left-color:var(--control-border-hover)!important}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.case-settings-popover-mobile,.mobile-case-picker-sheet){background:var(--floating-bg);border-color:var(--control-border);color:var(--text);box-shadow:var(--elevated-shadow)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.case-settings-popover-mobile .checkbox-inline,#createCaseModal .form-row label){color:var(--text)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) .case-settings-popover-mobile .form-hint{color:var(--text-muted)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) .mobile-case-picker .modal-backdrop{background:var(--modal-backdrop)}.ios-device.safari-browser{overscroll-behavior:none}@media(hover:none)and (pointer:coarse){.session-tab .tab-close,.session-tab .tab-gear{opacity:1;width:auto;padding:.15rem .25rem;align-items:center;justify-content:center}.btn-toolbar:hover,.btn-icon-header:hover{transform:none}.subagent-dropdown-trigger:active+.subagent-dropdown-menu,.subagent-dropdown-trigger:focus+.subagent-dropdown-menu{display:block}}@media(max-width:599px){.attachment-history-drawer{top:0;bottom:0;width:100%;max-width:100%;height:100vh;height:100dvh;border-left:none;border-radius:0;padding-top:var(--safe-area-top);padding-left:var(--safe-area-left);padding-right:var(--safe-area-right);padding-bottom:var(--safe-area-bottom)}.attachment-history-header{padding:12px}.attachment-history-list{padding:6px}.attachment-history-item{grid-template-columns:104px minmax(0,1fr);gap:8px;padding:8px 6px}.attachment-history-thumb{width:104px}.attachment-history-actions{gap:4px}.attachment-history-actions button{padding:4px 7px}}@media(max-width:599px){.reboot-restore-banner{padding:.4rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));font-size:.7rem;gap:.4rem}.reboot-restore-banner-detail,.reboot-restore-banner-note{display:none}.reboot-restore-banner-text{min-width:0;overflow:hidden;text-overflow:ellipsis}.reboot-restore-banner-accept,.reboot-restore-banner-dismiss{padding:.25rem .5rem}.reboot-restore-banner-accept{margin-left:auto}.offline-banner{padding:.4rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));font-size:.7rem;gap:.4rem}.offline-banner-detail{display:none}.offline-banner-retry{padding:.25rem .5rem;margin-left:auto}.offline-overlay-card{padding:22px 18px 18px}.offline-overlay-title{font-size:1.05rem}.offline-overlay-actions{flex-direction:column}.offline-overlay-btn{width:100%;padding:.65rem 1rem}}@media(max-width:860px){:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .modal-content.modal-lg{width:100%;max-width:100%;height:100%;max-height:100%}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-body{display:flex;flex-direction:column;min-height:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-rail{flex-direction:row;align-items:center;border-right:0;border-bottom:1px solid var(--border);background:transparent;padding:10px 14px;overflow:visible;flex-shrink:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-rail-items,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-rail-foot{display:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-search{margin:0;flex:1}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-search input{padding:9px 10px 9px 30px;border-radius:10px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-head-actions:has(.set-head-save){padding:3px;border:1px solid var(--border);border-radius:12px;background:var(--bg-input)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-head-save{display:inline-flex;height:36px;padding:0 16px;font-size:.86rem}#createCaseModal .set-head-save.loading{opacity:.6;pointer-events:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-head-actions .modal-close{width:36px;height:36px;font-size:1.35rem}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-foot{display:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-doc{padding:0 14px 34px;flex:1}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump{display:flex;position:sticky;top:0;z-index:4;align-items:center;gap:8px;width:100%;margin:10px 0 2px;padding:10px 12px;border-radius:11px;font:inherit;font-size:.82rem;color:var(--text);background:rgba(var(--accent-rgb),.13);border:1px solid rgba(var(--accent-rgb),.3);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);cursor:pointer}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-ico{color:var(--accent);flex-shrink:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-label{font-weight:580;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-chev{margin-left:auto;color:var(--text-muted);flex-shrink:0;transition:transform .18s}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump[aria-expanded=true] .set-jump-chev{transform:rotate(180deg)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-veil{display:none;position:fixed;inset:0;z-index:8;background:#04080d9e}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-menu{display:none;position:absolute;left:14px;right:14px;z-index:9;padding:7px;border-radius:16px;background:var(--bg-card);border:1px solid var(--control-border);box-shadow:var(--elevated-shadow);max-height:70vh;overflow-y:auto}#appSettingsModal.jump-open .set-jump-veil,#appSettingsModal.jump-open .set-jump-menu{display:block}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row{display:flex;align-items:center;gap:11px;width:100%;padding:11px 12px;border:0;border-radius:11px;background:transparent;color:var(--text-dim);font:inherit;font-size:.82rem;text-align:left}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row svg{color:var(--text-muted);flex-shrink:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row .set-jump-count{margin-left:auto;font-size:.62rem;color:var(--text-muted)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row.active{background:rgba(var(--accent-rgb),.14);color:var(--text);font-weight:570}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row.active svg{color:var(--accent)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section{padding-top:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section+.set-section{border-top:0;margin-top:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-head{gap:7px;margin:18px 0 2px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-head svg{padding:0;border:0;background:none;color:var(--text-muted);width:12px;height:12px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-head h2{font-size:.6rem;font-weight:640;letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-head:after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--border),transparent)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-blurb{display:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-preview{margin-bottom:12px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-preview-stage{min-height:62px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group{margin-top:14px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group+.set-group{margin-top:16px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-head{margin-bottom:7px;padding:0 3px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-hint{padding:0 3px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body{gap:0;background:#ffffff09;border:1px solid rgba(255,255,255,.06);border-radius:13px;overflow:hidden}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-row{background:transparent;border:0;border-radius:0;padding:12px 13px;gap:12px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-row+.set-row{border-top:1px solid rgba(255,255,255,.055)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-chips,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-modelgrid,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-minigrid,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>#appSettingsShortcutsList{padding:12px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.event-type-grid{padding:12px;margin:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row-label{font-size:.84rem}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row-desc{font-size:.69rem;max-width:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row.has-field{flex-direction:column;align-items:stretch;gap:9px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row.has-field .set-select,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row.has-field .set-input{width:100%;min-width:0;max-width:none;box-sizing:border-box}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row-actions-wide{width:100%}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row-actions-wide .set-input{flex:1;min-width:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-num{width:76px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .switch-sm{width:40px;height:24px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .switch-sm .slider:before{height:18px;width:18px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .switch-sm input:checked+.slider:before{transform:translate(16px)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-chip{font-size:.78rem;padding:9px 14px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-modelgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-minigrid{grid-template-columns:1fr}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-mini .set-select{width:148px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-segment{overflow-x:auto;scrollbar-width:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-segment::-webkit-scrollbar{display:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-segment button{flex:0 0 auto;padding:8px 12px}}@media(max-width:860px){:is(#sessionOptionsModal,#createCaseModal) .set-rail{padding:8px 10px}:is(#sessionOptionsModal,#createCaseModal) .set-rail-items{display:flex;flex-direction:row;flex:1;min-width:0;gap:4px;overflow-x:auto;scrollbar-width:none}:is(#sessionOptionsModal,#createCaseModal) .set-rail-items::-webkit-scrollbar{display:none}:is(#sessionOptionsModal,#createCaseModal) .set-rail-item{white-space:nowrap;padding:8px 12px}:is(#sessionOptionsModal,#createCaseModal) .set-rail-item.active:before{display:none}:is(#sessionOptionsModal,#createCaseModal) .set-rail-item.active{background:rgba(var(--accent-rgb),.13)}}html[data-session-list=sidebar] .session-sidebar{position:absolute;top:0;bottom:0;left:0;width:min(280px,80vw);flex:0 0 auto;transform:translate(-100%);visibility:hidden;transition:transform var(--sidebar-transition),visibility var(--sidebar-transition);box-shadow:10px 0 28px #0000005c;z-index:12;padding-left:var(--safe-area-left)}html[data-session-list=sidebar][data-sidebar-detail=rich] .session-sidebar{width:min(280px,80vw);flex:0 0 auto}html[data-session-list=sidebar] .session-sidebar.open{transform:translate(0);visibility:visible}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar{flex-basis:auto;width:min(280px,80vw)}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar-head,html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar-filter{display:flex}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar .session-tab{justify-content:flex-start;flex-wrap:nowrap;padding:.4rem .5rem}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar .tab-info{display:flex}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar .tab-number{display:inline-flex}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar .tab-subagent-badge{margin-left:4px}html[data-session-list=sidebar] .session-sidebar .session-tab{min-height:44px;max-height:none;flex-shrink:0}html[data-session-list=sidebar] .session-sidebar .session-tab .tab-gear,html[data-session-list=sidebar] .session-sidebar .session-tab .tab-close{display:inline-flex;align-items:center;justify-content:center;opacity:1;width:auto;min-width:28px;height:auto;margin-left:0;padding:.15rem .25rem}@media(prefers-reduced-motion:reduce){html[data-session-list=sidebar] .session-sidebar{transition:none}}@media(vertical-viewport-segments:2){.response-viewer{max-height:min(88vh,env(viewport-segment-height 0 1,88vh))}}@media(max-width:700px){.spreadsheet-sheet-tabs{padding-inline:4px;scroll-snap-type:x proximity}.spreadsheet-sheet-tab{min-width:96px;min-height:40px;scroll-snap-align:start}.spreadsheet-grid{min-height:55vh;-webkit-overflow-scrolling:touch;touch-action:pan-x pan-y}}
@@ -1,100 +0,0 @@
1
- "use strict";const RUN_MODE_LAUNCH={opencode:{label:"OpenCode",installHint:"OpenCode CLI not found. Install with: curl -fsSL https://opencode.ai/install | bash",supportsCustomModel:!0,buildConfig:()=>({openCodeConfig:{autoAllowTools:!0}})},codex:{label:"Codex",installHint:"Codex CLI not found. Install with: npm install -g @openai/codex",supportsCustomModel:!0,buildConfig:e=>({codexConfig:{dangerouslyBypassApprovals:e.codexDangerouslyBypassApprovals??!1,animations:e.codexAnimationsEnabled??!1,renderMode:"hybrid"}})},gemini:{label:"Gemini",installHint:"Gemini CLI not found. Install with: npm install -g @google/gemini-cli",supportsCustomModel:!0,buildConfig:()=>({geminiConfig:{approvalMode:"yolo"}})},antigravity:{label:"Antigravity",installHint:"Antigravity CLI not found. Install with: curl -fsSL https://antigravity.google/cli/install.sh | bash",supportsCustomModel:!1,buildConfig:()=>({antigravityConfig:{dangerouslySkipPermissions:!0}})},pi:{label:"Pi",installHint:"Pi CLI not found. Install with: npm install -g --ignore-scripts @earendil-works/pi-coding-agent",supportsCustomModel:!0,buildConfig:()=>null},omp:{label:"OMP",installHint:"OMP CLI not found. Install with: curl -fsSL https://omp.sh/install | sh",supportsCustomModel:!0,buildConfig:()=>null},grok:{label:"Grok",installHint:"Grok CLI not found. Install with: curl -fsSL https://x.ai/cli/install.sh | bash",supportsCustomModel:!0,buildConfig:()=>({grokConfig:{alwaysApprove:!0}})},deepseek:{label:"DeepSeek",installHint:"DeepSeek Harness CLI (dsh) not found. Install with: npm install -g @deepseek-ai/dsh",unrunnableHint:"No interactive DeepSeek Harness profile is installed. DeepSeek ships only web and headless profiles, so the terminal agent comes from a plugin. Install one from the Run menu, or run: dsh plugin --profile dsh-tui add @deepseek-harness-tui/dsh-tui",supportsCustomModel:!0,buildConfig:()=>({deepSeekConfig:{permissionMode:"danger-full-access"}})}},CASE_PICKER_REFRESH_MS=5e3,CASE_PICKER_ACTIONS=[{id:"add",icon:"+",label:"New or link a case\u2026",run:e=>e.showCreateCaseModal()},{id:"settings",icon:"\u2699",label:"Case settings\u2026",run:e=>e.toggleCaseSettings()}],EXTERNAL_CLI_MODES=new Set(Object.keys(RUN_MODE_LAUNCH)),BUILT_IN_RUN_MODES=new Set(["claude","shell",...Object.keys(RUN_MODE_LAUNCH)]);function registryCliCatalog(){return typeof window<"u"&&Array.isArray(window.__codemanCliCatalog)?window.__codemanCliCatalog:[]}function registryCliById(e){return registryCliCatalog().find(t=>t.id===e)}function isExternalCliRunMode(e){return EXTERNAL_CLI_MODES.has(e)||registryCliById(e)?.kind==="agent"}function isExternalCliSession(e){return registryCliById(e)?.external??isExternalCliRunMode(e)}Object.assign(CodemanApp.prototype,{buildEnvOverrides(e,t){const s={};return(e?.agentTeams||t?.agentTeamsEnabled)&&(s.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS="1"),s},getEffortSetting(e){const t=e?.thinkingEffort;return["low","medium","high","xhigh","max","ultracode"].includes(t)?t:void 0},getAdvisorSetting(e){const t=e?.claudeAdvisorModel;return["fable","opus","sonnet"].includes(t)?t:void 0},formatCasePickerLabel(e){return e?.location==="remote"&&e.remote?.hostId?`${e.name} @ ${e.remote.hostId}`:e?.location==="docker"?`${e.name} (${this.dockerCaseTag(e.docker?.hostId)})`:e?.name||""},dockerCaseTag(e){return!e||e==="default"||e==="local"||/^q-/.test(e)?"docker":e},buildCasePickerOptions(e=[]){const t=[],s=new Set;for(const n of e)!n?.name||s.has(n.name)||(s.add(n.name),t.push(n));return s.has("testcase")||t.push({name:"testcase"}),t.map(n=>{const o=this.formatCasePickerLabel(n),a=[n.name,o,n.path,n.location,n.remote?.hostId,n.remote?.label,n.remote?.path,n.docker?.container,n.docker?.image,n.docker?.path].filter(Boolean).join(" ").toLowerCase();return{name:n.name,label:o,case:n,searchText:a}}).sort((n,o)=>n.label.localeCompare(o.label,void 0,{sensitivity:"base",numeric:!0}))},filterCasePickerOptions(e,t){const s=String(t||"").trim().toLowerCase().split(/\s+/).filter(Boolean);return s.length===0?e:e.filter(n=>s.every(o=>n.searchText.includes(o)))},getCasePickerOptions(){return this.buildCasePickerOptions(this.cases||[])},updateCasePickerInput(e){const t=document.getElementById("quickStartCaseSearch");if(!t)return;const s=this.getCasePickerOptions().find(n=>n.name===e);t.value=s?.label||e||"testcase",t.title=s?.label||t.value},renderQuickStartCaseSelectOptions(e,t){e&&(e.innerHTML=t.map(s=>`<option value="${escapeHtml(s.name)}">${escapeHtml(s.label)}</option>`).join(""))},openCasePicker(e=""){const t=document.getElementById("quickStartCaseSearch"),s=document.getElementById("quickStartCaseList");if(!t||!s)return;const n=this._casePickerOpen===!0;this._casePickerOpen=!0,this._casePickerFilter=e,this._casePickerActiveIndex=0,t.setAttribute("aria-expanded","true"),this.renderCasePickerList(),n||this._startCasePickerRefresh()},_startCasePickerRefresh(){this.refreshCasePickerCases(),!this._casePickerRefreshTimer&&(this._casePickerRefreshTimer=setInterval(()=>{this.refreshCasePickerCases()},CASE_PICKER_REFRESH_MS))},_stopCasePickerRefresh(){this._casePickerRefreshTimer&&clearInterval(this._casePickerRefreshTimer),this._casePickerRefreshTimer=null},async refreshCasePickerCases(){if(!this._casePickerRefreshInFlight){this._casePickerRefreshInFlight=!0;try{const e=await fetch("/api/cases");if(!e.ok)return;const t=(await e.json()).data;if(!Array.isArray(t)||!this._casePickerOpen)return;const s=o=>JSON.stringify((o||[]).map(a=>[a.name,a.path,a.location]));if(s(t)===s(this.cases))return;this.cases=t;const n=document.getElementById("quickStartCase");if(n){const o=n.value;if(this.renderQuickStartCaseSelectOptions(n,this.getCasePickerOptions()),t.some(a=>a.name===o))n.value=o;else if(t.length>0){const a=t.find(i=>i.name==="testcase")||t[0];n.value=a.name,this.updateDirDisplayForCase(a.name),this.updateMobileCaseLabel(a.name),this.updateCasePickerInput(a.name)}}this.renderCasePickerList()}catch{}finally{this._casePickerRefreshInFlight=!1}}},closeCasePicker(){const e=document.getElementById("quickStartCaseSearch"),t=document.getElementById("quickStartCaseList");this._stopCasePickerRefresh(),this._casePickerOpen=!1,this._casePickerFilter="",e?.setAttribute("aria-expanded","false"),e?.removeAttribute("aria-activedescendant"),t?.classList.add("hidden")},renderCasePickerList(){const e=document.getElementById("quickStartCaseSearch"),t=document.getElementById("quickStartCaseList"),s=document.getElementById("quickStartCase");if(!e||!t||!s)return;const n=this.filterCasePickerOptions(this.getCasePickerOptions(),this._casePickerFilter||""),o=s.value||"testcase",a=n.length+CASE_PICKER_ACTIONS.length-1;this._casePickerActiveIndex=Math.min(Math.max(this._casePickerActiveIndex||0,0),a);const r=`<div class="case-combobox-actions" role="presentation">${CASE_PICKER_ACTIONS.map((c,u)=>{const l=n.length+u,d=l===this._casePickerActiveIndex;return`
2
- <button
3
- type="button"
4
- id="quickStartCaseOption-${l}"
5
- class="case-combobox-action ${d?"active":""}"
6
- role="option"
7
- aria-selected="false"
8
- data-case-action="${c.id}">
9
- <span class="case-combobox-action-icon" aria-hidden="true">${c.icon}</span>
10
- <span class="case-combobox-option-label">${escapeHtml(c.label)}</span>
11
- </button>
12
- `}).join("")}</div>`;if(n.length===0){t.innerHTML='<div class="case-combobox-empty">No cases match</div>'+r,t.classList.remove("hidden"),e.setAttribute("aria-activedescendant",`quickStartCaseOption-${this._casePickerActiveIndex}`);return}t.innerHTML=n.map((c,u)=>{const l=u===this._casePickerActiveIndex,d=c.name===o;return`
13
- <button
14
- type="button"
15
- id="${`quickStartCaseOption-${u}`}"
16
- class="case-combobox-option ${l?"active":""} ${d?"selected":""}"
17
- role="option"
18
- aria-selected="${d?"true":"false"}"
19
- data-case="${escapeHtml(c.name)}"
20
- title="${escapeHtml(c.label)}">
21
- <span class="case-combobox-check">${d?"\u2713":""}</span>
22
- <span class="case-combobox-option-label">${escapeHtml(c.label)}</span>
23
- </button>
24
- `}).join("")+r,t.classList.remove("hidden"),e.setAttribute("aria-activedescendant",`quickStartCaseOption-${this._casePickerActiveIndex}`)},runCasePickerAction(e){const t=CASE_PICKER_ACTIONS.find(n=>n.id===e);if(!t)return;const s=document.getElementById("quickStartCase");s&&this.updateCasePickerInput(s.value),this.closeCasePicker(),document.getElementById("quickStartCaseSearch")?.blur?.(),t.run(this)},selectQuickStartCase(e,{save:t=!0}={}){const s=document.getElementById("quickStartCase");if(!s)return;s.value=e||"testcase",this.updateCasePickerInput(s.value),this.closeCasePicker(),this.updateDirDisplayForCase(s.value),this.updateMobileCaseLabel(s.value);const n=(this.cases||[]).find(o=>o.name===s.value);n?.location==="docker"&&this._probeDockerCaseModes(n,null),t&&this.saveLastUsedCase(s.value)},setupQuickStartCasePicker(){const e=document.getElementById("quickStartCase"),t=document.getElementById("quickStartCaseSearch"),s=document.getElementById("quickStartCaseList"),n=document.getElementById("quickStartCasePicker");!e||!t||!s||!n||t.dataset.listenerAdded||(t.addEventListener("focus",()=>{t.select?.(),this.openCasePicker("")}),t.addEventListener("click",()=>{t.select?.(),this.openCasePicker("")}),t.addEventListener("input",()=>{this.openCasePicker(t.value)}),t.addEventListener("keydown",o=>{const a=this.filterCasePickerOptions(this.getCasePickerOptions(),this._casePickerFilter||t.value);if(o.key==="ArrowDown")o.preventDefault(),this._casePickerActiveIndex=Math.min((this._casePickerActiveIndex||0)+1,a.length+CASE_PICKER_ACTIONS.length-1),this._casePickerOpen?this.renderCasePickerList():this.openCasePicker(t.value);else if(o.key==="ArrowUp")o.preventDefault(),this._casePickerActiveIndex=Math.max((this._casePickerActiveIndex||0)-1,0),this._casePickerOpen?this.renderCasePickerList():this.openCasePicker(t.value);else if(o.key==="Enter"){const i=this._casePickerActiveIndex||0,r=a[i],c=this._casePickerOpen?CASE_PICKER_ACTIONS[i-a.length]:void 0;r?(o.preventDefault(),this.selectQuickStartCase(r.name),this.run?.()):c&&(o.preventDefault(),this.runCasePickerAction(c.id))}else o.key==="Escape"?(o.preventDefault(),this.updateCasePickerInput(e.value),this.closeCasePicker()):o.key==="Tab"&&(this.updateCasePickerInput(e.value),this.closeCasePicker())}),s.addEventListener("mousedown",o=>o.preventDefault()),s.addEventListener("click",o=>{const a=o.target.closest?.(".case-combobox-action");if(a?.dataset?.caseAction){this.runCasePickerAction(a.dataset.caseAction);return}const i=o.target.closest?.(".case-combobox-option");i?.dataset?.case&&this.selectQuickStartCase(i.dataset.case)}),document.addEventListener&&!this._casePickerDocumentListenerAdded&&(document.addEventListener("pointerdown",o=>{n.contains(o.target)||(this.updateCasePickerInput(e.value),this.closeCasePicker())}),this._casePickerDocumentListenerAdded=!0),t.dataset.listenerAdded="true")},async loadQuickStartCases(e=null,t=null){try{let s=null;try{const r=t?await t:await fetch("/api/settings").then(c=>c.ok?c.json():null).then(c=>c?.data??null);r&&(s=r.lastUsedCase||null)}catch{}const o=(await(await fetch("/api/cases")).json()).data;this.cases=o,console.log("[loadQuickStartCases] Loaded cases:",o.map(r=>r.name),"lastUsedCase:",s);const a=document.getElementById("quickStartCase"),i=this.getCasePickerOptions();if(this.renderQuickStartCaseSelectOptions(a,i),console.log("[loadQuickStartCases] Set options:",a.innerHTML.substring(0,200)),e)a.value=e,this.updateDirDisplayForCase(e),this.updateMobileCaseLabel(e);else if(s&&o.some(r=>r.name===s))a.value=s,this.updateDirDisplayForCase(s),this.updateMobileCaseLabel(s);else if(o.length>0){const r=o.find(c=>c.name==="testcase")||o[0];a.value=r.name,this.updateDirDisplayForCase(r.name),this.updateMobileCaseLabel(r.name)}else a.value="testcase",document.getElementById("dirDisplay").textContent="~/codeman-cases/testcase",this.updateMobileCaseLabel("testcase");this.updateCasePickerInput(a.value),this.renderCasePickerList(),this.closeCasePicker(),a.dataset.listenerAdded||(a.addEventListener("change",()=>{this.updateDirDisplayForCase(a.value),this.saveLastUsedCase(a.value),this.updateMobileCaseLabel(a.value),this.updateCasePickerInput(a.value)}),a.dataset.listenerAdded="true"),this.setupQuickStartCasePicker(),this._refreshMobileOverviewIfVisible?.()}catch(s){console.error("Failed to load cases:",s)}},async updateDirDisplayForCase(e){try{const s=(await(await fetch(`/api/cases/${e}`)).json()).data;s.path&&(document.getElementById("dirDisplay").textContent=s.path,document.getElementById("dirInput").value=s.path)}catch{document.getElementById("dirDisplay").textContent=e}},async saveLastUsedCase(e){try{await fetch("/api/settings",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({lastUsedCase:e})})}catch(t){console.error("Failed to save last used case:",t)}},async quickStart(){return this.run()},async _ensureCreatedSessionVisible(e,t){if(!e)return;let s=t;if(!s&&!this.sessions?.has(e)){const o=await(await fetch(`/api/sessions/${encodeURIComponent(e)}`)).json();if(!o.success)throw new Error(o.error||"Failed to load the new session");s=o.data?.session||o.data}s?.id&&this._onSessionCreated(s),this._joinTileGridFromRun?.(e),this._renderSessionTabsImmediate?.()},async run(){if(this._runInFlight)return;const e=Date.now(),t=Number.isFinite(this._runMinLockMs)?this._runMinLockMs:500,s=document.getElementById("runBtn");this._runInFlight=!0,s&&(s.disabled=!0,s.setAttribute("aria-busy","true"));try{const n=this._runMode||"claude";return n==="shell"?await this.runShell():n==="claude"||!isExternalCliRunMode(n)?await this.runClaude():await this._runCliMode(n)}finally{const n=t-(Date.now()-e);n>0&&await new Promise(o=>setTimeout(o,n)),this._runInFlight=!1,s&&(s.disabled=!1,s.removeAttribute("aria-busy"))}},setRunMode(e){this._runMode=e;try{localStorage.setItem("codeman_runMode",e)}catch{}this._applyRunMode(),this._apiPut("/api/settings",{runMode:e}).catch(()=>{}),document.getElementById("runModeMenu")?.classList.remove("active")},toggleRunModeMenu(e){e?.stopPropagation();const t=document.getElementById("runModeMenu");if(t&&(this.renderRegistryRunOptions(),t.classList.toggle("active"),t.querySelectorAll(".run-mode-option").forEach(s=>{s.classList.toggle("selected",s.dataset.mode===this.runMode)}),t.classList.contains("active"))){this._loadRunModeHistory(),this._refreshRunModeAvailability(t),this._refreshCustomModelRunOptions(t);const s=n=>{t.contains(n.target)||(t.classList.remove("active"),document.removeEventListener("click",s))};setTimeout(()=>document.addEventListener("click",s),0)}},_refreshRunModeAvailability(e){const t=document.getElementById("quickStartCase")?.value,s=t?(this.cases||[]).find(u=>u.name===t):null,n=s?.location==="docker",o=n&&(this._dockerCaseModes?.[t]||s.docker?.availableModes)||null;n&&!this._dockerCaseModes?.[t]&&this._probeDockerCaseModes(s,e);const a=n?this._dockerCaseProbeError?.[t]:null;for(const u of e.querySelectorAll(".run-mode-option[data-mode]")){const l=u.dataset.mode;if(!l||l==="shell")continue;let d;n?d=a?!1:o?o.includes(l):!0:d=this.isCliAvailable(l),u.style.display=d?"flex":"none"}this._renderRunModeNotice(e,a);const i=window.__codemanCliAvailable||{},r=e.querySelector("#runModeDeepSeekInstall");r&&(r.style.display=!i.deepseek&&i.deepseekBinary?"flex":"none");const c=e.querySelector("#runModeDeepSeekWeb");c&&(c.style.display=i.deepseekBinary?"flex":"none")},renderRegistryRunOptions(){const e=document.getElementById("runModeCliOptions");if(!e)return;const t=registryCliCatalog();if(t.length!==0){e.replaceChildren();for(const s of t){if(s.kind!=="agent"||!s.enabled)continue;const n=document.createElement("button");n.type="button",n.className="run-mode-option",n.dataset.mode=s.id,n.onclick=()=>this.setRunMode(s.id);const o=document.createElement("span");o.className=`run-mode-dot ${s.id}`,o.setAttribute("aria-hidden","true"),n.appendChild(o),n.append(s.label),e.appendChild(n)}}},async _refreshCustomModelRunOptions(e){const t=e.querySelector("#runModeCustomModelSep"),s=e.querySelector("#runModeCustomModelHeader"),n=e.querySelector("#runModeCustomModels");if(!n)return;const o=()=>{t&&(t.style.display="none"),s&&(s.style.display="none"),n.innerHTML=""},a=this.loadAppSettingsFromStorage(),i=(window.__codemanCustomModelClis||[]).filter(d=>this.isCliAvailable(d.id));if(!a.customModelEndpointsEnabled||i.length===0)return o();const r=document.getElementById("quickStartCase")?.value,c=r?(this.cases||[]).find(d=>d.name===r):null;if(c?.location==="remote"||c?.location==="docker")return o();const u=await this._apiJson("/api/model-endpoints");if(!Array.isArray(u)||u.length===0)return o();const l=[];for(const d of u){const m=d.models||[];if(m.length===0)continue;const p=d.defaultModelId||m[0];for(const h of i){const f=[h.id,d.id].map(g=>escapeHtml(JSON.stringify(g))).join(", ");l.push(`
25
- <button class="run-mode-option" data-mode="${escapeHtml(h.id)}" data-endpoint="${escapeHtml(d.id)}"
26
- onclick="app.selectCustomModelEntry(${f})"
27
- title="${escapeHtml(h.label)} \u2192 ${escapeHtml(d.baseUrl)} (${escapeHtml(p)}${m.length>1?`, +${m.length-1} more`:""})">
28
- <span class="run-mode-dot ${escapeHtml(h.id)}"></span>${escapeHtml(h.label)} (${escapeHtml(d.label)})
29
- </button>`)}}if(l.length===0)return o();t&&(t.style.display=""),s&&(s.style.display=""),n.innerHTML=l.join("")},async selectCustomModelEntry(e,t){document.getElementById("runModeMenu")?.classList.remove("active");const n=(await this._apiJson("/api/model-endpoints")||[]).find(a=>a.id===t);if(!n){this.showToast("That endpoint no longer exists","error");return}const o=n.models||[];if(o.length===0){this.showToast("No models discovered for this endpoint yet","warning");return}if(o.length===1)return this.runCustomModelEntry(e,t,o[0]);await this._openCustomModelPickModal(e,n)},_customModelLastUsedKey(e,t){return`codeman:customModelLastUsed:${e}:${t}`},_getCustomModelLastUsed(e,t){try{return localStorage.getItem(this._customModelLastUsedKey(e,t))}catch{return null}},_setCustomModelLastUsed(e,t,s){try{localStorage.setItem(this._customModelLastUsedKey(e,t),s)}catch{}},async _getCustomModelCurrentlyLoaded(e,t=800){const s=this._apiJson(`/api/model-endpoints/${encodeURIComponent(e.id)}/running-status`).catch(()=>null),n=new Promise(i=>setTimeout(()=>i(null),t)),o=await Promise.race([s,n]);return o?.isLlamaSwap&&(o.running||[]).find(i=>i.state==="ready"&&(e.models||[]).includes(i.model))?.model||null},async _openCustomModelPickModal(e,t){const s=document.getElementById("customModelPickModal"),n=document.getElementById("customModelPickList");if(!s||!n)return;const o=this._customModelPickGeneration=(this._customModelPickGeneration||0)+1,a=()=>this._customModelPickGeneration===o,i=await this._getCustomModelCurrentlyLoaded(t);if(!a())return;const r=i?null:this._getCustomModelLastUsed(e,t.id),c=i||r,u=[...t.models||[]];c&&u.includes(c)&&(u.splice(u.indexOf(c),1),u.unshift(c)),this._pendingCustomModelPick={mode:e,endpointId:t.id};const l=(window.__codemanCustomModelClis||[]).find(d=>d.id===e)?.label||e;document.getElementById("customModelPickTitle").textContent="Choose a model",document.getElementById("customModelPickHint").textContent=`${l} \u2192 ${t.label} \u2014 ${(t.models||[]).length} models discovered.`,n.innerHTML=u.map(d=>{const p=[d===i?"Currently loaded":d===r?"Last used":null,d===t.defaultModelId?"Default":null].filter(Boolean);return`
30
- <button class="run-mode-option" onclick="app.chooseCustomModelAndRun(${escapeHtml(JSON.stringify(d))})">
31
- <span class="run-mode-dot ${escapeHtml(e)}"></span>${escapeHtml(d)}${p.map(f=>` <span class="set-scope">${escapeHtml(f)}</span>`).join("")}
32
- </button>`}).join(""),s.classList.add("active")},closeCustomModelPickModal(){document.getElementById("customModelPickModal")?.classList.remove("active"),this._pendingCustomModelPick=null},_confirmModelSwap(e){const t=document.getElementById("customModelSwapConfirmModal"),s=document.getElementById("customModelSwapConfirmMessage");return s&&(s.textContent=e),t?.classList.add("active"),new Promise(n=>{this._resolveModelSwapConfirmPromise=n})},_resolveModelSwapConfirm(e){document.getElementById("customModelSwapConfirmModal")?.classList.remove("active");const t=this._resolveModelSwapConfirmPromise;this._resolveModelSwapConfirmPromise=null,t?.(e)},_confirmContextWarning(e,t,s){const n=document.getElementById("customModelContextWarningModal"),o=document.getElementById("customModelContextWarningMessage");if(o){const a=typeof t=="number";o.textContent=`${e} is configured with `+(a?`only ${t.toLocaleString()} tokens of`:"an unknown (too small)")+` context, but this CLI needs roughly ${s.toLocaleString()}+ tokens just for its own system prompt and tools \u2014 before any conversation history. Its very first message will fail outright, no matter what context size Codeman tells it to expect.
33
-
34
- To fix this, reconfigure llama-swap to give this model (or a smaller one) an explicit larger context instead of relying on auto-fit (--fit-ctx), which optimizes for the biggest MODEL that fits, not the biggest CONTEXT \u2014 e.g. add "-c 65536" (or as large a --ctx-size as your hardware holds) to its llama-swap config entry. A smaller model at a much larger explicit context often fits in the same VRAM a bigger model's auto-fit context gets shrunk to make room for.`}return n?.classList.add("active"),new Promise(a=>{this._resolveContextWarningConfirmPromise=a})},_resolveContextWarningConfirm(e){document.getElementById("customModelContextWarningModal")?.classList.remove("active");const t=this._resolveContextWarningConfirmPromise;this._resolveContextWarningConfirmPromise=null,t?.(e)},chooseCustomModelAndRun(e){const t=this._pendingCustomModelPick;this.closeCustomModelPickModal(),t&&this.runCustomModelEntry(t.mode,t.endpointId,e)},async runCustomModelEntry(e,t,s){return e==="claude"?this._runCustomModelEntryViaRestart(e,t,s):this._runCustomModelEntryOneShot(e,t,s)},async _runCustomModelEntryOneShot(e,t,s){document.getElementById("runModeMenu")?.classList.remove("active");const n=this._runMode,o=document.getElementById("tabCount"),a=o?.value;this._runMode=e,this._pendingCustomModelForLaunch={endpointId:t,modelId:s},o&&(o.value="1");try{await this.run()}finally{this._runMode=n,this._pendingCustomModelForLaunch=void 0,o&&a!==void 0&&(o.value=a)}const i=this._lastCustomModelLaunchResult;this._lastCustomModelLaunchResult=void 0,i?.modelSwapInProgress&&this._watchLlamaSwapLoading(t,s,i.sessionId)},async _quickStartWithCustomModelConfirm(e){const t=async a=>(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).json();let s={},n=await t(e);if(n?.data?.requiresContextWarning){const{modelId:a,contextLength:i,minSafeContextTokens:r}=n.data;if(!await this._confirmContextWarning(a,i,r))return this._lastCustomModelLaunchResult=void 0,{success:!1,error:"Launch cancelled \u2014 context window too small"};s={...s,confirmedContext:!0},n=await t({...e,customModel:{...e.customModel,...s}})}if(n?.data?.requiresConfirmation){const{currentlyLoadedModel:a,affectedSessions:i}=n.data,r=i.map(d=>d.name||d.id).join(", "),c=r?`${r} ${i.length===1?"is":"are"} currently using`:"Another session on this endpoint is currently using",u=r&&i.length>1?"those sessions":"that session";if(!await this._confirmModelSwap(`${c} ${a} on this endpoint. Switching will unload it for ${u} too. Continue?`))return this._lastCustomModelLaunchResult=void 0,{success:!1,error:"Model switch cancelled"};s={...s,confirmedSwap:!0},n=await t({...e,customModel:{...e.customModel,...s}})}const o=n?.success!==!1;return this._lastCustomModelLaunchResult=o?n?.data:void 0,o&&e.customModel&&this._setCustomModelLastUsed(e.mode,e.customModel.endpointId,e.customModel.modelId),n},async _runCustomModelEntryViaRestart(e,t,s){document.getElementById("runModeMenu")?.classList.remove("active");const n=this._runMode,o=this.activeSessionId,a=document.getElementById("tabCount"),i=a?.value;this._runMode=e,a&&(a.value="1");try{await this.run()}finally{this._runMode=n,a&&i!==void 0&&(a.value=i)}const r=this.activeSessionId;if(!r||r===o)return;const c=this._showCenterStatus(`Claude started \u2014 switching to ${t}\u2026`);await this._apiJson(`/api/sessions/${r}/wait?until=idle&timeout=20000`);let{ok:u,data:l,res:d}=await this._applyCustomModelToSession(r,t,s),m=l?.success!==!1?l?.data:void 0,p={};if(u&&m?.requiresContextWarning){if(!await this._confirmContextWarning(m.modelId,m.contextLength,m.minSafeContextTokens)){c?.dismiss(),this.showToast("Kept the native backend \u2014 context window too small","info");return}p={...p,confirmedContext:!0},{ok:u,data:l,res:d}=await this._applyCustomModelToSession(r,t,s,p),m=l?.success!==!1?l?.data:void 0}if(u&&m?.requiresConfirmation){const h=m.affectedSessions.map(b=>b.name||b.id).join(", "),f=h?`${h} ${m.affectedSessions.length===1?"is":"are"} currently using`:"Another session on this endpoint is currently using",g=h&&m.affectedSessions.length>1?"those sessions":"that session";if(!await this._confirmModelSwap(`${f} ${m.currentlyLoadedModel} on this endpoint. Switching to ${s} will unload it for ${g} too. Continue?`)){c?.dismiss(),this.showToast("Kept the native backend \u2014 model switch cancelled","info");return}p={...p,confirmedSwap:!0},{ok:u,data:l,res:d}=await this._applyCustomModelToSession(r,t,s,p),m=l?.success!==!1?l?.data:void 0}if(!u||!l||l.success===!1){c?.dismiss();const h=l?.error?`: ${l.error}`:d?` (HTTP ${d.status})`:" (request failed)";this.showToast(`Session started on the native backend \u2014 could not apply the custom endpoint${h}`,"error",{duration:0});return}if(this._setCustomModelLastUsed(e,t,s),m?.modelSwapInProgress){c?.dismiss(),this._watchLlamaSwapLoading(t,s,r);return}c?.setMessage(`Pointed at ${t} \u2014 restarting the session...`),setTimeout(()=>c?.dismiss(),3e3)},async _applyCustomModelToSession(e,t,s,n){const o=await this._api(`/api/sessions/${e}/custom-model`,{method:"POST",body:{endpointId:t,modelId:s,...n||{}}}),a=o?await o.json().catch(()=>null):null;return{ok:!!o,data:a,res:o}},async _lookupModelSizeGB(e,t){const s=await this._apiJson("/api/model-endpoints").catch(()=>null);if(!Array.isArray(s))return;const o=s.find(a=>a.id===e)?.modelSizesGB?.[t];return typeof o=="number"&&Number.isFinite(o)&&o>0?o:void 0},_formatLlamaLogLine(e){return typeof e=="string"?e.replace(/^[\d.]+\s+[IWE]\s+\S+\s+/,""):e},async _watchLlamaSwapLoading(e,t,s,n=1e3){const o=this._watchLlamaSwapGeneration=(this._watchLlamaSwapGeneration||0)+1,a=()=>this._watchLlamaSwapGeneration===o,i=await this._lookupModelSizeGB(e,t);if(!a())return;const r=i?` (${i.toFixed(1)} GB)`:"",c=`Loading ${t}${r} on ${e} \u2014 this can take a while depending on your hardware and the model size.`,u=m=>{const p=this._formatLlamaLogLine(m);return c+(p?`
35
- llama.cpp: ${p}`:"")};let l=!1;const d=this._showCenterStatus(u(),{onCancel:()=>{l=!0}});for(;!l;){const m=await this._apiJson(`/api/model-endpoints/${encodeURIComponent(e)}/running-status`);if(!a())return;if(l)break;if(m)if(m.isLlamaSwap){if(m.running.some(p=>p.model===t&&p.state==="ready")){d?.dismiss(),this.showToast(`${t} is ready`,"success",{duration:2500});return}}else{d?.dismiss();return}if(!a()||l)break;d?.setMessage(u(m?.logLine)),await new Promise(p=>setTimeout(p,n))}if(a()&&(d?.dismiss(),this.showToast(`Cancelled loading ${t} on ${e}`+(s?" \u2014 the session has been closed.":"."),"info"),s))try{await this.closeSession(s)}catch{}},async runDeepSeekWeb(){document.getElementById("runModeMenu")?.classList.remove("active");const e=this._beginSessionLaunchStatus("Starting the DeepSeek web UI...");try{const s=await(await fetch("/api/deepseek/web",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({authority:location.host})})).json();if(!s.success)throw new Error(s.error||"Failed to start the DeepSeek web UI");const n=s.data.url;let o=[...this.webviews?.values()||[]].find(a=>a.managed==="deepseek-web");if(o){const i=await(await fetch(`/api/webviews/${o.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:n,trusted:!0})})).json();if(!i.success)throw new Error(i.error||"Failed to update the web tab");o=i.data.webview||i.data}else{const i=await(await fetch("/api/webviews",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"DeepSeek Harness",url:n,icon:"\u{1F433}",managed:"deepseek-web",trusted:!0})})).json();if(!i.success)throw new Error(i.error||"Failed to save the web tab");o=i.data.webview||i.data}await this.refreshWebviews?.(),this._appendSessionLaunchStatus(e,`Serving on ${n} - opening it as a tab.`),o?.id&&await this.openWebview(o.id)}catch(t){this._reportSessionLaunchError(e,t.message)}},async installDeepSeekProfile(){const t=this._beginSessionLaunchStatus("Installing a DeepSeek terminal profile (this can take a minute)...");try{const n=await(await fetch("/api/deepseek/install-profile",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({})})).json();if(!n.success)throw new Error(n.error||"Failed to install the profile");window.__codemanCliAvailable={...window.__codemanCliAvailable||{},deepseek:!!n.data.runnable},this._appendSessionLaunchStatus(t,`Installed ${n.data.package} into profile "${n.data.profile}".`),this.showToast?.(`DeepSeek profile "${n.data.profile}" installed`,"success");const o=document.getElementById("runModeMenu");o&&this._refreshRunModeAvailability(o)}catch(s){this._reportSessionLaunchError(t,s.message)}},_renderRunModeNotice(e,t){if(!e)return;let s=e.querySelector(".run-mode-notice");if(!t){s?.remove();return}s||(s=document.createElement("div"),s.className="run-mode-notice",e.prepend(s)),s.textContent=t},async _probeDockerCaseModes(e,t){const s=e?.name,n=e?.docker?.container,o=e?.docker?.hostId;if(!(!s||!n||!o)&&(this._dockerCaseModes=this._dockerCaseModes||{},!this._dockerModeProbeInFlight?.[s])){this._dockerModeProbeInFlight=this._dockerModeProbeInFlight||{},this._dockerModeProbeInFlight[s]=!0;try{const a=await this._apiJson("/api/docker-cases/adopt-preflight",{method:"POST",body:{hostId:o,container:n}});a?.ok&&Array.isArray(a.availableModes)?(this._dockerCaseModes[s]=a.availableModes,delete this._dockerCaseProbeError?.[s]):(e?.docker?.owned===!1&&(this._dockerCaseProbeError=this._dockerCaseProbeError||{},this._dockerCaseProbeError[s]=a?.error||`Could not read container "${n}".`),delete this._dockerCaseModes[s]),t?.classList.contains("active")&&this._refreshRunModeAvailability(t)}finally{delete this._dockerModeProbeInFlight[s]}}},async _loadRunModeHistory(){const e=document.getElementById("runModeHistory");if(e){e.innerHTML='<div class="run-mode-hist-empty">Loading...</div>';try{const t=await this._fetchHistorySessions(10);if(t.length===0){e.innerHTML='<div class="run-mode-hist-empty">No history</div>';return}e.replaceChildren();for(const s of t){const n=new Date(s.lastModified),o=n.toLocaleDateString("en",{month:"short",day:"numeric"})+" "+n.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit",hour12:!1}),a=this._shortenHomePath(s.workingDir),i=a.lastIndexOf("/"),r=i===-1?a:a.slice(i+1),c=(i===-1?"":a.slice(0,i)).replace(/\/\.claude\/worktrees$/,""),u=document.createElement("button");u.className="run-mode-option run-mode-hist-row",u.title=s.workingDir,u.dataset.sessionId=s.sessionId,u.dataset.workingDir=s.workingDir;const l=document.createElement("span");l.className="hist-name",l.textContent=r;const d=[l],m=this._worktreeLabel?this._worktreeLabel(s):"";if(m){const h=document.createElement("span");h.className="hist-wt",h.textContent=m,d.push(h)}if(c){const h=document.createElement("span");h.className="hist-dir",h.textContent=c,d.push(h)}const p=document.createElement("span");p.className="hist-meta",p.textContent=o,d.push(p),u.append(...d),u.addEventListener("click",h=>{h.stopPropagation(),this.resumeHistorySession(s.sessionId,s.workingDir,s.name,s.mode,s.resumeId)}),e.appendChild(u)}}catch{e.innerHTML='<div class="run-mode-hist-empty">Failed to load</div>'}}},_applyRunMode(){const e=this.runMode,t=document.getElementById("runBtn"),s=t?.nextElementSibling,n=document.getElementById("runBtnLabel");if(t&&(t.className=`btn-toolbar btn-run mode-${e}`),s&&(s.className=`btn-toolbar btn-run-gear mode-${e}`),n){const o=registryCliById(e);n.textContent=e==="opencode"?"Run OC":e==="codex"?"Run CX":e==="gemini"?"Run GM":e==="antigravity"?"Run AG":e==="pi"?"Run PI":e==="grok"?"Run GK":e==="deepseek"?"Run DS":e==="omp"?"Run OMP":e==="shell"?"Run SH":o?`Run ${o.shortBadge}`:"Run"}},sendEnterKey(){if(!this.activeSessionId)return;const e=this.terminal?._core?.coreService;if(e&&typeof e.triggerDataEvent=="function"){e.triggerDataEvent("\r",!0);return}this.sendInput("\r")},_initRunMode(){this.renderRegistryRunOptions();let e="claude";try{e=localStorage.getItem("codeman_runMode")||"claude"}catch{}this.runMode=e,this._applyRunMode()},incrementTabCount(){const e=document.getElementById("tabCount"),t=parseInt(e.value)||1;e.value=Math.min(20,t+1)},decrementTabCount(){const e=document.getElementById("tabCount"),t=parseInt(e.value)||1;e.value=Math.max(1,t-1)},_nextCaseSessionStartNumber(e,t="w"){const s=new RegExp(`^${t}(\\d+)-([a-zA-Z0-9_-]+)`);let n=1;for(const[,o]of this.sessions||[]){const a=o.name&&o.name.match(s);if(a&&a[2]===e){const i=parseInt(a[1]);i>=n&&(n=i+1)}}return n},_beginSessionLaunchStatus(e,t="1;32"){const s=!this.activeSessionId;return s?(this.terminal.clear(),this.terminal.writeln(`\x1B[${t}m ${e}\x1B[0m`),this.terminal.writeln("")):this.showToast?.(e,"info"),s},_appendSessionLaunchStatus(e,t,s="90"){!e||this.activeSessionId||this.terminal.writeln(`\x1B[${s}m ${t}\x1B[0m`)},_reportSessionLaunchError(e,t){e&&!this.activeSessionId?this.terminal.writeln(`\x1B[1;31m Error: ${t}\x1B[0m`):this.showToast?.(t,"error")},async runClaude(){const e=document.getElementById("quickStartCase").value||"testcase",t=this._readTabCount(),s=this._beginSessionLaunchStatus(`Starting ${t} Claude session(s) in ${e}...`);this.terminal.focus();try{const o=await(await fetch(`/api/cases/${e}`)).json();let a=o?.data??{};if(!a.path){if(o?.errorCode!=="NOT_FOUND")throw new Error(o?.error||"Case lookup failed");const C=await(await fetch("/api/cases",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,description:""})})).json();if(!C.success)throw new Error(C.error||"Failed to create case");a=C.data.case}const i=a.path;if(!i)throw new Error("Case path not found");if(a.location==="remote"||a.location==="docker"){const k=this._nextCaseSessionStartNumber(e);let C;if(a.location==="docker"){const S=this.loadAppSettingsFromStorage(),B=this.getCaseSettings(e).opusContext1m||S.opusContext1mEnabled;C=S.claudeModel||(B?"opus[1m]":"")}const M=[];let _=!1;for(let S=0;S<t;S++){const T=JSON.stringify({caseName:e,mode:"claude",sessionName:`w${k+S}-${e}`,...C!==void 0?{modelOverride:C}:{}}),B=async()=>(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:T})).json();let E=await B();if(!E.success&&E.errorCode==="CONFLICT"&&a.location==="docker"&&!_&&(_=!0,confirm(`Container config for "${e}" changed since its container was created.
36
-
37
- Recreate the container to apply the new config? Workspace files and the conversation survive (the conversation resumes on launch).`))){const P=await(await fetch(`/api/docker-cases/${encodeURIComponent(e)}/recreate`,{method:"POST"})).json();if(!P.success)throw new Error(P.error||"Failed to recreate container");E=await B()}if(!E.success)throw new Error(E.error||"Failed to start remote Claude session");await this._ensureCreatedSessionVisible(E.data.sessionId,E.data.session),M.push(E.data.sessionId)}this._appendSessionLaunchStatus(s,`All ${t} remote session(s) ready`),M[0]&&(await this.selectSession(M[0]),this.loadQuickStartCases()),this.terminal.focus();return}let r=null;const c=this._nextCaseSessionStartNumber(e),u=this.isRalphTrackerEnabledByDefault(),l=[];for(let k=0;k<t;k++)l.push(`w${c+k}-${e}`);const d=this.getCaseSettings(e),m=this.loadAppSettingsFromStorage(),p=this.buildEnvOverrides(d,m),h=Object.keys(p).length>0,f=this.getEffortSetting(m),g=this.getAdvisorSetting(m),y=d.opusContext1m||m.opusContext1mEnabled,b=m.claudeModel||(y?"opus[1m]":"");this._appendSessionLaunchStatus(s,`Creating ${t} session(s)...`);const w=l.map(k=>fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workingDir:i,name:k,...h?{envOverrides:p}:{},...f?{effort:f}:{},...g?{advisorModel:g}:{},...b!==void 0?{modelOverride:b}:{}})}).then(C=>C.json())),I=await Promise.all(w),v=[];for(const k of I){if(!k.success)throw new Error(k.error);await this._ensureCreatedSessionVisible(k.data.session.id,k.data.session),v.push(k.data.session.id)}r=v[0],await Promise.all(v.map(k=>fetch(`/api/sessions/${k}/ralph-config`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:u,disableAutoEnable:!u})}))),this._appendSessionLaunchStatus(s,`Starting ${t} session(s) in parallel...`),await Promise.all(v.map(k=>fetch(`/api/sessions/${k}/interactive`,{method:"POST"}))),this._appendSessionLaunchStatus(s,`All ${t} sessions ready`),r&&(await this.selectSession(r),this.loadQuickStartCases()),this.terminal.focus()}catch(n){this._reportSessionLaunchError(s,n.message)}},stopClaude(){if(!this.activeSessionId)return;const e=document.querySelector(".btn-toolbar.btn-stop");e&&(this._stopConfirmTimer?(clearTimeout(this._stopConfirmTimer),this._stopConfirmTimer=null,e.innerHTML=e.dataset.origHtml,delete e.dataset.origHtml,e.classList.remove("confirming"),fetch(`/api/sessions/${this.activeSessionId}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:""})})):(e.dataset.origHtml=e.innerHTML,e.textContent="Tap again",e.classList.add("confirming"),this._stopConfirmTimer=setTimeout(()=>{this._stopConfirmTimer=null,e.dataset.origHtml&&(e.innerHTML=e.dataset.origHtml,delete e.dataset.origHtml),e.classList.remove("confirming")},2e3)))},async runShell(){const e=document.getElementById("quickStartCase").value||"testcase",t=this._readTabCount(),s=this._beginSessionLaunchStatus(`Starting ${t} Shell session(s) in ${e}...`,"1;33");try{const o=await(await fetch(`/api/cases/${e}`)).json();let a=o?.data??{};if(!a.path){if(o?.errorCode!=="NOT_FOUND")throw new Error(o?.error||"Case lookup failed");const g=await(await fetch("/api/cases",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,description:""})})).json();if(!g.success)throw new Error(g.error||"Failed to create case");a=g.data.case}const i=(this.cases||[]).find(f=>f.name===e),r=a.location==="remote"||a.location==="docker"||i?.location==="remote"||i?.location==="docker",c=a.path;if(!c)throw new Error("Case path not found");if(a.location==="remote"||a.location==="docker"){const f=this._nextCaseSessionStartNumber(e,"s"),g=[];for(let y=0;y<t;y++){const w=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"shell",sessionName:`s${f+y}-${e}`})})).json();if(!w.success)throw new Error(w.error||"Failed to start remote shell session");await this._ensureCreatedSessionVisible(w.data.sessionId,w.data.session),g.push(w.data.sessionId)}g[0]&&await this.selectSession(g[0]),this.terminal.focus();return}const u=this._nextCaseSessionStartNumber(e,"s"),l=[];for(let f=0;f<t;f++)l.push(`s${u+f}-${e}`);const d=l.map(f=>fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...r?{caseName:e}:{workingDir:c},mode:"shell",name:f})}).then(g=>g.json())),m=await Promise.all(d),p=[];for(const f of m){if(!f.success)throw new Error(f.error);await this._ensureCreatedSessionVisible(f.data.session.id,f.data.session),p.push(f.data.session.id)}await Promise.all(p.map(f=>fetch(`/api/sessions/${f}/shell`,{method:"POST"})));const h=this.getTerminalDimensions();h&&await Promise.all(p.map(f=>fetch(`/api/sessions/${f}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(h)}))),p.length>0&&await this.selectSession(p[0]),this.terminal.focus()}catch(n){this._reportSessionLaunchError(s,n.message)}},_readTabCount(){return Math.min(20,Math.max(1,parseInt(document.getElementById("tabCount")?.value)||1))},async _launchQuickStartInstances(e,t,s,n,o){const a=this._nextCaseSessionStartNumber(e);let i=null,r=!1;for(let c=0;c<t;c++){const u=`w${a+c}-${e}`,l=n(u),d=await this._quickStartWithCustomModelConfirm(r&&l.customModel?{...l,customModel:{...l.customModel,confirmedContext:!0,confirmedSwap:!0}}:l);if(!d.success)throw new Error(d.error||`Failed to start ${s}`);r=!0,await this._ensureCreatedSessionVisible(d.data.sessionId,d.data.session),i||(i=d.data.sessionId)}return t>1&&this._appendSessionLaunchStatus(o,`All ${t} ${s} session(s) ready`),i},async _runCliMode(e){const t=registryCliById(e),s=RUN_MODE_LAUNCH[e]||t&&{label:t.label,installHint:`${t.label} is not available on this host.`,supportsCustomModel:!1,buildConfig:()=>null};if(!s)throw new Error(`Unknown run mode: ${e}`);const n=document.getElementById("quickStartCase").value||"testcase",o=(this.cases||[]).find(c=>c.name===n)?.location,a=o==="remote"||o==="docker",i=this._readTabCount(),r=this._beginSessionLaunchStatus(`Starting ${i} ${s.label} session(s) in ${n}...`);this.terminal.focus();try{if(!a&&RUN_MODE_LAUNCH[e]){const m=(await(await fetch(`/api/${e}/status`)).json()).data;if(!m.available){this._reportSessionLaunchError(r,s.installHint);return}if(s.unrunnableHint&&!m.runnable){this._reportSessionLaunchError(r,s.unrunnableHint);return}}else if(!a&&!this.isCliAvailable(e)){this._reportSessionLaunchError(r,s.installHint);return}const c=this.loadAppSettingsFromStorage(),u=this.buildEnvOverrides(this.getCaseSettings(n),c),l=await this._launchQuickStartInstances(n,i,s.label,d=>({caseName:n,mode:e,sessionName:d,...a?{}:{...s.buildConfig(c)||{},...Object.keys(u).length>0?{envOverrides:u}:{},...s.supportsCustomModel&&this._pendingCustomModelForLaunch?{customModel:this._pendingCustomModelForLaunch}:{}}}),r);l&&await this.selectSession(l),this.terminal.focus()}catch(c){this._reportSessionLaunchError(r,c.message)}},async runOpenCode(){return this._runCliMode("opencode")},async runCodex(){return this._runCliMode("codex")},async runGemini(){return this._runCliMode("gemini")},async runAntigravity(){return this._runCliMode("antigravity")},async runPi(){return this._runCliMode("pi")},async runOmp(){return this._runCliMode("omp")},async runGrok(){return this._runCliMode("grok")},async runDeepSeek(){return this._runCliMode("deepseek")},_tabDetachOverrides(){if(this._tabDetachOverrideMap===void 0)try{this._tabDetachOverrideMap=JSON.parse(localStorage.getItem("codeman:tab-detach-overrides")||"{}")||{}}catch{this._tabDetachOverrideMap={}}return this._tabDetachOverrideMap},hasTabDetachOverride(e){return!!this._tabDetachOverrides()[e]},onSessionTabDetachToggle(e){const t=this.editingSessionId;if(!t)return;const s=this._tabDetachOverrides();e?s[t]=1:delete s[t];for(const o of Object.keys(s))o!==t&&this.sessions&&!this.sessions.has(o)&&delete s[o];try{localStorage.setItem("codeman:tab-detach-overrides",JSON.stringify(s))}catch{}const n=document.querySelector(`.session-tab[data-id="${CSS.escape(t)}"]`);n&&n.classList.toggle("tab-show-detach",!!e)},openSessionOptions(e){const t=this.sessions.get(e);if(!t)return;this.editingSessionId=e;const s=document.getElementById("sessionOptShowTabDetach");s&&(s.checked=this.hasTabDetachOverride(e));const n=isExternalCliSession(t.mode);this.switchOptionsTab(n?"summary":"respawn");const o=document.getElementById("sessionRespawnStatus"),a=document.getElementById("modalEnableRespawnBtn"),i=document.getElementById("modalStopRespawnBtn");this.respawnStatus[e]?(o.classList.add("active"),o.querySelector(".respawn-status-text").textContent=this.respawnStatus[e].state||"Active",a.style.display="none",i.style.display=""):(o.classList.remove("active"),o.querySelector(".respawn-status-text").textContent="Not active",a.style.display="",i.style.display="none");const r=document.getElementById("sessionRespawnSection");t.mode==="claude"&&t.pid?r.style.display="":r.style.display="none";const c=n;document.querySelectorAll("[data-claude-only]").forEach(y=>{y.style.display=c?"none":""}),this.selectDurationPreset(""),this.loadSavedRespawnConfig(e),document.getElementById("modalAutoCompactEnabled").checked=t.autoCompactEnabled??!1,document.getElementById("modalAutoCompactThreshold").value=t.autoCompactThreshold??11e4,document.getElementById("modalAutoCompactPrompt").value=t.autoCompactPrompt??"",document.getElementById("modalAutoClearEnabled").checked=t.autoClearEnabled??!1,document.getElementById("modalAutoClearThreshold").value=t.autoClearThreshold??14e4,document.getElementById("modalAutoResumeEnabled").checked=t.autoResumeEnabled??!1,this.updateAutoResumeStatus(e),document.getElementById("modalImageWatcherEnabled").checked=t.imageWatcherEnabled??!0,document.getElementById("modalFlickerFilterEnabled").checked=t.flickerFilterEnabled??!1;const l=parseSessionPrefix(t.name),d=document.getElementById("modalSessionPrefix");l?(d.textContent=l.prefix+": ",d.style.display="",document.getElementById("modalSessionName").value=l.suffix,document.getElementById("modalSessionName").placeholder="Add description..."):(d.style.display="none",d.textContent="",document.getElementById("modalSessionName").value=t.name||"",document.getElementById("modalSessionName").placeholder="Auto (directory name)");const m=t.color||"default";document.getElementById("sessionColorPicker")?.querySelectorAll(".color-swatch").forEach(y=>{y.classList.toggle("selected",y.dataset.color===m)}),this.renderPresetDropdown(),document.getElementById("respawnPresetSelect").value="",document.getElementById("presetDescriptionHint").textContent="";const h=document.querySelector('#sessionOptionsModal .set-rail-item[data-tab="ralph"]'),f=document.querySelector('#sessionOptionsModal .set-rail-item[data-tab="respawn"]');if(c?(h&&(h.style.display="none"),f&&(f.style.display="none"),this.switchOptionsTab("context")):(h&&(h.style.display=""),f&&(f.style.display="")),!c){const y=this.ralphStates.get(e);this.populateRalphForm({enabled:y?.loop?.enabled??t.ralphLoop?.enabled??!1,completionPhrase:y?.loop?.completionPhrase||t.ralphLoop?.completionPhrase||"",maxIterations:y?.loop?.maxIterations||t.ralphLoop?.maxIterations||0,maxTodos:y?.loop?.maxTodos||t.ralphLoop?.maxTodos,todoExpirationMinutes:y?.loop?.todoExpirationMinutes||t.ralphLoop?.todoExpirationMinutes})}const g=document.getElementById("sessionOptionsModal");g.dataset.chipsReady!=="1"&&(g.dataset.chipsReady="1",g.addEventListener("change",y=>{y.target?.closest?.(".set-chip")&&this._syncSettingsChips()})),this._syncSettingsChips(),g.classList.add("active"),this.activeFocusTrap=new FocusTrap(g),this.activeFocusTrap.activate()},_applyLocalSessionName(e,t){if(typeof t!="string")return;const s=this.sessions.get(e);s&&(s.name=t,this.sessions.set(e,s),this.updateSubagentParentNames?.(e))},async _putSessionName(e,t){const s=await this._apiPut(`/api/sessions/${e}/name`,{name:t});if(!s||!s.ok)return null;let n=null;try{n=await s.json()}catch{return null}if(n&&n.success===!1)return null;const o=n?.data?.name;return typeof o=="string"?o:t},_queueInlineSessionName(e,t){this._inlineRenameWrites??=new Map,this._inlineRenamePending??=new Map;const s=this._inlineRenameWrites,n=this._inlineRenamePending;n.set(e,t);const a=(s.get(e)||Promise.resolve()).catch(()=>{}).then(async()=>{const r=this.sessions.get(e);if(!r)return{status:"deleted"};if(r.name===t)return{status:"confirmed"};let c=null;try{c=await this._putSessionName(e,t)}catch{}if(!this.sessions.has(e))return{status:"deleted"};if(c===null)return this.showToast("Failed to rename","error"),{status:"failed"};try{this._applyLocalSessionName(e,c),this.renderSessionTabs()}catch(u){console.error("[rename] applying the confirmed name failed",u)}return{status:"confirmed"}});s.set(e,a);const i=()=>{s.get(e)===a&&(s.delete(e),n.delete(e))};return a.then(i,i),a},async saveSessionName(){if(!this.editingSessionId)return;const e=this.editingSessionId,t=this.sessions.get(e),s=t?parseSessionPrefix(t.name):null,n=document.getElementById("modalSessionName").value.trim();let o;s?o=s.prefix+(n?": "+n:""):o=n;const a=await this._putSessionName(e,o);if(a===null){this.showToast("Failed to save session name","error");return}this._applyLocalSessionName(e,a),this.renderSessionTabs()},async autoSaveAutoCompact(){if(this.editingSessionId)try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-compact`,{enabled:document.getElementById("modalAutoCompactEnabled").checked,threshold:parseInt(document.getElementById("modalAutoCompactThreshold").value)||11e4,prompt:document.getElementById("modalAutoCompactPrompt").value.trim()||void 0})}catch{}},async autoSaveAutoClear(){if(this.editingSessionId)try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-clear`,{enabled:document.getElementById("modalAutoClearEnabled").checked,threshold:parseInt(document.getElementById("modalAutoClearThreshold").value)||14e4})}catch{}},async autoSaveAutoResume(){if(!this.editingSessionId)return;const e=document.getElementById("modalAutoResumeEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-resume`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.autoResumeEnabled=e,e||(t.autoResumeAt=void 0)),this.updateAutoResumeStatus(this.editingSessionId),this.showToast(`Auto-resume on usage limit ${e?"enabled":"disabled"}`,"success")}catch(t){this.showToast("Failed to toggle auto-resume: "+t.message,"error")}},updateAutoResumeStatus(e){const t=document.getElementById("autoResumeStatus");if(!t||this.editingSessionId!==e)return;const s=this.sessions.get(e);if(s?.autoResumeAt&&s.autoResumeAt>Date.now()){const n=new Date(s.autoResumeAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});t.textContent=`Usage limit pause active \u2014 resumes at ${n}`,t.classList.add("active")}else t.textContent="",t.classList.remove("active")},async toggleSessionImageWatcher(){if(!this.editingSessionId)return;const e=document.getElementById("modalImageWatcherEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/image-watcher`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.imageWatcherEnabled=e),this.showToast(`Image watcher ${e?"enabled":"disabled"}`,"success")}catch{this.showToast("Failed to toggle image watcher","error")}},async toggleFlickerFilter(){if(!this.editingSessionId)return;const e=document.getElementById("modalFlickerFilterEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/flicker-filter`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.flickerFilterEnabled=e),this.showToast(`Flicker filter ${e?"enabled":"disabled"}`,"success")}catch{this.showToast("Failed to toggle flicker filter","error")}},async autoSaveRespawnConfig(){if(!this.editingSessionId)return;const e={updatePrompt:document.getElementById("modalRespawnPrompt").value,sendClear:document.getElementById("modalRespawnSendClear").checked,sendInit:document.getElementById("modalRespawnSendInit").checked,kickstartPrompt:document.getElementById("modalRespawnKickstart").value.trim()||void 0,autoAcceptPrompts:document.getElementById("modalRespawnAutoAccept").checked};try{await this._apiPut(`/api/sessions/${this.editingSessionId}/respawn/config`,e)}catch{}},async loadSavedRespawnConfig(e){try{const s=await(await fetch(`/api/sessions/${e}/respawn/config`)).json();if(s.success&&s.data&&s.data.config){const n=s.data.config;document.getElementById("modalRespawnPrompt").value=n.updatePrompt||"update all the docs and CLAUDE.md",document.getElementById("modalRespawnSendClear").checked=n.sendClear??!0,document.getElementById("modalRespawnSendInit").checked=n.sendInit??!0,document.getElementById("modalRespawnKickstart").value=n.kickstartPrompt||"",document.getElementById("modalRespawnAutoAccept").checked=n.autoAcceptPrompts??!0,n.durationMinutes&&(document.querySelector(`.duration-preset-btn[data-minutes="${n.durationMinutes}"]`)?this.selectDurationPreset(String(n.durationMinutes)):(this.selectDurationPreset("custom"),document.getElementById("modalRespawnDuration").value=n.durationMinutes))}}catch{}},selectDurationPreset(e){document.querySelectorAll(".duration-preset-btn").forEach(o=>o.classList.remove("active"));const t=document.querySelector(`.duration-preset-btn[data-minutes="${e}"]`);t&&t.classList.add("active");const s=document.querySelector(".duration-custom-input"),n=document.getElementById("modalRespawnDuration");e==="custom"?(s.classList.add("visible"),n.focus()):(s.classList.remove("visible"),n.value="")},getSelectedDuration(){const e=document.querySelector(".duration-custom-input"),t=document.getElementById("modalRespawnDuration");if(e.classList.contains("visible"))return t.value?parseInt(t.value):null;{const n=document.querySelector(".duration-preset-btn.active")?.dataset.minutes;return n?parseInt(n):null}},switchOptionsTab(e){document.querySelectorAll("#sessionOptionsModal .set-rail-item").forEach(s=>{s.classList.toggle("active",s.dataset.tab===e)}),document.getElementById("respawn-tab").classList.toggle("hidden",e!=="respawn"),document.getElementById("context-tab").classList.toggle("hidden",e!=="context"),document.getElementById("ralph-tab").classList.toggle("hidden",e!=="ralph"),document.getElementById("summary-tab").classList.toggle("hidden",e!=="summary");const t=document.getElementById("sessionOptionsDoc");t&&(t.scrollTop=0),e==="summary"&&this.editingSessionId&&this.loadRunSummary(this.editingSessionId)},getRalphConfig(){return{enabled:document.getElementById("modalRalphEnabled").checked,completionPhrase:document.getElementById("modalRalphPhrase").value.trim(),maxIterations:parseInt(document.getElementById("modalRalphMaxIterations").value)||0,maxTodos:parseInt(document.getElementById("modalRalphMaxTodos").value)||50,todoExpirationMinutes:parseInt(document.getElementById("modalRalphTodoExpiration").value)||60}},populateRalphForm(e){document.getElementById("modalRalphEnabled").checked=e?.enabled??!1,document.getElementById("modalRalphPhrase").value=e?.completionPhrase||"",document.getElementById("modalRalphMaxIterations").value=e?.maxIterations||0,document.getElementById("modalRalphMaxTodos").value=e?.maxTodos||50,document.getElementById("modalRalphTodoExpiration").value=e?.todoExpirationMinutes||60},async saveRalphConfig(){if(!this.editingSessionId){this.showToast("No session selected","warning");return}const e=this.getRalphConfig();e.enabled&&this.ralphClosedSessions.delete(this.editingSessionId);try{const s=await(await fetch(`/api/sessions/${this.editingSessionId}/ralph-config`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).json();if(s.error)throw new Error(s.error);this.showToast("Ralph config saved","success")}catch(t){this.showToast("Failed to save Ralph config: "+t.message,"error")}},startInlineRename(e){const t=this.sessions.get(e);if(!t)return;this._activeRename?.cancel();const s=document.querySelector(`.tab-name[data-session-id="${e}"]`);if(!s)return;this._inlineRenameActive=!0,s.classList.add("tab-name-renaming");const n=this.getSessionName(t),o=this._inlineRenamePending?.get(e)??t.name,a=o!==t.name,i=parseSessionPrefix(o),r=s.textContent,c=[...s.childNodes].map(C=>C.cloneNode(!0)),u=()=>{s.replaceChildren(...c.map(C=>C.cloneNode(!0)))};for(s.textContent="";s.firstChild;)s.removeChild(s.firstChild);if(i){const C=document.createElement("span");C.className="tab-rename-prefix",C.textContent=i.prefix+": ",C.style.cssText="color: var(--text-muted); font-size: 0.75rem; white-space: nowrap;",s.appendChild(C)}const l=document.createElement("input");l.type="text",l.value=i?i.suffix:o||"",l.placeholder=i?"Add description...":n,l.className="tab-rename-input";const d=!!s.closest(".tab-rail"),m=!d&&!!this.isSessionSidebarActive?.(),p=d?"auto":m?"100%":"80px",h=d||m?"4rem":"0";l.style.cssText=`width: ${p}; min-width: ${h}; font-size: 0.75rem; padding: 2px 4px; background: var(--bg-input); border: 1px solid var(--accent); border-radius: 3px; color: var(--text); outline: none;`,s.appendChild(l),l.focus(),l.select();let f=!1,g=!1,y=!1;const b=()=>{this._activeRename===k&&(this._inlineRenameActive=!1)},w=()=>{this._activeRename===k&&(y=!0,b(),this._activeRename=null,this.renderSessionTabs())},I=()=>{g||y||(g=!0,f=!0,s.classList.remove("tab-name-renaming"),u(),w())},v=async({commit:C})=>{if(f||g)return;if(f=!0,s.classList.remove("tab-name-renaming"),!C){I();return}if(this._activeRename!==k)return;b();const M=l.value.trim(),_=i?i.prefix+(M?": "+M:""):M;if(_===o&&!a?u():s.textContent=_||r,this.sessions.has(e)){const S=await this._queueInlineSessionName(e,_);if(g||this._activeRename!==k||!this.sessions.has(e))return;S.status==="failed"&&u()}w()},k={sessionId:e,cancel:I};this._activeRename=k,l.addEventListener("blur",()=>v({commit:!0})),l.addEventListener("keydown",C=>{C.isComposing||C.keyCode===229||(C.key==="Enter"?(C.preventDefault(),l.blur()):C.key==="Escape"&&(C.preventDefault(),I()))})},toggleCaseSettings(){const e=document.getElementById("caseSettingsPopover");if(e.classList.contains("hidden")){const t=document.getElementById("quickStartCase").value||"testcase",s=this.getCaseSettings(t);document.getElementById("caseAgentTeams").checked=s.agentTeams,document.getElementById("caseOpusContext1m").checked=s.opusContext1m,e.classList.remove("hidden");const n=o=>{!e.contains(o.target)&&!o.target.closest?.(".case-combobox-action")&&(e.classList.add("hidden"),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}else e.classList.add("hidden")},getCaseSettings(e){try{const t=localStorage.getItem("caseSettings_"+e);if(t)return JSON.parse(t)}catch{}return{agentTeams:!1,opusContext1m:!0}},saveCaseSettings(e,t){localStorage.setItem("caseSettings_"+e,JSON.stringify(t))},onCaseSettingChanged(){const e=document.getElementById("quickStartCase").value||"testcase",t=this.getCaseSettings(e);t.agentTeams=document.getElementById("caseAgentTeams").checked,t.opusContext1m=document.getElementById("caseOpusContext1m").checked,this.saveCaseSettings(e,t);const s=document.getElementById("caseAgentTeamsMobile");s&&(s.checked=t.agentTeams);const n=document.getElementById("caseOpusContext1mMobile");n&&(n.checked=t.opusContext1m)},toggleCaseSettingsMobile(){const e=document.getElementById("caseSettingsPopoverMobile");if(e.classList.contains("hidden")){const t=document.getElementById("quickStartCase").value||"testcase",s=this.getCaseSettings(t);document.getElementById("caseAgentTeamsMobile").checked=s.agentTeams,document.getElementById("caseOpusContext1mMobile").checked=s.opusContext1m,e.classList.remove("hidden");const n=o=>{!e.contains(o.target)&&!o.target.classList.contains("btn-case-settings-mobile")&&(e.classList.add("hidden"),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}else e.classList.add("hidden")},onCaseSettingChangedMobile(){const e=document.getElementById("quickStartCase").value||"testcase",t=this.getCaseSettings(e);t.agentTeams=document.getElementById("caseAgentTeamsMobile").checked,t.opusContext1m=document.getElementById("caseOpusContext1mMobile").checked,this.saveCaseSettings(e,t);const s=document.getElementById("caseAgentTeams");s&&(s.checked=t.agentTeams);const n=document.getElementById("caseOpusContext1m");n&&(n.checked=t.opusContext1m)},showCreateCaseModal(){document.getElementById("newCaseName").value="",document.getElementById("newCaseDescription").value="";const e=document.getElementById("newCaseCustomPathToggle");e&&(e.checked=!1);const t=document.getElementById("newCasePath");t&&(t.value="");const s=window.__codemanUser||{},n=document.getElementById("newCaseCustomPathToggleRow");n&&(n.style.display=s.multiUser&&s.role!=="admin"?"none":""),this.toggleNewCaseCustomPath(),document.getElementById("linkCaseName").value="",document.getElementById("linkCasePath").value="",["remoteCaseName","remoteCasePath","remoteHostId","remoteHostAddress","remoteHostUsername","remoteHostPort","remoteHostCodexCommand","remoteHostIdentityFile","remoteHostSocksProxy","remoteHostJumpHost","remoteHostExtraSshOptions","remoteHostWakeMac","remoteHostWakeCommand"].forEach(d=>{const m=document.getElementById(d);m&&(m.value="")}),this._resetCloneForm();const a=document.getElementById("caseCloneTabBtn");a&&(a.style.display=this.isCliAvailable("git")?"":"none"),this.caseModalTab="case-create",this.switchCaseModalTab("case-create");const i=document.getElementById("createCaseModal");i.querySelectorAll(".set-rail-item").forEach(d=>{d.onclick=()=>this.switchCaseModalTab(d.dataset.tab)});const r=document.getElementById("dockerAdoptExisting");r&&(r.onchange=()=>this._syncDockerAdoptMode());const c=document.getElementById("dockerAdoptCheckBtn");c&&(c.onclick=()=>this._dockerAdoptPreflight());const u=document.getElementById("dockerAdoptJumpBtn");u&&(u.onclick=()=>this.jumpToDockerAdopt());const l=document.getElementById("dockerHostId");l&&(l.onchange=()=>{delete document.getElementById("dockerContainerList")?.dataset.loadedFor,document.getElementById("dockerAdoptExisting")?.checked&&this._loadDockerContainerOptions()}),delete document.getElementById("dockerContainerList")?.dataset.loadedFor,this._syncDockerAdoptMode(),i.querySelectorAll('input[type="text"]').forEach(d=>{d._mobileScrollWired||(d._mobileScrollWired=!0,d.addEventListener("focus",()=>{window.innerWidth<600&&setTimeout(()=>d.scrollIntoView({behavior:"smooth",block:"center"}),300)}))}),i.classList.add("active"),document.getElementById("newCaseName").focus()},switchCaseModalTab(e){this.caseModalTab=e;const t=document.getElementById("createCaseModal");t.querySelectorAll(".set-rail-item").forEach(o=>{o.classList.toggle("active",o.dataset.tab===e)}),t.querySelectorAll(".set-section").forEach(o=>{o.classList.toggle("hidden",o.id!==e)});const s=document.getElementById("createCaseDoc");s&&(s.scrollTop=0);const n=["caseModalSubmit","caseModalSubmitMobile"].map(o=>document.getElementById(o)).filter(Boolean);if(e==="case-manage")n.forEach(o=>{o.style.display="none"}),this.renderCaseManageList(),this.refreshDockerExports();else{const o=e==="case-create"?"Create":e==="case-clone"?"Clone":e==="case-remote"?"Link Remote":e==="case-docker"?"Link Docker":"Link";n.forEach(a=>{a.style.display="",a.textContent=o})}e==="case-create"?document.getElementById("newCaseName").focus():e==="case-clone"?document.getElementById("cloneRepoUrl").focus():e==="case-link"?document.getElementById("linkCaseName").focus():e==="case-remote"?document.getElementById("remoteCaseName").focus():e==="case-docker"&&document.getElementById("dockerCaseName").focus()},closeCreateCaseModal(){document.getElementById("createCaseModal").classList.remove("active")},async submitCaseModal(){const e=["caseModalSubmit","caseModalSubmitMobile"].map(n=>document.getElementById(n)).filter(Boolean),t=e.map(n=>n.textContent),s=this.caseModalTab==="case-create"?"Creating...":this.caseModalTab==="case-clone"?"Cloning...":"Linking...";e.forEach(n=>{n.classList.add("loading"),n.textContent=s,n.disabled=!0});try{this.caseModalTab==="case-create"?await this.createCase():this.caseModalTab==="case-clone"?await this.cloneCase():this.caseModalTab==="case-remote"?await this.linkRemoteCase():this.caseModalTab==="case-docker"?await this.linkDockerCase():await this.linkCase()}finally{e.forEach((n,o)=>{n.classList.remove("loading"),n.disabled=!1,n.textContent=t[o]})}},toggleNewCaseCustomPath(){const e=document.getElementById("newCaseCustomPathToggle"),t=document.getElementById("newCaseDocker"),s=document.getElementById("newCaseCustomPathRow");if(!e||!s)return;s.style.display=e.checked?"":"none";const n=document.getElementById("newCaseBlurb");n&&(n.textContent=e.checked?"A fresh workspace in a folder you choose, scaffolded with its own CLAUDE.md.":"A fresh workspace under ~/codeman-cases, scaffolded with its own CLAUDE.md.");const o=document.getElementById("newCaseNameHint");o&&(o.textContent=e.checked?"Letters, numbers, hyphens, underscores only. Created inside the parent folder below.":"Letters, numbers, hyphens, underscores only. Created in ~/codeman-cases/"),e.disabled=!!t?.checked,e.title=t?.checked?"Not available for a Docker case":"",t&&(t.disabled=e.checked,t.title=e.checked?"Not available with a custom folder":""),this.updateNewCasePathPreview()},_newCaseTargetPath(){const e=(document.getElementById("newCasePath")?.value||"").trim(),t=(document.getElementById("newCaseName")?.value||"").trim();return!e||!t?"":`${e.replace(/\/+$/,"")}/${t}`},updateNewCasePathPreview(){const e=document.getElementById("newCasePathPreview");if(!e)return;const t=this._newCaseTargetPath();e.textContent=t?`Will create: ${t}`:"Pick the folder the new case folder should be created inside."},openNewCasePathPicker(){const e=document.getElementById("newCasePath");PathPicker.open({title:"Choose the folder to create the case in",initialPath:e.value.trim(),directoriesOnly:!0,onSelect:t=>{e.value=t,this.updateNewCasePathPreview(),e.focus(),e.setSelectionRange(t.length,t.length)}})},async createCase(){const e=document.getElementById("newCaseName").value.trim(),t=document.getElementById("newCaseDescription").value.trim();if(!e){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}const s=document.getElementById("newCaseDocker")?.checked,n=!s&&document.getElementById("newCaseCustomPathToggle")?.checked;if(n&&!(document.getElementById("newCasePath")?.value||"").trim()){this.showToast("Choose the folder to create the case in","error");return}const o=s?"/api/cases/docker-quickcreate":"/api/cases",a=s?{name:e,description:t,...this._collectDockerQuickSettings()}:n?{name:e,description:t,path:this._newCaseTargetPath()}:{name:e,description:t};try{const r=await(await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).json();if(r.success)if(this.closeCreateCaseModal(),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e),s){const c=r.data?.capsEnforced===!1?" (resource caps advisory on this engine)":"";this.showToast(`Docker case "${e}" created${c} \u2014 starting session\u2026`,"success"),await this.runClaude()}else{const c=r.data?.case?.path||a.path;this.showToast(n?`Case "${e}" created in ${c}`:`Case "${e}" created`,"success")}else this.showToast(r.error||"Failed to create case","error")}catch(i){console.error("Failed to create case:",i),this.showToast("Failed to create case: "+i.message,"error")}},applyDockerTemplate(){const e=document.getElementById("quickDockerTemplate")?.value,s={small:{m:"2g",c:"1",g:""},medium:{m:"",c:"",g:""},large:{m:"8g",c:"4",g:""},gpu:{m:"8g",c:"4",g:"all"}}[e];if(!s)return;const n=(o,a)=>{const i=document.getElementById(o);i&&(i.value=a)};n("quickDockerMemory",s.m),n("quickDockerCpus",s.c),n("quickDockerGpus",s.g)},_collectDockerQuickSettings(){const e=c=>(document.getElementById(c)?.value||"").trim(),t={},s=e("quickDockerMemory");s&&(t.memory=s);const n=e("quickDockerCpus");n&&(t.cpus=n);const o=e("quickDockerGpus");o&&o.toLowerCase()!=="none"&&(t.gpus=o);const a=document.getElementById("quickDockerNetwork")?.value;a&&a!=="bridge"&&(t.network=a);const i=e("quickDockerImage");i&&(t.image=i);const r=document.getElementById("quickDockerMountCreds");return r&&!r.checked&&(t.mountCredentials=!1),t},async linkCase(){const e=document.getElementById("linkCaseName").value.trim(),t=document.getElementById("linkCasePath").value.trim();if(!e){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t){this.showToast("Please enter a folder path","error");return}try{const n=await(await fetch("/api/cases/link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,path:t})})).json();n.success?(this.closeCreateCaseModal(),this.showToast(`Case "${e}" linked to ${t}`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)):this.showToast(n.error||"Failed to link case","error")}catch(s){console.error("Failed to link case:",s),this.showToast("Failed to link case: "+s.message,"error")}},_resetCloneForm(){const e=(i,r)=>{const c=document.getElementById(i);c&&(c.value=r)};e("cloneRepoUrl",""),e("cloneCaseName",""),e("cloneRepoRef","");const t=document.getElementById("cloneShallow");t&&(t.checked=!1);const s=document.getElementById("cloneStartSession");s&&(s.checked=!1);const n=document.getElementById("cloneRepoRefOptions");n&&n.replaceChildren();const o=document.getElementById("cloneRefHint");o&&(o.textContent="Leave blank for the repository's default branch."),this._cloneNameEdited=!1,this._clonePreflight=null,clearTimeout(this._clonePreflightTimer),this._clonePreflightAbort?.abort(),this._clonePreflightAbort=null,this._setCloneStatus("Public repositories only: Codeman clones with no credentials.","");const a=document.getElementById("cloneCaseBrain");if(a){for(const r of a.options){const c=r.dataset.cli;r.hidden=!!c&&!this.isCliAvailable(c)}const i=this.runMode||"claude";a.value=[...a.options].some(r=>r.value===i&&!r.hidden)?i:""}},_setCloneStatus(e,t){const s=document.getElementById("cloneRepoStatus");s&&(s.textContent=e,s.className=`form-hint clone-status${t?" clone-status-"+t:""}`)},_repoNameFromUrl(e){const t=(e||"").trim().replace(/\/+$/,"");return t?(t.replace(/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//,"").replace(/^[^@/]*@/,"").split(/[/:]/).filter(Boolean).pop()||"").replace(/\.git$/i,"").replace(/[^a-zA-Z0-9_-]+/g,"-").replace(/-{2,}/g,"-").replace(/^[-_]+|[-_]+$/g,"").slice(0,64):""},onCloneNameEdited(){this._cloneNameEdited=!!document.getElementById("cloneCaseName")?.value.trim()},onCloneUrlInput(){const e=document.getElementById("cloneRepoUrl")?.value.trim()||"",t=document.getElementById("cloneCaseName");if(t&&!this._cloneNameEdited&&(t.value=this._repoNameFromUrl(e)),clearTimeout(this._clonePreflightTimer),this._clonePreflightAbort?.abort(),this._clonePreflightAbort=null,!e){this._setCloneStatus("Public repositories only: Codeman clones with no credentials.","");return}if(this.isCliAvailable("git")===!1){this._setCloneStatus("git is not installed on the Codeman host, so cloning is unavailable.","err");return}this._setCloneStatus("Checking the repository\u2026",""),this._clonePreflightTimer=setTimeout(()=>this._runClonePreflight(e),450)},async _runClonePreflight(e){const t=new AbortController;this._clonePreflightAbort=t;try{const n=await(await fetch("/api/cases/clone-preflight",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({repository:e}),signal:t.signal})).json();if(document.getElementById("cloneRepoUrl")?.value.trim()!==e)return;if(!n.success){this._setCloneStatus(n.error||"Could not check that URL.","err");return}this._applyClonePreflight(n.data,e)}catch(s){if(s.name==="AbortError")return;this._setCloneStatus("Could not reach Codeman to check that URL.","err")}},_applyClonePreflight(e,t){this._clonePreflight=e;const s=e?.parse;if(!s?.cloneable){this._setCloneStatus(s?.message||"That URL cannot be cloned.","err");return}const n=document.getElementById("cloneCaseName");n&&!this._cloneNameEdited&&s.suggestedName&&(n.value=s.suggestedName);const o=s.owner?`${s.provider} ${s.owner}/${s.repo}`:`${s.provider} ${s.repo}`;if(e.gitAvailable===!1){this._setCloneStatus(`${o}: git is not installed on the Codeman host.`,"err");return}const a=e.remote;if(a&&!a.reachable){this._setCloneStatus(`${o}: ${a.failure?.message||"the remote could not be read."}`,"err");return}const i=document.getElementById("cloneRefHint"),r=document.getElementById("cloneRepoRefOptions");if(a&&r){r.replaceChildren();for(const u of[...a.branches||[],...a.tags||[]]){const l=document.createElement("option");l.value=u,r.appendChild(l)}if(i){const u=`${a.branches?.length||0} branches, ${a.tags?.length||0} tags`;i.textContent=a.defaultBranch?`Blank clones the default branch (${a.defaultBranch}). ${u} available.`:`Blank clones the default branch. ${u} available.`}}const c=s.warnings?.[0];this._setCloneStatus(c?`${o}: ${c}`:`${o}: ready to clone.`,c?"warn":"ok")},async cloneCase(){const e=document.getElementById("cloneRepoUrl").value.trim(),t=document.getElementById("cloneCaseName").value.trim(),s=document.getElementById("cloneRepoRef").value.trim(),n=!!document.getElementById("cloneShallow")?.checked,o=document.getElementById("cloneCaseBrain")?.value||"",a=!!document.getElementById("cloneStartSession")?.checked;if(!e){this.showToast("Please enter a repository URL","error");return}if(!t){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(t)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}this._setCloneStatus(`Cloning ${e}\u2026 this can take a while for a large repository.`,"");try{const r=await(await fetch("/api/cases/clone",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t,repository:e,...s?{ref:s}:{},...n?{shallow:!0}:{}})})).json();if(!r.success){this._setCloneStatus(r.error||"Clone failed.","err"),this.showToast(r.error||"Failed to clone repository","error");return}o&&this.setRunMode(o),this.closeCreateCaseModal(),await this.loadQuickStartCases(t),await this.saveLastUsedCase(t),this.showToast(`Cloned into case "${t}"`,"success");for(const c of r.data?.warnings||[])this.showToast(c,"warning");a&&await this.run()}catch(i){console.error("Failed to clone repository:",i),this._setCloneStatus(`Lost the connection while cloning: ${i.message}. If git finishes, the case still appears in the list.`,"warn"),this.showToast("Clone request interrupted \u2014 watch the case list","error")}},openLinkCasePathPicker(){const e=document.getElementById("linkCasePath");PathPicker.open({title:"Select Existing Project Folder",initialPath:e.value.trim(),directoriesOnly:!0,onSelect:t=>{e.value=t;const s=document.getElementById("linkCaseName");if(!s.value.trim()){const n=t.split("/").filter(Boolean).pop()||"";/^[\p{L}\p{N}_-]+$/u.test(n)&&(s.value=n)}e.focus(),e.setSelectionRange(t.length,t.length)}})},openDockerWorkspacePathPicker(){const e=document.getElementById("dockerWorkspacePath");PathPicker.open({title:"Select Host Workspace Folder",initialPath:e.value.trim(),directoriesOnly:!0,onSelect:t=>{e.value=t;const s=document.getElementById("dockerCaseName");if(s&&!s.value.trim()){const n=t.split("/").filter(Boolean).pop()||"";/^[a-zA-Z0-9_-]+$/.test(n)&&(s.value=n)}}})},openDockerWorkdirPicker(){const e=document.getElementById("dockerAdoptWorkdir"),t=document.getElementById("dockerContainerName")?.value.trim(),s=document.getElementById("dockerHostId")?.value.trim()||"local";if(!t){this.showToast("Enter the container name first","error");return}PathPicker.open({title:`Select Folder Inside ${t}`,initialPath:e.value.trim()||"/",directoriesOnly:!0,fetchListing:async n=>{const o=await this._apiJson("/api/docker-cases/browse",{method:"POST",body:{hostId:s,container:t,path:n||"/"}});return o?o.error?{success:!1,error:o.error}:{success:!0,data:{...o,root:"/",roots:[{label:t,path:"/"}],truncated:!1}}:{success:!1,error:`Could not read ${t}. Is it running?`}},onSelect:n=>{e.value=n}})},async linkRemoteCase(){const e=document.getElementById("remoteCaseName").value.trim(),t=document.getElementById("remoteCasePath").value.trim(),s=document.getElementById("remoteHostId").value.trim(),n=document.getElementById("remoteHostAddress").value.trim(),o=document.getElementById("remoteHostUsername").value.trim(),a=document.getElementById("remoteHostCodexCommand").value.trim(),i=document.getElementById("remoteHostPort").value.trim(),r=document.getElementById("remoteHostIdentityFile").value.trim(),c=document.getElementById("remoteHostSocksProxy").value.trim(),u=document.getElementById("remoteHostJumpHost").value.trim(),l=document.getElementById("remoteHostWakeMac").value.trim(),d=document.getElementById("remoteHostWakeCommand").value.trim(),m=document.getElementById("remoteHostExtraSshOptions").value.split(`
38
- `).map(h=>h.trim()).filter(h=>h.length>0);if(!e||!t||!s||!n||!o){this.showToast("Please complete all required remote fields","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)||!/^[a-zA-Z0-9_-]+$/.test(s)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t.startsWith("/")){this.showToast("Remote path must be absolute","error");return}let p;if(i&&(p=Number(i),!Number.isInteger(p)||p<1||p>65535)){this.showToast("SSH port must be a number between 1 and 65535","error");return}try{const h={id:s,label:s,host:n,username:o,...p?{port:p}:{},...r?{identityFile:r}:{},...c?{socksProxy:c}:{},...u?{jumpHost:u}:{},...m.length?{extraSshOptions:m}:{},...l?{wakeMac:l}:{},...d?{wakeCommand:d}:{},...a?{commands:{codex:a}}:{}},g=await(await fetch("/api/remote-hosts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(h)})).json();if(!g.success&&g.errorCode!=="ALREADY_EXISTS")throw new Error(g.error||"Failed to save remote host");const b=await(await fetch("/api/cases/remote-link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,hostId:s,remotePath:t})})).json();b.success?(this.closeCreateCaseModal(),this.showToast(`Remote case "${e}" linked`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)):this.showToast(b.error||"Failed to link remote case","error")}catch(h){console.error("Failed to link remote case:",h),this.showToast("Failed to link remote case: "+h.message,"error")}},_syncDockerAdoptMode(){const e=document.getElementById("createCaseModal");if(!e)return;const t=document.getElementById("dockerAdoptExisting")?.checked;t?e.setAttribute("data-docker-adopt","1"):e.removeAttribute("data-docker-adopt"),t&&(this._loadDockerContainerOptions(),this._loadDockerCloneOptions())},async _loadDockerCloneOptions(){const e=document.getElementById("dockerAdoptCloneFrom"),t=document.getElementById("dockerAdoptCloneRow");if(!e||!t)return;let s=[];try{const a=await(await fetch("/api/cases")).json();s=(Array.isArray(a)?a:a?.data||[]).filter(i=>i?.docker&&i.docker.owned===!1)}catch{s=[]}e.textContent="";const n=document.createElement("option");n.value="",n.textContent="Start from scratch",e.appendChild(n);for(const o of s){const a=document.createElement("option");a.value=o.name,a.textContent=`${o.name} \u2014 ${o.docker.container}:${o.docker.containerWorkdir||o.docker.path}`,a.dataset.container=o.docker.container,a.dataset.hostId=o.docker.hostId,a.dataset.path=o.docker.path,a.dataset.workdir=o.docker.containerWorkdir||o.docker.path,e.appendChild(a)}t.hidden=s.length===0},applyDockerCloneSource(){const e=document.getElementById("dockerAdoptCloneFrom"),t=e?.selectedOptions?.[0];if(!t||!t.value)return;const s=(o,a)=>{const i=document.getElementById(o);i&&(i.value=a||"")};s("dockerContainerName",t.dataset.container),s("dockerHostId",t.dataset.hostId),s("dockerWorkspacePath",t.dataset.path),s("dockerCaseName",t.value),s("dockerAdoptWorkdir",t.dataset.workdir),e.dataset.appliedName=t.value,e.dataset.appliedWorkdir=t.dataset.workdir||"";const n=document.getElementById("dockerAdoptWorkdir");n?.focus(),n&&n.setSelectionRange(n.value.length,n.value.length)},dockerCloneGuard(){const e=document.getElementById("dockerAdoptCloneFrom");if(!e||!e.value)return null;const t=document.getElementById("dockerCaseName"),s=document.getElementById("dockerAdoptWorkdir");return t&&t.value.trim()===(e.dataset.appliedName||"")?{el:t,message:`"${t.value.trim()}" is the case you copied from \u2014 give this one a new name.`}:s&&s.value.trim()===(e.dataset.appliedWorkdir||"")?{el:s,message:"Same container and same directory as the case you copied from \u2014 point this one at another directory."}:null},async _loadDockerContainerOptions(){const e=document.getElementById("dockerContainerList");if(!e)return;const t=document.getElementById("dockerHostId")?.value.trim()||"local";if(e.dataset.loadedFor===t)return;const n=(await this._apiJson(`/api/docker-hosts/${encodeURIComponent(t)}/containers`))?.containers||[];e.textContent="";for(const o of n){const a=document.createElement("option");a.value=o.name,a.textContent=o.running?`${o.image} \xB7 ${o.status}`:`${o.image} \xB7 ${o.status} (not running)`,e.appendChild(a)}e.dataset.loadedFor=t},jumpToDockerAdopt(){this.switchCaseModalTab("case-docker");const e=document.getElementById("dockerAdoptExisting");e&&(e.checked=!0),this._syncDockerAdoptMode(),document.getElementById("dockerContainerName")?.focus()},async _dockerAdoptPreflight(){const e=document.getElementById("dockerLinkStatus"),t=document.getElementById("dockerContainerName")?.value.trim(),s=document.getElementById("dockerAdoptWorkdir")?.value.trim(),n=document.getElementById("dockerHostId").value.trim()||"local";if(!t){e&&(e.textContent="Enter a container name first.");return}e&&(e.textContent="Inspecting container...");const o=await this._apiJson("/api/docker-cases/adopt-preflight",{method:"POST",body:{hostId:n,container:t,...s?{containerWorkdir:s}:{}}});if(!e)return;if(!o){e.textContent="Could not reach the docker host profile. Save a Host ID first.";return}if(!o.ok){e.textContent=o.error||"Container is not adoptable.";return}const a=(o.availableModes||[]).filter(i=>i!=="shell");e.textContent=a.length?`Running (${o.image||"unknown image"}). Available: ${a.join(", ")}.`:`Running (${o.image||"unknown image"}), but no agent CLI found inside \u2014 only Shell will work.`},async linkDockerCase(){const e=document.getElementById("dockerCaseName").value.trim(),t=document.getElementById("dockerWorkspacePath").value.trim(),s=document.getElementById("dockerHostId").value.trim()||"local",n=!!document.getElementById("dockerAdoptExisting")?.checked,o=document.getElementById("dockerContainerName")?.value.trim()||"",a=document.getElementById("dockerAdoptWorkdir")?.value.trim()||"",i=document.getElementById("dockerImage").value.trim()||"codeman/agent:base",r=document.getElementById("dockerNetwork").value,c=document.getElementById("dockerMemory").value.trim(),u=document.getElementById("dockerCpus").value.trim(),l=document.getElementById("dockerMountCredentials").checked,d=document.getElementById("dockerResumeOnStart").checked,m=document.getElementById("dockerLinkStatus");if(!e||!t){this.showToast("Please enter a case name and workspace path","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)||!/^[a-zA-Z0-9_-]+$/.test(s)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t.startsWith("/")){this.showToast("Workspace path must be absolute","error");return}if(n&&!o){this.showToast("Enter the name of the running container to attach to","error");return}const p=n?this.dockerCloneGuard():null;if(p){this.showToast(p.message,"error");const h=document.getElementById("dockerLinkStatus");h&&(h.textContent=p.message),p.el.focus(),p.el.select?.();return}try{m&&(m.textContent=n?"Inspecting the existing container...":"Checking docker daemon + base image...");const h={};c&&(h.memory=c),u&&(h.cpus=u);const f={id:s,label:s,image:i,network:r,mountCredentials:l,resumeOnStart:d,...Object.keys(h).length?{resources:h}:{}};let g=await fetch("/api/docker-hosts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)}),y=await g.json();if(!y.success&&y.errorCode==="ALREADY_EXISTS"&&(g=await fetch(`/api/docker-hosts/${encodeURIComponent(s)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)}),y=await g.json()),!y.success)throw new Error(y.error||"Failed to save docker host");const w=await(await fetch(n?"/api/cases/docker-adopt":"/api/cases/docker-link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n?{name:e,hostId:s,hostWorkspacePath:t,container:o,...a?{containerWorkdir:a}:{}}:{name:e,hostId:s,hostWorkspacePath:t})})).json();if(w.success){this.closeCreateCaseModal();const I=w.data?.capsEnforced===!1?" (resource caps are advisory on this engine)":"",v=(w.data?.availableModes||[]).filter(C=>C!=="shell"),k=n&&v.length?` \u2014 found ${v.join(", ")}`:"";this.showToast(`Docker case "${e}" ${n?"attached":"linked"}${I}${k}`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)}else m&&(m.textContent=w.error||"Failed to link docker case"),this.showToast(w.error||"Failed to link docker case","error")}catch(h){console.error("Failed to link docker case:",h),m&&(m.textContent=h.message),this.showToast("Failed to link docker case: "+h.message,"error")}},async refreshDockerExports(){const e=document.getElementById("dockerExportsList");if(e)try{const n=(await(await fetch("/api/docker-exports")).json())?.data?.exports||[];if(n.length===0){e.innerHTML='<span class="form-hint">No exports yet. Export a docker case from its tab.</span>';return}e.innerHTML=n.map(o=>{const a=(o.sizeBytes/1e6).toFixed(1),i=escapeHtml(o.name);return`<div class="case-manage-item" style="display:flex; align-items:center; gap:8px; justify-content:space-between;">
39
- <span style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${i}">${i} <span class="form-hint">(${a} MB)</span></span>
40
- <span style="flex-shrink:0;">
41
- <a class="btn-toolbar" href="${CodemanBase.url(`/api/docker-exports/${encodeURIComponent(o.name)}`)}" download>Download</a>
42
- <button class="btn-toolbar" onclick="app.importDockerBundle('${i.replace(/'/g,"\\'")}')">Import</button>
43
- <button class="btn-toolbar" onclick="app.deleteDockerExport('${i.replace(/'/g,"\\'")}')">Delete</button>
44
- </span>
45
- </div>`}).join("")}catch(t){e.innerHTML=`<span class="form-hint">Failed to load exports: ${t.message}</span>`}},async exportDockerCaseBundle(e,t="full"){try{const n=await(await fetch(`/api/docker-cases/${encodeURIComponent(e)}/export`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mode:t})})).json();n.success?this.showToast(`Exporting "${e}" (${t})... you'll be notified when the bundle is ready`,"info"):this.showToast(n.error||"Export failed","error")}catch(s){this.showToast("Export failed: "+s.message,"error")}},async importDockerBundle(e){const t=prompt("New case name for the imported bundle:",e.split("-")[0]+"-imported");if(!t)return;const s=prompt("Absolute host directory to restore the workspace into:","");if(s)try{const o=await(await fetch("/api/docker-cases/import",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({bundle:e,newCaseName:t,destWorkspacePath:s})})).json();o.success?(this.showToast(`Imported as "${t}"`,"success"),await this.loadQuickStartCases(t)):this.showToast(o.error||"Import failed","error")}catch(n){this.showToast("Import failed: "+n.message,"error")}},async deleteDockerExport(e){if(confirm(`Delete export bundle "${e}"?`))try{const s=await(await fetch(`/api/docker-exports/${encodeURIComponent(e)}`,{method:"DELETE"})).json();s.success?(this.showToast("Export deleted","success"),this.refreshDockerExports()):this.showToast(s.error||"Delete failed","error")}catch(t){this.showToast("Delete failed: "+t.message,"error")}},_readRemoteHostFromForm(){const e=document.getElementById("remoteHostId").value.trim(),t=document.getElementById("remoteHostAddress").value.trim(),s=document.getElementById("remoteHostUsername").value.trim(),n=document.getElementById("remoteHostPort").value.trim(),o=document.getElementById("remoteHostIdentityFile").value.trim(),a=document.getElementById("remoteHostSocksProxy").value.trim(),i=document.getElementById("remoteHostJumpHost").value.trim(),r=document.getElementById("remoteHostCodexCommand").value.trim(),c=document.getElementById("remoteHostWakeMac").value.trim(),u=document.getElementById("remoteHostWakeCommand").value.trim(),l=document.getElementById("remoteHostExtraSshOptions").value.split(`
46
- `).map(m=>m.trim()).filter(m=>m.length>0);let d;if(n){const m=Number(n);Number.isInteger(m)&&m>=1&&m<=65535&&(d=m)}return{id:e,label:e,host:t,username:s,...d?{port:d}:{},...o?{identityFile:o}:{},...a?{socksProxy:a}:{},...i?{jumpHost:i}:{},...l.length?{extraSshOptions:l}:{},...c?{wakeMac:c}:{},...u?{wakeCommand:u}:{},...r?{commands:{codex:r}}:{}}},async discoverRemoteSessions(){const e=document.getElementById("remoteDiscoverResults"),t=document.getElementById("remoteDiscoverBtn"),s=this._readRemoteHostFromForm();if(!s.id||!s.host||!s.username){this.showToast("Fill in Host ID, address, and username first","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(s.id)){this.showToast("Invalid Host ID. Use letters, numbers, hyphens, underscores.","error");return}t&&(t.disabled=!0),e&&(e.innerHTML='<div class="form-hint">Discovering\u2026</div>');try{const o=await(await fetch("/api/remote-hosts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})).json();if(!o.success&&o.errorCode!=="ALREADY_EXISTS")throw new Error(o.error||"Failed to save remote host");const i=await(await fetch(`/api/remote-hosts/${encodeURIComponent(s.id)}/sessions`)).json();if(!i.success)throw new Error(i.error||"Discovery failed");this._renderDiscoveredSessions(s.id,i.data.sessions||[])}catch(n){console.error("Discover remote sessions failed:",n),e&&(e.innerHTML=`<div class="form-hint" style="color: var(--error, #e06c75);">${escapeHtml(n.message)}</div>`)}finally{t&&(t.disabled=!1)}},_renderDiscoveredSessions(e,t){const s=document.getElementById("remoteDiscoverResults");if(!s)return;if(!t.length){s.innerHTML='<div class="form-hint">No <code>codeman-*</code> sessions running on this host (or it is unreachable).</div>';return}const n=Math.floor(Date.now()/1e3),o=t.map(a=>{const i=Math.max(0,n-(a.created||0)),r=i<3600?`${Math.floor(i/60)}m`:i<86400?`${Math.floor(i/3600)}h`:`${Math.floor(i/86400)}d`,c=a.attachedClients!=null?a.attachedClients:a.attached?1:0,u=c>1?`<span class="case-location-badge" style="background: var(--warning, #e5c07b); color: #000;">shared \xB7 ${c} clients</span>`:c===1?'<span class="case-location-badge" style="background: var(--accent, #61afef);">attached</span>':"";return`
47
- <div class="remote-discover-item">
48
- <div class="remote-discover-info">
49
- <span class="remote-discover-name">${escapeHtml(a.name)} ${u}</span>
50
- <span class="form-hint">age ${r} \xB7 ${a.windows||1} window(s)</span>
51
- </div>
52
- <button type="button" class="btn-toolbar" onclick="app.attachDiscoveredSession('${escapeHtml(e)}', '${escapeHtml(a.name)}')">Attach</button>
53
- </div>`}).join("");s.innerHTML=o},async attachDiscoveredSession(e,t){try{const n=await(await fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mode:"shell",name:t,attachRemoteSession:{hostId:e,remoteSessionName:t}})})).json();if(!n.success)throw new Error(n.error||"Failed to create session");const o=n.data.session.id;await fetch(`/api/sessions/${o}/shell`,{method:"POST"});const a=this.getTerminalDimensions();a&&await fetch(`/api/sessions/${o}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}),this.closeCreateCaseModal(),this.showToast(`Attached to ${t} (detach on close)`,"success"),this.activeSessionId=o,await this.selectSession(o),this.terminal&&typeof this.terminal.focus=="function"&&this.terminal.focus()}catch(s){console.error("Attach discovered session failed:",s),this.showToast("Failed to attach: "+s.message,"error")}},setCaseManageFilter(e){this._caseManageFilter=String(e||""),this.renderCaseManageList()},renderCaseManageList(){const e=document.getElementById("caseManageList"),t=this.cases||[];if(t.length===0){e.innerHTML='<div class="form-hint" style="text-align: center; padding: 2rem 0;">No cases yet</div>';return}const s=(this._caseManageFilter||"").trim().toLowerCase().split(/\s+/).filter(Boolean),n=s.length>0,o=n?t.filter(r=>{const c=`${r.name} ${r.path||""}`.toLowerCase();return s.every(u=>c.includes(u))}):t,a=t.filter(r=>r.agentCreated);let i=a.length>0?`<div class="case-manage-agent-bar">
54
- <span class="case-manage-agent-count">${a.length} case${a.length===1?"":"s"} created by agent workers</span>
55
- <button class="case-manage-btn case-manage-btn-cleanup" onclick="app.cleanupAgentCases()"
56
- title="Review and delete the scratch cases agent workers left behind">Clean up</button>
57
- </div>`:"";n&&o.length===0&&(i+='<div class="form-hint" style="text-align: center; padding: 2rem 0;">No cases match</div>'),o.forEach(r=>{const c=t.indexOf(r),u=n||c===0,l=n||c===t.length-1,d=n?"Clear the search to reorder":null,m=r.path?this._shortenHomePath(r.path):"",p=r.agentCreated?`Created by an agent worker${r.agentCreated.parentSessionName?` from ${r.agentCreated.parentSessionName}`:""} (${r.agentCreated.createdBy})${r.agentCreated.createdAt?` on ${new Date(r.agentCreated.createdAt).toLocaleString()}`:""}`:"";i+=`
58
- <div class="case-manage-item" data-case="${escapeHtml(r.name)}">
59
- <div class="case-manage-info">
60
- <span class="case-manage-name">${escapeHtml(r.name)}${r.agentCreated?`<span class="case-manage-tag-agent" title="${escapeHtml(p)}" data-i18n-skip>agent</span>`:""}</span>
61
- <span class="case-manage-path">${escapeHtml(m)}</span>
62
- </div>
63
- <div class="case-manage-actions">
64
- ${r.location==="docker"?`<button class="case-manage-btn" onclick="app.exportDockerCaseBundle(${escapeHtml(JSON.stringify(r.name))}, 'full')"
65
- title="Export container (full image + workspace) to move to another machine">&#x1F4E6;</button>`:""}
66
- <button class="case-manage-btn" onclick="app.moveCaseUp(${escapeHtml(JSON.stringify(r.name))})"
67
- title="${d||"Move up"}" ${u?"disabled":""}>&#x25B2;</button>
68
- <button class="case-manage-btn" onclick="app.moveCaseDown(${escapeHtml(JSON.stringify(r.name))})"
69
- title="${d||"Move down"}" ${l?"disabled":""}>&#x25BC;</button>
70
- <button class="case-manage-btn case-manage-btn-delete" onclick="app.deleteCase(${escapeHtml(JSON.stringify(r.name))})"
71
- title="Delete case">&#x2715;</button>
72
- </div>
73
- </div>
74
- `}),e.innerHTML=i},async moveCaseUp(e){const t=this.cases||[],s=t.findIndex(o=>o.name===e);if(s<=0)return;const n=[...t];[n[s-1],n[s]]=[n[s],n[s-1]],this.cases=n,this.renderCaseManageList(),await this.saveCaseOrder(n.map(o=>o.name))},async moveCaseDown(e){const t=this.cases||[],s=t.findIndex(o=>o.name===e);if(s<0||s>=t.length-1)return;const n=[...t];[n[s],n[s+1]]=[n[s+1],n[s]],this.cases=n,this.renderCaseManageList(),await this.saveCaseOrder(n.map(o=>o.name))},async deleteCase(e){if(confirm(`Delete case "${e}"? Linked cases will only be unlinked (folder preserved). Created cases will be permanently deleted.`))try{const s=await(await fetch(`/api/cases/${encodeURIComponent(e)}`,{method:"DELETE"})).json();if(s.success){this.showToast(`Case "${e}" ${s.data?.type==="unlinked"?"unlinked":"deleted"}`,"success"),this.cases=(this.cases||[]).filter(a=>a.name!==e),this.renderCaseManageList();const n=document.getElementById("quickStartCase"),o=n.value;o===e&&n.blur?.(),await this.loadQuickStartCases(o===e?null:o),o===e&&await this.saveLastUsedCase(document.getElementById("quickStartCase")?.value||"testcase")}else this.showToast(s.error||"Failed to delete case","error")}catch(t){this.showToast("Failed to delete case: "+t.message,"error")}},async cleanupAgentCases(){let e;try{const d=await(await fetch("/api/cases/agent-created")).json();if(!d.success){this.showToast(d.error||"Failed to list agent cases","error");return}e=d.data.cases||[]}catch(l){this.showToast("Failed to list agent cases: "+l.message,"error");return}const t=e.filter(l=>l.inUse),s=e.filter(l=>!l.inUse);if(s.length===0){this.showToast(t.length>0?`All ${t.length} agent case(s) are still in use by a running session`:"No agent-created cases to clean up","info");return}const n=s.map(l=>` ${l.name}`).join(`
75
- `),o=t.length>0?`
76
-
77
- Skipping ${t.length} case(s) still in use by a running session.`:"";if(!confirm(`Permanently delete ${s.length} agent-created case folder(s) and everything in them?
78
-
79
- ${n}${o}`))return;let a=0;const i=[];for(const l of s)try{(await(await fetch(`/api/cases/${encodeURIComponent(l.name)}`,{method:"DELETE"})).json()).success?a++:i.push(l.name)}catch{i.push(l.name)}this.showToast(i.length===0?`Deleted ${a} agent case(s)`:`Deleted ${a}, failed: ${i.join(", ")}`,i.length===0?"success":"error");const r=document.getElementById("quickStartCase"),c=r?.value,u=s.some(l=>l.name===c);u&&r?.blur?.(),await this.loadQuickStartCases(u?null:c),u&&await this.saveLastUsedCase(document.getElementById("quickStartCase")?.value||"testcase"),this.renderCaseManageList()},async saveCaseOrder(e){try{await fetch("/api/cases/order",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({order:e})});const s=document.getElementById("quickStartCase").value;await this.loadQuickStartCases(s)}catch(t){this.showToast("Failed to save case order: "+t.message,"error")}},showMobileCasePicker(){const e=document.getElementById("mobileCasePickerModal"),t=document.getElementById("mobileCaseList"),n=document.getElementById("quickStartCase").value;let o="";const a=this.getCasePickerOptions();for(const u of a){const l=u.name===n;o+=`
80
- <button class="mobile-case-item ${l?"selected":""}"
81
- data-search="${escapeHtml(`${u.label} ${u.name}`.toLowerCase())}"
82
- onclick="app.selectMobileCase(${escapeHtml(JSON.stringify(u.name))})">
83
- <span class="mobile-case-item-icon">
84
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
85
- <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
86
- </svg>
87
- </span>
88
- <span class="mobile-case-item-name">${escapeHtml(u.label)}</span>
89
- <span class="mobile-case-item-delete" onclick="event.stopPropagation(); app.deleteCaseMobile(${escapeHtml(JSON.stringify(u.name))})" title="Delete">
90
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
91
- <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
92
- </svg>
93
- </span>
94
- <span class="mobile-case-item-check">
95
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
96
- <polyline points="20 6 9 17 4 12"/>
97
- </svg>
98
- </span>
99
- </button>
100
- `}t.innerHTML=o;const i=document.getElementById("mobileCaseSearch");i&&(i.value=""),t.parentElement.style.minHeight="",this.filterMobileCases(),e.classList.add("active");const r=t.parentElement,c=t.querySelector(".mobile-case-item.selected");if(r&&c){const u=c.offsetTop-r.offsetTop;u+c.offsetHeight>r.scrollTop+r.clientHeight&&(r.scrollTop=u-(r.clientHeight-c.offsetHeight)/2)}},filterMobileCases(){const t=(document.getElementById("mobileCaseSearch")?.value||"").toLowerCase().split(/\s+/).filter(Boolean),s=document.querySelector(".mobile-case-picker-body");s&&t.length&&!s.style.minHeight&&(s.style.minHeight=`${s.offsetHeight}px`);let n=0;for(const a of document.querySelectorAll("#mobileCaseList .mobile-case-item")){const i=a.dataset.search||"",r=t.every(c=>i.includes(c));a.hidden=!r,r&&n++}const o=document.getElementById("mobileCaseEmpty");o&&(o.hidden=n>0)},onMobileCaseSearchKey(e){if(e.key==="Enter"){e.preventDefault();const t=[...document.querySelectorAll("#mobileCaseList .mobile-case-item:not([hidden])")];t.length===1&&t[0].click()}else e.key==="Escape"&&(e.preventDefault(),e.stopPropagation(),e.target.value?(e.target.value="",this.filterMobileCases()):this.closeMobileCasePicker())},closeMobileCasePicker(){document.getElementById("mobileCasePickerModal").classList.remove("active")},selectMobileCase(e){const t=document.getElementById("quickStartCase");t.value=e,this.updateMobileCaseLabel(e),this.updateDirDisplayForCase(e),this.saveLastUsedCase(e),this.closeMobileCasePicker(),this.showToast(`Selected: ${e}`,"success")},updateMobileCaseLabel(e){const t=document.getElementById("mobileCaseName");t&&(t.textContent=e)},async deleteCaseMobile(e){if(confirm(`Delete case "${e}"?`))try{const s=await(await fetch(`/api/cases/${encodeURIComponent(e)}`,{method:"DELETE"})).json();s.success?(this.showToast(`Case "${e}" ${s.data?.type==="unlinked"?"unlinked":"deleted"}`,"success"),this.cases=(this.cases||[]).filter(n=>n.name!==e),this.closeMobileCasePicker(),await this.loadQuickStartCases()):this.showToast(s.error||"Failed to delete case","error")}catch(t){this.showToast("Failed to delete case: "+t.message,"error")}},showCreateCaseFromMobile(){this.closeMobileCasePicker(),this.showCreateCaseModal();const e=document.getElementById("createCaseModal");e.classList.add("from-mobile"),setTimeout(()=>e.classList.remove("from-mobile"),300)}}),Object.defineProperty(CodemanApp.prototype,"runMode",{configurable:!0,enumerable:!0,get(){return this._runMode||"claude"},set(e){const t=registryCliById(e);if(t&&t.enabled||!t&&BUILT_IN_RUN_MODES.has(e)){this._runMode=e;return}const s=registryCliCatalog(),n=s.find(o=>o.enabled&&o.kind==="agent")||s.find(o=>o.enabled);this._runMode=n?n.id:"claude"}});