Skip to content

shell.resolveSpawnCommand walks PATH × PATHEXT with statSync on every spawn and picks Git's cmd launcher #11221

Description

@SkiTee3000

What happened

Every child process the server starts goes through resolveSpawnCommand, which re-scans PATH synchronously each time and, on Git for Windows, resolves git to the cmd\git.exe launcher. Each git command is therefore two processes, and the lookup itself burns event-loop time on every spawn.

Diagnosis

  • processRunner.ts:294 calls resolveSpawnCommand for every process. resolveSpawnExecutableWithNode (packages/shared/src/shell.ts:95-133) loops over every PATH entry times every candidate extension and calls NodeFS.statSync for each. Nothing is memoized, and the work is synchronous on the event loop.
  • On this machine that is ~22 ms per spawn. 2345 shell.resolveSpawnCommand spans in a 76-minute trace; ~580 s over 13 h.
  • Git for Windows puts Git\cmd on PATH ahead of Git\mingw64\bin, so the first hit is cmd\git.EXE, a launcher that execs the real mingw64\bin\git.exe. Every git command is two process creations (plus a conhost.exe each, see [Bug]: Frequent cmd.exe / conhost flashes on Windows from provider probe & VCS process kill paths #2537).

Steps to reproduce

  1. Windows with Git for Windows installed the default way.
  2. Run the desktop app or t3 serve with a git project and let the background sweeps run (see Thread PR discovery and settlement sweeps run every minute without client demand, and their caches expire before the next sweep #11220).
  3. Compare shell.resolveSpawnCommand span durations in server.trace.ndjson, and trace process creation: each runGitCommand shows git.exe (launcher) → git.exe (mingw64).

Expected: resolve a command once per (command, PATH, PATHEXT) and reuse it; resolve git to the real binary.
Actual: a full synchronous PATH scan per spawn, and a two-process git.

Version

0.0.41-nightly.20260908.1414 (desktop); code unchanged on main @ 211618f.

Environment

Windows 11 Pro 26200, git 2.55.0.windows.5, gh 2.100.0.

Evidence

shell.resolveSpawnCommand    2345 spans / 76 min   (~22 ms each on this machine)
processRunner.runProcessCore 2345

Related issues

#2537 (per-process console cost), #7570 (stale shim resolution, closed). Neither covers the missing memoization or the launcher choice.

Fix applied or workaround

None. PATH order could be changed by hand, but the resolver would still scan on every spawn.

Filed by

Claude Code (Claude Fable 5.1), following the t3 triage playbook from a checkout of main.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions