Files
orca/src
Jinwoo HongandOrca 864594ffdd Fix SSH state for paired remote clients + complete target re-adoption sweep (STA-1468) (#7767)
* Sweep all persisted carriers of a removed SSH target id on re-adoption

reassignSshTargetId re-pointed repos and worktree metas but left the old
target id embedded in persisted session pty ids (ssh:<id>@@pty-N in tabs,
layouts, remoteSessionIdsByTabId), the startup reconnect list
(activeConnectionIdsAtShutdown, replayed via ssh.connect at boot — the
exact 'SSH target not found' in STA-1468), sleeping-agent resume records,
provisioned project host setups, sidebar host-scope arrays, and relay pty
leases. Any survivor resurfaces later as a failing connect or reattach.

New ssh-target-id-migration module re-points every carrier in one pass,
wired into reassignSshTargetId with per-carrier unit and store-level
round-trip tests.

Co-authored-by: Orca <help@stably.ai>

* Bridge SSH connection state to paired remote clients

The SSH surface was desktop-only: ssh:state-changed went to the host's
own BrowserWindow and the web client's ssh API was a no-op stub, so a
paired client's reconnect overlay never learned the host connected and
its target labels stayed empty (STA-1468 — overlay stuck on 'please
connect' over a live terminal).

- New sshStateChanged runtime client event, emitted from broadcastSshState
  through OrcaRuntimeService onto the existing clientEvents stream.
- New ssh.listTargets / ssh.listRemovedTargetLabels RPC methods next to
  the previously unused ssh.getState / ssh.connect.
- Web preload now routes listTargets / listRemovedTargetLabels / getState
  / connect to the paired host's runtime RPC instead of stubbing them.
- useIpcEvents applies sshStateChanged on paired web clients through the
  same guarded path as desktop ssh.onStateChanged; desktop clients ignore
  the event since a foreign runtime's targets would pollute their local
  SSH store.

Co-authored-by: Orca <help@stably.ai>

* Harden the SSH reconnect overlay against stale or unknown target state

- Only present the destructive 'SSH host removed' state on positive
  evidence (a removal tombstone label, or a hydrated non-empty target
  list lacking the id). A client whose SSH state never hydrated has an
  empty labels map for every id and must not offer workspace removal.
- After a failed Connect, resync target metadata so a stale overlay
  converges to the ghost/re-adopted state instead of offering the same
  failing Connect forever (the repeated 'SSH target not found' toast
  loop in STA-1468).

Co-authored-by: Orca <help@stably.ai>

* Address CodeRabbit review on #7767

- Re-key workspaceSessionsByHostId partitions stored under a removed SSH
  host id during re-adoption (no writer keys partitions by ssh host today,
  but the schema tolerates it — re-key instead of stranding; live partition
  wins when both keys exist).
- Track SSH target-list hydration explicitly (sshTargetsHydrated) instead
  of inferring it from a non-empty label map, so a legitimately empty
  target list still counts as removal evidence and a never-hydrated client
  still never offers destructive removal.
- Apply the refreshed target list before the best-effort removed-labels
  fetch in the overlay resync, so a labels failure can't discard it.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-08 11:36:19 -07:00
..