dominds 1.17.2 → 1.17.4
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/apps-host/host.js +13 -2
- package/dist/apps-host/ipc-types.js +18 -1
- package/dist/dialog-fork.js +1 -0
- package/dist/dialog.js +5 -0
- package/dist/docs/mcp-support.md +4 -1
- package/dist/docs/team_mgmt-toolset.md +8 -7
- package/dist/docs/team_mgmt-toolset.zh.md +6 -5
- package/dist/mcp/manual-problems.d.ts +33 -0
- package/dist/mcp/manual-problems.js +323 -0
- package/dist/mcp/supervisor.js +23 -1
- package/dist/persistence.js +12 -0
- package/dist/priming.js +7 -0
- package/dist/shared-reminders.js +2 -0
- package/dist/tool.d.ts +5 -0
- package/dist/tool.js +66 -4
- package/dist/tools/app-reminders.js +20 -3
- package/dist/tools/ctrl.js +43 -4
- package/dist/tools/manual/output-limit.d.ts +9 -0
- package/dist/tools/manual/output-limit.js +12 -0
- package/dist/tools/os.js +173 -37
- package/dist/tools/pending-tellask-reminder.d.ts +1 -1
- package/dist/tools/pending-tellask-reminder.js +39 -19
- package/dist/tools/team_mgmt-manual.d.ts +2 -0
- package/dist/tools/team_mgmt-manual.js +160 -0
- package/dist/tools/team_mgmt-mcp-manual.d.ts +27 -0
- package/dist/tools/team_mgmt-mcp-manual.js +643 -0
- package/dist/tools/team_mgmt.d.ts +11 -1
- package/dist/tools/team_mgmt.js +22 -867
- package/dist/tools/toolset-manual.js +5 -5
- package/package.json +4 -4
- package/webapp/dist/assets/{_basePickBy-EK9iGcOl.js → _basePickBy-CgM-M_q8.js} +3 -3
- package/webapp/dist/assets/{_basePickBy-EK9iGcOl.js.map → _basePickBy-CgM-M_q8.js.map} +1 -1
- package/webapp/dist/assets/{_baseUniq-BHtz-XvO.js → _baseUniq-B06twih4.js} +2 -2
- package/webapp/dist/assets/{_baseUniq-BHtz-XvO.js.map → _baseUniq-B06twih4.js.map} +1 -1
- package/webapp/dist/assets/{arc-NqUmMwkS.js → arc-CoXJvjeB.js} +2 -2
- package/webapp/dist/assets/{arc-NqUmMwkS.js.map → arc-CoXJvjeB.js.map} +1 -1
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-CJ7Jb15a.js → architectureDiagram-2XIMDMQ5-BLFRWTKn.js} +7 -7
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-CJ7Jb15a.js.map → architectureDiagram-2XIMDMQ5-BLFRWTKn.js.map} +1 -1
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-RNM7ujN4.js → blockDiagram-WCTKOSBZ-CYRE6deu.js} +7 -7
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-RNM7ujN4.js.map → blockDiagram-WCTKOSBZ-CYRE6deu.js.map} +1 -1
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-DKra5-za.js → c4Diagram-IC4MRINW-B26QTIJt.js} +3 -3
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-DKra5-za.js.map → c4Diagram-IC4MRINW-B26QTIJt.js.map} +1 -1
- package/webapp/dist/assets/{channel-CxE9sL_E.js → channel-C5U2W0P9.js} +2 -2
- package/webapp/dist/assets/{channel-CxE9sL_E.js.map → channel-C5U2W0P9.js.map} +1 -1
- package/webapp/dist/assets/{chunk-4BX2VUAB-BlyIt9uv.js → chunk-4BX2VUAB-7z2PgnSv.js} +2 -2
- package/webapp/dist/assets/{chunk-4BX2VUAB-BlyIt9uv.js.map → chunk-4BX2VUAB-7z2PgnSv.js.map} +1 -1
- package/webapp/dist/assets/{chunk-55IACEB6-DsPShmjL.js → chunk-55IACEB6-6sRVmXqs.js} +2 -2
- package/webapp/dist/assets/{chunk-55IACEB6-DsPShmjL.js.map → chunk-55IACEB6-6sRVmXqs.js.map} +1 -1
- package/webapp/dist/assets/{chunk-FMBD7UC4-C2i0rEFF.js → chunk-FMBD7UC4-BwYp8OtY.js} +2 -2
- package/webapp/dist/assets/{chunk-FMBD7UC4-C2i0rEFF.js.map → chunk-FMBD7UC4-BwYp8OtY.js.map} +1 -1
- package/webapp/dist/assets/{chunk-JSJVCQXG-CK8inzJx.js → chunk-JSJVCQXG-CRq8LK53.js} +2 -2
- package/webapp/dist/assets/{chunk-JSJVCQXG-CK8inzJx.js.map → chunk-JSJVCQXG-CRq8LK53.js.map} +1 -1
- package/webapp/dist/assets/{chunk-KX2RTZJC-BjEK5_oI.js → chunk-KX2RTZJC-CzFE355P.js} +2 -2
- package/webapp/dist/assets/{chunk-KX2RTZJC-BjEK5_oI.js.map → chunk-KX2RTZJC-CzFE355P.js.map} +1 -1
- package/webapp/dist/assets/{chunk-NQ4KR5QH-Clf489xc.js → chunk-NQ4KR5QH-3cQSOzCt.js} +4 -4
- package/webapp/dist/assets/{chunk-NQ4KR5QH-Clf489xc.js.map → chunk-NQ4KR5QH-3cQSOzCt.js.map} +1 -1
- package/webapp/dist/assets/{chunk-QZHKN3VN-CMikir3s.js → chunk-QZHKN3VN-DWkpxb-w.js} +2 -2
- package/webapp/dist/assets/{chunk-QZHKN3VN-CMikir3s.js.map → chunk-QZHKN3VN-DWkpxb-w.js.map} +1 -1
- package/webapp/dist/assets/{chunk-WL4C6EOR-1gtCLicd.js → chunk-WL4C6EOR-DkpfoQzK.js} +6 -6
- package/webapp/dist/assets/{chunk-WL4C6EOR-1gtCLicd.js.map → chunk-WL4C6EOR-DkpfoQzK.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-kzzlkQ_D.js → classDiagram-VBA2DB6C-mVfJeuZL.js} +7 -7
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-kzzlkQ_D.js.map → classDiagram-VBA2DB6C-mVfJeuZL.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-kzzlkQ_D.js → classDiagram-v2-RAHNMMFH-mVfJeuZL.js} +7 -7
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-kzzlkQ_D.js.map → classDiagram-v2-RAHNMMFH-mVfJeuZL.js.map} +1 -1
- package/webapp/dist/assets/{clone-XglJh1R0.js → clone-5uLJc7AC.js} +2 -2
- package/webapp/dist/assets/{clone-XglJh1R0.js.map → clone-5uLJc7AC.js.map} +1 -1
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A--gZrh2tG.js → cose-bilkent-S5V4N54A-CoiJzdQi.js} +2 -2
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A--gZrh2tG.js.map → cose-bilkent-S5V4N54A-CoiJzdQi.js.map} +1 -1
- package/webapp/dist/assets/{dagre-KLK3FWXG-D_JMhNNL.js → dagre-KLK3FWXG-DU_3BSOq.js} +7 -7
- package/webapp/dist/assets/{dagre-KLK3FWXG-D_JMhNNL.js.map → dagre-KLK3FWXG-DU_3BSOq.js.map} +1 -1
- package/webapp/dist/assets/{diagram-E7M64L7V-HkYhqJDL.js → diagram-E7M64L7V-DgqOvF1U.js} +8 -8
- package/webapp/dist/assets/{diagram-E7M64L7V-HkYhqJDL.js.map → diagram-E7M64L7V-DgqOvF1U.js.map} +1 -1
- package/webapp/dist/assets/{diagram-IFDJBPK2-BFv5iU5U.js → diagram-IFDJBPK2-CFWMc1oD.js} +7 -7
- package/webapp/dist/assets/{diagram-IFDJBPK2-BFv5iU5U.js.map → diagram-IFDJBPK2-CFWMc1oD.js.map} +1 -1
- package/webapp/dist/assets/{diagram-P4PSJMXO-Dg46tTnk.js → diagram-P4PSJMXO-lrqvXDXp.js} +7 -7
- package/webapp/dist/assets/{diagram-P4PSJMXO-Dg46tTnk.js.map → diagram-P4PSJMXO-lrqvXDXp.js.map} +1 -1
- package/webapp/dist/assets/{erDiagram-INFDFZHY-BzJClUtq.js → erDiagram-INFDFZHY-C28KjRkA.js} +5 -5
- package/webapp/dist/assets/{erDiagram-INFDFZHY-BzJClUtq.js.map → erDiagram-INFDFZHY-C28KjRkA.js.map} +1 -1
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-IBGgxeki.js → flowDiagram-PKNHOUZH-DkxGh-JF.js} +7 -7
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-IBGgxeki.js.map → flowDiagram-PKNHOUZH-DkxGh-JF.js.map} +1 -1
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-DdxgzFKe.js → ganttDiagram-A5KZAMGK-BmZnHD96.js} +3 -3
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-DdxgzFKe.js.map → ganttDiagram-A5KZAMGK-BmZnHD96.js.map} +1 -1
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-C14OpSSI.js → gitGraphDiagram-K3NZZRJ6-xiHqomZC.js} +8 -8
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-C14OpSSI.js.map → gitGraphDiagram-K3NZZRJ6-xiHqomZC.js.map} +1 -1
- package/webapp/dist/assets/{graph-BrKKvSVx.js → graph-ozb0amP0.js} +3 -3
- package/webapp/dist/assets/{graph-BrKKvSVx.js.map → graph-ozb0amP0.js.map} +1 -1
- package/webapp/dist/assets/{index-BV_dDe3L.js → index-Cyx7eev_.js} +700 -165
- package/webapp/dist/assets/{index-BV_dDe3L.js.map → index-Cyx7eev_.js.map} +1 -1
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-k0Yv94VI.js → infoDiagram-LFFYTUFH-fLl_TA1F.js} +6 -6
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-k0Yv94VI.js.map → infoDiagram-LFFYTUFH-fLl_TA1F.js.map} +1 -1
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-C3EYBxjN.js → ishikawaDiagram-PHBUUO56-ZL9tBKUr.js} +2 -2
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-C3EYBxjN.js.map → ishikawaDiagram-PHBUUO56-ZL9tBKUr.js.map} +1 -1
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-BnSlOrbq.js → journeyDiagram-4ABVD52K--aRyymZs.js} +5 -5
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-BnSlOrbq.js.map → journeyDiagram-4ABVD52K--aRyymZs.js.map} +1 -1
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-CNYH0HDF.js → kanban-definition-K7BYSVSG-BO_QdW_O.js} +3 -3
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-CNYH0HDF.js.map → kanban-definition-K7BYSVSG-BO_QdW_O.js.map} +1 -1
- package/webapp/dist/assets/{layout-NtmBC9CZ.js → layout-Bu3Xw0z2.js} +5 -5
- package/webapp/dist/assets/{layout-NtmBC9CZ.js.map → layout-Bu3Xw0z2.js.map} +1 -1
- package/webapp/dist/assets/{linear-BrqwApt9.js → linear-Bq77itJm.js} +2 -2
- package/webapp/dist/assets/{linear-BrqwApt9.js.map → linear-Bq77itJm.js.map} +1 -1
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DcknQb8H.js → mindmap-definition-YRQLILUH-CHB8qv8L.js} +4 -4
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DcknQb8H.js.map → mindmap-definition-YRQLILUH-CHB8qv8L.js.map} +1 -1
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-wydKHXzN.js → pieDiagram-SKSYHLDU-Cxg_wh4K.js} +8 -8
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-wydKHXzN.js.map → pieDiagram-SKSYHLDU-Cxg_wh4K.js.map} +1 -1
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-D6i3VaFO.js → quadrantDiagram-337W2JSQ-DFguuaS9.js} +3 -3
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-D6i3VaFO.js.map → quadrantDiagram-337W2JSQ-DFguuaS9.js.map} +1 -1
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-C0sBwH6H.js → requirementDiagram-Z7DCOOCP--tJ_dfsT.js} +4 -4
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-C0sBwH6H.js.map → requirementDiagram-Z7DCOOCP--tJ_dfsT.js.map} +1 -1
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-33jPg4PK.js → sankeyDiagram-WA2Y5GQK-f0zWimMc.js} +2 -2
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-33jPg4PK.js.map → sankeyDiagram-WA2Y5GQK-f0zWimMc.js.map} +1 -1
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-CJsKHnh5.js → sequenceDiagram-2WXFIKYE-dwXRRnyq.js} +4 -4
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-CJsKHnh5.js.map → sequenceDiagram-2WXFIKYE-dwXRRnyq.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-B6A5jTdU.js → stateDiagram-RAJIS63D-DToxcEC2.js} +9 -9
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-B6A5jTdU.js.map → stateDiagram-RAJIS63D-DToxcEC2.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-6YIjpVKr.js → stateDiagram-v2-FVOUBMTO-BY5hDUqz.js} +5 -5
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-6YIjpVKr.js.map → stateDiagram-v2-FVOUBMTO-BY5hDUqz.js.map} +1 -1
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-BQS5KHfj.js → timeline-definition-YZTLITO2-CT3WRcFt.js} +3 -3
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-BQS5KHfj.js.map → timeline-definition-YZTLITO2-CT3WRcFt.js.map} +1 -1
- package/webapp/dist/assets/{treemap-KZPCXAKY-DB1uUX8l.js → treemap-KZPCXAKY-Lnkh2bpd.js} +5 -5
- package/webapp/dist/assets/{treemap-KZPCXAKY-DB1uUX8l.js.map → treemap-KZPCXAKY-Lnkh2bpd.js.map} +1 -1
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-BtcfWZJx.js → vennDiagram-LZ73GAT5-CYSLSh1w.js} +2 -2
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-BtcfWZJx.js.map → vennDiagram-LZ73GAT5-CYSLSh1w.js.map} +1 -1
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-CfIdcI74.js → xychartDiagram-JWTSCODW-DgvaqrGO.js} +3 -3
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-CfIdcI74.js.map → xychartDiagram-JWTSCODW-DgvaqrGO.js.map} +1 -1
- package/webapp/dist/index.html +1 -1
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.renderMcpToolsetManualDetailsSection = renderMcpToolsetManualDetailsSection;
|
|
7
|
+
exports.readMcpToolsetMappingSnapshot = readMcpToolsetMappingSnapshot;
|
|
8
|
+
exports.renderMcpToolsetMappingSection = renderMcpToolsetMappingSection;
|
|
9
|
+
exports.renderMcpToolsetSetupGuideSection = renderMcpToolsetSetupGuideSection;
|
|
10
|
+
exports.renderMcpManual = renderMcpManual;
|
|
11
|
+
exports.measureRenderedTeamMgmtMcpTopicRawChars = measureRenderedTeamMgmtMcpTopicRawChars;
|
|
12
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const config_1 = require("../mcp/config");
|
|
15
|
+
const manual_problems_1 = require("../mcp/manual-problems");
|
|
16
|
+
const registry_1 = require("./registry");
|
|
17
|
+
const MINDS_DIR = '.minds';
|
|
18
|
+
const TEAM_YAML_REL = `${MINDS_DIR}/team.yaml`;
|
|
19
|
+
const MCP_YAML_REL = `${MINDS_DIR}/mcp.yaml`;
|
|
20
|
+
function fmtHeader(title) {
|
|
21
|
+
return `# ${title}\n`;
|
|
22
|
+
}
|
|
23
|
+
function fmtSubHeader(title) {
|
|
24
|
+
return `\n## ${title}\n`;
|
|
25
|
+
}
|
|
26
|
+
function fmtList(items) {
|
|
27
|
+
return (items
|
|
28
|
+
.filter((s) => s.trim() !== '')
|
|
29
|
+
.map((s) => `- ${s}`)
|
|
30
|
+
.join('\n') + '\n');
|
|
31
|
+
}
|
|
32
|
+
function fmtCodeBlock(lang, lines) {
|
|
33
|
+
const body = lines.join('\n');
|
|
34
|
+
return `\n\n\`\`\`${lang}\n${body}\n\`\`\`\n`;
|
|
35
|
+
}
|
|
36
|
+
function isFsErrWithCode(err) {
|
|
37
|
+
return typeof err === 'object' && err !== null && 'code' in err;
|
|
38
|
+
}
|
|
39
|
+
function firstNonEmptyLine(raw) {
|
|
40
|
+
for (const line of raw.split('\n')) {
|
|
41
|
+
const trimmed = line.trim();
|
|
42
|
+
if (trimmed !== '')
|
|
43
|
+
return trimmed;
|
|
44
|
+
}
|
|
45
|
+
return raw.trim();
|
|
46
|
+
}
|
|
47
|
+
function describeMcpManualState(language, state) {
|
|
48
|
+
if (state.kind === 'present') {
|
|
49
|
+
const contentText = state.manual.content && state.manual.content.trim() !== ''
|
|
50
|
+
? language === 'zh'
|
|
51
|
+
? '有'
|
|
52
|
+
: 'yes'
|
|
53
|
+
: language === 'zh'
|
|
54
|
+
? '无'
|
|
55
|
+
: 'no';
|
|
56
|
+
const contentFileText = state.manual.contentFile && state.manual.contentFile.trim() !== ''
|
|
57
|
+
? state.manual.contentFile
|
|
58
|
+
: language === 'zh'
|
|
59
|
+
? '无'
|
|
60
|
+
: 'no';
|
|
61
|
+
return language === 'zh'
|
|
62
|
+
? `手册=已配置(contentFile=${contentFileText},content=${contentText},sections=${state.manual.sections.length})`
|
|
63
|
+
: `manual=configured (contentFile=${contentFileText}, content=${contentText}, sections=${state.manual.sections.length})`;
|
|
64
|
+
}
|
|
65
|
+
if (state.kind === 'invalid') {
|
|
66
|
+
return language === 'zh'
|
|
67
|
+
? `手册=声明无效(${firstNonEmptyLine(state.errorText)};不影响 toolset 可用性,但这是团队管理配置问题)`
|
|
68
|
+
: `manual=invalid declaration (${firstNonEmptyLine(state.errorText)}; toolset availability is unaffected, but team management should fix this)`;
|
|
69
|
+
}
|
|
70
|
+
return language === 'zh'
|
|
71
|
+
? '手册=缺失(不影响 toolset 可用性;这是团队管理配置不足,请根据每个工具 description/参数自行判断使用)'
|
|
72
|
+
: 'manual=missing (toolset availability is unaffected; this is a team-management gap, so rely on each tool description/arguments and proceed)';
|
|
73
|
+
}
|
|
74
|
+
function renderMcpManualPresentBlock(language, serverId, manual) {
|
|
75
|
+
let out = `\n### toolset \`${serverId}\`\n`;
|
|
76
|
+
if (manual.contentFile && manual.contentFile.trim() !== '') {
|
|
77
|
+
out += fmtList([
|
|
78
|
+
language === 'zh'
|
|
79
|
+
? `运行时手册文件前缀(\`contentFile\`):\`${manual.contentFile}\``
|
|
80
|
+
: `Runtime manual file prefix (\`contentFile\`): \`${manual.contentFile}\``,
|
|
81
|
+
]);
|
|
82
|
+
if ((!manual.content || manual.content.trim() === '') && manual.sections.length === 0) {
|
|
83
|
+
out += fmtList([
|
|
84
|
+
language === 'zh'
|
|
85
|
+
? `该 toolset 的最终 \`man({ "toolsetId": "${serverId}" })\` 正文会在运行时从该前缀下的 topic 文件加载;这里不直接内嵌正文。`
|
|
86
|
+
: `The final \`man({ "toolsetId": "${serverId}" })\` body is loaded at runtime from topic files under this prefix; it is not inlined here.`,
|
|
87
|
+
]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (manual.content && manual.content.trim() !== '') {
|
|
91
|
+
out +=
|
|
92
|
+
fmtList([language === 'zh' ? '总说明(content):' : 'Overview (`content`):']) +
|
|
93
|
+
fmtCodeBlock('markdown', [manual.content]);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
out += fmtList([
|
|
97
|
+
language === 'zh' ? '总说明(content):(未提供)' : 'Overview (`content`): (not provided)',
|
|
98
|
+
]);
|
|
99
|
+
}
|
|
100
|
+
if (manual.sections.length > 0) {
|
|
101
|
+
for (const section of manual.sections) {
|
|
102
|
+
out +=
|
|
103
|
+
fmtList([language === 'zh' ? `章节:${section.title}` : `Section: ${section.title}`]) +
|
|
104
|
+
fmtCodeBlock('markdown', [section.content]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
out += fmtList([
|
|
109
|
+
language === 'zh' ? '章节(sections):(未提供)' : 'Sections (`sections`): (not provided)',
|
|
110
|
+
]);
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
function inferAutoGeneratedMcpIntentDirections(language, toolNames) {
|
|
115
|
+
const names = toolNames.map((name) => name.toLowerCase());
|
|
116
|
+
const out = [];
|
|
117
|
+
const pushUnique = (line) => {
|
|
118
|
+
if (!out.includes(line))
|
|
119
|
+
out.push(line);
|
|
120
|
+
};
|
|
121
|
+
const has = (needle) => names.some((name) => name.includes(needle));
|
|
122
|
+
if (has('browser') || has('page') || has('playwright') || has('screenshot')) {
|
|
123
|
+
pushUnique(language === 'zh'
|
|
124
|
+
? '网页/浏览器自动化:用于页面操作、采样、信息抓取与可视化回归辅助。'
|
|
125
|
+
: 'Web/browser automation: page actions, sampling, information extraction, and visual-regression assistance.');
|
|
126
|
+
}
|
|
127
|
+
if (has('git') || has('repo') || has('diff') || has('pr') || has('commit')) {
|
|
128
|
+
pushUnique(language === 'zh'
|
|
129
|
+
? '仓库协作与变更分析:用于读取仓库状态、比较差异、辅助代码审查。'
|
|
130
|
+
: 'Repository collaboration and change analysis: inspect repo state, compare diffs, and support review workflows.');
|
|
131
|
+
}
|
|
132
|
+
if (has('sql') || has('db') || has('query') || has('table') || has('postgres')) {
|
|
133
|
+
pushUnique(language === 'zh'
|
|
134
|
+
? '数据查询/诊断:用于结构化检索与数据一致性排查。'
|
|
135
|
+
: 'Data query/diagnostics: structured retrieval and data-consistency investigation.');
|
|
136
|
+
}
|
|
137
|
+
if (has('k8s') || has('kubectl') || has('deploy') || has('cluster') || has('helm')) {
|
|
138
|
+
pushUnique(language === 'zh'
|
|
139
|
+
? '部署与运行状态诊断:用于集群状态检查、发布过程观测与故障定位。'
|
|
140
|
+
: 'Deployment/runtime diagnostics: cluster-state checks, release observation, and incident localization.');
|
|
141
|
+
}
|
|
142
|
+
if (has('ticket') || has('issue') || has('jira') || has('linear')) {
|
|
143
|
+
pushUnique(language === 'zh'
|
|
144
|
+
? '任务流转协作:用于工单读取、状态同步与流程追踪。'
|
|
145
|
+
: 'Ticket/workflow collaboration: ticket lookup, state synchronization, and process tracking.');
|
|
146
|
+
}
|
|
147
|
+
if (out.length === 0) {
|
|
148
|
+
out.push(language === 'zh'
|
|
149
|
+
? '未识别出明确领域特征:建议按工具 description/参数逐个确认用途,并与人类用户共同定义边界。'
|
|
150
|
+
: 'No clear domain signature detected: review each tool description/arguments and define boundaries jointly with the human user.');
|
|
151
|
+
}
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
function renderAutoGeneratedMcpManualDraftSection(language, entry) {
|
|
155
|
+
const lines = [];
|
|
156
|
+
const statusText = entry.status === 'registered'
|
|
157
|
+
? language === 'zh'
|
|
158
|
+
? '已加载'
|
|
159
|
+
: 'loaded'
|
|
160
|
+
: entry.status === 'declared_unloaded'
|
|
161
|
+
? language === 'zh'
|
|
162
|
+
? '已声明但未加载'
|
|
163
|
+
: 'declared but not loaded'
|
|
164
|
+
: language === 'zh'
|
|
165
|
+
? '声明无效'
|
|
166
|
+
: 'invalid declaration';
|
|
167
|
+
const transportText = entry.transport === 'invalid' ? 'invalid' : entry.transport === 'stdio' ? 'stdio' : 'http';
|
|
168
|
+
lines.push(`\n### toolset \`${entry.serverId}\``);
|
|
169
|
+
lines.push(...fmtList([
|
|
170
|
+
language === 'zh'
|
|
171
|
+
? '检测到 `servers.<serverId>.manual` 缺失,以下为自动生成的基础手册草稿(供临时使用)。'
|
|
172
|
+
: '`servers.<serverId>.manual` is missing. Below is an auto-generated baseline manual draft (temporary use).',
|
|
173
|
+
language === 'zh'
|
|
174
|
+
? `运行时状态:status=${statusText},transport=${transportText}。`
|
|
175
|
+
: `Runtime status: status=${statusText}, transport=${transportText}.`,
|
|
176
|
+
language === 'zh'
|
|
177
|
+
? '关键提醒:该草稿不等于最终规范。团队管理者必须与人类用户确认本 rtws 的真实意图后,再写入更准确的正式手册。'
|
|
178
|
+
: '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.',
|
|
179
|
+
])
|
|
180
|
+
.trimEnd()
|
|
181
|
+
.split('\n'));
|
|
182
|
+
lines.push(...fmtList([
|
|
183
|
+
language === 'zh'
|
|
184
|
+
? '章节:tools 列表(运行时快照)'
|
|
185
|
+
: 'Section: Tools list (runtime snapshot)',
|
|
186
|
+
])
|
|
187
|
+
.trimEnd()
|
|
188
|
+
.split('\n'));
|
|
189
|
+
if ((entry.loadedToolNames?.length ?? 0) > 0) {
|
|
190
|
+
const tools = entry.loadedToolNames ?? [];
|
|
191
|
+
lines.push(...fmtCodeBlock('text', tools.map((tool) => `- ${tool}`))
|
|
192
|
+
.trimEnd()
|
|
193
|
+
.split('\n'));
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
lines.push(...fmtList([
|
|
197
|
+
language === 'zh'
|
|
198
|
+
? '当前无法给出已加载 tools 清单(通常因为该 server 尚未加载)。先运行 `team_mgmt_validate_mcp_cfg({})`,必要时再 `mcp_restart`。'
|
|
199
|
+
: '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.',
|
|
200
|
+
])
|
|
201
|
+
.trimEnd()
|
|
202
|
+
.split('\n'));
|
|
203
|
+
}
|
|
204
|
+
lines.push(...fmtList([
|
|
205
|
+
language === 'zh'
|
|
206
|
+
? '章节:主要意图方向(自动推测,待确认)'
|
|
207
|
+
: 'Section: Primary intent directions (auto-inferred, pending confirmation)',
|
|
208
|
+
])
|
|
209
|
+
.trimEnd()
|
|
210
|
+
.split('\n'));
|
|
211
|
+
lines.push(...fmtList(inferAutoGeneratedMcpIntentDirections(language, entry.loadedToolNames ?? []))
|
|
212
|
+
.trimEnd()
|
|
213
|
+
.split('\n'));
|
|
214
|
+
lines.push(...fmtList([
|
|
215
|
+
language === 'zh'
|
|
216
|
+
? '团队管理者后续动作:精读每个工具说明 -> 与人类用户确认意图与边界 -> 明确不可用时是找谁协调、允许哪些降级路径、哪些动作必须暂停 -> 先把正式手册写到 `servers.<serverId>.manual.contentFile`,若还需团队管理补充说明,再追加 inline `content + sections`。'
|
|
217
|
+
: 'Team-manager follow-up: read each tool description carefully -> confirm intent/boundaries with the human user -> decide who coordinates when unavailable, which fallbacks are allowed, and which actions must pause -> put the formal manual in `servers.<serverId>.manual.contentFile` first, then add inline `content + sections` only if extra team-management guidance is still needed.',
|
|
218
|
+
])
|
|
219
|
+
.trimEnd()
|
|
220
|
+
.split('\n'));
|
|
221
|
+
return lines.join('\n') + '\n';
|
|
222
|
+
}
|
|
223
|
+
function renderMcpToolsetManualDetailsSection(language, snapshot) {
|
|
224
|
+
const header = language === 'zh'
|
|
225
|
+
? fmtSubHeader('MCP toolset 手册(来自 `.minds/mcp.yaml` 的 `servers.<serverId>.manual`)')
|
|
226
|
+
: fmtSubHeader('MCP Toolset Manuals (from `.minds/mcp.yaml` `servers.<serverId>.manual`)');
|
|
227
|
+
if (snapshot.kind !== 'loaded')
|
|
228
|
+
return '';
|
|
229
|
+
const entries = snapshot.entries;
|
|
230
|
+
if (entries.length === 0) {
|
|
231
|
+
return (header +
|
|
232
|
+
fmtList([
|
|
233
|
+
language === 'zh'
|
|
234
|
+
? '当前没有 MCP toolset 可展示。'
|
|
235
|
+
: 'There are currently no MCP toolsets to display.',
|
|
236
|
+
]));
|
|
237
|
+
}
|
|
238
|
+
let out = header +
|
|
239
|
+
fmtList([
|
|
240
|
+
language === 'zh'
|
|
241
|
+
? '若 `servers.<serverId>.manual` 已配置,这里会展示其 inline 说明或 `contentFile` 路径信息;若缺失,则自动生成基础草稿(含 tools 列表与意图方向草稿)供临时使用。'
|
|
242
|
+
: 'If `servers.<serverId>.manual` is configured, this section shows the inline guidance and/or the `contentFile` path information; if missing, an auto-generated baseline draft (including tools list and intent directions draft) is provided for temporary use.',
|
|
243
|
+
]);
|
|
244
|
+
for (const entry of entries) {
|
|
245
|
+
if (entry.manualState.kind === 'missing') {
|
|
246
|
+
out += renderAutoGeneratedMcpManualDraftSection(language, entry);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (entry.manualState.kind === 'invalid') {
|
|
250
|
+
out += `\n### toolset \`${entry.serverId}\`\n`;
|
|
251
|
+
out += fmtList([
|
|
252
|
+
language === 'zh'
|
|
253
|
+
? `\`servers.${entry.serverId}.manual\` 声明无效:${firstNonEmptyLine(entry.manualState.errorText)}`
|
|
254
|
+
: `\`servers.${entry.serverId}.manual\` is invalid: ${firstNonEmptyLine(entry.manualState.errorText)}`,
|
|
255
|
+
language === 'zh'
|
|
256
|
+
? '这不影响 toolset 可用性;请根据工具说明继续使用,并通知团队管理者修复手册字段。'
|
|
257
|
+
: 'Toolset availability is unaffected; continue by tool-level descriptions and ask the team manager to fix the manual field.',
|
|
258
|
+
]);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (entry.manualState.kind !== 'present')
|
|
262
|
+
continue;
|
|
263
|
+
const manual = entry.manualState.manual;
|
|
264
|
+
out += renderMcpManualPresentBlock(language, entry.serverId, manual);
|
|
265
|
+
}
|
|
266
|
+
return out;
|
|
267
|
+
}
|
|
268
|
+
async function readMcpToolsetMappingSnapshot() {
|
|
269
|
+
const mcpAbsPath = path_1.default.resolve(process.cwd(), MCP_YAML_REL);
|
|
270
|
+
let rawText;
|
|
271
|
+
try {
|
|
272
|
+
rawText = await promises_1.default.readFile(mcpAbsPath, 'utf8');
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
if (isFsErrWithCode(err) && err.code === 'ENOENT') {
|
|
276
|
+
return { kind: 'missing' };
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
kind: 'invalid_yaml',
|
|
280
|
+
errorText: err instanceof Error ? err.message : String(err),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const parsed = (0, config_1.parseMcpYaml)(rawText);
|
|
284
|
+
if (!parsed.ok) {
|
|
285
|
+
return { kind: 'invalid_yaml', errorText: parsed.errorText };
|
|
286
|
+
}
|
|
287
|
+
const manualInfo = (0, manual_problems_1.parseMcpManualByServer)(rawText);
|
|
288
|
+
const registeredToolsets = (0, registry_1.listToolsets)();
|
|
289
|
+
const invalidByServerId = new Map();
|
|
290
|
+
for (const invalid of parsed.invalidServers) {
|
|
291
|
+
invalidByServerId.set(invalid.serverId, invalid.errorText);
|
|
292
|
+
}
|
|
293
|
+
const entries = [];
|
|
294
|
+
for (const serverId of parsed.serverIdsInYamlOrder) {
|
|
295
|
+
const invalidError = invalidByServerId.get(serverId);
|
|
296
|
+
const manualError = manualInfo.invalidByServerId.get(serverId);
|
|
297
|
+
const manual = manualInfo.manualByServerId.get(serverId);
|
|
298
|
+
const manualState = manualError
|
|
299
|
+
? { kind: 'invalid', errorText: manualError }
|
|
300
|
+
: manual
|
|
301
|
+
? { kind: 'present', manual }
|
|
302
|
+
: { kind: 'missing' };
|
|
303
|
+
if (invalidError) {
|
|
304
|
+
entries.push({
|
|
305
|
+
serverId,
|
|
306
|
+
transport: 'invalid',
|
|
307
|
+
status: 'declared_invalid',
|
|
308
|
+
errorText: invalidError,
|
|
309
|
+
manualState,
|
|
310
|
+
});
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
const transport = parsed.config.servers[serverId]?.transport ?? 'invalid';
|
|
314
|
+
const loadedTools = registeredToolsets[serverId];
|
|
315
|
+
if (loadedTools) {
|
|
316
|
+
const loadedToolNames = loadedTools.map((t) => t.name);
|
|
317
|
+
entries.push({
|
|
318
|
+
serverId,
|
|
319
|
+
transport,
|
|
320
|
+
status: 'registered',
|
|
321
|
+
loadedToolCount: loadedTools.length,
|
|
322
|
+
loadedToolNames,
|
|
323
|
+
loadedToolNamesPreview: loadedToolNames.slice(0, 6),
|
|
324
|
+
manualState,
|
|
325
|
+
});
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
entries.push({
|
|
329
|
+
serverId,
|
|
330
|
+
transport,
|
|
331
|
+
status: 'declared_unloaded',
|
|
332
|
+
manualState,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
return { kind: 'loaded', entries };
|
|
336
|
+
}
|
|
337
|
+
function renderMcpToolsetMappingSection(language, snapshot) {
|
|
338
|
+
const header = language === 'zh'
|
|
339
|
+
? fmtSubHeader('MCP serverId -> toolset 当前映射(动态读取 .minds/mcp.yaml)')
|
|
340
|
+
: fmtSubHeader('Current MCP serverId -> toolset mapping (from .minds/mcp.yaml)');
|
|
341
|
+
if (snapshot.kind === 'missing') {
|
|
342
|
+
const items = language === 'zh'
|
|
343
|
+
? [
|
|
344
|
+
`未发现 \`${MCP_YAML_REL}\`;当前没有可映射的 MCP toolset。`,
|
|
345
|
+
`设置方法:在 \`${MCP_YAML_REL}\` 增加 \`servers.<serverId>\`,该 \`serverId\` 会映射为同名 toolset。`,
|
|
346
|
+
]
|
|
347
|
+
: [
|
|
348
|
+
`\`${MCP_YAML_REL}\` not found; there are currently no MCP toolsets to map.`,
|
|
349
|
+
`Setup rule: add \`servers.<serverId>\` in \`${MCP_YAML_REL}\`; that \`serverId\` maps to a toolset with the same name.`,
|
|
350
|
+
];
|
|
351
|
+
return header + fmtList(items);
|
|
352
|
+
}
|
|
353
|
+
if (snapshot.kind === 'invalid_yaml') {
|
|
354
|
+
const items = language === 'zh'
|
|
355
|
+
? [
|
|
356
|
+
`\`${MCP_YAML_REL}\` 解析失败,暂时无法生成 serverId -> toolset 映射。`,
|
|
357
|
+
`错误:${firstNonEmptyLine(snapshot.errorText)}`,
|
|
358
|
+
'先运行 `team_mgmt_validate_mcp_cfg({})` 修复配置,再查看映射。',
|
|
359
|
+
]
|
|
360
|
+
: [
|
|
361
|
+
`Failed to parse \`${MCP_YAML_REL}\`; cannot build serverId -> toolset mapping yet.`,
|
|
362
|
+
`Error: ${firstNonEmptyLine(snapshot.errorText)}`,
|
|
363
|
+
'Run `team_mgmt_validate_mcp_cfg({})` first, then re-check mapping.',
|
|
364
|
+
];
|
|
365
|
+
return header + fmtList(items);
|
|
366
|
+
}
|
|
367
|
+
if (snapshot.entries.length === 0) {
|
|
368
|
+
const items = language === 'zh'
|
|
369
|
+
? [
|
|
370
|
+
`\`${MCP_YAML_REL}\` 已存在,但 \`servers\` 为空;当前没有 MCP toolset。`,
|
|
371
|
+
'添加 `servers.<serverId>` 后,对应 `serverId` 会映射为同名 toolset。',
|
|
372
|
+
]
|
|
373
|
+
: [
|
|
374
|
+
`\`${MCP_YAML_REL}\` exists but \`servers\` is empty; there are currently no MCP toolsets.`,
|
|
375
|
+
'After adding `servers.<serverId>`, that `serverId` maps to a same-name toolset.',
|
|
376
|
+
];
|
|
377
|
+
return header + fmtList(items);
|
|
378
|
+
}
|
|
379
|
+
const lines = [];
|
|
380
|
+
for (const entry of snapshot.entries) {
|
|
381
|
+
const transportText = entry.transport === 'invalid' ? 'invalid' : entry.transport === 'stdio' ? 'stdio' : 'http';
|
|
382
|
+
const manualText = describeMcpManualState(language, entry.manualState);
|
|
383
|
+
if (entry.status === 'registered') {
|
|
384
|
+
const preview = entry.loadedToolNamesPreview ?? [];
|
|
385
|
+
const previewText = preview.length > 0
|
|
386
|
+
? preview.join(', ') +
|
|
387
|
+
(entry.loadedToolCount !== undefined && entry.loadedToolCount > preview.length
|
|
388
|
+
? ', ...'
|
|
389
|
+
: '')
|
|
390
|
+
: '(none)';
|
|
391
|
+
lines.push(language === 'zh'
|
|
392
|
+
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(transport=${transportText},状态=已加载,tools=${entry.loadedToolCount ?? 0}:${previewText};${manualText})`
|
|
393
|
+
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (transport=${transportText}, status=loaded, tools=${entry.loadedToolCount ?? 0}: ${previewText}; ${manualText})`);
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (entry.status === 'declared_unloaded') {
|
|
397
|
+
lines.push(language === 'zh'
|
|
398
|
+
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(transport=${transportText},状态=已声明但未加载;${manualText})`
|
|
399
|
+
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (transport=${transportText}, status=declared but not loaded; ${manualText})`);
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
lines.push(language === 'zh'
|
|
403
|
+
? `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\`(状态=声明无效:${firstNonEmptyLine(entry.errorText ?? '')};${manualText})`
|
|
404
|
+
: `\`servers.${entry.serverId}\` -> toolset \`${entry.serverId}\` (status=invalid declaration: ${firstNonEmptyLine(entry.errorText ?? '')}; ${manualText})`);
|
|
405
|
+
}
|
|
406
|
+
const tail = language === 'zh'
|
|
407
|
+
? [
|
|
408
|
+
'说明:`已声明但未加载` 通常表示当前会话尚未完成 MCP 重载,或 server 启动失败。',
|
|
409
|
+
'说明:MCP toolset “没有 manual” 不等于“不可用”。无 manual 仅表示团队管理者没有提供章节化手册;你应继续阅读每个工具的 description/参数并谨慎使用。',
|
|
410
|
+
'建议:运行 `team_mgmt_validate_mcp_cfg({})`,必要时执行 `mcp_restart`。',
|
|
411
|
+
]
|
|
412
|
+
: [
|
|
413
|
+
'`declared but not loaded` usually means MCP reload has not completed in the current session, or server startup failed.',
|
|
414
|
+
'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.',
|
|
415
|
+
'Recommendation: run `team_mgmt_validate_mcp_cfg({})`, then `mcp_restart` if needed.',
|
|
416
|
+
];
|
|
417
|
+
return header + fmtList(lines.concat(tail));
|
|
418
|
+
}
|
|
419
|
+
function renderMcpToolsetSetupGuideSection(language, snapshot) {
|
|
420
|
+
const title = language === 'zh'
|
|
421
|
+
? fmtSubHeader('MCP toolset 设置方法与示例')
|
|
422
|
+
: fmtSubHeader('How To Set Up MCP Toolsets (with example)');
|
|
423
|
+
const fallbackServerId = 'your_mcp_server';
|
|
424
|
+
const exampleServerId = snapshot.kind === 'loaded' && snapshot.entries.length > 0
|
|
425
|
+
? (snapshot.entries[0]?.serverId ?? fallbackServerId)
|
|
426
|
+
: fallbackServerId;
|
|
427
|
+
const exampleTransport = snapshot.kind === 'loaded'
|
|
428
|
+
? (snapshot.entries.find((e) => e.transport !== 'invalid')?.transport ?? 'stdio')
|
|
429
|
+
: 'stdio';
|
|
430
|
+
const notes = language === 'zh'
|
|
431
|
+
? fmtList([
|
|
432
|
+
`步骤 1:在 \`${MCP_YAML_REL}\` 声明 \`servers.${exampleServerId}\`。`,
|
|
433
|
+
`步骤 2:在 \`${TEAM_YAML_REL}\` 的 \`members.<id>.toolsets\` 添加 \`${exampleServerId}\`。`,
|
|
434
|
+
'规则:MCP toolset 名称恒等于 `serverId`(不加前缀)。',
|
|
435
|
+
])
|
|
436
|
+
: fmtList([
|
|
437
|
+
`Step 1: declare \`servers.${exampleServerId}\` in \`${MCP_YAML_REL}\`.`,
|
|
438
|
+
`Step 2: add \`${exampleServerId}\` under \`members.<id>.toolsets\` in \`${TEAM_YAML_REL}\`.`,
|
|
439
|
+
'Rule: MCP toolset name is exactly the `serverId` (no prefix).',
|
|
440
|
+
]);
|
|
441
|
+
const mcpExample = exampleTransport === 'streamable_http'
|
|
442
|
+
? fmtCodeBlock('yaml', [
|
|
443
|
+
'# .minds/mcp.yaml',
|
|
444
|
+
'version: 1',
|
|
445
|
+
'servers:',
|
|
446
|
+
` ${exampleServerId}:`,
|
|
447
|
+
' truely-stateless: false',
|
|
448
|
+
' transport: streamable_http',
|
|
449
|
+
' url: http://127.0.0.1:3000/mcp',
|
|
450
|
+
' tools: { whitelist: [], blacklist: [] }',
|
|
451
|
+
' transform: []',
|
|
452
|
+
])
|
|
453
|
+
: fmtCodeBlock('yaml', [
|
|
454
|
+
'# .minds/mcp.yaml',
|
|
455
|
+
'version: 1',
|
|
456
|
+
'servers:',
|
|
457
|
+
` ${exampleServerId}:`,
|
|
458
|
+
' truely-stateless: false',
|
|
459
|
+
' transport: stdio',
|
|
460
|
+
' command: npx',
|
|
461
|
+
" args: ['-y', '@some/mcp-server@latest']",
|
|
462
|
+
' tools: { whitelist: [], blacklist: [] }',
|
|
463
|
+
' transform: []',
|
|
464
|
+
]);
|
|
465
|
+
const teamExample = fmtCodeBlock('yaml', [
|
|
466
|
+
'# .minds/team.yaml',
|
|
467
|
+
'members:',
|
|
468
|
+
' operator:',
|
|
469
|
+
' toolsets:',
|
|
470
|
+
' - ws_read',
|
|
471
|
+
` - ${exampleServerId}`,
|
|
472
|
+
]);
|
|
473
|
+
return title + notes + mcpExample + teamExample;
|
|
474
|
+
}
|
|
475
|
+
async function renderMcpManual(language) {
|
|
476
|
+
const mcpSnapshot = await readMcpToolsetMappingSnapshot();
|
|
477
|
+
const mcpMapping = renderMcpToolsetMappingSection(language, mcpSnapshot);
|
|
478
|
+
const mcpSetup = renderMcpToolsetSetupGuideSection(language, mcpSnapshot);
|
|
479
|
+
const mcpManualDetails = renderMcpToolsetManualDetailsSection(language, mcpSnapshot);
|
|
480
|
+
if (language === 'zh') {
|
|
481
|
+
return (fmtHeader('.minds/mcp.yaml') +
|
|
482
|
+
fmtList([
|
|
483
|
+
'每个 MCP `serverId` 注册一个 toolset,toolset 名称 = `serverId`(不加 `mcp_` 前缀)。成员通过 `members.<id>.toolsets` 选择能用哪些 MCP toolset。',
|
|
484
|
+
'支持热重载:编辑 `.minds/mcp.yaml` 后通常无需重启 Dominds;必要时用 `mcp_restart`。',
|
|
485
|
+
'默认按“每个对话租用一个 MCP client”运行(更安全):首次使用该 toolset 会产生 sticky reminder,完成后用 `mcp_release` 释放;如确实是无状态服务器,可配置 `truely-stateless: true` 允许跨对话共享。',
|
|
486
|
+
'stdio 配置格式:`command` 必须是字符串(可执行命令),参数放在 `args`(string[],可省略,默认空数组)。`cwd` 可选(字符串):用于固定相对路径解析目录。',
|
|
487
|
+
'用 `tools.whitelist/blacklist` 控制暴露的工具,用 `transform` 做命名变换。',
|
|
488
|
+
'常见坑:stdio transport 需要可执行命令路径正确,且受成员权限(目录 + 扩展名:`*_dirs/no_*_dirs/*_file_ext_names/no_*_file_ext_names`)约束;HTTP transport 需要服务可达(url/端口/网络)。',
|
|
489
|
+
'高频坑(stdio 路径):若未设置 `cwd`,相对路径按 Dominds 进程工作目录(通常 rtws 根目录)解析;建议显式配置 `cwd` 或直接使用绝对路径。`cwd` 必须存在且是目录。',
|
|
490
|
+
'可选手册字段:你可以在 `servers.<serverId>.manual` 放手册内容。',
|
|
491
|
+
'如果你要控制最终 `man({ "toolsetId": "<serverId>" })` 给 LLM 看的正式手册,请使用 `manual.contentFile` 指向 topic 文件目录前缀。',
|
|
492
|
+
'如果你只是想在 `team_mgmt` 的 MCP 章节里补充团队管理说明,也可以使用 inline `content`(总说明)+ `sections`(章节列表)。这类 inline 内容会展示在 `team_mgmt` 指南里,但不会替代运行时 `contentFile` 手册。',
|
|
493
|
+
'重要:`manual` 缺失并不代表 MCP toolset 不可用;这只是团队管理工作不足。智能体应继续依据每个工具 description/参数自行判断并使用。',
|
|
494
|
+
'团队管理者建议:配置并验证 MCP 后,应先精读该 server 暴露的每个工具 description/参数,再与人类用户讨论本 rtws 中这些工具的使用意图,然后把正式手册沉淀到 `manual.contentFile`;若还需要在团队管理层额外解释业务边界,可再补 inline `content + sections`。',
|
|
495
|
+
'章节组织建议采用“半结构化”:可优先考虑 `何时使用`、`安全边界`、`不可用时业务处置` 这类高价值章节,但不要求所有 toolset 都照抄同一模板。应从真实业务目标出发,决定哪些章节需要展开、哪些只需一句话、哪些可以合并或另起更贴切的标题。',
|
|
496
|
+
'对每个 MCP toolset,团队管理者仍应刻意写明“不可用时业务处置规约”:至少回答 1) 当前 toolset 暂不可达时是否必须找协调者/专员接手;2) 是否允许走人工或其他工具链降级路径;3) 哪些业务动作在该 toolset 恢复前必须暂停,禁止擅自继续。',
|
|
497
|
+
'最小诊断流程(建议顺序):1) 先用 `team_mgmt_check_provider({ provider_key: "<providerKey>", model: "", all_models: false, live: false })` 确认 LLM provider 可用;2) 再检查该成员的目录权限(`man({ "toolsetId": "team_mgmt", "topics": ["permissions"] })`);3) 运行 `team_mgmt_validate_mcp_cfg({})` 汇总 `.minds/mcp.yaml` 与 MCP 问题;4) 必要时 `mcp_restart`,用完记得 `mcp_release`。',
|
|
498
|
+
]) +
|
|
499
|
+
fmtCodeBlock('yaml', [
|
|
500
|
+
'# 最小模板(stdio)',
|
|
501
|
+
'version: 1',
|
|
502
|
+
'servers:',
|
|
503
|
+
' sdk_stdio:',
|
|
504
|
+
' truely-stateless: false',
|
|
505
|
+
' transport: stdio',
|
|
506
|
+
' command: npx',
|
|
507
|
+
" args: ['-y', '@some/mcp-server@latest']",
|
|
508
|
+
' cwd: "."',
|
|
509
|
+
' env: {}',
|
|
510
|
+
' tools: { whitelist: [], blacklist: [] }',
|
|
511
|
+
' transform: []',
|
|
512
|
+
' manual:',
|
|
513
|
+
' content: |',
|
|
514
|
+
' 这个 MCP toolset 负责 xx,优先用于 xx 场景。',
|
|
515
|
+
' sections:',
|
|
516
|
+
" - title: '何时使用'",
|
|
517
|
+
' content: |',
|
|
518
|
+
' 1) 当你需要 ...',
|
|
519
|
+
' 2) 执行前先确认 ...',
|
|
520
|
+
" - title: '安全边界'",
|
|
521
|
+
' content: |',
|
|
522
|
+
' - 不要用于 ...',
|
|
523
|
+
' - 若失败先看 ...',
|
|
524
|
+
" - title: '不可用时业务处置'",
|
|
525
|
+
' content: |',
|
|
526
|
+
' - 若该 toolset 暂时不可达,先找 @coordinator(或指定协调者)确认是否改走降级路径。',
|
|
527
|
+
' - 仅允许改用 ... 作为临时替代;若涉及 ...,必须等待该 MCP 恢复,不可继续。',
|
|
528
|
+
]) +
|
|
529
|
+
fmtCodeBlock('yaml', [
|
|
530
|
+
'# stdio 路径示例(最小)',
|
|
531
|
+
'# 相对路径:配合 cwd 固定解析目录',
|
|
532
|
+
'command: node',
|
|
533
|
+
"args: ['./mcp/server.js']",
|
|
534
|
+
'cwd: "/absolute/path/to/project"',
|
|
535
|
+
'',
|
|
536
|
+
'# 绝对路径:更稳,不依赖 cwd',
|
|
537
|
+
'command: node',
|
|
538
|
+
"args: ['/absolute/path/to/mcp/server.js']",
|
|
539
|
+
]) +
|
|
540
|
+
fmtCodeBlock('yaml', [
|
|
541
|
+
'# 最小模板(HTTP)',
|
|
542
|
+
'version: 1',
|
|
543
|
+
'servers:',
|
|
544
|
+
' sdk_http:',
|
|
545
|
+
' truely-stateless: false',
|
|
546
|
+
' transport: streamable_http',
|
|
547
|
+
' url: http://127.0.0.1:3000/mcp',
|
|
548
|
+
' tools: { whitelist: [], blacklist: [] }',
|
|
549
|
+
' transform: []',
|
|
550
|
+
' manual:',
|
|
551
|
+
' content: "用于远端 MCP 接口调用"',
|
|
552
|
+
' sections:',
|
|
553
|
+
" UseCases: '适用于 ...'",
|
|
554
|
+
" Guardrails: '避免 ...'",
|
|
555
|
+
]) +
|
|
556
|
+
mcpMapping +
|
|
557
|
+
mcpSetup +
|
|
558
|
+
mcpManualDetails);
|
|
559
|
+
}
|
|
560
|
+
return (fmtHeader('.minds/mcp.yaml') +
|
|
561
|
+
fmtList([
|
|
562
|
+
'Each MCP `serverId` registers one toolset, and the toolset name is exactly `serverId` (no `mcp_` prefix). Members choose MCP access via `members.<id>.toolsets`.',
|
|
563
|
+
'Hot reload: edits usually apply without restarting Dominds; use `mcp_restart` when needed.',
|
|
564
|
+
"Default is per-dialog MCP client leasing (safer): first use adds a sticky reminder; call `mcp_release` when you're sure you won't need the toolset soon. If the server is truly stateless, set `truely-stateless: true` to allow cross-dialog sharing.",
|
|
565
|
+
'Stdio shape: `command` must be a string executable; parameters go in `args` (string[], optional, defaults to empty). Optional `cwd` (string) fixes the working directory used for relative paths.',
|
|
566
|
+
'Use `tools.whitelist/blacklist` for exposure control and `transform` for naming transforms.',
|
|
567
|
+
'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.',
|
|
568
|
+
'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.',
|
|
569
|
+
'Optional manual field: place guide text at `servers.<serverId>.manual`.',
|
|
570
|
+
'To control the final formal manual shown to the LLM by `man({ "toolsetId": "<serverId>" })`, use `manual.contentFile` and point it at the topic-file directory prefix.',
|
|
571
|
+
'If you only want extra team-management guidance inside the `team_mgmt` MCP chapter, you may also use inline `content` (overview) + `sections` (chapter list). That inline content is shown in the `team_mgmt` guide, but it does not replace runtime `contentFile` manuals.',
|
|
572
|
+
'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.',
|
|
573
|
+
'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 the formal manual into `manual.contentFile`; if extra team-management interpretation is still useful, add inline `content + sections` alongside it.',
|
|
574
|
+
'Use a semi-structured chapter shape: high-value sections often include `When To Use`, `Guardrails`, and `Business Handling When Unavailable`, but do not force every toolset into one fixed template. Start from the real business goal, then decide which sections deserve depth, which can stay brief, and which should be merged or renamed to fit the scenario.',
|
|
575
|
+
'For each MCP toolset, still document unavailable-case business rules explicitly: at minimum answer 1) whether a temporarily unavailable toolset must be escalated to a coordinator or specialist, 2) whether a manual or alternate-tool fallback path is allowed, and 3) which business actions must pause until this toolset recovers.',
|
|
576
|
+
'Minimal diagnostic flow: 1) run `team_mgmt_check_provider({ provider_key: "<providerKey>", model: "", all_models: false, live: false })` to confirm the LLM provider works; 2) review member directory permissions (`man({ "toolsetId": "team_mgmt", "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.',
|
|
577
|
+
]) +
|
|
578
|
+
fmtCodeBlock('yaml', [
|
|
579
|
+
'# Minimal template (stdio)',
|
|
580
|
+
'version: 1',
|
|
581
|
+
'servers:',
|
|
582
|
+
' sdk_stdio:',
|
|
583
|
+
' truely-stateless: false',
|
|
584
|
+
' transport: stdio',
|
|
585
|
+
' command: npx',
|
|
586
|
+
" args: ['-y', '@some/mcp-server@latest']",
|
|
587
|
+
' cwd: "."',
|
|
588
|
+
' env: {}',
|
|
589
|
+
' tools: { whitelist: [], blacklist: [] }',
|
|
590
|
+
' transform: []',
|
|
591
|
+
' manual:',
|
|
592
|
+
' content: |',
|
|
593
|
+
' This MCP toolset is for xx and should be preferred in xx cases.',
|
|
594
|
+
' sections:',
|
|
595
|
+
" - title: 'When To Use'",
|
|
596
|
+
' content: |',
|
|
597
|
+
' 1) Use when ...',
|
|
598
|
+
' 2) Confirm ... before execution.',
|
|
599
|
+
" - title: 'Guardrails'",
|
|
600
|
+
' content: |',
|
|
601
|
+
' - Avoid using for ...',
|
|
602
|
+
' - On failures, first inspect ...',
|
|
603
|
+
" - title: 'Business Handling When Unavailable'",
|
|
604
|
+
' content: |',
|
|
605
|
+
' - If this toolset is temporarily unavailable, ask @coordinator (or the designated coordinator) whether to switch to the fallback path.',
|
|
606
|
+
' - Only use ... as an interim fallback; if the task touches ..., wait for this MCP to recover instead of proceeding.',
|
|
607
|
+
]) +
|
|
608
|
+
fmtCodeBlock('yaml', [
|
|
609
|
+
'# stdio path example (minimal)',
|
|
610
|
+
'# Relative path: stable with explicit cwd',
|
|
611
|
+
'command: node',
|
|
612
|
+
"args: ['./mcp/server.js']",
|
|
613
|
+
'cwd: "/absolute/path/to/project"',
|
|
614
|
+
'',
|
|
615
|
+
'# Absolute path: more stable, independent of cwd',
|
|
616
|
+
'command: node',
|
|
617
|
+
"args: ['/absolute/path/to/mcp/server.js']",
|
|
618
|
+
]) +
|
|
619
|
+
fmtCodeBlock('yaml', [
|
|
620
|
+
'# Minimal template (HTTP)',
|
|
621
|
+
'version: 1',
|
|
622
|
+
'servers:',
|
|
623
|
+
' sdk_http:',
|
|
624
|
+
' truely-stateless: false',
|
|
625
|
+
' transport: streamable_http',
|
|
626
|
+
' url: http://127.0.0.1:3000/mcp',
|
|
627
|
+
' tools: { whitelist: [], blacklist: [] }',
|
|
628
|
+
' transform: []',
|
|
629
|
+
' manual:',
|
|
630
|
+
' content: "For remote MCP endpoint calls"',
|
|
631
|
+
' sections:',
|
|
632
|
+
" UseCases: 'Use for ...'",
|
|
633
|
+
" Guardrails: 'Avoid ...'",
|
|
634
|
+
]) +
|
|
635
|
+
mcpMapping +
|
|
636
|
+
mcpSetup +
|
|
637
|
+
mcpManualDetails);
|
|
638
|
+
}
|
|
639
|
+
async function measureRenderedTeamMgmtMcpTopicRawChars() {
|
|
640
|
+
const zh = await renderMcpManual('zh');
|
|
641
|
+
const en = await renderMcpManual('en');
|
|
642
|
+
return Math.max(zh.length, en.length);
|
|
643
|
+
}
|