@chiway/contextweaver 1.4.0 → 1.5.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 (33) hide show
  1. package/README.md +138 -28
  2. package/dist/{SearchService-OS7CYHNJ.js → SearchService-WVD6THR3.js} +116 -74
  3. package/dist/{chunk-ZOMGPIU6.js → chunk-3BNHQV5W.js} +1 -5
  4. package/dist/chunk-BFCIZ52F.js +102 -0
  5. package/dist/{chunk-X7PAYQMT.js → chunk-GDVB6PJ4.js} +21 -3
  6. package/dist/{lock-FL54LIQL.js → chunk-HHYPQA3X.js} +1 -1
  7. package/dist/chunk-ISVCQFB4.js +223 -0
  8. package/dist/chunk-IZ6IUHNN.js +77 -0
  9. package/dist/chunk-LB42CZEB.js +18 -0
  10. package/dist/{chunk-RGJSXUFS.js → chunk-PPLFJGO3.js} +60 -0
  11. package/dist/chunk-R6CNZXZ7.js +143 -0
  12. package/dist/chunk-TPM6YP43.js +38 -0
  13. package/dist/{chunk-EMSMLPMK.js → chunk-V3K4YVAR.js} +10 -117
  14. package/dist/chunk-VWBKZ6QL.js +115 -0
  15. package/dist/chunk-XFIM2T6S.js +57 -0
  16. package/dist/{chunk-AB24E3Z7.js → chunk-XMZZZKG7.js} +23 -79
  17. package/dist/chunk-XTWNT7KP.js +156 -0
  18. package/dist/chunk-Y6H7C3NA.js +85 -0
  19. package/dist/{codebaseRetrieval-3Z4CRA7X.js → codebaseRetrieval-DIS5RH2C.js} +5 -2
  20. package/dist/{db-PMVM7557.js → db-GBCLP4GG.js} +15 -1
  21. package/dist/findReferences-N7ML7TUP.js +16 -0
  22. package/dist/getSymbolDefinition-6KMY4H33.js +17 -0
  23. package/dist/index.js +244 -41
  24. package/dist/listFiles-4VT2TPJD.js +14 -0
  25. package/dist/loadConfig-XTVT2OWW.js +9 -0
  26. package/dist/lock-HNKQ6X5B.js +8 -0
  27. package/dist/scanner-QDFZJLP7.js +13 -0
  28. package/dist/server-UAI3U7AB.js +347 -0
  29. package/dist/stats-AGKUCJQI.js +12 -0
  30. package/dist/{vectorStore-HPQZOVWF.js → vectorStore-4ODCERRO.js} +1 -1
  31. package/package.json +9 -23
  32. package/dist/scanner-2XGJWYHR.js +0 -11
  33. package/dist/server-XK6EINRV.js +0 -146
@@ -2,10 +2,10 @@ import {
2
2
  closeAllIndexers,
3
3
  getIndexer,
4
4
  invalidateAllExpanderCaches
5
- } from "./chunk-AB24E3Z7.js";
5
+ } from "./chunk-XMZZZKG7.js";
6
6
  import {
7
7
  closeAllVectorStores
8
- } from "./chunk-ZOMGPIU6.js";
8
+ } from "./chunk-3BNHQV5W.js";
9
9
  import {
10
10
  batchDelete,
11
11
  batchUpdateMtime,
@@ -17,9 +17,12 @@ import {
17
17
  getAllPaths,
18
18
  getFilesNeedingVectorIndex,
19
19
  getStoredEmbeddingDimensions,
20
+ incrementIndexVersion,
21
+ incrementStat,
20
22
  initDb,
23
+ setStatJson,
21
24
  setStoredEmbeddingDimensions
22
- } from "./chunk-RGJSXUFS.js";
25
+ } from "./chunk-PPLFJGO3.js";
23
26
  import {
24
27
  logger
25
28
  } from "./chunk-JVKVSTQ3.js";
@@ -1382,6 +1385,19 @@ async function scan(rootPath, options = {}) {
1382
1385
  logger.warn({ error: error.message }, "GC \u8DF3\u8FC7");
1383
1386
  }
1384
1387
  }
