@zengjing/xmind-mcp 1.0.0
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/LICENSE +21 -0
- package/README.md +574 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +170 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/legacy-parser.d.ts +63 -0
- package/dist/core/legacy-parser.d.ts.map +1 -0
- package/dist/core/legacy-parser.js +139 -0
- package/dist/core/legacy-parser.js.map +1 -0
- package/dist/core/parser.d.ts +19 -0
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +111 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core/zen-parser.d.ts +15 -0
- package/dist/core/zen-parser.d.ts.map +1 -0
- package/dist/core/zen-parser.js +90 -0
- package/dist/core/zen-parser.js.map +1 -0
- package/dist/formatters/json-formatter.d.ts +69 -0
- package/dist/formatters/json-formatter.d.ts.map +1 -0
- package/dist/formatters/json-formatter.js +131 -0
- package/dist/formatters/json-formatter.js.map +1 -0
- package/dist/formatters/markdown-formatter.d.ts +40 -0
- package/dist/formatters/markdown-formatter.d.ts.map +1 -0
- package/dist/formatters/markdown-formatter.js +136 -0
- package/dist/formatters/markdown-formatter.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/dist/model/schemas.d.ts +54 -0
- package/dist/model/schemas.d.ts.map +1 -0
- package/dist/model/schemas.js +64 -0
- package/dist/model/schemas.js.map +1 -0
- package/dist/model/types.d.ts +79 -0
- package/dist/model/types.d.ts.map +1 -0
- package/dist/model/types.js +6 -0
- package/dist/model/types.js.map +1 -0
- package/dist/tools/branch-tool.d.ts +20 -0
- package/dist/tools/branch-tool.d.ts.map +1 -0
- package/dist/tools/branch-tool.js +150 -0
- package/dist/tools/branch-tool.js.map +1 -0
- package/dist/tools/parse-tool.d.ts +27 -0
- package/dist/tools/parse-tool.d.ts.map +1 -0
- package/dist/tools/parse-tool.js +126 -0
- package/dist/tools/parse-tool.js.map +1 -0
- package/dist/tools/search-tool.d.ts +27 -0
- package/dist/tools/search-tool.d.ts.map +1 -0
- package/dist/tools/search-tool.js +179 -0
- package/dist/tools/search-tool.js.map +1 -0
- package/dist/utils/errors.d.ts +26 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +41 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/file-utils.d.ts +25 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +58 -0
- package/dist/utils/file-utils.js.map +1 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +23 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON formatter for XMind documents.
|
|
3
|
+
* Converts parsed XMind AST to compact/beautified JSON with token hints.
|
|
4
|
+
* Includes token estimation and structure summary functionality.
|
|
5
|
+
*/
|
|
6
|
+
import type { XMindNode, XMindParsedResult } from '../model/types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Converts a single XMind node to JSON-serializable object.
|
|
9
|
+
* Includes title, labels, markers, notes, href, and children recursively.
|
|
10
|
+
* @param node - The node to convert
|
|
11
|
+
* @returns JSON-serializable object representation of the node
|
|
12
|
+
*/
|
|
13
|
+
export declare function nodeToJSON(node: XMindNode): Record<string, unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* Token estimate result object with suggestion hints.
|
|
16
|
+
*/
|
|
17
|
+
export interface JSONTokenEstimate {
|
|
18
|
+
estimatedTokens: number;
|
|
19
|
+
characterCount: number;
|
|
20
|
+
hint?: string;
|
|
21
|
+
estimatedOriginalSize?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Estimates token count for JSON output.
|
|
25
|
+
* JSON typically has more overhead than Markdown due to keys and structure.
|
|
26
|
+
* Uses rough estimation: ~1 token per 3 characters for JSON.
|
|
27
|
+
* @param jsonString - The JSON string to estimate
|
|
28
|
+
* @returns Object with token estimate and any warnings/hints
|
|
29
|
+
*/
|
|
30
|
+
export declare function getJSONTokenEstimate(jsonString: string): JSONTokenEstimate;
|
|
31
|
+
/**
|
|
32
|
+
* Recursively counts the number of nodes in a tree.
|
|
33
|
+
* @param node - The root node
|
|
34
|
+
* @returns Total node count including the root
|
|
35
|
+
*/
|
|
36
|
+
export declare function countNodes(node: XMindNode): number;
|
|
37
|
+
/**
|
|
38
|
+
* Extracts the top N topics from the direct children of a node.
|
|
39
|
+
* @param node - The root node
|
|
40
|
+
* @param count - Number of top topics to extract
|
|
41
|
+
* @returns Array of top topic titles
|
|
42
|
+
*/
|
|
43
|
+
export declare function getTopTopics(node: XMindNode, count?: number): string[];
|
|
44
|
+
/**
|
|
45
|
+
* Structure summary for a single sheet.
|
|
46
|
+
*/
|
|
47
|
+
export interface SheetSummary {
|
|
48
|
+
id: string;
|
|
49
|
+
title: string;
|
|
50
|
+
topicCount: number;
|
|
51
|
+
topTopics: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Generates a compact summary of the XMind structure.
|
|
55
|
+
* Returns key metadata about each sheet including topic counts and top-level topics.
|
|
56
|
+
* @param result - The parsed XMind result
|
|
57
|
+
* @returns Array of sheet summaries
|
|
58
|
+
*/
|
|
59
|
+
export declare function getStructureSummary(result: XMindParsedResult): SheetSummary[];
|
|
60
|
+
/**
|
|
61
|
+
* Converts entire XMind parsed result to JSON format.
|
|
62
|
+
* Supports both compact and beautified (indented) output.
|
|
63
|
+
* Includes metadata and structure information.
|
|
64
|
+
* @param result - The parsed XMind result
|
|
65
|
+
* @param beautify - If true, indent JSON for readability (default: false for compact)
|
|
66
|
+
* @returns Complete JSON string
|
|
67
|
+
*/
|
|
68
|
+
export declare function xmindToJSON(result: XMindParsedResult, beautify?: boolean): string;
|
|
69
|
+
//# sourceMappingURL=json-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/json-formatter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAc,MAAM,mBAAmB,CAAC;AAElF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BnE;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAkB1E;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAQlD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM,EAAE,CAQzE;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,EAAE,CAO7E;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,QAAQ,GAAE,OAAe,GAAG,MAAM,CAqBxF"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON formatter for XMind documents.
|
|
3
|
+
* Converts parsed XMind AST to compact/beautified JSON with token hints.
|
|
4
|
+
* Includes token estimation and structure summary functionality.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Converts a single XMind node to JSON-serializable object.
|
|
8
|
+
* Includes title, labels, markers, notes, href, and children recursively.
|
|
9
|
+
* @param node - The node to convert
|
|
10
|
+
* @returns JSON-serializable object representation of the node
|
|
11
|
+
*/
|
|
12
|
+
export function nodeToJSON(node) {
|
|
13
|
+
const nodeObj = {
|
|
14
|
+
id: node.id,
|
|
15
|
+
title: node.title,
|
|
16
|
+
children: node.children.map(child => nodeToJSON(child)),
|
|
17
|
+
};
|
|
18
|
+
// Add optional fields only if they exist
|
|
19
|
+
if (node.note) {
|
|
20
|
+
nodeObj.note = node.note;
|
|
21
|
+
}
|
|
22
|
+
if (node.labels && node.labels.length > 0) {
|
|
23
|
+
nodeObj.labels = node.labels;
|
|
24
|
+
}
|
|
25
|
+
if (node.markers && node.markers.length > 0) {
|
|
26
|
+
nodeObj.markers = node.markers;
|
|
27
|
+
}
|
|
28
|
+
if (node.href) {
|
|
29
|
+
nodeObj.href = node.href;
|
|
30
|
+
}
|
|
31
|
+
if (node.position) {
|
|
32
|
+
nodeObj.position = node.position;
|
|
33
|
+
}
|
|
34
|
+
return nodeObj;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Estimates token count for JSON output.
|
|
38
|
+
* JSON typically has more overhead than Markdown due to keys and structure.
|
|
39
|
+
* Uses rough estimation: ~1 token per 3 characters for JSON.
|
|
40
|
+
* @param jsonString - The JSON string to estimate
|
|
41
|
+
* @returns Object with token estimate and any warnings/hints
|
|
42
|
+
*/
|
|
43
|
+
export function getJSONTokenEstimate(jsonString) {
|
|
44
|
+
const characterCount = jsonString.length;
|
|
45
|
+
// JSON has more overhead, estimate ~1 token per 3 characters (less efficient than markdown)
|
|
46
|
+
const estimatedTokens = Math.ceil(characterCount / 3);
|
|
47
|
+
const estimate = {
|
|
48
|
+
estimatedTokens,
|
|
49
|
+
characterCount,
|
|
50
|
+
};
|
|
51
|
+
// Add hint if content is large
|
|
52
|
+
if (estimatedTokens > 30000) {
|
|
53
|
+
estimate.hint = 'Very large JSON (>30k tokens). Consider using Markdown format for better token efficiency, or implement compression/chunking strategy.';
|
|
54
|
+
}
|
|
55
|
+
else if (estimatedTokens > 15000) {
|
|
56
|
+
estimate.hint = 'Large JSON content (>15k tokens). Markdown format would be more token-efficient for the same content.';
|
|
57
|
+
}
|
|
58
|
+
return estimate;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Recursively counts the number of nodes in a tree.
|
|
62
|
+
* @param node - The root node
|
|
63
|
+
* @returns Total node count including the root
|
|
64
|
+
*/
|
|
65
|
+
export function countNodes(node) {
|
|
66
|
+
let count = 1;
|
|
67
|
+
if (node.children && node.children.length > 0) {
|
|
68
|
+
for (const child of node.children) {
|
|
69
|
+
count += countNodes(child);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return count;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Extracts the top N topics from the direct children of a node.
|
|
76
|
+
* @param node - The root node
|
|
77
|
+
* @param count - Number of top topics to extract
|
|
78
|
+
* @returns Array of top topic titles
|
|
79
|
+
*/
|
|
80
|
+
export function getTopTopics(node, count = 5) {
|
|
81
|
+
const topTopics = [];
|
|
82
|
+
if (node.children && node.children.length > 0) {
|
|
83
|
+
for (let i = 0; i < Math.min(count, node.children.length); i++) {
|
|
84
|
+
topTopics.push(node.children[i].title);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return topTopics;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Generates a compact summary of the XMind structure.
|
|
91
|
+
* Returns key metadata about each sheet including topic counts and top-level topics.
|
|
92
|
+
* @param result - The parsed XMind result
|
|
93
|
+
* @returns Array of sheet summaries
|
|
94
|
+
*/
|
|
95
|
+
export function getStructureSummary(result) {
|
|
96
|
+
return result.sheets.map((sheet) => ({
|
|
97
|
+
id: sheet.id,
|
|
98
|
+
title: sheet.title,
|
|
99
|
+
topicCount: countNodes(sheet.rootTopic),
|
|
100
|
+
topTopics: getTopTopics(sheet.rootTopic, 5),
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Converts entire XMind parsed result to JSON format.
|
|
105
|
+
* Supports both compact and beautified (indented) output.
|
|
106
|
+
* Includes metadata and structure information.
|
|
107
|
+
* @param result - The parsed XMind result
|
|
108
|
+
* @param beautify - If true, indent JSON for readability (default: false for compact)
|
|
109
|
+
* @returns Complete JSON string
|
|
110
|
+
*/
|
|
111
|
+
export function xmindToJSON(result, beautify = false) {
|
|
112
|
+
const sheets = result.sheets.map((sheet) => ({
|
|
113
|
+
id: sheet.id,
|
|
114
|
+
title: sheet.title,
|
|
115
|
+
rootTopic: nodeToJSON(sheet.rootTopic),
|
|
116
|
+
relationships: sheet.relationships || [],
|
|
117
|
+
}));
|
|
118
|
+
const output = {
|
|
119
|
+
metadata: {
|
|
120
|
+
file: result.filePath,
|
|
121
|
+
format: result.meta?.formatVersion || 'unknown',
|
|
122
|
+
topicCount: result.meta?.topicCount || 0,
|
|
123
|
+
sheetCount: result.sheets.length,
|
|
124
|
+
parsedAt: result.meta?.parsedAt || new Date().toISOString(),
|
|
125
|
+
},
|
|
126
|
+
sheets,
|
|
127
|
+
};
|
|
128
|
+
const indent = beautify ? 2 : undefined;
|
|
129
|
+
return JSON.stringify(output, null, indent);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=json-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-formatter.js","sourceRoot":"","sources":["../../src/formatters/json-formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown formatter for XMind documents.
|
|
3
|
+
* Converts parsed XMind AST to token-efficient Markdown outline format.
|
|
4
|
+
* Supports metadata headers, relationships, and token estimation.
|
|
5
|
+
*/
|
|
6
|
+
import type { XMindNode, XMindParsedResult } from '../model/types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Escapes special Markdown characters to prevent formatting issues.
|
|
9
|
+
* @param text - Raw text that may contain markdown special characters
|
|
10
|
+
* @returns Escaped text safe for markdown output
|
|
11
|
+
*/
|
|
12
|
+
export declare function escapeMarkdown(text: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Converts a single XMind node and its children to Markdown list format.
|
|
15
|
+
* Handles title, labels, markers, notes, and href information.
|
|
16
|
+
* @param node - The node to convert
|
|
17
|
+
* @param depth - Current nesting depth (0 = root)
|
|
18
|
+
* @returns Markdown string with proper indentation
|
|
19
|
+
*/
|
|
20
|
+
export declare function nodeToMarkdown(node: XMindNode, depth?: number): string;
|
|
21
|
+
/**
|
|
22
|
+
* Estimates token count for markdown output.
|
|
23
|
+
* Uses rough estimation: ~1 token per 4 characters for English text.
|
|
24
|
+
* @param markdown - The markdown string to estimate
|
|
25
|
+
* @returns Object with token estimate and any warnings/hints
|
|
26
|
+
*/
|
|
27
|
+
export interface TokenEstimate {
|
|
28
|
+
estimatedTokens: number;
|
|
29
|
+
characterCount: number;
|
|
30
|
+
hint?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function getMarkdownTokenEstimate(markdown: string): TokenEstimate;
|
|
33
|
+
/**
|
|
34
|
+
* Converts entire XMind parsed result to markdown format with metadata header.
|
|
35
|
+
* Includes all sheets, relationships (if present), and token estimation.
|
|
36
|
+
* @param result - The parsed XMind result
|
|
37
|
+
* @returns Complete markdown document with headers and all content
|
|
38
|
+
*/
|
|
39
|
+
export declare function xmindToMarkdown(result: XMindParsedResult): string;
|
|
40
|
+
//# sourceMappingURL=markdown-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown-formatter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAqB,MAAM,mBAAmB,CAAC;AAEzF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBnD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM,CA2CzE;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAkBxE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAgDjE"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown formatter for XMind documents.
|
|
3
|
+
* Converts parsed XMind AST to token-efficient Markdown outline format.
|
|
4
|
+
* Supports metadata headers, relationships, and token estimation.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Escapes special Markdown characters to prevent formatting issues.
|
|
8
|
+
* @param text - Raw text that may contain markdown special characters
|
|
9
|
+
* @returns Escaped text safe for markdown output
|
|
10
|
+
*/
|
|
11
|
+
export function escapeMarkdown(text) {
|
|
12
|
+
return text
|
|
13
|
+
.replace(/\\/g, '\\\\')
|
|
14
|
+
.replace(/\*/g, '\\*')
|
|
15
|
+
.replace(/_/g, '\\_')
|
|
16
|
+
.replace(/\[/g, '\\[')
|
|
17
|
+
.replace(/\]/g, '\\]')
|
|
18
|
+
.replace(/\(/g, '\\(')
|
|
19
|
+
.replace(/\)/g, '\\)')
|
|
20
|
+
.replace(/#/g, '\\#')
|
|
21
|
+
.replace(/\+/g, '\\+')
|
|
22
|
+
.replace(/-/g, '\\-')
|
|
23
|
+
.replace(/\./g, '\\.')
|
|
24
|
+
.replace(/!/g, '\\!')
|
|
25
|
+
.replace(/</g, '\\<')
|
|
26
|
+
.replace(/>/g, '\\>')
|
|
27
|
+
.replace(/`/g, '\\`');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Converts a single XMind node and its children to Markdown list format.
|
|
31
|
+
* Handles title, labels, markers, notes, and href information.
|
|
32
|
+
* @param node - The node to convert
|
|
33
|
+
* @param depth - Current nesting depth (0 = root)
|
|
34
|
+
* @returns Markdown string with proper indentation
|
|
35
|
+
*/
|
|
36
|
+
export function nodeToMarkdown(node, depth = 0) {
|
|
37
|
+
const indent = ' '.repeat(depth);
|
|
38
|
+
const bullet = '-';
|
|
39
|
+
let markdown = '';
|
|
40
|
+
// Build node line with title
|
|
41
|
+
let nodeLine = `${indent}${bullet} ${escapeMarkdown(node.title)}`;
|
|
42
|
+
// Add labels inline if present
|
|
43
|
+
if (node.labels && node.labels.length > 0) {
|
|
44
|
+
const labelStr = node.labels.map(l => `[${escapeMarkdown(l)}]`).join(' ');
|
|
45
|
+
nodeLine += ` ${labelStr}`;
|
|
46
|
+
}
|
|
47
|
+
// Add markers inline if present
|
|
48
|
+
if (node.markers && node.markers.length > 0) {
|
|
49
|
+
const markerStr = node.markers.map(m => `{${escapeMarkdown(m)}}`).join(' ');
|
|
50
|
+
nodeLine += ` ${markerStr}`;
|
|
51
|
+
}
|
|
52
|
+
// Add href as reference if present
|
|
53
|
+
if (node.href) {
|
|
54
|
+
nodeLine += ` [→ ${escapeMarkdown(node.href)}]`;
|
|
55
|
+
}
|
|
56
|
+
markdown += nodeLine + '\n';
|
|
57
|
+
// Add note as indented text if present
|
|
58
|
+
if (node.note && node.note.trim()) {
|
|
59
|
+
const noteIndent = ' '.repeat(depth + 1);
|
|
60
|
+
const noteLines = node.note.split('\n').map(line => line.trim()).filter(line => line);
|
|
61
|
+
markdown += noteLines.map(line => `${noteIndent}> ${escapeMarkdown(line)}`).join('\n') + '\n';
|
|
62
|
+
}
|
|
63
|
+
// Recursively process children
|
|
64
|
+
if (node.children && node.children.length > 0) {
|
|
65
|
+
for (const child of node.children) {
|
|
66
|
+
markdown += nodeToMarkdown(child, depth + 1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return markdown;
|
|
70
|
+
}
|
|
71
|
+
export function getMarkdownTokenEstimate(markdown) {
|
|
72
|
+
const characterCount = markdown.length;
|
|
73
|
+
// Rough estimate: 1 token ≈ 4 characters (conservative for markdown)
|
|
74
|
+
const estimatedTokens = Math.ceil(characterCount / 4);
|
|
75
|
+
const estimate = {
|
|
76
|
+
estimatedTokens,
|
|
77
|
+
characterCount,
|
|
78
|
+
};
|
|
79
|
+
// Add hint if content is large
|
|
80
|
+
if (estimatedTokens > 20000) {
|
|
81
|
+
estimate.hint = 'Large content (>20k tokens). Consider using search/branch extraction for better token efficiency.';
|
|
82
|
+
}
|
|
83
|
+
else if (estimatedTokens > 10000) {
|
|
84
|
+
estimate.hint = 'Medium-large content (>10k tokens). For better efficiency, consider branching or search strategies.';
|
|
85
|
+
}
|
|
86
|
+
return estimate;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Converts entire XMind parsed result to markdown format with metadata header.
|
|
90
|
+
* Includes all sheets, relationships (if present), and token estimation.
|
|
91
|
+
* @param result - The parsed XMind result
|
|
92
|
+
* @returns Complete markdown document with headers and all content
|
|
93
|
+
*/
|
|
94
|
+
export function xmindToMarkdown(result) {
|
|
95
|
+
let markdown = '';
|
|
96
|
+
// Generate metadata header
|
|
97
|
+
markdown += '# XMind Markdown Export\n\n';
|
|
98
|
+
markdown += '## Document Metadata\n\n';
|
|
99
|
+
markdown += `- **File**: ${escapeMarkdown(result.filePath)}\n`;
|
|
100
|
+
markdown += `- **Format**: ${result.meta?.formatVersion || 'unknown'}\n`;
|
|
101
|
+
markdown += `- **Topics**: ${result.meta?.topicCount || 0}\n`;
|
|
102
|
+
markdown += `- **Sheets**: ${result.sheets.length}\n`;
|
|
103
|
+
markdown += `- **Exported**: ${result.meta?.parsedAt || new Date().toISOString()}\n\n`;
|
|
104
|
+
// Process each sheet
|
|
105
|
+
for (let i = 0; i < result.sheets.length; i++) {
|
|
106
|
+
const sheet = result.sheets[i];
|
|
107
|
+
markdown += `## Sheet: ${escapeMarkdown(sheet.title)}\n\n`;
|
|
108
|
+
// Add root topic and all descendants
|
|
109
|
+
markdown += nodeToMarkdown(sheet.rootTopic, 0);
|
|
110
|
+
// Add relationships if present
|
|
111
|
+
if (sheet.relationships && sheet.relationships.length > 0) {
|
|
112
|
+
markdown += '\n### Relationships\n\n';
|
|
113
|
+
for (const rel of sheet.relationships) {
|
|
114
|
+
let relLine = `- **${escapeMarkdown(rel.sourceId)}** → **${escapeMarkdown(rel.targetId)}**`;
|
|
115
|
+
if (rel.title) {
|
|
116
|
+
relLine += ` (${escapeMarkdown(rel.title)})`;
|
|
117
|
+
}
|
|
118
|
+
markdown += relLine + '\n';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Add separator between sheets (except after last sheet)
|
|
122
|
+
if (i < result.sheets.length - 1) {
|
|
123
|
+
markdown += '\n---\n\n';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Add token estimate section
|
|
127
|
+
const estimate = getMarkdownTokenEstimate(markdown);
|
|
128
|
+
markdown += '\n\n## Export Info\n\n';
|
|
129
|
+
markdown += `- **Characters**: ${estimate.characterCount}\n`;
|
|
130
|
+
markdown += `- **Estimated Tokens**: ${estimate.estimatedTokens}\n`;
|
|
131
|
+
if (estimate.hint) {
|
|
132
|
+
markdown += `- **Note**: ${estimate.hint}\n`;
|
|
133
|
+
}
|
|
134
|
+
return markdown;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=markdown-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-formatter.js","sourceRoot":"","sources":["../../src/formatters/markdown-formatter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Entry Point
|
|
3
|
+
* Initializes and launches the XMind MCP server with stdio transport.
|
|
4
|
+
*/
|
|
5
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { PARSE_XMIND_TOOL, executeParseTool } from './tools/parse-tool.js';
|
|
9
|
+
import { SEARCH_XMIND_TOOL, executeSearchTool } from './tools/search-tool.js';
|
|
10
|
+
import { GET_BRANCH_TOOL, executeBranchTool } from './tools/branch-tool.js';
|
|
11
|
+
import { info, warn, error as logError } from './utils/logger.js';
|
|
12
|
+
/**
|
|
13
|
+
* Tool definitions for MCP server
|
|
14
|
+
*/
|
|
15
|
+
const TOOLS = [PARSE_XMIND_TOOL, SEARCH_XMIND_TOOL, GET_BRANCH_TOOL];
|
|
16
|
+
/**
|
|
17
|
+
* Initialize the MCP server with tool handlers
|
|
18
|
+
*/
|
|
19
|
+
const server = new Server({
|
|
20
|
+
name: '@zengjing/xmind-mcp-server',
|
|
21
|
+
version: '1.0.0',
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Handler for ListTools request
|
|
25
|
+
* Returns all available tools
|
|
26
|
+
*/
|
|
27
|
+
function setupHandlers() {
|
|
28
|
+
// Register tools capability
|
|
29
|
+
server.registerCapabilities({
|
|
30
|
+
tools: {},
|
|
31
|
+
});
|
|
32
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
33
|
+
info('ListTools request received');
|
|
34
|
+
return {
|
|
35
|
+
tools: TOOLS,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* Handler for CallTool request
|
|
40
|
+
* Routes tool calls to appropriate handlers and returns results
|
|
41
|
+
*/
|
|
42
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
43
|
+
info('CallTool request received', { toolName: request.params.name });
|
|
44
|
+
const toolName = request.params.name;
|
|
45
|
+
const input = request.params.arguments;
|
|
46
|
+
try {
|
|
47
|
+
let result;
|
|
48
|
+
// Route tool calls to appropriate handlers
|
|
49
|
+
if (toolName === 'parse_xmind') {
|
|
50
|
+
result = await executeParseTool(input);
|
|
51
|
+
}
|
|
52
|
+
else if (toolName === 'search_xmind_nodes') {
|
|
53
|
+
result = await executeSearchTool(input);
|
|
54
|
+
}
|
|
55
|
+
else if (toolName === 'get_xmind_node_branch') {
|
|
56
|
+
result = await executeBranchTool(input);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
warn('Unknown tool called', { toolName });
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: 'text',
|
|
64
|
+
text: `Error: Unknown tool "${toolName}". Available tools are: parse_xmind, search_xmind_nodes, get_xmind_node_branch`,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
info('Tool executed successfully', { toolName });
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: result,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
// Error handling for tool execution
|
|
82
|
+
logError('Tool execution error', err);
|
|
83
|
+
let errorMessage = 'An unknown error occurred';
|
|
84
|
+
if (err instanceof Error) {
|
|
85
|
+
errorMessage = err.message;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
content: [
|
|
89
|
+
{
|
|
90
|
+
type: 'text',
|
|
91
|
+
text: `Error executing tool "${toolName}": ${errorMessage}`,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
isError: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Start the MCP server with stdio transport
|
|
101
|
+
*/
|
|
102
|
+
async function main() {
|
|
103
|
+
try {
|
|
104
|
+
info('Initializing MCP server');
|
|
105
|
+
setupHandlers();
|
|
106
|
+
const transport = new StdioServerTransport();
|
|
107
|
+
await server.connect(transport);
|
|
108
|
+
info('MCP server started and connected via stdio transport');
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
logError('Failed to start MCP server', err);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Run the server
|
|
116
|
+
main();
|
|
117
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod runtime schemas for input validation.
|
|
3
|
+
* These validate tool parameters and parsed results.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import type { XMindNode, XMindSheet, XMindParsedResult, SearchResult, BranchExtractionResult } from './types.js';
|
|
7
|
+
export declare const ParseXMindInputSchema: z.ZodObject<{
|
|
8
|
+
path: z.ZodString;
|
|
9
|
+
format: z.ZodDefault<z.ZodEnum<["markdown", "json"]>>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
path: string;
|
|
12
|
+
format: "markdown" | "json";
|
|
13
|
+
}, {
|
|
14
|
+
path: string;
|
|
15
|
+
format?: "markdown" | "json" | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const SearchXMindInputSchema: z.ZodObject<{
|
|
18
|
+
path: z.ZodString;
|
|
19
|
+
query: z.ZodString;
|
|
20
|
+
searchIn: z.ZodDefault<z.ZodArray<z.ZodEnum<["title", "note", "label"]>, "many">>;
|
|
21
|
+
caseSensitive: z.ZodDefault<z.ZodBoolean>;
|
|
22
|
+
}, "strip", z.ZodTypeAny, {
|
|
23
|
+
path: string;
|
|
24
|
+
query: string;
|
|
25
|
+
searchIn: ("title" | "note" | "label")[];
|
|
26
|
+
caseSensitive: boolean;
|
|
27
|
+
}, {
|
|
28
|
+
path: string;
|
|
29
|
+
query: string;
|
|
30
|
+
searchIn?: ("title" | "note" | "label")[] | undefined;
|
|
31
|
+
caseSensitive?: boolean | undefined;
|
|
32
|
+
}>;
|
|
33
|
+
export declare const GetBranchInputSchema: z.ZodObject<{
|
|
34
|
+
path: z.ZodString;
|
|
35
|
+
nodeId: z.ZodString;
|
|
36
|
+
depth: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
path: string;
|
|
39
|
+
nodeId: string;
|
|
40
|
+
depth?: number | undefined;
|
|
41
|
+
}, {
|
|
42
|
+
path: string;
|
|
43
|
+
nodeId: string;
|
|
44
|
+
depth?: number | undefined;
|
|
45
|
+
}>;
|
|
46
|
+
export declare const XMindNodeSchema: z.ZodType<XMindNode>;
|
|
47
|
+
export declare const XMindSheetSchema: z.ZodType<XMindSheet>;
|
|
48
|
+
export declare const XMindParsedResultSchema: z.ZodType<XMindParsedResult>;
|
|
49
|
+
export declare const SearchResultSchema: z.ZodType<SearchResult>;
|
|
50
|
+
export declare const BranchExtractionResultSchema: z.ZodType<BranchExtractionResult>;
|
|
51
|
+
export type ParseXMindInput = z.infer<typeof ParseXMindInputSchema>;
|
|
52
|
+
export type SearchXMindInput = z.infer<typeof SearchXMindInputSchema>;
|
|
53
|
+
export type GetBranchInput = z.infer<typeof GetBranchInputSchema>;
|
|
54
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/model/schemas.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGjH,eAAO,MAAM,qBAAqB;;;;;;;;;EAGhC,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;EAKjC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAI/B,CAAC;AAGH,eAAO,MAAM,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAWxB,CAAC;AAE1B,eAAO,MAAM,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAUjD,CAAC;AAEH,eAAO,MAAM,uBAAuB,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAQ/D,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAKrD,CAAC;AAEH,eAAO,MAAM,4BAA4B,EAAE,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAIzE,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod runtime schemas for input validation.
|
|
3
|
+
* These validate tool parameters and parsed results.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
// Input validation schemas
|
|
7
|
+
export const ParseXMindInputSchema = z.object({
|
|
8
|
+
path: z.string().describe('Absolute file path to the .xmind file'),
|
|
9
|
+
format: z.enum(['markdown', 'json']).default('markdown').describe('Output format'),
|
|
10
|
+
});
|
|
11
|
+
export const SearchXMindInputSchema = z.object({
|
|
12
|
+
path: z.string().describe('Absolute file path to the .xmind file'),
|
|
13
|
+
query: z.string().min(1).describe('Search keyword or phrase'),
|
|
14
|
+
searchIn: z.array(z.enum(['title', 'note', 'label'])).default(['title', 'note', 'label']).describe('Fields to search in'),
|
|
15
|
+
caseSensitive: z.boolean().default(false).describe('Case-sensitive matching'),
|
|
16
|
+
});
|
|
17
|
+
export const GetBranchInputSchema = z.object({
|
|
18
|
+
path: z.string().describe('Absolute file path to the .xmind file'),
|
|
19
|
+
nodeId: z.string().describe('Target node ID to extract'),
|
|
20
|
+
depth: z.number().int().positive().optional().describe('Maximum depth to traverse'),
|
|
21
|
+
});
|
|
22
|
+
// Output validation schemas
|
|
23
|
+
export const XMindNodeSchema = z.lazy(() => z.object({
|
|
24
|
+
id: z.string(),
|
|
25
|
+
title: z.string(),
|
|
26
|
+
note: z.string().optional(),
|
|
27
|
+
labels: z.array(z.string()).optional(),
|
|
28
|
+
markers: z.array(z.string()).optional(),
|
|
29
|
+
children: z.array(XMindNodeSchema).default([]),
|
|
30
|
+
href: z.string().optional(),
|
|
31
|
+
position: z.object({ x: z.number().optional(), y: z.number().optional() }).optional(),
|
|
32
|
+
}));
|
|
33
|
+
export const XMindSheetSchema = z.object({
|
|
34
|
+
id: z.string(),
|
|
35
|
+
title: z.string(),
|
|
36
|
+
rootTopic: XMindNodeSchema,
|
|
37
|
+
relationships: z.array(z.object({
|
|
38
|
+
id: z.string(),
|
|
39
|
+
title: z.string().optional(),
|
|
40
|
+
sourceId: z.string(),
|
|
41
|
+
targetId: z.string(),
|
|
42
|
+
})).optional(),
|
|
43
|
+
});
|
|
44
|
+
export const XMindParsedResultSchema = z.object({
|
|
45
|
+
filePath: z.string(),
|
|
46
|
+
sheets: z.array(XMindSheetSchema),
|
|
47
|
+
meta: z.object({
|
|
48
|
+
formatVersion: z.enum(['zen', 'legacy']),
|
|
49
|
+
topicCount: z.number(),
|
|
50
|
+
parsedAt: z.string(),
|
|
51
|
+
}).optional(),
|
|
52
|
+
});
|
|
53
|
+
export const SearchResultSchema = z.object({
|
|
54
|
+
node: XMindNodeSchema,
|
|
55
|
+
matchType: z.enum(['title', 'note', 'label']),
|
|
56
|
+
matchText: z.string(),
|
|
57
|
+
pathToRoot: z.array(z.string()),
|
|
58
|
+
});
|
|
59
|
+
export const BranchExtractionResultSchema = z.object({
|
|
60
|
+
rootNode: XMindNodeSchema,
|
|
61
|
+
depthReached: z.number(),
|
|
62
|
+
nodeCount: z.number(),
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=schemas.js.map
|