Files
orca/src/shared/agent-launch-remote.test.ts
T
Neil d084a2a36a fix(ssh): decide remote-vs-local from the resolved execution host, not a raw field (#18294)
`repoIsRemote` read `repo.connectionId` directly. That is one of four spellings
of host ownership, so the predicate was wrong in both directions: a row carrying
only `executionHostId: 'ssh:<target>'` read as local and got the Linux-only
`orca-ide` rename it cannot resolve through the relay shim, while a row that
declares itself `local` with a stale `connectionId` read as remote and lost the
rename it needs on a Linux desktop.

The predicate now resolves the host first and asks "does an SSH target hold this
row's files" via `getRepoSshConnectionId`. That keeps a `runtime:` host's nested
SSH target remote (that machine reaches the files through its own relay shim)
while a runtime with no nested target - a full Orca install - stays local, as do
WSL and local.

Its call sites did not all want that question:

- The four launch-scope sites in main already hold the resolved PTY route on
  `TerminalWorkspaceLaunchScope.connectionId`. `scope.repo` is documented display
  metadata and can be a row from a different host than the worktree names, so
  they now read the route they will actually spawn on. A launch shape that
  disagrees with its own route is the bug, not a second predicate.
- `launchAgentInNewTab` picked its repo row with a host-blind
  `store.repos.find`, so a worktree that names its own host could be shaped by
  another host's row. It now resolves through `getConnectionIdFromState`, the
  same rule the file already used for transcript readability.
- `resolveAgentBackgroundLaunchHost` derived the route, the trust write and the
  launch shape from three reads of the raw field; one resolution now feeds all
  three.

Also converts the raw `repo.connectionId` agent-detection probe eight lines above
`buildWorktreeStartupForDraft`'s launch shape, which #17919 deferred precisely
because converting it alone would have left that file internally inconsistent.

Tests cover two distinct SSH hosts (a single-host fixture passes even when the
answer comes off the wrong row, which is how the `ssh:m4air` -> openclaw leak
survived review) and a `runtime:` host carrying a nested SSH target.
2026-09-02 17:46:01 -07:00

34 lines
1.5 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { repoIsRemote } from './agent-launch-remote'
describe('repoIsRemote', () => {
it('reads both spellings of SSH ownership on two different hosts', () => {
// Why two hosts: a single-host fixture passes even when the predicate answers from the wrong
// row, which is how the `ssh:m4air` -> openclaw leak survived review.
expect(repoIsRemote({ connectionId: 'm4air', executionHostId: null })).toBe(true)
expect(repoIsRemote({ connectionId: null, executionHostId: 'ssh:openclaw' })).toBe(true)
expect(repoIsRemote({ connectionId: 'm4air', executionHostId: 'ssh:m4air' })).toBe(true)
})
it('answers local for a row that declares itself local with a stale connection', () => {
expect(repoIsRemote({ connectionId: 'm4air', executionHostId: 'local' })).toBe(false)
})
it('keeps a runtime host with a nested SSH target remote', () => {
expect(repoIsRemote({ connectionId: 'nested-target', executionHostId: 'runtime:vm-1' })).toBe(
true
)
})
it('keeps a runtime host with no nested SSH target local-shaped', () => {
// A runtime with no nested target is a full Orca install, not a relay shim, so it keeps the
// platform CLI name.
expect(repoIsRemote({ connectionId: null, executionHostId: 'runtime:vm-1' })).toBe(false)
})
it('keeps plain local and WSL rows local', () => {
expect(repoIsRemote({ connectionId: null, executionHostId: null })).toBe(false)
expect(repoIsRemote({ connectionId: null, executionHostId: 'local' })).toBe(false)
})
})