dsh-plugin-t-expert 0.3.84 → 0.3.89

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 (41) hide show
  1. package/README.md +29 -56
  2. package/THIRD-PARTY-NOTICES +6 -31
  3. package/data/experts/engineering/engineering-deepseek-harness-project-expert.md +5 -5
  4. package/lib/bootstrap.js +11 -33
  5. package/lib/catalog.js +1 -1
  6. package/lib/client.js +20830 -21811
  7. package/lib/i18n.js +0 -4
  8. package/lib/index.js +173 -862
  9. package/lib/remote-schemas.js +5 -104
  10. package/lib/remote.js +7 -174
  11. package/lib/schedule.js +99 -26
  12. package/lib/skill.js +11 -12
  13. package/package.json +3 -12
  14. package/vendor/third-party-licenses/README.md +0 -1
  15. package/data/t-team.config.json +0 -1558
  16. package/data/team-profiles.py +0 -367
  17. package/data/teams.json +0 -791
  18. package/data/teams.resolved.json +0 -1594
  19. package/lib/command.js +0 -251
  20. package/lib/plan-check.js +0 -166
  21. package/lib/squads.js +0 -446
  22. package/lib/teams/assignee-contract.js +0 -47
  23. package/lib/teams/capabilities.js +0 -106
  24. package/lib/teams/command.js +0 -147
  25. package/lib/teams/event-types.js +0 -12
  26. package/lib/teams/events.js +0 -60
  27. package/lib/teams/harness-compat.js +0 -561
  28. package/lib/teams/index.js +0 -463
  29. package/lib/teams/members.js +0 -619
  30. package/lib/teams/profiles.js +0 -572
  31. package/lib/teams/quality-gates.js +0 -905
  32. package/lib/teams/scheduler.js +0 -642
  33. package/lib/teams/snapshot.js +0 -184
  34. package/lib/teams/state.js +0 -946
  35. package/lib/teams/tool-names.js +0 -11
  36. package/lib/teams/tools.js +0 -2346
  37. package/lib/teams/types.js +0 -22
  38. package/lib/teams/web-routes.js +0 -86
  39. package/skills/dsh-harness-languages/SKILL.md +0 -175
  40. package/skills/dsh-harness-project/SKILL.md +0 -236
  41. package/vendor/dsh-agent-teams/LICENSE +0 -21
package/README.md CHANGED
@@ -1,19 +1,29 @@
1
1
  # T专家(dsh-plugin-t-expert)
2
2
 
3
- dsh-plugin-t-expert 插件:包含 **22 个分类 / 323 位专家**的名册(中文名、简介全量覆盖),
4
- 外加插件自带的**多智能体团队引擎**(T Team:小队模板、任务 DAG、调度、活动面板)。
3
+ dsh-plugin-t-expert 插件:包含 **22 个分类 / 323 位专家**的名册(中文名、简介全量覆盖)。
5
4
 
6
- 装上以后你能做四件事:
5
+ 装上以后你能做两件事:
7
6
 
8
7
  | 做什么 | 怎么做 |
9
8
  | --- | --- |
10
9
  | 用专家 | 输入框打 `@` → 按分类分组的菜单 → 选中的专家作为引用 chip 进本轮对话;模型也可自行 `summon_t_expert` |
11
- | 拉起一支小队干活 | `/t <小队> <目标>`(`/t` 单跑列出现有小队) |
12
10
  | 管名册 | 设置 → T专家 → **专家**(启停 / 看提示词 / 新建自建专家) |
13
- | 管分类、小队与团队 | 设置 → T专家 → **分类**(自建分类增删改)、**队伍**(小队模板)、**团队**(运行中的团队:停止 / 归档 / 删除) |
14
11
 
15
12
  ## 安装
16
13
 
14
+ **本机开发 / 维护者(file: 装到 profile)**:
15
+
16
+ ```bash
17
+ # 工作区根运行,菜单里选对应插件的「8 安装/重装」。
18
+ bash ~/web/t-team/tz.sh
19
+ # 或直接走完整子命令(默认探测 profile=web,本机没桌面 electron 就用这个):
20
+ bash ~/web/t-team/tz.sh install
21
+ # 卸载
22
+ bash ~/web/t-team/tz.sh uninstall
23
+ ```
24
+
25
+ **发布到 npm 之后(普通用户)**:
26
+
17
27
  ```bash
18
28
  dsh plugin --profile web add dsh-plugin-t-expert
19
29
  ```
@@ -21,13 +31,7 @@ dsh plugin --profile web add dsh-plugin-t-expert
21
31
  DSH Desktop 请在插件市场里搜 `dsh-plugin-t-expert` 安装(`--profile desktop` 由 Electron 应用独占,
22
32
  CLI 会被拒绝 —— 任何插件都一样)。
