aicodeman 1.35.0 → 1.41.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.
- package/README.md +33 -7
- package/dist/attachment-registry.d.ts +6 -0
- package/dist/attachment-registry.d.ts.map +1 -1
- package/dist/attachment-registry.js +9 -3
- package/dist/attachment-registry.js.map +1 -1
- package/dist/cli-agent.d.ts +225 -0
- package/dist/cli-agent.d.ts.map +1 -0
- package/dist/cli-agent.js +767 -0
- package/dist/cli-agent.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -32
- package/dist/cli.js.map +1 -1
- package/dist/codeman-credentials.d.ts +27 -0
- package/dist/codeman-credentials.d.ts.map +1 -0
- package/dist/codeman-credentials.js +66 -0
- package/dist/codeman-credentials.js.map +1 -0
- package/dist/config/cli-registry/patterns.d.ts +6 -0
- package/dist/config/cli-registry/patterns.d.ts.map +1 -1
- package/dist/config/cli-registry/patterns.js +13 -0
- package/dist/config/cli-registry/patterns.js.map +1 -1
- package/dist/config/cli-registry/schema.d.ts +15 -0
- package/dist/config/cli-registry/schema.d.ts.map +1 -1
- package/dist/config/cli-registry/schema.js +63 -2
- package/dist/config/cli-registry/schema.js.map +1 -1
- package/dist/config/cli-registry/stock.d.ts.map +1 -1
- package/dist/config/cli-registry/stock.js +180 -7
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/config/cli-registry/types.d.ts +105 -7
- package/dist/config/cli-registry/types.d.ts.map +1 -1
- package/dist/deepseek-route-config.d.ts +110 -0
- package/dist/deepseek-route-config.d.ts.map +1 -0
- package/dist/deepseek-route-config.js +477 -0
- package/dist/deepseek-route-config.js.map +1 -0
- package/dist/git-clone.d.ts.map +1 -1
- package/dist/git-clone.js +4 -0
- package/dist/git-clone.js.map +1 -1
- package/dist/git-workspace-status.d.ts +31 -5
- package/dist/git-workspace-status.d.ts.map +1 -1
- package/dist/git-workspace-status.js +49 -29
- package/dist/git-workspace-status.js.map +1 -1
- package/dist/image-watcher.d.ts.map +1 -1
- package/dist/image-watcher.js +6 -2
- package/dist/image-watcher.js.map +1 -1
- package/dist/mcp-sync-targets.d.ts +34 -0
- package/dist/mcp-sync-targets.d.ts.map +1 -0
- package/dist/mcp-sync-targets.js +55 -0
- package/dist/mcp-sync-targets.js.map +1 -0
- package/dist/mcp-sync.d.ts +2 -1
- package/dist/mcp-sync.d.ts.map +1 -1
- package/dist/mcp-sync.js +62 -1
- package/dist/mcp-sync.js.map +1 -1
- package/dist/model-config-resolvers.d.ts +29 -0
- package/dist/model-config-resolvers.d.ts.map +1 -0
- package/dist/model-config-resolvers.js +34 -0
- package/dist/model-config-resolvers.js.map +1 -0
- package/dist/session-display-model.d.ts +110 -0
- package/dist/session-display-model.d.ts.map +1 -0
- package/dist/session-display-model.js +154 -0
- package/dist/session-display-model.js.map +1 -0
- package/dist/session.d.ts +145 -8
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +290 -39
- package/dist/session.js.map +1 -1
- package/dist/subagent-watcher.d.ts.map +1 -1
- package/dist/subagent-watcher.js +29 -6
- package/dist/subagent-watcher.js.map +1 -1
- package/dist/templates/case-template.md +2 -0
- package/dist/tmux-manager.d.ts +5 -0
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +47 -22
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tui/tui-client.d.ts +3 -17
- package/dist/tui/tui-client.d.ts.map +1 -1
- package/dist/tui/tui-client.js +3 -44
- package/dist/tui/tui-client.js.map +1 -1
- package/dist/types/session.d.ts +28 -1
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/dist/types/tools.d.ts +1 -1
- package/dist/types/tools.d.ts.map +1 -1
- package/dist/utils/deepseek-cli-resolver.d.ts +8 -0
- package/dist/utils/deepseek-cli-resolver.d.ts.map +1 -1
- package/dist/utils/deepseek-cli-resolver.js +18 -2
- package/dist/utils/deepseek-cli-resolver.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/process-exit-wait.d.ts +40 -0
- package/dist/utils/process-exit-wait.d.ts.map +1 -0
- package/dist/utils/process-exit-wait.js +68 -0
- package/dist/utils/process-exit-wait.js.map +1 -0
- package/dist/web/launch-defaults.d.ts +22 -0
- package/dist/web/launch-defaults.d.ts.map +1 -0
- package/dist/web/launch-defaults.js +46 -0
- package/dist/web/launch-defaults.js.map +1 -0
- package/dist/web/paste-image-gc.d.ts +46 -6
- package/dist/web/paste-image-gc.d.ts.map +1 -1
- package/dist/web/paste-image-gc.js +106 -32
- package/dist/web/paste-image-gc.js.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.6f8552e1.js +43 -0
- package/dist/web/public/app.6f8552e1.js.br +0 -0
- package/dist/web/public/app.6f8552e1.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/{constants.d95fade9.js → constants.bc9c1f63.js} +1276 -127
- package/dist/web/public/constants.bc9c1f63.js.br +0 -0
- package/dist/web/public/constants.bc9c1f63.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js +491 -43
- package/dist/web/public/entrance-animations.js.br +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/git-status-ui.js +55 -9
- package/dist/web/public/git-status-ui.js.br +0 -0
- package/dist/web/public/git-status-ui.js.gz +0 -0
- package/dist/web/public/home-sessions.js +13 -9
- package/dist/web/public/home-sessions.js.br +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/host-wake-ui.js.gz +0 -0
- package/dist/web/public/i18n.a9840ea2.js +2 -0
- package/dist/web/public/i18n.a9840ea2.js.br +0 -0
- package/dist/web/public/i18n.a9840ea2.js.gz +0 -0
- package/dist/web/public/{image-input.a216cf9e.js → image-input.e00471c6.js} +21 -9
- package/dist/web/public/image-input.e00471c6.js.br +0 -0
- package/dist/web/public/image-input.e00471c6.js.gz +0 -0
- package/dist/web/public/index.html +250 -59
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.c1e7c7b7.js.gz +0 -0
- package/dist/web/public/{mobile-handlers.23a85db1.js → mobile-handlers.0ef9c311.js} +20 -0
- package/dist/web/public/mobile-handlers.0ef9c311.js.br +0 -0
- package/dist/web/public/mobile-handlers.0ef9c311.js.gz +0 -0
- package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.111b187d.css +1 -0
- package/dist/web/public/mobile.111b187d.css.br +0 -0
- package/dist/web/public/mobile.111b187d.css.gz +0 -0
- package/dist/web/public/{notification-manager.50bb87d8.js → notification-manager.feb82c04.js} +19 -2
- package/dist/web/public/notification-manager.feb82c04.js.br +0 -0
- package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.6a5898d9.js → panels-ui.71846fcb.js} +4 -4
- package/dist/web/public/panels-ui.71846fcb.js.br +0 -0
- package/dist/web/public/panels-ui.71846fcb.js.gz +0 -0
- package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
- package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/reboot-restore-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
- package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
- package/dist/web/public/session-lineage.js +229 -86
- package/dist/web/public/session-lineage.js.br +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/session-ui.f731602c.js +100 -0
- package/dist/web/public/session-ui.f731602c.js.br +0 -0
- package/dist/web/public/session-ui.f731602c.js.gz +0 -0
- package/dist/web/public/settings-ui.4e33390f.js +97 -0
- package/dist/web/public/settings-ui.4e33390f.js.br +0 -0
- package/dist/web/public/settings-ui.4e33390f.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview-worker.js +290 -0
- package/dist/web/public/spreadsheet-preview-worker.js.br +0 -0
- package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview.af82fa2f.js +555 -0
- package/dist/web/public/spreadsheet-preview.af82fa2f.js.br +0 -0
- package/dist/web/public/spreadsheet-preview.af82fa2f.js.gz +0 -0
- package/dist/web/public/spreadsheet-xlsx-core.js +1006 -0
- package/dist/web/public/spreadsheet-xlsx-core.js.br +0 -0
- package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
- package/dist/web/public/styles.81a72906.css +1 -0
- package/dist/web/public/styles.81a72906.css.br +0 -0
- package/dist/web/public/styles.81a72906.css.gz +0 -0
- package/dist/web/public/{subagent-windows.e6ca799f.js → subagent-windows.07277a58.js} +7 -5
- package/dist/web/public/subagent-windows.07277a58.js.br +0 -0
- package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
- package/dist/web/public/sw.js +2 -2
- package/dist/web/public/sw.js.br +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-layout-browser.065fcba4.js.gz +0 -0
- package/dist/web/public/{tab-rail-resize.94cd59f0.js → tab-rail-resize.a5867793.js} +1 -1
- package/dist/web/public/tab-rail-resize.a5867793.js.br +0 -0
- package/dist/web/public/{tab-rail-resize.94cd59f0.js.gz → tab-rail-resize.a5867793.js.gz} +0 -0
- package/dist/web/public/terminal-keycode229-recovery.af09f99a.js +1 -0
- package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.br +0 -0
- package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
- package/dist/web/public/terminal-split.js +146 -649
- package/dist/web/public/terminal-split.js.br +0 -0
- package/dist/web/public/terminal-split.js.gz +0 -0
- package/dist/web/public/terminal-tile.js +1688 -0
- package/dist/web/public/terminal-tile.js.br +0 -0
- package/dist/web/public/terminal-tile.js.gz +0 -0
- package/dist/web/public/terminal-ui.b7267005.js +2 -0
- package/dist/web/public/terminal-ui.b7267005.js.br +0 -0
- package/dist/web/public/terminal-ui.b7267005.js.gz +0 -0
- package/dist/web/public/tile-grid.js +2895 -0
- package/dist/web/public/tile-grid.js.br +0 -0
- package/dist/web/public/tile-grid.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js +9 -6
- package/dist/web/public/ultracode-windows.js.br +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/exceljs.min.js +44 -0
- package/dist/web/public/vendor/exceljs.min.js.br +0 -0
- package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
- package/dist/web/public/vendor/fflate.min.js +1 -0
- package/dist/web/public/vendor/fflate.min.js.br +0 -0
- package/dist/web/public/vendor/fflate.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js +4 -0
- package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.br +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/{voice-input.c4b51eb6.js → voice-input.2342c37b.js} +64 -10
- package/dist/web/public/voice-input.2342c37b.js.br +0 -0
- package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js +9 -1
- package/dist/web/public/webview-tabs.js.br +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/routes/cli-registry-routes.d.ts +23 -4
- package/dist/web/routes/cli-registry-routes.d.ts.map +1 -1
- package/dist/web/routes/cli-registry-routes.js +95 -8
- package/dist/web/routes/cli-registry-routes.js.map +1 -1
- package/dist/web/routes/file-routes.d.ts +7 -0
- package/dist/web/routes/file-routes.d.ts.map +1 -1
- package/dist/web/routes/file-routes.js +34 -4
- package/dist/web/routes/file-routes.js.map +1 -1
- package/dist/web/routes/git-status-routes.d.ts.map +1 -1
- package/dist/web/routes/git-status-routes.js +33 -6
- package/dist/web/routes/git-status-routes.js.map +1 -1
- package/dist/web/routes/mcp-sync-routes.d.ts +7 -2
- package/dist/web/routes/mcp-sync-routes.d.ts.map +1 -1
- package/dist/web/routes/mcp-sync-routes.js +10 -3
- package/dist/web/routes/mcp-sync-routes.js.map +1 -1
- package/dist/web/routes/reboot-restore-routes.js +1 -1
- package/dist/web/routes/reboot-restore-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts +18 -0
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +154 -69
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/routes/status-telemetry-routes.d.ts +3 -0
- package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -1
- package/dist/web/routes/status-telemetry-routes.js +12 -0
- package/dist/web/routes/status-telemetry-routes.js.map +1 -1
- package/dist/web/routes/system-routes.d.ts.map +1 -1
- package/dist/web/routes/system-routes.js +13 -0
- package/dist/web/routes/system-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +30 -0
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +43 -0
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/server.d.ts +6 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +47 -21
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-listener-wiring.d.ts +1 -0
- package/dist/web/session-listener-wiring.d.ts.map +1 -1
- package/dist/web/session-listener-wiring.js +11 -0
- package/dist/web/session-listener-wiring.js.map +1 -1
- package/package.json +6 -4
- package/scripts/postinstall.js +16 -0
- package/skills/codeman/SKILL.md +6 -0
- package/README.zh-CN.md +0 -1139
- package/dist/web/public/app.b9516c7b.js +0 -43
- package/dist/web/public/app.b9516c7b.js.br +0 -0
- package/dist/web/public/app.b9516c7b.js.gz +0 -0
- package/dist/web/public/constants.d95fade9.js.br +0 -0
- package/dist/web/public/constants.d95fade9.js.gz +0 -0
- package/dist/web/public/i18n.52f5b7cc.js +0 -1
- package/dist/web/public/i18n.52f5b7cc.js.br +0 -0
- package/dist/web/public/i18n.52f5b7cc.js.gz +0 -0
- package/dist/web/public/image-input.a216cf9e.js.br +0 -0
- package/dist/web/public/image-input.a216cf9e.js.gz +0 -0
- package/dist/web/public/mobile-handlers.23a85db1.js.br +0 -0
- package/dist/web/public/mobile-handlers.23a85db1.js.gz +0 -0
- package/dist/web/public/mobile.1aa4952d.css +0 -1
- package/dist/web/public/mobile.1aa4952d.css.br +0 -0
- package/dist/web/public/mobile.1aa4952d.css.gz +0 -0
- package/dist/web/public/notification-manager.50bb87d8.js.br +0 -0
- package/dist/web/public/notification-manager.50bb87d8.js.gz +0 -0
- package/dist/web/public/panels-ui.6a5898d9.js.br +0 -0
- package/dist/web/public/panels-ui.6a5898d9.js.gz +0 -0
- package/dist/web/public/session-ui.6bddf916.js +0 -89
- package/dist/web/public/session-ui.6bddf916.js.br +0 -0
- package/dist/web/public/session-ui.6bddf916.js.gz +0 -0
- package/dist/web/public/settings-ui.6e798b7b.js +0 -97
- package/dist/web/public/settings-ui.6e798b7b.js.br +0 -0
- package/dist/web/public/settings-ui.6e798b7b.js.gz +0 -0
- package/dist/web/public/styles.2d175c60.css +0 -1
- package/dist/web/public/styles.2d175c60.css.br +0 -0
- package/dist/web/public/styles.2d175c60.css.gz +0 -0
- package/dist/web/public/subagent-windows.e6ca799f.js.br +0 -0
- package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.94cd59f0.js.br +0 -0
- package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js +0 -1
- package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js.br +0 -0
- package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js.gz +0 -0
- package/dist/web/public/terminal-ui.a4535311.js +0 -2
- package/dist/web/public/terminal-ui.a4535311.js.br +0 -0
- package/dist/web/public/terminal-ui.a4535311.js.gz +0 -0
- package/dist/web/public/upload.html +0 -155
- package/dist/web/public/upload.html.br +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.bbb5f84c.js +0 -4
- package/dist/web/public/vendor/xterm-zerolag-input.bbb5f84c.js.br +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.bbb5f84c.js.gz +0 -0
- package/dist/web/public/voice-input.c4b51eb6.js.br +0 -0
- package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";const _crashDiag={_entries:[],_maxEntries:50,_pageId:Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8),log(f){const e=typeof CodemanDiag<"u"?CodemanDiag:null,t=e?.sanitizeDiagEntry?e.sanitizeDiagEntry(f):String(f??"").replace(/[\r\n\u2028\u2029]+/g," ").slice(0,e?.DIAG_ENTRY_MAX_CHARS??300),s=`${new Date().toISOString().slice(11,23)} ${t}`;this._entries.push(s),this._entries.length>this._maxEntries&&this._entries.shift();try{localStorage.setItem("codeman-crash-diag",this._entries.join(`
|
|
2
|
+
`))}catch{}}};try{const f=localStorage.getItem("codeman-crash-diag");f&&(console.log(`[CRASH-DIAG] Previous session breadcrumbs:
|
|
3
|
+
`+f),navigator.sendBeacon(CodemanBase.url("/api/crash-diag"),JSON.stringify({data:f,id:_crashDiag._pageId+"-prev"})))}catch{}_crashDiag.log("PAGE LOAD");function _crashDiagBeacon(){try{_crashDiag._entries.length>0&&navigator.sendBeacon(CodemanBase.url("/api/crash-diag"),JSON.stringify({data:_crashDiag._entries.join(`
|
|
4
|
+
`),id:_crashDiag._pageId}))}catch{}}if(setInterval(()=>{try{localStorage.setItem("codeman-crash-heartbeat",String(Date.now()))}catch{}_crashDiagBeacon()},2e3),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&_crashDiagBeacon()}),window.addEventListener("error",f=>{_crashDiag.log(`ERROR: ${f.message} at ${f.filename}:${f.lineno}`),console.error("[CRASH-DIAG] Uncaught error:",f.message,`
|
|
5
|
+
File:`,f.filename,":",f.lineno,":",f.colno,`
|
|
6
|
+
Stack:`,f.error?.stack)}),window.addEventListener("unhandledrejection",f=>{_crashDiag.log(`UNHANDLED: ${f.reason?.message||f.reason}`),console.error("[CRASH-DIAG] Unhandled promise rejection:",f.reason?.message||f.reason,`
|
|
7
|
+
Stack:`,f.reason?.stack)}),typeof PerformanceObserver<"u")try{new PerformanceObserver(e=>{for(const t of e.getEntries())t.duration>200&&(_crashDiag.log(`LONG_TASK: ${t.duration.toFixed(0)}ms`),console.warn(`[CRASH-DIAG] Long task: ${t.duration.toFixed(0)}ms (type: ${t.entryType}, name: ${t.name})`))}).observe({type:"longtask",buffered:!0})}catch{}const _origGetContext=HTMLCanvasElement.prototype.getContext;HTMLCanvasElement.prototype.getContext=function(f,...e){const t=_origGetContext.call(this,f,...e);return(f==="webgl2"||f==="webgl")&&(this.addEventListener("webglcontextlost",s=>{_crashDiag.log(`WEBGL_LOST: ${this.width}x${this.height}`),console.error("[CRASH-DIAG] WebGL context LOST on canvas",this.width,"x",this.height,"\u2014 prevented:",s.defaultPrevented)}),this.addEventListener("webglcontextrestored",()=>{_crashDiag.log("WEBGL_RESTORED"),console.warn("[CRASH-DIAG] WebGL context restored")})),t};const _SSE_HANDLER_MAP=[[SSE_EVENTS.INIT,"_onInit"],[SSE_EVENTS.SESSION_CREATED,"_onSessionCreated"],[SSE_EVENTS.SESSION_UPDATED,"_onSessionUpdated"],[SSE_EVENTS.SESSION_DELETED,"_onSessionDeleted"],[SSE_EVENTS.SESSION_TERMINAL,"_onSSETerminal"],[SSE_EVENTS.SESSION_NEEDS_REFRESH,"_onSSENeedsRefresh"],[SSE_EVENTS.SESSION_CLEAR_TERMINAL,"_onSSEClearTerminal"],[SSE_EVENTS.SESSION_COMPLETION,"_onSessionCompletion"],[SSE_EVENTS.SESSION_ERROR,"_onSessionError"],[SSE_EVENTS.SESSION_EXIT,"_onSessionExit"],[SSE_EVENTS.SESSION_IDLE,"_onSessionIdle"],[SSE_EVENTS.SESSION_WORKING,"_onSessionWorking"],[SSE_EVENTS.SESSION_AUTO_CLEAR,"_onSessionAutoClear"],[SSE_EVENTS.SESSION_LIMIT_PAUSE_SCHEDULED,"_onSessionLimitPauseScheduled"],[SSE_EVENTS.SESSION_LIMIT_RESUME,"_onSessionLimitResume"],[SSE_EVENTS.SESSION_LIMIT_RESUME_CANCELLED,"_onSessionLimitResumeCancelled"],[SSE_EVENTS.SESSION_RESPAWN_BREAKER_TRIPPED,"_onSessionRespawnBreakerTripped"],[SSE_EVENTS.SESSION_CLI_INFO,"_onSessionCliInfo"],[SSE_EVENTS.SESSION_STATUS_TELEMETRY,"_onSessionStatusTelemetry"],[SSE_EVENTS.SCHEDULED_CREATED,"_onScheduledCreated"],[SSE_EVENTS.SCHEDULED_UPDATED,"_onScheduledUpdated"],[SSE_EVENTS.SCHEDULED_COMPLETED,"_onScheduledCompleted"],[SSE_EVENTS.SCHEDULED_STOPPED,"_onScheduledStopped"],[SSE_EVENTS.CRON_JOBS_CHANGED,"_onCronJobsChanged"],[SSE_EVENTS.CRON_JOB_DELETED,"_onCronJobsChanged"],[SSE_EVENTS.CRON_RUN_CREATED,"_onCronRunChanged"],[SSE_EVENTS.CRON_RUN_UPDATED,"_onCronRunChanged"],[SSE_EVENTS.RESPAWN_STARTED,"_onRespawnStarted"],[SSE_EVENTS.RESPAWN_STOPPED,"_onRespawnStopped"],[SSE_EVENTS.RESPAWN_STATE_CHANGED,"_onRespawnStateChanged"],[SSE_EVENTS.RESPAWN_CYCLE_STARTED,"_onRespawnCycleStarted"],[SSE_EVENTS.RESPAWN_BLOCKED,"_onRespawnBlocked"],[SSE_EVENTS.RESPAWN_AUTO_ACCEPT_SENT,"_onRespawnAutoAcceptSent"],[SSE_EVENTS.RESPAWN_DETECTION_UPDATE,"_onRespawnDetectionUpdate"],[SSE_EVENTS.RESPAWN_TIMER_STARTED,"_onRespawnTimerStarted"],[SSE_EVENTS.RESPAWN_TIMER_CANCELLED,"_onRespawnTimerCancelled"],[SSE_EVENTS.RESPAWN_TIMER_COMPLETED,"_onRespawnTimerCompleted"],[SSE_EVENTS.RESPAWN_ERROR,"_onRespawnError"],[SSE_EVENTS.RESPAWN_ACTION_LOG,"_onRespawnActionLog"],[SSE_EVENTS.TASK_CREATED,"_onTaskCreated"],[SSE_EVENTS.TASK_COMPLETED,"_onTaskCompleted"],[SSE_EVENTS.TASK_FAILED,"_onTaskFailed"],[SSE_EVENTS.TASK_UPDATED,"_onTaskUpdated"],[SSE_EVENTS.MUX_CREATED,"_onMuxCreated"],[SSE_EVENTS.MUX_KILLED,"_onMuxKilled"],[SSE_EVENTS.MUX_DIED,"_onMuxDied"],[SSE_EVENTS.MUX_STATS_UPDATED,"_onMuxStatsUpdated"],[SSE_EVENTS.REMOTE_SESSION_RECONNECTED,"_onRemoteSessionReconnected"],[SSE_EVENTS.REMOTE_RECONNECT_EXHAUSTED,"_onRemoteReconnectExhausted"],[SSE_EVENTS.REMOTE_HOST_WAKING,"_onRemoteHostWaking"],[SSE_EVENTS.REMOTE_HOST_WAKE_FAILED,"_onRemoteHostWakeFailed"],[SSE_EVENTS.SESSION_RALPH_LOOP_UPDATE,"_onRalphLoopUpdate"],[SSE_EVENTS.SESSION_RALPH_TODO_UPDATE,"_onRalphTodoUpdate"],[SSE_EVENTS.SESSION_RALPH_COMPLETION_DETECTED,"_onRalphCompletionDetected"],[SSE_EVENTS.SESSION_RALPH_STATUS_UPDATE,"_onRalphStatusUpdate"],[SSE_EVENTS.SESSION_CIRCUIT_BREAKER_UPDATE,"_onCircuitBreakerUpdate"],[SSE_EVENTS.SESSION_EXIT_GATE_MET,"_onExitGateMet"],[SSE_EVENTS.SESSION_BASH_TOOL_START,"_onBashToolStart"],[SSE_EVENTS.SESSION_BASH_TOOL_END,"_onBashToolEnd"],[SSE_EVENTS.SESSION_BASH_TOOLS_UPDATE,"_onBashToolsUpdate"],[SSE_EVENTS.HOOK_IDLE_PROMPT,"_onHookIdlePrompt"],[SSE_EVENTS.HOOK_PERMISSION_PROMPT,"_onHookPermissionPrompt"],[SSE_EVENTS.HOOK_ELICITATION_DIALOG,"_onHookElicitationDialog"],[SSE_EVENTS.HOOK_ELICITATION_COMPLETE,"_onHookElicitationComplete"],[SSE_EVENTS.HOOK_ELICITATION_RESPONSE,"_onHookElicitationResponse"],[SSE_EVENTS.HOOK_STOP,"_onHookStop"],[SSE_EVENTS.HOOK_AGENT_WORKING,"_onHookAgentWorking"],[SSE_EVENTS.HOOK_TEAMMATE_IDLE,"_onHookTeammateIdle"],[SSE_EVENTS.HOOK_TASK_COMPLETED,"_onHookTaskCompleted"],[SSE_EVENTS.APPROVAL_PENDING,"_onApprovalPending"],[SSE_EVENTS.APPROVAL_UPDATED,"_onApprovalUpdated"],[SSE_EVENTS.APPROVAL_RESOLVED,"_onApprovalResolved"],[SSE_EVENTS.SUBAGENT_DISCOVERED,"_onSubagentDiscovered"],[SSE_EVENTS.SUBAGENT_UPDATED,"_onSubagentUpdated"],[SSE_EVENTS.SUBAGENT_TOOL_CALL,"_onSubagentToolCall"],[SSE_EVENTS.SUBAGENT_PROGRESS,"_onSubagentProgress"],[SSE_EVENTS.SUBAGENT_MESSAGE,"_onSubagentMessage"],[SSE_EVENTS.SUBAGENT_TOOL_RESULT,"_onSubagentToolResult"],[SSE_EVENTS.SUBAGENT_COMPLETED,"_onSubagentCompleted"],[SSE_EVENTS.WORKFLOW_RUN_DISCOVERED,"_onWorkflowRunDiscovered"],[SSE_EVENTS.WORKFLOW_RUN_UPDATED,"_onWorkflowRunUpdated"],[SSE_EVENTS.WORKFLOW_RUN_REMOVED,"_onWorkflowRunRemoved"],[SSE_EVENTS.IMAGE_DETECTED,"_onImageDetected"],[SSE_EVENTS.ATTACHMENT_DETECTED,"_onAttachmentDetected"],[SSE_EVENTS.TUNNEL_STARTED,"_onTunnelStarted"],[SSE_EVENTS.TUNNEL_STOPPED,"_onTunnelStopped"],[SSE_EVENTS.TUNNEL_PROGRESS,"_onTunnelProgress"],[SSE_EVENTS.TUNNEL_ERROR,"_onTunnelError"],[SSE_EVENTS.TUNNEL_QR_ROTATED,"_onTunnelQrRotated"],[SSE_EVENTS.TUNNEL_QR_REGENERATED,"_onTunnelQrRegenerated"],[SSE_EVENTS.TUNNEL_QR_AUTH_USED,"_onTunnelQrAuthUsed"],[SSE_EVENTS.PLAN_SUBAGENT,"_onPlanSubagent"],[SSE_EVENTS.PLAN_PROGRESS,"_onPlanProgress"],[SSE_EVENTS.PLAN_STARTED,"_onPlanStarted"],[SSE_EVENTS.PLAN_CANCELLED,"_onPlanCancelled"],[SSE_EVENTS.PLAN_COMPLETED,"_onPlanCompleted"],[SSE_EVENTS.ORCHESTRATOR_STATE_CHANGED,"_onOrchestratorStateChanged"],[SSE_EVENTS.ORCHESTRATOR_PLAN_PROGRESS,"_onOrchestratorPlanProgress"],[SSE_EVENTS.ORCHESTRATOR_PLAN_READY,"_onOrchestratorPlanReady"],[SSE_EVENTS.ORCHESTRATOR_PHASE_STARTED,"_onOrchestratorPhaseStarted"],[SSE_EVENTS.ORCHESTRATOR_PHASE_COMPLETED,"_onOrchestratorPhaseCompleted"],[SSE_EVENTS.ORCHESTRATOR_PHASE_FAILED,"_onOrchestratorPhaseFailed"],[SSE_EVENTS.ORCHESTRATOR_VERIFICATION,"_onOrchestratorVerification"],[SSE_EVENTS.ORCHESTRATOR_TASK_ASSIGNED,"_onOrchestratorTaskAssigned"],[SSE_EVENTS.ORCHESTRATOR_TASK_COMPLETED,"_onOrchestratorTaskCompleted"],[SSE_EVENTS.ORCHESTRATOR_TASK_FAILED,"_onOrchestratorTaskFailed"],[SSE_EVENTS.ORCHESTRATOR_COMPLETED,"_onOrchestratorCompleted"],[SSE_EVENTS.ORCHESTRATOR_ERROR,"_onOrchestratorError"],[SSE_EVENTS.CLIPBOARD_WRITE,"_onClipboardWrite"],[SSE_EVENTS.SESSION_ORDER_CHANGED,"_onSessionOrderChanged"],[SSE_EVENTS.TAB_LAYOUT_CHANGED,"_onTabLayoutChanged"],[SSE_EVENTS.WEBVIEW_CHANGED,"_onWebviewChanged"]];function parseSessionPrefix(f){if(!f)return null;const e=f.match(/^(w\d+-[a-zA-Z0-9_-]+|s\d+-[a-zA-Z0-9_-]+)/);if(!e)return null;const t=e[1],s=f.slice(t.length);return s===""?{prefix:t,suffix:""}:s.startsWith(": ")?{prefix:t,suffix:s.slice(2)}:null}function paneExitLabel(f){return!f||typeof f!="object"?"":typeof f.signal=="number"&&f.signal>0?`exited (signal ${f.signal})`:typeof f.status=="number"?`exited (${f.status})`:"exited"}function paneExitAriaLabel(f,e){return e?`${f} session, agent ${e}`:`${f} session`}function applyPaneExitBadge(f,e){const t=paneExitLabel(e),s=f.querySelector(".tab-exited-badge");f.classList.toggle("tab-agent-exited",!!t);const i=f.querySelector(".tab-name")?.dataset?.fullName;if(i){const n=paneExitAriaLabel(i,t);f.dataset.ariaSource!==n&&(f.dataset.ariaSource=n,f.setAttribute("aria-label",n))}if(!t){s?.remove();return}if(!s){const n=document.createElement("span");n.className="tab-exited-badge",n.setAttribute("aria-hidden","true"),n.dataset.label=t,n.textContent=t,f.querySelector(".tab-name")?.insertAdjacentElement("afterend",n);return}s.dataset.label!==t&&(s.dataset.label=t,s.textContent=t)}const DEFAULT_SHORTCUTS=[{id:"show-shortcuts",group:"Panels",label:"Show Shortcuts",bindings:[{modifiers:["ctrl"],key:"?",code:"Slash"},{modifiers:["ctrl","shift"],key:"?"},{modifiers:["alt"],key:"?",code:"Slash"}],action:"showShortcutOverlay"},{id:"close-session",group:"Session",label:"Close Session",bindings:[],action:"killActiveSession"},{id:"next-session",group:"Session",label:"Next Session",bindings:[{modifiers:["ctrl"],key:"Tab"}],action:"nextSession"},{id:"clear-terminal",group:"Terminal",label:"Clear Terminal",bindings:[{modifiers:["ctrl"],key:"l"}],action:"clearTerminal"},{id:"copy-selection",group:"Terminal",label:"Copy Selection",bindings:[{modifiers:["ctrl"],key:"c"},{modifiers:["ctrl","shift"],key:"C"}],action:"copyTerminalSelection"},{id:"increase-font",group:"Terminal",label:"Increase Font",bindings:[{modifiers:["ctrl"],key:"=",code:"Equal"},{modifiers:["ctrl"],key:"+",code:"Equal"}],action:"increaseFontSize"},{id:"decrease-font",group:"Terminal",label:"Decrease Font",bindings:[{modifiers:["ctrl"],key:"-",code:"Minus"}],action:"decreaseFontSize"},{id:"voice-input",group:"Terminal",label:"Voice Input",bindings:[{modifiers:["ctrl","shift"],key:"V"}],action:"toggleVoiceInput"},{id:"restore-terminal-size",group:"Terminal",label:"Restore Terminal Size",bindings:[{modifiers:["ctrl","shift"],key:"R"}],action:"restoreTerminalSize"},{id:"move-tab-left",group:"Tabs",label:"Move Active Tab Left",bindings:[{modifiers:["ctrl","shift"],key:"{",code:"BracketLeft"}],action:"moveActiveTabLeft"},{id:"move-tab-right",group:"Tabs",label:"Move Active Tab Right",bindings:[{modifiers:["ctrl","shift"],key:"}",code:"BracketRight"}],action:"moveActiveTabRight"},{id:"command-palette",group:"Session",label:"Find Open Session",bindings:[{modifiers:["ctrl"],key:"k",code:"KeyK"},{modifiers:["meta"],key:"k",code:"KeyK"},{modifiers:["alt"],key:"k",code:"KeyK"}],action:"openCommandPalette"},{id:"toggle-session-sidebar",group:"Session",label:"Toggle Session Sidebar",bindings:[{modifiers:["alt"],key:"b",code:"KeyB"}],action:"toggleSessionSidebar"},{id:"toggle-tile-grid",group:"Tiles",label:"Toggle Tile Grid",bindings:[{modifiers:["ctrl","shift"],key:"G",code:"KeyG"}],action:"toggleTileGrid"},{id:"focus-tile-left",group:"Tiles",label:"Focus Tile Left",bindings:[{modifiers:["alt","shift"],key:"ArrowLeft"}],action:"focusTileLeft"},{id:"focus-tile-right",group:"Tiles",label:"Focus Tile Right",bindings:[{modifiers:["alt","shift"],key:"ArrowRight"}],action:"focusTileRight"},{id:"focus-tile-up",group:"Tiles",label:"Focus Tile Up",bindings:[{modifiers:["alt","shift"],key:"ArrowUp"}],action:"focusTileUp"},{id:"focus-tile-down",group:"Tiles",label:"Focus Tile Down",bindings:[{modifiers:["alt","shift"],key:"ArrowDown"}],action:"focusTileDown"},{id:"move-tile-left",group:"Tiles",label:"Move Tile Left",bindings:[{modifiers:["ctrl","shift"],key:"ArrowLeft"}],action:"moveTileLeft"},{id:"move-tile-right",group:"Tiles",label:"Move Tile Right",bindings:[{modifiers:["ctrl","shift"],key:"ArrowRight"}],action:"moveTileRight"},{id:"move-tile-up",group:"Tiles",label:"Move Tile Up",bindings:[{modifiers:["ctrl","shift"],key:"ArrowUp"}],action:"moveTileUp"},{id:"move-tile-down",group:"Tiles",label:"Move Tile Down",bindings:[{modifiers:["ctrl","shift"],key:"ArrowDown"}],action:"moveTileDown"},{id:"zoom-tile",group:"Tiles",label:"Zoom Focused Tile",bindings:[{modifiers:["alt","shift"],key:"Enter"}],action:"zoomTile"},{id:"remove-tile",group:"Tiles",label:"Remove Focused Tile",bindings:[],action:"removeTile"},{id:"previous-next-session",group:"Session",label:"Previous / Next Session",displayBindings:["Alt/Option+[","Alt/Option+]"]},{id:"switch-tab-n",group:"Session",label:"Switch to Tab N",displayBindings:["Alt/Option+1-9"]},{id:"focus-tabs",group:"Tabs",label:"Focus Tabs",displayBindings:["ArrowLeft","ArrowRight","Home","End"]},{id:"activate-focused-tab",group:"Tabs",label:"Activate Focused Tab",displayBindings:["Enter","Space"]},{id:"insert-newline",group:"Terminal",label:"Insert Newline",displayBindings:["Shift+Enter","Ctrl+Enter"]},{id:"close-panels",group:"Panels",label:"Close Panels",displayBindings:["Escape"]}],SIDEBAR_RICH_CLOCK_MS=2e4,URL_SESSION_WAIT_MS=3e4,TAB_LAYOUT_PENDING_MAX_AGE_MS=6e4;class CodemanApp{constructor(){this.sessions=new Map,this._shortIdCache=new Map,this.sessionOrder=[],this.draggedTabId=null,this.tabLayout=null,this.collapsedTabGroupIds=new Set,this._hiddenTabGroupByRef=new Map,this._lastTabGroupStructureKey=null,this._tabRailSearch="",this.cases=[],this.currentRun=null,this.totalTokens=0,this.globalStats=null,this.eventSource=null,this._clientId=typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"c-"+Math.random().toString(36).slice(2)+Date.now().toString(36),this._wsTabNonce=this._clientId,this.terminal=null,this.fitAddon=null,this.activeSessionId=null,this.soloSessionId=this._detectSoloSessionId(),this.isSoloWindow=!!this.soloSessionId,this._urlSessionId=this.isSoloWindow?null:this._takeUrlSession(),this._urlSessionWaitTimer=null,this.detachedSessions=new Set,this.detachedWindows=new Map,this._detachWatchTimers=new Map,this.windowChannel=null,this._redockGrace=new Map,this._detachPingPending=null,this._detachLivenessTimer=null,this._detachOrphanStrikes=new Map,this._initGeneration=0,this._initFallbackTimer=null,this._selectGeneration=0,this._fullHistoryLoaded=new Set,this._fullHistoryRepullAt=new Map,this._fullHistoryRepullInFlight=!1,this._fullHistoryRepullUseless=new Set,this._geometryRetryUseless=new Set,this.terminalLoadStates=new Map,this.respawnStatus={},this.respawnTimers={},this.respawnCountdownTimers={},this.respawnActionLogs={},this.timerCountdownInterval=null,this.terminalBuffers=new Map,this.editingSessionId=null,this.pendingCloseSessionId=null,this.muxSessions=[],this.ralphStates=new Map,this.subagents=new Map,this.subagentActivity=new Map,this.subagentToolResults=new Map,this.activeSubagentId=null,this.subagentPanelVisible=!1,this.workflowRuns=new Map,this.workflowRunDetails=new Map,this.activeWorkflowRunId=null,this.activeWorkflowPhaseIndex=null,this.ultracodeWindows=new Map,this.ultracodeWindowsClosed=new Set,this.ultracodeWindowCloseTimers=new Map,this.ultracodeWindowZIndex=1e3,this.subagentWindows=new Map,this.subagentWindowZIndex=ZINDEX_SUBAGENT_BASE,this.minimizedSubagents=new Map,this._subagentHideTimeout=null,this.subagentParentMap=new Map,this.teams=new Map,this.teamTasks=new Map,this.teammateMap=new Map,this.teammatePanesByName=new Map,this.teammateTerminals=new Map,this.terminalBufferCache=new Map,this.ralphStatePanelCollapsed=!0,this.ralphClosedSessions=new Set,this.planSubagents=new Map,this.planSubagentWindowZIndex=ZINDEX_PLAN_SUBAGENT_BASE,this.planGenerationStopped=!1,this.planAgentsMinimized=!1,this.wizardDragState=null,this.wizardDragListeners=null,this.wizardPosition=null,this.projectInsights=new Map,this.logViewerWindows=new Map,this.logViewerWindowZIndex=ZINDEX_LOG_VIEWER_BASE,this.projectInsightsPanelVisible=!1,this.orchestratorState=null,this.orchestratorPanelVisible=!1,this.currentSessionWorkingDir=null,this.imagePopups=new Map,this.imagePopupZIndex=ZINDEX_IMAGE_POPUP_BASE,this.attachmentCards=new Map,this.attachmentCardStack=null,this.attachmentHistoryCounts=new Map,this.attachmentHistoryItems=[],this.attachmentHistoryDrawerOpen=!1,this.fileBrowserData=null,this.fileBrowserExpandedDirs=new Set,this.fileBrowserFilter="",this.fileBrowserAllExpanded=!1,this.fileBrowserDragListeners=null,this.fileBrowserShowHidden=this._loadFileBrowserShowHidden?.()??!1,this.filePreviewContent="",this._toastContainer=null,this._tunnelUrl=null,this.tabAlerts=new Map,this.pendingHooks=new Map,this._closingSessions=new Set,this.approvals=new Map,this._ws=null,this._wsSessionId=null,this._wsReady=!1,this._wsState="disconnected",this._wsLastRecvAt=0,this._wsOutputGapSession=null,this.pendingWrites=[],this.writeFrameScheduled=!1,this._terminalWriteInFlight=!1,this._terminalWriteInFlightBytes=0,this._wasAtBottomBeforeWrite=!0,this.syncWaitTimeout=null,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadSeq=0,this._bufferLoadOwner=null,this._terminalRefreshOwner=null,this.flickerFilterBuffer="",this.flickerFilterActive=!1,this.flickerFilterTimeout=null,this._debounceTimers=Object.create(null),this.systemStatsInterval=null,this.sseReconnectTimeout=null,this._sseListenerCleanup=null,this.reconnectAttempts=0,this.maxReconnectAttempts=10,this.isOnline=navigator.onLine,this._sseLastMessageAt=0,this._sseStaleTimeoutMs=window.CodemanSseStale?.TIMEOUT_MS??45e3,this._sseStaleWatchdog=null,this._connDownSince=null,this._nextSseRetryAt=null,this._offlineOverlayDismissed=!1,this._offlineRetryPending=!1,this._offlineUiTicker=null,this._lastOfflineUiKey="",this._connectionStatus="connected",this._clientId="",this._seqCounters=new Map,this._pendingDeliveries=new Map,this._lastIndicatorDescriptor=null,this._lastIndicatorLanguage=null,this._postDraining=new Set,this._extraInputSockets=new Map,this._persistReliableTimer=null,this._reliableAckTimeoutMs=4e3,this._reliableMaxBytes=256*1024,this._loadReliableState(),this._reliableSweepTimer=setInterval(()=>this._redeliverSweep(),2e3),window.addEventListener("pagehide",()=>this._persistReliableNow()),window.addEventListener("pagehide",()=>this._persistPendingTabLayoutEdits()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?this._persistReliableNow():this._checkSseStale()}),this._localEchoOverlay=null,this._localEchoEnabled=!1,this._predictiveEcho=null,this._localEchoPolicy="off",this._restoringFlushedState=!1,this.activeFocusTrap=null,this.notificationManager=new NotificationManager(this),this.idleTimers=new Map,this._elemCache={},this.init()}$(e){return this._elemCache[e]||(this._elemCache[e]=document.getElementById(e)),this._elemCache[e]}_clearTimer(e){this[e]&&(clearTimeout(this[e]),this[e]=null)}_isStaleSelect(e){return e!==this._selectGeneration?(this._isLoadingBuffer&&this._finishBufferLoad(e),this._restoringFlushedState=!1,!0):!1}formatTokens(e){if(e>=1e6){const t=e/1e6;return t>=10?`${t.toFixed(1)}m`:`${t.toFixed(2)}m`}else if(e>=1e3){const t=e/1e3;return t>=100?`${t.toFixed(0)}k`:`${t.toFixed(1)}k`}return String(e)}estimateCost(e,t){const s=e/1e6*15,i=t/1e6*75;return s+i}setPendingHook(e,t){this.pendingHooks.has(e)||this.pendingHooks.set(e,new Set),this.pendingHooks.get(e).add(t),this.updateTabAlertFromHooks(e)}clearPendingHooks(e,t=null){const s=this.pendingHooks.get(e);s&&(t?s.delete(t):s.clear(),s.size===0&&this.pendingHooks.delete(e),this.updateTabAlertFromHooks(e))}markIdleAlertSeen(e){this.pendingHooks?.get(e)?.has("idle_prompt")&&(this.clearPendingHooks(e,"idle_prompt"),this.acknowledgeIdleApprovalOnView?.(e))}updateTabAlertFromHooks(e){const t=this.pendingHooks.get(e);!t||t.size===0?this.tabAlerts.delete(e):t.has("permission_prompt")||t.has("elicitation_dialog")?this.tabAlerts.set(e,"action"):t.has("idle_prompt")&&this.tabAlerts.set(e,"idle"),this.renderSessionTabs()}init(){MobileDetection.init(),this._initWindowChannel(),this.isSoloWindow&&document.body.classList.add("solo-mode"),this.isSoloWindow||window.addEventListener("hashchange",()=>{const s=this._takeUrlSession();s&&(this._retireUrlSession(),this._urlSessionId=s,this._selectUrlSession())}),document.documentElement.classList.toggle("host-windows",this.hasHostWindows()),KeyboardHandler.init(),SwipeHandler.init(),VoiceInput.init(),KeyboardAccessoryBar.init();const e=this.loadAppSettingsFromStorage();KeyboardAccessoryBar.setMode(e.extendedKeyboardBar?"extended":"simple"),this.applyHeaderVisibilitySettings(),this.restorePlanUsageChip(),this.applySkin(),this.applyLocalization(),this.applySessionListLayout(),this.applyTabOrientation(),this.initTabRailResize?.(),this.applyMonitorVisibility(),this.applyLineageLineSettings?.(),this._installLineageStripScrollListener?.(),this._setupTabMiddleClickClose(),this.initEntranceAnimations?.(),document.documentElement.classList.remove("mobile-init"),requestAnimationFrame(()=>{this.initTerminal(),this.loadFontSize(),this.connectSSE(),this._initFallbackTimer=setTimeout(()=>{this._initGeneration===0&&this.loadState()},3e3)}),this.registerServiceWorker(),this.loadTunnelStatus(),this.initRebootRestoreBanner?.();const t=fetch("/api/settings").then(s=>s.ok?s.json():null).then(s=>s?.data??null).catch(()=>null);if(this.loadQuickStartCases(null,t),this._initRunMode(),this.initWebviews?.(),this.setupEventListeners(),MobileDetection.isTouchDevice()){const s=i=>{i&&i.addEventListener("touchstart",n=>{if(!KeyboardHandler.keyboardVisible)return;const o=n.target.closest("button");o&&(n.preventDefault(),o.click(),typeof app<"u"&&app.terminal&&app.terminal.focus())},{passive:!1})};s(document.querySelector(".toolbar")),s(document.querySelector(".welcome-overlay"))}this.setupOnlineDetection(),this.loadAppSettingsFromServer(t).then(()=>{this.applyHeaderVisibilitySettings(),this.applySkin(),this.applyLocalization(),this.applySessionListLayout(),this.applyTabOrientation?.(),this.applyMonitorVisibility(),this.applyLineageLineSettings?.(),typeof this.syncAllUltracodeFloatingWindows=="function"&&this.syncAllUltracodeFloatingWindows()}),document.body.classList.add("app-loaded")}_initWebGL(){if(!(typeof WebglAddon>"u"))try{this._webglAddon=new WebglAddon.WebglAddon,this._webglAddon.onContextLoss(()=>{console.error("[CRASH-DIAG] WebGL context LOST \u2014 falling back to canvas renderer"),_crashDiag.log("WEBGL_LOST"),this._disableWebGLSticky("context-lost"),this._disposeWebGLObserver(),this._webglAddon?.dispose(),this._webglAddon=null,this._scheduleTerminalRepaint()}),this.terminal.loadAddon(this._webglAddon),console.log("[CRASH-DIAG] WebGL renderer enabled"),this._installWebGLLongTaskGuard()}catch{}}_installWebGLLongTaskGuard(){if(typeof PerformanceObserver>"u"||this._webglLongTaskObserver)return;const e=performance.now(),t=[];try{this._webglLongTaskObserver=new PerformanceObserver(s=>{if(!this._webglAddon||this._tilesOwnTerminal?.())return;const i=performance.now();i-e<WEBGL_FALLBACK.GRACE_MS||evaluateWebGLLongTaskTrip(t,s.getEntries(),i)&&(console.warn(`[CRASH-DIAG] WebGL long-task threshold (${t.length} stalls/${WEBGL_FALLBACK.WINDOW_MS}ms) \u2014 falling back to canvas renderer`),_crashDiag.log(`WEBGL_FALLBACK: ${t.length}`),this._disableWebGLSticky("long-tasks"),this._disposeWebGLObserver(),this._webglAddon?.dispose(),this._webglAddon=null,this._scheduleTerminalRepaint())}),this._webglLongTaskObserver.observe({type:"longtask",buffered:!1})}catch{}}_disposeWebGLObserver(){if(this._webglLongTaskObserver){try{this._webglLongTaskObserver.disconnect()}catch{}this._webglLongTaskObserver=null}}_scheduleTerminalRepaint(){if(this._terminalRepaintScheduled)return;this._terminalRepaintScheduled=!0,(typeof requestAnimationFrame=="function"?requestAnimationFrame:t=>setTimeout(t,0))(()=>{this._terminalRepaintScheduled=!1;try{this.terminal?.refresh(0,this.terminal.rows-1)}catch{}})}_disableWebGLSticky(e){try{localStorage.setItem("codeman-webgl-disabled",JSON.stringify({reason:e,at:Date.now()}))}catch{}}setupEventListeners(){const e={showShortcutOverlay:()=>this.showShortcutOverlay(),killActiveSession:()=>this.killActiveSession(),nextSession:()=>this.nextSession(),clearTerminal:()=>this.clearTerminal(),restoreTerminalSize:()=>this.restoreTerminalSize(),increaseFontSize:()=>this.increaseFontSize(),decreaseFontSize:()=>this.decreaseFontSize(),toggleVoiceInput:()=>VoiceInput.toggle(),moveActiveTabLeft:()=>this.moveActiveTabLeft(),moveActiveTabRight:()=>this.moveActiveTabRight(),toggleSessionSidebar:()=>this.toggleSessionSidebar()};document.addEventListener("keydown",s=>{if(s.target?.closest?.("[data-raw-keys]")||s.isComposing||s.keyCode===229)return;if(this.shouldOpenCommandPaletteFromShortcut?.(s)){s.preventDefault(),this.openCommandPalette();return}if(s.key==="Escape"){if(this._tabGroupMenu&&this._tabGroupMenuKeydown){this._tabGroupMenuKeydown(s);return}if(this._tabLayoutDrag?.active&&this._tabLayoutDragKeydown){this._tabLayoutDragKeydown(s);return}if(this._tileCountMenu){this.closeTileCountMenu({refocus:!0});return}if(s.target?.id==="tabRailSearch"&&this._tabRailSearch){this.handleTabRailSearchKeydown(s);return}this.closeAllPanels(),this.closeHelp(),this.attachmentHistoryDrawerOpen&&this.closeAttachmentHistory(),this.closeSessionManager(),this.closeCommandPalette?.(),this.closeShortcutOverlay?.(),this._isSessionSidebarOverlay()&&this.isSessionSidebarActive()&&!this.isSessionSidebarCollapsed()&&(this.toggleSessionSidebar(),document.getElementById("sidebarToggleBtn")?.focus())}if(s.altKey&&!s.ctrlKey&&!s.shiftKey){const o=(s.code||"").match(/^Digit([1-9])$/);if(o){const r=parseInt(o[1],10)-1,a=this.sessionOrder.filter(l=>this.sessions.has(l));if(r<a.length)s.preventDefault(),this.selectSession(a[r]);else{const l=r-a.length,c=(this.webviewOrder||[])[l];c&&(s.preventDefault(),this.openWebview(c))}return}if(s.code==="BracketLeft"){s.preventDefault(),this.prevSession();return}if(s.code==="BracketRight"){s.preventDefault(),this.nextSession();return}}const i=this.tileShortcutFor?.(s);if(i){s.preventDefault(),this.runTileShortcut(i);return}if(!(!s.ctrlKey&&!s.metaKey&&!s.altKey))for(const n of this.getShortcutRegistry()){if(n.disabled||!n.action)continue;const o=e[n.action];if(o&&this.matchesShortcutEvent(s,n)){s.preventDefault(),o();return}}},!0);const t=this.$("headerTokens");t&&!t._statsHandlerAttached&&(t.classList.add("clickable"),t._statsHandlerAttached=!0,t.addEventListener("click",()=>this.openTokenStats())),this.setupColorPicker()}_sseFilterSessionId(e){return this._tilesOwnTerminal?.()&&window.CodemanTileGrid?.TILE_GRID_SSE_FILTER||e}_updateSseSubscription(e){try{const t=this._sseFilterSessionId(e),s=JSON.stringify({clientId:this._clientId,sessions:t?[t]:null});fetch("/api/events/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:s,keepalive:!0}).catch(()=>{})}catch{}}_detectSoloSessionId(){try{if(typeof window<"u"&&typeof window.__CODEMAN_SOLO__=="string"&&window.__CODEMAN_SOLO__)return window.__CODEMAN_SOLO__;const e=window.CodemanBase?.base||"";let t=location.pathname;e&&t.startsWith(e)&&(t=t.slice(e.length)||"/");const s=t.match(/^\/session\/([^/]+)\/?$/);return s?decodeURIComponent(s[1]):null}catch{return null}}_takeUrlSession(){const e=window.CodemanUrlSession?.sessionIdFromFragment(location.hash)??null;if(e)try{history.replaceState(history.state,"",location.pathname+location.search)}catch{}return e}_selectUrlSession(){const e=this._urlSessionId;return e?this.sessions.has(e)?(this._retireUrlSession(),this.selectSession(e,{auto:!0,leaveTiles:!0}),!0):(this._armUrlSessionWait(e),!1):!1}_armUrlSessionWait(e){this._urlSessionWaitTimer||(this._urlSessionWaitTimer=setTimeout(()=>{if(this._urlSessionWaitTimer=null,this._urlSessionId===e){if(this.sessions.has(e)){this._selectUrlSession();return}this._retireUrlSession(),this.showToast?.("Session not found","warning")}},URL_SESSION_WAIT_MS))}_retireUrlSession(){this._urlSessionId=null,this._urlSessionWaitTimer&&(clearTimeout(this._urlSessionWaitTimer),this._urlSessionWaitTimer=null)}detachSession(e){if(this.isSoloWindow||!this.sessions.has(e)||this.detachedSessions.has(e)&&this._raiseDetached(e))return;const t=this.hasHostWindows()&&!this.windowChannel?!1:this.openInHostWindow(CodemanBase.url("/session/"+encodeURIComponent(e)));if(t!==null){if(!t){this.showToast?.("Could not open a new window for this session","error");return}this._markDetached(e,!0),this._postWindowMessage({type:"detached",id:e});return}const s="width=960,height=680,menubar=no,toolbar=no,location=no,status=no";let i=null;try{i=window.open(CodemanBase.url("/session/"+encodeURIComponent(e)),"codeman-session-"+e,s)}catch{}if(!i){this.showToast?.("Pop-out blocked \u2014 allow popups for this site to detach a session","error");return}this.detachedWindows.set(e,i),this._markDetached(e,!0),this._watchDetachedWindow(e,i),this._postWindowMessage({type:"detached",id:e});try{i.focus()}catch{}}hasHostWindows(){try{return typeof window<"u"&&typeof window.CodemanHost?.openWindow=="function"}catch{return!1}}tabDetachButtonEnabled(e,t={}){return e?.showTabDetachButton??(this.hasHostWindows()||(t?.showTabDetachButton??!1))}openInHostWindow(e){if(!this.hasHostWindows())return null;try{return window.CodemanHost.openWindow(new URL(e,location.href).href)!==!1}catch{return!1}}_raiseDetached(e){const t=this.detachedWindows.get(e);if(t&&!t.closed){try{t.focus()}catch{}return!0}return t&&t.closed?(this._redock(e),!1):(this._postWindowMessage({type:"focus-request",id:e}),!0)}redockSession(e){const t=this.detachedWindows.get(e);if(t&&!t.closed)try{t.close()}catch{}this._postWindowMessage({type:"close-request",id:e}),this._redock(e)}_redock(e){const t=this._detachWatchTimers.get(e);t&&(clearInterval(t),this._detachWatchTimers.delete(e)),this._cancelPendingRedock(e),this._detachOrphanStrikes.delete(e),this.detachedWindows.delete(e),this._markDetached(e,!1),this._lastResizeDims=null,this.sessions.has(e)&&e===this.activeSessionId&&this.sendResize(e,{force:!0})?.catch?.(()=>{})}_scheduleRedock(e){if(this._redockGrace.has(e))return;const t=setTimeout(()=>{this._redockGrace.delete(e),this._redock(e)},1500);this._redockGrace.set(e,t)}_cancelPendingRedock(e){const t=this._redockGrace.get(e);t&&(clearTimeout(t),this._redockGrace.delete(e))}_markDetached(e,t){t?this.detachedSessions.add(e):this.detachedSessions.delete(e),t&&this._tileGrid?.has(e)&&this.removeTile(e,{gone:!0});const s=this.$("sessionTabs"),i=s&&s.querySelector(`.session-tab[data-id="${e}"]`);i&&i.classList.toggle("detached",t)}_watchDetachedWindow(e,t){const s=this._detachWatchTimers.get(e);s&&clearInterval(s);const i=setInterval(()=>{(!t||t.closed)&&(clearInterval(i),this._detachWatchTimers.delete(e),this._redock(e))},800);this._detachWatchTimers.set(e,i)}_initWindowChannel(){if(!(typeof BroadcastChannel>"u")){try{this.windowChannel=new BroadcastChannel("codeman-windows")}catch{this.windowChannel=null;return}if(this.windowChannel.onmessage=e=>this._onWindowMessage(e.data),this.isSoloWindow){this._postWindowMessage({type:"detached",id:this.soloSessionId});const e=()=>this._postWindowMessage({type:"redocked",id:this.soloSessionId});window.addEventListener("pagehide",e),window.addEventListener("beforeunload",e)}else this._postWindowMessage({type:"roll-call"}),this._startDetachLiveness()}}_postWindowMessage(e){try{this.windowChannel&&this.windowChannel.postMessage(e)}catch{}}_onWindowMessage(e){if(!(!e||typeof e!="object")){if(this.isSoloWindow){if(e.type==="roll-call"){this._postWindowMessage({type:"detached",id:this.soloSessionId});return}if(e.id!==this.soloSessionId)return;if(e.type==="close-request")this._closeSoloWindow();else if(e.type==="focus-request")try{typeof window.CodemanHost?.focusWindow=="function"?window.CodemanHost.focusWindow():window.focus()}catch{}return}e.type==="detached"&&e.id?(this._cancelPendingRedock(e.id),this._detachPingPending?.delete(e.id),this._detachOrphanStrikes.delete(e.id),this._markDetached(e.id,!0)):e.type==="redocked"&&e.id?this._scheduleRedock(e.id):e.type==="detach-request"&&e.id&&this.detachSession(e.id)}}_startDetachLiveness(){this._detachLivenessTimer||(this._detachLivenessTimer=setInterval(()=>this._pingDetached(),5e3))}_pingDetached(){const e=[];for(const t of this.detachedSessions){const s=this.detachedWindows.get(t);s?s.closed&&this._redock(t):e.push(t)}e.length&&(this._detachPingPending=new Set(e),this._postWindowMessage({type:"roll-call"}),setTimeout(()=>{if(this._detachPingPending){for(const t of this._detachPingPending){const s=(this._detachOrphanStrikes.get(t)||0)+1;s>=2?(this._detachOrphanStrikes.delete(t),this._redock(t)):this._detachOrphanStrikes.set(t,s)}this._detachPingPending=null}},1200))}_closeSoloWindow(){try{typeof window.CodemanHost?.closeWindow=="function"?window.CodemanHost.closeWindow():window.close()}catch{}}_applySoloMode(){document.body.classList.add("solo-mode");const e=this.sessions.get(this.soloSessionId);if(!e){this._showSoloSessionGone();return}this.activeSessionId=null,this.selectSession(this.soloSessionId,{auto:!0});const t=this.getSessionName(e)||"Session",s=document.getElementById("soloSessionTitle");s&&(s.textContent=t,s.style.display="");const i=document.getElementById("soloRedockBtn");i&&(i.style.display=""),document.title=t+" \u2014 "+(window.CodemanI18n?.displayName||"Codeman"),this.notificationManager&&(this.notificationManager.originalTitle=document.title);const n=document.querySelector(".header-brand .logo");n&&(n.onclick=o=>{o.preventDefault()})}_showSoloSessionGone(){if(document.body.classList.add("solo-mode"),document.querySelector(".solo-gone-overlay"))return;const e=document.createElement("div");e.className="solo-gone-overlay",e.innerHTML='<h2>Session unavailable</h2><p>This session has ended or is no longer available.</p><button class="btn-primary" onclick="app._closeSoloWindow()">Close window</button>',document.body.appendChild(e),document.title=(window.codemanT?.("Session ended")||"Session ended")+" \u2014 "+(window.CodemanI18n?.displayName||"Codeman")}connectSSE(){if(!navigator.onLine){this.setConnectionStatus("offline");return}this._clearTimer("sseReconnectTimeout"),this._sseStaleWatchdog&&(clearInterval(this._sseStaleWatchdog),this._sseStaleWatchdog=null),this._sseListenerCleanup&&(this._sseListenerCleanup(),this._sseListenerCleanup=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.reconnectAttempts===0?this.setConnectionStatus("connecting"):this.setConnectionStatus("reconnecting");const e=new URLSearchParams({clientId:this._clientId}),t=this._sseFilterSessionId(this.activeSessionId);t&&e.set("sessions",t),this.eventSource=new EventSource(CodemanBase.url(`/api/events?${e.toString()}`));const s=[],i=(n,o)=>{const r=a=>{this._sseLastMessageAt=Date.now(),o(a)};this.eventSource.addEventListener(n,r),s.push({event:n,handler:r})};if(this._sseListenerCleanup=()=>{for(const{event:n,handler:o}of s)this.eventSource&&this.eventSource.removeEventListener(n,o);s.length=0},this.eventSource.onopen=()=>{this.reconnectAttempts=0,this._sseLastMessageAt=Date.now(),this.setConnectionStatus("connected")},this.eventSource.onerror=()=>{this.reconnectAttempts++,this.reconnectAttempts>=this.maxReconnectAttempts?this.setConnectionStatus("disconnected"):this.setConnectionStatus("reconnecting"),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this._clearTimer("sseReconnectTimeout");const n=this.reconnectAttempts<=1?200:Math.min(500*Math.pow(2,this.reconnectAttempts-2),3e4);this._nextSseRetryAt=Date.now()+n,this._updateConnectionLossUi(),this.sseReconnectTimeout=setTimeout(()=>this.connectSSE(),n)},!this._sseHandlerWrappers){this._sseHandlerWrappers=new Map;for(const[n,o]of _SSE_HANDLER_MAP){const r=this[o],a=o==="_onSSETerminal"||o==="_onSSENeedsRefresh"||o==="_onSSEClearTerminal";this._sseHandlerWrappers.set(n,l=>{if(!(a&&this._wsReady))try{r.call(this,l.data?JSON.parse(l.data):{})}catch(c){console.error(`[SSE] Error handling ${n}:`,c)}})}}for(const[n]of _SSE_HANDLER_MAP)i(n,this._sseHandlerWrappers.get(n));for(const n of[SSE_EVENTS.SESSION_CREATED,SSE_EVENTS.SESSION_DELETED])i(n,()=>this._onSessionListMaybeChanged());i(SSE_EVENTS.DOCKER_EXPORT_COMPLETE,n=>{try{const o=n.data?JSON.parse(n.data):{};this.showToast(`Docker export ready: ${o.bundle} (${Math.round((o.sizeBytes||0)/1e6)} MB)`,"success"),this.refreshDockerExports?.()}catch(o){console.error("[SSE] docker export complete:",o)}}),i(SSE_EVENTS.DOCKER_EXPORT_FAILED,n=>{try{const o=n.data?JSON.parse(n.data):{};this.showToast(`Docker export failed: ${o.error||"unknown error"}`,"error")}catch(o){console.error("[SSE] docker export failed:",o)}}),i(SSE_EVENTS.DOCKER_IMPORT_COMPLETE,n=>{try{const o=n.data?JSON.parse(n.data):{};this.showToast(`Docker bundle imported as case "${o.name}"`,"success"),this.loadQuickStartCases?.(),this.refreshDockerExports?.()}catch(o){console.error("[SSE] docker import complete:",o)}}),i(SSE_EVENTS.DOCKER_CONTAINER_RECREATED,n=>{try{const o=n.data?JSON.parse(n.data):{};this.showToast(`Container for "${o.name}" removed \u2014 next launch recreates it with the new config`,"info")}catch(o){console.error("[SSE] docker container recreated:",o)}}),i(SSE_EVENTS.CUSTOM_MODEL_SWAPPED_OUT,n=>{try{const o=n.data?JSON.parse(n.data):{};this.showToast(`${o.sessionName||o.sessionId}'s model (${o.previousModel}) was swapped out on llama-swap by another session \u2014 currently loaded: ${o.currentlyLoadedModel}. Sending a message there will reload it.`,"warning",{duration:0})}catch(o){console.error("[SSE] custom model swapped out:",o)}}),i(SSE_EVENTS.ADMIN_USERS_CHANGED,()=>{window.codemanAdmin?.onUsersChanged?.()}),i(SSE_EVENTS.DOCKER_IMAGE_BUILD_STARTED,()=>{this.showToast("Building the Codeman agent image (first Docker case, a few minutes)...","info",{duration:8e3})}),i(SSE_EVENTS.DOCKER_IMAGE_BUILD_COMPLETE,n=>{try{const o=n.data?JSON.parse(n.data):{};o.error?this.showToast(`Agent image build failed: ${o.error}`,"error"):this.showToast("Agent image ready. Starting the container...","success")}catch(o){console.error("[SSE] docker image build complete:",o)}}),i(SSE_EVENTS.DOCKER_IMAGE_BUILD_FAILED,n=>{try{const o=n.data?JSON.parse(n.data):{};this.showToast(`Agent image build failed: ${o.error||"unknown error"}`,"error")}catch(o){console.error("[SSE] docker image build failed:",o)}}),i(SSE_EVENTS.SESSION_PINNED,n=>{let o=null;try{o=JSON.parse(n.data)}catch{}if(o&&o.id){const r=this.sessions.get(o.id);r&&(r.pinned=o.pinned===!0,r.pinnedAt=o.pinned?o.pinnedAt:void 0)}this._onSessionListMaybeChanged()}),i(SSE_EVENTS.HEARTBEAT,()=>{}),this._sseStaleWatchdog=setInterval(()=>this._checkSseStale(),5e3)}_checkSseStale(){const e=window.CodemanSseStale;if(!e)return;const t=Date.now();e.compute({lastMessageAt:this._sseLastMessageAt,now:t,status:this._connectionStatus,isOnline:this.isOnline,timeoutMs:this._sseStaleTimeoutMs})&&(console.log(`[SSE] stream stale: no frame for ${t-this._sseLastMessageAt}ms (threshold ${this._sseStaleTimeoutMs}ms), forcing reconnect`),this.connectSSE())}_onInit(e){_crashDiag.log(`INIT: ${e.sessions?.length||0} sessions`),this.handleInit(e),this._ensureHostWakePoller?.()}_onSessionCreated(e){this._closingSessions?.has(e.id)||(this.sessions.set(e.id,e),this.sessionOrder.includes(e.id)||(this.sessionOrder.push(e.id),this.saveSessionOrder()),this.markSessionTabEntering?.(e.id),this.markTerminalEntering?.(e.id),e.parentSessionId&&this.markConnectionLineEntering?.("lineage:"+e.id),this.renderSessionTabs(),this.updateCost(),this.sessions.size===1&&this.startSystemStatsPolling(),this._urlSessionId===e.id&&this._selectUrlSession())}_onSessionUpdated(e){const t=e.session||e;if(this._closingSessions?.has(t.id))return;const s=this.sessions.get(t.id),i=t.claudeSessionId&&(!s||!s.claudeSessionId);this.sessions.set(t.id,t),this.renderSessionTabs(),this.updateCost(),t.id===this.activeSessionId&&t.tokens&&this.updateRespawnTokens(t.tokens),this.updateSubagentParentNames(t.id),i&&(this.recheckOrphanSubagents(),requestAnimationFrame(()=>{this.updateConnectionLines()}))}_onSessionDeleted(e){if(this._wsSessionId===e.id&&this._disconnectWs(),this.isSoloWindow&&e.id===this.soloSessionId&&this._showSoloSessionGone(),this.detachedSessions.has(e.id)&&this._redock(e.id),this._cleanupSessionData(e.id),this.activeSessionId===e.id&&!this._closingSessions.has(e.id)){this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.terminal.clear(),this.showWelcome()}this.renderSessionTabs(),this.renderRalphStatePanel(),this.renderProjectInsightsPanel(),this.sessions.size===0&&this.stopSystemStatsPolling()}_onSSETerminal(e){this._wsReady||this._onSessionTerminal(e)}_onSSENeedsRefresh(e){this._wsReady||this._onSessionNeedsRefresh(e)}_onSSEClearTerminal(e){this._wsReady||this._onSessionClearTerminal(e)}_bufferLoadFinishOpts(e,t){return{flushQueued:e?.source==="mux-visible"||e?.source==="mux-full-history",since:t}}_onSessionTerminal(e){if(!this._tilesOwnTerminal?.()&&e.id===this.activeSessionId){e.data.length>32768&&_crashDiag.log(`TERMINAL: ${(e.data.length/1024).toFixed(0)}KB`);const t=(this.pendingWrites?.reduce((s,i)=>s+i.length,0)||0)+(this.flickerFilterBuffer?.length||0)+(this._loadBufferQueue?.reduce((s,i)=>s+i.data.length,0)||0)+(this._terminalWriteInFlightBytes||0);if(t+e.data.length>131072){this._scheduleDroppedOutputRecovery(e.id,0,t);return}this.batchTerminalWrite(e.data)}}_scheduleDroppedOutputRecovery(e,t=0,s){!e||this._clientDropRecoveryTimer||this._tilesOwnTerminal?.()||(Number.isFinite(s)&&_crashDiag.log(`TERMINAL DROP: ${(s/1024).toFixed(0)}KB queued`),this._clientDropRecoveryTimer=setTimeout(async()=>{this._clientDropRecoveryTimer=null;let i=!1,n=!1;try{const r=await this._onSessionNeedsRefresh({id:e});i=r===!0,n=r==="deadline"}catch{}window.CodemanDroppedOutput.shouldRetryDroppedOutputRecovery({repainted:i,timedOut:n,attempt:t,stillActive:this.activeSessionId===e})&&(_crashDiag.log(`DROP RECOVERY: attempt ${t+1} did not repaint, retrying`),this._scheduleDroppedOutputRecovery(e,t+1))},window.CodemanDroppedOutput.DROP_RECOVERY_DELAY_MS))}_sanitizeHtml(e){return typeof window<"u"&&typeof window.sanitizeMarkdownHtml=="function"?window.sanitizeMarkdownHtml(e):String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}_cleanTerminalBuffer(e){const t=e.replace(/\x1b\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]/g,"").replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,"").replace(/\x1b[PX^_][^\x1b]*\x1b\\/g,"").replace(/\x1b[NO()][A-Z0-9]?/g,"").replace(/\x1b[>=<78cDEHM]/g,"").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"").replace(/\r\n/g,`
|
|
8
|
+
`).replace(/\r/g,`
|
|
9
|
+
`),s=[/^\s*❯\s*/,/^\s*[⏵⏺⏸⏹]+\s*/,/^\s*✻\s*(Crunching|Crunched|Thinking)/i,/bypass permissions/i,/\bshift\+tab to cycle\b/i,/^\s*focus\s*$/,/^\s*new task\?/i,/\/clear to save/i,/^\s*─{5,}\s*$/,/\[(Opus|Sonnet|Haiku|GPT|Claude)[\s\S]*(tokens?|\$|¥|%|↑|↓)/i,/^\s*\[\d+[km]?\/\d+[km]?\]/i,/[█░▓▒]{3,}/,/^\s*\(.*\s*(tokens?|context).*\)\s*$/i];return t.split(`
|
|
10
|
+
`).filter(o=>o.trim()?!s.some(a=>a.test(o)):!0).join(`
|
|
11
|
+
`).replace(/[ \t]+$/gm,"").replace(/\n{4,}/g,`
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
`).trim()}_preprocessAsciiArt(e){const t=/[─-╿▀-▟]/,s=/```[\s\S]*?```/g,i=[];return e.replace(s,r=>(i.push(r),`__CODEMAN_FENCE_${i.length-1}__`)).split(/(\n{2,})/).map(r=>/^\n{2,}$/.test(r)||!r.trim()||r.includes("__CODEMAN_FENCE_")?r:t.test(r)?"\n```\n"+r+"\n```\n":r).join("").replace(/__CODEMAN_FENCE_(\d+)__/g,(r,a)=>i[Number(a)])}_renderMarkdown(e,{breaks:t=!0}={}){const s=e||"";if(typeof marked<"u"&&marked.parse)try{const n=this._preprocessAsciiArt(s);let o=this._sanitizeHtml(marked.parse(n,{breaks:t,gfm:!0}));o=o.replace(/<table>/g,'<div class="rv-table-wrap"><table>').replace(/<\/table>/g,"</table></div>");const r=/[─-╿▀-▟]/,a=document.createElement("template");return a.innerHTML=o,a.content.querySelectorAll("pre > code").forEach(l=>{const c=l.parentElement,d=r.test(l.textContent||""),h=document.createElement("div");h.className=d?"rv-code-wrap rv-diagram-wrap":"rv-code-wrap";const u=document.createElement("div");u.className="rv-code-actions";const S=document.createElement("button");if(S.className="rv-copy-btn",S.type="button",S.setAttribute("aria-label","Copy code"),S.setAttribute("title","Copy code"),u.appendChild(S),d){c.classList.add("rv-diagram");const m=document.createElement("button");m.className="rv-wrap-toggle",m.type="button",m.setAttribute("aria-label","Toggle line wrapping"),m.setAttribute("title","Toggle line wrapping"),u.appendChild(m)}c.parentNode.insertBefore(h,c),h.appendChild(u),h.appendChild(c)}),a.content.querySelectorAll("a[href]").forEach(l=>{const c=l.getAttribute("href")||"";!c||c.startsWith("#")||/^(?:mailto|tel):/i.test(c)||(l.setAttribute("target","_blank"),l.setAttribute("rel","noopener noreferrer"))}),a.innerHTML}catch{}return`<pre style="white-space:pre-wrap;word-break:break-word">${s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}</pre>`}_bindResponseViewerInteractions(e){!e||e.dataset.rvBound==="1"||(e.dataset.rvBound="1",e.addEventListener("click",async t=>{const s=t.target.closest("a.rv-path");if(s){t.preventDefault(),t.stopPropagation();const d=s.dataset.path;d&&this.openFilePreview(d,s.dataset.sessionId||this.activeSessionId);return}const i=t.target.closest('a[href^="#"]');if(i&&e.contains(i)){t.preventDefault(),t.stopPropagation();const d=i.closest(".rv-text")||e,h=window.CodemanMarkdownAnchors?.find(d,i.getAttribute("href"));if(h){const u=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;h.scrollIntoView({block:"start",behavior:u?"auto":"smooth"})}return}const n=t.target.closest("a[href]");if(n&&this.openLinkThroughWebTabIfLoopback?.(n.href)){t.preventDefault(),t.stopPropagation();return}const o=t.target.closest(".rv-copy-btn");if(o){t.preventDefault(),t.stopPropagation();const d=o.closest(".rv-code-wrap")?.querySelector("pre code"),h=d?await this._copyText(d.textContent||""):!1;o.classList.remove("rv-copied","rv-copy-failed"),o.classList.add(h?"rv-copied":"rv-copy-failed"),clearTimeout(o._resetTimer),o._resetTimer=setTimeout(()=>{o.classList.remove("rv-copied","rv-copy-failed")},1500);return}const r=t.target.closest(".rv-wrap-toggle");if(!r)return;t.preventDefault(),t.stopPropagation();const a=r.closest(".rv-diagram-wrap"),l=a?.querySelector("pre.rv-diagram");if(!l||!a)return;const c=l.classList.toggle("rv-nowrap");a.classList.toggle("rv-wrap-nowrap",c)}))}async _copyText(e){if(!e)return!1;try{if(navigator.clipboard?.writeText)return await navigator.clipboard.writeText(e),!0}catch{}try{const t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.style.cssText="position:fixed;top:0;left:0;opacity:0;pointer-events:none",document.body.appendChild(t),t.select();const s=document.execCommand("copy");return document.body.removeChild(t),s}catch{return!1}}_buildResponseViewerMessage(e,t,s,i){const n=document.createElement("div"),o=t==="user";n.className="rv-message "+(o?"rv-msg-user":"rv-msg-assistant");const r=!!(i&&i.continuation);if(r&&n.classList.add("rv-msg-cont"),i&&i.kind&&(n.dataset.kind=i.kind),i&&i.queued&&(n.dataset.queued="1"),!r){const l=document.createElement("div");l.className="rv-role "+(o?"rv-role-user":"rv-role-assistant"),l.textContent=o?"You":s,n.appendChild(l)}const a=document.createElement("div");return a.className="rv-text",a.innerHTML=this._renderMarkdown(e),this._linkifyFilePaths(a),n.appendChild(a),n}_linkifyFilePaths(e){if(!e||typeof document>"u"||typeof absoluteFilePathPattern!="function")return;const t=absoluteFilePathPattern(),s=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),i=[];for(let n=s.nextNode();n;n=s.nextNode())n.parentElement?.closest("a")||(t.lastIndex=0,t.test(n.nodeValue||"")&&i.push(n));for(const n of i){const o=n.nodeValue,r=document.createDocumentFragment();let a=0,l;for(t.lastIndex=0;(l=t.exec(o))!==null;){const c=l[1];l.index>a&&r.appendChild(document.createTextNode(o.slice(a,l.index)));const d=document.createElement("a");d.className="rv-path",d.href="#",d.dataset.path=c,d.title=c,d.textContent=c,r.appendChild(d),a=l.index+c.length}a<o.length&&r.appendChild(document.createTextNode(o.slice(a))),n.parentNode?.replaceChild(r,n)}}_getResponseViewerAgentLabel(){const e=this.sessions.get(this.activeSessionId)?.mode;return e==="codex"?"Codex":e==="gemini"?"Gemini":e==="antigravity"?"Antigravity":e==="pi"?"Pi":e==="grok"?"Grok":e==="deepseek"?"DeepSeek":e==="omp"?"OMP":e==="opencode"?"OpenCode":"Claude"}async toggleResponseViewer(){const e=document.getElementById("responseViewer"),t=document.getElementById("responseViewerBackdrop");if(!e)return;if(e.classList.contains("visible")){e.classList.remove("visible"),t.classList.remove("visible");return}if(this.activeSessionId)try{const n=(await(await fetch(`/api/sessions/${this.activeSessionId}/last-response?context=turn`)).json())?.data??{};let o=n.text||"";const r=(Array.isArray(n.messages)?n.messages:[]).filter(h=>h&&h.role==="assistant"&&typeof h.text=="string"&&h.text.trim()),a=this.sessions.get(this.activeSessionId)?.mode||"claude";if(!o&&(a==="claude"||a==="shell")){const u=(await this._fetchTerminalCapture(`/api/sessions/${this.activeSessionId}/terminal`,{full:!0})).json?.data??{};u.terminalBuffer&&(o=this._cleanTerminalBuffer(u.terminalBuffer))}const l=document.getElementById("responseViewerBody");if(r.length>0){const h=this._getResponseViewerAgentLabel();l.innerHTML="";let u=null;for(const S of r){const m=!!u&&typeof S.turn=="number"&&u.turn===S.turn;l.appendChild(this._buildResponseViewerMessage(S.text,"assistant",h,{...S,continuation:m})),u=S}this._bindResponseViewerInteractions(l)}else o?(l.innerHTML="",l.appendChild(this._buildResponseViewerMessage(o,"assistant",this._getResponseViewerAgentLabel())),this._bindResponseViewerInteractions(l)):l.textContent=window.codemanT?.("No response yet \u2014 send a message in this session first.")||"No response yet \u2014 send a message in this session first.";const c=document.getElementById("responseViewerTitle"),d=document.getElementById("responseViewerMore");c&&(c.textContent="Last Response"),d&&(d.style.display="",d.textContent="More"),e.classList.add("visible"),t.classList.add("visible"),l.scrollTop=r.length>1?l.scrollHeight:0}catch(i){console.error("Failed to load response:",i)}}async loadFullContext(){if(!this.activeSessionId)return;const e=document.getElementById("responseViewerMore");e&&(e.textContent="...");try{const i=((await(await fetch(`/api/sessions/${this.activeSessionId}/last-response?context=full`)).json())?.data??{}).messages||[],n=document.getElementById("responseViewerBody"),o=document.getElementById("responseViewerTitle");if(!n)return;if(i.length===0){let c=n.querySelector(":scope > .rv-notice");c||(c=document.createElement("div"),c.className="rv-notice",n.appendChild(c));const d="No full conversation history available for this session";c.textContent=window.codemanT?.(d)||d;return}const r=this._getResponseViewerAgentLabel();n.innerHTML="";let a=null;for(const c of i){const d=!!a&&a.role===c.role&&typeof c.turn=="number"&&a.turn===c.turn;n.appendChild(this._buildResponseViewerMessage(c.text,c.role,r,{...c,continuation:d})),a=c}this._bindResponseViewerInteractions(n);const l=new Set(i.filter(c=>typeof c.turn=="number").map(c=>c.turn)).size;o&&(o.textContent=l?`Conversation (${i.length} messages, ${l} turns)`:`Conversation (${i.length} messages)`),e&&(e.style.display="none"),n.scrollTop=n.scrollHeight}catch(t){console.error("Failed to load context:",t)}finally{e&&(e.textContent="More")}}async _fetchTerminalCapture(e,t={}){const s=typeof CodemanFetchDeadline<"u"?CodemanFetchDeadline.terminalFetchDeadlineMs({full:!!t.full,inflight:this._terminalCaptureInflight||0}):45e3,n=typeof AbortController=="function"?new AbortController:null,o=n?setTimeout(()=>n.abort(),s):null;this._terminalCaptureInflight=(this._terminalCaptureInflight||0)+1;try{const r=await(n?fetch(e,{signal:n.signal}):fetch(e)),a=performance.now();return{json:await r.json(),headers:r.headers,headersAt:a}}catch(r){throw r?.name==="AbortError"&&_crashDiag.log(`TERMINAL FETCH TIMEOUT after ${s}ms`),r}finally{o!==null&&clearTimeout(o),this._terminalCaptureInflight=Math.max(0,(this._terminalCaptureInflight||1)-1)}}async _onSessionNeedsRefresh(e={}){if(this._tilesOwnTerminal?.())return!1;const t=this.activeSessionId;if(e?.id&&e.id!==t||!t||!this.terminal||this._isLoadingBuffer||this._terminalRefreshOwner?.sessionId===t)return!1;const s={sessionId:t};this._terminalRefreshOwner=s;try{const i=this.sessions.get(t)?.mode!=="shell";let n=await this._fetchTerminalCapture(i?`/api/sessions/${t}/terminal?full=1`:`/api/sessions/${t}/terminal?tail=${TERMINAL_TAIL_SIZE}`,{full:i}),o=n.headersAt,r=n.json?.data??{};if(i&&r.terminalBuffer&&this._replayWouldShrinkBuffer(r.terminalBuffer)&&(n=await this._fetchTerminalCapture(`/api/sessions/${t}/terminal?tail=${TERMINAL_TAIL_SIZE}`),o=n.headersAt,r=n.json?.data??{}),this.activeSessionId!==t||this._terminalRefreshOwner!==s)return!1;if(r.terminalBuffer){const a=this.terminal.buffer?.active,l=a?Math.max(0,(a.baseY||0)-(a.viewportY||0)):0;this._resetTerminalForReplay(),await this.chunkedTerminalWrite(r.terminalBuffer,TERMINAL_CHUNK_SIZE,void 0,this._bufferLoadFinishOpts(r,o)),this._setHistoryTruncation(t,r);const c=computeRewriteScrollLine({linesFromBottom:l,baseY:this.terminal.buffer?.active?.baseY??0});c===null||typeof this.terminal.scrollToLine!="function"?this.terminal.scrollToBottom():this.terminal.scrollToLine(c),this._syncStickyScrollBaseline(),this._localEchoOverlay?.rerender(),this.activeSessionId&&this.sendResize(this.activeSessionId)}return this._markTerminalBufferReconciled(t),!0}catch(i){return console.error("needsRefresh reload failed:",i),i?.name==="AbortError"?"deadline":!1}finally{this._terminalRefreshOwner===s&&(this._terminalRefreshOwner=null)}}_markTerminalBufferReconciled(e){e&&this._wsOutputGapSession===e&&(this._wsOutputGapSession=null)}async _onSessionClearTerminal(e){if(!this._tilesOwnTerminal?.()&&e.id===this.activeSessionId){if(this._isLoadingBuffer)return;try{const t=await this._fetchTerminalCapture(`/api/sessions/${e.id}/terminal`,{full:!0}),s=t.headersAt,i=t.json?.data??{};if(this._resetTerminalForReplay(),i.terminalBuffer){const n=i.terminalBuffer.replace(DEC_SYNC_STRIP_RE,"");await this.chunkedTerminalWrite(n,TERMINAL_CHUNK_SIZE,void 0,this._bufferLoadFinishOpts(i,s))}this.sendResize(e.id),this._localEchoOverlay?.rerender()}catch(t){console.error("clearTerminal refresh failed:",t)}}}_onSessionCompletion(e){this.totalCost+=e.cost||0,this.updateCost(),e.id===this.activeSessionId&&!this._tilesOwnTerminal?.()&&(this.terminal.writeln(""),this.terminal.writeln(`\x1B[1;32m Done (Cost: $${(e.cost||0).toFixed(4)})\x1B[0m`))}_onSessionError(e){e.id===this.activeSessionId&&!this._tilesOwnTerminal?.()&&this.terminal.writeln(`\x1B[1;31m Error: ${e.error}\x1B[0m`),this._notifySession(e.id,"critical","session-error","Session Error",e.error||"Unknown error")}_onSessionExit(e){this._wsSessionId===e.id&&this._disconnectWs();const t=this.sessions.get(e.id);t&&(t.status="stopped",this.renderSessionTabs(),e.id===this.activeSessionId&&this._updateLocalEchoState()),e.code&&e.code!==0&&this._notifySession(e.id,"critical","session-crash","Session Crashed",`Exited with code ${e.code}`)}_onSessionIdle(e){const t=this.sessions.get(e.id);if(t&&(t.status="idle",this.renderSessionTabs(),this.sendPendingCtrlL(e.id),e.id===this.activeSessionId&&this._updateLocalEchoState()),!this.respawnStatus[e.id]?.enabled){const s=this.notificationManager?.preferences?.stuckThresholdMs||6e5;clearTimeout(this.idleTimers.get(e.id)),this.idleTimers.set(e.id,setTimeout(()=>{this._notifySession(e.id,"warning","session-stuck","Session Idle",`Idle for ${Math.round(s/6e4)}+ minutes`),this.idleTimers.delete(e.id)},s))}}_onSessionWorking(e){const t=this.sessions.get(e.id);t&&(t.status="busy",this.pendingHooks.has(e.id)||this.tabAlerts.delete(e.id),this.renderSessionTabs(),this.sendPendingCtrlL(e.id),e.id===this.activeSessionId&&this._updateLocalEchoState());const s=this.idleTimers.get(e.id);s&&(clearTimeout(s),this.idleTimers.delete(e.id))}_onSessionAutoClear(e){e.sessionId===this.activeSessionId&&(this.showToast(`Auto-cleared at ${e.tokens.toLocaleString()} tokens`,"info"),this.updateRespawnTokens(0)),this._notifySession(e.sessionId,"info","auto-clear","Auto-Cleared",`Context reset at ${(e.tokens||0).toLocaleString()} tokens`)}_onSessionLimitPauseScheduled(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=e.resumeAt);const s=new Date(e.resumeAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});e.sessionId===this.activeSessionId&&this.showToast(`Usage limit reached \u2014 auto-resume at ${s}`,"warning"),this._notifySession(e.sessionId,"warning","limit-pause","Usage Limit Reached",`Auto-resume scheduled for ${s}`),this.updateAutoResumeStatus(e.sessionId)}_onSessionLimitResume(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=void 0),e.sessionId===this.activeSessionId&&this.showToast("Usage limit reset \u2014 work resumed automatically","success"),this._notifySession(e.sessionId,"info","limit-resume","Auto-Resumed","Usage limit reset \u2014 continuing work"),this.updateAutoResumeStatus(e.sessionId)}_onSessionLimitResumeCancelled(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=void 0),this.updateAutoResumeStatus(e.sessionId)}_onSessionRespawnBreakerTripped(e){const s=this.sessions.get(e.sessionId)?.name||"Session";this.showToast?.(`${s} stopped: repeated crashes detected. Restart to retry.`,"error")}_onSessionCliInfo(e){const t=this.sessions.get(e.sessionId);t&&(e.version&&(t.cliVersion=e.version),e.model&&(t.cliModel=e.model),e.accountType&&(t.cliAccountType=e.accountType),e.latestVersion&&(t.cliLatestVersion=e.latestVersion)),e.sessionId===this.activeSessionId&&this.updateCliInfoDisplay()}_onSessionStatusTelemetry(e){this.updatePlanUsageChip(e);try{localStorage.setItem("codeman:planUsage",JSON.stringify({t:Date.now(),data:e}))}catch{}}restorePlanUsageChip(){try{const e=localStorage.getItem("codeman:planUsage");if(!e)return;const t=JSON.parse(e);t?.data&&Date.now()-(t.t||0)<12*3600*1e3&&this.updatePlanUsageChip(t.data)}catch{}}updatePlanUsageChip(e){const t=document.getElementById("planUsageChip");if(!t||!e)return;const s=h=>h&&typeof h.usedPercentage=="number"?Math.round(h.usedPercentage):null,i=h=>h>=85?"pu-red":h>=60?"pu-yellow":"pu-green",n=(h,u,S)=>{if(u===null)return S?`<span class="pu-win pu-win-idle"><span class="pu-ring" style="--pu:0"></span><span class="pu-label">${h}</span><span class="pu-val">\u2014</span><span class="pu-meter"><i style="width:0%"></i></span></span>`:"";const m=Math.round(Number(u));if(!Number.isFinite(m))return"";const v=Math.min(100,Math.max(0,m)),b=i(m);return`<span class="pu-win"><span class="pu-ring ${b}" style="--pu:${v}"></span><span class="pu-label">${h}</span><span class="pu-val ${b}">${m}%</span><span class="pu-meter ${b}"><i style="width:${v}%"></i></span></span>`},o=h=>s(h?.fiveHour)!==null||s(h?.sevenDay)!==null,r=o(e)&&o(e.codex),a=(h,u,S)=>{if(!o(u))return"";const m=[n("5h",s(u?.fiveHour),S),n("7d",s(u?.sevenDay),S)].filter(Boolean);return m.length?`<span class="pu-row">${r?`<span class="pu-provider">${h}</span>`:""}<span class="pu-windows">${m.join('<span class="pu-sep">\xB7</span>')}</span></span>`:""},l=[a("Claude",e,!0),a("Codex",e.codex,!1)].filter(Boolean);t.innerHTML=l.length?l.join(""):"\u2014";const c=h=>h&&h.resetAt?new Date(h.resetAt).toLocaleString():"\u2014",d=(h,u,S)=>{const m=[],v=s(u?.fiveHour),b=s(u?.sevenDay);return v!==null?m.push(`5-hour limit: ${v}% used (resets ${c(u.fiveHour)})`):S&&b!==null&&m.push("5-hour limit: no active session window"),b!==null&&m.push(`Weekly limit: ${b}% used (resets ${c(u.sevenDay)})`),m.length?`${h} plan usage
|
|
15
|
+
${m.join(`
|
|
16
|
+
`)}`:""};t.title=[d("Claude",e,!0),d("Codex",e.codex,!1)].filter(Boolean).join(`
|
|
17
|
+
|
|
18
|
+
`)||"Plan usage limits"}_onScheduledCreated(e){this.currentRun=e,this.showTimer()}_onScheduledUpdated(e){this.currentRun=e,this.updateTimer()}_onScheduledCompleted(e){this.currentRun=e,this.hideTimer(),this.showToast("Scheduled run completed!","success")}_onScheduledStopped(){this.currentRun=null,this.hideTimer()}setConnectionStatus(e){this._connectionStatus=e,e==="connected"?(this._connDownSince=null,this._nextSseRetryAt=null,this._offlineOverlayDismissed=!1):this._connDownSince===null&&(this._connDownSince=Date.now()),this._updateConnectionIndicator(),this._updateConnectionLossUi(),e==="connected"&&this._redeliverSweep()}_connectWs(e){this._disconnectWs(),this._wsState="connecting",this._updateConnectionIndicator();const t=location.protocol==="https:"?"wss:":"ws:",s=this._clientId?`${this._clientId}:${this._wsTabNonce}`:"",i=s?`?cid=${encodeURIComponent(s)}`:"",n=`${t}//${location.host}${CodemanBase.base}/ws/sessions/${e}/terminal${i}`,o=new WebSocket(n);this._ws=o,this._wsSessionId=e,o.onopen=()=>{this._ws===o&&(this._wsReady=!0,this._wsState="connected",this._wsReconnectAttempts=0,this._updateConnectionIndicator(),this.sendResize(e)?.catch?.(()=>{}),this._startMobileResizeRetry(e),this._onWsReady(e),this._wsOutputGapSession===e&&(_crashDiag.log(`WS REOPEN: reconciling output gap for ${e}`),this._onSessionNeedsRefresh({id:e})))},o.onmessage=r=>{if(this._ws===o){this._wsLastRecvAt=Date.now();try{const a=JSON.parse(r.data);a.t==="o"?this._onSessionTerminal({id:e,data:a.d}):a.t==="c"?this._onSessionClearTerminal({id:e}):a.t==="r"?this._onSessionNeedsRefresh({id:e}):a.t==="ia"?this._onWsInputAck(a.seq,a,e):a.t==="zc"&&this._onPtyGeometryReport(e,a.c,a.r)}catch{}}},o.onclose=r=>{if(this._ws!==o)return;this._ws=null,this._wsSessionId=null,this._wsReady=!1,this._stopMobileResizeRetry();const a=window.CodemanWsReconnect.plan(r.code,this._wsReconnectAttempts||0);_crashDiag.log(`WS CLOSE code=${r.code} reason=${r.reason||""} action=${a.action} attempts=${this._wsReconnectAttempts||0}`),this._wsOutputGapSession=e;const l=this.activeSessionId===e;if(a.action==="give-up")this._wsState=l?"fallback":"disconnected",this._updateConnectionIndicator();else if(a.action==="reconnect")if(l){this._wsState="reconnecting",this._updateConnectionIndicator();const c=a.delayMs+Math.floor(Math.random()*250);this._wsReconnectAttempts=(this._wsReconnectAttempts||0)+1,this._wsReconnectTimer=setTimeout(()=>{this._wsReconnectTimer=null,this.activeSessionId===e&&this._connectWs(e)},c)}else this._wsState="disconnected",this._updateConnectionIndicator();else this._wsState=l?"fallback":"disconnected",this._updateConnectionIndicator(),l&&(this._wsReconnectAttempts=(this._wsReconnectAttempts||0)+1,this._wsReconnectTimer=setTimeout(()=>{this._wsReconnectTimer=null,this.activeSessionId===e&&this._connectWs(e)},a.delayMs))},o.onerror=()=>{}}_disconnectWs(){this._clearTimer("_wsReconnectTimer"),this._wsState="disconnected",this._stopMobileResizeRetry(),this._ws&&(this._ws.onclose=null,this._ws.close(),this._ws=null,this._wsSessionId=null,this._wsReady=!1)}_startMobileResizeRetry(e){this._stopMobileResizeRetry(),(typeof MobileDetection<"u"&&MobileDetection.getDeviceType?MobileDetection.getDeviceType():"desktop")!=="desktop"&&(this._mobileResizeRetryTimer=setInterval(()=>{document.visibilityState==="visible"&&(!this._wsReady||this._wsSessionId!==e||typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible||this.sendResize(e)?.catch?.(()=>{}))},MOBILE_RESIZE_RETRY_MS))}_stopMobileResizeRetry(){this._mobileResizeRetryTimer&&(clearInterval(this._mobileResizeRetryTimer),this._mobileResizeRetryTimer=null)}_sendInputAsync(e,t,s){if(!e||!t)return;const i=s?.useMux===!0,n=window.CodemanInputLimit;if(n&&t.length>n.FRAME_MAX_CHARS){if(i||t.length>n.PASTE_MAX_CHARS){const o=i?n.FRAME_MAX_CHARS:n.PASTE_MAX_CHARS;this.showToast?.(`Input too large (${Math.ceil(t.length/1024)} KB, limit ${Math.floor(o/1024)} KB); not sent`,"error");return}for(const o of n.split(t))this._reliableSend(e,o,!1);return}this._reliableSend(e,t,i)}_inputSocketFor(e){if(!e)return null;if(this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e)return{ws:this._ws,lastRecvAt:this._wsLastRecvAt};const t=this._extraInputSockets?.get(e);return t&&t.ws&&t.ws.readyState===WebSocket.OPEN?t:null}_registerInputSocket(e,t){!e||!t||(t.lastRecvAt=Date.now(),this._extraInputSockets||(this._extraInputSockets=new Map),this._extraInputSockets.set(e,t))}_unregisterInputSocket(e,t){this._extraInputSockets?.get(e)===t&&this._extraInputSockets.delete(e)}_sendInputEphemeral(e,t){if(!e||!t)return;const s=this._inputSocketFor(e);if(s)try{s.ws.send(JSON.stringify({t:"i",d:t}));return}catch{}try{fetch(`/api/sessions/${e}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:t}),keepalive:!0}).catch(()=>{})}catch{}}_reliableSend(e,t,s){const n={seq:this._nextSeq(e),data:t,useMux:!!s,ts:Date.now(),tries:0,sentAt:0};let o=this._pendingDeliveries.get(e);o||(o=[],this._pendingDeliveries.set(e,o)),o.push(n),this._persistReliableNow(),this._updateConnectionIndicator(),this._drainSession(e)}_nextSeq(e){const t=(this._seqCounters.get(e)||0)+1;return this._seqCounters.set(e,t),t}_drainSession(e){const t=this._pendingDeliveries.get(e);if(!t||t.length===0)return;const s=this._inputSocketFor(e);if(s){for(const i of t)if(i.sentAt===0)try{s.ws.send(JSON.stringify({t:"i",d:i.data,seq:i.seq,cid:this._clientId})),i.sentAt=Date.now(),i.tries++}catch{break}return}this._postDraining.has(e)||(this._postDraining.add(e),(async()=>{try{for(;;){const i=this._pendingDeliveries.get(e);if(!i||i.length===0||this._inputSocketFor(e))break;const n=i[0];n.tries++,n.sentAt=Date.now();let o=null;try{const r={input:n.data,seq:n.seq,clientId:this._clientId};n.useMux&&(r.useMux=!0),o=await fetch(`/api/sessions/${e}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:n.data.length<65536})}catch{o=null}if(o&&o.ok)this._ackDelivery(e,n.seq);else if(o&&(o.status===404||o.status===410))this._ackDelivery(e,n.seq);else if(o&&(o.status===400||o.status===413))this._dropRejectedInput(e,n);else break}}finally{this._postDraining.delete(e)}})())}_dropRejectedInput(e,t){this._ackDelivery(e,t.seq),this.showToast?.(`Input refused by the server (${Math.ceil(t.data.length/1024)} KB); not sent`,"error")}_ackDelivery(e,t){const s=this._pendingDeliveries.get(e);if(s){const i=s.findIndex(n=>n.seq===t);i!==-1&&(s.splice(i,1),s.length===0&&this._pendingDeliveries.delete(e),this._pendingDeliveries.size===0?this._persistReliableNow():this._persistReliableState(),this._updateConnectionIndicator())}this.markIdleAlertSeen?.(e)}_onWsInputAck(e,t,s=this._wsSessionId){if(!(!s||!Number.isInteger(e))){if(t&&t.err){const i=(this._pendingDeliveries.get(s)||[]).find(n=>n.seq===e);i?this._dropRejectedInput(s,i):this._ackDelivery(s,e);return}if(t&&t.dup){const i=this._pendingDeliveries.get(s),n=i&&i.find(a=>a.seq===e),o=Number.isInteger(t.last)?t.last:e;(this._seqCounters.get(s)||0)<=o&&(this._seqCounters.set(s,o),this._persistReliableNow());const r=n&&n.tries<=1?n.data:null;this._ackDelivery(s,e),r!==null&&this._reliableSend(s,r,n.useMux);return}this._ackDelivery(s,e)}}_onWsReady(e){const t=this._pendingDeliveries.get(e);if(t)for(const s of t)s.sentAt=0;this._drainSession(e)}_redeliverSweep(){if(this._pendingDeliveries.size!==0)for(const e of[...this._pendingDeliveries.keys()]){const t=this._pendingDeliveries.get(e);if(!t||t.length===0)continue;const s=this._inputSocketFor(e);if(s){const i=t[0],n=i&&i.sentAt&&Date.now()-i.sentAt>this._reliableAckTimeoutMs,o=Date.now()-(s.lastRecvAt||0)>this._reliableAckTimeoutMs;if(n&&o){try{s.ws.close()}catch{}continue}if(n)for(const r of t)r.sentAt&&Date.now()-r.sentAt>this._reliableAckTimeoutMs&&(r.sentAt=0)}this._drainSession(e)}}_pendingBytes(){let e=0,t=0;for(const s of this._pendingDeliveries.values())for(const i of s)e+=i.data.length,t++;return{bytes:e,count:t}}_loadReliableState(){try{this._clientId=localStorage.getItem("codeman:clientId")||""}catch{this._clientId=""}if(!this._clientId){this._clientId="c-"+Math.random().toString(36).slice(2)+"-"+Date.now().toString(36);try{localStorage.setItem("codeman:clientId",this._clientId)}catch{}}try{const e=localStorage.getItem("codeman:pendingInput");if(!e)return;const t=JSON.parse(e);if(t&&t.seqs)for(const[s,i]of Object.entries(t.seqs))Number.isFinite(i)&&this._seqCounters.set(s,i);if(t&&t.pending){for(const[s,i]of Object.entries(t.pending))if(Array.isArray(i)&&i.length){const n=window.CodemanInputLimit?.FRAME_MAX_CHARS??1/0,o=i.filter(r=>r&&typeof r.data=="string"&&Number.isInteger(r.seq)).filter(r=>r.data.length<=n).map(r=>({seq:r.seq,data:r.data,useMux:!!r.useMux,ts:r.ts||Date.now(),tries:0,sentAt:0}));o.length&&this._pendingDeliveries.set(s,o)}}}catch{}}_persistReliableState(){this._persistReliableTimer||(this._persistReliableTimer=setTimeout(()=>{this._persistReliableTimer=null,this._persistReliableNow()},250))}_persistReliableNow(){this._persistReliableTimer&&(clearTimeout(this._persistReliableTimer),this._persistReliableTimer=null);try{const e={};for(const[n,o]of this._seqCounters)e[n]=o;const t={};let s=0;for(const[n,o]of this._pendingDeliveries)if(o.length){t[n]=o.map(r=>({seq:r.seq,data:r.data,useMux:r.useMux,ts:r.ts,tries:r.tries}));for(const r of o)s+=r.data.length}const i=s>this._reliableMaxBytes?{seqs:e}:{seqs:e,pending:t};localStorage.setItem("codeman:pendingInput",JSON.stringify(i))}catch{}}_computeConnectionDescriptor(){const{bytes:e,count:t}=this._pendingBytes(),s=t>0,n=e>4,o=a=>a<1024?`${a}B`:`${(a/1024).toFixed(1)}KB`,r=n?` \xB7 ${o(e)} queued`:"";if(!this.isOnline||this._connectionStatus==="offline")return{display:"flex",dotClass:"connection-dot offline",text:n?`Offline (${o(e)} queued)`:"Offline",title:"No network connection"};if(this.activeSessionId){let a,l,c;switch(this._tilesOwnTerminal?.()?this._tileGridSocketState():this._wsState){case"connected":a="connected",l="WS",c="Terminal connected over WebSocket";break;case"fallback":a="fallback",l="HTTP",c="WebSocket unavailable \u2014 input sent over HTTP";break;case"reconnecting":a="reconnecting",l="WS\u2026",c="Reconnecting WebSocket";break;default:a="reconnecting",l="WS\u2026",c="Connecting WebSocket";break}return{display:"flex",dotClass:`connection-dot ${a}`,text:`${l}${r}`,title:c}}return this._connectionStatus==="reconnecting"||this._connectionStatus==="disconnected"?{display:"flex",dotClass:"connection-dot reconnecting",text:n?`Reconnecting (${o(e)} queued)`:"Reconnecting...",title:"Reconnecting to server"}:s?{display:"flex",dotClass:"connection-dot draining",text:n?`Sending ${o(e)}...`:"Sending...",title:"Delivering queued input"}:{display:"none",dotClass:"",text:"",title:""}}_connectionTileWords(e){const t=(e.dotClass||"").replace("connection-dot","").trim(),s=e.text||"";switch(t){case"connected":return{label:"WS",value:"live",state:t};case"fallback":return{label:"HTTP",value:"fallback",state:t};case"offline":return{label:"NET",value:"offline",state:t};case"draining":return{label:"SEND",value:"queued",state:t};case"reconnecting":return{label:s.startsWith("WS")?"WS":"SSE",value:"retry",state:t};default:return{label:"",value:"",state:t}}}_connectionTileValueText(e){if(!e)return"";const t=`Connection tile: ${e}`,s=typeof window.codemanT=="function"?window.codemanT(t):t;return s&&s!==t?s:e}_updateConnectionIndicator(){const e=this.$("connectionIndicator"),t=this.$("connectionDot"),s=this.$("connectionText");if(!e||!t||!s)return;const i=this._computeConnectionDescriptor(),n=this._lastIndicatorDescriptor,o=window.CodemanI18n?.language||"en";if(!(n&&o===this._lastIndicatorLanguage&&n.display===i.display&&n.dotClass===i.dotClass&&n.text===i.text&&n.title===i.title)&&(this._lastIndicatorDescriptor=i,this._lastIndicatorLanguage=o,e.style.display=i.display,i.display!=="none")){t.className=i.dotClass,s.textContent=i.text,e.title=i.title;const r=this.$("connectionTileLabel"),a=this.$("connectionTileValue");if(r&&a){const l=this._connectionTileWords(i);r.textContent=l.label,a.textContent=this._connectionTileValueText(l.value),a.className=`connection-tile-value ${l.state}`.trim()}}}setupOnlineDetection(){window.addEventListener("online",()=>{this.isOnline=!0,this.reconnectAttempts=0,this._connDownSince=Date.now(),this.connectSSE(),this._redeliverSweep()}),window.addEventListener("offline",()=>{this.isOnline=!1,this.setConnectionStatus("offline")})}_updateConnectionLossUi(){const e=window.CodemanConnectionLoss,t=this.$("offlineBanner"),s=this.$("offlineOverlay");if(!e||!t||!s)return;const i=e.compute({isOnline:this.isOnline,status:this._connectionStatus,everLoaded:this._initGeneration>0,downSince:this._connDownSince,now:Date.now(),nextRetryAt:this._nextSseRetryAt,overlayDismissed:this._offlineOverlayDismissed,retryPending:this._offlineRetryPending});this._connDownSince===null?this._stopOfflineTicker():this._startOfflineTicker();const n=this._offlineRetryPending?"Reconnecting\u2026":i.retryInSec!=null&&i.retryInSec>0?`Retrying in ${i.retryInSec}s`:"Retrying\u2026",o=`${i.mode}|${i.kind}|${n}`;if(o!==this._lastOfflineUiKey){if(this._lastOfflineUiKey=o,t.hidden=i.mode!=="banner",s.hidden=i.mode!=="overlay",document.body.classList.toggle("connection-lost",i.mode!=="hidden"),i.mode==="banner"){const r=this.$("offlineBannerText"),a=this.$("offlineBannerDetail");r&&(r.textContent=i.title),a&&(a.textContent=n)}else if(i.mode==="overlay"){const r=this.$("offlineOverlayTitle"),a=this.$("offlineOverlayBody"),l=this.$("offlineOverlayHost"),c=this.$("offlineOverlayStatus");r&&(r.textContent=i.title),a&&(a.textContent=i.detail),l&&(l.textContent=location.host),c&&(c.textContent=n)}}}_startOfflineTicker(){this._offlineUiTicker||(this._offlineUiTicker=setInterval(()=>this._updateConnectionLossUi(),1e3))}_stopOfflineTicker(){this._offlineUiTicker&&(clearInterval(this._offlineUiTicker),this._offlineUiTicker=null)}retryConnection(){if(this._offlineRetryPending=!0,this._nextSseRetryAt=null,this.reconnectAttempts=0,this._clearTimer("sseReconnectTimeout"),this.isOnline=navigator.onLine,this._lastOfflineUiKey="",this._updateConnectionLossUi(),this.connectSSE(),this._tilesOwnTerminal?.())for(const{tile:e}of this._tileGrid.tiles.values())e.reconnectNow();else this.activeSessionId&&this._wsState!=="connected"&&(this._wsReconnectAttempts=0,this._connectWs(this.activeSessionId));this._clearTimer("_offlineRetryTimer"),this._offlineRetryTimer=setTimeout(()=>{this._offlineRetryPending=!1,this._lastOfflineUiKey="",this._updateConnectionLossUi()},1500)}dismissOfflineOverlay(){this._offlineOverlayDismissed=!0,this._lastOfflineUiKey="",this._updateConnectionLossUi()}_updateCjkInputState(){const e=document.getElementById("cjkInput");if(!e)return;const t=this.loadAppSettingsFromStorage(),s=this.getDefaultSettings?.()||{},n=(this._serverCjkOverride||(t.cjkInputEnabled??s.cjkInputEnabled??!1))&&!!this.activeSessionId;e.classList.toggle("cjk-input-visible",!!n),document.body.classList.toggle("cjk-input-visible",!!n),e.style.display=n?"block":"none",e.setAttribute("aria-hidden",n?"false":"true"),n||(window.cjkActive=!1),typeof KeyboardHandler<"u"&&KeyboardHandler.updateLayoutForKeyboard()}_resetAllAppState(e=!1){this.sessions.clear(),this.ralphStates.clear(),e||(this.terminalBuffers.clear(),this.terminalBufferCache.clear(),this._xtermSnapshots?.clear()),this.projectInsights.clear(),this.teams.clear(),this.teamTasks.clear();for(const t of this.idleTimers.values())clearTimeout(t);if(this.idleTimers.clear(),this._clearTimer("flickerFilterTimeout"),this.flickerFilterBuffer="",this.flickerFilterActive=!1,this._clearTimer("syncWaitTimeout"),this._clearTimer("_clientDropRecoveryTimer"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._terminalWriteInFlight=!1,this._terminalWriteInFlightBytes=0,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadOwner=null,this._terminalRefreshOwner=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1,this._localEchoOverlay?.rerender(),this._predictiveEcho?.clearPredictions(),this.pendingHooks.clear(),this.approvals?.clear(),this._parentNameCache&&this._parentNameCache.clear(),this.subagentActivity.clear(),this.subagentToolResults.clear(),this.workflowRuns&&this.workflowRuns.clear(),this.workflowRunDetails&&this.workflowRunDetails.clear(),this.activeWorkflowRunId=null,this.activeWorkflowPhaseIndex=null,MobileDetection.cleanup(),KeyboardHandler.cleanup(),MobileDetection.init(),KeyboardHandler.init(),this.tabAlerts.clear(),this.attachmentHistoryCounts.clear(),this._shownCompletions&&this._shownCompletions.clear(),this.notificationManager?.titleFlashInterval&&(clearInterval(this.notificationManager.titleFlashInterval),this.notificationManager.titleFlashInterval=null),this.notificationManager?.groupingMap){for(const{timeout:t}of this.notificationManager.groupingMap.values())clearTimeout(t);this.notificationManager.groupingMap.clear()}this.planLoadingTimer&&(clearInterval(this.planLoadingTimer),this.planLoadingTimer=null),this.timerCountdownInterval&&(clearInterval(this.timerCountdownInterval),this.timerCountdownInterval=null),this.runSummaryAutoRefreshTimer&&(clearInterval(this.runSummaryAutoRefreshTimer),this.runSummaryAutoRefreshTimer=null)}handleInit(e){this._clearTimer("_initFallbackTimer");const t=++this._initGeneration;if(this._serverCjkOverride=e.inputCjkForm||!1,this._updateCjkInputState(),e.planUsage&&this.updatePlanUsageChip(e.planUsage),this.refreshRebootRestoreBanner?.(),e.version){const a=this.$("versionDisplay"),l=this.$("headerVersion");a&&(a.textContent=`v${e.version}`,a.title=`Codeman v${e.version}`),l&&(l.textContent=`v${e.version}`,l.title=`Codeman v${e.version}`)}VoiceInput.cleanup();const s=this.activeSessionId,i=t>1&&!!s&&Array.isArray(e.sessions)&&e.sessions.some(a=>a.id===s);this._resetAllAppState(i),e.sessions.forEach(a=>{this.sessions.set(a.id,a),(a.ralphLoop||a.ralphTodos)&&!this.ralphClosedSessions.has(a.id)&&this.ralphStates.set(a.id,{loop:a.ralphLoop||null,todos:a.ralphTodos||[]})});try{localStorage.removeItem("codeman-tab-meta")}catch{}if(Array.isArray(e.sessionOrder)&&e.sessionOrder.length)try{localStorage.setItem("codeman-session-order",JSON.stringify(e.sessionOrder))}catch{}this.syncSessionOrder(),this._loadTabLayout(),e.respawnStatus?this.respawnStatus=e.respawnStatus:this.respawnStatus={},this.respawnTimers={},this.respawnCountdownTimers={},this.respawnActionLogs={},e.globalStats&&(this.globalStats=e.globalStats),this.totalCost=e.sessions.reduce((a,l)=>a+(l.totalCost||0),0),this.totalCost+=e.scheduledRuns.reduce((a,l)=>a+(l.totalCost||0),0);const n=e.scheduledRuns.find(a=>a.status==="running");if(n&&(this.currentRun=n,this.showTimer()),this.updateCost(),this.renderSessionTabs(),this.seedApprovals?.(),this.sessions.size>0?this.startSystemStatsPolling():this.stopSystemStatsPolling(),this.cleanupAllFloatingWindows(),e.subagents&&(this.subagents.clear(),this.subagentActivity.clear(),this.subagentToolResults.clear(),e.subagents.forEach(a=>{this.subagents.set(a.agentId,a)}),this.renderSubagentPanel(),this.subagentParentMap.clear(),this.loadSubagentParentMap().then(()=>{for(const[a,l]of this.subagentParentMap){const c=this.subagents.get(a);if(c&&this.sessions.has(l)){c.parentSessionId=l;const d=this.sessions.get(l);d&&(c.parentSessionName=this.getSessionName(d)),this.subagents.set(a,c)}}for(const[a]of this.subagents)this.subagentParentMap.has(a)||this.findParentSessionForSubagent(a);this.restoreSubagentWindowStates()})),e.workflowRuns&&this.seedWorkflowRuns(e.workflowRuns),t!==this._initGeneration)return;if(this.isSoloWindow){this._applySoloMode();return}const o=this._reconcileTileGrid?.()===!0;if(this._urlSessionId&&this.sessions.has(this._urlSessionId)){o||this._closeStoredTileGrid?.(),this.activeSessionId=null,this._selectUrlSession();return}if(this._urlSessionId&&this._armUrlSessionWait(this._urlSessionId),o)return;const r=this.activeSessionId;if(this.sessionOrder.length===0)this.activeSessionId=null;else{let a=r;if(!a||!this.sessions.has(a))try{a=localStorage.getItem("codeman-active-session")}catch{}if(i&&a===r&&this.sessions.has(a))this._wsSessionId!==a&&this._connectWs(a),this._onSessionNeedsRefresh({id:a}),this._splitPane?.reconnectNow?.();else{if(this.activeSessionId=null,this._restoreTileGrid?.())return;a&&this.sessions.has(a)?this.selectSession(a,{auto:!0}):this.selectSession(this.sessionOrder[0],{auto:!0})}}}async loadState(){try{const t=await(await fetch("/api/status")).json();this.handleInit(t?.data??{})}catch(e){console.error("Failed to load state:",e)}}_debouncedCall(e,t,s=100){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{this._debounceTimers[e]=null,t.call(this)},s)}getSessionListLayout(){if(this.soloSessionId)return"header";const e=this.loadAppSettingsFromStorage(),t=this.getDefaultSettings(),s=e.sessionListLayout??t.sessionListLayout??"header";return s==="sidebar"||s==="sidebar-rich"?s:"header"}resolveSessionSidebarFontSize(e){const t=Number(e);return Number.isInteger(t)&&t>=11&&t<=18?t:12}applySessionSidebarFontSize(e=null){const t=e??this.loadAppSettingsFromStorage(),s=this.resolveSessionSidebarFontSize(t?.sessionSidebarFontSize);return document.documentElement.style.setProperty("--session-sidebar-name-font-size",`${s}px`),s}isSessionSidebarActive(){return document.documentElement.dataset.sessionList==="sidebar"}_tabOrientation(){return document.documentElement.getAttribute("data-tab-orientation")==="vertical"?"vertical":"horizontal"}_isVerticalTabList(){return this.isSessionSidebarActive()||this._tabOrientation()==="vertical"}shouldInlineSessionActions(){return this.isSessionSidebarActive()?!this.isSessionSidebarCollapsed():this._tabOrientation()==="vertical"&&!document.documentElement.classList.contains("tab-rail-compact")}isSessionSidebarRich(){const e=document.documentElement;return e.dataset.sessionList==="sidebar"&&e.dataset.sidebarDetail==="rich"}isTabRailRich(){const e=document.documentElement;return e.getAttribute("data-tab-orientation")==="vertical"&&e.dataset.tabRailDetail==="rich"&&!e.classList.contains("tab-rail-compact")}isRichTabRows(){return this.isSessionSidebarRich()||this.isTabRailRich()}isTabRailSorted(){const e=document.documentElement;return e.getAttribute("data-tab-orientation")==="vertical"&&e.dataset.tabRailSort==="activity"}_tabRailSortOrder(e){if(!this.isTabRailSorted()||!window.CodemanSessionOrder||typeof this._mobileOverviewState!="function")return null;const t=[];for(let n=0;n<e.length;n++){const o=this.sessions.get(e[n]);o&&t.push({id:e[n],state:this._mobileOverviewState(o,this.pendingHooks?.get(e[n])),lastActivityAt:Number(o.lastActivityAt)||0,lastSubmitAt:Number(o.lastSubmitAt)||0,orderIndex:n})}const s=window.CodemanSessionOrder.sort(t),i=new Map;for(let n=0;n<s.length;n++)i.set(s[n].id,n);return i}isTabTriage(){return document.documentElement.dataset.tabArrangement==="state"}_tabTriageLayout(e,t,s){if(t||!this.isTabTriage()||!window.CodemanTabTriage||typeof this._mobileOverviewState!="function")return null;const i=[];for(let r=0;r<e.length;r++){const a=this.sessions.get(e[r]);if(!a)continue;const l=this._mobileOverviewState(a,this.pendingHooks?.get(e[r]));i.push({id:e[r],state:l,exited:!!this._mobileOverviewExit?.(l,a),pos:s?.has(e[r])?s.get(e[r]):r})}const n=(this.webviewOrder||[]).filter(r=>this.webviews?.has(r)),o=document.documentElement.dataset.tabStateOrder==="urgent-last";return window.CodemanTabTriage.layout(i,n,{reverse:o})}_syncTabTriageChrome(e,t){if(!e)return;this._lastTabTriage=t,e.classList.toggle("tabs-triage",!!t);const s=new Map((t?.groups||[]).map(n=>[n.key,n]));for(const n of[...e.querySelectorAll(":scope > .tab-triage-head, :scope > .tab-triage-break")])s.has(n.dataset.triageGroup)||n.remove();const i=(n,o)=>{let r=e.querySelector(`:scope > .${n}[data-triage-group="${o}"]`);return r||(r=document.createElement("div"),r.className=n==="tab-triage-head"?`tab-triage-head tab-triage-head--${o}`:n,r.dataset.triageGroup=o,r.setAttribute("aria-hidden","true"),e.appendChild(r)),r};for(const n of s.values()){const o=i("tab-triage-head",n.key);if(o.classList.toggle("tab-triage-head--quiet",!!n.quiet),!n.quiet&&!o.firstElementChild){const d=document.createElement("span");d.className="tab-triage-label",d.textContent=n.label;const h=document.createElement("span");h.className="tab-triage-count",o.append(d,h)}const r=String(n.count);!n.quiet&&o.lastElementChild.textContent!==r&&(o.lastElementChild.textContent=r),o.classList.toggle("tab-triage-head--lead",n===t.groups[0]);const a=String(n.headOrder);o.style.order!==a&&(o.style.order=a);const l=i("tab-triage-break",n.key),c=String(n.breakOrder);l.style.order!==c&&(l.style.order=c)}for(const n of e.querySelectorAll(":scope > .session-tab[data-webview-id]")){const o=n.dataset.webviewId,r=t?.webOrder.has(o)?String(t.webOrder.get(o)):"";n.style.order!==r&&(n.style.order=r)}this._sizeTabTriageGutter(e,t)}_sizeTabTriageGutter(e,t){const s=!!e.parentElement?.classList.contains("session-tabs-host");if(!t||!s){e.style.getPropertyValue("--tab-triage-gutter")&&e.style.removeProperty("--tab-triage-gutter"),e.style.getPropertyValue("--tab-triage-brand")&&e.style.removeProperty("--tab-triage-brand"),this._tabTriageGutterKey=null;return}if(this._watchTabTriageBrand(e),Number.isFinite(this._tabTriageBrandWidth)){const o=`${this._tabTriageBrandWidth}px`;e.style.getPropertyValue("--tab-triage-brand")!==o&&e.style.setProperty("--tab-triage-brand",o)}if(!e.classList.contains("tabs-auto-wrap")&&!e.classList.contains("tabs-two-rows")){this._tabTriageGutterKey=null;return}const i=t.groups.map(o=>`${o.key}:${o.count}`).join("|");if(i===this._tabTriageGutterKey)return;let n=0;for(const o of e.querySelectorAll(":scope > .tab-triage-head")){let r=0,a=0;for(const l of o.children){const c=l.getBoundingClientRect().width;c>0&&(r+=c,a++)}a&&(n=Math.max(n,r+5*(a-1)))}n&&(this._tabTriageGutterKey=i,e.style.setProperty("--tab-triage-gutter",`${Math.ceil(n+10)}px`),!this._tabTriageFontsHooked&&document.fonts?.ready&&(this._tabTriageFontsHooked=!0,document.fonts.ready.then(()=>{this._tabTriageGutterKey=null,this._sizeTabTriageGutter(this.$("sessionTabs"),this._lastTabTriage)})))}_watchTabTriageBrand(e){if(this._tabTriageBrandObserver!==void 0)return;const t=e.closest(".header")?.querySelector(":scope > .header-brand");if(!t||typeof ResizeObserver!="function"){this._tabTriageBrandObserver=null;return}const s=8;this._tabTriageBrandWidth=Math.ceil(t.getBoundingClientRect().width+s),this._tabTriageBrandObserver=new ResizeObserver(i=>{const n=i[0]?.borderBoxSize?.[0],o=Math.ceil((n?n.inlineSize:t.getBoundingClientRect().width)+s);o!==this._tabTriageBrandWidth&&(this._tabTriageBrandWidth=o,this._sizeTabTriageGutter(this.$("sessionTabs"),this._lastTabTriage))}),this._tabTriageBrandObserver.observe(t)}_isTabDropAcrossGroups(e){const t=this.$("sessionTabs");if(!t||!this.draggedTabId||!e)return!1;const s=t.classList.contains("tabs-triage"),i=t.classList.contains("tabs-clusters");if(!s&&!i)return!1;const n=t.querySelector(`.session-tab[data-id="${this.draggedTabId}"]`);if(!n)return!1;if(i)return n.closest(".tab-cluster")!==e.closest(".tab-cluster");const o=window.CodemanTabTriage?.STRIDE||1e4,r=a=>Math.floor((Number(a.style.order)||0)/o);return r(n)!==r(e)}isTabClusters(){return document.documentElement.dataset.tabArrangement==="case"}isTabLedger(){return document.documentElement.dataset.tabArrangement==="ledger"}_tabClusterIdentity(e,t){const s=(e.workingDir||"").replace(/\/+$/,""),i=s&&typeof this._mobileOverviewCaseFor=="function"?this._mobileOverviewCaseFor(s,this.cases):null;return i?{key:i.path,label:i.name||""}:s?{key:s,label:s.split("/").pop()||s}:{key:`session:${t}`,label:""}}_tabClusterLayout(e,t){if(t||!this.isTabClusters()||!window.CodemanTabClusters)return null;const s=[];for(const a of e){const l=this.sessions.get(a);l&&s.push({id:a,...this._tabClusterIdentity(l,a)})}const i=window.CodemanTabClusters.compute(s),n=new Map;for(const a of i)if(a.ids.length>1)for(const l of a.ids)n.set(l,a.label);const o=(this.webviewOrder||[]).filter(a=>this.webviews?.has(a)),r=JSON.stringify([i.map(a=>[a.key,a.label,a.ids]),o]);return{clusters:i,labelFor:n,webviewIds:o,key:r}}_renderTabClusters(e,t,s){const i=[];for(const n of e.clusters){const o=n.ids.map(l=>t.get(l)||"").join(""),r=n.ids.length<2,a=`<span class="tab-cluster-label" aria-hidden="true"><span class="tab-cluster-swatch"></span><span class="tab-cluster-name" data-i18n-skip>${escapeHtml(n.label)}</span><span class="tab-cluster-count">${n.ids.length}</span></span>`;i.push(`<div class="tab-cluster${r?" tab-cluster--single":""}" role="presentation" data-cluster-key="${escapeHtml(n.key)}" style="--cluster-color: var(--session-${n.color})">${a}${o}</div>`)}return e.webviewIds.forEach((n,o)=>{const r=this.renderWebviewTab?.(n,s+o)||"";r&&i.push(`<div class="tab-cluster tab-cluster--single tab-cluster--web" role="presentation">${r}</div>`)}),i.join("")}_tabNameHtml(e,t){const s=parseSessionPrefix(e);if(s&&s.suffix)return`<span class="tab-name-prefix">${escapeHtml(s.prefix)}: </span>${escapeHtml(s.suffix)}`;const i=t?window.CodemanTabClusters?.nameSplit(e,t):null;return i?`${escapeHtml(i.shown)}<span class="tab-name-case">${escapeHtml(i.hidden)}</span>`:escapeHtml(e)}_syncTabArrangementClasses(e,{clusters:t,groupProjection:s}){e&&(e.classList.toggle("tabs-clusters",!!t),e.classList.toggle("tabs-ledger",this.isTabLedger()&&!s))}_isSessionSidebarOverlay(){return window.innerWidth<1024}isSessionSidebarCollapsed(){if(this._sidebarCollapsedOverride!==void 0)return this._sidebarCollapsedOverride;let e=null;try{e=localStorage.getItem("codeman-sidebar-collapsed")}catch{}return e===null?this._isSessionSidebarOverlay():e==="1"}shouldToggleSessionSidebarFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey||!this.isSessionSidebarActive()||typeof this.getShortcutRegistry!="function"||typeof this.matchesShortcutEvent!="function")return!1;const t=this.getShortcutRegistry().find(s=>s.id==="toggle-session-sidebar");return!t||t.disabled?!1:this.matchesShortcutEvent(e,t)}applySessionListLayout(){const e=this.getSessionListLayout();this.applySessionSidebarFontSize();const t=e==="sidebar"||e==="sidebar-rich",s=this.isSessionSidebarCollapsed(),i=document.documentElement.dataset.sessionList,n=document.documentElement.dataset.sidebarDetail,o=document.documentElement.dataset.sidebar,r=document.getElementById("sessionTabs"),a=document.getElementById("sessionTabsHost"),l=document.getElementById("sessionSidebarList");if(!r||!a||!l)return;const c=document.getElementById("tabRail"),d=!t&&document.documentElement.getAttribute("data-tab-orientation")==="vertical",h=t?l:d&&c?c:a;r.parentElement!==h&&h.appendChild(r),document.documentElement.dataset.sessionList=t?"sidebar":"header",document.documentElement.dataset.sidebarDetail=e==="sidebar-rich"?"rich":"simple",document.documentElement.dataset.sidebar=s?"collapsed":"expanded",r.setAttribute("aria-orientation",h===a?"horizontal":"vertical");const u=document.getElementById("sidebarToggleBtn");if(u){u.classList.toggle("btn-sidebar-toggle--hidden",!t);const w=s?"Expand session sidebar":"Collapse session sidebar";u.setAttribute("aria-expanded",s?"false":"true"),u.setAttribute("aria-label",w),u.setAttribute("title",w)}const S=document.getElementById("sessionSidebar");if(S){S.classList.toggle("open",t&&!s);const w=t&&s&&this._isSessionSidebarOverlay();S.toggleAttribute("inert",w),w?S.setAttribute("aria-hidden","true"):S.removeAttribute("aria-hidden")}if(!t){this._sidebarFilter="";const w=document.getElementById("sessionSidebarFilter");w&&(w.value="")}const m=this._tallTabsEnabled;this.applyTabWrapSettings();const v=i!==document.documentElement.dataset.sessionList||n!==document.documentElement.dataset.sidebarDetail,b=o!==document.documentElement.dataset.sidebar;(v||b)&&m===this._tallTabsEnabled&&this._fullRenderSessionTabs(),t&&r.classList.remove("tabs-auto-wrap"),this.applySidebarFilter(this._sidebarFilter),this.updateConnectionLines(),document.getElementById("welcomeOverlay")?.classList.contains("visible")&&this.showHomeSessions?.(),this.isRichTabRows()?this._startSidebarRichClock():this._stopSidebarRichClock()}toggleSessionSidebar(){if(!this.isSessionSidebarActive())return;const e=!this.isSessionSidebarCollapsed();this._sidebarCollapsedOverride=e;try{localStorage.setItem("codeman-sidebar-collapsed",e?"1":"0")}catch{}e&&this.$("sessionSidebar")?.contains(document.activeElement)&&document.getElementById("sidebarToggleBtn")?.focus(),this.applySessionListLayout(),!e&&this._isSessionSidebarOverlay()&&this.$("sessionTabs")?.querySelector(".session-tab.active")?.focus()}closeSessionSidebarOnHandheld(){this._isSessionSidebarOverlay()&&(!this.isSessionSidebarActive()||this.isSessionSidebarCollapsed()||this.toggleSessionSidebar())}updateSidebarCount(){const e=document.getElementById("sessionSidebarCount");if(!e)return;const t=this.$("sessionTabs"),s=t?t.querySelectorAll(".session-tab:not(.tab-filtered-out)").length:this.sessions?.size??0;e.textContent=String(s)}applySidebarFilter(e){this._sidebarFilter=(e??"").trim().toLowerCase(),this._applyTabListFilter()}_applyTabListFilter(){const e=this.$("sessionTabs");if(!e)return;const t=this._tabOrientation()==="vertical",s=!t&&this.isSessionSidebarActive()&&document.documentElement.dataset.sidebar!=="collapsed",i=t?this._tabRailSearch:s?this._sidebarFilter:"",n=[...e.querySelectorAll(".session-tab")].map(d=>({key:d,text:t?this._tabRowSearchName(d):`${d.getAttribute("aria-label")||""} ${d.getAttribute("title")||""}`,section:d.closest(".tab-layout-group, .tab-cluster"),keep:!d.dataset.webviewId&&!!d.dataset.id&&!!this.tabAlerts?.get(d.dataset.id)})),o=window.CodemanTabSearch?.filter(n,i);if(!o)return;let r=!1;e.classList.contains("tabs-filtering")!==o.active&&(e.classList.toggle("tabs-filtering",o.active),r=!0);const a=(d,h)=>{d.classList.contains("tab-filtered-out")!==h&&(d.classList.toggle("tab-filtered-out",h),r=!0)};for(const d of n)a(d.key,o.hidden.has(d.key));for(const d of e.querySelectorAll(".tab-layout-group, .tab-cluster")){const h=o.counts.get(d)??0;a(d,o.active&&h===0);const u=d.querySelector(".tab-layout-group-count, .tab-cluster-count");if(!u)continue;u.dataset.total===void 0&&(u.dataset.total=u.textContent);const S=o.active?String(h):u.dataset.total;u.textContent!==S&&(u.textContent=S)}const l=document.getElementById("tabRailSearchEmpty"),c=!(t&&o.active&&o.matchCount===0);if(l&&l.hidden!==c&&(l.hidden=c,r=!0),r&&this.updateConnectionLines?.(),(r||o.active)&&e.getAttribute("role")==="tree"){const d=this._applyTabTreePositions(e),h=e.querySelector('[role="treeitem"][tabindex="0"]');d.length&&!d.includes(h)&&this._setTabTreeStop(e,d.find(u=>u.getAttribute("aria-selected")==="true")||d[0])}this.updateSidebarCount()}_tabRowSearchName(e){return e.dataset.webviewId?this.webviews?.get(e.dataset.webviewId)?.name||"":e.querySelector(".tab-name")?.dataset.fullName||""}_tabRailSearchActive(){return this._tabOrientation()==="vertical"&&!!window.CodemanTabSearch?.needle(this._tabRailSearch)}setTabRailSearch(e){this._tabRailSearch=typeof e=="string"?e:"";const t=document.getElementById("tabRailSearchClear");t&&(t.hidden=this._tabRailSearch.length===0),this._isTabGroupStructureStale()?this._fullRenderSessionTabs():this._applyTabListFilter()}clearTabRailSearch(){const e=document.getElementById("tabRailSearch");e&&(e.value=""),this.setTabRailSearch(""),e?.focus()}handleTabRailSearchKeydown(e){e.key!=="Escape"||e.isComposing||!this._tabRailSearch||(e.preventDefault(),e.stopPropagation(),this.clearTabRailSearch())}_resetTabRailSearch(){this._tabRailSearch="";const e=document.getElementById("tabRailSearch");e&&(e.value="");const t=document.getElementById("tabRailSearchClear");t&&(t.hidden=!0);const s=document.getElementById("tabRailSearchEmpty");s&&(s.hidden=!0)}_sidebarRichPillLabel(e){return{needs:"needs you",error:"error",waiting:"waiting",working:"working",idle:"idle",done:"done"}[e]||e}_sidebarRichRow(e,t){if(typeof this._mobileOverviewState!="function")return null;const s=this._mobileOverviewState(t,this.pendingHooks?.get(e)),i=this._mobileOverviewExit?this._mobileOverviewExit(s,t):null,n=!!i;return{state:s,exited:n,pill:n?"exited":this._sidebarRichPillLabel(s),watching:typeof t.watching=="string"?t.watching:"",createdAt:Number(t.createdAt)||0,since:i?i.since:this._mobileOverviewSince?this._mobileOverviewSince(s,t):null}}_sidebarRichMetaHTML(e){if(!e)return"";const t=(r,a,l,c)=>{const d=this._sidebarRichStampText(a,l),h=a?` title="${escapeHtml(`${r==="created"?"First created":r}: ${new Date(a).toLocaleString()}`)}"`:"";return`<span class="tab-meta-item ${c}"${h}><span class="tab-meta-key">${escapeHtml(r)}</span><span data-tab-ts="${a||0}" data-tab-fmt="${l}">${escapeHtml(d)}</span></span>`},s=[t("created",e.createdAt,"ago","tab-meta-created")];e.since&&(s.push('<span class="tab-meta-sep" aria-hidden="true">\xB7</span>'),s.push(t(e.since.key,e.since.at,"for","tab-meta-since")));const i=e.exited?"exited":e.state;if(s.push(`<span class="tab-pill tab-pill--${escapeHtml(i)}">${escapeHtml(e.pill)}</span>`),e.watching){const r=escapeHtml(`Still running in the background: ${e.watching}`);s.push(`<span class="tab-pill tab-pill--watching" title="${r}">watching</span>`)}const n=[e.createdAt?`First created: ${new Date(e.createdAt).toLocaleString()}`:"",e.since&&e.since.at?`${e.since.key}: ${new Date(e.since.at).toLocaleString()}`:""].filter(Boolean).join(" \xB7 ");return`<span class="tab-meta"${n?` title="${escapeHtml(n)}"`:""} data-i18n-skip>${s.join("")}</span>`}_sidebarRichStampText(e,t){return this._mobileOverviewStampText?this._mobileOverviewStampText(e,t):"\u2014"}_updateSidebarRichRow(e,t,s){const i=this._sidebarRichRow(t,s);if(!i)return;const n=e.dataset.tabState,o=`${i.state}${i.exited?"+exited":""}:${i.since?i.since.at:0}:${i.createdAt}:${i.watching}`;if(e.dataset.tabMetaSig===o)return;e.dataset.tabMetaSig=o,e.dataset.tabState=i.state,n&&e.classList.remove(`tab-state-${n}`),e.classList.add(`tab-state-${i.state}`);const r=e.querySelector(".tab-info");if(!r)return;const a=this._sidebarRichMetaHTML(i),l=r.querySelector(".tab-meta");l?l.outerHTML=a:r.insertAdjacentHTML("beforeend",a)}_startSidebarRichClock(){this._sidebarRichClock||(this._sidebarRichClock=setInterval(()=>{if(!this.isRichTabRows()){this._stopSidebarRichClock();return}this._tickSidebarRichTimes()},SIDEBAR_RICH_CLOCK_MS))}_stopSidebarRichClock(){this._sidebarRichClock&&(clearInterval(this._sidebarRichClock),this._sidebarRichClock=null)}_tickSidebarRichTimes(){const e=this.$("sessionTabs");if(e)for(const t of e.querySelectorAll("[data-tab-ts]")){const s=this._sidebarRichStampText(Number(t.dataset.tabTs)||0,t.dataset.tabFmt);t.textContent!==s&&(t.textContent=s)}}renderSessionTabs({immediate:e=!1}={}){if(!this._inlineRenameActive){if(e){clearTimeout(this._debounceTimers.sessionTabs),this._debounceTimers.sessionTabs=null,this._renderSessionTabsImmediate();return}this._debouncedCall("sessionTabs",this._renderSessionTabsImmediate)}}_updateActiveTabImmediate(e){const t=this.$("sessionTabs");if(!t)return;if(this._isTabGroupStructureStale()){this._fullRenderSessionTabs();return}const s=t.querySelectorAll(".session-tab[data-id]");for(const i of s)i.dataset.id===e?i.classList.add("active"):i.classList.remove("active");this._syncTabTreeSelection(t),this._scrollActiveTabIntoView(e),this._noteActiveTabBand(t),this._lineageTotalEdges>0&&this.updateConnectionLines()}_scrollActiveTabIntoView(e,t="smooth"){const s=this.$("sessionTabs");if(!s)return;const i=e&&s.querySelector(`.session-tab[data-id="${e}"]`)||s.querySelector(".session-tab.active");if(!i)return;if(this._isVerticalTabList()){i.scrollIntoView({block:"nearest"});return}const n=window.CodemanTabOverflow?.computeTabScrollLeft;if(!n)return;const o=s.getBoundingClientRect(),r=i.getBoundingClientRect(),a=n({scrollLeft:s.scrollLeft,clientWidth:s.clientWidth,scrollWidth:s.scrollWidth,tabLeft:r.left-o.left+s.scrollLeft,tabWidth:r.width});if(Math.abs(a-s.scrollLeft)<1)return;const l=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;typeof s.scrollTo=="function"?s.scrollTo({left:a,behavior:l?"auto":t}):s.scrollLeft=a}_noteActiveTabBand(e){const t=this.activeWebviewId?null:this.activeSessionId,s=t&&e?e.querySelector(`.session-tab[data-id="${t}"]`):null,i=this._activeTabBand;if(!s)return this._activeTabBand=null,!1;const n=s.style.order,o=window.CodemanTabTriage?.STRIDE||1e4,r=n===""?null:Math.floor(Number(n)/o);return this._activeTabBand={id:t,band:r},!!i&&i.id===t&&i.band!==r}_isScrollingTabRow(e){return!this._isVerticalTabList()&&!e.classList.contains("tabs-auto-wrap")&&!e.classList.contains("tabs-two-rows")}_tabAnchor(e){return this._isVerticalTabList()?{x:e.right,y:e.top+e.height/2,spawnLeft:e.right+14,spawnTop:e.top,vertical:!1}:{x:e.left+e.width/2,y:e.bottom,spawnLeft:e.left,spawnTop:e.bottom,vertical:!0}}_paintedSessionTab(e){if(!e)return null;const t=document.querySelector(`.session-tab[data-id="${e}"]`);return t&&t.getClientRects().length>0?t:null}_tabConnectorPath(e,t){if(e.vertical){const o=t.left+t.width/2,r=t.top,a=(e.y+r)/2;return`M ${e.x} ${e.y} C ${e.x} ${a}, ${o} ${a}, ${o} ${r}`}const s=t.left,i=t.top+t.height/2,n=(e.x+s)/2;return`M ${e.x} ${e.y} C ${n} ${e.y}, ${n} ${i}, ${s} ${i}`}_setTerminalLoadState(e,t,s){this.terminalLoadStates.set(e,{generation:t,phase:s}),this._updateTerminalLoadTab(e)}_clearTerminalLoadState(e,t){const s=this.terminalLoadStates.get(e);s&&s.generation!==t||(this.terminalLoadStates.delete(e),this._updateTerminalLoadTab(e))}_updateTerminalLoadTab(e){const t=this.$("sessionTabs")?.querySelector(`.session-tab[data-id="${e}"]`);if(!t)return;const s=this.terminalLoadStates.get(e);if(t.classList.toggle("tab-loading",!!s),s){if(t.setAttribute("aria-busy","true"),t.dataset.loadPhase=s.phase,!t.querySelector(".tab-load-spinner")){const i=document.createElement("span");i.className="tab-load-spinner",i.setAttribute("aria-hidden","true");const n=t.querySelector(".tab-number");n?n.insertAdjacentElement("afterend",i):t.insertBefore(i,t.firstChild)}}else t.setAttribute("aria-busy","false"),delete t.dataset.loadPhase,t.querySelector(".tab-load-spinner")?.remove()}_renderSessionTabsImmediate(){if(this._inlineRenameActive)return;const e=this.$("sessionTabs"),t=e.querySelectorAll(".session-tab[data-id]"),s=new Set([...t].map(h=>h.dataset.id)),i=this._projectTabGroups(),n=i?new Set(i.visibleRefs.filter(h=>h.kind==="session").map(h=>h.id)):new Set(this.sessions.keys()),o=[...e.querySelectorAll(".session-tab[data-webview-id]")].map(h=>h.dataset.webviewId),r=i?i.visibleRefs.filter(h=>h.kind==="webview").map(h=>h.id):(this.webviewOrder||[]).filter(h=>this.webviews?.has(h)),a=o.length===r.length&&o.every((h,u)=>h===r[u]),l=this._tabClusterLayout(this.sessionOrder.filter(h=>this.sessions.has(h)),i),c=s.size===n.size&&[...s].every(h=>n.has(h))&&a&&!this._isTabGroupStructureStale(i)&&(l?l.key:null)===(this._lastTabClusterKey??null);let d=!1;if(c){const h=this.isRichTabRows(),u=this.sessionOrder.filter(b=>this.sessions.has(b)),S=this._tabRailSortOrder(u),m=this._tabTriageLayout(u,i,S),v=m?m.order:S;for(const[b,w]of this.sessions){const p=e.querySelector(`.session-tab[data-id="${b}"]`);if(!p)continue;const _=v?.has(b)?String(v.get(b)):"";p.style.order!==_&&(p.style.order=_);const T=b===this.activeSessionId&&!this.activeWebviewId,N=w.status||"idle",R=this.getSessionName(w),D=w.taskStats||{running:0,total:0},k=D.running>0,E=this.terminalLoadStates.get(b);if(T&&!p.classList.contains("active")?p.classList.add("active"):!T&&p.classList.contains("active")&&p.classList.remove("active"),p.classList.toggle("tab-loading",!!E),E){if(p.setAttribute("aria-busy","true"),p.dataset.loadPhase=E.phase,!p.querySelector(".tab-load-spinner")){const y=document.createElement("span");y.className="tab-load-spinner",y.setAttribute("aria-hidden","true");const L=p.querySelector(".tab-number");L?L.insertAdjacentElement("afterend",y):p.insertBefore(y,p.firstChild)}}else p.setAttribute("aria-busy","false"),delete p.dataset.loadPhase,p.querySelector(".tab-load-spinner")?.remove();const W=this.tabAlerts.get(b),B=W==="action",V=W==="idle",H=p.classList.contains("tab-alert-action"),x=p.classList.contains("tab-alert-idle");if(B&&!H?(p.classList.add("tab-alert-action"),p.classList.remove("tab-alert-idle")):V&&!x?(p.classList.add("tab-alert-idle"),p.classList.remove("tab-alert-action")):!W&&(H||x)&&p.classList.remove("tab-alert-action","tab-alert-idle"),p.classList.toggle("in-tiles",!!this._tileGrid?.has(b)),!p.querySelector(".tab-number")){const y=this.sessionOrder.indexOf(b);if(y>=0&&y<9){const L=document.createElement("span");L.className="tab-number",L.textContent=String(y+1),p.insertBefore(L,p.firstChild)}}const C=p.querySelector(".tab-status");C&&!C.classList.contains(N)&&(C.className=`tab-status ${N}`),applyPaneExitBadge(p,w.paneExit),h?this._updateSidebarRichRow(p,b,w):p.dataset.tabState&&(p.querySelector(".tab-meta")?.remove(),p.classList.remove(`tab-state-${p.dataset.tabState}`),delete p.dataset.tabState,delete p.dataset.tabMetaSig);const O=p.querySelector(".tab-name");if(O){const y=parseSessionPrefix(R);if(O.dataset.fullName!==R){O.replaceChildren();const L=y&&y.suffix?null:window.CodemanTabClusters?.nameSplit(R,l?.labelFor.get(b));if(y&&y.suffix){const g=document.createElement("span");g.className="tab-name-prefix",g.textContent=`${y.prefix}: `,O.append(g,document.createTextNode(y.suffix))}else if(L){const g=document.createElement("span");g.className="tab-name-case",g.textContent=L.hidden,O.append(document.createTextNode(L.shown),g)}else O.textContent=R;O.dataset.fullName=R,p.title=y&&y.suffix?w.workingDir?`${y.prefix} (${w.workingDir})`:y.prefix:w.workingDir||""}}const $=p.querySelector(".tab-badge");if(k)if($)$.textContent!==String(D.running)&&($.textContent=D.running);else{this._fullRenderSessionTabs();return}else if($){this._fullRenderSessionTabs();return}const I=p.querySelector(".tab-subagent-badge"),F=this.minimizedSubagents.get(b),M=F?.size||0;if(M>0&&I){const y=I.querySelector(".subagent-label"),L=M===1?"AGENT":`AGENTS (${M})`;y&&y.textContent!==L&&(y.textContent=L);const g=I.querySelector(".subagent-dropdown");if(g){const P=this.renderSubagentTabBadge(b,F),G=document.createElement("div");G.innerHTML=P;const A=G.querySelector(".subagent-dropdown");A&&(g.innerHTML=A.innerHTML)}}else if(M>0&&!I){const y=this.renderSubagentTabBadge(b,F),L=p.querySelector(":scope > .tab-actions");L?L.insertAdjacentHTML("beforebegin",y):p.insertAdjacentHTML("beforeend",y)}else M===0&&I&&I.remove()}i&&e.getAttribute("role")==="tree"&&(this._syncTabTreeSelection(e),this._applyTabTreePositions(e),this._syncTabGroupHeaderAlerts(e,i)),this._syncTabTriageChrome(e,m),this._syncTabArrangementClasses(e,{clusters:!!l,groupProjection:i}),d=this._noteActiveTabBand(e)}else this._fullRenderSessionTabs();this._lastRenderedActiveTabId=this.activeSessionId,this.updateTabOverflowMode(),d&&this._isScrollingTabRow(e)&&this._scrollActiveTabIntoView(this.activeSessionId),this._applyTabEntrances?.(),this._refreshMobileOverviewIfVisible?.(),this._refreshHomeSessionsIfVisible?.(),(this._lineageTotalEdges>0||this._isVerticalTabList())&&this.updateConnectionLines(),this.applySidebarFilter(this._sidebarFilter)}updateTabOverflowMode(){const e=this.$("sessionTabs");if(!e)return;if(this._syncLineageGutter?.(),this.isSessionSidebarActive()){e.classList.remove("tabs-auto-wrap");return}const t=MobileDetection.getDeviceType(),s=this.loadAppSettingsFromStorage(),i=this.getDefaultSettings(),n=t==="desktop"?s.tabTwoRows??i.tabTwoRows??!1:!1;if((window.CodemanTabOverflow?.resolveTabOrientation?window.CodemanTabOverflow.resolveTabOrientation({deviceType:t,setting:s.tabOrientation??i.tabOrientation??"horizontal"}):"horizontal")==="vertical"){e.classList.remove("tabs-auto-wrap");return}if(n||t!=="desktop"){e.classList.remove("tabs-auto-wrap"),this._sizeTabTriageGutter(e,this._lastTabTriage);return}if(e.classList.contains("tabs-triage")||e.classList.contains("tabs-ledger")){e.classList.add("tabs-auto-wrap"),this._sizeTabTriageGutter(e,this._lastTabTriage);return}e.classList.remove("tabs-auto-wrap");const r=window.CodemanTabOverflow?.shouldAutoWrapTabs?window.CodemanTabOverflow.shouldAutoWrapTabs({deviceType:t,manualTwoRows:n,tabCount:this.sessions.size,scrollWidth:e.scrollWidth,clientWidth:e.clientWidth,innerWrap:e.classList.contains("tabs-clusters")&&this._tabClustersWrapInside(e)}):e.scrollWidth>e.clientWidth+1;e.classList.toggle("tabs-auto-wrap",r)}_tabClustersWrapInside(e){for(const t of e.querySelectorAll(":scope > .tab-cluster")){const s=t.querySelectorAll(":scope > .session-tab");if(s.length>1&&s[s.length-1].offsetTop>s[0].offsetTop+4)return!0}return!1}_setupTabMiddleClickClose(){const e=this.$("sessionTabs");!e||this._tabAuxClickBound||(this._tabAuxClickBound=!0,e.addEventListener("auxclick",t=>{if(t.button!==1)return;const s=t.target.closest?.(".session-tab");s&&(t.preventDefault(),t.stopPropagation(),s.dataset.id?this.requestCloseSession(s.dataset.id):s.dataset.webviewId&&this.closeWebviewTab?.(s.dataset.webviewId))}))}_fullRenderSessionTabs(){if(this.closeTabRailActionMenu?.(),this._inlineRenameActive)return;this.closeTabGroupMenu();const e=this.$("sessionTabs");this.isSessionSidebarActive()&&(this._tallTabsEnabled=!0,e.classList.add("tabs-show-folder"),e.classList.remove("tabs-two-rows","tabs-auto-wrap")),document.querySelectorAll("body > .subagent-dropdown").forEach(_=>_.remove()),this.cancelHideSubagentDropdown();const t=e.scrollLeft,s=e.scrollTop,i=this._lastRenderedActiveTabId,n=!e.querySelector(".session-tab"),o=e.contains(document.activeElement)||this._tabRefocusAfterEdit===!0,r=this._tabFocusIdentity||(o?this._tabTreeIdentity(document.activeElement):null);this._tabFocusIdentity=null,this._tabRefocusAfterEdit=!1;const a=[],l=this.sessionOrder,c=this.isRichTabRows(),d=l.filter(_=>this.sessions.has(_)),h=this._tabRailSortOrder(d),u=this._projectTabGroups(),S=this._tabTriageLayout(d,u,h),m=S?S.order:h,v=this._tabClusterLayout(d,u),b=new Map;let w=0;for(const _ of l){const T=this.sessions.get(_);if(!T)continue;const N=m?.has(_)?` style="order:${m.get(_)}"`:"",R=_===this.activeSessionId&&!this.activeWebviewId,D=T.status||"idle",k=this.getSessionName(T),E=T.mode||"claude",W=T.color||"default",B=T.taskStats||{running:0,total:0},V=B.running>0,H=this.tabAlerts.get(_),x=H==="action"?" tab-alert-action":H==="idle"?" tab-alert-idle":"",C=this.terminalLoadStates.get(_),O=this.minimizedSubagents.get(_),I=(O?.size||0)>0?this.renderSubagentTabBadge(_,O):"",F=this.renderUltracodeTabBadge?this.renderUltracodeTabBadge(_):"",M=T.workingDir&&T.workingDir.split("/").pop()||"",L=(this._tallTabsEnabled??!1)&&T.name&&M&&M!==k,g=parseSessionPrefix(k),P=this._tabNameHtml(k,v?.labelFor.get(_)),G=g&&g.suffix?T.workingDir?`${g.prefix} (${T.workingDir})`:g.prefix:T.workingDir||"",A=c?this._sidebarRichRow(_,T):null,z=this._sidebarRichMetaHTML(A),j=A?` tab-state-${A.state}`:"",J=A?` data-tab-state="${A.state}" data-tab-meta-sig="${A.state}${A.exited?"+exited":""}:${A.since?A.since.at:0}:${A.createdAt}:${escapeHtml(A.watching)}"`:"",U=paneExitLabel(T.paneExit),X=E==="shell"?'<span class="tab-mode shell" aria-hidden="true">sh</span>':`<span class="tab-harness run-mode-dot ${escapeHtml(E)}" aria-hidden="true"></span>`,K=this.shouldInlineSessionActions(),q=`<span class="tab-actions"><span class="tab-gear" onclick="event.stopPropagation(); app.openSessionOptions(${escapeHtml(JSON.stringify(_))})" title="Session options" aria-label="Session options" tabindex="0">⚙</span><span class="tab-detach" onclick="event.stopPropagation(); app.detachSession(${escapeHtml(JSON.stringify(_))})" title="Open in a new window" aria-label="Open session in a new window" tabindex="0">⧉</span><span class="tab-close" onclick="event.stopPropagation(); app.requestCloseSession(${escapeHtml(JSON.stringify(_))})" title="Close session" aria-label="Close session" tabindex="0">×</span><button type="button" class="tab-more" onclick="event.stopPropagation(); app.openTabRailActionMenu(event, ${escapeHtml(JSON.stringify(_))})" title="Session actions" aria-label="Session actions">⋯</button></span>`;b.set(_,`<div class="session-tab ${R?"active":""}${x}${j}${U?" tab-agent-exited":""}${C?" tab-loading":""}${this.hasTabDetachOverride(_)?" tab-show-detach":""}${this._tileGrid?.has(_)?" in-tiles":""}"${J}${N} data-id="${_}" data-color="${W}" ${C?`data-load-phase="${escapeHtml(C.phase)}"`:""} onclick="app.handleSessionTabClick(event, ${escapeHtml(JSON.stringify(_))})" oncontextmenu="event.preventDefault(); app.startInlineRename(${escapeHtml(JSON.stringify(_))})" tabindex="0" role="tab" aria-selected="${R?"true":"false"}" aria-busy="${C?"true":"false"}" aria-label="${escapeHtml(paneExitAriaLabel(k,U))}" data-aria-source="${escapeHtml(paneExitAriaLabel(k,U))}" ${G?`title="${escapeHtml(G)}"`:""}>
|
|
19
|
+
${w<9?'<span class="tab-number">'+(w+1)+"</span>":""}
|
|
20
|
+
${C?'<span class="tab-load-spinner" aria-hidden="true"></span>':""}
|
|
21
|
+
<span class="tab-status ${D}" aria-hidden="true"></span>
|
|
22
|
+
<span class="tab-info">
|
|
23
|
+
<span class="tab-name-row">
|
|
24
|
+
${X}
|
|
25
|
+
<span class="tab-name" data-session-id="${_}" data-full-name="${escapeHtml(k)}">${P}</span>
|
|
26
|
+
${U?`<span class="tab-exited-badge" data-label="${escapeHtml(U)}" aria-hidden="true">${escapeHtml(U)}</span>`:""}
|
|
27
|
+
${K?q:""}
|
|
28
|
+
<span class="tab-detached-badge" aria-hidden="true">detached</span>
|
|
29
|
+
</span>
|
|
30
|
+
${L?`<span class="tab-folder">\u{1F4C1} ${escapeHtml(M)}</span>`:""}
|
|
31
|
+
${z}
|
|
32
|
+
</span>
|
|
33
|
+
${V?`<span class="tab-badge" onclick="event.stopPropagation(); app.toggleTaskPanel()" aria-label="${B.running} running tasks">${B.running}</span>`:""}
|
|
34
|
+
${I}
|
|
35
|
+
${F}
|
|
36
|
+
${K?"":q}
|
|
37
|
+
</div>`),w++}if(v)a.push(this._renderTabClusters(v,b,w)),this._hiddenTabGroupByRef=new Map;else if(u){const _=new Map((this.webviewOrder||[]).filter(T=>this.webviews?.has(T)).map((T,N)=>[T,w+N]));a.push(window.CodemanTabLayout.renderProjection(u,T=>T.kind==="session"?b.get(T.id)||"":this.renderWebviewTab?.(T.id,_.get(T.id)??1/0)||"",escapeHtml)),this._hiddenTabGroupByRef=new Map(Object.entries(u.hiddenTabGroupByRef))}else a.push(...b.values()),a.push(this.renderWebviewTabs?this.renderWebviewTabs(w):""),this._hiddenTabGroupByRef=new Map;this._lastTabGroupStructureKey=this._tabGroupStructureKey(u),this._lastTabClusterKey=v?v.key:null,e.innerHTML=a.join(""),e.classList.toggle("session-tabs--grouped",!!u),this._applyTabListRole(e,!!u),u&&(this._applyTabTreeSemantics(e,{identity:r,refocus:o}),this._syncTabGroupHeaderAlerts(e,u)),this._syncTabTriageChrome(e,S),this._syncTabArrangementClasses(e,{clusters:!!v,groupProjection:u});const p=this._noteActiveTabBand(e)&&this._isScrollingTabRow(e);e.scrollLeft=t,e.scrollTop=s,this._lastRenderedActiveTabId=this.activeSessionId,(n||i!==this.activeSessionId||p)&&this._scrollActiveTabIntoView(this.activeSessionId,n?"auto":"smooth"),this.setupTabDragHandlers(),this._bindTabLayoutPointerDrag(e),this.setupTabKeyboardNavigation(e),this.updateConnectionLines(),this.updateTabOverflowMode(),this._applyTabEntrances?.(),this.applySidebarFilter(this._sidebarFilter),c?this._startSidebarRichClock():this._stopSidebarRichClock()}setupTabKeyboardNavigation(e){this._tabKeydownHandler&&e.removeEventListener("keydown",this._tabKeydownHandler),this._tabKeydownHandler=t=>{if(e.getAttribute("role")==="tree"){this._handleTabTreeKeydown(t,e);return}if(!["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End","Enter"," "].includes(t.key))return;const s=[...e.querySelectorAll(".session-tab:not(.tab-filtered-out)")];if(this.isTabRailSorted()||e.classList.contains("tabs-triage")){const o=l=>Number(getComputedStyle(l).order)||0,r=[...e.querySelectorAll(":scope > .tab-cluster")],a=l=>r.indexOf(l.closest(".tab-cluster"));s.sort((l,c)=>a(l)-a(c)||o(l)-o(c))}const i=s.indexOf(document.activeElement);if((t.key==="Enter"||t.key===" ")&&i>=0){t.preventDefault(),this._activateTabRow(s[i]);return}if(i<0)return;let n;switch(t.key){case"ArrowLeft":case"ArrowUp":n=i>0?i-1:s.length-1;break;case"ArrowRight":case"ArrowDown":n=i<s.length-1?i+1:0;break;case"Home":n=0;break;case"End":n=s.length-1;break;default:return}t.preventDefault(),s[n]?.focus()},e.addEventListener("keydown",this._tabKeydownHandler),this._tabTreeFocusinHandler||(this._tabTreeFocusinHandler=t=>{if(e.getAttribute("role")!=="tree")return;const s=t.target?.closest?.('[role="treeitem"]');s&&e.contains(s)&&this._setTabTreeStop(e,s)},e.addEventListener("focusin",this._tabTreeFocusinHandler))}_activateTabRow(e){if(e?.dataset.webviewId)return this.openWebview(e.dataset.webviewId);if(e?.dataset.id)return this.selectSession(e.dataset.id,{forceReload:!0})}_applyTabListRole(e,t){t?(e.setAttribute("role","tree"),e.setAttribute("aria-label","Sessions")):e.getAttribute("role")==="tree"&&(e.setAttribute("role","tablist"),e.setAttribute("aria-label","Session tabs"))}_tabTreeIdentity(e){const t=e?.closest?.("[data-tab-group-header], .session-tab");return t?t.dataset.tabGroupHeader?`group:${t.dataset.tabGroupHeader}`:t.dataset.webviewId?`webview:${t.dataset.webviewId}`:t.dataset.id?`session:${t.dataset.id}`:null:null}_tabTreeItems(e){const t=this.isTabRailSorted(),s=n=>Number(getComputedStyle(n).order)||0,i=[];for(const n of e.querySelectorAll(".tab-layout-group")){if(n.classList.contains("tab-filtered-out"))continue;const o=n.querySelector(':scope > [role="treeitem"]');o&&i.push(o);const r=[...n.querySelectorAll('.session-tab[role="treeitem"]:not(.tab-filtered-out)')];t&&r.sort((a,l)=>s(a)-s(l)),i.push(...r)}return i}_setTabTreeStop(e,t){for(const s of e.querySelectorAll('[role="treeitem"]'))s.tabIndex=s===t?0:-1}_applyTabTreeSemantics(e,{identity:t=null,refocus:s=!1}={}){for(const a of e.querySelectorAll(".session-tab")){a.setAttribute("role","treeitem"),a.setAttribute("aria-selected",a.classList.contains("active")?"true":"false"),a.setAttribute("aria-level",a.closest('[role="group"]')?"2":"1");for(const l of a.querySelectorAll("[tabindex], button, a[href], input, select, textarea"))l.tabIndex=-1}for(const a of e.querySelectorAll("[data-tab-group-header]"))a.setAttribute("aria-level","1");const i=this._applyTabTreePositions(e),n=a=>a?i.find(l=>this._tabTreeIdentity(l)===a):null,o=t?this._hiddenTabGroupByRef?.get(t):null,r=n(t)||(o?n(`group:${o}`):null)||i.find(a=>a.getAttribute("aria-selected")==="true")||i[0];r&&(this._setTabTreeStop(e,r),s&&document.activeElement!==r&&r.focus())}_applyTabTreePositions(e){const t=this._tabTreeItems(e),s=new Map;for(const i of t){const n=i.getAttribute("aria-level")==="2"?i.closest('[role="group"]'):e;s.has(n)||s.set(n,[]),s.get(n).push(i)}for(const i of s.values())i.forEach((n,o)=>{const r=String(i.length),a=String(o+1);n.getAttribute("aria-setsize")!==r&&n.setAttribute("aria-setsize",r),n.getAttribute("aria-posinset")!==a&&n.setAttribute("aria-posinset",a)});return t}_syncTabGroupHeaderAlerts(e,t){const s=window.CodemanTabLayout?.hiddenGroupAlerts(t,i=>this.tabAlerts?.get(i))||{};for(const i of e.querySelectorAll("[data-tab-group-header]")){const n=s[i.dataset.tabGroupHeader];i.classList.toggle("tab-alert-action",n==="action"),i.classList.toggle("tab-alert-idle",n==="idle")}}_syncTabTreeSelection(e){if(e?.getAttribute("role")==="tree")for(const t of e.querySelectorAll(".session-tab"))t.setAttribute("aria-selected",t.classList.contains("active")?"true":"false")}_handleTabTreeKeydown(e,t){if(e.target?.closest?.('input, textarea, select, [contenteditable="true"]'))return;const s=this._tabTreeItems(t),i=e.target?.closest?.('[role="treeitem"]');if(!i||i!==e.target)return;const n=s.indexOf(i);if(n<0)return;const o=i.dataset.tabGroupHeader||null,r=i.getAttribute("aria-expanded")==="true",a=i.hasAttribute("aria-expanded"),l=d=>{d&&(this._setTabTreeStop(t,d),d.focus())},c=d=>{this._tabFocusIdentity=`group:${o}`,this.toggleTabGroupCollapsed(o,d)};switch(e.key){case"ArrowDown":case"ArrowUp":{const d=e.key==="ArrowDown"?1:-1;l(s[(n+d+s.length)%s.length]);break}case"Home":l(s[0]);break;case"End":l(s[s.length-1]);break;case"ArrowRight":if(!o||!a)return;if(!r)c(!1);else{const d=s.find(h=>h.closest('[role="group"]')?.id===i.getAttribute("aria-owns"));if(!d)return;l(d)}break;case"ArrowLeft":if(o){if(!a||!r)return;c(!0)}else{const d=i.closest('[role="group"]'),h=d?t.querySelector(`[aria-owns="${CSS.escape(d.id)}"]`):null;if(!h)return;l(h)}break;case"Enter":case" ":o?c():this._activateTabRow(i);break;case"F2":if(!o||!this.startTabGroupRename(o))return;break;case"F10":case"ContextMenu":{if(e.key==="F10"&&!e.shiftKey)return;const d={preventDefault(){},stopPropagation(){},currentTarget:i};if(o)this.openTabGroupMenu(d,o);else if(i.dataset.id)this.openTabRailActionMenu?.(d,i.dataset.id);else if(i.dataset.webviewId)this.openTabWebviewMenu(d,i.dataset.webviewId);else return;break}default:return}e.preventDefault()}handleSessionTabClick(e,t){return e?.preventDefault?.(),(e?.ctrlKey||e?.metaKey)&&this.addSessionToTiles?.(t)?void 0:(!(typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible===!0)&&MobileDetection.isTouchDevice()&&document.activeElement?.blur?.(),this.selectSession(t,{forceReload:!0}))}syncSessionOrder(){const e=new Set(this.sessions.keys()),s=this.loadSessionOrder().filter(o=>e.has(o)),i=new Set(s),n=[...e].filter(o=>!i.has(o));this.sessionOrder=[...s,...n]}loadSessionOrder(){try{const e=localStorage.getItem("codeman-session-order");return e?JSON.parse(e):[]}catch{return[]}}saveSessionOrder(){try{localStorage.setItem("codeman-session-order",JSON.stringify(this.sessionOrder))}catch{}const e=[...this.sessionOrder];this._debouncedCall("saveSessionOrderServer",()=>{fetch("/api/session-order",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({order:e})}).catch(()=>{})},400)}_onSessionOrderChanged(e){if(!e||!Array.isArray(e.order))return;try{localStorage.setItem("codeman-session-order",JSON.stringify(e.order))}catch{}const t=JSON.stringify(this.sessionOrder);this.syncSessionOrder(),JSON.stringify(this.sessionOrder)!==t&&this._fullRenderSessionTabs()}_ensureTabLayoutCoordinator(){return this._tabLayoutCoordinator?this._tabLayoutCoordinator:window.CodemanTabLayout?(this._tabLayoutCoordinator=window.CodemanTabLayout.createLoadCoordinator({fetchLayout:async()=>{const e=await this._apiJson("/api/tab-layout");if(!e?.layout)throw new Error("Tab layout unavailable");return e.layout},applyLayout:e=>this._applyTabLayout(e),applyFallback:()=>this._applyTabLayout(null),retryDelayMs:5e3,maxRetryDelayMs:6e4,maxRetries:4,scheduleRetry:(e,t)=>setTimeout(e,t),cancelRetry:e=>clearTimeout(e)}),this._tabLayoutCoordinator):null}_loadTabLayout(){return this._ensureTabLayoutCoordinator()?.load()??Promise.resolve(!1)}_onTabLayoutChanged(e){const t=window.__codemanUser;if(!(t?.multiUser&&typeof e?.owner=="string"&&e.owner!==t.username)&&!(Number.isSafeInteger(e?.version)&&this.tabLayout&&e.version<=this.tabLayout.version)){if(this._tabLayoutEditor?.hasPending()){this._tabLayoutReloadPending=!0;return}this._loadTabLayout()}}_applyTabLayout(e){let t=null;if(e)try{t=window.CodemanTabLayout.normalizeLayout(e)}catch{t=null}if(t&&this.tabLayout&&t.version<this.tabLayout.version)return;const s=this._tabLayoutEditor;if(s){if(!t&&s.hasPending()){this._tabLayoutReloadPending=!0;return}if(t&&s.isWriting()){this._tabLayoutReloadPending=!0;return}if(t&&s.hasPending()&&s.adoptExternal(t))return;s.hasPending()&&this.showToast?.("Your tab group edit was not saved.","error"),s.dispose(),this._tabLayoutEditor=null}this.tabLayout=t;const i=this._getTabCollapseStorage(),n=i&&t?window.CodemanTabLayout.loadCollapsedGroupIds(i,t.groups.map(o=>o.id)):{ids:[],ok:!t};n.ok||(this._tabCollapseStorageFailed=!0),this.collapsedTabGroupIds=new Set(n.ids),this._isTabGroupStructureStale()&&this._fullRenderSessionTabs(),t&&!this._tabLayoutRestoreChecked&&(this._tabLayoutRestoreChecked=!0,this._restorePendingTabLayoutEdits())}_getTabCollapseStorage(){if(this._tabCollapseStorageFailed)return null;try{return window.localStorage}catch{return this._tabCollapseStorageFailed=!0,null}}_projectTabGroups(){return!this.tabLayout||this._tabOrientation()!=="vertical"||!window.CodemanTabLayout?null:window.CodemanTabLayout.project(this.tabLayout,{liveSessionIds:this.sessionOrder.filter(e=>this.sessions.has(e)),openWebviewIds:(this.webviewOrder||[]).filter(e=>this.webviews?.has(e)),collapsedGroupIds:this._tabRailSearchActive()?[]:[...this.collapsedTabGroupIds],activeSessionId:this.activeSessionId,activeWebviewId:this.activeWebviewId})}_tabGroupStructureKey(e){return window.CodemanTabLayout?.structureKey(this.tabLayout,e,[...this.collapsedTabGroupIds])??null}_isTabGroupStructureStale(e=this._projectTabGroups()){return this._tabGroupStructureKey(e)!==this._lastTabGroupStructureKey}toggleTabGroupCollapsed(e,t){if(this._tabRailSearchActive()||!this.tabLayout?.groups?.some(r=>r.id===e))return!1;const s=new Set(this.collapsedTabGroupIds),i=t===void 0?!s.has(e):t===!0;i?s.add(e):s.delete(e);const n=this._getTabCollapseStorage(),o=n?window.CodemanTabLayout.saveCollapsedGroupIds(n,[...s]):{ids:[],ok:!1};return o.ok||(this._tabCollapseStorageFailed=!0),this.collapsedTabGroupIds=new Set(o.ids),this._fullRenderSessionTabs(),this.collapsedTabGroupIds.has(e)===i}_tabLayoutEditable(){return!!(this.tabLayout&&window.CodemanTabLayout&&this._tabOrientation()==="vertical")}_tabLayoutParents(){const e={};for(const t of this.sessions.values())t?.parentSessionId&&t.parentSessionId!==t.id&&(e[t.id]=t.parentSessionId);return e}async _putTabLayout({baseVersion:e,layout:t}){const s={baseVersion:e,layout:{...t,updatedAt:t.updatedAt||new Date().toISOString()}},i=await this._api("/api/tab-layout",{method:"PUT",body:s});if(!i)return{ok:!1,status:0,layout:null};let n=null;try{n=await i.json()}catch{}return{ok:i.ok,status:i.status,layout:n?.data?.layout||null}}_ensureTabLayoutEditor(){return this._tabLayoutEditor||!this.tabLayout?this._tabLayoutEditor||null:(this._tabLayoutEditor=window.CodemanTabLayout.createEditCoordinator({initialLayout:this.tabLayout,put:e=>this._putTabLayout(e),fetchLayout:async()=>{const e=await this._apiJson("/api/tab-layout");if(!e?.layout)throw new Error("Tab layout unavailable");return e.layout},applyLayout:e=>this._adoptEditedTabLayout(e),reportError:e=>this.showToast?.(e,"error"),onFailure:()=>{this._tabLayoutReloadPending=!0},onSettled:()=>{this._tabLayoutReloadPending&&(this._tabLayoutReloadPending=!1,this._loadTabLayout())}}),this._tabLayoutEditor)}_adoptEditedTabLayout(e){this.tabLayout=e;const t=this._getTabCollapseStorage();if(t){const s=window.CodemanTabLayout.loadCollapsedGroupIds(t,e.groups.map(i=>i.id));s.ok&&(this.collapsedTabGroupIds=new Set(s.ids))}this._fullRenderSessionTabs()}editTabLayout(e,t){if(!this._tabLayoutEditable())return!1;const s=document.activeElement,i=this.$("sessionTabs");t&&(!s||s===document.body||i?.contains(s))&&(this._tabFocusIdentity=t,this._tabRefocusAfterEdit=!0);try{return this._ensureTabLayoutEditor().enqueue(e),!0}catch(n){return this._tabRefocusAfterEdit=!1,this.showToast?.(n?.message||"Could not save tab groups.","error"),!1}}_newTabGroupId(){return globalThis.crypto?.randomUUID?.()||`group-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}createTabGroup({ref:e=null,index:t}={}){if(!this._tabLayoutEditable())return!1;const s=this._newTabGroupId(),i=window.CodemanI18n?.t?.("New group")||"New group";return this.editTabLayout({type:"createGroup",id:s,name:i,...Number.isInteger(t)?{index:t}:{}},`group:${s}`)?(e&&this.editTabLayout({type:"moveRef",ref:e,groupId:s,index:0,parents:this._tabLayoutParents()}),this.startTabGroupRename(s),!0):!1}deleteTabGroup(e){const t=this.tabLayout?.groups||[],s=t.findIndex(n=>n.id===e);if(s<0)return!1;if(!window.confirm(`Delete group "${t[s].name}"? Its tabs move to Ungrouped.`))return this.$("sessionTabs")?.querySelector(`[data-tab-group-header="${CSS.escape(e)}"]`)?.focus(),!1;const i=t[s+1]||t[s-1];return this.editTabLayout({type:"deleteGroup",groupId:e},i?`group:${i.id}`:null)}moveTabGroup(e,t){const s=this.tabLayout?.groups||[],i=s.findIndex(o=>o.id===e),n=i+t;return i<0||n<0||n>=s.length?!1:this.editTabLayout({type:"reorderGroup",groupId:e,index:n},`group:${e}`)}_tabRefLocation(e){const t=i=>i.kind===e.kind&&i.id===e.id;for(const i of this.tabLayout?.groups||[]){const n=i.refs.findIndex(t);if(n>=0)return{groupId:i.id,refs:i.refs,index:n}}const s=this.tabLayout?.ungrouped?.findIndex(t)??-1;return s>=0?{groupId:null,refs:this.tabLayout.ungrouped,index:s}:null}moveTabRef(e,t,s=null,i="before"){const n=this._tabLayoutParents();let o;try{o=window.CodemanTabLayout.moveDestination(this.tabLayout,e,t,s,i,n)}catch{return!1}return this.editTabLayout({type:"moveRef",ref:e,...o,parents:n},`${e.kind}:${e.id}`)}_tabRefMoveActions(e){if(!this._tabLayoutEditable())return[];const t=this._tabRefLocation(e);if(!t)return[];const s=[];if(this.tabLayout.groups.length>0&&!this.isTabRailSorted()){const n=new Set(window.CodemanTabLayout.movingRefKeys(this.tabLayout,e,this._tabLayoutParents())),o=t.refs[t.index-1],r=t.refs.slice(t.index+1).find(a=>!n.has(`${a.kind}:${a.id}`));o&&s.push({label:"Move up",run:()=>this.moveTabRef(e,t.groupId,o,"before")}),r&&s.push({label:"Move down",run:()=>this.moveTabRef(e,t.groupId,r,"after")})}for(const n of this.tabLayout.groups)n.id!==t.groupId&&s.push({label:`Move to "${n.name}"`,run:()=>this.moveTabRef(e,n.id)});return t.groupId!==null&&s.push({label:"Move to Ungrouped",run:()=>this.moveTabRef(e,null)}),this._canCreateTabGroup()&&s.push({label:"Move to new group",run:()=>this.createTabGroup({ref:e})}),s}closeTabGroupMenu({restoreFocus:e=!1}={}){const t=this._tabGroupMenu;if(!t)return;const s=this._tabGroupMenuTrigger,i=this._tabGroupMenuKey;if(this._tabGroupMenu=null,this._tabGroupMenuTrigger=null,this._tabGroupMenuKey=null,document.removeEventListener("pointerdown",this._tabGroupMenuOutside,!0),document.removeEventListener("keydown",this._tabGroupMenuKeydown,!0),window.removeEventListener("resize",this._tabGroupMenuResize),this._tabGroupMenuOutside=this._tabGroupMenuKeydown=this._tabGroupMenuResize=null,t.remove(),!e)return;const n=this.$("sessionTabs");(s?.isConnected&&s.closest('[role="treeitem"]')||[...n?.querySelectorAll('[role="treeitem"]')||[]].find(r=>this._tabTreeIdentity(r)===i))?.focus()}_canCreateTabGroup(){const e=window.CodemanTabLayout?.MAX_GROUPS;return!e||(this.tabLayout?.groups?.length||0)<e}openTabGroupMenu(e,t){const s=this.tabLayout?.groups||[],i=s.findIndex(n=>n.id===t);return i<0?!1:this._openTabLayoutMenu(e,`group:${t}`,"Group actions",[...this.canOpenTileGrid?.()?[{label:"Open group as tiles",run:()=>this.openGroupAsTiles(t)}]:[],{label:"Rename group",run:()=>this.startTabGroupRename(t)},...this._canCreateTabGroup()?[{label:"New group",run:()=>this.createTabGroup({index:i+1})}]:[],...i>0?[{label:"Move group up",run:()=>this.moveTabGroup(t,-1)}]:[],...i<s.length-1?[{label:"Move group down",run:()=>this.moveTabGroup(t,1)}]:[],{label:"Delete group",className:"danger",run:()=>this.deleteTabGroup(t)}])}openTabWebviewMenu(e,t){const s=this._tabRefMoveActions({kind:"webview",id:t});return s.length?this._openTabLayoutMenu(e,`webview:${t}`,"Web tab actions",[{label:"Web tab settings",run:()=>this.showWebviewModal?.(t)},...s]):(this.showWebviewModal?.(t),!1)}_openTabLayoutMenu(e,t,s,i){e?.preventDefault?.(),e?.stopPropagation?.();const n=e?.currentTarget||null;if(this._tabGroupMenu&&this._tabGroupMenuKey===t)return this.closeTabGroupMenu(),!1;if(this.closeTabGroupMenu(),this.closeTabRailActionMenu?.(),!this._tabLayoutEditable())return!1;const o=document.createElement("div");o.className="tab-rail-action-menu tab-layout-group-action-menu",o.setAttribute("role","menu"),o.setAttribute("aria-label",s);for(const d of i){const h=document.createElement("button");h.type="button",h.setAttribute("role","menuitem"),h.textContent=d.label,d.className&&(h.className=d.className),h.addEventListener("click",()=>{this.closeTabGroupMenu(),d.run()}),o.appendChild(h)}document.body.appendChild(o);const a=((n?.getBoundingClientRect?n:null)||this.$("sessionTabs"))?.getBoundingClientRect?.()||{left:8,bottom:8,right:8},l=o.getBoundingClientRect(),c=e?.clientX&&e.type==="contextmenu"?e.clientX:a.left;return o.style.left=`${Math.max(8,Math.min(c,window.innerWidth-l.width-8))}px`,o.style.top=`${Math.max(8,Math.min(a.bottom+4,window.innerHeight-l.height-8))}px`,this._tabGroupMenu=o,this._tabGroupMenuTrigger=n,this._tabGroupMenuKey=t,this._tabGroupMenuOutside=d=>{o.contains(d.target)||n&&n.contains?.(d.target)||this.closeTabGroupMenu()},this._tabGroupMenuKeydown=d=>{d.key==="Escape"&&(d.preventDefault(),d.stopImmediatePropagation(),this.closeTabGroupMenu({restoreFocus:!0}))},this._tabGroupMenuResize=()=>this.closeTabGroupMenu(),document.addEventListener("pointerdown",this._tabGroupMenuOutside,!0),document.addEventListener("keydown",this._tabGroupMenuKeydown,!0),window.addEventListener("resize",this._tabGroupMenuResize),o.addEventListener("keydown",d=>{const h=[...o.querySelectorAll("button")],u=h.indexOf(document.activeElement);d.key==="ArrowDown"||d.key==="ArrowUp"?(d.preventDefault(),h[(u+(d.key==="ArrowDown"?1:-1)+h.length)%h.length]?.focus()):d.key==="Home"||d.key==="End"?(d.preventDefault(),h[d.key==="Home"?0:h.length-1]?.focus()):d.key==="Tab"&&(d.preventDefault(),this.closeTabGroupMenu({restoreFocus:!0}))}),o.addEventListener("focusout",d=>{d.relatedTarget&&o.contains(d.relatedTarget)||this._tabGroupMenu===o&&this.closeTabGroupMenu()}),o.querySelector("button")?.focus(),!0}startTabGroupRename(e){if(!this.tabLayout?.groups?.some(l=>l.id===e))return!1;this._activeRename?.cancel();const t=this.tabLayout?.groups?.find(l=>l.id===e),i=this.$("sessionTabs")?.querySelector(`[data-tab-group-header="${CSS.escape(e)}"]`)?.querySelector(".tab-layout-group-name");if(!t||!i)return!1;this._inlineRenameActive=!0;const n=document.createElement("input");n.type="text",n.className="tab-layout-group-rename-input",n.value=t.name,n.maxLength=60,n.setAttribute("aria-label","Group name"),i.classList.add("tab-layout-group-name--renaming"),i.replaceChildren(n);for(const l of["click","contextmenu","pointerdown"])n.addEventListener(l,c=>c.stopPropagation());let o=!1;const r={groupId:e,cancel:()=>a(!1)},a=(l,{fromBlur:c=!1}={})=>{if(o)return;o=!0;const d=n.value.trim();if(this._activeRename!==r)return;this._activeRename=null,this._inlineRenameActive=!1;const h=this.tabLayout?.groups?.find(S=>S.id===e),u=c?null:`group:${e}`;l&&h&&d&&d!==h.name&&this.editTabLayout({type:"renameGroup",groupId:e,name:d},u)||(u&&(this._tabFocusIdentity=u,this._tabRefocusAfterEdit=!0),this._fullRenderSessionTabs())};return this._activeRename=r,n.addEventListener("keydown",l=>{l.stopPropagation(),!(l.isComposing||l.keyCode===229)&&(l.key==="Enter"?(l.preventDefault(),a(!0)):l.key==="Escape"&&(l.preventDefault(),a(!1)))}),n.addEventListener("blur",()=>a(!0,{fromBlur:!0})),n.focus(),n.select(),!0}_bindTabLayoutPointerDrag(e){!e||e._tabLayoutDragBound||(e._tabLayoutDragBound=!0,e.addEventListener("pointerdown",t=>this._onTabLayoutPointerDown(t,e)),e.addEventListener("pointermove",t=>this._onTabLayoutPointerMove(t,e)),e.addEventListener("pointerup",t=>this._finishTabLayoutPointerDrag(t,e)),e.addEventListener("pointercancel",()=>this._cancelTabLayoutPointerDrag(e)),e.addEventListener("lostpointercapture",()=>this._cancelTabLayoutPointerDrag(e)))}_onTabLayoutPointerDown(e,t){if(this._tabLayoutDrag&&this._cancelTabLayoutPointerDrag(t),e.button!==0||e.pointerType==="touch"||!t.classList.contains("session-tabs--grouped")||this._inlineRenameActive||!this._tabLayoutEditable()||e.target.closest('.tab-actions, .tab-badge, .tab-layout-group-menu, button, input, [onclick*="stopPropagation"]'))return;const s=e.target.closest("[data-tab-group-header]"),i=s?null:e.target.closest(".session-tab");let n=null;if(s?n={type:"group",groupId:s.dataset.tabGroupHeader}:i?.dataset.webviewId?n={type:"ref",ref:{kind:"webview",id:i.dataset.webviewId}}:i?.dataset.id&&(n={type:"ref",ref:{kind:"session",id:i.dataset.id}}),!n)return;const o={pointerId:e.pointerId,x:e.clientX,y:e.clientY,source:n,origin:s||i,active:!1,target:null};o.windowUp=r=>this._finishTabLayoutPointerDrag(r,t),o.windowCancel=()=>this._cancelTabLayoutPointerDrag(t),window.addEventListener("pointerup",o.windowUp,!0),window.addEventListener("pointercancel",o.windowCancel,!0),this._tabLayoutDrag=o}_tabLayoutDropTarget(e,t,s){const i=document.elementFromPoint(e,t);if(!i||!s.contains(i))return null;const n=i.closest(".session-tab"),o=i.closest(".tab-layout-group"),r=o?o.dataset.tabGroupId||null:void 0;if(n&&o&&!this.isTabRailSorted()){const l=n.dataset.webviewId?{kind:"webview",id:n.dataset.webviewId}:{kind:"session",id:n.dataset.id},c=n.getBoundingClientRect();return{type:"ref",ref:l,groupId:r,placement:t>=c.top+c.height/2?"after":"before",element:n}}if(r===void 0)return null;const a=o.querySelector(":scope > .tab-layout-group-header");return r===null?{type:"ungrouped",element:a}:{type:"group",groupId:r,element:a}}_clearTabLayoutDropMarks(e){e.querySelectorAll(".tab-layout-drop-before, .tab-layout-drop-after, .tab-layout-drop-into").forEach(t=>t.classList.remove("tab-layout-drop-before","tab-layout-drop-after","tab-layout-drop-into"))}_onTabLayoutPointerMove(e,t){const s=this._tabLayoutDrag;if(!s||s.pointerId!==e.pointerId)return;if((e.buttons&1)===0){this._cancelTabLayoutPointerDrag(t);return}if(!s.active){if(Math.hypot(e.clientX-s.x,e.clientY-s.y)<6)return;s.active=!0,s.origin.classList.add("tab-layout-dragging"),t.classList.add("tab-layout-drag-active"),this.closeTabGroupMenu(),this.closeTabRailActionMenu?.();try{t.setPointerCapture(e.pointerId)}catch{}this._tabLayoutDragKeydown&&document.removeEventListener("keydown",this._tabLayoutDragKeydown,!0),this._tabLayoutDragKeydown=o=>{o.key==="Escape"&&(o.preventDefault(),o.stopImmediatePropagation(),this._cancelTabLayoutPointerDrag(t))},document.addEventListener("keydown",this._tabLayoutDragKeydown,!0)}e.preventDefault();const i=this._tabLayoutDropTarget(e.clientX,e.clientY,t);if(this._clearTabLayoutDropMarks(t),s.target=i,!i?.element)return;const n=i.type==="ref"&&s.source.type==="ref"?`tab-layout-drop-${i.placement}`:"tab-layout-drop-into";i.element.classList.add(n)}_cancelTabLayoutPointerDrag(e){const t=this._tabLayoutDrag;if(t&&(this._tabLayoutDrag=null,t.windowUp&&window.removeEventListener("pointerup",t.windowUp,!0),t.windowCancel&&window.removeEventListener("pointercancel",t.windowCancel,!0),t.origin?.classList.remove("tab-layout-dragging"),e?.classList.remove("tab-layout-drag-active"),e&&this._clearTabLayoutDropMarks(e),this._tabLayoutDragKeydown&&document.removeEventListener("keydown",this._tabLayoutDragKeydown,!0),this._tabLayoutDragKeydown=null,t.active)){const s=i=>{i.stopPropagation(),i.preventDefault()};window.addEventListener("click",s,{capture:!0,once:!0}),setTimeout(()=>window.removeEventListener("click",s,{capture:!0}),0)}}_finishTabLayoutPointerDrag(e,t){const s=this._tabLayoutDrag;if(!s||s.pointerId!==e.pointerId)return;const i=s.active?this._tabLayoutDropTarget(e.clientX,e.clientY,t)||s.target:null;if(this._cancelTabLayoutPointerDrag(t),!i)return;const n=window.CodemanTabLayout.dropOperation(this.tabLayout,s.source,i,this._tabLayoutParents());if(!n)return;const o=s.source.type==="group"?`group:${s.source.groupId}`:`${s.source.ref.kind}:${s.source.ref.id}`;this.editTabLayout(n,o)}_persistPendingTabLayoutEdits(){const e=this._tabLayoutEditor,t=e?.pendingOperations?.()||[];if(!t.length)return!1;try{sessionStorage.setItem("codeman:tab-layout-pending",JSON.stringify({owner:this._tabLayoutOwnerKey(),baseVersion:e.baseVersion(),savedAt:Date.now(),operations:t}))}catch{}try{const s=e.getLayout();fetch("/api/tab-layout",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({baseVersion:e.baseVersion(),layout:{...s,updatedAt:s.updatedAt||new Date().toISOString()}}),keepalive:!0}).catch(()=>{})}catch{}return!0}_tabLayoutOwnerKey(){const e=window.__codemanUser;return e?e.multiUser?e.username:"@single":null}_restorePendingTabLayoutEdits(){let e;try{const n=sessionStorage.getItem("codeman:tab-layout-pending");if(!n)return!1;e=JSON.parse(n)}catch{return!1}const t=this._tabLayoutOwnerKey();if(t===null)return this._tabLayoutRestoreWaiting||(this._tabLayoutRestoreWaiting=!0,document.addEventListener("codeman:me",()=>{this._tabLayoutRestoreWaiting=!1,this._restorePendingTabLayoutEdits()},{once:!0})),!1;try{sessionStorage.removeItem("codeman:tab-layout-pending")}catch{}const s=e?.operations;if(!Array.isArray(s)||!s.length||!this.tabLayout||!window.CodemanTabLayout||e.owner!==t)return!1;const i=Date.now()-e.savedAt;return!Number.isFinite(i)||i<0||i>TAB_LAYOUT_PENDING_MAX_AGE_MS||!Number.isSafeInteger(e.baseVersion)||e.baseVersion>this.tabLayout.version?!1:this._ensureTabLayoutEditor().restore(s)}setupTabDragHandlers(){const e=this.$("sessionTabs"),t=e.querySelectorAll(".session-tab[data-id]");if(this.isTabRailSorted()||e.classList.contains("session-tabs--grouped")){t.forEach(s=>s.setAttribute("draggable","false"));return}t.forEach(s=>{s.setAttribute("draggable","true"),s.addEventListener("dragstart",i=>{this.draggedTabId=s.dataset.id,s.classList.add("dragging"),i.dataTransfer.effectAllowed="move",i.dataTransfer.setData("text/plain",s.dataset.id)}),s.addEventListener("dragend",()=>{s.classList.remove("dragging"),this.draggedTabId=null,e.querySelectorAll(".session-tab").forEach(i=>{i.classList.remove("drag-over-left","drag-over-right")})}),s.addEventListener("dragover",i=>{if(this._isTabDropAcrossGroups(s)||(i.preventDefault(),!this.draggedTabId||this.draggedTabId===s.dataset.id))return;i.dataTransfer.dropEffect="move";const n=s.getBoundingClientRect(),o=this._isVerticalTabList()?i.clientY<n.top+n.height/2:i.clientX<n.left+n.width/2;s.classList.toggle("drag-over-left",o),s.classList.toggle("drag-over-right",!o)}),s.addEventListener("dragleave",()=>{s.classList.remove("drag-over-left","drag-over-right")}),s.addEventListener("drop",i=>{if(i.preventDefault(),s.classList.remove("drag-over-left","drag-over-right"),!this.draggedTabId||this.draggedTabId===s.dataset.id||this._isTabDropAcrossGroups(s))return;const n=s.dataset.id,o=this.draggedTabId,r=s.getBoundingClientRect(),a=this._isVerticalTabList()?i.clientY<r.top+r.height/2:i.clientX<r.left+r.width/2,l=this.sessionOrder.indexOf(o);let c=this.sessionOrder.indexOf(n);l===-1||c===-1||(this.sessionOrder.splice(l,1),c=this.sessionOrder.indexOf(n),c!==-1&&(a?this.sessionOrder.splice(c,0,o):this.sessionOrder.splice(c+1,0,o),this.saveSessionOrder(),this._fullRenderSessionTabs()))})})}_canSwapActiveTabWith(e){const t=this._projectTabGroups();if(!t)return!0;const s=i=>t.sectionByRef[`session:${i}`];return s(this.activeSessionId)===s(e)}moveActiveTabLeft(){if(!this.activeSessionId)return;const e=this.sessionOrder.indexOf(this.activeSessionId);e<=0||this._canSwapActiveTabWith(this.sessionOrder[e-1])&&([this.sessionOrder[e-1],this.sessionOrder[e]]=[this.sessionOrder[e],this.sessionOrder[e-1]],this.saveSessionOrder(),this._fullRenderSessionTabs())}moveActiveTabRight(){if(!this.activeSessionId)return;const e=this.sessionOrder.indexOf(this.activeSessionId);e===-1||e>=this.sessionOrder.length-1||this._canSwapActiveTabWith(this.sessionOrder[e+1])&&([this.sessionOrder[e],this.sessionOrder[e+1]]=[this.sessionOrder[e+1],this.sessionOrder[e]],this.saveSessionOrder(),this._fullRenderSessionTabs())}getShortId(e){if(!e)return"";let t=this._shortIdCache.get(e);return t||(t=e.slice(0,8),this._shortIdCache.set(e,t)),t}getSessionName(e){return e.name?e.name:e.workingDir?e.workingDir.split("/").pop()||e.workingDir:this.getShortId(e.id)}_notifySession(e,t,s,i,n){const o=this.sessions.get(e);this.notificationManager?.notify({urgency:t,category:s,sessionId:e,sessionName:o?.name||this.getShortId(e),title:i,message:n})}_isUsableXtermSnapshot(e){return!e||typeof e!="string"||e.length<8?!1:e.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,"").replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g,"").replace(/\x1b[()][0-2A-Z]/g,"").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"").trim().length>=3}_persistXtermSnapshot(e,t){const s="codeman-xs-",n=()=>Object.keys(localStorage).filter(o=>o.startsWith(s)&&o!==e);try{if(localStorage.getItem(e)===null){const o=new Set(Array.from(this.sessions?.keys?.()||[])),r=n().sort((a,l)=>Number(o.has(a.slice(s.length)))-Number(o.has(l.slice(s.length))));for(;r.length>=10;)localStorage.removeItem(r.shift())}try{localStorage.setItem(e,t)}catch{for(const r of n()){localStorage.removeItem(r);try{localStorage.setItem(e,t);return}catch{}}try{localStorage.removeItem(e)}catch{}}}catch{}}_cleanupPreviousSession(e,{skipSnapshot:t=!1}={}){const s=this.activeSessionId?this.sessions?.get?.(this.activeSessionId):null;if(!t&&this.activeSessionId&&s?.mode!=="shell"&&this._serializeAddon&&this._xtermSnapshots)try{const i=this._serializeAddon.serialize({scrollback:1e3});if(this._isUsableXtermSnapshot(i)){if(this._xtermSnapshots.delete(this.activeSessionId),this._xtermSnapshots.set(this.activeSessionId,i),this._xtermSnapshots.size>20){const n=this._xtermSnapshots.keys().next().value;this._xtermSnapshots.delete(n)}i.length<256*1024&&this._persistXtermSnapshot(`codeman-xs-${this.activeSessionId}`,i)}else{this._xtermSnapshots.delete(this.activeSessionId);try{localStorage.removeItem(`codeman-xs-${this.activeSessionId}`)}catch{}}}catch{}if(this._disconnectWs(),typeof CjkInput<"u")CjkInput.clear();else{const i=document.getElementById("cjkInput");i&&(i.value="")}this._clearTimer("flickerFilterTimeout"),this.flickerFilterBuffer="",this.flickerFilterActive=!1,this._tabCompletionSessionId=null,this._tabCompletionRetries=0,this._tabCompletionBaseText=null,this._clearTimer("_tabCompletionFallback"),this._clearTimer("_clientDropRecoveryTimer"),this._terminalRefreshOwner=null,this._clearTimer("syncWaitTimeout"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._terminalWriteInFlight=!1,this._terminalWriteInFlightBytes=0,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadOwner=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1;try{const i=this.terminal?._core?._compositionHelper;if(i?._isComposing){i._isComposing=!1;const n=this.terminal?.element?.querySelector(".xterm-helper-textarea");n&&n.dispatchEvent(new CompositionEvent("compositionend",{data:""}))}}catch{}this._flushLocalEchoTo(this.activeSessionId),this._localEchoOverlay?.clear(),this._predictiveEcho?.clearPredictions(),this._localEchoOverlay&&!this._flushedOffsets?.has(e)&&this._localEchoOverlay.suppressBufferDetection()}_flushLocalEchoTo(e){if(!e)return;const t=this._localEchoOverlay?.pendingText||"",s=this._localEchoOverlay?.getFlushed()?.count||0,i=this._localEchoOverlay?.getFlushed()?.text||"";t&&this._sendInputAsync(e,t);const n=s+t.length;n>0&&(this._flushedOffsets||(this._flushedOffsets=new Map),this._flushedTexts||(this._flushedTexts=new Map),this._flushedOffsets.set(e,n),this._flushedTexts.set(e,i+t))}_resetTerminalForReplay(){this.terminal.write("\x1Bc")}_recordTerminalLoadTiming(e){this._lastTerminalLoadTiming=e,console.info("[TERMINAL-PERF]",e);const t=(e.cacheResetAndParseMs||0)+(e.freshResetAndParseMs||0)+(e.resetAndParseMs||0),s=e.selectDoneMs??e.totalMs??e.selectToReplayCompleteMs??0;_crashDiag.log(`TERMINAL_LOAD: ${e.trigger} ${e.full?"full":"tail"} ${e.chars} chars ttfb=${e.ttfbMs.toFixed(0)}ms body+json=${e.bodyAndJsonMs.toFixed(0)}ms reset+parse=${t.toFixed(0)}ms total=${s.toFixed(0)}ms server="${e.serverTiming}"${e.refused?" refused-downgrade":""}`)}async _maybeRefetchFullHistory({force:e=!1}={}){const t=this.activeSessionId;if(!t||this._fullHistoryRepullInFlight||this._isLoadingBuffer||this.detachedSessions?.has(t)||this._tilesOwnTerminal?.())return;const s=this.sessions.get(t),i=!e&&s?.mode==="shell",n=Date.now(),o=this._fullHistoryRepullUseless?.has(t)?6e4:4e3;if(!(!e&&n-(this._fullHistoryRepullAt.get(t)||0)<o)){this._fullHistoryRepullAt.set(t,n),this._fullHistoryRepullInFlight=!0;try{const r=performance.now(),a=await this._fetchTerminalCapture(i?`/api/sessions/${t}/terminal?full=1&tail=${TERMINAL_TAIL_SIZE}`:`/api/sessions/${t}/terminal?full=1`,{full:!0}),l=a.headersAt,c=a.json?.data??{},d=performance.now(),h=c.terminalBuffer,u={trigger:e?"full-history-button":"full-history-scroll",mode:s?.mode||"unknown",full:!0,source:c.source||"unknown",chars:h?.length||0,ttfbMs:l-r,bodyAndJsonMs:d-l,resetAndParseMs:0,totalMs:0,serverTiming:a.headers?.get?.("server-timing")||"",refused:!1};if(!h||this.activeSessionId!==t)return;const S=this._estimateReplayRows(h,this.terminal.cols),m=this.terminal.buffer.active.length,v=this.terminal.options?.scrollback||0,b=v>0&&m>=v+this.terminal.rows;if(i&&(S<=m||b)){(c.truncated||b)&&(this._fullHistoryRepullUseless||=new Set).add(t),this._logScrollRouting?.("repull-skipped-bounded");return}if(this._replayWouldShrinkBuffer(h,S)){u.refused=!0,u.totalMs=performance.now()-r,this._recordTerminalLoadTiming(u),(this._fullHistoryRepullUseless||=new Set).add(t),this._logScrollRouting?.("repull-refused-downgrade"),this._setHistoryTruncation(t,{...c,exhausted:!0});return}this._setHistoryTruncation(t,i&&c.truncated?{...c,truncationReason:"tail"}:c),this._fullHistoryRepullUseless?.delete(t);const w=this.terminal.buffer.active.length,p=performance.now();this._resetTerminalForReplay();const{parsedAt:_,bufferLength:T,completed:N}=await this.chunkedTerminalWrite(h,TERMINAL_CHUNK_SIZE,t,this._bufferLoadFinishOpts(c,l));if(u.resetAndParseMs=_-p,!N||this.activeSessionId!==t)return;this.sessions.get(t)?.mode!=="shell"?this.terminalBufferCache.set(t,h):this.terminalBufferCache.delete(t);const R=T-w;R>0?this.terminal.scrollToLine(R):this.terminal.scrollToTop(),this._syncStickyScrollBaseline(),u.totalMs=performance.now()-r,this._recordTerminalLoadTiming(u)}catch{}finally{this._fullHistoryRepullInFlight=!1}}}_setHistoryTruncation(e,t={}){e&&((this._historyTruncation||=new Map).set(e,{truncated:!!t.truncated,reason:t.truncationReason??null,source:t.source??null,fullSize:t.fullSize??0,retainedBytes:t.retainedBytes??0,exhausted:!!t.exhausted}),e===this.activeSessionId&&this._renderHistoryTruncationBanner())}_clearHistoryTruncation(e){this._historyTruncation?.delete(e),e===this.activeSessionId&&this._renderHistoryTruncationBanner()}_renderHistoryTruncationBanner(){const e=document.getElementById("historyTruncationBar");if(!e)return;const t=this.activeSessionId?this._historyTruncation?.get(this.activeSessionId):null,s=computeHistoryTruncationNotice(t||{});if(!s.visible){e.hidden=!0;return}e.textContent="";const i=document.createElement("span");if(i.className="history-trunc-text",i.textContent=s.message,e.appendChild(i),s.canLoadMore){const o=document.createElement("button");o.type="button",o.className="history-trunc-load",o.textContent="Load full history",o.onclick=()=>{o.disabled=!0,o.textContent="Loading\u2026",this._maybeRefetchFullHistory({force:!0}).finally(()=>{this._renderHistoryTruncationBanner()})},e.appendChild(o)}const n=document.createElement("button");n.type="button",n.className="history-trunc-dismiss",n.setAttribute("aria-label","Dismiss history notice"),n.textContent="\xD7",n.onclick=()=>{e.hidden=!0},e.appendChild(n),e.hidden=!1}_shouldFocusTerminalForTabSwitch(){return typeof MobileDetection>"u"||!MobileDetection.isTouchDevice()?!0:typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible}async selectSession(e,t={}){if(t?.auto!==!0&&this._urlSessionId&&this._urlSessionId!==e&&this._retireUrlSession(),!this.isSoloWindow&&this.detachedSessions.has(e)&&this._raiseDetached(e))return;const s=t?.forceReload===!0,i=t?.auto!==!0;if(this.activeSessionId===e&&!s){i&&this.markIdleAlertSeen(e);return}if(this._tileGrid?.open){if(this._tileGrid.has(e))return this._selectTiledSession(e,t);if(t?.auto===!0&&!t?.leaveTiles)return;this.closeTileGrid({keepStored:!0,reselect:!1}),this.activeSessionId=null}if(this.activeSessionId===e&&s){this.terminalBufferCache?.delete(e),this._xtermSnapshots?.delete(e);try{localStorage.removeItem(`codeman-xs-${e}`)}catch{}this._clearTimer("syncWaitTimeout"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._terminalWriteInFlight=!1,this._terminalWriteInFlightBytes=0,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._terminalRefreshOwner=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1,this._flushLocalEchoTo(e),this.activeSessionId=null}const n=this._shouldFocusTerminalForTabSwitch();n&&this.terminal&&this.terminal.focus();const o=performance.now(),r=this.sessions.get(e)?.name||e.slice(0,8);_crashDiag.log(`SELECT: ${r}`),console.log(`[CRASH-DIAG] selectSession START: ${e.slice(0,8)}`);const a=++this._selectGeneration;if(this._setTerminalLoadState(e,a,"resizing"),a!==this._selectGeneration){this._clearTerminalLoadState(e,a);return}this._hideWebviewLayer?.(),this._cleanupPreviousSession(e),this.activeSessionId=e,this._activateFileBrowserSession?.(e),this._renderHistoryTruncationBanner();try{localStorage.setItem("codeman-active-session",e)}catch{}this._updateSseSubscription(e),this.hideWelcome(),this.playTerminalEntrance?.(e),i&&this.markIdleAlertSeen(e),this._updateActiveTabImmediate(e),this.closeSessionSidebarOnHandheld(),this.renderSessionTabs(),this.updateAttachmentHistoryBadge?.(),this.attachmentHistoryDrawerOpen&&this.loadAttachmentHistory?.(e),this._updateLocalEchoState(),typeof KeyboardAccessoryBar<"u"&&KeyboardAccessoryBar.refreshForActiveSession(),this.refreshHostWakeBanner?.(e),this._flushedOffsets?.has(e)&&this._localEchoOverlay&&this._localEchoOverlay.setFlushed(this._flushedOffsets.get(e),this._flushedTexts?.get(e)||"",!1);const l=document.querySelector(`.session-tab.active[data-id="${e}"]`);l&&(l.classList.add("tab-glow"),l.addEventListener("animationend",()=>l.classList.remove("tab-glow"),{once:!0}));const c=this.sessions.get(e);if(this.currentSessionWorkingDir=c?.workingDir||null,c&&c.pid===null)if(c.respawnBlocked){const m=c.name||"Session";if(window.confirm(`${m} was stopped after crashing repeatedly. Restart it?`))try{await fetch(`/api/sessions/${e}/interactive`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clearBreaker:!0})}),c.respawnBlocked=!1,c.status="busy"}catch(v){console.error("Failed to restart crash-looped session:",v)}}else try{const m=c.mode==="shell"?`/api/sessions/${e}/shell`:`/api/sessions/${e}/interactive`;await fetch(m,{method:"POST"}),c.status="busy"}catch(m){console.error("Failed to attach to restored session:",m)}if(this._terminalFontReady&&(await this._terminalFontReady,this._isStaleSelect(a))){this._clearTerminalLoadState(e,a);return}this._restoringFlushedState=!0;const d=this._beginBufferLoad(a);let h=!1,u=0,S=!1;try{this._paneWidthRefused=!1,this.syncTerminalGeometry();const m=await this.sendResize(e,{forceHttp:!0}).catch(()=>!1),v=this.getTerminalDimensions?.();if(this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}let b=this._xtermSnapshots?.get(e);if(b&&!this._isUsableXtermSnapshot(b)&&(this._xtermSnapshots?.delete(e),b=null),!b)try{const g=localStorage.getItem(`codeman-xs-${e}`);g&&this._isUsableXtermSnapshot(g)?(b=g,this._xtermSnapshots?.delete(e),this._xtermSnapshots?.set(e,g)):g&&localStorage.removeItem(`codeman-xs-${e}`)}catch{}const w=c&&(c.status==="busy"||c.status==="working");let p=!1;if(b&&!w&&c?.mode!=="shell"){if(_crashDiag.log(`SNAPSHOT_RESTORE: ${(b.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying"),this._resetTerminalForReplay(),await new Promise(g=>this.terminal.write(b,g)),this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.scrollToLastNonEmptyLine(),_crashDiag.log("SNAPSHOT_RESTORE_DONE"),p=!0}const _=this.terminalBufferCache.get(e);if(_&&!w&&!p&&c?.mode!=="shell"){_crashDiag.log(`CACHE_WRITE: ${(_.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying");const g=performance.now();this._resetTerminalForReplay();const{parsedAt:P}=await this.chunkedTerminalWrite(_,TERMINAL_CHUNK_SIZE,d);if(u=P-g,this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.terminal.scrollToBottom(),_crashDiag.log("CACHE_DONE")}else(w||c?.mode==="shell")&&(this._resetTerminalForReplay(),S=!0,_crashDiag.log(c?.mode==="shell"?"CACHE_SKIP_SHELL":"CACHE_SKIP_BUSY"));if(c?.mode!=="shell"&&m&&(await new Promise(g=>setTimeout(g,TUI_REDRAW_SETTLE_MS)),this._isStaleSelect(a))){this._clearTerminalLoadState(e,a);return}this._setTerminalLoadState(e,a,"fetching"),_crashDiag.log("FETCH_START");const T=c?.mode!=="shell"&&!this._fullHistoryLoaded.has(e);T&&this._fullHistoryLoaded.add(e);const N=performance.now(),R=`/api/sessions/${e}/terminal?tail=${TERMINAL_TAIL_SIZE}`;let D;try{D=await this._fetchTerminalCapture(T?`/api/sessions/${e}/terminal?full=1`:R,{full:T})}catch(g){if(g?.name!=="AbortError"||!T)throw g;_crashDiag.log("FULL CAPTURE ABORTED \u2192 tail"),this._fullHistoryLoaded.delete(e),D=await this._fetchTerminalCapture(R)}const k=D.headersAt;if(this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}const E=D.json?.data??{},W=performance.now(),B=this._bufferLoadFinishOpts(E,k);_crashDiag.log(`FETCH_DONE: ${E.terminalBuffer?(E.terminalBuffer.length/1024).toFixed(0)+"KB":"empty"} truncated=${E.truncated}`);let V=0;if(E.terminalBuffer){if(p||S||E.terminalBuffer!==_){_crashDiag.log(`REWRITE: ${(E.terminalBuffer.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying");const P=performance.now();this._resetTerminalForReplay(),this._setHistoryTruncation(e,E);const{parsedAt:G}=await this.chunkedTerminalWrite(E.terminalBuffer,TERMINAL_CHUNK_SIZE,d,B);if(V=G-P,this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.terminal.scrollToBottom()}if(c?.mode==="shell")this.terminalBufferCache.delete(e);else if(this.terminalBufferCache.set(e,E.terminalBuffer),this.terminalBufferCache.size>20){const P=this.terminalBufferCache.keys().next().value;this.terminalBufferCache.delete(P)}}else(!_||S)&&(S||this._resetTerminalForReplay(),h=!0);const H={trigger:"session-select",mode:c?.mode||"unknown",full:T,source:E.source||"unknown",chars:E.terminalBuffer?.length||0,ttfbMs:k-N,bodyAndJsonMs:W-k,cacheResetAndParseMs:u,freshResetAndParseMs:V,selectToReplayCompleteMs:performance.now()-o,serverTiming:D.headers?.get?.("server-timing")||""};if(this._isLoadingBuffer&&this._finishBufferLoad(d,h?{flushQueued:!0,since:0}:B),this._markTerminalBufferReconciled(e),this._restoringFlushedState=!1,this._flushedOffsets?.has(e)&&this._localEchoOverlay){this._localEchoOverlay.setFlushed(this._flushedOffsets.get(e),this._flushedTexts?.get(e)||"",!1);const g=this._localEchoOverlay;this.terminal.write("",()=>{g.hasPending&&g.rerender()})}this.sendResize(e);const x=this.getTerminalDimensions?.(),C=E.source==="mux-visible",O=C&&Number.isFinite(E.captureRows)&&!!v&&!!x&&(x.cols!==v.cols||x.rows!==v.rows),$=C&&Number.isFinite(E.captureRows)&&E.captureRows>(this.terminal?.rows||0),I=C&&Number.isFinite(E.captureCols)&&E.captureCols>(this.terminal?.cols||0),F=!!x&&E.captureCols===x.cols&&E.captureRows===x.rows;(typeof requestIdleCallback=="function"?requestIdleCallback:g=>setTimeout(g,16))(()=>this._refreshSessionPanels(e,a)),this._connectWs(e),_crashDiag.log("FOCUS"),n&&this.terminal&&this.terminal.focus(),this.scrollToLastNonEmptyLine(),typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible&&KeyboardHandler.onKeyboardShow();const y=performance.now()-o;H.selectDoneMs=y,this._recordTerminalLoadTiming(H),this._clearTerminalLoadState(e,a),_crashDiag.log(`SELECT_DONE: ${y.toFixed(0)}ms`),console.log(`[CRASH-DIAG] selectSession DONE: ${e.slice(0,8)} in ${y.toFixed(0)}ms`),C&&Number.isFinite(E.captureRows)&&!$&&!I?this._geometryRetryUseless?.delete(e):t?.resizeRetry&&($||I)&&(this._geometryRetryUseless||=new Set).add(e),(O||$||I)&&!F&&!this._geometryRetryUseless?.has(e)&&!t?.resizeRetry&&!this._isStaleSelect(a)&&(_crashDiag.log(`RESIZE_RETRY: capture ${E.captureCols}x${E.captureRows} vs terminal ${this.terminal?.cols}x${this.terminal?.rows}`+(O?" (size moved under load)":"")),T&&this._fullHistoryLoaded.delete(e),await this.selectSession(e,{auto:!0,forceReload:!0,resizeRetry:!0}))}catch(m){if(this._isLoadingBuffer&&this._finishBufferLoad(d),this._restoringFlushedState=!1,console.error("Failed to load session terminal:",m),this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this._connectWs(e),S&&this.terminal&&this.terminal.write(`\r
|
|
38
|
+
\x1B[2m History did not load.\r
|
|
39
|
+
Live output continues.\r
|
|
40
|
+
Reload to try again.\x1B[0m\r
|
|
41
|
+
`),this._clearTerminalLoadState(e,a)}}_refreshSessionPanels(e,t){if(t!==this._selectGeneration)return;this.respawnStatus[e]?(this.showRespawnBanner(),this.updateRespawnBanner(this.respawnStatus[e].state),document.getElementById("respawnCycleCount").textContent=this.respawnStatus[e].cycleCount||0,this.updateCountdownTimerDisplay(),this.updateActionLogDisplay(),Object.keys(this.respawnCountdownTimers[e]||{}).length>0&&this.startCountdownInterval()):(this.hideRespawnBanner(),this.stopCountdownInterval());const s=document.getElementById("taskPanel");s&&s.classList.contains("open")&&this.renderTaskPanel();const i=this.sessions.get(e);if(i&&(i.ralphLoop||i.ralphTodos)&&this.updateRalphState(e,{loop:i.ralphLoop,todos:i.ralphTodos}),this.renderRalphStatePanel(),this.updateCliInfoDisplay(),this.renderProjectInsightsPanel(),this.updateSubagentWindowVisibility(),this.loadAppSettingsFromStorage().showFileBrowser){const o=this.$("fileBrowserPanel");if(o&&(o.classList.add("visible"),this.loadFileBrowser(e),!this.fileBrowserDragListeners)){const r=o.querySelector(".file-browser-header");if(r){const a=()=>{if(!o.style.left){const l=o.getBoundingClientRect();o.style.left=`${l.left}px`,o.style.top=`${l.top}px`,o.style.right="auto"}};r.addEventListener("mousedown",a),r.addEventListener("touchstart",a,{passive:!0}),this.fileBrowserDragListeners=this.makeWindowDraggable(o,r),this.fileBrowserDragListeners._onFirstDrag=a}}}}_cleanupSessionData(e){this.closeTabRailActionMenu?.(),this._markTerminalBufferReconciled(e),this._activeRename?.sessionId===e&&this._activeRename.cancel(),this.sessions.delete(e);const t=this.sessionOrder.indexOf(e);t!==-1&&(this.sessionOrder.splice(t,1),this.saveSessionOrder()),this.terminalBuffers.delete(e),this.terminalBufferCache.delete(e),this._clearHistoryTruncation(e),this._xtermSnapshots?.delete(e);try{localStorage.removeItem(`codeman-xs-${e}`)}catch{}this._flushedOffsets?.delete(e),this._flushedTexts?.delete(e),typeof KeyboardAccessoryBar<"u"&&KeyboardAccessoryBar.discardComposerDraft?.(e),this._pendingDeliveries?.delete(e),this._seqCounters?.delete(e),this._postDraining?.delete(e),this._persistReliableState(),this.ralphStates.delete(e),this.ralphClosedSessions.delete(e),this.projectInsights.delete(e),this.pendingHooks.delete(e),this.tabAlerts.delete(e),this.attachmentHistoryCounts.delete(e),this.attachmentHistoryDrawerOpen&&this.activeSessionId===e&&this.closeAttachmentHistory?.(),this.terminalLoadStates.delete(e),this.clearCountdownTimers(e),this.closeSessionLogViewerWindows(e),this.closeSessionImagePopups(e),this.closeSessionAttachmentCards(e),this.closeSessionSubagentWindows(e,!0);const s=this.idleTimers.get(e);s&&(clearTimeout(s),this.idleTimers.delete(e)),delete this.respawnStatus[e],delete this.respawnTimers[e],delete this.respawnCountdownTimers[e],delete this.respawnActionLogs[e]}async closeSession(e,t=!0){if(this._closingSessions.has(e))return;const s=this.sessions.get(e),i=this.sessionOrder.indexOf(e),n=this.activeSessionId===e,o=this._tileGrid,r=o?.has(e)?window.CodemanTileGrid.tileNeighbor(o.ids,e):null;this._closingSessions.add(e);let a=null;try{if(this._onSessionDeleted({id:e}),n&&o?.open){const c=o.has(r)?r:o.ids[0];this._selectTiledSession(c,{auto:!0})}else if(n){this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}const c=this.sessionOrder.find(d=>d!==e&&this.sessions.has(d));c?this.selectSession(c,{auto:!0}):(this.terminal.clear(),this.showWelcome(),this.renderRalphStatePanel())}this.renderSessionTabs({immediate:!0}),a=await this._apiDelete(`/api/sessions/${e}?killMux=${t}`)}catch(c){console.warn("[closeSession] close failed:",c)}finally{this._closingSessions.delete(e)}let l=!!a&&(a.ok||a.status===404);if(l||(l=(await this._api(`/api/sessions/${e}`))?.status===404),l){this.sessions.has(e)&&this._onSessionDeleted({id:e}),t?this.showToast("Session closed and tmux killed","success"):this.showToast("Tab hidden, tmux still running","info");return}if(s&&!this.sessions.has(e)){if(this.sessions.set(e,s),!this.sessionOrder.includes(e)){const c=i===-1?this.sessionOrder.length:Math.min(i,this.sessionOrder.length);this.sessionOrder.splice(c,0,e),this.saveSessionOrder()}this.renderSessionTabs()}this.showToast("Failed to close session","error")}requestCloseSession(e){const t=this.sessions.get(e);if(!t)return;this.pendingCloseSessionId=e;const s=this.getSessionName(t),i=document.getElementById("closeConfirmSessionName");i.textContent=s;const n=document.getElementById("closeConfirmKillTitle");n&&(n.textContent=t.mode==="opencode"?"Kill Tmux & OpenCode":t.mode==="codex"?"Kill Tmux & Codex":t.mode==="gemini"?"Kill Tmux & Gemini":t.mode==="antigravity"?"Kill Tmux & Antigravity":t.mode==="pi"?"Kill Tmux & Pi":t.mode==="grok"?"Kill Tmux & Grok":t.mode==="deepseek"?"Kill Tmux & DeepSeek":t.mode==="omp"?"Kill Tmux & OMP":"Kill Tmux & Claude Code"),document.getElementById("closeConfirmModal").classList.add("active")}cancelCloseSession(){this.pendingCloseSessionId=null,document.getElementById("closeConfirmModal").classList.remove("active")}async confirmCloseSession(e=!0){const t=this.pendingCloseSessionId;this.cancelCloseSession(),t&&await this.closeSession(t,e)}nextSession(){if(this._cycleTileFocus?.(1)||this.sessionOrder.length<=1)return;const t=(this.sessionOrder.indexOf(this.activeSessionId)+1)%this.sessionOrder.length;this.selectSession(this.sessionOrder[t])}prevSession(){if(this._cycleTileFocus?.(-1)||this.sessionOrder.length<=1)return;const t=(this.sessionOrder.indexOf(this.activeSessionId)-1+this.sessionOrder.length)%this.sessionOrder.length;this.selectSession(this.sessionOrder[t])}goHome(){this._retireUrlSession(),this.closeTileGrid?.({keepStored:!0,reselect:!1}),this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.terminal.clear(),this.showWelcome(),this.renderSessionTabs(),this.renderRalphStatePanel()}ralphWizardStep=1;ralphWizardConfig={taskDescription:"",completionPhrase:"COMPLETE",maxIterations:10,caseName:"testcase",enableRespawn:!1,generatedPlan:null,planGenerated:!1,skipPlanGeneration:!1,planDetailLevel:"detailed",existingPlan:null,useExistingPlan:!1};planLoadingTimer=null;planLoadingStartTime=null;async killActiveSession(){if(!this.activeSessionId){this.showToast("No active session","warning");return}await this.closeSession(this.activeSessionId)}async killAllSessions(){if(this.sessions.size!==0&&confirm(`Kill all ${this.sessions.size} session(s)?`))try{await this._apiDelete("/api/sessions"),this.closeTileGrid?.({keepStored:!0,reselect:!1}),this.sessions.clear(),this.terminalBuffers.clear(),this.terminalBufferCache.clear(),this.terminalLoadStates.clear(),this._xtermSnapshots?.clear();try{for(const e of Object.keys(localStorage))e.startsWith("codeman-xs-")&&localStorage.removeItem(e)}catch{}this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.respawnStatus={},this.respawnCountdownTimers={},this.respawnActionLogs={},this.stopCountdownInterval(),this.hideRespawnBanner(),this.renderSessionTabs(),this.terminal.clear(),this.showWelcome(),this.showToast("All sessions killed","success")}catch{this.showToast("Failed to kill sessions","error")}}showTimer(){document.getElementById("timerBanner").style.display="flex",this.updateTimer(),this.timerInterval=setInterval(()=>this.updateTimer(),1e3)}hideTimer(){document.getElementById("timerBanner").style.display="none",this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null)}updateTimer(){if(!this.currentRun||this.currentRun.status!=="running")return;const e=Date.now(),t=Math.max(0,this.currentRun.endAt-e),s=this.currentRun.endAt-this.currentRun.startedAt,i=e-this.currentRun.startedAt,n=Math.min(100,i/s*100);document.getElementById("timerValue").textContent=this.formatTime(t),document.getElementById("timerProgress").style.width=`${n}%`,document.getElementById("timerMeta").textContent=`${this.currentRun.completedTasks} tasks | $${this.currentRun.totalCost.toFixed(2)}`}async stopCurrentRun(){if(this.currentRun)try{await fetch(`/api/scheduled/${this.currentRun.id}`,{method:"DELETE"})}catch{this.showToast("Failed to stop run","error")}}formatTime(e){const t=Math.floor(e/1e3),s=Math.floor(t/3600),i=Math.floor(t%3600/60),n=t%60;return`${s.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`}updateCost(){this.updateTokens()}updateTokens(){this._clearTimer("_updateTokensTimeout"),this._updateTokensTimeout=setTimeout(()=>{this._updateTokensTimeout=null,this._updateTokensImmediate()},200)}_updateTokensImmediate(){let e=0,t=0;this.globalStats?(e=this.globalStats.totalInputTokens||0,t=this.globalStats.totalOutputTokens||0):this.sessions.forEach(r=>{r.tokens&&(e+=r.tokens.input||0,t+=r.tokens.output||0)});const s=e+t;this.totalTokens=s;const i=this.formatTokens(s),n=this.estimateCost(e,t),o=this.$("headerTokens");if(o){const a=this.loadAppSettingsFromStorage().showCost??!1;o.textContent=s>0?a?`${i} tokens \xB7 $${n.toFixed(2)}`:`${i} tokens`:"0 tokens",o.title=this.globalStats?`Lifetime: ${this.globalStats.totalSessionsCreated} sessions created${a?`
|
|
42
|
+
Estimated cost based on Claude Opus pricing`:""}`:`Token usage across active sessions${a?`
|
|
43
|
+
Estimated cost based on Claude Opus pricing`:""}`}}getShortcutRegistry(){const t=this.loadAppSettingsFromStorage().shortcutOverrides||{};return DEFAULT_SHORTCUTS.map(s=>{const i=t[s.id];if(!i)return s;const n={...s};return Array.isArray(i.bindings)&&(n.bindings=i.bindings,delete n.displayBindings),typeof i.disabled=="boolean"&&(n.disabled=i.disabled),n})}matchesShortcutEvent(e,t){return!t||!Array.isArray(t.bindings)?!1:t.bindings.some(s=>{const i=s.modifiers||[];return(i.includes("ctrl")||i.includes("meta"))!==!!(e.ctrlKey||e.metaKey)||i.includes("shift")!==!!e.shiftKey||i.includes("alt")!==!!e.altKey?!1:!!(s.code&&e.code===s.code||s.key&&typeof e.key=="string"&&e.key.toLowerCase()===s.key.toLowerCase())})}showShortcutOverlay(){const e=document.getElementById("shortcutOverlayModal");e&&(this.renderShortcutOverlay(),e.classList.add("active"),e.focus?.())}renderShortcutOverlay(){const e=document.getElementById("shortcutOverlayList");if(!e)return;const t=this.getShortcutRegistry(),s={};for(const n of t){const o=n.group||"General";s[o]||(s[o]=[]),s[o].push(n)}const i=n=>n.displayBindings?n.displayBindings.map(o=>`<kbd data-i18n-skip>${escapeHtml(o)}</kbd>`).join(" / "):n.bindings?n.bindings.length===0?'<span class="shortcut-overlay-unbound">not bound</span>':n.bindings.map(o=>{const r=[...(o.modifiers||[]).map(a=>a.charAt(0).toUpperCase()+a.slice(1)),o.key||o.code||""];return`<kbd data-i18n-skip>${escapeHtml(r.join("+"))}</kbd>`}).join(" / "):"";e.innerHTML=Object.entries(s).map(([n,o])=>`<div class="shortcut-overlay-group"><div class="shortcut-overlay-group-label">${escapeHtml(n)}</div>`+o.map(r=>`<div class="shortcut-overlay-row"><span class="shortcut-overlay-label">${escapeHtml(r.label)}</span><span class="shortcut-overlay-keys">${i(r)}</span></div>`).join("")+"</div>").join("")}closeShortcutOverlay(){const e=document.getElementById("shortcutOverlayModal");e&&e.classList.remove("active")}}try{for(let f=0;f<localStorage.length;f++){const e=localStorage.key(f);if(e&&(e.startsWith("claudeman-")||e.startsWith("claudeman_"))){const t=e.replace(/^claudeman[-_]/,s=>"codeman"+s.charAt(s.length-1));localStorage.getItem(t)===null&&localStorage.setItem(t,localStorage.getItem(e))}}}catch{}let app;document.addEventListener("DOMContentLoaded",()=>{app=new CodemanApp,window.app=app}),window.MobileDetection=MobileDetection;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|