Releases: sjh9714/dsh-win32
Release list
v0.8.0
doctor --json now emits the community dsh-doctor/v1 envelope (deepseek-harness#1719), so CI and support flows can consume a doctor run from any conforming implementation.
npx dsh-win32 doctor --jsonThe skip status is new to the contract and came from this plugin. The vocabulary had pass / warn / fail. A check like git_bash is none of those on Linux, it does not apply, so a platform-scoped implementation had to either report pass (a lie) or fail (poisoning any cross-platform CI run). A fourth status with a mandatory reason, counting as neither pass nor fail, was accepted into v1.1. This is the first implementation where it actually fires, since every check here except node is win32-scoped.
Also in this release.
- Checks carry the vocabulary names (
node,git_bash,powershell,koffi,sandbox_shell), so a consumer asserts on name plus status and never parsesdetail. - Exit codes follow the contract, 0 all pass, 1 any warn, 2 any fail. This is a breaking change if you run
doctorinside a script. Treat exit 1 as informational and gate on exit 2. Exit codes apply to a directdoctorrun only, sosetupstill decides for itself whether a finding is fatal. - The standing "mode matters" warning became a real
sandbox_shellcheck. It reports pass once the busybox variant is installed instead of nagging unconditionally. - The
noderange is now anchored to the deepseek-harness rootpackage.json, which declares^22.19.0 || >=24.0.0, rather than to an observed failure. Three doctor implementations had three different floors before this was found. - Fix. The Git Bash wrapper check was inverted.
Git\usr\bin\bash.exeis the real shell andGit\bin\bash.exeis the 47KB wrapper, but both end in\bin\bash.exe, so a correctly installed Git Bash was reported as the wrapper. Caught by Windows CI before release.
49 unit tests, 3-OS CI matrix. The envelope is asserted on every push on all three systems, including that every skip carries a reason and that the summary adds up.
v0.7.2
Hardening on the collect-path spill, prompted by deepseek-harness#2252.
That report is about the stock collector. A Windows temp cleaner (火绒, CCleaner, Storage Sense) removes %TEMP%\dsh-subprocess-* during a long session, the next spill open throws ENOENT out of a stream data listener, and the whole host process dies. Still reproducible at rc.6.
dsh-win32 rewrites collect-mode stdio to raw pipes on win32 in order to sniff and decode legacy code pages, and its collector already caught spill failures, so that crash class does not reach the collect path here. Two things changed anyway.
- The catch dropped the spill descriptor without closing it, leaking one fd per failure.
- The spill directory is re-made on every open rather than cached for the process lifetime. That is what makes a temp cleaner harmless, it was incidental before, and it is covered by tests now (one for the cleaner case, one for a spill target that cannot be created at all).
43 unit tests, 3-OS CI matrix. No behavior change for anyone who was not hitting a spill failure.
dsh-win32 v0.7.0
Foreground resolution is real now, contributed by @hili986 in #9 after their analysis in #7.
foregroundPgid returned undefined before, which looked like an honest degradation but silently defeated terminal-bash's completion detector. Its shell-vs-child discriminator compares the foreground pid against the shell pid, and undefined === undefined passes without discriminating anything, leaving prompt markers and silence as the only signals. Upstream's own comment notes the prompt marker is ambiguous by design since a child inherits PROMPT_COMMAND.
The win32 mapping is ConPTY's console process list, read through a one-shot helper because a process can attach to only one console. Parent links cannot substitute. MSYS fork emulation severs the chain, measured with a Git Bash PTY running sleep 20 that reports no direct children while the console list still shows the sleep. Cost is ~81ms against ~904ms for a CIM enumeration, and the single-candidate path takes no snapshot at all.
isStdinWaiting stays false on purpose. Windows has no reliable console-read-block probe and claiming a wait that is not happening would settle a still-running command. Undefined remains the fallback for every failure, so the previous behavior is the floor rather than a guess.
One reachability change. SIGTERM and SIGKILL against a foreground command now resolve and tree-kill it instead of throwing. SIGKILL against an idle shell still hits upstream's refusal guard, which works because v0.6.0 made the pty pid the real shell rather than the Git wrapper.
Also in this release. A new foreground smoke runs in CI on every push, the adoption doc records the mapping for deepseek-harness#1889, and the README gained a section for preset authors after a user in #6 found that a preset without an explicit shellPath hits the System32 WSL launcher on Windows.
41 unit tests, full matrix green.
dsh-win32 v0.6.0
Community-review release. Both issues came from an independent win32 plugin author who measured before filing (thank you @hili986).
#8, inspector cost. isAlive ran a full CIM enumeration (~904ms measured on a busy box) per member per 25ms poll tick during terminate, consuming the entire grace period at 4+ descendants and force-killing cleanly-exiting processes. Now kill(pid, 0) short-circuits dead pids (~0.002ms), the snapshot is TTL-cached at 200ms, and the CIM query materialises only the three needed properties. Identity-based pid-recycle protection unchanged.
#7, the wrapper trap. setup now selects Git\usr\bin\bash.exe (the real shell) over Git\bin\bash.exe (a 47KB wrapper that respawns it), removing a latent SIGKILL-guard bypass and one process layer. The adoption doc's impact assessment for the foreground degradation was corrected since it undersold the loss. The ConPTY console-list mapping is the tracked follow-up, with a PR invited from the reporter.
29 unit tests, full matrix green.
dsh-win32 v0.5.4
Field report #3 (#6, same tireless tester). The Git Bash preset silently fails with PTY shell exited during startup when the session runs in the default workspace-write sandbox. That is the measured MSYS restricted-token death, but nothing told the user. Now the preset picker descriptions state the mode requirement on both variants, and doctor warns about it on Windows with the sandboxed alternative spelled out. No behavior change, pure guidance.
dsh-win32 v0.5.3
Proactive-audit release, before anyone hit these.
- Spill contract restored. The shell executors request spill files on collect-mode spawns, and the v0.5 decoding collector silently produced none, so large command outputs on win32 lost their full-stream spill. The collector now streams raw bytes to a spill file exactly like stock (created on first overflow, discarded past the cap, raw semantics identical, and GBK spills were raw in stock too).
donewaits for pipe drain. A read immediately after process exit could miss final chunks. The handle's outcome now settles only after the claimed pipes drain.- busybox download fallback. If frippery.org is unreachable (some networks), setup now says how to pass a manually downloaded binary (
--busybox <path>), and the README carries a China-network note for both raw.githubusercontent.com and frippery.org.
27 unit tests, full matrix green.
dsh-win32 v0.5.2
Second field-report fix (#5). The dsh profile directory is a pnpm workspace root, and newer pnpm refuses a bare add there (ERR_PNPM_ADDING_TO_ROOT), so the internal dsh plugin add forwarding now passes -w. A failed bundle-wiring step also no longer aborts the whole setup. The preset installs regardless and the manual wiring command is printed. Retry with npx --yes dsh-win32@latest setup --shortcut
dsh-win32 v0.5.1
Hotfix for the first field report (#5, thank you @flyingfishzxf). npx dsh-win32 could 404 on @deepseek-ai/dsh-type-meta. npm auto-installed our peerDependencies and resolved them into a stale prerelease graph. The CLI is zero-dependency and the peers only matter inside a dsh profile, so they are now marked optional and npx no longer installs them. install.ps1 also fails loud now instead of printing Done after a failed setup. Retry with npx --yes dsh-win32@latest setup --shortcut
dsh-win32 v0.5.0
Encoding story complete, within what a plugin can reach. The runtime now serves foreground-shell collect output through a sniffing decoder, so native tools writing OEM 936 (GBK) or UTF-16 through the shell pipeline read back as correct text instead of mojibake. Same sniffer as the v0.4 filesystem reader, decided once per stream at first read. UTF-8 output passes through byte-identical. PTY output remains out of plugin reach (node-pty decodes first) and is documented as such.
Also, terminal teardown now falls back to taskkill /T /F when a ConPTY kill leaves the shell alive (observed with directly spawned busybox ash on CI), fixing the cleanup complaint tracked in #2. Core-adoption notes for the win32 ProcessInspector shipped in docs/core-adoption.md (see deepseek-harness#1889).
Receipts. windows-latest CI runs a real child emitting raw GBK bytes and asserts the decoded read. 24 unit tests. The full 3-OS matrix plus the sandboxed busybox job stay required.
dsh-win32 v0.4.0
Two firsts.
The sandboxed persistent shell. MSYS bash dies under the workspace-write restricted token (cygheap TokenDefaultDacl 0xC0000022, measured), but busybox-w32 ash has no cygheap and survives. npx dsh-win32 setup --sandboxed installs the minimal-windows-sandboxed preset (busybox downloaded on consent, GPLv2, never bundled). Proven on windows-latest CI with a full send/read round-trip inside the restricted token, now a required CI job. The trade-off is ash, not bash.
Legacy-encoding reads (dsh-win32/fs). Stock DSH refuses GBK/UTF-16 files outright (FS_NOT_TEXT), locking agents out of Chinese-locale legacy projects. Both presets now mount a reader that sniffs and transparently decodes GBK and UTF-16 on reads. Writes stay UTF-8, so editing a legacy file converts it. Deliberate and documented.
Also documented. PTY output of legacy-codepage native tools is unfixable at the plugin layer (node-pty decodes UTF-8 before DSH sees bytes). Shipped presets are unaffected since Git Bash and busybox default to UTF-8.
Upgrade with dsh plugin --profile web add dsh-win32@0.4.0 && npx dsh-win32 setup --sandboxed