Skip to content

Commit a8893a8

Browse files
committed
🤖 Add remote-side timeout using timeout command
When SSH is killed locally, the remote command may continue running (especially with ControlMaster multiplexing). Wrap remote commands with the `timeout` utility to ensure they're killed on the remote side too. Uses SIGKILL and sets remote timeout slightly longer than local timeout to ensure the local timeout normally fires first.
1 parent 5095745 commit a8893a8

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

src/runtime/SSHRuntime.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,23 @@ export class SSHRuntime implements Runtime {
9090
parts.push(command);
9191

9292
// Join all parts with && to ensure each step succeeds before continuing
93-
const fullCommand = parts.join(" && ");
93+
let fullCommand = parts.join(" && ");
94+
95+
// Wrap command with timeout if specified
96+
// This ensures the remote command is killed even if the SSH connection persists
97+
// (e.g., due to ControlMaster multiplexing)
98+
if (options.timeout !== undefined) {
99+
// Use timeout command with KILL signal after timeout expires
100+
// The timeout value is slightly longer than our local timeout to ensure
101+
// the local timeout fires first in normal cases
102+
const remoteTimeout = Math.ceil(options.timeout) + 1;
103+
fullCommand = `timeout --signal=KILL ${remoteTimeout} bash -c ${shescape.quote(fullCommand)}`;
104+
}
94105

95106
// Wrap in bash -c with shescape for safe shell execution
96-
const remoteCommand = `bash -c ${shescape.quote(fullCommand)}`;
107+
const remoteCommand = options.timeout
108+
? fullCommand
109+
: `bash -c ${shescape.quote(fullCommand)}`;
97110

98111
// Build SSH args
99112
const sshArgs: string[] = ["-T"];

0 commit comments

Comments
 (0)