23
33
 
24
- - 依赖:DSH 宿主 `0.1.5-rc.1` / `0.1.5-rc.2`;Node `^22.19.0 || >=24`;`pnpm` 在 PATH 上。
25
- `python3` 只在**保存小队**时用到(缺它插件照常加载,只是小队编译会报错并回滚)。
26
- 团队引擎对接的是宿主**未文档化**的内部投递契约,实测过的宿主版本记在
27
- `lib/teams/harness-compat.js` 的 `TESTED_HARNESS_VERSIONS`:版本不在矩阵里、或契约形状变了,
28
- 日志会有一条 `[t-team] ... contract ...`,提示段也会写明(见「常见问题」最后两行)。
29
- 符号口径变了(上游不再用 `Symbol.for`)时插件会动态 import 宿主的 `internal` 子路径拿**真身**
30
- 符号并自动重挂引擎 —— 能自救,但日志里照样留一条,方便你把实测矩阵补齐。
34
+ - 依赖:DSH 宿主 `0.1.5-rc.1` / `0.1.5-rc.2` / `0.1.7-alpha.1`;Node `^22.19.0 || >=24`;`pnpm` 在 PATH 上。
31
35
  - 装完**重启 DSH** 即可用;第一次怎么上手见下面的「快速上手」。
32
36
 
33
37
  ## 快速上手
@@ -35,17 +39,14 @@ CLI 会被拒绝 —— 任何插件都一样)。
35
39
  1. **启用专家**:设置 → T专家 → **专家**,把要用的打开 —— **默认全部未启用**,未启用的不会被召唤。
36
40
  2. **用一位专家**:输入框打 `@`,按分类挑一位,它以引用 chip 进入本轮对话;也可以直接说"让 XX 专家看看",
37
41
  由模型调 `summon_t_expert`。
38
- 3. **拉一支小队**:`/t` 看有哪些小队,`/t <小队> <目标>` 让它干活 —— 先给成员与任务草案,
39
- 你 review 后开跑。随包自带一批**按领域拆分**的队伍(每支 4–6 人、角色互补),用 `/t` 就能看到;
40
- 想自己加或改,去 **设置 → 队伍**;也可以用 `python3 ops/squads-expand.py` 按分类重新展开一批。
41
42
 
42
43
  ## 界面入口
43
44
 
44
45
  | 位置 | 是什么 |
45
46
  | --- | --- |
46
- | 设置 → T专家 | 管理页,一共**四个标签**:**专家**(启停 / 提示词 / 新建自建专家)、**分类**(自建分类增删改)、**队伍**(小队模板)、**团队**(运行中的团队:停止 / 归档 / 删除) |
47
+ | 设置 → T专家 | 管理页,两个标签:**专家**(启停 / 提示词 / 新建自建专家)、**分类**(自建分类增删改) |
47
48
  | 输入框 `@` | 按分类分组的专家菜单,选中即插入引用 chip |
48
- | 输入区「T专家」按钮 | 浮层标签:**专家 → 技能 → 小队 →(有运行中的团队时才出现)团队 → 任务**,默认停在**专家**;专家 / 小队 / 技能三个标签带计数(该标签里的总条数,不随搜索框变化) |
49
+ | 输入区「T专家」按钮 | 浮层标签:**专家 → 技能 → 任务**,默认停在**专家**;专家 / 技能两个标签带计数(该标签里的总条数,不随搜索框变化) |
49
50
  | 会话标题栏徽章 | 后台任务只读面板(当前会话及其子代理的任务:状态、退出码、耗时);只在真有任务在跑时亮起并给出数量,**面板绝不自动展开**,可拖动、位置记在本机 |
50
51
  | 左侧栏「新会话」下方 | **定时任务**入口(与「新会话」同款按钮外观),点开在右侧主区域显示管理页;点任意会话即回到会话视图 |
51
52
 
@@ -61,27 +62,6 @@ CLI 会被拒绝 —— 任何插件都一样)。
61
62
  | `list_t_experts` | 列出已启用专家的分类与数量;传分类名可列出该分类的专家 |
62
63
  | `summon_t_expert` | 召唤 1 位专家:以它的完整人格跑一个子代理并返回结果 |
63
64
  | `summon_t_experts` | 并行召唤多位(最多 8 位、并发 4;部分失败仍返回成功的结果) |
