mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
fix(ssh): let agent session history recover once the relay is ready
Reported against the adhoc build: a workspace whose editor was loading remote files perfectly still showed "SSH relay is not ready" and "0 shown · 0 recent" in the Agent Session History panel, permanently. That string is what the relay throws before it is ready, which is ordinary at startup and again for the window a reconnect leaves the session not-ready. The panel had three refresh triggers — mount, window refocus, and a newly seen agent session id — and none of them fire when the relay simply becomes ready. So a transient startup error became a stuck panel next to a workspace that plainly worked, which is why the report described it as broken while everything else was fine. The file explorer already recovers from exactly this, off exactly this signal, with the rationale written down at use-file-explorer-tree-load-effects.ts: it loads before SSH providers are registered, so it retries when sshConnectedGeneration bumps. This panel simply never did. Same idiom, same gate — only retries when there was a prior error, so a local workspace or one that already listed fine does not rescan every time some unrelated host connects. Two tests in the existing suite. The retry one fails on the unfixed code with "the panel never retried after SSH became ready"; the second pins the gate, since a retry that fires on every connection bump would turn one bug into a rescan storm.
This commit is contained in:
@@ -755,4 +755,49 @@ describe('useAiVaultSessionRefresh in-app agent session behavior', () => {
|
||||
await setAgentStatuses({ 'pane-2': makeAgentEntry('sess-2', 'working') })
|
||||
expect(listSessionsMock).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
|
||||
// Reported against an adhoc build: a workspace whose editor was loading files fine still showed
|
||||
// "SSH relay is not ready" with "0 shown · 0 recent" in this panel. That error is what the relay
|
||||
// throws before it is ready, which is ordinary at startup and for the window a reconnect leaves it
|
||||
// not-ready — but nothing here retried on the relay simply becoming ready. The remaining triggers
|
||||
// are mount, window refocus and a new agent session id, so the error stuck while the rest of the
|
||||
// workspace worked. The file explorer already recovers off this same signal.
|
||||
it('retries after a not-ready failure once the SSH connection lands', async () => {
|
||||
listSessionsMock.mockRejectedValueOnce(new Error('SSH relay is not ready'))
|
||||
await renderHook(['/home/neil/projects/orca'])
|
||||
await flushMicrotasks()
|
||||
|
||||
expect(latest?.error).toBe('SSH relay is not ready')
|
||||
const callsWhileBroken = listSessionsMock.mock.calls.length
|
||||
|
||||
listSessionsMock.mockResolvedValue(EMPTY_RESULT)
|
||||
await act(async () => {
|
||||
useAppStore.setState({ sshConnectedGeneration: 1 })
|
||||
})
|
||||
await flushMicrotasks()
|
||||
|
||||
expect(
|
||||
listSessionsMock.mock.calls.length,
|
||||
'the panel never retried after SSH became ready'
|
||||
).toBeGreaterThan(callsWhileBroken)
|
||||
expect(latest?.error).toBeNull()
|
||||
})
|
||||
|
||||
it('does not rescan on a connection bump when the last listing succeeded', async () => {
|
||||
// Gated on a prior error so a local workspace, or one that already listed fine, does not rescan
|
||||
// every time some unrelated host connects.
|
||||
listSessionsMock.mockResolvedValue(EMPTY_RESULT)
|
||||
await renderHook(['/home/neil/projects/orca'])
|
||||
await flushMicrotasks()
|
||||
|
||||
expect(latest?.error).toBeNull()
|
||||
const callsWhileHealthy = listSessionsMock.mock.calls.length
|
||||
|
||||
await act(async () => {
|
||||
useAppStore.setState({ sshConnectedGeneration: 1 })
|
||||
})
|
||||
await flushMicrotasks()
|
||||
|
||||
expect(listSessionsMock.mock.calls.length).toBe(callsWhileHealthy)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -267,6 +267,27 @@ export function useAiVaultSessionRefresh(
|
||||
void refresh({ force: false, reuseLoadedDepth: true })
|
||||
}, [executionHostScope, refresh, scanScopeKey])
|
||||
|
||||
// Why: this panel can query the relay before it is ready — at startup, and again for the window
|
||||
// in which a reconnect leaves the session not-ready — and the query throws 'SSH relay is not
|
||||
// ready'. Nothing else here retries: the remaining triggers are mount, window refocus and a new
|
||||
// agent session id, so a user whose workspace is otherwise working sits on that error
|
||||
// indefinitely. The file explorer already recovers this way for the same reason
|
||||
// (use-file-explorer-tree-load-effects.ts); this panel simply never did.
|
||||
//
|
||||
// Gated on a prior error so a local workspace, or one that already listed fine, does not rescan
|
||||
// every time some other host connects.
|
||||
const sshConnectedGeneration = useAppStore((s) => s.sshConnectedGeneration)
|
||||
const sshGenerationRef = useRef(sshConnectedGeneration)
|
||||
useEffect(() => {
|
||||
if (sshConnectedGeneration <= sshGenerationRef.current) {
|
||||
return
|
||||
}
|
||||
sshGenerationRef.current = sshConnectedGeneration
|
||||
if (error !== null) {
|
||||
void refresh({ background: true, force: false })
|
||||
}
|
||||
}, [sshConnectedGeneration, error, refresh])
|
||||
|
||||
// Refocus checks the shared host cache without forcing another transcript scan.
|
||||
useEffect(() => {
|
||||
const onRefocus = (): void => {
|
||||
|
||||
Reference in New Issue
Block a user