From 96624a20284f7e6324546deaf3fcb134f82afd3f Mon Sep 17 00:00:00 2001 From: yushengruohui <39661172+yushengruohui@users.noreply.github.com> Date: Wed, 27 May 2026 23:28:48 +0800 Subject: [PATCH 1/2] fix(windows): hide console window for git child processes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The codegraph daemon shells out to git via execFileSync without windowsHide:true. Because the daemon is launched with detached:true (no parent console), Windows allocates a fresh console window for every git child. Each short-lived git invocation makes that window flash on screen — very visible during auto-sync, where many file writes can trigger several git calls per second. This sets windowsHide:true on all 7 git call sites: - src/extraction/index.ts: shared gitOpts (covers ls-files --cached and -o), plus 3 inline opts for rev-parse, check-ignore, and status --porcelain - src/sync/worktree.ts: rev-parse --show-toplevel - src/sync/git-hooks.ts: rev-parse --is-inside-work-tree, rev-parse --git-path hooks mcp/index.ts already passes windowsHide:true when spawning the detached daemon — these git call sites were missed. windowsHide:true is a no-op on macOS and Linux. Fixes #485 --- src/sync/git-hooks.ts | 2 ++ src/sync/worktree.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/src/sync/git-hooks.ts b/src/sync/git-hooks.ts index 3344c5ff9..a657d7545 100644 --- a/src/sync/git-hooks.ts +++ b/src/sync/git-hooks.ts @@ -44,6 +44,7 @@ export function isGitRepo(projectRoot: string): boolean { cwd: projectRoot, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], + windowsHide: true, }).trim(); return out === 'true'; } catch { @@ -61,6 +62,7 @@ function gitHooksDir(projectRoot: string): string | null { cwd: projectRoot, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], + windowsHide: true, }).trim(); if (!out) return null; return path.isAbsolute(out) ? out : path.resolve(projectRoot, out); diff --git a/src/sync/worktree.ts b/src/sync/worktree.ts index 27bfca546..bf370b178 100644 --- a/src/sync/worktree.ts +++ b/src/sync/worktree.ts @@ -35,6 +35,7 @@ export function gitWorktreeRoot(dir: string): string | null { cwd: dir, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], + windowsHide: true, }).trim(); return out ? realpath(out) : null; } catch { From a2cf134287cd89e0753fd36e47fff42ca652cf9a Mon Sep 17 00:00:00 2001 From: yushengruohui <1950249908@qq.com> Date: Wed, 27 May 2026 23:31:34 +0800 Subject: [PATCH 2/2] fix(windows): hide console window for git child processes in extraction Add windowsHide:true to the 4 execFileSync call sites in src/extraction/index.ts (1 shared gitOpts plus 3 inline option objects for rev-parse --show-toplevel, check-ignore -q, and status --porcelain --no-renames). Companion to the previous commit on this branch which covered the sync/ module. See #485 for context. --- src/extraction/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/extraction/index.ts b/src/extraction/index.ts index 95e47e85f..db69d25ad 100644 --- a/src/extraction/index.ts +++ b/src/extraction/index.ts @@ -191,7 +191,7 @@ export function buildDefaultIgnore(rootDir: string): Ignore { * (See issue #193.) */ function collectGitFiles(repoDir: string, prefix: string, files: Set): void { - const gitOpts = { cwd: repoDir, encoding: 'utf-8' as const, timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'] as ['pipe', 'pipe', 'pipe'] }; + const gitOpts = { cwd: repoDir, encoding: 'utf-8' as const, timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'] as ['pipe', 'pipe', 'pipe'], windowsHide: true }; // Tracked files. --recurse-submodules pulls in files from active submodules, // which the index would otherwise represent only as a commit pointer. @@ -241,7 +241,7 @@ function getGitVisibleFiles(rootDir: string): Set | null { const gitRoot = execFileSync( 'git', ['rev-parse', '--show-toplevel'], - { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] } + { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true } ).trim(); if (path.resolve(gitRoot) !== path.resolve(rootDir)) { @@ -250,7 +250,7 @@ function getGitVisibleFiles(rootDir: string): Set | null { execFileSync( 'git', ['check-ignore', '-q', path.resolve(rootDir)], - { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] } + { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true } ); // Directory is gitignored by parent repo — fall back to filesystem walk return null; @@ -291,7 +291,7 @@ function getGitChangedFiles(rootDir: string): GitChanges | null { const output = execFileSync( 'git', ['status', '--porcelain', '--no-renames'], - { cwd: rootDir, encoding: 'utf-8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] } + { cwd: rootDir, encoding: 'utf-8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true } ); const modified: string[] = [];