@chiway/contextweaver 1.4.0 → 1.5.1

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 (35) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +482 -196
  3. package/README.zh-CN.md +669 -0
  4. package/dist/{SearchService-OS7CYHNJ.js → SearchService-WVD6THR3.js} +116 -74
  5. package/dist/chunk-2EVCLNYN.js +223 -0
  6. package/dist/{chunk-ZOMGPIU6.js → chunk-3BNHQV5W.js} +1 -5
  7. package/dist/chunk-BFCIZ52F.js +102 -0
  8. package/dist/chunk-H4MGLXXF.js +115 -0
  9. package/dist/{lock-FL54LIQL.js → chunk-HHYPQA3X.js} +1 -1
  10. package/dist/chunk-IZ6IUHNN.js +77 -0
  11. package/dist/chunk-LB42CZEB.js +18 -0
  12. package/dist/chunk-MN6BQJDB.js +85 -0
  13. package/dist/{chunk-EMSMLPMK.js → chunk-ORYIVY7D.js} +10 -117
  14. package/dist/{chunk-RGJSXUFS.js → chunk-PPLFJGO3.js} +60 -0
  15. package/dist/chunk-TPM6YP43.js +38 -0
  16. package/dist/chunk-XFIM2T6S.js +57 -0
  17. package/dist/{chunk-AB24E3Z7.js → chunk-XMZZZKG7.js} +23 -79
  18. package/dist/chunk-XTWNT7KP.js +156 -0
  19. package/dist/chunk-YMQWNIQI.js +143 -0
  20. package/dist/{chunk-X7PAYQMT.js → chunk-YSQI5IRI.js} +125 -5
  21. package/dist/{codebaseRetrieval-3Z4CRA7X.js → codebaseRetrieval-4BFIM7PU.js} +5 -2
  22. package/dist/{db-PMVM7557.js → db-GBCLP4GG.js} +15 -1
  23. package/dist/findReferences-EBYR3VNL.js +16 -0
  24. package/dist/getSymbolDefinition-ZQK65FPN.js +17 -0
  25. package/dist/index.js +244 -41
  26. package/dist/listFiles-W7C5UYOP.js +14 -0
  27. package/dist/loadConfig-XTVT2OWW.js +9 -0
  28. package/dist/lock-HNKQ6X5B.js +8 -0
  29. package/dist/scanner-OVMAMQSQ.js +13 -0
  30. package/dist/server-ZIJIRVWH.js +347 -0
  31. package/dist/stats-AGKUCJQI.js +12 -0
  32. package/dist/{vectorStore-HPQZOVWF.js → vectorStore-4ODCERRO.js} +1 -1
  33. package/package.json +15 -23
  34. package/dist/scanner-2XGJWYHR.js +0 -11
  35. package/dist/server-XK6EINRV.js +0 -146
@@ -1,7 +1,13 @@
1
+ import {
2
+ commonPrefixLength
3
+ } from "./chunk-LB42CZEB.js";
4
+ import {
5
+ ChunkContentLoader
6
+ } from "./chunk-XFIM2T6S.js";
1
7
  import {
2
8
  getVectorStore,
3
9
  sampleCheckDisplayCode
4
- } from "./chunk-ZOMGPIU6.js";
10
+ } from "./chunk-3BNHQV5W.js";
5
11
  import {
6
12
  batchDeleteFileChunksFts,
7
13
  batchUpdateVectorIndexHash,
@@ -17,7 +23,7 @@ import {
17
23
  replayPendingMarks,
18
24
  setLanceDbMigrationState,
19
25
  tryAcquireLanceDbMigrationLock
20
- } from "./chunk-RGJSXUFS.js";
26
+ } from "./chunk-PPLFJGO3.js";
21
27
  import {
22
28
  logger
23
29
  } from "./chunk-JVKVSTQ3.js";
@@ -606,10 +612,7 @@ var Indexer = class {
606
612
  stats.deleted = toDelete.length;
607
613
  } catch (err) {
608
614
  const error = err;
609
- logger.error(
610
- { error: error.message, count: toDelete.length },
611
- "\u5220\u9664\u9636\u6BB5\u5931\u8D25\uFF0C\u5DF2\u6807\u8BB0\u91CD\u8BD5"
612
- );
615
+ logger.error({ error: error.message, count: toDelete.length }, "\u5220\u9664\u9636\u6BB5\u5931\u8D25\uFF0C\u5DF2\u6807\u8BB0\u91CD\u8BD5");
613
616
  stats.errors += toDelete.length;
614
617
  }
