mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 10:08:13 +00:00
fix(terminal): a WSL pane a relaunched window reattached keeps its folder when slept (#33496)
After an app relaunch, the window reattaches a live pane without its spawn environment, so the daemon client never learned the pane's ORCA_PANE_KEY. Sleep then skipped the folder read for it, and the pane woke at its spawn folder. A move's kill-at-quiesced rollback also put a pane `cd`'d before the relaunch back at the project root (awin verify-11, 5e). Sleep now takes the pane key from the daemon's session list when it knows the session's distro but not its key. That is the same one `listSessions` the adoption of an unattached session already uses. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -184,6 +184,28 @@ describe('a sleeping bridge WSL pane keeps its shell folder', () => {
|
||||
expect(checkpointCwd(id)).toBe(`${WSL_CWD}\\deep\\er`)
|
||||
})
|
||||
|
||||
// awin verify-11, 5e: a pane the relaunched window reattached (no spawn env, so no pane key)
|
||||
// slept at its spawn folder.
|
||||
it('reads it for a pane a relaunched app reattached without its spawn environment', async () => {
|
||||
const before = new DaemonPtyAdapter({ socketPath, tokenPath, historyPath: historyDir() })
|
||||
const { id } = await before.spawn({
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
cwd: WSL_CWD,
|
||||
env: { ORCA_PANE_KEY: PANE_KEY },
|
||||
sessionId: 'repo::/repo@@reattached'
|
||||
})
|
||||
lastSubprocess._simulateData('$ cd deep/er\r\n')
|
||||
await before.disconnectOnly()
|
||||
adapter = new DaemonPtyAdapter({ socketPath, tokenPath, historyPath: historyDir() })
|
||||
await adapter.attach(id)
|
||||
|
||||
await adapter.shutdown(id, { immediate: true, keepHistory: true })
|
||||
|
||||
expect(readRows).toHaveBeenCalledWith('Ubuntu', expect.any(Number), { running: true })
|
||||
expect(checkpointCwd(id)).toBe(`${WSL_CWD}\\deep\\er`)
|
||||
})
|
||||
|
||||
it('keeps the spawn folder when the distro cannot be read', async () => {
|
||||
readRows.mockResolvedValue(null)
|
||||
adapter = new DaemonPtyAdapter({ socketPath, tokenPath, historyPath: historyDir() })
|
||||
|
||||
@@ -138,8 +138,10 @@ export abstract class DaemonPtyProcessInspection extends DaemonPtyBufferSnapshot
|
||||
}
|
||||
|
||||
/**
|
||||
* A session this client never spawned or reattached, such as one a relaunched app's window has
|
||||
* not reopened: adopted before its Sleep, or that Sleep writes no checkpoint and keeps no folder.
|
||||
* Before a Sleep, what only the daemon still knows about a session: one this client never
|
||||
* spawned or reattached (a relaunched window has not reopened it) is adopted, or that Sleep
|
||||
* writes no checkpoint; one it reattached has no spawn environment, so no pane key to read its
|
||||
* WSL shell's folder by.
|
||||
*/
|
||||
protected async adoptListedSessionForSleep(
|
||||
sessionId: string,
|
||||
@@ -147,11 +149,16 @@ export abstract class DaemonPtyProcessInspection extends DaemonPtyBufferSnapshot
|
||||
): Promise<void> {
|
||||
// Why active too: a session this client suspended after a seed failure must stay suspended,
|
||||
// or its fresh-only screen would replace the history it was restored from.
|
||||
if (
|
||||
!this.historyManager ||
|
||||
this.historyManager.hasWriter(sessionId) ||
|
||||
this.activeSessionIds.has(sessionId)
|
||||
) {
|
||||
const needsAdoption =
|
||||
!!this.historyManager &&
|
||||
!this.historyManager.hasWriter(sessionId) &&
|
||||
!this.activeSessionIds.has(sessionId)
|
||||
const needsPaneKey =
|
||||
process.platform === 'win32' &&
|
||||
!needsAdoption &&
|
||||
!this.wslPaneKeysBySessionId.has(sessionId) &&
|
||||
this.wslDistrosBySessionId.get(sessionId) !== undefined
|
||||
if (!needsAdoption && !needsPaneKey) {
|
||||
return
|
||||
}
|
||||
const result = await this.client.request<ListSessionsResult>(
|
||||
@@ -160,8 +167,10 @@ export abstract class DaemonPtyProcessInspection extends DaemonPtyBufferSnapshot
|
||||
remainingDaemonRequestTimeoutMs(deadlineMs)
|
||||
)
|
||||
const session = result.sessions.find((entry) => entry.sessionId === sessionId && entry.isAlive)
|
||||
if (session) {
|
||||
if (session && needsAdoption) {
|
||||
await this.adoptLiveSession(session, { activeOnlyIfReconciled: true })
|
||||
} else if (session?.wslDistro && session.paneKey) {
|
||||
this.wslPaneKeysBySessionId.set(sessionId, session.paneKey)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user