fix(cli): stop eager file watchers on JetBrains - #12897
Conversation
The JetBrains backend eagerly warmed the v2 location stack for every instance, which starts a native @parcel/watcher subscription that lives for the whole session. On macOS FSEvents watches the entire subtree recursively (the ignore list is only a userspace filter), so this always-on watcher burns CPU and leaks native memory while the IDE is idle — the cause of the 150%+ CPU and multi-GB RSS growth reported in `kilo serve` on macOS. The watcher's only consumer is the CLI/TUI sidebar branch label via the vcs.branch.updated event. JetBrains, like VS Code, has its own git integration and does not consume that event, so eager watchers are pure overhead for it. Extend the existing VS Code gate to also exclude jetbrains; the standalone CLI/TUI stays eager, and editor clients still build the stack lazily if a real file/pty route needs it. Fixes #12721
Code Review SummaryStatus: No Issues Found | Recommendation: Merge lgtm — the one-line gate extension is correct and matches the established VS Code pattern. Verified that the JetBrains plugin spawns Files Reviewed (3 files)
Reviewed by kimi-k3 · Input: 48.2K · Output: 5.5K · Cached: 258K Review guidance: REVIEW.md from base branch |
…atchers fix(cli): stop eager file watchers on JetBrains
What
Extend the existing VS Code watcher gate so the JetBrains client also skips eagerly warming the v2 location stack. One-line behavioral change in
KilocodeWatcher.eager():Why
Reported in #12721: on macOS, the JetBrains-spawned
kilo serveprocess pins 150–198% CPU and grows RSS to 10+ GB while idle. VS Code does not reproduce it.The cause is a structural difference between the two clients.
KilocodeWatchereagerly warms the location stack for every instance and holds it for the whole session, which starts a native@parcel/watchersubscription. This gate was already turned off for VS Code (commit160b0666, "avoid eager worktree watchers") but left on for JetBrains.On macOS,
@parcel/watcheruses FSEvents, which watches the entire subtree recursively at the kernel level — theignorelist is only a userspace post-filter. So an always-on watcher on a churny workspace (Rider/ReSharper constantly touch.gitand build outputs) keeps receiving and processing every event, and the per-event fiber fork amplifies it into CPU burn and native-memory growth (RSS, not JS heap).That work has no consumer on JetBrains:
Vcs, which publishesvcs.branch.updated.vcs.branch.updatedis the CLI/TUI sidebar branch label (packages/tui/src/context/sync.tsx).git branch --show-currentand never subscribes to the event (verified — no consumer inpackages/kilo-jetbrains/).So the eager watcher is pure idle overhead for JetBrains, exactly as it was for VS Code.
Behavior after this change
Testing
From
packages/opencode/:bun test ./test/kilocode/instance-vcs-watcher.test.ts— added aeager("jetbrains") === falsecase; all 4 tests pass (incl. the live branch-update test proving the standalone CLI still watches). Note: the suite must run withKILO_CLIENTunset (as in CI); inside a Kilo session shellKILO_CLIENT=vscodeis inherited and skewseager(undefined).bun run typecheck— clean.bun run script/check-opencode-annotations.ts --worktree— no markers needed (kilocode/-owned path).Rollout note
JetBrains runs a pinned, downloaded CLI release, so this fix reaches JetBrains users only after a CLI release is published and the pin in
packages/kilo-jetbrains/package.jsonis bumped to it. Interim user workaround: launch withKILO_EXPERIMENTAL_DISABLE_FILEWATCHER=true.Fixes #12721