Skip to main content
PathDocs

Plugin Inventory

Take a live look at which plugins are installed and what state they are in. DSH exposes a read-only pluginInventory service that projects the current Cordis Loader tree to clients via a Remote; the Web Settings "Plugins" tab is its visual surface.

Read-only projection:ctx.pluginInventory

The PluginInventoryGateway in packages/host/plugin-inventory (package @deepseek-ai/dsh-host-plugin-inventory) registers the pluginInventory service and publishes one Typert-generated direct Remote: pluginInventory/list.

Every call reads ctx.loader.entries() directly, skips structural group rows, and returns the remaining entries in Loader order — with only four fields:

fieldmeaning
entryIdstable Loader-tree entry identity (branded PluginEntryId)
moduleNamethe exact module specifier the entry imports
enabledeffective enablement (including disabled ancestor groups)
fiberPhasecurrent root Fiber phase, null when there is no live root Fiber
// packages/host/plugin-inventory/src/index.ts —— read the Loader directly, no second cache
@Remote('list')
list(): PluginInventorySnapshot {
const entries: PluginInventoryEntry[] = []
for (const entry of this.ctx.loader.entries()) {
if (entry.options.group) continue
entries.push({
entryId: pluginEntryId(entry.id),
moduleName: entry.options.name,
enabled: !entry.disabled,
fiberPhase: entry.fiber === undefined ? null : FIBER_PHASE[entry.fiber.state],
})
}
return { entries }
}

fiberPhase values

valueCordis Fiber statemeaning
pendingPENDINGnot yet started loading
loadingLOADINGloading the module
activeACTIVErunning / activated
failedFAILEDload/activation failed
unloadingUNLOADINGunloading
nullDISPOSEDno live root Fiber

The snapshot is point-in-time: the Loader remains the sole lifecycle authority, and this package owns no cache, history, provenance model, event stream, or mutation path. The service is Remote-only and deliberately declares no same-process Cordis Context merge — Client packages consume it through the api-remotes assembly.

// packages/host/plugin-inventory/src/types.ts —— the phase projection
export type PluginFiberPhase =
| 'pending' | 'loading' | 'active' | 'failed' | 'unloading' | null

The "Plugins" tab in Web Settings

packages/client/ui-settings-plugin-inventory (@deepseek-ai/dsh-client-ui-settings-plugin-inventory) is a browser plugin that registers a localized settings.plugins.tab contribution with id all. The Plugins section owns the navigation entry and tab chrome.

  • Lazy: the component is only mounted on first selecting the tab, which then lazily calls ctx.remote.pluginInventory.list() through api-remotes
  • renders a searchable two-column card catalog; each collapsed card = a short module-name title + an effective-enablement tag + (when enabled) a colored root-Fiber status dot
  • expanding a card shows: the Loader-tree entry id, the effective configuration, and for enabled entries the Cordis status; disabled entries omit the redundant "not mounted" runtime state
  • search matches the module name and entry id; loading/empty/no-match/failure states stay local to the mounted component, and a failed read can be retried without exposing transport details
// ui-settings-plugin-inventory/src/client/index.ts —— registered via slots, without importing the section owner
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
name: 'settings.plugins.tab', id: 'all', order: 10,
label: () => t('tab'), locale: NS, inject: injected,
}, PluginInventorySettingsTab))

The status dot is colored via data-phase (see .statusDot[data-phase='…'] in PluginInventorySettingsTab.module.css): enabled + active → success green, failed → error color, loading → a progress color, everything else gray.

capabilityrelationship
plugin install management and plugins.mdthe management surface (enable/disable/install); this capability is a read-only projection with no mutation path
tool-cordisthe model-facing tools; this capability is a deployment/host-side Loader-tree view with no tool or prompt registration
ctx.loaderthe sole lifecycle authority; pluginInventory is just its read-only mirror

This capability registers no prompt, tool, message, or provider request (README Model Experience: None).

Verify

# confirm the service and Remote contribution in the composition tree
dsh web --dump-config | grep -iE "plugin-inventory|pluginInventory"

# open Web Settings → "Plugins" tab and look at the searchable card catalog with its colored status dots

Next steps