mirror of
https://github.com/stablyai/orca.git
synced 2026-10-05 00:02:33 +00:00
Two fields in `mergeDirectSshRemoteWorkspaceSession` treated an absent remote entry as an authoritative delete. Both are records whose *absence* is meaningful, so deleting them on silence loses information the host never had. 1. The closed-last-terminal tombstone. `src/renderer/src/components/terminal/initial-terminal.ts:5` states the contract verbatim: "a missing row means never initialized; an explicit empty row records that the user closed the last terminal." `mergedWorktreeIds` was `keys(remote.tabsByWorktree)` union the replaced worktrees whose local tab list is NON-EMPTY (`:41-45`), so a worktree holding an explicit `[]` and absent from the host snapshot was excluded, `omitTargetWorktrees` stripped the key, and nothing re-added it. Measured before the fix: `Object.hasOwn(merged.tabsByWorktree, WORKTREE)` => false. Downstream, `worktree-initial-terminal-seeding.ts:125` computes `shouldHonourClosedTerminalTombstone = Object.hasOwn(store.tabsByWorktree, id) && ...` => false, so `shouldAutoCreateInitialTerminal(0, false)` => true and a terminal is created. The user closes their last terminal on an SSH workspace and it comes back on reconnect. The projection is innocent: `remote-workspace-session-projection.ts:47-59` and `:161-168` both round-trip an empty array faithfully. The row is lost only when the host snapshot has no entry for that worktree path at all -- a first sync, a snapshot predating the close, or `resolveWorktreeId(path)` returning null during startup. Fix: admit a replaced worktree whose local row EXISTS (`Object.hasOwn`) rather than whose local row is non-empty. That is the same "the host is authoritative for what it knows, not for what it has never been told" rule the rest of this function already applies to tabs. 2. `defaultTerminalTabsAppliedByWorktreeId`. This was the only field in the function with no preservation branch: `:257-260` deleted the local entry for every replaced worktree and trusted the remote snapshot to carry it. The marker is write-once and is the sole guard on `applyDefaultTerminalTabs` (`worktree-default-terminal-tabs.ts:34`), so deleting it re-applies the whole default-tab template over the user's tabs. Removal belongs to the worktree-teardown path, not to a reconnect. Why this shape rather than a revision counter: both are statements about what absence means, local to one function, so they survive the SSH-v3 consolidation unchanged. Neither adds a per-tab identity field. Deliberately not done: the `hostUnknown` preserve branch is untouched, and no close-suppression is added here -- that is the durable close tombstone, and it belongs on top of this rather than mixed into it. Before: 3 failed | 18 passed. After: 21 passed (45 across the wider merge, default-tabs and initial-terminal suites).