dsh-gate-agent 0.1.3 → 0.1.4

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 CHANGED
@@ -73,7 +73,7 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
73
73
  | `reviewing/proposal-review` | 单独提案评审 | review worker;`gate-plan-review` |
74
74
  | `reviewing/verify-standalone` | 单独只读验收 | verify worker;`gate-user-verify` |
75
75
  | `docs` | 文档治理 | root;不调用 gate 技能 |
76
- | `blocked` | 冻结写入/派 worker,等待用户决定 | root;`/gate-resume` 或 `/gate-return-discuss` |
76
+ | `blocked` | 冻结写入/派 worker,等待用户决定 | root;`/gate-resume` |
77
77
  | `complete` | 工作完成 | root;可重新进入 plan/implement |
78
78
 
79
79
  进入阶段不等于执行。主代理按当前 procedure 加载技能、派 worker,再用 `gate_record` 推进节点。
@@ -109,23 +109,23 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
109
109
  | 命令 | 参数 | 作用 |
110
110
  |---|---|---|
111
111
  | `/gate-init` | 无 | 初始化 notes、AGENTS.md、`verify-notes`、CI、git 与基础 `.gitignore`,保持 `discuss` |
112
- | `/gate-enter-plan [简单需求]` | 可选 | 进入 `orchestrating/plan` |
113
- | `/gate-enter-implement [简单说明]` | 可选 | 进入 `orchestrating/implement`;复用已通过的 task,或直接用简述 |
114
- | `/gate-docs` | 无 | 文档治理,不调用技能 |
115
- | `/gate-implement-review [范围]` | 可选 | 单独只读 code review,只输出 findings |
116
- | `/gate-code-verify [范围]` | 可选 | 单独只读验收;子代理使用 `gate-user-verify` |
117
- | `/gate-fix-bug [缺陷简述]` | 可选 | 派 fix worker 修复已授权缺陷,完成后回 discuss |
118
- | `/gate-propose-review [提案]` | 可选 | 单独提案评审,走 `gate-plan-review` 三轴 |
112
+ | `/gate-enter-plan [具体工作事项或上下文语义]` | 可选 | 基于讨论共识、既有决策与用户输入进入 `orchestrating/plan` |
113
+ | `/gate-enter-implement [具体工作事项或上下文语义]` | 可选 | 基于已确认计划或讨论后的实施说明进入 `orchestrating/implement` |
114
+ | `/gate-docs` | 无 | 进入文档治理,按项目文档规范处理 |
115
+ | `/gate-implement-review [具体工作事项或上下文语义]` | 可选 | 对当前改动做独立只读 code review,只输出 findings |
116
+ | `/gate-code-verify [具体工作事项或上下文语义]` | 可选 | 对当前改动做独立只读验收(gate-user-verify) |
117
+ | `/gate-fix-bug [具体工作事项或上下文语义]` | 可选 | 基于描述或当前上下文派 fix worker 修复已授权缺陷 |
118
+ | `/gate-propose-review [具体工作事项或上下文语义]` | 可选 | 对提案做独立只读三轴评审 |
119
119
  | `/gate-note-verify` | 无 | 只读检查 notes tree/format/lifecycle/archived |
120
120
  | `/gate-note-archive <note> [--superseded-by <new>]` | 必需 Note 路径 | 归档 implemented Note,写 Archived、移动、封印、报告入站链接 |
121
121
  | `/gate-note-board [输出路径] [标题]` | 可选 | 生成决策看板 `board.html` |
122
122
  | `/gate-note-seal` | 无 | 只给 `archived/` 中已有 Note 补写 `manifest.json` 的 SHA-256 封印 |
123
123
  | `/gate-block [原因]` | 可选 | 手动暂停,保留当前节点 |
124
124
  | `/gate-resume` | 无 | 解冻 blocked,回到 block 前的节点;轮次耗尽回 discuss |
125
- | `/gate-return-discuss` | 无 | 回到 discuss |
126
- | `/gate-status` | 无 | 只读显示当前 phase/node 与 procedure |
125
+ | `/gate-return-discuss` | 无 | 放弃当前节点,回到 discuss |
126
+ | `/gate-status` | 无 | 只读显示当前 phase/node、procedure、access 与下一步命令 |
127
127
 
128
- 直接 implement(`/gate-enter-implement [简单说明]` 或 `gate_start_phase({node:'implement',brief})`)会自动标记 `mechanical`,跳过 Note lifecycle;不需要 `mechanical:` 前缀。plan/plan-revise 手动选择 `mechanical` 时也不要求前缀,只需 `notePaths: []`。
128
+ 直接 implement(`/gate-enter-implement [具体工作事项或上下文语义]` 或 `gate_start_phase({node:'implement',brief})`)会自动标记 `mechanical`,跳过 Note lifecycle;不需要 `mechanical:` 前缀。plan/plan-revise 手动选择 `mechanical` 时也不要求前缀,只需 `notePaths: []`。
129
129
 
130
130
  离开 discuss 的授权可来自对话(包括要求用户再输入 slash command)或 `ask_user_question`;明确授权后,主代理可调用 `gate_start_phase({node:'plan'|'implement', brief})`。
131
131
 
@@ -190,7 +190,7 @@ gate 不自动 `git add`/`git commit`;完成 note-lifecycle 后由用户或主
190
190
  ### 单独 code review
191
191
 
192
192
  ```text
193
- /gate-implement-review [范围]
193
+ /gate-implement-review [具体工作事项或上下文语义]
194
194
  ```
195
195
 
196
196
  只读 review,不修改被评审对象;findings 直接输出。
@@ -198,7 +198,7 @@ gate 不自动 `git add`/`git commit`;完成 note-lifecycle 后由用户或主
198
198
  ### 单独验收
199
199
 
200
200
  ```text
201
- /gate-code-verify [范围]
201
+ /gate-code-verify [具体工作事项或上下文语义]
202
202
  ```
203
203
 
204
204
  主代理派只读 verify worker,使用 `gate-user-verify`;PASS 后 `gate_record({node:'verify-standalone', verification, workerSessionIds})` 回 discuss。
@@ -252,17 +252,20 @@ review worker 使用 `gate-plan-review` 做 Standards/Spec/Architecture 三轴
252
252
  ```text
253
253
  /gate-block 等待产品决定
254
254
  /gate-resume
255
- /gate-return-discuss
256
255
  /gate-status
257
256
  ```
258
257
 
259
258
  - `/gate-block`:保留当前节点,冻结写入与 worker 派发,对话仍可继续。
260
- - `/gate-resume`:回到 block 前的节点;review 轮次耗尽时回 discuss。
261
- - `/gate-return-discuss`:放弃当前节点,回 discuss。
259
+ - `/gate-resume`:唯一的 blocked 恢复入口;回到 block 前的节点,review 轮次耗尽时回 discuss。
260
+ - `/gate-return-discuss`:放弃当前节点回 discuss;blocked 时不可直接用,先 `/gate-resume`。
262
261
  - `/gate-status`:只读查看当前 phase/node 和 procedure。
263
262
 
264
263
  ## 工具
265
264
 
265
+ ### gate_help
266
+
267
+ 只读,root-only。列出全部 `/gate-*` 命令、`gate_*` 工具用途和当前 phase/node,并说明命令由用户执行、工具由模型调用。不确定命令名或工具用途时使用。
268
+
266
269
  ### gate_start_phase
267
270
 
268
271
  只允许 root 调用,在用户已授权时从 `discuss`/`complete` 进入 `plan` 或 `implement`:
