# @qipenglin/dsh-plugin-manager [中文](README.md) | English An optional active-profile plugin manager for DeepSeek Harness `0.1.1-rc.2`. It adds a Plugin manager tab under Settings → Plugins with install, single-package update, remove, and cancellation controls. ## Install ```sh dsh plugin --profile web add github:qipenglin/dsh-plugin-manager dsh web ``` This installs the plugin directly from the GitHub repository's default branch. The repository includes verified `lib` artifacts, so installation does not execute build scripts. Restart the current profile after installation so it loads both the Host and browser contributions. The manager changes only the profile that loaded it. `dsh web` selects `web`; `dsh --profile work` selects `work`; a desktop Host may publish an authoritative `desktopProfiles.current`. Startup fails when the active profile cannot be identified—there is no `web` fallback. ## Capabilities - Install registry packages, npm aliases, Git/GitHub sources, remote tarballs, absolute directories, and absolute `file:` or `link:` sources. - Upload and retain `.tgz`, `.tar.gz`, or `.tar` archives through the browser picker. - The install area and update dialog both provide a disabled-by-default **Skip new-version waiting period** option. Explicitly selecting it adds `--config.minimumReleaseAge=0` to that operation only; all other supply-chain checks remain enabled. When pnpm rejects an operation because of the waiting period, the UI points to this option without enabling it or retrying automatically. - Update or remove one direct dependency. Update opens one dialog for registry, Git/GitHub, remote tarball, absolute directory, and local archive sources, and always writes back to the original direct-dependency key. A remote tarball requires a new URL; a local archive must be selected again, and identical retained content is rejected before execution. - The manager card provides a dedicated self-update action that reuses the same dialog and release-age option. After self-update, the Host verifies that the direct dependency remains present, the installed package is still named `@qipenglin/dsh-plugin-manager`, and no manager aliases were introduced; a successful update is marked **Updated; restart to apply** and the action stays disabled until restart. The UI still blocks removal, duplicate installation, and npm aliases that install a second manager. If an unknown Git/archive source ultimately replaces the manager, the operation reports failure, but disk state may already have changed; inspect or restore it with the external DSH CLI before restarting. - Removing an existing direct dependency automatically disables the publication-age wait for that `remove`, so newer versions already present in the lockfile cannot block deletion. Integrity, source, and all other supply-chain checks remain enabled, and removal accepts no new package source. - Every successful dependency mutation keeps an explicit current-Host state: **Installed; restart to apply**, **Updated; restart to apply**, or **Removed; restart to apply**. Update and Remove are disabled for that row until restart. Removed rows stay visible until restart; installed and updated rows show the new on-disk metadata without implying that their runtime code is active. - Run one mutation at a time, support cancellation, and keep bounded redacted diagnostics. - Record successful changes and ask the user to restart manually; the next Host load consumes the marker and clears the prompt. No hot reload or automatic restart is performed. ## Optional WebAccess This package neither imports nor depends on `@qipenglin/dsh-web-access`. When the Host exposes a structured `webAccess.authorize(request)` service, archive requests are authenticated before their body is read. The service is detected per request, so a later load or unload takes effect immediately and an authentication rejection is never bypassed. Without WebAccess, all features remain available only when WebServer is bound to `127.0.0.1`. Any local process that can reach the loopback port may call management endpoints, and the UI shows that state. Startup fails if an unauthenticated manager would be exposed through `0.0.0.0`. ## Desktop Host integration A desktop Host may provide: ```ts desktopProfiles.current = { name: string, dir: string } desktopPnpm.runPlugin(args, invokingDirectory, signal) ``` They form one atomic Desktop integration: both must be valid or both absent. When present, all operations target that current profile. Otherwise the provider invokes the current Node/DSH entry with an argv array and `plugin --profile `; it never builds a shell command. The CLI provider removes API keys, base URLs, tokens, passwords, secrets, Authorization/Cookie values, `NODE_OPTIONS`, and `NODE_PATH` from the child environment while preserving ordinary `PATH`, `HOME`, proxy, and package-manager settings. Private-registry environment tokens are therefore intentionally unsupported; configure registry access outside Host secrets. A `desktopPnpm` implementation owns its subprocess environment and must apply equivalent filtering because this package gives it only structured args, directory, and cancellation signal. ## Development Node `^22.19.0 || >=24.0.0` and pnpm `11.7.0` are required. ```sh pnpm install --frozen-lockfile pnpm run typecheck pnpm run lint pnpm test pnpm run pack:check pnpm run test:installed ``` `pnpm run pack:check` replaces `dist/` with the single verified `dist/qipenglin-dsh-plugin-manager-0.3.7.tgz` tarball. The installed test creates the real installation archive, installs it into an isolated official DSH `0.1.1-rc.2` Web profile, and calls its Remote API through the real Loader. ## License [MIT](LICENSE)