tmux-weblink 2.2.28 → 2.2.30
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 +13 -6
- package/README.zh-CN.md +13 -6
- package/dist/assets/shell-client.js +20 -20
- package/dist/browser/terminal-core.js +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
**English** | [中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
+
**The best remote vibe-coding setup out there!**
|
|
6
|
+
Pick it and you can code remotely from any environment with a browser: unified management across devices and sessions, with Claude Code / Pi and other CLIs — **as long as your coding agent can run in tmux, it all goes to the cloud!**
|
|
7
|
+
With a public IP, enjoy buttery-smooth cloud coding!
|
|
8
|
+
**Mobile-optimized — small screens are no longer a problem!**
|
|
9
|
+
|
|
5
10
|
Access your tmux sessions from the browser. A lightweight web server that lists running tmux sessions and lets you attach through a full terminal in your browser — with built-in notes, a file browser, and a touch-friendly UI for both mobile and desktop.
|
|
6
11
|
|
|
7
12
|
## Features
|
|
@@ -39,13 +44,17 @@ The first visit shows a **"Set your password"** page (min 8 characters). The pas
|
|
|
39
44
|
|
|
40
45
|
## 3. Layout tour
|
|
41
46
|
|
|
47
|
+
<img width="1905" height="947" alt="image" src="https://github.com/user-attachments/assets/0a284f16-0e3c-4a44-8130-3accb582bfcb" />
|
|
48
|
+
|
|
42
49
|
- **Sidebar (Sessions mode, default)**:
|
|
43
50
|
- **`+ New Session`** button on top — create a new tmux session
|
|
44
51
|
- Session list **grouped by working directory** (folder-name headers, click to collapse). Sessions from the same project stack together.
|
|
45
|
-
- Each session has a colored dot: **green = idle, amber = working** (automatic activity probing, no config)
|
|
52
|
+
- Each session has a colored dot: **green = idle, amber = working** (automatic activity probing, no config — a herdr-style terminal-management experience, now in the cloud!)
|
|
46
53
|
- Sessions killed inside tmux move to a greyed-out **"失效会话 / dead sessions"** group (see §8)
|
|
47
54
|
- **Three mode buttons at the bottom**: `Sessions` / `Files` / `Settings`
|
|
48
55
|
- **Main area**: placeholder until you open a session, then the full terminal
|
|
56
|
+
<img width="901" height="947" alt="image" src="https://github.com/user-attachments/assets/474621c6-8c87-4436-807b-6f5b4faf3c60" />
|
|
57
|
+
|
|
49
58
|
|
|
50
59
|
## 4. Opening a session & day-to-day operations
|
|
51
60
|
|
|
@@ -75,6 +84,8 @@ The terminal is split in two zones — the **left 40% is a paging zone** (split
|
|
|
75
84
|
- tap/swipe **bottom half** = page down (PgDn)
|
|
76
85
|
- A translucent ↑/↓ hint appears; no soft keyboard pops up — tap the terminal body when you want to type
|
|
77
86
|
- **Right 60%**: drag up/down to **scroll terminal history** with inertia, like a normal mobile page
|
|
87
|
+
<img width="620" height="648" alt="image" src="https://github.com/user-attachments/assets/2b1245f0-4e81-4234-8d88-822fc689651d" />
|
|
88
|
+
|
|
78
89
|
|
|
79
90
|
### Virtual-key toolbar (mobile)
|
|
80
91
|
|
|
@@ -100,11 +111,7 @@ Click **`+ New Session`** in the sidebar:
|
|
|
100
111
|
|
|
101
112
|
> Leave the directory empty to start in `$HOME` and `cd` later — the tree is a convenience, not a requirement.
|
|
102
113
|
|
|
103
|
-
## 6.
|
|
104
|
-
|
|
105
|
-
### Notes (per-session scratchpad)
|
|
106
|
-
|
|
107
|
-
Click the **notepad icon** in the session header to open that session's Markdown pad; it **auto-saves as you type** into `~/.tmux-web/db.json`. Re-open the session later and the note is still there. For a bigger surface / export use `/notes/<session>` or the global note at `/notes/__global__`.
|
|
114
|
+
## 6. Files
|
|
108
115
|
|
|
109
116
|
### Files (browse/edit + git)
|
|
110
117
|
|
package/README.zh-CN.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | **中文**
|
|
4
4
|
|
|
5
|
+
**一千万以内,最好的远程vibe coding方式!**
|
|
6
|
+
选择它,你可以在任何可以使用浏览器的环境,进行远程编程,支持多设备多会话统一管理,支持Claude code / Pi 等CLI,**只要你的编程智能体能运行在tmux中,统统上云!**
|
|
7
|
+
配合公网IP,尽享云端丝滑编程!
|
|
8
|
+
**手机端适配,无需因为小屏幕产生困扰!**
|
|
9
|
+
|
|
5
10
|
在浏览器里访问你的 tmux 会话。一个轻量级 Web 服务器:列出正在运行的 tmux 会话,并让你通过浏览器里的完整终端接入——内置笔记与文件浏览,移动端与桌面端都能用。
|
|
6
11
|
|
|
7
12
|
## 特性
|
|
@@ -39,15 +44,19 @@ tmux-weblink
|
|
|
39
44
|
|
|
40
45
|
## 3. 界面一览
|
|
41
46
|
|
|
47
|
+
<img width="1905" height="947" alt="image" src="https://github.com/user-attachments/assets/0a284f16-0e3c-4a44-8130-3accb582bfcb" />
|
|
48
|
+
|
|
42
49
|
登录后主界面分三块:
|
|
43
50
|
|
|
44
51
|
- **左侧边栏(Sessions 模式,默认)**:
|
|
45
52
|
- 顶部 **`+ New Session`** 按钮——创建新 tmux 会话
|
|
46
53
|
- 下方会话列表,**按工作目录自动分组**(每组一个文件夹标题,可点击折叠)。同目录的多个会话堆在一起,一眼看到"我在哪个项目里开了什么"
|
|
47
|
-
- 每个会话前面的小圆点显示活动状态:**绿色 = 空闲(idle),橘黄 = 正在干活(working
|
|
54
|
+
- 每个会话前面的小圆点显示活动状态:**绿色 = 空闲(idle),橘黄 = 正在干活(working)**(后台自动探测,无需配置,类 herdr 的终端管理体验搬到了云端!)
|
|
48
55
|
- 若 session 在 tmux 里被杀掉,会出现在 **"失效会话"** 分组(灰显,见 §9)
|
|
49
56
|
- **底部三个模式按钮**:`Sessions`(会话)/ `Files`(文件)/ `Settings`(设置)
|
|
50
57
|
- **右侧主区**:点击会话前的占位提示;接入终端后显示完整终端
|
|
58
|
+
<img width="901" height="947" alt="image" src="https://github.com/user-attachments/assets/474621c6-8c87-4436-807b-6f5b4faf3c60" />
|
|
59
|
+
|
|
51
60
|
|
|
52
61
|
## 4. 接入终端 & 每天的操作
|
|
53
62
|
|
|
@@ -77,6 +86,8 @@ tmux-weblink
|
|
|
77
86
|
- 点/滑 **下半区** = 下翻一页(PgDn)
|
|
78
87
|
- 会弹出半透明提示(↑/↓),不弹软键盘;要输入时点击终端主体即可
|
|
79
88
|
- **右 60%**:上下拖动**回看终端历史**(带惯性),像普通手机页面一样往回翻
|
|
89
|
+
<img width="620" height="648" alt="image" src="https://github.com/user-attachments/assets/2b1245f0-4e81-4234-8d88-822fc689651d" />
|
|
90
|
+
|
|
80
91
|
|
|
81
92
|
### 虚拟键盘工具栏(移动端)
|
|
82
93
|
|
|
@@ -102,11 +113,7 @@ tmux-weblink
|
|
|
102
113
|
|
|
103
114
|
> 不会用目录树也没关系:留空 = 在 home 目录创建,之后在会话里 `cd` 即可。
|
|
104
115
|
|
|
105
|
-
## 6.
|
|
106
|
-
|
|
107
|
-
### Notes(每个会话一块便签)
|
|
108
|
-
|
|
109
|
-
会话头部点**记事本图标**,打开该会话的 Markdown 便签,**边写边自动保存**到 `~/.tmux-web/db.json`。下次再打开这个会话,便签还在。想用大编辑区/导出,打开 `/notes/<session名>` 或全局便签 `/notes/__global__`。
|
|
116
|
+
## 6. 文件 Files
|
|
110
117
|
|
|
111
118
|
### Files(文件浏览/编辑 + git)
|
|
112
119
|
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
var bn=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function et(e){return e.replace(/\x1b\[\?1049[hl]/g,"")}function fe(e){return e.replace(bn,"")}var
|
|
2
|
-
`)}selectRows(t,s){let n=this.terminal.buffer.active,[
|
|
3
|
-
`)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}};function
|
|
1
|
+
var bn=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function et(e){return e.replace(/\x1b\[\?1049[hl]/g,"")}function fe(e){return e.replace(bn,"")}var Re;function Ln(){return Re||(document.querySelector("link[data-tmux-web-xterm-css]")?Re=Promise.resolve():(Re=new Promise(e=>{let t=document.createElement("link");t.rel="stylesheet",t.href="/assets/xterm.css",t.setAttribute("data-tmux-web-xterm-css",""),t.addEventListener("load",()=>e(),{once:!0}),t.addEventListener("error",()=>e(),{once:!0}),document.head.appendChild(t)}),Re))}var En=class Kt{terminal;fitAddon;container;verifyRaf=0;verifyRounds=0;shrinkCols=0;lastLimit=0;lastCheckAt=0;constructor(t,s,n){this.container=t,this.terminal=s,this.fitAddon=n,this.terminal.loadAddon(this.fitAddon),this.terminal.open(t)}static async create(t,s,n){let[{Terminal:a},{FitAddon:r}]=await Promise.all([import("./xterm-BXEES47M.js"),import("./addon-fit-D5N335P2.js"),Ln()]),c=new a({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:s,convertEol:!1,smoothScrollDuration:120,theme:n});return new Kt(t,c,new r)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(t){return new Promise(s=>this.terminal.write(t,()=>{this.lastLimit>0&&this.scheduleColumnCheck(this.lastLimit),s()}))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(t,s=!1){this.terminal.scrollToLine(Math.max(0,t),s)}scrollLines(t){let s=this.terminal.buffer?.active;this.terminal.scrollLines(t)}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){let t=Cn(this.container);if(t.width<=0||t.height<=0)return!1;this.fitAddon.fit();let s=this.terminal.element?.querySelector(".xterm-viewport"),n=s?Math.max(0,s.offsetWidth-s.clientWidth):0,a=this.terminal.element?.querySelector(".vertical.scrollbar"),r=a?Math.max(0,Math.round(a.getBoundingClientRect().width)):0,c=this.container.getBoundingClientRect().left+t.width-n-r-1;if(this.lastLimit=c,this.shrinkCols>0){let o=Math.max(10,this.terminal.cols-this.shrinkCols);o!==this.terminal.cols&&this.terminal.resize(o,this.terminal.rows)}return this.verifyRounds=0,this.scheduleColumnCheck(c,!0),!0}scheduleColumnCheck(t,s=!1){if(this.lastLimit=t,this.verifyRaf)return;let n=Date.now();!s&&n-this.lastCheckAt<250||(this.lastCheckAt=n,this.verifyRaf=requestAnimationFrame(()=>{this.verifyRaf=0;try{this.recheckColumns(this.lastLimit)&&this.verifyRounds<8?(this.verifyRounds++,this.scheduleColumnCheck(this.lastLimit,!0)):this.verifyRounds=0}catch{}}))}recheckColumns(t){let s=this.terminal.element?.querySelector(".xterm-rows");if(!s)return!1;let n=0;for(let o of Array.from(s.children)){let u=o.children;for(let p=u.length-1;p>=0;p--){let E=u[p];if(!E.textContent)continue;let b=E.getBoundingClientRect().right;b>n&&(n=b);break}}if(n===0)return!1;let a=this.terminal.cols,r=this.terminal.element?.querySelector(".xterm-screen")?.getBoundingClientRect().width??0,c=a>0&&r>0?r/a:0;if(n>t){let o=n-t,u=c>0?Math.min(8,Math.ceil(o/c)):1,p=Math.max(10,a-Math.max(1,u));return p>=a?!1:(this.shrinkCols+=a-p,this.terminal.resize(p,this.terminal.rows),!0)}if(this.shrinkCols>0&&c>0&&n<=t-c){let o=Math.floor((t-n)/c)-1,u=Math.min(this.shrinkCols,Math.min(8,Math.max(1,o)));return this.shrinkCols-=u,this.terminal.resize(a+u,this.terminal.rows),!0}return!1}focus(){this.terminal.focus()}pasteText(t){this.terminal.paste(t)}input(t){this.terminal.input(t,!1)}onData(t){this.terminal.onData(t),this.terminal.onBinary(t)}onResize(t){this.terminal.onResize(t)}onScroll(t){this.terminal.onScroll(t)}attachCustomKeyEventHandler(t){this.terminal.attachCustomKeyEventHandler(t)}isFocused(){let t=document.activeElement;return t?t===this.container||t===this.terminal.textarea||this.container.contains(t)||!!t.closest?.(".xterm"):!1}getScreenText(){return this.getRowsText(0,this.terminal.rows-1)}getRowsText(t,s){let n=this.terminal.buffer.active,[a,r]=t<=s?[t,s]:[s,t],c=n.viewportY,o=[];for(let u=a;u<=r;u++){let p=n.getLine(c+u);o.push(p?p.translateToString(!0):"")}return o.join(`
|
|
2
|
+
`)}selectRows(t,s){let n=this.terminal.buffer.active,[a,r]=t<=s?[t,s]:[s,t];this.terminal.selectLines(n.viewportY+a,n.viewportY+r)}selectCells(t,s,n,a){let r=this.terminal.buffer.active,c=Math.min(s,a),o=Math.max(s,a);if(c===o){let u=Math.min(t,n),p=Math.max(t,n);this.terminal.select(u,r.viewportY+c,p-u+1)}else this.terminal.selectLines(r.viewportY+c,r.viewportY+o)}getCellsText(t,s,n,a){let r=this.terminal.buffer.active,c=Math.min(s,a),o=Math.max(s,a),u=s<a?t:s>a?n:Math.min(t,n),p=s<a?n:s>a?t:Math.max(t,n),E=r.viewportY,b=[];for(let F=c;F<=o;F++){let T=r.getLine(E+F);if(!T){b.push("");continue}let L=F===c?u:0,O=F===o?p:this.terminal.cols-1,ae="";for(let xe=L;xe<=O;xe++){let W=T.getCell(xe);W&&(ae+=W.getChars())}b.push(ae.replace(/\s+$/,""))}return b.join(`
|
|
3
|
+
`)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}};function Cn(e){let t=e.getBoundingClientRect(),s=window.visualViewport;return s?{width:Math.min(t.width,s.width),height:Math.max(0,Math.min(t.height,s.height-Math.max(0,t.top)))}:t}function kn(e,t,s){return e.innerHTML="",e.classList.add("terminal-pending"),(async()=>{let n=await En.create(e,s.scrollback,s.theme),a,r=0,c,o=null,u=0,p=0,E=.2,b=10,F=.95,T=.04,L=null,O=null;function ae(i){L||(L=document.createElement("div"),L.style.cssText=["position:absolute","left:0","width:40%","padding:10px 0","text-align:center","font:600 14px/1.4 system-ui, -apple-system, sans-serif","color:rgba(255,255,255,0.95)","background:rgba(20,30,50,0.55)","border:1px solid rgba(255,255,255,0.25)","border-radius:10px","pointer-events:none","opacity:0","transition:opacity 0.15s ease","z-index:6"].join(";"),e.appendChild(L)),L.textContent=i?"\u2191 \u4E0A\u7FFB\u4E00\u9875 (PgUp)":"\u2193 \u4E0B\u7FFB\u4E00\u9875 (PgDn)",L.style.top=i?"10%":"auto",L.style.bottom=i?"auto":"10%",L.style.opacity="1",O&&clearTimeout(O),O=setTimeout(()=>{L&&(L.style.opacity="0")},900)}function xe(){O&&clearTimeout(O),L&&(L.style.opacity="0")}function W(){u&&(cancelAnimationFrame(u),u=0),p=0}function Vt(i){if(W(),Math.abs(i)<E)return;p=Math.max(-b,Math.min(b,i));let l=()=>{if(q){u=0;return}let d=e.querySelector(".xterm-rows > div"),m=d?d.getBoundingClientRect().height:16,v=m>0?Math.round(p*16/m):p>0?1:-1;v===0&&(v=p>0?1:-1);let A=n.viewportY()-v,X=n.baseY(),me=Math.max(0,Math.min(A,X));if(n.scrollToLine(me,!0),p*=F,me!==A){u=0;return}if(Math.abs(p)<T){u=0;return}u=requestAnimationFrame(l)};u=requestAnimationFrame(l)}let Se=0,$="connecting",Be=0,oe=!1,Me=[],Q="",q=!1,le=1e3,Xt=location.protocol==="https:"?"wss:":"ws:",dt=s.wsBase||"/ws",Jt=Xt+"//"+location.host+dt+"/"+encodeURIComponent(t),Zt=(dt.replace(/^\/ws/,"")||"")+"/api/session/"+encodeURIComponent(t)+"/upload",Gt=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function Qt(){return Me.join("")+Q}async function en(i,l=0){let d=i?n.viewportY():0,m=fe(Qt());if(n.reset(),!m){i||n.scrollToBottom();return}await n.write(m),i?n.scrollToLine(l+d):n.scrollToBottom()}function K(i){a?.readyState===WebSocket.OPEN&&a.send(JSON.stringify(i))}function tn(i){let l;try{l=JSON.parse(i)}catch{$==="live"&&(Q+=i,n.write(fe(i)));return}if(l.type==="auth.required"){let d=localStorage.getItem("tmux-web-token");d?K({type:"auth.token",token:d}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(l.type==="attach_failed"&&typeof l.message=="string"){Te=!0,$="dead",n.reset(),n.write(`\r
|
|
4
4
|
\x1B[31m`+fe(l.message)+`\x1B[0m\r
|
|
5
|
-
`).then(()=>{
|
|
5
|
+
`).then(()=>{Ie();try{a?.close()}catch{}});return}if(l.type==="auth.ok"){l.token&&localStorage.setItem("tmux-web-token",l.token),le=1e3,V(),K({type:"resize",cols:n.cols,rows:n.rows}),M();return}if(l.type==="auth.failed"){if(l.permanentLock||l.retryAfterMs&&l.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(l.message);return}return}if(l.type==="snapshot"&&typeof l.data=="string"){let d=et(fe(l.data));Me=[d],Q="",Be=typeof l.lines=="number"?l.lines:s.terminal.initialLines,$="live",n.reset(),V(),K({type:"resize",cols:n.cols,rows:n.rows}),n.write(d).then(()=>n.scrollToBottom());return}if(l.type==="window_changed"&&typeof l.activeIndex=="number"){let d=new URL(location.href);d.searchParams.get("window")!==String(l.activeIndex)&&(d.searchParams.set("window",String(l.activeIndex)),history.replaceState(history.state,"",d)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:l.windows}));return}if(l.type==="history"&&typeof l.data=="string"){l.lines>0&&l.data?(Me.unshift(et(l.data)),Be+=l.lines,en(!0,l.lines).finally(()=>{oe=!1})):oe=!1;return}if(l.type==="data"&&typeof l.data=="string"){let d=et(fe(l.data));if($==="connecting"){$="live",Q=d,n.write(d);return}$==="live"&&(Q+=d,n.write(d))}}let Te=!1;function ut(){if(Te)return;let i=Jt,l=localStorage.getItem("tmux-web-token");l&&(i+=(i.includes("?")?"&":"?")+"token="+encodeURIComponent(l)),i+=(i.includes("?")?"&":"?")+"cols="+n.cols+"&rows="+n.rows,a=new WebSocket(i),a.onopen=()=>{$="connecting",Be=0,oe=!1,Me=[],Q="",n.reset(),le=1e3},a.onmessage=d=>{typeof d.data=="string"&&tn(d.data)},a.onclose=()=>{q||($="connecting",!Te&&setTimeout(()=>{le=Math.min(le*2,1e4),!q&&!Te&&ut()},le))},a.onerror=()=>a?.close()}function ee(i){K({type:"input",data:i})}function V(){return n.fit()}function Ie(){e.classList.remove("terminal-pending")}function M(){r&&cancelAnimationFrame(r),c&&clearTimeout(c),V(),r=requestAnimationFrame(()=>{r=0,V()&&Ie()}),c=setTimeout(()=>{V()&&Ie()},120)}function nn(){M(),setTimeout(M,50),setTimeout(M,150),setTimeout(M,300)}function pt(i){return typeof i=="string"&&i.startsWith("image/")}function mt(i){return i?.files?.length?i.files[0]??null:null}function sn(i){if(!i?.items)return null;for(let l=0;l<i.items.length;l++){let d=i.items[l];if(d?.kind==="file"&&pt(d.type))return d.getAsFile()}return null}async function an(i){let l=new FormData,d=i instanceof File&&i.name?i.name:"upload";l.append("file",i,d);let m=localStorage.getItem("tmux-web-token"),v={};m&&(v.Authorization="Bearer "+m);let A=await fetch(Zt,{method:"POST",body:l,headers:v});if(!A.ok){let me="upload failed";try{let bt=await A.json();bt.error&&(me=bt.error)}catch{}throw new Error(me)}let X=await A.json();if(!X.path)throw new Error("no path in response");return X.path}async function Ze(i){try{let l=await an(i);ee(l)}catch{}}n.onData(i=>ee(i)),n.onResize(({cols:i,rows:l})=>K({type:"resize",cols:i,rows:l})),n.onScroll(()=>{$!=="live"||oe||!n.isNearScrollbackTop()||(oe=!0,K({type:"load_history",before:Be}))});let re=!1,ce=!1,C=null,k=null,de=document.createElement("div");de.className="terminal-copy-banner",de.innerHTML='<strong>Copy mode</strong><span class="hint">drag to copy \xB7 Esc exits</span>',de.hidden=!0,e.appendChild(de);let z=document.createElement("div");z.className="terminal-copy-banner terminal-copy-toast",z.textContent="Copied",z.hidden=!0,e.appendChild(z);function ft(i,l){let d=e.querySelector(".xterm-screen, canvas"),m=(d&&d.getBoundingClientRect().width>0?d:e).getBoundingClientRect(),v=m.height>0&&n.rows>0?m.height/n.rows:18,A=m.width>0&&n.cols>0?m.width/n.cols:9;return{row:Math.max(0,Math.min(n.rows-1,Math.floor((l-m.top)/v))),col:Math.max(0,Math.min(n.cols-1,Math.floor((i-m.left)/A)))}}async function De(i){if(!i)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(i);return}}catch{}let l=document.createElement("textarea");l.value=i,l.style.position="fixed",l.style.opacity="0",l.style.pointerEvents="none",document.body.appendChild(l),l.focus(),l.select();try{document.execCommand("copy")}catch{}l.remove()}let ue;function Fe(){z.hidden=!1,ue&&clearTimeout(ue),ue=setTimeout(()=>{z.hidden=!0},1e3)}function te(i){re=i,de.hidden=!i,e.classList.toggle("terminal-copy-mode-active",i),i&&n.focus()}function ht(){te(!re)}function on(i){q||i.button!==0||ce||(re||i.shiftKey)&&(i.preventDefault(),i.stopPropagation(),ce=!0,C=ft(i.clientX,i.clientY),k=C,n.selectCells(C.col,C.row,k.col,k.row),document.addEventListener("mousemove",Ge,!0),document.addEventListener("mouseup",Qe,!0))}function Ge(i){q||!ce||!C||(i.preventDefault(),i.stopPropagation(),k=ft(i.clientX,i.clientY),n.selectCells(C.col,C.row,k.col,k.row))}function Qe(i){if(q||!ce||!C||!k)return;i.preventDefault(),i.stopPropagation(),document.removeEventListener("mousemove",Ge,!0),document.removeEventListener("mouseup",Qe,!0),ce=!1;let l=n.getCellsText(C.col,C.row,k.col,k.row);C=null,k=null,n.clearSelection(),te(!1),l&&(z.textContent="\u5DF2\u590D\u5236",De(l).then(Fe)),n.focus()}e.addEventListener("mousedown",on,!0),document.addEventListener("keydown",ln,!0);function ln(i){if(!(q||!n.isFocused()||i.defaultPrevented||i.isComposing)){if(re){if(i.key==="Escape"){i.preventDefault(),i.stopPropagation(),C=null,k=null,n.clearSelection(),te(!1);return}if(i.key==="Enter"||(i.ctrlKey||i.metaKey)&&i.code==="KeyC"){i.preventDefault(),i.stopPropagation(),De(n.getScreenText()).then(Fe),te(!1);return}}if(i.altKey&&i.code==="KeyC"&&!i.ctrlKey&&!i.metaKey){if(i.preventDefault(),i.stopPropagation(),C&&k){let l=n.getCellsText(C.col,C.row,k.col,k.row);C=null,k=null,n.clearSelection(),te(!1),l&&(z.textContent="Copied",De(l).then(Fe))}else{let l=n.getSelection();l?(n.clearSelection(),z.textContent="Copied",De(l).then(Fe)):ht()}return}if((i.ctrlKey||i.metaKey)&&i.code==="KeyV"){i.preventDefault(),i.stopPropagation(),(async()=>{try{if(navigator.clipboard?.read){let l=await navigator.clipboard.read();for(let d of l)for(let m of d.types)if(pt(m)){let v=await d.getType(m);await Ze(v);return}}}catch{}try{let l=await navigator.clipboard?.readText();l&&n.pasteText(vt(l))}catch{}})();return}}}let Ae=0;function vt(i){return i.split(`\r
|
|
6
6
|
`).join(`
|
|
7
7
|
`).split(`
|
|
8
|
-
`).join("\r")}async function rn(
|
|
8
|
+
`).join("\r")}async function rn(i){let l=sn(i.clipboardData);if(l){i.preventDefault(),i.stopPropagation();let v=Date.now();if(v-Ae<50)return;Ae=v,await Ze(l);return}let d=i.clipboardData?.getData("text/plain");if(!d)return;i.preventDefault(),i.stopPropagation();let m=Date.now();m-Ae<50||(Ae=m,n.pasteText(vt(d)))}let pe=0;function cn(i){i.preventDefault(),pe++,mt(i.dataTransfer)&&e.classList.add("terminal-drag-over")}function dn(i){i.preventDefault(),i.dataTransfer&&(i.dataTransfer.dropEffect="copy")}function un(i){i.preventDefault(),pe--,pe<=0&&(pe=0,e.classList.remove("terminal-drag-over"))}async function pn(i){i.preventDefault(),pe=0,e.classList.remove("terminal-drag-over");let l=mt(i.dataTransfer);l&&await Ze(l)}function gt(i){!Gt||i.key!=="Escape"||re||i.defaultPrevented||i.repeat||i.metaKey||i.ctrlKey||i.altKey||n.isFocused()&&(i.preventDefault(),i.stopPropagation(),ee("\x1B"))}e.addEventListener("paste",rn),e.addEventListener("dragenter",cn),e.addEventListener("dragover",dn),e.addEventListener("dragleave",un),e.addEventListener("drop",pn),document.addEventListener("keydown",gt,!0);function mn(i){if(i.touches.length!==1){o=null;return}let l=i.touches[0];if(!l)return;W();let d=e.getBoundingClientRect(),m=l.clientX-d.left<d.width*.4?"tui":"history",v=l.clientY-d.top<d.height*.5;o={startX:l.clientX,startY:l.clientY,lastX:l.clientX,lastY:l.clientY,lastT:performance.now(),velocity:0,scrolling:!1,zone:m,tuiUp:v,sent:!1},i.stopPropagation()}function fn(i){if(!o||i.touches.length!==1)return;let l=i.touches[0];if(!l)return;let d=l.clientY-o.startY,m=l.clientX-o.startX;if(!o.scrolling){if(Math.abs(d)<8||Math.abs(d)<Math.abs(m))return;o.scrolling=!0,Se=Date.now()+500}i.preventDefault(),i.stopPropagation();let v=performance.now(),A=l.clientY-o.lastY;if(o.zone==="tui"){o.sent||(o.sent=!0,ee(o.tuiUp?"\x1B[5~":"\x1B[6~"),ae(o.tuiUp)),o.lastX=l.clientX,o.lastY=l.clientY,o.lastT=v;return}let X=v-o.lastT;X>0&&(o.velocity=A/X),yn(-A),o.lastX=l.clientX,o.lastY=l.clientY,o.lastT=v}function hn(i){if(!o)return;let l=o.scrolling,d=o.zone,m=o.tuiUp,v=o.velocity;if(o=null,i.stopPropagation(),d==="tui"){l||(ee(m?"\x1B[5~":"\x1B[6~"),ae(m),Se=Date.now()+500,i.preventDefault());return}if(!l){n.focus();return}Se=Date.now()+500,i.preventDefault(),v&&Vt(v)}function vn(i){o=null,W(),i.stopPropagation()}function gn(i){i.pointerType==="touch"&&Date.now()<Se&&(i.preventDefault(),i.stopPropagation())}function yn(i){let l=e.querySelector(".xterm-rows > div"),d=l?l.getBoundingClientRect().height:16,m=d>0?Math.round(i/d):i>0?1:-1;m===0&&(m=i>0?1:-1),n.scrollLines(m)}e.addEventListener("touchstart",mn,{passive:!0,capture:!0}),e.addEventListener("touchmove",fn,{passive:!1,capture:!0}),e.addEventListener("touchend",hn,{passive:!1,capture:!0}),e.addEventListener("touchcancel",vn,{passive:!0,capture:!0}),e.addEventListener("pointerup",gn,!0);function yt(){M()}window.addEventListener("resize",yt),window.visualViewport?.addEventListener("resize",M),window.visualViewport?.addEventListener("scroll",M);let wt=new ResizeObserver(()=>M());wt.observe(e),document.fonts?.ready.then(()=>{M(),setTimeout(M,50),setTimeout(M,200)}),e.addEventListener("focusin",nn,!0);async function wn(){if(document.fonts?.ready)try{await Promise.race([document.fonts.ready,new Promise(i=>setTimeout(i,1e3))])}catch{}}return requestAnimationFrame(()=>{V()&&Ie(),(async()=>(await wn(),V()&&K({type:"resize",cols:n.cols,rows:n.rows}),ut(),M()))()}),{destroy(){if(q=!0,W(),te(!1),ue&&clearTimeout(ue),document.removeEventListener("mousemove",Ge,!0),document.removeEventListener("mouseup",Qe,!0),a){try{a.close(1e3,"session switch")}catch{}a=void 0}e.innerHTML="",e.classList.remove("terminal-pending"),window.removeEventListener("resize",yt),wt.disconnect(),document.removeEventListener("keydown",gt,!0)},focus(){n.focus()},sendInput(i){ee(i)},toggleCopyMode(){ht()}}})()}var he=window.__TMUX_WEB_SHELL__,g=null,y=null,ve=typeof window.__TMUX_WEB_SCOPE__?.agentId=="string"?window.__TMUX_WEB_SCOPE__.agentId:null,x=ve;window.__tmuxWebScopeAgent=ve;var tt="sessions",_="",He="",Ne="",Lt="";function S(e){return x?"/a/"+encodeURIComponent(x)+e:e}var f=document.getElementById("sidebar-content"),J=document.getElementById("main-placeholder"),I=document.getElementById("terminal-container"),ge=document.getElementById("file-editor"),xn=document.getElementById("fe-path"),R=document.getElementById("fe-status"),ye=document.getElementById("fe-content"),Z=document.getElementById("fe-save"),Sn=document.getElementById("fe-delete"),Bn=document.getElementById("fe-back"),Et=document.getElementById("fe-new-name"),Mn=document.getElementById("fe-new-btn"),nt=document.getElementById("settings-backdrop"),Ct=document.getElementById("settings-popover"),kt=document.querySelector(".sidebar"),xt="tmux-web-force-narrow";function Pe(){try{return localStorage.getItem(xt)==="1"}catch{return!1}}function St(){document.documentElement.classList.toggle("force-narrow",Pe()),Pe()&&Bt()&&$e()}function Bt(){return Pe()?!0:window.matchMedia("(max-width: 640px)").matches}function $e(){Bt()&&kt.classList.add("collapsed")}function Mt(){kt.classList.remove("collapsed")}document.getElementById("mode-sessions").addEventListener("click",()=>{Mt(),Tt("sessions")}),document.getElementById("mode-files").addEventListener("click",()=>{Mt(),Tt("files")});function Tt(e){tt=e,document.querySelectorAll(".mode-btn").forEach(s=>s.classList.remove("active"));let t=document.getElementById(e==="sessions"?"mode-sessions":"mode-files");t&&t.classList.add("active"),e==="sessions"?(st="",j()):qn()}var st="";async function j(){if(tt!=="sessions")return;try{let t=await(await fetch("/api/sidebar/sessions")).json(),s=JSON.stringify({recent:t.recent,agents:t.agents,tombstones:t.tombstones});if(s===st)return;st=s,An(t)}catch{f.innerHTML+='<div class="file-tree-empty">Failed to load sessions</div>'}let e=document.getElementById("ns-btn");e&&e.addEventListener("click",()=>{let t=window.__openNewSessionModal;typeof t=="function"?t():document.getElementById("new-session-modal")?.classList.add("open")}),ct()}var It="tmux-web-sidebar-group-collapsed";function Dt(){try{return new Set(JSON.parse(localStorage.getItem(It)||"[]"))}catch{return new Set}}function Tn(e){try{localStorage.setItem(It,JSON.stringify([...e]))}catch{}}function In(e,t,s){if(!e)return"\u2026";let n=s&&(e===s||e.startsWith(s+"/"))?"~"+e.slice(s.length):e,a=n.split("/").filter(Boolean);if(a.length===0)return e;for(let r=1;r<=a.length;r++){let c=a.slice(-r).join("/");if(!t.some(o=>!o||o===e?!1:(s&&(o===s||o.startsWith(s+"/"))?"~"+o.slice(s.length):o).split("/").filter(Boolean).slice(-r).join("/")===c))return c}return n}function Ft(e,t,s,n=!0){let a=new Map;for(let o of e){let u=o.path||"";a.has(u)||a.set(u,[]),a.get(u).push(o)}let r=[...a.keys()],c=Dt();for(let[o,u]of a){let p=In(o,r,t),E=c.has(o),b=document.createElement("div");b.className="session-group-header"+(E?" collapsed":""),b.title=o||"No working directory",b.innerHTML=`<span class="sg-folder">📁</span><span class="sg-label">${h(p)}</span>`,b.addEventListener("click",()=>{let T=Dt(),L=b.nextElementSibling;T.has(o)?(T.delete(o),b.classList.remove("collapsed"),L?.classList.remove("collapsed")):(T.add(o),b.classList.add("collapsed"),L?.classList.add("collapsed")),Tn(T)});let F=document.createElement("div");F.className="session-group-body"+(E?" collapsed":"");for(let T of u)F.appendChild(s?Dn(T,s,n):Fn(T));f.appendChild(b),f.appendChild(F)}}function Dn(e,t,s){let n=document.createElement("div");n.className="session-item"+(e.name===y&&x===t?" active":"")+(s?"":" session-offline"),n.setAttribute("data-session",e.name),n.setAttribute("data-agent",t),n.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${e.attached?"M19 4H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zm0 14H5V6h14v12z":"M4 6h16v2H4V6zm0 5h16v2H4v-2zm0 5h16v2H4v-2z"}"></svg>
|
|
9
9
|
<span>${h(e.name)}</span>${s?"":'<span class="meta">offline</span>'}
|
|
10
|
-
<button class="session-edit-btn" data-session="${h(e.name)}" title="Edit session"><svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg></button>`,s&&n.addEventListener("click",r=>{r.target.closest(".session-edit-btn")||we(e.name,t)});let
|
|
10
|
+
<button class="session-edit-btn" data-session="${h(e.name)}" title="Edit session"><svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg></button>`,s&&n.addEventListener("click",r=>{r.target.closest(".session-edit-btn")||we(e.name,t)});let a=n.querySelector(".session-edit-btn");return a&&a.addEventListener("click",r=>{r.stopPropagation(),Ve(e.name,a,{agentId:t})}),n}function Fn(e){let t=document.createElement("div");t.className="session-item"+(e.name===y&&!x?" active":""),t.setAttribute("data-session",e.name),t.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="${e.attached?"M19 4H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zm0 14H5V6h14v12z":"M4 6h16v2H4V6zm0 5h16v2H4v-2zm0 5h16v2H4v-2z"}"></svg>
|
|
11
11
|
<span>${h(e.name)}</span>
|
|
12
12
|
<button class="session-edit-btn" data-session="${h(e.name)}" title="Edit session"><svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg></button>
|
|
13
|
-
`,t.addEventListener("click",n=>{n.target.closest(".session-edit-btn")||we(e.name)});let s=t.querySelector(".session-edit-btn");return s&&s.addEventListener("click",n=>{n.stopPropagation(),Ve(e.name,s)}),t}function An(e){f.innerHTML='<button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';let t=e.recent||[],s=document.createElement("div");s.className="sidebar-section-label"+(ve?" clickable":""),s.textContent=ve?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",ve&&(s.title="Back to hub",s.addEventListener("click",()=>{window.location.href="/"})),f.appendChild(s),Ft(t,e.home);let n=e.agents||[];for(let r of n){if(!r.sessions||r.sessions.length===0)continue;let c=r.agentId===
|
|
13
|
+
`,t.addEventListener("click",n=>{n.target.closest(".session-edit-btn")||we(e.name)});let s=t.querySelector(".session-edit-btn");return s&&s.addEventListener("click",n=>{n.stopPropagation(),Ve(e.name,s)}),t}function An(e){f.innerHTML='<button class="new-session-sidebar-btn" id="ns-btn">+ New Session</button>';let t=e.recent||[],s=document.createElement("div");s.className="sidebar-section-label"+(ve?" clickable":""),s.textContent=ve?"\u2190 \u8FD4\u56DE\u672C\u673A":"\u672C\u673A",ve&&(s.title="Back to hub",s.addEventListener("click",()=>{window.location.href="/"})),f.appendChild(s),Ft(t,e.home);let n=e.agents||[];for(let r of n){if(!r.sessions||r.sessions.length===0)continue;let c=r.agentId===x,o=document.createElement("div");o.className="sidebar-section-label machine-label"+(r.online?"":" agent-offline-label")+(!c&&r.online?" clickable":""),o.textContent=r.agentName+(r.online?"":" (offline)"),!c&&r.online&&(o.title="\u6253\u5F00 "+r.agentName,o.addEventListener("click",()=>{window.location.href="/a/"+encodeURIComponent(r.agentId)+"/"})),f.appendChild(o),Ft(r.sessions,e.home,r.agentId,r.online)}let a=e.tombstones||[];if(a.length>0){let r=document.createElement("div");r.className="sidebar-section-label tombstone-label",r.textContent="\u5931\u6548\u4F1A\u8BDD",f.appendChild(r);for(let c of a){let o=document.createElement("div");o.className="session-item session-tombstone",o.setAttribute("data-session",c.name),c.agentId&&o.setAttribute("data-agent",c.agentId);let u=c.agentId?c.agentOnline?" (agent)":" (agent \u79BB\u7EBF)":"";o.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M4 6h16v2H4V6zm0 5h16v2H4v-2zm0 5h16v2H4v-2z"></svg>
|
|
14
14
|
<span>${h(c.name)}</span><span class="meta">\u5931\u6548${u}</span>
|
|
15
|
-
<button class="session-edit-btn" data-session="${h(c.name)}" title="\u6062\u590D\u4F1A\u8BDD"><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>`,o.title="\u5931\u6548\u4F1A\u8BDD\uFF1A\u70B9\u51FB\u7BA1\u7406\uFF08\u91CD\u5EFA/\u91CD\u547D\u540D/\u5220\u9664\uFF09",o.addEventListener("click",()=>{Ve(c.name,o,{tombstone:!0,agentId:c.agentId})});let
|
|
15
|
+
<button class="session-edit-btn" data-session="${h(c.name)}" title="\u6062\u590D\u4F1A\u8BDD"><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>`,o.title="\u5931\u6548\u4F1A\u8BDD\uFF1A\u70B9\u51FB\u7BA1\u7406\uFF08\u91CD\u5EFA/\u91CD\u547D\u540D/\u5220\u9664\uFF09",o.addEventListener("click",()=>{Ve(c.name,o,{tombstone:!0,agentId:c.agentId})});let p=o.querySelector(".session-edit-btn");p&&p.addEventListener("click",E=>{E.stopPropagation(),Ve(c.name,p,{tombstone:!0,agentId:c.agentId})}),f.appendChild(o)}}}function h(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}async function we(e,t){if(y===e&&g&&x===(t||null))return;ge.style.display="none",J.style.display="none",I.style.display="",I.classList.add("terminal-pending"),$e(),g&&(We(),g.destroy(),g=null),y=e,x=t||null,window.__tmuxWebScopeAgent=x,window.__tmuxWebCurrentSession=y,ts(e,t);let s=rt(e,t);Ot.set(s,Date.now()+Qn);let n=ie.get(s);if(n&&n.state==="working"){n.state="idle",n.doneUntil=void 0,n.unread=!1;let a=f.querySelector(t?'.session-item[data-agent="'+CSS.escape(t)+'"][data-session="'+CSS.escape(e)+'"]':'.session-item[data-session="'+CSS.escape(e)+'"]:not([data-agent])');a&&Je(a,s,n)}for(let a of f.querySelectorAll(".session-item"))a.classList.toggle("active",a.getAttribute("data-session")===e&&(a.getAttribute("data-agent")||null)===x);try{g=await kn(I,e,{terminal:he.terminal,scrollback:he.scrollback,theme:he.theme,wsBase:x?"/ws/a/"+encodeURIComponent(x):he.wsBase||"/ws"}),qt()}catch(a){console.error("[shell] terminal init failed:",a);let r=a&&typeof a=="object"&&"message"in a?a.message:String(a);I.textContent="Failed to open terminal for "+e+": "+r,I.classList.remove("terminal-pending")}}var ze=[],w=null,At=!1;function Rn(e){if(!w||!w.files.length)return null;let t=w.repoRoot;if(!t||!e.startsWith(t))return null;let s=e.slice(t.length+1);for(let n of w.files)if(n.path===s)return n.status;return null}async function Hn(e){At=!0;try{let t=await fetch(S("/api/git/status?path="+encodeURIComponent(e)));t.ok?w=await t.json():w=null}catch{w=null}finally{At=!1}}function Nn(){if(!w||!w.branch)return"";let{branch:e,linesAdded:t,linesRemoved:s}=w,n=`<div class="sidebar-git"><div class="git-branch-badge">
|
|
16
16
|
<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>
|
|
17
|
-
${h(e)}</div>`;return(t>0||s>0)&&(n+=`<div class="git-diff-stats">+<span class="add">${t}</span> <span class="del">-${s}</span></div>`),n+"</div>"}f.addEventListener("click",e=>{e.target.closest(".sidebar-git")&&ne&&w&&(e.stopPropagation(),$t())});var be=document.getElementById("header-git"),
|
|
18
|
-
<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>`;else{let t=`<div class="git-popover-header">${e.length} file${e.length>1?"s":""} changed</div>`;for(let s=0;s<e.length;s++){let n=e[s],
|
|
17
|
+
${h(e)}</div>`;return(t>0||s>0)&&(n+=`<div class="git-diff-stats">+<span class="add">${t}</span> <span class="del">-${s}</span></div>`),n+"</div>"}f.addEventListener("click",e=>{e.target.closest(".sidebar-git")&&ne&&w&&(e.stopPropagation(),$t())});var be=document.getElementById("header-git"),Rt=document.getElementById("git-diff-view"),Ht=document.getElementById("gd-path"),je=document.getElementById("gd-status"),Ue=document.getElementById("gd-content"),Pn=document.getElementById("gd-back"),ne=null;function Le(e){if(!e||!e.branch){be.style.display="none",ne=null;return}ne=e.repoRoot;let{branch:t,linesAdded:s,linesRemoved:n}=e,a=`<span class="branch">${h(t)}</span>`;(s>0||n>0)&&(a+=`<span class="sep">\xB7</span>+<span class="diff-add">${s}</span> <span class="diff-del">-${n}</span>`),be.innerHTML=a,be.style.display="block"}be.addEventListener("click",e=>{ne&&w&&(e.stopPropagation(),$t())});var B=document.getElementById("git-popover"),qe=document.getElementById("git-popover-backdrop");function it(){let e=be.getBoundingClientRect();B.style.top=e.bottom+4+"px",B.style.left=Math.max(8,Math.min(e.left,window.innerWidth-400))+"px"}function Nt(){let e=ne,t=document.getElementById("git-popover-browse");t&&t.addEventListener("click",()=>{if(Ye(),e){tt="files",document.querySelectorAll(".mode-btn").forEach(n=>n.classList.remove("active"));let s=document.getElementById("mode-files");s&&s.classList.add("active"),Y(e)}})}var Pt="";function $t(){if(!w)return;let e=w.files||[];if(!e.length)B.innerHTML=`<div class="git-popover-header">No changes \u2014 clean working tree</div>
|
|
18
|
+
<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>`;else{let t=`<div class="git-popover-header">${e.length} file${e.length>1?"s":""} changed</div>`;for(let s=0;s<e.length;s++){let n=e[s],a=n.additions||0,r=n.deletions||0,c="";switch(n.status){case"M":c='<span class="git-file-status M">M</span>';break;case"A":c='<span class="git-file-status A">A</span>';break;case"D":c='<span class="git-file-status D">D</span>';break;case"?":c='<span class="git-file-status ?">?</span>';break;case"R":c='<span class="git-file-status R">R</span>';break}t+=`<div class="git-popover-item" data-idx="${s}">
|
|
19
19
|
${c}<span class="file-path">${h(n.path)}</span>
|
|
20
|
-
<span class="file-add">${
|
|
20
|
+
<span class="file-add">${a>0?"+"+a:""}</span>
|
|
21
21
|
<span class="file-del">${r>0?"-"+r:""}</span>
|
|
22
|
-
</div>`}t+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',Pt=t,
|
|
22
|
+
</div>`}t+='<div class="git-popover-footer"><button id="git-popover-browse">Browse repository \u2192</button></div>',Pt=t,B.innerHTML=t,B.querySelectorAll(".git-popover-item").forEach(s=>{let n=parseInt(s.dataset.idx||"0",10),a=e[n];!a||a.status==="D"||(s.classList.add("clickable"),s.style.cursor="pointer",s.addEventListener("click",()=>jt(a.path)))})}it(),B.classList.add("open"),qe.classList.add("open"),Nt()}function $n(){return window.innerWidth>=1024}function zt(e,t){let s=(e+(t&&e?`
|
|
23
23
|
`:"")+t).split(`
|
|
24
|
-
`),n="",
|
|
24
|
+
`),n="",a=0,r=0;for(let c of s){let o=c;if(o.startsWith("@@")){let u=o.match(/@@\s+-(\d+)[^+]*\+(\d+)/);u&&(a=parseInt(u[1],10)-1,r=parseInt(u[2],10)-1),n+=`<div class="diff-line hunk"><span class="ln-body">${h(o)}</span></div>`;continue}if(o.startsWith("diff --git")||o.startsWith("index ")||o.startsWith("--- ")||o.startsWith("+++ ")||o.startsWith("new file")||o.startsWith("deleted file")){o.startsWith("diff --git")&&(n+=`<div class="diff-line header"><span class="ln-body">${h(o)}</span></div>`);continue}if(o.startsWith("+"))r++,n+=`<div class="diff-line add"><span class="ln-no">${r}</span><span class="ln-body">${h(o)}</span></div>`;else if(o.startsWith("-"))a++,n+=`<div class="diff-line del"><span class="ln-no">${a}</span><span class="ln-body">${h(o)}</span></div>`;else if(o.startsWith("\\"))n+=`<div class="diff-line"><span class="ln-body">${h(o)}</span></div>`;else{if(!o&&!a&&!r)continue;a++,r++,n+=`<div class="diff-line"><span class="ln-no">${a}</span><span class="ln-no" style="margin-right:12px">${r}</span><span class="ln-body">${h(o)}</span></div>`}}return{html:n,lineCount:s.length}}var _e=null;async function jt(e){let t=ne;if(t)if(Ye(),$n()){I.style.display="none",g&&(We(),g.destroy(),g=null,_e=y,y=null),Le(null),ge.style.display="none",J.style.display="none",Rt.style.display="flex",Ht.textContent=e,je.textContent="Loading\u2026",Ue.innerHTML="";try{let s=await fetch(S("/api/git/diff?path="+encodeURIComponent(t)+"&file="+encodeURIComponent(e)));if(!s.ok)throw new Error(await s.text());let n=await s.json();jn(e,n.diff,n.stagedDiff)}catch(s){let n=s instanceof Error?s.message:String(s);je.textContent="Error",Ue.innerHTML=`<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">Error: ${h(n)}</div>`}}else{B.innerHTML=`<div class="git-diff-view"><div class="diff-header">
|
|
25
25
|
<button class="diff-back">\u2190 Back</button>
|
|
26
26
|
<span class="diff-filename">${h(e)}</span>
|
|
27
27
|
<span class="diff-loading">Loading\u2026</span>
|
|
28
|
-
</div></div>`,
|
|
28
|
+
</div></div>`,it(),B.classList.add("open"),qe.classList.add("open");try{let s=await fetch(S("/api/git/diff?path="+encodeURIComponent(t)+"&file="+encodeURIComponent(e)));if(!s.ok)throw new Error(await s.text());let n=await s.json();zn(e,n.diff,n.stagedDiff)}catch(s){let n=s instanceof Error?s.message:String(s);B.innerHTML=`<div class="git-diff-view"><div class="diff-header">
|
|
29
29
|
<button class="diff-back">\u2190 Back</button>
|
|
30
30
|
<span class="diff-filename">${h(e)}</span>
|
|
31
|
-
</div><div class="diff-empty">Error loading diff: ${h(n)}</div></div>`}}}function zn(e,t,s){if(!t&&!s){
|
|
31
|
+
</div><div class="diff-empty">Error loading diff: ${h(n)}</div></div>`}}}function zn(e,t,s){if(!t&&!s){B.innerHTML=`<div class="git-diff-view"><div class="diff-header">
|
|
32
32
|
<button class="diff-back">\u2190 Back</button>
|
|
33
33
|
<span class="diff-filename">${h(e)}</span>
|
|
34
|
-
</div><div class="diff-empty">No diff content available</div></div>`;return}let{html:n,lineCount:
|
|
34
|
+
</div><div class="diff-empty">No diff content available</div></div>`;return}let{html:n,lineCount:a}=zt(t,s);B.innerHTML=`<div class="git-diff-view"><div class="diff-header">
|
|
35
35
|
<button class="diff-back">\u2190 Back</button>
|
|
36
36
|
<span class="diff-filename">${h(e)}</span>
|
|
37
|
-
<span class="diff-filesize">${
|
|
38
|
-
</div><div class="diff-content">${n}</div></div>`,
|
|
37
|
+
<span class="diff-filesize">${a} lines</span>
|
|
38
|
+
</div><div class="diff-content">${n}</div></div>`,B.querySelector(".diff-back")?.addEventListener("click",()=>{B.innerHTML=Pt,it(),w&&B.querySelectorAll(".git-popover-item").forEach(r=>{let c=parseInt(r.dataset.idx||"0",10),o=w.files[c];!o||o.status==="D"||(r.style.cursor="pointer",r.addEventListener("click",()=>jt(o.path)))}),Nt()})}function jn(e,t,s){if(!t&&!s){je.textContent="No diff",Ue.innerHTML='<div class="diff-empty" style="padding:24px;text-align:center;color:var(--panel-muted)">No diff content available</div>';return}let{html:n,lineCount:a}=zt(t,s);Ht.textContent=e,je.textContent=a+" lines",Ue.innerHTML=n}function Un(){Rt.style.display="none",_e?(I.style.display="",I.classList.add("terminal-pending"),we(_e),_e=null):y?(I.style.display="",I.classList.add("terminal-pending"),qt()):J.style.display="flex"}Pn.addEventListener("click",Un);function Ye(){B.classList.remove("open"),qe.classList.remove("open")}qe.addEventListener("click",Ye),document.addEventListener("keydown",e=>{e.key==="Escape"&&(Ye(),Xe())});async function Ut(e){try{let t=await(await fetch("/api/fs/session-path?session="+encodeURIComponent(e))).json();if(t.path){let s=await fetch("/api/git/status?path="+encodeURIComponent(t.path));if(s.ok){let n=await s.json();w=n,Le(n);return}}}catch{}w=null,Le(null)}var Oe=null;function qt(){We(),y&&(Ut(y),Oe=setInterval(()=>{y&&Ut(y)},3e4))}function We(){Oe&&(clearInterval(Oe),Oe=null)}function qn(){if(ze=he.fsRoots||[],ze.length===0){if(y){_n(y);return}f.innerHTML='<div class="file-tree-info">Open a session first, then switch to Files to browse its directory.</div>';return}f.innerHTML="";for(let e of ze){let t=document.createElement("div");t.className="file-tree-item",t.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor" class="file-icon"><path d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg> ${h(e)}`,t.addEventListener("click",()=>Y(e)),f.appendChild(t)}}async function _n(e){f.innerHTML='<div class="file-tree-empty">Loading...</div>';try{let t=await(await fetch(S("/api/fs/session-path?session="+encodeURIComponent(e)))).json();t.path?Y(t.path):f.innerHTML='<div class="file-tree-info">Could not determine session directory.</div>'}catch{f.innerHTML='<div class="file-tree-error">Failed to get session directory</div>'}}async function Y(e){_=e,f.innerHTML='<div class="file-tree-empty">Loading...</div>';let t=Hn(e);try{let s=await(await fetch(S("/api/fs/list?path="+encodeURIComponent(e)))).json();await t,f.innerHTML="",Le(w),f.innerHTML+=Nn();let n=Yn(e);if(n&&!ze.some(r=>e===r)){let r=document.createElement("div");r.className="file-tree-item",r.innerHTML="..",r.addEventListener("click",()=>Y(n)),f.appendChild(r)}if(s.dirs)for(let r of s.dirs){let c=r.split("/").pop()||r.split("\\").pop(),o=document.createElement("div");o.className="file-tree-item",o.innerHTML=`<svg viewBox="0 0 24 24" fill="currentColor" class="file-icon"><path d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg> ${h(c)}`,o.addEventListener("click",()=>Y(r)),f.appendChild(o)}else f.innerHTML="";let a=s.files||[];for(let r of a){let c=r.split("/").pop()||r.split("\\").pop(),o=Rn(r),u="",p="";if(o)switch(o){case"M":u="git-mod",p='<span class="git-file-status M">M</span>';break;case"A":u="git-add",p='<span class="git-file-status A">A</span>';break;case"D":u="git-del",p='<span class="git-file-status D">D</span>';break;case"?":u="git-untracked",p='<span class="git-file-status ?">?</span>';break;case"R":u="git-mod",p='<span class="git-file-status R">R</span>';break}let E=document.createElement("div");E.className="file-tree-item file"+(u?" "+u:""),E.innerHTML=`<span class="file-icon">\u{1F4C4}</span> ${p}${h(c)}`,E.addEventListener("click",()=>On(r)),f.appendChild(E)}}catch{f.innerHTML='<div class="file-tree-error">Failed to load directory</div>'}}function Yn(e){let t=e.lastIndexOf("/");return t<=0?null:e.substring(0,t)}async function On(e){He=e,I.style.display="none",g&&(We(),g.destroy(),g=null,y=null),Le(null),$e(),J.style.display="none",ge.style.display="flex",xn.textContent=e,R.textContent="Loading...",Z.style.display="none";try{let t=await fetch(S("/api/file?path="+encodeURIComponent(e)));if(!t.ok){let n=await t.json();R.textContent=n.error||"Failed to load",ye.value="";return}let s=await t.json();ye.value=s.content,Ne=s.content,Lt=s.content,R.textContent=s.size+" bytes",Z.style.display=""}catch{R.textContent="Failed to load",ye.value=""}}ye.addEventListener("input",()=>{Ne=ye.value}),Z.addEventListener("click",async()=>{Z.textContent="Saving...",Z.disabled=!0;try{let e=await fetch(S("/api/file"),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:He,content:Ne})});if(!e.ok){let t=await e.json();R.textContent=t.error||"Save failed";return}Lt=Ne,R.textContent="Saved"}catch{R.textContent="Save failed"}finally{Z.disabled=!1,Z.textContent="Save"}}),Sn.addEventListener("click",async()=>{if(confirm("Delete "+He+"?"))try{let e=await fetch(S("/api/file/delete"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:He})});if(!e.ok){let t=await e.json();R.textContent=t.error||"Delete failed";return}ge.style.display="none",J.style.display="flex",_&&Y(_)}catch{R.textContent="Delete failed"}}),Bn.addEventListener("click",()=>{ge.style.display="none",J.style.display="flex",_&&Y(_)}),Mn.addEventListener("click",async()=>{let e=Et.value.trim();if(!e)return;let t=_+"/"+e;try{let s=await fetch(S("/api/file/touch"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!s.ok){let n=await s.json();R.textContent=n.error||"Create failed";return}Et.value="",_&&Y(_)}catch{R.textContent="Create failed"}});var Ke=document.getElementById("force-narrow-toggle");Ke&&(Ke.checked=Pe(),Ke.addEventListener("change",()=>{try{localStorage.setItem(xt,Ke.checked?"1":"0")}catch{}St(),j()})),St(),document.getElementById("mode-settings").addEventListener("click",()=>{let e=Ct.classList.toggle("open");nt.classList.toggle("open",e)}),nt.addEventListener("click",()=>{Ct.classList.remove("open"),nt.classList.remove("open")});var D="",U=!1,H,Ee=document.createElement("div");Ee.className="session-popover-backdrop",document.body.appendChild(Ee);var N=document.createElement("div");N.id="session-popover",N.className="session-popover",N.style.display="none",N.innerHTML=`<div class="sp-field">
|
|
39
39
|
<label>Rename session</label>
|
|
40
40
|
<input type="text" id="sp-name" />
|
|
41
41
|
</div>
|
|
@@ -45,5 +45,5 @@ var bn=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function
|
|
|
45
45
|
</div>
|
|
46
46
|
<hr class="sp-divider" />
|
|
47
47
|
<button class="btn primary" id="sp-rebuild" style="display:none">\u91CD\u5EFA\u540C\u540D\u540C\u8DEF\u5F84 session</button>
|
|
48
|
-
<button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(
|
|
49
|
-
`).length;P.rows=Math.min(e,4)}),P.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),
|
|
48
|
+
<button class="btn danger" id="sp-delete">Delete session</button>`,document.body.appendChild(N);function Wn(e){let t=e.getBoundingClientRect(),s=window.innerHeight,n=N.offsetHeight||240,a=t.bottom+4;a+n>s-8&&(a=Math.max(8,t.top-n-4)),N.style.top=a+"px",N.style.left=Math.max(8,Math.min(t.left,window.innerWidth-240))+"px"}function Ve(e,t,s){D=e,U=!!s?.tombstone,H=s?.agentId;let n=document.getElementById("sp-name");n.value=e;let a=N.querySelector(".sp-field label");a.textContent=U?"\u91CD\u547D\u540D (\u4EC5\u8BB0\u5F55\uFF0C\u4E0D\u91CD\u5EFA)":"Rename session";let r=document.getElementById("sp-rebuild");r.style.display=U?"":"none";let c=document.getElementById("sp-delete");c.textContent=U?"\u5220\u9664\u5931\u6548\u8BB0\u5F55 (\u5893\u7891\u6D88\u5931)":"Delete session";let o=document.getElementById("sp-save");o.textContent=U?"\u91CD\u547D\u540D":"Save",Ee.classList.add("open"),N.style.display="block",Wn(t),setTimeout(()=>n.focus(),50)}function G(){Ee.classList.remove("open"),N.style.display="none"}Ee.addEventListener("click",G),document.getElementById("sp-save").addEventListener("click",async()=>{let e=document.getElementById("sp-name").value.trim();if(!e||e===D){G();return}try{let t=U?{oldName:D,newName:e,agentId:H}:{oldName:D,newName:e,...H?{agentId:H}:{}};if(!(await fetch(S(U?"/api/sessions/rename-tombstone":"/api/sessions/rename"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).ok)return;G(),j(),!U&&y===D&&(H??null)===x&&we(e,H)}catch{}}),document.getElementById("sp-rebuild").addEventListener("click",async()=>{if(confirm('\u91CD\u5EFA\u4F1A\u8BDD "'+D+'" (\u540C\u540D\u540C\u8DEF\u5F84\uFF0C\u5185\u5BB9\u4E3A\u7A7A)\uFF1F'))try{let e=await fetch(S("/api/sessions/rebuild"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:D,agentId:H})});if(!e.ok){let t=await e.json();alert(t.error||"\u91CD\u5EFA\u5931\u8D25");return}G(),j()}catch{}}),document.getElementById("sp-delete").addEventListener("click",async()=>{if(U){if(!confirm('\u5220\u9664\u5931\u6548\u8BB0\u5F55 "'+D+'"\uFF1F'))return;try{if(!(await fetch(S("/api/sessions/dismiss"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:D,agentId:H})})).ok)return;G(),j()}catch{}return}if(confirm('Delete session "'+D+'"?'))try{if(!(await fetch(S("/api/sessions/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:D,...H?{agentId:H}:{}})})).ok)return;G(),y===D&&(H??null)===x&&(g&&(g.destroy(),g=null),y=null,I.style.display="none",J.style.display="flex"),j()}catch{}}),document.getElementById("sp-cancel").addEventListener("click",G);var Kn={esc:"\x1B",tab:" ","s-tab":"\x1B[Z",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",space:" ",enter:"\r","ctrl-r":"","ctrl-c":"",btw:"/btw ",yes:"yes\r"};document.getElementById("mobile-keys").addEventListener("click",e=>{let t=e.target.closest("button[data-key]");if(!t||!g)return;let s=Kn[t.dataset.key];s&&(g.sendInput(s),g.focus())});var P=document.getElementById("mk-input"),_t=document.getElementById("mk-send");function Yt(){if(!P||!g)return;let e=P.value;e&&(g.sendInput(e+"\r"),P.value="",P.rows=1,g.focus())}if(P&&(P.addEventListener("input",()=>{P.rows=1;let e=P.value.split(`
|
|
49
|
+
`).length;P.rows=Math.min(e,4)}),P.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),Yt())})),_t&&_t.addEventListener("click",Yt),window.visualViewport){let e=document.querySelector(".app-layout"),t=()=>{e&&(e.style.height=window.visualViewport.height+"px"),window.scrollTo(0,0),document.documentElement.scrollTop=0,document.body.scrollTop=0};window.visualViewport.addEventListener("resize",t),window.addEventListener("orientationchange",()=>setTimeout(t,100)),document.addEventListener("touchstart",()=>{(window.scrollY>0||document.documentElement.scrollTop>0)&&window.scrollTo(0,0)},{passive:!0})}var at=document.getElementById("process-panel"),Ce=document.getElementById("proc-list"),Vn=document.getElementById("proc-close"),ot=document.getElementById("proc-backdrop"),Xn=document.getElementById("header-ram");function Jn(){Ce.innerHTML='<div class="proc-empty">Loading\u2026</div>',fetch(S("/api/system/processes")).then(e=>e.json()).then(e=>{if(!Array.isArray(e)||!e.length){Ce.innerHTML='<div class="proc-empty">No processes</div>';return}let t="";for(let s of e){let n=s.rss,a=n<1048576?(n/1024).toFixed(0)+"K":(n/1048576).toFixed(1)+"M";t+='<div class="proc-row" data-pid="'+s.pid+'"><span class="proc-mem">'+s.mem+'%</span><span class="proc-rss">'+a+'</span><span class="proc-cmd" title="'+h(s.command)+'">'+h(s.command)+'</span><button class="proc-kill" title="Kill PID '+s.pid+'">×</button></div>'}Ce.innerHTML=t;for(let s of Ce.querySelectorAll(".proc-row")){let n=s.querySelector(".proc-kill");n&&n.addEventListener("click",a=>{let r=a.target.closest(".proc-row");!r||!confirm("Kill PID "+r.dataset.pid+"?")||fetch(S("/api/system/kill"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({pid:parseInt(r.dataset.pid,10)})}).then(c=>c.json()).then(c=>{c.ok?r.style.opacity="0.3":alert("Failed: "+(c.error||"unknown"))}).catch(()=>alert("Network error"))})}}).catch(()=>{Ce.innerHTML='<div class="proc-empty">Failed to load</div>'})}function Zn(){at.classList.add("open"),ot.classList.add("open"),Jn()}function Xe(){at.classList.remove("open"),ot.classList.remove("open")}Xn.addEventListener("click",e=>{e.stopPropagation(),at.classList.contains("open")?Xe():Zn()}),Vn.addEventListener("click",Xe),ot.addEventListener("click",Xe);var Gn=2e3,ke=null,lt=null,se=new Map,ie=new Map,Qn=5e3,Ot=new Map;function rt(e,t){return(t?"a:"+t+":":"l:")+e}function es(e,t,s){let n=rt(e,t);if(s==="working"){let p=Ot.get(n);if(p&&Date.now()<p)return}let a=ie.get(n),r=e===y&&(t??null)===x,c=s==="idle"&&a?.state==="working";ie.set(n,{session:e,agentId:t,state:s,doneUntil:c?Date.now()+Gn:void 0,unread:c?!r:!1});let o=t?'.session-item[data-agent="'+CSS.escape(t)+'"][data-session="'+CSS.escape(e)+'"]':'.session-item[data-session="'+CSS.escape(e)+'"]:not([data-agent])',u=f.querySelector(o);u&&Je(u,n,ie.get(n))}function Je(e,t,s){let n=se.get(t);n&&(clearTimeout(n),se.delete(t)),e.classList.remove("working","just-done");let a=s.session===y&&(s.agentId??null)===x;s.state==="working"?e.classList.add("working"):a&&s.doneUntil&&Date.now()<s.doneUntil?(e.classList.add("just-done"),se.set(t,setTimeout(()=>{e.classList.remove("just-done"),se.delete(t)},Math.max(0,s.doneUntil-Date.now())))):!a&&s.unread&&e.classList.add("just-done")}function ct(){for(let[e,t]of ie){let s=t.agentId?'.session-item[data-agent="'+CSS.escape(t.agentId)+'"][data-session="'+CSS.escape(t.session)+'"]':'.session-item[data-session="'+CSS.escape(t.session)+'"]:not([data-agent])',n=f.querySelector(s);n&&Je(n,e,t)}}function ts(e,t){let s=rt(e,t),n=ie.get(s);if(!n)return;let a=se.get(s);a&&(clearTimeout(a),se.delete(s)),n.doneUntil=void 0,n.unread=!1;let r=t?'.session-item[data-agent="'+CSS.escape(t)+'"][data-session="'+CSS.escape(e)+'"]':'.session-item[data-session="'+CSS.escape(e)+'"]:not([data-agent])',c=f.querySelector(r);c&&Je(c,s,n)}function Wt(){if(ke||lt)return;let e=localStorage.getItem("tmux-web-token"),t=(location.protocol==="https:"?"wss:":"ws:")+"//"+location.host+"/ws/activity";e&&(t+="?token="+encodeURIComponent(e));try{let s=new WebSocket(t);ke=s,s.onmessage=n=>{try{let a=JSON.parse(String(n.data));a&&a.type==="session.activity"&&typeof a.session=="string"&&es(a.session,a.agentId||void 0,a.state==="working"?"working":"idle")}catch{}},s.onclose=()=>{ke===s&&(ke=null,lt=setTimeout(()=>{lt=null,Wt()},5e3))},s.onerror=()=>{try{s.close()}catch{}}}catch{ke=null}}window.__openSession=we,window.__refreshSidebar=j,j(),$e(),ct(),Wt(),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&ct()}),setInterval(()=>{document.visibilityState==="visible"&&j()},1e4);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const
|
|
2
|
-
`)}selectRows(o
|
|
3
|
-
`)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}}function
|
|
4
|
-
\x1B[31m`+
|
|
5
|
-
`).then(()=>{
|
|
1
|
+
const Ot=/\x1b\](?:10|11|110|111|104)(?:;[^\x07\x1b]*)?\x1b?(?:\\|\x07)/g;function rt(a){return a.replace(/\x1b\[\?1049[hl]/g,"")}function N(a){return a.replace(Ot,"")}let H;function Nt(){return H||(document.querySelector("link[data-tmux-web-xterm-css]")?H=Promise.resolve():(H=new Promise(i=>{const o=document.createElement("link");o.rel="stylesheet",o.href="/assets/xterm.css",o.setAttribute("data-tmux-web-xterm-css",""),o.addEventListener("load",()=>i(),{once:!0}),o.addEventListener("error",()=>i(),{once:!0}),document.head.appendChild(o)}),H))}class st{terminal;fitAddon;container;verifyRaf=0;verifyRounds=0;shrinkCols=0;lastLimit=0;lastCheckAt=0;constructor(i,o,n){this.container=i,this.terminal=o,this.fitAddon=n,this.terminal.loadAddon(this.fitAddon),this.terminal.open(i)}static async create(i,o,n){const[{Terminal:l},{FitAddon:h}]=await Promise.all([import("@xterm/xterm"),import("@xterm/addon-fit"),Nt()]),m=new l({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:o,convertEol:!1,smoothScrollDuration:120,theme:n});return new st(i,m,new h)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(i){return new Promise(o=>this.terminal.write(i,()=>{this.lastLimit>0&&this.scheduleColumnCheck(this.lastLimit),o()}))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(i,o=!1){this.terminal.scrollToLine(Math.max(0,i),o)}scrollLines(i){const o=this.terminal.buffer?.active;this.terminal.scrollLines(i)}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){const i=Ht(this.container);if(i.width<=0||i.height<=0)return!1;this.fitAddon.fit();const o=this.terminal.element?.querySelector(".xterm-viewport"),n=o?Math.max(0,o.offsetWidth-o.clientWidth):0,l=this.terminal.element?.querySelector(".vertical.scrollbar"),h=l?Math.max(0,Math.round(l.getBoundingClientRect().width)):0,m=this.container.getBoundingClientRect().left+i.width-n-h-1;if(this.lastLimit=m,this.shrinkCols>0){const s=Math.max(10,this.terminal.cols-this.shrinkCols);s!==this.terminal.cols&&this.terminal.resize(s,this.terminal.rows)}return this.verifyRounds=0,this.scheduleColumnCheck(m,!0),!0}scheduleColumnCheck(i,o=!1){if(this.lastLimit=i,this.verifyRaf)return;const n=Date.now();!o&&n-this.lastCheckAt<250||(this.lastCheckAt=n,this.verifyRaf=requestAnimationFrame(()=>{this.verifyRaf=0;try{this.recheckColumns(this.lastLimit)&&this.verifyRounds<8?(this.verifyRounds++,this.scheduleColumnCheck(this.lastLimit,!0)):this.verifyRounds=0}catch{}}))}recheckColumns(i){const o=this.terminal.element?.querySelector(".xterm-rows");if(!o)return!1;let n=0;for(const f of Array.from(o.children)){const d=f.children;for(let v=d.length-1;v>=0;v--){const b=d[v];if(!b.textContent)continue;const x=b.getBoundingClientRect().right;x>n&&(n=x);break}}if(n===0)return!1;const l=this.terminal.cols,m=this.terminal.element?.querySelector(".xterm-screen")?.getBoundingClientRect().width??0,s=l>0&&m>0?m/l:0;if(n>i){const f=n-i,d=s>0?Math.min(8,Math.ceil(f/s)):1,v=Math.max(10,l-Math.max(1,d));return v>=l?!1:(this.shrinkCols+=l-v,this.terminal.resize(v,this.terminal.rows),!0)}if(this.shrinkCols>0&&s>0&&n<=i-s){const f=Math.floor((i-n)/s)-1,d=Math.min(this.shrinkCols,Math.min(8,Math.max(1,f)));return this.shrinkCols-=d,this.terminal.resize(l+d,this.terminal.rows),!0}return!1}focus(){this.terminal.focus()}pasteText(i){this.terminal.paste(i)}input(i){this.terminal.input(i,!1)}onData(i){this.terminal.onData(i),this.terminal.onBinary(i)}onResize(i){this.terminal.onResize(i)}onScroll(i){this.terminal.onScroll(i)}attachCustomKeyEventHandler(i){this.terminal.attachCustomKeyEventHandler(i)}isFocused(){const i=document.activeElement;return i?i===this.container||i===this.terminal.textarea||this.container.contains(i)||!!i.closest?.(".xterm"):!1}getScreenText(){return this.getRowsText(0,this.terminal.rows-1)}getRowsText(i,o){const n=this.terminal.buffer.active,[l,h]=i<=o?[i,o]:[o,i],m=n.viewportY,s=[];for(let f=l;f<=h;f++){const d=n.getLine(m+f);s.push(d?d.translateToString(!0):"")}return s.join(`
|
|
2
|
+
`)}selectRows(i,o){const n=this.terminal.buffer.active,[l,h]=i<=o?[i,o]:[o,i];this.terminal.selectLines(n.viewportY+l,n.viewportY+h)}selectCells(i,o,n,l){const h=this.terminal.buffer.active,m=Math.min(o,l),s=Math.max(o,l);if(m===s){const f=Math.min(i,n),d=Math.max(i,n);this.terminal.select(f,h.viewportY+m,d-f+1)}else this.terminal.selectLines(h.viewportY+m,h.viewportY+s)}getCellsText(i,o,n,l){const h=this.terminal.buffer.active,m=Math.min(o,l),s=Math.max(o,l),f=o<l?i:o>l?n:Math.min(i,n),d=o<l?n:o>l?i:Math.max(i,n),v=h.viewportY,b=[];for(let x=m;x<=s;x++){const _=h.getLine(v+x);if(!_){b.push("");continue}const g=x===m?f:0,S=x===s?d:this.terminal.cols-1;let F="";for(let j=g;j<=S;j++){const k=_.getCell(j);k&&(F+=k.getChars())}b.push(F.replace(/\s+$/,""))}return b.join(`
|
|
3
|
+
`)}getSelection(){return this.terminal.getSelection()}clearSelection(){this.terminal.clearSelection()}hasSelectionSupport(){return!0}}function Ht(a){const i=a.getBoundingClientRect(),o=window.visualViewport;return o?{width:Math.min(i.width,o.width),height:Math.max(0,Math.min(i.height,o.height-Math.max(0,i.top)))}:i}function jt(a,i,o){return a.innerHTML="",a.classList.add("terminal-pending"),(async()=>{const n=await st.create(a,o.scrollback,o.theme);let l,h=0,m,s=null,f=0,d=0;const v=.2,b=10,x=.95,_=.04;let g=null,S=null;function F(t){g||(g=document.createElement("div"),g.style.cssText=["position:absolute","left:0","width:40%","padding:10px 0","text-align:center","font:600 14px/1.4 system-ui, -apple-system, sans-serif","color:rgba(255,255,255,0.95)","background:rgba(20,30,50,0.55)","border:1px solid rgba(255,255,255,0.25)","border-radius:10px","pointer-events:none","opacity:0","transition:opacity 0.15s ease","z-index:6"].join(";"),a.appendChild(g)),g.textContent=t?"\u2191 \u4E0A\u7FFB\u4E00\u9875 (PgUp)":"\u2193 \u4E0B\u7FFB\u4E00\u9875 (PgDn)",g.style.top=t?"10%":"auto",g.style.bottom=t?"auto":"10%",g.style.opacity="1",S&&clearTimeout(S),S=setTimeout(()=>{g&&(g.style.opacity="0")},900)}function j(){S&&clearTimeout(S),g&&(g.style.opacity="0")}function k(){f&&(cancelAnimationFrame(f),f=0),d=0}function gt(t){if(k(),Math.abs(t)<v)return;d=Math.max(-b,Math.min(b,t));const e=()=>{if(M){f=0;return}const r=a.querySelector(".xterm-rows > div"),u=r?r.getBoundingClientRect().height:16;let c=u>0?Math.round(d*16/u):d>0?1:-1;c===0&&(c=d>0?1:-1);const T=n.viewportY()-c,et=n.baseY(),O=Math.max(0,Math.min(T,et));if(n.scrollToLine(O,!0),d*=x,O!==T){f=0;return}if(Math.abs(d)<_){f=0;return}f=requestAnimationFrame(e)};f=requestAnimationFrame(e)}let W=0,C="connecting",V=0,R=!1,J=[],I="",M=!1,B=1e3;const wt=location.protocol==="https:"?"wss:":"ws:",at=o.wsBase||"/ws",vt=wt+"//"+location.host+at+"/"+encodeURIComponent(i),xt=(at.replace(/^\/ws/,"")||"")+"/api/session/"+encodeURIComponent(i)+"/upload",Tt=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function bt(){return J.join("")+I}async function Ct(t,e=0){const r=t?n.viewportY():0,u=N(bt());if(n.reset(),!u){t||n.scrollToBottom();return}await n.write(u),t?n.scrollToLine(e+r):n.scrollToBottom()}function D(t){l?.readyState===WebSocket.OPEN&&l.send(JSON.stringify(t))}function Et(t){let e;try{e=JSON.parse(t)}catch{C==="live"&&(I+=t,n.write(N(t)));return}if(e.type==="auth.required"){const r=localStorage.getItem("tmux-web-token");r?D({type:"auth.token",token:r}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(e.type==="attach_failed"&&typeof e.message=="string"){G=!0,C="dead",n.reset(),n.write(`\r
|
|
4
|
+
\x1B[31m`+N(e.message)+`\x1B[0m\r
|
|
5
|
+
`).then(()=>{$();try{l?.close()}catch{}});return}if(e.type==="auth.ok"){e.token&&localStorage.setItem("tmux-web-token",e.token),B=1e3,P(),D({type:"resize",cols:n.cols,rows:n.rows}),w();return}if(e.type==="auth.failed"){if(e.permanentLock||e.retryAfterMs&&e.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(e.message);return}return}if(e.type==="snapshot"&&typeof e.data=="string"){const r=rt(N(e.data));J=[r],I="",V=typeof e.lines=="number"?e.lines:o.terminal.initialLines,C="live",n.reset(),P(),D({type:"resize",cols:n.cols,rows:n.rows}),n.write(r).then(()=>n.scrollToBottom());return}if(e.type==="window_changed"&&typeof e.activeIndex=="number"){const r=new URL(location.href);r.searchParams.get("window")!==String(e.activeIndex)&&(r.searchParams.set("window",String(e.activeIndex)),history.replaceState(history.state,"",r)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:e.windows}));return}if(e.type==="history"&&typeof e.data=="string"){e.lines>0&&e.data?(J.unshift(rt(e.data)),V+=e.lines,Ct(!0,e.lines).finally(()=>{R=!1})):R=!1;return}if(e.type==="data"&&typeof e.data=="string"){const r=rt(N(e.data));if(C==="connecting"){C="live",I=r,n.write(r);return}C==="live"&&(I+=r,n.write(r))}}let G=!1;function lt(){if(G)return;let t=vt;const e=localStorage.getItem("tmux-web-token");e&&(t+=(t.includes("?")?"&":"?")+"token="+encodeURIComponent(e)),t+=(t.includes("?")?"&":"?")+"cols="+n.cols+"&rows="+n.rows,l=new WebSocket(t),l.onopen=()=>{C="connecting",V=0,R=!1,J=[],I="",n.reset(),B=1e3},l.onmessage=r=>{typeof r.data=="string"&&Et(r.data)},l.onclose=()=>{M||(C="connecting",!G&&setTimeout(()=>{B=Math.min(B*2,1e4),!M&&!G&<()},B))},l.onerror=()=>l?.close()}function Y(t){D({type:"input",data:t})}function P(){return n.fit()}function $(){a.classList.remove("terminal-pending")}function w(){h&&cancelAnimationFrame(h),m&&clearTimeout(m),P(),h=requestAnimationFrame(()=>{h=0,P()&&$()}),m=setTimeout(()=>{P()&&$()},120)}function Lt(){w(),setTimeout(w,50),setTimeout(w,150),setTimeout(w,300)}function ct(t){return typeof t=="string"&&t.startsWith("image/")}function ut(t){return t?.files?.length?t.files[0]??null:null}function Mt(t){if(!t?.items)return null;for(let e=0;e<t.items.length;e++){const r=t.items[e];if(r?.kind==="file"&&ct(r.type))return r.getAsFile()}return null}async function St(t){const e=new FormData,r=t instanceof File&&t.name?t.name:"upload";e.append("file",t,r);const u=localStorage.getItem("tmux-web-token"),c={};u&&(c.Authorization="Bearer "+u);const L=await fetch(xt,{method:"POST",body:e,headers:c});if(!L.ok){let et="upload failed";try{const O=await L.json();O.error&&(et=O.error)}catch{}throw new Error(et)}const T=await L.json();if(!T.path)throw new Error("no path in response");return T.path}async function nt(t){try{const e=await St(t);Y(e)}catch{}}n.onData(t=>Y(t)),n.onResize(({cols:t,rows:e})=>D({type:"resize",cols:t,rows:e})),n.onScroll(()=>{C!=="live"||R||!n.isNearScrollbackTop()||(R=!0,D({type:"load_history",before:V}))});let z=!1,K=!1,p=null,y=null;const U=document.createElement("div");U.className="terminal-copy-banner",U.innerHTML='<strong>Copy mode</strong><span class="hint">drag to copy \xB7 Esc exits</span>',U.hidden=!0,a.appendChild(U);const E=document.createElement("div");E.className="terminal-copy-banner terminal-copy-toast",E.textContent="Copied",E.hidden=!0,a.appendChild(E);function ft(t,e){const r=a.querySelector(".xterm-screen, canvas"),c=(r&&r.getBoundingClientRect().width>0?r:a).getBoundingClientRect(),L=c.height>0&&n.rows>0?c.height/n.rows:18,T=c.width>0&&n.cols>0?c.width/n.cols:9;return{row:Math.max(0,Math.min(n.rows-1,Math.floor((e-c.top)/L))),col:Math.max(0,Math.min(n.cols-1,Math.floor((t-c.left)/T)))}}async function Q(t){if(!t)return;try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(t);return}}catch{}const e=document.createElement("textarea");e.value=t,e.style.position="fixed",e.style.opacity="0",e.style.pointerEvents="none",document.body.appendChild(e),e.focus(),e.select();try{document.execCommand("copy")}catch{}e.remove()}let q;function Z(){E.hidden=!1,q&&clearTimeout(q),q=setTimeout(()=>{E.hidden=!0},1e3)}function A(t){z=t,U.hidden=!t,a.classList.toggle("terminal-copy-mode-active",t),t&&n.focus()}function dt(){A(!z)}function kt(t){M||t.button!==0||K||(z||t.shiftKey)&&(t.preventDefault(),t.stopPropagation(),K=!0,p=ft(t.clientX,t.clientY),y=p,n.selectCells(p.col,p.row,y.col,y.row),document.addEventListener("mousemove",it,!0),document.addEventListener("mouseup",ot,!0))}function it(t){M||!K||!p||(t.preventDefault(),t.stopPropagation(),y=ft(t.clientX,t.clientY),n.selectCells(p.col,p.row,y.col,y.row))}function ot(t){if(M||!K||!p||!y)return;t.preventDefault(),t.stopPropagation(),document.removeEventListener("mousemove",it,!0),document.removeEventListener("mouseup",ot,!0),K=!1;const e=n.getCellsText(p.col,p.row,y.col,y.row);p=null,y=null,n.clearSelection(),A(!1),e&&(E.textContent="\u5DF2\u590D\u5236",Q(e).then(Z)),n.focus()}a.addEventListener("mousedown",kt,!0),document.addEventListener("keydown",Dt,!0);function Dt(t){if(!(M||!n.isFocused()||t.defaultPrevented||t.isComposing)){if(z){if(t.key==="Escape"){t.preventDefault(),t.stopPropagation(),p=null,y=null,n.clearSelection(),A(!1);return}if(t.key==="Enter"||(t.ctrlKey||t.metaKey)&&t.code==="KeyC"){t.preventDefault(),t.stopPropagation(),Q(n.getScreenText()).then(Z),A(!1);return}}if(t.altKey&&t.code==="KeyC"&&!t.ctrlKey&&!t.metaKey){if(t.preventDefault(),t.stopPropagation(),p&&y){const e=n.getCellsText(p.col,p.row,y.col,y.row);p=null,y=null,n.clearSelection(),A(!1),e&&(E.textContent="Copied",Q(e).then(Z))}else{const e=n.getSelection();e?(n.clearSelection(),E.textContent="Copied",Q(e).then(Z)):dt()}return}if((t.ctrlKey||t.metaKey)&&t.code==="KeyV"){t.preventDefault(),t.stopPropagation(),(async()=>{try{if(navigator.clipboard?.read){const e=await navigator.clipboard.read();for(const r of e)for(const u of r.types)if(ct(u)){const c=await r.getType(u);await nt(c);return}}}catch{}try{const e=await navigator.clipboard?.readText();e&&n.pasteText(ht(e))}catch{}})();return}}}let tt=0;function ht(t){return t.split(`\r
|
|
6
6
|
`).join(`
|
|
7
7
|
`).split(`
|
|
8
|
-
`).join("\r")}async function
|
|
8
|
+
`).join("\r")}async function Pt(t){const e=Mt(t.clipboardData);if(e){t.preventDefault(),t.stopPropagation();const c=Date.now();if(c-tt<50)return;tt=c,await nt(e);return}const r=t.clipboardData?.getData("text/plain");if(!r)return;t.preventDefault(),t.stopPropagation();const u=Date.now();u-tt<50||(tt=u,n.pasteText(ht(r)))}let X=0;function It(t){t.preventDefault(),X++,ut(t.dataTransfer)&&a.classList.add("terminal-drag-over")}function Yt(t){t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy")}function At(t){t.preventDefault(),X--,X<=0&&(X=0,a.classList.remove("terminal-drag-over"))}async function Ft(t){t.preventDefault(),X=0,a.classList.remove("terminal-drag-over");const e=ut(t.dataTransfer);e&&await nt(e)}function mt(t){!Tt||t.key!=="Escape"||z||t.defaultPrevented||t.repeat||t.metaKey||t.ctrlKey||t.altKey||n.isFocused()&&(t.preventDefault(),t.stopPropagation(),Y("\x1B"))}a.addEventListener("paste",Pt),a.addEventListener("dragenter",It),a.addEventListener("dragover",Yt),a.addEventListener("dragleave",At),a.addEventListener("drop",Ft),document.addEventListener("keydown",mt,!0);function Rt(t){if(t.touches.length!==1){s=null;return}const e=t.touches[0];if(!e)return;k();const r=a.getBoundingClientRect(),u=e.clientX-r.left<r.width*.4?"tui":"history",c=e.clientY-r.top<r.height*.5;s={startX:e.clientX,startY:e.clientY,lastX:e.clientX,lastY:e.clientY,lastT:performance.now(),velocity:0,scrolling:!1,zone:u,tuiUp:c,sent:!1},t.stopPropagation()}function Bt(t){if(!s||t.touches.length!==1)return;const e=t.touches[0];if(!e)return;const r=e.clientY-s.startY,u=e.clientX-s.startX;if(!s.scrolling){if(Math.abs(r)<8||Math.abs(r)<Math.abs(u))return;s.scrolling=!0,W=Date.now()+500}t.preventDefault(),t.stopPropagation();const c=performance.now(),L=e.clientY-s.lastY;if(s.zone==="tui"){s.sent||(s.sent=!0,Y(s.tuiUp?"\x1B[5~":"\x1B[6~"),F(s.tuiUp)),s.lastX=e.clientX,s.lastY=e.clientY,s.lastT=c;return}const T=c-s.lastT;T>0&&(s.velocity=L/T),qt(-L),s.lastX=e.clientX,s.lastY=e.clientY,s.lastT=c}function zt(t){if(!s)return;const e=s.scrolling,r=s.zone,u=s.tuiUp,c=s.velocity;if(s=null,t.stopPropagation(),r==="tui"){e||(Y(u?"\x1B[5~":"\x1B[6~"),F(u),W=Date.now()+500,t.preventDefault());return}if(!e){n.focus();return}W=Date.now()+500,t.preventDefault(),c&>(c)}function Kt(t){s=null,k(),t.stopPropagation()}function Ut(t){t.pointerType==="touch"&&Date.now()<W&&(t.preventDefault(),t.stopPropagation())}function qt(t){const e=a.querySelector(".xterm-rows > div"),r=e?e.getBoundingClientRect().height:16;let u=r>0?Math.round(t/r):t>0?1:-1;u===0&&(u=t>0?1:-1),n.scrollLines(u)}a.addEventListener("touchstart",Rt,{passive:!0,capture:!0}),a.addEventListener("touchmove",Bt,{passive:!1,capture:!0}),a.addEventListener("touchend",zt,{passive:!1,capture:!0}),a.addEventListener("touchcancel",Kt,{passive:!0,capture:!0}),a.addEventListener("pointerup",Ut,!0);function pt(){w()}window.addEventListener("resize",pt),window.visualViewport?.addEventListener("resize",w),window.visualViewport?.addEventListener("scroll",w);const yt=new ResizeObserver(()=>w());yt.observe(a),document.fonts?.ready.then(()=>{w(),setTimeout(w,50),setTimeout(w,200)}),a.addEventListener("focusin",Lt,!0);async function Xt(){if(document.fonts?.ready)try{await Promise.race([document.fonts.ready,new Promise(t=>setTimeout(t,1e3))])}catch{}}return requestAnimationFrame(()=>{P()&&$(),(async()=>(await Xt(),P()&&D({type:"resize",cols:n.cols,rows:n.rows}),lt(),w()))()}),{destroy(){if(M=!0,k(),A(!1),q&&clearTimeout(q),document.removeEventListener("mousemove",it,!0),document.removeEventListener("mouseup",ot,!0),l){try{l.close(1e3,"session switch")}catch{}l=void 0}a.innerHTML="",a.classList.remove("terminal-pending"),window.removeEventListener("resize",pt),yt.disconnect(),document.removeEventListener("keydown",mt,!0)},focus(){n.focus()},sendInput(t){Y(t)},toggleCopyMode(){dt()}}})()}export{jt as initTerminal,rt as stripAltScreenSequences};
|