react-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/README.md +217 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +31 -0
- package/dist/config.js.map +1 -0
- package/dist/docsManager.d.ts +57 -0
- package/dist/docsManager.d.ts.map +1 -0
- package/dist/docsManager.js +185 -0
- package/dist/docsManager.js.map +1 -0
- package/dist/embeddingService.d.ts +52 -0
- package/dist/embeddingService.d.ts.map +1 -0
- package/dist/embeddingService.js +113 -0
- package/dist/embeddingService.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +272 -0
- package/dist/index.js.map +1 -0
- package/dist/markdownParser.d.ts +25 -0
- package/dist/markdownParser.d.ts.map +1 -0
- package/dist/markdownParser.js +85 -0
- package/dist/markdownParser.js.map +1 -0
- package/dist/searchEngine.d.ts +66 -0
- package/dist/searchEngine.d.ts.map +1 -0
- package/dist/searchEngine.js +261 -0
- package/dist/searchEngine.js.map +1 -0
- package/dist/summarizer.d.ts +18 -0
- package/dist/summarizer.d.ts.map +1 -0
- package/dist/summarizer.js +76 -0
- package/dist/summarizer.js.map +1 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# React Docs MCP Server
|
|
2
|
+
|
|
3
|
+
AI-powered semantic search over React documentation for Claude, Cursor, and other MCP clients.
|
|
4
|
+
|
|
5
|
+
## 🚀 Installation (One Command)
|
|
6
|
+
|
|
7
|
+
### Claude Code
|
|
8
|
+
```bash
|
|
9
|
+
claude mcp add --transport stdio react-docs -- npx react-docs-mcp
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### Claude Desktop
|
|
13
|
+
|
|
14
|
+
Edit: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"mcpServers": {
|
|
19
|
+
"react-docs": {
|
|
20
|
+
"command": "npx",
|
|
21
|
+
"args": ["-y", "react-docs-mcp"]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Cursor
|
|
28
|
+
|
|
29
|
+
**Settings** → **Features** → **MCP** → Add server:
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"react-docs": {
|
|
33
|
+
"command": "npx",
|
|
34
|
+
"args": ["-y", "react-docs-mcp"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**That's it!** Restart your editor and ask about React.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **🔍 Semantic Search**: AI-powered search using embeddings for conceptual matches
|
|
46
|
+
- **⚡ Fast Results**: In-memory vector search with hybrid keyword+semantic ranking
|
|
47
|
+
- **📦 Zero Config**: Works with `npx` - no installation needed
|
|
48
|
+
- **🤖 Local AI**: Runs embeddings locally (no API costs)
|
|
49
|
+
- **📝 Concise Responses**: Returns summaries instead of full documentation
|
|
50
|
+
- **🔄 Auto-sync**: Pulls latest docs from react.dev automatically
|
|
51
|
+
|
|
52
|
+
## Configuration
|
|
53
|
+
|
|
54
|
+
### For Claude Desktop
|
|
55
|
+
|
|
56
|
+
Add to your Claude Desktop configuration file:
|
|
57
|
+
|
|
58
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
59
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"react-docs": {
|
|
65
|
+
"command": "node",
|
|
66
|
+
"args": ["/absolute/path/to/reactDocsMcp/dist/index.js"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### For Claude Code
|
|
73
|
+
|
|
74
|
+
Add to your MCP settings configuration:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"react-docs": {
|
|
80
|
+
"command": "node",
|
|
81
|
+
"args": ["/absolute/path/to/reactDocsMcp/dist/index.js"]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Usage
|
|
88
|
+
|
|
89
|
+
Once configured, the server provides the following capabilities to AI agents:
|
|
90
|
+
|
|
91
|
+
### Tools
|
|
92
|
+
|
|
93
|
+
#### `search_react_docs`
|
|
94
|
+
|
|
95
|
+
Search across React documentation.
|
|
96
|
+
|
|
97
|
+
**Parameters**:
|
|
98
|
+
- `query` (required): Search query string
|
|
99
|
+
- `section` (optional): Filter by section (learn, reference, blog, community)
|
|
100
|
+
- `limit` (optional): Maximum number of results (default: 10, max: 50)
|
|
101
|
+
|
|
102
|
+
**Example**:
|
|
103
|
+
```
|
|
104
|
+
Search for "useState hook" in the learn section
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### `get_doc`
|
|
108
|
+
|
|
109
|
+
Get a specific documentation page.
|
|
110
|
+
|
|
111
|
+
**Parameters**:
|
|
112
|
+
- `path` (required): Document path (e.g., "learn/hooks/useState")
|
|
113
|
+
|
|
114
|
+
**Example**:
|
|
115
|
+
```
|
|
116
|
+
Get the useState documentation
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### `list_sections`
|
|
120
|
+
|
|
121
|
+
List all available documentation sections.
|
|
122
|
+
|
|
123
|
+
**Example**:
|
|
124
|
+
```
|
|
125
|
+
What sections are available?
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### `update_docs`
|
|
129
|
+
|
|
130
|
+
Pull latest documentation from the Git repository.
|
|
131
|
+
|
|
132
|
+
**Example**:
|
|
133
|
+
```
|
|
134
|
+
Update the React documentation
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Resources
|
|
138
|
+
|
|
139
|
+
The server exposes documentation as resources with the URI pattern:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
react-docs://{section}/{path}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Examples**:
|
|
146
|
+
- `react-docs://learn` - List all learn section docs
|
|
147
|
+
- `react-docs://learn/hooks/useState` - Get useState documentation
|
|
148
|
+
- `react-docs://reference/react/Component` - Get Component API reference
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
### Run in Development Mode
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm run dev
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Build
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
npm run build
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Project Structure
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
reactDocsMcp/
|
|
168
|
+
├── src/
|
|
169
|
+
│ ├── index.ts # MCP server entry point
|
|
170
|
+
│ ├── docsManager.ts # Git & file operations
|
|
171
|
+
│ ├── markdownParser.ts # Markdown parsing
|
|
172
|
+
│ ├── searchEngine.ts # Search implementation
|
|
173
|
+
│ ├── types.ts # TypeScript types
|
|
174
|
+
│ └── config.ts # Configuration
|
|
175
|
+
├── data/
|
|
176
|
+
│ └── react-dev-repo/ # Cloned React docs (auto-created)
|
|
177
|
+
├── dist/ # Compiled output
|
|
178
|
+
└── TECHNICAL_SPEC.md # Technical documentation
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## How It Works
|
|
182
|
+
|
|
183
|
+
1. **Initialization**: On first run, clones the official React documentation repository
|
|
184
|
+
2. **Indexing**: Parses all markdown files and builds an in-memory search index
|
|
185
|
+
3. **Search**: Provides keyword-based search with relevance scoring
|
|
186
|
+
4. **Updates**: Can pull latest changes from the repository and re-index
|
|
187
|
+
|
|
188
|
+
## Troubleshooting
|
|
189
|
+
|
|
190
|
+
### Server won't start
|
|
191
|
+
|
|
192
|
+
- Ensure Node.js 18+ is installed
|
|
193
|
+
- Check that the build completed successfully (`npm run build`)
|
|
194
|
+
- Verify the path in your MCP configuration is absolute and correct
|
|
195
|
+
|
|
196
|
+
### No search results
|
|
197
|
+
|
|
198
|
+
- The repository may still be cloning (check console output)
|
|
199
|
+
- Try running `update_docs` tool to refresh the index
|
|
200
|
+
|
|
201
|
+
### Git clone fails
|
|
202
|
+
|
|
203
|
+
- Check internet connection
|
|
204
|
+
- Verify Git is installed and accessible
|
|
205
|
+
- Check firewall/proxy settings
|
|
206
|
+
|
|
207
|
+
## Technical Details
|
|
208
|
+
|
|
209
|
+
For detailed technical information, see [TECHNICAL_SPEC.md](./TECHNICAL_SPEC.md).
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT
|
|
214
|
+
|
|
215
|
+
## Contributing
|
|
216
|
+
|
|
217
|
+
This is a personal project for connecting React documentation to AI coding agents. Feel free to fork and modify for your own use.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config.ts
|
|
3
|
+
* Centralize configuration constants
|
|
4
|
+
*/
|
|
5
|
+
declare const CONFIG: {
|
|
6
|
+
repo: {
|
|
7
|
+
url: string;
|
|
8
|
+
localPath: string;
|
|
9
|
+
contentPath: string;
|
|
10
|
+
};
|
|
11
|
+
search: {
|
|
12
|
+
defaultLimit: number;
|
|
13
|
+
maxLimit: number;
|
|
14
|
+
minScore: number;
|
|
15
|
+
semanticSearchEnabled: boolean;
|
|
16
|
+
semanticMinSimilarity: number;
|
|
17
|
+
hybridKeywordWeight: number;
|
|
18
|
+
hybridSemanticWeight: number;
|
|
19
|
+
};
|
|
20
|
+
server: {
|
|
21
|
+
name: string;
|
|
22
|
+
version: string;
|
|
23
|
+
};
|
|
24
|
+
sections: readonly ["learn", "reference", "blog", "community"];
|
|
25
|
+
};
|
|
26
|
+
export default CONFIG;
|
|
27
|
+
export type Section = typeof CONFIG.sections[number];
|
|
28
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;CA2BX,CAAC;AAEF,eAAe,MAAM,CAAC;AACtB,MAAM,MAAM,OAAO,GAAG,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config.ts
|
|
3
|
+
* Centralize configuration constants
|
|
4
|
+
*/
|
|
5
|
+
const CONFIG = {
|
|
6
|
+
// Repository settings
|
|
7
|
+
repo: {
|
|
8
|
+
url: 'https://github.com/reactjs/react.dev.git',
|
|
9
|
+
localPath: './data/react-dev-repo',
|
|
10
|
+
contentPath: 'src/content',
|
|
11
|
+
},
|
|
12
|
+
// Search settings
|
|
13
|
+
search: {
|
|
14
|
+
defaultLimit: 10,
|
|
15
|
+
maxLimit: 50,
|
|
16
|
+
minScore: 0.1,
|
|
17
|
+
semanticSearchEnabled: true,
|
|
18
|
+
semanticMinSimilarity: 0.3, // Minimum cosine similarity for semantic results
|
|
19
|
+
hybridKeywordWeight: 0.3, // Weight for keyword search in hybrid mode
|
|
20
|
+
hybridSemanticWeight: 0.7, // Weight for semantic search in hybrid mode
|
|
21
|
+
},
|
|
22
|
+
// MCP server settings
|
|
23
|
+
server: {
|
|
24
|
+
name: 'react-docs-mcp',
|
|
25
|
+
version: '1.0.0',
|
|
26
|
+
},
|
|
27
|
+
// Content sections in the repo
|
|
28
|
+
sections: ['learn', 'reference', 'blog', 'community'],
|
|
29
|
+
};
|
|
30
|
+
export default CONFIG;
|
|
31
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,GAAG;IACb,sBAAsB;IACtB,IAAI,EAAE;QACJ,GAAG,EAAE,0CAA0C;QAC/C,SAAS,EAAE,uBAAuB;QAClC,WAAW,EAAE,aAAa;KAC3B;IAED,kBAAkB;IAClB,MAAM,EAAE;QACN,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,GAAG;QACb,qBAAqB,EAAE,IAAI;QAC3B,qBAAqB,EAAE,GAAG,EAAG,iDAAiD;QAC9E,mBAAmB,EAAE,GAAG,EAAK,2CAA2C;QACxE,oBAAoB,EAAE,GAAG,EAAI,4CAA4C;KAC1E;IAED,sBAAsB;IACtB,MAAM,EAAE;QACN,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,OAAO;KACjB;IAED,+BAA+B;IAC/B,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,CAAU;CAC/D,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docsManager.ts
|
|
3
|
+
* Handle Git repository operations and file system access
|
|
4
|
+
*/
|
|
5
|
+
import type { RepoStatus } from './types.js';
|
|
6
|
+
export declare class DocsManager {
|
|
7
|
+
private git;
|
|
8
|
+
private repoPath;
|
|
9
|
+
private contentPath;
|
|
10
|
+
private fileCache;
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Initialize the docs manager
|
|
14
|
+
* Checks if repo exists, clones if needed
|
|
15
|
+
*/
|
|
16
|
+
initialize(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Check if repository exists locally
|
|
19
|
+
*/
|
|
20
|
+
private checkRepoExists;
|
|
21
|
+
/**
|
|
22
|
+
* Clone the repository
|
|
23
|
+
*/
|
|
24
|
+
private cloneRepo;
|
|
25
|
+
/**
|
|
26
|
+
* Get repository status
|
|
27
|
+
*/
|
|
28
|
+
getStatus(): Promise<RepoStatus>;
|
|
29
|
+
/**
|
|
30
|
+
* Update repository (git pull)
|
|
31
|
+
* Returns true if updates were pulled
|
|
32
|
+
*/
|
|
33
|
+
updateRepo(): Promise<boolean>;
|
|
34
|
+
/**
|
|
35
|
+
* Get all markdown files from a section
|
|
36
|
+
* @param section - Section name (learn, reference, etc.)
|
|
37
|
+
* @returns Array of file paths relative to content root
|
|
38
|
+
*/
|
|
39
|
+
getDocsInSection(section: string): Promise<string[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Get all markdown files across all sections
|
|
42
|
+
* @returns Array of file paths relative to content root
|
|
43
|
+
*/
|
|
44
|
+
getAllDocs(): Promise<string[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Read file content
|
|
47
|
+
* @param relativePath - Path relative to content root
|
|
48
|
+
* @returns Raw file content
|
|
49
|
+
*/
|
|
50
|
+
readDoc(relativePath: string): Promise<string>;
|
|
51
|
+
/**
|
|
52
|
+
* Check if file exists
|
|
53
|
+
* @param relativePath - Path relative to content root
|
|
54
|
+
*/
|
|
55
|
+
docExists(relativePath: string): Promise<boolean>;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=docsManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docsManager.d.ts","sourceRoot":"","sources":["../src/docsManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,qBAAa,WAAW;IACtB,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAoC;;IAQrD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC;;OAEG;YACW,eAAe;IAS7B;;OAEG;YACW,SAAS;IAevB;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC;IAsBtC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAgCpC;;;;OAIG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA4B1D;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAgBrC;;;;OAIG;IACG,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYpD;;;OAGG;IACG,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAUxD"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docsManager.ts
|
|
3
|
+
* Handle Git repository operations and file system access
|
|
4
|
+
*/
|
|
5
|
+
import { simpleGit } from 'simple-git';
|
|
6
|
+
import { promises as fs } from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import fg from 'fast-glob';
|
|
9
|
+
import CONFIG from './config.js';
|
|
10
|
+
export class DocsManager {
|
|
11
|
+
git;
|
|
12
|
+
repoPath;
|
|
13
|
+
contentPath;
|
|
14
|
+
fileCache = new Map();
|
|
15
|
+
constructor() {
|
|
16
|
+
this.repoPath = path.resolve(CONFIG.repo.localPath);
|
|
17
|
+
this.contentPath = path.join(this.repoPath, CONFIG.repo.contentPath);
|
|
18
|
+
this.git = simpleGit();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Initialize the docs manager
|
|
22
|
+
* Checks if repo exists, clones if needed
|
|
23
|
+
*/
|
|
24
|
+
async initialize() {
|
|
25
|
+
const repoExists = await this.checkRepoExists();
|
|
26
|
+
if (!repoExists) {
|
|
27
|
+
console.log('Cloning React documentation repository...');
|
|
28
|
+
await this.cloneRepo();
|
|
29
|
+
console.log('Repository cloned successfully');
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log('Repository already exists');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if repository exists locally
|
|
37
|
+
*/
|
|
38
|
+
async checkRepoExists() {
|
|
39
|
+
try {
|
|
40
|
+
await fs.access(path.join(this.repoPath, '.git'));
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Clone the repository
|
|
49
|
+
*/
|
|
50
|
+
async cloneRepo() {
|
|
51
|
+
try {
|
|
52
|
+
// Ensure parent directory exists
|
|
53
|
+
await fs.mkdir(path.dirname(this.repoPath), { recursive: true });
|
|
54
|
+
await this.git.clone(CONFIG.repo.url, this.repoPath, {
|
|
55
|
+
'--depth': 1, // Shallow clone for faster download
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw new Error(`Failed to clone repository: ${error instanceof Error ? error.message : String(error)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get repository status
|
|
64
|
+
*/
|
|
65
|
+
async getStatus() {
|
|
66
|
+
const isCloned = await this.checkRepoExists();
|
|
67
|
+
if (!isCloned) {
|
|
68
|
+
return { isCloned: false };
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const git = simpleGit(this.repoPath);
|
|
72
|
+
const log = await git.log({ maxCount: 1 });
|
|
73
|
+
return {
|
|
74
|
+
isCloned: true,
|
|
75
|
+
currentCommit: log.latest?.hash,
|
|
76
|
+
lastUpdated: log.latest?.date ? new Date(log.latest.date) : undefined,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error('Failed to get repo status:', error);
|
|
81
|
+
return { isCloned: true };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Update repository (git pull)
|
|
86
|
+
* Returns true if updates were pulled
|
|
87
|
+
*/
|
|
88
|
+
async updateRepo() {
|
|
89
|
+
const isCloned = await this.checkRepoExists();
|
|
90
|
+
if (!isCloned) {
|
|
91
|
+
throw new Error('Repository not cloned. Call initialize() first.');
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const git = simpleGit(this.repoPath);
|
|
95
|
+
const beforeHash = await git.revparse(['HEAD']);
|
|
96
|
+
await git.pull();
|
|
97
|
+
const afterHash = await git.revparse(['HEAD']);
|
|
98
|
+
const hasUpdates = beforeHash !== afterHash;
|
|
99
|
+
if (hasUpdates) {
|
|
100
|
+
// Clear file cache when repo is updated
|
|
101
|
+
this.fileCache.clear();
|
|
102
|
+
console.log('Repository updated successfully');
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log('Repository already up to date');
|
|
106
|
+
}
|
|
107
|
+
return hasUpdates;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw new Error(`Failed to update repository: ${error instanceof Error ? error.message : String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get all markdown files from a section
|
|
115
|
+
* @param section - Section name (learn, reference, etc.)
|
|
116
|
+
* @returns Array of file paths relative to content root
|
|
117
|
+
*/
|
|
118
|
+
async getDocsInSection(section) {
|
|
119
|
+
const cacheKey = `section:${section}`;
|
|
120
|
+
if (this.fileCache.has(cacheKey)) {
|
|
121
|
+
return this.fileCache.get(cacheKey);
|
|
122
|
+
}
|
|
123
|
+
const sectionPath = path.join(this.contentPath, section);
|
|
124
|
+
try {
|
|
125
|
+
await fs.access(sectionPath);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Section doesn't exist
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
const files = await fg('**/*.md', {
|
|
132
|
+
cwd: sectionPath,
|
|
133
|
+
absolute: false,
|
|
134
|
+
});
|
|
135
|
+
// Convert to paths relative to content root
|
|
136
|
+
const relativePaths = files.map(file => `${section}/${file}`);
|
|
137
|
+
this.fileCache.set(cacheKey, relativePaths);
|
|
138
|
+
return relativePaths;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get all markdown files across all sections
|
|
142
|
+
* @returns Array of file paths relative to content root
|
|
143
|
+
*/
|
|
144
|
+
async getAllDocs() {
|
|
145
|
+
const cacheKey = 'all';
|
|
146
|
+
if (this.fileCache.has(cacheKey)) {
|
|
147
|
+
return this.fileCache.get(cacheKey);
|
|
148
|
+
}
|
|
149
|
+
const files = await fg('**/*.md', {
|
|
150
|
+
cwd: this.contentPath,
|
|
151
|
+
absolute: false,
|
|
152
|
+
});
|
|
153
|
+
this.fileCache.set(cacheKey, files);
|
|
154
|
+
return files;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Read file content
|
|
158
|
+
* @param relativePath - Path relative to content root
|
|
159
|
+
* @returns Raw file content
|
|
160
|
+
*/
|
|
161
|
+
async readDoc(relativePath) {
|
|
162
|
+
const fullPath = path.join(this.contentPath, relativePath);
|
|
163
|
+
try {
|
|
164
|
+
return await fs.readFile(fullPath, 'utf-8');
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
throw new Error(`Failed to read document at ${relativePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Check if file exists
|
|
172
|
+
* @param relativePath - Path relative to content root
|
|
173
|
+
*/
|
|
174
|
+
async docExists(relativePath) {
|
|
175
|
+
const fullPath = path.join(this.contentPath, relativePath);
|
|
176
|
+
try {
|
|
177
|
+
await fs.access(fullPath);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=docsManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docsManager.js","sourceRoot":"","sources":["../src/docsManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* embeddingService.ts
|
|
3
|
+
* Generate embeddings using transformers.js for semantic search
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Embedding service using all-MiniLM-L6-v2 model
|
|
7
|
+
* This is a lightweight model (23MB) optimized for semantic similarity
|
|
8
|
+
*/
|
|
9
|
+
export declare class EmbeddingService {
|
|
10
|
+
private pipeline;
|
|
11
|
+
private initialized;
|
|
12
|
+
private modelName;
|
|
13
|
+
/**
|
|
14
|
+
* Initialize the embedding pipeline
|
|
15
|
+
* Downloads model on first run (~23MB)
|
|
16
|
+
*/
|
|
17
|
+
initialize(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Generate embedding for a text
|
|
20
|
+
* @param text - Text to embed
|
|
21
|
+
* @returns Vector embedding (384 dimensions for all-MiniLM-L6-v2)
|
|
22
|
+
*/
|
|
23
|
+
generateEmbedding(text: string): Promise<number[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Generate embeddings for multiple texts (batch processing)
|
|
26
|
+
* @param texts - Array of texts to embed
|
|
27
|
+
* @returns Array of vector embeddings
|
|
28
|
+
*/
|
|
29
|
+
generateEmbeddings(texts: string[]): Promise<number[][]>;
|
|
30
|
+
/**
|
|
31
|
+
* Calculate cosine similarity between two vectors
|
|
32
|
+
* @param a - First vector
|
|
33
|
+
* @param b - Second vector
|
|
34
|
+
* @returns Similarity score (0-1, higher is more similar)
|
|
35
|
+
*/
|
|
36
|
+
cosineSimilarity(a: number[], b: number[]): number;
|
|
37
|
+
/**
|
|
38
|
+
* Find most similar vectors to a query vector
|
|
39
|
+
* @param queryEmbedding - Query vector
|
|
40
|
+
* @param docEmbeddings - Array of document vectors with metadata
|
|
41
|
+
* @param topK - Number of results to return
|
|
42
|
+
* @returns Array of {index, similarity} sorted by similarity desc
|
|
43
|
+
*/
|
|
44
|
+
findMostSimilar(queryEmbedding: number[], docEmbeddings: Array<{
|
|
45
|
+
embedding: number[];
|
|
46
|
+
index: number;
|
|
47
|
+
}>, topK: number): Array<{
|
|
48
|
+
index: number;
|
|
49
|
+
similarity: number;
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=embeddingService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddingService.d.ts","sourceRoot":"","sources":["../src/embeddingService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,SAAS,CAAqC;IAEtD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAejC;;;;OAIG;IACG,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAuBxD;;;;OAIG;IACG,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAW9D;;;;;OAKG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM;IAsBlD;;;;;;OAMG;IACH,eAAe,CACb,cAAc,EAAE,MAAM,EAAE,EACxB,aAAa,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,EAC5D,IAAI,EAAE,MAAM,GACX,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAWhD"}
|