dsh-grill-first 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/LICENSE +21 -21
- package/README.en.md +167 -0
- package/README.md +60 -11
- package/cordis.patch.yml +4 -4
- package/dist/config.d.ts +6 -2
- package/dist/config.js +3 -1
- package/dist/configSchema.d.ts +4 -2
- package/dist/configSchema.js +8 -2
- package/dist/gate/preExecute.d.ts +14 -4
- package/dist/gate/preExecute.js +49 -2
- package/dist/index.js +13 -0
- package/dist/judge/heuristics.d.ts +12 -1
- package/dist/judge/heuristics.js +38 -7
- package/dist/memory/store.d.ts +14 -5
- package/dist/memory/store.js +20 -8
- package/dist/tools/grillConfirm.d.ts +6 -1
- package/dist/tools/grillConfirm.js +13 -2
- package/dist/tools/grillStart.d.ts +5 -1
- package/dist/tools/grillStart.js +27 -3
- package/dist/tools/sessions.d.ts +4 -0
- package/dist/tools/sessions.js +9 -1
- package/package.json +1 -1
- package/README.repo.md +0 -161
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## 0.1.5
|
|
6
|
+
|
|
7
|
+
"让人一眼看懂"版本:只有文档,没有代码改动。
|
|
8
|
+
|
|
9
|
+
### 新增
|
|
10
|
+
|
|
11
|
+
- **英文 README**(`README.en.md`):面向英文用户重写的,不是逐字翻译——一句话卖点、30 秒对话演示、四档对比、配置表、兼容性与已知限制。
|
|
12
|
+
- **中文 README 首屏重做**:一句话主张「Agent 不是不会做,是经常做完了你才发现不是你要的」、一段真实对话示例、四种门档位的对比表,都提到首屏。
|
|
13
|
+
|
|
14
|
+
### 变更
|
|
15
|
+
|
|
16
|
+
- 中英文 README 顶部互相加了语言切换链接。
|
|
17
|
+
|
|
18
|
+
## 0.1.4
|
|
19
|
+
|
|
20
|
+
"真的按你确认过的意思做"版本:修掉四个"配置写了但不生效"的地方,并让询问类消息不再被当成模糊任务。
|
|
21
|
+
|
|
22
|
+
### 新增
|
|
23
|
+
|
|
24
|
+
- **`gateMode: "ask"` 档位**:需求没确认时,变更类操作弹一张 DSH 原生确认卡片问你"照现在的理解直接动手吗",你点头就放行——不想切 `strict` 硬门禁、又不想写配置文件的人用这个。卡片只弹一次,之后本次任务照常跑。
|
|
25
|
+
- **`memoryScope` 配置**:项目背景与历史默认存工作区;改成 `global` 则落到全局目录的 `project.json`,跨项目共享。
|
|
26
|
+
- **问句不再触发澄清**:问号、"怎么样 / 查一下 / 看看 / 解释一下 / 我想知道" 这类询问,以及 `look at / check my / tell me / explain` 这类英文问句,一律直接放行并接话作答——0.1.3 及以前会被当成"模糊任务"要求先澄清。
|
|
27
|
+
- **`intensity` 真正生效**:`gentle` 两维齐就放行、`standard` 三维、`grill` 还要求写清验收标准(以前三个档位阈值完全一样)。
|
|
28
|
+
- **英文任务也能判**:四张维度词表补了英文同义词(write/implement/refactor、only/scope、use/based on、test/verify…),英文按词边界匹配,不会把 `skipList` 误当跳过词。
|
|
29
|
+
|
|
30
|
+
### 修复
|
|
31
|
+
|
|
32
|
+
- **`maxRounds` 现在真的会到上限**:以前 `grill_start` 每次都把轮数清零,问多少轮都不会停;现在问满上限后直接放行,并在返回值里给出 `rounds_used`。
|
|
33
|
+
- **用户追问不再把门禁关回去**:以前任何一条用户消息都会重置门禁,"继续""嗯""好的"也会;现在只把**新任务**当成新一轮,追问/答话不会打断进行中的工作。
|
|
34
|
+
- **历史记录不再无限增长**:项目历史只保留最近 100 条(摘要只用最近 3 条,多的读不到只是白占地方)。
|
|
35
|
+
- **删掉 `grill_memory` 这个不存在的只读白名单条目**(0.1.3 之前遗留的死引用)。
|
|
36
|
+
|
|
37
|
+
### 内部
|
|
38
|
+
|
|
39
|
+
- 单测/端到端用例从 94 个补到 127 个,新增:问句识别、intensity 阈值、`ask` 档位、追问不重置门禁、`maxRounds` 上限、`memoryScope`、历史裁剪,以及一张"主人真实说过的 11 句话"回归样例表。
|
|
40
|
+
- CI 增加 `npm run typecheck`;新增 `.github/workflows/release.yml`:打 `v*` tag 自动发 npm(需要仓库 Secrets 配 `NPM_TOKEN`)。
|
|
41
|
+
|
|
5
42
|
## 0.1.3
|
|
6
43
|
|
|
7
44
|
文档修正版。
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 InoriMutsumi
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 InoriMutsumi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# dsh-grill-first
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
> A [DSH (DeepSeek Harness)](https://github.com/deepseek-ai/dsh) plugin that **interviews you before it starts working**: vague requests get clarified first, and the main task only starts once you confirm the summary.
|
|
8
|
+
|
|
9
|
+
**Agents rarely fail because they can't do the work. They fail because they do the wrong work, confidently.**
|
|
10
|
+
|
|
11
|
+
[中文](./README.md) · [Install](#install) · [Configuration](#configuration) · [Known limitations](#known-limitations)
|
|
12
|
+
|
|
13
|
+
## See it in 30 seconds
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
you optimize that page
|
|
17
|
+
|
|
18
|
+
it 1) Which page? 2) "Optimize" meaning speed, style or copy?
|
|
19
|
+
3) How do we know it's done?
|
|
20
|
+
|
|
21
|
+
you the login page, mostly styling — the alignment and spacing look off
|
|
22
|
+
|
|
23
|
+
it GOAL tidy up the login page's visuals
|
|
24
|
+
SCOPE styling only; structure and copy stay as-is
|
|
25
|
+
CONSTRAINTS use the existing design tokens
|
|
26
|
+
ACCEPTANCE key screens don't break on mobile
|
|
27
|
+
[ Confirm and start ] [ Change something ]
|
|
28
|
+
|
|
29
|
+
you confirm
|
|
30
|
+
|
|
31
|
+
it (only now does it touch anything)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Without the plugin, the same sentence usually goes like this:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
you optimize that page
|
|
38
|
+
|
|
39
|
+
it Done! I've updated the homepage copy and color scheme ✨ ← you meant the login page
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## The four gate modes
|
|
43
|
+
|
|
44
|
+
| | No plugin | `gateMode: warn` (default) | `gateMode: ask` | `gateMode: strict` |
|
|
45
|
+
|---|---|---|---|---|
|
|
46
|
+
| Vague request | Guesses and starts | Asks; actions not blocked | Asks; one confirmation card before acting | Asks; blocks writes and commands until confirmed |
|
|
47
|
+
|
|
48
|
+
`warn` is the default so upgrading never silently freezes a workflow you already had.
|
|
49
|
+
|
|
50
|
+
## How it works
|
|
51
|
+
|
|
52
|
+
Every new task starts with a check, not with work:
|
|
53
|
+
|
|
54
|
+
1. The model passes your request to `grill_start`.
|
|
55
|
+
2. If it's missing goal / scope / constraints / acceptance criteria, the plugin asks up to 3 questions per round, 3 rounds max, each round built on your previous answer.
|
|
56
|
+
3. Once the picture is clear, `grill_confirm` hands you a four-part summary (goal / scope / constraints / acceptance criteria).
|
|
57
|
+
4. "Confirm" releases the task; "change something" makes it revise and ask again.
|
|
58
|
+
5. One-liners and questions don't trigger any of this — nor do messages containing `直接做`, `跳过提问`, `不用问`, `skip`, `skip the questions`, `just do it`.
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
Quit any running task first. Any of these works:
|
|
63
|
+
|
|
64
|
+
**Plugin marketplace (recommended)** — DSH settings → Plugins → search `dsh-grill-first`.
|
|
65
|
+
|
|
66
|
+
**npm**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
dsh plugin --profile <your-profile> add dsh-grill-first
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**From source**
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
dsh plugin --profile <your-profile> add github:InoriMutsumi/dsh-grill-first
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Live profiles hot-load the plugin — no restart needed (restart DSH once if it doesn't show up).
|
|
79
|
+
|
|
80
|
+
## What you get
|
|
81
|
+
|
|
82
|
+
- **A protocol paragraph** injected into the system prompt (~600 chars) telling the model to run `grill_start` before new work. If you can see `【开工前提问协议(grill-first)】` in the prompt, it's installed.
|
|
83
|
+
- **Two tools:**
|
|
84
|
+
|
|
85
|
+
| Tool | What it does |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `grill_start` | Decides whether the request needs clarification. Returns `verdict`, `focus_hints` (what to ask), and `memory_context` (preferences you already confirmed, so it doesn't ask twice) |
|
|
88
|
+
| `grill_confirm` | Hands you the four-part summary; on confirmation releases the task and saves what you confirmed |
|
|
89
|
+
|
|
90
|
+
## When you don't want to be asked
|
|
91
|
+
|
|
92
|
+
- Put `直接做`, `跳过提问`, `不用问`, `skip`, `skip the questions` or `just do it` in the message → it starts immediately.
|
|
93
|
+
- Asks a question ("how is this plugin", "check my repos", "explain this code") → treated as a question, not a task, so nothing is clarified.
|
|
94
|
+
- Or turn `enabled` off / set `gateMode: off` in the config → fully silent.
|
|
95
|
+
|
|
96
|
+
## Configuration
|
|
97
|
+
|
|
98
|
+
DSH settings → Plugins → dsh-grill-first, eight options:
|
|
99
|
+
|
|
100
|
+
| Option | Type | Default | Meaning |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| `enabled` | boolean | `true` | Master switch. Off = no questions, no gate |
|
|
103
|
+
| `gateMode` | `off` / `warn` / `ask` / `strict` | `warn` | `off` never blocks; `warn` only logs; `ask` shows one confirmation card; `strict` blocks mutating tools until confirmed |
|
|
104
|
+
| `maxQuestionsPerRound` | 1–6 | `3` | Questions per round |
|
|
105
|
+
| `maxRounds` | 1–10 | `3` | Max clarification rounds; on the last round `grill_start` passes the task through |
|
|
106
|
+
| `intensity` | `gentle` / `standard` / `grill` | `standard` | How much detail counts as clear: `gentle` needs two dimensions, `standard` three, `grill` also requires acceptance criteria |
|
|
107
|
+
| `bypassKeywords` | string[] | `["直接做","跳过提问","不用问","skip"]` | Hit any of these → skip the interview |
|
|
108
|
+
| `memoryEnabled` | boolean | `true` | Enable the two-layer memory |
|
|
109
|
+
| `memoryScope` | `project` / `global` | `project` | Where project context lives: in the workspace, or in the global directory shared across projects |
|
|
110
|
+
|
|
111
|
+
### Editing the config
|
|
112
|
+
|
|
113
|
+
The plugin page only offers an enable/disable toggle, so edit the profile's patch layer, `<profile>/cordis.patch.yml`:
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
- id: dsh-grill-first
|
|
117
|
+
name: dsh-grill-first
|
|
118
|
+
config:
|
|
119
|
+
gateMode: ask
|
|
120
|
+
maxQuestionsPerRound: 3
|
|
121
|
+
maxRounds: 3
|
|
122
|
+
intensity: standard
|
|
123
|
+
memoryEnabled: true
|
|
124
|
+
memoryScope: project
|
|
125
|
+
bypassKeywords: [直接做, 跳过提问, 不用问, skip]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Only the keys you set are overridden; the rest keep their defaults. Config changes hot-reload, code changes need a DSH restart.
|
|
129
|
+
|
|
130
|
+
## Two-layer memory
|
|
131
|
+
|
|
132
|
+
Only what you actually confirmed is stored — never raw conversation, never the summary as a file.
|
|
133
|
+
|
|
134
|
+
| Layer | Location | Contents |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| Global | `<profile>/grill-first/global.json` (falls back to `~/.dsh-grill-first/global.json`) | Standing preferences, e.g. "comments in English" |
|
|
137
|
+
| Project | `<workspace>/.dsh/grill-first/memory.json` | Project background and task history (task name, summary, date; last 100 entries) |
|
|
138
|
+
|
|
139
|
+
Set `memoryScope: global` to keep project context in the global directory instead — handy when you don't want a `.dsh/` folder in every repo. Next interview, `grill_start` returns this as `memory_context`, so the same question is never asked twice.
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npm install # dev dependencies (schemastery comes from the host at runtime)
|
|
145
|
+
npm run build # TypeScript → dist/
|
|
146
|
+
npm test # build + 127 unit / end-to-end tests
|
|
147
|
+
node scripts/selfcheck.mjs # static check: Chinese JSDoc, `any` usage, spec-to-code map
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`dist/` is committed on purpose so `dsh plugin add github:…` works without compiling on your machine. CI runs `typecheck` + tests on Node 22.
|
|
151
|
+
|
|
152
|
+
## Compatibility
|
|
153
|
+
|
|
154
|
+
- Peer dependency: only `@deepseek-ai/schemastery` (`^3.18.1`, shipped by the host).
|
|
155
|
+
- No import of any `@deepseek-ai/dsh*` runtime package, so no `engines.dsh` and no DSH peer range to keep in sync. Verified against DSH `0.2.1-rc.2`.
|
|
156
|
+
|
|
157
|
+
## Known limitations
|
|
158
|
+
|
|
159
|
+
- The gate only applies to the **root agent** that talks to you. Delegated work isn't gated (but delegation tools themselves are, so a subagent can't be used to sidestep it). This is deliberate.
|
|
160
|
+
- `ask` mode asks **once per task** — otherwise a task that writes 20 files would show 20 cards. Use `strict` if you want every action blocked.
|
|
161
|
+
- The judge is **keyword heuristics**, not a semantic model: questions are detected by punctuation and interrogatives. Rare ambiguous sentences can be misjudged; say `直接做` or let the model call `grill_start` again to correct it.
|
|
162
|
+
- The judge runs in Chinese and English only. English keywords match on word boundaries (`skip` matches `skip` and `(skip)` but not `skipList`).
|
|
163
|
+
- Memory is plain local JSON, unencrypted.
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT — see [LICENSE](./LICENSE).
|
package/README.md
CHANGED
|
@@ -1,11 +1,51 @@
|
|
|
1
1
|
# dsh-grill-first
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
> DSH(DeepSeek Harness)插件:**开工前先刨根问底**——把模糊需求问成明确需求,你在对话里点头之后,主任务才开工。
|
|
8
8
|
|
|
9
|
+
**Agent 不是不会做,是经常做完了你才发现不是你要的。**
|
|
10
|
+
|
|
11
|
+
[English](./README.en.md) · [安装](#安装) · [配置项](#配置项) · [已知限制](#已知限制)
|
|
12
|
+
|
|
13
|
+
## 30 秒看懂
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
你 把那个页面优化一下
|
|
17
|
+
|
|
18
|
+
它 1) 是哪个页面?2) 「优化」指速度、样式还是文案?
|
|
19
|
+
3) 怎么才算优化好了?
|
|
20
|
+
|
|
21
|
+
你 登录页,主要是样式,现在对齐和间距看着乱
|
|
22
|
+
|
|
23
|
+
它 【目标】整理登录页视觉
|
|
24
|
+
【范围】只改样式,不动结构和文案
|
|
25
|
+
【约束】沿用现有设计规范
|
|
26
|
+
【验收标准】主要页面在移动端不错位
|
|
27
|
+
[ 确认,按此开工 ] [ 要改 ]
|
|
28
|
+
|
|
29
|
+
你 确认
|
|
30
|
+
|
|
31
|
+
它 (这时才动手)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
不装这个插件时,同一句话大概率是这样:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
你 把那个页面优化一下
|
|
38
|
+
它 好的,已经帮你调整了首页的文案和配色 ✨ ← 你要的是登录页
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 四种档位的区别
|
|
42
|
+
|
|
43
|
+
| | 不装插件 | `gateMode: warn`(默认) | `gateMode: ask` | `gateMode: strict` |
|
|
44
|
+
|---|---|---|---|---|
|
|
45
|
+
| 任务模糊时 | 直接猜着做 | 追问;动手不拦 | 追问;动手前弹一次确认卡片 | 追问;没确认前拦截写文件、执行命令 |
|
|
46
|
+
|
|
47
|
+
`warn` 是默认值:升级插件不会突然卡住你已有的工作流。
|
|
48
|
+
|
|
9
49
|
## 它解决什么问题
|
|
10
50
|
|
|
11
51
|
AI 助手最常见的失败不是"不会做",而是"做完了才发现做的不是你要的"。这个插件在**任何新任务开工前**插入一道需求澄清环节:
|
|
@@ -18,6 +58,8 @@ AI 助手最常见的失败不是"不会做",而是"做完了才发现做的
|
|
|
18
58
|
|
|
19
59
|
严格档位(`gateMode: "strict"`)下,需求没确认前模型无法执行写文件、跑命令这类**变更类**操作——从机制上保证"没问清就不许动手"。
|
|
20
60
|
|
|
61
|
+
`ask` 档位(0.1.4 新增)介于两者之间:需求没确认时,变更类操作会弹一张 DSH 原生确认卡片问你"照现在的理解直接动手吗",你点「是」就放行,点「否」由你补一句需求——不写配置文件也能当场决定。
|
|
62
|
+
|
|
21
63
|
## 安装
|
|
22
64
|
|
|
23
65
|
装插件前请先退出正在跑的任务。三种方式任选:
|
|
@@ -35,7 +77,7 @@ dsh plugin --profile <你的 profile 名> add dsh-grill-first
|
|
|
35
77
|
**方式三:本地包 / GitHub 仓库**
|
|
36
78
|
|
|
37
79
|
```bash
|
|
38
|
-
dsh plugin --profile <你的 profile 名> add /绝对路径/dsh-grill-first-0.1.
|
|
80
|
+
dsh plugin --profile <你的 profile 名> add /绝对路径/dsh-grill-first-0.1.5.tgz
|
|
39
81
|
dsh plugin --profile <你的 profile 名> add github:InoriMutsumi/dsh-grill-first
|
|
40
82
|
```
|
|
41
83
|
|
|
@@ -56,38 +98,41 @@ dsh plugin --profile <你的 profile 名> add github:InoriMutsumi/dsh-grill-firs
|
|
|
56
98
|
### 想跳过提问时
|
|
57
99
|
|
|
58
100
|
- 消息里带上「**直接做**」「**跳过提问**」「**不用问**」「**skip**」中任意一个 → 立刻开工;
|
|
101
|
+
- 只是**问情况**("这个插件怎么样""查一下我的仓库里有什么""解释一下这段代码")→ 不算新任务,不追问;
|
|
59
102
|
- 或者在设置里把 `enabled` 关掉 / 把 `gateMode` 调成 `off` → 整个插件静默。
|
|
60
103
|
|
|
61
104
|
## 配置项
|
|
62
105
|
|
|
63
|
-
DSH 设置界面 → 插件 → dsh-grill-first,共
|
|
106
|
+
DSH 设置界面 → 插件 → dsh-grill-first,共 8 项:
|
|
64
107
|
|
|
65
108
|
| 配置 | 类型 | 默认 | 说明 |
|
|
66
109
|
|---|---|---|---|
|
|
67
110
|
| `enabled` | 布尔 | `true` | 总开关。关闭后既不追问也不拦截工具 |
|
|
68
|
-
| `gateMode` | `off` / `warn` / `strict` | `warn` | `off` 不拦截;`warn` 只在日志里记录"需求未确认";`strict`
|
|
111
|
+
| `gateMode` | `off` / `warn` / `ask` / `strict` | `warn` | `off` 不拦截;`warn` 只在日志里记录"需求未确认";`ask` 未确认时弹卡片问你;`strict` 未确认前直接拦截变更类工具 |
|
|
69
112
|
| `maxQuestionsPerRound` | 1-6 | `3` | 每轮最多问几个问题 |
|
|
70
|
-
| `maxRounds` | 1-10 | `3` |
|
|
71
|
-
| `intensity` | `gentle` / `standard` / `grill` | `standard` |
|
|
113
|
+
| `maxRounds` | 1-10 | `3` | 最多追问几轮;问满后 `grill_start` 直接放行 |
|
|
114
|
+
| `intensity` | `gentle` / `standard` / `grill` | `standard` | 追问力度:`gentle` 两维齐就放行 / `standard` 三维 / `grill` 还要求写清验收标准 |
|
|
72
115
|
| `bypassKeywords` | 字符串数组 | `["直接做","跳过提问","不用问","skip"]` | 命中即跳过提问 |
|
|
73
116
|
| `memoryEnabled` | 布尔 | `true` | 是否启用两层记忆 |
|
|
117
|
+
| `memoryScope` | `project` / `global` | `project` | 项目背景/历史存哪:`project` 存工作区,`global` 存全局目录(跨项目共享) |
|
|
74
118
|
|
|
75
119
|
> 默认是 `warn` 而不是 `strict`:默认档位保证升级插件不会突然卡住你已有的工作流。想要硬门禁请手动切 `strict`。
|
|
76
120
|
|
|
77
121
|
### 怎么改配置
|
|
78
122
|
|
|
79
|
-
DSH 设置页里的插件条目目前只提供「启用 / 停用」开关(客户端的插件页不渲染第三方插件的配置表单),要改上面
|
|
123
|
+
DSH 设置页里的插件条目目前只提供「启用 / 停用」开关(客户端的插件页不渲染第三方插件的配置表单),要改上面 8 项请编辑 **profile 的补丁层** `cordis.patch.yml`:
|
|
80
124
|
|
|
81
125
|
```yaml
|
|
82
126
|
# <profile 目录>/cordis.patch.yml
|
|
83
127
|
- id: dsh-grill-first
|
|
84
128
|
name: dsh-grill-first
|
|
85
129
|
config:
|
|
86
|
-
gateMode: strict # off | warn | strict
|
|
130
|
+
gateMode: strict # off | warn | ask | strict
|
|
87
131
|
maxQuestionsPerRound: 3 # 1-6
|
|
88
132
|
maxRounds: 3 # 1-10
|
|
89
133
|
intensity: standard # gentle | standard | grill
|
|
90
134
|
memoryEnabled: true
|
|
135
|
+
memoryScope: project # project | global
|
|
91
136
|
bypassKeywords: [直接做, 跳过提问, 不用问, skip]
|
|
92
137
|
```
|
|
93
138
|
|
|
@@ -102,6 +147,8 @@ DSH 设置页里的插件条目目前只提供「启用 / 停用」开关(客
|
|
|
102
147
|
| 全局层 | `<profile 目录>/grill-first/global.json`(不可写时退化到 `~/.dsh-grill-first/global.json`) | 通用偏好,如"注释一律用中文" |
|
|
103
148
|
| 项目层 | `<工作区>/.dsh/grill-first/memory.json` | 项目背景、任务历史(任务名 + 需求摘要 + 日期) |
|
|
104
149
|
|
|
150
|
+
项目层默认落在工作区;把 `memoryScope` 改成 `global` 后改落 `<全局目录>/project.json`——适合"所有项目通用"的背景约定,不想往每个仓库里塞 `.dsh/` 时也用这个。历史记录只保留最近 100 条(0.1.4 起)。
|
|
151
|
+
|
|
105
152
|
下次追问时,`grill_start` 会把这些内容作为 `memory_context` 返回,模型就不会重复问你同一件事。
|
|
106
153
|
|
|
107
154
|
## 开发
|
|
@@ -109,7 +156,7 @@ DSH 设置页里的插件条目目前只提供「启用 / 停用」开关(客
|
|
|
109
156
|
```bash
|
|
110
157
|
npm install # 装开发依赖(schemastery 由宿主提供,仅开发期需要)
|
|
111
158
|
npm run build # TypeScript → dist/
|
|
112
|
-
npm test # 构建 +
|
|
159
|
+
npm test # 构建 + 127 个单测 / 端到端场景测试
|
|
113
160
|
node scripts/selfcheck.mjs # 静态自检:中文 JSDoc、any 用量、需求→代码位置
|
|
114
161
|
```
|
|
115
162
|
|
|
@@ -121,7 +168,7 @@ node scripts/selfcheck.mjs # 静态自检:中文 JSDoc、any 用量、需求
|
|
|
121
168
|
src/
|
|
122
169
|
index.ts 插件装配入口(工具 + 协议段 + 门禁)
|
|
123
170
|
config.ts 配置归一化(不依赖宿主,可单测)
|
|
124
|
-
configSchema.ts Schemastery 配置声明(设置界面用,
|
|
171
|
+
configSchema.ts Schemastery 配置声明(设置界面用,8 项)
|
|
125
172
|
version.ts 从 package.json 读版本号,供 grill_start 返回
|
|
126
173
|
judge/heuristics.ts 任务模糊度判定(纯函数)
|
|
127
174
|
prompt/protocol.ts 注入系统提示的中文协议文本
|
|
@@ -145,7 +192,7 @@ src/
|
|
|
145
192
|
> DSH 自己的门禁用 `semver.satisfies(..., { includePrerelease: true })` 判定,`^0.2.0-rc.2` 能匹配 `0.2.1-rc.2`;
|
|
146
193
|
> 但标准 npm 语义(不加 `includePrerelease`)会判不匹配,所以上游要求写显式分支。
|
|
147
194
|
|
|
148
|
-
已验证的宿主版本:`0.2.0-rc.2`(0.1.x 开发期)、`0.2.1-rc.2`(2026-10-17 复核:`typecheck`、94 个单测、`verify-installed`
|
|
195
|
+
已验证的宿主版本:`0.2.0-rc.2`(0.1.x 开发期)、`0.2.1-rc.2`(2026-10-17 复核:`typecheck`、94 个单测、`verify-installed` 一致,且实测加载运行;0.1.4 起 127 个单测)。升完 DSH 后的自检三步:
|
|
149
196
|
|
|
150
197
|
```bash
|
|
151
198
|
node scripts/verify-installed.mjs # 安装拷贝与仓库产物是否一致
|
|
@@ -156,6 +203,8 @@ node scripts/verify-installed.mjs # 安装拷贝与仓库产物是否一致
|
|
|
156
203
|
## 已知限制
|
|
157
204
|
|
|
158
205
|
- 门禁只对**根 agent**(能直接跟你对话的那个)生效;子 agent / 团队成员不拦,否则正常的委派工作流会被卡死。因此**委派类工具本身**(`subagent`、`workflow`、`spawn_teammate`…)在未确认前也会被拦,防止"派个子代理替自己动手"绕过门禁。
|
|
206
|
+
- `ask` 档位**只问一次**:卡片弹过之后门禁即视为放行(否则一次任务里写 20 个文件就要弹 20 张卡片)。想每次都拦,请用 `strict`。
|
|
207
|
+
- 判定器是**关键词启发式**,不是语义模型:问句靠问号/疑问词/"查一下/看看"这类信号识别,极少数既像提问又像下令的句子可能判错;判错时直接说「直接做」或让模型调一次 `grill_start` 即可纠正。英文关键词按词边界匹配,中文按子串匹配。
|
|
159
208
|
- `warn` 档位只能"记录不拦截":DSH 的 `tools/pre-execute` 事件没有"放行但同时给模型提示"这种返回形态。
|
|
160
209
|
- 记忆是本地文件,不含加密;删掉对应 json 即清空。
|
|
161
210
|
- `grill_confirm` 优先走 DSH 的结构化提问通道;该通道不可用时(例如子 agent 内部)会返回 `needs_user_confirmation: true`,由模型改用内置提问工具兜底。
|
package/cordis.patch.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# DSH bundle 补丁:把本插件插入当前 profile 的插件表(格式参照已装插件 dsh-find-plugins)。
|
|
2
|
-
- insert:
|
|
3
|
-
- id: dsh-grill-first
|
|
4
|
-
name: 'dsh-grill-first'
|
|
1
|
+
# DSH bundle 补丁:把本插件插入当前 profile 的插件表(格式参照已装插件 dsh-find-plugins)。
|
|
2
|
+
- insert:
|
|
3
|
+
- id: dsh-grill-first
|
|
4
|
+
name: 'dsh-grill-first'
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
/** 门禁档位:off=不拦截、warn=只记录、strict
|
|
2
|
-
export type GateMode = 'off' | 'warn' | 'strict';
|
|
1
|
+
/** 门禁档位:off=不拦截、warn=只记录、strict=拦截变更类工具、ask=先弹卡片问用户。 */
|
|
2
|
+
export type GateMode = 'off' | 'warn' | 'strict' | 'ask';
|
|
3
|
+
/** 项目层记忆的落点:project=跟着当前工作区走、global=全局共享一份。 */
|
|
4
|
+
export type MemoryScope = 'project' | 'global';
|
|
3
5
|
/** 追问力度。 */
|
|
4
6
|
export type Intensity = 'gentle' | 'standard' | 'grill';
|
|
5
7
|
/** 归一化后的插件配置。 */
|
|
@@ -18,6 +20,8 @@ export interface GrillConfig {
|
|
|
18
20
|
bypassKeywords: string[];
|
|
19
21
|
/** 是否启用两层记忆(R5)。 */
|
|
20
22
|
memoryEnabled: boolean;
|
|
23
|
+
/** 项目层记忆落在哪里(0.1.4 新增:有些项目不想被写进 .dsh/)。 */
|
|
24
|
+
memoryScope: MemoryScope;
|
|
21
25
|
}
|
|
22
26
|
/** 默认配置(与工作表 3.7 的默认值一致)。 */
|
|
23
27
|
export declare const DEFAULT_CONFIG: GrillConfig;
|
package/dist/config.js
CHANGED
|
@@ -14,6 +14,7 @@ export const DEFAULT_CONFIG = {
|
|
|
14
14
|
intensity: 'standard',
|
|
15
15
|
bypassKeywords: [...DEFAULT_BYPASS_KEYWORDS],
|
|
16
16
|
memoryEnabled: true,
|
|
17
|
+
memoryScope: 'project',
|
|
17
18
|
};
|
|
18
19
|
/** 取整并夹到 [min, max];非法值返回 fallback。 */
|
|
19
20
|
function clampInt(value, min, max, fallback) {
|
|
@@ -53,11 +54,12 @@ export function normalizeConfig(raw) {
|
|
|
53
54
|
const input = (raw ?? {});
|
|
54
55
|
return {
|
|
55
56
|
enabled: pickBoolean(input.enabled, DEFAULT_CONFIG.enabled),
|
|
56
|
-
gateMode: pickEnum(input.gateMode, ['off', 'warn', 'strict'], DEFAULT_CONFIG.gateMode),
|
|
57
|
+
gateMode: pickEnum(input.gateMode, ['off', 'warn', 'strict', 'ask'], DEFAULT_CONFIG.gateMode),
|
|
57
58
|
maxQuestionsPerRound: clampInt(input.maxQuestionsPerRound, 1, 6, DEFAULT_CONFIG.maxQuestionsPerRound),
|
|
58
59
|
maxRounds: clampInt(input.maxRounds, 1, 10, DEFAULT_CONFIG.maxRounds),
|
|
59
60
|
intensity: pickEnum(input.intensity, ['gentle', 'standard', 'grill'], DEFAULT_CONFIG.intensity),
|
|
60
61
|
bypassKeywords: pickStringList(input.bypassKeywords, DEFAULT_CONFIG.bypassKeywords),
|
|
61
62
|
memoryEnabled: pickBoolean(input.memoryEnabled, DEFAULT_CONFIG.memoryEnabled),
|
|
63
|
+
memoryScope: pickEnum(input.memoryScope, ['project', 'global'], DEFAULT_CONFIG.memoryScope),
|
|
62
64
|
};
|
|
63
65
|
}
|
package/dist/configSchema.d.ts
CHANGED
|
@@ -10,18 +10,20 @@ import z from '@deepseek-ai/schemastery';
|
|
|
10
10
|
/** 插件配置 schema:改了这里,设置界面与 cordis.yml 校验同时生效。 */
|
|
11
11
|
export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
12
12
|
enabled: z<boolean, boolean, "defined">;
|
|
13
|
-
gateMode: z<"off" | "warn" | "strict", "off" | "warn" | "strict", "defined">;
|
|
13
|
+
gateMode: z<"off" | "warn" | "strict" | "ask", "off" | "warn" | "strict" | "ask", "defined">;
|
|
14
14
|
maxQuestionsPerRound: z<number, number, "defined">;
|
|
15
15
|
maxRounds: z<number, number, "defined">;
|
|
16
16
|
intensity: z<"gentle" | "standard" | "grill", "gentle" | "standard" | "grill", "defined">;
|
|
17
17
|
bypassKeywords: z<string[], string[], "defined">;
|
|
18
18
|
memoryEnabled: z<boolean, boolean, "defined">;
|
|
19
|
+
memoryScope: z<"project" | "global", "project" | "global", "defined">;
|
|
19
20
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
20
21
|
enabled: z<boolean, boolean, "defined">;
|
|
21
|
-
gateMode: z<"off" | "warn" | "strict", "off" | "warn" | "strict", "defined">;
|
|
22
|
+
gateMode: z<"off" | "warn" | "strict" | "ask", "off" | "warn" | "strict" | "ask", "defined">;
|
|
22
23
|
maxQuestionsPerRound: z<number, number, "defined">;
|
|
23
24
|
maxRounds: z<number, number, "defined">;
|
|
24
25
|
intensity: z<"gentle" | "standard" | "grill", "gentle" | "standard" | "grill", "defined">;
|
|
25
26
|
bypassKeywords: z<string[], string[], "defined">;
|
|
26
27
|
memoryEnabled: z<boolean, boolean, "defined">;
|
|
28
|
+
memoryScope: z<"project" | "global", "project" | "global", "defined">;
|
|
27
29
|
}>>, "plain">;
|
package/dist/configSchema.js
CHANGED
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
import z from '@deepseek-ai/schemastery';
|
|
10
10
|
import { DEFAULT_BYPASS_KEYWORDS } from './judge/heuristics.js';
|
|
11
11
|
/** 门禁档位 schema。 */
|
|
12
|
-
const gateModeSchema = z
|
|
12
|
+
const gateModeSchema = z
|
|
13
|
+
.union([z.const('off'), z.const('warn'), z.const('strict'), z.const('ask')])
|
|
14
|
+
.default('warn');
|
|
13
15
|
/** 追问力度 schema。 */
|
|
14
16
|
const intensitySchema = z.union([z.const('gentle'), z.const('standard'), z.const('grill')]).default('standard');
|
|
15
17
|
/** 插件配置 schema:改了这里,设置界面与 cordis.yml 校验同时生效。 */
|
|
16
18
|
export const Config = z.object({
|
|
17
19
|
enabled: z.boolean().default(true).description('总开关:关闭后任何任务都不再追问,也不拦截工具。'),
|
|
18
|
-
gateMode: gateModeSchema.description('门禁档位:off 不拦截 / warn 只记录 / strict
|
|
20
|
+
gateMode: gateModeSchema.description('门禁档位:off 不拦截 / warn 只记录 / strict 未确认需求前拦截写类工具 / ask 拦截前先弹卡片问一句。'),
|
|
19
21
|
maxQuestionsPerRound: z
|
|
20
22
|
.natural()
|
|
21
23
|
.max(6)
|
|
@@ -28,4 +30,8 @@ export const Config = z.object({
|
|
|
28
30
|
.default([...DEFAULT_BYPASS_KEYWORDS])
|
|
29
31
|
.description('跳过关键词:用户消息里出现这些词就不再追问,直接开工。'),
|
|
30
32
|
memoryEnabled: z.boolean().default(true).description('是否启用两层记忆(全局偏好 + 项目背景/历史)。'),
|
|
33
|
+
memoryScope: z
|
|
34
|
+
.union([z.const('project'), z.const('global')])
|
|
35
|
+
.default('project')
|
|
36
|
+
.description('项目层记忆落点:project 写进当前工作区的 .dsh/grill-first/,global 写进插件家目录。'),
|
|
31
37
|
});
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* 3. warn 模式只记录不拦截(pre-execute 没有"放行 + 附带提示"这种返回形态)。
|
|
10
10
|
*/
|
|
11
11
|
import type { GrillContext } from '../types.js';
|
|
12
|
-
/**
|
|
13
|
-
export type GateMode = 'off' | 'warn' | 'strict';
|
|
12
|
+
/** 门禁档位:ask 档在拦截前先弹一张"要不要继续"的卡片,交给人决定(0.1.4 新增)。 */
|
|
13
|
+
export type GateMode = 'off' | 'warn' | 'strict' | 'ask';
|
|
14
14
|
/** 门禁状态:open = 已确认或无需确认;closed = 尚未确认。 */
|
|
15
15
|
export type GateState = 'open' | 'closed';
|
|
16
16
|
/** 变更类工具名单(宁松勿紧)。 */
|
|
@@ -19,14 +19,16 @@ export declare const MUTATING_TOOLS: readonly string[];
|
|
|
19
19
|
export declare const READ_ONLY_TOOLS: readonly string[];
|
|
20
20
|
/** 拦截时给模型看的拒绝文案(工作表 3.6 原文)。 */
|
|
21
21
|
export declare const GATE_DENY_REASON = "\u9700\u6C42\u5C1A\u672A\u786E\u8BA4\uFF1A\u8BF7\u5148\u8C03\u7528 grill_confirm \u5B8C\u6210\u9700\u6C42\u786E\u8BA4\uFF0C\u6216\u8BA9\u7528\u6237\u8BF4'\u76F4\u63A5\u505A'\u8DF3\u8FC7\u3002";
|
|
22
|
+
/** ask 档弹给用户看的说明(宿主用 displayReason 渲染卡片正文)。 */
|
|
23
|
+
export declare const GATE_ASK_REASON = "\u8FD9\u6B21\u4EFB\u52A1\u7684\u9700\u6C42\u8FD8\u6CA1\u786E\u8BA4\uFF0C\u8981\u7167\u73B0\u5728\u7684\u7406\u89E3\u76F4\u63A5\u52A8\u624B\u5417\uFF1F";
|
|
22
24
|
/**
|
|
23
25
|
* 判断某个工具名是否属于"会真正改动工作区/交付物"的变更类工具。
|
|
24
26
|
* @param name 工具名。
|
|
25
27
|
*/
|
|
26
28
|
export declare function isMutatingTool(name: string): boolean;
|
|
27
|
-
/**
|
|
29
|
+
/** 门禁判定结果:ask = 弹卡片问用户后由其决定(宿主 PreToolDecision 支持)。 */
|
|
28
30
|
export interface GateDecision {
|
|
29
|
-
action: 'allow' | 'deny';
|
|
31
|
+
action: 'allow' | 'deny' | 'ask';
|
|
30
32
|
reason?: string;
|
|
31
33
|
}
|
|
32
34
|
/**
|
|
@@ -60,6 +62,14 @@ export interface GateOptions {
|
|
|
60
62
|
mode: GateMode;
|
|
61
63
|
/** warn 模式下的提示回调(默认写日志)。 */
|
|
62
64
|
onWarning?: (toolName: string, agentId: string) => void;
|
|
65
|
+
/**
|
|
66
|
+
* 新用户消息到达时,是否把门禁重置为 closed。
|
|
67
|
+
*
|
|
68
|
+
* 0.1.4 修:以前每条用户消息都关门禁,导致"刚确认完、用户回一句继续"又被拦。
|
|
69
|
+
* 现在由判定器看一眼消息内容——追问/询问/说了跳过词之类不关门禁。
|
|
70
|
+
* 返回 true 才关门;未提供该回调时保持旧行为(一律关)。
|
|
71
|
+
*/
|
|
72
|
+
shouldResetOnMessage?: (text: string) => boolean;
|
|
63
73
|
}
|
|
64
74
|
/**
|
|
65
75
|
* 把门禁挂到宿主事件上:`tools/pre-execute` 拦截 + `agent/inbox/inserted` 重置。
|