Сценарий 17: Редактирование файлов

Хирургические модификации кода на основе AST с предпросмотром diff, резервным копированием/отменой и многоинтерфейсным доступом (CLI, REST API, MCP).

Содержание

Быстрый старт

/select 17

Как это работает

Архитектура

Модуль редактирования (src/editing/) состоит из 5 компонентов, связанных в конвейер:

Запрос пользователя
    |
    v
ASTParser (tree-sitter + regex-резерв)
    |
    v
TargetFinder (CPG + AST, 7 методов поиска)
    |
    v
CodeModifier (6 режимов, резервное копирование/отмена)
    |
    v
DiffGenerator (4 формата вывода)
    |
    v
Предпросмотр / Применение

SSRAdapter ──> CodeModifier
  (мост GoCPG RewriteResult → EditOperation)
Компонент Модуль Назначение
ASTParser ast_parser.py Парсинг через tree-sitter с regex-резервом для 14 расширений файлов
TargetFinder target_finder.py Поиск функций/классов по имени, сигнатуре, расположению или CPG-запросу
CodeModifier code_modifier.py Применение правок с сохранением форматирования, стек отмены (до 50)
DiffGenerator diff_generator.py Генерация diff в форматах unified, side-by-side, inline и HTML
SSRAdapter ssr_adapter.py Конвертация diff-результатов GoCPG RewriteResult в объекты EditOperation

Определение намерения

Рабочий процесс (src/workflow/scenarios/file_editing.py) определяет намерение редактирования через is_file_editing_query() с использованием 27 двуязычных ключевых слов:

Язык Ключевые слова
Английский (16) edit, modify, change, update, replace, refactor, rename, insert, delete, remove, add code, change code, update function, modify class, edit method
Русский (11) редактировать, изменить, обновить, заменить, рефакторинг, переименовать, вставить, удалить, добавить код, изменить код, обновить функцию

Функция file_editing_workflow() зарегистрирована в LangGraph через graph_builder.py и маршрутизируется через intent_classifier.pyrouter.py. Опциональное обогащение через EnrichmentAdapter добавляет векторный контекст из документации и комментариев кода.

AST-парсинг

ASTParser поддерживает два режима парсинга:

  1. tree-sitter (основной) — точный AST через пакет tree-sitter-languages
  2. Regex-резерв — парсинг по шаблонам, когда tree-sitter недоступен

Поддерживаемые расширения файлов (14):

Язык Расширения
Python .py
C .c, .h
C++ .cpp, .hpp, .cc, .cxx
JavaScript .js, .jsx
TypeScript .ts, .tsx
Go .go
Java .java
C# .cs
PHP .php
Rust .rs
Kotlin .kt

Regex-шаблоны доступны для Python, C, C++, JavaScript и Go — покрывают определения функций, классов, методов, структур, интерфейсов и стрелочных функций.

Поиск целей

TargetFinder предоставляет 7 методов поиска, комбинирующих CPG-запросы и AST-парсинг:

Метод Источник Назначение
find_by_name() AST + CPG Поиск по имени или шаблону с точным совпадением
find_by_signature() AST Сопоставление сигнатур функций с regex-шаблоном
find_by_location() AST Поиск наименьшей цели, содержащей указанную строку
find_by_cpg_query() CPG Выполнение произвольного SQL к базе CPG
find_callers() CPG Поиск всех вызывающих указанную функцию
find_callees() CPG Поиск всех вызываемых указанной функцией
find_references() CPG Поиск всех ссылок на имя (переменные, функции, типы)

При наличии результатов и CPG, и AST метод _merge_targets() объединяет их — предпочитая AST для точного расположения и добавляя метаданные CPG.

Режимы редактирования и типы целей

Режимы редактирования (6)

Режим Перечисление Описание Применение
Замена REPLACE Заменить всю цель Переписать логику функции
Вставка до INSERT_BEFORE Вставить код перед целью Добавить импорты, объявления
Вставка после INSERT_AFTER Вставить код после цели Добавить новые методы
Удаление DELETE Удалить цель Удалить устаревший код
Обёртка WRAP Обернуть цель с префиксом/суффиксом (формат: prefix\|\|\|suffix) Добавить обработку ошибок, логирование
Переименование RENAME Переименовать идентификатор с regex по границам слов Рефакторинг именования по файлу

