dsh-plugin-t-expert 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -180
- package/THIRD-PARTY-NOTICES +23 -17
- package/data/source.json +3 -88
- package/data/team-profiles.py +1 -1
- package/data/zh/COVERAGE.json +1 -1
- package/lib/catalog.js +206 -42
- package/lib/client.js +458 -10
- package/lib/i18n.js +37 -5
- package/lib/index.js +315 -22
- package/lib/remote.js +173 -1
- package/lib/squads.js +9 -2
- package/package.json +2 -4
- package/vendor/dsh-agent-teams/VENDOR.md +0 -53
package/lib/remote.js
CHANGED
|
@@ -19,12 +19,43 @@ const expertSchema = z.object({
|
|
|
19
19
|
divisionZh: z.string(),
|
|
20
20
|
divisionEn: z.string(),
|
|
21
21
|
conflict: z.boolean().optional(),
|
|
22
|
+
/** 用户自建专家(可编辑/可删除);内置专家不带此标记。 */
|
|
23
|
+
custom: z.boolean().optional(),
|
|
24
|
+
/** 自建专家文件指纹:编辑/删除时回传,用于拦住并发覆盖。 */
|
|
25
|
+
hash: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/** 新建/编辑自建专家的入参(面板表单字段)。 */
|
|
29
|
+
const customExpertInputSchema = z.object({
|
|
30
|
+
slug: z.string().min(1).max(128).optional(),
|
|
31
|
+
name: z.string().min(1).max(200),
|
|
32
|
+
nameEn: z.string().max(200).optional(),
|
|
33
|
+
description: z.string().min(1).max(1000),
|
|
34
|
+
descriptionEn: z.string().max(1000).optional(),
|
|
35
|
+
emoji: z.string().max(16).optional(),
|
|
36
|
+
body: z.string().min(1).max(60000),
|
|
37
|
+
/** 落点分区(自建分区目录名);留空=默认分区。服务端仍会自己校验一遍。 */
|
|
38
|
+
division: z.string().max(128).optional(),
|
|
39
|
+
/** 新建分区时的中文显示名(落在 <customRoot>/divisions.json)。 */
|
|
40
|
+
divisionLabel: z.string().max(40).optional(),
|
|
22
41
|
});
|
|
23
42
|
|
|
24
43
|
const catalogSnapshotSchema = z.object({
|
|
25
44
|
experts: z.array(expertSchema),
|
|
26
45
|
enabled: z.array(z.string()),
|
|
27
46
|
revision: z.number().int().min(0),
|
|
47
|
+
// 这两个字段必须声明:zod 会把 schema 里没有的键**直接剥掉**(实测),
|
|
48
|
+
// 漏声明时面板拿到的快照里根本没有它们,界面上表现为"分区标签是空的"。
|
|
49
|
+
customDivision: z.string().optional(),
|
|
50
|
+
customDivisionLabel: z.string().optional(),
|
|
51
|
+
/** 可选的落点分类(面板「分类」下拉与管理页):官方在前,其余按目录/声明发现。 */
|
|
52
|
+
categories: z.array(z.object({
|
|
53
|
+
key: z.string(),
|
|
54
|
+
label: z.string(),
|
|
55
|
+
official: z.boolean(),
|
|
56
|
+
count: z.number().int().min(0),
|
|
57
|
+
customCount: z.number().int().min(0),
|
|
58
|
+
})).optional(),
|
|
28
59
|
});
|
|
29
60
|
|
|
30
61
|
const enabledStateSchema = z.object({
|
|
@@ -200,6 +231,86 @@ const DESCRIPTORS = [
|
|
|
200
231
|
codec: { mode: "strict", typeSymbol: "string", schema: z.string().min(1).max(128) },
|
|
201
232
|
},
|
|
202
233
|
], "TTeamStopResult", stopResultSchema),
|
|
234
|
+
// 自建专家的增删改:都回传刷新后的整份名册快照,面板拿到就能直接重绘。
|
|
235
|
+
descriptor("createExpert", [
|
|
236
|
+
{
|
|
237
|
+
name: "expert",
|
|
238
|
+
wire: "expert",
|
|
239
|
+
source: "json",
|
|
240
|
+
codec: { mode: "strict", typeSymbol: "TTeamCustomExpertInput", schema: customExpertInputSchema },
|
|
241
|
+
},
|
|
242
|
+
], "TTeamCatalog", catalogSnapshotSchema),
|
|
243
|
+
descriptor("updateExpert", [
|
|
244
|
+
{
|
|
245
|
+
name: "slug",
|
|
246
|
+
wire: "slug",
|
|
247
|
+
source: "json",
|
|
248
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().min(1).max(128) },
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: "expert",
|
|
252
|
+
wire: "expert",
|
|
253
|
+
source: "json",
|
|
254
|
+
codec: { mode: "strict", typeSymbol: "TTeamCustomExpertInput", schema: customExpertInputSchema },
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: "expectedHash",
|
|
258
|
+
wire: "expectedHash",
|
|
259
|
+
source: "json",
|
|
260
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().max(64) },
|
|
261
|
+
},
|
|
262
|
+
], "TTeamCatalog", catalogSnapshotSchema),
|
|
263
|
+
descriptor("deleteExpert", [
|
|
264
|
+
{
|
|
265
|
+
name: "slug",
|
|
266
|
+
wire: "slug",
|
|
267
|
+
source: "json",
|
|
268
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().min(1).max(128) },
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
name: "expectedHash",
|
|
272
|
+
wire: "expectedHash",
|
|
273
|
+
source: "json",
|
|
274
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().max(64) },
|
|
275
|
+
},
|
|
276
|
+
], "TTeamCatalog", catalogSnapshotSchema),
|
|
277
|
+
// 分类管理:都回传刷新后的整份名册快照(面板拿到就能直接重绘)。
|
|
278
|
+
descriptor("createCategory", [
|
|
279
|
+
{
|
|
280
|
+
name: "key",
|
|
281
|
+
wire: "key",
|
|
282
|
+
source: "json",
|
|
283
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().min(1).max(128) },
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: "label",
|
|
287
|
+
wire: "label",
|
|
288
|
+
source: "json",
|
|
289
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().max(40) },
|
|
290
|
+
},
|
|
291
|
+
], "TTeamCatalog", catalogSnapshotSchema),
|
|
292
|
+
descriptor("updateCategory", [
|
|
293
|
+
{
|
|
294
|
+
name: "key",
|
|
295
|
+
wire: "key",
|
|
296
|
+
source: "json",
|
|
297
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().min(1).max(128) },
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "label",
|
|
301
|
+
wire: "label",
|
|
302
|
+
source: "json",
|
|
303
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().max(40) },
|
|
304
|
+
},
|
|
305
|
+
], "TTeamCatalog", catalogSnapshotSchema),
|
|
306
|
+
descriptor("deleteCategory", [
|
|
307
|
+
{
|
|
308
|
+
name: "key",
|
|
309
|
+
wire: "key",
|
|
310
|
+
source: "json",
|
|
311
|
+
codec: { mode: "strict", typeSymbol: "string", schema: z.string().min(1).max(128) },
|
|
312
|
+
},
|
|
313
|
+
], "TTeamCatalog", catalogSnapshotSchema),
|
|
203
314
|
];
|
|
204
315
|
|
|
205
316
|
/** Host 严格描述符表;Gateway 优先读取它,避免启动期 SRC 扫描漏掉后加载的外部插件服务。 */
|
|
@@ -345,9 +456,70 @@ class TTeamRemote extends TypertRemoteService {
|
|
|
345
456
|
throw new RemoteError("tTeam/missing-expert", message, { slug });
|
|
346
457
|
}
|
|
347
458
|
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* 新建自建专家。服务侧校验 slug 合法性、与内置/自建 slug 撞车、以及与既有专家重名
|
|
462
|
+
* (重名会把内置那位一起标成冲突、双双不可召唤,所以必须挡在写盘前)。
|
|
463
|
+
*/
|
|
464
|
+
async createExpert(expert) {
|
|
465
|
+
try {
|
|
466
|
+
return await this.catalog().createExpert(expert);
|
|
467
|
+
} catch (error) {
|
|
468
|
+
throw this.businessError(error, "tTeam/custom-invalid");
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** 编辑自建专家;`expectedHash` 是打开表单时拿到的指纹,不符即并发冲突。 */
|
|
473
|
+
async updateExpert(slug, expert, expectedHash) {
|
|
474
|
+
try {
|
|
475
|
+
return await this.catalog().updateExpert(slug, expert, expectedHash);
|
|
476
|
+
} catch (error) {
|
|
477
|
+
throw this.businessError(error, "tTeam/custom-invalid");
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/** 删除自建专家;同样做指纹校验。 */
|
|
482
|
+
async deleteExpert(slug, expectedHash) {
|
|
483
|
+
try {
|
|
484
|
+
return await this.catalog().deleteExpert(slug, expectedHash);
|
|
485
|
+
} catch (error) {
|
|
486
|
+
throw this.businessError(error, "tTeam/custom-invalid");
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** 新建自建分类(可以先是空分类)。 */
|
|
491
|
+
async createCategory(key, label) {
|
|
492
|
+
try {
|
|
493
|
+
return await this.catalog().createCategory(key, label);
|
|
494
|
+
} catch (error) {
|
|
495
|
+
throw this.businessError(error, "tTeam/category-invalid");
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/** 改自建分类的显示名(官方分类只读,服务端会拒)。 */
|
|
500
|
+
async updateCategory(key, label) {
|
|
501
|
+
try {
|
|
502
|
+
return await this.catalog().updateCategory(key, label);
|
|
503
|
+
} catch (error) {
|
|
504
|
+
throw this.businessError(error, "tTeam/category-invalid");
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/** 删除自建分类(里面还有自建专家就拒)。 */
|
|
509
|
+
async deleteCategory(key) {
|
|
510
|
+
try {
|
|
511
|
+
return await this.catalog().deleteCategory(key);
|
|
512
|
+
} catch (error) {
|
|
513
|
+
throw this.businessError(error, "tTeam/category-invalid");
|
|
514
|
+
}
|
|
515
|
+
}
|
|
348
516
|
}
|
|
349
517
|
|
|
350
|
-
exposeRemoteMethods(TTeamRemote, [
|
|
518
|
+
exposeRemoteMethods(TTeamRemote, [
|
|
519
|
+
"getCatalog", "setEnabled", "getPrompt", "getSquads", "saveSquads", "getTeams", "stopTeam", "startSquad",
|
|
520
|
+
"createExpert", "updateExpert", "deleteExpert",
|
|
521
|
+
"createCategory", "updateCategory", "deleteCategory",
|
|
522
|
+
]);
|
|
351
523
|
|
|
352
524
|
export { SETTINGS_NAMESPACE, DESCRIPTORS, TYPERT };
|
|
353
525
|
export default TTeamRemote;
|
package/lib/squads.js
CHANGED
|
@@ -35,9 +35,16 @@ function memberSlug(member) {
|
|
|
35
35
|
return "";
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
/**
|
|
39
|
+
* @param generator - 小队编译器路径。调用方**优先传包内那份**(`<包>/data/team-profiles.py`):
|
|
40
|
+
* 它是随插件版本走的**代码**,而数据目录里那份只在首次启动时播种一次(非破坏性),
|
|
41
|
+
* 升级时不会更新 —— 一直用数据目录那份,等于这个版本的编译器修复永远送不到老用户手里。
|
|
42
|
+
*/
|
|
43
|
+
export function createSquadService({ teamsFile, catalog, python = "python3", generator: generatorPath }) {
|
|
39
44
|
const dataDir = dirname(teamsFile);
|
|
40
|
-
const generator =
|
|
45
|
+
const generator = typeof generatorPath === "string" && generatorPath !== ""
|
|
46
|
+
? generatorPath
|
|
47
|
+
: join(dataDir, "team-profiles.py");
|
|
41
48
|
let lastBuild = { at: 0, ok: true, output: "" };
|
|
42
49
|
|
|
43
50
|
function readSpec() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-t-expert",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "T Expert — a 314-expert, 22-division roster with full Chinese translations, as a standalone DeepSeek Harness plugin, with a built-in multi-agent team engine (T Team).",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,6 @@
|
|
|
47
47
|
"LICENSE",
|
|
48
48
|
"THIRD-PARTY-NOTICES",
|
|
49
49
|
"vendor/dsh-agent-teams/LICENSE",
|
|
50
|
-
"vendor/dsh-agent-teams/VENDOR.md",
|
|
51
50
|
"vendor/third-party-licenses"
|
|
52
51
|
],
|
|
53
52
|
"dsh": {
|
|
@@ -67,9 +66,8 @@
|
|
|
67
66
|
}
|
|
68
67
|
},
|
|
69
68
|
"scripts": {
|
|
70
|
-
"build": "node ../
|
|
69
|
+
"build": "node ../build-client.mjs",
|
|
71
70
|
"verify": "node ../verify.mjs",
|
|
72
|
-
"brand": "node ../brand.mjs",
|
|
73
71
|
"sync-data": "node ../sync-data.mjs",
|
|
74
72
|
"prepublishOnly": "npm run build && npm run verify && node ../sync-data.mjs --check"
|
|
75
73
|
},
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# vendor: @nanmicoder/dsh-agent-teams(T专家 内置团队引擎)
|
|
2
|
-
|
|
3
|
-
路线 A:把 AgentTeams 的团队引擎**原样**内置进 T专家,安装后不再需要单独安装 AgentTeams。
|
|
4
|
-
|
|
5
|
-
| 项 | 值 |
|
|
6
|
-
| --- | --- |
|
|
7
|
-
| 上游仓库 | https://github.com/NanmiCoder/dsh-agent-teams |
|
|
8
|
-
| 上游版本 | `0.1.17-rc.1` |
|
|
9
|
-
| 仓库 commit | `18fba6211fc3aac305fc9bb1c8a7faaf7273137a` |
|
|
10
|
-
| 同步来源目录 | `~/.dsh/profiles/desktop/node_modules/@nanmicoder/dsh-agent-teams` |
|
|
11
|
-
| 同步时间 | 2026-09-11 18:31:14 +0800 |
|
|
12
|
-
| 许可 | MIT(见同目录 LICENSE;本目录文件保持逐字节原样) |
|
|
13
|
-
|
|
14
|
-
## 同步进来的文件
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
lib/teams/capabilities.js 4943 bytes
|
|
18
|
-
lib/teams/command.js 8378 bytes
|
|
19
|
-
lib/teams/event-types.js 569 bytes
|
|
20
|
-
lib/teams/events.js 2827 bytes
|
|
21
|
-
lib/teams/harness-compat.js 8733 bytes
|
|
22
|
-
lib/teams/index.js 27236 bytes
|
|
23
|
-
lib/teams/members.js 33124 bytes
|
|
24
|
-
lib/teams/profiles.js 23215 bytes
|
|
25
|
-
lib/teams/quality-gates.js 37323 bytes
|
|
26
|
-
lib/teams/scheduler.js 24563 bytes
|
|
27
|
-
lib/teams/snapshot.js 7725 bytes
|
|
28
|
-
lib/teams/state.js 38289 bytes
|
|
29
|
-
lib/teams/tool-names.js 708 bytes
|
|
30
|
-
lib/teams/tools.js 127546 bytes
|
|
31
|
-
lib/teams/types.js 780 bytes
|
|
32
|
-
lib/teams/web-routes.js 3328 bytes
|
|
33
|
-
vendor/dsh-agent-teams/client.bundle.txt 197722 bytes
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## T专家 的改动点(都在我们的代码里,vendor 文件不动)
|
|
37
|
-
|
|
38
|
-
1. host:`lib/index.js` 里 `ctx.plugin(engineNamespace, engineConfig)` 内部挂载引擎,配置来自
|
|
39
|
-
`~/.t-team/t-team.config.json`(由 `team-profiles.py` 依据 `teams.json` 生成)。
|
|
40
|
-
2. client:`src/client.jsx` 在 factory 里临时截获 `window.__ModuleLoader__.load`,取出上游 client bundle
|
|
41
|
-
注册的 factory,用我们自己的 `require` 物化它,再调用它的 `apply(ctx)` —— 于是团队树/草案面板与
|
|
42
|
-
T专家 的设置页共用同一个客户端模块(同一个注册 id,DSH 只允许一个包注册一个 id)。
|
|
43
|
-
3. 工具名保持上游的 `agent_teams_*`,命令保持 `/agent-teams`;T专家 另加 `/t` 短命令与专家名册工具。
|
|
44
|
-
|
|
45
|
-
## 更新上游
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
bash ~/web/t-team/tz.sh 13 # 从已安装的包同步(先 dshmarket/pnpm 升到新版)
|
|
49
|
-
bash ~/web/t-team/tz.sh engine-sync --check # 只看差异
|
|
50
|
-
bash ~/web/t-team/tz.sh engine-sync --from DIR --clone ~/.t-team/vendor/dsh-agent-teams
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
同步后:`bash ~/web/t-team/tz.sh 10`(自检)→ `tz.sh 12`(构建)→ `tz.sh 8`(安装)→ 重启 DSH Desktop。
|