@joekytc/dsh-swarm 0.3.12 → 0.5.1

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 (37) hide show
  1. package/client/ConfigSection.tsx +127 -18
  2. package/client/ConfigSelect.tsx +1 -0
  3. package/client/config-store.ts +6 -3
  4. package/client/config.css +89 -1
  5. package/client/index.ts +8 -4
  6. package/client/session-bridge.ts +26 -2
  7. package/cordis.patch.yml +10 -52
  8. package/lib/client.js +215 -37
  9. package/lib/config.d.ts +7 -0
  10. package/lib/config.js +7 -1
  11. package/lib/dispatcher/agent-runner.d.ts +4 -0
  12. package/lib/dispatcher/agent-runner.js +28 -17
  13. package/lib/dispatcher/chain-auditor.d.ts +3 -2
  14. package/lib/dispatcher/chain-auditor.js +2 -2
  15. package/lib/dispatcher/model-candidates.d.ts +9 -3
  16. package/lib/dispatcher/model-candidates.js +27 -6
  17. package/lib/dispatcher/model-chain.d.ts +19 -0
  18. package/lib/dispatcher/model-chain.js +110 -0
  19. package/lib/dispatcher/session-events.d.ts +9 -0
  20. package/lib/dispatcher/session-events.js +28 -0
  21. package/lib/dispatcher/v-orchestrator.d.ts +2 -0
  22. package/lib/dispatcher/v-orchestrator.js +14 -9
  23. package/lib/domain/config-override.d.ts +20 -0
  24. package/lib/domain/config-override.js +46 -2
  25. package/lib/index.js +13 -3
  26. package/lib/roles/preset-installer.d.ts +50 -5
  27. package/lib/roles/preset-installer.js +154 -20
  28. package/lib/routes/kanban-http.js +24 -3
  29. package/lib/services/config-provider.js +5 -0
  30. package/package.json +23 -17
  31. package/personas/kanban-d/agent.cordis.yml +3 -1
  32. package/personas/kanban-dt/agent.cordis.yml +2 -1
  33. package/personas/kanban-p/agent.cordis.yml +1 -1
  34. package/personas/kanban-pt/agent.cordis.yml +1 -1
  35. package/personas/kanban-v/agent.cordis.yml +1 -1
  36. package/personas/kanban-w/agent.cordis.yml +1 -1
  37. package/personas/swarm/agent.cordis.yml +1 -1
@@ -1,36 +1,103 @@
1
1
  // src/roles/preset-installer.ts