Типы целей (7)

Тип Перечисление Описание
Функция FUNCTION Автономные функции
Класс CLASS Определения классов, структур, интерфейсов
Метод METHOD Методы классов
Переменная VARIABLE Объявления и ссылки на переменные
Импорт IMPORT Инструкции импорта
Блок BLOCK Произвольные блоки кода
Диапазон строк LINE_RANGE Явный диапазон строк (используется SSR-адаптером)

Модели данных

CodeTarget (13 полей)

Поле Тип Описание
file_path str Путь к файлу исходного кода
target_type TargetType Один из 7 типов целей
name str Имя цели
start_line int Начальная строка
end_line int Конечная строка
start_column int Начальная колонка (по умолчанию 0)
end_column int Конечная колонка (по умолчанию 0)
signature str? Сигнатура функции/класса
docstring str? Связанная строка документации
parent_name str? Для методов: имя вмещающего класса
ast_node_type str? Тип узла tree-sitter
source_code str? Полный текст исходного кода
metadata dict Дополнительные метаданные (напр., {"source": "cpg"})

EditOperation (8 полей)

Поле Тип Описание
target CodeTarget Цель редактирования
mode EditMode Один из 6 режимов
new_code str Код замены
description str? Описание для человека
preserve_indentation bool Сохранить исходные отступы (по умолчанию: True)
preserve_comments bool Сохранить окружающие комментарии (по умолчанию: True)
auto_format bool Автоформатирование результата (по умолчанию: True)
metadata dict Дополнительные метаданные

EditResult (10 полей)

Поле Тип Описание
success bool Успешность операции
file_path str Путь к отредактированному файлу
operation EditOperation Применённая операция
original_content str Содержимое до правки
new_content str Содержимое после правки
diff str Сгенерированный diff
backup_path str? Путь к файлу резервной копии
applied_at datetime? Метка времени (None для пробного запуска)
error_message str? Подробности ошибки при неудаче
warnings list[str] Некритичные предупреждения

Форматы diff

DiffGenerator поддерживает 4 формата вывода через перечисление DiffFormat:

Формат Перечисление Описание
Унифицированный UNIFIED Стандартный unified diff с маркерами +/- (по умолчанию)
Бок о бок SIDE_BY_SIDE Двухколоночное сравнение
Встроенный INLINE Двойная нумерация строк с маркерами изменений
HTML HTML Полная HTML-страница через difflib.HtmlDiff

Дополнительные методы: - summarize_changes() — текстовая сводка (напр., “+4 строки добавлено, -2 удалено (+2 итого)”) - get_colored_diff() — цветной вывод в терминал через ANSI (красный/зелёный/голубой) - get_changed_lines() — кортеж (добавленные, удалённые, изменённые) номера строк

Интеграция с SSR

SSRAdapter (ssr_adapter.py) связывает результаты структурного поиска-и-замены GoCPG с модулем редактирования:

GoCPG scan --fix --dry-run
    |
    v
Diff-результаты RewriteResult (unified diff + метаданные)
    |
    v
rewrite_results_to_edit_operations()  ──> List[EditOperation]
    |
    v
CodeModifier.apply_multiple()  ──> List[EditResult]

Две функции-адаптера: - rewrite_results_to_edit_operations(diffs) — разбор diff-фрагментов или явных line_start/fix_preview в объекты EditOperation с EditMode.REPLACE - edit_operations_from_findings(findings) — обёртка, фильтрующая находки с исправлениями из GoCPGScanResult

Примеры использования

Поиск целей кода

> Найти функцию heap_insert в src/backend/access/heap/heapam.c

## Найден код

**Имя:** heap_insert
**Тип:** функция
**Файл:** src/backend/access/heap/heapam.c
**Строки:** 2156-2298

  void heap_insert(Relation relation,
                   HeapTuple tup,
                   CommandId cid,
                   int options,
                   BulkInsertState bistate)
  { ... }

Предпросмотр изменений с diff

> Редактировать функцию validate_input для добавления проверки границ

## Предпросмотр изменений

**Цель:** validate_input (функция)
**Файл:** src/utils/validation.c:45-67

