Files
deepseek-harness/packages/host/plugin-manager
Yichen Jiang 7b713ca83b refactor(plugin-manager): move plugin management out of the Web host
What plugin management does now lives in `dsh-plugin-manager`, a boot-group
package beside `app-boot`: `PluginInstaller` runs pnpm, probes, and judges new
packages over the profile on disk, and `PluginManager` adds every operation
over the booted tree, each refusal a `PluginOperationError` with a `plugins/*`
code and no Remote protocol attached. The manager reads the profile runtime,
the preset roster, and the running-agent count through per-call readers, and
the roster only as `PresetLayers`, so the package depends on neither the
roster nor the agent registry.

`dsh-host-plugin-manager` keeps `pluginManager` and the `plugins` Remote as a
relay: one Remote method per manager method, and one exhaustive switch
turning a failure into the Remote error of the same code (`plugins/bad-request`
into `gateway/bad-request`). Its `./types` re-exports the manager's types, so
`api-remotes` and the client import one vocabulary unchanged.

`dsh plugin add` and `remove` now run the installer instead of a bare pnpm
forwarder: every new package is probed, a package that declares neither a
bundle nor a plugin module is removed again with its reason, and newly
installed bundles are enabled as before. Other pnpm verbs still forward.
2026-09-07 17:47:08 +08:00
..

description, kind
description kind
The plugins Remote of the Web host: pluginManager as a Typert service that relays each call to the shared plugin manager over the booted profile and maps its failures onto Remote error codes. package-reference

@deepseek-ai/dsh-host-plugin-manager

English | 中文

Summary

dsh-host-plugin-manager is the Web host's face of plugin management. It mounts pluginManager as a Typert service and exposes the plugins Remote — list, add, uninstall, enable, disable, retry, addRow, removeRow, setRowDisabled, dependents — each method relaying to the dsh-plugin-manager PluginManager built over this context, and each plugins/* failure crossing the wire as a RemoteError of the same code. What the operations do, and the plugins/changed and plugins/install-log events that follow them, belong to that package; this one reads the profile runtime, the preset roster, and the agent registry off the context and hands them over. Client packages consume the Remote through the api-remotes assembly.

Table of Contents


Use this package

Mount the row in a host composition beside the plugin inventory; the web bundle does. The row injects only the Loader and resolves the profile runtime per call, so a composition booted without the profile launcher still starts and answers every call with plugins/unavailable.

The Remote

plugins/list, plugins/add, plugins/uninstall, plugins/enable, plugins/disable, plugins/retry, plugins/addRow, plugins/removeRow, plugins/setRowDisabled, and plugins/dependents carry the arguments and answers the manager's methods of the same names define; the manager README documents each. The ./types export re-exports the manager's payload types unchanged, so a client imports one vocabulary.

Failure codes

A manager failure reaches the client as a RemoteError with the same code and details: plugins/unavailable, plugins/not-installed, plugins/not-enableable, plugins/enable-failed, plugins/install-failed, plugins/row-conflict, plugins/busy, and plugins/agents-running, each declared in the Remote failure map with the manager's details type. The manager's generic refusal, plugins/bad-request, crosses as the Gateway's gateway/bad-request. Any other error the manager throws propagates untouched, which the Gateway reports as gateway/internal.

Configuration

Field Default Meaning
pnpmCommand pnpm The executable, resolved through PATH like the dsh plugin command.
installTimeoutMs 600000 Bound on one install or remove run.
probeTimeoutMs 20000 Bound on one package probe.
installLogTailBytes 16384 How much trailing output an install failure reports.

Understand the implementation

Implementation internals — click to expand

A relay, not a second manager

The constructor builds one PluginManager with readers into the context — ctx.get('profileRuntime'), ctx.get('agentPresets'), and the running-agent count from ctx.get('agents') — so what is composed is read when a call arrives, not when the row mounts. Every Remote method is relay(() => this.manager.x(...)): a PluginOperationError becomes the Remote error of its code through one exhaustive switch, and anything else is rethrown. Tests hand a manager in through PluginManagerInternals.manager; the spawn and probe seams pass through to the manager.

Source map

File Role
src/index.ts PluginManagerRemote: the pluginManager service, the ten plugins Remote methods, and remoteErrorOf
src/types.ts The manager's types re-exported, and the plugins/* codes declared in the Remote failure map
— No runtime invariant companion is published; the row holds no state of its own.

Typert generates the Host and Client Remote artifacts exposed by ./typert and ./remote.


Further Exploration

Read these when the relay's contract is not enough: the manager behind it and the surface that renders it.

  • Plugin manager — what every operation does, the events, and the failure codes.
  • App boot — the profile runtime the manager drives.
  • Plugin inventory — the row-level read-only projection beside this service.

Model Experience

None, as the Remote registers nothing model-facing; the rows the manager composes own every registration they make.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

These limits define what the Remote will not do for a client. They are current package constraints, not a task backlog.

  • What the manager cannot do, the Remote cannot either — the manager's limits apply unchanged: a loaded package updates at the next restart, dependents stop at injection, a preset row composes for later sessions, engines.dsh is reported and not enforced.

Dev Note

Working context for maintainers — click to expand

None.