diff --git a/src/main/providers/working-directory-validation.ts b/src/main/providers/working-directory-validation.ts index 688cc85244..cf098cad2c 100644 --- a/src/main/providers/working-directory-validation.ts +++ b/src/main/providers/working-directory-validation.ts @@ -165,12 +165 @@ export function validateWorkingDirectoryAsync( - const shared = validation - // The shared probe outlives this caller; keep it from surfacing as unhandled. - void shared.catch(() => {}) - return new Promise((resolve, reject) => { - const onAbort = (): void => reject(new WorkingDirectoryValidationAbortedError(cwd)) - if (signal.aborted) { - onAbort() - return - } - signal.addEventListener('abort', onAbort, { once: true }) - shared.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort)) - }) + return waitForWorkingDirectoryValidation(validation, cwd, signal) @@ -204,0 +194,49 @@ async function probeWorkingDirectory(cwd: string): Promise { + +type WorkingDirectoryWaiterHolder = { + waiter: { + signal: AbortSignal + onAbort: () => void + resolve: () => void + reject: (error: unknown) => void + } | null +} + +function takeWorkingDirectoryWaiter( + holder: WorkingDirectoryWaiterHolder +): WorkingDirectoryWaiterHolder['waiter'] { + const waiter = holder.waiter + holder.waiter = null + waiter?.signal.removeEventListener('abort', waiter.onAbort) + return waiter +} + +// Keep reaction order while an abandoned caller's signal and resolver become collectible. +function observeWorkingDirectoryValidation( + promise: Promise, + holder: WorkingDirectoryWaiterHolder +): void { + void promise.then( + () => takeWorkingDirectoryWaiter(holder)?.resolve(), + (error: unknown) => takeWorkingDirectoryWaiter(holder)?.reject(error) + ) +} + +function waitForWorkingDirectoryValidation( + shared: Promise, + cwd: string, + signal: AbortSignal +): Promise { + return new Promise((resolve, reject) => { + const holder: WorkingDirectoryWaiterHolder = { waiter: null } + const onAbort = (): void => { + takeWorkingDirectoryWaiter(holder)?.reject(new WorkingDirectoryValidationAbortedError(cwd)) + } + holder.waiter = { signal, onAbort, resolve, reject } + if (signal.aborted) { + onAbort() + return + } + signal.addEventListener('abort', onAbort, { once: true }) + observeWorkingDirectoryValidation(shared, holder) + }) +}