# Changelog All notable changes to this project are documented in this file. ## [0.1.1] - 2026-09-18 ### Added - **Container-aware behaviour.** `isContainer()` detects Docker / Kubernetes / Podman (`.dockerenv`, `/run/.containerenv`, `KUBERNETES_SERVICE_HOST`, `/proc/1/cgroup`), overridable with `DSH_FORCE_CONTAINER=0|1`. Inside a container the plugin still reports versions but refuses to stage or apply — the image is the update unit — and the panel says so instead of offering buttons that could not work. - **Cross-platform relaunch.** `resolveRelaunchCommand()` resolves the `dsh` shim per platform (`/dsh.cmd` on Windows, `/bin/dsh` on POSIX) instead of assuming a Windows layout. ### Fixed - **Panel channel dead on harness ≥ 0.1.5 (`405 Method Not Allowed`).** The browser half posted to `/autoUpdate/`, a channel the host half published with `ctx.connection.rpc.handle('/autoUpdate', …)`. On dsh 0.1.5 that call throws `cannot get property "webServer" without inject` from inside the connection service — `register()` ends in `owner.effect(() => owner.webServer.register(route))`, where `owner` is the connection service's own context, which never declares `webServer`. The throw was swallowed by the plugin's own `try/catch`, so the route was never mounted, every panel request fell through to the web-server fallback, and the card sat on "—" forever while the plugin looked installed. The channel is now an ordinary `webServer` prefix route at `/auto-update` (registered through `ctx.effect`, so it still unloads with the plugin fiber), and `static inject` gained `webServer`. `/auto-update` is deliberately not under `/plugins/`, which the harness already owns for client-module delivery. Host/Origin and browser-session checks are preserved by calling `ctx.connection.requestRejection(req)`; that method reads no other service, so it does not hit the inject guard. - **Windows EBUSY on update apply.** The detached helper ran `npm install -g` with its working directory set to the harness install root. On Windows a directory that is a process's current working directory cannot be renamed, and npm swaps the old `@deepseek-ai/dsh` directory by renaming it — so the apply always failed with `EBUSY: resource busy or locked`, and no retry/backoff helped because the cwd never changed. The helper now runs npm from a neutral temp directory, removing that self-lock. - **Double-apply concurrency.** A pending manifest rebound by a second harness instance could spawn two apply helpers that run `npm install -g` at the same time. The helper now takes an exclusive pid-owned lock (`apply.lock`, stale locks reclaimed) so only one helper touches the global install at a time. - **Idempotent apply.** If the target version is already installed, the helper records success and clears the pending manifest instead of re-running npm. ### Docs - **Corrected the marketplace claims.** The README described the plugin as listed on an "official DeepSeek Harness plugin marketplace" and documented a *Settings → Plugin Market* install flow. No such surface exists in the harness — dsh ships no marketplace code at all, and the market UI belongs to the separate community plugin `dsh-plugin`. The README now names [dsh-plugin.org](https://dsh-plugin.org) as the community market and explains that its UI has to be installed first. - **Removed the dead npm install path.** The npm version badge pointed at a package that does not exist on the registry, and `dsh plugin add dsh-auto-update` failed for the same reason. The badge is now the dsh-plugin.org "listed" badge, and the install instructions use the `github:` specifier the market itself publishes. ## [0.1.0] - 2026-08-20 - Initial release. The harness can now update itself: checks npm for a newer `@deepseek-ai/dsh`, stages the tarball in `$DSH_HOME/updates/`, and applies it on harness exit or via an "update & restart" action from the web panel. - Registered as an installable bundle so it activates with `dsh plugin add`. - Ships a browser panel (check now / update & restart / cancel stage) and an English README.