mirror of
https://github.com/stablyai/orca.git
synced 2026-10-27 16:02:42 +00:00
The six oversized src/main/ipc modules each carried a file-level `eslint-disable max-lines` and ran 427-671 counted lines against a 300-line budget. AGENTS.md calls for splitting rather than suppressing, and config/max-lines-baseline.txt is a shrink-only ratchet, so this removes all six suppressions and prunes their entries (341 -> 335). Pure move, no behavior change. Each file is cut along the seams it already had: pet splits into format allowlist / storage paths / symlink-safe copy / bundle manifest + import; filesystem-auth into path-containment primitives, the config-derived allow-list, and the git-registered root cache; notifications into sound selection, native lifecycle, permission probe, and burst cooldown; crash-reporting into renderer error reports, breadcrumbs, and sender. The IPC surface is proved intact rather than assumed: comparing (method, channel) multisets between HEAD and the split gives 49 registrations across 49 distinct channels on both sides. filesystem-auth's security boundary keeps its acyclic layering -- containment primitives, then allow-list, then root cache, then path-resolution orchestration -- with no layer gaining a back-edge. Also keeps clipboard-ipc-handlers.test.ts under the 800-line test budget. The split had briefly added a redundant vi.mock for isENOENT (byte-identical to the real implementation) that pushed it to 801; the mock is dropped in favor of the real function, with realpath added to the existing node:fs/promises mock. Verified: oxlint clean, ratchet passes, typecheck clean, full unit suite green (the one remaining failure is a pre-existing load flake in an untouched file, green when re-run serially), no new runtime import cycles among 617 modules, and no lint suppression added anywhere.
44 lines
1.5 KiB
TypeScript
44 lines
1.5 KiB
TypeScript
import { lstat } from 'node:fs/promises'
|
|
import { basename } from 'node:path'
|
|
import { isENOENT } from './filesystem-path-containment'
|
|
|
|
/**
|
|
* Re-throw filesystem errors with user-friendly messages.
|
|
* The `wx` flag on writeFile throws a raw EEXIST with no helpful message,
|
|
* so we catch it here and provide context the renderer can display directly.
|
|
*/
|
|
export function rethrowWithUserMessage(error: unknown, targetPath: string): never {
|
|
const name = basename(targetPath)
|
|
if (error instanceof Error && 'code' in error) {
|
|
const code = (error as NodeJS.ErrnoException).code
|
|
if (code === 'EEXIST') {
|
|
throw new Error(`A file or folder named '${name}' already exists in this location`)
|
|
}
|
|
if (code === 'EACCES' || code === 'EPERM') {
|
|
throw new Error(`Permission denied: unable to create '${name}'`)
|
|
}
|
|
}
|
|
throw error
|
|
}
|
|
|
|
/**
|
|
* Ensure `targetPath` does not already exist. Throws if it does.
|
|
*
|
|
* Note: this is a non-atomic check — a concurrent operation could create the
|
|
* path between `lstat` and the caller's next action. Acceptable for a desktop
|
|
* app with low concurrency; `createFile` uses the `wx` flag for an atomic
|
|
* alternative where possible.
|
|
*/
|
|
export async function assertNotExists(targetPath: string): Promise<void> {
|
|
try {
|
|
await lstat(targetPath)
|
|
throw new Error(
|
|
`A file or folder named '${basename(targetPath)}' already exists in this location`
|
|
)
|
|
} catch (error) {
|
|
if (!isENOENT(error)) {
|
|
throw error
|
|
}
|
|
}
|
|
}
|