tmux-weblink 2.0.7 → 2.0.8
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/lib/attach-terminal.js +5 -5
- package/dist/lib/scheduler.js +1 -1
- package/dist/lib/tmux-capture.js +3 -3
- package/dist/lib/tmux-control.js +2 -2
- package/dist/lib/tmux-env.js +1 -0
- package/dist/lib/tmux-panes.js +2 -2
- package/dist/lib/tmux-windows.js +4 -4
- package/dist/sessions.js +2 -2
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import*as O from"node-pty";const f=new Set;function
|
|
2
|
-
`})}m&&(r.send({type:"data",data:m}),m="")}},E=()=>{d&&(u&&clearTimeout(u),u=setTimeout(P,k))};function $(){if(s)return;try{a=A(
|
|
3
|
-
\x1B[31mFailed to attach to tmux session "${
|
|
4
|
-
`}),
|
|
1
|
+
import*as O from"node-pty";import{tmuxEnv as _}from"./tmux-env.js";const f=new Set;function H(){for(const e of[...f])try{e()}catch{}f.clear()}function K(){return f.size}function j(e,r,n){const{initialLines:M,historyChunk:C,syncIdleMs:k,syncMaxMs:g}=n.terminalBufferConfig,A=n.spawn??(o=>{const c=n.tmuxSocketPath?["-S",n.tmuxSocketPath]:[];return c.push("attach-session","-t",o),O.spawn("tmux",c,{name:"xterm-256color",cols:80,rows:24,cwd:process.env.HOME||"/",env:_()})});let a=null,y=e,h=null,w=0,S="",d=!0,m="",u=null,p=null,s=!1;const T=()=>{u&&(clearTimeout(u),u=null),p&&(clearTimeout(p),p=null)},P=()=>{if(!(!d||s)){T(),d=!1;try{y=n.getSessionPaneTarget(e)}catch{y=e}try{const o=n.capturePaneTail(y,M);r.send({type:"snapshot",data:n.toCrlf(o),lines:M})}catch{r.send({type:"data",data:`\r
|
|
2
|
+
`})}m&&(r.send({type:"data",data:m}),m="")}},E=()=>{d&&(u&&clearTimeout(u),u=setTimeout(P,k))};function $(){if(s)return;try{a=A(e)}catch(t){const l=t?.message??String(t);r.send({type:"data",data:`\r
|
|
3
|
+
\x1B[31mFailed to attach to tmux session "${e}": ${l}\x1B[0m\r
|
|
4
|
+
`}),n.onSpawnError?.(e,l);return}let o=-1,c="";h=n.acquireControlClient(e,({activeIndex:t,windows:l})=>{r.send({type:"window_changed",activeIndex:t,windows:l});const x=l.map(D=>D.index).join(","),v=t!==o||x!==c;o=t,c=x}),w=Date.now(),p=setTimeout(P,g),n.onAttached?.(e),r.onMessage(b),a.onData(t=>{if(!s){if(Date.now()-w<g&&S.length<2048&&(S+=t),d){m+=t,E();return}r.send({type:"data",data:t})}}),a.onExit(({exitCode:t})=>{if(T(),a&&(a=null),!s){if(t!==0&&Date.now()-w<g){const l=S.trim();n.onSpawnError?.(e,l?`tmux attach-session failed: ${l}`:`tmux attach-session exited with code ${t}`);return}n.onPtyExit?.(e,t),r.send({type:"data",data:`\r
|
|
5
5
|
\x1B[2m--- tmux exited (code ${t}) ---\x1B[0m\r
|
|
6
|
-
`}),i()}})}function i(){if(!s){if(s=!0,T(),h&&(h(),h=null),a){try{a.kill()}catch{}a=null}f.delete(i)}}r.onClose(i);const b=o=>{if(s||!a)return;try{if(
|
|
6
|
+
`}),i()}})}function i(){if(!s){if(s=!0,T(),h&&(h(),h=null),a){try{a.kill()}catch{}a=null}f.delete(i)}}r.onClose(i);const b=o=>{if(s||!a)return;try{if(n.handleClientMessage(o,a))return}catch{return}let c;try{c=JSON.parse(o)}catch{return}if(c.type==="load_history"&&typeof c.before=="number"){const t=Math.max(0,Math.floor(c.before));try{const{data:l,lines:x}=n.capturePaneHistoryChunk(y,t,C);r.send({type:"history",data:n.toCrlf(l),before:t,lines:x})}catch{r.send({type:"history",data:"",before:t,lines:0})}}};return $(),f.add(i),{onMessage:b,dispose:i}}export{K as _liveAttachmentCount,j as attachTerminal,H as killAllAttachedPtys};
|
package/dist/lib/scheduler.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as o}from"node:child_process";import{randomUUID as
|
|
1
|
+
import{execFileSync as o}from"node:child_process";import{tmuxEnv as h}from"./tmux-env.js";import{randomUUID as u}from"node:crypto";import{ARM_SCAN_INTERVAL_MS as T,isValidDelayMs as l,MAX_TIMER_MS as d}from"./schedule-delay.js";const m=10080*60*1e3;function f(n,e,s){const t=`${n}:${e}`;o("tmux",["send-keys","-t",t,"-l",s],{timeout:5e3,env:h()}),o("tmux",["send-keys","-t",t,"Enter"],{timeout:5e3,env:h()})}function I(n){if(!n||typeof n!="object")return!1;const e=n;return typeof e.delayMs=="number"&&l(e.delayMs)}function p(n){if(!n||typeof n!="object")return!1;const e=n;return typeof e.sessionName=="string"&&e.sessionName.length>0&&typeof e.windowIndex=="number"&&Number.isInteger(e.windowIndex)&&e.windowIndex>=0&&typeof e.text=="string"&&e.text.length>0&&e.text.length<=4096&&typeof e.delayMs=="number"&&l(e.delayMs)}class b{deps;scheduledTasks=new Map;now;setTimer;clearTimer;setIntervalFn;clearIntervalFn;armScanIntervalMs;createId;sendKeys;onError;onMissedTask;historyRetentionMs;scanIntervalHandle=null;constructor(e){this.deps=e,this.now=e.now??Date.now,this.setTimer=e.setTimer??setTimeout,this.clearTimer=e.clearTimer??clearTimeout,this.setIntervalFn=e.setInterval??setInterval,this.clearIntervalFn=e.clearInterval??clearInterval,this.armScanIntervalMs=e.armScanIntervalMs??T,this.createId=e.createId??u,this.sendKeys=e.sendKeys??f,this.onError=e.onError??(s=>console.error(s)),this.onMissedTask=e.onMissedTask??(()=>{}),this.historyRetentionMs=e.historyRetentionMs??m}record(e){this.deps.db.data.triggeredTasks??=[],this.deps.db.data.triggeredTasks.push(e);const s=this.now()-this.historyRetentionMs;this.deps.db.data.triggeredTasks=this.deps.db.data.triggeredTasks.filter(t=>t.triggeredAt>=s)}listTriggered(){this.deps.db.data.triggeredTasks??=[];const e=this.now()-this.historyRetentionMs;return this.deps.db.data.triggeredTasks.filter(s=>s.triggeredAt>=e).sort((s,t)=>t.triggeredAt-s.triggeredAt)}async restoreFromDb(){const e=this.now(),s=[];for(const r of this.deps.db.data.scheduledTasks)r.fireAt<=e?(s.push(r.id),this.onMissedTask(r),this.record({...r,triggeredAt:e,status:"missed"})):this.registerTask(r);this.deps.db.data.triggeredTasks??=[];const t=this.deps.db.data.triggeredTasks.length,i=e-this.historyRetentionMs;this.deps.db.data.triggeredTasks=this.deps.db.data.triggeredTasks.filter(r=>r.triggeredAt>=i);const a=this.deps.db.data.triggeredTasks.length!==t;s.length&&(this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(r=>!s.includes(r.id))),(s.length||a)&&await this.deps.db.write(),this.scanPending(),this.startScanLoop()}list(e){return[...this.scheduledTasks.values()].filter(s=>!e||s.sessionName===e).map(({id:s,sessionName:t,windowIndex:i,text:a,fireAt:r,createdAt:c})=>({id:s,sessionName:t,windowIndex:i,text:a,fireAt:r,createdAt:c,remainingMs:Math.max(0,r-this.now())})).sort((s,t)=>s.fireAt-t.fireAt)}async create(e){const s=this.createId(),t=this.now(),i={id:s,sessionName:e.sessionName,windowIndex:e.windowIndex,text:e.text,fireAt:t+e.delayMs,createdAt:t};return this.registerTask(i),this.deps.db.data.scheduledTasks.push(i),await this.deps.db.write(),this.tryArm(i.id),i}async reschedule(e,s){const t=this.scheduledTasks.get(e);if(!t)return null;this.disarmTask(e);const i={...t,fireAt:this.now()+s};this.registerTask(i);const a=this.deps.db.data.scheduledTasks.findIndex(r=>r.id===e);return a>=0&&(this.deps.db.data.scheduledTasks[a]=i),await this.deps.db.write(),this.tryArm(e),i}async delete(e){return this.scheduledTasks.get(e)?(this.disarmTask(e),this.scheduledTasks.delete(e),this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(t=>t.id!==e),await this.deps.db.write(),!0):!1}cleanup(){if(this.scanIntervalHandle!=null){try{this.clearIntervalFn(this.scanIntervalHandle)}catch{}this.scanIntervalHandle=null}for(const e of this.scheduledTasks.values())if(e.timeoutHandle!=null)try{this.clearTimer(e.timeoutHandle)}catch{}this.scheduledTasks.clear()}scanPending(){for(const e of[...this.scheduledTasks.values()]){const s=e.fireAt-this.now();if(s<=0){e.timeoutHandle!=null&&this.disarmTask(e.id),this.fireTask(e);continue}s<=d&&e.timeoutHandle==null&&this.armTask(e)}}registerTask(e){this.scheduledTasks.set(e.id,{...e,timeoutHandle:null})}disarmTask(e){const s=this.scheduledTasks.get(e);s&&s.timeoutHandle!=null&&(this.clearTimer(s.timeoutHandle),s.timeoutHandle=null)}tryArm(e){const s=this.scheduledTasks.get(e);if(!s)return;const t=s.fireAt-this.now();if(t<=0){this.fireTask(s);return}t<=d&&s.timeoutHandle==null&&this.armTask(s)}armTask(e){const s=e.fireAt-this.now();if(s<=0){this.fireTask(e);return}this.disarmTask(e.id);const t=Math.min(s,d),i=this.setTimer(()=>this.onTimer(e.id),t);this.scheduledTasks.set(e.id,{...e,timeoutHandle:i})}onTimer(e){const s=this.scheduledTasks.get(e);if(s){if(s.timeoutHandle=null,s.fireAt<=this.now()){this.fireTask(s);return}this.armTask(s)}}startScanLoop(){this.scanIntervalHandle==null&&(this.scanIntervalHandle=this.setIntervalFn(()=>this.scanPending(),this.armScanIntervalMs))}fireTask(e){if(!this.scheduledTasks.has(e.id))return;this.disarmTask(e.id);const s=this.now(),t={id:e.id,sessionName:e.sessionName,windowIndex:e.windowIndex,text:e.text,fireAt:e.fireAt,createdAt:e.createdAt};try{this.sendKeys(e.sessionName,e.windowIndex,e.text),this.record({...t,triggeredAt:s,status:"ok"})}catch(i){const a=String(i?.message??i);this.onError(`[scheduler] send-keys to ${e.sessionName}:${e.windowIndex} failed: ${a}`),this.record({...t,triggeredAt:s,status:"error",error:a})}this.scheduledTasks.delete(e.id),this.deps.db.data.scheduledTasks=this.deps.db.data.scheduledTasks.filter(i=>i.id!==e.id),this.deps.db.write().catch(this.onError)}}export{b as SchedulerService,I as isValidRescheduleInput,p as isValidScheduleInput,f as sendTmuxKeys};
|
package/dist/lib/tmux-capture.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{execFileSync as f}from"node:child_process";const
|
|
2
|
-
`)}function o(n){return f("tmux",n,{encoding:"utf-8",timeout:l}).trimEnd()}function
|
|
1
|
+
import{execFileSync as f}from"node:child_process";import{tmuxEnv as l}from"./tmux-env.js";const m=3e3;function _(n){return n.replace(/\r?\n/g,`\r
|
|
2
|
+
`)}function o(n){return f("tmux",n,{encoding:"utf-8",timeout:m,env:l()}).trimEnd()}function h(n){return o(["display-message","-p","-t",n,"#{session_name}:#{window_index}.#{pane_index}"])}function x(n){const t=o(["display-message","-p","-t",n,"#{history_size}"]),e=parseInt(t,10);return Number.isFinite(e)?e:0}function y(n){return o(["display-message","-p","-t",n,"#{alternate_on}"])==="1"}function c(n,t,e){const i=["capture-pane","-t",n,"-p","-e","-S",String(t)];return e!==void 0&&i.push("-E",String(e)),o(i)}function P(n,t){return c(n,-t)}function T(n,t,e){const i=x(n);if(t>=i)return{data:"",lines:0};const p=-(t+e),a=-(t+1);let r=c(n,p,a);const u=r===""?0:r.split(`
|
|
3
3
|
`).length,s=Math.min(e,u,i-t);return s<u&&s>0&&(r=r.split(`
|
|
4
4
|
`).slice(-s).join(`
|
|
5
|
-
`)),{data:r,lines:s}}export{
|
|
5
|
+
`)),{data:r,lines:s}}export{T as capturePaneHistoryChunk,c as capturePaneLines,P as capturePaneTail,x as getPaneHistorySize,h as getSessionPaneTarget,y as isAlternateScreen,_ as toCrlf};
|
package/dist/lib/tmux-control.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import*as w from"node-pty";import{
|
|
2
|
-
`))>=0;){const b=t.buf.slice(0,d).replace(/\r$/,"");t.buf=t.buf.slice(d+1),
|
|
1
|
+
import*as w from"node-pty";import{tmuxEnv as p}from"./tmux-env.js";import{captureAndStoreWindows as T}from"./session-windows.js";import{recordWindowVisit as x}from"./window-history.js";const h=["%session-window-changed","%window-add","%window-close","%unlinked-window-close","%window-renamed","%session-renamed"];function y(e){return h.some(r=>e.startsWith(r))}const C=75,v=e=>w.spawn("tmux",["-CC","attach-session","-t",e,"-f","ignore-size,no-output"],{name:"xterm-256color",cols:80,rows:24,cwd:process.env.HOME||"/",env:p()});function E(e){const r=T(e);if(!r.length)return null;const o=r.find(i=>i.active);return o&&x(e,o.index,o.name),{activeIndex:o?o.index:r[0].index,windows:r.map(i=>({index:i.index,name:i.name,active:i.active}))}}const c=new Map;function S(e,r,o={}){const i=o.spawn??v,a=o.requery??E,f=o.debounceMs??C;let l=c.get(e);if(!l){let n;try{n=i(e)}catch{return()=>{}}const t={pty:n,refCount:0,subscribers:new Set,buf:"",debounceTimer:null,schedule:()=>{}},m=()=>{t.debounceTimer=null;let u;try{u=a(e)}catch{u=null}if(u)for(const d of t.subscribers)try{d(u)}catch{}};t.schedule=()=>{t.debounceTimer&&clearTimeout(t.debounceTimer),t.debounceTimer=setTimeout(m,f)},n.onData(u=>{t.buf+=u;let d;for(;(d=t.buf.indexOf(`
|
|
2
|
+
`))>=0;){const b=t.buf.slice(0,d).replace(/\r$/,"");t.buf=t.buf.slice(d+1),y(b)&&t.schedule()}}),n.onExit(()=>{t.debounceTimer&&clearTimeout(t.debounceTimer),c.delete(e)}),c.set(e,t),l=t}l.subscribers.add(r),l.refCount+=1,l.schedule();let s=!1;return()=>{if(s)return;s=!0;const n=c.get(e);if(n&&(n.subscribers.delete(r),n.refCount-=1,n.refCount<=0)){n.debounceTimer&&clearTimeout(n.debounceTimer);try{n.pty.kill()}catch{}c.delete(e)}}}function g(){for(const e of c.values()){e.debounceTimer&&clearTimeout(e.debounceTimer);try{e.pty.kill()}catch{}}c.clear()}function k(){return c.size}export{k as _controlClientCount,S as acquireControlClient,g as killAllControlClients,y as shouldRequery};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(){const n={...process.env};return!n.LC_ALL&&!n.LANG&&(n.LC_ALL=process.platform==="darwin"?"en_US.UTF-8":"C.UTF-8"),n}export{e as tmuxEnv};
|
package/dist/lib/tmux-panes.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{execFileSync as u}from"node:child_process";const w=3e3,l="#{pane_id} #{pane_index} #{window_index} #{pane_pid} #{pane_current_command} #{pane_active} #{window_active}";function
|
|
2
|
-
`).filter(Boolean).map(n=>
|
|
1
|
+
import{execFileSync as u}from"node:child_process";import{tmuxEnv as m}from"./tmux-env.js";const w=3e3,l="#{pane_id} #{pane_index} #{window_index} #{pane_pid} #{pane_current_command} #{pane_active} #{window_active}";function x(t,e){const[n,a,r,c,d,p,s]=e.split(" ");if(!n)return null;const i=parseInt(r,10),o=parseInt(a,10);return{paneId:n,paneIndex:Number.isFinite(o)?o:0,windowIndex:Number.isFinite(i)?i:0,pid:parseInt(c,10)||0,command:d??"",active:p==="1",windowActive:s==="1",target:`${t}:${i}.${o}`}}function I(t){try{return u("tmux",["list-panes","-s","-t",t,"-F",l],{encoding:"utf-8",timeout:w,env:m()}).trim().split(`
|
|
2
|
+
`).filter(Boolean).map(n=>x(t,n)).filter(n=>n!==null)}catch{return[]}}function _(t){return I(t).find(n=>n.active&&n.windowActive)??null}export{_ as getActivePaneInfo,I as listSessionPanes};
|
package/dist/lib/tmux-windows.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{execFileSync as r}from"node:child_process";class s extends Error{status;constructor(e,n){super(e),this.status=n,this.name="TmuxWindowsError"}}function
|
|
2
|
-
`).filter(Boolean).map(n=>{const[o,i,w]=n.split(" ");return{index:parseInt(o,10),name:i,active:w==="1"}})}catch{return[]}}function
|
|
3
|
-
`).filter(Boolean).map(n=>{const[o,i,w,
|
|
4
|
-
`);return!n||!o?!1:n!==o}catch{return!1}}function
|
|
1
|
+
import{execFileSync as r}from"node:child_process";import{tmuxEnv as a}from"./tmux-env.js";class s extends Error{status;constructor(e,n){super(e),this.status=n,this.name="TmuxWindowsError"}}function m(t){try{return r("tmux",["list-windows","-t",t,"-F","#{window_index} #{window_name} #{window_active}"],{encoding:"utf-8",timeout:3e3}).trim().split(`
|
|
2
|
+
`).filter(Boolean).map(n=>{const[o,i,w]=n.split(" ");return{index:parseInt(o,10),name:i,active:w==="1"}})}catch{return[]}}function x(t){try{return r("tmux",["list-windows","-t",t,"-F","#{window_index} #{window_name} #{window_active} #{pane_current_path}"],{encoding:"utf-8",timeout:3e3}).trim().split(`
|
|
3
|
+
`).filter(Boolean).map(n=>{const[o,i,w,c]=n.split(" ");return{index:parseInt(o,10),name:i,active:w==="1",path:c??""}})}catch{return[]}}function p(t){if(!t)return!1;try{const e=r("git",["-C",t,"rev-parse","--git-dir","--git-common-dir"],{encoding:"utf-8",timeout:3e3,stdio:["ignore","pipe","ignore"]}),[n,o]=e.trim().split(`
|
|
4
|
+
`);return!n||!o?!1:n!==o}catch{return!1}}function u(t){try{return r("tmux",["has-session","-t",t],{timeout:3e3,env:a()}),!0}catch{return!1}}function l(t){if(!u(t))throw new s("session not found",404);try{r("tmux",["new-window","-t",t],{timeout:3e3,env:a()})}catch(e){const n=e instanceof Error?e.message:"new-window failed";throw new s(n,500)}}function h(t,e){const n=["new-session","-d","-s",t];e&&n.push("-c",e);try{r("tmux",n,{timeout:5e3,env:a()})}catch(o){const i=o instanceof Error?o.message:"new-session failed";throw new s(i,500)}}function g(t,e){r("tmux",["rename-session","-t",t,e],{timeout:5e3,env:a()})}function v(t){r("tmux",["kill-session","-t",t],{timeout:5e3,env:a()})}function y(t,e){if(!u(t))throw new s("session not found",404);if(!m(t).some(o=>o.index===e))throw new s("window not found",404);try{r("tmux",["select-window","-t",`${t}:${e}`],{timeout:3e3})}catch(o){const i=o instanceof Error?o.message:"select-window failed";throw new s(i,500)}}function E(t,e,n){if(!u(t))throw new s("session not found",404);if(!m(t).some(w=>w.index===e))throw new s("window not found",404);const i=n.trim();if(!i)throw new s("name is required",500);try{r("tmux",["rename-window","-t",`${t}:${e}`,i],{timeout:3e3})}catch(w){const c=w instanceof Error?w.message:"rename-window failed";throw new s(c,500)}}export{s as TmuxWindowsError,x as captureSessionWindowsWithPath,p as isGitWorktree,v as killSession,m as listSessionWindows,l as newSessionWindow,h as newTmuxSession,g as renameSession,E as renameSessionWindow,y as selectSessionWindow};
|
package/dist/sessions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{execFileSync as
|
|
2
|
-
`).filter(Boolean).map(t=>{const[s,
|
|
1
|
+
import{execFileSync as n}from"node:child_process";import{tmuxEnv as e}from"./lib/tmux-env.js";function a(){try{return n("tmux",["display-message","-p","#{socket_path}"],{encoding:"utf-8",timeout:3e3,env:e()}).trim()||null}catch{return null}}function m(){try{return n("tmux",["list-sessions","-F","#{session_name} #{session_windows} #{session_attached}"],{encoding:"utf-8",timeout:3e3,env:e()}).trim().split(`
|
|
2
|
+
`).filter(Boolean).map(t=>{const[s,i,r]=t.split(" ");return{name:s,windows:parseInt(i,10),attached:r!=="0"}})}catch{return[]}}export{m as listSessions,a as resolveTmuxSocketPath};
|