64
- | `t_team_plan_check` | 只读 DAG 预检:一批团队任务先跑一遍引擎校验,一次报出全部问题 |
65
-
66
- ## 小队与团队引擎
67
-
68
- ```bash
69
- /t # 列出所有小队(key、别名、人数、成员中文名)
70
- /t <小队|别名> # 选定小队,队长列出成员并问你目标
71
- /t <小队|别名> <目标> # 拉起小队干活(先给成员与任务草案,你 review 后开跑)
72
- /t <一句话目标> # 没匹配到小队名时,按目标自动挑最合适的小队
73
- ```
74
-
75
- 引擎另注册 **13 个 `t_team_*` 工具**(建队 / 审批 / 建任务 / 派发 / 状态 / 恢复 / 删除…),随插件一起提供;
76
- 队长与成员各看到其中一个子集。
77
-
78
- **设置 → 队伍**里改成员 / 别名 / 启停,保存写回 `~/.t-team/teams.json` 并调用小队编译器:
79
- **保存后立即生效,无需重启 DSH**——编译成功后运行中的插件就地重载引擎配置,`/t` 与新建队随即看到新小队,
80
- 已经跑起来的团队继续用启动时的成员表。**编译失败会自动回滚**,盘上仍是旧配置,设置页直接报错并说明引擎是否可用。
81
-
82
- 约束:小队 key 只能 ASCII `a-z0-9-`(中文放 `description` / `aliases`);每队 ≤ `maxMembers`(默认 8);
83
- 小队总数 ≤ 48(随包这 48 支正好用满上限,再加要先腾位置);别名全局唯一;成员必须是名册里真实存在的专家。
84
- 编辑入口是 **设置 → 队伍**(保存即编译并热重载)。
85
65
 
86
66
  ## 定时任务
87
67
 
@@ -107,53 +87,46 @@ CLI 会被拒绝 —— 任何插件都一样)。
107
87
 
108
88
  ## 数据与目录
109
89
 
110
- **全部数据都在你本机**:不连任何网络服务、不做遥测;名册、中文译文与小队的编译器都随包分发,运行时不向上游拉取。
90
+ **全部数据都在你本机**:不连任何网络服务、不做遥测;名册与中文译文都随包分发,运行时不向上游拉取。
111
91
 
112
92
  ```
113
93
  ~/.t-team/
114
94
  ├── experts/ 名册:<分类>/<slug>.md(包内快照 22 个分类、323 位;你自建的另计)
115
95
  ├── zh/ 中文侧车:names.json、descriptions.json、<分类>/<slug>.md
116
96
  ├── custom/ 你在面板里自建的专家
117
- ├── teams.json 小队定义(设置页「队伍」写回)
118
97
  ├── schedule.json 定时任务:任务、cron 表达式与最近 20 次执行记录
119
- ├── t-team.config.json 小队编译产物(引擎配置,人格已内联)
120
- ├── teams.resolved.json 小队编译产物(/t 列表用)
121
- ├── team-profiles.py 小队编译器的播种副本(实际跑的是包内那份)
122
98
  ├── source.json 名册清单(专家数 / 分类 / 更新时间)
123
99
  └── .t-team-snapshot.json 上次对齐的记录(版本 / 漂移计数)
124
100
  ```
125
101
 
126
- - 启动时**按条目**与包内快照对齐:包内新增的专家 / 小队 / 译文键补齐;只读条目(`experts/`、`source.json`、
127
- `team-profiles.py`、`zh/` 的覆盖表与分区表)与包内对齐;`names.json` / `descriptions.json` / `teams.json`
128
- **只补缺失的键**(你改过的键一个都不动);你改过的译文正文保留盘上那份;包内已移除的条目只报告、不删你的文件。
129
- - 一句话:**送得到的送到,送不到的一定出声**(日志给出数量与例子)。唯一始终用包内那份的是小队编译器
130
- (它是代码,随插件版本走)。想换目录位置,用配置项 `root` / `zhRoot` / `customRoot` 覆盖。
102
+ - 启动时**按条目**与包内快照对齐:包内新增的专家 / 译文键补齐;只读条目(`experts/`、`source.json`、
103
+ `zh/` 的覆盖表与分区表)与包内对齐;`names.json` / `descriptions.json` **只补缺失的键**
104
+ (你改过的键一个都不动);你改过的译文正文保留盘上那份;包内已移除的条目只报告、不删你的文件。
105
+ - 一句话:**送得到的送到,送不到的一定出声**(日志给出数量与例子)。
106
+ 想换目录位置,用配置项 `root` / `zhRoot` / `customRoot` 覆盖。
131
107
 
132
108
  ## 常见问题
133
109
 
134
110
  | 现象 | 原因与处理 |
135
111
  | --- | --- |
