From b35755e1f0452e3dde252c5cfd16dc06c1d5faa9 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Fri, 2 Oct 2026 15:30:12 +0200 Subject: [PATCH] fix(ssh): remove remote mcp config via trap when the tile kills ssh --- src/ClaudeDo.Worker/Runner/InteractiveLaunchSpecService.cs | 5 +++-- .../Runner/InteractiveLaunchSpecServiceTests.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ClaudeDo.Worker/Runner/InteractiveLaunchSpecService.cs b/src/ClaudeDo.Worker/Runner/InteractiveLaunchSpecService.cs index 967be3c1..f8c4e1da 100644 --- a/src/ClaudeDo.Worker/Runner/InteractiveLaunchSpecService.cs +++ b/src/ClaudeDo.Worker/Runner/InteractiveLaunchSpecService.cs @@ -336,10 +336,11 @@ public sealed class InteractiveLaunchSpecService // No double quotes anywhere: ConPTY flattens Args into one Windows command line. // ssh runs a non-interactive shell whose .bashrc bails early, so the native installer's ~/.local/bin is added by hand. + // Closing the tile kills ssh → remote shell gets SIGHUP; a trailing "; rm -f" never runs, the trap does. var remote = - $"export PATH=$HOME/.local/bin:$PATH && umask 077 && mkdir -p ~/.claudedo && echo {b64} | base64 -d > {cfgFile}" + + $"export PATH=$HOME/.local/bin:$PATH && trap 'rm -f {cfgFile}' EXIT HUP TERM && umask 077 && mkdir -p ~/.claudedo && echo {b64} | base64 -d > {cfgFile}" + $" && cd {SshWorkspace.QuoteRemotePath(ws.RemotePath)}" + - $" && MCP_TOOL_TIMEOUT={McpToolTimeoutMs} claude --mcp-config {cfgFile}; rm -f {cfgFile}"; + $" && MCP_TOOL_TIMEOUT={McpToolTimeoutMs} claude --mcp-config {cfgFile}"; var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); return new LaunchSpec(home, ssh, diff --git a/tests/ClaudeDo.Worker.Tests/Runner/InteractiveLaunchSpecServiceTests.cs b/tests/ClaudeDo.Worker.Tests/Runner/InteractiveLaunchSpecServiceTests.cs index 4db1b716..bd7e6972 100644 --- a/tests/ClaudeDo.Worker.Tests/Runner/InteractiveLaunchSpecServiceTests.cs +++ b/tests/ClaudeDo.Worker.Tests/Runner/InteractiveLaunchSpecServiceTests.cs @@ -1692,7 +1692,7 @@ public sealed class InteractiveLaunchSpecServiceTests : IDisposable Assert.StartsWith("export PATH=$HOME/.local/bin:$PATH && ", remote); Assert.Contains("cd ~/'app'", remote); Assert.Contains($"MCP_TOOL_TIMEOUT={InteractiveLaunchSpecService.McpToolTimeoutMs} claude --mcp-config ~/.claudedo/mcp-{paneId}.json", remote); - Assert.EndsWith($"rm -f ~/.claudedo/mcp-{paneId}.json", remote); + Assert.Contains($"trap 'rm -f ~/.claudedo/mcp-{paneId}.json' EXIT HUP TERM && ", remote); var b64 = System.Text.RegularExpressions.Regex.Match(remote, @"echo ([A-Za-z0-9+/=]+) \| base64 -d").Groups[1].Value; using var json = System.Text.Json.JsonDocument.Parse(Convert.FromBase64String(b64));