@quill507/dsh-orchestrator-preset 0.1.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.
@@ -0,0 +1,399 @@
1
+ # Generated by tools/gen-cordis-patch.mjs — DO NOT EDIT BY HAND.
2
+ # Source of truth: tools/preset-declaration.mjs
3
+ # Regenerate: node tools/gen-cordis-patch.mjs
4
+ # Shell source: kind=dump-config fallback=yes bash=false @258 pwsh=true @262 normalized-digest=9d6e78b51fc4 (absolute path and raw md5 intentionally omitted; digest is path-normalized)
5
+ #
6
+ # This file's `plugins[]` rows are declared in full because DSH agent presets
7
+ # have no inheritance or composition mechanism (see DESIGN.md §2.1).
8
+ # Rows marked [official] below are configuration derived from DeepSeek Harness
9
+ # (MIT License, Copyright (c) 2026 DeepSeek); see LICENSE for the attribution.
10
+ - insert:
11
+ - id: preset-dsh-orchestrator-preset
12
+ name: '@deepseek-ai/dsh-agent-preset'
13
+ config:
14
+ id: 'dsh-orchestrator-preset'
15
+ name: 'DSH Orchestrator Preset'
16
+ description: |-
17
+ A thin orchestration preset: aegis method pack for methodology, self-authored lane boundaries for delegation. Declares its full plugins[] because DSH presets have no inheritance.
18
+ plugins:
19
+ - id: persona
20
+ name: '@quill507/dsh-orchestrator-preset/plan-aware-persona.mjs'
21
+ config:
22
+ suffix: 'Your working directory is {{cwd}}.'
23
+ - id: routing-sections
24
+ name: '@quill507/dsh-orchestrator-preset/routing-sections.mjs'
25
+ - id: lane-composition
26
+ name: '@quill507/dsh-orchestrator-preset/lane-composition.mjs'
27
+ - id: agent-instructions
28
+ name: '@deepseek-ai/dsh-agent-instructions'
29
+ config:
30
+ maxBytes: 65536
31
+ - id: tool-bash
32
+ name: '@deepseek-ai/dsh-tool-bash'
33
+ disabled: !!js process.platform === 'win32'
34
+ - id: tool-pwsh
35
+ name: '@deepseek-ai/dsh-tool-pwsh'
36
+ disabled: !!js process.platform !== 'win32'
37
+ - id: tool-fs
38
+ name: '@deepseek-ai/dsh-tool-fs'
39
+ - id: tool-fs-search
40
+ name: '@deepseek-ai/dsh-tool-fs-search'
41
+ config:
42
+ sampleOverCapGlobResults: false
43
+ - id: tool-jobs
44
+ name: '@deepseek-ai/dsh-tool-jobs'
45
+ - id: skill-filesystem
46
+ name: '@deepseek-ai/dsh-skill-filesystem'
47
+ - id: tool-skill
48
+ name: '@deepseek-ai/dsh-tool-skill'
49
+ - id: tool-ask-user
50
+ name: '@deepseek-ai/dsh-tool-ask-user'
51
+ - id: tool-todo
52
+ name: '@deepseek-ai/dsh-tool-todo'
53
+ config:
54
+ allowParallelInProgress: true
55
+ - id: tool-web
56
+ name: '@deepseek-ai/dsh-tool-web'
57
+ config:
58
+ fetch: true
59
+ searchTimeoutMs: 60000
60
+ - id: planning
61
+ name: cordis:group
62
+ group: true
63
+ isolate:
64
+ planMode: true
65
+ config:
66
+ - id: plan-mode
67
+ name: '@deepseek-ai/dsh-plan-mode'
68
+ config:
69
+ section: |
70
+ You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user 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.
71
+
72
+ 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.
73
+
74
+ 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.
75
+
76
+ 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.
77
+
78
+ 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.
79
+
80
+ 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.
81
+ - id: compaction
82
+ name: cordis:group
83
+ group: true
84
+ isolate:
85
+ compaction: true
86
+ toolResultPruner: true
87
+ config:
88
+ - id: compaction-basic
89
+ name: '@deepseek-ai/dsh-compaction-basic'
90
+ - id: command-compact
91
+ name: '@deepseek-ai/dsh-command-compact'
92
+ - id: tool-result-pruner
93
+ name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
94
+ config:
95
+ thresholdChars: 8192
96
+ headChars: 4096
97
+ tailChars: 1024
98
+ - id: delegation
99
+ name: cordis:group
100
+ group: true
101
+ config:
102
+ - id: tool-subagent-control
103
+ name: '@deepseek-ai/dsh-tool-subagent-control'
104
+ - id: tool-subagent-list-agents
105
+ name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
106
+ - id: tool-subagent-fork
107
+ name: '@deepseek-ai/dsh-tool-subagent'
108
+ config:
109
+ provider: fork
110
+ toolName: subagent_fork
111
+ backgroundMode: continuable
112
+ - id: tool-subagent-scout
113
+ name: '@deepseek-ai/dsh-tool-subagent'
114
+ config:
115
+ provider: spawn
116
+ toolName: subagent_scout
117
+ backgroundMode: continuable
118
+ maxDepth: 1
119
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/scout.md'), 'utf8')
120
+ toolFilter:
121
+ deny:
122
+ - write
123
+ - edit
124
+ - todo_write
125
+ - ask_user_question
126
+ - exit_plan_mode
127
+ - send_message
128
+ - interrupt_agent
129
+ - list_agents
130
+ - subagent_children
131
+ - subagent_send
132
+ - subagent_interrupt
133
+ - subagent_fork
134
+ - subagent_scout
135
+ - subagent_archivist
136
+ - subagent_seer
137
+ - subagent_reader
138
+ - subagent_analyst
139
+ - subagent_auditor
140
+ - subagent_wright
141
+ - subagent_forge
142
+ - subagent_planner
143
+ - mcp_playwright
144
+ - mcp_jlceda
145
+ - mcp_cloudflare-browser
146
+ - mcp_desktop-touch
147
+ - id: tool-subagent-archivist
148
+ name: '@deepseek-ai/dsh-tool-subagent'
149
+ config:
150
+ provider: spawn
151
+ toolName: subagent_archivist
152
+ backgroundMode: continuable
153
+ maxDepth: 1
154
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/archivist.md'), 'utf8')
155
+ toolFilter:
156
+ deny:
157
+ - write
158
+ - edit
159
+ - todo_write
160
+ - ask_user_question
161
+ - exit_plan_mode
162
+ - send_message
163
+ - interrupt_agent
164
+ - list_agents
165
+ - subagent_children
166
+ - subagent_send
167
+ - subagent_interrupt
168
+ - subagent_fork
169
+ - subagent_scout
170
+ - subagent_archivist
171
+ - subagent_seer
172
+ - subagent_reader
173
+ - subagent_analyst
174
+ - subagent_auditor
175
+ - subagent_wright
176
+ - subagent_forge
177
+ - subagent_planner
178
+ - mcp_playwright
179
+ - mcp_jlceda
180
+ - mcp_cloudflare-browser
181
+ - mcp_desktop-touch
182
+ - id: tool-subagent-seer
183
+ name: '@deepseek-ai/dsh-tool-subagent'
184
+ config:
185
+ provider: spawn
186
+ toolName: subagent_seer
187
+ backgroundMode: continuable
188
+ maxDepth: 1
189
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/seer.md'), 'utf8')
190
+ toolFilter:
191
+ deny:
192
+ - write
193
+ - edit
194
+ - todo_write
195
+ - ask_user_question
196
+ - exit_plan_mode
197
+ - send_message
198
+ - interrupt_agent
199
+ - list_agents
200
+ - subagent_children
201
+ - subagent_send
202
+ - subagent_interrupt
203
+ - subagent_fork
204
+ - subagent_scout
205
+ - subagent_archivist
206
+ - subagent_seer
207
+ - subagent_reader
208
+ - subagent_analyst
209
+ - subagent_auditor
210
+ - subagent_wright
211
+ - subagent_forge
212
+ - subagent_planner
213
+ - mcp_playwright
214
+ - mcp_jlceda
215
+ - mcp_cloudflare-browser
216
+ - mcp_desktop-touch
217
+ - id: tool-subagent-reader
218
+ name: '@deepseek-ai/dsh-tool-subagent'
219
+ config:
220
+ provider: spawn
221
+ toolName: subagent_reader
222
+ backgroundMode: continuable
223
+ maxDepth: 1
224
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/reader.md'), 'utf8')
225
+ toolFilter:
226
+ allow:
227
+ - read
228
+ - read_image
229
+ - id: tool-subagent-analyst
230
+ name: '@deepseek-ai/dsh-tool-subagent'
231
+ config:
232
+ provider: spawn
233
+ toolName: subagent_analyst
234
+ backgroundMode: continuable
235
+ maxDepth: 1
236
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/analyst.md'), 'utf8')
237
+ toolFilter:
238
+ deny:
239
+ - write
240
+ - edit
241
+ - todo_write
242
+ - ask_user_question
243
+ - exit_plan_mode
244
+ - send_message
245
+ - interrupt_agent
246
+ - list_agents
247
+ - subagent_children
248
+ - subagent_send
249
+ - subagent_interrupt
250
+ - subagent_fork
251
+ - subagent_scout
252
+ - subagent_archivist
253
+ - subagent_seer
254
+ - subagent_reader
255
+ - subagent_analyst
256
+ - subagent_auditor
257
+ - subagent_wright
258
+ - subagent_forge
259
+ - subagent_planner
260
+ - mcp_playwright
261
+ - mcp_jlceda
262
+ - mcp_cloudflare-browser
263
+ - mcp_desktop-touch
264
+ - id: tool-subagent-auditor
265
+ name: '@deepseek-ai/dsh-tool-subagent'
266
+ config:
267
+ provider: spawn
268
+ toolName: subagent_auditor
269
+ backgroundMode: continuable
270
+ maxDepth: 1
271
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/auditor.md'), 'utf8')
272
+ toolFilter:
273
+ deny:
274
+ - write
275
+ - edit
276
+ - todo_write
277
+ - ask_user_question
278
+ - exit_plan_mode
279
+ - send_message
280
+ - interrupt_agent
281
+ - list_agents
282
+ - subagent_children
283
+ - subagent_send
284
+ - subagent_interrupt
285
+ - subagent_fork
286
+ - subagent_scout
287
+ - subagent_archivist
288
+ - subagent_seer
289
+ - subagent_reader
290
+ - subagent_analyst
291
+ - subagent_auditor
292
+ - subagent_wright
293
+ - subagent_forge
294
+ - subagent_planner
295
+ - mcp_playwright
296
+ - mcp_jlceda
297
+ - mcp_cloudflare-browser
298
+ - mcp_desktop-touch
299
+ - id: tool-subagent-wright
300
+ name: '@deepseek-ai/dsh-tool-subagent'
301
+ config:
302
+ provider: spawn
303
+ toolName: subagent_wright
304
+ backgroundMode: continuable
305
+ maxDepth: 1
306
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/wright.md'), 'utf8')
307
+ toolFilter:
308
+ deny:
309
+ - ask_user_question
310
+ - exit_plan_mode
311
+ - send_message
312
+ - interrupt_agent
313
+ - list_agents
314
+ - subagent_children
315
+ - subagent_send
316
+ - subagent_interrupt
317
+ - subagent_fork
318
+ - subagent_scout
319
+ - subagent_archivist
320
+ - subagent_seer
321
+ - subagent_reader
322
+ - subagent_analyst
323
+ - subagent_auditor
324
+ - subagent_wright
325
+ - subagent_forge
326
+ - subagent_planner
327
+ - mcp_playwright
328
+ - mcp_jlceda
329
+ - mcp_cloudflare-browser
330
+ - mcp_desktop-touch
331
+ - id: tool-subagent-forge
332
+ name: '@deepseek-ai/dsh-tool-subagent'
333
+ config:
334
+ provider: spawn
335
+ toolName: subagent_forge
336
+ backgroundMode: continuable
337
+ maxDepth: 1
338
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/forge.md'), 'utf8')
339
+ toolFilter:
340
+ deny:
341
+ - ask_user_question
342
+ - exit_plan_mode
343
+ - interrupt_agent
344
+ - subagent_children
345
+ - subagent_send
346
+ - subagent_interrupt
347
+ - subagent_fork
348
+ - subagent_analyst
349
+ - subagent_auditor
350
+ - subagent_reader
351
+ - subagent_wright
352
+ - subagent_forge
353
+ - subagent_planner
354
+ - mcp_playwright
355
+ - mcp_jlceda
356
+ - mcp_cloudflare-browser
357
+ - mcp_desktop-touch
358
+ - id: tool-subagent-planner
359
+ name: '@deepseek-ai/dsh-tool-subagent'
360
+ config:
361
+ provider: spawn
362
+ toolName: subagent_planner
363
+ backgroundMode: continuable
364
+ maxDepth: 1
365
+ persona: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/planner.md'), 'utf8')
366
+ toolFilter:
367
+ deny:
368
+ - write
369
+ - edit
370
+ - todo_write
371
+ - ask_user_question
372
+ - exit_plan_mode
373
+ - send_message
374
+ - interrupt_agent
375
+ - list_agents
376
+ - subagent_children
377
+ - subagent_send
378
+ - subagent_interrupt
379
+ - subagent_fork
380
+ - subagent_scout
381
+ - subagent_archivist
382
+ - subagent_seer
383
+ - subagent_reader
384
+ - subagent_analyst
385
+ - subagent_auditor
386
+ - subagent_wright
387
+ - subagent_forge
388
+ - subagent_planner
389
+ - mcp_playwright
390
+ - mcp_jlceda
391
+ - mcp_cloudflare-browser
392
+ - mcp_desktop-touch
393
+ - id: orch-method-pack
394
+ name: '@quill507/dsh-orchestrator-preset/extensions/dsh/index.js'
395
+ - id: orch-aegis-prefix
396
+ name: '@quill507/dsh-orchestrator-preset/extensions/dsh/aegis-prefix.js'
397
+ config:
398
+ prefixAegisSkills: true
399
+ describeAegisSkillsInZh: false
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Namespaces the aegis methodology pack's skills with an `aegis-` prefix, and
3
+ * optionally localises their descriptions.
4
+ *
5
+ * WHY THE PREFIX LIVES HERE
6
+ * The preset's resident routing table names twenty-one skills by their prefixed
7
+ * name, while the upstream pack registers them bare — it is host-agnostic and has
8
+ * no reason to know this preset exists. Nothing bridged that, so every aegis row
9
+ * in the routing table pointed at a name resolving to nothing, and the failure was
10
+ * silent: a routing entry that matches no skill simply never fires.
11
+ *
12
+ * WHY THE DESCRIPTION SWAP IS A SECOND, OFF-BY-DEFAULT FLAG
13
+ * Translating the catalogue is a reader preference, not a routing requirement, and
14
+ * forcing it on everyone who installs this preset would be wrong. It is OFF by
15
+ * default and turned on per deployment, in a layer the reader owns.
16
+ *
17
+ * WHY BOTH LIVE IN ONE PLUGIN
18
+ * They were briefly two plugins: this bridge for the prefix, a separate local one
19
+ * for descriptions. That produced a race — this bridge copies a description while
20
+ * registering, so whichever plugin ran first decided whether Chinese or English
21
+ * got copied, and the observed result was neither: twenty-one routing targets
22
+ * resolved, but only four descriptions were localised. Two plugins mutating the
23
+ * same registrations need a load-order contract to be correct, and such a contract
24
+ * is only correct until somebody reorders the bundle array. Doing both in one pass
25
+ * at registration removes the question instead of answering it.
26
+ *
27
+ * `skills/change` is still observed rather than reading the catalogue once, so a
28
+ * pack that registers late still gets namespaced.
29
+ */
30
+
31
+ import z from '@deepseek-ai/schemastery'
32
+
33
+ const AEGIS_PROVIDER = 'aegis-method-pack'
34
+ const PREFIX = 'aegis-'
35
+
36
+ /** Cordis plugin name. */
37
+ export const name = 'orch-aegis-prefix'
38
+
39
+ /** Only the skill registry: this plugin registers names, it serves none.
40
+ * No `settings` injection, because there is no settings surface to serve — the
41
+ * switches are set in a patch layer. See the note above `Config`. */
42
+ export const inject = ['skills']
43
+
44
+ /** Behaviour defaults, shared by the schema below and by the read in `apply`.
45
+ * Declared once so the schema's default and the code's default cannot drift. */
46
+ const DEFAULTS = Object.freeze({
47
+ prefixAegisSkills: true,
48
+ describeAegisSkillsInZh: false,
49
+ })
50
+
51
+ /**
52
+ * The two switches. **Not rendered as a settings card — see below.**
53
+ *
54
+ * Set them in a patch layer: the home layer `$DSH_HOME/cordis.patch.yml` applies
55
+ * after this bundle's, so a row there wins. Restate both keys, because a patch
56
+ * replaces a row's config rather than deep-merging it.
57
+ *
58
+ * WHY THERE IS NO UI, measured rather than assumed
59
+ * The host does build forms from plugin schemas — `dsh-settings.describe()` reads
60
+ * `entry.fiber.runtime.Config` and runs its own `volatileForm()` over it — but it
61
+ * only considers entries returned by `dsh-config-editor.entries()`, which filters
62
+ * to rows whose `parent.tree.ctx.fiber.entry?.id === "include"`. A row inserted by
63
+ * a bundle patch is not one of those, so nothing here appears in the settings UI.
64
+ *
65
+ * The one third-party plugin on this host that *does* have a settings card
66
+ * (`@quill507/dsh-auto-approval-llm`) does not use that path either: it ships a
67
+ * browser client plugin and its own GET route, and its source says outright that
68
+ * the route exists as the degradation source "for a card that has no host form
69
+ * (entry not ACTIVE)".
70
+ *
71
+ * So reaching the UI means writing a client plugin, which is a separate project
72
+ * rather than a field on this schema. The schema is kept anyway: it is the correct
73
+ * declaration, it carries the two defaults, and it is exactly what such a client
74
+ * would bind to. Two earlier attempts at the auto-form failed for reasons recorded
75
+ * above — a `zod` Config is invisible to `volatileForm`, and adding schemastery plus
76
+ * `.volatile()` satisfies that function while leaving the `include` filter unmet.
77
+ */
78
+ export const Config = z.object({
79
+ prefixAegisSkills: z.boolean().default(DEFAULTS.prefixAegisSkills).volatile(),
80
+ describeAegisSkillsInZh: z.boolean().default(DEFAULTS.describeAegisSkillsInZh).volatile(),
81
+ })
82
+
83
+ /**
84
+ * English original -> compressed Chinese. The English string is the match key,
85
+ * taken verbatim from each SKILL.md, so an upstream rewrite falls through to
86
+ * English rather than mismatching into something garbled. `tools/verify-install.sh`
87
+ * checks every key against the installed pack, so a stale table announces itself.
88
+ */
89
+ const ZH_DESCRIPTIONS = [
90
+ ['Use when touching retiring old logic, collapsing duplicate owners, removing fallbacks, or schema/persistence/source-of-truth boundaries; identify opportunities automatically; destructive execution requires explicit confirmation.', '退役旧逻辑/合并重复owner/移除回退/动数据源边界时用;自动识别机会,破坏性执行需确认。'],
91
+ ['Use when defining ambiguous or high-complexity new features, product behavior, UI/component design, architecture choices, contract changes, or when grilling/pressure-testing a plan or design. Routine small requests stay on the fast path.', '模糊/高复杂度新功能、UI/组件、架构选择、合同变更,或盘问/压力测试方案时用;常规小请求走快路径。'],
92
+ ['Use when the user asks for caveman mode, fewer tokens, brief responses, compressed communication, or otherwise explicitly requests a much shorter answer.', '用户要求 caveman 模式/少 token/简短回答/压缩沟通时用。'],
93
+ ['Use when facing 2+ independent tasks without a written plan, with no conflicting shared mutable state or sequential dependencies, where parallel delegation beats inline cost; otherwise inline. Planned tasks use subagent-driven-development.', '2+ 独立无依赖任务、无书面计划、无冲突共享可变状态/顺序依赖、并行派发优于内联时用;有计划的任务用 subagent-driven-development。'],
94
+ ['Use when the user asks to establish shared project language, or project work exposes a conflicting, renamed, or deprecated domain term that needs active semantic modeling. Routine small tasks stay on the fast path.', '建立共享项目语言,或领域术语冲突/重命名/过时需要语义建模时用;常规小任务走快路径。'],
95
+ ['Use when executing a written implementation plan across sessions or with review checkpoints. Small or single-slice plans stay inline. For same-session independent tasks, use subagent-driven-development instead.', '跨会话或带审查检查点执行书面实现计划时用;小/单切片计划内联;同会话独立任务用 subagent-driven-development。'],
96
+ ['Use when verified work needs integration or cleanup of an existing task-created branch/worktree, or the user explicitly requests merge, PR, or branch lifecycle handling.', '已验证工作需集成/清理任务创建的分支/worktree,或用户明确要求 merge/PR/分支生命周期处理时用。'],
97
+ ["Use when asked for first-principles or Occam's-razor review, or when high-risk decisions involve competing constraints, fallback growth, duplicate owners, or architecture direction risk. Ordinary bug fixes stay on the fast path.", '被要求第一性原理/Occam 剃刀审查,或高风险决策(竞争约束/回退增长/重复owner/架构方向风险)时用;普通 bug 修复走快路径。'],
98
+ ['Use when the user explicitly sets an Aegis goal with /aegis-goal, Aegis goal:, or asks to define goal, success evidence, stop condition, or task boundaries before work.', '用户用 /aegis-goal、Aegis goal:,或要求定义目标、成功证据、停止条件、任务边界时用。'],
99
+ ['Use when a task is multi-step, may span context resets or sessions, uses subagents, or risks losing state before completion.', '任务多步骤、跨上下文重置/会话、用子代理、或有完成前丢失状态风险时用。'],
100
+ ['Use when receiving code review feedback before implementing suggestions, especially when feedback is unclear, risky, disputed, or technically questionable.', '收到代码评审反馈、实施建议前用,尤其反馈不清晰、有风险、有争议或技术上可疑时。'],
101
+ ['Use when the user asks to create, write, update, amend, supersede, or evaluate an ADR, architecture decision record, durable architecture decision, decision log, or baseline sync after architecture-changing work.', '用户要求创建/编写/更新/修订/废止/评估 ADR、架构决策记录、持久化架构决策、决策日志或基线同步时用。'],
102
+ ['Use when requesting independent code review, after implementation slices, before merging high-risk work, or when verification exposes evidence, baseline, architecture, compatibility, or retirement uncertainty.', '请求独立代码评审:实现切片后、合并高风险工作前、或验证暴露证据/基线/架构/兼容性/退役不确定性时用。'],
103
+ ['Use when executing a written implementation plan with independent tasks in the current session where delegation beats inline coordination cost; otherwise inline. Ad-hoc 2+ tasks without a plan use dispatching-parallel-agents.', '执行书面实现计划、当前会话独立任务委托优于内联时用;临时 2+ 无计划任务用 dispatching-parallel-agents。'],
104
+ ['Use when encountering a bug, test failure, or unexpected behavior, before proposing fixes', '遇到 bug、测试失败或意外行为、提出修复前用。'],
105
+ ['Use when the user explicitly requests strict or test-first TDD, or when the current conversation already contains an explicit `TDD Route: strict` decision from another Aegis workflow.', '用户显式要求严格/测试优先 TDD,或会话已有 TDD Route: strict 决策时用。'],
106
+ ['Use when the user says `aegis:update`, asks to update or upgrade an installed Aegis method-pack, wants the latest Aegis version, or asks whether Aegis is current on this host.', '用户说 aegis:update、要求更新/升级已装方法包、要最新版本或询问是否最新时用。'],
107
+ ['Use when starting a turn or checking Aegis skill routing.', '回合开始或检查 Aegis 技能路由时用。'],
108
+ ['Use when a coding task needs a concurrent checkout, unrelated dirty state blocks safe branch switching, or the user or repository explicitly requires a worktree.', '编码任务需并发 checkout、无关脏状态阻止安全切分支、或用户/仓库明确要求 worktree 时用。'],
109
+ ['Use when about to claim work is complete, fixed, passing, verified, release-ready, or ready to commit, merge, publish, or hand off.', '声称完成/修复/通过/可发布,或准备提交/合并/发布/移交时用。'],
110
+ ['Use when you have an approved spec or written requirements for a multi-step task that needs a durable plan document before touching code. Small, single-owner, or fast-path tasks do not need this skill.', '有已批准规格/书面需求的多步骤任务、动代码前需持久计划文档时用;小/单owner/快路径任务不需要。'],
111
+ ['Use when creating new skills, editing existing skills, or verifying skills work before deployment', '创建新技能、编辑现有技能、或部署前验证技能可用时用。'],
112
+ ]
113
+
114
+ const ZH_BY_EN = new Map(ZH_DESCRIPTIONS)
115
+
116
+ export function apply(ctx, rawConfig) {
117
+ // Read the two switches off the raw patch value, applying DEFAULTS for whatever
118
+ // the row does not set. Schemastery schemas are not zod's: there is no `.parse`
119
+ // here, and calling the schema does not fill defaults either — so the defaults
120
+ // have to come from the shared constant, which is also what the card shows.
121
+ const raw = rawConfig !== null && typeof rawConfig === 'object' ? rawConfig : {}
122
+ const pick = (key) => (typeof raw[key] === 'boolean' ? raw[key] : DEFAULTS[key])
123
+ const wantPrefix = pick('prefixAegisSkills')
124
+ const wantZh = pick('describeAegisSkillsInZh')
125
+
126
+ if (!wantPrefix) {
127
+ ctx.logger.info("[orch-aegis-prefix] prefix disabled by config; the preset's routing table will not resolve")
128
+ return
129
+ }
130
+
131
+ const skills = ctx.skills
132
+ const done = new Set()
133
+ const disposers = []
134
+ let syncing = false
135
+
136
+ async function sync() {
137
+ if (syncing) return
138
+ syncing = true
139
+ try {
140
+ const summaries = await skills.list()
141
+ const targets = summaries.filter((s) => s.provider === AEGIS_PROVIDER && !done.has(s.name))
142
+ for (const summary of targets) {
143
+ const skill = await skills.get(summary.name)
144
+ if (!skill) continue
145
+ const bare = skill.name
146
+ const prefixed = bare.startsWith(PREFIX) ? bare : PREFIX + bare
147
+ // The swap happens HERE, in the same pass as the rename, so no window
148
+ // exists in which another plugin could copy the un-swapped text.
149
+ const description = wantZh
150
+ ? (ZH_BY_EN.get(skill.description ?? '') ?? skill.description)
151
+ : skill.description
152
+ disposers.push(
153
+ skills.register({
154
+ name: prefixed,
155
+ ...(description !== undefined ? { description } : {}),
156
+ ...(skill.whenToUse !== undefined ? { whenToUse: skill.whenToUse } : {}),
157
+ invocation: skill.invocation ?? { modelInvocable: true, userInvocable: true },
158
+ source: 'orch-aegis-prefix',
159
+ content: skill.content,
160
+ ...(skill.resourceBase !== undefined ? { resourceBase: skill.resourceBase } : {}),
161
+ ...(skill.path !== undefined ? { path: skill.path } : {}),
162
+ ...(skill.metadata !== undefined ? { metadata: skill.metadata } : {}),
163
+ }),
164
+ )
165
+ if (prefixed !== bare) {
166
+ // Tombstone the bare name. Runtime beats bundled on collision, so this
167
+ // wins over the provider's entry and the old spelling stops being
168
+ // loadable — one skill, one name, no way to reach it by the other.
169
+ disposers.push(
170
+ skills.register({
171
+ name: bare,
172
+ description: `Renamed to ${prefixed}; load that name instead.`,
173
+ invocation: { modelInvocable: false, userInvocable: false },
174
+ source: 'orch-aegis-prefix',
175
+ content: `This skill was renamed to ${prefixed}.`,
176
+ }),
177
+ )
178
+ }
179
+ done.add(summary.name)
180
+ ctx.logger.info(`[orch-aegis-prefix] "${bare}" -> "${prefixed}"${wantZh ? ' (zh)' : ''}`)
181
+ }
182
+ } catch (error) {
183
+ ctx.logger.warn(`[orch-aegis-prefix] sync failed: ${String(error)}`)
184
+ } finally {
185
+ syncing = false
186
+ }
187
+ }
188
+
189
+ ctx.logger.info(`[orch-aegis-prefix] applied; zh=${wantZh}, ${ZH_DESCRIPTIONS.length} mappings available`)
190
+ void sync()
191
+ ctx.on('skills/change', () => {
192
+ void sync()
193
+ })
194
+ ctx.effect(() => () => {
195
+ for (const dispose of disposers) dispose()
196
+ })
197
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Thin DeepSeek Harness bundle adapter for the orchestrator preset's own skills.
3
+ *
4
+ * Deliberately aegis-shaped and nothing more:
5
+ * - the host-owned filesystem provider stays the discovery implementation; this
6
+ * adapter only points one isolated provider at this package's own skills/ tree;
7
+ * - no skill bodies are copied at load time and the native skill tool is untouched;
8
+ * - no agent or agentTeams injection, so `inject` is just ["skills"].
9
+ *
10
+ * The `orch-` prefix is NOT applied here. It lives in each SKILL.md's frontmatter
11
+ * `name:`, which is where the filesystem provider reads the skill name from, so a
12
+ * resync from source can never bake a second naming decision into the tree.
13
+ *
14
+ * `includeDefaultRoots: false` is what keeps this isolated: the user's global
15
+ * skills directory is somebody else's environment and is not this package's
16
+ * business.
17
+ *
18
+ * Entry specifier: the bundle patch mounts this file as
19
+ * @quill507/dsh-orchestrator-preset/extensions/dsh/index.js
20
+ * The full scoped form is required. A bare or short form resolves to a directory
21
+ * that does not exist and the bundle fails to load with MODULE_NOT_FOUND, which
22
+ * is silent from the user's side — measured on this host, see the note in
23
+ * tools/verify-install.sh and hw-skills' own cordis.patch.yml.
24
+ */
25
+
26
+ import { fileURLToPath } from "node:url";
27
+ import { apply as applyFilesystemProvider } from "@deepseek-ai/dsh-skill-filesystem";
28
+
29
+ const skillsRoot = fileURLToPath(new URL("../../skills/", import.meta.url));
30
+
31
+ export const name = "orch-method-pack";
32
+ export const inject = ["skills"];
33
+
34
+ export function apply(ctx) {
35
+ applyFilesystemProvider(ctx, {
36
+ providerName: "orch-method-pack",
37
+ includeDefaultRoots: false,
38
+ bundledSkillDir: skillsRoot,
39
+ watch: false,
40
+ });
41
+ }