docs-hub-mcp 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +171 -0
  2. package/dhm.js +2 -0
  3. package/dist/cli/commands.d.ts +11 -0
  4. package/dist/cli/commands.d.ts.map +1 -0
  5. package/dist/cli/commands.js +112 -0
  6. package/dist/cli/commands.js.map +1 -0
  7. package/dist/cli/config.d.ts +120 -0
  8. package/dist/cli/config.d.ts.map +1 -0
  9. package/dist/cli/config.js +76 -0
  10. package/dist/cli/config.js.map +1 -0
  11. package/dist/index/builder.d.ts +25 -0
  12. package/dist/index/builder.d.ts.map +1 -0
  13. package/dist/index/builder.js +40 -0
  14. package/dist/index/builder.js.map +1 -0
  15. package/dist/index/parser.d.ts +20 -0
  16. package/dist/index/parser.d.ts.map +1 -0
  17. package/dist/index/parser.js +162 -0
  18. package/dist/index/parser.js.map +1 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +92 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/mcp/server.d.ts +3 -0
  24. package/dist/mcp/server.d.ts.map +1 -0
  25. package/dist/mcp/server.js +97 -0
  26. package/dist/mcp/server.js.map +1 -0
  27. package/dist/mcp/tools.d.ts +57 -0
  28. package/dist/mcp/tools.d.ts.map +1 -0
  29. package/dist/mcp/tools.js +70 -0
  30. package/dist/mcp/tools.js.map +1 -0
  31. package/dist/search/cache.d.ts +12 -0
  32. package/dist/search/cache.d.ts.map +1 -0
  33. package/dist/search/cache.js +36 -0
  34. package/dist/search/cache.js.map +1 -0
  35. package/dist/search/exact.d.ts +3 -0
  36. package/dist/search/exact.d.ts.map +1 -0
  37. package/dist/search/exact.js +56 -0
  38. package/dist/search/exact.js.map +1 -0
  39. package/dist/search/graph.d.ts +6 -0
  40. package/dist/search/graph.d.ts.map +1 -0
  41. package/dist/search/graph.js +137 -0
  42. package/dist/search/graph.js.map +1 -0
  43. package/dist/search/pipeline.d.ts +18 -0
  44. package/dist/search/pipeline.d.ts.map +1 -0
  45. package/dist/search/pipeline.js +99 -0
  46. package/dist/search/pipeline.js.map +1 -0
  47. package/dist/search/semantic.d.ts +4 -0
  48. package/dist/search/semantic.d.ts.map +1 -0
  49. package/dist/search/semantic.js +120 -0
  50. package/dist/search/semantic.js.map +1 -0
  51. package/dist/sync/base.d.ts +21 -0
  52. package/dist/sync/base.d.ts.map +1 -0
  53. package/dist/sync/base.js +8 -0
  54. package/dist/sync/base.js.map +1 -0
  55. package/dist/sync/confluence.d.ts +3 -0
  56. package/dist/sync/confluence.d.ts.map +1 -0
  57. package/dist/sync/confluence.js +111 -0
  58. package/dist/sync/confluence.js.map +1 -0
  59. package/dist/sync/git-wiki.d.ts +3 -0
  60. package/dist/sync/git-wiki.d.ts.map +1 -0
  61. package/dist/sync/git-wiki.js +103 -0
  62. package/dist/sync/git-wiki.js.map +1 -0
  63. package/dist/sync/google-docs.d.ts +3 -0
  64. package/dist/sync/google-docs.d.ts.map +1 -0
  65. package/dist/sync/google-docs.js +87 -0
  66. package/dist/sync/google-docs.js.map +1 -0
  67. package/dist/sync/notion.d.ts +3 -0
  68. package/dist/sync/notion.d.ts.map +1 -0
  69. package/dist/sync/notion.js +126 -0
  70. package/dist/sync/notion.js.map +1 -0
  71. package/dist/sync/slack.d.ts +3 -0
  72. package/dist/sync/slack.d.ts.map +1 -0
  73. package/dist/sync/slack.js +92 -0
  74. package/dist/sync/slack.js.map +1 -0
  75. package/dist/sync/state.d.ts +25 -0
  76. package/dist/sync/state.d.ts.map +1 -0
  77. package/dist/sync/state.js +80 -0
  78. package/dist/sync/state.js.map +1 -0
  79. package/dist/utils/fs.d.ts +8 -0
  80. package/dist/utils/fs.d.ts.map +1 -0
  81. package/dist/utils/fs.js +43 -0
  82. package/dist/utils/fs.js.map +1 -0
  83. package/dist/utils/git.d.ts +7 -0
  84. package/dist/utils/git.d.ts.map +1 -0
  85. package/dist/utils/git.js +39 -0
  86. package/dist/utils/git.js.map +1 -0
  87. package/dist/utils/logger.d.ts +16 -0
  88. package/dist/utils/logger.d.ts.map +1 -0
  89. package/dist/utils/logger.js +21 -0
  90. package/dist/utils/logger.js.map +1 -0
  91. package/dist/web/server.d.ts +2 -0
  92. package/dist/web/server.d.ts.map +1 -0
  93. package/dist/web/server.js +82 -0
  94. package/dist/web/server.js.map +1 -0
  95. package/dist/web/ui.html +210 -0
  96. package/package.json +38 -0
