1import * as Effect from "effect/Effect";
2import * as Semaphore from "effect/Semaphore";
3
4const leases = new Map<string, { semaphore: Semaphore.Semaphore; users: number }>();
5
6/** Coordinates checkout removal and startup across threads using the same resolved cwd. */
7export const withWorkspaceLease = <A, E, R>(
8 cwd: string,
9 effect: Effect.Effect<A, E, R>,
10): Effect.Effect<A, E, R> =>
11 Effect.suspend(() => {
12 const lease = leases.get(cwd) ?? { semaphore: Semaphore.makeUnsafe(1), users: 0 };
13 leases.set(cwd, lease);
14 lease.users++;
15 return lease.semaphore.withPermit(effect).pipe(
16 Effect.ensuring(
17 Effect.sync(() => {
18 lease.users--;
19 if (lease.users === 0) leases.delete(cwd);
20 }),
21 ),
22 );
23 });