dsh-plugin-tool-management 0.6.0 → 0.8.0
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.
- package/CHANGELOG.md +179 -0
- package/README.md +117 -221
- package/README_EN.md +116 -220
- package/docs/images/1/345/234/272/346/231/257.png +0 -0
- package/docs/images/1/345/234/272/346/231/257_en.png +0 -0
- package/docs/images/2MCP.png +0 -0
- package/docs/images/2MCP_en.png +0 -0
- package/docs/images/3/346/212/200/350/203/275.png +0 -0
- package/docs/images/3/346/212/200/350/203/275_en.png +0 -0
- package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223.png +0 -0
- package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223_en.png +0 -0
- package/docs/images/5/346/217/220/347/244/272/350/257/215.png +0 -0
- package/docs/images/5/346/217/220/347/244/272/350/257/215_en.png +0 -0
- package/docs/images/6/350/256/260/345/277/206.png +0 -0
- package/docs/images/6/350/256/260/345/277/206_en.png +0 -0
- package/docs/images/7/344/274/232/350/257/235.png +0 -0
- package/docs/images/7/344/274/232/350/257/235_en.png +0 -0
- package/docs/images/8/345/205/274/345/256/271.png +0 -0
- package/docs/images/8/345/205/274/345/256/271_en.png +0 -0
- package/docs/update.md +56 -38
- package/lib/agents-md/service.js +84 -5
- package/lib/client.js +1488 -475
- package/lib/compat/preset-reach.js +425 -0
- package/lib/compat/probe.js +8 -0
- package/lib/http-fence.js +21 -0
- package/lib/hub.js +160 -2
- package/lib/index.js +687 -47
- package/lib/mcp/override-blocks.js +195 -0
- package/lib/mcp/state-section.js +90 -0
- package/lib/prompt-sections.js +148 -0
- package/lib/rules/archive-engine.js +99 -29
- package/lib/rules/archive.js +56 -28
- package/lib/rules/service.js +332 -35
- package/lib/skills/core.js +15 -1
- package/lib/skills/service.js +3 -0
- package/lib/subagents/catalog.js +89 -0
- package/lib/subagents/service.js +384 -41
- package/lib/subagents/tools.js +18 -5
- package/package.json +97 -96
- package/screenshots.json +10 -10
- package/docs/Changelog.md +0 -144
- package/lib/rules/provider.js +0 -121
package/README_EN.md
CHANGED
|
@@ -6,80 +6,68 @@
|
|
|
6
6
|
[](https://github.com/ouli-1242/dsh-plugin-tool-management)
|
|
7
7
|
[](https://dsh.market/)
|
|
8
8
|
|
|
9
|
-
[简体中文](README.md) · **English** · [Changelog](
|
|
9
|
+
[简体中文](README.md) · **English** · [Changelog](CHANGELOG.md) · [Release overview](docs/update.md)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- **MCP** — which servers are configured, what tools each exposes, and which ones the model may call: add, edit, remove, toggle, restart, effective immediately;
|
|
14
|
-
- **Skills** — every skill on the machine (DSH / Agents / Codex / Claude / project-level / any custom directory) at a glance, toggled individually or per source, created, imported, recycled;
|
|
15
|
-
- **AGENTS.md** — multiple global instruction baselines as presets, applied with one click into `~/.dsh/AGENTS.md`;
|
|
16
|
-
- **History** — archived sessions grouped by project, batch restore / delete, transcript import & export, retention-based cleanup;
|
|
17
|
-
- **Scene memory** — `memories/<scene>/<name>.md`, one folder per scene; the bodies of memories in an enabled scene are **injected into the system prompt in full**, so you never re-explain them.
|
|
18
|
-
|
|
19
|
-
No hand-editing of `cordis.patch.yml`, no skill source file ever touched, configuration survives restarts and upgrades.
|
|
11
|
+
- An **MCP, skills, scenes, memories, subagents, prompts & archived sessions** manager for DeepSeek Harness.
|
|
12
|
+
- Eight tabs: **Scenes**, **MCP**, **Skills**, **Subagents**, **Prompts**, **Memories**, **Sessions**, **Host**.
|
|
20
13
|
|
|
21
14
|
```sh
|
|
22
15
|
dsh plugin --profile web add dsh-plugin-tool-management@latest
|
|
23
16
|
```
|
|
24
17
|
|
|
25
|
-
Hard-refresh the browser
|
|
26
|
-
|
|
27
|
-
## Screenshots
|
|
28
|
-
|
|
29
|
-

|
|
18
|
+
Hard-refresh the browser (Cmd/Ctrl+Shift-R) afterwards — a **Tools** panel in Settings means it worked. No hand-editing of `cordis.patch.yml`, no skill source files touched, configuration survives restarts and upgrades.
|
|
30
19
|
|
|
31
|
-
|
|
20
|
+
---
|
|
32
21
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-

|
|
36
|
-
|
|
37
|
-

|
|
38
|
-
|
|
39
|
-

|
|
40
|
-
|
|
41
|
-

|
|
22
|
+
## Screenshots
|
|
42
23
|
|
|
43
|
-
|
|
24
|
+
| | |
|
|
25
|
+
|:---:|:---:|
|
|
26
|
+
|  |  |
|
|
27
|
+
| **Scenes** | **MCP** |
|
|
28
|
+
|  |  |
|
|
29
|
+
| **Skills** | **Subagents** |
|
|
30
|
+
|  |  |
|
|
31
|
+
| **Prompts** | **Memories** |
|
|
32
|
+
|  |  |
|
|
33
|
+
| **Sessions** | **Host** |
|
|
44
34
|
|
|
45
35
|
## Highlights
|
|
46
36
|
|
|
47
|
-
| Capability |
|
|
37
|
+
| Capability | Description |
|
|
48
38
|
|---|---|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
| Skill
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
| Prefix-cache friendly | Section text depends only on enabled scenes + file contents,
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
68
|
-
|
|
39
|
+
| Scene memory | `.md` bodies in an enabled scene are **injected into the system prompt**, effective on the next request |
|
|
40
|
+
| Scene profile | Every scene freely combines **MCP tools / skills / subagents / memories**; opening a scene applies it, closing restores from the snapshot |
|
|
41
|
+
| Scene prompt | A scene can bind a prompt preset; switching scenes rewrites `~/.dsh/AGENTS.md` (auto-restores on exit) |
|
|
42
|
+
| Scene lock | Locking a scene freezes **all five domains read-only** (bound entries or not); a scene must be running to lock, and a locked scene can't be turned off — unlock first |
|
|
43
|
+
| Per-tool switches | **Individual tools** inside one MCP server can be disabled: invisible to the model, blocked at call time |
|
|
44
|
+
| Restart semantics | Restart only reconnects — it **never flips the enabled state** |
|
|
45
|
+
| Secret safety | Secrets masked by default; "Reveal" & export **require a token** — no `token` configured means no plaintext |
|
|
46
|
+
| Skill sources | Hooks up `~/.agents` / `~/.codex` / `~/.claude` & custom dirs; default sources must be read but skills can be deleted |
|
|
47
|
+
| Recycle bin | Personas / scenes / prompts / memories / skills all go to recycle bin on delete, restorable |
|
|
48
|
+
| AGENTS.md presets | Multiple global baselines, one-click apply, 5-generation backup |
|
|
49
|
+
| Archived sessions | Grouped by project, batch restore / delete, retention cleanup; rebuildable after workspace deletion |
|
|
50
|
+
| Transcript import/export | Take over Claude Code / Cursor / Codex / any text; export Markdown / JSONL |
|
|
51
|
+
| Import pairs with export | Skills / subagents / prompts / memories all export too: pick items → zip into a directory you choose (read-only on sources) |
|
|
52
|
+
| Subagents | One file per persona, with an **on/off toggle** deciding whether it is injected; run-and-discard, never enters History, inherits scene memories |
|
|
53
|
+
| Context visibility | The persona catalog and "currently usable MCP servers + your notes" enter the system prompt, so the model knows what is available |
|
|
54
|
+
| Prefix-cache friendly | Section text depends only on enabled scenes + file contents, byte-stable |
|
|
55
|
+
| Compatibility check | The **Host** tab shows host capabilities, per-action routing, and degradations at a glance |
|
|
56
|
+
| Model tools | **14** (`skill_mcp_manager_*` / `skill_manager_*` / `agentsmd_*` / `rule_manager_*` / `subagent_*`) |
|
|
57
|
+
| UI | Custom design system, **eight tabs**, bilingual, follows host language |
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
69
60
|
|
|
70
61
|
Prerequisites: DSH installed (`dsh web` runs), Node.js ≥ 18.
|
|
71
62
|
|
|
72
63
|
```sh
|
|
73
|
-
|
|
74
|
-
dsh plugin --profile web
|
|
75
|
-
|
|
76
|
-
# Uninstall
|
|
77
|
-
dsh plugin --profile web remove dsh-plugin-tool-management
|
|
64
|
+
dsh plugin --profile web add dsh-plugin-tool-management@latest # install / update
|
|
65
|
+
dsh plugin --profile web remove dsh-plugin-tool-management # uninstall
|
|
78
66
|
```
|
|
79
67
|
|
|
80
|
-
Hard-refresh the browser
|
|
68
|
+
Hard-refresh the browser — a **Tools** panel with eight tabs means it worked. Client changes hot-reload; host-side changes need `dsh web` restarted.
|
|
81
69
|
|
|
82
|
-
You can also
|
|
70
|
+
You can also ask the model:
|
|
83
71
|
|
|
84
72
|
```text
|
|
85
73
|
Install the dsh-plugin-tool-management plugin:
|
|
@@ -87,213 +75,121 @@ dsh plugin --profile web add dsh-plugin-tool-management@latest
|
|
|
87
75
|
Then remind me to hard-refresh the browser.
|
|
88
76
|
```
|
|
89
77
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
### Scenes and memories
|
|
93
|
-
|
|
94
|
-
> A scene is the grouping dimension, a memory (`.md`) is the content. A scene can carry a **profile**: MCP tool set / skill set / subagent bindings / memories, four freely combined sections.
|
|
95
|
-
> All data lives under `~/.dsh/tool-management/` (see [Where data lives](#where-data-lives)).
|
|
96
|
-
|
|
97
|
-
- **A scene is an explicit record**: `memories/<scene>/` holds its memories, and the scene itself carries a **description** and an order (in the `scenes` slice of `rules-index.json`). Scene names accept any Unicode (≤64 chars, no `/ \ < > : " | ? *`, must not start with a dot, **a single path segment**). `global` is the reserved always-on scene ("Global" in the UI) and `_shared/` is the legacy shared scene.
|
|
98
|
-
- **New scene**: "New scene" asks for a name and a one-line description; you can also just `mkdir` under `memories/` — a record is filled in on the next read. **An empty scene is valid**, so you can create scenes first and add memories later. **A new scene starts switched off.**
|
|
99
|
-
- **Every `.md` is one memory**: no frontmatter needed, the whole body is injected. Drop a file into the scene folder and it takes effect, or use "New memory" on the page — **file names can be non-ASCII** (e.g. `站会流程.md`). A memory whose scene does not exist is rejected outright (`scene not found`) instead of silently creating one.
|
|
100
|
-
- **Toggle a scene (single choice)**: besides the reserved `global` scene, **only one scene can be enabled at a time** — once one is on, the other switches are greyed out until you turn it off; turning everything off leaves just `global` and `_shared` injecting. Every `.md` inside the enabled scene is injected into the system prompt, effective on the **very next request** — no new session, no plugin reload.
|
|
101
|
-
- **A scene can bind one prompt preset**: pick a preset in the scene form (one preset per scene; it **defaults to the one currently in effect**). **Switching scenes rewrites `~/.dsh/AGENTS.md` directly** — the bound preset is written into the global baseline (multi-generation backup under `agents-md/__last-applied__/` first); **turning the scene off restores the baseline from before you entered it** (hand-written content comes back verbatim). Rebinding, or editing the body of the preset currently in effect, also syncs the file. The Prompts page marks that preset as **Active**, and **it cannot be deleted**. If the bound preset is deleted the card says "preset missing" instead of silently touching the file. "Entering a scene" (applying its profile) also enables it, so profile, memories and prompt take effect together.
|
|
102
|
-
- **Global memories**: memories of the reserved `global` scene are injected into **every** conversation (they ignore scene switches; the global group on the Memories page is tagged **"always injected"**), which suits universal preferences and conventions. Leaving the scene empty when creating a memory lands it there.
|
|
103
|
-
- **Import memories**: the page header's "Import memories" takes `.md` and `.zip` (multi-select, drag-and-drop). Inside a zip, a directory name is the scene (`工作/standup.md` → scene `工作`); **dropping a folder works the same way** (multi-level directories are kept as `A/B`); a bare `.md` lands in the scene picked in the dialog — **leaving it empty means the reserved "Global" scene**. `<scene>/<name>/SKILL.md` inside a zip is imported as a **bundle** (sibling files become attachments; an illegal name, empty content, a single file >8 MB or >16 MB in total is skipped and reported). Files are written verbatim, **same names are skipped and listed** (never overwritten), nothing is dropped silently — every discarded item is reported with a reason — and scenes referenced by an import are created automatically and listed in the result.
|
|
104
|
-
- **A memory is a Markdown file**: `<scene>/<name>.md` (flat) or `<scene>/<name>/SKILL.md` (bundle). Creating one asks for scene, name (= file name), description and body; frontmatter is entirely optional and derived automatically when missing.
|
|
105
|
-
- **Bundle attachments**: the bundle form lets you add attachments right in the dialog (multi-select, ≤8 MB each, ≤16 MB / 32 files per upload); they live in the memory folder and are **never injected into the prompt** (only the `SKILL.md` body is), and can be removed one by one while editing. The flat form is a single file, so it has nowhere to put attachments.
|
|
106
|
-
- **Toggle & recycle**: enable/disable each row (a disabled memory stays on disk, it is simply left out of the prompt), edit, move to trash; the header's "Trash" can **restore** or **permanently delete** (with a confirmation step). `enabled` and friends live in the sidecar index and are never written back to your files.
|
|
107
|
-
- **The injection budget is visible**: a budget bar (used / max bytes) sits under the header and turns red when over. Default cap 64 KiB; when one memory does not fit it is **skipped** while smaller ones behind it are still included, and the section tail carries a "not injected (over budget)" list — both the model and you can see what was left out.
|
|
108
|
-
- **`~/.dsh/AGENTS.md` is no longer written**: the old "always layer" is gone; the shared baseline now lives in `_shared/` and flows through the system-prompt section.
|
|
109
|
-
- **Scenes page layout**: scenes form a **card grid** (single column below 640px). Each card carries exactly four things: the name (plus the on-disk folder name, status tags and the switch), a **one-line description**, and its action buttons ("Enter this mode" appears only when a profile exists; on the right "Profile / Edit / Delete scene"). Descriptions are capped at **60 characters** (enforced in the field, clipped with an ellipsis on the card with the full text in the tooltip) because cards carry **no counters at all**: what is in effect is told only by the **Active mode** bar at the top of the page, which **appears only while a mode is actually active** (no bar = no mode).
|
|
110
|
-
- **Scene profile (four free-form sections)**: "Profile" opens an editor where **MCP tools** (two levels: check a server first; unchecked = the whole server off, checked with no tool picked = all its tools off), **skills** (only currently discovered entries are listed; checked = enabled), **subagent bindings** (check personas; nothing checked = no restriction) and **memories** are added/removed independently. The memory section lists **only the memories of the scene being edited** and is filterable; it **only affects injection** — global memories are always injected and another scene's choices would have no effect, so neither appears here. **A newly added section starts with nothing checked**: the memory section pre-checks only the **enabled** memories of that same scene, the other three give an empty set (an empty MCP / skill / memory section disables that domain, an empty subagent section means no restriction — the section footer spells this out), and "Select all" covers the whole scene. Every section body has a filter box, memory descriptions are clipped at 80 characters with the full text in the tooltip, and the dialog keeps a fixed height so adding or removing sections never makes it jump.
|
|
111
|
-
- **Scene modes**: a scene with a tool or skill section gets "Enter this mode" — **entering takes a snapshot of the current toggles, persists it first, applies the selection and narrows memory injection to that scene**; exiting restores the snapshot **verbatim** (whole-server disable keys written during the mode disappear with it). Manual changes made while a mode is running are never silently written back — "Save to scene" does that. Any failed step rolls back and is reported honestly (an incomplete rollback goes into the error text instead of claiming success).
|
|
112
|
-
|
|
113
|
-
### Subagents (personas)
|
|
114
|
-
|
|
115
|
-
- **One file per persona**: `~/.dsh/tool-management/agents/<persona>.md`; every frontmatter key is optional — `description` (when to call it, one sentence is enough), `provider` + `model` (the model route, **a pair**: switching providers requires both; a bare `model` resolves against the main session's provider), `tools` allowlist, `toolsDeny` denylist. The body is the persona prompt.
|
|
116
|
-
- **Advanced options**: model and tool limits live in an "Advanced options" fold-out (auto-expanded for personas already using them). The model is a **dropdown** of `provider · model` pairs from the host LLM catalogue, with a "Custom" entry to type one it does not list; the tool allow/deny lists are **pickers** whose candidates are the **union of tool names across all agent presets**, grouped by preset — a persona can be reused under any preset, and listing only this session's tools would make the child fail to start after a preset switch (the official `toolFilter` rejects unknown names outright).
|
|
117
|
-
- **Import**: the header's "Import" takes `.md` and `.zip` (a `.md` at any depth inside a zip is imported by file name; **same names are skipped and listed**).
|
|
118
|
-
- **Running**: the model lists them with `subagent_list` and calls `subagent_run{agent, task}`; the child runs **with the persona**, inherits the memories of currently enabled scenes, returns only its final output (≤16 KiB) to the main model, and is discarded without entering History. A scene profile can bind "which personas are available in this scene" (a call outside the binding reports "persona unavailable"); running asks for confirmation by default (it spends real tokens), which `requireConfirmForModelSubagentRun: false` turns off.
|
|
119
|
-
- **Governance boundary**: all of the above covers only the `subagent_run` channel — DSH's own `subagent` / `subagent_fork` are host capabilities with no confirm gate and no notion of these personas, so they honour neither in any mode (see [FAQ](#faq)). Personas never enter a recycle bin (deleted is deleted), and v1 has no model tool that writes persona files.
|
|
78
|
+
The model can manage everything above via 14 tools (see highlights); scripts use `POST /dsh-plugin-tool-management/api` (`{op, args}` protocol).
|
|
120
79
|
|
|
121
|
-
|
|
80
|
+
---
|
|
122
81
|
|
|
123
|
-
|
|
124
|
-
- **See the state**: every card shows live status, loader phase and registered tool count; a summary bar sits on top, and fatal issues such as duplicate loader ids are flagged right on the page.
|
|
125
|
-
- **Turn off just one tool**: the "Details" dialog lists every tool — disable the ones the model keeps misusing; the schema disappears from the model's view and calls are denied, ready to re-enable anytime.
|
|
126
|
-
- **Inspect secrets safely**: secret-looking values render as `••••••` by default; click "Reveal" only when you need them.
|
|
127
|
-
- **Move and back up**: editing can rename a server or migrate it between project/global level (with automatic rollback on failure); JSON export/import covers full backups and machine moves.
|
|
82
|
+
## Features
|
|
128
83
|
|
|
129
|
-
###
|
|
84
|
+
### Scenes & memories
|
|
130
85
|
|
|
131
|
-
- **
|
|
132
|
-
- **
|
|
133
|
-
- **
|
|
134
|
-
- **
|
|
135
|
-
- **
|
|
136
|
-
- **
|
|
137
|
-
- **
|
|
86
|
+
- **A scene = a group, a memory = a `.md` file**. `memories/<scene>/<name>.md`, the whole body is injected, file names can be non-ASCII.
|
|
87
|
+
- **Single-choice toggle**: only one scene at a time (others greyed out); turning all off = only `global` and `_shared` inject. New scenes start off.
|
|
88
|
+
- **Scene-bound prompt**: switching scenes rewrites `~/.dsh/AGENTS.md` (5-gen backup, auto-restore on exit).
|
|
89
|
+
- **Scene profile**: every scene combines MCP tools / skills / subagents / memories (any mix); opening a scene applies and narrows injection, closing restores verbatim (the toggle is the only entry).
|
|
90
|
+
- **Import**: `.md` / `.zip` (dir name = scene, bundles carry attachments), same names skipped never overwritten, over-limit items reported.
|
|
91
|
+
- **Export**: pick memories and zip them, keeping the `scene/name` layout; bundle memories bring their attachments along. Sources are read-only.
|
|
92
|
+
- **Injection budget**: default 64 KiB, oversized memories skipped with a list. Deletes go to recycle bin.
|
|
93
|
+
- **Scene lock**: once locked, MCP / skills / subagents / memories / prompts are read-only — UI disabled plus a server-side guard; a scene must be running to lock, and a locked scene can't be closed until unlocked.
|
|
94
|
+
- **Deleting a scene deletes its memories too**: the scene record, profile and every memory go into one recycle-bin entry, restored as a whole; a running scene refuses deletion. Scene names are renameable (dir and profile follow, memory bodies untouched).
|
|
138
95
|
|
|
139
|
-
###
|
|
96
|
+
### Subagents
|
|
140
97
|
|
|
141
|
-
- **
|
|
142
|
-
- **
|
|
98
|
+
- **One file per persona**: `agents/<persona>.md`, frontmatter entirely optional.
|
|
99
|
+
- **Tool limits per Agent preset**: each preset gets its own allow/deny list (mutually exclusive), effective at runtime by the current preset — fixes the old "union of all presets" list that broke subagents after a preset switch.
|
|
100
|
+
- **Run and discard**: `subagent_run` runs with the persona, returns only the result, never enters History, inherits scene memories. Scenes can bind which personas are available.
|
|
101
|
+
- **On/off toggles**: a disabled persona is not injected and invisible to the model (file untouched); newly created / imported / restored personas start enabled. Starting a scene auto-enables the personas its profile binds; exit restores precisely from the snapshot.
|
|
102
|
+
- **Persona catalog enters the system prompt**: names + descriptions only, so the model knows what it can delegate to; personas are renameable, scene bindings follow.
|
|
143
103
|
|
|
144
|
-
###
|
|
145
|
-
|
|
146
|
-
- **Grouped by project**: archived sessions are grouped by workspace; search by title / session ID / project path; sessions whose workspace folder no longer exists are flagged with ⚠. When a **workspace registration is deleted** (DSH deletes neither the folder nor the sessions), the group is rebuilt from session directories and marked "Workspace removed" / "Unregistered directory"; while the folder still exists one click re-registers it (a registration only — no file or session is touched), and restoring a session also attaches it back to its workspace (previously it simply fell into "Ungrouped").
|
|
147
|
-
- **Batch operations**: "Select all" then batch-restore or permanently delete; restored sessions return to the workspace list, and deletion cascades to their subagent sessions.
|
|
148
|
-
- **Retention**: pick the cleanup period from the dropdown (0 = keep forever); the expiry baseline is the later of the archive time and the last retention change, so changing the retention resets the countdown.
|
|
149
|
-
- **Import conversations**: take over sessions from other tools — Claude Code / Cursor JSONL, Codex Markdown, and arbitrary text — and keep chatting right after import.
|
|
150
|
-
- **Export conversations**: pick a session scope (all / archived only / by workspace); each session becomes a Markdown or JSONL file; the export directory defaults to the desktop, and the adjacent "Select" button opens a directory tree to browse and fill in the absolute path.
|
|
104
|
+
### MCP servers
|
|
151
105
|
|
|
152
|
-
|
|
106
|
+
- **CRUD + immediate effect**: writes to `cordis.patch.yml`, HMR picks it up.
|
|
107
|
+
- **Per-tool switches**: disable individual tools (invisible to the model, blocked at call), whole-server batch.
|
|
108
|
+
- **Secret masking**: defaults to `••••••`, "Reveal" needs a token.
|
|
109
|
+
- **Migrate & back up**: cross-project/global migration rolls back on failure; JSON export/import.
|
|
110
|
+
- **Status & notes enter the system prompt**: only currently usable servers are listed, and your notes travel along as decision hints; levels are "global / app", new servers default to global.
|
|
153
111
|
|
|
154
|
-
|
|
155
|
-
- Archiving goes through the plugin's own facade: **a native entry when one exists, a checked adapter otherwise, and a refusal when neither works**. The decision is based on "are plugin and host the same physical module + does this capability exist on the live host object", **not on comparing official source text** — an upstream refactor can no longer kill the feature wholesale; the worst case is that one action is disabled with a reason, listed on the **Host** tab and in the refusal message.
|
|
156
|
-
- The adapter touches workspace internals (including methods the official API declares private) and, when the host lacks its own delete barrier, reversibly wraps the projection cache's `put` / `write`. **So "no longer replaces services / no longer competes for registration" does not mean "zero intrusion"**, nor "decoupled".
|
|
157
|
-
- Official durable events supply archive timestamps. Existing archives without a timestamp receive a fresh retention window on first observation instead of expiring from their older creation date.
|
|
158
|
-
- Legacy independent caches are retained untouched; official summaries may need rebuilding on demand. Explicit legacy `/workspace` or `/projcache` entries in user patches require review; the plugin does not rewrite those patches.
|
|
159
|
-
- Archive/restore/batch delete and late-cache-write protection were exercised with official services and isolated JSON storage. Actual co-installation with `@michengai/dsh-archive-manager` has not been verified; compatibility with arbitrary versions is not guaranteed.
|
|
112
|
+
### Skills
|
|
160
113
|
|
|
161
|
-
|
|
114
|
+
- **Sources at a glance**: project / DSH / Agents / Codex / Claude / custom dirs, grouped by source.
|
|
115
|
+
- **Opposite permissions**: default sources must be read but skills can be deleted; external dirs can be disabled/removed but skills are read-only.
|
|
116
|
+
- **Remove ≠ disable**: remove = directory not scanned at all (files untouched, restorable); disable = still listed but not callable.
|
|
117
|
+
- **Same-name picker / custom dirs / ZIP import & export / recycle bin**.
|
|
162
118
|
|
|
163
|
-
|
|
119
|
+
### Prompt presets
|
|
164
120
|
|
|
165
|
-
-
|
|
166
|
-
- **
|
|
121
|
+
- Multiple `~/.dsh/AGENTS.md` baselines, one-click apply (the host re-reads that file every turn, so it takes effect on the next turn), 5-gen backup.
|
|
122
|
+
- **Description**: one line saying what a preset is for — shown in this panel only. It lives in a sibling `meta.json`, never in AGENTS.md, so it is never injected into prompts.
|
|
123
|
+
- Create with body inline, edit can change id (= dir rename, scene bindings follow). Active preset can't be deleted; deletes go to recycle bin.
|
|
167
124
|
|
|
168
|
-
|
|
169
|
-
node scripts/doctor.mjs # read-only: same module instances? host capability overview
|
|
170
|
-
node scripts/host-deps.mjs # report drift (dry run by default)
|
|
171
|
-
node scripts/host-deps.mjs --fix # junction drifted packages into the host installation (originals backed up to .host-deps-backup/)
|
|
172
|
-
node scripts/host-deps.mjs --restore # put the originals back
|
|
173
|
-
```
|
|
125
|
+
### Archived sessions
|
|
174
126
|
|
|
175
|
-
|
|
127
|
+
- Grouped by project, search, batch restore / delete, retention auto-cleanup.
|
|
128
|
+
- Workspace registration deleted → group rebuilt from session dirs, one-click re-register.
|
|
129
|
+
- Import Claude Code / Cursor / Codex / any text; export Markdown / JSONL.
|
|
176
130
|
|
|
177
|
-
|
|
131
|
+
### Host compatibility
|
|
178
132
|
|
|
179
|
-
|
|
133
|
+
The plugin uses the host's own `@deepseek-ai/*` libraries at runtime — they must be the same physical modules, or every "adapt to host" decision degrades into guesswork.
|
|
180
134
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
| `skill_manager_list / set_enabled / create` | Let the model query and operate skills (creating asks for your consent) |
|
|
185
|
-
| `agentsmd_list / agentsmd_apply` | Let the model list the AGENTS.md preset library and switch the active preset (writes `~/.dsh/AGENTS.md`, effective for new sessions); **no create or delete**, so the model cannot wipe your presets |
|
|
186
|
-
| `rule_manager_list / read / write` | Let the model query and write scene memories (writes ask for your consent; can be disabled in settings) |
|
|
187
|
-
| `subagent_list / subagent_run` | Let the model list personas and run a one-shot persona subagent (result only, discarded afterwards; running asks for your consent by default, can be disabled in settings) |
|
|
188
|
-
| `POST /dsh-plugin-tool-management/api` | HTTP API for scripts (`{op, args}` protocol) |
|
|
135
|
+
- **Host tab**: host version, usable capability count, per-action routing (native/adapter/unavailable), degradations & reasons. Read-only.
|
|
136
|
+
- **Command line**: `node scripts/doctor.mjs` (check), `node scripts/host-deps.mjs --fix` (align deps).
|
|
137
|
+
- Under `minimal` preset, scene memory / AGENTS.md / skill directory don't take effect (by design); the Host tab marks this per column.
|
|
189
138
|
|
|
190
|
-
|
|
191
|
-
> `/scene-memory`): they could only print a text snapshot, could not operate anything, and drifted from
|
|
192
|
-
> the panel state. Every one of them has an equivalent entry in the settings panel.
|
|
139
|
+
---
|
|
193
140
|
|
|
194
141
|
## Where data lives
|
|
195
142
|
|
|
196
143
|
| Content | Location |
|
|
197
144
|
|---|---|
|
|
198
|
-
| MCP
|
|
199
|
-
|
|
|
200
|
-
|
|
|
201
|
-
|
|
|
202
|
-
|
|
|
203
|
-
|
|
|
204
|
-
|
|
|
205
|
-
|
|
|
206
|
-
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
| Memory recycle bin | `~/.dsh/tool-management/rules-trash/<trashId>/` (deleted memories land here and can be restored) |
|
|
210
|
-
| Runtime log | `~/.dsh/dsh-plugin-tool-management.log` (rolling) |
|
|
211
|
-
|
|
212
|
-
**No user data is ever stored inside the plugin's installation directory** — under an npm install, `dsh plugin update` replaces that directory wholesale.
|
|
145
|
+
| MCP definitions | `cordis.patch.yml` (auto `.bak` before rewrite) |
|
|
146
|
+
| Skill policy / custom dirs | `~/.dsh/tool-management/state.json` |
|
|
147
|
+
| Skills / memories / personas / presets | `~/.dsh/tool-management/{skills,memories,agents,agents-md}/` |
|
|
148
|
+
| Subagent toggles | `~/.dsh/tool-management/agents-index.json` |
|
|
149
|
+
| Recycle bin | `~/.dsh/tool-management/trash/` |
|
|
150
|
+
| Archive ledger / retention | `~/.dsh/tool-management/history-*.json` |
|
|
151
|
+
| Memory index / scenes / profiles | `~/.dsh/tool-management/rules-index.json` |
|
|
152
|
+
| Page settings | `~/.dsh/dsh-plugin-tool-management-settings.json` |
|
|
153
|
+
| Runtime log | `~/.dsh/dsh-plugin-tool-management.log` |
|
|
154
|
+
|
|
155
|
+
**No user data is stored inside the plugin's install directory** (`dsh plugin update` replaces it wholesale).
|
|
213
156
|
|
|
214
157
|
## Configuration & security
|
|
215
158
|
|
|
216
|
-
Optional fields on the plugin loader row (`dsh plugin add` inserts it automatically):
|
|
217
|
-
|
|
218
159
|
| Field | Description |
|
|
219
160
|
|---|---|
|
|
220
|
-
| `token` |
|
|
221
|
-
| `maxBodyBytes` | Request body cap, default 88 MiB
|
|
222
|
-
|
|
223
|
-
How authentication works: the plugin route is **not** behind a host-wide auth gate, so it calls the host's `connection.requestRejection(req)` itself — first the Host / Origin fence (Host must be a loopback or deployment-derived LAN IP literal, the one header DNS rebinding cannot forge), then browser-session cookie authentication. If that host service is absent, a **local check** takes over that only requires "loopback Host + not a cross-site fetch + Origin matching Host" and **does not include cookie authentication** (weaker than the host fence — configure a token in such an environment). Therefore:
|
|
161
|
+
| `token` | Access token. When set, **all writes + plaintext secrets** require `x-dsh-token`; **unset = plaintext endpoints closed**. Also the escape hatch for curl / LAN. |
|
|
162
|
+
| `maxBodyBytes` | Request body cap, default 88 MiB. |
|
|
224
163
|
|
|
225
|
-
- **
|
|
226
|
-
- **curl / scripts**: send
|
|
227
|
-
-
|
|
228
|
-
- If you forward the port to a LAN or the public internet, a token remains the key defense against strangers injecting MCP commands (equivalent to remote code execution — `command` / `args` are spawned verbatim) and reading plaintext secrets, so **configure one**.
|
|
229
|
-
- The `x-dsh-plugin` custom header is only a contact-prevention token, not a credential.
|
|
164
|
+
- **Browser**: reads/writes via cookie, no token needed; but **plaintext secrets** (Reveal / export) need a token.
|
|
165
|
+
- **curl / scripts**: send `x-dsh-token`, or carry the browser cookie.
|
|
166
|
+
- **Port forwarded to public**: configure a token — prevents strangers injecting MCP commands (≈ remote code execution) and stealing secrets.
|
|
230
167
|
|
|
231
168
|
## FAQ
|
|
232
169
|
|
|
233
170
|
| Symptom | Fix |
|
|
234
171
|
|---|---|
|
|
235
|
-
| Pages missing
|
|
236
|
-
| Duplicate MCP tabs
|
|
237
|
-
| Broken config, DSH won't boot | Restore the newest
|
|
238
|
-
|
|
|
239
|
-
|
|
|
240
|
-
|
|
|
241
|
-
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
| The scene binds only persona A, so why did an unbound subagent still run? | **There are two subagent channels.** This plugin's `subagent_run` goes through its confirm gate and the scene persona binding; DSH's own `subagent` / `subagent_fork` are host capabilities with **no confirm gate and no notion of this plugin's personas**, so they honour neither in any mode (verified live: in one message the official `subagent` returned with no approval card while the following `subagent_run` did prompt). This plugin's governance covers `subagent_run` only. |
|
|
172
|
+
| Pages missing after install | Hard refresh; restart DSH if that fails. |
|
|
173
|
+
| Duplicate MCP tabs | Remove the stale loader row from `cordis.patch.yml`, restart. |
|
|
174
|
+
| Broken config, DSH won't boot | Restore the newest `.bak-<timestamp>`. |
|
|
175
|
+
| Action stopped after DSH upgrade | Settings → Tools → **Host** for the reason; `doctor.mjs` → `host-deps.mjs --fix`. |
|
|
176
|
+
| Still asked to confirm in `approval=never`? | No card appears — straight through with a log line; switch back to "workspace write" to get asked again. |
|
|
177
|
+
| `subagent_run` reports spawn unavailable | Host has no spawn provider; mount `@deepseek-ai/dsh-subagent-spawn-in-process` and restart. |
|
|
178
|
+
| Scene binds persona A, but official `subagent` ran something else | Two channels: this plugin only governs `subagent_run`; official `subagent` / `subagent_fork` have no gate and don't know about personas. |
|
|
179
|
+
|
|
180
|
+
---
|
|
245
181
|
|
|
246
182
|
## Development
|
|
247
183
|
|
|
248
184
|
```bash
|
|
249
185
|
npm install
|
|
250
|
-
npm run build #
|
|
251
|
-
npm
|
|
252
|
-
npm run
|
|
253
|
-
npm run
|
|
254
|
-
npm run check:host # host dependency check (read-only, see "Host compatibility")
|
|
255
|
-
npm run host-deps # point the plugin's shared deps at the host installation
|
|
256
|
-
npm run doctor # print module identity + host capability probe results
|
|
257
|
-
npm test # build + i18n check + semantic-contract tests (node --test test/*.test.mjs, 13 groups)
|
|
186
|
+
npm run build # tsc + sync client
|
|
187
|
+
npm test # build + i18n + semantic-contract tests
|
|
188
|
+
npm run check:i18n # dictionary self-check
|
|
189
|
+
npm run doctor # host compatibility check
|
|
258
190
|
```
|
|
259
191
|
|
|
260
|
-
|
|
261
|
-
> The host loads `lib/` at startup, so **changes need `dsh web` restarted** (patch hot-reload does not re-import the plugin module).
|
|
262
|
-
|
|
263
|
-
### How this project verifies things
|
|
264
|
-
|
|
265
|
-
Verification means **actually exercising the real behaviour**, not asserting what the code currently does — the latter just copies the implementation and passes by construction.
|
|
266
|
-
**Wording and layout are not asserted line by line** (maintainer decision, 2026-09-14: those assertions chase a moving target — every style change would demand an assertion change, and the real look is confirmed by a human on the page).
|
|
267
|
-
|
|
268
|
-
What remains is 13 groups of **semantic-contract** tests (`npm test`, run against the built `lib/`):
|
|
269
|
-
|
|
270
|
-
| Test | Contract it asserts |
|
|
271
|
-
|---|---|
|
|
272
|
-
| `archive.test.mjs` | Scene engine state machine: section existence is independent of empty sets, selection → disable complement, deep-copied snapshots, failure rolls back and is reported honestly |
|
|
273
|
-
| `import.test.mjs` | Import expansion and landing plans: path traversal rejected, ZIP recognised by magic bytes not extension, over-limit and illegal entries each reported with a reason |
|
|
274
|
-
| `approval-policy.test.mjs` | The `approval=never` detection chain, driven by a real cordis context and a real `ApprovalService`; a missing service or a throw never means "allow" |
|
|
275
|
-
| `subagent-scene.test.mjs` | Scene persona bindings: a call outside the binding must be rejected **before** the subagent runs |
|
|
276
|
-
| `subagent-persona.test.mjs` | Persona frontmatter round-trip: `provider` / `model` / `toolsDeny` survive a UI save; creating a persona with no directory present |
|
|
277
|
-
| `hub-layout.test.mjs` | Unified data directory: legacy layouts move without overwriting, the reserved `global` scene always exists and cannot be deleted, a memory must belong to an existing scene, and the profile memory section only affects projection |
|
|
278
|
-
| `skills-state.test.mjs` | State-file read resilience: missing keys self-heal, type errors stay fail-closed, leftover policy bits for default sources are dropped |
|
|
279
|
-
| `skills-delete.test.mjs` | Default-source skills can be deleted and restored **byte-for-byte** from the recycle bin; read-only sources stay read-only |
|
|
280
|
-
| `skills-source-remove.test.mjs` | "Remove a source": it is no longer read, drops out of the same-name priority and is invisible to the model, while not a byte on disk changes and it can be restored; default sources can neither be removed nor disabled |
|
|
281
|
-
| `client-exports.test.mjs` | Client export contract: evaluating the factory alone — without running `apply` — must already expose `dict` / `pages`; exports written inside the `apply` method body are rejected |
|
|
282
|
-
| `client-render.test.mjs` | Assembly and rendering: a fake ctx drives the whole `apply`, `settings.section` is registered and the entire component tree renders without throwing (this is the one that caught a real blank screen), and again once data has arrived; the scenes page and profile dialog pin structure rather than wording; the Host tab colours only for real blockers or real degradation, and its summary line must contain no Chinese characters under the English dictionary |
|
|
283
|
-
| `compat-probe.test.mjs` | Host capability probing: host objects are built from the real official class prototypes, and a renamed member, a changed return shape or a wholly absent service must degrade into a **named** finding instead of a throw; the probe itself is read-only |
|
|
284
|
-
| `compat-fallback.test.mjs` | The capability gate really stops writes: with the serialized-write capability missing, archiving is refused and not a single host write method is called; the cache is wrapped only when the host lacks its own delete barrier, and restored on dispose |
|
|
285
|
-
|
|
286
|
-
Also `npm run check:i18n` (dictionary key sets, duplicates, placeholder alignment and literal-reference completeness — currently 722 keys per language, 454 referenced literals) and `node scripts/i18n-debt.mjs` (how much hard-coded Chinese is left — **214 lines today**: 15 on the prompts page, the rest spread across components and shared shells the script does not attribute to a page; the sessions page is at zero).
|
|
287
|
-
|
|
288
|
-
These tests assert contracts, not implementation copies; **real-behaviour acceptance still happens in the browser / host and these tests do not replace it**.
|
|
289
|
-
|
|
290
|
-
### Layout
|
|
291
|
-
|
|
292
|
-
Host half `src/index.ts` (object-form Cordis plugin, `lib/index.js` is the shipped artifact); host capability probe `src/compat/probe.ts` (the single place that decides what the plugin may do to the host, read-only); HTTP fence `src/http-fence.ts`; data-directory constants and migration `src/hub.ts`; skill core `src/skills/core.js` (pure Node); AGENTS.md presets `src/agents-md/service.ts`; archived session management `lib/history/` (`workspace.js` facade, `bridge.js` compatibility layer, `projcache.js`, `tombstone.js`); transcript import parsing `src/imports/parsers.js`; scene-memory store `src/rules/` (`service.ts` discovery, CRUD, index, check-up and two-phase section render; `provider.ts` registers the per-agent `systemPrompt` section — the module path and `rules-*` op names stay as internal protocol, while the user-visible page and folder are "Scene memory" / `memories/`); browser half `src/client.js` (ModuleLoader CJS bundle, `dsm-*` design system, talks to the host through the same-origin API); dev scripts `scripts/host-deps.mjs` (dependency alignment) and `scripts/doctor.mjs` (compatibility check).
|
|
293
|
-
|
|
294
|
-
The only runtime dependency is `fflate` (ZIP extraction); every `@deepseek-ai/*` package comes from the host (see "Host compatibility" above).
|
|
295
|
-
|
|
296
|
-
Publish: `npm publish` (`prepublishOnly` builds automatically; bump with `npm version <minor|patch>`).
|
|
192
|
+
`lib/` is not tracked — run `npm run build` after cloning. Changes need `dsh web` restarted. Runtime dep is only `fflate`; `@deepseek-ai/*` all come from the host.
|
|
297
193
|
|
|
298
194
|
## License
|
|
299
195
|
|
|
Binary file
|
|
Binary file
|
package/docs/images/2MCP.png
CHANGED
|
Binary file
|
package/docs/images/2MCP_en.png
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|