@lynn123411/dsh-ask-user-grilling 0.2.1 → 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 liceses
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.md CHANGED
@@ -1,15 +1,17 @@
1
1
  # @lynn123411/dsh-ask-user-grilling
2
2
 
3
- DSH 侧的 grilling 适配层(输送机制):把 Matt Pocock 的 grilling 流程在 DSH 里的提问环节做成工具级硬约束。本插件只提供 `ask_user_grilling`,不提供任何 plan-mode 工具——共识达成后不自动进入 plan mode,交还用户决定下一步。分工:本插件负责「在 DSH 里怎么问」的工具与报错层;grilling 纪律文案(散文预告 + 表单投递、子代理停轮)写在工具描述与 matt-* 预设 vendor 的 `skills/grilling/SKILL.md` 里(`matt-ptc` 另含 PTC 投递指引),preset persona 保持原厂原样不做任何修改。
3
+ DSH 侧的 grilling 适配层(输送机制):把 Matt Pocock 的 grilling 流程在 DSH 里的提问环节做成工具级硬约束。本插件只提供 `ask_user_grilling`,不提供任何 plan-mode 工具——共识达成后不自动进入 plan mode,交还用户决定下一步。分工:本插件负责「在 DSH 里怎么问」的工具层;grilling 纪律文案里散文预告 + 表单投递写在工具描述与 matt-* 预设 vendor 的 `skills/grilling/SKILL.md` 里(`matt-ptc` 另含 PTC 投递指引),子代理停轮纪律只写在工具描述里(软纪律、无硬拦)、不进 SKILL(避免诱导模型派遣子代理),preset persona 保持原厂原样不做任何修改。
4
+
5
+ > ⚠️ **安装约束:本插件是 preset 工具行消费的 Cordis 插件,严禁加入 profile `package.json` 的 `dsh.profile.bundles`**(bundle 层必须在包内声明 `dsh.bundle`,本插件没有,加入会导致启动报错)。只需通过 `pnpm add` / `dsh plugin --profile web add` 进入 dependencies 即可,preset 的工具行会直接从 node_modules 解析本包。
4
6
 
5
7
  ## 特性
6
8
 
7
- - **ask_user_grilling**:grilling 轮次专用提问工具。
8
- - **子代理闸门**:后台有子代理运行时会拒绝提问,返回「阻塞 + 运行中名单」——agent 应**结束当前回合**,子代理结算通知自动唤醒后再调用,不在回合内反复重试;
9
+ - **ask_user_grilling**:本 preset 唯一的提问工具(grilling 轮次与一切其他提问都走它——`tool-ask-user` 行已从三份 preset 删除)。
10
+ - **子代理等齐(软纪律,无硬拦)**:若本轮派了子代理且下轮依赖其结论,优先**结束当前回合**、等全部结算后再问——事实没回就先问只会浪费一轮;子代理运行时提问不再被拒绝;
9
11
  - **强制多选**:所有问题一律多选(schema 不提供关闭开关;此行为刻意**不写入工具描述**——模型若知道只能多选,会为避免互斥选项而影响出题质量,见「描述即纪律」);
10
12
  - **补充机制**:每题末尾的补充输入框由 UI 自动渲染、轮末补充题由代码自动追加,两者都不依赖模型也不写入描述(模型自加补充项只会与它们重复);仅当轮末补充输入非空时才应再开一轮;
11
13
  - **题干引导**:要求题干只含问题本身、不重复选项文本(仅模型侧引导,不做硬校验——避免误伤自然提及选项名称的题干);
12
- - **描述即纪律**:工具描述保持精简,只承载「grilling 轮次专用(其余用 ask_user_question)、先散文预告同一轮、再以一次调用投递表单、字段映射、勿自加收尾题、子代理运行中返回 blocked」等工具必知项;投递协议细节(散文预告与表单一一对应、PTC 形态)由技能旁注(DSH delivery / Sub-agent rounds)承载,不与工具描述重复。
14
+ - **描述即纪律**:工具描述保持精简,只承载工具必知项(以 `lib/index.js` 实物为准:唯一提问工具路由、散文预告 + 同一回合一次投递、字段映射与推荐标记、id 规则、勿自加收尾题、子代理等齐软纪律(无硬闸门));投递协议细节由技能旁注 DSH delivery 承载,不与工具描述重复;停轮纪律不在技能里写,只由本工具描述现教(软纪律,无硬闸门)。
13
15
  - 轮次收尾不自动进入 plan mode:grilling 达成共识后由用户决定继续方式(直接执行、或需要方案时自行 `/plan on`)。
14
16
 
15
17
  ## 安装
@@ -18,8 +20,6 @@ DSH 侧的 grilling 适配层(输送机制):把 Matt Pocock 的 grilling
18
20
  dsh plugin --profile web add @lynn123411/dsh-ask-user-grilling
