@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.
- package/client/ConfigSection.tsx +127 -18
- package/client/ConfigSelect.tsx +1 -0
- package/client/config-store.ts +6 -3
- package/client/config.css +89 -1
- package/client/index.ts +8 -4
- package/client/session-bridge.ts +26 -2
- package/cordis.patch.yml +10 -52
- package/lib/client.js +215 -37
- package/lib/config.d.ts +7 -0
- package/lib/config.js +7 -1
- package/lib/dispatcher/agent-runner.d.ts +4 -0
- package/lib/dispatcher/agent-runner.js +28 -17
- package/lib/dispatcher/chain-auditor.d.ts +3 -2
- package/lib/dispatcher/chain-auditor.js +2 -2
- package/lib/dispatcher/model-candidates.d.ts +9 -3
- package/lib/dispatcher/model-candidates.js +27 -6
- package/lib/dispatcher/model-chain.d.ts +19 -0
- package/lib/dispatcher/model-chain.js +110 -0
- package/lib/dispatcher/session-events.d.ts +9 -0
- package/lib/dispatcher/session-events.js +28 -0
- package/lib/dispatcher/v-orchestrator.d.ts +2 -0
- package/lib/dispatcher/v-orchestrator.js +14 -9
- package/lib/domain/config-override.d.ts +20 -0
- package/lib/domain/config-override.js +46 -2
- package/lib/index.js +13 -3
- package/lib/roles/preset-installer.d.ts +50 -5
- package/lib/roles/preset-installer.js +154 -20
- package/lib/routes/kanban-http.js +24 -3
- package/lib/services/config-provider.js +5 -0
- package/package.json +23 -17
- package/personas/kanban-d/agent.cordis.yml +3 -1
- package/personas/kanban-dt/agent.cordis.yml +2 -1
- package/personas/kanban-p/agent.cordis.yml +1 -1
- package/personas/kanban-pt/agent.cordis.yml +1 -1
- package/personas/kanban-v/agent.cordis.yml +1 -1
- package/personas/kanban-w/agent.cordis.yml +1 -1
- 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
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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(
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
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
|
-
|
|
112
|
+
written.push(id);
|
|
46
113
|
}
|
|
47
114
|
catch (err) {
|
|
48
115
|
// 尽力而为:写入失败(如沙箱/权限拒绝)仅告警,不阻断插件启动
|
|
49
|
-
console.warn('[dsh-swarm] role preset
|
|
116
|
+
console.warn('[dsh-swarm] role preset dir write skipped ' + id + ' -> ' + dstRoot + ': ' + String(err));
|
|
50
117
|
}
|
|
51
118
|
}
|
|
52
|
-
return
|
|
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(再兜底默认):旧客户端
|
|
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: {
|
|
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
|
+
"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": "
|
|
64
|
-
"@deepseek-ai/dsh-api-session-controller": "
|
|
65
|
-
"@deepseek-ai/dsh-client-ui-conversation": "
|
|
66
|
-
"@deepseek-ai/dsh-credentials": "
|
|
67
|
-
"@deepseek-ai/dsh-persona": "
|
|
68
|
-
"@deepseek-ai/dsh-session": "
|
|
69
|
-
"@deepseek-ai/dsh-tool-bash": "
|
|
70
|
-
"@deepseek-ai/dsh-tool-fs": "
|
|
71
|
-
"@deepseek-ai/dsh-tool-fs-search": "
|
|
72
|
-
"@deepseek-ai/dsh-tools": "
|
|
73
|
-
"@deepseek-ai/dsh-util-values": "
|
|
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/
|
|
78
|
-
"@deepseek-ai/dsh-client-
|
|
79
|
-
"@deepseek-ai/dsh-client-ui-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|