tmux-weblink 1.4.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/assets/addon-fit-D5N335P2.js +2 -3
  2. package/dist/assets/shell-client.js +30 -13
  3. package/dist/assets/xterm-BXEES47M.js +14 -15
  4. package/dist/browser/shell-client.js +29 -790
  5. package/dist/browser/terminal-core.js +4 -640
  6. package/dist/frontend.js +1 -9
  7. package/dist/index.js +13 -1636
  8. package/dist/lib/agent-detect.js +3 -249
  9. package/dist/lib/agents-watch.js +2 -2
  10. package/dist/lib/atomicWrite.js +1 -24
  11. package/dist/lib/auditLog.js +1 -40
  12. package/dist/lib/auth.js +2 -194
  13. package/dist/lib/cli.js +10 -162
  14. package/dist/lib/commandbar.js +17 -47
  15. package/dist/lib/db.js +1 -8
  16. package/dist/lib/drawer-resize.js +10 -25
  17. package/dist/lib/drawer-script.js +6 -13
  18. package/dist/lib/ext-loader.js +1 -168
  19. package/dist/lib/fs-access.js +1 -58
  20. package/dist/lib/html.js +1 -11
  21. package/dist/lib/icons.js +1 -73
  22. package/dist/lib/image-upload.js +1 -87
  23. package/dist/lib/load-env.js +6 -76
  24. package/dist/lib/notes-db.js +2 -4
  25. package/dist/lib/notes-drawer.js +12 -29
  26. package/dist/lib/notes-utils.js +2 -4
  27. package/dist/lib/pages/files-index.js +18 -26
  28. package/dist/lib/pages/history-index.js +17 -59
  29. package/dist/lib/pages/login.js +13 -35
  30. package/dist/lib/pages/notes-index.js +20 -45
  31. package/dist/lib/pages/notes-page.js +13 -28
  32. package/dist/lib/pages/quick-commands.js +22 -38
  33. package/dist/lib/pages/schedule-index.js +45 -81
  34. package/dist/lib/pages/settings.js +30 -76
  35. package/dist/lib/pages/shell.js +138 -81
  36. package/dist/lib/pinned-views.js +1 -38
  37. package/dist/lib/plugins.js +3 -108
  38. package/dist/lib/quick-commands.js +1 -79
  39. package/dist/lib/rateLimiter.js +2 -142
  40. package/dist/lib/schedule-delay.js +2 -36
  41. package/dist/lib/scheduler-drawer.js +14 -30
  42. package/dist/lib/scheduler.js +1 -263
  43. package/dist/lib/security-config.js +2 -65
  44. package/dist/lib/session-access.js +1 -19
  45. package/dist/lib/session-windows.js +1 -41
  46. package/dist/lib/sessions-drawer.js +16 -30
  47. package/dist/lib/sessions-sidebar.js +1 -50
  48. package/dist/lib/settings.js +2 -16
  49. package/dist/lib/setup-features.js +1 -37
  50. package/dist/lib/setup-prompts.js +3 -50
  51. package/dist/lib/shared-layout.js +51 -115
  52. package/dist/lib/state-paths.js +1 -41
  53. package/dist/lib/system-monitor.js +2 -98
  54. package/dist/lib/terminal-config.js +1 -14
  55. package/dist/lib/theme-store.js +2 -53
  56. package/dist/lib/theme.js +12 -15
  57. package/dist/lib/themes/dark-cove.js +1 -40
  58. package/dist/lib/themes/ghostty.js +1 -40
  59. package/dist/lib/themes/index.js +1 -28
  60. package/dist/lib/themes/types.js +0 -1
  61. package/dist/lib/themes/vscode.js +1 -40
  62. package/dist/lib/themes/warm-clay.js +1 -40
  63. package/dist/lib/tmux-capture.js +5 -71
  64. package/dist/lib/tmux-control.js +2 -153
  65. package/dist/lib/tmux-panes.js +2 -40
  66. package/dist/lib/tmux-windows.js +4 -149
  67. package/dist/lib/watched-panes.js +1 -1
  68. package/dist/lib/window-history.js +1 -32
  69. package/dist/lib/window-labels.js +1 -27
  70. package/dist/lib/windows-drawer.js +10 -21
  71. package/dist/lib/ws-message.js +1 -21
  72. package/dist/sessions.js +2 -21
  73. package/package.json +1 -1
