* Handle codegraph_search
(args: Record<string, unknown>)
| 1456 | * Handle codegraph_search |
| 1457 | */ |
| 1458 | private async handleSearch(args: Record<string, unknown>): Promise<ToolResult> { |
| 1459 | const query = this.validateString(args.query, 'query'); |
| 1460 | if (typeof query !== 'string') return query; |
| 1461 | |
| 1462 | const cg = this.getCodeGraph(args.projectPath as string | undefined); |
| 1463 | const rawKind = args.kind as string | undefined; |
| 1464 | // The schema enum says 'type' (what agents naturally reach for); the |
| 1465 | // NodeKind is 'type_alias'. Without the mapping, kind: "type" silently |
| 1466 | // matched nothing — a filter value we advertise must work. |
| 1467 | const kind = rawKind === 'type' ? 'type_alias' : rawKind; |
| 1468 | const rawLimit = Number(args.limit) || 10; |
| 1469 | const limit = clamp(rawLimit, 1, 100); |
| 1470 | |
| 1471 | const results = cg.searchNodes(query, { |
| 1472 | limit, |
| 1473 | kinds: kind ? [kind as NodeKind] : undefined, |
| 1474 | }); |
| 1475 | |
| 1476 | if (results.length === 0) { |
| 1477 | return this.textResult(`No results found for "${query}"`); |
| 1478 | } |
| 1479 | |
| 1480 | // Down-rank generated files within the FTS-returned set so a search |
| 1481 | // for "Send" surfaces the hand-written keeper before .pb.go stubs |
| 1482 | // that share the name. Stable: only reorders generated vs. not. |
| 1483 | const ranked = [...results].sort((a, b) => { |
| 1484 | const aGen = isGeneratedFile(a.node.filePath) ? 1 : 0; |
| 1485 | const bGen = isGeneratedFile(b.node.filePath) ? 1 : 0; |
| 1486 | return aGen - bGen; |
| 1487 | }); |
| 1488 | |
| 1489 | const formatted = this.formatSearchResults(ranked); |
| 1490 | return this.textResult(this.truncateOutput(formatted)); |
| 1491 | } |
| 1492 | |
| 1493 | /** |
| 1494 | * Group symbol matches into DISTINCT DEFINITIONS — one group per |
no test coverage detected