@hayhandsome/code-index-mcp 0.1.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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -0
  3. package/dist/cache/CacheManager.d.ts +19 -0
  4. package/dist/cache/CacheManager.js +51 -0
  5. package/dist/cache/CacheManager.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +13 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/config/loader.d.ts +4 -0
  10. package/dist/config/loader.js +159 -0
  11. package/dist/config/loader.js.map +1 -0
  12. package/dist/config/types.d.ts +41 -0
  13. package/dist/config/types.js +13 -0
  14. package/dist/config/types.js.map +1 -0
  15. package/dist/embedders/factory.d.ts +3 -0
  16. package/dist/embedders/factory.js +16 -0
  17. package/dist/embedders/factory.js.map +1 -0
  18. package/dist/embedders/ollama.d.ts +7 -0
  19. package/dist/embedders/ollama.js +41 -0
  20. package/dist/embedders/ollama.js.map +1 -0
  21. package/dist/embedders/openai.d.ts +8 -0
  22. package/dist/embedders/openai.js +39 -0
  23. package/dist/embedders/openai.js.map +1 -0
  24. package/dist/embedders/openaiCompatible.d.ts +8 -0
  25. package/dist/embedders/openaiCompatible.js +45 -0
  26. package/dist/embedders/openaiCompatible.js.map +1 -0
  27. package/dist/embedders/types.d.ts +6 -0
  28. package/dist/embedders/types.js +2 -0
  29. package/dist/embedders/types.js.map +1 -0
  30. package/dist/ignore/IgnoreManager.d.ts +10 -0
  31. package/dist/ignore/IgnoreManager.js +46 -0
  32. package/dist/ignore/IgnoreManager.js.map +1 -0
  33. package/dist/index.d.ts +37 -0
  34. package/dist/index.js +21 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/indexer/SyncService.d.ts +23 -0
  37. package/dist/indexer/SyncService.js +179 -0
  38. package/dist/indexer/SyncService.js.map +1 -0
  39. package/dist/mcp/tools.d.ts +7 -0
  40. package/dist/mcp/tools.js +115 -0
  41. package/dist/mcp/tools.js.map +1 -0
  42. package/dist/parser/CodeParser.d.ts +8 -0
  43. package/dist/parser/CodeParser.js +71 -0
  44. package/dist/parser/CodeParser.js.map +1 -0
  45. package/dist/parser/types.d.ts +13 -0
  46. package/dist/parser/types.js +2 -0
  47. package/dist/parser/types.js.map +1 -0
  48. package/dist/scanner/fileScanner.d.ts +2 -0
  49. package/dist/scanner/fileScanner.js +42 -0
  50. package/dist/scanner/fileScanner.js.map +1 -0
  51. package/dist/scanner/supportedExtensions.d.ts +3 -0
  52. package/dist/scanner/supportedExtensions.js +48 -0
  53. package/dist/scanner/supportedExtensions.js.map +1 -0
  54. package/dist/search/SearchService.d.ts +7 -0
  55. package/dist/search/SearchService.js +23 -0
  56. package/dist/search/SearchService.js.map +1 -0
  57. package/dist/vector-store/QdrantStore.d.ts +15 -0
  58. package/dist/vector-store/QdrantStore.js +120 -0
  59. package/dist/vector-store/QdrantStore.js.map +1 -0
  60. package/dist/vector-store/types.d.ts +21 -0
  61. package/dist/vector-store/types.js +2 -0
  62. package/dist/vector-store/types.js.map +1 -0
  63. package/package.json +33 -0
@@ -0,0 +1,6 @@
1
+ export interface EmbeddingResponse {
2
+ embeddings: number[][];
3
+ }
4
+ export interface Embedder {
5
+ createEmbeddings(texts: string[]): Promise<EmbeddingResponse>;
6
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/embedders/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ export declare class IgnoreManager {
2
+ private readonly workspacePath;
3
+ private ignoreInstance;
4
+ private gitignoreContent?;
5
+ private rooignoreContent?;
6
+ constructor(workspacePath: string);
7
+ load(): Promise<void>;
8
+ isIgnored(absolutePath: string): boolean;
9
+ private loadIgnoreFile;
10
+ }
@@ -0,0 +1,46 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import ignore from "ignore";
4
+ function toPosixPath(filePath) {
5
+ return filePath.split(path.sep).join("/");
6
+ }
7
+ export class IgnoreManager {
8
+ workspacePath;
9
+ ignoreInstance;
10
+ gitignoreContent;
11
+ rooignoreContent;
12
+ constructor(workspacePath) {
13
+ this.workspacePath = workspacePath;
14
+ this.ignoreInstance = ignore();
15
+ }
16
+ async load() {
17
+ this.ignoreInstance = ignore();
18
+ this.gitignoreContent = await this.loadIgnoreFile(".gitignore");
19
+ this.rooignoreContent = await this.loadIgnoreFile(".rooignore");
20
+ if (this.gitignoreContent) {
21
+ this.ignoreInstance.add(this.gitignoreContent);
22
+ }
23
+ if (this.rooignoreContent) {
24
+ this.ignoreInstance.add(this.rooignoreContent);
25
+ }
26
+ this.ignoreInstance.add([".gitignore", ".rooignore"]);
27
+ }
28
+ isIgnored(absolutePath) {
29
+ const relativePath = toPosixPath(path.relative(this.workspacePath, absolutePath));
30
+ return this.ignoreInstance.ignores(relativePath);
31
+ }
32
+ async loadIgnoreFile(fileName) {
33
+ const filePath = path.join(this.workspacePath, fileName);
34
+ try {
35
+ const content = await fs.readFile(filePath, "utf8");
36
+ return content;
37
+ }
38
+ catch (error) {
39
+ if (error?.code === "ENOENT") {
40
+ return undefined;
41
+ }
42
+ throw new Error(`Failed to read ${fileName}: ${error?.message ?? String(error)}`);
43
+ }
44
+ }
45
+ }
46
+ //# sourceMappingURL=IgnoreManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IgnoreManager.js","sourceRoot":"","sources":["../../src/ignore/IgnoreManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAA;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,MAAuB,MAAM,QAAQ,CAAA;AAE5C,SAAS,WAAW,CAAC,QAAgB;IACpC,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC1C,CAAC;AAED,MAAM,OAAO,aAAa;IAKI;IAJrB,cAAc,CAAQ;IACtB,gBAAgB,CAAS;IACzB,gBAAgB,CAAS;IAEjC,YAA6B,aAAqB;QAArB,kBAAa,GAAb,aAAa,CAAQ;QACjD,IAAI,CAAC,cAAc,GAAI,MAAkC,EAAE,CAAA;IAC5D,CAAC;IAED,KAAK,CAAC,IAAI;QACT,IAAI,CAAC,cAAc,GAAI,MAAkC,EAAE,CAAA;QAC3D,IAAI,CAAC,gBAAgB,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;QAC/D,IAAI,CAAC,gBAAgB,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;QAE/D,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC/C,CAAC;QACD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC/C,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAA;IACtD,CAAC;IAED,SAAS,CAAC,YAAoB;QAC7B,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,CAAA;QACjF,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;IACjD,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,QAAgB;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAA;QACxD,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;YACnD,OAAO,OAAO,CAAA;QACf,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACrB,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC9B,OAAO,SAAS,CAAA;YACjB,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,KAAK,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAClF,CAAC;IACF,CAAC;CACD"}
@@ -0,0 +1,37 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ export declare const PACKAGE_NAME = "code-index-mcp";
3
+ export declare const PACKAGE_VERSION = "0.1.0";
4
+ export declare function createServer(): Server<{
5
+ method: string;
6
+ params?: {
7
+ [x: string]: unknown;
8
+ _meta?: {
9
+ [x: string]: unknown;
10
+ progressToken?: string | number | undefined;
11
+ "io.modelcontextprotocol/related-task"?: {
12
+ taskId: string;
13
+ } | undefined;
14
+ } | undefined;
15
+ } | undefined;
16
+ }, {
17
+ method: string;
18
+ params?: {
19
+ [x: string]: unknown;
20
+ _meta?: {
21
+ [x: string]: unknown;
22
+ progressToken?: string | number | undefined;
23
+ "io.modelcontextprotocol/related-task"?: {
24
+ taskId: string;
25
+ } | undefined;
26
+ } | undefined;
27
+ } | undefined;
28
+ }, {
29
+ [x: string]: unknown;
30
+ _meta?: {
31
+ [x: string]: unknown;
32
+ progressToken?: string | number | undefined;
33
+ "io.modelcontextprotocol/related-task"?: {
34
+ taskId: string;
35
+ } | undefined;
36
+ } | undefined;
37
+ }>;
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { registerTools } from "./mcp/tools.js";
3
+ import { SyncService } from "./indexer/SyncService.js";
4
+ import { SearchService } from "./search/SearchService.js";
5
+ export const PACKAGE_NAME = "code-index-mcp";
6
+ export const PACKAGE_VERSION = "0.1.0";
7
+ export function createServer() {
8
+ const server = new Server({
9
+ name: PACKAGE_NAME,
10
+ version: PACKAGE_VERSION,
11
+ }, {
12
+ capabilities: {
13
+ tools: {},
14
+ },
15
+ });
16
+ const syncService = new SyncService();
17
+ const searchService = new SearchService(syncService);
18
+ registerTools(server, { syncService, searchService });
19
+ return server;
20
+ }
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEzD,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAA;AAC5C,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAA;AAEtC,MAAM,UAAU,YAAY;IAC3B,MAAM,MAAM,GAAG,IAAI,MAAM,CACxB;QACC,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,eAAe;KACxB,EACD;QACC,YAAY,EAAE;YACb,KAAK,EAAE,EAAE;SACT;KACD,CACD,CAAA;IAED,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;IACrC,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,WAAW,CAAC,CAAA;IACpD,aAAa,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAAA;IAErD,OAAO,MAAM,CAAA;AACd,CAAC"}
@@ -0,0 +1,23 @@
1
+ export interface SyncSummary {
2
+ added: number;
3
+ modified: number;
4
+ deleted: number;
5
+ indexedBlocks: number;
6
+ durationMs: number;
7
+ }
8
+ export declare class SyncService {
9
+ private lastStatus;
10
+ getStatus(): {
11
+ lastSyncAt?: string;
12
+ lastSummary?: SyncSummary;
13
+ state: "idle" | "syncing" | "error";
14
+ };
15
+ syncIncremental(workspacePath: string): Promise<SyncSummary>;
16
+ reindex(workspacePath: string): Promise<SyncSummary>;
17
+ clear(workspacePath: string): Promise<void>;
18
+ private runWithConfig;
19
+ private performSync;
20
+ private resolveVectorSize;
21
+ private withTimeout;
22
+ private createHash;
23
+ }
@@ -0,0 +1,179 @@
1
+ import { createHash } from "crypto";
2
+ import fs from "fs/promises";
3
+ import { CacheManager } from "../cache/CacheManager.js";
4
+ import { loadConfig } from "../config/loader.js";
5
+ import { createEmbedderFromConfig } from "../embedders/factory.js";
6
+ import { IgnoreManager } from "../ignore/IgnoreManager.js";
7
+ import { CodeParser } from "../parser/CodeParser.js";
8
+ import { scanWorkspaceFiles } from "../scanner/fileScanner.js";
9
+ import { QdrantStore } from "../vector-store/QdrantStore.js";
10
+ export class SyncService {
11
+ lastStatus = {
12
+ state: "idle",
13
+ };
14
+ getStatus() {
15
+ return this.lastStatus;
16
+ }
17
+ async syncIncremental(workspacePath) {
18
+ return this.runWithConfig(workspacePath, async (config, secrets) => {
19
+ return this.performSync(workspacePath, config, secrets, false);
20
+ });
21
+ }
22
+ async reindex(workspacePath) {
23
+ return this.runWithConfig(workspacePath, async (config, secrets) => {
24
+ return this.performSync(workspacePath, config, secrets, true);
25
+ });
26
+ }
27
+ async clear(workspacePath) {
28
+ await this.runWithConfig(workspacePath, async (config, secrets) => {
29
+ const vectorSize = await this.resolveVectorSize(config, secrets);
30
+ const store = new QdrantStore(workspacePath, config.qdrantUrl, vectorSize, secrets.qdrantApiKey);
31
+ await store.clear();
32
+ const cache = new CacheManager(workspacePath);
33
+ await cache.clear();
34
+ }, { validate: false });
35
+ }
36
+ async runWithConfig(workspacePath, task, options = {}) {
37
+ this.lastStatus.state = "syncing";
38
+ const { config, secrets } = await loadConfig(workspacePath, { validate: options.validate ?? true });
39
+ const result = await this.withTimeout(config.timeoutMs, task(config, secrets));
40
+ this.lastStatus.state = "idle";
41
+ return result;
42
+ }
43
+ async performSync(workspacePath, config, secrets, forceReindex) {
44
+ const start = Date.now();
45
+ const vectorSize = await this.resolveVectorSize(config, secrets);
46
+ const store = new QdrantStore(workspacePath, config.qdrantUrl, vectorSize, secrets.qdrantApiKey);
47
+ await store.initialize();
48
+ const cache = new CacheManager(workspacePath);
49
+ await cache.load();
50
+ if (forceReindex) {
51
+ await store.clear();
52
+ await cache.clear();
53
+ await store.initialize();
54
+ }
55
+ const ignoreManager = new IgnoreManager(workspacePath);
56
+ await ignoreManager.load();
57
+ const files = await scanWorkspaceFiles(workspacePath, ignoreManager);
58
+ const cachedEntries = cache.getAll();
59
+ const changedFiles = [];
60
+ const addedFiles = [];
61
+ const modifiedFiles = [];
62
+ for (const filePath of files) {
63
+ const stats = await fs.stat(filePath);
64
+ const cached = cachedEntries[filePath];
65
+ if (cached && cached.size === stats.size && cached.mtimeMs === stats.mtimeMs && !forceReindex) {
66
+ continue;
67
+ }
68
+ changedFiles.push(filePath);
69
+ if (!cached) {
70
+ addedFiles.push(filePath);
71
+ }
72
+ else {
73
+ modifiedFiles.push(filePath);
74
+ }
75
+ }
76
+ const existingSet = new Set(files);
77
+ const deletedFiles = Object.keys(cachedEntries).filter((filePath) => !existingSet.has(filePath));
78
+ if (deletedFiles.length > 0) {
79
+ await store.deleteByPaths(deletedFiles);
80
+ for (const filePath of deletedFiles) {
81
+ cache.delete(filePath);
82
+ }
83
+ }
84
+ if (changedFiles.length > 0) {
85
+ await store.deleteByPaths(changedFiles);
86
+ }
87
+ const parser = new CodeParser();
88
+ const embedder = createEmbedderFromConfig(config, secrets);
89
+ const pendingBlocks = [];
90
+ for (const filePath of changedFiles) {
91
+ const content = await fs.readFile(filePath, "utf8");
92
+ const stats = await fs.stat(filePath);
93
+ const fileHash = this.createHash(content);
94
+ const blocks = await parser.parseFile(filePath, content);
95
+ for (const block of blocks) {
96
+ const id = this.createHash(`${block.filePath}:${block.segmentHash}`);
97
+ pendingBlocks.push({
98
+ content: block.content,
99
+ point: {
100
+ id,
101
+ vector: [],
102
+ payload: {
103
+ filePath: block.filePath,
104
+ startLine: block.startLine,
105
+ endLine: block.endLine,
106
+ content: block.content,
107
+ fileHash: block.fileHash,
108
+ segmentHash: block.segmentHash,
109
+ },
110
+ },
111
+ });
112
+ }
113
+ cache.set(filePath, {
114
+ hash: fileHash,
115
+ size: stats.size,
116
+ mtimeMs: stats.mtimeMs,
117
+ });
118
+ }
119
+ const batchSize = Math.max(1, config.embeddingBatchSize);
120
+ let indexedBlocks = 0;
121
+ for (let i = 0; i < pendingBlocks.length; i += batchSize) {
122
+ const batch = pendingBlocks.slice(i, i + batchSize);
123
+ const embeddings = await embedder.createEmbeddings(batch.map((item) => item.content));
124
+ if (embeddings.embeddings.length !== batch.length) {
125
+ throw new Error("Embedding response size mismatch");
126
+ }
127
+ const points = batch.map((item, index) => ({
128
+ ...item.point,
129
+ vector: embeddings.embeddings[index],
130
+ }));
131
+ await store.upsert(points);
132
+ indexedBlocks += points.length;
133
+ }
134
+ await cache.save();
135
+ const summary = {
136
+ added: addedFiles.length,
137
+ modified: modifiedFiles.length,
138
+ deleted: deletedFiles.length,
139
+ indexedBlocks,
140
+ durationMs: Date.now() - start,
141
+ };
142
+ this.lastStatus = {
143
+ state: "idle",
144
+ lastSyncAt: new Date().toISOString(),
145
+ lastSummary: summary,
146
+ };
147
+ return summary;
148
+ }
149
+ async resolveVectorSize(config, secrets) {
150
+ if (config.modelDimension && config.modelDimension > 0) {
151
+ return config.modelDimension;
152
+ }
153
+ const embedder = createEmbedderFromConfig(config, secrets);
154
+ const response = await embedder.createEmbeddings(["dimension_probe"]);
155
+ const dimension = response.embeddings[0]?.length;
156
+ if (!dimension) {
157
+ throw new Error("Unable to determine embedding dimension");
158
+ }
159
+ return dimension;
160
+ }
161
+ async withTimeout(timeoutMs, task) {
162
+ let timeoutId;
163
+ const timeoutPromise = new Promise((_, reject) => {
164
+ timeoutId = setTimeout(() => reject(new Error(`Indexing timed out after ${timeoutMs}ms`)), timeoutMs);
165
+ });
166
+ try {
167
+ return await Promise.race([task, timeoutPromise]);
168
+ }
169
+ finally {
170
+ if (timeoutId) {
171
+ clearTimeout(timeoutId);
172
+ }
173
+ }
174
+ }
175
+ createHash(input) {
176
+ return createHash("sha256").update(input).digest("hex");
177
+ }
178
+ }
179
+ //# sourceMappingURL=SyncService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncService.js","sourceRoot":"","sources":["../../src/indexer/SyncService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { SyncService } from "../indexer/SyncService.js";
3
+ import { SearchService } from "../search/SearchService.js";
4
+ export declare function registerTools(server: Server, services: {
5
+ syncService: SyncService;
6
+ searchService: SearchService;
7
+ }): void;
@@ -0,0 +1,115 @@
1
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
2
+ import { loadConfig } from "../config/loader.js";
3
+ const TOOL_DEFINITIONS = [
4
+ {
5
+ name: "code_index_search",
6
+ description: "按需同步后执行语义搜索",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ query: { type: "string", description: "搜索查询" },
11
+ workspacePath: { type: "string", description: "项目根路径(可选)" },
12
+ directoryPrefix: { type: "string", description: "文件路径前缀过滤(可选)" },
13
+ },
14
+ required: ["query"],
15
+ },
16
+ },
17
+ {
18
+ name: "code_index_update",
19
+ description: "执行一次增量同步并返回变更摘要",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ workspacePath: { type: "string", description: "项目根路径(可选)" },
24
+ },
25
+ },
26
+ },
27
+ {
28
+ name: "code_index_reindex",
29
+ description: "清空并重建索引",
30
+ inputSchema: {
31
+ type: "object",
32
+ properties: {
33
+ workspacePath: { type: "string", description: "项目根路径(可选)" },
34
+ },
35
+ },
36
+ },
37
+ {
38
+ name: "code_index_clear",
39
+ description: "清空向量与本地缓存",
40
+ inputSchema: {
41
+ type: "object",
42
+ properties: {
43
+ workspacePath: { type: "string", description: "项目根路径(可选)" },
44
+ },
45
+ },
46
+ },
47
+ {
48
+ name: "code_index_status",
49
+ description: "获取当前配置与索引状态",
50
+ inputSchema: {
51
+ type: "object",
52
+ properties: {
53
+ workspacePath: { type: "string", description: "项目根路径(可选)" },
54
+ },
55
+ },
56
+ },
57
+ ];
58
+ export function registerTools(server, services) {
59
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOL_DEFINITIONS }));
60
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
61
+ const { name, arguments: args } = request.params;
62
+ const workspacePath = args?.workspacePath ?? process.cwd();
63
+ switch (name) {
64
+ case "code_index_search": {
65
+ const query = args?.query;
66
+ if (!query) {
67
+ throw new Error("Missing required parameter: query");
68
+ }
69
+ const directoryPrefix = args?.directoryPrefix;
70
+ const results = await services.searchService.search(workspacePath, query, directoryPrefix);
71
+ return {
72
+ content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
73
+ };
74
+ }
75
+ case "code_index_update": {
76
+ const summary = await services.syncService.syncIncremental(workspacePath);
77
+ return {
78
+ content: [{ type: "text", text: JSON.stringify(summary, null, 2) }],
79
+ };
80
+ }
81
+ case "code_index_reindex": {
82
+ const summary = await services.syncService.reindex(workspacePath);
83
+ return {
84
+ content: [{ type: "text", text: JSON.stringify(summary, null, 2) }],
85
+ };
86
+ }
87
+ case "code_index_clear": {
88
+ await services.syncService.clear(workspacePath);
89
+ return {
90
+ content: [{ type: "text", text: "OK" }],
91
+ };
92
+ }
93
+ case "code_index_status": {
94
+ const { config, paths } = await loadConfig(workspacePath, { validate: false });
95
+ const status = services.syncService.getStatus();
96
+ return {
97
+ content: [
98
+ {
99
+ type: "text",
100
+ text: JSON.stringify({
101
+ workspacePath,
102
+ config,
103
+ paths,
104
+ status,
105
+ }, null, 2),
106
+ },
107
+ ],
108
+ };
109
+ }
110
+ default:
111
+ throw new Error(`Unknown tool: ${name}`);
112
+ }
113
+ });
114
+ }
115
+ //# 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,8 @@
1
+ import { CodeBlock, TreeSitterProvider } from "./types.js";
2
+ export declare class CodeParser {
3
+ private readonly treeSitterProvider?;
4
+ constructor(treeSitterProvider?: TreeSitterProvider | undefined);
5
+ parseFile(filePath: string, content?: string): Promise<CodeBlock[]>;
6
+ private fallbackChunking;
7
+ private createHash;
8
+ }
@@ -0,0 +1,71 @@
1
+ import { createHash } from "crypto";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { shouldUseFallbackChunking } from "../scanner/supportedExtensions.js";
5
+ const MAX_BLOCK_CHARS = 1000;
6
+ const MIN_BLOCK_CHARS = 50;
7
+ export class CodeParser {
8
+ treeSitterProvider;
9
+ constructor(treeSitterProvider) {
10
+ this.treeSitterProvider = treeSitterProvider;
11
+ }
12
+ async parseFile(filePath, content) {
13
+ const ext = path.extname(filePath).toLowerCase();
14
+ const fileContent = content ?? (await fs.readFile(filePath, "utf8"));
15
+ const fileHash = this.createHash(fileContent);
16
+ if (ext === ".md" || ext === ".markdown") {
17
+ return this.fallbackChunking(filePath, fileContent, fileHash);
18
+ }
19
+ if (!shouldUseFallbackChunking(ext) && this.treeSitterProvider) {
20
+ return this.treeSitterProvider.parseFile(filePath, fileContent, fileHash);
21
+ }
22
+ return this.fallbackChunking(filePath, fileContent, fileHash);
23
+ }
24
+ fallbackChunking(filePath, content, fileHash) {
25
+ const lines = content.split(/\r?\n/);
26
+ const blocks = [];
27
+ let current = [];
28
+ let currentLength = 0;
29
+ let blockStartLine = 1;
30
+ const flushBlock = (endLine, force = false) => {
31
+ const blockContent = current.join("\n");
32
+ if (!force && blockContent.length < MIN_BLOCK_CHARS) {
33
+ return;
34
+ }
35
+ const segmentHash = this.createHash(`${filePath}:${blockStartLine}:${endLine}:${blockContent}`);
36
+ blocks.push({
37
+ filePath,
38
+ identifier: null,
39
+ type: "chunk",
40
+ startLine: blockStartLine,
41
+ endLine,
42
+ content: blockContent,
43
+ fileHash,
44
+ segmentHash,
45
+ });
46
+ current = [];
47
+ currentLength = 0;
48
+ blockStartLine = endLine + 1;
49
+ };
50
+ for (let i = 0; i < lines.length; i += 1) {
51
+ const line = lines[i];
52
+ const nextLength = currentLength + line.length + 1;
53
+ if (nextLength > MAX_BLOCK_CHARS && currentLength >= MIN_BLOCK_CHARS) {
54
+ flushBlock(i, true);
55
+ }
56
+ current.push(line);
57
+ currentLength += line.length + 1;
58
+ if (currentLength >= MAX_BLOCK_CHARS) {
59
+ flushBlock(i + 1, true);
60
+ }
61
+ }
62
+ if (current.length > 0) {
63
+ flushBlock(lines.length, true);
64
+ }
65
+ return blocks;
66
+ }
67
+ createHash(input) {
68
+ return createHash("sha256").update(input).digest("hex");
69
+ }
70
+ }
71
+ //# sourceMappingURL=CodeParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeParser.js","sourceRoot":"","sources":["../../src/parser/CodeParser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface CodeBlock {
2
+ filePath: string;
3
+ identifier: string | null;
4
+ type: string;
5
+ startLine: number;
6
+ endLine: number;
7
+ content: string;
8
+ fileHash: string;
9
+ segmentHash: string;
10
+ }
11
+ export interface TreeSitterProvider {
12
+ parseFile(filePath: string, content: string, fileHash: string): Promise<CodeBlock[]>;
13
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/parser/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import { IgnoreManager } from "../ignore/IgnoreManager.js";
2
+ export declare function scanWorkspaceFiles(workspacePath: string, ignoreManager: IgnoreManager): Promise<string[]>;
@@ -0,0 +1,42 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { scannerExtensions } from "./supportedExtensions.js";
4
+ const DEFAULT_IGNORED_DIRS = new Set([".git", "node_modules", ".code-index"]);
5
+ function hasSupportedExtension(filePath) {
6
+ return scannerExtensions.includes(path.extname(filePath).toLowerCase());
7
+ }
8
+ function shouldSkipDir(dirName) {
9
+ return DEFAULT_IGNORED_DIRS.has(dirName);
10
+ }
11
+ export async function scanWorkspaceFiles(workspacePath, ignoreManager) {
12
+ const results = [];
13
+ async function walk(currentPath) {
14
+ const entries = await fs.readdir(currentPath, { withFileTypes: true });
15
+ for (const entry of entries) {
16
+ const entryPath = path.join(currentPath, entry.name);
17
+ if (entry.isDirectory()) {
18
+ if (shouldSkipDir(entry.name)) {
19
+ continue;
20
+ }
21
+ if (ignoreManager.isIgnored(entryPath)) {
22
+ continue;
23
+ }
24
+ await walk(entryPath);
25
+ continue;
26
+ }
27
+ if (!entry.isFile()) {
28
+ continue;
29
+ }
30
+ if (!hasSupportedExtension(entryPath)) {
31
+ continue;
32
+ }
33
+ if (ignoreManager.isIgnored(entryPath)) {
34
+ continue;
35
+ }
36
+ results.push(entryPath);
37
+ }
38
+ }
39
+ await walk(workspacePath);
40
+ return results;
41
+ }
42
+ //# sourceMappingURL=fileScanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileScanner.js","sourceRoot":"","sources":["../../src/scanner/fileScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAA;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE5D,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,aAAa,CAAC,CAAC,CAAA;AAE7E,SAAS,qBAAqB,CAAC,QAAgB;IAC9C,OAAO,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;AACxE,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACrC,OAAO,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,aAAqB,EACrB,aAA4B;IAE5B,MAAM,OAAO,GAAa,EAAE,CAAA;IAE5B,KAAK,UAAU,IAAI,CAAC,WAAmB;QACtC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;QACtE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YACpD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACzB,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/B,SAAQ;gBACT,CAAC;gBACD,IAAI,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;oBACxC,SAAQ;gBACT,CAAC;gBACD,MAAM,IAAI,CAAC,SAAS,CAAC,CAAA;gBACrB,SAAQ;YACT,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrB,SAAQ;YACT,CAAC;YAED,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;gBACvC,SAAQ;YACT,CAAC;YAED,IAAI,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;gBACxC,SAAQ;YACT,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACxB,CAAC;IACF,CAAC;IAED,MAAM,IAAI,CAAC,aAAa,CAAC,CAAA;IACzB,OAAO,OAAO,CAAA;AACf,CAAC"}