@chiway/contextweaver 1.1.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 (37) hide show
  1. package/README.md +138 -28
  2. package/dist/{SearchService-MYPOCM3B.js → SearchService-WVD6THR3.js} +170 -82
  3. package/dist/chunk-3BNHQV5W.js +373 -0
  4. package/dist/chunk-BFCIZ52F.js +102 -0
  5. package/dist/{chunk-NQR4CGQ6.js → chunk-GDVB6PJ4.js} +58 -10
  6. package/dist/{lock-DVY3KJSK.js → chunk-HHYPQA3X.js} +2 -3
  7. package/dist/chunk-ISVCQFB4.js +223 -0
  8. package/dist/chunk-IZ6IUHNN.js +77 -0
  9. package/dist/{chunk-AMQQK4P7.js → chunk-JVKVSTQ3.js} +1 -2
  10. package/dist/chunk-LB42CZEB.js +18 -0
  11. package/dist/{chunk-6Z4JEEVJ.js → chunk-PPLFJGO3.js} +303 -58
  12. package/dist/chunk-R6CNZXZ7.js +143 -0
  13. package/dist/{chunk-RJURH22T.js → chunk-SKBAE26T.js} +0 -1
  14. package/dist/chunk-TPM6YP43.js +38 -0
  15. package/dist/{chunk-7G5V7YT5.js → chunk-V3K4YVAR.js} +12 -120
  16. package/dist/chunk-VWBKZ6QL.js +115 -0
  17. package/dist/chunk-XFIM2T6S.js +57 -0
  18. package/dist/{chunk-6QMYML5V.js → chunk-XMZZZKG7.js} +361 -295
  19. package/dist/chunk-XTWNT7KP.js +156 -0
  20. package/dist/chunk-Y6H7C3NA.js +85 -0
  21. package/dist/codebaseRetrieval-DIS5RH2C.js +14 -0
  22. package/dist/{config-BWZ6CU3W.js → config-LCOJHTCF.js} +1 -2
  23. package/dist/db-GBCLP4GG.js +68 -0
  24. package/dist/findReferences-N7ML7TUP.js +16 -0
  25. package/dist/getSymbolDefinition-6KMY4H33.js +17 -0
  26. package/dist/index.js +271 -40
  27. package/dist/listFiles-4VT2TPJD.js +14 -0
  28. package/dist/loadConfig-XTVT2OWW.js +9 -0
  29. package/dist/lock-HNKQ6X5B.js +8 -0
  30. package/dist/scanner-QDFZJLP7.js +13 -0
  31. package/dist/server-UAI3U7AB.js +347 -0
  32. package/dist/stats-AGKUCJQI.js +12 -0
  33. package/dist/vectorStore-4ODCERRO.js +12 -0
  34. package/package.json +9 -23
  35. package/dist/codebaseRetrieval-NLAMGOA2.js +0 -12
  36. package/dist/scanner-RFG4YWYI.js +0 -11
  37. package/dist/server-27HI7WZO.js +0 -147
@@ -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
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  isDev,
3
3
  isMcpMode
4
- } from "./chunk-RJURH22T.js";
4
+ } from "./chunk-SKBAE26T.js";
5
5
 
6
6
  // src/utils/logger.ts
7
7
  import fs from "fs";
@@ -168,4 +168,3 @@ export {
168
168
  logger,
169
169
  isDebugEnabled
170
170
  };
171
- //# sourceMappingURL=chunk-AMQQK4P7.js.map
@@ -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
+ };