aicodeman 1.26.2 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  2. package/dist/config/cli-registry/stock.js +13 -2
  3. package/dist/config/cli-registry/stock.js.map +1 -1
  4. package/dist/session-cli-builder.d.ts.map +1 -1
  5. package/dist/session-cli-builder.js +31 -5
  6. package/dist/session-cli-builder.js.map +1 -1
  7. package/dist/session.d.ts.map +1 -1
  8. package/dist/session.js +19 -0
  9. package/dist/session.js.map +1 -1
  10. package/dist/tmux-manager.d.ts +3 -0
  11. package/dist/tmux-manager.d.ts.map +1 -1
  12. package/dist/tmux-manager.js +65 -8
  13. package/dist/tmux-manager.js.map +1 -1
  14. package/dist/types/common.d.ts +2 -0
  15. package/dist/types/common.d.ts.map +1 -1
  16. package/dist/utils/omp-session-resolver.d.ts +14 -0
  17. package/dist/utils/omp-session-resolver.d.ts.map +1 -1
  18. package/dist/utils/omp-session-resolver.js +21 -2
  19. package/dist/utils/omp-session-resolver.js.map +1 -1
  20. package/dist/web/public/admin-ui.js.gz +0 -0
  21. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  22. package/dist/web/public/app.78bf0bf8.js +38 -0
  23. package/dist/web/public/app.78bf0bf8.js.br +0 -0
  24. package/dist/web/public/app.78bf0bf8.js.gz +0 -0
  25. package/dist/web/public/approvals-ui.js.gz +0 -0
  26. package/dist/web/public/{constants.e6d48776.js → constants.9cd8ed69.js} +7 -1
  27. package/dist/web/public/constants.9cd8ed69.js.br +0 -0
  28. package/dist/web/public/constants.9cd8ed69.js.gz +0 -0
  29. package/dist/web/public/cron-ui.js.gz +0 -0
  30. package/dist/web/public/entrance-animations.js.gz +0 -0
  31. package/dist/web/public/home-sessions.js.gz +0 -0
  32. package/dist/web/public/i18n.9db8c4e0.js.gz +0 -0
  33. package/dist/web/public/image-input.cd4b97c4.js.gz +0 -0
  34. package/dist/web/public/index.html +22 -10
  35. package/dist/web/public/index.html.br +0 -0
  36. package/dist/web/public/index.html.gz +0 -0
  37. package/dist/web/public/input-cjk.87f14251.js.gz +0 -0
  38. package/dist/web/public/{keyboard-accessory.daf18302.js → keyboard-accessory.1d0dda9b.js} +182 -13
  39. package/dist/web/public/keyboard-accessory.1d0dda9b.js.br +0 -0
  40. package/dist/web/public/keyboard-accessory.1d0dda9b.js.gz +0 -0
  41. package/dist/web/public/mobile-handlers.2e9c214a.js.gz +0 -0
  42. package/dist/web/public/mobile-overview.js.gz +0 -0
  43. package/dist/web/public/mobile.65176832.css.gz +0 -0
  44. package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
  45. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  46. package/dist/web/public/{panels-ui.9eb5b235.js → panels-ui.4e9ea307.js} +1 -1
  47. package/dist/web/public/panels-ui.4e9ea307.js.br +0 -0
  48. package/dist/web/public/panels-ui.4e9ea307.js.gz +0 -0
  49. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  50. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  51. package/dist/web/public/readmymind-ui.js.gz +0 -0
  52. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  53. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  54. package/dist/web/public/session-lineage.js.gz +0 -0
  55. package/dist/web/public/session-ui.cd222710.js.gz +0 -0
  56. package/dist/web/public/settings-ui.c175db9a.js +67 -0
  57. package/dist/web/public/settings-ui.c175db9a.js.br +0 -0
  58. package/dist/web/public/settings-ui.c175db9a.js.gz +0 -0
  59. package/dist/web/public/{styles.89069bbc.css → styles.0d41361c.css} +1 -1
  60. package/dist/web/public/styles.0d41361c.css.br +0 -0
  61. package/dist/web/public/styles.0d41361c.css.gz +0 -0
  62. package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
  63. package/dist/web/public/sw.js.gz +0 -0
  64. package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
  65. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js +1 -0
  66. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.br +0 -0
  67. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.gz +0 -0
  68. package/dist/web/public/terminal-ui.89e4eb1a.js +2 -0
  69. package/dist/web/public/terminal-ui.89e4eb1a.js.br +0 -0
  70. package/dist/web/public/terminal-ui.89e4eb1a.js.gz +0 -0
  71. package/dist/web/public/ultracode-panel.js.gz +0 -0
  72. package/dist/web/public/ultracode-windows.js.gz +0 -0
  73. package/dist/web/public/upload.html.gz +0 -0
  74. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  75. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  76. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  77. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  78. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  79. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  80. package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
  81. package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
  82. package/dist/web/public/vendor/xterm.css.gz +0 -0
  83. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  84. package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
  85. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  86. package/dist/web/public/webview-tabs.js +199 -9
  87. package/dist/web/public/webview-tabs.js.br +0 -0
  88. package/dist/web/public/webview-tabs.js.gz +0 -0
  89. package/dist/web/response-viewer-transcript.d.ts +20 -0
  90. package/dist/web/response-viewer-transcript.d.ts.map +1 -1
  91. package/dist/web/response-viewer-transcript.js +27 -0
  92. package/dist/web/response-viewer-transcript.js.map +1 -1
  93. package/dist/web/routes/file-routes.d.ts.map +1 -1
  94. package/dist/web/routes/file-routes.js +11 -3
  95. package/dist/web/routes/file-routes.js.map +1 -1
  96. package/dist/web/routes/session-routes.d.ts.map +1 -1
  97. package/dist/web/routes/session-routes.js +16 -4
  98. package/dist/web/routes/session-routes.js.map +1 -1
  99. package/dist/web/schemas.d.ts +4 -0
  100. package/dist/web/schemas.d.ts.map +1 -1
  101. package/dist/web/schemas.js +9 -0
  102. package/dist/web/schemas.js.map +1 -1
  103. package/package.json +1 -1
  104. package/skills/codeman/reference/endpoints.md +1 -0
  105. package/dist/web/public/app.c4dbfcfb.js +0 -38
  106. package/dist/web/public/app.c4dbfcfb.js.br +0 -0
  107. package/dist/web/public/app.c4dbfcfb.js.gz +0 -0
  108. package/dist/web/public/constants.e6d48776.js.br +0 -0
  109. package/dist/web/public/constants.e6d48776.js.gz +0 -0
  110. package/dist/web/public/keyboard-accessory.daf18302.js.br +0 -0
  111. package/dist/web/public/keyboard-accessory.daf18302.js.gz +0 -0
  112. package/dist/web/public/panels-ui.9eb5b235.js.br +0 -0
  113. package/dist/web/public/panels-ui.9eb5b235.js.gz +0 -0
  114. package/dist/web/public/settings-ui.554f9cdd.js +0 -67
  115. package/dist/web/public/settings-ui.554f9cdd.js.br +0 -0
  116. package/dist/web/public/settings-ui.554f9cdd.js.gz +0 -0
  117. package/dist/web/public/styles.89069bbc.css.br +0 -0
  118. package/dist/web/public/styles.89069bbc.css.gz +0 -0
  119. package/dist/web/public/terminal-ui.1547ce5e.js +0 -2
  120. package/dist/web/public/terminal-ui.1547ce5e.js.br +0 -0
  121. package/dist/web/public/terminal-ui.1547ce5e.js.gz +0 -0
