@menghuan1918/dsh-apollo 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +232 -2
  3. package/cordis.patch.yml +78 -0
  4. package/docs/DEVELOPMENT.md +629 -0
  5. package/package.json +75 -4
  6. package/presets/eng/NOTICE +2 -0
  7. package/presets/eng/plugins/exit-guard/index.js +111 -0
  8. package/presets/eng/plugins/exit-guard/package.json +7 -0
  9. package/presets/eng/plugins/mode-instructions/index.js +48 -0
  10. package/presets/eng/plugins/mode-instructions/package.json +7 -0
  11. package/presets/eng/plugins/wait-subagent/index.js +228 -0
  12. package/presets/eng/plugins/wait-subagent/package.json +7 -0
  13. package/presets/eng-noask/NOTICE +2 -0
  14. package/presets/eng-noask/plugins/exit-guard/index.js +111 -0
  15. package/presets/eng-noask/plugins/exit-guard/package.json +7 -0
  16. package/presets/eng-noask/plugins/mode-instructions/index.js +48 -0
  17. package/presets/eng-noask/plugins/mode-instructions/package.json +7 -0
  18. package/presets/eng-noask/plugins/wait-subagent/index.js +228 -0
  19. package/presets/eng-noask/plugins/wait-subagent/package.json +7 -0
  20. package/presets/eng-noask.patch.yml +341 -0
  21. package/presets/eng.patch.yml +341 -0
  22. package/skills/brainstorming/SKILL.md +90 -0
  23. package/skills/brainstorming/spec-document-reviewer-prompt.md +50 -0
  24. package/skills/code-review/SKILL.md +90 -0
  25. package/skills/dev/SKILL.md +43 -0
  26. package/skills/diagnosing-bugs/SKILL.md +132 -0
  27. package/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +55 -0
  28. package/skills/exec/SKILL.md +91 -0
  29. package/skills/handoff/SKILL.md +23 -0
  30. package/skills/main-agent-driven-development/SKILL.md +64 -0
  31. package/skills/tdd/SKILL.md +34 -0
  32. package/skills/tdd/mocking.md +59 -0
  33. package/skills/tdd/tests.md +77 -0
  34. package/src/cli/claude.js +166 -0
  35. package/src/cli/codex.js +164 -0
  36. package/src/cli/jsonl.js +216 -0
  37. package/src/cli-adapter.js +198 -0
  38. package/src/cli-sessions.js +69 -0
  39. package/src/client.js +815 -0
  40. package/src/config.js +301 -0
  41. package/src/dsh-home.js +38 -0
  42. package/src/index.js +181 -0
  43. package/src/panel.js +452 -0
  44. package/src/settings.js +191 -0
  45. package/src/subagents.js +199 -0
  46. package/third-party/LICENSE-MIT-dsh-standard-preset +21 -0
  47. package/third-party/NOTICE-mattpocock-skills +21 -0