@@ -1,5 +1,4 @@
1
- var p=2,c=1,d=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let i=this._terminal._core;(this._terminal.rows!==e.rows||this._terminal.cols!==e.cols)&&(i._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core._renderService.dimensions;if(e.css.cell.width===0||e.css.cell.height===0)return;let i=this._terminal.options.scrollback===0?0:this._terminal.options.overviewRuler?.width||14,s=window.getComputedStyle(this._terminal.element.parentElement),l=parseInt(s.getPropertyValue("height")),o=Math.max(0,parseInt(s.getPropertyValue("width"))),t=window.getComputedStyle(this._terminal.element),r={top:parseInt(t.getPropertyValue("padding-top")),bottom:parseInt(t.getPropertyValue("padding-bottom")),right:parseInt(t.getPropertyValue("padding-right")),left:parseInt(t.getPropertyValue("padding-left"))},a=r.top+r.bottom,n=r.right+r.left,h=l-a,m=o-n-i;return{cols:Math.max(p,Math.floor(m/e.css.cell.width)),rows:Math.max(c,Math.floor(h/e.css.cell.height))}}};export{d as FitAddon};
2
- /*! Bundled license information:
1
+ var p=2,c=1,d=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let i=this._terminal._core;(this._terminal.rows!==e.rows||this._terminal.cols!==e.cols)&&(i._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core._renderService.dimensions;if(e.css.cell.width===0||e.css.cell.height===0)return;let i=this._terminal.options.scrollback===0?0:this._terminal.options.overviewRuler?.width||14,s=window.getComputedStyle(this._terminal.element.parentElement),l=parseInt(s.getPropertyValue("height")),o=Math.max(0,parseInt(s.getPropertyValue("width"))),t=window.getComputedStyle(this._terminal.element),r={top:parseInt(t.getPropertyValue("padding-top")),bottom:parseInt(t.getPropertyValue("padding-bottom")),right:parseInt(t.getPropertyValue("padding-right")),left:parseInt(t.getPropertyValue("padding-left"))},a=r.top+r.bottom,n=r.right+r.left,h=l-a,m=o-n-i;return{cols:Math.max(p,Math.floor(m/e.css.cell.width)),rows:Math.max(c,Math.floor(h/e.css.cell.height))}}};/*! Bundled license information:
3
2
 
4
3
  @xterm/addon-fit/lib/addon-fit.mjs:
5
4
  (**
@@ -14,4 +13,4 @@ var p=2,c=1,d=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.pro
14
13
  * http://bellard.org/jslinux/
15
14
  * Copyright (c) 2011 Fabrice Bellard
16
15
  *)
17
- */
16
+ */export{d as FitAddon};
@@ -1,16 +1,33 @@
1
- var at="https://esm.sh/ghostty-web@0.4.0",lt=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function X(t){return t.replace(lt,"")}var A;function ct(){return A||(document.querySelector("link[data-tmux-web-xterm-css]")?A=Promise.resolve():(A=new Promise(e=>{let s=document.createElement("link");s.rel="stylesheet",s.href="/assets/xterm.css",s.setAttribute("data-tmux-web-xterm-css",""),s.addEventListener("load",()=>e(),{once:!0}),s.addEventListener("error",()=>e(),{once:!0}),document.head.appendChild(s)}),A))}var G=class t{terminal;fitAddon;container;constructor(e,s,i){this.container=e,this.terminal=s,this.fitAddon=i,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,s,i){let[{Terminal:r},{FitAddon:c}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),ct()]),d=new r({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:s,convertEol:!1,theme:i});return new t(e,d,new c)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(e){return new Promise(s=>this.terminal.write(e,s))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(e){this.terminal.scrollToLine(Math.max(0,e))}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){let e=Ce(this.container);return e.width<=0||e.height<=0?!1:(this.fitAddon.fit(),!0)}focus(){this.terminal.focus()}pasteText(e){this.terminal.paste(e)}input(e){this.terminal.input(e,!1)}onData(e){this.terminal.onData(e),this.terminal.onBinary(e)}onResize(e){this.terminal.onResize(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){let e=document.activeElement;return!!e&&(e===this.container||this.container.contains(e))}},ce=class t{terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(e,s){this.container=e,this.terminal=s,this.terminal.open(e)}static async create(e,s,i){let r=await import(at);await r.init();let c=new r.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:s,convertEol:!1,theme:i});return new t(e,c)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(e){return new Promise(s=>this.terminal.write(e,s))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom?.()}scrollToLine(e){this.terminal.scrollToLine?.(Math.max(0,e))}isNearScrollbackTop(){let e=this.terminal.buffer?.active;return e?e.viewportY>=e.baseY:!1}viewportY(){return this.terminal.buffer?.active?.viewportY??0}baseY(){return this.terminal.buffer?.active?.baseY??0}fit(){let e=Ce(this.container);if(e.width<=0||e.height<=0)return!1;this.updateCellMetrics(!this.charW||!this.charH);let s=Math.floor(e.width/this.charW),i=Math.floor(e.height/this.charH);if(s<10||i<5)return!1;if(s!==this.colsValue||i!==this.rowsValue){this.colsValue=s,this.rowsValue=i,this.terminal.resize(s,i);for(let r of this.resizeCallbacks)r({cols:s,rows:i})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(e){let s=this.terminal.getMode?.(2004)??!1;this.input(s?"\x1B[200~"+e+"\x1B[201~":e)}input(e){this.terminal.input?.(e,!1)}onData(e){this.terminal.onData(s=>e(s))}onResize(e){this.resizeCallbacks.push(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){let e=document.activeElement;return!!e&&(e===this.container||e===this.terminal.textarea||this.container.contains(e))}updateCellMetrics(e=!1){let s=this.container.querySelector("canvas");if(s instanceof HTMLElement&&s.offsetWidth>0&&s.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){let i=s.offsetWidth/this.colsValue,r=s.offsetHeight/this.rowsValue;(e||!this.charW||!this.charH)&&(this.charW=i,this.charH=r)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}};function Ce(t){let e=t.getBoundingClientRect(),s=window.visualViewport;return s?{width:Math.min(e.width,s.width),height:Math.max(0,Math.min(e.height,s.height-Math.max(0,e.top)))}:e}function Ie(t,e,s){return t.innerHTML="",t.classList.add("terminal-pending"),(async()=>{let i;if(s.renderer==="ghostty")try{i=await ce.create(t,s.scrollback,s.theme)}catch{console.error("[tmux-web] ghostty-web failed; falling back to xterm.js"),i=await G.create(t,s.scrollback,s.theme)}else i=await G.create(t,s.scrollback,s.theme);let r,c=0,d,a=null,y=0,f="connecting",b=0,k=!1,U=[],H="",oe=!1,D=1e3,Oe=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/"+encodeURIComponent(e),Ve="/api/session/"+encodeURIComponent(e)+"/upload",We=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function _e(){return U.join("")+H}async function Ke(n,o=0){let l=n?i.viewportY():0,g=n?i.baseY():0,E=X(_e());if(i.reset(),!E){n||i.scrollToBottom();return}await i.write(E),n?i.scrollToLine(g+l+o):i.scrollToBottom()}function P(n){r?.readyState===WebSocket.OPEN&&r.send(JSON.stringify(n))}function Ue(n){let o;try{o=JSON.parse(n)}catch{f==="live"&&(H+=n,i.write(X(n)));return}if(o.type==="auth.required"){let l=localStorage.getItem("tmux-web-token");l?P({type:"auth.token",token:l}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(o.type==="auth.ok"){o.token&&localStorage.setItem("tmux-web-token",o.token),D=1e3,R(),P({type:"resize",cols:i.cols,rows:i.rows}),h();return}if(o.type==="auth.failed"){if(o.permanentLock||o.retryAfterMs&&o.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(o.message);return}return}if(o.type==="snapshot"&&typeof o.data=="string"){let l=X(o.data);U=[l],H="",b=typeof o.lines=="number"?o.lines:s.terminal.initialLines,f="live",i.reset(),i.write(l).then(()=>i.scrollToBottom());return}if(o.type==="window_changed"&&typeof o.activeIndex=="number"){let l=new URL(location.href);l.searchParams.get("window")!==String(o.activeIndex)&&(l.searchParams.set("window",String(o.activeIndex)),history.replaceState(history.state,"",l)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:o.windows}));return}if(o.type==="history"&&typeof o.data=="string"){k=!1,o.lines>0&&o.data&&(U.unshift(o.data),b+=o.lines,Ke(!0,o.lines));return}if(o.type==="data"&&typeof o.data=="string"){let l=X(o.data);if(f==="connecting"){f="live",H=l,i.write(l);return}f==="live"&&(H+=l,i.write(l))}}function ye(){let n=Oe,o=localStorage.getItem("tmux-web-token");o&&(n+=(n.includes("?")?"&":"?")+"token="+encodeURIComponent(o)),r=new WebSocket(n),r.onopen=()=>{f="connecting",b=0,k=!1,U=[],H="",i.reset(),D=1e3},r.onmessage=l=>{typeof l.data=="string"&&Ue(l.data)},r.onclose=()=>{oe||(f="connecting",setTimeout(()=>{D=Math.min(D*2,1e4),oe||ye()},D))},r.onerror=()=>r?.close()}function $(n){P({type:"input",data:n})}function R(){return i.fit()}function re(){t.classList.remove("terminal-pending")}function h(){c&&cancelAnimationFrame(c),d&&clearTimeout(d),R(),c=requestAnimationFrame(()=>{c=0,R()&&re()}),d=setTimeout(()=>{R()&&re()},120)}function $e(){h(),setTimeout(h,50),setTimeout(h,150),setTimeout(h,300)}function be(n){return typeof n=="string"&&n.startsWith("image/")}function we(n){return n?.files?.length?n.files[0]??null:null}function qe(n){if(!n?.items)return null;for(let o=0;o<n.items.length;o++){let l=n.items[o];if(l?.kind==="file"&&be(l.type))return l.getAsFile()}return null}async function Xe(n){let o=new FormData,l=n instanceof File&&n.name?n.name:"upload";o.append("file",n,l);let g=localStorage.getItem("tmux-web-token"),E={};g&&(E.Authorization="Bearer "+g);let le=await fetch(Ve,{method:"POST",body:o,headers:E});if(!le.ok){let xe="upload failed";try{let Se=await le.json();Se.error&&(xe=Se.error)}catch{}throw new Error(xe)}let Me=await le.json();if(!Me.path)throw new Error("no path in response");return Me.path}async function ae(n){try{let o=await Xe(n);$(o)}catch{}}i.onData(n=>$(n)),i.onResize(({cols:n,rows:o})=>P({type:"resize",cols:n,rows:o})),i.onScroll(()=>{f!=="live"||k||!i.isNearScrollbackTop()||(k=!0,P({type:"load_history",before:b}))}),i.attachCustomKeyEventHandler(n=>n.type!=="keydown"?!0:(n.ctrlKey||n.metaKey)&&n.code==="KeyV"?(n.preventDefault(),(async()=>{try{if(navigator.clipboard?.read){let o=await navigator.clipboard.read();for(let l of o)for(let g of l.types)if(be(g)){let E=await l.getType(g);await ae(E);return}}}catch{}try{let o=await navigator.clipboard?.readText();o&&i.pasteText(Ee(o))}catch{}})(),!1):!0);let q=0;function Ee(n){return n.split(`\r
1
+ var wt="https://esm.sh/ghostty-web@0.4.0",bt=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function Z(t){return t.replace(bt,"")}var G;function Lt(){return G||(document.querySelector("link[data-tmux-web-xterm-css]")?G=Promise.resolve():(G=new Promise(t=>{let e=document.createElement("link");e.rel="stylesheet",e.href="/assets/xterm.css",e.setAttribute("data-tmux-web-xterm-css",""),e.addEventListener("load",()=>t(),{once:!0}),e.addEventListener("error",()=>t(),{once:!0}),document.head.appendChild(e)}),G))}var Se=class Ze{terminal;fitAddon;container;constructor(e,n,s){this.container=e,this.terminal=n,this.fitAddon=s,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,n,s){let[{Terminal:o},{FitAddon:l}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),Lt()]),d=new o({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:n,convertEol:!1,theme:s});return new Ze(e,d,new l)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(e){return new Promise(n=>this.terminal.write(e,n))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(e){this.terminal.scrollToLine(Math.max(0,e))}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){let e=He(this.container);return e.width<=0||e.height<=0?!1:(this.fitAddon.fit(),!0)}focus(){this.terminal.focus()}pasteText(e){this.terminal.paste(e)}input(e){this.terminal.input(e,!1)}onData(e){this.terminal.onData(e),this.terminal.onBinary(e)}onResize(e){this.terminal.onResize(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){let e=document.activeElement;return!!e&&(e===this.container||this.container.contains(e))}},Et=class Ge{terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(e,n){this.container=e,this.terminal=n,this.terminal.open(e)}static async create(e,n,s){let o=await import(wt);await o.init();let l=new o.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:n,convertEol:!1,theme:s});return new Ge(e,l)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(e){return new Promise(n=>this.terminal.write(e,n))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom?.()}scrollToLine(e){this.terminal.scrollToLine?.(Math.max(0,e))}isNearScrollbackTop(){let e=this.terminal.buffer?.active;return e?e.viewportY>=e.baseY:!1}viewportY(){return this.terminal.buffer?.active?.viewportY??0}baseY(){return this.terminal.buffer?.active?.baseY??0}fit(){let e=He(this.container);if(e.width<=0||e.height<=0)return!1;this.updateCellMetrics(!this.charW||!this.charH);let n=Math.floor(e.width/this.charW),s=Math.floor(e.height/this.charH);if(n<10||s<5)return!1;if(n!==this.colsValue||s!==this.rowsValue){this.colsValue=n,this.rowsValue=s,this.terminal.resize(n,s);for(let o of this.resizeCallbacks)o({cols:n,rows:s})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(e){let n=this.terminal.getMode?.(2004)??!1;this.input(n?"\x1B[200~"+e+"\x1B[201~":e)}input(e){this.terminal.input?.(e,!1)}onData(e){this.terminal.onData(n=>e(n))}onResize(e){this.resizeCallbacks.push(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){let e=document.activeElement;return!!e&&(e===this.container||e===this.terminal.textarea||this.container.contains(e))}updateCellMetrics(e=!1){let n=this.container.querySelector("canvas");if(n instanceof HTMLElement&&n.offsetWidth>0&&n.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){let s=n.offsetWidth/this.colsValue,o=n.offsetHeight/this.rowsValue;(e||!this.charW||!this.charH)&&(this.charW=s,this.charH=o)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}};function He(t){let e=t.getBoundingClientRect(),n=window.visualViewport;return n?{width:Math.min(e.width,n.width),height:Math.max(0,Math.min(e.height,n.height-Math.max(0,e.top)))}:e}function kt(t,e,n){return t.innerHTML="",t.classList.add("terminal-pending"),(async()=>{let s;if(n.renderer==="ghostty")try{s=await Et.create(t,n.scrollback,n.theme)}catch{console.error("[tmux-web] ghostty-web failed; falling back to xterm.js"),s=await Se.create(t,n.scrollback,n.theme)}else s=await Se.create(t,n.scrollback,n.theme);let o,l=0,d,r=null,v=0,y="connecting",T=0,K=!1,X=[],D="",pe=!1,A=1e3,Qe=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/"+encodeURIComponent(e),et="/api/session/"+encodeURIComponent(e)+"/upload",tt=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function nt(){return X.join("")+D}async function st(i,a=0){let c=i?s.viewportY():0,b=i?s.baseY():0,k=Z(nt());if(s.reset(),!k){i||s.scrollToBottom();return}await s.write(k),i?s.scrollToLine(b+c+a):s.scrollToBottom()}function R(i){o?.readyState===WebSocket.OPEN&&o.send(JSON.stringify(i))}function it(i){let a;try{a=JSON.parse(i)}catch{y==="live"&&(D+=i,s.write(Z(i)));return}if(a.type==="auth.required"){let c=localStorage.getItem("tmux-web-token");c?R({type:"auth.token",token:c}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(a.type==="auth.ok"){a.token&&localStorage.setItem("tmux-web-token",a.token),A=1e3,z(),R({type:"resize",cols:s.cols,rows:s.rows}),w();return}if(a.type==="auth.failed"){if(a.permanentLock||a.retryAfterMs&&a.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(a.message);return}return}if(a.type==="snapshot"&&typeof a.data=="string"){let c=Z(a.data);X=[c],D="",T=typeof a.lines=="number"?a.lines:n.terminal.initialLines,y="live",s.reset(),s.write(c).then(()=>s.scrollToBottom());return}if(a.type==="window_changed"&&typeof a.activeIndex=="number"){let c=new URL(location.href);c.searchParams.get("window")!==String(a.activeIndex)&&(c.searchParams.set("window",String(a.activeIndex)),history.replaceState(history.state,"",c)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:a.windows}));return}if(a.type==="history"&&typeof a.data=="string"){K=!1,a.lines>0&&a.data&&(X.unshift(a.data),T+=a.lines,st(!0,a.lines));return}if(a.type==="data"&&typeof a.data=="string"){let c=Z(a.data);if(y==="connecting"){y="live",D=c,s.write(c);return}y==="live"&&(D+=c,s.write(c))}}function be(){let i=Qe,a=localStorage.getItem("tmux-web-token");a&&(i+=(i.includes("?")?"&":"?")+"token="+encodeURIComponent(a)),o=new WebSocket(i),o.onopen=()=>{y="connecting",T=0,K=!1,X=[],D="",s.reset(),A=1e3},o.onmessage=c=>{typeof c.data=="string"&&it(c.data)},o.onclose=()=>{pe||(y="connecting",setTimeout(()=>{A=Math.min(A*2,1e4),pe||be()},A))},o.onerror=()=>o?.close()}function _(i){R({type:"input",data:i})}function z(){return s.fit()}function ue(){t.classList.remove("terminal-pending")}function w(){l&&cancelAnimationFrame(l),d&&clearTimeout(d),z(),l=requestAnimationFrame(()=>{l=0,z()&&ue()}),d=setTimeout(()=>{z()&&ue()},120)}function at(){w(),setTimeout(w,50),setTimeout(w,150),setTimeout(w,300)}function Le(i){return typeof i=="string"&&i.startsWith("image/")}function Ee(i){return i?.files?.length?i.files[0]??null:null}function ot(i){if(!i?.items)return null;for(let a=0;a<i.items.length;a++){let c=i.items[a];if(c?.kind==="file"&&Le(c.type))return c.getAsFile()}return null}async function lt(i){let a=new FormData,c=i instanceof File&&i.name?i.name:"upload";a.append("file",i,c);let b=localStorage.getItem("tmux-web-token"),k={};b&&(k.Authorization="Bearer "+b);let me=await fetch(et,{method:"POST",body:a,headers:k});if(!me.ok){let Ie="upload failed";try{let Ce=await me.json();Ce.error&&(Ie=Ce.error)}catch{}throw new Error(Ie)}let Be=await me.json();if(!Be.path)throw new Error("no path in response");return Be.path}async function fe(i){try{let a=await lt(i);_(a)}catch{}}s.onData(i=>_(i)),s.onResize(({cols:i,rows:a})=>R({type:"resize",cols:i,rows:a})),s.onScroll(()=>{y!=="live"||K||!s.isNearScrollbackTop()||(K=!0,R({type:"load_history",before:T}))}),s.attachCustomKeyEventHandler(i=>i.type!=="keydown"?!0:(i.ctrlKey||i.metaKey)&&i.code==="KeyV"?(i.preventDefault(),(async()=>{try{if(navigator.clipboard?.read){let a=await navigator.clipboard.read();for(let c of a)for(let b of c.types)if(Le(b)){let k=await c.getType(b);await fe(k);return}}}catch{}try{let a=await navigator.clipboard?.readText();a&&s.pasteText(ke(a))}catch{}})(),!1):!0);let J=0;function ke(i){return i.split(`\r
2
2
  `).join(`
3
3
  `).split(`
4
- `).join("\r")}async function Ge(n){let o=qe(n.clipboardData);if(o){n.preventDefault(),n.stopPropagation();let E=Date.now();if(E-q<50)return;q=E,await ae(o);return}let l=n.clipboardData?.getData("text/plain");if(!l)return;n.preventDefault(),n.stopPropagation();let g=Date.now();g-q<50||(q=g,i.pasteText(Ee(l)))}let F=0;function Je(n){n.preventDefault(),F++,we(n.dataTransfer)&&t.classList.add("terminal-drag-over")}function Ze(n){n.preventDefault(),n.dataTransfer&&(n.dataTransfer.dropEffect="copy")}function Qe(n){n.preventDefault(),F--,F<=0&&(F=0,t.classList.remove("terminal-drag-over"))}async function et(n){n.preventDefault(),F=0,t.classList.remove("terminal-drag-over");let o=we(n.dataTransfer);o&&await ae(o)}function Te(n){!We||n.key!=="Escape"||n.defaultPrevented||n.repeat||n.metaKey||n.ctrlKey||n.altKey||i.isFocused()&&(n.preventDefault(),n.stopPropagation(),$("\x1B"))}t.addEventListener("paste",Ge),t.addEventListener("dragenter",Je),t.addEventListener("dragover",Ze),t.addEventListener("dragleave",Qe),t.addEventListener("drop",et),document.addEventListener("keydown",Te,!0);function tt(n){if(n.touches.length!==1){a=null;return}let o=n.touches[0];o&&(a={startX:o.clientX,startY:o.clientY,lastX:o.clientX,lastY:o.clientY,scrolling:!1},n.stopPropagation())}function nt(n){if(!a||n.touches.length!==1)return;let o=n.touches[0];if(!o)return;let l=o.clientY-a.startY,g=o.clientX-a.startX;if(!a.scrolling){if(Math.abs(l)<8||Math.abs(l)<Math.abs(g))return;a.scrolling=!0,y=Date.now()+500}n.preventDefault(),n.stopPropagation(),rt(-(o.clientY-a.lastY),o.clientX,o.clientY),a.lastX=o.clientX,a.lastY=o.clientY}function st(n){if(!a)return;let o=a.scrolling;a=null,n.stopPropagation(),o?(y=Date.now()+500,n.preventDefault()):i.focus()}function it(n){a=null,n.stopPropagation()}function ot(n){n.pointerType==="touch"&&Date.now()<y&&(n.preventDefault(),n.stopPropagation())}function rt(n,o,l){(t.querySelector(".xterm-screen")??t).dispatchEvent(new WheelEvent("wheel",{deltaY:n,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:o,clientY:l,bubbles:!0,cancelable:!0}))}t.addEventListener("touchstart",tt,{passive:!0,capture:!0}),t.addEventListener("touchmove",nt,{passive:!1,capture:!0}),t.addEventListener("touchend",st,{passive:!1,capture:!0}),t.addEventListener("touchcancel",it,{passive:!0,capture:!0}),t.addEventListener("pointerup",ot,!0);function Le(){h()}window.addEventListener("resize",Le),window.visualViewport?.addEventListener("resize",h),window.visualViewport?.addEventListener("scroll",h);let ke=new ResizeObserver(()=>h());return ke.observe(t),document.fonts?.ready.then(()=>{h(),setTimeout(h,50),setTimeout(h,200)}),t.addEventListener("focusin",$e,!0),requestAnimationFrame(()=>{R()&&re(),ye(),h()}),{destroy(){if(oe=!0,r){try{r.close(1e3,"session switch")}catch{}r=void 0}t.innerHTML="",t.classList.remove("terminal-pending"),window.removeEventListener("resize",Le),ke.disconnect(),document.removeEventListener("keydown",Te,!0)},focus(){i.focus()},sendInput(n){$(n)}}})()}var Y=window.__TMUX_WEB_SHELL__,p=null,v=null,Re="sessions",x="",Q="",ee="",Fe="",u=document.getElementById("sidebar-content"),W=document.getElementById("main-placeholder"),C=document.getElementById("terminal-container"),se=document.getElementById("file-editor"),dt=document.getElementById("fe-path"),w=document.getElementById("fe-status"),j=document.getElementById("fe-content"),I=document.getElementById("fe-save"),ut=document.getElementById("fe-delete"),mt=document.getElementById("fe-back"),Be=document.getElementById("fe-new-name"),pt=document.getElementById("fe-new-btn"),de=document.getElementById("settings-backdrop"),Ae=document.getElementById("settings-popover"),ze=document.querySelector(".sidebar");function ft(){return window.matchMedia("(max-width: 640px)").matches}function ue(){ft()&&ze.classList.add("collapsed")}function Ye(){ze.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{Ye(),Ne("sessions")});document.getElementById("mode-files").addEventListener("click",()=>{Ye(),Ne("files")});function Ne(t){Re=t,document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));let e=document.getElementById(t==="sessions"?"mode-sessions":"mode-files");e&&e.classList.add("active"),t==="sessions"?_():wt()}async function _(){u.innerHTML='<div class="sidebar-section-label">Sessions</div><button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';try{let i=(await(await fetch("/api/sidebar/sessions")).json()).recent||[];for(let r of i){let c=document.createElement("div");c.className="session-item"+(r.name===v?" active":""),c.setAttribute("data-session",r.name),c.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${r.attached?"M19 4H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zm0 14H5V6h14v12z":"M4 6h16v2H4V6zm0 5h16v2H4v-2zm0 5h16v2H4v-2z"}"></svg>
5
- <span>${L(r.name)}</span>
6
- <button class="session-edit-btn" data-session="${L(r.name)}" title="Edit session"><svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg></button>
7
- `,c.addEventListener("click",a=>{a.target.closest(".session-edit-btn")||me(r.name)}),u.appendChild(c);let d=c.querySelector(".session-edit-btn");d&&d.addEventListener("click",a=>{a.stopPropagation(),Mt(r.name,d)})}}catch{u.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}let t=document.getElementById("ns-btn");t&&t.addEventListener("click",()=>document.getElementById("new-session-modal")?.classList.add("open"))}function L(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function me(t){if(!(v===t&&p)){se.style.display="none",W.style.display="none",C.style.display="",C.classList.add("terminal-pending"),ue(),p&&(he(),p.destroy(),p=null),v=t;for(let e of u.querySelectorAll(".session-item"))e.classList.toggle("active",e.getAttribute("data-session")===t);try{p=await Ie(C,t,{terminal:Y.terminal,scrollback:Y.scrollback,theme:Y.theme,renderer:Y.renderer}),bt()}catch(e){console.error("[shell] terminal init failed:",e);let s=e&&typeof e=="object"&&"message"in e?e.message:String(e);C.textContent="Failed to open terminal for "+t+": "+s,C.classList.remove("terminal-pending")}}}var J=[],m=null,He=!1;function ht(t){if(!m||!m.files.length)return null;let e=m.repoRoot;if(!e||!t.startsWith(e))return null;let s=t.slice(e.length+1);for(let i of m.files)if(i.path===s)return i.status;return null}async function gt(t){He=!0;try{let e=await fetch("/api/git/status?path="+encodeURIComponent(t));e.ok?m=await e.json():m=null}catch{m=null}finally{He=!1}}function vt(){if(!m||!m.branch)return"";let{branch:t,linesAdded:e,linesRemoved:s}=m,i="";return(e>0||s>0)&&(i=`<div class="git-diff-stats">+<span class="add">${e}</span> <span class="del">-${s}</span></div>`),`<div class="git-branch-badge">
8
- <svg viewBox="0 0 16 16" fill="currentColor"><path d="M11.63 1.22a.75.75 0 00-1.06 0L5.99 5.8 4.12 3.93a.75.75 0 10-1.06 1.06L4.93 6.87A3.5 3.5 0 003 10.09v3.16a.75.75 0 001 0v-3.16a2.5 2.5 0 012.5-2.5h.27l-1.06 1.06a.75.75 0 001.06 1.06l2.37-2.38a.75.75 0 000-1.06L7.59 5.27l4.04-4.05a.75.75 0 000-1.06L11.63 1.22zM3.25 13.94a.75.75 0 01-.75-.75v-.69a.75.75 0 011.5 0v.69c0 .414-.336.75-.75.75z"/></svg>
9
- ${L(t)}</div>${i}`}var O=document.getElementById("header-git"),te=null;function ne(t){if(!t||!t.branch){O.style.display="none",te=null;return}te=t.repoRoot;let{branch:e,linesAdded:s,linesRemoved:i}=t,r=`<span class="branch">${L(e)}</span>`;(s>0||i>0)&&(r+=`<span class="diff-stats"><span class="sep">\xB7</span>+<span class="diff-add">${s}</span> <span class="diff-del">-${i}</span></span>`),O.innerHTML=r,O.style.display="block"}O.addEventListener("click",t=>{te&&m&&m.files.length>0&&(t.stopPropagation(),yt())});var N=document.getElementById("git-popover"),pe=document.getElementById("git-popover-backdrop");function yt(){if(!m||!m.files.length)return;let t=m.files,e=`<div class="git-popover-header">${t.length} file${t.length>1?"s":""} changed</div>`;for(let r of t){let c=r.additions||0,d=r.deletions||0,a="";switch(r.status){case"M":a='<span class="git-file-status M">M</span>';break;case"A":a='<span class="git-file-status A">A</span>';break;case"D":a='<span class="git-file-status D">D</span>';break;case"?":a='<span class="git-file-status ?">?</span>';break;case"R":a='<span class="git-file-status R">R</span>';break}e+=`<div class="git-popover-item">
10
- ${a}<span class="file-path">${L(r.path)}</span>
11
- <span class="file-add">${c>0?"+"+c:""}</span>
12
- <span class="file-del">${d>0?"-"+d:""}</span>
13
- </div>`}e+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',N.innerHTML=e;let s=O.getBoundingClientRect();N.style.top=s.bottom+4+"px",N.style.left=Math.max(8,Math.min(s.left,window.innerWidth-400))+"px",N.classList.add("open"),pe.classList.add("open");let i=te;document.getElementById("git-popover-browse").addEventListener("click",()=>{if(fe(),i){Re="files",document.querySelectorAll(".mode-btn").forEach(c=>c.classList.remove("active"));let r=document.getElementById("mode-files");r&&r.classList.add("active"),S(i)}})}function fe(){N.classList.remove("open"),pe.classList.remove("open")}pe.addEventListener("click",fe);document.addEventListener("keydown",t=>{t.key==="Escape"&&(fe(),ie())});async function De(t){try{let s=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(t))).json();if(s.path){let i=await fetch("/api/git/status?path="+encodeURIComponent(s.path));if(i.ok){let r=await i.json();m=r,ne(r);return}}}catch{}m=null,ne(null)}var Z=null;function bt(){he(),v&&(De(v),Z=setInterval(()=>{v&&De(v)},3e4))}function he(){Z&&(clearInterval(Z),Z=null)}function wt(){if(J=Y.fsRoots||[],J.length===0){if(v){Et(v);return}u.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}u.innerHTML="";for(let t of J){let e=document.createElement("div");e.className="file-tree-item",e.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor" class="file-icon"><path d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg> ${L(t)}`,e.addEventListener("click",()=>S(t)),u.appendChild(e)}}async function Et(t){u.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let s=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(t))).json();s.path?S(s.path):u.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{u.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function S(t){x=t,u.innerHTML='<div class="file-tree-empty">Loading...</div>';let e=gt(t);try{let i=await(await fetch("/api/fs/list?path="+encodeURIComponent(t))).json();await e,u.innerHTML="",ne(m),u.innerHTML+=vt();let r=Tt(t);if(r&&!J.some(a=>t===a)){let a=document.createElement("div");a.className="file-tree-item",a.innerHTML="..",a.addEventListener("click",()=>S(r)),u.appendChild(a)}if(i.dirs)for(let d of i.dirs){let a=d.split("/").pop()||d.split("\\").pop(),y=document.createElement("div");y.className="file-tree-item",y.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor" class="file-icon"><path d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg> ${L(a)}`,y.addEventListener("click",()=>S(d)),u.appendChild(y)}else u.innerHTML="";let c=i.files||[];for(let d of c){let a=d.split("/").pop()||d.split("\\").pop(),y=ht(d),f="",b="";if(y)switch(y){case"M":f="git-mod",b='<span class="git-file-status M">M</span>';break;case"A":f="git-add",b='<span class="git-file-status A">A</span>';break;case"D":f="git-del",b='<span class="git-file-status D">D</span>';break;case"?":f="git-untracked",b='<span class="git-file-status ?">?</span>';break;case"R":f="git-mod",b='<span class="git-file-status R">R</span>';break}let k=document.createElement("div");k.className="file-tree-item file"+(f?" "+f:""),k.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${b}${L(a)}`,k.addEventListener("click",()=>Lt(d)),u.appendChild(k)}}catch{u.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function Tt(t){let e=t.lastIndexOf("/");return e<=0?null:t.substring(0,e)}async function Lt(t){Q=t,C.style.display="none",p&&(he(),p.destroy(),p=null,v=null),ne(null),ue(),W.style.display="none",se.style.display="flex",dt.textContent=t,w.textContent="Loading...",I.style.display="none";try{let e=await fetch("/api/file?path="+encodeURIComponent(t));if(!e.ok){let i=await e.json();w.textContent=i.error||"Failed to load",j.value="";return}let s=await e.json();j.value=s.content,ee=s.content,Fe=s.content,w.textContent=s.size+" bytes",I.style.display=""}catch{w.textContent="Failed to load",j.value=""}}j.addEventListener("input",()=>{ee=j.value});I.addEventListener("click",async()=>{I.textContent="Saving...",I.disabled=!0;try{let t=await fetch("/api/file",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Q,content:ee})});if(!t.ok){let e=await t.json();w.textContent=e.error||"Save failed";return}Fe=ee,w.textContent="Saved"}catch{w.textContent="Save failed"}finally{I.disabled=!1,I.textContent="Save"}});ut.addEventListener("click",async()=>{if(confirm("Delete "+Q+"?"))try{let t=await fetch("/api/file/delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Q})});if(!t.ok){let e=await t.json();w.textContent=e.error||"Delete failed";return}se.style.display="none",W.style.display="flex",x&&S(x)}catch{w.textContent="Delete failed"}});mt.addEventListener("click",()=>{se.style.display="none",W.style.display="flex",x&&S(x)});pt.addEventListener("click",async()=>{let t=Be.value.trim();if(!t)return;let e=x+"/"+t;try{let s=await fetch("/api/file/touch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})});if(!s.ok){let i=await s.json();w.textContent=i.error||"Create failed";return}Be.value="",x&&S(x)}catch{w.textContent="Create failed"}});document.getElementById("mode-settings").addEventListener("click",()=>{let t=Ae.classList.toggle("open");de.classList.toggle("open",t)});de.addEventListener("click",()=>{Ae.classList.remove("open"),de.classList.remove("open")});var B="",K=document.createElement("div");K.className="session-popover-backdrop";document.body.appendChild(K);var M=document.createElement("div");M.id="session-popover";M.className="session-popover";M.style.display="none";M.innerHTML=`<div class="sp-field">
4
+ `).join("\r")}async function rt(i){let a=ot(i.clipboardData);if(a){i.preventDefault(),i.stopPropagation();let k=Date.now();if(k-J<50)return;J=k,await fe(a);return}let c=i.clipboardData?.getData("text/plain");if(!c)return;i.preventDefault(),i.stopPropagation();let b=Date.now();b-J<50||(J=b,s.pasteText(ke(c)))}let P=0;function ct(i){i.preventDefault(),P++,Ee(i.dataTransfer)&&t.classList.add("terminal-drag-over")}function dt(i){i.preventDefault(),i.dataTransfer&&(i.dataTransfer.dropEffect="copy")}function pt(i){i.preventDefault(),P--,P<=0&&(P=0,t.classList.remove("terminal-drag-over"))}async function ut(i){i.preventDefault(),P=0,t.classList.remove("terminal-drag-over");let a=Ee(i.dataTransfer);a&&await fe(a)}function xe(i){!tt||i.key!=="Escape"||i.defaultPrevented||i.repeat||i.metaKey||i.ctrlKey||i.altKey||s.isFocused()&&(i.preventDefault(),i.stopPropagation(),_("\x1B"))}t.addEventListener("paste",rt),t.addEventListener("dragenter",ct),t.addEventListener("dragover",dt),t.addEventListener("dragleave",pt),t.addEventListener("drop",ut),document.addEventListener("keydown",xe,!0);function ft(i){if(i.touches.length!==1){r=null;return}let a=i.touches[0];a&&(r={startX:a.clientX,startY:a.clientY,lastX:a.clientX,lastY:a.clientY,scrolling:!1},i.stopPropagation())}function mt(i){if(!r||i.touches.length!==1)return;let a=i.touches[0];if(!a)return;let c=a.clientY-r.startY,b=a.clientX-r.startX;if(!r.scrolling){if(Math.abs(c)<8||Math.abs(c)<Math.abs(b))return;r.scrolling=!0,v=Date.now()+500}i.preventDefault(),i.stopPropagation(),gt(-(a.clientY-r.lastY),a.clientX,a.clientY),r.lastX=a.clientX,r.lastY=a.clientY}function ht(i){if(!r)return;let a=r.scrolling;r=null,i.stopPropagation(),a?(v=Date.now()+500,i.preventDefault()):s.focus()}function vt(i){r=null,i.stopPropagation()}function yt(i){i.pointerType==="touch"&&Date.now()<v&&(i.preventDefault(),i.stopPropagation())}function gt(i,a,c){(t.querySelector(".xterm-screen")??t).dispatchEvent(new WheelEvent("wheel",{deltaY:i,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:a,clientY:c,bubbles:!0,cancelable:!0}))}t.addEventListener("touchstart",ft,{passive:!0,capture:!0}),t.addEventListener("touchmove",mt,{passive:!1,capture:!0}),t.addEventListener("touchend",ht,{passive:!1,capture:!0}),t.addEventListener("touchcancel",vt,{passive:!0,capture:!0}),t.addEventListener("pointerup",yt,!0);function Te(){w()}window.addEventListener("resize",Te),window.visualViewport?.addEventListener("resize",w),window.visualViewport?.addEventListener("scroll",w);let Me=new ResizeObserver(()=>w());return Me.observe(t),document.fonts?.ready.then(()=>{w(),setTimeout(w,50),setTimeout(w,200)}),t.addEventListener("focusin",at,!0),requestAnimationFrame(()=>{z()&&ue(),be(),w()}),{destroy(){if(pe=!0,o){try{o.close(1e3,"session switch")}catch{}o=void 0}t.innerHTML="",t.classList.remove("terminal-pending"),window.removeEventListener("resize",Te),Me.disconnect(),document.removeEventListener("keydown",xe,!0)},focus(){s.focus()},sendInput(i){_(i)}}})()}var W=window.__TMUX_WEB_SHELL__,u=null,h=null,De="sessions",B="",Q="",ee="",$e="",f=document.getElementById("sidebar-content"),C=document.getElementById("main-placeholder"),L=document.getElementById("terminal-container"),j=document.getElementById("file-editor"),xt=document.getElementById("fe-path"),E=document.getElementById("fe-status"),N=document.getElementById("fe-content"),S=document.getElementById("fe-save"),Tt=document.getElementById("fe-delete"),Mt=document.getElementById("fe-back"),Ae=document.getElementById("fe-new-name"),Bt=document.getElementById("fe-new-btn"),he=document.getElementById("settings-backdrop"),Re=document.getElementById("settings-popover"),ze=document.querySelector(".sidebar");function It(){return window.matchMedia("(max-width: 640px)").matches}function ve(){It()&&ze.classList.add("collapsed")}function Pe(){ze.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{Pe(),We("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{Pe(),We("files")});function We(t){De=t,document.querySelectorAll(".mode-btn").forEach(n=>n.classList.remove("active"));let e=document.getElementById(t==="sessions"?"mode-sessions":"mode-files");e&&e.classList.add("active"),t==="sessions"?Y():Pt()}async function Y(){f.innerHTML='<div class="sidebar-section-label">Sessions</div><button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';try{let e=(await(await fetch("/api/sidebar/sessions")).json()).recent||[];for(let n of e){let s=document.createElement("div");s.className="session-item"+(n.name===h?" active":""),s.setAttribute("data-session",n.name),s.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${n.attached?"M19 4H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zm0 14H5V6h14v12z":"M4 6h16v2H4V6zm0 5h16v2H4v-2zm0 5h16v2H4v-2z"}"></svg>
5
+ <span>${p(n.name)}</span>
6
+ <button class="session-edit-btn" data-session="${p(n.name)}" title="Edit session"><svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg></button>
7
+ `,s.addEventListener("click",l=>{l.target.closest(".session-edit-btn")||te(n.name)}),f.appendChild(s);let o=s.querySelector(".session-edit-btn");o&&o.addEventListener("click",l=>{l.stopPropagation(),Ft(n.name,o)})}}catch{f.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}let t=document.getElementById("ns-btn");t&&t.addEventListener("click",()=>document.getElementById("new-session-modal")?.classList.add("open"))}function p(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function te(t){if(!(h===t&&u)){j.style.display="none",C.style.display="none",L.style.display="",L.classList.add("terminal-pending"),ve(),u&&(ce(),u.destroy(),u=null),h=t;for(let e of f.querySelectorAll(".session-item"))e.classList.toggle("active",e.getAttribute("data-session")===t);try{u=await kt(L,t,{terminal:W.terminal,scrollback:W.scrollback,theme:W.theme,renderer:W.renderer}),Xe()}catch(e){console.error("[shell] terminal init failed:",e);let n=e&&typeof e=="object"&&"message"in e?e.message:String(e);L.textContent="Failed to open terminal for "+t+": "+n,L.classList.remove("terminal-pending")}}}var ne=[],m=null,je=!1;function Ct(t){if(!m||!m.files.length)return null;let e=m.repoRoot;if(!e||!t.startsWith(e))return null;let n=t.slice(e.length+1);for(let s of m.files)if(s.path===n)return s.status;return null}async function St(t){je=!0;try{let e=await fetch("/api/git/status?path="+encodeURIComponent(t));e.ok?m=await e.json():m=null}catch{m=null}finally{je=!1}}function Ht(){if(!m||!m.branch)return"";let{branch:t,linesAdded:e,linesRemoved:n}=m,s=`<div class="sidebar-git"><div class="git-branch-badge">
8
+ <svg viewBox="0 0 16 16" fill="currentColor"><path d="M11.63 1.22a.75.75 0 00-1.06 0L5.99 5.8 4.12 3.93a.75.75 0 10-1.06 1.06L4.93 6.87A3.5 3.5 0 003 10.09v3.16a.75.75 0 001 0v-3.16a2.5 2.5 0 012.5-2.5h.27l-1.06 1.06a.75.75 0 001.06 1.06l2.37-2.38a.75.75 0 000-1.06L7.59 5.27l4.04-4.05a.75.75 0 000-1.06L11.63 1.22zM3.25 13.94a.75.75 0 01-.75-.75v-.69a.75.75 0 011.5 0v.69c0 .414-.336.75-.75.75z"/></svg>
9
+ ${p(t)}</div>`;return(e>0||n>0)&&(s+=`<div class="git-diff-stats">+<span class="add">${e}</span> <span class="del">-${n}</span></div>`),s+"</div>"}f.addEventListener("click",t=>{t.target.closest(".sidebar-git")&&$&&m&&(t.stopPropagation(),Oe())});var F=document.getElementById("header-git"),Ne=document.getElementById("git-diff-view"),Ye=document.getElementById("gd-path"),se=document.getElementById("gd-status"),ie=document.getElementById("gd-content"),Dt=document.getElementById("gd-back"),$=null;function V(t){if(!t||!t.branch){F.style.display="none",$=null;return}$=t.repoRoot;let{branch:e,linesAdded:n,linesRemoved:s}=t,o=`<span class="branch">${p(e)}</span>`;(n>0||s>0)&&(o+=`<span class="sep">\xB7</span>+<span class="diff-add">${n}</span> <span class="diff-del">-${s}</span>`),F.innerHTML=o,F.style.display="block"}F.addEventListener("click",t=>{$&&m&&(t.stopPropagation(),Oe())});var g=document.getElementById("git-popover"),ae=document.getElementById("git-popover-backdrop");function ye(){let t=F.getBoundingClientRect();g.style.top=t.bottom+4+"px",g.style.left=Math.max(8,Math.min(t.left,window.innerWidth-400))+"px"}function Fe(){let t=$,e=document.getElementById("git-popover-browse");e&&e.addEventListener("click",()=>{if(le(),t){De="files",document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));let n=document.getElementById("mode-files");n&&n.classList.add("active"),I(t)}})}var Ve="";function Oe(){if(!m)return;let t=m.files||[];if(!t.length)g.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
10
+ <div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>`;else{let e=`<div class="git-popover-header">${t.length} file${t.length>1?"s":""} changed</div>`;for(let n=0;n<t.length;n++){let s=t[n],o=s.additions||0,l=s.deletions||0,d="";switch(s.status){case"M":d='<span class="git-file-status M">M</span>';break;case"A":d='<span class="git-file-status A">A</span>';break;case"D":d='<span class="git-file-status D">D</span>';break;case"?":d='<span class="git-file-status ?">?</span>';break;case"R":d='<span class="git-file-status R">R</span>';break}e+=`<div class="git-popover-item" data-idx="${n}">
11
+ ${d}<span class="file-path">${p(s.path)}</span>
12
+ <span class="file-add">${o>0?"+"+o:""}</span>
13
+ <span class="file-del">${l>0?"-"+l:""}</span>
14
+ </div>`}e+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',Ve=e,g.innerHTML=e,g.querySelectorAll(".git-popover-item").forEach(n=>{let s=parseInt(n.dataset.idx||"0",10),o=t[s];!o||o.status==="D"||(n.classList.add("clickable"),n.style.cursor="pointer",n.addEventListener("click",()=>Ue(o.path)))})}ye(),g.classList.add("open"),ae.classList.add("open"),Fe()}function $t(){return window.innerWidth>=1024}function qe(t,e){let n=(t+(e&&t?`
15
+ `:"")+e).split(`
16
+ `),s="",o=0,l=0;for(let d of n){let r=d;if(r.startsWith("@@")){let v=r.match(/@@\s+-(\d+)[^+]*\+(\d+)/);v&&(o=parseInt(v[1],10)-1,l=parseInt(v[2],10)-1),s+=`<div class="diff-line hunk"><span class="ln-body">${p(r)}</span></div>`;continue}if(r.startsWith("diff --git")||r.startsWith("index ")||r.startsWith("--- ")||r.startsWith("+++ ")||r.startsWith("new file")||r.startsWith("deleted file")){r.startsWith("diff --git")&&(s+=`<div class="diff-line header"><span class="ln-body">${p(r)}</span></div>`);continue}if(r.startsWith("+"))l++,s+=`<div class="diff-line add"><span class="ln-no">${l}</span><span class="ln-body">${p(r)}</span></div>`;else if(r.startsWith("-"))o++,s+=`<div class="diff-line del"><span class="ln-no">${o}</span><span class="ln-body">${p(r)}</span></div>`;else if(r.startsWith("\\"))s+=`<div class="diff-line"><span class="ln-body">${p(r)}</span></div>`;else{if(!r&&!o&&!l)continue;o++,l++,s+=`<div class="diff-line"><span class="ln-no">${o}</span><span class="ln-no" style="margin-right:12px">${l}</span><span class="ln-body">${p(r)}</span></div>`}}return{html:s,lineCount:n.length}}var oe=null;async function Ue(t){let e=$;if(e)if(le(),$t()){L.style.display="none",u&&(ce(),u.destroy(),u=null,oe=h,h=null),V(null),j.style.display="none",C.style.display="none",Ne.style.display="flex",Ye.textContent=t,se.textContent="Loading\u2026",ie.innerHTML="";try{let n=await fetch("/api/git/diff?path="+encodeURIComponent(e)+"&file="+encodeURIComponent(t));if(!n.ok)throw new Error(await n.text());let s=await n.json();Rt(t,s.diff,s.stagedDiff)}catch(n){let s=n instanceof Error?n.message:String(n);se.textContent="Error",ie.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${p(s)}</div>`}}else{g.innerHTML=`<div class="git-diff-view"><div class="diff-header">
17
+ <button class="diff-back">\u2190 Back</button>
18
+ <span class="diff-filename">${p(t)}</span>
19
+ <span class="diff-loading">Loading\u2026</span>
20
+ </div></div>`,ye(),g.classList.add("open"),ae.classList.add("open");try{let n=await fetch("/api/git/diff?path="+encodeURIComponent(e)+"&file="+encodeURIComponent(t));if(!n.ok)throw new Error(await n.text());let s=await n.json();At(t,s.diff,s.stagedDiff)}catch(n){let s=n instanceof Error?n.message:String(n);g.innerHTML=`<div class="git-diff-view"><div class="diff-header">
21
+ <button class="diff-back">\u2190 Back</button>
22
+ <span class="diff-filename">${p(t)}</span>
23
+ </div><div class="diff-empty">Error loading diff: ${p(s)}</div></div>`}}}function At(t,e,n){if(!e&&!n){g.innerHTML=`<div class="git-diff-view"><div class="diff-header">
24
+ <button class="diff-back">\u2190 Back</button>
25
+ <span class="diff-filename">${p(t)}</span>
26
+ </div><div class="diff-empty">No diff content available</div></div>`;return}let{html:s,lineCount:o}=qe(e,n);g.innerHTML=`<div class="git-diff-view"><div class="diff-header">
27
+ <button class="diff-back">\u2190 Back</button>
28
+ <span class="diff-filename">${p(t)}</span>
29
+ <span class="diff-filesize">${o} lines</span>
30
+ </div><div class="diff-content">${s}</div></div>`,g.querySelector(".diff-back")?.addEventListener("click",()=>{g.innerHTML=Ve,ye(),m&&g.querySelectorAll(".git-popover-item").forEach(l=>{let d=parseInt(l.dataset.idx||"0",10),r=m.files[d];!r||r.status==="D"||(l.style.cursor="pointer",l.addEventListener("click",()=>Ue(r.path)))}),Fe()})}function Rt(t,e,n){if(!e&&!n){se.textContent="No diff",ie.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}let{html:s,lineCount:o}=qe(e,n);Ye.textContent=t,se.textContent=o+" lines",ie.innerHTML=s}function zt(){Ne.style.display="none",oe?(L.style.display="",L.classList.add("terminal-pending"),te(oe),oe=null):h?(L.style.display="",L.classList.add("terminal-pending"),Xe()):C.style.display="flex"}Dt.addEventListener("click",zt);function le(){g.classList.remove("open"),ae.classList.remove("open")}ae.addEventListener("click",le),document.addEventListener("keydown",t=>{t.key==="Escape"&&(le(),de())});async function Ke(t){try{let e=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(t))).json();if(e.path){let n=await fetch("/api/git/status?path="+encodeURIComponent(e.path));if(n.ok){let s=await n.json();m=s,V(s);return}}}catch{}m=null,V(null)}var re=null;function Xe(){ce(),h&&(Ke(h),re=setInterval(()=>{h&&Ke(h)},3e4))}function ce(){re&&(clearInterval(re),re=null)}function Pt(){if(ne=W.fsRoots||[],ne.length===0){if(h){Wt(h);return}f.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}f.innerHTML="";for(let t of ne){let e=document.createElement("div");e.className="file-tree-item",e.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor" class="file-icon"><path d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg> ${p(t)}`,e.addEventListener("click",()=>I(t)),f.appendChild(e)}}async function Wt(t){f.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let e=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(t))).json();e.path?I(e.path):f.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{f.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function I(t){B=t,f.innerHTML='<div class="file-tree-empty">Loading...</div>';let e=St(t);try{let n=await(await fetch("/api/fs/list?path="+encodeURIComponent(t))).json();await e,f.innerHTML="",V(m),f.innerHTML+=Ht();let s=jt(t);if(s&&!ne.some(l=>t===l)){let l=document.createElement("div");l.className="file-tree-item",l.innerHTML="..",l.addEventListener("click",()=>I(s)),f.appendChild(l)}if(n.dirs)for(let l of n.dirs){let d=l.split("/").pop()||l.split("\\").pop(),r=document.createElement("div");r.className="file-tree-item",r.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor" class="file-icon"><path d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg> ${p(d)}`,r.addEventListener("click",()=>I(l)),f.appendChild(r)}else f.innerHTML="";let o=n.files||[];for(let l of o){let d=l.split("/").pop()||l.split("\\").pop(),r=Ct(l),v="",y="";if(r)switch(r){case"M":v="git-mod",y='<span class="git-file-status M">M</span>';break;case"A":v="git-add",y='<span class="git-file-status A">A</span>';break;case"D":v="git-del",y='<span class="git-file-status D">D</span>';break;case"?":v="git-untracked",y='<span class="git-file-status ?">?</span>';break;case"R":v="git-mod",y='<span class="git-file-status R">R</span>';break}let T=document.createElement("div");T.className="file-tree-item file"+(v?" "+v:""),T.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${y}${p(d)}`,T.addEventListener("click",()=>Nt(l)),f.appendChild(T)}}catch{f.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function jt(t){let e=t.lastIndexOf("/");return e<=0?null:t.substring(0,e)}async function Nt(t){Q=t,L.style.display="none",u&&(ce(),u.destroy(),u=null,h=null),V(null),ve(),C.style.display="none",j.style.display="flex",xt.textContent=t,E.textContent="Loading...",S.style.display="none";try{let e=await fetch("/api/file?path="+encodeURIComponent(t));if(!e.ok){let s=await e.json();E.textContent=s.error||"Failed to load",N.value="";return}let n=await e.json();N.value=n.content,ee=n.content,$e=n.content,E.textContent=n.size+" bytes",S.style.display=""}catch{E.textContent="Failed to load",N.value=""}}N.addEventListener("input",()=>{ee=N.value}),S.addEventListener("click",async()=>{S.textContent="Saving...",S.disabled=!0;try{let t=await fetch("/api/file",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Q,content:ee})});if(!t.ok){let e=await t.json();E.textContent=e.error||"Save failed";return}$e=ee,E.textContent="Saved"}catch{E.textContent="Save failed"}finally{S.disabled=!1,S.textContent="Save"}}),Tt.addEventListener("click",async()=>{if(confirm("Delete "+Q+"?"))try{let t=await fetch("/api/file/delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Q})});if(!t.ok){let e=await t.json();E.textContent=e.error||"Delete failed";return}j.style.display="none",C.style.display="flex",B&&I(B)}catch{E.textContent="Delete failed"}}),Mt.addEventListener("click",()=>{j.style.display="none",C.style.display="flex",B&&I(B)}),Bt.addEventListener("click",async()=>{let t=Ae.value.trim();if(!t)return;let e=B+"/"+t;try{let n=await fetch("/api/file/touch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})});if(!n.ok){let s=await n.json();E.textContent=s.error||"Create failed";return}Ae.value="",B&&I(B)}catch{E.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{let t=Re.classList.toggle("open");he.classList.toggle("open",t)}),he.addEventListener("click",()=>{Re.classList.remove("open"),he.classList.remove("open")});var H="",O=document.createElement("div");O.className="session-popover-backdrop",document.body.appendChild(O);var M=document.createElement("div");M.id="session-popover",M.className="session-popover",M.style.display="none",M.innerHTML=`<div class="sp-field">
14
31
  <label>Rename session</label>
15
32
  <input type="text" id="sp-name" />
16
33
  </div>
@@ -19,5 +36,5 @@ var at="https://esm.sh/ghostty-web@0.4.0",lt=/\x1b\](?:10|11|110|111|104)(?:;[^\
19
36
  <button class="btn" id="sp-cancel">Cancel</button>
20
37
  </div>
21
38
  <hr class="sp-divider" />
22
- <button class="btn danger" id="sp-delete">Delete session</button>`;document.body.appendChild(M);function kt(t){let e=t.getBoundingClientRect();M.style.top=e.bottom+4+"px",M.style.left=Math.max(8,Math.min(e.left,window.innerWidth-240))+"px"}function Mt(t,e){B=t;let s=document.getElementById("sp-name");s.value=t,K.classList.add("open"),M.style.display="block",kt(e),setTimeout(()=>s.focus(),50)}function V(){K.classList.remove("open"),M.style.display="none"}K.addEventListener("click",V);document.getElementById("sp-save").addEventListener("click",async()=>{let t=document.getElementById("sp-name").value.trim();if(!t||t===B){V();return}try{if(!(await fetch("/api/sessions/rename",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:B,newName:t})})).ok)return;V(),_(),v===B&&me(t)}catch{}});document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+B+'"?'))try{if(!(await fetch("/api/sessions/kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:B})})).ok)return;V(),v===B&&(p&&(p.destroy(),p=null),v=null,C.style.display="none",W.style.display="flex"),_()}catch{}});document.getElementById("sp-cancel").addEventListener("click",V);var xt={esc:"\x1B",tab:" ","s-tab":"\x1B[Z",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",space:" ",enter:"\r",exit:"exit\r",yes:"yes\r"};document.getElementById("mobile-keys").addEventListener("click",t=>{let e=t.target.closest("button[data-key]");if(!e||!p)return;let s=xt[e.dataset.key];s&&(p.sendInput(s),p.focus())});var T=document.getElementById("mk-input"),Pe=document.getElementById("mk-send");function je(){if(!T||!p)return;let t=T.value;t&&(p.sendInput(t+"\r"),T.value="",T.rows=1,p.focus())}T&&(T.addEventListener("input",()=>{T.rows=1;let t=T.value.split(`
23
- `).length;T.rows=Math.min(t,4)}),T.addEventListener("keydown",t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),je())}));Pe&&Pe.addEventListener("click",je);if(window.visualViewport){let t=document.querySelector(".app-layout"),e=()=>{t&&(t.style.height=window.visualViewport.height+"px"),window.scrollTo(0,0),document.documentElement.scrollTop=0,document.body.scrollTop=0};window.visualViewport.addEventListener("resize",e),window.addEventListener("orientationchange",()=>setTimeout(e,100)),document.addEventListener("touchstart",()=>{(window.scrollY>0||document.documentElement.scrollTop>0)&&window.scrollTo(0,0)},{passive:!0})}var ge=document.getElementById("process-panel"),z=document.getElementById("proc-list"),St=document.getElementById("proc-close"),ve=document.getElementById("proc-backdrop"),Ct=document.getElementById("header-ram");function It(){z.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch("/api/system/processes").then(t=>t.json()).then(t=>{if(!Array.isArray(t)||!t.length){z.innerHTML='<div class="proc-empty">No processes</div>';return}let e="";for(let s of t){let i=s.rss,r=i<1048576?(i/1024).toFixed(0)+"K":(i/1048576).toFixed(1)+"M";e+='<div class="proc-row" data-pid="'+s.pid+'"><span class="proc-mem">'+s.mem+'%</span><span class="proc-rss">'+r+'</span><span class="proc-cmd" title="'+L(s.command)+'">'+L(s.command)+'</span><button class="proc-kill" title="Kill PID '+s.pid+'">&times;</button></div>'}z.innerHTML=e;for(let s of z.querySelectorAll(".proc-row")){let i=s.querySelector(".proc-kill");i&&i.addEventListener("click",r=>{let c=r.target.closest(".proc-row");!c||!confirm("Kill PID "+c.dataset.pid+"?")||fetch("/api/system/kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(c.dataset.pid,10)})}).then(d=>d.json()).then(d=>{d.ok?c.style.opacity="0.3":alert("Failed: "+(d.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{z.innerHTML='<div class="proc-empty">Failed to load</div>'})}function Bt(){ge.classList.add("open"),ve.classList.add("open"),It()}function ie(){ge.classList.remove("open"),ve.classList.remove("open")}Ct.addEventListener("click",t=>{t.stopPropagation(),ge.classList.contains("open")?ie():Bt()});St.addEventListener("click",ie);ve.addEventListener("click",ie);window.__openSession=me;window.__refreshSidebar=_;_();ue();
39
+ <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(M);function Yt(t){let e=t.getBoundingClientRect();M.style.top=e.bottom+4+"px",M.style.left=Math.max(8,Math.min(e.left,window.innerWidth-240))+"px"}function Ft(t,e){H=t;let n=document.getElementById("sp-name");n.value=t,O.classList.add("open"),M.style.display="block",Yt(e),setTimeout(()=>n.focus(),50)}function q(){O.classList.remove("open"),M.style.display="none"}O.addEventListener("click",q),document.getElementById("sp-save").addEventListener("click",async()=>{let t=document.getElementById("sp-name").value.trim();if(!t||t===H){q();return}try{if(!(await fetch("/api/sessions/rename",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:H,newName:t})})).ok)return;q(),Y(),h===H&&te(t)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+H+'"?'))try{if(!(await fetch("/api/sessions/kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:H})})).ok)return;q(),h===H&&(u&&(u.destroy(),u=null),h=null,L.style.display="none",C.style.display="flex"),Y()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",q);var Vt={esc:"\x1B",tab:" ","s-tab":"\x1B[Z",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",space:" ",enter:"\r",exit:"exit\r",yes:"yes\r"};document.getElementById("mobile-keys").addEventListener("click",t=>{let e=t.target.closest("button[data-key]");if(!e||!u)return;let n=Vt[e.dataset.key];n&&(u.sendInput(n),u.focus())});var x=document.getElementById("mk-input"),_e=document.getElementById("mk-send");function Je(){if(!x||!u)return;let t=x.value;t&&(u.sendInput(t+"\r"),x.value="",x.rows=1,u.focus())}if(x&&(x.addEventListener("input",()=>{x.rows=1;let t=x.value.split(`
40
+ `).length;x.rows=Math.min(t,4)}),x.addEventListener("keydown",t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),Je())})),_e&&_e.addEventListener("click",Je),window.visualViewport){let t=document.querySelector(".app-layout"),e=()=>{t&&(t.style.height=window.visualViewport.height+"px"),window.scrollTo(0,0),document.documentElement.scrollTop=0,document.body.scrollTop=0};window.visualViewport.addEventListener("resize",e),window.addEventListener("orientationchange",()=>setTimeout(e,100)),document.addEventListener("touchstart",()=>{(window.scrollY>0||document.documentElement.scrollTop>0)&&window.scrollTo(0,0)},{passive:!0})}var ge=document.getElementById("process-panel"),U=document.getElementById("proc-list"),Ot=document.getElementById("proc-close"),we=document.getElementById("proc-backdrop"),qt=document.getElementById("header-ram");function Ut(){U.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch("/api/system/processes").then(t=>t.json()).then(t=>{if(!Array.isArray(t)||!t.length){U.innerHTML='<div class="proc-empty">No processes</div>';return}let e="";for(let n of t){let s=n.rss,o=s<1048576?(s/1024).toFixed(0)+"K":(s/1048576).toFixed(1)+"M";e+='<div class="proc-row" data-pid="'+n.pid+'"><span class="proc-mem">'+n.mem+'%</span><span class="proc-rss">'+o+'</span><span class="proc-cmd" title="'+p(n.command)+'">'+p(n.command)+'</span><button class="proc-kill" title="Kill PID '+n.pid+'">&times;</button></div>'}U.innerHTML=e;for(let n of U.querySelectorAll(".proc-row")){let s=n.querySelector(".proc-kill");s&&s.addEventListener("click",o=>{let l=o.target.closest(".proc-row");!l||!confirm("Kill PID "+l.dataset.pid+"?")||fetch("/api/system/kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(l.dataset.pid,10)})}).then(d=>d.json()).then(d=>{d.ok?l.style.opacity="0.3":alert("Failed: "+(d.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{U.innerHTML='<div class="proc-empty">Failed to load</div>'})}function Kt(){ge.classList.add("open"),we.classList.add("open"),Ut()}function de(){ge.classList.remove("open"),we.classList.remove("open")}qt.addEventListener("click",t=>{t.stopPropagation(),ge.classList.contains("open")?de():Kt()}),Ot.addEventListener("click",de),we.addEventListener("click",de),window.__openSession=te,window.__refreshSidebar=Y,Y(),ve();