@ebowwa/terminal 0.2.1 → 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/dist/index.js +6855 -28130
- package/dist/mcp/index.js +7244 -27317
- package/package.json +1 -1
- package/src/api.js +0 -861
- package/src/client.js +0 -92
- package/src/config.js +0 -490
- package/src/error.js +0 -32
- package/src/exec.js +0 -183
- package/src/files.js +0 -521
- package/src/fingerprint.js +0 -336
- package/src/index.js +0 -127
- package/src/manager.js +0 -358
- package/src/mcp/index.js +0 -555
- package/src/mcp/stdio.js +0 -840
- package/src/network-error-detector.js +0 -101
- package/src/pool.js +0 -840
- package/src/pty.js +0 -344
- package/src/resources.js +0 -64
- package/src/scp.js +0 -166
- package/src/sessions.js +0 -895
- package/src/tmux-exec.js +0 -169
- package/src/tmux-local.js +0 -937
- package/src/tmux-manager.js +0 -1026
- package/src/tmux.js +0 -826
- package/src/types.js +0 -5
package/src/tmux-local.js
DELETED
|
@@ -1,937 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* tmux-based Local Terminal Sessions
|
|
4
|
-
* Provides persistent terminal sessions using local tmux for SSH connections
|
|
5
|
-
* SSH connections stay active within tmux sessions on the local machine
|
|
6
|
-
*/
|
|
7
|
-
var __assign = (this && this.__assign) || function () {
|
|
8
|
-
__assign = Object.assign || function(t) {
|
|
9
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
10
|
-
s = arguments[i];
|
|
11
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
12
|
-
t[p] = s[p];
|
|
13
|
-
}
|
|
14
|
-
return t;
|
|
15
|
-
};
|
|
16
|
-
return __assign.apply(this, arguments);
|
|
17
|
-
};
|
|
18
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
19
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
20
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
21
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
22
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
23
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
24
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
28
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
29
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
30
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
31
|
-
function step(op) {
|
|
32
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
33
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
34
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
35
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
36
|
-
switch (op[0]) {
|
|
37
|
-
case 0: case 1: t = op; break;
|
|
38
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
39
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
40
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
41
|
-
default:
|
|
42
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
43
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
44
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
45
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
46
|
-
if (t[2]) _.ops.pop();
|
|
47
|
-
_.trys.pop(); continue;
|
|
48
|
-
}
|
|
49
|
-
op = body.call(thisArg, _);
|
|
50
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
51
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
-
exports.isLocalTmuxInstalled = isLocalTmuxInstalled;
|
|
56
|
-
exports.generateLocalSessionName = generateLocalSessionName;
|
|
57
|
-
exports.listLocalSessions = listLocalSessions;
|
|
58
|
-
exports.hasLocalSession = hasLocalSession;
|
|
59
|
-
exports.createLocalTmuxSSHSession = createLocalTmuxSSHSession;
|
|
60
|
-
exports.sendCommandToLocalSession = sendCommandToLocalSession;
|
|
61
|
-
exports.captureLocalPane = captureLocalPane;
|
|
62
|
-
exports.getLocalPaneHistory = getLocalPaneHistory;
|
|
63
|
-
exports.killLocalSession = killLocalSession;
|
|
64
|
-
exports.getLocalSessionInfo = getLocalSessionInfo;
|
|
65
|
-
exports.listLocalSessionWindows = listLocalSessionWindows;
|
|
66
|
-
exports.listLocalWindowPanes = listLocalWindowPanes;
|
|
67
|
-
exports.splitLocalPane = splitLocalPane;
|
|
68
|
-
exports.cleanupOldLocalSessions = cleanupOldLocalSessions;
|
|
69
|
-
exports.getLocalTmuxResourceUsage = getLocalTmuxResourceUsage;
|
|
70
|
-
exports.waitForTextInPane = waitForTextInPane;
|
|
71
|
-
exports.switchLocalWindow = switchLocalWindow;
|
|
72
|
-
exports.switchLocalPane = switchLocalPane;
|
|
73
|
-
exports.renameLocalWindow = renameLocalWindow;
|
|
74
|
-
exports.killLocalPane = killLocalPane;
|
|
75
|
-
exports.getDetailedLocalSessionInfo = getDetailedLocalSessionInfo;
|
|
76
|
-
var node_child_process_1 = require("node:child_process");
|
|
77
|
-
var node_util_1 = require("node:util");
|
|
78
|
-
var execAsync = (0, node_util_1.promisify)(node_child_process_1.exec);
|
|
79
|
-
var DEFAULT_CONFIG = {
|
|
80
|
-
sessionPrefix: "mcp-ssh",
|
|
81
|
-
defaultShell: "/bin/bash",
|
|
82
|
-
term: "xterm-256color",
|
|
83
|
-
timeout: 30,
|
|
84
|
-
historyLimit: 10000, // 10k lines ~ 1-2MB per session
|
|
85
|
-
sessionAgeLimit: 30 * 24 * 60 * 60 * 1000, // 30 days
|
|
86
|
-
};
|
|
87
|
-
/**
|
|
88
|
-
* Check if tmux is installed locally
|
|
89
|
-
*/
|
|
90
|
-
function isLocalTmuxInstalled() {
|
|
91
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
92
|
-
var stdout, _a;
|
|
93
|
-
return __generator(this, function (_b) {
|
|
94
|
-
switch (_b.label) {
|
|
95
|
-
case 0:
|
|
96
|
-
_b.trys.push([0, 2, , 3]);
|
|
97
|
-
return [4 /*yield*/, execAsync("type tmux", { timeout: 5000 })];
|
|
98
|
-
case 1:
|
|
99
|
-
stdout = (_b.sent()).stdout;
|
|
100
|
-
return [2 /*return*/, stdout.trim() !== "tmux not found" && stdout.trim() !== ""];
|
|
101
|
-
case 2:
|
|
102
|
-
_a = _b.sent();
|
|
103
|
-
return [2 /*return*/, false];
|
|
104
|
-
case 3: return [2 /*return*/];
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Generate a local tmux session name for a host
|
|
111
|
-
* @param host - Remote host IP or hostname
|
|
112
|
-
* @param user - SSH user (default: "root")
|
|
113
|
-
* @returns Session name (e.g., "mcp-ssh-192-168-1-1")
|
|
114
|
-
*/
|
|
115
|
-
function generateLocalSessionName(host, user) {
|
|
116
|
-
if (user === void 0) { user = "root"; }
|
|
117
|
-
var sanitizedHost = host.replace(/[.]/g, "-");
|
|
118
|
-
return "".concat(DEFAULT_CONFIG.sessionPrefix, "-").concat(sanitizedHost);
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* List all local tmux sessions
|
|
122
|
-
* @returns Array of session names
|
|
123
|
-
*/
|
|
124
|
-
function listLocalSessions() {
|
|
125
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
126
|
-
var stdout, _a;
|
|
127
|
-
return __generator(this, function (_b) {
|
|
128
|
-
switch (_b.label) {
|
|
129
|
-
case 0:
|
|
130
|
-
_b.trys.push([0, 2, , 3]);
|
|
131
|
-
return [4 /*yield*/, execAsync('tmux list-sessions -F "#{session_name}" 2>/dev/null || echo ""', { timeout: 5000 })];
|
|
132
|
-
case 1:
|
|
133
|
-
stdout = (_b.sent()).stdout;
|
|
134
|
-
if (!stdout || stdout.trim() === "") {
|
|
135
|
-
return [2 /*return*/, []];
|
|
136
|
-
}
|
|
137
|
-
return [2 /*return*/, stdout.trim().split("\n")];
|
|
138
|
-
case 2:
|
|
139
|
-
_a = _b.sent();
|
|
140
|
-
return [2 /*return*/, []];
|
|
141
|
-
case 3: return [2 /*return*/];
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Check if a specific local tmux session exists
|
|
148
|
-
* @param sessionName - Session name to check
|
|
149
|
-
* @returns True if session exists
|
|
150
|
-
*/
|
|
151
|
-
function hasLocalSession(sessionName) {
|
|
152
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
153
|
-
var sessions;
|
|
154
|
-
return __generator(this, function (_a) {
|
|
155
|
-
switch (_a.label) {
|
|
156
|
-
case 0: return [4 /*yield*/, listLocalSessions()];
|
|
157
|
-
case 1:
|
|
158
|
-
sessions = _a.sent();
|
|
159
|
-
return [2 /*return*/, sessions.includes(sessionName)];
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Create a local tmux session with an active SSH connection
|
|
166
|
-
*
|
|
167
|
-
* This function creates a tmux session on the local machine that maintains
|
|
168
|
-
* an active SSH connection to the remote host. The connection stays alive
|
|
169
|
-
* within the tmux session, allowing for persistent interactions.
|
|
170
|
-
*
|
|
171
|
-
* @param host - Remote host IP or hostname
|
|
172
|
-
* @param user - SSH user (default: "root")
|
|
173
|
-
* @param keyPath - Path to SSH private key (for key-based auth)
|
|
174
|
-
* @param password - SSH password (for password-based auth)
|
|
175
|
-
* @param options - Additional options for session creation
|
|
176
|
-
* @returns Session creation result
|
|
177
|
-
*
|
|
178
|
-
* @example
|
|
179
|
-
* ```ts
|
|
180
|
-
* // Key-based authentication
|
|
181
|
-
* const result = await createLocalTmuxSSHSession(
|
|
182
|
-
* "192.168.1.100",
|
|
183
|
-
* "root",
|
|
184
|
-
* "/path/to/key"
|
|
185
|
-
* );
|
|
186
|
-
*
|
|
187
|
-
* // Password-based authentication (requires sshpass)
|
|
188
|
-
* const result = await createLocalTmuxSSHSession(
|
|
189
|
-
* "192.168.1.100",
|
|
190
|
-
* "root",
|
|
191
|
-
* undefined,
|
|
192
|
-
* "mypassword"
|
|
193
|
-
* );
|
|
194
|
-
* ```
|
|
195
|
-
*/
|
|
196
|
-
function createLocalTmuxSSHSession(host_1) {
|
|
197
|
-
return __awaiter(this, arguments, void 0, function (host, user, keyPath, password, options) {
|
|
198
|
-
var tmuxInstalled, sessionName, windowName, sessionExists, sshCommand, _a, createCmd, _b, error_1;
|
|
199
|
-
if (user === void 0) { user = "root"; }
|
|
200
|
-
if (options === void 0) { options = {}; }
|
|
201
|
-
return __generator(this, function (_c) {
|
|
202
|
-
switch (_c.label) {
|
|
203
|
-
case 0: return [4 /*yield*/, isLocalTmuxInstalled()];
|
|
204
|
-
case 1:
|
|
205
|
-
tmuxInstalled = _c.sent();
|
|
206
|
-
if (!tmuxInstalled) {
|
|
207
|
-
throw new Error("tmux is not installed on the local machine. Please install it using: brew install tmux (macOS) or apt install tmux (Linux)");
|
|
208
|
-
}
|
|
209
|
-
sessionName = options.sessionName || generateLocalSessionName(host, user);
|
|
210
|
-
windowName = options.windowName || "ssh";
|
|
211
|
-
return [4 /*yield*/, hasLocalSession(sessionName)];
|
|
212
|
-
case 2:
|
|
213
|
-
sessionExists = _c.sent();
|
|
214
|
-
if (sessionExists) {
|
|
215
|
-
// Session already exists, return info
|
|
216
|
-
return [2 /*return*/, {
|
|
217
|
-
sessionName: sessionName,
|
|
218
|
-
newlyCreated: false,
|
|
219
|
-
command: "tmux attach-session -t ".concat(sessionName),
|
|
220
|
-
}];
|
|
221
|
-
}
|
|
222
|
-
if (!keyPath) return [3 /*break*/, 3];
|
|
223
|
-
// Key-based authentication
|
|
224
|
-
sshCommand = "ssh -i ".concat(keyPath, " -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ").concat(user, "@").concat(host);
|
|
225
|
-
return [3 /*break*/, 9];
|
|
226
|
-
case 3:
|
|
227
|
-
if (!password) return [3 /*break*/, 8];
|
|
228
|
-
_c.label = 4;
|
|
229
|
-
case 4:
|
|
230
|
-
_c.trys.push([4, 6, , 7]);
|
|
231
|
-
return [4 /*yield*/, execAsync("type sshpass", { timeout: 5000 })];
|
|
232
|
-
case 5:
|
|
233
|
-
_c.sent();
|
|
234
|
-
sshCommand = "sshpass -p '".concat(password, "' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ").concat(user, "@").concat(host);
|
|
235
|
-
return [3 /*break*/, 7];
|
|
236
|
-
case 6:
|
|
237
|
-
_a = _c.sent();
|
|
238
|
-
throw new Error("Password authentication requires 'sshpass' to be installed. Please install it using: brew install sshpass (macOS) or apt install sshpass (Linux). Alternatively, use key-based authentication.");
|
|
239
|
-
case 7: return [3 /*break*/, 9];
|
|
240
|
-
case 8:
|
|
241
|
-
// No auth method provided, try default SSH agent
|
|
242
|
-
sshCommand = "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ".concat(user, "@").concat(host);
|
|
243
|
-
_c.label = 9;
|
|
244
|
-
case 9:
|
|
245
|
-
createCmd = [
|
|
246
|
-
"tmux",
|
|
247
|
-
"new-session",
|
|
248
|
-
"-d",
|
|
249
|
-
"-s", sessionName,
|
|
250
|
-
"-n", windowName,
|
|
251
|
-
sshCommand,
|
|
252
|
-
].join(" ");
|
|
253
|
-
_c.label = 10;
|
|
254
|
-
case 10:
|
|
255
|
-
_c.trys.push([10, 19, , 20]);
|
|
256
|
-
// Create the session
|
|
257
|
-
return [4 /*yield*/, execAsync(createCmd, { timeout: DEFAULT_CONFIG.timeout * 1000 })];
|
|
258
|
-
case 11:
|
|
259
|
-
// Create the session
|
|
260
|
-
_c.sent();
|
|
261
|
-
_c.label = 12;
|
|
262
|
-
case 12:
|
|
263
|
-
_c.trys.push([12, 14, , 15]);
|
|
264
|
-
return [4 /*yield*/, execAsync("tmux set-option -t \"".concat(sessionName, "\" history-limit ").concat(DEFAULT_CONFIG.historyLimit), { timeout: 5000 })];
|
|
265
|
-
case 13:
|
|
266
|
-
_c.sent();
|
|
267
|
-
return [3 /*break*/, 15];
|
|
268
|
-
case 14:
|
|
269
|
-
_b = _c.sent();
|
|
270
|
-
return [3 /*break*/, 15];
|
|
271
|
-
case 15:
|
|
272
|
-
if (!options.initialCommand) return [3 /*break*/, 18];
|
|
273
|
-
// Wait a moment for SSH to connect
|
|
274
|
-
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 2000); })];
|
|
275
|
-
case 16:
|
|
276
|
-
// Wait a moment for SSH to connect
|
|
277
|
-
_c.sent();
|
|
278
|
-
return [4 /*yield*/, sendCommandToLocalSession(sessionName, options.initialCommand)];
|
|
279
|
-
case 17:
|
|
280
|
-
_c.sent();
|
|
281
|
-
_c.label = 18;
|
|
282
|
-
case 18: return [2 /*return*/, {
|
|
283
|
-
sessionName: sessionName,
|
|
284
|
-
newlyCreated: true,
|
|
285
|
-
command: createCmd,
|
|
286
|
-
}];
|
|
287
|
-
case 19:
|
|
288
|
-
error_1 = _c.sent();
|
|
289
|
-
throw new Error("Failed to create local tmux session: ".concat(error_1 instanceof Error ? error_1.message : String(error_1)));
|
|
290
|
-
case 20: return [2 /*return*/];
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Send a command to a local tmux pane (already SSH'd into the remote host)
|
|
297
|
-
*
|
|
298
|
-
* This function sends a command to the tmux pane, which will be executed
|
|
299
|
-
* on the remote host since the SSH connection is already active.
|
|
300
|
-
*
|
|
301
|
-
* @param sessionName - Local tmux session name
|
|
302
|
-
* @param command - Command to send to the remote host
|
|
303
|
-
* @param paneIndex - Pane index (default: "0")
|
|
304
|
-
* @param windowName - Window name (default: auto-detects first window)
|
|
305
|
-
* @returns True if command was sent successfully
|
|
306
|
-
*/
|
|
307
|
-
function sendCommandToLocalSession(sessionName_1, command_1) {
|
|
308
|
-
return __awaiter(this, arguments, void 0, function (sessionName, command, paneIndex, windowName) {
|
|
309
|
-
var escapedCmd, targetWindow, windows, _a, target, sendCmd, error_2;
|
|
310
|
-
if (paneIndex === void 0) { paneIndex = "0"; }
|
|
311
|
-
return __generator(this, function (_b) {
|
|
312
|
-
switch (_b.label) {
|
|
313
|
-
case 0:
|
|
314
|
-
_b.trys.push([0, 6, , 7]);
|
|
315
|
-
escapedCmd = command.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
316
|
-
targetWindow = windowName;
|
|
317
|
-
if (!!targetWindow) return [3 /*break*/, 4];
|
|
318
|
-
_b.label = 1;
|
|
319
|
-
case 1:
|
|
320
|
-
_b.trys.push([1, 3, , 4]);
|
|
321
|
-
return [4 /*yield*/, listLocalSessionWindows(sessionName)];
|
|
322
|
-
case 2:
|
|
323
|
-
windows = _b.sent();
|
|
324
|
-
if (windows.length > 0) {
|
|
325
|
-
targetWindow = windows[0].name;
|
|
326
|
-
}
|
|
327
|
-
return [3 /*break*/, 4];
|
|
328
|
-
case 3:
|
|
329
|
-
_a = _b.sent();
|
|
330
|
-
// Fallback to default
|
|
331
|
-
targetWindow = "ssh";
|
|
332
|
-
return [3 /*break*/, 4];
|
|
333
|
-
case 4:
|
|
334
|
-
target = paneIndex === "0"
|
|
335
|
-
? "".concat(sessionName, ":").concat(targetWindow)
|
|
336
|
-
: "".concat(sessionName, ":").concat(targetWindow, ".").concat(parseInt(paneIndex, 10));
|
|
337
|
-
sendCmd = "tmux send-keys -t \"".concat(target, "\" \"").concat(escapedCmd, "\" Enter");
|
|
338
|
-
return [4 /*yield*/, execAsync(sendCmd, { timeout: 5000 })];
|
|
339
|
-
case 5:
|
|
340
|
-
_b.sent();
|
|
341
|
-
return [2 /*return*/, true];
|
|
342
|
-
case 6:
|
|
343
|
-
error_2 = _b.sent();
|
|
344
|
-
console.error("[LocalTmux] Failed to send command to ".concat(sessionName, ":").concat(paneIndex, ":"), error_2);
|
|
345
|
-
return [2 /*return*/, false];
|
|
346
|
-
case 7: return [2 /*return*/];
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Capture output from a local tmux pane
|
|
353
|
-
*
|
|
354
|
-
* This captures the current visible content of the pane, including
|
|
355
|
-
* the scrollback history.
|
|
356
|
-
*
|
|
357
|
-
* @param sessionName - Local tmux session name
|
|
358
|
-
* @param paneIndex - Pane index (default: "0")
|
|
359
|
-
* @param windowName - Window name (default: auto-detects first window)
|
|
360
|
-
* @returns Captured output or null if failed
|
|
361
|
-
*/
|
|
362
|
-
function captureLocalPane(sessionName_1) {
|
|
363
|
-
return __awaiter(this, arguments, void 0, function (sessionName, paneIndex, windowName) {
|
|
364
|
-
var targetWindow, windows, _a, target, stdout, error_3;
|
|
365
|
-
if (paneIndex === void 0) { paneIndex = "0"; }
|
|
366
|
-
return __generator(this, function (_b) {
|
|
367
|
-
switch (_b.label) {
|
|
368
|
-
case 0:
|
|
369
|
-
_b.trys.push([0, 6, , 7]);
|
|
370
|
-
targetWindow = windowName;
|
|
371
|
-
if (!!targetWindow) return [3 /*break*/, 4];
|
|
372
|
-
_b.label = 1;
|
|
373
|
-
case 1:
|
|
374
|
-
_b.trys.push([1, 3, , 4]);
|
|
375
|
-
return [4 /*yield*/, listLocalSessionWindows(sessionName)];
|
|
376
|
-
case 2:
|
|
377
|
-
windows = _b.sent();
|
|
378
|
-
if (windows.length > 0) {
|
|
379
|
-
targetWindow = windows[0].name;
|
|
380
|
-
}
|
|
381
|
-
return [3 /*break*/, 4];
|
|
382
|
-
case 3:
|
|
383
|
-
_a = _b.sent();
|
|
384
|
-
targetWindow = "ssh";
|
|
385
|
-
return [3 /*break*/, 4];
|
|
386
|
-
case 4:
|
|
387
|
-
target = paneIndex === "0"
|
|
388
|
-
? "".concat(sessionName, ":").concat(targetWindow)
|
|
389
|
-
: "".concat(sessionName, ":").concat(targetWindow, ".").concat(parseInt(paneIndex, 10));
|
|
390
|
-
return [4 /*yield*/, execAsync("tmux capture-pane -t \"".concat(target, "\" -p"), { timeout: 5000 })];
|
|
391
|
-
case 5:
|
|
392
|
-
stdout = (_b.sent()).stdout;
|
|
393
|
-
return [2 /*return*/, stdout || null];
|
|
394
|
-
case 6:
|
|
395
|
-
error_3 = _b.sent();
|
|
396
|
-
console.error("[LocalTmux] Failed to capture pane ".concat(sessionName, ":").concat(paneIndex, ":"), error_3);
|
|
397
|
-
return [2 /*return*/, null];
|
|
398
|
-
case 7: return [2 /*return*/];
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* Get scrollback/history from a local tmux pane
|
|
405
|
-
*
|
|
406
|
-
* @param sessionName - Local tmux session name
|
|
407
|
-
* @param paneIndex - Pane index (default: "0")
|
|
408
|
-
* @param lines - Number of lines to retrieve (default: -1 for all)
|
|
409
|
-
* @param windowName - Window name (default: auto-detects first window)
|
|
410
|
-
* @returns History content or null if failed
|
|
411
|
-
*/
|
|
412
|
-
function getLocalPaneHistory(sessionName_1) {
|
|
413
|
-
return __awaiter(this, arguments, void 0, function (sessionName, paneIndex, lines, windowName) {
|
|
414
|
-
var targetWindow, windows, _a, target, linesArg, stdout, error_4;
|
|
415
|
-
if (paneIndex === void 0) { paneIndex = "0"; }
|
|
416
|
-
if (lines === void 0) { lines = -1; }
|
|
417
|
-
return __generator(this, function (_b) {
|
|
418
|
-
switch (_b.label) {
|
|
419
|
-
case 0:
|
|
420
|
-
_b.trys.push([0, 6, , 7]);
|
|
421
|
-
targetWindow = windowName;
|
|
422
|
-
if (!!targetWindow) return [3 /*break*/, 4];
|
|
423
|
-
_b.label = 1;
|
|
424
|
-
case 1:
|
|
425
|
-
_b.trys.push([1, 3, , 4]);
|
|
426
|
-
return [4 /*yield*/, listLocalSessionWindows(sessionName)];
|
|
427
|
-
case 2:
|
|
428
|
-
windows = _b.sent();
|
|
429
|
-
if (windows.length > 0) {
|
|
430
|
-
targetWindow = windows[0].name;
|
|
431
|
-
}
|
|
432
|
-
return [3 /*break*/, 4];
|
|
433
|
-
case 3:
|
|
434
|
-
_a = _b.sent();
|
|
435
|
-
targetWindow = "ssh";
|
|
436
|
-
return [3 /*break*/, 4];
|
|
437
|
-
case 4:
|
|
438
|
-
target = paneIndex === "0"
|
|
439
|
-
? "".concat(sessionName, ":").concat(targetWindow)
|
|
440
|
-
: "".concat(sessionName, ":").concat(targetWindow, ".").concat(parseInt(paneIndex, 10));
|
|
441
|
-
linesArg = lines > 0 ? "-S -".concat(lines) : "-S -";
|
|
442
|
-
return [4 /*yield*/, execAsync("tmux capture-pane ".concat(linesArg, " -t \"").concat(target, "\" -p"), { timeout: 10000 })];
|
|
443
|
-
case 5:
|
|
444
|
-
stdout = (_b.sent()).stdout;
|
|
445
|
-
return [2 /*return*/, stdout || null];
|
|
446
|
-
case 6:
|
|
447
|
-
error_4 = _b.sent();
|
|
448
|
-
console.error("[LocalTmux] Failed to get history for ".concat(sessionName, ":").concat(paneIndex, ":"), error_4);
|
|
449
|
-
return [2 /*return*/, null];
|
|
450
|
-
case 7: return [2 /*return*/];
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Kill a local tmux session
|
|
457
|
-
*
|
|
458
|
-
* @param sessionName - Session name to kill
|
|
459
|
-
* @returns True if session was killed successfully
|
|
460
|
-
*/
|
|
461
|
-
function killLocalSession(sessionName) {
|
|
462
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
463
|
-
var _a;
|
|
464
|
-
return __generator(this, function (_b) {
|
|
465
|
-
switch (_b.label) {
|
|
466
|
-
case 0:
|
|
467
|
-
_b.trys.push([0, 2, , 3]);
|
|
468
|
-
return [4 /*yield*/, execAsync("tmux kill-session -t \"".concat(sessionName, "\" 2>/dev/null"), {
|
|
469
|
-
timeout: 5000,
|
|
470
|
-
})];
|
|
471
|
-
case 1:
|
|
472
|
-
_b.sent();
|
|
473
|
-
return [2 /*return*/, true];
|
|
474
|
-
case 2:
|
|
475
|
-
_a = _b.sent();
|
|
476
|
-
return [2 /*return*/, false];
|
|
477
|
-
case 3: return [2 /*return*/];
|
|
478
|
-
}
|
|
479
|
-
});
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Get information about a local tmux session
|
|
484
|
-
*
|
|
485
|
-
* @param sessionName - Session name to query
|
|
486
|
-
* @returns Session information or null if session doesn't exist
|
|
487
|
-
*/
|
|
488
|
-
function getLocalSessionInfo(sessionName) {
|
|
489
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
490
|
-
var stdout, _a, windows, panes, _b;
|
|
491
|
-
return __generator(this, function (_c) {
|
|
492
|
-
switch (_c.label) {
|
|
493
|
-
case 0:
|
|
494
|
-
_c.trys.push([0, 2, , 3]);
|
|
495
|
-
return [4 /*yield*/, execAsync("tmux display-message -t \"".concat(sessionName, "\" -p '#{session_windows} #{window_panes}' 2>/dev/null || echo \"\""), { timeout: 5000 })];
|
|
496
|
-
case 1:
|
|
497
|
-
stdout = (_c.sent()).stdout;
|
|
498
|
-
if (!stdout || stdout.trim() === "") {
|
|
499
|
-
return [2 /*return*/, { exists: false }];
|
|
500
|
-
}
|
|
501
|
-
_a = stdout.trim().split(" ").map(Number), windows = _a[0], panes = _a[1];
|
|
502
|
-
return [2 /*return*/, { exists: true, windows: windows, panes: panes }];
|
|
503
|
-
case 2:
|
|
504
|
-
_b = _c.sent();
|
|
505
|
-
return [2 /*return*/, { exists: false }];
|
|
506
|
-
case 3: return [2 /*return*/];
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
/**
|
|
512
|
-
* List all windows in a local tmux session
|
|
513
|
-
*
|
|
514
|
-
* @param sessionName - Local tmux session name
|
|
515
|
-
* @returns Array of window information
|
|
516
|
-
*/
|
|
517
|
-
function listLocalSessionWindows(sessionName) {
|
|
518
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
519
|
-
var stdout, _a;
|
|
520
|
-
return __generator(this, function (_b) {
|
|
521
|
-
switch (_b.label) {
|
|
522
|
-
case 0:
|
|
523
|
-
_b.trys.push([0, 2, , 3]);
|
|
524
|
-
return [4 /*yield*/, execAsync("tmux list-windows -t \"".concat(sessionName, "\" -F '#{window_index} #{window_name} #{window_active}' 2>/dev/null || echo ''"), { timeout: 5000 })];
|
|
525
|
-
case 1:
|
|
526
|
-
stdout = (_b.sent()).stdout;
|
|
527
|
-
if (!stdout || stdout.trim() === "") {
|
|
528
|
-
return [2 /*return*/, []];
|
|
529
|
-
}
|
|
530
|
-
return [2 /*return*/, stdout.trim().split("\n").map(function (line) {
|
|
531
|
-
var _a = line.split(" "), index = _a[0], name = _a[1], active = _a[2];
|
|
532
|
-
return { index: index, name: name, active: active === "1" };
|
|
533
|
-
})];
|
|
534
|
-
case 2:
|
|
535
|
-
_a = _b.sent();
|
|
536
|
-
return [2 /*return*/, []];
|
|
537
|
-
case 3: return [2 /*return*/];
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* List all panes in a local tmux session window
|
|
544
|
-
*
|
|
545
|
-
* @param sessionName - Local tmux session name
|
|
546
|
-
* @param windowIndex - Window index (default: "0")
|
|
547
|
-
* @returns Array of pane information
|
|
548
|
-
*/
|
|
549
|
-
function listLocalWindowPanes(sessionName_1) {
|
|
550
|
-
return __awaiter(this, arguments, void 0, function (sessionName, windowIndex) {
|
|
551
|
-
var stdout, _a;
|
|
552
|
-
if (windowIndex === void 0) { windowIndex = "0"; }
|
|
553
|
-
return __generator(this, function (_b) {
|
|
554
|
-
switch (_b.label) {
|
|
555
|
-
case 0:
|
|
556
|
-
_b.trys.push([0, 2, , 3]);
|
|
557
|
-
return [4 /*yield*/, execAsync("tmux list-panes -t \"".concat(sessionName, ":").concat(windowIndex, "\" -F '#{pane_index} #{pane_current_path} #{pane_pid} #{pane_active}' 2>/dev/null || echo ''"), { timeout: 5000 })];
|
|
558
|
-
case 1:
|
|
559
|
-
stdout = (_b.sent()).stdout;
|
|
560
|
-
if (!stdout || stdout.trim() === "") {
|
|
561
|
-
return [2 /*return*/, []];
|
|
562
|
-
}
|
|
563
|
-
return [2 /*return*/, stdout.trim().split("\n").map(function (line) {
|
|
564
|
-
var _a = line.split(" "), index = _a[0], currentPath = _a[1], pid = _a[2], active = _a[3];
|
|
565
|
-
return { index: index, currentPath: currentPath, pid: pid, active: active === "1" };
|
|
566
|
-
})];
|
|
567
|
-
case 2:
|
|
568
|
-
_a = _b.sent();
|
|
569
|
-
return [2 /*return*/, []];
|
|
570
|
-
case 3: return [2 /*return*/];
|
|
571
|
-
}
|
|
572
|
-
});
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
/**
|
|
576
|
-
* Split a pane horizontally or vertically in a local tmux session
|
|
577
|
-
*
|
|
578
|
-
* @param sessionName - Local tmux session name
|
|
579
|
-
* @param direction - Split direction: "h" (horizontal) or "v" (vertical)
|
|
580
|
-
* @param command - Optional command to run in the new pane
|
|
581
|
-
* @param windowName - Window name (default: auto-detects first window)
|
|
582
|
-
* @returns The new pane index or null if failed
|
|
583
|
-
*/
|
|
584
|
-
function splitLocalPane(sessionName_1) {
|
|
585
|
-
return __awaiter(this, arguments, void 0, function (sessionName, direction, command, windowName) {
|
|
586
|
-
var targetWindow, windows, _a, target, splitCmd, stdout, error_5;
|
|
587
|
-
if (direction === void 0) { direction = "v"; }
|
|
588
|
-
return __generator(this, function (_b) {
|
|
589
|
-
switch (_b.label) {
|
|
590
|
-
case 0:
|
|
591
|
-
_b.trys.push([0, 6, , 7]);
|
|
592
|
-
targetWindow = windowName;
|
|
593
|
-
if (!!targetWindow) return [3 /*break*/, 4];
|
|
594
|
-
_b.label = 1;
|
|
595
|
-
case 1:
|
|
596
|
-
_b.trys.push([1, 3, , 4]);
|
|
597
|
-
return [4 /*yield*/, listLocalSessionWindows(sessionName)];
|
|
598
|
-
case 2:
|
|
599
|
-
windows = _b.sent();
|
|
600
|
-
if (windows.length > 0) {
|
|
601
|
-
targetWindow = windows[0].name;
|
|
602
|
-
}
|
|
603
|
-
return [3 /*break*/, 4];
|
|
604
|
-
case 3:
|
|
605
|
-
_a = _b.sent();
|
|
606
|
-
targetWindow = "ssh";
|
|
607
|
-
return [3 /*break*/, 4];
|
|
608
|
-
case 4:
|
|
609
|
-
target = "".concat(sessionName, ":").concat(targetWindow);
|
|
610
|
-
splitCmd = command
|
|
611
|
-
? "tmux split-window -".concat(direction, " -t \"").concat(target, "\" -c \"#{pane_current_path}\" \"").concat(command, "\"")
|
|
612
|
-
: "tmux split-window -".concat(direction, " -t \"").concat(target, "\"");
|
|
613
|
-
return [4 /*yield*/, execAsync(splitCmd, { timeout: 10000 })];
|
|
614
|
-
case 5:
|
|
615
|
-
stdout = (_b.sent()).stdout;
|
|
616
|
-
return [2 /*return*/, (stdout === null || stdout === void 0 ? void 0 : stdout.trim()) || null];
|
|
617
|
-
case 6:
|
|
618
|
-
error_5 = _b.sent();
|
|
619
|
-
console.error("[LocalTmux] Failed to split pane in ".concat(sessionName, ":"), error_5);
|
|
620
|
-
return [2 /*return*/, null];
|
|
621
|
-
case 7: return [2 /*return*/];
|
|
622
|
-
}
|
|
623
|
-
});
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
/**
|
|
627
|
-
* Cleanup old local tmux sessions
|
|
628
|
-
*
|
|
629
|
-
* @param config - Optional configuration (uses default age limit if not provided)
|
|
630
|
-
* @returns Object with cleaned count and errors
|
|
631
|
-
*/
|
|
632
|
-
function cleanupOldLocalSessions() {
|
|
633
|
-
return __awaiter(this, arguments, void 0, function (config) {
|
|
634
|
-
var fullConfig, errors, cleaned, sessions, mcpSessions, _i, mcpSessions_1, sessionName, ageCheckCmd, stdout, ageMs, err_1, err_2;
|
|
635
|
-
if (config === void 0) { config = {}; }
|
|
636
|
-
return __generator(this, function (_a) {
|
|
637
|
-
switch (_a.label) {
|
|
638
|
-
case 0:
|
|
639
|
-
fullConfig = __assign(__assign({}, DEFAULT_CONFIG), config);
|
|
640
|
-
errors = [];
|
|
641
|
-
cleaned = 0;
|
|
642
|
-
_a.label = 1;
|
|
643
|
-
case 1:
|
|
644
|
-
_a.trys.push([1, 11, , 12]);
|
|
645
|
-
return [4 /*yield*/, listLocalSessions()];
|
|
646
|
-
case 2:
|
|
647
|
-
sessions = _a.sent();
|
|
648
|
-
mcpSessions = sessions.filter(function (s) { return s.startsWith(fullConfig.sessionPrefix); });
|
|
649
|
-
_i = 0, mcpSessions_1 = mcpSessions;
|
|
650
|
-
_a.label = 3;
|
|
651
|
-
case 3:
|
|
652
|
-
if (!(_i < mcpSessions_1.length)) return [3 /*break*/, 10];
|
|
653
|
-
sessionName = mcpSessions_1[_i];
|
|
654
|
-
_a.label = 4;
|
|
655
|
-
case 4:
|
|
656
|
-
_a.trys.push([4, 8, , 9]);
|
|
657
|
-
ageCheckCmd = "\n find /tmp -type s -name \"*".concat(sessionName, "*\" 2>/dev/null | head -1 | while read socket; do\n if [ -n \"$socket\" ]; then\n mtime=$(stat -f %m \"$socket\" 2>/dev/null || stat -c %Y \"$socket\" 2>/dev/null)\n if [ -n \"$mtime\" ]; then\n now=$(date +%s)\n age=$((now - mtime))\n age_ms=$((age * 1000))\n echo \"$age_ms\"\n fi\n fi\n done\n ");
|
|
658
|
-
return [4 /*yield*/, execAsync(ageCheckCmd, { timeout: 10000 })];
|
|
659
|
-
case 5:
|
|
660
|
-
stdout = (_a.sent()).stdout;
|
|
661
|
-
ageMs = parseInt(stdout.trim());
|
|
662
|
-
if (!(!isNaN(ageMs) && ageMs > fullConfig.sessionAgeLimit)) return [3 /*break*/, 7];
|
|
663
|
-
console.log("[LocalTmux] Cleaning up old session \"".concat(sessionName, "\" (age: ").concat(Math.round(ageMs / 86400000), " days)"));
|
|
664
|
-
return [4 /*yield*/, killLocalSession(sessionName)];
|
|
665
|
-
case 6:
|
|
666
|
-
_a.sent();
|
|
667
|
-
cleaned++;
|
|
668
|
-
_a.label = 7;
|
|
669
|
-
case 7: return [3 /*break*/, 9];
|
|
670
|
-
case 8:
|
|
671
|
-
err_1 = _a.sent();
|
|
672
|
-
errors.push("".concat(sessionName, ": ").concat(err_1 instanceof Error ? err_1.message : String(err_1)));
|
|
673
|
-
return [3 /*break*/, 9];
|
|
674
|
-
case 9:
|
|
675
|
-
_i++;
|
|
676
|
-
return [3 /*break*/, 3];
|
|
677
|
-
case 10: return [2 /*return*/, { cleaned: cleaned, errors: errors }];
|
|
678
|
-
case 11:
|
|
679
|
-
err_2 = _a.sent();
|
|
680
|
-
errors.push("Cleanup failed: ".concat(err_2 instanceof Error ? err_2.message : String(err_2)));
|
|
681
|
-
return [2 /*return*/, { cleaned: cleaned, errors: errors }];
|
|
682
|
-
case 12: return [2 /*return*/];
|
|
683
|
-
}
|
|
684
|
-
});
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
/**
|
|
688
|
-
* Get resource usage information for local tmux sessions
|
|
689
|
-
*
|
|
690
|
-
* @returns Resource usage summary
|
|
691
|
-
*/
|
|
692
|
-
function getLocalTmuxResourceUsage() {
|
|
693
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
694
|
-
var sessions, mcpSessions, estimatedMemoryMB, _a;
|
|
695
|
-
return __generator(this, function (_b) {
|
|
696
|
-
switch (_b.label) {
|
|
697
|
-
case 0:
|
|
698
|
-
_b.trys.push([0, 2, , 3]);
|
|
699
|
-
return [4 /*yield*/, listLocalSessions()];
|
|
700
|
-
case 1:
|
|
701
|
-
sessions = _b.sent();
|
|
702
|
-
mcpSessions = sessions.filter(function (s) {
|
|
703
|
-
return s.startsWith(DEFAULT_CONFIG.sessionPrefix);
|
|
704
|
-
});
|
|
705
|
-
estimatedMemoryMB = mcpSessions.length * 11;
|
|
706
|
-
return [2 /*return*/, {
|
|
707
|
-
totalSessions: sessions.length,
|
|
708
|
-
mcpSessions: mcpSessions.length,
|
|
709
|
-
estimatedMemoryMB: estimatedMemoryMB,
|
|
710
|
-
}];
|
|
711
|
-
case 2:
|
|
712
|
-
_a = _b.sent();
|
|
713
|
-
return [2 /*return*/, null];
|
|
714
|
-
case 3: return [2 /*return*/];
|
|
715
|
-
}
|
|
716
|
-
});
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
/**
|
|
720
|
-
* Wait for a specific text to appear in the pane output
|
|
721
|
-
*
|
|
722
|
-
* @param sessionName - Local tmux session name
|
|
723
|
-
* @param text - Text to wait for
|
|
724
|
-
* @param timeoutMs - Maximum time to wait in milliseconds (default: 30000)
|
|
725
|
-
* @param paneIndex - Pane index (default: "0")
|
|
726
|
-
* @param windowName - Window name (default: auto-detects first window)
|
|
727
|
-
* @returns True if text appeared, false if timeout
|
|
728
|
-
*/
|
|
729
|
-
function waitForTextInPane(sessionName_1, text_1) {
|
|
730
|
-
return __awaiter(this, arguments, void 0, function (sessionName, text, timeoutMs, paneIndex, windowName) {
|
|
731
|
-
var startTime, checkInterval, output;
|
|
732
|
-
if (timeoutMs === void 0) { timeoutMs = 30000; }
|
|
733
|
-
if (paneIndex === void 0) { paneIndex = "0"; }
|
|
734
|
-
return __generator(this, function (_a) {
|
|
735
|
-
switch (_a.label) {
|
|
736
|
-
case 0:
|
|
737
|
-
startTime = Date.now();
|
|
738
|
-
checkInterval = 500;
|
|
739
|
-
_a.label = 1;
|
|
740
|
-
case 1:
|
|
741
|
-
if (!(Date.now() - startTime < timeoutMs)) return [3 /*break*/, 4];
|
|
742
|
-
return [4 /*yield*/, captureLocalPane(sessionName, paneIndex, windowName)];
|
|
743
|
-
case 2:
|
|
744
|
-
output = _a.sent();
|
|
745
|
-
if (output && output.includes(text)) {
|
|
746
|
-
return [2 /*return*/, true];
|
|
747
|
-
}
|
|
748
|
-
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, checkInterval); })];
|
|
749
|
-
case 3:
|
|
750
|
-
_a.sent();
|
|
751
|
-
return [3 /*break*/, 1];
|
|
752
|
-
case 4: return [2 /*return*/, false];
|
|
753
|
-
}
|
|
754
|
-
});
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Switch to a specific window in a local tmux session
|
|
759
|
-
*
|
|
760
|
-
* @param sessionName - Local tmux session name
|
|
761
|
-
* @param windowIndex - Target window index
|
|
762
|
-
* @returns True if successful
|
|
763
|
-
*/
|
|
764
|
-
function switchLocalWindow(sessionName, windowIndex) {
|
|
765
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
766
|
-
var _a;
|
|
767
|
-
return __generator(this, function (_b) {
|
|
768
|
-
switch (_b.label) {
|
|
769
|
-
case 0:
|
|
770
|
-
_b.trys.push([0, 2, , 3]);
|
|
771
|
-
return [4 /*yield*/, execAsync("tmux select-window -t \"".concat(sessionName, ":").concat(windowIndex, "\""), {
|
|
772
|
-
timeout: 5000,
|
|
773
|
-
})];
|
|
774
|
-
case 1:
|
|
775
|
-
_b.sent();
|
|
776
|
-
return [2 /*return*/, true];
|
|
777
|
-
case 2:
|
|
778
|
-
_a = _b.sent();
|
|
779
|
-
return [2 /*return*/, false];
|
|
780
|
-
case 3: return [2 /*return*/];
|
|
781
|
-
}
|
|
782
|
-
});
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
/**
|
|
786
|
-
* Switch to a specific pane in a local tmux session window
|
|
787
|
-
*
|
|
788
|
-
* @param sessionName - Local tmux session name
|
|
789
|
-
* @param paneIndex - Target pane index (e.g., "0", "1", "0.1" for window.pane)
|
|
790
|
-
* @returns True if successful
|
|
791
|
-
*/
|
|
792
|
-
function switchLocalPane(sessionName, paneIndex) {
|
|
793
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
794
|
-
var _a;
|
|
795
|
-
return __generator(this, function (_b) {
|
|
796
|
-
switch (_b.label) {
|
|
797
|
-
case 0:
|
|
798
|
-
_b.trys.push([0, 2, , 3]);
|
|
799
|
-
return [4 /*yield*/, execAsync("tmux select-pane -t \"".concat(sessionName, ":").concat(paneIndex, "\""), {
|
|
800
|
-
timeout: 5000,
|
|
801
|
-
})];
|
|
802
|
-
case 1:
|
|
803
|
-
_b.sent();
|
|
804
|
-
return [2 /*return*/, true];
|
|
805
|
-
case 2:
|
|
806
|
-
_a = _b.sent();
|
|
807
|
-
return [2 /*return*/, false];
|
|
808
|
-
case 3: return [2 /*return*/];
|
|
809
|
-
}
|
|
810
|
-
});
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
/**
|
|
814
|
-
* Rename a window in a local tmux session
|
|
815
|
-
*
|
|
816
|
-
* @param sessionName - Local tmux session name
|
|
817
|
-
* @param windowIndex - Window index (default: "0")
|
|
818
|
-
* @param newName - New window name
|
|
819
|
-
* @returns True if successful
|
|
820
|
-
*/
|
|
821
|
-
function renameLocalWindow(sessionName, windowIndex, newName) {
|
|
822
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
823
|
-
var _a;
|
|
824
|
-
return __generator(this, function (_b) {
|
|
825
|
-
switch (_b.label) {
|
|
826
|
-
case 0:
|
|
827
|
-
_b.trys.push([0, 2, , 3]);
|
|
828
|
-
return [4 /*yield*/, execAsync("tmux rename-window -t \"".concat(sessionName, ":").concat(windowIndex, "\" \"").concat(newName, "\""), { timeout: 5000 })];
|
|
829
|
-
case 1:
|
|
830
|
-
_b.sent();
|
|
831
|
-
return [2 /*return*/, true];
|
|
832
|
-
case 2:
|
|
833
|
-
_a = _b.sent();
|
|
834
|
-
return [2 /*return*/, false];
|
|
835
|
-
case 3: return [2 /*return*/];
|
|
836
|
-
}
|
|
837
|
-
});
|
|
838
|
-
});
|
|
839
|
-
}
|
|
840
|
-
/**
|
|
841
|
-
* Kill a specific pane in a local tmux session
|
|
842
|
-
*
|
|
843
|
-
* @param sessionName - Local tmux session name
|
|
844
|
-
* @param paneIndex - Pane index to kill
|
|
845
|
-
* @param windowName - Window name (default: auto-detects first window)
|
|
846
|
-
* @returns True if successful
|
|
847
|
-
*/
|
|
848
|
-
function killLocalPane(sessionName, paneIndex, windowName) {
|
|
849
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
850
|
-
var targetWindow, windows, _a, target, _b;
|
|
851
|
-
return __generator(this, function (_c) {
|
|
852
|
-
switch (_c.label) {
|
|
853
|
-
case 0:
|
|
854
|
-
_c.trys.push([0, 6, , 7]);
|
|
855
|
-
targetWindow = windowName;
|
|
856
|
-
if (!!targetWindow) return [3 /*break*/, 4];
|
|
857
|
-
_c.label = 1;
|
|
858
|
-
case 1:
|
|
859
|
-
_c.trys.push([1, 3, , 4]);
|
|
860
|
-
return [4 /*yield*/, listLocalSessionWindows(sessionName)];
|
|
861
|
-
case 2:
|
|
862
|
-
windows = _c.sent();
|
|
863
|
-
if (windows.length > 0) {
|
|
864
|
-
targetWindow = windows[0].name;
|
|
865
|
-
}
|
|
866
|
-
return [3 /*break*/, 4];
|
|
867
|
-
case 3:
|
|
868
|
-
_a = _c.sent();
|
|
869
|
-
targetWindow = "ssh";
|
|
870
|
-
return [3 /*break*/, 4];
|
|
871
|
-
case 4:
|
|
872
|
-
target = paneIndex === "0"
|
|
873
|
-
? "".concat(sessionName, ":").concat(targetWindow)
|
|
874
|
-
: "".concat(sessionName, ":").concat(targetWindow, ".").concat(parseInt(paneIndex, 10));
|
|
875
|
-
return [4 /*yield*/, execAsync("tmux kill-pane -t \"".concat(target, "\""), {
|
|
876
|
-
timeout: 5000,
|
|
877
|
-
})];
|
|
878
|
-
case 5:
|
|
879
|
-
_c.sent();
|
|
880
|
-
return [2 /*return*/, true];
|
|
881
|
-
case 6:
|
|
882
|
-
_b = _c.sent();
|
|
883
|
-
return [2 /*return*/, false];
|
|
884
|
-
case 7: return [2 /*return*/];
|
|
885
|
-
}
|
|
886
|
-
});
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
/**
|
|
890
|
-
* Get detailed information about all panes in a local session
|
|
891
|
-
*
|
|
892
|
-
* @param sessionName - Local tmux session name
|
|
893
|
-
* @returns Detailed session information or null
|
|
894
|
-
*/
|
|
895
|
-
function getDetailedLocalSessionInfo(sessionName) {
|
|
896
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
897
|
-
var exists, windows, windowsWithPanes, error_6;
|
|
898
|
-
var _this = this;
|
|
899
|
-
return __generator(this, function (_a) {
|
|
900
|
-
switch (_a.label) {
|
|
901
|
-
case 0:
|
|
902
|
-
_a.trys.push([0, 4, , 5]);
|
|
903
|
-
return [4 /*yield*/, hasLocalSession(sessionName)];
|
|
904
|
-
case 1:
|
|
905
|
-
exists = _a.sent();
|
|
906
|
-
if (!exists) {
|
|
907
|
-
return [2 /*return*/, { exists: false, windows: [] }];
|
|
908
|
-
}
|
|
909
|
-
return [4 /*yield*/, listLocalSessionWindows(sessionName)];
|
|
910
|
-
case 2:
|
|
911
|
-
windows = _a.sent();
|
|
912
|
-
return [4 /*yield*/, Promise.all(windows.map(function (window) { return __awaiter(_this, void 0, void 0, function () {
|
|
913
|
-
var panes;
|
|
914
|
-
return __generator(this, function (_a) {
|
|
915
|
-
switch (_a.label) {
|
|
916
|
-
case 0: return [4 /*yield*/, listLocalWindowPanes(sessionName, window.index)];
|
|
917
|
-
case 1:
|
|
918
|
-
panes = _a.sent();
|
|
919
|
-
return [2 /*return*/, __assign(__assign({}, window), { panes: panes })];
|
|
920
|
-
}
|
|
921
|
-
});
|
|
922
|
-
}); }))];
|
|
923
|
-
case 3:
|
|
924
|
-
windowsWithPanes = _a.sent();
|
|
925
|
-
return [2 /*return*/, {
|
|
926
|
-
exists: true,
|
|
927
|
-
windows: windowsWithPanes,
|
|
928
|
-
}];
|
|
929
|
-
case 4:
|
|
930
|
-
error_6 = _a.sent();
|
|
931
|
-
console.error("[LocalTmux] Failed to get detailed info for ".concat(sessionName, ":"), error_6);
|
|
932
|
-
return [2 /*return*/, null];
|
|
933
|
-
case 5: return [2 /*return*/];
|
|
934
|
-
}
|
|
935
|
-
});
|
|
936
|
-
});
|
|
937
|
-
}
|