Files
OrcaWinandm4air ab331253a0 fix: release canceled working-directory waiter references (#21144)
* fix: release canceled working-directory waiter references

* test: normalize working-directory proof patch

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-09-17 20:12:22 -07:00

69 lines
2.4 KiB
Diff

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<void>((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<void> {
+
+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<void>,
+ holder: WorkingDirectoryWaiterHolder
+): void {
+ void promise.then(
+ () => takeWorkingDirectoryWaiter(holder)?.resolve(),
+ (error: unknown) => takeWorkingDirectoryWaiter(holder)?.reject(error)
+ )
+}
+
+function waitForWorkingDirectoryValidation(
+ shared: Promise<void>,
+ cwd: string,
+ signal: AbortSignal
+): Promise<void> {
+ return new Promise<void>((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)
+ })
+}