@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.
- package/LICENSE +1 -1
- package/README.md +482 -196
- package/README.zh-CN.md +669 -0
- package/dist/{SearchService-OS7CYHNJ.js → SearchService-WVD6THR3.js} +116 -74
- package/dist/chunk-2EVCLNYN.js +223 -0
- package/dist/{chunk-ZOMGPIU6.js → chunk-3BNHQV5W.js} +1 -5
- package/dist/chunk-BFCIZ52F.js +102 -0
- package/dist/chunk-H4MGLXXF.js +115 -0
- package/dist/{lock-FL54LIQL.js → chunk-HHYPQA3X.js} +1 -1
- package/dist/chunk-IZ6IUHNN.js +77 -0
- package/dist/chunk-LB42CZEB.js +18 -0
- package/dist/chunk-MN6BQJDB.js +85 -0
- package/dist/{chunk-EMSMLPMK.js → chunk-ORYIVY7D.js} +10 -117
- package/dist/{chunk-RGJSXUFS.js → chunk-PPLFJGO3.js} +60 -0
- package/dist/chunk-TPM6YP43.js +38 -0
- package/dist/chunk-XFIM2T6S.js +57 -0
- package/dist/{chunk-AB24E3Z7.js → chunk-XMZZZKG7.js} +23 -79
- package/dist/chunk-XTWNT7KP.js +156 -0
- package/dist/chunk-YMQWNIQI.js +143 -0
- package/dist/{chunk-X7PAYQMT.js → chunk-YSQI5IRI.js} +125 -5
- package/dist/{codebaseRetrieval-3Z4CRA7X.js → codebaseRetrieval-4BFIM7PU.js} +5 -2
- package/dist/{db-PMVM7557.js → db-GBCLP4GG.js} +15 -1
- package/dist/findReferences-EBYR3VNL.js +16 -0
- package/dist/getSymbolDefinition-ZQK65FPN.js +17 -0
- package/dist/index.js +244 -41
- package/dist/listFiles-W7C5UYOP.js +14 -0
- package/dist/loadConfig-XTVT2OWW.js +9 -0
- package/dist/lock-HNKQ6X5B.js +8 -0
- package/dist/scanner-OVMAMQSQ.js +13 -0
- package/dist/server-ZIJIRVWH.js +347 -0
- package/dist/stats-AGKUCJQI.js +12 -0
- package/dist/{vectorStore-HPQZOVWF.js → vectorStore-4ODCERRO.js} +1 -1
- package/package.json +15 -23
- package/dist/scanner-2XGJWYHR.js +0 -11
- 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-
|
|
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-
|
|
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
|
-
{
|
|
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(
|
|
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(
|
|
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-
|
|
5
|
+
} from "./chunk-XMZZZKG7.js";
|
|
6
6
|
import {
|
|
7
7
|
closeAllVectorStores
|
|
8
|
-
} from "./chunk-
|
|
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-
|
|
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([
|
|
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-
|
|
5
|
-
import "./chunk-
|
|
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-
|
|
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
|
};
|