615
618
  }
@@ -678,16 +681,27 @@ var Indexer = class {
678
681
  continue;
679
682
  }
680
683
  logger.info(
681
- { batch: `${batchNum}/${totalBatches}`, texts: batchTexts.length, files: batchFiles.length },
684
+ {
685
+ batch: `${batchNum}/${totalBatches}`,
686
+ texts: batchTexts.length,
687
+ files: batchFiles.length
688
+ },
682
689
  "\u6279\u6B21 Embedding \u5F00\u59CB"
683
690
  );
684
691
  let embeddings;
685
692
  const EMBED_BATCH_SIZE = 10;
686
693
  try {
687
694
  const batchOnProgress = onProgress ? (_completed, _total) => {
688
- onProgress(completedChunks + Math.min(_completed * EMBED_BATCH_SIZE, batchTexts.length), totalChunks);
695
+ onProgress(
696
+ completedChunks + Math.min(_completed * EMBED_BATCH_SIZE, batchTexts.length),
697
+ totalChunks
698
+ );
689
699
  } : void 0;
690
- const results = await this.embeddingClient.embedBatch(batchTexts, EMBED_BATCH_SIZE, batchOnProgress);
700
+ const results = await this.embeddingClient.embedBatch(
701
+ batchTexts,
702
+ EMBED_BATCH_SIZE,
703
+ batchOnProgress
704
+ );
691
705
  embeddings = results.map((r) => r.embedding);
692
706
  } catch (err) {
693
707
  const error = err;
@@ -1007,75 +1021,6 @@ function scoreChunkTokenOverlap(chunk, code, queryTokens) {
1007
1021
  return score;
1008
1022
  }
1009
1023
 
1010
- // src/search/ChunkContentLoader.ts
1011
- var ChunkContentLoader = class _ChunkContentLoader {
1012
- constructor(db) {
1013
- this.db = db;
1014
- }
1015
- /**
1016
- * 生成 cache key
1017
- */
1018
- static key(slice) {
1019
- return `${slice.filePath}#${slice.start_index}#${slice.end_index}`;
1020
- }
1021
- /**
1022
- * 批量加载 chunk 正文
1023
- *
1024
- * @returns Map<key, code>,key 由 ChunkContentLoader.key 生成
1025
- */
1026
- loadMany(slices) {
1027
- const result = /* @__PURE__ */ new Map();
1028
- if (slices.length === 0) return result;
1029
- const byPath = /* @__PURE__ */ new Map();
1030
- for (const s of slices) {
1031
- let arr = byPath.get(s.filePath);
1032
- if (!arr) {
1033
- arr = [];
1034
- byPath.set(s.filePath, arr);
1035
- }
1036
- arr.push(s);
1037
- }
1038
- const stmt = this.db.prepare("SELECT content FROM files WHERE path = ?");
1039
- for (const [path, spans] of byPath) {
1040
- const row = stmt.get(path);
1041
- const content = row?.content ?? null;
1042
- for (const s of spans) {
1043
- const k = _ChunkContentLoader.key(s);
1044
- if (content === null) {
1045
- result.set(k, "");
1046
- continue;
1047
- }
1048
- const safeStart = Math.max(0, Math.min(s.start_index, content.length));
1049
- const safeEnd = Math.max(safeStart, Math.min(s.end_index, content.length));
1050
- result.set(k, content.slice(safeStart, safeEnd));
1051
- }
1052
- }
1053
- return result;
1054
- }
1055
- /**
1056
- * 加载单个 chunk 正文(便捷方法,不推荐在批量场景使用)
1057
- */
1058
- loadOne(slice) {
1059
- const map = this.loadMany([slice]);
1060
- return map.get(_ChunkContentLoader.key(slice)) ?? "";
1061
- }
1062
- };
1063
-
1064
- // src/search/resolvers/types.ts
1065
- function commonPrefixLength(path1, path2) {
1066
- const parts1 = path1.split("/");
1067
- const parts2 = path2.split("/");
1068
- let count = 0;
1069
- for (let i = 0; i < Math.min(parts1.length, parts2.length); i++) {
1070
- if (parts1[i] === parts2[i]) {
1071
- count++;
1072
- } else {
1073
- break;
1074
- }
1075
- }
1076
- return count;
1077
- }
1078
-
1079
1024
  // src/search/resolvers/CppResolver.ts
1080
1025
  var CPP_EXTENSIONS = /* @__PURE__ */ new Set([".c", ".cpp", ".cc", ".cxx", ".h", ".hpp", ".hh", ".hxx"]);
1081
1026
  var CppResolver = class {
@@ -1876,7 +1821,6 @@ export {
1876
1821
  getIndexer,
1877
1822
  closeAllIndexers,
1878
1823
  scoreChunkTokenOverlap,
1879
- ChunkContentLoader,
1880
1824
  invalidateAllExpanderCaches,
1881
1825
  getGraphExpander
1882
1826
  };
@@ -0,0 +1,156 @@
1
+ import {
2
+ getVectorStore
3
+ } from "./chunk-3BNHQV5W.js";
4
+ import {
5
+ closeDb,
6
+ collectHealthSnapshot,
7
+ getAllStats,
8
+ getStatJson,
9
+ initDb
10
+ } from "./chunk-PPLFJGO3.js";
11
+ import {
12
+ logger
13
+ } from "./chunk-JVKVSTQ3.js";
14
+ import {
15
+ getEmbeddingConfig
16
+ } from "./chunk-SKBAE26T.js";
17
+
18
+ // src/stats/index.ts
19
+ function num(stats, key) {
20
+ const v = stats[key];
21
+ if (v === void 0) return 0;
22
+ const parsed = Number.parseInt(v, 10);
23
+ return Number.isNaN(parsed) ? 0 : parsed;
24
+ }
25
+ function avg(sum, count) {
26
+ if (count <= 0) return null;
27
+ return sum / count;
28
+ }
29
+ async function collectStats(projectId) {
30
+ const db = initDb(projectId);
31
+ try {
32
+ const health = collectHealthSnapshot(db);
33
+ const stats = getAllStats(db);
34
+ let lancedbRows = 0;
35
+ try {
36
+ const store = await getVectorStore(projectId, getEmbeddingConfig().dimensions);
37
+ lancedbRows = await store.count();
38
+ } catch (err) {
39
+ logger.warn({ error: err.message }, "\u8BFB\u53D6 LanceDB \u884C\u6570\u5931\u8D25");
40
+ }
41
+ const computeRuns = num(stats, "stats.search.compute_runs");
42
+ const totalQueries = num(stats, "stats.search.total_queries");
43
+ const cacheHits = num(stats, "stats.search.cache_hits");
44
+ const index = {
45
+ totalRuns: num(stats, "stats.index.total_runs"),
46
+ lastRun: getStatJson(db, "stats.index.last_run_json"),
47
+ lastRunAt: getStatJson(db, "stats.index.last_run_at")
48
+ };
49
+ const search = {
50
+ totalQueries,
51
+ cacheHits,
52
+ cacheHitRate: totalQueries > 0 ? cacheHits / totalQueries : null,
53
+ computeRuns,
54
+ avgRetrieveMs: avg(num(stats, "stats.search.sum_retrieve_ms"), computeRuns),
55
+ avgRerankMs: avg(num(stats, "stats.search.sum_rerank_ms"), computeRuns),
56
+ avgExpandMs: avg(num(stats, "stats.search.sum_expand_ms"), computeRuns),
57
+ avgPackMs: avg(num(stats, "stats.search.sum_pack_ms"), computeRuns),
58
+ avgSeedCount: avg(num(stats, "stats.search.sum_seed_count"), computeRuns)
59
+ };
60
+ const diagnostics = buildDiagnostics(health, lancedbRows);
61
+ return { projectId, health, lancedbRows, index, search, diagnostics };
62
+ } finally {
63
+ closeDb(db);
64
+ }
65
+ }
66
+ function buildDiagnostics(health, lancedbRows) {
67
+ const out = [];
68
+ if (health.migrationState === "aborted") {
69
+ out.push(
70
+ "LanceDB \u8FC1\u79FB\u72B6\u6001\u4E3A aborted\uFF0C\u7D22\u5F15\u5199\u5165\u88AB\u62D2\u7EDD\u3002\u8FD0\u884C `contextweaver migrate --reset` \u89E3\u9664\u3002"
71
+ );
72
+ }
73
+ if (health.migrationState === "pending") {
74
+ out.push("LanceDB \u8FC1\u79FB\u72B6\u6001\u4E3A pending\uFF0C\u53EF\u80FD\u4E0A\u6B21\u8FC1\u79FB\u672A\u5B8C\u6210\u3002");
75
+ }
76
+ if (health.pendingMarks > 0) {
77
+ out.push(`pending_marks \u79EF\u538B ${health.pendingMarks} \u6761\uFF0C\u4E0B\u6B21\u542F\u52A8\u5C06\u91CD\u653E\u3002\u82E5\u6301\u7EED\u4E0D\u51CF\u9700\u6392\u67E5\u3002`);
78
+ }
79
+ if (health.totalFiles > 0 && lancedbRows === 0) {
80
+ out.push(
81
+ `\u5DF2\u7D22\u5F15 ${health.totalFiles} \u4E2A\u6587\u4EF6\u4F46 LanceDB \u65E0\u5411\u91CF\u884C\uFF0C\u5411\u91CF\u7D22\u5F15\u53EF\u80FD\u672A\u5EFA\u7ACB\u3002\u8FD0\u884C \`contextweaver index\` \u91CD\u5EFA\u3002`
82
+ );
83
+ }
84
+ if (health.embeddingDimensions === null && health.totalFiles > 0) {
85
+ out.push("\u672A\u8BB0\u5F55 embedding \u7EF4\u5EA6\uFF0C\u7D22\u5F15\u5143\u6570\u636E\u53EF\u80FD\u4E0D\u5B8C\u6574\u3002");
86
+ }
87
+ return out;
88
+ }
89
+ function renderStatsText(report) {
90
+ const fmt = (v, suffix = "") => v === null ? "\u2014" : `${Number.isInteger(v) ? v : v.toFixed(1)}${suffix}`;
91
+ const pct = (v) => v === null ? "\u2014" : `${(v * 100).toFixed(1)}%`;
92
+ const bytes = (n) => {
93
+ if (n < 1024) return `${n} B`;
94
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
95
+ return `${(n / 1024 / 1024).toFixed(1)} MB`;
96
+ };
97
+ const lines = [];
98
+ lines.push(`ContextWeaver \u7EDF\u8BA1 (projectId: ${report.projectId})`);
99
+ lines.push("");
100
+ const ix = report.index;
101
+ lines.push("\u3010\u7D22\u5F15\u8FC7\u7A0B\u3011");
102
+ lines.push(` \u7D2F\u8BA1\u7D22\u5F15\u8FD0\u884C: ${ix.totalRuns} \u6B21`);
103
+ if (ix.lastRunAt) {
104
+ lines.push(` \u4E0A\u6B21\u7D22\u5F15\u65F6\u95F4: ${new Date(ix.lastRunAt).toLocaleString()}`);
105
+ }
106
+ if (ix.lastRun) {
107
+ const r = ix.lastRun;
108
+ lines.push(
109
+ ` \u4E0A\u6B21\u7ED3\u679C: \u603B\u6570=${r.totalFiles} \u65B0\u589E=${r.added} \u4FEE\u6539=${r.modified} \u672A\u53D8=${r.unchanged} \u5220\u9664=${r.deleted} \u8DF3\u8FC7=${r.skipped} \u9519\u8BEF=${r.errors}`
110
+ );
111
+ if (r.vectorIndex) {
112
+ lines.push(
113
+ ` \u5411\u91CF\u7D22\u5F15: \u5DF2\u7D22\u5F15=${r.vectorIndex.indexed} \u5220\u9664=${r.vectorIndex.deleted} \u9519\u8BEF=${r.vectorIndex.errors}`
114
+ );
115
+ }
116
+ } else {
117
+ lines.push(" \u4E0A\u6B21\u7ED3\u679C: \u6682\u65E0\uFF08\u5C1A\u672A\u7D22\u5F15\uFF09");
118
+ }
119
+ lines.push("");
120
+ const s = report.search;
121
+ lines.push("\u3010\u641C\u7D22\u8D28\u91CF/\u884C\u4E3A\u3011");
122
+ lines.push(
123
+ ` \u7D2F\u8BA1\u67E5\u8BE2: ${s.totalQueries} \u6B21 (\u7F13\u5B58\u547D\u4E2D ${s.cacheHits}\uFF0C\u547D\u4E2D\u7387 ${pct(s.cacheHitRate)})`
124
+ );
125
+ lines.push(` \u5B9E\u9645\u8BA1\u7B97: ${s.computeRuns} \u6B21\uFF08\u672A\u547D\u4E2D\u7F13\u5B58\uFF0C\u4F5C\u4E3A\u4E0B\u5217\u5747\u503C\u5206\u6BCD\uFF09`);
126
+ lines.push(
127
+ ` \u5E73\u5747\u8017\u65F6: retrieve=${fmt(s.avgRetrieveMs, "ms")} rerank=${fmt(s.avgRerankMs, "ms")} expand=${fmt(s.avgExpandMs, "ms")} pack=${fmt(s.avgPackMs, "ms")}`
128
+ );
129
+ lines.push(` \u5E73\u5747\u53EC\u56DE: ${fmt(s.avgSeedCount)} \u4E2A seed`);
130
+ lines.push("");
131
+ const h = report.health;
132
+ lines.push("\u3010\u5065\u5EB7/\u4E00\u81F4\u6027\u3011");
133
+ lines.push(` \u6587\u4EF6: ${h.totalFiles} \u4E2A\uFF0C\u6B63\u6587\u603B\u91CF ${bytes(h.totalBytes)}`);
134
+ lines.push(` LanceDB \u5411\u91CF\u884C: ${report.lancedbRows}`);
135
+ lines.push(
136
+ ` embedding \u7EF4\u5EA6: ${h.embeddingDimensions ?? "\u2014"} \u7D22\u5F15\u7248\u672C: ${h.indexVersion} \u8FC1\u79FB\u72B6\u6001: ${h.migrationState ?? "\u672A\u8BBE\u7F6E"} pending_marks: ${h.pendingMarks}`
137
+ );
138
+ const langs = Object.entries(h.byLanguage).sort((a, b) => b[1] - a[1]);
139
+ if (langs.length > 0) {
140
+ const langStr = langs.map(([lang, c]) => `${lang}=${c}`).join(" ");
141
+ lines.push(` \u8BED\u8A00\u5360\u6BD4: ${langStr}`);
142
+ }
143
+ lines.push("");
144
+ if (report.diagnostics.length > 0) {
145
+ lines.push("\u3010\u8BCA\u65AD\u544A\u8B66\u3011");
146
+ for (const d of report.diagnostics) lines.push(` \u26A0 ${d}`);
147
+ } else {
148
+ lines.push("\u3010\u8BCA\u65AD\u3011\u65E0\u5F02\u5E38");
149
+ }
150
+ return lines.join("\n");
151
+ }
152
+
153
+ export {
154
+ collectStats,
155
+ renderStatsText
156
+ };
@@ -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-H4MGLXXF.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
+ };
@@ -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";
@@ -178,7 +181,13 @@ var GRAMMAR_MODULES = {
178
181
  java: "tree-sitter-java",
179
182
  c: "tree-sitter-c",
180
183
  cpp: "tree-sitter-cpp",
181
- c_sharp: "tree-sitter-c-sharp"
184
+ c_sharp: "tree-sitter-c-sharp",
185
+ ruby: "tree-sitter-ruby",
186
+ php: "tree-sitter-php",
187
+ kotlin: "tree-sitter-kotlin",
188
+ swift: "tree-sitter-swift",
189
+ lua: "@tree-sitter-grammars/tree-sitter-lua",
190
+ shell: "tree-sitter-bash"
182
191
  };
183
192
  var loadedGrammars = /* @__PURE__ */ new Map();
184
193
  var parserCache = /* @__PURE__ */ new Map();
@@ -428,6 +437,89 @@ var LANGUAGE_SPECS = {
428
437
  namespace_declaration: "namespace "
429
438
  },
430
439
  commentTypes: /* @__PURE__ */ new Set(["comment"])
440
+ },
441
+ ruby: {
442
+ hierarchy: /* @__PURE__ */ new Set(["module", "class", "singleton_class", "method", "singleton_method"]),
443
+ nameFields: ["name"],
444
+ nameNodeTypes: /* @__PURE__ */ new Set(["constant", "identifier"]),
445
+ prefixMap: {
446
+ module: "module ",
447
+ class: "class ",
448
+ singleton_class: "class ",
449
+ method: "def ",
450
+ singleton_method: "def "
451
+ },
452
+ commentTypes: /* @__PURE__ */ new Set(["comment"])
453
+ },
454
+ php: {
455
+ hierarchy: /* @__PURE__ */ new Set([
456
+ "namespace_definition",
457
+ "class_declaration",
458
+ "interface_declaration",
459
+ "trait_declaration",
460
+ "enum_declaration",
461
+ "method_declaration",
462
+ "function_definition"
463
+ ]),
464
+ nameFields: ["name"],
465
+ nameNodeTypes: /* @__PURE__ */ new Set(["name"]),
466
+ prefixMap: {
467
+ namespace_definition: "namespace ",
468
+ class_declaration: "class ",
469
+ interface_declaration: "interface ",
470
+ trait_declaration: "trait ",
471
+ enum_declaration: "enum ",
472
+ method_declaration: "",
473
+ function_definition: "function "
474
+ },
475
+ commentTypes: /* @__PURE__ */ new Set(["comment"])
476
+ },
477
+ kotlin: {
478
+ hierarchy: /* @__PURE__ */ new Set(["class_declaration", "object_declaration", "function_declaration"]),
479
+ nameFields: ["name"],
480
+ nameNodeTypes: /* @__PURE__ */ new Set(["type_identifier", "simple_identifier"]),
481
+ prefixMap: {
482
+ class_declaration: "class ",
483
+ object_declaration: "object ",
484
+ function_declaration: "fun "
485
+ },
486
+ commentTypes: /* @__PURE__ */ new Set(["line_comment", "multiline_comment"])
487
+ },
488
+ swift: {
489
+ hierarchy: /* @__PURE__ */ new Set([
490
+ "class_declaration",
491
+ "protocol_declaration",
492
+ "function_declaration",
493
+ "init_declaration"
494
+ ]),
495
+ nameFields: ["name"],
496
+ nameNodeTypes: /* @__PURE__ */ new Set(["type_identifier", "simple_identifier"]),
497
+ prefixMap: {
498
+ class_declaration: "type ",
499
+ protocol_declaration: "protocol ",
500
+ function_declaration: "func ",
501
+ init_declaration: "init "
502
+ },
503
+ commentTypes: /* @__PURE__ */ new Set(["comment", "multiline_comment"])
504
+ },
505
+ lua: {
506
+ hierarchy: /* @__PURE__ */ new Set(["function_declaration", "function_definition"]),
507
+ nameFields: ["name"],
508
+ nameNodeTypes: /* @__PURE__ */ new Set(["identifier", "dot_index_expression", "method_index_expression"]),
509
+ prefixMap: {
510
+ function_declaration: "function ",
511
+ function_definition: "function "
512
+ },
513
+ commentTypes: /* @__PURE__ */ new Set(["comment"])
514
+ },
515
+ shell: {
516
+ hierarchy: /* @__PURE__ */ new Set(["function_definition"]),
517
+ nameFields: ["name"],
518
+ nameNodeTypes: /* @__PURE__ */ new Set(["word"]),
519
+ prefixMap: {
520
+ function_definition: "function "
521
+ },
522
+ commentTypes: /* @__PURE__ */ new Set(["comment"])
431
523
  }
