(options: SemanticSearchOptions)
| 155 | } |
| 156 | |
| 157 | export async function semanticCodeSearch(options: SemanticSearchOptions): Promise<string> { |
| 158 | const index = await buildIndex(options.rootDir); |
| 159 | const searchOptions: SearchQueryOptions = { |
| 160 | topK: options.topK, |
| 161 | semanticWeight: options.semanticWeight, |
| 162 | keywordWeight: options.keywordWeight, |
| 163 | minSemanticScore: options.minSemanticScore, |
| 164 | minKeywordScore: options.minKeywordScore, |
| 165 | minCombinedScore: options.minCombinedScore, |
| 166 | requireKeywordMatch: options.requireKeywordMatch, |
| 167 | requireSemanticMatch: options.requireSemanticMatch, |
| 168 | }; |
| 169 | const results = await index.search(options.query, searchOptions); |
| 170 | |
| 171 | if (results.length === 0) return "No matching files found for the given query."; |
| 172 | |
| 173 | const lines: string[] = [`Top ${results.length} hybrid matches for: "${options.query}"\n`]; |
| 174 | |
| 175 | for (let i = 0; i < results.length; i++) { |
| 176 | const r = results[i]; |
| 177 | lines.push(`${i + 1}. ${r.path} (${r.score}% total)`); |
| 178 | lines.push(` Semantic: ${r.semanticScore}% | Keyword: ${r.keywordScore}%`); |
| 179 | if (r.header) lines.push(` Header: ${r.header}`); |
| 180 | if (r.matchedSymbols.length > 0) lines.push(` Matched symbols: ${r.matchedSymbols.join(", ")}`); |
| 181 | if (r.matchedSymbolLocations.length > 0) lines.push(` Definition lines: ${r.matchedSymbolLocations.join(", ")}`); |
| 182 | lines.push(""); |
| 183 | } |
| 184 | |
| 185 | return lines.join("\n"); |
| 186 | } |
| 187 | |
| 188 | export function invalidateSearchCache(): void { |
| 189 | cachedIndex = null; |
no test coverage detected