* Handle codegraph_search
(args: Record<string, unknown>)
| 1563 | * Handle codegraph_search |
| 1564 | */ |
| 1565 | private async handleSearch(args: Record<string, unknown>): Promise<ToolResult> { |
| 1566 | const query = this.validateString(args.query, 'query'); |
| 1567 | if (typeof query !== 'string') return query; |
| 1568 | |
| 1569 | const cg = this.getCodeGraph(args.projectPath as string | undefined); |
| 1570 | const rawKind = args.kind as string | undefined; |
| 1571 | // The schema enum says 'type' (what agents naturally reach for); the |
| 1572 | // NodeKind is 'type_alias'. Without the mapping, kind: "type" silently |
| 1573 | // matched nothing — a filter value we advertise must work. |
| 1574 | const kind = rawKind === 'type' ? 'type_alias' : rawKind; |
| 1575 | const rawLimit = Number(args.limit) || 10; |
| 1576 | const limit = clamp(rawLimit, 1, 100); |
| 1577 | |
| 1578 | const results = cg.searchNodes(query, { |
| 1579 | limit, |
| 1580 | kinds: kind ? [kind as NodeKind] : undefined, |
| 1581 | }); |
| 1582 | |
| 1583 | if (results.length === 0) { |
| 1584 | return this.textResult(`No results found for "${query}"`); |
| 1585 | } |
| 1586 | |
| 1587 | // Down-rank generated files within the FTS-returned set so a search |
| 1588 | // for "Send" surfaces the hand-written keeper before .pb.go stubs |
| 1589 | // that share the name. Stable: only reorders generated vs. not. |
| 1590 | const ranked = [...results].sort((a, b) => { |
| 1591 | const aGen = isGeneratedFile(a.node.filePath) ? 1 : 0; |
| 1592 | const bGen = isGeneratedFile(b.node.filePath) ? 1 : 0; |
| 1593 | return aGen - bGen; |
| 1594 | }); |
| 1595 | |
| 1596 | const formatted = this.formatSearchResults(ranked); |
| 1597 | return this.textResult(this.truncateOutput(formatted)); |
| 1598 | } |
| 1599 | |
| 1600 | /** |
| 1601 | * Group symbol matches into DISTINCT DEFINITIONS — one group per |
no test coverage detected