tmux-weblink 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,23 +2,23 @@ var an=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function
2
2
  `)}selectRows(t,n){let s=this.terminal.buffer.active,[o,r]=t<=n?[t,n]:[n,t];this.terminal.selectLines(s.viewportY+o,s.viewportY+r)}selectCells(t,n,s,o){let r=this.terminal.buffer.active,c=Math.min(n,o),l=Math.max(n,o);if(c===l){let u=Math.min(t,s),p=Math.max(t,s);this.terminal.select(u,r.viewportY+c,p-u+1)}else this.terminal.selectLines(r.viewportY+c,r.viewportY+l)}getCellsText(t,n,s,o){let r=this.terminal.buffer.active,c=Math.min(n,o),l=Math.max(n,o),u=n<o?t:n>o?s:Math.min(t,s),p=n<o?s:n>o?t:Math.max(t,s),S=r.viewportY,x=[];for(let H=c;H<=l;H++){let ge=r.getLine(S+H);if(!ge){x.push("");continue}let O=H===c?u:0,je=H===l?p:this.terminal.cols-1,K="";for(let C=O;C<=je;C++){let j=ge.getCell(C);j&&(K+=j.getChars())}x.push(K.replace(/\s+$/,""))}return x.join(`
3
3
  `)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}};function rn(e){let t=e.getBoundingClientRect(),n=window.visualViewport;return n?{width:Math.min(t.width,n.width),height:Math.max(0,Math.min(t.height,n.height-Math.max(0,t.top)))}:t}function cn(e,t,n){return e.innerHTML="",e.classList.add("terminal-pending"),(async()=>{let s=await ln.create(e,n.scrollback,n.theme),o,r=0,c,l=null,u=0,p=0,S=.2,x=10,H=.95,ge=.04;function O(){u&&(cancelAnimationFrame(u),u=0),p=0}function je(i){if(O(),Math.abs(i)<S)return;p=Math.max(-x,Math.min(x,i));let a=()=>{if(N){u=0;return}let d=e.querySelector(".xterm-rows > div"),f=d?d.getBoundingClientRect().height:16,b=f>0?Math.round(p*16/f):p>0?1:-1;b===0&&(b=p>0?1:-1);let B=s.viewportY()-b,F=s.baseY(),ae=Math.max(0,Math.min(B,F));if(s.scrollToLine(ae,!0),p*=H,ae!==B){u=0;return}if(Math.abs(p)<ge){u=0;return}u=requestAnimationFrame(a)};u=requestAnimationFrame(a)}let K=0,C="connecting",j=0,G=!1,ye=[],V="",N=!1,Q=1e3,At=location.protocol==="https:"?"wss:":"ws:",Rt=n.wsBase||"/ws",$t=At+"//"+location.host+Rt+"/"+encodeURIComponent(t),Nt="/api/session/"+encodeURIComponent(t)+"/upload",Pt=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function _t(){return ye.join("")+V}async function jt(i,a=0){let d=i?s.viewportY():0,f=oe(_t());if(s.reset(),!f){i||s.scrollToBottom();return}await s.write(f),i?s.scrollToLine(a+d):s.scrollToBottom()}function z(i){o?.readyState===WebSocket.OPEN&&o.send(JSON.stringify(i))}function zt(i){let a;try{a=JSON.parse(i)}catch{C==="live"&&(V+=i,s.write(oe(i)));return}if(a.type==="auth.required"){let d=localStorage.getItem("tmux-web-token");d?z({type:"auth.token",token:d}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(a.type==="attach_failed"&&typeof a.message=="string"){we=!0,C="dead",s.reset(),s.write(`\r
