mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 16:03:26 +00:00
Destructive worktree removal proves every PTY is physically dead before it touches the filesystem. When a stop RPC failed, it re-listed the provider to check whether the PTY had actually exited — but on the *same* deadline the sweeps had just spent. A slow-but-successful sweep therefore reached the re-list with ~0ms of budget, timed out, and reported "unverifiable", which the gate treated as "still live". `--force` never reached this gate, so the workspace became permanently unremovable and every retry failed identically. - Verification now gets its own 2s window instead of inheriting an exhausted deadline, so an already-exited PTY can be proven exited. - The verdict distinguishes live / unverifiable / exited, and the error names the blocking PTY ids plus the escape hatch instead of only the worktree. - `--force` propagates to the gate (`allowUnverifiedStop`), downgrading an unproven stop to a loud warning so removal can always complete. Extracts `settleBeforeDeadline` and the verification logic into their own modules to stay under max-lines.
51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
/**
|
|
* Races `run()` against an absolute deadline (epoch ms).
|
|
*
|
|
* Without `failClosedError` the call is best-effort: a timeout or a rejection
|
|
* resolves to `fallback`. With it, both surface as a rejection so destructive
|
|
* callers can block on unproven work — `failClosedOnRunError` narrows which
|
|
* rejections count (some are benign sentinels).
|
|
*/
|
|
export async function settleBeforeDeadline<T>(
|
|
run: () => Promise<T>,
|
|
fallback: T,
|
|
deadline: number,
|
|
failClosedError?: Error,
|
|
failClosedOnRunError: (error: unknown) => boolean = () => true
|
|
): Promise<T> {
|
|
const remaining = deadline - Date.now()
|
|
if (remaining <= 0) {
|
|
if (failClosedError) {
|
|
throw failClosedError
|
|
}
|
|
return fallback
|
|
}
|
|
return new Promise((resolve, reject) => {
|
|
let settled = false
|
|
const finish = (value: T): void => {
|
|
if (settled) {
|
|
return
|
|
}
|
|
settled = true
|
|
clearTimeout(timer)
|
|
resolve(value)
|
|
}
|
|
const fail = (error: unknown): void => {
|
|
if (settled) {
|
|
return
|
|
}
|
|
settled = true
|
|
clearTimeout(timer)
|
|
reject(error)
|
|
}
|
|
const timer = setTimeout(
|
|
() => (failClosedError ? fail(failClosedError) : finish(fallback)),
|
|
remaining
|
|
)
|
|
timer.unref?.()
|
|
void run().then(finish, (error: unknown) =>
|
|
failClosedError && failClosedOnRunError(error) ? fail(error) : finish(fallback)
|
|
)
|
|
})
|
|
}
|