Skip to content

feat(app): Remote SSH support for OpenCode desktop - #40843

Closed
dntxos wants to merge 6 commits into
anomalyco:devfrom
dntxos:ci/mac-dmg
Closed

dntxos wants to merge 6 commits into
anomalyco:devfrom
dntxos:ci/mac-dmg

Conversation

@dntxos

@dntxos dntxos commented Aug 6, 2026 •

Copy link
Copy Markdown

Issue for this PR

Implements #33273

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds native SSH connections to the desktop app, following the same architecture as the existing WSL integration. The ServerConnection.Ssh type already existed in the app package but had no implementation.

How it works: the main process spawns the system ssh client (so ~/.ssh/config, keys, agents and ProxyJump all apply) with a single connection per server: ssh -L 127.0.0.1:<local>:127.0.0.1:<remote> -- <host> sh -se, piping a script over stdin that resolves the remote opencode binary (~/.opencode/bin or PATH) and execs opencode serve on the forwarded port with per-session basic-auth credentials. The app then talks to the remote server through the tunnel like any other HTTP connection, so chat, PTY terminal (WebSocket) and the server-side directory picker work unchanged.

Details worth reviewing:

  • Remote port is picked at random; bind conflicts are detected from the server's error output and retried on a fresh connection (3 attempts).
  • The remote script keeps a watchdog reading the ssh channel's stdin: when the connection drops, the remote server is killed, so nothing keeps running on the host. POSIX gives backgrounded commands /dev/null as fd 0, so the original stdin is saved to fd 9 first — without that the watchdog would kill the server immediately at startup.
  • Host input is validated ([user@]host[:port], bracketed/bare IPv6) and always passed after --, so nothing typed can become an ssh option.
  • BatchMode=yes everywhere: no TTY in the main process, so auth must be non-interactive; failures surface the real ssh stderr plus a hint to run ssh <host> once in a terminal, and each server row has an "Open terminal" action.
  • UI: "Add SSH server" in the servers settings menu, with host suggestions parsed from ~/.ssh/config (including Include), a connect probe, and remote install/update of opencode pinned to the desktop version via the official install script. Servers persist, auto-connect on launch, and fall back to the local sidecar at startup when not ready.
  • i18n: 36 new keys (ssh.*, desktop.ssh.error.*) added to all 28 locales; parity test passes.

How did you verify your code works?

  • 63 new unit tests (destination/config parsing, argv/script construction, failure classification, controller start/remove/stop races, startup fallback, dialog view-model) — all passing under bun test.
  • Full suites: app 712/712; desktop 100/101 (the one failure is the pre-existing node:sqlite issue in draft-store.test.ts, present without these changes).
  • tsgo -b clean in both packages; production electron-vite build succeeds.
  • End-to-end manual testing on macOS against a real SSH host is still pending — that's the next step before merge.

Screenshots / recordings

image image

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

dntxos added 2 commits August 6, 2026 10:43
Add SSH as a desktop-managed server type alongside WSL. The app connects
through the system ssh client (SSH config, keys, and agents work as-is),
starts `opencode serve` on the remote host over a single connection with a
-L tunnel, and manages lifecycle from Settings -> Servers: add with
~/.ssh/config host suggestions, probe, install/update opencode remotely,
reconnect/disconnect/open terminal, start on launch.

- main: ssh controller, tunnel sidecar with random remote port retry and
  stdin watchdog cleanup, ssh_config parser, ssh-servers-* IPC
- renderer/app: sshServers platform bridge, connection merge, settings rows,
  add dialog, ssh: startup fallback
- i18n: ssh.* and desktop.ssh.error.* keys translated for all locales
@github-actions github-actions Bot added needs:compliance This means the issue will auto-close after 2 hours. needs:title labels Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Hey! Your PR title Ci/mac dmg doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@dntxos dntxos changed the title Ci/mac dmg Remote SSH support for OpenCode desktop Aug 6, 2026
dntxos added 3 commits August 6, 2026 11:30
Match the WSL add-server dialog visual language: card-style host list
with row separators and hover states, consistent 16px body padding,
section title typography, and grouped input+hint spacing.
@dntxos dntxos changed the title Remote SSH support for OpenCode desktop feat(app): Remote SSH support for OpenCode desktop Aug 6, 2026
@dntxos

dntxos commented Aug 6, 2026

Copy link
Copy Markdown
Author

link to issue #33273

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Automated PR Cleanup

Thank you for contributing to opencode.

Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions.

This PR was closed because it matched the following cleanup criteria:

  • The PR was created more than 1 month ago
  • The PR had fewer than 2 positive reactions
  • Positive reactions are counted as thumbs-up, heart, celebration, or rocket reactions on the PR

PRs created within the last month are not affected by this cleanup.

If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate.

Thanks again for taking the time to contribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant