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.
- package/dist/config/cli-registry/stock.d.ts.map +1 -1
- package/dist/config/cli-registry/stock.js +13 -2
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/session-cli-builder.d.ts.map +1 -1
- package/dist/session-cli-builder.js +31 -5
- package/dist/session-cli-builder.js.map +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +19 -0
- package/dist/session.js.map +1 -1
- package/dist/tmux-manager.d.ts +3 -0
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +65 -8
- package/dist/tmux-manager.js.map +1 -1
- package/dist/types/common.d.ts +2 -0
- package/dist/types/common.d.ts.map +1 -1
- package/dist/utils/omp-session-resolver.d.ts +14 -0
- package/dist/utils/omp-session-resolver.d.ts.map +1 -1
- package/dist/utils/omp-session-resolver.js +21 -2
- package/dist/utils/omp-session-resolver.js.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.78bf0bf8.js +38 -0
- package/dist/web/public/app.78bf0bf8.js.br +0 -0
- package/dist/web/public/app.78bf0bf8.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/{constants.e6d48776.js → constants.9cd8ed69.js} +7 -1
- package/dist/web/public/constants.9cd8ed69.js.br +0 -0
- package/dist/web/public/constants.9cd8ed69.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/i18n.9db8c4e0.js.gz +0 -0
- package/dist/web/public/image-input.cd4b97c4.js.gz +0 -0
- package/dist/web/public/index.html +22 -10
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.87f14251.js.gz +0 -0
- package/dist/web/public/{keyboard-accessory.daf18302.js → keyboard-accessory.1d0dda9b.js} +182 -13
- package/dist/web/public/keyboard-accessory.1d0dda9b.js.br +0 -0
- package/dist/web/public/keyboard-accessory.1d0dda9b.js.gz +0 -0
- package/dist/web/public/mobile-handlers.2e9c214a.js.gz +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.65176832.css.gz +0 -0
- package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.9eb5b235.js → panels-ui.4e9ea307.js} +1 -1
- package/dist/web/public/panels-ui.4e9ea307.js.br +0 -0
- package/dist/web/public/panels-ui.4e9ea307.js.gz +0 -0
- package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
- package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
- package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/session-ui.cd222710.js.gz +0 -0
- package/dist/web/public/settings-ui.c175db9a.js +67 -0
- package/dist/web/public/settings-ui.c175db9a.js.br +0 -0
- package/dist/web/public/settings-ui.c175db9a.js.gz +0 -0
- package/dist/web/public/{styles.89069bbc.css → styles.0d41361c.css} +1 -1
- package/dist/web/public/styles.0d41361c.css.br +0 -0
- package/dist/web/public/styles.0d41361c.css.gz +0 -0
- package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
- package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js +1 -0
- package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.br +0 -0
- package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.gz +0 -0
- package/dist/web/public/terminal-ui.89e4eb1a.js +2 -0
- package/dist/web/public/terminal-ui.89e4eb1a.js.br +0 -0
- package/dist/web/public/terminal-ui.89e4eb1a.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js +199 -9
- package/dist/web/public/webview-tabs.js.br +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/response-viewer-transcript.d.ts +20 -0
- package/dist/web/response-viewer-transcript.d.ts.map +1 -1
- package/dist/web/response-viewer-transcript.js +27 -0
- package/dist/web/response-viewer-transcript.js.map +1 -1
- package/dist/web/routes/file-routes.d.ts.map +1 -1
- package/dist/web/routes/file-routes.js +11 -3
- package/dist/web/routes/file-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +16 -4
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +4 -0
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +9 -0
- package/dist/web/schemas.js.map +1 -1
- package/package.json +1 -1
- package/skills/codeman/reference/endpoints.md +1 -0
- package/dist/web/public/app.c4dbfcfb.js +0 -38
- package/dist/web/public/app.c4dbfcfb.js.br +0 -0
- package/dist/web/public/app.c4dbfcfb.js.gz +0 -0
- package/dist/web/public/constants.e6d48776.js.br +0 -0
- package/dist/web/public/constants.e6d48776.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.daf18302.js.br +0 -0
- package/dist/web/public/keyboard-accessory.daf18302.js.gz +0 -0
- package/dist/web/public/panels-ui.9eb5b235.js.br +0 -0
- package/dist/web/public/panels-ui.9eb5b235.js.gz +0 -0
- package/dist/web/public/settings-ui.554f9cdd.js +0 -67
- package/dist/web/public/settings-ui.554f9cdd.js.br +0 -0
- package/dist/web/public/settings-ui.554f9cdd.js.gz +0 -0
- package/dist/web/public/styles.89069bbc.css.br +0 -0
- package/dist/web/public/styles.89069bbc.css.gz +0 -0
- package/dist/web/public/terminal-ui.1547ce5e.js +0 -2
- package/dist/web/public/terminal-ui.1547ce5e.js.br +0 -0
- package/dist/web/public/terminal-ui.1547ce5e.js.gz +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/web/public/sw.js.gz
CHANGED
|
Binary file
|
|
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);
|
|
Binary file
|
|
Binary file
|
|
@@ -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="×",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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
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
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
153
|
-
|
|
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
|