lvy-jsd/dsh-tool-manager--packages-dsh-tool-manager-panel ↗★ 0
dsh-tool-manager-panel
提供可视化网页面板以浏览和管理工具状态 适合需要直观查看、加载或卸载工具及监控会话的用户。
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:lvy-jsd/dsh-tool-manager#7b37565ac428824a61f82534240b14374f0f5378&path:packages/dsh-tool-manager-panel说明文档
阅读完整 README ↗dsh-tool-manager-panel
Web panel for dsh-tool-manager: browse the tool
directory, see what each live session has loaded and what it costs, and load or
unload from the UI.
Optional — the core works without it. When the deployment has no web server (headless), the plugin mounts nothing and stays harmless.
What you get
| View | Shows | Actions |
|---|---|---|
| Directory | the same category → group → tool tree the model browses, with per-node tool counts and schema tokens, plus each tool's summary and high-risk mark | click to drill down; load on any node; search across the whole tree from the search box |
| Sessions | every live agent (subagents marked with their parent), its loaded groups and tools, how many tools are visible (exempt for a route listed in exemptProviders, which is never narrowed), and the schema tokens actually sent for it | load / unload per agent |
| Configuration | the effective always-on list, config additions, and the high-risk list, plus every registered extension point (classifiers with priorities, visibility filters, risk gates, state providers, categories) | read-only in v1 |
Loading from the panel goes through the same path as tools_load, so
tool-catalog/before-load hooks and vetoes apply. The risk gate's approval
prompt does not: it guards the model's tools_load call, and a click in the
panel is itself the user's consent. Without any risk gate installed, high-risk
loads are still refused.
Install
dsh plugin --profile web add dsh-tool-manager dsh-tool-manager-classifier-rules dsh-tool-manager-panel
Then restart DSH (or let live reload pick it up). Open Settings: a Tool manager section (工具管理 in Chinese) appears in the settings sidebar.
The panel follows the DSH interface language (English and Chinese, English by
default; category names and descriptions are translated) and the active theme,
light or dark, because it is styled only with the host's --dsw-alias-* theme
variables.
- id: tool-manager-panel
name: dsh-tool-manager-panel
config:
enabled: true # false disables the routes (the settings section then reports the service offline)
How it is put together
Two halves:
-
Server half (
lib/index.js) mounts two same-origin routes under a loopback + same-origin trust fence (the same shapedsh-mcp-connectoruses):Route Purpose POST /tool-manager/apiJSON-RPC with a method whitelist ( tree,sessions,load,unload,config,extensions,search)GET /tool-manager/eventsSSE: catalog rebuilt, per-session state changed -
Browser half (
lib/client.js) is a small hand-writtenwindow.__ModuleLoader__.load({...})registration — no bundler. It registers onesettings.sectionslot and renders the panel natively with React (no iframe). Copy lives in two dictionaries registered with the hostlocaleservice; styles use only--dsw-alias-*variables, so any DSH theme applies.
To add a language, add a dictionary next to en and zh in lib/client.js
and register it under the same namespace (tool-manager.panel).
Writing your own panel
Every method reads from the toolCatalog service, so a different UI needs no
core changes:
ctx.inject(['toolCatalog'], (c) => {
const tree = c.toolCatalog.get() // catalog for an agent (or the union)
const rows = c.toolCatalog.agents() // live agents with parents
const state = c.toolCatalog.stateOf(agent) // { loaded, groups, … } (Sets)
const tokens = c.toolCatalog.wireTokens(agent) // schema tokens really sent
const hits = c.toolCatalog.find('adb') // structured cross-tree search
await c.toolCatalog.load(agent, ['/device/adb']) // same path as tools_load
})
License
MIT — see LICENSE.