dsh-plugin-tool-management 0.19.1 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +915 -829
  2. package/README.md +237 -254
  3. package/README_EN.md +234 -223
  4. package/docs/images/1-EN.png +0 -0
  5. package/docs/images/1.png +0 -0
  6. package/docs/images/2-EN.png +0 -0
  7. package/docs/images/2.png +0 -0
  8. package/docs/images/3-EN.png +0 -0
  9. package/docs/images/3.png +0 -0
  10. package/docs/images/4-EN.png +0 -0
  11. package/docs/images/4.png +0 -0
  12. package/docs/images/5-EN.png +0 -0
  13. package/docs/images/5.png +0 -0
  14. package/docs/images/6-EN.png +0 -0
  15. package/docs/images/6.png +0 -0
  16. package/docs/images/7-EN.png +0 -0
  17. package/docs/images/7.png +0 -0
  18. package/docs/images/8-EN.png +0 -0
  19. package/docs/images/8.png +0 -0
  20. package/docs/images/logo.gif +0 -0
  21. package/docs/update.md +32 -30
  22. package/lib/client.js +9480 -6970
  23. package/lib/compat/preset-reach.js +5 -2
  24. package/lib/context-inject-frame.js +13 -8
  25. package/lib/hub.js +104 -11
  26. package/lib/index.js +72 -24
  27. package/lib/mcp/manager.js +45 -13
  28. package/lib/mcp/secret-guard.js +2 -2
  29. package/lib/mcp/state-section.js +1 -1
  30. package/lib/memories/archive-engine.js +4 -5
  31. package/lib/memories/constants.js +11 -4
  32. package/lib/memories/service.js +6 -1
  33. package/lib/op-registry.js +13 -11
  34. package/lib/ops/memory.js +42 -4
  35. package/lib/ops/scene-records.js +43 -9
  36. package/lib/ops/sessions.js +67 -46
  37. package/lib/ops/trash.js +107 -8
  38. package/lib/request-gate.js +9 -2
  39. package/lib/scene-prompt-sync.js +48 -23
  40. package/lib/sessions/history.js +32 -22
  41. package/lib/sessions/workspace.js +0 -10
  42. package/lib/skills/catalog.js +17 -5
  43. package/lib/skills/core.js +189 -7
  44. package/lib/skills/frontmatter.js +31 -0
  45. package/lib/skills/manager-state.js +73 -3
  46. package/lib/skills/service.js +53 -13
  47. package/lib/skills/skill-roots.js +54 -4
  48. package/lib/skills/skill-trash.js +118 -12
  49. package/lib/skills/upload-pipeline.js +110 -26
  50. package/lib/subagents/catalog.js +9 -5
  51. package/lib/subagents/service.js +44 -6
  52. package/lib/subagents/tools.js +45 -15
  53. package/lib/tool-table-switch.js +6 -6
  54. package/lib/tools/deps.js +43 -0
  55. package/lib/tools/mcp.js +74 -27
  56. package/lib/tools/memory.js +49 -9
  57. package/lib/tools/prompt.js +38 -9
  58. package/lib/tools/remove.js +206 -0
  59. package/lib/tools/scene.js +155 -32
  60. package/lib/tools/skills.js +162 -55
  61. package/lib/tools/subagent.js +65 -31
  62. package/lib/tools/table.js +39 -12
  63. package/lib/trash-id.js +16 -0
  64. package/lib/trash-retention.js +3 -3
  65. package/package.json +115 -114
  66. package/lib/mcp/inspect-probe.js +0 -199
