aicodeman 1.44.0 → 1.46.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 (351) hide show
  1. package/README.md +32 -8
  2. package/dist/agent-codex-identity.d.ts +26 -0
  3. package/dist/agent-codex-identity.d.ts.map +1 -0
  4. package/dist/agent-codex-identity.js +253 -0
  5. package/dist/agent-codex-identity.js.map +1 -0
  6. package/dist/agent-inspection.d.ts +32 -0
  7. package/dist/agent-inspection.d.ts.map +1 -0
  8. package/dist/agent-inspection.js +196 -0
  9. package/dist/agent-inspection.js.map +1 -0
  10. package/dist/agent-staging.d.ts +130 -0
  11. package/dist/agent-staging.d.ts.map +1 -0
  12. package/dist/agent-staging.js +312 -0
  13. package/dist/agent-staging.js.map +1 -0
  14. package/dist/case-rename.d.ts +65 -0
  15. package/dist/case-rename.d.ts.map +1 -0
  16. package/dist/case-rename.js +198 -0
  17. package/dist/case-rename.js.map +1 -0
  18. package/dist/cli-agent.d.ts +91 -3
  19. package/dist/cli-agent.d.ts.map +1 -1
  20. package/dist/cli-agent.js +501 -44
  21. package/dist/cli-agent.js.map +1 -1
  22. package/dist/cli-history.d.ts +20 -0
  23. package/dist/cli-history.d.ts.map +1 -0
  24. package/dist/cli-history.js +61 -0
  25. package/dist/cli-history.js.map +1 -0
  26. package/dist/cli.d.ts.map +1 -1
  27. package/dist/cli.js +6 -1
  28. package/dist/cli.js.map +1 -1
  29. package/dist/codex-rollout-format.d.ts +66 -0
  30. package/dist/codex-rollout-format.d.ts.map +1 -0
  31. package/dist/codex-rollout-format.js +111 -0
  32. package/dist/codex-rollout-format.js.map +1 -0
  33. package/dist/codex-transcript.d.ts +3 -0
  34. package/dist/codex-transcript.d.ts.map +1 -1
  35. package/dist/codex-transcript.js +13 -41
  36. package/dist/codex-transcript.js.map +1 -1
  37. package/dist/config/auth-config.d.ts +16 -1
  38. package/dist/config/auth-config.d.ts.map +1 -1
  39. package/dist/config/auth-config.js +16 -1
  40. package/dist/config/auth-config.js.map +1 -1
  41. package/dist/config/cli-registry/schema.d.ts +12 -7
  42. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  43. package/dist/config/cli-registry/schema.js +26 -0
  44. package/dist/config/cli-registry/schema.js.map +1 -1
  45. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  46. package/dist/config/cli-registry/stock.js +40 -1
  47. package/dist/config/cli-registry/stock.js.map +1 -1
  48. package/dist/config/cli-registry/types.d.ts +57 -0
  49. package/dist/config/cli-registry/types.d.ts.map +1 -1
  50. package/dist/config/server-timing.d.ts +6 -0
  51. package/dist/config/server-timing.d.ts.map +1 -1
  52. package/dist/config/server-timing.js +9 -0
  53. package/dist/config/server-timing.js.map +1 -1
  54. package/dist/daemon-control.d.ts +1 -0
  55. package/dist/daemon-control.d.ts.map +1 -1
  56. package/dist/daemon-control.js +2 -0
  57. package/dist/daemon-control.js.map +1 -1
  58. package/dist/deepseek-transcript.d.ts +9 -7
  59. package/dist/deepseek-transcript.d.ts.map +1 -1
  60. package/dist/deepseek-transcript.js +9 -7
  61. package/dist/deepseek-transcript.js.map +1 -1
  62. package/dist/docker-hosts.d.ts +8 -0
  63. package/dist/docker-hosts.d.ts.map +1 -1
  64. package/dist/docker-hosts.js +29 -0
  65. package/dist/docker-hosts.js.map +1 -1
  66. package/dist/git-fetch-scheduler.d.ts +124 -0
  67. package/dist/git-fetch-scheduler.d.ts.map +1 -0
  68. package/dist/git-fetch-scheduler.js +249 -0
  69. package/dist/git-fetch-scheduler.js.map +1 -0
  70. package/dist/git-fetch.d.ts +241 -0
  71. package/dist/git-fetch.d.ts.map +1 -0
  72. package/dist/git-fetch.js +392 -0
  73. package/dist/git-fetch.js.map +1 -0
  74. package/dist/git-workspace-status.d.ts +36 -1
  75. package/dist/git-workspace-status.d.ts.map +1 -1
  76. package/dist/git-workspace-status.js +42 -5
  77. package/dist/git-workspace-status.js.map +1 -1
  78. package/dist/hooks-config.d.ts +14 -2
  79. package/dist/hooks-config.d.ts.map +1 -1
  80. package/dist/hooks-config.js +39 -3
  81. package/dist/hooks-config.js.map +1 -1
  82. package/dist/host-sensors.d.ts +115 -0
  83. package/dist/host-sensors.d.ts.map +1 -0
  84. package/dist/host-sensors.js +457 -0
  85. package/dist/host-sensors.js.map +1 -0
  86. package/dist/local-history.d.ts +71 -0
  87. package/dist/local-history.d.ts.map +1 -0
  88. package/dist/local-history.js +750 -0
  89. package/dist/local-history.js.map +1 -0
  90. package/dist/mcp-server.d.ts.map +1 -1
  91. package/dist/mcp-server.js +2 -2
  92. package/dist/mcp-server.js.map +1 -1
  93. package/dist/mux-interface.d.ts +5 -2
  94. package/dist/mux-interface.d.ts.map +1 -1
  95. package/dist/prompt-cache-keepwarm.d.ts.map +1 -1
  96. package/dist/prompt-cache-keepwarm.js +5 -3
  97. package/dist/prompt-cache-keepwarm.js.map +1 -1
  98. package/dist/remote-hosts.d.ts +7 -0
  99. package/dist/remote-hosts.d.ts.map +1 -1
  100. package/dist/remote-hosts.js +17 -3
  101. package/dist/remote-hosts.js.map +1 -1
  102. package/dist/remote-pane-history.d.ts.map +1 -1
  103. package/dist/remote-pane-history.js +2 -2
  104. package/dist/remote-pane-history.js.map +1 -1
  105. package/dist/session.d.ts +113 -0
  106. package/dist/session.d.ts.map +1 -1
  107. package/dist/session.js +354 -13
  108. package/dist/session.js.map +1 -1
  109. package/dist/terminal-input-classifier.d.ts +8 -0
  110. package/dist/terminal-input-classifier.d.ts.map +1 -0
  111. package/dist/terminal-input-classifier.js +60 -0
  112. package/dist/terminal-input-classifier.js.map +1 -0
  113. package/dist/tmux-manager.d.ts +30 -4
  114. package/dist/tmux-manager.d.ts.map +1 -1
  115. package/dist/tmux-manager.js +101 -21
  116. package/dist/tmux-manager.js.map +1 -1
  117. package/dist/tmux-prefix-table.d.ts +37 -5
  118. package/dist/tmux-prefix-table.d.ts.map +1 -1
  119. package/dist/tmux-prefix-table.js +40 -5
  120. package/dist/tmux-prefix-table.js.map +1 -1
  121. package/dist/tui/tui-app.d.ts +8 -1
  122. package/dist/tui/tui-app.d.ts.map +1 -1
  123. package/dist/tui/tui-app.js +49 -12
  124. package/dist/tui/tui-app.js.map +1 -1
  125. package/dist/tui/tui-client.d.ts +90 -3
  126. package/dist/tui/tui-client.d.ts.map +1 -1
  127. package/dist/tui/tui-client.js +195 -26
  128. package/dist/tui/tui-client.js.map +1 -1
  129. package/dist/types/session.d.ts +15 -0
  130. package/dist/types/session.d.ts.map +1 -1
  131. package/dist/types/session.js.map +1 -1
  132. package/dist/web/agent-inbox-persistence.d.ts +52 -0
  133. package/dist/web/agent-inbox-persistence.d.ts.map +1 -0
  134. package/dist/web/agent-inbox-persistence.js +139 -0
  135. package/dist/web/agent-inbox-persistence.js.map +1 -0
  136. package/dist/web/agent-inbox.d.ts +140 -0
  137. package/dist/web/agent-inbox.d.ts.map +1 -0
  138. package/dist/web/agent-inbox.js +258 -0
  139. package/dist/web/agent-inbox.js.map +1 -0
  140. package/dist/web/middleware/auth.d.ts +2 -0
  141. package/dist/web/middleware/auth.d.ts.map +1 -1
  142. package/dist/web/middleware/auth.js +145 -52
  143. package/dist/web/middleware/auth.js.map +1 -1
  144. package/dist/web/network-auth-policy.d.ts +13 -3
  145. package/dist/web/network-auth-policy.d.ts.map +1 -1
  146. package/dist/web/network-auth-policy.js +15 -3
  147. package/dist/web/network-auth-policy.js.map +1 -1
  148. package/dist/web/ports/infra-port.d.ts +2 -0
  149. package/dist/web/ports/infra-port.d.ts.map +1 -1
  150. package/dist/web/public/admin-ui.js.gz +0 -0
  151. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  152. package/dist/web/public/app.3093527f.js +43 -0
  153. package/dist/web/public/app.3093527f.js.br +0 -0
  154. package/dist/web/public/app.3093527f.js.gz +0 -0
  155. package/dist/web/public/approvals-ui.js.gz +0 -0
  156. package/dist/web/public/{constants.4866ecc3.js → constants.affcdde6.js} +622 -12
  157. package/dist/web/public/constants.affcdde6.js.br +0 -0
  158. package/dist/web/public/constants.affcdde6.js.gz +0 -0
  159. package/dist/web/public/cron-ui.js.gz +0 -0
  160. package/dist/web/public/entrance-animations.js.gz +0 -0
  161. package/dist/web/public/git-status-ui.js +88 -5
  162. package/dist/web/public/git-status-ui.js.br +0 -0
  163. package/dist/web/public/git-status-ui.js.gz +0 -0
  164. package/dist/web/public/header-divider.eb2d2463.js +1 -0
  165. package/dist/web/public/header-divider.eb2d2463.js.br +0 -0
  166. package/dist/web/public/header-divider.eb2d2463.js.gz +0 -0
  167. package/dist/web/public/home-sessions.js.gz +0 -0
  168. package/dist/web/public/host-wake-ui.js.gz +0 -0
  169. package/dist/web/public/i18n.70265257.js +2 -0
  170. package/dist/web/public/i18n.70265257.js.br +0 -0
  171. package/dist/web/public/i18n.70265257.js.gz +0 -0
  172. package/dist/web/public/image-input.941386e7.js.gz +0 -0
  173. package/dist/web/public/index.html +170 -16
  174. package/dist/web/public/index.html.br +0 -0
  175. package/dist/web/public/index.html.gz +0 -0
  176. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  177. package/dist/web/public/keyboard-accessory.4e8b20ac.js.gz +0 -0
  178. package/dist/web/public/{mobile-handlers.44adaa07.js → mobile-handlers.f7c3f692.js} +26 -2
  179. package/dist/web/public/mobile-handlers.f7c3f692.js.br +0 -0
  180. package/dist/web/public/mobile-handlers.f7c3f692.js.gz +0 -0
  181. package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
  182. package/dist/web/public/mobile-overview.js.gz +0 -0
  183. package/dist/web/public/mobile.1bbd2d67.css +1 -0
  184. package/dist/web/public/mobile.1bbd2d67.css.br +0 -0
  185. package/dist/web/public/mobile.1bbd2d67.css.gz +0 -0
  186. package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
  187. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  188. package/dist/web/public/{panels-ui.cbb24ba1.js → panels-ui.4a56ee63.js} +76 -70
  189. package/dist/web/public/panels-ui.4a56ee63.js.br +0 -0
  190. package/dist/web/public/panels-ui.4a56ee63.js.gz +0 -0
  191. package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
  192. package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
  193. package/dist/web/public/readmymind-ui.js.gz +0 -0
  194. package/dist/web/public/reboot-restore-ui.js.gz +0 -0
  195. package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
  196. package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
  197. package/dist/web/public/session-lineage.js.gz +0 -0
  198. package/dist/web/public/session-ui.186f9419.js +106 -0
  199. package/dist/web/public/session-ui.186f9419.js.br +0 -0
  200. package/dist/web/public/session-ui.186f9419.js.gz +0 -0
  201. package/dist/web/public/settings-ui.a191154e.js +106 -0
  202. package/dist/web/public/settings-ui.a191154e.js.br +0 -0
  203. package/dist/web/public/settings-ui.a191154e.js.gz +0 -0
  204. package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
  205. package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
  206. package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
  207. package/dist/web/public/styles.7238eae8.css +1 -0
  208. package/dist/web/public/styles.7238eae8.css.br +0 -0
  209. package/dist/web/public/styles.7238eae8.css.gz +0 -0
  210. package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
  211. package/dist/web/public/sw.js +2 -2
  212. package/dist/web/public/sw.js.br +0 -0
  213. package/dist/web/public/sw.js.gz +0 -0
  214. package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
  215. package/dist/web/public/{tab-rail-resize.7157e0bd.js → tab-rail-resize.b5cdceaf.js} +1 -1
  216. package/dist/web/public/tab-rail-resize.b5cdceaf.js.br +0 -0
  217. package/dist/web/public/tab-rail-resize.b5cdceaf.js.gz +0 -0
  218. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
  219. package/dist/web/public/terminal-split.js.gz +0 -0
  220. package/dist/web/public/terminal-tile.js +10 -1
  221. package/dist/web/public/terminal-tile.js.br +0 -0
  222. package/dist/web/public/terminal-tile.js.gz +0 -0
  223. package/dist/web/public/terminal-ui.7e787829.js +4 -0
  224. package/dist/web/public/terminal-ui.7e787829.js.br +0 -0
  225. package/dist/web/public/terminal-ui.7e787829.js.gz +0 -0
  226. package/dist/web/public/tile-grid.js.gz +0 -0
  227. package/dist/web/public/ultracode-panel.js.gz +0 -0
  228. package/dist/web/public/ultracode-windows.js.gz +0 -0
  229. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  230. package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
  231. package/dist/web/public/vendor/fflate.min.js.gz +0 -0
  232. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  233. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  234. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  235. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  236. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  237. package/dist/web/public/vendor/{xterm-predictive-echo.ae5e3d5d.js → xterm-predictive-echo.276b11d9.js} +1 -1
  238. package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.br +0 -0
  239. package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.gz +0 -0
  240. package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js +5 -0
  241. package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.br +0 -0
  242. package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.gz +0 -0
  243. package/dist/web/public/vendor/xterm.css.gz +0 -0
  244. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  245. package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
  246. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  247. package/dist/web/public/webview-tabs.js.gz +0 -0
  248. package/dist/web/public/whats-new.json +9 -9
  249. package/dist/web/route-helpers.d.ts +57 -6
  250. package/dist/web/route-helpers.d.ts.map +1 -1
  251. package/dist/web/route-helpers.js +72 -4
  252. package/dist/web/route-helpers.js.map +1 -1
  253. package/dist/web/routes/agent-session-routes.d.ts +20 -0
  254. package/dist/web/routes/agent-session-routes.d.ts.map +1 -0
  255. package/dist/web/routes/agent-session-routes.js +160 -0
  256. package/dist/web/routes/agent-session-routes.js.map +1 -0
  257. package/dist/web/routes/case-routes.d.ts.map +1 -1
  258. package/dist/web/routes/case-routes.js +203 -16
  259. package/dist/web/routes/case-routes.js.map +1 -1
  260. package/dist/web/routes/config-backup-routes.js +2 -2
  261. package/dist/web/routes/config-backup-routes.js.map +1 -1
  262. package/dist/web/routes/git-status-routes.d.ts +21 -7
  263. package/dist/web/routes/git-status-routes.d.ts.map +1 -1
  264. package/dist/web/routes/git-status-routes.js +78 -12
  265. package/dist/web/routes/git-status-routes.js.map +1 -1
  266. package/dist/web/routes/inbox-routes.d.ts +43 -0
  267. package/dist/web/routes/inbox-routes.d.ts.map +1 -0
  268. package/dist/web/routes/inbox-routes.js +148 -0
  269. package/dist/web/routes/inbox-routes.js.map +1 -0
  270. package/dist/web/routes/index.d.ts +2 -0
  271. package/dist/web/routes/index.d.ts.map +1 -1
  272. package/dist/web/routes/index.js +2 -0
  273. package/dist/web/routes/index.js.map +1 -1
  274. package/dist/web/routes/ralph-routes.d.ts.map +1 -1
  275. package/dist/web/routes/ralph-routes.js +7 -16
  276. package/dist/web/routes/ralph-routes.js.map +1 -1
  277. package/dist/web/routes/session-routes.d.ts.map +1 -1
  278. package/dist/web/routes/session-routes.js +120 -74
  279. package/dist/web/routes/session-routes.js.map +1 -1
  280. package/dist/web/routes/system-routes.d.ts.map +1 -1
  281. package/dist/web/routes/system-routes.js +107 -59
  282. package/dist/web/routes/system-routes.js.map +1 -1
  283. package/dist/web/routes/ws-routes.d.ts +5 -0
  284. package/dist/web/routes/ws-routes.d.ts.map +1 -1
  285. package/dist/web/routes/ws-routes.js +84 -47
  286. package/dist/web/routes/ws-routes.js.map +1 -1
  287. package/dist/web/schemas.d.ts +56 -7
  288. package/dist/web/schemas.d.ts.map +1 -1
  289. package/dist/web/schemas.js +88 -1
  290. package/dist/web/schemas.js.map +1 -1
  291. package/dist/web/sensitive-path.d.ts.map +1 -1
  292. package/dist/web/sensitive-path.js +2 -0
  293. package/dist/web/sensitive-path.js.map +1 -1
  294. package/dist/web/server.d.ts +7 -2
  295. package/dist/web/server.d.ts.map +1 -1
  296. package/dist/web/server.js +144 -16
  297. package/dist/web/server.js.map +1 -1
  298. package/dist/web/session-wait-registry.d.ts +48 -4
  299. package/dist/web/session-wait-registry.d.ts.map +1 -1
  300. package/dist/web/session-wait-registry.js +144 -6
  301. package/dist/web/session-wait-registry.js.map +1 -1
  302. package/dist/web/settings-writer.d.ts +47 -0
  303. package/dist/web/settings-writer.d.ts.map +1 -0
  304. package/dist/web/settings-writer.js +110 -0
  305. package/dist/web/settings-writer.js.map +1 -0
  306. package/dist/web/sse-events.d.ts +4 -1
  307. package/dist/web/sse-events.d.ts.map +1 -1
  308. package/dist/web/sse-events.js +4 -1
  309. package/dist/web/sse-events.js.map +1 -1
  310. package/package.json +1 -1
  311. package/skills/codeman/SKILL.md +30 -8
  312. package/skills/codeman/preamble.sh +3 -3
  313. package/skills/codeman/reference/endpoints.md +24 -3
  314. package/skills/codeman/reference/history.md +84 -0
  315. package/skills/codeman/reference/inspection-and-staging.md +152 -0
  316. package/skills/codeman/reference/messaging.md +1 -1
  317. package/skills/codeman/reference/verbs.md +65 -3
  318. package/dist/web/public/app.9314ee60.js +0 -43
  319. package/dist/web/public/app.9314ee60.js.br +0 -0
  320. package/dist/web/public/app.9314ee60.js.gz +0 -0
  321. package/dist/web/public/constants.4866ecc3.js.br +0 -0
  322. package/dist/web/public/constants.4866ecc3.js.gz +0 -0
  323. package/dist/web/public/i18n.22ca902b.js +0 -2
  324. package/dist/web/public/i18n.22ca902b.js.br +0 -0
  325. package/dist/web/public/i18n.22ca902b.js.gz +0 -0
  326. package/dist/web/public/mobile-handlers.44adaa07.js.br +0 -0
  327. package/dist/web/public/mobile-handlers.44adaa07.js.gz +0 -0
  328. package/dist/web/public/mobile.12fb18de.css +0 -1
  329. package/dist/web/public/mobile.12fb18de.css.br +0 -0
  330. package/dist/web/public/mobile.12fb18de.css.gz +0 -0
  331. package/dist/web/public/panels-ui.cbb24ba1.js.br +0 -0
  332. package/dist/web/public/panels-ui.cbb24ba1.js.gz +0 -0
  333. package/dist/web/public/session-ui.9c1f009b.js +0 -104
  334. package/dist/web/public/session-ui.9c1f009b.js.br +0 -0
  335. package/dist/web/public/session-ui.9c1f009b.js.gz +0 -0
  336. package/dist/web/public/settings-ui.fea9ddae.js +0 -106
  337. package/dist/web/public/settings-ui.fea9ddae.js.br +0 -0
  338. package/dist/web/public/settings-ui.fea9ddae.js.gz +0 -0
  339. package/dist/web/public/styles.e096fcd6.css +0 -1
  340. package/dist/web/public/styles.e096fcd6.css.br +0 -0
  341. package/dist/web/public/styles.e096fcd6.css.gz +0 -0
  342. package/dist/web/public/tab-rail-resize.7157e0bd.js.br +0 -0
  343. package/dist/web/public/tab-rail-resize.7157e0bd.js.gz +0 -0
  344. package/dist/web/public/terminal-ui.68dbd352.js +0 -2
  345. package/dist/web/public/terminal-ui.68dbd352.js.br +0 -0
  346. package/dist/web/public/terminal-ui.68dbd352.js.gz +0 -0
  347. package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.br +0 -0
  348. package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
  349. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js +0 -4
  350. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.br +0 -0
  351. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.gz +0 -0
@@ -1,12 +1,18 @@
1
- "use strict";const AWAY_DIGEST_LAST_VIEWED_KEY="codeman-away-digest-last-viewed",FILE_BROWSER_SHOW_HIDDEN_KEY="codeman:fileBrowserShowHidden",TEXT_PREVIEW_MAX_BYTES=524288,TEXT_PREVIEW_MAX_LINES=500,MARKDOWN_PREVIEW_MAX_LINES=1e4,MARKDOWN_EXTS=new Set(["md","markdown"]),FILE_PREVIEW_PREF_KEYS={mdRendered:"codeman:filePreviewMdRendered",htmlRendered:"codeman:filePreviewHtmlRendered",lineNumbers:"codeman:filePreviewLineNumbers",wrap:"codeman:filePreviewWrap",expanded:"codeman:filePreviewExpanded"},FILE_PREVIEW_PREF_DEFAULTS={mdRendered:!0,htmlRendered:!0,lineNumbers:!1,wrap:!0,expanded:!1},FILE_PREVIEW_HISTORY_MAX=50,AWAY_DIGEST_SECTIONS=[["needsAttention","Needs Attention"],["completed","Completed"],["stillRunning","Still Running"],["idle","Idle"],["informational","Informational"]];Object.assign(CodemanApp.prototype,{_addActivityEntry(e,t,s=50){const i=this.subagentActivity.get(e)||[];i.push(t),i.length>s&&i.shift(),this.subagentActivity.set(e,i)},_onTaskCreated(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskCompleted(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskFailed(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskUpdated(e){e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onMuxCreated(e){this.muxSessions.push(e),this.renderMuxSessions()},_onMuxKilled(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions()},_onMuxDied(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions(),this.showToast("Mux session died: "+this.getShortId(e.sessionId),"warning")},_onMuxStatsUpdated(e){this.muxSessions=e,document.getElementById("monitorPanel").classList.contains("open")&&this.renderMuxSessions()},_onRemoteSessionReconnected(e){const t=this.getShortId(e.sessionId);this.showToast(`Remote session ${t} reconnected`,"success"),this.activeSessionId===e.sessionId&&this._pollHostReachability?.(!0)},_onRemoteReconnectExhausted(e){const t=e.sessionId,s=this.getShortId(t);this.showToast(`Remote session ${s} dropped \u2014 auto-reconnect gave up`,"error",{duration:15e3,action:{label:"Reconnect",onClick:()=>{this.sessions&&this.sessions.has(t)?this.selectSession(t,{forceReload:!0}):this.showToast("Session no longer available","warning")}}})},_onBashToolStart(e){this.handleBashToolStart(e.sessionId,e.tool)},_onBashToolEnd(e){this.handleBashToolEnd(e.sessionId,e.tool)},_onBashToolsUpdate(e){this.handleBashToolsUpdate(e.sessionId,e.tools)},_onSubagentDiscovered(e){this.subagents.set(e.agentId,e),this.subagentActivity.set(e.agentId,[]),this.subagentToolResults.delete(e.agentId),this.subagentWindows.has(e.agentId)&&this.forceCloseSubagentWindow(e.agentId),this.renderSubagentPanel(),this.findParentSessionForSubagent(e.agentId),requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId);this._notifySession(t||e.sessionId,"info","subagent-spawn","Subagent Spawned",e.description||"New background agent started")},_onSubagentUpdated(e){const t=this.subagents.get(e.agentId);t?(Object.assign(t,e),this.subagents.set(e.agentId,t)):this.subagents.set(e.agentId,e),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&(this.renderSubagentWindowContent(e.agentId),this.updateSubagentWindowHeader(e.agentId))},_onSubagentToolCall(e){this._addActivityEntry(e.agentId,{type:"tool",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){this._addActivityEntry(e.agentId,{type:"progress",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){this._addActivityEntry(e.agentId,{type:"message",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentToolResult(e){this.subagentToolResults.has(e.agentId)||this.subagentToolResults.set(e.agentId,new Map);const t=this.subagentToolResults.get(e.agentId);if(t.set(e.toolUseId,e),t.size>50){const s=t.keys().next().value;t.delete(s)}this._addActivityEntry(e.agentId,{type:"tool_result",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},async _onSubagentCompleted(e){const t=this.subagents.get(e.agentId);if(t&&(t.status="completed",this.subagents.set(e.agentId,t)),this.renderSubagentPanel(),this.updateSubagentWindows(),this.subagentWindows.has(e.agentId)){const i=this.subagentWindows.get(e.agentId);i&&!i.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId);this._notifySession(s||t?.sessionId||e.sessionId,"info","subagent-complete","Subagent Completed",t?.description||e.description||"Background agent finished"),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&(this.subagentActivity.delete(e.agentId),this.subagentToolResults.delete(e.agentId))},300*1e3),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&!this.subagentWindows.has(e.agentId)&&(this.subagents.delete(e.agentId),this.subagentParentMap.delete(e.agentId))},1800*1e3)},_onImageDetected(e){console.log("[Image Detected]",e),this.openImagePopup(e)},shouldOpenCommandPaletteFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey)return!1;const s=typeof this.getShortcutRegistry=="function"&&typeof this.matchesShortcutEvent=="function"?this.getShortcutRegistry().find(a=>a.id==="command-palette"):null;if(s){if(s.disabled||!this.matchesShortcutEvent(e,s))return!1}else if((e.key||"").toLowerCase()!=="k"&&e.code!=="KeyK"||e.shiftKey)return!1;const i=e.target;if(!i)return!0;const n=(i.tagName||"").toUpperCase(),o=typeof i.className=="string"?i.className:"";return i.classList?.contains?.("xterm-helper-textarea")||o.includes("xterm-helper-textarea")?!0:!(n==="INPUT"||n==="TEXTAREA"||n==="SELECT"||i.isContentEditable||typeof i.closest=="function"&&i.closest('[contenteditable="true"]'))},_rememberOverlayFocus(e){this[e]=typeof document<"u"&&document.activeElement||null},_restoreOverlayFocus(e,t){const s=this[e];this[e]=null;const i=typeof document<"u"?document.body:null,n=typeof document<"u"?document.activeElement:null;if(!(n&&n!==i&&t?.contains?.(n)===!1)){if(s&&s!==i&&s.isConnected!==!1&&typeof s.focus=="function"){s.focus();return}this.activeSessionId&&this._shouldFocusTerminalForTabSwitch?.()!==!1&&this.terminal?.focus?.()}},openCommandPalette(){const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch");!e||!t||(this.commandPaletteActiveIndex=0,t.value="",e.classList.add("active"),this._wireCommandPalette(),this.renderCommandPalette(),this._rememberOverlayFocus("_commandPalettePrevFocus"),t.focus(),t.select?.())},closeCommandPalette(){const e=document.getElementById("commandPaletteModal");e?.classList?.contains("active")&&(e.classList.remove("active"),this._restoreOverlayFocus("_commandPalettePrevFocus",e))},_wireCommandPalette(){if(this._commandPaletteWired)return;this._commandPaletteWired=!0;const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch"),s=document.getElementById("commandPaletteList");t?.addEventListener("input",()=>{this.commandPaletteActiveIndex=0,this.renderCommandPalette()}),t?.addEventListener("keydown",async i=>{if(i.key==="ArrowDown"){i.preventDefault(),this.moveCommandPaletteSelection(1);return}if(i.key==="ArrowUp"){i.preventDefault(),this.moveCommandPaletteSelection(-1);return}if(i.key==="Enter"){i.preventDefault(),i.stopPropagation(),await this.activateCommandPaletteItem();return}i.key==="Escape"&&(i.preventDefault(),this.closeCommandPalette())}),e?.addEventListener("keydown",i=>{i.key==="Escape"&&(i.preventDefault(),this.closeCommandPalette())}),s?.addEventListener?.("click",i=>{const n=i.target?.closest?.("[data-command-index]");n&&(this.commandPaletteActiveIndex=Number(n.dataset.commandIndex)||0,this.activateCommandPaletteItem())})},buildCommandPaletteItems(e=""){const t=e.trim().toLowerCase(),s=[...Array.isArray(this.sessionOrder)?this.sessionOrder:[],...Array.from(this.sessions?.keys?.()||[]).filter(o=>!this.sessionOrder?.includes?.(o))],i=new Set,n=[];for(const o of s){if(i.has(o))continue;i.add(o);const l=this.sessions?.get?.(o);if(!l)continue;const a=this.getSessionName?.(l)||l.name||l.title||o.slice(0,8),r=[l.workingDir,l.mode,l.status].filter(Boolean),c=[a,l.workingDir,l.mode,l.status,o].filter(Boolean).join(" ").toLowerCase();t&&!c.includes(t)||n.push({id:`session:${o}`,type:"session",sessionId:o,title:a,subtitle:r.join(" \xB7 ")})}return n.push(this._buildCommandPaletteNewSessionItem(e)),n.push({id:"browse-sessions",type:"browse-sessions",title:"Browse all sessions\u2026",subtitle:"Open Session Manager"}),n},_buildCommandPaletteNewSessionItem(e=""){const t=this.runMode||this._runMode||"claude",s={claude:"Claude",opencode:"OpenCode",codex:"Codex",gemini:"Gemini",antigravity:"Antigravity",pi:"Pi",grok:"Grok",deepseek:"DeepSeek",omp:"OMP",copilot:"Copilot"},i=this._findCommandPaletteCaseMatch(e)||document.getElementById("quickStartCase")?.value||"testcase";return{id:"new-session",type:"new-session",caseName:i,title:"New session",subtitle:`Run ${s[t]||t} in ${i}`}},_findCommandPaletteCaseMatch(e=""){const t=e.trim().toLowerCase();if(!t||!Array.isArray(this.cases))return null;const s=o=>{const l=String(o?.name||"").trim();if(!l)return 0;const a=[l,o?.path,o?.casePath,o?.workingDir,o?.remote?.path,o?.remote?.hostId].filter(Boolean).join(" ").toLowerCase(),r=l.toLowerCase();return r===t?100:r.startsWith(t)?90:r.includes(t)?80:a.includes(t)?60:0};let i=null,n=0;for(const o of this.cases){const l=s(o);l>n&&(i=o,n=l)}return i?.name||null},renderCommandPalette(){const e=document.getElementById("commandPaletteSearch"),t=document.getElementById("commandPaletteList");if(!t)return;const s=e?.value||"",i=this.buildCommandPaletteItems(s);this.commandPaletteItems=i,this.commandPaletteActiveIndex=Math.max(0,Math.min(this.commandPaletteActiveIndex||0,i.length-1)),t.innerHTML=i.map((n,o)=>{const l=o===this.commandPaletteActiveIndex?" active":"",a=n.type==="new-session"?"+":n.type==="browse-sessions"?"\u2261":"\u203A",r=n.type==="browse-sessions"?" command-palette-item--browse":"";return`
2
- <button class="command-palette-item${l}${r}" type="button" data-command-index="${o}">
1
+ "use strict";const AWAY_DIGEST_LAST_VIEWED_KEY="codeman-away-digest-last-viewed",FILE_BROWSER_SHOW_HIDDEN_KEY="codeman:fileBrowserShowHidden",TEXT_PREVIEW_MAX_BYTES=524288,TEXT_PREVIEW_MAX_LINES=500,MARKDOWN_PREVIEW_MAX_LINES=1e4,MARKDOWN_EXTS=new Set(["md","markdown"]),FILE_PREVIEW_PREF_KEYS={mdRendered:"codeman:filePreviewMdRendered",htmlRendered:"codeman:filePreviewHtmlRendered",lineNumbers:"codeman:filePreviewLineNumbers",wrap:"codeman:filePreviewWrap",expanded:"codeman:filePreviewExpanded"},FILE_PREVIEW_PREF_DEFAULTS={mdRendered:!0,htmlRendered:!0,lineNumbers:!1,wrap:!0,expanded:!1},FILE_PREVIEW_HISTORY_MAX=50,AWAY_DIGEST_SECTIONS=[["needsAttention","Needs Attention"],["completed","Completed"],["stillRunning","Still Running"],["idle","Idle"],["informational","Informational"]];Object.assign(CodemanApp.prototype,{_addActivityEntry(e,t,s=50){const n=this.subagentActivity.get(e)||[];n.push(t),n.length>s&&n.shift(),this.subagentActivity.set(e,n)},_onTaskCreated(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskCompleted(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskFailed(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskUpdated(e){e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onMuxCreated(e){this.muxSessions.push(e),this.renderMuxSessions()},_onMuxKilled(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions()},_onMuxDied(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions(),this.showToast("Mux session died: "+this.getShortId(e.sessionId),"warning")},_onMuxStatsUpdated(e){this.muxSessions=e,document.getElementById("monitorPanel").classList.contains("open")&&this.renderMuxSessions()},_onRemoteSessionReconnected(e){const t=this.getShortId(e.sessionId);this.showToast(`Remote session ${t} reconnected`,"success"),this.activeSessionId===e.sessionId&&this._pollHostReachability?.(!0)},_onRemoteReconnectExhausted(e){const t=e.sessionId,s=this.getShortId(t);this.showToast(`Remote session ${s} dropped \u2014 auto-reconnect gave up`,"error",{duration:15e3,action:{label:"Reconnect",onClick:()=>{this.sessions&&this.sessions.has(t)?this.selectSession(t,{forceReload:!0}):this.showToast("Session no longer available","warning")}}})},_onBashToolStart(e){this.handleBashToolStart(e.sessionId,e.tool)},_onBashToolEnd(e){this.handleBashToolEnd(e.sessionId,e.tool)},_onBashToolsUpdate(e){this.handleBashToolsUpdate(e.sessionId,e.tools)},_onSubagentDiscovered(e){this.subagents.set(e.agentId,e),this.subagentActivity.set(e.agentId,[]),this.subagentToolResults.delete(e.agentId),this.subagentWindows.has(e.agentId)&&this.forceCloseSubagentWindow(e.agentId),this.renderSubagentPanel(),this.findParentSessionForSubagent(e.agentId),requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId);this._notifySession(t||e.sessionId,"info","subagent-spawn","Subagent Spawned",e.description||"New background agent started")},_onSubagentUpdated(e){const t=this.subagents.get(e.agentId);t?(Object.assign(t,e),this.subagents.set(e.agentId,t)):this.subagents.set(e.agentId,e),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&(this.renderSubagentWindowContent(e.agentId),this.updateSubagentWindowHeader(e.agentId))},_onSubagentToolCall(e){this._addActivityEntry(e.agentId,{type:"tool",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){this._addActivityEntry(e.agentId,{type:"progress",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){this._addActivityEntry(e.agentId,{type:"message",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentToolResult(e){this.subagentToolResults.has(e.agentId)||this.subagentToolResults.set(e.agentId,new Map);const t=this.subagentToolResults.get(e.agentId);if(t.set(e.toolUseId,e),t.size>50){const s=t.keys().next().value;t.delete(s)}this._addActivityEntry(e.agentId,{type:"tool_result",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},async _onSubagentCompleted(e){const t=this.subagents.get(e.agentId);if(t&&(t.status="completed",this.subagents.set(e.agentId,t)),this.renderSubagentPanel(),this.updateSubagentWindows(),this.subagentWindows.has(e.agentId)){const n=this.subagentWindows.get(e.agentId);n&&!n.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId);this._notifySession(s||t?.sessionId||e.sessionId,"info","subagent-complete","Subagent Completed",t?.description||e.description||"Background agent finished"),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&(this.subagentActivity.delete(e.agentId),this.subagentToolResults.delete(e.agentId))},300*1e3),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&!this.subagentWindows.has(e.agentId)&&(this.subagents.delete(e.agentId),this.subagentParentMap.delete(e.agentId))},1800*1e3)},_onImageDetected(e){console.log("[Image Detected]",e),this.openImagePopup(e)},shouldOpenCommandPaletteFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey)return!1;const s=typeof this.getShortcutRegistry=="function"&&typeof this.matchesShortcutEvent=="function"?this.getShortcutRegistry().find(a=>a.id==="command-palette"):null;if(s){if(s.disabled||!this.matchesShortcutEvent(e,s))return!1}else if((e.key||"").toLowerCase()!=="k"&&e.code!=="KeyK"||e.shiftKey)return!1;const n=e.target;if(!n)return!0;const i=(n.tagName||"").toUpperCase(),o=typeof n.className=="string"?n.className:"";return n.classList?.contains?.("xterm-helper-textarea")||o.includes("xterm-helper-textarea")?!0:!(i==="INPUT"||i==="TEXTAREA"||i==="SELECT"||n.isContentEditable||typeof n.closest=="function"&&n.closest('[contenteditable="true"]'))},_rememberOverlayFocus(e){this[e]=typeof document<"u"&&document.activeElement||null},_restoreOverlayFocus(e,t){const s=this[e];this[e]=null;const n=typeof document<"u"?document.body:null,i=typeof document<"u"?document.activeElement:null;if(!(i&&i!==n&&t?.contains?.(i)===!1)){if(s&&s!==n&&s.isConnected!==!1&&typeof s.focus=="function"){s.focus();return}this.activeSessionId&&this._shouldFocusTerminalForTabSwitch?.()!==!1&&this.terminal?.focus?.()}},openCommandPalette(){const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch");!e||!t||(this.commandPaletteActiveIndex=0,this._resetCommandPaletteAgent(),t.value="",e.classList.add("active"),this._wireCommandPalette(),this.renderCommandPalette(),this._rememberOverlayFocus("_commandPalettePrevFocus"),t.focus(),t.select?.())},closeCommandPalette(){const e=document.getElementById("commandPaletteModal");e?.classList?.contains("active")&&(e.classList.remove("active"),this._restoreOverlayFocus("_commandPalettePrevFocus",e))},_wireCommandPalette(){if(this._commandPaletteWired)return;this._commandPaletteWired=!0;const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch"),s=document.getElementById("commandPaletteList");t?.addEventListener("input",()=>{this.commandPaletteActiveIndex=0,this.renderCommandPalette()}),t?.addEventListener("keydown",async n=>{if((n.key==="ArrowLeft"||n.key==="ArrowRight")&&this._commandPaletteArrowCyclesAgent(n)){n.preventDefault(),this._cycleCommandPaletteAgent(n.key==="ArrowRight"?1:-1);return}if(n.key==="ArrowDown"){n.preventDefault(),this.moveCommandPaletteSelection(1);return}if(n.key==="ArrowUp"){n.preventDefault(),this.moveCommandPaletteSelection(-1);return}if(n.key==="Enter"){n.preventDefault(),n.stopPropagation(),await this.activateCommandPaletteItem();return}n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),e?.addEventListener("keydown",n=>{n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),s?.addEventListener?.("mousedown",n=>{n.target?.closest?.("[data-palette-agent-cycle]")&&n.preventDefault?.()}),s?.addEventListener?.("click",n=>{const i=n.target?.closest?.("[data-palette-agent-cycle]");if(i){n.preventDefault?.(),n.stopPropagation?.(),this._cycleCommandPaletteAgent(i.dataset.paletteAgentCycle==="prev"?-1:1);return}const o=n.target?.closest?.("[data-command-index]");o&&(this.commandPaletteActiveIndex=Number(o.dataset.commandIndex)||0,this.activateCommandPaletteItem())})},buildCommandPaletteItems(e=""){const t=e.trim().toLowerCase(),s=[...Array.isArray(this.sessionOrder)?this.sessionOrder:[],...Array.from(this.sessions?.keys?.()||[]).filter(o=>!this.sessionOrder?.includes?.(o))],n=new Set,i=[];for(const o of s){if(n.has(o))continue;n.add(o);const l=this.sessions?.get?.(o);if(!l)continue;const a=this.getSessionName?.(l)||l.name||l.title||o.slice(0,8),r=[l.workingDir,l.mode,l.status].filter(Boolean),c=[a,l.workingDir,l.mode,l.status,o].filter(Boolean).join(" ").toLowerCase();t&&!c.includes(t)||i.push({id:`session:${o}`,type:"session",sessionId:o,title:a,subtitle:r.join(" \xB7 ")})}return i.push(this._buildCommandPaletteNewSessionItem(e)),i.push({id:"browse-sessions",type:"browse-sessions",title:"Browse all sessions\u2026",subtitle:"Open Session Manager"}),i},_buildCommandPaletteNewSessionItem(e=""){const t=this._commandPaletteCaseName(e),s=this._commandPaletteAgent(t),n=s?.id||this.runMode||this._runMode||"claude",i={claude:"Claude",opencode:"OpenCode",codex:"Codex",gemini:"Gemini",antigravity:"Antigravity",pi:"Pi",grok:"Grok",deepseek:"DeepSeek",omp:"OMP",copilot:"Copilot"};return{id:"new-session",type:"new-session",caseName:t,mode:n,title:"New session",subtitle:`Run ${s?.label||i[n]||n} in ${t}`}},_commandPaletteCaseName(e=""){return this._findCommandPaletteCaseMatch(e)||document.getElementById("quickStartCase")?.value||"testcase"},_commandPaletteRowCase(){const e=(this.commandPaletteItems||[]).find(t=>t?.type==="new-session");return e?e.caseName:this._commandPaletteCaseName(document.getElementById("commandPaletteSearch")?.value||"")},_commandPaletteAgentChoices(e=this._commandPaletteRowCase()){const t=typeof window<"u"&&Array.isArray(window.__codemanCliCatalog)?window.__codemanCliCatalog:[],s=n=>typeof this._runModeAvailableForCase=="function"?this._runModeAvailableForCase(n,e):this.isCliAvailable?.(n)??!0;return t.filter(n=>n&&typeof n.id=="string"&&n.enabled&&(n.kind!=="agent"||s(n.id))).map(n=>({id:n.id,label:typeof n.label=="string"&&n.label.trim()||n.id}))},_commandPaletteAgent(e=this._commandPaletteRowCase()){const t=this._commandPaletteAgentChoices(e);if(t.length<2)return null;const s=this.runMode||this._runMode;return t.find(n=>n.id===this._commandPaletteAgentId)||t.find(n=>n.id===s)||t[0]},_resetCommandPaletteAgent(){this._commandPaletteAgentId=null},_cycleCommandPaletteAgent(e){const t=this._commandPaletteRowCase(),s=this._commandPaletteAgentChoices(t);if(s.length<2)return;const n=Math.max(0,s.findIndex(i=>i.id===this._commandPaletteAgent(t)?.id));this._commandPaletteAgentId=s[((n+e)%s.length+s.length)%s.length].id,this.renderCommandPalette()},_commandPaletteArrowCyclesAgent(e){const t=(this.commandPaletteItems||[])[this.commandPaletteActiveIndex||0];if(t?.type!=="new-session"||this._commandPaletteAgentChoices(t.caseName).length<2||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey)return!1;const s=e.target,n=typeof s?.value=="string"?s.value:"",i=Number.isFinite(s?.selectionStart)?s.selectionStart:n.length,o=Number.isFinite(s?.selectionEnd)?s.selectionEnd:i;return i!==o?!1:i<=0||o>=n.length},_findCommandPaletteCaseMatch(e=""){const t=e.trim().toLowerCase();if(!t||!Array.isArray(this.cases))return null;const s=o=>{const l=String(o?.name||"").trim();if(!l)return 0;const a=[l,o?.path,o?.casePath,o?.workingDir,o?.remote?.path,o?.remote?.hostId].filter(Boolean).join(" ").toLowerCase(),r=l.toLowerCase();return r===t?100:r.startsWith(t)?90:r.includes(t)?80:a.includes(t)?60:0};let n=null,i=0;for(const o of this.cases){const l=s(o);l>i&&(n=o,i=l)}return n?.name||null},renderCommandPalette(){const e=document.getElementById("commandPaletteSearch"),t=document.getElementById("commandPaletteList");if(!t)return;const s=e?.value||"",n=this.buildCommandPaletteItems(s);this.commandPaletteItems=n,this.commandPaletteActiveIndex=Math.max(0,Math.min(this.commandPaletteActiveIndex||0,n.length-1)),t.innerHTML=n.map((i,o)=>{const l=o===this.commandPaletteActiveIndex?" active":"",a=i.type==="new-session"?"+":i.type==="browse-sessions"?"\u2261":"\u203A",r=i.type==="browse-sessions"?" command-palette-item--browse":"",c=i.type==="new-session"?this._renderCommandPaletteAgentPicker(i.mode,i.caseName):"";return`
2
+ <button class="command-palette-item${l}${r}${c?" command-palette-item--agent":""}" type="button" data-command-index="${o}">
3
3
  <span class="command-palette-icon" aria-hidden="true">${a}</span>
4
4
  <span class="command-palette-text">
5
- <span class="command-palette-title">${escapeHtml(n.title)}</span>
6
- <span class="command-palette-subtitle">${escapeHtml(n.subtitle||"")}</span>
7
- </span>
5
+ <span class="command-palette-title">${escapeHtml(i.title)}</span>
6
+ <span class="command-palette-subtitle">${escapeHtml(i.subtitle||"")}</span>
7
+ </span>${c}
8
8
  </button>
9
- `}).join("")},moveCommandPaletteSelection(e){const t=this.commandPaletteItems||this.buildCommandPaletteItems(document.getElementById("commandPaletteSearch")?.value||"");t.length&&(this.commandPaletteActiveIndex=(this.commandPaletteActiveIndex+e+t.length)%t.length,this.renderCommandPalette())},async activateCommandPaletteItem(e=this.commandPaletteActiveIndex||0){const t=(this.commandPaletteItems||[])[e];if(t){if(this.closeCommandPalette(),t.type==="session"&&t.sessionId){await this.selectSession(t.sessionId);return}if(t.type==="browse-sessions"){this.openSessionManager();return}if(t.type==="new-session"){const s=document.getElementById("quickStartCase");if(s&&t.caseName){if(s.tagName==="SELECT"&&typeof s.appendChild=="function"&&!Array.from(s.options||[]).some(i=>i.value===t.caseName)){const i=document.createElement("option");i.value=t.caseName,i.textContent=t.caseName,s.appendChild(i)}typeof this.selectQuickStartCase=="function"?this.selectQuickStartCase(t.caseName):s.value=t.caseName}await this.run()}}},async openSessionManager(){const e=document.getElementById("sessionManagerModal");if(e&&(e.classList.add("active"),this._sessionManagerEscWired||(this._sessionManagerEscWired=!0,e.addEventListener("keydown",s=>{s.key==="Escape"&&(s.preventDefault(),s.stopPropagation(),this.closeSessionManager())}))),!Array.isArray(this.cases)||this.cases.length===0)try{const s=await fetch("/api/cases"),i=s.ok?await s.json():null;this.cases=i?.data||[]}catch{this.cases=this.cases||[]}const t=document.getElementById("sessionManagerSearch");t&&(this._sessionManagerSearchWired||(this._sessionManagerSearchWired=!0,t.addEventListener("input",()=>{const s=t.value.trim();this._debouncedCall("sessionManagerSearch",()=>this._loadSessionManagerList(s),200)})),t.value="",this._rememberOverlayFocus("_sessionManagerPrevFocus"),t.focus()),await this._loadSessionManagerList("")},closeSessionManager(){const e=document.getElementById("sessionManagerModal");e?.classList?.contains("active")&&(e.classList.remove("active"),this._restoreOverlayFocus("_sessionManagerPrevFocus",e))},_setSessionManagerMessage(e,t){e.replaceChildren();const s=document.createElement("p");s.className="empty-message",s.textContent=t,e.appendChild(s)},async _loadSessionManagerList(e=""){this._sessionManagerQuery=e;const t=document.getElementById("sessionManagerList");if(t)try{const s="/api/sessions/unified?limit=200"+(e?"&q="+encodeURIComponent(e):""),i=await fetch(s),n=await i.json().catch(()=>null);if(!i.ok||!n||n.success===!1||!n.data){this._setSessionManagerMessage(t,n?.error||`Failed to load sessions (HTTP ${i.status})`);return}const o=n.data.sessions||[];if(t.replaceChildren(),o.length===0){this._setSessionManagerMessage(t,e?"No sessions match your search":"No sessions found");return}for(const l of o){const a={sessionId:l.sessionId,workingDir:l.workingDir||"",sizeBytes:l.sizeBytes??0,lastModified:new Date(l.lastActivityAt??l.createdAt??Date.now()).toISOString(),firstPrompt:l.firstPrompt||l.name||"",gitBranch:l.gitBranch,worktreeName:l.worktreeName,worktreeRepo:l.worktreeRepo,mode:l.mode,claudeSessionId:l.claudeSessionId,resumeId:l.resumeId},r=!!this.sessions?.has?.(l.sessionId),c=this._buildHistoryItem(a,this.cases,{showViewAll:!1,onActivate:()=>{this.closeSessionManager(),r?this.selectSession(l.sessionId):a.workingDir&&this.resumeHistorySession(l.claudeSessionId||l.sessionId,a.workingDir,void 0,l.mode,l.resumeId)}});t.appendChild(c)}}catch(s){console.error("[_loadSessionManagerList]",s),this._setSessionManagerMessage(t,"Failed to load sessions")}},async openAwayDigest(e="since-last-visit"){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this._awayDigestSinceLastVisitGeneratedAt=void 0;const t=document.getElementById("awayDigestModal");t&&t.classList.add("active"),this.updateAwayDigestRangeControls(),await this.loadAwayDigest()},closeAwayDigest(){const e=document.getElementById("awayDigestModal"),t=this._awayDigestSinceLastVisitGeneratedAt;if(Number.isFinite(t))try{localStorage.setItem(AWAY_DIGEST_LAST_VIEWED_KEY,String(t))}catch(s){console.warn("Failed to save away digest last-viewed marker:",s)}e&&e.classList.remove("active")},_onSessionListMaybeChanged(){const e=document.getElementById("sessionManagerModal");e&&e.classList.contains("active")&&this._debouncedCall("sessionManagerRefresh",()=>this._loadSessionManagerList(this._sessionManagerQuery||""),400);const t=document.getElementById("welcomeOverlay");t&&t.classList.contains("visible")&&this._debouncedCall("welcomeHistoryRefresh",()=>this.loadHistorySessions(),600)},setAwayDigestRange(e){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this.updateAwayDigestRangeControls(),this.loadAwayDigest()},updateAwayDigestRangeControls(){const e=this.awayDigestRange||"since-last-visit";document.querySelectorAll("[data-away-range]").forEach(s=>{s.classList.toggle("active",s.dataset.awayRange===e)});const t=document.getElementById("awayDigestCustomRange");t&&t.classList.toggle("active",e==="custom"),e==="custom"&&this.ensureAwayDigestCustomDefaults()},ensureAwayDigestCustomDefaults(){const e=document.getElementById("awayDigestCustomSince"),t=document.getElementById("awayDigestCustomUntil");if(!e||!t)return;const s=new Date;if(t.value||(t.value=this.formatAwayDigestDateTimeLocal(s)),!e.value){const i=new Date(s.getTime()-36e5);e.value=this.formatAwayDigestDateTimeLocal(i)}},formatAwayDigestDateTimeLocal(e){const t=s=>String(s).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`},async loadAwayDigest(){const e=document.getElementById("awayDigestSummary"),t=document.getElementById("awayDigestFreshness"),s=document.getElementById("awayDigestSections");e&&(e.innerHTML='<div class="away-digest-loading">Loading digest...</div>'),t&&(t.textContent=""),s&&(s.innerHTML="");try{const i=this.awayDigestRange||"since-last-visit",n=new URLSearchParams({range:i});if(i==="since-last-visit"){const a=this.readAwayDigestLastViewed();Number.isFinite(a)&&n.set("lastViewed",String(a))}if(i==="custom"){this.ensureAwayDigestCustomDefaults();const a=this.readAwayDigestDateTimeInput("awayDigestCustomSince"),r=this.readAwayDigestDateTimeInput("awayDigestCustomUntil");if(!Number.isFinite(a))throw new Error("Choose a custom start time");n.set("since",String(a)),Number.isFinite(r)&&n.set("until",String(r))}const o=await fetch(`/api/away-digest?${n.toString()}`),l=await o.json();if(!o.ok||!l.success)throw new Error(l.error||"Failed to load away digest");this._awayDigestLoadedSuccessfully=!0,this._awayDigestGeneratedAt=l.digest.generatedAt,i==="since-last-visit"&&(this._awayDigestSinceLastVisitGeneratedAt=l.digest.generatedAt),this.renderAwayDigest(l.digest)}catch(i){const n=i instanceof Error?i.message:"Failed to load away digest";console.error("Failed to fetch away digest:",i),e&&(e.innerHTML='<div class="away-digest-load-error">Failed to load away digest</div>'),s&&(s.innerHTML=`<div class="empty-message">${escapeHtml(n)}</div>`),this.showToast(n,"error")}},readAwayDigestLastViewed(){try{const e=localStorage.getItem(AWAY_DIGEST_LAST_VIEWED_KEY),t=Number(e);return Number.isFinite(t)?t:void 0}catch{return}},readAwayDigestDateTimeInput(e){const t=document.getElementById(e);if(!t||!t.value)return;const s=Date.parse(t.value);return Number.isFinite(s)?s:void 0},renderAwayDigest(e){const t=document.getElementById("awayDigestSummary"),s=document.getElementById("awayDigestFreshness"),i=document.getElementById("awayDigestSections");if(!t||!s||!i)return;const n=e.totals.inputTokens||0,o=e.totals.outputTokens||0,l=e.totals.estimatedCost||0;t.innerHTML=`
9
+ `}).join("")},_renderCommandPaletteAgentPicker(e,t){const s=this._commandPaletteAgentChoices(t);if(s.length<2)return"";const n=s.find(i=>i.id===e)||s[0];return`
10
+ <span class="command-palette-agent" aria-hidden="true" title="Agent for the new session (Left/Right to change)">
11
+ <span class="command-palette-agent-arrow" data-palette-agent-cycle="prev">&lsaquo;</span>
12
+ <span class="run-mode-dot ${escapeHtml(n.id)}" aria-hidden="true"></span>
13
+ <span class="command-palette-agent-label">${escapeHtml(n.label)}</span>
14
+ <span class="command-palette-agent-arrow" data-palette-agent-cycle="next">&rsaquo;</span>
15
+ </span>`},moveCommandPaletteSelection(e){const t=this.commandPaletteItems||this.buildCommandPaletteItems(document.getElementById("commandPaletteSearch")?.value||"");t.length&&(this.commandPaletteActiveIndex=(this.commandPaletteActiveIndex+e+t.length)%t.length,this.renderCommandPalette())},async activateCommandPaletteItem(e=this.commandPaletteActiveIndex||0){const t=(this.commandPaletteItems||[])[e];if(t){if(this.closeCommandPalette(),t.type==="session"&&t.sessionId){await this.selectSession(t.sessionId);return}if(t.type==="browse-sessions"){this.openSessionManager();return}if(t.type==="new-session"){const s=document.getElementById("quickStartCase");if(s&&t.caseName){if(s.tagName==="SELECT"&&typeof s.appendChild=="function"&&!Array.from(s.options||[]).some(i=>i.value===t.caseName)){const i=document.createElement("option");i.value=t.caseName,i.textContent=t.caseName,s.appendChild(i)}typeof this.selectQuickStartCase=="function"?this.selectQuickStartCase(t.caseName):s.value=t.caseName}const n=this._runMode;t.mode&&(this._runMode=t.mode);try{await this.run()}finally{this._runMode=n}}}},async openSessionManager(){const e=document.getElementById("sessionManagerModal");if(e&&(e.classList.add("active"),this._sessionManagerEscWired||(this._sessionManagerEscWired=!0,e.addEventListener("keydown",s=>{s.key==="Escape"&&(s.preventDefault(),s.stopPropagation(),this.closeSessionManager())}))),!Array.isArray(this.cases)||this.cases.length===0)try{const s=await fetch("/api/cases"),n=s.ok?await s.json():null;this.cases=n?.data||[]}catch{this.cases=this.cases||[]}const t=document.getElementById("sessionManagerSearch");t&&(this._sessionManagerSearchWired||(this._sessionManagerSearchWired=!0,t.addEventListener("input",()=>{const s=t.value.trim();this._debouncedCall("sessionManagerSearch",()=>this._loadSessionManagerList(s),200)})),t.value="",this._rememberOverlayFocus("_sessionManagerPrevFocus"),t.focus()),await this._loadSessionManagerList("")},closeSessionManager(){const e=document.getElementById("sessionManagerModal");e?.classList?.contains("active")&&(e.classList.remove("active"),this._restoreOverlayFocus("_sessionManagerPrevFocus",e))},_setSessionManagerMessage(e,t){e.replaceChildren();const s=document.createElement("p");s.className="empty-message",s.textContent=t,e.appendChild(s)},async _loadSessionManagerList(e=""){this._sessionManagerQuery=e;const t=document.getElementById("sessionManagerList");if(t)try{const s="/api/sessions/unified?limit=200"+(e?"&q="+encodeURIComponent(e):""),n=await fetch(s),i=await n.json().catch(()=>null);if(!n.ok||!i||i.success===!1||!i.data){this._setSessionManagerMessage(t,i?.error||`Failed to load sessions (HTTP ${n.status})`);return}const o=i.data.sessions||[];if(t.replaceChildren(),o.length===0){this._setSessionManagerMessage(t,e?"No sessions match your search":"No sessions found");return}for(const l of o){const a={sessionId:l.sessionId,workingDir:l.workingDir||"",sizeBytes:l.sizeBytes??0,lastModified:new Date(l.lastActivityAt??l.createdAt??Date.now()).toISOString(),firstPrompt:l.firstPrompt||l.name||"",gitBranch:l.gitBranch,worktreeName:l.worktreeName,worktreeRepo:l.worktreeRepo,mode:l.mode,claudeSessionId:l.claudeSessionId,resumeId:l.resumeId},r=!!this.sessions?.has?.(l.sessionId),c=this._buildHistoryItem(a,this.cases,{showViewAll:!1,onActivate:()=>{this.closeSessionManager(),r?this.selectSession(l.sessionId):a.workingDir&&this.resumeHistorySession(l.claudeSessionId||l.sessionId,a.workingDir,void 0,l.mode,l.resumeId)}});t.appendChild(c)}}catch(s){console.error("[_loadSessionManagerList]",s),this._setSessionManagerMessage(t,"Failed to load sessions")}},async openAwayDigest(e="since-last-visit"){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this._awayDigestSinceLastVisitGeneratedAt=void 0;const t=document.getElementById("awayDigestModal");t&&t.classList.add("active"),this.updateAwayDigestRangeControls(),await this.loadAwayDigest()},closeAwayDigest(){const e=document.getElementById("awayDigestModal"),t=this._awayDigestSinceLastVisitGeneratedAt;if(Number.isFinite(t))try{localStorage.setItem(AWAY_DIGEST_LAST_VIEWED_KEY,String(t))}catch(s){console.warn("Failed to save away digest last-viewed marker:",s)}e&&e.classList.remove("active")},_onSessionListMaybeChanged(){const e=document.getElementById("sessionManagerModal");e&&e.classList.contains("active")&&this._debouncedCall("sessionManagerRefresh",()=>this._loadSessionManagerList(this._sessionManagerQuery||""),400);const t=document.getElementById("welcomeOverlay");t&&t.classList.contains("visible")&&this._debouncedCall("welcomeHistoryRefresh",()=>this.loadHistorySessions(),600)},setAwayDigestRange(e){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this.updateAwayDigestRangeControls(),this.loadAwayDigest()},updateAwayDigestRangeControls(){const e=this.awayDigestRange||"since-last-visit";document.querySelectorAll("[data-away-range]").forEach(s=>{s.classList.toggle("active",s.dataset.awayRange===e)});const t=document.getElementById("awayDigestCustomRange");t&&t.classList.toggle("active",e==="custom"),e==="custom"&&this.ensureAwayDigestCustomDefaults()},ensureAwayDigestCustomDefaults(){const e=document.getElementById("awayDigestCustomSince"),t=document.getElementById("awayDigestCustomUntil");if(!e||!t)return;const s=new Date;if(t.value||(t.value=this.formatAwayDigestDateTimeLocal(s)),!e.value){const n=new Date(s.getTime()-36e5);e.value=this.formatAwayDigestDateTimeLocal(n)}},formatAwayDigestDateTimeLocal(e){const t=s=>String(s).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`},async loadAwayDigest(){const e=document.getElementById("awayDigestSummary"),t=document.getElementById("awayDigestFreshness"),s=document.getElementById("awayDigestSections");e&&(e.innerHTML='<div class="away-digest-loading">Loading digest...</div>'),t&&(t.textContent=""),s&&(s.innerHTML="");try{const n=this.awayDigestRange||"since-last-visit",i=new URLSearchParams({range:n});if(n==="since-last-visit"){const a=this.readAwayDigestLastViewed();Number.isFinite(a)&&i.set("lastViewed",String(a))}if(n==="custom"){this.ensureAwayDigestCustomDefaults();const a=this.readAwayDigestDateTimeInput("awayDigestCustomSince"),r=this.readAwayDigestDateTimeInput("awayDigestCustomUntil");if(!Number.isFinite(a))throw new Error("Choose a custom start time");i.set("since",String(a)),Number.isFinite(r)&&i.set("until",String(r))}const o=await fetch(`/api/away-digest?${i.toString()}`),l=await o.json();if(!o.ok||!l.success)throw new Error(l.error||"Failed to load away digest");this._awayDigestLoadedSuccessfully=!0,this._awayDigestGeneratedAt=l.digest.generatedAt,n==="since-last-visit"&&(this._awayDigestSinceLastVisitGeneratedAt=l.digest.generatedAt),this.renderAwayDigest(l.digest)}catch(n){const i=n instanceof Error?n.message:"Failed to load away digest";console.error("Failed to fetch away digest:",n),e&&(e.innerHTML='<div class="away-digest-load-error">Failed to load away digest</div>'),s&&(s.innerHTML=`<div class="empty-message">${escapeHtml(i)}</div>`),this.showToast(i,"error")}},readAwayDigestLastViewed(){try{const e=localStorage.getItem(AWAY_DIGEST_LAST_VIEWED_KEY),t=Number(e);return Number.isFinite(t)?t:void 0}catch{return}},readAwayDigestDateTimeInput(e){const t=document.getElementById(e);if(!t||!t.value)return;const s=Date.parse(t.value);return Number.isFinite(s)?s:void 0},renderAwayDigest(e){const t=document.getElementById("awayDigestSummary"),s=document.getElementById("awayDigestFreshness"),n=document.getElementById("awayDigestSections");if(!t||!s||!n)return;const i=e.totals.inputTokens||0,o=e.totals.outputTokens||0,l=e.totals.estimatedCost||0;t.innerHTML=`
10
16
  <div class="away-digest-card">
11
17
  <span class="away-digest-card-label">Needs Attention</span>
12
18
  <span class="away-digest-card-value">${e.totals.needsAttention}</span>
@@ -21,18 +27,18 @@
21
27
  </div>
22
28
  <div class="away-digest-card">
23
29
  <span class="away-digest-card-label">Tokens</span>
24
- <span class="away-digest-card-value">${this.formatTokens(n+o)}</span>
30
+ <span class="away-digest-card-value">${this.formatTokens(i+o)}</span>
25
31
  <span class="away-digest-card-cost">~$${l.toFixed(2)}</span>
26
32
  </div>
27
- `;const a=[];(e.dataFreshness.runSummariesLiveOnly||e.dataFreshness.subagentsLiveOnly)&&a.push("Run summaries and subagent completions use recent live state; lifecycle and token stats are persisted."),e.totals.tokenWindowPrecision==="day"&&a.push("Token totals are aggregated at day precision."),s.textContent=a.join(" "),i.innerHTML=AWAY_DIGEST_SECTIONS.map(([r,c])=>this.renderAwayDigestSection(c,e.sections[r]||[])).join(""),this.attachAwayDigestActions()},renderAwayDigestSection(e,t){const s=t.length,i=s?t.map(n=>this.renderAwayDigestItem(n)).join(""):'<div class="away-digest-empty">No items</div>';return`
33
+ `;const a=[];(e.dataFreshness.runSummariesLiveOnly||e.dataFreshness.subagentsLiveOnly)&&a.push("Run summaries and subagent completions use recent live state; lifecycle and token stats are persisted."),e.totals.tokenWindowPrecision==="day"&&a.push("Token totals are aggregated at day precision."),s.textContent=a.join(" "),n.innerHTML=AWAY_DIGEST_SECTIONS.map(([r,c])=>this.renderAwayDigestSection(c,e.sections[r]||[])).join(""),this.attachAwayDigestActions()},renderAwayDigestSection(e,t){const s=t.length,n=s?t.map(i=>this.renderAwayDigestItem(i)).join(""):'<div class="away-digest-empty">No items</div>';return`
28
34
  <section class="away-digest-section">
29
35
  <div class="away-digest-section-title">
30
36
  <h4>${escapeHtml(e)}</h4>
31
37
  <span>${s}</span>
32
38
  </div>
33
- ${i}
39
+ ${n}
34
40
  </section>
35
- `},renderAwayDigestItem(e){const t=this.formatAwayDigestSource(e.source),s=e.sessionName||e.sessionId||"",i=e.detail?`<div class="away-digest-item-detail">${escapeHtml(e.detail)}</div>`:"",n=e.link?`
41
+ `},renderAwayDigestItem(e){const t=this.formatAwayDigestSource(e.source),s=e.sessionName||e.sessionId||"",n=e.detail?`<div class="away-digest-item-detail">${escapeHtml(e.detail)}</div>`:"",i=e.link?`
36
42
  <button class="away-digest-action"
37
43
  data-away-link-type="${escapeHtml(e.link.type)}"
38
44
  data-away-session-id="${escapeHtml(e.link.sessionId||"")}">
@@ -47,15 +53,15 @@
47
53
  ${s?`<span>${escapeHtml(s)}</span>`:""}
48
54
  </div>
49
55
  <div class="away-digest-item-title">${escapeHtml(e.title)}</div>
50
- ${i}
56
+ ${n}
51
57
  </div>
52
- ${n}
58
+ ${i}
53
59
  </article>
54
- `},attachAwayDigestActions(){const e=document.getElementById("awayDigestSections");e&&e.querySelectorAll("[data-away-link-type]").forEach(t=>{t.addEventListener("click",()=>{this.openAwayDigestItem(t.dataset.awayLinkType,t.dataset.awaySessionId||void 0)})})},async openAwayDigestItem(e,t){if(e==="session"&&t){await this.selectSession(t),this.closeAwayDigest();return}if(e==="run_summary"&&t){await this.openRunSummary(t),this.closeAwayDigest();return}e==="lifecycle"&&(this.openLifecycleLog(),this.closeAwayDigest())},formatAwayDigestTimestamp(e){return Number.isFinite(e)?new Date(e).toLocaleString([],{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}):""},formatAwayDigestSource(e){return{lifecycle:"Lifecycle",run_summary:"Run Summary",status:"Status",token_stats:"Token Stats",subagent:"Subagent"}[e]||e},async openTokenStats(){try{const t=await(await fetch("/api/token-stats")).json();t.success?(this.renderTokenStats(t.data),document.getElementById("tokenStatsModal").classList.add("active")):this.showToast("Failed to load token stats","error")}catch(e){console.error("Failed to fetch token stats:",e),this.showToast("Failed to load token stats","error")}},renderTokenStats(e){const{daily:t,totals:s}=e,i=new Date().toISOString().split("T")[0],n=t.find(m=>m.date===i)||{inputTokens:0,outputTokens:0,estimatedCost:0},o=new Date;o.setDate(o.getDate()-7);const l=t.filter(m=>new Date(m.date)>=o),a=l.reduce((m,S)=>m+S.inputTokens,0),r=l.reduce((m,S)=>m+S.outputTokens,0),c=this.estimateCost(a,r),h=s.totalInputTokens,d=s.totalOutputTokens,u=this.estimateCost(h,d),p=document.getElementById("statsSummary");p.innerHTML=`
60
+ `},attachAwayDigestActions(){const e=document.getElementById("awayDigestSections");e&&e.querySelectorAll("[data-away-link-type]").forEach(t=>{t.addEventListener("click",()=>{this.openAwayDigestItem(t.dataset.awayLinkType,t.dataset.awaySessionId||void 0)})})},async openAwayDigestItem(e,t){if(e==="session"&&t){await this.selectSession(t),this.closeAwayDigest();return}if(e==="run_summary"&&t){await this.openRunSummary(t),this.closeAwayDigest();return}e==="lifecycle"&&(this.openLifecycleLog(),this.closeAwayDigest())},formatAwayDigestTimestamp(e){return Number.isFinite(e)?new Date(e).toLocaleString([],{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}):""},formatAwayDigestSource(e){return{lifecycle:"Lifecycle",run_summary:"Run Summary",status:"Status",token_stats:"Token Stats",subagent:"Subagent"}[e]||e},async openTokenStats(){try{const t=await(await fetch("/api/token-stats")).json();t.success?(this.renderTokenStats(t.data),document.getElementById("tokenStatsModal").classList.add("active")):this.showToast("Failed to load token stats","error")}catch(e){console.error("Failed to fetch token stats:",e),this.showToast("Failed to load token stats","error")}},renderTokenStats(e){const{daily:t,totals:s}=e,n=new Date().toISOString().split("T")[0],i=t.find(m=>m.date===n)||{inputTokens:0,outputTokens:0,estimatedCost:0},o=new Date;o.setDate(o.getDate()-7);const l=t.filter(m=>new Date(m.date)>=o),a=l.reduce((m,S)=>m+S.inputTokens,0),r=l.reduce((m,S)=>m+S.outputTokens,0),c=this.estimateCost(a,r),h=s.totalInputTokens,d=s.totalOutputTokens,u=this.estimateCost(h,d),p=document.getElementById("statsSummary");p.innerHTML=`
55
61
  <div class="stat-card">
56
62
  <span class="stat-card-label">Today</span>
57
- <span class="stat-card-value">${this.formatTokens(n.inputTokens+n.outputTokens)}</span>
58
- <span class="stat-card-cost">~$${n.estimatedCost.toFixed(2)}</span>
63
+ <span class="stat-card-value">${this.formatTokens(i.inputTokens+i.outputTokens)}</span>
64
+ <span class="stat-card-cost">~$${i.estimatedCost.toFixed(2)}</span>
59
65
  </div>
60
66
  <div class="stat-card">
61
67
  <span class="stat-card-label">7 Days</span>
@@ -67,14 +73,14 @@
67
73
  <span class="stat-card-value">${this.formatTokens(h+d)}</span>
68
74
  <span class="stat-card-cost">~$${u.toFixed(2)}</span>
69
75
  </div>
70
- `;const f=document.getElementById("statsChart"),w=document.getElementById("statsChartDays"),y=[];for(let m=6;m>=0;m--){const S=new Date;S.setDate(S.getDate()-m);const $=S.toISOString().split("T")[0],b=t.find(C=>C.date===$);y.push({date:$,dayName:S.toLocaleDateString("en-US",{weekday:"short"}),tokens:b?b.inputTokens+b.outputTokens:0,cost:b?b.estimatedCost:0})}const v=Math.max(...y.map(m=>m.tokens),1);f.innerHTML=y.map(m=>{const S=Math.max(m.tokens/v*100,3),$=`${m.dayName}: ${this.formatTokens(m.tokens)} (~$${m.cost.toFixed(2)})`;return`<div class="bar" style="height: ${S}%" data-tooltip="${$}"></div>`}).join(""),w.innerHTML=y.map(m=>`<span>${m.dayName}</span>`).join("");const g=document.getElementById("statsTable"),T=t.slice(0,14);T.length===0?g.innerHTML='<div class="stats-no-data">No usage data recorded yet</div>':g.innerHTML=`
76
+ `;const f=document.getElementById("statsChart"),w=document.getElementById("statsChartDays"),y=[];for(let m=6;m>=0;m--){const S=new Date;S.setDate(S.getDate()-m);const $=S.toISOString().split("T")[0],b=t.find(T=>T.date===$);y.push({date:$,dayName:S.toLocaleDateString("en-US",{weekday:"short"}),tokens:b?b.inputTokens+b.outputTokens:0,cost:b?b.estimatedCost:0})}const v=Math.max(...y.map(m=>m.tokens),1);f.innerHTML=y.map(m=>{const S=Math.max(m.tokens/v*100,3),$=`${m.dayName}: ${this.formatTokens(m.tokens)} (~$${m.cost.toFixed(2)})`;return`<div class="bar" style="height: ${S}%" data-tooltip="${$}"></div>`}).join(""),w.innerHTML=y.map(m=>`<span>${m.dayName}</span>`).join("");const g=document.getElementById("statsTable"),C=t.slice(0,14);C.length===0?g.innerHTML='<div class="stats-no-data">No usage data recorded yet</div>':g.innerHTML=`
71
77
  <div class="stats-table-header">
72
78
  <span>Date</span>
73
79
  <span>Input</span>
74
80
  <span>Output</span>
75
81
  <span>Cost</span>
76
82
  </div>
77
- ${T.map(m=>`
83
+ ${C.map(m=>`
78
84
  <div class="stats-table-row">
79
85
  <span class="cell cell-date">${new Date(m.date+"T00:00:00").toLocaleDateString("en-US",{month:"short",day:"numeric"})}</span>
80
86
  <span class="cell">${this.formatTokens(m.inputTokens)}</span>
@@ -82,7 +88,7 @@
82
88
  <span class="cell cell-cost">$${m.estimatedCost.toFixed(2)}</span>
83
89
  </div>
84
90
  `).join("")}
85
- `},closeTokenStats(){const e=document.getElementById("tokenStatsModal");e&&e.classList.remove("active")},async toggleMonitorPanel(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorToggleBtn");e.classList.toggle("open"),e.classList.contains("open")?(e.style.display="",await this.loadMuxSessions(),await fetch("/api/mux-sessions/stats/start",{method:"POST"}),this.renderTaskPanel(),t&&(t.innerHTML="&#x25BC;")):(await fetch("/api/mux-sessions/stats/stop",{method:"POST"}),t&&(t.innerHTML="&#x25B2;"))},toggleTaskPanel(){this.toggleMonitorPanel()},toggleMonitorDetach(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupMonitorDrag())},setupMonitorDrag(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorPanelHeader");if(!e||!t)return;let s=!1,i,n,o,l;const a=h=>{if(h.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const d=getEventCoords(h);i=d.clientX,n=d.clientY;const u=e.getBoundingClientRect();o=u.left,l=u.top,document.addEventListener("mousemove",r),document.addEventListener("mouseup",c),document.addEventListener("touchmove",r,{passive:!1}),document.addEventListener("touchend",c),h.preventDefault()},r=h=>{if(!s)return;const d=getEventCoords(h),u=d.clientX-i,p=d.clientY-n;let f=o+u,w=l+p;const y=e.getBoundingClientRect();f=Math.max(0,Math.min(window.innerWidth-y.width,f)),w=Math.max(0,Math.min(window.innerHeight-y.height,w)),e.style.left=f+"px",e.style.top=w+"px"},c=()=>{s=!1,document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",r),document.removeEventListener("touchend",c)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=a,t._touchDragHandler=a,t.addEventListener("mousedown",a),t.addEventListener("touchstart",a,{passive:!1})},toggleSubagentsDetach(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupSubagentsDrag())},setupSubagentsDrag(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsPanelHeader");if(!e||!t)return;let s=!1,i,n,o,l;const a=h=>{if(h.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const d=getEventCoords(h);i=d.clientX,n=d.clientY;const u=e.getBoundingClientRect();o=u.left,l=u.top,document.addEventListener("mousemove",r),document.addEventListener("mouseup",c),document.addEventListener("touchmove",r,{passive:!1}),document.addEventListener("touchend",c),h.preventDefault()},r=h=>{if(!s)return;const d=getEventCoords(h),u=d.clientX-i,p=d.clientY-n;let f=o+u,w=l+p;const y=e.getBoundingClientRect();f=Math.max(0,Math.min(window.innerWidth-y.width,f)),w=Math.max(0,Math.min(window.innerHeight-y.height,w)),e.style.left=f+"px",e.style.top=w+"px"},c=()=>{s=!1,document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",r),document.removeEventListener("touchend",c)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=a,t._touchDragHandler=a,t.addEventListener("mousedown",a),t.addEventListener("touchstart",a,{passive:!1})},renderTaskPanel(){this._debouncedCall("taskPanel",this._renderTaskPanelImmediate)},_renderTaskPanelImmediate(){const e=this.sessions.get(this.activeSessionId),t=document.getElementById("backgroundTasksBody"),s=document.getElementById("taskPanelStats"),i=document.getElementById("backgroundTasksSection");if(!e||!e.taskTree||e.taskTree.length===0){i&&(i.style.display="none"),t.innerHTML="",s.textContent="0 tasks";return}i&&(i.style.display="");const n=e.taskStats||{running:0,completed:0,failed:0,total:0};s.textContent=`${n.running} running, ${n.completed} done`;const o=(r,c)=>{const h=r.status==="running"?"":r.status==="completed"?"&#x2713;":"&#x2717;",d=r.endTime?`${((r.endTime-r.startTime)/1e3).toFixed(1)}s`:`${((Date.now()-r.startTime)/1e3).toFixed(0)}s...`;let u="";if(r.children&&r.children.length>0){u='<div class="task-children">';for(const p of r.children){const f=c.find(w=>w.id===p);f&&(u+=`<div class="task-node">${o(f,c)}</div>`)}u+="</div>"}return`
91
+ `},closeTokenStats(){const e=document.getElementById("tokenStatsModal");e&&e.classList.remove("active")},async toggleMonitorPanel(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorToggleBtn");e.classList.toggle("open"),e.classList.contains("open")?(e.style.display="",await this.loadMuxSessions(),await fetch("/api/mux-sessions/stats/start",{method:"POST"}),this.renderTaskPanel(),t&&(t.innerHTML="&#x25BC;")):(await fetch("/api/mux-sessions/stats/stop",{method:"POST"}),t&&(t.innerHTML="&#x25B2;"))},toggleTaskPanel(){this.toggleMonitorPanel()},toggleMonitorDetach(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupMonitorDrag())},setupMonitorDrag(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorPanelHeader");if(!e||!t)return;let s=!1,n,i,o,l;const a=h=>{if(h.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const d=getEventCoords(h);n=d.clientX,i=d.clientY;const u=e.getBoundingClientRect();o=u.left,l=u.top,document.addEventListener("mousemove",r),document.addEventListener("mouseup",c),document.addEventListener("touchmove",r,{passive:!1}),document.addEventListener("touchend",c),h.preventDefault()},r=h=>{if(!s)return;const d=getEventCoords(h),u=d.clientX-n,p=d.clientY-i;let f=o+u,w=l+p;const y=e.getBoundingClientRect();f=Math.max(0,Math.min(window.innerWidth-y.width,f)),w=Math.max(0,Math.min(window.innerHeight-y.height,w)),e.style.left=f+"px",e.style.top=w+"px"},c=()=>{s=!1,document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",r),document.removeEventListener("touchend",c)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=a,t._touchDragHandler=a,t.addEventListener("mousedown",a),t.addEventListener("touchstart",a,{passive:!1})},toggleSubagentsDetach(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupSubagentsDrag())},setupSubagentsDrag(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsPanelHeader");if(!e||!t)return;let s=!1,n,i,o,l;const a=h=>{if(h.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const d=getEventCoords(h);n=d.clientX,i=d.clientY;const u=e.getBoundingClientRect();o=u.left,l=u.top,document.addEventListener("mousemove",r),document.addEventListener("mouseup",c),document.addEventListener("touchmove",r,{passive:!1}),document.addEventListener("touchend",c),h.preventDefault()},r=h=>{if(!s)return;const d=getEventCoords(h),u=d.clientX-n,p=d.clientY-i;let f=o+u,w=l+p;const y=e.getBoundingClientRect();f=Math.max(0,Math.min(window.innerWidth-y.width,f)),w=Math.max(0,Math.min(window.innerHeight-y.height,w)),e.style.left=f+"px",e.style.top=w+"px"},c=()=>{s=!1,document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",r),document.removeEventListener("touchend",c)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=a,t._touchDragHandler=a,t.addEventListener("mousedown",a),t.addEventListener("touchstart",a,{passive:!1})},renderTaskPanel(){this._debouncedCall("taskPanel",this._renderTaskPanelImmediate)},_renderTaskPanelImmediate(){const e=this.sessions.get(this.activeSessionId),t=document.getElementById("backgroundTasksBody"),s=document.getElementById("taskPanelStats"),n=document.getElementById("backgroundTasksSection");if(!e||!e.taskTree||e.taskTree.length===0){n&&(n.style.display="none"),t.innerHTML="",s.textContent="0 tasks";return}n&&(n.style.display="");const i=e.taskStats||{running:0,completed:0,failed:0,total:0};s.textContent=`${i.running} running, ${i.completed} done`;const o=(r,c)=>{const h=r.status==="running"?"":r.status==="completed"?"&#x2713;":"&#x2717;",d=r.endTime?`${((r.endTime-r.startTime)/1e3).toFixed(1)}s`:`${((Date.now()-r.startTime)/1e3).toFixed(0)}s...`;let u="";if(r.children&&r.children.length>0){u='<div class="task-children">';for(const p of r.children){const f=c.find(w=>w.id===p);f&&(u+=`<div class="task-node">${o(f,c)}</div>`)}u+="</div>"}return`
86
92
  <div class="task-item">
87
93
  <span class="task-status-icon ${r.status}">${h}</span>
88
94
  <div class="task-info">
@@ -94,28 +100,28 @@
94
100
  </div>
95
101
  </div>
96
102
  ${u}
97
- `},l=this.flattenTaskTree(e.taskTree);let a='<div class="task-tree">';for(const r of e.taskTree)a+=`<div class="task-node">${o(r,l)}</div>`;a+="</div>",t.innerHTML=a},flattenTaskTree(e,t=[]){for(const s of e)t.push(s);return t},toggleSubagentPanel(){this.toggleSubagentsPanel()},updateSubagentBadge(){const e=this.$("subagentCountBadge"),t=Array.from(this.subagents.values()).filter(s=>s.status==="active"||s.status==="idle").length;e&&(e.textContent=t>0?t:"")},renderSubagentPanel(){this._subagentPanelRenderTimeout&&clearTimeout(this._subagentPanelRenderTimeout),this._subagentPanelRenderTimeout=setTimeout(()=>{scheduleBackground(()=>this._renderSubagentPanelImmediate())},150)},_renderSubagentPanelImmediate(){const e=this.$("subagentList");if(!e||(this.updateSubagentBadge(),this.renderMonitorSubagents(),!this.subagentPanelVisible))return;if(this.subagents.size===0){e.innerHTML='<div class="subagent-empty">No background agents detected</div>';return}const t=[],s=Array.from(this.subagents.values()).sort((i,n)=>i.status==="active"&&n.status!=="active"?-1:n.status==="active"&&i.status!=="active"?1:(n.lastActivityAt||0)-(i.lastActivityAt||0));for(const i of s){const n=this.activeSubagentId===i.agentId,o=i.status==="active"?"active":i.status==="idle"?"idle":"completed",l=this.subagentActivity.get(i.agentId)||[],a=l[l.length-1],r=a?.type==="tool"?a.tool:null,c=this.subagentWindows.has(i.agentId),h=i.status==="active"||i.status==="idle",d=i.modelShort?`<span class="subagent-model-badge ${escapeHtml(i.modelShort)}">${escapeHtml(i.modelShort)}</span>`:"",u=this.getTeammateInfo(i),p=u?u.name:i.description||i.agentId.substring(0,7),f=this.getTeammateBadgeHtml(i),w=u?`<span class="subagent-icon teammate-dot teammate-color-${u.color}">\u25CF</span>`:'<span class="subagent-icon">\u{1F916}</span>';t.push(`
98
- <div class="subagent-item ${o} ${n?"selected":""}${u?" is-teammate":""}"
99
- onclick="app.selectSubagent(${escapeHtml(JSON.stringify(i.agentId))})"
100
- ondblclick="app.openSubagentWindow(${escapeHtml(JSON.stringify(i.agentId))})"
103
+ `},l=this.flattenTaskTree(e.taskTree);let a='<div class="task-tree">';for(const r of e.taskTree)a+=`<div class="task-node">${o(r,l)}</div>`;a+="</div>",t.innerHTML=a},flattenTaskTree(e,t=[]){for(const s of e)t.push(s);return t},toggleSubagentPanel(){this.toggleSubagentsPanel()},updateSubagentBadge(){const e=this.$("subagentCountBadge"),t=Array.from(this.subagents.values()).filter(s=>s.status==="active"||s.status==="idle").length;e&&(e.textContent=t>0?t:"")},renderSubagentPanel(){this._subagentPanelRenderTimeout&&clearTimeout(this._subagentPanelRenderTimeout),this._subagentPanelRenderTimeout=setTimeout(()=>{scheduleBackground(()=>this._renderSubagentPanelImmediate())},150)},_renderSubagentPanelImmediate(){const e=this.$("subagentList");if(!e||(this.updateSubagentBadge(),this.renderMonitorSubagents(),!this.subagentPanelVisible))return;if(this.subagents.size===0){e.innerHTML='<div class="subagent-empty">No background agents detected</div>';return}const t=[],s=Array.from(this.subagents.values()).sort((n,i)=>n.status==="active"&&i.status!=="active"?-1:i.status==="active"&&n.status!=="active"?1:(i.lastActivityAt||0)-(n.lastActivityAt||0));for(const n of s){const i=this.activeSubagentId===n.agentId,o=n.status==="active"?"active":n.status==="idle"?"idle":"completed",l=this.subagentActivity.get(n.agentId)||[],a=l[l.length-1],r=a?.type==="tool"?a.tool:null,c=this.subagentWindows.has(n.agentId),h=n.status==="active"||n.status==="idle",d=n.modelShort?`<span class="subagent-model-badge ${escapeHtml(n.modelShort)}">${escapeHtml(n.modelShort)}</span>`:"",u=this.getTeammateInfo(n),p=u?u.name:n.description||n.agentId.substring(0,7),f=this.getTeammateBadgeHtml(n),w=u?`<span class="subagent-icon teammate-dot teammate-color-${u.color}">\u25CF</span>`:'<span class="subagent-icon">\u{1F916}</span>';t.push(`
104
+ <div class="subagent-item ${o} ${i?"selected":""}${u?" is-teammate":""}"
105
+ onclick="app.selectSubagent(${escapeHtml(JSON.stringify(n.agentId))})"
106
+ ondblclick="app.openSubagentWindow(${escapeHtml(JSON.stringify(n.agentId))})"
101
107
  title="Double-click to open tracking window">
102
108
  <div class="subagent-header">
103
109
  ${w}
104
- <span class="subagent-id" title="${escapeHtml(i.description||i.agentId)}">${escapeHtml(p.length>40?p.substring(0,40)+"...":p)}</span>
110
+ <span class="subagent-id" title="${escapeHtml(n.description||n.agentId)}">${escapeHtml(p.length>40?p.substring(0,40)+"...":p)}</span>
105
111
  ${f}
106
112
  ${d}
107
- <span class="subagent-status ${o}">${i.status}</span>
108
- ${h?`<button class="subagent-kill-btn" onclick="event.stopPropagation(); app.killSubagent(${escapeHtml(JSON.stringify(i.agentId))})" title="Kill agent">&#x2715;</button>`:""}
109
- <button class="subagent-window-btn" onclick="event.stopPropagation(); app.${c?"closeSubagentWindow":"openSubagentWindow"}(${escapeHtml(JSON.stringify(i.agentId))})" title="${c?"Close window":"Open in window"}">
113
+ <span class="subagent-status ${o}">${n.status}</span>
114
+ ${h?`<button class="subagent-kill-btn" onclick="event.stopPropagation(); app.killSubagent(${escapeHtml(JSON.stringify(n.agentId))})" title="Kill agent">&#x2715;</button>`:""}
115
+ <button class="subagent-window-btn" onclick="event.stopPropagation(); app.${c?"closeSubagentWindow":"openSubagentWindow"}(${escapeHtml(JSON.stringify(n.agentId))})" title="${c?"Close window":"Open in window"}">
110
116
  ${c?"\u2715":"\u29C9"}
111
117
  </button>
112
118
  </div>
113
119
  <div class="subagent-meta">
114
- <span class="subagent-tools">${i.toolCallCount} tools</span>
120
+ <span class="subagent-tools">${n.toolCallCount} tools</span>
115
121
  ${r?`<span class="subagent-last-tool">${this.getToolIcon(r)} ${r}</span>`:""}
116
122
  </div>
117
123
  </div>
118
- `)}e.innerHTML=t.join("")},selectSubagent(e){this.activeSubagentId=e,this.renderSubagentPanel(),this.renderSubagentDetail()},renderSubagentDetail(){const e=this.$("subagentDetail");if(!e)return;if(!this.activeSubagentId){e.innerHTML='<div class="subagent-empty">Select an agent to view details</div>';return}const t=this.subagents.get(this.activeSubagentId),s=this.subagentActivity.get(this.activeSubagentId)||[];if(!t){e.innerHTML='<div class="subagent-empty">Agent not found</div>';return}const i=s.slice(-30).map(a=>{const r=new Date(a.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(a.type==="tool"){const c=this.getToolDetailExpanded(a.tool,a.input,a.fullInput,a.toolUseId);return`<div class="subagent-activity tool" data-tool-use-id="${escapeHtml(a.toolUseId||"")}">
124
+ `)}e.innerHTML=t.join("")},selectSubagent(e){this.activeSubagentId=e,this.renderSubagentPanel(),this.renderSubagentDetail()},renderSubagentDetail(){const e=this.$("subagentDetail");if(!e)return;if(!this.activeSubagentId){e.innerHTML='<div class="subagent-empty">Select an agent to view details</div>';return}const t=this.subagents.get(this.activeSubagentId),s=this.subagentActivity.get(this.activeSubagentId)||[];if(!t){e.innerHTML='<div class="subagent-empty">Agent not found</div>';return}const n=s.slice(-30).map(a=>{const r=new Date(a.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(a.type==="tool"){const c=this.getToolDetailExpanded(a.tool,a.input,a.fullInput,a.toolUseId);return`<div class="subagent-activity tool" data-tool-use-id="${escapeHtml(a.toolUseId||"")}">
119
125
  <span class="time">${r}</span>
120
126
  <span class="icon">${this.getToolIcon(a.tool)}</span>
121
127
  <span class="name">${escapeHtml(a.tool)}</span>
@@ -135,9 +141,9 @@
135
141
  <span class="time">${r}</span>
136
142
  <span class="icon">\u{1F4AC}</span>
137
143
  <span class="detail">${escapeHtml(c)}</span>
138
- </div>`}return""}).join(""),n=t.description||`Agent ${t.agentId}`,o=t.modelShort?`<span class="subagent-model-badge ${escapeHtml(t.modelShort)}">${escapeHtml(t.modelShort)}</span>`:"",l=t.totalInputTokens||t.totalOutputTokens?`<span>Tokens: ${this.formatTokenCount(t.totalInputTokens||0)}\u2193 ${this.formatTokenCount(t.totalOutputTokens||0)}\u2191</span>`:"";e.innerHTML=`
144
+ </div>`}return""}).join(""),i=t.description||`Agent ${t.agentId}`,o=t.modelShort?`<span class="subagent-model-badge ${escapeHtml(t.modelShort)}">${escapeHtml(t.modelShort)}</span>`:"",l=t.totalInputTokens||t.totalOutputTokens?`<span>Tokens: ${this.formatTokenCount(t.totalInputTokens||0)}\u2193 ${this.formatTokenCount(t.totalOutputTokens||0)}\u2191</span>`:"";e.innerHTML=`
139
145
  <div class="subagent-detail-header">
140
- <span class="subagent-id" title="${escapeHtml(t.description||t.agentId)}">${escapeHtml(n.length>60?n.substring(0,60)+"...":n)}</span>
146
+ <span class="subagent-id" title="${escapeHtml(t.description||t.agentId)}">${escapeHtml(i.length>60?i.substring(0,60)+"...":i)}</span>
141
147
  ${o}
142
148
  <span class="subagent-status ${t.status}">${t.status}</span>
143
149
  <button class="subagent-transcript-btn" onclick="app.viewSubagentTranscript(${escapeHtml(JSON.stringify(t.agentId))})">
@@ -151,9 +157,9 @@
151
157
  ${l}
152
158
  </div>
153
159
  <div class="subagent-activity-log">
154
- ${i||'<div class="subagent-empty">No activity yet</div>'}
160
+ ${n||'<div class="subagent-empty">No activity yet</div>'}
155
161
  </div>
156
- `},toggleToolParams(e){const t=document.getElementById(`tool-params-${e}`);if(!t)return;const s=t.previousElementSibling;t.style.display==="none"?(t.style.display="block",s&&(s.textContent="\u25BC")):(t.style.display="none",s&&(s.textContent="\u25B6"))},formatTokenCount(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()},formatBytes(e){return e>=1024*1024?(e/(1024*1024)).toFixed(1)+"MB":e>=1024?(e/1024).toFixed(1)+"KB":e+"B"},getToolIcon(e){return{WebSearch:"\u{1F50D}",WebFetch:"\u{1F310}",Read:"\u{1F4D6}",Write:"\u{1F4DD}",Edit:"\u270F\uFE0F",Bash:"\u{1F4BB}",Glob:"\u{1F4C1}",Grep:"\u{1F50E}",Task:"\u{1F916}"}[e]||"\u{1F527}"},getToolDetail(e,t){if(!t)return"";if(e==="WebSearch"&&t.query)return`"${t.query}"`;if(e==="WebFetch"&&t.url)return t.url;if(e==="Read"&&t.file_path||(e==="Write"||e==="Edit")&&t.file_path)return t.file_path;if(e==="Bash"&&t.command){const s=t.command;return s.length>40?s.substring(0,40)+"...":s}return e==="Glob"&&t.pattern||e==="Grep"&&t.pattern?t.pattern:""},getToolDetailExpanded(e,t,s,i){const n=this.getToolDetail(e,t),o=["query","url","file_path","command","pattern"],r=Object.keys(s||t||{}).filter(c=>!o.includes(c)).length>0||s&&JSON.stringify(s).length>100;return{primary:n,hasMore:r,fullInput:s||t}},async killSubagent(e){try{const s=await(await this._apiDelete(`/api/subagents/${e}`))?.json();if(s?.success){const i=this.subagents.get(e);i&&(i.status="completed",this.subagents.set(e,i)),this.renderSubagentPanel(),this.renderSubagentDetail(),this.updateSubagentWindows(),this.showToast(`Subagent ${e.substring(0,7)} killed`,"success")}else this.showToast(s.error||"Failed to kill subagent","error")}catch(t){console.error("Failed to kill subagent:",t),this.showToast("Failed to kill subagent: "+t.message,"error")}},async viewSubagentTranscript(e){try{const s=await(await fetch(`/api/subagents/${e}/transcript?format=formatted`)).json();if(!s.success){alert("Failed to load transcript");return}const i=s.data.formatted.join(`
162
+ `},toggleToolParams(e){const t=document.getElementById(`tool-params-${e}`);if(!t)return;const s=t.previousElementSibling;t.style.display==="none"?(t.style.display="block",s&&(s.textContent="\u25BC")):(t.style.display="none",s&&(s.textContent="\u25B6"))},formatTokenCount(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()},formatBytes(e){return e>=1024*1024?(e/(1024*1024)).toFixed(1)+"MB":e>=1024?(e/1024).toFixed(1)+"KB":e+"B"},getToolIcon(e){return{WebSearch:"\u{1F50D}",WebFetch:"\u{1F310}",Read:"\u{1F4D6}",Write:"\u{1F4DD}",Edit:"\u270F\uFE0F",Bash:"\u{1F4BB}",Glob:"\u{1F4C1}",Grep:"\u{1F50E}",Task:"\u{1F916}"}[e]||"\u{1F527}"},getToolDetail(e,t){if(!t)return"";if(e==="WebSearch"&&t.query)return`"${t.query}"`;if(e==="WebFetch"&&t.url)return t.url;if(e==="Read"&&t.file_path||(e==="Write"||e==="Edit")&&t.file_path)return t.file_path;if(e==="Bash"&&t.command){const s=t.command;return s.length>40?s.substring(0,40)+"...":s}return e==="Glob"&&t.pattern||e==="Grep"&&t.pattern?t.pattern:""},getToolDetailExpanded(e,t,s,n){const i=this.getToolDetail(e,t),o=["query","url","file_path","command","pattern"],r=Object.keys(s||t||{}).filter(c=>!o.includes(c)).length>0||s&&JSON.stringify(s).length>100;return{primary:i,hasMore:r,fullInput:s||t}},async killSubagent(e){try{const s=await(await this._apiDelete(`/api/subagents/${e}`))?.json();if(s?.success){const n=this.subagents.get(e);n&&(n.status="completed",this.subagents.set(e,n)),this.renderSubagentPanel(),this.renderSubagentDetail(),this.updateSubagentWindows(),this.showToast(`Subagent ${e.substring(0,7)} killed`,"success")}else this.showToast(s.error||"Failed to kill subagent","error")}catch(t){console.error("Failed to kill subagent:",t),this.showToast("Failed to kill subagent: "+t.message,"error")}},async viewSubagentTranscript(e){try{const s=await(await fetch(`/api/subagents/${e}/transcript?format=formatted`)).json();if(!s.success){alert("Failed to load transcript");return}const n=s.data.formatted.join(`
157
163
  `);window.open("","_blank","width=800,height=600").document.write(`
158
164
  <html>
159
165
  <head>
@@ -165,29 +171,29 @@
165
171
  </head>
166
172
  <body>
167
173
  <h2>Subagent ${escapeHtml(e)} Transcript (${s.data.entryCount} entries)</h2>
168
- <pre>${escapeHtml(i)}</pre>
174
+ <pre>${escapeHtml(n)}</pre>
169
175
  </body>
170
176
  </html>
171
- `)}catch(t){console.error("Failed to load transcript:",t),alert("Failed to load transcript: "+t.message)}},findParentSessionForSubagent(e){if(this.subagentParentMap.has(e)){const s=this.subagentParentMap.get(e);if(this.sessions.has(s)){const i=this.subagents.get(e);if(i&&!i.parentSessionId){i.parentSessionId=s;const n=this.sessions.get(s);n&&(i.parentSessionName=this.getSessionName(n)),this.subagents.set(e,i),this.updateSubagentWindowParent(e)}return}this.subagentParentMap.delete(e)}const t=this.subagents.get(e);if(t){if(t.sessionId){for(const[s,i]of this.sessions)if(i.claudeSessionId===t.sessionId){this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}}if(this.activeSessionId&&this.sessions.has(this.activeSessionId)){this.setAgentParentSessionId(e,this.activeSessionId),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}if(this.sessions.size>0){const s=this.sessions.keys().next().value;this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines()}}},recheckOrphanSubagents(){let e=!1;for(const[t,s]of this.subagents)if(!this.subagentParentMap.has(t))this.findParentSessionForSubagent(t),this.subagentParentMap.has(t)&&(e=!0);else if(s.sessionId){const i=this.subagentParentMap.get(t),n=this.sessions.get(i);if(n&&n.claudeSessionId!==s.sessionId){for(const[o,l]of this.sessions)if(l.claudeSessionId===s.sessionId){this.subagentParentMap.set(t,o),s.parentSessionId=o,s.parentSessionName=this.getSessionName(l),this.subagents.set(t,s),this.updateSubagentWindowParent(t),e=!0;break}}}e&&(this.saveSubagentParentMap(),this.updateConnectionLines())},updateSubagentParentNames(e){const t=this.sessions.get(e);if(!t)return;const s=this.getSessionName(t);if(this._parentNameCache?.get(e)!==s){this._parentNameCache||(this._parentNameCache=new Map),this._parentNameCache.set(e,s);for(const[n,o]of this.subagentParentMap)if(o===e){const l=this.subagents.get(n);if(l){l.parentSessionName=s,this.subagents.set(n,l);const a=this.subagentWindows.get(n);if(a){const r=a.element.querySelector(".subagent-window-parent .parent-name");r&&(r.textContent=s)}}}}},updateSubagentWindowParent(e){const t=this.subagentWindows.get(e);if(!t)return;const s=this.subagentParentMap.get(e);if(!s)return;const i=this.sessions.get(s),n=i?this.getSessionName(i):"Unknown",o=t.element,l=o.querySelector(".subagent-window-parent");if(l){l.dataset.parentSession=s;const r=l.querySelector(".parent-name");r&&(r.textContent=n,r.onclick=()=>this.selectSession(s));return}const a=o.querySelector(".subagent-window-header");if(a){const r=document.createElement("div");r.className="subagent-window-parent",r.dataset.parentSession=s,r.innerHTML=`
177
+ `)}catch(t){console.error("Failed to load transcript:",t),alert("Failed to load transcript: "+t.message)}},findParentSessionForSubagent(e){if(this.subagentParentMap.has(e)){const s=this.subagentParentMap.get(e);if(this.sessions.has(s)){const n=this.subagents.get(e);if(n&&!n.parentSessionId){n.parentSessionId=s;const i=this.sessions.get(s);i&&(n.parentSessionName=this.getSessionName(i)),this.subagents.set(e,n),this.updateSubagentWindowParent(e)}return}this.subagentParentMap.delete(e)}const t=this.subagents.get(e);if(t){if(t.sessionId){for(const[s,n]of this.sessions)if(n.claudeSessionId===t.sessionId){this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}}if(this.activeSessionId&&this.sessions.has(this.activeSessionId)){this.setAgentParentSessionId(e,this.activeSessionId),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}if(this.sessions.size>0){const s=this.sessions.keys().next().value;this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines()}}},recheckOrphanSubagents(){let e=!1;for(const[t,s]of this.subagents)if(!this.subagentParentMap.has(t))this.findParentSessionForSubagent(t),this.subagentParentMap.has(t)&&(e=!0);else if(s.sessionId){const n=this.subagentParentMap.get(t),i=this.sessions.get(n);if(i&&i.claudeSessionId!==s.sessionId){for(const[o,l]of this.sessions)if(l.claudeSessionId===s.sessionId){this.subagentParentMap.set(t,o),s.parentSessionId=o,s.parentSessionName=this.getSessionName(l),this.subagents.set(t,s),this.updateSubagentWindowParent(t),e=!0;break}}}e&&(this.saveSubagentParentMap(),this.updateConnectionLines())},updateSubagentParentNames(e){const t=this.sessions.get(e);if(!t)return;const s=this.getSessionName(t);if(this._parentNameCache?.get(e)!==s){this._parentNameCache||(this._parentNameCache=new Map),this._parentNameCache.set(e,s);for(const[i,o]of this.subagentParentMap)if(o===e){const l=this.subagents.get(i);if(l){l.parentSessionName=s,this.subagents.set(i,l);const a=this.subagentWindows.get(i);if(a){const r=a.element.querySelector(".subagent-window-parent .parent-name");r&&(r.textContent=s)}}}}},updateSubagentWindowParent(e){const t=this.subagentWindows.get(e);if(!t)return;const s=this.subagentParentMap.get(e);if(!s)return;const n=this.sessions.get(s),i=n?this.getSessionName(n):"Unknown",o=t.element,l=o.querySelector(".subagent-window-parent");if(l){l.dataset.parentSession=s;const r=l.querySelector(".parent-name");r&&(r.textContent=i,r.onclick=()=>this.selectSession(s));return}const a=o.querySelector(".subagent-window-header");if(a){const r=document.createElement("div");r.className="subagent-window-parent",r.dataset.parentSession=s,r.innerHTML=`
172
178
  <span class="parent-label">from</span>
173
- <span class="parent-name" onclick="app.selectSession(${escapeHtml(JSON.stringify(s))})">${escapeHtml(n)}</span>
174
- `,a.insertAdjacentElement("afterend",r)}},updateSubagentWindowVisibility(){const t=this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0;for(const[s,i]of this.subagentWindows){const n=this.subagentParentMap.get(s),o=this.subagents.get(s),l=n||o?.parentSessionId;let a;t?a=!!!l||l===this.activeSessionId:a=!0,a?(i.minimized||(i.element.style.display="flex",i._lazyTerminal&&this._restoreTeammateTerminalFromLazy(s)),i.hidden=!1):(this._disposeTeammateTerminalForMinimize(s),i.element.style.display="none",i.hidden=!0)}this.updateConnectionLines(),this.relayoutMobileSubagentWindows()},closeSessionSubagentWindows(e,t=!1){const s=[];for(const[i,n]of this.subagentWindows){const o=this.subagents.get(i),l=this.subagentParentMap.get(i);(o?.parentSessionId===e||l===e)&&s.push(i)}for(const i of s)this.forceCloseSubagentWindow(i),t&&(this.subagents.delete(i),this.subagentActivity.delete(i),this.subagentToolResults.delete(i),this.subagentParentMap.delete(i));this.minimizedSubagents.delete(e),this.renderSessionTabs()},forceCloseSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(t.resizeObserver&&t.resizeObserver.disconnect(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.subagentWindows.delete(e));const s=this.teammateTerminals.get(e);if(s){if(s.resizeObserver&&s.resizeObserver.disconnect(),s.terminal)try{s.terminal.dispose()}catch{}this.teammateTerminals.delete(e)}},minimizeSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(this._disposeTeammateTerminalForMinimize(e),t.element.style.display="none",t.minimized=!0,this.updateConnectionLines())},scheduleSubagentWindowRender(e){this.subagentWindows.get(e)?.minimized||(this._subagentWindowRenderTimeouts||(this._subagentWindowRenderTimeouts=new Map),this._subagentWindowRenderTimeouts.has(e)&&clearTimeout(this._subagentWindowRenderTimeouts.get(e)),this._subagentWindowRenderTimeouts.set(e,setTimeout(()=>{this._subagentWindowRenderTimeouts.delete(e),scheduleBackground(()=>this.renderSubagentWindowContent(e))},100)))},renderSubagentWindowContent(e){if(this.teammateTerminals.has(e)||this.subagentWindows.get(e)?._lazyTerminal)return;const s=document.getElementById(`subagent-window-body-${e}`);if(!s)return;const i=this.subagentActivity.get(e)||[];if(i.length===0){s.innerHTML='<div class="subagent-empty">No activity yet</div>';return}const n=s.dataset.renderedCount?parseInt(s.dataset.renderedCount,10):0,o=100,l=i.slice(-o);if(n===0||n>l.length||s.children.length===0||s.children.length===1&&s.querySelector(".subagent-empty")){const a=l.map(r=>this._renderActivityItem(r)).join("");s.innerHTML=a,s.dataset.renderedCount=String(l.length)}else{const a=l.slice(n);if(a.length>0){const r=a.map(c=>this._renderActivityItem(c)).join("");for(s.insertAdjacentHTML("beforeend",r),s.dataset.renderedCount=String(l.length);s.children.length>o;)s.removeChild(s.firstChild)}}s.scrollTop=s.scrollHeight},_renderActivityItem(e){const t=new Date(e.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(e.type==="tool")return`<div class="activity-line">
179
+ <span class="parent-name" onclick="app.selectSession(${escapeHtml(JSON.stringify(s))})">${escapeHtml(i)}</span>
180
+ `,a.insertAdjacentElement("afterend",r)}},updateSubagentWindowVisibility(){const t=this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0;for(const[s,n]of this.subagentWindows){const i=this.subagentParentMap.get(s),o=this.subagents.get(s),l=i||o?.parentSessionId;let a;t?a=!!!l||l===this.activeSessionId:a=!0,a?(n.minimized||(n.element.style.display="flex",n._lazyTerminal&&this._restoreTeammateTerminalFromLazy(s)),n.hidden=!1):(this._disposeTeammateTerminalForMinimize(s),n.element.style.display="none",n.hidden=!0)}this.updateConnectionLines(),this.relayoutMobileSubagentWindows()},closeSessionSubagentWindows(e,t=!1){const s=[];for(const[n,i]of this.subagentWindows){const o=this.subagents.get(n),l=this.subagentParentMap.get(n);(o?.parentSessionId===e||l===e)&&s.push(n)}for(const n of s)this.forceCloseSubagentWindow(n),t&&(this.subagents.delete(n),this.subagentActivity.delete(n),this.subagentToolResults.delete(n),this.subagentParentMap.delete(n));this.minimizedSubagents.delete(e),this.renderSessionTabs()},forceCloseSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(t.resizeObserver&&t.resizeObserver.disconnect(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.subagentWindows.delete(e));const s=this.teammateTerminals.get(e);if(s){if(s.resizeObserver&&s.resizeObserver.disconnect(),s.terminal)try{s.terminal.dispose()}catch{}this.teammateTerminals.delete(e)}},minimizeSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(this._disposeTeammateTerminalForMinimize(e),t.element.style.display="none",t.minimized=!0,this.updateConnectionLines())},scheduleSubagentWindowRender(e){this.subagentWindows.get(e)?.minimized||(this._subagentWindowRenderTimeouts||(this._subagentWindowRenderTimeouts=new Map),this._subagentWindowRenderTimeouts.has(e)&&clearTimeout(this._subagentWindowRenderTimeouts.get(e)),this._subagentWindowRenderTimeouts.set(e,setTimeout(()=>{this._subagentWindowRenderTimeouts.delete(e),scheduleBackground(()=>this.renderSubagentWindowContent(e))},100)))},renderSubagentWindowContent(e){if(this.teammateTerminals.has(e)||this.subagentWindows.get(e)?._lazyTerminal)return;const s=document.getElementById(`subagent-window-body-${e}`);if(!s)return;const n=this.subagentActivity.get(e)||[];if(n.length===0){s.innerHTML='<div class="subagent-empty">No activity yet</div>';return}const i=s.dataset.renderedCount?parseInt(s.dataset.renderedCount,10):0,o=100,l=n.slice(-o);if(i===0||i>l.length||s.children.length===0||s.children.length===1&&s.querySelector(".subagent-empty")){const a=l.map(r=>this._renderActivityItem(r)).join("");s.innerHTML=a,s.dataset.renderedCount=String(l.length)}else{const a=l.slice(i);if(a.length>0){const r=a.map(c=>this._renderActivityItem(c)).join("");for(s.insertAdjacentHTML("beforeend",r),s.dataset.renderedCount=String(l.length);s.children.length>o;)s.removeChild(s.firstChild)}}s.scrollTop=s.scrollHeight},_renderActivityItem(e){const t=new Date(e.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(e.type==="tool")return`<div class="activity-line">
175
181
  <span class="time">${t}</span>
176
182
  <span class="tool-icon">${this.getToolIcon(e.tool)}</span>
177
183
  <span class="tool-name">${escapeHtml(e.tool)}</span>
178
184
  <span class="tool-detail">${escapeHtml(this.getToolDetail(e.tool,e.input))}</span>
179
- </div>`;if(e.type==="tool_result"){const s=e.isError?"\u274C":"\u{1F4C4}",i=e.isError?" error":"",n=e.contentLength>500?` (${this.formatBytes(e.contentLength)})`:"",o=e.preview.length>60?e.preview.substring(0,60)+"...":e.preview;return`<div class="activity-line result-line${i}">
185
+ </div>`;if(e.type==="tool_result"){const s=e.isError?"\u274C":"\u{1F4C4}",n=e.isError?" error":"",i=e.contentLength>500?` (${this.formatBytes(e.contentLength)})`:"",o=e.preview.length>60?e.preview.substring(0,60)+"...":e.preview;return`<div class="activity-line result-line${n}">
180
186
  <span class="time">${t}</span>
181
187
  <span class="tool-icon">${s}</span>
182
188
  <span class="tool-name">${escapeHtml(e.tool||"\u2192")}</span>
183
- <span class="tool-detail">${escapeHtml(o)}${n}</span>
184
- </div>`}else if(e.type==="progress"){const s=e.hookEvent||e.hookName,i=s?"\u{1FA9D}":e.progressType==="query_update"?"\u27F3":"\u2713",n=s?e.hookName||e.hookEvent:e.query||e.progressType;return`<div class="activity-line progress-line${s?" hook-line":""}">
189
+ <span class="tool-detail">${escapeHtml(o)}${i}</span>
190
+ </div>`}else if(e.type==="progress"){const s=e.hookEvent||e.hookName,n=s?"\u{1FA9D}":e.progressType==="query_update"?"\u27F3":"\u2713",i=s?e.hookName||e.hookEvent:e.query||e.progressType;return`<div class="activity-line progress-line${s?" hook-line":""}">
185
191
  <span class="time">${t}</span>
186
- <span class="tool-icon">${i}</span>
187
- <span class="tool-detail">${escapeHtml(n)}</span>
192
+ <span class="tool-icon">${n}</span>
193
+ <span class="tool-detail">${escapeHtml(i)}</span>
188
194
  </div>`}else if(e.type==="message"){const s=e.text.length>150?e.text.substring(0,150)+"...":e.text;return`<div class="message-line">
189
195
  <span class="time">${t}</span> \u{1F4AC} ${escapeHtml(s)}
190
- </div>`}return""},updateSubagentWindows(){for(const e of this.subagentWindows.keys())this.renderSubagentWindowContent(e),this.updateSubagentWindowHeader(e)},updateSubagentWindowHeader(e){const t=this.subagents.get(e);if(!t)return;const s=document.getElementById(`subagent-window-${e}`);if(!s)return;const i=s.querySelector(".subagent-window-title .id");if(i){const c=this.getTeammateInfo(t),h=c?c.name:t.description||e.substring(0,7),d=h.length>50?h.substring(0,50)+"...":h;i.textContent=d}let n=s.querySelector(".teammate-badge");const o=this.getTeammateInfo(t);if(o&&!n){const c=s.querySelector(".subagent-window-title");if(c){const h=document.createElement("span");h.className=`teammate-badge teammate-color-${o.color}`,h.title=`Team: ${o.teamName}`,h.textContent=`@${o.name}`;const d=c.querySelector(".status");d&&d.insertAdjacentElement("beforebegin",h)}}const l=s.querySelector(".subagent-window-title");l&&(l.title=t.description||e);let a=s.querySelector(".subagent-window-title .subagent-model-badge");if(t.modelShort){if(!a){a=document.createElement("span"),a.className=`subagent-model-badge ${t.modelShort}`;const c=s.querySelector(".subagent-window-title .status");c&&c.insertAdjacentElement("beforebegin",a)}a.className=`subagent-model-badge ${t.modelShort}`,a.textContent=t.modelShort}const r=s.querySelector(".subagent-window-title .status");r&&(r.className=`status ${t.status}`,r.textContent=t.status)},openAllActiveSubagentWindows(){for(const[e,t]of this.subagents)t.status==="active"&&!this.subagentWindows.has(e)&&this.openSubagentWindow(e)},initTeammateTerminal(e,t,s){const i=s.querySelector(".subagent-window-body");if(!i)return;i.innerHTML="",i.classList.add("teammate-terminal-body"),s.classList.add("has-terminal");const n=t.sessionId,o=[];this.teammateTerminals.set(e,{terminal:null,fitAddon:null,paneTarget:t.paneTarget,sessionId:n,resizeObserver:null,pendingData:o}),requestAnimationFrame(()=>{if(!document.contains(i)){this.teammateTerminals.delete(e);return}const l=this.loadAppSettingsFromStorage?.()||{},a=new Terminal({theme:{...window.codemanCurrentXtermTheme()},minimumContrastRatio:window.codemanCurrentSkinIsLight()?4.5:1,fontFamily:window.CodemanTerminalFont.resolve(l.terminalFontFamily),...window.CodemanTerminalFont.resolveWeights(l),fontSize:12,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:DEFAULT_SCROLLBACK,allowTransparency:!0,allowProposedApi:!0}),r=new FitAddon.FitAddon;if(a.loadAddon(r),typeof Unicode11Addon<"u")try{const d=new Unicode11Addon.Unicode11Addon;a.loadAddon(d),a.unicode.activeVersion="11"}catch{}try{a.open(i)}catch(d){console.warn("[TeammateTerminal] Failed to open terminal:",d),this.teammateTerminals.delete(e);return}a.attachCustomKeyEventHandler(d=>d.type==="keydown"&&d.key.toLowerCase()==="z"&&d.ctrlKey&&!d.altKey&&!d.metaKey&&!d.shiftKey?(d.preventDefault(),!1):!0),setTimeout(()=>{try{r.fit()}catch{}fetch(`/api/sessions/${n}/teammate-pane-buffer/${encodeURIComponent(t.paneTarget)}`).then(d=>d.json()).then(d=>{if(d.success&&d.data?.buffer)try{a.write(d.data.buffer)}catch{}}).catch(d=>console.error("[TeammateTerminal] Failed to fetch buffer:",d));for(const d of o)try{a.write(d)}catch{}o.length=0},100),a.onData(d=>{fetch(`/api/sessions/${n}/teammate-pane-input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paneTarget:t.paneTarget,input:d})}).catch(u=>console.error("[TeammateTerminal] Failed to send input:",u))});const c=new ResizeObserver(()=>{requestAnimationFrame(()=>{try{r.fit()}catch{}})});c.observe(i);const h=this.teammateTerminals.get(e);h&&(h.terminal=a,h.fitAddon=r,h.resizeObserver=c)})},openTeammateTerminalWindow(e){if(!this.sessions.has(e.sessionId))return;const t=`pane-${e.paneTarget}`;if(this.subagentWindows.has(t)){const b=this.subagentWindows.get(t);b.hidden&&(b.element.style.display="flex",b.hidden=!1),b.element.style.zIndex=++this.subagentWindowZIndex,b.minimized&&this.restoreSubagentWindow(t);return}const s=this.subagentWindows.size,i=550,n=400,o=20,l=window.innerWidth,a=window.innerHeight,r=50,c=120,h=Math.floor((l-r-50)/(i+o))||1,d=Math.floor((a-c-50)/(n+o))||1,u=s%h,p=Math.floor(s/h)%d;let f=r+u*(i+o),w=c+p*(n+o);f=Math.max(10,Math.min(f,l-i-10)),w=Math.max(10,Math.min(w,a-n-10));const y=e.color||"blue",v=document.createElement("div");v.className="subagent-window has-terminal",v.id=`subagent-window-${t}`,v.style.zIndex=++this.subagentWindowZIndex,v.style.left=`${f}px`,v.style.top=`${w}px`,v.style.width=`${i}px`,v.style.height=`${n}px`,v.innerHTML=`
196
+ </div>`}return""},updateSubagentWindows(){for(const e of this.subagentWindows.keys())this.renderSubagentWindowContent(e),this.updateSubagentWindowHeader(e)},updateSubagentWindowHeader(e){const t=this.subagents.get(e);if(!t)return;const s=document.getElementById(`subagent-window-${e}`);if(!s)return;const n=s.querySelector(".subagent-window-title .id");if(n){const c=this.getTeammateInfo(t),h=c?c.name:t.description||e.substring(0,7),d=h.length>50?h.substring(0,50)+"...":h;n.textContent=d}let i=s.querySelector(".teammate-badge");const o=this.getTeammateInfo(t);if(o&&!i){const c=s.querySelector(".subagent-window-title");if(c){const h=document.createElement("span");h.className=`teammate-badge teammate-color-${o.color}`,h.title=`Team: ${o.teamName}`,h.textContent=`@${o.name}`;const d=c.querySelector(".status");d&&d.insertAdjacentElement("beforebegin",h)}}const l=s.querySelector(".subagent-window-title");l&&(l.title=t.description||e);let a=s.querySelector(".subagent-window-title .subagent-model-badge");if(t.modelShort){if(!a){a=document.createElement("span"),a.className=`subagent-model-badge ${t.modelShort}`;const c=s.querySelector(".subagent-window-title .status");c&&c.insertAdjacentElement("beforebegin",a)}a.className=`subagent-model-badge ${t.modelShort}`,a.textContent=t.modelShort}const r=s.querySelector(".subagent-window-title .status");r&&(r.className=`status ${t.status}`,r.textContent=t.status)},openAllActiveSubagentWindows(){for(const[e,t]of this.subagents)t.status==="active"&&!this.subagentWindows.has(e)&&this.openSubagentWindow(e)},initTeammateTerminal(e,t,s){const n=s.querySelector(".subagent-window-body");if(!n)return;n.innerHTML="",n.classList.add("teammate-terminal-body"),s.classList.add("has-terminal");const i=t.sessionId,o=[];this.teammateTerminals.set(e,{terminal:null,fitAddon:null,paneTarget:t.paneTarget,sessionId:i,resizeObserver:null,pendingData:o}),requestAnimationFrame(()=>{if(!document.contains(n)){this.teammateTerminals.delete(e);return}const l=this.loadAppSettingsFromStorage?.()||{},a=new Terminal({theme:{...window.codemanCurrentXtermTheme()},minimumContrastRatio:window.codemanCurrentSkinIsLight()?4.5:1,fontFamily:window.CodemanTerminalFont.resolve(l.terminalFontFamily),...window.CodemanTerminalFont.resolveWeights(l),fontSize:12,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:DEFAULT_SCROLLBACK,allowTransparency:!0,allowProposedApi:!0}),r=new FitAddon.FitAddon;if(a.loadAddon(r),typeof Unicode11Addon<"u")try{const d=new Unicode11Addon.Unicode11Addon;a.loadAddon(d),a.unicode.activeVersion="11"}catch{}try{a.open(n)}catch(d){console.warn("[TeammateTerminal] Failed to open terminal:",d),this.teammateTerminals.delete(e);return}a.attachCustomKeyEventHandler(d=>d.type==="keydown"&&d.key.toLowerCase()==="z"&&d.ctrlKey&&!d.altKey&&!d.metaKey&&!d.shiftKey?(d.preventDefault(),!1):!0),setTimeout(()=>{try{r.fit()}catch{}fetch(`/api/sessions/${i}/teammate-pane-buffer/${encodeURIComponent(t.paneTarget)}`).then(d=>d.json()).then(d=>{if(d.success&&d.data?.buffer)try{a.write(d.data.buffer)}catch{}}).catch(d=>console.error("[TeammateTerminal] Failed to fetch buffer:",d));for(const d of o)try{a.write(d)}catch{}o.length=0},100),a.onData(d=>{fetch(`/api/sessions/${i}/teammate-pane-input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paneTarget:t.paneTarget,input:d})}).catch(u=>console.error("[TeammateTerminal] Failed to send input:",u))});const c=new ResizeObserver(()=>{requestAnimationFrame(()=>{try{r.fit()}catch{}})});c.observe(n);const h=this.teammateTerminals.get(e);h&&(h.terminal=a,h.fitAddon=r,h.resizeObserver=c)})},openTeammateTerminalWindow(e){if(!this.sessions.has(e.sessionId))return;const t=`pane-${e.paneTarget}`;if(this.subagentWindows.has(t)){const b=this.subagentWindows.get(t);b.hidden&&(b.element.style.display="flex",b.hidden=!1),b.element.style.zIndex=++this.subagentWindowZIndex,b.minimized&&this.restoreSubagentWindow(t);return}const s=this.subagentWindows.size,n=550,i=400,o=20,l=window.innerWidth,a=window.innerHeight,r=50,c=120,h=Math.floor((l-r-50)/(n+o))||1,d=Math.floor((a-c-50)/(i+o))||1,u=s%h,p=Math.floor(s/h)%d;let f=r+u*(n+o),w=c+p*(i+o);f=Math.max(10,Math.min(f,l-n-10)),w=Math.max(10,Math.min(w,a-i-10));const y=e.color||"blue",v=document.createElement("div");v.className="subagent-window has-terminal",v.id=`subagent-window-${t}`,v.style.zIndex=++this.subagentWindowZIndex,v.style.left=`${f}px`,v.style.top=`${w}px`,v.style.width=`${n}px`,v.style.height=`${i}px`,v.innerHTML=`
191
197
  <div class="subagent-window-header">
192
198
  <div class="subagent-window-title" title="Teammate terminal: ${escapeHtml(e.teammateName)} (pane ${e.paneTarget})">
193
199
  <span class="icon" style="color: var(--team-color-${y}, #339af0)">\u2B24</span>
@@ -200,11 +206,11 @@
200
206
  </div>
201
207
  <div class="subagent-window-body teammate-terminal-body" id="subagent-window-body-${t}">
202
208
  </div>
203
- `,document.body.appendChild(v);const g=this.makeWindowDraggable(v,v.querySelector(".subagent-window-header"));typeof this.makeWindowResizable=="function"&&this.makeWindowResizable(v);const S=(this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0)&&e.sessionId!==this.activeSessionId;this.subagentWindows.set(t,{element:v,minimized:!1,hidden:S,dragListeners:g,description:`Teammate: ${e.teammateName}`}),this.subagentParentMap.set(t,e.sessionId),S&&(v.style.display="none"),v.addEventListener("mousedown",()=>{v.style.zIndex=++this.subagentWindowZIndex});const $=new ResizeObserver(()=>{this.updateConnectionLines()});if($.observe(v),this.subagentWindows.get(t).resizeObserver=$,S){const b=this.subagentWindows.get(t);b&&(b._lazyTerminal=!0,b._lazyPaneTarget=e.paneTarget,b._lazySessionId=e.sessionId)}else this.initTeammateTerminal(t,e,v);requestAnimationFrame(()=>{v.style.transition="transform 0.3s ease, opacity 0.3s ease",v.style.transform="scale(1)",v.style.opacity="1"})},rebuildTeammateMap(){this.teammateMap.clear();for(const[e,t]of this.teams)for(const s of t.members)s.agentType!=="team-lead"&&this.teammateMap.set(s.name,{name:s.name,color:s.color||"blue",teamName:e,agentId:s.agentId})},getTeammateInfo(e){if(!e?.description)return null;const t=e.description.match(/<teammate-message\s+teammate_id="?([^">\s]+)/);if(!t)return null;const i=t[1].split("@")[0];return this.teammateMap.get(i)||{name:i,color:"blue",teamName:"unknown"}},getTeammateBadgeHtml(e){const t=this.getTeammateInfo(e);return t?`<span class="teammate-badge teammate-color-${t.color}" title="Team: ${escapeHtml(t.teamName)}">@${escapeHtml(t.name)}</span>`:""},renderTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");if(!e)return;let t=null,s=null;if(this.activeSessionId){for(const[p,f]of this.teams)if(f.leadSessionId===this.activeSessionId){t=f,s=p;break}}if(!t){e.style.display="none";return}const i=e.style.display==="none";if(e.style.display="flex",i&&!this.teamTasksDragListeners){e.style.left=`${Math.max(10,window.innerWidth-360-20)}px`,e.style.top=`${Math.max(10,window.innerHeight-300-70)}px`;const w=e.querySelector(".team-tasks-header");w&&(this.teamTasksDragListeners=this.makeWindowDraggable(e,w))}const n=this.teamTasks.get(s)||[],o=n.filter(p=>p.status==="completed").length,l=n.length,a=l>0?Math.round(o/l*100):0,r=e.querySelector(".team-tasks-header-text");if(r){const p=t.members.filter(f=>f.agentType!=="team-lead").length;r.textContent=`Team Tasks (${p} teammates)`}const c=e.querySelector(".team-tasks-progress-fill");c&&(c.style.width=`${a}%`);const h=e.querySelector(".team-tasks-progress-text");h&&(h.textContent=`${o}/${l}`);const d=e.querySelector(".team-tasks-list");if(!d)return;if(n.length===0){d.innerHTML='<div class="team-task-empty">No tasks yet</div>';return}const u=n.map(p=>{const f=p.status==="completed"?"\u2713":p.status==="in_progress"?"\u25C9":"\u25CB",w=p.status.replace("_","-"),y=p.owner?`<span class="team-task-owner teammate-color-${this.getTeammateColor(p.owner)}">${escapeHtml(p.owner)}</span>`:"";return`<div class="team-task-item ${w}">
209
+ `,document.body.appendChild(v);const g=this.makeWindowDraggable(v,v.querySelector(".subagent-window-header"));typeof this.makeWindowResizable=="function"&&this.makeWindowResizable(v);const S=(this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0)&&e.sessionId!==this.activeSessionId;this.subagentWindows.set(t,{element:v,minimized:!1,hidden:S,dragListeners:g,description:`Teammate: ${e.teammateName}`}),this.subagentParentMap.set(t,e.sessionId),S&&(v.style.display="none"),v.addEventListener("mousedown",()=>{v.style.zIndex=++this.subagentWindowZIndex});const $=new ResizeObserver(()=>{this.updateConnectionLines()});if($.observe(v),this.subagentWindows.get(t).resizeObserver=$,S){const b=this.subagentWindows.get(t);b&&(b._lazyTerminal=!0,b._lazyPaneTarget=e.paneTarget,b._lazySessionId=e.sessionId)}else this.initTeammateTerminal(t,e,v);requestAnimationFrame(()=>{v.style.transition="transform 0.3s ease, opacity 0.3s ease",v.style.transform="scale(1)",v.style.opacity="1"})},rebuildTeammateMap(){this.teammateMap.clear();for(const[e,t]of this.teams)for(const s of t.members)s.agentType!=="team-lead"&&this.teammateMap.set(s.name,{name:s.name,color:s.color||"blue",teamName:e,agentId:s.agentId})},getTeammateInfo(e){if(!e?.description)return null;const t=e.description.match(/<teammate-message\s+teammate_id="?([^">\s]+)/);if(!t)return null;const n=t[1].split("@")[0];return this.teammateMap.get(n)||{name:n,color:"blue",teamName:"unknown"}},getTeammateBadgeHtml(e){const t=this.getTeammateInfo(e);return t?`<span class="teammate-badge teammate-color-${t.color}" title="Team: ${escapeHtml(t.teamName)}">@${escapeHtml(t.name)}</span>`:""},renderTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");if(!e)return;let t=null,s=null;if(this.activeSessionId){for(const[p,f]of this.teams)if(f.leadSessionId===this.activeSessionId){t=f,s=p;break}}if(!t){e.style.display="none";return}const n=e.style.display==="none";if(e.style.display="flex",n&&!this.teamTasksDragListeners){e.style.left=`${Math.max(10,window.innerWidth-360-20)}px`,e.style.top=`${Math.max(10,window.innerHeight-300-70)}px`;const w=e.querySelector(".team-tasks-header");w&&(this.teamTasksDragListeners=this.makeWindowDraggable(e,w))}const i=this.teamTasks.get(s)||[],o=i.filter(p=>p.status==="completed").length,l=i.length,a=l>0?Math.round(o/l*100):0,r=e.querySelector(".team-tasks-header-text");if(r){const p=t.members.filter(f=>f.agentType!=="team-lead").length;r.textContent=`Team Tasks (${p} teammates)`}const c=e.querySelector(".team-tasks-progress-fill");c&&(c.style.width=`${a}%`);const h=e.querySelector(".team-tasks-progress-text");h&&(h.textContent=`${o}/${l}`);const d=e.querySelector(".team-tasks-list");if(!d)return;if(i.length===0){d.innerHTML='<div class="team-task-empty">No tasks yet</div>';return}const u=i.map(p=>{const f=p.status==="completed"?"\u2713":p.status==="in_progress"?"\u25C9":"\u25CB",w=p.status.replace("_","-"),y=p.owner?`<span class="team-task-owner teammate-color-${this.getTeammateColor(p.owner)}">${escapeHtml(p.owner)}</span>`:"";return`<div class="team-task-item ${w}">
204
210
  <span class="team-task-status">${f}</span>
205
211
  <span class="team-task-subject">${escapeHtml(p.subject)}</span>
206
212
  ${y}
207
- </div>`}).join("");d.innerHTML=u},hideTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");e&&(e.style.display="none"),this.teamTasksDragListeners&&(document.removeEventListener("mousemove",this.teamTasksDragListeners.move),document.removeEventListener("mouseup",this.teamTasksDragListeners.up),this.teamTasksDragListeners.touchMove&&(document.removeEventListener("touchmove",this.teamTasksDragListeners.touchMove),document.removeEventListener("touchend",this.teamTasksDragListeners.up),document.removeEventListener("touchcancel",this.teamTasksDragListeners.up)),this.teamTasksDragListeners.handle&&(this.teamTasksDragListeners.handle.removeEventListener("mousedown",this.teamTasksDragListeners.handleMouseDown),this.teamTasksDragListeners.handle.removeEventListener("touchstart",this.teamTasksDragListeners.handleTouchStart)),this.teamTasksDragListeners=null)},getTeammateColor(e){return this.teammateMap.get(e)?.color||"blue"},normalizeFilePath(e,t){if(!e)return"";let s=e.trim();const i="/home/"+(window.USER||"user");s.startsWith("~/")?s=i+s.slice(1):s==="~"&&(s=i),!s.startsWith("/")&&t&&(s=t+"/"+s);const n=s.split("/"),o=[];for(const l of n)l===""||l==="."||(l===".."?o.length>1&&o.pop():o.push(l));return"/"+o.join("/")},getFilename(e){const t=e.split("/");return t[t.length-1]||""},isShallowRootPath(e){return e.startsWith("/")?e.split("/").filter(s=>s!=="").length===1:!1},isPathInWorkingDir(e,t){if(!t)return!1;const s=this.normalizeFilePath(e,t);return s.startsWith(t+"/")||s===t},pathsAreEquivalent(e,t,s){const i=this.normalizeFilePath(e,s),n=this.normalizeFilePath(t,s);if(i===n)return!0;const o=this.getFilename(i),l=this.getFilename(n);if(o!==l)return!1;const a=this.isShallowRootPath(e),r=this.isShallowRootPath(t),c=this.isPathInWorkingDir(i,s),h=this.isPathInWorkingDir(n,s);return!!(a&&h||r&&c)},pickBetterPath(e,t,s){if(s){const o=this.isPathInWorkingDir(e,s),l=this.isPathInWorkingDir(t,s);if(o&&!l)return e;if(l&&!o)return t}const i=e.startsWith("/"),n=t.startsWith("/");return i&&!n?e:n&&!i?t:e.length!==t.length?e.length>t.length?e:t:!e.includes("~")&&t.includes("~")?e:!t.includes("~")&&e.includes("~")?t:e},deduplicateProjectInsightPaths(e,t){const s=[];for(const o of e)for(const l of o.filePaths)s.push({rawPath:l,toolId:o.id});if(s.length<=1){const o=new Map;for(const l of s)o.set(this.normalizeFilePath(l.rawPath,t),l);return o}s.sort((o,l)=>{const a=this.isPathInWorkingDir(o.rawPath,t),r=this.isPathInWorkingDir(l.rawPath,t);return a&&!r?-1:r&&!a?1:l.rawPath.length-o.rawPath.length});const i=new Map,n=new Set;for(const{rawPath:o,toolId:l}of s){const a=this.normalizeFilePath(o,t);let r=!1;for(const[,c]of i)if(this.pathsAreEquivalent(o,c.rawPath,t)){r=!0;break}!r&&!n.has(a)&&(i.set(a,{rawPath:o,toolId:l}),n.add(a))}return i},handleBashToolStart(e,t){let s=this.projectInsights.get(e)||[];s=s.filter(i=>i.id!==t.id),s.push(t),this.projectInsights.set(e,s),this.renderProjectInsightsPanel()},handleBashToolEnd(e,t){const i=(this.projectInsights.get(e)||[]).find(n=>n.id===t.id);i&&(i.status="completed"),this.renderProjectInsightsPanel(),setTimeout(()=>{const n=this.projectInsights.get(e)||[];this.projectInsights.set(e,n.filter(o=>o.id!==t.id)),this.renderProjectInsightsPanel()},2e3)},handleBashToolsUpdate(e,t){this.projectInsights.set(e,t),this.renderProjectInsightsPanel()},renderProjectInsightsPanel(){const e=this.$("projectInsightsPanel"),t=this.$("projectInsightsList");if(!e||!t)return;if(!(this.loadAppSettingsFromStorage().showProjectInsights??!1)){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}const o=(this.projectInsights.get(this.activeSessionId)||[]).filter(d=>d.status==="running");if(o.length===0){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}e.classList.add("visible"),this.projectInsightsPanelVisible=!0;const a=this.sessions.get(this.activeSessionId)?.workingDir||this.currentSessionWorkingDir,r=this.deduplicateProjectInsightPaths(o,a),c=new Set(Array.from(r.values()).map(d=>d.rawPath)),h=[];for(const d of o){const u=d.filePaths.filter(f=>c.has(f));if(u.length===0)continue;const p=d.command.length>50?d.command.substring(0,50)+"...":d.command;h.push(`
213
+ </div>`}).join("");d.innerHTML=u},hideTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");e&&(e.style.display="none"),this.teamTasksDragListeners&&(document.removeEventListener("mousemove",this.teamTasksDragListeners.move),document.removeEventListener("mouseup",this.teamTasksDragListeners.up),this.teamTasksDragListeners.touchMove&&(document.removeEventListener("touchmove",this.teamTasksDragListeners.touchMove),document.removeEventListener("touchend",this.teamTasksDragListeners.up),document.removeEventListener("touchcancel",this.teamTasksDragListeners.up)),this.teamTasksDragListeners.handle&&(this.teamTasksDragListeners.handle.removeEventListener("mousedown",this.teamTasksDragListeners.handleMouseDown),this.teamTasksDragListeners.handle.removeEventListener("touchstart",this.teamTasksDragListeners.handleTouchStart)),this.teamTasksDragListeners=null)},getTeammateColor(e){return this.teammateMap.get(e)?.color||"blue"},normalizeFilePath(e,t){if(!e)return"";let s=e.trim();const n="/home/"+(window.USER||"user");s.startsWith("~/")?s=n+s.slice(1):s==="~"&&(s=n),!s.startsWith("/")&&t&&(s=t+"/"+s);const i=s.split("/"),o=[];for(const l of i)l===""||l==="."||(l===".."?o.length>1&&o.pop():o.push(l));return"/"+o.join("/")},getFilename(e){const t=e.split("/");return t[t.length-1]||""},isShallowRootPath(e){return e.startsWith("/")?e.split("/").filter(s=>s!=="").length===1:!1},isPathInWorkingDir(e,t){if(!t)return!1;const s=this.normalizeFilePath(e,t);return s.startsWith(t+"/")||s===t},pathsAreEquivalent(e,t,s){const n=this.normalizeFilePath(e,s),i=this.normalizeFilePath(t,s);if(n===i)return!0;const o=this.getFilename(n),l=this.getFilename(i);if(o!==l)return!1;const a=this.isShallowRootPath(e),r=this.isShallowRootPath(t),c=this.isPathInWorkingDir(n,s),h=this.isPathInWorkingDir(i,s);return!!(a&&h||r&&c)},pickBetterPath(e,t,s){if(s){const o=this.isPathInWorkingDir(e,s),l=this.isPathInWorkingDir(t,s);if(o&&!l)return e;if(l&&!o)return t}const n=e.startsWith("/"),i=t.startsWith("/");return n&&!i?e:i&&!n?t:e.length!==t.length?e.length>t.length?e:t:!e.includes("~")&&t.includes("~")?e:!t.includes("~")&&e.includes("~")?t:e},deduplicateProjectInsightPaths(e,t){const s=[];for(const o of e)for(const l of o.filePaths)s.push({rawPath:l,toolId:o.id});if(s.length<=1){const o=new Map;for(const l of s)o.set(this.normalizeFilePath(l.rawPath,t),l);return o}s.sort((o,l)=>{const a=this.isPathInWorkingDir(o.rawPath,t),r=this.isPathInWorkingDir(l.rawPath,t);return a&&!r?-1:r&&!a?1:l.rawPath.length-o.rawPath.length});const n=new Map,i=new Set;for(const{rawPath:o,toolId:l}of s){const a=this.normalizeFilePath(o,t);let r=!1;for(const[,c]of n)if(this.pathsAreEquivalent(o,c.rawPath,t)){r=!0;break}!r&&!i.has(a)&&(n.set(a,{rawPath:o,toolId:l}),i.add(a))}return n},handleBashToolStart(e,t){let s=this.projectInsights.get(e)||[];s=s.filter(n=>n.id!==t.id),s.push(t),this.projectInsights.set(e,s),this.renderProjectInsightsPanel()},handleBashToolEnd(e,t){const n=(this.projectInsights.get(e)||[]).find(i=>i.id===t.id);n&&(n.status="completed"),this.renderProjectInsightsPanel(),setTimeout(()=>{const i=this.projectInsights.get(e)||[];this.projectInsights.set(e,i.filter(o=>o.id!==t.id)),this.renderProjectInsightsPanel()},2e3)},handleBashToolsUpdate(e,t){this.projectInsights.set(e,t),this.renderProjectInsightsPanel()},renderProjectInsightsPanel(){const e=this.$("projectInsightsPanel"),t=this.$("projectInsightsList");if(!e||!t)return;if(!(this.loadAppSettingsFromStorage().showProjectInsights??!1)){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}const o=(this.projectInsights.get(this.activeSessionId)||[]).filter(d=>d.status==="running");if(o.length===0){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}e.classList.add("visible"),this.projectInsightsPanelVisible=!0;const a=this.sessions.get(this.activeSessionId)?.workingDir||this.currentSessionWorkingDir,r=this.deduplicateProjectInsightPaths(o,a),c=new Set(Array.from(r.values()).map(d=>d.rawPath)),h=[];for(const d of o){const u=d.filePaths.filter(f=>c.has(f));if(u.length===0)continue;const p=d.command.length>50?d.command.substring(0,50)+"...":d.command;h.push(`
208
214
  <div class="project-insight-item" data-tool-id="${d.id}">
209
215
  <div class="project-insight-command">
210
216
  <span class="icon">\u{1F4BB}</span>
@@ -220,7 +226,7 @@
220
226
  `)}h.push(`
221
227
  </div>
222
228
  </div>
223
- `)}t.innerHTML=h.join("")},closeProjectInsightsPanel(){const e=this.$("projectInsightsPanel");e&&(e.classList.remove("visible"),this.projectInsightsPanelVisible=!1)},_loadFileBrowserShowHidden(){try{return localStorage.getItem(FILE_BROWSER_SHOW_HIDDEN_KEY)==="1"}catch{return!1}},_syncFileBrowserHiddenBtn(){const e=this.$("fileBrowserHiddenBtn");if(!e)return;const t=this.fileBrowserShowHidden===!0;e.classList.toggle("active",t),e.setAttribute("aria-pressed",String(t));const s=t?"Hide hidden files and folders":"Show hidden files and folders";e.setAttribute("title",s),e.setAttribute("aria-label",s)},_ensureFileBrowserState(){if(!this._fileBrowserState){const e=this.activeSessionId||null,t=this.fileBrowserShowHidden===!0;this._fileBrowserState={treeEpoch:0,searchEpoch:0,ownerSessionId:e,view:"normal",normalState:this.fileBrowserData?{sessionId:e,showHidden:t,treeEpoch:0,phase:"ready",data:this.fileBrowserData}:null,treeInFlight:null,inFlight:null,matches:[],deferredDirectoryTarget:null,filter:typeof this.fileBrowserFilter=="string"?this.fileBrowserFilter:""}}return this._fileBrowserState},_activateFileBrowserSession(e){if(!e)return;const t=this._ensureFileBrowserState();t.inFlight?.timer!==void 0&&t.inFlight?.timer!==null&&clearTimeout(t.inFlight.timer),t.searchEpoch++,t.treeEpoch++,t.ownerSessionId=e,t.treeInFlight=null,t.inFlight=null,t.normalState=null,t.matches=[],t.deferredDirectoryTarget=null,t.filter="",t.view="normal",this.fileBrowserData=null,this.fileBrowserFilter="",this.fileBrowserExpandedDirs?.clear?.(),this.fileBrowserAllExpanded=!1;const s=this.$?.("fileBrowserSearch");s&&(s.value=""),this._syncFileBrowserExpandBtn();const i=this.$?.("fileBrowserExpandBtn");i&&(i.innerHTML="\u229E");const n=this.$?.("fileBrowserPanel"),o=this.$?.("fileBrowserTree"),l=this.$?.("fileBrowserStatus"),a=n?.classList.contains("visible")===!0;o&&(o.innerHTML=a?`<div class="file-browser-loading">${escapeHtml("Loading files...")}</div>`:""),l&&(l.textContent=a?"Loading files...":""),a&&this.loadFileBrowser?.(e)?.catch?.(()=>{})},_resetFileBrowserForHide(){const e=this._ensureFileBrowserState();e.inFlight?.timer!==void 0&&e.inFlight?.timer!==null&&clearTimeout(e.inFlight.timer),e.searchEpoch++,e.treeEpoch++,e.treeInFlight=null,e.inFlight=null,e.normalState=null,e.matches=[],e.deferredDirectoryTarget=null,e.filter="",e.view="normal",this.fileBrowserData=null,this.fileBrowserFilter="",this.fileBrowserExpandedDirs?.clear?.(),this.fileBrowserAllExpanded=!1;const t=this.$?.("fileBrowserSearch");t&&(t.value=""),this._syncFileBrowserExpandBtn();const s=this.$?.("fileBrowserExpandBtn");s&&(s.innerHTML="\u229E");const i=this.$?.("fileBrowserTree");i&&(i.innerHTML="");const n=this.$?.("fileBrowserStatus");n&&(n.textContent="")},_setFileBrowserExpandDisabled(e){const t=this.$("fileBrowserExpandBtn");t&&(t.disabled=e)},_hasFileBrowserQuery(){const e=this._ensureFileBrowserState(),t=this.$?.("fileBrowserSearch"),s=typeof t?.value=="string"?t.value:"",i=typeof e.filter=="string"?e.filter:"";return s.trim()!==""||i.trim()!==""},_syncFileBrowserExpandBtn(){this._setFileBrowserExpandDisabled(this._hasFileBrowserQuery())},_renderFileBrowserNormalStatus(e,t){const s=this.$("fileBrowserStatus");if(!s||!e)return;const{totalFiles:i,totalDirectories:n,truncated:o}=e;s.textContent=`${i} files, ${n} dirs${o?" (truncated)":""}${t?" \xB7 hidden shown":""}`},_isFileBrowserNormalCompatible(e,t,s,i){return e?.sessionId===t&&e.showHidden===s&&e.treeEpoch===i},_isFileBrowserTreeContextCurrent(e,t=!1){const s=this._ensureFileBrowserState();return(!t||s.treeInFlight===e)&&s.ownerSessionId===e.sessionId&&s.treeEpoch===e.treeEpoch&&this.fileBrowserShowHidden===!0===e.showHidden},_canRenderFileBrowserNormal(e){const t=this._ensureFileBrowserState();return t.view==="normal"&&this.activeSessionId===e?.sessionId&&this._isFileBrowserNormalCompatible(e,t.ownerSessionId,this.fileBrowserShowHidden===!0,t.treeEpoch)&&this.$("fileBrowserPanel")?.classList.contains("visible")===!0},_renderFileBrowserNormalState(e){if(!e||!this._canRenderFileBrowserNormal(e))return;const t=this.$("fileBrowserTree"),s=this.$("fileBrowserStatus");if(t){if(e.phase==="loading"){this.fileBrowserData=null,t.innerHTML=`<div class="file-browser-loading">${escapeHtml("Loading files...")}</div>`,s&&(s.textContent="Loading files...");return}if(e.phase==="error"){this.fileBrowserData=null;const n=`Failed to load files${e.error&&e.error!=="Failed to load files"?`: ${e.error}`:""}`;t.innerHTML=`<div class="file-browser-empty">${escapeHtml(n)}</div>`,s&&(s.textContent=n);return}e.phase==="ready"&&(this.fileBrowserData=e.data,this._syncFileBrowserExpandBtn(),this.renderFileBrowserTree(e.sessionId),this._renderFileBrowserNormalStatus(e.data,e.showHidden))}},_validateFileBrowserTreeEnvelope(e){if(!e||typeof e!="object"||e.success!==!0)return null;const t=e.data;if(!t||typeof t!="object"||!Array.isArray(t.tree)||t.mode==="search"||typeof t.totalFiles!="number"||!Number.isFinite(t.totalFiles)||t.totalFiles<0||typeof t.totalDirectories!="number"||!Number.isFinite(t.totalDirectories)||t.totalDirectories<0||typeof t.truncated!="boolean")return null;const s=i=>i.every(n=>!(!n||typeof n!="object"||typeof n.name!="string"||typeof n.path!="string"||n.type!=="file"&&n.type!=="directory"||n.size!==void 0&&(typeof n.size!="number"||!Number.isFinite(n.size))||n.extension!==void 0&&typeof n.extension!="string"||n.children!==void 0&&(!Array.isArray(n.children)||!s(n.children))));return s(t.tree)?t:null},_normalizeFileBrowserTreeError(e){return typeof e?.message=="string"&&e.message?e.message:"Failed to load files"},_validateFileBrowserSearchEnvelope(e){if(!e||typeof e!="object"||e.success!==!0)return null;const t=e.data;if(!t||typeof t!="object"||t.mode!=="search"||!Array.isArray(t.matches)||typeof t.truncated!="boolean"||t.matchCount!==void 0&&(typeof t.matchCount!="number"||!Number.isFinite(t.matchCount)||t.matchCount<0))return null;for(const s of t.matches)if(!s||typeof s!="object"||typeof s.name!="string"||typeof s.path!="string"||s.type!=="file"&&s.type!=="directory"||s.size!==void 0&&(typeof s.size!="number"||!Number.isFinite(s.size))||s.extension!==void 0&&typeof s.extension!="string")return null;return t},_canRenderFileBrowserSearch(e){const t=this._ensureFileBrowserState(),s=this.$("fileBrowserPanel");return t.searchEpoch===e.epoch&&t.ownerSessionId===e.ownerSessionId&&this.activeSessionId===e.ownerSessionId&&this.fileBrowserShowHidden===!0===e.showHidden&&t.filter===e.rawInput&&s?.classList.contains("visible")===!0},_renderFileBrowserSearchError(){const e=this.$("fileBrowserTree"),t=this.$("fileBrowserStatus"),s="Search failed";e&&(e.innerHTML=`<div class="file-browser-empty">${escapeHtml(s)}</div>`),t&&(t.textContent=s)},_canContinueFileBrowserHiddenReload(e,t){const s=this._ensureFileBrowserState(),i=this.$?.("fileBrowserSearch"),n=typeof i?.value=="string"?i.value:s.filter;return s.view==="normal"&&s.searchEpoch===e.searchEpoch&&s.treeEpoch===e.treeEpoch&&s.ownerSessionId===e.ownerSessionId&&this.activeSessionId===e.ownerSessionId&&this.fileBrowserShowHidden===!0===e.showHidden&&s.filter===e.rawInput&&n===e.rawInput&&n.trim()===e.query&&this.$?.("fileBrowserPanel")?.classList.contains("visible")===!0&&t?.phase==="ready"&&this._isFileBrowserNormalCompatible(t,e.ownerSessionId,e.showHidden,e.treeEpoch)},async toggleFileBrowserHidden(){const e=this._ensureFileBrowserState(),t=typeof e.filter=="string"?e.filter:"",s=t.trim();this.fileBrowserShowHidden=!this.fileBrowserShowHidden;try{localStorage.setItem(FILE_BROWSER_SHOW_HIDDEN_KEY,this.fileBrowserShowHidden?"1":"0")}catch{}this._syncFileBrowserHiddenBtn(),e.inFlight?.timer!==void 0&&e.inFlight?.timer!==null&&clearTimeout(e.inFlight.timer),e.searchEpoch++,e.inFlight=null,e.matches=[],e.deferredDirectoryTarget=null,e.normalState=null,this.fileBrowserData=null,s.length<=256&&(e.view="normal"),this._syncFileBrowserExpandBtn();const i=e.ownerSessionId||this.activeSessionId;if(!i||this.activeSessionId!==i)return;const n=e.searchEpoch,o=this.fileBrowserShowHidden===!0,l=this.loadFileBrowser(i,{force:!0}),a=e.treeEpoch;if(!l?.then||(await l,!s||s.length>256))return;const r={ownerSessionId:i,showHidden:o,treeEpoch:a,searchEpoch:n,rawInput:t,query:s};this._canContinueFileBrowserHiddenReload(r,e.normalState)&&this.filterFileBrowser(t)},loadFileBrowser(e,{force:t=!1}={}){if(!e)return;const s=this._ensureFileBrowserState(),i=this.$("fileBrowserTree");if(this._syncFileBrowserHiddenBtn(),!i||(s.ownerSessionId||(s.ownerSessionId=e),s.ownerSessionId!==e))return;t&&s.treeEpoch++;const n=this.fileBrowserShowHidden===!0,o=s.treeEpoch,l=s.treeInFlight;if(!t&&this._isFileBrowserNormalCompatible(l,e,n,o))return l.promise;const a=s.normalState;if(!t&&this._isFileBrowserNormalCompatible(a,e,n,o)&&(a.phase==="ready"||a.phase==="error"))return a.phase==="ready"&&(this.fileBrowserData=a.data),this._renderFileBrowserNormalState(a),Promise.resolve(a);const r={sessionId:e,showHidden:n,treeEpoch:o,phase:"loading"};s.normalState=r,this.fileBrowserData=null,this._renderFileBrowserNormalState(r);const c={sessionId:e,showHidden:n,treeEpoch:o,promise:null},h=(async()=>{try{const d=await fetch(`/api/sessions/${encodeURIComponent(e)}/files?depth=5&showHidden=${n}`);if(!d.ok)throw new Error("Failed to load files");const u=await d.json(),p=this._validateFileBrowserTreeEnvelope(u);if(!p){const y=u&&typeof u=="object"&&typeof u.error=="string"?u.error:"Failed to load files";throw new Error(y)}if(!this._isFileBrowserTreeContextCurrent(c,!0))return;const f={sessionId:e,showHidden:n,treeEpoch:o,phase:"ready",data:p};s.normalState=f,this.fileBrowserData=p,this._completeDeferredFileBrowserDirectory?.(f)===!0||this._renderFileBrowserNormalState(f)}catch(d){if(!this._isFileBrowserTreeContextCurrent(c,!0))return;const u={sessionId:e,showHidden:n,treeEpoch:o,phase:"error",error:this._normalizeFileBrowserTreeError(d)};s.normalState=u,this.fileBrowserData=null,this._completeDeferredFileBrowserDirectory?.(u),console.error("Failed to load file browser:",d),this._renderFileBrowserNormalState(u)}})();return c.promise=h.finally(()=>{s.treeInFlight===c&&(s.treeInFlight=null)}),s.treeInFlight=c,c.promise},renderFileBrowserTree(e){const t=this.$("fileBrowserTree");if(!t||!this.fileBrowserData)return;const s=this._ensureFileBrowserState(),i=e||s.normalState?.sessionId||s.ownerSessionId||this.activeSessionId;if(!i)return;const{tree:n}=this.fileBrowserData;if(!n||n.length===0){t.innerHTML='<div class="file-browser-empty">No files found</div>';return}const o=[],l=(a,r)=>{const c=a.type==="directory",h=this.fileBrowserExpandedDirs.has(a.path),d=c?h?"\u{1F4C2}":"\u{1F4C1}":this.getFileIcon(a.extension),u=c?`<span class="file-tree-expand${h?" expanded":""}">\u25B6</span>`:'<span class="file-tree-expand"></span>',p=!c&&a.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(a.size)}</span>`:"",f=c?"file-tree-name directory":"file-tree-name",w=c?"":`<a class="file-tree-download" href="${escapeHtml(CodemanBase.url(`/api/sessions/${encodeURIComponent(i)}/file-raw?path=${encodeURIComponent(a.path)}&download=true`))}" title="Download" onclick="event.stopPropagation()">&#x2B07;</a>`;if(o.push(`
229
+ `)}t.innerHTML=h.join("")},closeProjectInsightsPanel(){const e=this.$("projectInsightsPanel");e&&(e.classList.remove("visible"),this.projectInsightsPanelVisible=!1)},_loadFileBrowserShowHidden(){try{return localStorage.getItem(FILE_BROWSER_SHOW_HIDDEN_KEY)==="1"}catch{return!1}},_syncFileBrowserHiddenBtn(){const e=this.$("fileBrowserHiddenBtn");if(!e)return;const t=this.fileBrowserShowHidden===!0;e.classList.toggle("active",t),e.setAttribute("aria-pressed",String(t));const s=t?"Hide hidden files and folders":"Show hidden files and folders";e.setAttribute("title",s),e.setAttribute("aria-label",s)},_ensureFileBrowserState(){if(!this._fileBrowserState){const e=this.activeSessionId||null,t=this.fileBrowserShowHidden===!0;this._fileBrowserState={treeEpoch:0,searchEpoch:0,ownerSessionId:e,view:"normal",normalState:this.fileBrowserData?{sessionId:e,showHidden:t,treeEpoch:0,phase:"ready",data:this.fileBrowserData}:null,treeInFlight:null,inFlight:null,matches:[],deferredDirectoryTarget:null,filter:typeof this.fileBrowserFilter=="string"?this.fileBrowserFilter:""}}return this._fileBrowserState},_activateFileBrowserSession(e){if(!e)return;const t=this._ensureFileBrowserState();t.inFlight?.timer!==void 0&&t.inFlight?.timer!==null&&clearTimeout(t.inFlight.timer),t.searchEpoch++,t.treeEpoch++,t.ownerSessionId=e,t.treeInFlight=null,t.inFlight=null,t.normalState=null,t.matches=[],t.deferredDirectoryTarget=null,t.filter="",t.view="normal",this.fileBrowserData=null,this.fileBrowserFilter="",this.fileBrowserExpandedDirs?.clear?.(),this.fileBrowserAllExpanded=!1;const s=this.$?.("fileBrowserSearch");s&&(s.value=""),this._syncFileBrowserExpandBtn();const n=this.$?.("fileBrowserExpandBtn");n&&(n.innerHTML="\u229E");const i=this.$?.("fileBrowserPanel"),o=this.$?.("fileBrowserTree"),l=this.$?.("fileBrowserStatus"),a=i?.classList.contains("visible")===!0;o&&(o.innerHTML=a?`<div class="file-browser-loading">${escapeHtml("Loading files...")}</div>`:""),l&&(l.textContent=a?"Loading files...":""),a&&this.loadFileBrowser?.(e)?.catch?.(()=>{})},_resetFileBrowserForHide(){const e=this._ensureFileBrowserState();e.inFlight?.timer!==void 0&&e.inFlight?.timer!==null&&clearTimeout(e.inFlight.timer),e.searchEpoch++,e.treeEpoch++,e.treeInFlight=null,e.inFlight=null,e.normalState=null,e.matches=[],e.deferredDirectoryTarget=null,e.filter="",e.view="normal",this.fileBrowserData=null,this.fileBrowserFilter="",this.fileBrowserExpandedDirs?.clear?.(),this.fileBrowserAllExpanded=!1;const t=this.$?.("fileBrowserSearch");t&&(t.value=""),this._syncFileBrowserExpandBtn();const s=this.$?.("fileBrowserExpandBtn");s&&(s.innerHTML="\u229E");const n=this.$?.("fileBrowserTree");n&&(n.innerHTML="");const i=this.$?.("fileBrowserStatus");i&&(i.textContent="")},_setFileBrowserExpandDisabled(e){const t=this.$("fileBrowserExpandBtn");t&&(t.disabled=e)},_hasFileBrowserQuery(){const e=this._ensureFileBrowserState(),t=this.$?.("fileBrowserSearch"),s=typeof t?.value=="string"?t.value:"",n=typeof e.filter=="string"?e.filter:"";return s.trim()!==""||n.trim()!==""},_syncFileBrowserExpandBtn(){this._setFileBrowserExpandDisabled(this._hasFileBrowserQuery())},_renderFileBrowserNormalStatus(e,t){const s=this.$("fileBrowserStatus");if(!s||!e)return;const{totalFiles:n,totalDirectories:i,truncated:o}=e;s.textContent=`${n} files, ${i} dirs${o?" (truncated)":""}${t?" \xB7 hidden shown":""}`},_isFileBrowserNormalCompatible(e,t,s,n){return e?.sessionId===t&&e.showHidden===s&&e.treeEpoch===n},_isFileBrowserTreeContextCurrent(e,t=!1){const s=this._ensureFileBrowserState();return(!t||s.treeInFlight===e)&&s.ownerSessionId===e.sessionId&&s.treeEpoch===e.treeEpoch&&this.fileBrowserShowHidden===!0===e.showHidden},_canRenderFileBrowserNormal(e){const t=this._ensureFileBrowserState();return t.view==="normal"&&this.activeSessionId===e?.sessionId&&this._isFileBrowserNormalCompatible(e,t.ownerSessionId,this.fileBrowserShowHidden===!0,t.treeEpoch)&&this.$("fileBrowserPanel")?.classList.contains("visible")===!0},_renderFileBrowserNormalState(e){if(!e||!this._canRenderFileBrowserNormal(e))return;const t=this.$("fileBrowserTree"),s=this.$("fileBrowserStatus");if(t){if(e.phase==="loading"){this.fileBrowserData=null,t.innerHTML=`<div class="file-browser-loading">${escapeHtml("Loading files...")}</div>`,s&&(s.textContent="Loading files...");return}if(e.phase==="error"){this.fileBrowserData=null;const i=`Failed to load files${e.error&&e.error!=="Failed to load files"?`: ${e.error}`:""}`;t.innerHTML=`<div class="file-browser-empty">${escapeHtml(i)}</div>`,s&&(s.textContent=i);return}e.phase==="ready"&&(this.fileBrowserData=e.data,this._syncFileBrowserExpandBtn(),this.renderFileBrowserTree(e.sessionId),this._renderFileBrowserNormalStatus(e.data,e.showHidden))}},_validateFileBrowserTreeEnvelope(e){if(!e||typeof e!="object"||e.success!==!0)return null;const t=e.data;if(!t||typeof t!="object"||!Array.isArray(t.tree)||t.mode==="search"||typeof t.totalFiles!="number"||!Number.isFinite(t.totalFiles)||t.totalFiles<0||typeof t.totalDirectories!="number"||!Number.isFinite(t.totalDirectories)||t.totalDirectories<0||typeof t.truncated!="boolean")return null;const s=n=>n.every(i=>!(!i||typeof i!="object"||typeof i.name!="string"||typeof i.path!="string"||i.type!=="file"&&i.type!=="directory"||i.size!==void 0&&(typeof i.size!="number"||!Number.isFinite(i.size))||i.extension!==void 0&&typeof i.extension!="string"||i.children!==void 0&&(!Array.isArray(i.children)||!s(i.children))));return s(t.tree)?t:null},_normalizeFileBrowserTreeError(e){return typeof e?.message=="string"&&e.message?e.message:"Failed to load files"},_validateFileBrowserSearchEnvelope(e){if(!e||typeof e!="object"||e.success!==!0)return null;const t=e.data;if(!t||typeof t!="object"||t.mode!=="search"||!Array.isArray(t.matches)||typeof t.truncated!="boolean"||t.matchCount!==void 0&&(typeof t.matchCount!="number"||!Number.isFinite(t.matchCount)||t.matchCount<0))return null;for(const s of t.matches)if(!s||typeof s!="object"||typeof s.name!="string"||typeof s.path!="string"||s.type!=="file"&&s.type!=="directory"||s.size!==void 0&&(typeof s.size!="number"||!Number.isFinite(s.size))||s.extension!==void 0&&typeof s.extension!="string")return null;return t},_canRenderFileBrowserSearch(e){const t=this._ensureFileBrowserState(),s=this.$("fileBrowserPanel");return t.searchEpoch===e.epoch&&t.ownerSessionId===e.ownerSessionId&&this.activeSessionId===e.ownerSessionId&&this.fileBrowserShowHidden===!0===e.showHidden&&t.filter===e.rawInput&&s?.classList.contains("visible")===!0},_renderFileBrowserSearchError(){const e=this.$("fileBrowserTree"),t=this.$("fileBrowserStatus"),s="Search failed";e&&(e.innerHTML=`<div class="file-browser-empty">${escapeHtml(s)}</div>`),t&&(t.textContent=s)},_canContinueFileBrowserHiddenReload(e,t){const s=this._ensureFileBrowserState(),n=this.$?.("fileBrowserSearch"),i=typeof n?.value=="string"?n.value:s.filter;return s.view==="normal"&&s.searchEpoch===e.searchEpoch&&s.treeEpoch===e.treeEpoch&&s.ownerSessionId===e.ownerSessionId&&this.activeSessionId===e.ownerSessionId&&this.fileBrowserShowHidden===!0===e.showHidden&&s.filter===e.rawInput&&i===e.rawInput&&i.trim()===e.query&&this.$?.("fileBrowserPanel")?.classList.contains("visible")===!0&&t?.phase==="ready"&&this._isFileBrowserNormalCompatible(t,e.ownerSessionId,e.showHidden,e.treeEpoch)},async toggleFileBrowserHidden(){const e=this._ensureFileBrowserState(),t=typeof e.filter=="string"?e.filter:"",s=t.trim();this.fileBrowserShowHidden=!this.fileBrowserShowHidden;try{localStorage.setItem(FILE_BROWSER_SHOW_HIDDEN_KEY,this.fileBrowserShowHidden?"1":"0")}catch{}this._syncFileBrowserHiddenBtn(),e.inFlight?.timer!==void 0&&e.inFlight?.timer!==null&&clearTimeout(e.inFlight.timer),e.searchEpoch++,e.inFlight=null,e.matches=[],e.deferredDirectoryTarget=null,e.normalState=null,this.fileBrowserData=null,s.length<=256&&(e.view="normal"),this._syncFileBrowserExpandBtn();const n=e.ownerSessionId||this.activeSessionId;if(!n||this.activeSessionId!==n)return;const i=e.searchEpoch,o=this.fileBrowserShowHidden===!0,l=this.loadFileBrowser(n,{force:!0}),a=e.treeEpoch;if(!l?.then||(await l,!s||s.length>256))return;const r={ownerSessionId:n,showHidden:o,treeEpoch:a,searchEpoch:i,rawInput:t,query:s};this._canContinueFileBrowserHiddenReload(r,e.normalState)&&this.filterFileBrowser(t)},loadFileBrowser(e,{force:t=!1}={}){if(!e)return;const s=this._ensureFileBrowserState(),n=this.$("fileBrowserTree");if(this._syncFileBrowserHiddenBtn(),!n||(s.ownerSessionId||(s.ownerSessionId=e),s.ownerSessionId!==e))return;t&&s.treeEpoch++;const i=this.fileBrowserShowHidden===!0,o=s.treeEpoch,l=s.treeInFlight;if(!t&&this._isFileBrowserNormalCompatible(l,e,i,o))return l.promise;const a=s.normalState;if(!t&&this._isFileBrowserNormalCompatible(a,e,i,o)&&(a.phase==="ready"||a.phase==="error"))return a.phase==="ready"&&(this.fileBrowserData=a.data),this._renderFileBrowserNormalState(a),Promise.resolve(a);const r={sessionId:e,showHidden:i,treeEpoch:o,phase:"loading"};s.normalState=r,this.fileBrowserData=null,this._renderFileBrowserNormalState(r);const c={sessionId:e,showHidden:i,treeEpoch:o,promise:null},h=(async()=>{try{const d=await fetch(`/api/sessions/${encodeURIComponent(e)}/files?depth=5&showHidden=${i}`);if(!d.ok)throw new Error("Failed to load files");const u=await d.json(),p=this._validateFileBrowserTreeEnvelope(u);if(!p){const y=u&&typeof u=="object"&&typeof u.error=="string"?u.error:"Failed to load files";throw new Error(y)}if(!this._isFileBrowserTreeContextCurrent(c,!0))return;const f={sessionId:e,showHidden:i,treeEpoch:o,phase:"ready",data:p};s.normalState=f,this.fileBrowserData=p,this._completeDeferredFileBrowserDirectory?.(f)===!0||this._renderFileBrowserNormalState(f)}catch(d){if(!this._isFileBrowserTreeContextCurrent(c,!0))return;const u={sessionId:e,showHidden:i,treeEpoch:o,phase:"error",error:this._normalizeFileBrowserTreeError(d)};s.normalState=u,this.fileBrowserData=null,this._completeDeferredFileBrowserDirectory?.(u),console.error("Failed to load file browser:",d),this._renderFileBrowserNormalState(u)}})();return c.promise=h.finally(()=>{s.treeInFlight===c&&(s.treeInFlight=null)}),s.treeInFlight=c,c.promise},renderFileBrowserTree(e){const t=this.$("fileBrowserTree");if(!t||!this.fileBrowserData)return;const s=this._ensureFileBrowserState(),n=e||s.normalState?.sessionId||s.ownerSessionId||this.activeSessionId;if(!n)return;const{tree:i}=this.fileBrowserData;if(!i||i.length===0){t.innerHTML='<div class="file-browser-empty">No files found</div>';return}const o=[],l=(a,r)=>{const c=a.type==="directory",h=this.fileBrowserExpandedDirs.has(a.path),d=c?h?"\u{1F4C2}":"\u{1F4C1}":this.getFileIcon(a.extension),u=c?`<span class="file-tree-expand${h?" expanded":""}">\u25B6</span>`:'<span class="file-tree-expand"></span>',p=!c&&a.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(a.size)}</span>`:"",f=c?"file-tree-name directory":"file-tree-name",w=c?"":`<a class="file-tree-download" href="${escapeHtml(CodemanBase.url(`/api/sessions/${encodeURIComponent(n)}/file-raw?path=${encodeURIComponent(a.path)}&download=true`))}" title="Download" onclick="event.stopPropagation()">&#x2B07;</a>`;if(o.push(`
224
230
  <div class="file-tree-item" data-path="${escapeHtml(a.path)}" data-type="${escapeHtml(a.type)}" data-depth="${r}">
225
231
  ${u}
226
232
  <span class="file-tree-icon">${d}</span>
@@ -228,7 +234,7 @@
228
234
  ${p}
229
235
  ${w}
230
236
  </div>
231
- `),c&&h&&a.children)for(const y of a.children)l(y,r+1)};for(const a of n)l(a,0);t.innerHTML=o.join(""),t.querySelectorAll(".file-tree-item").forEach(a=>{a.addEventListener("click",()=>{const r=a.dataset.path;a.dataset.type==="directory"?this.toggleFileBrowserFolder(r):this.openFilePreview(r,i)})})},toggleFileBrowserFolder(e){this.fileBrowserExpandedDirs.has(e)?this.fileBrowserExpandedDirs.delete(e):this.fileBrowserExpandedDirs.add(e),this.renderFileBrowserTree()},filterFileBrowser(e){const t=this._ensureFileBrowserState(),s=String(e??""),i=s.trim();t.searchEpoch++,t.filter=s,t.deferredDirectoryTarget=null,this.fileBrowserFilter=s,this._syncFileBrowserExpandBtn(),t.inFlight?.timer!==void 0&&t.inFlight?.timer!==null&&clearTimeout(t.inFlight.timer),t.inFlight=null,!t.ownerSessionId&&this.activeSessionId&&(t.ownerSessionId=this.activeSessionId);const n=t.ownerSessionId||null;if(!this.activeSessionId||!n||this.activeSessionId!==n)return;if(!i){t.view="normal",t.matches=[],this._syncFileBrowserExpandBtn();const c=t.normalState;n&&this._isFileBrowserNormalCompatible(c,n,this.fileBrowserShowHidden===!0,t.treeEpoch)&&this._renderFileBrowserNormalState(c);return}if(i.length>256){const c="Search queries are limited to 256 characters";t.view="query-error",t.matches=[],this._syncFileBrowserExpandBtn();const h=this.$("fileBrowserTree"),d=this.$("fileBrowserStatus");h&&(h.innerHTML=`<div class="file-browser-empty">${escapeHtml(c)}</div>`),d&&(d.textContent=c);return}const o=this.$("fileBrowserPanel"),l=this.$("fileBrowserTree");if(!n||!o||!l)return;const a={epoch:t.searchEpoch,treeEpoch:t.treeEpoch,ownerSessionId:n,showHidden:this.fileBrowserShowHidden===!0,rawInput:s,query:i,timer:null};t.view="search-pending",t.matches=[],t.inFlight=a,this._syncFileBrowserExpandBtn(),l.innerHTML=`<div class="file-browser-loading">${escapeHtml("Searching...")}</div>`;const r=this.$("fileBrowserStatus");r&&(r.textContent="Searching..."),a.timer=setTimeout(async()=>{a.timer=null;try{const c=await fetch(`/api/sessions/${encodeURIComponent(n)}/files?depth=5&showHidden=${a.showHidden}&q=${encodeURIComponent(i)}`);if(!c.ok)throw new Error("Search failed");const h=await c.json(),d=this._validateFileBrowserSearchEnvelope(h);if(!d)throw new Error("Search failed");const u=this._canRenderFileBrowserSearch(a);if(t.inFlight===a&&(t.inFlight=null),!u)return;t.view="search-results",t.matches=d.matches,this._renderFileBrowserSearchResults(d.matches,n,d)}catch(c){const h=this._canRenderFileBrowserSearch(a);if(t.inFlight===a&&(t.inFlight=null),!h)return;console.error("Failed to search file browser:",c),t.view="search-error",t.matches=[],this._renderFileBrowserSearchError()}},250)},_renderFileBrowserSearchResults(e,t,s){const i=this.$("fileBrowserTree");if(!i||!t)return;const n=this._ensureFileBrowserState(),o={ownerSessionId:t,showHidden:this.fileBrowserShowHidden===!0,treeEpoch:n.treeEpoch,searchEpoch:n.searchEpoch,rawInput:n.filter,query:n.filter.trim(),view:n.view};if(e.length===0)i.innerHTML=`<div class="file-browser-empty">${escapeHtml("No matches")}</div>`;else{const a=encodeURIComponent(t);i.innerHTML=e.map(r=>{const c=r.type==="directory",h=c?"\u{1F4C1}":this.getFileIcon(r.extension||""),d=!c&&r.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(r.size)}</span>`:"",u=c?"file-tree-name directory":"file-tree-name",p=c?"":`<a class="file-tree-download" href="${escapeHtml(CodemanBase.url(`/api/sessions/${a}/file-raw?path=${encodeURIComponent(r.path)}&download=true`))}" title="Download" onclick="event.stopPropagation()">&#x2B07;</a>`;return`
237
+ `),c&&h&&a.children)for(const y of a.children)l(y,r+1)};for(const a of i)l(a,0);t.innerHTML=o.join(""),t.querySelectorAll(".file-tree-item").forEach(a=>{a.addEventListener("click",()=>{const r=a.dataset.path;a.dataset.type==="directory"?this.toggleFileBrowserFolder(r):this.openFilePreview(r,n)})})},toggleFileBrowserFolder(e){this.fileBrowserExpandedDirs.has(e)?this.fileBrowserExpandedDirs.delete(e):this.fileBrowserExpandedDirs.add(e),this.renderFileBrowserTree()},filterFileBrowser(e){const t=this._ensureFileBrowserState(),s=String(e??""),n=s.trim();t.searchEpoch++,t.filter=s,t.deferredDirectoryTarget=null,this.fileBrowserFilter=s,this._syncFileBrowserExpandBtn(),t.inFlight?.timer!==void 0&&t.inFlight?.timer!==null&&clearTimeout(t.inFlight.timer),t.inFlight=null,!t.ownerSessionId&&this.activeSessionId&&(t.ownerSessionId=this.activeSessionId);const i=t.ownerSessionId||null;if(!this.activeSessionId||!i||this.activeSessionId!==i)return;if(!n){t.view="normal",t.matches=[],this._syncFileBrowserExpandBtn();const c=t.normalState;i&&this._isFileBrowserNormalCompatible(c,i,this.fileBrowserShowHidden===!0,t.treeEpoch)&&this._renderFileBrowserNormalState(c);return}if(n.length>256){const c="Search queries are limited to 256 characters";t.view="query-error",t.matches=[],this._syncFileBrowserExpandBtn();const h=this.$("fileBrowserTree"),d=this.$("fileBrowserStatus");h&&(h.innerHTML=`<div class="file-browser-empty">${escapeHtml(c)}</div>`),d&&(d.textContent=c);return}const o=this.$("fileBrowserPanel"),l=this.$("fileBrowserTree");if(!i||!o||!l)return;const a={epoch:t.searchEpoch,treeEpoch:t.treeEpoch,ownerSessionId:i,showHidden:this.fileBrowserShowHidden===!0,rawInput:s,query:n,timer:null};t.view="search-pending",t.matches=[],t.inFlight=a,this._syncFileBrowserExpandBtn(),l.innerHTML=`<div class="file-browser-loading">${escapeHtml("Searching...")}</div>`;const r=this.$("fileBrowserStatus");r&&(r.textContent="Searching..."),a.timer=setTimeout(async()=>{a.timer=null;try{const c=await fetch(`/api/sessions/${encodeURIComponent(i)}/files?depth=5&showHidden=${a.showHidden}&q=${encodeURIComponent(n)}`);if(!c.ok)throw new Error("Search failed");const h=await c.json(),d=this._validateFileBrowserSearchEnvelope(h);if(!d)throw new Error("Search failed");const u=this._canRenderFileBrowserSearch(a);if(t.inFlight===a&&(t.inFlight=null),!u)return;t.view="search-results",t.matches=d.matches,this._renderFileBrowserSearchResults(d.matches,i,d)}catch(c){const h=this._canRenderFileBrowserSearch(a);if(t.inFlight===a&&(t.inFlight=null),!h)return;console.error("Failed to search file browser:",c),t.view="search-error",t.matches=[],this._renderFileBrowserSearchError()}},250)},_renderFileBrowserSearchResults(e,t,s){const n=this.$("fileBrowserTree");if(!n||!t)return;const i=this._ensureFileBrowserState(),o={ownerSessionId:t,showHidden:this.fileBrowserShowHidden===!0,treeEpoch:i.treeEpoch,searchEpoch:i.searchEpoch,rawInput:i.filter,query:i.filter.trim(),view:i.view};if(e.length===0)n.innerHTML=`<div class="file-browser-empty">${escapeHtml("No matches")}</div>`;else{const a=encodeURIComponent(t);n.innerHTML=e.map(r=>{const c=r.type==="directory",h=c?"\u{1F4C1}":this.getFileIcon(r.extension||""),d=!c&&r.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(r.size)}</span>`:"",u=c?"file-tree-name directory":"file-tree-name",p=c?"":`<a class="file-tree-download" href="${escapeHtml(CodemanBase.url(`/api/sessions/${a}/file-raw?path=${encodeURIComponent(r.path)}&download=true`))}" title="Download" onclick="event.stopPropagation()">&#x2B07;</a>`;return`
232
238
  <div class="file-tree-item" data-path="${escapeHtml(r.path)}" data-type="${escapeHtml(r.type)}" data-owner="${escapeHtml(t)}">
233
239
  <span class="file-tree-expand"></span>
234
240
  <span class="file-tree-icon">${h}</span>
@@ -236,18 +242,18 @@
236
242
  ${d}
237
243
  ${p}
238
244
  </div>
239
- `}).join("")}i.querySelectorAll(".file-tree-item").forEach(a=>{a.addEventListener("click",()=>{const r=a.dataset.path;a.dataset.type==="directory"?this._openFileBrowserSearchDirectory({...o,path:r}):this.openFilePreview(r,t)})});const l=this.$("fileBrowserStatus");if(l){const a=s.matchCount===void 0?e.length:s.matchCount;l.textContent=`${a} ${a===1?"match":"matches"}${s.truncated?" (truncated)":""}`}},_findFileBrowserDirectory(e,t,s=[]){if(!Array.isArray(e))return null;for(const i of e){if(!i||typeof i!="object")continue;if(i.type==="directory"&&i.path===t)return{target:i,ancestors:[...s]};if(i.type!=="directory"||!Array.isArray(i.children))continue;const n=this._findFileBrowserDirectory(i.children,t,[...s,i.path]);if(n)return n}return null},_isFileBrowserDirectoryContextCurrent(e){const t=this._ensureFileBrowserState(),s=this.$?.("fileBrowserSearch"),i=typeof s?.value=="string"?s.value:t.filter;return e&&t.ownerSessionId===e.ownerSessionId&&this.activeSessionId===e.ownerSessionId&&t.treeEpoch===e.treeEpoch&&t.searchEpoch===e.searchEpoch&&this.fileBrowserShowHidden===!0===e.showHidden&&t.filter===e.rawInput&&i===e.rawInput&&i.trim()===e.query&&t.view===e.view&&this.$?.("fileBrowserPanel")?.classList.contains("visible")===!0},_promptFileBrowserDirectoryReload(){this.showToast?.("Reload files before opening this folder","info")},_openFileBrowserSearchDirectory(e){if(!this._isFileBrowserDirectoryContextCurrent(e))return;const t=this._ensureFileBrowserState(),s=t.normalState;if(!this._isFileBrowserNormalCompatible(s,e.ownerSessionId,e.showHidden,e.treeEpoch)){t.deferredDirectoryTarget=null,this._promptFileBrowserDirectoryReload();return}if(s.phase==="loading"){t.deferredDirectoryTarget={...e};return}if(t.deferredDirectoryTarget=null,s.phase!=="ready"){this._promptFileBrowserDirectoryReload();return}const i=this._findFileBrowserDirectory(s.data?.tree,e.path);if(!i){this._promptFileBrowserDirectoryReload();return}this._leaveFileBrowserSearchForDirectory([...i.ancestors,i.target.path],s)},_completeDeferredFileBrowserDirectory(e){const t=this._ensureFileBrowserState(),s=t.deferredDirectoryTarget;if(!s)return!1;if(!this._isFileBrowserDirectoryContextCurrent(s))return t.deferredDirectoryTarget===s&&(t.deferredDirectoryTarget=null),!1;if(!this._isFileBrowserNormalCompatible(e,s.ownerSessionId,s.showHidden,s.treeEpoch)||e.phase!=="ready"&&e.phase!=="error")return!1;if(t.deferredDirectoryTarget=null,e.phase==="error")return this._promptFileBrowserDirectoryReload(),!1;const i=this._findFileBrowserDirectory(e.data?.tree,s.path);return i?(this._leaveFileBrowserSearchForDirectory([...i.ancestors,i.target.path],e),!0):(this._promptFileBrowserDirectoryReload(),!1)},_leaveFileBrowserSearchForDirectory(e,t){const s=this._ensureFileBrowserState();s.inFlight?.timer!==void 0&&s.inFlight?.timer!==null&&clearTimeout(s.inFlight.timer),s.searchEpoch++,s.inFlight=null,s.filter="",s.matches=[],s.deferredDirectoryTarget=null,s.view="normal",this.fileBrowserFilter="";const i=this.$?.("fileBrowserSearch");i&&(i.value=""),this._syncFileBrowserExpandBtn();for(const n of e)typeof n=="string"&&this.fileBrowserExpandedDirs?.add?.(n);this.fileBrowserData=t.data,this._renderFileBrowserNormalState(t)},expandAllDirectories(e){for(const t of e)t.type==="directory"&&(this.fileBrowserExpandedDirs.add(t.path),t.children&&this.expandAllDirectories(t.children))},collapseAllDirectories(){this.fileBrowserExpandedDirs.clear()},toggleFileBrowserExpand(){if(this._hasFileBrowserQuery()){this._syncFileBrowserExpandBtn();return}this.fileBrowserAllExpanded=!this.fileBrowserAllExpanded;const e=this.$("fileBrowserExpandBtn");this.fileBrowserAllExpanded?(this.expandAllDirectories(this.fileBrowserData?.tree||[]),e&&(e.innerHTML="\u229F")):(this.collapseAllDirectories(),e&&(e.innerHTML="\u229E")),this.renderFileBrowserTree()},refreshFileBrowser(){const e=this._ensureFileBrowserState();e.inFlight?.timer!==void 0&&e.inFlight?.timer!==null&&clearTimeout(e.inFlight.timer),e.inFlight=null,e.searchEpoch++,e.filter="",e.matches=[],e.deferredDirectoryTarget=null,e.view="normal",this.fileBrowserFilter="",this.fileBrowserExpandedDirs.clear(),this.fileBrowserAllExpanded=!1;const t=this.$("fileBrowserExpandBtn");t&&(t.innerHTML="\u229E");const s=this.$("fileBrowserSearch");s&&(s.value=""),this._syncFileBrowserExpandBtn();const i=e.ownerSessionId||this.activeSessionId;if(!(!i||this.activeSessionId!==i))return this.loadFileBrowser(i,{force:!0})},toggleFileBrowserButton(){const t=this.$("fileBrowserPanel")?.classList.contains("visible"),s=document.querySelector(".btn-file-viewer");if(t){this.closeFileBrowserPanel(),s&&s.setAttribute("aria-expanded","false");return}if(!this.activeSessionId){this.showToast("Open a session to browse its files","info");return}const i=this.loadAppSettingsFromStorage();i.showFileBrowser=!0,this.saveAppSettingsToStorage(i);const n=document.getElementById("appSettingsShowFileBrowser");n&&(n.checked=!0),this.applyMonitorVisibility(),s&&s.setAttribute("aria-expanded","true")},closeFileBrowserPanel(){const e=this.$("fileBrowserPanel");if(this._resetFileBrowserForHide(),e&&(e.classList.remove("visible"),e.style.left="",e.style.top="",e.style.bottom="",e.style.right=""),this.fileBrowserDragListeners){const n=this.fileBrowserDragListeners;document.removeEventListener("mousemove",n.move),document.removeEventListener("mouseup",n.up),document.removeEventListener("touchmove",n.touchMove),document.removeEventListener("touchend",n.up),document.removeEventListener("touchcancel",n.up),n.handle&&(n.handle.removeEventListener("mousedown",n.handleMouseDown),n.handle.removeEventListener("touchstart",n.handleTouchStart),n._onFirstDrag&&(n.handle.removeEventListener("mousedown",n._onFirstDrag),n.handle.removeEventListener("touchstart",n._onFirstDrag))),this.fileBrowserDragListeners=null}const t=this.loadAppSettingsFromStorage();t.showFileBrowser=!1,this.saveAppSettingsToStorage(t);const s=document.getElementById("appSettingsShowFileBrowser");s&&(s.checked=!1);const i=document.querySelector(".btn-file-viewer");i&&i.setAttribute("aria-expanded","false")},_isExternalPreviewPath(e,t){if(typeof e=="string"&&e.startsWith("~/"))return!0;if(typeof e!="string"||!e.startsWith("/"))return!1;const s=this.sessions.get(t)?.workingDir;if(!s)return!1;const i=s.endsWith("/")?s:`${s}/`;return e!==s&&!e.startsWith(i)},async _registerExternalPreview(e,t){try{const s=await fetch(`/api/sessions/${t}/attachments`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e,notify:!1})}),i=await s.json().catch(()=>null);if(s.ok&&i?.success&&i.data?.attachmentId)return{attachmentId:i.data.attachmentId,size:i.data.size||0};const n=i?.error||`Cannot open this file (HTTP ${s.status})`;return/unsupported/i.test(n)?{error:`Cannot preview .${(e.split(".").pop()||"").toLowerCase()} from outside the session workspace (images, video, audio, PDF, Office documents and text files only).`}:{error:n}}catch(s){return{error:s.message||"Cannot open this file"}}},async openFilePreview(e,t=this.activeSessionId,s=null,i={}){if(!t||!e)return;const n=i.folderFile||null;!n&&this.folderGrid&&(this.folderGrid.index=null),this._updateFolderPreviewNav(n?null:this._previewFolderPath(e,t,s));const o=this.$("filePreviewOverlay"),l=this.$("filePreviewTitle"),a=this.$("filePreviewBody"),r=this.$("filePreviewFooter");if(!o||!a)return;this._recordFilePreviewHistory(e,t,s,i),this._bindFilePreviewChrome();const c=this._filePreviewLoad=(this._filePreviewLoad||0)+1,h=()=>c!==this._filePreviewLoad;this._resetFilePreviewEdit(),this._stopFilePreviewMedia(),this.filePreviewDetachUrl="";const d=this.$("filePreviewDetachBtn");d&&(d.hidden=!0),this.filePreviewText=null,this.filePreviewPage=null,this.filePreviewPageRefused=!1,this._updateFilePreviewToolbar("none"),o.classList.add("visible"),this._applyFilePreviewExpanded(),l.textContent=e,a.innerHTML='<div class="binary-message">Loading...</div>',r.textContent="";const u=(e.split(".").pop()||"").toLowerCase();if(!s&&rendersAsPage(e)&&this._filePreviewPref("htmlRendered")){const g=await this._mintHtmlViewUrl(e,t);if(g){r.textContent="HTML",this.filePreviewPage={filePath:e,sessionId:t},this.filePreviewDetachUrl=g,d&&(d.hidden=!1),a.innerHTML=`<iframe src="${escapeHtml(g)}" title="${escapeHtml(e)}" sandbox="allow-scripts allow-forms allow-popups allow-modals allow-downloads"></iframe>`,this._updateFilePreviewToolbar("page");return}this.filePreviewPageRefused=!0}let p="",f=0;if(!s&&!n&&this._isExternalPreviewPath(e,t)){const g=await this._registerExternalPreview(e,t);if(h())return;s=g.attachmentId||null,p=g.error||"",f=g.size||0}if(!s&&p){r.textContent="",a.innerHTML=`<div class="binary-message">${escapeHtml(p)}</div>`;return}const w=u==="docx"||u==="pptx",y=s?`/api/sessions/${t}/attachments/${encodeURIComponent(s)}`:n?`/api/sessions/${t}/folders/${encodeURIComponent(n.folderId)}/files/${encodeURIComponent(n.name)}`:null;if(this.filePreviewDetachUrl=CodemanBase.url(y?`${y}/${w?"preview":"raw"}`:w?`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`),d&&(d.hidden=!1),y){const g=CodemanBase.url(y),T=new Set(["png","jpg","jpeg","gif","webp","bmp","svg"]),m=new Set(["mp4","webm","mov","m4v","ogv"]),S=new Set(["mp3","wav","ogg","oga","m4a","aac","flac","opus"]);if(n&&!f&&(f=i.size||0),r.textContent=f?`${this.formatFileSize(f)} \u2022 ${u}`:u.toUpperCase(),T.has(u))a.innerHTML=`<img src="${escapeHtml(`${g}/raw`)}" alt="${escapeHtml(e)}">`;else if(m.has(u))a.innerHTML=`<video src="${escapeHtml(`${g}/raw`)}" controls autoplay playsinline preload="metadata"></video>`;else if(S.has(u))a.innerHTML=`<audio src="${escapeHtml(`${g}/raw`)}" controls autoplay preload="metadata"></audio>`;else if(u==="pdf")a.innerHTML=`<iframe src="${escapeHtml(`${g}/raw`)}" title="${escapeHtml(e)}"></iframe>`;else if(u==="docx"||u==="pptx")a.innerHTML=`<iframe src="${escapeHtml(`${g}/preview`)}" title="${escapeHtml(e)}"></iframe>`;else if(u==="xlsx")this._openSpreadsheetPreview(a,`${g}/raw`,f);else try{const $=await fetch(`${g}/raw`,{headers:{Range:"bytes=0-524287"}});if(!$.ok)throw new Error("Failed to load attachment");const b=await $.text();if(h())return;const C=$.status===206&&b.length>=524288,E=b.split(`
240
- `),I=MARKDOWN_EXTS.has(u)?1/0:500,B=E.length>I,D=B?E.slice(0,I).join(`
241
- `):b;if(this.filePreviewContent=D,this.filePreviewText={ext:u,sessionId:t,filePath:e,attachmentId:s||n?.folderId},this._renderFilePreviewText(),B||C){const x=B?`showing first ${I} lines`:"showing the start of the file";r.textContent=`${r.textContent} (${x})`}}catch($){if(h())return;a.innerHTML=`<div class="binary-message">Error: ${escapeHtml($.message)}</div>`}return}if(u==="docx"||u==="pptx"){r.textContent=u.toUpperCase();const g=CodemanBase.url(`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`);a.innerHTML=`<iframe src="${escapeHtml(g)}" title="${escapeHtml(e)}"></iframe>`;return}if(u==="pdf"){r.textContent="PDF";const g=CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);a.innerHTML=`<iframe src="${escapeHtml(g)}" title="${escapeHtml(e)}"></iframe>`;return}if(u==="svg"){r.textContent="SVG";try{const g=await fetch(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);if(!g.ok)throw new Error("Failed to load image");const T=await g.text();if(h())return;const m=URL.createObjectURL(new Blob([T],{type:"image/svg+xml"}));a.innerHTML=`<img src="${m}" alt="${escapeHtml(e)}">`;const S=a.querySelector("img");S&&(S.onload=()=>URL.revokeObjectURL(m))}catch(g){if(h())return;a.innerHTML=`<div class="binary-message">Error: ${escapeHtml(g.message)}</div>`}return}const v=MARKDOWN_EXTS.has(u)?1e4:500;try{const g=await fetch(`/api/sessions/${t}/file-content?path=${encodeURIComponent(e)}&lines=${v}`);if(!g.ok)throw new Error("Failed to load file");const T=await g.json();if(h())return;if(!T.success)throw new Error(T.error||"Failed to load file");const m=T.data;if(m.type==="image")a.innerHTML=`<img src="${escapeHtml(CodemanBase.url(m.url))}" alt="${escapeHtml(e)}">`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="video")a.innerHTML=`<video src="${escapeHtml(CodemanBase.url(m.url))}" controls autoplay playsinline preload="metadata"></video>`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="audio")a.innerHTML=`<audio src="${escapeHtml(CodemanBase.url(m.url))}" controls autoplay preload="metadata"></audio>`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="spreadsheet")this._openSpreadsheetPreview(a,CodemanBase.url(m.url),m.size),r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="binary"){const S=CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}&download=true`);a.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(m.size)})<br>Cannot preview<br><a href="${escapeHtml(S)}" download>Download</a></div>`,r.textContent=m.extension||"binary"}else{this.filePreviewContent=m.content,this.filePreviewText={ext:u,sessionId:t,filePath:e},this._renderFilePreviewText();const S=m.truncated?` (showing ${v}/${m.totalLines} lines)`:"";if(r.textContent=`${m.totalLines} lines \u2022 ${this.formatFileSize(m.size)}${S}`,m.editable){this.filePreviewEditTarget={sessionId:t,filePath:e};const $=this.$("filePreviewEditBtn");$&&($.hidden=!1)}}}catch(g){if(h())return;console.error("Failed to preview file:",g),a.innerHTML=`<div class="binary-message">Error: ${escapeHtml(g.message)}</div>`}},async openFolderGrid(e,t=this.activeSessionId){if(!t||!e)return;const s=this.$("folderGridOverlay"),i=this.$("folderGridBody");if(!s||!i)return;this._bindFolderGridKeys();const n=this._folderGridLoad=(this._folderGridLoad||0)+1;let o=null,l=0;try{const a=await fetch(`/api/sessions/${t}/folders`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})});l=a.status,o=await a.json().catch(()=>null)}catch(a){if(n!==this._folderGridLoad)return;this.showToast(`Cannot open folder: ${a.message||a}`,"error");return}if(n===this._folderGridLoad){if(!o?.success||!o.data){const a=o?.error||`HTTP ${l}`;if(l===400&&/not a folder/i.test(a)){this.openFilePreview(e,t);return}this.showToast(`Cannot open folder ${e}: ${a}`,"error");return}this.folderGrid={sessionId:t,...o.data,index:null},this._renderFolderGrid(),s.classList.add("visible"),i.scrollTop=0}},closeFolderGrid(){this._folderGridLoad=(this._folderGridLoad||0)+1,this.$("folderGridOverlay")?.classList.remove("visible");const e=this.$("folderGridBody");e&&(e.innerHTML=""),this.folderGrid=null,this._updateFolderPreviewNav(null)},folderGridUp(){const e=this.folderGrid;!e||e.path==="/"||this.openFolderGrid(e.path.slice(0,e.path.lastIndexOf("/"))||"/",e.sessionId)},_renderFolderGrid(){const e=this.folderGrid;if(!e)return;const t=this.$("folderGridTitle"),s=this.$("folderGridFolders"),i=this.$("folderGridBody"),n=this.$("folderGridFooter");t.textContent=e.path,t.title=e.path;const o=this.$("folderGridUpBtn");o&&(o.disabled=e.path==="/"),s.innerHTML="";for(const r of e.folders){const c=document.createElement("button");c.type="button",c.className="folder-grid-chip",c.textContent=`${r}/`,c.onclick=()=>this.openFolderGrid(`${e.path==="/"?"":e.path}/${r}`,e.sessionId),s.appendChild(c)}if(i.innerHTML="",e.files.length===0){const r=document.createElement("div");r.className="folder-grid-empty",r.textContent="No previewable files in this folder.",i.appendChild(r)}e.files.forEach((r,c)=>{const h=document.createElement("button");h.type="button",h.className="folder-grid-tile",h.title=`${r.name} \u2022 ${this.formatFileSize(r.size)}`,h.dataset.index=String(c);const d=document.createElement("div");d.className="folder-grid-thumb";const u=r.extension.toUpperCase(),p=this._folderFileUrl(e,r.name,""),f=r.attachmentType==="image"?`${p}/raw`:["pdf","docx","pptx"].includes(r.extension)?`${p}/thumbnail`:null;if(f){const y=document.createElement("img");y.loading="lazy",y.decoding="async",y.alt=r.name,y.src=f,y.onerror=()=>{d.textContent=u},d.appendChild(y)}else d.textContent=u;const w=document.createElement("span");w.className="folder-grid-name",w.textContent=r.name,h.append(d,w),h.onclick=()=>this._openFolderGridFile(c),i.appendChild(h)});const l=`${e.files.length} file${e.files.length===1?"":"s"}`,a=e.folders.length?` \u2022 ${e.folders.length} folder${e.folders.length===1?"":"s"}`:"";n.textContent=`${l}${a}${e.truncated?" (folder too large \u2014 showing the first entries)":""}`},_folderFileUrl(e,t,s){return CodemanBase.url(`/api/sessions/${e.sessionId}/folders/${encodeURIComponent(e.folderId)}/files/${encodeURIComponent(t)}${s}`)},_openFolderGridFile(e){const t=this.folderGrid,s=t?.files[e];if(!s)return;const i=this.$("folderGridBody");i?.querySelectorAll(".folder-grid-tile.current").forEach(o=>o.classList.remove("current"));const n=i?.querySelector(`.folder-grid-tile[data-index="${e}"]`);n?.classList.add("current"),n?.scrollIntoView({block:"nearest"}),this.openFilePreview(`${t.path==="/"?"":t.path}/${s.name}`,t.sessionId,null,{folderFile:{folderId:t.folderId,name:s.name},size:s.size}),t.index=e,t.lastIndex=e,this._updateFolderPreviewNav(null)},stepFolderPreview(e){const t=this.folderGrid;if(!t||t.index===null||t.files.length===0||this.filePreviewEdit?.dirty&&!confirm("Discard unsaved changes?"))return;const s=(t.index+e+t.files.length)%t.files.length;this._openFolderGridFile(s)},_recordFilePreviewHistory(e,t,s,i){const n=this.filePreviewHistory=this.filePreviewHistory||{entries:[],index:-1};if(!this._filePreviewHistoryStepping){const o=n.entries[n.index];o&&o.filePath===e&&o.sessionId===t&&(o.attachmentId||null)===(s||null)||(n.entries.length=n.index+1,n.entries.push({filePath:e,sessionId:t,attachmentId:s||null,options:i}),n.entries.length>FILE_PREVIEW_HISTORY_MAX&&n.entries.shift(),n.index=n.entries.length-1)}this._updateFilePreviewHistoryNav()},stepFilePreviewHistory(e){const t=this.filePreviewHistory;if(!t)return;const s=t.index+e;if(s<0||s>=t.entries.length||this.filePreviewEdit?.dirty&&!confirm("Discard unsaved changes?"))return;t.index=s;const i=t.entries[s];this._filePreviewHistoryStepping=!0;try{const n=i.options?.folderFile;if(n&&n.folderId===this.folderGrid?.folderId){const o=this.folderGrid.files.findIndex(l=>l.name===n.name);if(o!==-1)return this._openFolderGridFile(o)}return this.openFilePreview(i.filePath,i.sessionId,i.attachmentId,i.options||{})}finally{this._filePreviewHistoryStepping=!1}},_updateFilePreviewHistoryNav(){const e=this.filePreviewHistory,t=!!e&&e.entries.length>1,s=this.$("filePreviewBackBtn"),i=this.$("filePreviewForwardBtn");s&&(s.hidden=!t,s.disabled=!t||e.index<=0),i&&(i.hidden=!t,i.disabled=!t||e.index>=e.entries.length-1)},toggleFilePreviewExpanded(){this._setFilePreviewPref("expanded",!this._filePreviewPref("expanded")),this._applyFilePreviewExpanded()},_applyFilePreviewExpanded(){const e=this._filePreviewPref("expanded");this.$("filePreviewOverlay")?.querySelector?.(".file-preview-window")?.classList?.toggle("expanded",e),this.$("filePreviewExpandBtn")?.setAttribute("aria-pressed",e?"true":"false")},_bindFilePreviewChrome(){this._filePreviewChromeBound||(this._filePreviewChromeBound=!0,document.addEventListener("keydown",e=>{if(!e.altKey||e.ctrlKey||e.metaKey||e.shiftKey||e.key!=="ArrowLeft"&&e.key!=="ArrowRight"||!this.$("filePreviewOverlay")?.classList.contains("visible"))return;const t=e.target;if(t&&(t.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName)&&!t.classList?.contains("xterm-helper-textarea")))return;e.preventDefault(),e.stopPropagation();const s=this.filePreviewHistory,i=e.key==="ArrowLeft"?-1:1;!s||s.index+i<0||s.index+i>=s.entries.length||this.stepFilePreviewHistory(i)},!0),this._bindFilePreviewResize())},_bindFilePreviewResize(){const e=this.$("filePreviewResize"),t=e?.parentElement;!e||!t||e.addEventListener("pointerdown",s=>{if(s.button!==0)return;s.preventDefault();const i=s.clientX,n=s.clientY,o=t.offsetWidth,l=t.offsetHeight;e.setPointerCapture?.(s.pointerId);const a=c=>{const h=Math.max(320,Math.min(window.innerWidth*.96,o+2*(c.clientX-i))),d=Math.max(240,Math.min(window.innerHeight*.94,l+2*(c.clientY-n)));t.style.width=`${Math.round(h)}px`,t.style.height=`${Math.round(d)}px`},r=()=>{e.removeEventListener("pointermove",a),e.removeEventListener("pointerup",r),e.removeEventListener("pointercancel",r)};e.addEventListener("pointermove",a),e.addEventListener("pointerup",r),e.addEventListener("pointercancel",r)})},openFolderOfPreview(){const e=this.filePreviewFolderTarget;e&&(this.closeFilePreview(),this.openFolderGrid(e.dir,e.sessionId))},_previewFolderPath(e,t,s){if(typeof e!="string"||s&&!e.includes("/"))return null;const i=this.sessions?.get?.(t)?.workingDir,n=typeof resolveLinkedFilePath=="function"?resolveLinkedFilePath(e,i):e;if(!n.startsWith("/")&&!n.startsWith("~/"))return null;const o=n.lastIndexOf("/");return{dir:n.slice(0,o)||"/",sessionId:t}},_updateFolderPreviewNav(e){const t=!!this.folderGrid&&this.folderGrid.index!==null&&this.folderGrid.files.length>1,s=this.$("filePreviewPrevBtn"),i=this.$("filePreviewNextBtn");s&&(s.hidden=!t),i&&(i.hidden=!t),e!==void 0&&(this.filePreviewFolderTarget=e);const n=!!this.folderGrid&&this.folderGrid.index!==null,o=this.$("filePreviewFolderBtn");o&&(o.hidden=n||!this.filePreviewFolderTarget)},_bindFolderGridKeys(){this._folderGridKeysBound||(this._folderGridKeysBound=!0,document.addEventListener("keydown",e=>{const t=this.folderGrid;if(!t||e.altKey||e.ctrlKey||e.metaKey)return;const s=this.$("filePreviewOverlay")?.classList.contains("visible");if(!this.$("folderGridOverlay")?.classList.contains("visible"))return;const n=e.target;if(n&&(n.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(n.tagName)&&!n.classList?.contains("xterm-helper-textarea"))||this.filePreviewEdit)return;let l=!0;s&&t.index!==null&&e.key==="ArrowLeft"?this.stepFolderPreview(-1):s&&t.index!==null&&e.key==="ArrowRight"?this.stepFolderPreview(1):!s&&(e.key==="ArrowLeft"||e.key==="ArrowRight")&&t.files.length?this._openFolderGridFile(t.lastIndex??0):e.key==="Escape"?s?this.closeFilePreview():this.closeFolderGrid():l=!1,l&&(e.preventDefault(),e.stopPropagation())},!0))},closeFilePreview(){if(this.filePreviewEdit?.dirty&&!confirm("Discard unsaved changes?"))return;this._resetFilePreviewEdit(),this.folderGrid&&(this.folderGrid.index=null),this._updateFolderPreviewNav(null),this.filePreviewHistory=null,this._updateFilePreviewHistoryNav();const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this._stopFilePreviewMedia(),this.filePreviewContent="",this.filePreviewText=null,this._updateFilePreviewToolbar("none"),this.filePreviewDetachUrl="";const t=this.$("filePreviewDetachBtn");t&&(t.hidden=!0)},detachFilePreview(){if(!this.filePreviewDetachUrl)return;const e=this.openInHostWindow?.(this.filePreviewDetachUrl)??null;if(e!==null){e?this.closeFilePreview():this.showToast("Could not open a new window for this preview","error");return}const t=window.open(this.filePreviewDetachUrl,"_blank");if(!t){this.showToast("Pop-up blocked: allow pop-ups for this site to detach previews","error");return}t.opener=null,this.closeFilePreview()},_stopFilePreviewMedia(){this._disposeSpreadsheetPreview();const e=this.$("filePreviewBody");if(e){for(const t of e.querySelectorAll("video, audio"))try{t.pause(),t.removeAttribute("src"),t.load()}catch(s){console.warn("Failed to stop preview media:",s)}e.innerHTML=""}},_openSpreadsheetPreview(e,t,s){this._disposeSpreadsheetPreview();const i=window.CodemanSpreadsheetPreview;if(!i?.open){e.innerHTML='<div class="binary-message">Spreadsheet preview is unavailable.</div>';return}e.textContent="";const n={};this._spreadsheetPreviewToken=n,this._spreadsheetPreview=i.open({container:e,url:t,size:s,isCurrent:()=>this._spreadsheetPreviewToken===n})},_disposeSpreadsheetPreview(){const e=this._spreadsheetPreview;this._spreadsheetPreview=null,this._spreadsheetPreviewToken=null;try{e?.dispose()}catch(t){console.warn("Failed to dispose spreadsheet preview:",t)}},_filePreviewPref(e){try{const t=localStorage.getItem(FILE_PREVIEW_PREF_KEYS[e]);if(t==="1")return!0;if(t==="0")return!1}catch{}return FILE_PREVIEW_PREF_DEFAULTS[e]},_setFilePreviewPref(e,t){try{localStorage.setItem(FILE_PREVIEW_PREF_KEYS[e],t?"1":"0")}catch{}},_renderFilePreviewText(){const e=this.filePreviewText,t=this.$("filePreviewBody");if(!e||!t)return;const i=MARKDOWN_EXTS.has(e.ext)&&this._filePreviewPref("mdRendered");if(i){const n=document.createElement("template");n.innerHTML=`<div class="rv-text file-preview-md" data-i18n-skip>${this._renderMarkdown(this.filePreviewContent,{breaks:!1})}</div>`;const o=n.content.firstElementChild;this._rebaseFilePreviewMarkdownRefs(o,e),this._linkifyFilePaths(o);for(const l of o.querySelectorAll("a.rv-path:not([data-session-id])"))l.dataset.sessionId=e.sessionId;t.replaceChildren(n.content),this._bindResponseViewerInteractions(t)}else{const n=document.createElement("pre");n.className="file-preview-text",n.classList.toggle("wrap",this._filePreviewPref("wrap")),n.classList.toggle("show-lines",this._filePreviewPref("lineNumbers"));const o=document.createElement("code");o.innerHTML=this.filePreviewContent.split(`
245
+ `}).join("")}n.querySelectorAll(".file-tree-item").forEach(a=>{a.addEventListener("click",()=>{const r=a.dataset.path;a.dataset.type==="directory"?this._openFileBrowserSearchDirectory({...o,path:r}):this.openFilePreview(r,t)})});const l=this.$("fileBrowserStatus");if(l){const a=s.matchCount===void 0?e.length:s.matchCount;l.textContent=`${a} ${a===1?"match":"matches"}${s.truncated?" (truncated)":""}`}},_findFileBrowserDirectory(e,t,s=[]){if(!Array.isArray(e))return null;for(const n of e){if(!n||typeof n!="object")continue;if(n.type==="directory"&&n.path===t)return{target:n,ancestors:[...s]};if(n.type!=="directory"||!Array.isArray(n.children))continue;const i=this._findFileBrowserDirectory(n.children,t,[...s,n.path]);if(i)return i}return null},_isFileBrowserDirectoryContextCurrent(e){const t=this._ensureFileBrowserState(),s=this.$?.("fileBrowserSearch"),n=typeof s?.value=="string"?s.value:t.filter;return e&&t.ownerSessionId===e.ownerSessionId&&this.activeSessionId===e.ownerSessionId&&t.treeEpoch===e.treeEpoch&&t.searchEpoch===e.searchEpoch&&this.fileBrowserShowHidden===!0===e.showHidden&&t.filter===e.rawInput&&n===e.rawInput&&n.trim()===e.query&&t.view===e.view&&this.$?.("fileBrowserPanel")?.classList.contains("visible")===!0},_promptFileBrowserDirectoryReload(){this.showToast?.("Reload files before opening this folder","info")},_openFileBrowserSearchDirectory(e){if(!this._isFileBrowserDirectoryContextCurrent(e))return;const t=this._ensureFileBrowserState(),s=t.normalState;if(!this._isFileBrowserNormalCompatible(s,e.ownerSessionId,e.showHidden,e.treeEpoch)){t.deferredDirectoryTarget=null,this._promptFileBrowserDirectoryReload();return}if(s.phase==="loading"){t.deferredDirectoryTarget={...e};return}if(t.deferredDirectoryTarget=null,s.phase!=="ready"){this._promptFileBrowserDirectoryReload();return}const n=this._findFileBrowserDirectory(s.data?.tree,e.path);if(!n){this._promptFileBrowserDirectoryReload();return}this._leaveFileBrowserSearchForDirectory([...n.ancestors,n.target.path],s)},_completeDeferredFileBrowserDirectory(e){const t=this._ensureFileBrowserState(),s=t.deferredDirectoryTarget;if(!s)return!1;if(!this._isFileBrowserDirectoryContextCurrent(s))return t.deferredDirectoryTarget===s&&(t.deferredDirectoryTarget=null),!1;if(!this._isFileBrowserNormalCompatible(e,s.ownerSessionId,s.showHidden,s.treeEpoch)||e.phase!=="ready"&&e.phase!=="error")return!1;if(t.deferredDirectoryTarget=null,e.phase==="error")return this._promptFileBrowserDirectoryReload(),!1;const n=this._findFileBrowserDirectory(e.data?.tree,s.path);return n?(this._leaveFileBrowserSearchForDirectory([...n.ancestors,n.target.path],e),!0):(this._promptFileBrowserDirectoryReload(),!1)},_leaveFileBrowserSearchForDirectory(e,t){const s=this._ensureFileBrowserState();s.inFlight?.timer!==void 0&&s.inFlight?.timer!==null&&clearTimeout(s.inFlight.timer),s.searchEpoch++,s.inFlight=null,s.filter="",s.matches=[],s.deferredDirectoryTarget=null,s.view="normal",this.fileBrowserFilter="";const n=this.$?.("fileBrowserSearch");n&&(n.value=""),this._syncFileBrowserExpandBtn();for(const i of e)typeof i=="string"&&this.fileBrowserExpandedDirs?.add?.(i);this.fileBrowserData=t.data,this._renderFileBrowserNormalState(t)},expandAllDirectories(e){for(const t of e)t.type==="directory"&&(this.fileBrowserExpandedDirs.add(t.path),t.children&&this.expandAllDirectories(t.children))},collapseAllDirectories(){this.fileBrowserExpandedDirs.clear()},toggleFileBrowserExpand(){if(this._hasFileBrowserQuery()){this._syncFileBrowserExpandBtn();return}this.fileBrowserAllExpanded=!this.fileBrowserAllExpanded;const e=this.$("fileBrowserExpandBtn");this.fileBrowserAllExpanded?(this.expandAllDirectories(this.fileBrowserData?.tree||[]),e&&(e.innerHTML="\u229F")):(this.collapseAllDirectories(),e&&(e.innerHTML="\u229E")),this.renderFileBrowserTree()},refreshFileBrowser(){const e=this._ensureFileBrowserState();e.inFlight?.timer!==void 0&&e.inFlight?.timer!==null&&clearTimeout(e.inFlight.timer),e.inFlight=null,e.searchEpoch++,e.filter="",e.matches=[],e.deferredDirectoryTarget=null,e.view="normal",this.fileBrowserFilter="",this.fileBrowserExpandedDirs.clear(),this.fileBrowserAllExpanded=!1;const t=this.$("fileBrowserExpandBtn");t&&(t.innerHTML="\u229E");const s=this.$("fileBrowserSearch");s&&(s.value=""),this._syncFileBrowserExpandBtn();const n=e.ownerSessionId||this.activeSessionId;if(!(!n||this.activeSessionId!==n))return this.loadFileBrowser(n,{force:!0})},toggleFileBrowserButton(){const t=this.$("fileBrowserPanel")?.classList.contains("visible"),s=document.querySelector(".btn-file-viewer");if(t){this.closeFileBrowserPanel(),s&&s.setAttribute("aria-expanded","false");return}if(!this.activeSessionId){this.showToast("Open a session to browse its files","info");return}const n=this.loadAppSettingsFromStorage();n.showFileBrowser=!0,this.saveAppSettingsToStorage(n);const i=document.getElementById("appSettingsShowFileBrowser");i&&(i.checked=!0),this.applyMonitorVisibility(),s&&s.setAttribute("aria-expanded","true")},closeFileBrowserPanel(){const e=this.$("fileBrowserPanel");if(this._resetFileBrowserForHide(),e&&(e.classList.remove("visible"),e.style.left="",e.style.top="",e.style.bottom="",e.style.right=""),this.fileBrowserDragListeners){const i=this.fileBrowserDragListeners;document.removeEventListener("mousemove",i.move),document.removeEventListener("mouseup",i.up),document.removeEventListener("touchmove",i.touchMove),document.removeEventListener("touchend",i.up),document.removeEventListener("touchcancel",i.up),i.handle&&(i.handle.removeEventListener("mousedown",i.handleMouseDown),i.handle.removeEventListener("touchstart",i.handleTouchStart),i._onFirstDrag&&(i.handle.removeEventListener("mousedown",i._onFirstDrag),i.handle.removeEventListener("touchstart",i._onFirstDrag))),this.fileBrowserDragListeners=null}const t=this.loadAppSettingsFromStorage();t.showFileBrowser=!1,this.saveAppSettingsToStorage(t);const s=document.getElementById("appSettingsShowFileBrowser");s&&(s.checked=!1);const n=document.querySelector(".btn-file-viewer");n&&n.setAttribute("aria-expanded","false")},_isExternalPreviewPath(e,t){if(typeof e=="string"&&e.startsWith("~/"))return!0;if(typeof e!="string"||!e.startsWith("/"))return!1;const s=this.sessions.get(t)?.workingDir;if(!s)return!1;const n=s.endsWith("/")?s:`${s}/`;return e!==s&&!e.startsWith(n)},async _registerExternalPreview(e,t){try{const s=await fetch(`/api/sessions/${t}/attachments`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e,notify:!1})}),n=await s.json().catch(()=>null);if(s.ok&&n?.success&&n.data?.attachmentId)return{attachmentId:n.data.attachmentId,size:n.data.size||0};const i=n?.error||`Cannot open this file (HTTP ${s.status})`;return/unsupported/i.test(i)?{error:`Cannot preview .${(e.split(".").pop()||"").toLowerCase()} from outside the session workspace (images, video, audio, PDF, Office documents and text files only).`}:{error:i}}catch(s){return{error:s.message||"Cannot open this file"}}},async openFilePreview(e,t=this.activeSessionId,s=null,n={}){if(!t||!e)return;const i=n.folderFile||null;!i&&this.folderGrid&&(this.folderGrid.index=null),this._updateFolderPreviewNav(i?null:this._previewFolderPath(e,t,s));const o=this.$("filePreviewOverlay"),l=this.$("filePreviewTitle"),a=this.$("filePreviewBody"),r=this.$("filePreviewFooter");if(!o||!a)return;this._recordFilePreviewHistory(e,t,s,n),this._bindFilePreviewChrome();const c=this._filePreviewLoad=(this._filePreviewLoad||0)+1,h=()=>c!==this._filePreviewLoad;this._resetFilePreviewEdit(),this._stopFilePreviewMedia(),this.filePreviewDetachUrl="";const d=this.$("filePreviewDetachBtn");d&&(d.hidden=!0),this.filePreviewText=null,this.filePreviewPage=null,this.filePreviewPageRefused=!1,this._updateFilePreviewToolbar("none"),o.classList.add("visible"),this._applyFilePreviewExpanded(),l.textContent=e,a.innerHTML='<div class="binary-message">Loading...</div>',r.textContent="";const u=(e.split(".").pop()||"").toLowerCase();if(!s&&rendersAsPage(e)&&this._filePreviewPref("htmlRendered")){const g=await this._mintHtmlViewUrl(e,t);if(g){r.textContent="HTML",this.filePreviewPage={filePath:e,sessionId:t},this.filePreviewDetachUrl=g,d&&(d.hidden=!1),a.innerHTML=`<iframe src="${escapeHtml(g)}" title="${escapeHtml(e)}" sandbox="allow-scripts allow-forms allow-popups allow-modals allow-downloads"></iframe>`,this._updateFilePreviewToolbar("page");return}this.filePreviewPageRefused=!0}let p="",f=0;if(!s&&!i&&this._isExternalPreviewPath(e,t)){const g=await this._registerExternalPreview(e,t);if(h())return;s=g.attachmentId||null,p=g.error||"",f=g.size||0}if(!s&&p){r.textContent="",a.innerHTML=`<div class="binary-message">${escapeHtml(p)}</div>`;return}const w=u==="docx"||u==="pptx",y=s?`/api/sessions/${t}/attachments/${encodeURIComponent(s)}`:i?`/api/sessions/${t}/folders/${encodeURIComponent(i.folderId)}/files/${encodeURIComponent(i.name)}`:null;if(this.filePreviewDetachUrl=CodemanBase.url(y?`${y}/${w?"preview":"raw"}`:w?`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`),d&&(d.hidden=!1),y){const g=CodemanBase.url(y),C=new Set(["png","jpg","jpeg","gif","webp","bmp","svg"]),m=new Set(["mp4","webm","mov","m4v","ogv"]),S=new Set(["mp3","wav","ogg","oga","m4a","aac","flac","opus"]);if(i&&!f&&(f=n.size||0),r.textContent=f?`${this.formatFileSize(f)} \u2022 ${u}`:u.toUpperCase(),C.has(u))a.innerHTML=`<img src="${escapeHtml(`${g}/raw`)}" alt="${escapeHtml(e)}">`;else if(m.has(u))a.innerHTML=`<video src="${escapeHtml(`${g}/raw`)}" controls autoplay playsinline preload="metadata"></video>`;else if(S.has(u))a.innerHTML=`<audio src="${escapeHtml(`${g}/raw`)}" controls autoplay preload="metadata"></audio>`;else if(u==="pdf")a.innerHTML=`<iframe src="${escapeHtml(`${g}/raw`)}" title="${escapeHtml(e)}"></iframe>`;else if(u==="docx"||u==="pptx")a.innerHTML=`<iframe src="${escapeHtml(`${g}/preview`)}" title="${escapeHtml(e)}"></iframe>`;else if(u==="xlsx")this._openSpreadsheetPreview(a,`${g}/raw`,f);else try{const $=await fetch(`${g}/raw`,{headers:{Range:"bytes=0-524287"}});if(!$.ok)throw new Error("Failed to load attachment");const b=await $.text();if(h())return;const T=$.status===206&&b.length>=524288,E=b.split(`
246
+ `),I=MARKDOWN_EXTS.has(u)?1/0:500,P=E.length>I,B=P?E.slice(0,I).join(`
247
+ `):b;if(this.filePreviewContent=B,this.filePreviewText={ext:u,sessionId:t,filePath:e,attachmentId:s||i?.folderId},this._renderFilePreviewText(),P||T){const x=P?`showing first ${I} lines`:"showing the start of the file";r.textContent=`${r.textContent} (${x})`}}catch($){if(h())return;a.innerHTML=`<div class="binary-message">Error: ${escapeHtml($.message)}</div>`}return}if(u==="docx"||u==="pptx"){r.textContent=u.toUpperCase();const g=CodemanBase.url(`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`);a.innerHTML=`<iframe src="${escapeHtml(g)}" title="${escapeHtml(e)}"></iframe>`;return}if(u==="pdf"){r.textContent="PDF";const g=CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);a.innerHTML=`<iframe src="${escapeHtml(g)}" title="${escapeHtml(e)}"></iframe>`;return}if(u==="svg"){r.textContent="SVG";try{const g=await fetch(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);if(!g.ok)throw new Error("Failed to load image");const C=await g.text();if(h())return;const m=URL.createObjectURL(new Blob([C],{type:"image/svg+xml"}));a.innerHTML=`<img src="${m}" alt="${escapeHtml(e)}">`;const S=a.querySelector("img");S&&(S.onload=()=>URL.revokeObjectURL(m))}catch(g){if(h())return;a.innerHTML=`<div class="binary-message">Error: ${escapeHtml(g.message)}</div>`}return}const v=MARKDOWN_EXTS.has(u)?1e4:500;try{const g=await fetch(`/api/sessions/${t}/file-content?path=${encodeURIComponent(e)}&lines=${v}`);if(!g.ok)throw new Error("Failed to load file");const C=await g.json();if(h())return;if(!C.success)throw new Error(C.error||"Failed to load file");const m=C.data;if(m.type==="image")a.innerHTML=`<img src="${escapeHtml(CodemanBase.url(m.url))}" alt="${escapeHtml(e)}">`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="video")a.innerHTML=`<video src="${escapeHtml(CodemanBase.url(m.url))}" controls autoplay playsinline preload="metadata"></video>`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="audio")a.innerHTML=`<audio src="${escapeHtml(CodemanBase.url(m.url))}" controls autoplay preload="metadata"></audio>`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="spreadsheet")this._openSpreadsheetPreview(a,CodemanBase.url(m.url),m.size),r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="binary"){const S=CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}&download=true`);a.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(m.size)})<br>Cannot preview<br><a href="${escapeHtml(S)}" download>Download</a></div>`,r.textContent=m.extension||"binary"}else{this.filePreviewContent=m.content,this.filePreviewText={ext:u,sessionId:t,filePath:e},this._renderFilePreviewText();const S=m.truncated?` (showing ${v}/${m.totalLines} lines)`:"";if(r.textContent=`${m.totalLines} lines \u2022 ${this.formatFileSize(m.size)}${S}`,m.editable){this.filePreviewEditTarget={sessionId:t,filePath:e};const $=this.$("filePreviewEditBtn");$&&($.hidden=!1)}}}catch(g){if(h())return;console.error("Failed to preview file:",g),a.innerHTML=`<div class="binary-message">Error: ${escapeHtml(g.message)}</div>`}},async openFolderGrid(e,t=this.activeSessionId){if(!t||!e)return;const s=this.$("folderGridOverlay"),n=this.$("folderGridBody");if(!s||!n)return;this._bindFolderGridKeys();const i=this._folderGridLoad=(this._folderGridLoad||0)+1;let o=null,l=0;try{const a=await fetch(`/api/sessions/${t}/folders`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})});l=a.status,o=await a.json().catch(()=>null)}catch(a){if(i!==this._folderGridLoad)return;this.showToast(`Cannot open folder: ${a.message||a}`,"error");return}if(i===this._folderGridLoad){if(!o?.success||!o.data){const a=o?.error||`HTTP ${l}`;if(l===400&&/not a folder/i.test(a)){this.openFilePreview(e,t);return}this.showToast(`Cannot open folder ${e}: ${a}`,"error");return}this.folderGrid={sessionId:t,...o.data,index:null},this._renderFolderGrid(),s.classList.add("visible"),n.scrollTop=0}},closeFolderGrid(){this._folderGridLoad=(this._folderGridLoad||0)+1,this.$("folderGridOverlay")?.classList.remove("visible");const e=this.$("folderGridBody");e&&(e.innerHTML=""),this.folderGrid=null,this._updateFolderPreviewNav(null)},folderGridUp(){const e=this.folderGrid;!e||e.path==="/"||this.openFolderGrid(e.path.slice(0,e.path.lastIndexOf("/"))||"/",e.sessionId)},_renderFolderGrid(){const e=this.folderGrid;if(!e)return;const t=this.$("folderGridTitle"),s=this.$("folderGridFolders"),n=this.$("folderGridBody"),i=this.$("folderGridFooter");t.textContent=e.path,t.title=e.path;const o=this.$("folderGridUpBtn");o&&(o.disabled=e.path==="/"),s.innerHTML="";for(const r of e.folders){const c=document.createElement("button");c.type="button",c.className="folder-grid-chip",c.textContent=`${r}/`,c.onclick=()=>this.openFolderGrid(`${e.path==="/"?"":e.path}/${r}`,e.sessionId),s.appendChild(c)}if(n.innerHTML="",e.files.length===0){const r=document.createElement("div");r.className="folder-grid-empty",r.textContent="No previewable files in this folder.",n.appendChild(r)}e.files.forEach((r,c)=>{const h=document.createElement("button");h.type="button",h.className="folder-grid-tile",h.title=`${r.name} \u2022 ${this.formatFileSize(r.size)}`,h.dataset.index=String(c);const d=document.createElement("div");d.className="folder-grid-thumb";const u=r.extension.toUpperCase(),p=this._folderFileUrl(e,r.name,""),f=r.attachmentType==="image"?`${p}/raw`:["pdf","docx","pptx"].includes(r.extension)?`${p}/thumbnail`:null;if(f){const y=document.createElement("img");y.loading="lazy",y.decoding="async",y.alt=r.name,y.src=f,y.onerror=()=>{d.textContent=u},d.appendChild(y)}else d.textContent=u;const w=document.createElement("span");w.className="folder-grid-name",w.textContent=r.name,h.append(d,w),h.onclick=()=>this._openFolderGridFile(c),n.appendChild(h)});const l=`${e.files.length} file${e.files.length===1?"":"s"}`,a=e.folders.length?` \u2022 ${e.folders.length} folder${e.folders.length===1?"":"s"}`:"";i.textContent=`${l}${a}${e.truncated?" (folder too large \u2014 showing the first entries)":""}`},_folderFileUrl(e,t,s){return CodemanBase.url(`/api/sessions/${e.sessionId}/folders/${encodeURIComponent(e.folderId)}/files/${encodeURIComponent(t)}${s}`)},_openFolderGridFile(e){const t=this.folderGrid,s=t?.files[e];if(!s)return;const n=this.$("folderGridBody");n?.querySelectorAll(".folder-grid-tile.current").forEach(o=>o.classList.remove("current"));const i=n?.querySelector(`.folder-grid-tile[data-index="${e}"]`);i?.classList.add("current"),i?.scrollIntoView({block:"nearest"}),this.openFilePreview(`${t.path==="/"?"":t.path}/${s.name}`,t.sessionId,null,{folderFile:{folderId:t.folderId,name:s.name},size:s.size}),t.index=e,t.lastIndex=e,this._updateFolderPreviewNav(null)},stepFolderPreview(e){const t=this.folderGrid;if(!t||t.index===null||t.files.length===0||this.filePreviewEdit?.dirty&&!confirm("Discard unsaved changes?"))return;const s=(t.index+e+t.files.length)%t.files.length;this._openFolderGridFile(s)},_recordFilePreviewHistory(e,t,s,n){const i=this.filePreviewHistory=this.filePreviewHistory||{entries:[],index:-1};if(!this._filePreviewHistoryStepping){const o=i.entries[i.index];o&&o.filePath===e&&o.sessionId===t&&(o.attachmentId||null)===(s||null)||(i.entries.length=i.index+1,i.entries.push({filePath:e,sessionId:t,attachmentId:s||null,options:n}),i.entries.length>FILE_PREVIEW_HISTORY_MAX&&i.entries.shift(),i.index=i.entries.length-1)}this._updateFilePreviewHistoryNav()},stepFilePreviewHistory(e){const t=this.filePreviewHistory;if(!t)return;const s=t.index+e;if(s<0||s>=t.entries.length||this.filePreviewEdit?.dirty&&!confirm("Discard unsaved changes?"))return;t.index=s;const n=t.entries[s];this._filePreviewHistoryStepping=!0;try{const i=n.options?.folderFile;if(i&&i.folderId===this.folderGrid?.folderId){const o=this.folderGrid.files.findIndex(l=>l.name===i.name);if(o!==-1)return this._openFolderGridFile(o)}return this.openFilePreview(n.filePath,n.sessionId,n.attachmentId,n.options||{})}finally{this._filePreviewHistoryStepping=!1}},_updateFilePreviewHistoryNav(){const e=this.filePreviewHistory,t=!!e&&e.entries.length>1,s=this.$("filePreviewBackBtn"),n=this.$("filePreviewForwardBtn");s&&(s.hidden=!t,s.disabled=!t||e.index<=0),n&&(n.hidden=!t,n.disabled=!t||e.index>=e.entries.length-1)},toggleFilePreviewExpanded(){this._setFilePreviewPref("expanded",!this._filePreviewPref("expanded")),this._applyFilePreviewExpanded()},_applyFilePreviewExpanded(){const e=this._filePreviewPref("expanded");this.$("filePreviewOverlay")?.querySelector?.(".file-preview-window")?.classList?.toggle("expanded",e),this.$("filePreviewExpandBtn")?.setAttribute("aria-pressed",e?"true":"false")},_bindFilePreviewChrome(){this._filePreviewChromeBound||(this._filePreviewChromeBound=!0,document.addEventListener("keydown",e=>{if(!e.altKey||e.ctrlKey||e.metaKey||e.shiftKey||e.key!=="ArrowLeft"&&e.key!=="ArrowRight"||!this.$("filePreviewOverlay")?.classList.contains("visible"))return;const t=e.target;if(t&&(t.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName)&&!t.classList?.contains("xterm-helper-textarea")))return;e.preventDefault(),e.stopPropagation();const s=this.filePreviewHistory,n=e.key==="ArrowLeft"?-1:1;!s||s.index+n<0||s.index+n>=s.entries.length||this.stepFilePreviewHistory(n)},!0),this._bindFilePreviewResize())},_bindFilePreviewResize(){const e=this.$("filePreviewResize"),t=e?.parentElement;!e||!t||e.addEventListener("pointerdown",s=>{if(s.button!==0)return;s.preventDefault();const n=s.clientX,i=s.clientY,o=t.offsetWidth,l=t.offsetHeight;e.setPointerCapture?.(s.pointerId);const a=c=>{const h=Math.max(320,Math.min(window.innerWidth*.96,o+2*(c.clientX-n))),d=Math.max(240,Math.min(window.innerHeight*.94,l+2*(c.clientY-i)));t.style.width=`${Math.round(h)}px`,t.style.height=`${Math.round(d)}px`},r=()=>{e.removeEventListener("pointermove",a),e.removeEventListener("pointerup",r),e.removeEventListener("pointercancel",r)};e.addEventListener("pointermove",a),e.addEventListener("pointerup",r),e.addEventListener("pointercancel",r)})},openFolderOfPreview(){const e=this.filePreviewFolderTarget;e&&(this.closeFilePreview(),this.openFolderGrid(e.dir,e.sessionId))},_previewFolderPath(e,t,s){if(typeof e!="string"||s&&!e.includes("/"))return null;const n=this.sessions?.get?.(t)?.workingDir,i=typeof resolveLinkedFilePath=="function"?resolveLinkedFilePath(e,n):e;if(!i.startsWith("/")&&!i.startsWith("~/"))return null;const o=i.lastIndexOf("/");return{dir:i.slice(0,o)||"/",sessionId:t}},_updateFolderPreviewNav(e){const t=!!this.folderGrid&&this.folderGrid.index!==null&&this.folderGrid.files.length>1,s=this.$("filePreviewPrevBtn"),n=this.$("filePreviewNextBtn");s&&(s.hidden=!t),n&&(n.hidden=!t),e!==void 0&&(this.filePreviewFolderTarget=e);const i=!!this.folderGrid&&this.folderGrid.index!==null,o=this.$("filePreviewFolderBtn");o&&(o.hidden=i||!this.filePreviewFolderTarget)},_bindFolderGridKeys(){this._folderGridKeysBound||(this._folderGridKeysBound=!0,document.addEventListener("keydown",e=>{const t=this.folderGrid;if(!t||e.altKey||e.ctrlKey||e.metaKey)return;const s=this.$("filePreviewOverlay")?.classList.contains("visible");if(!this.$("folderGridOverlay")?.classList.contains("visible"))return;const i=e.target;if(i&&(i.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(i.tagName)&&!i.classList?.contains("xterm-helper-textarea"))||this.filePreviewEdit)return;let l=!0;s&&t.index!==null&&e.key==="ArrowLeft"?this.stepFolderPreview(-1):s&&t.index!==null&&e.key==="ArrowRight"?this.stepFolderPreview(1):!s&&(e.key==="ArrowLeft"||e.key==="ArrowRight")&&t.files.length?this._openFolderGridFile(t.lastIndex??0):e.key==="Escape"?s?this.closeFilePreview():this.closeFolderGrid():l=!1,l&&(e.preventDefault(),e.stopPropagation())},!0))},closeFilePreview(){if(this.filePreviewEdit?.dirty&&!confirm("Discard unsaved changes?"))return;this._resetFilePreviewEdit(),this.folderGrid&&(this.folderGrid.index=null),this._updateFolderPreviewNav(null),this.filePreviewHistory=null,this._updateFilePreviewHistoryNav();const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this._stopFilePreviewMedia(),this.filePreviewContent="",this.filePreviewText=null,this._updateFilePreviewToolbar("none"),this.filePreviewDetachUrl="";const t=this.$("filePreviewDetachBtn");t&&(t.hidden=!0)},detachFilePreview(){if(!this.filePreviewDetachUrl)return;const e=this.openInHostWindow?.(this.filePreviewDetachUrl)??null;if(e!==null){e?this.closeFilePreview():this.showToast("Could not open a new window for this preview","error");return}const t=window.open(this.filePreviewDetachUrl,"_blank");if(!t){this.showToast("Pop-up blocked: allow pop-ups for this site to detach previews","error");return}t.opener=null,this.closeFilePreview()},_stopFilePreviewMedia(){this._disposeSpreadsheetPreview();const e=this.$("filePreviewBody");if(e){for(const t of e.querySelectorAll("video, audio"))try{t.pause(),t.removeAttribute("src"),t.load()}catch(s){console.warn("Failed to stop preview media:",s)}e.innerHTML=""}},_openSpreadsheetPreview(e,t,s){this._disposeSpreadsheetPreview();const n=window.CodemanSpreadsheetPreview;if(!n?.open){e.innerHTML='<div class="binary-message">Spreadsheet preview is unavailable.</div>';return}e.textContent="";const i={};this._spreadsheetPreviewToken=i,this._spreadsheetPreview=n.open({container:e,url:t,size:s,isCurrent:()=>this._spreadsheetPreviewToken===i})},_disposeSpreadsheetPreview(){const e=this._spreadsheetPreview;this._spreadsheetPreview=null,this._spreadsheetPreviewToken=null;try{e?.dispose()}catch(t){console.warn("Failed to dispose spreadsheet preview:",t)}},_filePreviewPref(e){try{const t=localStorage.getItem(FILE_PREVIEW_PREF_KEYS[e]);if(t==="1")return!0;if(t==="0")return!1}catch{}return FILE_PREVIEW_PREF_DEFAULTS[e]},_setFilePreviewPref(e,t){try{localStorage.setItem(FILE_PREVIEW_PREF_KEYS[e],t?"1":"0")}catch{}},_renderFilePreviewText(){const e=this.filePreviewText,t=this.$("filePreviewBody");if(!e||!t)return;const n=MARKDOWN_EXTS.has(e.ext)&&this._filePreviewPref("mdRendered");if(n){const i=document.createElement("template");i.innerHTML=`<div class="rv-text file-preview-md" data-i18n-skip>${this._renderMarkdown(this.filePreviewContent,{breaks:!1})}</div>`;const o=i.content.firstElementChild;this._rebaseFilePreviewMarkdownRefs(o,e),this._linkifyFilePaths(o);for(const l of o.querySelectorAll("a.rv-path:not([data-session-id])"))l.dataset.sessionId=e.sessionId;t.replaceChildren(i.content),this._bindResponseViewerInteractions(t)}else{const i=document.createElement("pre");i.className="file-preview-text",i.classList.toggle("wrap",this._filePreviewPref("wrap")),i.classList.toggle("show-lines",this._filePreviewPref("lineNumbers"));const o=document.createElement("code");o.innerHTML=this.filePreviewContent.split(`
242
248
  `).map(l=>`<span class="fp-line">${escapeHtml(l)}</span>`).join(`
243
- `),n.appendChild(o),t.replaceChildren(n)}this._updateFilePreviewToolbar(i?"markdown":"text")},_rebaseFilePreviewMarkdownRefs(e,{sessionId:t,filePath:s,attachmentId:i}){const n=s.includes("/")?s.slice(0,s.lastIndexOf("/")+1):"",o=!!i&&!s.startsWith("/"),l=r=>!!r&&!/^[a-z][a-z0-9+.-]*:/i.test(r)&&!r.startsWith("//")&&!r.startsWith("#"),a=r=>{let c=r.split("#")[0].split("?")[0];try{c=decodeURIComponent(c)}catch{}const h=[];for(const d of(c.startsWith("/")?c.slice(1):n+c).split("/"))d==="."||d===""&&h.length||(d===".."&&h.length&&h[h.length-1]!==".."&&h[h.length-1]!==""?h.pop():h.push(d));return h.join("/")};for(const r of e.querySelectorAll("img[src]")){const c=r.getAttribute("src")||"";if(o&&l(c)){r.replaceWith(r.getAttribute("alt")||c);continue}if(l(c)){const h=a(c);r.setAttribute("src",CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(h)}`))}r.addEventListener("error",()=>r.replaceWith(r.getAttribute("alt")||c),{once:!0})}for(const r of e.querySelectorAll("a[href]")){const c=r.getAttribute("href")||"";if(l(c)){if(o){r.replaceWith(...r.childNodes);continue}r.className="rv-path",r.dataset.path=a(c),r.dataset.sessionId=t,r.setAttribute("href","#"),r.removeAttribute("target"),r.removeAttribute("rel")}}},_updateFilePreviewToolbar(e){const t=(o,l,a)=>{const r=this.$(o);r&&(r.hidden=!l,l&&r.setAttribute("aria-pressed",String(a)))},s=e!=="none"&&MARKDOWN_EXTS.has(this.filePreviewText?.ext||"");t("filePreviewMdBtn",s,e==="markdown");const i=this.filePreviewText,n=e==="text"&&!this.filePreviewPageRefused&&rendersAsPage(i?.filePath)&&(!i.attachmentId||i.filePath.startsWith("/"));t("filePreviewPageBtn",e==="page"||n,e==="page"),t("filePreviewLinesBtn",e==="text",this._filePreviewPref("lineNumbers")),t("filePreviewWrapBtn",e==="text",this._filePreviewPref("wrap"))},async _mintHtmlViewUrl(e,t){try{const s=await fetch(`/api/sessions/${t}/html-view`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})}),i=await s.json().catch(()=>({}));return s.ok&&i.success?CodemanBase.url(i.data.url):null}catch{return null}},toggleFilePreviewPage(){const e=this.filePreviewPage||this.filePreviewText;if(e)return this._setFilePreviewPref("htmlRendered",!this._filePreviewPref("htmlRendered")),this.openFilePreview(e.filePath,e.sessionId)},toggleFilePreviewMd(){this._setFilePreviewPref("mdRendered",!this._filePreviewPref("mdRendered")),this._renderFilePreviewText()},toggleFilePreviewLines(){this._toggleFilePreviewTextClass("lineNumbers","show-lines")},toggleFilePreviewWrap(){this._toggleFilePreviewTextClass("wrap","wrap")},_toggleFilePreviewTextClass(e,t){const s=!this._filePreviewPref(e);this._setFilePreviewPref(e,s);const i=this.$("filePreviewBody")?.querySelector(":scope > pre.file-preview-text");i&&i.classList.toggle(t,s),this._updateFilePreviewToolbar("text")},_resetFilePreviewEdit(){this.filePreviewEdit=null,this.filePreviewEditTarget=null;const e=this.$("filePreviewEditBtn");e&&(e.hidden=!0);const t=this.$("filePreviewEditBar");t&&(t.hidden=!0);const s=this.$("filePreviewDirty");s&&(s.hidden=!0);const i=this.$("filePreviewSaveBtn");i&&(i.disabled=!0,i.textContent="Save")},async enterFilePreviewEdit(){const e=this.filePreviewEditTarget;if(!e||this.filePreviewEdit)return;const t=this.$("filePreviewBody"),s=this.$("filePreviewFooter");if(!t)return;let i;try{const a=await fetch(`/api/sessions/${e.sessionId}/file-content?path=${encodeURIComponent(e.filePath)}&edit=1`),r=await a.json().catch(()=>null);if(!r||r.success!==!0)throw new Error(r?.error||`Failed to load file for editing (HTTP ${a.status})`);i=r.data}catch(a){this.showToast(a.message,"error");return}this.filePreviewEdit={sessionId:e.sessionId,filePath:e.filePath,baseHash:i.hash,eol:i.eol,original:i.content,dirty:!1,saving:!1};const n=document.createElement("textarea");n.className="file-preview-editor",n.spellcheck=!1,n.setAttribute("autocapitalize","off"),n.setAttribute("autocorrect","off"),n.setAttribute("autocomplete","off"),n.wrap="off",n.value=i.content,n.addEventListener("input",()=>this._onFilePreviewEditInput()),t.innerHTML="",t.appendChild(n),this._updateFilePreviewToolbar("none");const o=this.$("filePreviewEditBtn");o&&(o.hidden=!0);const l=this.$("filePreviewEditBar");if(l&&(l.hidden=!1),s){const a=i.eol==="crlf"?" \u2022 CRLF":"";s.textContent=`Editing \u2022 ${i.totalLines} lines \u2022 ${this.formatFileSize(i.size)}${a}`}},_onFilePreviewEditInput(){const e=this.filePreviewEdit;if(!e)return;const t=this.$("filePreviewBody")?.querySelector("textarea.file-preview-editor");if(!t)return;e.dirty=t.value!==e.original;const s=this.$("filePreviewDirty");s&&(s.hidden=!e.dirty);const i=this.$("filePreviewSaveBtn");i&&(i.disabled=!e.dirty||e.saving)},cancelFilePreviewEdit(){const e=this.filePreviewEdit;if(!e||e.dirty&&!confirm("Discard unsaved changes?"))return;const{sessionId:t,filePath:s}=e;this._resetFilePreviewEdit(),this.openFilePreview(s,t)},async saveFilePreviewEdit(e=!1){const t=this.filePreviewEdit;if(!t||t.saving)return;const s=this.$("filePreviewBody")?.querySelector("textarea.file-preview-editor");if(!s)return;t.saving=!0;const i=this.$("filePreviewSaveBtn");i&&(i.disabled=!0,i.textContent="Saving\u2026");const n=()=>{t.saving=!1,i&&(i.textContent="Save"),this._onFilePreviewEditInput()};let o=null,l=0;try{const c=await fetch(`/api/sessions/${t.sessionId}/file-content`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t.filePath,content:s.value,baseHash:t.baseHash,eol:t.eol??void 0,force:e||void 0})});l=c.status,o=await c.json().catch(()=>null)}catch(c){n(),this.showToast(`Save failed: ${c.message}`,"error");return}if(l===409||o?.errorCode==="CONFLICT"){n(),confirm(`File changed on disk since you loaded it.
244
- OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFilePreviewEdit(!0);return}if(!o||o.success!==!0){n(),this.showToast(`Save failed: ${o?.error||`HTTP ${l}`}`,"error");return}const{sessionId:a,filePath:r}=t;this._resetFilePreviewEdit(),this.showToast("Saved","success"),this.openFilePreview(r,a)},_onAttachmentDetected(e){if(console.log("[Attachment Detected]",e),this.addAttachmentCard(e),e.sessionId){const t=this.attachmentHistoryCounts.get(e.sessionId)??this.sessions.get(e.sessionId)?.attachmentHistory?.length??0;this.attachmentHistoryCounts.set(e.sessionId,Math.min(t+1,100)),e.sessionId===this.activeSessionId&&(this.updateAttachmentHistoryBadge(),this.attachmentHistoryDrawerOpen&&this._debouncedCall("attachmentHistoryRefresh",()=>{this.attachmentHistoryDrawerOpen&&this.activeSessionId===e.sessionId&&this.loadAttachmentHistory(e.sessionId)},250))}},ensureAttachmentCardStack(){let e=this.attachmentCardStack||document.getElementById("attachmentCardStack");return e||(e=document.createElement("div"),e.id="attachmentCardStack",e.className="attachment-card-stack",document.body.appendChild(e)),this.attachmentCardStack=e,e},openAttachmentInNewTab(e,t,s=null){const i=CodemanBase.url(s?`/api/sessions/${e}/attachments/${encodeURIComponent(s)}/raw`:`/api/sessions/${e}/file-raw?path=${encodeURIComponent(t)}`);window.open(i,"_blank")},addAttachmentCard(e){const{sessionId:t,relativePath:s,fileName:i,timestamp:n,size:o,attachmentType:l,extension:a,attachmentId:r,rawUrl:c,previewUrl:h,thumbnailUrl:d}=e,u=s||i,p=r||`${t}-${n}-${i}`;if(this.attachmentCards.has(p)){this.attachmentCards.get(p).element.focus?.();return}if(this.attachmentCards.size>=10){const E=this.attachmentCards.keys().next().value;E&&this.closeAttachmentCard(E)}const w=this.ensureAttachmentCardStack(),v=this.sessions.get(t)?.name||t.substring(0,8),g=CodemanBase.url(c||(r?`/api/sessions/${t}/attachments/${encodeURIComponent(r)}/raw`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(u)}`)),T=CodemanBase.url(h||(r?`/api/sessions/${t}/attachments/${encodeURIComponent(r)}/preview`:null)),m=CodemanBase.url(d||(r?`/api/sessions/${t}/attachments/${encodeURIComponent(r)}/thumbnail`:`/api/sessions/${t}/file-thumbnail?path=${encodeURIComponent(u)}`)),S=r?`${g}?download=true`:`${g}&download=true`,$=(a||l||"file").toUpperCase(),b=document.createElement("article");b.className=`attachment-card attachment-${escapeHtml(l||"file")}`,b.tabIndex=0,b.dataset.attachmentId=p,b.dataset.previewUrl=T||"",b.innerHTML=`
249
+ `),i.appendChild(o),t.replaceChildren(i)}this._updateFilePreviewToolbar(n?"markdown":"text")},_rebaseFilePreviewMarkdownRefs(e,{sessionId:t,filePath:s,attachmentId:n}){const i=s.includes("/")?s.slice(0,s.lastIndexOf("/")+1):"",o=!!n&&!s.startsWith("/"),l=r=>!!r&&!/^[a-z][a-z0-9+.-]*:/i.test(r)&&!r.startsWith("//")&&!r.startsWith("#"),a=r=>{let c=r.split("#")[0].split("?")[0];try{c=decodeURIComponent(c)}catch{}const h=[];for(const d of(c.startsWith("/")?c.slice(1):i+c).split("/"))d==="."||d===""&&h.length||(d===".."&&h.length&&h[h.length-1]!==".."&&h[h.length-1]!==""?h.pop():h.push(d));return h.join("/")};for(const r of e.querySelectorAll("img[src]")){const c=r.getAttribute("src")||"";if(o&&l(c)){r.replaceWith(r.getAttribute("alt")||c);continue}if(l(c)){const h=a(c);r.setAttribute("src",CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(h)}`))}r.addEventListener("error",()=>r.replaceWith(r.getAttribute("alt")||c),{once:!0})}for(const r of e.querySelectorAll("a[href]")){const c=r.getAttribute("href")||"";if(l(c)){if(o){r.replaceWith(...r.childNodes);continue}r.className="rv-path",r.dataset.path=a(c),r.dataset.sessionId=t,r.setAttribute("href","#"),r.removeAttribute("target"),r.removeAttribute("rel")}}},_updateFilePreviewToolbar(e){const t=(o,l,a)=>{const r=this.$(o);r&&(r.hidden=!l,l&&r.setAttribute("aria-pressed",String(a)))},s=e!=="none"&&MARKDOWN_EXTS.has(this.filePreviewText?.ext||"");t("filePreviewMdBtn",s,e==="markdown");const n=this.filePreviewText,i=e==="text"&&!this.filePreviewPageRefused&&rendersAsPage(n?.filePath)&&(!n.attachmentId||n.filePath.startsWith("/"));t("filePreviewPageBtn",e==="page"||i,e==="page"),t("filePreviewLinesBtn",e==="text",this._filePreviewPref("lineNumbers")),t("filePreviewWrapBtn",e==="text",this._filePreviewPref("wrap"))},async _mintHtmlViewUrl(e,t){try{const s=await fetch(`/api/sessions/${t}/html-view`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})}),n=await s.json().catch(()=>({}));return s.ok&&n.success?CodemanBase.url(n.data.url):null}catch{return null}},toggleFilePreviewPage(){const e=this.filePreviewPage||this.filePreviewText;if(e)return this._setFilePreviewPref("htmlRendered",!this._filePreviewPref("htmlRendered")),this.openFilePreview(e.filePath,e.sessionId)},toggleFilePreviewMd(){this._setFilePreviewPref("mdRendered",!this._filePreviewPref("mdRendered")),this._renderFilePreviewText()},toggleFilePreviewLines(){this._toggleFilePreviewTextClass("lineNumbers","show-lines")},toggleFilePreviewWrap(){this._toggleFilePreviewTextClass("wrap","wrap")},_toggleFilePreviewTextClass(e,t){const s=!this._filePreviewPref(e);this._setFilePreviewPref(e,s);const n=this.$("filePreviewBody")?.querySelector(":scope > pre.file-preview-text");n&&n.classList.toggle(t,s),this._updateFilePreviewToolbar("text")},_resetFilePreviewEdit(){this.filePreviewEdit=null,this.filePreviewEditTarget=null;const e=this.$("filePreviewEditBtn");e&&(e.hidden=!0);const t=this.$("filePreviewEditBar");t&&(t.hidden=!0);const s=this.$("filePreviewDirty");s&&(s.hidden=!0);const n=this.$("filePreviewSaveBtn");n&&(n.disabled=!0,n.textContent="Save")},async enterFilePreviewEdit(){const e=this.filePreviewEditTarget;if(!e||this.filePreviewEdit)return;const t=this.$("filePreviewBody"),s=this.$("filePreviewFooter");if(!t)return;let n;try{const a=await fetch(`/api/sessions/${e.sessionId}/file-content?path=${encodeURIComponent(e.filePath)}&edit=1`),r=await a.json().catch(()=>null);if(!r||r.success!==!0)throw new Error(r?.error||`Failed to load file for editing (HTTP ${a.status})`);n=r.data}catch(a){this.showToast(a.message,"error");return}this.filePreviewEdit={sessionId:e.sessionId,filePath:e.filePath,baseHash:n.hash,eol:n.eol,original:n.content,dirty:!1,saving:!1};const i=document.createElement("textarea");i.className="file-preview-editor",i.spellcheck=!1,i.setAttribute("autocapitalize","off"),i.setAttribute("autocorrect","off"),i.setAttribute("autocomplete","off"),i.wrap="off",i.value=n.content,i.addEventListener("input",()=>this._onFilePreviewEditInput()),t.innerHTML="",t.appendChild(i),this._updateFilePreviewToolbar("none");const o=this.$("filePreviewEditBtn");o&&(o.hidden=!0);const l=this.$("filePreviewEditBar");if(l&&(l.hidden=!1),s){const a=n.eol==="crlf"?" \u2022 CRLF":"";s.textContent=`Editing \u2022 ${n.totalLines} lines \u2022 ${this.formatFileSize(n.size)}${a}`}},_onFilePreviewEditInput(){const e=this.filePreviewEdit;if(!e)return;const t=this.$("filePreviewBody")?.querySelector("textarea.file-preview-editor");if(!t)return;e.dirty=t.value!==e.original;const s=this.$("filePreviewDirty");s&&(s.hidden=!e.dirty);const n=this.$("filePreviewSaveBtn");n&&(n.disabled=!e.dirty||e.saving)},cancelFilePreviewEdit(){const e=this.filePreviewEdit;if(!e||e.dirty&&!confirm("Discard unsaved changes?"))return;const{sessionId:t,filePath:s}=e;this._resetFilePreviewEdit(),this.openFilePreview(s,t)},async saveFilePreviewEdit(e=!1){const t=this.filePreviewEdit;if(!t||t.saving)return;const s=this.$("filePreviewBody")?.querySelector("textarea.file-preview-editor");if(!s)return;t.saving=!0;const n=this.$("filePreviewSaveBtn");n&&(n.disabled=!0,n.textContent="Saving\u2026");const i=()=>{t.saving=!1,n&&(n.textContent="Save"),this._onFilePreviewEditInput()};let o=null,l=0;try{const c=await fetch(`/api/sessions/${t.sessionId}/file-content`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t.filePath,content:s.value,baseHash:t.baseHash,eol:t.eol??void 0,force:e||void 0})});l=c.status,o=await c.json().catch(()=>null)}catch(c){i(),this.showToast(`Save failed: ${c.message}`,"error");return}if(l===409||o?.errorCode==="CONFLICT"){i(),confirm(`File changed on disk since you loaded it.
250
+ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFilePreviewEdit(!0);return}if(!o||o.success!==!0){i(),this.showToast(`Save failed: ${o?.error||`HTTP ${l}`}`,"error");return}const{sessionId:a,filePath:r}=t;this._resetFilePreviewEdit(),this.showToast("Saved","success"),this.openFilePreview(r,a)},_onAttachmentDetected(e){if(console.log("[Attachment Detected]",e),this.addAttachmentCard(e),e.sessionId){const t=this.attachmentHistoryCounts.get(e.sessionId)??this.sessions.get(e.sessionId)?.attachmentHistory?.length??0;this.attachmentHistoryCounts.set(e.sessionId,Math.min(t+1,100)),e.sessionId===this.activeSessionId&&(this.updateAttachmentHistoryBadge(),this.attachmentHistoryDrawerOpen&&this._debouncedCall("attachmentHistoryRefresh",()=>{this.attachmentHistoryDrawerOpen&&this.activeSessionId===e.sessionId&&this.loadAttachmentHistory(e.sessionId)},250))}},ensureAttachmentCardStack(){let e=this.attachmentCardStack||document.getElementById("attachmentCardStack");return e||(e=document.createElement("div"),e.id="attachmentCardStack",e.className="attachment-card-stack",document.body.appendChild(e)),this.attachmentCardStack=e,e},openAttachmentInNewTab(e,t,s=null){const n=CodemanBase.url(s?`/api/sessions/${e}/attachments/${encodeURIComponent(s)}/raw`:`/api/sessions/${e}/file-raw?path=${encodeURIComponent(t)}`);window.open(n,"_blank")},addAttachmentCard(e){const{sessionId:t,relativePath:s,fileName:n,timestamp:i,size:o,attachmentType:l,extension:a,attachmentId:r,rawUrl:c,previewUrl:h,thumbnailUrl:d}=e,u=s||n,p=r||`${t}-${i}-${n}`;if(this.attachmentCards.has(p)){this.attachmentCards.get(p).element.focus?.();return}if(this.attachmentCards.size>=10){const E=this.attachmentCards.keys().next().value;E&&this.closeAttachmentCard(E)}const w=this.ensureAttachmentCardStack(),v=this.sessions.get(t)?.name||t.substring(0,8),g=CodemanBase.url(c||(r?`/api/sessions/${t}/attachments/${encodeURIComponent(r)}/raw`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(u)}`)),C=CodemanBase.url(h||(r?`/api/sessions/${t}/attachments/${encodeURIComponent(r)}/preview`:null)),m=CodemanBase.url(d||(r?`/api/sessions/${t}/attachments/${encodeURIComponent(r)}/thumbnail`:`/api/sessions/${t}/file-thumbnail?path=${encodeURIComponent(u)}`)),S=r?`${g}?download=true`:`${g}&download=true`,$=(a||l||"file").toUpperCase(),b=document.createElement("article");b.className=`attachment-card attachment-${escapeHtml(l||"file")}`,b.tabIndex=0,b.dataset.attachmentId=p,b.dataset.previewUrl=C||"",b.innerHTML=`
245
251
  <div class="attachment-thumbnail">
246
252
  ${m?`<img class="attachment-thumbnail-img" src="${escapeHtml(m)}" alt="">`:""}
247
253
  <div class="attachment-thumbnail-fallback ${m?"":"visible"}">${escapeHtml($)}</div>
248
254
  </div>
249
255
  <div class="attachment-card-main">
250
- <div class="attachment-file-name" title="${escapeHtml(u)}">${escapeHtml(i)}</div>
256
+ <div class="attachment-file-name" title="${escapeHtml(u)}">${escapeHtml(n)}</div>
251
257
  <div class="attachment-file-meta">
252
258
  <span>${escapeHtml(v)}</span>
253
259
  <span>${this.formatFileSize(o||0)}</span>
@@ -259,7 +265,7 @@ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFi
259
265
  </div>
260
266
  </div>
261
267
  <button type="button" class="attachment-close-btn" title="Dismiss">&times;</button>
262
- `;const C=b.querySelector(".attachment-thumbnail-img");C&&(C.onerror=()=>{C.remove(),b.querySelector(".attachment-thumbnail-fallback")?.classList.add("visible")}),b.querySelector(".attachment-preview-btn")?.addEventListener("click",()=>{this.openFilePreview(u,t,r||null)}),b.querySelector(".attachment-open-btn")?.addEventListener("click",()=>{this.openAttachmentInNewTab(t,u,r||null)}),b.querySelector(".attachment-close-btn")?.addEventListener("click",()=>{this.closeAttachmentCard(p)}),w.prepend(b),this.attachmentCards.set(p,{element:b,sessionId:t,filePath:u}),this._refreshAttachmentClearAll()},_refreshAttachmentClearAll(){const e=this.attachmentCardStack;if(!e)return;let t=e.querySelector(".attachment-clear-all");if(this.attachmentCards.size<2){t&&(t.hidden=!0);return}t||(t=document.createElement("button"),t.type="button",t.className="attachment-clear-all",t.textContent="Clear all",t.title="Dismiss all attachment cards",t.addEventListener("click",()=>this.closeAllAttachmentCards()),e.prepend(t)),t.hidden=!1},closeAttachmentCard(e){const t=this.attachmentCards.get(e);t&&(t.element.remove(),this.attachmentCards.delete(e),this.attachmentCardStack&&this.attachmentCards.size===0?(this.attachmentCardStack.remove(),this.attachmentCardStack=null):this._refreshAttachmentClearAll())},closeAllAttachmentCards(){for(const e of[...this.attachmentCards.keys()])this.closeAttachmentCard(e)},closeSessionAttachmentCards(e){const t=[];for(const[s,i]of this.attachmentCards)i.sessionId===e&&t.push(s);for(const s of t)this.closeAttachmentCard(s)},updateAttachmentHistoryBadge(e=null){const t=document.getElementById("attachmentHistoryBadge"),s=document.getElementById("attachmentsHistoryBtn"),i=this.activeSessionId,n=e??(i&&this.attachmentHistoryCounts.get(i)||0);t&&(t.textContent=n>99?"99+":String(n),t.style.display=n>0?"":"none"),s&&(s.classList.toggle("active",this.attachmentHistoryDrawerOpen),s.setAttribute("aria-expanded",this.attachmentHistoryDrawerOpen?"true":"false"))},ensureAttachmentHistoryDrawer(){let e=document.getElementById("attachmentHistoryDrawer");return e||(e=document.createElement("aside"),e.id="attachmentHistoryDrawer",e.className="attachment-history-drawer",e.setAttribute("aria-label","Attachment history"),e.innerHTML=`
268
+ `;const T=b.querySelector(".attachment-thumbnail-img");T&&(T.onerror=()=>{T.remove(),b.querySelector(".attachment-thumbnail-fallback")?.classList.add("visible")}),b.querySelector(".attachment-preview-btn")?.addEventListener("click",()=>{this.openFilePreview(u,t,r||null)}),b.querySelector(".attachment-open-btn")?.addEventListener("click",()=>{this.openAttachmentInNewTab(t,u,r||null)}),b.querySelector(".attachment-close-btn")?.addEventListener("click",()=>{this.closeAttachmentCard(p)}),w.prepend(b),this.attachmentCards.set(p,{element:b,sessionId:t,filePath:u}),this._refreshAttachmentClearAll()},_refreshAttachmentClearAll(){const e=this.attachmentCardStack;if(!e)return;let t=e.querySelector(".attachment-clear-all");if(this.attachmentCards.size<2){t&&(t.hidden=!0);return}t||(t=document.createElement("button"),t.type="button",t.className="attachment-clear-all",t.textContent="Clear all",t.title="Dismiss all attachment cards",t.addEventListener("click",()=>this.closeAllAttachmentCards()),e.prepend(t)),t.hidden=!1},closeAttachmentCard(e){const t=this.attachmentCards.get(e);t&&(t.element.remove(),this.attachmentCards.delete(e),this.attachmentCardStack&&this.attachmentCards.size===0?(this.attachmentCardStack.remove(),this.attachmentCardStack=null):this._refreshAttachmentClearAll())},closeAllAttachmentCards(){for(const e of[...this.attachmentCards.keys()])this.closeAttachmentCard(e)},closeSessionAttachmentCards(e){const t=[];for(const[s,n]of this.attachmentCards)n.sessionId===e&&t.push(s);for(const s of t)this.closeAttachmentCard(s)},updateAttachmentHistoryBadge(e=null){const t=document.getElementById("attachmentHistoryBadge"),s=document.getElementById("attachmentsHistoryBtn"),n=this.activeSessionId,i=e??(n&&this.attachmentHistoryCounts.get(n)||0);t&&(t.textContent=i>99?"99+":String(i),t.style.display=i>0?"":"none"),s&&(s.classList.toggle("active",this.attachmentHistoryDrawerOpen),s.setAttribute("aria-expanded",this.attachmentHistoryDrawerOpen?"true":"false"))},ensureAttachmentHistoryDrawer(){let e=document.getElementById("attachmentHistoryDrawer");return e||(e=document.createElement("aside"),e.id="attachmentHistoryDrawer",e.className="attachment-history-drawer",e.setAttribute("aria-label","Attachment history"),e.innerHTML=`
263
269
  <div class="attachment-history-header">
264
270
  <div>
265
271
  <div class="attachment-history-title">Attachments</div>
@@ -271,31 +277,31 @@ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFi
271
277
  </div>
272
278
  </div>
273
279
  <div class="attachment-history-list" id="attachmentHistoryList"></div>
274
- `,document.body.appendChild(e),e.querySelector("#attachmentHistoryRefreshBtn")?.addEventListener("click",()=>{this.loadAttachmentHistory(this.activeSessionId)}),e.querySelector("#attachmentHistoryCloseBtn")?.addEventListener("click",()=>{this.closeAttachmentHistory()}),e)},async toggleAttachmentHistory(){if(this.attachmentHistoryDrawerOpen){this.closeAttachmentHistory();return}await this.openAttachmentHistory()},async openAttachmentHistory(){const e=this.ensureAttachmentHistoryDrawer();this.attachmentHistoryDrawerOpen=!0,e.classList.add("open"),this.updateAttachmentHistoryBadge(),await this.loadAttachmentHistory(this.activeSessionId)},closeAttachmentHistory(){const e=document.getElementById("attachmentHistoryDrawer");this.attachmentHistoryDrawerOpen=!1,e?.classList.remove("open"),this._debounceTimers?.attachmentHistoryRefresh&&(clearTimeout(this._debounceTimers.attachmentHistoryRefresh),this._debounceTimers.attachmentHistoryRefresh=null),this.updateAttachmentHistoryBadge()},async loadAttachmentHistory(e=this.activeSessionId){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),i=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!i)){if(!e){this.attachmentHistoryItems=[],i.textContent="No session",s.innerHTML='<div class="attachment-history-empty">No active session</div>',this.updateAttachmentHistoryBadge(0);return}s.innerHTML='<div class="attachment-history-empty">Loading...</div>';try{const n=await fetch(`/api/sessions/${e}/attachments`);if(!n.ok)throw new Error("Failed to load attachments");const o=await n.json();if(!o.success)throw new Error(o.error||"Failed to load attachments");const l=o.data?.items||[];this.attachmentHistoryItems=l,this.attachmentHistoryCounts.set(e,l.length),this.updateAttachmentHistoryBadge(l.length),this.renderAttachmentHistory(l)}catch(n){console.error("Failed to load attachment history:",n),i.textContent="Unavailable",s.innerHTML=`<div class="attachment-history-empty">Error: ${escapeHtml(n.message)}</div>`}}},renderAttachmentHistory(e=this.attachmentHistoryItems||[]){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),i=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!i)){if(i.textContent=`${e.length} ${e.length===1?"file":"files"}`,e.length===0){s.innerHTML=`
280
+ `,document.body.appendChild(e),e.querySelector("#attachmentHistoryRefreshBtn")?.addEventListener("click",()=>{this.loadAttachmentHistory(this.activeSessionId)}),e.querySelector("#attachmentHistoryCloseBtn")?.addEventListener("click",()=>{this.closeAttachmentHistory()}),e)},async toggleAttachmentHistory(){if(this.attachmentHistoryDrawerOpen){this.closeAttachmentHistory();return}await this.openAttachmentHistory()},async openAttachmentHistory(){const e=this.ensureAttachmentHistoryDrawer();this.attachmentHistoryDrawerOpen=!0,e.classList.add("open"),this.updateAttachmentHistoryBadge(),await this.loadAttachmentHistory(this.activeSessionId)},closeAttachmentHistory(){const e=document.getElementById("attachmentHistoryDrawer");this.attachmentHistoryDrawerOpen=!1,e?.classList.remove("open"),this._debounceTimers?.attachmentHistoryRefresh&&(clearTimeout(this._debounceTimers.attachmentHistoryRefresh),this._debounceTimers.attachmentHistoryRefresh=null),this.updateAttachmentHistoryBadge()},async loadAttachmentHistory(e=this.activeSessionId){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(!e){this.attachmentHistoryItems=[],n.textContent="No session",s.innerHTML='<div class="attachment-history-empty">No active session</div>',this.updateAttachmentHistoryBadge(0);return}s.innerHTML='<div class="attachment-history-empty">Loading...</div>';try{const i=await fetch(`/api/sessions/${e}/attachments`);if(!i.ok)throw new Error("Failed to load attachments");const o=await i.json();if(!o.success)throw new Error(o.error||"Failed to load attachments");const l=o.data?.items||[];this.attachmentHistoryItems=l,this.attachmentHistoryCounts.set(e,l.length),this.updateAttachmentHistoryBadge(l.length),this.renderAttachmentHistory(l)}catch(i){console.error("Failed to load attachment history:",i),n.textContent="Unavailable",s.innerHTML=`<div class="attachment-history-empty">Error: ${escapeHtml(i.message)}</div>`}}},renderAttachmentHistory(e=this.attachmentHistoryItems||[]){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(n.textContent=`${e.length} ${e.length===1?"file":"files"}`,e.length===0){s.innerHTML=`
275
281
  <div class="attachment-history-empty">
276
282
  <div class="attachment-history-empty-title">No attachments yet</div>
277
283
  <div>Show a file here by running:</div>
278
284
  <code>codeman attach /absolute/path/to/file.pptx</code>
279
285
  <div>Supports .pptx, .docx, .xlsx, .pdf, .png, .md, and .txt.</div>
280
286
  </div>
281
- `;return}s.innerHTML=e.map(n=>this.renderAttachmentHistoryItem(n)).join(""),s.querySelectorAll(".attachment-history-thumb-img").forEach(n=>{n.onerror=()=>{n.remove(),n.closest(".attachment-history-thumb")?.querySelector(".attachment-history-thumb-fallback")?.classList.add("visible")}}),s.querySelectorAll("[data-attachment-action]").forEach(n=>{n.addEventListener("click",()=>{const o=n.getAttribute("data-history-id"),l=n.getAttribute("data-attachment-action");!o||!l||(l==="preview"&&this.previewAttachmentHistoryItem(o),l==="download"&&this.downloadAttachmentHistoryItem(o),l==="open"&&this.openAttachmentHistoryItem(o),l==="reshow"&&this.reshowAttachmentCard(o))})})}},renderAttachmentHistoryItem(e){const t=(e.extension||e.attachmentType||"file").toUpperCase(),s=[e.source==="external"?"published":"workspace",this.formatFileSize(e.size||0),e.missing?"missing":""].filter(Boolean).join(" \u2022 "),i=e.thumbnailUrl&&!e.missing?`<img class="attachment-history-thumb-img" src="${escapeHtml(CodemanBase.url(e.thumbnailUrl))}" alt="">`:"",n=e.missing?'disabled aria-disabled="true"':"";return`
287
+ `;return}s.innerHTML=e.map(i=>this.renderAttachmentHistoryItem(i)).join(""),s.querySelectorAll(".attachment-history-thumb-img").forEach(i=>{i.onerror=()=>{i.remove(),i.closest(".attachment-history-thumb")?.querySelector(".attachment-history-thumb-fallback")?.classList.add("visible")}}),s.querySelectorAll("[data-attachment-action]").forEach(i=>{i.addEventListener("click",()=>{const o=i.getAttribute("data-history-id"),l=i.getAttribute("data-attachment-action");!o||!l||(l==="preview"&&this.previewAttachmentHistoryItem(o),l==="download"&&this.downloadAttachmentHistoryItem(o),l==="open"&&this.openAttachmentHistoryItem(o),l==="reshow"&&this.reshowAttachmentCard(o))})})}},renderAttachmentHistoryItem(e){const t=(e.extension||e.attachmentType||"file").toUpperCase(),s=[e.source==="external"?"published":"workspace",this.formatFileSize(e.size||0),e.missing?"missing":""].filter(Boolean).join(" \u2022 "),n=e.thumbnailUrl&&!e.missing?`<img class="attachment-history-thumb-img" src="${escapeHtml(CodemanBase.url(e.thumbnailUrl))}" alt="">`:"",i=e.missing?'disabled aria-disabled="true"':"";return`
282
288
  <div class="attachment-history-item ${e.missing?"missing":""}" data-history-item="${escapeHtml(e.id)}">
283
289
  <div class="attachment-history-thumb">
284
- ${i}
285
- <div class="attachment-history-thumb-fallback ${i?"":"visible"}">${escapeHtml(t)}</div>
290
+ ${n}
291
+ <div class="attachment-history-thumb-fallback ${n?"":"visible"}">${escapeHtml(t)}</div>
286
292
  </div>
287
293
  <div class="attachment-history-item-main">
288
294
  <div class="attachment-history-file-name" title="${escapeHtml(e.fileName)}">${escapeHtml(e.fileName)}</div>
289
295
  <div class="attachment-history-meta">${escapeHtml(s)}</div>
290
296
  <div class="attachment-history-actions">
291
- <button type="button" data-attachment-action="preview" data-history-id="${escapeHtml(e.id)}" ${n}>Preview</button>
292
- <button type="button" data-attachment-action="download" data-history-id="${escapeHtml(e.id)}" ${n}>Download</button>
293
- <button type="button" data-attachment-action="open" data-history-id="${escapeHtml(e.id)}" ${n}>Open</button>
294
- <button type="button" data-attachment-action="reshow" data-history-id="${escapeHtml(e.id)}" ${n}>Card</button>
297
+ <button type="button" data-attachment-action="preview" data-history-id="${escapeHtml(e.id)}" ${i}>Preview</button>
298
+ <button type="button" data-attachment-action="download" data-history-id="${escapeHtml(e.id)}" ${i}>Download</button>
299
+ <button type="button" data-attachment-action="open" data-history-id="${escapeHtml(e.id)}" ${i}>Open</button>
300
+ <button type="button" data-attachment-action="reshow" data-history-id="${escapeHtml(e.id)}" ${i}>Card</button>
295
301
  </div>
296
302
  </div>
297
303
  </div>
298
- `},getAttachmentHistoryItem(e){return(this.attachmentHistoryItems||[]).find(t=>t.id===e)||null},previewAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!t||t.missing)return;const s=t.relativePath||t.fileName;this.openFilePreview(s,t.sessionId,t.attachmentId||null),this.closeAttachmentHistory()},openAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!(!t||t.missing)){if(t.rawUrl||t.url){window.open(CodemanBase.url(t.rawUrl||t.url),"_blank");return}this.openAttachmentInNewTab(t.sessionId,t.relativePath||t.fileName,t.attachmentId||null)}},downloadAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||!t.downloadUrl||window.open(CodemanBase.url(t.downloadUrl),"_blank")},reshowAttachmentCard(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||this.addAttachmentCard({sessionId:t.sessionId,relativePath:t.relativePath,fileName:t.fileName,timestamp:t.timestamp??Date.now(),size:t.size,attachmentType:t.attachmentType,extension:t.extension,attachmentId:t.attachmentId,rawUrl:t.rawUrl,previewUrl:t.previewUrl,thumbnailUrl:t.thumbnailUrl})},copyFilePreviewContent(){const e=this.filePreviewEdit?this.$("filePreviewBody")?.querySelector("textarea.file-preview-editor"):null,t=e?e.value:this.filePreviewContent;t?navigator.clipboard.writeText(t).then(()=>{this.showToast("Copied to clipboard","success")}).catch(()=>{this.showToast("Failed to copy","error")}):this.showToast("Nothing to copy in this preview","info")},getFileIcon(e){return e&&{ts:"\u{1F4D8}",tsx:"\u{1F4D8}",js:"\u{1F4D2}",jsx:"\u{1F4D2}",mjs:"\u{1F4D2}",cjs:"\u{1F4D2}",py:"\u{1F40D}",pyx:"\u{1F40D}",pyw:"\u{1F40D}",rs:"\u{1F980}",go:"\u{1F439}",c:"\u2699\uFE0F",cpp:"\u2699\uFE0F",h:"\u2699\uFE0F",hpp:"\u2699\uFE0F",html:"\u{1F310}",htm:"\u{1F310}",css:"\u{1F3A8}",scss:"\u{1F3A8}",sass:"\u{1F3A8}",less:"\u{1F3A8}",json:"\u{1F4CB}",yaml:"\u{1F4CB}",yml:"\u{1F4CB}",xml:"\u{1F4CB}",toml:"\u{1F4CB}",csv:"\u{1F4CB}",md:"\u{1F4DD}",markdown:"\u{1F4DD}",txt:"\u{1F4DD}",rst:"\u{1F4DD}",png:"\u{1F5BC}\uFE0F",jpg:"\u{1F5BC}\uFE0F",jpeg:"\u{1F5BC}\uFE0F",gif:"\u{1F5BC}\uFE0F",svg:"\u{1F5BC}\uFE0F",webp:"\u{1F5BC}\uFE0F",ico:"\u{1F5BC}\uFE0F",bmp:"\u{1F5BC}\uFE0F",mp4:"\u{1F3AC}",webm:"\u{1F3AC}",mov:"\u{1F3AC}",mp3:"\u{1F3B5}",wav:"\u{1F3B5}",ogg:"\u{1F3B5}",sh:"\u{1F4BB}",bash:"\u{1F4BB}",zsh:"\u{1F4BB}",env:"\u{1F510}",gitignore:"\u{1F6AB}",dockerfile:"\u{1F433}",lock:"\u{1F512}"}[e.toLowerCase()]||"\u{1F4C4}"},formatFileSize(e){return e==null?"":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${(e/(1024*1024*1024)).toFixed(1)} GB`},openLogViewerWindow(e,t){if(t=t||this.activeSessionId,!t)return;const s=`${t}-${e.replace(/[^a-zA-Z0-9]/g,"_")}`;if(this.logViewerWindows.has(s)){const h=this.logViewerWindows.get(s);h.element.style.zIndex=++this.logViewerWindowZIndex;return}const i=this.logViewerWindows.size,n=100+i%5*30,o=100+i%5*30,l=e.split("/").pop(),a=document.createElement("div");a.className="log-viewer-window",a.id=`log-viewer-window-${s}`,a.style.left=`${n}px`,a.style.top=`${o}px`,a.style.zIndex=++this.logViewerWindowZIndex,a.innerHTML=`
304
+ `},getAttachmentHistoryItem(e){return(this.attachmentHistoryItems||[]).find(t=>t.id===e)||null},previewAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!t||t.missing)return;const s=t.relativePath||t.fileName;this.openFilePreview(s,t.sessionId,t.attachmentId||null),this.closeAttachmentHistory()},openAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!(!t||t.missing)){if(t.rawUrl||t.url){window.open(CodemanBase.url(t.rawUrl||t.url),"_blank");return}this.openAttachmentInNewTab(t.sessionId,t.relativePath||t.fileName,t.attachmentId||null)}},downloadAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||!t.downloadUrl||window.open(CodemanBase.url(t.downloadUrl),"_blank")},reshowAttachmentCard(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||this.addAttachmentCard({sessionId:t.sessionId,relativePath:t.relativePath,fileName:t.fileName,timestamp:t.timestamp??Date.now(),size:t.size,attachmentType:t.attachmentType,extension:t.extension,attachmentId:t.attachmentId,rawUrl:t.rawUrl,previewUrl:t.previewUrl,thumbnailUrl:t.thumbnailUrl})},copyFilePreviewContent(){const e=this.filePreviewEdit?this.$("filePreviewBody")?.querySelector("textarea.file-preview-editor"):null,t=e?e.value:this.filePreviewContent;t?navigator.clipboard.writeText(t).then(()=>{this.showToast("Copied to clipboard","success")}).catch(()=>{this.showToast("Failed to copy","error")}):this.showToast("Nothing to copy in this preview","info")},getFileIcon(e){return e&&{ts:"\u{1F4D8}",tsx:"\u{1F4D8}",js:"\u{1F4D2}",jsx:"\u{1F4D2}",mjs:"\u{1F4D2}",cjs:"\u{1F4D2}",py:"\u{1F40D}",pyx:"\u{1F40D}",pyw:"\u{1F40D}",rs:"\u{1F980}",go:"\u{1F439}",c:"\u2699\uFE0F",cpp:"\u2699\uFE0F",h:"\u2699\uFE0F",hpp:"\u2699\uFE0F",html:"\u{1F310}",htm:"\u{1F310}",css:"\u{1F3A8}",scss:"\u{1F3A8}",sass:"\u{1F3A8}",less:"\u{1F3A8}",json:"\u{1F4CB}",yaml:"\u{1F4CB}",yml:"\u{1F4CB}",xml:"\u{1F4CB}",toml:"\u{1F4CB}",csv:"\u{1F4CB}",md:"\u{1F4DD}",markdown:"\u{1F4DD}",txt:"\u{1F4DD}",rst:"\u{1F4DD}",png:"\u{1F5BC}\uFE0F",jpg:"\u{1F5BC}\uFE0F",jpeg:"\u{1F5BC}\uFE0F",gif:"\u{1F5BC}\uFE0F",svg:"\u{1F5BC}\uFE0F",webp:"\u{1F5BC}\uFE0F",ico:"\u{1F5BC}\uFE0F",bmp:"\u{1F5BC}\uFE0F",mp4:"\u{1F3AC}",webm:"\u{1F3AC}",mov:"\u{1F3AC}",mp3:"\u{1F3B5}",wav:"\u{1F3B5}",ogg:"\u{1F3B5}",sh:"\u{1F4BB}",bash:"\u{1F4BB}",zsh:"\u{1F4BB}",env:"\u{1F510}",gitignore:"\u{1F6AB}",dockerfile:"\u{1F433}",lock:"\u{1F512}"}[e.toLowerCase()]||"\u{1F4C4}"},formatFileSize(e){return e==null?"":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${(e/(1024*1024*1024)).toFixed(1)} GB`},openLogViewerWindow(e,t){if(t=t||this.activeSessionId,!t)return;const s=`${t}-${e.replace(/[^a-zA-Z0-9]/g,"_")}`;if(this.logViewerWindows.has(s)){const h=this.logViewerWindows.get(s);h.element.style.zIndex=++this.logViewerWindowZIndex;return}const n=this.logViewerWindows.size,i=100+n%5*30,o=100+n%5*30,l=e.split("/").pop(),a=document.createElement("div");a.className="log-viewer-window",a.id=`log-viewer-window-${s}`,a.style.left=`${i}px`,a.style.top=`${o}px`,a.style.zIndex=++this.logViewerWindowZIndex,a.innerHTML=`
299
305
  <div class="log-viewer-window-header">
300
306
  <div class="log-viewer-window-title" title="${escapeHtml(e)}">
301
307
  <span class="icon">\u{1F4C4}</span>
@@ -309,11 +315,11 @@ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFi
309
315
  <div class="log-viewer-window-body" id="log-viewer-body-${s}">
310
316
  <div class="log-info">Connecting to ${escapeHtml(e)}...</div>
311
317
  </div>
312
- `,document.body.appendChild(a);const r=this.makeWindowDraggable(a,a.querySelector(".log-viewer-window-header")),c=new EventSource(CodemanBase.url(`/api/sessions/${t}/tail-file?path=${encodeURIComponent(e)}&lines=50`));c.onmessage=h=>{const d=JSON.parse(h.data),u=document.getElementById(`log-viewer-body-${s}`);if(u)switch(d.type){case"connected":u.innerHTML="";break;case"data":const p=u.scrollTop+u.clientHeight>=u.scrollHeight-10,f=escapeHtml(d.content);u.innerHTML+=f,p&&(u.scrollTop=u.scrollHeight),u.innerHTML.length>5e5&&(u.innerHTML=u.innerHTML.slice(-4e5));break;case"end":this.updateLogViewerStatus(s,"disconnected","ended");break;case"error":u.innerHTML+=`<div class="log-error">${escapeHtml(d.error)}</div>`,this.updateLogViewerStatus(s,"error","error");break}},c.onerror=()=>{this.updateLogViewerStatus(s,"disconnected","connection error")},this.logViewerWindows.set(s,{element:a,eventSource:c,filePath:e,sessionId:t,dragListeners:r})},updateLogViewerStatus(e,t,s){const i=document.querySelector(`#log-viewer-window-${e} .status`);i&&(i.className=`status ${t}`,i.textContent=s)},closeLogViewerWindow(e){const t=this.logViewerWindows.get(e);t&&(t.eventSource&&t.eventSource.close(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.logViewerWindows.delete(e))},closeSessionLogViewerWindows(e){const t=[];for(const[s,i]of this.logViewerWindows)i.sessionId===e&&t.push(s);for(const s of t)this.closeLogViewerWindow(s)},openImagePopup(e){const{sessionId:t,filePath:s,relativePath:i,fileName:n,timestamp:o,size:l}=e,a=`${t}-${o}`;if(this.imagePopups.has(a)){const m=this.imagePopups.get(a);m.element.style.zIndex=++this.imagePopupZIndex;return}if(this.imagePopups.size>=20){const m=this.imagePopups.keys().next().value;m&&this.closeImagePopup(m)}const c=this.imagePopups.size,h=(window.innerWidth-600)/2,d=(window.innerHeight-500)/2,u=h+c%5*30,p=d+c%5*30,w=this.sessions.get(t)?.name||t.substring(0,8),y=(l/1024).toFixed(1),v=CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(i||n)}`),g=document.createElement("div");g.className="image-popup-window",g.id=`image-popup-${a}`,g.style.left=`${u}px`,g.style.top=`${p}px`,g.style.zIndex=++this.imagePopupZIndex,g.innerHTML=`
318
+ `,document.body.appendChild(a);const r=this.makeWindowDraggable(a,a.querySelector(".log-viewer-window-header")),c=new EventSource(CodemanBase.url(`/api/sessions/${t}/tail-file?path=${encodeURIComponent(e)}&lines=50`));c.onmessage=h=>{const d=JSON.parse(h.data),u=document.getElementById(`log-viewer-body-${s}`);if(u)switch(d.type){case"connected":u.innerHTML="";break;case"data":const p=u.scrollTop+u.clientHeight>=u.scrollHeight-10,f=escapeHtml(d.content);u.innerHTML+=f,p&&(u.scrollTop=u.scrollHeight),u.innerHTML.length>5e5&&(u.innerHTML=u.innerHTML.slice(-4e5));break;case"end":this.updateLogViewerStatus(s,"disconnected","ended");break;case"error":u.innerHTML+=`<div class="log-error">${escapeHtml(d.error)}</div>`,this.updateLogViewerStatus(s,"error","error");break}},c.onerror=()=>{this.updateLogViewerStatus(s,"disconnected","connection error")},this.logViewerWindows.set(s,{element:a,eventSource:c,filePath:e,sessionId:t,dragListeners:r})},updateLogViewerStatus(e,t,s){const n=document.querySelector(`#log-viewer-window-${e} .status`);n&&(n.className=`status ${t}`,n.textContent=s)},closeLogViewerWindow(e){const t=this.logViewerWindows.get(e);t&&(t.eventSource&&t.eventSource.close(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.logViewerWindows.delete(e))},closeSessionLogViewerWindows(e){const t=[];for(const[s,n]of this.logViewerWindows)n.sessionId===e&&t.push(s);for(const s of t)this.closeLogViewerWindow(s)},openImagePopup(e){const{sessionId:t,filePath:s,relativePath:n,fileName:i,timestamp:o,size:l}=e,a=`${t}-${o}`;if(this.imagePopups.has(a)){const m=this.imagePopups.get(a);m.element.style.zIndex=++this.imagePopupZIndex;return}if(this.imagePopups.size>=20){const m=this.imagePopups.keys().next().value;m&&this.closeImagePopup(m)}const c=this.imagePopups.size,h=(window.innerWidth-600)/2,d=(window.innerHeight-500)/2,u=h+c%5*30,p=d+c%5*30,w=this.sessions.get(t)?.name||t.substring(0,8),y=(l/1024).toFixed(1),v=CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(n||i)}`),g=document.createElement("div");g.className="image-popup-window",g.id=`image-popup-${a}`,g.style.left=`${u}px`,g.style.top=`${p}px`,g.style.zIndex=++this.imagePopupZIndex,g.innerHTML=`
313
319
  <div class="image-popup-header">
314
320
  <div class="image-popup-title" title="${escapeHtml(s)}">
315
321
  <span class="icon">\u{1F5BC}\uFE0F</span>
316
- <span class="filename">${escapeHtml(n)}</span>
322
+ <span class="filename">${escapeHtml(i)}</span>
317
323
  <span class="session-badge">${escapeHtml(w)}</span>
318
324
  <span class="size-badge">${y} KB</span>
319
325
  </div>
@@ -323,11 +329,11 @@ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFi
323
329
  </div>
324
330
  </div>
325
331
  <div class="image-popup-body">
326
- <img src="${v}" alt="${escapeHtml(n)}"
332
+ <img src="${v}" alt="${escapeHtml(i)}"
327
333
  onerror="this.parentElement.innerHTML='<div class=\\'image-error\\'>Failed to load image</div>'"
328
334
  onclick="app.openImageInNewTab(${escapeHtml(JSON.stringify(v))})" />
329
335
  </div>
330
- `,document.body.appendChild(g);const T=this.makeWindowDraggable(g,g.querySelector(".image-popup-header"));g.addEventListener("mousedown",()=>{g.style.zIndex=++this.imagePopupZIndex}),this.imagePopups.set(a,{element:g,sessionId:t,filePath:s,dragListeners:T})},closeImagePopup(e){const t=this.imagePopups.get(e);t&&(t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.imagePopups.delete(e))},openImageInNewTab(e){window.open(e,"_blank")},closeSessionImagePopups(e){const t=[];for(const[s,i]of this.imagePopups)i.sessionId===e&&t.push(s);for(const s of t)this.closeImagePopup(s)},async loadMuxSessions(){try{const t=await(await fetch("/api/mux-sessions")).json();this.muxSessions=t.data?.sessions||[],this.renderMuxSessions()}catch(e){console.error("Failed to load mux sessions:",e)}},killAllMuxSessions(){const e=this.muxSessions?.length||0;if(e===0){alert("No sessions to kill");return}document.getElementById("killAllCount").textContent=e;const t=document.getElementById("killAllModal");t.classList.add("active"),this.activeFocusTrap=new FocusTrap(t),this.activeFocusTrap.activate()},closeKillAllModal(){document.getElementById("killAllModal").classList.remove("active"),this.activeFocusTrap&&(this.activeFocusTrap.deactivate(),this.activeFocusTrap=null)},async confirmKillAll(e){this.closeKillAllModal();try{if(e){if((await(await fetch("/api/sessions",{method:"DELETE"})).json()).success){this.sessions.clear(),this.muxSessions=[],this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.renderMuxSessions(),this._resetTerminalForReplay(),this.toast("All sessions and tmux killed","success")}}else{this.sessions.clear(),this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this._resetTerminalForReplay(),this.toast("All tabs removed, tmux still running","info")}}catch(t){console.error("Failed to kill sessions:",t),this.toast("Failed to kill sessions: "+t.message,"error")}},renderMuxSessions(){this._debouncedCall("muxSessions",this._renderMuxSessionsImmediate)},_renderMuxSessionsImmediate(){const e=document.getElementById("muxSessionsBody");if(!this.muxSessions||this.muxSessions.length===0){e.innerHTML='<div class="monitor-empty">No mux sessions</div>';return}let t="";for(const s of this.muxSessions){const i=s.stats||{memoryMB:0,cpuPercent:0,childCount:0},n=this.sessions.get(s.sessionId),o=n?n.status:"unknown",l=n?n.isWorking:!1;let a,r;o==="idle"&&!l?(a="IDLE",r="status-idle"):o==="busy"||l?(a="WORKING",r="status-working"):o==="stopped"?(a="STOPPED",r="status-stopped"):(a=o.toUpperCase(),r="");const c=n&&n.tokens?n.tokens:null,h=n?n.totalCost:0,d=n&&n.cliModel||"",u=d.includes("opus")?"opus":d.includes("sonnet")?"sonnet":d.includes("haiku")?"haiku":"",p=n?n.ralphTodoStats:null;let f="";if(p&&p.total>0){const T=Math.round(p.completed/p.total*100);f=`<span class="process-stat todo-progress">${p.completed}/${p.total} (${T}%)</span>`}let w="";c&&c.total>0&&(w=`<span class="process-stat tokens">${(c.total/1e3).toFixed(1)}k tok</span>`);let y="";h>0&&(y=`<span class="process-stat cost">$${h.toFixed(2)}</span>`);let v="";u&&(v=`<span class="monitor-model-badge ${u}">${u}</span>`);const g=escapeHtml(JSON.stringify(s.sessionId));t+=`
336
+ `,document.body.appendChild(g);const C=this.makeWindowDraggable(g,g.querySelector(".image-popup-header"));g.addEventListener("mousedown",()=>{g.style.zIndex=++this.imagePopupZIndex}),this.imagePopups.set(a,{element:g,sessionId:t,filePath:s,dragListeners:C})},closeImagePopup(e){const t=this.imagePopups.get(e);t&&(t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.imagePopups.delete(e))},openImageInNewTab(e){window.open(e,"_blank")},closeSessionImagePopups(e){const t=[];for(const[s,n]of this.imagePopups)n.sessionId===e&&t.push(s);for(const s of t)this.closeImagePopup(s)},async loadMuxSessions(){try{const t=await(await fetch("/api/mux-sessions")).json();this.muxSessions=t.data?.sessions||[],this.renderMuxSessions()}catch(e){console.error("Failed to load mux sessions:",e)}},killAllMuxSessions(){const e=this.muxSessions?.length||0;if(e===0){alert("No sessions to kill");return}document.getElementById("killAllCount").textContent=e;const t=document.getElementById("killAllModal");t.classList.add("active"),this.activeFocusTrap=new FocusTrap(t),this.activeFocusTrap.activate()},closeKillAllModal(){document.getElementById("killAllModal").classList.remove("active"),this.activeFocusTrap&&(this.activeFocusTrap.deactivate(),this.activeFocusTrap=null)},async confirmKillAll(e){this.closeKillAllModal();try{if(e){if((await(await fetch("/api/sessions",{method:"DELETE"})).json()).success){this.sessions.clear(),this.muxSessions=[],this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.renderMuxSessions(),this._resetTerminalForReplay(),this.toast("All sessions and tmux killed","success")}}else{this.sessions.clear(),this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this._resetTerminalForReplay(),this.toast("All tabs removed, tmux still running","info")}}catch(t){console.error("Failed to kill sessions:",t),this.toast("Failed to kill sessions: "+t.message,"error")}},renderMuxSessions(){this._debouncedCall("muxSessions",this._renderMuxSessionsImmediate)},_renderMuxSessionsImmediate(){const e=document.getElementById("muxSessionsBody");if(!this.muxSessions||this.muxSessions.length===0){e.innerHTML='<div class="monitor-empty">No mux sessions</div>';return}let t="";for(const s of this.muxSessions){const n=s.stats||{memoryMB:0,cpuPercent:0,childCount:0},i=this.sessions.get(s.sessionId),o=i?i.status:"unknown",l=i?i.isWorking:!1;let a,r;o==="idle"&&!l?(a="IDLE",r="status-idle"):o==="busy"||l?(a="WORKING",r="status-working"):o==="stopped"?(a="STOPPED",r="status-stopped"):(a=o.toUpperCase(),r="");const c=i&&i.tokens?i.tokens:null,h=i?i.totalCost:0,d=i&&i.cliModel||"",u=d.includes("opus")?"opus":d.includes("sonnet")?"sonnet":d.includes("haiku")?"haiku":"",p=i?i.ralphTodoStats:null;let f="";if(p&&p.total>0){const C=Math.round(p.completed/p.total*100);f=`<span class="process-stat todo-progress">${p.completed}/${p.total} (${C}%)</span>`}let w="";c&&c.total>0&&(w=`<span class="process-stat tokens">${(c.total/1e3).toFixed(1)}k tok</span>`);let y="";h>0&&(y=`<span class="process-stat cost">$${h.toFixed(2)}</span>`);let v="";u&&(v=`<span class="monitor-model-badge ${u}">${u}</span>`);const g=escapeHtml(JSON.stringify(s.sessionId));t+=`
331
337
  <div class="process-item process-item-clickable" onclick="app.selectSession(${g})" title="Switch to session">
332
338
  <span class="monitor-status-badge ${r}">${a}</span>
333
339
  <div class="process-info">
@@ -336,15 +342,15 @@ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFi
336
342
  ${w}
337
343
  ${y}
338
344
  ${f}
339
- <span class="process-stat memory">${i.memoryMB}MB</span>
340
- <span class="process-stat cpu">${i.cpuPercent}%</span>
345
+ <span class="process-stat memory">${n.memoryMB}MB</span>
346
+ <span class="process-stat cpu">${n.cpuPercent}%</span>
341
347
  </div>
342
348
  </div>
343
349
  <div class="process-actions">
344
350
  <button class="btn-toolbar btn-sm btn-danger" onclick="event.stopPropagation(); app.killMuxSession(${g})" title="Kill session">Kill</button>
345
351
  </div>
346
352
  </div>
347
- `}e.innerHTML=t},renderMonitorSubagents(){const e=document.getElementById("monitorSubagentsBody"),t=document.getElementById("monitorSubagentStats");if(!e)return;const s=Array.from(this.subagents.values()),i=s.filter(o=>o.status==="active"||o.status==="idle").length;if(t&&(t.textContent=`${s.length} tracked`+(i>0?`, ${i} active`:"")),s.length===0){e.innerHTML='<div class="monitor-empty">No background agents</div>';return}let n="";for(const o of s){const l=o.status==="active"?"active":o.status==="idle"?"idle":"completed",a=o.modelShort?`<span class="model-badge ${o.modelShort}">${o.modelShort}</span>`:"",r=o.description?escapeHtml(o.description.substring(0,40)):o.agentId;n+=`
353
+ `}e.innerHTML=t},renderMonitorSubagents(){const e=document.getElementById("monitorSubagentsBody"),t=document.getElementById("monitorSubagentStats");if(!e)return;const s=Array.from(this.subagents.values()),n=s.filter(o=>o.status==="active"||o.status==="idle").length;if(t&&(t.textContent=`${s.length} tracked`+(n>0?`, ${n} active`:"")),s.length===0){e.innerHTML='<div class="monitor-empty">No background agents</div>';return}let i="";for(const o of s){const l=o.status==="active"?"active":o.status==="idle"?"idle":"completed",a=o.modelShort?`<span class="model-badge ${o.modelShort}">${o.modelShort}</span>`:"",r=o.description?escapeHtml(o.description.substring(0,40)):o.agentId;i+=`
348
354
  <div class="process-item">
349
355
  <span class="process-mode ${l}">${o.status}</span>
350
356
  <div class="process-info">
@@ -358,4 +364,4 @@ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFi
358
364
  ${o.status!=="completed"?`<button class="btn-toolbar btn-sm btn-danger" onclick="app.killSubagent(${escapeHtml(JSON.stringify(o.agentId))})" title="Kill agent">Kill</button>`:""}
359
365
  </div>
360
366
  </div>
361
- `}e.innerHTML=n},async killMuxSession(e){if(confirm("Kill this mux session?")){try{await this.closeSession(e,!0)}catch{try{await fetch(`/api/mux-sessions/${e}`,{method:"DELETE"})}catch{}this.showToast("Tmux session killed","success")}this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e),this.renderMuxSessions()}},async reconcileMuxSessions(){try{const t=await(await fetch("/api/mux-sessions/reconcile",{method:"POST"})).json();t.data?.dead&&t.data.dead.length>0?(this.showToast(`Found ${t.data.dead.length} dead mux session(s)`,"warning"),await this.loadMuxSessions()):this.showToast("All mux sessions are alive","success")}catch{this.showToast("Failed to reconcile mux sessions","error")}},toggleNotifications(){this.notificationManager?.toggleDrawer()},async launchMultiMonitor(){try{const e=await fetch("/api/system/span-displays",{method:"POST"}),t=await e.json().catch(()=>({}));e.ok&&t.success?this.showToast("Opening Codeman across all displays\u2026","success"):this.showToast(t.error||"Could not open spanning window","error")}catch(e){this.showToast("Could not open spanning window: "+(e?.message||e),"error")}},toast(e,t="info"){return this.showToast(e,t)},showToast(e,t="info",s={}){const{duration:i=this.notificationManager?.getToastDurationMs?.()??3e3,action:n}=s,o=document.createElement("div");o.className=`toast toast-${t}`;const l=document.createElement("span");if(l.className="toast-message",l.textContent=e,o.appendChild(l),n){const h=document.createElement("button");h.textContent=n.label,h.style.cssText="margin-left:12px;padding:2px 10px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:3px;color:inherit;cursor:pointer;font-size:12px",h.onclick=d=>{d.stopPropagation(),n.onClick(),o.remove()},o.appendChild(h)}let a=null;const r=()=>{a&&clearTimeout(a),o.classList.remove("show"),setTimeout(()=>o.remove(),200)},c=document.createElement("button");return c.className="toast-close",c.textContent="\xD7",c.setAttribute("aria-label","Dismiss"),c.onclick=h=>{h.stopPropagation(),r()},o.appendChild(c),this._toastStack().appendChild(o),requestAnimationFrame(()=>o.classList.add("show")),i>0&&(a=setTimeout(r,i)),{dismiss:r,setMessage:h=>{l.textContent=h}}},_toastStack(){return this._toastContainer||(this._toastContainer=document.querySelector(".toast-container"),this._toastContainer||(this._toastContainer=document.createElement("div"),this._toastContainer.className="toast-container",document.body.appendChild(this._toastContainer))),this._toastContainer},showSecurityNotice(e,t={}){const s=this._noticeCard("security-notice",t.onClose),i=this._noticeEl("div","security-notice-main");i.append(this._noticeEl("div","security-notice-eyebrow","Security notice")),i.append(...this._noticeTextBlock(e));const n=this._noticeEl("div","security-notice-actions"),o=this._noticeLinkButton(e,s,()=>s.close("link"));return o&&n.append(o),n.append(this._noticeButton("security-notice-quiet","Dismiss",()=>s.close("dismiss"))),i.append(n),s.el.append(this._noticeIcon("shield","security-notice-icon"),i,s.closeButton),s.mount(),{dismiss:()=>s.close(null)}},showUpdateNotice({text:e,releaseUrl:t,notices:s,onNoticeSeen:i}){const n=r=>{try{i?.(r)}catch(c){console.error("[notice] onNoticeSeen failed:",c)}},o=this._noticeCard("security-notice update-notice",r=>{if(r==="close")for(const c of s)n(c.id)}),l=this._noticeEl("div","security-notice-main");l.append(this._noticeEl("p","update-notice-text",e));const a=this._noticeEl("div","security-notice-actions");for(const r of s){const c=this._noticeEl("section","security-notice-section"),h=this._noticeEl("div","security-notice-section-head");h.append(this._noticeIcon("shield"),this._noticeEl("span","security-notice-eyebrow","Security notice")),c.append(h,...this._noticeTextBlock(r)),l.append(c);const d=this._noticeLinkButton(r,o,()=>{n(r.id),o.close("link")});d&&a.append(d)}return a.append(this._noticeButton("security-notice-secondary","See what's new",o.act(()=>window.open(t,"_blank","noopener,noreferrer")))),l.append(a),o.el.append(this._noticeIcon("update","security-notice-icon update-notice-icon"),l,o.closeButton),o.mount(),{dismiss:()=>o.close(null)}},_noticeCard(e,t){const s=this._noticeEl("div",e);s.setAttribute("role","alert"),s.setAttribute("aria-live","assertive");let i=!1;const n=r=>{if(!i&&(i=!0,s.inert=!0,s.classList.remove("show"),setTimeout(()=>s.remove(),200),r&&typeof t=="function"))try{t(r)}catch(c){console.error("[notice] onClose failed:",c)}},o=this._noticeButton("security-notice-close","\xD7",()=>n("close"));return o.setAttribute("aria-label","Close"),{el:s,closeButton:o,close:n,mount:()=>{this._toastStack().appendChild(s),requestAnimationFrame(()=>s.classList.add("show"))},act:r=>()=>{i||r()}}},_noticeTextBlock(e){const t=[];return e.title&&t.push(this._noticeEl("div","security-notice-title",e.title,!0)),t.push(this._noticeEl("p","security-notice-body",e.message,!0)),t},_noticeLinkButton(e,t,s){const i=e.url;return window.CodemanSecurityNotices?.urlOk?.(i)?this._noticeButton("security-notice-primary",e.label,t.act(()=>{window.open(i,"_blank","noopener,noreferrer"),s()}),!0):null},_noticeButton(e,t,s,i=!1){const n=this._noticeEl("button",e,t,i);return n.type="button",n.onclick=o=>{o.stopPropagation(),s()},n},_noticeEl(e,t,s,i=!1){const n=document.createElement(e);return n.className=t,s!==void 0&&(n.textContent=s),i&&n.setAttribute("data-i18n-skip",""),n},_noticeIcon(e,t){const s="http://www.w3.org/2000/svg",i=document.createElementNS(s,"svg");for(const[l,a]of Object.entries({viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round","aria-hidden":"true",focusable:"false"}))i.setAttribute(l,a);const n=e==="shield"?[["path",{d:"M12 3 4.5 6v5.2c0 4.5 3.1 8.4 7.5 9.8 4.4-1.4 7.5-5.3 7.5-9.8V6L12 3z"}],["path",{d:"M12 8.5v4.5"}],["path",{d:"M12 16.5h.01"}]]:[["circle",{cx:"12",cy:"12",r:"9"}],["path",{d:"M12 16.5v-9"}],["path",{d:"m8.5 11 3.5-3.5 3.5 3.5"}]];for(const[l,a]of n){const r=document.createElementNS(s,l);for(const[c,h]of Object.entries(a))r.setAttribute(c,h);i.appendChild(r)}if(!t)return i;const o=this._noticeEl("span",t);return o.setAttribute("aria-hidden","true"),o.appendChild(i),o},_showCenterStatus(e,t={}){const{type:s="info",onCancel:i}=t;let n=document.getElementById("customModelCenterStatus");n||(n=document.createElement("div"),n.id="customModelCenterStatus",document.body.appendChild(n)),n._hideTimer&&(clearTimeout(n._hideTimer),n._hideTimer=null),n.className=`center-status-banner center-status-${s}`,n.innerHTML="";const o=()=>{n.classList.remove("show"),n._hideTimer=setTimeout(()=>{n.hidden=!0,n._hideTimer=null},200)};if(s!=="error"){const a=document.createElement("span");a.className="center-status-spinner",a.setAttribute("aria-hidden","true"),n.appendChild(a)}const l=document.createElement("span");if(l.className="center-status-text",l.textContent=e,n.appendChild(l),s==="error"){const a=document.createElement("button");a.className="center-status-close",a.textContent="\xD7",a.setAttribute("aria-label","Dismiss"),a.onclick=r=>{r.stopPropagation(),o()},n.appendChild(a)}else if(i){const a=document.createElement("button");a.className="center-status-cancel",a.textContent="Cancel",a.onclick=r=>{r.stopPropagation(),i()},n.appendChild(a)}return n.hidden=!1,requestAnimationFrame(()=>n.classList.add("show")),{dismiss:o,setMessage:a=>{const r=n.querySelector(".center-status-text");r&&(r.textContent=a)}}},startSystemStatsPolling(){this.stopSystemStatsPolling(),this.fetchSystemStats(),this.systemStatsInterval=setInterval(()=>{this.fetchSystemStats()},2e3)},stopSystemStatsPolling(){this.systemStatsInterval&&(clearInterval(this.systemStatsInterval),this.systemStatsInterval=null)},async fetchSystemStats(){const e=document.getElementById("headerSystemStats");if(!(!e||e.style.display==="none"))try{const s=await(await fetch("/api/system/stats")).json();this.updateSystemStatsDisplay(s.data)}catch{}},updateSystemStatsDisplay(e){const t=this.$("statCpu"),s=this.$("statCpuBar"),i=this.$("statMem"),n=this.$("statMemBar");if(t&&s&&(t.textContent=`${e.cpu}%`,s.style.width=`${Math.min(100,e.cpu)}%`,s.classList.remove("medium","high"),t.classList.remove("high"),e.cpu>80?(s.classList.add("high"),t.classList.add("high")):e.cpu>50&&s.classList.add("medium")),this._setStatRing("statCpuRing",e.cpu),this._setStatRing("statMemRing",e.memory?.percent),i&&n){const o=(e.memory.usedMB/1024).toFixed(1);i.textContent=`${o}G`,n.style.width=`${Math.min(100,e.memory.percent)}%`,n.classList.remove("medium","high"),i.classList.remove("high"),e.memory.percent>80?(n.classList.add("high"),i.classList.add("high")):e.memory.percent>50&&n.classList.add("medium")}},_setStatRing(e,t){const s=this.$(e);if(!s)return;const i=Number(t),n=Number.isFinite(i)?Math.round(Math.min(100,Math.max(0,i))):0;s.style.setProperty("--pu",String(n)),s.classList.toggle("high",n>80)},async _onClipboardWrite(e){const t=e?.text;if(typeof t=="string")try{await navigator.clipboard.writeText(t),this.showToast(`Copied to clipboard (${t.length} chars)`,"success")}catch{this._showClipboardFallback(t)}},_showClipboardFallback(e){const t=document.createElement("div");t.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:10000;display:flex;align-items:center;justify-content:center";const s=document.createElement("div");s.style.cssText="background:#1e1e2e;border:1px solid #444;border-radius:8px;padding:16px;max-width:600px;width:90%;max-height:60vh;display:flex;flex-direction:column;gap:12px";const i=document.createElement("div");i.style.cssText="display:flex;justify-content:space-between;align-items:center";const n=document.createElement("span");n.style.cssText="color:#cdd6f4;font-weight:600",n.textContent="Clipboard (browser blocked auto-copy)";const o=document.createElement("button");o.style.cssText="background:none;border:none;color:#cdd6f4;font-size:18px;cursor:pointer",o.textContent="\xD7",i.appendChild(n),i.appendChild(o);const l=document.createElement("textarea");l.readOnly=!0,l.style.cssText="background:#181825;color:#cdd6f4;border:1px solid #555;border-radius:4px;padding:8px;font-family:monospace;font-size:13px;resize:none;height:200px;width:100%",l.value=e;const a=document.createElement("button");a.style.cssText="background:#89b4fa;color:#1e1e2e;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-weight:600",a.textContent="Copy to Clipboard",s.appendChild(i),s.appendChild(l),s.appendChild(a),t.appendChild(s),document.body.appendChild(t),a.onclick=async()=>{try{await navigator.clipboard.writeText(e),this.showToast("Copied to clipboard","success"),t.remove()}catch{l.select(),document.execCommand("copy"),this.showToast("Copied (fallback)","success"),t.remove()}};const r=()=>t.remove();o.onclick=r,t.onclick=c=>{c.target===t&&r()}}});
367
+ `}e.innerHTML=i},async killMuxSession(e){if(confirm("Kill this mux session?")){try{await this.closeSession(e,!0)}catch{try{await fetch(`/api/mux-sessions/${e}`,{method:"DELETE"})}catch{}this.showToast("Tmux session killed","success")}this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e),this.renderMuxSessions()}},async reconcileMuxSessions(){try{const t=await(await fetch("/api/mux-sessions/reconcile",{method:"POST"})).json();t.data?.dead&&t.data.dead.length>0?(this.showToast(`Found ${t.data.dead.length} dead mux session(s)`,"warning"),await this.loadMuxSessions()):this.showToast("All mux sessions are alive","success")}catch{this.showToast("Failed to reconcile mux sessions","error")}},toggleNotifications(){this.notificationManager?.toggleDrawer()},async launchMultiMonitor(){try{const e=await fetch("/api/system/span-displays",{method:"POST"}),t=await e.json().catch(()=>({}));e.ok&&t.success?this.showToast("Opening Codeman across all displays\u2026","success"):this.showToast(t.error||"Could not open spanning window","error")}catch(e){this.showToast("Could not open spanning window: "+(e?.message||e),"error")}},toast(e,t="info"){return this.showToast(e,t)},showToast(e,t="info",s={}){const{duration:n=this.notificationManager?.getToastDurationMs?.()??3e3,action:i}=s,o=document.createElement("div");o.className=`toast toast-${t}`;const l=document.createElement("span");if(l.className="toast-message",l.textContent=e,o.appendChild(l),i){const h=document.createElement("button");h.textContent=i.label,h.style.cssText="margin-left:12px;padding:2px 10px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:3px;color:inherit;cursor:pointer;font-size:12px",h.onclick=d=>{d.stopPropagation(),i.onClick(),o.remove()},o.appendChild(h)}let a=null;const r=()=>{a&&clearTimeout(a),o.classList.remove("show"),setTimeout(()=>o.remove(),200)},c=document.createElement("button");return c.className="toast-close",c.textContent="\xD7",c.setAttribute("aria-label","Dismiss"),c.onclick=h=>{h.stopPropagation(),r()},o.appendChild(c),this._toastStack().appendChild(o),requestAnimationFrame(()=>o.classList.add("show")),n>0&&(a=setTimeout(r,n)),{dismiss:r,setMessage:h=>{l.textContent=h}}},_toastStack(){return this._toastContainer||(this._toastContainer=document.querySelector(".toast-container"),this._toastContainer||(this._toastContainer=document.createElement("div"),this._toastContainer.className="toast-container",document.body.appendChild(this._toastContainer))),this._toastContainer},showSecurityNotice(e,t={}){const s=this._noticeCard("security-notice",t.onClose),n=this._noticeEl("div","security-notice-main");n.append(this._noticeEl("div","security-notice-eyebrow","Security notice")),n.append(...this._noticeTextBlock(e));const i=this._noticeEl("div","security-notice-actions"),o=this._noticeLinkButton(e,s,()=>s.close("link"));return o&&i.append(o),i.append(this._noticeButton("security-notice-quiet","Dismiss",()=>s.close("dismiss"))),n.append(i),s.el.append(this._noticeIcon("shield","security-notice-icon"),n,s.closeButton),s.mount(),{dismiss:()=>s.close(null)}},showUpdateNotice({text:e,releaseUrl:t,notices:s,onNoticeSeen:n}){const i=r=>{try{n?.(r)}catch(c){console.error("[notice] onNoticeSeen failed:",c)}},o=this._noticeCard("security-notice update-notice",r=>{if(r==="close")for(const c of s)i(c.id)}),l=this._noticeEl("div","security-notice-main");l.append(this._noticeEl("p","update-notice-text",e));const a=this._noticeEl("div","security-notice-actions");for(const r of s){const c=this._noticeEl("section","security-notice-section"),h=this._noticeEl("div","security-notice-section-head");h.append(this._noticeIcon("shield"),this._noticeEl("span","security-notice-eyebrow","Security notice")),c.append(h,...this._noticeTextBlock(r)),l.append(c);const d=this._noticeLinkButton(r,o,()=>{i(r.id),o.close("link")});d&&a.append(d)}return a.append(this._noticeButton("security-notice-secondary","See what's new",o.act(()=>window.open(t,"_blank","noopener,noreferrer")))),l.append(a),o.el.append(this._noticeIcon("update","security-notice-icon update-notice-icon"),l,o.closeButton),o.mount(),{dismiss:()=>o.close(null)}},_noticeCard(e,t){const s=this._noticeEl("div",e);s.setAttribute("role","alert"),s.setAttribute("aria-live","assertive");let n=!1;const i=r=>{if(!n&&(n=!0,s.inert=!0,s.classList.remove("show"),setTimeout(()=>s.remove(),200),r&&typeof t=="function"))try{t(r)}catch(c){console.error("[notice] onClose failed:",c)}},o=this._noticeButton("security-notice-close","\xD7",()=>i("close"));return o.setAttribute("aria-label","Close"),{el:s,closeButton:o,close:i,mount:()=>{this._toastStack().appendChild(s),requestAnimationFrame(()=>s.classList.add("show"))},act:r=>()=>{n||r()}}},_noticeTextBlock(e){const t=[];return e.title&&t.push(this._noticeEl("div","security-notice-title",e.title,!0)),t.push(this._noticeEl("p","security-notice-body",e.message,!0)),t},_noticeLinkButton(e,t,s){const n=e.url;return window.CodemanSecurityNotices?.urlOk?.(n)?this._noticeButton("security-notice-primary",e.label,t.act(()=>{window.open(n,"_blank","noopener,noreferrer"),s()}),!0):null},_noticeButton(e,t,s,n=!1){const i=this._noticeEl("button",e,t,n);return i.type="button",i.onclick=o=>{o.stopPropagation(),s()},i},_noticeEl(e,t,s,n=!1){const i=document.createElement(e);return i.className=t,s!==void 0&&(i.textContent=s),n&&i.setAttribute("data-i18n-skip",""),i},_noticeIcon(e,t){const s="http://www.w3.org/2000/svg",n=document.createElementNS(s,"svg");for(const[l,a]of Object.entries({viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round","aria-hidden":"true",focusable:"false"}))n.setAttribute(l,a);const i=e==="shield"?[["path",{d:"M12 3 4.5 6v5.2c0 4.5 3.1 8.4 7.5 9.8 4.4-1.4 7.5-5.3 7.5-9.8V6L12 3z"}],["path",{d:"M12 8.5v4.5"}],["path",{d:"M12 16.5h.01"}]]:[["circle",{cx:"12",cy:"12",r:"9"}],["path",{d:"M12 16.5v-9"}],["path",{d:"m8.5 11 3.5-3.5 3.5 3.5"}]];for(const[l,a]of i){const r=document.createElementNS(s,l);for(const[c,h]of Object.entries(a))r.setAttribute(c,h);n.appendChild(r)}if(!t)return n;const o=this._noticeEl("span",t);return o.setAttribute("aria-hidden","true"),o.appendChild(n),o},_showCenterStatus(e,t={}){const{type:s="info",onCancel:n}=t;let i=document.getElementById("customModelCenterStatus");i||(i=document.createElement("div"),i.id="customModelCenterStatus",document.body.appendChild(i)),i._hideTimer&&(clearTimeout(i._hideTimer),i._hideTimer=null),i.className=`center-status-banner center-status-${s}`,i.innerHTML="";const o=()=>{i.classList.remove("show"),i._hideTimer=setTimeout(()=>{i.hidden=!0,i._hideTimer=null},200)};if(s!=="error"){const a=document.createElement("span");a.className="center-status-spinner",a.setAttribute("aria-hidden","true"),i.appendChild(a)}const l=document.createElement("span");if(l.className="center-status-text",l.textContent=e,i.appendChild(l),s==="error"){const a=document.createElement("button");a.className="center-status-close",a.textContent="\xD7",a.setAttribute("aria-label","Dismiss"),a.onclick=r=>{r.stopPropagation(),o()},i.appendChild(a)}else if(n){const a=document.createElement("button");a.className="center-status-cancel",a.textContent="Cancel",a.onclick=r=>{r.stopPropagation(),n()},i.appendChild(a)}return i.hidden=!1,requestAnimationFrame(()=>i.classList.add("show")),{dismiss:o,setMessage:a=>{const r=i.querySelector(".center-status-text");r&&(r.textContent=a)}}},startSystemStatsPolling(){this.stopSystemStatsPolling(),this.fetchSystemStats(),this.systemStatsInterval=setInterval(()=>{this.fetchSystemStats()},2e3)},stopSystemStatsPolling(){this.systemStatsInterval&&(clearInterval(this.systemStatsInterval),this.systemStatsInterval=null)},async fetchSystemStats(){const e=document.getElementById("headerSystemStats");if(!(!e||e.style.display==="none")&&!this._systemStatsPending){this._systemStatsPending=!0;try{const t=this.loadAppSettingsFromStorage?.()??{},s=["gpu",t.showGpuStats,"cpumhz",t.showCpuMhz],n=[];for(let l=0;l<s.length;l+=2)s[l+1]===!0&&n.push(`${s[l]}=1`);const o=await(await fetch("/api/system/stats"+(n.length?"?"+n.join("&"):""),{signal:typeof AbortSignal<"u"&&typeof AbortSignal.timeout=="function"?AbortSignal.timeout(8e3):void 0})).json();this.updateSystemStatsDisplay(o.data)}catch{}finally{this._systemStatsPending=!1}}},updateSystemStatsDisplay(e){const t=this.$("statCpu"),s=this.$("statCpuBar"),n=this.$("statMem"),i=this.$("statMemBar");if(t&&s&&(t.textContent=`${e.cpu}%`,s.style.width=`${Math.min(100,e.cpu)}%`,s.classList.remove("medium","high"),t.classList.remove("high"),e.cpu>80?(s.classList.add("high"),t.classList.add("high")):e.cpu>50&&s.classList.add("medium")),this._setStatRing("statCpuRing",e.cpu),this._setStatRing("statMemRing",e.memory?.percent),n&&i){const o=(e.memory.usedMB/1024).toFixed(1);n.textContent=`${o}G`,i.style.width=`${Math.min(100,e.memory.percent)}%`,i.classList.remove("medium","high"),n.classList.remove("high"),e.memory.percent>80?(i.classList.add("high"),n.classList.add("high")):e.memory.percent>50&&i.classList.add("medium")}this._updateHostSensors(e)},_updateHostSensors(e){const t=this.loadAppSettingsFromStorage?.()??{},s=(r,c)=>{const h=this.$(r);h&&(h.hidden=!c)},n=(r,c,h,d,u)=>{const p=this.$(r);p&&(p.textContent=u,p.classList.toggle("high",d>80)),this._setStatRing(c,d);const f=this.$(h);f&&(f.style.width=`${Math.min(100,d)}%`)},i=t.showGpuStats===!0?e.gpu:void 0;if(s("statGpuItem",!!i),i&&n("statGpu","statGpuRing","statGpuBar",i.percent,`${i.percent}%`),s("statVramItem",!!(i&&i.memUsedMB!==void 0)),i&&i.memUsedMB!==void 0){const r=`${(i.memUsedMB/1024).toFixed(1)}G`,c=this.$("statVramRing");if(this.$("statVramItem")?.classList.toggle("stat-item--ringless",i.memPercent===void 0),i.memPercent!==void 0)n("statVram","statVramRing","statVramBar",i.memPercent,r),c&&(c.style.display="");else{const h=this.$("statVram");h&&(h.textContent=r),c&&(c.style.display="none")}}s("statGpuMhzItem",!!(i&&i.mhz!==void 0));const o=i&&i.mhz!==void 0?this.$("statGpuMhz"):null;o&&(o.textContent=`${i.mhz} MHz`);const l=t.showCpuMhz===!0&&e.cpuMhz!==void 0?e.cpuMhz:void 0;s("statCpuMhzItem",l!==void 0);const a=l!==void 0?this.$("statCpuMhz"):null;a&&(a.textContent=`${l} MHz`)},_setStatRing(e,t){const s=this.$(e);if(!s)return;const n=Number(t),i=Number.isFinite(n)?Math.round(Math.min(100,Math.max(0,n))):0;s.style.setProperty("--pu",String(i)),s.classList.toggle("high",i>80)},async _onClipboardWrite(e){const t=e?.text;if(typeof t=="string")try{await navigator.clipboard.writeText(t),this.showToast(`Copied to clipboard (${t.length} chars)`,"success")}catch{this._showClipboardFallback(t)}},_showClipboardFallback(e){const t=document.createElement("div");t.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:10000;display:flex;align-items:center;justify-content:center";const s=document.createElement("div");s.style.cssText="background:#1e1e2e;border:1px solid #444;border-radius:8px;padding:16px;max-width:600px;width:90%;max-height:60vh;display:flex;flex-direction:column;gap:12px";const n=document.createElement("div");n.style.cssText="display:flex;justify-content:space-between;align-items:center";const i=document.createElement("span");i.style.cssText="color:#cdd6f4;font-weight:600",i.textContent="Clipboard (browser blocked auto-copy)";const o=document.createElement("button");o.style.cssText="background:none;border:none;color:#cdd6f4;font-size:18px;cursor:pointer",o.textContent="\xD7",n.appendChild(i),n.appendChild(o);const l=document.createElement("textarea");l.readOnly=!0,l.style.cssText="background:#181825;color:#cdd6f4;border:1px solid #555;border-radius:4px;padding:8px;font-family:monospace;font-size:13px;resize:none;height:200px;width:100%",l.value=e;const a=document.createElement("button");a.style.cssText="background:#89b4fa;color:#1e1e2e;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-weight:600",a.textContent="Copy to Clipboard",s.appendChild(n),s.appendChild(l),s.appendChild(a),t.appendChild(s),document.body.appendChild(t),a.onclick=async()=>{try{await navigator.clipboard.writeText(e),this.showToast("Copied to clipboard","success"),t.remove()}catch{l.select(),document.execCommand("copy"),this.showToast("Copied (fallback)","success"),t.remove()}};const r=()=>t.remove();o.onclick=r,t.onclick=c=>{c.target===t&&r()}}});