1388
+ const didWork = stats.added + stats.modified + stats.deleted > 0;
1389
+ if (didWork) {
1390
+ incrementIndexVersion(db);
1391
+ }
1392
+ try {
1393
+ if (didWork) {
1394
+ incrementStat(db, "stats.index.total_runs");
1395
+ }
1396
+ setStatJson(db, "stats.index.last_run_json", stats);
1397
+ setStatJson(db, "stats.index.last_run_at", Date.now());
1398
+ } catch (err) {
1399
+ logger.warn({ error: err.message }, "\u7D22\u5F15\u7EDF\u8BA1\u57CB\u70B9\u5931\u8D25");
1400
+ }
1385
1401
  invalidateAllExpanderCaches();
1386
1402
  return stats;
1387
1403
  } finally {
@@ -1392,5 +1408,7 @@ async function scan(rootPath, options = {}) {
1392
1408
  }
1393
1409
 
1394
1410
  export {
1411
+ initFilter,
1412
+ isFiltered,
1395
1413
  scan
1396
1414
  };
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  logger
3
3
  } from "./chunk-JVKVSTQ3.js";
4
- import "./chunk-SKBAE26T.js";
5
4
 
6
5
  // src/utils/lock.ts
7
6
  import fs from "fs";
@@ -122,6 +121,7 @@ async function withLock(projectId, operation, fn, timeoutMs = 3e4) {
122
121
  releaseLock(projectId);
123
122
  }
124
123
  }
124
+
125
125
  export {
126
126
  withLock
127
127
  };
