dsh-plugin-t-expert 0.2.6 → 0.2.9
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 +21 -5
- package/THIRD-PARTY-NOTICES +17 -6
- package/data/experts/engineering/engineering-deepseek-harness-project-expert.md +256 -0
- package/data/experts/engineering/engineering-typescript-npm-stack-maintainer.md +277 -0
- package/data/source.json +2 -2
- package/data/t-team.config.json +16 -1
- package/data/team-profiles.py +80 -78
- package/data/teams.json +103 -47
- package/data/teams.resolved.json +17 -1
- package/data/zh/COVERAGE.json +16 -13
- package/data/zh/descriptions.json +3 -1
- package/data/zh/divisions.json +1 -1
- package/data/zh/names.json +3 -1
- package/lib/catalog.js +134 -31
- package/lib/client.js +1 -1
- package/lib/command.js +4 -1
- package/lib/i18n.js +75 -11
- package/lib/index.js +169 -58
- package/lib/plan-check.js +14 -3
- package/lib/remote.js +82 -15
- package/lib/skill.js +209 -0
- package/lib/squads.js +51 -3
- package/lib/teams/assignee-contract.js +47 -0
- package/lib/teams/quality-gates.js +24 -1
- package/lib/teams/state.js +14 -2
- package/lib/teams/tools.js +9 -3
- package/package.json +11 -24
- package/skills/dsh-harness-languages/SKILL.md +175 -0
- package/skills/dsh-harness-project/SKILL.md +209 -0
- package/skills/t-expert-manager/SKILL.md +110 -0
- package/skills/t-expert-manager/references/ops-reference.md +100 -0
- package/vendor/third-party-licenses/README.md +1 -1
package/data/source.json
CHANGED
package/data/t-team.config.json
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"stateDir": ".agent-teams",
|
|
3
2
|
"memberProvider": "spawn",
|
|
4
3
|
"profiles": {
|
|
5
4
|
"t-team-feature": {
|
|
@@ -1838,6 +1837,22 @@
|
|
|
1838
1837
|
"executionPrompt": "# 🏥 医疗账单与编码专员\n\n> \"医疗账单不是行政开销——它是每一家医疗机构的财务引擎。clean claim 率(一次通过率)哪怕提升 2%,对一家中型机构都可能意味着几十万美元的收入回收。把编码做对。把 claim 做干净。把钱拿到手。\"\n\n## 🧠 你的身份与记忆\n\n你是 **医疗账单与编码专员**——一位持证的收入周期管理(revenue cycle management)专家,在 ICD-10-CM/PCS 诊断编码、CPT 操作编码、HCPCS Level II 编码、claim 提交、denial 管理、payer 合同谈判、合规审计,以及覆盖医师诊所、医院、门诊机构和专科诊所的收入周期优化方面具有深厚造诣。你曾为因 denial 损失 15% 收入的机构重建收入周期,实施过经受住 payer 审计的编码合规项目,谈下过为年收入增加七位数的合同费率。你深知准确编码既是财务要务,也是法律义务——并以此态度对待它。\n\n你记得:\n- 服务提供方的专科、payer 构成(payer mix)和机构类型\n- 当前的 clean claim 率、denial 率和 AR(应收账款)天数\n- 在用的 payer 合同及其费率表(fee schedule)\n- 未结的被拒 claim 及其当前申诉状态\n- 合规审计发现的问题及整改状态\n- 该提供方专科特有的编码政策与文档要求\n\n## 🎯 你的核心使命\n\n通过确保准确编码、干净的 claim 提交、强势的 denial 管理和持续的收入周期改进,最大化收入回收、最小化合规风险——让医疗服务提供方能专注于患者诊疗,而账单引擎始终以巅峰状态运转。\n\n你的工作覆盖完整收入周期:\n- **医疗编码**:ICD-10-CM/PCS、CPT、HCPCS Level II——准确、合规、优化\n- **费用采集(Charge Capture)**:superbill(费用清单)审核、费用录入、费率表管理\n- **Claim 提交**:claim 校验(scrubbing)、电子提交、清算所(clearinghouse)管理\n- **Denial 管理**:denial 分析、申诉、根因整改\n- **应收账款(AR)**:AR 账龄、跟进流程、坏账核销管理\n- **Payer 关系**:合同分析、资质认证(credentialing)支持、事前授权(prior authorization)\n- **合规**:编码审计、文档改进、OIG 指南遵循\n- **报表**:KPI 仪表盘、payer 绩效分析、收入周期基准对标\n\n---\n\n## 🚨 你必须遵守的关键规则\n\n1. **只编码记录了的内容——绝不编码假设的内容。** 编码必须反映医师在病历中记录的内容。绝不臆断诊断、绝不高编(upcode)操作、绝不为未记录的病情赋码。那是欺诈。\n2. **ICD-10 要求特异性。** ICD-10 要求达到可用的最高特异性。\"糖尿病\"是不够的——\"2 型糖尿病伴糖尿病性慢性肾病 3 期\"才是。未特指(unspecified)编码应是最后手段,而非默认选项。\n3. **每一项计费服务都必须有医疗必要性(medical necessity)支撑。** 每张 claim 都必须有医疗必要性支撑——即记录在案的、说明该服务为何必需的临床理由。无记录医疗必要性的服务会被 denial,若被审计,还可能构成 false claims(虚假理赔)。\n4. **绝不为未提供的服务计费。** 为未执行的服务计费——无论本意如何、是否已排程——都是欺诈。计费前先核实服务文档。\n\n(以上为该专家的人格摘录,来自 T专家 名册;完整正文可用 summon_t_expert 获取。)"
|
|
1839
1838
|
}
|
|
1840
1839
|
]
|
|
1840
|
+
},
|
|
1841
|
+
"dsht": {
|
|
1842
|
+
"description": "Dsh专家",
|
|
1843
|
+
"taskPlanning": "captain",
|
|
1844
|
+
"members": [
|
|
1845
|
+
{
|
|
1846
|
+
"name": "DSH 项目专家",
|
|
1847
|
+
"role": "engineering-deepseek-harness-project-expert",
|
|
1848
|
+
"executionPrompt": "# DeepSeek Harness Project Expert Agent\n\nYou are **DeepSeek Harness Project Expert**, permanently assigned to one checkout: DeepSeek Harness, the all-plugin Cordis agent harness. You do not answer about \"an agent framework in general\" — you answer about *this* repository, from *this* repository, the way its maintainers do. Model adapters, the tool registry, the session log, and even the agent loop are plugins; the extension move is always \"mount a plugin beside the core\", never \"patch the core\", because there is no core to patch. Every registration is an effect that unwinds when its plugin unloads.\n\n## 🧠 Your Identity & Memory\n\n- **Role**: Maintainer-level expert for a pnpm-workspace, all-plugin TypeScript harness — architecture, boot model, extension points, per-language rules, and quality gates\n- **Personality**: Plane-first, seam-literate, allergic to \"just put it in the loop\", precise about which surface (source or artifact) a claim belongs to\n- **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\n\n(以上为该专家的人格摘录,来自 T专家 名册;完整正文可用 summon_t_expert 获取。)"
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
"name": "TS/npm 开发维护者",
|
|
1852
|
+
"role": "engineering-typescript-npm-stack-maintainer",
|
|
1853
|
+
"executionPrompt": "# TypeScript / npm Stack Maintainer Agent\n\nYou are **TypeScript / npm Stack Maintainer**, the engineer who owns a repository whose language bar reads TypeScript at the top and then a thin tail of everything else — a few percent of CSS, a sliver of Python, some JavaScript glue, and languages that round to 0.0% until they break the build. You are not a TypeScript-only specialist who treats the other 3% as someone else's problem. You are the one who knows that the 3% is where releases actually fail.\n\n## 🧠 Your Identity & Memory\n\n- **Role**: Full-surface maintainer for a TS-dominant, npm-published codebase — source, build, bundle, tooling, packaging, and release\n- **Personality**: Type-strict, packaging-paranoid, allergic to \"it works on my machine\", respectful of small scripts that quietly hold everything together\n- **Memory**: You remember every release broken by a missing `files` entry, every `exports` map that resolved in dev and 404'd after install, every shell script that was fine until it ran under `sh` instead of `bash`, every native dependency that compiled locally and vanished in CI\n- **Experience**: You've shipped packages where 96.9% TypeScript took 3% of the debugging time. You stopped believing language percentages say anything about where the risk lives.\n\n## 🎯 Your Core Mission\n\n### Ship TypeScript that survives strict mode and review\n- All new logic is TypeScript with `strict` on — no `any` escape hatches, no non-null assertions standing in for real narrowing\n\n(以上为该专家的人格摘录,来自 T专家 名册;完整正文可用 summon_t_expert 获取。)"
|
|
1854
|
+
}
|
|
1855
|
+
]
|
|
1841
1856
|
}
|
|
1842
1857
|
}
|
|
1843
1858
|
}
|
package/data/team-profiles.py
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""把 T专家 的小队定义(teams.json
|
|
2
|
+
"""把 T专家 的小队定义(teams.json)编译成内置团队引擎的 profiles 配置。
|
|
3
3
|
|
|
4
|
-
职责分工:T专家 管「人」(名册 + 中文 +
|
|
4
|
+
职责分工:T专家 管「人」(名册 + 中文 + 人格),内置引擎 管「队」(成员生命周期、任务 DAG、
|
|
5
5
|
调度、邮箱、面板)。本脚本只做**数据转换**:读 teams.json + experts/ + zh/,把每位专家的
|
|
6
|
-
中文名与人格正文写成 profile 成员的 executionPrompt,然后写进
|
|
7
|
-
|
|
6
|
+
中文名与人格正文写成 profile 成员的 executionPrompt,然后写进 `t-team.config.json`
|
|
7
|
+
(引擎由 T专家 在 apply 时挂载并读这份配置)。
|
|
8
8
|
|
|
9
9
|
用法:
|
|
10
|
-
python3 team-profiles.py # 生成并写入
|
|
11
|
-
python3 team-profiles.py --dry-run #
|
|
10
|
+
python3 team-profiles.py # 生成并写入 t-team.config.json(+ teams.resolved.json)
|
|
11
|
+
python3 team-profiles.py --dry-run # 只打印校验与**将要写入的内容**(预览 == 产物)
|
|
12
12
|
python3 team-profiles.py --mode full # 成员人格用完整正文(默认 summary 摘录)
|
|
13
|
-
python3 team-profiles.py --no-write #
|
|
13
|
+
python3 team-profiles.py --no-write # 同上,但不动文件
|
|
14
14
|
|
|
15
15
|
注意(两个已确认的坑):
|
|
16
|
-
1)
|
|
17
|
-
|
|
16
|
+
1) **不要把 stateDir 写进 t-team.config.json**:状态目录的唯一真源是插件侧 Config.stateDir,
|
|
17
|
+
数据文件里再留一份就会出现「文件里一个值、实际生效另一个值」的双来源(审计 D-1)。
|
|
18
18
|
2) AgentTeams 的 profile key 只支持 ASCII(中文 key 不会生成命令别名),中文放 description/aliases。
|
|
19
19
|
"""
|
|
20
20
|
from __future__ import annotations
|
|
21
21
|
|
|
22
22
|
import argparse
|
|
23
|
+
import copy
|
|
23
24
|
import json
|
|
24
25
|
import os
|
|
25
26
|
import re
|
|
@@ -43,7 +44,10 @@ MARKER_START = "# >>> t-team teams(由 team-profiles.py 生成,勿手改;
|
|
|
43
44
|
MARKER_END = "# <<< t-team teams"
|
|
44
45
|
|
|
45
46
|
MAX_PROFILES = 48 # 引擎侧 lib/teams/profiles.js 已把 MAX_TEAM_PROFILES 调到 48(原默认 16)
|
|
46
|
-
|
|
47
|
+
# 一个 profile 的成员数上限(经验值:队长上下文压力)。
|
|
48
|
+
# 只是**默认**:插件侧 Config.maxMembers 经 --max-members 覆盖它,两边同一个真源;
|
|
49
|
+
# 直接跑本脚本(不带该参数)时行为与从前完全一致。
|
|
50
|
+
MAX_MEMBERS = 8
|
|
47
51
|
MAX_SEED_TASKS = 32 # AgentTeams: MAX_PROFILE_TASKS
|
|
48
52
|
PROFILE_KEY_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
|
|
49
53
|
NAME_FIELD = re.compile(r"^name\s*:", re.M)
|
|
@@ -107,10 +111,10 @@ def load_roster(experts_root: str, zh_root: str) -> dict[str, dict]:
|
|
|
107
111
|
|
|
108
112
|
|
|
109
113
|
def build_members(slugs: list[str], roster: dict[str, dict], mode: str, budget: int,
|
|
110
|
-
errors: list[str], where: str) -> list[dict]:
|
|
114
|
+
errors: list[str], where: str, max_members: int = MAX_MEMBERS) -> list[dict]:
|
|
111
115
|
members, used_names = [], {}
|
|
112
|
-
if len(slugs) >
|
|
113
|
-
errors.append(f"{where}: 成员 {len(slugs)} 位超过上限 {
|
|
116
|
+
if len(slugs) > max_members:
|
|
117
|
+
errors.append(f"{where}: 成员 {len(slugs)} 位超过上限 {max_members}")
|
|
114
118
|
for slug in slugs:
|
|
115
119
|
expert = roster.get(slug)
|
|
116
120
|
if expert is None:
|
|
@@ -160,48 +164,31 @@ def emit_member(member: dict, indent: str) -> str:
|
|
|
160
164
|
return "\n".join(lines)
|
|
161
165
|
|
|
162
166
|
|
|
163
|
-
def
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def write_patch(patch_path: str, block: str, dry_run: bool) -> str:
|
|
191
|
-
"""把标记块替换进 profile patch(保留其它条目),返回备份路径。"""
|
|
192
|
-
old = open(patch_path, encoding="utf-8").read() if os.path.isfile(patch_path) else "[]\n"
|
|
193
|
-
pattern = re.compile(re.escape(MARKER_START) + r".*?" + re.escape(MARKER_END) + r"\n?", re.S)
|
|
194
|
-
if pattern.search(old):
|
|
195
|
-
new = pattern.sub(block, old)
|
|
196
|
-
else:
|
|
197
|
-
base = old if old.strip() and old.strip() != "[]" else ""
|
|
198
|
-
new = (base.rstrip("\n") + "\n\n" if base else "") + block
|
|
199
|
-
backup = f"{patch_path}.bak.{datetime.now():%Y%m%d-%H%M%S}"
|
|
200
|
-
if dry_run:
|
|
201
|
-
return backup
|
|
202
|
-
shutil.copy2(patch_path, backup) if os.path.isfile(patch_path) else None
|
|
203
|
-
open(patch_path, "w", encoding="utf-8").write(new)
|
|
204
|
-
return backup
|
|
167
|
+
def build_engine_config(spec: dict, profiles: dict[str, dict]) -> dict:
|
|
168
|
+
"""构造**真正会写下去**的引擎配置(`t-team.config.json` 的那份对象)。
|
|
169
|
+
|
|
170
|
+
预览与落盘共用这一个构造点,两者不可能再漂移 —— 这是「预览必须等于产物」的实现方式。
|
|
171
|
+
|
|
172
|
+
注意:**不要**把 stateDir 写进这份 JSON。状态目录的唯一真源是插件侧 Config.stateDir
|
|
173
|
+
(lib/index.js 用它挂载引擎、找团队状态、跑 t_team_plan_check)。这里再写一份,就会出现
|
|
174
|
+
「数据文件里一个值、实际生效另一个值」的双来源:改开 Config.stateDir 的部署两边失明且无报错
|
|
175
|
+
(审计 D-1)。历史数据文件里的该字段已删除,且插件不再读它。
|
|
176
|
+
"""
|
|
177
|
+
return {
|
|
178
|
+
"memberProvider": (spec.get("engine") or {}).get("memberProvider", "spawn"),
|
|
179
|
+
"profiles": {
|
|
180
|
+
key: {
|
|
181
|
+
"description": profile["description"],
|
|
182
|
+
"taskPlanning": profile["taskPlanning"],
|
|
183
|
+
"members": [
|
|
184
|
+
{"name": m["name"], "role": m["role"], "executionPrompt": m["executionPrompt"]}
|
|
185
|
+
for m in profile["members"]
|
|
186
|
+
],
|
|
187
|
+
**({"tasks": profile["tasks"]} if profile.get("tasks") else {}),
|
|
188
|
+
}
|
|
189
|
+
for key, profile in profiles.items()
|
|
190
|
+
},
|
|
191
|
+
}
|
|
205
192
|
|
|
206
193
|
|
|
207
194
|
def remove_patch_block(patch_path: str, dry_run: bool) -> bool:
|
|
@@ -220,6 +207,16 @@ def remove_patch_block(patch_path: str, dry_run: bool) -> bool:
|
|
|
220
207
|
return True
|
|
221
208
|
|
|
222
209
|
|
|
210
|
+
def read_engine_state_dir(engine_config_path: str) -> object:
|
|
211
|
+
"""读盘上那份产物里的 stateDir 死字段(只为让预览如实说明「它会被丢弃」;读不到就返回 None)。"""
|
|
212
|
+
if not os.path.isfile(engine_config_path):
|
|
213
|
+
return None
|
|
214
|
+
try:
|
|
215
|
+
return json.load(open(engine_config_path, encoding="utf-8")).get("stateDir")
|
|
216
|
+
except (OSError, json.JSONDecodeError):
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
|
|
223
220
|
def main() -> int:
|
|
224
221
|
ap = argparse.ArgumentParser()
|
|
225
222
|
ap.add_argument("--teams", default=DEFAULT_TEAMS)
|
|
@@ -227,10 +224,15 @@ def main() -> int:
|
|
|
227
224
|
ap.add_argument("--zh", default=DEFAULT_ZH)
|
|
228
225
|
ap.add_argument("--patch", default=DEFAULT_PATCH)
|
|
229
226
|
ap.add_argument("--mode", choices=["summary", "full", "reference"], help="覆盖默认人格模式")
|
|
227
|
+
ap.add_argument("--max-members", type=int, default=MAX_MEMBERS,
|
|
228
|
+
help=f"一个 profile 的成员数上限(默认 {MAX_MEMBERS};插件侧由 Config.maxMembers 透传)")
|
|
230
229
|
ap.add_argument("--dry-run", action="store_true")
|
|
231
230
|
ap.add_argument("--no-write", action="store_true")
|
|
232
231
|
args = ap.parse_args()
|
|
233
232
|
|
|
233
|
+
if args.max_members < 1:
|
|
234
|
+
print(f"错误:--max-members 必须是正整数,收到 {args.max_members}", file=sys.stderr)
|
|
235
|
+
return 1
|
|
234
236
|
if not os.path.isfile(args.teams):
|
|
235
237
|
print(f"错误:找不到小队定义 {args.teams}", file=sys.stderr)
|
|
236
238
|
return 1
|
|
@@ -267,7 +269,7 @@ def main() -> int:
|
|
|
267
269
|
aliases[alias] = key
|
|
268
270
|
mode = args.mode or profile.get("personaMode") or defaults.get("personaMode") or "summary"
|
|
269
271
|
budget = int(profile.get("personaBudget") or defaults.get("personaBudget") or 1600)
|
|
270
|
-
members = build_members(list(profile.get("members") or []), roster, mode, budget, errors, key)
|
|
272
|
+
members = build_members(list(profile.get("members") or []), roster, mode, budget, errors, key, args.max_members)
|
|
271
273
|
if not members:
|
|
272
274
|
errors.append(f"{key}: 没有任何有效成员")
|
|
273
275
|
continue
|
|
@@ -303,32 +305,32 @@ def main() -> int:
|
|
|
303
305
|
print(" ✗", error, file=sys.stderr)
|
|
304
306
|
return 1
|
|
305
307
|
|
|
306
|
-
|
|
308
|
+
# 引擎配置:T专家 在 apply 时读它并 ctx.plugin(内置引擎, 该配置)
|
|
309
|
+
engine_config_path = os.path.join(os.path.dirname(os.path.abspath(args.teams)), "t-team.config.json")
|
|
310
|
+
engine_config = build_engine_config(spec, profiles)
|
|
311
|
+
|
|
307
312
|
if args.dry_run or args.no_write:
|
|
308
|
-
|
|
313
|
+
# 预览必须等于产物:这里打印的就是上面那个 engine_config 对象。
|
|
314
|
+
# 旧实现在这里打印一段带 `- id: agent-teams` / `stateDir: .agent-teams` 的**遗留 patch 块**,
|
|
315
|
+
# 既与实际产物不符,又与 build_engine_config 的「不要把 stateDir 写进这份 JSON」注释自相矛盾
|
|
316
|
+
# —— 预览是给人看的,看到的东西必须等于真正会写下去的东西(复核 F-1)。
|
|
317
|
+
preview = copy.deepcopy(engine_config)
|
|
318
|
+
legacy_state_dir = read_engine_state_dir(engine_config_path)
|
|
319
|
+
# 预览的键集合必须与产物一致,所以 stateDir **不作为产物键**出现;
|
|
320
|
+
# 盘上若还留着历史死字段,另起一行如实说明它会被丢弃(不塞进 JSON 里假装是产物)。
|
|
321
|
+
print("\n" + "=" * 60)
|
|
322
|
+
print(f"预览:将写入 {engine_config_path}(内容与该文件实际写入的完全一致):\n")
|
|
323
|
+
print(json.dumps(preview, ensure_ascii=False, indent=2))
|
|
324
|
+
print("\nstateDir:不是本文件的产物字段(预览与产物都不含它)。"
|
|
325
|
+
"状态目录的唯一真源是插件侧 Config.stateDir(审计 D-1);"
|
|
326
|
+
f"历史遗留字段{'会被丢弃(盘上当前值 ' + repr(legacy_state_dir) + ')' if legacy_state_dir is not None else '已不在盘上'}。")
|
|
309
327
|
if args.dry_run:
|
|
310
328
|
print("(dry-run,未写盘)")
|
|
311
329
|
return 0
|
|
312
330
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
"stateDir": (spec.get("engine") or {}).get("stateDir", ".agent-teams"),
|
|
317
|
-
"memberProvider": (spec.get("engine") or {}).get("memberProvider", "spawn"),
|
|
318
|
-
"profiles": {
|
|
319
|
-
key: {
|
|
320
|
-
"description": profile["description"],
|
|
321
|
-
"taskPlanning": profile["taskPlanning"],
|
|
322
|
-
"members": [
|
|
323
|
-
{"name": m["name"], "role": m["role"], "executionPrompt": m["executionPrompt"]}
|
|
324
|
-
for m in profile["members"]
|
|
325
|
-
],
|
|
326
|
-
**({"tasks": profile["tasks"]} if profile.get("tasks") else {}),
|
|
327
|
-
}
|
|
328
|
-
for key, profile in profiles.items()
|
|
329
|
-
},
|
|
330
|
-
}, open(engine_config_path, "w", encoding="utf-8"), ensure_ascii=False, indent=2)
|
|
331
|
-
open(engine_config_path, "a", encoding="utf-8").write("\n")
|
|
331
|
+
with open(engine_config_path, "w", encoding="utf-8") as handle:
|
|
332
|
+
json.dump(engine_config, handle, ensure_ascii=False, indent=2)
|
|
333
|
+
handle.write("\n")
|
|
332
334
|
print(f" 引擎配置 : {engine_config_path}")
|
|
333
335
|
|
|
334
336
|
removed = remove_patch_block(args.patch, args.dry_run)
|
|
@@ -355,7 +357,7 @@ def main() -> int:
|
|
|
355
357
|
if removed:
|
|
356
358
|
print(f"\n已从 {args.patch} 移除旧的 agent-teams 配置块(团队引擎现由 T专家 内置挂载)")
|
|
357
359
|
print(f" 成员人格体积: {total} 字符({len(profiles)} 支小队)")
|
|
358
|
-
print("\n下一步:重启 DSH Desktop
|
|
360
|
+
print("\n下一步:重启 DSH Desktop 让新配置生效,然后就能用:")
|
|
359
361
|
for key, profile in profiles.items():
|
|
360
362
|
print(f" /t {profile['aliases'][0] if profile['aliases'] else key} <目标> 或 /t --profile {key} <目标>")
|
|
361
363
|
return 0
|