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:
-
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 = ''.
-
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.
-
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)
Summary
On Windows, the Harness process — and therefore every agent tool shell (
pwsh,bash, …) spawned by it — can be launched with an emptyPATH. The user's full PATH is lost; only the two directories prepended by the market-installer shim (<dshHome>\.desktop-binand the bundled Nodebin) 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\Environmentstores the PATH value name as lowercasepath, the environment block of every child process (explorer → DSH Desktop main) carries the key as lowercasepath.Two pieces of this repo then treat the captured environment as case-sensitive:
src/main/runtime/harness-runtime.tsresolveShellEnvironment()(line 55) captures the user environment by running Windows PowerShellGet-ChildItem Env:and parsingNAME=VALUElines withparseEnvOutput, 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 keypath, notPath.buildHarnessSpawnOptions()(line 200) on win32 then doespathKey = 'Path'and (line 236):pathkey matches neither → the Harness is spawned withPath = ''.packages/dsh-desktop-market-installer/index.js—ensurePnpmShim()(lines 293–304) prepends<dshHome>\.desktop-binand the bundled Node dir toprocess.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.The same exact-case pattern exists in
src/main/runtime/profile-plugin-command.tsprocessPath()(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:
path(value = full user PATH).Pathwith 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:Visible symptom in the GUI: tool shells report
git/python/npmas "not found", and$env:PATHinside apwshtool call shows only:(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 inresolveShellEnvironment()("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.envis already case-insensitive on Windows). Concretely:buildHarnessSpawnOptions(), resolve the PATH value by scanningenvironmentkeys case-insensitively (or normalize key case duringparseEnvOutput), instead ofenvironment['Path'] ?? environment.PATH ?? ''.processPath()insrc/main/runtime/profile-plugin-command.ts.Environment
16893cb5)