@@ -0,0 +1,223 @@
1
+ import {
2
+ commonPrefixLength
3
+ } from "./chunk-LB42CZEB.js";
4
+ import {
5
+ ChunkContentLoader
6
+ } from "./chunk-XFIM2T6S.js";
7
+ import {
8
+ getVectorStore
9
+ } from "./chunk-3BNHQV5W.js";
10
+ import {
11
+ ensureIndexed,
12
+ formatTextResponse
13
+ } from "./chunk-VWBKZ6QL.js";
14
+ import {
15
+ generateProjectId,
16
+ initDb,
17
+ searchChunksFts
18
+ } from "./chunk-PPLFJGO3.js";
19
+ import {
20
+ logger
21
+ } from "./chunk-JVKVSTQ3.js";
22
+
23
+ // src/mcp/tools/getSymbolDefinition.ts
24
+ import { z } from "zod";
25
+ var getSymbolDefinitionSchema = z.object({
26
+ repo_path: z.string().describe(
27
+ "The absolute file system path to the repository root. (e.g., '/Users/dev/my-project')"
28
+ ),
29
+ symbol: z.string().min(1).describe("The exact symbol name to resolve."),
30
+ hint_path: z.string().optional().describe("Optional preferred path used to disambiguate same-name definitions."),
31
+ max_results: z.number().int().positive().max(20).optional().describe("Maximum number of definitions to return. Defaults to 3.")
32
+ });
33
+ var LANGUAGE_DEFINITION_PATTERNS = {
34
+ typescript: [
35
+ "function\\s+{symbol}\\b",
36
+ "class\\s+{symbol}\\b",
37
+ "(?:const|let|var)\\s+{symbol}\\b",
38
+ "interface\\s+{symbol}\\b",
39
+ "type\\s+{symbol}\\b",
40
+ "enum\\s+{symbol}\\b"
41
+ ],
42
+ javascript: [
43
+ "function\\s+{symbol}\\b",
44
+ "class\\s+{symbol}\\b",
45
+ "(?:const|let|var)\\s+{symbol}\\b"
46
+ ],
47
+ python: ["def\\s+{symbol}\\b", "class\\s+{symbol}\\b"],
48
+ go: ["func\\s+{symbol}\\b", "type\\s+{symbol}\\b", "const\\s+{symbol}\\b", "var\\s+{symbol}\\b"],
49
+ rust: [
50
+ "fn\\s+{symbol}\\b",
51
+ "struct\\s+{symbol}\\b",
52
+ "enum\\s+{symbol}\\b",
53
+ "const\\s+{symbol}\\b"
54
+ ],
55
+ java: [
56
+ "class\\s+{symbol}\\b",
57
+ "interface\\s+{symbol}\\b",
58
+ "enum\\s+{symbol}\\b",
59
+ "\\b{symbol}\\s*\\("
60
+ ],
61
+ csharp: [
62
+ "class\\s+{symbol}\\b",
63
+ "interface\\s+{symbol}\\b",
64
+ "enum\\s+{symbol}\\b",
65
+ "\\b{symbol}\\s*\\("
66
+ ],
67
+ cpp: ["class\\s+{symbol}\\b", "struct\\s+{symbol}\\b", "\\b{symbol}\\s*\\("],
68
+ c: ["\\b{symbol}\\s*\\("]
69
+ };
70
+ function escapeRegex(text) {
71
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
72
+ }
73
+ function breadcrumbTail(breadcrumb) {
74
+ return breadcrumb.split(">").pop()?.trim() ?? "";
75
+ }
76
+ function countLinesBefore(content, index) {
77
+ let line = 1;
78
+ for (let i = 0; i < index && i < content.length; i++) {
79
+ if (content[i] === "\n") {
80
+ line += 1;
81
+ }
82
+ }
83
+ return line;
84
+ }
85
+ function computeEndLine(startLine, code) {
86
+ const normalized = code.replace(/\n+$/u, "");
87
+ if (!normalized) {
88
+ return startLine;
89
+ }
90
+ return startLine + normalized.split("\n").length - 1;
91
+ }
92
+ function detectLanguage(filePath) {
93
+ const ext = filePath.split(".").pop()?.toLowerCase() || "";
94
+ const langMap = {
95
+ ts: "typescript",
96
+ tsx: "typescript",
97
+ js: "javascript",
98
+ jsx: "javascript",
99
+ py: "python",
100
+ rs: "rust",
101
+ go: "go",
102
+ java: "java",
103
+ c: "c",
104
+ cpp: "cpp",
105
+ h: "c",
106
+ hpp: "cpp",
107
+ cs: "csharp",
108
+ md: "markdown",
109
+ json: "json"
110
+ };
111
+ return langMap[ext] || ext || "plaintext";
112
+ }
113
+ function formatDefinition(candidate) {
114
+ const header = `## ${candidate.chunk.file_path} (L${candidate.startLine}-L${candidate.endLine})`;
115
+ const breadcrumb = candidate.chunk.breadcrumb ? `> ${candidate.chunk.breadcrumb}` : "";
116
+ const code = `\`\`\`${detectLanguage(candidate.chunk.file_path)}
117
+ ${candidate.code}
118
+ \`\`\``;
119
+ return [header, breadcrumb, code].filter(Boolean).join("\n");
120
+ }
121
+ function hasDefinitionPattern(language, code, symbol) {
122
+ const patterns = LANGUAGE_DEFINITION_PATTERNS[language] ?? LANGUAGE_DEFINITION_PATTERNS.typescript;
123
+ return patterns.some((pattern) => {
124
+ const source = pattern.replaceAll("{symbol}", escapeRegex(symbol));
125
+ return new RegExp(source, "u").test(code);
126
+ });
127
+ }
128
+ function rankCandidates(a, b) {
129
+ if (a.breadcrumbExact !== b.breadcrumbExact) {
130
+ return a.breadcrumbExact ? -1 : 1;
131
+ }
132
+ if (a.prefixScore !== b.prefixScore) {
133
+ return b.prefixScore - a.prefixScore;
134
+ }
135
+ if (a.score !== b.score) {
136
+ return b.score - a.score;
137
+ }
138
+ return a.chunk.file_path.localeCompare(b.chunk.file_path);
139
+ }
140
+ async function handleGetSymbolDefinition(args, onProgress) {
141
+ const { repo_path, symbol, hint_path, max_results = 3 } = args;
142
+ const projectId = generateProjectId(repo_path);
143
+ logger.info({ repo_path, symbol, hint_path, max_results }, "MCP get-symbol-definition \u8C03\u7528\u5F00\u59CB");
144
+ await ensureIndexed(repo_path, projectId, { onProgress });
145
+ const db = initDb(projectId);
146
+ try {
147
+ const hits = searchChunksFts(db, symbol, Math.max(max_results * 5, 20));
148
+ const uniquePaths = Array.from(new Set(hits.map((hit) => hit.filePath)));
149
+ const vectorStore = await getVectorStore(projectId);
150
+ const chunkMap = await vectorStore.getFilesChunks(uniquePaths);
151
+ const chunkByKey = /* @__PURE__ */ new Map();
152
+ for (const [filePath, chunks] of chunkMap) {
153
+ for (const chunk of chunks) {
154
+ chunkByKey.set(`${filePath}#${chunk.chunk_index}`, chunk);
155
+ }
156
+ }
157
+ const slices = Array.from(chunkByKey.values()).map((chunk) => ({
158
+ filePath: chunk.file_path,
159
+ start_index: chunk.start_index,
160
+ end_index: chunk.end_index
161
+ }));
162
+ const loader = new ChunkContentLoader(db);
163
+ const codeMap = loader.loadMany(slices);
164
+ const fileContentStmt = db.prepare("SELECT content FROM files WHERE path = ?");
165
+ const fullFileCache = /* @__PURE__ */ new Map();
166
+ const candidates = /* @__PURE__ */ new Map();
167
+ for (const hit of hits) {
168
+ const chunk = chunkByKey.get(`${hit.filePath}#${hit.chunkIndex}`);
169
+ if (!chunk) {
170
+ continue;
171
+ }
172
+ const codeKey = ChunkContentLoader.key({
173
+ filePath: chunk.file_path,
174
+ start_index: chunk.start_index,
175
+ end_index: chunk.end_index
176
+ });
177
+ const code = codeMap.get(codeKey) ?? "";
178
+ if (!code) {
179
+ continue;
180
+ }
181
+ const breadcrumbExact = breadcrumbTail(chunk.breadcrumb) === symbol;
182
+ const definitionPattern = hasDefinitionPattern(chunk.language, code, symbol);
183
+ if (!breadcrumbExact && !definitionPattern) {
184
+ continue;
185
+ }
186
+ let fullContent = fullFileCache.get(chunk.file_path);
187
+ if (fullContent === void 0) {
188
+ const row = fileContentStmt.get(chunk.file_path);
189
+ fullContent = row?.content ?? "";
190
+ fullFileCache.set(chunk.file_path, fullContent);
191
+ }
192
+ const startLine = countLinesBefore(fullContent, chunk.start_index);
193
+ const candidate = {
194
+ chunk,
195
+ code,
196
+ score: hit.score,
197
+ breadcrumbExact,
198
+ prefixScore: hint_path ? commonPrefixLength(hint_path, chunk.file_path) : 0,
199
+ startLine,
200
+ endLine: computeEndLine(startLine, code)
201
+ };
202
+ const key = `${chunk.file_path}#${chunk.chunk_index}`;
203
+ const existing = candidates.get(key);
204
+ if (!existing || rankCandidates(candidate, existing) < 0) {
205
+ candidates.set(key, candidate);
206
+ }
207
+ }
208
+ const ranked = Array.from(candidates.values()).sort(rankCandidates).slice(0, max_results);
209
+ const body = ranked.length > 0 ? ranked.map((candidate) => formatDefinition(candidate)).join("\n\n---\n\n") : "No likely symbol definitions found.";
210
+ return formatTextResponse(
211
+ `Found ${ranked.length} symbol definitions for "${symbol}"
212
+
213
+ ${body}`
214
+ );
215
+ } finally {
216
+ db.close();
217
+ }
218
+ }
219
+
220
+ export {
221
+ getSymbolDefinitionSchema,
222
+ handleGetSymbolDefinition
223
+ };
@@ -0,0 +1,77 @@
1
+ import {
2
+ DEFAULT_CONFIG,
3
+ SEARCH_CONFIG_BOUNDS
4
+ } from "./chunk-BFCIZ52F.js";
5
+
6
+ // src/search/loadConfig.ts
7
+ import crypto from "crypto";
8
+ var SEARCH_ENV_MAP = {
9
+ CW_SEARCH_WVEC: "wVec",
10
+ CW_SEARCH_WLEX: "wLex",
11
+ CW_SEARCH_RERANK_TOP_N: "rerankTopN",
12
+ CW_SEARCH_MAX_TOTAL_CHARS: "maxTotalChars",
13
+ CW_SEARCH_VECTOR_TOP_K: "vectorTopK",
14
+ CW_SEARCH_SMART_MAX_K: "smartMaxK",
15
+ CW_SEARCH_IMPORT_FILES_PER_SEED: "importFilesPerSeed"
16
+ };
17
+ var SEARCH_FINGERPRINT_FIELDS = Object.keys(DEFAULT_CONFIG);
18
+ function normalizeWeight(value) {
19
+ return Math.round(value * 1e6) / 1e6;
20
+ }
21
+ function clampValue(key, rawValue) {
22
+ const parsed = Number(rawValue);
23
+ if (!Number.isFinite(parsed)) {
24
+ return void 0;
25
+ }
26
+ const bounds = SEARCH_CONFIG_BOUNDS[key];
27
+ if (!bounds) {
28
+ return parsed;
29
+ }
30
+ const clamped = Math.min(bounds.max, Math.max(bounds.min, parsed));
31
+ return bounds.integer ? Math.round(clamped) : clamped;
32
+ }
33
+ function getSearchConfigOverrides() {
34
+ const overrides = {};
35
+ const explicitWeights = {};
36
+ for (const [envKey, configKey] of Object.entries(SEARCH_ENV_MAP)) {
37
+ const rawValue = process.env[envKey];
38
+ if (rawValue === void 0 || rawValue.trim() === "") {
39
+ continue;
40
+ }
41
+ const parsed = clampValue(configKey, rawValue);
42
+ if (parsed === void 0) {
43
+ continue;
44
+ }
45
+ if (configKey === "wVec" || configKey === "wLex") {
46
+ explicitWeights[configKey] = parsed;
47
+ continue;
48
+ }
49
+ overrides[configKey] = parsed;
50
+ }
51
+ if (explicitWeights.wVec !== void 0 && explicitWeights.wLex === void 0) {
52
+ overrides.wVec = explicitWeights.wVec;
53
+ overrides.wLex = normalizeWeight(1 - explicitWeights.wVec);
54
+ } else if (explicitWeights.wLex !== void 0 && explicitWeights.wVec === void 0) {
55
+ overrides.wLex = explicitWeights.wLex;
56
+ overrides.wVec = normalizeWeight(1 - explicitWeights.wLex);
57
+ } else {
58
+ if (explicitWeights.wVec !== void 0) {
59
+ overrides.wVec = explicitWeights.wVec;
60
+ }
61
+ if (explicitWeights.wLex !== void 0) {
62
+ overrides.wLex = explicitWeights.wLex;
63
+ }
64
+ }
65
+ return overrides;
66
+ }
67
+ function createSearchConfigFingerprint(config) {
68
+ const payload = Object.fromEntries(
69
+ SEARCH_FINGERPRINT_FIELDS.map((field) => [field, config[field]])
70
+ );
71
+ return crypto.createHash("sha256").update(JSON.stringify(payload)).digest("hex");
72
+ }
73
+
74
+ export {
75
+ getSearchConfigOverrides,
76
+ createSearchConfigFingerprint
77
+ };
@@ -0,0 +1,18 @@
1
+ // src/search/resolvers/types.ts
2
+ function commonPrefixLength(path1, path2) {
3
+ const parts1 = path1.split("/");
4
+ const parts2 = path2.split("/");
5
+ let count = 0;
6
+ for (let i = 0; i < Math.min(parts1.length, parts2.length); i++) {
7
+ if (parts1[i] === parts2[i]) {
8
+ count++;
9
+ } else {
10
+ break;
11
+ }
12
+ }
13
+ return count;
14
+ }
15
+
16
+ export {
17
+ commonPrefixLength
18
+ };
@@ -640,6 +640,7 @@ function clear(db) {
640
640
  db.exec("DELETE FROM chunks_fts");
641
641
  }
