diff --git a/browse/src/find-browse.ts b/browse/src/find-browse.ts index ab9f6a54d..5b0c1742e 100644 --- a/browse/src/find-browse.ts +++ b/browse/src/find-browse.ts @@ -8,17 +8,31 @@ import { accessSync, constants } from 'fs'; import { join } from 'path'; import { homedir } from 'os'; +import { spawnSync as nodeSpawnSync } from 'child_process'; + +const IS_WINDOWS = process.platform === 'win32'; // ─── Binary Discovery ─────────────────────────────────────────── function getGitRoot(): string | null { try { + if (IS_WINDOWS) { + const proc = nodeSpawnSync('git', ['rev-parse', '--show-toplevel'], { + stdout: 'pipe', + stderr: 'pipe', + timeout: 2_000, + windowsHide: true, + }); + if (proc.error || proc.status !== 0) return null; + return proc.stdout.toString().trim() || null; + } const proc = Bun.spawnSync(['git', 'rev-parse', '--show-toplevel'], { stdout: 'pipe', stderr: 'pipe', + timeout: 2_000, }); if (proc.exitCode !== 0) return null; - return proc.stdout.toString().trim(); + return proc.stdout.toString().trim() || null; } catch { return null; } diff --git a/browse/test/cli-windows-hide.test.ts b/browse/test/cli-windows-hide.test.ts index 73e377ec4..3f450bd34 100644 --- a/browse/test/cli-windows-hide.test.ts +++ b/browse/test/cli-windows-hide.test.ts @@ -14,6 +14,7 @@ import * as path from 'node:path'; const ROOT = path.resolve(import.meta.dir, '..', '..'); const CLI = path.join(ROOT, 'browse', 'src', 'cli.ts'); const CONFIG = path.join(ROOT, 'browse', 'src', 'config.ts'); +const FIND_BROWSE = path.join(ROOT, 'browse', 'src', 'find-browse.ts'); const FILE_PERMISSIONS = path.join(ROOT, 'browse', 'src', 'file-permissions.ts'); function read(filePath: string): string { @@ -53,6 +54,18 @@ describe('#1784 Windows console flash suppression', () => { ); }); + test('find-browse git probe uses hidden Node spawnSync on Windows and keeps Bun on POSIX', () => { + const body = read(FIND_BROWSE); + const hiddenGitSpawns = body.match( + /nodeSpawnSync\(\s*['"]git['"][\s\S]{0,250}windowsHide:\s*true/g, + ) || []; + expect(body).toContain("process.platform === 'win32'"); + expect(hiddenGitSpawns).toHaveLength(1); + expect(body).toMatch( + /Bun\.spawnSync\(\s*\[\s*['"]git['"],\s*['"]rev-parse['"],\s*['"]--show-toplevel['"]/, + ); + }); + test('icacls ACL helpers pass windowsHide to execFileSync', () => { const body = read(FILE_PERMISSIONS); const hiddenIcaclsCalls = body.match(