From 3e816d3e12335d4a10db460c11aa834b84d6e60f Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 23 Aug 2026 12:40:44 +0300 Subject: [PATCH] =?UTF-8?q?feat(db-repo):=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=20=D0=B7=D0=B0=D1=85=D0=B2=D0=B0=D1=82=D0=B0,=20?= =?UTF-8?q?=D0=BD=D1=83=D0=BB=D0=B5=D0=B2=D0=BE=D0=B9=20=D1=88=D0=B0=D0=B3?= =?UTF-8?q?=20=D1=86=D0=B8=D0=BA=D0=BB=D0=B0=20=D0=B8=20=D0=B4=D0=B8=D0=B0?= =?UTF-8?q?=D0=B3=D0=BD=D0=BE=D1=81=D1=82=D0=B8=D0=BA=D0=B0=20=D0=BF=D0=BE?= =?UTF-8?q?=20=D0=BE=D1=82=D1=87=D1=91=D1=82=D1=83=20=D1=81=D1=83=D0=B1?= =?UTF-8?q?=D0=B0=D0=B3=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проверка навыка субагентом на сквозном сценарии вскрыла фактическую ошибку в инструкции: реквизиты и табличные части перечислялись наравне с формами как захватываемые объекты. Платформа их объектами не считает — список объектов получается пустым, причём без секции «отсутствующие в конфигурации». Правишь реквизит, табличную часть, измерение, ресурс или модуль — захватывай владельца; формы, макеты и команды захватываются отдельно. Сообщение «объект не найден» имеет три разные причины: опечатка, отставание базы от хранилища и попытка захватить то, что объектом не является. Теперь перечислены все три. В цикл добавлен нулевой шаг — получение актуального состояния перед началом работы: правки должны опираться на актуальные версии в том числе тех объектов, которые не меняются, но используются. Загрузка и обновление БД слиты в один шаг через -UpdateDB, поэтому цикл не удлинился. Захват корня конфигурации с -WithChildren отклоняется: это захват всей конфигурации, а выглядит как захват корня. Для всей конфигурации есть однозначная форма — вызов без -Objects. Текстовый отчёт печатается, а не только сохраняется в файл. Схема repository и extensions[] описана в docs/v8-project-guide.md, цикл под хранилищем — в docs/db-guide.md. Co-Authored-By: Claude Opus 5 --- .claude/skills/db-repo/SKILL.md | 51 ++++++++++++++-------- .claude/skills/db-repo/scripts/db-repo.ps1 | 32 +++++++++++++- .v8-project.example.json | 40 ++++++++++++++--- docs/db-guide.md | 26 +++++++++++ docs/v8-project-guide.md | 49 ++++++++++++++++++++- 5 files changed, 172 insertions(+), 26 deletions(-) diff --git a/.claude/skills/db-repo/SKILL.md b/.claude/skills/db-repo/SKILL.md index da86222b0..772a12e63 100644 --- a/.claude/skills/db-repo/SKILL.md +++ b/.claude/skills/db-repo/SKILL.md @@ -31,25 +31,35 @@ allowed-tools: объектам. Выполняй строго по шагам: ``` +0. /db-repo update <база> — начать с актуального состояния 1. /db-repo lock <база> -Objects "Справочник.Номенклатура" -2. если шаг 1 сообщил о полученных из хранилища объектах — выгрузи их заново: - /db-dump-xml <база> <каталог> -Mode Partial -ObjectsFile "<файл из вывода шага 1>" -3. правки в исходниках -4. /db-load-xml <каталог> <база> -Mode Partial -Files "Catalogs/Номенклатура.xml,…" -5. /db-update <база> -6. /db-repo commit <база> -Objects "Справочник.Номенклатура" -Comment "…" +2. если шаг 0 или 1 напечатал «локальная конфигурация изменена: из хранилища получено N» — + выгрузи названные объекты: /db-dump-xml <база> <каталог> -Mode Partial -ObjectsFile "<файл из вывода>" +3. правки в исходниках: /meta-edit, /form-edit, /skd-edit, /meta-compile и т. д. +4. /db-load-xml <каталог> <база> -Mode Partial -Files "Catalogs/Номенклатура.xml,…" -UpdateDB +5. /db-repo commit <база> -Objects "Справочник.Номенклатура" -Comment "…" ``` -Шаг 2 пропускать нельзя: захват подтягивает из хранилища свежие версии, и загрузка исходников, -снятых до захвата, откатит чужие изменения — молча, без ошибки. +Шаг 0 стоит делать всегда, когда работа не продолжается сразу после предыдущего цикла: правки +должны опираться на актуальное состояние — в том числе тех объектов, которые ты не меняешь, но +используешь. -**Добавляешь новый объект** — захватывай его вместе с корнем конфигурации: -`-Objects "Конфигурация,Справочник.Склады"`. +Шаг 2 пропускать нельзя: захват и обновление подтягивают из хранилища свежие версии, и загрузка +исходников, снятых раньше, откатит чужие изменения — молча, без ошибки. -**Правишь подчинённый объект** — форму, макет, команду, реквизит — захватывай именно его: -`-Objects "Справочник.Номенклатура.Форма.ФормаЭлемента"`. Захват объекта его подчинённые объекты -не захватывает. Захватывай минимум того, что правишь: чем шире захват, тем больше конфликтов -с коллегами. +**Что вообще захватывается.** Отдельные объекты хранилища — сам объект, а также его **формы, +макеты и команды**. Реквизиты, табличные части, измерения и ресурсы отдельными объектами **не +являются**: они правятся в составе владельца. + +| Что правишь | Что захватывать | +|-------------|-----------------| +| Реквизит, табличную часть, измерение, ресурс, модуль объекта | сам объект: `Справочник.Контрагенты` | +| Существующую форму, макет, команду | её саму: `Справочник.Контрагенты.Форма.ФормаЭлемента` | +| Добавляешь новую форму, макет, команду | объект-владельца; при помещении назови и новый объект | +| Добавляешь новый объект конфигурации | объект и корень: `Конфигурация,Справочник.Склады` | + +Захватывай минимум того, что правишь: чем шире захват, тем больше конфликтов с коллегами. +Захват объекта его формы и макеты не захватывает — для этого есть `-WithChildren`. ## Параметры подключения @@ -59,8 +69,9 @@ allowed-tools: 3. Если не указал — сопоставь текущую ветку Git с `databases[].branches` 4. Если ветка не совпала — используй `default` -Реквизиты хранилища передавать не нужно — они берутся из `repository` записи базы. Задать их явно -можно параметрами `-Repository*`. +Реквизиты хранилища передавать не нужно: запись базы находится по переданным параметрам +соединения (`-InfoBasePath` либо `-InfoBaseServer` + `-InfoBaseRef`), реквизиты берутся из её +`repository`. Задать их явно можно параметрами `-Repository*`. ## Команда @@ -86,7 +97,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-repo.ps1" <по | `-InfoBaseRef <имя>` | * | Имя базы на сервере | | `-UserName <имя>` | нет | Пользователь базы | | `-Password <пароль>` | нет | Пароль пользователя базы | -| `-Objects <список>` | нет | Объекты через запятую. Без него — вся конфигурация | +| `-Objects <список>` | нет | Объекты через запятую. Без него — вся конфигурация, спроси подтверждение | | `-ObjectsFile <путь>` | нет | Файл со списком объектов, одно имя на строку | | `-WithChildren` | нет | Вместе с подчинёнными объектами на полную глубину | | `-Comment <текст>` | нет | Комментарий к помещению (`commit`). Многострочный — как есть, с переводами строк | @@ -111,10 +122,14 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-repo.ps1" <по ### Имена объектов -Объект — `Справочник.Номенклатура`. Подчинённый объект — полным путём: +Объект — `Справочник.Номенклатура`. Форма, макет, команда — полным путём: `Документ.ЗаказПокупателя.Форма.ФормаДокумента`, `Справочник.Номенклатура.Макет.Печать`. Корень конфигурации — `Конфигурация`. +Если объект «не найден», это не всегда опечатка: он мог появиться в хранилище позже, чем +обновлялась база (`/db-repo update`), либо это вовсе не объект хранилища — реквизит или +табличная часть. + ## Результат Код возврата отражает, достигнуто ли запрошенное состояние, а не факт изменения: «уже захвачено», diff --git a/.claude/skills/db-repo/scripts/db-repo.ps1 b/.claude/skills/db-repo/scripts/db-repo.ps1 index b844ec5bc..a54c0ec20 100644 --- a/.claude/skills/db-repo/scripts/db-repo.ps1 +++ b/.claude/skills/db-repo/scripts/db-repo.ps1 @@ -1,4 +1,4 @@ -# db-repo v1.0 — 1C configuration repository operations +# db-repo v1.1 — 1C configuration repository operations # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: движок только 1cv8 — ibcmd работу с хранилищем не поддерживает (нет такого режима). <# @@ -771,7 +771,11 @@ function Write-RepoVerdict { if ($Log.Missing.Count -gt 0) { Write-Host "Error: objects not found in the configuration:" -ForegroundColor Red foreach ($n in $Log.Missing) { Write-Host " $n" -ForegroundColor Red } - Write-Host "Проверьте написание. Принимаются обе формы: Справочник.Номенклатура и Catalog.Номенклатура." -ForegroundColor Yellow + Write-Host "Возможные причины:" -ForegroundColor Yellow + Write-Host " - опечатка в имени. Принимаются обе формы: Справочник.Номенклатура и Catalog.Номенклатура" -ForegroundColor Yellow + Write-Host " - база отстала от хранилища, объект появился позже — выполните /db-repo update" -ForegroundColor Yellow + Write-Host " - это не объект хранилища: реквизиты, табличные части, измерения и ресурсы" -ForegroundColor Yellow + Write-Host " отдельно не захватываются — указывайте объект-владельца" -ForegroundColor Yellow return 1 } @@ -879,6 +883,18 @@ function Write-RepoVerdict { return 1 } Write-Host "Команда '$Cmd' выполнена." -ForegroundColor Green + if ($Cmd -eq 'report' -and $ReportFormat -eq 'txt' -and (Test-Path $OutputFile)) { + $txt = [System.Text.Encoding]::UTF8.GetString([System.IO.File]::ReadAllBytes($OutputFile)) + if ($txt.Length -gt 0 -and $txt[0] -eq [char]0xFEFF) { $txt = $txt.Substring(1) } + $lines = @($txt -split "`r?`n") + $limit = 200 + Write-Host "--- $OutputFile ---" + Write-Host (($lines | Select-Object -First $limit) -join [Environment]::NewLine) + if ($lines.Count -gt $limit) { + Write-Host "[... показаны первые $limit строк из $($lines.Count); полный отчёт в файле ...]" -ForegroundColor Yellow + } + Write-Host "--- End ---" + } return 0 } } @@ -922,6 +938,18 @@ if ($requested.Count -gt 0 -and $objectAware -notcontains $cmd) { exit 1 } +# Корень с подчинёнными — это ВСЯ конфигурация, а выглядит как «захвачу корень». Для всей +# конфигурации есть однозначная форма (вызов без -Objects), поэтому двусмысленную отклоняем. +if ($WithChildren) { + $rootAsked = @($requested | Where-Object { $script:ConfigRootAliases -contains $_ }) + if ($rootAsked.Count -gt 0) { + Write-Host "Error: '$($rootAsked[0])' with -WithChildren means the WHOLE configuration, not just its root." -ForegroundColor Red + Write-Host " Нужен только корень (чтобы добавить или удалить объект) — уберите -WithChildren." -ForegroundColor Yellow + Write-Host " Нужна вся конфигурация — вызовите без -Objects." -ForegroundColor Yellow + exit 1 + } +} + switch ($cmd) { 'report' { if (-not $OutputFile) { Write-Host "Error: -OutputFile is required for report" -ForegroundColor Red; exit 1 } } 'dump-cfg' { if (-not $OutputFile) { Write-Host "Error: -OutputFile (path to the .cf file) is required for dump-cfg" -ForegroundColor Red; exit 1 } } diff --git a/.v8-project.example.json b/.v8-project.example.json index f811ac34d..8b7302f82 100644 --- a/.v8-project.example.json +++ b/.v8-project.example.json @@ -8,10 +8,33 @@ "path": "C:\\Bases\\MyApp_Dev", "user": "Администратор", "password": "", - "aliases": ["dev", "разработка"], - "branches": ["dev", "develop", "feature/*"], + "aliases": [ + "dev", + "разработка" + ], + "branches": [ + "dev", + "develop", + "feature/*" + ], "configSrc": "src\\cf", - "webUrl": "http://localhost:8081/dev" + "webUrl": "http://localhost:8081/dev", + "repository": { + "path": "\\\\srv01\\repo\\MyApp", + "user": "", + "password": "" + }, + "extensions": [ + { + "name": "", + "src": "src\\cfe", + "repository": { + "path": "", + "user": "", + "password": "" + } + } + ] }, { "id": "test", @@ -21,8 +44,15 @@ "ref": "MyApp_Test", "user": "Администратор", "password": "", - "aliases": ["test", "тест", "тестовая"], - "branches": ["main", "release/*"] + "aliases": [ + "test", + "тест", + "тестовая" + ], + "branches": [ + "main", + "release/*" + ] } ], "default": "dev", diff --git a/docs/db-guide.md b/docs/db-guide.md index f86debf2d..893d2fc4d 100644 --- a/docs/db-guide.md +++ b/docs/db-guide.md @@ -15,6 +15,7 @@ | `/db-update` | — | Обновление конфигурации БД | | `/db-run` | — | Запуск 1С:Предприятие | | `/db-load-git` | `.ps1` | Загрузка изменений из Git в базу | +| `/db-repo` | `.ps1` | Хранилище конфигурации: захват, помещение, получение изменений | ## Рабочий цикл @@ -35,6 +36,31 @@ 7. **Обновление** — `/db-update` применить 8. **Запуск** — `/db-run` открыть предприятие +## Работа с хранилищем конфигурации + +База, подключённая к хранилищу, живёт по другим правилам, и это меняет весь цикл: + +- **полная загрузка XML в неё невозможна** — платформа отвечает «текущая конфигурация помещена в + хранилище». Работает только `-Mode Partial`; +- частичная загрузка проходит **только по захваченным** объектам, иначе отказ с именем объекта; +- **новый объект требует захвата корня конфигурации** — без него частичная загрузка не пройдёт; +- любой команде конфигуратора нужны реквизиты хранилища. Их берут из `repository` записи базы + (см. [справочник .v8-project.json](v8-project-guide.md)), передавать в каждом вызове не нужно. + +Цикл разработки под хранилищем: + +``` +/db-repo update → /db-repo lock → /db-dump-xml -Mode Partial → правки + ↓ + /db-repo commit ← /db-load-xml -Mode Partial -UpdateDB +``` + +Выгрузка после захвата обязательна: захват и обновление молча подтягивают из хранилища свежие +версии объектов, и загрузка исходников, снятых раньше, откатит чужие изменения без единой ошибки. +`/db-repo` печатает список полученных объектов и готовую команду выгрузки. + +Подробности — в SKILL.md навыка `/db-repo`. + ## Формат `.v8-project.json` Полное описание формата — в [справочнике .v8-project.json](v8-project-guide.md). diff --git a/docs/v8-project-guide.md b/docs/v8-project-guide.md index af60773ba..a56192824 100644 --- a/docs/v8-project-guide.md +++ b/docs/v8-project-guide.md @@ -27,7 +27,25 @@ "aliases": ["dev", "разработка"], // альтернативные имена "branches": ["dev", "feature/*"], // привязка к Git-веткам "configSrc": "src\\cf", // каталог XML-выгрузки конфигурации (см. структуру ниже) - "webUrl": "http://localhost:8081/dev" // URL веб-клиента (для /web-test) + "webUrl": "http://localhost:8081/dev", // URL веб-клиента (для /web-test) + + // Хранилище конфигурации (для /db-repo). Без него навыки группы db-* не смогут + // работать с базой, подключённой к хранилищу: платформа не примет от них ни одной + // операции конфигуратора. + "repository": { + "path": "\\\\srv01\\repo\\MyApp", // каталог или tcp://srv01/MyApp + "user": "Ivanov", + "password": "" + }, + + // Расширения конфигурации: каталог исходников и, если есть, СВОЁ хранилище + "extensions": [ + { + "name": "МоёРасширение", + "src": "src\\cfe\\МоёРасширение", + "repository": { "path": "\\\\srv01\\repo\\MyApp_Ext", "user": "Ivanov", "password": "" } + } + ] }, { "id": "test", @@ -85,6 +103,35 @@ | `editingAllowedCheck` | `"deny"`/`"warn"`/`"off"` | нет | Override реакции support-guard для этой базы (см. ниже) | Руками | | `skillSuggester` | `"on"`/`"off"` | нет | Override подсказок навыков для этой базы (см. ниже) | Руками | | `webUrl` | string | нет | URL веб-клиента для `/web-test` | Руками | +| `repository` | object | нет | Хранилище конфигурации: `path`, `user`, `password` (см. ниже) | Руками | +| `extensions` | array | нет | Расширения конфигурации: `name`, `src`, необязательное `repository` (см. ниже) | Руками | + +### Хранилище конфигурации (`repository`, `extensions[]`) + +База, подключённая к хранилищу конфигурации, не принимает **ни одной** операции конфигуратора без +реквизитов доступа к хранилищу — это касается не только `/db-repo`, но и `/db-load-xml`, +`/db-dump-xml`, `/db-update`, `/db-load-git`. Реквизиты берутся из `repository` записи базы, поэтому +передавать их в каждом вызове не нужно. + +| Поле | Тип | Обяз. | Описание | +|------|-----|:-----:|----------| +| `repository.path` | string | да | Каталог хранилища или `tcp://<сервер>/<имя>` | +| `repository.user` | string | нет | Пользователь хранилища. **Не наследуется** от `user` базы — задаётся явно | +| `repository.password` | string | нет | Пароль пользователя хранилища | + +У **расширения своё хранилище** со своим путём — одного `repository` на запись базы недостаточно: + +| Поле | Тип | Обяз. | Описание | +|------|-----|:-----:|----------| +| `extensions[].name` | string | да | Имя расширения, как в конфигурации | +| `extensions[].src` | string | нет | Каталог XML-исходников расширения (напр. `src/cfe/<Имя>`) | +| `extensions[].repository` | object | нет | Хранилище расширения. Расширение без хранилища — обычный случай | + +Пароль хранилища — такой же секрет, как `password` базы; `.v8-project.json` в `.gitignore`. + +`/db-repo update` отказывается работать, если у базы не объявлено `repository` и реквизиты не +переданы явно: на базе, **не** подключённой к хранилищу, эта команда молча заменяет всю +конфигурацию содержимым хранилища и рапортует успех. ### Support-guard и `editingAllowedCheck`