@@ -297,7 +300,7 @@ gate_record({
297
300
 
298
301
  ### gate_status
299
302
 
300
- 只读,root 和 worker 可调用。root 返回当前 procedure 与状态;worker 只返回状态,不返回 root procedure。
303
+ 只读,root 和 worker 可调用。root 返回当前 procedure、状态和 nextCommands;worker 只返回状态,不返回 root procedure。
301
304
 
302
305
  ```text
303
306
  gate_status()
package/lib/index.js CHANGED
@@ -189,43 +189,80 @@ var NODE_PROCEDURES = {
189
189
  "proposal-review": REVIEWING_PROPOSAL_PROCEDURE,
190
190
  "verify-standalone": REVIEWING_VERIFY_PROCEDURE
191
191
  };
192
+ var METHODOLOGY_KEYS = [
193
+ "discuss",
194
+ "orchestrating/plan",
195
+ "orchestrating/plan-review",
196
+ "orchestrating/plan-revise",
197
+ "orchestrating/implement",
198
+ "orchestrating/code-review",
199
+ "orchestrating/implement-revise",
200
+ "orchestrating/verify",
201
+ "orchestrating/note-lifecycle",
202
+ "orchestrating/fix-bug",
203
+ "docs",
204
+ "reviewing/code-review-standalone",
205
+ "reviewing/proposal-review",
206
+ "reviewing/verify-standalone",
207
+ "blocked",
208
+ "complete",
209
+ "orchestrating",
210
+ "reviewing"
211
+ ];
212
+ var METHODOLOGY_KEY_SET = new Set(METHODOLOGY_KEYS);
213
+ function methodologyKeyFor(state) {
214
+ if (state.phase === "orchestrating" || state.phase === "reviewing") {
215
+ const key = state.node === null ? state.phase : `${state.phase}/${state.node}`;
216
+ return METHODOLOGY_KEY_SET.has(key) ? key : state.phase;
217
+ }
218
+ return state.phase;
219
+ }
192
220
  var GATE_METHODOLOGY = `## Gate \u65B9\u6CD5\u8BBA
193
- \u672C\u6BB5\u53EA\u5B9A\u4E49\u5404\u9636\u6BB5\u7684\u5DE5\u4F5C\u65B9\u6CD5\u4E0E\u8D28\u91CF\u6807\u51C6\u3002\u5F53\u524D phase/node\u3001procedure \u548C\u8981\u52A0\u8F7D\u7684\u6280\u80FD\u6765\u81EA\u6700\u8FD1\u4E00\u6B21 gate_status\u3001gate_record \u6216\u547D\u4EE4\u7ED3\u679C\uFF1B\u53EA\u6267\u884C\u5F53\u524D phase \u7684 procedure\uFF0C\u5176\u4ED6\u9636\u6BB5\u7684\u65B9\u6CD5\u8BBA\u4EC5\u4F5C\u80CC\u666F\u53C2\u8003\uFF1Bcompaction \u540E\u5FC5\u987B\u91CD\u65B0\u83B7\u53D6 procedure\uFF0C\u5E76\u786E\u8BA4\u6280\u80FD\u5185\u5BB9\u662F\u5426\u4ECD\u5728\u4E0A\u4E0B\u6587\uFF1A\u9996\u6B21\u9700\u8981\u65F6\u52A0\u8F7D\uFF0C\u5DF2\u5728\u4E0A\u6587\u5219\u590D\u7528\uFF0C\u4E0D\u8981\u56E0 procedure \u66F4\u65B0\u91CD\u590D\u52A0\u8F7D\u3002
221
+ \u672C\u6BB5\u53EA\u5B9A\u4E49\u5404\u9636\u6BB5\u7684\u5DE5\u4F5C\u65B9\u6CD5\u4E0E\u8D28\u91CF\u6807\u51C6\u3002\u5F53\u524D phase/node\u3001procedure \u548C\u8981\u52A0\u8F7D\u7684\u6280\u80FD\u6765\u81EA\u6700\u8FD1\u4E00\u6B21 gate_status\u3001gate_record \u6216\u547D\u4EE4\u7ED3\u679C\uFF1B\u53EA\u6267\u884C\u5F53\u524D phase \u7684 procedure\uFF0C\u5176\u4ED6\u9636\u6BB5\u7684\u65B9\u6CD5\u8BBA\u4EC5\u4F5C\u80CC\u666F\u53C2\u8003\uFF1Bcompaction \u540E\u5FC5\u987B\u91CD\u65B0\u83B7\u53D6 procedure\uFF0C\u5E76\u786E\u8BA4\u6280\u80FD\u5185\u5BB9\u662F\u5426\u4ECD\u5728\u4E0A\u4E0B\u6587\uFF1A\u9996\u6B21\u9700\u8981\u65F6\u52A0\u8F7D\uFF0C\u5DF2\u5728\u4E0A\u6587\u5219\u590D\u7528\uFF0C\u4E0D\u8981\u56E0 procedure \u66F4\u65B0\u91CD\u590D\u52A0\u8F7D\u3002\u4E0D\u786E\u5B9A\u6709\u54EA\u4E9B /gate-* \u547D\u4EE4\u6216\u5DE5\u5177\u7528\u9014\u65F6\uFF0C\u8C03\u7528\u53EA\u8BFB gate_help\u3002
194
222
 
195
223
  ${DISCUSS_ORCHESTRATION}
196
224
 
197
- ## plan
198
- \u628A\u7528\u6237\u7B80\u8FF0\u6536\u655B\u6210\u53EF\u5B9E\u65BD\u8BA1\u5212\u4E0E proposed Note\uFF1B\u8BA1\u5212\u5FC5\u987B\u5199\u6E05\u8303\u56F4\u3001\u9A8C\u6536\u3001\u5907\u9009\u4E0E\u98CE\u9669\u3002Plan Review \u72EC\u7ACB\u5224\u65AD\uFF1Bfindings \u5148\u8BB0\u5F55\u518D revise\uFF1Breview \u901A\u8FC7\u540E\u56DE discuss\u3002\u4E0D\u8981\u5728\u89C4\u5212\u91CC\u5F00\u59CB\u5B9E\u73B0\u3002
225
+ ## orchestrating/plan \xB7 orchestrating/plan-review \xB7 orchestrating/plan-revise
226
+ \u628A\u8BA8\u8BBA\u5171\u8BC6\u3001\u65E2\u6709\u51B3\u7B56\u4E0E\u7528\u6237\u9700\u6C42\u6536\u655B\u6210\u53EF\u5B9E\u65BD\u8BA1\u5212\u4E0E proposed Note\uFF1B\u8BA1\u5212\u5FC5\u987B\u5199\u6E05\u8303\u56F4\u3001\u9A8C\u6536\u3001\u5907\u9009\u4E0E\u98CE\u9669\u3002Plan Review \u72EC\u7ACB\u5224\u65AD\uFF1Bfindings \u5148\u8BB0\u5F55\u518D revise\uFF1Breview \u901A\u8FC7\u540E\u56DE discuss\u3002\u4E0D\u8981\u5728\u89C4\u5212\u91CC\u5F00\u59CB\u5B9E\u73B0\u3002
199
227
 
200
- ## implement
201
- \u6309\u5DF2\u786E\u8BA4\u7684\u8BA1\u5212\u5B9E\u65BD\u5E76\u5B8C\u6210\u6D4B\u8BD5\uFF1B\u5B9E\u73B0\u540E\u505A\u72EC\u7ACB review\uFF0C\u518D\u7528\u53EF\u6267\u884C\u8BC1\u636E verify\uFF1B\u6700\u540E\u5B8C\u6210 Note lifecycle\u3002\u4E0D\u6269\u5927\u8303\u56F4\uFF0C\u4E0D\u5728\u5B9E\u73B0\u4E2D\u91CD\u65B0\u89C4\u5212\u3002
228
+ ## orchestrating/implement \xB7 orchestrating/implement-revise
229
+ \u6309\u5DF2\u786E\u8BA4\u7684\u8BA1\u5212\u6216\u8BA8\u8BBA\u540E\u7684\u5B9E\u65BD\u8BF4\u660E\u5B9E\u65BD\u5E76\u5B8C\u6210\u6D4B\u8BD5\uFF1B\u5B9E\u73B0\u540E\u505A\u72EC\u7ACB review\uFF0C\u518D\u7528\u53EF\u6267\u884C\u8BC1\u636E verify\uFF1B\u6700\u540E\u5B8C\u6210 Note lifecycle\u3002\u4E0D\u6269\u5927\u8303\u56F4\uFF0C\u4E0D\u5728\u5B9E\u73B0\u4E2D\u91CD\u65B0\u89C4\u5212\u3002
202
230
 
203
- ## code-review
231
+ ## orchestrating/code-review
204
232
  \u72EC\u7ACB\u5224\u65AD\u6539\u52A8\u662F\u5426\u6EE1\u8DB3\u5408\u540C\u4E0E\u6807\u51C6\uFF1B\u53EA\u62A5 findings\uFF0C\u4E0D\u4FEE\u4EE3\u7801\u3001\u4E0D\u66FF\u4EE3 verify\uFF1Bfindings \u8BB0\u5F55\u540E\u518D\u8FDB\u5165 revise\u3002
205
233
 
206
- ## verify
234
+ ## orchestrating/verify
207
235
  \u7528\u53EF\u6267\u884C\u8BC1\u636E\u5224\u5B9A PASS/FAIL\uFF1B\u4E0D\u4FEE\u6539\u4EA7\u54C1/\u6D4B\u8BD5\u8BA9\u7ED3\u679C\u53D8\u7EFF\uFF1BFAIL \u56DE implement-revise\u3002
208
236
 
209
- ## note-lifecycle
237
+ ## orchestrating/note-lifecycle
210
238
  \u5B8C\u6210 Note \u7684 finalize \u4E0E\u6821\u9A8C\uFF1B\u4E0D\u5199\u4E1A\u52A1\u4EE3\u7801\uFF1B\u68C0\u67E5\u662F\u5426\u4EA7\u751F\u5F52\u6863\u5019\u9009\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
211
239
 
212
- ## fix-bug
240
+ ## orchestrating/fix-bug
213
241
  \u5BF9\u5DF2\u6388\u6743\u7684\u5B9E\u73B0\u7F3A\u9677\uFF1A\u590D\u73B0\u3001\u56DE\u5F52\u8986\u76D6\u3001\u6839\u56E0\u3001\u6700\u5C0F\u4FEE\u590D\u3001\u72EC\u7ACB review\uFF1B\u4E0D\u505A\u65B0\u529F\u80FD\u3001\u4E0D\u6269\u5927\u8303\u56F4\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
214
242
 
215
243
  ## docs
216
244
  \u6587\u6863\u6CBB\u7406\uFF1B\u4E0D\u6539\u53D8\u529F\u80FD\u884C\u4E3A\uFF1B\u8303\u56F4\u7531\u6A21\u578B\u6309\u9879\u76EE\u5B9E\u9645\u6587\u6863\u9700\u8981\u5224\u65AD\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
217
245
 
218
- ## reviewing-code
246
+ ## reviewing/code-review-standalone
219
247
  \u53EA\u8BFB code review\uFF1A\u72EC\u7ACB\u5224\u65AD Standards \u4E0E Spec \u4E24\u8F74\uFF0C\u53EA\u8F93\u51FA findings\uFF0C\u4E0D\u4FEE\u4EE3\u7801\u3001\u4E0D\u66FF\u4EE3 verify\u3002
220
248
 
221
- ## reviewing-proposal
249
+ ## reviewing/proposal-review
222
250
  \u53EA\u8BFB\u63D0\u6848\u8BC4\u5BA1\uFF1A\u8986\u76D6 Standards\u3001Spec\u3001Architecture \u4E09\u8F74\uFF0C\u53EA\u8F93\u51FA\u5224\u65AD\uFF0C\u4E0D\u4FEE\u6539\u89C4\u5212\u3001\u4E0D\u81EA\u52A8 revise\u3002
223
251
 
224
- ## reviewing-verify
252
+ ## reviewing/verify-standalone
225
253
  \u53EA\u8BFB\u72EC\u7ACB\u9A8C\u6536\uFF1A\u4E0D\u6539\u4EE3\u7801\u3001\u4E0D\u66FF\u4EE3 implement\uFF0C\u53EA\u8F93\u51FA PASS/FAIL \u4E0E\u8BC1\u636E\u5224\u65AD\u3002
226
254
 
227
- ## blocked / complete
228
- blocked \u8868\u793A\u51BB\u7ED3\uFF1A\u7B49\u5F85 /gate-resume \u6216 /gate-return-discuss\u3002complete \u8868\u793A\u5F53\u524D\u4EFB\u52A1\u5B8C\u6210\uFF0C\u65B0\u4EFB\u52A1\u9700\u8981\u91CD\u65B0\u6388\u6743\u3002`;
255
+ ## blocked
256
+ blocked \u8868\u793A\u51BB\u7ED3\uFF1A\u7B49\u5F85 /gate-resume\u3002
257
+
258
+ ## complete
259
+ complete \u8868\u793A\u5F53\u524D\u4EFB\u52A1\u5B8C\u6210\uFF0C\u65B0\u4EFB\u52A1\u9700\u8981\u91CD\u65B0\u6388\u6743\u3002
260
+
261
+ ## orchestrating
262
+ \u5F53\u524D\u5904\u4E8E orchestrating \u4F46\u6CA1\u6709\u5339\u914D node\uFF1B\u8C03\u7528 gate_status \u91CD\u65B0\u8BFB\u53D6\uFF1B\u82E5\u4ECD\u4E0D\u4E00\u81F4\uFF0C\u56DE discuss \u4FEE\u590D Gate \u72B6\u6001\u3002
263
+
264
+ ## reviewing
265
+ \u5F53\u524D\u5904\u4E8E reviewing \u4F46\u6CA1\u6709\u5339\u914D node\uFF1B\u8C03\u7528 gate_status \u91CD\u65B0\u8BFB\u53D6\uFF1B\u82E5\u4ECD\u4E0D\u4E00\u81F4\uFF0C\u56DE discuss \u4FEE\u590D Gate \u72B6\u6001\u3002`;
229
266
  function protocolVariant(state) {
230
267
  if (state.phase === "orchestrating") return NODE_INFO[state.node ?? ""]?.variant ?? state.phase;
231
268
  if (state.phase === "reviewing") return NODE_INFO[state.node ?? ""]?.variant ?? "reviewing-code";
@@ -238,7 +275,7 @@ function procedureFor(state, { reviewLimit = DEFAULT_REVIEW_LIMIT } = {}) {
238
275
  if (variant === "discuss") {
239
276
  text = "discuss \u4E0D\u6D3E worker\uFF1B\u6587\u4EF6\u9ED8\u8BA4\u53EA\u8BFB\uFF0C\u63D0\u4EA4\u5DF2\u6709\u6539\u52A8\u4E0D\u53D7\u5F71\u54CD\uFF1B\u7528\u6237\u6388\u6743\u540E\u8C03\u7528 gate_start_phase \u8FDB\u5165 plan/implement\u3002";
240
277
  } else if (variant === "blocked") {
241
- text = `Gate \u5DF2\u51BB\u7ED3\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u89E3\u51BB\u540E\u56DE ${state.blockedFrom?.phase ?? "discuss"} / ${state.blockedFrom?.node ?? "\u65E0"}\uFF1B\u7528 /gate-resume \u6216 /gate-return-discuss\u3002`;
278
+ text = `Gate \u5DF2\u51BB\u7ED3\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u89E3\u51BB\u540E\u56DE ${state.blockedFrom?.phase ?? "discuss"} / ${state.blockedFrom?.node ?? "\u65E0"}\uFF1B\u7528 /gate-resume\u3002`;
242
279
  } else if (variant === "complete") {
243
280
  text = "Gate \u5DF2\u5B8C\u6210\uFF1B\u65B0\u4EFB\u52A1\u9700\u8981\u91CD\u65B0\u6388\u6743\u3002";
244
281
  } else if (variant === "docs") {
@@ -256,7 +293,7 @@ function procedureFor(state, { reviewLimit = DEFAULT_REVIEW_LIMIT } = {}) {
256
293
  text = [text, `## \u5F53\u524D\u8F6E\u6B21
257
294
  ${roundsText(state, reviewLimit)}`].filter(Boolean).join("\n\n");
258
295
  }
259
- return { phase: state.phase, node: state.node, method, text, hasRounds: variant === "plan" || variant === "implement" };
296
+ return { phase: state.phase, node: state.node, methodologyKey: methodologyKeyFor(state), method, text, hasRounds: variant === "plan" || variant === "implement" };
260
297
  }
261
298
  function procedureFailure(state, reviewLimit, fields) {
262
299
  const procedure = procedureFor(state, { reviewLimit });
@@ -301,6 +338,7 @@ function statusText(state, reviewLimit = DEFAULT_REVIEW_LIMIT, { includeRounds =
301
338
  }
302
339
  function procedureBlock(procedure) {
303
340
  return `\u5F53\u524D phase/node\uFF1A${procedure.phase} / ${procedure.node ?? "\u65E0"}
341
+ \u65B9\u6CD5\u8BBA\uFF1A${procedure.methodologyKey}
304
342
  \u65B9\u6CD5\uFF1A${procedure.method}
305
343
 
306
344
  ${procedure.text}`;
@@ -910,9 +948,9 @@ function classifyPath(root, value, cwd = root) {
910
948
  var GIT_VALUE_OPTIONS = /* @__PURE__ */ new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace", "--config-env"]);
911
949
  var GIT_FILE_WRITE = /* @__PURE__ */ new Set(["checkout", "switch", "reset", "clean", "restore", "stash", "merge", "rebase", "cherry-pick", "apply", "pull"]);
912
950
  var GIT_NON_WRITE = /* @__PURE__ */ new Set(["status", "add", "commit", "push"]);
913
- function gitSubcommands(command) {
951
+ function gitSubcommands(command2) {
914
952
  const subcommands = /* @__PURE__ */ new Set();
915
- for (const segment of String(command).split(/&&|\|\||;|\r?\n|\|/u)) {
953
+ for (const segment of String(command2).split(/&&|\|\||;|\r?\n|\|/u)) {
916
954
  const tokens = [...segment.matchAll(/"([^"]*)"|'([^']*)'|(\S+)/gu)].map((match) => match[1] ?? match[2] ?? match[3] ?? "");
917
955
  const gitIndex = tokens.findIndex((token) => /^git(?:\.exe)?$/iu.test(token));
918
956
  if (gitIndex < 0) continue;
@@ -975,8 +1013,8 @@ function addTarget(targets, token, map) {
975
1013
  }
976
1014
  function segmentAccess(text, root, cwd, map) {
977
1015
  const git = gitSubcommands(text);
978
- if ([...git].some((command) => GIT_FILE_WRITE.has(command))) return { write: true, outsideTargets: [] };
979
- if ([...git].some((command) => GIT_NON_WRITE.has(command))) return { write: false, outsideTargets: [] };
1016
+ if ([...git].some((command2) => GIT_FILE_WRITE.has(command2))) return { write: true, outsideTargets: [] };
1017
+ if ([...git].some((command2) => GIT_NON_WRITE.has(command2))) return { write: false, outsideTargets: [] };
980
1018
  const raw = [];
981
1019
  const verb = WRITE_VERB.exec(text);
982
1020
  if (verb !== null) {
@@ -995,9 +1033,9 @@ function segmentAccess(text, root, cwd, map) {
995
1033
  function segments(text) {
996
1034
  return String(text).split(/&&|\|\||;|\r?\n/u).map((part) => part.trim()).filter(Boolean);
997
1035
  }
998
- function shellAccess(command, root, cwd = root) {
999
- const map = assignments(command);
1000
- const parts = segments(command).map((part) => segmentAccess(part, root, cwd, map)).filter((item) => item.write);
1036
+ function shellAccess(command2, root, cwd = root) {
1037
+ const map = assignments(command2);
1038
+ const parts = segments(command2).map((part) => segmentAccess(part, root, cwd, map)).filter((item) => item.write);
1001
1039
  return {
1002
1040
  write: parts.length > 0,
1003
1041
  outsideTargets: parts.flatMap((item) => item.outsideTargets ?? [])
@@ -1032,9 +1070,9 @@ function accessFor(state, worker) {
1032
1070
  function accessText(access) {
1033
1071
  return `\u6743\u9650\uFF1Aread=${access.read ? "yes" : "no"} write=${access.write} noteWrite=${access.noteWrite ? "yes" : "no"} shell=${access.shell} repoWrite=${access.repoWrite}`;
1034
1072
  }
1035
- function repoCommands(command) {
1073
+ function repoCommands(command2) {
1036
1074
  const commands = /* @__PURE__ */ new Set();
1037
- for (const subcommand of gitSubcommands(command)) {
1075
+ for (const subcommand of gitSubcommands(command2)) {
1038
1076
  if (subcommand === "add" || subcommand === "commit" || subcommand === "push") commands.add(subcommand);
1039
1077
  }
1040
1078
  return commands;
@@ -1085,7 +1123,7 @@ function enterPhase(ctx, agent, node, reviewLimit, store, current) {
1085
1123
  store.write(gate.root, agent, state);
1086
1124
  return { gate, state, reviewLimit };
1087
1125
  }
1088
- function wakeGateAgent(invocation, text, command) {
1126
+ function wakeGateAgent(invocation, text, command2) {
1089
1127
  const followup = invocation?.agent?.followup;
1090
1128
  if (typeof followup !== "function") return;
1091
1129
  try {
@@ -1093,19 +1131,19 @@ function wakeGateAgent(invocation, text, command) {
1093
1131
  id: randomUUID2(),
1094
1132
  role: "user",
1095
1133
  content: [{ type: "text", text }],
1096
- source: { kind: "gate-command", command }
1134
+ source: { kind: "gate-command", command: command2 }
1097
1135
  });
1098
1136
  } catch {
1099
1137
  }
1100
1138
  }
1101
1139
  function makeWake(reviewLimit) {
1102
- return (invocation, state, text, command) => {
1140
+ return (invocation, state, text, command2) => {
1103
1141
  const procedure = procedureFor(state, { reviewLimit });
1104
1142
  wakeGateAgent(invocation, `${procedureBlock(procedure)}
1105
1143
 
1106
1144
  ${accessText(accessFor(state, false))}
1107
1145
 
1108
- ${text}`, command);
1146
+ ${text}`, command2);
1109
1147
  };
1110
1148
  }
1111
1149
 
@@ -1249,7 +1287,7 @@ function targetList(name, args) {
1249
1287
  if (name !== "apply_patch") return [args?.file_path];
1250
1288
  return [...String(args?.input ?? "").matchAll(/^\*\*\* (?:Add File|Update File|Delete File|Move to):\s*(.+)$/gmu)].map((match) => String(match[1] ?? "").trim());
1251
1289
  }
1252
- var GATE_FROZEN_REASON = "Gate \u5DF2\u51BB\u7ED3\uFF1A\u5148 /gate-resume \u6216 /gate-return-discuss";
1290
+ var GATE_FROZEN_REASON = "Gate \u5DF2\u51BB\u7ED3\uFF1A\u5148 /gate-resume";
1253
1291
  function fileWriteDenied(state, effective) {
1254
1292
  if (state.phase === "blocked") return GATE_FROZEN_REASON;
1255
1293
  if (!effective.worker && state.phase === "discuss") return DISCUSS_READ_ONLY;
@@ -1303,10 +1341,10 @@ function gateDenyReason(ctx, exec, store) {
1303
1341
  const base = sessionCwd(ctx, exec.agent, gate.workspace);
1304
1342
  const requested = exec.arguments?.workdir;
1305
1343
  const cwd = typeof requested === "string" && requested !== "" ? path7.resolve(base, requested) : base;
1306
- const command = String(exec.arguments?.command ?? "");
1307
- const repos = repoCommands(command);
1344
+ const command2 = String(exec.arguments?.command ?? "");
1345
+ const repos = repoCommands(command2);
1308
1346
  if (repos.size > 0 && access.repoWrite === "none") return repoDenied(state, effective, [...repos].join("/"));
1309
- const shell = shellAccess(command, gate.workspace, cwd);
1347
+ const shell = shellAccess(command2, gate.workspace, cwd);
1310
1348
  if (!shell.write) return void 0;
1311
1349
  if (shell.outsideTargets.length > 0) return "\u5DE5\u4F5C\u533A\u5916\u5199\u5165\u88AB\u62D2\u7EDD";
1312
1350
  if (access.write === "none") return shellWriteDenied(state, effective);
@@ -1380,15 +1418,15 @@ function provisionProjectScripts(root) {
1380
1418
  if (pkg === null || typeof pkg !== "object" || Array.isArray(pkg)) throw new Error("package.json \u5FC5\u987B\u662F\u5BF9\u8C61");
1381
1419
  }
1382
1420
  pkg.scripts = pkg.scripts !== null && typeof pkg.scripts === "object" && !Array.isArray(pkg.scripts) ? pkg.scripts : {};
1383
- const command = "node .agents/gate/verify-notes.mjs";
1421
+ const command2 = "node .agents/gate/verify-notes.mjs";
1384
1422
  const existing = pkg.scripts["verify-notes"];
1385
- if (existing === void 0) pkg.scripts["verify-notes"] = command;
1423
+ if (existing === void 0) pkg.scripts["verify-notes"] = command2;
1386
1424
  writeFileSync3(packagePath, `${JSON.stringify(pkg, null, 2)}
1387
1425
  `);
1388
1426
  return {
1389
1427
  launcher: path8.relative(root, launcher).replaceAll("\\", "/"),
1390
1428
  package: path8.relative(root, packagePath).replaceAll("\\", "/"),
1391
- command: existing === void 0 ? command : String(existing),
1429
+ command: existing === void 0 ? command2 : String(existing),
1392
1430
  changed: existing === void 0
1393
1431
  };
1394
1432
  }
@@ -1450,16 +1488,70 @@ function provisionCi(root) {
1450
1488
 
1451
1489
  // src/commands.ts
1452
1490
  import { execFileSync as execFileSync3 } from "node:child_process";
1491
+
1492
+ // src/command-catalog.ts
1493
+ var GATE_COMMANDS = [
1494
+ { name: "gate-init", description: "\u521D\u59CB\u5316 notes\u3001AGENTS.md\u3001verify-notes\u3001CI\u3001git \u4E0E\u57FA\u7840 .gitignore", hint: null, when: "any" },
1495
+ { name: "gate-enter-plan", description: "\u57FA\u4E8E\u8BA8\u8BBA\u5171\u8BC6\u3001\u65E2\u6709\u51B3\u7B56\u4E0E\u7528\u6237\u8F93\u5165\u8FDB\u5165 planning", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1496
+ { name: "gate-enter-implement", description: "\u57FA\u4E8E\u5DF2\u786E\u8BA4\u8BA1\u5212\u6216\u8BA8\u8BBA\u540E\u7684\u5B9E\u65BD\u8BF4\u660E\u8FDB\u5165 implementation", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1497
+ { name: "gate-fix-bug", description: "\u4E3A\u5DF2\u6388\u6743\u7F3A\u9677\u6D3E\u53D1 fix worker\uFF0C\u57FA\u4E8E\u63CF\u8FF0\u6216\u5F53\u524D\u4E0A\u4E0B\u6587\u4FEE\u590D", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1498
+ { name: "gate-docs", description: "\u8FDB\u5165\u6587\u6863\u6CBB\u7406\uFF0C\u6309\u9879\u76EE\u6587\u6863\u89C4\u8303\u5904\u7406", hint: null, when: "discuss/complete" },
1499
+ { name: "gate-implement-review", description: "\u5BF9\u5F53\u524D\u6539\u52A8\u505A\u72EC\u7ACB\u53EA\u8BFB code review", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1500
+ { name: "gate-code-verify", description: "\u5BF9\u5F53\u524D\u6539\u52A8\u505A\u72EC\u7ACB\u53EA\u8BFB\u9A8C\u6536\uFF08gate-user-verify\uFF09", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1501
+ { name: "gate-propose-review", description: "\u5BF9\u63D0\u6848\u505A\u72EC\u7ACB\u53EA\u8BFB\u4E09\u8F74\u8BC4\u5BA1", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1502
+ { name: "gate-block", description: "\u624B\u52A8\u6682\u505C\uFF1A\u4FDD\u7559\u5F53\u524D\u8282\u70B9\u5E76\u505C\u6B62\u5199\u5165/\u6D3E worker\uFF1B\u5BF9\u8BDD\u4ECD\u53EF\u7EE7\u7EED", hint: "[\u539F\u56E0]", when: "any" },
1503
+ { name: "gate-resume", description: "\u89E3\u51BB blocked\uFF1A\u56DE\u5230 block \u524D\u7684\u8282\u70B9\uFF1B\u8F6E\u6B21\u8017\u5C3D\u56DE discuss", hint: null, when: "blocked" },
1504
+ { name: "gate-return-discuss", description: "\u653E\u5F03\u5F53\u524D\u8282\u70B9\uFF0C\u56DE\u5230 discuss", hint: null, when: "non-blocked" },
1505
+ { name: "gate-status", description: "\u67E5\u770B\u5F53\u524D phase/node\u3001procedure\u3001access \u4E0E\u4E0B\u4E00\u6B65\u547D\u4EE4", hint: null, when: "any" },
1506
+ { name: "gate-note-verify", description: "\u53EA\u8BFB\u68C0\u67E5 notes tree/format/lifecycle/archived", hint: null, when: "any" },
1507
+ { name: "gate-note-archive", description: "\u5C06 implemented Note \u5F52\u6863\u5230 archived/\uFF1A\u52A0 Archived\u3001\u79FB\u52A8\u3001\u5C01\u5370\u5E76\u62A5\u544A\u5165\u7AD9\u94FE\u63A5", hint: "<implemented-note> [--superseded-by <new-note>]", when: "any" },
1508
+ { name: "gate-note-board", description: "\u751F\u6210\u51B3\u7B56\u770B\u677F board.html\uFF08\u8F7B\u91CF\u6A21\u5F0F\uFF0C\u8FDE\u63A5\u672C\u5730 notes \u76EE\u5F55\uFF09", hint: "[\u8F93\u51FA\u8DEF\u5F84] [\u6807\u9898]", when: "any" },
1509
+ { name: "gate-note-seal", description: "\u53EA\u7ED9 archived/ \u4E2D\u5DF2\u6709 Note \u8865\u5199 manifest.json \u7684 SHA-256 \u5C01\u5370\uFF1B\u4E0D\u5F52\u6863\u3001\u4E0D\u6539 Note \u5185\u5BB9", hint: null, when: "any" }
1510
+ ];
1511
+ function commandSpec(name) {
1512
+ return GATE_COMMANDS.find((command2) => command2.name === name);
1513
+ }
1514
+ function commandLabel(spec) {
1515
+ return `/${spec.name}`;
1516
+ }
1517
+
1518
+ // src/command-next.ts
1519
+ function command(name, reason) {
1520
+ const spec = commandSpec(name);
1521
+ return { command: spec === void 0 ? `/${name}` : commandLabel(spec), reason };
1522
+ }
1523
+ function nextCommandsFor(state) {
1524
+ if (state.phase === "blocked") {
1525
+ return [command("gate-resume", "\u89E3\u51BB\u540E\u56DE\u5230\u6682\u505C\u524D\u8282\u70B9\uFF1B\u8F6E\u6B21\u8017\u5C3D\u65F6\u56DE discuss\u3002")];
1526
+ }
1527
+ if (state.phase === "discuss" || state.phase === "complete") {
1528
+ return [
1529
+ command("gate-enter-plan", "\u9700\u8981\u7528\u6237\u6388\u6743\u540E\u8FDB\u5165 planning\u3002"),
1530
+ command("gate-enter-implement", "\u9700\u8981\u7528\u6237\u6388\u6743\u540E\u8FDB\u5165\u5B9E\u65BD\uFF1B\u590D\u7528\u5DF2\u901A\u8FC7\u7684 plan task\uFF0C\u6216\u76F4\u63A5\u4ECE\u7528\u6237\u7B80\u8FF0\u5B9E\u65BD\u3002")
1531
+ ];
1532
+ }
1533
+ return [];
1534
+ }
1535
+ function nextCommandsText(commands) {
1536
+ if (commands.length === 0) return "";
1537
+ return `\u4E0B\u4E00\u6B65\u547D\u4EE4\uFF1A${commands.map((item) => `${item.command}\uFF08${item.reason}\uFF09`).join("\uFF1B")}`;
1538
+ }
1539
+
1540
+ // src/commands.ts
1453
1541
  function registerCommands(ctx, deps) {
1454
1542
  const { store, reviewLimit, wake } = deps;
1455
1543
  ctx.inject(["commands"], (scope) => {
1456
- const register = (name, description, handler, input = { hint: "<\u5DE5\u4F5C\u9879>" }) => scope.commands.register({
1457
- name,
1458
- description,
1459
- ...input === null ? {} : { input },
1460
- handler
1461
- });
1462
- register("gate-init", "\u521D\u59CB\u5316 notes\u3001AGENTS.md\u3001verify-notes \u4E0E GitHub Actions CI", async (invocation) => {
1544
+ const command2 = (name, handler) => {
1545
+ const spec = commandSpec(name);
1546
+ if (spec === void 0) throw new Error(`unknown gate command: ${name}`);
1547
+ scope.commands.register({
1548
+ name: spec.name,
1549
+ description: spec.description,
1550
+ ...spec.hint === null ? {} : { input: { hint: spec.hint } },
1551
+ handler
1552
+ });
1553
+ };
1554
+ command2("gate-init", async (invocation) => {
1463
1555
  const workspace = workspaceBoundary(ctx, invocation.agent);
1464
1556
  if (workspace === void 0) return { kind: "error", text: "\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D\u4F1A\u8BDD\u5DE5\u4F5C\u533A" };
1465
1557
  const root = path9.resolve(workspace);
@@ -1483,15 +1575,15 @@ verify-notes\uFF1A${projectScripts.command}
1483
1575
  CI\uFF1A${projectCi.workflow}
1484
1576
  git\uFF1A${projectGit.git}${projectGit.gitError === null ? "" : `\uFF08${projectGit.gitError}\uFF09`}
1485
1577
  ignore\uFF1A${projectGit.ignore}` };
1486
- }, null);
1487
- register("gate-enter-plan", "\u6309\u7528\u6237\u7B80\u8FF0\u8FDB\u5165 planning", async (invocation) => {
1578
+ });
1579
+ command2("gate-enter-plan", async (invocation) => {
1488
1580
  const result = enterPhase(ctx, invocation.agent, "plan", reviewLimit, store, void 0);
1489
1581
  if (result.kind === "error") return result;
1490
1582
  const brief = String(invocation.rawInput ?? "").trim();
1491
1583
  wake(invocation, result.state, `Gate \u5DF2\u8FDB\u5165 plan\u3002\u7528\u6237\u89C4\u5212\u8F93\u5165\uFF1A${brief === "" ? "\uFF08\u672A\u63D0\u4F9B\u989D\u5916\u8F93\u5165\uFF09" : brief}\u3002`, "gate-enter-plan");
1492
1584
  return { kind: "success", text: "\u8FDB\u5165 planning\u3002" };
1493
- }, { hint: "[\u7B80\u5355\u9700\u6C42]" });
1494
- register("gate-enter-implement", "\u4ECE\u5DF2\u786E\u8BA4\u89C4\u5212\u6216\u7528\u6237\u7B80\u8FF0\u8FDB\u5165 implementation", async (invocation) => {
1585
+ });
1586
+ command2("gate-enter-implement", async (invocation) => {
1495
1587
  const brief = String(invocation.rawInput ?? "").trim();
1496
1588
  const gate = resolveGate(ctx, invocation.agent);
1497
1589
  const state = store.read(gate.root, invocation.agent);
@@ -1513,8 +1605,8 @@ ignore\uFF1A${projectGit.ignore}` };
1513
1605
  const constraints = direct ? "\uFF08\u672C\u53E5\u5373\u5DE5\u4F5C\u9879\u7B80\u8FF0\uFF09" : brief === "" ? "\uFF08\u65E0\u989D\u5916\u7EA6\u675F\uFF09" : brief;
1514
1606
  wake(invocation, result.state, `Gate \u5DF2\u8FDB\u5165 implement\uFF1A${result.state.task ?? ""}${direct ? "\uFF08\u76F4\u63A5\u5B9E\u65BD\uFF0C\u672A\u8D70 planning\uFF09" : ""}\u3002\u7528\u6237\u8BF4\u660E\uFF1A${constraints}\u3002`, "gate-enter-implement");
1515
1607
  return { kind: "success", text: `\u8FDB\u5165 implement\uFF1A${result.state.task}${direct ? "\uFF08\u76F4\u63A5\u5B9E\u65BD\uFF09" : ""}` };
1516
- }, { hint: "[\u7B80\u5355\u8BF4\u660E]" });
1517
- register("gate-fix-bug", "\u4E3A\u5DF2\u6388\u6743\u7684\u5B9E\u73B0\u7F3A\u9677\u6D3E\u53D1 fix worker", async (invocation) => {
1608
+ });
1609
+ command2("gate-fix-bug", async (invocation) => {
1518
1610
  const brief = String(invocation.rawInput ?? "").trim();
1519
1611
  const gate = resolveGate(ctx, invocation.agent);
1520
1612
  const state = store.read(gate.root, invocation.agent);
@@ -1530,8 +1622,8 @@ ignore\uFF1A${projectGit.ignore}` };
1530
1622
  store.write(gate.root, invocation.agent, state);
1531
1623
  wake(invocation, state, `Gate \u5DF2\u8FDB\u5165 fix-bug\uFF1A${scope2}\u3002`, "gate-fix-bug");
1532
1624
  return { kind: "success", text: `\u8FDB\u5165 fix-bug\uFF1A${scope2}` };
1533
- }, { hint: "[\u7F3A\u9677\u7B80\u8FF0]" });
1534
- register("gate-docs", "\u5F00\u59CB\u6587\u6863\u6CBB\u7406", async (invocation) => {
1625
+ });
1626
+ command2("gate-docs", async (invocation) => {
1535
1627
  const gate = resolveGate(ctx, invocation.agent);
1536
1628
  const state = store.read(gate.root, invocation.agent);
1537
1629
  if (state.phase !== "discuss" && state.phase !== "complete") return { kind: "error", text: `\u5F53\u524D phase \u662F ${state.phase}` };
@@ -1545,8 +1637,8 @@ ignore\uFF1A${projectGit.ignore}` };
1545
1637
  store.write(gate.root, invocation.agent, state);
1546
1638
  wake(invocation, state, "Gate \u5DF2\u8FDB\u5165 docs\u3002", "gate-docs");
1547
1639
  return { kind: "success", text: "\u8FDB\u5165 docs\uFF1A\u6587\u6863\u6CBB\u7406" };
1548
- }, null);
1549
- register("gate-implement-review", "\u5F00\u59CB\u72EC\u7ACB\u53EA\u8BFB code review", async (invocation) => {
1640
+ });
1641
+ command2("gate-implement-review", async (invocation) => {
1550
1642
  const brief = String(invocation.rawInput ?? "").trim();
1551
1643
  const gate = resolveGate(ctx, invocation.agent);
1552
1644
  const state = store.read(gate.root, invocation.agent);
@@ -1563,7 +1655,7 @@ ignore\uFF1A${projectGit.ignore}` };
1563
1655
  wake(invocation, state, `Gate \u5DF2\u8FDB\u5165\u53EA\u8BFB code review\uFF1A${scope2}\u3002`, "gate-implement-review");
1564
1656
  return { kind: "success", text: `\u8FDB\u5165\u53EA\u8BFB code review\uFF1A${scope2}` };
1565
1657
  });
1566
- register("gate-code-verify", "\u5F00\u59CB\u72EC\u7ACB\u53EA\u8BFB\u9A8C\u6536", async (invocation) => {
1658
+ command2("gate-code-verify", async (invocation) => {
1567
1659
  const brief = String(invocation.rawInput ?? "").trim();
1568
1660
  const gate = resolveGate(ctx, invocation.agent);
1569
1661
  const state = store.read(gate.root, invocation.agent);
@@ -1580,7 +1672,7 @@ ignore\uFF1A${projectGit.ignore}` };
1580
1672
  wake(invocation, state, `Gate \u5DF2\u8FDB\u5165\u72EC\u7ACB\u9A8C\u6536\uFF1A${scope2}\u3002`, "gate-code-verify");
1581
1673
  return { kind: "success", text: `\u8FDB\u5165\u72EC\u7ACB\u9A8C\u6536\uFF1A${scope2}` };
1582
1674
  });
1583
- register("gate-propose-review", "\u5F00\u59CB\u72EC\u7ACB\u63D0\u6848\u8BC4\u5BA1", async (invocation) => {
1675
+ command2("gate-propose-review", async (invocation) => {
1584
1676
  const brief = String(invocation.rawInput ?? "").trim();
1585
1677
  const gate = resolveGate(ctx, invocation.agent);
1586
1678
  const state = store.read(gate.root, invocation.agent);
@@ -1597,7 +1689,7 @@ ignore\uFF1A${projectGit.ignore}` };
1597
1689
  wake(invocation, state, `Gate \u5DF2\u8FDB\u5165\u63D0\u6848\u8BC4\u5BA1\uFF1A${scope2}\u3002`, "gate-propose-review");
1598
1690
  return { kind: "success", text: `\u8FDB\u5165\u63D0\u6848\u8BC4\u5BA1\uFF1A${scope2}` };
1599
1691
  });
1600
- register("gate-block", "\u624B\u52A8\u6682\u505C\uFF1A\u4FDD\u7559\u5F53\u524D\u8282\u70B9\u5E76\u505C\u6B62\u5199\u5165/\u6D3E worker\uFF1B\u5BF9\u8BDD\u4ECD\u53EF\u7EE7\u7EED", async (invocation) => {
1692
+ command2("gate-block", async (invocation) => {
1601
1693
  const gate = resolveGate(ctx, invocation.agent);
1602
1694
  const state = store.read(gate.root, invocation.agent);
1603
1695
  if (state.phase === "blocked") return { kind: "success", text: "\u5DF2\u7ECF\u662F blocked" };
@@ -1609,9 +1701,9 @@ ignore\uFF1A${projectGit.ignore}` };
1609
1701
  store.write(gate.root, invocation.agent, state);
1610
1702
  return { kind: "success", text: `\u5DF2\u6682\u505C\uFF1A${state.blockReason}
1611
1703
  \u89E3\u51BB\u540E\uFF1A${state.blockedFrom?.phase ?? "discuss"}${state.blockedFrom?.node === null || state.blockedFrom?.node === void 0 ? "" : ` / ${state.blockedFrom.node}`}
1612
- \u540C\u4E00\u4E8B\u9879\uFF1A/gate-resume \u56DE\u5230\u8BE5\u8282\u70B9\uFF1B\u6539\u53D8\u65B9\u6848\uFF1A/gate-return-discuss\u3002` };
1613
- }, { hint: "[\u539F\u56E0]" });
1614
- register("gate-resume", "\u89E3\u51BB blocked\uFF1A\u56DE\u5230 block \u524D\u7684\u8282\u70B9\uFF1B\u8F6E\u6B21\u8017\u5C3D\u56DE discuss", async (invocation) => {
1704
+ \u540C\u4E00\u4E8B\u9879\uFF1A/gate-resume \u56DE\u5230\u8BE5\u8282\u70B9\uFF1B\u6539\u53D8\u65B9\u6848\uFF1A\u5148 /gate-resume\uFF0C\u518D /gate-return-discuss\u3002` };
1705
+ });
1706
+ command2("gate-resume", async (invocation) => {
1615
1707
  const gate = resolveGate(ctx, invocation.agent);
1616
1708
  const state = store.read(gate.root, invocation.agent);
1617
1709
  if (state.phase !== "blocked") return { kind: "error", text: "\u5F53\u524D\u4E0D\u662F blocked" };
@@ -1628,8 +1720,8 @@ ignore\uFF1A${projectGit.ignore}` };
1628
1720
  }
1629
1721
  const exhausted = reason === "plan-review-rounds-exhausted" || reason === "code-review-rounds-exhausted";
1630
1722
  return { kind: "success", text: `\u5DF2\u89E3\u9664 blocked\uFF1A${state.phase}${state.node === null ? "" : ` / ${state.node}`}${exhausted ? "\nreview \u8F6E\u6B21\u5DF2\u8017\u5C3D\uFF0C\u4E0D\u80FD\u7EE7\u7EED\u539F\u8282\u70B9\uFF1B\u7528 /gate-enter-plan \u91CD\u65B0\u89C4\u5212\u3002" : "\n\u5DF2\u56DE\u5230\u6682\u505C\u524D\u8282\u70B9\uFF0C\u6309\u5F53\u524D procedure \u7EE7\u7EED\u3002"}` };
1631
- }, null);
1632
- register("gate-return-discuss", "\u56DE\u5230 discuss", async (invocation) => {
1723
+ });
1724
+ command2("gate-return-discuss", async (invocation) => {
1633
1725
  const gate = resolveGate(ctx, invocation.agent);
1634
1726
  const state = store.read(gate.root, invocation.agent);
1635
1727
  if (state.phase === "blocked") return { kind: "error", text: `\u5F53\u524D blocked\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u5148 /gate-resume` };
@@ -1651,21 +1743,22 @@ ignore\uFF1A${projectGit.ignore}` };
1651
1743
  state.pending = {};
1652
1744
  store.write(gate.root, invocation.agent, state);
1653
1745
  return { kind: "success", text: "\u5DF2\u56DE\u5230 discuss" };
1654
- }, null);
1655
- register("gate-status", "\u67E5\u770B\u5F53\u524D gate \u72B6\u6001", async (invocation) => {
1746
+ });
1747
+ command2("gate-status", async (invocation) => {
1656
1748
  const gate = resolveGate(ctx, invocation.agent);
1657
1749
  const root = rootAgentOf(ctx, invocation.agent);
1658
1750
  const state = store.read(gate.root, root);
1659
1751
  const worker = root?.id !== invocation.agent?.id;
1660
- return { kind: "success", text: [accessText(accessFor(state, worker)), statusText(state, reviewLimit)].join("\n\n") };
1661
- }, null);
1662
- register("gate-note-verify", "\u53EA\u8BFB\u68C0\u67E5 notes tree/format/lifecycle/archived", async (invocation) => {
1752
+ const next = worker ? "" : nextCommandsText(nextCommandsFor(state));
1753
+ return { kind: "success", text: [accessText(accessFor(state, worker)), statusText(state, reviewLimit), next].filter(Boolean).join("\n\n") };
1754
+ });
1755
+ command2("gate-note-verify", async (invocation) => {
1663
1756
  const gate = resolveGate(ctx, invocation.agent);
1664
1757
  const check = runNotesScripts(gate.root);
1665
1758
  return check.ok ? { kind: "success", text: check.results.map((item) => `${item.name}: ok`).join("\n") } : { kind: "error", text: `notes \u6821\u9A8C\u5931\u8D25\uFF1A
1666
1759
  ${JSON.stringify(check.results, null, 2)}` };
1667
- }, null);
1668
- register("gate-note-archive", "\u5C06 implemented Note \u5F52\u6863\u5230 archived/\uFF1A\u52A0 Archived\u3001\u79FB\u52A8\u3001\u5C01\u5370\u5E76\u62A5\u544A\u5165\u7AD9\u94FE\u63A5", async (invocation) => {
1760
+ });
1761
+ command2("gate-note-archive", async (invocation) => {
1669
1762
  const gate = resolveGate(ctx, invocation.agent);
1670
1763
  const raw = String(invocation.rawInput ?? "").trim();
1671
1764
  const args = raw === "" ? [] : raw.split(/\s+/u);
@@ -1679,8 +1772,8 @@ ${JSON.stringify(check.results, null, 2)}` };
1679
1772
  } catch (error) {
1680
1773
  return { kind: "error", text: String(error?.stderr ?? error?.message ?? error).trim() };
1681
1774
  }
1682
- }, { hint: "<implemented-note> [--superseded-by <new-note>]" });
1683
- register("gate-note-board", "\u751F\u6210\u51B3\u7B56\u770B\u677F board.html\uFF08\u8F7B\u91CF\u6A21\u5F0F\uFF0C\u8FDE\u63A5\u672C\u5730 notes \u76EE\u5F55\uFF09", async (invocation) => {
1775
+ });
1776
+ command2("gate-note-board", async (invocation) => {
1684
1777
  const gate = resolveGate(ctx, invocation.agent);
1685
1778
  const raw = String(invocation.rawInput ?? "").trim();
1686
1779
  const args = raw === "" ? [] : raw.split(/\s+/u);
@@ -1695,8 +1788,8 @@ ${JSON.stringify(check.results, null, 2)}` };
1695
1788
  } catch (error) {
1696
1789
  return { kind: "error", text: String(error?.stderr ?? error?.message ?? error).trim() };
1697
1790
  }
1698
- }, { hint: "[\u8F93\u51FA\u8DEF\u5F84] [\u6807\u9898]" });
1699
- register("gate-note-seal", "\u53EA\u7ED9 archived/ \u4E2D\u5DF2\u6709 Note \u8865\u5199 manifest.json \u7684 SHA-256 \u5C01\u5370\uFF1B\u4E0D\u5F52\u6863\u3001\u4E0D\u6539 Note \u5185\u5BB9", async (invocation) => {
1791
+ });
1792
+ command2("gate-note-seal", async (invocation) => {
1700
1793
  const gate = resolveGate(ctx, invocation.agent);
1701
1794
  const node = resolveNodeBinary();
1702
1795
  if (node === void 0) return { kind: "error", text: "notes-runtime-unavailable" };
@@ -1707,7 +1800,7 @@ ${JSON.stringify(check.results, null, 2)}` };
1707
1800
  } catch (error) {
1708
1801
  return { kind: "error", text: String(error?.stderr ?? error?.message ?? error).trim() };
1709
1802
  }
1710
- }, null);
1803
+ });
1711
1804
  });
1712
1805
  }
1713
1806
 
@@ -2081,8 +2174,10 @@ function registerStatus(ctx, deps) {
2081
2174
  const worker = root?.id !== exec.agent?.id;
2082
2175
  const access = accessFor(state, worker);
2083
2176
  if (worker) {
2084
- return { ok: true, procedure: null, method: null, access, text: [accessText(access), statusText(state, reviewLimit)].join("\n\n") };
2177
+ return { ok: true, procedure: null, method: null, access, nextCommands: [], text: [accessText(access), statusText(state, reviewLimit)].join("\n\n") };
2085
2178
  }
2179
+ const nextCommands = nextCommandsFor(state);
2180
+ const nextText = nextCommandsText(nextCommands);
2086
2181
  const procedure = procedureFor(state, { reviewLimit });
2087
2182
  const includeRounds = !procedure.hasRounds;
2088
2183
  return {
@@ -2090,7 +2185,8 @@ function registerStatus(ctx, deps) {
2090
2185
  procedure,
2091
2186
  method: procedure.method,
2092
2187
  access,
2093
- text: procedureResultText(procedure, [statusText(state, reviewLimit, { includeRounds }), accessText(access)].join("\n\n"))
2188
+ nextCommands,
2189
+ text: procedureResultText(procedure, [statusText(state, reviewLimit, { includeRounds }), nextText, accessText(access)].filter(Boolean).join("\n\n"))
2094
2190
  };
2095
2191
  }
2096
2192
  });
@@ -2251,12 +2347,73 @@ function registerNoteTools(ctx, deps) {
2251
2347
  });
2252
2348
  }
2253
2349
 
2350
+ // src/tools/catalog.ts
2351
+ var GATE_TOOLS = [
2352
+ { name: "gate_status", summary: "\u8BFB\u53D6\u5F53\u524D phase/node\u3001procedure\u3001access \u548C nextCommands\uFF1Broot/worker \u5747\u53EF\u8C03\u7528\u3002" },
2353
+ { name: "gate_record", summary: "\u8BB0\u5F55 worker \u7ED3\u679C\u5E76\u63A8\u8FDB gate\uFF1B\u4EC5 root \u53EF\u8C03\u7528\u3002" },
2354
+ { name: "gate_start_phase", summary: "\u5728\u7528\u6237\u6388\u6743\u540E\u8FDB\u5165 plan/implement\uFF1Bplan \u57FA\u4E8E\u8BA8\u8BBA\u5171\u8BC6\uFF0Cimplement \u57FA\u4E8E\u5DF2\u786E\u8BA4\u8BA1\u5212\u6216\u5B9E\u65BD\u8BF4\u660E\uFF1B\u4EC5 root \u53EF\u8C03\u7528\u3002" },
2355
+ { name: "gate_note_write", summary: "planning worker \u5199 proposed Note \u6216\u539F\u5730\u66F4\u65B0 implemented Note\u3002" },
2356
+ { name: "gate_note_verify", summary: "\u5728 note-lifecycle \u4E2D\u8FD0\u884C notes \u6821\u9A8C\uFF1Broot-only\u3002" },
2357
+ { name: "gate_note_finalize", summary: "\u628A proposed Note \u79FB\u5230 implemented \u5E76\u66F4\u65B0\u5934\u5757\uFF1Broot-only\u3002" },
2358
+ { name: "gate_help", summary: "\u5217\u51FA gate \u547D\u4EE4\u3001\u5DE5\u5177\u548C\u5F53\u524D phase/node\uFF1B\u53EA\u8BFB\uFF0Croot-only\u3002" }
2359
+ ];
2360
+
2361
+ // src/tools/help.ts
2362
+ function commandLine(spec) {
2363
+ const hint = spec.hint === null ? "" : ` ${spec.hint}`;
2364
+ return `- ${commandLabel(spec)}${hint} \u2014 ${spec.description}\uFF08${spec.when}\uFF09`;
2365
+ }
2366
+ function helpText(phase, node) {
2367
+ return [
2368
+ "## Gate help",
2369
+ `\u5F53\u524D phase/node\uFF1A${phase} / ${node ?? "\u65E0"}`,
2370
+ "",
2371
+ "\u547D\u4EE4\uFF08\u7531\u7528\u6237\u6267\u884C\uFF09\uFF1A",
2372
+ ...GATE_COMMANDS.map(commandLine),
2373
+ "",
2374
+ "\u5DE5\u5177\uFF08\u7531\u6A21\u578B\u8C03\u7528\uFF09\uFF1A",
2375
+ ...GATE_TOOLS.map((tool) => `- ${tool.name} \u2014 ${tool.summary}`),
2376
+ "",
2377
+ "\u547D\u4EE4\u7531\u7528\u6237\u6267\u884C\uFF1B\u5DE5\u5177\u7531\u6A21\u578B\u8C03\u7528\u3002\u547D\u4EE4\u4E0D\u4F1A\u4F5C\u4E3A tool \u51FA\u73B0\u5728\u5DE5\u5177\u76EE\u5F55\u3002"
2378
+ ].join("\n");
2379
+ }
2380
+ function registerHelp(ctx, deps) {
2381
+ const { store } = deps;
2382
+ ctx.tools.register({
2383
+ name: "gate_help",
2384
+ description: "\u53EA\u8BFB\u5217\u51FA gate \u547D\u4EE4\u3001\u5DE5\u5177\u7528\u9014\u548C\u5F53\u524D phase/node\u3002\u4EC5 root agent\uFF1B\u53EA\u5728\u4E0D\u786E\u5B9A\u547D\u4EE4\u540D/\u5DE5\u5177\u7528\u9014\u65F6\u4F7F\u7528\u3002",
2385
+ parameters: { type: "object", additionalProperties: false, properties: {} },
2386
+ output: {
2387
+ schema: { type: "object", additionalProperties: true },
2388
+ render: (_args, value) => [{ type: "text", text: typeof value?.text === "string" ? value.text : JSON.stringify(value) }]
2389
+ },
2390
+ async execute(_args, exec) {
2391
+ const root = rootAgentOf(ctx, exec.agent);
2392
+ if (root?.id !== exec.agent?.id) return { ok: false, code: "root-only", reason: "gate_help \u53EA\u80FD\u7531 root agent \u8C03\u7528\u3002" };
2393
+ const gate = resolveGate(ctx, exec.agent);
2394
+ if (gate.root === void 0) return { ok: false, code: "state-unavailable", reason: "\u65E0\u6CD5\u786E\u5B9A\u5DE5\u4F5C\u533A\u3002" };
2395
+ const state = store.read(gate.root, root);
2396
+ return {
2397
+ ok: true,
2398
+ phase: state.phase,
2399
+ node: state.node,
2400
+ current: { phase: state.phase, node: state.node },
2401
+ note: "\u547D\u4EE4\u7531\u7528\u6237\u6267\u884C\uFF1B\u5DE5\u5177\u7531\u6A21\u578B\u8C03\u7528\u3002",
2402
+ commands: GATE_COMMANDS.map((spec) => ({ ...spec, command: commandLabel(spec) })),
2403
+ tools: GATE_TOOLS,
2404
+ text: helpText(state.phase, state.node)
2405
+ };
2406
+ }
2407
+ });
2408
+ }
2409
+
2254
2410
  // src/tools/index.ts
2255
2411
  function registerTools(ctx, deps) {
2256
2412
  registerStartPhase(ctx, deps);
2257
2413
  registerRecord(ctx, deps);
2258
2414
  registerStatus(ctx, deps);
2259
2415
  registerNoteTools(ctx, deps);
2416
+ registerHelp(ctx, deps);
2260
2417
  }
2261
2418
 
2262
2419
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-gate-agent",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Phase/node workflow gate with built-in commands, tools, and skills.",
6
6
  "exports": {
@@ -56,11 +56,10 @@ user-invocable: false
56
56
  - 产品范围、行为与验收问题报告给工作项;
57
57
  - 本次规划的技术设计问题报告给 Agent Note;引用输入的问题按项目配置反馈其属主;
58
58
  - 状态、评审与批准证据报告给工作项;
59
- - 领域术语问题报告给 技能`gate-domain-modeling` 的属主,技术决定报告给相关 Agent Note。
60
59
 
61
60
  由 planning worker 决定并执行修正;本 worker 不更新工作项、Note 或就绪状态。
62
61
 
63
- 仅当提议为架构决定单独建档时,使用 技能`adr` 的准入条件检查反悔成本与真实权衡。其他 Agent Note 按项目部署后的 README 判断是否有长期设计价值。纯行为规则归产品合同;普通实现细节不因“重要”就自动生成 Note。
62
+ 纯行为规则归产品合同;普通实现细节不因“重要”就自动生成 Note。
64
63
 
65
64
  设计仍依赖临时产品假设时保持非权威。修订产品合同后,检查所有承接同一产品合同的设计,不只修改最先暴露问题的那一份。
66
65
 
@@ -64,8 +64,6 @@ user-invocable: false
64
64
 
65
65
  设计定稿遵循 技术设计规则([rfc.md](./rfc.md) ) 的合同稳定性与评审条件。Note 的 proposed/implemented 表示交付生命周期,不代替评审和批准证据。
66
66
 
67
- 使用项目既有领域语言和适用架构约束。领域术语与模型变化使用 `gate-domain-modeling`;需要为架构决定单独建档时,使用 `adr` 的准入条件判断,在相关 Agent Note 中记录决定。
68
-
69
67
  ### 决定权限
70
68
 
71
69
  在已同意的产品合同、既有架构和项目约束内,自主解决普通技术选择。
@@ -54,8 +54,6 @@
54
54
 
55
55
  需要产品、业务、兼容性、成本、风险、持久架构方向或其他价值判断时,交给相应决定权限,不把问题伪装成纯技术选择。
56
56
 
57
- 接受的决定形成或改变领域语言时,使用 `gate-domain-modeling` SKILL 维护领域资料。需要为架构决定单独建档时,使用 `adr` SKILL 的准入条件判断;决定属于本设计时在同一 Note 中维护,可独立判断的新决定按项目 Note 规则记录。
58
-
59
57
  ## 定稿与评审条件
60
58
 
61
59
  技术设计可以进入 Plan Review,需要满足:
@@ -12,6 +12,3 @@ Its job:
12
12
  2. Write the findings to a single Markdown file, citing each claim's source.
13
13
  3. Save it where the repo already keeps such notes; match the existing convention, and if there is none, put it somewhere sensible and say where.
14
14
 
15
-
16
-
17
-
@@ -1,64 +0,0 @@
1
- # CONTEXT.md Format
2
-
3
- ## Structure
4
-
5
- ```md
6
- # {Context Name}
7
-
8
- {One or two sentence description of what this context is and why it exists.}
9
-
10
- ## Language
11
-
12
- **Order**:
13
- {A one or two sentence description of the term}
14
- _Avoid_: Purchase, transaction
15
-
16
- **Invoice**:
17
- A request for payment sent to a customer after delivery.
18
- _Avoid_: Bill, payment request
19
-
20
- **Customer**:
21
- A person or organization that places orders.
22
- _Avoid_: Client, buyer, account
23
- ```
24
-
25
- ## Rules
26
-
27
- - **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`.
28
- - **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does.
29
- - **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs.
30
- - **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine.
31
-
32
- ## Single vs multi-context repos
33
-
34
- **Single context (most repos):** One `CONTEXT.md` at the repo root.
35
-
36
- **Multiple contexts:** A `CONTEXT-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other:
37
-
38
- ```md
39
- # Context Map
40
-
41
- ## Contexts
42
-
43
- - [Ordering](./src/ordering/CONTEXT.md): receives and tracks customer orders
44
- - [Billing](./src/billing/CONTEXT.md): generates invoices and processes payments
45
- - [Fulfillment](./src/fulfillment/CONTEXT.md): manages warehouse picking and shipping
46
-
47
- ## Relationships
48
-
49
- - **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking
50
- - **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices
51
- - **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money`
52
- ```
53
-
54
- The skill infers which structure applies:
55
-
56
- Resolve the root from project instructions before these checks; the current working directory may be a subproject. Use the project documentation hierarchy for ownership; the context map does not create separate record categories. Paths shown in the map are Markdown links relative to the map file.
57
-
58
- - If `CONTEXT-MAP.md` exists, read it to find contexts
59
- - If only a root `CONTEXT.md` exists, single context
60
- - If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved
61
-
62
- When multiple contexts exist, infer which one the current topic relates to. If unclear, ask.
63
-
64
-
@@ -1,64 +0,0 @@
1
- # GLOSSARY.md Format
2
-
3
- ## Structure
4
-
5
- ```md
6
- # {Context Name}
7
-
8
- {One or two sentence description of what this context is and why it exists.}
9
-
10
- ## Language
11
-
12
- **Order**:
13
- {A one or two sentence description of the term}
14
- _Avoid_: Purchase, transaction
15
-
16
- **Invoice**:
17
- A request for payment sent to a customer after delivery.
18
- _Avoid_: Bill, payment request
19
-
20
- **Customer**:
21
- A person or organization that places orders.
22
- _Avoid_: Client, buyer, account
23
- ```
24
-
25
- ## Rules
26
-
27
- - **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`.
28
- - **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does.
29
- - **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs.
30
- - **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine.
31
-
32
- ## Single vs multi-context repos
33
-
34
- **Single context (most repos):** One `GLOSSARY.md` at the repo root.
35
-
36
- **Multiple contexts:** A `GLOSSARY-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other:
37
-
38
- ```md
39
- # Glossary Map
40
-
41
- ## Contexts
42
-
43
- - [Ordering](./src/ordering/GLOSSARY.md): receives and tracks customer orders
44
- - [Billing](./src/billing/GLOSSARY.md): generates invoices and processes payments
45
- - [Fulfillment](./src/fulfillment/GLOSSARY.md): manages warehouse picking and shipping
46
-
47
- ## Relationships
48
-
49
- - **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking
50
- - **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices
51
- - **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money`
52
- ```
53
-
54
- The skill infers which structure applies:
55
-
56
- Resolve the root from project instructions before these checks; the current working directory may be a subproject. Use the project documentation hierarchy for ownership; the context map does not create separate record categories. Paths shown in the map are Markdown links relative to the map file.
57
-
58
- - If `GLOSSARY-MAP.md` exists, read it to find contexts
59
- - If only a root `GLOSSARY.md` exists, single context
60
- - If neither exists, create a root `GLOSSARY.md` lazily when the first term is resolved
61
-
62
- When multiple contexts exist, infer which one the current topic relates to. If unclear, ask.
63
-
64
-
@@ -1,47 +0,0 @@
1
- ---
2
- name: gate-domain-modeling
3
- description: Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a GLOSSARY.md, or recording a durable decision in its selected owner.
4
- user-invocable: false
5
- ---
6
-
7
- # Domain Modeling
8
-
9
- Actively build and sharpen the project's domain model as you design. This is the *active* discipline: challenging terms, inventing edge-case scenarios, and writing the glossary and decisions down the moment they crystallise. (Merely *reading* `GLOSSARY.md` for vocabulary is not this skill: that's a one-line habit any skill can do. This skill is for when you're changing the model, not just consuming it.)
10
-
11
- ## File structure
12
-
13
- Follow the document ownership entry referenced by project instructions for glossary paths and decisions applicable to the model being discussed. If a required input's owner or scope is unclear, report the configuration gap.
14
-
15
- Resolve the repository management root from project instructions, using the Git top-level only as a fallback. Working inside a subproject does not change it. A root `GLOSSARY-MAP.md` selects domain documents when the repository has multiple contexts. Do not create a separate record system per context or derive record categories automatically from contexts.
16
-
17
- A single-context project may use a root `GLOSSARY.md`. A root `GLOSSARY-MAP.md`, when present, points to the selected contexts' glossaries; context paths need not be under `src/`. Resolve decision paths separately from the document ownership entry and, for Agent Notes, its configured record roots. Create a glossary or decision record only when there is content for its selected owner. Use the `adr` skill when a separate architecture decision record is warranted.
18
-
19
- ## During the session
20
-
21
- ### Challenge against the glossary
22
-
23
- When the user uses a term that conflicts with the existing language in `GLOSSARY.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y. Which is it?"
24
-
25
- ### Sharpen fuzzy language
26
-
27
- When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account': do you mean the Customer or the User? Those are different things."
28
-
29
- ### Discuss concrete scenarios
30
-
31
- When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts.
32
-
33
- ### Cross-reference with code
34
-
35
- When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible. Which is right?"
36
-
37
- ### Update GLOSSARY.md inline
38
-
39
- When a term is resolved, update `GLOSSARY.md` right there. Don't batch these up: capture them as they happen. Use the format in [GLOSSARY-FORMAT.md](./GLOSSARY-FORMAT.md).
40
-
41
- `GLOSSARY.md` should be totally devoid of implementation details. Do not treat `GLOSSARY.md` as a spec, a scratch pad, or a repository for implementation decisions. It is a glossary and nothing else.
42
-
43
-
44
-
45
-
46
-
47
-