Skip to content

fix(ssh): keep managed remote server ownership through stop - #215

Merged
leoisadev1 merged 4 commits into
mainfrom
fix/ssh-runner-ownership
Sep 13, 2026
Merged

leoisadev1 merged 4 commits into
mainfrom
fix/ssh-runner-ownership

Conversation

@leoisadev1

Copy link
Copy Markdown
Member

Problem

SSH-managed servers started through npx/npm can outlive Disconnect or app shutdown. The launcher recorded the npm wrapper PID, so stop signaled npm while the server kept its listener and database open. A failed installer that printed a path could still launch, and a stop that timed out still deleted ownership files.

Fix

  • Exec the CLI path already resolved by the install preflight, so the recorded PID is the server.
  • Check the installer's exit status before accepting stdout. Keep npm's stderr and report installation failure without guessing a C-compiler cause.
  • Confirm the saved process has exited before removing PID, port, and ownership files. If it stays alive after the two-second wait, keep those files and return SshCommandError.
  • Run connect and disconnect in order for each target so reconnect cannot overtake an earlier stop.

External servers remain running. No remote force-kill was added.

Adaptation

Reviewed port of pingdotgg/t3code#9843, #10088, and #10105. Package and executable names stay akeru-bot / akeru. Hosted relay was not added.

Scope

This PR is SSH runner, install diagnostics, and stop ownership only. Cookie isolation is #208. LAN vs Tailscale pairing and Zed remote open are separate PRs.

Verification

  • vp test run packages/ssh: 54 passed, including POSIX runner PID ownership, installer ETARGET/network/empty-success/success paths, stop timeout keeping ownership files, disconnect failure retry, and per-target reconnect ordering.
  • vp run --filter @t3tools/ssh typecheck exited 0.
  • Targeted lint on the changed files reported no errors.

No live bot/group UI changed. Native remote SSH hosts were not used; tests run a real POSIX runner against fixture package managers and a local Node listener.

Implemented with Grok 4.6 High in Grok Build via Orca.

SSH-managed servers started through npx/npm can outlive Disconnect because the
launcher recorded the wrapper PID. Exec the resolved CLI, treat installer
non-zero exits as failures, and keep ownership files when the remote process
is still alive. Connect and disconnect on one target run in order.

Adapted from pingdotgg#9843, pingdotgg#10088, and pingdotgg#10105.

Implemented with Grok 4.6 High in Grok Build via Orca.
@vercel

vercel Bot commented Sep 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
akeru-bot-landing Building Building Preview Sep 10, 2026 5:42pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Greptile Summary

Summary

  • SSH remote-server lifecycle handling retains the installed CLI path and directly executes it so the recorded process ID belongs to the server process.
  • Failed package-manager preflights now surface installation diagnostics instead of proceeding with an empty executable path.
  • Shutdown preserves ownership state when the managed remote process cannot be confirmed stopped, allowing a later retry.
  • Connect and disconnect remain serialized per target, preventing reconnect from overtaking remote shutdown.

Merge safety

Safe to merge.

Confidence Score: 5/5

Safe to merge; there are no outstanding blocking issues.

The reconnect-ordering thread was resolved by greptile-apps[bot] without explanation. Current code acquires the per-target lock before resolving the SSH target for both connect and disconnect, which addresses the reported ordering race. The target-lock retention concern was correctly conceded after leoisadev1 explained that retaining one session-scoped lock per target prevents a new reconnect from racing an in-progress shutdown.

Reviews (3): Last reviewed commit: "test(ssh): avoid empty generator in tunn..." | Re-trigger Greptile

Comment thread packages/ssh/src/tunnel.ts
Comment thread packages/ssh/src/tunnel.ts
Acquire the per-target lock before SSH host resolution so a slow disconnect
cannot lose the race to a later reconnect.

Implemented with Grok 4.6 High in Grok Build via Orca.
@leoisadev1
leoisadev1 merged commit 6d5d36b into main Sep 13, 2026
11 checks passed
@leoisadev1
leoisadev1 deleted the fix/ssh-runner-ownership branch September 13, 2026 23:01
@github-actions github-actions Bot mentioned this pull request Sep 13, 2026
@leoisadev1

Copy link
Copy Markdown
Member Author

This is Leo's agent. The independent SSH target-identity race still reproduces on current head48eee07016d795c05a95239fbb110cfb135e5ad8 despite successful CI and the 5/5 review. The production tunnel manager is unchanged from the previously reported head; the current delta only replaces an empty test generator with Effect.sync.

I reran the preserved regression against the current shipped manager: disconnect the original alias-shaped target while shutdown is Deferred-gated, then reconnect using the resolved target returned by provisioning. Both local-tunnel-stop and remote-server-stop variants launch a second tunnel before shutdown is released: launchesBeforeShutdown is2, expected1. Both tests fail on that assertion in29ms/8ms, not from a timeout. The35committed runner/tunnel tests pass, but do not cover this alias/resolved identity case.

The raw-input targetConnectionKey lock and resolved tunnel-map key still disagree. Holding the raw-input lock before SSH resolution fixes ordering for identical inputs, but does not serialize the alias and its returned/persisted resolved form. Please retain the repair hold and add canonical serialization with committed regressions for both identities, preserving resolution-order guarantees and different-host independence. The supervisor regression is scratch-only, uses the actual manager with fake SSH responses and Deferred synchronization, and does not claim a real remote-host run.

This comment is evidence and a scoped repair request, not an Orca delivery/execution receipt; that interface remains unavailable to this supervisor.

This branch was successfully deployed

1 active deployment
Preview — 48eee070 Deployed Sep 13, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant