mirror of
https://github.com/stablyai/orca.git
synced 2026-10-12 16:03:03 +00:00
fix(orcad): a connected but unused SSH host previews as movable (#24609)
The untransferred-dependency census counted activeConnectionIdsAtShutdown naming the target as workspace-session state. The renderer rewrites that list on every connection change, so merely connecting to an empty host blocked the move. It is a reconnect hint; the remote work it can stand for is counted on its own. The empty-target claim check likewise ignores global-field copies inside the host's session partition. Co-authored-by: m4air <m4air@Mac.localdomain>
This commit is contained in:
+2
-3
@@ -97,9 +97,8 @@ export function countUnsupportedSessionState(
|
||||
? 1
|
||||
: 0
|
||||
count += session.activeWorkspaceExecutionHostId === scope.hostId && !sourceHostPartition ? 1 : 0
|
||||
count += (session.activeConnectionIdsAtShutdown ?? []).filter(
|
||||
(targetId) => targetId === scope.targetId
|
||||
).length
|
||||
// activeConnectionIdsAtShutdown is not counted: it is the renderer's live "connected now" hint, and
|
||||
// the remote work it can stand for (tab PTYs, remote session ids, leases) is counted on its own.
|
||||
count +=
|
||||
session.activeTabId && terminalTabIds.has(session.activeTabId) && !sourceHostPartition ? 1 : 0
|
||||
for (const [ownerKey, files] of Object.entries(session.openFilesByWorktree ?? {})) {
|
||||
|
||||
@@ -25,6 +25,29 @@ describe('client state that still references an SSH target', () => {
|
||||
expect(blockersFor({ getWorkspaceSessionHostIds: () => ['local', HOST] })).toEqual([])
|
||||
})
|
||||
|
||||
it('ignores a connected host: the reconnect hint and global copies in its partition', () => {
|
||||
const connected = {
|
||||
...getDefaultWorkspaceSession(),
|
||||
activeConnectionIdsAtShutdown: ['ssh-1'],
|
||||
activeWorktreeId: 'local-wt',
|
||||
browserUrlHistory: [
|
||||
{
|
||||
url: 'https://example.com',
|
||||
normalizedUrl: 'https://example.com',
|
||||
title: 'Example',
|
||||
lastVisitedAt: 1,
|
||||
visitCount: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
expect(
|
||||
blockersFor({
|
||||
getWorkspaceSessionHostIds: () => ['local', HOST],
|
||||
getWorkspaceSession: () => connected
|
||||
})
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
it('blocks on the host session partition and names the fields holding state', () => {
|
||||
const blockers = blockersFor({
|
||||
getWorkspaceSessionHostIds: () => ['local', HOST],
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import type { Store } from '../persistence'
|
||||
import { getDefaultWorkspaceSession } from '../../shared/constants'
|
||||
import { toSshExecutionHostId } from '../../shared/execution-host'
|
||||
import { GLOBAL_WORKSPACE_SESSION_FIELDS } from '../../shared/workspace-session-host-field-ownership'
|
||||
import {
|
||||
ORCAD_MIGRATION_DEPENDENCY_KINDS,
|
||||
type OrcadMigrationBlocker,
|
||||
@@ -112,7 +113,7 @@ export function collectUntransferredDependentBlockers(
|
||||
: []
|
||||
}
|
||||
|
||||
/** Non-default fields of the host's session partition, plus a local session pointed at the host. */
|
||||
/** Non-default host-owned fields of the host's partition, plus a local session pointed at the host. */
|
||||
function workspaceSessionReferences(store: DependentStateStore, hostId: string): string[] {
|
||||
const references: string[] = []
|
||||
if (store.getWorkspaceSession().activeWorkspaceExecutionHostId === hostId) {
|
||||
@@ -122,7 +123,12 @@ function workspaceSessionReferences(store: DependentStateStore, hostId: string):
|
||||
return references
|
||||
}
|
||||
const defaults: Record<string, unknown> = { ...getDefaultWorkspaceSession() }
|
||||
// A partition's global fields are copies of client-wide focus and history, not host state.
|
||||
const globalFields = new Set<string>(GLOBAL_WORKSPACE_SESSION_FIELDS)
|
||||
for (const [field, value] of Object.entries(store.getWorkspaceSession(hostId))) {
|
||||
if (globalFields.has(field)) {
|
||||
continue
|
||||
}
|
||||
if (!isEmptyValue(value) && JSON.stringify(value) !== JSON.stringify(defaults[field])) {
|
||||
references.push(field)
|
||||
}
|
||||
|
||||
@@ -72,6 +72,18 @@ describe('migration export preflight', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('previews a connected but unused host as movable with no blockers', () => {
|
||||
const store = preflightStore((store) => {
|
||||
store.addSshTarget(TARGET)
|
||||
// What the renderer writes on connect: the reconnect hint names the now-connected target.
|
||||
store.patchWorkspaceSession({ activeConnectionIdsAtShutdown: [TARGET.id] })
|
||||
})
|
||||
expect(preflightOrcadMigrationExport(store, TARGET.id)).toMatchObject({
|
||||
claimable: true,
|
||||
blockers: []
|
||||
})
|
||||
})
|
||||
|
||||
it('blocks on a live relay terminal, which cannot move', () => {
|
||||
const lease: SshRemotePtyLease = {
|
||||
targetId: TARGET.id,
|
||||
|
||||
Reference in New Issue
Block a user