Skip to content

Windows: CLI agent connect fails — resolve_cli picks extensionless npm shim before .cmd/.exe #189

Description

@OldSuns

Summary

On Windows, connecting OpenCode / Claude Code / Codex in the desktop app fails even when the CLIs work fine in a terminal.

OpenCode error shown in UI:

No models configured in OpenCode. Run "opencode" to set up

(Claude/Codex fail for the same root cause when installed via npm.)

Root cause

resolve_cli in crates/op-host-services/src/model_discovery.rs tries Windows extensions in this order:

[", ".exe", ".cmd", ".bat"]

npm global installs put an extensionless Unix shell script (#!/bin/sh) next to the real Windows entry:

Path What it is
%APPDATA%\npm\opencode Unix shim — not a valid Win32 PE
%APPDATA%\npm\opencode.cmd Real Windows launcher
...\node_modules\opencode-ai\bin\opencode.exe Real binary

Because candidate.is_file() is true for the extensionless shim, resolve_cli returns that path first. Command::new(exe).arg("models").output() then fails (invalid application for this OS), discover_opencode() gets an empty list, and connect_opencode() reports “No models configured…”.

Terminal works because PowerShell/CMD prefer .ps1 / .cmd, not the bare shim.

Same pattern for claude and codex under %APPDATA%\npm\.

Repro

  1. Windows 10/11
  2. Install CLIs via npm, e.g. npm i -g opencode-ai (and/or Claude Code / Codex)
  3. Confirm terminal works: opencode models lists provider/model lines
  4. Launch OpenPencil desktop (Start Menu / shortcut is enough)
  5. Settings → connect OpenCode

Expected: models listed, connect succeeds
Actual: No models configured in OpenCode. Run "opencode" to set up

Local proof (CreateProcess-style)

# Fails — bare npm shim is a shell script
Start-Process -FilePath "$env:APPDATA\npm\opencode" -ArgumentList models -NoNewWindow -Wait
# → not a valid application for this OS platform

# Works
& "$env:APPDATA\npm\opencode.cmd" models
& "$env:APPDATA\npm\node_modules\opencode-ai\bin\opencode.exe" models

Workaround

Rename/remove the extensionless shims so resolution falls through to .cmd:

cd $env:APPDATA\npm
Rename-Item opencode opencode.sh.bak -ErrorAction SilentlyContinue
Rename-Item claude claude.sh.bak -ErrorAction SilentlyContinue
Rename-Item codex codex.sh.bak -ErrorAction SilentlyContinue

Then fully quit and restart OpenPencil.

Suggested fix

On Windows, do not treat extensionless files as executables in resolve_cli (or try .exe / .cmd / .bat before ""`).

Minimal change sketch:

// windows: prefer real PE / cmd shims over npm's extensionless #!/bin/sh
let exts: &[&str] = if cfg!(windows) {
    &[".exe", ".cmd", ".bat", "]  // or drop " entirely on Windows
} else {
    &["]
};

Optionally also prefer resolving through to the real .exe under node_modules\...\bin\ when the hit is an npm shim.

Environment (reporter)

  • OpenPencil desktop (latest pre-release, e.g. v0.8.2)
  • Windows (win32)
  • opencode 1.18.7 via npm (%APPDATA%\npm)
  • opencode models works in PowerShell and lists many models
  • Config present at %USERPROFILE%\.config\opencode\opencode.json (not the old ~\.opencode\config.json path the UI hint mentions)

Related code

  • crates/op-host-services/src/model_discovery.rsresolve_cli, discover_opencode
  • crates/op-host-services/src/provider_probe.rsconnect_opencode empty-models message
  • crates/op-host-services/src/cli_resolver_windows.rs — GUI PATH fallbacks (includes %APPDATA%\npm, which is correct; the bug is extension order)

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions