gitlab-docs-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 +130 -0
- package/data/gitlab-docs/documents.json +38252 -0
- package/data/gitlab-docs/index_meta.json +6 -0
- package/dist/bin.js +2 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/content/cache.d.ts +51 -0
- package/dist/content/cache.d.ts.map +1 -0
- package/dist/content/cache.js +60 -0
- package/dist/content/cache.js.map +1 -0
- package/dist/content/cache.test.d.ts +2 -0
- package/dist/content/cache.test.d.ts.map +1 -0
- package/dist/content/cache.test.js +58 -0
- package/dist/content/cache.test.js.map +1 -0
- package/dist/content/index.d.ts +3 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/index.js +3 -0
- package/dist/content/index.js.map +1 -0
- package/dist/content/parser.d.ts +32 -0
- package/dist/content/parser.d.ts.map +1 -0
- package/dist/content/parser.js +72 -0
- package/dist/content/parser.js.map +1 -0
- package/dist/content/parser.test.d.ts +2 -0
- package/dist/content/parser.test.d.ts.map +1 -0
- package/dist/content/parser.test.js +71 -0
- package/dist/content/parser.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/search/document.d.ts +11 -0
- package/dist/search/document.d.ts.map +1 -0
- package/dist/search/document.js +47 -0
- package/dist/search/document.js.map +1 -0
- package/dist/search/engine.d.ts +41 -0
- package/dist/search/engine.d.ts.map +1 -0
- package/dist/search/engine.js +200 -0
- package/dist/search/engine.js.map +1 -0
- package/dist/search/flexsearch-wrapper.d.ts +51 -0
- package/dist/search/flexsearch-wrapper.d.ts.map +1 -0
- package/dist/search/flexsearch-wrapper.js +55 -0
- package/dist/search/flexsearch-wrapper.js.map +1 -0
- package/dist/search/index.d.ts +4 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +4 -0
- package/dist/search/index.js.map +1 -0
- package/dist/tools/getDocPage.d.ts +8 -0
- package/dist/tools/getDocPage.d.ts.map +1 -0
- package/dist/tools/getDocPage.js +48 -0
- package/dist/tools/getDocPage.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/listDocSections.d.ts +8 -0
- package/dist/tools/listDocSections.d.ts.map +1 -0
- package/dist/tools/listDocSections.js +17 -0
- package/dist/tools/listDocSections.js.map +1 -0
- package/dist/tools/registry.d.ts +14 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +64 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/registry.test.d.ts +2 -0
- package/dist/tools/registry.test.d.ts.map +1 -0
- package/dist/tools/registry.test.js +45 -0
- package/dist/tools/registry.test.js.map +1 -0
- package/dist/tools/searchGitLabDocs.d.ts +19 -0
- package/dist/tools/searchGitLabDocs.d.ts.map +1 -0
- package/dist/tools/searchGitLabDocs.js +25 -0
- package/dist/tools/searchGitLabDocs.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/models.d.ts +57 -0
- package/dist/types/models.d.ts.map +1 -0
- package/dist/types/models.js +41 -0
- package/dist/types/models.js.map +1 -0
- package/dist/utils/constants.d.ts +31 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +38 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/constants.test.d.ts +2 -0
- package/dist/utils/constants.test.d.ts.map +1 -0
- package/dist/utils/constants.test.js +16 -0
- package/dist/utils/constants.test.js.map +1 -0
- package/dist/utils/errors.d.ts +22 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +43 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/errors.test.d.ts +2 -0
- package/dist/utils/errors.test.d.ts.map +1 -0
- package/dist/utils/errors.test.js +55 -0
- package/dist/utils/errors.test.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +23 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +44 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/logger.test.d.ts +2 -0
- package/dist/utils/logger.test.d.ts.map +1 -0
- package/dist/utils/logger.test.js +71 -0
- package/dist/utils/logger.test.js.map +1 -0
- package/dist/utils/performance.d.ts +53 -0
- package/dist/utils/performance.d.ts.map +1 -0
- package/dist/utils/performance.js +130 -0
- package/dist/utils/performance.js.map +1 -0
- package/dist/utils/performance.test.d.ts +2 -0
- package/dist/utils/performance.test.d.ts.map +1 -0
- package/dist/utils/performance.test.js +75 -0
- package/dist/utils/performance.test.js.map +1 -0
- package/package.json +75 -0
package/dist/bin.js
ADDED
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration schema with validation
|
|
4
|
+
*/
|
|
5
|
+
declare const ConfigSchema: z.ZodObject<{
|
|
6
|
+
indexPath: z.ZodString;
|
|
7
|
+
search: z.ZodObject<{
|
|
8
|
+
minScore: z.ZodNumber;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
cache: z.ZodObject<{
|
|
11
|
+
maxSizeMB: z.ZodNumber;
|
|
12
|
+
maxEntries: z.ZodNumber;
|
|
13
|
+
ttlMinutes: z.ZodNumber;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
export type Config = z.infer<typeof ConfigSchema>;
|
|
17
|
+
/**
|
|
18
|
+
* Load and validate configuration from environment variables
|
|
19
|
+
* @throws {IndexNotFoundError} If index path doesn't exist
|
|
20
|
+
* @throws {z.ZodError} If configuration is invalid
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadConfig(): Config;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAqBxB;;GAEG;AACH,QAAA,MAAM,YAAY;;;;;;;;;;iBAUhB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CA2BnC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { config as dotenvConfig } from 'dotenv';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { IndexNotFoundError } from './utils/errors.js';
|
|
7
|
+
import { DEFAULT_INDEX_PATH, INDEX_META_FILE, DEFAULT_CACHE_SIZE_MB, DEFAULT_CACHE_ENTRIES, DEFAULT_CACHE_TTL_MINUTES, MIN_SEARCH_SCORE, } from './utils/constants.js';
|
|
8
|
+
dotenvConfig();
|
|
9
|
+
// Get the directory where this module is located
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
const PROJECT_ROOT = join(__dirname, '..');
|
|
13
|
+
/**
|
|
14
|
+
* Configuration schema with validation
|
|
15
|
+
*/
|
|
16
|
+
const ConfigSchema = z.object({
|
|
17
|
+
indexPath: z.string().min(1),
|
|
18
|
+
search: z.object({
|
|
19
|
+
minScore: z.number().min(0).max(10),
|
|
20
|
+
}),
|
|
21
|
+
cache: z.object({
|
|
22
|
+
maxSizeMB: z.number().int().positive(),
|
|
23
|
+
maxEntries: z.number().int().positive(),
|
|
24
|
+
ttlMinutes: z.number().int().positive(),
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Load and validate configuration from environment variables
|
|
29
|
+
* @throws {IndexNotFoundError} If index path doesn't exist
|
|
30
|
+
* @throws {z.ZodError} If configuration is invalid
|
|
31
|
+
*/
|
|
32
|
+
export function loadConfig() {
|
|
33
|
+
// Determine index path - use PROJECT_ROOT instead of process.cwd()
|
|
34
|
+
const indexPath = process.env.GITLAB_DOCS_INDEX_PATH || join(PROJECT_ROOT, DEFAULT_INDEX_PATH);
|
|
35
|
+
// Verify index exists
|
|
36
|
+
const metaPath = join(indexPath, INDEX_META_FILE);
|
|
37
|
+
if (!existsSync(metaPath)) {
|
|
38
|
+
throw new IndexNotFoundError(indexPath);
|
|
39
|
+
}
|
|
40
|
+
// Parse and validate configuration
|
|
41
|
+
const config = ConfigSchema.parse({
|
|
42
|
+
indexPath,
|
|
43
|
+
search: {
|
|
44
|
+
minScore: parseFloat(process.env.GITLAB_DOCS_MIN_SCORE || String(MIN_SEARCH_SCORE)),
|
|
45
|
+
},
|
|
46
|
+
cache: {
|
|
47
|
+
maxSizeMB: parseInt(process.env.GITLAB_DOCS_CACHE_SIZE_MB || String(DEFAULT_CACHE_SIZE_MB), 10),
|
|
48
|
+
maxEntries: parseInt(process.env.GITLAB_DOCS_CACHE_ENTRIES || String(DEFAULT_CACHE_ENTRIES), 10),
|
|
49
|
+
ttlMinutes: parseInt(process.env.GITLAB_DOCS_CACHE_TTL_MIN || String(DEFAULT_CACHE_TTL_MINUTES), 10),
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
return config;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EAAE,CAAC;AAEf,iDAAiD;AACjD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;KACpC,CAAC;IACF,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;QACtC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;QACvC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;KACxC,CAAC;CACH,CAAC,CAAC;AAIH;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,mEAAmE;IACnE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,IAAI,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;IAE/F,sBAAsB;IACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,mCAAmC;IACnC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC;QAChC,SAAS;QACT,MAAM,EAAE;YACN,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAC;SACpF;QACD,KAAK,EAAE;YACL,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,MAAM,CAAC,qBAAqB,CAAC,EAAE,EAAE,CAAC;YAC/F,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,MAAM,CAAC,qBAAqB,CAAC,EAAE,EAAE,CAAC;YAChG,UAAU,EAAE,QAAQ,CAClB,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,MAAM,CAAC,yBAAyB,CAAC,EAC1E,EAAE,CACH;SACF;KACF,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for configuring the content cache
|
|
3
|
+
*/
|
|
4
|
+
export interface CacheOptions {
|
|
5
|
+
/** Maximum cache size in megabytes */
|
|
6
|
+
maxSizeMB: number;
|
|
7
|
+
/** Maximum number of cache entries */
|
|
8
|
+
maxEntries: number;
|
|
9
|
+
/** Time-to-live for cache entries in minutes */
|
|
10
|
+
ttlMinutes: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* LRU cache for storing parsed document content
|
|
14
|
+
* Reduces repeated parsing and improves response times
|
|
15
|
+
*/
|
|
16
|
+
export declare class ContentCache {
|
|
17
|
+
private cache;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new content cache with the specified options
|
|
20
|
+
* @param options - Cache configuration options
|
|
21
|
+
*/
|
|
22
|
+
constructor(options: CacheOptions);
|
|
23
|
+
/**
|
|
24
|
+
* Retrieves a cached value by key
|
|
25
|
+
* @param key - Cache key
|
|
26
|
+
* @returns Cached value or undefined if not found/expired
|
|
27
|
+
*/
|
|
28
|
+
get(key: string): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Stores a value in the cache
|
|
31
|
+
* @param key - Cache key
|
|
32
|
+
* @param value - Value to cache
|
|
33
|
+
*/
|
|
34
|
+
set(key: string, value: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Checks if a key exists in the cache
|
|
37
|
+
* @param key - Cache key to check
|
|
38
|
+
* @returns True if key exists and hasn't expired
|
|
39
|
+
*/
|
|
40
|
+
has(key: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Clears all entries from the cache
|
|
43
|
+
*/
|
|
44
|
+
clear(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Returns the current number of entries in the cache
|
|
47
|
+
* @returns Number of cached entries
|
|
48
|
+
*/
|
|
49
|
+
size(): number;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/content/cache.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAA2B;IAExC;;;OAGG;gBACS,OAAO,EAAE,YAAY;IAWjC;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpC;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIrC;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,IAAI,IAAI,MAAM;CAGf"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { LRUCache } from 'lru-cache';
|
|
2
|
+
/**
|
|
3
|
+
* LRU cache for storing parsed document content
|
|
4
|
+
* Reduces repeated parsing and improves response times
|
|
5
|
+
*/
|
|
6
|
+
export class ContentCache {
|
|
7
|
+
cache;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a new content cache with the specified options
|
|
10
|
+
* @param options - Cache configuration options
|
|
11
|
+
*/
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.cache = new LRUCache({
|
|
14
|
+
max: options.maxEntries,
|
|
15
|
+
maxSize: options.maxSizeMB * 1024 * 1024,
|
|
16
|
+
sizeCalculation: (value) => value.length,
|
|
17
|
+
ttl: options.ttlMinutes * 60 * 1000,
|
|
18
|
+
updateAgeOnGet: true,
|
|
19
|
+
updateAgeOnHas: false,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Retrieves a cached value by key
|
|
24
|
+
* @param key - Cache key
|
|
25
|
+
* @returns Cached value or undefined if not found/expired
|
|
26
|
+
*/
|
|
27
|
+
get(key) {
|
|
28
|
+
return this.cache.get(key);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Stores a value in the cache
|
|
32
|
+
* @param key - Cache key
|
|
33
|
+
* @param value - Value to cache
|
|
34
|
+
*/
|
|
35
|
+
set(key, value) {
|
|
36
|
+
this.cache.set(key, value);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Checks if a key exists in the cache
|
|
40
|
+
* @param key - Cache key to check
|
|
41
|
+
* @returns True if key exists and hasn't expired
|
|
42
|
+
*/
|
|
43
|
+
has(key) {
|
|
44
|
+
return this.cache.has(key);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Clears all entries from the cache
|
|
48
|
+
*/
|
|
49
|
+
clear() {
|
|
50
|
+
this.cache.clear();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns the current number of entries in the cache
|
|
54
|
+
* @returns Number of cached entries
|
|
55
|
+
*/
|
|
56
|
+
size() {
|
|
57
|
+
return this.cache.size;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/content/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAcrC;;;GAGG;AACH,MAAM,OAAO,YAAY;IACf,KAAK,CAA2B;IAExC;;;OAGG;IACH,YAAY,OAAqB;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC;YACxB,GAAG,EAAE,OAAO,CAAC,UAAU;YACvB,OAAO,EAAE,OAAO,CAAC,SAAS,GAAG,IAAI,GAAG,IAAI;YACxC,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM;YACxC,GAAG,EAAE,OAAO,CAAC,UAAU,GAAG,EAAE,GAAG,IAAI;YACnC,cAAc,EAAE,IAAI;YACpB,cAAc,EAAE,KAAK;SACtB,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAW,EAAE,KAAa;QAC5B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../../src/content/cache.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ContentCache } from '../content/cache.js';
|
|
3
|
+
describe('ContentCache', () => {
|
|
4
|
+
it('should store and retrieve values', () => {
|
|
5
|
+
const cache = new ContentCache({
|
|
6
|
+
maxSizeMB: 1,
|
|
7
|
+
maxEntries: 10,
|
|
8
|
+
ttlMinutes: 5,
|
|
9
|
+
});
|
|
10
|
+
cache.set('key1', 'value1');
|
|
11
|
+
expect(cache.get('key1')).toBe('value1');
|
|
12
|
+
});
|
|
13
|
+
it('should return undefined for missing keys', () => {
|
|
14
|
+
const cache = new ContentCache({
|
|
15
|
+
maxSizeMB: 1,
|
|
16
|
+
maxEntries: 10,
|
|
17
|
+
ttlMinutes: 5,
|
|
18
|
+
});
|
|
19
|
+
expect(cache.get('nonexistent')).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
it('should check key existence', () => {
|
|
22
|
+
const cache = new ContentCache({
|
|
23
|
+
maxSizeMB: 1,
|
|
24
|
+
maxEntries: 10,
|
|
25
|
+
ttlMinutes: 5,
|
|
26
|
+
});
|
|
27
|
+
cache.set('key1', 'value1');
|
|
28
|
+
expect(cache.has('key1')).toBe(true);
|
|
29
|
+
expect(cache.has('key2')).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
it('should clear all entries', () => {
|
|
32
|
+
const cache = new ContentCache({
|
|
33
|
+
maxSizeMB: 1,
|
|
34
|
+
maxEntries: 10,
|
|
35
|
+
ttlMinutes: 5,
|
|
36
|
+
});
|
|
37
|
+
cache.set('key1', 'value1');
|
|
38
|
+
cache.set('key2', 'value2');
|
|
39
|
+
expect(cache.size()).toBe(2);
|
|
40
|
+
cache.clear();
|
|
41
|
+
expect(cache.size()).toBe(0);
|
|
42
|
+
expect(cache.has('key1')).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
it('should respect max entries limit', () => {
|
|
45
|
+
const cache = new ContentCache({
|
|
46
|
+
maxSizeMB: 1,
|
|
47
|
+
maxEntries: 2,
|
|
48
|
+
ttlMinutes: 5,
|
|
49
|
+
});
|
|
50
|
+
cache.set('key1', 'value1');
|
|
51
|
+
cache.set('key2', 'value2');
|
|
52
|
+
cache.set('key3', 'value3'); // Should evict key1
|
|
53
|
+
expect(cache.has('key1')).toBe(false);
|
|
54
|
+
expect(cache.has('key2')).toBe(true);
|
|
55
|
+
expect(cache.has('key3')).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=cache.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../../src/content/cache.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown parser using remark for GitLab documentation
|
|
3
|
+
* Handles GitHub Flavored Markdown and frontmatter extraction
|
|
4
|
+
*/
|
|
5
|
+
export declare class MarkdownParser {
|
|
6
|
+
private processor;
|
|
7
|
+
constructor();
|
|
8
|
+
/**
|
|
9
|
+
* Parses markdown content using remark
|
|
10
|
+
* @param content - Raw markdown content
|
|
11
|
+
* @returns Processed markdown string
|
|
12
|
+
*/
|
|
13
|
+
parse(content: string): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Strips markdown formatting for search indexing
|
|
16
|
+
* Removes headers, bold, italic, links, code blocks, and list markers
|
|
17
|
+
* @param content - Markdown content to strip
|
|
18
|
+
* @returns Plain text without markdown formatting
|
|
19
|
+
*/
|
|
20
|
+
stripMarkdown(content: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Extracts YAML frontmatter from markdown content
|
|
23
|
+
* Parses simple key: value pairs from frontmatter block
|
|
24
|
+
* @param content - Markdown content with optional frontmatter
|
|
25
|
+
* @returns Object containing frontmatter data and remaining content
|
|
26
|
+
*/
|
|
27
|
+
extractFrontmatter(content: string): {
|
|
28
|
+
data: Record<string, unknown>;
|
|
29
|
+
content: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/content/parser.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAC;;IAWlB;;;;OAIG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK7C;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAYtC;;;;;OAKG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;CAwBxF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { unified } from 'unified';
|
|
2
|
+
import remarkParse from 'remark-parse';
|
|
3
|
+
import remarkGfm from 'remark-gfm';
|
|
4
|
+
import remarkStringify from 'remark-stringify';
|
|
5
|
+
/**
|
|
6
|
+
* Markdown parser using remark for GitLab documentation
|
|
7
|
+
* Handles GitHub Flavored Markdown and frontmatter extraction
|
|
8
|
+
*/
|
|
9
|
+
export class MarkdownParser {
|
|
10
|
+
processor;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.processor = unified().use(remarkParse).use(remarkGfm).use(remarkStringify, {
|
|
13
|
+
bullet: '-',
|
|
14
|
+
emphasis: '*',
|
|
15
|
+
strong: '*',
|
|
16
|
+
listItemIndent: 'one',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parses markdown content using remark
|
|
21
|
+
* @param content - Raw markdown content
|
|
22
|
+
* @returns Processed markdown string
|
|
23
|
+
*/
|
|
24
|
+
async parse(content) {
|
|
25
|
+
const file = await this.processor.process(content);
|
|
26
|
+
return String(file);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Strips markdown formatting for search indexing
|
|
30
|
+
* Removes headers, bold, italic, links, code blocks, and list markers
|
|
31
|
+
* @param content - Markdown content to strip
|
|
32
|
+
* @returns Plain text without markdown formatting
|
|
33
|
+
*/
|
|
34
|
+
stripMarkdown(content) {
|
|
35
|
+
// Remove markdown syntax for search indexing
|
|
36
|
+
return content
|
|
37
|
+
.replace(/#{1,6}\s/g, '') // Headers
|
|
38
|
+
.replace(/\*\*(.+?)\*\*/g, '$1') // Bold
|
|
39
|
+
.replace(/\*(.+?)\*/g, '$1') // Italic
|
|
40
|
+
.replace(/\[(.+?)\]\(.+?\)/g, '$1') // Links
|
|
41
|
+
.replace(/`{1,3}(.+?)`{1,3}/g, '$1') // Code
|
|
42
|
+
.replace(/^\s*[-*+]\s/gm, '') // Lists
|
|
43
|
+
.trim();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Extracts YAML frontmatter from markdown content
|
|
47
|
+
* Parses simple key: value pairs from frontmatter block
|
|
48
|
+
* @param content - Markdown content with optional frontmatter
|
|
49
|
+
* @returns Object containing frontmatter data and remaining content
|
|
50
|
+
*/
|
|
51
|
+
extractFrontmatter(content) {
|
|
52
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n/;
|
|
53
|
+
const match = content.match(frontmatterRegex);
|
|
54
|
+
if (!match) {
|
|
55
|
+
return { data: {}, content };
|
|
56
|
+
}
|
|
57
|
+
const frontmatter = match[1];
|
|
58
|
+
const data = {};
|
|
59
|
+
// Simple YAML parsing (key: value)
|
|
60
|
+
for (const line of frontmatter.split('\n')) {
|
|
61
|
+
const [key, ...valueParts] = line.split(':');
|
|
62
|
+
if (key && valueParts.length) {
|
|
63
|
+
data[key.trim()] = valueParts.join(':').trim();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
data,
|
|
68
|
+
content: content.replace(frontmatterRegex, ''),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/content/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,eAAe,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,MAAM,OAAO,cAAc;IACjB,SAAS,CAAC;IAElB;QACE,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,eAAe,EAAE;YAC9E,MAAM,EAAE,GAAG;YACX,QAAQ,EAAE,GAAG;YACb,MAAM,EAAE,GAAG;YACX,cAAc,EAAE,KAAK;SACtB,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,OAAe;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAED;;;;;OAKG;IACH,aAAa,CAAC,OAAe;QAC3B,6CAA6C;QAC7C,OAAO,OAAO;aACX,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,UAAU;aACnC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,OAAO;aACvC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,SAAS;aACrC,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,QAAQ;aAC3C,OAAO,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,OAAO;aAC3C,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,QAAQ;aACrC,IAAI,EAAE,CAAC;IACZ,CAAC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,OAAe;QAChC,MAAM,gBAAgB,GAAG,+BAA+B,CAAC;QACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAE9C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;QAC/B,CAAC;QAED,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,IAAI,GAA4B,EAAE,CAAC;QAEzC,mCAAmC;QACnC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,MAAM,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7C,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACjD,CAAC;QACH,CAAC;QAED,OAAO;YACL,IAAI;YACJ,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;SAC/C,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.test.d.ts","sourceRoot":"","sources":["../../src/content/parser.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { MarkdownParser } from '../content/parser.js';
|
|
3
|
+
describe('MarkdownParser', () => {
|
|
4
|
+
const parser = new MarkdownParser();
|
|
5
|
+
describe('stripMarkdown', () => {
|
|
6
|
+
it('should remove headers', () => {
|
|
7
|
+
const input = '# Header 1\n## Header 2';
|
|
8
|
+
const result = parser.stripMarkdown(input);
|
|
9
|
+
expect(result).toBe('Header 1\nHeader 2');
|
|
10
|
+
});
|
|
11
|
+
it('should remove bold formatting', () => {
|
|
12
|
+
const input = 'This is **bold** text';
|
|
13
|
+
const result = parser.stripMarkdown(input);
|
|
14
|
+
expect(result).toBe('This is bold text');
|
|
15
|
+
});
|
|
16
|
+
it('should remove italic formatting', () => {
|
|
17
|
+
const input = 'This is *italic* text';
|
|
18
|
+
const result = parser.stripMarkdown(input);
|
|
19
|
+
expect(result).toBe('This is italic text');
|
|
20
|
+
});
|
|
21
|
+
it('should remove links', () => {
|
|
22
|
+
const input = '[Link text](https://example.com)';
|
|
23
|
+
const result = parser.stripMarkdown(input);
|
|
24
|
+
expect(result).toBe('Link text');
|
|
25
|
+
});
|
|
26
|
+
it('should remove inline code', () => {
|
|
27
|
+
const input = 'Use `code` here';
|
|
28
|
+
const result = parser.stripMarkdown(input);
|
|
29
|
+
expect(result).toBe('Use code here');
|
|
30
|
+
});
|
|
31
|
+
it('should remove code blocks', () => {
|
|
32
|
+
const input = '```javascript\nconst x = 1;\n```';
|
|
33
|
+
const result = parser.stripMarkdown(input);
|
|
34
|
+
// Triple backticks are not fully stripped by the simple regex
|
|
35
|
+
expect(result).toContain('const x = 1');
|
|
36
|
+
});
|
|
37
|
+
it('should remove list markers', () => {
|
|
38
|
+
const input = '- Item 1\n- Item 2\n* Item 3';
|
|
39
|
+
const result = parser.stripMarkdown(input);
|
|
40
|
+
expect(result).toBe('Item 1\nItem 2\nItem 3');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('extractFrontmatter', () => {
|
|
44
|
+
it('should extract YAML frontmatter', () => {
|
|
45
|
+
const input = `---
|
|
46
|
+
title: Test Page
|
|
47
|
+
author: John Doe
|
|
48
|
+
---
|
|
49
|
+
# Content`;
|
|
50
|
+
const result = parser.extractFrontmatter(input);
|
|
51
|
+
expect(result.data.title).toBe('Test Page');
|
|
52
|
+
expect(result.data.author).toBe('John Doe');
|
|
53
|
+
expect(result.content).toBe('# Content');
|
|
54
|
+
});
|
|
55
|
+
it('should handle content without frontmatter', () => {
|
|
56
|
+
const input = '# Just content';
|
|
57
|
+
const result = parser.extractFrontmatter(input);
|
|
58
|
+
expect(result.data).toEqual({});
|
|
59
|
+
expect(result.content).toBe('# Just content');
|
|
60
|
+
});
|
|
61
|
+
it('should handle values with colons', () => {
|
|
62
|
+
const input = `---
|
|
63
|
+
url: https://example.com
|
|
64
|
+
---
|
|
65
|
+
Content`;
|
|
66
|
+
const result = parser.extractFrontmatter(input);
|
|
67
|
+
expect(result.data.url).toBe('https://example.com');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=parser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.test.js","sourceRoot":"","sources":["../../src/content/parser.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,MAAM,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;IAEpC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,KAAK,GAAG,yBAAyB,CAAC;YACxC,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,KAAK,GAAG,uBAAuB,CAAC;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,KAAK,GAAG,uBAAuB,CAAC;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;YAC7B,MAAM,KAAK,GAAG,kCAAkC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;YACnC,MAAM,KAAK,GAAG,iBAAiB,CAAC;YAChC,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;YACnC,MAAM,KAAK,GAAG,kCAAkC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC3C,8DAA8D;YAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,KAAK,GAAG,8BAA8B,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,KAAK,GAAG;;;;UAIV,CAAC;YACL,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,KAAK,GAAG,gBAAgB,CAAC;YAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,KAAK,GAAG;;;QAGZ,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { SearchEngine } from './search/engine.js';
|
|
6
|
+
import { DocumentTree } from './search/document.js';
|
|
7
|
+
import { MarkdownParser } from './content/parser.js';
|
|
8
|
+
import { ContentCache } from './content/cache.js';
|
|
9
|
+
import { loadConfig } from './config.js';
|
|
10
|
+
import { searchGitLabDocsTool, getDocPageTool, listDocSectionsTool, } from './tools/index.js';
|
|
11
|
+
import { TOOL_DEFINITIONS } from './tools/registry.js';
|
|
12
|
+
import { logger } from './utils/logger.js';
|
|
13
|
+
import { SERVER_VERSION, SERVER_NAME } from './utils/constants.js';
|
|
14
|
+
async function main() {
|
|
15
|
+
try {
|
|
16
|
+
// Load configuration
|
|
17
|
+
const config = loadConfig();
|
|
18
|
+
// Initialize components
|
|
19
|
+
const searchEngine = new SearchEngine(config.indexPath);
|
|
20
|
+
searchEngine.loadIndex();
|
|
21
|
+
const docTree = new DocumentTree();
|
|
22
|
+
docTree.buildFromEngine(searchEngine);
|
|
23
|
+
const parser = new MarkdownParser();
|
|
24
|
+
const cache = new ContentCache({
|
|
25
|
+
maxSizeMB: config.cache.maxSizeMB,
|
|
26
|
+
maxEntries: config.cache.maxEntries,
|
|
27
|
+
ttlMinutes: config.cache.ttlMinutes,
|
|
28
|
+
});
|
|
29
|
+
const context = {
|
|
30
|
+
searchEngine,
|
|
31
|
+
docTree,
|
|
32
|
+
parser,
|
|
33
|
+
cache,
|
|
34
|
+
config,
|
|
35
|
+
};
|
|
36
|
+
logger.info(`✅ Loaded ${searchEngine.getDocumentCount()} documents`);
|
|
37
|
+
logger.info(`📚 Built document tree: ${docTree.getSectionCount()} sections`);
|
|
38
|
+
// Create MCP server
|
|
39
|
+
const server = new Server({
|
|
40
|
+
name: SERVER_NAME,
|
|
41
|
+
version: SERVER_VERSION,
|
|
42
|
+
}, {
|
|
43
|
+
capabilities: {
|
|
44
|
+
tools: {},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
// Register list_tools handler
|
|
48
|
+
server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
49
|
+
tools: TOOL_DEFINITIONS,
|
|
50
|
+
}));
|
|
51
|
+
// Register call_tool handler
|
|
52
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
53
|
+
const { name, arguments: args } = request.params;
|
|
54
|
+
try {
|
|
55
|
+
switch (name) {
|
|
56
|
+
case 'searchGitLabDocs':
|
|
57
|
+
return searchGitLabDocsTool(args, context);
|
|
58
|
+
case 'getDocPage':
|
|
59
|
+
return await getDocPageTool(args, context);
|
|
60
|
+
case 'listDocSections':
|
|
61
|
+
return listDocSectionsTool(args, context);
|
|
62
|
+
default:
|
|
63
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: 'text',
|
|
72
|
+
text: `Error: ${errorMessage}`,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
isError: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
logger.info(`🚀 GitLab Docs MCP Server v${SERVER_VERSION}`);
|
|
80
|
+
logger.info(`🔍 Index: ${config.indexPath}`);
|
|
81
|
+
// Connect via stdio
|
|
82
|
+
const transport = new StdioServerTransport();
|
|
83
|
+
await server.connect(transport);
|
|
84
|
+
logger.info('✓ Server initialized successfully');
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
logger.error('❌ Fatal error:', error instanceof Error ? error.message : String(error));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
void main();
|
|
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,11 @@
|
|
|
1
|
+
import type { DocSection } from '../types/models.js';
|
|
2
|
+
import type { SearchEngine } from './engine.js';
|
|
3
|
+
export declare class DocumentTree {
|
|
4
|
+
private sections;
|
|
5
|
+
constructor();
|
|
6
|
+
buildFromEngine(engine: SearchEngine): void;
|
|
7
|
+
getAllSections(): DocSection[];
|
|
8
|
+
getSectionCount(): number;
|
|
9
|
+
getSection(name: string): DocSection | undefined;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/search/document.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAA0B;;IAM1C,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAmC3C,cAAc,IAAI,UAAU,EAAE;IAI9B,eAAe,IAAI,MAAM;IAIzB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;CAGjD"}
|