136
112
  | 召唤不了某位专家 | 它没被启用(设置 → T专家 → 专家);名册默认是"全部未启用" |
137
- | `/t` 不可用或提示引擎降级 | 宿主版本不在实测范围内(见「安装」的依赖一行)时团队引擎会降级:`/t` 会给出原因,名册与 `@` 召唤不受影响 |
138
- | 保存小队报错 | 缺 `python3`,或新定义没通过编译 —— **失败会自动回滚**,盘上仍是旧配置,设置页会说明引擎是否可用 |
139
113
  | 定时任务没有按时跑 | 设置 → T专家 → 「显示定时任务按钮」若被关掉,宿主会停掉**全部**定时触发(手动执行也会被拒),这是有意为之 |
140
114
  | 改完插件看不到变化 | 客户端与宿主代码都要重启 DSH 才生效;设置 → T专家 标题行有当前版本号(`v0.3.x`)可核对 |
141
- | 升级 DSH 后团队功能变得可疑(叫不醒成员、已退休成员又干活) | 宿主的 subagent 内部投递契约变了:日志里有一条 `[t-team] ... contract ...`,模型看到的提示段也会写明「宿主版本不在实测矩阵 / 形状与实测不符」。改 `lib/teams/harness-compat.js`:按新宿主核对 `HARNESS_ROUTES` 的形参个数,实测通过后把版本加进 `TESTED_HARNESS_VERSIONS` |
142
115
 
143
116
  ## 卸载与反馈
144
117
 
145
118
  - **卸载**:DSH Desktop 在插件市场里卸载;CLI 用 `dsh plugin --profile web remove dsh-plugin-t-expert`。
146
- 卸载不会删数据目录 `~/.t-team/`(名册、自建专家、小队、定时任务都在那儿),要清干净手动删它即可。
119
+ 卸载不会删数据目录 `~/.t-team/`(名册、自建专家、定时任务都在那儿),要清干净手动删它即可。
147
120
  - **反馈与源码**:<https://github.com/jiuaiwo/dsh-plugin-t-expert> —— 问题请走 Issues。
148
121
 
149
122
  ## 许可
150
123
 
151
124
  本插件以 **MIT** 发布(见 `LICENSE`)。
152
125
 
153
- 随包内容包含第三方成果 —— 内置团队引擎(派生自 `@nanmicoder/dsh-agent-teams`)、专家名册与中文译文
154
- (`msitarzewski/agency-agents`、`jnMetaCode/agency-agents-zh` 等)、以及运行时依赖 `croner` ——
155
- 它们各自保留原许可。完整来源、版本与署名见 `THIRD-PARTY-NOTICES`,完整许可文本随包放在 `vendor/`。
126
+ 随包内容包含第三方成果 —— 专家名册与中文译文(`msitarzewski/agency-agents`、
127
+ `jnMetaCode/agency-agents-zh` 等)、以及运行时依赖 `croner` —— 它们各自保留原许可。
128
+ 完整来源、版本与署名见 `THIRD-PARTY-NOTICES`,完整许可文本随包放在 `vendor/`。
156
129
 
157
130
  本插件及随包内容按**「原样」提供,不附带任何明示或默示担保**;与上述上游项目及 DeepSeek Harness
158
131
  官方无隶属或背书关系。再分发(含修改版)时请保留 `LICENSE`、`THIRD-PARTY-NOTICES` 与 `vendor/`
159
- 下的许可文本。
132
+ 下的许可文本。
@@ -1,34 +1,10 @@
1
1
  # 第三方组件与内容声明
2
2
 
3
- 本插件(`dsh-plugin-t-expert`,MIT,见 `LICENSE`)打包了两部分第三方成果。
4
- 它们各自保留原许可,本文件说明来源、版本与许可,以便再分发时履行署名义务。
5
- **完整许可文本随包分发**在 `vendor/` 下(见第 3 节)。
3
+ 本插件(`dsh-plugin-t-expert`,MIT,见 `LICENSE`)随包分发两类第三方成果:专家名册与中文侧车内容、
4
+ 以及一个运行期 npm 依赖。它们各自保留原许可,本文件说明来源、版本与许可,以便再分发时履行署名义务。
5
+ **完整许可文本随包分发**在 `vendor/third-party-licenses/` 下(见第 3 节)。
6
6
 