Binary file
@@ -0,0 +1 @@
1
+ "use strict";(function(i){"use strict";function h(o){const t=o?.textarea,d=o?.emitRecovered;if(!t?.addEventListener||!t?.removeEventListener||typeof d!="function")return null;const E=o.isScreenReaderMode,T=o.setTimer||i.setTimeout.bind(i),C=o.clearTimer||i.clearTimeout.bind(i);let n=!1,c=0,m=0,u=!1;const s=[];function a(){for(const e of s.splice(0))if(e.active=!1,e.timer!==null){try{C(e.timer)}catch{}e.timer=null}}function L(e){const r=s.indexOf(e);if(r!==-1&&s.splice(r,1),e.timer=null,!(!e.active||n)&&(e.active=!1,!(c>e.snapshot)))try{d(e.data)}catch{}}function w(){c+=1}function x(e){n||e?.type!=="keydown"||(m=c)}function l(e){if(n||u||e?.isComposing||e.inputType!=="insertText")return;const r=e.data;if(typeof r!="string"||r==="")return;try{if(E?.())return}catch{return}const f={data:r,snapshot:m??c,active:!0,timer:null};s.push(f);try{f.timer=T(()=>L(f),0)}catch{a()}}function p(){n||(u=!0,a())}function v(){n||(u=!1)}function y(){if(!n){n=!0,a();try{t.removeEventListener("input",l,!0),t.removeEventListener("compositionstart",p,!0),t.removeEventListener("compositionend",v,!0)}catch{}}}try{t.addEventListener("input",l,!0),t.addEventListener("compositionstart",p,!0),t.addEventListener("compositionend",v,!0)}catch{return y(),null}return Object.freeze({handleKeyEvent:x,notifyCanonicalData:w,destroy:y})}i.CodemanKeyCode229Recovery=Object.freeze({create:h})})(typeof window<"u"?window:globalThis);
@@ -0,0 +1,2 @@
1
+ "use strict";(function(e){const t=/^\x1b\[[\?>=]?[\d;]*[cnR]$/,i=/^\x1b\][\d;]*[^\x07\x1b]*(?:\x07|\x1b\\)$/,s=/^\x1b\[<\d+;\d+;\d+[Mm]$/,n=/^\x1b\[M[\s\S]{3}$/,o=/^\x1b\[[IO]$/,c=["input","textarea","select","button","a[href]",'[contenteditable=""]','[contenteditable="true"]','[tabindex]:not([tabindex="-1"])',".keyboard-accessory-bar",".path-picker-overlay"].join(","),p=/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[[0-9;?<>=!]*[ -/]*[@-~]|\x1b[()#][0-9A-Za-z]|\x1b[=>78M]/g,v="\x1B[5~",E="\x1B[6~",y=.5,w=3,l=4,h=/^\x1b(?:\[(?:[ABCDHF]|1;[2-8][ABCDHF]|[1-8](?:;[2-8])?~)|O[ABCDHF])$/,f="\x1B[200~";function g(T){return h.test(T)}const _=/^› /;function b(T){const A=Array.from(T);if(A.length===1){const M=A[0].codePointAt(0);return M===127?"backspace":M>=32?"char":"clear"}return T.charCodeAt(0)===27?"clear":T.charCodeAt(0)>=32?"text":"clear"}function C(T){try{const A=T.buffer.active,M=A.getLine(A.baseY+A.cursorY);return!!M&&_.test(M.translateToString(!0))}catch{return!1}}function L(T){return t.test(T)||i.test(T)}function I(T){return L(T)}function k(T){return o.test(T)||s.test(T)||n.test(T)}const x={og:{background:"#0d0d0d",foreground:"#e0e0e0",cursor:"#e0e0e0",cursorAccent:"#0d0d0d",selection:"rgba(255,255,255,0.3)",black:"#0d0d0d",red:"#ff6b6b",green:"#51cf66",yellow:"#ffd43b",blue:"#339af0",magenta:"#cc5de8",cyan:"#22b8cf",white:"#e0e0e0",brightBlack:"#495057",brightRed:"#ff8787",brightGreen:"#69db7c",brightYellow:"#ffe066",brightBlue:"#5c7cfa",brightMagenta:"#da77f2",brightCyan:"#66d9e8",brightWhite:"#ffffff"},"daylight-green":{background:"#161b23",foreground:"#dfe6ef",cursor:"#2fd3aa",cursorAccent:"#161b23",selection:"rgba(47,211,170,0.22)",black:"#161b23",red:"#ff8585",green:"#34d8a0",yellow:"#f0c25a",blue:"#5cc6e8",magenta:"#c79af2",cyan:"#2bcbbb",white:"#dfe6ef",brightBlack:"#5b6675",brightRed:"#ffa0a0",brightGreen:"#5fe6b8",brightYellow:"#ffd884",brightBlue:"#82d4ee",brightMagenta:"#d6b3f7",brightCyan:"#5ee0d4",brightWhite:"#f3f6fa"},"daylight-blue":{background:"#161b23",foreground:"#dfe6ef",cursor:"#38b6f0",cursorAccent:"#161b23",selection:"rgba(56,182,240,0.22)",black:"#161b23",red:"#ff8585",green:"#34d8a0",yellow:"#f0c25a",blue:"#5cc6e8",magenta:"#c79af2",cyan:"#2bcbbb",white:"#dfe6ef",brightBlack:"#5b6675",brightRed:"#ffa0a0",brightGreen:"#5fe6b8",brightYellow:"#ffd884",brightBlue:"#82d4ee",brightMagenta:"#d6b3f7",brightCyan:"#5ee0d4",brightWhite:"#f3f6fa"},"paper-gray":{background:"#f6f8fa",foreground:"#1f2328",cursor:"#0969da",cursorAccent:"#ffffff",selection:"rgba(9,105,218,0.2)",black:"#24292f",red:"#cf222e",green:"#1a7f37",yellow:"#9a6700",blue:"#0969da",magenta:"#8250df",cyan:"#1b7c83",white:"#59636e",brightBlack:"#6e7781",brightRed:"#a40e26",brightGreen:"#116329",brightYellow:"#7d4e00",brightBlue:"#0550ae",brightMagenta:"#6639ba",brightCyan:"#116b75",brightWhite:"#1f2328"},"solarized-light":{background:"#fdf6e3",foreground:"#586e75",cursor:"#147ba3",cursorAccent:"#fdf6e3",selection:"rgba(38,139,210,0.2)",black:"#eee8d5",red:"#dc322f",green:"#758600",yellow:"#9b7800",blue:"#147ba3",magenta:"#d33682",cyan:"#2a9189",white:"#073642",brightBlack:"#93a1a1",brightRed:"#cb4b16",brightGreen:"#657b83",brightYellow:"#586e75",brightBlue:"#268bd2",brightMagenta:"#6c71c4",brightCyan:"#2aa198",brightWhite:"#002b36"},"catppuccin-latte":{background:"#eff1f5",foreground:"#4c4f69",cursor:"#1e66f5",cursorAccent:"#ffffff",selection:"rgba(30,102,245,0.18)",black:"#5c5f77",red:"#d20f39",green:"#3b8f2b",yellow:"#a86605",blue:"#1e66f5",magenta:"#8839ef",cyan:"#177f86",white:"#6c6f85",brightBlack:"#7c7f93",brightRed:"#b50930",brightGreen:"#2f7622",brightYellow:"#8b5604",brightBlue:"#174fbf",brightMagenta:"#6f2bc5",brightCyan:"#116b71",brightWhite:"#4c4f69"},"rose-pine-dawn":{background:"#faf4ed",foreground:"#575279",cursor:"#286983",cursorAccent:"#fffaf3",selection:"rgba(40,105,131,0.2)",black:"#575279",red:"#b4637a",green:"#286983",yellow:"#96681f",blue:"#477f91",magenta:"#907aa9",cyan:"#3f7f8b",white:"#6e6a86",brightBlack:"#797593",brightRed:"#984d66",brightGreen:"#1f5266",brightYellow:"#7d5417",brightBlue:"#386b7c",brightMagenta:"#765f90",brightCyan:"#326b76",brightWhite:"#575279"}},F=new Set(["paper-gray","solarized-light","catppuccin-latte","rose-pine-dawn"]);function O(){return typeof document<"u"&&document.documentElement.dataset.skin||"daylight-blue"}function B(){const T=O();return x[T]||x["daylight-blue"]}function S(T=O()){return F.has(T)}e.CodemanTerminalInput={isTerminalQueryResponse:L,shouldSuppressTerminalQueryResponse:I,isTerminalFocusOrMouseReport:k,isComposerNavKey:g,classifyPredictInput:b,isCodexComposerRow:C,CODEX_COMPOSER_ROW_RE:_,BRACKETED_PASTE_START:f,USER_SCROLL_STICKY_SUPPRESS_MS:1500,TOUCH_COMPAT_MOUSE_SUPPRESS_MS:450,REPLAY_ESCAPE_RE:p,KEY_PAGE_UP:v,KEY_PAGE_DOWN:E,PAGE_KEY_SCREEN_FRACTION:y,PAGE_KEY_MAX_PER_BATCH:w,TUI_PROMPT_DEFAULT_ROWS_FROM_BOTTOM:l,MOBILE_KEYBOARD_DISMISS_EXEMPT_SELECTOR:c,MOBILE_KEYBOARD_DISMISS_TAP_SLOP:8,TOUCH_SELECT_LONG_PRESS_MS:350,TOUCH_SELECT_FOCUS_GUARD_MS:800},e.CODEMAN_XTERM_THEMES=x,e.codemanCurrentXtermTheme=B,e.codemanCurrentSkinIsLight=S})(window),Object.assign(CodemanApp.prototype,{_destroyKeyCode229Recovery(){try{this._keyCode229Recovery?.destroy?.()}catch{}this._keyCode229Recovery=null},initTerminal(){const e=parseInt(localStorage.getItem("codeman-scrollback")),t=Number.isFinite(e)&&e>0?Math.max(e,DEFAULT_SCROLLBACK):DEFAULT_SCROLLBACK;if(this._destroyKeyCode229Recovery(),this.terminal=new Terminal({theme:{...window.codemanCurrentXtermTheme()},fontFamily:window.CodemanTerminalFont.resolve(this.loadAppSettingsFromStorage?.().terminalFontFamily),fontSize:MobileDetection.getDeviceType()==="mobile"?10:14,lineHeight:1.2,cursorBlink:!1,cursorStyle:"block",minimumContrastRatio:window.codemanCurrentSkinIsLight()?4.5:1,scrollback:t,allowTransparency:!0,allowProposedApi:!0}),this.fitAddon=new FitAddon.FitAddon,this.terminal.loadAddon(this.fitAddon),this._xtermSnapshots=new Map,typeof SerializeAddon<"u")try{this._serializeAddon=new SerializeAddon.SerializeAddon,this.terminal.loadAddon(this._serializeAddon)}catch{this._serializeAddon=null}if(typeof Unicode11Addon<"u")try{const l=new Unicode11Addon.Unicode11Addon;this.terminal.loadAddon(l),this.terminal.unicode.activeVersion="11"}catch{}const i=document.getElementById("terminalContainer");this.terminal.open(i),this._installMobileTapMouseGuard(),this._installTouchSelectionFocusGuard(),this.terminal.attachCustomKeyEventHandler(l=>{try{this._keyCode229Recovery?.handleKeyEvent?.(l)}catch{}if(l.isComposing||l.key==="Process"||l.keyCode===229)return!0;if(l.altKey&&!l.ctrlKey&&!l.shiftKey&&/^(Digit[1-9]|BracketLeft|BracketRight|KeyK)$/.test(l.code||"")||l.type==="keydown"&&this.shouldOpenCommandPaletteFromShortcut?.(l))return!1;if(this.shouldCopyTerminalSelectionFromShortcut?.(l)){const h=this.terminal.hasSelection?.()?this.terminal.getSelection():"";return h?(l.preventDefault(),this.copyTerminalSelection(h),!1):l.shiftKey?(l.preventDefault(),!1):!0}if(l.type==="keydown"&&this.shouldToggleSessionSidebarFromShortcut?.(l))return!1;if((l.ctrlKey||l.metaKey)&&l.key==="v"&&l.type==="keydown")return this.activeSessionId&&this._handleImagePaste&&this._handleImagePaste(),!1;if(l.type==="keydown"&&l.key.toLowerCase()==="z"&&l.ctrlKey&&!l.altKey&&!l.metaKey&&!l.shiftKey){const h=this.activeSessionId?this.sessions.get(this.activeSessionId):null;if(h&&h.mode!=="shell")return l.preventDefault(),!1}if(l.key==="Enter"&&(l.shiftKey||l.ctrlKey)&&l.type==="keydown"){if(this.activeSessionId)if(this._localEchoEnabled){const h=this._localEchoOverlay?.pendingText||"";this._localEchoOverlay?.clear(),this._localEchoOverlay?.suppressBufferDetection(),this._flushedOffsets?.delete(this.activeSessionId),this._flushedTexts?.delete(this.activeSessionId),h&&(this._pendingInput+=h,y()),setTimeout(()=>{fetch(`/api/sessions/${this.activeSessionId}/send-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:l.ctrlKey?"C-Enter":"S-Enter"})})},h?80:0)}else fetch(`/api/sessions/${this.activeSessionId}/send-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:l.ctrlKey?"C-Enter":"S-Enter"})});return!1}return!0}),this._webglAddon=null;const s=new URLSearchParams(location.search),n=(()=>{try{const l=localStorage.getItem("codeman-webgl-disabled");if(!l)return!1;const{at:h}=JSON.parse(l);return Date.now()-h>WEBGL_FALLBACK.STICKY_EXPIRY_MS?(localStorage.removeItem("codeman-webgl-disabled"),!1):!0}catch{return!1}})(),o=this.loadAppSettingsFromStorage(),r=this.getDefaultSettings(),a=o.webglRendererEnabled??r.webglRendererEnabled,{skip:d,clearSticky:u}=shouldSkipWebGL({deviceType:MobileDetection.getDeviceType(),noWebglParam:s.has("nowebgl"),forceParam:s.get("webgl")==="force",stickyDisabled:n,userPrefEnabled:a});if(u)try{localStorage.removeItem("codeman-webgl-disabled")}catch{}if(d&&n&&console.log("[CRASH-DIAG] WebGL sticky-disabled from prior stalls \u2014 DOM renderer in use. Re-enable: ?webgl=force"),!d)if(typeof WebglAddon<"u")this._initWebGL();else{const l=document.createElement("script");l.src="vendor/xterm-addon-webgl.min.js",l.onload=()=>this._initWebGL(),l.onerror=()=>console.warn("[CRASH-DIAG] Failed to load WebGL addon \u2014 using canvas renderer"),document.head.appendChild(l)}this._localEchoOverlay=new LocalEchoOverlay(this.terminal),this._predictiveEcho=typeof PredictiveEchoOverlay<"u"?new PredictiveEchoOverlay(this.terminal):null,this._predictiveEcho?.setPredictWhen(l=>window.CodemanTerminalInput.isCodexComposerRow(l)),MobileDetection.isTouchDevice()&&(this.terminal.onCursorMove(()=>this._syncMobileHelperTextareaToCursor()),this.terminal.onRender(()=>this._syncMobileHelperTextareaToCursor())),this._cjkInput=null,typeof CjkInput<"u"&&(this._cjkInput=CjkInput.init({send:l=>{this._handleCjkInput(l)}}));const m=this.terminal.focus.bind(this.terminal);this.terminal.focus=()=>{const l=document.getElementById("cjkInput");l?.classList.contains("cjk-input-visible")?l.focus():m()},MobileDetection.getDeviceType()==="mobile"&&document.body.classList.contains("safari-browser")?requestAnimationFrame(()=>{this.fitAddon.fit(),requestAnimationFrame(()=>this.fitAddon.fit())}):this.fitAddon.fit(),this._terminalFontReady=this._awaitTerminalFont(),this.registerFilePathLinkProvider(),this.terminal.onSelectionChange?.(()=>{if(!this.terminal?.hasSelection?.()){this._touchSelecting=!1,this._touchSelectionActive=!1,this._touchSelectionAnchor=null,this._hideTouchSelectionBar(),this._autoCopyPending=!1;return}this._autoCopyPending=!0}),this._autoCopyListenerInstalled||(this._autoCopyListenerInstalled=!0,document.addEventListener("mouseup",()=>this._flushAutoCopySelection())),i.addEventListener("wheel",l=>{const h=this.terminal?.modes?.mouseTrackingMode;if(h&&h!=="none"||this.terminal?.buffer?.active?.type==="alternate")return;if(l.preventDefault(),l.stopPropagation(),this._shouldForwardWheelToApp(l)){this._logScrollRouting("forward-sgr"),this._forwardScrollToApp(l.clientX,l.clientY,this._wheelScrollLines(l));return}const f=this._wheelScrollLinesFloat(l);this._maybePageCliTranscript(l,f)||(this._logScrollRouting("local-scrollback"),this._noteTerminalUserScroll(f),this._smoothScrollBy(f))},{passive:!1,capture:!0});{const l=()=>this.terminal._core?._renderService?.dimensions?.css?.cell?.height||13;let h=0,f=0,g=0,_=0,b=null,C=!1;const L=M=>{const R=_?(M-_)/16.67:1;if(_=M,!C&&Math.abs(g)>.3){const P=Math.round(g/l());P!==0&&(this._shouldForwardWheelToApp({shiftKey:!1})?this._forwardScrollToApp(h,f,P):this._maybePageCliTranscript({shiftKey:!1},P)||(this.terminal.scrollLines(P),this._maybeLoadMoreHistoryOnScroll(P))),g*=.92,b=requestAnimationFrame(L)}else C?b=requestAnimationFrame(L):(b=null,g=0)};let I=0,k=!1,x=null,F=0,O=0,B=0,S=!1,T=null;const A=window.CodemanTerminalInput.MOBILE_KEYBOARD_DISMISS_TAP_SLOP;i.addEventListener("touchstart",M=>{if(!M.target?.closest?.(".term-select-bar")&&(M.touches.length!==1&&(clearTimeout(x),x=null),M.touches.length===1)){h=M.touches[0].clientX,f=M.touches[0].clientY,B=f,g=0,I=0,C=!0,k=!1,S=this._isMobileTerminalInputFocused();const R=this._classifyMobileTerminalTap(h,f);T={x:h,y:f,intent:R},R==="content"&&(M.preventDefault(),this._blurMobileTerminalInput()),F=h,O=f,clearTimeout(x),x=setTimeout(()=>{x=null,this._beginTouchSelection(F,O)},window.CodemanTerminalInput.TOUCH_SELECT_LONG_PRESS_MS),_=0,b&&(cancelAnimationFrame(b),b=null)}},{passive:!1}),i.addEventListener("touchmove",M=>{if(this._touchSelecting){M.preventDefault();const R=M.touches[0];R&&this._extendTouchSelection(R.clientX,R.clientY);return}if(x&&M.touches.length===1){const R=M.touches[0];(Math.abs(R.clientX-F)>A||Math.abs(R.clientY-O)>A)&&(clearTimeout(x),x=null)}if(M.touches.length===1&&C){const R=M.touches[0].clientY;if(!k&&Math.abs(R-B)>=A&&(k=!0),!k)return;M.preventDefault();const P=f-R;I+=P,g=P*1.2,h=M.touches[0].clientX,f=R;const N=l(),D=Math.trunc(I/N);D!==0&&(this._shouldForwardWheelToApp({shiftKey:!1})?(this._logScrollRouting("forward-sgr"),this._forwardScrollToApp(h,f,D)):this._maybePageCliTranscript({shiftKey:!1},D)||(this._logScrollRouting("local-scrollback"),this._noteTerminalUserScroll(D),this.terminal.scrollLines(D),this._maybeLoadMoreHistoryOnScroll(D)),I-=D*N)}},{passive:!1}),i.addEventListener("touchend",M=>{if(!M.target?.closest?.(".term-select-bar")){if(clearTimeout(x),x=null,C=!1,this._touchSelecting){M.preventDefault(),g=0,this._endTouchSelectionGesture(),S=!1;return}if(!b&&Math.abs(g)>.3&&(b=requestAnimationFrame(L)),!k&&this.terminal){const R=M.changedTouches&&M.changedTouches[0];if(R){this._suppressTrustedTapMouseEvents();const P=T&&T.x===R.clientX&&T.y===R.clientY?T.intent:null;this._handleMobileTerminalTap(R,S,P)}}S=!1}},{passive:!1}),i.addEventListener("contextmenu",M=>{(x!==null||this._touchSelecting||this._touchSelectionActive)&&M.preventDefault()}),i.addEventListener("touchcancel",()=>{clearTimeout(x),x=null,C=!1,this._touchSelecting=!1,g=0,I=0,S=!1},{passive:!0})}i.addEventListener("click",l=>this._handleDesktopTerminalClick(l)),this._installMobileKeyboardDismiss(),this.showWelcome(),this.initImageInput(),this._chunkedWriteGen=0,this._bufferLoadSeq=0,this._bufferLoadOwner=null,this._lastUserScrollUpAt=null,this._resizeTimeout=null,this._lastResizeDims=null;const p=40,v=10,E=()=>{this._tabRailResizeOwnsObserver||(this._resizeTimeout&&clearTimeout(this._resizeTimeout),this._resizeTimeout=setTimeout(()=>{this._resizeTimeout=null,this.fitAddon&&this.fitAddon.fit(),this.flickerFilterBuffer&&(this.flickerFilterTimeout&&(clearTimeout(this.flickerFilterTimeout),this.flickerFilterTimeout=null),this.flushFlickerBuffer());const l=typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible,h=!this.isSoloWindow&&this.detachedSessions?.has(this.activeSessionId);if(this.activeSessionId&&!l&&!h){const f=this.fitAddon.proposeDimensions(),g=f?Math.max(f.cols,p):p,_=f?Math.max(f.rows,v):v;if(!this._lastResizeDims||g!==this._lastResizeDims.cols||_!==this._lastResizeDims.rows){const b=this.activeSessionId?this.sessions.get(this.activeSessionId):null;b&&b.mode!=="shell"&&this.terminal&&this.isTerminalAtBottom()&&this.terminal.write("\x1B[3J\x1B[H\x1B[2J"),this._lastResizeDims={cols:g,rows:_};const C=typeof MobileDetection<"u"&&MobileDetection.getDeviceType?MobileDetection.getDeviceType():"desktop";let L=!1;if(this._wsReady&&this._wsSessionId===this.activeSessionId)try{this._ws.send(JSON.stringify({t:"z",c:g,r:_,v:C})),L=!0}catch{}L||fetch(`/api/sessions/${this.activeSessionId}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cols:g,rows:_,viewportType:C})}).catch(()=>{})}}this.applyLineageLineSettings?.(),this.updateConnectionLines(),this._localEchoOverlay?.hasPending&&this._localEchoOverlay.rerender()},300))};window.addEventListener("resize",E),this.terminalResizeObserver&&this.terminalResizeObserver.disconnect(),this.terminalResizeObserver=new ResizeObserver(E),this.terminalResizeObserver.observe(i),this._pendingInput="",this._inputFlushTimeout=null,this._lastKeystrokeTime=0;const y=()=>{if(this._inputFlushTimeout=null,this._pendingInput&&this.activeSessionId){const l=this._pendingInput,h=this.activeSessionId;this._pendingInput="",this._sendInputAsync(h,l)}},w=l=>{if(!/^\x1b\[<\d+;\d+;\d+[Mm]$/.test(l)&&(window.cjkActive||document.activeElement?.id==="cjkInput")){const f=document.getElementById("cjkInput");f?.classList.contains("cjk-input-visible")&&document.activeElement===this.terminal.textarea&&!window.CodemanTerminalInput?.shouldSuppressTerminalQueryResponse(l)&&(_crashDiag.log("CJK regain-focus (onData swallowed input)"),f.focus());return}if(this.activeSessionId){if(window.CodemanTerminalInput?.shouldSuppressTerminalQueryResponse(l))return;typeof KeyboardAccessoryBar<"u"&&KeyboardAccessoryBar.isCtrlArmed?.()&&!window.CodemanTerminalInput?.isTerminalFocusOrMouseReport(l)&&(l=KeyboardAccessoryBar.consumeCtrl(l)),this._lastTerminalData={data:l,time:performance.now()};const f=this._localEchoEnabled&&this._echoPassthroughSessions?.has(this.activeSessionId);if(f&&(l==="\r"||l==="")&&this._echoPassthroughSessions.delete(this.activeSessionId),this._localEchoEnabled&&!f){if(l==="\x7F"){const _=this._localEchoOverlay?.removeChar();if(_==="flushed"){const{count:b,text:C}=this._localEchoOverlay.getFlushed();this._flushedOffsets?.has(this.activeSessionId)&&(b===0?(this._flushedOffsets.delete(this.activeSessionId),this._flushedTexts?.delete(this.activeSessionId)):(this._flushedOffsets.set(this.activeSessionId,b),this._flushedTexts?.set(this.activeSessionId,C))),this._pendingInput+=l,y()}else _===!1&&(this._pendingInput+=l,y());return}if(/^[\r\n]+$/.test(l)){const _=this._localEchoOverlay?.pendingText||"";this._localEchoOverlay?.clear(),this._localEchoOverlay?.suppressBufferDetection(),this._flushedOffsets?.delete(this.activeSessionId),this._flushedTexts?.delete(this.activeSessionId),this._inputFlushTimeout&&(clearTimeout(this._inputFlushTimeout),this._inputFlushTimeout=null),_&&(this._pendingInput+=_,y()),setTimeout(()=>{this._pendingInput+="\r",y()},80);return}if(l.length>1&&l.charCodeAt(0)>=32){this._localEchoOverlay?.appendText(l);return}if(l.charCodeAt(0)<32){if(l.length>1&&l.charCodeAt(0)===27){if(l.startsWith(window.CodemanTerminalInput.BRACKETED_PASTE_START)){const b=!!this._localEchoOverlay?.pendingText;this._flushLocalEchoPending(),b?(y(),setTimeout(()=>{this._pendingInput+=l,y()},80)):(this._pendingInput+=l,y());return}if(window.CodemanTerminalInput.isComposerNavKey(l)){this._flushLocalEchoPending(),this._echoPassthroughSessions||(this._echoPassthroughSessions=new Set),this._echoPassthroughSessions.add(this.activeSessionId),this._pendingInput+=l,y();return}this._pendingInput+=l,y();return}if(this._restoringFlushedState){this._pendingInput+=l,y();return}if(l===" "){const b=this._localEchoOverlay?.pendingText||"";this._localEchoOverlay?.clear(),this._flushedOffsets?.delete(this.activeSessionId),this._flushedTexts?.delete(this.activeSessionId),b&&(this._pendingInput+=b),this._pendingInput+=l,this._inputFlushTimeout&&(clearTimeout(this._inputFlushTimeout),this._inputFlushTimeout=null);let C="";try{const I=this._localEchoOverlay?.findPrompt?.();if(I){const k=this.terminal.buffer.active,x=k.getLine(k.viewportY+I.row);x&&(C=x.translateToString(!0).slice(I.col+2).trimEnd())}}catch{}this._tabCompletionBaseText=C,y(),this._tabCompletionSessionId=this.activeSessionId,this._tabCompletionRetries=0,this._tabCompletionFallback&&clearTimeout(this._tabCompletionFallback);const L=this;this._tabCompletionFallback=setTimeout(()=>{if(L._tabCompletionFallback=null,!L._tabCompletionSessionId||L._tabCompletionSessionId!==L.activeSessionId)return;const I=L._localEchoOverlay;!I||I.pendingText||L.terminal.write("",()=>{if(!L._tabCompletionSessionId)return;I.resetBufferDetection();const k=I.detectBufferText();k&&k!==L._tabCompletionBaseText&&(L._tabCompletionSessionId=null,L._tabCompletionRetries=0,L._tabCompletionBaseText=null,I.rerender())})},300);return}const _=this._localEchoOverlay?.pendingText||"";this._localEchoOverlay?.clear(),this._localEchoOverlay?.suppressBufferDetection(),this._flushedOffsets?.delete(this.activeSessionId),this._flushedTexts?.delete(this.activeSessionId),_&&(this._pendingInput+=_),this._pendingInput+=l,this._inputFlushTimeout&&(clearTimeout(this._inputFlushTimeout),this._inputFlushTimeout=null),y();return}if(l.length===1&&l.charCodeAt(0)>=32){this._localEchoOverlay?.addChar(l);return}}if(this._predictHookOnData(l),this._pendingInput+=l,l.charCodeAt(0)<32||l.length>1){this._inputFlushTimeout&&(clearTimeout(this._inputFlushTimeout),this._inputFlushTimeout=null),y();return}const g=performance.now();g-this._lastKeystrokeTime>50?(this._inputFlushTimeout&&(clearTimeout(this._inputFlushTimeout),this._inputFlushTimeout=null),this._lastKeystrokeTime=g,y()):(this._lastKeystrokeTime=g,this._inputFlushTimeout||(this._inputFlushTimeout=setTimeout(y,0)))}};try{this._keyCode229Recovery=window.CodemanKeyCode229Recovery?.create?.({textarea:this.terminal.textarea,emitRecovered:l=>w(l),isScreenReaderMode:()=>this.terminal?.options?.screenReaderMode===!0})}catch{this._keyCode229Recovery=null}this.terminal.onData(l=>{try{const h=window.CodemanTerminalInput;!h?.shouldSuppressTerminalQueryResponse(l)&&!h?.isTerminalFocusOrMouseReport(l)&&this._keyCode229Recovery?.notifyCanonicalData?.()}catch{}w(l)})},registerFilePathLinkProvider(){const e=this;let t=-1;const i={provideLinks(s,n){s!==t&&(t=s,console.debug("[LinkProvider] Checking line:",s));const o=e.terminal.buffer.active;if(!o.getLine(s-1)){n(void 0);return}const d=window.CodemanTerminalLines?.terminalLogicalLine(o,s-1,e.terminal.cols,12);if(!d){n(void 0);return}const u=d.text,m=f=>{const g=d.offsetToCell(f);return{x:g.col+1,y:g.row+1}};if(!u||!u.includes("/")){n(void 0);return}const c=[],p=/https?:\/\/(?:[^\s"'<>|;&)\]\x00-\x1f]|&(?!&))+/g,v=(f,g)=>{const _=f.replace(/[.,;:!?)&]+$/,""),b=u.indexOf(_,g);if(b===-1)return;const C=m(b),L=m(b+_.length);c.some(I=>I.range.start.x===C.x&&I.range.start.y===C.y)||c.push({text:_,range:{start:C,end:L},decorations:{pointerCursor:!0,underline:!0},activate(I,k){e.openLinkThroughWebTabIfLoopback?.(k)||window.open(k,"_blank","noopener,noreferrer")},hover(){e._linkHovered=!0},leave(){e._linkHovered=!1}})},E=/\b(tail|cat|head|less|grep|watch|vim|nano)\s+(?:[^\s\/]+\s+){0,4}(\/[^\s"'<>|;&\n\x00-\x1f]+)/g,y=absoluteFilePathPattern(),w=/Bash\([^)]*?(\/(?:home|tmp|var|etc|opt)[^\s"'<>|;&\)\n\x00-\x1f]+)/g,l=(f,g)=>{const _=u.indexOf(f,g);if(_===-1)return;const b=m(_),C=m(_+f.length);c.some(L=>L.range.start.x===b.x&&L.range.start.y===b.y)||c.push({text:f,range:{start:b,end:C},decorations:{pointerCursor:!0,underline:!0},activate(L,I){if(previewsInFileViewer(I)||e._isExternalPreviewPath(I,e.activeSessionId)){e.openFilePreview(I,e.activeSessionId);return}e.openLogViewerWindow(I,e.activeSessionId)},hover(){e._linkHovered=!0},leave(){e._linkHovered=!1}})};let h;for(p.lastIndex=0;(h=p.exec(u))!==null;)v(h[0],h.index);for(E.lastIndex=0;(h=E.exec(u))!==null;)l(h[2],h.index);for(y.lastIndex=0;(h=y.exec(u))!==null;)l(h[1],h.index);for(w.lastIndex=0;(h=w.exec(u))!==null;)l(h[1],h.index);c.length>0&&console.debug("[LinkProvider] Found links:",c.map(f=>f.text)),n(c.length>0?c:void 0)}};this._terminalLinkProvider=i,this.terminal.registerLinkProvider(i),console.log("[LinkProvider] File path link provider registered")},_terminalLinkAtPoint(e,t){const i=this._terminalLinkProvider,s=this.terminal?.buffer?.active;if(!i||!s)return null;const n=this._clientPointToCell(e,t);if(!n)return null;const o=(s.viewportY||0)+n.row;let r=null;try{i.provideLinks(o,u=>{r=u||[]})}catch{return null}if(!r||r.length===0)return null;const a=Math.max(1,this.terminal.cols||1),d=o*a+n.col;return r.find(u=>{const m=u?.range?.start,c=u?.range?.end;return!m||!c?!1:m.y*a+m.x<=d&&d<=c.y*a+c.x})||null},_tapIsOnCaretLine(e,t){const i=this.terminal?.buffer?.active;if(!i?.getLine)return!1;const s=this._clientPointToCell(e,t);if(!s)return!1;const n=Math.max(1,this.terminal.rows||1),o=Math.max(0,Math.min(n-1,i.cursorY||0)),r=s.row-1;if(r===o)return!0;let a=o;for(;a>0&&i.getLine(i.viewportY+a)?.isWrapped;)a--;let d=o;for(;d+1<n&&i.getLine(i.viewportY+d+1)?.isWrapped;)d++;return r>=a&&r<=d},_activateTerminalLinkAtPoint(e,t){const i=this._terminalLinkAtPoint(e,t);if(!i||typeof i.activate!="function")return!1;try{i.activate(null,i.text)}catch(s){return console.warn("[LinkProvider] tap activation failed:",s),!1}return!0},_installTouchSelectionFocusGuard(){const e=this.terminal?.textarea;!e||e._codemanSelectionFocusGuard||(e._codemanSelectionFocusGuard=!0,e.addEventListener("focus",()=>{this._touchSelectionFocusGuarded()&&this._blurMobileTerminalInput()}))},_touchSelectionFocusGuarded(){return this._touchSelecting?!0:performance.now()<(this._touchSelectionFocusGuardUntil||0)},_armTouchSelectionFocusGuard(){this._touchSelectionFocusGuardUntil=performance.now()+(window.CodemanTerminalInput?.TOUCH_SELECT_FOCUS_GUARD_MS||800)},_touchSelectionCellAt(e,t){const i=this._clientPointToCell(e,t),s=this.terminal?.buffer?.active;return!i||!s?null:{col:i.col-1,row:(s.viewportY||0)+i.row-1}},_touchSelectionLogicalLine(e){const t=this.terminal?.buffer?.active,i=Math.max(1,this.terminal?.cols||1);return!t||typeof window.CodemanTerminalLines?.terminalLogicalLine!="function"?null:window.CodemanTerminalLines.terminalLogicalLine(t,e,i)},_touchSelectionWordAt(e){const t=Math.max(1,this.terminal?.cols||1),i=this._touchSelectionLogicalLine(e.row);if(!i)return null;const s=i.cellToOffset(e.row,e.col);if(s<0)return null;const n=i.text[s];if(!n||!n.trim())return null;let o=s;for(;o>0&&i.text[o-1]&&i.text[o-1].trim();)o--;let r=s;for(;r+1<i.text.length&&i.text[r+1]&&i.text[r+1].trim();)r++;const a=i.offsetToCell(o),d=i.offsetToCell(r),u=a.row*t+a.col,m=d.row*t+d.col-u+1;return m>0?{index:u,length:m}:null},_applyTouchSelection(e,t){const i=Math.max(1,this.terminal?.cols||1);t<=0||this.terminal?.select?.(e%i,Math.floor(e/i),t)},_beginTouchSelection(e,t){const i=this._touchSelectionCellAt(e,t);if(!i)return!1;const s=this._touchSelectionWordAt(i);if(!s)return!1;this._blurMobileTerminalInput(),this._touchSelectionAnchor=s,this._touchSelecting=!0,this._touchSelectionActive=!0,this._suppressTrustedTapMouseEvents(),this._armTouchSelectionFocusGuard(),this._applyTouchSelection(s.index,s.length);try{navigator.vibrate?.(15)}catch{}return this._showTouchSelectionBar(),!0},_extendTouchSelection(e,t){const i=this._touchSelectionAnchor,s=this._touchSelectionCellAt(e,t);if(!i||!s)return;const n=Math.max(1,this.terminal?.cols||1),o=s.row*n+s.col,r=Math.min(i.index,o),a=Math.max(i.index+i.length,o+1);this._applyTouchSelection(r,a-r),this._armTouchSelectionFocusGuard(),this._positionTouchSelectionBar()},_endTouchSelectionGesture(){this._touchSelecting=!1,this._suppressTrustedTapMouseEvents(),this._armTouchSelectionFocusGuard(),this._positionTouchSelectionBar(),this._flushAutoCopySelection()},_selectTouchSelectionLine(){const e=this._touchSelectionAnchor,t=Math.max(1,this.terminal?.cols||1);if(!e)return;const i=this._touchSelectionLogicalLine(Math.floor(e.index/t));if(!i)return;const n=(this.terminal?.buffer?.active?.getLine(i.endRow)?.translateToString(!0)||"").length,o=i.startRow*t,r=i.endRow*t+Math.max(0,n-1)-o+1;r<=0||(this._touchSelectionAnchor={index:o,length:r},this._applyTouchSelection(o,r),this._positionTouchSelectionBar(),this._flushAutoCopySelection())},async _copyTouchSelection(){const e=await this.copyTerminalSelection();return this._clearTouchSelection(),typeof MobileDetection<"u"&&MobileDetection.isTouchDevice?.()&&this._blurMobileTerminalInput(),e},_clearTouchSelection(){this._touchSelecting=!1,this._touchSelectionActive=!1,this._touchSelectionAnchor=null,this.terminal?.clearSelection?.(),this._hideTouchSelectionBar()},_ensureTouchSelectionBar(){if(this._touchSelectionBar?.isConnected)return this._touchSelectionBar;const e=document.getElementById("terminalContainer");if(!e)return null;const t=document.createElement("div");return t.className="term-select-bar",t.setAttribute("role","toolbar"),t.innerHTML='<button type="button" class="term-select-btn" data-act="copy">Copy</button><button type="button" class="term-select-btn" data-act="line">Line</button><button type="button" class="term-select-btn term-select-btn--close" data-act="close" aria-label="Clear selection">\u2715</button>',t.addEventListener("click",i=>{const s=i.target?.closest?.("[data-act]")?.dataset?.act;s&&(i.preventDefault(),i.stopPropagation(),s==="copy"?this._copyTouchSelection():s==="line"?this._selectTouchSelectionLine():this._clearTouchSelection())}),e.appendChild(t),this._touchSelectionBar=t,t},_showTouchSelectionBar(){const e=this._ensureTouchSelectionBar();e&&(e.classList.add("visible"),this._positionTouchSelectionBar())},_hideTouchSelectionBar(){this._touchSelectionBar?.classList.remove("visible")},_positionTouchSelectionBar(){const e=this._touchSelectionBar,t=document.getElementById("terminalContainer"),i=this.terminal?.element?.querySelector(".xterm-screen"),s=this.terminal?._core?._renderService?.dimensions?.css?.cell,n=this.terminal?.getSelectionPosition?.(),o=this.terminal?.buffer?.active;if(!e||!t||!i||!s?.height||!n||!o)return;const r=i.getBoundingClientRect(),a=t.getBoundingClientRect(),d=w=>w-(o.viewportY||0),u=r.top-a.top+d(n.start.y)*s.height,m=r.top-a.top+(d(n.end.y)+1)*s.height,c=e.offsetHeight||36,p=6;let v=u-c-p;v<0&&(v=m+p),v=Math.max(0,Math.min(v,a.height-c));const E=r.left-a.left+n.start.x*(s.width||8),y=e.offsetWidth||150;e.style.top=`${Math.round(v)}px`,e.style.left=`${Math.round(Math.max(0,Math.min(E,a.width-y)))}px`},showWelcome(){if(this.shouldUseMobileOverview?.()){const t=document.getElementById("welcomeOverlay");t&&t.classList.remove("visible"),this.hideHomeSessions?.(),this.showMobileOverview(),this._updateCjkInputState?.();return}this.hideMobileOverview?.();const e=document.getElementById("welcomeOverlay");e&&(e.classList.add("visible"),this.loadTunnelStatus(),this.applyWelcomeCliVisibility(),this.loadHistorySessions(),this.initSearchPanel(),this.showHomeSessions?.()),this._updateCjkInputState?.()},hideWelcome(){this.hideMobileOverview?.(),this.hideHomeSessions?.();const e=document.getElementById("welcomeOverlay");e&&e.classList.remove("visible");const t=document.getElementById("welcomeQr");t&&(clearTimeout(this._welcomeQrShrinkTimer),t.classList.remove("expanded")),this._updateCjkInputState?.()},async _fetchHistorySessions(){const i=(await(await fetch("/api/history/sessions")).json()).data?.sessions||[];if(i.length===0)return[];const s=new Map;for(const o of i){const r=o.projectKey||o.workingDir;s.has(r)||s.set(r,[]),s.get(r).push(o)}const n=[];for(const[,o]of s)n.push(...o.slice(0,3));return n.sort((o,r)=>new Date(r.lastModified)-new Date(o.lastModified)),n},async _fetchUnifiedSessions(e=60){const t=await fetch("/api/sessions/unified?limit="+e),i=await t.json().catch(()=>null);if(!t.ok||!i||i.success===!1||!i.data)throw new Error(i?.error||`unified sessions request failed (HTTP ${t.status})`);return i.data.sessions||[]},_worktreeLabel(e){const t=e&&e.worktreeName;if(!t)return"";let i=e.gitBranch||"";return(i===t||i===`worktree-${t}`)&&(i=""),i.length>24&&(i=i.slice(0,23)+"\u2026"),"\u2442 "+[t,i].filter(Boolean).join(" \xB7 ")},_resolveCaseLabel(e,t){if(!e)return"";let i=null;for(const s of t||[])if(!(!s||!s.path)){if(e===s.path)return`#${s.name}`;if(e.startsWith(s.path+"/")){const n=s.path.length;(!i||n>i.len)&&(i={name:s.name,suffix:e.slice(n),len:n})}}return i?`#${i.name}${i.suffix}`:e.split("/").pop()||e},_shortenHomePath(e){return(e||"").replace(/^\/(?:home|Users)\/[^/]+(?=\/|$)/,"~")},_buildHistoryItem(e,t,i){const s=i?.showViewAll!==!1,n=typeof e.sizeBytes=="number",o=n?e.sizeBytes<1024?`${e.sizeBytes}B`:e.sizeBytes<1048576?`${(e.sizeBytes/1024).toFixed(0)}K`:`${(e.sizeBytes/1048576).toFixed(1)}M`:"",r=typeof e.lastActivityAt=="number"?e.lastActivityAt:e.lastModified?Date.parse(e.lastModified):NaN;let a="";if(!Number.isNaN(r)){const S=new Date(r);a=S.toLocaleDateString("en",{month:"short",day:"numeric"})+" "+S.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit",hour12:!1})}const d=this._shortenHomePath(e.workingDir),u=this._resolveCaseLabel(e.workingDir,t),m=Array.isArray(e.sources)&&e.sources.includes("live"),c=e.pinned===!0,p=document.createElement("div");p.className="history-item"+(c?" is-pinned":""),p.title=e.workingDir||"";const v=document.createElement("div");v.className="history-item-main",v.addEventListener("click",i?.onActivate||(()=>{m&&this.sessions.has(e.sessionId)?this.selectSession(e.sessionId):this.resumeHistorySession(e.claudeSessionId||e.sessionId,e.workingDir||"",e.name,e.mode,e.resumeId)}));const E=document.createElement("div");E.className="history-item-text";const y=document.createElement("span");if(y.className="history-item-title",c){const S=document.createElement("span");S.className="history-item-pin",S.textContent="\u{1F4CC}",S.setAttribute("aria-label","Pinned"),S.title="Pinned",y.appendChild(S)}y.appendChild(document.createTextNode(this._historyRowLabel(e,d)));const w=document.createElement("div");if(w.className="history-item-badges",e.mode){const S=document.createElement("span");S.className="history-item-badge history-item-badge-mode",S.textContent=e.mode,w.appendChild(S)}const l=this._worktreeLabel(e);if(l){const S=document.createElement("span");S.className="history-item-badge history-item-badge-worktree",S.textContent=l,S.title=e.worktreeRepo?`worktree of ${e.worktreeRepo}`:l,w.appendChild(S)}if(m){const S=document.createElement("span");S.className="history-item-badge history-item-badge-live",S.textContent="LIVE",w.appendChild(S)}const h=document.createElement("span");h.className="history-item-subtitle",u.startsWith("#")&&h.classList.add("is-case"),h.textContent=u,E.append(y),w.childElementCount>0&&E.append(w),E.append(h);const f=document.createElement("span");f.className="history-item-meta",f.textContent=a;const g=document.createElement("button");g.className="history-item-expand",g.type="button",g.setAttribute("aria-haspopup","menu"),g.setAttribute("aria-label","Session actions"),g.setAttribute("aria-expanded","false"),g.textContent="\u22EF",v.append(E,f,g);const _=document.createElement("div");_.className="history-item-detail",_.hidden=!0;const b=document.createElement("div");b.className="history-detail-row";const C=document.createElement("span");C.className="history-detail-label",C.textContent="Prompt";const L=document.createElement("span");L.className="history-detail-value history-detail-prompt",L.textContent=e.firstPrompt||"(no prompt captured)",b.append(C,L);let I=null;if(e.lastPrompt&&e.lastPrompt!==e.firstPrompt){I=document.createElement("div"),I.className="history-detail-row";const S=document.createElement("span");S.className="history-detail-label",S.textContent="Last prompt";const T=document.createElement("span");T.className="history-detail-value history-detail-prompt",T.textContent=e.lastPrompt,I.append(S,T)}const k=document.createElement("div");k.className="history-detail-row";const x=document.createElement("span");x.className="history-detail-label",x.textContent="Path";const F=document.createElement("span");F.className="history-detail-value history-detail-path",F.textContent=d,k.append(x,F);const O=document.createElement("div");O.className="history-detail-row history-detail-meta";const B=[];if(a&&B.push(a),n&&B.push(o),B.push(e.sessionId.slice(0,8)),O.textContent=B.join(" \xB7 "),_.append(b),I&&_.append(I),_.append(k,O),s&&e.projectKey){const S=document.createElement("div");S.className="history-detail-row history-detail-actions";const T=document.createElement("button");T.type="button",T.className="history-view-all-btn",T.textContent="View all in this folder",T.addEventListener("click",A=>{A.stopPropagation(),this.openFolderHistoryModal(e.projectKey,e.workingDir,t)}),S.appendChild(T),_.appendChild(S)}return g.addEventListener("click",S=>{S.stopPropagation(),S.preventDefault(),this._openSessionRowMenu(S.currentTarget,e,t,p,_)}),p.append(v,_),p},_openSessionRowMenu(e,t,i,s,n){if(this._openRowMenuClose)try{this._openRowMenuClose()}catch{}const o=Array.isArray(t.sources)&&t.sources.includes("live")&&this.sessions.has(t.sessionId),r=document.createElement("div");r.className="session-row-menu",r.setAttribute("role","menu");let a=null,d=null,u=null;const m=()=>{document.removeEventListener("mousedown",a,!0),document.removeEventListener("keydown",d,!0),window.removeEventListener("scroll",u,!0),window.removeEventListener("resize",u,!0);try{r.remove()}catch{}this._openRowMenuEl===r&&(this._openRowMenuEl=null,this._openRowMenuClose=null)},c=(h,f,g)=>{const _=document.createElement("button");_.type="button",_.className="session-row-menu-item",_.setAttribute("role","menuitem");const b=document.createElement("span");if(b.className="session-row-menu-label",b.textContent=h,_.appendChild(b),g&&g.sublabel){const C=document.createElement("span");C.className="session-row-menu-sublabel",C.textContent=g.sublabel,_.appendChild(C)}_.addEventListener("click",async C=>{C.stopPropagation(),C.preventDefault(),await f()}),r.appendChild(_)};c(o?"Switch to session":"Resume session",()=>{o?this.selectSession(t.sessionId):this.resumeHistorySession(t.claudeSessionId||t.sessionId,t.workingDir||"",t.name,t.mode,t.resumeId),this.closeSessionManager?.(),m()});const p=t.pinned===!0;c(p?"Unpin session":"Pin to top",async()=>{await this._setSessionPinned(t.sessionId,!p)?(t.pinned=!p,this.showToast(p?"Unpinned":"Pinned to top","success")):this.showToast("Pin failed","error"),m()}),o&&c("Open folder",()=>{this.selectSession(t.sessionId),this.loadFileBrowser?.(t.sessionId),this.closeSessionManager?.(),m()}),t.workingDir&&c("Copy path",async()=>{const h=await this._copyText(t.workingDir);this.showToast(h?"Path copied":"Copy failed",h?"success":"error"),m()}),c("Show details",()=>{const h=s.classList.toggle("expanded");n.hidden=!h,e.setAttribute("aria-expanded",h?"true":"false"),m()}),document.body.appendChild(r);const v=e.getBoundingClientRect(),E=r.getBoundingClientRect(),y=4;let w=v.bottom+y;w+E.height>window.innerHeight&&v.top-y-E.height>=0&&(w=v.top-y-E.height);let l=v.right-E.width;l<y&&(l=y),l+E.width>window.innerWidth-y&&(l=Math.max(y,window.innerWidth-y-E.width)),r.style.top=`${Math.max(y,w)}px`,r.style.left=`${l}px`,a=h=>{r.contains(h.target)||e.contains(h.target)||m()},d=h=>{h.key==="Escape"&&(h.stopPropagation(),m())},u=()=>m(),document.addEventListener("mousedown",a,!0),document.addEventListener("keydown",d,!0),window.addEventListener("scroll",u,!0),window.addEventListener("resize",u,!0),this._openRowMenuEl=r,this._openRowMenuClose=m},async _setSessionPinned(e,t){try{const i=await fetch(`/api/sessions/${encodeURIComponent(e)}/pin`,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"same-origin",body:JSON.stringify({pinned:t})});return i.ok?(await i.json())?.success===!0:!1}catch(i){return console.error("[_setSessionPinned]",i),!1}},_HISTORY_INITIAL_COUNT:10,_HISTORY_FETCH_LIMIT:200,_HISTORY_SORT_KEY:"codeman:historySort",async loadHistorySessions(){const e=document.getElementById("historySessions"),t=document.getElementById("historyList");if(!(!e||!t))try{const i=Array.isArray(this.cases)&&this.cases.length>0?Promise.resolve(this.cases):fetch("/api/cases").then(o=>o.ok?o.json():null).then(o=>o?.data||[]).catch(()=>[]),[s,n]=await Promise.all([this._fetchUnifiedSessions(this._HISTORY_FETCH_LIMIT),i]);if(s.length===0){e.style.display="none";return}this._historyAll=s,this._historyCases=n,this._wireHistoryControls(),this._renderHistoryList(),e.style.display=""}catch(i){console.error("[loadHistorySessions]",i),e.style.display="none"}},_wireHistoryControls(){if(this._historyControlsWired)return;const e=document.getElementById("historyFilter"),t=document.getElementById("historySort");if(!(!e&&!t)){if(this._historyControlsWired=!0,t)try{const i=localStorage.getItem(this._HISTORY_SORT_KEY);i&&Array.from(t.options).some(s=>s.value===i)&&(t.value=i)}catch{}e&&(e.addEventListener("input",()=>this._renderHistoryList()),e.addEventListener("keydown",i=>{i.key==="Escape"&&e.value&&(i.stopPropagation(),e.value="",this._renderHistoryList())})),t&&t.addEventListener("change",()=>{try{localStorage.setItem(this._HISTORY_SORT_KEY,t.value)}catch{}this._renderHistoryList()})}},_historyRowMatches(e,t,i){return[e.name,e.workingDir,this._resolveCaseLabel(e.workingDir,i),e.firstPrompt,e.lastPrompt,e.sessionId].some(n=>typeof n=="string"&&n.toLowerCase().includes(t))},_historyRowLabel(e,t){return e.name||e.firstPrompt||t||""},_sortHistoryRows(e,t){const n=t==="name"?a=>this._historyRowLabel(a,this._shortenHomePath(a.workingDir)).toLowerCase():a=>((a.workingDir||"").split("/").pop()||"").toLowerCase(),o=t==="recent"?e.slice():e.slice().sort((a,d)=>n(a).localeCompare(n(d),void 0,{sensitivity:"base",numeric:!0})),r=o.filter(a=>a.pinned);return r.length===0?o:r.concat(o.filter(a=>!a.pinned))},_renderHistoryList(){const e=document.getElementById("historyList");if(!e)return;const t=this._historyAll||[],i=this._historyCases||[],s=document.getElementById("historyCount"),n=(document.getElementById("historyFilter")?.value||"").trim().toLowerCase(),o=document.getElementById("historySort")?.value||"recent",r=n?t.filter(c=>this._historyRowMatches(c,n,i)):t,a=this._sortHistoryRows(r,o),d=!!this._historyExpanded||n.length>0,u=d?a:a.slice(0,this._HISTORY_INITIAL_COUNT);if(e.replaceChildren(),e.classList.toggle("expanded",d),a.length===0){const c=document.createElement("div");c.className="history-empty",c.textContent=`No conversations match "${n}"`,e.appendChild(c)}for(const c of u)e.appendChild(this._buildHistoryItem(c,i));const m=a.length-u.length;if(m>0){const c=document.createElement("button");c.className="history-show-more",c.textContent=`Show ${m} more`,c.addEventListener("click",()=>{this._historyExpanded=!0,this._renderHistoryList()}),e.appendChild(c)}else if(d&&!n&&a.length>this._HISTORY_INITIAL_COUNT){const c=document.createElement("button");c.className="history-show-more",c.textContent="Show less",c.addEventListener("click",()=>{this._historyExpanded=!1,this._renderHistoryList(),e.scrollTop=0}),e.appendChild(c)}s&&(s.textContent=n?`${a.length} of ${t.length}`:a.length>u.length?`${u.length} of ${a.length}`:String(a.length))},_FOLDER_HISTORY_PAGE_SIZE:20,openFolderHistoryModal(e,t,i){this._closeFolderHistoryModal();const s=document.createElement("div");s.className="modal active folder-history-modal",s.id="folderHistoryModal";const n=document.createElement("div");n.className="modal-backdrop",n.addEventListener("click",()=>this._closeFolderHistoryModal());const o=document.createElement("div");o.className="modal-content modal-lg";const r=document.createElement("div");r.className="modal-header";const a=document.createElement("h3");a.textContent="Folder History";const d=document.createElement("div");d.className="folder-history-subtitle",d.textContent=this._shortenHomePath(t);const u=document.createElement("button");u.className="modal-close",u.setAttribute("aria-label","Close"),u.innerHTML="&times;",u.addEventListener("click",()=>this._closeFolderHistoryModal()),r.append(a,u);const m=document.createElement("div");m.className="modal-body";const c=document.createElement("div");c.className="folder-history-list",c.setAttribute("data-loading","true"),c.textContent="Loading...",m.append(d,c),o.append(r,m),s.append(n,o),document.body.appendChild(s),this._folderHistoryState={projectKey:e,workingDir:t,cases:i||[],offset:0,total:null,list:c},this._folderHistoryEscHandler=p=>{p.key==="Escape"&&this._closeFolderHistoryModal()},document.addEventListener("keydown",this._folderHistoryEscHandler),this._loadFolderHistoryPage()},async _loadFolderHistoryPage(){const e=this._folderHistoryState;if(!e)return;const{projectKey:t,cases:i,list:s}=e,n=this._FOLDER_HISTORY_PAGE_SIZE,o=e.offset,r=s.querySelector(".folder-history-more");r&&r.remove(),o===0&&(s.replaceChildren(),s.removeAttribute("data-loading"));try{const a=`/api/history/sessions?projectKey=${encodeURIComponent(t)}&offset=${o}&limit=${n}`,u=await(await fetch(a)).json(),m=u.data?.sessions||[];if(e.total=typeof u.data?.total=="number"?u.data.total:m.length+o,o===0&&m.length===0){const c=document.createElement("div");c.className="folder-history-empty",c.textContent="No conversations found in this folder.",s.appendChild(c);return}for(const c of m)s.appendChild(this._buildHistoryItem(c,i,{showViewAll:!1}));if(e.offset=o+m.length,e.offset<e.total){const c=e.total-e.offset,p=document.createElement("button");p.className="history-show-more folder-history-more",p.textContent=`Show ${Math.min(n,c)} more (${c} remaining)`,p.addEventListener("click",()=>this._loadFolderHistoryPage()),s.appendChild(p)}}catch(a){console.error("[loadFolderHistoryPage]",a);const d=document.createElement("div");d.className="folder-history-empty",d.textContent="Failed to load folder history.",s.appendChild(d)}},_closeFolderHistoryModal(){const e=document.getElementById("folderHistoryModal");e&&e.remove(),this._folderHistoryEscHandler&&(document.removeEventListener("keydown",this._folderHistoryEscHandler),this._folderHistoryEscHandler=null),this._folderHistoryState=null},_resolveResumeName(e,t){if(typeof e=="string"&&e.trim())return e;const i=(t||"").split("/").pop()||"session";let s=1;for(const[,n]of this.sessions){const o=n.name&&n.name.match(/^w(\d+)-/);if(o){const r=parseInt(o[1]);r>=s&&(s=r+1)}}return`w${s}-${i}`},async resumeHistorySession(e,t,i,s,n){document.getElementById("runModeMenu")?.classList.remove("active"),this._closeFolderHistoryModal();try{this.terminal.clear(),this.terminal.writeln(`\x1B[1;32m Resuming conversation ${e.slice(0,8)}...\x1B[0m`);const o=this._resolveResumeName(i,t),a=(this.cases||[]).find(f=>f.path===t)?.name||t.split("/").pop()||"",d=this.loadAppSettingsFromStorage(),u=this.buildEnvOverrides(this.getCaseSettings(a),d),m=this.getEffortSetting(d),c=s||"claude",p={opencode:"openCodeConfig",pi:"piConfig",grok:"grokConfig",omp:"ompConfig"}[c],v=c==="codex"?n:void 0,E=p?{[p]:{continueSession:!0}}:c==="deepseek"?{deepSeekConfig:{resumeSession:!0}}:v?{codexConfig:{resumeSessionId:v}}:{},y=!!p||c==="deepseek"||!!v,l=await(await fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workingDir:t,name:o,mode:c,...c==="claude"?{resumeSessionId:e}:{},...E,...Object.keys(u).length>0?{envOverrides:u}:{},...m?{effort:m}:{}})})).json();if(!l.success)throw new Error(l.error);const h=l.data.session.id;await fetch(`/api/sessions/${h}/interactive`,{method:"POST"}),c!=="claude"&&y&&e!==h&&fetch(`/api/sessions/${e}?killMux=true`,{method:"DELETE"}).catch(()=>{}),this.terminal.writeln(`\x1B[90m Session ${o} ready\x1B[0m`),await this.selectSession(h),this.terminal.focus()}catch(o){this.terminal.writeln(`\x1B[1;31m Error: ${o.message}\x1B[0m`)}},isTerminalAtBottom(){if(!this.terminal)return!0;const e=this.terminal.buffer.active;return e.viewportY>=e.baseY-2},_noteTerminalUserScroll(e){e<0?this._lastUserScrollUpAt=performance.now():this.isTerminalAtBottom()&&(this._lastUserScrollUpAt=null)},_maybeLoadMoreHistoryOnScroll(e){e>=0||this.terminal?.buffer?.active?.viewportY===0&&this._maybeRefetchFullHistory?.()},_estimateReplayRows(e,t){if(typeof e!="string"||!e)return 0;const i=t>0?t:80,s=e.replace(window.CodemanTerminalInput.REPLAY_ESCAPE_RE,"");let n=0;for(const o of s.split(`
2
+ `)){const r=o.endsWith("\r")?o.length-1:o.length;n+=r>i?Math.ceil(r/i):1}return n},_replayWouldShrinkBuffer(e){const t=this.terminal,i=t?.buffer?.active?.length||0;if(!i)return!1;const s=t?.rows||24;return this._estimateReplayRows(e,t?.cols)+s<i},_smoothScrollBy(e){if(!e||(this._smoothScrollPending=(this._smoothScrollPending||0)+e,this._smoothScrollSession=this.activeSessionId,this._smoothScrollFrame))return;const t=()=>{this._smoothScrollFrame=null;const i=this._smoothScrollPending||0;if(!i)return;if(this.activeSessionId!==this._smoothScrollSession){this._smoothScrollPending=0;return}if(Math.abs(i)<1)return;const s=i*.22,n=i>0?Math.max(1,Math.floor(s)):Math.min(-1,Math.ceil(s));this._smoothScrollPending=i-n,this.terminal.scrollLines(n),this._maybeLoadMoreHistoryOnScroll(n),Math.abs(this._smoothScrollPending)>=1&&(this._smoothScrollFrame=requestAnimationFrame(t))};this._smoothScrollFrame=requestAnimationFrame(t)},_forwardScrollToApp(e,t,i){this._terminalViewportAtBottom()||this.terminal.scrollToBottom(),this._sendSyntheticSgrWheel(e,t,i)},_hasRecentUserScrollUp(){return typeof this._lastUserScrollUpAt!="number"?!1:performance.now()-this._lastUserScrollUpAt<window.CodemanTerminalInput.USER_SCROLL_STICKY_SUPPRESS_MS},batchTerminalWrite(e){if(this._isLoadingBuffer){this._loadBufferQueue&&this._loadBufferQueue.push(e);return}if(this.writeFrameScheduled||(this._wasAtBottomBeforeWrite=this.isTerminalAtBottom()),(this.activeSessionId?this.sessions.get(this.activeSessionId):null)?.flickerFilterEnabled??!1){if(e.includes("\x1B[2J")||e.includes("\x1B[H\x1B[J")||e.includes("\x1B[H")&&e.includes("\x1B[?25l")){this.flickerFilterActive=!0,this.flickerFilterBuffer+=e,this.flickerFilterTimeout&&clearTimeout(this.flickerFilterTimeout),this.flickerFilterTimeout=setTimeout(()=>{this.flickerFilterTimeout=null,this.flushFlickerBuffer()},SYNC_WAIT_TIMEOUT_MS);return}if(this.flickerFilterActive){this.flickerFilterBuffer+=e;return}}this.pendingWrites.push(e),this._scheduleTerminalWriteFlush()},_scheduleTerminalWriteFlush(){this._terminalWriteInFlight||this.writeFrameScheduled||this.pendingWrites.length===0||(this.writeFrameScheduled=!0,this._safeYield(()=>{this.writeFrameScheduled=!1,this.flushPendingWrites()}))},flushFlickerBuffer(){this.flickerFilterBuffer&&(this.pendingWrites.push(this.flickerFilterBuffer),this.flickerFilterBuffer="",this.flickerFilterActive=!1,this._scheduleTerminalWriteFlush())},_flushLocalEchoPending(){const e=this._localEchoOverlay?.pendingText||"";this._localEchoOverlay?.clear(),this._localEchoOverlay?.suppressBufferDetection(),this._flushedOffsets?.delete(this.activeSessionId),this._flushedTexts?.delete(this.activeSessionId),e&&(this._pendingInput+=e)},_updateLocalEchoState(){const e=this.loadAppSettingsFromStorage(),t=this.activeSessionId?this.sessions.get(this.activeSessionId):null,i=e.localEchoEnabled??MobileDetection.isTouchDevice(),s=!!(i&&t);this._localEchoEnabled&&!s&&this._localEchoOverlay?.clear(),this._localEchoEnabled=s,this._localEchoOverlay&&t&&(t.mode==="opencode"?this._localEchoOverlay.setPrompt({type:"custom",offset:3,find:o=>{try{const r=o.buffer.active,a=r.cursorY,d=r.getLine(r.viewportY+a);if(!d)return null;const m=d.translateToString(!0).indexOf("\u2503");return m>=0?{row:a,col:m}:null}catch{return null}}}):t.mode==="shell"||t.mode==="codex"?(this._localEchoOverlay.clear(),this._localEchoEnabled=!1):this._localEchoOverlay.setPrompt({type:"custom",offset:0,find:o=>{try{const r=o.buffer.active;for(let a=o.rows-1;a>=0;a--){const d=r.getLine(r.viewportY+a);if(!d)continue;const m=d.translateToString(!0).lastIndexOf("\u276F");if(m>=0)return{row:a,col:m+2}}return{row:Math.max(0,Math.min(o.rows-1,r.cursorY)),col:Math.max(0,Math.min(o.cols-1,r.cursorX))}}catch{return null}}}));let n="off";t&&i&&(t.mode==="codex"?n="predict":t.mode!=="shell"&&(n="buffer")),this._localEchoPolicy=n,n!=="predict"&&this._predictiveEcho?.clearPredictions()},_predictHookOnData(e){if(!(this._localEchoPolicy!=="predict"||!this._predictiveEcho))try{const t=window.CodemanTerminalInput.classifyPredictInput(e);t==="char"?this._predictiveEcho.predictChar(e):t==="backspace"?this._predictiveEcho.predictBackspace():this._predictiveEcho.clearPredictions()}catch{}},_handleCjkInput(e){if(!this.activeSessionId){_crashDiag.log(`CJK send DROP no-session len=${e.length}`);return}typeof KeyboardAccessoryBar<"u"&&KeyboardAccessoryBar.isCtrlArmed?.()&&(e=KeyboardAccessoryBar.consumeCtrl(e)),this._localEchoPolicy==="predict"&&this._predictiveEcho?.clearPredictions(),_crashDiag.log(`CJK send\u2192${this.activeSessionId.slice(0,8)} len=${e.length}`),this._sendInputAsync(this.activeSessionId,e)},flushPendingWrites(){if(this._terminalWriteInFlight||this.pendingWrites.length===0||!this.terminal)return;const e=performance.now(),t=this.pendingWrites.join("");this.pendingWrites=[];const i=t.length;i>16384&&_crashDiag.log(`FLUSH: ${(i/1024).toFixed(0)}KB`);const n=(this.activeSessionId&&this.sessions?this.sessions.get(this.activeSessionId):null)?.mode==="codex"?32768:65536;let o=!1;const r=this.terminal.buffer?.active&&!this.isTerminalAtBottom()?this.terminal.buffer.active.viewportY:null,a=t.slice(0,n);i>n&&(this.pendingWrites.push(t.slice(n)),o=!0),this._terminalWriteInFlight=!0,this._terminalWriteInFlightBytes=a.length;try{this.terminal.write(a,()=>{this._terminalWriteInFlight=!1,this._terminalWriteInFlightBytes=0,this._scheduleTerminalWriteFlush()})}catch(m){throw this._terminalWriteInFlight=!1,this._terminalWriteInFlightBytes=0,m}r!==null&&this.terminal.buffer?.active?.viewportY!==r&&typeof this.terminal.scrollToLine=="function"&&this.terminal.scrollToLine(r);const d=o?n:i,u=performance.now()-e;if((u>100||o)&&console.warn(`[CRASH-DIAG] flushPendingWrites: ${u.toFixed(0)}ms, ${(d/1024).toFixed(0)}KB written${o?", rest deferred":""} (total ${(i/1024).toFixed(0)}KB)`),this._wasAtBottomBeforeWrite&&!this._hasRecentUserScrollUp()&&this.terminal.scrollToBottom(),this._localEchoOverlay?.hasPending&&this._localEchoOverlay.rerender(),this._tabCompletionSessionId&&this._tabCompletionSessionId===this.activeSessionId&&this._localEchoOverlay&&!this._localEchoOverlay.pendingText){const m=this._localEchoOverlay,c=this;this.terminal.write("",()=>{if(!c._tabCompletionSessionId)return;m.resetBufferDetection();const p=m.detectBufferText();p?p===c._tabCompletionBaseText?(m.undoDetection(),c._tabCompletionRetries=(c._tabCompletionRetries||0)+1,c._tabCompletionRetries>60&&(c._tabCompletionSessionId=null,c._tabCompletionRetries=0)):(c._tabCompletionSessionId=null,c._tabCompletionRetries=0,c._tabCompletionBaseText=null,c._tabCompletionFallback&&(clearTimeout(c._tabCompletionFallback),c._tabCompletionFallback=null),m.rerender()):(c._tabCompletionRetries=(c._tabCompletionRetries||0)+1,c._tabCompletionRetries>60&&(c._tabCompletionSessionId=null,c._tabCompletionRetries=0))})}},_safeYield(e){let t=!1;const i=()=>{t||(t=!0,e())};requestAnimationFrame(i),setTimeout(i,50),this._workerYield(i)},_workerYield(e){try{if(this._yieldWorker===void 0){const t="onmessage=()=>setTimeout(()=>postMessage(0),0);",i=new Blob([t],{type:"application/javascript"}),s=URL.createObjectURL(i);this._yieldWorker=new Worker(s),URL.revokeObjectURL(s),this._yieldQueue=[],this._yieldWorker.onmessage=()=>{const n=this._yieldQueue.shift();n&&n()}}if(!this._yieldWorker)return;this._yieldQueue.push(e),this._yieldWorker.postMessage(0)}catch{this._yieldWorker=null}},scrollToLastNonEmptyLine(){if(!this.terminal?.buffer?.active){this.terminal?.scrollToBottom?.();return}const e=this.terminal.buffer.active,t=e.length;let i=-1;for(let s=t-1;s>=0;s--)if(e.getLine(s)?.translateToString(!0).trim()){i=s;break}if(i>=0&&typeof this.terminal.scrollToLine=="function"){let s=Math.max(0,i-this.terminal.rows+2);const n=Math.max(0,i);for(;s<n&&!e.getLine(s)?.translateToString(!0).trim();)s++;this.terminal.scrollToLine(s)}else this.terminal.scrollToBottom()},chunkedTerminalWrite(e,t=TERMINAL_CHUNK_SIZE,i){const s=++this._chunkedWriteGen,n=this._beginBufferLoad(i);return new Promise(o=>{const r=(p=this._chunkedWriteGen===s)=>({parsedAt:performance.now(),bufferLength:this.terminal?.buffer?.active?.length??0,completed:p});if(!e||e.length===0){this._finishBufferLoad(n),o(r());return}const a=e.replace(DEC_SYNC_STRIP_RE,"");if(a.length<=t){this.terminal.write(a,()=>o(r())),this._finishBufferLoad(n);return}let d=0;const u=performance.now();let m=0;const c=()=>{if(this._chunkedWriteGen!==s){o(r(!1));return}const p=a.slice(d,d+t);if(d+=p.length,m++,this.terminal.write(p),d>=a.length){this.terminal.write("",()=>{const v=r(),E=v.parsedAt-u;console.log(`[CRASH-DIAG] chunkedTerminalWrite complete: ${a.length} bytes in ${m} chunks, ${E.toFixed(0)}ms parsed`),o(v)}),this._finishBufferLoad(n);return}this._safeYield(c)};this._safeYield(c)})},_beginBufferLoad(e){this._bufferLoadSeq===void 0&&(this._bufferLoadSeq=0);const t=e===void 0?`buffer-${++this._bufferLoadSeq}`:e;return this._bufferLoadOwner=t,this._isLoadingBuffer=!0,this._loadBufferQueue=[],t},_finishBufferLoad(e,t){if(e!==void 0&&this._bufferLoadOwner!==e)return!1;const i=this._loadBufferQueue;if(this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadOwner=null,t?.flushQueued&&i&&i.length)for(const s of i)this.batchTerminalWrite(s);return!0},clearTerminal(){this.terminal.clear()},insertTerminalText(e){!this.activeSessionId||!e||(this._localEchoPolicy==="predict"&&this._predictiveEcho?.clearPredictions(),this._localEchoEnabled&&this._localEchoOverlay&&!this._echoPassthroughSessions?.has(this.activeSessionId)?this._localEchoOverlay.appendText(e):this.sendInput(e).catch(()=>{}),this.terminal?.focus())},clearTerminalInput(){if(this.activeSessionId){if(typeof CjkInput<"u"&&CjkInput.clear(),this._inputFlushTimeout&&(clearTimeout(this._inputFlushTimeout),this._inputFlushTimeout=null),this._pendingInput="",this._localEchoPolicy==="predict"&&this._predictiveEcho?.clearPredictions(),this._localEchoEnabled&&this._localEchoOverlay){const e=this._localEchoOverlay.getFlushed?.()||{count:0,text:""};this._localEchoOverlay.clear(),this._localEchoOverlay.suppressBufferDetection(),this._flushedOffsets?.delete(this.activeSessionId),this._flushedTexts?.delete(this.activeSessionId),e.count>0&&this.sendInput("\x7F".repeat(e.count)).catch(()=>{})}else this.sendInput("").catch(()=>{});this.showToast?.("Input cleared","success"),this.terminal?.focus()}},async restoreTerminalSize(){if(!this.activeSessionId){this.showToast("No active session","warning");return}if(!this.isSoloWindow&&this.detachedSessions?.has(this.activeSessionId)){this.showToast("This session is sized by its own window","warning");return}const e=this.getTerminalDimensions();if(!e){this.showToast("Could not determine terminal size","error");return}try{await this.sendResize(this.activeSessionId,{force:!0}),this.showToast(`Terminal restored to ${e.cols}x${e.rows}`,"success")}catch(t){console.error("Failed to restore terminal size:",t),this.showToast("Failed to restore terminal size","error")}},sendPendingCtrlL(e){},shouldCopyTerminalSelectionFromShortcut(e){if(!e||e.type!=="keydown"||!e.ctrlKey&&!e.metaKey&&!e.altKey)return!1;const i=typeof this.getShortcutRegistry=="function"&&typeof this.matchesShortcutEvent=="function"?this.getShortcutRegistry().find(s=>s.id==="copy-selection"):null;return i?!i.disabled&&this.matchesShortcutEvent(e,i):!e.altKey&&(e.key||"").toLowerCase()==="c"},async copyTerminalSelection(e){const t=e??(this.terminal.hasSelection?.()?this.terminal.getSelection():"");if(!t)return!1;const i=await this._copyText(t);return i?(this.terminal.clearSelection?.(),this.showToast("Copied to clipboard","success")):this.showToast("Failed to copy","error"),this.terminal.focus(),i},_autoCopySelectionEnabled(){try{return this.loadAppSettingsFromStorage?.()?.autoCopySelection===!0}catch{return!1}},async _flushAutoCopySelection(){const e=window.CodemanAutoCopy?.decide;if(!e||!this.terminal)return;const t=this.terminal.hasSelection?.()?this.terminal.getSelection():"",i=e({enabled:this._autoCopySelectionEnabled(),text:t,lastCopied:this._autoCopyLastText,pending:!!this._autoCopyPending});if(this._autoCopyPending=!1,i==="skip")return;if(i==="too-large"){this._autoCopyNotify("Selection too large to copy automatically. Press Ctrl+C.","warning");return}this._autoCopyLastText=t;const s=document.activeElement,n=await this._copyText(t);if(s&&s!==document.activeElement&&s.isConnected&&typeof s.focus=="function")try{s.focus()}catch{}if(!n){this._autoCopyLastText="",this._autoCopyNotify("Auto Copy failed: the browser blocked clipboard access","error");return}this._autoCopyHintShown||(this._autoCopyHintShown=!0,this.showToast("Auto Copy: selection copied","success"))},_autoCopyNotify(e,t){const i=Date.now(),s=this._autoCopyNotifiedAt;s!==void 0&&i-s<1e4||(this._autoCopyNotifiedAt=i,this.showToast(e,t))},_syncMobileHelperTextareaToCursor(){if(!(!MobileDetection.isTouchDevice()||!this.terminal?.element))try{const e=this.terminal.element,t=this.terminal.element.querySelector(".xterm-cursor"),i=this.terminal.element.querySelector(".xterm-screen");if(!(e instanceof HTMLElement)||!(t instanceof HTMLElement)||!(i instanceof HTMLElement))return;const s=t.getBoundingClientRect(),n=i.getBoundingClientRect();if(!s.width&&!s.height)return;const o=Math.max(0,Math.round(s.left-n.left)),r=Math.max(0,Math.round(s.top-n.top));e.style.setProperty("--xterm-helper-left",`${o}px`),e.style.setProperty("--xterm-helper-top",`${r}px`)}catch{}},_isMobileTerminalInputFocused(){const e=document.activeElement;return e===this.terminal?.textarea||e?.classList?.contains("xterm-helper-textarea")||e?.id==="cjkInput"},_classifyMobileTerminalTap(e,t){if(!this._terminalViewportAtBottom())return"history";const i=this._clientPointToCell(e,t);if(!i||!this.terminal)return"input";const s=this.terminal.modes?.mouseTrackingMode;if(!(!!s&&s!=="none")&&!this._shouldReportMouseToCli())return"input";const o=this.terminal.buffer?.active;if(!o?.getLine)return"input";const r=Math.max(1,this.terminal.rows||1),a=[],d=[];let u=!1;for(let h=0;h<r;h++){const f=o.getLine(o.viewportY+h),g=f?.translateToString?.(!0)||"";a.push(g),d.push(!!f?.isWrapped),g.trim()&&(u=!0)}if(!u)return"input";const m=Math.max(0,Math.min(r-1,o.cursorY||0)),c=this.sessions?.get(this.activeSessionId)?.mode||"claude";let p=-1,v=!1;if(c==="opencode")a[m]?.includes("\u2503")&&(p=m);else for(let h=r-1;h>=0;h--){const f=a[h].match(/^\s*[❯›]/);if(!f)continue;const g=a[h].slice(f[0].length).trim(),_=a.some((b,C)=>C!==h&&/^\s+\d+[.)]\s/.test(b));if(/^\d+[.)]\s/.test(g)&&_){v=!0;break}p=h;break}const E=i.row-1;let y=E;for(;y>0&&d[y];)y--;let w=E;for(;w+1<r&&d[w+1];)w++;const l=a.slice(y,w+1).join("");if(c==="claude"&&/\b(?:esc to interrupt|background)\b/i.test(l)||v)return"content";if(p>=0){const h=m>=p?m:p;if(E>=p&&E<=h)return"input"}else if(E===m||E>=Math.max(0,r-window.CodemanTerminalInput.TUI_PROMPT_DEFAULT_ROWS_FROM_BOTTOM))return"input";return"content"},_blurMobileTerminalInput(){const e=document.activeElement;(e===this.terminal?.textarea||e?.classList?.contains("xterm-helper-textarea")||e?.id==="cjkInput")&&e.blur?.()},_installMobileKeyboardDismiss(){if(this._mobileKeyboardDismissHandler)return;let e=0,t=0,i=!1;this._mobileKeyboardDismissStart=s=>{if(s.touches.length!==1){i=!0;return}e=s.touches[0].clientX,t=s.touches[0].clientY,i=!1},this._mobileKeyboardDismissMove=s=>{if(i||!s.touches.length)return;const n=s.touches[0].clientX-e,o=s.touches[0].clientY-t,r=window.CodemanTerminalInput.MOBILE_KEYBOARD_DISMISS_TAP_SLOP;(Math.abs(n)>r||Math.abs(o)>r)&&(i=!0)},this._mobileKeyboardDismissHandler=s=>{if(i||!this._isMobileTerminalInputFocused())return;const n=s.target;!n||typeof n.closest!="function"||n.closest("#terminalContainer")||n.closest(window.CodemanTerminalInput.MOBILE_KEYBOARD_DISMISS_EXEMPT_SELECTOR)||this._blurMobileTerminalInput()},document.addEventListener("touchstart",this._mobileKeyboardDismissStart,{passive:!0}),document.addEventListener("touchmove",this._mobileKeyboardDismissMove,{passive:!0}),document.addEventListener("touchend",this._mobileKeyboardDismissHandler,{passive:!0})},_isActionableMobileTerminalTap(e,t){const i=this._clientPointToCell(e,t),s=this.terminal?.buffer?.active;if(!i||!s?.getLine)return!1;const n=Math.max(1,this.terminal.rows||1),o=[],r=[];for(let w=0;w<n;w++){const l=s.getLine(s.viewportY+w);o.push(l?.translateToString?.(!0)||""),r.push(!!l?.isWrapped)}const a=i.row-1;let d=a;for(;d>0&&r[d];)d--;let u=a;for(;u+1<n&&r[u+1];)u++;const m=o.slice(d,u+1).join(""),c=/\b(?:ctrl\+\w+|shift\+\w+|esc|enter|tab|tap)\s+to\s+(?:expand|collapse|view|open|interrupt|see)\b/i,p=Math.max(0,d-1),v=Math.min(n-1,u+1);for(let w=p;w<=v;w++)if(c.test(o[w]))return!0;const E=o.some(w=>/^\s*[❯›]\s+\d+[.)]\s/.test(w)),y=o.some(w=>/^\s+\d+[.)]\s/.test(w));return E&&y&&/^\s*(?:[❯›]\s*)?\d+[.)]\s/.test(m)},_focusMobileTerminalInput(){this._syncMobileHelperTextareaToCursor();const e=document.getElementById("cjkInput");e?.classList.contains("cjk-input-visible")?e.focus():this.terminal?.focus()},_handleMobileTerminalTap(e,t,i=null){if(!e||!this.terminal)return null;if(this._touchSelectionActive)return this._extendTouchSelection(e.clientX,e.clientY),"select";const s=i??this._classifyMobileTerminalTap(e.clientX,e.clientY),n=this._isActionableMobileTerminalTap(e.clientX,e.clientY);if(!n&&!this._tapIsOnCaretLine(e.clientX,e.clientY)&&this._activateTerminalLinkAtPoint(e.clientX,e.clientY))return"link";if(s==="history")return this._focusMobileTerminalInput(),s;const o=this.terminal.modes?.mouseTrackingMode,r=!!o&&o!=="none",a=s==="content"||t;return a&&r?this._dispatchSyntheticTerminalClick(e.clientX,e.clientY):a&&this._shouldReportMouseToCli()&&this._sendSyntheticSgrTap(e.clientX,e.clientY),s==="content"&&n?this._blurMobileTerminalInput():s==="content"&&t?this._blurMobileTerminalInput():this._focusMobileTerminalInput(),s},_dispatchSyntheticTerminalClick(e,t){const i=this.terminal?.element;if(!i||!Number.isFinite(e)||!Number.isFinite(t))return;const s={bubbles:!0,cancelable:!0,view:window,clientX:e,clientY:t,screenX:e,screenY:t,button:0,detail:1};try{i.dispatchEvent(new MouseEvent("mousedown",{...s,buttons:1})),i.dispatchEvent(new MouseEvent("mouseup",{...s,buttons:0}))}catch{}},_shouldReportMouseToCli(){const e=this.sessions?.get(this.activeSessionId),t=e?.mode||"claude";return t!=="claude"&&t!=="codex"&&t!=="gemini"?!1:e?.cliMouseTracking===!0},_terminalViewportAtBottom(){const e=this.terminal?.buffer?.active;return!e||e.viewportY>=e.baseY},_clientPointToCell(e,t){if(!this.terminal||!Number.isFinite(e)||!Number.isFinite(t))return null;const i=this.terminal.element?.querySelector(".xterm-screen"),s=this.terminal._core?._renderService?.dimensions?.css?.cell;if(!i||!s?.width||!s?.height)return null;const n=i.getBoundingClientRect(),o=Math.max(1,Math.min(this.terminal.cols,Math.floor((e-n.left)/s.width)+1)),r=Math.max(1,Math.min(this.terminal.rows,Math.floor((t-n.top)/s.height)+1));return{col:o,row:r}},_sendSyntheticSgrTap(e,t){if(!this.activeSessionId||!this._terminalViewportAtBottom())return;const i=this._clientPointToCell(e,t);i&&this._sendInputAsync(this.activeSessionId,`\x1B[<0;${i.col};${i.row}M\x1B[<0;${i.col};${i.row}m`)},_cliVersionAtLeast(e,t){if(typeof e!="string")return!1;const i=e.trim().replace(/^v/,"").split(".").map(Number);if(i.length!==3||i.some(n=>!Number.isFinite(n)))return!1;const s=t.split(".").map(Number);for(let n=0;n<3;n++)if(i[n]!==s[n])return i[n]>s[n];return!0},_wheelScrollLines(e){const t=this._wheelScrollLinesFloat(e);return t?Math.round(t)||(t>0?1:-1):0},_wheelScrollLinesFloat(e){const t=e.shiftKey&&Math.abs(e.deltaX)>Math.abs(e.deltaY)?e.deltaX:e.deltaY;return t?e.deltaMode===1?t:e.deltaMode===2?t*(this.terminal?.rows||24):t/25:0},_shouldForwardWheelToApp(e){if(e.shiftKey||this.loadAppSettingsFromStorage?.()?.terminalWheelLocalScrollback)return!1;const t=this.terminal?.modes?.mouseTrackingMode;if(t&&t!=="none")return!1;const i=this.sessions?.get(this.activeSessionId);return!((i?.mode||"claude")!=="claude"||!this._cliVersionAtLeast(i?.cliVersion,"2.1.187"))},_sendSyntheticSgrWheel(e,t,i){if(!this.activeSessionId||!i)return;const s=this._clientPointToCell(e,t);if(!s)return;const n=i<0?64:65,o=Math.min(Math.abs(i),5);this._queueScrollBytes(`\x1B[<${n};${s.col};${s.row}M`.repeat(o))},_queueScrollBytes(e){if(!e||!this.activeSessionId)return;const t=this._wheelSgrQueue||"";t.length>512||(this._wheelSgrQueue=t+e,!this._wheelSgrFlushTimer&&(this._wheelSgrFlushTimer=setTimeout(()=>this._flushWheelSgrQueue(),40)))},_localScrollbackIsHollow(){if((this.sessions?.get(this.activeSessionId)?.mode||"claude")!=="claude")return!1;const t=this.terminal?.buffer?.active;return!t||t.type==="alternate"?!1:(t.baseY||0)===0},_maybePageCliTranscript(e,t){if(!t||e?.shiftKey||!this.activeSessionId||!this._localScrollbackIsHollow())return!1;this._pageKeySession!==this.activeSessionId&&(this._pageKeySession=this.activeSessionId,this._pageKeyPending=0);const i=window.CodemanTerminalInput,s=Math.max(2,Math.round((this.terminal?.rows||24)*i.PAGE_KEY_SCREEN_FRACTION)),n=(this._pageKeyPending||0)+t,o=Math.trunc(n/s);if(this._pageKeyPending=n-o*s,o){const r=o<0?i.KEY_PAGE_UP:i.KEY_PAGE_DOWN;this._queueScrollBytes(r.repeat(Math.min(Math.abs(o),i.PAGE_KEY_MAX_PER_BATCH)))}return this._logScrollRouting("page-keys"),!0},_logScrollRouting(e){const t=this.activeSessionId||"(none)",i=this.sessions?.get(t),s=!!this.loadAppSettingsFromStorage?.()?.terminalWheelLocalScrollback,n=this.terminal?.modes?.mouseTrackingMode||"none",o=this.terminal?.buffer?.active?.baseY??-1,r=`${e}|${i?.mode}|${i?.cliVersion}|${s}|${n}|${o>0}`;this._scrollRoutingLogged||(this._scrollRoutingLogged=new Map),this._scrollRoutingLogged.get(t)!==r&&(this._scrollRoutingLogged.set(t,r),console.log(`[scroll] ${t} \u2192 ${e} (mode=${i?.mode||"?"}, cliVersion=${i?.cliVersion||"unknown"}, localScrollbackOptOut=${s}, mouseTracking=${n}, localScrollbackRows=${o})`))},_flushWheelSgrQueue(){this._wheelSgrFlushTimer=null;const e=this._wheelSgrQueue;this._wheelSgrQueue="",e&&this.activeSessionId&&this._sendInputEphemeral(this.activeSessionId,e)},_handleDesktopTerminalClick(e){if(!this.terminal||!e?.isTrusted||e.button!==0||e.detail!==1||e.shiftKey||e.altKey||e.ctrlKey||e.metaKey)return;const t=this.terminal.modes?.mouseTrackingMode;t&&t!=="none"||this._shouldReportMouseToCli()&&(this.terminal.hasSelection?.()||this._linkHovered||performance.now()<=(this._trustedTapMouseSuppressUntil||0)||e.target?.closest?.(".xterm-screen")&&this._sendSyntheticSgrTap(e.clientX,e.clientY))},_installMobileTapMouseGuard(){const e=this.terminal?.element;if(!e||e._codemanTapMouseGuardInstalled||typeof MobileDetection<"u"&&MobileDetection.isTouchDevice&&!MobileDetection.isTouchDevice())return;e._codemanTapMouseGuardInstalled=!0;const t=i=>{const s=this._trustedTapMouseSuppressUntil||0;!i.isTrusted||performance.now()>s||(i.preventDefault(),i.stopImmediatePropagation())};e.addEventListener("mousedown",t,!0),e.addEventListener("mouseup",t,!0)},_suppressTrustedTapMouseEvents(){const e=window.CodemanTerminalInput?.TOUCH_COMPAT_MOUSE_SUPPRESS_MS||450;this._trustedTapMouseSuppressUntil=performance.now()+e},increaseFontSize(){const e=this.terminal.options.fontSize||14;this.setFontSize(Math.min(e+2,24))},decreaseFontSize(){const e=this.terminal.options.fontSize||14;this.setFontSize(Math.max(e-2,10))},setFontSize(e){this.terminal.options.fontSize=e,document.getElementById("fontSizeDisplay").textContent=e,this.fitAddon.fit(),localStorage.setItem("codeman-font-size",e),this._localEchoOverlay?.refreshFont(),this._predictiveEcho?.refreshFont()},applyTerminalFontFamily(e){const t=window.CodemanTerminalFont.resolve(e);!this.terminal||this.terminal.options.fontFamily===t||(this.terminal.options.fontFamily=t,this._terminalFontReady=this._awaitTerminalFont().then(()=>{this.terminal?.options?.fontFamily===t&&this.fitAddon?.fit()}),this.fitAddon?.fit(),this._localEchoOverlay?.refreshFont(),this._predictiveEcho?.refreshFont())},loadFontSize(){const e=localStorage.getItem("codeman-font-size");if(e){const t=parseInt(e,10);t>=10&&t<=24&&(this.terminal.options.fontSize=t,document.getElementById("fontSizeDisplay").textContent=t)}},async _awaitTerminalFont(){try{if(typeof document>"u"||!document.fonts?.load)return;const e=this.terminal?.options?.fontSize||14,t=String(this.terminal?.options?.fontFamily||"").split(",").map(s=>s.trim().replace(/^["']|["']$/g,"")).filter(Boolean).filter(s=>!TERMINAL_FONT_UNMEASURED.has(s.toLowerCase())),i=Promise.all(t.map(s=>document.fonts.load(`${e}px "${s}"`).catch(()=>{}))).then(()=>document.fonts.ready);await Promise.race([i,new Promise(s=>setTimeout(s,TERMINAL_FONT_WAIT_MS))])}catch{}try{this.terminal?._core?._charSizeService?.measure()}catch{}},getTerminalDimensions(){const i=this.fitAddon?.proposeDimensions();return i?{cols:Math.max(i.cols,40),rows:Math.max(i.rows,10)}:null},async sendResize(e,t={}){if(this.fitAddon&&this.fitAddon.fit(),!this.isSoloWindow&&this.detachedSessions?.has(e))return!1;const i=this.getTerminalDimensions();if(!i)return!1;const s=this._lastResizeDims,n=!s||s.cols!==i.cols||s.rows!==i.rows;this._lastResizeDims={cols:i.cols,rows:i.rows};const o=typeof MobileDetection<"u"&&MobileDetection.getDeviceType?MobileDetection.getDeviceType():window.innerWidth<430?"mobile":window.innerWidth<768?"tablet":"desktop";if(!t.forceHttp&&this._wsReady&&this._wsSessionId===e)try{const a={t:"z",c:i.cols,r:i.rows,v:o};return t.force&&(a.f=!0),this._ws.send(JSON.stringify(a)),n}catch{}const r={...i,viewportType:o};return t.force&&(r.force=!0),await fetch(`/api/sessions/${e}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)}),n},async sendInput(e){!this.activeSessionId||!e||this._sendInputAsync(this.activeSessionId,e,{useMux:!0})},toggleDirInput(){const e=document.querySelector("#dirDisplay").parentElement,t=document.getElementById("dirInput");t.classList.contains("hidden")&&(t.classList.remove("hidden"),e.style.display="none",t.focus())},hideDirInput(){const e=document.querySelector("#dirDisplay").parentElement,t=document.getElementById("dirInput");setTimeout(()=>{t.classList.add("hidden"),e.style.display="";const i=t.value.trim();document.getElementById("dirDisplay").textContent=i||"No directory"},100)},applyTerminalSkin(e){const t={...window.CODEMAN_XTERM_THEMES[e]||window.CODEMAN_XTERM_THEMES["daylight-blue"]},i=window.codemanCurrentSkinIsLight(e)?4.5:1;if(this.terminal){this.terminal.options.minimumContrastRatio=i,this.terminal.options.theme=t,this._localEchoOverlay?.refreshFont(),this._predictiveEcho?.refreshFont();try{this.terminal.refresh(0,this.terminal.rows-1)}catch{}}if(this.teammateTerminals){for(const[,s]of this.teammateTerminals)if(s&&s.terminal){s.terminal.options.minimumContrastRatio=i,s.terminal.options.theme={...t};try{s.terminal.refresh(0,s.terminal.rows-1)}catch{}}}}}),(function(e){const s={session:"Sessions",event:"Events",file:"Files"};function n(o){if(!Number.isFinite(o))return"";const r=new Date(o);return r.toLocaleDateString("en",{month:"short",day:"numeric"})+" "+r.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit",hour12:!1})}e.CodemanSearch={SEARCH_DEBOUNCE_MS:250,SEARCH_LIMIT:60,SOURCE_LABELS:s,formatSearchTime:n}})(window),Object.assign(CodemanApp.prototype,{initSearchPanel(){const e=document.getElementById("searchInput");if(!e||this._searchPanelWired){this._searchPanelWired&&this._populateSearchCaseFilter();return}this._searchPanelWired=!0,this._searchTypes=new Set(["session","event","file"]),this._searchSecondary={caseLabel:"",status:"",days:""},this._searchDebounceTimer=null,this._searchSeq=0,this._searchLastData=null;const t=document.getElementById("searchClearBtn"),i=document.getElementById("searchResults");e.addEventListener("input",()=>{t&&(t.hidden=e.value.length===0),this._scheduleSearch()}),e.addEventListener("keydown",r=>{r.key==="Escape"&&e.value&&(r.stopPropagation(),this._clearSearch())}),t&&t.addEventListener("click",()=>this._clearSearch()),document.querySelectorAll("#searchFilters .search-filter-chip").forEach(r=>{r.addEventListener("click",()=>{const a=r.dataset.typeFilter;this._searchTypes.has(a)&&this._searchTypes.size===1||(this._searchTypes.has(a)?(this._searchTypes.delete(a),r.classList.remove("active")):(this._searchTypes.add(a),r.classList.add("active")),this._runSearch())})});const s=document.getElementById("searchCaseFilter"),n=document.getElementById("searchStatusFilter"),o=document.getElementById("searchDateFilter");s&&s.addEventListener("change",()=>{this._searchSecondary.caseLabel=s.value,this._renderSearch(this._searchLastData)}),n&&n.addEventListener("change",()=>{this._searchSecondary.status=n.value,this._renderSearch(this._searchLastData)}),o&&o.addEventListener("change",()=>{this._searchSecondary.days=o.value,this._renderSearch(this._searchLastData)}),this._populateSearchCaseFilter(),i&&(i.hidden=!0)},_populateSearchCaseFilter(){const e=document.getElementById("searchCaseFilter");if(!e)return;const t=Array.isArray(this.cases)?this.cases:[],i=Array.from(new Set(t.map(o=>o&&o.name).filter(Boolean))).sort(),s=e.value;e.innerHTML="";const n=document.createElement("option");n.value="",n.textContent="All cases",e.appendChild(n);for(const o of i){const r=document.createElement("option");r.value=o,r.textContent="#"+o,e.appendChild(r)}s&&i.includes(s)&&(e.value=s)},_scheduleSearch(){clearTimeout(this._searchDebounceTimer),this._searchDebounceTimer=setTimeout(()=>this._runSearch(),window.CodemanSearch.SEARCH_DEBOUNCE_MS)},_clearSearch(){const e=document.getElementById("searchInput"),t=document.getElementById("searchClearBtn");e&&(e.value=""),t&&(t.hidden=!0),this._searchLastData=null,this._renderSearch(null)},async _runSearch(){const e=document.getElementById("searchInput");if(!e)return;const t=e.value.trim();if(t.length===0){this._searchLastData=null,this._renderSearch(null);return}const i=Array.from(this._searchTypes),s=new URLSearchParams;s.set("q",t.slice(0,200)),i.length>0&&i.length<3&&s.set("types",i.join(",")),s.set("limit",String(window.CodemanSearch.SEARCH_LIMIT));const n=++this._searchSeq,o=await this._apiJson("/api/search?"+s.toString());n===this._searchSeq&&(o?this._searchLastData=o:this._searchLastData={query:t,groups:[],totalResults:0,truncated:!1,_error:!0},this._renderSearch(this._searchLastData))},_applySecondaryFilters(e){const{caseLabel:t,status:i,days:s}=this._searchSecondary;let n=e;if(t){const o="#"+t;n=n.filter(r=>(r.sessionName||"").includes(o)||r.sessionName===t)}if(i){const o=new Set((this.sessionOrder||[]).concat(Object.keys(this.sessions||{})));n=n.filter(r=>{const a=o.has(r.sessionId);return i==="active"?a:!a})}if(s){const o=Date.now()-Number(s)*24*60*60*1e3;n=n.filter(r=>Number.isFinite(r.timestamp)&&r.timestamp>=o)}return n},_renderSearch(e){const t=document.getElementById("searchResults"),i=document.getElementById("historyHeader")||document.getElementById("historyTitle"),s=document.getElementById("historyList");if(!t)return;const n=!!e;if(i&&(i.style.display=n?"none":""),s&&(s.style.display=n?"none":""),t.innerHTML="",!e){t.hidden=!0;return}if(t.hidden=!1,e._error){const a=document.createElement("div");a.className="search-empty",a.textContent="Search unavailable \u2014 check the query and try again.",t.appendChild(a);return}const o=(e.groups||[]).map(a=>({type:a.type,results:this._applySecondaryFilters(a.results||[])})).filter(a=>a.results.length>0);if(o.reduce((a,d)=>a+d.results.length,0)===0){const a=document.createElement("div");a.className="search-empty",a.textContent='No results for "'+(e.query||"")+'"',t.appendChild(a);return}for(const a of o){const d=document.createElement("div");d.className="search-group-header";const u=document.createElement("span");u.className="search-group-label",u.textContent=window.CodemanSearch.SOURCE_LABELS[a.type]||a.type;const m=document.createElement("span");m.className="search-group-count",m.textContent=String(a.results.length),d.append(u,m),t.appendChild(d);for(const c of a.results)t.appendChild(this._buildSearchResultCard(c))}if(e.truncated){const a=document.createElement("div");a.className="search-truncated",a.textContent="Showing the top matches \u2014 refine your search to narrow results.",t.appendChild(a)}},_buildSearchResultCard(e){const t=document.createElement("div");t.className="search-result-card",t.dataset.type=e.type,t.tabIndex=0,t.setAttribute("role","button");const i=document.createElement("div");i.className="search-result-top";const s=e.jumpTo&&e.jumpTo.kind==="resume-session",n=document.createElement("span");n.className="search-result-badge search-badge-"+e.type+(s?" search-badge-past":""),n.textContent=s?"Resume":(window.CodemanSearch.SOURCE_LABELS[e.type]||e.type).replace(/s$/,"");const o=document.createElement("span");o.className="search-result-name",o.textContent=e.sessionName||e.sessionId||"(session)";const r=document.createElement("span");r.className="search-result-time",r.textContent=window.CodemanSearch.formatSearchTime(e.timestamp),i.append(n,o,r);const a=document.createElement("div");a.className="search-result-snippet",a.textContent=e.snippet||"",t.append(i,a);const d=()=>this._jumpToSearchResult(e);return t.addEventListener("click",d),t.addEventListener("keydown",u=>{(u.key==="Enter"||u.key===" ")&&(u.preventDefault(),d())}),t},_jumpToSearchResult(e){const t=e&&e.jumpTo;if(t){if(t.kind==="resume-session"){this.resumeHistorySession(t.claudeSessionId||t.sessionId,t.workingDir||"",e.sessionName);return}typeof this.hideWelcome=="function"&&this.hideWelcome();try{t.kind==="run-summary"?this.openRunSummary(t.sessionId):t.kind==="file-preview"?this.openFilePreview(t.relativePath||"",t.sessionId,t.targetId||null):this.selectSession(t.sessionId)}catch(i){console.error("[search] jump failed",i)}}}});
Binary file
Binary file
@@ -19,7 +19,170 @@
19
19
  * @loadorder 12.5 of 16, after session-ui.js (needs the tab strip), before api-client.js
20
20
  */
21
21
 
22
+ // ── Loopback links ──────────────────────────────────────────────────────────
23
+ //
24
+ // An agent prints `http://localhost:5173/` and the user taps it on a phone.
25
+ // That link can only ever resolve on the Codeman box itself, so opening it in
26
+ // the browser is a guaranteed connection error from anywhere else — while the
27
+ // proxied web tab fetches from the server, where it works. Only loopback is
28
+ // routed this way: a LAN or tailnet address may well be reachable from the
29
+ // device (a VPN, the same Wi-Fi), and a direct open is the cheaper, richer path.
30
+
31
+ const LOOPBACK_HOSTNAMES = new Set(['localhost', '0.0.0.0', '::1', '[::1]', '::', '[::]']);
32
+
33
+ function normalizeHostname(hostname) {
34
+ return String(hostname || '')
35
+ .trim()
36
+ .toLowerCase()
37
+ .replace(/\.$/, '');
38
+ }
39
+
40
+ /**
41
+ * `localhost`, 127.0.0.0/8, 0.0.0.0 and the IPv6 loopback forms: names that can
42
+ * only ever mean this box.
43
+ *
44
+ * ⚠️ `*.localhost` is deliberately NOT here. The link source is agent-written
45
+ * terminal output and response-viewer markdown, i.e. prompt-injectable, and
46
+ * this set is the whole confinement on a tap that makes Codeman fetch a URL
47
+ * server-side and persist it. Every other member is an address literal; a
48
+ * `*.localhost` DNS name is not one: on a resolver that does not synthesise it
49
+ * locally and has a search domain configured, `evil.localhost` NXDOMAINs as
50
+ * absolute and is retried as `evil.localhost.<search domain>`, which an
51
+ * attacker can control. A user who really runs `api.localhost` dev hosts can
52
+ * still save that dashboard by hand, which is an explicit action.
53
+ */
54
+ function isLoopbackHostname(hostname) {
55
+ const host = normalizeHostname(hostname);
56
+ if (!host) return false;
57
+ if (LOOPBACK_HOSTNAMES.has(host)) return true;
58
+ const ipv4 = /^(\d{1,3})\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.exec(host);
59
+ return !!ipv4 && Number(ipv4[1]) === 127;
60
+ }
61
+
62
+ /**
63
+ * Whether the PAGE is being viewed on the box itself. Broader than the
64
+ * auto-route set on purpose, and safe in the opposite direction: a false
65
+ * positive here only ever DECLINES to proxy, leaving the caller's direct open.
66
+ */
67
+ function isOnBoxHostname(hostname) {
68
+ const host = normalizeHostname(hostname);
69
+ return isLoopbackHostname(host) || host.endsWith('.localhost');
70
+ }
71
+
72
+ /**
73
+ * One key per dev server, so `localhost:5173` and `127.0.0.1:5173` reuse a
74
+ * single saved dashboard and a single tab instead of one per host spelling.
75
+ */
76
+ function webTabOriginKey(url) {
77
+ return isLoopbackHostname(url.hostname) ? `${url.protocol}//loopback:${url.port}` : url.origin;
78
+ }
79
+
80
+ /**
81
+ * Whether a link should open through a proxied web tab rather than directly:
82
+ * an http(s) URL on a loopback host, viewed from a page that is NOT itself on
83
+ * that host (on the box, the browser can reach localhost and the direct open
84
+ * keeps devtools, extensions and the real origin).
85
+ */
86
+ function linkNeedsWebTabProxy(rawUrl, pageHostname) {
87
+ let url;
88
+ try {
89
+ url = new URL(String(rawUrl || ''));
90
+ } catch {
91
+ return false;
92
+ }
93
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;
94
+ if (!isLoopbackHostname(url.hostname)) return false;
95
+ return !isOnBoxHostname(pageHostname);
96
+ }
97
+
98
+ if (typeof window !== 'undefined') {
99
+ window.CodemanWebviewLinks = { isLoopbackHostname, isOnBoxHostname, webTabOriginKey, linkNeedsWebTabProxy };
100
+ }
101
+
22
102
  Object.assign(CodemanApp.prototype, {
103
+ // ── Loopback links ────────────────────────────────────────────────────────
104
+
105
+ /**
106
+ * Take a link the device cannot reach and open it through a proxied web tab.
107
+ * Returns true when it took the link; false leaves the caller's own opening
108
+ * path (window.open, an anchor's default) untouched.
109
+ */
110
+ openLinkThroughWebTabIfLoopback(rawUrl) {
111
+ if (!linkNeedsWebTabProxy(rawUrl, window.location?.hostname)) return false;
112
+ void this.openUrlInWebTab(rawUrl);
113
+ return true;
114
+ },
115
+
116
+ /**
117
+ * Open an arbitrary URL as a proxied web tab, deep path included. A saved
118
+ * proxied dashboard on the same origin is reused (one tab per dev server,
119
+ * not one per link); otherwise one is saved under the host:port name so it
120
+ * is there in the Run dropdown next time.
121
+ */
122
+ async openUrlInWebTab(rawUrl) {
123
+ let url;
124
+ try {
125
+ url = new URL(String(rawUrl || ''));
126
+ } catch {
127
+ return;
128
+ }
129
+ // ⚠️ "is `this.webviews` set" does NOT answer "is it loaded": initWebviews()
130
+ // assigns a truthy EMPTY map synchronously and only then awaits the list, so
131
+ // a tap during page load used to find nothing to reuse and POST a duplicate
132
+ // record for an origin that already exists server-side. Join an in-flight
133
+ // load; start one only when none has ever run.
134
+ if (this._webviewsRefresh) await this._webviewsRefresh;
135
+ else if (!this._webviewsLoaded) await this.refreshWebviews();
136
+ if (!this.webviews) {
137
+ this.showToast?.('Could not open URL', 'error');
138
+ return;
139
+ }
140
+
141
+ const wantedKey = webTabOriginKey(url);
142
+ let existing = null;
143
+ for (const webview of this.webviews.values()) {
144
+ // ⚠️ `trusted` is excluded alongside `managed` and direct-mode records: a
145
+ // trusted frame runs with `allow-same-origin`, i.e. on Codeman's origin with
146
+ // the user's cookie, and the link being followed came from agent output. An
147
+ // agent that can write into the dev server's tree (it IS the workspace) could
148
+ // otherwise print a path that one tap navigates that privileged frame to.
149
+ // Opening such a dashboard from the Run dropdown is still an explicit action.
150
+ if (webview.managed || webview.trusted || (webview.embedMode ?? 'proxy') !== 'proxy') continue;
151
+ try {
152
+ if (webTabOriginKey(new URL(webview.url)) === wantedKey) {
153
+ existing = webview;
154
+ break;
155
+ }
156
+ } catch {
157
+ /* a saved URL that no longer parses is not a match */
158
+ }
159
+ }
160
+
161
+ let id = existing?.id;
162
+ if (!id) {
163
+ const created = await this._apiJson('/api/webviews', {
164
+ method: 'POST',
165
+ body: { name: url.host.slice(0, 60), url: `${url.origin}/`, embedMode: 'proxy', trusted: false },
166
+ });
167
+ if (!created?.id) {
168
+ this.showToast?.('Could not open URL', 'error');
169
+ return;
170
+ }
171
+ await this.refreshWebviews();
172
+ id = created.id;
173
+ // The create is a persisted record: it writes webviews.json, broadcasts
174
+ // over SSE, adds a Run-dropdown row on every device this owner is signed
175
+ // in on and counts toward MAX_WEBVIEWS. Adding one by hand goes through a
176
+ // modal; a tap should not do all that with a new tab as its only signal.
177
+ this.showToast?.(`Saved ${url.host} as a web tab`, 'success');
178
+ }
179
+ // `/` is passed through rather than flattened to '': openWebview reads an
180
+ // empty path as "no deep link" and leaves an already-open frame on whatever
181
+ // page it was showing, so a link to the origin root did nothing visible.
182
+ const path = `${url.pathname}${url.search}${url.hash}`;
183
+ await this.openWebview(id, { path: path || '/' });
184
+ },
185
+
23
186
  // ── State ─────────────────────────────────────────────────────────────────
24
187
 
25
188
  /** Load the saved list and restore which tabs were open. */
@@ -45,11 +208,19 @@ Object.assign(CodemanApp.prototype, {
45
208
  },
46
209
 
47
210
  async refreshWebviews() {
48
- const data = await this._apiJson('/api/webviews');
49
- if (!data) return;
50
- this.webviews = new Map((data.webviews || []).map((w) => [w.id, w]));
51
- if (typeof data.maxLiveFrames === 'number') this._webviewMaxFrames = data.maxLiveFrames;
52
- this.renderWebviewMenuItems();
211
+ const inFlight = this._apiJson('/api/webviews').then((data) => {
212
+ if (!data) return;
213
+ this.webviews = new Map((data.webviews || []).map((w) => [w.id, w]));
214
+ if (typeof data.maxLiveFrames === 'number') this._webviewMaxFrames = data.maxLiveFrames;
215
+ this._webviewsLoaded = true;
216
+ this.renderWebviewMenuItems();
217
+ });
218
+ this._webviewsRefresh = inFlight;
219
+ try {
220
+ await inFlight;
221
+ } finally {
222
+ if (this._webviewsRefresh === inFlight) this._webviewsRefresh = null;
223
+ }
53
224
  },
54
225
 
55
226
  /** SSE: the saved list changed (possibly on another device). */
@@ -133,7 +304,14 @@ Object.assign(CodemanApp.prototype, {
133
304
  * memory-only and expire, so a tab reopened after a server restart must not reuse
134
305
  * the dead URL from the previous run.
135
306
  */
136
- async openWebview(id) {
307
+ /**
308
+ * @param {string} id
309
+ * @param {{path?: string}} [options] `path` (pathname+search+hash) opens a
310
+ * deep link inside the dashboard: appended to the proxy prefix, or resolved
311
+ * against the real URL in direct mode. A mounted frame is navigated there
312
+ * rather than left on whatever page it was showing.
313
+ */
314
+ async openWebview(id, options = {}) {
137
315
  const webview = this.webviews.get(id);
138
316
  if (!webview) return;
139
317
 
@@ -149,8 +327,14 @@ Object.assign(CodemanApp.prototype, {
149
327
  }
150
328
  if (data.webview) this.webviews.set(id, data.webview);
151
329
 
152
- const src = data.embedUrl || data.webview?.url || webview.url;
153
- this._mountWebviewFrame(id, src, data.webview || webview);
330
+ let src = data.embedUrl || data.webview?.url || webview.url;
331
+ const path = typeof options.path === 'string' ? options.path : '';
332
+ if (path) {
333
+ // The proxy prefix is `/webview/<cap>/`; a wildcard rides after it. In
334
+ // direct mode the deep link resolves against the dashboard's own origin.
335
+ src = data.embedUrl ? `${data.embedUrl.replace(/\/?$/, '/')}${path.replace(/^\//, '')}` : new URL(path, src).href;
336
+ }
337
+ this._mountWebviewFrame(id, src, data.webview || webview, { navigate: !!path });
154
338
  this.activeWebviewId = id;
155
339
  this.hideWelcome?.();
156
340
  document.querySelector('.main')?.classList.add('webview-active');
@@ -162,11 +346,17 @@ Object.assign(CodemanApp.prototype, {
162
346
  },
163
347
 
164
348
  /** Create the frame if absent, then reveal it and hide its siblings. */
165
- _mountWebviewFrame(id, src, webview) {
349
+ _mountWebviewFrame(id, src, webview, { navigate = false } = {}) {
166
350
  const layer = document.getElementById('webviewLayer');
167
351
  if (!layer) return;
168
352
 
169
353
  let wrap = layer.querySelector(`.webview-frame[data-webview-id="${CSS.escape(id)}"]`);
354
+ if (wrap && navigate) {
355
+ // A deep link into an already-mounted dashboard: navigate the live frame
356
+ // instead of tearing it down, so its login and state survive.
357
+ const frame = wrap.querySelector('iframe');
358
+ if (frame) frame.src = CodemanBase.url(src);
359
+ }
170
360
  if (!wrap) {
171
361
  wrap = document.createElement('div');
172
362
  wrap.className = 'webview-frame';
Binary file
Binary file
@@ -9,4 +9,24 @@ export interface ResponseViewerTranscriptBlock {
9
9
  export declare function isExternalCliTranscriptMode(mode: string | null | undefined): boolean;
10
10
  export declare function parseExternalCliTranscript(buffer: string, mode: string | null | undefined): ResponseViewerTranscriptBlock[];
11
11
  export declare function getLastTranscriptResponse(blocks: ResponseViewerTranscriptBlock[]): string;
12
+ /**
13
+ * The messages of the most recent turn that has an answer: every assistant
14
+ * message whose `turn` matches the highest turn any assistant message carries.
15
+ *
16
+ * This is what the viewer's brief ("Last Response") view renders for Claude.
17
+ * The brief `text` is one row — the last assistant row — and a Claude turn is
18
+ * a median of 3 rows (p90 11), so that row alone was usually the tail of the
19
+ * answer ("Done.") with the substance in the rows before it. Reading the whole
20
+ * turn gives the same cards the full view shows for it, and no more.
21
+ *
22
+ * Deliberately NOT "everything after the last user message": a prompt queued
23
+ * while the agent works opens a new, still-unanswered turn, and the honest
24
+ * brief view is then the previous, answered one — exactly the row `text`
25
+ * already points at. Messages without a numeric `turn` (Codex, the pane
26
+ * parser, an older reader) yield an empty list so callers fall back to `text`.
27
+ */
28
+ export declare function selectLastAnsweredTurn<T extends {
29
+ role: string;
30
+ turn?: number;
31
+ }>(messages: T[]): T[];
12
32
  //# sourceMappingURL=response-viewer-transcript.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"response-viewer-transcript.d.ts","sourceRoot":"","sources":["../../src/web/response-viewer-transcript.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,4BAA4B,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAErF,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,KAAK,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjD,kGAAkG;IAClG,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AA+PD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEpF;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,6BAA6B,EAAE,CAmFjC;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,6BAA6B,EAAE,GAAG,MAAM,CAKzF"}
1
+ {"version":3,"file":"response-viewer-transcript.d.ts","sourceRoot":"","sources":["../../src/web/response-viewer-transcript.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,4BAA4B,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAErF,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,KAAK,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjD,kGAAkG;IAClG,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AA+PD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEpF;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,6BAA6B,EAAE,CAmFjC;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,6BAA6B,EAAE,GAAG,MAAM,CAKzF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CASpG"}
@@ -342,4 +342,31 @@ export function getLastTranscriptResponse(blocks) {
342
342
  }
343
343
  return '';
344
344
  }
345
+ /**
346
+ * The messages of the most recent turn that has an answer: every assistant
347
+ * message whose `turn` matches the highest turn any assistant message carries.
348
+ *
349
+ * This is what the viewer's brief ("Last Response") view renders for Claude.
350
+ * The brief `text` is one row — the last assistant row — and a Claude turn is
351
+ * a median of 3 rows (p90 11), so that row alone was usually the tail of the
352
+ * answer ("Done.") with the substance in the rows before it. Reading the whole
353
+ * turn gives the same cards the full view shows for it, and no more.
354
+ *
355
+ * Deliberately NOT "everything after the last user message": a prompt queued
356
+ * while the agent works opens a new, still-unanswered turn, and the honest
357
+ * brief view is then the previous, answered one — exactly the row `text`
358
+ * already points at. Messages without a numeric `turn` (Codex, the pane
359
+ * parser, an older reader) yield an empty list so callers fall back to `text`.
360
+ */
361
+ export function selectLastAnsweredTurn(messages) {
362
+ let latest = -1;
363
+ for (const message of messages) {
364
+ if (message.role === 'assistant' && typeof message.turn === 'number' && message.turn > latest) {
365
+ latest = message.turn;
366
+ }
367
+ }
368
+ if (latest < 0)
369
+ return [];
370
+ return messages.filter((message) => message.role === 'assistant' && message.turn === latest);
371
+ }
345
372
  //# sourceMappingURL=response-viewer-transcript.js.map