tmux-weblink 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/addon-fit-D5N335P2.js +3 -2
- package/dist/assets/shell-client.js +13 -7
- package/dist/assets/xterm-BXEES47M.js +15 -14
- package/dist/browser/shell-client.js +790 -6
- package/dist/browser/terminal-core.js +640 -4
- package/dist/frontend.js +9 -1
- package/dist/index.js +1646 -9
- package/dist/lib/agent-detect.js +249 -3
- package/dist/lib/agents-watch.js +2 -2
- package/dist/lib/atomicWrite.js +24 -1
- package/dist/lib/auditLog.js +40 -1
- package/dist/lib/auth.js +194 -2
- package/dist/lib/cli.js +162 -10
- package/dist/lib/commandbar.js +47 -17
- package/dist/lib/db.js +8 -1
- package/dist/lib/drawer-resize.js +25 -10
- package/dist/lib/drawer-script.js +13 -6
- package/dist/lib/ext-loader.js +168 -1
- package/dist/lib/fs-access.js +58 -1
- package/dist/lib/html.js +11 -1
- package/dist/lib/icons.js +73 -1
- package/dist/lib/image-upload.js +87 -1
- package/dist/lib/load-env.js +76 -6
- package/dist/lib/notes-db.js +4 -2
- package/dist/lib/notes-drawer.js +29 -12
- package/dist/lib/notes-utils.js +4 -2
- package/dist/lib/pages/files-index.js +26 -18
- package/dist/lib/pages/history-index.js +59 -17
- package/dist/lib/pages/login.js +35 -13
- package/dist/lib/pages/notes-index.js +45 -20
- package/dist/lib/pages/notes-page.js +28 -13
- package/dist/lib/pages/quick-commands.js +38 -22
- package/dist/lib/pages/schedule-index.js +81 -45
- package/dist/lib/pages/settings.js +76 -30
- package/dist/lib/pages/shell.js +269 -214
- package/dist/lib/pinned-views.js +38 -1
- package/dist/lib/plugins.js +108 -3
- package/dist/lib/quick-commands.js +79 -1
- package/dist/lib/rateLimiter.js +142 -2
- package/dist/lib/schedule-delay.js +36 -2
- package/dist/lib/scheduler-drawer.js +30 -14
- package/dist/lib/scheduler.js +263 -1
- package/dist/lib/security-config.js +65 -2
- package/dist/lib/session-access.js +19 -1
- package/dist/lib/session-windows.js +41 -1
- package/dist/lib/sessions-drawer.js +30 -16
- package/dist/lib/sessions-sidebar.js +50 -1
- package/dist/lib/settings.js +16 -2
- package/dist/lib/setup-features.js +37 -1
- package/dist/lib/setup-prompts.js +50 -3
- package/dist/lib/shared-layout.js +115 -51
- package/dist/lib/state-paths.js +41 -1
- package/dist/lib/system-monitor.js +98 -2
- package/dist/lib/terminal-config.js +14 -1
- package/dist/lib/theme-store.js +53 -2
- package/dist/lib/theme.js +15 -12
- package/dist/lib/themes/dark-cove.js +40 -1
- package/dist/lib/themes/ghostty.js +40 -1
- package/dist/lib/themes/index.js +28 -1
- package/dist/lib/themes/types.js +1 -0
- package/dist/lib/themes/vscode.js +40 -1
- package/dist/lib/themes/warm-clay.js +40 -1
- package/dist/lib/tmux-capture.js +71 -5
- package/dist/lib/tmux-control.js +153 -2
- package/dist/lib/tmux-panes.js +40 -2
- package/dist/lib/tmux-windows.js +149 -4
- package/dist/lib/watched-panes.js +1 -1
- package/dist/lib/window-history.js +32 -1
- package/dist/lib/window-labels.js +27 -1
- package/dist/lib/windows-drawer.js +21 -10
- package/dist/lib/ws-message.js +21 -1
- package/dist/sessions.js +21 -2
- package/package.json +6 -4
- package/scripts/generate-icons.mjs +167 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
var p=2,c=1,d=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let i=this._terminal._core;(this._terminal.rows!==e.rows||this._terminal.cols!==e.cols)&&(i._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core._renderService.dimensions;if(e.css.cell.width===0||e.css.cell.height===0)return;let i=this._terminal.options.scrollback===0?0:this._terminal.options.overviewRuler?.width||14,s=window.getComputedStyle(this._terminal.element.parentElement),l=parseInt(s.getPropertyValue("height")),o=Math.max(0,parseInt(s.getPropertyValue("width"))),t=window.getComputedStyle(this._terminal.element),r={top:parseInt(t.getPropertyValue("padding-top")),bottom:parseInt(t.getPropertyValue("padding-bottom")),right:parseInt(t.getPropertyValue("padding-right")),left:parseInt(t.getPropertyValue("padding-left"))},a=r.top+r.bottom,n=r.right+r.left,h=l-a,m=o-n-i;return{cols:Math.max(p,Math.floor(m/e.css.cell.width)),rows:Math.max(c,Math.floor(h/e.css.cell.height))}}}
|
|
1
|
+
var p=2,c=1,d=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let i=this._terminal._core;(this._terminal.rows!==e.rows||this._terminal.cols!==e.cols)&&(i._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core._renderService.dimensions;if(e.css.cell.width===0||e.css.cell.height===0)return;let i=this._terminal.options.scrollback===0?0:this._terminal.options.overviewRuler?.width||14,s=window.getComputedStyle(this._terminal.element.parentElement),l=parseInt(s.getPropertyValue("height")),o=Math.max(0,parseInt(s.getPropertyValue("width"))),t=window.getComputedStyle(this._terminal.element),r={top:parseInt(t.getPropertyValue("padding-top")),bottom:parseInt(t.getPropertyValue("padding-bottom")),right:parseInt(t.getPropertyValue("padding-right")),left:parseInt(t.getPropertyValue("padding-left"))},a=r.top+r.bottom,n=r.right+r.left,h=l-a,m=o-n-i;return{cols:Math.max(p,Math.floor(m/e.css.cell.width)),rows:Math.max(c,Math.floor(h/e.css.cell.height))}}};export{d as FitAddon};
|
|
2
|
+
/*! Bundled license information:
|
|
2
3
|
|
|
3
4
|
@xterm/addon-fit/lib/addon-fit.mjs:
|
|
4
5
|
(**
|
|
@@ -13,4 +14,4 @@ var p=2,c=1,d=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.pro
|
|
|
13
14
|
* http://bellard.org/jslinux/
|
|
14
15
|
* Copyright (c) 2011 Fabrice Bellard
|
|
15
16
|
*)
|
|
16
|
-
*/
|
|
17
|
+
*/
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
var
|
|
1
|
+
var at="https://esm.sh/ghostty-web@0.4.0",lt=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function X(t){return t.replace(lt,"")}var A;function ct(){return A||(document.querySelector("link[data-tmux-web-xterm-css]")?A=Promise.resolve():(A=new Promise(e=>{let s=document.createElement("link");s.rel="stylesheet",s.href="/assets/xterm.css",s.setAttribute("data-tmux-web-xterm-css",""),s.addEventListener("load",()=>e(),{once:!0}),s.addEventListener("error",()=>e(),{once:!0}),document.head.appendChild(s)}),A))}var G=class t{terminal;fitAddon;container;constructor(e,s,i){this.container=e,this.terminal=s,this.fitAddon=i,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,s,i){let[{Terminal:r},{FitAddon:c}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),ct()]),d=new r({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:s,convertEol:!1,theme:i});return new t(e,d,new c)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(e){return new Promise(s=>this.terminal.write(e,s))}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=Ce(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))}},ce=class t{terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(e,s){this.container=e,this.terminal=s,this.terminal.open(e)}static async create(e,s,i){let r=await import(at);await r.init();let c=new r.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:s,convertEol:!1,theme:i});return new t(e,c)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(e){return new Promise(s=>this.terminal.write(e,s))}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=Ce(this.container);if(e.width<=0||e.height<=0)return!1;this.updateCellMetrics(!this.charW||!this.charH);let s=Math.floor(e.width/this.charW),i=Math.floor(e.height/this.charH);if(s<10||i<5)return!1;if(s!==this.colsValue||i!==this.rowsValue){this.colsValue=s,this.rowsValue=i,this.terminal.resize(s,i);for(let r of this.resizeCallbacks)r({cols:s,rows:i})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(e){let s=this.terminal.getMode?.(2004)??!1;this.input(s?"\x1B[200~"+e+"\x1B[201~":e)}input(e){this.terminal.input?.(e,!1)}onData(e){this.terminal.onData(s=>e(s))}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 s=this.container.querySelector("canvas");if(s instanceof HTMLElement&&s.offsetWidth>0&&s.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){let i=s.offsetWidth/this.colsValue,r=s.offsetHeight/this.rowsValue;(e||!this.charW||!this.charH)&&(this.charW=i,this.charH=r)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}};function Ce(t){let e=t.getBoundingClientRect(),s=window.visualViewport;return s?{width:Math.min(e.width,s.width),height:Math.max(0,Math.min(e.height,s.height-Math.max(0,e.top)))}:e}function Ie(t,e,s){return t.innerHTML="",t.classList.add("terminal-pending"),(async()=>{let i;if(s.renderer==="ghostty")try{i=await ce.create(t,s.scrollback,s.theme)}catch{console.error("[tmux-web] ghostty-web failed; falling back to xterm.js"),i=await G.create(t,s.scrollback,s.theme)}else i=await G.create(t,s.scrollback,s.theme);let r,c=0,d,a=null,y=0,f="connecting",b=0,k=!1,U=[],H="",oe=!1,D=1e3,Oe=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/"+encodeURIComponent(e),Ve="/api/session/"+encodeURIComponent(e)+"/upload",We=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function _e(){return U.join("")+H}async function Ke(n,o=0){let l=n?i.viewportY():0,g=n?i.baseY():0,E=X(_e());if(i.reset(),!E){n||i.scrollToBottom();return}await i.write(E),n?i.scrollToLine(g+l+o):i.scrollToBottom()}function P(n){r?.readyState===WebSocket.OPEN&&r.send(JSON.stringify(n))}function Ue(n){let o;try{o=JSON.parse(n)}catch{f==="live"&&(H+=n,i.write(X(n)));return}if(o.type==="auth.required"){let l=localStorage.getItem("tmux-web-token");l?P({type:"auth.token",token:l}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(o.type==="auth.ok"){o.token&&localStorage.setItem("tmux-web-token",o.token),D=1e3,R(),P({type:"resize",cols:i.cols,rows:i.rows}),h();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 l=X(o.data);U=[l],H="",b=typeof o.lines=="number"?o.lines:s.terminal.initialLines,f="live",i.reset(),i.write(l).then(()=>i.scrollToBottom());return}if(o.type==="window_changed"&&typeof o.activeIndex=="number"){let l=new URL(location.href);l.searchParams.get("window")!==String(o.activeIndex)&&(l.searchParams.set("window",String(o.activeIndex)),history.replaceState(history.state,"",l)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:o.windows}));return}if(o.type==="history"&&typeof o.data=="string"){k=!1,o.lines>0&&o.data&&(U.unshift(o.data),b+=o.lines,Ke(!0,o.lines));return}if(o.type==="data"&&typeof o.data=="string"){let l=X(o.data);if(f==="connecting"){f="live",H=l,i.write(l);return}f==="live"&&(H+=l,i.write(l))}}function ye(){let n=Oe,o=localStorage.getItem("tmux-web-token");o&&(n+=(n.includes("?")?"&":"?")+"token="+encodeURIComponent(o)),r=new WebSocket(n),r.onopen=()=>{f="connecting",b=0,k=!1,U=[],H="",i.reset(),D=1e3},r.onmessage=l=>{typeof l.data=="string"&&Ue(l.data)},r.onclose=()=>{oe||(f="connecting",setTimeout(()=>{D=Math.min(D*2,1e4),oe||ye()},D))},r.onerror=()=>r?.close()}function $(n){P({type:"input",data:n})}function R(){return i.fit()}function re(){t.classList.remove("terminal-pending")}function h(){c&&cancelAnimationFrame(c),d&&clearTimeout(d),R(),c=requestAnimationFrame(()=>{c=0,R()&&re()}),d=setTimeout(()=>{R()&&re()},120)}function $e(){h(),setTimeout(h,50),setTimeout(h,150),setTimeout(h,300)}function be(n){return typeof n=="string"&&n.startsWith("image/")}function we(n){return n?.files?.length?n.files[0]??null:null}function qe(n){if(!n?.items)return null;for(let o=0;o<n.items.length;o++){let l=n.items[o];if(l?.kind==="file"&&be(l.type))return l.getAsFile()}return null}async function Xe(n){let o=new FormData,l=n instanceof File&&n.name?n.name:"upload";o.append("file",n,l);let g=localStorage.getItem("tmux-web-token"),E={};g&&(E.Authorization="Bearer "+g);let le=await fetch(Ve,{method:"POST",body:o,headers:E});if(!le.ok){let xe="upload failed";try{let Se=await le.json();Se.error&&(xe=Se.error)}catch{}throw new Error(xe)}let Me=await le.json();if(!Me.path)throw new Error("no path in response");return Me.path}async function ae(n){try{let o=await Xe(n);$(o)}catch{}}i.onData(n=>$(n)),i.onResize(({cols:n,rows:o})=>P({type:"resize",cols:n,rows:o})),i.onScroll(()=>{f!=="live"||k||!i.isNearScrollbackTop()||(k=!0,P({type:"load_history",before:b}))}),i.attachCustomKeyEventHandler(n=>n.type!=="keydown"?!0:(n.ctrlKey||n.metaKey)&&n.code==="KeyV"?(n.preventDefault(),(async()=>{try{if(navigator.clipboard?.read){let o=await navigator.clipboard.read();for(let l of o)for(let g of l.types)if(be(g)){let E=await l.getType(g);await ae(E);return}}}catch{}try{let o=await navigator.clipboard?.readText();o&&i.pasteText(Ee(o))}catch{}})(),!1):!0);let q=0;function Ee(n){return n.split(`\r
|
|
2
2
|
`).join(`
|
|
3
3
|
`).split(`
|
|
4
|
-
`).join("\r")}async function
|
|
5
|
-
<span>${
|
|
6
|
-
<button class="session-edit-btn" data-session="${
|
|
7
|
-
`,
|
|
4
|
+
`).join("\r")}async function Ge(n){let o=qe(n.clipboardData);if(o){n.preventDefault(),n.stopPropagation();let E=Date.now();if(E-q<50)return;q=E,await ae(o);return}let l=n.clipboardData?.getData("text/plain");if(!l)return;n.preventDefault(),n.stopPropagation();let g=Date.now();g-q<50||(q=g,i.pasteText(Ee(l)))}let F=0;function Je(n){n.preventDefault(),F++,we(n.dataTransfer)&&t.classList.add("terminal-drag-over")}function Ze(n){n.preventDefault(),n.dataTransfer&&(n.dataTransfer.dropEffect="copy")}function Qe(n){n.preventDefault(),F--,F<=0&&(F=0,t.classList.remove("terminal-drag-over"))}async function et(n){n.preventDefault(),F=0,t.classList.remove("terminal-drag-over");let o=we(n.dataTransfer);o&&await ae(o)}function Te(n){!We||n.key!=="Escape"||n.defaultPrevented||n.repeat||n.metaKey||n.ctrlKey||n.altKey||i.isFocused()&&(n.preventDefault(),n.stopPropagation(),$("\x1B"))}t.addEventListener("paste",Ge),t.addEventListener("dragenter",Je),t.addEventListener("dragover",Ze),t.addEventListener("dragleave",Qe),t.addEventListener("drop",et),document.addEventListener("keydown",Te,!0);function tt(n){if(n.touches.length!==1){a=null;return}let o=n.touches[0];o&&(a={startX:o.clientX,startY:o.clientY,lastX:o.clientX,lastY:o.clientY,scrolling:!1},n.stopPropagation())}function nt(n){if(!a||n.touches.length!==1)return;let o=n.touches[0];if(!o)return;let l=o.clientY-a.startY,g=o.clientX-a.startX;if(!a.scrolling){if(Math.abs(l)<8||Math.abs(l)<Math.abs(g))return;a.scrolling=!0,y=Date.now()+500}n.preventDefault(),n.stopPropagation(),rt(-(o.clientY-a.lastY),o.clientX,o.clientY),a.lastX=o.clientX,a.lastY=o.clientY}function st(n){if(!a)return;let o=a.scrolling;a=null,n.stopPropagation(),o?(y=Date.now()+500,n.preventDefault()):i.focus()}function it(n){a=null,n.stopPropagation()}function ot(n){n.pointerType==="touch"&&Date.now()<y&&(n.preventDefault(),n.stopPropagation())}function rt(n,o,l){(t.querySelector(".xterm-screen")??t).dispatchEvent(new WheelEvent("wheel",{deltaY:n,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:o,clientY:l,bubbles:!0,cancelable:!0}))}t.addEventListener("touchstart",tt,{passive:!0,capture:!0}),t.addEventListener("touchmove",nt,{passive:!1,capture:!0}),t.addEventListener("touchend",st,{passive:!1,capture:!0}),t.addEventListener("touchcancel",it,{passive:!0,capture:!0}),t.addEventListener("pointerup",ot,!0);function Le(){h()}window.addEventListener("resize",Le),window.visualViewport?.addEventListener("resize",h),window.visualViewport?.addEventListener("scroll",h);let ke=new ResizeObserver(()=>h());return ke.observe(t),document.fonts?.ready.then(()=>{h(),setTimeout(h,50),setTimeout(h,200)}),t.addEventListener("focusin",$e,!0),requestAnimationFrame(()=>{R()&&re(),ye(),h()}),{destroy(){if(oe=!0,r){try{r.close(1e3,"session switch")}catch{}r=void 0}t.innerHTML="",t.classList.remove("terminal-pending"),window.removeEventListener("resize",Le),ke.disconnect(),document.removeEventListener("keydown",Te,!0)},focus(){i.focus()},sendInput(n){$(n)}}})()}var Y=window.__TMUX_WEB_SHELL__,p=null,v=null,Re="sessions",x="",Q="",ee="",Fe="",u=document.getElementById("sidebar-content"),W=document.getElementById("main-placeholder"),C=document.getElementById("terminal-container"),se=document.getElementById("file-editor"),dt=document.getElementById("fe-path"),w=document.getElementById("fe-status"),j=document.getElementById("fe-content"),I=document.getElementById("fe-save"),ut=document.getElementById("fe-delete"),mt=document.getElementById("fe-back"),Be=document.getElementById("fe-new-name"),pt=document.getElementById("fe-new-btn"),de=document.getElementById("settings-backdrop"),Ae=document.getElementById("settings-popover"),ze=document.querySelector(".sidebar");function ft(){return window.matchMedia("(max-width: 640px)").matches}function ue(){ft()&&ze.classList.add("collapsed")}function Ye(){ze.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{Ye(),Ne("sessions")});document.getElementById("mode-files").addEventListener("click",()=>{Ye(),Ne("files")});function Ne(t){Re=t,document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));let e=document.getElementById(t==="sessions"?"mode-sessions":"mode-files");e&&e.classList.add("active"),t==="sessions"?_():wt()}async function _(){u.innerHTML='<div class="sidebar-section-label">Sessions</div><button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';try{let i=(await(await fetch("/api/sidebar/sessions")).json()).recent||[];for(let r of i){let c=document.createElement("div");c.className="session-item"+(r.name===v?" active":""),c.setAttribute("data-session",r.name),c.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>
|
|
5
|
+
<span>${L(r.name)}</span>
|
|
6
|
+
<button class="session-edit-btn" data-session="${L(r.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>
|
|
7
|
+
`,c.addEventListener("click",a=>{a.target.closest(".session-edit-btn")||me(r.name)}),u.appendChild(c);let d=c.querySelector(".session-edit-btn");d&&d.addEventListener("click",a=>{a.stopPropagation(),Mt(r.name,d)})}}catch{u.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}let t=document.getElementById("ns-btn");t&&t.addEventListener("click",()=>document.getElementById("new-session-modal")?.classList.add("open"))}function L(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}async function me(t){if(!(v===t&&p)){se.style.display="none",W.style.display="none",C.style.display="",C.classList.add("terminal-pending"),ue(),p&&(he(),p.destroy(),p=null),v=t;for(let e of u.querySelectorAll(".session-item"))e.classList.toggle("active",e.getAttribute("data-session")===t);try{p=await Ie(C,t,{terminal:Y.terminal,scrollback:Y.scrollback,theme:Y.theme,renderer:Y.renderer}),bt()}catch(e){console.error("[shell] terminal init failed:",e);let s=e&&typeof e=="object"&&"message"in e?e.message:String(e);C.textContent="Failed to open terminal for "+t+": "+s,C.classList.remove("terminal-pending")}}}var J=[],m=null,He=!1;function ht(t){if(!m||!m.files.length)return null;let e=m.repoRoot;if(!e||!t.startsWith(e))return null;let s=t.slice(e.length+1);for(let i of m.files)if(i.path===s)return i.status;return null}async function gt(t){He=!0;try{let e=await fetch("/api/git/status?path="+encodeURIComponent(t));e.ok?m=await e.json():m=null}catch{m=null}finally{He=!1}}function vt(){if(!m||!m.branch)return"";let{branch:t,linesAdded:e,linesRemoved:s}=m,i="";return(e>0||s>0)&&(i=`<div class="git-diff-stats">+<span class="add">${e}</span> <span class="del">-${s}</span></div>`),`<div class="git-branch-badge">
|
|
8
|
+
<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>
|
|
9
|
+
${L(t)}</div>${i}`}var O=document.getElementById("header-git"),te=null;function ne(t){if(!t||!t.branch){O.style.display="none",te=null;return}te=t.repoRoot;let{branch:e,linesAdded:s,linesRemoved:i}=t,r=`<span class="branch">${L(e)}</span>`;(s>0||i>0)&&(r+=`<span class="diff-stats"><span class="sep">\xB7</span>+<span class="diff-add">${s}</span> <span class="diff-del">-${i}</span></span>`),O.innerHTML=r,O.style.display="block"}O.addEventListener("click",t=>{te&&m&&m.files.length>0&&(t.stopPropagation(),yt())});var N=document.getElementById("git-popover"),pe=document.getElementById("git-popover-backdrop");function yt(){if(!m||!m.files.length)return;let t=m.files,e=`<div class="git-popover-header">${t.length} file${t.length>1?"s":""} changed</div>`;for(let r of t){let c=r.additions||0,d=r.deletions||0,a="";switch(r.status){case"M":a='<span class="git-file-status M">M</span>';break;case"A":a='<span class="git-file-status A">A</span>';break;case"D":a='<span class="git-file-status D">D</span>';break;case"?":a='<span class="git-file-status ?">?</span>';break;case"R":a='<span class="git-file-status R">R</span>';break}e+=`<div class="git-popover-item">
|
|
10
|
+
${a}<span class="file-path">${L(r.path)}</span>
|
|
11
|
+
<span class="file-add">${c>0?"+"+c:""}</span>
|
|
12
|
+
<span class="file-del">${d>0?"-"+d:""}</span>
|
|
13
|
+
</div>`}e+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',N.innerHTML=e;let s=O.getBoundingClientRect();N.style.top=s.bottom+4+"px",N.style.left=Math.max(8,Math.min(s.left,window.innerWidth-400))+"px",N.classList.add("open"),pe.classList.add("open");let i=te;document.getElementById("git-popover-browse").addEventListener("click",()=>{if(fe(),i){Re="files",document.querySelectorAll(".mode-btn").forEach(c=>c.classList.remove("active"));let r=document.getElementById("mode-files");r&&r.classList.add("active"),S(i)}})}function fe(){N.classList.remove("open"),pe.classList.remove("open")}pe.addEventListener("click",fe);document.addEventListener("keydown",t=>{t.key==="Escape"&&(fe(),ie())});async function De(t){try{let s=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(t))).json();if(s.path){let i=await fetch("/api/git/status?path="+encodeURIComponent(s.path));if(i.ok){let r=await i.json();m=r,ne(r);return}}}catch{}m=null,ne(null)}var Z=null;function bt(){he(),v&&(De(v),Z=setInterval(()=>{v&&De(v)},3e4))}function he(){Z&&(clearInterval(Z),Z=null)}function wt(){if(J=Y.fsRoots||[],J.length===0){if(v){Et(v);return}u.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}u.innerHTML="";for(let t of J){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> ${L(t)}`,e.addEventListener("click",()=>S(t)),u.appendChild(e)}}async function Et(t){u.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let s=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(t))).json();s.path?S(s.path):u.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{u.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function S(t){x=t,u.innerHTML='<div class="file-tree-empty">Loading...</div>';let e=gt(t);try{let i=await(await fetch("/api/fs/list?path="+encodeURIComponent(t))).json();await e,u.innerHTML="",ne(m),u.innerHTML+=vt();let r=Tt(t);if(r&&!J.some(a=>t===a)){let a=document.createElement("div");a.className="file-tree-item",a.innerHTML="..",a.addEventListener("click",()=>S(r)),u.appendChild(a)}if(i.dirs)for(let d of i.dirs){let a=d.split("/").pop()||d.split("\\").pop(),y=document.createElement("div");y.className="file-tree-item",y.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> ${L(a)}`,y.addEventListener("click",()=>S(d)),u.appendChild(y)}else u.innerHTML="";let c=i.files||[];for(let d of c){let a=d.split("/").pop()||d.split("\\").pop(),y=ht(d),f="",b="";if(y)switch(y){case"M":f="git-mod",b='<span class="git-file-status M">M</span>';break;case"A":f="git-add",b='<span class="git-file-status A">A</span>';break;case"D":f="git-del",b='<span class="git-file-status D">D</span>';break;case"?":f="git-untracked",b='<span class="git-file-status ?">?</span>';break;case"R":f="git-mod",b='<span class="git-file-status R">R</span>';break}let k=document.createElement("div");k.className="file-tree-item file"+(f?" "+f:""),k.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${b}${L(a)}`,k.addEventListener("click",()=>Lt(d)),u.appendChild(k)}}catch{u.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function Tt(t){let e=t.lastIndexOf("/");return e<=0?null:t.substring(0,e)}async function Lt(t){Q=t,C.style.display="none",p&&(he(),p.destroy(),p=null,v=null),ne(null),ue(),W.style.display="none",se.style.display="flex",dt.textContent=t,w.textContent="Loading...",I.style.display="none";try{let e=await fetch("/api/file?path="+encodeURIComponent(t));if(!e.ok){let i=await e.json();w.textContent=i.error||"Failed to load",j.value="";return}let s=await e.json();j.value=s.content,ee=s.content,Fe=s.content,w.textContent=s.size+" bytes",I.style.display=""}catch{w.textContent="Failed to load",j.value=""}}j.addEventListener("input",()=>{ee=j.value});I.addEventListener("click",async()=>{I.textContent="Saving...",I.disabled=!0;try{let t=await fetch("/api/file",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Q,content:ee})});if(!t.ok){let e=await t.json();w.textContent=e.error||"Save failed";return}Fe=ee,w.textContent="Saved"}catch{w.textContent="Save failed"}finally{I.disabled=!1,I.textContent="Save"}});ut.addEventListener("click",async()=>{if(confirm("Delete "+Q+"?"))try{let t=await fetch("/api/file/delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:Q})});if(!t.ok){let e=await t.json();w.textContent=e.error||"Delete failed";return}se.style.display="none",W.style.display="flex",x&&S(x)}catch{w.textContent="Delete failed"}});mt.addEventListener("click",()=>{se.style.display="none",W.style.display="flex",x&&S(x)});pt.addEventListener("click",async()=>{let t=Be.value.trim();if(!t)return;let e=x+"/"+t;try{let s=await fetch("/api/file/touch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})});if(!s.ok){let i=await s.json();w.textContent=i.error||"Create failed";return}Be.value="",x&&S(x)}catch{w.textContent="Create failed"}});document.getElementById("mode-settings").addEventListener("click",()=>{let t=Ae.classList.toggle("open");de.classList.toggle("open",t)});de.addEventListener("click",()=>{Ae.classList.remove("open"),de.classList.remove("open")});var B="",K=document.createElement("div");K.className="session-popover-backdrop";document.body.appendChild(K);var M=document.createElement("div");M.id="session-popover";M.className="session-popover";M.style.display="none";M.innerHTML=`<div class="sp-field">
|
|
8
14
|
<label>Rename session</label>
|
|
9
15
|
<input type="text" id="sp-name" />
|
|
10
16
|
</div>
|
|
@@ -13,5 +19,5 @@ var Ke="https://esm.sh/ghostty-web@0.4.0",Xe=/\x1b\](?:10|11|110|111|104)(?:;[^\
|
|
|
13
19
|
<button class="btn" id="sp-cancel">Cancel</button>
|
|
14
20
|
</div>
|
|
15
21
|
<hr class="sp-divider" />
|
|
16
|
-
<button class="btn danger" id="sp-delete">Delete session</button
|
|
17
|
-
`).length;
|
|
22
|
+
<button class="btn danger" id="sp-delete">Delete session</button>`;document.body.appendChild(M);function kt(t){let e=t.getBoundingClientRect();M.style.top=e.bottom+4+"px",M.style.left=Math.max(8,Math.min(e.left,window.innerWidth-240))+"px"}function Mt(t,e){B=t;let s=document.getElementById("sp-name");s.value=t,K.classList.add("open"),M.style.display="block",kt(e),setTimeout(()=>s.focus(),50)}function V(){K.classList.remove("open"),M.style.display="none"}K.addEventListener("click",V);document.getElementById("sp-save").addEventListener("click",async()=>{let t=document.getElementById("sp-name").value.trim();if(!t||t===B){V();return}try{if(!(await fetch("/api/sessions/rename",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:B,newName:t})})).ok)return;V(),_(),v===B&&me(t)}catch{}});document.getElementById("sp-delete").addEventListener("click",async()=>{if(confirm('Delete session "'+B+'"?'))try{if(!(await fetch("/api/sessions/kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:B})})).ok)return;V(),v===B&&(p&&(p.destroy(),p=null),v=null,C.style.display="none",W.style.display="flex"),_()}catch{}});document.getElementById("sp-cancel").addEventListener("click",V);var xt={esc:"\x1B",tab:" ","s-tab":"\x1B[Z",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",space:" ",enter:"\r",exit:"exit\r",yes:"yes\r"};document.getElementById("mobile-keys").addEventListener("click",t=>{let e=t.target.closest("button[data-key]");if(!e||!p)return;let s=xt[e.dataset.key];s&&(p.sendInput(s),p.focus())});var T=document.getElementById("mk-input"),Pe=document.getElementById("mk-send");function je(){if(!T||!p)return;let t=T.value;t&&(p.sendInput(t+"\r"),T.value="",T.rows=1,p.focus())}T&&(T.addEventListener("input",()=>{T.rows=1;let t=T.value.split(`
|
|
23
|
+
`).length;T.rows=Math.min(t,4)}),T.addEventListener("keydown",t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),je())}));Pe&&Pe.addEventListener("click",je);if(window.visualViewport){let t=document.querySelector(".app-layout"),e=()=>{t&&(t.style.height=window.visualViewport.height+"px"),window.scrollTo(0,0),document.documentElement.scrollTop=0,document.body.scrollTop=0};window.visualViewport.addEventListener("resize",e),window.addEventListener("orientationchange",()=>setTimeout(e,100)),document.addEventListener("touchstart",()=>{(window.scrollY>0||document.documentElement.scrollTop>0)&&window.scrollTo(0,0)},{passive:!0})}var ge=document.getElementById("process-panel"),z=document.getElementById("proc-list"),St=document.getElementById("proc-close"),ve=document.getElementById("proc-backdrop"),Ct=document.getElementById("header-ram");function It(){z.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch("/api/system/processes").then(t=>t.json()).then(t=>{if(!Array.isArray(t)||!t.length){z.innerHTML='<div class="proc-empty">No processes</div>';return}let e="";for(let s of t){let i=s.rss,r=i<1048576?(i/1024).toFixed(0)+"K":(i/1048576).toFixed(1)+"M";e+='<div class="proc-row" data-pid="'+s.pid+'"><span class="proc-mem">'+s.mem+'%</span><span class="proc-rss">'+r+'</span><span class="proc-cmd" title="'+L(s.command)+'">'+L(s.command)+'</span><button class="proc-kill" title="Kill PID '+s.pid+'">×</button></div>'}z.innerHTML=e;for(let s of z.querySelectorAll(".proc-row")){let i=s.querySelector(".proc-kill");i&&i.addEventListener("click",r=>{let c=r.target.closest(".proc-row");!c||!confirm("Kill PID "+c.dataset.pid+"?")||fetch("/api/system/kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(c.dataset.pid,10)})}).then(d=>d.json()).then(d=>{d.ok?c.style.opacity="0.3":alert("Failed: "+(d.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{z.innerHTML='<div class="proc-empty">Failed to load</div>'})}function Bt(){ge.classList.add("open"),ve.classList.add("open"),It()}function ie(){ge.classList.remove("open"),ve.classList.remove("open")}Ct.addEventListener("click",t=>{t.stopPropagation(),ge.classList.contains("open")?ie():Bt()});St.addEventListener("click",ie);ve.addEventListener("click",ie);window.__openSession=me;window.__refreshSidebar=_;_();ue();
|