Repository navigation
feat(ssh): show saved port forwards that couldn't start, with why, and let you remove them - #33450
Conversation
…d let you remove them (#32484) A saved forward whose local port is taken, or that keeps failing, stayed saved but invisible, retried in the background with no way to remove it. The port-forward lists now show each saved forward that isn't open, with the last start error, and Remove deletes it by its mapping.
…tore reopened before removing it, and update IPC fixtures
…that died, toast a failed remove, and reset backoff on manual edits
…offline; label the remove button; test the healthy-uptime reset
…cluding hosts that never connect
497ace9 to
fb54122
Compare
|
No actionable comments were generated in the recent review.
|
There was a problem hiding this comment.
Actionable comments posted: 1

Review info
-
Run configuration-
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
e29ccf9f-78b5-4751-9798-4121f86b6070
Files selected for processing: 48-
src/main/ipc/ssh/ssh-handler-reregistration.test.tssrc/main/ipc/ssh/ssh-port-forward-handlers.test.tssrc/main/ipc/ssh/ssh-port-forward-handlers.tssrc/main/ipc/ssh/ssh-port-forward-persistence.tssrc/main/ipc/ssh/ssh-port-forward-restore.test.tssrc/main/ipc/ssh/ssh-port-forward-unrestored.tssrc/main/ipc/ssh/ssh-renderer-broadcast.tssrc/main/ipc/ssh/ssh.tssrc/preload/api/ssh-api.tssrc/preload/api/ssh-bridge.tssrc/renderer/src/components/right-sidebar/ssh-forwarded-ports-section.tsxsrc/renderer/src/components/right-sidebar/ssh-ports-panel.tsxsrc/renderer/src/components/right-sidebar/ssh-unrestored-port-row.tsxsrc/renderer/src/hooks/ipc-events-agent-status-store-test-fixtures.tssrc/renderer/src/hooks/ipc-events-agent-status-window-test-fixtures.tssrc/renderer/src/hooks/ipc-events-close-routing-test-harness.tssrc/renderer/src/hooks/ipc-events-harness-store-state.tssrc/renderer/src/hooks/ipc-events-ssh-api-test-fixtures.tssrc/renderer/src/hooks/ipc-events-terminal-create-scenario-types.tssrc/renderer/src/hooks/ipc-events-terminal-create-test-harness.tssrc/renderer/src/hooks/ipc-events-terminal-create-window-test-fixtures.tssrc/renderer/src/hooks/ipc-events-test-harness.tssrc/renderer/src/hooks/ipc-events/direct-ssh-connect-reply-routing.test.tssrc/renderer/src/hooks/ipc-events/direct-ssh-hydration-fanout.test.tssrc/renderer/src/hooks/ipc-events/direct-ssh-hydration-target-metadata.test.tssrc/renderer/src/hooks/ipc-events/direct-ssh-initial-state-hydration.tssrc/renderer/src/hooks/ipc-events/direct-ssh-state-ipc-bridge.tssrc/renderer/src/hooks/ipc-events/direct-ssh-unrestored-forward-sync.test.tssrc/renderer/src/hooks/ipc-events/direct-ssh-unrestored-forward-sync.tssrc/renderer/src/hooks/useIpcEvents-agent-status-ssh-authority.test.tssrc/renderer/src/hooks/useIpcEvents-browser-tab-create.test.tssrc/renderer/src/hooks/useIpcEvents-cli-worktree-activation.test.tssrc/renderer/src/hooks/useIpcEvents-close-routing-browser-pages.test.tssrc/renderer/src/hooks/useIpcEvents-rate-limit-hydration.test.tssrc/renderer/src/hooks/useIpcEvents-ssh-disconnect-cleanup.test.tssrc/renderer/src/hooks/useIpcEvents-updater-status.test.tssrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/es.jsonsrc/renderer/src/i18n/locales/fr.jsonsrc/renderer/src/i18n/locales/ja.jsonsrc/renderer/src/i18n/locales/ko.jsonsrc/renderer/src/i18n/locales/pt.jsonsrc/renderer/src/i18n/locales/zh.jsonsrc/renderer/src/store/slices/ssh-target-cleanup.tssrc/renderer/src/store/slices/ssh.tssrc/renderer/src/web/preload-api/web-terminal-api.tssrc/shared/ssh-types.tstests/e2e/ssh-orcad-workspace-tools.spec.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.
-
ELI5
Some saved SSH port forwards can't start: their local port is already in use, the port falls in a range Windows reserves, or the ssh process keeps exiting. Orca keeps those forwards saved and retries them in the background, but the Ports panel only listed open forwards. So you couldn't see them, and you couldn't remove them. Now they're listed with the reason they didn't start, and you can remove them.
Builds on #33388, which has merged; this PR is rebased onto main.
What Changed
unrestoredlist. It goes from main to this app's own renderer, so client and host versions don't matter.ssh:listUnrestoredPortForwardscall, and reads it again when a host disconnects. A read that a newer push has already replaced is dropped.ssh:removeSavedPortForwardremoves a forward by its mapping.Why
Hiding these forwards leaves users with no way to stop a forward that can never start, and no clue why it's missing. Listing them next to the open forwards, with the last error, reuses the existing list and row styling: muted text,
text-destructivefor the error state, and the same remove button. Mobile has no port-forward list, so there's nothing to match there.Linked Issue
Refs #32484 (follow-up to #33388)
Visual Proof
The Docker e2e takes a screenshot of the row (
unrestored-forward-row.pngin the run's artifacts). Taken in a hidden window.Testing
Review
Codex review: the final head is clean against the merge-base with main. Earlier rounds found these, all fixed here: the two new channels were missing from IPC re-registration; Remove could lose to a restore that had just opened the forward; hydration fixtures needed the new call; the empty state showed next to saved rows; a flapping ssh reset its backoff; offline hosts weren't loaded and stale reads could win; the offline list couldn't scroll. An independent Opus review approved the PR (no P0/P1); its P2/P3 items are fixed here: every locale has the strings, the existing Remove key is reused, a failed remove shows a toast, a dead forward is labelled Stopped, manual edits reset the backoff, the list survives going offline, the button has an aria-label, the healthy-uptime reset is tested, and a test that only checked its own mocks is removed.
Agent skill upstream boundary
Notes
Cross-platform: no platform-specific code; the reason text comes from the OS error. SSH/remote: client-only, with optional fields. Folder workspaces: forwards belong to the SSH host, not the workspace.
Checklist