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