Repository navigation
Description
Summary
On Windows, the shared background service (opencode serve --service) runs without a console. When it cold-starts and checks an unpinned git plugin for updates, it spawns git ls-remote without CREATE_NO_WINDOW, so Windows opens a new visible console window (routed through the default terminal application, Windows Terminal) that shows git output on the desktop. Because the spawner is the shared service, the window appears whether the client is the TUI or the Desktop app — it reads as "a git terminal window pops up when OpenCode starts."
Environment
- opencode version: 2.0.15
- OS: Microsoft Windows [版本 10.0.22631.6199] (Windows 11 23H2, x64); default terminal application: Windows Terminal 1.24.11911.0
- Terminal: Windows Terminal;
TERM=xterm-256color,TERM_PROGRAM/COLORTERMunset - Shell:
%ComSpec%=C:\Windows\system32\cmd.exe(interactive shell: PowerShell 7.6.6 in Windows Terminal) - Install/channel: npm global install (
%APPDATA%\npm\node_modules\@opencode\cli), release channel; auto-updated 2.0.14 → 2.0.15 during the captured occurrence - Active plugins:
superpowers@git+https://github.com/obra/superpowers.git(unpinned git spec, global config), local~/.config/opencode/plugins/rtk.ts
Reproduction
- Install OpenCode via npm and configure an unpinned git plugin:
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git"]. - Make sure no background service is running (fresh boot, idle exit, or — as observed — a version update that restarts the service).
- Launch any client (TUI or Desktop) so it cold-starts the shared service.
- Within ~5 seconds of service start, a window titled
C:\Program Files\Git\cmd\git.exeappears on the desktop runninggit ls-remote https://github.com/obra/superpowers.git; when that attempt fails, a second window appears withgit ls-remote ssh://[email protected]/....
Expected Behavior
Service child processes should spawn with CREATE_NO_WINDOW, consistent with the shell-tool pwsh spawns and snapshot git spawns (which are already hidden) — no visible console windows.
Actual Behavior
A visible Windows Terminal window with git content flashes on every service cold start. Window lifetime = ls-remote latency: brief when GitHub is fast, ~27 seconds when GitHub is slow/unreachable, after which the check fails with NpmInstallFailedError: An unknown git error occurred, preceded by an ssh-retry window.
Additional Context
Runtime capture (EnumWindows + IsWindowVisible probe; local time = UTC+8; local paths redacted):
15:37:03.204 WINDOW pid=17476 class=CASCADIA_HOSTING_WINDOW_CLASS title=C:\Program Files\Git\cmd\git.exe
owner-chain: WindowsTerminal.exe(17476)
15:37:04.294 WINDOW pid=6268 class=PseudoConsoleWindow
owner-chain: git.exe(6268): git --no-replace-objects ls-remote https://github.com/obra/superpowers.git
<< opencode.exe(1988): ...\@opencode\cli\bin\opencode.exe serve --service
<< opencode.exe(7244): ...\@opencode\cli\bin\opencode.exe
<< pwsh.exe(11052): C:\Program Files\PowerShell\7\pwsh.exe
15:37:25.262 WINDOW pid=17844 class=PseudoConsoleWindow
owner-chain: git.exe(17844): git --no-replace-objects ls-remote ssh://[email protected]/obra/superpowers.git
<< opencode.exe(1988): ...\opencode.exe serve --service
<< opencode.exe(7244)
<< pwsh.exe(11052)
Service log (verbatim):
timestamp=2026-09-23T07:36:17.611Z level=INFO run=b3ea6081 message="update check" current=2.0.14 latest=2.0.15 role=cli
timestamp=2026-09-23T07:36:29.226Z level=INFO run=b3ea6081 message="spawning process" command=npm args=["install","--global","--force","@opencode/[email protected]"] role=cli
timestamp=2026-09-23T07:37:00.335Z level=INFO run=7bc8a43d ... (service cold start, new version)
timestamp=2026-09-23T07:37:28.114Z level=WARN run=7bc8a43d message="failed to check plugin update" target=superpowers@git+https://github.com/obra/superpowers.git cause="Cause([Fail(NpmInstallFailedError (cause: Error: An unknown git error occurred))])" http.span=27335 role=server
Timeline: 07:36:17 update detected → 07:36:29 npm install (runs inside the client's console — no flash) → 07:37:00 service cold start → 07:37:03 and 07:37:25 visible git windows → 07:37:28 plugin check fails after http.span=27335 ms.
Contrast — same service process, spawns that are hidden correctly (an 8-minute visible-window monitoring session covering 3 snapshot git bursts and dozens of 5-second git polls from an MCP daemon captured zero windows from these paths):
- snapshot git:
--git-dir <data>/snapshot/<hash> ... diff-files / write-tree / ... - MCP daemon git polls every ~5 s (
codebase-memory-mcp) - shell-tool
pwsh -NoLogo -NoProfile -NonInteractive ...spawns
So the missing window-hiding flag appears specific to the plugin-update-check call site (and possibly other cold-start git call sites such as rev-parse / worktree list, which run in the same window).
Reproducibility: intermittent — only when the service cold-starts (update day, first launch of the day), and only noticeable while ls-remote is slow. Observed twice on 2026-09-23 (04:16:22 and 07:37:28 UTC), both right after service cold starts.
Documented workaround (not applied in this environment): pinning the plugin to a full commit hash (superpowers@git+...#<40-char-sha>) skips the update check entirely ("full Git commit hashes stay pinned"). Suggested fixes:
- Pass
CREATE_NO_WINDOWwhen spawning plugin-update-checkgit, consistent with the other spawn sites. - Consider skipping or deferring the
ls-remotecheck on cold start when offline — today it blocks ~27 s, fails, and only produces visible windows.
Activity
dayesann commentedon Oct 14, 2026
Additional data from 2.0.29 (desktop app, Windows 10 19045, git 2.54.0) confirming this and making it reproducible on demand rather than only on a cold start.
On-demand reproduction (no cold start needed)
With an unpinned git plugin (
superpowers@git+https://github.com/obra/superpowers.git) the request takes ~6.9 s, and a window exists for exactly that interval (EnumWindows +IsWindowVisible,ConsoleWindowClass, sampling every 150 ms; local time UTC+8):So it is not a flash: the window lifetime equals the git operation and it stays visible while
ls-remoteretries/fails (hereNpmInstallFailedError: An unknown git error occurred), which is why it reads as a stuck popup. In the same 90 s sampling window, ~12 snapshot/diffgitinvocations produced zero windows.Why it recurs on every launch, not only after a cold start
PluginUpdate.checkcaches its result in an in-memory map with a 24 h TTL, so the cache dies with the service. The desktop app starts the service together with the app, so the git check runs on every launch.Code path in the bundled CLI, for the fix
@opencode/AppProcesspasseswindowsHide: !0forStandardCommandspawns (and the kill path usespr.exec("taskkill ...", { windowsHide: !0 })), so snapshot/shell children are hidden.Npm.checkresolves with{ preferOnline: true, noGitRevCache: true, ignoreScripts: true }and, fortype === "git", goes through the bundled npm git code (@npmcli/git), which shells out togitwithout any window-hiding flag. That spawn is the one that gets a fresh visible console because the service has no console. It is also visible in the logs: only theAppProcessspawns emit "spawning process" lines, the failing plugin check does not.Why pinning to a commit works, quantified
Npm.checkearly-returns for immutable specs (if (!a.mutable) return false), so a full 40-hex committish never invokes git at all. Measured after pinning both git plugins to their currently installed commits:gitprocess spawned, zero console windows over a 90 s sampling windowSuggested fix remains the same: give this npm-git spawn the same
windowsHide/CREATE_NO_WINDOWtreatment asAppProcess.