432
524
  };
433
525
  function getLanguageSpec(language) {
@@ -1067,7 +1159,20 @@ function sha256(data) {
1067
1159
 
1068
1160
  // src/scanner/processor.ts
1069
1161
  var MAX_FILE_SIZE = 100 * 1024;
1070
- var FALLBACK_LANGS = /* @__PURE__ */ new Set(["python", "go", "rust", "java", "markdown", "json"]);
1162
+ var FALLBACK_LANGS = /* @__PURE__ */ new Set([
1163
+ "python",
1164
+ "go",
1165
+ "rust",
1166
+ "java",
1167
+ "markdown",
1168
+ "json",
1169
+ "ruby",
1170
+ "php",
1171
+ "kotlin",
1172
+ "swift",
1173
+ "lua",
1174
+ "shell"
1175
+ ]);
1071
1176
  function shouldSkipJson(relPath) {
1072
1177
  if (relPath.endsWith("-lock.json") || relPath.endsWith("package-lock.json")) {
1073
1178
  return true;
@@ -1382,6 +1487,19 @@ async function scan(rootPath, options = {}) {
1382
1487
  logger.warn({ error: error.message }, "GC \u8DF3\u8FC7");
1383
1488
  }
1384
1489
  }
1490
+ const didWork = stats.added + stats.modified + stats.deleted > 0;
1491
+ if (didWork) {
1492
+ incrementIndexVersion(db);
1493
+ }
1494
+ try {
1495
+ if (didWork) {
1496
+ incrementStat(db, "stats.index.total_runs");
1497
+ }
1498
+ setStatJson(db, "stats.index.last_run_json", stats);
1499
+ setStatJson(db, "stats.index.last_run_at", Date.now());
1500
+ } catch (err) {
1501
+ logger.warn({ error: err.message }, "\u7D22\u5F15\u7EDF\u8BA1\u57CB\u70B9\u5931\u8D25");
1502
+ }
1385
1503
  invalidateAllExpanderCaches();
1386
1504
  return stats;
1387
1505
  } finally {
@@ -1392,5 +1510,7 @@ async function scan(rootPath, options = {}) {
1392
1510
  }
1393
1511
 
1394
1512
  export {
1513
+ initFilter,
1514
+ isFiltered,
1395
1515
  scan
1396
1516
  };
@@ -1,8 +1,11 @@
1
1
  import {
2
2
  codebaseRetrievalSchema,
3
3
  handleCodebaseRetrieval
4
- } from "./chunk-EMSMLPMK.js";
5
- import "./chunk-RGJSXUFS.js";
4
+ } from "./chunk-ORYIVY7D.js";
5
+ import "./chunk-H4MGLXXF.js";
6
+ import "./chunk-TPM6YP43.js";
7
+ import "./chunk-BFCIZ52F.js";
8
+ import "./chunk-PPLFJGO3.js";
6
9
  import "./chunk-JVKVSTQ3.js";
7
10
  import "./chunk-SKBAE26T.js";
8
11
  export {
@@ -7,23 +7,30 @@ import {
7
7
  clearAllVectorIndexHash,
8
8
  clearVectorIndexHash,
9
9
  closeDb,
10
+ collectHealthSnapshot,
10
11
  countPendingMarks,
11
12
  deletePendingMarks,
12
13
  generateProjectId,
13
14
  getAllFileMeta,
14
15
  getAllPaths,
16
+ getAllStats,
15
17
  getFilesNeedingVectorIndex,
18
+ getIndexVersion,
16
19
  getLanceDbMigrationState,
20
+ getStatJson,
17
21
  getStoredEmbeddingDimensions,
22
+ incrementIndexVersion,
23
+ incrementStat,
18
24
  initDb,
19
25
  insertPendingMarks,
20
26
  migrateSchema,
21
27
  releaseLanceDbMigrationLock,
22
28
  replayPendingMarks,
23
29
  setLanceDbMigrationState,
30
+ setStatJson,
24
31
  setStoredEmbeddingDimensions,
25
32
  tryAcquireLanceDbMigrationLock
26
- } from "./chunk-RGJSXUFS.js";
33
+ } from "./chunk-PPLFJGO3.js";
27
34
  import "./chunk-JVKVSTQ3.js";
28
35
  import "./chunk-SKBAE26T.js";
29
36
  export {
@@ -35,20 +42,27 @@ export {
35
42
  clearAllVectorIndexHash,
36
43
  clearVectorIndexHash,
37
44
  closeDb,
45
+ collectHealthSnapshot,
38
46
  countPendingMarks,
39
47
  deletePendingMarks,
40
48
  generateProjectId,
41
49
  getAllFileMeta,
42
50
  getAllPaths,
51
+ getAllStats,
43
52
  getFilesNeedingVectorIndex,
53
+ getIndexVersion,
44
54
  getLanceDbMigrationState,
55
+ getStatJson,
45
56
  getStoredEmbeddingDimensions,
57
+ incrementIndexVersion,
58
+ incrementStat,
46
59
  initDb,
47
60
  insertPendingMarks,
48
61
  migrateSchema,
49
62
  releaseLanceDbMigrationLock,
50
63
  replayPendingMarks,
51
64
  setLanceDbMigrationState,
65
+ setStatJson,
52
66
  setStoredEmbeddingDimensions,
53
67
  tryAcquireLanceDbMigrationLock
54
68
  };