tmux-weblink 0.3.0 → 0.3.2
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/README.md +2 -2
- package/dist/assets/terminal-client.js +2 -2
- package/dist/assets/{xterm-NI46XXQY.js → xterm-BXEES47M.js} +2 -2
- package/dist/browser/terminal-client.js +2 -2
- package/dist/index.js +1 -1
- package/dist/lib/scheduler.js +1 -1
- package/dist/lib/session-sidebar.js +253 -0
- package/dist/lib/themes/warm-clay.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ npx tmux-weblink
|
|
|
20
20
|
# Interactive setup (command bar, agents page)
|
|
21
21
|
tmux-weblink setup
|
|
22
22
|
|
|
23
|
-
# Start on default port
|
|
23
|
+
# Start on default port 21000
|
|
24
24
|
tmux-weblink
|
|
25
25
|
|
|
26
26
|
# Custom port
|
|
@@ -39,7 +39,7 @@ TMUX_WEB_TERMINAL_RENDERER=ghostty tmux-weblink
|
|
|
39
39
|
TMUX_WEB_INITIAL_LINES=1000 TMUX_WEB_HISTORY_CHUNK=500 tmux-weblink
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
Then open `http://localhost:
|
|
42
|
+
Then open `http://localhost:21000` in your browser. You'll see a list of active tmux sessions — click one to attach.
|
|
43
43
|
|
|
44
44
|
## Documentation
|
|
45
45
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var U="https://esm.sh/ghostty-web@0.4.0",J=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function y(t){return t.replace(J,"")}var b;function G(){return b||(document.querySelector("link[data-tmux-web-xterm-css]")?b=Promise.resolve():(b=new Promise(t=>{let e=document.createElement("link");e.rel="stylesheet",e.href="/assets/xterm.css",e.setAttribute("data-tmux-web-xterm-css",""),e.addEventListener("load",()=>t(),{once:!0}),e.addEventListener("error",()=>t(),{once:!0}),document.head.appendChild(e)}),b))}var Q=class q{terminal;fitAddon;container;constructor(e,n,r){this.container=e,this.terminal=n,this.fitAddon=r,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,n,r){let[{Terminal:o},{FitAddon:h}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),G()]),g=new o({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:n,convertEol:!1,theme:r});return new q(e,g,new h)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(e){return new Promise(n=>this.terminal.write(e,n))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(e){this.terminal.scrollToLine(Math.max(0,e))}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){let e=H(this.container);return e.width<=0||e.height<=0?!1:(this.fitAddon.fit(),!0)}focus(){this.terminal.focus()}pasteText(e){this.terminal.paste(e)}input(e){this.terminal.input(e,!1)}onData(e){this.terminal.onData(e),this.terminal.onBinary(e)}onResize(e){this.terminal.onResize(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){let e=document.activeElement;return!!e&&(e===this.container||this.container.contains(e))}},Z=class O{terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(e,n){this.container=e,this.terminal=n,this.terminal.open(e)}static async create(e,n,r){let o=await import(U);await o.init();let h=new o.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:n,convertEol:!1,theme:r});return new O(e,h)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(e){return new Promise(n=>this.terminal.write(e,n))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom?.()}scrollToLine(e){this.terminal.scrollToLine?.(Math.max(0,e))}isNearScrollbackTop(){let e=this.terminal.buffer?.active;return e?e.viewportY>=e.baseY:!1}viewportY(){return this.terminal.buffer?.active?.viewportY??0}baseY(){return this.terminal.buffer?.active?.baseY??0}fit(){let e=H(this.container);if(e.width<=0||e.height<=0)return!1;this.updateCellMetrics(!this.charW||!this.charH);let n=Math.floor(e.width/this.charW),r=Math.floor(e.height/this.charH);if(n<10||r<5)return!1;if(n!==this.colsValue||r!==this.rowsValue){this.colsValue=n,this.rowsValue=r,this.terminal.resize(n,r);for(let o of this.resizeCallbacks)o({cols:n,rows:r})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(e){let n=this.terminal.getMode?.(2004)??!1;this.input(n?"\x1B[200~"+e+"\x1B[201~":e)}input(e){this.terminal.input?.(e,!1)}onData(e){this.terminal.onData(n=>e(n))}onResize(e){this.resizeCallbacks.push(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){let e=document.activeElement;return!!e&&(e===this.container||e===this.terminal.textarea||this.container.contains(e))}updateCellMetrics(e=!1){let n=this.container.querySelector("canvas");if(n instanceof HTMLElement&&n.offsetWidth>0&&n.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){let r=n.offsetWidth/this.colsValue,o=n.offsetHeight/this.rowsValue;(e||!this.charW||!this.charH)&&(this.charW=r,this.charH=o)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}},W=window.__TMUX_WEB_TERMINAL__;if(!W)throw new Error("missing tmux-web terminal config");var u=W,V=document.getElementById("terminal-container");if(!V)throw new Error("missing terminal container");var i=V;function $(){let t=document.createElement("div");t.textContent="ghostty-web unavailable \u2014 using xterm.js",t.style.cssText='position:fixed;bottom:12px;right:12px;z-index:2000;background:rgba(0,0,0,0.85);color:#fbbf24;font:12px/1.4 "JetBrains Mono",monospace;padding:8px 12px;border:1px solid rgba(251,191,36,0.4);border-radius:6px;',document.body.appendChild(t),setTimeout(()=>t.remove(),6e3)}async function ee(){if(u.renderer==="ghostty")try{return await Z.create(i,u.scrollback,u.theme)}catch(t){console.error("[tmux-web] ghostty-web failed to load; falling back to xterm.js:",t),$()}return Q.create(i,u.scrollback,u.theme)}var a=await ee(),c,x=0,C,s=null,B=0,d="connecting",E=0,T=!1,k=[],m="";function te(){return k.join("")+m}async function ne(t,e=0){let n=t?a.viewportY():0,r=t?a.baseY():0,o=y(te());if(a.reset(),!o){t||a.scrollToBottom();return}await a.write(o),t?a.scrollToLine(r+n+e):a.scrollToBottom()}function re(t){let e;try{e=JSON.parse(t)}catch{d==="live"&&(m+=t,a.write(y(t)));return}if(e.type==="auth.required"){let n=localStorage.getItem("tmux-web-token");n?w({type:"auth.token",token:n}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(e.type==="auth.ok"){e.token&&localStorage.setItem("tmux-web-token",e.token),L(!0),f=1e3,p(),w({type:"resize",cols:a.cols,rows:a.rows}),l();return}if(e.type==="auth.failed"){if(L(!1),e.permanentLock||e.retryAfterMs&&e.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(e.message);return}let n=document.createElement("div");n.textContent="Auth failed: "+e.message,n.style.cssText='position:fixed;top:12px;right:12px;z-index:2000;background:rgba(0,0,0,0.85);color:#f87171;font:12px/1.4 "JetBrains Mono",monospace;padding:8px 12px;border:1px solid rgba(248,113,113,0.4);border-radius:6px;',document.body.appendChild(n),setTimeout(()=>n.remove(),4e3);return}if(e.type==="snapshot"&&typeof e.data=="string"){let n=y(e.data);k=[n],m="",E=typeof e.lines=="number"?e.lines:u.terminal.initialLines,d="live",a.reset(),a.write(n).then(()=>a.scrollToBottom());return}if(e.type==="window_changed"&&typeof e.activeIndex=="number"){let n=new URL(location.href);n.searchParams.get("window")!==String(e.activeIndex)&&(n.searchParams.set("window",String(e.activeIndex)),history.replaceState(history.state,"",n)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:e.windows}));return}if(e.type==="history"&&typeof e.data=="string"){T=!1,e.lines>0&&e.data&&(k.unshift(e.data),E+=e.lines,ne(!0,e.lines));return}if(e.type==="data"&&typeof e.data=="string"){let n=y(e.data);if(d==="connecting"){d="live",m=n,a.write(n);return}d==="live"&&(m+=n,a.write(n))}}function H(t){let e=t.getBoundingClientRect(),n=window.visualViewport;return n?{width:Math.min(e.width,n.width),height:Math.max(0,Math.min(e.height,n.height-Math.max(0,e.top)))}:e}function p(){return a.fit()}function P(){i.classList.remove("terminal-pending")}function l(){x&&cancelAnimationFrame(x),C&&clearTimeout(C),p(),x=requestAnimationFrame(()=>{x=0,p()&&P()}),C=setTimeout(()=>{p()&&P()},120)}function F(){l(),setTimeout(l,50),setTimeout(l,150),setTimeout(l,300)}var R=document.getElementById("status-dot"),S=document.getElementById("status-text");function L(t){R&&(R.className="dot"+(t?" connected":"")),S&&(S.textContent=t?"connected":"reconnecting")}var ae=location.protocol==="https:"?"wss:":"ws:",ie=ae+"//"+location.host+"/ws/"+encodeURIComponent(u.sessionName),oe="/api/session/"+encodeURIComponent(u.sessionName)+"/upload",f=1e3,se=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function w(t){c?.readyState===WebSocket.OPEN&&c.send(JSON.stringify(t))}function X(){let t=ie,e=localStorage.getItem("tmux-web-token");e&&(t+=(t.includes("?")?"&":"?")+"token="+encodeURIComponent(e)),c=new WebSocket(t),c.onopen=()=>{d="connecting",E=0,T=!1,k=[],m="",a.reset(),f=1e3},c.onmessage=n=>{typeof n.data=="string"&&re(n.data)},c.onclose=()=>{L(!1),d="connecting",setTimeout(()=>{f=Math.min(f*2,1e4),X()},f)},c.onerror=()=>c?.close()}function M(t){w({type:"input",data:t})}function le(t){M(t)}function K(t){return t.split(`\r
|
|
2
2
|
`).join(`
|
|
3
3
|
`).split(`
|
|
4
|
-
`).join("\r")}function
|
|
4
|
+
`).join("\r")}function N(t){return typeof t=="string"&&t.startsWith("image/")}function _(t){return t?.files?.length?t.files[0]??null:null}function ce(t){if(!t?.items)return null;for(let e=0;e<t.items.length;e++){let n=t.items[e];if(n?.kind==="file"&&N(n.type))return n.getAsFile()}return null}function D(t){t&&S?S.textContent=t:L(c?.readyState===WebSocket.OPEN)}async function ue(t){let e=new FormData,n=t instanceof File&&t.name?t.name:"upload";e.append("file",t,n);let r=localStorage.getItem("tmux-web-token"),o={};r&&(o.Authorization="Bearer "+r);let h=await fetch(oe,{method:"POST",body:e,headers:o});if(!h.ok){let z="upload failed";try{let A=await h.json();A.error&&(z=A.error)}catch{}throw new Error(z)}let g=await h.json();if(!g.path)throw new Error("no path in response");return g.path}async function I(t){try{D("uploading...");let e=await ue(t);le(e),D(null)}catch(e){console.warn("image upload:",e),D("upload failed"),setTimeout(()=>D(null),2e3)}}a.onData(t=>M(t)),a.onResize(({cols:t,rows:e})=>w({type:"resize",cols:t,rows:e})),window.tmuxWeb={sendInput:M,focusTerminal:j},a.onScroll(()=>{d!=="live"||T||!a.isNearScrollbackTop()||(T=!0,w({type:"load_history",before:E}))}),a.attachCustomKeyEventHandler(t=>t.type!=="keydown"?!0:(t.ctrlKey||t.metaKey)&&t.code==="KeyV"?(t.preventDefault(),(async()=>{try{if(navigator.clipboard?.read){let e=await navigator.clipboard.read();for(let n of e)for(let r of n.types)if(N(r)){let o=await n.getType(r);await I(o);return}}}catch{}try{let e=await navigator.clipboard?.readText();e&&a.pasteText(K(e))}catch{}})(),!1):!0);var Y=0;async function de(t){let e=ce(t.clipboardData);if(e){t.preventDefault(),t.stopPropagation();let o=Date.now();if(o-Y<50)return;Y=o,await I(e);return}let n=t.clipboardData?.getData("text/plain");if(!n)return;t.preventDefault(),t.stopPropagation();let r=Date.now();r-Y<50||(Y=r,a.pasteText(K(n)))}i.addEventListener("paste",de);var v=0;i.addEventListener("dragenter",t=>{t.preventDefault(),v++,_(t.dataTransfer)&&i.classList.add("terminal-drag-over")}),i.addEventListener("dragover",t=>{t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy")}),i.addEventListener("dragleave",t=>{t.preventDefault(),v--,v<=0&&(v=0,i.classList.remove("terminal-drag-over"))}),i.addEventListener("drop",async t=>{t.preventDefault(),v=0,i.classList.remove("terminal-drag-over");let e=_(t.dataTransfer);e&&await I(e)}),document.addEventListener("keydown",t=>{!se||t.key!=="Escape"||t.defaultPrevented||t.repeat||t.metaKey||t.ctrlKey||t.altKey||a.isFocused()&&(t.preventDefault(),t.stopPropagation(),M("\x1B"))},!0);function he(t,e,n){(i.querySelector(".xterm-screen")??i).dispatchEvent(new WheelEvent("wheel",{deltaY:t,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:e,clientY:n,bubbles:!0,cancelable:!0}))}function j(){a.focus(),F()}i.addEventListener("touchstart",t=>{if(t.touches.length!==1){s=null;return}let e=t.touches[0];e&&(s={startX:e.clientX,startY:e.clientY,lastX:e.clientX,lastY:e.clientY,scrolling:!1},t.stopPropagation())},{passive:!0,capture:!0}),i.addEventListener("touchmove",t=>{if(!s||t.touches.length!==1)return;let e=t.touches[0];if(!e)return;let n=e.clientY-s.startY,r=e.clientX-s.startX;if(!s.scrolling){if(Math.abs(n)<8||Math.abs(n)<Math.abs(r))return;s.scrolling=!0,B=Date.now()+500}t.preventDefault(),t.stopPropagation(),he(-(e.clientY-s.lastY),e.clientX,e.clientY),s.lastX=e.clientX,s.lastY=e.clientY},{passive:!1,capture:!0}),i.addEventListener("touchend",t=>{if(!s)return;let e=s.scrolling;s=null,t.stopPropagation(),e?(B=Date.now()+500,t.preventDefault()):j()},{passive:!1,capture:!0}),i.addEventListener("touchcancel",t=>{s=null,t.stopPropagation()},{passive:!0,capture:!0}),i.addEventListener("pointerup",t=>{t.pointerType==="touch"&&Date.now()<B&&(t.preventDefault(),t.stopPropagation())},!0),window.addEventListener("resize",l),window.visualViewport?.addEventListener("resize",l),window.visualViewport?.addEventListener("scroll",l),new ResizeObserver(l).observe(i),document.fonts?.ready.then(()=>{l(),setTimeout(l,50),setTimeout(l,200)}),i.addEventListener("focusin",F,!0),requestAnimationFrame(()=>{p()&&P(),X(),l()});
|