4
4
  \x1B[31m`+oe(a.message)+`\x1B[0m\r
5
- `).then(()=>{Le();try{o?.close()}catch{}});return}if(a.type==="auth.ok"){a.token&&localStorage.setItem("tmux-web-token",a.token),Q=1e3,W(),z({type:"resize",cols:s.cols,rows:s.rows}),M();return}if(a.type==="auth.failed"){if(a.permanentLock||a.retryAfterMs&&a.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(a.message);return}return}if(a.type==="snapshot"&&typeof a.data=="string"){let d=Ue(oe(a.data));ye=[d],V="",j=typeof a.lines=="number"?a.lines:n.terminal.initialLines,C="live",s.reset(),W(),z({type:"resize",cols:s.cols,rows:s.rows}),s.write(d).then(()=>s.scrollToBottom());return}if(a.type==="window_changed"&&typeof a.activeIndex=="number"){let d=new URL(location.href);d.searchParams.get("window")!==String(a.activeIndex)&&(d.searchParams.set("window",String(a.activeIndex)),history.replaceState(history.state,"",d)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:a.windows}));return}if(a.type==="history"&&typeof a.data=="string"){a.lines>0&&a.data?(ye.unshift(Ue(a.data)),j+=a.lines,jt(!0,a.lines).finally(()=>{G=!1})):G=!1;return}if(a.type==="data"&&typeof a.data=="string"){let d=Ue(oe(a.data));if(C==="connecting"){C="live",V=d,s.write(d);return}C==="live"&&(V+=d,s.write(d))}}let we=!1;function Ge(){if(we)return;let i=$t,a=localStorage.getItem("tmux-web-token");a&&(i+=(i.includes("?")?"&":"?")+"token="+encodeURIComponent(a)),i+=(i.includes("?")?"&":"?")+"cols="+s.cols+"&rows="+s.rows,o=new WebSocket(i),o.onopen=()=>{C="connecting",j=0,G=!1,ye=[],V="",s.reset(),Q=1e3},o.onmessage=d=>{typeof d.data=="string"&&zt(d.data)},o.onclose=()=>{N||(C="connecting",!we&&setTimeout(()=>{Q=Math.min(Q*2,1e4),!N&&!we&&Ge()},Q))},o.onerror=()=>o?.close()}function be(i){z({type:"input",data:i})}function W(){return s.fit()}function Le(){e.classList.remove("terminal-pending")}function M(){r&&cancelAnimationFrame(r),c&&clearTimeout(c),W(),r=requestAnimationFrame(()=>{r=0,W()&&Le()}),c=setTimeout(()=>{W()&&Le()},120)}function Wt(){M(),setTimeout(M,50),setTimeout(M,150),setTimeout(M,300)}function Qe(i){return typeof i=="string"&&i.startsWith("image/")}function et(i){return i?.files?.length?i.files[0]??null:null}function Ft(i){if(!i?.items)return null;for(let a=0;a<i.items.length;a++){let d=i.items[a];if(d?.kind==="file"&&Qe(d.type))return d.getAsFile()}return null}async function Ut(i){let a=new FormData,d=i instanceof File&&i.name?i.name:"upload";a.append("file",i,d);let f=localStorage.getItem("tmux-web-token"),b={};f&&(b.Authorization="Bearer "+f);let B=await fetch(Nt,{method:"POST",body:a,headers:b});if(!B.ok){let ae="upload failed";try{let lt=await B.json();lt.error&&(ae=lt.error)}catch{}throw new Error(ae)}let F=await B.json();if(!F.path)throw new Error("no path in response");return F.path}async function ze(i){try{let a=await Ut(i);be(a)}catch{}}s.onData(i=>be(i)),s.onResize(({cols:i,rows:a})=>z({type:"resize",cols:i,rows:a})),s.onScroll(()=>{C!=="live"||G||!s.isNearScrollbackTop()||(G=!0,z({type:"load_history",before:j}))});let ee=!1,te=!1,w=null,L=null,ne=document.createElement("div");ne.className="terminal-copy-banner",ne.innerHTML='<strong>Copy mode</strong><span class="hint">drag to copy \xB7 Esc exits</span>',ne.hidden=!0,e.appendChild(ne);let R=document.createElement("div");R.className="terminal-copy-banner terminal-copy-toast",R.textContent="Copied",R.hidden=!0,e.appendChild(R);function tt(i,a){let d=e.querySelector(".xterm-screen, canvas"),f=(d&&d.getBoundingClientRect().width>0?d:e).getBoundingClientRect(),b=f.height>0&&s.rows>0?f.height/s.rows:18,B=f.width>0&&s.cols>0?f.width/s.cols:9;return{row:Math.max(0,Math.min(s.rows-1,Math.floor((a-f.top)/b))),col:Math.max(0,Math.min(s.cols-1,Math.floor((i-f.left)/B)))}}async function Ee(i){if(!i)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(i);return}}catch{}let a=document.createElement("textarea");a.value=i,a.style.position="fixed",a.style.opacity="0",a.style.pointerEvents="none",document.body.appendChild(a),a.focus(),a.select();try{document.execCommand("copy")}catch{}a.remove()}let se;function ke(){R.hidden=!1,se&&clearTimeout(se),se=setTimeout(()=>{R.hidden=!0},1e3)}function J(i){ee=i,ne.hidden=!i,e.classList.toggle("terminal-copy-mode-active",i),i&&s.focus()}function nt(){J(!ee)}function Yt(i){N||i.button!==0||te||(ee||i.shiftKey)&&(i.preventDefault(),i.stopPropagation(),te=!0,w=tt(i.clientX,i.clientY),L=w,s.selectCells(w.col,w.row,L.col,L.row),document.addEventListener("mousemove",We,!0),document.addEventListener("mouseup",Fe,!0))}function We(i){N||!te||!w||(i.preventDefault(),i.stopPropagation(),L=tt(i.clientX,i.clientY),s.selectCells(w.col,w.row,L.col,L.row))}function Fe(i){if(N||!te||!w||!L)return;i.preventDefault(),i.stopPropagation(),document.removeEventListener("mousemove",We,!0),document.removeEventListener("mouseup",Fe,!0),te=!1;let a=s.getCellsText(w.col,w.row,L.col,L.row);w=null,L=null,s.clearSelection(),J(!1),a&&(R.textContent="\u5DF2\u590D\u5236",Ee(a).then(ke)),s.focus()}e.addEventListener("mousedown",Yt,!0),document.addEventListener("keydown",qt,!0);function qt(i){if(!(N||!s.isFocused()||i.defaultPrevented||i.isComposing)){if(ee){if(i.key==="Escape"){i.preventDefault(),i.stopPropagation(),w=null,L=null,s.clearSelection(),J(!1);return}if(i.key==="Enter"||(i.ctrlKey||i.metaKey)&&i.code==="KeyC"){i.preventDefault(),i.stopPropagation(),Ee(s.getScreenText()).then(ke),J(!1);return}}if(i.altKey&&i.code==="KeyC"&&!i.ctrlKey&&!i.metaKey){if(i.preventDefault(),i.stopPropagation(),w&&L){let a=s.getCellsText(w.col,w.row,L.col,L.row);w=null,L=null,s.clearSelection(),J(!1),a&&(R.textContent="Copied",Ee(a).then(ke))}else{let a=s.getSelection();a?(s.clearSelection(),R.textContent="Copied",Ee(a).then(ke)):nt()}return}if((i.ctrlKey||i.metaKey)&&i.code==="KeyV"){i.preventDefault(),i.stopPropagation(),(async()=>{try{if(navigator.clipboard?.read){let a=await navigator.clipboard.read();for(let d of a)for(let f of d.types)if(Qe(f)){let b=await d.getType(f);await ze(b);return}}}catch{}try{let a=await navigator.clipboard?.readText();a&&s.pasteText(st(a))}catch{}})();return}}}let xe=0;function st(i){return i.split(`\r
5
+ `).then(()=>{Le();try{o?.close()}catch{}});return}if(a.type==="auth.ok"){a.token&&localStorage.setItem("tmux-web-token",a.token),Q=1e3,W(),z({type:"resize",cols:s.cols,rows:s.rows}),M();return}if(a.type==="auth.failed"){if(a.permanentLock||a.retryAfterMs&&a.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(a.message);return}return}if(a.type==="snapshot"&&typeof a.data=="string"){let d=Ue(oe(a.data));ye=[d],V="",j=typeof a.lines=="number"?a.lines:n.terminal.initialLines,C="live",s.reset(),W(),z({type:"resize",cols:s.cols,rows:s.rows}),s.write(d).then(()=>s.scrollToBottom());return}if(a.type==="window_changed"&&typeof a.activeIndex=="number"){let d=new URL(location.href);d.searchParams.get("window")!==String(a.activeIndex)&&(d.searchParams.set("window",String(a.activeIndex)),history.replaceState(history.state,"",d)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:a.windows}));return}if(a.type==="history"&&typeof a.data=="string"){a.lines>0&&a.data?(ye.unshift(Ue(a.data)),j+=a.lines,jt(!0,a.lines).finally(()=>{G=!1})):G=!1;return}if(a.type==="data"&&typeof a.data=="string"){let d=Ue(oe(a.data));if(C==="connecting"){C="live",V=d,s.write(d);return}C==="live"&&(V+=d,s.write(d))}}let we=!1;function Qe(){if(we)return;let i=$t,a=localStorage.getItem("tmux-web-token");a&&(i+=(i.includes("?")?"&":"?")+"token="+encodeURIComponent(a)),i+=(i.includes("?")?"&":"?")+"cols="+s.cols+"&rows="+s.rows,o=new WebSocket(i),o.onopen=()=>{C="connecting",j=0,G=!1,ye=[],V="",s.reset(),Q=1e3},o.onmessage=d=>{typeof d.data=="string"&&zt(d.data)},o.onclose=()=>{N||(C="connecting",!we&&setTimeout(()=>{Q=Math.min(Q*2,1e4),!N&&!we&&Qe()},Q))},o.onerror=()=>o?.close()}function be(i){z({type:"input",data:i})}function W(){return s.fit()}function Le(){e.classList.remove("terminal-pending")}function M(){r&&cancelAnimationFrame(r),c&&clearTimeout(c),W(),r=requestAnimationFrame(()=>{r=0,W()&&Le()}),c=setTimeout(()=>{W()&&Le()},120)}function Wt(){M(),setTimeout(M,50),setTimeout(M,150),setTimeout(M,300)}function et(i){return typeof i=="string"&&i.startsWith("image/")}function tt(i){return i?.files?.length?i.files[0]??null:null}function Ft(i){if(!i?.items)return null;for(let a=0;a<i.items.length;a++){let d=i.items[a];if(d?.kind==="file"&&et(d.type))return d.getAsFile()}return null}async function Ut(i){let a=new FormData,d=i instanceof File&&i.name?i.name:"upload";a.append("file",i,d);let f=localStorage.getItem("tmux-web-token"),b={};f&&(b.Authorization="Bearer "+f);let B=await fetch(Nt,{method:"POST",body:a,headers:b});if(!B.ok){let ae="upload failed";try{let rt=await B.json();rt.error&&(ae=rt.error)}catch{}throw new Error(ae)}let F=await B.json();if(!F.path)throw new Error("no path in response");return F.path}async function ze(i){try{let a=await Ut(i);be(a)}catch{}}s.onData(i=>be(i)),s.onResize(({cols:i,rows:a})=>z({type:"resize",cols:i,rows:a})),s.onScroll(()=>{C!=="live"||G||!s.isNearScrollbackTop()||(G=!0,z({type:"load_history",before:j}))});let ee=!1,te=!1,w=null,L=null,ne=document.createElement("div");ne.className="terminal-copy-banner",ne.innerHTML='<strong>Copy mode</strong><span class="hint">drag to copy \xB7 Esc exits</span>',ne.hidden=!0,e.appendChild(ne);let R=document.createElement("div");R.className="terminal-copy-banner terminal-copy-toast",R.textContent="Copied",R.hidden=!0,e.appendChild(R);function nt(i,a){let d=e.querySelector(".xterm-screen, canvas"),f=(d&&d.getBoundingClientRect().width>0?d:e).getBoundingClientRect(),b=f.height>0&&s.rows>0?f.height/s.rows:18,B=f.width>0&&s.cols>0?f.width/s.cols:9;return{row:Math.max(0,Math.min(s.rows-1,Math.floor((a-f.top)/b))),col:Math.max(0,Math.min(s.cols-1,Math.floor((i-f.left)/B)))}}async function Ee(i){if(!i)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(i);return}}catch{}let a=document.createElement("textarea");a.value=i,a.style.position="fixed",a.style.opacity="0",a.style.pointerEvents="none",document.body.appendChild(a),a.focus(),a.select();try{document.execCommand("copy")}catch{}a.remove()}let se;function ke(){R.hidden=!1,se&&clearTimeout(se),se=setTimeout(()=>{R.hidden=!0},1e3)}function J(i){ee=i,ne.hidden=!i,e.classList.toggle("terminal-copy-mode-active",i),i&&s.focus()}function st(){J(!ee)}function Yt(i){N||i.button!==0||te||(ee||i.shiftKey)&&(i.preventDefault(),i.stopPropagation(),te=!0,w=nt(i.clientX,i.clientY),L=w,s.selectCells(w.col,w.row,L.col,L.row),document.addEventListener("mousemove",We,!0),document.addEventListener("mouseup",Fe,!0))}function We(i){N||!te||!w||(i.preventDefault(),i.stopPropagation(),L=nt(i.clientX,i.clientY),s.selectCells(w.col,w.row,L.col,L.row))}function Fe(i){if(N||!te||!w||!L)return;i.preventDefault(),i.stopPropagation(),document.removeEventListener("mousemove",We,!0),document.removeEventListener("mouseup",Fe,!0),te=!1;let a=s.getCellsText(w.col,w.row,L.col,L.row);w=null,L=null,s.clearSelection(),J(!1),a&&(R.textContent="\u5DF2\u590D\u5236",Ee(a).then(ke)),s.focus()}e.addEventListener("mousedown",Yt,!0),document.addEventListener("keydown",qt,!0);function qt(i){if(!(N||!s.isFocused()||i.defaultPrevented||i.isComposing)){if(ee){if(i.key==="Escape"){i.preventDefault(),i.stopPropagation(),w=null,L=null,s.clearSelection(),J(!1);return}if(i.key==="Enter"||(i.ctrlKey||i.metaKey)&&i.code==="KeyC"){i.preventDefault(),i.stopPropagation(),Ee(s.getScreenText()).then(ke),J(!1);return}}if(i.altKey&&i.code==="KeyC"&&!i.ctrlKey&&!i.metaKey){if(i.preventDefault(),i.stopPropagation(),w&&L){let a=s.getCellsText(w.col,w.row,L.col,L.row);w=null,L=null,s.clearSelection(),J(!1),a&&(R.textContent="Copied",Ee(a).then(ke))}else{let a=s.getSelection();a?(s.clearSelection(),R.textContent="Copied",Ee(a).then(ke)):st()}return}if((i.ctrlKey||i.metaKey)&&i.code==="KeyV"){i.preventDefault(),i.stopPropagation(),(async()=>{try{if(navigator.clipboard?.read){let a=await navigator.clipboard.read();for(let d of a)for(let f of d.types)if(et(f)){let b=await d.getType(f);await ze(b);return}}}catch{}try{let a=await navigator.clipboard?.readText();a&&s.pasteText(it(a))}catch{}})();return}}}let xe=0;function it(i){return i.split(`\r
6
6
  `).join(`
7
7
  `).split(`
8
- `).join("\r")}async function Ot(i){let a=Ft(i.clipboardData);if(a){i.preventDefault(),i.stopPropagation();let b=Date.now();if(b-xe<50)return;xe=b,await ze(a);return}let d=i.clipboardData?.getData("text/plain");if(!d)return;i.preventDefault(),i.stopPropagation();let f=Date.now();f-xe<50||(xe=f,s.pasteText(st(d)))}let ie=0;function Kt(i){i.preventDefault(),ie++,et(i.dataTransfer)&&e.classList.add("terminal-drag-over")}function Vt(i){i.preventDefault(),i.dataTransfer&&(i.dataTransfer.dropEffect="copy")}function Jt(i){i.preventDefault(),ie--,ie<=0&&(ie=0,e.classList.remove("terminal-drag-over"))}async function Xt(i){i.preventDefault(),ie=0,e.classList.remove("terminal-drag-over");let a=et(i.dataTransfer);a&&await ze(a)}function it(i){!Pt||i.key!=="Escape"||ee||i.defaultPrevented||i.repeat||i.metaKey||i.ctrlKey||i.altKey||s.isFocused()&&(i.preventDefault(),i.stopPropagation(),be("\x1B"))}e.addEventListener("paste",Ot),e.addEventListener("dragenter",Kt),e.addEventListener("dragover",Vt),e.addEventListener("dragleave",Jt),e.addEventListener("drop",Xt),document.addEventListener("keydown",it,!0);function Zt(i){if(i.touches.length!==1){l=null;return}let a=i.touches[0];a&&(O(),l={startX:a.clientX,startY:a.clientY,lastX:a.clientX,lastY:a.clientY,lastT:performance.now(),velocity:0,scrolling:!1},i.stopPropagation())}function Gt(i){if(!l||i.touches.length!==1)return;let a=i.touches[0];if(!a)return;let d=a.clientY-l.startY,f=a.clientX-l.startX;if(!l.scrolling){if(Math.abs(d)<8||Math.abs(d)<Math.abs(f))return;l.scrolling=!0,K=Date.now()+500}i.preventDefault(),i.stopPropagation();let b=performance.now(),B=a.clientY-l.lastY,F=b-l.lastT;F>0&&(l.velocity=B/F),nn(-B),l.lastX=a.clientX,l.lastY=a.clientY,l.lastT=b}function Qt(i){if(!l)return;let a=l.scrolling,d=l.velocity;if(l=null,i.stopPropagation(),!a){s.focus();return}K=Date.now()+500,i.preventDefault(),d&&je(d)}function en(i){l=null,O(),i.stopPropagation()}function tn(i){i.pointerType==="touch"&&Date.now()<K&&(i.preventDefault(),i.stopPropagation())}function nn(i){let a=e.querySelector(".xterm-rows > div"),d=a?a.getBoundingClientRect().height:16,f=d>0?Math.round(i/d):i>0?1:-1;f===0&&(f=i>0?1:-1),s.scrollLines(f)}e.addEventListener("touchstart",Zt,{passive:!0,capture:!0}),e.addEventListener("touchmove",Gt,{passive:!1,capture:!0}),e.addEventListener("touchend",Qt,{passive:!1,capture:!0}),e.addEventListener("touchcancel",en,{passive:!0,capture:!0}),e.addEventListener("pointerup",tn,!0);function at(){M()}window.addEventListener("resize",at),window.visualViewport?.addEventListener("resize",M),window.visualViewport?.addEventListener("scroll",M);let ot=new ResizeObserver(()=>M());ot.observe(e),document.fonts?.ready.then(()=>{M(),setTimeout(M,50),setTimeout(M,200)}),e.addEventListener("focusin",Wt,!0);async function sn(){if(document.fonts?.ready)try{await Promise.race([document.fonts.ready,new Promise(i=>setTimeout(i,1e3))])}catch{}}return requestAnimationFrame(()=>{W()&&Le(),(async()=>(await sn(),W()&&z({type:"resize",cols:s.cols,rows:s.rows}),Ge(),M()))()}),{destroy(){if(N=!0,O(),J(!1),se&&clearTimeout(se),document.removeEventListener("mousemove",We,!0),document.removeEventListener("mouseup",Fe,!0),o){try{o.close(1e3,"session switch")}catch{}o=void 0}e.innerHTML="",e.classList.remove("terminal-pending"),window.removeEventListener("resize",at),ot.disconnect(),document.removeEventListener("keydown",it,!0)},focus(){s.focus()},sendInput(i){be(i)},toggleCopyMode(){nt()}}})()}var le=window.__TMUX_WEB_SHELL__,v=null,y=null,rt=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null,k=rt;window.__tmuxWebScopeAgent=rt;var Ye="sessions",P="",Me="",Te="",ct="";function T(e){return k?"/a/"+encodeURIComponent(k)+e:e}var m=document.getElementById("sidebar-content"),U=document.getElementById("main-placeholder"),I=document.getElementById("terminal-container"),re=document.getElementById("file-editor"),dn=document.getElementById("fe-path"),D=document.getElementById("fe-status"),ce=document.getElementById("fe-content"),Y=document.getElementById("fe-save"),un=document.getElementById("fe-delete"),pn=document.getElementById("fe-back"),dt=document.getElementById("fe-new-name"),fn=document.getElementById("fe-new-btn"),qe=document.getElementById("settings-backdrop"),ut=document.getElementById("settings-popover"),pt=document.querySelector(".sidebar");function mn(){return window.matchMedia("(max-width: 640px)").matches}function Oe(){mn()&&pt.classList.add("collapsed")}function ft(){pt.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{ft(),mt("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{ft(),mt("files")});function mt(e){Ye=e,document.querySelectorAll(".mode-btn").forEach(n=>n.classList.remove("active"));let t=document.getElementById(e==="sessions"?"mode-sessions":"mode-files");t&&t.classList.add("active"),e==="sessions"?(Ke="",X()):Sn()}var Ke="";async function X(){if(Ye!=="sessions")return;try{let t=await(await fetch("/api/sidebar/sessions")).json(),n=JSON.stringify({recent:t.recent,agents:t.agents});if(n===Ke)return;Ke=n,wn(t)}catch{m.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}let e=document.getElementById("ns-btn");e&&e.addEventListener("click",()=>{let t=window.__openNewSessionModal;typeof t=="function"?t():document.getElementById("new-session-modal")?.classList.add("open")}),Bt()}var ht="tmux-web-sidebar-group-collapsed";function vt(){try{return new Set(JSON.parse(localStorage.getItem(ht)||"[]"))}catch{return new Set}}function hn(e){try{localStorage.setItem(ht,JSON.stringify([...e]))}catch{}}function vn(e,t,n){if(!e)return"\u2026";let s=n&&(e===n||e.startsWith(n+"/"))?"~"+e.slice(n.length):e,o=s.split("/").filter(Boolean);if(o.length===0)return e;for(let r=1;r<=o.length;r++){let c=o.slice(-r).join("/");if(!t.some(l=>!l||l===e?!1:(n&&(l===n||l.startsWith(n+"/"))?"~"+l.slice(n.length):l).split("/").filter(Boolean).slice(-r).join("/")===c))return c}return s}function gn(e,t){let n=new Map;for(let r of e){let c=r.path||"";n.has(c)||n.set(c,[]),n.get(c).push(r)}let s=[...n.keys()],o=vt();for(let[r,c]of n){let l=vn(r,s,t),u=o.has(r),p=document.createElement("div");p.className="session-group-header"+(u?" collapsed":""),p.title=r||"No working directory",p.innerHTML=`<span class="sg-folder">&#128193;</span><span class="sg-label">${h(l)}</span>`,p.addEventListener("click",()=>{let x=vt(),H=p.nextElementSibling;x.has(r)?(x.delete(r),p.classList.remove("collapsed"),H?.classList.remove("collapsed")):(x.add(r),p.classList.add("collapsed"),H?.classList.add("collapsed")),hn(x)});let S=document.createElement("div");S.className="session-group-body"+(u?" collapsed":"");for(let x of c)S.appendChild(yn(x));m.appendChild(p),m.appendChild(S)}}function yn(e){let t=document.createElement("div");t.className="session-item"+(e.name===y&&!k?" active":""),t.setAttribute("data-session",e.name),t.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${e.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>
8
+ `).join("\r")}async function Ot(i){let a=Ft(i.clipboardData);if(a){i.preventDefault(),i.stopPropagation();let b=Date.now();if(b-xe<50)return;xe=b,await ze(a);return}let d=i.clipboardData?.getData("text/plain");if(!d)return;i.preventDefault(),i.stopPropagation();let f=Date.now();f-xe<50||(xe=f,s.pasteText(it(d)))}let ie=0;function Kt(i){i.preventDefault(),ie++,tt(i.dataTransfer)&&e.classList.add("terminal-drag-over")}function Vt(i){i.preventDefault(),i.dataTransfer&&(i.dataTransfer.dropEffect="copy")}function Jt(i){i.preventDefault(),ie--,ie<=0&&(ie=0,e.classList.remove("terminal-drag-over"))}async function Xt(i){i.preventDefault(),ie=0,e.classList.remove("terminal-drag-over");let a=tt(i.dataTransfer);a&&await ze(a)}function at(i){!Pt||i.key!=="Escape"||ee||i.defaultPrevented||i.repeat||i.metaKey||i.ctrlKey||i.altKey||s.isFocused()&&(i.preventDefault(),i.stopPropagation(),be("\x1B"))}e.addEventListener("paste",Ot),e.addEventListener("dragenter",Kt),e.addEventListener("dragover",Vt),e.addEventListener("dragleave",Jt),e.addEventListener("drop",Xt),document.addEventListener("keydown",at,!0);function Zt(i){if(i.touches.length!==1){l=null;return}let a=i.touches[0];a&&(O(),l={startX:a.clientX,startY:a.clientY,lastX:a.clientX,lastY:a.clientY,lastT:performance.now(),velocity:0,scrolling:!1},i.stopPropagation())}function Gt(i){if(!l||i.touches.length!==1)return;let a=i.touches[0];if(!a)return;let d=a.clientY-l.startY,f=a.clientX-l.startX;if(!l.scrolling){if(Math.abs(d)<8||Math.abs(d)<Math.abs(f))return;l.scrolling=!0,K=Date.now()+500}i.preventDefault(),i.stopPropagation();let b=performance.now(),B=a.clientY-l.lastY,F=b-l.lastT;F>0&&(l.velocity=B/F),nn(-B),l.lastX=a.clientX,l.lastY=a.clientY,l.lastT=b}function Qt(i){if(!l)return;let a=l.scrolling,d=l.velocity;if(l=null,i.stopPropagation(),!a){s.focus();return}K=Date.now()+500,i.preventDefault(),d&&je(d)}function en(i){l=null,O(),i.stopPropagation()}function tn(i){i.pointerType==="touch"&&Date.now()<K&&(i.preventDefault(),i.stopPropagation())}function nn(i){let a=e.querySelector(".xterm-rows > div"),d=a?a.getBoundingClientRect().height:16,f=d>0?Math.round(i/d):i>0?1:-1;f===0&&(f=i>0?1:-1),s.scrollLines(f)}e.addEventListener("touchstart",Zt,{passive:!0,capture:!0}),e.addEventListener("touchmove",Gt,{passive:!1,capture:!0}),e.addEventListener("touchend",Qt,{passive:!1,capture:!0}),e.addEventListener("touchcancel",en,{passive:!0,capture:!0}),e.addEventListener("pointerup",tn,!0);function ot(){M()}window.addEventListener("resize",ot),window.visualViewport?.addEventListener("resize",M),window.visualViewport?.addEventListener("scroll",M);let lt=new ResizeObserver(()=>M());lt.observe(e),document.fonts?.ready.then(()=>{M(),setTimeout(M,50),setTimeout(M,200)}),e.addEventListener("focusin",Wt,!0);async function sn(){if(document.fonts?.ready)try{await Promise.race([document.fonts.ready,new Promise(i=>setTimeout(i,1e3))])}catch{}}return requestAnimationFrame(()=>{W()&&Le(),(async()=>(await sn(),W()&&z({type:"resize",cols:s.cols,rows:s.rows}),Qe(),M()))()}),{destroy(){if(N=!0,O(),J(!1),se&&clearTimeout(se),document.removeEventListener("mousemove",We,!0),document.removeEventListener("mouseup",Fe,!0),o){try{o.close(1e3,"session switch")}catch{}o=void 0}e.innerHTML="",e.classList.remove("terminal-pending"),window.removeEventListener("resize",ot),lt.disconnect(),document.removeEventListener("keydown",at,!0)},focus(){s.focus()},sendInput(i){be(i)},toggleCopyMode(){st()}}})()}var le=window.__TMUX_WEB_SHELL__,v=null,y=null,ct=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null,k=ct;window.__tmuxWebScopeAgent=ct;var Ye="sessions",P="",Me="",Te="",dt="";function T(e){return k?"/a/"+encodeURIComponent(k)+e:e}var m=document.getElementById("sidebar-content"),U=document.getElementById("main-placeholder"),I=document.getElementById("terminal-container"),re=document.getElementById("file-editor"),dn=document.getElementById("fe-path"),D=document.getElementById("fe-status"),ce=document.getElementById("fe-content"),Y=document.getElementById("fe-save"),un=document.getElementById("fe-delete"),pn=document.getElementById("fe-back"),ut=document.getElementById("fe-new-name"),fn=document.getElementById("fe-new-btn"),qe=document.getElementById("settings-backdrop"),pt=document.getElementById("settings-popover"),ft=document.querySelector(".sidebar");function mn(){return window.matchMedia("(max-width: 640px)").matches}function Oe(){mn()&&ft.classList.add("collapsed")}function mt(){ft.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{mt(),ht("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{mt(),ht("files")});function ht(e){Ye=e,document.querySelectorAll(".mode-btn").forEach(n=>n.classList.remove("active"));let t=document.getElementById(e==="sessions"?"mode-sessions":"mode-files");t&&t.classList.add("active"),e==="sessions"?(Ke="",X()):Sn()}var Ke="";async function X(){if(Ye!=="sessions")return;try{let t=await(await fetch("/api/sidebar/sessions")).json(),n=JSON.stringify({recent:t.recent,agents:t.agents});if(n===Ke)return;Ke=n,wn(t)}catch{m.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}let e=document.getElementById("ns-btn");e&&e.addEventListener("click",()=>{let t=window.__openNewSessionModal;typeof t=="function"?t():document.getElementById("new-session-modal")?.classList.add("open")}),Ge()}var vt="tmux-web-sidebar-group-collapsed";function gt(){try{return new Set(JSON.parse(localStorage.getItem(vt)||"[]"))}catch{return new Set}}function hn(e){try{localStorage.setItem(vt,JSON.stringify([...e]))}catch{}}function vn(e,t,n){if(!e)return"\u2026";let s=n&&(e===n||e.startsWith(n+"/"))?"~"+e.slice(n.length):e,o=s.split("/").filter(Boolean);if(o.length===0)return e;for(let r=1;r<=o.length;r++){let c=o.slice(-r).join("/");if(!t.some(l=>!l||l===e?!1:(n&&(l===n||l.startsWith(n+"/"))?"~"+l.slice(n.length):l).split("/").filter(Boolean).slice(-r).join("/")===c))return c}return s}function gn(e,t){let n=new Map;for(let r of e){let c=r.path||"";n.has(c)||n.set(c,[]),n.get(c).push(r)}let s=[...n.keys()],o=gt();for(let[r,c]of n){let l=vn(r,s,t),u=o.has(r),p=document.createElement("div");p.className="session-group-header"+(u?" collapsed":""),p.title=r||"No working directory",p.innerHTML=`<span class="sg-folder">&#128193;</span><span class="sg-label">${h(l)}</span>`,p.addEventListener("click",()=>{let x=gt(),H=p.nextElementSibling;x.has(r)?(x.delete(r),p.classList.remove("collapsed"),H?.classList.remove("collapsed")):(x.add(r),p.classList.add("collapsed"),H?.classList.add("collapsed")),hn(x)});let S=document.createElement("div");S.className="session-group-body"+(u?" collapsed":"");for(let x of c)S.appendChild(yn(x));m.appendChild(p),m.appendChild(S)}}function yn(e){let t=document.createElement("div");t.className="session-item"+(e.name===y&&!k?" active":""),t.setAttribute("data-session",e.name),t.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${e.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
9
  <span>${h(e.name)}</span>
10
10
  <button class="session-edit-btn" data-session="${h(e.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
11
  `,t.addEventListener("click",s=>{s.target.closest(".session-edit-btn")||de(e.name)});let n=t.querySelector(".session-edit-btn");return n&&n.addEventListener("click",s=>{s.stopPropagation(),An(e.name,n)}),t}function wn(e){m.innerHTML='<button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';let t=e.recent||[],n=document.createElement("div");n.className="sidebar-section-label"+(k?" clickable":""),n.textContent=k?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",k&&(n.title="Back to hub",n.addEventListener("click",()=>{window.location.href="/"})),m.appendChild(n),gn(t,e.home);let s=e.agents||[];for(let o of s){if(!o.sessions||o.sessions.length===0)continue;let r=o.agentId===k,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&&k===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>${h(l.name)}</span><span class="meta">${o.online?"":"offline"}</span>`,o.online&&u.addEventListener("click",p=>{p.target.closest(".session-edit-btn")||de(l.name,o.agentId)}),m.appendChild(u)}}}function h(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function de(e,t){if(!(y===e&&v&&k===(t||null))){re.style.display="none",U.style.display="none",I.style.display="",I.classList.add("terminal-pending"),Oe(),v&&($e(),v.destroy(),v=null),y=e,k=t||null,window.__tmuxWebScopeAgent=k,window.__tmuxWebCurrentSession=y;for(let n of m.querySelectorAll(".session-item"))n.classList.toggle("active",n.getAttribute("data-session")===e&&(n.getAttribute("data-agent")||null)===k);try{v=await cn(I,e,{terminal:le.terminal,scrollback:le.scrollback,theme:le.theme,wsBase:k?"/ws/a/"+encodeURIComponent(k):le.wsBase||"/ws"}),Mt()}catch(n){console.error("[shell] terminal init failed:",n);let s=n&&typeof n=="object"&&"message"in n?n.message:String(n);I.textContent="Failed to open terminal for "+e+": "+s,I.classList.remove("terminal-pending")}}}var Se=[],g=null,gt=!1;function bn(e){if(!g||!g.files.length)return null;let t=g.repoRoot;if(!t||!e.startsWith(t))return null;let n=e.slice(t.length+1);for(let s of g.files)if(s.path===n)return s.status;return null}async function Ln(e){gt=!0;try{let t=await fetch(T("/api/git/status?path="+encodeURIComponent(e)));t.ok?g=await t.json():g=null}catch{g=null}finally{gt=!1}}function En(){if(!g||!g.branch)return"";let{branch:e,linesAdded:t,linesRemoved:n}=g,s=`<div class="sidebar-git"><div class="git-branch-badge">
12
+ <span>${h(l.name)}</span><span class="meta">${o.online?"":"offline"}</span>`,o.online&&u.addEventListener("click",p=>{p.target.closest(".session-edit-btn")||de(l.name,o.agentId)}),m.appendChild(u)}}}function h(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function de(e,t){if(!(y===e&&v&&k===(t||null))){re.style.display="none",U.style.display="none",I.style.display="",I.classList.add("terminal-pending"),Oe(),v&&($e(),v.destroy(),v=null),y=e,k=t||null,window.__tmuxWebScopeAgent=k,window.__tmuxWebCurrentSession=y;for(let n of m.querySelectorAll(".session-item"))n.classList.toggle("active",n.getAttribute("data-session")===e&&(n.getAttribute("data-agent")||null)===k);try{v=await cn(I,e,{terminal:le.terminal,scrollback:le.scrollback,theme:le.theme,wsBase:k?"/ws/a/"+encodeURIComponent(k):le.wsBase||"/ws"}),Tt()}catch(n){console.error("[shell] terminal init failed:",n);let s=n&&typeof n=="object"&&"message"in n?n.message:String(n);I.textContent="Failed to open terminal for "+e+": "+s,I.classList.remove("terminal-pending")}}}var Se=[],g=null,yt=!1;function bn(e){if(!g||!g.files.length)return null;let t=g.repoRoot;if(!t||!e.startsWith(t))return null;let n=e.slice(t.length+1);for(let s of g.files)if(s.path===n)return s.status;return null}async function Ln(e){yt=!0;try{let t=await fetch(T("/api/git/status?path="+encodeURIComponent(e)));t.ok?g=await t.json():g=null}catch{g=null}finally{yt=!1}}function En(){if(!g||!g.branch)return"";let{branch:e,linesAdded:t,linesRemoved:n}=g,s=`<div class="sidebar-git"><div class="git-branch-badge">
13
13
  <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
- ${h(e)}</div>`;return(t>0||n>0)&&(s+=`<div class="git-diff-stats">+<span class="add">${t}</span> <span class="del">-${n}</span></div>`),s+"</div>"}m.addEventListener("click",e=>{e.target.closest(".sidebar-git")&&Z&&g&&(e.stopPropagation(),Et())});var ue=document.getElementById("header-git"),yt=document.getElementById("git-diff-view"),wt=document.getElementById("gd-path"),Ie=document.getElementById("gd-status"),Be=document.getElementById("gd-content"),kn=document.getElementById("gd-back"),Z=null;function pe(e){if(!e||!e.branch){ue.style.display="none",Z=null;return}Z=e.repoRoot;let{branch:t,linesAdded:n,linesRemoved:s}=e,o=`<span class="branch">${h(t)}</span>`;(n>0||s>0)&&(o+=`<span class="sep">\xB7</span>+<span class="diff-add">${n}</span> <span class="diff-del">-${s}</span>`),ue.innerHTML=o,ue.style.display="block"}ue.addEventListener("click",e=>{Z&&g&&(e.stopPropagation(),Et())});var E=document.getElementById("git-popover"),De=document.getElementById("git-popover-backdrop");function Ve(){let e=ue.getBoundingClientRect();E.style.top=e.bottom+4+"px",E.style.left=Math.max(8,Math.min(e.left,window.innerWidth-400))+"px"}function bt(){let e=Z,t=document.getElementById("git-popover-browse");t&&t.addEventListener("click",()=>{if(Ae(),e){Ye="files",document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));let n=document.getElementById("mode-files");n&&n.classList.add("active"),_(e)}})}var Lt="";function Et(){if(!g)return;let e=g.files||[];if(!e.length)E.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
14
+ ${h(e)}</div>`;return(t>0||n>0)&&(s+=`<div class="git-diff-stats">+<span class="add">${t}</span> <span class="del">-${n}</span></div>`),s+"</div>"}m.addEventListener("click",e=>{e.target.closest(".sidebar-git")&&Z&&g&&(e.stopPropagation(),kt())});var ue=document.getElementById("header-git"),wt=document.getElementById("git-diff-view"),bt=document.getElementById("gd-path"),Ie=document.getElementById("gd-status"),Be=document.getElementById("gd-content"),kn=document.getElementById("gd-back"),Z=null;function pe(e){if(!e||!e.branch){ue.style.display="none",Z=null;return}Z=e.repoRoot;let{branch:t,linesAdded:n,linesRemoved:s}=e,o=`<span class="branch">${h(t)}</span>`;(n>0||s>0)&&(o+=`<span class="sep">\xB7</span>+<span class="diff-add">${n}</span> <span class="diff-del">-${s}</span>`),ue.innerHTML=o,ue.style.display="block"}ue.addEventListener("click",e=>{Z&&g&&(e.stopPropagation(),kt())});var E=document.getElementById("git-popover"),De=document.getElementById("git-popover-backdrop");function Ve(){let e=ue.getBoundingClientRect();E.style.top=e.bottom+4+"px",E.style.left=Math.max(8,Math.min(e.left,window.innerWidth-400))+"px"}function Lt(){let e=Z,t=document.getElementById("git-popover-browse");t&&t.addEventListener("click",()=>{if(Ae(),e){Ye="files",document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));let n=document.getElementById("mode-files");n&&n.classList.add("active"),_(e)}})}var Et="";function kt(){if(!g)return;let e=g.files||[];if(!e.length)E.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
15
15
  <div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>`;else{let t=`<div class="git-popover-header">${e.length} file${e.length>1?"s":""} changed</div>`;for(let n=0;n<e.length;n++){let s=e[n],o=s.additions||0,r=s.deletions||0,c="";switch(s.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}t+=`<div class="git-popover-item" data-idx="${n}">
16
16
  ${c}<span class="file-path">${h(s.path)}</span>
17
17
  <span class="file-add">${o>0?"+"+o:""}</span>
18
18
  <span class="file-del">${r>0?"-"+r:""}</span>
19
- </div>`}t+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',Lt=t,E.innerHTML=t,E.querySelectorAll(".git-popover-item").forEach(n=>{let s=parseInt(n.dataset.idx||"0",10),o=e[s];!o||o.status==="D"||(n.classList.add("clickable"),n.style.cursor="pointer",n.addEventListener("click",()=>xt(o.path)))})}Ve(),E.classList.add("open"),De.classList.add("open"),bt()}function xn(){return window.innerWidth>=1024}function kt(e,t){let n=(e+(t&&e?`
19
+ </div>`}t+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',Et=t,E.innerHTML=t,E.querySelectorAll(".git-popover-item").forEach(n=>{let s=parseInt(n.dataset.idx||"0",10),o=e[s];!o||o.status==="D"||(n.classList.add("clickable"),n.style.cursor="pointer",n.addEventListener("click",()=>Ct(o.path)))})}Ve(),E.classList.add("open"),De.classList.add("open"),Lt()}function xn(){return window.innerWidth>=1024}function xt(e,t){let n=(e+(t&&e?`
20
20
  `:"")+t).split(`
21
- `),s="",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),s+=`<div class="diff-line hunk"><span class="ln-body">${h(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")&&(s+=`<div class="diff-line header"><span class="ln-body">${h(l)}</span></div>`);continue}if(l.startsWith("+"))r++,s+=`<div class="diff-line add"><span class="ln-no">${r}</span><span class="ln-body">${h(l)}</span></div>`;else if(l.startsWith("-"))o++,s+=`<div class="diff-line del"><span class="ln-no">${o}</span><span class="ln-body">${h(l)}</span></div>`;else if(l.startsWith("\\"))s+=`<div class="diff-line"><span class="ln-body">${h(l)}</span></div>`;else{if(!l&&!o&&!r)continue;o++,r++,s+=`<div class="diff-line"><span class="ln-no">${o}</span><span class="ln-no" style="margin-right:12px">${r}</span><span class="ln-body">${h(l)}</span></div>`}}return{html:s,lineCount:n.length}}var He=null;async function xt(e){let t=Z;if(t)if(Ae(),xn()){I.style.display="none",v&&($e(),v.destroy(),v=null,He=y,y=null),pe(null),re.style.display="none",U.style.display="none",yt.style.display="flex",wt.textContent=e,Ie.textContent="Loading\u2026",Be.innerHTML="";try{let n=await fetch(T("/api/git/diff?path="+encodeURIComponent(t)+"&file="+encodeURIComponent(e)));if(!n.ok)throw new Error(await n.text());let s=await n.json();Mn(e,s.diff,s.stagedDiff)}catch(n){let s=n instanceof Error?n.message:String(n);Ie.textContent="Error",Be.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${h(s)}</div>`}}else{E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
21
+ `),s="",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),s+=`<div class="diff-line hunk"><span class="ln-body">${h(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")&&(s+=`<div class="diff-line header"><span class="ln-body">${h(l)}</span></div>`);continue}if(l.startsWith("+"))r++,s+=`<div class="diff-line add"><span class="ln-no">${r}</span><span class="ln-body">${h(l)}</span></div>`;else if(l.startsWith("-"))o++,s+=`<div class="diff-line del"><span class="ln-no">${o}</span><span class="ln-body">${h(l)}</span></div>`;else if(l.startsWith("\\"))s+=`<div class="diff-line"><span class="ln-body">${h(l)}</span></div>`;else{if(!l&&!o&&!r)continue;o++,r++,s+=`<div class="diff-line"><span class="ln-no">${o}</span><span class="ln-no" style="margin-right:12px">${r}</span><span class="ln-body">${h(l)}</span></div>`}}return{html:s,lineCount:n.length}}var He=null;async function Ct(e){let t=Z;if(t)if(Ae(),xn()){I.style.display="none",v&&($e(),v.destroy(),v=null,He=y,y=null),pe(null),re.style.display="none",U.style.display="none",wt.style.display="flex",bt.textContent=e,Ie.textContent="Loading\u2026",Be.innerHTML="";try{let n=await fetch(T("/api/git/diff?path="+encodeURIComponent(t)+"&file="+encodeURIComponent(e)));if(!n.ok)throw new Error(await n.text());let s=await n.json();Mn(e,s.diff,s.stagedDiff)}catch(n){let s=n instanceof Error?n.message:String(n);Ie.textContent="Error",Be.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${h(s)}</div>`}}else{E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
22
22
  <button class="diff-back">\u2190 Back</button>
23
23
  <span class="diff-filename">${h(e)}</span>
24
24
  <span class="diff-loading">Loading\u2026</span>
@@ -28,11 +28,11 @@ var an=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function
28
28
  </div><div class="diff-empty">Error loading diff: ${h(s)}</div></div>`}}}function Cn(e,t,n){if(!t&&!n){E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
29
29
  <button class="diff-back">\u2190 Back</button>
30
30
  <span class="diff-filename">${h(e)}</span>
31
- </div><div class="diff-empty">No diff content available</div></div>`;return}let{html:s,lineCount:o}=kt(t,n);E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
31
+ </div><div class="diff-empty">No diff content available</div></div>`;return}let{html:s,lineCount:o}=xt(t,n);E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
32
32
  <button class="diff-back">\u2190 Back</button>
33
33
  <span class="diff-filename">${h(e)}</span>
34
34
  <span class="diff-filesize">${o} lines</span>
35
- </div><div class="diff-content">${s}</div></div>`,E.querySelector(".diff-back")?.addEventListener("click",()=>{E.innerHTML=Lt,Ve(),g&&E.querySelectorAll(".git-popover-item").forEach(r=>{let c=parseInt(r.dataset.idx||"0",10),l=g.files[c];!l||l.status==="D"||(r.style.cursor="pointer",r.addEventListener("click",()=>xt(l.path)))}),bt()})}function Mn(e,t,n){if(!t&&!n){Ie.textContent="No diff",Be.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}let{html:s,lineCount:o}=kt(t,n);wt.textContent=e,Ie.textContent=o+" lines",Be.innerHTML=s}function Tn(){yt.style.display="none",He?(I.style.display="",I.classList.add("terminal-pending"),de(He),He=null):y?(I.style.display="",I.classList.add("terminal-pending"),Mt()):U.style.display="flex"}kn.addEventListener("click",Tn);function Ae(){E.classList.remove("open"),De.classList.remove("open")}De.addEventListener("click",Ae),document.addEventListener("keydown",e=>{e.key==="Escape"&&(Ae(),Ne())});async function Ct(e){try{let t=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(e))).json();if(t.path){let n=await fetch("/api/git/status?path="+encodeURIComponent(t.path));if(n.ok){let s=await n.json();g=s,pe(s);return}}}catch{}g=null,pe(null)}var Re=null;function Mt(){$e(),y&&(Ct(y),Re=setInterval(()=>{y&&Ct(y)},3e4))}function $e(){Re&&(clearInterval(Re),Re=null)}function Sn(){if(Se=le.fsRoots||[],Se.length===0){if(y){In(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 e of Se){let t=document.createElement("div");t.className="file-tree-item",t.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> ${h(e)}`,t.addEventListener("click",()=>_(e)),m.appendChild(t)}}async function In(e){m.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let t=await(await fetch(T("/api/fs/session-path?session="+encodeURIComponent(e)))).json();t.path?_(t.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 _(e){P=e,m.innerHTML='<div class="file-tree-empty">Loading...</div>';let t=Ln(e);try{let n=await(await fetch(T("/api/fs/list?path="+encodeURIComponent(e)))).json();await t,m.innerHTML="",pe(g),m.innerHTML+=En();let s=Bn(e);if(s&&!Se.some(r=>e===r)){let r=document.createElement("div");r.className="file-tree-item",r.innerHTML="..",r.addEventListener("click",()=>_(s)),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> ${h(c)}`,l.addEventListener("click",()=>_(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=bn(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 S=document.createElement("div");S.className="file-tree-item file"+(u?" "+u:""),S.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${p}${h(c)}`,S.addEventListener("click",()=>Dn(r)),m.appendChild(S)}}catch{m.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function Bn(e){let t=e.lastIndexOf("/");return t<=0?null:e.substring(0,t)}async function Dn(e){Me=e,I.style.display="none",v&&($e(),v.destroy(),v=null,y=null),pe(null),Oe(),U.style.display="none",re.style.display="flex",dn.textContent=e,D.textContent="Loading...",Y.style.display="none";try{let t=await fetch(T("/api/file?path="+encodeURIComponent(e)));if(!t.ok){let s=await t.json();D.textContent=s.error||"Failed to load",ce.value="";return}let n=await t.json();ce.value=n.content,Te=n.content,ct=n.content,D.textContent=n.size+" bytes",Y.style.display=""}catch{D.textContent="Failed to load",ce.value=""}}ce.addEventListener("input",()=>{Te=ce.value}),Y.addEventListener("click",async()=>{Y.textContent="Saving...",Y.disabled=!0;try{let e=await fetch(T("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Me,content:Te})});if(!e.ok){let t=await e.json();D.textContent=t.error||"Save failed";return}ct=Te,D.textContent="Saved"}catch{D.textContent="Save failed"}finally{Y.disabled=!1,Y.textContent="Save"}}),un.addEventListener("click",async()=>{if(confirm("Delete "+Me+"?"))try{let e=await fetch(T("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Me})});if(!e.ok){let t=await e.json();D.textContent=t.error||"Delete failed";return}re.style.display="none",U.style.display="flex",P&&_(P)}catch{D.textContent="Delete failed"}}),pn.addEventListener("click",()=>{re.style.display="none",U.style.display="flex",P&&_(P)}),fn.addEventListener("click",async()=>{let e=dt.value.trim();if(!e)return;let t=P+"/"+e;try{let n=await fetch(T("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!n.ok){let s=await n.json();D.textContent=s.error||"Create failed";return}dt.value="",P&&_(P)}catch{D.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{let e=ut.classList.toggle("open");qe.classList.toggle("open",e)}),qe.addEventListener("click",()=>{ut.classList.remove("open"),qe.classList.remove("open")});var q="",fe=document.createElement("div");fe.className="session-popover-backdrop",document.body.appendChild(fe);var $=document.createElement("div");$.id="session-popover",$.className="session-popover",$.style.display="none",$.innerHTML=`<div class="sp-field">
35
+ </div><div class="diff-content">${s}</div></div>`,E.querySelector(".diff-back")?.addEventListener("click",()=>{E.innerHTML=Et,Ve(),g&&E.querySelectorAll(".git-popover-item").forEach(r=>{let c=parseInt(r.dataset.idx||"0",10),l=g.files[c];!l||l.status==="D"||(r.style.cursor="pointer",r.addEventListener("click",()=>Ct(l.path)))}),Lt()})}function Mn(e,t,n){if(!t&&!n){Ie.textContent="No diff",Be.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}let{html:s,lineCount:o}=xt(t,n);bt.textContent=e,Ie.textContent=o+" lines",Be.innerHTML=s}function Tn(){wt.style.display="none",He?(I.style.display="",I.classList.add("terminal-pending"),de(He),He=null):y?(I.style.display="",I.classList.add("terminal-pending"),Tt()):U.style.display="flex"}kn.addEventListener("click",Tn);function Ae(){E.classList.remove("open"),De.classList.remove("open")}De.addEventListener("click",Ae),document.addEventListener("keydown",e=>{e.key==="Escape"&&(Ae(),Ne())});async function Mt(e){try{let t=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(e))).json();if(t.path){let n=await fetch("/api/git/status?path="+encodeURIComponent(t.path));if(n.ok){let s=await n.json();g=s,pe(s);return}}}catch{}g=null,pe(null)}var Re=null;function Tt(){$e(),y&&(Mt(y),Re=setInterval(()=>{y&&Mt(y)},3e4))}function $e(){Re&&(clearInterval(Re),Re=null)}function Sn(){if(Se=le.fsRoots||[],Se.length===0){if(y){In(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 e of Se){let t=document.createElement("div");t.className="file-tree-item",t.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> ${h(e)}`,t.addEventListener("click",()=>_(e)),m.appendChild(t)}}async function In(e){m.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let t=await(await fetch(T("/api/fs/session-path?session="+encodeURIComponent(e)))).json();t.path?_(t.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 _(e){P=e,m.innerHTML='<div class="file-tree-empty">Loading...</div>';let t=Ln(e);try{let n=await(await fetch(T("/api/fs/list?path="+encodeURIComponent(e)))).json();await t,m.innerHTML="",pe(g),m.innerHTML+=En();let s=Bn(e);if(s&&!Se.some(r=>e===r)){let r=document.createElement("div");r.className="file-tree-item",r.innerHTML="..",r.addEventListener("click",()=>_(s)),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> ${h(c)}`,l.addEventListener("click",()=>_(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=bn(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 S=document.createElement("div");S.className="file-tree-item file"+(u?" "+u:""),S.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${p}${h(c)}`,S.addEventListener("click",()=>Dn(r)),m.appendChild(S)}}catch{m.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function Bn(e){let t=e.lastIndexOf("/");return t<=0?null:e.substring(0,t)}async function Dn(e){Me=e,I.style.display="none",v&&($e(),v.destroy(),v=null,y=null),pe(null),Oe(),U.style.display="none",re.style.display="flex",dn.textContent=e,D.textContent="Loading...",Y.style.display="none";try{let t=await fetch(T("/api/file?path="+encodeURIComponent(e)));if(!t.ok){let s=await t.json();D.textContent=s.error||"Failed to load",ce.value="";return}let n=await t.json();ce.value=n.content,Te=n.content,dt=n.content,D.textContent=n.size+" bytes",Y.style.display=""}catch{D.textContent="Failed to load",ce.value=""}}ce.addEventListener("input",()=>{Te=ce.value}),Y.addEventListener("click",async()=>{Y.textContent="Saving...",Y.disabled=!0;try{let e=await fetch(T("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Me,content:Te})});if(!e.ok){let t=await e.json();D.textContent=t.error||"Save failed";return}dt=Te,D.textContent="Saved"}catch{D.textContent="Save failed"}finally{Y.disabled=!1,Y.textContent="Save"}}),un.addEventListener("click",async()=>{if(confirm("Delete "+Me+"?"))try{let e=await fetch(T("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Me})});if(!e.ok){let t=await e.json();D.textContent=t.error||"Delete failed";return}re.style.display="none",U.style.display="flex",P&&_(P)}catch{D.textContent="Delete failed"}}),pn.addEventListener("click",()=>{re.style.display="none",U.style.display="flex",P&&_(P)}),fn.addEventListener("click",async()=>{let e=ut.value.trim();if(!e)return;let t=P+"/"+e;try{let n=await fetch(T("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!n.ok){let s=await n.json();D.textContent=s.error||"Create failed";return}ut.value="",P&&_(P)}catch{D.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{let e=pt.classList.toggle("open");qe.classList.toggle("open",e)}),qe.addEventListener("click",()=>{pt.classList.remove("open"),qe.classList.remove("open")});var q="",fe=document.createElement("div");fe.className="session-popover-backdrop",document.body.appendChild(fe);var $=document.createElement("div");$.id="session-popover",$.className="session-popover",$.style.display="none",$.innerHTML=`<div class="sp-field">
36
36
  <label>Rename session</label>
37
37
  <input type="text" id="sp-name" />
38
38
  </div>
@@ -41,5 +41,5 @@ var an=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function
41
41
  <button class="btn" id="sp-cancel">Cancel</button>
42
42
  </div>
43
43
  <hr class="sp-divider" />
44
- <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild($);function Hn(e){let t=e.getBoundingClientRect();$.style.top=t.bottom+4+"px",$.style.left=Math.max(8,Math.min(t.left,window.innerWidth-240))+"px"}function An(e,t){q=e;let n=document.getElementById("sp-name");n.value=e,fe.classList.add("open"),$.style.display="block",Hn(t),setTimeout(()=>n.focus(),50)}function me(){fe.classList.remove("open"),$.style.display="none"}fe.addEventListener("click",me),document.getElementById("sp-save").addEventListener("click",async()=>{let e=document.getElementById("sp-name").value.trim();if(!e||e===q){me();return}try{if(!(await fetch(T("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:q,newName:e})})).ok)return;me(),X(),y===q&&de(e)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+q+'"?'))try{if(!(await fetch(T("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:q})})).ok)return;me(),y===q&&(v&&(v.destroy(),v=null),y=null,I.style.display="none",U.style.display="flex"),X()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",me);var Rn={esc:"\x1B",tab:" ","s-tab":"\x1B[Z",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",space:" ",enter:"\r","ctrl-r":"","ctrl-c":"",btw:"/btw ",yes:"yes\r"};document.getElementById("mobile-keys").addEventListener("click",e=>{let t=e.target.closest("button[data-key]");if(!t||!v)return;let n=Rn[t.dataset.key];n&&(v.sendInput(n),v.focus())});var A=document.getElementById("mk-input"),Tt=document.getElementById("mk-send");function St(){if(!A||!v)return;let e=A.value;e&&(v.sendInput(e+"\r"),A.value="",A.rows=1,v.focus())}if(A&&(A.addEventListener("input",()=>{A.rows=1;let e=A.value.split(`
45
- `).length;A.rows=Math.min(e,4)}),A.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),St())})),Tt&&Tt.addEventListener("click",St),window.visualViewport){let e=document.querySelector(".app-layout"),t=()=>{e&&(e.style.height=window.visualViewport.height+"px"),window.scrollTo(0,0),document.documentElement.scrollTop=0,document.body.scrollTop=0};window.visualViewport.addEventListener("resize",t),window.addEventListener("orientationchange",()=>setTimeout(t,100)),document.addEventListener("touchstart",()=>{(window.scrollY>0||document.documentElement.scrollTop>0)&&window.scrollTo(0,0)},{passive:!0})}var Je=document.getElementById("process-panel"),he=document.getElementById("proc-list"),$n=document.getElementById("proc-close"),Xe=document.getElementById("proc-backdrop"),Nn=document.getElementById("header-ram");function Pn(){he.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(T("/api/system/processes")).then(e=>e.json()).then(e=>{if(!Array.isArray(e)||!e.length){he.innerHTML='<div class="proc-empty">No processes</div>';return}let t="";for(let n of e){let s=n.rss,o=s<1048576?(s/1024).toFixed(0)+"K":(s/1048576).toFixed(1)+"M";t+='<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="'+h(n.command)+'">'+h(n.command)+'</span><button class="proc-kill" title="Kill PID '+n.pid+'">&times;</button></div>'}he.innerHTML=t;for(let n of he.querySelectorAll(".proc-row")){let s=n.querySelector(".proc-kill");s&&s.addEventListener("click",o=>{let r=o.target.closest(".proc-row");!r||!confirm("Kill PID "+r.dataset.pid+"?")||fetch(T("/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(()=>{he.innerHTML='<div class="proc-empty">Failed to load</div>'})}function _n(){Je.classList.add("open"),Xe.classList.add("open"),Pn()}function Ne(){Je.classList.remove("open"),Xe.classList.remove("open")}Nn.addEventListener("click",e=>{e.stopPropagation(),Je.classList.contains("open")?Ne():_n()}),$n.addEventListener("click",Ne),Xe.addEventListener("click",Ne);var jn=2e3,ve=null,Ze=null,Pe=new Map,_e=new Map;function zn(e,t){return(t?"a:"+t+":":"l:")+e}function Wn(e,t,n){let s=zn(e,t),o=_e.get(s);_e.set(s,{session:e,agentId:t,state:n,doneUntil:n==="idle"&&o?.state==="working"?Date.now()+jn:void 0});let r=t?'.session-item[data-agent="'+CSS.escape(t)+'"][data-session="'+CSS.escape(e)+'"]':'.session-item[data-session="'+CSS.escape(e)+'"]:not([data-agent])',c=m.querySelector(r);c&&It(c,s,_e.get(s))}function It(e,t,n){let s=Pe.get(t);s&&(clearTimeout(s),Pe.delete(t)),e.classList.remove("working","just-done"),n.state==="working"?e.classList.add("working"):n.doneUntil&&Date.now()<n.doneUntil&&(e.classList.add("just-done"),Pe.set(t,setTimeout(()=>{e.classList.remove("just-done"),Pe.delete(t)},Math.max(0,n.doneUntil-Date.now()))))}function Bt(){for(let[e,t]of _e){let n=t.agentId?'.session-item[data-agent="'+CSS.escape(t.agentId)+'"][data-session="'+CSS.escape(t.session)+'"]':'.session-item[data-session="'+CSS.escape(t.session)+'"]:not([data-agent])',s=m.querySelector(n);s&&It(s,e,t)}}function Dt(){if(ve||Ze)return;let e=localStorage.getItem("tmux-web-token"),t=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/activity";e&&(t+="?token="+encodeURIComponent(e));try{let n=new WebSocket(t);ve=n,n.onmessage=s=>{try{let o=JSON.parse(String(s.data));o&&o.type==="session.activity"&&typeof o.session=="string"&&Wn(o.session,o.agentId||void 0,o.state==="working"?"working":"idle")}catch{}},n.onclose=()=>{ve===n&&(ve=null,Ze=setTimeout(()=>{Ze=null,Dt()},5e3))},n.onerror=()=>{try{n.close()}catch{}}}catch{ve=null}}window.__openSession=de,window.__refreshSidebar=X,X(),Oe(),Bt(),Dt(),setInterval(()=>{document.visibilityState==="visible"&&X()},1e4);
44
+ <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild($);function Hn(e){let t=e.getBoundingClientRect();$.style.top=t.bottom+4+"px",$.style.left=Math.max(8,Math.min(t.left,window.innerWidth-240))+"px"}function An(e,t){q=e;let n=document.getElementById("sp-name");n.value=e,fe.classList.add("open"),$.style.display="block",Hn(t),setTimeout(()=>n.focus(),50)}function me(){fe.classList.remove("open"),$.style.display="none"}fe.addEventListener("click",me),document.getElementById("sp-save").addEventListener("click",async()=>{let e=document.getElementById("sp-name").value.trim();if(!e||e===q){me();return}try{if(!(await fetch(T("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:q,newName:e})})).ok)return;me(),X(),y===q&&de(e)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+q+'"?'))try{if(!(await fetch(T("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:q})})).ok)return;me(),y===q&&(v&&(v.destroy(),v=null),y=null,I.style.display="none",U.style.display="flex"),X()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",me);var Rn={esc:"\x1B",tab:" ","s-tab":"\x1B[Z",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",space:" ",enter:"\r","ctrl-r":"","ctrl-c":"",btw:"/btw ",yes:"yes\r"};document.getElementById("mobile-keys").addEventListener("click",e=>{let t=e.target.closest("button[data-key]");if(!t||!v)return;let n=Rn[t.dataset.key];n&&(v.sendInput(n),v.focus())});var A=document.getElementById("mk-input"),St=document.getElementById("mk-send");function It(){if(!A||!v)return;let e=A.value;e&&(v.sendInput(e+"\r"),A.value="",A.rows=1,v.focus())}if(A&&(A.addEventListener("input",()=>{A.rows=1;let e=A.value.split(`
45
+ `).length;A.rows=Math.min(e,4)}),A.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),It())})),St&&St.addEventListener("click",It),window.visualViewport){let e=document.querySelector(".app-layout"),t=()=>{e&&(e.style.height=window.visualViewport.height+"px"),window.scrollTo(0,0),document.documentElement.scrollTop=0,document.body.scrollTop=0};window.visualViewport.addEventListener("resize",t),window.addEventListener("orientationchange",()=>setTimeout(t,100)),document.addEventListener("touchstart",()=>{(window.scrollY>0||document.documentElement.scrollTop>0)&&window.scrollTo(0,0)},{passive:!0})}var Je=document.getElementById("process-panel"),he=document.getElementById("proc-list"),$n=document.getElementById("proc-close"),Xe=document.getElementById("proc-backdrop"),Nn=document.getElementById("header-ram");function Pn(){he.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(T("/api/system/processes")).then(e=>e.json()).then(e=>{if(!Array.isArray(e)||!e.length){he.innerHTML='<div class="proc-empty">No processes</div>';return}let t="";for(let n of e){let s=n.rss,o=s<1048576?(s/1024).toFixed(0)+"K":(s/1048576).toFixed(1)+"M";t+='<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="'+h(n.command)+'">'+h(n.command)+'</span><button class="proc-kill" title="Kill PID '+n.pid+'">&times;</button></div>'}he.innerHTML=t;for(let n of he.querySelectorAll(".proc-row")){let s=n.querySelector(".proc-kill");s&&s.addEventListener("click",o=>{let r=o.target.closest(".proc-row");!r||!confirm("Kill PID "+r.dataset.pid+"?")||fetch(T("/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(()=>{he.innerHTML='<div class="proc-empty">Failed to load</div>'})}function _n(){Je.classList.add("open"),Xe.classList.add("open"),Pn()}function Ne(){Je.classList.remove("open"),Xe.classList.remove("open")}Nn.addEventListener("click",e=>{e.stopPropagation(),Je.classList.contains("open")?Ne():_n()}),$n.addEventListener("click",Ne),Xe.addEventListener("click",Ne);var jn=2e3,ve=null,Ze=null,Pe=new Map,_e=new Map;function zn(e,t){return(t?"a:"+t+":":"l:")+e}function Wn(e,t,n){let s=zn(e,t),o=_e.get(s);_e.set(s,{session:e,agentId:t,state:n,doneUntil:n==="idle"&&o?.state==="working"?Date.now()+jn:void 0});let r=t?'.session-item[data-agent="'+CSS.escape(t)+'"][data-session="'+CSS.escape(e)+'"]':'.session-item[data-session="'+CSS.escape(e)+'"]:not([data-agent])',c=m.querySelector(r);c&&Bt(c,s,_e.get(s))}function Bt(e,t,n){let s=Pe.get(t);s&&(clearTimeout(s),Pe.delete(t)),e.classList.remove("working","just-done"),n.state==="working"?e.classList.add("working"):n.doneUntil&&Date.now()<n.doneUntil&&(e.classList.add("just-done"),Pe.set(t,setTimeout(()=>{e.classList.remove("just-done"),Pe.delete(t)},Math.max(0,n.doneUntil-Date.now()))))}function Ge(){for(let[e,t]of _e){let n=t.agentId?'.session-item[data-agent="'+CSS.escape(t.agentId)+'"][data-session="'+CSS.escape(t.session)+'"]':'.session-item[data-session="'+CSS.escape(t.session)+'"]:not([data-agent])',s=m.querySelector(n);s&&Bt(s,e,t)}}function Dt(){if(ve||Ze)return;let e=localStorage.getItem("tmux-web-token"),t=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/activity";e&&(t+="?token="+encodeURIComponent(e));try{let n=new WebSocket(t);ve=n,n.onmessage=s=>{try{let o=JSON.parse(String(s.data));o&&o.type==="session.activity"&&typeof o.session=="string"&&Wn(o.session,o.agentId||void 0,o.state==="working"?"working":"idle")}catch{}},n.onclose=()=>{ve===n&&(ve=null,Ze=setTimeout(()=>{Ze=null,Dt()},5e3))},n.onerror=()=>{try{n.close()}catch{}}}catch{ve=null}}window.__openSession=de,window.__refreshSidebar=X,X(),Oe(),Ge(),Dt(),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&Ge()}),setInterval(()=>{document.visibilityState==="visible"&&X()},1e4);
@@ -1,17 +1,17 @@
1
- import{initTerminal as $e}from"./terminal-core.js";const H=window.__TMUX_WEB_SHELL__;let f=null,m=null;const re=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null;let g=re;window.__tmuxWebScopeAgent=re;let ee="sessions",C="",F="",O="",de="";function y(e){return g?"/a/"+encodeURIComponent(g)+e:e}const r=document.getElementById("sidebar-content"),I=document.getElementById("main-placeholder"),h=document.getElementById("terminal-container"),R=document.getElementById("file-editor"),Ne=document.getElementById("fe-path"),b=document.getElementById("fe-status"),$=document.getElementById("fe-content"),x=document.getElementById("fe-save"),_e=document.getElementById("fe-delete"),Ae=document.getElementById("fe-back"),pe=document.getElementById("fe-new-name"),De=document.getElementById("fe-new-btn"),te=document.getElementById("settings-backdrop"),fe=document.getElementById("settings-popover"),ue=document.querySelector(".sidebar");function Pe(){return window.matchMedia("(max-width: 640px)").matches}function ne(){Pe()&&ue.classList.add("collapsed")}function me(){ue.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{me(),ve("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{me(),ve("files")});function ve(e){ee=e,document.querySelectorAll(".mode-btn").forEach(t=>t.classList.remove("active"));const n=document.getElementById(e==="sessions"?"mode-sessions":"mode-files");n&&n.classList.add("active"),e==="sessions"?(se="",M()):Ze()}let se="";async function M(){if(ee!=="sessions")return;try{const t=await(await fetch("/api/sidebar/sessions")).json(),s=JSON.stringify({recent:t.recent,agents:t.agents});if(s===se)return;se=s,Ue(t)}catch{r.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}const e=document.getElementById("ns-btn");e&&e.addEventListener("click",()=>{const n=window.__openNewSessionModal;typeof n=="function"?n():document.getElementById("new-session-modal")?.classList.add("open")}),He()}const ge="tmux-web-sidebar-group-collapsed";function ye(){try{return new Set(JSON.parse(localStorage.getItem(ge)||"[]"))}catch{return new Set}}function je(e){try{localStorage.setItem(ge,JSON.stringify([...e]))}catch{}}function We(e,n,t){if(!e)return"\u2026";const s=t&&(e===t||e.startsWith(t+"/"))?"~"+e.slice(t.length):e,i=s.split("/").filter(Boolean);if(i.length===0)return e;for(let a=1;a<=i.length;a++){const o=i.slice(-a).join("/");if(!n.some(l=>!l||l===e?!1:(t&&(l===t||l.startsWith(t+"/"))?"~"+l.slice(t.length):l).split("/").filter(Boolean).slice(-a).join("/")===o))return o}return s}function Fe(e,n){const t=new Map;for(const a of e){const o=a.path||"";t.has(o)||t.set(o,[]),t.get(o).push(a)}const s=[...t.keys()],i=ye();for(const[a,o]of t){const c=We(a,s,n),l=i.has(a),p=document.createElement("div");p.className="session-group-header"+(l?" collapsed":""),p.title=a||"No working directory",p.innerHTML=`<span class="sg-folder">&#128193;</span><span class="sg-label">${d(c)}</span>`,p.addEventListener("click",()=>{const w=ye(),ce=p.nextElementSibling;w.has(a)?(w.delete(a),p.classList.remove("collapsed"),ce?.classList.remove("collapsed")):(w.add(a),p.classList.add("collapsed"),ce?.classList.add("collapsed")),je(w)});const L=document.createElement("div");L.className="session-group-body"+(l?" collapsed":"");for(const w of o)L.appendChild(Oe(w));r.appendChild(p),r.appendChild(L)}}function Oe(e){const n=document.createElement("div");n.className="session-item"+(e.name===m&&!g?" active":""),n.setAttribute("data-session",e.name),n.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${e.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>
1
+ import{initTerminal as $e}from"./terminal-core.js";const H=window.__TMUX_WEB_SHELL__;let f=null,m=null;const de=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null;let g=de;window.__tmuxWebScopeAgent=de;let ee="sessions",S="",F="",O="",pe="";function y(e){return g?"/a/"+encodeURIComponent(g)+e:e}const r=document.getElementById("sidebar-content"),I=document.getElementById("main-placeholder"),h=document.getElementById("terminal-container"),R=document.getElementById("file-editor"),Ne=document.getElementById("fe-path"),w=document.getElementById("fe-status"),$=document.getElementById("fe-content"),x=document.getElementById("fe-save"),_e=document.getElementById("fe-delete"),Ae=document.getElementById("fe-back"),fe=document.getElementById("fe-new-name"),De=document.getElementById("fe-new-btn"),te=document.getElementById("settings-backdrop"),ue=document.getElementById("settings-popover"),me=document.querySelector(".sidebar");function Pe(){return window.matchMedia("(max-width: 640px)").matches}function ne(){Pe()&&me.classList.add("collapsed")}function ve(){me.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{ve(),ge("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{ve(),ge("files")});function ge(e){ee=e,document.querySelectorAll(".mode-btn").forEach(t=>t.classList.remove("active"));const n=document.getElementById(e==="sessions"?"mode-sessions":"mode-files");n&&n.classList.add("active"),e==="sessions"?(se="",M()):Ze()}let se="";async function M(){if(ee!=="sessions")return;try{const t=await(await fetch("/api/sidebar/sessions")).json(),s=JSON.stringify({recent:t.recent,agents:t.agents});if(s===se)return;se=s,Ue(t)}catch{r.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}const e=document.getElementById("ns-btn");e&&e.addEventListener("click",()=>{const n=window.__openNewSessionModal;typeof n=="function"?n():document.getElementById("new-session-modal")?.classList.add("open")}),ce()}const ye="tmux-web-sidebar-group-collapsed";function he(){try{return new Set(JSON.parse(localStorage.getItem(ye)||"[]"))}catch{return new Set}}function je(e){try{localStorage.setItem(ye,JSON.stringify([...e]))}catch{}}function We(e,n,t){if(!e)return"\u2026";const s=t&&(e===t||e.startsWith(t+"/"))?"~"+e.slice(t.length):e,i=s.split("/").filter(Boolean);if(i.length===0)return e;for(let a=1;a<=i.length;a++){const o=i.slice(-a).join("/");if(!n.some(l=>!l||l===e?!1:(t&&(l===t||l.startsWith(t+"/"))?"~"+l.slice(t.length):l).split("/").filter(Boolean).slice(-a).join("/")===o))return o}return s}function Fe(e,n){const t=new Map;for(const a of e){const o=a.path||"";t.has(o)||t.set(o,[]),t.get(o).push(a)}const s=[...t.keys()],i=he();for(const[a,o]of t){const c=We(a,s,n),l=i.has(a),p=document.createElement("div");p.className="session-group-header"+(l?" collapsed":""),p.title=a||"No working directory",p.innerHTML=`<span class="sg-folder">&#128193;</span><span class="sg-label">${d(c)}</span>`,p.addEventListener("click",()=>{const b=he(),re=p.nextElementSibling;b.has(a)?(b.delete(a),p.classList.remove("collapsed"),re?.classList.remove("collapsed")):(b.add(a),p.classList.add("collapsed"),re?.classList.add("collapsed")),je(b)});const L=document.createElement("div");L.className="session-group-body"+(l?" collapsed":"");for(const b of o)L.appendChild(Oe(b));r.appendChild(p),r.appendChild(L)}}function Oe(e){const n=document.createElement("div");n.className="session-item"+(e.name===m&&!g?" active":""),n.setAttribute("data-session",e.name),n.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${e.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>
2
2
  <span>${d(e.name)}</span>
3
3
  <button class="session-edit-btn" data-session="${d(e.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>
4
4
  `,n.addEventListener("click",s=>{s.target.closest(".session-edit-btn")||N(e.name)});const t=n.querySelector(".session-edit-btn");return t&&t.addEventListener("click",s=>{s.stopPropagation(),st(e.name,t)}),n}function Ue(e){r.innerHTML='<button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';const n=e.recent||[],t=document.createElement("div");t.className="sidebar-section-label"+(g?" clickable":""),t.textContent=g?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",g&&(t.title="Back to hub",t.addEventListener("click",()=>{window.location.href="/"})),r.appendChild(t),Fe(n,e.home);const s=e.agents||[];for(const i of s){if(!i.sessions||i.sessions.length===0)continue;const a=i.agentId===g,o=document.createElement("div");o.className="sidebar-section-label machine-label"+(i.online?"":" agent-offline-label")+(!a&&i.online?" clickable":""),o.textContent=i.agentName+(i.online?"":" (offline)"),!a&&i.online&&(o.title="\u6253\u5F00 "+i.agentName,o.addEventListener("click",()=>{window.location.href="/a/"+encodeURIComponent(i.agentId)+"/"})),r.appendChild(o);for(const c of i.sessions){const l=document.createElement("div");l.className="session-item"+(c.name===m&&g===i.agentId?" active":"")+(i.online?"":" session-offline"),l.setAttribute("data-session",c.name),l.setAttribute("data-agent",i.agentId),l.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${c.attached?"M19 4H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zm0 14H5V6h14v12z":"M4 6h16v2H4V6zm0 5h16v2H4v-2zm0 5h16v2H4v-2z"}"></svg>
5
- <span>${d(c.name)}</span><span class="meta">${i.online?"":"offline"}</span>`,i.online&&l.addEventListener("click",p=>{p.target.closest(".session-edit-btn")||N(c.name,i.agentId)}),r.appendChild(l)}}}function d(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function N(e,n){if(!(m===e&&f&&g===(n||null))){R.style.display="none",I.style.display="none",h.style.display="",h.classList.add("terminal-pending"),ne(),f&&(X(),f.destroy(),f=null),m=e,g=n||null,window.__tmuxWebScopeAgent=g,window.__tmuxWebCurrentSession=m;for(const t of r.querySelectorAll(".session-item"))t.classList.toggle("active",t.getAttribute("data-session")===e&&(t.getAttribute("data-agent")||null)===g);try{f=await $e(h,e,{terminal:H.terminal,scrollback:H.scrollback,theme:H.theme,wsBase:g?"/ws/a/"+encodeURIComponent(g):H.wsBase||"/ws"}),xe()}catch(t){console.error("[shell] terminal init failed:",t);const s=t&&typeof t=="object"&&"message"in t?t.message:String(t);h.textContent="Failed to open terminal for "+e+": "+s,h.classList.remove("terminal-pending")}}}let U=[],u=null,he=!1;function Ge(e){if(!u||!u.files.length)return null;const n=u.repoRoot;if(!n||!e.startsWith(n))return null;const t=e.slice(n.length+1);for(const s of u.files)if(s.path===t)return s.status;return null}async function ze(e){he=!0;try{const n=await fetch(y("/api/git/status?path="+encodeURIComponent(e)));n.ok?u=await n.json():u=null}catch{u=null}finally{he=!1}}function qe(){if(!u||!u.branch)return"";const{branch:e,linesAdded:n,linesRemoved:t}=u;let s=`<div class="sidebar-git"><div class="git-branch-badge">
5
+ <span>${d(c.name)}</span><span class="meta">${i.online?"":"offline"}</span>`,i.online&&l.addEventListener("click",p=>{p.target.closest(".session-edit-btn")||N(c.name,i.agentId)}),r.appendChild(l)}}}function d(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function N(e,n){if(!(m===e&&f&&g===(n||null))){R.style.display="none",I.style.display="none",h.style.display="",h.classList.add("terminal-pending"),ne(),f&&(X(),f.destroy(),f=null),m=e,g=n||null,window.__tmuxWebScopeAgent=g,window.__tmuxWebCurrentSession=m;for(const t of r.querySelectorAll(".session-item"))t.classList.toggle("active",t.getAttribute("data-session")===e&&(t.getAttribute("data-agent")||null)===g);try{f=await $e(h,e,{terminal:H.terminal,scrollback:H.scrollback,theme:H.theme,wsBase:g?"/ws/a/"+encodeURIComponent(g):H.wsBase||"/ws"}),Be()}catch(t){console.error("[shell] terminal init failed:",t);const s=t&&typeof t=="object"&&"message"in t?t.message:String(t);h.textContent="Failed to open terminal for "+e+": "+s,h.classList.remove("terminal-pending")}}}let U=[],u=null,be=!1;function Ge(e){if(!u||!u.files.length)return null;const n=u.repoRoot;if(!n||!e.startsWith(n))return null;const t=e.slice(n.length+1);for(const s of u.files)if(s.path===t)return s.status;return null}async function ze(e){be=!0;try{const n=await fetch(y("/api/git/status?path="+encodeURIComponent(e)));n.ok?u=await n.json():u=null}catch{u=null}finally{be=!1}}function qe(){if(!u||!u.branch)return"";const{branch:e,linesAdded:n,linesRemoved:t}=u;let s=`<div class="sidebar-git"><div class="git-branch-badge">
6
6
  <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>
7
- ${d(e)}</div>`;return(n>0||t>0)&&(s+=`<div class="git-diff-stats">+<span class="add">${n}</span> <span class="del">-${t}</span></div>`),s+"</div>"}r.addEventListener("click",e=>{e.target.closest(".sidebar-git")&&T&&u&&(e.stopPropagation(),ke())});const _=document.getElementById("header-git"),we=document.getElementById("git-diff-view"),be=document.getElementById("gd-path"),G=document.getElementById("gd-status"),z=document.getElementById("gd-content"),Ve=document.getElementById("gd-back");let T=null;function A(e){if(!e||!e.branch){_.style.display="none",T=null;return}T=e.repoRoot;const{branch:n,linesAdded:t,linesRemoved:s}=e;let i=`<span class="branch">${d(n)}</span>`;(t>0||s>0)&&(i+=`<span class="sep">\xB7</span>+<span class="diff-add">${t}</span> <span class="diff-del">-${s}</span>`),_.innerHTML=i,_.style.display="block"}_.addEventListener("click",e=>{T&&u&&(e.stopPropagation(),ke())});const v=document.getElementById("git-popover"),q=document.getElementById("git-popover-backdrop");function ie(){const e=_.getBoundingClientRect();v.style.top=e.bottom+4+"px",v.style.left=Math.max(8,Math.min(e.left,window.innerWidth-400))+"px"}function Le(){const e=T,n=document.getElementById("git-popover-browse");n&&n.addEventListener("click",()=>{if(J(),e){ee="files",document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));const t=document.getElementById("mode-files");t&&t.classList.add("active"),S(e)}})}let Ee="";function ke(){if(!u)return;const e=u.files||[];if(!e.length)v.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
7
+ ${d(e)}</div>`;return(n>0||t>0)&&(s+=`<div class="git-diff-stats">+<span class="add">${n}</span> <span class="del">-${t}</span></div>`),s+"</div>"}r.addEventListener("click",e=>{e.target.closest(".sidebar-git")&&T&&u&&(e.stopPropagation(),Se())});const _=document.getElementById("header-git"),we=document.getElementById("git-diff-view"),Le=document.getElementById("gd-path"),G=document.getElementById("gd-status"),z=document.getElementById("gd-content"),Ve=document.getElementById("gd-back");let T=null;function A(e){if(!e||!e.branch){_.style.display="none",T=null;return}T=e.repoRoot;const{branch:n,linesAdded:t,linesRemoved:s}=e;let i=`<span class="branch">${d(n)}</span>`;(t>0||s>0)&&(i+=`<span class="sep">\xB7</span>+<span class="diff-add">${t}</span> <span class="diff-del">-${s}</span>`),_.innerHTML=i,_.style.display="block"}_.addEventListener("click",e=>{T&&u&&(e.stopPropagation(),Se())});const v=document.getElementById("git-popover"),q=document.getElementById("git-popover-backdrop");function ie(){const e=_.getBoundingClientRect();v.style.top=e.bottom+4+"px",v.style.left=Math.max(8,Math.min(e.left,window.innerWidth-400))+"px"}function Ee(){const e=T,n=document.getElementById("git-popover-browse");n&&n.addEventListener("click",()=>{if(J(),e){ee="files",document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));const t=document.getElementById("mode-files");t&&t.classList.add("active"),C(e)}})}let ke="";function Se(){if(!u)return;const e=u.files||[];if(!e.length)v.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
8
8
  <div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>`;else{let n=`<div class="git-popover-header">${e.length} file${e.length>1?"s":""} changed</div>`;for(let t=0;t<e.length;t++){const s=e[t],i=s.additions||0,a=s.deletions||0;let o="";switch(s.status){case"M":o='<span class="git-file-status M">M</span>';break;case"A":o='<span class="git-file-status A">A</span>';break;case"D":o='<span class="git-file-status D">D</span>';break;case"?":o='<span class="git-file-status ?">?</span>';break;case"R":o='<span class="git-file-status R">R</span>';break}n+=`<div class="git-popover-item" data-idx="${t}">
9
9
  ${o}<span class="file-path">${d(s.path)}</span>
10
10
  <span class="file-add">${i>0?"+"+i:""}</span>
11
11
  <span class="file-del">${a>0?"-"+a:""}</span>
12
- </div>`}n+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',Ee=n,v.innerHTML=n,v.querySelectorAll(".git-popover-item").forEach(t=>{const s=parseInt(t.dataset.idx||"0",10),i=e[s];!i||i.status==="D"||(t.classList.add("clickable"),t.style.cursor="pointer",t.addEventListener("click",()=>Se(i.path)))})}ie(),v.classList.add("open"),q.classList.add("open"),Le()}function Je(){return window.innerWidth>=1024}function Ce(e,n){const s=(e+(n&&e?`
12
+ </div>`}n+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',ke=n,v.innerHTML=n,v.querySelectorAll(".git-popover-item").forEach(t=>{const s=parseInt(t.dataset.idx||"0",10),i=e[s];!i||i.status==="D"||(t.classList.add("clickable"),t.style.cursor="pointer",t.addEventListener("click",()=>Ie(i.path)))})}ie(),v.classList.add("open"),q.classList.add("open"),Ee()}function Je(){return window.innerWidth>=1024}function Ce(e,n){const s=(e+(n&&e?`
13
13
  `:"")+n).split(`
14
- `);let i="",a=0,o=0;for(const c of s){const l=c;if(l.startsWith("@@")){const p=l.match(/@@\s+-(\d+)[^+]*\+(\d+)/);p&&(a=parseInt(p[1],10)-1,o=parseInt(p[2],10)-1),i+=`<div class="diff-line hunk"><span class="ln-body">${d(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">${d(l)}</span></div>`);continue}if(l.startsWith("+"))o++,i+=`<div class="diff-line add"><span class="ln-no">${o}</span><span class="ln-body">${d(l)}</span></div>`;else if(l.startsWith("-"))a++,i+=`<div class="diff-line del"><span class="ln-no">${a}</span><span class="ln-body">${d(l)}</span></div>`;else if(l.startsWith("\\"))i+=`<div class="diff-line"><span class="ln-body">${d(l)}</span></div>`;else{if(!l&&!a&&!o)continue;a++,o++,i+=`<div class="diff-line"><span class="ln-no">${a}</span><span class="ln-no" style="margin-right:12px">${o}</span><span class="ln-body">${d(l)}</span></div>`}}return{html:i,lineCount:s.length}}let V=null;async function Se(e){const n=T;if(n)if(J(),Je()){h.style.display="none",f&&(X(),f.destroy(),f=null,V=m,m=null),A(null),R.style.display="none",I.style.display="none",we.style.display="flex",be.textContent=e,G.textContent="Loading\u2026",z.innerHTML="";try{const t=await fetch(y("/api/git/diff?path="+encodeURIComponent(n)+"&file="+encodeURIComponent(e)));if(!t.ok)throw new Error(await t.text());const s=await t.json();Xe(e,s.diff,s.stagedDiff)}catch(t){const s=t instanceof Error?t.message:String(t);G.textContent="Error",z.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${d(s)}</div>`}}else{v.innerHTML=`<div class="git-diff-view"><div class="diff-header">
14
+ `);let i="",a=0,o=0;for(const c of s){const l=c;if(l.startsWith("@@")){const p=l.match(/@@\s+-(\d+)[^+]*\+(\d+)/);p&&(a=parseInt(p[1],10)-1,o=parseInt(p[2],10)-1),i+=`<div class="diff-line hunk"><span class="ln-body">${d(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">${d(l)}</span></div>`);continue}if(l.startsWith("+"))o++,i+=`<div class="diff-line add"><span class="ln-no">${o}</span><span class="ln-body">${d(l)}</span></div>`;else if(l.startsWith("-"))a++,i+=`<div class="diff-line del"><span class="ln-no">${a}</span><span class="ln-body">${d(l)}</span></div>`;else if(l.startsWith("\\"))i+=`<div class="diff-line"><span class="ln-body">${d(l)}</span></div>`;else{if(!l&&!a&&!o)continue;a++,o++,i+=`<div class="diff-line"><span class="ln-no">${a}</span><span class="ln-no" style="margin-right:12px">${o}</span><span class="ln-body">${d(l)}</span></div>`}}return{html:i,lineCount:s.length}}let V=null;async function Ie(e){const n=T;if(n)if(J(),Je()){h.style.display="none",f&&(X(),f.destroy(),f=null,V=m,m=null),A(null),R.style.display="none",I.style.display="none",we.style.display="flex",Le.textContent=e,G.textContent="Loading\u2026",z.innerHTML="";try{const t=await fetch(y("/api/git/diff?path="+encodeURIComponent(n)+"&file="+encodeURIComponent(e)));if(!t.ok)throw new Error(await t.text());const s=await t.json();Xe(e,s.diff,s.stagedDiff)}catch(t){const s=t instanceof Error?t.message:String(t);G.textContent="Error",z.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${d(s)}</div>`}}else{v.innerHTML=`<div class="git-diff-view"><div class="diff-header">
15
15
  <button class="diff-back">\u2190 Back</button>
16
16
  <span class="diff-filename">${d(e)}</span>
17
17
  <span class="diff-loading">Loading\u2026</span>
@@ -25,7 +25,7 @@ import{initTerminal as $e}from"./terminal-core.js";const H=window.__TMUX_WEB_SHE
25
25
  <button class="diff-back">\u2190 Back</button>
26
26
  <span class="diff-filename">${d(e)}</span>
27
27
  <span class="diff-filesize">${i} lines</span>
28
- </div><div class="diff-content">${s}</div></div>`,v.querySelector(".diff-back")?.addEventListener("click",()=>{v.innerHTML=Ee,ie(),u&&v.querySelectorAll(".git-popover-item").forEach(a=>{const o=parseInt(a.dataset.idx||"0",10),c=u.files[o];!c||c.status==="D"||(a.style.cursor="pointer",a.addEventListener("click",()=>Se(c.path)))}),Le()})}function Xe(e,n,t){if(!n&&!t){G.textContent="No diff",z.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}const{html:s,lineCount:i}=Ce(n,t);be.textContent=e,G.textContent=i+" lines",z.innerHTML=s}function Ye(){we.style.display="none",V?(h.style.display="",h.classList.add("terminal-pending"),N(V),V=null):m?(h.style.display="",h.classList.add("terminal-pending"),xe()):I.style.display="flex"}Ve.addEventListener("click",Ye);function J(){v.classList.remove("open"),q.classList.remove("open")}q.addEventListener("click",J),document.addEventListener("keydown",e=>{e.key==="Escape"&&(J(),Y())});async function Ie(e){try{const t=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(e))).json();if(t.path){const s=await fetch("/api/git/status?path="+encodeURIComponent(t.path));if(s.ok){const i=await s.json();u=i,A(i);return}}}catch{}u=null,A(null)}let K=null;function xe(){X(),m&&(Ie(m),K=setInterval(()=>{m&&Ie(m)},3e4))}function X(){K&&(clearInterval(K),K=null)}function Ze(){if(U=H.fsRoots||[],U.length===0){if(m){Qe(m);return}r.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}r.innerHTML="";for(const e of U){const n=document.createElement("div");n.className="file-tree-item",n.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> ${d(e)}`,n.addEventListener("click",()=>S(e)),r.appendChild(n)}}async function Qe(e){r.innerHTML='<div class="file-tree-empty">Loading...</div>';try{const t=await(await fetch(y("/api/fs/session-path?session="+encodeURIComponent(e)))).json();t.path?S(t.path):r.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{r.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function S(e){C=e,r.innerHTML='<div class="file-tree-empty">Loading...</div>';const n=ze(e);try{const s=await(await fetch(y("/api/fs/list?path="+encodeURIComponent(e)))).json();await n,r.innerHTML="",A(u),r.innerHTML+=qe();const i=et(e);if(i&&!U.some(c=>e===c)){const c=document.createElement("div");c.className="file-tree-item",c.innerHTML="..",c.addEventListener("click",()=>S(i)),r.appendChild(c)}if(s.dirs)for(const o of s.dirs){const c=o.split("/").pop()||o.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> ${d(c)}`,l.addEventListener("click",()=>S(o)),r.appendChild(l)}else r.innerHTML="";const a=s.files||[];for(const o of a){const c=o.split("/").pop()||o.split("\\").pop(),l=Ge(o);let p="",L="";if(l)switch(l){case"M":p="git-mod",L='<span class="git-file-status M">M</span>';break;case"A":p="git-add",L='<span class="git-file-status A">A</span>';break;case"D":p="git-del",L='<span class="git-file-status D">D</span>';break;case"?":p="git-untracked",L='<span class="git-file-status ?">?</span>';break;case"R":p="git-mod",L='<span class="git-file-status R">R</span>';break}const w=document.createElement("div");w.className="file-tree-item file"+(p?" "+p:""),w.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${L}${d(c)}`,w.addEventListener("click",()=>tt(o)),r.appendChild(w)}}catch{r.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function et(e){const n=e.lastIndexOf("/");return n<=0?null:e.substring(0,n)}async function tt(e){F=e,h.style.display="none",f&&(X(),f.destroy(),f=null,m=null),A(null),ne(),I.style.display="none",R.style.display="flex",Ne.textContent=e,b.textContent="Loading...",x.style.display="none";try{const n=await fetch(y("/api/file?path="+encodeURIComponent(e)));if(!n.ok){const s=await n.json();b.textContent=s.error||"Failed to load",$.value="";return}const t=await n.json();$.value=t.content,O=t.content,de=t.content,b.textContent=t.size+" bytes",x.style.display=""}catch{b.textContent="Failed to load",$.value=""}}$.addEventListener("input",()=>{O=$.value}),x.addEventListener("click",async()=>{x.textContent="Saving...",x.disabled=!0;try{const e=await fetch(y("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:F,content:O})});if(!e.ok){const n=await e.json();b.textContent=n.error||"Save failed";return}de=O,b.textContent="Saved"}catch{b.textContent="Save failed"}finally{x.disabled=!1,x.textContent="Save"}}),_e.addEventListener("click",async()=>{if(confirm("Delete "+F+"?"))try{const e=await fetch(y("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:F})});if(!e.ok){const n=await e.json();b.textContent=n.error||"Delete failed";return}R.style.display="none",I.style.display="flex",C&&S(C)}catch{b.textContent="Delete failed"}}),Ae.addEventListener("click",()=>{R.style.display="none",I.style.display="flex",C&&S(C)}),De.addEventListener("click",async()=>{const e=pe.value.trim();if(!e)return;const n=C+"/"+e;try{const t=await fetch(y("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:n})});if(!t.ok){const s=await t.json();b.textContent=s.error||"Create failed";return}pe.value="",C&&S(C)}catch{b.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{const e=fe.classList.toggle("open");te.classList.toggle("open",e)}),te.addEventListener("click",()=>{fe.classList.remove("open"),te.classList.remove("open")});let B="";const D=document.createElement("div");D.className="session-popover-backdrop",document.body.appendChild(D);const k=document.createElement("div");k.id="session-popover",k.className="session-popover",k.style.display="none",k.innerHTML=`<div class="sp-field">
28
+ </div><div class="diff-content">${s}</div></div>`,v.querySelector(".diff-back")?.addEventListener("click",()=>{v.innerHTML=ke,ie(),u&&v.querySelectorAll(".git-popover-item").forEach(a=>{const o=parseInt(a.dataset.idx||"0",10),c=u.files[o];!c||c.status==="D"||(a.style.cursor="pointer",a.addEventListener("click",()=>Ie(c.path)))}),Ee()})}function Xe(e,n,t){if(!n&&!t){G.textContent="No diff",z.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}const{html:s,lineCount:i}=Ce(n,t);Le.textContent=e,G.textContent=i+" lines",z.innerHTML=s}function Ye(){we.style.display="none",V?(h.style.display="",h.classList.add("terminal-pending"),N(V),V=null):m?(h.style.display="",h.classList.add("terminal-pending"),Be()):I.style.display="flex"}Ve.addEventListener("click",Ye);function J(){v.classList.remove("open"),q.classList.remove("open")}q.addEventListener("click",J),document.addEventListener("keydown",e=>{e.key==="Escape"&&(J(),Y())});async function xe(e){try{const t=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(e))).json();if(t.path){const s=await fetch("/api/git/status?path="+encodeURIComponent(t.path));if(s.ok){const i=await s.json();u=i,A(i);return}}}catch{}u=null,A(null)}let K=null;function Be(){X(),m&&(xe(m),K=setInterval(()=>{m&&xe(m)},3e4))}function X(){K&&(clearInterval(K),K=null)}function Ze(){if(U=H.fsRoots||[],U.length===0){if(m){Qe(m);return}r.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}r.innerHTML="";for(const e of U){const n=document.createElement("div");n.className="file-tree-item",n.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> ${d(e)}`,n.addEventListener("click",()=>C(e)),r.appendChild(n)}}async function Qe(e){r.innerHTML='<div class="file-tree-empty">Loading...</div>';try{const t=await(await fetch(y("/api/fs/session-path?session="+encodeURIComponent(e)))).json();t.path?C(t.path):r.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{r.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function C(e){S=e,r.innerHTML='<div class="file-tree-empty">Loading...</div>';const n=ze(e);try{const s=await(await fetch(y("/api/fs/list?path="+encodeURIComponent(e)))).json();await n,r.innerHTML="",A(u),r.innerHTML+=qe();const i=et(e);if(i&&!U.some(c=>e===c)){const c=document.createElement("div");c.className="file-tree-item",c.innerHTML="..",c.addEventListener("click",()=>C(i)),r.appendChild(c)}if(s.dirs)for(const o of s.dirs){const c=o.split("/").pop()||o.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> ${d(c)}`,l.addEventListener("click",()=>C(o)),r.appendChild(l)}else r.innerHTML="";const a=s.files||[];for(const o of a){const c=o.split("/").pop()||o.split("\\").pop(),l=Ge(o);let p="",L="";if(l)switch(l){case"M":p="git-mod",L='<span class="git-file-status M">M</span>';break;case"A":p="git-add",L='<span class="git-file-status A">A</span>';break;case"D":p="git-del",L='<span class="git-file-status D">D</span>';break;case"?":p="git-untracked",L='<span class="git-file-status ?">?</span>';break;case"R":p="git-mod",L='<span class="git-file-status R">R</span>';break}const b=document.createElement("div");b.className="file-tree-item file"+(p?" "+p:""),b.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${L}${d(c)}`,b.addEventListener("click",()=>tt(o)),r.appendChild(b)}}catch{r.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function et(e){const n=e.lastIndexOf("/");return n<=0?null:e.substring(0,n)}async function tt(e){F=e,h.style.display="none",f&&(X(),f.destroy(),f=null,m=null),A(null),ne(),I.style.display="none",R.style.display="flex",Ne.textContent=e,w.textContent="Loading...",x.style.display="none";try{const n=await fetch(y("/api/file?path="+encodeURIComponent(e)));if(!n.ok){const s=await n.json();w.textContent=s.error||"Failed to load",$.value="";return}const t=await n.json();$.value=t.content,O=t.content,pe=t.content,w.textContent=t.size+" bytes",x.style.display=""}catch{w.textContent="Failed to load",$.value=""}}$.addEventListener("input",()=>{O=$.value}),x.addEventListener("click",async()=>{x.textContent="Saving...",x.disabled=!0;try{const e=await fetch(y("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:F,content:O})});if(!e.ok){const n=await e.json();w.textContent=n.error||"Save failed";return}pe=O,w.textContent="Saved"}catch{w.textContent="Save failed"}finally{x.disabled=!1,x.textContent="Save"}}),_e.addEventListener("click",async()=>{if(confirm("Delete "+F+"?"))try{const e=await fetch(y("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:F})});if(!e.ok){const n=await e.json();w.textContent=n.error||"Delete failed";return}R.style.display="none",I.style.display="flex",S&&C(S)}catch{w.textContent="Delete failed"}}),Ae.addEventListener("click",()=>{R.style.display="none",I.style.display="flex",S&&C(S)}),De.addEventListener("click",async()=>{const e=fe.value.trim();if(!e)return;const n=S+"/"+e;try{const t=await fetch(y("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:n})});if(!t.ok){const s=await t.json();w.textContent=s.error||"Create failed";return}fe.value="",S&&C(S)}catch{w.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{const e=ue.classList.toggle("open");te.classList.toggle("open",e)}),te.addEventListener("click",()=>{ue.classList.remove("open"),te.classList.remove("open")});let B="";const D=document.createElement("div");D.className="session-popover-backdrop",document.body.appendChild(D);const k=document.createElement("div");k.id="session-popover",k.className="session-popover",k.style.display="none",k.innerHTML=`<div class="sp-field">
29
29
  <label>Rename session</label>
30
30
  <input type="text" id="sp-name" />
31
31
  </div>
@@ -34,5 +34,5 @@ import{initTerminal as $e}from"./terminal-core.js";const H=window.__TMUX_WEB_SHE
34
34
  <button class="btn" id="sp-cancel">Cancel</button>
35
35
  </div>
36
36
  <hr class="sp-divider" />
37
- <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(k);function nt(e){const n=e.getBoundingClientRect();k.style.top=n.bottom+4+"px",k.style.left=Math.max(8,Math.min(n.left,window.innerWidth-240))+"px"}function st(e,n){B=e;const t=document.getElementById("sp-name");t.value=e,D.classList.add("open"),k.style.display="block",nt(n),setTimeout(()=>t.focus(),50)}function P(){D.classList.remove("open"),k.style.display="none"}D.addEventListener("click",P),document.getElementById("sp-save").addEventListener("click",async()=>{const e=document.getElementById("sp-name").value.trim();if(!e||e===B){P();return}try{if(!(await fetch(y("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:B,newName:e})})).ok)return;P(),M(),m===B&&N(e)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+B+'"?'))try{if(!(await fetch(y("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:B})})).ok)return;P(),m===B&&(f&&(f.destroy(),f=null),m=null,h.style.display="none",I.style.display="flex"),M()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",P);const it={esc:"\x1B",tab:" ","s-tab":"\x1B[Z",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",space:" ",enter:"\r","ctrl-r":"","ctrl-c":"",btw:"/btw ",yes:"yes\r"};document.getElementById("mobile-keys").addEventListener("click",e=>{const n=e.target.closest("button[data-key]");if(!n||!f)return;const t=it[n.dataset.key];t&&(f.sendInput(t),f.focus())});const E=document.getElementById("mk-input"),Be=document.getElementById("mk-send");function Me(){if(!E||!f)return;const e=E.value;e&&(f.sendInput(e+"\r"),E.value="",E.rows=1,f.focus())}if(E&&(E.addEventListener("input",()=>{E.rows=1;const e=E.value.split(`
38
- `).length;E.rows=Math.min(e,4)}),E.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),Me())})),Be&&Be.addEventListener("click",Me),window.visualViewport){const e=document.querySelector(".app-layout"),n=()=>{e&&(e.style.height=window.visualViewport.height+"px"),window.scrollTo(0,0),document.documentElement.scrollTop=0,document.body.scrollTop=0};window.visualViewport.addEventListener("resize",n),window.addEventListener("orientationchange",()=>setTimeout(n,100)),document.addEventListener("touchstart",()=>{(window.scrollY>0||document.documentElement.scrollTop>0)&&window.scrollTo(0,0)},{passive:!0})}const oe=document.getElementById("process-panel"),j=document.getElementById("proc-list"),ot=document.getElementById("proc-close"),ae=document.getElementById("proc-backdrop"),at=document.getElementById("header-ram");function lt(){j.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(y("/api/system/processes")).then(e=>e.json()).then(e=>{if(!Array.isArray(e)||!e.length){j.innerHTML='<div class="proc-empty">No processes</div>';return}let n="";for(const t of e){const s=t.rss,i=s<1048576?(s/1024).toFixed(0)+"K":(s/1048576).toFixed(1)+"M";n+='<div class="proc-row" data-pid="'+t.pid+'"><span class="proc-mem">'+t.mem+'%</span><span class="proc-rss">'+i+'</span><span class="proc-cmd" title="'+d(t.command)+'">'+d(t.command)+'</span><button class="proc-kill" title="Kill PID '+t.pid+'">&times;</button></div>'}j.innerHTML=n;for(const t of j.querySelectorAll(".proc-row")){const s=t.querySelector(".proc-kill");s&&s.addEventListener("click",i=>{const a=i.target.closest(".proc-row");!a||!confirm("Kill PID "+a.dataset.pid+"?")||fetch(y("/api/system/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(a.dataset.pid,10)})}).then(o=>o.json()).then(o=>{o.ok?a.style.opacity="0.3":alert("Failed: "+(o.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{j.innerHTML='<div class="proc-empty">Failed to load</div>'})}function ct(){oe.classList.add("open"),ae.classList.add("open"),lt()}function Y(){oe.classList.remove("open"),ae.classList.remove("open")}at.addEventListener("click",e=>{e.stopPropagation(),oe.classList.contains("open")?Y():ct()}),ot.addEventListener("click",Y),ae.addEventListener("click",Y);const rt=2e3;let W=null,le=null;const Z=new Map,Q=new Map;function dt(e,n){return(n?"a:"+n+":":"l:")+e}function pt(e,n,t){const s=dt(e,n),i=Q.get(s);Q.set(s,{session:e,agentId:n,state:t,doneUntil:t==="idle"&&i?.state==="working"?Date.now()+rt:void 0});const a=n?'.session-item[data-agent="'+CSS.escape(n)+'"][data-session="'+CSS.escape(e)+'"]':'.session-item[data-session="'+CSS.escape(e)+'"]:not([data-agent])',o=r.querySelector(a);o&&Te(o,s,Q.get(s))}function Te(e,n,t){const s=Z.get(n);s&&(clearTimeout(s),Z.delete(n)),e.classList.remove("working","just-done"),t.state==="working"?e.classList.add("working"):t.doneUntil&&Date.now()<t.doneUntil&&(e.classList.add("just-done"),Z.set(n,setTimeout(()=>{e.classList.remove("just-done"),Z.delete(n)},Math.max(0,t.doneUntil-Date.now()))))}function He(){for(const[e,n]of Q){const t=n.agentId?'.session-item[data-agent="'+CSS.escape(n.agentId)+'"][data-session="'+CSS.escape(n.session)+'"]':'.session-item[data-session="'+CSS.escape(n.session)+'"]:not([data-agent])',s=r.querySelector(t);s&&Te(s,e,n)}}function Re(){if(W||le)return;const e=localStorage.getItem("tmux-web-token");let t=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/activity";e&&(t+="?token="+encodeURIComponent(e));try{const s=new WebSocket(t);W=s,s.onmessage=i=>{try{const a=JSON.parse(String(i.data));a&&a.type==="session.activity"&&typeof a.session=="string"&&pt(a.session,a.agentId||void 0,a.state==="working"?"working":"idle")}catch{}},s.onclose=()=>{W===s&&(W=null,le=setTimeout(()=>{le=null,Re()},5e3))},s.onerror=()=>{try{s.close()}catch{}}}catch{W=null}}window.__openSession=N,window.__refreshSidebar=M,M(),ne(),He(),Re(),setInterval(()=>{document.visibilityState==="visible"&&M()},1e4);
37
+ <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(k);function nt(e){const n=e.getBoundingClientRect();k.style.top=n.bottom+4+"px",k.style.left=Math.max(8,Math.min(n.left,window.innerWidth-240))+"px"}function st(e,n){B=e;const t=document.getElementById("sp-name");t.value=e,D.classList.add("open"),k.style.display="block",nt(n),setTimeout(()=>t.focus(),50)}function P(){D.classList.remove("open"),k.style.display="none"}D.addEventListener("click",P),document.getElementById("sp-save").addEventListener("click",async()=>{const e=document.getElementById("sp-name").value.trim();if(!e||e===B){P();return}try{if(!(await fetch(y("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:B,newName:e})})).ok)return;P(),M(),m===B&&N(e)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+B+'"?'))try{if(!(await fetch(y("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:B})})).ok)return;P(),m===B&&(f&&(f.destroy(),f=null),m=null,h.style.display="none",I.style.display="flex"),M()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",P);const it={esc:"\x1B",tab:" ","s-tab":"\x1B[Z",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",space:" ",enter:"\r","ctrl-r":"","ctrl-c":"",btw:"/btw ",yes:"yes\r"};document.getElementById("mobile-keys").addEventListener("click",e=>{const n=e.target.closest("button[data-key]");if(!n||!f)return;const t=it[n.dataset.key];t&&(f.sendInput(t),f.focus())});const E=document.getElementById("mk-input"),Me=document.getElementById("mk-send");function Te(){if(!E||!f)return;const e=E.value;e&&(f.sendInput(e+"\r"),E.value="",E.rows=1,f.focus())}if(E&&(E.addEventListener("input",()=>{E.rows=1;const e=E.value.split(`
38
+ `).length;E.rows=Math.min(e,4)}),E.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),Te())})),Me&&Me.addEventListener("click",Te),window.visualViewport){const e=document.querySelector(".app-layout"),n=()=>{e&&(e.style.height=window.visualViewport.height+"px"),window.scrollTo(0,0),document.documentElement.scrollTop=0,document.body.scrollTop=0};window.visualViewport.addEventListener("resize",n),window.addEventListener("orientationchange",()=>setTimeout(n,100)),document.addEventListener("touchstart",()=>{(window.scrollY>0||document.documentElement.scrollTop>0)&&window.scrollTo(0,0)},{passive:!0})}const oe=document.getElementById("process-panel"),j=document.getElementById("proc-list"),ot=document.getElementById("proc-close"),ae=document.getElementById("proc-backdrop"),at=document.getElementById("header-ram");function lt(){j.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(y("/api/system/processes")).then(e=>e.json()).then(e=>{if(!Array.isArray(e)||!e.length){j.innerHTML='<div class="proc-empty">No processes</div>';return}let n="";for(const t of e){const s=t.rss,i=s<1048576?(s/1024).toFixed(0)+"K":(s/1048576).toFixed(1)+"M";n+='<div class="proc-row" data-pid="'+t.pid+'"><span class="proc-mem">'+t.mem+'%</span><span class="proc-rss">'+i+'</span><span class="proc-cmd" title="'+d(t.command)+'">'+d(t.command)+'</span><button class="proc-kill" title="Kill PID '+t.pid+'">&times;</button></div>'}j.innerHTML=n;for(const t of j.querySelectorAll(".proc-row")){const s=t.querySelector(".proc-kill");s&&s.addEventListener("click",i=>{const a=i.target.closest(".proc-row");!a||!confirm("Kill PID "+a.dataset.pid+"?")||fetch(y("/api/system/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(a.dataset.pid,10)})}).then(o=>o.json()).then(o=>{o.ok?a.style.opacity="0.3":alert("Failed: "+(o.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{j.innerHTML='<div class="proc-empty">Failed to load</div>'})}function ct(){oe.classList.add("open"),ae.classList.add("open"),lt()}function Y(){oe.classList.remove("open"),ae.classList.remove("open")}at.addEventListener("click",e=>{e.stopPropagation(),oe.classList.contains("open")?Y():ct()}),ot.addEventListener("click",Y),ae.addEventListener("click",Y);const rt=2e3;let W=null,le=null;const Z=new Map,Q=new Map;function dt(e,n){return(n?"a:"+n+":":"l:")+e}function pt(e,n,t){const s=dt(e,n),i=Q.get(s);Q.set(s,{session:e,agentId:n,state:t,doneUntil:t==="idle"&&i?.state==="working"?Date.now()+rt:void 0});const a=n?'.session-item[data-agent="'+CSS.escape(n)+'"][data-session="'+CSS.escape(e)+'"]':'.session-item[data-session="'+CSS.escape(e)+'"]:not([data-agent])',o=r.querySelector(a);o&&He(o,s,Q.get(s))}function He(e,n,t){const s=Z.get(n);s&&(clearTimeout(s),Z.delete(n)),e.classList.remove("working","just-done"),t.state==="working"?e.classList.add("working"):t.doneUntil&&Date.now()<t.doneUntil&&(e.classList.add("just-done"),Z.set(n,setTimeout(()=>{e.classList.remove("just-done"),Z.delete(n)},Math.max(0,t.doneUntil-Date.now()))))}function ce(){for(const[e,n]of Q){const t=n.agentId?'.session-item[data-agent="'+CSS.escape(n.agentId)+'"][data-session="'+CSS.escape(n.session)+'"]':'.session-item[data-session="'+CSS.escape(n.session)+'"]:not([data-agent])',s=r.querySelector(t);s&&He(s,e,n)}}function Re(){if(W||le)return;const e=localStorage.getItem("tmux-web-token");let t=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/activity";e&&(t+="?token="+encodeURIComponent(e));try{const s=new WebSocket(t);W=s,s.onmessage=i=>{try{const a=JSON.parse(String(i.data));a&&a.type==="session.activity"&&typeof a.session=="string"&&pt(a.session,a.agentId||void 0,a.state==="working"?"working":"idle")}catch{}},s.onclose=()=>{W===s&&(W=null,le=setTimeout(()=>{le=null,Re()},5e3))},s.onerror=()=>{try{s.close()}catch{}}}catch{W=null}}window.__openSession=N,window.__refreshSidebar=M,M(),ne(),ce(),Re(),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&ce()}),setInterval(()=>{document.visibilityState==="visible"&&M()},1e4);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmux-weblink",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "Access your tmux sessions from the browser. A continuation of tmux-web and persalink.",
5
5
  "type": "module",
6
6
  "bin": {