dsh-custom-mode 2.1.0 → 2.2.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/README.i18n.yaml +2 -2
- package/README.md +34 -394
- package/README.zh.md +34 -290
- package/client.js +14 -14
- package/composition.mjs +6 -6
- package/defaults.mjs +59 -0
- package/index.mjs +14 -4
- package/locales.mjs +8 -8
- package/package.json +13 -24
package/README.i18n.yaml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# 双语配对一致性记录:两侧在「上次确认一致」时的 git blob 哈希。
|
|
2
2
|
# 两份文档权威相同——改完任意一侧,请把另一侧也改掉,然后重新记录:
|
|
3
3
|
# node tools/verify-translation-pairing.mjs --write
|
|
4
|
-
README.md:
|
|
5
|
-
README.zh.md:
|
|
4
|
+
README.md: 3cd8af1d44fc5c7270a4cb7d4ff7eadb37f9e534
|
|
5
|
+
README.zh.md: 8a2b8340cc30daab299f0255f88186eb8458ee4b
|
package/README.md
CHANGED
|
@@ -2,426 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文](README.zh.md)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
the settings page, and keep several assistants side by side (multi-mode / multi-persona, coding, chat or
|
|
7
|
-
role-play). · **中文**:DeepSeek Harness(dsh)自定义模式插件 —— 在设置页编辑系统提示词、选择基础模式、逐行
|
|
8
|
-
开关插件,可并存多个助手(多模式 / 多角色扮演 RP)。
|
|
5
|
+
Edit a DeepSeek Harness (`dsh`) mode's system prompt, base mode, and plugin switches. Keep more than one assistant. Standard, PTC, Minimal, and Creator stay in the menu.
|
|
9
6
|
|
|
10
|
-
](https://github.com/BOWLUNA/dsh-custom-mode/stargazers) [](https://www.npmjs.com/package/dsh-custom-mode) [](https://github.com/BOWLUNA/dsh-custom-mode/actions/workflows/test.yml) [](LICENSE) [](https://github.com/BOWLUNA/dsh-custom-mode#readme)
|
|
13
|
-
|
|
14
|
-
[](https://b23.tv/qJ4Ev0W) [](https://v.douyin.com/VWh0M03Fa4Y/) [](https://xhslink.cn/o/A7QtXmePBBF) [](https://discord.gg/pz97SfAfSy) [](https://github.com/BOWLUNA/dsh-custom-mode/discussions)
|
|
15
|
-
|
|
16
|
-
A custom mode for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh). Its
|
|
17
|
-
system prompt is a plain file you can edit on the Web settings page, and an edit takes effect on the
|
|
18
|
-
**next model step** — no restart, no new session.
|
|
19
|
-
|
|
20
|
-
In one line: **a settings page for dsh agent modes** — choose a mode's base composition, toggle the plugin
|
|
21
|
-
rows it mounts, and edit its system prompt, which the agent loop re-reads before every model step. Several
|
|
22
|
-
modes ("assistants") can live side by side, each with its own prompt.
|
|
23
|
-
|
|
24
|
-
Also searched for as: custom mode · custom prompt · system-prompt editor · multi-mode / several assistants ·
|
|
25
|
-
multi-agent · roleplay (RP) / chat personas.
|
|
26
|
-
|
|
27
|
-
**Unit tests cover three lines. The render gate runs only on `0.2.0-rc.2`.** npm's `latest` and `next` have both pointed at `0.2.0-rc.2` since 2026-09-29:
|
|
28
|
-
|
|
29
|
-
| dsh | role | status |
|
|
30
|
-
| --- | --- | --- |
|
|
31
|
-
| `0.2.0-rc.2` | **newest line** — npm's `latest` *and* `next`, and the line the official desktop app ships (it is version-locked to dsh) | ✅ CI (ubuntu node 20/24 + **windows**) + a real instance: install, composition and the seeded preset verified on this line (the full render gate runs here) |
|
|
32
|
-
| `0.2.1-alpha.1` | preview line — npm `alpha`. Covered by unit tests; the render gate does not run here | ✅ CI |
|
|
33
|
-
| `0.1.7-rc.2` | previous stable — still inside the declared range, and what most existing installs run | ✅ CI. On this line the page falls back where the shell does not provide atoms; the render gate does not run here |
|
|
34
|
-
|
|
35
|
-
Older builds (`0.1.5-rc.3`, `0.1.6-alpha.*`) use the same mechanisms and remain inside the declared peer
|
|
36
|
-
range, but they no longer get a CI leg of their own.
|
|
37
|
-
|
|
38
|
-
The four official modes (`standard` / `ptc` / `minimal` / `cordis`) are untouched.
|
|
39
|
-
|
|
40
|
-
<p align="center">
|
|
41
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/01-mode-switch.png" width="360" alt="Base mode and plugin switches">
|
|
42
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/02-plugin-switches.png" width="360" alt="Plugin switches"><br>
|
|
43
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/03-system-prompt.png" width="360" alt="System prompt">
|
|
44
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/04-preset-picker.png" width="360" alt="Mode picker">
|
|
45
|
-
</p>
|
|
46
|
-
|
|
47
|
-
<p align="center">
|
|
48
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/05-assistant-manager.png" width="360" alt="Assistants">
|
|
49
|
-
</p>
|
|
50
|
-
|
|
51
|
-
The four views above are one 2×2 set. The assistant manager sits on its own, centered. Every file is English and exactly 800×800, shot on a throwaway `DSH_HOME` with no sessions.
|
|
7
|
+

|
|
52
8
|
|
|
53
9
|
## Install
|
|
54
10
|
|
|
55
|
-
|
|
56
|
-
activation:
|
|
11
|
+
Pin the version. A bare name can install an older build during pnpm's release cooldown. Details: [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md).
|
|
57
12
|
|
|
58
13
|
```sh
|
|
59
|
-
dsh plugin --profile web add dsh-custom-mode@2.
|
|
60
|
-
# A bare `add dsh-custom-mode` is subject to pnpm's release cooldown (`minimumReleaseAge`, 1 day by
|
|
61
|
-
# default): for hours after a release it can silently install an OLDER version — measured: a bare
|
|
62
|
-
# install 38 minutes after 1.3.0 shipped landed on 1.0.3. Check what you got with `npm ls
|
|
63
|
-
# dsh-custom-mode` inside the profile, or pin the version as above.
|
|
14
|
+
dsh plugin --profile web add dsh-custom-mode@2.2.0
|
|
64
15
|
```
|
|
65
16
|
|
|
66
|
-
Restart
|
|
67
|
-
`$DSH_HOME/.agent-presets/custom/`; anything already there is left alone, so a `prompt.md` you wrote
|
|
68
|
-
yourself is never overwritten.
|
|
69
|
-
|
|
70
|
-
**Platforms**: the suite runs on every push under Ubuntu (Node 20 and 24) **and Windows (Node 24)** — the
|
|
71
|
-
Windows job exists because that platform has its own failure modes (MSYS paths in `install.sh`, `rename`
|
|
72
|
-
locking under concurrent saves, platform expressions evaluating the other way). Both shell scripts work in
|
|
73
|
-
any POSIX shell, Git Bash included.
|
|
74
|
-
|
|
75
|
-
### Installing from the interface (no terminal)
|
|
76
|
-
|
|
77
|
-
From dsh `0.1.6-alpha.2` there is a Plugins page: **sidebar → Plugins → Add plugin**. It takes three
|
|
78
|
-
kinds of input, and all three work here:
|
|
17
|
+
Restart the process that serves the profile. The version on the settings page is the one that is running.
|
|
79
18
|
|
|
80
|
-
|
|
81
|
-
| --- | --- |
|
|
82
|
-
| **Package name** | `dsh-custom-mode` |
|
|
83
|
-
| **GitHub repository URL** | `https://github.com/BOWLUNA/dsh-custom-mode` (the repository root) |
|
|
84
|
-
| **Local plugin directory** | `<your clone>` — the repository root, which *is* the package |
|
|
85
|
-
|
|
86
|
-
There is also an **in-app market** for browsing the whole ecosystem: install `dshmarket`
|
|
87
|
-
(`dsh plugin --profile web add dshmarket`), open **Settings → Plugin Market** and search
|
|
88
|
-
`dsh-custom-mode` — its cards read the `engines.dsh` range this plugin declares, and the curated shots
|
|
89
|
-
listed in the repository's `screenshots.json` (five images; they are the same `docs/images/*.png`
|
|
90
|
-
files the README shows, so each picture exists once).
|
|
91
|
-
|
|
92
|
-
All three work because the repository's **root `package.json` is the published package**: `dsh.bundle`,
|
|
93
|
-
`main` and `exports["./client"]` are declared there, so an npm install and a GitHub-URL install fetch
|
|
94
|
-
the same files. Before 1.10.0 this repository carried two manifests — a `private: true` wrapper at the
|
|
95
|
-
root plus `editor/package.json` — and that is what made third-party catalogues render the plugin as
|
|
96
|
-
`dsh-custom-mode#editor` and what made dshfind-derived cards read the wrapper's `private: true` and
|
|
97
|
-
report "not published to npm". One manifest at the root, and `test/manifests.test.mjs` keeps it that way.
|
|
98
|
-
|
|
99
|
-
### On the desktop app
|
|
19
|
+
Desktop app: install from the in-app Plugins page. The CLI cannot modify `profiles/desktop`.
|
|
100
20
|
|
|
101
|
-
|
|
102
|
-
`@deepseek-ai/dsh` always carry the same exact version — and it is **the complete Web application in an
|
|
103
|
-
Electron shell**, so this plugin's page renders there unchanged. One install path, and it is the one above:
|
|
21
|
+
On Windows, `install.sh` is bash and it needs a `dsh` executable on `PATH`. Otherwise use the `dsh` shipped with DeepSeek Harness, or `node node_modules/@deepseek-ai/dsh/lib/bin.js`.
|
|
104
22
|
|
|
105
|
-
|
|
106
|
-
The app runs the shared plugin manager with its own bundled pnpm.
|
|
107
|
-
- **Do not try to use a standalone CLI for it — dsh itself refuses** (measured on 0.1.7-rc.2, and again on
|
|
108
|
-
0.2.0-rc.2):
|
|
109
|
-
```
|
|
110
|
-
$ dsh plugin --profile desktop add .
|
|
111
|
-
error: profile "desktop" is managed exclusively by the Electron application
|
|
112
|
-
```
|
|
113
|
-
The desktop owns `$DSH_HOME/profiles/desktop`: package operations there hold a profile transaction lock
|
|
114
|
-
and startup recovery renames `cordis.patch.yml`. `install.sh` therefore **refuses** `--profile desktop`
|
|
115
|
-
too and points you at the app, so the two agree instead of one silently working around the other.
|
|
116
|
-
(A lab simulation of the profile shape can override it with `DSH_ALLOW_DESKTOP_PROFILE=1`.)
|
|
117
|
-
**The app's own bundled CLI is the exception** — `<install>\resources\runtime\cli\bin\dsh.cmd` is allowed
|
|
118
|
-
to operate on that profile (an older note claimed a pin installed a different version; that note is withdrawn).
|
|
119
|
-
It is a launcher, not a dsh feature: it starts Electron with `ELECTRON_RUN_AS_NODE=1` and runs the
|
|
120
|
-
desktop-host CLI, so it is the app talking to its own profile rather than something driving from outside.
|
|
121
|
-
- **Nothing else to do on the preset side**: `$DSH_HOME/.agent-presets/` is product data shared by the
|
|
122
|
-
desktop app and the CLI, and the preset is seeded by the plugin on first activation.
|
|
123
|
-
- **If the mode does not show up in the picker, open Settings → Custom mode and read the warning.** A preset
|
|
124
|
-
whose rows cannot start on that machine is marked *broken* by the platform and dropped from every picker;
|
|
125
|
-
the settings page names the rows and offers **Fix for this line**. On the desktop line that can take one
|
|
126
|
-
click and then a **restart of the app** — the picker re-reads the registry only at boot (measured on
|
|
127
|
-
1.11.1, see `docs/MEASUREMENTS.md` section 34).
|
|
128
|
-
- If a third-party bundle ever keeps the app from starting, the native recovery dialog offers
|
|
129
|
-
**Disable third-party plugins**; installed packages and the plugin's own data stay on disk.
|
|
130
|
-
|
|
131
|
-
**Compatibility is declared, not assumed.** dsh checks every plugin's
|
|
132
|
-
`peerDependencies["@deepseek-ai/dsh"]` against the running runtime (prereleases included), and since
|
|
133
|
-
0.2.0 that check is an **installation gate**, not a warning: a range that does not cover the runtime
|
|
134
|
-
means `dsh plugin add` refuses the package outright
|
|
135
|
-
(`installation rejected: Plugin … is incompatible with dsh 0.2.0-rc.2`). The declared range therefore
|
|
136
|
-
*is* the support statement, which is why it moves only after the new line has been installed and tested
|
|
137
|
-
— a range that "probably" works is exactly the kind of claim that turns into a support ticket.
|
|
138
|
-
|
|
139
|
-
To keep the sources around as well — or to install without npm — clone and run the script, which does
|
|
140
|
-
the same two things explicitly:
|
|
141
|
-
|
|
142
|
-
```sh
|
|
143
|
-
git clone https://github.com/BOWLUNA/dsh-custom-mode
|
|
144
|
-
cd dsh-custom-mode
|
|
145
|
-
./install.sh # copies preset/ into $DSH_HOME/.agent-presets/custom/ and installs the plugin
|
|
146
|
-
./uninstall.sh # removes the plugin; keeps your prompt unless you pass --purge
|
|
147
|
-
```
|
|
23
|
+
## Use
|
|
148
24
|
|
|
149
|
-
|
|
150
|
-
|
|
25
|
+
1. Open Settings → Custom mode.
|
|
26
|
+
2. Edit the system prompt. Save is directly under the editor.
|
|
27
|
+
3. A new session uses this assistant when `settings.yaml` has no `agent-presets.default` yet. An existing value is left as it is.
|
|
151
28
|
|
|
152
|
-
|
|
29
|
+
The prompt is `prompt.md`. The next time a model step is assembled, that file is read again. History can load an older draft into the editor; loading does not write. A save computed against an older copy is refused when the file changed underneath. The model can change the same file only through `custom_prompt`, which asks first.
|
|
153
30
|
|
|
154
|
-
|
|
155
|
-
([latest](https://github.com/BOWLUNA/dsh-custom-mode/releases/latest/download/dsh-custom-mode.dshpreset)).
|
|
156
|
-
It is a zip holding one ready-to-use assistant: `manifest.json` plus `preset/` — the composition, a
|
|
157
|
-
`prompt.md`, the reader that re-reads it before every model step, and a model-facing tool that reads and
|
|
158
|
-
rewrites that prompt. Import it in the desktop app and you have a working「自定义模式」**without
|
|
159
|
-
installing a package**:
|
|
31
|
+
New assistants start as one posture. That choice applies only to the assistant you create next.
|
|
160
32
|
|
|
161
|
-
| | |
|
|
33
|
+
| Posture | After create |
|
|
162
34
|
| --- | --- |
|
|
163
|
-
|
|
|
164
|
-
|
|
|
165
|
-
|
|
166
|
-
So the preset is the 30-second way to see what this is, and the plugin is the way to live with it.
|
|
167
|
-
Importing the preset does not conflict with installing the plugin afterwards: the plugin seeds its own
|
|
168
|
-
preset under `$DSH_HOME/.agent-presets/` and never overwrites a `prompt.md` you wrote.
|
|
169
|
-
|
|
170
|
-
## Usage
|
|
171
|
-
|
|
172
|
-
The settings page (Settings → "Custom mode") is an **assistant manager**: the top of the page lists
|
|
173
|
-
every custom mode you have — create, switch, delete — and the four blocks below (name, base mode,
|
|
174
|
-
plugin switches, system prompt) edit **whichever one is selected**.
|
|
35
|
+
| Develop | Built-in Standard tool set. |
|
|
36
|
+
| Write | Terminal off. File tools on. |
|
|
37
|
+
| Chat | Files and terminal off. |
|
|
175
38
|
|
|
176
|
-
|
|
177
|
-
the roster's own sort key), so it survives a restart and the new-session picker follows it.
|
|
178
|
-
- **Import / export a prompt** — "Export prompt" saves the current text as a `.md`; "Import prompt"
|
|
179
|
-
reads a file into the **editor** (nothing is written until you save), so an import goes through the
|
|
180
|
-
same `{{…}}` validation as anything typed.
|
|
181
|
-
- **Asking the agent to change its own prompt requires your approval.** The in-session `custom_prompt`
|
|
182
|
-
tool goes through the platform's approval seam (`tools/pre-execute` returning `ask`), so the request waits
|
|
183
|
-
for an explicit「允许一次」and shows what would be written and where. Measured: with the `ask` approval
|
|
184
|
-
policy the panel appears and approving really writes; with `never` (full access) nothing prompts and the
|
|
185
|
-
call is **denied**. The worst case is therefore "the change does not happen", never "it happened quietly".
|
|
186
|
-
- **配置了却不生效会被点名** — the page warns when a setting cannot take effect: the「身份(系统提示词)」
|
|
187
|
-
row is off while `prompt.md` still has content (so your prompt is silently ignored), the `custom_prompt`
|
|
188
|
-
tool row is off, the assistant has no name or no description (the picker shows the bare id /「暂无描述」).
|
|
189
|
-
- **The agent can change its own prompt, with your approval** — the in-session `custom_prompt` tool reads the
|
|
190
|
-
prompt, replaces it, or **appends** to it. Appending matters because it never has to *reproduce* the whole
|
|
191
|
-
prompt: an agent that wants to remember one rule cannot lose existing content on the way (measured: it may
|
|
192
|
-
still read first to see what it is adding to). Both writing actions go through the platform's approval panel
|
|
193
|
-
first.
|
|
194
|
-
- **Change history** — every save, *and* any change made outside this page (the in-session
|
|
195
|
-
`custom_prompt` tool, a hand edit of `prompt.md`), leaves a version in the history list under the
|
|
196
|
-
prompt box, labelled with when and where it came from. Loading one only edits the draft: nothing is
|
|
197
|
-
written until you save, so browsing old versions cannot destroy the current one. Before this, a prompt
|
|
198
|
-
changed from inside a session was invisible — the page only ever showed "the current text".
|
|
199
|
-
- **Reset to the factory prompt** — one click puts the **shipped template** (the text a new assistant
|
|
200
|
-
starts from) back into the editor. It is draft-only like every other edit: nothing is written until
|
|
201
|
-
you save, and Reload discards it. Before this existed, a prompt you had edited into a corner could
|
|
202
|
-
only be recovered by deleting the assistant and creating it again.
|
|
203
|
-
- **New assistant** — type a name and click "New assistant". It is seeded from the packaged template:
|
|
204
|
-
the full Standard row set plus a starter prompt, selectable in a new session as soon as you save it —
|
|
205
|
-
**in an already-open page the picker's list is a load-time snapshot, so refresh (F5) once to see a new
|
|
206
|
-
assistant there** (measured; the roster itself is up to date).
|
|
207
|
-
- **Duplicate** — copies the selected assistant's prompt, base mode and row switches into a new one;
|
|
208
|
-
the two are independent afterwards.
|
|
209
|
-
- **Each assistant is independent** — its prompt, base mode and row switches are its own; changing one
|
|
210
|
-
leaves the others alone.
|
|
211
|
-
- **Base mode is the row set, not the prompt** — it decides which rows exist and which tools the mode has;
|
|
212
|
-
this plugin always replaces the base's `persona` row with its own reader (`complete: false`), so the
|
|
213
|
-
base's *prompt* semantics are **not** inherited. Minimal is the visible case: you get minimal's tool set,
|
|
214
|
-
not minimal's prompt.
|
|
215
|
-
- **A fifth base mode: Custom — the union of every shipped row.** The first four are dsh's own; the fifth is
|
|
216
|
-
**synthesised by this plugin**. Its row set is the union of those four, and a row declared by more than one
|
|
217
|
-
mode keeps the text and shipped default of whichever mode comes first in `standard → ptc → minimal →
|
|
218
|
-
cordis` order — so standard's shipped state wins where there is a conflict.
|
|
219
|
-
Why it has to exist: a switch can only rewrite a row the *base text already has*, so on Standard the rows
|
|
220
|
-
only PTC declares (`tool-presentation`), only Minimal declares (the persistent-terminal group) and only
|
|
221
|
-
Cordis declares (`tool-cordis`) were **unreachable** — not hidden in the UI, just absent from the composer.
|
|
222
|
-
Measured on `0.2.0-rc.2`: standard 32 rows, PTC 33, Cordis 33, Minimal 7, and the union **40**. Groups
|
|
223
|
-
travel whole with their `isolate` realms and `!!js` conditions intact, so the union cannot invent a row
|
|
224
|
-
that `dsh-agent-presets` would refuse to mount.
|
|
225
|
-
- **The two shells cannot both be on, and the plugin moves the switch for you.** The union contains one
|
|
226
|
-
mutually exclusive pair: Minimal's "persistent terminal" set and standard's `tool-bash` / `tool-pwsh` are
|
|
227
|
-
two implementations of the same thing — both register a tool called `bash`. Enabling both makes
|
|
228
|
-
`dsh-agent-presets` mark the whole mode **broken**, and a broken mode is silently dropped from **every**
|
|
229
|
-
picker while the settings page stays green. So in Custom mode, turning one side on turns the other off,
|
|
230
|
-
and the save message says which row moved. A conflicting combination written outside the page (hand edit,
|
|
231
|
-
another tool) is named by a warning instead of failing silently.
|
|
232
|
-
- **Switching assistants never discards drafts** — each keeps its own unsaved edits, marked
|
|
233
|
-
"Unsaved" in the list; the only path that throws edits away is the reload button, which renames
|
|
234
|
-
itself to say so.
|
|
235
|
-
- **Delete** — a confirmation, then the plugin does the removal itself. Which confirmation depends on the
|
|
236
|
-
line: when the shell hands a third-party client plugin its `RiskConfirmation` atom you get the shell's own
|
|
237
|
-
dialog with a tick-box; on `0.1.7-rc.2` the client seed table only exposes `Button/Input/Switch/Tag/Pill`,
|
|
238
|
-
so it degrades to a native `confirm` (same guardrail, one prompt instead of a dialog). Removal works on both
|
|
239
|
-
lines: `0.1.6` and older have `agentPresets.remove()`, while `0.1.7`+ has no such call at all — there the
|
|
240
|
-
plugin disposes its own registration and removes the directory. It only removes the mode directory from disk:
|
|
241
|
-
**sessions already using it keep running** (their composition was read when they started), and new sessions
|
|
242
|
-
no longer offer it.
|
|
243
|
-
- **Ask the agent** — every assistant ships a `custom_prompt` tool, so a session can read or rewrite
|
|
244
|
-
**its own** prompt.
|
|
245
|
-
- **Edit the file** — `$DSH_HOME/.agent-presets/<assistant id>/prompt.md` is that assistant's single
|
|
246
|
-
source of truth.
|
|
39
|
+
## Boundaries
|
|
247
40
|
|
|
248
|
-
|
|
249
|
-
|
|
41
|
+
- It does not replace Standard, PTC, Minimal, or Creator.
|
|
42
|
+
- It does not ship a role-play preset.
|
|
43
|
+
- It does not run in the desktop profile from the CLI. Headless mode will not start a session that uses an agent preset.
|
|
250
44
|
|
|
251
|
-
|
|
252
|
-
shell's own `@deepseek-ai/dsh-client-ui-primitives`, so theme, light/dark and future restyling reach
|
|
253
|
-
this page automatically; a shell that does not provide those atoms falls back to built-in plain
|
|
254
|
-
controls with the same behaviour.
|
|
45
|
+
## Compatibility
|
|
255
46
|
|
|
256
|
-
|
|
257
|
-
and its directory name is its internal id. The page manages only **presets this tool created** — the
|
|
258
|
-
test is that the directory carries `prompt.md` and that its composition injects identity through
|
|
259
|
-
`prompt-reader.mjs`. Any other hand-authored preset is neither listed nor touched: the page
|
|
260
|
-
regenerates a composition from a base mode, and doing that to a hand-written one would destroy it.
|
|
47
|
+
Declared range: `>=0.1.5-rc.2 <0.2.0-0 || >=0.1.6-alpha.1 <0.2.0-0 || >=0.1.7-alpha.1 <0.2.0-0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0`
|
|
261
48
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
From dsh `0.1.6-alpha.2` the harness ships a Plugins page that can enable and disable plugins live.
|
|
265
|
-
It and this mode's per-row switches act at **different levels**:
|
|
266
|
-
|
|
267
|
-
| | Built-in Plugins page | This mode's per-row switches |
|
|
49
|
+
| dsh | Claim | Checked for 2.2.0 |
|
|
268
50
|
| --- | --- | --- |
|
|
269
|
-
|
|
|
270
|
-
|
|
|
271
|
-
|
|
272
|
-
They coexist: the harness decides what the machine has, this mode decides which of it the mode uses.
|
|
273
|
-
|
|
274
|
-
The boundary is **drawn by upstream**: the Plugins page documents that it manages "the profile's bundles
|
|
275
|
-
and their uniquely addressable rows", and states plainly that **agent-preset rows remain read-only**.
|
|
276
|
-
The preset layer is therefore out of its reach — and that is exactly the layer this mode covers.
|
|
51
|
+
| `0.2.0-rc.2` | declared | Windows web profile, before this release |
|
|
52
|
+
| `0.2.1-alpha.1` | declared, in CI | not re-run for this release |
|
|
53
|
+
| `0.1.7-rc.2` | declared, in CI | not re-run for this release |
|
|
277
54
|
|
|
278
|
-
|
|
279
|
-
Standard and PTC** — only Creator enables it. The official modes give you no way to change that; here
|
|
280
|
-
you flip one switch.
|
|
55
|
+
The unit suite also passed under WSL2 Ubuntu 26.04 (Node only, no dsh process, no browser). That is not a Linux desktop result.
|
|
281
56
|
|
|
282
|
-
##
|
|
57
|
+
## Docs
|
|
283
58
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
- **Prompt text** is re-read per step, so an edit applies to the **running** session immediately.
|
|
291
|
-
- **Switches and base mode** rewrite the composition file. `agent-presets` remounts a preset when that
|
|
292
|
-
file's `mtimeMs` and `size` change, so a **new session** picks them up; a running session keeps the
|
|
293
|
-
configuration it started with, which is deliberate — swapping a tool set mid-conversation would be wrong.
|
|
294
|
-
|
|
295
|
-
Row switches are tri-state. A row you never touched stays byte-identical to the shipped one, including
|
|
296
|
-
its `!!js` platform condition and its shipped `disabled` state; an explicit on/off replaces that
|
|
297
|
-
condition with a boolean. Platform expressions are evaluated on the host, so the page shows the state
|
|
298
|
-
actually in force on this machine rather than whether a key exists.
|
|
299
|
-
|
|
300
|
-
Several assistants need no new mechanism: `dsh-agent-presets` already scans **every** directory under
|
|
301
|
-
the user preset root, and re-reads those roots on each roster call, so a directory created just now is
|
|
302
|
-
selectable the next time a session is started. Each assistant's `prompt-reader.mjs` / `prompt-tool.mjs`
|
|
303
|
-
resolves `prompt.md` relative to **its own module location**, so N copies are N independent prompts.
|
|
304
|
-
Creation seeds the packaged template; deletion goes through the platform's `agentPresets.remove()` where it
|
|
305
|
-
exists and through the plugin's own dispose-and-remove path where it does not (0.1.7+),
|
|
306
|
-
which refuses a shipped preset and re-checks that the directory really lives under the writable root.
|
|
307
|
-
|
|
308
|
-
## Versioning
|
|
309
|
-
|
|
310
|
-
The package version is its **own line** — `1.0.0`, then `1.0.1`, … It does not mirror the DSH release.
|
|
311
|
-
What this plugin supports is declared in `engines.dsh` and the `@deepseek-ai/dsh` peer range in
|
|
312
|
-
`package.json`, and `tools/verify-version-consistency.mjs` (run in CI) asserts that the DSH
|
|
313
|
-
version CI installs and tests falls inside those ranges.
|
|
314
|
-
|
|
315
|
-
**Three lines are supported: the newest stable line (`0.2.0-rc.2`, which npm's `latest` and `next` both
|
|
316
|
-
point at since 2026-09-29, and the line the desktop app ships), the newest preview line
|
|
317
|
-
(`0.2.1-alpha.1`, which npm's `alpha` points at) and the previous stable (`0.1.7-rc.2` — still inside
|
|
318
|
-
the declared range, and what most existing installs run)** — declared as
|
|
319
|
-
`>=0.1.5-rc.2 <0.2.0-0 || >=0.1.6-alpha.1 <0.2.0-0 || >=0.1.7-alpha.1 <0.2.0-0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0`.
|
|
320
|
-
The official one-click installer reads `peerDependencies` and **lets prereleases match** (`semver.satisfies(version, range, { includePrerelease: true })` in `dsh-app-boot`). The current stable line `0.2.0-rc.2` and the preview line `0.2.1-alpha.1` both install. The range still names those prereleases because npm and pnpm's default comparison is stricter, so a marketplace using that comparison does not reject the preview line either. CI installs all three lines and runs the full suite on each. The render gate runs only on `0.2.0-rc.2`, where the shell's UI changes land first. Older `0.1.5` / `0.1.6` builds stay inside the peer range and no longer have their own CI leg.
|
|
321
|
-
**The official desktop app (DeepSeek Harness Desktop) is covered too**: it is version-locked to dsh and now
|
|
322
|
-
ships `0.2.0-rc.2`, i.e. the same combination this matrix pins. Install it from inside the app (sidebar →
|
|
323
|
-
Plugins); the CLI is refused for that profile by dsh itself. On `0.2.0-rc.2` measured (2026-09-30, clean
|
|
324
|
-
throwaway `DSH_HOME`): `dsh plugin --profile web add dsh-custom-mode` resolves the package in 640 ms, the
|
|
325
|
-
composition tree carries the row, boot seeds all five preset files, the declarative registry syncs the
|
|
326
|
-
assistant, and the `agentPresets` capability set is unchanged (`list, register, inventory, select,
|
|
327
|
-
document`).
|
|
328
|
-
|
|
329
|
-
Two reasons for the split. A bare `x.y.z` is what directories and markets require before they will
|
|
330
|
-
auto-install a package — several resolve npm `latest` and reject anything carrying a prerelease tag.
|
|
331
|
-
And a version string was never a checkable claim anyway: the declared range is, and it is the thing
|
|
332
|
-
that goes stale when upstream moves. What decides compatibility in practice is still whether the APIs
|
|
333
|
-
below exist, which is what the ranges are for.
|
|
334
|
-
|
|
335
|
-
<details>
|
|
336
|
-
<summary>Coupling points (check these when upgrading dsh)</summary>
|
|
337
|
-
|
|
338
|
-
| Dependency | Failure if it changes |
|
|
339
|
-
| --- | --- |
|
|
340
|
-
| `ctx.systemPrompt.section()` with a **function** `text` | the prompt stops hot-reloading — the point of the project |
|
|
341
|
-
| `agentPresets` remounts on composition `mtimeMs`+`size` | switches need a process restart to apply |
|
|
342
|
-
| `ctx.tools.register()` | loses the `custom_prompt` tool |
|
|
343
|
-
| `ctx.connection.fetch.register({ path, methods, requestBody, fetch })` | settings page 404s — nothing is registered |
|
|
344
|
-
| `kind: 'prefix'` matching both `path` and `path/…` | only the list opens; `/state`, `/create`, `/delete` all 404 |
|
|
345
|
-
| `agentPresets.list()` rows carrying `id` / `trust` / `path`, with `preset.yml` supplying `name` / `description` | the assistant list is empty or unrecognisable |
|
|
346
|
-
| `agentPresets.remove(id)` (legacy only), refusing `trust: 'system'` | 0.1.7+ deletion no longer needs it — the declarative backend disposes the registration and deletes the directory instead |
|
|
347
|
-
| the `/api` channel's fence (Host/Origin + browser auth) | the page cannot authenticate at all; do **not** "fix" it by moving the route to the raw `webServer` table |
|
|
348
|
-
| `ctx.inject(deps, cb)` (scoped wait) | the row parks in `pending` in profiles without a web server |
|
|
349
|
-
| `dsh.client` + `exports["./client"]`, client bundle id == package name | the browser half is not discovered |
|
|
350
|
-
| `settings.section` slot (`id` / `order` / `label`) | page placement and label |
|
|
351
|
-
| **`settings.section` no longer takes `locale:`** (since 0.1.6-alpha.2) | the shell does not hand over a `t` bound to this namespace; the page carries its own dictionaries as a floor — see ARCHITECTURE §15 |
|
|
352
|
-
| `preset.yml`'s `order` participating in the roster sort | move up/down stops working |
|
|
353
|
-
| `ctx.locale.register/bind` | falls back to Chinese |
|
|
354
|
-
| **where the base composition comes from** — `agentPresets.readDocument(<mode>).content` on 0.1.7+, the `@deepseek-ai/dsh-agent-presets` files before that | the base mode and the plugin switches become read-only (the prompt still saves); see `base-composition.mjs` |
|
|
355
|
-
| shipped layout `<presets>/<id>/agent.cordis.yml` and row text shape | base-mode switching breaks |
|
|
356
|
-
| `!!js` platform expressions | platform rows display the wrong state |
|
|
357
|
-
|
|
358
|
-
</details>
|
|
359
|
-
|
|
360
|
-
## Documentation
|
|
361
|
-
|
|
362
|
-
- [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) — failures reproduced on a real machine, with symptoms, cause and a way out.
|
|
363
|
-
- [`docs/MEASUREMENTS.md`](docs/MEASUREMENTS.md) — the commands and raw output behind each claim.
|
|
364
|
-
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — why this is two artifacts, and which host APIs it depends on.
|
|
365
|
-
- [`docs/PUBLISHING.md`](docs/PUBLISHING.md) — how the npm package is published.
|
|
366
|
-
- [`AGENTS.md`](AGENTS.md) — agent-facing notes, including the full recipe for verifying the UI in a
|
|
367
|
-
real browser on the lab (`tools/browser-verify.mjs`).
|
|
368
|
-
- [`CHANGELOG.md`](CHANGELOG.md) · [`SECURITY.md`](SECURITY.md) · [`CONTRIBUTING.md`](CONTRIBUTING.md)
|
|
369
|
-
|
|
370
|
-
## Development
|
|
371
|
-
|
|
372
|
-
```sh
|
|
373
|
-
node test/run.mjs # 15 suites; resolves the shipped presets itself (0.1.7+ derives them from the host)
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
Edits to `client.js` are hot-swapped by `@deepseek-ai/dsh-client-hmr` about a second later; the
|
|
377
|
-
host half (`index.mjs`, `composition.mjs`, `meta.mjs`, `paths.mjs`) needs a restart. See
|
|
378
|
-
[`test/README.md`](test/README.md) for what each suite protects, and [`CONTRIBUTING.md`](CONTRIBUTING.md)
|
|
379
|
-
before changing behaviour.
|
|
380
|
-
|
|
381
|
-
## If it helps
|
|
382
|
-
|
|
383
|
-
A ⭐ on GitHub is what makes a plugin findable in a catalogue of thousands — it costs you nothing and it is
|
|
384
|
-
the whole reason this page keeps getting maintenance. If it is **not** working on your dsh line, open an issue
|
|
385
|
-
with the output of `dsh --version`: that is the fastest path to a fix, and the compatibility table above is
|
|
386
|
-
what came out of the last one.
|
|
59
|
+
- [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) — wrong version installed, base mode unavailable, half-finished upgrade
|
|
60
|
+
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — where the prompt is read, and which host calls this package depends on
|
|
61
|
+
- [docs/PUBLISHING.md](docs/PUBLISHING.md) — tags and release
|
|
62
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) — people
|
|
63
|
+
- [AGENTS.md](AGENTS.md) — agents
|
|
387
64
|
|
|
388
65
|
## License
|
|
389
66
|
|
|
390
67
|
MIT
|
|
391
|
-
|
|
392
|
-
## Updating
|
|
393
|
-
|
|
394
|
-
The plugin lives in the profile's `node_modules` and the platform owns that installation, so updating means
|
|
395
|
-
installing again — your data is not touched:
|
|
396
|
-
|
|
397
|
-
```sh
|
|
398
|
-
# the pinned form: what you ask for is what you get
|
|
399
|
-
dsh plugin --profile web add dsh-custom-mode@2.1.0
|
|
400
|
-
# then restart the DSH process that serves the web profile
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
**Do not install by bare name, and do not use `@latest`.** pnpm applies a release cooldown
|
|
404
|
-
(`minimumReleaseAge`, 24 hours by default). A bare `dsh plugin add dsh-custom-mode` resolves to *the newest
|
|
405
|
-
version older than 24 hours*. Measured: while npm `latest` was 1.12.2 and six minutes old, `@latest` installed
|
|
406
|
-
1.11.6. Pin the exact version.
|
|
407
|
-
|
|
408
|
-
Each exact pin appends a `minimumReleaseAgeExclude` line in the profile's `pnpm-workspace.yaml`. pnpm 11.7.0
|
|
409
|
-
honours only the first line that matches the package name ([pnpm#12463](https://github.com/pnpm/pnpm/issues/12463)).
|
|
410
|
-
Keep one line, `dsh-custom-mode`, not a list of versions. This plugin does not edit that file. If install fails
|
|
411
|
-
with `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`, merge the list to that one line and run the install again:
|
|
412
|
-
`node_modules` may already show the new version while `package.json` still names the old one.
|
|
413
|
-
|
|
414
|
-
**How to know the upgrade worked**: restart dsh, then read the version at the bottom of this settings page.
|
|
415
|
-
|
|
416
|
-
**What an update does not touch**: `$DSH_HOME/.agent-presets/<your assistants>/` — `prompt.md`, `preset.yml` and
|
|
417
|
-
your row switches are yours. Seeding only fills in *missing* files, so a prompt you wrote is never overwritten.
|
|
418
|
-
|
|
419
|
-
**If the base mode and the plugin switches are greyed out with a one-line warning**: this dsh line exposes no
|
|
420
|
-
shipped composition to this plugin (the resolver tried the host's `readDocument()`, the legacy presets package
|
|
421
|
-
and the packaged `dsh-web-app` patch — the host log names each attempt). The system prompt still saves on its
|
|
422
|
-
own; nothing else about the mode is touched. On 0.1.7 that was a hard 500 until 1.9.13.
|
|
423
|
-
|
|
424
|
-
**If a mode stops appearing in the picker after an update**: an assistant created by an older version keeps its
|
|
425
|
-
old composition file, and if that file enables a plugin row this dsh line does not ship, the platform marks the
|
|
426
|
-
whole preset broken and silently drops it while the settings page keeps working. Open the settings page: it says
|
|
427
|
-
so and offers **「Fix for this line」**, which turns exactly those rows off and leaves everything else alone.
|
package/README.zh.md
CHANGED
|
@@ -2,322 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | 中文
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
助手(多模式 / 多角色扮演 RP)。英文关键词:dsh custom mode / custom prompt / system prompt editor /
|
|
7
|
-
base mode / plugin switches / multi-assistant / multi-persona。
|
|
5
|
+
在 DeepSeek Harness(`dsh`)里改一个模式的系统提示词、基础模式和插件开关。可以有多个助手。标准、PTC、极简、创造仍留在菜单里。
|
|
8
6
|
|
|
9
|
-
](https://github.com/BOWLUNA/dsh-custom-mode/stargazers) [](https://www.npmjs.com/package/dsh-custom-mode) [](https://github.com/BOWLUNA/dsh-custom-mode/actions/workflows/test.yml) [](LICENSE) [](https://github.com/BOWLUNA/dsh-custom-mode#readme)
|
|
12
|
-
|
|
13
|
-
[](https://b23.tv/qJ4Ev0W) [](https://v.douyin.com/VWh0M03Fa4Y/) [](https://xhslink.cn/o/A7QtXmePBBF) [](https://discord.gg/pz97SfAfSy) [](https://github.com/BOWLUNA/dsh-custom-mode/discussions)
|
|
14
|
-
|
|
15
|
-
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(dsh)用的自定义模式。它的系统提示词是一个普通文件,可以在 Web 设置页里编辑,**改完下一步模型调用即生效** —— 不用重启,也不用新建会话。
|
|
16
|
-
|
|
17
|
-
一句话:**给 dsh 的 agent 模式用的设置页** —— 选这个模式的基础组成、逐行开关它挂载的插件、并编辑它的系统提示词;提示词每个模型调用前重新读取。可以并存多个模式(「助手」),各自的提示词互不影响。
|
|
18
|
-
|
|
19
|
-
常见的叫法:自定义模式 · 自定义提示词 · 系统提示词编辑 · 多助手/多模式 · 多个 Agent 模式 ·
|
|
20
|
-
角色扮演/聊天人格(RP)。
|
|
21
|
-
|
|
22
|
-
**单元测试覆盖三条线,渲染闸门只跑 `0.2.0-rc.2`。** npm 的 `latest` 与 `next` 自 2026-09-29 起都指向 `0.2.0-rc.2`:
|
|
23
|
-
|
|
24
|
-
| dsh | 定位 | 状态 |
|
|
25
|
-
| --- | --- | --- |
|
|
26
|
-
| `0.2.0-rc.2` | **最新线** —— npm 的 `latest` 与 `next` 都指向它,官方桌面端也在这一条线上(与 dsh 同版本号) | ✅ CI(ubuntu node 20/24 + **windows**)+ 真机:这条线上安装、组合树与播种都验过(整道渲染闸门跑在这里)|
|
|
27
|
-
| `0.2.1-alpha.1` | 预览线 —— npm 的 `alpha` 指向它。单元测试覆盖;渲染闸门不在这条线上 | ✅ CI |
|
|
28
|
-
| `0.1.7-rc.2` | 上一个正式版 —— 仍在声明范围内,现役安装大多在它上面 | ✅ CI。设置页在这条线上会退回壳没提供的控件;渲染闸门不在这里 |
|
|
29
|
-
|
|
30
|
-
更早的线(`0.1.5-rc.3`、`0.1.6-alpha.*`)共用同一套机制,peer 范围仍然接纳,但不再单独占 CI 腿。
|
|
31
|
-
|
|
32
|
-
官方四个模式(`standard` / `ptc` / `minimal` / `cordis`)不受影响。
|
|
33
|
-
|
|
34
|
-
<p align="center">
|
|
35
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/01-mode-switch.png" width="360" alt="基础模式与插件开关">
|
|
36
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/02-plugin-switches.png" width="360" alt="插件开关"><br>
|
|
37
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/03-system-prompt.png" width="360" alt="系统提示词">
|
|
38
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/04-preset-picker.png" width="360" alt="模式选择器">
|
|
39
|
-
</p>
|
|
40
|
-
|
|
41
|
-
<p align="center">
|
|
42
|
-
<img src="https://raw.githubusercontent.com/BOWLUNA/dsh-custom-mode/main/docs/images/05-assistant-manager.png" width="360" alt="助手">
|
|
43
|
-
</p>
|
|
44
|
-
|
|
45
|
-
上面四张是一组 2×2。助手管理器单独居中。五张都是英文,文件都是 800×800,用一个没有会话记录的一次性 `DSH_HOME` 拍出。
|
|
7
|
+

|
|
46
8
|
|
|
47
9
|
## 安装
|
|
48
10
|
|
|
49
|
-
|
|
11
|
+
钉版本。只写包名时,pnpm 的发布冷却期可能装到旧版。细节见 [docs/TROUBLESHOOTING.zh.md](docs/TROUBLESHOOTING.zh.md)。
|
|
50
12
|
|
|
51
13
|
```sh
|
|
52
|
-
dsh plugin --profile web add dsh-custom-mode@2.
|
|
53
|
-
# 不带版本号会受 pnpm 的发布冷却期影响(`minimumReleaseAge`,默认一天):发布后数小时内按名安装
|
|
54
|
-
# 可能**静默装到旧版** —— 实测 1.3.0 发布 38 分钟后按名安装装到了 1.0.3。用 profile 里的
|
|
55
|
-
# `npm ls dsh-custom-mode` 核对实际装到的版本,或像上面那样钉版本。
|
|
14
|
+
dsh plugin --profile web add dsh-custom-mode@2.2.0
|
|
56
15
|
```
|
|
57
16
|
|
|
58
|
-
|
|
59
|
-
**那里已有的文件一律不动**,所以你自己写过的 `prompt.md` 不会被覆盖。
|
|
17
|
+
重启为这个 profile 提供服务的进程。设置页上的版本号才是正在运行的版本。
|
|
60
18
|
|
|
61
|
-
|
|
62
|
-
任务是因为那个平台有自己的失败模式(`install.sh` 里的 MSYS 路径、并发保存时 `rename` 的目标锁、平台表达式
|
|
63
|
-
求值方向相反)。两个 shell 脚本在任何 POSIX shell 下都能用,含 Git Bash。
|
|
64
|
-
|
|
65
|
-
### 图形界面安装(不用终端)
|
|
66
|
-
|
|
67
|
-
dsh `0.1.6-alpha.2` 起有插件管理页:**侧边栏 → 插件 → 添加插件**。它接受三种输入,本插件对应如下:
|
|
68
|
-
|
|
69
|
-
| 输入 | 填什么 | 说明 |
|
|
70
|
-
| --- | --- | --- |
|
|
71
|
-
| **包名** | `dsh-custom-mode` | 受 pnpm 发布冷却期影响,可能装到旧版。要这一版请钉 `@2.1.0` |
|
|
72
|
-
| **GitHub 仓库地址** | `https://github.com/BOWLUNA/dsh-custom-mode` | 指向**仓库根**即可 |
|
|
73
|
-
| **本地插件目录** | `<你 clone 的路径>` | 就是仓库根 —— 仓库根**本身**就是发布包 |
|
|
19
|
+
桌面端从应用里的插件页安装。CLI 不能改 `profiles/desktop`。
|
|
74
20
|
|
|
75
|
-
|
|
76
|
-
打开 **设置 → 插件市场**,搜 `dsh-custom-mode` —— 卡片会读本插件声明的 `engines.dsh` 范围,
|
|
77
|
-
以及仓库里 `screenshots.json` 列出的精选截图(五张;它们就是 README 用的那几张
|
|
78
|
-
`docs/images/*.png`,所以每张图在仓库里只有一份)。
|
|
21
|
+
在 Windows 上,`install.sh` 是 bash,而且 PATH 里要有 `dsh`。否则用 DeepSeek Harness 自带的 `dsh`,或 `node node_modules/@deepseek-ai/dsh/lib/bin.js`。
|
|
79
22
|
|
|
80
|
-
|
|
81
|
-
`exports["./client"]` 都声明在仓库根,所以 npm 安装与"GitHub 地址"安装拿到的是同一批文件。
|
|
82
|
-
1.10.0 之前这个仓库有**两份清单**——根部的 `private: true` 包装清单加 `editor/package.json`——
|
|
83
|
-
那正是第三方目录把本插件显示成 `dsh-custom-mode#editor`、以及 dshfind 这类站点读到包装清单的
|
|
84
|
-
`private: true` 后报"作者尚未发布到 npm"的原因。现在只有根清单一份,`test/manifests.test.mjs` 盯着它不被加回来。
|
|
85
|
-
|
|
86
|
-
### 桌面端
|
|
87
|
-
|
|
88
|
-
桌面端就在 dsh 仓库里(`apps/desktop`),**与 dsh 同版本号发布**(Electron 与 `@deepseek-ai/dsh`
|
|
89
|
-
永远同一个精确版本),而且它就是**套了 Electron 壳的完整 Web 应用** —— 所以本插件的页面在那边原样渲染。
|
|
90
|
-
安装只有一条路,就是上面那条:
|
|
91
|
-
|
|
92
|
-
- **在应用里装**:侧栏 → **插件** → 添加插件 → 搜 `dsh-custom-mode`。应用自带 pnpm,走的是同一套插件管理器。
|
|
93
|
-
- **不要试着用独立的 CLI 装 —— dsh 自己就会拒绝**(0.1.7-rc.2 实测,0.2.0-rc.2 复测同样):
|
|
94
|
-
```
|
|
95
|
-
$ dsh plugin --profile desktop add .
|
|
96
|
-
error: profile "desktop" is managed exclusively by the Electron application
|
|
97
|
-
```
|
|
98
|
-
桌面端独占 `$DSH_HOME/profiles/desktop`:那里的包操作持有 profile 事务锁,启动恢复还会重命名
|
|
99
|
-
`cordis.patch.yml`。所以 `install.sh` 也**拒绝** `--profile desktop` 并指向应用内安装 —— 两边一致,
|
|
100
|
-
而不是某一方偷偷绕过去。(只想在本机模拟 profile 形状时可设 `DSH_ALLOW_DESKTOP_PROFILE=1`。)
|
|
101
|
-
**应用自带的捆绑 CLI 是例外**:`<安装目录>\resources\runtime\cli\bin\dsh.cmd` 可以操作那个 profile
|
|
102
|
-
(1.11.1 实测时,命令写的版本和装上的版本对不上,这次记录作废)。它是启动器而不是 dsh 的
|
|
103
|
-
新功能 —— 它用 `ELECTRON_RUN_AS_NODE=1` 起 Electron 去跑 desktop-host 的 CLI,所以那是**应用在跟自己的
|
|
104
|
-
profile 说话**,不是从外面驱动它。
|
|
105
|
-
- **预设那一侧不用做任何事**:`$DSH_HOME/.agent-presets/` 是桌面端与 CLI 共享的产品数据,
|
|
106
|
-
预设由插件首次激活时落盘。
|
|
107
|
-
- **模式没出现在选择器里,就去「设置 → 自定义模式」读那条告警。** 行的启动条件在本机不满足时,平台会把整个
|
|
108
|
-
预设判为 broken 并**从所有选择器里丢掉**;设置页会点名那几行,并给出**「按本线修复」**。在桌面端那条线上,
|
|
109
|
-
这通常是一次点击 + **重启应用** —— 选择器只在应用启动时重读注册表(1.11.1 实测,见 `docs/MEASUREMENTS.md` §34)。
|
|
110
|
-
- 万一某个第三方 bundle 让应用起不来:原生恢复对话框提供**「禁用第三方插件」**,已安装的包与插件数据都留在磁盘上。
|
|
111
|
-
|
|
112
|
-
**兼容性是声明出来的,不是猜的。** dsh 会拿每个插件的 `peerDependencies["@deepseek-ai/dsh"]` 与运行时
|
|
113
|
-
版本比对(含预发布版);而且自 0.2.0 起这项检查从"警告"升级成了**安装闸门**:范围不覆盖运行时就
|
|
114
|
-
直接装不进去(`installation rejected: Plugin … is incompatible with dsh 0.2.0-rc.2`)。所以那个范围
|
|
115
|
-
**就是**支持声明本身,只有在真实安装并测过新线之后才会动——"大概能用"的范围正是会变成支持工单的那种声明。
|
|
116
|
-
|
|
117
|
-
想同时留下源码(或者不用 npm 安装),就 clone 下来跑脚本,它把同样两件事显式做一遍:
|
|
118
|
-
|
|
119
|
-
```sh
|
|
120
|
-
git clone https://github.com/BOWLUNA/dsh-custom-mode
|
|
121
|
-
cd dsh-custom-mode
|
|
122
|
-
./install.sh # 复制 preset/ 到 $DSH_HOME/.agent-presets/custom/,并安装插件
|
|
123
|
-
./uninstall.sh # 卸载插件;默认保留你的提示词,加 --purge 一并删除
|
|
124
|
-
```
|
|
23
|
+
## 使用
|
|
125
24
|
|
|
126
|
-
|
|
25
|
+
1. 打开设置 → 自定义模式。
|
|
26
|
+
2. 改系统提示词。保存按钮在编辑器下面。
|
|
27
|
+
3. `settings.yaml` 里还没有 `agent-presets.default` 时,新会话用这个助手。已经写过的值保持原样。
|
|
127
28
|
|
|
128
|
-
|
|
29
|
+
提示词是 `prompt.md`。下一步组装模型输入时会重读这个文件。历史可以把旧稿载入编辑器;载入不落盘。打开页面之后文件被改过时,这一次保存会被拒绝。模型要改同一份文件,只能走 `custom_prompt`,并且先问过你。
|
|
129
30
|
|
|
130
|
-
|
|
131
|
-
([最新版](https://github.com/BOWLUNA/dsh-custom-mode/releases/latest/download/dsh-custom-mode.dshpreset))。
|
|
132
|
-
它是一个 zip,里面是一个**开箱可用的助手**:`manifest.json` 加 `preset/` —— 组成文件、`prompt.md`、
|
|
133
|
-
每次模型调用前重读它的读取器,以及一个**模型可见的工具**(读写这份提示词)。在桌面端导入它,
|
|
134
|
-
**不用装任何包**就能得到一个可用的「自定义模式」:
|
|
31
|
+
新建助手时选一种姿态。它只影响下一次新建。
|
|
135
32
|
|
|
136
|
-
| | |
|
|
33
|
+
| 姿态 | 新建之后 |
|
|
137
34
|
| --- | --- |
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
|
|
141
|
-
⇒ 预设是「30 秒看看这是什么」,插件是「长期用它」。导入预设与之后装插件**不冲突**:
|
|
142
|
-
插件把自己的预设写在 `$DSH_HOME/.agent-presets/` 下,且**从不覆盖**你自己写的 `prompt.md`。
|
|
143
|
-
|
|
144
|
-
## 使用
|
|
35
|
+
| 开发 | 内置标准模式的工具集。 |
|
|
36
|
+
| 写作 | 终端关,文件工具开。 |
|
|
37
|
+
| 聊天 | 文件和终端关。 |
|
|
145
38
|
|
|
146
|
-
|
|
39
|
+
## 边界
|
|
147
40
|
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
(`tools/pre-execute` 返回 `ask`):请求会停在「等待审批」,面板里写明**要写什么、写到哪**,你点「允许一次」
|
|
152
|
-
才会执行。实测:审批策略为 `ask` 时弹面板且批准后真的写入;为 `never`(完全权限)时不弹窗、**直接拒绝**。
|
|
153
|
-
所以最坏情况是"改不成",从不是"悄悄改成了"。
|
|
154
|
-
- **「配置了却不生效」会被点名** —— 设置页会指出那些不生效的配置:「身份(系统提示词)」这一行关着而
|
|
155
|
-
`prompt.md` 还有内容(你写的提示词被静默忽略)、`custom_prompt` 工具行关着、助手没有名字或描述
|
|
156
|
-
(选择器里会显示成裸 id 或「暂无描述」)。
|
|
157
|
-
- **agent 能改自己的提示词,但要你批准** —— 会话内的 `custom_prompt` 工具可以读、整体替换,或者**追加**。
|
|
158
|
-
追加的意义在于**不必把整段提示词重新写一遍**:想记住一条规则时,不可能因为重写而丢掉已有内容
|
|
159
|
-
(实测:模型可能仍会先读一次,看看自己要加到什么内容后面)。两种写入动作都会先过平台的审批面板。
|
|
160
|
-
- **改动历史** —— 每次保存,以及**在设置页之外**发生的任何改动(会话内的 `custom_prompt` 工具、手工编辑 `prompt.md`),都会在提示词框下面留下一版,并标明时间与来源。载入某一版**只改草稿**:不点保存不会落盘,所以翻旧版本不会毁掉当前这版。在此之前,提示词被会话内改掉是**看不见的** —— 页面永远只显示"当前文本"。
|
|
161
|
-
- **恢复出厂提示词** —— 一键把**出厂模板**(新建助手时得到的那份文本)填回编辑器。它和页面上其它改动一样只改**草稿**:不点保存不会落盘,「重新读取」即可撤销。在此之前,把提示词改坏了只能删掉助手重建。
|
|
162
|
-
- **新增助手** —— 填个名字点「新增助手」。新助手从模板生成:标准模式的全部行 + 一份默认提示词,写好后在新建会话的选择器里就能选到它 —— **已经打开的页面里,选择器的列表是加载时的快照,要看到新助手需刷新一次(F5)**(实测;roster 本身已是最新)。
|
|
163
|
-
- **复制一份** —— 把当前助手的提示词、基础模式、逐行开关整个复制到新助手,之后各改各的。
|
|
164
|
-
- **每个助手各自独立** —— 提示词、基础模式、逐行开关都属于它自己,改一个不影响别的。
|
|
165
|
-
- **基础模式是"行集合",不是提示词** —— 底子决定有哪些行、这个模式有哪些工具;本插件始终把底子的
|
|
166
|
-
`persona` 行替换成自己的读取器(`complete: false`),所以底子的**提示词语义不会被继承**。最明显的是
|
|
167
|
-
「极简模式」:你拿到的是极简的工具集,不是极简的提示词。
|
|
168
|
-
- **第五个基础模式:自定义模式(全部出厂行的并集)** —— 前四个是 dsh 出厂的模式,第五个是**本插件自己合成**的。
|
|
169
|
-
它的行集合是那四个模式的并集;同一行在多个模式里都有时,取**先出现的那个模式**的原文与出厂默认
|
|
170
|
-
(顺序:标准 → PTC → 极简 → 创造),所以出厂状态以标准模式为准。
|
|
171
|
-
为什么需要它:开关只能作用在**基础文本里已经有的行**上,于是选「标准模式」时,只有 PTC 才有的
|
|
172
|
-
`tool-presentation`、只有极简才有的持久终端组、只有创造模式才有的 `tool-cordis` 是**拨不到的**
|
|
173
|
-
—— 不是界面藏起来了,是合成器里根本没有那条通路。0.2.0-rc.2 上实测:标准 32 行、PTC 33 行、创造 33 行、
|
|
174
|
-
极简 7 行,**并集 40 行**。取并集时分组整体搬运,`isolate` realm 与 `!!js` 平台条件原样保留,
|
|
175
|
-
因此不会凭空造出一个会让 `dsh-agent-presets` 拒绝挂载的行。
|
|
176
|
-
- **两套壳不能同时开 —— 插件替你避让。** 并集里有一组互斥的行:极简的「持久终端壳」和标准的
|
|
177
|
-
`tool-bash`/`tool-pwsh` 是同一件东西的两种实现,都注册一个叫 `bash` 的工具。同时启用会让
|
|
178
|
-
`dsh-agent-presets` 把整个模式判为 **broken**,而 broken 的模式会被**从所有选择器里静默丢掉** ——
|
|
179
|
-
设置页却全绿。所以当选「自定义模式」时,打开其中一侧会自动关掉另一侧,并在保存提示里说明动了哪一行。
|
|
180
|
-
页面之外写进去的冲突组合(手工编辑、别的工具)会在告警里被点名。
|
|
181
|
-
- **切换助手不会丢草稿** —— 每个助手各自留着未保存的修改,列表上用「未保存」标出来;唯一会放弃修改的是「放弃修改并重新读取」(有草稿时按钮会改名说明)。
|
|
182
|
-
- **删除** —— 先确认,再由插件自己动手删。确认形态取决于这条线:壳把 `RiskConfirmation` 交给第三方客户端插件时,是壳自己的弹窗(需勾选);而 `0.1.7-rc.2` 的客户端种子表只暴露 `Button/Input/Switch/Tag/Pill`,于是退化为原生 `confirm`(护栏不变,少一个勾选框)。删除两条线都能用:`0.1.6` 及更早有 `agentPresets.remove()`,`0.1.7`+ 根本没有这个调用 —— 那里由插件自己注销注册表项并删掉目录。删除只移除磁盘上的模式目录:**正在使用它的会话不受影响**(组成在会话创建时就已读取),新建会话时不再出现。
|
|
183
|
-
- **直接对 agent 说** —— 每个助手都自带 `custom_prompt` 工具,会话里可以读取或改写**它自己**的提示词。
|
|
184
|
-
- **直接改文件** —— `$DSH_HOME/.agent-presets/<助手 id>/prompt.md` 是那个助手的唯一事实来源。
|
|
41
|
+
- 不替换标准、PTC、极简、创造。
|
|
42
|
+
- 不附带角色扮演预设。
|
|
43
|
+
- 不用 CLI 改桌面端 profile。headless 不会启动使用 agent preset 的会话。
|
|
185
44
|
|
|
186
|
-
|
|
45
|
+
## 兼容
|
|
187
46
|
|
|
188
|
-
|
|
189
|
-
`@deepseek-ai/dsh-client-ui-primitives`,因此主题、深浅色与后续改版都会自动作用到本页;老壳没有提供这组
|
|
190
|
-
原子组件时会退回内置的朴素控件,功能不变。
|
|
47
|
+
声明范围:`>=0.1.5-rc.2 <0.2.0-0 || >=0.1.6-alpha.1 <0.2.0-0 || >=0.1.7-alpha.1 <0.2.0-0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0`
|
|
191
48
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
### 与官方「插件管理」页的分工
|
|
195
|
-
|
|
196
|
-
dsh `0.1.6-alpha.2` 起自带了插件管理页,可以实时启用/停用插件。它和本模式的逐行开关**管的是不同层级**:
|
|
197
|
-
|
|
198
|
-
| | 官方插件管理页 | 本模式的逐行开关 |
|
|
49
|
+
| dsh | 声明 | 2.2.0 核对 |
|
|
199
50
|
| --- | --- | --- |
|
|
200
|
-
|
|
|
201
|
-
|
|
|
202
|
-
|
|
203
|
-
两者并存,不冲突:官方决定「这台机器有什么」,本模式决定「这个模式用其中的哪些」。
|
|
51
|
+
| `0.2.0-rc.2` | 声明支持 | 本版发布前的 Windows web profile |
|
|
52
|
+
| `0.2.1-alpha.1` | 声明支持,CI 有这条腿 | 本版没有重跑 |
|
|
53
|
+
| `0.1.7-rc.2` | 声明支持,CI 有这条腿 | 本版没有重跑 |
|
|
204
54
|
|
|
205
|
-
|
|
206
|
-
**agent-preset 行保持只读**。也就是说**官方管不到 preset 这一层**——本模式补的正是这一块。
|
|
207
|
-
|
|
208
|
-
一个可以当场演示的例子:`tool-plugin-manager`(模型侧的插件安装/启停工具)在**标准模式与 PTC 模式里
|
|
209
|
-
出厂就是关闭的**(只有创造模式默认打开)。官方模式不给你改它的入口,而在这里**拨一下就能打开**。
|
|
210
|
-
|
|
211
|
-
## 工作原理
|
|
212
|
-
|
|
213
|
-
dsh 的系统提示词通常来自 preset 的 YAML,而官方 `@deepseek-ai/dsh-persona` 的 `prefix` 只在挂载时解析一次。本 preset 注册同名的 `deployment:persona-prefix` section,但把 `text` 写成**函数**,agent loop 在每次模型调用前都会调它。
|
|
214
|
-
|
|
215
|
-
因此两件事的生效时机不同:
|
|
216
|
-
|
|
217
|
-
- **提示词文本**每步重新读取,所以改动对**正在运行**的会话立即生效。
|
|
218
|
-
- **开关与基础模式**会重写组成文件。`agent-presets` 在该文件的 `mtimeMs` 与 `size` 变化时重新挂载,所以由**新会话**生效;已开着的会话保持它启动时的配置 —— 这是刻意的,中途换工具集会出问题。
|
|
219
|
-
|
|
220
|
-
行开关是三态。没碰过的行与出厂行逐字节相同,包括 `!!js` 平台条件与出厂 `disabled`;显式开或关才会把那个条件替换成布尔值。平台表达式在宿主端求值,所以页面显示的是这台机器上实际生效的状态,而不是"有没有这个键"。
|
|
221
|
-
|
|
222
|
-
多助手不需要机制上的新能力:`dsh-agent-presets` 本来就会扫描用户预设根目录下的**每一个**目录,而且每次读 roster 都重新扫盘,所以一个刚建的目录在下一次选会话时就可见。每个助手的 `prompt-reader.mjs` / `prompt-tool.mjs` 都是按**自己模块位置**解析 `prompt.md` 的,N 份拷贝等于 N 套互不干扰的提示词。新增用包内模板播种;删除在有 `agentPresets.remove()` 的线上交给平台(它会拒绝删出厂 preset,并再确认目录确实在可写根目录下),在 `0.1.7`+ 上由本插件自己注销注册表项并删目录。
|
|
223
|
-
|
|
224
|
-
## 版本
|
|
225
|
-
|
|
226
|
-
**支持三条线:最新正式线(`0.2.0-rc.2`,npm 的 `latest` 与 `next` 自 2026-09-29 起都指向它,也是桌面端
|
|
227
|
-
所在的那条线)、最新预览线(`0.2.1-alpha.1`,npm 的 `alpha` 指向它)与上一个正式版(`0.1.7-rc.2`,
|
|
228
|
-
仍在声明范围内,现役安装大多在它上面)** —— 声明为
|
|
229
|
-
`>=0.1.5-rc.2 <0.2.0-0 || >=0.1.6-alpha.1 <0.2.0-0 || >=0.1.7-alpha.1 <0.2.0-0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0`。
|
|
230
|
-
官方一键安装读的是 `peerDependencies`,并且**预发布版参与比较**(`dsh-app-boot` 里的 `semver.satisfies(version, range, { includePrerelease: true })`)。因此当前稳定线 `0.2.0-rc.2` 与预览线 `0.2.1-alpha.1` 都能装上。范围里仍点名预发布版本,是因为 npm / pnpm 的默认比较更严,插件市场走那套语义时也不会把预览线拒掉。CI 对这三条线各装一次并跑完全部测试。渲染闸门只跑 `0.2.0-rc.2`,壳的界面改动先落在这条线上。更早的 `0.1.5` / `0.1.6` 仍在 peer 范围内,不再单独占一条 CI。
|
|
231
|
-
**官方桌面端(DeepSeek Harness Desktop)也在覆盖范围内**:它与 dsh 同版本号,当前即为 `0.2.0-rc.2`,
|
|
232
|
-
正是这条矩阵钉住的组合;在应用内(侧栏 → Plugins)安装即可,CLI 那条路 dsh 自己会拒。
|
|
233
|
-
`0.2.0-rc.2` 实测(2026-09-30,干净的一次性 `DSH_HOME`):`dsh plugin --profile web add dsh-custom-mode`
|
|
234
|
-
640ms 解析成功、组合树里有本插件的行、启动时五个预设文件全部播种、声明式注册表同步出助手,
|
|
235
|
-
且 `agentPresets` 能力面不变(`list, register, inventory, select, document`)。
|
|
236
|
-
|
|
237
|
-
包版本走**自己的线** —— `1.0.0`、`1.0.1` …… 它不镜像 DSH 的版本号。本插件支持哪些 dsh,由
|
|
238
|
-
根 `package.json` 的 `engines.dsh` 与 `@deepseek-ai/dsh` peer 范围声明,并由
|
|
239
|
-
`tools/verify-version-consistency.mjs`(CI 里执行)断言"CI 实际安装并测试的 dsh 版本落在这些范围内"。
|
|
240
|
-
|
|
241
|
-
拆开有两个原因。一是目录与市场要求裸 `x.y.z` 才自动安装 —— 有的会解析 npm `latest` 并拒绝任何带
|
|
242
|
-
预发布标签的版本;二是版本号字符串本来就不是一个可校验的声明,声明式的范围才是,而且它才是官方改动时
|
|
243
|
-
会过期的那一个。实际决定兼容性的仍然是下面这些 API 是否还在 —— 那些范围就是为它们写的。
|
|
244
|
-
|
|
245
|
-
<details>
|
|
246
|
-
<summary>耦合点清单(升级 dsh 时逐个核对)</summary>
|
|
247
|
-
|
|
248
|
-
| 依赖 | 变化后的后果 |
|
|
249
|
-
| --- | --- |
|
|
250
|
-
| `ctx.systemPrompt.section()` 且 `text` 支持**函数** | 提示词不再热更新 —— 整个项目的立足点 |
|
|
251
|
-
| `agentPresets` 依据组成文件的 `mtimeMs`+`size` 重挂载 | 开关要重启进程才生效 |
|
|
252
|
-
| `ctx.tools.register()` | 失去 `custom_prompt` 工具 |
|
|
253
|
-
| `ctx.connection.fetch.register({ path, methods, requestBody, fetch })` | 设置页 404 —— 什么都没注册 |
|
|
254
|
-
| `kind: 'prefix'` 同时匹配 `path` 与 `path/…` | 只有列表能打开,`/state`、`/create`、`/delete` 全部 404 |
|
|
255
|
-
| `agentPresets.list()` 行里有 `id` / `trust` / `path`,`preset.yml` 提供 `name` / `description` | 助手列表为空或认不出助手 |
|
|
256
|
-
| `agentPresets.remove(id)`(仅旧线),且拒绝 `trust: 'system'` | 0.1.7+ 的删除不再需要它 —— 声明式后端自己注销注册表项并删目录 |
|
|
257
|
-
| `ctx.connection.requestRejection(req)` | 设置页失败关闭(503),不再提供服务 |
|
|
258
|
-
| `ctx.inject(deps, cb)`(作用域化等待) | 在没有 web 服务器的 profile 里,整行会停在 `pending` |
|
|
259
|
-
| `dsh.client` + `exports["./client"]`,且客户端 bundle id 等于包名 | 浏览器半不会被发现 |
|
|
260
|
-
| `settings.section` 插槽(`id` / `order` / `label`) | 设置项位置与标签 |
|
|
261
|
-
| **`settings.section` 不再提供 `locale:`**(0.1.6-alpha.2 起) | 壳不会递进绑定到本命名空间的 `t`;页面自带词典兜底,见 ARCHITECTURE §15 |
|
|
262
|
-
| `preset.yml` 的 `order` 参与 roster 排序 | 「上移 / 下移」不生效 |
|
|
263
|
-
| `ctx.locale.register/bind` | 回退中文 |
|
|
264
|
-
| **出厂组成从哪来** —— 0.1.7+ 是 `agentPresets.readDocument(<mode>).content`,更早是 `@deepseek-ai/dsh-agent-presets` 的文件 | 基础模式与插件开关变为只读(提示词仍可保存),见 `base-composition.mjs` |
|
|
265
|
-
| 出厂布局 `<presets>/<id>/agent.cordis.yml` 与行的文本形状 | 基础模式切换失效 |
|
|
266
|
-
| `!!js` 平台表达式 | 平台行显示错误状态 |
|
|
267
|
-
|
|
268
|
-
</details>
|
|
55
|
+
单元套件在 WSL2 Ubuntu 26.04 下也通过了(只有 Node,没有 dsh 进程,没有浏览器)。这不是 Linux 桌面的结果。
|
|
269
56
|
|
|
270
57
|
## 文档
|
|
271
58
|
|
|
272
|
-
- [
|
|
273
|
-
- [
|
|
274
|
-
- [
|
|
275
|
-
- [
|
|
276
|
-
- [
|
|
277
|
-
- [`CHANGELOG.md`](CHANGELOG.zh.md) · [`SECURITY.md`](SECURITY.zh.md) · [`CONTRIBUTING.zh.md`](CONTRIBUTING.zh.md)
|
|
59
|
+
- [docs/TROUBLESHOOTING.zh.md](docs/TROUBLESHOOTING.zh.md) — 装到旧版、基础模式不可用、升级停在半截
|
|
60
|
+
- [docs/ARCHITECTURE.zh.md](docs/ARCHITECTURE.zh.md) — 提示词在哪被读,依赖宿主的哪些调用
|
|
61
|
+
- [docs/PUBLISHING.zh.md](docs/PUBLISHING.zh.md) — tag 与发布
|
|
62
|
+
- [CONTRIBUTING.zh.md](CONTRIBUTING.zh.md) — 给人看
|
|
63
|
+
- [AGENTS.md](AGENTS.md) — 给 agent 看
|
|
278
64
|
|
|
279
|
-
##
|
|
280
|
-
|
|
281
|
-
```sh
|
|
282
|
-
node test/run.mjs # 15 个套件;自己解析出厂 preset 目录(0.1.7+ 从宿主声明派生)
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
改 `client.js` 会被 `@deepseek-ai/dsh-client-hmr` 在约 1 秒后热替换;改宿主半(`index.mjs`、`composition.mjs`、`meta.mjs`、`paths.mjs`)需要重启。每个套件在防什么见 [`test/README.md`](test/README.zh.md),改行为之前先读 [`CONTRIBUTING.zh.md`](CONTRIBUTING.zh.md)。
|
|
286
|
-
|
|
287
|
-
## 如果它有用
|
|
288
|
-
|
|
289
|
-
在 GitHub 上点个 ⭐,是让一个插件在几千个条目的目录里被看见的唯一办法 —— 它不花你什么,却正是这个项目
|
|
290
|
-
还在被维护的理由。如果它在你的 dsh 线上**不好用**,带上 `dsh --version` 提个 issue:那是最快的修法,
|
|
291
|
-
上面那张兼容表就是上一次这么来的。
|
|
292
|
-
|
|
293
|
-
## License
|
|
65
|
+
## 许可证
|
|
294
66
|
|
|
295
67
|
MIT
|
|
296
|
-
|
|
297
|
-
## 更新
|
|
298
|
-
|
|
299
|
-
插件装在 profile 的 `node_modules` 里,安装由平台负责,所以"更新"就是**再装一次** —— 你的数据不会被碰:
|
|
300
|
-
|
|
301
|
-
```sh
|
|
302
|
-
# 钉版本的写法:要哪版就是哪版
|
|
303
|
-
dsh plugin --profile web add dsh-custom-mode@2.1.0
|
|
304
|
-
# 然后重启为该 profile 提供服务的 DSH 进程
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
**不要按裸名安装,也不要用 `@latest`。** pnpm 有发布冷却期(`minimumReleaseAge`,默认 24 小时)。
|
|
308
|
-
`dsh plugin add dsh-custom-mode` 会解析成**超过 24 小时的最新版**。实测:npm 上 `latest` 已是发布 6 分钟的 1.12.2 时,`@latest` 装成了 1.11.6。请钉精确版本。
|
|
309
|
-
|
|
310
|
-
每次钉精确版本,pnpm 都会在 profile 的 `pnpm-workspace.yaml` 里追加一条 `minimumReleaseAgeExclude`。pnpm 11.7.0 只认第一条命中包名的记录([pnpm#12463](https://github.com/pnpm/pnpm/issues/12463))。这个包只留一条 `dsh-custom-mode`,不要留一串版本号。本插件不改这个文件。若安装报 `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`,把列表收成那一条再装一次:`node_modules` 里可能已经是新版本,而 `package.json` 仍写着旧版本。
|
|
311
|
-
|
|
312
|
-
**怎样算升级成功**:重启 dsh,再看本设置页底部的版本号。
|
|
313
|
-
|
|
314
|
-
**更新不会碰的东西**:`$DSH_HOME/.agent-presets/<你的助手>/` —— `prompt.md`、`preset.yml` 与你逐行拨过的开关都属于你。
|
|
315
|
-
播种只补**缺失**的文件,你写过的提示词永远不会被覆盖。
|
|
316
|
-
|
|
317
|
-
**如果基础模式与插件开关变灰、并带一行提示**:这条 dsh 线没有向本插件交出出厂组成(解析器依次试过宿主的
|
|
318
|
-
`readDocument()`、旧线的 presets 包、打包的 `dsh-web-app` patch,宿主日志里会写清每一次尝试)。系统提示词
|
|
319
|
-
仍可单独保存,模式本身不受影响。0.1.7 上这在 1.9.13 之前是一个硬 500。
|
|
320
|
-
|
|
321
|
-
**如果更新后某个模式不再出现在选择器里**:老版本创建的助手会保留它自己的组成文件;如果那份文件启用了一行本机
|
|
322
|
-
这条 dsh 线不提供的插件,平台会把整个预设判为 broken 并从选择器里静默丢弃(设置页照常能开)。打开设置页:
|
|
323
|
-
它会明确告诉你,并提供**「按本线修复」** —— 只关掉那几行,其它选择一字不动。
|
package/client.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Browser half: 「自定义模式」settings page — the assistant manager.
|
|
3
3
|
*
|
|
4
4
|
* Blocks:
|
|
5
|
-
* 0. 助手 —
|
|
6
|
-
* 1.
|
|
7
|
-
* 2.
|
|
8
|
-
* 3.
|
|
9
|
-
* 4.
|
|
5
|
+
* 0. 助手 — pick, create, duplicate, delete.
|
|
6
|
+
* 1. 系统提示词 — the prompt, then Save directly under it.
|
|
7
|
+
* 2. 模式名称 — display name and description.
|
|
8
|
+
* 3. 基础模式 — standard / ptc / minimal / cordis / all.
|
|
9
|
+
* 4. 插件开关 — collapsed until the user opens it.
|
|
10
10
|
*
|
|
11
11
|
* Three decisions worth knowing before editing this file:
|
|
12
12
|
*
|
|
@@ -126,11 +126,11 @@ try {
|
|
|
126
126
|
"msg.repaired": "已修复",
|
|
127
127
|
"meta.version": "插件版本",
|
|
128
128
|
"meta.versionHint": "未钉版本时,可能装到较旧的发布。要换版本,按 README 钉版本重装,然后重启。",
|
|
129
|
-
"api.saved": "已保存({name},{mode}
|
|
129
|
+
"api.saved": "已保存({name},{mode})。下一步组装时会重读已保存的提示词。",
|
|
130
130
|
"api.conflict": "磁盘上的提示词已经变了,这次没有写入。先重新读取,再决定要不要覆盖。",
|
|
131
131
|
"api.savedWithExclusiveRows": "已保存({name},{mode})。已关闭不能同时启用的行:{rows}。",
|
|
132
132
|
"api.created": "已创建「{name}」。刷新后,新会话的模式菜单里会出现它。",
|
|
133
|
-
"api.savedPrompt": "已保存系统提示词({name}
|
|
133
|
+
"api.savedPrompt": "已保存系统提示词({name})。下一步组装时会重读这个文件。",
|
|
134
134
|
"api.duplicated": "已从「{from}」复制。两份互不影响。",
|
|
135
135
|
"api.deleted": "已删除「{name}」。正在使用它的会话不受影响。",
|
|
136
136
|
"api.reordered": "顺序已保存。新会话的模式菜单按此排列。",
|
|
@@ -205,7 +205,7 @@ try {
|
|
|
205
205
|
"cap.hint": "关闭的行,这个助手不会使用。",
|
|
206
206
|
"rows.hint": "关闭的行,这个助手不会使用。",
|
|
207
207
|
"prompt.heading": "系统提示词",
|
|
208
|
-
"prompt.hint": "
|
|
208
|
+
"prompt.hint": "保存后,下一步组装模型输入时重读这个文件。",
|
|
209
209
|
"status.enabled": "已启用",
|
|
210
210
|
"status.disabled": "已停用",
|
|
211
211
|
"status.changed": "已改",
|
|
@@ -219,7 +219,7 @@ try {
|
|
|
219
219
|
"msg.unsaved": "有未保存的修改",
|
|
220
220
|
"msg.readFailed": "读取失败",
|
|
221
221
|
"msg.saveFailed": "保存失败",
|
|
222
|
-
"msg.saved": "
|
|
222
|
+
"msg.saved": "已保存。下一步组装时会重读这个文件。",
|
|
223
223
|
"status.detail": "{message}:{detail}",
|
|
224
224
|
"row.persona.label": "身份(系统提示词)",
|
|
225
225
|
"row.persona.note": "关闭后,此提示词不会生效。",
|
|
@@ -360,11 +360,11 @@ try {
|
|
|
360
360
|
"msg.repaired": "Repaired",
|
|
361
361
|
"meta.version": "Plugin version",
|
|
362
362
|
"meta.versionHint": "Without a pinned version, an older release may be installed. To change it, reinstall with the version pin from the README, then restart.",
|
|
363
|
-
"api.saved": "Saved ({name}, {mode}).
|
|
363
|
+
"api.saved": "Saved ({name}, {mode}). The next model step rereads the saved prompt.",
|
|
364
364
|
"api.conflict": "The prompt on disk has changed, so this save was not written. Reload, then decide whether to overwrite.",
|
|
365
365
|
"api.savedWithExclusiveRows": "Saved ({name}, {mode}). Turned off rows that cannot be on together: {rows}.",
|
|
366
366
|
"api.created": "Created {name}. Refresh once, then it appears in the mode menu for a new session.",
|
|
367
|
-
"api.savedPrompt": "System prompt saved ({name}).
|
|
367
|
+
"api.savedPrompt": "System prompt saved ({name}). The next model step rereads this file.",
|
|
368
368
|
"api.duplicated": "Copied from {from}. The two are independent from now on.",
|
|
369
369
|
"api.deleted": "Deleted {name}. Sessions already using it are unchanged.",
|
|
370
370
|
"api.reordered": "Order saved. New sessions list modes in this order.",
|
|
@@ -439,7 +439,7 @@ try {
|
|
|
439
439
|
"cap.hint": "A row that is off is not used by this assistant.",
|
|
440
440
|
"rows.hint": "A row that is off is not used by this assistant.",
|
|
441
441
|
"prompt.heading": "System prompt",
|
|
442
|
-
"prompt.hint": "After you save, the next model step
|
|
442
|
+
"prompt.hint": "After you save, the next model step rereads this file.",
|
|
443
443
|
"status.enabled": "Enabled",
|
|
444
444
|
"status.disabled": "Disabled",
|
|
445
445
|
"status.changed": "changed",
|
|
@@ -453,7 +453,7 @@ try {
|
|
|
453
453
|
"msg.unsaved": "Unsaved changes",
|
|
454
454
|
"msg.readFailed": "Load failed",
|
|
455
455
|
"msg.saveFailed": "Save failed",
|
|
456
|
-
"msg.saved": "Saved.
|
|
456
|
+
"msg.saved": "Saved. The next model step rereads this file.",
|
|
457
457
|
"status.detail": "{message}: {detail}",
|
|
458
458
|
"row.persona.label": "Identity (system prompt)",
|
|
459
459
|
"row.persona.note": "Off: this prompt has no effect.",
|
|
@@ -2252,7 +2252,6 @@ try {
|
|
|
2252
2252
|
),
|
|
2253
2253
|
),
|
|
2254
2254
|
...(editorReady ? editorSections.filter((section) => section.key === "prompt") : []),
|
|
2255
|
-
...(editorReady ? editorSections.filter((section) => section.key === "name") : []),
|
|
2256
2255
|
react.createElement(
|
|
2257
2256
|
"div",
|
|
2258
2257
|
{ className: "cpfe-bar" },
|
|
@@ -2284,6 +2283,7 @@ try {
|
|
|
2284
2283
|
),
|
|
2285
2284
|
react.createElement("span", { className: statusClass }, shown),
|
|
2286
2285
|
),
|
|
2286
|
+
...(editorReady ? editorSections.filter((section) => section.key === "name") : []),
|
|
2287
2287
|
editorReady
|
|
2288
2288
|
? react.createElement(
|
|
2289
2289
|
"p",
|
package/composition.mjs
CHANGED
|
@@ -66,14 +66,14 @@ export {
|
|
|
66
66
|
* it never asks the host for the user's own preset.
|
|
67
67
|
*/
|
|
68
68
|
export const BASE_MODES = [
|
|
69
|
-
{ id: 'standard', label: '标准模式', note: '
|
|
70
|
-
{ id: 'ptc', label: 'PTC 模式', note: '
|
|
71
|
-
{ id: 'minimal', label: '极简模式', note: '只有 Shell
|
|
72
|
-
{ id: 'cordis', label: '
|
|
69
|
+
{ id: 'standard', label: '标准模式', note: '出厂的完整工具集。' },
|
|
70
|
+
{ id: 'ptc', label: 'PTC 模式', note: '标准模式,另开 PTC 工具呈现。' },
|
|
71
|
+
{ id: 'minimal', label: '极简模式', note: '只有 Shell 与终端。提示词仍以本页为准。' },
|
|
72
|
+
{ id: 'cordis', label: '创造模式', note: '标准模式,另开 Cordis 运行时工具。' },
|
|
73
73
|
{
|
|
74
74
|
id: UNION_MODE_ID,
|
|
75
|
-
label: '
|
|
76
|
-
note: '
|
|
75
|
+
label: '全部出厂行',
|
|
76
|
+
note: '四套官方预设的行合在一处,均可开关。',
|
|
77
77
|
},
|
|
78
78
|
]
|
|
79
79
|
|
package/defaults.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fill `agent-presets.default` only when the user has not set it.
|
|
3
|
+
*
|
|
4
|
+
* The host hard-codes `standard` in the profile composition. The same key in
|
|
5
|
+
* `$DSH_HOME/settings.yaml` is the runtime override. Writing it on every boot
|
|
6
|
+
* would undo a user who chose Standard on purpose, so an existing `default`
|
|
7
|
+
* is left untouched — including `default: standard`.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs'
|
|
10
|
+
import { join } from 'node:path'
|
|
11
|
+
import { writeAtomic } from './atomic.mjs'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} home - `DSH_HOME`.
|
|
15
|
+
* @param {string} presetId - assistant directory id, normally `custom`.
|
|
16
|
+
* @returns {{ wrote: boolean, reason: string }}
|
|
17
|
+
*/
|
|
18
|
+
export function ensureUnsetDefaultPreset(home, presetId) {
|
|
19
|
+
if (typeof home !== 'string' || home === '' || typeof presetId !== 'string' || !/^[a-z0-9-]+$/.test(presetId)) {
|
|
20
|
+
return { wrote: false, reason: 'bad-args' }
|
|
21
|
+
}
|
|
22
|
+
if (!existsSync(join(home, '.agent-presets', presetId, 'prompt.md'))) {
|
|
23
|
+
return { wrote: false, reason: 'no-preset' }
|
|
24
|
+
}
|
|
25
|
+
const file = join(home, 'settings.yaml')
|
|
26
|
+
if (!existsSync(file)) {
|
|
27
|
+
mkdirSync(home, { recursive: true })
|
|
28
|
+
writeAtomic(file, 'agent-presets:\n default: ' + presetId + '\n')
|
|
29
|
+
return { wrote: true, reason: 'created' }
|
|
30
|
+
}
|
|
31
|
+
const text = readFileSync(file, 'utf8')
|
|
32
|
+
if (text.includes('\0')) return { wrote: false, reason: 'binary' }
|
|
33
|
+
const lines = text.split('\n')
|
|
34
|
+
let section = -1
|
|
35
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
36
|
+
const line = lines[i]
|
|
37
|
+
if (line.trim() === '' || /^\s*#/.test(line)) continue
|
|
38
|
+
if (/^agent-presets\s*:/.test(line)) {
|
|
39
|
+
if (/default\s*:/.test(line)) return { wrote: false, reason: 'inline' }
|
|
40
|
+
section = i
|
|
41
|
+
break
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (section === -1) {
|
|
45
|
+
const suffix = (text.endsWith('\n') || text === '' ? '' : '\n') + 'agent-presets:\n default: ' + presetId + '\n'
|
|
46
|
+
writeAtomic(file, text + suffix)
|
|
47
|
+
return { wrote: true, reason: 'appended' }
|
|
48
|
+
}
|
|
49
|
+
for (let i = section + 1; i < lines.length; i += 1) {
|
|
50
|
+
const line = lines[i]
|
|
51
|
+
if (line.trim() === '' || /^\s*#/.test(line)) continue
|
|
52
|
+
if (/^\S/.test(line)) break
|
|
53
|
+
if (/^\s+default\s*:/.test(line)) return { wrote: false, reason: 'present' }
|
|
54
|
+
}
|
|
55
|
+
lines.splice(section + 1, 0, ' default: ' + presetId)
|
|
56
|
+
const next = lines.join('\n')
|
|
57
|
+
writeAtomic(file, next.endsWith('\n') ? next : next + '\n')
|
|
58
|
+
return { wrote: true, reason: 'inserted' }
|
|
59
|
+
}
|
package/index.mjs
CHANGED
|
@@ -55,7 +55,8 @@ import {
|
|
|
55
55
|
} from './preset-backend/index.mjs'
|
|
56
56
|
import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
57
57
|
import { dirname, join } from 'node:path'
|
|
58
|
-
import { PROMPT_PATH, COMPOSITION_PATH, ROUTE_PATH, PRESET_DIR } from './paths.mjs'
|
|
58
|
+
import { PROMPT_PATH, COMPOSITION_PATH, ROUTE_PATH, PRESET_DIR, dshHome } from './paths.mjs'
|
|
59
|
+
import { ensureUnsetDefaultPreset } from './defaults.mjs'
|
|
59
60
|
import {
|
|
60
61
|
allowlistOverrides,
|
|
61
62
|
applyRowExclusivity,
|
|
@@ -579,7 +580,7 @@ export function savePromptOnly(directory, { id, mode, prompt, name, description,
|
|
|
579
580
|
code: 'savedPromptOnly',
|
|
580
581
|
// 响应里的名字用**磁盘上的那个**(issue #9):请求省略 name 时不该把 params.name 报成裸目录 id。
|
|
581
582
|
params: { name: (displayName === undefined || displayName === '' ? name : displayName) === '' ? id : (displayName === undefined || displayName === '' ? name : displayName), mode },
|
|
582
|
-
note: '
|
|
583
|
+
note: '已保存系统提示词(本机取不到基础模式的出厂组成,插件开关与基础模式未改动)。下一步组装时会重读这个文件。',
|
|
583
584
|
}
|
|
584
585
|
}
|
|
585
586
|
|
|
@@ -730,7 +731,7 @@ export function saveState(rows, input) {
|
|
|
730
731
|
params: { name: displayName, mode, rows: autoOff.join(', ') },
|
|
731
732
|
note:
|
|
732
733
|
'已保存(' + displayName + ',基础模式 ' + mode + ')。这两套壳注册同名工具、不能同时启用 —— ' +
|
|
733
|
-
'已自动关掉:' + autoOff.join('、') + '
|
|
734
|
+
'已自动关掉:' + autoOff.join('、') + '。下一步组装时会重读已保存的提示词。',
|
|
734
735
|
}
|
|
735
736
|
}
|
|
736
737
|
return {
|
|
@@ -739,7 +740,7 @@ export function saveState(rows, input) {
|
|
|
739
740
|
mode,
|
|
740
741
|
code: 'saved',
|
|
741
742
|
params: { name: displayName, mode },
|
|
742
|
-
note: '已保存(' + displayName + ',基础模式 ' + mode + '
|
|
743
|
+
note: '已保存(' + displayName + ',基础模式 ' + mode + ')。下一步组装时会重读已保存的提示词。',
|
|
743
744
|
}
|
|
744
745
|
}
|
|
745
746
|
|
|
@@ -1124,6 +1125,15 @@ export function apply(ctx) {
|
|
|
1124
1125
|
console.error('custom-mode: 初始化 preset 目录时出现意外错误(已忽略): ' + describe(error))
|
|
1125
1126
|
}
|
|
1126
1127
|
|
|
1128
|
+
try {
|
|
1129
|
+
const presetDefault = ensureUnsetDefaultPreset(dshHome(), LEGACY_ID)
|
|
1130
|
+
if (presetDefault.wrote) {
|
|
1131
|
+
console.log('custom-mode: settings.yaml 里没有 agent-presets.default,已写成 ' + LEGACY_ID + '。已有的值不会改。')
|
|
1132
|
+
}
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
console.error('custom-mode: 没有写 agent-presets.default: ' + describe(error))
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1127
1137
|
try {
|
|
1128
1138
|
ctx.inject(WEB_SERVICES, (scope) => {
|
|
1129
1139
|
// Compatibility guard: this plugin reads host APIs that a future DSH release could
|
package/locales.mjs
CHANGED
|
@@ -87,11 +87,11 @@ export const zh = {
|
|
|
87
87
|
'msg.repaired': '已修复',
|
|
88
88
|
'meta.version': '插件版本',
|
|
89
89
|
'meta.versionHint': '未钉版本时,可能装到较旧的发布。要换版本,按 README 钉版本重装,然后重启。',
|
|
90
|
-
'api.saved': '已保存({name},{mode}
|
|
90
|
+
'api.saved': '已保存({name},{mode})。下一步组装时会重读已保存的提示词。',
|
|
91
91
|
'api.conflict': '磁盘上的提示词已经变了,这次没有写入。先重新读取,再决定要不要覆盖。',
|
|
92
92
|
'api.savedWithExclusiveRows': '已保存({name},{mode})。已关闭不能同时启用的行:{rows}。',
|
|
93
93
|
'api.created': '已创建「{name}」。刷新后,新会话的模式菜单里会出现它。',
|
|
94
|
-
'api.savedPrompt': '已保存系统提示词({name}
|
|
94
|
+
'api.savedPrompt': '已保存系统提示词({name})。下一步组装时会重读这个文件。',
|
|
95
95
|
'api.duplicated': '已从「{from}」复制。两份互不影响。',
|
|
96
96
|
'api.deleted': '已删除「{name}」。正在使用它的会话不受影响。',
|
|
97
97
|
'api.reordered': '顺序已保存。新会话的模式菜单按此排列。',
|
|
@@ -170,7 +170,7 @@ export const zh = {
|
|
|
170
170
|
'rows.hint': '关闭的行,这个助手不会使用。',
|
|
171
171
|
|
|
172
172
|
'prompt.heading': '系统提示词',
|
|
173
|
-
'prompt.hint': '
|
|
173
|
+
'prompt.hint': '保存后,下一步组装模型输入时重读这个文件。',
|
|
174
174
|
|
|
175
175
|
'status.enabled': '已启用',
|
|
176
176
|
'status.disabled': '已停用',
|
|
@@ -187,7 +187,7 @@ export const zh = {
|
|
|
187
187
|
'msg.unsaved': '有未保存的修改',
|
|
188
188
|
'msg.readFailed': '读取失败',
|
|
189
189
|
'msg.saveFailed': '保存失败',
|
|
190
|
-
'msg.saved': '
|
|
190
|
+
'msg.saved': '已保存。下一步组装时会重读这个文件。',
|
|
191
191
|
// 把「一句已翻译的话 + 一个底层细节」拼起来时,中间那个标点也必须**按语言**走 ——
|
|
192
192
|
// 硬编码全角冒号会让英文界面在出错那一刻出现中文标点(issue #7)。
|
|
193
193
|
'status.detail': '{message}:{detail}',
|
|
@@ -343,11 +343,11 @@ export const en = {
|
|
|
343
343
|
'msg.repaired': 'Repaired',
|
|
344
344
|
'meta.version': 'Plugin version',
|
|
345
345
|
'meta.versionHint': 'Without a pinned version, an older release may be installed. To change it, reinstall with the version pin from the README, then restart.',
|
|
346
|
-
'api.saved': 'Saved ({name}, {mode}).
|
|
346
|
+
'api.saved': 'Saved ({name}, {mode}). The next model step rereads the saved prompt.',
|
|
347
347
|
'api.conflict': 'The prompt on disk has changed, so this save was not written. Reload, then decide whether to overwrite.',
|
|
348
348
|
'api.savedWithExclusiveRows': 'Saved ({name}, {mode}). Turned off rows that cannot be on together: {rows}.',
|
|
349
349
|
'api.created': 'Created {name}. Refresh once, then it appears in the mode menu for a new session.',
|
|
350
|
-
'api.savedPrompt': 'System prompt saved ({name}).
|
|
350
|
+
'api.savedPrompt': 'System prompt saved ({name}). The next model step rereads this file.',
|
|
351
351
|
'api.duplicated': 'Copied from {from}. The two are independent from now on.',
|
|
352
352
|
'api.deleted': 'Deleted {name}. Sessions already using it are unchanged.',
|
|
353
353
|
'api.reordered': 'Order saved. New sessions list modes in this order.',
|
|
@@ -426,7 +426,7 @@ export const en = {
|
|
|
426
426
|
'rows.hint': 'A row that is off is not used by this assistant.',
|
|
427
427
|
|
|
428
428
|
'prompt.heading': 'System prompt',
|
|
429
|
-
'prompt.hint': 'After you save, the next model step
|
|
429
|
+
'prompt.hint': 'After you save, the next model step rereads this file.',
|
|
430
430
|
|
|
431
431
|
'status.enabled': 'Enabled',
|
|
432
432
|
'status.disabled': 'Disabled',
|
|
@@ -443,7 +443,7 @@ export const en = {
|
|
|
443
443
|
'msg.unsaved': 'Unsaved changes',
|
|
444
444
|
'msg.readFailed': 'Load failed',
|
|
445
445
|
'msg.saveFailed': 'Save failed',
|
|
446
|
-
'msg.saved': 'Saved.
|
|
446
|
+
'msg.saved': 'Saved. The next model step rereads this file.',
|
|
447
447
|
'status.detail': '{message}: {detail}',
|
|
448
448
|
|
|
449
449
|
// ── row labels ────────────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-custom-mode",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Edit a DeepSeek Harness (dsh) mode's system prompt, base mode, and plugin switches.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"author": "bowluna <ai@bowluna.com>",
|
|
7
8
|
"main": "./index.mjs",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": "./index.mjs",
|
|
@@ -23,31 +24,11 @@
|
|
|
23
24
|
"deepseek-harness",
|
|
24
25
|
"deepseek",
|
|
25
26
|
"dsh-plugin",
|
|
26
|
-
"cordis",
|
|
27
27
|
"plugin",
|
|
28
28
|
"agent-preset",
|
|
29
|
-
"agent-mode",
|
|
30
29
|
"custom-mode",
|
|
31
|
-
"multi-mode",
|
|
32
|
-
"assistant",
|
|
33
30
|
"system-prompt",
|
|
34
|
-
"
|
|
35
|
-
"prompt-editor",
|
|
36
|
-
"prompt-engineering",
|
|
37
|
-
"persona",
|
|
38
|
-
"multi-agent",
|
|
39
|
-
"roleplay",
|
|
40
|
-
"chat",
|
|
41
|
-
"settings-page",
|
|
42
|
-
"自定义模式",
|
|
43
|
-
"系统提示词",
|
|
44
|
-
"提示词编辑",
|
|
45
|
-
"多助手",
|
|
46
|
-
"角色扮演",
|
|
47
|
-
"deepseek-desktop",
|
|
48
|
-
"agent-preset",
|
|
49
|
-
"persona-editor",
|
|
50
|
-
"dshpreset"
|
|
31
|
+
"prompt-editor"
|
|
51
32
|
],
|
|
52
33
|
"dsh": {
|
|
53
34
|
"bundle": {
|
|
@@ -69,6 +50,7 @@
|
|
|
69
50
|
"paths.mjs",
|
|
70
51
|
"locales.mjs",
|
|
71
52
|
"journal.mjs",
|
|
53
|
+
"defaults.mjs",
|
|
72
54
|
"cordis.patch.yml",
|
|
73
55
|
"LICENSE",
|
|
74
56
|
"postures.mjs",
|
|
@@ -78,7 +60,14 @@
|
|
|
78
60
|
"scripts": {
|
|
79
61
|
"test": "node test/run.mjs",
|
|
80
62
|
"verify-translation-pairing": "node tools/verify-translation-pairing.mjs",
|
|
81
|
-
"verify-doc-numbers": "node tools/verify-doc-numbers.mjs"
|
|
63
|
+
"verify-doc-numbers": "node tools/verify-doc-numbers.mjs",
|
|
64
|
+
"verify-version-consistency": "node tools/verify-version-consistency.mjs",
|
|
65
|
+
"verify-browser-literals": "node tools/verify-browser-literals.mjs",
|
|
66
|
+
"boot-check": "node tools/boot-check.mjs",
|
|
67
|
+
"union-mount-check": "node tools/union-mount-check.mjs",
|
|
68
|
+
"session-trace": "node tools/session-trace.mjs",
|
|
69
|
+
"browser-verify": "node tools/browser-verify.mjs",
|
|
70
|
+
"upgrade-preflight": "node tools/upgrade-preflight.mjs"
|
|
82
71
|
},
|
|
83
72
|
"peerDependencies": {
|
|
84
73
|
"@deepseek-ai/dsh": ">=0.1.5-rc.2 <0.2.0-0 || >=0.1.6-alpha.1 <0.2.0-0 || >=0.1.7-alpha.1 <0.2.0-0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0"
|