7
- ## 1. 内置团队引擎
8
-
9
- | 项 | 值 |
10
- | --- | --- |
11
- | 上游包 | `@nanmicoder/dsh-agent-teams` |
12
- | 上游仓库 | https://github.com/NanmiCoder/dsh-agent-teams |
13
- | 版本 | `0.1.17-rc.1` |
14
- | 许可 | MIT(完整文本随包:`vendor/dsh-agent-teams/LICENSE`)— Copyright (c) 2026 程序员阿江(Relakkes) |
15
- | 位置 | `lib/teams/`(一组由上述上游派生的品牌化产物文件,随版本增减:命令 `/agent-teams` → `/t`、工具 `agent_teams_*` → `t_team_*`)。它的客户端产物`vendor/dsh-agent-teams/client.bundle.txt` 被内联进 `lib/client.js`,并在内联时由 `build-client.mjs` 做下述本地化与清理 |
16
- | 许可全文 | `vendor/dsh-agent-teams/LICENSE` |
17
-
18
- **本插件对该上游做的改动**(都在 `lib/teams/` 与内联环节,可直接对照阅读):
19
- 一是品牌化改名(命令与工具名、包 id、事件与路由前缀);二是少量**本地缺陷修补与必要的行为改动**
20
- (例如把 profile 上限从 16 抬到 48、修正命令视图 key、修正交接期与终态任务的校验、
21
- 放行 `.env.example` 一类模板文件等)。三是**内联期后处理**:`build-client.mjs` 在把上游客户端文本
22
- 内联进 `lib/client.js` 时,(a) 把 `shell.overlay` 注册项的英文导航文案 `label: "T Team activity"`
23
- 改为经 locale 词典取 `activity.title`(该词条由上游自己的词典注册),(b) 剥掉上游产物里的
24
- `//#region` / `//#endregion` 区域标记与悬空的 `//# sourceMappingURL` 注释,(c) 把上游构建机的
25
- 绝对路径(`/home/runner/work/…`)压成包内相对路径。四是**宿主兼容适配层**(在 `vendor/dsh-agent-teams/client.bundle.txt` 内,涉及 `tTeamSessionsList` 与 `openAgentTeamMember`):宿主 `0.1.6-alpha.2` 起 (a) `sessions.list` 快照不再携带 `current`(当前会话已迁到 `uiSession` 的 scope 适配器)—— 上游活动面板以 `snapshot.current` 作为「当前会话」的唯一来源,字段缺失会让它既不轮询状态路由、也不渲染徽标与审批入口;(b) 打开 subagent 会话改由 `uiWorkspace.openSession(target)` 负责 —— `sessions` 上既无 `openSubagent` 也无 `open`,上游那两条路径都会抛 TypeError 并被 `.catch` 吞成一行 `console.warn`,表现为「点成员没有任何反应」。适配层在旧宿主上仍走原路径,在新宿主上分别从 `uiSession` 补齐 `current`、改走 `uiWorkspace.openSession`;前者按 `sessions.list` 记忆化,以满足 `useSyncExternalStore` 对引用稳定的要求。除这四项与品牌化外,上游逻辑未被改写。
26
-
27
- > 2026-09-12 起,上游的**逐字节原样镜像**(`vendor/dsh-agent-teams/upstream/`)与品牌化生成工具
28
- > (`brand.mjs`)已从仓库移除:`lib/teams/` 转为**手工维护的源码**,不再在构建时从上游重新生成。
29
- > 停止跟随上游不改变署名义务,故本节保留。
30
-
31
- ## 2. 专家名册与中文侧车
7
+ ## 1. 专家名册与中文侧车
32
8
 
33
9
  | 项 | 值 |
34
10
  | --- | --- |
@@ -65,7 +41,7 @@
65
41
  `data/zh/manual.json` 与 `data/zh/manual-bodies/` 是**本项目的补充翻译**(用于补齐尚未覆盖的条目
66
42
  或在译文不准确时覆盖),随本插件以 MIT 发布,同样保留在包内。
67
43
 
68
- ## 3. 定时任务调度器(运行时依赖)
44
+ ## 2. 定时任务调度器(运行时依赖)
69
45
 
70
46
  | 项 | 值 |
71
47
  | --- | --- |
@@ -81,13 +57,12 @@
81
57
  > 与 `@weibaohui/dsh-tasks` 的关系:两者都用 `croner`,但**各自声明依赖、各装各的**,
82
58
  > 数据文件、服务名与定时器互不共享(见 README 的「定时任务」一节)。
83
59
 
84
- ## 4. 分发要求
60
+ ## 3. 分发要求
85
61
 
86
62
  再分发本插件(或其修改版)时请一并保留以下文件(它们都在 npm 包内):
87
63
 
88
64
  - `LICENSE`(本插件)
89
65
  - `THIRD-PARTY-NOTICES`(本文件)
90
- - `vendor/dsh-agent-teams/LICENSE`(内置团队引擎)
91
66
  - `vendor/third-party-licenses/agency-agents.LICENSE`(英文名册)
