mirror of
https://github.com/stablyai/orca.git
synced 2026-10-16 08:03:09 +00:00
* fix(worktrees): stop a failed worktree scan from pruning as an authoritative empty listing A `git worktree list` that could not run at all — a WSL distro that stopped resolving, a hung mount, a git binary that errored — was softened to `[]` by the lenient listing path, so the detected scan published it as `authoritative: true, worktrees: []`. That disables the #1158 retention guard, drops every persisted tab for the repo, and the pruned session is written back to disk on the next launch. The loss is permanent, not a transient glitch. Route the detected scan through a strict listing that still reports the two genuinely empty states (repo path gone, not a Git repo) as `[]`. Everything else rejects, so the existing catch answers `authoritative: false` and the destructive halves (`rememberLocalWorktreeRoots`, `pruneLineageForMissingRepoWorktrees`) never see a failed scan. Also make the failure readable: wsl.exe reports its own launch failures as exit 0xFFFFFFFF with an EMPTY stderr and the `Wsl/Service/WSL_E_*` line on stdout as UTF-16LE, which is why the field bundle carried a git error with no text. Set WSL_UTF8 for WSL-routed git (matching the wsl runner, #9010) and attach that stdout diagnostic to the error so `git.exec` spans name the cause. * fix(worktrees): surface a failed worktree scan's cause on the repo header with a retry A failed scan now travels with its reason (optional unavailableReason on DetectedWorktreeListResult), the repo header shows it with click-to-retry, and the WSL deleted-guest-directory shape measured on a real Windows host is pinned as retained-not-pruned.
56 lines
2.2 KiB
TypeScript
56 lines
2.2 KiB
TypeScript
import type { ResolvedCommand } from './wsl-command-resolution'
|
|
|
|
/** wsl.exe's own launch-failure exit, distinct from any status the guest process can return. */
|
|
export const WSL_HOST_FAILURE_EXIT_CODE = 0xffffffff
|
|
|
|
function outputText(value: unknown): string {
|
|
if (typeof value === 'string') {
|
|
return value
|
|
}
|
|
return Buffer.isBuffer(value) ? value.toString('utf8') : ''
|
|
}
|
|
|
|
/**
|
|
* The message wsl.exe prints when it — not the guest — failed: a distro that was renamed or
|
|
* removed, or a VM that would not start.
|
|
*
|
|
* Why this needs decoding at all: wsl.exe exits 0xFFFFFFFF, leaves stderr EMPTY, and writes
|
|
* `Error code: Wsl/Service/WSL_E_*` to stdout, so every caller that reports stderr reports nothing.
|
|
* NULs are stripped because a wsl.exe that ignores WSL_UTF8 writes that line as UTF-16LE (#9010).
|
|
*/
|
|
export function readWslHostFailureDiagnostic(
|
|
error: unknown,
|
|
command: ResolvedCommand
|
|
): string | null {
|
|
if (!command.wsl || !error || typeof error !== 'object') {
|
|
return null
|
|
}
|
|
const { code, status, stdout, stderr } = error as {
|
|
code?: unknown
|
|
status?: unknown
|
|
stdout?: unknown
|
|
stderr?: unknown
|
|
}
|
|
const exitCode = typeof code === 'number' ? code : typeof status === 'number' ? status : null
|
|
// A guest failure always explains itself on stderr; an empty one plus this exit is the host.
|
|
if (exitCode !== WSL_HOST_FAILURE_EXIT_CODE || outputText(stderr).trim().length > 0) {
|
|
return null
|
|
}
|
|
const diagnostic = outputText(stdout).replaceAll('\u0000', '').trim()
|
|
return diagnostic.length > 0 ? diagnostic : 'wsl.exe reported no diagnostic.'
|
|
}
|
|
|
|
/**
|
|
* Move a wsl.exe host failure into the error's message, which is what `git.exec` spans record ahead
|
|
* of the stack. Left untouched when the failure came from git itself.
|
|
*/
|
|
export function annotateWslHostFailure(error: unknown, command: ResolvedCommand): unknown {
|
|
const diagnostic = readWslHostFailureDiagnostic(error, command)
|
|
if (diagnostic === null || !(error instanceof Error) || !command.wsl) {
|
|
return error
|
|
}
|
|
const distro = command.wsl.distro
|
|
error.message = `wsl.exe host failure (distro "${distro}"): ${diagnostic}\n${error.message}`
|
|
return Object.assign(error, { wslHostFailure: true, wslDistro: distro })
|
|
}
|