@@ -0,0 +1,162 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { relative } from 'node:path';
3
+ import { listFiles } from '../utils/fs.js';
4
+ import { logger } from '../utils/logger.js';
5
+ const VIETNAMESE_STOP_WORDS = new Set([
6
+ 'của', 'và', 'các', 'một', 'cho', 'được', 'trong', 'có', 'với', 'là',
7
+ 'để', 'không', 'này', 'như', 'khi', 'từ', 'sẽ', 'đã', 'về', 'ra',
8
+ ]);
9
+ const ENGLISH_STOP_WORDS = new Set([
10
+ 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'of', 'to', 'in',
11
+ 'for', 'on', 'with', 'and', 'or', 'this', 'that', 'it', 'be',
12
+ ]);
13
+ function isStopWord(word) {
14
+ return VIETNAMESE_STOP_WORDS.has(word.toLowerCase()) ||
15
+ ENGLISH_STOP_WORDS.has(word.toLowerCase()) ||
16
+ word.length <= 1;
17
+ }
18
+ function extractTitle(lines) {
19
+ for (const line of lines) {
20
+ if (line.startsWith('# ')) {
21
+ return line.replace(/^#\s+/, '').trim();
22
+ }
23
+ }
24
+ return '';
25
+ }
26
+ function extractTags(lines) {
27
+ const tags = new Set();
28
+ for (const line of lines) {
29
+ // Inline hashtags: #deploy #production
30
+ const hashtags = line.match(/#([a-zA-ZÀ-ỹ][a-zA-ZÀ-ỹ0-9_-]{2,})/g);
31
+ if (hashtags) {
32
+ for (const tag of hashtags) {
33
+ tags.add(tag.slice(1).toLowerCase());
34
+ }
35
+ }
36
+ }
37
+ // Extract from frontmatter if present
38
+ const content = lines.join('\n');
39
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
40
+ if (fmMatch) {
41
+ const fm = fmMatch[1];
42
+ const tagLine = fm.match(/tags?\s*:\s*\[([^\]]+)\]/);
43
+ if (tagLine) {
44
+ for (const t of tagLine[1].split(',')) {
45
+ tags.add(t.trim().replace(/['"]/g, '').toLowerCase());
46
+ }
47
+ }
48
+ }
49
+ return [...tags].slice(0, 20);
50
+ }
51
+ function extractKeywords(title, lines, tags) {
52
+ const keywords = new Set();
53
+ const text = lines.join(' ');
54
+ // Words from title (excluding stop words)
55
+ const titleWords = title
56
+ .toLowerCase()
57
+ .replace(/[#*_`\[\]()]/g, '')
58
+ .split(/\s+/)
59
+ .filter((w) => w.length > 2 && !isStopWord(w));
60
+ for (const w of titleWords) {
61
+ keywords.add(w);
62
+ }
63
+ // Tags are also keywords
64
+ for (const tag of tags) {
65
+ keywords.add(tag.toLowerCase());
66
+ }
67
+ // Extract bold/italic terms (often key concepts)
68
+ const boldTerms = text.match(/\*\*(.+?)\*\*/g);
69
+ if (boldTerms) {
70
+ for (const term of boldTerms) {
71
+ const cleaned = term.replace(/\*\*/g, '').trim().toLowerCase();
72
+ if (cleaned.length > 2 && !isStopWord(cleaned)) {
73
+ keywords.add(cleaned);
74
+ }
75
+ }
76
+ }
77
+ return [...keywords].slice(0, 30);
78
+ }
79
+ function extractSections(lines) {
80
+ const sections = [];
81
+ for (const line of lines) {
82
+ const match = line.match(/^#{1,4}\s+(.+)/);
83
+ if (!match)
84
+ continue;
85
+ const title = match[1].trim();
86
+ const textOnly = title.replace(/[#*_`\[\]()]/g, '').toLowerCase();
87
+ const anchor = textOnly
88
+ .replace(/[^a-z0-9à-ỹ\s-]/g, '')
89
+ .trim()
90
+ .replace(/\s+/g, '-')
91
+ .slice(0, 50);
92
+ const kw = textOnly
93
+ .split(/\s+/)
94
+ .filter((w) => w.length > 2 && !isStopWord(w));
95
+ sections.push({ anchor, title, keywords: kw });
96
+ }
97
+ return sections;
98
+ }
99
+ function extractRelations(lines, currentPath) {
100
+ const relations = [];
101
+ const content = lines.join('\n');
102
+ // Markdown links: [text](path.md)
103
+ const mdLinks = content.match(/\[([^\]]+)\]\(([^)]+\.md)\)/g);
104
+ if (mdLinks) {
105
+ for (const link of mdLinks) {
106
+ const match = link.match(/\[([^\]]+)\]\(([^)]+)\)/);
107
+ if (match) {
108
+ relations.push({
109
+ path: match[2],
110
+ relation: match[1],
111
+ });
112
+ }
113
+ }
114
+ }
115
+ // "Related:" or "Xem thêm:" sections
116
+ const relatedRegex = /(?:Related|Xem thêm|Liên quan|See also)[:\s]*\n((?:[-*]\s*\[[^\]]+\]\([^)]+\)\s*\n?)+)/i;
117
+ const relMatch = content.match(relatedRegex);
118
+ if (relMatch) {
119
+ for (const line of relMatch[1].split('\n')) {
120
+ const linkMatch = line.match(/\[([^\]]+)\]\(([^)]+)\)/);
121
+ if (linkMatch) {
122
+ relations.push({ path: linkMatch[2], relation: linkMatch[1] });
123
+ }
124
+ }
125
+ }
126
+ return relations;
127
+ }
128
+ export function parseDocument(fullPath, kbPath) {
129
+ if (!existsSync(fullPath))
130
+ return null;
131
+ try {
132
+ const content = readFileSync(fullPath, 'utf-8');
133
+ const lines = content.split('\n');
134
+ const relPath = relative(kbPath, fullPath);
135
+ const basename = relPath.split('/').pop()?.replace('.md', '') || relPath;
136
+ const title = extractTitle(lines) || basename;
137
+ const tags = extractTags(lines);
138
+ const keywords = extractKeywords(title, lines, tags);
139
+ const sections = extractSections(lines);
140
+ const related = extractRelations(lines, relPath);
141
+ return { path: relPath, title, tags, keywords, related, sections };
142
+ }
143
+ catch {
144
+ logger.warn('Failed to parse document', { path: fullPath });
145
+ return null;
146
+ }
147
+ }
148
+ export function parseAllDocuments(kbPath) {
149
+ const docs = [];
150
+ const mdFiles = listFiles(kbPath, '.md');
151
+ for (const fullPath of mdFiles) {
152
+ // Skip index file
153
+ if (fullPath.endsWith('dhm-index.yaml'))
154
+ continue;
155
+ const doc = parseDocument(fullPath, kbPath);
156
+ if (doc)
157
+ docs.push(doc);
158
+ }
159
+ logger.info('Parsed documents', { count: docs.length });
160
+ return docs;
161
+ }
162
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/index/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ import { logger, setLogLevel } from './utils/logger.js';
3
+ import { cmdInit, cmdServe, cmdSync, cmdIndex, cmdSearch, cmdPrewarm } from './cli/commands.js';
4
+ import { startWebServer } from './web/server.js';
5
+ const HELP = `
6
+ doc-hub-mcp — MCP server for documentation hub, 3-tier search
7
+
8
+ Usage: dhm <command> [options]
9
+
10
+ Commands:
11
+ init Initialize doc-hub-mcp in current directory
12
+ serve Start MCP server (for AI agents)
13
+ web Start Web UI (browser dashboard)
14
+ sync Sync all configured sources → knowledge-base/
15
+ --incremental Only sync changes since last sync
16
+ --full Force full re-sync (ignore state)
17
+ index Rebuild .dhm-index.yaml from knowledge-base/
18
+ search <query> Run 3-tier search from CLI
19
+ --tier <1|2|3> Force specific search tier
20
+ --max <n> Maximum results (default: 10)
21
+ --json Output as JSON
22
+ prewarm Pre-warm cache with seed queries
23
+
24
+ Examples:
25
+ dhm init
26
+ dhm serve
27
+ dhm web
28
+ dhm search "how to deploy to production"
29
+ dhm search --tier 1 --json "deploy"
30
+ dhm sync --incremental
31
+
32
+ Environment:
33
+ DHM_LOG_LEVEL debug | info | warn | error (default: info)
34
+ DHM_PORT Web UI port (default: 3456)
35
+ `;
36
+ async function main() {
37
+ const args = process.argv.slice(2);
38
+ const cmd = args[0];
39
+ if (process.env.DHM_LOG_LEVEL) {
40
+ setLogLevel(process.env.DHM_LOG_LEVEL);
41
+ }
42
+ const cwd = process.cwd();
43
+ switch (cmd) {
44
+ case 'init':
45
+ await cmdInit(cwd);
46
+ break;
47
+ case 'serve':
48
+ await cmdServe(cwd);
49
+ break;
50
+ case 'web':
51
+ await startWebServer(cwd);
52
+ break;
53
+ case 'sync': {
54
+ const incremental = args.includes('--incremental') || args.includes('-i');
55
+ const full = args.includes('--full');
56
+ await cmdSync(cwd, incremental && !full);
57
+ break;
58
+ }
59
+ case 'index':
60
+ await cmdIndex(cwd);
61
+ break;
62
+ case 'search': {
63
+ const rest = args.slice(1);
64
+ const queryIdx = rest.findIndex(a => !a.startsWith('--'));
65
+ const query = queryIdx >= 0 ? rest.slice(queryIdx).join(' ') : '';
66
+ if (!query) {
67
+ console.error('Usage: dhm search [--tier 1|2|3] [--max <n>] [--json] <query>');
68
+ process.exit(1);
69
+ }
70
+ const tierArg = rest.indexOf('--tier');
71
+ const maxArg = rest.indexOf('--max');
72
+ const jsonFlag = rest.includes('--json');
73
+ await cmdSearch(cwd, query, {
74
+ tier: tierArg >= 0 ? Number(rest[tierArg + 1]) : undefined,
75
+ max: maxArg >= 0 ? Number(rest[maxArg + 1]) : undefined,
76
+ json: jsonFlag,
77
+ });
78
+ break;
79
+ }
80
+ case 'prewarm':
81
+ await cmdPrewarm(cwd);
82
+ break;
83
+ default:
84
+ console.log(HELP);
85
+ break;
86
+ }
87
+ }
88
+ main().catch((err) => {
89
+ logger.error('fatal error', { error: String(err) });
90
+ process.exit(1);
91
+ });
92
+ //# 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,3 @@
1
+ import type { AppConfig } from '../cli/config.js';
2
+ export declare function startServer(config: AppConfig, kbPath: string): Promise<void>;
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAsDlD,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+ClF"}
@@ -0,0 +1,97 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
4
+ import { logger } from '../utils/logger.js';
5
+ import { createSearchKnowledge, createReadDocument, createGetDocumentStructure, } from './tools.js';
6
+ import { SearchPipeline } from '../search/pipeline.js';
7
+ const TOOLS = [
8
+ {
9
+ name: 'search_knowledge',
10
+ description: 'Search the knowledge base using 3-tier search (exact → graph → semantic). Returns ranked results with snippets.',
11
+ inputSchema: {
12
+ type: 'object',
13
+ properties: {
14
+ query: {
15
+ type: 'string',
16
+ description: 'The search query. Supports exact keywords, synonyms, and natural language.',
17
+ },
18
+ maxResults: {
19
+ type: 'number',
20
+ description: 'Maximum number of results to return (default: 10)',
21
+ },
22
+ minResults: {
23
+ type: 'number',
24
+ description: 'Minimum results before trying the next tier (default: 3)',
25
+ },
26
+ tier: {
27
+ type: 'number',
28
+ enum: [1, 2, 3],
29
+ description: 'Force a specific search tier (1=exact, 2=graph, 3=semantic)',
30
+ },
31
+ },
32
+ required: ['query'],
33
+ },
34
+ },
35
+ {
36
+ name: 'read_document',
37
+ description: 'Read the full content of a document from the knowledge base by its relative path.',
38
+ inputSchema: {
39
+ type: 'object',
40
+ properties: {
41
+ path: {
42
+ type: 'string',
43
+ description: 'Relative path to the document (e.g., "wiki/deployment.md")',
44
+ },
45
+ },
46
+ required: ['path'],
47
+ },
48
+ },
49
+ {
50
+ name: 'get_document_structure',
51
+ description: 'Get the directory tree of the knowledge base, list of configured sources, and last sync timestamp.',
52
+ inputSchema: {
53
+ type: 'object',
54
+ properties: {},
55
+ },
56
+ },
57
+ ];
58
+ export async function startServer(config, kbPath) {
59
+ const server = new Server({ name: 'doc-hub-mcp', version: '0.1.0' }, { capabilities: { tools: {} } });
60
+ const pipeline = new SearchPipeline(kbPath, config);
61
+ const ctx = { config, kbPath, pipeline };
62
+ const searchKnowledge = createSearchKnowledge(ctx);
63
+ const readDocument = createReadDocument(ctx);
64
+ const getDocumentStructure = createGetDocumentStructure(ctx);
65
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
66
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
67
+ const { name, arguments: args } = request.params;
68
+ try {
69
+ switch (name) {
70
+ case 'search_knowledge': {
71
+ const result = await searchKnowledge(args);
72
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
73
+ }
74
+ case 'read_document': {
75
+ const result = await readDocument(args);
76
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
77
+ }
78
+ case 'get_document_structure': {
79
+ const result = await getDocumentStructure();
80
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
81
+ }
82
+ default:
83
+ return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
84
+ }
85
+ }
86
+ catch (err) {
87
+ logger.error('tool error', { name, error: String(err) });
88
+ return { content: [{ type: 'text', text: `Error: ${String(err)}` }], isError: true };
89
+ }
90
+ });
91
+ const transport = new StdioServerTransport();
92
+ await server.connect(transport);
93
+ logger.info('MCP server started', { tools: TOOLS.map(t => t.name) });
94
+ // Keep process alive on stdin
95
+ process.stdin.resume();
96
+ }
97
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { AppConfig } from '../cli/config.js';
2
+ import type { SearchPipeline } from '../search/pipeline.js';
3
+ export interface SearchResult {
4
+ path: string;
5
+ score: number;
6
+ matchType: 'exact' | 'tag' | 'keyword' | 'related' | 'semantic';
7
+ tier: 1 | 2 | 3;
8
+ snippet: string;
9
+ }
10
+ export interface SearchResponse {
11
+ results: SearchResult[];
12
+ totalTime: number;
13
+ tierUsed: number;
14
+ }
15
+ export interface DocumentMeta {
16
+ title: string;
17
+ source: string;
18
+ tags: string[];
19
+ lastModified: string;
20
+ }
21
+ export interface FileNode {
22
+ name: string;
23
+ path: string;
24
+ type: 'file' | 'directory';
25
+ children?: FileNode[];
26
+ }
27
+ export interface SourceInfo {
28
+ name: string;
29
+ type: string;
30
+ enabled: boolean;
31
+ lastSync: string | null;
32
+ }
33
+ export interface ToolContext {
34
+ config: AppConfig;
35
+ kbPath: string;
36
+ pipeline: SearchPipeline;
37
+ }
38
+ export declare function createSearchKnowledge(ctx: ToolContext): (params: {
39
+ query: string;
40
+ maxResults?: number;
41
+ minResults?: number;
42
+ tier?: 1 | 2 | 3;
43
+ }) => Promise<SearchResponse>;
44
+ export declare function createReadDocument(ctx: ToolContext): (params: {
45
+ path: string;
46
+ }) => Promise<{
47
+ content: string;
48
+ metadata: DocumentMeta;
49
+ } | {
50
+ error: string;
51
+ }>;
52
+ export declare function createGetDocumentStructure(ctx: ToolContext): () => Promise<{
53
+ tree: FileNode[];
54
+ sources: SourceInfo[];
55
+ lastSync: string | null;
56
+ }>;
57
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IAChE,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,IACtC,QAAQ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAAE,KAAG,OAAO,CAAC,cAAc,CAAC,CAQ9H;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,IACnC,QAAQ;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA2BlH;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,WAAW,SACxC,OAAO,CAAC;IAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAa/F"}
@@ -0,0 +1,70 @@
1
+ import { readFileSafe, fileExists, listFiles } from '../utils/fs.js';
2
+ import { resolve, relative } from 'node:path';
3
+ import { statSync } from 'node:fs';
4
+ import { logger } from '../utils/logger.js';
5
+ export function createSearchKnowledge(ctx) {
6
+ return async (params) => {
7
+ logger.info('search_knowledge', { query: params.query });
8
+ return ctx.pipeline.search(params.query, {
9
+ maxResults: params.maxResults,
10
+ minResults: params.minResults,
11
+ tier: params.tier,
12
+ });
13
+ };
14
+ }
15
+ export function createReadDocument(ctx) {
16
+ return async (params) => {
17
+ const fullPath = resolve(ctx.kbPath, params.path);
18
+ if (!fileExists(fullPath)) {
19
+ return { error: `Document not found: ${params.path}` };
20
+ }
21
+ const content = readFileSafe(fullPath);
22
+ if (content === null) {
23
+ return { error: `Failed to read: ${params.path}` };
24
+ }
25
+ const stat = statSync(fullPath);
26
+ const firstLine = content.split('\n')[0] || params.path;
27
+ const title = firstLine.startsWith('#') ? firstLine.replace(/^#+\s*/, '') : params.path;
28
+ logger.info('read_document', { path: params.path });
29
+ return {
30
+ content,
31
+ metadata: {
32
+ title,
33
+ source: ctx.config.sources[0]?.name || 'unknown',
34
+ tags: [],
35
+ lastModified: stat.mtime.toISOString(),
36
+ },
37
+ };
38
+ };
39
+ }
40
+ export function createGetDocumentStructure(ctx) {
41
+ return async () => {
42
+ logger.info('get_document_structure');
43
+ const tree = buildFileTree(ctx.kbPath);
44
+ const sources = ctx.config.sources.map(s => ({
45
+ name: s.name,
46
+ type: s.type,
47
+ enabled: s.enabled ?? true,
48
+ lastSync: null,
49
+ }));
50
+ return { tree, sources, lastSync: null };
51
+ };
52
+ }
53
+ function buildFileTree(dir) {
54
+ const nodes = [];
55
+ if (!fileExists(dir))
56
+ return nodes;
57
+ for (const fullPath of listFiles(dir, '.md')) {
58
+ const relPath = relative(dir, fullPath);
59
+ const parts = relPath.split('/');
60
+ const name = parts[parts.length - 1];
61
+ nodes.push({
62
+ name,
63
+ path: relPath,
64
+ type: 'file',
65
+ });
66
+ // TODO: build actual nested tree structure
67
+ }
68
+ return nodes;
69
+ }
70
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { SearchResult } from '../mcp/tools.js';
2
+ export declare class SearchCache {
3
+ private cache;
4
+ private maxSize;
5
+ private ttl;
6
+ constructor(maxSize?: number, ttl?: number);
7
+ get(query: string): SearchResult[] | null;
8
+ set(query: string, results: SearchResult[]): void;
9
+ clear(): void;
10
+ get size(): number;
11
+ }
12
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/search/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAOpD,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,GAAG,CAAS;gBAER,OAAO,SAAM,EAAE,GAAG,SAAO;IAKrC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,IAAI;IAazC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI;IASjD,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,36 @@
1
+ export class SearchCache {
2
+ cache = new Map();
3
+ maxSize;
4
+ ttl; // seconds
5
+ constructor(maxSize = 100, ttl = 3600) {
6
+ this.maxSize = maxSize;
7
+ this.ttl = ttl;
8
+ }
9
+ get(query) {
10
+ const normalized = query.toLowerCase().trim();
11
+ const entry = this.cache.get(normalized);
12
+ if (!entry)
13
+ return null;
14
+ if (Date.now() - entry.timestamp >= this.ttl * 1000) {
15
+ this.cache.delete(normalized);
16
+ return null;
17
+ }
18
+ return entry.results;
19
+ }
20
+ set(query, results) {
21
+ const normalized = query.toLowerCase().trim();
22
+ if (this.cache.size >= this.maxSize) {
23
+ const firstKey = this.cache.keys().next().value;
24
+ if (firstKey !== undefined)
25
+ this.cache.delete(firstKey);
26
+ }
27
+ this.cache.set(normalized, { results, timestamp: Date.now() });
28
+ }
29
+ clear() {
30
+ this.cache.clear();
31
+ }
32
+ get size() {
33
+ return this.cache.size;
34
+ }
35
+ }
36
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/search/cache.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,WAAW;IACd,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtC,OAAO,CAAS;IAChB,GAAG,CAAS,CAAC,UAAU;IAE/B,YAAY,OAAO,GAAG,GAAG,EAAE,GAAG,GAAG,IAAI;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,GAAG,CAAC,KAAa;QACf,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;YACpD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,GAAG,CAAC,KAAa,EAAE,OAAuB;QACxC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAC9C,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAChD,IAAI,QAAQ,KAAK,SAAS;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ import type { SearchResult } from '../mcp/tools.js';
2
+ export declare function searchExact(query: string, kbPath: string, maxResults?: number): SearchResult[];
3
+ //# sourceMappingURL=exact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exact.d.ts","sourceRoot":"","sources":["../../src/search/exact.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAQpD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,YAAY,EAAE,CAgB1F"}