@ebowwa/terminal 0.3.4 → 0.3.5

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/api.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * API routes for Multi-Node Tmux Session Manager
3
+ * Provides REST API for managing tmux sessions across multiple VPS nodes
4
+ */
5
+ import { Hono } from "hono";
6
+ declare const tmuxApi: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
7
+ export { tmuxApi };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Core SSH client for executing commands on remote servers
3
+ * Uses persistent connection pool for efficient reuse
4
+ * Uses base64 encoding to avoid shell escaping issues
5
+ */
6
+ import type { SSHOptions } from "./types.js";
7
+ /**
8
+ * Execute a command on a remote server via SSH
9
+ * Uses persistent connection pool for better performance
10
+ * @param command - Shell command to execute
11
+ * @param options - SSH connection options
12
+ * @returns Command output as string
13
+ */
14
+ export declare function execSSH(command: string, options: SSHOptions): Promise<string>;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * SSH Config Manager
3
+ *
4
+ * Manages ~/.ssh/config entries for easy node access.
5
+ * When a node is created, adds an alias so you can:
6
+ * ssh node-<id> or ssh <name>
7
+ * Instead of:
8
+ * ssh -i ~/.../key -o StrictHostKeyChecking=no root@167.235.236.8
9
+ */
10
+ export interface SSHConfigEntry {
11
+ id: string;
12
+ name: string;
13
+ host: string;
14
+ user?: string;
15
+ keyPath: string;
16
+ port?: number;
17
+ }
18
+ /**
19
+ * Add or update an SSH config entry for a node
20
+ */
21
+ export declare function addSSHConfigEntry(entry: SSHConfigEntry): void;
22
+ /**
23
+ * Remove an SSH config entry for a node
24
+ */
25
+ export declare function removeSSHConfigEntry(id: string): void;
26
+ /**
27
+ * Update IP address for an existing node (e.g., after rebuild)
28
+ */
29
+ export declare function updateSSHConfigHost(id: string, newHost: string): void;
30
+ /**
31
+ * List all managed SSH config entries
32
+ */
33
+ export declare function listSSHConfigEntries(): SSHConfigEntry[];
34
+ /**
35
+ * Validate SSH connection works with the configured key
36
+ * Returns true if connection succeeds, throws on failure with diagnostic info
37
+ */
38
+ export declare function validateSSHConnection(host: string, keyPath: string, user?: string, timeoutSeconds?: number): Promise<{
39
+ success: boolean;
40
+ error?: string;
41
+ diagnostics?: string;
42
+ }>;
43
+ /**
44
+ * Ensure SSH key is loaded correctly and agent doesn't interfere
45
+ * Clears wrong keys from agent and adds the correct one
46
+ */
47
+ export declare function ensureCorrectSSHKey(keyPath: string): Promise<void>;
48
+ /**
49
+ * Wait for SSH to become ready on a new server
50
+ * Polls until connection succeeds or timeout
51
+ */
52
+ export declare function waitForSSHReady(host: string, keyPath: string, options?: {
53
+ user?: string;
54
+ maxAttempts?: number;
55
+ intervalMs?: number;
56
+ onAttempt?: (attempt: number, maxAttempts: number) => void;
57
+ }): Promise<{
58
+ success: boolean;
59
+ attempts: number;
60
+ error?: string;
61
+ }>;
62
+ /**
63
+ * Sync result for a single node
64
+ */
65
+ export interface SyncResult {
66
+ id: string;
67
+ name: string;
68
+ ip: string;
69
+ status: "added" | "updated" | "skipped" | "error";
70
+ error?: string;
71
+ sshReady?: boolean;
72
+ }
73
+ /**
74
+ * Sync all existing Hetzner nodes to SSH config
75
+ * Call this to add aliases for nodes created before this feature
76
+ */
77
+ export declare function syncNodesToSSHConfig(nodes: Array<{
78
+ id: string;
79
+ name: string;
80
+ ip: string;
81
+ keyPath: string;
82
+ }>, options?: {
83
+ validateSSH?: boolean;
84
+ onProgress?: (result: SyncResult) => void;
85
+ }): Promise<SyncResult[]>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * SSH error class
3
+ */
4
+ export declare class SSHError extends Error {
5
+ readonly cause?: unknown;
6
+ constructor(message: string, cause?: unknown);
7
+ }
package/dist/exec.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * SSH command execution functions
3
+ */
4
+ import type { SSHOptions } from "./types.js";
5
+ /**
6
+ * Execute multiple SSH commands in parallel using multiple connections
7
+ *
8
+ * DESIGN DECISION: Multiple Connections vs Single Connection
9
+ * ===========================================================
10
+ *
11
+ * We use MULTIPLE SSH connections to avoid channel saturation issues.
12
+ * SSH servers typically limit concurrent channels per connection (~10).
13
+ * When executing 9+ commands in parallel, we can exceed this limit.
14
+ *
15
+ * Solution: Distribute commands across multiple pooled connections.
16
+ * Each connection handles a subset of commands, staying within channel limits.
17
+ *
18
+ * DESIGN DECISION: Promise.allSettled() vs Promise.all()
19
+ * ======================================================
20
+ *
21
+ * We use Promise.allSettled() instead of Promise.all() for a critical reason:
22
+ * Resource monitoring should be RESILIENT. If one command fails (e.g., GPU
23
+ * query on a CPU-only server), we still want results from all other commands.
24
+ *
25
+ * Example scenario:
26
+ * - CPU, memory, disk commands: succeed
27
+ * - GPU command: fails (no NVIDIA GPU)
28
+ * - Network command: succeeds
29
+ *
30
+ * With Promise.all(): entire batch fails, no metrics collected
31
+ * With Promise.allSettled(): we get 6/7 metrics, GPU returns "0" fallback
32
+ *
33
+ * ERROR HANDLING:
34
+ * ==============
35
+ * 1. Individual command failures are logged to console
36
+ * 2. Failed commands return "0" as fallback (matches execSSH default)
37
+ * 3. The function always completes successfully (never throws)
38
+ * 4. Calling code can check for "0" values to detect failures
39
+ */
40
+ export declare function execSSHParallel(commands: Record<string, string>, options: SSHOptions): Promise<Record<string, string>>;
41
+ /**
42
+ * Test SSH connection to a remote server
43
+ * @param options - SSH connection options
44
+ * @returns True if connection successful
45
+ */
46
+ export declare function testSSHConnection(options: SSHOptions): Promise<boolean>;
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Remote file operations via SSH
3
+ */
4
+ import type { SSHOptions } from "./types.js";
5
+ import { SSHError } from "./error.js";
6
+ /**
7
+ * Path sanitization options
8
+ */
9
+ export interface SanitizePathOptions {
10
+ /**
11
+ * Allowed base directories (absolute paths)
12
+ * Default: ["/root"] for root user
13
+ */
14
+ allowedBaseDirs?: string[];
15
+ /**
16
+ * User context for determining default base directory
17
+ */
18
+ user?: string;
19
+ /**
20
+ * Whether to allow absolute paths
21
+ * Default: false (security best practice)
22
+ */
23
+ allowAbsolutePaths?: boolean;
24
+ /**
25
+ * Maximum path depth to prevent deep traversal attempts
26
+ * Default: 20
27
+ */
28
+ maxDepth?: number;
29
+ /**
30
+ * Log suspicious path attempts
31
+ * Default: true
32
+ */
33
+ logSuspicious?: boolean;
34
+ }
35
+ /**
36
+ * Path traversal security error
37
+ */
38
+ export declare class PathTraversalError extends SSHError {
39
+ readonly attemptedPath: string;
40
+ readonly reason: string;
41
+ constructor(message: string, attemptedPath: string, reason: string);
42
+ }
43
+ /**
44
+ * Security event log for path traversal attempts
45
+ */
46
+ interface SecurityEvent {
47
+ timestamp: string;
48
+ attemptedPath: string;
49
+ reason: string;
50
+ severity: "blocked" | "suspicious" | "warning";
51
+ }
52
+ /**
53
+ * Get recent security events for monitoring
54
+ */
55
+ export declare function getSecurityEvents(limit?: number): SecurityEvent[];
56
+ /**
57
+ * Clear old security events (for maintenance)
58
+ */
59
+ export declare function clearSecurityEvents(olderThanMs?: number): number;
60
+ /**
61
+ * Sanitize and validate a file path for security
62
+ *
63
+ * This function prevents path traversal attacks by:
64
+ * 1. Rejecting paths with .. components
65
+ * 2. Validating against allowed base directories
66
+ * 3. Normalizing paths to remove . and redundant /
67
+ * 4. Checking for null bytes and other escape sequences
68
+ * 5. Limiting path depth to prevent deep traversal
69
+ *
70
+ * @param inputPath - The user-provided path to sanitize
71
+ * @param options - Sanitization options
72
+ * @returns Sanitized absolute path
73
+ * @throws PathTraversalError if path is suspicious or invalid
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * // Safe: within /root
78
+ * sanitizePath("project/file.txt", { user: "root" })
79
+ * // Returns: "/root/project/file.txt"
80
+ *
81
+ * // BLOCKED: attempts to escape
82
+ * sanitizePath("../../../etc/passwd", { user: "root" })
83
+ * // Throws: PathTraversalError
84
+ *
85
+ * // BLOCKED: null byte injection
86
+ * sanitizePath("file.txt\0../../../etc/passwd", { user: "root" })
87
+ * // Throws: PathTraversalError
88
+ * ```
89
+ */
90
+ export declare function sanitizePath(inputPath: string, options?: SanitizePathOptions): string;
91
+ export type FileType = "file" | "directory";
92
+ export interface RemoteFile {
93
+ name: string;
94
+ path: string;
95
+ size: string;
96
+ modified: string;
97
+ type: FileType;
98
+ }
99
+ export type PreviewType = "text" | "image" | "binary" | "error";
100
+ export interface FilePreview {
101
+ type: PreviewType;
102
+ content?: string;
103
+ error?: string;
104
+ }
105
+ /**
106
+ * List files in a directory on remote server
107
+ * @param path - Directory path to list (default: .)
108
+ * @param options - SSH connection options
109
+ * @returns List of files with metadata
110
+ * @throws PathTraversalError if path attempts to escape allowed directories
111
+ * @throws SSHError if SSH command fails
112
+ */
113
+ export declare function listFiles(path: string, options: SSHOptions): Promise<RemoteFile[]>;
114
+ /**
115
+ * Preview a file's content from remote server
116
+ * @param filePath - Path to the file to preview
117
+ * @param options - SSH connection options
118
+ * @returns File content for preview
119
+ * @throws PathTraversalError if path attempts to escape allowed directories
120
+ * @throws SSHError if SSH command fails
121
+ */
122
+ export declare function previewFile(filePath: string, options: SSHOptions): Promise<FilePreview>;
123
+ export {};
@@ -0,0 +1,66 @@
1
+ /**
2
+ * SSH fingerprint utilities with validation and recovery
3
+ */
4
+ import type { SSHOptions } from "./types.js";
5
+ /**
6
+ * Get SSH fingerprint from remote server
7
+ * @param options - SSH connection options
8
+ * @returns SSH fingerprint or null
9
+ */
10
+ export declare function getSSHFingerprint(options: SSHOptions): Promise<string | null>;
11
+ /**
12
+ * Get SSH fingerprint from a local private key file
13
+ * @param keyPath - Path to the private key file
14
+ * @returns SSH fingerprint (SHA256 format) or null
15
+ */
16
+ export declare function getLocalKeyFingerprint(keyPath: string): Promise<string | null>;
17
+ /**
18
+ * Convert MD5 fingerprint format to SHA256 format (for comparison)
19
+ * Hetzner returns MD5 like "29:cd:c1:c3:84:eb:ca:31:a4:1f:94:69:0c:84:b3:56"
20
+ * We need to handle both formats
21
+ */
22
+ export declare function normalizeFingerprint(fingerprint: string): string;
23
+ /**
24
+ * Validate that a local SSH key matches what's on a remote server
25
+ * @param host - Server hostname or IP
26
+ * @param keyPath - Path to local private key
27
+ * @returns Validation result
28
+ */
29
+ export declare function validateSSHKeyMatch(host: string, keyPath: string): Promise<{
30
+ valid: boolean;
31
+ localFingerprint?: string;
32
+ remoteFingerprint?: string;
33
+ error?: string;
34
+ }>;
35
+ /**
36
+ * Check if we can SSH to a server with a given key
37
+ * @param host - Server hostname or IP
38
+ * @param keyPath - Path to SSH private key
39
+ * @returns true if SSH works
40
+ */
41
+ export declare function testSSHKeyConnection(host: string, keyPath: string): Promise<boolean>;
42
+ /**
43
+ * SSH Key Mismatch Error with recovery suggestions
44
+ */
45
+ export declare class SSHKeyMismatchError extends Error {
46
+ host: string;
47
+ localFingerprint: string;
48
+ hetznerFingerprint: string;
49
+ keyPath: string;
50
+ constructor(host: string, localFingerprint: string, hetznerFingerprint: string, keyPath: string);
51
+ }
52
+ /**
53
+ * Comprehensive SSH key validation for server creation
54
+ * @param host - Server hostname or IP
55
+ * @param keyPath - Path to local SSH key
56
+ * @param hetznerKeyId - SSH key ID on Hetzner (for comparison)
57
+ * @returns Validation result with recovery suggestions
58
+ */
59
+ export declare function validateSSHKeyForServer(host: string, keyPath: string, hetznerKeyId?: string): Promise<{
60
+ canConnect: boolean;
61
+ fingerprintMatch: boolean;
62
+ localFingerprint?: string;
63
+ remoteFingerprint?: string;
64
+ error?: string;
65
+ recovery?: string[];
66
+ }>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * SSH utility library - modular entry point
3
+ */
4
+ export { TmuxSessionManager, getTmuxManager, resetTmuxManager, type Node, type TmuxSession, type DetailedTmuxSession, type BatchOperationResult, type CreateSessionOptions, type BatchCommandOptions, type SessionQueryOptions, } from "./tmux-manager.js";
5
+ export type { SSHOptions, SCPOptions } from "./types.js";
6
+ export { SSHError } from "./error.js";
7
+ export { execSSH } from "./client.js";
8
+ export { execSSHParallel, testSSHConnection } from "./exec.js";
9
+ export { execViaTmux, execViaTmuxParallel } from "./tmux-exec.js";
10
+ export { scpUpload, scpDownload } from "./scp.js";
11
+ export { listFiles, previewFile, sanitizePath, PathTraversalError, getSecurityEvents, clearSecurityEvents, type FileType, type RemoteFile, type PreviewType, type FilePreview, type SanitizePathOptions, } from "./files.js";
12
+ export { getSSHFingerprint, getLocalKeyFingerprint, normalizeFingerprint, validateSSHKeyMatch, testSSHKeyConnection, validateSSHKeyForServer, SSHKeyMismatchError } from "./fingerprint.js";
13
+ export { createPTYSession, writeToPTY, setPTYSize, readFromPTY, closePTYSession, getPTYSession, getActivePTYSessions, } from "./pty.js";
14
+ export { getSSHPool, closeGlobalSSHPool, getActiveSSHConnections, SSHConnectionPool, } from "./pool.js";
15
+ export { closeSession, cleanupStaleSessions, getOrCreateSession, getSession, getAllSessions, getAllSessionInfo, getSessionInfo, getSessionCount, getSessionsByHost, attachWebSocket, writeToSession, resizeSession, detachWebSocket, } from "./sessions.js";
16
+ export type { TerminalSession, SessionInfo } from "./sessions.js";
17
+ export { generateSessionName, isTmuxInstalled, installTmux, ensureTmux, listTmuxSessions, hasTmuxSession, createOrAttachTmuxSession, killTmuxSession, getTmuxSessionInfo, cleanupOldTmuxSessions, getTmuxResourceUsage, sendCommandToPane, splitPane, listSessionWindows, listWindowPanes, capturePane, getPaneHistory, switchWindow, switchPane, renameWindow, killPane, getDetailedSessionInfo, } from "./tmux.js";
18
+ export { generateLocalSessionName, isLocalTmuxInstalled, listLocalSessions, hasLocalSession, createLocalTmuxSSHSession, sendCommandToLocalSession, captureLocalPane, getLocalPaneHistory, killLocalSession, getLocalSessionInfo, listLocalSessionWindows, listLocalWindowPanes, splitLocalPane, cleanupOldLocalSessions, getLocalTmuxResourceUsage, waitForTextInPane, switchLocalWindow, switchLocalPane, renameLocalWindow, killLocalPane, getDetailedLocalSessionInfo, type LocalTmuxSessionOptions, type LocalTmuxSessionResult, } from "./tmux-local.js";
19
+ export { RESOURCE_COMMANDS } from "./resources.js";
20
+ export type { ResourceCommand } from "./resources.js";
21
+ export { detectNetworkError, formatNetworkError, type NetworkErrorDetails, } from "./network-error-detector.js";
@@ -0,0 +1,102 @@
1
+ /**
2
+ * SSH Key Manager - Single Source of Truth
3
+ *
4
+ * Consolidates SSH key creation, upload, and management for Hetzner.
5
+ * Replaces duplicate ensureSSHKey() functions in api.ts and crud.ts.
6
+ *
7
+ * FEATURES:
8
+ * - Create or reuse local SSH key pairs
9
+ * - Upload public key to Hetzner if not exists
10
+ * - Handle fingerprint format conversion (SHA256 <-> MD5)
11
+ * - Provide consistent API for all SSH key operations
12
+ * - OS-specific user data directory for portable key storage
13
+ *
14
+ * ENVIRONMENT VARIABLES:
15
+ * - HETZNER_SSH_KEYS_DIR: Override default SSH keys directory
16
+ */
17
+ import type { HetznerClient } from "../lib/hetzner/client";
18
+ declare module "bun" {
19
+ interface Env {
20
+ HETZNER_SSH_KEYS_DIR?: string;
21
+ }
22
+ }
23
+ /**
24
+ * Get OS-specific user data directory for SSH keys
25
+ * - macOS: ~/Library/Application Support/com.hetzner.codespaces/ssh-keys/
26
+ * - Linux: ~/.config/com.hetzner.codespaces/ssh-keys/
27
+ * - Windows: %APPDATA%\com.hetzner.codespaces\ssh-keys\
28
+ *
29
+ * Can be overridden via .env file:
30
+ * HETZNER_SSH_KEYS_DIR=/custom/path
31
+ */
32
+ export declare function getDefaultKeysDir(): string;
33
+ /**
34
+ * SSH Key information returned by the manager
35
+ */
36
+ export interface SSHKeyInfo {
37
+ keyId: number;
38
+ keyPath: string;
39
+ fingerprint: string;
40
+ name: string;
41
+ }
42
+ /**
43
+ * Configuration for SSH key manager
44
+ */
45
+ export interface SSHKeyManagerConfig {
46
+ keyName?: string;
47
+ keysDir?: string;
48
+ }
49
+ /**
50
+ * Fingerprint format types
51
+ */
52
+ export type FingerprintFormat = "md5" | "sha256";
53
+ /**
54
+ * Convert SSH key fingerprint between formats
55
+ * Hetzner uses MD5 with colons, modern tools use SHA256
56
+ */
57
+ export declare function convertFingerprintFormat(publicKeyPath: string, format: FingerprintFormat): Promise<string>;
58
+ /**
59
+ * SSH Key Manager - Main class for managing SSH keys
60
+ */
61
+ export declare class SSHKeyManager {
62
+ private keyName;
63
+ private keysDir;
64
+ constructor(config?: SSHKeyManagerConfig);
65
+ /**
66
+ * Get the absolute path to the SSH keys directory
67
+ */
68
+ private getKeysDirPath;
69
+ /**
70
+ * Get the full path to the SSH key files (absolute path)
71
+ */
72
+ private getKeyPath;
73
+ /**
74
+ * Ensure SSH key exists locally and on Hetzner
75
+ * This is the main entry point - replaces duplicate ensureSSHKey() functions
76
+ *
77
+ * @param hetznerClient - Hetzner API client
78
+ * @returns SSH key information for server creation
79
+ */
80
+ ensureSSHKey(hetznerClient: HetznerClient): Promise<SSHKeyInfo>;
81
+ /**
82
+ * Get local key fingerprint in SHA256 format
83
+ */
84
+ getLocalFingerprint(): Promise<string | null>;
85
+ /**
86
+ * Get local key fingerprint in MD5 format (for Hetzner comparison)
87
+ */
88
+ getHetznerFingerprint(): Promise<string>;
89
+ /**
90
+ * Get the key path
91
+ */
92
+ getKeyPathValue(): string;
93
+ }
94
+ /**
95
+ * Convenience function - creates default manager and ensures SSH key
96
+ * This is a drop-in replacement for the old ensureSSHKey() functions
97
+ *
98
+ * @param hetznerClient - Hetzner API client
99
+ * @param config - Optional configuration
100
+ * @returns SSH key information
101
+ */
102
+ export declare function ensureSSHKey(hetznerClient: HetznerClient, config?: SSHKeyManagerConfig): Promise<SSHKeyInfo>;
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Terminal MCP Server
4
+ *
5
+ * Exposes terminal session management via Model Context Protocol
6
+ * Integrates with tmux, SSH, PTY, and file operations
7
+ */
8
+ export {};
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Terminal MCP Server (stdio protocol)
4
+ *
5
+ * Model Context Protocol server for terminal session management
6
+ * Uses stdio transport for Claude Code integration
7
+ */
8
+ export {};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Network Error Detection
3
+ * Detects and provides helpful messages for common network issues
4
+ */
5
+ export interface NetworkErrorDetails {
6
+ type: "SERVER_NOT_READY" | "NETWORK_BLOCKED" | "AUTH_FAILED" | "UNKNOWN";
7
+ message: string;
8
+ troubleshooting: string[];
9
+ isLikelyNetworkBlock: boolean;
10
+ }
11
+ /**
12
+ * Analyzes SSH connection error and provides detailed diagnosis
13
+ */
14
+ export declare function detectNetworkError(error: Error | string, host: string, serverStatus?: string): NetworkErrorDetails;
15
+ /**
16
+ * Format network error for WebSocket/UI display
17
+ */
18
+ export declare function formatNetworkError(diagnosis: NetworkErrorDetails): string;
package/dist/pool.d.ts ADDED
@@ -0,0 +1,142 @@
1
+ /**
2
+ * SSH Connection Pool Manager
3
+ * Maintains persistent SSH connections for reuse across commands
4
+ */
5
+ import { NodeSSH } from 'node-ssh';
6
+ import type { SSHOptions } from './types.js';
7
+ /**
8
+ * Connection pool configuration
9
+ */
10
+ interface PoolConfig {
11
+ /** Maximum number of connections to keep alive across all hosts */
12
+ maxConnections: number;
13
+ /** Maximum number of connections per host (for parallel execution) */
14
+ maxConnectionsPerHost: number;
15
+ /** Idle timeout in milliseconds (default: 5 minutes) */
16
+ idleTimeout: number;
17
+ /** Connection timeout in milliseconds (default: 10 seconds) */
18
+ connectionTimeout: number;
19
+ /** Keep alive interval in milliseconds (default: 30 seconds) */
20
+ keepAliveInterval: number;
21
+ }
22
+ /**
23
+ * SSH Connection Pool Class
24
+ */
25
+ export declare class SSHConnectionPool {
26
+ private connections;
27
+ private config;
28
+ private cleanupInterval;
29
+ private nextId;
30
+ constructor(config?: Partial<PoolConfig>);
31
+ /**
32
+ * Generate a unique key for the connection (host-based)
33
+ */
34
+ private getKey;
35
+ /**
36
+ * Get all connections for a given host
37
+ */
38
+ private getConnectionsList;
39
+ /**
40
+ * Get or create a connection (returns least recently used connection)
41
+ */
42
+ getConnection(options: SSHOptions): Promise<NodeSSH>;
43
+ /**
44
+ * Get or create a connection using password authentication
45
+ */
46
+ getConnectionWithPassword(host: string, user: string, password: string, port?: number): Promise<NodeSSH>;
47
+ /**
48
+ * Get or create multiple connections for parallel execution
49
+ * @param options - SSH connection options
50
+ * @param count - Number of connections to retrieve
51
+ * @returns Array of SSH connections
52
+ */
53
+ getConnections(options: SSHOptions, count: number): Promise<NodeSSH[]>;
54
+ /**
55
+ * Create a new SSH connection
56
+ * Tries key-based auth first, then password auth, then SSH agent
57
+ */
58
+ private createConnection;
59
+ /**
60
+ * Get total number of connections across all hosts
61
+ */
62
+ private getTotalConnectionCount;
63
+ /**
64
+ * Execute a command using a pooled connection
65
+ *
66
+ * ERROR HANDLING BEHAVIOR:
67
+ * =========================
68
+ * If result.stderr exists AND result.stdout is empty, we throw an error.
69
+ * This is intentional - commands that fail should return fallback values
70
+ * via shell redirection (e.g., `|| echo "0"` or `2>/dev/null`).
71
+ *
72
+ * Example of proper fallback handling:
73
+ * `type nvidia-smi 2>/dev/null && nvidia-smi ... || echo NOGPU`
74
+ *
75
+ * This ensures commands don't silently fail - they must handle their own
76
+ * error cases and return sensible defaults.
77
+ */
78
+ exec(command: string, options: SSHOptions): Promise<string>;
79
+ /**
80
+ * Check if a connection exists and is alive for a given host
81
+ */
82
+ hasConnection(options: SSHOptions): Promise<boolean>;
83
+ /**
84
+ * Close a specific connection by SSH instance
85
+ */
86
+ private closeConnectionInstance;
87
+ /**
88
+ * Close all connections for a specific host
89
+ */
90
+ closeConnection(options: SSHOptions): Promise<void>;
91
+ /**
92
+ * Evict the oldest connection from the pool
93
+ */
94
+ private evictOldest;
95
+ /**
96
+ * Clean up idle connections
97
+ */
98
+ private cleanupIdle;
99
+ /**
100
+ * Start periodic cleanup
101
+ */
102
+ private startCleanup;
103
+ /**
104
+ * Stop cleanup interval
105
+ */
106
+ private stopCleanup;
107
+ /**
108
+ * Close all connections and stop cleanup
109
+ */
110
+ closeAll(): Promise<void>;
111
+ /**
112
+ * Get pool statistics
113
+ */
114
+ getStats(): {
115
+ totalConnections: number;
116
+ connections: Array<{
117
+ host: string;
118
+ port: number;
119
+ user: string;
120
+ lastUsed: Date;
121
+ idleMs: number;
122
+ id: string;
123
+ }>;
124
+ };
125
+ /**
126
+ * Check if a host has an active connection
127
+ */
128
+ isConnected(host: string, user?: string, port?: number): boolean;
129
+ }
130
+ /**
131
+ * Get the global connection pool instance
132
+ */
133
+ export declare function getSSHPool(config?: Partial<PoolConfig>): SSHConnectionPool;
134
+ /**
135
+ * Close the global pool (for cleanup/shutdown)
136
+ */
137
+ export declare function closeGlobalSSHPool(): Promise<void>;
138
+ /**
139
+ * Get active SSH connections (for monitoring)
140
+ */
141
+ export declare function getActiveSSHConnections(): ReturnType<SSHConnectionPool['getStats']>;
142
+ export {};