tmux-weblink 1.3.0 → 1.4.1

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 (74) hide show
  1. package/dist/assets/addon-fit-D5N335P2.js +3 -2
  2. package/dist/assets/shell-client.js +13 -7
  3. package/dist/assets/xterm-BXEES47M.js +15 -14
  4. package/dist/browser/shell-client.js +790 -6
  5. package/dist/browser/terminal-core.js +640 -4
  6. package/dist/frontend.js +9 -1
  7. package/dist/index.js +1646 -9
  8. package/dist/lib/agent-detect.js +249 -3
  9. package/dist/lib/agents-watch.js +2 -2
  10. package/dist/lib/atomicWrite.js +24 -1
  11. package/dist/lib/auditLog.js +40 -1
  12. package/dist/lib/auth.js +194 -2
  13. package/dist/lib/cli.js +162 -10
  14. package/dist/lib/commandbar.js +47 -17
  15. package/dist/lib/db.js +8 -1
  16. package/dist/lib/drawer-resize.js +25 -10
  17. package/dist/lib/drawer-script.js +13 -6
  18. package/dist/lib/ext-loader.js +168 -1
  19. package/dist/lib/fs-access.js +58 -1
  20. package/dist/lib/html.js +11 -1
  21. package/dist/lib/icons.js +73 -1
  22. package/dist/lib/image-upload.js +87 -1
  23. package/dist/lib/load-env.js +76 -6
  24. package/dist/lib/notes-db.js +4 -2
  25. package/dist/lib/notes-drawer.js +29 -12
  26. package/dist/lib/notes-utils.js +4 -2
  27. package/dist/lib/pages/files-index.js +26 -18
  28. package/dist/lib/pages/history-index.js +59 -17
  29. package/dist/lib/pages/login.js +35 -13
  30. package/dist/lib/pages/notes-index.js +45 -20
  31. package/dist/lib/pages/notes-page.js +28 -13
  32. package/dist/lib/pages/quick-commands.js +38 -22
  33. package/dist/lib/pages/schedule-index.js +81 -45
  34. package/dist/lib/pages/settings.js +76 -30
  35. package/dist/lib/pages/shell.js +269 -214
  36. package/dist/lib/pinned-views.js +38 -1
  37. package/dist/lib/plugins.js +108 -3
  38. package/dist/lib/quick-commands.js +79 -1
  39. package/dist/lib/rateLimiter.js +142 -2
  40. package/dist/lib/schedule-delay.js +36 -2
  41. package/dist/lib/scheduler-drawer.js +30 -14
  42. package/dist/lib/scheduler.js +263 -1
  43. package/dist/lib/security-config.js +65 -2
  44. package/dist/lib/session-access.js +19 -1
  45. package/dist/lib/session-windows.js +41 -1
  46. package/dist/lib/sessions-drawer.js +30 -16
  47. package/dist/lib/sessions-sidebar.js +50 -1
  48. package/dist/lib/settings.js +16 -2
  49. package/dist/lib/setup-features.js +37 -1
  50. package/dist/lib/setup-prompts.js +50 -3
  51. package/dist/lib/shared-layout.js +115 -51
  52. package/dist/lib/state-paths.js +41 -1
  53. package/dist/lib/system-monitor.js +98 -2
  54. package/dist/lib/terminal-config.js +14 -1
  55. package/dist/lib/theme-store.js +53 -2
  56. package/dist/lib/theme.js +15 -12
  57. package/dist/lib/themes/dark-cove.js +40 -1
  58. package/dist/lib/themes/ghostty.js +40 -1
  59. package/dist/lib/themes/index.js +28 -1
  60. package/dist/lib/themes/types.js +1 -0
  61. package/dist/lib/themes/vscode.js +40 -1
  62. package/dist/lib/themes/warm-clay.js +40 -1
  63. package/dist/lib/tmux-capture.js +71 -5
  64. package/dist/lib/tmux-control.js +153 -2
  65. package/dist/lib/tmux-panes.js +40 -2
  66. package/dist/lib/tmux-windows.js +149 -4
  67. package/dist/lib/watched-panes.js +1 -1
  68. package/dist/lib/window-history.js +32 -1
  69. package/dist/lib/window-labels.js +27 -1
  70. package/dist/lib/windows-drawer.js +21 -10
  71. package/dist/lib/ws-message.js +21 -1
  72. package/dist/sessions.js +21 -2
  73. package/package.json +6 -4
  74. package/scripts/generate-icons.mjs +167 -0
