dominds 0.9.0 → 0.9.2
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/dist/docs/mcp-support.md +9 -0
- package/dist/docs/mcp-support.zh.md +9 -0
- package/dist/docs/team_mgmt-toolset.md +16 -0
- package/dist/docs/team_mgmt-toolset.zh.md +13 -0
- package/dist/llm/driver-v2/core.js +17 -0
- package/dist/static/assets/{_baseUniq-CoUduYbj.js → _baseUniq-yVhEFITr.js} +2 -2
- package/dist/static/assets/{_baseUniq-CoUduYbj.js.map → _baseUniq-yVhEFITr.js.map} +1 -1
- package/dist/static/assets/{arc-B79evgv8.js → arc-Buo-Z5vX.js} +2 -2
- package/dist/static/assets/{arc-B79evgv8.js.map → arc-Buo-Z5vX.js.map} +1 -1
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-rLlQb9R_.js → architectureDiagram-VXUJARFQ-CFzWyC5l.js} +6 -6
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-rLlQb9R_.js.map → architectureDiagram-VXUJARFQ-CFzWyC5l.js.map} +1 -1
- package/dist/static/assets/{blockDiagram-VD42YOAC-DKsP6RFH.js → blockDiagram-VD42YOAC-DZr3jTjY.js} +7 -7
- package/dist/static/assets/{blockDiagram-VD42YOAC-DKsP6RFH.js.map → blockDiagram-VD42YOAC-DZr3jTjY.js.map} +1 -1
- package/dist/static/assets/{c4Diagram-YG6GDRKO-BrSPmLIb.js → c4Diagram-YG6GDRKO-B0fMMEbY.js} +3 -3
- package/dist/static/assets/{c4Diagram-YG6GDRKO-BrSPmLIb.js.map → c4Diagram-YG6GDRKO-B0fMMEbY.js.map} +1 -1
- package/dist/static/assets/{channel-CQ18oNtY.js → channel-Dx_4w8Od.js} +2 -2
- package/dist/static/assets/{channel-CQ18oNtY.js.map → channel-Dx_4w8Od.js.map} +1 -1
- package/dist/static/assets/{chunk-4BX2VUAB-D8e6GJKc.js → chunk-4BX2VUAB-D6Vsm_4V.js} +2 -2
- package/dist/static/assets/{chunk-4BX2VUAB-D8e6GJKc.js.map → chunk-4BX2VUAB-D6Vsm_4V.js.map} +1 -1
- package/dist/static/assets/{chunk-55IACEB6-0_nYvlGV.js → chunk-55IACEB6-DyjobdoE.js} +2 -2
- package/dist/static/assets/{chunk-55IACEB6-0_nYvlGV.js.map → chunk-55IACEB6-DyjobdoE.js.map} +1 -1
- package/dist/static/assets/{chunk-B4BG7PRW-c3Osrj3P.js → chunk-B4BG7PRW-CiTT1gze.js} +5 -5
- package/dist/static/assets/{chunk-B4BG7PRW-c3Osrj3P.js.map → chunk-B4BG7PRW-CiTT1gze.js.map} +1 -1
- package/dist/static/assets/{chunk-DI55MBZ5-B3wy4mTI.js → chunk-DI55MBZ5-DmS3Qu9w.js} +4 -4
- package/dist/static/assets/{chunk-DI55MBZ5-B3wy4mTI.js.map → chunk-DI55MBZ5-DmS3Qu9w.js.map} +1 -1
- package/dist/static/assets/{chunk-FMBD7UC4-DrcK9WUz.js → chunk-FMBD7UC4-k4uK2G8t.js} +2 -2
- package/dist/static/assets/{chunk-FMBD7UC4-DrcK9WUz.js.map → chunk-FMBD7UC4-k4uK2G8t.js.map} +1 -1
- package/dist/static/assets/{chunk-QN33PNHL-fn6UG5b8.js → chunk-QN33PNHL-Ds40b6qm.js} +2 -2
- package/dist/static/assets/{chunk-QN33PNHL-fn6UG5b8.js.map → chunk-QN33PNHL-Ds40b6qm.js.map} +1 -1
- package/dist/static/assets/{chunk-QZHKN3VN-lwz9tfKX.js → chunk-QZHKN3VN-B2Bw3EH7.js} +2 -2
- package/dist/static/assets/{chunk-QZHKN3VN-lwz9tfKX.js.map → chunk-QZHKN3VN-B2Bw3EH7.js.map} +1 -1
- package/dist/static/assets/{chunk-TZMSLE5B-aXbZylkp.js → chunk-TZMSLE5B-CehctPfm.js} +2 -2
- package/dist/static/assets/{chunk-TZMSLE5B-aXbZylkp.js.map → chunk-TZMSLE5B-CehctPfm.js.map} +1 -1
- package/dist/static/assets/{classDiagram-2ON5EDUG-ByC6PvUi.js → classDiagram-2ON5EDUG-BqXw6Omx.js} +6 -6
- package/dist/static/assets/{classDiagram-2ON5EDUG-ByC6PvUi.js.map → classDiagram-2ON5EDUG-BqXw6Omx.js.map} +1 -1
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-ByC6PvUi.js → classDiagram-v2-WZHVMYZB-BqXw6Omx.js} +6 -6
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-ByC6PvUi.js.map → classDiagram-v2-WZHVMYZB-BqXw6Omx.js.map} +1 -1
- package/dist/static/assets/{clone-BDJhQHyk.js → clone-oYVOR_4R.js} +2 -2
- package/dist/static/assets/{clone-BDJhQHyk.js.map → clone-oYVOR_4R.js.map} +1 -1
- package/dist/static/assets/{cose-bilkent-S5V4N54A-HAsn54-S.js → cose-bilkent-S5V4N54A-Bqq83f0f.js} +2 -2
- package/dist/static/assets/{cose-bilkent-S5V4N54A-HAsn54-S.js.map → cose-bilkent-S5V4N54A-Bqq83f0f.js.map} +1 -1
- package/dist/static/assets/{dagre-6UL2VRFP-DgBnUfQ7.js → dagre-6UL2VRFP-BkOS4vBF.js} +7 -7
- package/dist/static/assets/{dagre-6UL2VRFP-DgBnUfQ7.js.map → dagre-6UL2VRFP-BkOS4vBF.js.map} +1 -1
- package/dist/static/assets/{diagram-PSM6KHXK-B0Oej_SM.js → diagram-PSM6KHXK-C_7bZw50.js} +7 -7
- package/dist/static/assets/{diagram-PSM6KHXK-B0Oej_SM.js.map → diagram-PSM6KHXK-C_7bZw50.js.map} +1 -1
- package/dist/static/assets/{diagram-QEK2KX5R-B-P9Chdj.js → diagram-QEK2KX5R-35Xrtz1F.js} +6 -6
- package/dist/static/assets/{diagram-QEK2KX5R-B-P9Chdj.js.map → diagram-QEK2KX5R-35Xrtz1F.js.map} +1 -1
- package/dist/static/assets/{diagram-S2PKOQOG-BrnNRpnf.js → diagram-S2PKOQOG-DXggXCVc.js} +6 -6
- package/dist/static/assets/{diagram-S2PKOQOG-BrnNRpnf.js.map → diagram-S2PKOQOG-DXggXCVc.js.map} +1 -1
- package/dist/static/assets/{erDiagram-Q2GNP2WA-CjhZUP-_.js → erDiagram-Q2GNP2WA-DN23msL7.js} +5 -5
- package/dist/static/assets/{erDiagram-Q2GNP2WA-CjhZUP-_.js.map → erDiagram-Q2GNP2WA-DN23msL7.js.map} +1 -1
- package/dist/static/assets/{flowDiagram-NV44I4VS-DW5irfHa.js → flowDiagram-NV44I4VS-DdCZ32fT.js} +6 -6
- package/dist/static/assets/{flowDiagram-NV44I4VS-DW5irfHa.js.map → flowDiagram-NV44I4VS-DdCZ32fT.js.map} +1 -1
- package/dist/static/assets/{ganttDiagram-JELNMOA3-CkFnAxLO.js → ganttDiagram-JELNMOA3-i4C2Jb9s.js} +3 -3
- package/dist/static/assets/{ganttDiagram-JELNMOA3-CkFnAxLO.js.map → ganttDiagram-JELNMOA3-i4C2Jb9s.js.map} +1 -1
- package/dist/static/assets/{gitGraphDiagram-NY62KEGX-CW5UQfhl.js → gitGraphDiagram-NY62KEGX-B-pz2yGv.js} +7 -7
- package/dist/static/assets/{gitGraphDiagram-NY62KEGX-CW5UQfhl.js.map → gitGraphDiagram-NY62KEGX-B-pz2yGv.js.map} +1 -1
- package/dist/static/assets/{graph-QsUQvOUG.js → graph-Dt0ICYC4.js} +3 -3
- package/dist/static/assets/{graph-QsUQvOUG.js.map → graph-Dt0ICYC4.js.map} +1 -1
- package/dist/static/assets/{index-BWgwzFdG.js → index-CFSjKmjb.js} +31 -34
- package/dist/static/assets/index-CFSjKmjb.js.map +1 -0
- package/dist/static/assets/{infoDiagram-WHAUD3N6-1hutUswv.js → infoDiagram-WHAUD3N6-B83tboBX.js} +5 -5
- package/dist/static/assets/{infoDiagram-WHAUD3N6-1hutUswv.js.map → infoDiagram-WHAUD3N6-B83tboBX.js.map} +1 -1
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-CYEB2gYA.js → journeyDiagram-XKPGCS4Q-ByUNASkI.js} +5 -5
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-CYEB2gYA.js.map → journeyDiagram-XKPGCS4Q-ByUNASkI.js.map} +1 -1
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-B_rokrwL.js → kanban-definition-3W4ZIXB7-DoV-Fpix.js} +3 -3
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-B_rokrwL.js.map → kanban-definition-3W4ZIXB7-DoV-Fpix.js.map} +1 -1
- package/dist/static/assets/{layout-DD4e7kuc.js → layout-W5BPV8_t.js} +5 -5
- package/dist/static/assets/{layout-DD4e7kuc.js.map → layout-W5BPV8_t.js.map} +1 -1
- package/dist/static/assets/{linear-CpmZo_ZS.js → linear-CHvuvVAs.js} +2 -2
- package/dist/static/assets/{linear-CpmZo_ZS.js.map → linear-CHvuvVAs.js.map} +1 -1
- package/dist/static/assets/{min-CFkzEekk.js → min-B310j0Qx.js} +3 -3
- package/dist/static/assets/{min-CFkzEekk.js.map → min-B310j0Qx.js.map} +1 -1
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-WLy2VPYm.js → mindmap-definition-VGOIOE7T-BqOBARwH.js} +4 -4
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-WLy2VPYm.js.map → mindmap-definition-VGOIOE7T-BqOBARwH.js.map} +1 -1
- package/dist/static/assets/{pieDiagram-ADFJNKIX-2nx2cHS8.js → pieDiagram-ADFJNKIX-24-wPJjd.js} +7 -7
- package/dist/static/assets/{pieDiagram-ADFJNKIX-2nx2cHS8.js.map → pieDiagram-ADFJNKIX-24-wPJjd.js.map} +1 -1
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-ELd4blG4.js → quadrantDiagram-AYHSOK5B-C7Wx-AmK.js} +3 -3
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-ELd4blG4.js.map → quadrantDiagram-AYHSOK5B-C7Wx-AmK.js.map} +1 -1
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-BEleMcvW.js → requirementDiagram-UZGBJVZJ-BW0tZfAm.js} +4 -4
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-BEleMcvW.js.map → requirementDiagram-UZGBJVZJ-BW0tZfAm.js.map} +1 -1
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-_xcwg8aT.js → sankeyDiagram-TZEHDZUN-DZl5Dn6u.js} +2 -2
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-_xcwg8aT.js.map → sankeyDiagram-TZEHDZUN-DZl5Dn6u.js.map} +1 -1
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-B5W6BMbd.js → sequenceDiagram-WL72ISMW-BQdfWJzw.js} +4 -4
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-B5W6BMbd.js.map → sequenceDiagram-WL72ISMW-BQdfWJzw.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-BtAHVsVQ.js → stateDiagram-FKZM4ZOC-CcSySFVm.js} +9 -9
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-BtAHVsVQ.js.map → stateDiagram-FKZM4ZOC-CcSySFVm.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-DzGcYKQT.js → stateDiagram-v2-4FDKWEC3-DCrGc6-D.js} +5 -5
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-DzGcYKQT.js.map → stateDiagram-v2-4FDKWEC3-DCrGc6-D.js.map} +1 -1
- package/dist/static/assets/{timeline-definition-IT6M3QCI-UdhLD6FT.js → timeline-definition-IT6M3QCI-Ltw_zbSJ.js} +3 -3
- package/dist/static/assets/{timeline-definition-IT6M3QCI-UdhLD6FT.js.map → timeline-definition-IT6M3QCI-Ltw_zbSJ.js.map} +1 -1
- package/dist/static/assets/{treemap-KMMF4GRG-C9kUtGO2.js → treemap-KMMF4GRG-BFyGamhb.js} +4 -4
- package/dist/static/assets/{treemap-KMMF4GRG-C9kUtGO2.js.map → treemap-KMMF4GRG-BFyGamhb.js.map} +1 -1
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-BZCzGwDm.js → xychartDiagram-PRI3JC2R-DJFdQWtf.js} +3 -3
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-BZCzGwDm.js.map → xychartDiagram-PRI3JC2R-DJFdQWtf.js.map} +1 -1
- package/dist/static/index.html +1 -1
- package/dist/tools/prompts/team_mgmt/en/tools.md +4 -0
- package/dist/tools/prompts/team_mgmt/zh/tools.md +4 -0
- package/dist/tools/team_mgmt.js +413 -14
- package/package.json +1 -1
- package/dist/static/assets/index-BWgwzFdG.js.map +0 -1
package/dist/static/index.html
CHANGED
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
padding: 20px;
|
|
53
53
|
}
|
|
54
54
|
</style>
|
|
55
|
-
<script type="module" crossorigin src="/assets/index-
|
|
55
|
+
<script type="module" crossorigin src="/assets/index-CFSjKmjb.js"></script>
|
|
56
56
|
<link rel="stylesheet" crossorigin href="/assets/index-Be077roh.css">
|
|
57
57
|
</head>
|
|
58
58
|
<body>
|
|
@@ -74,6 +74,10 @@
|
|
|
74
74
|
- `codex_style_tools`: Codex-style tools (`apply_patch` / `readonly_shell` / `update_plan`); **do not configure this toolset on Windows**
|
|
75
75
|
- `mcp_admin`: MCP operations (`mcp_restart` / `mcp_release`), plus env tools (`env_get` / `env_set` / `env_unset`)
|
|
76
76
|
- MCP-declared toolsets: dynamically mapped from `.minds/mcp.yaml` `servers.<serverId>` (toolset name = `serverId`). Exact capabilities depend on each MCP server’s exposed tools; use `team_mgmt_manual({ topics: ["toolsets"] })` to view the current mapping snapshot
|
|
77
|
+
- Optional per-toolset manual can be placed at `servers.<serverId>.manual` using `content` (overview) and `sections` (chapters)
|
|
78
|
+
- Missing manual does **not** mean the toolset is unavailable; runtime manual will auto-generate a baseline draft (at least a tools-list section) for temporary use
|
|
79
|
+
- Auto-generated draft is only a scaffold: team manager must confirm intent/boundaries with the human user, then replace it with accurate manual content
|
|
80
|
+
- Team managers should, after MCP validation passes, carefully read each exposed tool description, align with the human user on intended rtws usage, then write `servers.<serverId>.manual` with typical usage patterns and primary intent directions
|
|
77
81
|
|
|
78
82
|
## ripgrep Dependency (Detection & Install)
|
|
79
83
|
|
|
@@ -74,6 +74,10 @@
|
|
|
74
74
|
- `codex_style_tools`:Codex 风格工具(`apply_patch` / `readonly_shell` / `update_plan`);**Windows 环境下不要配置该 toolset**
|
|
75
75
|
- `mcp_admin`:MCP 运维(`mcp_restart` / `mcp_release`),并包含环境变量工具(`env_get` / `env_set` / `env_unset`)
|
|
76
76
|
- MCP 声明型 toolset:来源于 `.minds/mcp.yaml` 的 `servers.<serverId>` 动态映射(toolset 名称 = `serverId`)。具体能力以该 MCP server 实际暴露工具为准;可在 `team_mgmt_manual({ topics: ["toolsets"] })` 查看当前映射快照
|
|
77
|
+
- 可选:在 `servers.<serverId>.manual` 放手册内容,支持 `content`(总说明)+ `sections`(章节)
|
|
78
|
+
- 注意:没有手册 **不代表** toolset 不可用;运行时手册会自动生成基础草稿(至少包含 tools 列表章节)供临时使用
|
|
79
|
+
- 自动草稿只是脚手架:团队管理者必须与人类用户确认意图与边界后,再改写成准确手册
|
|
80
|
+
- 团队管理者应在 MCP 配置验证通过后:先精读该 server 各工具说明,再与人类用户讨论本 rtws 的使用意图,最后把典型用法与主要意图方向写入 `servers.<serverId>.manual`
|
|
77
81
|
|
|
78
82
|
## ripgrep 依赖(检测与安装)
|
|
79
83
|
|
package/dist/tools/team_mgmt.js
CHANGED
|
@@ -2858,6 +2858,7 @@ async function renderMcpManual(language) {
|
|
|
2858
2858
|
const mcpSnapshot = await readMcpToolsetMappingSnapshot();
|
|
2859
2859
|
const mcpMapping = renderMcpToolsetMappingSection(language, mcpSnapshot);
|
|
2860
2860
|
const mcpSetup = renderMcpToolsetSetupGuideSection(language, mcpSnapshot);
|
|
2861
|
+
const mcpManualDetails = renderMcpToolsetManualDetailsSection(language, mcpSnapshot);
|
|
2861
2862
|
if (language === 'zh') {
|
|
2862
2863
|
return (fmtHeader('.minds/mcp.yaml') +
|
|
2863
2864
|
fmtList([
|
|
@@ -2868,6 +2869,9 @@ async function renderMcpManual(language) {
|
|
|
2868
2869
|
'用 `tools.whitelist/blacklist` 控制暴露的工具,用 `transform` 做命名变换。',
|
|
2869
2870
|
'常见坑:stdio transport 需要可执行命令路径正确,且受成员权限(目录 + 扩展名:`*_dirs/no_*_dirs/*_file_ext_names/no_*_file_ext_names`)约束;HTTP transport 需要服务可达(url/端口/网络)。',
|
|
2870
2871
|
'高频坑(stdio 路径):若未设置 `cwd`,相对路径按 Dominds 进程工作目录(通常 rtws 根目录)解析;建议显式配置 `cwd` 或直接使用绝对路径。`cwd` 必须存在且是目录。',
|
|
2872
|
+
'可选手册字段:你可以在 `servers.<serverId>.manual` 放手册内容。支持 `content`(总说明)+ `sections`(章节列表),用于告诉智能体该 toolset 该怎么用。',
|
|
2873
|
+
'重要:`manual` 缺失并不代表 MCP toolset 不可用;这只是团队管理工作不足。智能体应继续依据每个工具 description/参数自行判断并使用。',
|
|
2874
|
+
'团队管理者建议:配置并验证 MCP 后,应先精读该 server 暴露的每个工具 description/参数,再与人类用户讨论本 rtws 中这些工具的使用意图,最后把“典型用法 + 主要意图方向”沉淀到 `servers.<serverId>.manual`(`content + sections`)。',
|
|
2871
2875
|
'最小诊断流程(建议顺序):1) 先用 `team_mgmt_check_provider({ provider_key: \"<providerKey>\", model: \"\", all_models: false, live: false, max_models: 0 })` 确认 LLM provider 可用;2) 再检查该成员的目录权限(`team_mgmt_manual({ topics: [\"permissions\"] })`);3) 运行 `team_mgmt_validate_mcp_cfg({})` 汇总 `.minds/mcp.yaml` 与 MCP 问题;4) 必要时 `mcp_restart`,用完记得 `mcp_release`。',
|
|
2872
2876
|
]) +
|
|
2873
2877
|
fmtCodeBlock('yaml', [
|
|
@@ -2883,6 +2887,18 @@ async function renderMcpManual(language) {
|
|
|
2883
2887
|
' env: {}',
|
|
2884
2888
|
' tools: { whitelist: [], blacklist: [] }',
|
|
2885
2889
|
' transform: []',
|
|
2890
|
+
' manual:',
|
|
2891
|
+
' content: |',
|
|
2892
|
+
' 这个 MCP toolset 负责 xx,优先用于 xx 场景。',
|
|
2893
|
+
' sections:',
|
|
2894
|
+
" - title: '何时使用'",
|
|
2895
|
+
' content: |',
|
|
2896
|
+
' 1) 当你需要 ...',
|
|
2897
|
+
' 2) 执行前先确认 ...',
|
|
2898
|
+
" - title: '安全边界'",
|
|
2899
|
+
' content: |',
|
|
2900
|
+
' - 不要用于 ...',
|
|
2901
|
+
' - 若失败先看 ...',
|
|
2886
2902
|
]) +
|
|
2887
2903
|
fmtCodeBlock('yaml', [
|
|
2888
2904
|
'# stdio 路径示例(最小)',
|
|
@@ -2905,9 +2921,15 @@ async function renderMcpManual(language) {
|
|
|
2905
2921
|
' url: http://127.0.0.1:3000/mcp',
|
|
2906
2922
|
' tools: { whitelist: [], blacklist: [] }',
|
|
2907
2923
|
' transform: []',
|
|
2924
|
+
' manual:',
|
|
2925
|
+
' content: "用于远端 MCP 接口调用"',
|
|
2926
|
+
' sections:',
|
|
2927
|
+
" UseCases: '适用于 ...'",
|
|
2928
|
+
" Guardrails: '避免 ...'",
|
|
2908
2929
|
]) +
|
|
2909
2930
|
mcpMapping +
|
|
2910
|
-
mcpSetup
|
|
2931
|
+
mcpSetup +
|
|
2932
|
+
mcpManualDetails);
|
|
2911
2933
|
}
|
|
2912
2934
|
return (fmtHeader('.minds/mcp.yaml') +
|
|
2913
2935
|
fmtList([
|
|
@@ -2918,6 +2940,9 @@ async function renderMcpManual(language) {
|
|
|
2918
2940
|
'Use `tools.whitelist/blacklist` for exposure control and `transform` for naming transforms.',
|
|
2919
2941
|
'Common pitfalls: stdio transport needs a correct executable/command path, and is subject to member permissions (directory + extension: `*_dirs/no_*_dirs/*_file_ext_names/no_*_file_ext_names`); HTTP transport requires the server URL to be reachable.',
|
|
2920
2942
|
'High-frequency pitfall (stdio paths): if `cwd` is omitted, relative paths are resolved from Dominds process cwd (usually rtws root). Prefer setting `cwd` explicitly or use absolute paths. `cwd` must exist and be a directory.',
|
|
2943
|
+
'Optional manual field: place guide text at `servers.<serverId>.manual`. Supported shapes: `content` (overview) + `sections` (chapter list) to explain practical usage for this toolset.',
|
|
2944
|
+
'Important: missing `manual` does not mean the MCP toolset is unavailable. It only indicates team-management coverage is incomplete; continue by reading each tool description/argument schema.',
|
|
2945
|
+
'Team-manager recommendation: after MCP config is validated, carefully read descriptions/arguments of each exposed tool, discuss intended usage for this rtws with the human user, then write `servers.<serverId>.manual` (`content + sections`) capturing typical usage patterns and primary intent directions.',
|
|
2921
2946
|
'Minimal diagnostic flow: 1) run `team_mgmt_check_provider({ provider_key: \"<providerKey>\", model: \"\", all_models: false, live: false, max_models: 0 })` to confirm the LLM provider works; 2) review member directory permissions (`team_mgmt_manual({ topics: [\"permissions\"] })`); 3) run `team_mgmt_validate_mcp_cfg({})` to summarize `.minds/mcp.yaml` + MCP issues; 4) use `mcp_restart` if needed, and `mcp_release` when done.',
|
|
2922
2947
|
]) +
|
|
2923
2948
|
fmtCodeBlock('yaml', [
|
|
@@ -2933,6 +2958,18 @@ async function renderMcpManual(language) {
|
|
|
2933
2958
|
' env: {}',
|
|
2934
2959
|
' tools: { whitelist: [], blacklist: [] }',
|
|
2935
2960
|
' transform: []',
|
|
2961
|
+
' manual:',
|
|
2962
|
+
' content: |',
|
|
2963
|
+
' This MCP toolset is for xx and should be preferred in xx cases.',
|
|
2964
|
+
' sections:',
|
|
2965
|
+
" - title: 'When To Use'",
|
|
2966
|
+
' content: |',
|
|
2967
|
+
' 1) Use when ...',
|
|
2968
|
+
' 2) Confirm ... before execution.',
|
|
2969
|
+
" - title: 'Guardrails'",
|
|
2970
|
+
' content: |',
|
|
2971
|
+
' - Avoid using for ...',
|
|
2972
|
+
' - On failures, first inspect ...',
|
|
2936
2973
|
]) +
|
|
2937
2974
|
fmtCodeBlock('yaml', [
|
|
2938
2975
|
'# stdio path example (minimal)',
|
|
@@ -2955,9 +2992,15 @@ async function renderMcpManual(language) {
|
|
|
2955
2992
|
' url: http://127.0.0.1:3000/mcp',
|
|
2956
2993
|
' tools: { whitelist: [], blacklist: [] }',
|
|
2957
2994
|
' transform: []',
|
|
2995
|
+
' manual:',
|
|
2996
|
+
' content: "For remote MCP endpoint calls"',
|
|
2997
|
+
' sections:',
|
|
2998
|
+
" UseCases: 'Use for ...'",
|
|
2999
|
+
" Guardrails: 'Avoid ...'",
|
|
2958
3000
|
]) +
|
|
2959
3001
|
mcpMapping +
|
|
2960
|
-
mcpSetup
|
|
3002
|
+
mcpSetup +
|
|
3003
|
+
mcpManualDetails);
|
|
2961
3004
|
}
|
|
2962
3005
|
function renderPermissionsManual(language) {
|
|
2963
3006
|
if (language === 'zh') {
|
|
@@ -3219,6 +3262,320 @@ function firstNonEmptyLine(raw) {
|
|
|
3219
3262
|
}
|
|
3220
3263
|
return raw.trim();
|
|
3221
3264
|
}
|
|
3265
|
+
function isObjectRecord(value) {
|
|
3266
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3267
|
+
}
|
|
3268
|
+
function parseMcpManualByServer(rawText) {
|
|
3269
|
+
const manualByServerId = new Map();
|
|
3270
|
+
const invalidByServerId = new Map();
|
|
3271
|
+
let parsedRoot;
|
|
3272
|
+
try {
|
|
3273
|
+
parsedRoot = yaml_1.default.parse(rawText);
|
|
3274
|
+
}
|
|
3275
|
+
catch {
|
|
3276
|
+
return { manualByServerId, invalidByServerId };
|
|
3277
|
+
}
|
|
3278
|
+
if (!isObjectRecord(parsedRoot)) {
|
|
3279
|
+
return { manualByServerId, invalidByServerId };
|
|
3280
|
+
}
|
|
3281
|
+
const serversVal = parsedRoot['servers'];
|
|
3282
|
+
if (!isObjectRecord(serversVal)) {
|
|
3283
|
+
return { manualByServerId, invalidByServerId };
|
|
3284
|
+
}
|
|
3285
|
+
for (const [serverId, serverVal] of Object.entries(serversVal)) {
|
|
3286
|
+
if (!isObjectRecord(serverVal))
|
|
3287
|
+
continue;
|
|
3288
|
+
const manualVal = serverVal['manual'];
|
|
3289
|
+
if (manualVal === undefined || manualVal === null)
|
|
3290
|
+
continue;
|
|
3291
|
+
const parsed = parseMcpManualField(serverId, manualVal);
|
|
3292
|
+
if (parsed.kind === 'present') {
|
|
3293
|
+
manualByServerId.set(serverId, parsed.manual);
|
|
3294
|
+
continue;
|
|
3295
|
+
}
|
|
3296
|
+
if (parsed.kind === 'invalid') {
|
|
3297
|
+
invalidByServerId.set(serverId, parsed.errorText);
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
return { manualByServerId, invalidByServerId };
|
|
3301
|
+
}
|
|
3302
|
+
function parseMcpManualField(serverId, value) {
|
|
3303
|
+
const fieldPath = `servers.${serverId}.manual`;
|
|
3304
|
+
if (typeof value === 'string') {
|
|
3305
|
+
const text = value.trim();
|
|
3306
|
+
if (text === '') {
|
|
3307
|
+
return { kind: 'invalid', errorText: `${fieldPath} must not be empty` };
|
|
3308
|
+
}
|
|
3309
|
+
return { kind: 'present', manual: { content: text, sections: [] } };
|
|
3310
|
+
}
|
|
3311
|
+
if (!isObjectRecord(value)) {
|
|
3312
|
+
return {
|
|
3313
|
+
kind: 'invalid',
|
|
3314
|
+
errorText: `${fieldPath} must be either a string, or an object with optional content + sections`,
|
|
3315
|
+
};
|
|
3316
|
+
}
|
|
3317
|
+
const contentVal = value['content'];
|
|
3318
|
+
let content;
|
|
3319
|
+
if (contentVal !== undefined) {
|
|
3320
|
+
if (!isNonEmptyString(contentVal)) {
|
|
3321
|
+
return {
|
|
3322
|
+
kind: 'invalid',
|
|
3323
|
+
errorText: `${fieldPath}.content must be a non-empty string when provided`,
|
|
3324
|
+
};
|
|
3325
|
+
}
|
|
3326
|
+
content = contentVal.trim();
|
|
3327
|
+
}
|
|
3328
|
+
const sectionsVal = value['sections'];
|
|
3329
|
+
const sections = [];
|
|
3330
|
+
if (sectionsVal !== undefined) {
|
|
3331
|
+
if (Array.isArray(sectionsVal)) {
|
|
3332
|
+
for (let i = 0; i < sectionsVal.length; i++) {
|
|
3333
|
+
const sectionVal = sectionsVal[i];
|
|
3334
|
+
if (!isObjectRecord(sectionVal)) {
|
|
3335
|
+
return {
|
|
3336
|
+
kind: 'invalid',
|
|
3337
|
+
errorText: `${fieldPath}.sections[${i}] must be an object with title/content non-empty strings`,
|
|
3338
|
+
};
|
|
3339
|
+
}
|
|
3340
|
+
const title = sectionVal['title'];
|
|
3341
|
+
const sectionContent = sectionVal['content'];
|
|
3342
|
+
if (!isNonEmptyString(title) || !isNonEmptyString(sectionContent)) {
|
|
3343
|
+
return {
|
|
3344
|
+
kind: 'invalid',
|
|
3345
|
+
errorText: `${fieldPath}.sections[${i}] must provide non-empty title/content strings`,
|
|
3346
|
+
};
|
|
3347
|
+
}
|
|
3348
|
+
sections.push({ title: title.trim(), content: sectionContent.trim() });
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
else if (isObjectRecord(sectionsVal)) {
|
|
3352
|
+
for (const [sectionTitle, sectionContent] of Object.entries(sectionsVal)) {
|
|
3353
|
+
if (!isNonEmptyString(sectionTitle) || !isNonEmptyString(sectionContent)) {
|
|
3354
|
+
return {
|
|
3355
|
+
kind: 'invalid',
|
|
3356
|
+
errorText: `${fieldPath}.sections object entries must be non-empty string -> string`,
|
|
3357
|
+
};
|
|
3358
|
+
}
|
|
3359
|
+
sections.push({ title: sectionTitle.trim(), content: sectionContent.trim() });
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
else {
|
|
3363
|
+
return {
|
|
3364
|
+
kind: 'invalid',
|
|
3365
|
+
errorText: `${fieldPath}.sections must be either [{ title, content }] or { "<title>": "<content>" }`,
|
|
3366
|
+
};
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
if (!content && sections.length === 0) {
|
|
3370
|
+
return {
|
|
3371
|
+
kind: 'invalid',
|
|
3372
|
+
errorText: `${fieldPath} must include at least one of content or sections`,
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
return { kind: 'present', manual: { content, sections } };
|
|
3376
|
+
}
|
|
3377
|
+
function describeMcpManualState(language, state) {
|
|
3378
|
+
if (state.kind === 'present') {
|
|
3379
|
+
const contentText = state.manual.content && state.manual.content.trim() !== ''
|
|
3380
|
+
? language === 'zh'
|
|
3381
|
+
? '有'
|
|
3382
|
+
: 'yes'
|
|
3383
|
+
: language === 'zh'
|
|
3384
|
+
? '无'
|
|
3385
|
+
: 'no';
|
|
3386
|
+
return language === 'zh'
|
|
3387
|
+
? `手册=已配置(content=${contentText},sections=${state.manual.sections.length})`
|
|
3388
|
+
: `manual=configured (content=${contentText}, sections=${state.manual.sections.length})`;
|
|
3389
|
+
}
|
|
3390
|
+
if (state.kind === 'invalid') {
|
|
3391
|
+
return language === 'zh'
|
|
3392
|
+
? `手册=声明无效(${firstNonEmptyLine(state.errorText)};不影响 toolset 可用性,但这是团队管理配置问题)`
|
|
3393
|
+
: `manual=invalid declaration (${firstNonEmptyLine(state.errorText)}; toolset availability is unaffected, but team management should fix this)`;
|
|
3394
|
+
}
|
|
3395
|
+
return language === 'zh'
|
|
3396
|
+
? '手册=缺失(不影响 toolset 可用性;这是团队管理配置不足,请根据每个工具 description/参数自行判断使用)'
|
|
3397
|
+
: 'manual=missing (toolset availability is unaffected; this is a team-management gap, so rely on each tool description/arguments and proceed)';
|
|
3398
|
+
}
|
|
3399
|
+
function inferAutoGeneratedMcpIntentDirections(language, toolNames) {
|
|
3400
|
+
const names = toolNames.map((name) => name.toLowerCase());
|
|
3401
|
+
const out = [];
|
|
3402
|
+
const pushUnique = (line) => {
|
|
3403
|
+
if (!out.includes(line))
|
|
3404
|
+
out.push(line);
|
|
3405
|
+
};
|
|
3406
|
+
const has = (needle) => names.some((name) => name.includes(needle));
|
|
3407
|
+
if (has('browser') || has('page') || has('playwright') || has('screenshot')) {
|
|
3408
|
+
pushUnique(language === 'zh'
|
|
3409
|
+
? '网页/浏览器自动化:用于页面操作、采样、信息抓取与可视化回归辅助。'
|
|
3410
|
+
: 'Web/browser automation: page actions, sampling, information extraction, and visual-regression assistance.');
|
|
3411
|
+
}
|
|
3412
|
+
if (has('git') || has('repo') || has('diff') || has('pr') || has('commit')) {
|
|
3413
|
+
pushUnique(language === 'zh'
|
|
3414
|
+
? '仓库协作与变更分析:用于读取仓库状态、比较差异、辅助代码审查。'
|
|
3415
|
+
: 'Repository collaboration and change analysis: inspect repo state, compare diffs, and support review workflows.');
|
|
3416
|
+
}
|
|
3417
|
+
if (has('sql') || has('db') || has('query') || has('table') || has('postgres')) {
|
|
3418
|
+
pushUnique(language === 'zh'
|
|
3419
|
+
? '数据查询/诊断:用于结构化检索与数据一致性排查。'
|
|
3420
|
+
: 'Data query/diagnostics: structured retrieval and data-consistency investigation.');
|
|
3421
|
+
}
|
|
3422
|
+
if (has('k8s') || has('kubectl') || has('deploy') || has('cluster') || has('helm')) {
|
|
3423
|
+
pushUnique(language === 'zh'
|
|
3424
|
+
? '部署与运行状态诊断:用于集群状态检查、发布过程观测与故障定位。'
|
|
3425
|
+
: 'Deployment/runtime diagnostics: cluster-state checks, release observation, and incident localization.');
|
|
3426
|
+
}
|
|
3427
|
+
if (has('ticket') || has('issue') || has('jira') || has('linear')) {
|
|
3428
|
+
pushUnique(language === 'zh'
|
|
3429
|
+
? '任务流转协作:用于工单读取、状态同步与流程追踪。'
|
|
3430
|
+
: 'Ticket/workflow collaboration: ticket lookup, state synchronization, and process tracking.');
|
|
3431
|
+
}
|
|
3432
|
+
if (out.length === 0) {
|
|
3433
|
+
out.push(language === 'zh'
|
|
3434
|
+
? '未识别出明确领域特征:建议按工具 description/参数逐个确认用途,并与人类用户共同定义边界。'
|
|
3435
|
+
: 'No clear domain signature detected: review each tool description/arguments and define boundaries jointly with the human user.');
|
|
3436
|
+
}
|
|
3437
|
+
return out;
|
|
3438
|
+
}
|
|
3439
|
+
function renderAutoGeneratedMcpManualDraftSection(language, entry) {
|
|
3440
|
+
const lines = [];
|
|
3441
|
+
const statusText = entry.status === 'registered'
|
|
3442
|
+
? language === 'zh'
|
|
3443
|
+
? '已加载'
|
|
3444
|
+
: 'loaded'
|
|
3445
|
+
: entry.status === 'declared_unloaded'
|
|
3446
|
+
? language === 'zh'
|
|
3447
|
+
? '已声明但未加载'
|
|
3448
|
+
: 'declared but not loaded'
|
|
3449
|
+
: language === 'zh'
|
|
3450
|
+
? '声明无效'
|
|
3451
|
+
: 'invalid declaration';
|
|
3452
|
+
const transportText = entry.transport === 'invalid' ? 'invalid' : entry.transport === 'stdio' ? 'stdio' : 'http';
|
|
3453
|
+
lines.push(`\n### toolset \`${entry.serverId}\``);
|
|
3454
|
+
lines.push(...fmtList([
|
|
3455
|
+
language === 'zh'
|
|
3456
|
+
? '检测到 `servers.<serverId>.manual` 缺失,以下为自动生成的基础手册草稿(供临时使用)。'
|
|
3457
|
+
: '`servers.<serverId>.manual` is missing. Below is an auto-generated baseline manual draft (temporary use).',
|
|
3458
|
+
language === 'zh'
|
|
3459
|
+
? `运行时状态:status=${statusText},transport=${transportText}。`
|
|
3460
|
+
: `Runtime status: status=${statusText}, transport=${transportText}.`,
|
|
3461
|
+
language === 'zh'
|
|
3462
|
+
? '关键提醒:该草稿不等于最终规范。团队管理者必须与人类用户确认本 rtws 的真实意图后,再写入更准确的正式手册。'
|
|
3463
|
+
: 'Critical reminder: this draft is not the final policy. Team manager must confirm actual rtws intent with the human user, then author a more accurate final manual.',
|
|
3464
|
+
])
|
|
3465
|
+
.trimEnd()
|
|
3466
|
+
.split('\n'));
|
|
3467
|
+
lines.push(...fmtList([
|
|
3468
|
+
language === 'zh'
|
|
3469
|
+
? '章节:tools 列表(运行时快照)'
|
|
3470
|
+
: 'Section: Tools list (runtime snapshot)',
|
|
3471
|
+
])
|
|
3472
|
+
.trimEnd()
|
|
3473
|
+
.split('\n'));
|
|
3474
|
+
if ((entry.loadedToolNames?.length ?? 0) > 0) {
|
|
3475
|
+
const tools = entry.loadedToolNames ?? [];
|
|
3476
|
+
lines.push(...fmtCodeBlock('text', tools.map((tool) => `- ${tool}`))
|
|
3477
|
+
.trimEnd()
|
|
3478
|
+
.split('\n'));
|
|
3479
|
+
}
|
|
3480
|
+
else {
|
|
3481
|
+
lines.push(...fmtList([
|
|
3482
|
+
language === 'zh'
|
|
3483
|
+
? '当前无法给出已加载 tools 清单(通常因为该 server 尚未加载)。先运行 `team_mgmt_validate_mcp_cfg({})`,必要时再 `mcp_restart`。'
|
|
3484
|
+
: 'Loaded tools are not currently available (usually because this server is not loaded yet). Run `team_mgmt_validate_mcp_cfg({})`, then `mcp_restart` if needed.',
|
|
3485
|
+
])
|
|
3486
|
+
.trimEnd()
|
|
3487
|
+
.split('\n'));
|
|
3488
|
+
}
|
|
3489
|
+
lines.push(...fmtList([
|
|
3490
|
+
language === 'zh'
|
|
3491
|
+
? '章节:主要意图方向(自动推测,待确认)'
|
|
3492
|
+
: 'Section: Primary intent directions (auto-inferred, pending confirmation)',
|
|
3493
|
+
])
|
|
3494
|
+
.trimEnd()
|
|
3495
|
+
.split('\n'));
|
|
3496
|
+
lines.push(...fmtList(inferAutoGeneratedMcpIntentDirections(language, entry.loadedToolNames ?? []))
|
|
3497
|
+
.trimEnd()
|
|
3498
|
+
.split('\n'));
|
|
3499
|
+
lines.push(...fmtList([
|
|
3500
|
+
language === 'zh'
|
|
3501
|
+
? '团队管理者后续动作:精读每个工具说明 -> 与人类用户确认意图与边界 -> 回写 `servers.<serverId>.manual.content + sections`。'
|
|
3502
|
+
: 'Team-manager follow-up: read each tool description carefully -> confirm intent/boundaries with the human user -> write back to `servers.<serverId>.manual.content + sections`.',
|
|
3503
|
+
])
|
|
3504
|
+
.trimEnd()
|
|
3505
|
+
.split('\n'));
|
|
3506
|
+
return lines.join('\n') + '\n';
|
|
3507
|
+
}
|
|
3508
|
+
function renderMcpToolsetManualDetailsSection(language, snapshot) {
|
|
3509
|
+
const header = language === 'zh'
|
|
3510
|
+
? fmtSubHeader('MCP toolset 手册(来自 `.minds/mcp.yaml` 的 `servers.<serverId>.manual`)')
|
|
3511
|
+
: fmtSubHeader('MCP Toolset Manuals (from `.minds/mcp.yaml` `servers.<serverId>.manual`)');
|
|
3512
|
+
if (snapshot.kind !== 'loaded')
|
|
3513
|
+
return '';
|
|
3514
|
+
const entries = snapshot.entries;
|
|
3515
|
+
if (entries.length === 0) {
|
|
3516
|
+
return (header +
|
|
3517
|
+
fmtList([
|
|
3518
|
+
language === 'zh'
|
|
3519
|
+
? '当前没有 MCP toolset 可展示。'
|
|
3520
|
+
: 'There are currently no MCP toolsets to display.',
|
|
3521
|
+
]));
|
|
3522
|
+
}
|
|
3523
|
+
let out = header +
|
|
3524
|
+
fmtList([
|
|
3525
|
+
language === 'zh'
|
|
3526
|
+
? '若 `servers.<serverId>.manual` 已配置,显示正式手册;若缺失,则自动生成基础草稿(含 tools 列表与意图方向草稿)供临时使用。'
|
|
3527
|
+
: 'If `servers.<serverId>.manual` is configured, the formal manual is shown; if missing, an auto-generated baseline draft (including tools list and intent directions draft) is provided for temporary use.',
|
|
3528
|
+
]);
|
|
3529
|
+
for (const entry of entries) {
|
|
3530
|
+
if (entry.manualState.kind === 'missing') {
|
|
3531
|
+
out += renderAutoGeneratedMcpManualDraftSection(language, entry);
|
|
3532
|
+
continue;
|
|
3533
|
+
}
|
|
3534
|
+
if (entry.manualState.kind === 'invalid') {
|
|
3535
|
+
out += `\n### toolset \`${entry.serverId}\`\n`;
|
|
3536
|
+
out += fmtList([
|
|
3537
|
+
language === 'zh'
|
|
3538
|
+
? `\`servers.${entry.serverId}.manual\` 声明无效:${firstNonEmptyLine(entry.manualState.errorText)}`
|
|
3539
|
+
: `\`servers.${entry.serverId}.manual\` is invalid: ${firstNonEmptyLine(entry.manualState.errorText)}`,
|
|
3540
|
+
language === 'zh'
|
|
3541
|
+
? '这不影响 toolset 可用性;请根据工具说明继续使用,并通知团队管理者修复手册字段。'
|
|
3542
|
+
: 'Toolset availability is unaffected; continue by tool-level descriptions and ask the team manager to fix the manual field.',
|
|
3543
|
+
]);
|
|
3544
|
+
continue;
|
|
3545
|
+
}
|
|
3546
|
+
if (entry.manualState.kind !== 'present')
|
|
3547
|
+
continue;
|
|
3548
|
+
const manual = entry.manualState.manual;
|
|
3549
|
+
out += `\n### toolset \`${entry.serverId}\`\n`;
|
|
3550
|
+
if (manual.content && manual.content.trim() !== '') {
|
|
3551
|
+
out +=
|
|
3552
|
+
fmtList([language === 'zh' ? '总说明(content):' : 'Overview (`content`):']) +
|
|
3553
|
+
fmtCodeBlock('markdown', [manual.content]);
|
|
3554
|
+
}
|
|
3555
|
+
else {
|
|
3556
|
+
out += fmtList([
|
|
3557
|
+
language === 'zh'
|
|
3558
|
+
? '总说明(content):(未提供)'
|
|
3559
|
+
: 'Overview (`content`): (not provided)',
|
|
3560
|
+
]);
|
|
3561
|
+
}
|
|
3562
|
+
if (manual.sections.length > 0) {
|
|
3563
|
+
for (const section of manual.sections) {
|
|
3564
|
+
out +=
|
|
3565
|
+
fmtList([language === 'zh' ? `章节:${section.title}` : `Section: ${section.title}`]) +
|
|
3566
|
+
fmtCodeBlock('markdown', [section.content]);
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
else {
|
|
3570
|
+
out += fmtList([
|
|
3571
|
+
language === 'zh'
|
|
3572
|
+
? '章节(sections):(未提供)'
|
|
3573
|
+
: 'Sections (`sections`): (not provided)',
|
|
3574
|
+
]);
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
return out;
|
|
3578
|
+
}
|
|
3222
3579
|
async function readMcpToolsetMappingSnapshot() {
|
|
3223
3580
|
const mcpAbsPath = path_1.default.resolve(process.cwd(), MCP_YAML_REL);
|
|
3224
3581
|
let rawText;
|
|
@@ -3238,6 +3595,7 @@ async function readMcpToolsetMappingSnapshot() {
|
|
|
3238
3595
|
if (!parsed.ok) {
|
|
3239
3596
|
return { kind: 'invalid_yaml', errorText: parsed.errorText };
|
|
3240
3597
|
}
|
|
3598
|
+
const manualInfo = parseMcpManualByServer(rawText);
|
|
3241
3599
|
const registeredToolsets = (0, registry_2.listToolsets)();
|
|
3242
3600
|
const invalidByServerId = new Map();
|
|
3243
3601
|
for (const invalid of parsed.invalidServers) {
|
|
@@ -3246,24 +3604,35 @@ async function readMcpToolsetMappingSnapshot() {
|
|
|
3246
3604
|
const entries = [];
|
|
3247
3605
|
for (const serverId of parsed.serverIdsInYamlOrder) {
|
|
3248
3606
|
const invalidError = invalidByServerId.get(serverId);
|
|
3607
|
+
const manualError = manualInfo.invalidByServerId.get(serverId);
|
|
3608
|
+
const manual = manualInfo.manualByServerId.get(serverId);
|
|
3609
|
+
const manualState = manualError
|
|
3610
|
+
? { kind: 'invalid', errorText: manualError }
|
|
3611
|
+
: manual
|
|
3612
|
+
? { kind: 'present', manual }
|
|
3613
|
+
: { kind: 'missing' };
|
|
3249
3614
|
if (invalidError) {
|
|
3250
3615
|
entries.push({
|
|
3251
3616
|
serverId,
|
|
3252
3617
|
transport: 'invalid',
|
|
3253
3618
|
status: 'declared_invalid',
|
|
3254
3619
|
errorText: invalidError,
|
|
3620
|
+
manualState,
|
|
3255
3621
|
});
|
|
3256
3622
|
continue;
|
|
3257
3623
|
}
|
|
3258
3624
|
const transport = parsed.config.servers[serverId]?.transport ?? 'invalid';
|
|
3259
3625
|
const loadedTools = registeredToolsets[serverId];
|
|
3260
3626
|
if (loadedTools) {
|
|
3627
|
+
const loadedToolNames = loadedTools.map((t) => t.name);
|
|
3261
3628
|
entries.push({
|
|
3262
3629
|
serverId,
|
|
3263
3630
|
transport,
|
|
3264
3631
|
status: 'registered',
|
|
3265
3632
|
loadedToolCount: loadedTools.length,
|
|
3266
|
-
|
|
3633
|
+
loadedToolNames,
|
|
3634
|
+
loadedToolNamesPreview: loadedToolNames.slice(0, 6),
|
|
3635
|
+
manualState,
|
|
3267
3636
|
});
|
|
3268
3637
|
continue;
|
|
3269
3638
|
}
|
|
@@ -3271,6 +3640,7 @@ async function readMcpToolsetMappingSnapshot() {
|
|
|
3271
3640
|
serverId,
|
|
3272
3641
|
transport,
|
|
3273
3642
|
status: 'declared_unloaded',
|
|
3643
|
+
manualState,
|
|
3274
3644
|
});
|
|
3275
3645
|
}
|
|
3276
3646
|
return { kind: 'loaded', entries };
|
|
@@ -3320,6 +3690,7 @@ function renderMcpToolsetMappingSection(language, snapshot) {
|
|
|
3320
3690
|
const lines = [];
|
|
3321
3691
|
for (const entry of snapshot.entries) {
|
|
3322
3692
|
const transportText = entry.transport === 'invalid' ? 'invalid' : entry.transport === 'stdio' ? 'stdio' : 'http';
|
|
3693
|
+
const manualText = describeMcpManualState(language, entry.manualState);
|
|
3323
3694
|
if (entry.status === 'registered') {
|
|
3324
3695
|
const preview = entry.loadedToolNamesPreview ?? [];
|
|
3325
3696
|
const previewText = preview.length > 0
|
|
@@ -3329,27 +3700,29 @@ function renderMcpToolsetMappingSection(language, snapshot) {
|
|
|
3329
3700
|
: '')
|
|
3330
3701
|
: '(none)';
|
|
3331
3702
|
lines.push(language === 'zh'
|
|
3332
|
-
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(transport=${transportText},状态=已加载,tools=${entry.loadedToolCount ?? 0}:${previewText})`
|
|
3333
|
-
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (transport=${transportText}, status=loaded, tools=${entry.loadedToolCount ?? 0}: ${previewText})`);
|
|
3703
|
+
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(transport=${transportText},状态=已加载,tools=${entry.loadedToolCount ?? 0}:${previewText};${manualText})`
|
|
3704
|
+
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (transport=${transportText}, status=loaded, tools=${entry.loadedToolCount ?? 0}: ${previewText}; ${manualText})`);
|
|
3334
3705
|
continue;
|
|
3335
3706
|
}
|
|
3336
3707
|
if (entry.status === 'declared_unloaded') {
|
|
3337
3708
|
lines.push(language === 'zh'
|
|
3338
|
-
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(transport=${transportText}
|
|
3339
|
-
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (transport=${transportText}, status=declared but not loaded)`);
|
|
3709
|
+
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(transport=${transportText},状态=已声明但未加载;${manualText})`
|
|
3710
|
+
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (transport=${transportText}, status=declared but not loaded; ${manualText})`);
|
|
3340
3711
|
continue;
|
|
3341
3712
|
}
|
|
3342
3713
|
lines.push(language === 'zh'
|
|
3343
|
-
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(状态=声明无效:${firstNonEmptyLine(entry.errorText ?? '')})`
|
|
3344
|
-
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (status=invalid declaration: ${firstNonEmptyLine(entry.errorText ?? '')})`);
|
|
3714
|
+
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(状态=声明无效:${firstNonEmptyLine(entry.errorText ?? '')};${manualText})`
|
|
3715
|
+
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (status=invalid declaration: ${firstNonEmptyLine(entry.errorText ?? '')}; ${manualText})`);
|
|
3345
3716
|
}
|
|
3346
3717
|
const tail = language === 'zh'
|
|
3347
3718
|
? [
|
|
3348
3719
|
'说明:`已声明但未加载` 通常表示当前会话尚未完成 MCP 重载,或 server 启动失败。',
|
|
3720
|
+
'说明:MCP toolset “没有 manual” 不等于“不可用”。无 manual 仅表示团队管理者没有提供章节化手册;你应继续阅读每个工具的 description/参数并谨慎使用。',
|
|
3349
3721
|
'建议:运行 `team_mgmt_validate_mcp_cfg({})`,必要时执行 `mcp_restart`。',
|
|
3350
3722
|
]
|
|
3351
3723
|
: [
|
|
3352
3724
|
'`declared but not loaded` usually means MCP reload has not completed in the current session, or server startup failed.',
|
|
3725
|
+
'Important: “missing manual” for an MCP toolset does NOT mean unavailable. It only means the team manager did not provide chapterized manual text; continue by reading each tool description/arguments and use with care.',
|
|
3353
3726
|
'Recommendation: run `team_mgmt_validate_mcp_cfg({})`, then `mcp_restart` if needed.',
|
|
3354
3727
|
];
|
|
3355
3728
|
return header + fmtList(lines.concat(tail));
|
|
@@ -3553,6 +3926,7 @@ async function renderToolsets(language) {
|
|
|
3553
3926
|
const mcpSnapshot = await readMcpToolsetMappingSnapshot();
|
|
3554
3927
|
const mcpMapping = renderMcpToolsetMappingSection(language, mcpSnapshot);
|
|
3555
3928
|
const mcpSetup = renderMcpToolsetSetupGuideSection(language, mcpSnapshot);
|
|
3929
|
+
const mcpManualDetails = renderMcpToolsetManualDetailsSection(language, mcpSnapshot);
|
|
3556
3930
|
return (header +
|
|
3557
3931
|
intro +
|
|
3558
3932
|
patterns +
|
|
@@ -3561,7 +3935,8 @@ async function renderToolsets(language) {
|
|
|
3561
3935
|
list +
|
|
3562
3936
|
capabilitySummary +
|
|
3563
3937
|
mcpMapping +
|
|
3564
|
-
mcpSetup
|
|
3938
|
+
mcpSetup +
|
|
3939
|
+
mcpManualDetails);
|
|
3565
3940
|
}
|
|
3566
3941
|
async function renderBuiltinDefaults(language) {
|
|
3567
3942
|
const header = language === 'zh'
|
|
@@ -3709,6 +4084,7 @@ exports.teamMgmtValidateMcpCfgTool = {
|
|
|
3709
4084
|
let mcpRaw = null;
|
|
3710
4085
|
let declaredServerCount = 0;
|
|
3711
4086
|
let fallbackInvalidServers = [];
|
|
4087
|
+
let fallbackInvalidToolsetManuals = [];
|
|
3712
4088
|
try {
|
|
3713
4089
|
const st = await promises_1.default.stat(mcpYamlAbs);
|
|
3714
4090
|
if (!st.isFile()) {
|
|
@@ -3739,6 +4115,8 @@ exports.teamMgmtValidateMcpCfgTool = {
|
|
|
3739
4115
|
}
|
|
3740
4116
|
declaredServerCount = parsed.serverIdsInYamlOrder.length;
|
|
3741
4117
|
fallbackInvalidServers = parsed.invalidServers;
|
|
4118
|
+
const manualInfo = parseMcpManualByServer(mcpRaw);
|
|
4119
|
+
fallbackInvalidToolsetManuals = [...manualInfo.invalidByServerId.entries()].map(([serverId, errorText]) => ({ serverId, errorText }));
|
|
3742
4120
|
}
|
|
3743
4121
|
catch (err) {
|
|
3744
4122
|
if (!(isFsErrWithCode(err) && err.code === 'ENOENT')) {
|
|
@@ -3754,7 +4132,18 @@ exports.teamMgmtValidateMcpCfgTool = {
|
|
|
3754
4132
|
fallbackOnlyInvalidServers.push(s);
|
|
3755
4133
|
}
|
|
3756
4134
|
}
|
|
3757
|
-
|
|
4135
|
+
const fallbackOnlyInvalidToolsetManuals = [];
|
|
4136
|
+
for (const s of fallbackInvalidToolsetManuals) {
|
|
4137
|
+
const hasMatchingProblem = mcpProblems.some((p) => p.kind === 'mcp_server_error' &&
|
|
4138
|
+
p.detail.serverId === s.serverId &&
|
|
4139
|
+
p.detail.errorText.includes(firstNonEmptyLine(s.errorText)));
|
|
4140
|
+
if (!hasMatchingProblem) {
|
|
4141
|
+
fallbackOnlyInvalidToolsetManuals.push(s);
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
if (mcpProblems.length === 0 &&
|
|
4145
|
+
fallbackOnlyInvalidServers.length === 0 &&
|
|
4146
|
+
fallbackOnlyInvalidToolsetManuals.length === 0) {
|
|
3758
4147
|
const msg = language === 'zh'
|
|
3759
4148
|
? fmtHeader('mcp.yaml 校验通过') +
|
|
3760
4149
|
fmtList([
|
|
@@ -3809,19 +4198,29 @@ exports.teamMgmtValidateMcpCfgTool = {
|
|
|
3809
4198
|
issueLines.push(` serverId: ${s.serverId}`);
|
|
3810
4199
|
issueLines.push(' ' + s.errorText.split('\n').join('\n '));
|
|
3811
4200
|
}
|
|
3812
|
-
const
|
|
4201
|
+
for (const s of fallbackOnlyInvalidToolsetManuals) {
|
|
4202
|
+
issueLines.push(`- [error] ${MCP_SERVER_PROBLEM_PREFIX}${s.serverId}/toolset_manual_error`);
|
|
4203
|
+
issueLines.push(` serverId: ${s.serverId}`);
|
|
4204
|
+
issueLines.push(language === 'zh'
|
|
4205
|
+
? ' toolset manual: servers.<serverId>.manual 声明无效'
|
|
4206
|
+
: ' toolset manual: servers.<serverId>.manual invalid declaration');
|
|
4207
|
+
issueLines.push(' ' + s.errorText.split('\n').join('\n '));
|
|
4208
|
+
}
|
|
4209
|
+
const totalIssues = mcpProblems.length +
|
|
4210
|
+
fallbackOnlyInvalidServers.length +
|
|
4211
|
+
fallbackOnlyInvalidToolsetManuals.length;
|
|
3813
4212
|
const msg = language === 'zh'
|
|
3814
4213
|
? fmtHeader('mcp.yaml 校验失败') +
|
|
3815
4214
|
fmtList([
|
|
3816
4215
|
`\`${MCP_YAML_REL}\`:❌ 检测到 ${totalIssues} 个问题(详见 Problems 面板)`,
|
|
3817
|
-
'说明:MCP
|
|
4216
|
+
'说明:MCP 配置问题(含 toolset manual 声明错误)会导致 server/toolset 加载失败、工具手册缺失/错误或运行时异常。',
|
|
3818
4217
|
]) +
|
|
3819
4218
|
'\n' +
|
|
3820
4219
|
issueLines.join('\n')
|
|
3821
4220
|
: fmtHeader('mcp.yaml Validation Failed') +
|
|
3822
4221
|
fmtList([
|
|
3823
4222
|
`\`${MCP_YAML_REL}\`: ❌ ${totalIssues} issue(s) detected (see Problems panel)`,
|
|
3824
|
-
'Note: MCP config issues can block server/toolset loading
|
|
4223
|
+
'Note: MCP config issues (including toolset manual declaration errors) can block server/toolset loading, produce bad/missing manual guidance, or cause runtime tool failures.',
|
|
3825
4224
|
]) +
|
|
3826
4225
|
'\n' +
|
|
3827
4226
|
issueLines.join('\n');
|