package/README_EN.md CHANGED
@@ -1,223 +1,234 @@
1
- <p align="center">
2
- <img src="docs/images/logo.png" width="120" height="120" alt="dsh-plugin-tool-management">
3
- </p>
4
-
5
- # dsh-plugin-tool-management
6
-
7
- [![npm version](https://img.shields.io/npm/v/dsh-plugin-tool-management?logo=npm&color=cb3837)](https://www.npmjs.com/package/dsh-plugin-tool-management)
8
- [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
9
- [![Node](https://img.shields.io/badge/node-%3E%3D18-339933?logo=node.js)](package.json)
10
- [![GitHub](https://img.shields.io/badge/GitHub-ouli--1242%2Fdsh--plugin--tool--management-181717?logo=github)](https://github.com/ouli-1242/dsh-plugin-tool-management)
11
-
12
- [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
13
- [![awesome-dsh-plugin](https://img.shields.io/badge/awesome--dsh--plugin-listed-3fb950)](https://awesome-dsh-plugin.com)
14
- [![dshfind](https://dshfind.com/api/badge/ouli-1242/dsh-plugin-tool-management?lang=en)](https://dshfind.com/en/plugins/ouli-1242/dsh-plugin-tool-management)
15
- [![0xsline](https://img.shields.io/badge/0xsline-listed-3fb950)](https://github.com/0xsline/awesome-deepseek-harness)
16
-
17
- [简体中文](README.md) · **English** · [Changelog](CHANGELOG.md) · [Release overview](docs/update.md)
18
-
19
- An **MCP, skills, scenes, memories, subagents, prompts & archived sessions** manager for DeepSeek Harness. Eight tabs: Scenes / MCP / Skills / Subagents / Prompts / Memories / Sessions / Host.
20
-
21
- ```sh
22
- dsh plugin --profile web add dsh-plugin-tool-management@latest # web
23
- dsh plugin --profile desktop add dsh-plugin-tool-management@latest # desktop
24
- ```
25
-
26
- Hard-refresh the browser after installing for web (Cmd/Ctrl+Shift+R), or restart the desktop app after installing for desktop — a **Tools** panel in Settings means it worked. The plugin only writes its own files, never touches skill sources, and your configuration survives restarts and upgrades.
27
-
28
- ---
29
-
30
- ## Demo
31
-
32
- <video controls src="https://github.com/user-attachments/assets/91b9673d-d201-462a-83de-8bc663c7629d"></video>
33
-
34
- Every interface shown is a real screenshot of the running product — no redrawn UI, no fabricated controls.
35
-
36
- Music: Kevin MacLeod「Limit 70」, [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
37
-
38
- ---
39
-
40
- ## Screenshots
41
-
42
- | | |
43
- |:---------------------------------:|:----------------------------------:|
44
- | ![Scenes](docs/images/1-EN.png) | ![MCP](docs/images/2-EN.png) |
45
- | **Scenes** | **MCP** |
46
- | ![Skills](docs/images/3-EN.png) | ![Subagents](docs/images/4-EN.png) |
47
- | **Skills** | **Subagents** |
48
- | ![Prompts](docs/images/5-EN.png) | ![Memories](docs/images/6-EN.png) |
49
- | **Prompts** | **Memories** |
50
- | ![Sessions](docs/images/7-EN.png) | ![Host](docs/images/8-EN.png) |
51
- | **Sessions** | **Host** |
52
-
53
- ## Highlights
54
-
55
- In one line: **configure "work / writing / coding" each as a scene and switch the whole stack with one click — and the model always sees whatever this plugin manages.**
56
-
57
- | Highlight | What it means |
58
- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
59
- | One-click scene switch | Each scene carries its own MCP / skills / personas / memories; entering applies them, leaving restores. The model can switch for you too |
60
- | Manage without leaving chat | Type `/` for a "Tools" section and toggle any domain's items — one click, done |
61
- | Memories reach the model | A few `.md` files under a scene become its knowledge base, injected automatically |
62
- | Notes for MCP servers | A note you write is seen by the model every turn and acted on |
63
- | Disable a single tool | Mute one tool on a server: invisible to the model and uncallable |
64
- | Skills at a glance | The copy in effect is marked "preferred"; shadowed ones name the winning source |
65
- | Subagent = one file, one role | Write a role file and delegate to it; only the result comes back, never in History |
66
- | Several prompt presets | Keep multiple `AGENTS.md` baselines and switch with one click; each scene can bind its own, or none |
67
- | Sessions no longer lost | Archives grouped by project, searchable, batch-restorable; imports Claude Code / Cursor / Codex transcripts |
68
- | The model always sees it | One context message per domain, republished only when the content changes |
69
- | Lock it and relax | Locking a scene makes create/update/delete across the five domains read-only |
70
- | Deleted is not gone | Skills / memories / personas / presets / scenes land in a recycle bin (permanent session deletion excepted); tick items to delete in bulk, or set a retention period so it cleans itself (keep-forever by default) |
71
- | Safe by default | Only the plugin's own files are written; secrets masked, plaintext needs a token |
72
-
73
- ## Quick start
74
-
75
- Prerequisites: DSH installed (`dsh web` runs), Node.js ≥ 18. Pick the profile matching your client: `--profile web` for the browser app, `--profile desktop` for the desktop app. The desktop profile is initialized by DSH Desktop itself — open the app once, then quit it completely before running the command.
76
-
77
- ```sh
78
- dsh plugin --profile web add dsh-plugin-tool-management@latest # web · install / update
79
- dsh plugin --profile web remove dsh-plugin-tool-management # web · uninstall
80
- dsh plugin --profile desktop add dsh-plugin-tool-management@latest # desktop · install / update
81
- dsh plugin --profile desktop remove dsh-plugin-tool-management # desktop · uninstall
82
- ```
83
-
84
- Hard-refresh the browser (web) or restart the desktop app, then a **Tools** panel with eight tabs means it worked. Client changes hot-reload; host-side changes need the client restarted (`dsh web` / the desktop app).
85
-
86
- You can also ask the model:
87
-
88
- ```text
89
- Install the dsh-plugin-tool-management plugin:
90
- dsh plugin --profile web add dsh-plugin-tool-management@latest
91
- Then remind me to hard-refresh the browser.
92
- ```
93
-
94
- For the desktop app, swap `web` for `desktop` and end with "remind me to restart the desktop app" instead.
95
-
96
- ## Features
97
-
98
- ### Slash commands (manage from the chat box)
99
-
100
- - **Type `/` for a "Tools" section**: scenes / skills / MCP servers / subagents / prompts / memories. Click a row to enter that domain, click an item to apply it; the menu stays open.
101
- - **State is visible** (green check / empty box / note in grey), and long lists scroll on their own; each external skill directory gets one row that toggles the whole source.
102
- - **Only reversible actions**: entering a scene and the various toggles; create / delete / edit / import / export stay on their own pages.
103
-
104
- ### Scenes & memories
105
-
106
- - **A scene = a group, a memory = a `.md` file**: `memories/<scene>/<name>.md`, the whole body is injected.
107
- - **"Enabled" and "entered" are two axes**: enabled decides which scene the injection follows (single-select; none enabled = only `global` and `_shared`); entering applies the scene's whole MCP / skills / personas set and writes its bound prompt into `AGENTS.md`.
108
- - **Scene profile**: ticked = on, unchecked = off, a section never created means that domain is off; leaving restores the pre-scene state.
109
- - **Every domain offers "None"**: for MCP / skills / personas / memories / global prompt it means the scene leaves that domain alone; for quick prompts it means none are enabled while the scene is on, and it is the default for a new scene.
110
- - **Scene lock** makes those five domains read-only; deleting a scene takes its memories with it into one recycle-bin entry. Import / export `.md` / `.zip`, same names skipped.
111
-
112
- ### Subagents
113
-
114
- - **One file per persona**: `subagents/<persona>.md`, frontmatter entirely optional.
115
- - **Delegation**: `subagent_manager_run` runs with the persona, returns only its final result, and never enters History; `inherit: true` seeds the child with this conversation's finished turns.
116
- - **On/off**: a disabled persona is neither injected nor visible to the model; new / imported / restored personas start disabled.
117
- - **Tool limits per agent preset**: one allow or deny list per preset (mutually exclusive). Model and provider are picked from the host LLM catalogue; empty means inherit the main session.
118
-
119
- ### MCP servers
120
-
121
- - **CRUD with immediate effect**: written into `cordis.patch.yml`, backed up before every change.
122
- - **Per-tool switches**: disable individual tools, or a whole server; a stopped server still shows the tools last seen.
123
- - **Secret masking**: a credential is replaced as a whole, and "Reveal" needs a token; a masked value is never written back.
124
- - A per-server note travels along as a decision hint; migration rolls back on failure, with JSON export/import.
125
-
126
- ### Skills
127
-
128
- - **Sources at a glance**: project / DSH / Agents / Codex / Claude / custom directories, grouped by source.
129
- - **Opposite permissions**: default sources are readable and their skills deletable; external directories can be disabled or removed but their files stay read-only.
130
- - **Remove ≠ disable**: removing stops scanning the directory at all (nothing is written, restorable); disabling keeps it listed but uncallable.
131
- - The winning copy of a shared name is marked "preferred"; custom directories, ZIP import/export and the recycle bin are all here.
132
-
133
- ### Prompt presets
134
-
135
- - Multiple `~/.dsh/AGENTS.md` baselines, applied with one click (next turn), with 5 generations of backups; each preset can carry a one-line description that is never injected.
136
- - **The switch on the left of a card is the answer to "is this one in effect"**: flip it on and that preset is written into `AGENTS.md`; flip it off to **un-apply**, which restores the state from before you started applying (and deletes the file if there was none back then). The confirmation says which one it will be, and a receipt afterwards states what happened.
137
- - **Two kinds cannot be deleted directly**: a scene-bound preset, and the one currently applied. The copy auto-created on first open can be deleted. Deletes always go to the recycle bin.
138
- - **Quick prompts** (the second section on the same page): save a piece of text you keep typing, then hit `/` and click it; a scene can bind a set of them.
139
- - **This page's recycle bin is split in two by domain**, each half scrolling on its own with its own batch bar.
140
-
141
- ### Archived sessions
142
-
143
- - Grouped by project, searchable, batch restore / delete, retention auto-cleanup; a workspace whose registration was deleted can be re-registered in one click.
144
- - Import Claude Code / Cursor / Codex / any text; export Markdown / JSONL in three cumulative modes: text only → plus tool calls → plus reasoning. **An export is a transcript, not a backup**.
145
-
146
- ### Host compatibility
147
-
148
- - **Host tab**: host version, usable capability count, per-action routing (native / adapter / unavailable), degradations and reasons; three write entries: access token, injection settings, model tool table.
149
- - **Command line**: `node scripts/doctor.mjs` (health check), `node scripts/host-deps.mjs --fix` (align dependencies).
150
- - Under a **suppressing preset** such as `minimal`, this plugin's injection is off by default; the Host tab can force any domain back on.
151
- - Unchecking "Skills" or "Prompt" really stops them — under standard presets the host delivers those two itself.
152
-
153
- ---
154
-
155
- ## Where data lives
156
-
157
- | Content | Location |
158
- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
159
- | MCP definitions | `~/.dsh/cordis.patch.yml` (written by the plugin; pre-write copies land in the hub's `backups/`) |
160
- | Skill policy / custom dirs | `~/.dsh/tool-management/skills-state.json` |
161
- | Skills / memories / personas / presets | `~/.dsh/tool-management/{skills,memories,subagents,prompts}/` |
162
- | Subagent toggles | `~/.dsh/tool-management/subagents-index.json` |
163
- | Recycle bin (skills / personas / presets / scenes) | `~/.dsh/tool-management/trash/{skills,subagents,prompts,scenes}-trash/` |
164
- | Memory recycle bin | `~/.dsh/tool-management/memories-trash/` (a directory at the hub root, not under `trash/`) |
165
- | Archive ledger / retention | `~/.dsh/tool-management/history-*.json` |
166
- | Recycle-bin retention | `~/.dsh/tool-management/trash-retention.json` (`0` = keep forever) |
167
- | Memory index / scenes / profiles | `~/.dsh/tool-management/memories-index.json` |
168
- | MCP sidecars (disabled tools / known tools / notes / settings) | `~/.dsh/tool-management/mcp-*.json` |
169
- | Injection settings (six domain switches) | `~/.dsh/tool-management/inject-settings.json` |
170
- | Model tool table (switched-off tools + saved sets) | `~/.dsh/tool-management/tool-table.json` |
171
- | Scene page preference (preview card before entering a scene) | `~/.dsh/tool-management/scene-settings.json` |
172
- | Runtime log / patch backups | `~/.dsh/tool-management/tool-management.log` · `backups/` |
173
-
174
- **No user data is stored inside the plugin's install directory** (`dsh plugin update` replaces it wholesale). `backups/` keeps **5 copies per patch file** — the global patch and each profile patch count separately.
175
-
176
- ## Configuration & security
177
-
178
- | Field | What it does |
179
- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
180
- | `token` | Access token. Once set, **every write and every plaintext credential** requires `x-dsh-token`; with no token the plaintext endpoints are closed entirely. Prefer not to keep it in the config? Use the `DSH_PLUGIN_TOOL_MANAGEMENT_TOKEN` environment variable. |
181
- | `tokenDisabled` | `true` = the token stays in the config but is not enforced (this is the line written by "Turn protection off"). Writes no longer need it; revealing plaintext still does. |
182
- | `maxBodyBytes` | Request body cap, 88 MiB by default. |
183
-
184
- **Plaintext on disk (read this)**: masking is **display-only**; MCP `env` / `headers` and the plugin's own `token` stay in cleartext inside `cordis.patch.yml` (and each profile copy), and every config change copies the whole file into `~/.dsh/tool-management/backups/` — unencrypted, never rotated, not reclaimed on uninstall. One secret can therefore exist as `5 × (patch files holding it) + 1` plaintext copies. The token gate decides *who may read plaintext over HTTP*; it does nothing about *reading the files*, where the only defence is your filesystem permissions. **To clean up: Settings → Tools → Host → "Clean old backups"**.
185
-
186
- - **Browser**: reads and writes go through cookies, no token needed; **plaintext credentials** (reveal / export) do. The token is managed in the **Access token** block on the Host tab.
187
- - **Every destructive direction asks for the current token again** (turn protection off / change / delete). Being unlocked this run does not count.
188
- - **curl / scripts**: send `x-dsh-token`, or carry the browser cookie. Except for the fence's 401 / 403, failures come back as **HTTP 200 + `{ ok: false, error }`** — branch on `body.ok`.
189
- - **Port forwarding**: when the host has no `connection` service the fence falls back to "loopback Host + same origin", which any local process can imitate. If you forward the port to a LAN or the public internet, **configure a token**.
190
- - **Avoid `__` in a server name**: a tool's full name is `mcp__<server>__<tool>`, so an extra `__` inside a server name makes it ambiguous; the Host tab shows an informational note.
191
-
192
- ## FAQ
193
-
194
- | Symptom | Fix |
195
- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
196
- | Pages missing after install | Hard refresh; restart DSH if that fails. |
197
- | Duplicate MCP tabs | Remove the stale loader row from `cordis.patch.yml`, restart. |
198
- | Broken config, DSH won't boot | Restore the newest `cordis.patch.yml.<level>.bak-<timestamp>` from `~/.dsh/tool-management/backups/` (5 per patch file). |
199
- | Action stopped working after a DSH upgrade | Settings → Tools → **Host** for the reason; `doctor.mjs` → `host-deps.mjs --fix`. |
200
- | The model cannot call a tool it should have | Check the **Model tool table** on the Host tab — 15 tools ship switched off. The panel and scripts are unaffected either way. |
201
- | Still asked to confirm with `approval=never`? | No card appears — straight through with a log line. Switch back to "workspace write" to get the questions again. |
202
- | `subagent_manager_run` reports provider unavailable | The provider is not registered: `spawn` (default) / `fork` (`inherit`) come from `@deepseek-ai/dsh-subagent-spawn-in-process` / `-fork-in-process` — mount and restart. |
203
- | Scene binds persona A, but the official `subagent` ran something else | Those two are host tools and this plugin cannot hide them; work matching a persona goes to `subagent_manager_run`, host tools only when no persona fits or a background job is needed. |
204
-
205
- ---
206
-
207
- ## Development
208
-
209
- ```bash
210
- npm install
211
- npm run build # tsc + sync client
212
- npm test # build + i18n + contract tests (pure-function invariants & host contracts)
213
- npm run check:i18n # dictionary self-check
214
- npm run doctor # host compatibility check
215
- ```
216
-
217
- `lib/` is not tracked — run `npm run build` after cloning. Changes need `dsh web` restarted. Runtime deps: `fflate` (export bundling) and `js-yaml` (parse check before writing host patches, loaded lazily); `@deepseek-ai/*` all come from the host.
218
-
219
- > **Deployment note**: the profile mirror produced by `npm run build` does **not** include `node_modules`, so a runtime dependency added locally (e.g. `js-yaml`) must either be installed on the profile side or accepted as "patch-write check skipped and reported". Regular `npm install` deployments are unaffected.
220
-
221
- ## License
222
-
223
- MIT
1
+ <p align="center">
2
+ <img src="docs/images/logo.png" width="120" height="120" alt="dsh-plugin-tool-management">
3
+ </p>
4
+
5
+ # dsh-plugin-tool-management
6
+
7
+ [![npm version](https://img.shields.io/npm/v/dsh-plugin-tool-management?logo=npm&color=cb3837)](https://www.npmjs.com/package/dsh-plugin-tool-management)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
9
+ [![Node](https://img.shields.io/badge/node-%3E%3D18-339933?logo=node.js)](package.json)
10
+ [![GitHub](https://img.shields.io/badge/GitHub-ouli--1242%2Fdsh--plugin--tool--management-181717?logo=github)](https://github.com/ouli-1242/dsh-plugin-tool-management)
11
+
12
+ [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
13
+ [![awesome-dsh-plugin](https://img.shields.io/badge/awesome--dsh--plugin-listed-3fb950)](https://awesome-dsh-plugin.com)
14
+ [![dshfind](https://dshfind.com/api/badge/ouli-1242/dsh-plugin-tool-management?lang=en)](https://dshfind.com/en/plugins/ouli-1242/dsh-plugin-tool-management)
15
+ [![0xsline](https://img.shields.io/badge/0xsline-listed-3fb950)](https://github.com/0xsline/awesome-deepseek-harness)
16
+
17
+ [简体中文](README.md) · **English** · [Changelog](CHANGELOG.md) · [Release overview](docs/update.md)
18
+
19
+ An **MCP, skills, scenes, memories, subagents, prompts & archived sessions** manager for DeepSeek Harness. Eight tabs: Scenes / MCP / Skills / Subagents / Prompts / Memories / Sessions / Host.
20
+
21
+ ```sh
22
+ dsh plugin --profile web add dsh-plugin-tool-management@latest # web
23
+ dsh plugin --profile desktop add dsh-plugin-tool-management@latest # desktop
24
+ ```
25
+
26
+ Hard-refresh the browser after installing for web (Cmd/Ctrl+Shift+R), or restart the desktop app after installing for desktop — a **Tools** panel in Settings means it worked. The plugin only writes its own files, never touches skill sources, and your configuration survives restarts and upgrades.
27
+
28
+ ---
29
+
30
+ ## Demo
31
+
32
+ <video controls src="https://github.com/user-attachments/assets/91b9673d-d201-462a-83de-8bc663c7629d"></video>
33
+
34
+ Every interface shown is a real screenshot of the running product — no redrawn UI, no fabricated controls.
35
+
36
+ Music: Kevin MacLeod「Limit 70」, [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
37
+
38
+ ---
39
+
40
+ ## Screenshots
41
+
42
+ | | |
43
+ |:---------------------------------:|:----------------------------------:|
44
+ | ![Scenes](docs/images/1-EN.png) | ![MCP](docs/images/2-EN.png) |
45
+ | **Scenes** | **MCP** |
46
+ | ![Skills](docs/images/3-EN.png) | ![Subagents](docs/images/4-EN.png) |
47
+ | **Skills** | **Subagents** |
48
+ | ![Prompts](docs/images/5-EN.png) | ![Memories](docs/images/6-EN.png) |
49
+ | **Prompts** | **Memories** |
50
+ | ![Sessions](docs/images/7-EN.png) | ![Host](docs/images/8-EN.png) |
51
+ | **Sessions** | **Host** |
52
+
53
+ ## Highlights
54
+
55
+ In one line: **configure "work / writing / coding" each as a scene and switch the whole stack with one click — and the model always sees whatever this plugin manages.**
56
+
57
+ | Highlight | What it means |
58
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
59
+ | One-click scene switch | Each scene carries its own MCP / skills / personas / memories; entering applies them, leaving restores. The model can switch for you too |
60
+ | Manage without leaving chat | Type `/` for a "Tools" section and toggle any domain's items — one click, done |
61
+ | Memories reach the model | A few `.md` files under a scene become its knowledge base, injected automatically |
62
+ | Notes for MCP servers | A note you write is seen by the model every turn and acted on |
63
+ | Disable a single tool | Mute one tool on a server: invisible to the model and uncallable |
64
+ | Skills at a glance | The copy in effect is marked "preferred"; shadowed ones name the winning source |
65
+ | Subagent = one file, one role | Write a role file and delegate to it; only the result comes back, never in History |
66
+ | Several prompt presets | Keep multiple `AGENTS.md` baselines and switch with one click; each scene can bind its own, or none |
67
+ | Sessions no longer lost | Archives grouped by project, searchable, batch-restorable; imports Claude Code / Cursor / Codex transcripts |
68
+ | The model always sees it | One context message per domain, republished only when the content changes |
69
+ | Lock it and relax | Locking a scene makes create/update/delete across the five domains read-only |
70
+ | Deleted is not gone | Skills / memories / personas / presets / scenes land in a recycle bin (permanent session deletion excepted); tick items to delete in bulk, or set a retention period so it cleans itself (keep-forever by default) |
71
+ | Safe by default | Only the plugin's own files are written; secrets masked, plaintext needs a token |
72
+
73
+ ## Quick start
74
+
75
+ Prerequisites: DSH installed (`dsh web` runs), Node.js ≥ 18. Pick the profile matching your client: `--profile web` for the browser app, `--profile desktop` for the desktop app. The desktop profile is initialized by DSH Desktop itself — open the app once, then quit it completely before running the command.
76
+
77
+ ```sh
78
+ dsh plugin --profile web add dsh-plugin-tool-management@latest # web · install / update
79
+ dsh plugin --profile web remove dsh-plugin-tool-management # web · uninstall
80
+ dsh plugin --profile desktop add dsh-plugin-tool-management@latest # desktop · install / update
81
+ dsh plugin --profile desktop remove dsh-plugin-tool-management # desktop · uninstall
82
+ ```
83
+
84
+ Hard-refresh the browser (web) or restart the desktop app, then a **Tools** panel with eight tabs means it worked. Client changes hot-reload; host-side changes need the client restarted (`dsh web` / the desktop app).
85
+
86
+ You can also ask the model:
87
+
88
+ ```text
89
+ Install the dsh-plugin-tool-management plugin:
90
+ dsh plugin --profile web add dsh-plugin-tool-management@latest
91
+ Then remind me to hard-refresh the browser.
92
+ ```
93
+
94
+ For the desktop app, swap `web` for `desktop` and end with "remind me to restart the desktop app" instead.
95
+
96
+ ## Features
97
+
98
+ ### Slash commands (manage from the chat box)
99
+
100
+ - **Type `/` for a "Tools" section**: scenes / skills / MCP servers / subagents / prompts / memories. Click a row to enter that domain, click an item to apply it; the menu stays open.
101
+ - **State is visible**: green check / empty box / note in grey, plus a status summary on the domain row.
102
+ - **Long lists stay out of the way**: every domain lists in full and scrolls on its own; skills group by source directory, memories by scene, enabled ones first.
103
+ - **Both kinds of prompts are here**: the global group picks which one is written into `AGENTS.md` (single-select); the quick group is on/off, and clicking one pastes the saved text into the input box without sending it.
104
+ - **Only reversible actions**: entering a scene and the various toggles; create / delete / edit / import / export stay on their own pages.
105
+ - **Registered through the host's own channel**: DSH's input-trigger interface, no patching of official packages.
106
+
107
+ ### Scenes & memories
108
+
109
+ - **A scene = a group, a memory = a `.md` file**: `memories/<scene>/<name>.md`, the whole body is injected, file names may be Chinese.
110
+ - **"Enabled" and "entered" are two axes**: enabled decides which scene the injection follows (single-select; none enabled = only `global` and `_shared`); entering applies the scene's whole MCP / skills / personas set and writes its bound prompt into `AGENTS.md`.
111
+ - **Scene profile**: each scene pairs a set of MCP tools (with scene-level note overrides) / skills / subagents / quick prompts / a model tool-table scheme, plus a bound global prompt preset; ticked = on, unchecked = off, a section never created means that domain is off (quick prompts excepted: unbound = left alone on entry); leaving restores the pre-scene state.
112
+ - **Every domain also offers "None"**: this scene leaves that domain alone (the prompt cell = leave `AGENTS.md` as-is; quick prompts = none enabled). It differs from "keep current" — that one really changes nothing.
113
+ - **Scene lock** makes those five domains read-only.
114
+ - **Deleting a scene takes its memories with it**: the record, the profile and every memory go into one recycle-bin entry and come back together; a scene in use refuses to be deleted.
115
+ - **Import / export** `.md` / `.zip` (directory name = scene, bundles carry attachments), same names skipped and never overwritten; the injection budget defaults to 128 KiB, and anything that does not fit is skipped and listed.
116
+
117
+ ### Subagents
118
+
119
+ - **One file per persona**: `subagents/<persona>.md`, frontmatter entirely optional; `output:` gives one line per requirement for what the result must look like. The body is used verbatim under a `# Persona: <name>` heading, and the file itself needs no changes.
120
+ - **Delegation**: `subagent_manager_run` runs with the persona, returns only its final result, and never enters History; it starts a fresh session by default, and `inherit: true` seeds it with this conversation's finished turns.
121
+ - **On/off and catalogue**: a disabled persona is neither injected nor visible to the model (the file stays put); new / imported / restored personas start disabled. The catalogue lists name + description only.
122
+ - **Tool limits per agent preset**: one allow or deny list per preset (mutually exclusive); candidates list only that preset's own tools, split into "plugin tools / official tools / other tools".
123
+ - **Model and provider**: both are picked from the host LLM catalogue (choosing a provider narrows the model list); empty means inherit the main session, and the reasoning-effort level comes from the chosen model.
124
+
125
+ ### MCP servers
126
+
127
+ - **CRUD with immediate effect**: written into `cordis.patch.yml`, backed up before every change; scope is "global / app-level", and new entries default to global.
128
+ - **Per-tool switches**: disable individual tools (invisible and uncallable to the model), or a whole server in one go.
129
+ - **A stopped server still shows its list**: tools last seen are listed with their descriptions (marked "as of last run"); one that never ran can be started to read them.
130
+ - **Notes and secrets**: a per-server note for the model travels along with the status section; credentials are masked as a whole (`$VAR`, `!!js` and similar indirect references are left alone), and "Reveal" needs a token.
131
+ - **Migration and backups**: a cross-scope migration rolls back on failure; JSON export/import is supported.
132
+
133
+ ### Skills
134
+
135
+ - **Sources at a glance**: project / DSH / Agents / Codex / Claude / custom directories, grouped by source.
136
+ - **Opposite permissions**: default sources are readable and their skills deletable; external directories can be disabled or removed but their files stay read-only.
137
+ - **Remove ≠ disable**: removing stops scanning the directory at all (nothing is written, restorable); disabling keeps it listed but uncallable.
138
+ - **The winning copy of a shared name** is marked "preferred", and the ones it shadows are marked with their source.
139
+ - **Custom directories / ZIP import-export / recycle bin.**
140
+
141
+ ### Prompt presets
142
+
143
+ - **Multiple `~/.dsh/AGENTS.md` baselines**, applied with one click (next turn), with 5 generations of backups; each preset can carry a one-line description that lives only on the plugin side; the last applied preset is always identifiable, even after you edit `AGENTS.md` by hand.
144
+ - **The switch on the left of a card is the answer to "is this one in effect"**: flip it on and that preset is written into `AGENTS.md`; flip it off to **un-apply**. The confirmation says which one it will be (the button turns red when the file is going to be deleted), and a receipt follows.
145
+ - **"Un-apply" goes back to the start of the chain, not one step**: it restores whatever was there before this run of apply / un-apply began (deleting the file if there was none); every intermediate version stays in `__last-applied__/AGENTS.md.bak-*` (5 generations), so it can be applied again.
146
+ - **Two kinds cannot be deleted directly**: a scene-bound preset, and the one currently applied (un-apply it first). The copy auto-created on first open was never applied and can be deleted. Deletes always go to the recycle bin.
147
+ - **Quick prompts** (the second section on the same page): save a piece of text you keep typing, then hit `/` and click it to paste it in; a scene can bind a set of them (only the ticked ones are on while the scene is entered, restored on exit, or pick "None").
148
+
149
+ ### Archived sessions
150
+
151
+ - Grouped by project, searchable, batch restore / delete, retention auto-cleanup; a workspace whose registration was deleted can be re-registered in one click.
152
+ - Import Claude Code / Cursor / Codex / any text (pick a workspace, browse for one, or type a path).
153
+ - Export Markdown / JSONL in three cumulative modes: text only → plus tool calls → plus reasoning. **An export is a transcript, not a backup** — use "archive" to keep everything.
154
+
155
+ ### Host compatibility
156
+
157
+ - **Host tab**: host version, usable capability count, per-action routing (native / adapter / unavailable), degradations and reasons; three write entries: access token, injection settings, model tool table.
158
+ - **Command line**: `node scripts/doctor.mjs` (health check), `node scripts/host-deps.mjs --fix` (align dependencies).
159
+ - Under a **suppressing preset** such as `minimal`, this plugin's injection is off by default; the Host tab can force any domain back on.
160
+ - Unchecking "Skills" or "Prompt" really stops them — under standard presets the host delivers those two itself; the other three domains follow the checkbox exactly.
161
+ - **What the injection looks like**: one `<system-reminder>` per domain — `# heading` + body + a "this one wins" line; a `</system-reminder>` inside the body is escaped.
162
+
163
+ ---
164
+
165
+ ## Where data lives
166
+
167
+ | Content | Location |
168
+ | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
169
+ | MCP definitions | `~/.dsh/cordis.patch.yml` (written by the plugin; pre-write copies land in the hub's `backups/`) |
170
+ | Skill policy / custom dirs | `~/.dsh/tool-management/skills-state.json` |
171
+ | Skills / memories / personas / presets | `~/.dsh/tool-management/{skills,memories,subagents,prompts}/` |
172
+ | Subagent toggles | `~/.dsh/tool-management/subagents-index.json` |
173
+ | Recycle bin (skills / memories / personas / presets / scenes) | `~/.dsh/tool-management/trash/<domain>-trash/` (one directory per kind) |
174
+ | Archive ledger / retention | `~/.dsh/tool-management/history-*.json` |
175
+ | Recycle-bin retention | `~/.dsh/tool-management/trash-retention.json` (`0` = keep forever) |
176
+ | Memory index / scenes / profiles | `~/.dsh/tool-management/memories-index.json` |
177
+ | MCP sidecars (disabled tools / known tools / notes / settings) | `~/.dsh/tool-management/mcp-*.json` |
178
+ | Injection settings (six domain switches) | `~/.dsh/tool-management/inject-settings.json` |
179
+ | Model tool table (switched-off tools + saved sets) | `~/.dsh/tool-management/tool-table.json` |
180
+ | Scene page preference (preview card before entering a scene) | `~/.dsh/tool-management/scene-settings.json` |
181
+ | Runtime log / patch backups | `~/.dsh/tool-management/tool-management.log` · `backups/` |
182
+
183
+ **No user data is stored inside the plugin's install directory** (`dsh plugin update` replaces it wholesale). `backups/` keeps **5 copies per patch file** — the global patch and each profile patch count separately.
184
+
185
+ The six recycle bins each own one directory under `trash/`: `{skills,memories,subagents,prompts,scenes,quick-prompts}-trash/`. The memories one moved in from the hub root on 2026-10-10; existing data is carried over by the startup migration.
186
+
187
+ ## Configuration & security
188
+
189
+ | Field | What it does |
190
+ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
191
+ | `token` | Access token. Once set, **every write and every plaintext credential** requires `x-dsh-token`; with no token the plaintext endpoints are closed entirely. Prefer not to keep it in the config? Use the `DSH_PLUGIN_TOOL_MANAGEMENT_TOKEN` environment variable. |
192
+ | `tokenDisabled` | `true` = the token stays in the config but is not enforced (this is the line written by "Turn protection off"). Writes no longer need it; revealing plaintext still does. |
193
+ | `maxBodyBytes` | Request body cap, 88 MiB by default. |
194
+
195
+ **Plaintext on disk (read this)**: masking is **display-only**; MCP `env` / `headers` and the plugin's own `token` stay in cleartext inside `cordis.patch.yml` (and each profile copy), and every config change copies the whole file into `~/.dsh/tool-management/backups/` — unencrypted, never rotated, not reclaimed on uninstall. One secret can therefore exist as `5 × (patch files holding it) + 1` plaintext copies. The token gate decides *who may read plaintext over HTTP*; it does nothing about *reading the files*, where the only defence is your filesystem permissions. **To clean up: Settings → Tools → Host → "Clean old backups"**.
196
+
197
+ - **Browser**: reads and writes go through cookies, no token needed; **plaintext credentials** (reveal / export) do. The token is managed in the **Access token** block on the Host tab.
198
+ - **Every destructive direction asks for the current token again** (turn protection off / change / delete). Being unlocked this run does not count.
199
+ - **curl / scripts**: send `x-dsh-token`, or carry the browser cookie. Except for the fence's 401 / 403, failures come back as **HTTP 200 + `{ ok: false, error }`** — branch on `body.ok`.
200
+ - **Port forwarding**: when the host has no `connection` service the fence falls back to "loopback Host + same origin", which any local process can imitate. If you forward the port to a LAN or the public internet, **configure a token**.
201
+ - **Avoid `__` in a server name**: a tool's full name is `mcp__<server>__<tool>`, so an extra `__` inside a server name makes it ambiguous; the Host tab shows an informational note.
202
+
203
+ ## FAQ
204
+
205
+ | Symptom | Fix |
206
+ | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
207
+ | Pages missing after install | Hard refresh; restart DSH if that fails. |
208
+ | Duplicate MCP tabs | Remove the stale loader row from `cordis.patch.yml`, restart. |
209
+ | Broken config, DSH won't boot | Restore the newest `cordis.patch.yml.<level>.bak-<timestamp>` from `~/.dsh/tool-management/backups/` (5 per patch file). |
210
+ | Action stopped working after a DSH upgrade | Settings → Tools → **Host** for the reason; `doctor.mjs` → `host-deps.mjs --fix`. |
211
+ | The model cannot call a tool it should have | Check the **Model tool table** on the Host tab — 19 tools ship switched off. The panel and scripts are unaffected either way. |
212
+ | Still asked to confirm with `approval=never`? | No card appears — straight through with a log line. Switch back to "workspace write" to get the questions again. |
213
+ | `subagent_manager_run` reports provider unavailable | The provider is not registered: `spawn` (default) / `fork` (`inherit`) come from `@deepseek-ai/dsh-subagent-spawn-in-process` / `-fork-in-process` — mount and restart. |
214
+ | Scene binds persona A, but the official `subagent` ran something else | Those two are host tools and this plugin cannot hide them; work matching a persona goes to `subagent_manager_run`, host tools only when no persona fits or a background job is needed. |
215
+
216
+ ---
217
+
218
+ ## Development
219
+
220
+ ```bash
221
+ npm install
222
+ npm run build # tsc + sync client
223
+ npm test # build + i18n + contract tests (pure-function invariants & host contracts)
224
+ npm run check:i18n # dictionary self-check
225
+ npm run doctor # host compatibility check
226
+ ```
227
+
228
+ `lib/` is not tracked — run `npm run build` after cloning. Changes need `dsh web` restarted. Runtime deps: `fflate` (export bundling) and `js-yaml` (parse check before writing host patches, loaded lazily); `@deepseek-ai/*` all come from the host.
229
+
230
+ > **Deployment note**: the profile mirror produced by `npm run build` does **not** include `node_modules`, so a runtime dependency added locally (e.g. `js-yaml`) must either be installed on the profile side or accepted as "patch-write check skipped and reported". Regular `npm install` deployments are unaffected.
231
+
232
+ ## License
233
+
234
+ MIT
Binary file
package/docs/images/1.png CHANGED
Binary file
Binary file
package/docs/images/2.png CHANGED
Binary file
Binary file
package/docs/images/3.png CHANGED
Binary file
Binary file
package/docs/images/4.png CHANGED
Binary file
Binary file
package/docs/images/5.png CHANGED
Binary file
Binary file
package/docs/images/6.png CHANGED
Binary file
Binary file
package/docs/images/7.png CHANGED
Binary file
Binary file
package/docs/images/8.png CHANGED
Binary file
Binary file