Skip to content

windows: plugin update check spawns git in a visible console window #55457

Closed as duplicate

Description

@dayesann

Summary

On Windows, every time the OpenCode desktop app starts, an empty console window titled C:\Program Files\Git\cmd\git.exe pops up and stays visible for several seconds. It comes from the plugin update check, which runs git for git-sourced plugins (e.g. git+https://...). Every other child process OpenCode spawns passes windowsHide: true; this code path does not, and because the background service has no console, Windows allocates a brand-new visible console window for the git child.

Environment

  • opencode version: 2.0.29 (desktop app, bundled CLI 2.0.29). A separately installed CLI on PATH reports 2.0.18.
  • OS: Windows 10.0.19045 (win32 x64)
  • Terminal: OpenCode desktop app (Electron), not a terminal client
  • Shell: C:\Windows\system32\cmd.exe
  • Install/channel: desktop app (@opencode-aidesktop, packaged, channel latest)
  • Active plugins:
    • superpowers@git+https://github.com/obra/superpowers.git (project config)
    • compound-engineering@git+https://github.com/EveryInc/compound-engineering-plugin.git (global config)
    • opencode-wakatime (registry spec; fails to load in V2 for unrelated reasons)
    • two local plugins

Reproduction

  1. On Windows, configure at least one plugin from a git spec, e.g. "plugin": ["superpowers@git+https://github.com/obra/superpowers.git"].
  2. Start the OpenCode desktop app (it launches the bundled CLI as opencode-cli.exe serve --service, which has no console).
  3. Let the plugin update check run at startup.
  4. A console window titled C:\Program Files\Git\cmd\git.exe appears, empty (git's stdio is piped), and remains for the duration of the git operation.

The same happens on demand with POST /api/plugin/check, which makes it easy to reproduce deterministically:

# timed window sampling while triggering the check
opencode api post /api/plugin/check --data "{}"

Observed (window enumerated via EnumWindows every 150 ms, ConsoleWindowClass, title match):

23:26:17.90  POST /api/plugin/check issued
23:26:18.20  window APPEAR  pid=35484  proc=git  title=[C:\Program Files\Git\cmd\git.exe]
23:26:24.68  window GONE
23:26:24.59  request returned

The window lifetime equals the git operation lifetime (here ~6.5 s), which is why it looks like a stuck popup rather than a flash. In the same 90-second sampling window, the ~12 snapshot/diff git invocations that OpenCode performs did not create any window.

Expected Behavior

No console window should appear. Every other process OpenCode spawns hides its console window, including on Windows: the bundled @opencode/AppProcess service spawns with windowsHide: !0, and even the kill path uses pr.exec("taskkill /pid ... /T /F", { windowsHide: !0 }).

Actual Behavior

The plugin update check spawns git without hiding the console window, so Windows allocates a new visible console window for it:

timestamp=2026-10-14T15:14:55.820Z level=WARN run=97c65e04 role=server
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))])"

Note the corresponding git process is not logged by AppProcess ("spawning process" lines contain only the AppProcess spawns), confirming a different spawn path.

Relevant code shape in the bundled CLI (2.0.29):

  • Npm.check resolves the spec with { preferOnline: true, noGitRevCache: true, ignoreScripts: true } and, for type === "git", resolves through the bundled npm git code (@npmcli/git), which shells out to git. No windowsHide is passed there.
  • @opencode/AppProcess does pass windowsHide: true for StandardCommand spawns.

Because the desktop app's background service has no console, a console subsystem child spawned without CREATE_NO_WINDOW gets a fresh console window from Windows. (Verified independently: spawning cmd.exe from a console-less host process produces a window titled C:\Windows\system32\cmd.exe with identical behavior.)

Additional Context

  • Frequency: every desktop app start (the "already checked" cache is an in-memory 24h map inside the service, and the service is restarted with the app).
  • The window lingers longer when the git operation is slow or retried; in this environment the check fails after retries (An unknown git error occurred), so the window stays for several seconds.
  • Impact: cosmetic but alarming — an unexplained black git.exe console window appears on every launch.
  • Workaround that works (verified): pin the git plugin to a full 40-hex commit, e.g. superpowers@git+https://github.com/obra/superpowers.git#8ca22dba9a94f28898bbce59f2537ff4d87c747d. Npm.check then returns early (if (!a.mutable) return false) and never invokes git. Measured after pinning: POST /api/plugin/check returned in 0.3–0.6 s (was ~6.9 s) with no git process and no window. Downside: updates become manual.
  • Suggested fix: pass windowsHide: true (or create with CREATE_NO_WINDOW) for the plugin/npm git spawns, matching AppProcess.
  • Not specific to one project: observed with the global plugin set as well as the project plugin set.

Activity

  1. opencode-agent commented on Oct 14, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report and the measurements. I think this is a duplicate of #50868, which describes the same thing: the plugin update check for an unpinned git plugin (the same superpowers@git+https://github.com/obra/superpowers.git spec) runs git ls-remote from the console-less background service, so a visible C:\Program Files\Git\cmd\git.exe window appears. It also fails with the same An unknown git error occurred, and pinning to a full commit SHA works around it there too.

    Possible duplicates and related issues, ordered by likelihood:

    Your 2.0.29 reproduction and your POST /api/plugin/check method would be useful additions on #50868.

    The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.

  2. dayesann commented on Oct 14, 2026

    @dayesann
    Author

    Confirmed duplicate of #50868 — closing this one is correct.

    I have moved the additions over to #50868: the 2.0.29 desktop measurements, the on-demand reproduction via POST /api/plugin/check, the window-lifetime/duration data, and the code-path notes (why the check re-runs on every launch, and why commit-pinning bypasses it).

  3. opencode-agent commented on Oct 14, 2026

    @opencode-agent
    Contributor

    Thanks for confirming, and for moving the 2.0.29 measurements, the POST /api/plugin/check reproduction and the code-path notes to #50868. Having everything in one place makes it easier to follow. The bot will close this issue as a duplicate of #50868 as planned.

  4. opencode-agent commented on Oct 15, 2026

    @opencode-agent
    Contributor

    Closing this as a duplicate of #50868, as you confirmed. Thanks again for moving the 2.0.29 measurements, the POST /api/plugin/check reproduction and the code-path notes there. Please follow #50868 for updates. Until it's fixed, pinning git plugins to a full commit SHA avoids the console window.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions