tailwindcss-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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +159 -0
  3. package/dist/auto-index.d.ts +21 -0
  4. package/dist/auto-index.d.ts.map +1 -0
  5. package/dist/auto-index.js +27 -0
  6. package/dist/auto-index.js.map +1 -0
  7. package/dist/index.d.ts +16 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +67 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/pipeline/chunker.d.ts +61 -0
  12. package/dist/pipeline/chunker.d.ts.map +1 -0
  13. package/dist/pipeline/chunker.js +162 -0
  14. package/dist/pipeline/chunker.js.map +1 -0
  15. package/dist/pipeline/embedder.d.ts +57 -0
  16. package/dist/pipeline/embedder.d.ts.map +1 -0
  17. package/dist/pipeline/embedder.js +108 -0
  18. package/dist/pipeline/embedder.js.map +1 -0
  19. package/dist/pipeline/fetcher.d.ts +63 -0
  20. package/dist/pipeline/fetcher.d.ts.map +1 -0
  21. package/dist/pipeline/fetcher.js +128 -0
  22. package/dist/pipeline/fetcher.js.map +1 -0
  23. package/dist/pipeline/parser.d.ts +73 -0
  24. package/dist/pipeline/parser.d.ts.map +1 -0
  25. package/dist/pipeline/parser.js +127 -0
  26. package/dist/pipeline/parser.js.map +1 -0
  27. package/dist/server.d.ts +47 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +141 -0
  30. package/dist/server.js.map +1 -0
  31. package/dist/storage/database.d.ts +90 -0
  32. package/dist/storage/database.d.ts.map +1 -0
  33. package/dist/storage/database.js +342 -0
  34. package/dist/storage/database.js.map +1 -0
  35. package/dist/storage/search.d.ts +84 -0
  36. package/dist/storage/search.d.ts.map +1 -0
  37. package/dist/storage/search.js +165 -0
  38. package/dist/storage/search.js.map +1 -0
  39. package/dist/tools/check-status.d.ts +35 -0
  40. package/dist/tools/check-status.d.ts.map +1 -0
  41. package/dist/tools/check-status.js +40 -0
  42. package/dist/tools/check-status.js.map +1 -0
  43. package/dist/tools/fetch-docs.d.ts +42 -0
  44. package/dist/tools/fetch-docs.d.ts.map +1 -0
  45. package/dist/tools/fetch-docs.js +98 -0
  46. package/dist/tools/fetch-docs.js.map +1 -0
  47. package/dist/tools/list-utilities.d.ts +49 -0
  48. package/dist/tools/list-utilities.d.ts.map +1 -0
  49. package/dist/tools/list-utilities.js +63 -0
  50. package/dist/tools/list-utilities.js.map +1 -0
  51. package/dist/tools/search-docs.d.ts +44 -0
  52. package/dist/tools/search-docs.d.ts.map +1 -0
  53. package/dist/tools/search-docs.js +53 -0
  54. package/dist/tools/search-docs.js.map +1 -0
  55. package/dist/utils/categories.d.ts +25 -0
  56. package/dist/utils/categories.d.ts.map +1 -0
  57. package/dist/utils/categories.js +240 -0
  58. package/dist/utils/categories.js.map +1 -0
  59. package/dist/utils/config.d.ts +39 -0
  60. package/dist/utils/config.d.ts.map +1 -0
  61. package/dist/utils/config.js +37 -0
  62. package/dist/utils/config.js.map +1 -0
  63. package/dist/utils/query-expansion.d.ts +28 -0
  64. package/dist/utils/query-expansion.d.ts.map +1 -0
  65. package/dist/utils/query-expansion.js +147 -0
  66. package/dist/utils/query-expansion.js.map +1 -0
  67. package/dist/utils/similarity.d.ts +12 -0
  68. package/dist/utils/similarity.d.ts.map +1 -0
  69. package/dist/utils/similarity.js +28 -0
  70. package/dist/utils/similarity.js.map +1 -0
  71. package/package.json +59 -0
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Build the embedding input string for a chunk.
3
+ *
4
+ * Prepends metadata to improve retrieval quality:
5
+ * - Library context ("Tailwind CSS: {docTitle}")
6
+ * - Section context (heading breadcrumb)
7
+ * - Actual content
8
+ */
9
+ export function buildEmbeddingInput(docTitle, heading, content) {
10
+ return `Tailwind CSS: ${docTitle}\n\n${heading}\n\n${content}`;
11
+ }
12
+ /**
13
+ * Normalize a vector to unit length (L2 normalization).
14
+ */
15
+ export function normalize(vector) {
16
+ let magnitude = 0;
17
+ for (let i = 0; i < vector.length; i++) {
18
+ magnitude += vector[i] * vector[i];
19
+ }
20
+ magnitude = Math.sqrt(magnitude);
21
+ if (magnitude === 0)
22
+ return vector;
23
+ const result = new Float32Array(vector.length);
24
+ for (let i = 0; i < vector.length; i++) {
25
+ result[i] = vector[i] / magnitude;
26
+ }
27
+ return result;
28
+ }
29
+ /**
30
+ * Build an Embedder from an already-loaded pipeline extractor.
31
+ * Extracted for reuse between createEmbedder and loadCachedEmbedder.
32
+ */
33
+ function buildEmbedder(extractor, config) {
34
+ async function embed(text, options) {
35
+ const input = options?.isQuery ? `${config.queryPrefix}${text}` : text;
36
+ const output = await extractor(input, { pooling: "cls", normalize: false });
37
+ const list = output.tolist();
38
+ if (!Array.isArray(list) || !Array.isArray(list[0])) {
39
+ throw new Error(`Unexpected embedding output shape: expected number[][], got ${typeof list}`);
40
+ }
41
+ const data = list[0];
42
+ if (data.length !== config.embeddingDimensions) {
43
+ throw new Error(`Embedding dimension mismatch: expected ${config.embeddingDimensions}, got ${data.length}`);
44
+ }
45
+ return normalize(new Float32Array(data));
46
+ }
47
+ return {
48
+ embed,
49
+ async embedBatch(texts, options) {
50
+ const results = [];
51
+ for (const text of texts) {
52
+ results.push(await embed(text, options));
53
+ }
54
+ return results;
55
+ },
56
+ isReady: () => true,
57
+ };
58
+ }
59
+ /**
60
+ * Try to load the embedder from local cache only (no network).
61
+ * Returns null if the model is not cached or cache is corrupted.
62
+ *
63
+ * CONCURRENCY: This function and `createEmbedder` both mutate the shared
64
+ * `env` singleton from @huggingface/transformers. They must NOT be called
65
+ * concurrently — always await one before starting the other.
66
+ */
67
+ export async function loadCachedEmbedder(config) {
68
+ const { pipeline, env } = await import("@huggingface/transformers");
69
+ env.cacheDir = config.modelCacheDir;
70
+ env.allowRemoteModels = false;
71
+ try {
72
+ const extractor = await pipeline("feature-extraction", config.embeddingModel, {
73
+ dtype: "fp32",
74
+ });
75
+ return buildEmbedder(extractor, config);
76
+ }
77
+ catch (error) {
78
+ console.error("[tailwindcss-docs-mcp] Cache load failed (will download):", error);
79
+ return null;
80
+ }
81
+ finally {
82
+ env.allowRemoteModels = true;
83
+ }
84
+ }
85
+ /**
86
+ * Create an embedder, downloading the model if needed.
87
+ *
88
+ * The model (snowflake-arctic-embed-xs) is downloaded on first use and cached locally.
89
+ * Subsequent calls load from cache (~27 MB model file).
90
+ *
91
+ * For search queries, the model requires prepending a specific prefix:
92
+ * "Represent this sentence for searching relevant passages: "
93
+ * This is handled automatically when `isQuery: true` is passed to embed().
94
+ *
95
+ * CONCURRENCY: This function and `loadCachedEmbedder` both mutate the shared
96
+ * `env` singleton from @huggingface/transformers. They must NOT be called
97
+ * concurrently — always await one before starting the other.
98
+ */
99
+ export async function createEmbedder(config) {
100
+ const { pipeline, env } = await import("@huggingface/transformers");
101
+ env.cacheDir = config.modelCacheDir;
102
+ env.allowRemoteModels = true;
103
+ const extractor = await pipeline("feature-extraction", config.embeddingModel, {
104
+ dtype: "fp32",
105
+ });
106
+ return buildEmbedder(extractor, config);
107
+ }
108
+ //# sourceMappingURL=embedder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedder.js","sourceRoot":"","sources":["../../src/pipeline/embedder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { Config, TailwindVersion } from "../utils/config.js";
2
+ /**
3
+ * Options for fetching documentation from GitHub.
4
+ */
5
+ export interface FetchOptions {
6
+ /** Tailwind CSS major version (maps to branch: master for v3, next for v4) */
7
+ version: TailwindVersion;
8
+ /** Force re-fetch even if cached locally */
9
+ force: boolean;
10
+ }
11
+ /**
12
+ * Result of a fetch operation.
13
+ */
14
+ export interface FetchResult {
15
+ /** Number of MDX files fetched */
16
+ fileCount: number;
17
+ /** Directory where raw files were saved */
18
+ outputDir: string;
19
+ /** Whether files were fetched from network or loaded from cache */
20
+ cached: boolean;
21
+ /** Number of files skipped due to fetch errors (0 when cached) */
22
+ skipped: number;
23
+ }
24
+ /**
25
+ * A single raw MDX file fetched from the repository.
26
+ */
27
+ export interface RawMdxFile {
28
+ /** Filename without extension (e.g., "padding") */
29
+ slug: string;
30
+ /** Raw MDX content */
31
+ content: string;
32
+ /** File path relative to docs directory */
33
+ path: string;
34
+ }
35
+ /**
36
+ * Fetch Tailwind CSS documentation MDX files from the GitHub repository.
37
+ *
38
+ * Uses the GitHub REST API (2 calls) for file discovery, then downloads
39
+ * raw content from raw.githubusercontent.com (no rate limits, no auth needed).
40
+ * Files are cached on disk at `~/.tailwindcss-docs-mcp/raw/{version}/`.
41
+ * Subsequent calls return cached files unless `force: true`.
42
+ */
43
+ export declare function fetchDocs(config: Config, options: FetchOptions): Promise<FetchResult>;
44
+ /** Maximum concurrent file downloads. */
45
+ export declare const FETCH_CONCURRENCY = 10;
46
+ /** Maximum consecutive fetch failures before aborting. */
47
+ export declare const MAX_CONSECUTIVE_FAILURES = 5;
48
+ /**
49
+ * Fetch raw file content from raw.githubusercontent.com in parallel batches.
50
+ * Aborts after MAX_CONSECUTIVE_FAILURES consecutive failures.
51
+ * Returns counts of successfully fetched and skipped files.
52
+ */
53
+ export declare function fetchRawFiles(branch: string, files: {
54
+ path?: string;
55
+ }[], outputDir: string): Promise<{
56
+ fetched: number;
57
+ skipped: number;
58
+ }>;
59
+ /**
60
+ * Read cached MDX files from disk for a given version.
61
+ */
62
+ export declare function readCachedDocs(config: Config, version: TailwindVersion): RawMdxFile[];
63
+ //# sourceMappingURL=fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/pipeline/fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGlE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,OAAO,EAAE,eAAe,CAAC;IACzB,4CAA4C;IAC5C,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,MAAM,EAAE,OAAO,CAAC;IAChB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAmCD;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA2C3F;AAED,yCAAyC;AACzC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,0DAA0D;AAC1D,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAkC1C;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAC1B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA0B/C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,UAAU,EAAE,CAYrF"}
@@ -0,0 +1,128 @@
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
2
+ import { basename, join } from "node:path";
3
+ import { GITHUB_REPO, VERSION_BRANCH_MAP } from "../utils/config.js";
4
+ const GITHUB_API_BASE = "https://api.github.com";
5
+ const RAW_CONTENT_BASE = "https://raw.githubusercontent.com";
6
+ /**
7
+ * Fetch JSON from the GitHub REST API with proper headers and optional auth.
8
+ */
9
+ async function githubApiFetch(path) {
10
+ const url = `${GITHUB_API_BASE}${path}`;
11
+ const headers = {
12
+ Accept: "application/vnd.github+json",
13
+ "User-Agent": "tailwindcss-docs-mcp",
14
+ };
15
+ const token = process.env.GITHUB_TOKEN;
16
+ if (token) {
17
+ headers.Authorization = `Bearer ${token}`;
18
+ }
19
+ const response = await fetch(url, { headers });
20
+ if (!response.ok) {
21
+ throw new Error(`GitHub API error ${response.status}: ${url}`);
22
+ }
23
+ return response.json();
24
+ }
25
+ /**
26
+ * Fetch Tailwind CSS documentation MDX files from the GitHub repository.
27
+ *
28
+ * Uses the GitHub REST API (2 calls) for file discovery, then downloads
29
+ * raw content from raw.githubusercontent.com (no rate limits, no auth needed).
30
+ * Files are cached on disk at `~/.tailwindcss-docs-mcp/raw/{version}/`.
31
+ * Subsequent calls return cached files unless `force: true`.
32
+ */
33
+ export async function fetchDocs(config, options) {
34
+ const { version, force } = options;
35
+ const outputDir = join(config.rawDir, version);
36
+ // Check cache: if directory exists and has .mdx files, skip unless force
37
+ if (!force && existsSync(outputDir)) {
38
+ const cached = readdirSync(outputDir).filter((f) => f.endsWith(".mdx"));
39
+ if (cached.length > 0) {
40
+ return { fileCount: cached.length, outputDir, cached: true, skipped: 0 };
41
+ }
42
+ }
43
+ mkdirSync(outputDir, { recursive: true });
44
+ const branch = VERSION_BRANCH_MAP[version];
45
+ // Step 1: Get the git tree recursively to list all files (2 API calls)
46
+ const refData = await githubApiFetch(`/repos/${GITHUB_REPO.owner}/${GITHUB_REPO.repo}/git/ref/heads/${branch}`);
47
+ const commitSha = refData.object.sha;
48
+ const treeData = await githubApiFetch(`/repos/${GITHUB_REPO.owner}/${GITHUB_REPO.repo}/git/trees/${commitSha}?recursive=true`);
49
+ // Step 2: Filter for MDX files under the docs path
50
+ const mdxFiles = treeData.tree.filter((item) => item.type === "blob" &&
51
+ item.path?.startsWith(`${GITHUB_REPO.docsPath}/`) &&
52
+ item.path.endsWith(".mdx"));
53
+ // Step 3: Fetch raw file content in parallel batches
54
+ const blobResult = await fetchRawFiles(branch, mdxFiles, outputDir);
55
+ return {
56
+ fileCount: blobResult.fetched,
57
+ outputDir,
58
+ cached: false,
59
+ skipped: blobResult.skipped,
60
+ };
61
+ }
62
+ /** Maximum concurrent file downloads. */
63
+ export const FETCH_CONCURRENCY = 10;
64
+ /** Maximum consecutive fetch failures before aborting. */
65
+ export const MAX_CONSECUTIVE_FAILURES = 5;
66
+ /** Fetch a single raw file and return its path + content. */
67
+ async function fetchOneRawFile(branch, filePath) {
68
+ const url = `${RAW_CONTENT_BASE}/${GITHUB_REPO.owner}/${GITHUB_REPO.repo}/${branch}/${filePath}`;
69
+ const res = await fetch(url);
70
+ if (!res.ok)
71
+ throw new Error(`HTTP ${res.status}: ${filePath}`);
72
+ return { path: filePath, content: await res.text() };
73
+ }
74
+ /** Process settled batch results, writing files and tracking failures. */
75
+ function processBatchResults(results, outputDir, state) {
76
+ for (const result of results) {
77
+ if (result.status === "fulfilled") {
78
+ writeFileSync(join(outputDir, basename(result.value.path)), result.value.content, "utf-8");
79
+ state.fetched++;
80
+ state.consecutiveFailures = 0;
81
+ }
82
+ else {
83
+ state.skipped++;
84
+ state.consecutiveFailures++;
85
+ const msg = result.reason instanceof Error ? result.reason.message : String(result.reason);
86
+ console.warn(`[tailwindcss-docs-mcp] Failed to fetch: ${msg}`);
87
+ if (state.consecutiveFailures >= MAX_CONSECUTIVE_FAILURES)
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ /**
93
+ * Fetch raw file content from raw.githubusercontent.com in parallel batches.
94
+ * Aborts after MAX_CONSECUTIVE_FAILURES consecutive failures.
95
+ * Returns counts of successfully fetched and skipped files.
96
+ */
97
+ export async function fetchRawFiles(branch, files, outputDir) {
98
+ const validFiles = files.filter((f) => !!f.path);
99
+ const state = { fetched: 0, skipped: 0, consecutiveFailures: 0 };
100
+ for (let i = 0; i < validFiles.length; i += FETCH_CONCURRENCY) {
101
+ if (state.consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
102
+ console.warn(`[tailwindcss-docs-mcp] Aborting: ${MAX_CONSECUTIVE_FAILURES} consecutive fetch failures.`);
103
+ break;
104
+ }
105
+ const batch = validFiles.slice(i, i + FETCH_CONCURRENCY);
106
+ const results = await Promise.allSettled(batch.map((file) => fetchOneRawFile(branch, file.path)));
107
+ processBatchResults(results, outputDir, state);
108
+ }
109
+ if (state.skipped > 0) {
110
+ console.warn(`[tailwindcss-docs-mcp] Skipped ${state.skipped} of ${validFiles.length} files due to fetch errors.`);
111
+ }
112
+ return { fetched: state.fetched, skipped: state.skipped };
113
+ }
114
+ /**
115
+ * Read cached MDX files from disk for a given version.
116
+ */
117
+ export function readCachedDocs(config, version) {
118
+ const dir = join(config.rawDir, version);
119
+ if (!existsSync(dir))
120
+ return [];
121
+ const files = readdirSync(dir).filter((f) => f.endsWith(".mdx"));
122
+ return files.map((filename) => ({
123
+ slug: basename(filename, ".mdx"),
124
+ content: readFileSync(join(dir, filename), "utf-8"),
125
+ path: `${GITHUB_REPO.docsPath}/${filename}`,
126
+ }));
127
+ }
128
+ //# sourceMappingURL=fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../src/pipeline/fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * A parsed and cleaned document ready for chunking.
3
+ */
4
+ export interface CleanDocument {
5
+ /** URL slug (e.g., "padding", "flex-direction", "dark-mode") */
6
+ slug: string;
7
+ /** Document title from frontmatter */
8
+ title: string;
9
+ /** Document description from frontmatter */
10
+ description: string;
11
+ /** Clean markdown content (JSX and imports stripped) */
12
+ content: string;
13
+ /** Full URL to the documentation page */
14
+ url: string;
15
+ /** Tailwind CSS version */
16
+ version: string;
17
+ }
18
+ /**
19
+ * Frontmatter extracted from an MDX file.
20
+ */
21
+ export interface Frontmatter {
22
+ title: string;
23
+ description: string;
24
+ [key: string]: unknown;
25
+ }
26
+ /**
27
+ * Parse raw MDX content into a clean markdown document.
28
+ *
29
+ * Processing pipeline:
30
+ * 1. stripFrontmatter — extract title, description into metadata
31
+ * 2. stripImportStatements — remove `import ... from ...` lines
32
+ * 3. stripJsxComponents — remove <Component> tags, keep inner text
33
+ * 4. normalizeCodeBlocks — strip `{{ filename: '...' }}` metadata
34
+ * 5. preserveMarkdownStructure — keep headings, lists, code, links
35
+ */
36
+ export declare function parseMdx(raw: string, slug: string, version: string): CleanDocument;
37
+ /**
38
+ * Extract frontmatter from raw MDX content.
39
+ *
40
+ * Parses YAML frontmatter between `---` delimiters.
41
+ * Returns the frontmatter data and the remaining content.
42
+ */
43
+ export declare function stripFrontmatter(raw: string): {
44
+ frontmatter: Frontmatter;
45
+ content: string;
46
+ };
47
+ /**
48
+ * Remove ES module import statements from MDX content.
49
+ *
50
+ * Handles both single-line and multi-line imports:
51
+ * - `import { Tip } from '@/components/Tip'`
52
+ * - `import utilities from 'utilities?plugin=padding'`
53
+ */
54
+ export declare function stripImportStatements(content: string): string;
55
+ /**
56
+ * Remove JSX component tags, optionally preserving inner text content.
57
+ *
58
+ * - Self-closing tags: `<TipGood />` -> removed entirely
59
+ * - Wrapper tags: `<TipGood>Use padding</TipGood>` -> `Use padding`
60
+ * - Nested tags: `<SnippetGroup><Snippet>...</Snippet></SnippetGroup>` -> content only
61
+ */
62
+ export declare function stripJsxComponents(content: string): string;
63
+ /**
64
+ * Normalize code block metadata syntax.
65
+ *
66
+ * Strips `{{ filename: '...' }}` annotations from fenced code blocks
67
+ * while preserving the language identifier and code content.
68
+ *
69
+ * Input: ` ```js {{ filename: 'tailwind.config.js' }} `
70
+ * Output: ` ```js `
71
+ */
72
+ export declare function normalizeCodeBlocks(content: string): string;
73
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/pipeline/parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAgBlF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC7C,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB,CAuBA;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM7D;AAoBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAuB1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Parse raw MDX content into a clean markdown document.
3
+ *
4
+ * Processing pipeline:
5
+ * 1. stripFrontmatter — extract title, description into metadata
6
+ * 2. stripImportStatements — remove `import ... from ...` lines
7
+ * 3. stripJsxComponents — remove <Component> tags, keep inner text
8
+ * 4. normalizeCodeBlocks — strip `{{ filename: '...' }}` metadata
9
+ * 5. preserveMarkdownStructure — keep headings, lists, code, links
10
+ */
11
+ export function parseMdx(raw, slug, version) {
12
+ const { frontmatter, content: afterFrontmatter } = stripFrontmatter(raw);
13
+ let content = stripImportStatements(afterFrontmatter);
14
+ content = stripExportStatements(content);
15
+ content = stripJsxComponents(content);
16
+ content = normalizeCodeBlocks(content);
17
+ content = collapseBlankLines(content);
18
+ return {
19
+ slug,
20
+ title: frontmatter.title,
21
+ description: frontmatter.description,
22
+ content: content.trim(),
23
+ url: `https://tailwindcss.com/docs/${slug}`,
24
+ version,
25
+ };
26
+ }
27
+ /**
28
+ * Extract frontmatter from raw MDX content.
29
+ *
30
+ * Parses YAML frontmatter between `---` delimiters.
31
+ * Returns the frontmatter data and the remaining content.
32
+ */
33
+ export function stripFrontmatter(raw) {
34
+ const match = raw.match(/^---\n([\s\S]*?)\n---\n?/);
35
+ if (!match) {
36
+ return {
37
+ frontmatter: { title: "", description: "" },
38
+ content: raw,
39
+ };
40
+ }
41
+ const yamlBlock = match[1];
42
+ const frontmatter = { title: "", description: "" };
43
+ for (const line of yamlBlock.split("\n")) {
44
+ const kvMatch = line.match(/^(\w+):\s*"?(.*?)"?\s*$/);
45
+ if (kvMatch) {
46
+ frontmatter[kvMatch[1]] = kvMatch[2];
47
+ }
48
+ }
49
+ return {
50
+ frontmatter,
51
+ content: raw.slice(match[0].length),
52
+ };
53
+ }
54
+ /**
55
+ * Remove ES module import statements from MDX content.
56
+ *
57
+ * Handles both single-line and multi-line imports:
58
+ * - `import { Tip } from '@/components/Tip'`
59
+ * - `import utilities from 'utilities?plugin=padding'`
60
+ */
61
+ export function stripImportStatements(content) {
62
+ // Single-line imports
63
+ let result = content.replace(/^import\s+.*from\s+['"].*['"];?\s*$/gm, "");
64
+ // Default/namespace imports without from
65
+ result = result.replace(/^import\s+['"].*['"];?\s*$/gm, "");
66
+ return result;
67
+ }
68
+ /**
69
+ * Remove ES module export statements from MDX content.
70
+ *
71
+ * Handles:
72
+ * - `export const classes = { ... }`
73
+ * - Multi-line export blocks
74
+ */
75
+ function stripExportStatements(content) {
76
+ // Multi-line export blocks: export const ... = { ... }
77
+ let result = content.replace(/^export\s+(?:const|let|var|function)\s+[\s\S]*?(?:\n\}|\n\);?)\s*$/gm, "");
78
+ // Single-line exports
79
+ result = result.replace(/^export\s+.*$/gm, "");
80
+ return result;
81
+ }
82
+ /**
83
+ * Remove JSX component tags, optionally preserving inner text content.
84
+ *
85
+ * - Self-closing tags: `<TipGood />` -> removed entirely
86
+ * - Wrapper tags: `<TipGood>Use padding</TipGood>` -> `Use padding`
87
+ * - Nested tags: `<SnippetGroup><Snippet>...</Snippet></SnippetGroup>` -> content only
88
+ */
89
+ export function stripJsxComponents(content) {
90
+ // Protect code blocks from JSX stripping
91
+ const codeBlocks = [];
92
+ let result = content.replace(/```[\s\S]*?```/g, (match) => {
93
+ codeBlocks.push(match);
94
+ return `__CODE_BLOCK_${codeBlocks.length - 1}__`;
95
+ });
96
+ // Remove self-closing JSX tags: <Component /> or <Component prop="val" />
97
+ result = result.replace(/<[A-Z][a-zA-Z]*(?:\s+[^>]*)?\s*\/>/g, "");
98
+ // Remove JSX wrapper tags, keeping inner text (handle nested by repeating)
99
+ let prev = "";
100
+ while (prev !== result) {
101
+ prev = result;
102
+ // Tags with text content: <Component ...>text</Component>
103
+ result = result.replace(/<([A-Z][a-zA-Z]*)[^>]*>([\s\S]*?)<\/\1>/g, "$2");
104
+ }
105
+ // Restore code blocks
106
+ result = result.replace(/__CODE_BLOCK_(\d+)__/g, (_, idx) => codeBlocks[Number(idx)]);
107
+ return result;
108
+ }
109
+ /**
110
+ * Normalize code block metadata syntax.
111
+ *
112
+ * Strips `{{ filename: '...' }}` annotations from fenced code blocks
113
+ * while preserving the language identifier and code content.
114
+ *
115
+ * Input: ` ```js {{ filename: 'tailwind.config.js' }} `
116
+ * Output: ` ```js `
117
+ */
118
+ export function normalizeCodeBlocks(content) {
119
+ return content.replace(/(```\w*(?:-\w+)*)\s*\{\{[\s\S]*?\}\}/g, "$1");
120
+ }
121
+ /**
122
+ * Collapse runs of 3+ blank lines into 2.
123
+ */
124
+ function collapseBlankLines(content) {
125
+ return content.replace(/\n{3,}/g, "\n\n");
126
+ }
127
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/pipeline/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
2
+ import type { Embedder } from "./pipeline/embedder.js";
3
+ import type { Database } from "./storage/database.js";
4
+ import type { Config } from "./utils/config.js";
5
+ /**
6
+ * MCP tool names exposed by this server.
7
+ */
8
+ export declare const TOOL_NAMES: {
9
+ readonly FETCH_DOCS: "fetch_docs";
10
+ readonly SEARCH_DOCS: "search_docs";
11
+ readonly LIST_UTILITIES: "list_utilities";
12
+ readonly CHECK_STATUS: "check_status";
13
+ };
14
+ /**
15
+ * Embedder loading status for observability.
16
+ */
17
+ export type EmbedderStatus = "pending" | "downloading" | "ready" | "failed";
18
+ /**
19
+ * Server dependencies injected at startup.
20
+ * Embedder may be null if the model is still downloading.
21
+ */
22
+ export interface ServerDeps {
23
+ config: Config;
24
+ db: Database;
25
+ embedder: Embedder | null;
26
+ }
27
+ /**
28
+ * Handle returned by createServer for post-initialization updates.
29
+ */
30
+ export interface ServerHandle {
31
+ /** Set the embedder once it finishes loading in the background. */
32
+ setEmbedder(embedder: Embedder): void;
33
+ /** Update the embedder loading status for observability. */
34
+ setEmbedderStatus(status: EmbedderStatus): void;
35
+ /** Get the current embedder loading status. */
36
+ getEmbedderStatus(): EmbedderStatus;
37
+ }
38
+ export declare const EMBEDDER_STATUS_MESSAGES: Record<EmbedderStatus, string>;
39
+ /**
40
+ * Create and configure the MCP server with all tool handlers.
41
+ *
42
+ * The server starts immediately even if the embedder is not yet available.
43
+ * Tools that require the embedder (fetch_docs, search_docs) will throw
44
+ * an error if called before the model has finished loading.
45
+ */
46
+ export declare function createServer(deps: ServerDeps, transport?: Transport): Promise<ServerHandle>;
47
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAKtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAMhD;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;CAKb,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5E;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtC,4DAA4D;IAC5D,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAChD,+CAA+C;IAC/C,iBAAiB,IAAI,cAAc,CAAC;CACrC;AAED,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAKnE,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CAyIjG"}