shell.resolveSpawnCommand walks PATH × PATHEXT with statSync on every spawn and picks Git's cmd launcher
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
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:294callsresolveSpawnCommandfor every process.resolveSpawnExecutableWithNode(packages/shared/src/shell.ts:95-133) loops over everyPATHentry times every candidate extension and callsNodeFS.statSyncfor each. Nothing is memoized, and the work is synchronous on the event loop.- On this machine that is ~22 ms per spawn. 2345
shell.resolveSpawnCommandspans in a 76-minute trace; ~580 s over 13 h. - Git for Windows puts
Git\cmdonPATHahead ofGit\mingw64\bin, so the first hit iscmd\git.EXE, a launcher that execs the realmingw64\bin\git.exe. Every git command is two process creations (plus aconhost.exeeach, see #2537).
Steps to reproduce
- Windows with Git for Windows installed the default way.
- Run the desktop app or
t3 servewith a git project and let the background sweeps run (see #11220). - Compare
shell.resolveSpawnCommandspan durations inserver.trace.ndjson, and trace process creation: eachrunGitCommandshowsgit.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 @ 211618fd9f.
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read packages/shared/src/shell.ts:95-133 and processRunner.ts:294 to trace resolveSpawnCommand and its synchronous PATH/PATHEXT scan. Reproduce on Windows with Git for Windows and inspect shell.resolveSpawnCommand spans and process creation. Done means repeated resolutions reuse results for the same inputs and git resolves to the real binary rather than the cmd launcher.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- performance, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100