@@ -1,4 +1,5 @@
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:
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:
2
3
 
3
4
  @xterm/addon-fit/lib/addon-fit.mjs:
4
5
  (**
@@ -13,4 +14,4 @@ var p=2,c=1,d=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.pro
13
14
  * http://bellard.org/jslinux/
14
15
  * Copyright (c) 2011 Fabrice Bellard
15
16
  *)
16
- */export{d as FitAddon};
17
+ */
@@ -1,10 +1,16 @@
1
- var Ke="https://esm.sh/ghostty-web@0.4.0",Xe=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function W(t){return t.replace(Xe,"")}var q;function _e(){return q||(document.querySelector("link[data-tmux-web-xterm-css]")?q=Promise.resolve():(q=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)}),q))}var pe=class xe{terminal;fitAddon;container;constructor(e,a,s){this.container=e,this.terminal=a,this.fitAddon=s,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,a,s){let[{Terminal:o},{FitAddon:d}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),_e()]),u=new o({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:a,convertEol:!1,theme:s});return new xe(e,u,new d)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(e){return new Promise(a=>this.terminal.write(e,a))}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))}},Ue=class ke{terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(e,a){this.container=e,this.terminal=a,this.terminal.open(e)}static async create(e,a,s){let o=await import(Ke);await o.init();let d=new o.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:a,convertEol:!1,theme:s});return new ke(e,d)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(e){return new Promise(a=>this.terminal.write(e,a))}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 a=Math.floor(e.width/this.charW),s=Math.floor(e.height/this.charH);if(a<10||s<5)return!1;if(a!==this.colsValue||s!==this.rowsValue){this.colsValue=a,this.rowsValue=s,this.terminal.resize(a,s);for(let o of this.resizeCallbacks)o({cols:a,rows:s})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(e){let a=this.terminal.getMode?.(2004)??!1;this.input(a?"\x1B[200~"+e+"\x1B[201~":e)}input(e){this.terminal.input?.(e,!1)}onData(e){this.terminal.onData(a=>e(a))}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 a=this.container.querySelector("canvas");if(a instanceof HTMLElement&&a.offsetWidth>0&&a.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){let s=a.offsetWidth/this.colsValue,o=a.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(),a=window.visualViewport;return a?{width:Math.min(e.width,a.width),height:Math.max(0,Math.min(e.height,a.height-Math.max(0,e.top)))}:e}function Je(t,e,a){return t.innerHTML="",t.classList.add("terminal-pending"),(async()=>{let s;if(a.renderer==="ghostty")try{s=await Ue.create(t,a.scrollback,a.theme)}catch{console.error("[tmux-web] ghostty-web failed; falling back to xterm.js"),s=await pe.create(t,a.scrollback,a.theme)}else s=await pe.create(t,a.scrollback,a.theme);let o,d=0,u,m=null,J=0,b="connecting",A=0,N=!1,j=[],C="",$=!1,B=1e3,Te=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/"+encodeURIComponent(e),Ce="/api/session/"+encodeURIComponent(e)+"/upload",Be=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function Se(){return j.join("")+C}async function Me(n,i=0){let r=n?s.viewportY():0,h=n?s.baseY():0,v=W(Se());if(s.reset(),!v){n||s.scrollToBottom();return}await s.write(v),n?s.scrollToLine(h+r+i):s.scrollToBottom()}function S(n){o?.readyState===WebSocket.OPEN&&o.send(JSON.stringify(n))}function Ie(n){let i;try{i=JSON.parse(n)}catch{b==="live"&&(C+=n,s.write(W(n)));return}if(i.type==="auth.required"){let r=localStorage.getItem("tmux-web-token");r?S({type:"auth.token",token:r}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(i.type==="auth.ok"){i.token&&localStorage.setItem("tmux-web-token",i.token),B=1e3,M(),S({type:"resize",cols:s.cols,rows:s.rows}),p();return}if(i.type==="auth.failed"){if(i.permanentLock||i.retryAfterMs&&i.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(i.message);return}return}if(i.type==="snapshot"&&typeof i.data=="string"){let r=W(i.data);j=[r],C="",A=typeof i.lines=="number"?i.lines:a.terminal.initialLines,b="live",s.reset(),s.write(r).then(()=>s.scrollToBottom());return}if(i.type==="window_changed"&&typeof i.activeIndex=="number"){let r=new URL(location.href);r.searchParams.get("window")!==String(i.activeIndex)&&(r.searchParams.set("window",String(i.activeIndex)),history.replaceState(history.state,"",r)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:i.windows}));return}if(i.type==="history"&&typeof i.data=="string"){N=!1,i.lines>0&&i.data&&(j.unshift(i.data),A+=i.lines,Me(!0,i.lines));return}if(i.type==="data"&&typeof i.data=="string"){let r=W(i.data);if(b==="connecting"){b="live",C=r,s.write(r);return}b==="live"&&(C+=r,s.write(r))}}function ie(){let n=Te,i=localStorage.getItem("tmux-web-token");i&&(n+=(n.includes("?")?"&":"?")+"token="+encodeURIComponent(i)),o=new WebSocket(n),o.onopen=()=>{b="connecting",A=0,N=!1,j=[],C="",s.reset(),B=1e3},o.onmessage=r=>{typeof r.data=="string"&&Ie(r.data)},o.onclose=()=>{$||(b="connecting",setTimeout(()=>{B=Math.min(B*2,1e4),$||ie()},B))},o.onerror=()=>o?.close()}function R(n){S({type:"input",data:n})}function M(){return s.fit()}function Z(){t.classList.remove("terminal-pending")}function p(){d&&cancelAnimationFrame(d),u&&clearTimeout(u),M(),d=requestAnimationFrame(()=>{d=0,M()&&Z()}),u=setTimeout(()=>{M()&&Z()},120)}function He(){p(),setTimeout(p,50),setTimeout(p,150),setTimeout(p,300)}function ae(n){return typeof n=="string"&&n.startsWith("image/")}function se(n){return n?.files?.length?n.files[0]??null:null}function De(n){if(!n?.items)return null;for(let i=0;i<n.items.length;i++){let r=n.items[i];if(r?.kind==="file"&&ae(r.type))return r.getAsFile()}return null}async function ze(n){let i=new FormData,r=n instanceof File&&n.name?n.name:"upload";i.append("file",n,r);let h=localStorage.getItem("tmux-web-token"),v={};h&&(v.Authorization="Bearer "+h);let Q=await fetch(Ce,{method:"POST",body:i,headers:v});if(!Q.ok){let ue="upload failed";try{let me=await Q.json();me.error&&(ue=me.error)}catch{}throw new Error(ue)}let de=await Q.json();if(!de.path)throw new Error("no path in response");return de.path}async function G(n){try{let i=await ze(n);R(i)}catch{}}s.onData(n=>R(n)),s.onResize(({cols:n,rows:i})=>S({type:"resize",cols:n,rows:i})),s.onScroll(()=>{b!=="live"||N||!s.isNearScrollbackTop()||(N=!0,S({type:"load_history",before:A}))}),s.attachCustomKeyEventHandler(n=>n.type!=="keydown"?!0:(n.ctrlKey||n.metaKey)&&n.code==="KeyV"?(n.preventDefault(),(async()=>{try{if(navigator.clipboard?.read){let i=await navigator.clipboard.read();for(let r of i)for(let h of r.types)if(ae(h)){let v=await r.getType(h);await G(v);return}}}catch{}try{let i=await navigator.clipboard?.readText();i&&s.pasteText(oe(i))}catch{}})(),!1):!0);let O=0;function oe(n){return n.split(`\r
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
2
2
  `).join(`
3
3
  `).split(`
4
- `).join("\r")}async function Ye(n){let i=De(n.clipboardData);if(i){n.preventDefault(),n.stopPropagation();let v=Date.now();if(v-O<50)return;O=v,await G(i);return}let r=n.clipboardData?.getData("text/plain");if(!r)return;n.preventDefault(),n.stopPropagation();let h=Date.now();h-O<50||(O=h,s.pasteText(oe(r)))}let I=0;function Pe(n){n.preventDefault(),I++,se(n.dataTransfer)&&t.classList.add("terminal-drag-over")}function Ve(n){n.preventDefault(),n.dataTransfer&&(n.dataTransfer.dropEffect="copy")}function Fe(n){n.preventDefault(),I--,I<=0&&(I=0,t.classList.remove("terminal-drag-over"))}async function Ae(n){n.preventDefault(),I=0,t.classList.remove("terminal-drag-over");let i=se(n.dataTransfer);i&&await G(i)}function re(n){!Be||n.key!=="Escape"||n.defaultPrevented||n.repeat||n.metaKey||n.ctrlKey||n.altKey||s.isFocused()&&(n.preventDefault(),n.stopPropagation(),R("\x1B"))}t.addEventListener("paste",Ye),t.addEventListener("dragenter",Pe),t.addEventListener("dragover",Ve),t.addEventListener("dragleave",Fe),t.addEventListener("drop",Ae),document.addEventListener("keydown",re,!0);function Ne(n){if(n.touches.length!==1){m=null;return}let i=n.touches[0];i&&(m={startX:i.clientX,startY:i.clientY,lastX:i.clientX,lastY:i.clientY,scrolling:!1},n.stopPropagation())}function je(n){if(!m||n.touches.length!==1)return;let i=n.touches[0];if(!i)return;let r=i.clientY-m.startY,h=i.clientX-m.startX;if(!m.scrolling){if(Math.abs(r)<8||Math.abs(r)<Math.abs(h))return;m.scrolling=!0,J=Date.now()+500}n.preventDefault(),n.stopPropagation(),qe(-(i.clientY-m.lastY),i.clientX,i.clientY),m.lastX=i.clientX,m.lastY=i.clientY}function Re(n){if(!m)return;let i=m.scrolling;m=null,n.stopPropagation(),i?(J=Date.now()+500,n.preventDefault()):s.focus()}function Oe(n){m=null,n.stopPropagation()}function We(n){n.pointerType==="touch"&&Date.now()<J&&(n.preventDefault(),n.stopPropagation())}function qe(n,i,r){(t.querySelector(".xterm-screen")??t).dispatchEvent(new WheelEvent("wheel",{deltaY:n,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:i,clientY:r,bubbles:!0,cancelable:!0}))}t.addEventListener("touchstart",Ne,{passive:!0,capture:!0}),t.addEventListener("touchmove",je,{passive:!1,capture:!0}),t.addEventListener("touchend",Re,{passive:!1,capture:!0}),t.addEventListener("touchcancel",Oe,{passive:!0,capture:!0}),t.addEventListener("pointerup",We,!0);function le(){p()}window.addEventListener("resize",le),window.visualViewport?.addEventListener("resize",p),window.visualViewport?.addEventListener("scroll",p);let ce=new ResizeObserver(()=>p());return ce.observe(t),document.fonts?.ready.then(()=>{p(),setTimeout(p,50),setTimeout(p,200)}),t.addEventListener("focusin",He,!0),requestAnimationFrame(()=>{M()&&Z(),ie(),p()}),{destroy(){if($=!0,o){try{o.close(1e3,"session switch")}catch{}o=void 0}t.innerHTML="",t.classList.remove("terminal-pending"),window.removeEventListener("resize",le),ce.disconnect(),document.removeEventListener("keydown",re,!0)},focus(){s.focus()},sendInput(n){R(n)}}})()}var H=window.__TMUX_WEB_SHELL__,l=null,w=null,$e="sessions",E="",K="",X="",fe="",c=document.getElementById("sidebar-content"),D=document.getElementById("main-placeholder"),L=document.getElementById("terminal-container"),_=document.getElementById("file-editor"),Ze=document.getElementById("fe-path"),f=document.getElementById("fe-status"),z=document.getElementById("fe-content"),x=document.getElementById("fe-save"),Ge=document.getElementById("fe-delete"),Qe=document.getElementById("fe-back"),ve=document.getElementById("fe-new-name"),et=document.getElementById("fe-new-btn"),ee=document.getElementById("settings-backdrop"),ye=document.getElementById("settings-popover"),we=document.querySelector(".sidebar");function tt(){return window.matchMedia("(max-width: 640px)").matches}function te(){tt()&&we.classList.add("collapsed")}function ge(){we.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{ge(),be("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{ge(),be("files")});function be(t){$e=t,document.querySelectorAll(".mode-btn").forEach(a=>a.classList.remove("active"));let e=document.getElementById(t==="sessions"?"mode-sessions":"mode-files");e&&e.classList.add("active"),t==="sessions"?Y():nt()}async function Y(){c.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 a of e){let s=document.createElement("div");s.className="session-item"+(a.name===w?" active":""),s.setAttribute("data-session",a.name),s.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${a.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(a.name)}</span>
6
- <button class="session-edit-btn" data-session="${P(a.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",d=>{d.target.closest(".session-edit-btn")||ne(a.name)}),c.appendChild(s);let o=s.querySelector(".session-edit-btn");o&&o.addEventListener("click",d=>{d.stopPropagation(),rt(a.name,o)})}}catch{c.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 ne(t){if(!(w===t&&l)){_.style.display="none",D.style.display="none",L.style.display="",L.classList.add("terminal-pending"),te(),l&&(l.destroy(),l=null),w=t;for(let e of c.querySelectorAll(".session-item"))e.classList.toggle("active",e.getAttribute("data-session")===t);try{l=await Je(L,t,{terminal:H.terminal,scrollback:H.scrollback,theme:H.theme,renderer:H.renderer})}catch(e){console.error("[shell] terminal init failed:",e);let a=e&&typeof e=="object"&&"message"in e?e.message:String(e);L.textContent="Failed to open terminal for "+t+": "+a,L.classList.remove("terminal-pending")}}}var U=[];function nt(){if(U=H.fsRoots||[],U.length===0){if(w){it(w);return}c.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}c.innerHTML="";for(let t of U){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",()=>k(t)),c.appendChild(e)}}async function it(t){c.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let e=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(t))).json();e.path?k(e.path):c.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{c.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function k(t){E=t,c.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let e=await(await fetch("/api/fs/list?path="+encodeURIComponent(t))).json();c.innerHTML="";let a=at(t);if(a&&!U.some(o=>t===o)){let o=document.createElement("div");o.className="file-tree-item",o.innerHTML="..",o.addEventListener("click",()=>k(a)),c.appendChild(o)}if(e.dirs)for(let o of e.dirs){let d=o.split("/").pop()||o.split("\\").pop(),u=document.createElement("div");u.className="file-tree-item",u.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)}`,u.addEventListener("click",()=>k(o)),c.appendChild(u)}else c.innerHTML="";let s=e.files||[];for(let o of s){let d=o.split("/").pop()||o.split("\\").pop(),u=document.createElement("div");u.className="file-tree-item file",u.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${P(d)}`,u.addEventListener("click",()=>st(o)),c.appendChild(u)}}catch{c.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function at(t){let e=t.lastIndexOf("/");return e<=0?null:t.substring(0,e)}async function st(t){K=t,L.style.display="none",l&&(l.destroy(),l=null,w=null),te(),D.style.display="none",_.style.display="flex",Ze.textContent=t,f.textContent="Loading...",x.style.display="none";try{let e=await fetch("/api/file?path="+encodeURIComponent(t));if(!e.ok){let s=await e.json();f.textContent=s.error||"Failed to load",z.value="";return}let a=await e.json();z.value=a.content,X=a.content,fe=a.content,f.textContent=a.size+" bytes",x.style.display=""}catch{f.textContent="Failed to load",z.value=""}}z.addEventListener("input",()=>{X=z.value}),x.addEventListener("click",async()=>{x.textContent="Saving...",x.disabled=!0;try{let t=await fetch("/api/file",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:K,content:X})});if(!t.ok){let e=await t.json();f.textContent=e.error||"Save failed";return}fe=X,f.textContent="Saved"}catch{f.textContent="Save failed"}finally{x.disabled=!1,x.textContent="Save"}}),Ge.addEventListener("click",async()=>{if(confirm("Delete "+K+"?"))try{let t=await fetch("/api/file/delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:K})});if(!t.ok){let e=await t.json();f.textContent=e.error||"Delete failed";return}_.style.display="none",D.style.display="flex",E&&k(E)}catch{f.textContent="Delete failed"}}),Qe.addEventListener("click",()=>{_.style.display="none",D.style.display="flex",E&&k(E)}),et.addEventListener("click",async()=>{let t=ve.value.trim();if(!t)return;let e=E+"/"+t;try{let a=await fetch("/api/file/touch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})});if(!a.ok){let s=await a.json();f.textContent=s.error||"Create failed";return}ve.value="",E&&k(E)}catch{f.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{let t=ye.classList.toggle("open");ee.classList.toggle("open",t)}),ee.addEventListener("click",()=>{ye.classList.remove("open"),ee.classList.remove("open")});var T="",V=document.createElement("div");V.className="session-popover-backdrop",document.body.appendChild(V);var g=document.createElement("div");g.id="session-popover",g.className="session-popover",g.style.display="none",g.innerHTML=`<div class="sp-field">
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">
8
14
  <label>Rename session</label>
9
15
  <input type="text" id="sp-name" />
10
16
  </div>
@@ -13,5 +19,5 @@ var Ke="https://esm.sh/ghostty-web@0.4.0",Xe=/\x1b\](?:10|11|110|111|104)(?:;[^\
13
19
  <button class="btn" id="sp-cancel">Cancel</button>
14
20
  </div>
15
21
  <hr class="sp-divider" />
16
- <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(g);function ot(t){let e=t.getBoundingClientRect();g.style.top=e.bottom+4+"px",g.style.left=Math.max(8,Math.min(e.left,window.innerWidth-240))+"px"}function rt(t,e){T=t;let a=document.getElementById("sp-name");a.value=t,V.classList.add("open"),g.style.display="block",ot(e),setTimeout(()=>a.focus(),50)}function F(){V.classList.remove("open"),g.style.display="none"}V.addEventListener("click",F),document.getElementById("sp-save").addEventListener("click",async()=>{let t=document.getElementById("sp-name").value.trim();if(!t||t===T){F();return}try{if(!(await fetch("/api/sessions/rename",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:T,newName:t})})).ok)return;F(),Y(),w===T&&ne(t)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+T+'"?'))try{if(!(await fetch("/api/sessions/kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:T})})).ok)return;F(),w===T&&(l&&(l.destroy(),l=null),w=null,L.style.display="none",D.style.display="flex"),Y()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",F);var lt={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||!l)return;let a=lt[e.dataset.key];a&&(l.sendInput(a),l.focus())});var y=document.getElementById("mk-input"),Ee=document.getElementById("mk-send");function Le(){if(!y||!l)return;let t=y.value;t&&(l.sendInput(t+"\r"),y.value="",y.rows=1,l.focus())}if(y&&(y.addEventListener("input",()=>{y.rows=1;let t=y.value.split(`
17
- `).length;y.rows=Math.min(t,4)}),y.addEventListener("keydown",t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),Le())})),Ee&&Ee.addEventListener("click",Le),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})}window.__openSession=ne,window.__refreshSidebar=Y,Y(),te();
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();