Перейти до вмісту

Шукати код через граф коду

Цей посібник показує, як занести репозиторій у граф коду, а потім скористатися ним, щоб відповісти на питання, яке насправді постає перед рефакторингом: від чого це залежить?

Граф коду — це база даних символів і ребер, яку будують, розбираючи ваші зареєстровані чекаути через tree-sitter. Його інструменти призначені для агентів — дістатися до них можна, попросивши агента.

Граф індексує Dart, JavaScript, TypeScript, TSX, PHP, Python, Rust, Zig, C, C++, Go, Java, Ruby, C#, Swift, Kotlin, R, Assembly, MATLAB і Ada. Файли будь-якою іншою мовою не розбираються, тож вони не потрапляють у search_code, code_symbol, code_callers, code_callees чи code_impact.

Ще дві речі визначають, що саме потрапляє в індекс:

  • У робочому дереві git перелік файлів покладається на git ls-files --cached --others --exclude-standard, тож дотримано кожного .gitignore, вкладеного ignore-файлу, .git/info/exclude і глобального файлу винятків. Саме це тримає node_modules і результати збірки поза графом.
  • Згенерований Dart відкидають у будь-якому разі. Згенеровані файли зазвичай закомічено, тож сам git їх не виключив би, а вони змінюються під час кожного запуску кодогенерації.

Реєстрація чекауту породжує RepoAdded, яка автоматично запускає для нього конвеєр index_code. Див. Додати репозиторії до робочого простору.

Щоб переіндексувати вручну:

  1. Відкрийте Налаштування → Робочий простір → Репозиторії.
  2. Натисніть кнопку Індексувати код у рядку репозиторію.
  3. Поки вона виконується, кнопка показує, скільки файлів уже оброблено із загальної кількості, та елемент керування скасуванням. Коли все завершується, вона стає позначкою з кількістю символів.

Граф розбито на партиції за робочим простором, репозиторієм і чекаутом: прив’язаний чекаут — це одна партиція, а кожен worktree простору отримує власну (з ключем за його id ізольованого репозиторію).

Варто знати про два обмежувачі, бо вони пояснюють очікування, яке виглядає як зависання:

  • Файловий спостерігач допускає на хості лише один запуск індексування водночас — другий чекаут чекає. Конвеєр index_code окремо обмежено одним запуском на робочий простір, тож два репозиторії в одному робочому просторі стають у чергу; різні робочі простори можуть індексуватися паралельно. Сам індексатор серіалізує два запуски того самого чекауту, щоб старт конвеєра й прохід спостерігача не розібрали його двічі.
  • Worktree, що належать неактивним просторам (жодного повідомлення за останній тиждень), не спостерігаються й не індексуються. Прив’язані чекаути залишаються під спостереженням. Рішення про пропуск перевіряють знову за п’ять хвилин, тож простір, який знову стає активним, підхоплюється.

Попросіть агента виконати пошук. Інструмент називається search_code і потребує і робочого простору, і репозиторію:

search_code(workspace_id: "...", repo_id: "...", query: "authentication middleware")

Id репозиторіїв беруться з list_repos. Необов’язковий аргумент mode — це keyword, semantic або hybrid, і типово він має значення hybrid — BM25 за назвами, сигнатурами й doc-коментарями, об’єднаний із векторною схожістю.

Кожен результат містить id символу, назву, кваліфіковану назву, вид, шлях до файлу, початковий і кінцевий рядок, а також його сигнатуру, якщо вона є. id — це дескриптор, який ви передаєте в кожен інший інструмент на цій сторінці.

Коли ви знаєте точну назву, натомість знайдіть його напряму:

code_symbol(workspace_id: "...", repo_id: "...", name: "MyClass")

Обидва приймають symbol_id з результату пошуку та необов’язковий limit (типово 50):

code_callers(workspace_id: "...", symbol_id: "...")
code_callees(workspace_id: "...", symbol_id: "...")

code_callers повертає символи, які мають ребро, що входить до цього; code_callees повертає ті, від яких він залежить.

Це той інструмент, заради якого існує вся ця сторінка:

code_impact(workspace_id: "...", symbol_id: "...", depth: 3)

Він обчислює радіус зворотних залежностей: усе, що прямо чи транзитивно залежить від символу вздовж ребер calls, extends та implements (імпорти, mixes-in та узагальнені посилання зберігаються в графі, але тут ними не проходять). depth — це максимальна кількість переходів, від 1 до 6, типово 2.

Результат містить три поля:

  • root — символ, про який ви запитали
  • impacted — досяжна множина, включно з коренем на глибині 0, де кожен елемент несе свій depth від кореня
  • edgeCount — скільки ребер перетнув обхід, як число, а не самі ребра

Запускайте його перед перейменуванням чи зміною сигнатури й передавайте агенту список impacted як обсяг його роботи.

Результати звіряють із власною робочою копією того, хто викликає

Розділ із назвою «Результати звіряють із власною робочою копією того, хто викликає»

Коли викликає агент, id простору підставляють автоматично, і результати звіряють із робочою копією того простору. Символ, чийого файлу вже немає в дереві того, хто викликає, пропускають, а відповідь містить лічильник staleOmitted і примітку про те, що індекс застарілий для цих символів.

Саме тому ви й агент можете отримати різні відповіді на той самий запит, і саме тому агент в одному просторі може отримати іншу відповідь, ніж агент в іншому. Кожна розмова в просторі поділяє той самий worktree. Перевірка поводиться за принципом fail-open: застарілій відповіді віддають перевагу перед порожньою.

Попросіть агента запустити code_impact (або review_studio.blastRadius), коли вам потрібен радіус впливу зміни. Див. Обчислення перевірки.

Семантичний пошук потребує моделі ембедингів

Розділ із назвою «Семантичний пошук потребує моделі ембедингів»

Символи й факти отримують ембединг під час запису і лише тоді, коли встановлено локальну модель ембедингів. До того часу mode: "semantic" і семантична половина гібридного пошуку не мають із чим зіставлятися, тож пошук фактично працює лише за ключовими словами.

Установіть модель у Налаштування → Сервер → Діагностика та приватність → Семантичний пошук ще до індексування. Символи отримують вектор, коли їхній файл потрапляє в індекс.

Зауважте також, що будь-яке перезбирання бінарника сервера заново готує dylib-и граматик і змінює їхні mtime, а це робить недійсною кожну контрольну точку індексу й змушує заново повністю обійти кожен чекаут під час наступного запуску. Він перегешовує файли, але не витягує повторно незмінені.

Види символів: function, method, class, field, enum, constructor, getter, setter, typedef, extension, mixin, variable.

Види ребер: calls, imports, extends, implements, mixes in, references.

Канонічні сигнатури цих інструментів наведено в Інструменти MCP.