* Handle codegraph_search
(args: Record<string, unknown>)
| 1491 | * Handle codegraph_search |
| 1492 | */ |
| 1493 | private async handleSearch(args: Record<string, unknown>): Promise<ToolResult> { |
| 1494 | const query = this.validateString(args.query, 'query'); |
| 1495 | if (typeof query !== 'string') return query; |
| 1496 | |
| 1497 | const cg = this.getCodeGraph(args.projectPath as string | undefined); |
| 1498 | const rawKind = args.kind as string | undefined; |
| 1499 | // The schema enum says 'type' (what agents naturally reach for); the |
| 1500 | // NodeKind is 'type_alias'. Without the mapping, kind: "type" silently |
| 1501 | // matched nothing — a filter value we advertise must work. |
| 1502 | const kind = rawKind === 'type' ? 'type_alias' : rawKind; |
| 1503 | const rawLimit = Number(args.limit) || 10; |
| 1504 | const limit = clamp(rawLimit, 1, 100); |
| 1505 | |
| 1506 | const results = cg.searchNodes(query, { |
| 1507 | limit, |
| 1508 | kinds: kind ? [kind as NodeKind] : undefined, |
| 1509 | }); |
| 1510 | |
| 1511 | if (results.length === 0) { |
| 1512 | return this.textResult(`No results found for "${query}"`); |
| 1513 | } |
| 1514 | |
| 1515 | // Down-rank generated files within the FTS-returned set so a search |
| 1516 | // for "Send" surfaces the hand-written keeper before .pb.go stubs |
| 1517 | // that share the name. Stable: only reorders generated vs. not. |
| 1518 | const ranked = [...results].sort((a, b) => { |
| 1519 | const aGen = isGeneratedFile(a.node.filePath) ? 1 : 0; |
| 1520 | const bGen = isGeneratedFile(b.node.filePath) ? 1 : 0; |
| 1521 | return aGen - bGen; |
| 1522 | }); |
| 1523 | |
| 1524 | const formatted = this.formatSearchResults(ranked); |
| 1525 | return this.textResult(this.truncateOutput(formatted)); |
| 1526 | } |
| 1527 | |
| 1528 | /** |
| 1529 | * Group symbol matches into DISTINCT DEFINITIONS — one group per |
no test coverage detected