92
67
  - `vendor/third-party-licenses/agency-agents-zh.LICENSE`(中文译文)
93
68
  - `vendor/third-party-licenses/croner.LICENSE`(定时任务调度器,运行时依赖)
@@ -17,10 +17,10 @@ You are **DeepSeek Harness Project Expert**, permanently assigned to one checkou
17
17
  - **Memory**: You remember every change that landed on the wrong plane, every registration that wasn't an effect and therefore leaked on reload, every model-visible input that couldn't be rebuilt from the session log, every `interface` mistaken for a Service Definition, every `catch` that swallowed a failure the repository's own rules say must be loud
18
18
  - **Experience**: You have watched a "small" tool addition turn into a lifecycle incident because it read a host registry through an entry-local realm; you have seen a preset rejected at mount time for publishing a service without an `isolate` realm. You know the repository's conventions are load-bearing and that the answer to "where does this go?" is decided before the first line is written.
19
19
 
20
- You carry two knowledge skills that ship with this plugin; load the relevant one **before** writing or reviewing code, not after:
20
+ Ground every claim in the checkout itself, and read the owning source **before** writing or reviewing code, not after:
21
21
 
22
- - **`dsh-harness-project`** — architecture, package map, profile/bundle/patch boot model, the three planes, the spine packages, event domains, capability seams, the extension-point table, the conventions that get rejected in review, the command list, the test tiers, and the documentation layering.
23
- - **`dsh-harness-languages`** — the per-language and per-toolchain rules of every face: TypeScript on Node, React/TSX on the client, Python 3.10+, the C Node-API addon, Cordis YAML composition, SQLite, shell, and the build/test tooling (pnpm, tsc, tsdown, vitest, tsx, oxlint, Electron, Vite).
22
+ - **`AGENTS.md`** (root and `packages/`) — repository conventions, the boot model, the three planes, the extension-point rules, the command list, the test tiers, and the documentation layering.
23
+ - **`docs/architecture.md` + `docs/subsystems/<subsystem>.md`** — the architecture, the package map, capability seams, and the per-subsystem type definitions; each `<package>/README.md` owns that package's contract and the per-language rules of its face.
24
24
 
25
25
  ## 🎯 Your Core Mission
26
26
 
@@ -195,7 +195,7 @@ Host, preset, or session — using the table above. If a preset needs to publish
195
195
  Walk the "new behavior goes where" table. If no documented point fits, say so explicitly and propose one — do not invent a convention this repository does not have, and do not reach into the loop as a shortcut.
196
196
 
197
197
  ### Step 4: Write it in the language rules of that face
198
- Load `dsh-harness-languages` and follow the section for the face you are editing: export shape and JSDoc for Host TypeScript, theme tokens and locale ownership for the client, boundary validation and explicit Harness home for Python, "consumers never compile native code" for the addon, `!!js` limits and `Config` validation for YAML, strict `user_version` for SQLite.
198
+ Follow the language rules of the face you are editing — the owning package's README and `docs/subsystems/` carry them: export shape and JSDoc for Host TypeScript, theme tokens and locale ownership for the client, boundary validation and explicit Harness home for Python, "consumers never compile native code" for the addon, `!!js` limits and `Config` validation for YAML, strict `user_version` for SQLite.
199
199
 
200
200
  ### Step 5: Verify with the smallest covering gate
201
201
  Behavior test for logic; `doc-sync` for documentation; the recorded-session snapshot for anything model/protocol/user visible; real-API e2e for a provider path; built smoke for the release path. "It works locally" is only meaningful when the local gate mirrors CI.
@@ -279,4 +279,4 @@ You are successful when:
279
279
 
280
280
  ---
281
281
 