2
- import { copyFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { join } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
+ import { JSON_SCHEMA, load as loadYaml, Type } from 'js-yaml';
6
7
  /**
7
- * 角色裁剪 preset 的运行时安装(2026-08-15 取舍记录):
8
- * - 组合文件随包分发(personas/kanban-{v,p,w,d}/agent.cordis.yml,随 npm 包分发)。
9
- * kanban-v 于 2026-08-17 补充:V=butler·orchestrator 零执行能力,组合仅 persona+instructions。
10
- * - 官方 dsh-agent-presets 的 roots 在 web 启动的 composeProfile 中被强制覆盖为
11
- * 官方 shipped root 单一路径(profile-boot 内 SHIPPED_PRESET_ROOT 硬编码),
12
- * 因此 cordis.patch.yml 追加 roots 指向包内目录在真实 API 下无效;
13
- * 唯一可发现的自定义根是 includeUserRoot 派生的 `$DSH_HOME/.agent-presets`。
14
- * - 故插件 apply 时把包内组合复制到 `$DSH_HOME/.agent-presets/<id>/`,
15
- * agentPresets.mount(agentCtx, 'kanban-v'|'kanban-p'|'kanban-w'|'kanban-d') 即可解析。
16
- * - 幂等:重复安装覆盖同名文件;缺组合文件(未随包)则跳过并让 runner 降级日志。
8
+ * 角色裁剪 preset 的双路安装:
9
+ *
10
+ * 路径一 · 目录写(0.1.7-rc.x 宿主的底线):把包内组合复制到 `$DSH_HOME/.agent-presets/<id>/`,
11
+ * 老宿主的 agent-presets 发现逻辑扫该目录完成装载。0.2.0 宿主不再扫描任何目录,此路不影响新宿主。
12
+ *
13
+ * 路径二 · 运行时注册(0.2.0 起的唯一生效路径):0.2.0 的 dsh-agent-preset-registry 是纯运行时
14
+ * 服务,preset 定义只经 `agentPresets.register(definition)` 进入(官方 dsh-agent-preset 插件
15
+ * 即在 Service.init 中 yield register(config)),无任何目录发现。本插件经 ctx 取 agentPresets
16
+ * 服务(未就绪则短轮询等待),把与目录写同一份 yml 解析出的定义注册进去,两个路径语义同源。
17
+ *
18
+ * 幂等:目录写覆盖同名文件;运行时注册遇宿主 "Duplicate agent preset" 视为已注册成功。
19
+ * 尽力而为:单 preset 目录写/注册失败仅告警不阻断插件启动,后续挂载失败由 runner 降级日志兜底。
17
20
  */
18
21
  const PRESET_IDS = ['kanban-v', 'kanban-p', 'kanban-w', 'kanban-d', 'kanban-pt', 'kanban-dt', 'swarm'];
22
+ /** 等待 agentPresets 服务就绪的超时(宿主组合启动期服务装配可能晚于插件 apply)。 */
23
+ const REGISTER_WAIT_MS = 60000;
19
24
  /** 包内组合目录(随包分发)。src/roles/ 与 lib/roles/ 深度一致,均经 ../../ 回到包根。 */
20
25
  export function packagePresetsDir() {
21
26
  return fileURLToPath(new URL('../../personas/', import.meta.url));
22
27
  }
23
- /** $DSH_HOME/.agent-presets(agent-presets 服务 includeUserRoot 派生根;DSH_HOME 缺省 ~/.dsh)。 */
28
+ /** $DSH_HOME/.agent-presets(0.1.7-rc.x 宿主用户预设根;DSH_HOME 缺省 ~/.dsh)。 */
24
29
  export function userPresetsRoot() {
25
30
  return join(process.env.DSH_HOME ?? join(homedir(), '.dsh'), '.agent-presets');
26
31
  }
27
- /** 安装角色裁剪 preset 到用户预设根;返回成功安装的 preset id 列表(空=无随包组合)。
28
- * 尽力而为:单 preset 写失败(用户预设根不可写等)仅告警不抛出,
29
- * 后续 agentPresets.mount('kanban-<role>') 失败由 runner 降级日志兜底。 */
30
- export function installRolePresets() {
32
+ // 宿主 entry-list YAML 方言的镜像(@deepseek-ai/cordis-plugin-include 的 entryListSchema):
33
+ // `!!js` 标量解析为 { __jsExpr } 表达式节点,由宿主 Loader 在行激活时求值(组合内
34
+ // `disabled: !!js process.platform === 'win32'` 等行依赖此节点形态,禁在解析期求值)。
35
+ const JS_EXPR_TAG = new Type('tag:yaml.org,2002:js', {
36
+ kind: 'scalar',
37
+ resolve: (data) => typeof data === 'string',
38
+ construct: (data) => ({ __jsExpr: data }),
39
+ });
40
+ const ENTRY_LIST_SCHEMA = JSON_SCHEMA.extend(JS_EXPR_TAG);
41
+ /** 镜像宿主 registry 的入口列表形状校验:顶层为带 name 的行数组(组行递归其 config)。 */
42
+ function entryListProblem(rows, at = '') {
43
+ if (!Array.isArray(rows))
44
+ return at === '' ? 'composition must be a top-level list of plugin rows' : `group ${at} must hold a list of plugin rows`;
45
+ for (const [index, row] of rows.entries()) {
46
+ const label = at === '' ? `row ${String(index + 1)}` : `${at} row ${String(index + 1)}`;
47
+ if (typeof row !== 'object' || row === null || Array.isArray(row))
48
+ return `${label} is not a plugin row`;
49
+ const name = row.name;
50
+ if (typeof name !== 'string' || name === '')
51
+ return `${label} names no plugin (a "name" string is required)`;
52
+ const config = row.config;
53
+ if (row.group === true && config !== undefined) {
54
+ const nested = entryListProblem(config, label);
55
+ if (nested !== undefined)
56
+ return nested;
57
+ }
58
+ }
59
+ return undefined;
60
+ }
61
+ /** 解析包内单个 preset 的组合与元数据为宿主 registry 定义;组合缺失返回 undefined。 */
62
+ export function readPresetDefinition(pkgDir, id) {
63
+ const srcFile = join(pkgDir, id, 'agent.cordis.yml');
64
+ if (!existsSync(srcFile))
65
+ return undefined;
66
+ let rows;
67
+ let meta;
68
+ try {
69
+ rows = loadYaml(readFileSync(srcFile, 'utf8'), { schema: ENTRY_LIST_SCHEMA });
70
+ const metaFile = join(pkgDir, id, 'preset.yml');
71
+ meta = existsSync(metaFile)
72
+ ? loadYaml(readFileSync(metaFile, 'utf8'), { schema: JSON_SCHEMA })
73
+ : {};
74
+ }
75
+ catch (err) {
76
+ console.warn('[dsh-swarm] role preset parse failed ' + id + ': ' + String(err));
77
+ return undefined;
78
+ }
79
+ const problem = entryListProblem(rows);
80
+ if (problem !== undefined) {
81
+ console.warn('[dsh-swarm] role preset composition invalid ' + id + ': ' + problem);
82
+ return undefined;
83
+ }
84
+ const definition = {
85
+ id,
86
+ plugins: rows,
87
+ };
88
+ if (typeof meta.name === 'string')
89
+ definition.name = meta.name;
90
+ if (typeof meta.description === 'string')
91
+ definition.description = meta.description;
92
+ if (typeof meta.order === 'number')
93
+ definition.order = meta.order;
94
+ return definition;
95
+ }
96
+ /** 路径一:目录写(0.1.7-rc.x 宿主发现根)。返回成功写入的 preset id 列表。 */
97
+ function writeUserDirPresets() {
31
98
  const src = packagePresetsDir();
32
99
  const dstRoot = userPresetsRoot();
33
- const installed = [];
100
+ const written = [];
34
101
  for (const id of PRESET_IDS) {
35
102
  const srcFile = join(src, id, 'agent.cordis.yml');
36
103
  if (!existsSync(srcFile))
@@ -42,14 +109,81 @@ export function installRolePresets() {
42
109
  const meta = join(src, id, 'preset.yml');
43
110
  if (existsSync(meta))
44
111
  copyFileSync(meta, join(dstDir, 'preset.yml'));
45
- installed.push(id);
112
+ written.push(id);
46
113
  }
47
114
  catch (err) {
48
115
  // 尽力而为:写入失败(如沙箱/权限拒绝)仅告警,不阻断插件启动
49
- console.warn('[dsh-swarm] role preset install skipped ' + id + ' -> ' + dstRoot + ': ' + String(err));
116
+ console.warn('[dsh-swarm] role preset dir write skipped ' + id + ' -> ' + dstRoot + ': ' + String(err));
50
117
  }
51
118
  }
52
- return installed;
119
+ return written;
120
+ }
121
+ /** 路径二:运行时注册全部包内 preset;返回注册成功/失败 id 列表与成功项的撤销句柄(组合缺失的 id 不计)。 */
122
+ export async function registerRolePresets(registry, ids, pkgDir = packagePresetsDir()) {
123
+ const registered = [];
124
+ const failed = [];
125
+ const disposers = [];
126
+ for (const id of ids) {
127
+ const definition = readPresetDefinition(pkgDir, id);
128
+ if (!definition)
129
+ continue;
130
+ try {
131
+ disposers.push(await registry.register(definition));
132
+ registered.push(id);
133
+ }
134
+ catch (err) {
135
+ // 插件重 apply 时定义已在 registry:与首次注册语义等价,按成功计
136
+ if (String(err).includes('Duplicate agent preset')) {
137
+ registered.push(id);
138
+ continue;
139
+ }
140
+ failed.push(id);
141
+ console.warn('[dsh-swarm] role preset runtime register failed ' + id + ': ' + String(err));
142
+ }
143
+ }
144
+ return { registered, failed, disposers };
145
+ }
146
+ /** 短轮询等待宿主 agentPresets 服务就绪;超时返回 undefined(降级仅目录写)。 */
147
+ async function waitForPresets(ctx, timeoutMs) {
148
+ const started = Date.now();
149
+ return new Promise((resolve) => {
150
+ const poll = setInterval(() => {
151
+ const found = ctx.get?.('agentPresets');
152
+ if (found) {
153
+ clearInterval(poll);
154
+ resolve(found);
155
+ }
156
+ else if (Date.now() - started >= timeoutMs) {
157
+ clearInterval(poll);
158
+ resolve(undefined);
159
+ }
160
+ }, 500);
161
+ });
162
+ }
163
+ /**
164
+ * 双路安装入口。目录写同步完成并即时留痕;运行时注册等服务就绪后完成并留痕。
165
+ * 返回前目录写已落盘;注册部分异步收敛(fire-and-forget 调用方须 catch)。
166
+ */
167
+ export async function installRolePresets(ctx, opts = {}) {
168
+ const dirWritten = writeUserDirPresets();
169
+ console.info('[dsh-swarm] role preset dir write: ' + (dirWritten.length ? dirWritten.join(',') : 'none'));
170
+ const registry = await waitForPresets(ctx, opts.registerWaitMs ?? REGISTER_WAIT_MS);
171
+ if (!registry) {
172
+ console.warn('[dsh-swarm] role presets installed: dir-write=' + (dirWritten.join(',') || 'none')
173
+ + ' runtime-register=none (agentPresets service unavailable; directory write only)');
174
+ return { dirWritten, runtimeRegistered: [], runtimeFailed: [], runtimeMode: 'unavailable' };
175
+ }
176
+ const { registered, failed, disposers } = await registerRolePresets(registry, PRESET_IDS);
177
+ console.info('[dsh-swarm] role presets installed: dir-write=' + (dirWritten.join(',') || 'none')
178
+ + ' runtime-register=' + (registered.join(',') || 'none')
179
+ + (failed.length ? ' failed=' + failed.join(',') : ''));
180
+ // 插件卸载/重载时撤销注册,避免宿主 registry 留下失效定义(官方 register 契约:声明方持有 disposer)。
181
+ ctx.on?.('dispose', () => {
182
+ for (const dispose of disposers.splice(0))
183
+ void dispose().catch(() => { });
184
+ });
185
+ const report = { dirWritten, runtimeRegistered: registered, runtimeFailed: failed, runtimeMode: 'runtime' };
186
+ return report;
53
187
  }
54
188
  /**
55
189
  * preset 挂载收敛入口(2026-09-21 事故修复):宿主 dsh-scope 的 scope key 绑定在进程
@@ -309,12 +309,27 @@ export function registerKanbanHttp(ctx, provider, configProvider, llm, config, o
309
309
  if (req.method === 'PUT' && req.url?.startsWith('/kanban/config')) {
310
310
  const raw = JSON.parse((await readBody(req)) || '{}');
311
311
  // 归一化缺省字段,保证缺字段走 400 校验失败而非 500。
312
- // reviewEngine/imDelivery 缺省时回退当前 effective(再兜底默认):旧客户端 bundle 不带这些字段时保存不清空既有配置。
312
+ // reviewEngine/imDelivery/chainFallback 缺省时回退当前 effective(再兜底默认):旧客户端
313
+ // bundle 不带这些字段时保存不清空既有配置;chainFallback 属部署配置只读,原样回填。
313
314
  const cur = configProvider.getEffective();
314
315
  const fb = cur.reviewEngine;
316
+ const cfb = cur.roles.chainFallback;
315
317
  const snapshot = {
316
318
  wikiVault: { baseUrl: raw.wikiVault?.baseUrl ?? '', pagePrefix: raw.wikiVault?.pagePrefix ?? '' },
317
- roles: { models: raw.roles?.models ?? {} },
319
+ roles: {
320
+ models: Object.fromEntries(Object.entries(raw.roles?.models ?? {}).map(([k, m]) => [
321
+ k,
322
+ // 旧客户端 bundle 不带 fallbacks 字段:回填当前 effective 链,避免保存时误清降级链。
323
+ m.fallbacks === undefined
324
+ ? { ...m, fallbacks: cur.roles.models?.[k]?.fallbacks ?? [] }
325
+ : m,
326
+ ])),
327
+ },
328
+ chainFallback: {
329
+ provider: raw.chainFallback?.provider ?? cfb?.provider ?? '',
330
+ model: raw.chainFallback?.model ?? cfb?.model ?? '',
331
+ reasoningEffort: raw.chainFallback?.reasoningEffort ?? cfb?.reasoningEffort ?? 'high',
332
+ },
318
333
  reviewEngine: {
319
334
  mode: raw.reviewEngine?.mode ?? fb?.mode ?? 'delegate',
320
335
  managed: {
@@ -331,8 +346,14 @@ export function registerKanbanHttp(ctx, provider, configProvider, llm, config, o
331
346
  const toProbe = [];
332
347
  for (const role of ROLES) {
333
348
  const m = snapshot.roles.models[role];
334
- if (m?.provider?.trim() && m?.model?.trim())
349
+ if (m?.provider?.trim() && m?.model?.trim()) {
335
350
  toProbe.push({ provider: m.provider, model: m.model, reasoningEffort: m.reasoningEffort });
351
+ // 降级候选同口径预检:死组合保存时拦下,不流入派发。
352
+ for (const f of m.fallbacks ?? []) {
353
+ if (f.provider?.trim() && f.model?.trim())
354
+ toProbe.push({ provider: f.provider, model: f.model, reasoningEffort: f.reasoningEffort });
355
+ }
356
+ }
336
357
  }
337
358
  if (snapshot.reviewEngine.mode === 'managed' && snapshot.reviewEngine.managed.provider.trim() && snapshot.reviewEngine.managed.model.trim()) {
338
359
  toProbe.push({ provider: snapshot.reviewEngine.managed.provider, model: snapshot.reviewEngine.managed.model });
@@ -80,6 +80,11 @@ export class ConfigProvider extends Service {
80
80
  if (a !== b)
81
81
  keys.add(`roles.models.${role}.${f}`);
82
82
  }
83
+ // 降级链整组审计(实例必不同,按内容比较)。
84
+ const af = prev.roles?.models?.[role]?.fallbacks;
85
+ const bf = next.roles?.models?.[role]?.fallbacks;
86
+ if (JSON.stringify(af ?? []) !== JSON.stringify(bf ?? []))
87
+ keys.add(`roles.models.${role}.fallbacks`);
83
88
  }
84
89
  if (prev.reviewEngine?.mode !== next.reviewEngine?.mode)
85
90
  keys.add('reviewEngine.mode');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joekytc/dsh-swarm",
3
- "version": "0.3.12",
3
+ "version": "0.5.1",
4
4
  "description": "A governed swarm of six specialist DSH agents (orchestrator, planner, knowledge-base bridge, developer and two reviewers) that turns a requirement into a strict phase pipeline with machine-verified delivery evidence, review-gated merges, a full audit-log event stream and a live kanban tab; design inspired by the Hermes Agent kanban",
5
5
  "license": "MIT",
6
6
  "author": "joekytc",
@@ -33,7 +33,8 @@
33
33
  "client": {
34
34
  "platform": "web",
35
35
  "inject": [
36
- "@deepseek-ai/dsh-client-ui-conversation"
36
+ "@deepseek-ai/dsh-client-ui-conversation",
37
+ "@deepseek-ai/dsh-client-ui-workspace"
37
38
  ]
38
39
  }
39
40
  },
@@ -58,27 +59,32 @@
58
59
  "test": "vitest run",
59
60
  "build:client": "node scripts/build-client.mjs"
60
61
  },
62
+ "dependencies": {
63
+ "js-yaml": "^4.3.2"
64
+ },
61
65
  "peerDependencies": {
62
66
  "@deepseek-ai/cordis": "^4.0.1",
63
- "@deepseek-ai/dsh-agent": "^0.1.2-rc.1",
64
- "@deepseek-ai/dsh-api-session-controller": "^0.1.2-rc.1",
65
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-rc.1",
66
- "@deepseek-ai/dsh-credentials": "^0.1.2-rc.1",
67
- "@deepseek-ai/dsh-persona": "^0.1.2-rc.1",
68
- "@deepseek-ai/dsh-session": "^0.1.2-rc.1",
69
- "@deepseek-ai/dsh-tool-bash": "^0.1.2-rc.1",
70
- "@deepseek-ai/dsh-tool-fs": "^0.1.2-rc.1",
71
- "@deepseek-ai/dsh-tool-fs-search": "^0.1.2-rc.1",
72
- "@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
73
- "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1",
67
+ "@deepseek-ai/dsh-agent": "~0.1.7-rc.2 || ^0.2.0-rc.2",
68
+ "@deepseek-ai/dsh-api-session-controller": "~0.1.7-rc.2 || ^0.2.0-rc.2",
69
+ "@deepseek-ai/dsh-client-ui-conversation": "~0.1.7-rc.2 || ^0.2.0-rc.2",
70
+ "@deepseek-ai/dsh-credentials": "~0.1.7-rc.2 || ^0.2.0-rc.2",
71
+ "@deepseek-ai/dsh-persona": "~0.1.7-rc.2 || ^0.2.0-rc.2",
72
+ "@deepseek-ai/dsh-session": "~0.1.7-rc.2 || ^0.2.0-rc.2",
73
+ "@deepseek-ai/dsh-tool-bash": "~0.1.7-rc.2 || ^0.2.0-rc.2",
74
+ "@deepseek-ai/dsh-tool-fs": "~0.1.7-rc.2 || ^0.2.0-rc.2",
75
+ "@deepseek-ai/dsh-tool-fs-search": "~0.1.7-rc.2 || ^0.2.0-rc.2",
76
+ "@deepseek-ai/dsh-tools": "~0.1.7-rc.2 || ^0.2.0-rc.2",
77
+ "@deepseek-ai/dsh-util-values": "~0.1.7-rc.2 || ^0.2.0-rc.2",
74
78
  "@deepseek-ai/schemastery": "^3.18.1"
75
79
  },
76
80
  "devDependencies": {
77
- "@deepseek-ai/dsh-client-store": "^0.1.2-rc.1",
78
- "@deepseek-ai/dsh-client-ui-layout": "^0.1.2-rc.1",
79
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
81
+ "@deepseek-ai/cordis-plugin-include": "^1.0.9",
82
+ "@deepseek-ai/dsh-client-store": "^0.2.0-rc.2",
83
+ "@deepseek-ai/dsh-client-ui-layout": "^0.2.0-rc.2",
84
+ "@deepseek-ai/dsh-client-ui-slots": "^0.2.0-rc.2",
80
85
  "@testing-library/dom": "^10.4.0",
81
86
  "@testing-library/react": "^16.1.0",
87
+ "@types/js-yaml": "^4.0.9",
82
88
  "@types/node": "^22.0.0",
83
89
  "@types/react": "^18.3.0",
84
90
  "@types/react-dom": "^18.3.0",
@@ -90,4 +96,4 @@
90
96
  "typescript": "^5.8.0",
91
97
  "vitest": "^3.0.0"
92
98
  }
93
- }
99
+ }
@@ -12,7 +12,7 @@
12
12
  - id: persona
13
13
  name: '@deepseek-ai/dsh-persona'
14
14
  config:
15
- text: >-
15
+ prefix: >-
16
16
  You are the fullstack development agent (the ONLY executor) powered by the {{model}} model.
17
17
  Your working directory is {{cwd}}. You implement and test the aligned spec; you are
18
18
  the sole accountable executor and may delegate implementation subtasks. Rules:
@@ -134,12 +134,14 @@
134
134
  config:
135
135
  provider: spawn
136
136
  toolName: subagent
137
+ maxDepth: 3
137
138
 
138
139
  - id: tool-subagent-fork
139
140
  name: '@deepseek-ai/dsh-tool-subagent'
140
141
  config:
141
142
  provider: fork
142
143
  toolName: subagent_fork
144
+ maxDepth: 3
143
145
 
144
146
  - id: tool-subagent-control
145
147
  name: '@deepseek-ai/dsh-tool-subagent-control'
@@ -11,7 +11,7 @@
11
11
  - id: persona
12
12
  name: '@deepseek-ai/dsh-persona'
13
13
  config:
14
- text: >-
14
+ prefix: >-
15
15
  You are the implementation verifier + reviewer agent (read-only) powered by the {{model}}
16
16
  model. Your working directory is {{cwd}}. You empirically verify D's implementation and
17
17
  review it — you never modify source and you never execute writes. Rules:
@@ -95,3 +95,4 @@
95
95
  config:
96
96
  provider: spawn
97
97
  toolName: subagent
98
+ maxDepth: 3
@@ -15,7 +15,7 @@
15
15
  - id: persona
16
16
  name: '@deepseek-ai/dsh-persona'
17
17
  config:
18
- text: >-
18
+ prefix: >-
19
19
  You are the planning agent (planner) powered by the {{model}} model. Your working
20
20
  directory is {{cwd}}. You produce the implementation plan only — you are NOT the
21
21
  executor. When injected repo facts are insufficient, you may do READ-ONLY self-inspection
@@ -9,7 +9,7 @@
9
9
  - id: persona
10
10
  name: '@deepseek-ai/dsh-persona'
11
11
  config:
12
- text: >-
12
+ prefix: >-
13
13
  You are the plan-review agent (read-only) powered by the {{model}} model. Your working
14
14
  directory is {{cwd}}. You review P's plan deliverable only — you never modify any artifact
15
15
  and you never execute code. Rules:
@@ -12,7 +12,7 @@
12
12
  - id: persona
13
13
  name: '@deepseek-ai/dsh-persona'
14
14
  config:
15
- text: >-
15
+ prefix: >-
16
16
  You are the orchestration agent (butler) powered by the {{model}} model. Your working
17
17
  directory is {{cwd}}. You only decompose, dispatch and summarize — you are NEVER the executor.
18
18
  Rules:
@@ -12,7 +12,7 @@
12
12
  - id: persona
13
13
  name: '@deepseek-ai/dsh-persona'
14
14
  config:
15
- text: >-
15
+ prefix: >-
16
16
  You are the knowledge officer (Knowledge Officer) powered by the {{model}} model. Your
17
17
  working directory is {{cwd}}. You curate the requirement knowledge base (KB) in one of two
18
18
  modes (the active mode and the local KB root, when local, are stated in your task context);
@@ -6,7 +6,7 @@
6
6
  - id: persona
7
7
  name: '@deepseek-ai/dsh-persona'
8
8
  config:
9
- text: >-
9
+ prefix: >-
10
10
  你是蜂群模式的领队。本模式下你负责把「要动手开发的需求」转化为一条多角色工作流链并跟进到交付;其余对话正常应答。
11
11
 
12
12
  ## 分流判定(每轮先判)