19
21
  ```
20
22
 
21
- 已发布至 npm,配合 `matt-standard` 预设使用(preset 的工具行直接消费本包)。
22
-
23
- **本地开发**:将本目录复制到 `~/.dsh/profiles/web/node_modules/@lynn123411/dsh-ask-user-grilling/` 即可,preset 的工具行会直接从 node_modules 解析。注意:**不要**把它加进 profile `package.json` 的 `dsh.profile.bundles`(bundle 层必须在包内声明 `dsh.bundle`,否则启动报错)。
23
+ 已发布至 npm,供三个 matt 预设(`matt-standard` / `matt-ptc` / `matt-cordis`)使用(preset 的工具行直接消费本包)。
24
24
 
25
- > 注意:profile pnpm hoisted 布局:`pnpm install` / `dsh plugin add|remove` 重装后,手工同步的本地副本会被清掉,需重新同步。
25
+ **本地开发**:临时联调可将本目录复制到 `~/.dsh/profiles/web/node_modules/@lynn123411/dsh-ask-user-grilling/`(preset 的工具行会直接从 node_modules 解析),但裸拷贝是未注册状态:`pnpm install` / `dsh plugin add|remove` 等任何 profile 同步都会把它当 extraneous 清掉,并导致三份 matt preset 从模式选择里消失(2026-09-08 真实事故,见 `patches/matt-presets-bootstrap/README.md` §四)——“被清重拷”只是重复踩坑。注意:**不要**把它加进 profile `package.json` 的 `dsh.profile.bundles`(bundle 层必须在包内声明 `dsh.bundle`,否则启动报错)。含未发布改点时调完即发版,再用 `pnpm add` 回装为注册版本。
package/lib/index.js CHANGED
@@ -7,7 +7,7 @@ import "@deepseek-ai/dsh-user-questions";
7
7
  * hardens how rounds are asked inside DSH.
8
8
  *
9
9
  * ask_user_grilling:
10
- * - gate: refuses while background subagents are running (R1)
10
+ * - no hard gate on running subagents: waiting for settlement is description-level discipline only (soft, was R1)
11
11
  * - forces multi-select on every question (R2)
12
12
  * - appends a round-end supplement question (R3) — per-question supplement is
13
13
  * via the built-in custom input ("Type your answer" / "输入你的答案"), no
@@ -29,14 +29,10 @@ const ROUND_END_QUESTION = {
29
29
  multiSelect: true,
30
30
  };
31
31
 
32
- function displayName(entry) {
33
- return entry.label ?? entry.id;
34
- }
35
-
36
32
  function apply(ctx) {
37
33
  ctx.tools.register(defineTool({
38
34
  name: "ask_user_grilling",
39
- description: "Deliver one ROUND of grilling questions as a form. Use it only when the grilling skill (grill-me / grill-with-docs, or the grilling phases of triage / wayfinder / improve-codebase-architecture) directs a round: first announce the whole round in the message text (title, options and your recommendation, per the skill's template), then deliver the SAME round as ONE call here the prose and the form must match one-to-one. Map each question to the fields below (title → header, body → question, the A/B/C choices → options; mark your recommended option with \"(Recommended)\" (it need not be listed first); if your recommendation is not an option, state it briefly in the question text). Each question needs a stable id that does not start with __grill_ (reserved for the auto-appended round-end supplement question — never add your own catch-all/\"anything else?\" question; a non-empty supplement input reshapes the tree: ask a further round, and stop asking once the user confirms shared understanding). If background subagents are still running, this tool returns blocked: end your turn and wait for the settlement notice, do not retry within the same turn. For any non-grilling question use the plain ask_user_question tool.",
35
+ description: "Ask the user questions as a form the only question tool in these presets; route every user-facing question through here, grilling rounds and all other questions alike. For a grilling round, deliver the round the skill had you announce in the message text the SAME round, ONE call, in the same turn; the prose and the form must match one-to-one. Map each announced question to the fields below (title → header, body → question, the A/B/C choices → options; recommendation as below). Each question needs a stable id matching the Q-number you announced, never starting with __grill_ (reserved for the auto-appended round-end supplement question — never add your own catch-all/\"anything else?\" question; a non-empty supplement input reshapes the tree: ask a further round, and stop asking once the user confirms shared understanding). Mark your recommended option by appending \"(Recommended)\" to its label (any position; if it isn't an option, state it briefly in the question text). If you dispatched subagents whose findings the next round depends on, prefer ending your turn and waiting until all of them have settled before asking asking the frontier before the facts arrive wastes a round.",
40
36
  parameters: {
41
37
  questions: {
42
38
  type: "array",
@@ -88,15 +84,6 @@ function apply(ctx) {
88
84
  type: "object",
89
85
  additionalProperties: false,
90
86
  properties: {
91
- blocked: {
92
- type: "boolean",
93
- description: "True when background subagents are running and the round was not asked.",
94
- },
95
- waiting: {
96
- type: "array",
97
- items: { type: "string" },
98
- description: "Running subagent display names when blocked.",
99
- },
100
87
  rejected: {
101
88
  type: "boolean",
102
89
  description: "True when input validation failed and the round was not asked.",
@@ -108,7 +95,7 @@ function apply(ctx) {
108
95
  },
109
96
  error: {
110
97
  type: "string",
111
- description: "Human-readable error when blocked or rejected.",
98
+ description: "Human-readable error when rejected.",
112
99
  },
113
100
  answers: {
114
101
  type: "array",
@@ -140,38 +127,7 @@ function apply(ctx) {
140
127
  render: (_args, value) => [{ type: "text", text: JSON.stringify(value) }],
141
128
  },
142
129
  async execute(args, exec) {
143
- // 1. gate: refuse while background subagents are running (R1)
144
- const subagents = ctx.get("subagents");
145
- const agent = exec.agent;
146
- const waiting = [];
147
- if (subagents !== undefined && agent !== undefined) {
148
- try {
149
- const entries = await subagents.listDescendants(agent.id, exec.signal);
150
- for (const entry of entries) {
151
- if (entry.kind === "child" && entry.activity === "running") waiting.push(displayName(entry));
152
- }
153
- } catch (error) {
154
- // Fail-closed: R1 says never enter the decision tree unless we know
155
- // no subagents are running. Only an aborted call (user cancelled)
156
- // propagates; any other listing failure blocks the round.
157
- if (exec.signal.aborted) throw error;
158
- console.error("ask_user_grilling: subagent listing failed: %o", error);
159
- return {
160
- blocked: true,
161
- waiting: [],
162
- error: "Cannot confirm background subagent status (subagents query failed). End your turn and wait; call this tool again in a later turn.",
163
- };
164
- }
165
- }
166
- if (waiting.length > 0) {
167
- return {
168
- blocked: true,
169
- waiting,
170
- error: `Still ${waiting.length} subagent(s) running (${waiting.join(", ")}). End your turn and wait — the settlement notice will wake you automatically, then call again.`,
171
- };
172
- }
173
-
174
- // 2. input validation: reserved id prefix guard only (the round-end
130
+ // 1. input validation: reserved id prefix guard only (the round-end
175
131
  // question owns __grill_). Stem/option separation (R4) is guidance,
176
132
  // NOT enforced: substring matching rejected legitimate stems (e.g. a
177
133
  // stem that naturally mentions an option name), so no stem check may
@@ -190,7 +146,7 @@ function apply(ctx) {
190
146
  };
191
147
  }
192
148
 
193
- // 3. transform: force multi-select (R2); per-question supplement is via the built-in custom input ("Type your answer"/"输入你的答案") — no extra option is added to avoid duplication with that field
149
+ // 2. transform: force multi-select (R2); per-question supplement is via the built-in custom input ("Type your answer"/"输入你的答案") — no extra option is added to avoid duplication with that field
194
150
  const questions = args.questions.map((question) => ({
195
151
  id: question.id,
196
152
  question: question.question,
@@ -204,10 +160,10 @@ function apply(ctx) {
204
160
  multiSelect: true,
205
161
  }));
206
162
 
207
- // 4. round-end supplement question (R3) — single "无需补充" option; supplement is via custom input, so no "I have something to add" option (duplicates that field)
163
+ // 3. round-end supplement question (R3) — single "无需补充" option; supplement is via custom input, so no "I have something to add" option (duplicates that field)
208
164
  questions.push(ROUND_END_QUESTION);
209
165
 
210
- // 5. ask through the userQuestions seam (UI renders from the service)
166
+ // 4. ask through the userQuestions seam (UI renders from the service)
211
167
  const answer = await ctx.userQuestions.ask({
212
168
  questions,
213
169
  ...(exec.agent !== undefined ? { agent: exec.agent } : {}),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lynn123411/dsh-ask-user-grilling",
3
- "version": "0.2.1",
4
- "description": "DSH delivery adaptations for grilling rounds: ask_user_grilling (subagent gate / forced multi-select / round-end supplement / stem guidance). Does not modify any skill file.",
3
+ "version": "0.2.3",
4
+ "description": "DSH delivery adaptations for grilling rounds: ask_user_grilling (sole question tool / forced multi-select / round-end supplement / stem guidance). Does not modify any skill file.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -18,6 +18,9 @@
18
18
  "@deepseek-ai/dsh-tools": "^0.1.2-alpha.1",
19
19
  "@deepseek-ai/dsh-user-questions": "^0.1.2-alpha.1"
20
20
  },
21
+ "engines": {
22
+ "node": "^22.19 || >=24"
23
+ },
21
24
  "publishConfig": {
22
25
  "access": "public"
23
26
  }