@@ -0,0 +1,341 @@
1
+ # dsh-apollo bundle patch: the `eng` (工程模式) agent preset, declared as
2
+ # one `@deepseek-ai/dsh-agent-preset` insert row — the DSH 0.2.1 preset
3
+ # mechanism (the `<dshHome>/.agent-presets` scan root is gone; third-party
4
+ # presets ship as bundle-patch insert rows). Loaded after ./cordis.patch.yml
5
+ # per the `dsh.bundle.patch` array in package.json.
6
+ #
7
+ # The `config.plugins` block below is the single source of truth for the
8
+ # preset's row list; it supersedes the former presets/eng/agent.cordis.yml +
9
+ # preset.yml pair (metadata folded into `config`). `config.id` MUST stay
10
+ # `eng`: it is the preset identity historical sessions resume by.
11
+ #
12
+ # Preset-local plugin modules are referenced by bare package subpaths
13
+ # (`@menghuan1918/dsh-apollo/presets/eng/plugins/...`): names inside `config.plugins`
14
+ # resolve from the profile directory's node_modules (where this package is
15
+ # installed or linked; `exports["./presets/*"]` maps the subpath), not from
16
+ # the preset directory.
17
+
18
+ - insert:
19
+ - id: preset-eng
20
+ name: '@deepseek-ai/dsh-agent-preset'
21
+ config:
22
+ id: eng
23
+ name: 工程模式
24
+ description: >-
25
+ 面向编码与基础设施任务的工程 Agent:内置工程纪律、后台任务与子代理约定、由独立 goal 插件提供的长期目标续跑。
26
+ order: 10
27
+ plugins:
28
+ #
29
+ # This plugins block is an AGENT-PLANE composition. The roster mounts it ONCE under a
30
+ # standing scope; every session naming it joins by scope parentage, so the
31
+ # tools and prompt sections registered here cover each joined agent while a
32
+ # session's own state stays keyed per Session/Agent inside the plugins. The
33
+ # host composition (`base.cordis.yml` + `web.cordis.yml`) keeps everything a
34
+ # preset must not own: the registries themselves, the sandbox and approval
35
+ # stack, persistence, and the model route.
36
+ #
37
+ # A service row here MUST sit inside a group carrying an `isolate` realm.
38
+ # Without one it publishes into the root realm, where it is process-global —
39
+ # another preset publishing the same name collides, and a host reader would
40
+ # resolve one preset's instance for every session; `dsh-agent-preset` rejects
41
+ # that at mount. `true` means an entry-local realm: this standing mount's own
42
+ # private instance, apart from every other preset's. (A shared label does NOT
43
+ # pool instances — `provide()` throws on the second registration under the
44
+ # same realm symbol; labels join REALMS, and are not what this file needs.)
45
+
46
+ # ── identity ────────────────────────────────────────────────────────────────
47
+
48
+ # The preset's own persona, shadowing the deployment default for this agent.
49
+ # One row on purpose: the rich engineering rules live in the user-global
50
+ # instructions (~/.dsh/AGENTS.md) and the preset's `eng:mode-instructions`
51
+ # section, not in the persona. `eng:mode-instructions` owns the delegation
52
+ # policy; the tiers stay global because they track local route config.
53
+ # 0.2.1's upstream `standard` preset carries `prefix` only: the working-
54
+ # directory `suffix` line it used to set is gone, and eng follows suit.
55
+ - id: persona
56
+ name: '@deepseek-ai/dsh-persona'
57
+ config:
58
+ prefix: >-
59
+ You are a coding agent powered by the {{model}} model.
60
+
61
+ # Workspace instructions (repository AGENTS.md files) are injected from the
62
+ # first request, capped at 64 KiB.
63
+ - id: agent-instructions
64
+ name: '@deepseek-ai/dsh-agent-instructions'
65
+ config:
66
+ maxBytes: 65536
67
+
68
+ # 0.2.1 standard adds the per-step time context (sampled current time,
69
+ # browser time zone and elapsed time) so date/time reasoning does not depend
70
+ # on the model's own clock. It consumes host services and provides nothing,
71
+ # so it needs no realm.
72
+ - id: time-context
73
+ name: '@deepseek-ai/dsh-time-context'
74
+
75
+ # ── shell ───────────────────────────────────────────────────────────────────
76
+
77
+ # `shell-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
78
+ # publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
79
+ # the criterion for host-plane ownership — injection resolves before any session
80
+ # exists, so there is no agent to key by. Behind a preset realm those variables
81
+ # never reached the model's shell at all. Both shell tools consume the host
82
+ # registry from here; their executors (`bash-sandbox`/`pwsh-sandbox`) are
83
+ # host-plane too.
84
+ - id: tool-bash
85
+ name: '@deepseek-ai/dsh-tool-bash'
86
+ disabled: !!js process.platform === 'win32'
87
+
88
+ - id: tool-pwsh
89
+ name: '@deepseek-ai/dsh-tool-pwsh'
90
+ disabled: !!js process.platform !== 'win32'
91
+
92
+ # ── filesystem ──────────────────────────────────────────────────────────────
93
+
94
+ # Both register into the host `tools` registry and provide nothing, so
95
+ # they need no realm. The `fs` service and its policy stay in the host.
96
+ - id: tool-fs
97
+ name: '@deepseek-ai/dsh-tool-fs'
98
+
99
+ - id: tool-fs-search
100
+ name: '@deepseek-ai/dsh-tool-fs-search'
101
+ config:
102
+ sampleOverCapGlobResults: false
103
+
104
+ # ── background jobs ────────────────────────────────────────────────────────
105
+
106
+ # Only the model-facing controls. The task REGISTRY stays on the host plane:
107
+ # its producers sit outside any realm this file could put it in — `tool-bash`
108
+ # above resolves it with `ctx.get`, and an entry-local realm here is invisible
109
+ # to every sibling row, so `run_in_background` would answer "background jobs
110
+ # unavailable" while these controls sat in the catalog. The registry is keyed by
111
+ # owning agent anyway, so one host instance serves every session. What a preset
112
+ # chooses is whether its agent can collect and stop background work at all.
113
+ #
114
+ # LOCAL OVERRIDE (2026-09-22): `maxConsecutiveWakes` is 5000 instead of the
115
+ # bundled 3. The budget is spent by every completion that opens a turn on an
116
+ # idle owner and is restored ONLY by a user-authored message, so a long
117
+ # unattended chain of background jobs parks after its third wake — from the
118
+ # fourth completion on, the notice degrades to injection and waits for the
119
+ # user's next input. Keep this value identical in the eng-noask patch (the
120
+ # upstream-drift test compares same-id row configs); upstream `standard`
121
+ # ships no such key, and the drift test whitelists exactly this delta.
122
+ - id: tool-jobs
123
+ name: '@deepseek-ai/dsh-tool-jobs'
124
+ config:
125
+ maxConsecutiveWakes: 5000
126
+
127
+ # The automation-task tools (schedule_create/list/update/delete) are
128
+ # deliberately omitted from engineering mode: coding/infrastructure work
129
+ # does not need scheduled reminders. The host `schedule` service and the
130
+ # sidebar Automation page stay available to other presets.
131
+
132
+ # ── skills ──────────────────────────────────────────────────────────────────
133
+
134
+ # The skill REGISTRY lives in the host composition and is layered per scope:
135
+ # these rows register into THIS preset's layer of it, so they need no realm.
136
+ # `skill-filesystem` contributes local-root discovery for agents on this preset, and
137
+ # `tool-skill` gives them the catalog and loader; the merged catalog also
138
+ # carries whatever the deployment registered globally (repository plugins).
139
+ - id: skill-filesystem
140
+ name: '@deepseek-ai/dsh-skill-filesystem'
141
+
142
+ - id: tool-skill
143
+ name: '@deepseek-ai/dsh-tool-skill'
144
+
145
+ # ── goals ───────────────────────────────────────────────────────────────────
146
+
147
+ # Native command-goal/tool-goal rows are deliberately omitted. The goal
148
+ # domain is owned by the independent dsh-better-goal plugin row in the
149
+ # top-level patch: it registers one `goal` tool and one `/goal` command
150
+ # per Agent, hides any legacy goal tools a preset still carries, and has
151
+ # its own Plugins row for round limits and question timeouts. The two
152
+ # removed rows remain deliberate removals in tests/upstream-drift.test.mjs,
153
+ # which asserts they still exist upstream before filtering them out.
154
+
155
+ # ── plan mode ───────────────────────────────────────────────────────────────
156
+
157
+ # Plan state is per-agent by nature, so an entry-local realm is not a
158
+ # workaround here — it is the correct lifetime.
159
+ - id: planning
160
+ name: cordis:group
161
+ group: true
162
+ isolate:
163
+ planMode: true
164
+ config:
165
+ - id: plan-mode
166
+ name: '@deepseek-ai/dsh-plan-mode'
167
+ config:
168
+ section: |
169
+ You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode or switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
170
+
171
+ Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
172
+
173
+ The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
174
+
175
+ Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
176
+
177
+ Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
178
+
179
+ When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
180
+
181
+ # ── compaction ──────────────────────────────────────────────────────────────
182
+
183
+ # `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
184
+ # share this realm rather than sit outside it.
185
+ #
186
+ # `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
187
+ # plane, and the rows here resolve that one instance. It takes no configuration,
188
+ # keys every fold by Session, and owns the context-meter projection units the
189
+ # browser reads for every session — behind a realm those units would come and go
190
+ # with whichever presets happen to be mounted. What a preset chooses is whether
191
+ # its agent compacts at all, which is `compaction-basic` below.
192
+ - id: compaction
193
+ name: cordis:group
194
+ group: true
195
+ isolate:
196
+ compaction: true
197
+ toolResultPruner: true
198
+ config:
199
+ - id: compaction-basic
200
+ name: '@deepseek-ai/dsh-compaction-basic'
201
+
202
+ - id: command-compact
203
+ name: '@deepseek-ai/dsh-command-compact'
204
+
205
+ - id: tool-result-pruner
206
+ name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
207
+ config:
208
+ # Deliberately 2x the upstream `standard` preset (8192/4096/1024): eng
209
+ # sessions emit large build/test/log tool results, and the extra
210
+ # head/tail retention preserves the failure context the agent acts on.
211
+ thresholdChars: 16384
212
+ headChars: 8192
213
+ tailChars: 2048
214
+
215
+ # ── delegation and workflows ────────────────────────────────────────────────
216
+
217
+ # The `subagents` registry and its spawn/fork backends live in the HOST
218
+ # composition: the registry is a process singleton whose cross-session queries
219
+ # the api-proxy serves to the browser, and a provider name may only be
220
+ # registered once. This preset contributes the delegation TOOLS, which resolve
221
+ # that host registry.
222
+ #
223
+ # `workflows` is different — nothing outside an agent reads it — so every row
224
+ # that reaches it shares one entry-local realm here, and a consumer left
225
+ # outside would resolve a host registry this preset does not populate.
226
+ #
227
+ # 0.1.2-alpha.4 note: the one-way child `report` tool is gone — parent/child
228
+ # messaging now rides the globally named `send_message` registered by
229
+ # `tool-subagent-control` below (children inherit it too), so this preset
230
+ # mounts no messaging row of its own.
231
+ - id: delegation
232
+ name: cordis:group
233
+ group: true
234
+ isolate:
235
+ workflowEngine: true
236
+ config:
237
+ - id: tool-subagent-control
238
+ name: '@deepseek-ai/dsh-tool-subagent-control'
239
+
240
+ - id: tool-subagent-list-agents
241
+ name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
242
+
243
+ - id: tool-subagent
244
+ name: '@deepseek-ai/dsh-tool-subagent'
245
+ config:
246
+ provider: spawn
247
+ toolName: subagent
248
+ modelSelectionSettings: true
249
+
250
+ # Fork omits model selection so provider/model stay equal to the parent and
251
+ # the inherited history remains eligible for KV Cache reuse.
252
+ - id: tool-subagent-fork
253
+ name: '@deepseek-ai/dsh-tool-subagent'
254
+ config:
255
+ provider: fork
256
+ toolName: subagent_fork
257
+
258
+ # 0.1.6-alpha.2 renamed `dsh-workflow-worker-thread` to `dsh-workflow-ptc`
259
+ # (workflow orchestration in the shared sandboxed Node PTC runtime).
260
+ - id: workflow-ptc
261
+ name: '@deepseek-ai/dsh-workflow-ptc'
262
+ config:
263
+ provider: spawn
264
+
265
+ - id: tool-workflow
266
+ name: '@deepseek-ai/dsh-tool-workflow'
267
+
268
+ # ── remaining model-facing rows ─────────────────────────────────────────────
269
+
270
+ - id: tool-ask-user
271
+ name: '@deepseek-ai/dsh-tool-ask-user'
272
+
273
+ - id: tool-todo
274
+ name: '@deepseek-ai/dsh-tool-todo'
275
+ config:
276
+ allowParallelInProgress: true
277
+
278
+ # The `web` service and its search/fetch providers stay in the host
279
+ # composition; only the model-facing tool is per-session. `fetch` reads the
280
+ # host-mounted SSRF-guarded `web-fetch-http` provider.
281
+ - id: tool-web
282
+ name: '@deepseek-ai/dsh-tool-web'
283
+ config:
284
+ fetch: true
285
+ searchTimeoutMs: 60000
286
+
287
+ # Declares deliverable files to the user (file-card surface). Upstream
288
+ # `standard` mounts it; eng is a fork-copy of that block, so this row has to be
289
+ # carried by hand — `tests/upstream-drift.test.mjs` fails when a shipped
290
+ # preset gains rows that eng never picked up.
291
+ - id: present
292
+ name: '@deepseek-ai/dsh-tool-present'
293
+
294
+ # 0.2.1 ships both plugin surfaces disabled by default; enable either only in a
295
+ # copy of this plugins block (edits saved from the Web editor override
296
+ # config.plugins by row id from the profile patch).
297
+ - id: tool-plugin-manager
298
+ name: '@deepseek-ai/dsh-plugin-manager/tools'
299
+ disabled: true
300
+
301
+ - id: tool-plugin-market
302
+ name: '@deepseek-ai/dsh-plugin-market/tools'
303
+ disabled: true
304
+
305
+ # ── subagent waiting ─────────────────────────────────────────────────────────
306
+
307
+ # Preset-local plugin: explicit wait for one continuable child to settle, so
308
+ # the agent can block on a specific subagent (pi-style await_task semantics)
309
+ # without giving up send_message continuations. The module specifier is a
310
+ # bare subpath of this package (@menghuan1918/dsh-apollo/presets/eng/plugins/...):
311
+ # config.plugins names resolve from the profile directory's node_modules,
312
+ # where this package is installed or linked; it has zero bare imports on
313
+ # purpose.
314
+ - id: tool-wait-subagent
315
+ name: '@menghuan1918/dsh-apollo/presets/eng/plugins/wait-subagent/index.js'
316
+
317
+ # ── exit guard ───────────────────────────────────────────────────────────────
318
+ #
319
+ # Preset-local plugin: pi-atlas 式退出守卫。回合结束(agent/turn-stopping)
320
+ # 时若有运行中的直接子代理或后台任务,注入 next-step 提醒(agent.steer)
321
+ # 强制回合继续,直到 wait_subagent / job_output / job_kill 处理完毕或用户
322
+ # 中断(被中断回合不触发)。开关为正式 Config.exitGuard,默认关闭,
323
+ # 每次事件读取当前值,设置保存后即时生效。监听器注册型
324
+ # 插件,无服务发布,无需 realm。
325
+ - id: eng-exit-guard
326
+ name: '@menghuan1918/dsh-apollo/presets/eng/plugins/exit-guard/index.js'
327
+
328
+ # ── mode instructions ────────────────────────────────────────────────────────
329
+
330
+ # Preset-local prompt section carrying the two eng-only rules: the exit guard
331
+ # contract and the delegation/orchestration policy (the latter moved out of the
332
+ # user-global ~/.dsh/AGENTS.md on 2026-09-11 — the model tiers stay there
333
+ # because they mirror this host's `subagent-model-selection` route list).
334
+ # Registered as a system-prompt section (order 1, right after the persona slot)
335
+ # so it is scoped to sessions mounted on this preset and nothing else; injected
336
+ # from the first request alongside the other sections.
337
+ # This plugins block (presets/eng.patch.yml) is the single source of truth;
338
+ # the 0.2.1 bundle-patch mechanism loads it straight from this file, with no
339
+ # boot-time copy in between.
340
+ - id: eng-mode-instructions
341
+ name: '@menghuan1918/dsh-apollo/presets/eng/plugins/mode-instructions/index.js'
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: brainstorming
3
+ description: "把大型需求设计为多个协同 Spec。仅当用户显式调用 /brainstorming,或要求把大型任务拆分为可执行 Spec 时使用。"
4
+ ---
5
+
6
+ # 大型任务头脑风暴
7
+
8
+ 把大型需求整理为一个获批的主 Spec 和至少两个可执行子 Spec。保持 KISS:只沿真实的职责、依赖或验证边界拆分。
9
+
10
+ **终态是交接给 `/exec`。** 不得实现功能、创建 worktree 或调用开发技能。用户批准书面 Spec 后停止。
11
+
12
+ ## 流程
13
+
14
+ 1. **探索项目上下文** — 检查文件、文档和当前项目状态。事实自己查,不问用户。
15
+ 2. **逐一提问** — 每条消息只问一个决策问题,系统遍历设计树,每个问题以推荐答案开头。区分事实(自行查明)与决策(用户定夺)。详见下文提问规则。
16
+ 3. **给出 2-3 个方案** — 含权衡和推荐,以推荐方案开头。
17
+ 4. **分段展示设计** — 按复杂度决定每段长度,每段取得用户确认。需拆分时展示拆分方案(主 Spec + 子 Spec、依赖顺序、共享契约、集成验收)。
18
+ 5. **写入全部 Spec** — 写盘后自审(占位符、矛盾、歧义、过度细节),内联修复。详见下文自审。
19
+ 6. **派 spec-reviewer 审查** — 按 [`spec-document-reviewer-prompt.md`](spec-document-reviewer-prompt.md) 派一个全新只读 `subagent`(质量档 = 本会话最强模型)审查主 Spec 与全部子 Spec;修复阻塞项,必要时复派。
20
+ 7. **请用户审阅** — 按反馈修改直至批准。
21
+ 8. **交接给 `/exec`** — 告知用户用主 Spec 路径调用 `/exec`。
22
+
23
+ 完成标准:主 Spec + 全部子 Spec 已写入磁盘,用户已批准,已给出 `/exec` 调用方式。
24
+
25
+ ## 提问规则
26
+
27
+ - **每条消息只问一个问题。** 等用户反馈再继续。一次问多个会导致混乱。
28
+ - **给出推荐答案。** 附推理,用户可接受、拒绝或修改。
29
+ - **事实 vs 决策。** 事实查代码库或文档获得,不问用户;决策展示给用户等待回答。
30
+ - **优先多选题**,开放式问题也可以。
31
+ - **聚焦理解:** 目标、约束、成功标准、架构、错误处理、测试。
32
+
33
+ 共识达成前不写 Spec。后续答案改变前提时,回头修正既有决定。
34
+
35
+ ## 设计粒度
36
+
37
+ 子 Spec 定义**做什么和为什么**,以及独立实现和验证所需的边界。不是实现食谱。(主 Spec 不在此列——它只是目标 + 索引,见拆分准则。)
38
+
39
+ - 包含目标、范围、关键决策、组件职责、交互、外部可观察行为、错误语义、验收标准、测试范围。
40
+ - 把局部编码选择留给实现。不含代码、伪代码、私有类型设计、逐文件修改清单、分步指令。
41
+ - 精确的公共契约(API 路由、共享 schema、配置键)仅在兼容性或迁移依赖时写入。
42
+
43
+ ## 拆分准则
44
+
45
+ 主 Spec 只承载总目标 + 索引(见下文多 Spec 结构),不承载任何具体执行内容。**鼓励多写子 Spec**——任务有几个独立单元就拆几个,下限两个,但更细的拆分只要每个子 Spec 仍能独立实现、独立验证就值得。每个子 Spec 必须能独立实现、独立测试,适合独立的 Spec → 实现周期。
46
+
47
+ **拆分有价值时:** 任务确实复杂,有多个独立子系统或可并行轨道;每个子 Spec 接口清晰;拆分提升清晰度而非仅为并行。
48
+
49
+ **过度拆分信号:** 子 Spec 间循环依赖;无法独立验证;共享契约多处不一致;拆出无独立职责的子 Spec。
50
+
51
+ 质量优先于并行——为清晰而拆分,不仅为了并行执行。
52
+
53
+ ## 多 Spec 结构
54
+
55
+ ### 主 Spec
56
+
57
+ **只做总目标 + 索引,不承载执行。** 内容限于:总目标、范围与非目标、子 Spec 索引(每个子 Spec 一行:职责 + 路径)、依赖 DAG 与并行分组、整体验收的指向。关键决策、共享契约、组件职责、交互、错误语义等具体内容一律下沉到子 Spec;主 Spec 只指明每个契约由哪个子 Spec 定义/拥有。不得在主 Spec 里实现任何东西。
58
+
59
+ ### 子 Spec
60
+
61
+ 独立实现、审查、测试和提交所需:边界明确的目标、范围内/外行为、依赖、输入输出和共享契约、错误语义、验收标准、聚焦验证范围、指向主 Spec 的链接。不复制主 Spec,只带入执行所需契约。
62
+
63
+ ## 文件布局
64
+
65
+ 落盘位置按工作区实际情况择一,不要两处都写:
66
+
67
+ ```text
68
+ <工作区>/.workspace-docs/specs/MM-DD-<主题>-主设计/ # 工作区有 .workspace-docs/ 时用它
69
+ <目标仓库>/docs/specs/MM-DD-<主题>-主设计/ # 否则用目标仓库自己的 specs 目录
70
+ ├── MM-DD-<主题>-主设计.md
71
+ ├── MM-DD-<主题>-<子任务A>-设计.md
72
+ └── MM-DD-<主题>-<子任务B>-设计.md
73
+ ```
74
+
75
+ - 主 Spec 与子 Spec 双向链接。
76
+ - 目录内已有其它 Spec 时,沿用其文件名与头格式,不引入第二套约定。
77
+ - 写入 `.workspace-docs/` 时每篇带 OKF 头部(`type: Design Spec`、`title`、`description`、`tags`、`status`、`repos`);提交推送遵循该仓库自己的 `AGENTS.md`。目标仓库无此约定时用仓库现有文档格式,不新造 OKF。
78
+
79
+ ## 自审
80
+
81
+ 写入后用新鲜眼光检查:占位符(`TODO`/`TBD`)、内部一致性、范围聚焦、歧义、过度细节。内联修复全部问题。这是自己先过一遍;随后派 spec-reviewer 子代理做独立审查(流程第 6 步)。
82
+
83
+ ## 可视化辅助
84
+
85
+ 当展示优于讲述(mockup、布局、架构图、方案对比)时,写一个自包含 HTML 到系统临时目录(`$TMPDIR`,未设置时 `/tmp`),文件名 `brainstorm-<主题>-<序号>.html`:
86
+
87
+ - 用 write 工具写完整文档:内联 CSS、无外部依赖、无脚本、无服务;每页 2-4 个选项或变体。
88
+ - 文件名不复用;迭代就写新文件(`-2`、`-3`)。
89
+ - 告知用户文件路径(DSH 界面可直接打开预览),并用一两句话概括页面内容;用户看后回到对话作答,不采集点击。
90
+ - 每个问题独立判断是否需要可视化;概念性选择(A/B/C 方案、取舍清单)留在对话里。
@@ -0,0 +1,50 @@
1
+ # Spec Document Reviewer Prompt Template
2
+
3
+ Use this template when dispatching a spec document reviewer via the `subagent` tool (fresh read-only child, quality tier = the strongest model this session offers; omit provider/model to inherit the parent route).
4
+
5
+ **Purpose:** Verify a main decomposition spec or child spec is complete, consistent, and ready for implementation.
6
+
7
+ **Dispatch after:** Spec document is written to the workspace's spec directory (`.workspace-docs/specs/` where that convention exists, otherwise the target repo's own specs directory).
8
+
9
+ ```
10
+ subagent(
11
+ prompt="You are a spec document reviewer. Verify this spec is complete and ready for implementation.
12
+
13
+ **Spec to review:** [SPEC_FILE_PATH]
14
+ **Spec type:** [main decomposition | child]
15
+ **Main spec, if this is a child spec:** [MAIN_SPEC_FILE_PATH or N/A]
16
+
17
+ ## What to Check
18
+
19
+ | Category | What to Look For |
20
+ |----------|------------------|
21
+ | Frontmatter | Where the workspace uses OKF: parseable YAML frontmatter with `type: Design Spec`, `title`, `description`, `tags`, `status`, and `repos` (plural `tags`, never a singular `tag`). Where it does not: the header matches the surrounding specs instead |
22
+ | Completeness | TODOs, placeholders, "TBD", incomplete sections |
23
+ | Consistency | Internal contradictions, conflicting requirements |
24
+ | Clarity | Requirements ambiguous enough to cause someone to build the wrong thing |
25
+ | Scope | Main specs decompose large work into child specs; child specs are independently implementable and do not try to implement the whole main spec |
26
+ | YAGNI | Unrequested features, over-engineering |
27
+
28
+ ## Calibration
29
+
30
+ **Only flag issues that would cause real problems during implementation.**
31
+ A missing section, a contradiction, or a requirement so ambiguous it could be
32
+ interpreted two different ways — those are issues. Minor wording improvements,
33
+ stylistic preferences, and "sections less detailed than others" are not.
34
+
35
+ Approve unless there are serious gaps that would lead to a flawed implementation. Do not reject a main decomposition spec merely because it covers multiple subsystems; reject it only if it lacks clear child specs, ordering, boundaries, or shared contracts. Do not reject a child spec merely because it does not implement the whole main spec.
36
+
37
+ ## Output Format
38
+
39
+ ## Spec Review
40
+
41
+ **Status:** Approved | Issues Found
42
+
43
+ **Issues (if any):**
44
+ - [Section X]: [specific issue] - [why it matters for implementation]
45
+
46
+ **Recommendations (advisory, do not block approval):**
47
+ - [suggestions for improvement]
48
+ ```
49
+
50
+ **Reviewer returns:** Status, Issues (if any), Recommendations
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: code-review
3
+ description: Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes — Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the originating issue/PRD asked for?). Runs both reviews as parallel `subagent` delegations and reports them side by side. Use when the user wants to review a branch, a PR, work-in-progress changes, or asks to "review since X".
4
+ ---
5
+
6
+ # Code Review
7
+
8
+ Two-axis review of the diff between `HEAD` and a fixed point the user supplies:
9
+
10
+ - **Standards** — does the code conform to this repo's documented coding standards?
11
+ - **Spec** — does the code faithfully implement the originating issue / PRD / spec?
12
+
13
+ Both axes run as parallel `subagent` delegations so they don't pollute each other's context, then this skill aggregates their findings.
14
+
15
+ ## Process
16
+
17
+ ### 1. Pin the fixed point
18
+
19
+ Whatever the user said is the fixed point — a commit SHA, branch name, tag, `main`, `HEAD~5`, etc. If they didn't specify one, ask for it.
20
+
21
+ Capture the diff command once: `git diff <fixed-point>...HEAD` (three-dot, so the comparison is against the merge-base). Also note the list of commits via `git log <fixed-point>..HEAD --oneline`.
22
+
23
+ Before going further, confirm the fixed point resolves (`git rev-parse <fixed-point>`) and the diff is non-empty. A bad ref or empty diff should fail here — not inside two parallel agents.
24
+
25
+ ### 2. Identify the spec source
26
+
27
+ Look for the originating spec, in this order:
28
+
29
+ 1. Issue references in the commit messages (`#123`, `Closes #45`, GitLab `!67`, etc.)
30
+ 2. A path the user passed as an argument.
31
+ 3. A spec/PRD file under `docs/`, `specs/`, `.workspace-docs/`, or `.scratch/` matching the branch name or feature.
32
+ 4. If nothing is found, ask the user where the spec is. If they say there isn't one, the **Spec** agent will skip and report "no spec available".
33
+
34
+ ### 3. Identify the standards sources
35
+
36
+ Anything in the repo that documents how code should be written, such as `CODING_STANDARDS.md`, `CONTRIBUTING.md`, `CLAUDE.md`, or `AGENTS.md`.
37
+
38
+ On top of whatever the repo documents, the Standards axis always carries the **smell baseline** below — a fixed set of Fowler code smells (_Refactoring_, ch.3) that applies even when a repo documents nothing. Two rules bind it:
39
+
40
+ - **The repo overrides.** A documented repo standard always wins; where it endorses something the baseline would flag, suppress the smell.
41
+ - **Always a judgement call.** Each smell is a labelled heuristic ("possible Feature Envy"), never a hard violation — and, like any standard here, skip anything tooling already enforces.
42
+
43
+ Each smell reads *what it is* → *how to fix*; match it against the diff:
44
+
45
+ - **Mysterious Name** — a function, variable, or type whose name doesn't reveal what it does or holds. → rename it; if no honest name comes, the design's murky.
46
+ - **Duplicated Code** — the same logic shape appears in more than one hunk or file in the change. → extract the shared shape, call it from both.
47
+ - **Feature Envy** — a method that reaches into another object's data more than its own. → move the method onto the data it envies.
48
+ - **Data Clumps** — the same few fields or params keep travelling together (a type wanting to be born). → bundle them into one type, pass that.
49
+ - **Primitive Obsession** — a primitive or string standing in for a domain concept that deserves its own type. → give the concept its own small type.
50
+ - **Repeated Switches** — the same `switch`/`if`-cascade on the same type recurs across the change. → replace with polymorphism, or one map both sites share.
51
+ - **Shotgun Surgery** — one logical change forces scattered edits across many files in the diff. → gather what changes together into one module.
52
+ - **Divergent Change** — one file or module is edited for several unrelated reasons. → split so each module changes for one reason.
53
+ - **Speculative Generality** — abstraction, parameters, or hooks added for needs the spec doesn't have. → delete it; inline back until a real need shows.
54
+ - **Message Chains** — long `a.b().c().d()` navigation the caller shouldn't depend on. → hide the walk behind one method on the first object.
55
+ - **Middle Man** — a class or function that mostly just delegates onward. → cut it, call the real target direct.
56
+ - **Refused Bequest** — a subclass or implementer that ignores or overrides most of what it inherits. → drop the inheritance, use composition.
57
+
58
+ ### 4. Spawn both sub-agents in parallel
59
+
60
+ Send both `subagent` calls in a single message — each a fresh child (quality tier = the strongest model this session offers; omit provider/model to inherit the parent route) with a fully self-contained prompt; children see none of this conversation.
61
+
62
+ **Standards sub-agent prompt** — include:
63
+
64
+ - The full diff command and commit list.
65
+ - The list of standards-source files you found in step 3, **plus the smell baseline from step 3** pasted in full — the sub-agent has no other access to it.
66
+ - The brief: "Report — per file/hunk where relevant — (a) every place the diff violates a documented standard: cite the standard (file + the rule); and (b) any baseline smell you spot: name it and quote the hunk. Distinguish hard violations from judgement calls — documented-standard breaches can be hard, but baseline smells are always judgement calls, and a documented repo standard overrides the baseline. Skip anything tooling enforces. Under 400 words."
67
+
68
+ **Spec sub-agent prompt** — include:
69
+
70
+ - The diff command and commit list.
71
+ - The path or fetched contents of the spec.
72
+ - The brief: "Report: (a) requirements the spec asked for that are missing or partial; (b) behaviour in the diff that wasn't asked for (scope creep); (c) requirements that look implemented but where the implementation looks wrong. Quote the spec line for each finding. Under 400 words."
73
+
74
+ If the spec is missing, skip the Spec agent and note this in the final report.
75
+
76
+ ### 5. Aggregate
77
+
78
+ Present the two reports under `## Standards` and `## Spec` headings, verbatim or lightly cleaned. Do **not** merge or rerank findings — the two axes are deliberately separate.
79
+
80
+ End with a one-line summary: total findings per axis, and the worst issue _within each axis_ (if any).
81
+
82
+ ## Handling review feedback
83
+
84
+ When you receive feedback from a review:
85
+
86
+ 1. **Verify before implementing.** Check each finding against the codebase — does it break existing functionality? Is the reviewer missing context? Is the current implementation intentional?
87
+ 2. **Push back with reasoning** when a finding is wrong — reference working code, tests, or architectural decisions.
88
+ 3. **No performative agreement.** State the fix, not "Great point!" or "You're absolutely right!" — just fix it and show the result.
89
+ 4. **YAGNI check.** When a reviewer suggests "implementing properly", grep for actual usage. If unused, propose removal instead.
90
+ 5. **Fix in order:** blocking issues → simple fixes → complex fixes. Test each fix individually.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: dev
3
+ description: "DSH 执行后端的节点契约:实现节点与审查节点的 prompt 要求、报告 schema 与失败语义。"
4
+ ---
5
+
6
+ # 内置开发后端(节点契约)
7
+
8
+ 本技能定义执行后端的两类节点。波次编排(worktree、合并、清理、CR 循环调度)归 `/exec`;本技能不得创建、合并或删除 worktree。子代理没有独立工作目录,也看不到编排会话:节点的一切输入靠 prompt 自带(worktree 绝对路径、Spec 路径、共享契约、验证命令),bash 一律 `workdir`、文件工具一律绝对路径。
9
+
10
+ 「质量档」指本会话可用的最强模型;不指定路由时子代理继承父会话的 provider/model,具体档位由调用方的会话配置决定,本技能不写死供应商。
11
+
12
+ ## 实现节点(develop)
13
+
14
+ 一个全新子代理(质量档)处理恰好一个子 Spec,以预建 worktree 模式遵循 `main-agent-driven-development`(在 `/exec` 的 workflow 波次中跳过其内部 CR 步骤——CR 循环由编排脚本承担,节点不自行派 reviewer)。
15
+
16
+ 报告 schema(结构化输出):
17
+
18
+ ```js
19
+ {
20
+ status: 'complete' | 'blocked',
21
+ commit: '<最终 commit SHA>',
22
+ verification: '<本轮已跑的验证命令与结果>',
23
+ summary: '<实现摘要,供 reviewer 与编排器使用>',
24
+ blocker: '<status=blocked 时必填>'
25
+ }
26
+ ```
27
+
28
+ ## 审查节点(review-only)
29
+
30
+ 全新只读子代理(质量档)。prompt 自带:worktree 绝对路径、diff 范围、Spec 路径、实现摘要、已跑验证。四态判定 schema:
31
+
32
+ ```js
33
+ {
34
+ status: 'APPROVED' | 'APPROVED_WITH_NOTES' | 'CHANGES_REQUIRED' | 'BLOCKED',
35
+ findings: ['<问题,附文件与行号>']
36
+ }
37
+ ```
38
+
39
+ 严重正确性错误、Spec 缺口、集成风险、安全问题或缺失验证必须 `CHANGES_REQUIRED`。不得编辑、提交、合并。
40
+
41
+ ## 失败语义
42
+
43
+ 子代理失败(error / 空返回)= `node-failed`;`blocked`、超时、部分回复或未提交的结果均不得视为完成。调用方决定重派,或仅在对同一子 Spec 解除阻塞时用 `send_message` 续谈。不得复用节点处理其他子 Spec。