MCPcopy Create free account
hub / github.com/MoonshotAI/kimi-code / SSHProcess

Class SSHProcess

packages/kaos/src/ssh.ts:216–273  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

214
215/** Exported for unit tests only. Do not use directly. */
216export class SSHProcess implements KaosProcess {
217 readonly stdin: Writable;
218 readonly stdout: Readable;
219 readonly stderr: Readable;
220 readonly pid: number = -1;
221
222 private _exitCode: number | null = null;
223 private readonly _exitPromise: Promise<number>;
224 private readonly _channel: ClientChannel;
225 private _disposed = false;
226
227 constructor(channel: ClientChannel) {
228 this._channel = channel;
229 this.stdin = channel;
230 this.stdout = new BufferedReadable(channel as unknown as Readable);
231 this.stderr = new BufferedReadable(channel.stderr);
232
233 this._exitPromise = new Promise<number>((resolve) => {
234 // Listen to 'close' on the channel, not 'exit', to ensure all
235 // buffered output is flushed before we resolve.
236 channel.on('close', (code: number | null) => {
237 // Some ssh2 backends surface the exit status only on 'close'.
238 this._exitCode ??= code ?? 1;
239 resolve(this._exitCode);
240 });
241 channel.on('exit', (code: number | null) => {
242 this._exitCode = code ?? 1;
243 });
244 });
245 }
246
247 get exitCode(): number | null {
248 return this._exitCode;
249 }
250
251 async wait(): Promise<number> {
252 return this._exitPromise;
253 }
254
255 kill(signal?: NodeJS.Signals): Promise<void> {
256 // SSH signals must be stripped of the "SIG" prefix (RFC 4254 §6.9):
257 // e.g. 'SIGTERM' → 'TERM', 'SIGKILL' → 'KILL', 'SIGINT' → 'INT'.
258 // Honor the caller's requested signal so that remote processes can
259 // perform graceful shutdown on SIGTERM/SIGINT.
260 const rawSignal = signal ?? 'SIGTERM';
261 const sshSignal = rawSignal.startsWith('SIG') ? rawSignal.slice(3) : rawSignal;
262 this._channel.signal(sshSignal);
263 return Promise.resolve();
264 }
265
266 dispose(): void {
267 if (this._disposed) return;
268 this._disposed = true;
269 this.stdin.destroy();
270 this.stdout.destroy();
271 this.stderr.destroy();
272 }
273}

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected