code-patch · git:20261021.431a6f9 · 2026-10-21 · sha256 3ee92fd2b552a40a

code-patch git:20261021.431a6f9A

Immutable. This exact content never changes and is served at /api/v1/blob/3ee92fd2b552a40a.

---
name: code-patch
description: Точечно вставить или заменить BSL-код в логически адресованном модуле XML-выгрузки Configuration или Extension 1С. Используй для одной проверяемой операции insert или replace.
argument-hint: <at> <insert|replace> <text>
allowed-tools:
  - Read
  - Glob
---

# /code-patch — безопасная вставка и замена BSL

## MCP routing

- Preferred path: use MCP `unica` tool `unica.apply` с операциями
  `code.insert` и `code.replace`.
- Do not call internal MCP/CLI adapters directly. They are hidden behind
  `unica` and synchronized by the orchestrator.
- Сначала вызови `unica.apply` с `at` и `ops`: это план без записи.
  Когда пользователь поручил внести эту правку, вызови `unica.apply` только
  с `executionToken` из `data.executionToken` успешного плана.

`args.at` выбирает модуль или его содержимое. У объекта с несколькими модулями
роль входит в адрес: `…Module.Object`, тело модуля — `…Module.Object.Body`.
Общий модуль сам себе модуль: `CommonModule.<Имя>` и `CommonModule.<Имя>.Body`.

Для `code.insert` без `selector` допустим адрес модуля или его `.Body`:
текст добавляется в конец модуля, `position` не передаётся. Вставка до или
после метода адресуется самим методом `…Method.<Имя>` с обязательным
`position: "before" | "after"`; `selector` при этом не передаётся.
`selector.method` снят: такой вызов получает отказ `bad_value`, а `next`
ведёт к адресу метода. Адрес `…Method.<Имя>.Body` вставку не адресует. Для
вставки внутрь тела метода передай адрес самого модуля, `selector` с одним
`anchor`, который однозначно находится внутри одного метода, и обязательный
`position`. Совпадения вне методов не учитываются. `before` вставляет текст
перед первой строкой anchor, `after` — после его последней строки; это
границы строк, а не позиция подстроки. Вставка перед методом встаёт выше
его документирующего комментария, аннотаций и директив; условие
`#Если … #КонецЕсли`, обрамляющее только этот метод, она обходит целиком,
а в условии с другими методами остаётся внутри него.

При вставке метода операция добавляет недостающие пустые строки между ним
и соседними методами. Уже существующие разделители и нетронутые участки
модуля сохраняются; комментарии, аннотации и директивы остаются со своим методом.

`code.replace` принимает адрес тела модуля, метода или тела метода, например
`CommonModule.<Имя>.Method.<Имя>.Body`. При таком адресе отдельный `selector`
не передаётся. `unica.view` по адресу `…Method.<Имя>.Body` отдаёт текст
метода с документирующим комментарием, директивой, объявлением и строкой
окончания. Этот текст с правкой, переданный `code.replace` по тому же адресу,
заменяет ровно прочитанный участок; текст без объявления метода заменяет
только строки тела. Метод целиком заменяется только по адресу `…Method.<Имя>`:
`selector.method` у замены получает отказ `bad_value`, а `next` ведёт к адресу
метода. На адресе самого модуля замена принимает лишь `selector` с `anchor`.
Сначала проверь выбранный адрес чтением.

Чтобы выделить метод, замени по адресу `…Method.<Имя>` весь метод текстом
из него самого и новых helper-методов. Helpers встанут сразу после метода,
а повтор той же замены ничего не запишет. Имена helpers должны быть новыми
для модуля: метод, уже объявленный в модуле, вызывает отказ `bad_value`
до записи. Одноимённые методы в ветвях `#Если … #Иначе` внутри текста
замены или уже в модуле дубликатами не считаются.

Правится модуль существующего объекта метаданных в допущенном наборе
исходников формата платформы. Физический путь к `*Module.bsl` остаётся
внутренней деталью: наружу его отдаёт только аварийный `unica.resolve`, и в
обычном ходе работы он не нужен. Создать объект метаданных, удалить модуль
целиком, править EDT или внешние файлы, синхронизировать исходники с базой
этим путём нельзя.

Если правку нельзя выразить одной безопасной операцией, остановись: прочитай
предмет через `unica.view {at}` на узле модуля — ветвь `Method` перечисляет
методы, ветвь `Body` отдаёт исходный текст модуля отдельным текстовым блоком
ответа — и вернись с более узкой операцией. Текст сверх бюджета ответа клиента
(по умолчанию 16 КиБ) не отдаётся:
отказ `result_too_large` ведёт к `Region` и `Method`, читай по методам.

## Операции

| Операция | Что делает | `args` |
|---|---|---|
| `code.insert` | Добавляет текст в конец модуля, до/после метода или якоря | `at`, `text`; у метода — `position`; у якоря — `selector.anchor`, `position` |
| `code.replace` | Заменяет содержимое узла по адресу | `at`, `text` |

Несколько операций одного вызова применяются как одна правка: либо все, либо
ни одной.

У заимствованного объекта расширения запись BSL также подключает модуль:
недостающее состояние `PropertyState` добавляется в дескриптор той же
транзакцией. Предпросмотр показывает обе правки. Уже установленное состояние
сохраняется; несовместимое состояние вызывает отказ до записи. После
применения проверь расширение через `unica.check {at: "ext:Configuration"}`,
подставив имя своего набора исходников.

## Порядок

1. Найди адрес: `unica.search {corpus: "names"}` по имени объекта, затем
   `unica.view {at}` вниз по ветвям `Module` и `Method`.
2. Прочти предмет: `unica.view {at}` на узле метода даёт подпись, контекст
   компиляции и собственные строки, `…Method.<Имя>.Body` — его текст.
3. Предпросмотр: `unica.apply` с `at` и `ops`. Ответ несёт план правки и
   токен `data.executionToken`. Для точного просмотра вызови `unica.diff`
   с этим `executionToken`: `data.chunks` содержит исходные и итоговые
   диапазоны с контекстом. Отступы, BOM и переводы строк сохранены.
   При `truncated: true` продолжи с `cursor` и тем же `limit` до конца.
   Чтение не меняет файлы и не расходует токен.
4. Применение: вызов только с `executionToken` из успешного плана.
   Исполнитель использует сохранённую транзакцию и проверяет её входы.
   После `stale_revision` получи новый план; изменение файла вне входов плана
   не мешает исполнению.
5. Проверка: `unica.check {at}` на модуле. Новые находки важности `error`
   блокируют.

## MCP examples

### Вставить строку внутрь обработчика

Сначала прочитай тело метода и убедись, что `// insertion point` однозначно
находится внутри одного метода; совпадение вне методов не мешает выбору.
Адрес и имена ниже иллюстративные; подставь адрес, полученный через `unica.view`.

```json
{
  "at": "main:Catalog.Пример.Module.Object",
  "ops": [
    {
      "op": "code.insert",
      "args": {
        "at": "main:Catalog.Пример.Module.Object",
        "selector": {"anchor": "// insertion point"},
        "position": "before",
        "text": "    Сообщить(\"Проверка вставки\");\n"
      }
    }
  ]
}
```

### Вставить новый метод после существующего

Метод называет адрес, место — `position`:

```json
{
  "at": "main:CommonModule.Пример.Method.ОбработатьПример",
  "ops": [
    {
      "op": "code.insert",
      "args": {
        "at": "main:CommonModule.Пример.Method.ОбработатьПример",
        "position": "after",
        "text": "Процедура ПослеМетода() Экспорт\nКонецПроцедуры\n"
      }
    }
  ]
}
```

### Предпросмотр замены тела метода

```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "unica.apply",
    "arguments": {
      "at": "main:CommonModule.Пример",
      "ops": [
        {
          "op": "code.replace",
          "args": {
            "at": "main:CommonModule.Пример.Method.ОбработатьПример.Body",
            "text": "    Возврат Истина;"
          }
        }
      ]
    }
  }
}
```

### Исполнение сохранённого плана

Сначала получи план этого изменения. В примере метод `ОбработатьПример` ещё
отсутствует: перед вставкой проверь имена и выбери новое, если оно занято.

```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "unica.apply",
    "arguments": {
      "at": "main:CommonModule.Пример",
      "ops": [
        {
          "op": "code.insert",
          "args": {
            "at": "main:CommonModule.Пример.Body",
            "text": "Процедура ОбработатьПример() Экспорт\nКонецПроцедуры\n"
          }
        }
      ]
    }
  }
}
```

Для исполнения передай `data.executionToken` из этого успешного плана:

```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "unica.apply",
    "arguments": {
      "executionToken": "<data.executionToken из успешного плана>"
    }
  }
}
```

### Точные исходники сохранённого плана

После успешного планирования передай тот же токен в `unica.diff`:

```json
{
  "executionToken": "<data.executionToken из успешного плана>",
  "limit": 20
}
```

Ответ называет `sourceSet` и `planIdentity`. В каждом `chunks` путь `path`
относителен к этому набору исходников; `pathEncoding` задаёт его представление.
`utf8` — текст компонентов, соединённых `/`; буквальный `\` внутри Unix-имени
сохраняется. `base64-unix-bytes` — Base64 точных байтов Unix-компонентов,
соединённых байтом `/`. `base64-utf16le` — Base64 точных UTF-16LE code units
Windows-компонентов с разделителем U+002F. Native-кодировка используется,
если хотя бы один компонент нельзя представить Unicode-текстом.
`side` различает `before` и `after`.
`rangeStart` и `rangeEnd` ограничивают показанный диапазон с контекстом,
`startByte` и `endByte` — фрагмент страницы; смещения байтовые, конец
не включается. `totalBytes` — полный размер соответствующей версии файла,
`present` отличает пустой файл от отсутствующего. Соединяй `content` в порядке
страниц отдельно по `(pathEncoding, path, side)`: `encoding: "utf8"` содержит точный текст,
`encoding: "base64"` — двоичные байты в Base64.

Умолчание `limit` — 20, максимум — 50. `page.stoppedBy` сообщает причину
остановки: `limit`, `bytes` или `complete`.

`cursor` продолжает только этот план с тем же `limit`. Изменение входов
даёт `stale_revision` и требует нового плана. Применение использует сохранённые
байты и повторно проверяет входы. После исполнения токена этот предпросмотр
недоступен; повторное применение возвращает прежний результат исполнения.