282
- **Instructions Reference**: Load `dsh-harness-project` for architecture, boot model, extension points, conventions, commands, and gates; load `dsh-harness-languages` for the per-language rules of the face you are touching. When they are silent, read the owning package's README and `docs/subsystems/<subsystem>.md`, and when those are silent too, say the repository does not answer the question yet rather than inventing an answer.
282
+ **Instructions Reference**: Read `docs/architecture.md` for the boot model, extension points, and seams; `AGENTS.md` (root and `packages/`) for conventions, commands, and gates; the owning package's README plus `docs/subsystems/<subsystem>.md` for the per-language rules of the face you are touching. When those are silent too, say the repository does not answer the question yet rather than inventing an answer.
package/lib/bootstrap.js CHANGED
@@ -2,13 +2,13 @@
2
2
  /**
3
3
  * 启动期同步:把包内自带的名册快照落到可写数据目录,让插件对任何机器都自包含。
4
4
  *
5
- * 背景:T专家 的运行时数据(专家名册、中文侧车、小队定义、引擎配置)体积不大但必须先存在,
5
+ * 背景:T专家 的运行时数据(专家名册、中文侧车)体积不大但必须先存在,
6
6
  * 插件才可用。把它们随包发布后,安装即自带一份快照;这里负责在**每次启动**把包内快照与
7
7
  * 数据目录对齐,此后由用户自己的数据目录作主。
8
8
  *
9
9
  * ⚠️ 为什么不再是「首次播种、之后一律不动」(2026-09-13 修):
10
10
  * 旧实现按**整项**判断——目录非空就跳过、文件已存在就跳过——于是升级到新版本时,
11
- * 包内**新增**的专家/小队/译文、以及包内**修订**过的只读条目,对老安装**永不送达**,
11
+ * 包内**新增**的专家/译文、以及包内**修订**过的只读条目,对老安装**永不送达**,
12
12
  * 而且一句日志都没有(旧代码只在 `copied.length > 0` 时打印)。这是本项目最典型的一类
13
13
  * 恒存缺陷:「同一事实多份副本 + 只在缺失时播种」= 静默过期。
14
14
  *
@@ -16,18 +16,15 @@
16
16
  * 1. **缺失就补**:任何包内条目在数据目录里不存在就复制过去 —— 首次安装、半成品自愈、
17
17
  * 升级新增,走的是同一条路径。
18
18
  * 2. **只读条目一律对齐**(见 {@link PACKAGE_OWNED_DIRS}/{@link PACKAGE_OWNED_FILES}):
19
- * 名册 `experts/`、`source.json`、小队编译器 `team-profiles.py`、`zh/` 的覆盖表与分区表
19
+ * 名册 `experts/`、`source.json`、`zh/` 的覆盖表与分区表
20
20
  * 都是**随包发布的只读内容**(`lib/catalog.js` 里也写明 root 只读,自建专家走 customRoot),
21
21
  * 安装副本与包内不同就覆盖,并进 `updated` 报告。
22
22
  * 3. **键值型用户文件只补键、不改键**({@link MERGE_FILES}):`zh/names.json`、
23
- * `zh/descriptions.json`、`teams.json` 的缺失键从包内补齐 —— 上游新增的译文与新小队
23
+ * `zh/descriptions.json` 的缺失键从包内补齐 —— 上游新增的译文
24
24
  * 因此能到达老安装,而用户改过的键一个都不动。
25
25
  * 4. **用户内容绝不覆盖**:`zh/<分区>/<slug>.md` 正文等与包内不同时**保留盘上那份**,
26
26
  * 进 `kept` 报告(而不是像旧实现那样静默跳过)。
27
- * 5. **派生产物只补缺**({@link DERIVED_FILES}):`t-team.config.json` /
28
- * `teams.resolved.json` 由引擎按用户的 `teams.json` 编译,盘上那份天生与包内不同,
29
- * 因此只在缺失时播种,也不计入漂移。
30
- * 6. **只报告、不删除**:包内已移除的条目进 `stale`,盘上文件保留。
27
+ * 5. **只报告、不删除**:包内已移除的条目进 `stale`,盘上文件保留。
31
28
  * 7. **失败不致命**:只读文件系统、权限不足等导致同步失败时只报告,插件照常加载,
32
29
  * 后续会以「读不到名册」的正常错误路径报出来。
33
30
  *
@@ -48,16 +45,14 @@ export const MANIFEST_NAME = ".t-team-snapshot.json";
48
45
  /** 快照里的目录项:`experts` → root,`zh` → zhRoot。 */
49
46
  const SNAPSHOT_DIRS = ["experts", "zh"];
50
47
  /** 快照里的文件项:全部落在数据目录(= dirname(root))下。 */
51
- const SNAPSHOT_FILES = ["teams.json", "teams.resolved.json", "t-team.config.json", "team-profiles.py", "source.json"];
48
+ const SNAPSHOT_FILES = ["source.json"];
52
49
 
53
50
  /** 只读目录:随包发布、安装副本一律对齐(自建专家在 customRoot,不在这些目录里)。 */
54
51
  const PACKAGE_OWNED_DIRS = ["experts"];
55
52
  /** 只读文件:同上。`zh/` 下的两个表是生成物,不是用户译文。 */
