dsh-baize-rules 0.1.1 → 0.1.3
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.md +120 -110
- package/README.zh.md +238 -0
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -3,45 +3,45 @@
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
`dsh-baize-rules` (Baize) is a [dsh](https://www.npmjs.com/package/@deepseek-ai/dsh) plugin that injects **user-set, durable "must-do / must-not" requirements** — plain-text rules — into the model at conversation start as a *sourced* `user/message`.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The name comes from **Baize (白泽)** — a mythical beast said to "understand the nature of all creatures, know the names of all things, and comprehend the principles of everything." It carries the behavioral baseline that the user sets for the model.
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
10
|
+
- Rules are **plain text** with no `must`/`mustNot` markers — whether something is "must-do" or "must-not" is expressed by the language of the body itself (e.g. `Write comments in Chinese.` = must, `Do not delete the tests.` = must-not).
|
|
11
|
+
- Injection happens at the **start of a conversation**: the currently active rules are injected into the model request as a **persistent** `user/message`, wrapped in a `<system-reminder>` frame, with `source.kind='plugin'` and `plugin='baize-rules'`.
|
|
12
|
+
- **No rules → no injection**; if the byte budget shrinks such that all rules are cut, it returns `undefined` and never injects an empty reminder shell.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Features
|
|
17
17
|
|
|
18
|
-
|
|
|
18
|
+
| Feature | Description |
|
|
19
19
|
|---|---|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
20
|
+
| **Three scopes** | `global` (all sessions) / `session` (current session) / `project` (per session working directory, **experimental**) |
|
|
21
|
+
| **Persistence** | Everything is written to `$DSH_HOME` (default `~/.dsh`); survives across sessions and restarts |
|
|
22
|
+
| **Specificity wins** | Render order `project > session > global`; when the byte budget is tight, the more specific rules are preserved first |
|
|
23
|
+
| **Deduplication** | Suppresses duplicate injection by SHA-1 digest of the rendered text; optional `injectAtEveryStep` forces a refresh on every step |
|
|
24
|
+
| **Escape protection** | Literal `</system-reminder>` in rule bodies is escaped so user text can't close the plugin's frame |
|
|
25
|
+
| **Command + API share the same source** | The `/baize-rules` command and the front-end panel use the same store/core, so there is always a single source of truth |
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Installation
|
|
30
30
|
|
|
31
|
-
> dsh
|
|
31
|
+
> dsh plugins are distributed from npm and installed into a profile via `dsh plugin`.
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
#
|
|
35
|
-
dsh plugin --profile web add dsh-baize-rules@0.1.
|
|
36
|
-
pm2 restart dsh # dsh
|
|
34
|
+
# Install from npm into the web profile (use the actual published version)
|
|
35
|
+
dsh plugin --profile web add dsh-baize-rules@0.1.3
|
|
36
|
+
pm2 restart dsh # Reload when dsh is managed by pm2
|
|
37
37
|
dsh --profile web
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Peer dependencies (`@deepseek-ai/*`, `react`, etc.) are provided by the dsh profile; if any are missing, pnpm resolves them against `peerDependencies` in the profile directory.
|
|
41
41
|
|
|
42
|
-
###
|
|
42
|
+
### Local development (link)
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
If you haven't published yet, or want to pick up source changes live, use this directory as a link dependency:
|
|
45
45
|
|
|
46
46
|
```jsonc
|
|
47
47
|
// /home/abc/.dsh/profiles/web/package.json
|
|
@@ -50,77 +50,77 @@ dsh --profile web
|
|
|
50
50
|
}
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Then run `pnpm install` in the profile directory and add `dsh-baize-rules` to `dsh.profile.bundles`.
|
|
54
54
|
|
|
55
55
|
---
|
|
56
56
|
|
|
57
|
-
##
|
|
57
|
+
## Quick Start
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
/baize-rules #
|
|
61
|
-
/baize-rules add
|
|
62
|
-
/baize-rules global add
|
|
63
|
-
/baize-rules list #
|
|
64
|
-
/baize-rules edit <id>
|
|
65
|
-
/baize-rules disable <id> #
|
|
66
|
-
/baize-rules enable <id> #
|
|
67
|
-
/baize-rules scope global #
|
|
68
|
-
/baize-rules clear session #
|
|
69
|
-
/baize-rules export #
|
|
60
|
+
/baize-rules # Same as /baize-rules list: show the currently active rules
|
|
61
|
+
/baize-rules add Write comments in Chinese. # Add to the default scope (usually session)
|
|
62
|
+
/baize-rules global add Don't delete or rewrite existing tests. # Explicitly add to global
|
|
63
|
+
/baize-rules list # Show global + session (with abbreviated id / disabled markers)
|
|
64
|
+
/baize-rules edit <id> Use pnpm to build only. # Edit a rule's text
|
|
65
|
+
/baize-rules disable <id> # Disable one (keep it, don't delete)
|
|
66
|
+
/baize-rules enable <id> # Re-enable
|
|
67
|
+
/baize-rules scope global # Subsequent commands default to global
|
|
68
|
+
/baize-rules clear session # Clear the current session's rules
|
|
69
|
+
/baize-rules export # Export all rules as JSON
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
---
|
|
73
73
|
|
|
74
|
-
##
|
|
74
|
+
## Commands
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
All subcommands live under **`/baize-rules`**; no argument is equivalent to `list`.
|
|
77
77
|
|
|
78
78
|
```
|
|
79
79
|
/baize-rules [list|add <text>|remove <id>|edit <id> <text>|enable|disable <id>|scope <global|session|project>|clear <scope>|export]
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
|
|
|
82
|
+
| Subcommand | Syntax | Purpose |
|
|
83
83
|
|---|---|---|
|
|
84
|
-
| **list** | `/baize-rules list` |
|
|
85
|
-
| **add** | `/baize-rules add <text>` |
|
|
86
|
-
| **remove** | `/baize-rules remove <id>` |
|
|
87
|
-
| **edit** | `/baize-rules edit <id> <text>` |
|
|
88
|
-
| **enable** | `/baize-rules enable <id>` |
|
|
89
|
-
| **disable** | `/baize-rules disable <id>` |
|
|
90
|
-
| **scope** | `/baize-rules scope <global\|session\|project>` |
|
|
91
|
-
| **clear** | `/baize-rules clear <global\|session\|project>` |
|
|
92
|
-
| **export** | `/baize-rules export` |
|
|
84
|
+
| **list** | `/baize-rules list` | List the merged active rules (`Project`/`Global`/`Session` sections; shows `No active rules.` when empty) |
|
|
85
|
+
| **add** | `/baize-rules add <text>` | Append a rule to the target scope (default `scope`); the text *is* the rule |
|
|
86
|
+
| **remove** | `/baize-rules remove <id>` | Delete a rule by its **full id** |
|
|
87
|
+
| **edit** | `/baize-rules edit <id> <text>` | Change a rule's text |
|
|
88
|
+
| **enable** | `/baize-rules enable <id>` | Enable a disabled rule |
|
|
89
|
+
| **disable** | `/baize-rules disable <id>` | Disable a rule (keep but not active) |
|
|
90
|
+
| **scope** | `/baize-rules scope <global\|session\|project>` | Switch the default scope for subsequent commands (persistent for the current process) |
|
|
91
|
+
| **clear** | `/baize-rules clear <global\|session\|project>` | Clear all rules in a scope |
|
|
92
|
+
| **export** | `/baize-rules export` | Export `{ global, session }` as JSON |
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
**Argument details**
|
|
95
95
|
|
|
96
|
-
- `<text
|
|
97
|
-
- `<id
|
|
98
|
-
|
|
96
|
+
- `<text>`: the rule body, may contain spaces. Whether it's "must-do" or "must-not" is expressed by the body's language; there is no marker.
|
|
97
|
+
- `<id>`: a stable rule id (`crypto.randomUUID`). `list` shows the **first 8 characters** as an abbreviated id for readability;
|
|
98
|
+
when running `remove`/`edit`/`enable`/`disable` please provide the **full id** (you can view it via `list` or `export`).
|
|
99
99
|
|
|
100
|
-
###
|
|
100
|
+
### Scope syntax
|
|
101
101
|
|
|
102
|
-
`add/remove/edit/enable/disable`
|
|
102
|
+
`add/remove/edit/enable/disable` support an **explicit scope**, two equivalent ways:
|
|
103
103
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
104
|
+
- **Prefix**: `/baize-rules global add Write in Chinese.`
|
|
105
|
+
- **Suffix**: `/baize-rules add Write in Chinese. global` (only when the scope is the **last token**)
|
|
106
106
|
|
|
107
|
-
>
|
|
108
|
-
> `scope`/`clear`
|
|
109
|
-
|
|
107
|
+
> Only `add/remove/edit/enable/disable` recognize a trailing scope keyword as a scope modifier;
|
|
108
|
+
> the argument to `scope`/`clear` is itself a scope and won't be swallowed. So a scope word inside the body
|
|
109
|
+
> won't be misparsed (e.g. `/baize-rules add Writeglobal`).
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
When no scope is given, the default set by `/baize-rules scope` is used (initially from `Config.scope`, usually `session`).
|
|
112
112
|
|
|
113
113
|
---
|
|
114
114
|
|
|
115
|
-
##
|
|
115
|
+
## Injection behavior (how the model context changes)
|
|
116
116
|
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
117
|
+
- **Conversation-start baseline**: at the start of a session, `agent/pre-step` (`prepend:true`) inserts the active rules as a `user/message` into the request, framed as `<system-reminder>` with `source.kind='plugin'`, `plugin='baize-rules'`, `form='snapshot'`.
|
|
118
|
+
- **Specificity wins**: `project > session > global`; when the budget is tight the broader `global` rules are trimmed first.
|
|
119
|
+
- **Deduplication**: a SHA-1 digest is computed over the rendered text; unchanged rules aren't re-injected. `injectAtEveryStep:true` forces a refresh on each step.
|
|
120
|
+
- **Escape**: a literal `</system-reminder>` in a body is escaped via `escapeReminder`.
|
|
121
|
+
- **Empty / fully trimmed**: when there are no rules, or the budget cuts all of them, it returns `undefined` (i.e. does not inject that message).
|
|
122
122
|
|
|
123
|
-
###
|
|
123
|
+
### What the model actually sees
|
|
124
124
|
|
|
125
125
|
```markdown
|
|
126
126
|
<system-reminder>
|
|
@@ -128,101 +128,111 @@ The following user requirements apply to every step of this conversation. Obey t
|
|
|
128
128
|
More specific instructions take precedence over broader ones. They do not override system, developer, or direct user instructions.
|
|
129
129
|
|
|
130
130
|
Session requirements (this conversation only):
|
|
131
|
-
-
|
|
131
|
+
- Always test the plugin in isolation before deploying.
|
|
132
132
|
|
|
133
133
|
Global requirements:
|
|
134
|
-
-
|
|
135
|
-
-
|
|
134
|
+
- Write comments in Chinese.
|
|
135
|
+
- Do not delete or rewrite existing tests.
|
|
136
136
|
</system-reminder>
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
---
|
|
140
140
|
|
|
141
|
-
##
|
|
141
|
+
## Configuration (`Config`)
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
On startup the plugin validates `Config` with `@deepseek-ai/schemastery`; an invalid value makes the plugin fail to load.
|
|
144
144
|
|
|
145
|
-
|
|
|
145
|
+
| Config | Default | Description |
|
|
146
146
|
|---|---|---|
|
|
147
|
-
| `scope` |
|
|
148
|
-
| `maxBytes` |
|
|
149
|
-
| `globalRulesPath` | `$DSH_HOME/rules/global.json` |
|
|
150
|
-
| `injectAtEveryStep` | `false` |
|
|
147
|
+
| `scope` | — (required) | Default scope, used when `/baize-rules` doesn't specify one; only `global`/`session` allowed |
|
|
148
|
+
| `maxBytes` | — (required) | Byte cap visible to the model; trimmed with specificity-wins when exceeded |
|
|
149
|
+
| `globalRulesPath` | `$DSH_HOME/rules/global.json` | Override the global rules file path |
|
|
150
|
+
| `injectAtEveryStep` | `false` | Force re-render on every step (debugging); default only patches on change |
|
|
151
151
|
|
|
152
|
-
###
|
|
152
|
+
### Mount metadata (`cordis.patch.yml`)
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
`cordis.patch.yml`
|
|
154
|
+
The published npm package ships `dsh.bundle.patch`, wired up automatically by dsh when you install `dsh-baize-rules@<version>`:
|
|
155
|
+
`cordis.patch.yml` inserts a single plugin line with default `scope: session` and `maxBytes: 8192`. To adjust the default scope / budget, change it there.
|
|
156
156
|
|
|
157
157
|
---
|
|
158
158
|
|
|
159
|
-
##
|
|
159
|
+
## Data location
|
|
160
160
|
|
|
161
|
-
|
|
|
161
|
+
| Scope | Storage | When written | Persistence |
|
|
162
162
|
|---|---|---|---|
|
|
163
|
-
| global | `$DSH_HOME/rules/global.json` |
|
|
164
|
-
| session | `$DSH_HOME/rules/sessions/<sessionId>.json` |
|
|
165
|
-
| project | `$DSH_HOME/rules/projects/<slug>.json
|
|
163
|
+
| global | `$DSH_HOME/rules/global.json` | On any command / API submission | ✅ across restarts |
|
|
164
|
+
| session | `$DSH_HOME/rules/sessions/<sessionId>.json` | Same | ✅ across restarts |
|
|
165
|
+
| project | `$DSH_HOME/rules/projects/<slug>.json` (slug from the session cwd) | Same | ✅ across restarts |
|
|
166
166
|
|
|
167
|
-
> `$DSH_HOME`
|
|
168
|
-
>
|
|
169
|
-
>
|
|
167
|
+
> `$DSH_HOME` is resolved by `@deepseek-ai/dsh-home-paths`, default `~/.dsh`.
|
|
168
|
+
> Reads/writes go through `ctx.fs` (`resolve/stat/readText/writeText`, auto-creating directories on write); missing is tolerated, corrupt files fail loudly.
|
|
169
|
+
> **Note**: `project` rules can be managed via the command and are persisted, but **the current pre-step injection view only includes `global` + `session`**, so `project` rules are not yet part of the model context (reserved/experimental).
|
|
170
170
|
|
|
171
171
|
---
|
|
172
172
|
|
|
173
|
-
##
|
|
173
|
+
## Client panel (optional)
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
The published package also exposes a dsh web client panel (`lib/client.js`; see the `./client` entry in `package.json` `exports`), talking to the same store/core as the command through the host HTTP API `/baize-rules.api`:
|
|
176
176
|
|
|
177
177
|
- `GET /baize-rules.api?sessionId=…&project=…` → `{ global, session, project }`
|
|
178
|
-
- `POST /baize-rules.api
|
|
178
|
+
- `POST /baize-rules.api`, body `{ sessionId, raw, scope }` → `{ ok, text, view }`
|
|
179
179
|
|
|
180
180
|
---
|
|
181
181
|
|
|
182
|
-
##
|
|
182
|
+
## Module structure
|
|
183
183
|
|
|
184
184
|
```
|
|
185
|
-
src/rules.ts
|
|
186
|
-
src/core.ts
|
|
187
|
-
src/store.ts
|
|
188
|
-
src/command.ts
|
|
189
|
-
src/index.ts apply
|
|
190
|
-
src/api.ts Host HTTP API
|
|
191
|
-
src/invariant.ts dsh-invariants
|
|
192
|
-
scripts/dev-render.ts Loop 0
|
|
193
|
-
test/*.spec.ts rules/core/composition
|
|
194
|
-
cordis.patch.yml
|
|
185
|
+
src/rules.ts Pure logic: Rule model + render/<system-reminder>/byte budget(specificity-wins)/digest/escapeReminder
|
|
186
|
+
src/core.ts Pure logic: parseCommand/runCommand/scope resolution/CRUD (zero deps, unit-testable without dsh)
|
|
187
|
+
src/store.ts Pure logic: global/session/project rule file persistence (ctx.fs + dshHomePath)
|
|
188
|
+
src/command.ts Thin dsh adapter: feed view/defaultScope → core, persist nextView/defaultScope
|
|
189
|
+
src/index.ts apply: agent/pre-step injection + /baize-rules command registration + API mount (inject: agents/commands/fs/webServer/sessions)
|
|
190
|
+
src/api.ts Host HTTP API: GET/POST /baize-rules.api (for the front-end panel)
|
|
191
|
+
src/invariant.ts dsh-invariants contract companion (name/inject/apply)
|
|
192
|
+
scripts/dev-render.ts Loop 0 demo
|
|
193
|
+
test/*.spec.ts rules/core/composition tests
|
|
194
|
+
cordis.patch.yml Mount metadata (inserts the baize-rules plugin line + default config)
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
**Public entry points** (see `package.json` `exports`): `.` (index), `./invariant`, `./client`, `./src/*`.
|
|
198
198
|
|
|
199
199
|
---
|
|
200
200
|
|
|
201
|
-
##
|
|
201
|
+
## Development & instant feedback
|
|
202
202
|
|
|
203
203
|
```bash
|
|
204
|
-
pnpm dev:render #
|
|
205
|
-
pnpm test #
|
|
206
|
-
pnpm test:watch #
|
|
204
|
+
pnpm dev:render # Print the <system-reminder> text the model will actually see (supports budget args)
|
|
205
|
+
pnpm test # Run unit + REAL-composition tests
|
|
206
|
+
pnpm test:watch # Re-run on save
|
|
207
207
|
pnpm build # tsc -p tsconfig.build.json → lib/
|
|
208
208
|
pnpm typecheck # npx tsc --noEmit
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
Change the pure functions in `src/rules.ts` (rendering) or `src/core.ts` (command decisions), then re-run `pnpm dev:render` to see the change — the **fastest feedback loop** (sub-second, without touching dsh).
|
|
212
212
|
|
|
213
213
|
---
|
|
214
214
|
|
|
215
|
-
##
|
|
215
|
+
## Publishing
|
|
216
|
+
|
|
217
|
+
Releases are **single-source**: bump the version, push a `v*` tag, and GitHub Actions publishes to npm. **Don't run `npm publish` locally** — doing so alongside a tag would conflict, since a version can't be published twice.
|
|
216
218
|
|
|
217
219
|
```bash
|
|
218
|
-
|
|
219
|
-
|
|
220
|
+
# 1. Bump the version: update `version` in package.json + the install example in both READMEs
|
|
221
|
+
# 2. Verify locally
|
|
222
|
+
pnpm build && pnpm test
|
|
223
|
+
# 3. Commit and push the tag to trigger the CI publish job
|
|
224
|
+
git add -A && git commit -m "release: vX.Y.Z"
|
|
225
|
+
git tag vX.Y.Z && git push origin main --tags
|
|
220
226
|
```
|
|
221
227
|
|
|
222
|
-
|
|
228
|
+
The `publish` job in `.github/workflows/ci.yml` runs on `v*` tags, needs the `test` job to pass, and uses the GitHub `NPM_TOKEN` secret.
|
|
223
229
|
|
|
224
230
|
---
|
|
225
231
|
|
|
226
|
-
##
|
|
232
|
+
## Changelog
|
|
233
|
+
|
|
234
|
+
See [CHANGELOG.md](./CHANGELOG.md).
|
|
235
|
+
|
|
236
|
+
## License
|
|
227
237
|
|
|
228
238
|
[MIT](./LICENSE)
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# dsh-baize-rules
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
> English: *`dsh-baize-rules` (Baize) is a dsh plugin that injects user-set, durable "must-do / must-not" requirements — plain-text rules — into the model at conversation start as a sourced `user/message`.*
|
|
7
|
+
|
|
8
|
+
[dsh](https://www.npmjs.com/package/@deepseek-ai/dsh) 的**会话 / 全局「必须做 / 不能做」要求**插件。名字取自**白泽**——传说中「通万物之情、晓万物之名、知万物之理」的神兽,用它来承载「用户给模型立下的行为基线」。
|
|
9
|
+
|
|
10
|
+
- 规则是**纯文本**,没有 `must`/`mustNot` 标记——「必须做 / 不能做」由正文语言表达(例如 `用中文写注释。`=必须,`不要删除测试。`=禁止)。
|
|
11
|
+
- 注入发生在**会话起点**:把当前生效规则作为一条**持久** `user/message` 注入模型请求,套用 `<system-reminder>` 框架,来源标记为 `source.kind='plugin'`、`plugin='baize-rules'`。
|
|
12
|
+
- **无规则则不注入**;字节预算小到裁光所有规则时返回 `undefined`,绝不注入空壳 reminder。
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 功能特性
|
|
17
|
+
|
|
18
|
+
| 特性 | 说明 |
|
|
19
|
+
|---|---|
|
|
20
|
+
| **三作用域** | `global`(所有会话)/ `session`(当前会话)/ `project`(按会话工作目录,**实验性**) |
|
|
21
|
+
| **持久化** | 全部落盘到 `$DSH_HOME`(默认 `~/.dsh`),跨会话、跨重启 |
|
|
22
|
+
| **具体优先** | 渲染顺序 `project > session > global`;字节预算受压时优先保留更具体的规则 |
|
|
23
|
+
| **去重** | 按渲染文本 SHA-1 digest 抑制重复注入;`injectAtEveryStep` 可选每步强制刷新 |
|
|
24
|
+
| **防逃逸** | 正文里的字面 `</system-reminder>` 会被转义,防止用户文本关闭插件框架 |
|
|
25
|
+
| **命令 + API 同源** | `/baize-rules` 命令与前端面板共用同一套 store/core,改动始终同一真值 |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 安装
|
|
30
|
+
|
|
31
|
+
> dsh 插件从 npm 仓库分发,通过 `dsh plugin` 安装到某个 profile。
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# 从 npm 安装到 web profile(版本以发布后的实际版本为准)
|
|
35
|
+
dsh plugin --profile web add dsh-baize-rules@0.1.3
|
|
36
|
+
pm2 restart dsh # dsh 由 pm2 托管时重载生效
|
|
37
|
+
dsh --profile web
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
安装时依赖的 peer 包(`@deepseek-ai/` 系列、`react` 等)由 dsh profile 提供;若缺少,pnpm 会在 profile 目录里按 `peerDependencies` 解析。
|
|
41
|
+
|
|
42
|
+
### 本地开发联调(link)
|
|
43
|
+
|
|
44
|
+
尚未发布或想改源码即时生效时,用本目录作为 link 依赖:
|
|
45
|
+
|
|
46
|
+
```jsonc
|
|
47
|
+
// /home/abc/.dsh/profiles/web/package.json
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"dsh-baize-rules": "link:/home/abc/work/plugin/dsh-baize-rules"
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
随后在 profile 目录执行 `pnpm install`,并把 `dsh-baize-rules` 加进 `dsh.profile.bundles`。
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 快速开始
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
/baize-rules # 等价于 /baize-rules list,查看当前生效规则
|
|
61
|
+
/baize-rules add 用中文写注释。 # 加到默认作用域(通常是 session)
|
|
62
|
+
/baize-rules global add 不要删除或改写现有测试。 # 明确加到 global
|
|
63
|
+
/baize-rules list # 显示 global + session(含缩略 id / disabled 标注)
|
|
64
|
+
/baize-rules edit <id> 只用 pnpm 构建。 # 修改某条规则文本
|
|
65
|
+
/baize-rules disable <id> # 停用某条(保留不删)
|
|
66
|
+
/baize-rules enable <id> # 重新启用
|
|
67
|
+
/baize-rules scope global # 之后命令默认写到 global
|
|
68
|
+
/baize-rules clear session # 清空当前会话规则
|
|
69
|
+
/baize-rules export # 导出全部规则为 JSON
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 命令
|
|
75
|
+
|
|
76
|
+
所有子命令挂在 **`/baize-rules`** 下;无参数时等价于 `list`。
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
/baize-rules [list|add <text>|remove <id>|edit <id> <text>|enable|disable <id>|scope <global|session|project>|clear <scope>|export]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
| 子命令 | 语法 | 作用 |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| **list** | `/baize-rules list` | 列出合并后的生效规则(`Project`/`Global`/`Session` 节;空时显示 `No active rules.`) |
|
|
85
|
+
| **add** | `/baize-rules add <text>` | 追加一条规则到目标作用域(默认 `scope`);文本即规则 |
|
|
86
|
+
| **remove** | `/baize-rules remove <id>` | 按**完整 id** 删除一条规则 |
|
|
87
|
+
| **edit** | `/baize-rules edit <id> <text>` | 修改某条规则的文本 |
|
|
88
|
+
| **enable** | `/baize-rules enable <id>` | 启用一条被停用的规则 |
|
|
89
|
+
| **disable** | `/baize-rules disable <id>` | 停用一条规则(保留但不生效) |
|
|
90
|
+
| **scope** | `/baize-rules scope <global\|session\|project>` | 切换后续命令的默认作用域(持久到当前进程) |
|
|
91
|
+
| **clear** | `/baize-rules clear <global\|session\|project>` | 清空某作用域的全部规则 |
|
|
92
|
+
| **export** | `/baize-rules export` | 以 JSON 导出 `{ global, session }` |
|
|
93
|
+
|
|
94
|
+
**参数细节**
|
|
95
|
+
|
|
96
|
+
- `<text>`:规则正文,可含空格;是「必须做」还是「不能做」由正文语言表达,无标记。
|
|
97
|
+
- `<id>`:规则的稳定 id(`crypto.randomUUID`)。`list` 显示**前 8 位缩略 id** 便于阅读;
|
|
98
|
+
执行 `remove`/`edit`/`enable`/`disable` 时请提供**完整 id**(可用 `list` 或 `export` 查看完整 id)。
|
|
99
|
+
|
|
100
|
+
### 作用域写法
|
|
101
|
+
|
|
102
|
+
`add/remove/edit/enable/disable` 支持**显式作用域**,两种等价写法:
|
|
103
|
+
|
|
104
|
+
- **前缀**:`/baize-rules global add 用中文。`
|
|
105
|
+
- **后缀**:`/baize-rules add 用中文。 global`(仅当作用域是**最后一个 token** 时)
|
|
106
|
+
|
|
107
|
+
> 只有 `add/remove/edit/enable/disable` 会把**末尾**的作用域关键字识别为作用域修饰;
|
|
108
|
+
> `scope`/`clear` 的参数本身就是作用域,不会被吞。因此正文里含 `global`/`session` 不会被误判
|
|
109
|
+
>(例如 `/baize-rules add 用global写`)。
|
|
110
|
+
|
|
111
|
+
未指定作用域时,用 `/baize-rules scope` 设定的默认值(初始来自配置文件 `Config.scope`,通常 `session`)。
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 注入行为(模型上下文如何被改变)
|
|
116
|
+
|
|
117
|
+
- **会话起点基线**:会话开始时,`agent/pre-step`(`prepend:true`)把生效规则作为一条 `user/message` 插入请求,内容为 `<system-reminder>` 框架,`source.kind='plugin'`、`plugin='baize-rules'`、`form='snapshot'`。
|
|
118
|
+
- **具体优先**:`project > session > global`;预算受限时优先裁剪较宽泛的 `global` 规则。
|
|
119
|
+
- **去重**:对渲染文本算 SHA-1 digest,规则不变则不重复注入;`injectAtEveryStep:true` 时每步强制刷新。
|
|
120
|
+
- **转义**:正文里的 `</system-reminder>` 会被 `escapeReminder` 转义。
|
|
121
|
+
- **空 / 全裁**:无规则、或预算裁光所有规则时返回 `undefined`(即不注入该消息)。
|
|
122
|
+
|
|
123
|
+
### 模型实际看到的形态
|
|
124
|
+
|
|
125
|
+
```markdown
|
|
126
|
+
<system-reminder>
|
|
127
|
+
The following user requirements apply to every step of this conversation. Obey them.
|
|
128
|
+
More specific instructions take precedence over broader ones. They do not override system, developer, or direct user instructions.
|
|
129
|
+
|
|
130
|
+
Session requirements (this conversation only):
|
|
131
|
+
- 插件每次都要隔离测试后才能部署。
|
|
132
|
+
|
|
133
|
+
Global requirements:
|
|
134
|
+
- 用中文写注释。
|
|
135
|
+
- 不要删除或改写现有的测试。
|
|
136
|
+
</system-reminder>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 配置(`Config`)
|
|
142
|
+
|
|
143
|
+
插件启动时用 `@deepseek-ai/schemastery` 校验 `Config`;非法值会令插件加载失败。
|
|
144
|
+
|
|
145
|
+
| 配置 | 默认 | 说明 |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `scope` | —(必填) | 默认作用域,`/baize-rules` 未指定时使用;仅允许 `global`/`session` |
|
|
148
|
+
| `maxBytes` | —(必填) | 模型可见字节上限;超出时按「具体优先」裁剪 |
|
|
149
|
+
| `globalRulesPath` | `$DSH_HOME/rules/global.json` | 覆盖全局规则文件路径 |
|
|
150
|
+
| `injectAtEveryStep` | `false` | 每步强制重渲(调试用);默认为仅变化时打补丁 |
|
|
151
|
+
|
|
152
|
+
### 挂载元数据(`cordis.patch.yml`)
|
|
153
|
+
|
|
154
|
+
发布的 npm 包里携带 `dsh.bundle.patch`,安装 `dsh-baize-rules@<version>` 时由 dsh 自动接入:
|
|
155
|
+
`cordis.patch.yml` 中 `insert` 一行插件,默认 `scope: session`、`maxBytes: 8192`。如需调整默认作用域 / 预算,改这里即可。
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 数据落点
|
|
160
|
+
|
|
161
|
+
| 作用域 | 存储位置 | 何时写 | 持久性 |
|
|
162
|
+
|---|---|---|---|
|
|
163
|
+
| global | `$DSH_HOME/rules/global.json` | 任一命令 / API 提交时 | ✅ 跨重启 |
|
|
164
|
+
| session | `$DSH_HOME/rules/sessions/<sessionId>.json` | 同上 | ✅ 跨重启 |
|
|
165
|
+
| project | `$DSH_HOME/rules/projects/<slug>.json`(slug 来自会话 cwd) | 同上 | ✅ 跨重启 |
|
|
166
|
+
|
|
167
|
+
> `$DSH_HOME` 由 `@deepseek-ai/dsh-home-paths` 解析,默认 `~/.dsh`。
|
|
168
|
+
> 读写走 `ctx.fs`(`resolve/stat/readText/writeText`,写时自动建目录);缺失容忍、损坏文件 failing-loud。
|
|
169
|
+
> **注意**:`project` 规则可通过命令管理并落盘,但**当前 pre-step 注入视图只包含 `global` + `session`**,故 `project` 规则暂未进入模型上下文(预留/实验性)。
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 客户端面板(可选)
|
|
174
|
+
|
|
175
|
+
发布包还暴露一个 dsh web 客户端面板(`lib/client.js`,见 `package.json` 的 `exports` 里的 `./client`),通过宿主 HTTP API `/baize-rules.api` 与命令共用同一套 store/core:
|
|
176
|
+
|
|
177
|
+
- `GET /baize-rules.api?sessionId=…&project=…` → `{ global, session, project }`
|
|
178
|
+
- `POST /baize-rules.api`,body `{ sessionId, raw, scope }` → `{ ok, text, view }`
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 模块结构
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
src/rules.ts 纯逻辑:Rule 模型 + 渲染/<system-reminder>/字节预算(具体优先)/digest/escapeReminder
|
|
186
|
+
src/core.ts 纯逻辑:parseCommand/runCommand/作用域解析/CRUD(零依赖,可脱离 dsh 单测)
|
|
187
|
+
src/store.ts 纯逻辑:global/session/project 规则文件持久化(ctx.fs + dshHomePath)
|
|
188
|
+
src/command.ts 薄 dsh 适配:喂 view/defaultScope → core,持久化 nextView/defaultScope
|
|
189
|
+
src/index.ts apply:agent/pre-step 注入 + /baize-rules 命令注册 + API 挂载(inject: agents/commands/fs/webServer/sessions)
|
|
190
|
+
src/api.ts Host HTTP API:GET/POST /baize-rules.api(供前端面板)
|
|
191
|
+
src/invariant.ts dsh-invariants 契约 companion(name/inject/apply)
|
|
192
|
+
scripts/dev-render.ts Loop 0 演示
|
|
193
|
+
test/*.spec.ts rules/core/composition 测试
|
|
194
|
+
cordis.patch.yml 挂载元数据(insert baize-rules 插件行 + 默认配置)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**公共入口**(见 `package.json` 的 `exports`):`.`(index)、`./invariant`、`./client`、`./src/*`。
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 开发与即时反馈
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
pnpm dev:render # 打印模型实际会看到的 <system-reminder> 文案(支持预算参数)
|
|
205
|
+
pnpm test # 跑单元 + REAL-composition 测试
|
|
206
|
+
pnpm test:watch # 保存即重跑
|
|
207
|
+
pnpm build # tsc -p tsconfig.build.json → lib/
|
|
208
|
+
pnpm typecheck # npx tsc --noEmit
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
改 `src/rules.ts`(渲染)或 `src/core.ts`(命令决策)里的纯函数,重跑 `pnpm dev:render` 即可看到变化——**最快的反馈回路**(亚秒级,不碰 dsh)。
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 发布
|
|
216
|
+
|
|
217
|
+
发布是**单一来源**:升版本号、推送 `v*` tag,由 GitHub Actions 自动发布到 npm;**请勿在本地手动 `npm publish`**——否则会跟 tag 触发的发布冲突(同一版本无法重复发布)。
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# 1. 升版本:更新 package.json 的 version + 两份 README 里的安装示例
|
|
221
|
+
# 2. 本地验证
|
|
222
|
+
pnpm build && pnpm test
|
|
223
|
+
# 3. 提交并推送 tag,触发 CI 发布
|
|
224
|
+
git add -A && git commit -m "release: vX.Y.Z"
|
|
225
|
+
git tag vX.Y.Z && git push origin main --tags
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`.github/workflows/ci.yml` 的 `publish` job 在 `v*` tag 时运行,需 `test` 通过,并使用 GitHub `NPM_TOKEN` secret。
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 变更日志
|
|
233
|
+
|
|
234
|
+
见 [CHANGELOG.md](./CHANGELOG.md)。
|
|
235
|
+
|
|
236
|
+
## 许可证
|
|
237
|
+
|
|
238
|
+
[MIT](./LICENSE)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-baize-rules",
|
|
3
3
|
"description": "User-set session/global must-do and must-not requirements injected at conversation start (Baize).",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"src",
|
|
31
31
|
"cordis.patch.yml",
|
|
32
32
|
"README.md",
|
|
33
|
+
"README.zh.md",
|
|
33
34
|
"LICENSE"
|
|
34
35
|
],
|
|
35
36
|
"publishConfig": {
|
|
@@ -40,7 +41,8 @@
|
|
|
40
41
|
"test": "vitest run",
|
|
41
42
|
"test:watch": "vitest --watch",
|
|
42
43
|
"build": "tsc -p tsconfig.build.json",
|
|
43
|
-
"typecheck": "tsc --noEmit"
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"prepublishOnly": "pnpm build"
|
|
44
46
|
},
|
|
45
47
|
"dsh": {
|
|
46
48
|
"bundle": {
|
|
@@ -105,6 +107,10 @@
|
|
|
105
107
|
"session",
|
|
106
108
|
"baize",
|
|
107
109
|
"must-do",
|
|
108
|
-
"must-not"
|
|
110
|
+
"must-not",
|
|
111
|
+
"deepseek-harness",
|
|
112
|
+
"agent-rules",
|
|
113
|
+
"system-reminder",
|
|
114
|
+
"developer"
|
|
109
115
|
]
|
|
110
116
|
}
|