@ebowwa/terminal 0.3.0 → 0.3.2
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 +5722 -6207
- package/dist/mcp/index.js +6160 -6717
- package/package.json +13 -75
- package/dist/cpufeatures-vxqw2k6s.node +0 -0
- package/dist/mcp/cpufeatures-vxqw2k6s.node +0 -0
- package/dist/mcp/sshcrypto-gez6h7ch.node +0 -0
- package/dist/sshcrypto-gez6h7ch.node +0 -0
- package/mcp/README.md +0 -181
- package/mcp/package.json +0 -40
- package/mcp/stdio.js +0 -555
- package/mcp/test-fix.sh +0 -273
- package/mcp/wrapper.mjs +0 -10
- package/src/api.ts +0 -752
- package/src/client.ts +0 -55
- package/src/config.ts +0 -489
- package/src/error.ts +0 -13
- package/src/exec.ts +0 -128
- package/src/files.ts +0 -636
- package/src/fingerprint.ts +0 -263
- package/src/index.ts +0 -148
- package/src/manager.ts +0 -319
- package/src/mcp/index.ts +0 -467
- package/src/mcp/stdio.ts +0 -708
- package/src/network-error-detector.ts +0 -121
- package/src/pool.ts +0 -662
- package/src/pty.ts +0 -285
- package/src/resources.ts +0 -72
- package/src/scp.ts +0 -109
- package/src/sessions.ts +0 -861
- package/src/tmux-exec.ts +0 -96
- package/src/tmux-local.ts +0 -839
- package/src/tmux-manager.ts +0 -962
- package/src/tmux.ts +0 -711
- package/src/types.ts +0 -19
package/src/api.ts
DELETED
|
@@ -1,752 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API routes for Multi-Node Tmux Session Manager
|
|
3
|
-
* Provides REST API for managing tmux sessions across multiple VPS nodes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Hono } from "hono";
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
import { addActivity } from "../lib/activities";
|
|
9
|
-
import {
|
|
10
|
-
getTmuxManager,
|
|
11
|
-
type Node,
|
|
12
|
-
type BatchOperationResult,
|
|
13
|
-
type DetailedTmuxSession,
|
|
14
|
-
} from "./tmux-manager.js";
|
|
15
|
-
import {
|
|
16
|
-
TmuxManagerAddNodeSchema,
|
|
17
|
-
TmuxManagerCreateSessionSchema,
|
|
18
|
-
TmuxManagerAttachSessionSchema,
|
|
19
|
-
TmuxManagerKillSessionSchema,
|
|
20
|
-
TmuxManagerSendCommandSchema,
|
|
21
|
-
TmuxManagerBatchSendCommandSchema,
|
|
22
|
-
TmuxManagerSplitPaneSchema,
|
|
23
|
-
TmuxManagerCapturePaneSchema,
|
|
24
|
-
TmuxManagerGetHistorySchema,
|
|
25
|
-
TmuxManagerListWindowsSchema,
|
|
26
|
-
TmuxManagerListPanesSchema,
|
|
27
|
-
TmuxManagerSwitchWindowSchema,
|
|
28
|
-
TmuxManagerSwitchPaneSchema,
|
|
29
|
-
TmuxManagerRenameWindowSchema,
|
|
30
|
-
TmuxManagerKillPaneSchema,
|
|
31
|
-
TmuxManagerCleanupOldSessionsSchema,
|
|
32
|
-
TmuxManagerDetailedSessionSchema,
|
|
33
|
-
TmuxManagerListSessionsQuerySchema,
|
|
34
|
-
} from "@ebowwa/codespaces-types/runtime/api";
|
|
35
|
-
|
|
36
|
-
const tmuxApi = new Hono();
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Helper function to validate request body against Zod schema
|
|
40
|
-
*/
|
|
41
|
-
function validateRequest<T>(
|
|
42
|
-
schema: z.ZodSchema<T>,
|
|
43
|
-
data: unknown
|
|
44
|
-
): { success: true; data: T } | { success: false; error: string } {
|
|
45
|
-
try {
|
|
46
|
-
const result = schema.safeParse(data);
|
|
47
|
-
if (result.success) {
|
|
48
|
-
return { success: true, data: result.data };
|
|
49
|
-
} else {
|
|
50
|
-
return {
|
|
51
|
-
success: false,
|
|
52
|
-
error: result.error.issues
|
|
53
|
-
.map((e) => `${e.path.join(".")}: ${e.message}`)
|
|
54
|
-
.join(", "),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
} catch (error) {
|
|
58
|
-
return { success: false, error: String(error) };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ============================================
|
|
63
|
-
// Node Management
|
|
64
|
-
// ============================================
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* POST /api/tmux/manager/nodes - Add a node to the manager
|
|
68
|
-
*/
|
|
69
|
-
tmuxApi.post("/manager/nodes", async (c) => {
|
|
70
|
-
const body = await c.req.json();
|
|
71
|
-
const validation = validateRequest(TmuxManagerAddNodeSchema, body);
|
|
72
|
-
|
|
73
|
-
if (!validation.success) {
|
|
74
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
const manager = getTmuxManager();
|
|
79
|
-
manager.addNode(validation.data);
|
|
80
|
-
return c.json({ success: true, node: validation.data });
|
|
81
|
-
} catch (error) {
|
|
82
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* GET /api/tmux/manager/nodes - List all nodes
|
|
88
|
-
*/
|
|
89
|
-
tmuxApi.get("/manager/nodes", async (c) => {
|
|
90
|
-
try {
|
|
91
|
-
const manager = getTmuxManager();
|
|
92
|
-
const nodes = manager.getAllNodes();
|
|
93
|
-
return c.json({ success: true, nodes });
|
|
94
|
-
} catch (error) {
|
|
95
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* GET /api/tmux/manager/nodes/:id - Get a specific node
|
|
101
|
-
*/
|
|
102
|
-
tmuxApi.get("/manager/nodes/:id", async (c) => {
|
|
103
|
-
const id = c.req.param("id");
|
|
104
|
-
if (!id) {
|
|
105
|
-
return c.json({ success: false, error: "Node ID is required" }, 400);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
const manager = getTmuxManager();
|
|
110
|
-
const node = manager.getNode(id);
|
|
111
|
-
if (!node) {
|
|
112
|
-
return c.json({ success: false, error: "Node not found" }, 404);
|
|
113
|
-
}
|
|
114
|
-
return c.json({ success: true, node });
|
|
115
|
-
} catch (error) {
|
|
116
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* DELETE /api/tmux/manager/nodes/:id - Remove a node
|
|
122
|
-
*/
|
|
123
|
-
tmuxApi.delete("/manager/nodes/:id", async (c) => {
|
|
124
|
-
const id = c.req.param("id");
|
|
125
|
-
if (!id) {
|
|
126
|
-
return c.json({ success: false, error: "Node ID is required" }, 400);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
const manager = getTmuxManager();
|
|
131
|
-
const node = manager.getNode(id);
|
|
132
|
-
if (!node) {
|
|
133
|
-
return c.json({ success: false, error: "Node not found" }, 404);
|
|
134
|
-
}
|
|
135
|
-
manager.removeNode(id);
|
|
136
|
-
return c.json({ success: true });
|
|
137
|
-
} catch (error) {
|
|
138
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
// ============================================
|
|
143
|
-
// Session Management
|
|
144
|
-
// ============================================
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* POST /api/tmux/manager/sessions - Create a new session
|
|
148
|
-
*/
|
|
149
|
-
tmuxApi.post("/manager/sessions", async (c) => {
|
|
150
|
-
const body = await c.req.json();
|
|
151
|
-
const validation = validateRequest(TmuxManagerCreateSessionSchema, body);
|
|
152
|
-
|
|
153
|
-
if (!validation.success) {
|
|
154
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
const manager = getTmuxManager();
|
|
159
|
-
const result = await manager.createSession(
|
|
160
|
-
validation.data.nodeId,
|
|
161
|
-
validation.data
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
if (result.success) {
|
|
165
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
166
|
-
if (node) {
|
|
167
|
-
addActivity({
|
|
168
|
-
environmentId: node.id,
|
|
169
|
-
action: "tmux_session_created",
|
|
170
|
-
environmentName: node.name,
|
|
171
|
-
details: result.sessionName
|
|
172
|
-
? `Session "${result.sessionName}" created`
|
|
173
|
-
: "Session created",
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return c.json(result);
|
|
179
|
-
} catch (error) {
|
|
180
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* GET /api/tmux/manager/sessions - List all sessions
|
|
186
|
-
*/
|
|
187
|
-
tmuxApi.get("/manager/sessions", async (c) => {
|
|
188
|
-
try {
|
|
189
|
-
const manager = getTmuxManager();
|
|
190
|
-
|
|
191
|
-
// Parse query parameters
|
|
192
|
-
const nodeIds = c.req.queries()["nodeIds"];
|
|
193
|
-
const tags = c.req.queries()["tags"];
|
|
194
|
-
const detailed = c.req.query("detailed") === "true";
|
|
195
|
-
const includeInactive = c.req.query("includeInactive") === "true";
|
|
196
|
-
|
|
197
|
-
const sessions = await manager.listSessions({
|
|
198
|
-
nodeIds,
|
|
199
|
-
tags,
|
|
200
|
-
detailed,
|
|
201
|
-
includeInactive,
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
return c.json({ success: true, sessions });
|
|
205
|
-
} catch (error) {
|
|
206
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* POST /api/tmux/manager/sessions/attach - Attach to a session
|
|
212
|
-
*/
|
|
213
|
-
tmuxApi.post("/manager/sessions/attach", async (c) => {
|
|
214
|
-
const body = await c.req.json();
|
|
215
|
-
const validation = validateRequest(TmuxManagerAttachSessionSchema, body);
|
|
216
|
-
|
|
217
|
-
if (!validation.success) {
|
|
218
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
const manager = getTmuxManager();
|
|
223
|
-
const result = await manager.attachSession(
|
|
224
|
-
validation.data.nodeId,
|
|
225
|
-
validation.data.sessionName
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
if (result.success) {
|
|
229
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
230
|
-
if (node) {
|
|
231
|
-
addActivity({
|
|
232
|
-
environmentId: node.id,
|
|
233
|
-
action: "tmux_session_attached",
|
|
234
|
-
environmentName: node.name,
|
|
235
|
-
details: `Attached to session "${result.sessionName}"`,
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return c.json(result);
|
|
241
|
-
} catch (error) {
|
|
242
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* DELETE /api/tmux/manager/sessions - Kill a session
|
|
248
|
-
*/
|
|
249
|
-
tmuxApi.delete("/manager/sessions", async (c) => {
|
|
250
|
-
const body = await c.req.json();
|
|
251
|
-
const validation = validateRequest(TmuxManagerKillSessionSchema, body);
|
|
252
|
-
|
|
253
|
-
if (!validation.success) {
|
|
254
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
const manager = getTmuxManager();
|
|
259
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
260
|
-
const result = await manager.killSession(
|
|
261
|
-
validation.data.nodeId,
|
|
262
|
-
validation.data.sessionName
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
if (result.success && node) {
|
|
266
|
-
addActivity({
|
|
267
|
-
environmentId: node.id,
|
|
268
|
-
action: "tmux_session_killed",
|
|
269
|
-
environmentName: node.name,
|
|
270
|
-
details: `Session "${validation.data.sessionName}" killed`,
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return c.json(result);
|
|
275
|
-
} catch (error) {
|
|
276
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
// ============================================
|
|
281
|
-
// Command Execution
|
|
282
|
-
// ============================================
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* POST /api/tmux/manager/sessions/command - Send command to a session
|
|
286
|
-
*/
|
|
287
|
-
tmuxApi.post("/manager/sessions/command", async (c) => {
|
|
288
|
-
const body = await c.req.json();
|
|
289
|
-
const validation = validateRequest(TmuxManagerSendCommandSchema, body);
|
|
290
|
-
|
|
291
|
-
if (!validation.success) {
|
|
292
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
try {
|
|
296
|
-
const manager = getTmuxManager();
|
|
297
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
298
|
-
const result = await manager.sendCommand(
|
|
299
|
-
validation.data.nodeId,
|
|
300
|
-
validation.data.sessionName,
|
|
301
|
-
validation.data.command,
|
|
302
|
-
validation.data.paneIndex
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
if (result.success && node) {
|
|
306
|
-
addActivity({
|
|
307
|
-
environmentId: node.id,
|
|
308
|
-
action: "tmux_command_sent",
|
|
309
|
-
environmentName: node.name,
|
|
310
|
-
details: `Command: ${validation.data.command.slice(0, 100)}${validation.data.command.length > 100 ? "..." : ""}`,
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
return c.json(result);
|
|
315
|
-
} catch (error) {
|
|
316
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* POST /api/tmux/manager/sessions/command/batch - Send command to multiple nodes
|
|
322
|
-
*/
|
|
323
|
-
tmuxApi.post("/manager/sessions/command/batch", async (c) => {
|
|
324
|
-
const body = await c.req.json();
|
|
325
|
-
const validation = validateRequest(TmuxManagerBatchSendCommandSchema, body);
|
|
326
|
-
|
|
327
|
-
if (!validation.success) {
|
|
328
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
try {
|
|
332
|
-
const manager = getTmuxManager();
|
|
333
|
-
const result: BatchOperationResult = await manager.sendCommandToNodes(
|
|
334
|
-
validation.data.nodeIds,
|
|
335
|
-
validation.data.sessionName,
|
|
336
|
-
validation.data.command,
|
|
337
|
-
{
|
|
338
|
-
paneIndex: validation.data.paneIndex,
|
|
339
|
-
parallel: validation.data.parallel,
|
|
340
|
-
continueOnError: validation.data.continueOnError,
|
|
341
|
-
timeout: validation.data.timeout,
|
|
342
|
-
}
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
// Log activity per node
|
|
346
|
-
for (const r of result.results) {
|
|
347
|
-
if (r.success) {
|
|
348
|
-
const node = manager.getNode(r.nodeId);
|
|
349
|
-
if (node) {
|
|
350
|
-
addActivity({
|
|
351
|
-
environmentId: node.id,
|
|
352
|
-
action: "tmux_batch_command_sent",
|
|
353
|
-
environmentName: node.name,
|
|
354
|
-
details: `Batch command to ${result.total} nodes: ${validation.data.command.slice(0, 80)}${validation.data.command.length > 80 ? "..." : ""}`,
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return c.json({ success: true, result });
|
|
361
|
-
} catch (error) {
|
|
362
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
363
|
-
}
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
// ============================================
|
|
367
|
-
// Pane Operations
|
|
368
|
-
// ============================================
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* POST /api/tmux/manager/sessions/split - Split a pane
|
|
372
|
-
*/
|
|
373
|
-
tmuxApi.post("/manager/sessions/split", async (c) => {
|
|
374
|
-
const body = await c.req.json();
|
|
375
|
-
const validation = validateRequest(TmuxManagerSplitPaneSchema, body);
|
|
376
|
-
|
|
377
|
-
if (!validation.success) {
|
|
378
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
try {
|
|
382
|
-
const manager = getTmuxManager();
|
|
383
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
384
|
-
const result = await manager.splitPaneOnNode(
|
|
385
|
-
validation.data.nodeId,
|
|
386
|
-
validation.data.sessionName,
|
|
387
|
-
validation.data.direction,
|
|
388
|
-
validation.data.command,
|
|
389
|
-
validation.data.windowIndex
|
|
390
|
-
);
|
|
391
|
-
|
|
392
|
-
if (result.success && node) {
|
|
393
|
-
addActivity({
|
|
394
|
-
environmentId: node.id,
|
|
395
|
-
action: "tmux_pane_split",
|
|
396
|
-
environmentName: node.name,
|
|
397
|
-
details: `Split pane ${validation.data.direction === "h" ? "horizontally" : "vertically"}${validation.data.command ? ` with command: ${validation.data.command.slice(0, 50)}...` : ""}`,
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return c.json(result);
|
|
402
|
-
} catch (error) {
|
|
403
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* POST /api/tmux/manager/sessions/capture - Capture pane output
|
|
409
|
-
*/
|
|
410
|
-
tmuxApi.post("/manager/sessions/capture", async (c) => {
|
|
411
|
-
const body = await c.req.json();
|
|
412
|
-
const validation = validateRequest(TmuxManagerCapturePaneSchema, body);
|
|
413
|
-
|
|
414
|
-
if (!validation.success) {
|
|
415
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
try {
|
|
419
|
-
const manager = getTmuxManager();
|
|
420
|
-
const result = await manager.capturePaneOutput(
|
|
421
|
-
validation.data.nodeId,
|
|
422
|
-
validation.data.sessionName,
|
|
423
|
-
validation.data.paneIndex
|
|
424
|
-
);
|
|
425
|
-
return c.json(result);
|
|
426
|
-
} catch (error) {
|
|
427
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
428
|
-
}
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* POST /api/tmux/manager/sessions/history - Get pane history
|
|
433
|
-
*/
|
|
434
|
-
tmuxApi.post("/manager/sessions/history", async (c) => {
|
|
435
|
-
const body = await c.req.json();
|
|
436
|
-
const validation = validateRequest(TmuxManagerGetHistorySchema, body);
|
|
437
|
-
|
|
438
|
-
if (!validation.success) {
|
|
439
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
try {
|
|
443
|
-
const manager = getTmuxManager();
|
|
444
|
-
const result = await manager.getPaneHistory(
|
|
445
|
-
validation.data.nodeId,
|
|
446
|
-
validation.data.sessionName,
|
|
447
|
-
validation.data.paneIndex,
|
|
448
|
-
validation.data.lines
|
|
449
|
-
);
|
|
450
|
-
return c.json(result);
|
|
451
|
-
} catch (error) {
|
|
452
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* DELETE /api/tmux/manager/sessions/pane - Kill a pane
|
|
458
|
-
*/
|
|
459
|
-
tmuxApi.delete("/manager/sessions/pane", async (c) => {
|
|
460
|
-
const body = await c.req.json();
|
|
461
|
-
const validation = validateRequest(TmuxManagerKillPaneSchema, body);
|
|
462
|
-
|
|
463
|
-
if (!validation.success) {
|
|
464
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
try {
|
|
468
|
-
const manager = getTmuxManager();
|
|
469
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
470
|
-
const result = await manager.killPaneInSession(
|
|
471
|
-
validation.data.nodeId,
|
|
472
|
-
validation.data.sessionName,
|
|
473
|
-
validation.data.paneIndex
|
|
474
|
-
);
|
|
475
|
-
|
|
476
|
-
if (result.success && node) {
|
|
477
|
-
addActivity({
|
|
478
|
-
environmentId: node.id,
|
|
479
|
-
action: "tmux_pane_killed",
|
|
480
|
-
environmentName: node.name,
|
|
481
|
-
details: `Pane ${validation.data.paneIndex} killed in session "${validation.data.sessionName}"`,
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
return c.json(result);
|
|
486
|
-
} catch (error) {
|
|
487
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
488
|
-
}
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
// ============================================
|
|
492
|
-
// Window Operations
|
|
493
|
-
// ============================================
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
* POST /api/tmux/manager/sessions/windows - List windows in a session
|
|
497
|
-
*/
|
|
498
|
-
tmuxApi.post("/manager/sessions/windows", async (c) => {
|
|
499
|
-
const body = await c.req.json();
|
|
500
|
-
const validation = validateRequest(TmuxManagerListWindowsSchema, body);
|
|
501
|
-
|
|
502
|
-
if (!validation.success) {
|
|
503
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
try {
|
|
507
|
-
const manager = getTmuxManager();
|
|
508
|
-
const result = await manager.listWindows(
|
|
509
|
-
validation.data.nodeId,
|
|
510
|
-
validation.data.sessionName
|
|
511
|
-
);
|
|
512
|
-
return c.json(result);
|
|
513
|
-
} catch (error) {
|
|
514
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
515
|
-
}
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
* POST /api/tmux/manager/sessions/panes - List panes in a window
|
|
520
|
-
*/
|
|
521
|
-
tmuxApi.post("/manager/sessions/panes", async (c) => {
|
|
522
|
-
const body = await c.req.json();
|
|
523
|
-
const validation = validateRequest(TmuxManagerListPanesSchema, body);
|
|
524
|
-
|
|
525
|
-
if (!validation.success) {
|
|
526
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
try {
|
|
530
|
-
const manager = getTmuxManager();
|
|
531
|
-
const result = await manager.listPanes(
|
|
532
|
-
validation.data.nodeId,
|
|
533
|
-
validation.data.sessionName,
|
|
534
|
-
validation.data.windowIndex
|
|
535
|
-
);
|
|
536
|
-
return c.json(result);
|
|
537
|
-
} catch (error) {
|
|
538
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
539
|
-
}
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* POST /api/tmux/manager/sessions/windows/switch - Switch to a window
|
|
544
|
-
*/
|
|
545
|
-
tmuxApi.post("/manager/sessions/windows/switch", async (c) => {
|
|
546
|
-
const body = await c.req.json();
|
|
547
|
-
const validation = validateRequest(TmuxManagerSwitchWindowSchema, body);
|
|
548
|
-
|
|
549
|
-
if (!validation.success) {
|
|
550
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
try {
|
|
554
|
-
const manager = getTmuxManager();
|
|
555
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
556
|
-
const result = await manager.switchToWindow(
|
|
557
|
-
validation.data.nodeId,
|
|
558
|
-
validation.data.sessionName,
|
|
559
|
-
validation.data.windowIndex
|
|
560
|
-
);
|
|
561
|
-
|
|
562
|
-
if (result.success && node) {
|
|
563
|
-
addActivity({
|
|
564
|
-
environmentId: node.id,
|
|
565
|
-
action: "tmux_window_switched",
|
|
566
|
-
environmentName: node.name,
|
|
567
|
-
details: `Switched to window ${validation.data.windowIndex} in session "${validation.data.sessionName}"`,
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
return c.json(result);
|
|
572
|
-
} catch (error) {
|
|
573
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
/**
|
|
578
|
-
* POST /api/tmux/manager/sessions/panes/switch - Switch to a pane
|
|
579
|
-
*/
|
|
580
|
-
tmuxApi.post("/manager/sessions/panes/switch", async (c) => {
|
|
581
|
-
const body = await c.req.json();
|
|
582
|
-
const validation = validateRequest(TmuxManagerSwitchPaneSchema, body);
|
|
583
|
-
|
|
584
|
-
if (!validation.success) {
|
|
585
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
try {
|
|
589
|
-
const manager = getTmuxManager();
|
|
590
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
591
|
-
const result = await manager.switchToPane(
|
|
592
|
-
validation.data.nodeId,
|
|
593
|
-
validation.data.sessionName,
|
|
594
|
-
validation.data.paneIndex
|
|
595
|
-
);
|
|
596
|
-
|
|
597
|
-
if (result.success && node) {
|
|
598
|
-
addActivity({
|
|
599
|
-
environmentId: node.id,
|
|
600
|
-
action: "tmux_pane_switched",
|
|
601
|
-
environmentName: node.name,
|
|
602
|
-
details: `Switched to pane ${validation.data.paneIndex} in session "${validation.data.sessionName}"`,
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
return c.json(result);
|
|
607
|
-
} catch (error) {
|
|
608
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
609
|
-
}
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
/**
|
|
613
|
-
* PUT /api/tmux/manager/sessions/windows/rename - Rename a window
|
|
614
|
-
*/
|
|
615
|
-
tmuxApi.put("/manager/sessions/windows/rename", async (c) => {
|
|
616
|
-
const body = await c.req.json();
|
|
617
|
-
const validation = validateRequest(TmuxManagerRenameWindowSchema, body);
|
|
618
|
-
|
|
619
|
-
if (!validation.success) {
|
|
620
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
try {
|
|
624
|
-
const manager = getTmuxManager();
|
|
625
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
626
|
-
const result = await manager.renameWindowInSession(
|
|
627
|
-
validation.data.nodeId,
|
|
628
|
-
validation.data.sessionName,
|
|
629
|
-
validation.data.windowIndex,
|
|
630
|
-
validation.data.newName
|
|
631
|
-
);
|
|
632
|
-
|
|
633
|
-
if (result.success && node) {
|
|
634
|
-
addActivity({
|
|
635
|
-
environmentId: node.id,
|
|
636
|
-
action: "tmux_window_renamed",
|
|
637
|
-
environmentName: node.name,
|
|
638
|
-
details: `Renamed window ${validation.data.windowIndex} to "${validation.data.newName}" in session "${validation.data.sessionName}"`,
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
return c.json(result);
|
|
643
|
-
} catch (error) {
|
|
644
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
645
|
-
}
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
// ============================================
|
|
649
|
-
// Maintenance & Monitoring
|
|
650
|
-
// ============================================
|
|
651
|
-
|
|
652
|
-
/**
|
|
653
|
-
* GET /api/tmux/manager/sessions/detailed - Get detailed session info
|
|
654
|
-
*/
|
|
655
|
-
tmuxApi.get("/manager/sessions/detailed", async (c) => {
|
|
656
|
-
const nodeId = c.req.query("nodeId");
|
|
657
|
-
const sessionName = c.req.query("sessionName");
|
|
658
|
-
|
|
659
|
-
if (!nodeId || !sessionName) {
|
|
660
|
-
return c.json({ success: false, error: "nodeId and sessionName are required" }, 400);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
try {
|
|
664
|
-
const manager = getTmuxManager();
|
|
665
|
-
const result = await manager.getDetailedSession(nodeId, sessionName);
|
|
666
|
-
return c.json({ success: result !== null, session: result });
|
|
667
|
-
} catch (error) {
|
|
668
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
669
|
-
}
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
/**
|
|
673
|
-
* POST /api/tmux/manager/sessions/cleanup - Cleanup old sessions
|
|
674
|
-
*/
|
|
675
|
-
tmuxApi.post("/manager/sessions/cleanup", async (c) => {
|
|
676
|
-
const body = await c.req.json();
|
|
677
|
-
const validation = validateRequest(TmuxManagerCleanupOldSessionsSchema, body);
|
|
678
|
-
|
|
679
|
-
if (!validation.success) {
|
|
680
|
-
return c.json({ success: false, error: validation.error }, 400);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
try {
|
|
684
|
-
const manager = getTmuxManager();
|
|
685
|
-
const node = manager.getNode(validation.data.nodeId);
|
|
686
|
-
const result = await manager.cleanupOldSessions(
|
|
687
|
-
validation.data.nodeId,
|
|
688
|
-
validation.data.ageLimitMs
|
|
689
|
-
);
|
|
690
|
-
|
|
691
|
-
if (result.success && result.cleaned && result.cleaned > 0 && node) {
|
|
692
|
-
addActivity({
|
|
693
|
-
environmentId: node.id,
|
|
694
|
-
action: "tmux_sessions_cleaned",
|
|
695
|
-
environmentName: node.name,
|
|
696
|
-
details: `Cleaned up ${result.cleaned} old tmux sessions`,
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
return c.json(result);
|
|
701
|
-
} catch (error) {
|
|
702
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
703
|
-
}
|
|
704
|
-
});
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* GET /api/tmux/manager/nodes/:id/resources - Get resource usage for a node
|
|
708
|
-
*/
|
|
709
|
-
tmuxApi.get("/manager/nodes/:id/resources", async (c) => {
|
|
710
|
-
const id = c.req.param("id");
|
|
711
|
-
if (!id) {
|
|
712
|
-
return c.json({ success: false, error: "Node ID is required" }, 400);
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
try {
|
|
716
|
-
const manager = getTmuxManager();
|
|
717
|
-
const result = await manager.getResourceUsage(id);
|
|
718
|
-
return c.json(result);
|
|
719
|
-
} catch (error) {
|
|
720
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
721
|
-
}
|
|
722
|
-
});
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* GET /api/tmux/manager/summary - Get summary statistics
|
|
726
|
-
*/
|
|
727
|
-
tmuxApi.get("/manager/summary", async (c) => {
|
|
728
|
-
try {
|
|
729
|
-
const manager = getTmuxManager();
|
|
730
|
-
const summary = await manager.getSummary();
|
|
731
|
-
return c.json({ success: true, summary });
|
|
732
|
-
} catch (error) {
|
|
733
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
734
|
-
}
|
|
735
|
-
});
|
|
736
|
-
|
|
737
|
-
/**
|
|
738
|
-
* POST /api/tmux/manager/cache/invalidate - Invalidate session cache
|
|
739
|
-
*/
|
|
740
|
-
tmuxApi.post("/manager/cache/invalidate", async (c) => {
|
|
741
|
-
try {
|
|
742
|
-
const manager = getTmuxManager();
|
|
743
|
-
const body = await c.req.json().catch(() => ({}));
|
|
744
|
-
const nodeId = body?.nodeId;
|
|
745
|
-
manager.invalidateCache(nodeId);
|
|
746
|
-
return c.json({ success: true });
|
|
747
|
-
} catch (error) {
|
|
748
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
|
|
752
|
-
export { tmuxApi };
|