56
- const PACKAGE_OWNED_FILES = ["source.json", "team-profiles.py", "zh/COVERAGE.json", "zh/divisions.json"];
57
- /** 键值型用户文件:只补缺失键,绝不改已有键(`teams.json` 的小队在 `profiles` 下)。 */
58
- const MERGE_FILES = ["zh/names.json", "zh/descriptions.json", "teams.json"];
59
- /** 派生产物:只在缺失时播种;盘上那份由引擎/编译器维护。 */
60
- const DERIVED_FILES = ["t-team.config.json", "teams.resolved.json"];
53
+ const PACKAGE_OWNED_FILES = ["source.json", "zh/COVERAGE.json", "zh/divisions.json"];
54
+ /** 键值型用户文件:只补缺失键,绝不改已有键。 */
55
+ const MERGE_FILES = ["zh/names.json", "zh/descriptions.json"];
61
56
  /** 遍历时跳过的垃圾与同步记录本身。 */
62
57
  const JUNK = new Set([".DS_Store", MANIFEST_NAME]);
63
58
 
@@ -136,7 +131,6 @@ function collectEntries(snapshotDir, root, zhRoot) {
136
131
  function classify(rel) {
137
132
  if (PACKAGE_OWNED_FILES.includes(rel)) return "package-owned";
138
133
  if (MERGE_FILES.includes(rel)) return "merge";
139
- if (DERIVED_FILES.includes(rel)) return "derived";
140
134
  for (const dir of PACKAGE_OWNED_DIRS) if (rel.startsWith(`${dir}/`)) return "package-owned";
141
135
  return "user";
142
136
  }
@@ -149,9 +143,8 @@ function isPlainObject(value) {
149
143
  /**
150
144
  * 把包内文件里**盘上还没有的键**补进去(已有键一个都不动)。
151
145
  *
152
- * 两处特例都是真实数据形状:`zh/names.json` / `zh/descriptions.json` 是扁平的
153
- * `slug → 文案`;`teams.json` 的小队表在 `profiles` 这一层。除 `profiles` 外不做嵌套合并 ——
154
- * 合并范围越宽,越容易覆盖用户内容。
146
+ * 两处都是真实数据形状:`zh/names.json` / `zh/descriptions.json` 是扁平的
147
+ * `slug → 文案`;不做嵌套合并 —— 合并范围越宽,越容易覆盖用户内容。
155
148
  * @param targetText - 盘上那份的文本。
156
149
  * @param sourceText - 包内那份的文本。
157
150
  * @returns 合并后的文本(无键可补时 `text` 为 undefined)与补齐的键名。
@@ -175,16 +168,6 @@ function mergeMissingKeys(targetText, sourceText) {
175
168
  target[key] = value;
176
169
  keys.push(key);
177
170
  }
178
- for (const nested of ["profiles"]) {
179
- const inner = source[nested];
180
- const existing = target[nested];
181
- if (!isPlainObject(inner) || !isPlainObject(existing)) continue;
182
- for (const [key, value] of Object.entries(inner)) {
183
- if (Object.prototype.hasOwnProperty.call(existing, key)) continue;
184
- existing[key] = value;
185
- keys.push(`${nested}.${key}`);
186
- }
187
- }
188
171
  if (keys.length === 0) return { text: undefined, keys };
189
172
  return { text: `${JSON.stringify(target, null, 2)}\n`, keys };
190
173
  }
@@ -311,11 +294,6 @@ export function seedData({ root, zhRoot, snapshotDir = SNAPSHOT_DIR }) {
311
294
  report.copied.push(rel);
312
295
  continue;
313
296
  }
314
- // 派生产物由引擎按用户的小队定义编译,与包内那份天生不同 —— 不是漂移,也不碰。
315
- if (kind === "derived") {
316
- report.unchanged += 1;
317
- continue;
318
- }
319
297
  if (sameContent(from, to)) {
320
298
  report.unchanged += 1;
321
299
  continue;
package/lib/catalog.js CHANGED
@@ -464,7 +464,7 @@ export const CUSTOM_LIMITS = { name: 60, nameEn: 80, description: 240, body: 400
464
464
  * 两处必须共用这一个判断:`discoverDivisions()` 发现什么、`loadCatalog()` 就扫什么。
465
465
  * 曾经列表用未过滤的结果、扫描用过滤过的结果,于是手建一个中文目录名后,
466
466
  * 面板上凭空多出一个零专家的分区(2026-09-12 实测)。非 ASCII 分区名一律不支持:
467
- * 分区 key 会进 `@` 源 id 与文件路径,ASCII 才和 slug、小队 key 的口径一致;
467
+ * 分区 key 会进 `@` 源 id 与文件路径,ASCII 才和 slug 的口径一致;
468
468
  * 中文显示名走 `customDivisions[].label`(落在 `<customRoot>/divisions.json`)。
469
469
  */
470
470
  export function isValidDivision(division) {