tmux-weblink 0.3.0
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 +70 -0
- package/dist/assets/addon-fit-D5N335P2.js +16 -0
- package/dist/assets/terminal-client.js +4 -0
- package/dist/assets/xterm-NI46XXQY.js +51 -0
- package/dist/assets/xterm.css +285 -0
- package/dist/browser/terminal-client.js +4 -0
- package/dist/frontend.js +1 -0
- package/dist/index.js +12 -0
- package/dist/lib/agent-detect.js +3 -0
- package/dist/lib/agents-watch.js +2 -0
- package/dist/lib/atomicWrite.js +1 -0
- package/dist/lib/auditLog.js +1 -0
- package/dist/lib/auth.js +2 -0
- package/dist/lib/cli.js +32 -0
- package/dist/lib/commandbar.js +555 -0
- package/dist/lib/db.js +1 -0
- package/dist/lib/drawer-resize.js +166 -0
- package/dist/lib/drawer-script.js +8 -0
- package/dist/lib/ext-loader.js +1 -0
- package/dist/lib/html.js +1 -0
- package/dist/lib/icons.js +1 -0
- package/dist/lib/image-upload.js +1 -0
- package/dist/lib/load-env.js +6 -0
- package/dist/lib/mobile-toolbar.js +313 -0
- package/dist/lib/notes-db.js +18 -0
- package/dist/lib/notes-drawer.js +210 -0
- package/dist/lib/notes-utils.js +15 -0
- package/dist/lib/pages/agents-index.js +105 -0
- package/dist/lib/pages/history-index.js +85 -0
- package/dist/lib/pages/landing.js +78 -0
- package/dist/lib/pages/login.js +191 -0
- package/dist/lib/pages/notes-index.js +65 -0
- package/dist/lib/pages/notes-page.js +158 -0
- package/dist/lib/pages/quick-commands.js +361 -0
- package/dist/lib/pages/schedule-index.js +392 -0
- package/dist/lib/pages/settings.js +206 -0
- package/dist/lib/pages/terminal.js +364 -0
- package/dist/lib/pinned-views.js +1 -0
- package/dist/lib/plugins.js +3 -0
- package/dist/lib/quick-commands.js +1 -0
- package/dist/lib/rateLimiter.js +2 -0
- package/dist/lib/schedule-delay.js +9 -0
- package/dist/lib/scheduler-drawer.js +379 -0
- package/dist/lib/scheduler.js +1 -0
- package/dist/lib/security-config.js +2 -0
- package/dist/lib/session-access.js +1 -0
- package/dist/lib/session-windows.js +1 -0
- package/dist/lib/sessions-drawer.js +634 -0
- package/dist/lib/sessions-sidebar.js +1 -0
- package/dist/lib/settings.js +2 -0
- package/dist/lib/setup-features.js +1 -0
- package/dist/lib/setup-prompts.js +3 -0
- package/dist/lib/shared-layout.js +412 -0
- package/dist/lib/state-paths.js +1 -0
- package/dist/lib/terminal-config.js +1 -0
- package/dist/lib/theme-store.js +2 -0
- package/dist/lib/theme.js +28 -0
- package/dist/lib/themes/dark-cove.js +1 -0
- package/dist/lib/themes/ghostty.js +1 -0
- package/dist/lib/themes/index.js +1 -0
- package/dist/lib/themes/types.js +0 -0
- package/dist/lib/themes/vscode.js +1 -0
- package/dist/lib/themes/warm-clay.js +1 -0
- package/dist/lib/tmux-capture.js +5 -0
- package/dist/lib/tmux-control.js +2 -0
- package/dist/lib/tmux-panes.js +2 -0
- package/dist/lib/tmux-windows.js +4 -0
- package/dist/lib/watched-panes.js +1 -0
- package/dist/lib/window-history.js +1 -0
- package/dist/lib/window-labels.js +1 -0
- package/dist/lib/windows-drawer.js +364 -0
- package/dist/lib/ws-message.js +1 -0
- package/dist/sessions.js +2 -0
- package/package.json +62 -0
- package/scripts/fix-pty-perms.mjs +16 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import{commandbarButtonHTML as y}from"./commandbar.js";import{escapeHtml as l}from"./html.js";import{icon as a,iconPath as o}from"./icons.js";const d=[{id:"vscode",name:"VS Code",dot:"#007acc"},{id:"ghostty",name:"Ghostty",dot:"#ff5f00"},{id:"warm-clay",name:"Warm Clay",dot:"#b86b52"},{id:"dark-cove",name:"Dark Cove",dot:"#7aa2f7"}];function i(e="var(--panel-accent)"){return`box-shadow: 0 0 0 2px ${e}; outline: none;`}function k(e=""){return`
|
|
2
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3
|
+
*, *::before, *::after {
|
|
4
|
+
animation-duration: 0.01ms !important;
|
|
5
|
+
animation-iteration-count: 1 !important;
|
|
6
|
+
transition-duration: 0.01ms !important;
|
|
7
|
+
scroll-behavior: auto !important;
|
|
8
|
+
}
|
|
9
|
+
${e}
|
|
10
|
+
}`}function I(e="vscode"){const r=d.find(t=>t.id===e)??d[0],s=d.map(t=>{const n=t.id===e;return`<button type="button" class="theme-option${n?" active":""}" data-theme="${t.id}" role="menuitem">
|
|
11
|
+
<span class="theme-dot" style="background:${t.dot}"></span>
|
|
12
|
+
${l(t.name)}
|
|
13
|
+
${n?a("check",'class="theme-check" aria-hidden="true"'):""}
|
|
14
|
+
</button>`}).join(`
|
|
15
|
+
`);return`<div class="theme-switcher" id="theme-switcher">
|
|
16
|
+
<button type="button" class="theme-switcher-btn" aria-label="Theme" aria-haspopup="true" aria-expanded="false">
|
|
17
|
+
<span class="theme-dot" style="background:${r.dot}"></span>
|
|
18
|
+
<span>${l(r.name)}</span>
|
|
19
|
+
</button>
|
|
20
|
+
<div class="theme-switcher-popover" role="menu">
|
|
21
|
+
${s}
|
|
22
|
+
</div>
|
|
23
|
+
</div>`}function E(){return`(function() {
|
|
24
|
+
const switcher = document.getElementById('theme-switcher');
|
|
25
|
+
if (!switcher) return;
|
|
26
|
+
const btn = switcher.querySelector('.theme-switcher-btn');
|
|
27
|
+
const popover = switcher.querySelector('.theme-switcher-popover');
|
|
28
|
+
function close() { switcher.classList.remove('open'); btn.setAttribute('aria-expanded', 'false'); }
|
|
29
|
+
function open() { switcher.classList.add('open'); btn.setAttribute('aria-expanded', 'true'); }
|
|
30
|
+
btn.addEventListener('click', (e) => {
|
|
31
|
+
e.stopPropagation();
|
|
32
|
+
switcher.classList.contains('open') ? close() : open();
|
|
33
|
+
});
|
|
34
|
+
popover.addEventListener('click', async (e) => {
|
|
35
|
+
const opt = e.target.closest('.theme-option');
|
|
36
|
+
if (!opt) return;
|
|
37
|
+
const theme = opt.dataset.theme;
|
|
38
|
+
try {
|
|
39
|
+
await fetch('/api/theme', {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
headers: { 'Content-Type': 'application/json' },
|
|
42
|
+
body: JSON.stringify({ template: theme }),
|
|
43
|
+
});
|
|
44
|
+
location.reload();
|
|
45
|
+
} catch {}
|
|
46
|
+
});
|
|
47
|
+
document.addEventListener('click', (e) => {
|
|
48
|
+
if (switcher.classList.contains('open') && !switcher.contains(e.target)) close();
|
|
49
|
+
});
|
|
50
|
+
})();`}function T(e=""){return`
|
|
51
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
52
|
+
html, body { background: var(--page-bg); color: var(--page-fg); min-height: 100%; font-family: var(--font-sans); margin: 0; padding: 0; }
|
|
53
|
+
|
|
54
|
+
/* \u2500\u2500 Fixed header \u2500\u2500 */
|
|
55
|
+
.fixed-header {
|
|
56
|
+
position: fixed; top: 0; left: 0; right: 0; z-index: 200;
|
|
57
|
+
background: color-mix(in srgb, var(--panel-bg) 92%, transparent);
|
|
58
|
+
backdrop-filter: blur(12px);
|
|
59
|
+
border-bottom: 1px solid var(--panel-border);
|
|
60
|
+
display: flex; justify-content: space-between; align-items: center;
|
|
61
|
+
padding: 0 16px; height: 56px;
|
|
62
|
+
}
|
|
63
|
+
.fixed-header .brand {
|
|
64
|
+
font-size: var(--text-base); font-weight: 600; letter-spacing: -0.01em; color: var(--page-fg);
|
|
65
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
66
|
+
}
|
|
67
|
+
.fixed-header .brand span { color: var(--panel-accent); font-weight: 500; }
|
|
68
|
+
.fixed-header .brand a { color: inherit; text-decoration: none; }
|
|
69
|
+
.header-actions { display: flex; align-items: center; gap: 4px; }
|
|
70
|
+
.header-btn, .icon-btn {
|
|
71
|
+
display: flex; align-items: center; justify-content: center; gap: 6px;
|
|
72
|
+
background: none; border: none; color: var(--panel-muted); cursor: pointer;
|
|
73
|
+
min-width: 44px; min-height: 44px; padding: 8px 12px; border-radius: 10px;
|
|
74
|
+
transition: color 0.15s, background 0.15s;
|
|
75
|
+
font-size: var(--text-sm); text-decoration: none;
|
|
76
|
+
}
|
|
77
|
+
.header-btn:hover, .icon-btn:hover { color: var(--panel-accent); background: color-mix(in srgb, var(--panel-accent) 8%, transparent); }
|
|
78
|
+
.header-btn:focus-visible, .icon-btn:focus-visible { ${i()} }
|
|
79
|
+
.header-btn svg, .icon-btn svg { width: 18px; height: 18px; fill: currentColor; flex-shrink: 0; }
|
|
80
|
+
|
|
81
|
+
/* \u2500\u2500 Theme switcher popover \u2500\u2500 */
|
|
82
|
+
.theme-switcher { position: relative; }
|
|
83
|
+
.theme-switcher-btn {
|
|
84
|
+
display: flex; align-items: center; justify-content: center; gap: 6px;
|
|
85
|
+
background: none; border: none; color: var(--panel-muted); cursor: pointer;
|
|
86
|
+
min-width: 44px; min-height: 44px; padding: 8px 12px; border-radius: 10px;
|
|
87
|
+
transition: color 0.15s, background 0.15s;
|
|
88
|
+
font-size: var(--text-sm); text-decoration: none; font-family: inherit;
|
|
89
|
+
}
|
|
90
|
+
.theme-switcher-btn:hover { color: var(--panel-accent); background: color-mix(in srgb, var(--panel-accent) 8%, transparent); }
|
|
91
|
+
.theme-switcher-btn:focus-visible { ${i()} }
|
|
92
|
+
.theme-switcher-btn svg { width: 18px; height: 18px; fill: currentColor; flex-shrink: 0; }
|
|
93
|
+
.theme-switcher-popover {
|
|
94
|
+
position: absolute; top: calc(100% + 6px); right: 0;
|
|
95
|
+
min-width: 180px; max-width: calc(100vw - 24px);
|
|
96
|
+
background: var(--panel-bg); border: 1px solid var(--panel-border);
|
|
97
|
+
border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.12); padding: 6px;
|
|
98
|
+
display: none; z-index: 300;
|
|
99
|
+
}
|
|
100
|
+
.theme-switcher.open .theme-switcher-popover { display: block; }
|
|
101
|
+
.theme-option {
|
|
102
|
+
display: flex; align-items: center; gap: 10px; width: 100%;
|
|
103
|
+
min-height: 44px; padding: 10px 12px; border-radius: 8px; border: none; background: none;
|
|
104
|
+
color: var(--page-fg); font-size: var(--text-sm); cursor: pointer; text-align: left; font-family: inherit;
|
|
105
|
+
}
|
|
106
|
+
.theme-option:hover { background: color-mix(in srgb, var(--panel-accent) 8%, transparent); color: var(--panel-accent); }
|
|
107
|
+
.theme-option:focus-visible { ${i()} }
|
|
108
|
+
.theme-option.active { color: var(--panel-accent); font-weight: 500; }
|
|
109
|
+
.theme-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
|
|
110
|
+
.theme-check { width: 16px; height: 16px; margin-left: auto; color: var(--panel-accent); }
|
|
111
|
+
|
|
112
|
+
/* \u2500\u2500 Page layout \u2500\u2500 */
|
|
113
|
+
.page-wrap { padding-top: 56px; }
|
|
114
|
+
.page-layout {
|
|
115
|
+
display: flex; gap: 24px; max-width: 1120px; margin: 0 auto; padding: 24px 16px;
|
|
116
|
+
align-items: flex-start;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* \u2500\u2500 Main content panel \u2500\u2500 */
|
|
120
|
+
.main-panel { flex: 1; min-width: 0; }
|
|
121
|
+
|
|
122
|
+
/* \u2500\u2500 Action sidebar \u2500\u2500 */
|
|
123
|
+
.action-sidebar {
|
|
124
|
+
flex: 0 0 220px; max-width: 220px; min-width: 180px;
|
|
125
|
+
margin-right: 0; position: sticky; top: 80px;
|
|
126
|
+
}
|
|
127
|
+
.sidebar-label {
|
|
128
|
+
font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase;
|
|
129
|
+
color: var(--panel-muted); margin: 0 0 12px 4px; font-weight: 500;
|
|
130
|
+
}
|
|
131
|
+
.sidebar-btn {
|
|
132
|
+
display: flex; align-items: center; gap: 12px;
|
|
133
|
+
width: 100%; min-height: 44px;
|
|
134
|
+
padding: 10px 14px; border: 1px solid transparent; border-radius: 12px;
|
|
135
|
+
background: transparent; color: var(--page-fg); cursor: pointer;
|
|
136
|
+
font-size: var(--text-sm); font-family: inherit; text-decoration: none;
|
|
137
|
+
transition: background 0.15s, color 0.15s; margin-bottom: 4px;
|
|
138
|
+
text-align: left;
|
|
139
|
+
}
|
|
140
|
+
.sidebar-btn:hover { background: color-mix(in srgb, var(--panel-accent) 8%, transparent); color: var(--panel-accent); }
|
|
141
|
+
.sidebar-btn:focus-visible { ${i()} }
|
|
142
|
+
.sidebar-btn.primary {
|
|
143
|
+
background: var(--panel-accent); border-color: var(--panel-accent); color: var(--panel-accent-on);
|
|
144
|
+
font-weight: 500; margin-bottom: 16px; justify-content: center;
|
|
145
|
+
}
|
|
146
|
+
.sidebar-btn.primary:hover { opacity: 0.9; }
|
|
147
|
+
.sidebar-btn.current {
|
|
148
|
+
background: color-mix(in srgb, var(--panel-accent) 8%, transparent); color: var(--panel-accent);
|
|
149
|
+
font-weight: 500; cursor: default; pointer-events: none;
|
|
150
|
+
}
|
|
151
|
+
.sidebar-btn svg { width: 18px; height: 18px; fill: currentColor; flex-shrink: 0; }
|
|
152
|
+
.sidebar-divider { border: none; border-top: 1px solid var(--panel-border); margin: 14px 0; }
|
|
153
|
+
|
|
154
|
+
/* \u2500\u2500 New session modal \u2500\u2500 */
|
|
155
|
+
.modal-backdrop {
|
|
156
|
+
display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.3);
|
|
157
|
+
z-index: 500; align-items: center; justify-content: center;
|
|
158
|
+
padding: 16px;
|
|
159
|
+
}
|
|
160
|
+
.modal-backdrop.open { display: flex; }
|
|
161
|
+
.modal-panel {
|
|
162
|
+
background: var(--panel-bg); border: 1px solid var(--panel-border);
|
|
163
|
+
border-radius: 20px; padding: 24px; width: 100%; max-width: 440px;
|
|
164
|
+
}
|
|
165
|
+
.modal-panel h2 { font-size: var(--text-lg); font-weight: 600; margin: 0 0 20px; color: var(--page-fg); }
|
|
166
|
+
.modal-field { margin-bottom: 18px; position: relative; }
|
|
167
|
+
.modal-field label { display: block; font-size: var(--text-sm); font-weight: 500; color: var(--page-fg); margin-bottom: 8px; }
|
|
168
|
+
.modal-field input {
|
|
169
|
+
width: 100%; padding: 13px 15px; background: var(--page-bg);
|
|
170
|
+
border: 1px solid var(--panel-border); border-radius: 14px;
|
|
171
|
+
color: var(--page-fg); font-size: var(--text-base); font-family: inherit;
|
|
172
|
+
outline: none; transition: border-color 0.15s, box-shadow 0.15s;
|
|
173
|
+
}
|
|
174
|
+
.modal-field input:focus { border-color: var(--panel-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--panel-accent) 8%, transparent); }
|
|
175
|
+
/* Custom directory autocomplete dropdown (replaces native <datalist>) */
|
|
176
|
+
.modal-dropdown {
|
|
177
|
+
display: none; position: absolute; left: 0; right: 0; top: 100%;
|
|
178
|
+
margin-top: 4px; max-height: 220px; overflow-y: auto; z-index: 10;
|
|
179
|
+
background: var(--panel-bg); border: 1px solid var(--panel-border);
|
|
180
|
+
border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.12);
|
|
181
|
+
}
|
|
182
|
+
.modal-dropdown.open { display: block; }
|
|
183
|
+
.modal-dropdown-item {
|
|
184
|
+
display: flex; align-items: center;
|
|
185
|
+
min-height: 44px; padding: 10px 14px; font-size: var(--text-sm); color: var(--page-fg); cursor: pointer;
|
|
186
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
187
|
+
}
|
|
188
|
+
.modal-dropdown-item:hover, .modal-dropdown-item.active, .modal-dropdown-item:focus-visible {
|
|
189
|
+
background: color-mix(in srgb, var(--panel-accent) 8%, transparent); color: var(--panel-accent);
|
|
190
|
+
}
|
|
191
|
+
.modal-dropdown-item:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--panel-accent); }
|
|
192
|
+
.modal-error { font-size: var(--text-sm); color: #b91c1c; margin-bottom: 12px; display: none; }
|
|
193
|
+
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 8px; }
|
|
194
|
+
.modal-btn {
|
|
195
|
+
min-height: 44px; padding: 10px 20px; border-radius: 12px; font-size: var(--text-sm); font-family: inherit;
|
|
196
|
+
cursor: pointer; border: 1px solid var(--panel-border); background: var(--panel-bg);
|
|
197
|
+
color: var(--page-fg); transition: opacity 0.15s;
|
|
198
|
+
}
|
|
199
|
+
.modal-btn:hover { opacity: 0.85; }
|
|
200
|
+
.modal-btn:focus-visible { ${i()} }
|
|
201
|
+
.modal-btn.confirm {
|
|
202
|
+
background: var(--panel-accent); border-color: var(--panel-accent);
|
|
203
|
+
color: var(--panel-accent-on); font-weight: 500;
|
|
204
|
+
}
|
|
205
|
+
.modal-btn.confirm:hover { opacity: 0.9; }
|
|
206
|
+
|
|
207
|
+
/* \u2500\u2500 Mobile \u2500\u2500 */
|
|
208
|
+
@media (max-width: 560px) {
|
|
209
|
+
.page-layout { flex-direction: column; padding: 16px; gap: 0; }
|
|
210
|
+
.action-sidebar { max-width: 100%; min-width: 0; width: 100%; margin-right: 0; position: static; order: -1; }
|
|
211
|
+
.sidebar-label { display: none; }
|
|
212
|
+
.sidebar-btn { justify-content: center; }
|
|
213
|
+
.fixed-header { padding: 0 12px; }
|
|
214
|
+
.header-btn span,
|
|
215
|
+
.theme-switcher-btn span { display: none; }
|
|
216
|
+
.header-btn, .theme-switcher-btn { padding: 8px; }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
${k()}
|
|
220
|
+
${e}`}function z(e){const{commandbarEnabled:r,title:s="TMUX Sessions",themeTemplate:t="vscode"}=e;return`<script>
|
|
221
|
+
(function() {
|
|
222
|
+
const token = localStorage.getItem('tmux-web-token');
|
|
223
|
+
if (token) {
|
|
224
|
+
const orig = window.fetch;
|
|
225
|
+
window.fetch = function(input, init) {
|
|
226
|
+
init = init || {};
|
|
227
|
+
const headers = init.headers || {};
|
|
228
|
+
if (typeof headers === 'object' && !Array.isArray(headers) && !headers['Authorization'] && !headers['authorization']) {
|
|
229
|
+
init.headers = { ...headers, Authorization: 'Bearer ' + token };
|
|
230
|
+
}
|
|
231
|
+
return orig(input, init);
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
})();
|
|
235
|
+
</script>
|
|
236
|
+
<header class="fixed-header">
|
|
237
|
+
<div class="brand"><a href="/" aria-label="Go to home">tmux<span>-weblink</span></a></div>
|
|
238
|
+
<div class="header-actions">
|
|
239
|
+
${r?y("Search"):""}
|
|
240
|
+
<button class="header-btn" id="notes-toggle" title="Global notes" aria-label="Global notes">
|
|
241
|
+
${a("notes")}
|
|
242
|
+
<span>Notes</span>
|
|
243
|
+
</button>
|
|
244
|
+
${I(t)}
|
|
245
|
+
<a class="header-btn" href="/settings" title="Settings">
|
|
246
|
+
${a("settings")}
|
|
247
|
+
<span>Settings</span>
|
|
248
|
+
</a>
|
|
249
|
+
</div>
|
|
250
|
+
</header>
|
|
251
|
+
<script>${E()}</script>`}function D(e){const{activePage:r,agentsEnabled:s,refreshHref:t}=e;function n(c,x,g,v,w=""){return`<a href="${x}" class="${c!==null&&c===r?"sidebar-btn current":"sidebar-btn"}"${w}>
|
|
252
|
+
<svg viewBox="0 0 24 24" fill="currentColor">${g}</svg>
|
|
253
|
+
${v}
|
|
254
|
+
</a>`}const p=o("sessions"),m=o("notes"),u=o("schedule"),h=o("agents"),b=o("history"),f=o("quick-commands"),L=o("refresh");return`<aside class="action-sidebar">
|
|
255
|
+
<p class="sidebar-label">Actions</p>
|
|
256
|
+
<button class="sidebar-btn primary" id="new-session-btn">
|
|
257
|
+
${a("add")}
|
|
258
|
+
New Session
|
|
259
|
+
</button>
|
|
260
|
+
<hr class="sidebar-divider">
|
|
261
|
+
${n("home","/",p,"Sessions")}
|
|
262
|
+
${n("notes","/notes",m,"All Notes")}
|
|
263
|
+
${n("schedule","/schedule",u,"Scheduled")}
|
|
264
|
+
${n("history","/history",b,"History")}
|
|
265
|
+
${n("quickCommands","/quick-commands",f,"Quick Commands")}
|
|
266
|
+
${s?n("agents","/agents",h,"All Agents"):""}
|
|
267
|
+
<hr class="sidebar-divider">
|
|
268
|
+
<a href="${t}" class="sidebar-btn">
|
|
269
|
+
${a("refresh")}
|
|
270
|
+
Refresh
|
|
271
|
+
</a>
|
|
272
|
+
</aside>`}function M(){return`<div class="modal-backdrop" id="new-session-modal" role="dialog" aria-modal="true" aria-label="Create new tmux session">
|
|
273
|
+
<div class="modal-panel">
|
|
274
|
+
<h2>New Session</h2>
|
|
275
|
+
<div class="modal-field">
|
|
276
|
+
<label for="ns-name">Session name</label>
|
|
277
|
+
<input type="text" id="ns-name" placeholder="e.g. myproject" autocomplete="off" spellcheck="false" />
|
|
278
|
+
</div>
|
|
279
|
+
<div class="modal-field">
|
|
280
|
+
<label for="ns-dir">Start directory</label>
|
|
281
|
+
<input type="text" id="ns-dir" placeholder="~" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="ns-dir-list" />
|
|
282
|
+
<div class="modal-dropdown" id="ns-dir-list" role="listbox"></div>
|
|
283
|
+
</div>
|
|
284
|
+
<p class="modal-error" id="ns-error"></p>
|
|
285
|
+
<div class="modal-actions">
|
|
286
|
+
<button class="modal-btn" id="ns-cancel">Cancel</button>
|
|
287
|
+
<button class="modal-btn confirm" id="ns-submit">Create</button>
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
</div>`}function j(){return`(function() {
|
|
291
|
+
const modal = document.getElementById('new-session-modal');
|
|
292
|
+
const openBtn = document.getElementById('new-session-btn');
|
|
293
|
+
const cancelBtn = document.getElementById('ns-cancel');
|
|
294
|
+
const submitBtn = document.getElementById('ns-submit');
|
|
295
|
+
const nameInput = document.getElementById('ns-name');
|
|
296
|
+
const dirInput = document.getElementById('ns-dir');
|
|
297
|
+
const dirList = document.getElementById('ns-dir-list');
|
|
298
|
+
const errorEl = document.getElementById('ns-error');
|
|
299
|
+
|
|
300
|
+
function openModal() {
|
|
301
|
+
modal.classList.add('open');
|
|
302
|
+
nameInput.value = '';
|
|
303
|
+
dirInput.value = '';
|
|
304
|
+
errorEl.style.display = 'none';
|
|
305
|
+
errorEl.textContent = '';
|
|
306
|
+
closeDropdown();
|
|
307
|
+
setTimeout(() => nameInput.focus(), 50);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function closeModal() { modal.classList.remove('open'); }
|
|
311
|
+
|
|
312
|
+
openBtn.addEventListener('click', openModal);
|
|
313
|
+
cancelBtn.addEventListener('click', closeModal);
|
|
314
|
+
modal.addEventListener('click', (e) => { if (e.target === modal) closeModal(); });
|
|
315
|
+
document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && modal.classList.contains('open')) closeModal(); });
|
|
316
|
+
|
|
317
|
+
let debounceTimer = null;
|
|
318
|
+
let activeIdx = -1;
|
|
319
|
+
|
|
320
|
+
function closeDropdown() {
|
|
321
|
+
dirList.classList.remove('open');
|
|
322
|
+
dirList.innerHTML = '';
|
|
323
|
+
activeIdx = -1;
|
|
324
|
+
dirInput.setAttribute('aria-expanded', 'false');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function setActive(idx) {
|
|
328
|
+
const items = dirList.querySelectorAll('.modal-dropdown-item');
|
|
329
|
+
if (!items.length) return;
|
|
330
|
+
activeIdx = (idx + items.length) % items.length;
|
|
331
|
+
items.forEach((it, i) => it.classList.toggle('active', i === activeIdx));
|
|
332
|
+
items[activeIdx].scrollIntoView({ block: 'nearest' });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function renderDropdown(dirs) {
|
|
336
|
+
dirList.innerHTML = '';
|
|
337
|
+
activeIdx = -1;
|
|
338
|
+
if (!dirs.length) { closeDropdown(); return; }
|
|
339
|
+
for (const d of dirs) {
|
|
340
|
+
const item = document.createElement('div');
|
|
341
|
+
item.className = 'modal-dropdown-item';
|
|
342
|
+
item.setAttribute('role', 'option');
|
|
343
|
+
item.textContent = d;
|
|
344
|
+
// mousedown (not click) so the input doesn't blur before we read the value
|
|
345
|
+
item.addEventListener('mousedown', (e) => {
|
|
346
|
+
e.preventDefault();
|
|
347
|
+
dirInput.value = d;
|
|
348
|
+
closeDropdown();
|
|
349
|
+
dirInput.focus();
|
|
350
|
+
});
|
|
351
|
+
dirList.appendChild(item);
|
|
352
|
+
}
|
|
353
|
+
dirList.classList.add('open');
|
|
354
|
+
dirInput.setAttribute('aria-expanded', 'true');
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
dirInput.addEventListener('input', () => {
|
|
358
|
+
clearTimeout(debounceTimer);
|
|
359
|
+
const val = dirInput.value.trim();
|
|
360
|
+
if (!val) { closeDropdown(); return; }
|
|
361
|
+
debounceTimer = setTimeout(async () => {
|
|
362
|
+
try {
|
|
363
|
+
const res = await fetch('/api/fs/list?path=' + encodeURIComponent(val));
|
|
364
|
+
const data = await res.json();
|
|
365
|
+
renderDropdown(data.dirs || []);
|
|
366
|
+
} catch { closeDropdown(); }
|
|
367
|
+
}, 200);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
dirInput.addEventListener('blur', () => { setTimeout(closeDropdown, 120); });
|
|
371
|
+
|
|
372
|
+
async function submit() {
|
|
373
|
+
const name = nameInput.value.trim();
|
|
374
|
+
const dir = dirInput.value.trim();
|
|
375
|
+
if (!name) { showError('Session name is required.'); nameInput.focus(); return; }
|
|
376
|
+
submitBtn.disabled = true;
|
|
377
|
+
submitBtn.textContent = 'Creating\u2026';
|
|
378
|
+
errorEl.style.display = 'none';
|
|
379
|
+
try {
|
|
380
|
+
const res = await fetch('/api/sessions/new', {
|
|
381
|
+
method: 'POST',
|
|
382
|
+
headers: { 'Content-Type': 'application/json' },
|
|
383
|
+
body: JSON.stringify({ name, dir: dir || undefined }),
|
|
384
|
+
});
|
|
385
|
+
const data = await res.json();
|
|
386
|
+
if (!res.ok) { showError(data.error || 'Failed to create session.'); return; }
|
|
387
|
+
window.location.href = '/s/' + encodeURIComponent(name);
|
|
388
|
+
} catch { showError('Network error. Please try again.'); }
|
|
389
|
+
finally { submitBtn.disabled = false; submitBtn.textContent = 'Create'; }
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function showError(msg) { errorEl.textContent = msg; errorEl.style.display = 'block'; }
|
|
393
|
+
|
|
394
|
+
submitBtn.addEventListener('click', submit);
|
|
395
|
+
nameInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') dirInput.focus(); });
|
|
396
|
+
dirInput.addEventListener('keydown', (e) => {
|
|
397
|
+
const open = dirList.classList.contains('open');
|
|
398
|
+
const items = dirList.querySelectorAll('.modal-dropdown-item');
|
|
399
|
+
if (open && items.length) {
|
|
400
|
+
if (e.key === 'ArrowDown') { e.preventDefault(); setActive(activeIdx + 1); return; }
|
|
401
|
+
if (e.key === 'ArrowUp') { e.preventDefault(); setActive(activeIdx - 1); return; }
|
|
402
|
+
if (e.key === 'Escape') { e.preventDefault(); e.stopPropagation(); closeDropdown(); return; }
|
|
403
|
+
if (e.key === 'Enter' && activeIdx >= 0) {
|
|
404
|
+
e.preventDefault();
|
|
405
|
+
dirInput.value = items[activeIdx].textContent;
|
|
406
|
+
closeDropdown();
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (e.key === 'Enter') submit();
|
|
411
|
+
});
|
|
412
|
+
})();`}export{M as newSessionModalHTML,j as newSessionModalScript,z as sharedHeader,T as sharedLayoutCSS,D as sharedSidebar,I as themeSwitcherButtonHTML,E as themeSwitcherScript};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"node:path";import{homedir as n}from"node:os";function s(t){if(!t)return!1;const o=t.trim().toLowerCase();return o==="1"||o==="true"||o==="yes"}function i(){const t=process.env.TMUX_WEB_MODE?.trim().toLowerCase();return t==="development"||t==="dev"||s(process.env.TMUX_WEB_DEV)?!0:process.env.NODE_ENV==="development"||process.env.npm_lifecycle_event==="dev"}function r(){return i()?e.join(n(),".dev",".tmux-web"):e.join(n(),".tmux-web")}function u(){return i()?e.join(n(),".dev",".config"):e.join(n(),".config")}function f(){return e.join(u(),"tmux-web","settings.json")}function m(){return e.join(u(),"tmux-web","theme.json")}function d(){return e.join(r(),"node_modules")}function x(t){return e.join(r(),"extensions",t)}function a(){return e.join(r(),"uploads")}export{u as getConfigRoot,r as getDataRoot,x as getExtensionDataDir,d as getPluginDir,f as getSettingsPath,m as getThemePath,a as getUploadsRoot};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function n(s,r){if(!s)return r;const e=parseInt(s,10);return Number.isFinite(e)&&e>0?e:r}function i(){return{initialLines:n(process.env.TMUX_WEB_INITIAL_LINES,1e3),historyChunk:n(process.env.TMUX_WEB_HISTORY_CHUNK,500),syncIdleMs:n(process.env.TMUX_WEB_SYNC_IDLE_MS,200),syncMaxMs:n(process.env.TMUX_WEB_SYNC_MAX_MS,3e3)}}export{i as readTerminalBufferConfig};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{readFile as o,writeFile as a,mkdir as m}from"node:fs/promises";import l from"node:path";import{getThemePath as c}from"./state-paths.js";import{isThemeTemplateId as s,resolveTheme as i}from"./themes/index.js";const r=c();function f(t){if(!t||typeof t!="object")return!1;const e=t;return s(e.template)&&typeof e.shell=="object"&&e.shell!==null&&typeof e.shell.pageBg=="string"&&typeof e.terminal=="object"&&e.terminal!==null&&typeof e.terminal.background=="string"}async function n(t){await m(l.dirname(r),{recursive:!0}),await a(r,JSON.stringify(t,null,2)+`
|
|
2
|
+
`)}async function y(){try{const e=JSON.parse(await o(r,"utf-8"));if(f(e))return e}catch{}const t=i("vscode");return await n(t),t}async function w(t){const e=i(t);return await n(e),e}export{y as readActiveTheme,w as setActiveThemeTemplate,n as writeActiveTheme};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import{vscodeTheme as n}from"./themes/vscode.js";function a(e=n.shell){return`
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');
|
|
3
|
+
:root {
|
|
4
|
+
--page-bg: ${e.pageBg};
|
|
5
|
+
--page-fg: ${e.pageFg};
|
|
6
|
+
--panel-bg: ${e.panelBg};
|
|
7
|
+
--panel-border: ${e.panelBorder};
|
|
8
|
+
--panel-muted: ${e.panelMuted};
|
|
9
|
+
--panel-accent: ${e.panelAccent};
|
|
10
|
+
--panel-accent-on: ${e.panelAccentOn};
|
|
11
|
+
--panel-success: ${e.panelSuccess};
|
|
12
|
+
--terminal-bg: ${e.terminalBg};
|
|
13
|
+
--header-gradient: ${e.headerGradient??"none"};
|
|
14
|
+
|
|
15
|
+
/* Typography */
|
|
16
|
+
--font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
17
|
+
--font-mono: 'JetBrains Mono', 'SF Mono', 'Menlo', 'Consolas', monospace;
|
|
18
|
+
|
|
19
|
+
--text-xs: 0.75rem; /* 12px */
|
|
20
|
+
--text-sm: 0.875rem; /* 14px */
|
|
21
|
+
--text-base: 1rem; /* 16px */
|
|
22
|
+
--text-lg: 1.25rem; /* 20px */
|
|
23
|
+
--text-xl: 1.5rem; /* 24px */
|
|
24
|
+
--text-2xl: 1.75rem; /* 28px */
|
|
25
|
+
}
|
|
26
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
27
|
+
html { font-family: var(--font-sans); font-size: 16px; line-height: 1.5; }
|
|
28
|
+
body { font-family: var(--font-sans); }`}export{a as cssVarsStyle};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={template:"dark-cove",shell:{pageBg:"#1a1d23",pageFg:"#e8eaed",panelBg:"#22262d",panelBorder:"#2f353f",panelMuted:"#9097a3",panelAccent:"#7aa2f7",panelAccentOn:"#15181d",panelSuccess:"#73daca",terminalBg:"#15181d",headerGradient:"linear-gradient(180deg, rgba(34, 38, 45, 0.98), rgba(26, 29, 35, 0.98))"},terminal:{foreground:"#c0caf5",background:"#15181d",cursor:"#c0caf5",cursorAccent:"#15181d",selectionBackground:"rgba(122, 162, 247, 0.35)",selectionForeground:"#c0caf5",black:"#15161e",red:"#f7768e",green:"#9ece6a",yellow:"#e0af68",blue:"#7aa2f7",magenta:"#bb9af7",cyan:"#7dcfff",white:"#a9b1d6",brightBlack:"#414868",brightRed:"#f7768e",brightGreen:"#9ece6a",brightYellow:"#e0af68",brightBlue:"#7aa2f7",brightMagenta:"#bb9af7",brightCyan:"#7dcfff",brightWhite:"#c0caf5"}};export{e as darkCoveTheme};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={template:"ghostty",shell:{pageBg:"#1a1b26",pageFg:"#a9b1d6",panelBg:"#1f2335",panelBorder:"#292e42",panelMuted:"#565f89",panelAccent:"#7aa2f7",panelAccentOn:"#1a1b26",panelSuccess:"#9ece6a",terminalBg:"#1a1b26",headerGradient:"linear-gradient(180deg, rgba(31, 35, 53, 0.98), rgba(26, 27, 38, 0.98))"},terminal:{foreground:"#c0caf5",background:"#1a1b26",cursor:"#c0caf5",cursorAccent:"#1a1b26",selectionBackground:"#33467c",selectionForeground:"#c0caf5",black:"#15161e",red:"#f7768e",green:"#9ece6a",yellow:"#e0af68",blue:"#7aa2f7",magenta:"#bb9af7",cyan:"#7dcfff",white:"#a9b1d6",brightBlack:"#414868",brightRed:"#f7768e",brightGreen:"#9ece6a",brightYellow:"#e0af68",brightBlue:"#7aa2f7",brightMagenta:"#bb9af7",brightCyan:"#7dcfff",brightWhite:"#c0caf5"}};export{e as ghosttyTheme};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{darkCoveTheme as t}from"./dark-cove.js";import{ghosttyTheme as m}from"./ghostty.js";import{vscodeTheme as h}from"./vscode.js";import{warmClayTheme as T}from"./warm-clay.js";import{darkCoveTheme as w}from"./dark-cove.js";import{ghosttyTheme as k}from"./ghostty.js";import{vscodeTheme as v}from"./vscode.js";import{warmClayTheme as l}from"./warm-clay.js";const o={vscode:h,ghostty:m,"warm-clay":T,"dark-cove":t},f=Object.keys(o);function a(){return o}function d(e){const r=o[e];if(!r)throw new Error(`unknown theme template: ${e}`);return structuredClone(r)}function i(e){return e==="vscode"||e==="ghostty"||e==="warm-clay"||e==="dark-cove"}export{f as THEME_TEMPLATE_IDS,w as darkCoveTheme,a as getThemeTemplates,k as ghosttyTheme,i as isThemeTemplateId,d as resolveTheme,v as vscodeTheme,l as warmClayTheme};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={template:"vscode",shell:{pageBg:"#111111",pageFg:"#d0d0d0",panelBg:"#11161d",panelBorder:"#243241",panelMuted:"#8a97a6",panelAccent:"#7dd3fc",panelAccentOn:"#0d1117",panelSuccess:"#73c991",terminalBg:"#1e1e1e",headerGradient:"linear-gradient(180deg, rgba(19, 28, 36, 0.98), rgba(13, 18, 24, 0.98))"},terminal:{foreground:"#cccccc",background:"#1e1e1e",cursor:"#aeafad",cursorAccent:"#1e1e1e",selectionBackground:"#264f78",selectionForeground:"#ffffff",black:"#000000",red:"#cd3131",green:"#0dbc79",yellow:"#e5e510",blue:"#2472c8",magenta:"#bc3fbc",cyan:"#11a8cd",white:"#e5e5e5",brightBlack:"#666666",brightRed:"#f14c4c",brightGreen:"#23d18b",brightYellow:"#f5f543",brightBlue:"#3b8eea",brightMagenta:"#d670d6",brightCyan:"#29b8db",brightWhite:"#ffffff"}};export{e as vscodeTheme};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={template:"warm-clay",shell:{pageBg:"#faf8f5",pageFg:"#2d2926",panelBg:"#ffffff",panelBorder:"#ebe5df",panelMuted:"#7b726b",panelAccent:"#b86b52",panelAccentOn:"#ffffff",panelSuccess:"#6b9e7c",terminalBg:"#2b2623",headerGradient:"linear-gradient(180deg, rgba(255,255,255,0.98), rgba(250,248,245,0.98))"},terminal:{foreground:"#e8e2dc",background:"#2b2623",cursor:"#e8e2dc",cursorAccent:"#2b2623",selectionBackground:"rgba(184, 107, 82, 0.35)",selectionForeground:"#e8e2dc",black:"#2b2623",red:"#d88a8a",green:"#8fc49f",yellow:"#e0c28a",blue:"#8ab4d8",magenta:"#c9a5c9",cyan:"#8ad0d0",white:"#d8d0c8",brightBlack:"#4a433e",brightRed:"#e8a0a0",brightGreen:"#a5d6b2",brightYellow:"#efd69a",brightBlue:"#a5c8e8",brightMagenta:"#d9b8d9",brightCyan:"#a0dede",brightWhite:"#f5f0eb"}};export{e as warmClayTheme};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{execFileSync as f}from"node:child_process";const l=3e3;function g(n){return n.replace(/\r?\n/g,`\r
|
|
2
|
+
`)}function o(n){return f("tmux",n,{encoding:"utf-8",timeout:l}).trimEnd()}function S(n){return o(["display-message","-p","-t",n,"#{session_name}:#{window_index}.#{pane_index}"])}function m(n){const t=o(["display-message","-p","-t",n,"#{history_size}"]),e=parseInt(t,10);return Number.isFinite(e)?e:0}function _(n){return o(["display-message","-p","-t",n,"#{alternate_on}"])==="1"}function c(n,t,e){const i=["capture-pane","-t",n,"-p","-S",String(t)];return e!==void 0&&i.push("-E",String(e)),o(i)}function h(n,t){return c(n,-t)}function y(n,t,e){const i=m(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
|
+
`).length,s=Math.min(e,u,i-t);return s<u&&s>0&&(r=r.split(`
|
|
4
|
+
`).slice(-s).join(`
|
|
5
|
+
`)),{data:r,lines:s}}export{y as capturePaneHistoryChunk,c as capturePaneLines,h as capturePaneTail,m as getPaneHistorySize,S as getSessionPaneTarget,_ as isAlternateScreen,g as toCrlf};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import*as w from"node-pty";import{captureAndStoreWindows as p}from"./session-windows.js";import{recordWindowVisit as T}from"./window-history.js";const h=["%session-window-changed","%window-add","%window-close","%unlinked-window-close","%window-renamed","%session-renamed"];function x(e){return h.some(r=>e.startsWith(r))}const y=75,C=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:process.env});function v(e){const r=p(e);if(!r.length)return null;const o=r.find(i=>i.active);return o&&T(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 M(e,r,o={}){const i=o.spawn??C,a=o.requery??v,f=o.debounceMs??y;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),x(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 R(){for(const e of c.values()){e.debounceTimer&&clearTimeout(e.debounceTimer);try{e.pty.kill()}catch{}}c.clear()}function S(){return c.size}export{S as _controlClientCount,M as acquireControlClient,R as killAllControlClients,x as shouldRequery};
|
|
@@ -0,0 +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 m(t,e){const[n,a,c,r,d,p,s]=e.split(" ");if(!n)return null;const i=parseInt(c,10),o=parseInt(a,10);return{paneId:n,paneIndex:Number.isFinite(o)?o:0,windowIndex:Number.isFinite(i)?i:0,pid:parseInt(r,10)||0,command:d??"",active:p==="1",windowActive:s==="1",target:`${t}:${i}.${o}`}}function x(t){try{return u("tmux",["list-panes","-s","-t",t,"-F",l],{encoding:"utf-8",timeout:w}).trim().split(`
|
|
2
|
+
`).filter(Boolean).map(n=>m(t,n)).filter(n=>n!==null)}catch{return[]}}function _(t){return x(t).find(n=>n.active&&n.windowActive)??null}export{_ as getActivePaneInfo,x as listSessionPanes};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{execFileSync as w}from"node:child_process";class r extends Error{status;constructor(n,e){super(n),this.status=e,this.name="TmuxWindowsError"}}function u(t){try{return w("tmux",["list-windows","-t",t,"-F","#{window_index} #{window_name} #{window_active}"],{encoding:"utf-8",timeout:3e3}).trim().split(`
|
|
2
|
+
`).filter(Boolean).map(e=>{const[o,i,s]=e.split(" ");return{index:parseInt(o,10),name:i,active:s==="1"}})}catch{return[]}}function d(t){try{return w("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(e=>{const[o,i,s,a]=e.split(" ");return{index:parseInt(o,10),name:i,active:s==="1",path:a??""}})}catch{return[]}}function f(t){if(!t)return!1;try{const n=w("git",["-C",t,"rev-parse","--git-dir","--git-common-dir"],{encoding:"utf-8",timeout:3e3,stdio:["ignore","pipe","ignore"]}),[e,o]=n.trim().split(`
|
|
4
|
+
`);return!e||!o?!1:e!==o}catch{return!1}}function c(t){try{return w("tmux",["has-session","-t",t],{timeout:3e3}),!0}catch{return!1}}function p(t){if(!c(t))throw new r("session not found",404);try{w("tmux",["new-window","-t",t],{timeout:3e3})}catch(n){const e=n instanceof Error?n.message:"new-window failed";throw new r(e,500)}}function h(t,n){const e=["new-session","-d","-s",t];n&&e.push("-c",n);try{w("tmux",e,{timeout:5e3})}catch(o){const i=o instanceof Error?o.message:"new-session failed";throw new r(i,500)}}function x(t,n){if(!c(t))throw new r("session not found",404);if(!u(t).some(o=>o.index===n))throw new r("window not found",404);try{w("tmux",["select-window","-t",`${t}:${n}`],{timeout:3e3})}catch(o){const i=o instanceof Error?o.message:"select-window failed";throw new r(i,500)}}function l(t,n,e){if(!c(t))throw new r("session not found",404);if(!u(t).some(s=>s.index===n))throw new r("window not found",404);const i=e.trim();if(!i)throw new r("name is required",500);try{w("tmux",["rename-window","-t",`${t}:${n}`,i],{timeout:3e3})}catch(s){const a=s instanceof Error?s.message:"rename-window failed";throw new r(a,500)}}export{r as TmuxWindowsError,d as captureSessionWindowsWithPath,f as isGitWorktree,u as listSessionWindows,p as newSessionWindow,h as newTmuxSession,l as renameSessionWindow,x as selectSessionWindow};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{db as a}from"./db.js";const c=50;async function o(t){const e={...t,watchedAt:Date.now()},n=a.data.watchedPanes.filter(d=>d.paneId!==t.paneId);a.data.watchedPanes=[e,...n].slice(0,c),await a.write()}function r(){return a.data.watchedPanes}async function h(t){const e=a.data.watchedPanes.length;a.data.watchedPanes=a.data.watchedPanes.filter(n=>t.has(n.paneId)),a.data.watchedPanes.length!==e&&await a.write()}export{c as MAX_WATCHED_PANES,r as getWatchedPanes,h as pruneWatchedPanes,o as recordWatchedPane};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{db as t}from"./db.js";const e=200;async function c(i,r,o){const s=t.data.windowHistory??=[],a={sessionName:i,windowIndex:r,windowName:o,visitedAt:Date.now()},w=s.filter(n=>!(n.sessionName===i&&n.windowName===o));t.data.windowHistory=[a,...w].slice(0,e),await t.write()}function y(){return t.data.windowHistory??[]}async function H(){(t.data.windowHistory??[]).length&&(t.data.windowHistory=[],await t.write())}export{e as MAX_WINDOW_HISTORY,H as clearWindowHistory,y as listWindowHistory,c as recordWindowVisit};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{db as a}from"./db.js";function r(t){return(a.data.windowLabels??[]).filter(n=>n.sessionName===t)}async function b(t,n,w){const e=a.data.windowLabels??=[],d=w.trim(),i=e.findIndex(o=>o.sessionName===t&&o.windowIndex===n);if(!d)return i>=0&&(e.splice(i,1),await a.write()),r(t);const l=Date.now();return i>=0?(e[i].label=d,e[i].updatedAt=l):e.push({sessionName:t,windowIndex:n,label:d,updatedAt:l}),await a.write(),r(t)}export{r as listWindowLabels,b as setWindowLabel};
|