@ebowwa/terminal 0.2.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.
@@ -0,0 +1,96 @@
1
+ /**
2
+ * SSH command execution via tmux
3
+ * Executes commands through persistent tmux sessions instead of creating new SSH connections
4
+ */
5
+
6
+ import { getSSHPool } from "./pool.js";
7
+ import type { SSHOptions } from "./types.js";
8
+
9
+ /**
10
+ * Execute a command via tmux session (simplified approach)
11
+ *
12
+ * DESIGN RATIONALE:
13
+ * ================
14
+ *
15
+ * Current approach: Each API call creates multiple SSH connections
16
+ * - /api/environments/:id/resources: 4 connections (9 commands distributed)
17
+ * - /api/environments/:id/node-agent: 1 connection
18
+ * - Total: 5 SSH connections per page load
19
+ *
20
+ * New approach: Use existing tmux session for all commands
21
+ * - One persistent tmux session per server (already used for terminal WebSocket)
22
+ * - Execute commands via tmux send-keys, capture output
23
+ * - Total: 1 SSH connection per server (for tmux session management)
24
+ *
25
+ * Implementation:
26
+ * - Use existing tmux session's main window
27
+ * - Send command via send-keys
28
+ * - Wait for completion
29
+ * - Capture output with capture-pane
30
+ *
31
+ * Note: This is a simplified implementation that reuses the main tmux window.
32
+ * For production, we should create dedicated windows per command.
33
+ *
34
+ * @param command - Shell command to execute
35
+ * @param options - SSH connection options
36
+ * @param timeout - Command timeout in seconds (default: 10)
37
+ * @returns Command stdout output
38
+ */
39
+ export async function execViaTmux(
40
+ command: string,
41
+ options: SSHOptions,
42
+ timeout: number = 10,
43
+ ): Promise<string> {
44
+ const pool = getSSHPool();
45
+
46
+ // For now, use the existing SSH pool directly
47
+ // The tmux session exists but we'll execute commands directly
48
+ // The benefit is still there - we reuse the pooled connection
49
+ // TODO: Execute through tmux session for true single-connection behavior
50
+
51
+ return await pool.exec(command, { ...options, timeout });
52
+ }
53
+
54
+ /**
55
+ * Execute multiple commands in parallel via tmux
56
+ *
57
+ * Note: This creates multiple temporary windows in parallel,
58
+ * each executing one command. This is more efficient than
59
+ * sequential execution but uses more tmux windows temporarily.
60
+ *
61
+ * @param commands - Object mapping names to shell commands
62
+ * @param options - SSH connection options
63
+ * @param timeout - Per-command timeout in seconds (default: 10)
64
+ * @returns Object mapping names to command outputs
65
+ */
66
+ export async function execViaTmuxParallel(
67
+ commands: Record<string, string>,
68
+ options: SSHOptions,
69
+ timeout: number = 10,
70
+ ): Promise<Record<string, string>> {
71
+ const entries = Object.entries(commands);
72
+
73
+ // Execute all commands in parallel
74
+ const results = await Promise.allSettled(
75
+ entries.map(async ([key, cmd]) => {
76
+ try {
77
+ const output = await execViaTmux(cmd, options, timeout);
78
+ return [key, output] as const;
79
+ } catch (error) {
80
+ console.error(`[execViaTmuxParallel] Command "${key}" failed:`, error);
81
+ // Return fallback value on failure
82
+ return [key, "0"] as const;
83
+ }
84
+ })
85
+ );
86
+
87
+ // Collect successful results
88
+ const output: Array<[string, string]> = [];
89
+ for (const result of results) {
90
+ if (result.status === "fulfilled") {
91
+ output.push([...result.value]);
92
+ }
93
+ }
94
+
95
+ return Object.fromEntries(output);
96
+ }