Skip to content

[Bug] Windows: Harness spawned with empty PATH when env block stores PATH as lowercase 'path' — user tools invisible to tool shells #232

Description

@Tony-ooo

Summary

On Windows, the Harness process — and therefore every agent tool shell (pwsh, bash, …) spawned by it — can be launched with an empty PATH. The user's full PATH is lost; only the two directories prepended by the market-installer shim (<dshHome>\.desktop-bin and the bundled Node bin) survive, which masks the loss. As a result, all user-installed CLIs (git, python, conda, node, npm, …) become invisible to the Harness and its subprocesses.

Root cause

Windows environment variable names are case-insensitive, and the case stored in the environment block is not normalized — it follows the stored case of the registry value. For example, when HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment stores the PATH value name as lowercase path, the environment block of every child process (explorer → DSH Desktop main) carries the key as lowercase path.

Two pieces of this repo then treat the captured environment as case-sensitive:

  1. src/main/runtime/harness-runtime.ts

    • resolveShellEnvironment() (line 55) captures the user environment by running Windows PowerShell Get-ChildItem Env: and parsing NAME=VALUE lines with parseEnvOutput, which builds a plain JS object with exact-case keys. PowerShell reports each key with the case stored in the environment block, so on such a machine the parsed object has key path, not Path.
    • buildHarnessSpawnOptions() (line 200) on win32 then does pathKey = 'Path' and (line 236):
      [pathKey]: environment[pathKey] ?? environment.PATH ?? ''
      Both lookups are exact-case on a plain object, so a lowercase path key matches neither → the Harness is spawned with Path = ''.
  2. packages/dsh-desktop-market-installer/index.js — ensurePnpmShim() (lines 293–304) prepends <dshHome>\.desktop-bin and the bundled Node dir to process.env.PATH. Because the spawn PATH was already empty, this prepend becomes the entire PATH, so the Harness ends up with exactly those two directories. The bundled node/pnpm shims keep working, which hides the bug while the user's PATH stays lost.

  3. The same exact-case pattern exists in src/main/runtime/profile-plugin-command.ts processPath() (lines 141–143), so plugin-command children get the same empty base.

Evidence / reproduction

Measured on an affected machine (DSH Desktop 0.7.0, Windows 11 26200), by reading the environment blocks via the process PEB:

  • DSH Desktop main process and explorer: the key is lowercase path (value = full user PATH).
  • Harness node process: key Path with value exactly <dshHome>\.desktop-bin;<app>\resources\app\node_modules\node\bin — only the two shim dirs.

Running the repo's own functions verbatim against a capture whose key is lowercase path:

parsed keys: ['path', 'TEMP']
has 'Path': false; has 'PATH': false; has 'path': true
>>> harness spawn Path = ""          # bug
>>> case-insensitive lookup would give: "<full user PATH>"

Visible symptom in the GUI: tool shells report git / python / npm as "not found", and $env:PATH inside a pwsh tool call shows only:

C:\Program Files\PowerShell\7
<dshHome>\.desktop-bin
<app>\resources\app\node_modules\node\bin

(The first entry is added by PowerShell itself at startup and is unrelated to DSH.)

Expected behavior

The Harness should be spawned with the user's full PATH plus the intentional .desktop-bin / bundled-Node prepend. The intent is documented in resolveShellEnvironment() ("capture the full environment the user would have in a terminal … use as the Harness spawn base") and in PR #61, which describes the shim dirs as prepended to PATH — not replacing it.

Suggested fix

Make the PATH lookup case-insensitive, matching Windows environment semantics (Node's own process.env is already case-insensitive on Windows). Concretely:

  • In buildHarnessSpawnOptions(), resolve the PATH value by scanning environment keys case-insensitively (or normalize key case during parseEnvOutput), instead of environment['Path'] ?? environment.PATH ?? ''.
  • Apply the same fix to processPath() in src/main/runtime/profile-plugin-command.ts.

Environment

  • DSH Desktop: 0.7.0 (also reproduced against repo HEAD 16893cb5)
  • OS: Windows 11 (build 26200)
  • Harness: 0.1.2-alpha.1 (bundled)

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions