tmux-weblink 2.0.28 → 2.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,38 +1,38 @@
1
- var Xt=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function Fe(e){return e.replace(/\x1b\[\?1049[hl]/g,"")}function oe(e){return e.replace(Xt,"")}var ke;function Jt(){return ke||(document.querySelector("link[data-tmux-web-xterm-css]")?ke=Promise.resolve():(ke=new Promise(e=>{let t=document.createElement("link");t.rel="stylesheet",t.href="/assets/xterm.css",t.setAttribute("data-tmux-web-xterm-css",""),t.addEventListener("load",()=>e(),{once:!0}),t.addEventListener("error",()=>e(),{once:!0}),document.head.appendChild(t)}),ke))}var Zt=class xt{terminal;fitAddon;container;constructor(t,s,i){this.container=t,this.terminal=s,this.fitAddon=i,this.terminal.loadAddon(this.fitAddon),this.terminal.open(t)}static async create(t,s,i){let[{Terminal:o},{FitAddon:r}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),Jt()]),d=new o({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:s,convertEol:!1,smoothScrollDuration:120,theme:i});return new xt(t,d,new r)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(t){return new Promise(s=>this.terminal.write(t,s))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(t,s=!1){this.terminal.scrollToLine(Math.max(0,t),s)}scrollLines(t){let s=this.terminal.buffer?.active;this.terminal.scrollLines(t)}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){let t=Gt(this.container);return t.width<=0||t.height<=0?!1:(this.fitAddon.fit(),!0)}focus(){this.terminal.focus()}pasteText(t){this.terminal.paste(t)}input(t){this.terminal.input(t,!1)}onData(t){this.terminal.onData(t),this.terminal.onBinary(t)}onResize(t){this.terminal.onResize(t)}onScroll(t){this.terminal.onScroll(t)}attachCustomKeyEventHandler(t){this.terminal.attachCustomKeyEventHandler(t)}isFocused(){let t=document.activeElement;return t?t===this.container||t===this.terminal.textarea||this.container.contains(t)||!!t.closest?.(".xterm"):!1}getScreenText(){return this.getRowsText(0,this.terminal.rows-1)}getRowsText(t,s){let i=this.terminal.buffer.active,[o,r]=t<=s?[t,s]:[s,t],d=i.viewportY,l=[];for(let u=o;u<=r;u++){let f=i.getLine(d+u);l.push(f?f.translateToString(!0):"")}return l.join(`
2
- `)}selectRows(t,s){let i=this.terminal.buffer.active,[o,r]=t<=s?[t,s]:[s,t];this.terminal.selectLines(i.viewportY+o,i.viewportY+r)}selectCells(t,s,i,o){let r=this.terminal.buffer.active,d=Math.min(s,o),l=Math.max(s,o);if(d===l){let u=Math.min(t,i),f=Math.max(t,i);this.terminal.select(u,r.viewportY+d,f-u+1)}else this.terminal.selectLines(r.viewportY+d,r.viewportY+l)}getCellsText(t,s,i,o){let r=this.terminal.buffer.active,d=Math.min(s,o),l=Math.max(s,o),u=s<o?t:s>o?i:Math.min(t,i),f=s<o?i:s>o?t:Math.max(t,i),R=r.viewportY,q=[];for(let N=d;N<=l;N++){let he=r.getLine(R+N);if(!he){q.push("");continue}let O=N===d?u:0,Pe=N===l?f:this.terminal.cols-1,K="";for(let k=O;k<=Pe;k++){let z=he.getCell(k);z&&(K+=z.getChars())}q.push(K.replace(/\s+$/,""))}return q.join(`
3
- `)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}};function Gt(e){let t=e.getBoundingClientRect(),s=window.visualViewport;return s?{width:Math.min(t.width,s.width),height:Math.max(0,Math.min(t.height,s.height-Math.max(0,t.top)))}:t}function Qt(e,t,s){return e.innerHTML="",e.classList.add("terminal-pending"),(async()=>{let i=await Zt.create(e,s.scrollback,s.theme),o,r=0,d,l=null,u=0,f=0,R=.2,q=10,N=.95,he=.04;function O(){u&&(cancelAnimationFrame(u),u=0),f=0}function Pe(n){if(O(),Math.abs(n)<R)return;f=Math.max(-q,Math.min(q,n));let a=()=>{if(A){u=0;return}let c=e.querySelector(".xterm-rows > div"),p=c?c.getBoundingClientRect().height:16,b=p>0?Math.round(f*16/p):f>0?1:-1;b===0&&(b=f>0?1:-1);let B=i.viewportY()-b,j=i.baseY(),ae=Math.max(0,Math.min(B,j));if(i.scrollToLine(ae,!0),f*=N,ae!==B){u=0;return}if(Math.abs(f)<he){u=0;return}u=requestAnimationFrame(a)};u=requestAnimationFrame(a)}let K=0,k="connecting",z=0,G=!1,ge=[],V="",A=!1,Q=1e3,kt=location.protocol==="https:"?"wss:":"ws:",Ct=s.wsBase||"/ws",Tt=kt+"//"+location.host+Ct+"/"+encodeURIComponent(t),Mt="/api/session/"+encodeURIComponent(t)+"/upload",Bt=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function It(){return ge.join("")+V}async function St(n,a=0){let c=n?i.viewportY():0,p=oe(It());if(i.reset(),!p){n||i.scrollToBottom();return}await i.write(p),n?i.scrollToLine(a+c):i.scrollToBottom()}function _(n){o?.readyState===WebSocket.OPEN&&o.send(JSON.stringify(n))}function Ht(n){let a;try{a=JSON.parse(n)}catch{k==="live"&&(V+=n,i.write(oe(n)));return}if(a.type==="auth.required"){let c=localStorage.getItem("tmux-web-token");c?_({type:"auth.token",token:c}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(a.type==="attach_failed"&&typeof a.message=="string"){ye=!0,k="dead",i.reset(),i.write(`\r
4
- \x1B[31m`+oe(a.message)+`\x1B[0m\r
5
- `).then(()=>{be();try{o?.close()}catch{}});return}if(a.type==="auth.ok"){a.token&&localStorage.setItem("tmux-web-token",a.token),Q=1e3,F(),_({type:"resize",cols:i.cols,rows:i.rows}),C();return}if(a.type==="auth.failed"){if(a.permanentLock||a.retryAfterMs&&a.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(a.message);return}return}if(a.type==="snapshot"&&typeof a.data=="string"){let c=Fe(oe(a.data));ge=[c],V="",z=typeof a.lines=="number"?a.lines:s.terminal.initialLines,k="live",i.reset(),F(),_({type:"resize",cols:i.cols,rows:i.rows}),i.write(c).then(()=>i.scrollToBottom());return}if(a.type==="window_changed"&&typeof a.activeIndex=="number"){let c=new URL(location.href);c.searchParams.get("window")!==String(a.activeIndex)&&(c.searchParams.set("window",String(a.activeIndex)),history.replaceState(history.state,"",c)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:a.windows}));return}if(a.type==="history"&&typeof a.data=="string"){a.lines>0&&a.data?(ge.unshift(Fe(a.data)),z+=a.lines,St(!0,a.lines).finally(()=>{G=!1})):G=!1;return}if(a.type==="data"&&typeof a.data=="string"){let c=Fe(oe(a.data));if(k==="connecting"){k="live",V=c,i.write(c);return}k==="live"&&(V+=c,i.write(c))}}let ye=!1;function Ve(){if(ye)return;let n=Tt,a=localStorage.getItem("tmux-web-token");a&&(n+=(n.includes("?")?"&":"?")+"token="+encodeURIComponent(a)),n+=(n.includes("?")?"&":"?")+"cols="+i.cols+"&rows="+i.rows,o=new WebSocket(n),o.onopen=()=>{k="connecting",z=0,G=!1,ge=[],V="",i.reset(),Q=1e3},o.onmessage=c=>{typeof c.data=="string"&&Ht(c.data)},o.onclose=()=>{A||(k="connecting",!ye&&setTimeout(()=>{Q=Math.min(Q*2,1e4),!A&&!ye&&Ve()},Q))},o.onerror=()=>o?.close()}function we(n){_({type:"input",data:n})}function F(){return i.fit()}function be(){e.classList.remove("terminal-pending")}function C(){r&&cancelAnimationFrame(r),d&&clearTimeout(d),F(),r=requestAnimationFrame(()=>{r=0,F()&&be()}),d=setTimeout(()=>{F()&&be()},120)}function Dt(){C(),setTimeout(C,50),setTimeout(C,150),setTimeout(C,300)}function Xe(n){return typeof n=="string"&&n.startsWith("image/")}function Je(n){return n?.files?.length?n.files[0]??null:null}function Rt(n){if(!n?.items)return null;for(let a=0;a<n.items.length;a++){let c=n.items[a];if(c?.kind==="file"&&Xe(c.type))return c.getAsFile()}return null}async function At(n){let a=new FormData,c=n instanceof File&&n.name?n.name:"upload";a.append("file",n,c);let p=localStorage.getItem("tmux-web-token"),b={};p&&(b.Authorization="Bearer "+p);let B=await fetch(Mt,{method:"POST",body:a,headers:b});if(!B.ok){let ae="upload failed";try{let it=await B.json();it.error&&(ae=it.error)}catch{}throw new Error(ae)}let j=await B.json();if(!j.path)throw new Error("no path in response");return j.path}async function Ne(n){try{let a=await At(n);we(a)}catch{}}i.onData(n=>we(n)),i.onResize(({cols:n,rows:a})=>_({type:"resize",cols:n,rows:a})),i.onScroll(()=>{k!=="live"||G||!i.isNearScrollbackTop()||(G=!0,_({type:"load_history",before:z}))});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 H=document.createElement("div");H.className="terminal-copy-banner terminal-copy-toast",H.textContent="Copied",H.hidden=!0,e.appendChild(H);function Ze(n,a){let c=e.querySelector(".xterm-screen, canvas"),p=(c&&c.getBoundingClientRect().width>0?c:e).getBoundingClientRect(),b=p.height>0&&i.rows>0?p.height/i.rows:18,B=p.width>0&&i.cols>0?p.width/i.cols:9;return{row:Math.max(0,Math.min(i.rows-1,Math.floor((a-p.top)/b))),col:Math.max(0,Math.min(i.cols-1,Math.floor((n-p.left)/B)))}}async function Le(n){if(!n)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(n);return}}catch{}let a=document.createElement("textarea");a.value=n,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 ie;function Ee(){H.hidden=!1,ie&&clearTimeout(ie),ie=setTimeout(()=>{H.hidden=!0},1e3)}function X(n){ee=n,ne.hidden=!n,e.classList.toggle("terminal-copy-mode-active",n),n&&i.focus()}function Ge(){X(!ee)}function $t(n){A||n.button!==0||te||(ee||n.shiftKey)&&(n.preventDefault(),n.stopPropagation(),te=!0,w=Ze(n.clientX,n.clientY),L=w,i.selectCells(w.col,w.row,L.col,L.row),document.addEventListener("mousemove",ze,!0),document.addEventListener("mouseup",_e,!0))}function ze(n){A||!te||!w||(n.preventDefault(),n.stopPropagation(),L=Ze(n.clientX,n.clientY),i.selectCells(w.col,w.row,L.col,L.row))}function _e(n){if(A||!te||!w||!L)return;n.preventDefault(),n.stopPropagation(),document.removeEventListener("mousemove",ze,!0),document.removeEventListener("mouseup",_e,!0),te=!1;let a=i.getCellsText(w.col,w.row,L.col,L.row);w=null,L=null,i.clearSelection(),X(!1),a&&(H.textContent="\u5DF2\u590D\u5236",Le(a).then(Ee)),i.focus()}e.addEventListener("mousedown",$t,!0),document.addEventListener("keydown",Pt,!0);function Pt(n){if(!(A||!i.isFocused()||n.defaultPrevented||n.isComposing)){if(ee){if(n.key==="Escape"){n.preventDefault(),n.stopPropagation(),w=null,L=null,i.clearSelection(),X(!1);return}if(n.key==="Enter"||(n.ctrlKey||n.metaKey)&&n.code==="KeyC"){n.preventDefault(),n.stopPropagation(),Le(i.getScreenText()).then(Ee),X(!1);return}}if(n.altKey&&n.code==="KeyC"&&!n.ctrlKey&&!n.metaKey){if(n.preventDefault(),n.stopPropagation(),w&&L){let a=i.getCellsText(w.col,w.row,L.col,L.row);w=null,L=null,i.clearSelection(),X(!1),a&&(H.textContent="Copied",Le(a).then(Ee))}else{let a=i.getSelection();a?(i.clearSelection(),H.textContent="Copied",Le(a).then(Ee)):Ge()}return}if((n.ctrlKey||n.metaKey)&&n.code==="KeyV"){n.preventDefault(),n.stopPropagation(),(async()=>{try{if(navigator.clipboard?.read){let a=await navigator.clipboard.read();for(let c of a)for(let p of c.types)if(Xe(p)){let b=await c.getType(p);await Ne(b);return}}}catch{}try{let a=await navigator.clipboard?.readText();a&&i.pasteText(Qe(a))}catch{}})();return}}}let xe=0;function Qe(n){return n.split(`\r
1
+ var Zt=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function je(e){return e.replace(/\x1b\[\?1049[hl]/g,"")}function oe(e){return e.replace(Zt,"")}var ke;function Gt(){return ke||(document.querySelector("link[data-tmux-web-xterm-css]")?ke=Promise.resolve():(ke=new Promise(e=>{let t=document.createElement("link");t.rel="stylesheet",t.href="/assets/xterm.css",t.setAttribute("data-tmux-web-xterm-css",""),t.addEventListener("load",()=>e(),{once:!0}),t.addEventListener("error",()=>e(),{once:!0}),document.head.appendChild(t)}),ke))}var Qt=class Ct{terminal;fitAddon;container;constructor(t,a,n){this.container=t,this.terminal=a,this.fitAddon=n,this.terminal.loadAddon(this.fitAddon),this.terminal.open(t)}static async create(t,a,n){let[{Terminal:o},{FitAddon:r}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),Gt()]),u=new o({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:a,convertEol:!1,smoothScrollDuration:120,theme:n});return new Ct(t,u,new r)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(t){return new Promise(a=>this.terminal.write(t,a))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(t,a=!1){this.terminal.scrollToLine(Math.max(0,t),a)}scrollLines(t){let a=this.terminal.buffer?.active;this.terminal.scrollLines(t)}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){let t=en(this.container);return t.width<=0||t.height<=0?!1:(this.fitAddon.fit(),!0)}focus(){this.terminal.focus()}pasteText(t){this.terminal.paste(t)}input(t){this.terminal.input(t,!1)}onData(t){this.terminal.onData(t),this.terminal.onBinary(t)}onResize(t){this.terminal.onResize(t)}onScroll(t){this.terminal.onScroll(t)}attachCustomKeyEventHandler(t){this.terminal.attachCustomKeyEventHandler(t)}isFocused(){let t=document.activeElement;return t?t===this.container||t===this.terminal.textarea||this.container.contains(t)||!!t.closest?.(".xterm"):!1}getScreenText(){return this.getRowsText(0,this.terminal.rows-1)}getRowsText(t,a){let n=this.terminal.buffer.active,[o,r]=t<=a?[t,a]:[a,t],u=n.viewportY,l=[];for(let c=o;c<=r;c++){let p=n.getLine(u+c);l.push(p?p.translateToString(!0):"")}return l.join(`
2
+ `)}selectRows(t,a){let n=this.terminal.buffer.active,[o,r]=t<=a?[t,a]:[a,t];this.terminal.selectLines(n.viewportY+o,n.viewportY+r)}selectCells(t,a,n,o){let r=this.terminal.buffer.active,u=Math.min(a,o),l=Math.max(a,o);if(u===l){let c=Math.min(t,n),p=Math.max(t,n);this.terminal.select(c,r.viewportY+u,p-c+1)}else this.terminal.selectLines(r.viewportY+u,r.viewportY+l)}getCellsText(t,a,n,o){let r=this.terminal.buffer.active,u=Math.min(a,o),l=Math.max(a,o),c=a<o?t:a>o?n:Math.min(t,n),p=a<o?n:a>o?t:Math.max(t,n),L=r.viewportY,D=[];for(let z=u;z<=l;z++){let he=r.getLine(L+z);if(!he){D.push("");continue}let U=z===u?c:0,Ne=z===l?p:this.terminal.cols-1,K="";for(let C=U;C<=Ne;C++){let _=he.getCell(C);_&&(K+=_.getChars())}D.push(K.replace(/\s+$/,""))}return D.join(`
3
+ `)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}};function en(e){let t=e.getBoundingClientRect(),a=window.visualViewport;return a?{width:Math.min(t.width,a.width),height:Math.max(0,Math.min(t.height,a.height-Math.max(0,t.top)))}:t}function tn(e,t,a){return e.innerHTML="",e.classList.add("terminal-pending"),(async()=>{let n=await Qt.create(e,a.scrollback,a.theme),o,r=0,u,l=null,c=0,p=0,L=.2,D=10,z=.95,he=.04;function U(){c&&(cancelAnimationFrame(c),c=0),p=0}function Ne(i){if(U(),Math.abs(i)<L)return;p=Math.max(-D,Math.min(D,i));let s=()=>{if(A){c=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 S=n.viewportY()-b,Y=n.baseY(),se=Math.max(0,Math.min(S,Y));if(n.scrollToLine(se,!0),p*=z,se!==S){c=0;return}if(Math.abs(p)<he){c=0;return}c=requestAnimationFrame(s)};c=requestAnimationFrame(s)}let K=0,C="connecting",_=0,G=!1,ge=[],V="",A=!1,Q=1e3,Tt=location.protocol==="https:"?"wss:":"ws:",Mt=a.wsBase||"/ws",Bt=Tt+"//"+location.host+Mt+"/"+encodeURIComponent(t),St="/api/session/"+encodeURIComponent(t)+"/upload",It=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function Ht(){return ge.join("")+V}async function Dt(i,s=0){let d=i?n.viewportY():0,f=oe(Ht());if(n.reset(),!f){i||n.scrollToBottom();return}await n.write(f),i?n.scrollToLine(s+d):n.scrollToBottom()}function j(i){o?.readyState===WebSocket.OPEN&&o.send(JSON.stringify(i))}function Rt(i){let s;try{s=JSON.parse(i)}catch{C==="live"&&(V+=i,n.write(oe(i)));return}if(s.type==="auth.required"){let d=localStorage.getItem("tmux-web-token");d?j({type:"auth.token",token:d}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(s.type==="attach_failed"&&typeof s.message=="string"){ye=!0,C="dead",n.reset(),n.write(`\r
4
+ \x1B[31m`+oe(s.message)+`\x1B[0m\r
5
+ `).then(()=>{be();try{o?.close()}catch{}});return}if(s.type==="auth.ok"){s.token&&localStorage.setItem("tmux-web-token",s.token),Q=1e3,F(),j({type:"resize",cols:n.cols,rows:n.rows}),T();return}if(s.type==="auth.failed"){if(s.permanentLock||s.retryAfterMs&&s.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(s.message);return}return}if(s.type==="snapshot"&&typeof s.data=="string"){let d=je(oe(s.data));ge=[d],V="",_=typeof s.lines=="number"?s.lines:a.terminal.initialLines,C="live",n.reset(),F(),j({type:"resize",cols:n.cols,rows:n.rows}),n.write(d).then(()=>n.scrollToBottom());return}if(s.type==="window_changed"&&typeof s.activeIndex=="number"){let d=new URL(location.href);d.searchParams.get("window")!==String(s.activeIndex)&&(d.searchParams.set("window",String(s.activeIndex)),history.replaceState(history.state,"",d)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:s.windows}));return}if(s.type==="history"&&typeof s.data=="string"){s.lines>0&&s.data?(ge.unshift(je(s.data)),_+=s.lines,Dt(!0,s.lines).finally(()=>{G=!1})):G=!1;return}if(s.type==="data"&&typeof s.data=="string"){let d=je(oe(s.data));if(C==="connecting"){C="live",V=d,n.write(d);return}C==="live"&&(V+=d,n.write(d))}}let ye=!1;function Ve(){if(ye)return;let i=Bt,s=localStorage.getItem("tmux-web-token");s&&(i+=(i.includes("?")?"&":"?")+"token="+encodeURIComponent(s)),i+=(i.includes("?")?"&":"?")+"cols="+n.cols+"&rows="+n.rows,o=new WebSocket(i),o.onopen=()=>{C="connecting",_=0,G=!1,ge=[],V="",n.reset(),Q=1e3},o.onmessage=d=>{typeof d.data=="string"&&Rt(d.data)},o.onclose=()=>{A||(C="connecting",!ye&&setTimeout(()=>{Q=Math.min(Q*2,1e4),!A&&!ye&&Ve()},Q))},o.onerror=()=>o?.close()}function we(i){j({type:"input",data:i})}function F(){return n.fit()}function be(){e.classList.remove("terminal-pending")}function T(){r&&cancelAnimationFrame(r),u&&clearTimeout(u),F(),r=requestAnimationFrame(()=>{r=0,F()&&be()}),u=setTimeout(()=>{F()&&be()},120)}function $t(){T(),setTimeout(T,50),setTimeout(T,150),setTimeout(T,300)}function Xe(i){return typeof i=="string"&&i.startsWith("image/")}function Je(i){return i?.files?.length?i.files[0]??null:null}function At(i){if(!i?.items)return null;for(let s=0;s<i.items.length;s++){let d=i.items[s];if(d?.kind==="file"&&Xe(d.type))return d.getAsFile()}return null}async function Nt(i){let s=new FormData,d=i instanceof File&&i.name?i.name:"upload";s.append("file",i,d);let f=localStorage.getItem("tmux-web-token"),b={};f&&(b.Authorization="Bearer "+f);let S=await fetch(St,{method:"POST",body:s,headers:b});if(!S.ok){let se="upload failed";try{let it=await S.json();it.error&&(se=it.error)}catch{}throw new Error(se)}let Y=await S.json();if(!Y.path)throw new Error("no path in response");return Y.path}async function Pe(i){try{let s=await Nt(i);we(s)}catch{}}n.onData(i=>we(i)),n.onResize(({cols:i,rows:s})=>j({type:"resize",cols:i,rows:s})),n.onScroll(()=>{C!=="live"||G||!n.isNearScrollbackTop()||(G=!0,j({type:"load_history",before:_}))});let ee=!1,te=!1,w=null,E=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 Ze(i,s){let d=e.querySelector(".xterm-screen, canvas"),f=(d&&d.getBoundingClientRect().width>0?d:e).getBoundingClientRect(),b=f.height>0&&n.rows>0?f.height/n.rows:18,S=f.width>0&&n.cols>0?f.width/n.cols:9;return{row:Math.max(0,Math.min(n.rows-1,Math.floor((s-f.top)/b))),col:Math.max(0,Math.min(n.cols-1,Math.floor((i-f.left)/S)))}}async function Le(i){if(!i)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(i);return}}catch{}let s=document.createElement("textarea");s.value=i,s.style.position="fixed",s.style.opacity="0",s.style.pointerEvents="none",document.body.appendChild(s),s.focus(),s.select();try{document.execCommand("copy")}catch{}s.remove()}let ie;function Ee(){R.hidden=!1,ie&&clearTimeout(ie),ie=setTimeout(()=>{R.hidden=!0},1e3)}function X(i){ee=i,ne.hidden=!i,e.classList.toggle("terminal-copy-mode-active",i),i&&n.focus()}function Ge(){X(!ee)}function Pt(i){A||i.button!==0||te||(ee||i.shiftKey)&&(i.preventDefault(),i.stopPropagation(),te=!0,w=Ze(i.clientX,i.clientY),E=w,n.selectCells(w.col,w.row,E.col,E.row),document.addEventListener("mousemove",ze,!0),document.addEventListener("mouseup",_e,!0))}function ze(i){A||!te||!w||(i.preventDefault(),i.stopPropagation(),E=Ze(i.clientX,i.clientY),n.selectCells(w.col,w.row,E.col,E.row))}function _e(i){if(A||!te||!w||!E)return;i.preventDefault(),i.stopPropagation(),document.removeEventListener("mousemove",ze,!0),document.removeEventListener("mouseup",_e,!0),te=!1;let s=n.getCellsText(w.col,w.row,E.col,E.row);w=null,E=null,n.clearSelection(),X(!1),s&&(R.textContent="\u5DF2\u590D\u5236",Le(s).then(Ee)),n.focus()}e.addEventListener("mousedown",Pt,!0),document.addEventListener("keydown",zt,!0);function zt(i){if(!(A||!n.isFocused()||i.defaultPrevented||i.isComposing)){if(ee){if(i.key==="Escape"){i.preventDefault(),i.stopPropagation(),w=null,E=null,n.clearSelection(),X(!1);return}if(i.key==="Enter"||(i.ctrlKey||i.metaKey)&&i.code==="KeyC"){i.preventDefault(),i.stopPropagation(),Le(n.getScreenText()).then(Ee),X(!1);return}}if(i.altKey&&i.code==="KeyC"&&!i.ctrlKey&&!i.metaKey){if(i.preventDefault(),i.stopPropagation(),w&&E){let s=n.getCellsText(w.col,w.row,E.col,E.row);w=null,E=null,n.clearSelection(),X(!1),s&&(R.textContent="Copied",Le(s).then(Ee))}else{let s=n.getSelection();s?(n.clearSelection(),R.textContent="Copied",Le(s).then(Ee)):Ge()}return}if((i.ctrlKey||i.metaKey)&&i.code==="KeyV"){i.preventDefault(),i.stopPropagation(),(async()=>{try{if(navigator.clipboard?.read){let s=await navigator.clipboard.read();for(let d of s)for(let f of d.types)if(Xe(f)){let b=await d.getType(f);await Pe(b);return}}}catch{}try{let s=await navigator.clipboard?.readText();s&&n.pasteText(Qe(s))}catch{}})();return}}}let xe=0;function Qe(i){return i.split(`\r
6
6
  `).join(`
7
7
  `).split(`
8
- `).join("\r")}async function Nt(n){let a=Rt(n.clipboardData);if(a){n.preventDefault(),n.stopPropagation();let b=Date.now();if(b-xe<50)return;xe=b,await Ne(a);return}let c=n.clipboardData?.getData("text/plain");if(!c)return;n.preventDefault(),n.stopPropagation();let p=Date.now();p-xe<50||(xe=p,i.pasteText(Qe(c)))}let se=0;function zt(n){n.preventDefault(),se++,Je(n.dataTransfer)&&e.classList.add("terminal-drag-over")}function _t(n){n.preventDefault(),n.dataTransfer&&(n.dataTransfer.dropEffect="copy")}function Ft(n){n.preventDefault(),se--,se<=0&&(se=0,e.classList.remove("terminal-drag-over"))}async function jt(n){n.preventDefault(),se=0,e.classList.remove("terminal-drag-over");let a=Je(n.dataTransfer);a&&await Ne(a)}function et(n){!Bt||n.key!=="Escape"||ee||n.defaultPrevented||n.repeat||n.metaKey||n.ctrlKey||n.altKey||i.isFocused()&&(n.preventDefault(),n.stopPropagation(),we("\x1B"))}e.addEventListener("paste",Nt),e.addEventListener("dragenter",zt),e.addEventListener("dragover",_t),e.addEventListener("dragleave",Ft),e.addEventListener("drop",jt),document.addEventListener("keydown",et,!0);function Yt(n){if(n.touches.length!==1){l=null;return}let a=n.touches[0];a&&(O(),l={startX:a.clientX,startY:a.clientY,lastX:a.clientX,lastY:a.clientY,lastT:performance.now(),velocity:0,scrolling:!1},n.stopPropagation())}function Ut(n){if(!l||n.touches.length!==1)return;let a=n.touches[0];if(!a)return;let c=a.clientY-l.startY,p=a.clientX-l.startX;if(!l.scrolling){if(Math.abs(c)<8||Math.abs(c)<Math.abs(p))return;l.scrolling=!0,K=Date.now()+500}n.preventDefault(),n.stopPropagation();let b=performance.now(),B=a.clientY-l.lastY,j=b-l.lastT;j>0&&(l.velocity=B/j),Kt(-B),l.lastX=a.clientX,l.lastY=a.clientY,l.lastT=b}function Wt(n){if(!l)return;let a=l.scrolling,c=l.velocity;if(l=null,n.stopPropagation(),!a){i.focus();return}K=Date.now()+500,n.preventDefault(),c&&Pe(c)}function qt(n){l=null,O(),n.stopPropagation()}function Ot(n){n.pointerType==="touch"&&Date.now()<K&&(n.preventDefault(),n.stopPropagation())}function Kt(n){let a=e.querySelector(".xterm-rows > div"),c=a?a.getBoundingClientRect().height:16,p=c>0?Math.round(n/c):n>0?1:-1;p===0&&(p=n>0?1:-1),i.scrollLines(p)}e.addEventListener("touchstart",Yt,{passive:!0,capture:!0}),e.addEventListener("touchmove",Ut,{passive:!1,capture:!0}),e.addEventListener("touchend",Wt,{passive:!1,capture:!0}),e.addEventListener("touchcancel",qt,{passive:!0,capture:!0}),e.addEventListener("pointerup",Ot,!0);function tt(){C()}window.addEventListener("resize",tt),window.visualViewport?.addEventListener("resize",C),window.visualViewport?.addEventListener("scroll",C);let nt=new ResizeObserver(()=>C());nt.observe(e),document.fonts?.ready.then(()=>{C(),setTimeout(C,50),setTimeout(C,200)}),e.addEventListener("focusin",Dt,!0);async function Vt(){if(document.fonts?.ready)try{await Promise.race([document.fonts.ready,new Promise(n=>setTimeout(n,1e3))])}catch{}}return requestAnimationFrame(()=>{F()&&be(),(async()=>(await Vt(),F()&&_({type:"resize",cols:i.cols,rows:i.rows}),Ve(),C()))()}),{destroy(){if(A=!0,O(),X(!1),ie&&clearTimeout(ie),document.removeEventListener("mousemove",ze,!0),document.removeEventListener("mouseup",_e,!0),o){try{o.close(1e3,"session switch")}catch{}o=void 0}e.innerHTML="",e.classList.remove("terminal-pending"),window.removeEventListener("resize",tt),nt.disconnect(),document.removeEventListener("keydown",et,!0)},focus(){i.focus()},sendInput(n){we(n)},toggleCopyMode(){Ge()}}})()}var le=window.__TMUX_WEB_SHELL__,h=null,y=null,st=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null,x=st;window.__tmuxWebScopeAgent=st;var je="sessions",$="",Ce="",Te="",at="";function T(e){return x?"/a/"+encodeURIComponent(x)+e:e}var v=document.getElementById("sidebar-content"),Y=document.getElementById("main-placeholder"),M=document.getElementById("terminal-container"),re=document.getElementById("file-editor"),en=document.getElementById("fe-path"),I=document.getElementById("fe-status"),ce=document.getElementById("fe-content"),U=document.getElementById("fe-save"),tn=document.getElementById("fe-delete"),nn=document.getElementById("fe-back"),ot=document.getElementById("fe-new-name"),sn=document.getElementById("fe-new-btn"),Ye=document.getElementById("settings-backdrop"),lt=document.getElementById("settings-popover"),rt=document.querySelector(".sidebar");function an(){return window.matchMedia("(max-width: 640px)").matches}function Ue(){an()&&rt.classList.add("collapsed")}function ct(){rt.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{ct(),dt("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{ct(),dt("files")});function dt(e){je=e,document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));let t=document.getElementById(e==="sessions"?"mode-sessions":"mode-files");t&&t.classList.add("active"),e==="sessions"?(We="",J()):vn()}var We="";async function J(){if(je!=="sessions")return;try{let t=await(await fetch("/api/sidebar/sessions")).json(),s=JSON.stringify({recent:t.recent,agents:t.agents});if(s===We)return;We=s,on(t)}catch{v.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")})}function on(e){v.innerHTML='<button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';let t=e.recent||[],s=document.createElement("div");s.className="sidebar-section-label"+(x?" clickable":""),s.textContent=x?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",x&&(s.title="Back to hub",s.addEventListener("click",()=>{window.location.href="/"})),v.appendChild(s);for(let o of t){let r=document.createElement("div");r.className="session-item"+(o.name===y&&!x?" active":""),r.setAttribute("data-session",o.name),r.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${o.attached?"M19 4H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zm0 14H5V6h14v12z":"M4 6h16v2H4V6zm0 5h16v2H4v-2zm0 5h16v2H4v-2z"}"></svg>
9
- <span>${m(o.name)}</span>
10
- <button class="session-edit-btn" data-session="${m(o.name)}" title="Edit session"><svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg></button>
11
- `,r.addEventListener("click",l=>{l.target.closest(".session-edit-btn")||de(o.name)}),v.appendChild(r);let d=r.querySelector(".session-edit-btn");d&&d.addEventListener("click",l=>{l.stopPropagation(),bn(o.name,d)})}let i=e.agents||[];for(let o of i){if(!o.sessions||o.sessions.length===0)continue;let r=o.agentId===x,d=document.createElement("div");d.className="sidebar-section-label machine-label"+(o.online?"":" agent-offline-label")+(!r&&o.online?" clickable":""),d.textContent=o.agentName+(o.online?"":" (offline)"),!r&&o.online&&(d.title="\u6253\u5F00 "+o.agentName,d.addEventListener("click",()=>{window.location.href="/a/"+encodeURIComponent(o.agentId)+"/"})),v.appendChild(d);for(let l of o.sessions){let u=document.createElement("div");u.className="session-item"+(l.name===y&&x===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>${m(l.name)}</span><span class="meta">${o.online?"":"offline"}</span>`,o.online&&u.addEventListener("click",f=>{f.target.closest(".session-edit-btn")||de(l.name,o.agentId)}),v.appendChild(u)}}}function m(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function de(e,t){if(!(y===e&&h&&x===(t||null))){re.style.display="none",Y.style.display="none",M.style.display="",M.classList.add("terminal-pending"),Ue(),h&&(Ae(),h.destroy(),h=null),y=e,x=t||null,window.__tmuxWebScopeAgent=x,window.__tmuxWebCurrentSession=y;for(let s of v.querySelectorAll(".session-item"))s.classList.toggle("active",s.getAttribute("data-session")===e&&(s.getAttribute("data-agent")||null)===x);try{h=await Qt(M,e,{terminal:le.terminal,scrollback:le.scrollback,theme:le.theme,wsBase:x?"/ws/a/"+encodeURIComponent(x):le.wsBase||"/ws"}),bt()}catch(s){console.error("[shell] terminal init failed:",s);let i=s&&typeof s=="object"&&"message"in s?s.message:String(s);M.textContent="Failed to open terminal for "+e+": "+i,M.classList.remove("terminal-pending")}}}var Me=[],g=null,ut=!1;function ln(e){if(!g||!g.files.length)return null;let t=g.repoRoot;if(!t||!e.startsWith(t))return null;let s=e.slice(t.length+1);for(let i of g.files)if(i.path===s)return i.status;return null}async function rn(e){ut=!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{ut=!1}}function cn(){if(!g||!g.branch)return"";let{branch:e,linesAdded:t,linesRemoved:s}=g,i=`<div class="sidebar-git"><div class="git-branch-badge">
8
+ `).join("\r")}async function _t(i){let s=At(i.clipboardData);if(s){i.preventDefault(),i.stopPropagation();let b=Date.now();if(b-xe<50)return;xe=b,await Pe(s);return}let d=i.clipboardData?.getData("text/plain");if(!d)return;i.preventDefault(),i.stopPropagation();let f=Date.now();f-xe<50||(xe=f,n.pasteText(Qe(d)))}let ae=0;function jt(i){i.preventDefault(),ae++,Je(i.dataTransfer)&&e.classList.add("terminal-drag-over")}function Ft(i){i.preventDefault(),i.dataTransfer&&(i.dataTransfer.dropEffect="copy")}function Yt(i){i.preventDefault(),ae--,ae<=0&&(ae=0,e.classList.remove("terminal-drag-over"))}async function Wt(i){i.preventDefault(),ae=0,e.classList.remove("terminal-drag-over");let s=Je(i.dataTransfer);s&&await Pe(s)}function et(i){!It||i.key!=="Escape"||ee||i.defaultPrevented||i.repeat||i.metaKey||i.ctrlKey||i.altKey||n.isFocused()&&(i.preventDefault(),i.stopPropagation(),we("\x1B"))}e.addEventListener("paste",_t),e.addEventListener("dragenter",jt),e.addEventListener("dragover",Ft),e.addEventListener("dragleave",Yt),e.addEventListener("drop",Wt),document.addEventListener("keydown",et,!0);function qt(i){if(i.touches.length!==1){l=null;return}let s=i.touches[0];s&&(U(),l={startX:s.clientX,startY:s.clientY,lastX:s.clientX,lastY:s.clientY,lastT:performance.now(),velocity:0,scrolling:!1},i.stopPropagation())}function Ot(i){if(!l||i.touches.length!==1)return;let s=i.touches[0];if(!s)return;let d=s.clientY-l.startY,f=s.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(),S=s.clientY-l.lastY,Y=b-l.lastT;Y>0&&(l.velocity=S/Y),Xt(-S),l.lastX=s.clientX,l.lastY=s.clientY,l.lastT=b}function Ut(i){if(!l)return;let s=l.scrolling,d=l.velocity;if(l=null,i.stopPropagation(),!s){n.focus();return}K=Date.now()+500,i.preventDefault(),d&&Ne(d)}function Kt(i){l=null,U(),i.stopPropagation()}function Vt(i){i.pointerType==="touch"&&Date.now()<K&&(i.preventDefault(),i.stopPropagation())}function Xt(i){let s=e.querySelector(".xterm-rows > div"),d=s?s.getBoundingClientRect().height:16,f=d>0?Math.round(i/d):i>0?1:-1;f===0&&(f=i>0?1:-1),n.scrollLines(f)}e.addEventListener("touchstart",qt,{passive:!0,capture:!0}),e.addEventListener("touchmove",Ot,{passive:!1,capture:!0}),e.addEventListener("touchend",Ut,{passive:!1,capture:!0}),e.addEventListener("touchcancel",Kt,{passive:!0,capture:!0}),e.addEventListener("pointerup",Vt,!0);function tt(){T()}window.addEventListener("resize",tt),window.visualViewport?.addEventListener("resize",T),window.visualViewport?.addEventListener("scroll",T);let nt=new ResizeObserver(()=>T());nt.observe(e),document.fonts?.ready.then(()=>{T(),setTimeout(T,50),setTimeout(T,200)}),e.addEventListener("focusin",$t,!0);async function Jt(){if(document.fonts?.ready)try{await Promise.race([document.fonts.ready,new Promise(i=>setTimeout(i,1e3))])}catch{}}return requestAnimationFrame(()=>{F()&&be(),(async()=>(await Jt(),F()&&j({type:"resize",cols:n.cols,rows:n.rows}),Ve(),T()))()}),{destroy(){if(A=!0,U(),X(!1),ie&&clearTimeout(ie),document.removeEventListener("mousemove",ze,!0),document.removeEventListener("mouseup",_e,!0),o){try{o.close(1e3,"session switch")}catch{}o=void 0}e.innerHTML="",e.classList.remove("terminal-pending"),window.removeEventListener("resize",tt),nt.disconnect(),document.removeEventListener("keydown",et,!0)},focus(){n.focus()},sendInput(i){we(i)},toggleCopyMode(){Ge()}}})()}var le=window.__TMUX_WEB_SHELL__,h=null,y=null,at=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null,k=at;window.__tmuxWebScopeAgent=at;var Fe="sessions",N="",Ce="",Te="",st="";function M(e){return k?"/a/"+encodeURIComponent(k)+e:e}var v=document.getElementById("sidebar-content"),W=document.getElementById("main-placeholder"),B=document.getElementById("terminal-container"),re=document.getElementById("file-editor"),nn=document.getElementById("fe-path"),I=document.getElementById("fe-status"),ce=document.getElementById("fe-content"),q=document.getElementById("fe-save"),an=document.getElementById("fe-delete"),sn=document.getElementById("fe-back"),ot=document.getElementById("fe-new-name"),on=document.getElementById("fe-new-btn"),Ye=document.getElementById("settings-backdrop"),lt=document.getElementById("settings-popover"),rt=document.querySelector(".sidebar");function ln(){return window.matchMedia("(max-width: 640px)").matches}function We(){ln()&&rt.classList.add("collapsed")}function ct(){rt.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{ct(),dt("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{ct(),dt("files")});function dt(e){Fe=e,document.querySelectorAll(".mode-btn").forEach(a=>a.classList.remove("active"));let t=document.getElementById(e==="sessions"?"mode-sessions":"mode-files");t&&t.classList.add("active"),e==="sessions"?(qe="",J()):Ln()}var qe="";async function J(){if(Fe!=="sessions")return;try{let t=await(await fetch("/api/sidebar/sessions")).json(),a=JSON.stringify({recent:t.recent,agents:t.agents});if(a===qe)return;qe=a,pn(t)}catch{v.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")})}var ut="tmux-web-sidebar-group-collapsed";function pt(){try{return new Set(JSON.parse(localStorage.getItem(ut)||"[]"))}catch{return new Set}}function rn(e){try{localStorage.setItem(ut,JSON.stringify([...e]))}catch{}}function cn(e,t){if(!e)return"\u2026";let a=e.split("/").filter(Boolean);if(a.length===0)return e;for(let n=2;n<=a.length;n++){let o=a.slice(-n).join("/");if(!t.some(r=>r&&r!==e&&r.split("/").filter(Boolean).slice(-n).join("/")===o))return"\u2026/"+o}return e}function dn(e){let t=new Map;for(let o of e){let r=o.path||"";t.has(r)||t.set(r,[]),t.get(r).push(o)}let a=[...t.keys()],n=pt();for(let[o,r]of t){let u=cn(o,a),l=n.has(o),c=document.createElement("div");c.className="session-group-header"+(l?" collapsed":""),c.title=o||"No working directory",c.innerHTML=`<span class="sg-folder">&#128193;</span><span class="sg-label">${m(u)}</span><span class="sg-count">${r.length}</span><span class="sg-arrow">${l?"\u25B8":"\u25BE"}</span>`,c.addEventListener("click",()=>{let L=pt(),D=c.nextElementSibling;L.has(o)?(L.delete(o),c.classList.remove("collapsed"),D?.classList.remove("collapsed"),c.querySelector(".sg-arrow").textContent="\u25BE"):(L.add(o),c.classList.add("collapsed"),D?.classList.add("collapsed"),c.querySelector(".sg-arrow").textContent="\u25B8"),rn(L)});let p=document.createElement("div");p.className="session-group-body"+(l?" collapsed":"");for(let L of r)p.appendChild(un(L));v.appendChild(c),v.appendChild(p)}}function un(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
+ <span>${m(e.name)}</span>
10
+ <button class="session-edit-btn" data-session="${m(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
+ `,t.addEventListener("click",n=>{n.target.closest(".session-edit-btn")||de(e.name)});let a=t.querySelector(".session-edit-btn");return a&&a.addEventListener("click",n=>{n.stopPropagation(),Tn(e.name,a)}),t}function pn(e){v.innerHTML='<button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';let t=e.recent||[],a=document.createElement("div");a.className="sidebar-section-label"+(k?" clickable":""),a.textContent=k?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",k&&(a.title="Back to hub",a.addEventListener("click",()=>{window.location.href="/"})),v.appendChild(a),dn(t);let n=e.agents||[];for(let o of n){if(!o.sessions||o.sessions.length===0)continue;let r=o.agentId===k,u=document.createElement("div");u.className="sidebar-section-label machine-label"+(o.online?"":" agent-offline-label")+(!r&&o.online?" clickable":""),u.textContent=o.agentName+(o.online?"":" (offline)"),!r&&o.online&&(u.title="\u6253\u5F00 "+o.agentName,u.addEventListener("click",()=>{window.location.href="/a/"+encodeURIComponent(o.agentId)+"/"})),v.appendChild(u);for(let l of o.sessions){let c=document.createElement("div");c.className="session-item"+(l.name===y&&k===o.agentId?" active":"")+(o.online?"":" session-offline"),c.setAttribute("data-session",l.name),c.setAttribute("data-agent",o.agentId),c.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>${m(l.name)}</span><span class="meta">${o.online?"":"offline"}</span>`,o.online&&c.addEventListener("click",p=>{p.target.closest(".session-edit-btn")||de(l.name,o.agentId)}),v.appendChild(c)}}}function m(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function de(e,t){if(!(y===e&&h&&k===(t||null))){re.style.display="none",W.style.display="none",B.style.display="",B.classList.add("terminal-pending"),We(),h&&($e(),h.destroy(),h=null),y=e,k=t||null,window.__tmuxWebScopeAgent=k,window.__tmuxWebCurrentSession=y;for(let a of v.querySelectorAll(".session-item"))a.classList.toggle("active",a.getAttribute("data-session")===e&&(a.getAttribute("data-agent")||null)===k);try{h=await tn(B,e,{terminal:le.terminal,scrollback:le.scrollback,theme:le.theme,wsBase:k?"/ws/a/"+encodeURIComponent(k):le.wsBase||"/ws"}),Et()}catch(a){console.error("[shell] terminal init failed:",a);let n=a&&typeof a=="object"&&"message"in a?a.message:String(a);B.textContent="Failed to open terminal for "+e+": "+n,B.classList.remove("terminal-pending")}}}var Me=[],g=null,ft=!1;function fn(e){if(!g||!g.files.length)return null;let t=g.repoRoot;if(!t||!e.startsWith(t))return null;let a=e.slice(t.length+1);for(let n of g.files)if(n.path===a)return n.status;return null}async function mn(e){ft=!0;try{let t=await fetch(M("/api/git/status?path="+encodeURIComponent(e)));t.ok?g=await t.json():g=null}catch{g=null}finally{ft=!1}}function vn(){if(!g||!g.branch)return"";let{branch:e,linesAdded:t,linesRemoved:a}=g,n=`<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
- ${m(e)}</div>`;return(t>0||s>0)&&(i+=`<div class="git-diff-stats">+<span class="add">${t}</span> <span class="del">-${s}</span></div>`),i+"</div>"}v.addEventListener("click",e=>{e.target.closest(".sidebar-git")&&Z&&g&&(e.stopPropagation(),ht())});var ue=document.getElementById("header-git"),pt=document.getElementById("git-diff-view"),ft=document.getElementById("gd-path"),Be=document.getElementById("gd-status"),Ie=document.getElementById("gd-content"),dn=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:s,linesRemoved:i}=e,o=`<span class="branch">${m(t)}</span>`;(s>0||i>0)&&(o+=`<span class="sep">\xB7</span>+<span class="diff-add">${s}</span> <span class="diff-del">-${i}</span>`),ue.innerHTML=o,ue.style.display="block"}ue.addEventListener("click",e=>{Z&&g&&(e.stopPropagation(),ht())});var E=document.getElementById("git-popover"),Se=document.getElementById("git-popover-backdrop");function qe(){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 mt(){let e=Z,t=document.getElementById("git-popover-browse");t&&t.addEventListener("click",()=>{if(De(),e){je="files",document.querySelectorAll(".mode-btn").forEach(i=>i.classList.remove("active"));let s=document.getElementById("mode-files");s&&s.classList.add("active"),P(e)}})}var vt="";function ht(){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
- <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 s=0;s<e.length;s++){let i=e[s],o=i.additions||0,r=i.deletions||0,d="";switch(i.status){case"M":d='<span class="git-file-status M">M</span>';break;case"A":d='<span class="git-file-status A">A</span>';break;case"D":d='<span class="git-file-status D">D</span>';break;case"?":d='<span class="git-file-status ?">?</span>';break;case"R":d='<span class="git-file-status R">R</span>';break}t+=`<div class="git-popover-item" data-idx="${s}">
16
- ${d}<span class="file-path">${m(i.path)}</span>
14
+ ${m(e)}</div>`;return(t>0||a>0)&&(n+=`<div class="git-diff-stats">+<span class="add">${t}</span> <span class="del">-${a}</span></div>`),n+"</div>"}v.addEventListener("click",e=>{e.target.closest(".sidebar-git")&&Z&&g&&(e.stopPropagation(),yt())});var ue=document.getElementById("header-git"),mt=document.getElementById("git-diff-view"),vt=document.getElementById("gd-path"),Be=document.getElementById("gd-status"),Se=document.getElementById("gd-content"),hn=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:a,linesRemoved:n}=e,o=`<span class="branch">${m(t)}</span>`;(a>0||n>0)&&(o+=`<span class="sep">\xB7</span>+<span class="diff-add">${a}</span> <span class="diff-del">-${n}</span>`),ue.innerHTML=o,ue.style.display="block"}ue.addEventListener("click",e=>{Z&&g&&(e.stopPropagation(),yt())});var x=document.getElementById("git-popover"),Ie=document.getElementById("git-popover-backdrop");function Oe(){let e=ue.getBoundingClientRect();x.style.top=e.bottom+4+"px",x.style.left=Math.max(8,Math.min(e.left,window.innerWidth-400))+"px"}function ht(){let e=Z,t=document.getElementById("git-popover-browse");t&&t.addEventListener("click",()=>{if(De(),e){Fe="files",document.querySelectorAll(".mode-btn").forEach(n=>n.classList.remove("active"));let a=document.getElementById("mode-files");a&&a.classList.add("active"),P(e)}})}var gt="";function yt(){if(!g)return;let e=g.files||[];if(!e.length)x.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
15
+ <div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>`;else{let t=`<div class="git-popover-header">${e.length} file${e.length>1?"s":""} changed</div>`;for(let a=0;a<e.length;a++){let n=e[a],o=n.additions||0,r=n.deletions||0,u="";switch(n.status){case"M":u='<span class="git-file-status M">M</span>';break;case"A":u='<span class="git-file-status A">A</span>';break;case"D":u='<span class="git-file-status D">D</span>';break;case"?":u='<span class="git-file-status ?">?</span>';break;case"R":u='<span class="git-file-status R">R</span>';break}t+=`<div class="git-popover-item" data-idx="${a}">
16
+ ${u}<span class="file-path">${m(n.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>',vt=t,E.innerHTML=t,E.querySelectorAll(".git-popover-item").forEach(s=>{let i=parseInt(s.dataset.idx||"0",10),o=e[i];!o||o.status==="D"||(s.classList.add("clickable"),s.style.cursor="pointer",s.addEventListener("click",()=>yt(o.path)))})}qe(),E.classList.add("open"),Se.classList.add("open"),mt()}function un(){return window.innerWidth>=1024}function gt(e,t){let s=(e+(t&&e?`
19
+ </div>`}t+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',gt=t,x.innerHTML=t,x.querySelectorAll(".git-popover-item").forEach(a=>{let n=parseInt(a.dataset.idx||"0",10),o=e[n];!o||o.status==="D"||(a.classList.add("clickable"),a.style.cursor="pointer",a.addEventListener("click",()=>bt(o.path)))})}Oe(),x.classList.add("open"),Ie.classList.add("open"),ht()}function gn(){return window.innerWidth>=1024}function wt(e,t){let a=(e+(t&&e?`
20
20
  `:"")+t).split(`
21
- `),i="",o=0,r=0;for(let d of s){let l=d;if(l.startsWith("@@")){let u=l.match(/@@\s+-(\d+)[^+]*\+(\d+)/);u&&(o=parseInt(u[1],10)-1,r=parseInt(u[2],10)-1),i+=`<div class="diff-line hunk"><span class="ln-body">${m(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">${m(l)}</span></div>`);continue}if(l.startsWith("+"))r++,i+=`<div class="diff-line add"><span class="ln-no">${r}</span><span class="ln-body">${m(l)}</span></div>`;else if(l.startsWith("-"))o++,i+=`<div class="diff-line del"><span class="ln-no">${o}</span><span class="ln-body">${m(l)}</span></div>`;else if(l.startsWith("\\"))i+=`<div class="diff-line"><span class="ln-body">${m(l)}</span></div>`;else{if(!l&&!o&&!r)continue;o++,r++,i+=`<div class="diff-line"><span class="ln-no">${o}</span><span class="ln-no" style="margin-right:12px">${r}</span><span class="ln-body">${m(l)}</span></div>`}}return{html:i,lineCount:s.length}}var He=null;async function yt(e){let t=Z;if(t)if(De(),un()){M.style.display="none",h&&(Ae(),h.destroy(),h=null,He=y,y=null),pe(null),re.style.display="none",Y.style.display="none",pt.style.display="flex",ft.textContent=e,Be.textContent="Loading\u2026",Ie.innerHTML="";try{let s=await fetch(T("/api/git/diff?path="+encodeURIComponent(t)+"&file="+encodeURIComponent(e)));if(!s.ok)throw new Error(await s.text());let i=await s.json();fn(e,i.diff,i.stagedDiff)}catch(s){let i=s instanceof Error?s.message:String(s);Be.textContent="Error",Ie.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${m(i)}</div>`}}else{E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
21
+ `),n="",o=0,r=0;for(let u of a){let l=u;if(l.startsWith("@@")){let c=l.match(/@@\s+-(\d+)[^+]*\+(\d+)/);c&&(o=parseInt(c[1],10)-1,r=parseInt(c[2],10)-1),n+=`<div class="diff-line hunk"><span class="ln-body">${m(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")&&(n+=`<div class="diff-line header"><span class="ln-body">${m(l)}</span></div>`);continue}if(l.startsWith("+"))r++,n+=`<div class="diff-line add"><span class="ln-no">${r}</span><span class="ln-body">${m(l)}</span></div>`;else if(l.startsWith("-"))o++,n+=`<div class="diff-line del"><span class="ln-no">${o}</span><span class="ln-body">${m(l)}</span></div>`;else if(l.startsWith("\\"))n+=`<div class="diff-line"><span class="ln-body">${m(l)}</span></div>`;else{if(!l&&!o&&!r)continue;o++,r++,n+=`<div class="diff-line"><span class="ln-no">${o}</span><span class="ln-no" style="margin-right:12px">${r}</span><span class="ln-body">${m(l)}</span></div>`}}return{html:n,lineCount:a.length}}var He=null;async function bt(e){let t=Z;if(t)if(De(),gn()){B.style.display="none",h&&($e(),h.destroy(),h=null,He=y,y=null),pe(null),re.style.display="none",W.style.display="none",mt.style.display="flex",vt.textContent=e,Be.textContent="Loading\u2026",Se.innerHTML="";try{let a=await fetch(M("/api/git/diff?path="+encodeURIComponent(t)+"&file="+encodeURIComponent(e)));if(!a.ok)throw new Error(await a.text());let n=await a.json();wn(e,n.diff,n.stagedDiff)}catch(a){let n=a instanceof Error?a.message:String(a);Be.textContent="Error",Se.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${m(n)}</div>`}}else{x.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">${m(e)}</span>
24
24
  <span class="diff-loading">Loading\u2026</span>
25
- </div></div>`,qe(),E.classList.add("open"),Se.classList.add("open");try{let s=await fetch(T("/api/git/diff?path="+encodeURIComponent(t)+"&file="+encodeURIComponent(e)));if(!s.ok)throw new Error(await s.text());let i=await s.json();pn(e,i.diff,i.stagedDiff)}catch(s){let i=s instanceof Error?s.message:String(s);E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
25
+ </div></div>`,Oe(),x.classList.add("open"),Ie.classList.add("open");try{let a=await fetch(M("/api/git/diff?path="+encodeURIComponent(t)+"&file="+encodeURIComponent(e)));if(!a.ok)throw new Error(await a.text());let n=await a.json();yn(e,n.diff,n.stagedDiff)}catch(a){let n=a instanceof Error?a.message:String(a);x.innerHTML=`<div class="git-diff-view"><div class="diff-header">
26
26
  <button class="diff-back">\u2190 Back</button>
27
27
  <span class="diff-filename">${m(e)}</span>
28
- </div><div class="diff-empty">Error loading diff: ${m(i)}</div></div>`}}}function pn(e,t,s){if(!t&&!s){E.innerHTML=`<div class="git-diff-view"><div class="diff-header">
28
+ </div><div class="diff-empty">Error loading diff: ${m(n)}</div></div>`}}}function yn(e,t,a){if(!t&&!a){x.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">${m(e)}</span>
31
- </div><div class="diff-empty">No diff content available</div></div>`;return}let{html:i,lineCount:o}=gt(t,s);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:n,lineCount:o}=wt(t,a);x.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">${m(e)}</span>
34
34
  <span class="diff-filesize">${o} lines</span>
35
- </div><div class="diff-content">${i}</div></div>`,E.querySelector(".diff-back")?.addEventListener("click",()=>{E.innerHTML=vt,qe(),g&&E.querySelectorAll(".git-popover-item").forEach(r=>{let d=parseInt(r.dataset.idx||"0",10),l=g.files[d];!l||l.status==="D"||(r.style.cursor="pointer",r.addEventListener("click",()=>yt(l.path)))}),mt()})}function fn(e,t,s){if(!t&&!s){Be.textContent="No diff",Ie.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}let{html:i,lineCount:o}=gt(t,s);ft.textContent=e,Be.textContent=o+" lines",Ie.innerHTML=i}function mn(){pt.style.display="none",He?(M.style.display="",M.classList.add("terminal-pending"),de(He),He=null):y?(M.style.display="",M.classList.add("terminal-pending"),bt()):Y.style.display="flex"}dn.addEventListener("click",mn);function De(){E.classList.remove("open"),Se.classList.remove("open")}Se.addEventListener("click",De),document.addEventListener("keydown",e=>{e.key==="Escape"&&(De(),$e())});async function wt(e){try{let t=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(e))).json();if(t.path){let s=await fetch("/api/git/status?path="+encodeURIComponent(t.path));if(s.ok){let i=await s.json();g=i,pe(i);return}}}catch{}g=null,pe(null)}var Re=null;function bt(){Ae(),y&&(wt(y),Re=setInterval(()=>{y&&wt(y)},3e4))}function Ae(){Re&&(clearInterval(Re),Re=null)}function vn(){if(Me=le.fsRoots||[],Me.length===0){if(y){hn(y);return}v.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}v.innerHTML="";for(let e of Me){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> ${m(e)}`,t.addEventListener("click",()=>P(e)),v.appendChild(t)}}async function hn(e){v.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?P(t.path):v.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{v.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function P(e){$=e,v.innerHTML='<div class="file-tree-empty">Loading...</div>';let t=rn(e);try{let s=await(await fetch(T("/api/fs/list?path="+encodeURIComponent(e)))).json();await t,v.innerHTML="",pe(g),v.innerHTML+=cn();let i=gn(e);if(i&&!Me.some(r=>e===r)){let r=document.createElement("div");r.className="file-tree-item",r.innerHTML="..",r.addEventListener("click",()=>P(i)),v.appendChild(r)}if(s.dirs)for(let r of s.dirs){let d=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> ${m(d)}`,l.addEventListener("click",()=>P(r)),v.appendChild(l)}else v.innerHTML="";let o=s.files||[];for(let r of o){let d=r.split("/").pop()||r.split("\\").pop(),l=ln(r),u="",f="";if(l)switch(l){case"M":u="git-mod",f='<span class="git-file-status M">M</span>';break;case"A":u="git-add",f='<span class="git-file-status A">A</span>';break;case"D":u="git-del",f='<span class="git-file-status D">D</span>';break;case"?":u="git-untracked",f='<span class="git-file-status ?">?</span>';break;case"R":u="git-mod",f='<span class="git-file-status R">R</span>';break}let R=document.createElement("div");R.className="file-tree-item file"+(u?" "+u:""),R.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${f}${m(d)}`,R.addEventListener("click",()=>yn(r)),v.appendChild(R)}}catch{v.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function gn(e){let t=e.lastIndexOf("/");return t<=0?null:e.substring(0,t)}async function yn(e){Ce=e,M.style.display="none",h&&(Ae(),h.destroy(),h=null,y=null),pe(null),Ue(),Y.style.display="none",re.style.display="flex",en.textContent=e,I.textContent="Loading...",U.style.display="none";try{let t=await fetch(T("/api/file?path="+encodeURIComponent(e)));if(!t.ok){let i=await t.json();I.textContent=i.error||"Failed to load",ce.value="";return}let s=await t.json();ce.value=s.content,Te=s.content,at=s.content,I.textContent=s.size+" bytes",U.style.display=""}catch{I.textContent="Failed to load",ce.value=""}}ce.addEventListener("input",()=>{Te=ce.value}),U.addEventListener("click",async()=>{U.textContent="Saving...",U.disabled=!0;try{let e=await fetch(T("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Ce,content:Te})});if(!e.ok){let t=await e.json();I.textContent=t.error||"Save failed";return}at=Te,I.textContent="Saved"}catch{I.textContent="Save failed"}finally{U.disabled=!1,U.textContent="Save"}}),tn.addEventListener("click",async()=>{if(confirm("Delete "+Ce+"?"))try{let e=await fetch(T("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Ce})});if(!e.ok){let t=await e.json();I.textContent=t.error||"Delete failed";return}re.style.display="none",Y.style.display="flex",$&&P($)}catch{I.textContent="Delete failed"}}),nn.addEventListener("click",()=>{re.style.display="none",Y.style.display="flex",$&&P($)}),sn.addEventListener("click",async()=>{let e=ot.value.trim();if(!e)return;let t=$+"/"+e;try{let s=await fetch(T("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!s.ok){let i=await s.json();I.textContent=i.error||"Create failed";return}ot.value="",$&&P($)}catch{I.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{let e=lt.classList.toggle("open");Ye.classList.toggle("open",e)}),Ye.addEventListener("click",()=>{lt.classList.remove("open"),Ye.classList.remove("open")});var W="",fe=document.createElement("div");fe.className="session-popover-backdrop",document.body.appendChild(fe);var D=document.createElement("div");D.id="session-popover",D.className="session-popover",D.style.display="none",D.innerHTML=`<div class="sp-field">
35
+ </div><div class="diff-content">${n}</div></div>`,x.querySelector(".diff-back")?.addEventListener("click",()=>{x.innerHTML=gt,Oe(),g&&x.querySelectorAll(".git-popover-item").forEach(r=>{let u=parseInt(r.dataset.idx||"0",10),l=g.files[u];!l||l.status==="D"||(r.style.cursor="pointer",r.addEventListener("click",()=>bt(l.path)))}),ht()})}function wn(e,t,a){if(!t&&!a){Be.textContent="No diff",Se.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}let{html:n,lineCount:o}=wt(t,a);vt.textContent=e,Be.textContent=o+" lines",Se.innerHTML=n}function bn(){mt.style.display="none",He?(B.style.display="",B.classList.add("terminal-pending"),de(He),He=null):y?(B.style.display="",B.classList.add("terminal-pending"),Et()):W.style.display="flex"}hn.addEventListener("click",bn);function De(){x.classList.remove("open"),Ie.classList.remove("open")}Ie.addEventListener("click",De),document.addEventListener("keydown",e=>{e.key==="Escape"&&(De(),Ae())});async function Lt(e){try{let t=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(e))).json();if(t.path){let a=await fetch("/api/git/status?path="+encodeURIComponent(t.path));if(a.ok){let n=await a.json();g=n,pe(n);return}}}catch{}g=null,pe(null)}var Re=null;function Et(){$e(),y&&(Lt(y),Re=setInterval(()=>{y&&Lt(y)},3e4))}function $e(){Re&&(clearInterval(Re),Re=null)}function Ln(){if(Me=le.fsRoots||[],Me.length===0){if(y){En(y);return}v.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}v.innerHTML="";for(let e of Me){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> ${m(e)}`,t.addEventListener("click",()=>P(e)),v.appendChild(t)}}async function En(e){v.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let t=await(await fetch(M("/api/fs/session-path?session="+encodeURIComponent(e)))).json();t.path?P(t.path):v.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{v.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function P(e){N=e,v.innerHTML='<div class="file-tree-empty">Loading...</div>';let t=mn(e);try{let a=await(await fetch(M("/api/fs/list?path="+encodeURIComponent(e)))).json();await t,v.innerHTML="",pe(g),v.innerHTML+=vn();let n=xn(e);if(n&&!Me.some(r=>e===r)){let r=document.createElement("div");r.className="file-tree-item",r.innerHTML="..",r.addEventListener("click",()=>P(n)),v.appendChild(r)}if(a.dirs)for(let r of a.dirs){let u=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> ${m(u)}`,l.addEventListener("click",()=>P(r)),v.appendChild(l)}else v.innerHTML="";let o=a.files||[];for(let r of o){let u=r.split("/").pop()||r.split("\\").pop(),l=fn(r),c="",p="";if(l)switch(l){case"M":c="git-mod",p='<span class="git-file-status M">M</span>';break;case"A":c="git-add",p='<span class="git-file-status A">A</span>';break;case"D":c="git-del",p='<span class="git-file-status D">D</span>';break;case"?":c="git-untracked",p='<span class="git-file-status ?">?</span>';break;case"R":c="git-mod",p='<span class="git-file-status R">R</span>';break}let L=document.createElement("div");L.className="file-tree-item file"+(c?" "+c:""),L.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${p}${m(u)}`,L.addEventListener("click",()=>kn(r)),v.appendChild(L)}}catch{v.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function xn(e){let t=e.lastIndexOf("/");return t<=0?null:e.substring(0,t)}async function kn(e){Ce=e,B.style.display="none",h&&($e(),h.destroy(),h=null,y=null),pe(null),We(),W.style.display="none",re.style.display="flex",nn.textContent=e,I.textContent="Loading...",q.style.display="none";try{let t=await fetch(M("/api/file?path="+encodeURIComponent(e)));if(!t.ok){let n=await t.json();I.textContent=n.error||"Failed to load",ce.value="";return}let a=await t.json();ce.value=a.content,Te=a.content,st=a.content,I.textContent=a.size+" bytes",q.style.display=""}catch{I.textContent="Failed to load",ce.value=""}}ce.addEventListener("input",()=>{Te=ce.value}),q.addEventListener("click",async()=>{q.textContent="Saving...",q.disabled=!0;try{let e=await fetch(M("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Ce,content:Te})});if(!e.ok){let t=await e.json();I.textContent=t.error||"Save failed";return}st=Te,I.textContent="Saved"}catch{I.textContent="Save failed"}finally{q.disabled=!1,q.textContent="Save"}}),an.addEventListener("click",async()=>{if(confirm("Delete "+Ce+"?"))try{let e=await fetch(M("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Ce})});if(!e.ok){let t=await e.json();I.textContent=t.error||"Delete failed";return}re.style.display="none",W.style.display="flex",N&&P(N)}catch{I.textContent="Delete failed"}}),sn.addEventListener("click",()=>{re.style.display="none",W.style.display="flex",N&&P(N)}),on.addEventListener("click",async()=>{let e=ot.value.trim();if(!e)return;let t=N+"/"+e;try{let a=await fetch(M("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!a.ok){let n=await a.json();I.textContent=n.error||"Create failed";return}ot.value="",N&&P(N)}catch{I.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{let e=lt.classList.toggle("open");Ye.classList.toggle("open",e)}),Ye.addEventListener("click",()=>{lt.classList.remove("open"),Ye.classList.remove("open")});var O="",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 Xt=/\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(D);function wn(e){let t=e.getBoundingClientRect();D.style.top=t.bottom+4+"px",D.style.left=Math.max(8,Math.min(t.left,window.innerWidth-240))+"px"}function bn(e,t){W=e;let s=document.getElementById("sp-name");s.value=e,fe.classList.add("open"),D.style.display="block",wn(t),setTimeout(()=>s.focus(),50)}function me(){fe.classList.remove("open"),D.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===W){me();return}try{if(!(await fetch(T("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:W,newName:e})})).ok)return;me(),J(),y===W&&de(e)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+W+'"?'))try{if(!(await fetch(T("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:W})})).ok)return;me(),y===W&&(h&&(h.destroy(),h=null),y=null,M.style.display="none",Y.style.display="flex"),J()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",me);var Ln={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||!h)return;let s=Ln[t.dataset.key];s&&(h.sendInput(s),h.focus())});var S=document.getElementById("mk-input"),Lt=document.getElementById("mk-send");function Et(){if(!S||!h)return;let e=S.value;e&&(h.sendInput(e+"\r"),S.value="",S.rows=1,h.focus())}if(S&&(S.addEventListener("input",()=>{S.rows=1;let e=S.value.split(`
45
- `).length;S.rows=Math.min(e,4)}),S.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),Et())})),Lt&&Lt.addEventListener("click",Et),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 Oe=document.getElementById("process-panel"),ve=document.getElementById("proc-list"),En=document.getElementById("proc-close"),Ke=document.getElementById("proc-backdrop"),xn=document.getElementById("header-ram");function kn(){ve.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){ve.innerHTML='<div class="proc-empty">No processes</div>';return}let t="";for(let s of e){let i=s.rss,o=i<1048576?(i/1024).toFixed(0)+"K":(i/1048576).toFixed(1)+"M";t+='<div class="proc-row" data-pid="'+s.pid+'"><span class="proc-mem">'+s.mem+'%</span><span class="proc-rss">'+o+'</span><span class="proc-cmd" title="'+m(s.command)+'">'+m(s.command)+'</span><button class="proc-kill" title="Kill PID '+s.pid+'">&times;</button></div>'}ve.innerHTML=t;for(let s of ve.querySelectorAll(".proc-row")){let i=s.querySelector(".proc-kill");i&&i.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(d=>d.json()).then(d=>{d.ok?r.style.opacity="0.3":alert("Failed: "+(d.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{ve.innerHTML='<div class="proc-empty">Failed to load</div>'})}function Cn(){Oe.classList.add("open"),Ke.classList.add("open"),kn()}function $e(){Oe.classList.remove("open"),Ke.classList.remove("open")}xn.addEventListener("click",e=>{e.stopPropagation(),Oe.classList.contains("open")?$e():Cn()}),En.addEventListener("click",$e),Ke.addEventListener("click",$e),window.__openSession=de,window.__refreshSidebar=J,J(),Ue(),setInterval(()=>{document.visibilityState==="visible"&&J()},1e4);
44
+ <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild($);function Cn(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 Tn(e,t){O=e;let a=document.getElementById("sp-name");a.value=e,fe.classList.add("open"),$.style.display="block",Cn(t),setTimeout(()=>a.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===O){me();return}try{if(!(await fetch(M("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:O,newName:e})})).ok)return;me(),J(),y===O&&de(e)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+O+'"?'))try{if(!(await fetch(M("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:O})})).ok)return;me(),y===O&&(h&&(h.destroy(),h=null),y=null,B.style.display="none",W.style.display="flex"),J()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",me);var Mn={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||!h)return;let a=Mn[t.dataset.key];a&&(h.sendInput(a),h.focus())});var H=document.getElementById("mk-input"),xt=document.getElementById("mk-send");function kt(){if(!H||!h)return;let e=H.value;e&&(h.sendInput(e+"\r"),H.value="",H.rows=1,h.focus())}if(H&&(H.addEventListener("input",()=>{H.rows=1;let e=H.value.split(`
45
+ `).length;H.rows=Math.min(e,4)}),H.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),kt())})),xt&&xt.addEventListener("click",kt),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 Ue=document.getElementById("process-panel"),ve=document.getElementById("proc-list"),Bn=document.getElementById("proc-close"),Ke=document.getElementById("proc-backdrop"),Sn=document.getElementById("header-ram");function In(){ve.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(M("/api/system/processes")).then(e=>e.json()).then(e=>{if(!Array.isArray(e)||!e.length){ve.innerHTML='<div class="proc-empty">No processes</div>';return}let t="";for(let a of e){let n=a.rss,o=n<1048576?(n/1024).toFixed(0)+"K":(n/1048576).toFixed(1)+"M";t+='<div class="proc-row" data-pid="'+a.pid+'"><span class="proc-mem">'+a.mem+'%</span><span class="proc-rss">'+o+'</span><span class="proc-cmd" title="'+m(a.command)+'">'+m(a.command)+'</span><button class="proc-kill" title="Kill PID '+a.pid+'">&times;</button></div>'}ve.innerHTML=t;for(let a of ve.querySelectorAll(".proc-row")){let n=a.querySelector(".proc-kill");n&&n.addEventListener("click",o=>{let r=o.target.closest(".proc-row");!r||!confirm("Kill PID "+r.dataset.pid+"?")||fetch(M("/api/system/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(r.dataset.pid,10)})}).then(u=>u.json()).then(u=>{u.ok?r.style.opacity="0.3":alert("Failed: "+(u.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{ve.innerHTML='<div class="proc-empty">Failed to load</div>'})}function Hn(){Ue.classList.add("open"),Ke.classList.add("open"),In()}function Ae(){Ue.classList.remove("open"),Ke.classList.remove("open")}Sn.addEventListener("click",e=>{e.stopPropagation(),Ue.classList.contains("open")?Ae():Hn()}),Bn.addEventListener("click",Ae),Ke.addEventListener("click",Ae),window.__openSession=de,window.__refreshSidebar=J,J(),We(),setInterval(()=>{document.visibilityState==="visible"&&J()},1e4);
@@ -1,31 +1,31 @@
1
- import{initTerminal as ke}from"./terminal-core.js";const T=window.__TMUX_WEB_SHELL__;let p=null,u=null;const ie=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null;let v=ie;window.__tmuxWebScopeAgent=ie;let Y="sessions",E="",j="",W="",oe="";function y(e){return v?"/a/"+encodeURIComponent(v)+e:e}const r=document.getElementById("sidebar-content"),C=document.getElementById("main-placeholder"),h=document.getElementById("terminal-container"),H=document.getElementById("file-editor"),Ce=document.getElementById("fe-path"),b=document.getElementById("fe-status"),$=document.getElementById("fe-content"),I=document.getElementById("fe-save"),Ie=document.getElementById("fe-delete"),xe=document.getElementById("fe-back"),ae=document.getElementById("fe-new-name"),Be=document.getElementById("fe-new-btn"),Z=document.getElementById("settings-backdrop"),le=document.getElementById("settings-popover"),ce=document.querySelector(".sidebar");function Me(){return window.matchMedia("(max-width: 640px)").matches}function Q(){Me()&&ce.classList.add("collapsed")}function de(){ce.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{de(),re("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{de(),re("files")});function re(e){Y=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"?(ee="",M()):Ae()}let ee="";async function M(){if(Y!=="sessions")return;try{const t=await(await fetch("/api/sidebar/sessions")).json(),s=JSON.stringify({recent:t.recent,agents:t.agents});if(s===ee)return;ee=s,Se(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")})}function Se(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"+(v?" clickable":""),t.textContent=v?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",v&&(t.title="Back to hub",t.addEventListener("click",()=>{window.location.href="/"})),r.appendChild(t);for(const i of n){const l=document.createElement("div");l.className="session-item"+(i.name===u&&!v?" active":""),l.setAttribute("data-session",i.name),l.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${i.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
- <span>${d(i.name)}</span>
3
- <button class="session-edit-btn" data-session="${d(i.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
- `,l.addEventListener("click",c=>{c.target.closest(".session-edit-btn")||R(i.name)}),r.appendChild(l);const o=l.querySelector(".session-edit-btn");o&&o.addEventListener("click",c=>{c.stopPropagation(),Oe(i.name,o)})}const s=e.agents||[];for(const i of s){if(!i.sessions||i.sessions.length===0)continue;const l=i.agentId===v,o=document.createElement("div");o.className="sidebar-section-label machine-label"+(i.online?"":" agent-offline-label")+(!l&&i.online?" clickable":""),o.textContent=i.agentName+(i.online?"":" (offline)"),!l&&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 a=document.createElement("div");a.className="session-item"+(c.name===u&&v===i.agentId?" active":"")+(i.online?"":" session-offline"),a.setAttribute("data-session",c.name),a.setAttribute("data-agent",i.agentId),a.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&&a.addEventListener("click",g=>{g.target.closest(".session-edit-btn")||R(c.name,i.agentId)}),r.appendChild(a)}}}function d(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function R(e,n){if(!(u===e&&p&&v===(n||null))){H.style.display="none",C.style.display="none",h.style.display="",h.classList.add("terminal-pending"),Q(),p&&(K(),p.destroy(),p=null),u=e,v=n||null,window.__tmuxWebScopeAgent=v,window.__tmuxWebCurrentSession=u;for(const t of r.querySelectorAll(".session-item"))t.classList.toggle("active",t.getAttribute("data-session")===e&&(t.getAttribute("data-agent")||null)===v);try{p=await ke(h,e,{terminal:T.terminal,scrollback:T.scrollback,theme:T.theme,wsBase:v?"/ws/a/"+encodeURIComponent(v):T.wsBase||"/ws"}),we()}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 z=[],f=null,pe=!1;function Te(e){if(!f||!f.files.length)return null;const n=f.repoRoot;if(!n||!e.startsWith(n))return null;const t=e.slice(n.length+1);for(const s of f.files)if(s.path===t)return s.status;return null}async function He(e){pe=!0;try{const n=await fetch(y("/api/git/status?path="+encodeURIComponent(e)));n.ok?f=await n.json():f=null}catch{f=null}finally{pe=!1}}function $e(){if(!f||!f.branch)return"";const{branch:e,linesAdded:n,linesRemoved:t}=f;let s=`<div class="sidebar-git"><div class="git-branch-badge">
1
+ import{initTerminal as Be}from"./terminal-core.js";const H=window.__TMUX_WEB_SHELL__;let p=null,u=null;const ie=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null;let g=ie;window.__tmuxWebScopeAgent=ie;let Y="sessions",k="",F="",W="",oe="";function h(e){return g?"/a/"+encodeURIComponent(g)+e:e}const r=document.getElementById("sidebar-content"),I=document.getElementById("main-placeholder"),b=document.getElementById("terminal-container"),$=document.getElementById("file-editor"),Ie=document.getElementById("fe-path"),w=document.getElementById("fe-status"),R=document.getElementById("fe-content"),x=document.getElementById("fe-save"),xe=document.getElementById("fe-delete"),Se=document.getElementById("fe-back"),ae=document.getElementById("fe-new-name"),Me=document.getElementById("fe-new-btn"),Z=document.getElementById("settings-backdrop"),le=document.getElementById("settings-popover"),ce=document.querySelector(".sidebar");function Te(){return window.matchMedia("(max-width: 640px)").matches}function Q(){Te()&&ce.classList.add("collapsed")}function de(){ce.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{de(),re("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{de(),re("files")});function re(e){Y=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"?(ee="",M()):ze()}let ee="";async function M(){if(Y!=="sessions")return;try{const t=await(await fetch("/api/sidebar/sessions")).json(),s=JSON.stringify({recent:t.recent,agents:t.agents});if(s===ee)return;ee=s,_e(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")})}const pe="tmux-web-sidebar-group-collapsed";function fe(){try{return new Set(JSON.parse(localStorage.getItem(pe)||"[]"))}catch{return new Set}}function He(e){try{localStorage.setItem(pe,JSON.stringify([...e]))}catch{}}function $e(e,n){if(!e)return"\u2026";const t=e.split("/").filter(Boolean);if(t.length===0)return e;for(let s=2;s<=t.length;s++){const i=t.slice(-s).join("/");if(!n.some(a=>a&&a!==e&&a.split("/").filter(Boolean).slice(-s).join("/")===i))return"\u2026/"+i}return e}function Re(e){const n=new Map;for(const i of e){const l=i.path||"";n.has(l)||n.set(l,[]),n.get(l).push(i)}const t=[...n.keys()],s=fe();for(const[i,l]of n){const a=$e(i,t),c=s.has(i),o=document.createElement("div");o.className="session-group-header"+(c?" collapsed":""),o.title=i||"No working directory",o.innerHTML=`<span class="sg-folder">&#128193;</span><span class="sg-label">${d(a)}</span><span class="sg-count">${l.length}</span><span class="sg-arrow">${c?"\u25B8":"\u25BE"}</span>`,o.addEventListener("click",()=>{const y=fe(),B=o.nextElementSibling;y.has(i)?(y.delete(i),o.classList.remove("collapsed"),B?.classList.remove("collapsed"),o.querySelector(".sg-arrow").textContent="\u25BE"):(y.add(i),o.classList.add("collapsed"),B?.classList.add("collapsed"),o.querySelector(".sg-arrow").textContent="\u25B8"),He(y)});const m=document.createElement("div");m.className="session-group-body"+(c?" collapsed":"");for(const y of l)m.appendChild(Ne(y));r.appendChild(o),r.appendChild(m)}}function Ne(e){const n=document.createElement("div");n.className="session-item"+(e.name===u&&!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
+ <span>${d(e.name)}</span>
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
+ `,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(),Ke(e.name,t)}),n}function _e(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),Re(n);const s=e.agents||[];for(const i of s){if(!i.sessions||i.sessions.length===0)continue;const l=i.agentId===g,a=document.createElement("div");a.className="sidebar-section-label machine-label"+(i.online?"":" agent-offline-label")+(!l&&i.online?" clickable":""),a.textContent=i.agentName+(i.online?"":" (offline)"),!l&&i.online&&(a.title="\u6253\u5F00 "+i.agentName,a.addEventListener("click",()=>{window.location.href="/a/"+encodeURIComponent(i.agentId)+"/"})),r.appendChild(a);for(const c of i.sessions){const o=document.createElement("div");o.className="session-item"+(c.name===u&&g===i.agentId?" active":"")+(i.online?"":" session-offline"),o.setAttribute("data-session",c.name),o.setAttribute("data-agent",i.agentId),o.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&&o.addEventListener("click",m=>{m.target.closest(".session-edit-btn")||N(c.name,i.agentId)}),r.appendChild(o)}}}function d(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function N(e,n){if(!(u===e&&p&&g===(n||null))){$.style.display="none",I.style.display="none",b.style.display="",b.classList.add("terminal-pending"),Q(),p&&(K(),p.destroy(),p=null),u=e,g=n||null,window.__tmuxWebScopeAgent=g,window.__tmuxWebCurrentSession=u;for(const t of r.querySelectorAll(".session-item"))t.classList.toggle("active",t.getAttribute("data-session")===e&&(t.getAttribute("data-agent")||null)===g);try{p=await Be(b,e,{terminal:H.terminal,scrollback:H.scrollback,theme:H.theme,wsBase:g?"/ws/a/"+encodeURIComponent(g):H.wsBase||"/ws"}),Ee()}catch(t){console.error("[shell] terminal init failed:",t);const s=t&&typeof t=="object"&&"message"in t?t.message:String(t);b.textContent="Failed to open terminal for "+e+": "+s,b.classList.remove("terminal-pending")}}}let G=[],f=null,ue=!1;function Pe(e){if(!f||!f.files.length)return null;const n=f.repoRoot;if(!n||!e.startsWith(n))return null;const t=e.slice(n.length+1);for(const s of f.files)if(s.path===t)return s.status;return null}async function Ae(e){ue=!0;try{const n=await fetch(h("/api/git/status?path="+encodeURIComponent(e)));n.ok?f=await n.json():f=null}catch{f=null}finally{ue=!1}}function De(){if(!f||!f.branch)return"";const{branch:e,linesAdded:n,linesRemoved:t}=f;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")&&S&&f&&(e.stopPropagation(),ge())});const N=document.getElementById("header-git"),fe=document.getElementById("git-diff-view"),ue=document.getElementById("gd-path"),O=document.getElementById("gd-status"),U=document.getElementById("gd-content"),Re=document.getElementById("gd-back");let S=null;function _(e){if(!e||!e.branch){N.style.display="none",S=null;return}S=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>`),N.innerHTML=i,N.style.display="block"}N.addEventListener("click",e=>{S&&f&&(e.stopPropagation(),ge())});const m=document.getElementById("git-popover"),G=document.getElementById("git-popover-backdrop");function te(){const e=N.getBoundingClientRect();m.style.top=e.bottom+4+"px",m.style.left=Math.max(8,Math.min(e.left,window.innerWidth-400))+"px"}function me(){const e=S,n=document.getElementById("git-popover-browse");n&&n.addEventListener("click",()=>{if(q(),e){Y="files",document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));const t=document.getElementById("mode-files");t&&t.classList.add("active"),k(e)}})}let ve="";function ge(){if(!f)return;const e=f.files||[];if(!e.length)m.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
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,l=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
- ${o}<span class="file-path">${d(s.path)}</span>
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&&f&&(e.stopPropagation(),he())});const _=document.getElementById("header-git"),me=document.getElementById("git-diff-view"),ve=document.getElementById("gd-path"),O=document.getElementById("gd-status"),z=document.getElementById("gd-content"),je=document.getElementById("gd-back");let T=null;function P(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&&f&&(e.stopPropagation(),he())});const v=document.getElementById("git-popover"),U=document.getElementById("git-popover-backdrop");function te(){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 ge(){const e=T,n=document.getElementById("git-popover-browse");n&&n.addEventListener("click",()=>{if(V(),e){Y="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 ye="";function he(){if(!f)return;const e=f.files||[];if(!e.length)v.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
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,l=s.deletions||0;let a="";switch(s.status){case"M":a='<span class="git-file-status M">M</span>';break;case"A":a='<span class="git-file-status A">A</span>';break;case"D":a='<span class="git-file-status D">D</span>';break;case"?":a='<span class="git-file-status ?">?</span>';break;case"R":a='<span class="git-file-status R">R</span>';break}n+=`<div class="git-popover-item" data-idx="${t}">
9
+ ${a}<span class="file-path">${d(s.path)}</span>
10
10
  <span class="file-add">${i>0?"+"+i:""}</span>
11
11
  <span class="file-del">${l>0?"-"+l:""}</span>
12
- </div>`}n+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',ve=n,m.innerHTML=n,m.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",()=>he(i.path)))})}te(),m.classList.add("open"),G.classList.add("open"),me()}function Ne(){return window.innerWidth>=1024}function ye(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>',ye=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",()=>we(i.path)))})}te(),v.classList.add("open"),U.classList.add("open"),ge()}function Fe(){return window.innerWidth>=1024}function be(e,n){const s=(e+(n&&e?`
13
13
  `:"")+n).split(`
14
- `);let i="",l=0,o=0;for(const c of s){const a=c;if(a.startsWith("@@")){const g=a.match(/@@\s+-(\d+)[^+]*\+(\d+)/);g&&(l=parseInt(g[1],10)-1,o=parseInt(g[2],10)-1),i+=`<div class="diff-line hunk"><span class="ln-body">${d(a)}</span></div>`;continue}if(a.startsWith("diff --git")||a.startsWith("index ")||a.startsWith("--- ")||a.startsWith("+++ ")||a.startsWith("new file")||a.startsWith("deleted file")){a.startsWith("diff --git")&&(i+=`<div class="diff-line header"><span class="ln-body">${d(a)}</span></div>`);continue}if(a.startsWith("+"))o++,i+=`<div class="diff-line add"><span class="ln-no">${o}</span><span class="ln-body">${d(a)}</span></div>`;else if(a.startsWith("-"))l++,i+=`<div class="diff-line del"><span class="ln-no">${l}</span><span class="ln-body">${d(a)}</span></div>`;else if(a.startsWith("\\"))i+=`<div class="diff-line"><span class="ln-body">${d(a)}</span></div>`;else{if(!a&&!l&&!o)continue;l++,o++,i+=`<div class="diff-line"><span class="ln-no">${l}</span><span class="ln-no" style="margin-right:12px">${o}</span><span class="ln-body">${d(a)}</span></div>`}}return{html:i,lineCount:s.length}}let V=null;async function he(e){const n=S;if(n)if(q(),Ne()){h.style.display="none",p&&(K(),p.destroy(),p=null,V=u,u=null),_(null),H.style.display="none",C.style.display="none",fe.style.display="flex",ue.textContent=e,O.textContent="Loading\u2026",U.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();De(e,s.diff,s.stagedDiff)}catch(t){const s=t instanceof Error?t.message:String(t);O.textContent="Error",U.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${d(s)}</div>`}}else{m.innerHTML=`<div class="git-diff-view"><div class="diff-header">
14
+ `);let i="",l=0,a=0;for(const c of s){const o=c;if(o.startsWith("@@")){const m=o.match(/@@\s+-(\d+)[^+]*\+(\d+)/);m&&(l=parseInt(m[1],10)-1,a=parseInt(m[2],10)-1),i+=`<div class="diff-line hunk"><span class="ln-body">${d(o)}</span></div>`;continue}if(o.startsWith("diff --git")||o.startsWith("index ")||o.startsWith("--- ")||o.startsWith("+++ ")||o.startsWith("new file")||o.startsWith("deleted file")){o.startsWith("diff --git")&&(i+=`<div class="diff-line header"><span class="ln-body">${d(o)}</span></div>`);continue}if(o.startsWith("+"))a++,i+=`<div class="diff-line add"><span class="ln-no">${a}</span><span class="ln-body">${d(o)}</span></div>`;else if(o.startsWith("-"))l++,i+=`<div class="diff-line del"><span class="ln-no">${l}</span><span class="ln-body">${d(o)}</span></div>`;else if(o.startsWith("\\"))i+=`<div class="diff-line"><span class="ln-body">${d(o)}</span></div>`;else{if(!o&&!l&&!a)continue;l++,a++,i+=`<div class="diff-line"><span class="ln-no">${l}</span><span class="ln-no" style="margin-right:12px">${a}</span><span class="ln-body">${d(o)}</span></div>`}}return{html:i,lineCount:s.length}}let q=null;async function we(e){const n=T;if(n)if(V(),Fe()){b.style.display="none",p&&(K(),p.destroy(),p=null,q=u,u=null),P(null),$.style.display="none",I.style.display="none",me.style.display="flex",ve.textContent=e,O.textContent="Loading\u2026",z.innerHTML="";try{const t=await fetch(h("/api/git/diff?path="+encodeURIComponent(n)+"&file="+encodeURIComponent(e)));if(!t.ok)throw new Error(await t.text());const s=await t.json();Ge(e,s.diff,s.stagedDiff)}catch(t){const s=t instanceof Error?t.message:String(t);O.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>
18
- </div></div>`,te(),m.classList.add("open"),G.classList.add("open");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();_e(e,s.diff,s.stagedDiff)}catch(t){const s=t instanceof Error?t.message:String(t);m.innerHTML=`<div class="git-diff-view"><div class="diff-header">
18
+ </div></div>`,te(),v.classList.add("open"),U.classList.add("open");try{const t=await fetch(h("/api/git/diff?path="+encodeURIComponent(n)+"&file="+encodeURIComponent(e)));if(!t.ok)throw new Error(await t.text());const s=await t.json();We(e,s.diff,s.stagedDiff)}catch(t){const s=t instanceof Error?t.message:String(t);v.innerHTML=`<div class="git-diff-view"><div class="diff-header">
19
19
  <button class="diff-back">\u2190 Back</button>
20
20
  <span class="diff-filename">${d(e)}</span>
21
- </div><div class="diff-empty">Error loading diff: ${d(s)}</div></div>`}}}function _e(e,n,t){if(!n&&!t){m.innerHTML=`<div class="git-diff-view"><div class="diff-header">
21
+ </div><div class="diff-empty">Error loading diff: ${d(s)}</div></div>`}}}function We(e,n,t){if(!n&&!t){v.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">${d(e)}</span>
24
- </div><div class="diff-empty">No diff content available</div></div>`;return}const{html:s,lineCount:i}=ye(n,t);m.innerHTML=`<div class="git-diff-view"><div class="diff-header">
24
+ </div><div class="diff-empty">No diff content available</div></div>`;return}const{html:s,lineCount:i}=be(n,t);v.innerHTML=`<div class="git-diff-view"><div class="diff-header">
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>`,m.querySelector(".diff-back")?.addEventListener("click",()=>{m.innerHTML=ve,te(),f&&m.querySelectorAll(".git-popover-item").forEach(l=>{const o=parseInt(l.dataset.idx||"0",10),c=f.files[o];!c||c.status==="D"||(l.style.cursor="pointer",l.addEventListener("click",()=>he(c.path)))}),me()})}function De(e,n,t){if(!n&&!t){O.textContent="No diff",U.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}=ye(n,t);ue.textContent=e,O.textContent=i+" lines",U.innerHTML=s}function Pe(){fe.style.display="none",V?(h.style.display="",h.classList.add("terminal-pending"),R(V),V=null):u?(h.style.display="",h.classList.add("terminal-pending"),we()):C.style.display="flex"}Re.addEventListener("click",Pe);function q(){m.classList.remove("open"),G.classList.remove("open")}G.addEventListener("click",q),document.addEventListener("keydown",e=>{e.key==="Escape"&&(q(),X())});async function be(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();f=i,_(i);return}}}catch{}f=null,_(null)}let J=null;function we(){K(),u&&(be(u),J=setInterval(()=>{u&&be(u)},3e4))}function K(){J&&(clearInterval(J),J=null)}function Ae(){if(z=T.fsRoots||[],z.length===0){if(u){Fe(u);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 z){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",()=>k(e)),r.appendChild(n)}}async function Fe(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?k(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 k(e){E=e,r.innerHTML='<div class="file-tree-empty">Loading...</div>';const n=He(e);try{const s=await(await fetch(y("/api/fs/list?path="+encodeURIComponent(e)))).json();await n,r.innerHTML="",_(f),r.innerHTML+=$e();const i=je(e);if(i&&!z.some(c=>e===c)){const c=document.createElement("div");c.className="file-tree-item",c.innerHTML="..",c.addEventListener("click",()=>k(i)),r.appendChild(c)}if(s.dirs)for(const o of s.dirs){const c=o.split("/").pop()||o.split("\\").pop(),a=document.createElement("div");a.className="file-tree-item",a.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)}`,a.addEventListener("click",()=>k(o)),r.appendChild(a)}else r.innerHTML="";const l=s.files||[];for(const o of l){const c=o.split("/").pop()||o.split("\\").pop(),a=Te(o);let g="",B="";if(a)switch(a){case"M":g="git-mod",B='<span class="git-file-status M">M</span>';break;case"A":g="git-add",B='<span class="git-file-status A">A</span>';break;case"D":g="git-del",B='<span class="git-file-status D">D</span>';break;case"?":g="git-untracked",B='<span class="git-file-status ?">?</span>';break;case"R":g="git-mod",B='<span class="git-file-status R">R</span>';break}const F=document.createElement("div");F.className="file-tree-item file"+(g?" "+g:""),F.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${B}${d(c)}`,F.addEventListener("click",()=>We(o)),r.appendChild(F)}}catch{r.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function je(e){const n=e.lastIndexOf("/");return n<=0?null:e.substring(0,n)}async function We(e){j=e,h.style.display="none",p&&(K(),p.destroy(),p=null,u=null),_(null),Q(),C.style.display="none",H.style.display="flex",Ce.textContent=e,b.textContent="Loading...",I.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,W=t.content,oe=t.content,b.textContent=t.size+" bytes",I.style.display=""}catch{b.textContent="Failed to load",$.value=""}}$.addEventListener("input",()=>{W=$.value}),I.addEventListener("click",async()=>{I.textContent="Saving...",I.disabled=!0;try{const e=await fetch(y("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:j,content:W})});if(!e.ok){const n=await e.json();b.textContent=n.error||"Save failed";return}oe=W,b.textContent="Saved"}catch{b.textContent="Save failed"}finally{I.disabled=!1,I.textContent="Save"}}),Ie.addEventListener("click",async()=>{if(confirm("Delete "+j+"?"))try{const e=await fetch(y("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:j})});if(!e.ok){const n=await e.json();b.textContent=n.error||"Delete failed";return}H.style.display="none",C.style.display="flex",E&&k(E)}catch{b.textContent="Delete failed"}}),xe.addEventListener("click",()=>{H.style.display="none",C.style.display="flex",E&&k(E)}),Be.addEventListener("click",async()=>{const e=ae.value.trim();if(!e)return;const n=E+"/"+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}ae.value="",E&&k(E)}catch{b.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{const e=le.classList.toggle("open");Z.classList.toggle("open",e)}),Z.addEventListener("click",()=>{le.classList.remove("open"),Z.classList.remove("open")});let x="";const D=document.createElement("div");D.className="session-popover-backdrop",document.body.appendChild(D);const L=document.createElement("div");L.id="session-popover",L.className="session-popover",L.style.display="none",L.innerHTML=`<div class="sp-field">
28
+ </div><div class="diff-content">${s}</div></div>`,v.querySelector(".diff-back")?.addEventListener("click",()=>{v.innerHTML=ye,te(),f&&v.querySelectorAll(".git-popover-item").forEach(l=>{const a=parseInt(l.dataset.idx||"0",10),c=f.files[a];!c||c.status==="D"||(l.style.cursor="pointer",l.addEventListener("click",()=>we(c.path)))}),ge()})}function Ge(e,n,t){if(!n&&!t){O.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}=be(n,t);ve.textContent=e,O.textContent=i+" lines",z.innerHTML=s}function Oe(){me.style.display="none",q?(b.style.display="",b.classList.add("terminal-pending"),N(q),q=null):u?(b.style.display="",b.classList.add("terminal-pending"),Ee()):I.style.display="flex"}je.addEventListener("click",Oe);function V(){v.classList.remove("open"),U.classList.remove("open")}U.addEventListener("click",V),document.addEventListener("keydown",e=>{e.key==="Escape"&&(V(),X())});async function Le(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();f=i,P(i);return}}}catch{}f=null,P(null)}let J=null;function Ee(){K(),u&&(Le(u),J=setInterval(()=>{u&&Le(u)},3e4))}function K(){J&&(clearInterval(J),J=null)}function ze(){if(G=H.fsRoots||[],G.length===0){if(u){Ue(u);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 G){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 Ue(e){r.innerHTML='<div class="file-tree-empty">Loading...</div>';try{const t=await(await fetch(h("/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){k=e,r.innerHTML='<div class="file-tree-empty">Loading...</div>';const n=Ae(e);try{const s=await(await fetch(h("/api/fs/list?path="+encodeURIComponent(e)))).json();await n,r.innerHTML="",P(f),r.innerHTML+=De();const i=qe(e);if(i&&!G.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 a of s.dirs){const c=a.split("/").pop()||a.split("\\").pop(),o=document.createElement("div");o.className="file-tree-item",o.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)}`,o.addEventListener("click",()=>C(a)),r.appendChild(o)}else r.innerHTML="";const l=s.files||[];for(const a of l){const c=a.split("/").pop()||a.split("\\").pop(),o=Pe(a);let m="",y="";if(o)switch(o){case"M":m="git-mod",y='<span class="git-file-status M">M</span>';break;case"A":m="git-add",y='<span class="git-file-status A">A</span>';break;case"D":m="git-del",y='<span class="git-file-status D">D</span>';break;case"?":m="git-untracked",y='<span class="git-file-status ?">?</span>';break;case"R":m="git-mod",y='<span class="git-file-status R">R</span>';break}const B=document.createElement("div");B.className="file-tree-item file"+(m?" "+m:""),B.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${y}${d(c)}`,B.addEventListener("click",()=>Ve(a)),r.appendChild(B)}}catch{r.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function qe(e){const n=e.lastIndexOf("/");return n<=0?null:e.substring(0,n)}async function Ve(e){F=e,b.style.display="none",p&&(K(),p.destroy(),p=null,u=null),P(null),Q(),I.style.display="none",$.style.display="flex",Ie.textContent=e,w.textContent="Loading...",x.style.display="none";try{const n=await fetch(h("/api/file?path="+encodeURIComponent(e)));if(!n.ok){const s=await n.json();w.textContent=s.error||"Failed to load",R.value="";return}const t=await n.json();R.value=t.content,W=t.content,oe=t.content,w.textContent=t.size+" bytes",x.style.display=""}catch{w.textContent="Failed to load",R.value=""}}R.addEventListener("input",()=>{W=R.value}),x.addEventListener("click",async()=>{x.textContent="Saving...",x.disabled=!0;try{const e=await fetch(h("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:F,content:W})});if(!e.ok){const n=await e.json();w.textContent=n.error||"Save failed";return}oe=W,w.textContent="Saved"}catch{w.textContent="Save failed"}finally{x.disabled=!1,x.textContent="Save"}}),xe.addEventListener("click",async()=>{if(confirm("Delete "+F+"?"))try{const e=await fetch(h("/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}$.style.display="none",I.style.display="flex",k&&C(k)}catch{w.textContent="Delete failed"}}),Se.addEventListener("click",()=>{$.style.display="none",I.style.display="flex",k&&C(k)}),Me.addEventListener("click",async()=>{const e=ae.value.trim();if(!e)return;const n=k+"/"+e;try{const t=await fetch(h("/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}ae.value="",k&&C(k)}catch{w.textContent="Create failed"}}),document.getElementById("mode-settings").addEventListener("click",()=>{const e=le.classList.toggle("open");Z.classList.toggle("open",e)}),Z.addEventListener("click",()=>{le.classList.remove("open"),Z.classList.remove("open")});let S="";const A=document.createElement("div");A.className="session-popover-backdrop",document.body.appendChild(A);const E=document.createElement("div");E.id="session-popover",E.className="session-popover",E.style.display="none",E.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 ke}from"./terminal-core.js";const T=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(L);function ze(e){const n=e.getBoundingClientRect();L.style.top=n.bottom+4+"px",L.style.left=Math.max(8,Math.min(n.left,window.innerWidth-240))+"px"}function Oe(e,n){x=e;const t=document.getElementById("sp-name");t.value=e,D.classList.add("open"),L.style.display="block",ze(n),setTimeout(()=>t.focus(),50)}function P(){D.classList.remove("open"),L.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===x){P();return}try{if(!(await fetch(y("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:x,newName:e})})).ok)return;P(),M(),u===x&&R(e)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+x+'"?'))try{if(!(await fetch(y("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:x})})).ok)return;P(),u===x&&(p&&(p.destroy(),p=null),u=null,h.style.display="none",C.style.display="flex"),M()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",P);const Ue={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||!p)return;const t=Ue[n.dataset.key];t&&(p.sendInput(t),p.focus())});const w=document.getElementById("mk-input"),Le=document.getElementById("mk-send");function Ee(){if(!w||!p)return;const e=w.value;e&&(p.sendInput(e+"\r"),w.value="",w.rows=1,p.focus())}if(w&&(w.addEventListener("input",()=>{w.rows=1;const e=w.value.split(`
38
- `).length;w.rows=Math.min(e,4)}),w.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),Ee())})),Le&&Le.addEventListener("click",Ee),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 ne=document.getElementById("process-panel"),A=document.getElementById("proc-list"),Ge=document.getElementById("proc-close"),se=document.getElementById("proc-backdrop"),Ve=document.getElementById("header-ram");function qe(){A.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){A.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>'}A.innerHTML=n;for(const t of A.querySelectorAll(".proc-row")){const s=t.querySelector(".proc-kill");s&&s.addEventListener("click",i=>{const l=i.target.closest(".proc-row");!l||!confirm("Kill PID "+l.dataset.pid+"?")||fetch(y("/api/system/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(l.dataset.pid,10)})}).then(o=>o.json()).then(o=>{o.ok?l.style.opacity="0.3":alert("Failed: "+(o.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{A.innerHTML='<div class="proc-empty">Failed to load</div>'})}function Je(){ne.classList.add("open"),se.classList.add("open"),qe()}function X(){ne.classList.remove("open"),se.classList.remove("open")}Ve.addEventListener("click",e=>{e.stopPropagation(),ne.classList.contains("open")?X():Je()}),Ge.addEventListener("click",X),se.addEventListener("click",X),window.__openSession=R,window.__refreshSidebar=M,M(),Q(),setInterval(()=>{document.visibilityState==="visible"&&M()},1e4);
37
+ <button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(E);function Je(e){const n=e.getBoundingClientRect();E.style.top=n.bottom+4+"px",E.style.left=Math.max(8,Math.min(n.left,window.innerWidth-240))+"px"}function Ke(e,n){S=e;const t=document.getElementById("sp-name");t.value=e,A.classList.add("open"),E.style.display="block",Je(n),setTimeout(()=>t.focus(),50)}function D(){A.classList.remove("open"),E.style.display="none"}A.addEventListener("click",D),document.getElementById("sp-save").addEventListener("click",async()=>{const e=document.getElementById("sp-name").value.trim();if(!e||e===S){D();return}try{if(!(await fetch(h("/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:S,newName:e})})).ok)return;D(),M(),u===S&&N(e)}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+S+'"?'))try{if(!(await fetch(h("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:S})})).ok)return;D(),u===S&&(p&&(p.destroy(),p=null),u=null,b.style.display="none",I.style.display="flex"),M()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",D);const Xe={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||!p)return;const t=Xe[n.dataset.key];t&&(p.sendInput(t),p.focus())});const L=document.getElementById("mk-input"),ke=document.getElementById("mk-send");function Ce(){if(!L||!p)return;const e=L.value;e&&(p.sendInput(e+"\r"),L.value="",L.rows=1,p.focus())}if(L&&(L.addEventListener("input",()=>{L.rows=1;const e=L.value.split(`
38
+ `).length;L.rows=Math.min(e,4)}),L.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),Ce())})),ke&&ke.addEventListener("click",Ce),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 ne=document.getElementById("process-panel"),j=document.getElementById("proc-list"),Ye=document.getElementById("proc-close"),se=document.getElementById("proc-backdrop"),Ze=document.getElementById("header-ram");function Qe(){j.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(h("/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 l=i.target.closest(".proc-row");!l||!confirm("Kill PID "+l.dataset.pid+"?")||fetch(h("/api/system/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(l.dataset.pid,10)})}).then(a=>a.json()).then(a=>{a.ok?l.style.opacity="0.3":alert("Failed: "+(a.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{j.innerHTML='<div class="proc-empty">Failed to load</div>'})}function et(){ne.classList.add("open"),se.classList.add("open"),Qe()}function X(){ne.classList.remove("open"),se.classList.remove("open")}Ze.addEventListener("click",e=>{e.stopPropagation(),ne.classList.contains("open")?X():et()}),Ye.addEventListener("click",X),se.addEventListener("click",X),window.__openSession=N,window.__refreshSidebar=M,M(),Q(),setInterval(()=>{document.visibilityState==="visible"&&M()},1e4);
@@ -1,4 +1,4 @@
1
- import{cssVarsStyle as d}from"../theme.js";import{newSessionModalCSS as c,newSessionModalHTML as f,newSessionModalScript as g,reducedMotion as b}from"../shared-layout.js";import{icon as i}from"../icons.js";function h(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function o(t="var(--panel-accent)"){return`box-shadow: 0 0 0 2px ${t}; outline: none;`}function y(t){const{theme:e,fsRoots:n,terminalCfg:r,scrollback:a,wsBase:s}=t,l=`
1
+ import{cssVarsStyle as d}from"../theme.js";import{newSessionModalCSS as c,newSessionModalHTML as f,newSessionModalScript as g,reducedMotion as x}from"../shared-layout.js";import{icon as i}from"../icons.js";function h(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function o(t="var(--panel-accent)"){return`box-shadow: 0 0 0 2px ${t}; outline: none;`}function y(t){const{theme:e,fsRoots:n,terminalCfg:r,scrollback:a,wsBase:s}=t,l=`
2
2
  *, *::before, *::after { box-sizing: border-box; }
3
3
  html, body {
4
4
  background: var(--page-bg); color: var(--page-fg);
@@ -124,6 +124,25 @@ import{cssVarsStyle as d}from"../theme.js";import{newSessionModalCSS as c,newSes
124
124
  transition: color 0.15s;
125
125
  }
126
126
  .sidebar-section-label.clickable:hover { color: var(--panel-accent); }
127
+ .session-group-header {
128
+ display: flex; align-items: center; gap: 6px;
129
+ padding: 7px 12px 3px; cursor: pointer; user-select: none;
130
+ font-size: var(--text-xs); font-weight: 500; color: var(--panel-muted);
131
+ }
132
+ .session-group-header:hover { color: var(--page-fg); }
133
+ .sg-folder { flex-shrink: 0; font-size: 12px; }
134
+ .sg-label {
135
+ flex: 1; overflow: hidden; white-space: nowrap;
136
+ direction: rtl; text-align: left; text-overflow: ellipsis;
137
+ }
138
+ .sg-count {
139
+ flex-shrink: 0; font-size: 10px; font-weight: 600;
140
+ color: color-mix(in srgb, var(--panel-muted) 80%, transparent);
141
+ background: color-mix(in srgb, var(--panel-border) 55%, transparent);
142
+ border-radius: 8px; padding: 1px 6px;
143
+ }
144
+ .sg-arrow { flex-shrink: 0; font-size: 9px; }
145
+ .session-group-body.collapsed { display: none; }
127
146
  .session-item.session-offline { opacity: 0.5; cursor: default; }
128
147
  .session-item .meta { margin-left: auto; }
129
148
  .new-session-sidebar-btn {
@@ -595,7 +614,7 @@ import{cssVarsStyle as d}from"../theme.js";import{newSessionModalCSS as c,newSes
595
614
  .file-roots-list li:hover { border-color: var(--panel-accent); }
596
615
  .file-roots-list li svg { width: 20px; height: 20px; flex-shrink: 0; fill: var(--panel-accent); }
597
616
 
598
- ${b()}
617
+ ${x()}
599
618
  ${c()}
600
619
  @media (max-width: 640px) {
601
620
  .app-layout { flex-direction: column; }
@@ -607,7 +626,7 @@ import{cssVarsStyle as d}from"../theme.js";import{newSessionModalCSS as c,newSes
607
626
  .mobile-keys .mk-buttons { display: none; }
608
627
  .mobile-keys.mk-focused .mk-buttons { display: flex; flex-wrap: wrap; gap: 4px; }
609
628
  }
610
- `,x=JSON.stringify(e.terminal).replace(/</g,"\\u003c"),p=JSON.stringify({terminal:r,scrollback:a,theme:e.terminal,fsRoots:n,wsBase:s||""}).replace(/</g,"\\u003c");return`<!DOCTYPE html>
629
+ `,b=JSON.stringify(e.terminal).replace(/</g,"\\u003c"),p=JSON.stringify({terminal:r,scrollback:a,theme:e.terminal,fsRoots:n,wsBase:s||""}).replace(/</g,"\\u003c");return`<!DOCTYPE html>
611
630
  <html lang="en">
612
631
  <head>
613
632
  <meta charset="UTF-8" />
@@ -1 +1 @@
1
- import{viewKey as r}from"./pinned-views.js";import{listSessionWindows as f}from"./tmux-windows.js";function A(t,o){return t.has(r(o))}function N(t,o,d){const m=new Map(t.map(n=>[n.name,n])),c=new Set(d.map(n=>r(n.sessionName,n.windowIndex))),w=[...d].sort((n,s)=>s.pinnedAt-n.pinnedAt).map(n=>{const s=m.get(n.sessionName),e={sessionName:n.sessionName,windowIndex:n.windowIndex,pinnedAt:n.pinnedAt};if(!s)return e.missing=!0,e;if(e.windows=s.windows,e.attached=s.attached,n.windowIndex!==void 0){const a=f(n.sessionName).find(u=>u.index===n.windowIndex);a?e.windowName=a.name:e.missing=!0}return e}),p=t.map(n=>({...n,lastAccessedAt:o.get(n.name)})).filter(n=>!A(c,n.name)).sort((n,s)=>{const e=n.lastAccessedAt??0,i=s.lastAccessedAt??0;return e!==i?i-e:n.name.localeCompare(s.name)});return{pinned:w,recent:p}}export{N as buildSidebarSessions};
1
+ import{viewKey as c}from"./pinned-views.js";import{captureSessionWindowsWithPath as f,listSessionWindows as h}from"./tmux-windows.js";function A(s,i){return s.has(c(i))}function l(s){try{const i=f(s);return(i.find(a=>a.active)??i[0])?.path}catch{return}}function S(s,i,o){const a=new Map(s.map(n=>[n.name,n])),m=new Set(o.map(n=>c(n.sessionName,n.windowIndex))),w=[...o].sort((n,t)=>t.pinnedAt-n.pinnedAt).map(n=>{const t=a.get(n.sessionName),e={sessionName:n.sessionName,windowIndex:n.windowIndex,pinnedAt:n.pinnedAt};if(!t)return e.missing=!0,e;if(e.windows=t.windows,e.attached=t.attached,n.windowIndex!==void 0){const r=h(n.sessionName).find(u=>u.index===n.windowIndex);r?e.windowName=r.name:e.missing=!0}return e}),p=s.map(n=>({...n,path:l(n.name),lastAccessedAt:i.get(n.name)})).filter(n=>!A(m,n.name)).sort((n,t)=>{const e=n.lastAccessedAt??0,d=t.lastAccessedAt??0;return e!==d?d-e:n.name.localeCompare(t.name)});return{pinned:w,recent:p}}export{S as buildSidebarSessions,l as sessionWorkingPath};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmux-weblink",
3
- "version": "2.0.28",
3
+ "version": "2.0.29",
4
4
  "description": "Access your tmux sessions from the browser. A continuation of tmux-web and persalink.",
5
5
  "type": "module",
6
6
  "bin": {