642
642
  var METADATA_KEY_EMBEDDING_DIMENSIONS = "embedding_dimensions";
643
+ var METADATA_KEY_INDEX_VERSION = "index_version";
643
644
  var METADATA_KEY_LANCEDB_MIGRATION_STATE = "lancedb_migration_displaycode_state";
644
645
  var METADATA_KEY_LANCEDB_MIGRATION_LOCK = "lancedb_migration_lock";
645
646
  var MIGRATION_LOCK_STALE_MS = 10 * 60 * 1e3;
@@ -663,6 +664,58 @@ function getStoredEmbeddingDimensions(db) {
663
664
  function setStoredEmbeddingDimensions(db, dimensions) {
664
665
  setMetadata(db, METADATA_KEY_EMBEDDING_DIMENSIONS, String(dimensions));
665
666
  }
667
+ function incrementStat(db, key, by = 1) {
668
+ const delta = Math.trunc(by);
669
+ db.prepare(`
670
+ INSERT INTO metadata (key, value)
671
+ VALUES (?, ?)
672
+ ON CONFLICT(key) DO UPDATE SET value = CAST(CAST(value AS INTEGER) + CAST(? AS INTEGER) AS TEXT)
673
+ `).run(key, String(delta), delta);
674
+ }
675
+ function setStatJson(db, key, value) {
676
+ setMetadata(db, key, JSON.stringify(value));
677
+ }
678
+ function getStatJson(db, key) {
679
+ const raw = getMetadata(db, key);
680
+ if (raw === null) return null;
681
+ try {
682
+ return JSON.parse(raw);
683
+ } catch {
684
+ return null;
685
+ }
686
+ }
687
+ function getAllStats(db) {
688
+ const rows = db.prepare(`SELECT key, value FROM metadata WHERE key LIKE 'stats.%'`).all();
689
+ const out = {};
690
+ for (const row of rows) out[row.key] = row.value;
691
+ return out;
692
+ }
693
+ function collectHealthSnapshot(db) {
694
+ const agg = db.prepare("SELECT COUNT(*) as c, COALESCE(SUM(size), 0) as bytes FROM files").get();
695
+ const langRows = db.prepare("SELECT language, COUNT(*) as c FROM files GROUP BY language").all();
696
+ const byLanguage = {};
697
+ for (const row of langRows) byLanguage[row.language] = row.c;
698
+ return {
699
+ totalFiles: agg.c,
700
+ totalBytes: agg.bytes,
701
+ byLanguage,
702
+ pendingMarks: countPendingMarks(db),
703
+ migrationState: getLanceDbMigrationState(db),
704
+ embeddingDimensions: getStoredEmbeddingDimensions(db),
705
+ indexVersion: getIndexVersion(db)
706
+ };
707
+ }
708
+ function getIndexVersion(db) {
709
+ const value = getMetadata(db, METADATA_KEY_INDEX_VERSION);
710
+ if (value === null) return 0;
711
+ const parsed = parseInt(value, 10);
712
+ return Number.isNaN(parsed) ? 0 : parsed;
713
+ }
714
+ function incrementIndexVersion(db) {
715
+ const next = getIndexVersion(db) + 1;
716
+ setMetadata(db, METADATA_KEY_INDEX_VERSION, String(next));
717
+ return next;
718
+ }
666
719
  function getLanceDbMigrationState(db) {
667
720
  const value = getMetadata(db, METADATA_KEY_LANCEDB_MIGRATION_STATE);
668
721
  if (value === "pending" || value === "done" || value === "aborted") return value;
@@ -732,6 +785,13 @@ export {
732
785
  clear,
733
786
  getStoredEmbeddingDimensions,
734
787
  setStoredEmbeddingDimensions,
788
+ incrementStat,
789
+ setStatJson,
790
+ getStatJson,
791
+ getAllStats,
792
+ collectHealthSnapshot,
793
+ getIndexVersion,
794
+ incrementIndexVersion,
735
795
  getLanceDbMigrationState,
736
796
  setLanceDbMigrationState,
737
797
  clearAllVectorIndexHash,
@@ -0,0 +1,143 @@
1
+ import {
2
+ ChunkContentLoader
3
+ } from "./chunk-XFIM2T6S.js";
4
+ import {
5
+ getVectorStore
6
+ } from "./chunk-3BNHQV5W.js";
7
+ import {
8
+ ensureIndexed,
9
+ formatTextResponse
10
+ } from "./chunk-VWBKZ6QL.js";
11
+ import {
12
+ generateProjectId,
13
+ initDb,
14
+ searchChunksFts
15
+ } from "./chunk-PPLFJGO3.js";
16
+ import {
17
+ logger
18
+ } from "./chunk-JVKVSTQ3.js";
19
+
20
+ // src/mcp/tools/findReferences.ts
21
+ import { z } from "zod";
22
+ var findReferencesSchema = z.object({
23
+ repo_path: z.string().describe(
24
+ "The absolute file system path to the repository root. (e.g., '/Users/dev/my-project')"
25
+ ),
26
+ symbol: z.string().min(1).describe("The exact symbol name to search for."),
27
+ exclude_definition: z.boolean().optional().describe("Exclude chunks whose breadcrumb tail matches the symbol name."),
28
+ max_results: z.number().int().positive().max(200).optional().describe("Maximum number of references to return. Defaults to 50.")
29
+ });
30
+ function escapeRegex(text) {
31
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32
+ }
33
+ function buildSymbolPattern(symbol) {
34
+ return new RegExp(`(?<![\\w$])${escapeRegex(symbol)}(?![\\w$])`, "u");
35
+ }
36
+ function breadcrumbTail(breadcrumb) {
37
+ const tail = breadcrumb.split(">").pop();
38
+ return tail?.trim() ?? "";
39
+ }
40
+ function countLinesBefore(content, index) {
41
+ let line = 1;
42
+ for (let i = 0; i < index && i < content.length; i++) {
43
+ if (content[i] === "\n") {
44
+ line += 1;
45
+ }
46
+ }
47
+ return line;
48
+ }
49
+ function locateMatches(code, pattern, baseLine) {
50
+ return code.split("\n").flatMap(
51
+ (text, offset) => pattern.test(text) ? [
52
+ {
53
+ line: baseLine + offset,
54
+ snippet: text.trim()
55
+ }
56
+ ] : []
57
+ );
58
+ }
59
+ async function handleFindReferences(args, onProgress) {
60
+ const { repo_path, symbol, exclude_definition = false, max_results = 50 } = args;
61
+ const projectId = generateProjectId(repo_path);
62
+ logger.info(
63
+ { repo_path, symbol, exclude_definition, max_results },
64
+ "MCP find-references \u8C03\u7528\u5F00\u59CB"
65
+ );
66
+ await ensureIndexed(repo_path, projectId, { onProgress });
67
+ const db = initDb(projectId);
68
+ try {
69
+ const hits = searchChunksFts(db, symbol, Math.max(max_results * 2, 20));
70
+ const uniquePaths = Array.from(new Set(hits.map((hit) => hit.filePath)));
71
+ const vectorStore = await getVectorStore(projectId);
72
+ const chunkMap = await vectorStore.getFilesChunks(uniquePaths);
73
+ const chunkByKey = /* @__PURE__ */ new Map();
74
+ for (const [filePath, chunks] of chunkMap) {
75
+ for (const chunk of chunks) {
76
+ chunkByKey.set(`${filePath}#${chunk.chunk_index}`, chunk);
77
+ }
78
+ }
79
+ const slices = Array.from(chunkByKey.values()).map((chunk) => ({
80
+ filePath: chunk.file_path,
81
+ start_index: chunk.start_index,
82
+ end_index: chunk.end_index
83
+ }));
84
+ const loader = new ChunkContentLoader(db);
85
+ const codeMap = loader.loadMany(slices);
86
+ const fileContentStmt = db.prepare("SELECT content FROM files WHERE path = ?");
87
+ const fullFileCache = /* @__PURE__ */ new Map();
88
+ const pattern = buildSymbolPattern(symbol);
89
+ const matches = [];
90
+ for (const hit of hits) {
91
+ if (matches.length >= max_results) {
92
+ break;
93
+ }
94
+ const chunk = chunkByKey.get(`${hit.filePath}#${hit.chunkIndex}`);
95
+ if (!chunk) {
96
+ continue;
97
+ }
98
+ if (exclude_definition && breadcrumbTail(chunk.breadcrumb) === symbol) {
99
+ continue;
100
+ }
101
+ const sliceKey = ChunkContentLoader.key({
102
+ filePath: chunk.file_path,
103
+ start_index: chunk.start_index,
104
+ end_index: chunk.end_index
105
+ });
106
+ const code = codeMap.get(sliceKey) ?? "";
107
+ if (!code) {
108
+ continue;
109
+ }
110
+ let fullContent = fullFileCache.get(chunk.file_path);
111
+ if (fullContent === void 0) {
112
+ const row = fileContentStmt.get(chunk.file_path);
113
+ fullContent = row?.content ?? "";
114
+ fullFileCache.set(chunk.file_path, fullContent);
115
+ }
116
+ const baseLine = countLinesBefore(fullContent, chunk.start_index);
117
+ for (const match of locateMatches(code, pattern, baseLine)) {
118
+ matches.push({
119
+ filePath: chunk.file_path,
120
+ line: match.line,
121
+ breadcrumb: chunk.breadcrumb,
122
+ snippet: match.snippet
123
+ });
124
+ if (matches.length >= max_results) {
125
+ break;
126
+ }
127
+ }
128
+ }
129
+ const body = matches.length > 0 ? matches.map(
130
+ (match) => `- ${match.filePath}:${match.line} | ${match.breadcrumb || "-"} | ${match.snippet}`
131
+ ).join("\n") : "No exact text references found.";
132
+ return formatTextResponse(`Found ${matches.length} text references for "${symbol}"
133
+
134
+ ${body}`);
135
+ } finally {
136
+ db.close();
137
+ }
138
+ }
139
+
140
+ export {
141
+ findReferencesSchema,
142
+ handleFindReferences
143
+ };
@@ -0,0 +1,38 @@
1
+ import {
2
+ DEFAULT_CONFIG
3
+ } from "./chunk-BFCIZ52F.js";
4
+
5
+ // src/defaultEnv.ts
6
+ function getDefaultEnvFileContent() {
7
+ return `# ContextWeaver \u793A\u4F8B\u73AF\u5883\u53D8\u91CF\u914D\u7F6E\u6587\u4EF6
8
+
9
+ # Embedding API \u914D\u7F6E\uFF08\u5FC5\u9700\uFF09
10
+ EMBEDDINGS_API_KEY=your-api-key-here
11
+ EMBEDDINGS_BASE_URL=https://api.siliconflow.cn/v1/embeddings
12
+ EMBEDDINGS_MODEL=BAAI/bge-m3
13
+ EMBEDDINGS_MAX_CONCURRENCY=10
14
+ EMBEDDINGS_DIMENSIONS=1024
15
+
16
+ # Reranker \u914D\u7F6E\uFF08\u5FC5\u9700\uFF09
17
+ RERANK_API_KEY=your-api-key-here
18
+ RERANK_BASE_URL=https://api.siliconflow.cn/v1/rerank
19
+ RERANK_MODEL=BAAI/bge-reranker-v2-m3
20
+ RERANK_TOP_N=20
21
+
22
+ # \u641C\u7D22\u53C2\u6570\uFF08\u53EF\u9009\uFF0C\u8986\u76D6\u5185\u7F6E\u9ED8\u8BA4\u503C\uFF09
23
+ CW_SEARCH_WVEC=${DEFAULT_CONFIG.wVec}
24
+ CW_SEARCH_WLEX=${DEFAULT_CONFIG.wLex}
25
+ CW_SEARCH_RERANK_TOP_N=${DEFAULT_CONFIG.rerankTopN}
26
+ CW_SEARCH_MAX_TOTAL_CHARS=${DEFAULT_CONFIG.maxTotalChars}
27
+ CW_SEARCH_VECTOR_TOP_K=${DEFAULT_CONFIG.vectorTopK}
28
+ CW_SEARCH_SMART_MAX_K=${DEFAULT_CONFIG.smartMaxK}
29
+ CW_SEARCH_IMPORT_FILES_PER_SEED=${DEFAULT_CONFIG.importFilesPerSeed}
30
+
31
+ # \u7D22\u5F15\u5FFD\u7565\u6A21\u5F0F\uFF08\u53EF\u9009\uFF0C\u9017\u53F7\u5206\u9694\uFF0C\u9ED8\u8BA4\u5DF2\u5305\u542B\u5E38\u89C1\u5FFD\u7565\u9879\uFF09
32
+ # IGNORE_PATTERNS=.venv,node_modules
33
+ `;
34
+ }
35
+
36
+ export {
37
+ getDefaultEnvFileContent
38
+ };