mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 00:03:45 +00:00
The user report F0BDXH978GJ surfaced 'Error invoking remote method fs:readDir' — Electron's opaque message when the main-process handler throws. On Windows this is typically a WSL \wsl$ / \wsl.localhostUNC path or network drive failing realpath/readdir after the distro or share goes away, or a dropped SSH provider. Nothing recorded which throw site fired or what kind of path was involved, so the crash report carried no actionable cause. Wrap the fs:readDir handler to record an 'fs_readdir_error' breadcrumb on throw, tagging the throw site (ssh-provider | authorize | readdir), the error name/code, and a REDACTED path shape (isUNC, isWsl, driveLetter, hasConnectionId) — never the raw path. The error is re-thrown unchanged, so renderer behavior is identical; only crash reports gain structured context. Pure classification lives in readdir-error-diagnostics.ts (8 unit tests covering WSL UNC, \wsl$, network share, drive letter, SSH, and no-path-leak); 4 handler tests assert the breadcrumb fires per throw site and not on success. Co-authored-by: Neil <neil@stably.ai>
58 lines
2.0 KiB
TypeScript
58 lines
2.0 KiB
TypeScript
import type { CrashReportBreadcrumbData } from '../../shared/crash-reporting'
|
|
|
|
export type ReadDirThrowSite = 'ssh-provider' | 'authorize' | 'readdir'
|
|
|
|
/**
|
|
* Redacted shape of a directory path for crash diagnostics.
|
|
*
|
|
* Why shape, not the path: "Error invoking remote method 'fs:readDir'" reaches
|
|
* the renderer with no cause. We want to know *what kind* of path failed (WSL
|
|
* UNC, network share, drive letter, SSH) without recording the path itself —
|
|
* even though breadcrumbs are path-redacted downstream, never collecting the
|
|
* raw path is the safer default.
|
|
*/
|
|
export function describeReadDirPathShape(
|
|
dirPath: string,
|
|
connectionId: string | undefined
|
|
): CrashReportBreadcrumbData {
|
|
const isUNC = /^[\\/]{2}/.test(dirPath)
|
|
const lower = dirPath.toLowerCase()
|
|
// \\wsl$\ and \\wsl.localhost\ (either slash direction) are WSL UNC roots.
|
|
const isWsl = isUNC && (lower.includes('wsl$') || lower.includes('wsl.localhost'))
|
|
const driveLetterMatch = /^([a-zA-Z]):[\\/]/.exec(dirPath)
|
|
return {
|
|
hasConnectionId: Boolean(connectionId),
|
|
isUNC,
|
|
isWsl,
|
|
...(driveLetterMatch ? { driveLetter: driveLetterMatch[1].toUpperCase() } : {})
|
|
}
|
|
}
|
|
|
|
function errorCode(error: unknown): string | undefined {
|
|
if (error && typeof error === 'object' && 'code' in error) {
|
|
const code = (error as { code?: unknown }).code
|
|
if (typeof code === 'string') {
|
|
return code
|
|
}
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
/**
|
|
* Build the redacted breadcrumb payload for a thrown fs:readDir call: which
|
|
* throw site fired, the error code/name, and the path shape — no raw path.
|
|
*/
|
|
export function buildReadDirErrorBreadcrumb(args: {
|
|
dirPath: string
|
|
connectionId: string | undefined
|
|
throwSite: ReadDirThrowSite
|
|
error: unknown
|
|
}): CrashReportBreadcrumbData {
|
|
return {
|
|
throwSite: args.throwSite,
|
|
errorName: args.error instanceof Error ? args.error.name : typeof args.error,
|
|
...(errorCode(args.error) ? { errorCode: errorCode(args.error)! } : {}),
|
|
...describeReadDirPathShape(args.dirPath, args.connectionId)
|
|
}
|
|
}
|