Repository navigation
Conversation
Plugin activation awaits the VCS branch refresh and the location watcher's repository probe, so every Location boot waited on three to four sequential git rounds before the agent, model, provider and integration lists answered. Each round costs ~40ms on Windows. - Read the remote list with origin's HEAD in one round, and local branches with init.defaultBranch in one more only when no remote HEAD names the default branch. - Cache repository discovery by the .git metadata fingerprint, as Project.resolve already does. - vcs.status no longer checks HEAD before listing; vcs.diff fetches the batched patch with the change list and reads HEAD with the default branch. - Look up commands on Windows with one stat per PATHEXT extension instead of one per case, without throwing on every miss. Adds packages/server/script/benchmark-server.ts, which boots `opencode serve` from any checkout and replays a client opening a location.
There was a problem hiding this comment.
Looks sound to me. On Linux, the server benchmark from this PR (base checkout as --source, then --compare) shows git spawns per reopen dropping from 12 to 9 and first open from 6 to 5, and the branch and working diffs are faster. The core boot-work, which, vcs, git, project and snapshot tests pass, and tsc is clean. I couldn't run the Windows-only which lookup or its test, so the Windows timings are taken from the description.
On the code: skipping the HEAD check in vcs.status is safe, because failed git commands come back as empty output, so an unborn HEAD gives an empty stats list. The new discover cache can't store a failure, since the probe never errors and an empty result is removed from the cache. The rewritten which follows the which package's search step by step.
Public API is unchanged; the benchmark is a dev-only script. No blocking concerns.
Issue for this PR
No issue: found while profiling the server on Windows.
Type of change
What does this PR do?
On Windows each git process costs ~35-40 ms, and opening a Location ran several of them back to back while the agent, model, provider and integration lists waited. Plugin activation awaits every state's notify, and two of them do git work: the VCS branch refresh (2 sequential rounds for a clone, 3 without a remote) and the location watcher's repository probe, a
rev-parsethat project resolution had already answered. That was ~175 ms of the ~200 ms activation flush on reopen.plugin/vcs/git.ts: the default branch reads the remote list together with origin's HEAD, and reads local branches withinit.defaultBranchin one more round only when no remote HEAD answers.vcs.statusno longer checks HEAD first (diffing an unborn HEAD lists nothing).vcs.difffetches the batched patch in the same round as the change list, since chunks name their own files, and branch mode reads HEAD and the default branch together.git.ts:repo.discoveris cached by the.gitmetadata fingerprint, asProject.resolvealready is, so the location watcher and snapshots reuse project discovery.util/which.ts: the Windows lookup stats once per PATHEXT extension instead of once per case and does not throw on each miss: 14.6 → 6.2 ms for a missing command, which the Azure plugin looks up on every Location boot. A test checks it againstwhichwith awkward PATH and PATHEXT values.boot-work.test.ts: a step spawns 8 git processes instead of 9, because snapshot discovery is reused.packages/server/script/benchmark-server.ts(new): bootsopencode servefrom any checkout with isolated state and replays a client opening a location: open, each endpoint warm, reopen, and/api/infolatency while review diffs run, with git spawns per phase.--compareprints before/after.Windows 11, Ryzen 7 7800X3D, Git for Windows 2.48.1. Median of 8 server launches on a generated 3,000-file repo shaped like a clone, with two edits and a new file:
vcs.statusvcs.diffworking (review panel)vcs.diffbranch (review panel)/api/infop99 while diffs runOn effect-smol (2,163 files, clean tree): reopen 245.9 → 156.8 ms,
vcs.status88.5 → 50.4 ms, branch diff 247.8 → 178.7 ms. The working diff is flat there (93.6 → 94.5 ms): on a clean tree the batched patch is a wasted parallel process. Starting four git processes at once also makes the worst single event-loop stall during a diff ~4 ms longer; p99 is unchanged.Not included: starting
mingw64\bin\git.exeinstead of thecmd\git.exelauncher saves another ~10 ms per git call, but the synchronous part ofCreateProcessgrows with the image (~3 ms for the 45 KiB launcher, ~8.4 ms for the 4 MiB git.exe) and lands on the server thread. With it,/api/infop99 during diffs went from 1.0 to 9.1 ms.How did you verify your code works?
bun run script/test.ts: boot-work, vcs, git, snapshot, project, worktree, vcs-init, provider-azure, location-watcher-policy, which, shell, formatter and ripgrep (217 pass). server: vcs, worktree, session-diff and process tests.bun run check, andbun run typecheck:tscin core and server.packages/server, against adevworktree:bun run script/benchmark-server.ts --source <dev worktree> --runs 8 --json before.json, thenbun run script/benchmark-server.ts --runs 8 --compare before.json. Also with--directoryon effect-smol.Visual
Screenshots / recordings
Not a UI change.
Checklist