### Изменения:
  @@ -45,6 +45,10 @@
   bool validate_input(const char *input, size_t len)
   {
  +    /* Проверка границ */
  +    if (len > MAX_INPUT_SIZE) {
  +        return false;
  +    }
       if (input == NULL) {
           return false;
       }

Используйте `/edit apply` для применения изменений.

Применение с резервным копированием

CodeModifier автоматически создаёт резервные копии (формат: name.YYYYMMDD_HHMMSS.hash.bak) и поддерживает стек отмены (до 50 записей). Операции с одним файлом сортируются по номеру строки в обратном порядке для предотвращения сдвигов строк.

Операция переименования

Режим RENAME использует regex по границам слов (\bOldName\b) для замены всех вхождений в файле без затрагивания частичных совпадений.

Конфигурация

Класс данных EditingConfig (9 параметров):

editing:
  ast_parser: "tree-sitter"         # Основной парсер
  fallback_parser: "regex"           # Резерв при недоступности tree-sitter
  preserve_formatting: true          # Сохранять исходное форматирование
  preserve_comments: true            # Сохранять комментарии вокруг целей
  diff_context_lines: 5              # Строки контекста в diff-выводе
  backup_before_edit: true           # Создавать копии перед правками
  backup_dir: "./backups/edits"      # Директория резервных копий
  max_file_size_mb: 10               # Максимальный размер файла для редактирования
  supported_extensions:              # Обрабатываемые типы файлов
    - .py
    - .c
    - .h
    - .cpp
    - .js
    - .ts
    - .go
    - .rb

Использование CLI

# Поиск целей по имени
python -m src.cli.import_commands edit find "heap_insert" --file src/heap.c --exact

# Поиск всех функций по шаблону в директории
python -m src.cli.import_commands edit find "validate_*" --file src/ --type function --limit 20

# Предпросмотр правки (формат цели: file.py::name или file.py:line)
python -m src.cli.import_commands edit preview src/utils/validation.c::validate_input \
    --new-code "bool validate_input(...) { ... }" \
    --format unified --context 5

# Предпросмотр с кодом из файла
python -m src.cli.import_commands edit preview src/file.c::func_name \
    --new-code-file patch.txt

# Применить правку
python -m src.cli.import_commands edit apply --backup

# Отмена последней правки (восстановление из копии)
python -m src.cli.import_commands edit undo --steps 1

# Показать историю правок
python -m src.cli.import_commands edit history --limit 10 --file src/utils/

REST API

5 эндпоинтов в src/api/routers/editing.py:

Метод Эндпоинт Описание
POST /api/v1/edit/find-target Поиск целей кода по имени/шаблону
POST /api/v1/edit/preview Генерация предпросмотра diff (пробный запуск)
POST /api/v1/edit/apply Применение правки с опциональной резервной копией
POST /api/v1/edit/undo Отмена последней правки
GET /api/v1/edit/history Получение истории правок (лимит, по умолчанию 10)

Пример:

# Поиск целей
curl -X POST http://localhost:8000/api/v1/edit/find-target \
  -H "Content-Type: application/json" \
  -d '{"file_path": "src/utils/validation.c", "name_pattern": "validate_input", "target_type": "function"}'

# Предпросмотр правки
curl -X POST http://localhost:8000/api/v1/edit/preview \
  -H "Content-Type: application/json" \
  -d '{"file_path": "src/file.c", "target_name": "func", "new_code": "...", "diff_format": "unified"}'

Инструмент MCP

codegraph_edit_preview(file_path, target_name, target_type="function")

Находит цель в CPG и возвращает тип, расположение и предпросмотр кода — полезно для безопасного рефакторинга из ИИ-ассистента. Использует TargetFinder с CPG-сервисом для семантического понимания.

Примеры вопросов

Поиск целей: - «Найти функцию heap_insert в src/heap.c» - «Найти все классы в src/backend/executor/» - «Какие функции вызывают heap_insert?»

Редактирование: - «Редактировать функцию validate_input — добавить проверку null» - «Вставить логирование перед функцией process_request» - «Удалить неиспользуемую функцию old_helper» - «Обернуть функцию обработкой ошибок» - «Переименовать класс TransactionHandler в TxHandler»

Предпросмотр и история: - «Показать текущий предпросмотр редактирования» - «Показать историю правок» - «Отменить последнюю правку»

Связанные сценарии