MCPcopy
hub / github.com/claude-code-best/claude-code / SSHSessionManagerImpl

Class SSHSessionManagerImpl

src/ssh/SSHSessionManager.ts:59–353  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

57const DEFAULT_MAX_RECONNECT_ATTEMPTS = 3
58
59export class SSHSessionManagerImpl implements SSHSessionManager {
60 private proc: Subprocess
61 private options: SSHSessionManagerOptions
62 private connected = false
63 private disconnected = false
64 private readLoopAbort: AbortController | null = null
65 private reconnectAttempt = 0
66 private readonly maxReconnectAttempts: number
67 private userInitiatedDisconnect = false
68 private reconnecting = false
69
70 constructor(proc: Subprocess, options: SSHSessionManagerOptions) {
71 this.proc = proc
72 this.options = options
73 this.maxReconnectAttempts =
74 options.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS
75 }
76
77 connect(): void {
78 if (this.connected) return
79
80 this.readLoopAbort = new AbortController()
81 this.startReadLoop()
82 this.monitorExit()
83
84 this.connected = true
85 this.options.onConnected()
86 }
87
88 private async startReadLoop(): Promise<void> {
89 const stdout = this.proc.stdout
90 if (!stdout) {
91 this.options.onError(new Error('SSH process stdout is not available'))
92 return
93 }
94
95 const reader = (stdout as ReadableStream<Uint8Array>).getReader()
96 const decoder = new TextDecoder()
97 let lineBuffer = ''
98
99 try {
100 while (!this.disconnected) {
101 const { done, value } = await reader.read()
102 if (done) break
103
104 lineBuffer += decoder.decode(value, { stream: true })
105 const lines = lineBuffer.split('\n')
106 lineBuffer = lines.pop() ?? ''
107
108 for (const line of lines) {
109 const trimmed = line.trim()
110 if (!trimmed) continue
111 this.processLine(trimmed)
112 }
113 }
114 } catch (err) {
115 if (!this.disconnected) {
116 this.options.onError(

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected