@ebowwa/terminal 0.3.4 → 0.3.6

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/pty.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * SSH PTY session manager for interactive terminal sessions
3
+ * Handles bidirectional communication with remote shells
4
+ */
5
+ interface PTYSession {
6
+ id: string;
7
+ host: string;
8
+ user: string;
9
+ proc: any;
10
+ stdin: WritableStream<Uint8Array>;
11
+ stdout: ReadableStream<Uint8Array>;
12
+ stderr: ReadableStream<Uint8Array>;
13
+ rows: number;
14
+ cols: number;
15
+ createdAt: number;
16
+ }
17
+ /**
18
+ * Create a new SSH PTY session
19
+ * Uses script or expect to wrap SSH with PTY allocation
20
+ */
21
+ export declare function createPTYSession(host: string, user?: string, options?: {
22
+ rows?: number;
23
+ cols?: number;
24
+ port?: number;
25
+ keyPath?: string;
26
+ }): Promise<{
27
+ sessionId: string;
28
+ initialOutput: string;
29
+ }>;
30
+ /**
31
+ * Write data to PTY session stdin
32
+ */
33
+ export declare function writeToPTY(sessionId: string, data: string): Promise<boolean>;
34
+ /**
35
+ * Set PTY size (rows and columns)
36
+ */
37
+ export declare function setPTYSize(sessionId: string, rows: number, cols: number): Promise<boolean>;
38
+ /**
39
+ * Read from PTY session stdout (non-blocking)
40
+ */
41
+ export declare function readFromPTY(sessionId: string, timeout?: number): Promise<string | null>;
42
+ /**
43
+ * Close PTY session
44
+ */
45
+ export declare function closePTYSession(sessionId: string): Promise<boolean>;
46
+ /**
47
+ * Get session info
48
+ */
49
+ export declare function getPTYSession(sessionId: string): PTYSession | undefined;
50
+ /**
51
+ * Get all active sessions
52
+ */
53
+ export declare function getActivePTYSessions(): PTYSession[];
54
+ /**
55
+ * Clean up stale sessions (older than specified milliseconds)
56
+ */
57
+ export declare function cleanupStaleSessions(maxAge?: number): void;
58
+ export {};
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Resource monitoring commands for remote servers
3
+ *
4
+ * SSH commands for fetching system resources via execSSHParallel
5
+ * Returns: raw command string to execute via SSH
6
+ *
7
+ * Commands avoid complex quoting for reliable SSH execution
8
+ */
9
+ /**
10
+ * SSH commands for fetching system resources
11
+ * Each command returns space-separated values for easy parsing
12
+ */
13
+ export declare const RESOURCE_COMMANDS: {
14
+ /**
15
+ * CPU usage percentage
16
+ * Format: "12.5" (user+system as percentage of total)
17
+ */
18
+ readonly cpu: "cat /proc/stat | head -1 | awk '{print ($2+$4)*100/($2+$4+$5)}'";
19
+ /**
20
+ * Memory usage - reads from /proc/meminfo
21
+ * Format: "percent used_gb total_gb"
22
+ * Example: "17.5 0.7 3.7"
23
+ */
24
+ readonly memory: "cat /proc/meminfo | grep -E '^MemTotal|^MemAvailable' | awk '{if(NR==1)t=$2; else a=$2} END {print (t-a)*100/t, (t-a)/1024/1024, t/1024/1024}'";
25
+ /**
26
+ * Disk usage for root partition
27
+ * Format: "percent used_size total_size"
28
+ * Example: "4% 2.8G 75G"
29
+ */
30
+ readonly disk: "df -h / | grep -v '^Filesystem' | awk '{print $5, $3, $2}' | head -1";
31
+ /**
32
+ * GPU usage (if NVIDIA GPU present)
33
+ * Format: "utilization_percent memory_used_mb memory_total_mb" or "NOGPU"
34
+ */
35
+ readonly gpu: "type nvidia-smi 2>/dev/null && nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits | head -1 || echo NOGPU";
36
+ /**
37
+ * Network I/O bytes (total rx/tx since boot)
38
+ * Format: "rx_bytes tx_bytes"
39
+ */
40
+ readonly network: "cat /proc/net/dev | grep -E ': ' | head -1 | awk '{print $2, $10}'";
41
+ /**
42
+ * Load average (1min, 5min, 15min)
43
+ * Format: "1min 5min 15min"
44
+ */
45
+ readonly loadavg: "cut -d' ' -f1-3 /proc/loadavg";
46
+ /**
47
+ * Active process count
48
+ * Format: "count"
49
+ */
50
+ readonly processes: "ls /proc 2>/dev/null | grep -cE '^[0-9]+$'";
51
+ /**
52
+ * Active network connections (established + listening)
53
+ * Format: "count"
54
+ */
55
+ readonly connections: "cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | wc -l";
56
+ /**
57
+ * Active listening ports (hex format)
58
+ * Format: "port1;port2;..." or empty
59
+ */
60
+ readonly ports: "cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -v 'local_address' | awk '{print $2}' | cut -d: -f2 | sort -u | tr '\\n' ';' | sed 's/;$//'";
61
+ };
62
+ export type ResourceCommand = keyof typeof RESOURCE_COMMANDS;
package/dist/scp.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * SCP/SFTP file transfer operations
3
+ * Uses SSH connection pool and SFTP for efficient transfers
4
+ */
5
+ import type { SCPOptions } from "./types.js";
6
+ /**
7
+ * Upload a file to remote server via SFTP
8
+ * @param options - SCP options including source and destination
9
+ * @returns True if successful
10
+ */
11
+ export declare function scpUpload(options: SCPOptions): Promise<boolean>;
12
+ /**
13
+ * Download a file from remote server via SFTP
14
+ * @param options - SCP options including source (remote) and destination (local)
15
+ * @returns True if successful
16
+ */
17
+ export declare function scpDownload(options: SCPOptions): Promise<boolean>;
18
+ /**
19
+ * Upload a directory to remote server via SFTP
20
+ * @param options - SCP options with source directory
21
+ * @returns True if successful
22
+ */
23
+ export declare function scpUploadDirectory(options: SCPOptions): Promise<boolean>;
24
+ /**
25
+ * Download a directory from remote server via SFTP
26
+ * @param options - SCP options with source directory
27
+ * @returns True if successful
28
+ */
29
+ export declare function scpDownloadDirectory(options: SCPOptions): Promise<boolean>;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Terminal Session Management
3
+ * Handles SSH PTY session lifecycle, persistence, and querying
4
+ * Uses tmux for persistent sessions that survive disconnections
5
+ */
6
+ import type { ServerWebSocket, Subprocess } from "bun";
7
+ /**
8
+ * Terminal session interface
9
+ * Represents an active SSH PTY session
10
+ */
11
+ export interface TerminalSession {
12
+ sessionId: string;
13
+ proc: Subprocess<"pipe", "pipe", "pipe">;
14
+ stdin: Subprocess<"pipe", "pipe", "pipe">["stdin"];
15
+ stdout: ReadableStream<Uint8Array>;
16
+ stderr: ReadableStream<Uint8Array>;
17
+ host: string;
18
+ user: string;
19
+ ws: ServerWebSocket<unknown> | null;
20
+ createdAt: number;
21
+ lastUsed: number;
22
+ reader: ReadableStreamDefaultReader<Uint8Array> | null;
23
+ stderrReader: ReadableStreamDefaultReader<Uint8Array> | null;
24
+ writer: WritableStreamDefaultWriter<Uint8Array> | null;
25
+ closed: boolean;
26
+ tmuxSessionName?: string;
27
+ bootstrapLogStreamer?: Subprocess;
28
+ }
29
+ /**
30
+ * Session info for API responses (safe to expose)
31
+ */
32
+ export interface SessionInfo {
33
+ sessionId: string;
34
+ host: string;
35
+ user: string;
36
+ createdAt: number;
37
+ lastUsed: number;
38
+ hasActiveWebSocket: boolean;
39
+ closed: boolean;
40
+ uptime: number;
41
+ idleTime: number;
42
+ }
43
+ /**
44
+ * Clean up old sessions (older than specified milliseconds)
45
+ * Called automatically by interval timer
46
+ */
47
+ export declare function cleanupStaleSessions(maxAge?: number): string[];
48
+ /**
49
+ * Close a specific session
50
+ */
51
+ export declare function closeSession(sessionId: string): Promise<boolean>;
52
+ /**
53
+ * Find or create a session for a host
54
+ * If sessionId is provided, try to reuse that specific session
55
+ * If sessionId is null/undefined, always create a new session (for multiple terminals)
56
+ * @param onProgress - Optional callback to send progress updates to WebSocket
57
+ * @param onBootstrapOutput - Optional callback to stream bootstrap log output to WebSocket
58
+ */
59
+ export declare function getOrCreateSession(host: string, user?: string, sessionId?: string | null, keyPath?: string, onProgress?: (message: string, status: "info" | "success" | "error") => void, environmentId?: string, onBootstrapOutput?: (data: string) => void): Promise<TerminalSession>;
60
+ /**
61
+ * Get a session by ID
62
+ */
63
+ export declare function getSession(sessionId: string): TerminalSession | undefined;
64
+ /**
65
+ * Get all active sessions
66
+ */
67
+ export declare function getAllSessions(): TerminalSession[];
68
+ /**
69
+ * Get session info for all sessions (safe for API responses)
70
+ */
71
+ export declare function getAllSessionInfo(): SessionInfo[];
72
+ /**
73
+ * Get session info for a specific session
74
+ */
75
+ export declare function getSessionInfo(sessionId: string): SessionInfo | undefined;
76
+ /**
77
+ * Get the total number of active sessions
78
+ */
79
+ export declare function getSessionCount(): number;
80
+ /**
81
+ * Find sessions by host
82
+ */
83
+ export declare function getSessionsByHost(host: string): TerminalSession[];
84
+ /**
85
+ * Attach a WebSocket to a session
86
+ * Sets up stdin/stdout/stderr streaming
87
+ */
88
+ export declare function attachWebSocket(session: TerminalSession, ws: ServerWebSocket<unknown>, wasReused?: boolean): void;
89
+ /**
90
+ * Write data to a session's stdin
91
+ */
92
+ export declare function writeToSession(sessionId: string, data: string): Promise<boolean>;
93
+ /**
94
+ * Resize a session's PTY
95
+ */
96
+ export declare function resizeSession(sessionId: string, rows: number, cols: number): Promise<boolean>;
97
+ /**
98
+ * Detach WebSocket from session (without closing session)
99
+ */
100
+ export declare function detachWebSocket(sessionId: string, ws: ServerWebSocket): boolean;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * SSH command execution via tmux
3
+ * Executes commands through persistent tmux sessions instead of creating new SSH connections
4
+ */
5
+ import type { SSHOptions } from "./types.js";
6
+ /**
7
+ * Execute a command via tmux session (simplified approach)
8
+ *
9
+ * DESIGN RATIONALE:
10
+ * ================
11
+ *
12
+ * Current approach: Each API call creates multiple SSH connections
13
+ * - /api/environments/:id/resources: 4 connections (9 commands distributed)
14
+ * - /api/environments/:id/node-agent: 1 connection
15
+ * - Total: 5 SSH connections per page load
16
+ *
17
+ * New approach: Use existing tmux session for all commands
18
+ * - One persistent tmux session per server (already used for terminal WebSocket)
19
+ * - Execute commands via tmux send-keys, capture output
20
+ * - Total: 1 SSH connection per server (for tmux session management)
21
+ *
22
+ * Implementation:
23
+ * - Use existing tmux session's main window
24
+ * - Send command via send-keys
25
+ * - Wait for completion
26
+ * - Capture output with capture-pane
27
+ *
28
+ * Note: This is a simplified implementation that reuses the main tmux window.
29
+ * For production, we should create dedicated windows per command.
30
+ *
31
+ * @param command - Shell command to execute
32
+ * @param options - SSH connection options
33
+ * @param timeout - Command timeout in seconds (default: 10)
34
+ * @returns Command stdout output
35
+ */
36
+ export declare function execViaTmux(command: string, options: SSHOptions, timeout?: number): Promise<string>;
37
+ /**
38
+ * Execute multiple commands in parallel via tmux
39
+ *
40
+ * Note: This creates multiple temporary windows in parallel,
41
+ * each executing one command. This is more efficient than
42
+ * sequential execution but uses more tmux windows temporarily.
43
+ *
44
+ * @param commands - Object mapping names to shell commands
45
+ * @param options - SSH connection options
46
+ * @param timeout - Per-command timeout in seconds (default: 10)
47
+ * @returns Object mapping names to command outputs
48
+ */
49
+ export declare function execViaTmuxParallel(commands: Record<string, string>, options: SSHOptions, timeout?: number): Promise<Record<string, string>>;
@@ -0,0 +1,272 @@
1
+ /**
2
+ * tmux-based Local Terminal Sessions
3
+ * Provides persistent terminal sessions using local tmux for SSH connections
4
+ * SSH connections stay active within tmux sessions on the local machine
5
+ */
6
+ /**
7
+ * Local tmux session configuration
8
+ */
9
+ interface LocalTmuxConfig {
10
+ /** Session name prefix for local MCP SSH sessions */
11
+ sessionPrefix: string;
12
+ /** Default shell to use in tmux */
13
+ defaultShell: string;
14
+ /** Terminal type */
15
+ term: string;
16
+ /** Timeout for local commands (seconds) */
17
+ timeout: number;
18
+ /** Scrollback limit (lines) */
19
+ historyLimit: number;
20
+ /** Session age limit for cleanup (milliseconds) */
21
+ sessionAgeLimit: number;
22
+ }
23
+ /**
24
+ * Options for creating a local tmux SSH session
25
+ */
26
+ export interface LocalTmuxSessionOptions {
27
+ /** Initial command to run after SSH connection */
28
+ initialCommand?: string;
29
+ /** Custom session name (auto-generated if not provided) */
30
+ sessionName?: string;
31
+ /** Window name */
32
+ windowName?: string;
33
+ }
34
+ /**
35
+ * Result of creating a local tmux session
36
+ */
37
+ export interface LocalTmuxSessionResult {
38
+ /** Session name */
39
+ sessionName: string;
40
+ /** Whether the session was newly created */
41
+ newlyCreated: boolean;
42
+ /** Full tmux command used to create the session */
43
+ command: string;
44
+ }
45
+ /**
46
+ * Check if tmux is installed locally
47
+ */
48
+ export declare function isLocalTmuxInstalled(): Promise<boolean>;
49
+ /**
50
+ * Generate a local tmux session name for a host
51
+ * @param host - Remote host IP or hostname
52
+ * @param user - SSH user (default: "root")
53
+ * @returns Session name (e.g., "mcp-ssh-192-168-1-1")
54
+ */
55
+ export declare function generateLocalSessionName(host: string, user?: string): string;
56
+ /**
57
+ * List all local tmux sessions
58
+ * @returns Array of session names
59
+ */
60
+ export declare function listLocalSessions(): Promise<string[]>;
61
+ /**
62
+ * Check if a specific local tmux session exists
63
+ * @param sessionName - Session name to check
64
+ * @returns True if session exists
65
+ */
66
+ export declare function hasLocalSession(sessionName: string): Promise<boolean>;
67
+ /**
68
+ * Create a local tmux session with an active SSH connection
69
+ *
70
+ * This function creates a tmux session on the local machine that maintains
71
+ * an active SSH connection to the remote host. The connection stays alive
72
+ * within the tmux session, allowing for persistent interactions.
73
+ *
74
+ * @param host - Remote host IP or hostname
75
+ * @param user - SSH user (default: "root")
76
+ * @param keyPath - Path to SSH private key (for key-based auth)
77
+ * @param password - SSH password (for password-based auth)
78
+ * @param options - Additional options for session creation
79
+ * @returns Session creation result
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * // Key-based authentication
84
+ * const result = await createLocalTmuxSSHSession(
85
+ * "192.168.1.100",
86
+ * "root",
87
+ * "/path/to/key"
88
+ * );
89
+ *
90
+ * // Password-based authentication (requires sshpass)
91
+ * const result = await createLocalTmuxSSHSession(
92
+ * "192.168.1.100",
93
+ * "root",
94
+ * undefined,
95
+ * "mypassword"
96
+ * );
97
+ * ```
98
+ */
99
+ export declare function createLocalTmuxSSHSession(host: string, user?: string, keyPath?: string, password?: string, options?: LocalTmuxSessionOptions): Promise<LocalTmuxSessionResult>;
100
+ /**
101
+ * Send a command to a local tmux pane (already SSH'd into the remote host)
102
+ *
103
+ * This function sends a command to the tmux pane, which will be executed
104
+ * on the remote host since the SSH connection is already active.
105
+ *
106
+ * @param sessionName - Local tmux session name
107
+ * @param command - Command to send to the remote host
108
+ * @param paneIndex - Pane index (default: "0")
109
+ * @param windowName - Window name (default: auto-detects first window)
110
+ * @returns True if command was sent successfully
111
+ */
112
+ export declare function sendCommandToLocalSession(sessionName: string, command: string, paneIndex?: string, windowName?: string): Promise<boolean>;
113
+ /**
114
+ * Capture output from a local tmux pane
115
+ *
116
+ * This captures the current visible content of the pane, including
117
+ * the scrollback history.
118
+ *
119
+ * @param sessionName - Local tmux session name
120
+ * @param paneIndex - Pane index (default: "0")
121
+ * @param windowName - Window name (default: auto-detects first window)
122
+ * @returns Captured output or null if failed
123
+ */
124
+ export declare function captureLocalPane(sessionName: string, paneIndex?: string, windowName?: string): Promise<string | null>;
125
+ /**
126
+ * Get scrollback/history from a local tmux pane
127
+ *
128
+ * @param sessionName - Local tmux session name
129
+ * @param paneIndex - Pane index (default: "0")
130
+ * @param lines - Number of lines to retrieve (default: -1 for all)
131
+ * @param windowName - Window name (default: auto-detects first window)
132
+ * @returns History content or null if failed
133
+ */
134
+ export declare function getLocalPaneHistory(sessionName: string, paneIndex?: string, lines?: number, windowName?: string): Promise<string | null>;
135
+ /**
136
+ * Kill a local tmux session
137
+ *
138
+ * @param sessionName - Session name to kill
139
+ * @returns True if session was killed successfully
140
+ */
141
+ export declare function killLocalSession(sessionName: string): Promise<boolean>;
142
+ /**
143
+ * Get information about a local tmux session
144
+ *
145
+ * @param sessionName - Session name to query
146
+ * @returns Session information or null if session doesn't exist
147
+ */
148
+ export declare function getLocalSessionInfo(sessionName: string): Promise<{
149
+ exists: boolean;
150
+ windows?: number;
151
+ panes?: number;
152
+ } | null>;
153
+ /**
154
+ * List all windows in a local tmux session
155
+ *
156
+ * @param sessionName - Local tmux session name
157
+ * @returns Array of window information
158
+ */
159
+ export declare function listLocalSessionWindows(sessionName: string): Promise<Array<{
160
+ index: string;
161
+ name: string;
162
+ active: boolean;
163
+ }>>;
164
+ /**
165
+ * List all panes in a local tmux session window
166
+ *
167
+ * @param sessionName - Local tmux session name
168
+ * @param windowIndex - Window index (default: "0")
169
+ * @returns Array of pane information
170
+ */
171
+ export declare function listLocalWindowPanes(sessionName: string, windowIndex?: string): Promise<Array<{
172
+ index: string;
173
+ currentPath: string;
174
+ pid: string;
175
+ active: boolean;
176
+ }>>;
177
+ /**
178
+ * Split a pane horizontally or vertically in a local tmux session
179
+ *
180
+ * @param sessionName - Local tmux session name
181
+ * @param direction - Split direction: "h" (horizontal) or "v" (vertical)
182
+ * @param command - Optional command to run in the new pane
183
+ * @param windowName - Window name (default: auto-detects first window)
184
+ * @returns The new pane index or null if failed
185
+ */
186
+ export declare function splitLocalPane(sessionName: string, direction?: "h" | "v", command?: string, windowName?: string): Promise<string | null>;
187
+ /**
188
+ * Cleanup old local tmux sessions
189
+ *
190
+ * @param config - Optional configuration (uses default age limit if not provided)
191
+ * @returns Object with cleaned count and errors
192
+ */
193
+ export declare function cleanupOldLocalSessions(config?: Partial<LocalTmuxConfig>): Promise<{
194
+ cleaned: number;
195
+ errors: string[];
196
+ }>;
197
+ /**
198
+ * Get resource usage information for local tmux sessions
199
+ *
200
+ * @returns Resource usage summary
201
+ */
202
+ export declare function getLocalTmuxResourceUsage(): Promise<{
203
+ totalSessions: number;
204
+ mcpSessions: number;
205
+ estimatedMemoryMB: number;
206
+ } | null>;
207
+ /**
208
+ * Wait for a specific text to appear in the pane output
209
+ *
210
+ * @param sessionName - Local tmux session name
211
+ * @param text - Text to wait for
212
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 30000)
213
+ * @param paneIndex - Pane index (default: "0")
214
+ * @param windowName - Window name (default: auto-detects first window)
215
+ * @returns True if text appeared, false if timeout
216
+ */
217
+ export declare function waitForTextInPane(sessionName: string, text: string, timeoutMs?: number, paneIndex?: string, windowName?: string): Promise<boolean>;
218
+ /**
219
+ * Switch to a specific window in a local tmux session
220
+ *
221
+ * @param sessionName - Local tmux session name
222
+ * @param windowIndex - Target window index
223
+ * @returns True if successful
224
+ */
225
+ export declare function switchLocalWindow(sessionName: string, windowIndex: string): Promise<boolean>;
226
+ /**
227
+ * Switch to a specific pane in a local tmux session window
228
+ *
229
+ * @param sessionName - Local tmux session name
230
+ * @param paneIndex - Target pane index (e.g., "0", "1", "0.1" for window.pane)
231
+ * @returns True if successful
232
+ */
233
+ export declare function switchLocalPane(sessionName: string, paneIndex: string): Promise<boolean>;
234
+ /**
235
+ * Rename a window in a local tmux session
236
+ *
237
+ * @param sessionName - Local tmux session name
238
+ * @param windowIndex - Window index (default: "0")
239
+ * @param newName - New window name
240
+ * @returns True if successful
241
+ */
242
+ export declare function renameLocalWindow(sessionName: string, windowIndex: string, newName: string): Promise<boolean>;
243
+ /**
244
+ * Kill a specific pane in a local tmux session
245
+ *
246
+ * @param sessionName - Local tmux session name
247
+ * @param paneIndex - Pane index to kill
248
+ * @param windowName - Window name (default: auto-detects first window)
249
+ * @returns True if successful
250
+ */
251
+ export declare function killLocalPane(sessionName: string, paneIndex: string, windowName?: string): Promise<boolean>;
252
+ /**
253
+ * Get detailed information about all panes in a local session
254
+ *
255
+ * @param sessionName - Local tmux session name
256
+ * @returns Detailed session information or null
257
+ */
258
+ export declare function getDetailedLocalSessionInfo(sessionName: string): Promise<{
259
+ exists: boolean;
260
+ windows: Array<{
261
+ index: string;
262
+ name: string;
263
+ active: boolean;
264
+ panes: Array<{
265
+ index: string;
266
+ currentPath: string;
267
+ pid: string;
268
+ active: boolean;
269
+ }>;
270
+ }>;
271
+ } | null>;
272
+ export {};