Skip to content

[Windows] dsh1024 plugin command silently fails (exit 1) when dsh.cmd is on PATH — spawn EINVAL #1

Description

@ZiMiao-01

title: "[Windows] dsh1024 plugin command silently fails (exit 1) when dsh.cmd is on PATH — spawn EINVAL"
labels: bug, windows

Describe the bug

On Windows, dsh1024 plugin --profile <profile> add <pkg> exits with code 1 and no output at all whenever an official dsh CLI shim (a dsh.cmd batch file) is present on PATH. The wrapper picks the .cmd shim from PATH and spawns it with shell: false, which Node.js cannot do on Windows (.bat/.cmd files require a shell) — the spawn throws EINVAL, the error is swallowed, and the CLI exits 1 silently. Running the same command through the official dsh CLI directly works fine.

Environment

  • OS: Windows (win32, x64)
  • Node: v24.13.1
  • npm: 11.8.0
  • pnpm: 10.30.2
  • dsh1024: 0.5.0 (latest)

To reproduce

  1. Have an official @deepseek-ai/dsh shim on PATH, e.g. ...\node_modules\.bin\dsh.cmd (from a global install or an npx cache).

  2. Run:

    npm install -g dsh1024
    dsh1024 plugin --profile web add dsh1024@latest
    
  3. Observe: the command prints nothing and exits with code 1.

  4. Control: dsh plugin --profile web add dsh1024@latest succeeds (pnpm output shown, exit 0).

Expected behavior

The command forwards to the official CLI and reports the install outcome, exiting 0 on success.

Actual behavior

Silent exit code 1. With NODE_DEBUG=child_process the wrapper is seen spawning:

file: 'C:\\Program Files\\nodejs\\node_cache\\_npx\\...\\node_modules\\.bin\\dsh.cmd',
args: [ 'plugin', '--profile', 'web', 'add', 'dsh1024@latest' ],
shell: false,

which throws Error: spawn EINVAL (errno -4071) synchronously from spawn(). runOfficialCommand resolves with exitCode: null and the error is never printed (cli/plugin.js only maps it to failureCode === 'SPAWN_FAILED'), so the user sees nothing.

Root cause

  • cli/plugin.jsfindOfficialCliOnPath() scans PATH using PATHEXT extensions (.COM;.EXE;.BAT;.CMD) and returns the first hit, which on typical Windows setups is a dsh.cmd npm shim.
  • officialCliInvocation() then returns { file: '<...>\\dsh.cmd', prefixArgs: [], useShell: false }.
  • lib/shared/install-runner.jsrunOfficialCommand() spawns it with shell: false. On Windows, .bat/.cmd files can only be executed through a shell (cmd.exe), so Node throws EINVAL from spawn() (see Node docs: "batch files can only be launched with the shell option").
  • The wrapper treats this as a failed install and exits 1, printing nothing.

Suggested fix

In the win32 branch of officialCliInvocation() (or in findOfficialCliOnPath()):

  • Prefer a real executable (dsh.exe); if the only match is a .cmd/.bat shim, either
    • spawn it with useShell: true, or
    • skip .cmd/.bat in the PATH scan and fall back to the npm exec route (node <npm-cli.js> exec --yes -- @deepseek-ai/dsh ...), which already works on Windows.

Also consider printing result.error to stderr when failureCode === 'SPAWN_FAILED' so failures are never silent.

Workaround (verified)

$env:DSH1024_DSH_PACKAGE='@deepseek-ai/dsh'
dsh1024 plugin --profile web add dsh1024@latest

Setting DSH1024_DSH_PACKAGE forces the wrapper to skip the PATH lookup and use the npm exec route, which succeeds (exit 0, receipts recorded correctly in ~/.dsh/.dsh-1024store/receipts.json).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions