tmux-weblink 2.0.7 → 2.0.9

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.
@@ -1,38 +1,40 @@
1
- var Vt="https://esm.sh/ghostty-web@0.4.0",_t=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function Z(t){return t.replace(_t,"")}var pe;function Ft(){return pe||(document.querySelector("link[data-tmux-web-xterm-css]")?pe=Promise.resolve():(pe=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)}),pe))}var Oe=class vt{terminal;fitAddon;container;constructor(e,n,i){this.container=e,this.terminal=n,this.fitAddon=i,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,n,i){let[{Terminal:o},{FitAddon:r}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),Ft()]),c=new o({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:n,convertEol:!1,theme:i});return new vt(e,c,new r)}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=qe(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))}getScreenText(){return this.getRowsText(0,this.terminal.rows-1)}getRowsText(e,n){let i=this.terminal.buffer.active,[o,r]=e<=n?[e,n]:[n,e],c=i.viewportY,l=[];for(let u=o;u<=r;u++){let p=i.getLine(c+u);l.push(p?p.translateToString(!0):"")}return l.join(`
2
- `)}selectRows(e,n){let i=this.terminal.buffer.active,[o,r]=e<=n?[e,n]:[n,e];this.terminal.selectLines(i.viewportY+o,i.viewportY+r)}hasSelectionSupport(){return!0}},Kt=class yt{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,i){let o=await import(Vt);await o.init();let r=new o.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:n,convertEol:!1,theme:i});return new yt(e,r)}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=qe(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),i=Math.floor(e.height/this.charH);if(n<10||i<5)return!1;if(n!==this.colsValue||i!==this.rowsValue){this.colsValue=n,this.rowsValue=i,this.terminal.resize(n,i);for(let o of this.resizeCallbacks)o({cols:n,rows:i})}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))}getScreenText(){return this.getRowsText(0,this.rowsValue-1)}getRowsText(e,n){try{let i=this.terminal.buffer?.active;if(!i||typeof i.getLine!="function")return"";let[o,r]=e<=n?[e,n]:[n,e],c=typeof i.viewportY=="number"?i.viewportY:0,l=[];for(let u=o;u<=r;u++){let p=i.getLine(c+u);l.push(typeof p?.translateToString=="function"?p.translateToString(!0):"")}return l.join(`
3
- `)}catch{return""}}selectRows(e,n){try{if(typeof this.terminal?.selectLines!="function")return;let i=this.terminal.buffer?.active,o=typeof i?.viewportY=="number"?i.viewportY:0,[r,c]=e<=n?[e,n]:[n,e];this.terminal.selectLines(o+r,o+c)}catch{}}hasSelectionSupport(){return typeof this.terminal?.selectLines=="function"}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 i=n.offsetWidth/this.colsValue,o=n.offsetHeight/this.rowsValue;(e||!this.charW||!this.charH)&&(this.charW=i,this.charH=o)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}};function qe(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 Ut(t,e,n){return t.innerHTML="",t.classList.add("terminal-pending"),(async()=>{let i;if(n.renderer==="ghostty")try{i=await Kt.create(t,n.scrollback,n.theme)}catch{console.error("[tmux-web] ghostty-web failed; falling back to xterm.js"),i=await Oe.create(t,n.scrollback,n.theme)}else i=await Oe.create(t,n.scrollback,n.theme);let o,r=0,c,l=null,u=0,p="connecting",B=0,oe=!1,le=[],z="",N=!1,V=1e3,gt=location.protocol==="https:"?"wss:":"ws:",wt=n.wsBase||"/ws",bt=gt+"//"+location.host+wt+"/"+encodeURIComponent(e),Et="/api/session/"+encodeURIComponent(e)+"/upload",Lt=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function kt(){return le.join("")+z}async function xt(a,s=0){let d=a?i.viewportY():0,L=a?i.baseY():0,C=Z(kt());if(i.reset(),!C){a||i.scrollToBottom();return}await i.write(C),a?i.scrollToLine(L+d+s):i.scrollToBottom()}function _(a){o?.readyState===WebSocket.OPEN&&o.send(JSON.stringify(a))}function Tt(a){let s;try{s=JSON.parse(a)}catch{p==="live"&&(z+=a,i.write(Z(a)));return}if(s.type==="auth.required"){let d=localStorage.getItem("tmux-web-token");d?_({type:"auth.token",token:d}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(s.type==="attach_failed"&&typeof s.message=="string"){re=!0,p="dead",i.reset(),i.write(`\r
4
- \x1B[31m`+Z(s.message)+`\x1B[0m\r
5
- `).then(()=>{de();try{o?.close()}catch{}});return}if(s.type==="auth.ok"){s.token&&localStorage.setItem("tmux-web-token",s.token),V=1e3,F(),_({type:"resize",cols:i.cols,rows:i.rows}),b();return}if(s.type==="auth.failed"){if(s.permanentLock||s.retryAfterMs&&s.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(s.message);return}return}if(s.type==="snapshot"&&typeof s.data=="string"){let d=Z(s.data);le=[d],z="",B=typeof s.lines=="number"?s.lines:n.terminal.initialLines,p="live",i.reset(),i.write(d).then(()=>i.scrollToBottom());return}if(s.type==="window_changed"&&typeof s.activeIndex=="number"){let d=new URL(location.href);d.searchParams.get("window")!==String(s.activeIndex)&&(d.searchParams.set("window",String(s.activeIndex)),history.replaceState(history.state,"",d)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:s.windows}));return}if(s.type==="history"&&typeof s.data=="string"){oe=!1,s.lines>0&&s.data&&(le.unshift(s.data),B+=s.lines,xt(!0,s.lines));return}if(s.type==="data"&&typeof s.data=="string"){let d=Z(s.data);if(p==="connecting"){p="live",z=d,i.write(d);return}p==="live"&&(z+=d,i.write(d))}}let re=!1;function Re(){if(re)return;let a=bt,s=localStorage.getItem("tmux-web-token");s&&(a+=(a.includes("?")?"&":"?")+"token="+encodeURIComponent(s)),o=new WebSocket(a),o.onopen=()=>{p="connecting",B=0,oe=!1,le=[],z="",i.reset(),V=1e3},o.onmessage=d=>{typeof d.data=="string"&&Tt(d.data)},o.onclose=()=>{N||(p="connecting",!re&&setTimeout(()=>{V=Math.min(V*2,1e4),!N&&!re&&Re()},V))},o.onerror=()=>o?.close()}function ce(a){_({type:"input",data:a})}function F(){return i.fit()}function de(){t.classList.remove("terminal-pending")}function b(){r&&cancelAnimationFrame(r),c&&clearTimeout(c),F(),r=requestAnimationFrame(()=>{r=0,F()&&de()}),c=setTimeout(()=>{F()&&de()},120)}function Ct(){b(),setTimeout(b,50),setTimeout(b,150),setTimeout(b,300)}function Ae(a){return typeof a=="string"&&a.startsWith("image/")}function $e(a){return a?.files?.length?a.files[0]??null:null}function Mt(a){if(!a?.items)return null;for(let s=0;s<a.items.length;s++){let d=a.items[s];if(d?.kind==="file"&&Ae(d.type))return d.getAsFile()}return null}async function Bt(a){let s=new FormData,d=a instanceof File&&a.name?a.name:"upload";s.append("file",a,d);let L=localStorage.getItem("tmux-web-token"),C={};L&&(C.Authorization="Bearer "+L);let Me=await fetch(Et,{method:"POST",body:s,headers:C});if(!Me.ok){let Ke="upload failed";try{let Ue=await Me.json();Ue.error&&(Ke=Ue.error)}catch{}throw new Error(Ke)}let Fe=await Me.json();if(!Fe.path)throw new Error("no path in response");return Fe.path}async function xe(a){try{let s=await Bt(a);ce(s)}catch{}}i.onData(a=>ce(a)),i.onResize(({cols:a,rows:s})=>_({type:"resize",cols:a,rows:s})),i.onScroll(()=>{p!=="live"||oe||!i.isNearScrollbackTop()||(oe=!0,_({type:"load_history",before:B}))});let K=!1,U=!1,x=null,D=null,O=document.createElement("div");O.className="terminal-copy-banner",O.innerHTML='<strong>Copy mode</strong><span class="hint">drag to select \xB7 Esc exits</span>',O.hidden=!0,t.appendChild(O);let P=document.createElement("div");P.className="terminal-copy-banner terminal-copy-toast",P.textContent="Copied",P.hidden=!0,t.appendChild(P);function ze(a){let s=t.getBoundingClientRect(),d=s.height>0&&i.rows>0?s.height/i.rows:18;return Math.max(0,Math.min(i.rows-1,Math.floor((a-s.top)/d)))}async function Ne(a){if(!a)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(a);return}}catch{}let s=document.createElement("textarea");s.value=a,s.style.position="fixed",s.style.opacity="0",s.style.pointerEvents="none",document.body.appendChild(s),s.focus(),s.select();try{document.execCommand("copy")}catch{}s.remove()}let q;function Pe(){P.hidden=!1,q&&clearTimeout(q),q=setTimeout(()=>{P.hidden=!0},1e3)}function X(a){K=a,O.hidden=!a,t.classList.toggle("terminal-copy-mode-active",a),a&&i.focus()}function Ye(){X(!K)}function It(){return x===null||D===null?null:x<=D?[x,D]:[D,x]}function St(a){N||a.button!==0||U||(K||a.shiftKey)&&(a.preventDefault(),a.stopPropagation(),U=!0,x=ze(a.clientY),D=x,i.selectRows(x,x),document.addEventListener("mousemove",Te,!0),document.addEventListener("mouseup",Ce,!0))}function Te(a){N||!U||x===null||(a.preventDefault(),a.stopPropagation(),D=ze(a.clientY),i.selectRows(x,D))}function Ce(a){if(N||!U||x===null)return;a.preventDefault(),a.stopPropagation();let s=It();document.removeEventListener("mousemove",Te,!0),document.removeEventListener("mouseup",Ce,!0),U=!1,X(!1),s&&(Ne(i.getRowsText(s[0],s[1])).then(Pe),i.focus())}t.addEventListener("mousedown",St,!0),i.attachCustomKeyEventHandler(a=>{if(a.type!=="keydown")return!0;if(K){if(a.key==="Escape")return a.preventDefault(),X(!1),!1;if(a.key==="Enter"||(a.ctrlKey||a.metaKey)&&a.code==="KeyC")return a.preventDefault(),Ne(i.getScreenText()).then(Pe),X(!1),!1}return a.altKey&&a.code==="KeyC"&&!a.ctrlKey&&!a.metaKey?(a.preventDefault(),Ye(),!1):(a.ctrlKey||a.metaKey)&&a.code==="KeyV"?(a.preventDefault(),(async()=>{try{if(navigator.clipboard?.read){let s=await navigator.clipboard.read();for(let d of s)for(let L of d.types)if(Ae(L)){let C=await d.getType(L);await xe(C);return}}}catch{}try{let s=await navigator.clipboard?.readText();s&&i.pasteText(We(s))}catch{}})(),!1):!0});let ue=0;function We(a){return a.split(`\r
1
+ var Ft="https://esm.sh/ghostty-web@0.4.0",Vt=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function ie(n){return n.replace(Vt,"")}var ge;function _t(){return ge||(document.querySelector("link[data-tmux-web-xterm-css]")?ge=Promise.resolve():(ge=new Promise(n=>{let e=document.createElement("link");e.rel="stylesheet",e.href="/assets/xterm.css",e.setAttribute("data-tmux-web-xterm-css",""),e.addEventListener("load",()=>n(),{once:!0}),e.addEventListener("error",()=>n(),{once:!0}),document.head.appendChild(e)}),ge))}var Je=class wt{terminal;fitAddon;container;constructor(e,t,i){this.container=e,this.terminal=t,this.fitAddon=i,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,t,i){let[{Terminal:a},{FitAddon:l}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),_t()]),c=new a({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:t,convertEol:!1,theme:i});return new wt(e,c,new l)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(e){return new Promise(t=>this.terminal.write(e,t))}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=Ze(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||e===this.terminal.textarea||this.container.contains(e)||!!e.closest?.(".xterm"):!1}getScreenText(){return this.getRowsText(0,this.terminal.rows-1)}getRowsText(e,t){let i=this.terminal.buffer.active,[a,l]=e<=t?[e,t]:[t,e],c=i.viewportY,r=[];for(let d=a;d<=l;d++){let p=i.getLine(c+d);r.push(p?p.translateToString(!0):"")}return r.join(`
2
+ `)}selectRows(e,t){let i=this.terminal.buffer.active,[a,l]=e<=t?[e,t]:[t,e];this.terminal.selectLines(i.viewportY+a,i.viewportY+l)}selectCells(e,t,i,a){let l=this.terminal.buffer.active,c=Math.min(t,a),r=Math.max(t,a);if(c===r){let d=Math.min(e,i),p=Math.max(e,i);this.terminal.select(d,l.viewportY+c,p-d+1)}else this.terminal.selectLines(l.viewportY+c,l.viewportY+r)}getCellsText(e,t,i,a){let l=this.terminal.buffer.active,c=Math.min(t,a),r=Math.max(t,a),d=t<a?e:t>a?i:Math.min(e,i),p=t<a?i:t>a?e:Math.max(e,i),b=l.viewportY,M=[];for(let w=c;w<=r;w++){let L=l.getLine(b+w);if(!L){M.push("");continue}let H=w===c?d:0,A=w===r?p:this.terminal.cols-1,z="";for(let Y=H;Y<=A;Y++){let N=L.getCell(Y);N&&(z+=N.getChars())}M.push(z.replace(/\s+$/,""))}return M.join(`
3
+ `)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}},Ut=class bt{terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(e,t){this.container=e,this.terminal=t,this.terminal.open(e)}static async create(e,t,i){let a=await import(Ft);await a.init();let l=new a.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:t,convertEol:!1,theme:i});return new bt(e,l)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(e){return new Promise(t=>this.terminal.write(e,t))}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=Ze(this.container);if(e.width<=0||e.height<=0)return!1;this.updateCellMetrics(!this.charW||!this.charH);let t=Math.floor(e.width/this.charW),i=Math.floor(e.height/this.charH);if(t<10||i<5)return!1;if(t!==this.colsValue||i!==this.rowsValue){this.colsValue=t,this.rowsValue=i,this.terminal.resize(t,i);for(let a of this.resizeCallbacks)a({cols:t,rows:i})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(e){let t=this.terminal.getMode?.(2004)??!1;this.input(t?"\x1B[200~"+e+"\x1B[201~":e)}input(e){this.terminal.input?.(e,!1)}onData(e){this.terminal.onData(t=>e(t))}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))}getScreenText(){return this.getRowsText(0,this.rowsValue-1)}getRowsText(e,t){try{let i=this.terminal.buffer?.active;if(!i||typeof i.getLine!="function")return"";let[a,l]=e<=t?[e,t]:[t,e],c=typeof i.viewportY=="number"?i.viewportY:0,r=[];for(let d=a;d<=l;d++){let p=i.getLine(c+d);r.push(typeof p?.translateToString=="function"?p.translateToString(!0):"")}return r.join(`
4
+ `)}catch{return""}}selectRows(e,t){try{if(typeof this.terminal?.selectLines!="function")return;let i=this.terminal.buffer?.active,a=typeof i?.viewportY=="number"?i.viewportY:0,[l,c]=e<=t?[e,t]:[t,e];this.terminal.selectLines(a+l,a+c)}catch{}}selectCells(e,t,i,a){try{let l=this.terminal.buffer?.active,c=typeof l?.viewportY=="number"?l.viewportY:0,r=Math.min(t,a),d=Math.max(t,a);if(r===d){if(typeof this.terminal?.select!="function"){this.selectRows(r,d);return}let p=Math.min(e,i),b=Math.max(e,i);this.terminal.select(p,c+r,b-p+1)}else this.selectRows(r,d)}catch{this.selectRows(t,a)}}getCellsText(e,t,i,a){try{let l=this.terminal.buffer?.active;if(!l||typeof l.getLine!="function")return this.getRowsText(t,a);let c=typeof l.viewportY=="number"?l.viewportY:0,r=Math.min(t,a),d=Math.max(t,a),p=t<a?e:t>a?i:Math.min(e,i),b=t<a?i:t>a?e:Math.max(e,i),M=[];for(let w=r;w<=d;w++){let L=l.getLine(c+w);if(!L){M.push("");continue}let H=w===r?p:0,A=w===d?b:this.colsValue-1,z="";if(typeof L.getCell=="function")for(let Y=H;Y<=A;Y++){let N=L.getCell(Y);N&&(z+=typeof N.getChars=="function"?N.getChars():"")}else z=typeof L.translateToString=="function"?L.translateToString(!1):"";M.push(z.replace(/\s+$/,""))}return M.join(`
5
+ `)}catch{return this.getRowsText(t,a)}}getSelection(){try{if(typeof this.terminal?.getSelection=="function")return this.terminal.getSelection()}catch{}return""}clearSelection(){try{typeof this.terminal?.clearSelection=="function"&&this.terminal.clearSelection()}catch{}}hasSelectionSupport(){return typeof this.terminal?.selectLines=="function"}updateCellMetrics(e=!1){let t=this.container.querySelector("canvas");if(t instanceof HTMLElement&&t.offsetWidth>0&&t.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){let i=t.offsetWidth/this.colsValue,a=t.offsetHeight/this.rowsValue;(e||!this.charW||!this.charH)&&(this.charW=i,this.charH=a)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}};function Ze(n){let e=n.getBoundingClientRect(),t=window.visualViewport;return t?{width:Math.min(e.width,t.width),height:Math.max(0,Math.min(e.height,t.height-Math.max(0,e.top)))}:e}function Kt(n,e,t){return n.innerHTML="",n.classList.add("terminal-pending"),(async()=>{let i;if(t.renderer==="ghostty")try{i=await Ut.create(n,t.scrollback,t.theme)}catch{console.error("[tmux-web] ghostty-web failed; falling back to xterm.js"),i=await Je.create(n,t.scrollback,t.theme)}else i=await Je.create(n,t.scrollback,t.theme);let a,l=0,c,r=null,d=0,p="connecting",b=0,M=!1,w=[],L="",H=!1,A=1e3,z=location.protocol==="https:"?"wss:":"ws:",Y=t.wsBase||"/ws",N=z+"//"+location.host+Y+"/"+encodeURIComponent(e),Lt="/api/session/"+encodeURIComponent(e)+"/upload",Et=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function xt(){return w.join("")+L}async function kt(s,o=0){let u=s?i.viewportY():0,v=s?i.baseY():0,B=ie(xt());if(i.reset(),!B){s||i.scrollToBottom();return}await i.write(B),s?i.scrollToLine(v+u+o):i.scrollToBottom()}function X(s){a?.readyState===WebSocket.OPEN&&a.send(JSON.stringify(s))}function Ct(s){let o;try{o=JSON.parse(s)}catch{p==="live"&&(L+=s,i.write(ie(s)));return}if(o.type==="auth.required"){let u=localStorage.getItem("tmux-web-token");u?X({type:"auth.token",token:u}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(o.type==="attach_failed"&&typeof o.message=="string"){pe=!0,p="dead",i.reset(),i.write(`\r
6
+ \x1B[31m`+ie(o.message)+`\x1B[0m\r
7
+ `).then(()=>{me();try{a?.close()}catch{}});return}if(o.type==="auth.ok"){o.token&&localStorage.setItem("tmux-web-token",o.token),A=1e3,J(),X({type:"resize",cols:i.cols,rows:i.rows}),k();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 u=ie(o.data);w=[u],L="",b=typeof o.lines=="number"?o.lines:t.terminal.initialLines,p="live",i.reset(),i.write(u).then(()=>i.scrollToBottom());return}if(o.type==="window_changed"&&typeof o.activeIndex=="number"){let u=new URL(location.href);u.searchParams.get("window")!==String(o.activeIndex)&&(u.searchParams.set("window",String(o.activeIndex)),history.replaceState(history.state,"",u)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:o.windows}));return}if(o.type==="history"&&typeof o.data=="string"){M=!1,o.lines>0&&o.data&&(w.unshift(o.data),b+=o.lines,kt(!0,o.lines));return}if(o.type==="data"&&typeof o.data=="string"){let u=ie(o.data);if(p==="connecting"){p="live",L=u,i.write(u);return}p==="live"&&(L+=u,i.write(u))}}let pe=!1;function ze(){if(pe)return;let s=N,o=localStorage.getItem("tmux-web-token");o&&(s+=(s.includes("?")?"&":"?")+"token="+encodeURIComponent(o)),a=new WebSocket(s),a.onopen=()=>{p="connecting",b=0,M=!1,w=[],L="",i.reset(),A=1e3},a.onmessage=u=>{typeof u.data=="string"&&Ct(u.data)},a.onclose=()=>{H||(p="connecting",!pe&&setTimeout(()=>{A=Math.min(A*2,1e4),!H&&!pe&&ze()},A))},a.onerror=()=>a?.close()}function fe(s){X({type:"input",data:s})}function J(){return i.fit()}function me(){n.classList.remove("terminal-pending")}function k(){l&&cancelAnimationFrame(l),c&&clearTimeout(c),J(),l=requestAnimationFrame(()=>{l=0,J()&&me()}),c=setTimeout(()=>{J()&&me()},120)}function Tt(){k(),setTimeout(k,50),setTimeout(k,150),setTimeout(k,300)}function Ne(s){return typeof s=="string"&&s.startsWith("image/")}function We(s){return s?.files?.length?s.files[0]??null:null}function Mt(s){if(!s?.items)return null;for(let o=0;o<s.items.length;o++){let u=s.items[o];if(u?.kind==="file"&&Ne(u.type))return u.getAsFile()}return null}async function St(s){let o=new FormData,u=s instanceof File&&s.name?s.name:"upload";o.append("file",s,u);let v=localStorage.getItem("tmux-web-token"),B={};v&&(B.Authorization="Bearer "+v);let ne=await fetch(Lt,{method:"POST",body:o,headers:B});if(!ne.ok){let qe="upload failed";try{let Xe=await ne.json();Xe.error&&(qe=Xe.error)}catch{}throw new Error(qe)}let Oe=await ne.json();if(!Oe.path)throw new Error("no path in response");return Oe.path}async function Be(s){try{let o=await St(s);fe(o)}catch{}}i.onData(s=>fe(s)),i.onResize(({cols:s,rows:o})=>X({type:"resize",cols:s,rows:o})),i.onScroll(()=>{p!=="live"||M||!i.isNearScrollbackTop()||(M=!0,X({type:"load_history",before:b}))});let Z=!1,G=!1,C=null,S=null,Q=document.createElement("div");Q.className="terminal-copy-banner",Q.innerHTML='<strong>Copy mode</strong><span class="hint">drag to select \xB7 Alt+C copies \xB7 Esc exits</span>',Q.hidden=!0,n.appendChild(Q);let $=document.createElement("div");$.className="terminal-copy-banner terminal-copy-toast",$.textContent="Copied",$.hidden=!0,n.appendChild($);function je(s,o){let u=n.querySelector(".xterm-screen, canvas"),v=(u&&u.getBoundingClientRect().width>0?u:n).getBoundingClientRect(),B=v.height>0&&i.rows>0?v.height/i.rows:18,ne=v.width>0&&i.cols>0?v.width/i.cols:9;return{row:Math.max(0,Math.min(i.rows-1,Math.floor((o-v.top)/B))),col:Math.max(0,Math.min(i.cols-1,Math.floor((s-v.left)/ne)))}}async function Ie(s){if(!s)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(s);return}}catch{}let o=document.createElement("textarea");o.value=s,o.style.position="fixed",o.style.opacity="0",o.style.pointerEvents="none",document.body.appendChild(o),o.focus(),o.select();try{document.execCommand("copy")}catch{}o.remove()}let ee;function he(){$.hidden=!1,ee&&clearTimeout(ee),ee=setTimeout(()=>{$.hidden=!0},1e3)}function U(s){Z=s,Q.hidden=!s,n.classList.toggle("terminal-copy-mode-active",s),s&&i.focus()}function Fe(){U(!Z)}function Bt(s){H||s.button!==0||G||(Z||s.shiftKey)&&(s.preventDefault(),s.stopPropagation(),G=!0,C=je(s.clientX,s.clientY),S=C,i.selectCells(C.col,C.row,S.col,S.row),document.addEventListener("mousemove",He,!0),document.addEventListener("mouseup",De,!0))}function He(s){H||!G||!C||(s.preventDefault(),s.stopPropagation(),S=je(s.clientX,s.clientY),i.selectCells(C.col,C.row,S.col,S.row))}function De(s){H||!G||!C||!S||(s.preventDefault(),s.stopPropagation(),document.removeEventListener("mousemove",He,!0),document.removeEventListener("mouseup",De,!0),G=!1,U(!1),$.textContent="\u5DF2\u9009\u4E2D \xB7 Alt+C \u590D\u5236",he(),i.focus())}n.addEventListener("mousedown",Bt,!0),document.addEventListener("keydown",It,!0);function It(s){if(!(H||!i.isFocused()||s.defaultPrevented||s.isComposing)){if(Z){if(s.key==="Escape"){s.preventDefault(),s.stopPropagation(),C=null,S=null,i.clearSelection(),U(!1);return}if(s.key==="Enter"||(s.ctrlKey||s.metaKey)&&s.code==="KeyC"){s.preventDefault(),s.stopPropagation(),Ie(i.getScreenText()).then(he),U(!1);return}}if(s.altKey&&s.code==="KeyC"&&!s.ctrlKey&&!s.metaKey){if(s.preventDefault(),s.stopPropagation(),C&&S){let o=i.getCellsText(C.col,C.row,S.col,S.row);C=null,S=null,i.clearSelection(),U(!1),o&&($.textContent="Copied",Ie(o).then(he))}else{let o=i.getSelection();o?(i.clearSelection(),$.textContent="Copied",Ie(o).then(he)):Fe()}return}if((s.ctrlKey||s.metaKey)&&s.code==="KeyV"){s.preventDefault(),s.stopPropagation(),(async()=>{try{if(navigator.clipboard?.read){let o=await navigator.clipboard.read();for(let u of o)for(let v of u.types)if(Ne(v)){let B=await u.getType(v);await Be(B);return}}}catch{}try{let o=await navigator.clipboard?.readText();o&&i.pasteText(Ve(o))}catch{}})();return}}}let ve=0;function Ve(s){return s.split(`\r
6
8
  `).join(`
7
9
  `).split(`
8
- `).join("\r")}async function Ht(a){let s=Mt(a.clipboardData);if(s){a.preventDefault(),a.stopPropagation();let C=Date.now();if(C-ue<50)return;ue=C,await xe(s);return}let d=a.clipboardData?.getData("text/plain");if(!d)return;a.preventDefault(),a.stopPropagation();let L=Date.now();L-ue<50||(ue=L,i.pasteText(We(d)))}let J=0;function Dt(a){a.preventDefault(),J++,$e(a.dataTransfer)&&t.classList.add("terminal-drag-over")}function Rt(a){a.preventDefault(),a.dataTransfer&&(a.dataTransfer.dropEffect="copy")}function At(a){a.preventDefault(),J--,J<=0&&(J=0,t.classList.remove("terminal-drag-over"))}async function $t(a){a.preventDefault(),J=0,t.classList.remove("terminal-drag-over");let s=$e(a.dataTransfer);s&&await xe(s)}function je(a){!Lt||a.key!=="Escape"||K||a.defaultPrevented||a.repeat||a.metaKey||a.ctrlKey||a.altKey||i.isFocused()&&(a.preventDefault(),a.stopPropagation(),ce("\x1B"))}t.addEventListener("paste",Ht),t.addEventListener("dragenter",Dt),t.addEventListener("dragover",Rt),t.addEventListener("dragleave",At),t.addEventListener("drop",$t),document.addEventListener("keydown",je,!0);function zt(a){if(a.touches.length!==1){l=null;return}let s=a.touches[0];s&&(l={startX:s.clientX,startY:s.clientY,lastX:s.clientX,lastY:s.clientY,scrolling:!1},a.stopPropagation())}function Nt(a){if(!l||a.touches.length!==1)return;let s=a.touches[0];if(!s)return;let d=s.clientY-l.startY,L=s.clientX-l.startX;if(!l.scrolling){if(Math.abs(d)<8||Math.abs(d)<Math.abs(L))return;l.scrolling=!0,u=Date.now()+500}a.preventDefault(),a.stopPropagation(),jt(-(s.clientY-l.lastY),s.clientX,s.clientY),l.lastX=s.clientX,l.lastY=s.clientY}function Pt(a){if(!l)return;let s=l.scrolling;l=null,a.stopPropagation(),s?(u=Date.now()+500,a.preventDefault()):i.focus()}function Yt(a){l=null,a.stopPropagation()}function Wt(a){a.pointerType==="touch"&&Date.now()<u&&(a.preventDefault(),a.stopPropagation())}function jt(a,s,d){(t.querySelector(".xterm-screen")??t).dispatchEvent(new WheelEvent("wheel",{deltaY:a,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:s,clientY:d,bubbles:!0,cancelable:!0}))}t.addEventListener("touchstart",zt,{passive:!0,capture:!0}),t.addEventListener("touchmove",Nt,{passive:!1,capture:!0}),t.addEventListener("touchend",Pt,{passive:!1,capture:!0}),t.addEventListener("touchcancel",Yt,{passive:!0,capture:!0}),t.addEventListener("pointerup",Wt,!0);function Ve(){b()}window.addEventListener("resize",Ve),window.visualViewport?.addEventListener("resize",b),window.visualViewport?.addEventListener("scroll",b);let _e=new ResizeObserver(()=>b());return _e.observe(t),document.fonts?.ready.then(()=>{b(),setTimeout(b,50),setTimeout(b,200)}),t.addEventListener("focusin",Ct,!0),requestAnimationFrame(()=>{F()&&de(),Re(),b()}),{destroy(){if(N=!0,X(!1),q&&clearTimeout(q),document.removeEventListener("mousemove",Te,!0),document.removeEventListener("mouseup",Ce,!0),o){try{o.close(1e3,"session switch")}catch{}o=void 0}t.innerHTML="",t.classList.remove("terminal-pending"),window.removeEventListener("resize",Ve),_e.disconnect(),document.removeEventListener("keydown",je,!0)},focus(){i.focus()},sendInput(a){ce(a)},toggleCopyMode(){Ye()}}})()}var Y=window.__TMUX_WEB_SHELL__,h=null,y=null,Xe=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null,w=Xe;window.__tmuxWebScopeAgent=Xe;var Je="sessions",S="",fe="",me="",Ze="";function E(t){return w?"/a/"+encodeURIComponent(w)+t:t}var m=document.getElementById("sidebar-content"),R=document.getElementById("main-placeholder"),k=document.getElementById("terminal-container"),G=document.getElementById("file-editor"),Ot=document.getElementById("fe-path"),T=document.getElementById("fe-status"),Q=document.getElementById("fe-content"),A=document.getElementById("fe-save"),qt=document.getElementById("fe-delete"),Xt=document.getElementById("fe-back"),Ge=document.getElementById("fe-new-name"),Jt=document.getElementById("fe-new-btn"),Be=document.getElementById("settings-backdrop"),Qe=document.getElementById("settings-popover"),et=document.querySelector(".sidebar");function Zt(){return window.matchMedia("(max-width: 640px)").matches}function Ie(){Zt()&&et.classList.add("collapsed")}function tt(){et.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{tt(),nt("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{tt(),nt("files")});function nt(t){Je=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"?W():rn()}var it="";async function W(){try{let e=await(await fetch("/api/sidebar/sessions")).json(),n=JSON.stringify({recent:e.recent,agents:e.agents});if(n===it)return;it=n,Gt(e)}catch{m.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 Gt(t){m.innerHTML='<button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';let e=t.recent||[],n=document.createElement("div");n.className="sidebar-section-label"+(w?" clickable":""),n.textContent=w?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",w&&(n.title="Back to hub",n.addEventListener("click",()=>{window.location.href="/"})),m.appendChild(n);for(let o of e){let r=document.createElement("div");r.className="session-item"+(o.name===y&&!w?" active":""),r.setAttribute("data-session",o.name),r.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${o.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>
9
- <span>${f(o.name)}</span>
10
- <button class="session-edit-btn" data-session="${f(o.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>
11
- `,r.addEventListener("click",l=>{l.target.closest(".session-edit-btn")||ee(o.name)}),m.appendChild(r);let c=r.querySelector(".session-edit-btn");c&&c.addEventListener("click",l=>{l.stopPropagation(),fn(o.name,c)})}let i=t.agents||[];for(let o of i){if(!o.sessions||o.sessions.length===0)continue;let r=o.agentId===w,c=document.createElement("div");c.className="sidebar-section-label machine-label"+(o.online?"":" agent-offline-label")+(!r&&o.online?" clickable":""),c.textContent=o.agentName+(o.online?"":" (offline)"),!r&&o.online&&(c.title="\u6253\u5F00 "+o.agentName,c.addEventListener("click",()=>{window.location.href="/a/"+encodeURIComponent(o.agentId)+"/"})),m.appendChild(c);for(let l of o.sessions){let u=document.createElement("div");u.className="session-item"+(l.name===y&&w===o.agentId?" active":"")+(o.online?"":" session-offline"),u.setAttribute("data-session",l.name),u.setAttribute("data-agent",o.agentId),u.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${l.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>
12
- <span>${f(l.name)}</span><span class="meta">${o.online?"":"offline"}</span>`,o.online&&u.addEventListener("click",p=>{p.target.closest(".session-edit-btn")||ee(l.name,o.agentId)}),m.appendChild(u)}}}function f(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function ee(t,e){if(!(y===t&&h&&w===(e||null))){G.style.display="none",R.style.display="none",k.style.display="",k.classList.add("terminal-pending"),Ie(),h&&(Le(),h.destroy(),h=null),y=t,w=e||null,window.__tmuxWebScopeAgent=w;for(let n of m.querySelectorAll(".session-item"))n.classList.toggle("active",n.getAttribute("data-session")===t&&(n.getAttribute("data-agent")||null)===w);try{h=await Ut(k,t,{terminal:Y.terminal,scrollback:Y.scrollback,theme:Y.theme,renderer:Y.renderer,wsBase:w?"/ws/a/"+encodeURIComponent(w):Y.wsBase||"/ws"}),ft()}catch(n){console.error("[shell] terminal init failed:",n);let i=n&&typeof n=="object"&&"message"in n?n.message:String(n);k.textContent="Failed to open terminal for "+t+": "+i,k.classList.remove("terminal-pending")}}}var he=[],v=null,at=!1;function Qt(t){if(!v||!v.files.length)return null;let e=v.repoRoot;if(!e||!t.startsWith(e))return null;let n=t.slice(e.length+1);for(let i of v.files)if(i.path===n)return i.status;return null}async function en(t){at=!0;try{let e=await fetch(E("/api/git/status?path="+encodeURIComponent(t)));e.ok?v=await e.json():v=null}catch{v=null}finally{at=!1}}function tn(){if(!v||!v.branch)return"";let{branch:t,linesAdded:e,linesRemoved:n}=v,i=`<div class="sidebar-git"><div class="git-branch-badge">
10
+ `).join("\r")}async function Ht(s){let o=Mt(s.clipboardData);if(o){s.preventDefault(),s.stopPropagation();let B=Date.now();if(B-ve<50)return;ve=B,await Be(o);return}let u=s.clipboardData?.getData("text/plain");if(!u)return;s.preventDefault(),s.stopPropagation();let v=Date.now();v-ve<50||(ve=v,i.pasteText(Ve(u)))}let te=0;function Dt(s){s.preventDefault(),te++,We(s.dataTransfer)&&n.classList.add("terminal-drag-over")}function Rt(s){s.preventDefault(),s.dataTransfer&&(s.dataTransfer.dropEffect="copy")}function At(s){s.preventDefault(),te--,te<=0&&(te=0,n.classList.remove("terminal-drag-over"))}async function Yt(s){s.preventDefault(),te=0,n.classList.remove("terminal-drag-over");let o=We(s.dataTransfer);o&&await Be(o)}function _e(s){!Et||s.key!=="Escape"||Z||s.defaultPrevented||s.repeat||s.metaKey||s.ctrlKey||s.altKey||i.isFocused()&&(s.preventDefault(),s.stopPropagation(),fe("\x1B"))}n.addEventListener("paste",Ht),n.addEventListener("dragenter",Dt),n.addEventListener("dragover",Rt),n.addEventListener("dragleave",At),n.addEventListener("drop",Yt),document.addEventListener("keydown",_e,!0);function $t(s){if(s.touches.length!==1){r=null;return}let o=s.touches[0];o&&(r={startX:o.clientX,startY:o.clientY,lastX:o.clientX,lastY:o.clientY,scrolling:!1},s.stopPropagation())}function Pt(s){if(!r||s.touches.length!==1)return;let o=s.touches[0];if(!o)return;let u=o.clientY-r.startY,v=o.clientX-r.startX;if(!r.scrolling){if(Math.abs(u)<8||Math.abs(u)<Math.abs(v))return;r.scrolling=!0,d=Date.now()+500}s.preventDefault(),s.stopPropagation(),jt(-(o.clientY-r.lastY),o.clientX,o.clientY),r.lastX=o.clientX,r.lastY=o.clientY}function zt(s){if(!r)return;let o=r.scrolling;r=null,s.stopPropagation(),o?(d=Date.now()+500,s.preventDefault()):i.focus()}function Nt(s){r=null,s.stopPropagation()}function Wt(s){s.pointerType==="touch"&&Date.now()<d&&(s.preventDefault(),s.stopPropagation())}function jt(s,o,u){(n.querySelector(".xterm-screen")??n).dispatchEvent(new WheelEvent("wheel",{deltaY:s,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:o,clientY:u,bubbles:!0,cancelable:!0}))}n.addEventListener("touchstart",$t,{passive:!0,capture:!0}),n.addEventListener("touchmove",Pt,{passive:!1,capture:!0}),n.addEventListener("touchend",zt,{passive:!1,capture:!0}),n.addEventListener("touchcancel",Nt,{passive:!0,capture:!0}),n.addEventListener("pointerup",Wt,!0);function Ue(){k()}window.addEventListener("resize",Ue),window.visualViewport?.addEventListener("resize",k),window.visualViewport?.addEventListener("scroll",k);let Ke=new ResizeObserver(()=>k());return Ke.observe(n),document.fonts?.ready.then(()=>{k(),setTimeout(k,50),setTimeout(k,200)}),n.addEventListener("focusin",Tt,!0),requestAnimationFrame(()=>{J()&&me(),ze(),k()}),{destroy(){if(H=!0,U(!1),ee&&clearTimeout(ee),document.removeEventListener("mousemove",He,!0),document.removeEventListener("mouseup",De,!0),a){try{a.close(1e3,"session switch")}catch{}a=void 0}n.innerHTML="",n.classList.remove("terminal-pending"),window.removeEventListener("resize",Ue),Ke.disconnect(),document.removeEventListener("keydown",_e,!0)},focus(){i.focus()},sendInput(s){fe(s)},toggleCopyMode(){Fe()}}})()}var K=window.__TMUX_WEB_SHELL__,h=null,y=null,Ge=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null,x=Ge;window.__tmuxWebScopeAgent=Ge;var Qe="sessions",W="",ye="",we="",et="";function T(n){return x?"/a/"+encodeURIComponent(x)+n:n}var m=document.getElementById("sidebar-content"),F=document.getElementById("main-placeholder"),I=document.getElementById("terminal-container"),se=document.getElementById("file-editor"),Ot=document.getElementById("fe-path"),D=document.getElementById("fe-status"),ae=document.getElementById("fe-content"),V=document.getElementById("fe-save"),qt=document.getElementById("fe-delete"),Xt=document.getElementById("fe-back"),tt=document.getElementById("fe-new-name"),Jt=document.getElementById("fe-new-btn"),Re=document.getElementById("settings-backdrop"),nt=document.getElementById("settings-popover"),it=document.querySelector(".sidebar");function Zt(){return window.matchMedia("(max-width: 640px)").matches}function Ae(){Zt()&&it.classList.add("collapsed")}function st(){it.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{st(),at("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{st(),at("files")});function at(n){Qe=n,document.querySelectorAll(".mode-btn").forEach(t=>t.classList.remove("active"));let e=document.getElementById(n==="sessions"?"mode-sessions":"mode-files");e&&e.classList.add("active"),n==="sessions"?O():rn()}var ot="";async function O(){try{let e=await(await fetch("/api/sidebar/sessions")).json(),t=JSON.stringify({recent:e.recent,agents:e.agents});if(t===ot)return;ot=t,Gt(e)}catch{m.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}let n=document.getElementById("ns-btn");n&&n.addEventListener("click",()=>document.getElementById("new-session-modal")?.classList.add("open"))}function Gt(n){m.innerHTML='<button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';let e=n.recent||[],t=document.createElement("div");t.className="sidebar-section-label"+(x?" clickable":""),t.textContent=x?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",x&&(t.title="Back to hub",t.addEventListener("click",()=>{window.location.href="/"})),m.appendChild(t);for(let a of e){let l=document.createElement("div");l.className="session-item"+(a.name===y&&!x?" active":""),l.setAttribute("data-session",a.name),l.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>
11
+ <span>${f(a.name)}</span>
12
+ <button class="session-edit-btn" data-session="${f(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>
13
+ `,l.addEventListener("click",r=>{r.target.closest(".session-edit-btn")||oe(a.name)}),m.appendChild(l);let c=l.querySelector(".session-edit-btn");c&&c.addEventListener("click",r=>{r.stopPropagation(),fn(a.name,c)})}let i=n.agents||[];for(let a of i){if(!a.sessions||a.sessions.length===0)continue;let l=a.agentId===x,c=document.createElement("div");c.className="sidebar-section-label machine-label"+(a.online?"":" agent-offline-label")+(!l&&a.online?" clickable":""),c.textContent=a.agentName+(a.online?"":" (offline)"),!l&&a.online&&(c.title="\u6253\u5F00 "+a.agentName,c.addEventListener("click",()=>{window.location.href="/a/"+encodeURIComponent(a.agentId)+"/"})),m.appendChild(c);for(let r of a.sessions){let d=document.createElement("div");d.className="session-item"+(r.name===y&&x===a.agentId?" active":"")+(a.online?"":" session-offline"),d.setAttribute("data-session",r.name),d.setAttribute("data-agent",a.agentId),d.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>
14
+ <span>${f(r.name)}</span><span class="meta">${a.online?"":"offline"}</span>`,a.online&&d.addEventListener("click",p=>{p.target.closest(".session-edit-btn")||oe(r.name,a.agentId)}),m.appendChild(d)}}}function f(n){return n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function oe(n,e){if(!(y===n&&h&&x===(e||null))){se.style.display="none",F.style.display="none",I.style.display="",I.classList.add("terminal-pending"),Ae(),h&&(Me(),h.destroy(),h=null),y=n,x=e||null,window.__tmuxWebScopeAgent=x;for(let t of m.querySelectorAll(".session-item"))t.classList.toggle("active",t.getAttribute("data-session")===n&&(t.getAttribute("data-agent")||null)===x);try{h=await Kt(I,n,{terminal:K.terminal,scrollback:K.scrollback,theme:K.theme,renderer:K.renderer,wsBase:x?"/ws/a/"+encodeURIComponent(x):K.wsBase||"/ws"}),vt()}catch(t){console.error("[shell] terminal init failed:",t);let i=t&&typeof t=="object"&&"message"in t?t.message:String(t);I.textContent="Failed to open terminal for "+n+": "+i,I.classList.remove("terminal-pending")}}}var be=[],g=null,lt=!1;function Qt(n){if(!g||!g.files.length)return null;let e=g.repoRoot;if(!e||!n.startsWith(e))return null;let t=n.slice(e.length+1);for(let i of g.files)if(i.path===t)return i.status;return null}async function en(n){lt=!0;try{let e=await fetch(T("/api/git/status?path="+encodeURIComponent(n)));e.ok?g=await e.json():g=null}catch{g=null}finally{lt=!1}}function tn(){if(!g||!g.branch)return"";let{branch:n,linesAdded:e,linesRemoved:t}=g,i=`<div class="sidebar-git"><div class="git-branch-badge">
13
15
  <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>
14
- ${f(t)}</div>`;return(e>0||n>0)&&(i+=`<div class="git-diff-stats">+<span class="add">${e}</span> <span class="del">-${n}</span></div>`),i+"</div>"}m.addEventListener("click",t=>{t.target.closest(".sidebar-git")&&j&&v&&(t.stopPropagation(),ct())});var te=document.getElementById("header-git"),st=document.getElementById("git-diff-view"),ot=document.getElementById("gd-path"),ve=document.getElementById("gd-status"),ye=document.getElementById("gd-content"),nn=document.getElementById("gd-back"),j=null;function ne(t){if(!t||!t.branch){te.style.display="none",j=null;return}j=t.repoRoot;let{branch:e,linesAdded:n,linesRemoved:i}=t,o=`<span class="branch">${f(e)}</span>`;(n>0||i>0)&&(o+=`<span class="sep">\xB7</span>+<span class="diff-add">${n}</span> <span class="diff-del">-${i}</span>`),te.innerHTML=o,te.style.display="block"}te.addEventListener("click",t=>{j&&v&&(t.stopPropagation(),ct())});var g=document.getElementById("git-popover"),ge=document.getElementById("git-popover-backdrop");function Se(){let t=te.getBoundingClientRect();g.style.top=t.bottom+4+"px",g.style.left=Math.max(8,Math.min(t.left,window.innerWidth-400))+"px"}function lt(){let t=j,e=document.getElementById("git-popover-browse");e&&e.addEventListener("click",()=>{if(be(),t){Je="files",document.querySelectorAll(".mode-btn").forEach(i=>i.classList.remove("active"));let n=document.getElementById("mode-files");n&&n.classList.add("active"),H(t)}})}var rt="";function ct(){if(!v)return;let t=v.files||[];if(!t.length)g.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
15
- <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 i=t[n],o=i.additions||0,r=i.deletions||0,c="";switch(i.status){case"M":c='<span class="git-file-status M">M</span>';break;case"A":c='<span class="git-file-status A">A</span>';break;case"D":c='<span class="git-file-status D">D</span>';break;case"?":c='<span class="git-file-status ?">?</span>';break;case"R":c='<span class="git-file-status R">R</span>';break}e+=`<div class="git-popover-item" data-idx="${n}">
16
+ ${f(n)}</div>`;return(e>0||t>0)&&(i+=`<div class="git-diff-stats">+<span class="add">${e}</span> <span class="del">-${t}</span></div>`),i+"</div>"}m.addEventListener("click",n=>{n.target.closest(".sidebar-git")&&q&&g&&(n.stopPropagation(),pt())});var le=document.getElementById("header-git"),rt=document.getElementById("git-diff-view"),ct=document.getElementById("gd-path"),Le=document.getElementById("gd-status"),Ee=document.getElementById("gd-content"),nn=document.getElementById("gd-back"),q=null;function re(n){if(!n||!n.branch){le.style.display="none",q=null;return}q=n.repoRoot;let{branch:e,linesAdded:t,linesRemoved:i}=n,a=`<span class="branch">${f(e)}</span>`;(t>0||i>0)&&(a+=`<span class="sep">\xB7</span>+<span class="diff-add">${t}</span> <span class="diff-del">-${i}</span>`),le.innerHTML=a,le.style.display="block"}le.addEventListener("click",n=>{q&&g&&(n.stopPropagation(),pt())});var E=document.getElementById("git-popover"),xe=document.getElementById("git-popover-backdrop");function Ye(){let n=le.getBoundingClientRect();E.style.top=n.bottom+4+"px",E.style.left=Math.max(8,Math.min(n.left,window.innerWidth-400))+"px"}function dt(){let n=q,e=document.getElementById("git-popover-browse");e&&e.addEventListener("click",()=>{if(Ce(),n){Qe="files",document.querySelectorAll(".mode-btn").forEach(i=>i.classList.remove("active"));let t=document.getElementById("mode-files");t&&t.classList.add("active"),j(n)}})}var ut="";function pt(){if(!g)return;let n=g.files||[];if(!n.length)E.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
17
+ <div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>`;else{let e=`<div class="git-popover-header">${n.length} file${n.length>1?"s":""} changed</div>`;for(let t=0;t<n.length;t++){let i=n[t],a=i.additions||0,l=i.deletions||0,c="";switch(i.status){case"M":c='<span class="git-file-status M">M</span>';break;case"A":c='<span class="git-file-status A">A</span>';break;case"D":c='<span class="git-file-status D">D</span>';break;case"?":c='<span class="git-file-status ?">?</span>';break;case"R":c='<span class="git-file-status R">R</span>';break}e+=`<div class="git-popover-item" data-idx="${t}">
16
18
  ${c}<span class="file-path">${f(i.path)}</span>
17
- <span class="file-add">${o>0?"+"+o:""}</span>
18
- <span class="file-del">${r>0?"-"+r:""}</span>
19
- </div>`}e+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',rt=e,g.innerHTML=e,g.querySelectorAll(".git-popover-item").forEach(n=>{let i=parseInt(n.dataset.idx||"0",10),o=t[i];!o||o.status==="D"||(n.classList.add("clickable"),n.style.cursor="pointer",n.addEventListener("click",()=>ut(o.path)))})}Se(),g.classList.add("open"),ge.classList.add("open"),lt()}function an(){return window.innerWidth>=1024}function dt(t,e){let n=(t+(e&&t?`
19
+ <span class="file-add">${a>0?"+"+a:""}</span>
20
+ <span class="file-del">${l>0?"-"+l:""}</span>
21
+ </div>`}e+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',ut=e,E.innerHTML=e,E.querySelectorAll(".git-popover-item").forEach(t=>{let i=parseInt(t.dataset.idx||"0",10),a=n[i];!a||a.status==="D"||(t.classList.add("clickable"),t.style.cursor="pointer",t.addEventListener("click",()=>mt(a.path)))})}Ye(),E.classList.add("open"),xe.classList.add("open"),dt()}function sn(){return window.innerWidth>=1024}function ft(n,e){let t=(n+(e&&n?`
20
22
  `:"")+e).split(`
21
- `),i="",o=0,r=0;for(let c of n){let l=c;if(l.startsWith("@@")){let u=l.match(/@@\s+-(\d+)[^+]*\+(\d+)/);u&&(o=parseInt(u[1],10)-1,r=parseInt(u[2],10)-1),i+=`<div class="diff-line hunk"><span class="ln-body">${f(l)}</span></div>`;continue}if(l.startsWith("diff --git")||l.startsWith("index ")||l.startsWith("--- ")||l.startsWith("+++ ")||l.startsWith("new file")||l.startsWith("deleted file")){l.startsWith("diff --git")&&(i+=`<div class="diff-line header"><span class="ln-body">${f(l)}</span></div>`);continue}if(l.startsWith("+"))r++,i+=`<div class="diff-line add"><span class="ln-no">${r}</span><span class="ln-body">${f(l)}</span></div>`;else if(l.startsWith("-"))o++,i+=`<div class="diff-line del"><span class="ln-no">${o}</span><span class="ln-body">${f(l)}</span></div>`;else if(l.startsWith("\\"))i+=`<div class="diff-line"><span class="ln-body">${f(l)}</span></div>`;else{if(!l&&!o&&!r)continue;o++,r++,i+=`<div class="diff-line"><span class="ln-no">${o}</span><span class="ln-no" style="margin-right:12px">${r}</span><span class="ln-body">${f(l)}</span></div>`}}return{html:i,lineCount:n.length}}var we=null;async function ut(t){let e=j;if(e)if(be(),an()){k.style.display="none",h&&(Le(),h.destroy(),h=null,we=y,y=null),ne(null),G.style.display="none",R.style.display="none",st.style.display="flex",ot.textContent=t,ve.textContent="Loading\u2026",ye.innerHTML="";try{let n=await fetch(E("/api/git/diff?path="+encodeURIComponent(e)+"&file="+encodeURIComponent(t)));if(!n.ok)throw new Error(await n.text());let i=await n.json();on(t,i.diff,i.stagedDiff)}catch(n){let i=n instanceof Error?n.message:String(n);ve.textContent="Error",ye.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${f(i)}</div>`}}else{g.innerHTML=`<div class="git-diff-view"><div class="diff-header">
23
+ `),i="",a=0,l=0;for(let c of t){let r=c;if(r.startsWith("@@")){let d=r.match(/@@\s+-(\d+)[^+]*\+(\d+)/);d&&(a=parseInt(d[1],10)-1,l=parseInt(d[2],10)-1),i+=`<div class="diff-line hunk"><span class="ln-body">${f(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")&&(i+=`<div class="diff-line header"><span class="ln-body">${f(r)}</span></div>`);continue}if(r.startsWith("+"))l++,i+=`<div class="diff-line add"><span class="ln-no">${l}</span><span class="ln-body">${f(r)}</span></div>`;else if(r.startsWith("-"))a++,i+=`<div class="diff-line del"><span class="ln-no">${a}</span><span class="ln-body">${f(r)}</span></div>`;else if(r.startsWith("\\"))i+=`<div class="diff-line"><span class="ln-body">${f(r)}</span></div>`;else{if(!r&&!a&&!l)continue;a++,l++,i+=`<div class="diff-line"><span class="ln-no">${a}</span><span class="ln-no" style="margin-right:12px">${l}</span><span class="ln-body">${f(r)}</span></div>`}}return{html:i,lineCount:t.length}}var ke=null;async function mt(n){let e=q;if(e)if(Ce(),sn()){I.style.display="none",h&&(Me(),h.destroy(),h=null,ke=y,y=null),re(null),se.style.display="none",F.style.display="none",rt.style.display="flex",ct.textContent=n,Le.textContent="Loading\u2026",Ee.innerHTML="";try{let t=await fetch(T("/api/git/diff?path="+encodeURIComponent(e)+"&file="+encodeURIComponent(n)));if(!t.ok)throw new Error(await t.text());let i=await t.json();on(n,i.diff,i.stagedDiff)}catch(t){let i=t instanceof Error?t.message:String(t);Le.textContent="Error",Ee.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${f(i)}</div>`}}else{E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
22
24
  <button class="diff-back">\u2190 Back</button>
23
- <span class="diff-filename">${f(t)}</span>
25
+ <span class="diff-filename">${f(n)}</span>
24
26
  <span class="diff-loading">Loading\u2026</span>
25
- </div></div>`,Se(),g.classList.add("open"),ge.classList.add("open");try{let n=await fetch(E("/api/git/diff?path="+encodeURIComponent(e)+"&file="+encodeURIComponent(t)));if(!n.ok)throw new Error(await n.text());let i=await n.json();sn(t,i.diff,i.stagedDiff)}catch(n){let i=n instanceof Error?n.message:String(n);g.innerHTML=`<div class="git-diff-view"><div class="diff-header">
27
+ </div></div>`,Ye(),E.classList.add("open"),xe.classList.add("open");try{let t=await fetch(T("/api/git/diff?path="+encodeURIComponent(e)+"&file="+encodeURIComponent(n)));if(!t.ok)throw new Error(await t.text());let i=await t.json();an(n,i.diff,i.stagedDiff)}catch(t){let i=t instanceof Error?t.message:String(t);E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
26
28
  <button class="diff-back">\u2190 Back</button>
27
- <span class="diff-filename">${f(t)}</span>
28
- </div><div class="diff-empty">Error loading diff: ${f(i)}</div></div>`}}}function sn(t,e,n){if(!e&&!n){g.innerHTML=`<div class="git-diff-view"><div class="diff-header">
29
+ <span class="diff-filename">${f(n)}</span>
30
+ </div><div class="diff-empty">Error loading diff: ${f(i)}</div></div>`}}}function an(n,e,t){if(!e&&!t){E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
29
31
  <button class="diff-back">\u2190 Back</button>
30
- <span class="diff-filename">${f(t)}</span>
31
- </div><div class="diff-empty">No diff content available</div></div>`;return}let{html:i,lineCount:o}=dt(e,n);g.innerHTML=`<div class="git-diff-view"><div class="diff-header">
32
+ <span class="diff-filename">${f(n)}</span>
33
+ </div><div class="diff-empty">No diff content available</div></div>`;return}let{html:i,lineCount:a}=ft(e,t);E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
32
34
  <button class="diff-back">\u2190 Back</button>
33
- <span class="diff-filename">${f(t)}</span>
34
- <span class="diff-filesize">${o} lines</span>
35
- </div><div class="diff-content">${i}</div></div>`,g.querySelector(".diff-back")?.addEventListener("click",()=>{g.innerHTML=rt,Se(),v&&g.querySelectorAll(".git-popover-item").forEach(r=>{let c=parseInt(r.dataset.idx||"0",10),l=v.files[c];!l||l.status==="D"||(r.style.cursor="pointer",r.addEventListener("click",()=>ut(l.path)))}),lt()})}function on(t,e,n){if(!e&&!n){ve.textContent="No diff",ye.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}let{html:i,lineCount:o}=dt(e,n);ot.textContent=t,ve.textContent=o+" lines",ye.innerHTML=i}function ln(){st.style.display="none",we?(k.style.display="",k.classList.add("terminal-pending"),ee(we),we=null):y?(k.style.display="",k.classList.add("terminal-pending"),ft()):R.style.display="flex"}nn.addEventListener("click",ln);function be(){g.classList.remove("open"),ge.classList.remove("open")}ge.addEventListener("click",be),document.addEventListener("keydown",t=>{t.key==="Escape"&&(be(),ke())});async function pt(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 i=await n.json();v=i,ne(i);return}}}catch{}v=null,ne(null)}var Ee=null;function ft(){Le(),y&&(pt(y),Ee=setInterval(()=>{y&&pt(y)},3e4))}function Le(){Ee&&(clearInterval(Ee),Ee=null)}function rn(){if(he=Y.fsRoots||[],he.length===0){if(y){cn(y);return}m.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}m.innerHTML="";for(let t of he){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> ${f(t)}`,e.addEventListener("click",()=>H(t)),m.appendChild(e)}}async function cn(t){m.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let e=await(await fetch(E("/api/fs/session-path?session="+encodeURIComponent(t)))).json();e.path?H(e.path):m.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{m.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function H(t){S=t,m.innerHTML='<div class="file-tree-empty">Loading...</div>';let e=en(t);try{let n=await(await fetch(E("/api/fs/list?path="+encodeURIComponent(t)))).json();await e,m.innerHTML="",ne(v),m.innerHTML+=tn();let i=dn(t);if(i&&!he.some(r=>t===r)){let r=document.createElement("div");r.className="file-tree-item",r.innerHTML="..",r.addEventListener("click",()=>H(i)),m.appendChild(r)}if(n.dirs)for(let r of n.dirs){let c=r.split("/").pop()||r.split("\\").pop(),l=document.createElement("div");l.className="file-tree-item",l.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> ${f(c)}`,l.addEventListener("click",()=>H(r)),m.appendChild(l)}else m.innerHTML="";let o=n.files||[];for(let r of o){let c=r.split("/").pop()||r.split("\\").pop(),l=Qt(r),u="",p="";if(l)switch(l){case"M":u="git-mod",p='<span class="git-file-status M">M</span>';break;case"A":u="git-add",p='<span class="git-file-status A">A</span>';break;case"D":u="git-del",p='<span class="git-file-status D">D</span>';break;case"?":u="git-untracked",p='<span class="git-file-status ?">?</span>';break;case"R":u="git-mod",p='<span class="git-file-status R">R</span>';break}let B=document.createElement("div");B.className="file-tree-item file"+(u?" "+u:""),B.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${p}${f(c)}`,B.addEventListener("click",()=>un(r)),m.appendChild(B)}}catch{m.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function dn(t){let e=t.lastIndexOf("/");return e<=0?null:t.substring(0,e)}async function un(t){fe=t,k.style.display="none",h&&(Le(),h.destroy(),h=null,y=null),ne(null),Ie(),R.style.display="none",G.style.display="flex",Ot.textContent=t,T.textContent="Loading...",A.style.display="none";try{let e=await fetch(E("/api/file?path="+encodeURIComponent(t)));if(!e.ok){let i=await e.json();T.textContent=i.error||"Failed to load",Q.value="";return}let n=await e.json();Q.value=n.content,me=n.content,Ze=n.content,T.textContent=n.size+" bytes",A.style.display=""}catch{T.textContent="Failed to load",Q.value=""}}Q.addEventListener("input",()=>{me=Q.value}),A.addEventListener("click",async()=>{A.textContent="Saving...",A.disabled=!0;try{let t=await fetch(E("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:fe,content:me})});if(!t.ok){let e=await t.json();T.textContent=e.error||"Save failed";return}Ze=me,T.textContent="Saved"}catch{T.textContent="Save failed"}finally{A.disabled=!1,A.textContent="Save"}}),qt.addEventListener("click",async()=>{if(confirm("Delete "+fe+"?"))try{let t=await fetch(E("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:fe})});if(!t.ok){let e=await t.json();T.textContent=e.error||"Delete failed";return}G.style.display="none",R.style.display="flex",S&&H(S)}catch{T.textContent="Delete failed"}}),Xt.addEventListener("click",()=>{G.style.display="none",R.style.display="flex",S&&H(S)}),Jt.addEventListener("click",async()=>{let t=Ge.value.trim();if(!t)return;let e=S+"/"+t;try{let n=await fetch(E("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})});if(!n.ok){let i=await n.json();T.textContent=i.error||"Create failed";return}Ge.value="",S&&H(S)}catch{T.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{let t=Qe.classList.toggle("open");Be.classList.toggle("open",t)}),Be.addEventListener("click",()=>{Qe.classList.remove("open"),Be.classList.remove("open")});var $="",ie=document.createElement("div");ie.className="session-popover-backdrop",document.body.appendChild(ie);var I=document.createElement("div");I.id="session-popover",I.className="session-popover",I.style.display="none",I.innerHTML=`<div class="sp-field">
35
+ <span class="diff-filename">${f(n)}</span>
36
+ <span class="diff-filesize">${a} lines</span>
37
+ </div><div class="diff-content">${i}</div></div>`,E.querySelector(".diff-back")?.addEventListener("click",()=>{E.innerHTML=ut,Ye(),g&&E.querySelectorAll(".git-popover-item").forEach(l=>{let c=parseInt(l.dataset.idx||"0",10),r=g.files[c];!r||r.status==="D"||(l.style.cursor="pointer",l.addEventListener("click",()=>mt(r.path)))}),dt()})}function on(n,e,t){if(!e&&!t){Le.textContent="No diff",Ee.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}let{html:i,lineCount:a}=ft(e,t);ct.textContent=n,Le.textContent=a+" lines",Ee.innerHTML=i}function ln(){rt.style.display="none",ke?(I.style.display="",I.classList.add("terminal-pending"),oe(ke),ke=null):y?(I.style.display="",I.classList.add("terminal-pending"),vt()):F.style.display="flex"}nn.addEventListener("click",ln);function Ce(){E.classList.remove("open"),xe.classList.remove("open")}xe.addEventListener("click",Ce),document.addEventListener("keydown",n=>{n.key==="Escape"&&(Ce(),Se())});async function ht(n){try{let e=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(n))).json();if(e.path){let t=await fetch("/api/git/status?path="+encodeURIComponent(e.path));if(t.ok){let i=await t.json();g=i,re(i);return}}}catch{}g=null,re(null)}var Te=null;function vt(){Me(),y&&(ht(y),Te=setInterval(()=>{y&&ht(y)},3e4))}function Me(){Te&&(clearInterval(Te),Te=null)}function rn(){if(be=K.fsRoots||[],be.length===0){if(y){cn(y);return}m.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}m.innerHTML="";for(let n of be){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> ${f(n)}`,e.addEventListener("click",()=>j(n)),m.appendChild(e)}}async function cn(n){m.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let e=await(await fetch(T("/api/fs/session-path?session="+encodeURIComponent(n)))).json();e.path?j(e.path):m.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{m.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function j(n){W=n,m.innerHTML='<div class="file-tree-empty">Loading...</div>';let e=en(n);try{let t=await(await fetch(T("/api/fs/list?path="+encodeURIComponent(n)))).json();await e,m.innerHTML="",re(g),m.innerHTML+=tn();let i=dn(n);if(i&&!be.some(l=>n===l)){let l=document.createElement("div");l.className="file-tree-item",l.innerHTML="..",l.addEventListener("click",()=>j(i)),m.appendChild(l)}if(t.dirs)for(let l of t.dirs){let c=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> ${f(c)}`,r.addEventListener("click",()=>j(l)),m.appendChild(r)}else m.innerHTML="";let a=t.files||[];for(let l of a){let c=l.split("/").pop()||l.split("\\").pop(),r=Qt(l),d="",p="";if(r)switch(r){case"M":d="git-mod",p='<span class="git-file-status M">M</span>';break;case"A":d="git-add",p='<span class="git-file-status A">A</span>';break;case"D":d="git-del",p='<span class="git-file-status D">D</span>';break;case"?":d="git-untracked",p='<span class="git-file-status ?">?</span>';break;case"R":d="git-mod",p='<span class="git-file-status R">R</span>';break}let b=document.createElement("div");b.className="file-tree-item file"+(d?" "+d:""),b.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${p}${f(c)}`,b.addEventListener("click",()=>un(l)),m.appendChild(b)}}catch{m.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function dn(n){let e=n.lastIndexOf("/");return e<=0?null:n.substring(0,e)}async function un(n){ye=n,I.style.display="none",h&&(Me(),h.destroy(),h=null,y=null),re(null),Ae(),F.style.display="none",se.style.display="flex",Ot.textContent=n,D.textContent="Loading...",V.style.display="none";try{let e=await fetch(T("/api/file?path="+encodeURIComponent(n)));if(!e.ok){let i=await e.json();D.textContent=i.error||"Failed to load",ae.value="";return}let t=await e.json();ae.value=t.content,we=t.content,et=t.content,D.textContent=t.size+" bytes",V.style.display=""}catch{D.textContent="Failed to load",ae.value=""}}ae.addEventListener("input",()=>{we=ae.value}),V.addEventListener("click",async()=>{V.textContent="Saving...",V.disabled=!0;try{let n=await fetch(T("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:ye,content:we})});if(!n.ok){let e=await n.json();D.textContent=e.error||"Save failed";return}et=we,D.textContent="Saved"}catch{D.textContent="Save failed"}finally{V.disabled=!1,V.textContent="Save"}}),qt.addEventListener("click",async()=>{if(confirm("Delete "+ye+"?"))try{let n=await fetch(T("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:ye})});if(!n.ok){let e=await n.json();D.textContent=e.error||"Delete failed";return}se.style.display="none",F.style.display="flex",W&&j(W)}catch{D.textContent="Delete failed"}}),Xt.addEventListener("click",()=>{se.style.display="none",F.style.display="flex",W&&j(W)}),Jt.addEventListener("click",async()=>{let n=tt.value.trim();if(!n)return;let e=W+"/"+n;try{let t=await fetch(T("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})});if(!t.ok){let i=await t.json();D.textContent=i.error||"Create failed";return}tt.value="",W&&j(W)}catch{D.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{let n=nt.classList.toggle("open");Re.classList.toggle("open",n)}),Re.addEventListener("click",()=>{nt.classList.remove("open"),Re.classList.remove("open")});var _="",ce=document.createElement("div");ce.className="session-popover-backdrop",document.body.appendChild(ce);var P=document.createElement("div");P.id="session-popover",P.className="session-popover",P.style.display="none",P.innerHTML=`<div class="sp-field">
36
38
  <label>Rename session</label>
37
39
  <input type="text" id="sp-name" />
38
40
  </div>
@@ -41,5 +43,5 @@ var Vt="https://esm.sh/ghostty-web@0.4.0",_t=/\x1b\](?:10|11|110|111|104)(?:;[^\
41
43
  <button class="btn" id="sp-cancel">Cancel</button>
42
44
  </div>
43
45
  <hr class="sp-divider" />
44
- <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(I);function pn(t){let e=t.getBoundingClientRect();I.style.top=e.bottom+4+"px",I.style.left=Math.max(8,Math.min(e.left,window.innerWidth-240))+"px"}function fn(t,e){$=t;let n=document.getElementById("sp-name");n.value=t,ie.classList.add("open"),I.style.display="block",pn(e),setTimeout(()=>n.focus(),50)}function ae(){ie.classList.remove("open"),I.style.display="none"}ie.addEventListener("click",ae),document.getElementById("sp-save").addEventListener("click",async()=>{let t=document.getElementById("sp-name").value.trim();if(!t||t===$){ae();return}try{if(!(await fetch(E("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:$,newName:t})})).ok)return;ae(),W(),y===$&&ee(t)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+$+'"?'))try{if(!(await fetch(E("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:$})})).ok)return;ae(),y===$&&(h&&(h.destroy(),h=null),y=null,k.style.display="none",R.style.display="flex"),W()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",ae);var mn={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||!h)return;let n=mn[e.dataset.key];n&&(h.sendInput(n),h.focus())});var M=document.getElementById("mk-input"),mt=document.getElementById("mk-send");function ht(){if(!M||!h)return;let t=M.value;t&&(h.sendInput(t+"\r"),M.value="",M.rows=1,h.focus())}if(M&&(M.addEventListener("input",()=>{M.rows=1;let t=M.value.split(`
45
- `).length;M.rows=Math.min(t,4)}),M.addEventListener("keydown",t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),ht())})),mt&&mt.addEventListener("click",ht),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 He=document.getElementById("process-panel"),se=document.getElementById("proc-list"),hn=document.getElementById("proc-close"),De=document.getElementById("proc-backdrop"),vn=document.getElementById("header-ram");function yn(){se.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(E("/api/system/processes")).then(t=>t.json()).then(t=>{if(!Array.isArray(t)||!t.length){se.innerHTML='<div class="proc-empty">No processes</div>';return}let e="";for(let n of t){let i=n.rss,o=i<1048576?(i/1024).toFixed(0)+"K":(i/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="'+f(n.command)+'">'+f(n.command)+'</span><button class="proc-kill" title="Kill PID '+n.pid+'">&times;</button></div>'}se.innerHTML=e;for(let n of se.querySelectorAll(".proc-row")){let i=n.querySelector(".proc-kill");i&&i.addEventListener("click",o=>{let r=o.target.closest(".proc-row");!r||!confirm("Kill PID "+r.dataset.pid+"?")||fetch(E("/api/system/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(r.dataset.pid,10)})}).then(c=>c.json()).then(c=>{c.ok?r.style.opacity="0.3":alert("Failed: "+(c.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{se.innerHTML='<div class="proc-empty">Failed to load</div>'})}function gn(){He.classList.add("open"),De.classList.add("open"),yn()}function ke(){He.classList.remove("open"),De.classList.remove("open")}vn.addEventListener("click",t=>{t.stopPropagation(),He.classList.contains("open")?ke():gn()}),hn.addEventListener("click",ke),De.addEventListener("click",ke),window.__openSession=ee,window.__refreshSidebar=W,W(),Ie(),setInterval(()=>{document.visibilityState==="visible"&&W()},1e4);
46
+ <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(P);function pn(n){let e=n.getBoundingClientRect();P.style.top=e.bottom+4+"px",P.style.left=Math.max(8,Math.min(e.left,window.innerWidth-240))+"px"}function fn(n,e){_=n;let t=document.getElementById("sp-name");t.value=n,ce.classList.add("open"),P.style.display="block",pn(e),setTimeout(()=>t.focus(),50)}function de(){ce.classList.remove("open"),P.style.display="none"}ce.addEventListener("click",de),document.getElementById("sp-save").addEventListener("click",async()=>{let n=document.getElementById("sp-name").value.trim();if(!n||n===_){de();return}try{if(!(await fetch(T("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:_,newName:n})})).ok)return;de(),O(),y===_&&oe(n)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+_+'"?'))try{if(!(await fetch(T("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:_})})).ok)return;de(),y===_&&(h&&(h.destroy(),h=null),y=null,I.style.display="none",F.style.display="flex"),O()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",de);var mn={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",n=>{let e=n.target.closest("button[data-key]");if(!e||!h)return;let t=mn[e.dataset.key];t&&(h.sendInput(t),h.focus())});var R=document.getElementById("mk-input"),gt=document.getElementById("mk-send");function yt(){if(!R||!h)return;let n=R.value;n&&(h.sendInput(n+"\r"),R.value="",R.rows=1,h.focus())}if(R&&(R.addEventListener("input",()=>{R.rows=1;let n=R.value.split(`
47
+ `).length;R.rows=Math.min(n,4)}),R.addEventListener("keydown",n=>{n.key==="Enter"&&!n.shiftKey&&(n.preventDefault(),yt())})),gt&&gt.addEventListener("click",yt),window.visualViewport){let n=document.querySelector(".app-layout"),e=()=>{n&&(n.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 $e=document.getElementById("process-panel"),ue=document.getElementById("proc-list"),hn=document.getElementById("proc-close"),Pe=document.getElementById("proc-backdrop"),vn=document.getElementById("header-ram");function gn(){ue.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(T("/api/system/processes")).then(n=>n.json()).then(n=>{if(!Array.isArray(n)||!n.length){ue.innerHTML='<div class="proc-empty">No processes</div>';return}let e="";for(let t of n){let i=t.rss,a=i<1048576?(i/1024).toFixed(0)+"K":(i/1048576).toFixed(1)+"M";e+='<div class="proc-row" data-pid="'+t.pid+'"><span class="proc-mem">'+t.mem+'%</span><span class="proc-rss">'+a+'</span><span class="proc-cmd" title="'+f(t.command)+'">'+f(t.command)+'</span><button class="proc-kill" title="Kill PID '+t.pid+'">&times;</button></div>'}ue.innerHTML=e;for(let t of ue.querySelectorAll(".proc-row")){let i=t.querySelector(".proc-kill");i&&i.addEventListener("click",a=>{let l=a.target.closest(".proc-row");!l||!confirm("Kill PID "+l.dataset.pid+"?")||fetch(T("/api/system/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(l.dataset.pid,10)})}).then(c=>c.json()).then(c=>{c.ok?l.style.opacity="0.3":alert("Failed: "+(c.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{ue.innerHTML='<div class="proc-empty">Failed to load</div>'})}function yn(){$e.classList.add("open"),Pe.classList.add("open"),gn()}function Se(){$e.classList.remove("open"),Pe.classList.remove("open")}vn.addEventListener("click",n=>{n.stopPropagation(),$e.classList.contains("open")?Se():yn()}),hn.addEventListener("click",Se),Pe.addEventListener("click",Se),window.__openSession=oe,window.__refreshSidebar=O,O(),Ae(),setInterval(()=>{document.visibilityState==="visible"&&O()},1e4);
@@ -1,8 +1,10 @@
1
- const Yt="https://esm.sh/ghostty-web@0.4.0",Pt=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function Y(s){return s.replace(Pt,"")}let P;function Ft(){return P||(document.querySelector("link[data-tmux-web-xterm-css]")?P=Promise.resolve():(P=new Promise(n=>{const i=document.createElement("link");i.rel="stylesheet",i.href="/assets/xterm.css",i.setAttribute("data-tmux-web-xterm-css",""),i.addEventListener("load",()=>n(),{once:!0}),i.addEventListener("error",()=>n(),{once:!0}),document.head.appendChild(i)}),P))}class A{terminal;fitAddon;container;constructor(n,i,r){this.container=n,this.terminal=i,this.fitAddon=r,this.terminal.loadAddon(this.fitAddon),this.terminal.open(n)}static async create(n,i,r){const[{Terminal:a},{FitAddon:c}]=await Promise.all([import("@xterm/xterm"),import("@xterm/addon-fit"),Ft()]),d=new a({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:i,convertEol:!1,theme:r});return new A(n,d,new c)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(n){return new Promise(i=>this.terminal.write(n,i))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(n){this.terminal.scrollToLine(Math.max(0,n))}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){const n=ot(this.container);return n.width<=0||n.height<=0?!1:(this.fitAddon.fit(),!0)}focus(){this.terminal.focus()}pasteText(n){this.terminal.paste(n)}input(n){this.terminal.input(n,!1)}onData(n){this.terminal.onData(n),this.terminal.onBinary(n)}onResize(n){this.terminal.onResize(n)}onScroll(n){this.terminal.onScroll(n)}attachCustomKeyEventHandler(n){this.terminal.attachCustomKeyEventHandler(n)}isFocused(){const n=document.activeElement;return!!n&&(n===this.container||this.container.contains(n))}getScreenText(){return this.getRowsText(0,this.terminal.rows-1)}getRowsText(n,i){const r=this.terminal.buffer.active,[a,c]=n<=i?[n,i]:[i,n],d=r.viewportY,l=[];for(let m=a;m<=c;m++){const u=r.getLine(d+m);l.push(u?u.translateToString(!0):"")}return l.join(`
2
- `)}selectRows(n,i){const r=this.terminal.buffer.active,[a,c]=n<=i?[n,i]:[i,n];this.terminal.selectLines(r.viewportY+a,r.viewportY+c)}hasSelectionSupport(){return!0}}class X{terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(n,i){this.container=n,this.terminal=i,this.terminal.open(n)}static async create(n,i,r){const a=await import(Yt);await a.init();const c=new a.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:i,convertEol:!1,theme:r});return new X(n,c)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(n){return new Promise(i=>this.terminal.write(n,i))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom?.()}scrollToLine(n){this.terminal.scrollToLine?.(Math.max(0,n))}isNearScrollbackTop(){const n=this.terminal.buffer?.active;return n?n.viewportY>=n.baseY:!1}viewportY(){return this.terminal.buffer?.active?.viewportY??0}baseY(){return this.terminal.buffer?.active?.baseY??0}fit(){const n=ot(this.container);if(n.width<=0||n.height<=0)return!1;this.updateCellMetrics(!this.charW||!this.charH);const i=Math.floor(n.width/this.charW),r=Math.floor(n.height/this.charH);if(i<10||r<5)return!1;if(i!==this.colsValue||r!==this.rowsValue){this.colsValue=i,this.rowsValue=r,this.terminal.resize(i,r);for(const a of this.resizeCallbacks)a({cols:i,rows:r})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(n){const i=this.terminal.getMode?.(2004)??!1;this.input(i?"\x1B[200~"+n+"\x1B[201~":n)}input(n){this.terminal.input?.(n,!1)}onData(n){this.terminal.onData(i=>n(i))}onResize(n){this.resizeCallbacks.push(n)}onScroll(n){this.terminal.onScroll(n)}attachCustomKeyEventHandler(n){this.terminal.attachCustomKeyEventHandler(n)}isFocused(){const n=document.activeElement;return!!n&&(n===this.container||n===this.terminal.textarea||this.container.contains(n))}getScreenText(){return this.getRowsText(0,this.rowsValue-1)}getRowsText(n,i){try{const r=this.terminal.buffer?.active;if(!r||typeof r.getLine!="function")return"";const[a,c]=n<=i?[n,i]:[i,n],d=typeof r.viewportY=="number"?r.viewportY:0,l=[];for(let m=a;m<=c;m++){const u=r.getLine(d+m);l.push(typeof u?.translateToString=="function"?u.translateToString(!0):"")}return l.join(`
3
- `)}catch{return""}}selectRows(n,i){try{if(typeof this.terminal?.selectLines!="function")return;const r=this.terminal.buffer?.active,a=typeof r?.viewportY=="number"?r.viewportY:0,[c,d]=n<=i?[n,i]:[i,n];this.terminal.selectLines(a+c,a+d)}catch{}}hasSelectionSupport(){return typeof this.terminal?.selectLines=="function"}updateCellMetrics(n=!1){const i=this.container.querySelector("canvas");if(i instanceof HTMLElement&&i.offsetWidth>0&&i.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){const r=i.offsetWidth/this.colsValue,a=i.offsetHeight/this.rowsValue;(n||!this.charW||!this.charH)&&(this.charW=r,this.charH=a)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}}function ot(s){const n=s.getBoundingClientRect(),i=window.visualViewport;return i?{width:Math.min(n.width,i.width),height:Math.max(0,Math.min(n.height,i.height-Math.max(0,n.top)))}:n}function Bt(s,n,i){return s.innerHTML="",s.classList.add("terminal-pending"),(async()=>{let r;if(i.renderer==="ghostty")try{r=await X.create(s,i.scrollback,i.theme)}catch{console.error("[tmux-web] ghostty-web failed; falling back to xterm.js"),r=await A.create(s,i.scrollback,i.theme)}else r=await A.create(s,i.scrollback,i.theme);let a,c=0,d,l=null,m=0,u="connecting",F=0,B=!1,H=[],g="",v=!1,T=1e3;const st=location.protocol==="https:"?"wss:":"ws:",at=i.wsBase||"/ws",lt=st+"//"+location.host+at+"/"+encodeURIComponent(n),ct="/api/session/"+encodeURIComponent(n)+"/upload",ut=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function ft(){return H.join("")+g}async function ht(t,e=0){const o=t?r.viewportY():0,h=t?r.baseY():0,w=Y(ft());if(r.reset(),!w){t||r.scrollToBottom();return}await r.write(w),t?r.scrollToLine(h+o+e):r.scrollToBottom()}function x(t){a?.readyState===WebSocket.OPEN&&a.send(JSON.stringify(t))}function dt(t){let e;try{e=JSON.parse(t)}catch{u==="live"&&(g+=t,r.write(Y(t)));return}if(e.type==="auth.required"){const o=localStorage.getItem("tmux-web-token");o?x({type:"auth.token",token:o}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(e.type==="attach_failed"&&typeof e.message=="string"){z=!0,u="dead",r.reset(),r.write(`\r
4
- \x1B[31m`+Y(e.message)+`\x1B[0m\r
5
- `).then(()=>{K();try{a?.close()}catch{}});return}if(e.type==="auth.ok"){e.token&&localStorage.setItem("tmux-web-token",e.token),T=1e3,E(),x({type:"resize",cols:r.cols,rows:r.rows}),f();return}if(e.type==="auth.failed"){if(e.permanentLock||e.retryAfterMs&&e.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(e.message);return}return}if(e.type==="snapshot"&&typeof e.data=="string"){const o=Y(e.data);H=[o],g="",F=typeof e.lines=="number"?e.lines:i.terminal.initialLines,u="live",r.reset(),r.write(o).then(()=>r.scrollToBottom());return}if(e.type==="window_changed"&&typeof e.activeIndex=="number"){const o=new URL(location.href);o.searchParams.get("window")!==String(e.activeIndex)&&(o.searchParams.set("window",String(e.activeIndex)),history.replaceState(history.state,"",o)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:e.windows}));return}if(e.type==="history"&&typeof e.data=="string"){B=!1,e.lines>0&&e.data&&(H.unshift(e.data),F+=e.lines,ht(!0,e.lines));return}if(e.type==="data"&&typeof e.data=="string"){const o=Y(e.data);if(u==="connecting"){u="live",g=o,r.write(o);return}u==="live"&&(g+=o,r.write(o))}}let z=!1;function j(){if(z)return;let t=lt;const e=localStorage.getItem("tmux-web-token");e&&(t+=(t.includes("?")?"&":"?")+"token="+encodeURIComponent(e)),a=new WebSocket(t),a.onopen=()=>{u="connecting",F=0,B=!1,H=[],g="",r.reset(),T=1e3},a.onmessage=o=>{typeof o.data=="string"&&dt(o.data)},a.onclose=()=>{v||(u="connecting",!z&&setTimeout(()=>{T=Math.min(T*2,1e4),!v&&!z&&j()},T))},a.onerror=()=>a?.close()}function I(t){x({type:"input",data:t})}function E(){return r.fit()}function K(){s.classList.remove("terminal-pending")}function f(){c&&cancelAnimationFrame(c),d&&clearTimeout(d),E(),c=requestAnimationFrame(()=>{c=0,E()&&K()}),d=setTimeout(()=>{E()&&K()},120)}function mt(){f(),setTimeout(f,50),setTimeout(f,150),setTimeout(f,300)}function q(t){return typeof t=="string"&&t.startsWith("image/")}function N(t){return t?.files?.length?t.files[0]??null:null}function pt(t){if(!t?.items)return null;for(let e=0;e<t.items.length;e++){const o=t.items[e];if(o?.kind==="file"&&q(o.type))return o.getAsFile()}return null}async function wt(t){const e=new FormData,o=t instanceof File&&t.name?t.name:"upload";e.append("file",t,o);const h=localStorage.getItem("tmux-web-token"),w={};h&&(w.Authorization="Bearer "+h);const U=await fetch(ct,{method:"POST",body:e,headers:w});if(!U.ok){let rt="upload failed";try{const it=await U.json();it.error&&(rt=it.error)}catch{}throw new Error(rt)}const nt=await U.json();if(!nt.path)throw new Error("no path in response");return nt.path}async function W(t){try{const e=await wt(t);I(e)}catch{}}r.onData(t=>I(t)),r.onResize(({cols:t,rows:e})=>x({type:"resize",cols:t,rows:e})),r.onScroll(()=>{u!=="live"||B||!r.isNearScrollbackTop()||(B=!0,x({type:"load_history",before:F}))});let L=!1,S=!1,p=null,y=null;const D=document.createElement("div");D.className="terminal-copy-banner",D.innerHTML='<strong>Copy mode</strong><span class="hint">drag to select \xB7 Esc exits</span>',D.hidden=!0,s.appendChild(D);const b=document.createElement("div");b.className="terminal-copy-banner terminal-copy-toast",b.textContent="Copied",b.hidden=!0,s.appendChild(b);function _(t){const e=s.getBoundingClientRect(),o=e.height>0&&r.rows>0?e.height/r.rows:18;return Math.max(0,Math.min(r.rows-1,Math.floor((t-e.top)/o)))}async function J(t){if(!t)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(t);return}}catch{}const e=document.createElement("textarea");e.value=t,e.style.position="fixed",e.style.opacity="0",e.style.pointerEvents="none",document.body.appendChild(e),e.focus(),e.select();try{document.execCommand("copy")}catch{}e.remove()}let C;function G(){b.hidden=!1,C&&clearTimeout(C),C=setTimeout(()=>{b.hidden=!0},1e3)}function M(t){L=t,D.hidden=!t,s.classList.toggle("terminal-copy-mode-active",t),t&&r.focus()}function Q(){M(!L)}function yt(){return p===null||y===null?null:p<=y?[p,y]:[y,p]}function gt(t){v||t.button!==0||S||(L||t.shiftKey)&&(t.preventDefault(),t.stopPropagation(),S=!0,p=_(t.clientY),y=p,r.selectRows(p,p),document.addEventListener("mousemove",R,!0),document.addEventListener("mouseup",O,!0))}function R(t){v||!S||p===null||(t.preventDefault(),t.stopPropagation(),y=_(t.clientY),r.selectRows(p,y))}function O(t){if(v||!S||p===null)return;t.preventDefault(),t.stopPropagation();const e=yt();document.removeEventListener("mousemove",R,!0),document.removeEventListener("mouseup",O,!0),S=!1,M(!1),e&&(J(r.getRowsText(e[0],e[1])).then(G),r.focus())}s.addEventListener("mousedown",gt,!0),r.attachCustomKeyEventHandler(t=>{if(t.type!=="keydown")return!0;if(L){if(t.key==="Escape")return t.preventDefault(),M(!1),!1;if(t.key==="Enter"||(t.ctrlKey||t.metaKey)&&t.code==="KeyC")return t.preventDefault(),J(r.getScreenText()).then(G),M(!1),!1}return t.altKey&&t.code==="KeyC"&&!t.ctrlKey&&!t.metaKey?(t.preventDefault(),Q(),!1):(t.ctrlKey||t.metaKey)&&t.code==="KeyV"?(t.preventDefault(),(async()=>{try{if(navigator.clipboard?.read){const e=await navigator.clipboard.read();for(const o of e)for(const h of o.types)if(q(h)){const w=await o.getType(h);await W(w);return}}}catch{}try{const e=await navigator.clipboard?.readText();e&&r.pasteText(Z(e))}catch{}})(),!1):!0});let V=0;function Z(t){return t.split(`\r
1
+ const kt="https://esm.sh/ghostty-web@0.4.0",Pt=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function K(a){return a.replace(Pt,"")}let A;function Ft(){return A||(document.querySelector("link[data-tmux-web-xterm-css]")?A=Promise.resolve():(A=new Promise(e=>{const r=document.createElement("link");r.rel="stylesheet",r.href="/assets/xterm.css",r.setAttribute("data-tmux-web-xterm-css",""),r.addEventListener("load",()=>e(),{once:!0}),r.addEventListener("error",()=>e(),{once:!0}),document.head.appendChild(r)}),A))}class q{terminal;fitAddon;container;constructor(e,r,i){this.container=e,this.terminal=r,this.fitAddon=i,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,r,i){const[{Terminal:o},{FitAddon:c}]=await Promise.all([import("@xterm/xterm"),import("@xterm/addon-fit"),Ft()]),h=new o({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:r,convertEol:!1,theme:i});return new q(e,h,new c)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(e){return new Promise(r=>this.terminal.write(e,r))}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(){const e=lt(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(){const e=document.activeElement;return e?e===this.container||e===this.terminal.textarea||this.container.contains(e)||!!e.closest?.(".xterm"):!1}getScreenText(){return this.getRowsText(0,this.terminal.rows-1)}getRowsText(e,r){const i=this.terminal.buffer.active,[o,c]=e<=r?[e,r]:[r,e],h=i.viewportY,l=[];for(let f=o;f<=c;f++){const u=i.getLine(h+f);l.push(u?u.translateToString(!0):"")}return l.join(`
2
+ `)}selectRows(e,r){const i=this.terminal.buffer.active,[o,c]=e<=r?[e,r]:[r,e];this.terminal.selectLines(i.viewportY+o,i.viewportY+c)}selectCells(e,r,i,o){const c=this.terminal.buffer.active,h=Math.min(r,o),l=Math.max(r,o);if(h===l){const f=Math.min(e,i),u=Math.max(e,i);this.terminal.select(f,c.viewportY+h,u-f+1)}else this.terminal.selectLines(c.viewportY+h,c.viewportY+l)}getCellsText(e,r,i,o){const c=this.terminal.buffer.active,h=Math.min(r,o),l=Math.max(r,o),f=r<o?e:r>o?i:Math.min(e,i),u=r<o?i:r>o?e:Math.max(e,i),x=c.viewportY,v=[];for(let p=h;p<=l;p++){const d=c.getLine(x+p);if(!d){v.push("");continue}const T=p===h?f:0,S=p===l?u:this.terminal.cols-1;let M="";for(let L=T;L<=S;L++){const C=d.getCell(L);C&&(M+=C.getChars())}v.push(M.replace(/\s+$/,""))}return v.join(`
3
+ `)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}}class ${terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(e,r){this.container=e,this.terminal=r,this.terminal.open(e)}static async create(e,r,i){const o=await import(kt);await o.init();const c=new o.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:r,convertEol:!1,theme:i});return new $(e,c)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(e){return new Promise(r=>this.terminal.write(e,r))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom?.()}scrollToLine(e){this.terminal.scrollToLine?.(Math.max(0,e))}isNearScrollbackTop(){const 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(){const e=lt(this.container);if(e.width<=0||e.height<=0)return!1;this.updateCellMetrics(!this.charW||!this.charH);const r=Math.floor(e.width/this.charW),i=Math.floor(e.height/this.charH);if(r<10||i<5)return!1;if(r!==this.colsValue||i!==this.rowsValue){this.colsValue=r,this.rowsValue=i,this.terminal.resize(r,i);for(const o of this.resizeCallbacks)o({cols:r,rows:i})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(e){const r=this.terminal.getMode?.(2004)??!1;this.input(r?"\x1B[200~"+e+"\x1B[201~":e)}input(e){this.terminal.input?.(e,!1)}onData(e){this.terminal.onData(r=>e(r))}onResize(e){this.resizeCallbacks.push(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){const e=document.activeElement;return!!e&&(e===this.container||e===this.terminal.textarea||this.container.contains(e))}getScreenText(){return this.getRowsText(0,this.rowsValue-1)}getRowsText(e,r){try{const i=this.terminal.buffer?.active;if(!i||typeof i.getLine!="function")return"";const[o,c]=e<=r?[e,r]:[r,e],h=typeof i.viewportY=="number"?i.viewportY:0,l=[];for(let f=o;f<=c;f++){const u=i.getLine(h+f);l.push(typeof u?.translateToString=="function"?u.translateToString(!0):"")}return l.join(`
4
+ `)}catch{return""}}selectRows(e,r){try{if(typeof this.terminal?.selectLines!="function")return;const i=this.terminal.buffer?.active,o=typeof i?.viewportY=="number"?i.viewportY:0,[c,h]=e<=r?[e,r]:[r,e];this.terminal.selectLines(o+c,o+h)}catch{}}selectCells(e,r,i,o){try{const c=this.terminal.buffer?.active,h=typeof c?.viewportY=="number"?c.viewportY:0,l=Math.min(r,o),f=Math.max(r,o);if(l===f){if(typeof this.terminal?.select!="function"){this.selectRows(l,f);return}const u=Math.min(e,i),x=Math.max(e,i);this.terminal.select(u,h+l,x-u+1)}else this.selectRows(l,f)}catch{this.selectRows(r,o)}}getCellsText(e,r,i,o){try{const c=this.terminal.buffer?.active;if(!c||typeof c.getLine!="function")return this.getRowsText(r,o);const h=typeof c.viewportY=="number"?c.viewportY:0,l=Math.min(r,o),f=Math.max(r,o),u=r<o?e:r>o?i:Math.min(e,i),x=r<o?i:r>o?e:Math.max(e,i),v=[];for(let p=l;p<=f;p++){const d=c.getLine(h+p);if(!d){v.push("");continue}const T=p===l?u:0,S=p===f?x:this.colsValue-1;let M="";if(typeof d.getCell=="function")for(let L=T;L<=S;L++){const C=d.getCell(L);C&&(M+=typeof C.getChars=="function"?C.getChars():"")}else M=typeof d.translateToString=="function"?d.translateToString(!1):"";v.push(M.replace(/\s+$/,""))}return v.join(`
5
+ `)}catch{return this.getRowsText(r,o)}}getSelection(){try{if(typeof this.terminal?.getSelection=="function")return this.terminal.getSelection()}catch{}return""}clearSelection(){try{typeof this.terminal?.clearSelection=="function"&&this.terminal.clearSelection()}catch{}}hasSelectionSupport(){return typeof this.terminal?.selectLines=="function"}updateCellMetrics(e=!1){const r=this.container.querySelector("canvas");if(r instanceof HTMLElement&&r.offsetWidth>0&&r.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){const i=r.offsetWidth/this.colsValue,o=r.offsetHeight/this.rowsValue;(e||!this.charW||!this.charH)&&(this.charW=i,this.charH=o)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}}function lt(a){const e=a.getBoundingClientRect(),r=window.visualViewport;return r?{width:Math.min(e.width,r.width),height:Math.max(0,Math.min(e.height,r.height-Math.max(0,e.top)))}:e}function Bt(a,e,r){return a.innerHTML="",a.classList.add("terminal-pending"),(async()=>{let i;if(r.renderer==="ghostty")try{i=await $.create(a,r.scrollback,r.theme)}catch{console.error("[tmux-web] ghostty-web failed; falling back to xterm.js"),i=await q.create(a,r.scrollback,r.theme)}else i=await q.create(a,r.scrollback,r.theme);let o,c=0,h,l=null,f=0,u="connecting",x=0,v=!1,p=[],d="",T=!1,S=1e3;const M=location.protocol==="https:"?"wss:":"ws:",L=r.wsBase||"/ws",C=M+"//"+location.host+L+"/"+encodeURIComponent(e),ct="/api/session/"+encodeURIComponent(e)+"/upload",ut=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function ft(){return p.join("")+d}async function ht(t,n=0){const s=t?i.viewportY():0,g=t?i.baseY():0,m=K(ft());if(i.reset(),!m){t||i.scrollToBottom();return}await i.write(m),t?i.scrollToLine(g+s+n):i.scrollToBottom()}function Y(t){o?.readyState===WebSocket.OPEN&&o.send(JSON.stringify(t))}function mt(t){let n;try{n=JSON.parse(t)}catch{u==="live"&&(d+=t,i.write(K(t)));return}if(n.type==="auth.required"){const s=localStorage.getItem("tmux-web-token");s?Y({type:"auth.token",token:s}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(n.type==="attach_failed"&&typeof n.message=="string"){V=!0,u="dead",i.reset(),i.write(`\r
6
+ \x1B[31m`+K(n.message)+`\x1B[0m\r
7
+ `).then(()=>{O();try{o?.close()}catch{}});return}if(n.type==="auth.ok"){n.token&&localStorage.setItem("tmux-web-token",n.token),S=1e3,k(),Y({type:"resize",cols:i.cols,rows:i.rows}),y();return}if(n.type==="auth.failed"){if(n.permanentLock||n.retryAfterMs&&n.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(n.message);return}return}if(n.type==="snapshot"&&typeof n.data=="string"){const s=K(n.data);p=[s],d="",x=typeof n.lines=="number"?n.lines:r.terminal.initialLines,u="live",i.reset(),i.write(s).then(()=>i.scrollToBottom());return}if(n.type==="window_changed"&&typeof n.activeIndex=="number"){const s=new URL(location.href);s.searchParams.get("window")!==String(n.activeIndex)&&(s.searchParams.set("window",String(n.activeIndex)),history.replaceState(history.state,"",s)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:n.windows}));return}if(n.type==="history"&&typeof n.data=="string"){v=!1,n.lines>0&&n.data&&(p.unshift(n.data),x+=n.lines,ht(!0,n.lines));return}if(n.type==="data"&&typeof n.data=="string"){const s=K(n.data);if(u==="connecting"){u="live",d=s,i.write(s);return}u==="live"&&(d+=s,i.write(s))}}let V=!1;function Q(){if(V)return;let t=C;const n=localStorage.getItem("tmux-web-token");n&&(t+=(t.includes("?")?"&":"?")+"token="+encodeURIComponent(n)),o=new WebSocket(t),o.onopen=()=>{u="connecting",x=0,v=!1,p=[],d="",i.reset(),S=1e3},o.onmessage=s=>{typeof s.data=="string"&&mt(s.data)},o.onclose=()=>{T||(u="connecting",!V&&setTimeout(()=>{S=Math.min(S*2,1e4),!T&&!V&&Q()},S))},o.onerror=()=>o?.close()}function W(t){Y({type:"input",data:t})}function k(){return i.fit()}function O(){a.classList.remove("terminal-pending")}function y(){c&&cancelAnimationFrame(c),h&&clearTimeout(h),k(),c=requestAnimationFrame(()=>{c=0,k()&&O()}),h=setTimeout(()=>{k()&&O()},120)}function pt(){y(),setTimeout(y,50),setTimeout(y,150),setTimeout(y,300)}function Z(t){return typeof t=="string"&&t.startsWith("image/")}function R(t){return t?.files?.length?t.files[0]??null:null}function dt(t){if(!t?.items)return null;for(let n=0;n<t.items.length;n++){const s=t.items[n];if(s?.kind==="file"&&Z(s.type))return s.getAsFile()}return null}async function gt(t){const n=new FormData,s=t instanceof File&&t.name?t.name:"upload";n.append("file",t,s);const g=localStorage.getItem("tmux-web-token"),m={};g&&(m.Authorization="Bearer "+g);const I=await fetch(ct,{method:"POST",body:n,headers:m});if(!I.ok){let st="upload failed";try{const at=await I.json();at.error&&(st=at.error)}catch{}throw new Error(st)}const U=await I.json();if(!U.path)throw new Error("no path in response");return U.path}async function N(t){try{const n=await gt(t);W(n)}catch{}}i.onData(t=>W(t)),i.onResize(({cols:t,rows:n})=>Y({type:"resize",cols:t,rows:n})),i.onScroll(()=>{u!=="live"||v||!i.isNearScrollbackTop()||(v=!0,Y({type:"load_history",before:x}))});let P=!1,F=!1,w=null,b=null;const B=document.createElement("div");B.className="terminal-copy-banner",B.innerHTML='<strong>Copy mode</strong><span class="hint">drag to select \xB7 Alt+C copies \xB7 Esc exits</span>',B.hidden=!0,a.appendChild(B);const E=document.createElement("div");E.className="terminal-copy-banner terminal-copy-toast",E.textContent="Copied",E.hidden=!0,a.appendChild(E);function tt(t,n){const s=a.querySelector(".xterm-screen, canvas"),m=(s&&s.getBoundingClientRect().width>0?s:a).getBoundingClientRect(),I=m.height>0&&i.rows>0?m.height/i.rows:18,U=m.width>0&&i.cols>0?m.width/i.cols:9;return{row:Math.max(0,Math.min(i.rows-1,Math.floor((n-m.top)/I))),col:Math.max(0,Math.min(i.cols-1,Math.floor((t-m.left)/U)))}}async function _(t){if(!t)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(t);return}}catch{}const n=document.createElement("textarea");n.value=t,n.style.position="fixed",n.style.opacity="0",n.style.pointerEvents="none",document.body.appendChild(n),n.focus(),n.select();try{document.execCommand("copy")}catch{}n.remove()}let z;function X(){E.hidden=!1,z&&clearTimeout(z),z=setTimeout(()=>{E.hidden=!0},1e3)}function D(t){P=t,B.hidden=!t,a.classList.toggle("terminal-copy-mode-active",t),t&&i.focus()}function et(){D(!P)}function yt(t){T||t.button!==0||F||(P||t.shiftKey)&&(t.preventDefault(),t.stopPropagation(),F=!0,w=tt(t.clientX,t.clientY),b=w,i.selectCells(w.col,w.row,b.col,b.row),document.addEventListener("mousemove",J,!0),document.addEventListener("mouseup",G,!0))}function J(t){T||!F||!w||(t.preventDefault(),t.stopPropagation(),b=tt(t.clientX,t.clientY),i.selectCells(w.col,w.row,b.col,b.row))}function G(t){T||!F||!w||!b||(t.preventDefault(),t.stopPropagation(),document.removeEventListener("mousemove",J,!0),document.removeEventListener("mouseup",G,!0),F=!1,D(!1),E.textContent="\u5DF2\u9009\u4E2D \xB7 Alt+C \u590D\u5236",X(),i.focus())}a.addEventListener("mousedown",yt,!0),document.addEventListener("keydown",wt,!0);function wt(t){if(!(T||!i.isFocused()||t.defaultPrevented||t.isComposing)){if(P){if(t.key==="Escape"){t.preventDefault(),t.stopPropagation(),w=null,b=null,i.clearSelection(),D(!1);return}if(t.key==="Enter"||(t.ctrlKey||t.metaKey)&&t.code==="KeyC"){t.preventDefault(),t.stopPropagation(),_(i.getScreenText()).then(X),D(!1);return}}if(t.altKey&&t.code==="KeyC"&&!t.ctrlKey&&!t.metaKey){if(t.preventDefault(),t.stopPropagation(),w&&b){const n=i.getCellsText(w.col,w.row,b.col,b.row);w=null,b=null,i.clearSelection(),D(!1),n&&(E.textContent="Copied",_(n).then(X))}else{const n=i.getSelection();n?(i.clearSelection(),E.textContent="Copied",_(n).then(X)):et()}return}if((t.ctrlKey||t.metaKey)&&t.code==="KeyV"){t.preventDefault(),t.stopPropagation(),(async()=>{try{if(navigator.clipboard?.read){const n=await navigator.clipboard.read();for(const s of n)for(const g of s.types)if(Z(g)){const m=await s.getType(g);await N(m);return}}}catch{}try{const n=await navigator.clipboard?.readText();n&&i.pasteText(nt(n))}catch{}})();return}}}let j=0;function nt(t){return t.split(`\r
6
8
  `).join(`
7
9
  `).split(`
8
- `).join("\r")}async function vt(t){const e=pt(t.clipboardData);if(e){t.preventDefault(),t.stopPropagation();const w=Date.now();if(w-V<50)return;V=w,await W(e);return}const o=t.clipboardData?.getData("text/plain");if(!o)return;t.preventDefault(),t.stopPropagation();const h=Date.now();h-V<50||(V=h,r.pasteText(Z(o)))}let k=0;function bt(t){t.preventDefault(),k++,N(t.dataTransfer)&&s.classList.add("terminal-drag-over")}function Tt(t){t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy")}function xt(t){t.preventDefault(),k--,k<=0&&(k=0,s.classList.remove("terminal-drag-over"))}async function Et(t){t.preventDefault(),k=0,s.classList.remove("terminal-drag-over");const e=N(t.dataTransfer);e&&await W(e)}function $(t){!ut||t.key!=="Escape"||L||t.defaultPrevented||t.repeat||t.metaKey||t.ctrlKey||t.altKey||r.isFocused()&&(t.preventDefault(),t.stopPropagation(),I("\x1B"))}s.addEventListener("paste",vt),s.addEventListener("dragenter",bt),s.addEventListener("dragover",Tt),s.addEventListener("dragleave",xt),s.addEventListener("drop",Et),document.addEventListener("keydown",$,!0);function Lt(t){if(t.touches.length!==1){l=null;return}const e=t.touches[0];e&&(l={startX:e.clientX,startY:e.clientY,lastX:e.clientX,lastY:e.clientY,scrolling:!1},t.stopPropagation())}function St(t){if(!l||t.touches.length!==1)return;const e=t.touches[0];if(!e)return;const o=e.clientY-l.startY,h=e.clientX-l.startX;if(!l.scrolling){if(Math.abs(o)<8||Math.abs(o)<Math.abs(h))return;l.scrolling=!0,m=Date.now()+500}t.preventDefault(),t.stopPropagation(),kt(-(e.clientY-l.lastY),e.clientX,e.clientY),l.lastX=e.clientX,l.lastY=e.clientY}function Dt(t){if(!l)return;const e=l.scrolling;l=null,t.stopPropagation(),e?(m=Date.now()+500,t.preventDefault()):r.focus()}function Ct(t){l=null,t.stopPropagation()}function Mt(t){t.pointerType==="touch"&&Date.now()<m&&(t.preventDefault(),t.stopPropagation())}function kt(t,e,o){(s.querySelector(".xterm-screen")??s).dispatchEvent(new WheelEvent("wheel",{deltaY:t,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:e,clientY:o,bubbles:!0,cancelable:!0}))}s.addEventListener("touchstart",Lt,{passive:!0,capture:!0}),s.addEventListener("touchmove",St,{passive:!1,capture:!0}),s.addEventListener("touchend",Dt,{passive:!1,capture:!0}),s.addEventListener("touchcancel",Ct,{passive:!0,capture:!0}),s.addEventListener("pointerup",Mt,!0);function tt(){f()}window.addEventListener("resize",tt),window.visualViewport?.addEventListener("resize",f),window.visualViewport?.addEventListener("scroll",f);const et=new ResizeObserver(()=>f());return et.observe(s),document.fonts?.ready.then(()=>{f(),setTimeout(f,50),setTimeout(f,200)}),s.addEventListener("focusin",mt,!0),requestAnimationFrame(()=>{E()&&K(),j(),f()}),{destroy(){if(v=!0,M(!1),C&&clearTimeout(C),document.removeEventListener("mousemove",R,!0),document.removeEventListener("mouseup",O,!0),a){try{a.close(1e3,"session switch")}catch{}a=void 0}s.innerHTML="",s.classList.remove("terminal-pending"),window.removeEventListener("resize",tt),et.disconnect(),document.removeEventListener("keydown",$,!0)},focus(){r.focus()},sendInput(t){I(t)},toggleCopyMode(){Q()}}})()}export{Bt as initTerminal};
10
+ `).join("\r")}async function vt(t){const n=dt(t.clipboardData);if(n){t.preventDefault(),t.stopPropagation();const m=Date.now();if(m-j<50)return;j=m,await N(n);return}const s=t.clipboardData?.getData("text/plain");if(!s)return;t.preventDefault(),t.stopPropagation();const g=Date.now();g-j<50||(j=g,i.pasteText(nt(s)))}let H=0;function bt(t){t.preventDefault(),H++,R(t.dataTransfer)&&a.classList.add("terminal-drag-over")}function Tt(t){t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy")}function xt(t){t.preventDefault(),H--,H<=0&&(H=0,a.classList.remove("terminal-drag-over"))}async function St(t){t.preventDefault(),H=0,a.classList.remove("terminal-drag-over");const n=R(t.dataTransfer);n&&await N(n)}function it(t){!ut||t.key!=="Escape"||P||t.defaultPrevented||t.repeat||t.metaKey||t.ctrlKey||t.altKey||i.isFocused()&&(t.preventDefault(),t.stopPropagation(),W("\x1B"))}a.addEventListener("paste",vt),a.addEventListener("dragenter",bt),a.addEventListener("dragover",Tt),a.addEventListener("dragleave",xt),a.addEventListener("drop",St),document.addEventListener("keydown",it,!0);function Lt(t){if(t.touches.length!==1){l=null;return}const n=t.touches[0];n&&(l={startX:n.clientX,startY:n.clientY,lastX:n.clientX,lastY:n.clientY,scrolling:!1},t.stopPropagation())}function Et(t){if(!l||t.touches.length!==1)return;const n=t.touches[0];if(!n)return;const s=n.clientY-l.startY,g=n.clientX-l.startX;if(!l.scrolling){if(Math.abs(s)<8||Math.abs(s)<Math.abs(g))return;l.scrolling=!0,f=Date.now()+500}t.preventDefault(),t.stopPropagation(),Yt(-(n.clientY-l.lastY),n.clientX,n.clientY),l.lastX=n.clientX,l.lastY=n.clientY}function Mt(t){if(!l)return;const n=l.scrolling;l=null,t.stopPropagation(),n?(f=Date.now()+500,t.preventDefault()):i.focus()}function Ct(t){l=null,t.stopPropagation()}function Dt(t){t.pointerType==="touch"&&Date.now()<f&&(t.preventDefault(),t.stopPropagation())}function Yt(t,n,s){(a.querySelector(".xterm-screen")??a).dispatchEvent(new WheelEvent("wheel",{deltaY:t,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:n,clientY:s,bubbles:!0,cancelable:!0}))}a.addEventListener("touchstart",Lt,{passive:!0,capture:!0}),a.addEventListener("touchmove",Et,{passive:!1,capture:!0}),a.addEventListener("touchend",Mt,{passive:!1,capture:!0}),a.addEventListener("touchcancel",Ct,{passive:!0,capture:!0}),a.addEventListener("pointerup",Dt,!0);function rt(){y()}window.addEventListener("resize",rt),window.visualViewport?.addEventListener("resize",y),window.visualViewport?.addEventListener("scroll",y);const ot=new ResizeObserver(()=>y());return ot.observe(a),document.fonts?.ready.then(()=>{y(),setTimeout(y,50),setTimeout(y,200)}),a.addEventListener("focusin",pt,!0),requestAnimationFrame(()=>{k()&&O(),Q(),y()}),{destroy(){if(T=!0,D(!1),z&&clearTimeout(z),document.removeEventListener("mousemove",J,!0),document.removeEventListener("mouseup",G,!0),o){try{o.close(1e3,"session switch")}catch{}o=void 0}a.innerHTML="",a.classList.remove("terminal-pending"),window.removeEventListener("resize",rt),ot.disconnect(),document.removeEventListener("keydown",it,!0)},focus(){i.focus()},sendInput(t){W(t)},toggleCopyMode(){et()}}})()}export{Bt as initTerminal};
@@ -1,6 +1,6 @@
1
- import*as O from"node-pty";const f=new Set;function _(){for(const n of[...f])try{n()}catch{}f.clear()}function B(){return f.size}function H(n,r,e){const{initialLines:M,historyChunk:C,syncIdleMs:k,syncMaxMs:g}=e.terminalBufferConfig,A=e.spawn??(o=>{const c=e.tmuxSocketPath?["-S",e.tmuxSocketPath]:[];return c.push("attach-session","-t",o),O.spawn("tmux",c,{name:"xterm-256color",cols:80,rows:24,cwd:process.env.HOME||"/",env:process.env})});let a=null,y=n,h=null,w=0,S="",d=!0,m="",u=null,p=null,s=!1;const T=()=>{u&&(clearTimeout(u),u=null),p&&(clearTimeout(p),p=null)},P=()=>{if(!(!d||s)){T(),d=!1;try{y=e.getSessionPaneTarget(n)}catch{y=n}try{const o=e.capturePaneTail(y,M);r.send({type:"snapshot",data:e.toCrlf(o),lines:M})}catch{r.send({type:"data",data:`\r
2
- `})}m&&(r.send({type:"data",data:m}),m="")}},E=()=>{d&&(u&&clearTimeout(u),u=setTimeout(P,k))};function $(){if(s)return;try{a=A(n)}catch(t){const l=t?.message??String(t);r.send({type:"data",data:`\r
3
- \x1B[31mFailed to attach to tmux session "${n}": ${l}\x1B[0m\r
4
- `}),e.onSpawnError?.(n,l);return}let o=-1,c="";h=e.acquireControlClient(n,({activeIndex:t,windows:l})=>{r.send({type:"window_changed",activeIndex:t,windows:l});const x=l.map(D=>D.index).join(","),v=t!==o||x!==c;o=t,c=x}),w=Date.now(),p=setTimeout(P,g),e.onAttached?.(n),r.onMessage(b),a.onData(t=>{if(!s){if(Date.now()-w<g&&S.length<2048&&(S+=t),d){m+=t,E();return}r.send({type:"data",data:t})}}),a.onExit(({exitCode:t})=>{if(T(),a&&(a=null),!s){if(t!==0&&Date.now()-w<g){const l=S.trim();e.onSpawnError?.(n,l?`tmux attach-session failed: ${l}`:`tmux attach-session exited with code ${t}`);return}e.onPtyExit?.(n,t),r.send({type:"data",data:`\r
1
+ import*as O from"node-pty";import{tmuxEnv as _}from"./tmux-env.js";const f=new Set;function H(){for(const e of[...f])try{e()}catch{}f.clear()}function K(){return f.size}function j(e,r,n){const{initialLines:M,historyChunk:C,syncIdleMs:k,syncMaxMs:g}=n.terminalBufferConfig,A=n.spawn??(o=>{const c=n.tmuxSocketPath?["-S",n.tmuxSocketPath]:[];return c.push("attach-session","-t",o),O.spawn("tmux",c,{name:"xterm-256color",cols:80,rows:24,cwd:process.env.HOME||"/",env:_()})});let a=null,y=e,h=null,w=0,S="",d=!0,m="",u=null,p=null,s=!1;const T=()=>{u&&(clearTimeout(u),u=null),p&&(clearTimeout(p),p=null)},P=()=>{if(!(!d||s)){T(),d=!1;try{y=n.getSessionPaneTarget(e)}catch{y=e}try{const o=n.capturePaneTail(y,M);r.send({type:"snapshot",data:n.toCrlf(o),lines:M})}catch{r.send({type:"data",data:`\r
2
+ `})}m&&(r.send({type:"data",data:m}),m="")}},E=()=>{d&&(u&&clearTimeout(u),u=setTimeout(P,k))};function $(){if(s)return;try{a=A(e)}catch(t){const l=t?.message??String(t);r.send({type:"data",data:`\r
3
+ \x1B[31mFailed to attach to tmux session "${e}": ${l}\x1B[0m\r
4
+ `}),n.onSpawnError?.(e,l);return}let o=-1,c="";h=n.acquireControlClient(e,({activeIndex:t,windows:l})=>{r.send({type:"window_changed",activeIndex:t,windows:l});const x=l.map(D=>D.index).join(","),v=t!==o||x!==c;o=t,c=x}),w=Date.now(),p=setTimeout(P,g),n.onAttached?.(e),r.onMessage(b),a.onData(t=>{if(!s){if(Date.now()-w<g&&S.length<2048&&(S+=t),d){m+=t,E();return}r.send({type:"data",data:t})}}),a.onExit(({exitCode:t})=>{if(T(),a&&(a=null),!s){if(t!==0&&Date.now()-w<g){const l=S.trim();n.onSpawnError?.(e,l?`tmux attach-session failed: ${l}`:`tmux attach-session exited with code ${t}`);return}n.onPtyExit?.(e,t),r.send({type:"data",data:`\r
5
5
  \x1B[2m--- tmux exited (code ${t}) ---\x1B[0m\r
6
- `}),i()}})}function i(){if(!s){if(s=!0,T(),h&&(h(),h=null),a){try{a.kill()}catch{}a=null}f.delete(i)}}r.onClose(i);const b=o=>{if(s||!a)return;try{if(e.handleClientMessage(o,a))return}catch{return}let c;try{c=JSON.parse(o)}catch{return}if(c.type==="load_history"&&typeof c.before=="number"){const t=Math.max(0,Math.floor(c.before));try{const{data:l,lines:x}=e.capturePaneHistoryChunk(y,t,C);r.send({type:"history",data:e.toCrlf(l),before:t,lines:x})}catch{r.send({type:"history",data:"",before:t,lines:0})}}};return $(),f.add(i),{onMessage:b,dispose:i}}export{B as _liveAttachmentCount,H as attachTerminal,_ as killAllAttachedPtys};
6
+ `}),i()}})}function i(){if(!s){if(s=!0,T(),h&&(h(),h=null),a){try{a.kill()}catch{}a=null}f.delete(i)}}r.onClose(i);const b=o=>{if(s||!a)return;try{if(n.handleClientMessage(o,a))return}catch{return}let c;try{c=JSON.parse(o)}catch{return}if(c.type==="load_history"&&typeof c.before=="number"){const t=Math.max(0,Math.floor(c.before));try{const{data:l,lines:x}=n.capturePaneHistoryChunk(y,t,C);r.send({type:"history",data:n.toCrlf(l),before:t,lines:x})}catch{r.send({type:"history",data:"",before:t,lines:0})}}};return $(),f.add(i),{onMessage:b,dispose:i}}export{K as _liveAttachmentCount,j as attachTerminal,H as killAllAttachedPtys};
@@ -1 +1 @@
1
- import{execFileSync as o}from"node:child_process";import{randomUUID as c}from"node:crypto";import{ARM_SCAN_INTERVAL_MS as u,isValidDelayMs as h,MAX_TIMER_MS as n}from"./schedule-delay.js";const T=10080*60*1e3;function m(a,e,s){const t=`${a}:${e}`;o("tmux",["send-keys","-t",t,"-l",s],{timeout:5e3}),o("tmux",["send-keys","-t",t,"Enter"],{timeout:5e3})}function w(a){if(!a||typeof a!="object")return!1;const e=a;return typeof e.delayMs=="number"&&h(e.delayMs)}function y(a){if(!a||typeof a!="object")return!1;const e=a;return typeof e.sessionName=="string"&&e.sessionName.length>0&&typeof e.windowIndex=="number"&&Number.isInteger(e.windowIndex)&&e.windowIndex>=0&&typeof e.text=="string"&&e.text.length>0&&e.text.length<=4096&&typeof e.delayMs=="number"&&h(e.delayMs)}class I{deps;scheduledTasks=new Map;now;setTimer;clearTimer;setIntervalFn;clearIntervalFn;armScanIntervalMs;createId;sendKeys;onError;onMissedTask;historyRetentionMs;scanIntervalHandle=null;constructor(e){this.deps=e,this.now=e.now??Date.now,this.setTimer=e.setTimer??setTimeout,this.clearTimer=e.clearTimer??clearTimeout,this.setIntervalFn=e.setInterval??setInterval,this.clearIntervalFn=e.clearInterval??clearInterval,this.armScanIntervalMs=e.armScanIntervalMs??u,this.createId=e.createId??c,this.sendKeys=e.sendKeys??m,this.onError=e.onError??(s=>console.error(s)),this.onMissedTask=e.onMissedTask??(()=>{}),this.historyRetentionMs=e.historyRetentionMs??T}record(e){this.deps.db.data.triggeredTasks??=[],this.deps.db.data.triggeredTasks.push(e);const s=this.now()-this.historyRetentionMs;this.deps.db.data.triggeredTasks=this.deps.db.data.triggeredTasks.filter(t=>t.triggeredAt>=s)}listTriggered(){this.deps.db.data.triggeredTasks??=[];const e=this.now()-this.historyRetentionMs;return this.deps.db.data.triggeredTasks.filter(s=>s.triggeredAt>=e).sort((s,t)=>t.triggeredAt-s.triggeredAt)}async restoreFromDb(){const e=this.now(),s=[];for(const r of this.deps.db.data.scheduledTasks)r.fireAt<=e?(s.push(r.id),this.onMissedTask(r),this.record({...r,triggeredAt:e,status:"missed"})):this.registerTask(r);this.deps.db.data.triggeredTasks??=[];const t=this.deps.db.data.triggeredTasks.length,i=e-this.historyRetentionMs;this.deps.db.data.triggeredTasks=this.deps.db.data.triggeredTasks.filter(r=>r.triggeredAt>=i);const d=this.deps.db.data.triggeredTasks.length!==t;s.length&&(this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(r=>!s.includes(r.id))),(s.length||d)&&await this.deps.db.write(),this.scanPending(),this.startScanLoop()}list(e){return[...this.scheduledTasks.values()].filter(s=>!e||s.sessionName===e).map(({id:s,sessionName:t,windowIndex:i,text:d,fireAt:r,createdAt:l})=>({id:s,sessionName:t,windowIndex:i,text:d,fireAt:r,createdAt:l,remainingMs:Math.max(0,r-this.now())})).sort((s,t)=>s.fireAt-t.fireAt)}async create(e){const s=this.createId(),t=this.now(),i={id:s,sessionName:e.sessionName,windowIndex:e.windowIndex,text:e.text,fireAt:t+e.delayMs,createdAt:t};return this.registerTask(i),this.deps.db.data.scheduledTasks.push(i),await this.deps.db.write(),this.tryArm(i.id),i}async reschedule(e,s){const t=this.scheduledTasks.get(e);if(!t)return null;this.disarmTask(e);const i={...t,fireAt:this.now()+s};this.registerTask(i);const d=this.deps.db.data.scheduledTasks.findIndex(r=>r.id===e);return d>=0&&(this.deps.db.data.scheduledTasks[d]=i),await this.deps.db.write(),this.tryArm(e),i}async delete(e){return this.scheduledTasks.get(e)?(this.disarmTask(e),this.scheduledTasks.delete(e),this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(t=>t.id!==e),await this.deps.db.write(),!0):!1}cleanup(){if(this.scanIntervalHandle!=null){try{this.clearIntervalFn(this.scanIntervalHandle)}catch{}this.scanIntervalHandle=null}for(const e of this.scheduledTasks.values())if(e.timeoutHandle!=null)try{this.clearTimer(e.timeoutHandle)}catch{}this.scheduledTasks.clear()}scanPending(){for(const e of[...this.scheduledTasks.values()]){const s=e.fireAt-this.now();if(s<=0){e.timeoutHandle!=null&&this.disarmTask(e.id),this.fireTask(e);continue}s<=n&&e.timeoutHandle==null&&this.armTask(e)}}registerTask(e){this.scheduledTasks.set(e.id,{...e,timeoutHandle:null})}disarmTask(e){const s=this.scheduledTasks.get(e);s&&s.timeoutHandle!=null&&(this.clearTimer(s.timeoutHandle),s.timeoutHandle=null)}tryArm(e){const s=this.scheduledTasks.get(e);if(!s)return;const t=s.fireAt-this.now();if(t<=0){this.fireTask(s);return}t<=n&&s.timeoutHandle==null&&this.armTask(s)}armTask(e){const s=e.fireAt-this.now();if(s<=0){this.fireTask(e);return}this.disarmTask(e.id);const t=Math.min(s,n),i=this.setTimer(()=>this.onTimer(e.id),t);this.scheduledTasks.set(e.id,{...e,timeoutHandle:i})}onTimer(e){const s=this.scheduledTasks.get(e);if(s){if(s.timeoutHandle=null,s.fireAt<=this.now()){this.fireTask(s);return}this.armTask(s)}}startScanLoop(){this.scanIntervalHandle==null&&(this.scanIntervalHandle=this.setIntervalFn(()=>this.scanPending(),this.armScanIntervalMs))}fireTask(e){if(!this.scheduledTasks.has(e.id))return;this.disarmTask(e.id);const s=this.now(),t={id:e.id,sessionName:e.sessionName,windowIndex:e.windowIndex,text:e.text,fireAt:e.fireAt,createdAt:e.createdAt};try{this.sendKeys(e.sessionName,e.windowIndex,e.text),this.record({...t,triggeredAt:s,status:"ok"})}catch(i){const d=String(i?.message??i);this.onError(`[scheduler] send-keys to ${e.sessionName}:${e.windowIndex} failed: ${d}`),this.record({...t,triggeredAt:s,status:"error",error:d})}this.scheduledTasks.delete(e.id),this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(i=>i.id!==e.id),this.deps.db.write().catch(this.onError)}}export{I as SchedulerService,w as isValidRescheduleInput,y as isValidScheduleInput,m as sendTmuxKeys};
1
+ import{execFileSync as o}from"node:child_process";import{tmuxEnv as h}from"./tmux-env.js";import{randomUUID as u}from"node:crypto";import{ARM_SCAN_INTERVAL_MS as T,isValidDelayMs as l,MAX_TIMER_MS as d}from"./schedule-delay.js";const m=10080*60*1e3;function f(n,e,s){const t=`${n}:${e}`;o("tmux",["send-keys","-t",t,"-l",s],{timeout:5e3,env:h()}),o("tmux",["send-keys","-t",t,"Enter"],{timeout:5e3,env:h()})}function I(n){if(!n||typeof n!="object")return!1;const e=n;return typeof e.delayMs=="number"&&l(e.delayMs)}function p(n){if(!n||typeof n!="object")return!1;const e=n;return typeof e.sessionName=="string"&&e.sessionName.length>0&&typeof e.windowIndex=="number"&&Number.isInteger(e.windowIndex)&&e.windowIndex>=0&&typeof e.text=="string"&&e.text.length>0&&e.text.length<=4096&&typeof e.delayMs=="number"&&l(e.delayMs)}class b{deps;scheduledTasks=new Map;now;setTimer;clearTimer;setIntervalFn;clearIntervalFn;armScanIntervalMs;createId;sendKeys;onError;onMissedTask;historyRetentionMs;scanIntervalHandle=null;constructor(e){this.deps=e,this.now=e.now??Date.now,this.setTimer=e.setTimer??setTimeout,this.clearTimer=e.clearTimer??clearTimeout,this.setIntervalFn=e.setInterval??setInterval,this.clearIntervalFn=e.clearInterval??clearInterval,this.armScanIntervalMs=e.armScanIntervalMs??T,this.createId=e.createId??u,this.sendKeys=e.sendKeys??f,this.onError=e.onError??(s=>console.error(s)),this.onMissedTask=e.onMissedTask??(()=>{}),this.historyRetentionMs=e.historyRetentionMs??m}record(e){this.deps.db.data.triggeredTasks??=[],this.deps.db.data.triggeredTasks.push(e);const s=this.now()-this.historyRetentionMs;this.deps.db.data.triggeredTasks=this.deps.db.data.triggeredTasks.filter(t=>t.triggeredAt>=s)}listTriggered(){this.deps.db.data.triggeredTasks??=[];const e=this.now()-this.historyRetentionMs;return this.deps.db.data.triggeredTasks.filter(s=>s.triggeredAt>=e).sort((s,t)=>t.triggeredAt-s.triggeredAt)}async restoreFromDb(){const e=this.now(),s=[];for(const r of this.deps.db.data.scheduledTasks)r.fireAt<=e?(s.push(r.id),this.onMissedTask(r),this.record({...r,triggeredAt:e,status:"missed"})):this.registerTask(r);this.deps.db.data.triggeredTasks??=[];const t=this.deps.db.data.triggeredTasks.length,i=e-this.historyRetentionMs;this.deps.db.data.triggeredTasks=this.deps.db.data.triggeredTasks.filter(r=>r.triggeredAt>=i);const a=this.deps.db.data.triggeredTasks.length!==t;s.length&&(this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(r=>!s.includes(r.id))),(s.length||a)&&await this.deps.db.write(),this.scanPending(),this.startScanLoop()}list(e){return[...this.scheduledTasks.values()].filter(s=>!e||s.sessionName===e).map(({id:s,sessionName:t,windowIndex:i,text:a,fireAt:r,createdAt:c})=>({id:s,sessionName:t,windowIndex:i,text:a,fireAt:r,createdAt:c,remainingMs:Math.max(0,r-this.now())})).sort((s,t)=>s.fireAt-t.fireAt)}async create(e){const s=this.createId(),t=this.now(),i={id:s,sessionName:e.sessionName,windowIndex:e.windowIndex,text:e.text,fireAt:t+e.delayMs,createdAt:t};return this.registerTask(i),this.deps.db.data.scheduledTasks.push(i),await this.deps.db.write(),this.tryArm(i.id),i}async reschedule(e,s){const t=this.scheduledTasks.get(e);if(!t)return null;this.disarmTask(e);const i={...t,fireAt:this.now()+s};this.registerTask(i);const a=this.deps.db.data.scheduledTasks.findIndex(r=>r.id===e);return a>=0&&(this.deps.db.data.scheduledTasks[a]=i),await this.deps.db.write(),this.tryArm(e),i}async delete(e){return this.scheduledTasks.get(e)?(this.disarmTask(e),this.scheduledTasks.delete(e),this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(t=>t.id!==e),await this.deps.db.write(),!0):!1}cleanup(){if(this.scanIntervalHandle!=null){try{this.clearIntervalFn(this.scanIntervalHandle)}catch{}this.scanIntervalHandle=null}for(const e of this.scheduledTasks.values())if(e.timeoutHandle!=null)try{this.clearTimer(e.timeoutHandle)}catch{}this.scheduledTasks.clear()}scanPending(){for(const e of[...this.scheduledTasks.values()]){const s=e.fireAt-this.now();if(s<=0){e.timeoutHandle!=null&&this.disarmTask(e.id),this.fireTask(e);continue}s<=d&&e.timeoutHandle==null&&this.armTask(e)}}registerTask(e){this.scheduledTasks.set(e.id,{...e,timeoutHandle:null})}disarmTask(e){const s=this.scheduledTasks.get(e);s&&s.timeoutHandle!=null&&(this.clearTimer(s.timeoutHandle),s.timeoutHandle=null)}tryArm(e){const s=this.scheduledTasks.get(e);if(!s)return;const t=s.fireAt-this.now();if(t<=0){this.fireTask(s);return}t<=d&&s.timeoutHandle==null&&this.armTask(s)}armTask(e){const s=e.fireAt-this.now();if(s<=0){this.fireTask(e);return}this.disarmTask(e.id);const t=Math.min(s,d),i=this.setTimer(()=>this.onTimer(e.id),t);this.scheduledTasks.set(e.id,{...e,timeoutHandle:i})}onTimer(e){const s=this.scheduledTasks.get(e);if(s){if(s.timeoutHandle=null,s.fireAt<=this.now()){this.fireTask(s);return}this.armTask(s)}}startScanLoop(){this.scanIntervalHandle==null&&(this.scanIntervalHandle=this.setIntervalFn(()=>this.scanPending(),this.armScanIntervalMs))}fireTask(e){if(!this.scheduledTasks.has(e.id))return;this.disarmTask(e.id);const s=this.now(),t={id:e.id,sessionName:e.sessionName,windowIndex:e.windowIndex,text:e.text,fireAt:e.fireAt,createdAt:e.createdAt};try{this.sendKeys(e.sessionName,e.windowIndex,e.text),this.record({...t,triggeredAt:s,status:"ok"})}catch(i){const a=String(i?.message??i);this.onError(`[scheduler] send-keys to ${e.sessionName}:${e.windowIndex} failed: ${a}`),this.record({...t,triggeredAt:s,status:"error",error:a})}this.scheduledTasks.delete(e.id),this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(i=>i.id!==e.id),this.deps.db.write().catch(this.onError)}}export{b as SchedulerService,I as isValidRescheduleInput,p as isValidScheduleInput,f as sendTmuxKeys};
@@ -1,5 +1,5 @@
1
- import{execFileSync as f}from"node:child_process";const l=3e3;function g(n){return n.replace(/\r?\n/g,`\r
2
- `)}function o(n){return f("tmux",n,{encoding:"utf-8",timeout:l}).trimEnd()}function S(n){return o(["display-message","-p","-t",n,"#{session_name}:#{window_index}.#{pane_index}"])}function m(n){const t=o(["display-message","-p","-t",n,"#{history_size}"]),e=parseInt(t,10);return Number.isFinite(e)?e:0}function _(n){return o(["display-message","-p","-t",n,"#{alternate_on}"])==="1"}function c(n,t,e){const i=["capture-pane","-t",n,"-p","-e","-S",String(t)];return e!==void 0&&i.push("-E",String(e)),o(i)}function h(n,t){return c(n,-t)}function y(n,t,e){const i=m(n);if(t>=i)return{data:"",lines:0};const p=-(t+e),a=-(t+1);let r=c(n,p,a);const u=r===""?0:r.split(`
1
+ import{execFileSync as f}from"node:child_process";import{tmuxEnv as l}from"./tmux-env.js";const m=3e3;function _(n){return n.replace(/\r?\n/g,`\r
2
+ `)}function o(n){return f("tmux",n,{encoding:"utf-8",timeout:m,env:l()}).trimEnd()}function h(n){return o(["display-message","-p","-t",n,"#{session_name}:#{window_index}.#{pane_index}"])}function x(n){const t=o(["display-message","-p","-t",n,"#{history_size}"]),e=parseInt(t,10);return Number.isFinite(e)?e:0}function y(n){return o(["display-message","-p","-t",n,"#{alternate_on}"])==="1"}function c(n,t,e){const i=["capture-pane","-t",n,"-p","-e","-S",String(t)];return e!==void 0&&i.push("-E",String(e)),o(i)}function P(n,t){return c(n,-t)}function T(n,t,e){const i=x(n);if(t>=i)return{data:"",lines:0};const p=-(t+e),a=-(t+1);let r=c(n,p,a);const u=r===""?0:r.split(`
3
3
  `).length,s=Math.min(e,u,i-t);return s<u&&s>0&&(r=r.split(`
4
4
  `).slice(-s).join(`
5
- `)),{data:r,lines:s}}export{y as capturePaneHistoryChunk,c as capturePaneLines,h as capturePaneTail,m as getPaneHistorySize,S as getSessionPaneTarget,_ as isAlternateScreen,g as toCrlf};
5
+ `)),{data:r,lines:s}}export{T as capturePaneHistoryChunk,c as capturePaneLines,P as capturePaneTail,x as getPaneHistorySize,h as getSessionPaneTarget,y as isAlternateScreen,_ as toCrlf};
@@ -1,2 +1,2 @@
1
- import*as w from"node-pty";import{captureAndStoreWindows as p}from"./session-windows.js";import{recordWindowVisit as T}from"./window-history.js";const h=["%session-window-changed","%window-add","%window-close","%unlinked-window-close","%window-renamed","%session-renamed"];function x(e){return h.some(r=>e.startsWith(r))}const y=75,C=e=>w.spawn("tmux",["-CC","attach-session","-t",e,"-f","ignore-size,no-output"],{name:"xterm-256color",cols:80,rows:24,cwd:process.env.HOME||"/",env:process.env});function v(e){const r=p(e);if(!r.length)return null;const o=r.find(i=>i.active);return o&&T(e,o.index,o.name),{activeIndex:o?o.index:r[0].index,windows:r.map(i=>({index:i.index,name:i.name,active:i.active}))}}const c=new Map;function M(e,r,o={}){const i=o.spawn??C,a=o.requery??v,f=o.debounceMs??y;let l=c.get(e);if(!l){let n;try{n=i(e)}catch{return()=>{}}const t={pty:n,refCount:0,subscribers:new Set,buf:"",debounceTimer:null,schedule:()=>{}},m=()=>{t.debounceTimer=null;let u;try{u=a(e)}catch{u=null}if(u)for(const d of t.subscribers)try{d(u)}catch{}};t.schedule=()=>{t.debounceTimer&&clearTimeout(t.debounceTimer),t.debounceTimer=setTimeout(m,f)},n.onData(u=>{t.buf+=u;let d;for(;(d=t.buf.indexOf(`
2
- `))>=0;){const b=t.buf.slice(0,d).replace(/\r$/,"");t.buf=t.buf.slice(d+1),x(b)&&t.schedule()}}),n.onExit(()=>{t.debounceTimer&&clearTimeout(t.debounceTimer),c.delete(e)}),c.set(e,t),l=t}l.subscribers.add(r),l.refCount+=1,l.schedule();let s=!1;return()=>{if(s)return;s=!0;const n=c.get(e);if(n&&(n.subscribers.delete(r),n.refCount-=1,n.refCount<=0)){n.debounceTimer&&clearTimeout(n.debounceTimer);try{n.pty.kill()}catch{}c.delete(e)}}}function R(){for(const e of c.values()){e.debounceTimer&&clearTimeout(e.debounceTimer);try{e.pty.kill()}catch{}}c.clear()}function S(){return c.size}export{S as _controlClientCount,M as acquireControlClient,R as killAllControlClients,x as shouldRequery};
1
+ import*as w from"node-pty";import{tmuxEnv as p}from"./tmux-env.js";import{captureAndStoreWindows as T}from"./session-windows.js";import{recordWindowVisit as x}from"./window-history.js";const h=["%session-window-changed","%window-add","%window-close","%unlinked-window-close","%window-renamed","%session-renamed"];function y(e){return h.some(r=>e.startsWith(r))}const C=75,v=e=>w.spawn("tmux",["-CC","attach-session","-t",e,"-f","ignore-size,no-output"],{name:"xterm-256color",cols:80,rows:24,cwd:process.env.HOME||"/",env:p()});function E(e){const r=T(e);if(!r.length)return null;const o=r.find(i=>i.active);return o&&x(e,o.index,o.name),{activeIndex:o?o.index:r[0].index,windows:r.map(i=>({index:i.index,name:i.name,active:i.active}))}}const c=new Map;function S(e,r,o={}){const i=o.spawn??v,a=o.requery??E,f=o.debounceMs??C;let l=c.get(e);if(!l){let n;try{n=i(e)}catch{return()=>{}}const t={pty:n,refCount:0,subscribers:new Set,buf:"",debounceTimer:null,schedule:()=>{}},m=()=>{t.debounceTimer=null;let u;try{u=a(e)}catch{u=null}if(u)for(const d of t.subscribers)try{d(u)}catch{}};t.schedule=()=>{t.debounceTimer&&clearTimeout(t.debounceTimer),t.debounceTimer=setTimeout(m,f)},n.onData(u=>{t.buf+=u;let d;for(;(d=t.buf.indexOf(`
2
+ `))>=0;){const b=t.buf.slice(0,d).replace(/\r$/,"");t.buf=t.buf.slice(d+1),y(b)&&t.schedule()}}),n.onExit(()=>{t.debounceTimer&&clearTimeout(t.debounceTimer),c.delete(e)}),c.set(e,t),l=t}l.subscribers.add(r),l.refCount+=1,l.schedule();let s=!1;return()=>{if(s)return;s=!0;const n=c.get(e);if(n&&(n.subscribers.delete(r),n.refCount-=1,n.refCount<=0)){n.debounceTimer&&clearTimeout(n.debounceTimer);try{n.pty.kill()}catch{}c.delete(e)}}}function g(){for(const e of c.values()){e.debounceTimer&&clearTimeout(e.debounceTimer);try{e.pty.kill()}catch{}}c.clear()}function k(){return c.size}export{k as _controlClientCount,S as acquireControlClient,g as killAllControlClients,y as shouldRequery};
@@ -0,0 +1 @@
1
+ function e(){const n={...process.env};return!n.LC_ALL&&!n.LANG&&(n.LC_ALL=process.platform==="darwin"?"en_US.UTF-8":"C.UTF-8"),n}export{e as tmuxEnv};
@@ -1,2 +1,2 @@
1
- import{execFileSync as u}from"node:child_process";const w=3e3,l="#{pane_id} #{pane_index} #{window_index} #{pane_pid} #{pane_current_command} #{pane_active} #{window_active}";function m(t,e){const[n,a,c,r,d,p,s]=e.split(" ");if(!n)return null;const i=parseInt(c,10),o=parseInt(a,10);return{paneId:n,paneIndex:Number.isFinite(o)?o:0,windowIndex:Number.isFinite(i)?i:0,pid:parseInt(r,10)||0,command:d??"",active:p==="1",windowActive:s==="1",target:`${t}:${i}.${o}`}}function x(t){try{return u("tmux",["list-panes","-s","-t",t,"-F",l],{encoding:"utf-8",timeout:w}).trim().split(`
2
- `).filter(Boolean).map(n=>m(t,n)).filter(n=>n!==null)}catch{return[]}}function _(t){return x(t).find(n=>n.active&&n.windowActive)??null}export{_ as getActivePaneInfo,x as listSessionPanes};
1
+ import{execFileSync as u}from"node:child_process";import{tmuxEnv as m}from"./tmux-env.js";const w=3e3,l="#{pane_id} #{pane_index} #{window_index} #{pane_pid} #{pane_current_command} #{pane_active} #{window_active}";function x(t,e){const[n,a,r,c,d,p,s]=e.split(" ");if(!n)return null;const i=parseInt(r,10),o=parseInt(a,10);return{paneId:n,paneIndex:Number.isFinite(o)?o:0,windowIndex:Number.isFinite(i)?i:0,pid:parseInt(c,10)||0,command:d??"",active:p==="1",windowActive:s==="1",target:`${t}:${i}.${o}`}}function I(t){try{return u("tmux",["list-panes","-s","-t",t,"-F",l],{encoding:"utf-8",timeout:w,env:m()}).trim().split(`
2
+ `).filter(Boolean).map(n=>x(t,n)).filter(n=>n!==null)}catch{return[]}}function _(t){return I(t).find(n=>n.active&&n.windowActive)??null}export{_ as getActivePaneInfo,I as listSessionPanes};
@@ -1,4 +1,4 @@
1
- import{execFileSync as r}from"node:child_process";class s extends Error{status;constructor(e,n){super(e),this.status=n,this.name="TmuxWindowsError"}}function u(t){try{return r("tmux",["list-windows","-t",t,"-F","#{window_index} #{window_name} #{window_active}"],{encoding:"utf-8",timeout:3e3}).trim().split(`
2
- `).filter(Boolean).map(n=>{const[o,i,w]=n.split(" ");return{index:parseInt(o,10),name:i,active:w==="1"}})}catch{return[]}}function d(t){try{return r("tmux",["list-windows","-t",t,"-F","#{window_index} #{window_name} #{window_active} #{pane_current_path}"],{encoding:"utf-8",timeout:3e3}).trim().split(`
3
- `).filter(Boolean).map(n=>{const[o,i,w,a]=n.split(" ");return{index:parseInt(o,10),name:i,active:w==="1",path:a??""}})}catch{return[]}}function f(t){if(!t)return!1;try{const e=r("git",["-C",t,"rev-parse","--git-dir","--git-common-dir"],{encoding:"utf-8",timeout:3e3,stdio:["ignore","pipe","ignore"]}),[n,o]=e.trim().split(`
4
- `);return!n||!o?!1:n!==o}catch{return!1}}function c(t){try{return r("tmux",["has-session","-t",t],{timeout:3e3}),!0}catch{return!1}}function x(t){if(!c(t))throw new s("session not found",404);try{r("tmux",["new-window","-t",t],{timeout:3e3})}catch(e){const n=e instanceof Error?e.message:"new-window failed";throw new s(n,500)}}function p(t,e){const n=["new-session","-d","-s",t];e&&n.push("-c",e);try{r("tmux",n,{timeout:5e3})}catch(o){const i=o instanceof Error?o.message:"new-session failed";throw new s(i,500)}}function l(t,e){r("tmux",["rename-session","-t",t,e],{timeout:5e3})}function h(t){r("tmux",["kill-session","-t",t],{timeout:5e3})}function g(t,e){if(!c(t))throw new s("session not found",404);if(!u(t).some(o=>o.index===e))throw new s("window not found",404);try{r("tmux",["select-window","-t",`${t}:${e}`],{timeout:3e3})}catch(o){const i=o instanceof Error?o.message:"select-window failed";throw new s(i,500)}}function y(t,e,n){if(!c(t))throw new s("session not found",404);if(!u(t).some(w=>w.index===e))throw new s("window not found",404);const i=n.trim();if(!i)throw new s("name is required",500);try{r("tmux",["rename-window","-t",`${t}:${e}`,i],{timeout:3e3})}catch(w){const a=w instanceof Error?w.message:"rename-window failed";throw new s(a,500)}}export{s as TmuxWindowsError,d as captureSessionWindowsWithPath,f as isGitWorktree,h as killSession,u as listSessionWindows,x as newSessionWindow,p as newTmuxSession,l as renameSession,y as renameSessionWindow,g as selectSessionWindow};
1
+ import{execFileSync as r}from"node:child_process";import{tmuxEnv as a}from"./tmux-env.js";class s extends Error{status;constructor(e,n){super(e),this.status=n,this.name="TmuxWindowsError"}}function m(t){try{return r("tmux",["list-windows","-t",t,"-F","#{window_index} #{window_name} #{window_active}"],{encoding:"utf-8",timeout:3e3}).trim().split(`
2
+ `).filter(Boolean).map(n=>{const[o,i,w]=n.split(" ");return{index:parseInt(o,10),name:i,active:w==="1"}})}catch{return[]}}function x(t){try{return r("tmux",["list-windows","-t",t,"-F","#{window_index} #{window_name} #{window_active} #{pane_current_path}"],{encoding:"utf-8",timeout:3e3}).trim().split(`
3
+ `).filter(Boolean).map(n=>{const[o,i,w,c]=n.split(" ");return{index:parseInt(o,10),name:i,active:w==="1",path:c??""}})}catch{return[]}}function p(t){if(!t)return!1;try{const e=r("git",["-C",t,"rev-parse","--git-dir","--git-common-dir"],{encoding:"utf-8",timeout:3e3,stdio:["ignore","pipe","ignore"]}),[n,o]=e.trim().split(`
4
+ `);return!n||!o?!1:n!==o}catch{return!1}}function u(t){try{return r("tmux",["has-session","-t",t],{timeout:3e3,env:a()}),!0}catch{return!1}}function l(t){if(!u(t))throw new s("session not found",404);try{r("tmux",["new-window","-t",t],{timeout:3e3,env:a()})}catch(e){const n=e instanceof Error?e.message:"new-window failed";throw new s(n,500)}}function h(t,e){const n=["new-session","-d","-s",t];e&&n.push("-c",e);try{r("tmux",n,{timeout:5e3,env:a()})}catch(o){const i=o instanceof Error?o.message:"new-session failed";throw new s(i,500)}}function g(t,e){r("tmux",["rename-session","-t",t,e],{timeout:5e3,env:a()})}function v(t){r("tmux",["kill-session","-t",t],{timeout:5e3,env:a()})}function y(t,e){if(!u(t))throw new s("session not found",404);if(!m(t).some(o=>o.index===e))throw new s("window not found",404);try{r("tmux",["select-window","-t",`${t}:${e}`],{timeout:3e3})}catch(o){const i=o instanceof Error?o.message:"select-window failed";throw new s(i,500)}}function E(t,e,n){if(!u(t))throw new s("session not found",404);if(!m(t).some(w=>w.index===e))throw new s("window not found",404);const i=n.trim();if(!i)throw new s("name is required",500);try{r("tmux",["rename-window","-t",`${t}:${e}`,i],{timeout:3e3})}catch(w){const c=w instanceof Error?w.message:"rename-window failed";throw new s(c,500)}}export{s as TmuxWindowsError,x as captureSessionWindowsWithPath,p as isGitWorktree,v as killSession,m as listSessionWindows,l as newSessionWindow,h as newTmuxSession,g as renameSession,E as renameSessionWindow,y as selectSessionWindow};
package/dist/sessions.js CHANGED
@@ -1,2 +1,2 @@
1
- import{execFileSync as e}from"node:child_process";function r(){try{return e("tmux",["display-message","-p","#{socket_path}"],{encoding:"utf-8",timeout:3e3}).trim()||null}catch{return null}}function c(){try{return e("tmux",["list-sessions","-F","#{session_name} #{session_windows} #{session_attached}"],{encoding:"utf-8",timeout:3e3}).trim().split(`
2
- `).filter(Boolean).map(t=>{const[s,o,i]=t.split(" ");return{name:s,windows:parseInt(o,10),attached:i!=="0"}})}catch{return[]}}export{c as listSessions,r as resolveTmuxSocketPath};
1
+ import{execFileSync as n}from"node:child_process";import{tmuxEnv as e}from"./lib/tmux-env.js";function a(){try{return n("tmux",["display-message","-p","#{socket_path}"],{encoding:"utf-8",timeout:3e3,env:e()}).trim()||null}catch{return null}}function m(){try{return n("tmux",["list-sessions","-F","#{session_name} #{session_windows} #{session_attached}"],{encoding:"utf-8",timeout:3e3,env:e()}).trim().split(`
2
+ `).filter(Boolean).map(t=>{const[s,i,r]=t.split(" ");return{name:s,windows:parseInt(i,10),attached:r!=="0"}})}catch{return[]}}export{m as listSessions,a as resolveTmuxSocketPath};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmux-weblink",
3
- "version": "2.0.7",
3
+ "version": "2.0.9",
4
4
  "description": "Access your tmux sessions from the browser. A continuation of tmux-web and persalink.",
5
5
  "type": "module",
6
6
  "bin": {