Revive pending SSH watcher installs (#2095)

This commit is contained in:
Jinjing 2026-05-16 12:20:51 -07:00 committed by GitHub
parent d7e4431e84
commit e9029feec1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 0 deletions

View File

@ -281,6 +281,41 @@ describe('registerFilesystemWatcherHandlers', () => {
expect(unwatchMock).toHaveBeenCalledTimes(1)
})
it('revives a pending SSH watcher install when a new sender joins after cancellation', async () => {
const args = { worktreePath: '/home/me/repo', connectionId: 'conn-1' }
const senderOne = { isDestroyed: () => false, send: vi.fn(), once: vi.fn(), id: 1 }
const senderTwo = { isDestroyed: () => false, send: vi.fn(), once: vi.fn(), id: 2 }
const unwatchMock = vi.fn()
let resolveWatch!: (unwatch: () => void) => void
const watchMock = vi.fn().mockReturnValue(
new Promise<() => void>((resolve) => {
resolveWatch = resolve
})
)
getSshFilesystemProviderMock.mockReturnValue({ watch: watchMock })
const firstWatch = handlers['fs:watchWorktree']({ sender: senderOne }, args) as Promise<unknown>
await Promise.resolve()
handlers['fs:unwatchWorktree']({ sender: { id: 1 } }, args)
const secondWatch = handlers['fs:watchWorktree'](
{ sender: senderTwo },
args
) as Promise<unknown>
expect(watchMock).toHaveBeenCalledTimes(1)
resolveWatch(unwatchMock)
await Promise.all([firstWatch, secondWatch])
const onEvents = watchMock.mock.calls[0][1]
onEvents([{ path: '/home/me/repo/file.txt', type: 'update' }])
expect(senderOne.send).not.toHaveBeenCalled()
expect(senderTwo.send).toHaveBeenCalledTimes(1)
handlers['fs:unwatchWorktree']({ sender: { id: 2 } }, args)
expect(unwatchMock).toHaveBeenCalledTimes(1)
})
it('registers one destroyed listener for many SSH worktree watches', async () => {
const destroyedCallbacks: (() => void)[] = []
const sender = {

View File

@ -518,6 +518,10 @@ async function installRemoteWatcher(
const inFlight = inFlightRemoteInstalls.get(key)
if (inFlight && !sender.isDestroyed()) {
inFlight.listeners.set(sender.id, sender)
// Why: a new watcher can join after all previous pending listeners
// unwatched but before provider.watch() resolves; revive that install
// instead of inheriting the stale cancellation.
inFlight.cancelled = false
}
const result = await pendingInstall
if (