mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
fix(ssh): a migrated host's old session no longer brings closed tabs back on restart (#33702)
* fix(ssh): a migrated host's old session no longer brings closed tabs back on restart (#33539) After an SSH host moved to a managed server, main hides its retained source repos but still listed its frozen session partition. The window adopted that partition at startup, and agent tabs the user had closed on the server came back on every restart. The partition census now hides that partition exactly when its repos are hidden; the stored rows stay for downgraded clients. * test(ssh): pin that an uncommitted move keeps its session listed
This commit is contained in:
@@ -3,6 +3,7 @@ import type { Store } from '../persistence'
|
||||
import type { OrcaRuntimeService } from '../runtime/orca-runtime'
|
||||
import { parseTerminalSurfaceCloseTarget } from '../../shared/terminal-surface-close-target'
|
||||
import { isFrozenOrcadSourceSessionPartition } from '../ssh/orcad-retained-source'
|
||||
import { visibleSessionHostIds } from '../ssh/orcad-retained-source-session'
|
||||
import { markAgentLaunchesClosedByUser } from '../agent-launch/agent-launch-pane-attachment'
|
||||
import { windowViewPatchForMain, windowViewSaveForMain } from '../persistence/window-save-view'
|
||||
import { reportWindowSaveDrift } from '../persistence/window-save-divergence'
|
||||
@@ -25,7 +26,7 @@ export function registerSessionHandlers(store: Store, runtime: OrcaRuntimeServic
|
||||
|
||||
// Repo catalogs omit folder-only SSH hosts; enumerate session partitions directly (#12723).
|
||||
ipcMain.handle('session:list-host-ids', () => {
|
||||
return store.getWorkspaceSessionHostIds()
|
||||
return visibleSessionHostIds(store, store.getWorkspaceSessionHostIds())
|
||||
})
|
||||
|
||||
// Main owns layout membership; merge the window's view and facts, then report layout drift.
|
||||
|
||||
@@ -25,6 +25,7 @@ vi.mock('../../shared/app-environment', () => ({
|
||||
|
||||
const { isFrozenOrcadSourceSessionPartition, visibleProjectGroups, visibleProjectHostSetups } =
|
||||
await import('./orcad-retained-source')
|
||||
const { visibleSessionHostIds } = await import('./orcad-retained-source-session')
|
||||
|
||||
const FENCED: SshTarget = {
|
||||
id: 'ssh-box',
|
||||
@@ -108,6 +109,26 @@ describe('lists while a converted host keeps its source rows', () => {
|
||||
])
|
||||
})
|
||||
|
||||
// #33539: adopting the hidden source's session at startup restored tabs closed on the server.
|
||||
it('leaves the hidden host session out of the partition census until the host changes', () => {
|
||||
const hostIds: ExecutionHostId[] = ['local', 'ssh:ssh-box', 'ssh:other', 'runtime:env-1']
|
||||
expect(visibleSessionHostIds(catalog([FENCED]), hostIds)).toEqual([
|
||||
'local',
|
||||
'ssh:other',
|
||||
'runtime:env-1'
|
||||
])
|
||||
const changed = { ...FENCED, orcadFence: { environmentId: 'env-1', sourceChangedAt: 'x' } }
|
||||
expect(visibleSessionHostIds(catalog([changed]), hostIds)).toEqual(hostIds)
|
||||
// A fenced move that has not committed still shows its repos, so their session stays too.
|
||||
const inFlight = mkdtempSync(join(tmpdir(), 'orcad-retained-lists-'))
|
||||
try {
|
||||
writeOrcadMigrationSourceCutover(inFlight, orcadMigrationCutoverFixture('m-1', FENCED.id))
|
||||
expect(visibleSessionHostIds(catalog([FENCED]), hostIds, () => inFlight)).toEqual(hostIds)
|
||||
} finally {
|
||||
rmSync(inFlight, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('shows them until the migration commits, while freezing the session from the fence on', () => {
|
||||
const userDataPath = mkdtempSync(join(tmpdir(), 'orcad-retained-lists-'))
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { parseExecutionHostId, type ExecutionHostId } from '../../shared/execution-host'
|
||||
import type { Store } from '../persistence'
|
||||
import { appUserDataPath, hiddenRetainedSourceTargetIds } from './orcad-retained-source'
|
||||
|
||||
/** A hidden source's session goes with its repos: a window adopting it at startup brings closed tabs back (#33539). */
|
||||
export function visibleSessionHostIds(
|
||||
store: Pick<Store, 'getSshTargets'>,
|
||||
hostIds: readonly ExecutionHostId[],
|
||||
getUserDataPath = appUserDataPath
|
||||
): ExecutionHostId[] {
|
||||
const hidden = new Set(hiddenRetainedSourceTargetIds(getUserDataPath, store.getSshTargets()))
|
||||
return hostIds.filter((hostId) => {
|
||||
const parsed = parseExecutionHostId(hostId)
|
||||
return parsed?.kind !== 'ssh' || !hidden.has(parsed.targetId)
|
||||
})
|
||||
}
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
withoutWslMovedRepos
|
||||
} from '../persistence/moving-wsl-projects/wsl-move-scope-guard'
|
||||
|
||||
const appUserDataPath = (): string => getAppEnvironment().getPath('userData')
|
||||
export const appUserDataPath = (): string => getAppEnvironment().getPath('userData')
|
||||
|
||||
type CatalogStore = Pick<Store, 'getFolderWorkspaces' | 'getProjectGroups' | 'getRepos'>
|
||||
type TargetStore = Pick<Store, 'getSshTargets' | 'updateSshTarget'>
|
||||
@@ -64,7 +64,7 @@ function isHiddenRetainedSourceTarget(
|
||||
}
|
||||
|
||||
/** Delay journal reads until a host is fenced. */
|
||||
function hiddenRetainedSourceTargetIds(
|
||||
export function hiddenRetainedSourceTargetIds(
|
||||
getUserDataPath: () => string,
|
||||
targets: readonly SshTarget[]
|
||||
): string[] {
|
||||
|
||||
Reference in New Issue
Block a user