Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot] 70bdc9cd7f Auto-build: claude-code (python) from 6d119eb 2026-06-04 09:28:00 +00:00
2080 changed files with 26940 additions and 169014 deletions
-32
View File
@@ -1,32 +0,0 @@
{
"name": "cc-1c-skills",
"interface": {
"displayName": "1C Skills"
},
"plugins": [
{
"name": "1c-skills",
"source": {
"source": "url",
"url": "https://github.com/Nikolay-Shirokov/cc-1c-skills.git",
"ref": "port-codex"
},
"policy": {
"installation": "AVAILABLE"
},
"category": "Development"
},
{
"name": "1c-skills-py",
"source": {
"source": "url",
"url": "https://github.com/Nikolay-Shirokov/cc-1c-skills.git",
"ref": "port-codex-py"
},
"policy": {
"installation": "AVAILABLE"
},
"category": "Development"
}
]
}
-24
View File
@@ -1,24 +0,0 @@
{
"$schema": "https://json.schemastore.org/claude-code-marketplace-manifest.json",
"name": "cc-1c-skills",
"description": "Маркетплейс навыков для разработки на платформе 1С:Предприятие",
"owner": {
"name": "Nikolay Shirokov"
},
"plugins": [
{
"name": "1c-skills",
"source": "./",
"description": "[PowerShell] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент."
},
{
"name": "1c-skills-py",
"source": {
"source": "github",
"repo": "Nikolay-Shirokov/cc-1c-skills",
"ref": "port-claude-code-py"
},
"description": "[Python] То же — для Linux/Mac или когда PowerShell недоступен."
}
]
}
+2 -2
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "1c-skills",
"description": "[PowerShell] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент.",
"name": "1c-skills-py",
"description": "[Python] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент. Linux/Mac или когда PowerShell недоступен.",
"author": {
"name": "Nikolay Shirokov"
},
+60 -60
View File
@@ -1,60 +1,60 @@
---
name: cf-edit
description: Точечное редактирование конфигурации 1С. Используй когда нужно изменить свойства конфигурации, добавить или удалить объект из состава, настроить роли по умолчанию, поменять раскладку панелей, настроить начальную страницу
argument-hint: -ConfigPath <path> -Operation <op> -Value <value>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /cf-edit — редактирование конфигурации 1С
Точечное редактирование Configuration.xml: свойства, состав ChildObjects, роли по умолчанию.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `ConfigPath` | Путь к Configuration.xml или каталогу выгрузки |
| `Operation` | Операция (см. таблицу) |
| `Value` | Значение для операции (batch через `;;`) |
| `DefinitionFile` | JSON-файл с массивом операций |
| `NoValidate` | Пропустить авто-валидацию |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-edit.ps1" -ConfigPath '<path>' -Operation modify-property -Value 'Version=1.0.0.1'
```
## Операции
| Операция | Формат Value | Описание |
|----------|-------------|----------|
| `modify-property` | `Ключ=Значение` (batch `;;`) | Изменить свойство |
| `add-childObject` | `Type.Name` (batch `;;`) | Зарегистрировать уже существующий файл объекта в ChildObjects. Для создания нового объекта используй `/meta-compile`, `/role-compile`, `/subsystem-compile` — они регистрируют автоматически |
| `remove-childObject` | `Type.Name` (batch `;;`) | Удалить объект из ChildObjects |
| `add-defaultRole` | `Role.Name` или `Name` | Добавить роль по умолчанию |
| `remove-defaultRole` | `Role.Name` или `Name` | Удалить роль по умолчанию |
| `set-defaultRoles` | Имена через `;;` | Заменить список ролей по умолчанию |
| `set-panels` | JSON-объект (см. [reference.md](reference.md)) | Перезаписать `Ext/ClientApplicationInterface.xml` (раскладка панелей) |
| `set-home-page` | JSON-объект (см. [reference.md](reference.md)) | Перезаписать `Ext/HomePageWorkArea.xml` (начальная страница) |
Допустимые значения свойств, формат DefinitionFile (JSON), каноничный порядок: [reference.md](reference.md)
## Примеры
```powershell
# Изменить версию и поставщика
... -ConfigPath src -Operation modify-property -Value "Version=1.0.0.1 ;; Vendor=Фирма 1С"
# Добавить объекты
... -ConfigPath src -Operation add-childObject -Value "Catalog.Товары ;; Document.Заказ"
# Удалить объект
... -ConfigPath src -Operation remove-childObject -Value "Catalog.Устаревший"
# Роли по умолчанию
... -ConfigPath src -Operation add-defaultRole -Value "ПолныеПрава"
... -ConfigPath src -Operation set-defaultRoles -Value "ПолныеПрава ;; Администратор"
```
---
name: cf-edit
description: Точечное редактирование конфигурации 1С. Используй когда нужно изменить свойства конфигурации, добавить или удалить объект из состава, настроить роли по умолчанию, поменять раскладку панелей, настроить начальную страницу
argument-hint: -ConfigPath <path> -Operation <op> -Value <value>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /cf-edit — редактирование конфигурации 1С
Точечное редактирование Configuration.xml: свойства, состав ChildObjects, роли по умолчанию.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `ConfigPath` | Путь к Configuration.xml или каталогу выгрузки |
| `Operation` | Операция (см. таблицу) |
| `Value` | Значение для операции (batch через `;;`) |
| `DefinitionFile` | JSON-файл с массивом операций |
| `NoValidate` | Пропустить авто-валидацию |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cf-edit.py" -ConfigPath '<path>' -Operation modify-property -Value 'Version=1.0.0.1'
```
## Операции
| Операция | Формат Value | Описание |
|----------|-------------|----------|
| `modify-property` | `Ключ=Значение` (batch `;;`) | Изменить свойство |
| `add-childObject` | `Type.Name` (batch `;;`) | Зарегистрировать уже существующий файл объекта в ChildObjects. Для создания нового объекта используй `/meta-compile`, `/role-compile`, `/subsystem-compile` — они регистрируют автоматически |
| `remove-childObject` | `Type.Name` (batch `;;`) | Удалить объект из ChildObjects |
| `add-defaultRole` | `Role.Name` или `Name` | Добавить роль по умолчанию |
| `remove-defaultRole` | `Role.Name` или `Name` | Удалить роль по умолчанию |
| `set-defaultRoles` | Имена через `;;` | Заменить список ролей по умолчанию |
| `set-panels` | JSON-объект (см. [reference.md](reference.md)) | Перезаписать `Ext/ClientApplicationInterface.xml` (раскладка панелей) |
| `set-home-page` | JSON-объект (см. [reference.md](reference.md)) | Перезаписать `Ext/HomePageWorkArea.xml` (начальная страница) |
Допустимые значения свойств, формат DefinitionFile (JSON), каноничный порядок: [reference.md](reference.md)
## Примеры
```powershell
# Изменить версию и поставщика
... -ConfigPath src -Operation modify-property -Value "Version=1.0.0.1 ;; Vendor=Фирма 1С"
# Добавить объекты
... -ConfigPath src -Operation add-childObject -Value "Catalog.Товары ;; Document.Заказ"
# Удалить объект
... -ConfigPath src -Operation remove-childObject -Value "Catalog.Устаревший"
# Роли по умолчанию
... -ConfigPath src -Operation add-defaultRole -Value "ПолныеПрава"
... -ConfigPath src -Operation set-defaultRoles -Value "ПолныеПрава ;; Администратор"
```
+54 -54
View File
@@ -1,54 +1,54 @@
---
name: cf-info
description: Анализ структуры конфигурации 1С — свойства, состав, счётчики объектов. Используй для обзора конфигурации — какие объекты есть, сколько их, какие настройки
argument-hint: <ConfigPath> [-Mode overview|brief|full] [-Section home-page]
allowed-tools:
- Bash
- Read
- Glob
---
# /cf-info — Структура конфигурации 1С
Читает Configuration.xml из выгрузки конфигурации и выводит компактное описание структуры.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `ConfigPath` | Путь к Configuration.xml или каталогу выгрузки |
| `Mode` | Режим: `overview` (default), `brief`, `full` |
| `Section` | Drill-down по разделу (alias: `Name`). Сейчас: `home-page` |
| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк) |
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-info.ps1" -ConfigPath "<путь>"
```
## Три режима
| Режим | Что показывает |
|---|---|
| `overview` *(default)* | Заголовок + ключевые свойства + таблица счётчиков объектов по типам |
| `brief` | Одна строка: Имя — "Синоним" vВерсия \| N объектов \| совместимость |
| `full` | Все свойства по категориям + полный список ChildObjects + DefaultRoles + мобильные функциональности |
## Примеры
```powershell
# Обзор пустой конфигурации
... -ConfigPath src
# Краткая сводка реальной конфигурации
... -ConfigPath src -Mode brief
# Полная информация
... -ConfigPath src -Mode full
# С пагинацией
... -ConfigPath src -Mode full -Limit 50 -Offset 100
# Drill-down: только начальная страница (раскладка форм с ролями)
... -ConfigPath src -Section home-page
```
---
name: cf-info
description: Анализ структуры конфигурации 1С — свойства, состав, счётчики объектов. Используй для обзора конфигурации — какие объекты есть, сколько их, какие настройки
argument-hint: <ConfigPath> [-Mode overview|brief|full] [-Section home-page]
allowed-tools:
- Bash
- Read
- Glob
---
# /cf-info — Структура конфигурации 1С
Читает Configuration.xml из выгрузки конфигурации и выводит компактное описание структуры.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `ConfigPath` | Путь к Configuration.xml или каталогу выгрузки |
| `Mode` | Режим: `overview` (default), `brief`, `full` |
| `Section` | Drill-down по разделу (alias: `Name`). Сейчас: `home-page` |
| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк) |
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cf-info.py" -ConfigPath "<путь>"
```
## Три режима
| Режим | Что показывает |
|---|---|
| `overview` *(default)* | Заголовок + ключевые свойства + таблица счётчиков объектов по типам |
| `brief` | Одна строка: Имя — "Синоним" vВерсия \| N объектов \| совместимость |
| `full` | Все свойства по категориям + полный список ChildObjects + DefaultRoles + мобильные функциональности |
## Примеры
```powershell
# Обзор пустой конфигурации
... -ConfigPath src
# Краткая сводка реальной конфигурации
... -ConfigPath src -Mode brief
# Полная информация
... -ConfigPath src -Mode full
# С пагинацией
... -ConfigPath src -Mode full -Limit 50 -Offset 100
# Drill-down: только начальная страница (раскладка форм с ролями)
... -ConfigPath src -Section home-page
```
+49 -49
View File
@@ -1,49 +1,49 @@
---
name: cf-init
description: Создать пустую конфигурацию 1С (scaffold XML-исходников). Используй когда нужно начать новую конфигурацию с нуля
argument-hint: <Name> [-Synonym <name>] [-OutputDir src]
allowed-tools:
- Bash
- Read
- Glob
---
# /cf-init — Создание пустой конфигурации 1С
Создаёт scaffold исходников пустой конфигурации 1С: `Configuration.xml`, `Languages/Русский.xml`.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `Name` | Имя конфигурации (обязат.) |
| `Synonym` | Синоним (= Name если не указан) |
| `OutputDir` | Каталог для создания (default: `src`) |
| `Version` | Версия конфигурации |
| `Vendor` | Поставщик |
| `CompatibilityMode` | Режим совместимости (default: `Version8_3_24`) |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-init.ps1" -Name "МояКонфигурация"
```
## Примеры
```powershell
# Базовая конфигурация
... -Name МояКонфигурация -Synonym "Моя конфигурация" -OutputDir test-tmp/cf
# С версией и поставщиком
... -Name TestCfg -Synonym "Тестовая" -Version "1.0.0.1" -Vendor "Фирма 1С" -OutputDir test-tmp/cf2
# Другой режим совместимости
... -Name TestCfg -CompatibilityMode Version8_3_27 -OutputDir test-tmp/cf3
```
## Верификация
```
/cf-init TestConfig -OutputDir test-tmp/cf
/cf-info test-tmp/cf — проверить созданное
/cf-validate test-tmp/cf — валидировать
```
---
name: cf-init
description: Создать пустую конфигурацию 1С (scaffold XML-исходников). Используй когда нужно начать новую конфигурацию с нуля
argument-hint: <Name> [-Synonym <name>] [-OutputDir src]
allowed-tools:
- Bash
- Read
- Glob
---
# /cf-init — Создание пустой конфигурации 1С
Создаёт scaffold исходников пустой конфигурации 1С: `Configuration.xml`, `Languages/Русский.xml`.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `Name` | Имя конфигурации (обязат.) |
| `Synonym` | Синоним (= Name если не указан) |
| `OutputDir` | Каталог для создания (default: `src`) |
| `Version` | Версия конфигурации |
| `Vendor` | Поставщик |
| `CompatibilityMode` | Режим совместимости (default: `Version8_3_24`) |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cf-init.py" -Name "МояКонфигурация"
```
## Примеры
```powershell
# Базовая конфигурация
... -Name МояКонфигурация -Synonym "Моя конфигурация" -OutputDir test-tmp/cf
# С версией и поставщиком
... -Name TestCfg -Synonym "Тестовая" -Version "1.0.0.1" -Vendor "Фирма 1С" -OutputDir test-tmp/cf2
# Другой режим совместимости
... -Name TestCfg -CompatibilityMode Version8_3_27 -OutputDir test-tmp/cf3
```
## Верификация
```
/cf-init TestConfig -OutputDir test-tmp/cf
/cf-info test-tmp/cf — проверить созданное
/cf-validate test-tmp/cf — валидировать
```
+29 -29
View File
@@ -1,29 +1,29 @@
---
name: cf-validate
description: Валидация конфигурации 1С. Используй после создания или модификации конфигурации для проверки корректности
argument-hint: <ConfigPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /cf-validate — валидация конфигурации 1С
Проверяет Configuration.xml на структурные ошибки: XML well-formedness, InternalInfo, свойства, enum-значения, ChildObjects, DefaultLanguage, файлы языков, каталоги объектов.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|------------|:-----:|---------|-------------------------------------------------|
| ConfigPath | да | — | Путь к Configuration.xml или каталогу выгрузки |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-validate.ps1" -ConfigPath "upload/cfempty"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-validate.ps1" -ConfigPath "upload/cfempty/Configuration.xml"
```
---
name: cf-validate
description: Валидация конфигурации 1С. Используй после создания или модификации конфигурации для проверки корректности
argument-hint: <ConfigPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /cf-validate — валидация конфигурации 1С
Проверяет Configuration.xml на структурные ошибки: XML well-formedness, InternalInfo, свойства, enum-значения, ChildObjects, DefaultLanguage, файлы языков, каталоги объектов.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|------------|:-----:|---------|-------------------------------------------------|
| ConfigPath | да | — | Путь к Configuration.xml или каталогу выгрузки |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cf-validate.py" -ConfigPath "upload/cfempty"
python "${CLAUDE_SKILL_DIR}/scripts/cf-validate.py" -ConfigPath "upload/cfempty/Configuration.xml"
```
+101 -101
View File
@@ -1,101 +1,101 @@
---
name: cfe-borrow
description: Заимствование объектов из конфигурации 1С в расширение (CFE). Используй когда нужно перехватить метод, изменить форму или добавить реквизит к существующему объекту конфигурации
argument-hint: -ExtensionPath <path> -ConfigPath <path> -Object "Catalog.Контрагенты.Form.ФормаЭлемента" -BorrowMainAttribute
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-borrow — Заимствование объектов из конфигурации
Заимствует объекты из основной конфигурации в расширение. Создаёт XML-файлы с `ObjectBelonging=Adopted` и `ExtendedConfigurationObject`, добавляет запись в ChildObjects расширения.
## Предусловие
Расширение должно быть создано (`/cfe-init`) и содержать валидный `Configuration.xml`.
### Авто-определение ConfigPath
Если пользователь не указал `-ConfigPath` — попробуй определить автоматически:
1. Прочитай `.v8-project.json` из корня проекта
2. Разреши целевую базу (по имени, ветке или `default` — алгоритм из `/db-list`)
3. Если у базы есть поле `configSrc` — используй как `-ConfigPath`
4. Если `configSrc` нет — спроси у пользователя
## Параметры
| Параметр | Описание |
|----------|----------|
| `ExtensionPath` | Путь к каталогу расширения (обязат.) |
| `ConfigPath` | Путь к конфигурации-источнику (обязат.) |
| `Object` | Что заимствовать (обязат.), batch через `;;` |
| `BorrowMainAttribute` | Заимствовать основной реквизит формы. Без параметра — не заимствует. `Form` — реквизиты, используемые на форме. `All` — все реквизиты объекта. Требует форму в -Object |
## Формат -Object
- `Catalog.Контрагенты` — справочник
- `CommonModule.РаботаСФайлами` — общий модуль
- `Document.РеализацияТоваров` — документ
- `Enum.ВидыОплат` — перечисление
- `Catalog.Контрагенты.Form.ФормаЭлемента` — форма объекта (заимствование формы)
- `Catalog.X ;; CommonModule.Y ;; Enum.Z` — несколько объектов
Поддерживаются все 44 типа объектов конфигурации.
### Заимствование форм
Формат `Тип.Имя.Form.ИмяФормы` заимствует форму конкретного объекта. Если родительский объект ещё не заимствован — он будет заимствован автоматически.
Создаётся:
1. **Метаданные формы**`Forms/ИмяФормы.xml` с `ObjectBelonging=Adopted`, `FormType=Managed`
2. **Form.xml**`Forms/ИмяФормы/Ext/Form.xml` с копией исходной формы + `<BaseForm>` (начальное состояние)
3. **Module.bsl** — пустой файл `Forms/ИмяФормы/Ext/Form/Module.bsl`
4. **Регистрация**`<Form>` в ChildObjects родительского объекта
### Заимствование основного реквизита формы (-BorrowMainAttribute)
**Когда нужно**: пользователь хочет добавить новый реквизит в существующий объект конфигурации и вывести его на заимствованную форму. Без `-BorrowMainAttribute` форма заимствуется "пустой" — только визуальные элементы, без привязки к данным объекта. С `-BorrowMainAttribute` форма сохраняет привязки к реквизитам объекта (DataPath), что позволяет затем добавить на неё новые элементы через `/form-edit`.
**Два режима**:
- `Form` (по умолчанию) — заимствует только те реквизиты объекта, которые уже выведены на форму. Оптимальный выбор для большинства случаев
- `All` — заимствует все реквизиты и табличные части объекта. Используй если планируешь выводить на форму реквизиты, которых на ней ещё нет
**Типовой сценарий** (добавление реквизита + вывод на форму):
1. `/cfe-borrow` с `-BorrowMainAttribute` — заимствовать форму с реквизитами
2. `/meta-edit` — добавить новый реквизит в объект расширения
3. `/form-edit` — вывести реквизит на заимствованную форму
**Защита существующих данных**: если зависимый объект уже заимствован с содержимым (реквизитами, формами) — скрипт не перезаписывает его, а добавляет только недостающее.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-borrow.ps1" -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты"
```
## Примеры
```powershell
# Заимствовать один объект
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты"
# Заимствовать форму (автоматически заимствует родительский объект)
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты.Form.ФормаЭлемента"
# Несколько объектов за раз
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты ;; CommonModule.ОбщийМодуль ;; Enum.ВидыОплат"
# Заимствовать форму с основным реквизитом (реквизиты по DataPath формы)
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Номенклатура.Form.ФормаЭлемента" -BorrowMainAttribute
# Заимствовать форму с ВСЕМИ реквизитами объекта
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Номенклатура.Form.ФормаЭлемента" -BorrowMainAttribute All
```
## Верификация
```
/cfe-validate <ExtensionPath>
```
---
name: cfe-borrow
description: Заимствование объектов из конфигурации 1С в расширение (CFE). Используй когда нужно перехватить метод, изменить форму или добавить реквизит к существующему объекту конфигурации
argument-hint: -ExtensionPath <path> -ConfigPath <path> -Object "Catalog.Контрагенты.Form.ФормаЭлемента" -BorrowMainAttribute
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-borrow — Заимствование объектов из конфигурации
Заимствует объекты из основной конфигурации в расширение. Создаёт XML-файлы с `ObjectBelonging=Adopted` и `ExtendedConfigurationObject`, добавляет запись в ChildObjects расширения.
## Предусловие
Расширение должно быть создано (`/cfe-init`) и содержать валидный `Configuration.xml`.
### Авто-определение ConfigPath
Если пользователь не указал `-ConfigPath` — попробуй определить автоматически:
1. Прочитай `.v8-project.json` из корня проекта
2. Разреши целевую базу (по имени, ветке или `default` — алгоритм из `/db-list`)
3. Если у базы есть поле `configSrc` — используй как `-ConfigPath`
4. Если `configSrc` нет — спроси у пользователя
## Параметры
| Параметр | Описание |
|----------|----------|
| `ExtensionPath` | Путь к каталогу расширения (обязат.) |
| `ConfigPath` | Путь к конфигурации-источнику (обязат.) |
| `Object` | Что заимствовать (обязат.), batch через `;;` |
| `BorrowMainAttribute` | Заимствовать основной реквизит формы. Без параметра — не заимствует. `Form` — реквизиты, используемые на форме. `All` — все реквизиты объекта. Требует форму в -Object |
## Формат -Object
- `Catalog.Контрагенты` — справочник
- `CommonModule.РаботаСФайлами` — общий модуль
- `Document.РеализацияТоваров` — документ
- `Enum.ВидыОплат` — перечисление
- `Catalog.Контрагенты.Form.ФормаЭлемента` — форма объекта (заимствование формы)
- `Catalog.X ;; CommonModule.Y ;; Enum.Z` — несколько объектов
Поддерживаются все 44 типа объектов конфигурации.
### Заимствование форм
Формат `Тип.Имя.Form.ИмяФормы` заимствует форму конкретного объекта. Если родительский объект ещё не заимствован — он будет заимствован автоматически.
Создаётся:
1. **Метаданные формы**`Forms/ИмяФормы.xml` с `ObjectBelonging=Adopted`, `FormType=Managed`
2. **Form.xml**`Forms/ИмяФормы/Ext/Form.xml` с копией исходной формы + `<BaseForm>` (начальное состояние)
3. **Module.bsl** — пустой файл `Forms/ИмяФормы/Ext/Form/Module.bsl`
4. **Регистрация**`<Form>` в ChildObjects родительского объекта
### Заимствование основного реквизита формы (-BorrowMainAttribute)
**Когда нужно**: пользователь хочет добавить новый реквизит в существующий объект конфигурации и вывести его на заимствованную форму. Без `-BorrowMainAttribute` форма заимствуется "пустой" — только визуальные элементы, без привязки к данным объекта. С `-BorrowMainAttribute` форма сохраняет привязки к реквизитам объекта (DataPath), что позволяет затем добавить на неё новые элементы через `/form-edit`.
**Два режима**:
- `Form` (по умолчанию) — заимствует только те реквизиты объекта, которые уже выведены на форму. Оптимальный выбор для большинства случаев
- `All` — заимствует все реквизиты и табличные части объекта. Используй если планируешь выводить на форму реквизиты, которых на ней ещё нет
**Типовой сценарий** (добавление реквизита + вывод на форму):
1. `/cfe-borrow` с `-BorrowMainAttribute` — заимствовать форму с реквизитами
2. `/meta-edit` — добавить новый реквизит в объект расширения
3. `/form-edit` — вывести реквизит на заимствованную форму
**Защита существующих данных**: если зависимый объект уже заимствован с содержимым (реквизитами, формами) — скрипт не перезаписывает его, а добавляет только недостающее.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cfe-borrow.py" -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты"
```
## Примеры
```powershell
# Заимствовать один объект
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты"
# Заимствовать форму (автоматически заимствует родительский объект)
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты.Form.ФормаЭлемента"
# Несколько объектов за раз
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты ;; CommonModule.ОбщийМодуль ;; Enum.ВидыОплат"
# Заимствовать форму с основным реквизитом (реквизиты по DataPath формы)
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Номенклатура.Form.ФормаЭлемента" -BorrowMainAttribute
# Заимствовать форму с ВСЕМИ реквизитами объекта
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Номенклатура.Form.ФормаЭлемента" -BorrowMainAttribute All
```
## Верификация
```
/cfe-validate <ExtensionPath>
```
+57 -57
View File
@@ -1,57 +1,57 @@
---
name: cfe-diff
description: Анализ расширения конфигурации 1С (CFE) — состав, заимствованные объекты, перехватчики, проверка переноса. Используй когда нужно понять что содержит расширение или проверить перенесены ли вставки в конфигурацию
argument-hint: -ExtensionPath <path> -ConfigPath <path> [-Mode A|B]
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-diff — Анализ расширения конфигурации
Анализирует расширение в двух режимах: обзор изменений (Mode A) или проверка переноса (Mode B).
## Параметры
| Параметр | Описание | По умолчанию |
|----------|----------|--------------|
| `ExtensionPath` | Путь к расширению (обязат.) | — |
| `ConfigPath` | Путь к конфигурации (обязат.) | — |
| `Mode` | `A` (обзор) / `B` (проверка переноса) | `A` |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-diff.ps1" -ExtensionPath src -ConfigPath C:\cfsrc\erp -Mode A
```
## Mode A — обзор расширения
Для каждого объекта показывает:
- `[BORROWED]` — заимствованный: перехватчики (`&Перед`, `&После`, `&ИзменениеИКонтроль`, `&Вместо`), собственные реквизиты/ТЧ/формы
- `[OWN]` — собственный: количество реквизитов, ТЧ, форм
Для каждой формы заимствованного объекта показывается:
- `(borrowed)` / `(own)` — заимствованная или собственная форма
- callType-события формы и элементов
- callType на командах
## Mode B — проверка переноса
Для каждого `&ИзменениеИКонтроль` извлекает блоки `#Вставка`/`#КонецВставки` из расширения и ищет их в соответствующем модуле конфигурации.
Статусы:
- `[TRANSFERRED]` — код найден в конфигурации
- `[NOT_TRANSFERRED]` — код не найден
- `[NEEDS_REVIEW]` — нет блоков `#Вставка` или модуль конфигурации не найден
## Примеры
```powershell
# Обзор — что изменено в расширении
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Mode A
# Проверка переноса — все ли #Вставка перенесены
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Mode B
```
---
name: cfe-diff
description: Анализ расширения конфигурации 1С (CFE) — состав, заимствованные объекты, перехватчики, проверка переноса. Используй когда нужно понять что содержит расширение или проверить перенесены ли вставки в конфигурацию
argument-hint: -ExtensionPath <path> -ConfigPath <path> [-Mode A|B]
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-diff — Анализ расширения конфигурации
Анализирует расширение в двух режимах: обзор изменений (Mode A) или проверка переноса (Mode B).
## Параметры
| Параметр | Описание | По умолчанию |
|----------|----------|--------------|
| `ExtensionPath` | Путь к расширению (обязат.) | — |
| `ConfigPath` | Путь к конфигурации (обязат.) | — |
| `Mode` | `A` (обзор) / `B` (проверка переноса) | `A` |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cfe-diff.py" -ExtensionPath src -ConfigPath C:\cfsrc\erp -Mode A
```
## Mode A — обзор расширения
Для каждого объекта показывает:
- `[BORROWED]` — заимствованный: перехватчики (`&Перед`, `&После`, `&ИзменениеИКонтроль`, `&Вместо`), собственные реквизиты/ТЧ/формы
- `[OWN]` — собственный: количество реквизитов, ТЧ, форм
Для каждой формы заимствованного объекта показывается:
- `(borrowed)` / `(own)` — заимствованная или собственная форма
- callType-события формы и элементов
- callType на командах
## Mode B — проверка переноса
Для каждого `&ИзменениеИКонтроль` извлекает блоки `#Вставка`/`#КонецВставки` из расширения и ищет их в соответствующем модуле конфигурации.
Статусы:
- `[TRANSFERRED]` — код найден в конфигурации
- `[NOT_TRANSFERRED]` — код не найден
- `[NEEDS_REVIEW]` — нет блоков `#Вставка` или модуль конфигурации не найден
## Примеры
```powershell
# Обзор — что изменено в расширении
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Mode A
# Проверка переноса — все ли #Вставка перенесены
... -ExtensionPath src -ConfigPath C:\cfsrc\erp -Mode B
```
+71 -71
View File
@@ -1,71 +1,71 @@
---
name: cfe-init
description: Создать расширение конфигурации 1С (CFE) — scaffold XML-исходников. Используй когда нужно создать новое расширение для исправления, доработки или дополнения конфигурации
argument-hint: <Name> [-ConfigPath <path>] [-Purpose Patch|Customization|AddOn] [-CompatibilityMode Version8_3_24]
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-init — Создание расширения конфигурации 1С
Создаёт scaffold расширения: `Configuration.xml`, `Languages/Русский.xml`, опционально `Roles/`.
## Подготовка
Если есть выгрузка базовой конфигурации, передай `-ConfigPath` — скрипт автоматически определит `CompatibilityMode` и UUID языка из базовой конфигурации.
### Авто-определение ConfigPath
Если пользователь не указал `-ConfigPath` — попробуй определить автоматически:
1. Прочитай `.v8-project.json` из корня проекта
2. Разреши целевую базу (по имени, ветке или `default` — алгоритм из `/db-list`)
3. Если у базы есть поле `configSrc` — используй как `-ConfigPath`
4. Если `configSrc` нет — спроси у пользователя
Если `.v8-project.json` не найден и `-ConfigPath` не задан — расширение создастся с предупреждением (UUID языка = нули, CompatibilityMode по умолчанию).
## Параметры
| Параметр | Описание | По умолчанию |
|----------|----------|--------------|
| `Name` | Имя расширения (обязат.) | — |
| `Synonym` | Синоним | = Name |
| `NamePrefix` | Префикс собственных объектов | = Name + "_" |
| `OutputDir` | Каталог для создания | `src` |
| `Purpose` | `Patch` (исправление) / `Customization` (доработка) / `AddOn` (дополнение) | `Customization` |
| `Version` | Версия расширения | — |
| `Vendor` | Поставщик | — |
| `CompatibilityMode` | Режим совместимости | `Version8_3_24` |
| `ConfigPath` | Путь к выгрузке базовой конфигурации (авто-определяет CompatibilityMode и Language UUID) | — |
| `NoRole` | Без основной роли | false |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-init.ps1" -Name "МоёРасширение"
```
## Примеры
```powershell
# Расширение для ERP с авто-определением совместимости из базовой конфигурации
... -Name Расш1 -ConfigPath C:\WS\tasks\cfsrc\erp_8.3.24 -OutputDir src
# Расширение-исправление с явным режимом совместимости
... -Name Расш1 -Purpose Patch -CompatibilityMode Version8_3_17 -OutputDir src
# Расширение-доработка с версией
... -Name МоёРасширение -Version "1.0.0.1" -Vendor "Компания" -OutputDir src
# Без роли, с явным префиксом
... -Name ИсправлениеБага -NamePrefix "ИБ_" -Purpose Patch -NoRole -OutputDir src
```
## Верификация
```
/cfe-validate <OutputDir>
```
---
name: cfe-init
description: Создать расширение конфигурации 1С (CFE) — scaffold XML-исходников. Используй когда нужно создать новое расширение для исправления, доработки или дополнения конфигурации
argument-hint: <Name> [-ConfigPath <path>] [-Purpose Patch|Customization|AddOn] [-CompatibilityMode Version8_3_24]
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-init — Создание расширения конфигурации 1С
Создаёт scaffold расширения: `Configuration.xml`, `Languages/Русский.xml`, опционально `Roles/`.
## Подготовка
Если есть выгрузка базовой конфигурации, передай `-ConfigPath` — скрипт автоматически определит `CompatibilityMode` и UUID языка из базовой конфигурации.
### Авто-определение ConfigPath
Если пользователь не указал `-ConfigPath` — попробуй определить автоматически:
1. Прочитай `.v8-project.json` из корня проекта
2. Разреши целевую базу (по имени, ветке или `default` — алгоритм из `/db-list`)
3. Если у базы есть поле `configSrc` — используй как `-ConfigPath`
4. Если `configSrc` нет — спроси у пользователя
Если `.v8-project.json` не найден и `-ConfigPath` не задан — расширение создастся с предупреждением (UUID языка = нули, CompatibilityMode по умолчанию).
## Параметры
| Параметр | Описание | По умолчанию |
|----------|----------|--------------|
| `Name` | Имя расширения (обязат.) | — |
| `Synonym` | Синоним | = Name |
| `NamePrefix` | Префикс собственных объектов | = Name + "_" |
| `OutputDir` | Каталог для создания | `src` |
| `Purpose` | `Patch` (исправление) / `Customization` (доработка) / `AddOn` (дополнение) | `Customization` |
| `Version` | Версия расширения | — |
| `Vendor` | Поставщик | — |
| `CompatibilityMode` | Режим совместимости | `Version8_3_24` |
| `ConfigPath` | Путь к выгрузке базовой конфигурации (авто-определяет CompatibilityMode и Language UUID) | — |
| `NoRole` | Без основной роли | false |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cfe-init.py" -Name "МоёРасширение"
```
## Примеры
```powershell
# Расширение для ERP с авто-определением совместимости из базовой конфигурации
... -Name Расш1 -ConfigPath C:\WS\tasks\cfsrc\erp_8.3.24 -OutputDir src
# Расширение-исправление с явным режимом совместимости
... -Name Расш1 -Purpose Patch -CompatibilityMode Version8_3_17 -OutputDir src
# Расширение-доработка с версией
... -Name МоёРасширение -Version "1.0.0.1" -Vendor "Компания" -OutputDir src
# Без роли, с явным префиксом
... -Name ИсправлениеБага -NamePrefix "ИБ_" -Purpose Patch -NoRole -OutputDir src
```
## Верификация
```
/cfe-validate <OutputDir>
```
+78 -78
View File
@@ -1,78 +1,78 @@
---
name: cfe-patch-method
description: Генерация перехватчика метода в расширении 1С (CFE). Используй когда нужно перехватить метод заимствованного объекта — вставить код до, после или вместо оригинального
argument-hint: -ExtensionPath <path> -ModulePath "Catalog.X.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-patch-method — Генерация перехватчика метода
Генерирует `.bsl` файл с декоратором перехвата для заимствованного объекта расширения. Создаёт файл или дописывает в существующий.
## Предусловие
Объект должен быть заимствован в расширение (`/cfe-borrow`). Скрипт читает `NamePrefix` из `Configuration.xml` расширения для формирования имени процедуры.
## Параметры
| Параметр | Описание | По умолчанию |
|----------|----------|--------------|
| `ExtensionPath` | Путь к расширению (обязат.) | — |
| `ModulePath` | Путь к модулю (обязат.) | — |
| `MethodName` | Имя перехватываемого метода (обязат.) | — |
| `InterceptorType` | `Before` / `After` / `ModificationAndControl` (обязат.) | — |
| `Context` | Директива контекста | `НаСервере` |
| `IsFunction` | Метод — функция (добавит `Возврат`) | false |
## Формат ModulePath
| ModulePath | Файл |
|------------|------|
| `Catalog.X.ObjectModule` | `Catalogs/X/Ext/ObjectModule.bsl` |
| `Catalog.X.ManagerModule` | `Catalogs/X/Ext/ManagerModule.bsl` |
| `Catalog.X.Form.Y` | `Catalogs/X/Forms/Y/Ext/Form/Module.bsl` |
| `CommonModule.X` | `CommonModules/X/Ext/Module.bsl` |
| `Document.X.ObjectModule` | `Documents/X/Ext/ObjectModule.bsl` |
| `Document.X.Form.Y` | `Documents/X/Forms/Y/Ext/Form/Module.bsl` |
Аналогично для Report, DataProcessor, InformationRegister и других типов.
## Типы перехвата
| InterceptorType | Декоратор | Назначение |
|-----------------|-----------|------------|
| `Before` | `&Перед` | Код до вызова оригинального метода |
| `After` | `&После` | Код после вызова оригинального метода |
| `ModificationAndControl` | `&ИзменениеИКонтроль` | Копия тела метода с маркерами `#Вставка`/`#Удаление` |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-patch-method.ps1" -ExtensionPath src -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before
```
## Примеры
```powershell
# Перехват &Перед на сервере
... -ExtensionPath src -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before
# Перехват &После на клиенте
... -ExtensionPath src -ModulePath "Document.Заказ.Form.ФормаДокумента" -MethodName "ПослеЗаписиНаСервере" -InterceptorType After -Context "НаКлиенте"
# ИзменениеИКонтроль для функции
... -ExtensionPath src -ModulePath "CommonModule.ОбщийМодуль" -MethodName "ПолучитьДанные" -InterceptorType ModificationAndControl -IsFunction
```
## Генерируемый код (Before)
```bsl
&НаСервере
&Перед("ПриЗаписи")
Процедура Расш1_ПриЗаписи()
// TODO: код перед вызовом оригинального метода
КонецПроцедуры
```
---
name: cfe-patch-method
description: Генерация перехватчика метода в расширении 1С (CFE). Используй когда нужно перехватить метод заимствованного объекта — вставить код до, после или вместо оригинального
argument-hint: -ExtensionPath <path> -ModulePath "Catalog.X.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-patch-method — Генерация перехватчика метода
Генерирует `.bsl` файл с декоратором перехвата для заимствованного объекта расширения. Создаёт файл или дописывает в существующий.
## Предусловие
Объект должен быть заимствован в расширение (`/cfe-borrow`). Скрипт читает `NamePrefix` из `Configuration.xml` расширения для формирования имени процедуры.
## Параметры
| Параметр | Описание | По умолчанию |
|----------|----------|--------------|
| `ExtensionPath` | Путь к расширению (обязат.) | — |
| `ModulePath` | Путь к модулю (обязат.) | — |
| `MethodName` | Имя перехватываемого метода (обязат.) | — |
| `InterceptorType` | `Before` / `After` / `ModificationAndControl` (обязат.) | — |
| `Context` | Директива контекста | `НаСервере` |
| `IsFunction` | Метод — функция (добавит `Возврат`) | false |
## Формат ModulePath
| ModulePath | Файл |
|------------|------|
| `Catalog.X.ObjectModule` | `Catalogs/X/Ext/ObjectModule.bsl` |
| `Catalog.X.ManagerModule` | `Catalogs/X/Ext/ManagerModule.bsl` |
| `Catalog.X.Form.Y` | `Catalogs/X/Forms/Y/Ext/Form/Module.bsl` |
| `CommonModule.X` | `CommonModules/X/Ext/Module.bsl` |
| `Document.X.ObjectModule` | `Documents/X/Ext/ObjectModule.bsl` |
| `Document.X.Form.Y` | `Documents/X/Forms/Y/Ext/Form/Module.bsl` |
Аналогично для Report, DataProcessor, InformationRegister и других типов.
## Типы перехвата
| InterceptorType | Декоратор | Назначение |
|-----------------|-----------|------------|
| `Before` | `&Перед` | Код до вызова оригинального метода |
| `After` | `&После` | Код после вызова оригинального метода |
| `ModificationAndControl` | `&ИзменениеИКонтроль` | Копия тела метода с маркерами `#Вставка`/`#Удаление` |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cfe-patch-method.py" -ExtensionPath src -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before
```
## Примеры
```powershell
# Перехват &Перед на сервере
... -ExtensionPath src -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before
# Перехват &После на клиенте
... -ExtensionPath src -ModulePath "Document.Заказ.Form.ФормаДокумента" -MethodName "ПослеЗаписиНаСервере" -InterceptorType After -Context "НаКлиенте"
# ИзменениеИКонтроль для функции
... -ExtensionPath src -ModulePath "CommonModule.ОбщийМодуль" -MethodName "ПолучитьДанные" -InterceptorType ModificationAndControl -IsFunction
```
## Генерируемый код (Before)
```bsl
&НаСервере
&Перед("ПриЗаписи")
Процедура Расш1_ПриЗаписи()
// TODO: код перед вызовом оригинального метода
КонецПроцедуры
```
+29 -29
View File
@@ -1,29 +1,29 @@
---
name: cfe-validate
description: Валидация расширения конфигурации 1С (CFE). Используй после создания или модификации расширения для проверки корректности
argument-hint: <ExtensionPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-validate — валидация расширения конфигурации (CFE)
Проверяет структурную корректность расширения: XML-формат, свойства, состав, заимствованные объекты. Аналог `/cf-validate`, но для расширений.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|---------------|:-----:|---------|-------------------------------------------------|
| ExtensionPath | да | — | Путь к каталогу или Configuration.xml расширения |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-validate.ps1" -ExtensionPath "src"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-validate.ps1" -ExtensionPath "src/Configuration.xml"
```
---
name: cfe-validate
description: Валидация расширения конфигурации 1С (CFE). Используй после создания или модификации расширения для проверки корректности
argument-hint: <ExtensionPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /cfe-validate — валидация расширения конфигурации (CFE)
Проверяет структурную корректность расширения: XML-формат, свойства, состав, заимствованные объекты. Аналог `/cf-validate`, но для расширений.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|---------------|:-----:|---------|-------------------------------------------------|
| ExtensionPath | да | — | Путь к каталогу или Configuration.xml расширения |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/cfe-validate.py" -ExtensionPath "src"
python "${CLAUDE_SKILL_DIR}/scripts/cfe-validate.py" -ExtensionPath "src/Configuration.xml"
```
+78 -78
View File
@@ -1,78 +1,78 @@
---
name: db-create
description: Создание информационной базы 1С. Используй когда нужно создать базу, новую ИБ, пустую базу
argument-hint: <path|name>
allowed-tools:
- Bash
- Read
- Write
- Glob
- AskUserQuestion
---
# /db-create — Создание информационной базы
Создаёт новую информационную базу 1С (файловую или серверную) и предлагает зарегистрировать в `.v8-project.json`.
## Usage
```
/db-create <path> — файловая база по указанному пути
/db-create <server>/<name> — серверная база
/db-create — интерактивно
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта для `v8path` (путь к платформе).
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
После создания базы предложи зарегистрировать через `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Путь к файловой базе |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UseTemplate <файл>` | нет | Создать из шаблона (.cf или .dt) |
| `-AddToList` | нет | Добавить в список баз 1С |
| `-ListName <имя>` | нет | Имя базы в списке |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## После создания
1. Прочитай лог-файл и покажи результат
2. Предложи зарегистрировать базу в `.v8-project.json` (через `/db-list add`)
3. Если указан шаблон `/UseTemplate` — предупреди что конфигурация будет загружена из шаблона
## Примеры
```powershell
# Создать файловую базу
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" -InfoBasePath "C:\Bases\NewDB"
# Создать серверную базу
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test"
# Создать из шаблона CF
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" -InfoBasePath "C:\Bases\NewDB" -UseTemplate "C:\Templates\config.cf"
# Создать и добавить в список баз
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" -InfoBasePath "C:\Bases\NewDB" -AddToList -ListName "Новая база"
```
---
name: db-create
description: Создание информационной базы 1С. Используй когда нужно создать базу, новую ИБ, пустую базу
argument-hint: <path|name>
allowed-tools:
- Bash
- Read
- Write
- Glob
- AskUserQuestion
---
# /db-create — Создание информационной базы
Создаёт новую информационную базу 1С (файловую или серверную) и предлагает зарегистрировать в `.v8-project.json`.
## Usage
```
/db-create <path> — файловая база по указанному пути
/db-create <server>/<name> — серверная база
/db-create — интерактивно
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта для `v8path` (путь к платформе).
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
После создания базы предложи зарегистрировать через `/db-list add`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/db-create.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Путь к файловой базе |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UseTemplate <файл>` | нет | Создать из шаблона (.cf или .dt) |
| `-AddToList` | нет | Добавить в список баз 1С |
| `-ListName <имя>` | нет | Имя базы в списке |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## После создания
1. Прочитай лог-файл и покажи результат
2. Предложи зарегистрировать базу в `.v8-project.json` (через `/db-list add`)
3. Если указан шаблон `/UseTemplate` — предупреди что конфигурация будет загружена из шаблона
## Примеры
```powershell
# Создать файловую базу
python "${CLAUDE_SKILL_DIR}/scripts/db-create.py" -InfoBasePath "C:\Bases\NewDB"
# Создать серверную базу
python "${CLAUDE_SKILL_DIR}/scripts/db-create.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test"
# Создать из шаблона CF
python "${CLAUDE_SKILL_DIR}/scripts/db-create.py" -InfoBasePath "C:\Bases\NewDB" -UseTemplate "C:\Templates\config.cf"
# Создать и добавить в список баз
python "${CLAUDE_SKILL_DIR}/scripts/db-create.py" -InfoBasePath "C:\Bases\NewDB" -AddToList -ListName "Новая база"
```
+79 -79
View File
@@ -1,79 +1,79 @@
---
name: db-dump-cf
description: Выгрузка конфигурации 1С в CF-файл. Используй когда нужно выгрузить конфигурацию в CF, сохранить конфигурацию, сделать бэкап CF
argument-hint: "[database] [output.cf]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-dump-cf — Выгрузка конфигурации в CF-файл
Выгружает конфигурацию информационной базы в бинарный CF-файл.
## Usage
```
/db-dump-cf [database] [output.cf]
/db-dump-cf dev config.cf
/db-dump-cf — база по умолчанию, файл config.cf
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-OutputFile <путь>` | да | Путь к выходному CF-файлу |
| `-Extension <имя>` | нет | Выгрузить расширение |
| `-AllExtensions` | нет | Выгрузить все расширения |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## После выполнения
Прочитай лог-файл и покажи результат. Если есть ошибки — покажи содержимое лога.
## Примеры
```powershell
# Выгрузка конфигурации (файловая база)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "C:\backup\config.cf"
# Серверная база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -OutputFile "config.cf"
# Выгрузка расширения
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "ext.cfe" -Extension "МоёРасширение"
```
---
name: db-dump-cf
description: Выгрузка конфигурации 1С в CF-файл. Используй когда нужно выгрузить конфигурацию в CF, сохранить конфигурацию, сделать бэкап CF
argument-hint: "[database] [output.cf]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-dump-cf — Выгрузка конфигурации в CF-файл
Выгружает конфигурацию информационной базы в бинарный CF-файл.
## Usage
```
/db-dump-cf [database] [output.cf]
/db-dump-cf dev config.cf
/db-dump-cf — база по умолчанию, файл config.cf
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-OutputFile <путь>` | да | Путь к выходному CF-файлу |
| `-Extension <имя>` | нет | Выгрузить расширение |
| `-AllExtensions` | нет | Выгрузить все расширения |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## После выполнения
Прочитай лог-файл и покажи результат. Если есть ошибки — покажи содержимое лога.
## Примеры
```powershell
# Выгрузка конфигурации (файловая база)
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "C:\backup\config.cf"
# Серверная база
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -OutputFile "config.cf"
# Выгрузка расширения
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "ext.cfe" -Extension "МоёРасширение"
```
+97 -97
View File
@@ -1,97 +1,97 @@
---
name: db-dump-xml
description: Выгрузка конфигурации 1С в XML-файлы. Используй когда нужно выгрузить конфигурацию в файлы, XML, исходники, DumpConfigToFiles
argument-hint: "[database] [outputDir]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-dump-xml — Выгрузка конфигурации в XML
Выгружает конфигурацию информационной базы в XML-файлы (исходники). Поддерживает полную, инкрементальную, частичную выгрузку и обновление ConfigDumpInfo.
## Usage
```
/db-dump-xml [database] [outputDir]
/db-dump-xml dev src/config
/db-dump-xml dev src/config -Mode Full
/db-dump-xml dev src/config -Mode Partial -Objects "Справочник.Номенклатура,Документ.Заказ"
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
Если в записи базы указан `configSrc` — используй как каталог выгрузки по умолчанию.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-ConfigDir <путь>` | да | Каталог для выгрузки |
| `-Mode <режим>` | нет | `Full` / `Changes` (по умолч.) / `Partial` / `UpdateInfo` |
| `-Objects <список>` | для Partial | Имена объектов через запятую |
| `-Extension <имя>` | нет | Выгрузить расширение |
| `-AllExtensions` | нет | Выгрузить все расширения |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
### Режимы выгрузки
| Режим | Описание |
|-------|----------|
| `Full` | Полная выгрузка — все объекты конфигурации |
| `Changes` | Инкрементальная — только изменённые с последней выгрузки (использует ConfigDumpInfo.xml) |
| `Partial` | Частичная — выбранные объекты из параметра `-Objects` |
| `UpdateInfo` | Обновить только ConfigDumpInfo.xml без выгрузки файлов |
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
> Если пользователь просит выгрузить конкретные объекты — используй `-Mode Partial` с `-Objects`.
## Примеры
```powershell
# Полная выгрузка (файловая база)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full
# Инкрементальная выгрузка
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Changes
# Частичная выгрузка
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Partial -Objects "Справочник.Номенклатура,Документ.Заказ"
# Серверная база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -ConfigDir "C:\WS\cfsrc" -Mode Full
# Выгрузка расширения
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\ext_src" -Mode Full -Extension "МоёРасширение"
```
---
name: db-dump-xml
description: Выгрузка конфигурации 1С в XML-файлы. Используй когда нужно выгрузить конфигурацию в файлы, XML, исходники, DumpConfigToFiles
argument-hint: "[database] [outputDir]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-dump-xml — Выгрузка конфигурации в XML
Выгружает конфигурацию информационной базы в XML-файлы (исходники). Поддерживает полную, инкрементальную, частичную выгрузку и обновление ConfigDumpInfo.
## Usage
```
/db-dump-xml [database] [outputDir]
/db-dump-xml dev src/config
/db-dump-xml dev src/config -Mode Full
/db-dump-xml dev src/config -Mode Partial -Objects "Справочник.Номенклатура,Документ.Заказ"
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
Если в записи базы указан `configSrc` — используй как каталог выгрузки по умолчанию.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-ConfigDir <путь>` | да | Каталог для выгрузки |
| `-Mode <режим>` | нет | `Full` / `Changes` (по умолч.) / `Partial` / `UpdateInfo` |
| `-Objects <список>` | для Partial | Имена объектов через запятую |
| `-Extension <имя>` | нет | Выгрузить расширение |
| `-AllExtensions` | нет | Выгрузить все расширения |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
### Режимы выгрузки
| Режим | Описание |
|-------|----------|
| `Full` | Полная выгрузка — все объекты конфигурации |
| `Changes` | Инкрементальная — только изменённые с последней выгрузки (использует ConfigDumpInfo.xml) |
| `Partial` | Частичная — выбранные объекты из параметра `-Objects` |
| `UpdateInfo` | Обновить только ConfigDumpInfo.xml без выгрузки файлов |
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
> Если пользователь просит выгрузить конкретные объекты — используй `-Mode Partial` с `-Objects`.
## Примеры
```powershell
# Полная выгрузка (файловая база)
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.py" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full
# Инкрементальная выгрузка
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Changes
# Частичная выгрузка
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Partial -Objects "Справочник.Номенклатура,Документ.Заказ"
# Серверная база
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -ConfigDir "C:\WS\cfsrc" -Mode Full
# Выгрузка расширения
python "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\ext_src" -Mode Full -Extension "МоёРасширение"
```
+81 -81
View File
@@ -1,81 +1,81 @@
---
name: db-load-cf
description: Загрузка конфигурации 1С из CF-файла. Используй когда нужно загрузить конфигурацию из CF, восстановить из бэкапа CF
argument-hint: <input.cf> [database]
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-load-cf — Загрузка конфигурации из CF-файла
Загружает конфигурацию из бинарного CF-файла в информационную базу.
## Usage
```
/db-load-cf <input.cf> [database]
/db-load-cf config.cf dev
```
> **Внимание**: загрузка CF **полностью заменяет** конфигурацию в базе. Перед выполнением запроси подтверждение у пользователя.
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-InputFile <путь>` | да | Путь к CF-файлу |
| `-Extension <имя>` | нет | Загрузить как расширение |
| `-AllExtensions` | нет | Загрузить все расширения из архива |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## После выполнения
1. Прочитай лог-файл и покажи результат
2. **Предложи выполнить `/db-update`** — загрузка CF обновляет только «основную» конфигурацию конфигуратора, для применения к БД нужен `/UpdateDBCfg`
## Примеры
```powershell
# Файловая база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "C:\backup\config.cf"
# Серверная база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test" -UserName "Admin" -Password "secret" -InputFile "config.cf"
# Загрузка расширения
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "ext.cfe" -Extension "МоёРасширение"
```
---
name: db-load-cf
description: Загрузка конфигурации 1С из CF-файла. Используй когда нужно загрузить конфигурацию из CF, восстановить из бэкапа CF
argument-hint: <input.cf> [database]
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-load-cf — Загрузка конфигурации из CF-файла
Загружает конфигурацию из бинарного CF-файла в информационную базу.
## Usage
```
/db-load-cf <input.cf> [database]
/db-load-cf config.cf dev
```
> **Внимание**: загрузка CF **полностью заменяет** конфигурацию в базе. Перед выполнением запроси подтверждение у пользователя.
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-InputFile <путь>` | да | Путь к CF-файлу |
| `-Extension <имя>` | нет | Загрузить как расширение |
| `-AllExtensions` | нет | Загрузить все расширения из архива |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## После выполнения
1. Прочитай лог-файл и покажи результат
2. **Предложи выполнить `/db-update`** — загрузка CF обновляет только «основную» конфигурацию конфигуратора, для применения к БД нужен `/UpdateDBCfg`
## Примеры
```powershell
# Файловая база
python "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "C:\backup\config.cf"
# Серверная база
python "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test" -UserName "Admin" -Password "secret" -InputFile "config.cf"
# Загрузка расширения
python "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "ext.cfe" -Extension "МоёРасширение"
```
+78 -78
View File
@@ -1,78 +1,78 @@
---
name: db-load-git
description: Загрузка изменений из Git в базу 1С. Используй когда нужно загрузить изменения из гита, обновить базу из репозитория, partial load из коммита
argument-hint: "[database] [source]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-load-git — Загрузка изменений из Git
Определяет изменённые файлы конфигурации по данным Git и выполняет частичную загрузку в информационную базу.
## Usage
```
/db-load-git [database]
/db-load-git dev — все незафиксированные изменения
/db-load-git dev -Source Staged — только staged
/db-load-git dev -Source Commit -CommitRange "HEAD~3..HEAD"
/db-load-git dev -DryRun — только показать что будет загружено
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
Если в записи базы указан `configSrc` — используй как каталог конфигурации.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-ConfigDir <путь>` | да | Каталог XML-выгрузки (git-репозиторий) |
| `-Source <источник>` | нет | `All` (по умолч.) / `Staged` / `Unstaged` / `Commit` |
| `-CommitRange <range>` | для Commit | Диапазон коммитов (напр. `HEAD~3..HEAD`) |
| `-Extension <имя>` | нет | Загрузить в расширение |
| `-AllExtensions` | нет | Загрузить все расширения |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
| `-DryRun` | нет | Только показать что будет загружено (без загрузки) |
| `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## После выполнения
1. Показать список загруженных файлов и результат из лога
2. Если `-UpdateDB` не был указан — **предложить `/db-update`** для применения изменений к БД
## Примеры
```powershell
# Все незафиксированные изменения
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -ConfigDir "C:\WS\cfsrc" -Source All -UpdateDB
# Из диапазона коммитов
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" -InfoBasePath "C:\Bases\MyDB" -ConfigDir "C:\WS\cfsrc" -Source Commit -CommitRange "HEAD~3..HEAD"
```
---
name: db-load-git
description: Загрузка изменений из Git в базу 1С. Используй когда нужно загрузить изменения из гита, обновить базу из репозитория, partial load из коммита
argument-hint: "[database] [source]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-load-git — Загрузка изменений из Git
Определяет изменённые файлы конфигурации по данным Git и выполняет частичную загрузку в информационную базу.
## Usage
```
/db-load-git [database]
/db-load-git dev — все незафиксированные изменения
/db-load-git dev -Source Staged — только staged
/db-load-git dev -Source Commit -CommitRange "HEAD~3..HEAD"
/db-load-git dev -DryRun — только показать что будет загружено
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
Если в записи базы указан `configSrc` — используй как каталог конфигурации.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/db-load-git.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-ConfigDir <путь>` | да | Каталог XML-выгрузки (git-репозиторий) |
| `-Source <источник>` | нет | `All` (по умолч.) / `Staged` / `Unstaged` / `Commit` |
| `-CommitRange <range>` | для Commit | Диапазон коммитов (напр. `HEAD~3..HEAD`) |
| `-Extension <имя>` | нет | Загрузить в расширение |
| `-AllExtensions` | нет | Загрузить все расширения |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
| `-DryRun` | нет | Только показать что будет загружено (без загрузки) |
| `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## После выполнения
1. Показать список загруженных файлов и результат из лога
2. Если `-UpdateDB` не был указан — **предложить `/db-update`** для применения изменений к БД
## Примеры
```powershell
# Все незафиксированные изменения
python "${CLAUDE_SKILL_DIR}/scripts/db-load-git.py" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -ConfigDir "C:\WS\cfsrc" -Source All -UpdateDB
# Из диапазона коммитов
python "${CLAUDE_SKILL_DIR}/scripts/db-load-git.py" -InfoBasePath "C:\Bases\MyDB" -ConfigDir "C:\WS\cfsrc" -Source Commit -CommitRange "HEAD~3..HEAD"
```
+109 -109
View File
@@ -1,109 +1,109 @@
---
name: db-load-xml
description: Загрузка конфигурации 1С из XML-файлов. Используй когда нужно загрузить конфигурацию из файлов, XML, исходников, LoadConfigFromFiles
argument-hint: <configDir> [database]
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-load-xml — Загрузка конфигурации из XML
Загружает конфигурацию в информационную базу из XML-файлов (исходников). Поддерживает полную и частичную загрузку.
## Usage
```
/db-load-xml <configDir> [database]
/db-load-xml src/config dev
/db-load-xml src/config dev -Mode Partial -Files "Catalogs/Номенклатура.xml,Catalogs/Номенклатура/Ext/ObjectModule.bsl"
```
> **Внимание**: полная загрузка **заменяет всю конфигурацию** в базе. Перед выполнением запроси подтверждение у пользователя.
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
Если в записи базы указан `configSrc` — используй как каталог загрузки по умолчанию.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-ConfigDir <путь>` | да | Каталог XML-исходников |
| `-Mode <режим>` | нет | `Full` (по умолч.) / `Partial` |
| `-Files <список>` | для Partial | Относительные пути файлов через запятую |
| `-ListFile <путь>` | для Partial | Путь к файлу со списком (альтернатива `-Files`) |
| `-Extension <имя>` | нет | Загрузить в расширение |
| `-AllExtensions` | нет | Загрузить все расширения |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
| `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
### Режимы загрузки
| Режим | Описание |
|-------|----------|
| `Full` | Полная загрузка — замена всей конфигурации из каталога XML |
| `Partial` | Частичная — загрузка выбранных файлов (с `-partial -updateConfigDumpInfo`) |
### Формат файла списка (listFile)
Файл содержит **относительные пути к файлам** в каталоге выгрузки (один на строку), кодировка **UTF-8 с BOM**:
```
Catalogs/Номенклатура.xml
Catalogs/Номенклатура/Ext/ObjectModule.bsl
Documents/Заказ.xml
Documents/Заказ/Forms/ФормаДокумента.xml
```
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## После выполнения
1. Прочитай лог и покажи результат
2. Если `-UpdateDB` не был указан — **предложи выполнить `/db-update`** для применения изменений к БД
## Примеры
```powershell
# Полная загрузка
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full
# Частичная загрузка конкретных файлов
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Partial -Files "Catalogs/Номенклатура.xml,Catalogs/Номенклатура/Ext/ObjectModule.bsl"
# Загрузка расширения
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\ext_src" -Mode Full -Extension "МоёРасширение"
# Загрузка + обновление БД в одном запуске
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full -UpdateDB
```
---
name: db-load-xml
description: Загрузка конфигурации 1С из XML-файлов. Используй когда нужно загрузить конфигурацию из файлов, XML, исходников, LoadConfigFromFiles
argument-hint: <configDir> [database]
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-load-xml — Загрузка конфигурации из XML
Загружает конфигурацию в информационную базу из XML-файлов (исходников). Поддерживает полную и частичную загрузку.
## Usage
```
/db-load-xml <configDir> [database]
/db-load-xml src/config dev
/db-load-xml src/config dev -Mode Partial -Files "Catalogs/Номенклатура.xml,Catalogs/Номенклатура/Ext/ObjectModule.bsl"
```
> **Внимание**: полная загрузка **заменяет всю конфигурацию** в базе. Перед выполнением запроси подтверждение у пользователя.
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
Если в записи базы указан `configSrc` — используй как каталог загрузки по умолчанию.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-ConfigDir <путь>` | да | Каталог XML-исходников |
| `-Mode <режим>` | нет | `Full` (по умолч.) / `Partial` |
| `-Files <список>` | для Partial | Относительные пути файлов через запятую |
| `-ListFile <путь>` | для Partial | Путь к файлу со списком (альтернатива `-Files`) |
| `-Extension <имя>` | нет | Загрузить в расширение |
| `-AllExtensions` | нет | Загрузить все расширения |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
| `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
### Режимы загрузки
| Режим | Описание |
|-------|----------|
| `Full` | Полная загрузка — замена всей конфигурации из каталога XML |
| `Partial` | Частичная — загрузка выбранных файлов (с `-partial -updateConfigDumpInfo`) |
### Формат файла списка (listFile)
Файл содержит **относительные пути к файлам** в каталоге выгрузки (один на строку), кодировка **UTF-8 с BOM**:
```
Catalogs/Номенклатура.xml
Catalogs/Номенклатура/Ext/ObjectModule.bsl
Documents/Заказ.xml
Documents/Заказ/Forms/ФормаДокумента.xml
```
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## После выполнения
1. Прочитай лог и покажи результат
2. Если `-UpdateDB` не был указан — **предложи выполнить `/db-update`** для применения изменений к БД
## Примеры
```powershell
# Полная загрузка
python "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.py" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full
# Частичная загрузка конкретных файлов
python "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Partial -Files "Catalogs/Номенклатура.xml,Catalogs/Номенклатура/Ext/ObjectModule.bsl"
# Загрузка расширения
python "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\ext_src" -Mode Full -Extension "МоёРасширение"
# Загрузка + обновление БД в одном запуске
python "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full -UpdateDB
```
+76 -76
View File
@@ -1,76 +1,76 @@
---
name: db-run
description: Запуск 1С:Предприятие. Используй когда нужно запустить 1С, открыть базу, запустить предприятие
argument-hint: "[database]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-run — Запуск 1С:Предприятие
Запускает информационную базу в режиме 1С:Предприятие (пользовательский режим).
## Usage
```
/db-run [database]
/db-run dev
/db-run dev /Execute process.epf
/db-run dev /C "параметр запуска"
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-Execute <файл.epf>` | нет | Запуск внешней обработки сразу после старта |
| `-CParam <строка>` | нет | Параметр запуска (/C) |
| `-URL <ссылка>` | нет | Навигационная ссылка (формат `e1cib/...`) |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Важно
Скрипт запускает 1С в фоне (`Start-Process` без `-Wait`) — управление возвращается сразу.
## Примеры
```powershell
# Простой запуск
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
# Запуск с обработкой
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -Execute "C:\epf\МояОбработка.epf"
# Открыть по навигационной ссылке
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -URL "e1cib/data/Справочник.Номенклатура"
# Серверная база с параметром запуска
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -CParam "ЗапуститьОбновление"
```
---
name: db-run
description: Запуск 1С:Предприятие. Используй когда нужно запустить 1С, открыть базу, запустить предприятие
argument-hint: "[database]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-run — Запуск 1С:Предприятие
Запускает информационную базу в режиме 1С:Предприятие (пользовательский режим).
## Usage
```
/db-run [database]
/db-run dev
/db-run dev /Execute process.epf
/db-run dev /C "параметр запуска"
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/db-run.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-Execute <файл.epf>` | нет | Запуск внешней обработки сразу после старта |
| `-CParam <строка>` | нет | Параметр запуска (/C) |
| `-URL <ссылка>` | нет | Навигационная ссылка (формат `e1cib/...`) |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Важно
Скрипт запускает 1С в фоне (`Start-Process` без `-Wait`) — управление возвращается сразу.
## Примеры
```powershell
# Простой запуск
python "${CLAUDE_SKILL_DIR}/scripts/db-run.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
# Запуск с обработкой
python "${CLAUDE_SKILL_DIR}/scripts/db-run.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -Execute "C:\epf\МояОбработка.epf"
# Открыть по навигационной ссылке
python "${CLAUDE_SKILL_DIR}/scripts/db-run.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -URL "e1cib/data/Справочник.Номенклатура"
# Серверная база с параметром запуска
python "${CLAUDE_SKILL_DIR}/scripts/db-run.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -CParam "ЗапуститьОбновление"
```
+93 -93
View File
@@ -1,93 +1,93 @@
---
name: db-update
description: Обновление конфигурации базы данных 1С. Используй когда нужно обновить БД, применить конфигурацию, UpdateDBCfg
argument-hint: "[database]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-update — Обновление конфигурации БД
Применяет изменения основной конфигурации к конфигурации базы данных (`/UpdateDBCfg`). Обязательный шаг после `/db-load-cf`, `/db-load-xml`, `/db-load-git`.
## Usage
```
/db-update [database]
/db-update dev
/db-update dev -Dynamic+
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-Extension <имя>` | нет | Обновить расширение |
| `-AllExtensions` | нет | Обновить все расширения |
| `-Dynamic <+/->` | нет | `+` — динамическое обновление, `-` — отключить |
| `-Server` | нет | Обновление на стороне сервера |
| `-WarningsAsErrors` | нет | Предупреждения считать ошибками |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
### Фоновое обновление (серверная база)
| Параметр | Описание |
|----------|----------|
| `-BackgroundStart` | Начать фоновое обновление |
| `-BackgroundFinish` | Дождаться окончания |
| `-BackgroundCancel` | Отменить |
| `-BackgroundSuspend` | Приостановить |
| `-BackgroundResume` | Возобновить |
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## Предупреждения
- Если обновление **не динамическое** — потребуется **монопольный доступ** к базе (все пользователи должны выйти)
- Для серверных баз рекомендуется `-Dynamic+` для обновления без остановки
- Если структура данных существенно изменилась (удаление реквизитов, изменение типов) — динамическое обновление может быть невозможно
## Примеры
```powershell
# Обычное обновление (файловая база)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
# Динамическое обновление (серверная база)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -Dynamic "+"
# Обновление расширения
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -Extension "МоёРасширение"
```
---
name: db-update
description: Обновление конфигурации базы данных 1С. Используй когда нужно обновить БД, применить конфигурацию, UpdateDBCfg
argument-hint: "[database]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /db-update — Обновление конфигурации БД
Применяет изменения основной конфигурации к конфигурации базы данных (`/UpdateDBCfg`). Обязательный шаг после `/db-load-cf`, `/db-load-xml`, `/db-load-git`.
## Usage
```
/db-update [database]
/db-update dev
/db-update dev -Dynamic+
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если файла нет — предложи `/db-list add`.
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/db-update.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-Extension <имя>` | нет | Обновить расширение |
| `-AllExtensions` | нет | Обновить все расширения |
| `-Dynamic <+/->` | нет | `+` — динамическое обновление, `-` — отключить |
| `-Server` | нет | Обновление на стороне сервера |
| `-WarningsAsErrors` | нет | Предупреждения считать ошибками |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
### Фоновое обновление (серверная база)
| Параметр | Описание |
|----------|----------|
| `-BackgroundStart` | Начать фоновое обновление |
| `-BackgroundFinish` | Дождаться окончания |
| `-BackgroundCancel` | Отменить |
| `-BackgroundSuspend` | Приостановить |
| `-BackgroundResume` | Возобновить |
## Коды возврата
| Код | Описание |
|-----|----------|
| 0 | Успешно |
| 1 | Ошибка (см. лог) |
## Предупреждения
- Если обновление **не динамическое** — потребуется **монопольный доступ** к базе (все пользователи должны выйти)
- Для серверных баз рекомендуется `-Dynamic+` для обновления без остановки
- Если структура данных существенно изменилась (удаление реквизитов, изменение типов) — динамическое обновление может быть невозможно
## Примеры
```powershell
# Обычное обновление (файловая база)
python "${CLAUDE_SKILL_DIR}/scripts/db-update.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
# Динамическое обновление (серверная база)
python "${CLAUDE_SKILL_DIR}/scripts/db-update.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -Dynamic "+"
# Обновление расширения
python "${CLAUDE_SKILL_DIR}/scripts/db-update.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -Extension "МоёРасширение"
```
+69 -69
View File
@@ -1,69 +1,69 @@
---
name: epf-build
description: Собрать внешнюю обработку 1С (EPF/ERF) из XML-исходников. Используй когда пользователь просит собрать, скомпилировать обработку или получить EPF/ERF файл из исходников
argument-hint: <ProcessorName>
allowed-tools:
- Bash
- Read
- Glob
- Grep
---
# /epf-build — Сборка обработки
## Usage
```
/epf-build <ProcessorName> [SrcDir] [OutDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|---------------|:------------:|--------------|--------------------------------------|
| ProcessorName | да | — | Имя обработки (имя корневого XML) |
| SrcDir | нет | `src` | Каталог исходников |
| OutDir | нет | `build` | Каталог для результата |
## Параметры подключения (опционально)
Предпочтительно использовать конкретную базу — это надёжнее и не требует создания временной базы.
1. Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` и разреши базу:
2. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
3. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
4. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
5. Если ветка не совпала — используй `default`
6. Если `.v8-project.json` нет или база не найдена — не указывай параметры подключения: скрипт автоматически создаст временную базу. Для EPF со ссылочными типами (CatalogRef, DocumentRef и т.д.) генерируются заглушки метаданных. Временная база удаляется после сборки.
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-SourceFile <путь>` | да | Путь к корневому XML-файлу исходников |
| `-OutputFile <путь>` | да | Путь к выходному EPF/ERF-файлу |
> `*` — опционально. Если не указано — автоматически создаётся временная база со заглушками метаданных
## Примеры
```powershell
# Сборка обработки (файловая база)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" -InfoBasePath "C:\Bases\MyDB" -SourceFile "src/МояОбработка.xml" -OutputFile "build/МояОбработка.epf"
# Серверная база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -SourceFile "src/МояОбработка.xml" -OutputFile "build/МояОбработка.epf"
```
---
name: epf-build
description: Собрать внешнюю обработку 1С (EPF/ERF) из XML-исходников. Используй когда пользователь просит собрать, скомпилировать обработку или получить EPF/ERF файл из исходников
argument-hint: <ProcessorName>
allowed-tools:
- Bash
- Read
- Glob
- Grep
---
# /epf-build — Сборка обработки
## Usage
```
/epf-build <ProcessorName> [SrcDir] [OutDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|---------------|:------------:|--------------|--------------------------------------|
| ProcessorName | да | — | Имя обработки (имя корневого XML) |
| SrcDir | нет | `src` | Каталог исходников |
| OutDir | нет | `build` | Каталог для результата |
## Параметры подключения (опционально)
Предпочтительно использовать конкретную базу — это надёжнее и не требует создания временной базы.
1. Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` и разреши базу:
2. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
3. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
4. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
5. Если ветка не совпала — используй `default`
6. Если `.v8-project.json` нет или база не найдена — не указывай параметры подключения: скрипт автоматически создаст временную базу. Для EPF со ссылочными типами (CatalogRef, DocumentRef и т.д.) генерируются заглушки метаданных. Временная база удаляется после сборки.
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/epf-build.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-SourceFile <путь>` | да | Путь к корневому XML-файлу исходников |
| `-OutputFile <путь>` | да | Путь к выходному EPF/ERF-файлу |
> `*` — опционально. Если не указано — автоматически создаётся временная база со заглушками метаданных
## Примеры
```powershell
# Сборка обработки (файловая база)
python "${CLAUDE_SKILL_DIR}/scripts/epf-build.py" -InfoBasePath "C:\Bases\MyDB" -SourceFile "src/МояОбработка.xml" -OutputFile "build/МояОбработка.epf"
# Серверная база
python "${CLAUDE_SKILL_DIR}/scripts/epf-build.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -SourceFile "src/МояОбработка.xml" -OutputFile "build/МояОбработка.epf"
```
+69 -69
View File
@@ -1,69 +1,69 @@
---
name: epf-dump
description: Разобрать EPF-файл обработки 1С (EPF/ERF) в XML-исходники. Используй когда пользователь просит разобрать, декомпилировать обработку, получить исходники из EPF/ERF файла
argument-hint: <EpfFile>
allowed-tools:
- Bash
- Read
- Glob
- Grep
---
# /epf-dump — Разборка обработки
## Usage
```
/epf-dump <EpfFile> [OutDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|----------|:------------:|--------------|-------------------------------------|
| EpfFile | да | — | Путь к EPF-файлу |
| OutDir | нет | `src` | Каталог для выгрузки исходников |
## Параметры подключения (обязательно)
Для разборки EPF/ERF требуется информационная база с конфигурацией. Без базы ссылочные типы безвозвратно теряются.
1. Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` и разреши базу:
2. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
3. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
4. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
5. Если ветка не совпала — используй `default`
6. Если `.v8-project.json` нет или база не найдена — **сообщи пользователю об ошибке**. Для dump база обязательна: в пустой базе ссылочные типы (CatalogRef, DocumentRef и т.д.) безвозвратно сбрасываются в строки. Предложи указать базу или зарегистрировать через `/db-list add`.
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-InputFile <путь>` | да | Путь к EPF/ERF-файлу |
| `-OutputDir <путь>` | да | Каталог для выгрузки исходников |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
> `*` — обязательно хотя бы одно подключение. Без базы скрипт завершится с ошибкой (dump в пустой базе безвозвратно теряет ссылочные типы)
## Примеры
```powershell
# Разборка обработки (файловая база)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" -InfoBasePath "C:\Bases\MyDB" -InputFile "build/МояОбработка.epf" -OutputDir "src"
# Серверная база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -InputFile "build/МояОбработка.epf" -OutputDir "src"
```
---
name: epf-dump
description: Разобрать EPF-файл обработки 1С (EPF/ERF) в XML-исходники. Используй когда пользователь просит разобрать, декомпилировать обработку, получить исходники из EPF/ERF файла
argument-hint: <EpfFile>
allowed-tools:
- Bash
- Read
- Glob
- Grep
---
# /epf-dump — Разборка обработки
## Usage
```
/epf-dump <EpfFile> [OutDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|----------|:------------:|--------------|-------------------------------------|
| EpfFile | да | — | Путь к EPF-файлу |
| OutDir | нет | `src` | Каталог для выгрузки исходников |
## Параметры подключения (обязательно)
Для разборки EPF/ERF требуется информационная база с конфигурацией. Без базы ссылочные типы безвозвратно теряются.
1. Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` и разреши базу:
2. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
3. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
4. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
5. Если ветка не совпала — используй `default`
6. Если `.v8-project.json` нет или база не найдена — **сообщи пользователю об ошибке**. Для dump база обязательна: в пустой базе ссылочные типы (CatalogRef, DocumentRef и т.д.) безвозвратно сбрасываются в строки. Предложи указать базу или зарегистрировать через `/db-list add`.
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/epf-dump.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-InputFile <путь>` | да | Путь к EPF/ERF-файлу |
| `-OutputDir <путь>` | да | Каталог для выгрузки исходников |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
> `*` — обязательно хотя бы одно подключение. Без базы скрипт завершится с ошибкой (dump в пустой базе безвозвратно теряет ссылочные типы)
## Примеры
```powershell
# Разборка обработки (файловая база)
python "${CLAUDE_SKILL_DIR}/scripts/epf-dump.py" -InfoBasePath "C:\Bases\MyDB" -InputFile "build/МояОбработка.epf" -OutputDir "src"
# Серверная база
python "${CLAUDE_SKILL_DIR}/scripts/epf-dump.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -InputFile "build/МояОбработка.epf" -OutputDir "src"
```
+41 -41
View File
@@ -1,41 +1,41 @@
---
name: epf-init
description: Создать пустую внешнюю обработку 1С (scaffold XML-исходников). Используй когда нужно создать новую внешнюю обработку с нуля
argument-hint: <Name> [Synonym]
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /epf-init — Создание новой обработки
Генерирует минимальный набор XML-исходников для внешней обработки 1С: корневой файл метаданных и каталог обработки.
## Usage
```
/epf-init <Name> [Synonym] [SrcDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|-----------|:------------:|--------------|-------------------------------------|
| Name | да | — | Имя обработки (латиница/кириллица) |
| Synonym | нет | = Name | Синоним (отображаемое имя) |
| SrcDir | нет | `src` | Каталог исходников относительно CWD |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/init.ps1" -Name "<Name>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"]
```
## Дальнейшие шаги
- Добавить форму: `/form-add`
- Добавить макет: `/template-add`
- Добавить справку: `/help-add`
- Собрать EPF: `/epf-build`
---
name: epf-init
description: Создать пустую внешнюю обработку 1С (scaffold XML-исходников). Используй когда нужно создать новую внешнюю обработку с нуля
argument-hint: <Name> [Synonym]
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /epf-init — Создание новой обработки
Генерирует минимальный набор XML-исходников для внешней обработки 1С: корневой файл метаданных и каталог обработки.
## Usage
```
/epf-init <Name> [Synonym] [SrcDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|-----------|:------------:|--------------|-------------------------------------|
| Name | да | — | Имя обработки (латиница/кириллица) |
| Synonym | нет | = Name | Синоним (отображаемое имя) |
| SrcDir | нет | `src` | Каталог исходников относительно CWD |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/init.py" -Name "<Name>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"]
```
## Дальнейшие шаги
- Добавить форму: `/form-add`
- Добавить макет: `/template-add`
- Добавить справку: `/help-add`
- Собрать EPF: `/epf-build`
+30 -30
View File
@@ -1,30 +1,30 @@
---
name: epf-validate
description: Валидация внешней обработки 1С (EPF). Используй после создания или модификации обработки для проверки корректности
argument-hint: <ObjectPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /epf-validate — валидация внешней обработки (EPF)
Проверяет структурную корректность XML-исходников внешней обработки: корневую структуру, InternalInfo, свойства, ChildObjects, реквизиты, табличные части, уникальность имён, наличие файлов форм и макетов. Также работает для внешних отчётов (ERF).
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|------------|:-----:|---------|-------------------------------------------------|
| ObjectPath | да | — | Путь к корневому XML или каталогу обработки |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-validate.ps1" -ObjectPath "src/МояОбработка"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-validate.ps1" -ObjectPath "src/МояОбработка/МояОбработка.xml"
```
---
name: epf-validate
description: Валидация внешней обработки 1С (EPF). Используй после создания или модификации обработки для проверки корректности
argument-hint: <ObjectPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /epf-validate — валидация внешней обработки (EPF)
Проверяет структурную корректность XML-исходников внешней обработки: корневую структуру, InternalInfo, свойства, ChildObjects, реквизиты, табличные части, уникальность имён, наличие файлов форм и макетов. Также работает для внешних отчётов (ERF).
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|------------|:-----:|---------|-------------------------------------------------|
| ObjectPath | да | — | Путь к корневому XML или каталогу обработки |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/epf-validate.py" -ObjectPath "src/МояОбработка"
python "${CLAUDE_SKILL_DIR}/scripts/epf-validate.py" -ObjectPath "src/МояОбработка/МояОбработка.xml"
```
+71 -71
View File
@@ -1,71 +1,71 @@
---
name: erf-build
description: Собрать внешний отчёт 1С (ERF) из XML-исходников. Используй когда пользователь просит собрать, скомпилировать отчёт или получить ERF файл из исходников
argument-hint: <ReportName>
allowed-tools:
- Bash
- Read
- Glob
- Grep
---
# /erf-build — Сборка отчёта
## Usage
```
/erf-build <ReportName> [SrcDir] [OutDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|------------|:------------:|--------------|--------------------------------------|
| ReportName | да | — | Имя отчёта (имя корневого XML) |
| SrcDir | нет | `src` | Каталог исходников |
| OutDir | нет | `build` | Каталог для результата |
## Параметры подключения (опционально)
Предпочтительно использовать конкретную базу — это надёжнее и не требует создания временной базы.
1. Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` и разреши базу:
2. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
3. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
4. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
5. Если ветка не совпала — используй `default`
6. Если `.v8-project.json` нет или база не найдена — не указывай параметры подключения: скрипт автоматически создаст временную базу. Для ERF со ссылочными типами (CatalogRef, DocumentRef и т.д.) генерируются заглушки метаданных. Временная база удаляется после сборки.
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
Используй общий скрипт из epf-build:
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-SourceFile <путь>` | да | Путь к корневому XML-файлу исходников |
| `-OutputFile <путь>` | да | Путь к выходному ERF-файлу |
> `*` — опционально. Если не указано — автоматически создаётся временная база со заглушками метаданных
## Примеры
```powershell
# Сборка отчёта (файловая база)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.ps1" -InfoBasePath "C:\Bases\MyDB" -SourceFile "src/МойОтчёт.xml" -OutputFile "build/МойОтчёт.erf"
# Серверная база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -SourceFile "src/МойОтчёт.xml" -OutputFile "build/МойОтчёт.erf"
```
---
name: erf-build
description: Собрать внешний отчёт 1С (ERF) из XML-исходников. Используй когда пользователь просит собрать, скомпилировать отчёт или получить ERF файл из исходников
argument-hint: <ReportName>
allowed-tools:
- Bash
- Read
- Glob
- Grep
---
# /erf-build — Сборка отчёта
## Usage
```
/erf-build <ReportName> [SrcDir] [OutDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|------------|:------------:|--------------|--------------------------------------|
| ReportName | да | — | Имя отчёта (имя корневого XML) |
| SrcDir | нет | `src` | Каталог исходников |
| OutDir | нет | `build` | Каталог для результата |
## Параметры подключения (опционально)
Предпочтительно использовать конкретную базу — это надёжнее и не требует создания временной базы.
1. Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` и разреши базу:
2. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
3. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
4. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
5. Если ветка не совпала — используй `default`
6. Если `.v8-project.json` нет или база не найдена — не указывай параметры подключения: скрипт автоматически создаст временную базу. Для ERF со ссылочными типами (CatalogRef, DocumentRef и т.д.) генерируются заглушки метаданных. Временная база удаляется после сборки.
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
Используй общий скрипт из epf-build:
```powershell
python "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-SourceFile <путь>` | да | Путь к корневому XML-файлу исходников |
| `-OutputFile <путь>` | да | Путь к выходному ERF-файлу |
> `*` — опционально. Если не указано — автоматически создаётся временная база со заглушками метаданных
## Примеры
```powershell
# Сборка отчёта (файловая база)
python "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.py" -InfoBasePath "C:\Bases\MyDB" -SourceFile "src/МойОтчёт.xml" -OutputFile "build/МойОтчёт.erf"
# Серверная база
python "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -SourceFile "src/МойОтчёт.xml" -OutputFile "build/МойОтчёт.erf"
```
+71 -71
View File
@@ -1,71 +1,71 @@
---
name: erf-dump
description: Разобрать ERF-файл отчёта 1С в XML-исходники. Используй когда пользователь просит разобрать, декомпилировать отчёт, получить исходники из ERF файла
argument-hint: <ErfFile>
allowed-tools:
- Bash
- Read
- Glob
- Grep
---
# /erf-dump — Разборка отчёта
## Usage
```
/erf-dump <ErfFile> [OutDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|----------|:------------:|--------------|-------------------------------------|
| ErfFile | да | — | Путь к ERF-файлу |
| OutDir | нет | `src` | Каталог для выгрузки исходников |
## Параметры подключения (обязательно)
Для разборки EPF/ERF требуется информационная база с конфигурацией. Без базы ссылочные типы безвозвратно теряются.
1. Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` и разреши базу:
2. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
3. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
4. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
5. Если ветка не совпала — используй `default`
6. Если `.v8-project.json` нет или база не найдена — **сообщи пользователю об ошибке**. Для dump база обязательна: в пустой базе ссылочные типы (CatalogRef, DocumentRef и т.д.) безвозвратно сбрасываются в строки. Предложи указать базу или зарегистрировать через `/db-list add`.
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
Используй общий скрипт из epf-dump:
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-InputFile <путь>` | да | Путь к ERF-файлу |
| `-OutputDir <путь>` | да | Каталог для выгрузки исходников |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
> `*` — обязательно хотя бы одно подключение. Без базы скрипт завершится с ошибкой (dump в пустой базе безвозвратно теряет ссылочные типы)
## Примеры
```powershell
# Разборка отчёта (файловая база)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.ps1" -InfoBasePath "C:\Bases\MyDB" -InputFile "build/МойОтчёт.erf" -OutputDir "src"
# Серверная база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -InputFile "build/МойОтчёт.erf" -OutputDir "src"
```
---
name: erf-dump
description: Разобрать ERF-файл отчёта 1С в XML-исходники. Используй когда пользователь просит разобрать, декомпилировать отчёт, получить исходники из ERF файла
argument-hint: <ErfFile>
allowed-tools:
- Bash
- Read
- Glob
- Grep
---
# /erf-dump — Разборка отчёта
## Usage
```
/erf-dump <ErfFile> [OutDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|----------|:------------:|--------------|-------------------------------------|
| ErfFile | да | — | Путь к ERF-файлу |
| OutDir | нет | `src` | Каталог для выгрузки исходников |
## Параметры подключения (обязательно)
Для разборки EPF/ERF требуется информационная база с конфигурацией. Без базы ссылочные типы безвозвратно теряются.
1. Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` и разреши базу:
2. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
3. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
4. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
5. Если ветка не совпала — используй `default`
6. Если `.v8-project.json` нет или база не найдена — **сообщи пользователю об ошибке**. Для dump база обязательна: в пустой базе ссылочные типы (CatalogRef, DocumentRef и т.д.) безвозвратно сбрасываются в строки. Предложи указать базу или зарегистрировать через `/db-list add`.
Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1`
Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`.
## Команда
Используй общий скрипт из epf-dump:
```powershell
python "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-InputFile <путь>` | да | Путь к ERF-файлу |
| `-OutputDir <путь>` | да | Каталог для выгрузки исходников |
| `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` |
> `*` — обязательно хотя бы одно подключение. Без базы скрипт завершится с ошибкой (dump в пустой базе безвозвратно теряет ссылочные типы)
## Примеры
```powershell
# Разборка отчёта (файловая база)
python "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.py" -InfoBasePath "C:\Bases\MyDB" -InputFile "build/МойОтчёт.erf" -OutputDir "src"
# Серверная база
python "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -InputFile "build/МойОтчёт.erf" -OutputDir "src"
```
+42 -42
View File
@@ -1,42 +1,42 @@
---
name: erf-init
description: Создать пустой внешний отчёт 1С (scaffold XML-исходников). Используй когда нужно создать новый внешний отчёт с нуля
argument-hint: <Name> [Synonym] [--with-skd]
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /erf-init — Создание нового отчёта
Генерирует минимальный набор XML-исходников для внешнего отчёта 1С: корневой файл метаданных и каталог отчёта.
## Usage
```
/erf-init <Name> [Synonym] [SrcDir] [--with-skd]
```
| Параметр | Обязательный | По умолчанию | Описание |
|-----------|:------------:|--------------|---------------------------------------|
| Name | да | — | Имя отчёта (латиница/кириллица) |
| Synonym | нет | = Name | Синоним (отображаемое имя) |
| SrcDir | нет | `src` | Каталог исходников относительно CWD |
| --WithSKD | нет | — | Создать пустую СКД и привязать к MainDataCompositionSchema |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/init.ps1" -Name "<Name>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"] [-WithSKD]
```
## Дальнейшие шаги
- Добавить форму: `/form-add`
- Добавить макет: `/template-add`
- Добавить справку: `/help-add`
- Собрать ERF: `/erf-build`
---
name: erf-init
description: Создать пустой внешний отчёт 1С (scaffold XML-исходников). Используй когда нужно создать новый внешний отчёт с нуля
argument-hint: <Name> [Synonym] [--with-skd]
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /erf-init — Создание нового отчёта
Генерирует минимальный набор XML-исходников для внешнего отчёта 1С: корневой файл метаданных и каталог отчёта.
## Usage
```
/erf-init <Name> [Synonym] [SrcDir] [--with-skd]
```
| Параметр | Обязательный | По умолчанию | Описание |
|-----------|:------------:|--------------|---------------------------------------|
| Name | да | — | Имя отчёта (латиница/кириллица) |
| Synonym | нет | = Name | Синоним (отображаемое имя) |
| SrcDir | нет | `src` | Каталог исходников относительно CWD |
| --WithSKD | нет | — | Создать пустую СКД и привязать к MainDataCompositionSchema |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/init.py" -Name "<Name>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"] [-WithSKD]
```
## Дальнейшие шаги
- Добавить форму: `/form-add`
- Добавить макет: `/template-add`
- Добавить справку: `/help-add`
- Собрать ERF: `/erf-build`
+32 -32
View File
@@ -1,32 +1,32 @@
---
name: erf-validate
description: Валидация внешнего отчёта 1С (ERF). Используй после создания или модификации отчёта для проверки корректности
argument-hint: <ObjectPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /erf-validate — валидация внешнего отчёта (ERF)
Проверяет структурную корректность XML-исходников внешнего отчёта: корневую структуру, InternalInfo, свойства (включая MainDataCompositionSchema), ChildObjects, реквизиты, табличные части, уникальность имён, наличие файлов форм и макетов.
Использует тот же скрипт, что и `/epf-validate` — автоопределение по типу элемента (ExternalReport).
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|------------|:-----:|---------|-------------------------------------------------|
| ObjectPath | да | — | Путь к корневому XML или каталогу отчёта |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-validate/scripts/epf-validate.ps1" -ObjectPath "src/МойОтчёт"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-validate/scripts/epf-validate.ps1" -ObjectPath "src/МойОтчёт/МойОтчёт.xml"
```
---
name: erf-validate
description: Валидация внешнего отчёта 1С (ERF). Используй после создания или модификации отчёта для проверки корректности
argument-hint: <ObjectPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /erf-validate — валидация внешнего отчёта (ERF)
Проверяет структурную корректность XML-исходников внешнего отчёта: корневую структуру, InternalInfo, свойства (включая MainDataCompositionSchema), ChildObjects, реквизиты, табличные части, уникальность имён, наличие файлов форм и макетов.
Использует тот же скрипт, что и `/epf-validate` — автоопределение по типу элемента (ExternalReport).
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|------------|:-----:|---------|-------------------------------------------------|
| ObjectPath | да | — | Путь к корневому XML или каталогу отчёта |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/../epf-validate/scripts/epf-validate.py" -ObjectPath "src/МойОтчёт"
python "${CLAUDE_SKILL_DIR}/../epf-validate/scripts/epf-validate.py" -ObjectPath "src/МойОтчёт/МойОтчёт.xml"
```
+71 -71
View File
@@ -1,71 +1,71 @@
---
name: form-add
description: Добавить пустую управляемую форму к объекту 1С. Используй когда нужно создать у объекта новую форму
argument-hint: <ObjectPath> <FormName> [Purpose] [--set-default]
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /form-add — Добавление формы к объекту конфигурации
Создаёт управляемую форму (metadata XML + Form.xml + Module.bsl) и регистрирует её в корневом XML объекта конфигурации (Document, Catalog, InformationRegister и др.).
## Usage
```
/form-add <ObjectPath> <FormName> [Purpose] [Synonym] [--set-default]
```
| Параметр | Обязательный | По умолчанию | Описание |
|-------------|:------------:|--------------|----------------------------------------------|
| ObjectPath | да | — | Путь к XML-файлу объекта (Documents/Док.xml) |
| FormName | да | — | Имя формы (ФормаДокумента) |
| Purpose | нет | Object | Назначение: Object, List, Choice, Record |
| Synonym | нет | = FormName | Синоним формы |
| --set-default | нет | авто | Установить как форму по умолчанию |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/form-add.ps1" -ObjectPath "<ObjectPath>" -FormName "<FormName>" [-Purpose "<Purpose>"] [-Synonym "<Synonym>"] [-SetDefault]
```
## Purpose — назначение формы
| Purpose | Допустимые типы объектов | Основной реквизит | DefaultForm-свойство |
|---------|-------------------------|-------------------|---------------------|
| Object | Document, Catalog, DataProcessor, Report, ExternalDataProcessor, ExternalReport, ChartOf*, ExchangePlan, BusinessProcess, Task | Объект (тип: *Object.Имя) | DefaultObjectForm (DefaultForm для DataProcessor/Report/ExternalDataProcessor/ExternalReport) |
| List | Все кроме DataProcessor | Список (DynamicList) | DefaultListForm |
| Choice | Document, Catalog, ChartOf*, ExchangePlan, BusinessProcess, Task | Список (DynamicList) | DefaultChoiceForm |
| Record | InformationRegister | Запись (InformationRegisterRecordManager) | DefaultRecordForm |
## Примеры
```
# Форма документа
/form-add Documents/АвансовыйОтчет.xml ФормаДокумента --purpose Object
# Форма списка каталога
/form-add Catalogs/Контрагенты.xml ФормаСписка --purpose List
# Форма записи регистра сведений
/form-add InformationRegisters/КурсыВалют.xml ФормаЗаписи --purpose Record
# Форма выбора с синонимом
/form-add Catalogs/Номенклатура.xml ФормаВыбора --purpose Choice --synonym "Выбор номенклатуры"
# Установить как форму по умолчанию
/form-add Documents/Заказ.xml ФормаДокументаНовая --purpose Object --set-default
```
## Workflow
1. `/form-add` — создать каркас формы
2. `/form-compile` или `/form-edit` — наполнить Form.xml элементами
3. `/form-validate` — проверить корректность
4. `/form-info` — проанализировать результат
---
name: form-add
description: Добавить пустую управляемую форму к объекту 1С. Используй когда нужно создать у объекта новую форму
argument-hint: <ObjectPath> <FormName> [Purpose] [--set-default]
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /form-add — Добавление формы к объекту конфигурации
Создаёт управляемую форму (metadata XML + Form.xml + Module.bsl) и регистрирует её в корневом XML объекта конфигурации (Document, Catalog, InformationRegister и др.).
## Usage
```
/form-add <ObjectPath> <FormName> [Purpose] [Synonym] [--set-default]
```
| Параметр | Обязательный | По умолчанию | Описание |
|-------------|:------------:|--------------|----------------------------------------------|
| ObjectPath | да | — | Путь к XML-файлу объекта (Documents/Док.xml) |
| FormName | да | — | Имя формы (ФормаДокумента) |
| Purpose | нет | Object | Назначение: Object, List, Choice, Record |
| Synonym | нет | = FormName | Синоним формы |
| --set-default | нет | авто | Установить как форму по умолчанию |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/form-add.py" -ObjectPath "<ObjectPath>" -FormName "<FormName>" [-Purpose "<Purpose>"] [-Synonym "<Synonym>"] [-SetDefault]
```
## Purpose — назначение формы
| Purpose | Допустимые типы объектов | Основной реквизит | DefaultForm-свойство |
|---------|-------------------------|-------------------|---------------------|
| Object | Document, Catalog, DataProcessor, Report, ExternalDataProcessor, ExternalReport, ChartOf*, ExchangePlan, BusinessProcess, Task | Объект (тип: *Object.Имя) | DefaultObjectForm (DefaultForm для DataProcessor/Report/ExternalDataProcessor/ExternalReport) |
| List | Все кроме DataProcessor | Список (DynamicList) | DefaultListForm |
| Choice | Document, Catalog, ChartOf*, ExchangePlan, BusinessProcess, Task | Список (DynamicList) | DefaultChoiceForm |
| Record | InformationRegister | Запись (InformationRegisterRecordManager) | DefaultRecordForm |
## Примеры
```
# Форма документа
/form-add Documents/АвансовыйОтчет.xml ФормаДокумента --purpose Object
# Форма списка каталога
/form-add Catalogs/Контрагенты.xml ФормаСписка --purpose List
# Форма записи регистра сведений
/form-add InformationRegisters/КурсыВалют.xml ФормаЗаписи --purpose Record
# Форма выбора с синонимом
/form-add Catalogs/Номенклатура.xml ФормаВыбора --purpose Choice --synonym "Выбор номенклатуры"
# Установить как форму по умолчанию
/form-add Documents/Заказ.xml ФормаДокументаНовая --purpose Object --set-default
```
## Workflow
1. `/form-add` — создать каркас формы
2. `/form-compile` или `/form-edit` — наполнить Form.xml элементами
3. `/form-validate` — проверить корректность
4. `/form-info` — проанализировать результат
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
# form-compile v1.21 — Compile 1C managed form from JSON or object metadata
# form-compile v1.23 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$JsonPath,
@@ -1929,7 +1929,7 @@ function Emit-Element {
# button-specific
"type"=1;"command"=1;"stdCommand"=1;"defaultButton"=1;"locationInCommandBar"=1
# picture/decoration
"src"=1
"src"=1;"valuesPicture"=1;"loadTransparent"=1
# cmdBar-specific
"autofill"=1
}
@@ -2134,6 +2134,7 @@ function Emit-Input {
if ($el.multiLine -eq $true) { X "$inner<MultiLine>true</MultiLine>" }
if ($el.passwordMode -eq $true) { X "$inner<PasswordMode>true</PasswordMode>" }
if ($el.choiceButton -eq $false) { X "$inner<ChoiceButton>false</ChoiceButton>" }
elseif ($el.choiceButton -eq $true -and ($el.on -contains 'StartChoice')) { X "$inner<ChoiceButton>true</ChoiceButton>" }
if ($el.clearButton -eq $true) { X "$inner<ClearButton>true</ClearButton>" }
if ($el.spinButton -eq $true) { X "$inner<SpinButton>true</SpinButton>" }
if ($el.dropListButton -eq $true) { X "$inner<DropListButton>true</DropListButton>" }
@@ -2722,6 +2723,16 @@ function Emit-PictureField {
Emit-Title -el $el -name $name -indent $inner
Emit-CommonFlags -el $el -indent $inner
# ValuesPicture — picture (collection) used to render the field's value.
# Required for a Boolean-bound PictureField to actually show an icon.
# loadTransparent emitted only when true (1С default is false).
if ($el.valuesPicture) {
X "$inner<ValuesPicture>"
X "$inner`t<xr:Ref>$($el.valuesPicture)</xr:Ref>"
if ($el.loadTransparent) { X "$inner`t<xr:LoadTransparent>true</xr:LoadTransparent>" }
X "$inner</ValuesPicture>"
}
if ($el.width) { X "$inner<Width>$($el.width)</Width>" }
if ($el.height) { X "$inner<Height>$($el.height)</Height>" }
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# form-compile v1.21 — Compile 1C managed form from JSON or object metadata
# form-compile v1.23 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -1358,7 +1358,7 @@ KNOWN_KEYS = {
"commandBarLocation", "searchStringLocation",
"pagesRepresentation",
"type", "command", "stdCommand", "defaultButton", "locationInCommandBar",
"src",
"src", "valuesPicture", "loadTransparent",
"autofill",
"choiceMode", "initialTreeView", "enableDrag", "enableStartDrag",
"rowPictureDataPath", "tableAutofill",
@@ -1933,6 +1933,8 @@ def emit_input(lines, el, name, eid, indent):
lines.append(f'{inner}<PasswordMode>true</PasswordMode>')
if el.get('choiceButton') is False:
lines.append(f'{inner}<ChoiceButton>false</ChoiceButton>')
elif el.get('choiceButton') is True and 'StartChoice' in (el.get('on') or []):
lines.append(f'{inner}<ChoiceButton>true</ChoiceButton>')
if el.get('clearButton') is True:
lines.append(f'{inner}<ClearButton>true</ClearButton>')
if el.get('spinButton') is True:
@@ -2362,6 +2364,16 @@ def emit_picture_field(lines, el, name, eid, indent):
emit_title(lines, el, name, inner)
emit_common_flags(lines, el, inner)
# ValuesPicture \u2014 picture (collection) used to render the field's value.
# Required for a Boolean-bound PictureField to actually show an icon.
# loadTransparent emitted only when true (1\u0421 default is false).
if el.get('valuesPicture'):
lines.append(f'{inner}<ValuesPicture>')
lines.append(f'{inner}\t<xr:Ref>{el["valuesPicture"]}</xr:Ref>')
if el.get('loadTransparent'):
lines.append(f'{inner}\t<xr:LoadTransparent>true</xr:LoadTransparent>')
lines.append(f'{inner}</ValuesPicture>')
if el.get('width'):
lines.append(f'{inner}<Width>{el["width"]}</Width>')
if el.get('height'):
+142 -142
View File
@@ -1,142 +1,142 @@
---
name: form-edit
description: Добавление элементов, реквизитов и команд в существующую управляемую форму 1С. Используй когда нужно точечно модифицировать готовую форму
argument-hint: <FormPath> <JsonPath>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /form-edit — Редактирование формы
Добавляет элементы, реквизиты и/или команды в существующий Form.xml. Автоматически выделяет ID из правильного пула, генерирует companion-элементы (ContextMenu, ExtendedTooltip, и др.) и обработчики событий.
## Использование
```
/form-edit <FormPath> <JsonPath>
```
## Параметры
| Параметр | Обязательный | Описание |
|-----------|:------------:|----------------------------------|
| FormPath | да | Путь к существующему Form.xml |
| JsonPath | да | Путь к JSON с описанием добавлений |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/form-edit.ps1" -FormPath "<путь>" -JsonPath "<путь>"
```
## JSON формат
```json
{
"into": "ГруппаШапка",
"after": "Контрагент",
"elements": [
{ "input": "Склад", "path": "Объект.Склад", "on": ["OnChange"] }
],
"attributes": [
{ "name": "СуммаИтого", "type": "decimal(15,2)" }
],
"commands": [
{ "name": "Рассчитать", "action": "РассчитатьОбработка" }
]
}
```
### Расширения (extension-формы)
Для заимствованных форм (с `<BaseForm>`) автоматически активируется extension-режим: ID начинаются с 1000000+. Доступны дополнительные секции:
```json
{
"formEvents": [
{ "name": "OnCreateAtServer", "handler": "Расш1_ПриСозданииПосле", "callType": "After" },
{ "name": "OnOpen", "handler": "Расш1_ПриОткрытии", "callType": "Before" }
],
"elementEvents": [
{ "element": "Банк", "name": "OnChange", "handler": "Расш1_БанкПриИзменении", "callType": "Before" }
],
"commands": [
{ "name": "Подбор", "action": "Расш1_ПодборПосле", "callType": "After" },
{ "name": "Запрос", "actions": [
{ "callType": "Before", "handler": "Расш1_ЗапросПеред" },
{ "callType": "After", "handler": "Расш1_ЗапросПосле" }
]}
],
"elements": [
{ "input": "Поле", "path": "Объект.Поле", "on": [{ "event": "OnChange", "callType": "After" }] }
]
}
```
### Позиционирование элементов
| Ключ | По умолчанию | Описание |
|------|-------------|----------|
| `into` | корневой ChildItems | Имя группы/таблицы/страницы, куда вставлять |
| `after` | в конец | Имя элемента, после которого вставлять |
### Типы элементов
Те же DSL-ключи, что в `/form-compile`:
| Ключ | XML тег | Companions |
|------|---------|------------|
| `input` | InputField | ContextMenu, ExtendedTooltip |
| `check` | CheckBoxField | ContextMenu, ExtendedTooltip |
| `label` | LabelDecoration | ContextMenu, ExtendedTooltip |
| `labelField` | LabelField | ContextMenu, ExtendedTooltip |
| `group` | UsualGroup | ExtendedTooltip |
| `table` | Table | ContextMenu, AutoCommandBar, Search*, ViewStatus* |
| `pages` | Pages | ExtendedTooltip |
| `page` | Page | ExtendedTooltip |
| `button` | Button | ExtendedTooltip |
Группы и таблицы поддерживают `children`/`columns` для вложенных элементов.
### Кнопки: command и stdCommand
- `"command": "ИмяКоманды"``Form.Command.ИмяКоманды`
- `"stdCommand": "Close"``Form.StandardCommand.Close`
- `"stdCommand": "Товары.Add"``Form.Item.Товары.StandardCommand.Add` (стандартная команда элемента)
### Допустимые события (`on`)
Компилятор предупреждает об ошибках в именах событий. Основные:
- **input**: `OnChange`, `StartChoice`, `ChoiceProcessing`, `Clearing`, `AutoComplete`, `TextEditEnd`
- **check**: `OnChange`
- **table**: `OnStartEdit`, `OnEditEnd`, `OnChange`, `Selection`, `BeforeAddRow`, `BeforeDeleteRow`, `OnActivateRow`
- **label/picture**: `Click`, `URLProcessing`
- **pages**: `OnCurrentPageChange`
- **button**: `Click`
### Система типов (для attributes)
`string`, `string(100)`, `decimal(15,2)`, `boolean`, `date`, `dateTime`, `CatalogRef.XXX`, `DocumentObject.XXX`, `ValueTable`, `DynamicList`, `Type1 | Type2` (составной).
### Секции расширений
| Секция | Назначение |
|--------|-----------|
| `formEvents` | События уровня формы с `callType` (Before/After/Override) |
| `elementEvents` | События на существующих элементах заимствованной формы |
| `callType` на `commands` | callType на Action команды |
| `callType` на `on` | callType на событиях новых элементов (объектный формат) |
Все extension-секции опциональны — без них навык работает как с обычными формами.
## Workflow
1. `/form-info` — посмотреть текущую структуру формы
2. Создать JSON с описанием добавлений
3. `/form-edit` — добавить в форму
4. `/form-validate` — проверить корректность
5. `/form-info` — убедиться что добавилось правильно
---
name: form-edit
description: Добавление элементов, реквизитов и команд в существующую управляемую форму 1С. Используй когда нужно точечно модифицировать готовую форму
argument-hint: <FormPath> <JsonPath>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /form-edit — Редактирование формы
Добавляет элементы, реквизиты и/или команды в существующий Form.xml. Автоматически выделяет ID из правильного пула, генерирует companion-элементы (ContextMenu, ExtendedTooltip, и др.) и обработчики событий.
## Использование
```
/form-edit <FormPath> <JsonPath>
```
## Параметры
| Параметр | Обязательный | Описание |
|-----------|:------------:|----------------------------------|
| FormPath | да | Путь к существующему Form.xml |
| JsonPath | да | Путь к JSON с описанием добавлений |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/form-edit.py" -FormPath "<путь>" -JsonPath "<путь>"
```
## JSON формат
```json
{
"into": "ГруппаШапка",
"after": "Контрагент",
"elements": [
{ "input": "Склад", "path": "Объект.Склад", "on": ["OnChange"] }
],
"attributes": [
{ "name": "СуммаИтого", "type": "decimal(15,2)" }
],
"commands": [
{ "name": "Рассчитать", "action": "РассчитатьОбработка" }
]
}
```
### Расширения (extension-формы)
Для заимствованных форм (с `<BaseForm>`) автоматически активируется extension-режим: ID начинаются с 1000000+. Доступны дополнительные секции:
```json
{
"formEvents": [
{ "name": "OnCreateAtServer", "handler": "Расш1_ПриСозданииПосле", "callType": "After" },
{ "name": "OnOpen", "handler": "Расш1_ПриОткрытии", "callType": "Before" }
],
"elementEvents": [
{ "element": "Банк", "name": "OnChange", "handler": "Расш1_БанкПриИзменении", "callType": "Before" }
],
"commands": [
{ "name": "Подбор", "action": "Расш1_ПодборПосле", "callType": "After" },
{ "name": "Запрос", "actions": [
{ "callType": "Before", "handler": "Расш1_ЗапросПеред" },
{ "callType": "After", "handler": "Расш1_ЗапросПосле" }
]}
],
"elements": [
{ "input": "Поле", "path": "Объект.Поле", "on": [{ "event": "OnChange", "callType": "After" }] }
]
}
```
### Позиционирование элементов
| Ключ | По умолчанию | Описание |
|------|-------------|----------|
| `into` | корневой ChildItems | Имя группы/таблицы/страницы, куда вставлять |
| `after` | в конец | Имя элемента, после которого вставлять |
### Типы элементов
Те же DSL-ключи, что в `/form-compile`:
| Ключ | XML тег | Companions |
|------|---------|------------|
| `input` | InputField | ContextMenu, ExtendedTooltip |
| `check` | CheckBoxField | ContextMenu, ExtendedTooltip |
| `label` | LabelDecoration | ContextMenu, ExtendedTooltip |
| `labelField` | LabelField | ContextMenu, ExtendedTooltip |
| `group` | UsualGroup | ExtendedTooltip |
| `table` | Table | ContextMenu, AutoCommandBar, Search*, ViewStatus* |
| `pages` | Pages | ExtendedTooltip |
| `page` | Page | ExtendedTooltip |
| `button` | Button | ExtendedTooltip |
Группы и таблицы поддерживают `children`/`columns` для вложенных элементов.
### Кнопки: command и stdCommand
- `"command": "ИмяКоманды"``Form.Command.ИмяКоманды`
- `"stdCommand": "Close"``Form.StandardCommand.Close`
- `"stdCommand": "Товары.Add"``Form.Item.Товары.StandardCommand.Add` (стандартная команда элемента)
### Допустимые события (`on`)
Компилятор предупреждает об ошибках в именах событий. Основные:
- **input**: `OnChange`, `StartChoice`, `ChoiceProcessing`, `Clearing`, `AutoComplete`, `TextEditEnd`
- **check**: `OnChange`
- **table**: `OnStartEdit`, `OnEditEnd`, `OnChange`, `Selection`, `BeforeAddRow`, `BeforeDeleteRow`, `OnActivateRow`
- **label/picture**: `Click`, `URLProcessing`
- **pages**: `OnCurrentPageChange`
- **button**: `Click`
### Система типов (для attributes)
`string`, `string(100)`, `decimal(15,2)`, `boolean`, `date`, `dateTime`, `CatalogRef.XXX`, `DocumentObject.XXX`, `ValueTable`, `DynamicList`, `Type1 | Type2` (составной).
### Секции расширений
| Секция | Назначение |
|--------|-----------|
| `formEvents` | События уровня формы с `callType` (Before/After/Override) |
| `elementEvents` | События на существующих элементах заимствованной формы |
| `callType` на `commands` | callType на Action команды |
| `callType` на `on` | callType на событиях новых элементов (объектный формат) |
Все extension-секции опциональны — без них навык работает как с обычными формами.
## Workflow
1. `/form-info` — посмотреть текущую структуру формы
2. Создать JSON с описанием добавлений
3. `/form-edit` — добавить в форму
4. `/form-validate` — проверить корректность
5. `/form-info` — убедиться что добавилось правильно
+30 -30
View File
@@ -1,30 +1,30 @@
---
name: form-info
description: Анализ структуры управляемой формы 1С (Form.xml) — элементы, реквизиты, команды, события. Используй для понимания формы — при написании модуля формы, анализе обработчиков и элементов
argument-hint: <FormPath>
allowed-tools:
- Bash
- Read
- Glob
---
# /form-info — Компактная сводка формы
Читает Form.xml и выводит дерево элементов, реквизиты с типами, команды, события. Заменяет чтение тысяч строк XML.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/form-info.ps1" -FormPath "<путь к Form.xml>"
```
## Параметры
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| FormPath | да | Путь к файлу Form.xml |
| Expand | нет | Раскрыть свёрнутую секцию по имени или title, `*` — все |
| Limit | нет | Макс. строк (по умолчанию 150) |
| Offset | нет | Пропустить N строк (пагинация) |
Вывод самодокументирован. `[Group:AH]`/`[Group:AV]` = AlwaysHorizontal/AlwaysVertical.
---
name: form-info
description: Анализ структуры управляемой формы 1С (Form.xml) — элементы, реквизиты, команды, события. Используй для понимания формы — при написании модуля формы, анализе обработчиков и элементов
argument-hint: <FormPath>
allowed-tools:
- Bash
- Read
- Glob
---
# /form-info — Компактная сводка формы
Читает Form.xml и выводит дерево элементов, реквизиты с типами, команды, события. Заменяет чтение тысяч строк XML.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/form-info.py" -FormPath "<путь к Form.xml>"
```
## Параметры
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| FormPath | да | Путь к файлу Form.xml |
| Expand | нет | Раскрыть свёрнутую секцию по имени или title, `*` — все |
| Limit | нет | Макс. строк (по умолчанию 150) |
| Offset | нет | Пропустить N строк (пагинация) |
Вывод самодокументирован. `[Group:AH]`/`[Group:AV]` = AlwaysHorizontal/AlwaysVertical.
+47 -47
View File
@@ -1,47 +1,47 @@
---
name: form-remove
description: Удалить форму из объекта 1С (обработка, отчёт, справочник, документ и др.)
argument-hint: <ObjectName> <FormName>
disable-model-invocation: true
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /form-remove — Удаление формы
Удаляет форму и убирает её регистрацию из корневого XML объекта.
## Usage
```
/form-remove <ObjectName> <FormName>
```
| Параметр | Обязательный | По умолчанию | Описание |
|------------|:------------:|--------------|-------------------------------------|
| ObjectName | да | — | Имя объекта |
| FormName | да | — | Имя формы для удаления |
| SrcDir | нет | `src` | Каталог исходников |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/remove-form.ps1" -ObjectName "<ObjectName>" -FormName "<FormName>" [-SrcDir "<SrcDir>"]
```
## Что удаляется
```
<SrcDir>/<ObjectName>/Forms/<FormName>.xml # Метаданные формы
<SrcDir>/<ObjectName>/Forms/<FormName>/ # Каталог формы (рекурсивно)
```
## Что модифицируется
- `<SrcDir>/<ObjectName>.xml` — убирается `<Form>` из `ChildObjects`
- Если удаляемая форма была DefaultForm — очищается значение DefaultForm
---
name: form-remove
description: Удалить форму из объекта 1С (обработка, отчёт, справочник, документ и др.)
argument-hint: <ObjectName> <FormName>
disable-model-invocation: true
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /form-remove — Удаление формы
Удаляет форму и убирает её регистрацию из корневого XML объекта.
## Usage
```
/form-remove <ObjectName> <FormName>
```
| Параметр | Обязательный | По умолчанию | Описание |
|------------|:------------:|--------------|-------------------------------------|
| ObjectName | да | — | Имя объекта |
| FormName | да | — | Имя формы для удаления |
| SrcDir | нет | `src` | Каталог исходников |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/remove-form.py" -ObjectName "<ObjectName>" -FormName "<FormName>" [-SrcDir "<SrcDir>"]
```
## Что удаляется
```
<SrcDir>/<ObjectName>/Forms/<FormName>.xml # Метаданные формы
<SrcDir>/<ObjectName>/Forms/<FormName>/ # Каталог формы (рекурсивно)
```
## Что модифицируется
- `<SrcDir>/<ObjectName>.xml` — убирается `<Form>` из `ChildObjects`
- Если удаляемая форма была DefaultForm — очищается значение DefaultForm
+29 -29
View File
@@ -1,29 +1,29 @@
---
name: form-validate
description: Валидация управляемой формы 1С. Используй после создания или модификации формы для проверки корректности. При наличии BaseForm автоматически проверяет callType и ID расширений
argument-hint: <FormPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /form-validate — валидация управляемой формы 1С
Проверяет Form.xml на структурные ошибки: уникальность ID, наличие companion-элементов, корректность ссылок DataPath и команд.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|-----------|:-----:|---------|-----------------------------------------|
| FormPath | да | — | Путь к файлу Form.xml |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/form-validate.ps1" -FormPath "Catalogs/Номенклатура/Forms/ФормаЭлемента"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/form-validate.ps1" -FormPath "src/МояОбработка/Forms/Форма/Ext/Form.xml"
```
---
name: form-validate
description: Валидация управляемой формы 1С. Используй после создания или модификации формы для проверки корректности. При наличии BaseForm автоматически проверяет callType и ID расширений
argument-hint: <FormPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /form-validate — валидация управляемой формы 1С
Проверяет Form.xml на структурные ошибки: уникальность ID, наличие companion-элементов, корректность ссылок DataPath и команд.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|-----------|:-----:|---------|-----------------------------------------|
| FormPath | да | — | Путь к файлу Form.xml |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/form-validate.py" -FormPath "Catalogs/Номенклатура/Forms/ФормаЭлемента"
python "${CLAUDE_SKILL_DIR}/scripts/form-validate.py" -FormPath "src/МояОбработка/Forms/Форма/Ext/Form.xml"
```
+44 -44
View File
@@ -1,44 +1,44 @@
---
name: help-add
description: Добавить встроенную справку к объекту 1С (обработка, отчёт, справочник, документ и др.). Используй когда пользователь просит добавить справку, help, встроенную помощь к объекту
argument-hint: <ObjectName>
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /help-add — Добавление справки
Добавляет встроенную справку к объекту: файл метаданных `Help.xml`, HTML-страницу и при необходимости обновляет метаданные форм.
## Usage
```
/help-add <ObjectName> [Lang] [SrcDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|------------|:------------:|--------------|-------------------------------------|
| ObjectName | да | — | Путь объекта относительно SrcDir (например `Catalogs/МойСправочник`, `DataProcessors/МояОбработка`) |
| Lang | нет | `ru` | Код языка справки |
| SrcDir | нет | `src` | Каталог исходников |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/add-help.ps1" -ObjectName "<ObjectName>" [-Lang "<Lang>"] [-SrcDir "<SrcDir>"]
```
## Что делает скрипт
- Создаёт `Ext/Help.xml` и `Ext/Help/ru.html` — шаблон справки
- Если у объекта есть формы — добавляет `<IncludeHelpInContents>` в метаданные форм (если отсутствует)
- Справка **не регистрируется** в `ChildObjects` — достаточно наличия файлов
## После запуска
Отредактируй `Ext/Help/ru.html` — наполни содержимым справки (стандартный HTML: `<h1>`..`<h4>`, `<p>`, `<ul>`, `<table>` и т.д.). Кнопка справки появится автоматически через `Autofill` в AutoCommandBar формы.
---
name: help-add
description: Добавить встроенную справку к объекту 1С (обработка, отчёт, справочник, документ и др.). Используй когда пользователь просит добавить справку, help, встроенную помощь к объекту
argument-hint: <ObjectName>
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /help-add — Добавление справки
Добавляет встроенную справку к объекту: файл метаданных `Help.xml`, HTML-страницу и при необходимости обновляет метаданные форм.
## Usage
```
/help-add <ObjectName> [Lang] [SrcDir]
```
| Параметр | Обязательный | По умолчанию | Описание |
|------------|:------------:|--------------|-------------------------------------|
| ObjectName | да | — | Путь объекта относительно SrcDir (например `Catalogs/МойСправочник`, `DataProcessors/МояОбработка`) |
| Lang | нет | `ru` | Код языка справки |
| SrcDir | нет | `src` | Каталог исходников |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/add-help.py" -ObjectName "<ObjectName>" [-Lang "<Lang>"] [-SrcDir "<SrcDir>"]
```
## Что делает скрипт
- Создаёт `Ext/Help.xml` и `Ext/Help/ru.html` — шаблон справки
- Если у объекта есть формы — добавляет `<IncludeHelpInContents>` в метаданные форм (если отсутствует)
- Справка **не регистрируется** в `ChildObjects` — достаточно наличия файлов
## После запуска
Отредактируй `Ext/Help/ru.html` — наполни содержимым справки (стандартный HTML: `<h1>`..`<h4>`, `<p>`, `<ul>`, `<table>` и т.д.). Кнопка справки появится автоматически через `Autofill` в AutoCommandBar формы.
+75 -75
View File
@@ -1,75 +1,75 @@
---
name: interface-edit
description: Настройка командного интерфейса подсистемы 1С. Используй когда нужно скрыть или показать команды, разместить в группах, настроить порядок
argument-hint: <CIPath> <Operation> <Value>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /interface-edit — редактирование CommandInterface.xml
Точечное редактирование файла командного интерфейса подсистемы 1С.
## Параметры
| Параметр | Обяз. | Описание |
|----------|:-----:|----------|
| CIPath | да | Путь к CommandInterface.xml |
| Operation | нет | Операция: hide, show, place, order, subsystem-order, group-order |
| Value | нет | Значение для операции |
| DefinitionFile | нет | JSON-файл с массивом операций (альтернатива Operation) |
| CreateIfMissing | нет | Создать файл если не существует |
| NoValidate | нет | Пропустить авто-валидацию |
## Команда
### Inline mode
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/interface-edit.ps1" -CIPath '<path>' -Operation hide -Value '<cmd>'
```
### JSON mode
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/interface-edit.ps1" -CIPath '<path>' -DefinitionFile '<json>'
```
## Операции
| Операция | Значение | Описание |
|----------|----------|----------|
| hide | Cmd.Name или массив | Скрыть команду (CommandsVisibility, false) |
| show | Cmd.Name или массив | Показать команду (visibility, true) |
| place | {"command":"...","group":"CommandGroup.X"} | Разместить команду в группе |
| order | {"group":"...","commands":[...]} | Задать порядок команд в группе |
| subsystem-order | ["Subsystem.X.Subsystem.A",...] | Порядок дочерних подсистем |
| group-order | ["NavigationPanelOrdinary",...] | Порядок групп |
## Примеры
```powershell
# Скрыть команду
... -CIPath Subsystems/Продажи/Ext/CommandInterface.xml -Operation hide -Value "Catalog.Товары.StandardCommand.OpenList"
# Показать команду
... -Operation show -Value "Report.Продажи.Command.Отчёт"
# Разместить в группе
... -Operation place -Value '{"command":"Report.X.Command.Y","group":"CommandGroup.Отчеты"}'
# Задать порядок подсистем
... -Operation subsystem-order -Value '["Subsystem.X.Subsystem.A","Subsystem.X.Subsystem.B"]'
# Создать новый CI
... -CIPath <new-path> -Operation subsystem-order -Value '[...]' -CreateIfMissing
```
## Верификация
```
/interface-validate <CIPath>
```
---
name: interface-edit
description: Настройка командного интерфейса подсистемы 1С. Используй когда нужно скрыть или показать команды, разместить в группах, настроить порядок
argument-hint: <CIPath> <Operation> <Value>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /interface-edit — редактирование CommandInterface.xml
Точечное редактирование файла командного интерфейса подсистемы 1С.
## Параметры
| Параметр | Обяз. | Описание |
|----------|:-----:|----------|
| CIPath | да | Путь к CommandInterface.xml |
| Operation | нет | Операция: hide, show, place, order, subsystem-order, group-order |
| Value | нет | Значение для операции |
| DefinitionFile | нет | JSON-файл с массивом операций (альтернатива Operation) |
| CreateIfMissing | нет | Создать файл если не существует |
| NoValidate | нет | Пропустить авто-валидацию |
## Команда
### Inline mode
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/interface-edit.py" -CIPath '<path>' -Operation hide -Value '<cmd>'
```
### JSON mode
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/interface-edit.py" -CIPath '<path>' -DefinitionFile '<json>'
```
## Операции
| Операция | Значение | Описание |
|----------|----------|----------|
| hide | Cmd.Name или массив | Скрыть команду (CommandsVisibility, false) |
| show | Cmd.Name или массив | Показать команду (visibility, true) |
| place | {"command":"...","group":"CommandGroup.X"} | Разместить команду в группе |
| order | {"group":"...","commands":[...]} | Задать порядок команд в группе |
| subsystem-order | ["Subsystem.X.Subsystem.A",...] | Порядок дочерних подсистем |
| group-order | ["NavigationPanelOrdinary",...] | Порядок групп |
## Примеры
```powershell
# Скрыть команду
... -CIPath Subsystems/Продажи/Ext/CommandInterface.xml -Operation hide -Value "Catalog.Товары.StandardCommand.OpenList"
# Показать команду
... -Operation show -Value "Report.Продажи.Command.Отчёт"
# Разместить в группе
... -Operation place -Value '{"command":"Report.X.Command.Y","group":"CommandGroup.Отчеты"}'
# Задать порядок подсистем
... -Operation subsystem-order -Value '["Subsystem.X.Subsystem.A","Subsystem.X.Subsystem.B"]'
# Создать новый CI
... -CIPath <new-path> -Operation subsystem-order -Value '[...]' -CreateIfMissing
```
## Верификация
```
/interface-validate <CIPath>
```
+29 -29
View File
@@ -1,29 +1,29 @@
---
name: interface-validate
description: Валидация командного интерфейса 1С. Используй после настройки командного интерфейса подсистемы для проверки корректности
argument-hint: <CIPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /interface-validate — валидация CommandInterface.xml
Проверяет XML командного интерфейса на структурные ошибки: корневой элемент, допустимые секции, порядок, формат ссылок на команды, дубликаты.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|-----------|:-----:|---------|-----------------------------------------|
| CIPath | да | — | Путь к CommandInterface.xml |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/interface-validate.ps1" -CIPath "Subsystems/Продажи"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/interface-validate.ps1" -CIPath "Subsystems/Продажи/Ext/CommandInterface.xml"
```
---
name: interface-validate
description: Валидация командного интерфейса 1С. Используй после настройки командного интерфейса подсистемы для проверки корректности
argument-hint: <CIPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /interface-validate — валидация CommandInterface.xml
Проверяет XML командного интерфейса на структурные ошибки: корневой элемент, допустимые секции, порядок, формат ссылок на команды, дубликаты.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|-----------|:-----:|---------|-----------------------------------------|
| CIPath | да | — | Путь к CommandInterface.xml |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/interface-validate.py" -CIPath "Subsystems/Продажи"
python "${CLAUDE_SKILL_DIR}/scripts/interface-validate.py" -CIPath "Subsystems/Продажи/Ext/CommandInterface.xml"
```
+119 -119
View File
@@ -1,119 +1,119 @@
---
name: meta-compile
description: Создать объект метаданных 1С. Используй когда нужно создать или добавить справочник, документ, регистр, перечисление, константу, общий модуль, обработку, отчёт и др.
argument-hint: <JsonPath> <OutputDir>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /meta-compile — генерация объектов метаданных из JSON DSL
Принимает JSON-определение объекта метаданных → генерирует XML + модули в структуре выгрузки конфигурации + регистрирует в Configuration.xml.
## Порядок работы
1. Составь JSON по синтаксису и примерам ниже → запиши во временный файл
2. Запусти скрипт meta-compile
3. Если нужно изменить созданный объект — `/meta-edit`
4. Если нужно проверить — `/meta-validate`
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/meta-compile.ps1" -JsonPath "<json>" -OutputDir "<ConfigDir>"
```
| Параметр | Описание |
|----------|----------|
| `JsonPath` | Путь к JSON-файлу (один объект `{...}` или массив `[{...}, ...]`) |
| `OutputDir` | Корень выгрузки конфигурации (где `Configuration.xml`, `Catalogs/`, `Documents/` и т.д.) |
## JSON DSL
### Общая структура
```json
{ "type": "Catalog", "name": "Номенклатура", ...свойства типа... }
```
`type` и `name` — обязательные. `synonym` генерируется из `name` автоматически (CamelCase → слова через пробел). Можно задать явно: `"synonym": "Мой синоним"`.
### Shorthand реквизитов
Используется в `attributes`, `dimensions`, `resources`, `tabularSections`:
```
"ИмяРеквизита" → String(10) по умолчанию
"ИмяРеквизита: Тип" → с типом
"ИмяРеквизита: Тип | req, index" → с флагами
```
Типы: `String(100)`, `Number(15,2)`, `Boolean`, `Date`, `DateTime`, `CatalogRef.Xxx`, `DocumentRef.Xxx`, `EnumRef.Xxx`, `DefinedType.Xxx` и др. ссылочные.
Составной тип: `"Значение: String + Number(15,2) + CatalogRef.Контрагенты"`.
Флаги: `req`, `index`, `indexAdditional`, `nonneg`, `master`, `mainFilter`, `denyIncomplete`, `useInTotals`.
### Свойства по типам
Примеров и shorthand-синтаксиса выше достаточно для типовых задач. Если нужны свойства типа, не показанные в примерах, и их допустимые значения — см. reference-файл:
- `reference/types-basic.md` — Catalog, Document, Enum, Constant, DefinedType, Report, DataProcessor
- `reference/types-registers.md` — InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes
- `reference/types-process.md` — BusinessProcess, Task, ExchangePlan, CommonModule, ScheduledJob, EventSubscription, DocumentJournal
- `reference/types-web.md` — HTTPService, WebService
Эта инструкция и reference-файлы — полная документация для генерации. Не ищи примеры XML в выгрузках конфигураций.
## Примеры паттернов DSL
### Минимальный объект
```json
{ "type": "Catalog", "name": "Валюты" }
```
### С реквизитами
```json
{
"type": "Catalog", "name": "Организации",
"descriptionLength": 100,
"attributes": ["ИНН: String(12)", "КПП: String(9)", "Директор: CatalogRef.ФизическиеЛица"]
}
```
### С табличной частью
```json
{
"type": "Document", "name": "ПриходнаяНакладная",
"registerRecords": ["AccumulationRegister.ОстаткиТоваров"],
"attributes": ["Организация: CatalogRef.Организации", "Контрагент: CatalogRef.Контрагенты"],
"tabularSections": { "Товары": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(15,3)", "Цена: Number(15,2)"] }
}
```
### Регистровый паттерн (измерения + ресурсы)
```json
{
"type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day",
"dimensions": ["Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"],
"resources": ["Курс: Number(15,4)", "Кратность: Number(10,0)"]
}
```
### Batch — несколько объектов в одном файле
```json
[
{ "type": "Enum", "name": "Статусы", "values": ["Новый", "Закрыт"] },
{ "type": "Catalog", "name": "Валюты" },
{ "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" }
]
```
---
name: meta-compile
description: Создать объект метаданных 1С. Используй когда нужно создать или добавить справочник, документ, регистр, перечисление, константу, общий модуль, обработку, отчёт и др.
argument-hint: <JsonPath> <OutputDir>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /meta-compile — генерация объектов метаданных из JSON DSL
Принимает JSON-определение объекта метаданных → генерирует XML + модули в структуре выгрузки конфигурации + регистрирует в Configuration.xml.
## Порядок работы
1. Составь JSON по синтаксису и примерам ниже → запиши во временный файл
2. Запусти скрипт meta-compile
3. Если нужно изменить созданный объект — `/meta-edit`
4. Если нужно проверить — `/meta-validate`
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/meta-compile.py" -JsonPath "<json>" -OutputDir "<ConfigDir>"
```
| Параметр | Описание |
|----------|----------|
| `JsonPath` | Путь к JSON-файлу (один объект `{...}` или массив `[{...}, ...]`) |
| `OutputDir` | Корень выгрузки конфигурации (где `Configuration.xml`, `Catalogs/`, `Documents/` и т.д.) |
## JSON DSL
### Общая структура
```json
{ "type": "Catalog", "name": "Номенклатура", ...свойства типа... }
```
`type` и `name` — обязательные. `synonym` генерируется из `name` автоматически (CamelCase → слова через пробел). Можно задать явно: `"synonym": "Мой синоним"`.
### Shorthand реквизитов
Используется в `attributes`, `dimensions`, `resources`, `tabularSections`:
```
"ИмяРеквизита" → String(10) по умолчанию
"ИмяРеквизита: Тип" → с типом
"ИмяРеквизита: Тип | req, index" → с флагами
```
Типы: `String(100)`, `Number(15,2)`, `Boolean`, `Date`, `DateTime`, `CatalogRef.Xxx`, `DocumentRef.Xxx`, `EnumRef.Xxx`, `DefinedType.Xxx` и др. ссылочные.
Составной тип: `"Значение: String + Number(15,2) + CatalogRef.Контрагенты"`.
Флаги: `req`, `index`, `indexAdditional`, `nonneg`, `master`, `mainFilter`, `denyIncomplete`, `useInTotals`.
### Свойства по типам
Примеров и shorthand-синтаксиса выше достаточно для типовых задач. Если нужны свойства типа, не показанные в примерах, и их допустимые значения — см. reference-файл:
- `reference/types-basic.md` — Catalog, Document, Enum, Constant, DefinedType, Report, DataProcessor
- `reference/types-registers.md` — InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes
- `reference/types-process.md` — BusinessProcess, Task, ExchangePlan, CommonModule, ScheduledJob, EventSubscription, DocumentJournal
- `reference/types-web.md` — HTTPService, WebService
Эта инструкция и reference-файлы — полная документация для генерации. Не ищи примеры XML в выгрузках конфигураций.
## Примеры паттернов DSL
### Минимальный объект
```json
{ "type": "Catalog", "name": "Валюты" }
```
### С реквизитами
```json
{
"type": "Catalog", "name": "Организации",
"descriptionLength": 100,
"attributes": ["ИНН: String(12)", "КПП: String(9)", "Директор: CatalogRef.ФизическиеЛица"]
}
```
### С табличной частью
```json
{
"type": "Document", "name": "ПриходнаяНакладная",
"registerRecords": ["AccumulationRegister.ОстаткиТоваров"],
"attributes": ["Организация: CatalogRef.Организации", "Контрагент: CatalogRef.Контрагенты"],
"tabularSections": { "Товары": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(15,3)", "Цена: Number(15,2)"] }
}
```
### Регистровый паттерн (измерения + ресурсы)
```json
{
"type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day",
"dimensions": ["Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"],
"resources": ["Курс: Number(15,4)", "Кратность: Number(10,0)"]
}
```
### Batch — несколько объектов в одном файле
```json
[
{ "type": "Enum", "name": "Статусы", "values": ["Новый", "Закрыт"] },
{ "type": "Catalog", "name": "Валюты" },
{ "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" }
]
```
+108 -108
View File
@@ -1,108 +1,108 @@
---
name: meta-edit
description: Точечное редактирование объекта метаданных 1С. Используй когда нужно добавить, удалить или изменить реквизиты, табличные части, измерения, ресурсы или свойства существующего объекта конфигурации
argument-hint: <ObjectPath> -Operation <op> -Value "<val>" | -DefinitionFile <json> [-NoValidate]
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /meta-edit — точечное редактирование метаданных 1С
Атомарные операции модификации существующих XML объектов метаданных.
## Команда
### Inline mode (простые операции)
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/meta-edit.ps1" -ObjectPath "<path>" -Operation <op> -Value "<val>"
```
### JSON mode (сложные/комбинированные)
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/meta-edit.ps1" -DefinitionFile "<json>" -ObjectPath "<path>"
```
| Параметр | Описание |
|----------|----------|
| ObjectPath | XML-файл или директория объекта (обязательный, авторезолв `<dirName>.xml`) |
| Operation | Inline-операция (альтернатива DefinitionFile) |
| Value | Значение для inline-операции |
| DefinitionFile | JSON-файл с операциями (альтернатива Operation) |
| NoValidate | Не запускать meta-validate после правки |
## Операции — сводная таблица
Batch через `;;` во всех операциях. Подробный синтаксис — в файлах по ссылкам.
### Дочерние элементы — [child-operations.md](child-operations.md)
| Операция | Формат Value | Пример |
|----------|-------------|--------|
| `add-attribute` | `Имя: Тип \| флаги` | `"Сумма: Число(15,2) \| req, index"` |
| `add-ts` | `ТЧ: Рекв1: Тип1, Рекв2: Тип2` | `"Товары: Ном: CatalogRef.Ном, Кол: Число(15,3)"` |
| `add-dimension` | `Имя: Тип \| флаги` | `"Организация: CatalogRef.Организации \| master"` |
| `add-resource` | `Имя: Тип` | `"Сумма: Число(15,2)"` |
| `add-enumValue` | `Имя` | `"Значение1 ;; Значение2"` |
| `add-column` | `Имя: Тип` | `"Тип: EnumRef.ТипыДокументов"` |
| `add-form` / `add-template` / `add-command` | `Имя` | `"ФормаЭлемента"` |
| `add-ts-attribute` | `ТЧ.Имя: Тип` | `"Товары.Скидка: Число(15,2)"` |
| `remove-*` | `Имя` | `"СтарыйРеквизит ;; ЕщёОдин"` |
| `remove-ts-attribute` | `ТЧ.Имя` | `"Товары.УстаревшийРекв"` |
| `modify-attribute` | `Имя: ключ=значение` | `"СтароеИмя: name=НовоеИмя, type=Строка(500)"` |
| `modify-ts-attribute` | `ТЧ.Имя: ключ=значение` | `"Товары.Рекв: name=НовоеИмя"` |
| `modify-ts` | `ТЧ: ключ=значение` | `"Товары: synonym=Товарный состав"` |
Позиционная вставка: `"Склад: CatalogRef.Склады >> after Организация"`.
### Свойства объекта — [properties-reference.md](properties-reference.md)
| Операция | Формат Value | Пример |
|----------|-------------|--------|
| `modify-property` | `Ключ=Значение` | `"CodeLength=11 ;; DescriptionLength=150"` |
| `add-owner` | `MetaType.Name` | `"Catalog.Контрагенты ;; Catalog.Организации"` |
| `add-registerRecord` | `MetaType.Name` | `"AccumulationRegister.ОстаткиТоваров"` |
| `add-basedOn` | `MetaType.Name` | `"Document.ЗаказКлиента"` |
| `add-inputByString` | `Путь поля` | `"StandardAttribute.Description"` |
| `set-owners` / `set-registerRecords` / `set-basedOn` / `set-inputByString` | Замена всего списка | `"Catalog.Орг ;; Catalog.Контр"` |
| `remove-owner` / `remove-registerRecord` / ... | Удаление из списка | `"Catalog.Контрагенты"` |
### JSON DSL — [json-dsl.md](json-dsl.md)
Для комбинированных операций (add + remove + modify в одном файле), синонимы ключей/типов, таблица поддерживаемых объектов.
## Быстрые примеры
```powershell
# Добавить реквизиты
-Operation add-attribute -Value "Комментарий: Строка(200) ;; Сумма: Число(15,2) | index"
# Составной тип (несколько типов через +)
-Operation add-attribute -Value "Значение: Строка + Число(15,2) + Дата + CatalogRef.Контрагенты"
# Добавить ТЧ с реквизитами
-Operation add-ts -Value "Товары: Ном: CatalogRef.Ном | req, Кол: Число(15,3), Цена: Число(15,2)"
# Удалить реквизит
-Operation remove-attribute -Value "УстаревшийРеквизит"
# Переименовать + сменить тип
-Operation modify-attribute -Value "СтароеИмя: name=НовоеИмя, type=Строка(500)"
# Изменить свойства объекта
-Operation modify-property -Value "CodeLength=11 ;; DescriptionLength=150"
# Владельцы справочника
-Operation set-owners -Value "Catalog.Контрагенты ;; Catalog.Организации"
```
## Верификация
```
/meta-validate <ObjectPath> — валидация после редактирования
/meta-info <ObjectPath> — визуальная сводка
```
---
name: meta-edit
description: Точечное редактирование объекта метаданных 1С. Используй когда нужно добавить, удалить или изменить реквизиты, табличные части, измерения, ресурсы или свойства существующего объекта конфигурации
argument-hint: <ObjectPath> -Operation <op> -Value "<val>" | -DefinitionFile <json> [-NoValidate]
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /meta-edit — точечное редактирование метаданных 1С
Атомарные операции модификации существующих XML объектов метаданных.
## Команда
### Inline mode (простые операции)
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/meta-edit.py" -ObjectPath "<path>" -Operation <op> -Value "<val>"
```
### JSON mode (сложные/комбинированные)
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/meta-edit.py" -DefinitionFile "<json>" -ObjectPath "<path>"
```
| Параметр | Описание |
|----------|----------|
| ObjectPath | XML-файл или директория объекта (обязательный, авторезолв `<dirName>.xml`) |
| Operation | Inline-операция (альтернатива DefinitionFile) |
| Value | Значение для inline-операции |
| DefinitionFile | JSON-файл с операциями (альтернатива Operation) |
| NoValidate | Не запускать meta-validate после правки |
## Операции — сводная таблица
Batch через `;;` во всех операциях. Подробный синтаксис — в файлах по ссылкам.
### Дочерние элементы — [child-operations.md](child-operations.md)
| Операция | Формат Value | Пример |
|----------|-------------|--------|
| `add-attribute` | `Имя: Тип \| флаги` | `"Сумма: Число(15,2) \| req, index"` |
| `add-ts` | `ТЧ: Рекв1: Тип1, Рекв2: Тип2` | `"Товары: Ном: CatalogRef.Ном, Кол: Число(15,3)"` |
| `add-dimension` | `Имя: Тип \| флаги` | `"Организация: CatalogRef.Организации \| master"` |
| `add-resource` | `Имя: Тип` | `"Сумма: Число(15,2)"` |
| `add-enumValue` | `Имя` | `"Значение1 ;; Значение2"` |
| `add-column` | `Имя: Тип` | `"Тип: EnumRef.ТипыДокументов"` |
| `add-form` / `add-template` / `add-command` | `Имя` | `"ФормаЭлемента"` |
| `add-ts-attribute` | `ТЧ.Имя: Тип` | `"Товары.Скидка: Число(15,2)"` |
| `remove-*` | `Имя` | `"СтарыйРеквизит ;; ЕщёОдин"` |
| `remove-ts-attribute` | `ТЧ.Имя` | `"Товары.УстаревшийРекв"` |
| `modify-attribute` | `Имя: ключ=значение` | `"СтароеИмя: name=НовоеИмя, type=Строка(500)"` |
| `modify-ts-attribute` | `ТЧ.Имя: ключ=значение` | `"Товары.Рекв: name=НовоеИмя"` |
| `modify-ts` | `ТЧ: ключ=значение` | `"Товары: synonym=Товарный состав"` |
Позиционная вставка: `"Склад: CatalogRef.Склады >> after Организация"`.
### Свойства объекта — [properties-reference.md](properties-reference.md)
| Операция | Формат Value | Пример |
|----------|-------------|--------|
| `modify-property` | `Ключ=Значение` | `"CodeLength=11 ;; DescriptionLength=150"` |
| `add-owner` | `MetaType.Name` | `"Catalog.Контрагенты ;; Catalog.Организации"` |
| `add-registerRecord` | `MetaType.Name` | `"AccumulationRegister.ОстаткиТоваров"` |
| `add-basedOn` | `MetaType.Name` | `"Document.ЗаказКлиента"` |
| `add-inputByString` | `Путь поля` | `"StandardAttribute.Description"` |
| `set-owners` / `set-registerRecords` / `set-basedOn` / `set-inputByString` | Замена всего списка | `"Catalog.Орг ;; Catalog.Контр"` |
| `remove-owner` / `remove-registerRecord` / ... | Удаление из списка | `"Catalog.Контрагенты"` |
### JSON DSL — [json-dsl.md](json-dsl.md)
Для комбинированных операций (add + remove + modify в одном файле), синонимы ключей/типов, таблица поддерживаемых объектов.
## Быстрые примеры
```powershell
# Добавить реквизиты
-Operation add-attribute -Value "Комментарий: Строка(200) ;; Сумма: Число(15,2) | index"
# Составной тип (несколько типов через +)
-Operation add-attribute -Value "Значение: Строка + Число(15,2) + Дата + CatalogRef.Контрагенты"
# Добавить ТЧ с реквизитами
-Operation add-ts -Value "Товары: Ном: CatalogRef.Ном | req, Кол: Число(15,3), Цена: Число(15,2)"
# Удалить реквизит
-Operation remove-attribute -Value "УстаревшийРеквизит"
# Переименовать + сменить тип
-Operation modify-attribute -Value "СтароеИмя: name=НовоеИмя, type=Строка(500)"
# Изменить свойства объекта
-Operation modify-property -Value "CodeLength=11 ;; DescriptionLength=150"
# Владельцы справочника
-Operation set-owners -Value "Catalog.Контрагенты ;; Catalog.Организации"
```
## Верификация
```
/meta-validate <ObjectPath> — валидация после редактирования
/meta-info <ObjectPath> — визуальная сводка
```
+148 -148
View File
@@ -1,148 +1,148 @@
# JSON DSL — режим определений
Для сложных и комбинированных операций используйте JSON-файл вместо inline-режима.
```powershell
powershell.exe -NoProfile -File .claude/skills/meta-edit/scripts/meta-edit.ps1 -DefinitionFile "<json>" -ObjectPath "<path>"
```
## add — добавить элементы
```json
{
"add": {
"attributes": [
{ "name": "Комментарий", "type": "Строка(200)" },
{ "name": "Сумма", "type": "Число(15,2)", "indexing": "Index" }
],
"tabularSections": [{
"name": "Товары",
"attrs": [
{ "name": "Номенклатура", "type": "CatalogRef.Номенклатура" },
{ "name": "Количество", "type": "Число(15,3)" }
]
}],
"forms": ["ФормаЭлемента"],
"templates": ["ПечатнаяФорма"]
}
}
```
Реквизиты можно задавать shorthand-строками: `"Сумма: Число(15,2) | req, index"`.
## remove — удалить элементы
```json
{
"remove": {
"attributes": ["СтарыйРеквизит"],
"tabularSections": ["УстаревшаяТЧ"]
}
}
```
## modify — изменить существующие
```json
{
"modify": {
"properties": {
"CodeLength": 11,
"Hierarchical": true,
"Owners": ["Catalog.Контрагенты", "Catalog.Организации"],
"RegisterRecords": ["AccumulationRegister.Продажи"],
"InputByString": ["StandardAttribute.Description"]
},
"attributes": {
"Комментарий": { "type": "Строка(500)" },
"СтароеИмя": { "name": "НовоеИмя" }
}
}
}
```
## modify — реквизиты внутри ТЧ
```json
{
"modify": {
"tabularSections": {
"Товары": {
"add": ["СтавкаНДС: EnumRef.СтавкиНДС", "Скидка: Число(15,2)"],
"remove": ["УстаревшийРекв"],
"modify": {
"СтароеИмя": { "name": "НовоеИмя", "type": "Строка(500)" }
}
}
}
}
}
```
## Комбинирование
Все три операции (`add`, `remove`, `modify`) можно указать в одном JSON-файле:
```json
{
"add": { "tabularSections": [{ "name": "НоваяТЧ", "attrs": ["Имя: Строка(100)"] }] },
"modify": {
"tabularSections": {
"СуществующаяТЧ": {
"add": ["НовыйРекв: Число(15,2)"],
"remove": ["СтарыйРекв"]
}
}
}
}
```
## Позиционная вставка
```json
{ "name": "Склад", "type": "CatalogRef.Склады", "after": "Организация" }
```
## Синонимы ключей (case-insensitive)
**Операции:** `add`/`добавить`, `remove`/`удалить`, `modify`/`изменить`
| Каноническое | Синонимы |
|-------------|----------|
| attributes | реквизиты, attrs |
| tabularSections | табличныеЧасти, тч, ts |
| dimensions | измерения, dims |
| resources | ресурсы, res |
| enumValues | значения, values |
| columns | графы, колонки |
| forms | формы |
| templates | макеты |
| commands | команды |
| properties | свойства |
## Составные типы
Для полей с несколькими допустимыми типами — массив в `type`:
```json
{ "name": "Значение", "type": ["Строка", "Число(15,2)", "Дата", "CatalogRef.Контрагенты"] }
```
В inline-формате — через `+`:
```
"Значение: Строка + Число(15,2) + Дата + CatalogRef.Контрагенты"
```
## Синонимы типов
`Строка(200)`, `Число(15,2)`, `Булево`, `Дата`, `ДатаВремя`, `ХранилищеЗначения`, `СправочникСсылка.XXX`, `ДокументСсылка.XXX`, `ПеречислениеСсылка.XXX`, `ОпределяемыйТип.XXX`.
## Поддерживаемые типы объектов
| Тип объекта | Допустимые add-типы |
|-------------|-------------------|
| Catalog, Document, ExchangePlan, ChartOf*, BP, Task, Report, DP | attributes, tabularSections, forms, templates, commands |
| Enum | enumValues, forms, templates, commands |
| *Register (4 типа) | dimensions, resources, attributes, forms, templates, commands |
| DocumentJournal | columns, forms, templates, commands |
| Constant | forms |
# JSON DSL — режим определений
Для сложных и комбинированных операций используйте JSON-файл вместо inline-режима.
```powershell
python .claude/skills/meta-edit/scripts/meta-edit.py -DefinitionFile "<json>" -ObjectPath "<path>"
```
## add — добавить элементы
```json
{
"add": {
"attributes": [
{ "name": "Комментарий", "type": "Строка(200)" },
{ "name": "Сумма", "type": "Число(15,2)", "indexing": "Index" }
],
"tabularSections": [{
"name": "Товары",
"attrs": [
{ "name": "Номенклатура", "type": "CatalogRef.Номенклатура" },
{ "name": "Количество", "type": "Число(15,3)" }
]
}],
"forms": ["ФормаЭлемента"],
"templates": ["ПечатнаяФорма"]
}
}
```
Реквизиты можно задавать shorthand-строками: `"Сумма: Число(15,2) | req, index"`.
## remove — удалить элементы
```json
{
"remove": {
"attributes": ["СтарыйРеквизит"],
"tabularSections": ["УстаревшаяТЧ"]
}
}
```
## modify — изменить существующие
```json
{
"modify": {
"properties": {
"CodeLength": 11,
"Hierarchical": true,
"Owners": ["Catalog.Контрагенты", "Catalog.Организации"],
"RegisterRecords": ["AccumulationRegister.Продажи"],
"InputByString": ["StandardAttribute.Description"]
},
"attributes": {
"Комментарий": { "type": "Строка(500)" },
"СтароеИмя": { "name": "НовоеИмя" }
}
}
}
```
## modify — реквизиты внутри ТЧ
```json
{
"modify": {
"tabularSections": {
"Товары": {
"add": ["СтавкаНДС: EnumRef.СтавкиНДС", "Скидка: Число(15,2)"],
"remove": ["УстаревшийРекв"],
"modify": {
"СтароеИмя": { "name": "НовоеИмя", "type": "Строка(500)" }
}
}
}
}
}
```
## Комбинирование
Все три операции (`add`, `remove`, `modify`) можно указать в одном JSON-файле:
```json
{
"add": { "tabularSections": [{ "name": "НоваяТЧ", "attrs": ["Имя: Строка(100)"] }] },
"modify": {
"tabularSections": {
"СуществующаяТЧ": {
"add": ["НовыйРекв: Число(15,2)"],
"remove": ["СтарыйРекв"]
}
}
}
}
```
## Позиционная вставка
```json
{ "name": "Склад", "type": "CatalogRef.Склады", "after": "Организация" }
```
## Синонимы ключей (case-insensitive)
**Операции:** `add`/`добавить`, `remove`/`удалить`, `modify`/`изменить`
| Каноническое | Синонимы |
|-------------|----------|
| attributes | реквизиты, attrs |
| tabularSections | табличныеЧасти, тч, ts |
| dimensions | измерения, dims |
| resources | ресурсы, res |
| enumValues | значения, values |
| columns | графы, колонки |
| forms | формы |
| templates | макеты |
| commands | команды |
| properties | свойства |
## Составные типы
Для полей с несколькими допустимыми типами — массив в `type`:
```json
{ "name": "Значение", "type": ["Строка", "Число(15,2)", "Дата", "CatalogRef.Контрагенты"] }
```
В inline-формате — через `+`:
```
"Значение: Строка + Число(15,2) + Дата + CatalogRef.Контрагенты"
```
## Синонимы типов
`Строка(200)`, `Число(15,2)`, `Булево`, `Дата`, `ДатаВремя`, `ХранилищеЗначения`, `СправочникСсылка.XXX`, `ДокументСсылка.XXX`, `ПеречислениеСсылка.XXX`, `ОпределяемыйТип.XXX`.
## Поддерживаемые типы объектов
| Тип объекта | Допустимые add-типы |
|-------------|-------------------|
| Catalog, Document, ExchangePlan, ChartOf*, BP, Task, Report, DP | attributes, tabularSections, forms, templates, commands |
| Enum | enumValues, forms, templates, commands |
| *Register (4 типа) | dimensions, resources, attributes, forms, templates, commands |
| DocumentJournal | columns, forms, templates, commands |
| Constant | forms |
+87 -87
View File
@@ -1,87 +1,87 @@
---
name: meta-info
description: Анализ структуры объекта метаданных 1С из XML-выгрузки — реквизиты, табличные части, формы, движения, типы. Используй для изучения структуры объектов (вместо чтения XML-файлов напрямую) и как подготовительный шаг при написании запросов и кода, работающего с объектами
argument-hint: <ObjectPath> [-Mode overview|brief|full] [-Name <элемент>]
allowed-tools:
- Bash
- Read
- Glob
---
# /meta-info — Структура объекта метаданных 1С
Читает XML объекта метаданных из выгрузки конфигурации 1С и выводит компактное описание структуры.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `ObjectPath` | Путь к XML-файлу объекта или каталогу (авто-резолв `<name>/<name>.xml`) |
| `Mode` | Режим: `overview` (default), `brief`, `full` |
| `Name` | Drill-down по имени элемента (реквизит, ТЧ, значение перечисления, шаблон URL, операция) |
| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк) |
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/meta-info.ps1" -ObjectPath "<путь>"
```
## Три режима
| Режим | Что показывает |
|---|---|
| `overview` *(default)* | Заголовок + ключевые свойства + структура без раскрытия деталей |
| `brief` | Всё одной-двумя строками: имена полей, счётчики |
| `full` | Всё раскрыто: колонки ТЧ, список источников подписки, движения, формы |
`-Name` — drill-down: раскрыть конкретный элемент объекта (ТЧ, реквизит, шаблон URL, операцию веб-сервиса).
## Поддерживаемые типы (23)
**Ссылочные:** Справочник, Документ, Перечисление, Бизнес-процесс, Задача, План обмена, План счетов, ПВХ, ПВР
**Регистры:** Регистр сведений, Регистр накопления, Регистр бухгалтерии, Регистр расчёта
**Сервисные:** Отчёт, Обработка, HTTP-сервис, Веб-сервис, Общий модуль, Регламентное задание, Подписка на событие
**Прочие:** Константа, Журнал документов, Определяемый тип
## Примеры
```powershell
# Справочник — overview
... -ObjectPath Catalogs/Валюты/Валюты.xml
# Документ — полная сводка с колонками ТЧ, движениями, формами
... -ObjectPath Documents/АвансовыйОтчет/АвансовыйОтчет.xml -Mode full
# Регистр сведений — краткая сводка
... -ObjectPath InformationRegisters/КурсыВалют/КурсыВалют.xml -Mode brief
# Drill-down в ТЧ документа
... -ObjectPath Documents/АвансовыйОтчет/АвансовыйОтчет.xml -Name Товары
# Drill-down в реквизит
... -ObjectPath Catalogs/Валюты/Валюты.xml -Name ОсновнаяВалюта
# Общий модуль — флаги контекста и повторное использование
... -ObjectPath CommonModules/ОбщегоНазначения/ОбщегоНазначения.xml
# HTTP-сервис — шаблоны URL и методы
... -ObjectPath HTTPServices/ExternalAPI/ExternalAPI.xml
# HTTP-сервис — drill-down в шаблон URL
... -ObjectPath HTTPServices/ExternalAPI/ExternalAPI.xml -Name АктуальныеЗадачи
# Веб-сервис — операции с параметрами
... -ObjectPath WebServices/EnterpriseDataUpload_1_0_1_1/EnterpriseDataUpload_1_0_1_1.xml
# Веб-сервис — drill-down в операцию
... -ObjectPath WebServices/EnterpriseDataUpload_1_0_1_1/EnterpriseDataUpload_1_0_1_1.xml -Name TestConnection
# Подписка на событие — full раскрывает список источников
... -ObjectPath EventSubscriptions/ПолныйРегистрацияУдаления/ПолныйРегистрацияУдаления.xml -Mode full
# Регламентное задание
... -ObjectPath ScheduledJobs/АвтоматическоеЗакрытиеМесяца/АвтоматическоеЗакрытиеМесяца.xml
# Определяемый тип
... -ObjectPath DefinedTypes/GLN/GLN.xml
```
---
name: meta-info
description: Анализ структуры объекта метаданных 1С из XML-выгрузки — реквизиты, табличные части, формы, движения, типы. Используй для изучения структуры объектов (вместо чтения XML-файлов напрямую) и как подготовительный шаг при написании запросов и кода, работающего с объектами
argument-hint: <ObjectPath> [-Mode overview|brief|full] [-Name <элемент>]
allowed-tools:
- Bash
- Read
- Glob
---
# /meta-info — Структура объекта метаданных 1С
Читает XML объекта метаданных из выгрузки конфигурации 1С и выводит компактное описание структуры.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `ObjectPath` | Путь к XML-файлу объекта или каталогу (авто-резолв `<name>/<name>.xml`) |
| `Mode` | Режим: `overview` (default), `brief`, `full` |
| `Name` | Drill-down по имени элемента (реквизит, ТЧ, значение перечисления, шаблон URL, операция) |
| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк) |
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/meta-info.py" -ObjectPath "<путь>"
```
## Три режима
| Режим | Что показывает |
|---|---|
| `overview` *(default)* | Заголовок + ключевые свойства + структура без раскрытия деталей |
| `brief` | Всё одной-двумя строками: имена полей, счётчики |
| `full` | Всё раскрыто: колонки ТЧ, список источников подписки, движения, формы |
`-Name` — drill-down: раскрыть конкретный элемент объекта (ТЧ, реквизит, шаблон URL, операцию веб-сервиса).
## Поддерживаемые типы (23)
**Ссылочные:** Справочник, Документ, Перечисление, Бизнес-процесс, Задача, План обмена, План счетов, ПВХ, ПВР
**Регистры:** Регистр сведений, Регистр накопления, Регистр бухгалтерии, Регистр расчёта
**Сервисные:** Отчёт, Обработка, HTTP-сервис, Веб-сервис, Общий модуль, Регламентное задание, Подписка на событие
**Прочие:** Константа, Журнал документов, Определяемый тип
## Примеры
```powershell
# Справочник — overview
... -ObjectPath Catalogs/Валюты/Валюты.xml
# Документ — полная сводка с колонками ТЧ, движениями, формами
... -ObjectPath Documents/АвансовыйОтчет/АвансовыйОтчет.xml -Mode full
# Регистр сведений — краткая сводка
... -ObjectPath InformationRegisters/КурсыВалют/КурсыВалют.xml -Mode brief
# Drill-down в ТЧ документа
... -ObjectPath Documents/АвансовыйОтчет/АвансовыйОтчет.xml -Name Товары
# Drill-down в реквизит
... -ObjectPath Catalogs/Валюты/Валюты.xml -Name ОсновнаяВалюта
# Общий модуль — флаги контекста и повторное использование
... -ObjectPath CommonModules/ОбщегоНазначения/ОбщегоНазначения.xml
# HTTP-сервис — шаблоны URL и методы
... -ObjectPath HTTPServices/ExternalAPI/ExternalAPI.xml
# HTTP-сервис — drill-down в шаблон URL
... -ObjectPath HTTPServices/ExternalAPI/ExternalAPI.xml -Name АктуальныеЗадачи
# Веб-сервис — операции с параметрами
... -ObjectPath WebServices/EnterpriseDataUpload_1_0_1_1/EnterpriseDataUpload_1_0_1_1.xml
# Веб-сервис — drill-down в операцию
... -ObjectPath WebServices/EnterpriseDataUpload_1_0_1_1/EnterpriseDataUpload_1_0_1_1.xml -Name TestConnection
# Подписка на событие — full раскрывает список источников
... -ObjectPath EventSubscriptions/ПолныйРегистрацияУдаления/ПолныйРегистрацияУдаления.xml -Mode full
# Регламентное задание
... -ObjectPath ScheduledJobs/АвтоматическоеЗакрытиеМесяца/АвтоматическоеЗакрытиеМесяца.xml
# Определяемый тип
... -ObjectPath DefinedTypes/GLN/GLN.xml
```
+28 -1
View File
@@ -1,4 +1,4 @@
# meta-info v1.1 — Compact summary of 1C metadata object
# meta-info v1.2 — Compact summary of 1C metadata object
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory=$true)][Alias('Path')][string]$ObjectPath,
@@ -422,6 +422,22 @@ $objName = $props.SelectSingleNode("md:Name", $ns).InnerText
$synNode = $props.SelectSingleNode("md:Synonym", $ns)
$synonym = Get-MLText $synNode
# Presentations (type-choice dialogs show "Представление объекта" as the ref type name)
$objPresentation = Get-MLText $props.SelectSingleNode("md:ObjectPresentation", $ns)
$extObjPresentation = Get-MLText $props.SelectSingleNode("md:ExtendedObjectPresentation", $ns)
$listPresentation = Get-MLText $props.SelectSingleNode("md:ListPresentation", $ns)
$extListPresentation = Get-MLText $props.SelectSingleNode("md:ExtendedListPresentation", $ns)
# Reference (ref-typed) metadata objects — those with a ...Ref type
$refMdTypes = @("Catalog","Document","Enum","ChartOfAccounts","ChartOfCharacteristicTypes",
"ChartOfCalculationTypes","ExchangePlan","BusinessProcess","Task")
$isRefObject = $refMdTypes -contains $mdType
# Effective type presentation: ObjectPresentation -> Synonym -> Name
$typePresentation = if ($objPresentation) { $objPresentation }
elseif ($synonym) { $synonym }
else { $objName }
# --- Handle -Name drill-down ---
$drillDone = $false
if ($Name -and $childObjs) {
@@ -593,6 +609,17 @@ if (-not $drillDone) {
$header += " ==="
Out $header
# --- Type presentation (ref objects) ---
if ($isRefObject) {
Out "Представление типа: $typePresentation"
if ($Mode -eq "full") {
if ($objPresentation) { Out "Представление объекта: $objPresentation" }
if ($extObjPresentation) { Out "Расширенное представление объекта: $extObjPresentation" }
if ($listPresentation) { Out "Представление списка: $listPresentation" }
if ($extListPresentation) { Out "Расширенное представление списка: $extListPresentation" }
}
}
# --- Mode: brief ---
if ($Mode -eq "brief") {
# Attributes
+29 -1
View File
@@ -1,4 +1,4 @@
# meta-info v1.1 — Compact summary of 1C metadata object (Python port)
# meta-info v1.2 — Compact summary of 1C metadata object (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -477,6 +477,21 @@ obj_name = inner_text(find(props, "md:Name"))
syn_node = find(props, "md:Synonym")
synonym = get_ml_text(syn_node)
# Presentations (type-choice dialogs show "Представление объекта" as the ref type name)
obj_presentation = get_ml_text(find(props, "md:ObjectPresentation"))
ext_obj_presentation = get_ml_text(find(props, "md:ExtendedObjectPresentation"))
list_presentation = get_ml_text(find(props, "md:ListPresentation"))
ext_list_presentation = get_ml_text(find(props, "md:ExtendedListPresentation"))
# Reference (ref-typed) metadata objects — those with a ...Ref type
ref_md_types = {"Catalog", "Document", "Enum", "ChartOfAccounts",
"ChartOfCharacteristicTypes", "ChartOfCalculationTypes",
"ExchangePlan", "BusinessProcess", "Task"}
is_ref_object = md_type in ref_md_types
# Effective type presentation: ObjectPresentation -> Synonym -> Name
type_presentation = obj_presentation or synonym or obj_name
# ── Handle -Name drill-down ──────────────────────────────────
drill_done = False
@@ -636,6 +651,19 @@ if not drill_done:
header += " ==="
out(header)
# Type presentation (ref objects)
if is_ref_object:
out(f"Представление типа: {type_presentation}")
if mode == "full":
if obj_presentation:
out(f"Представление объекта: {obj_presentation}")
if ext_obj_presentation:
out(f"Расширенное представление объекта: {ext_obj_presentation}")
if list_presentation:
out(f"Представление списка: {list_presentation}")
if ext_list_presentation:
out(f"Расширенное представление списка: {ext_list_presentation}")
if mode == "brief":
# Attributes
attrs = get_attributes(child_objs) if child_objs is not None else []
+60 -60
View File
@@ -1,60 +1,60 @@
---
name: meta-remove
description: Удалить объект метаданных из конфигурации 1С. Используй когда нужно удалить, убрать объект из конфигурации
argument-hint: <ConfigDir> -Object <Type.Name>
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /meta-remove — удаление объекта метаданных
Безопасно удаляет объект из XML-выгрузки конфигурации. Перед удалением проверяет ссылки на объект в реквизитах, коде и других метаданных. Если ссылки найдены — удаление блокируется.
## Использование
```
/meta-remove <ConfigDir> -Object <Type.Name>
```
## Параметры
| Параметр | Обязательный | Описание |
|------------|:------------:|-------------------------------------------------|
| ConfigDir | да | Корневая директория выгрузки (где Configuration.xml) |
| Object | да | Тип и имя объекта: `Catalog.Товары`, `Document.Заказ` и т.д. |
| DryRun | нет | Только показать что будет удалено, без изменений |
| KeepFiles | нет | Не удалять файлы, только дерегистрировать |
| Force | нет | Удалить несмотря на найденные ссылки |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/meta-remove.ps1" -ConfigDir "<путь>" -Object "Catalog.Товары"
```
## Поддерживаемые типы
Catalog, Document, Enum, Constant, InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes, BusinessProcess, Task, ExchangePlan, DocumentJournal, Report, DataProcessor, CommonModule, ScheduledJob, EventSubscription, HTTPService, WebService, DefinedType, Role, Subsystem, CommonForm, CommonTemplate, CommonPicture, CommonAttribute, SessionParameter, FunctionalOption, FunctionalOptionsParameter, Sequence, FilterCriterion, SettingsStorage, XDTOPackage, WSReference, StyleItem, Language
## Примеры
```powershell
# Проверка ссылок + dry run
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший" -DryRun
# Удалить объект без ссылок
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший"
# Принудительно удалить несмотря на ссылки
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший" -Force
# Только дерегистрировать (файлы оставить)
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Report.Старый" -KeepFiles
# Удалить общий модуль
... -ConfigDir src -Object "CommonModule.МойМодуль"
```
---
name: meta-remove
description: Удалить объект метаданных из конфигурации 1С. Используй когда нужно удалить, убрать объект из конфигурации
argument-hint: <ConfigDir> -Object <Type.Name>
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /meta-remove — удаление объекта метаданных
Безопасно удаляет объект из XML-выгрузки конфигурации. Перед удалением проверяет ссылки на объект в реквизитах, коде и других метаданных. Если ссылки найдены — удаление блокируется.
## Использование
```
/meta-remove <ConfigDir> -Object <Type.Name>
```
## Параметры
| Параметр | Обязательный | Описание |
|------------|:------------:|-------------------------------------------------|
| ConfigDir | да | Корневая директория выгрузки (где Configuration.xml) |
| Object | да | Тип и имя объекта: `Catalog.Товары`, `Document.Заказ` и т.д. |
| DryRun | нет | Только показать что будет удалено, без изменений |
| KeepFiles | нет | Не удалять файлы, только дерегистрировать |
| Force | нет | Удалить несмотря на найденные ссылки |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/meta-remove.py" -ConfigDir "<путь>" -Object "Catalog.Товары"
```
## Поддерживаемые типы
Catalog, Document, Enum, Constant, InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes, BusinessProcess, Task, ExchangePlan, DocumentJournal, Report, DataProcessor, CommonModule, ScheduledJob, EventSubscription, HTTPService, WebService, DefinedType, Role, Subsystem, CommonForm, CommonTemplate, CommonPicture, CommonAttribute, SessionParameter, FunctionalOption, FunctionalOptionsParameter, Sequence, FilterCriterion, SettingsStorage, XDTOPackage, WSReference, StyleItem, Language
## Примеры
```powershell
# Проверка ссылок + dry run
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший" -DryRun
# Удалить объект без ссылок
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший"
# Принудительно удалить несмотря на ссылки
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший" -Force
# Только дерегистрировать (файлы оставить)
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Report.Старый" -KeepFiles
# Удалить общий модуль
... -ConfigDir src -Object "CommonModule.МойМодуль"
```
+29 -29
View File
@@ -1,29 +1,29 @@
---
name: meta-validate
description: Валидация объекта метаданных 1С. Используй после создания или модификации объекта конфигурации для проверки корректности
argument-hint: <ObjectPath> [-Detailed] [-MaxErrors 30] — pipe-separated paths for batch
allowed-tools:
- Bash
- Read
- Glob
---
# /meta-validate — валидация объекта метаданных 1С
Проверяет XML объекта метаданных из выгрузки конфигурации на структурные ошибки.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|------------|:-----:|---------|-------------------------------------------------|
| ObjectPath | да | — | Путь к XML-файлу или каталогу. Через `\|` для batch |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок (per object) |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/meta-validate.ps1" -ObjectPath "Catalogs/Номенклатура/Номенклатура.xml"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/meta-validate.ps1" -ObjectPath "Catalogs/Банки|Documents/Заказ"
```
---
name: meta-validate
description: Валидация объекта метаданных 1С. Используй после создания или модификации объекта конфигурации для проверки корректности
argument-hint: <ObjectPath> [-Detailed] [-MaxErrors 30] — pipe-separated paths for batch
allowed-tools:
- Bash
- Read
- Glob
---
# /meta-validate — валидация объекта метаданных 1С
Проверяет XML объекта метаданных из выгрузки конфигурации на структурные ошибки.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|------------|:-----:|---------|-------------------------------------------------|
| ObjectPath | да | — | Путь к XML-файлу или каталогу. Через `\|` для batch |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок (per object) |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/meta-validate.py" -ObjectPath "Catalogs/Номенклатура/Номенклатура.xml"
python "${CLAUDE_SKILL_DIR}/scripts/meta-validate.py" -ObjectPath "Catalogs/Банки|Documents/Заказ"
```
+65 -65
View File
@@ -1,65 +1,65 @@
---
name: mxl-compile
description: Компиляция табличного документа (MXL) из JSON-определения. Используй когда нужно создать макет печатной формы
argument-hint: <JsonPath> <OutputPath>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /mxl-compile — Компилятор макета из DSL
Принимает компактное JSON-определение макета и генерирует корректный Template.xml для табличного документа 1С. Claude описывает *что* нужно (области, параметры, стили), скрипт обеспечивает *корректность* XML (палитры, индексы, объединения, namespace).
## Использование
```
/mxl-compile <JsonPath> <OutputPath>
```
## Параметры
| Параметр | Обязательный | Описание |
|------------|:------------:|------------------------------------|
| JsonPath | да | Путь к JSON-определению макета |
| OutputPath | да | Путь для генерации Template.xml |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-compile.ps1" -JsonPath "<путь>.json" -OutputPath "<путь>/Template.xml"
```
## Рабочий процесс
1. Claude пишет JSON-определение (Write tool) → файл `.json`
2. Claude вызывает `/mxl-compile` для генерации Template.xml
3. Claude вызывает `/mxl-validate` для проверки корректности
4. Claude вызывает `/mxl-info` для верификации структуры
**Если макет создаётся по изображению** (скриншот, скан печатной формы) — сначала вызвать `/img-grid` для наложения сетки, по ней определить границы колонок и пропорции, затем использовать `"Nx"` ширины + `"page"` для автоматического расчёта размеров.
## JSON-схема DSL
Полная спецификация формата: **`docs/mxl-dsl-spec.md`** (прочитать через Read tool перед написанием JSON).
Краткая структура:
```
{ columns, page, defaultWidth, columnWidths,
fonts: { name: { face, size, bold, italic, underline, strikeout } },
styles: { name: { font, align, valign, border, borderWidth, wrap, format } },
areas: [{ name, rows: [{ height, rowStyle, cells: [
{ col, span, rowspan, style, param, detail, text, template }
]}]}]
}
```
Ключевые правила:
- `page` — формат страницы (`"A4-landscape"`, `"A4-portrait"` или число). Автоматически вычисляет `defaultWidth` из суммы пропорций `"Nx"`
- `col` — 1-based позиция колонки
- `rowStyle` — автозаполнение пустот стилем (рамки по всей ширине)
- Тип заполнения определяется автоматически: `param` → Parameter, `text` → Text, `template` → Template
- `rowspan` — объединение строк вниз (rowStyle учитывает занятые ячейки)
---
name: mxl-compile
description: Компиляция табличного документа (MXL) из JSON-определения. Используй когда нужно создать макет печатной формы
argument-hint: <JsonPath> <OutputPath>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /mxl-compile — Компилятор макета из DSL
Принимает компактное JSON-определение макета и генерирует корректный Template.xml для табличного документа 1С. Claude описывает *что* нужно (области, параметры, стили), скрипт обеспечивает *корректность* XML (палитры, индексы, объединения, namespace).
## Использование
```
/mxl-compile <JsonPath> <OutputPath>
```
## Параметры
| Параметр | Обязательный | Описание |
|------------|:------------:|------------------------------------|
| JsonPath | да | Путь к JSON-определению макета |
| OutputPath | да | Путь для генерации Template.xml |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/mxl-compile.py" -JsonPath "<путь>.json" -OutputPath "<путь>/Template.xml"
```
## Рабочий процесс
1. Claude пишет JSON-определение (Write tool) → файл `.json`
2. Claude вызывает `/mxl-compile` для генерации Template.xml
3. Claude вызывает `/mxl-validate` для проверки корректности
4. Claude вызывает `/mxl-info` для верификации структуры
**Если макет создаётся по изображению** (скриншот, скан печатной формы) — сначала вызвать `/img-grid` для наложения сетки, по ней определить границы колонок и пропорции, затем использовать `"Nx"` ширины + `"page"` для автоматического расчёта размеров.
## JSON-схема DSL
Полная спецификация формата: **`docs/mxl-dsl-spec.md`** (прочитать через Read tool перед написанием JSON).
Краткая структура:
```
{ columns, page, defaultWidth, columnWidths,
fonts: { name: { face, size, bold, italic, underline, strikeout } },
styles: { name: { font, align, valign, border, borderWidth, wrap, format } },
areas: [{ name, rows: [{ height, rowStyle, cells: [
{ col, span, rowspan, style, param, detail, text, template }
]}]}]
}
```
Ключевые правила:
- `page` — формат страницы (`"A4-landscape"`, `"A4-portrait"` или число). Автоматически вычисляет `defaultWidth` из суммы пропорций `"Nx"`
- `col` — 1-based позиция колонки
- `rowStyle` — автозаполнение пустот стилем (рамки по всей ширине)
- Тип заполнения определяется автоматически: `param` → Parameter, `text` → Text, `template` → Template
- `rowspan` — объединение строк вниз (rowStyle учитывает занятые ячейки)
+57 -57
View File
@@ -1,57 +1,57 @@
---
name: mxl-decompile
description: Декомпиляция табличного документа (MXL) в JSON-определение. Используй когда нужно получить редактируемое описание существующего макета
argument-hint: <TemplatePath> [OutputPath]
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /mxl-decompile — Декомпилятор макета в DSL
Принимает Template.xml табличного документа 1С и генерирует компактное JSON-определение (DSL). Обратная операция к `/mxl-compile`.
## Использование
```
/mxl-decompile <TemplatePath> [OutputPath]
```
## Параметры
| Параметр | Обязательный | Описание |
|--------------|:------------:|-----------------------------------------|
| TemplatePath | да | Путь к Template.xml |
| OutputPath | нет | Путь для JSON (если не указан — stdout) |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-decompile.ps1" -TemplatePath "<путь>/Template.xml" [-OutputPath "<путь>.json"]
```
## Рабочий процесс
Декомпиляция существующего макета для анализа или доработки:
1. Claude вызывает `/mxl-decompile` для получения JSON из Template.xml
2. Claude анализирует или модифицирует JSON (добавляет области, меняет стили)
3. Claude вызывает `/mxl-compile` для генерации нового Template.xml
4. Claude вызывает `/mxl-validate` для проверки
## JSON-схема DSL
Полная спецификация формата: **`docs/mxl-dsl-spec.md`** (прочитать через Read tool).
## Генерация имён
Скрипт автоматически генерирует осмысленные имена:
- **Шрифты**: `default`, `bold`, `header`, `small`, `italic` — или описательные имена по свойствам
- **Стили**: `bordered`, `bordered-center`, `bold-right`, `border-top` и т.д. — по комбинации свойств
## Детектирование `rowStyle`
Если в строке есть пустые ячейки (без параметров/текста) и все они имеют одинаковый формат — этот формат распознаётся как `rowStyle`, а пустые ячейки исключаются из вывода.
---
name: mxl-decompile
description: Декомпиляция табличного документа (MXL) в JSON-определение. Используй когда нужно получить редактируемое описание существующего макета
argument-hint: <TemplatePath> [OutputPath]
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /mxl-decompile — Декомпилятор макета в DSL
Принимает Template.xml табличного документа 1С и генерирует компактное JSON-определение (DSL). Обратная операция к `/mxl-compile`.
## Использование
```
/mxl-decompile <TemplatePath> [OutputPath]
```
## Параметры
| Параметр | Обязательный | Описание |
|--------------|:------------:|-----------------------------------------|
| TemplatePath | да | Путь к Template.xml |
| OutputPath | нет | Путь для JSON (если не указан — stdout) |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/mxl-decompile.py" -TemplatePath "<путь>/Template.xml" [-OutputPath "<путь>.json"]
```
## Рабочий процесс
Декомпиляция существующего макета для анализа или доработки:
1. Claude вызывает `/mxl-decompile` для получения JSON из Template.xml
2. Claude анализирует или модифицирует JSON (добавляет области, меняет стили)
3. Claude вызывает `/mxl-compile` для генерации нового Template.xml
4. Claude вызывает `/mxl-validate` для проверки
## JSON-схема DSL
Полная спецификация формата: **`docs/mxl-dsl-spec.md`** (прочитать через Read tool).
## Генерация имён
Скрипт автоматически генерирует осмысленные имена:
- **Шрифты**: `default`, `bold`, `header`, `small`, `italic` — или описательные имена по свойствам
- **Стили**: `bordered`, `bordered-center`, `bold-right`, `border-top` и т.д. — по комбинации свойств
## Детектирование `rowStyle`
Если в строке есть пустые ячейки (без параметров/текста) и все они имеют одинаковый формат — этот формат распознаётся как `rowStyle`, а пустые ячейки исключаются из вывода.
+132 -132
View File
@@ -1,132 +1,132 @@
---
name: mxl-info
description: Анализ структуры макета табличного документа (MXL) — области, параметры, наборы колонок. Используй при разработке печати — получить области и заполняемые параметры макета
argument-hint: <TemplatePath> или <ProcessorName> <TemplateName>
allowed-tools:
- Bash
- Read
- Glob
---
# /mxl-info — Анализ структуры макета
Читает Template.xml табличного документа и выводит компактную сводку: именованные области, параметры, наборы колонок. Заменяет необходимость читать тысячи строк XML.
## Использование
```
/mxl-info <TemplatePath>
/mxl-info <ProcessorName> <TemplateName>
```
## Параметры
| Параметр | Обязательный | По умолчанию | Описание |
|---------------|:------------:|--------------|------------------------------------------|
| TemplatePath | нет | — | Прямой путь к Template.xml |
| ProcessorName | нет | — | Имя обработки (альтернатива пути) |
| TemplateName | нет | — | Имя макета (альтернатива пути) |
| SrcDir | нет | `src` | Каталог исходников |
| Format | нет | `text` | Формат вывода: `text` или `json` |
| WithText | нет | false | Включить статический текст и шаблоны |
| MaxParams | нет | 10 | Макс. параметров в списке на область |
| Limit | нет | 150 | Макс. строк вывода (защита от переполнения) |
| Offset | нет | 0 | Пропустить N строк (для пагинации) |
Укажите либо `-TemplatePath`, либо оба `-ProcessorName` и `-TemplateName`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-info.ps1" -TemplatePath "<путь>"
```
Или по имени обработки/макета:
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-info.ps1" -ProcessorName "<Имя>" -TemplateName "<Макет>" [-SrcDir "<каталог>"]
```
Дополнительные флаги:
```powershell
... -WithText # включить текстовое содержимое ячеек
... -Format json # JSON-вывод для программной обработки
... -MaxParams 20 # показать больше параметров на область
... -Offset 150 # пагинация: пропустить первые 150 строк
```
## Чтение вывода
### Области — сортировка сверху вниз
Области перечислены в порядке документа (по позиции строки), а не по алфавиту. Это соответствует порядку вывода областей в коде заполнения — сверху вниз.
```
--- Named areas ---
Заголовок Rows rows 1-4 (1 params)
Поставщик Rows rows 5-6 (1 params)
Строка Rows rows 14-14 (8 params)
Итого Rows rows 16-17 (1 params)
```
Типы областей:
- **Rows** — горизонтальная область (диапазон строк). Получение: `Макет.ПолучитьОбласть("Имя")`
- **Columns** — вертикальная область (диапазон колонок). Получение: `Макет.ПолучитьОбласть("Имя")`
- **Rectangle** — фиксированная область (строки + колонки). Обычно использует отдельный набор колонок.
- **Drawing** — именованный рисунок/штрихкод.
### Пересечения
Когда есть области и Rows, и Columns (этикетки, ценники), скрипт выводит пары пересечений:
```
--- Intersections (use with GetArea) ---
ВысотаЭтикетки|ШиринаЭтикетки
```
В BSL: `Макет.ПолучитьОбласть("ВысотаЭтикетки|ШиринаЭтикетки")`
### Параметры и detailParameter
Параметры перечислены по областям. Если у параметра есть `detailParameter` (расшифровка), он показан ниже:
```
--- Parameters by area ---
Поставщик: ПредставлениеПоставщика
detail: ПредставлениеПоставщика->Поставщик
Строка: НомерСтроки, Товар, Количество, Цена, Сумма, ... (+3)
detail: Товар->Номенклатура
```
Это означает: параметр `Товар` отображает значение, а при клике открывает `Номенклатура` (объект расшифровки).
### Параметры из шаблонов (суффикс `[tpl]`)
Некоторые параметры встроены в шаблонный текст: `"Инв № [ИнвентарныйНомер]"`. Они заполняются через fillType=Template, а не fillType=Parameter. Скрипт всегда извлекает их и помечает суффиксом `[tpl]`:
```
НумерацияЛистов: Номер [tpl], Дата [tpl], НомерЛиста [tpl]
```
В BSL шаблонные параметры заполняются так же, как обычные:
```bsl
Область.Параметры.Номер = НомерДокумента;
Область.Параметры.Дата = ДатаДокумента;
```
Числовые подстановки вроде `[5]`, `[6]` (ссылки на сноски в официальных формах) игнорируются.
### Текстовое содержимое (`-WithText`)
Показывает статический текст (надписи, заголовки) и шаблонные строки с подстановками `[Параметр]`:
```
--- Text content ---
ШапкаТаблицы:
Text: "№", "Товар", "Ед. изм.", "Кол-во", "Цена", "Сумма"
Строка:
Templates: "Инв № [ИнвентарныйНомер]"
```
- **Text** — статические надписи (fillType=Text). Полезно для понимания назначения колонок.
- **Templates** — текст с подстановками `[ИмяПараметра]` (fillType=Template). Параметр внутри `[]` заполняется программно.
---
name: mxl-info
description: Анализ структуры макета табличного документа (MXL) — области, параметры, наборы колонок. Используй при разработке печати — получить области и заполняемые параметры макета
argument-hint: <TemplatePath> или <ProcessorName> <TemplateName>
allowed-tools:
- Bash
- Read
- Glob
---
# /mxl-info — Анализ структуры макета
Читает Template.xml табличного документа и выводит компактную сводку: именованные области, параметры, наборы колонок. Заменяет необходимость читать тысячи строк XML.
## Использование
```
/mxl-info <TemplatePath>
/mxl-info <ProcessorName> <TemplateName>
```
## Параметры
| Параметр | Обязательный | По умолчанию | Описание |
|---------------|:------------:|--------------|------------------------------------------|
| TemplatePath | нет | — | Прямой путь к Template.xml |
| ProcessorName | нет | — | Имя обработки (альтернатива пути) |
| TemplateName | нет | — | Имя макета (альтернатива пути) |
| SrcDir | нет | `src` | Каталог исходников |
| Format | нет | `text` | Формат вывода: `text` или `json` |
| WithText | нет | false | Включить статический текст и шаблоны |
| MaxParams | нет | 10 | Макс. параметров в списке на область |
| Limit | нет | 150 | Макс. строк вывода (защита от переполнения) |
| Offset | нет | 0 | Пропустить N строк (для пагинации) |
Укажите либо `-TemplatePath`, либо оба `-ProcessorName` и `-TemplateName`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/mxl-info.py" -TemplatePath "<путь>"
```
Или по имени обработки/макета:
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/mxl-info.py" -ProcessorName "<Имя>" -TemplateName "<Макет>" [-SrcDir "<каталог>"]
```
Дополнительные флаги:
```powershell
... -WithText # включить текстовое содержимое ячеек
... -Format json # JSON-вывод для программной обработки
... -MaxParams 20 # показать больше параметров на область
... -Offset 150 # пагинация: пропустить первые 150 строк
```
## Чтение вывода
### Области — сортировка сверху вниз
Области перечислены в порядке документа (по позиции строки), а не по алфавиту. Это соответствует порядку вывода областей в коде заполнения — сверху вниз.
```
--- Named areas ---
Заголовок Rows rows 1-4 (1 params)
Поставщик Rows rows 5-6 (1 params)
Строка Rows rows 14-14 (8 params)
Итого Rows rows 16-17 (1 params)
```
Типы областей:
- **Rows** — горизонтальная область (диапазон строк). Получение: `Макет.ПолучитьОбласть("Имя")`
- **Columns** — вертикальная область (диапазон колонок). Получение: `Макет.ПолучитьОбласть("Имя")`
- **Rectangle** — фиксированная область (строки + колонки). Обычно использует отдельный набор колонок.
- **Drawing** — именованный рисунок/штрихкод.
### Пересечения
Когда есть области и Rows, и Columns (этикетки, ценники), скрипт выводит пары пересечений:
```
--- Intersections (use with GetArea) ---
ВысотаЭтикетки|ШиринаЭтикетки
```
В BSL: `Макет.ПолучитьОбласть("ВысотаЭтикетки|ШиринаЭтикетки")`
### Параметры и detailParameter
Параметры перечислены по областям. Если у параметра есть `detailParameter` (расшифровка), он показан ниже:
```
--- Parameters by area ---
Поставщик: ПредставлениеПоставщика
detail: ПредставлениеПоставщика->Поставщик
Строка: НомерСтроки, Товар, Количество, Цена, Сумма, ... (+3)
detail: Товар->Номенклатура
```
Это означает: параметр `Товар` отображает значение, а при клике открывает `Номенклатура` (объект расшифровки).
### Параметры из шаблонов (суффикс `[tpl]`)
Некоторые параметры встроены в шаблонный текст: `"Инв № [ИнвентарныйНомер]"`. Они заполняются через fillType=Template, а не fillType=Parameter. Скрипт всегда извлекает их и помечает суффиксом `[tpl]`:
```
НумерацияЛистов: Номер [tpl], Дата [tpl], НомерЛиста [tpl]
```
В BSL шаблонные параметры заполняются так же, как обычные:
```bsl
Область.Параметры.Номер = НомерДокумента;
Область.Параметры.Дата = ДатаДокумента;
```
Числовые подстановки вроде `[5]`, `[6]` (ссылки на сноски в официальных формах) игнорируются.
### Текстовое содержимое (`-WithText`)
Показывает статический текст (надписи, заголовки) и шаблонные строки с подстановками `[Параметр]`:
```
--- Text content ---
ШапкаТаблицы:
Text: "№", "Товар", "Ед. изм.", "Кол-во", "Цена", "Сумма"
Строка:
Templates: "Инв № [ИнвентарныйНомер]"
```
- **Text** — статические надписи (fillType=Text). Полезно для понимания назначения колонок.
- **Templates** — текст с подстановками `[ИмяПараметра]` (fillType=Template). Параметр внутри `[]` заполняется программно.
+29 -29
View File
@@ -1,29 +1,29 @@
---
name: mxl-validate
description: Валидация макета табличного документа (MXL). Используй после создания или модификации макета для проверки корректности
argument-hint: <TemplatePath> [-Detailed] [-MaxErrors 20]
allowed-tools:
- Bash
- Read
- Glob
---
# /mxl-validate — валидация макета табличного документа (MXL)
Проверяет Template.xml на структурные ошибки: индексы, ссылки на палитры, диапазоны именованных областей и объединений.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|---------------|:-----:|---------|--------------------------------------------|
| TemplatePath | да | — | Путь к макету (директория или Template.xml) |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 20 | Остановиться после N ошибок |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-validate.ps1" -TemplatePath "Catalogs/Номенклатура/Templates/Макет"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-validate.ps1" -TemplatePath "src/МояОбработка/Templates/ПечатнаяФорма"
```
---
name: mxl-validate
description: Валидация макета табличного документа (MXL). Используй после создания или модификации макета для проверки корректности
argument-hint: <TemplatePath> [-Detailed] [-MaxErrors 20]
allowed-tools:
- Bash
- Read
- Glob
---
# /mxl-validate — валидация макета табличного документа (MXL)
Проверяет Template.xml на структурные ошибки: индексы, ссылки на палитры, диапазоны именованных областей и объединений.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|---------------|:-----:|---------|--------------------------------------------|
| TemplatePath | да | — | Путь к макету (директория или Template.xml) |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 20 | Остановиться после N ошибок |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/mxl-validate.py" -TemplatePath "Catalogs/Номенклатура/Templates/Макет"
python "${CLAUDE_SKILL_DIR}/scripts/mxl-validate.py" -TemplatePath "src/МояОбработка/Templates/ПечатнаяФорма"
```
+109 -109
View File
@@ -1,109 +1,109 @@
---
name: role-compile
description: Создание роли 1С из описания прав. Используй когда нужно создать новую роль с набором прав на объекты
argument-hint: <JsonPath> <OutputDir>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /role-compile — генерация роли 1С из JSON DSL
Принимает JSON-определение роли → генерирует `Roles/Имя.xml` (метаданные) и `Roles/Имя/Ext/Rights.xml` (права). UUID автоматически.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `JsonPath` | Путь к JSON-определению роли |
| `OutputDir` | Корень выгрузки конфигурации (где `Configuration.xml`, `Roles/` и т.д.) |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/role-compile.ps1" -JsonPath "<json>" -OutputDir "<ConfigDir>"
```
Создаёт `{OutputDir}/Roles/Имя.xml` и `{OutputDir}/Roles/Имя/Ext/Rights.xml`. Регистрирует `<Role>` в `Configuration.xml`.
## JSON DSL
### Структура
```json
{ "name": "ИмяРоли", "synonym": "Отображаемое имя", "objects": [...], "templates": [...] }
```
Необязательные: `comment` (""), `setForNewObjects` (false), `setForAttributesByDefault` (true), `independentRightsOfChildObjects` (false).
### Shorthand-строки и объектная форма
```json
"objects": [
"Catalog.Номенклатура: @view",
"Document.Реализация: @edit",
"DataProcessor.Загрузка: @view",
"InformationRegister.Цены: Read, Update",
{ "name": "Document.Продажа", "preset": "view", "rights": {"Delete": false}, "rls": {"Read": "#Шаблон(\"\")"} }
]
```
- Shorthand: `"Тип.Имя: @пресет"` или `"Тип.Имя: Право1, Право2"`
- Объектная форма: `preset` + `rights` (переопределения) + `rls` (ограничения)
### Пресеты
| Пресет | Действие |
|--------|----------|
| `@view` | Просмотр — Read, View (+InputByString для справочников/документов; Use+View для обработок/отчётов) |
| `@edit` | Полное редактирование — CRUD + Interactive* + Posting (документы) |
`@` обязателен в shorthand. В объектной форме — `"preset": "view"` без `@`.
Для сервисов (WebService, HTTPService, IntegrationService) пресеты не определены — используй явные права: `"WebService.Имя: Use"`.
### Русские синонимы
Поддерживаются русские типы (`Справочник`→Catalog, `Документ`→Document) и права (`Чтение`→Read, `Просмотр`→View). Смешивание допустимо: `"Справочник.Контрагенты: Чтение, View"`.
### Шаблоны RLS
```json
"templates": [{"name": "ДляОбъекта(Мод)", "condition": "ГДЕ Организация = &ТекОрг"}]
```
Ссылка в `rls`: `"#ДляОбъекта(\"\")"`. Символ `&` автоматически экранируется в XML.
## Примеры
### Простая роль
```json
{
"name": "ЧтениеНоменклатуры", "synonym": "Чтение номенклатуры",
"objects": ["Catalog.Номенклатура: @view", "Catalog.Контрагенты: @view", "DataProcessor.Загрузка: @view"]
}
```
### Роль с RLS
```json
{
"name": "ЧтениеДокументовПоОрганизации",
"synonym": "Чтение документов (ограничение по организации)",
"objects": [
"Catalog.Организации: @view",
{"name": "Document.РеализацияТоваровУслуг", "preset": "view", "rls": {"Read": "#ДляОбъекта(\"\")"}}
],
"templates": [{"name": "ДляОбъекта(Модификатор)", "condition": "ГДЕ Организация = &ТекущаяОрганизация"}]
}
```
Подробные таблицы пресетов, русских синонимов и дополнительные примеры — в `dsl-reference.md`.
## Верификация
```
/role-validate <RightsPath> [MetadataPath] — проверка корректности XML, прав, RLS
/role-info <RightsPath> — визуальная сводка структуры
```
---
name: role-compile
description: Создание роли 1С из описания прав. Используй когда нужно создать новую роль с набором прав на объекты
argument-hint: <JsonPath> <OutputDir>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /role-compile — генерация роли 1С из JSON DSL
Принимает JSON-определение роли → генерирует `Roles/Имя.xml` (метаданные) и `Roles/Имя/Ext/Rights.xml` (права). UUID автоматически.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `JsonPath` | Путь к JSON-определению роли |
| `OutputDir` | Корень выгрузки конфигурации (где `Configuration.xml`, `Roles/` и т.д.) |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/role-compile.py" -JsonPath "<json>" -OutputDir "<ConfigDir>"
```
Создаёт `{OutputDir}/Roles/Имя.xml` и `{OutputDir}/Roles/Имя/Ext/Rights.xml`. Регистрирует `<Role>` в `Configuration.xml`.
## JSON DSL
### Структура
```json
{ "name": "ИмяРоли", "synonym": "Отображаемое имя", "objects": [...], "templates": [...] }
```
Необязательные: `comment` (""), `setForNewObjects` (false), `setForAttributesByDefault` (true), `independentRightsOfChildObjects` (false).
### Shorthand-строки и объектная форма
```json
"objects": [
"Catalog.Номенклатура: @view",
"Document.Реализация: @edit",
"DataProcessor.Загрузка: @view",
"InformationRegister.Цены: Read, Update",
{ "name": "Document.Продажа", "preset": "view", "rights": {"Delete": false}, "rls": {"Read": "#Шаблон(\"\")"} }
]
```
- Shorthand: `"Тип.Имя: @пресет"` или `"Тип.Имя: Право1, Право2"`
- Объектная форма: `preset` + `rights` (переопределения) + `rls` (ограничения)
### Пресеты
| Пресет | Действие |
|--------|----------|
| `@view` | Просмотр — Read, View (+InputByString для справочников/документов; Use+View для обработок/отчётов) |
| `@edit` | Полное редактирование — CRUD + Interactive* + Posting (документы) |
`@` обязателен в shorthand. В объектной форме — `"preset": "view"` без `@`.
Для сервисов (WebService, HTTPService, IntegrationService) пресеты не определены — используй явные права: `"WebService.Имя: Use"`.
### Русские синонимы
Поддерживаются русские типы (`Справочник`→Catalog, `Документ`→Document) и права (`Чтение`→Read, `Просмотр`→View). Смешивание допустимо: `"Справочник.Контрагенты: Чтение, View"`.
### Шаблоны RLS
```json
"templates": [{"name": "ДляОбъекта(Мод)", "condition": "ГДЕ Организация = &ТекОрг"}]
```
Ссылка в `rls`: `"#ДляОбъекта(\"\")"`. Символ `&` автоматически экранируется в XML.
## Примеры
### Простая роль
```json
{
"name": "ЧтениеНоменклатуры", "synonym": "Чтение номенклатуры",
"objects": ["Catalog.Номенклатура: @view", "Catalog.Контрагенты: @view", "DataProcessor.Загрузка: @view"]
}
```
### Роль с RLS
```json
{
"name": "ЧтениеДокументовПоОрганизации",
"synonym": "Чтение документов (ограничение по организации)",
"objects": [
"Catalog.Организации: @view",
{"name": "Document.РеализацияТоваровУслуг", "preset": "view", "rls": {"Read": "#ДляОбъекта(\"\")"}}
],
"templates": [{"name": "ДляОбъекта(Модификатор)", "condition": "ГДЕ Организация = &ТекущаяОрганизация"}]
}
```
Подробные таблицы пресетов, русских синонимов и дополнительные примеры — в `dsl-reference.md`.
## Верификация
```
/role-validate <RightsPath> [MetadataPath] — проверка корректности XML, прав, RLS
/role-info <RightsPath> — визуальная сводка структуры
```
+44 -44
View File
@@ -1,44 +1,44 @@
---
name: role-info
description: Компактная сводка прав роли 1С из Rights.xml — объекты, права, RLS, шаблоны ограничений. Используй для аудита прав — какие объекты и действия доступны, ограничения RLS
argument-hint: <RightsPath>
allowed-tools:
- Bash
- Read
---
# /role-info — анализ роли 1С
Парсит `Rights.xml` роли и выдаёт компактную сводку: объекты сгруппированы по типу, показаны только разрешённые права. Сжатие: тысячи строк XML → 50–150 строк текста.
## Использование
```
/role-info <RightsPath>
```
**RightsPath** — путь к файлу `Rights.xml` роли (обычно `Roles/ИмяРоли/Ext/Rights.xml`).
## Запуск скрипта
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/role-info.ps1" -RightsPath <path> -OutFile <output.txt>
```
### Параметры
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-RightsPath` | да | Путь к Rights.xml |
| `-ShowDenied` | нет | Показать запрещённые права (по умолчанию скрыты) |
| `-Limit` | нет | Макс. строк вывода (по умолчанию `150`). `0` = без ограничений |
| `-Offset` | нет | Пропустить N строк — для пагинации (по умолчанию `0`) |
| `-OutFile` | нет | Записать результат в файл (UTF-8 BOM). Без этого — вывод в консоль |
**Важно:** Всегда используй `-OutFile` и читай результат через Read tool. Прямой вывод в консоль через bash ломает кириллицу.
Для большой роли при усечении вывода:
```powershell
... -Offset 150 # пагинация: пропустить первые 150 строк
```
---
name: role-info
description: Компактная сводка прав роли 1С из Rights.xml — объекты, права, RLS, шаблоны ограничений. Используй для аудита прав — какие объекты и действия доступны, ограничения RLS
argument-hint: <RightsPath>
allowed-tools:
- Bash
- Read
---
# /role-info — анализ роли 1С
Парсит `Rights.xml` роли и выдаёт компактную сводку: объекты сгруппированы по типу, показаны только разрешённые права. Сжатие: тысячи строк XML → 50–150 строк текста.
## Использование
```
/role-info <RightsPath>
```
**RightsPath** — путь к файлу `Rights.xml` роли (обычно `Roles/ИмяРоли/Ext/Rights.xml`).
## Запуск скрипта
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/role-info.py" -RightsPath <path> -OutFile <output.txt>
```
### Параметры
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-RightsPath` | да | Путь к Rights.xml |
| `-ShowDenied` | нет | Показать запрещённые права (по умолчанию скрыты) |
| `-Limit` | нет | Макс. строк вывода (по умолчанию `150`). `0` = без ограничений |
| `-Offset` | нет | Пропустить N строк — для пагинации (по умолчанию `0`) |
| `-OutFile` | нет | Записать результат в файл (UTF-8 BOM). Без этого — вывод в консоль |
**Важно:** Всегда используй `-OutFile` и читай результат через Read tool. Прямой вывод в консоль через bash ломает кириллицу.
Для большой роли при усечении вывода:
```powershell
... -Offset 150 # пагинация: пропустить первые 150 строк
```
+27 -27
View File
@@ -1,27 +1,27 @@
---
name: role-validate
description: Валидация роли 1С. Используй после создания или модификации роли для проверки корректности
argument-hint: <RightsPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
---
# /role-validate — валидация роли 1С
Проверяет корректность `Rights.xml` роли: формат XML, namespace, глобальные флаги, типы объектов, имена прав, RLS-ограничения, шаблоны. Опционально проверяет метаданные роли (UUID, имя, синоним).
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|--------------|:-----:|---------|-------------------------------------------------|
| RightsPath | да | — | Путь к роли (директория или `Rights.xml`) |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Макс. ошибок до остановки (по умолчанию 30) |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/role-validate.ps1" -RightsPath "Roles/МояРоль"
```
---
name: role-validate
description: Валидация роли 1С. Используй после создания или модификации роли для проверки корректности
argument-hint: <RightsPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
---
# /role-validate — валидация роли 1С
Проверяет корректность `Rights.xml` роли: формат XML, namespace, глобальные флаги, типы объектов, имена прав, RLS-ограничения, шаблоны. Опционально проверяет метаданные роли (UUID, имя, синоним).
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|--------------|:-----:|---------|-------------------------------------------------|
| RightsPath | да | — | Путь к роли (директория или `Rights.xml`) |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Макс. ошибок до остановки (по умолчанию 30) |
| OutFile | нет | — | Записать результат в файл (UTF-8 BOM) |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/role-validate.py" -RightsPath "Roles/МояРоль"
```
+436 -416
View File
@@ -1,416 +1,436 @@
---
name: skd-compile
description: Компиляция схемы компоновки данных 1С (СКД) из компактного JSON-определения. Используй когда нужно создать СКД с нуля
argument-hint: "[-DefinitionFile <json> | -Value <json-string>] -OutputPath <Template.xml>"
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /skd-compile — генерация СКД из JSON DSL
Принимает JSON-определение схемы компоновки данных → генерирует Template.xml (DataCompositionSchema).
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `DefinitionFile` | Путь к JSON-файлу с определением СКД (взаимоисключающий с Value) |
| `Value` | JSON-строка с определением СКД (взаимоисключающий с DefinitionFile) |
| `OutputPath` | Путь к выходному Template.xml |
```powershell
# Из файла
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-compile.ps1" -DefinitionFile "<json>" -OutputPath "<Template.xml>"
# Из строки (без промежуточного файла)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-compile.ps1" -Value '<json-string>' -OutputPath "<Template.xml>"
```
## JSON DSL — краткий справочник
Справочник ниже. Все примеры компилируемы как есть.
### Корневая структура
```json
{
"dataSets": [...],
"calculatedFields": [...],
"totalFields": [...],
"parameters": [...],
"templates": [...],
"groupTemplates": [...],
"dataSetLinks": [...],
"settingsVariants": [...]
}
```
Умолчания: `dataSources` → авто `ИсточникДанных1/Local`; `settingsVariants` → авто "Основной" с деталями.
### Наборы данных
Тип по ключу: `query` → DataSetQuery, `objectName` → DataSetObject, `items` → DataSetUnion.
```json
{ "name": "Продажи", "query": "ВЫБРАТЬ ...", "fields": [...] }
```
Запрос поддерживает `@file` — ссылку на внешний .sql файл вместо inline-текста: `"query": "@queries/sales.sql"`. Путь разрешается относительно JSON-файла, затем CWD.
**DataSetObject** — внешний набор данных (без источника-запроса). Поля описываются явно; данные передаются вторым параметром `ПроцессорКомпоновкиДанных.Инициализировать(Макет, Новый Структура("<objectName>", ТЗ), ...)`.
```json
{ "name": "ЖурналОшибок", "objectName": "ЖурналОшибок", "fields": [
{ "field": "ТекстСообщения", "title": "Текст сообщения", "type": "string(150)" },
{ "field": "Расшифровка", "title": "Описание", "type": "CatalogRef.СтруктураПредприятия" }
]}
```
`name` — имя набора в схеме, `objectName` — ключ в структуре передачи данных.
### Поля — shorthand и объектная форма
```
"Наименование" — просто имя
"Количество: decimal(15,2)" — имя + тип
"Организация: CatalogRef.Организации @dimension" — + роль
"Служебное: string #noFilter #noOrder" — + ограничения
```
Объектная форма — когда нужен title или другие свойства:
```json
{ "field": "ОстатокНаНачалоПериода", "title": "Остаток на начало периода" }
```
`dataPath` автоматически берётся из `field`, если не указан явно.
Многоязычный заголовок: `"title": { "ru": "...", "en": "..." }`. Применимо везде, где принимается title/presentation (поля, calculatedFields, parameters, settingsVariants, availableValues и пр.). Строка эквивалентна `{ "ru": "..." }`.
Типы: `string`, `string(N)`, `decimal(D,F)`, `boolean`, `date`, `dateTime`, `CatalogRef.X`, `DocumentRef.X`, `EnumRef.X`, `StandardPeriod`. Ссылочные типы эмитируются с inline namespace `d5p1:` (`http://v8.1c.ru/8.1/data/enterprise/current-config`). Сборка EPF со ссылочными типами требует базу с соответствующей конфигурацией.
Составной тип (несколько типов значений) — массив в объектной форме: `"type": ["CatalogRef.A", "CatalogRef.B"]`. Квалификаторы (`(N)`, `(D,F)`) применяются к каждому элементу.
Роли: `@dimension`, `@account`, `@balance`, `@period`.
Ограничения: `#noField`, `#noFilter`, `#noGroup`, `#noOrder`.
В объектной форме: `"useRestriction": { "field": true, "condition": true, "group": true, "order": true }` или `"restrict": ["noField", "noFilter"]`.
Дополнительные ключи объектной формы:
- `"presentationExpression": "<выражение>"` — что показывать вместо значения поля. Исходное значение остаётся «под капотом» для перехода/расшифровки.
- `"appearance": { "<параметр>": "<значение>" }` — оформление колонки по умолчанию (применяется во всех вариантах настроек). Ключи — параметры платформы (`ГоризонтальноеПоложение`, `МинимальнаяШирина`, `Формат`, `Текст` и т.п.).
```json
{ "field": "Сумма", "title": "Сумма продажи", "type": "decimal(15,2)",
"appearance": { "ГоризонтальноеПоложение": "Right", "МинимальнаяШирина": "80" } }
```
### Вычисляемые поля (calculatedFields)
Shorthand: `"Имя [Заголовок]: тип = Выражение #noField #noFilter #noGroup #noOrder"` — все части кроме имени опциональны.
```json
"calculatedFields": [
"Маржа = Цена - Закупка",
"Наценка [Наценка, %]: decimal(10,2) = Маржа / Закупка * 100",
"Служебное: string = \"\" #noField #noFilter #noGroup #noOrder"
]
```
Объектная форма — когда нужна `appearance`:
```json
{ "name": "Маржа", "title": "Маржа", "expression": "Цена - Закупка", "type": "decimal(15,2)", "useRestriction": "#noField #noFilter" }
```
### Итоги (shorthand)
```json
"totalFields": ["Количество: Сумма", "Стоимость: Сумма(Кол * Цена)"]
```
### Параметры (shorthand + @autoDates)
```json
"parameters": [
"Период [Отчетный период]: StandardPeriod = LastMonth @autoDates"
]
```
Shorthand: `"Имя [Заголовок]: тип = значение @флаги"`. `[Заголовок]` опциональный — добавляет `<title>` (LocalStringType).
Флаги shorthand:
- `@autoDates` — добавляет к параметру StandardPeriod пару дат `НачалоПериода`/`КонецПериода`, вычисляемых из него. Используй их в тексте запроса как `&НачалоПериода`/`&КонецПериода`; пользователь выбирает только сам период. По умолчанию сам параметр получает `use=Always` и `denyIncompleteValues=true` (чтобы производные даты всегда были заполнены); в объектной форме можно явно переопределить.
- `@valueList``<valueListAllowed>true</valueListAllowed>` — разрешает передавать список значений
- `@hidden` — скрытый параметр: `availableAsField=false` + исключается из `"dataParameters": "auto"`
Объектная форма: `title`, `hidden: true`, `valueListAllowed: true`, `availableAsField: false`, `denyIncompleteValues: true`, `use: "Always"`.
Список допустимых значений (availableValues):
```json
{
"name": "ПорядокОкругления",
"type": "EnumRef.Округления",
"value": "Перечисление.Округления.Окр1_00",
"use": "Always",
"denyIncompleteValues": true,
"availableValues": [
{"value": "Перечисление.Округления.Окр1_00", "presentation": "руб. коп"},
{"value": "Перечисление.Округления.Окр1", "presentation": "руб."},
{"value": "Перечисление.Округления.Окр1000", "presentation": "тыс. руб"}
]
}
```
В варианте настроек `"dataParameters": "auto"` выводит все не-hidden параметры с `userSettingID`. Значения по умолчанию наследуются и остаются активными; параметры без значения по умолчанию отключаются (пользователь включит их в настройках).
### Фильтры — shorthand
```json
"filter": [
"Организация = _ @off @user",
"Дата >= 2024-01-01T00:00:00",
"Статус filled"
]
```
Формат: `"Поле оператор значение @флаги"`. Значение `_` = пустое (placeholder). Флаги: `@off` (use=false), `@user` (userSettingID=auto), `@quickAccess`, `@normal`, `@inaccessible`.
В объектной форме доступны: `viewMode`, `userSettingID`, `userSettingPresentation`.
Группы фильтров (Or/And/Not):
```json
{ "group": "Or", "items": [
{ "group": "And", "items": [
{ "field": "Статус", "op": "=", "value": "Активен" },
{ "field": "Сумма", "op": ">", "value": 1000 }
]},
{ "field": "Количество", "op": "filled" }
]}
```
### Параметры данных — shorthand
```json
"dataParameters": [
"Период = LastMonth @user",
"Организация @off @user"
]
```
Формат: `"Имя [= значение] @флаги"`. Для StandardPeriod варианты (LastMonth, ThisYear и т.д.) распознаются автоматически.
### Структура — string shorthand
```json
"structure": "Организация > details"
"structure": "Организация > Номенклатура > details"
```
`>` разделяет уровни группировки. `details` (или `детали`) = детальные записи. `selection` и `order` по умолчанию `["Auto"]` на каждом уровне.
Объектная форма — для сложных случаев (именованные группировки, selection/filter на уровне группировки, таблицы, диаграммы):
```json
"structure": [
{
"name": "ПоОрганизациям",
"groupFields": ["Организация"],
"selection": ["Организация", "Сумма", "Auto"],
"children": [{ "groupFields": [] }]
}
]
```
`type` по умолчанию `"group"` (можно не указывать). `groupFields` — алиас для `groupBy`. Поддержка `name`, `selection`, `order`, `filter`, `outputParameters`, рекурсивных `children`.
### Варианты настроек
```json
"settingsVariants": [{
"name": "Основной",
"title": "Продажи по организациям",
"settings": {
"selection": ["Номенклатура", "Количество", "Auto"],
"filter": ["Организация = _ @off @user"],
"order": ["Количество desc", "Auto"],
"conditionalAppearance": [
{
"filter": ["Просрочено = true"],
"appearance": { "ЦветТекста": "style:ПросроченныеДанныеЦвет" },
"presentation": "Выделять просроченные",
"viewMode": "Normal",
"userSettingID": "auto"
}
],
"outputParameters": { "Заголовок": "Мой отчёт" },
"dataParameters": ["Период = LastMonth @user"],
"structure": "Организация > details"
}
}]
```
### Условное оформление (conditionalAppearance)
```json
"conditionalAppearance": [
{
"selection": ["Поле1"],
"filter": [оле1 notFilled"],
"appearance": { "Текст": "Не указано", "ЦветТекста": "style:XXX" },
"presentation": "Описание",
"viewMode": "Normal",
"userSettingID": "auto"
}
]
```
Типы значений appearance: `style:XXX`/`web:XXX`/`win:XXX` → Color, `true`/`false` → Boolean, параметр `Формат`/`Текст`/`Заголовок` → LocalStringType, прочее → String.
Типы значений фильтра: `Перечисление.*`/`Справочник.*`/`ПланСчетов.*`/`Документ.*` → DesignTimeValue (автодетект).
OrGroup в фильтре: `{"group": "Or", "items": ["условие1", "условие2"]}`.
Folder в selection: `{"folder": "Поступление", "items": ["ПолеА", "ПолеБ"]}` → SelectedItemFolder с lwsTitle и placement=Auto.
### Итоги с привязкой к группировкам
```json
"totalFields": [
{ "dataPath": "Кол", "expression": "Сумма(Кол)", "group": ["Группа1", "Группа1 Иерархия", "ОбщийИтог"] }
]
```
### Шаблоны вывода — компактный DSL
Вместо raw XML (`template`) — табличное описание через `rows` + именованный стиль `style`:
```json
"templates": [
{
"name": "Макет1",
"style": "header",
"widths": [36, 33, 16, 17],
"minHeight": 24.75,
"rows": [
["Виды кассы", "Валюта", "Остаток на начало\nпериода", "Остаток на\nконец периода"],
["|", "|", "|", "|"],
["К1", "К2", "К3", "К4"]
]
},
{
"name": "Макет2",
"style": "data",
"widths": [36, 33, 16, 17],
"rows": [["{ВидКассы}", "{Валюта}", "{Остаток}", "{ОстатокКонец}"]],
"parameters": [
{ "name": "ВидКассы", "expression": "Представление(Счет)" },
{ "name": "Остаток", "expression": "ОстатокНаНачалоПериода" }
]
}
]
```
Синтаксис ячеек: `"текст"` — статика, `"{Имя}"` — параметр, `"|"` — объединение с ячейкой выше, `">"` — объединение с ячейкой слева, `null` — пустая.
Двухуровневая шапка с горизонтальным объединением:
```json
"rows": [
["Вид актива", "Остаток начало", "Поступление", ">", ">", ">", "Выбытие", ">", ">", "Остаток конец"],
["|", "|", "из произв.", "из п/ф", "со сч.40", "прочее", "Реализ.", "отгруж.", "прочее", "|"],
["К1", "К2", "К3", "К4", "К5", "К6", "К7", "К8", "К9", "К10"]
]
```
Встроенные стили: `header` (фон, центр, перенос), `data` (фон группы), `subheader` (без фона, центр), `total` (без фона). Все — Arial 10, рамки Solid 1px, цвета через стили платформы.
Пользовательские стили: файл `skd-styles.json` рядом с JSON-определением, в текущей директории, или в `presets/skills/skd/skd-styles.json` (поиск вверх от OutputPath). Первый найденный файл побеждает. Все допустимые ключи и формат цветов — в `examples/skd-styles.json`.
Raw XML (`"template": "<...>"`) остаётся как fallback. Детект: если есть `rows` — DSL, иначе — raw.
### Расшифровка (drilldown) в параметрах шаблона
Ключ `drilldown` в параметре шаблона автоматически генерирует `DetailsAreaTemplateParameter` и привязку `Расшифровка` в appearance ячеек:
```json
"parameters": [
{ "name": "Сырье", "expression": "ПоступлениеСырья", "drilldown": "ПоступлениеСырья" }
]
```
Генерирует: `ExpressionAreaTemplateParameter` (обычный) + `DetailsAreaTemplateParameter` с именем `Расшифровка_ПоступлениеСырья`, `fieldExpression` по полю `ИмяРесурса`, `mainAction=DrillDown`. Ячейки `{Сырье}` автоматически получают appearance `Расшифровка = Расшифровка_ПоступлениеСырья`.
### Привязки макетов к группировкам
```json
"groupTemplates": [
{ "groupName": "ДанныеОтчета", "templateType": "GroupHeader", "template": "Макет1" },
{ "groupField": "Счет", "templateType": "Header", "template": "Макет2" },
{ "groupField": "Счет", "templateType": "OverallHeader", "template": "Макет3" }
]
```
`groupField` привязка к полю группировки, `groupName` — к именованной группировке в структуре варианта.
`templateType`: `Header` (строки данных) → `<groupTemplate>`, `OverallHeader` (итоги) → `<groupTemplate>`, `GroupHeader` (шапка) → `<groupHeaderTemplate>`.
## Примеры
### Минимальный
```json
{
"dataSets": [{
"query": "ВЫБРАТЬ Номенклатура.Наименование КАК Наименование ИЗ Справочник.Номенклатура КАК Номенклатура",
"fields": ["Наименование"]
}]
}
```
### С запросом из внешнего файла (@file)
```json
{
"dataSets": [{
"query": "@queries/sales.sql",
"fields": ["Номенклатура: СправочникСсылка.Номенклатура @dimension", "Количество: число(15,3)", "Сумма: число(15,2)"]
}]
}
```
### С ресурсами, параметрами и @autoDates
```json
{
"dataSets": [{
"query": "ВЫБРАТЬ Продажи.Организация, Продажи.Номенклатура, Продажи.КоличествоОборот КАК Количество, Продажи.СуммаОборот КАК Сумма ИЗ РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК Продажи",
"fields": [
"Организация: СправочникСсылка.Организации @dimension",
"Номенклатура: СправочникСсылка.Номенклатура @dimension",
"Количество: число(15,3)",
"Сумма: число(15,2)"
]
}],
"totalFields": ["Количество: Сумма", "Сумма: Сумма"],
"parameters": ["Период: СтандартныйПериод = LastMonth @autoDates"],
"settingsVariants": [{
"name": "Основной",
"settings": {
"selection": ["Организация", "Номенклатура", "Количество", "Сумма"],
"filter": ["Организация = _ @off @user"],
"dataParameters": "auto",
"structure": "Организация > details"
}
}]
}
```
## Верификация
```
/skd-validate <OutputPath> — валидация структуры XML
/skd-info <OutputPath> — визуальная сводка
/skd-info <OutputPath> -Mode variant -Name 1 — проверка варианта настроек
```
---
name: skd-compile
description: Компиляция схемы компоновки данных 1С (СКД) из компактного JSON-определения. Используй когда нужно создать СКД с нуля
argument-hint: "[-DefinitionFile <json> | -Value <json-string>] -OutputPath <Template.xml>"
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /skd-compile — генерация СКД из JSON DSL
Принимает JSON-определение схемы компоновки данных → генерирует Template.xml (DataCompositionSchema).
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `DefinitionFile` | Путь к JSON-файлу с определением СКД (взаимоисключающий с Value) |
| `Value` | JSON-строка с определением СКД (взаимоисключающий с DefinitionFile) |
| `OutputPath` | Путь к выходному Template.xml |
```powershell
# Из файла
python "${CLAUDE_SKILL_DIR}/scripts/skd-compile.py" -DefinitionFile "<json>" -OutputPath "<Template.xml>"
# Из строки (без промежуточного файла)
python "${CLAUDE_SKILL_DIR}/scripts/skd-compile.py" -Value '<json-string>' -OutputPath "<Template.xml>"
```
## JSON DSL — краткий справочник
Справочник ниже. Все примеры компилируемы как есть.
### Корневая структура
```json
{
"dataSets": [...],
"calculatedFields": [...],
"totalFields": [...],
"parameters": [...],
"templates": [...],
"groupTemplates": [...],
"dataSetLinks": [...],
"settingsVariants": [...]
}
```
Умолчания: `dataSources` → авто `ИсточникДанных1/Local`; `settingsVariants` → авто "Основной" с деталями.
### Наборы данных
Тип по ключу: `query` → DataSetQuery, `objectName` → DataSetObject, `items` → DataSetUnion.
```json
{ "name": "Продажи", "query": "ВЫБРАТЬ ...", "fields": [...] }
```
Запрос поддерживает `@file` — ссылку на внешний .sql файл вместо inline-текста: `"query": "@queries/sales.sql"`. Путь разрешается относительно JSON-файла, затем CWD.
**DataSetObject** — внешний набор данных (без источника-запроса). Поля описываются явно; данные передаются вторым параметром `ПроцессорКомпоновкиДанных.Инициализировать(Макет, Новый Структура("<objectName>", ТЗ), ...)`.
```json
{ "name": "ЖурналОшибок", "objectName": "ЖурналОшибок", "fields": [
{ "field": "ТекстСообщения", "title": "Текст сообщения", "type": "string(150)" },
{ "field": "Расшифровка", "title": "Описание", "type": "CatalogRef.СтруктураПредприятия" }
]}
```
`name` — имя набора в схеме, `objectName` — ключ в структуре передачи данных.
### Поля — shorthand и объектная форма
```
"Наименование" — просто имя
"Количество: decimal(15,2)" — имя + тип
"Организация: CatalogRef.Организации @dimension" — + роль
"Служебное: string #noFilter #noOrder" — + ограничения
```
Объектная форма — когда нужен title или другие свойства:
```json
{ "field": "ОстатокНаНачалоПериода", "title": "Остаток на начало периода" }
```
`dataPath` автоматически берётся из `field`, если не указан явно.
Многоязычный заголовок: `"title": { "ru": "...", "en": "..." }`. Применимо везде, где принимается title/presentation (поля, calculatedFields, parameters, settingsVariants, availableValues и пр.). Строка эквивалентна `{ "ru": "..." }`.
Типы: `string`, `string(N)`, `decimal`, `decimal(D)`, `decimal(D,F)`, `boolean`, `date`, `dateTime`, `CatalogRef.X`, `DocumentRef.X`, `EnumRef.X`, `StandardPeriod`. Ссылочные типы эмитируются с inline namespace `d5p1:` (`http://v8.1c.ru/8.1/data/enterprise/current-config`). Сборка EPF со ссылочными типами требует базу с соответствующей конфигурацией.
`decimal` без скобок = `10,2` (деньги по умолчанию), `decimal(N)` = `N,0` (целое); `,nonneg` в конце скобок → AllowedSign=Nonnegative.
Составной тип (несколько типов значений) — массив в объектной форме: `"type": ["CatalogRef.A", "CatalogRef.B"]`. Квалификаторы (`(N)`, `(D,F)`) применяются к каждому элементу.
Роли (shorthand или объект):
- `@`-флаги: `@dimension`, `@account`, `@balance`, `@period`, `@required`, `@autoOrder`, `@ignoreNullValues`
- KV: `balanceGroupName`, `balanceType` (`OpeningBalance`/`ClosingBalance`), `parentDimension`, `accountTypeExpression`, `expression`, `orderType` (`Asc`/`Desc`), `periodNumber`, `periodType`
```
"Сумма: decimal(15,2) @balance balanceGroupName=Сумма balanceType=OpeningBalance"
```
Ограничения: `#noField`, `#noFilter`, `#noGroup`, `#noOrder`.
В объектной форме: `"useRestriction": { "field": true, "condition": true, "group": true, "order": true }` или `"restrict": ["noField", "noFilter"]`.
Дополнительные ключи объектной формы:
- `"presentationExpression": "<выражение>"` — что показывать вместо значения поля. Исходное значение остаётся «под капотом» для перехода/расшифровки.
- `"appearance": { "<параметр>": "<значение>" }` — оформление колонки по умолчанию (применяется во всех вариантах настроек). Ключи — параметры платформы (`ГоризонтальноеПоложение`, `МинимальнаяШирина`, `Формат`, `Текст` и т.п.).
- `"orderExpression": { "expression": "<выражение>", "orderType": "Asc"/"Desc", "autoOrder": true/false }` — сортировка поля по выражению (например `ЕстьNULL(Поле.Порядок, 10000)`).
```json
{ "field": "Сумма", "title": "Сумма продажи", "type": "decimal(15,2)",
"appearance": { "ГоризонтальноеПоложение": "Right", "МинимальнаяШирина": "80" } }
```
### Вычисляемые поля (calculatedFields)
Shorthand: `"Имя [Заголовок]: тип = Выражение #noField #noFilter #noGroup #noOrder"` — все части кроме имени опциональны.
```json
"calculatedFields": [
"Маржа = Цена - Закупка",
"Наценка [Наценка, %]: decimal(10,2) = Маржа / Закупка * 100",
"Служебное: string = \"\" #noField #noFilter #noGroup #noOrder"
]
```
Объектная форма — когда нужна `appearance`:
```json
{ "name": "Маржа", "title": "Маржа", "expression": "Цена - Закупка", "type": "decimal(15,2)", "useRestriction": "#noField #noFilter" }
```
### Итоги (shorthand)
```json
"totalFields": ["Количество: Сумма", "Стоимость: Сумма(Кол * Цена)"]
```
### Параметры (shorthand + @autoDates)
```json
"parameters": [
"Период [Отчетный период]: StandardPeriod = LastMonth @autoDates"
]
```
Shorthand: `"Имя [Заголовок]: тип = значение @флаги"`. `[Заголовок]` опциональный — добавляет `<title>` (LocalStringType).
Флаги shorthand:
- `@autoDates` — добавляет к параметру StandardPeriod пару дат `НачалоПериода`/`КонецПериода`, вычисляемых из него. Используй их в тексте запроса как `&НачалоПериода`/`&КонецПериода`; пользователь выбирает только сам период. По умолчанию сам параметр получает `use=Always` и `denyIncompleteValues=true` (чтобы производные даты всегда были заполнены); в объектной форме можно явно переопределить.
- `@valueList``<valueListAllowed>true</valueListAllowed>` — разрешает передавать список значений (при значении-списке ниже подразумевается автоматически)
- `@hidden` — скрытый параметр: `availableAsField=false` + исключается из `"dataParameters": "auto"`
Объектная форма: `title`, `hidden: true`, `valueListAllowed: true`, `availableAsField: false`, `denyIncompleteValues: true`, `use: "Always"`.
Значение-список: несколько значений по умолчанию через запятую в `значение` (для запятой внутри значения — кавычки `'...'`). В объектной форме — массив в `value`.
```json
"parameters": [
"Виды: ChartOfCharacteristicTypesRef.ВидыСубконтоХозрасчетные = ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты, ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры"
]
```
Если значения по умолчанию нет — пропусти `=` в shorthand или укажи `"value": null` в объектной форме.
Список допустимых значений (availableValues):
```json
{
"name": "ПорядокОкругления",
"type": "EnumRef.Округления",
"value": "Перечисление.Округления.Окр1_00",
"use": "Always",
"denyIncompleteValues": true,
"availableValues": [
{"value": "Перечисление.Округления.Окр1_00", "presentation": "руб. коп"},
{"value": "Перечисление.Округления.Окр1", "presentation": "руб."},
{"value": "Перечисление.Округления.Окр1000", "presentation": "тыс. руб"}
]
}
```
В варианте настроек `"dataParameters": "auto"` выводит все не-hidden параметры с `userSettingID`. Значения по умолчанию наследуются и остаются активными; параметры без значения по умолчанию отключаются (пользователь включит их в настройках).
### Фильтры — shorthand
```json
"filter": [
"Организация = _ @off @user",
"Дата >= 2024-01-01T00:00:00",
"Статус filled"
]
```
Формат: `"Поле оператор значение @флаги"`. Значение `_` = пустое (placeholder). Флаги: `@off` (use=false), `@user` (userSettingID=auto), `@quickAccess`, `@normal`, `@inaccessible`.
В объектной форме доступны: `viewMode`, `userSettingID`, `userSettingPresentation`.
Группы фильтров (Or/And/Not):
```json
{ "group": "Or", "items": [
{ "group": "And", "items": [
{ "field": "Статус", "op": "=", "value": "Активен" },
{ "field": "Сумма", "op": ">", "value": 1000 }
]},
{ "field": "Количество", "op": "filled" }
]}
```
### Параметры данных — shorthand
```json
"dataParameters": [
"Период = LastMonth @user",
"Организация @off @user"
]
```
Формат: `"Имя [= значение] @флаги"`. Для StandardPeriod варианты (LastMonth, ThisYear и т.д.) распознаются автоматически.
### Структура — string shorthand
```json
"structure": "Организация > details"
"structure": "Организация > Номенклатура > details"
```
`>` разделяет уровни группировки. `details` (или `детали`) = детальные записи. `selection` и `order` по умолчанию `["Auto"]` на каждом уровне.
Объектная форма — для сложных случаев (именованные группировки, selection/filter на уровне группировки, таблицы, диаграммы):
```json
"structure": [
{
"name": "ПоОрганизациям",
"groupFields": ["Организация"],
"selection": ["Организация", "Сумма", "Auto"],
"children": [{ "groupFields": [] }]
}
]
```
`type` по умолчанию `"group"` (можно не указывать). `groupFields` — алиас для `groupBy`. Поддержка `name`, `selection`, `order`, `filter`, `outputParameters`, рекурсивных `children`.
### Варианты настроек
```json
"settingsVariants": [{
"name": "Основной",
"title": "Продажи по организациям",
"settings": {
"selection": ["Номенклатура", "Количество", "Auto"],
"filter": ["Организация = _ @off @user"],
"order": ["Количество desc", "Auto"],
"conditionalAppearance": [
{
"filter": [росрочено = true"],
"appearance": { "ЦветТекста": "style:ПросроченныеДанныеЦвет" },
"presentation": "Выделять просроченные",
"viewMode": "Normal",
"userSettingID": "auto"
}
],
"outputParameters": { "Заголовок": "Мой отчёт" },
"dataParameters": ["Период = LastMonth @user"],
"structure": "Организация > details"
}
}]
```
### Условное оформление (conditionalAppearance)
```json
"conditionalAppearance": [
{
"selection": ["Поле1"],
"filter": ["Поле1 notFilled"],
"appearance": { "Текст": "Не указано", "ЦветТекста": "style:XXX" },
"presentation": "Описание",
"viewMode": "Normal",
"userSettingID": "auto"
}
]
```
Типы значений appearance: `style:XXX`/`web:XXX`/`win:XXX` → Color, `true`/`false` → Boolean, параметр `Формат`/`Текст`/`Заголовок` → LocalStringType, прочее → String.
Типы значений фильтра: `Перечисление.*`/`Справочник.*`/`ПланСчетов.*`/`Документ.*` → DesignTimeValue (автодетект).
OrGroup в фильтре: `{"group": "Or", "items": ["условие1", "условие2"]}`.
Folder в selection: `{"folder": "Поступление", "items": ["ПолеА", "ПолеБ"]}` → SelectedItemFolder с lwsTitle и placement=Auto.
### Итоги с привязкой к группировкам
```json
"totalFields": [
{ "dataPath": "Кол", "expression": "Сумма(Кол)", "group": ["Группа1", "Группа1 Иерархия", "ОбщийИтог"] }
]
```
### Шаблоны вывода — компактный DSL
Вместо raw XML (`template`) — табличное описание через `rows` + именованный стиль `style`:
```json
"templates": [
{
"name": "Макет1",
"style": "header",
"widths": [36, 33, 16, 17],
"minHeight": 24.75,
"rows": [
["Виды кассы", "Валюта", "Остаток на начало\nпериода", "Остаток на\nконец периода"],
["|", "|", "|", "|"],
["К1", "К2", "К3", "К4"]
]
},
{
"name": "Макет2",
"style": "data",
"widths": [36, 33, 16, 17],
"rows": [["{ВидКассы}", "{Валюта}", "{Остаток}", "{ОстатокКонец}"]],
"parameters": [
{ "name": "ВидКассы", "expression": "Представление(Счет)" },
{ "name": "Остаток", "expression": "ОстатокНаНачалоПериода" }
]
}
]
```
Синтаксис ячеек: `"текст"` — статика, `"{Имя}"` — параметр, `"|"` — объединение с ячейкой выше, `">"` — объединение с ячейкой слева, `null` — пустая.
Двухуровневая шапка с горизонтальным объединением:
```json
"rows": [
["Вид актива", "Остаток начало", "Поступление", ">", ">", ">", "Выбытие", ">", ">", "Остаток конец"],
["|", "|", "из произв.", "из п/ф", "со сч.40", "прочее", "Реализ.", "отгруж.", "прочее", "|"],
["К1", "К2", "К3", "К4", "К5", "К6", "К7", "К8", "К9", "К10"]
]
```
Встроенные стили: `header` (фон, центр, перенос), `data` (фон группы), `subheader` (без фона, центр), `total` (без фона). Все — Arial 10, рамки Solid 1px, цвета через стили платформы.
Пользовательские стили: файл `skd-styles.json` рядом с JSON-определением, в текущей директории, или в `presets/skills/skd/skd-styles.json` (поиск вверх от OutputPath). Первый найденный файл побеждает. Все допустимые ключи и формат цветов — в `examples/skd-styles.json`.
Raw XML (`"template": "<...>"`) остаётся как fallback. Детект: если есть `rows` — DSL, иначе — raw.
### Расшифровка (drilldown) в параметрах шаблона
Ключ `drilldown` в параметре шаблона автоматически генерирует `DetailsAreaTemplateParameter` и привязку `Расшифровка` в appearance ячеек:
```json
"parameters": [
{ "name": "Сырье", "expression": "ПоступлениеСырья", "drilldown": "ПоступлениеСырья" }
]
```
Генерирует: `ExpressionAreaTemplateParameter` (обычный) + `DetailsAreaTemplateParameter` с именем `Расшифровка_ПоступлениеСырья`, `fieldExpression` по полю `ИмяРесурса`, `mainAction=DrillDown`. Ячейки `{Сырье}` автоматически получают appearance `Расшифровка = Расшифровка_ПоступлениеСырья`.
### Привязки макетов к группировкам
```json
"groupTemplates": [
{ "groupName": "ДанныеОтчета", "templateType": "GroupHeader", "template": "Макет1" },
{ "groupField": "Счет", "templateType": "Header", "template": "Макет2" },
{ "groupField": "Счет", "templateType": "OverallHeader", "template": "Макет3" }
]
```
`groupField` — привязка к полю группировки, `groupName` — к именованной группировке в структуре варианта.
`templateType`: `Header` (строки данных) → `<groupTemplate>`, `OverallHeader` (итоги) → `<groupTemplate>`, `GroupHeader` (шапка) → `<groupHeaderTemplate>`.
## Примеры
### Минимальный
```json
{
"dataSets": [{
"query": "ВЫБРАТЬ Номенклатура.Наименование КАК Наименование ИЗ Справочник.Номенклатура КАК Номенклатура",
"fields": ["Наименование"]
}]
}
```
### С запросом из внешнего файла (@file)
```json
{
"dataSets": [{
"query": "@queries/sales.sql",
"fields": ["Номенклатура: СправочникСсылка.Номенклатура @dimension", "Количество: число(15,3)", "Сумма: число(15,2)"]
}]
}
```
### С ресурсами, параметрами и @autoDates
```json
{
"dataSets": [{
"query": "ВЫБРАТЬ Продажи.Организация, Продажи.Номенклатура, Продажи.КоличествоОборот КАК Количество, Продажи.СуммаОборот КАК Сумма ИЗ РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК Продажи",
"fields": [
"Организация: СправочникСсылка.Организации @dimension",
"Номенклатура: СправочникСсылка.Номенклатура @dimension",
"Количество: число(15,3)",
"Сумма: число(15,2)"
]
}],
"totalFields": ["Количество: Сумма", "Сумма: Сумма"],
"parameters": ["Период: СтандартныйПериод = LastMonth @autoDates"],
"settingsVariants": [{
"name": "Основной",
"settings": {
"selection": ["Организация", "Номенклатура", "Количество", "Сумма"],
"filter": ["Организация = _ @off @user"],
"dataParameters": "auto",
"structure": "Организация > details"
}
}]
}
```
## Верификация
```
/skd-validate <OutputPath> — валидация структуры XML
/skd-info <OutputPath> — визуальная сводка
/skd-info <OutputPath> -Mode variant -Name 1 — проверка варианта настроек
```
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
---
name: skd-decompile
description: Декомпиляция схемы компоновки данных 1С (СКД) в JSON-черновик в формате skd-compile. Используй для scaffold нового отчёта по образцу или структурного рефакторинга. Не для точечных правок
argument-hint: <TemplatePath> [-OutputPath <out.json>]
disable-model-invocation: true
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /skd-decompile — JSON-черновик из Template.xml СКД
Читает Template.xml и эмитит JSON в формате `skd-compile`. **Результат — черновик**, а не обратимое представление: см. раздел «Что получаешь».
## Когда использовать
- **Scaffold нового отчёта по образцу** — взять существующий СКД, получить JSON, поправить и скомпилировать в новый.
- **Структурный рефакторинг** — переписать вариант, перерисовать шаблон, перебрать набор полей.
## Когда **не** использовать
- **Точечные правки готового отчёта** (добавить поле, фильтр, итог, переименовать) → `/skd-edit`. Цикл «декомпиляция → правка JSON → компиляция» переписывает шаблон целиком, может терять непокрытые конструкции и даёт большой diff в исходниках. `/skd-edit` правит адресно, без полной реконструкции.
## Параметры
| Параметр | Описание |
|----------|----------|
| `TemplatePath` | Путь к Template.xml (обязательный) |
| `OutputPath` | Путь к выходному JSON. Если не задан — JSON в stdout |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/skd-decompile.py" -TemplatePath "<Template.xml>" -OutputPath "<out.json>"
```
## Что получаешь
JSON-черновик в формате `/skd-compile`**не полное обратимое представление СКД**. На вход компилятору такой JSON напрямую может не пойти: в нём встречаются sentinel-узлы (маркер `__unsupported__`).
- **Готовые узлы** — большая часть СКД (поля, параметры, шаблоны, варианты со structure/filter/order/conditionalAppearance и т.п.) ложится в JSON как обычные узлы DSL.
- **Sentinel-узлы** — места, где встретилась конструкция, которую декомпилятор не умеет выразить в DSL. JSON остаётся валидным, но компилятор откажется его собирать, пока sentinel не **заменён ручной реализацией** (явный raw `template`, прописанный appearance и т.п.) **или не удалён**, если в новом отчёте конструкция не нужна. Это намеренный барьер — чтобы непокрытое не уехало в финальный отчёт незамеченным.
- **`<basename>.warnings.md`** рядом с `OutputPath` — список всех sentinel-узлов с координатами в исходнике, по нему удобно обходить места под ручную доработку.
- **Критичные конструкции** (Picture cells, ХранилищеЗначения, вложенные схемы, не-СКД root) — скрипт падает с ненулевым кодом и сообщением в stderr; такой Template как образец не годится.
## Workflow
1. `/skd-decompile <Template.xml> -OutputPath draft.json` — получить черновик.
2. Открыть `draft.warnings.md`, посмотреть, что не покрылось.
3. Поправить JSON под задачу. Sentinel-узлы — заменить на ручную реализацию (через явный raw `template`, через ручное описание appearance и т.п.) либо удалить, если конструкция в новом отчёте не нужна.
4. `/skd-compile -DefinitionFile draft.json -OutputPath new-Template.xml` — собрать обратно.
5. `/skd-validate` + `/skd-info` — проверить.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+373 -361
View File
@@ -1,361 +1,373 @@
---
name: skd-edit
description: Точечное редактирование схемы компоновки данных 1С (СКД). Используй когда нужно модифицировать существующую СКД — добавить поля, итоги, фильтры, параметры, изменить текст запроса
argument-hint: <TemplatePath> -Operation <op> -Value <value>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /skd-edit — точечное редактирование СКД (Template.xml)
Атомарные операции модификации существующей схемы компоновки данных: добавление, удаление и модификация полей, итогов, фильтров, параметров, настроек варианта, управление структурой, замена запроса.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `TemplatePath` | Путь к Template.xml (или к папке — автодополнение Ext/Template.xml) |
| `Operation` | Операция (см. список ниже) |
| `Value` | Значение операции (shorthand-строка или текст запроса) |
| `DataSet` | (опц.) Имя набора данных (умолч. первый) |
| `Variant` | (опц.) Имя варианта настроек (умолч. первый) |
| `NoSelection` | (опц.) Не добавлять поле в selection варианта |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-edit.ps1" -TemplatePath "<path>" -Operation <op> -Value "<value>"
```
## Пакетный режим (batch)
Несколько значений в одном вызове через разделитель `;;`:
```powershell
-Operation add-field -Value "Цена: decimal(15,2) ;; Количество: decimal(15,3) ;; Сумма: decimal(15,2)"
```
Работает для всех операций кроме `set-query`, `set-structure` и `add-dataSet`.
## Операции
### add-field — добавить поле в набор данных
Shorthand: `"Имя [Заголовок]: тип @роль #ограничение"`.
```
"Цена: decimal(15,2)"
"Организация [Орг-ция]: CatalogRef.Организации @dimension"
"Служебное: string #noFilter #noOrder"
```
Поле добавляется в набор и в selection варианта (если нет `-NoSelection`). Дубликат dataPath — предупреждение, пропуск.
### add-total — добавить итог
Shorthand: `"<dataPath>: <выражение>"`. Если выражение — известная аггрегатная функция без скобок (`Сумма`, `Количество`, `Минимум`, `Максимум`, `Среднее`), оно автоматически оборачивается в `Func(dataPath)`. Если функция со скобками или произвольное выражение — используется как есть.
```
"Цена: Среднее" # → Среднее(Цена)
"Стоимость: Сумма(Кол * Цена)" # → как есть
"Проверка: Проверка" # identity: выражение = Проверка
```
### add-calculated-field — добавить вычисляемое поле
Shorthand: `"Имя [Заголовок]: тип = Выражение #noFilter #noOrder #noGroup"`.
```
"Маржа = Продажа - Закупка"
"Наценка [Наценка, %]: decimal(10,2) = Маржа / Закупка * 100"
"Служебное: string = \"\" #noFilter #noOrder #noGroup"
```
`#noFilter`, `#noOrder`, `#noGroup`, `#noField``<useRestriction>` (аналогично add-field).
Также добавляется в selection варианта.
### add-parameter — добавить параметр
```
"Период [Отчетный период]: StandardPeriod = LastMonth @autoDates"
"Организация: CatalogRef.Организации"
```
Shorthand: `"Имя [Заголовок]: тип = значение [availableValue=список] [@флаги]"`. `[Заголовок]` опциональный — добавляет `<title>`.
Флаги:
- `@autoDates` — генерирует пару скрытых параметров `ДатаНачала`/`ДатаОкончания` для StandardPeriod-параметра.
- `@hidden` — скрывает параметр от пользовательских настроек (для параметров-констант, используемых в запросе).
- `@always` — параметр всегда подставляется в запрос. Часто вместе с `@hidden`, но используется и отдельно (для видимых обязательных параметров типа отчётного периода).
```
"ПС: CatalogRef.Контрагенты = Справочник.Контрагенты.ПустаяСсылка @hidden"
"Период: StandardPeriod = LastMonth @always"
"ПСчет: ChartOfAccountsRef.Хозрасчетный = ПланСчетов.Хозрасчетный.X @hidden @always"
"Округление: EnumRef.Округления = Окр1 availableValue=Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс."
```
`availableValue=` задаёт начальный список допустимых значений. Формат списка: `v1[: p1], v2[: p2], ...` — элементы через `,`, представление после `:`. Если в значении или представлении встречается `,` или `:` — оборачивай в одинарные кавычки `'...'`:
```
"Округление: ... = Окр1 availableValue=Окр1_00: 'руб., коп.', Окр1: руб."
```
### modify-parameter — изменить существующий параметр
Shorthand: `"ИмяПараметра [Заголовок] [ключ=значение]... [@флаги]"`. Находит параметр по имени, обновляет указанные свойства.
```
"ПорядокОкругления use=Always"
"ПорядокОкругления [Округление сумм] denyIncompleteValues=true"
"ПериодОтчета [Отчетный период]" # только title
"ПорядокОкругления availableValue=Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс."
"СчетПС value=ПланСчетов.Хозрасчетный.КассаПредприятия"
"Контрагент @hidden @always"
```
`[Заголовок]` опциональный — устанавливает или заменяет `<title>`. Можно вызывать без других kv-пар, чтобы только обновить title.
`availableValue=` **заменяет весь список** допустимых значений (старые удаляются). Формат и кавычки — те же, что в `add-parameter`.
`value=` заменяет значение параметра (тип значения подбирается автоматически по объявленному типу параметра).
Флаги `@hidden` / `@always` — те же, что и в `add-parameter`. Идемпотентны.
### rename-parameter — переименовать параметр
Shorthand: `"OldName => NewName"`. Атомарно обновляет имя параметра, ссылки `&Имя` в выражениях других параметров (только полные совпадения, `&ПериодX` не задевается), и записи в `dataParameters` всех вариантов. Текст запроса не трогает — переименование строго в области параметров.
```
"Период => ПериодОтчета"
```
### reorder-parameters — переставить параметры в указанном порядке
Shorthand: `"Имя1, Имя2, Имя3"`. Частичный список — указанные параметры идут первыми в заданном порядке, остальные сохраняют исходный порядок и идут в конце. Параметры из списка, которых нет в схеме — warning, пропуск.
```
"ПериодОтчета, НачалоПериода, КонецПериода"
```
### add-filter — добавить фильтр в вариант
Shorthand: `"Поле оператор значение @флаги"`. Флаги: `@off` (use=false), `@user` (userSettingID=auto), `@quickAccess`, `@normal`, `@inaccessible`.
```
"Номенклатура = _ @off @user"
"Дата >= 2024-01-01T00:00:00"
"Статус filled"
```
### add-dataParameter — добавить параметр данных в вариант
Shorthand: `"Имя [= значение] @флаги"`.
```
"Период = LastMonth @user"
"Организация @off @user"
```
### add-order — добавить сортировку
Shorthand: `"Поле [desc]"`. По умолчанию asc. `Auto` — авто-элемент.
```
"Количество desc"
"Auto"
```
### add-selection — добавить элемент выборки
```
"Номенклатура"
"Auto"
"Folder(Поступление: ПолеА, ПолеБ, ПолеВ)"
```
`Folder(Название: поле1, поле2)` — группа полей (SelectedItemFolder) с заголовком и `placement=Auto`.
`@group=ИмяГруппировки` — добавить в selection именованной группировки (вместо уровня варианта):
```
"Folder(Поступление: ПолеА, ПолеБ) @group=ДанныеОтчета"
```
### add-dataSetLink — добавить связь наборов данных
Shorthand: `"Источник > Приёмник on ВырИсточника = ВырПриёмника [param Имя]"`.
```
"Набор1 > Набор2 on Поле1 = Поле2"
"Набор1 > Набор2 on Поле1 = Поле2 [param Связь]"
```
### add-dataSet — добавить набор данных
Shorthand: `"Имя: ТЕКСТ_ЗАПРОСА"` или `"ТЕКСТ_ЗАПРОСА"` (авто-имя `НаборДанныхN`).
```
"Доп: ВЫБРАТЬ 1 КАК Тест"
"ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура"
"Продажи: @queries/sales.sql"
```
`dataSource` берётся из первого существующего. Дубликат имени — предупреждение, пропуск. Не поддерживает пакетный режим (запрос может содержать `;;`).
### add-variant — добавить вариант настроек
Shorthand: `"Имя [Представление]"`. Представление опционально, по умолчанию = имя.
```
"Детальный"
"Детальный [Детальный отчёт]"
```
Создаёт вариант с Auto selection + detail group. Дубликат имени — предупреждение, пропуск.
### add-conditionalAppearance — добавить условное оформление
Shorthand: `"Параметр = значение [when условие] [for Поле1, Поле2]"`. Блок `when` — синтаксис `add-filter` (Поле оператор значение).
```
"ЦветТекста = web:Red when Сумма < 0"
"ЦветФона = web:LightGreen when Статус = Одобрен for Статус"
"МинимальнаяШирина = 50 for Организация"
"Формат = ЧДЦ=2 for Цена, Сумма"
```
Типы значений appearance (автодетект): `web:*`/`style:*`/`win:*` → Color, `true`/`false` → Boolean, параметр `Формат`/`Текст`/`Заголовок` → LocalStringType, иначе String.
Типы значений фильтра (автодетект): `Перечисление.*`/`Справочник.*`/`ПланСчетов.*`/`Документ.*` → DesignTimeValue, `true`/`false` → Boolean, дата → DateTime, числа → Decimal, иначе String.
OrGroup: несколько условий через ` or ` в `when` объединяются в FilterItemGroup/OrGroup:
```
"Формат = ЧЦ=15; ЧДЦ=0 when ПараметрыДанных.Округление = Перечисление.Округления.Окр1 or ПараметрыДанных.Округление = Перечисление.Округления.Окр1000"
```
**Важно**: для параметров данных используйте префикс `ПараметрыДанных.` в поле фильтра.
### add-drilldown — подключить расшифровку к ресурсам в шаблонах
Value — имена ресурсов (как в полях/вычисляемых полях СКД) через запятую.
```
"ПоступлениеИзПроизводства, ВыбытиеПрочее"
"Сумма_Дт83, Сумма_Дт99, Сумма_68, Сумма_84"
```
Подключает DrillDown по `ИмяРесурса` ко всем шаблонам, содержащим указанные ресурсы. Идемпотентно.
### set-query — заменить текст запроса
Не поддерживает пакетный режим. Value — полный текст запроса или `@path/to/file.sql` (ссылка на внешний файл). Путь разрешается относительно Template.xml, затем CWD.
### patch-query — точечная замена в тексте запроса
Shorthand: `"старое => новое [@once]"`. По умолчанию заменяет все вхождения подстроки. Поддерживает пакетный режим и `-DataSet`.
```
"СубконтоДт1) В => СубконтоКт1) В"
"КАК ВТ_СтароеИмя => КАК ВТ_НовоеИмя @once"
```
`@once` — упасть с ошибкой, если в запросе не **ровно одно** вхождение. Защищает от случайных замен в комментариях и однотипных идентификаторах.
Многострочные подстроки поддерживаются — переводы строк в `старое`/`новое` сравниваются буквально (включая отступы).
### set-outputParameter — установить параметр вывода
```
"Заголовок = Мой отчёт"
"ВыводитьЗаголовок = true"
```
Если параметр уже существует — заменяет значение.
### set-structure — установить структуру варианта
Shorthand: `"Поле1 > Поле2 > details"`. `>` — вложенный уровень группировки, `,` — несколько полей в одном уровне, `details` — детальные записи. **Заменяет всю структуру полностью** (включая Selection/order/filter/conditionalAppearance каждой группы). Для точечной модификации полей группировки с сохранением настроек — используй `modify-structure`. Не поддерживает пакетный режим.
```
"Организация > Номенклатура > details"
"Валюта, НаименованиеБанка, ИНН"
"details"
"СчетМеждународногоУчета @name=ДанныеОтчета"
```
`@name=Имя` — присваивает имя группировке (`<dcsset:name>`). Используется для привязки шаблонов через `groupName`.
### modify-structure — изменить поля группировки существующей группы
Тот же shorthand что и `set-structure`. Находит группу по `@name=`, заменяет только `<groupItems>` (поля группировки). Selection/order/filter/conditionalAppearance/outputParameters группы сохраняются. Без `@name=` — ошибка.
```
"Валюта @name=ДанныеОтчета"
"Валюта, НаименованиеБанка @name=ДанныеОтчета"
"details @name=ДанныеОтчета"
```
### modify-field — изменить существующее поле
Тот же shorthand что и `add-field`. Находит по dataPath, объединяет свойства (непустые переопределяют), сохраняет позицию.
```
"Цена [Цена USD]: decimal(10,4) @dimension"
```
### set-field-role — установить роль поля
Shorthand: `"<dataPath> [@флаги] [kv=значение]"`. **Полностью заменяет** роль поля. Если в значении только dataPath без флагов/kv — удаляет роль.
```
"Сумма" # снять роль полностью
"СуммаОстаток @balance" # простая балансовая роль
"СуммаНач @balance balanceGroupName=Сумма balanceType=OpeningBalance" # с уточнением
"Контрагент @dimension parentDimension=Группа"
"Период @period" # роль периода
```
Флаги: `@balance`, `@dimension`, `@account`, `@period`, `@required`, `@autoOrder`, `@ignoreNullValues`.
KV: `balanceGroupName`, `balanceType` (OpeningBalance/ClosingBalance), `parentDimension`, `accountTypeExpression`, `orderType` (Asc/Desc), `expression`, `periodNumber`, `periodType`.
Поддерживает пакетный режим (`;;`).
### modify-filter — изменить существующий фильтр
Тот же shorthand что и `add-filter`. Находит по полю, обновляет оператор/значение/флаги. См. правило для `<use>` ниже.
### modify-dataParameter — изменить параметр данных
Тот же shorthand что и `add-dataParameter`. Находит по имени, обновляет значение/флаги. См. правило для `<use>` ниже.
#### Правило `<use>` для modify-filter / modify-dataParameter
В отличие от `add-*`, в `modify-*` поле `<use>` обновляется **только если флаг задан явно**:
- `@off` — установить `<use>false</use>`
- `@on` — убрать существующий `<use>false</use>` (включить параметр)
- ни `@off`, ни `@on` не задано — `<use>` не трогается, существующее значение сохраняется (важно: это значит, что отключённый параметр останется отключённым после модификации других свойств)
### remove-* и clear-*
| Операция | Value | Действие |
|----------|-------|----------|
| `remove-field` | dataPath | Удаляет поле из набора + из selection варианта |
| `remove-total` | dataPath | Удаляет итог |
| `remove-calculated-field` | dataPath | Удаляет вычисляемое поле + из selection |
| `remove-parameter` | name | Удаляет параметр |
| `remove-filter` | поле | Удаляет первый фильтр с указанным полем |
| `clear-selection` | `*` | Очищает все элементы selection |
| `clear-order` | `*` | Очищает все элементы order |
| `clear-filter` | `*` | Очищает все элементы filter |
| `clear-conditionalAppearance` | `*` | Очищает все правила условного оформления |
## Верификация
```
/skd-validate <TemplatePath> — валидация структуры после редактирования
/skd-info <TemplatePath> — визуальная сводка
```
---
name: skd-edit
description: Точечное редактирование схемы компоновки данных 1С (СКД). Используй когда нужно модифицировать существующую СКД — добавить поля, итоги, фильтры, параметры, изменить текст запроса
argument-hint: <TemplatePath> -Operation <op> -Value <value>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /skd-edit — точечное редактирование СКД (Template.xml)
Атомарные операции модификации существующей схемы компоновки данных: добавление, удаление и модификация полей, итогов, фильтров, параметров, настроек варианта, управление структурой, замена запроса.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `TemplatePath` | Путь к Template.xml (или к папке — автодополнение Ext/Template.xml) |
| `Operation` | Операция (см. список ниже) |
| `Value` | Значение операции (shorthand-строка или текст запроса) |
| `DataSet` | (опц.) Имя набора данных (умолч. первый) |
| `Variant` | (опц.) Имя варианта настроек (умолч. первый) |
| `NoSelection` | (опц.) Не добавлять поле в selection варианта |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/skd-edit.py" -TemplatePath "<path>" -Operation <op> -Value "<value>"
```
## Пакетный режим (batch)
Несколько значений в одном вызове через разделитель `;;`:
```powershell
-Operation add-field -Value "Цена: decimal(15,2) ;; Количество: decimal(15,3) ;; Сумма: decimal(15,2)"
```
Работает для всех операций кроме `set-query`, `set-structure` и `add-dataSet`.
## Операции
### add-field — добавить поле в набор данных
Shorthand: `"Имя [Заголовок]: тип @роль #ограничение"`.
```
"Цена: decimal(15,2)"
"Организация [Орг-ция]: CatalogRef.Организации @dimension"
"Служебное: string #noFilter #noOrder"
```
Поле добавляется в набор и в selection варианта (если нет `-NoSelection`). Дубликат dataPath — предупреждение, пропуск.
Чтобы поле попало в selection не варианта, а конкретной группировки структуры — используй `-NoSelection` и затем `add-selection "Имя @group=ИмяГруппы"`.
### add-total — добавить итог
Shorthand: `"<dataPath>: <выражение>"`. Если выражение — известная аггрегатная функция без скобок (`Сумма`, `Количество`, `Минимум`, `Максимум`, `Среднее`), оно автоматически оборачивается в `Func(dataPath)`. Если функция со скобками или произвольное выражение — используется как есть.
```
"Цена: Среднее" # → Среднее(Цена)
"Стоимость: Сумма(Кол * Цена)" # → как есть
"Проверка: Проверка" # identity: выражение = Проверка
```
### add-calculated-field — добавить вычисляемое поле
Shorthand: `"Имя [Заголовок]: тип = Выражение #noFilter #noOrder #noGroup"`.
```
"Маржа = Продажа - Закупка"
"Наценка [Наценка, %]: decimal(10,2) = Маржа / Закупка * 100"
"Служебное: string = \"\" #noFilter #noOrder #noGroup"
```
`#noFilter`, `#noOrder`, `#noGroup`, `#noField``<useRestriction>` (аналогично add-field).
Также добавляется в selection варианта.
### add-parameter — добавить параметр
```
"Период [Отчетный период]: StandardPeriod = LastMonth @autoDates"
"Организация: CatalogRef.Организации"
```
Shorthand: `"Имя [Заголовок]: тип = значение [availableValue=список] [@флаги]"`. `[Заголовок]` опциональный — добавляет `<title>`.
Флаги:
- `@autoDates` — генерирует пару скрытых параметров `ДатаНачала`/`ДатаОкончания` для StandardPeriod-параметра.
- `@hidden` — скрывает параметр от пользовательских настроек (для параметров-констант, используемых в запросе).
- `@always` — параметр всегда подставляется в запрос. Часто вместе с `@hidden`, но используется и отдельно (для видимых обязательных параметров типа отчётного периода).
- `@valueList` — разрешает передавать в параметр список значений (при значении-списке ниже подразумевается автоматически, отдельно указывать не обязательно).
Значение-список: несколько значений по умолчанию задаются через запятую в `значение`. Для запятой внутри одного значения — кавычки `'...'`.
```
"Виды [Виды субконто]: ChartOfCharacteristicTypesRef.ВидыСубконтоХозрасчетные = ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты, ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры"
```
```
"ПС: CatalogRef.Контрагенты = Справочник.Контрагенты.ПустаяСсылка @hidden"
"Период: StandardPeriod = LastMonth @always"
"ПСчет: ChartOfAccountsRef.Хозрасчетный = ПланСчетов.Хозрасчетный.X @hidden @always"
"Округление: EnumRef.Округления = Окр1 availableValue=Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс."
```
`availableValue=` задаёт начальный список допустимых значений. Формат списка: `v1[: p1], v2[: p2], ...` — элементы через `,`, представление после `:`. Если в значении или представлении встречается `,` или `:` — оборачивай в одинарные кавычки `'...'`:
```
"Округление: ... = Окр1 availableValue=Окр1_00: 'руб., коп.', Окр1: руб."
```
### modify-parameter — изменить существующий параметр
Shorthand: `"ИмяПараметра [Заголовок] [ключ=значение]... [@флаги]"`. Находит параметр по имени, обновляет указанные свойства.
```
"ПорядокОкругления use=Always"
"ПорядокОкругления [Округление сумм] denyIncompleteValues=true"
"ПериодОтчета [Отчетный период]" # только title
"ПорядокОкругления availableValue=Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс."
"СчетПС value=ПланСчетов.Хозрасчетный.КассаПредприятия"
"Виды value=ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты, ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры"
"Контрагент @hidden @always"
```
`[Заголовок]` опциональный — устанавливает или заменяет `<title>`. Можно вызывать без других kv-пар, чтобы только обновить title.
`availableValue=` **заменяет весь список** допустимых значений (старые удаляются). Формат и кавычки — те же, что в `add-parameter`.
`value=` заменяет значение параметра. Несколько значений через запятую → **список значений** (заменяет все прежние); для запятой внутри значения — кавычки `'...'`.
Флаги `@hidden` / `@always` — те же, что и в `add-parameter`. Идемпотентны.
### rename-parameter — переименовать параметр
Shorthand: `"OldName => NewName"`. Атомарно обновляет имя параметра, ссылки `&Имя` в выражениях других параметров (только полные совпадения, `&ПериодX` не задевается), и записи в `dataParameters` всех вариантов. Текст запроса не трогает — переименование строго в области параметров.
```
"Период => ПериодОтчета"
```
### reorder-parameters — переставить параметры в указанном порядке
Shorthand: `"Имя1, Имя2, Имя3"`. Частичный список — указанные параметры идут первыми в заданном порядке, остальные сохраняют исходный порядок и идут в конце. Параметры из списка, которых нет в схеме — warning, пропуск.
```
"ПериодОтчета, НачалоПериода, КонецПериода"
```
### add-filter — добавить фильтр в вариант
Shorthand: `"Поле оператор значение @флаги"`. Флаги: `@off` (use=false), `@user` (userSettingID=auto), `@quickAccess`, `@normal`, `@inaccessible`.
```
"Номенклатура = _ @off @user"
"Дата >= 2024-01-01T00:00:00"
"Статус filled"
```
### add-dataParameter — добавить параметр данных в вариант
Shorthand: `"Имя [= значение] @флаги"`.
```
"Период = LastMonth @user"
"Организация @off @user"
```
### add-order — добавить сортировку
Shorthand: `"Поле [desc]"`. По умолчанию asc. `Auto` — авто-элемент.
```
"Количество desc"
"Auto"
```
### add-selection — добавить элемент выборки
```
"Номенклатура"
"Auto"
"Folder(Поступление: ПолеА, ПолеБ, ПолеВ)"
```
`Folder(Название: поле1, поле2)` — группа полей (SelectedItemFolder) с заголовком и `placement=Auto`.
`@group=ИмяГруппировки` — добавить в selection именованной группировки (вместо уровня варианта):
```
"Folder(Поступление: ПолеА, ПолеБ) @group=ДанныеОтчета"
```
### add-dataSetLink — добавить связь наборов данных
Shorthand: `"Источник > Приёмник on ВырИсточника = ВырПриёмника [param Имя]"`.
```
"Набор1 > Набор2 on Поле1 = Поле2"
"Набор1 > Набор2 on Поле1 = Поле2 [param Связь]"
```
### add-dataSet — добавить набор данных
Shorthand: `"Имя: ТЕКСТ_ЗАПРОСА"` или `"ТЕКСТ_ЗАПРОСА"` (авто-имя `НаборДанныхN`).
```
"Доп: ВЫБРАТЬ 1 КАК Тест"
"ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура"
"Продажи: @queries/sales.sql"
```
`dataSource` берётся из первого существующего. Дубликат имени — предупреждение, пропуск. Не поддерживает пакетный режим (запрос может содержать `;;`).
### add-variant — добавить вариант настроек
Shorthand: `"Имя [Представление]"`. Представление опционально, по умолчанию = имя.
```
"Детальный"
"Детальный [Детальный отчёт]"
```
Создаёт вариант с Auto selection + detail group. Дубликат имени — предупреждение, пропуск.
### add-conditionalAppearance — добавить условное оформление
Shorthand: `"Параметр = значение [when условие] [for Поле1, Поле2]"`. Блок `when` — синтаксис `add-filter` (Поле оператор значение).
```
"ЦветТекста = web:Red when Сумма < 0"
"ЦветФона = web:LightGreen when Статус = Одобрен for Статус"
"МинимальнаяШирина = 50 for Организация"
"Формат = ЧДЦ=2 for Цена, Сумма"
```
Типы значений appearance (автодетект): `web:*`/`style:*`/`win:*` → Color, `true`/`false` → Boolean, параметр `Формат`/`Текст`/`Заголовок` → LocalStringType, иначе String.
Типы значений фильтра (автодетект): `Перечисление.*`/`Справочник.*`/`ПланСчетов.*`/`Документ.*` → DesignTimeValue, `true`/`false` → Boolean, дата → DateTime, числа → Decimal, иначе String.
OrGroup: несколько условий через ` or ` в `when` объединяются в FilterItemGroup/OrGroup:
```
"Формат = ЧЦ=15; ЧДЦ=0 when ПараметрыДанных.Округление = Перечисление.Округления.Окр1 or ПараметрыДанных.Округление = Перечисление.Округления.Окр1000"
```
**Важно**: для параметров данных используйте префикс `ПараметрыДанных.` в поле фильтра.
### add-drilldown — подключить расшифровку к ресурсам в шаблонах
Value — имена ресурсов (как в полях/вычисляемых полях СКД) через запятую.
```
"ПоступлениеИзПроизводства, ВыбытиеПрочее"
"Сумма_Дт83, Сумма_Дт99, Сумма_68, Сумма_84"
```
Подключает DrillDown по `ИмяРесурса` ко всем шаблонам, содержащим указанные ресурсы. Идемпотентно.
### set-query — заменить текст запроса
Не поддерживает пакетный режим. Value — полный текст запроса или `@path/to/file.sql` (ссылка на внешний файл). Путь разрешается относительно Template.xml, затем CWD.
Когда что: **существенная переработка** (добавить поля, соединения, переписать пакет) → выгрузи запрос через `/skd-info <tpl> -Mode query -Name <набор> -Raw -OutFile file.sql`, отредактируй файл, верни `set-query @file`. `-Raw` отдаёт запрос целиком без декораций, поэтому выгрузка ↔ возврат точны (включая многопакетные запросы). **Точечная замена** (переименовать идентификатор, заменить подстроку) → выгрузка не нужна, используй `patch-query` ниже.
### patch-query — точечная замена в тексте запроса
Shorthand: `"старое => новое [@once]"`. По умолчанию заменяет все вхождения подстроки. Поддерживает пакетный режим и `-DataSet`.
```
"СубконтоДт1) В => СубконтоКт1) В"
"КАК ВТ_СтароеИмя => КАК ВТ_НовоеИмя @once"
```
`@once` — упасть с ошибкой, если в запросе не **ровно одно** вхождение. Защищает от случайных замен в комментариях и однотипных идентификаторах.
Многострочные подстроки поддерживаются.
### set-outputParameter — установить параметр вывода
```
"Заголовок = Мой отчёт"
"ВыводитьЗаголовок = true"
```
Если параметр уже существует — заменяет значение.
### set-structure — установить структуру варианта
Shorthand: `"Поле1 > Поле2 > details"`. `>` — вложенный уровень группировки, `,` — несколько полей в одном уровне, `details` — детальные записи. **Заменяет всю структуру полностью** (включая Selection/order/filter/conditionalAppearance каждой группы). Для точечной модификации полей группировки с сохранением настроек — используй `modify-structure`. Не поддерживает пакетный режим.
```
"Организация > Номенклатура > details"
"Валюта, НаименованиеБанка, ИНН"
"details"
"СчетМеждународногоУчета @name=ДанныеОтчета"
```
`@name=Имя` — присваивает имя группировке (`<dcsset:name>`). Используется для привязки шаблонов через `groupName`.
### modify-structure — изменить поля группировки существующей группы
Тот же shorthand что и `set-structure`. Находит группу по `@name=`, заменяет только `<groupItems>` (поля группировки). Selection/order/filter/conditionalAppearance/outputParameters группы сохраняются. Без `@name=` — ошибка.
```
"Валюта @name=ДанныеОтчета"
"Валюта, НаименованиеБанка @name=ДанныеОтчета"
"details @name=ДанныеОтчета"
```
### modify-field — изменить существующее поле
Тот же shorthand что и `add-field`. Находит по dataPath, объединяет свойства (непустые переопределяют), сохраняет позицию.
```
"Цена [Цена USD]: decimal(10,4) @dimension"
```
### set-field-role — установить роль поля
Shorthand: `"<dataPath> [@флаги] [kv=значение]"`. **Полностью заменяет** роль поля. Если в значении только dataPath без флагов/kv — удаляет роль.
```
"Сумма" # снять роль полностью
"СуммаОстаток @balance" # простая балансовая роль
"СуммаНач @balance balanceGroupName=Сумма balanceType=OpeningBalance" # с уточнением
"Контрагент @dimension parentDimension=Группа"
"Период @period" # роль периода
```
Флаги: `@balance`, `@dimension`, `@account`, `@period`, `@required`, `@autoOrder`, `@ignoreNullValues`.
KV: `balanceGroupName`, `balanceType` (OpeningBalance/ClosingBalance), `parentDimension`, `accountTypeExpression`, `orderType` (Asc/Desc), `expression`, `periodNumber`, `periodType`.
Поддерживает пакетный режим (`;;`).
### modify-filter — изменить существующий фильтр
Тот же shorthand что и `add-filter`. Находит по полю, обновляет оператор/значение/флаги. См. правило для `<use>` ниже.
### modify-dataParameter — изменить параметр данных
Тот же shorthand что и `add-dataParameter`. Находит по имени, обновляет значение/флаги. См. правило для `<use>` ниже.
#### Правило `<use>` для modify-filter / modify-dataParameter
В отличие от `add-*`, в `modify-*` поле `<use>` обновляется **только если флаг задан явно**:
- `@off` — установить `<use>false</use>`
- `@on` — убрать существующий `<use>false</use>` (включить параметр)
- ни `@off`, ни `@on` не задано — `<use>` не трогается, существующее значение сохраняется (важно: это значит, что отключённый параметр останется отключённым после модификации других свойств)
### remove-* и clear-*
| Операция | Value | Действие |
|----------|-------|----------|
| `remove-field` | dataPath | Удаляет поле из набора + из selection варианта |
| `remove-total` | dataPath | Удаляет итог |
| `remove-calculated-field` | dataPath | Удаляет вычисляемое поле + из selection |
| `remove-parameter` | name | Удаляет параметр |
| `remove-filter` | поле | Удаляет первый фильтр с указанным полем |
| `clear-selection` | `*` | Очищает все элементы selection |
| `clear-order` | `*` | Очищает все элементы order |
| `clear-filter` | `*` | Очищает все элементы filter |
| `clear-conditionalAppearance` | `*` | Очищает все правила условного оформления |
## Верификация
```
/skd-validate <TemplatePath> — валидация структуры после редактирования
/skd-info <TemplatePath> — визуальная сводка
```
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+80 -75
View File
@@ -1,75 +1,80 @@
---
name: skd-info
description: Анализ структуры схемы компоновки данных 1С (СКД) — наборы, поля, параметры, варианты. Используй для понимания отчёта — источник данных (запрос), доступные поля, параметры
argument-hint: <TemplatePath> [-Mode overview|query|fields|links|calculated|resources|params|variant|templates|trace|full] [-Name <dataset|variant|field|group>]
allowed-tools:
- Bash
- Read
- Glob
---
# /skd-info — Анализ схемы компоновки данных
Читает Template.xml схемы компоновки данных (СКД) и выводит компактную сводку. Заменяет необходимость читать тысячи строк XML.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `TemplatePath` | Путь к Template.xml или каталогу макета (авто-резолв в `Ext/Template.xml`) |
| `Mode` | Режим анализа (по умолчанию `overview`) |
| `Name` | Имя набора (query), поля (fields/calculated/resources/trace), варианта (variant) или группировки/поля (templates) |
| `Batch` | Номер пакета запроса, 0 = все (только query) |
| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк) |
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-info.ps1" -TemplatePath "<путь>"
```
С указанием режима:
```powershell
... -Mode query -Name НоменклатураСЦенами
... -Mode query -Name ДанныеТ13 -Batch 3
... -Mode fields -Name КадастроваяСтоимость
... -Mode calculated -Name КоэффициентКи
... -Mode resources -Name СуммаНалога
... -Mode trace -Name "Коэффициент Ки"
... -Mode variant -Name 1
... -Mode templates
... -Mode templates -Name ВидНалоговойБазы
```
## Режимы
| Режим | Без `-Name` | С `-Name` |
|-------|-------------|-----------|
| `overview` | Навигационная карта схемы + подсказки Next | — |
| `query` | — | Текст запроса набора (с оглавлением батчей) |
| `fields` | Карта: имена полей по наборам | Деталь поля: набор, тип, роль, формат |
| `links` | Все связи наборов | — |
| `calculated` | Карта: имена вычисляемых полей | Выражение + заголовок + ограничения |
| `resources` | Карта: имена ресурсов (`*` = групповые формулы) | Формулы агрегации по группировкам |
| `params` | Таблица параметров: тип, значение, видимость | — |
| `variant` | Список вариантов | Структура группировок + фильтры + вывод |
| `templates` | Карта привязок шаблонов (field/group) | Содержимое шаблона: строки, ячейки, выражения |
| `trace` | — | Полная цепочка: набор → вычисление → ресурс |
| `full` | Полная сводка: overview + query + fields + resources + params + variant | — |
Паттерн: без `-Name` — карта/индекс, с `-Name` — деталь конкретного элемента. Режим `full` объединяет 6 ключевых режимов в один вызов.
## Типичный workflow
1. `overview` — понять структуру, увидеть подсказки
2. `trace -Name <поле>` — узнать как считается колонка отчёта (от заголовка до запроса за один вызов)
3. `query -Name <набор>` — посмотреть текст SQL-запроса
4. `variant -Name <N>`посмотреть группировки и фильтры варианта
Подробные примеры вывода каждого режима — в `modes-reference.md`.
## Верификация
```
/skd-info <path> — overview (точка входа)
/skd-info <path> -Mode trace -Name <field> — трассировка поля
```
---
name: skd-info
description: Анализ структуры схемы компоновки данных 1С (СКД) — наборы, поля, параметры, варианты. Используй для понимания отчёта — источник данных (запрос), доступные поля, параметры
argument-hint: <TemplatePath> [-Mode overview|query|fields|links|calculated|resources|params|variant|templates|trace|full] [-Name <dataset|variant|field|group>] [-Raw]
allowed-tools:
- Bash
- Read
- Glob
---
# /skd-info — Анализ схемы компоновки данных
Читает Template.xml схемы компоновки данных (СКД) и выводит компактную сводку. Заменяет необходимость читать тысячи строк XML.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `TemplatePath` | Путь к Template.xml или каталогу макета (авто-резолв в `Ext/Template.xml`) |
| `Mode` | Режим анализа (по умолчанию `overview`) |
| `Name` | Имя набора (query), поля (fields/calculated/resources/trace), варианта (variant) или группировки/поля (templates) |
| `Batch` | Номер пакета запроса, 0 = все (только query) |
| `Raw` | (только query) сырой текст запроса целиком, без заголовков/оглавления/разделителей пакетов. Для выгрузки в `.sql` и возврата через `skd-edit set-query @file` |
| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк; `-Raw` не усекается) |
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/skd-info.py" -TemplatePath "<путь>"
```
С указанием режима:
```powershell
... -Mode query -Name НоменклатураСЦенами
... -Mode query -Name ДанныеТ13 -Batch 3
... -Mode query -Name ДанныеТ13 -Raw -OutFile query.sql
... -Mode fields -Name КадастроваяСтоимость
... -Mode calculated -Name КоэффициентКи
... -Mode resources -Name СуммаНалога
... -Mode trace -Name "Коэффициент Ки"
... -Mode variant -Name 1
... -Mode templates
... -Mode templates -Name ВидНалоговойБазы
```
## Режимы
| Режим | Без `-Name` | С `-Name` |
|-------|-------------|-----------|
| `overview` | Навигационная карта схемы + подсказки Next | — |
| `query` | — | Текст запроса набора (с оглавлением батчей); `-Raw` — чистая выгрузка для правки |
| `fields` | Карта: имена полей по наборам | Деталь поля: набор, тип, роль, формат |
| `links` | Все связи наборов | — |
| `calculated` | Карта: имена вычисляемых полей | Выражение + заголовок + ограничения |
| `resources` | Карта: имена ресурсов (`*` = групповые формулы) | Формулы агрегации по группировкам |
| `params` | Таблица параметров: тип, значение, видимость | — |
| `variant` | Список вариантов | Структура группировок + фильтры + вывод |
| `templates` | Карта привязок шаблонов (field/group) | Содержимое шаблона: строки, ячейки, выражения |
| `trace` | — | Полная цепочка: набор → вычисление → ресурс |
| `full` | Полная сводка: overview + query + fields + resources + params + variant | — |
Паттерн: без `-Name` — карта/индекс, с `-Name` — деталь конкретного элемента. Режим `full` объединяет 6 ключевых режимов в один вызов.
## Типичный workflow
1. `overview` — понять структуру, увидеть подсказки
2. `trace -Name <поле>`узнать как считается колонка отчёта (от заголовка до запроса за один вызов)
3. `query -Name <набор>` — посмотреть текст SQL-запроса
4. `variant -Name <N>` — посмотреть группировки и фильтры варианта
Переработка запроса (round-trip): `query -Name <набор> -Raw -OutFile q.sql`
правка `q.sql``/skd-edit <tpl> -Operation set-query -Value "@q.sql"`. Флаг
`-Raw` отдаёт запрос целиком без декораций, поэтому выгрузка ↔ возврат
точны (включая многопакетные запросы с временными таблицами).
## Верификация
```
/skd-info <path> — overview (точка входа)
/skd-info <path> -Mode trace -Name <field> — трассировка поля
```
-246
View File
@@ -1,246 +0,0 @@
# /skd-info — полная справка по режимам
Компактное описание — в [SKILL.md](SKILL.md).
## overview (по умолчанию) — карта схемы
Компактная навигационная карта (10-25 строк). Показывает структуру и подсказывает следующие шаги:
```
=== DCS: ОсновнаяСхемаКомпоновкиДанных (362 lines) ===
Sources: ИсточникДанных1 (Local)
Datasets:
[Query] НоменклатураСЦенами 7 fields, query 40 lines
Calculated: 1
Resources: 1
Templates: 1 templates, 1 group bindings
Params: (none)
Variants:
[1] НоменклатураИЦены "Номенклатура и цены" Table(detail) 3 filters
[2] НоменклатураБезЦен "Номенклатура без цен" Group(detail) 2 filters
Next:
-Mode query query text
-Mode fields field tables by dataset
-Mode calculated calculated field expressions
-Mode resources resource aggregation
-Mode variant -Name <N> variant structure (1..2)
```
Для DataSetUnion — дерево наборов + связи:
```
Datasets:
[Union] РасчетНалогаНаИмущество 52 fields
├─ [Query] РасчетНалогаНаИмущество 51 fields, query 181 lines
├─ [Query] ДанныеПоКадастровой 29 fields, query 40 lines
├─ [Query] ДанныеПоСреднегодовой 34 fields, query 41 lines
Links: РасчетНалогаНаИмущество -> СостояниеОС (2 fields)
```
Параметры разделяются на видимые/скрытые:
```
Params: 18 (7 visible, 11 hidden): Период, Ответственный, ...
```
## query — текст запроса
`-Name <набор>` — имя DataSet (обязателен если наборов > 1).
Извлекает raw-текст запроса с деэкранированием XML (`&amp;``&`, `&gt;``>`). Для пакетных запросов — оглавление батчей:
```
=== Query: ДанныеТ13 (334 lines, 13 batches) ===
Batch 1: lines 1-8 → ПОМЕСТИТЬ Представления_Периоды
Batch 2: lines 9-26 → ПОМЕСТИТЬ Представления_СотрудникиОрганизации
...
--- Batch 1 ---
ВЫБРАТЬ
ДАТАВРЕМЯ(1, 1, 1) КАК Период
ПОМЕСТИТЬ Представления_Периоды
...
```
Фильтр по номеру батча: `-Batch 3` покажет только 3-й пакет.
## fields — поля наборов данных
Без `-Name` — карта: имена полей по наборам:
```
=== Fields map ===
СостояниеОС [Query] (3): Организация, ОсновноеСредство, ДатаСостояния
РасчетНалогаНаИмущество [Union] (52): ДоляСтоимостиЧислитель, ...
РасчетНалогаНаИмущество [Query] (51): КадастроваяСтоимость, ...
```
С `-Name <поле>` — детали конкретного поля:
```
=== Field: ДатаСостояния "Дата ввода в эксплуатацию" ===
Dataset: СостояниеОС [Query]
Format: ДФ=dd.MM.yyyy
```
Показывает: dataset, title, type, role, useRestriction, format, presentationExpression.
## links — связи наборов данных
```
=== Links (4) ===
РасчетНалогаНаИмущество -> СостояниеОС :
Организация -> Организация
ОсновноеСредство -> ОсновноеСредство
```
Группирует по парам наборов. Показывает поля связи и параметры.
## calculated — вычисляемые поля
Без `-Name` — карта: имена и заголовки:
```
=== Calculated fields (23) ===
ДоляСтоимости "Доля стоимости"
КоэффициентКи "Коэффициент Ки"
...
```
С `-Name <поле>` — полное выражение:
```
=== Calculated: ДоляСтоимости ===
Expression:
ВЫБОР КОГДА ... ТОГДА "1" ИНАЧЕ ... КОНЕЦ
Title: Доля стоимости
Restrict: condition
```
## resources — ресурсы (итоги по группировкам)
Без `-Name` — карта: имена полей, `*` = есть формулы по группировкам:
```
=== Resources (51) ===
НалоговаяБаза
КоэффициентКи *
...
* = has group-level formulas
```
С `-Name <поле>` — формулы агрегации:
```
=== Resource: ДатаСостояния ===
[ОсновноеСредство] ЕстьNull(ДатаСостояния, "")
```
## params — параметры схемы
```
=== Parameters (16) ===
Name Type Default Visible Expression
Период StandardPeriod LastMonth yes -
НачалоПериода DateTime - hidden &Период.ДатаНачала
Организация CatalogRef.Организации null yes -
```
## variant — варианты отчёта
Без `-Name` — список вариантов:
```
=== Variants (2) ===
[1] НоменклатураИЦены "Номенклатура и цены" Table(detail) 3 filters
[2] НоменклатураБезЦен "Номенклатура без цен" Group(detail) 2 filters
```
С `-Name <N|имя>` — структура конкретного варианта:
```
=== Variant [1]: НоменклатураИЦены "Номенклатура и цены" ===
Structure:
Table "Таблица"
├── Columns: [ТипЦен Items]
│ Selection: Auto, Цена
└── Rows: [Номенклатура Items]
Selection: Номенклатура, УИД, Auto
Filter:
[ ] Номенклатура InHierarchy [user]
[ ] ТипЦен Equal
[x] ВАрхиве = false "Исключая скрытые товары"
DataParams: КлючВарианта="НоменклатураИЦены"
Output: style=ЧерноБелый groups=Separately totalsH=None totalsV=None
```
## templates — привязки шаблонов вывода
Три типа привязок: `fieldTemplate` (к полю), `groupTemplate` (к группировке, Header/Footer), `groupHeaderTemplate` (заголовок группы).
Без `-Name` — карта привязок:
```
=== Templates (70 defined: 49 field, 37 group) ===
Field bindings (49): (all trivial)
ОстаточнаяСтоимостьНа0101, ОстаточнаяСтоимостьНа0102, ...
Group bindings (37):
ВидНалоговойБазы
Header -> Макет3 (1 rows, 1 params)
СреднегодоваяСтоимость2019
Footer -> Макет50 (1 rows) spacer
GroupHeader -> Макет40 (3 rows)
```
С `-Name <группировка|поле>` — содержимое шаблонов:
```
=== Templates: СреднегодоваяСтоимость2019 ===
Footer -> Макет50 [1 rows, 1 cells]:
Row 1: (empty)
GroupHeader -> Макет40 [3 rows, 78 cells]:
Row 1: "№ п/п" | "###Группировки1###" | "Инв. номер" | ...
Row 2: "01.01" | "01.02" | ... | "31.12"
Row 3: "1" | "2" | ... | "26"
```
Для field-привязок:
```
=== Field template: ОстаточнаяСтоимостьНа0101 -> Макет4 ===
[1 rows, 1 cells]
Row 1: {ОстаточнаяСтоимостьНа0101}
(all params trivial)
```
**Тривиальность выражений**: `Поле = Поле` и `Поле = Представление(Поле)` считаются тривиальными и НЕ выводятся. Показываются только нетривиальные — когда выражение содержит другое поле, вызов метода, пустую строку и т.д.
## trace — трассировка поля от заголовка до запроса
Ищет поле по dataPath ИЛИ заголовку (включая подстроку) и показывает полную цепочку происхождения за один вызов:
```
=== Trace: КоэффициентКи "Коэффициент Ки" ===
Dataset: (schema-level only, not in dataset fields)
Calculated:
ВЫБОР КОГДА ... ТОГДА 0 ИНАЧЕ ... КОНЕЦ
Operands:
КоличествоМесяцевИспользования -> РасчетНалогаНаИмущество [Query]
КоличествоМесяцевВладения -> РасчетНалогаНаИмущество [Query]
Resource:
[ОсновноеСредство] Сумма(КоэффициентКи)
```
Типичный сценарий: пользователь видит колонку "Коэффициент Ки" в отчёте и спрашивает как она считается. Один вызов `trace` показывает: формулу вычисления, откуда берутся операнды, как агрегируется в ресурс.
## Что не выводится
- XML namespace-декларации
- Обёртки v8:item/v8:lang/v8:content (извлекаем чистый текст)
- userSettingID (GUID-ы пользовательских настроек)
- Дефолтные periodAdditionBegin/End = 0001-01-01
- viewMode
+17 -4
View File
@@ -1,4 +1,4 @@
# skd-info v1.4 — Analyze 1C DCS structure
# skd-info v1.6 — Analyze 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory=$true)]
@@ -10,7 +10,8 @@ param(
[int]$Batch = 0,
[int]$Limit = 150,
[int]$Offset = 0,
[string]$OutFile
[string]$OutFile,
[switch]$Raw
)
$ErrorActionPreference = "Stop"
@@ -655,6 +656,13 @@ function Show-Query {
}
$rawQuery = Unescape-Xml $queryNode.InnerText
# Raw mode: emit verbatim query text only (no headers/TOC/batch split) for round-trip
if ($Raw) {
foreach ($ql in ($rawQuery.Trim() -split "`n")) { $lines.Add($ql.TrimEnd()) }
return
}
$dsNameStr = $targetDs.SelectSingleNode("s:name", $ns).InnerText
# Split into batches
@@ -1875,7 +1883,12 @@ $totalLines = $result.Count
# OutFile
if ($OutFile) {
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllLines((Join-Path (Get-Location) $OutFile), $result, $utf8Bom)
if ([System.IO.Path]::IsPathRooted($OutFile)) {
$outPath = [System.IO.Path]::GetFullPath($OutFile)
} else {
$outPath = [System.IO.Path]::GetFullPath((Join-Path (Get-Location).Path $OutFile))
}
[System.IO.File]::WriteAllLines($outPath, $result, $utf8Bom)
Write-Host "Written $totalLines lines to $OutFile"
exit 0
}
@@ -1889,7 +1902,7 @@ if ($Offset -gt 0) {
$result = $result[$Offset..($totalLines - 1)]
}
if ($result.Count -gt $Limit) {
if (-not $Raw -and $result.Count -gt $Limit) {
$shown = $result[0..($Limit - 1)]
foreach ($l in $shown) { Write-Host $l }
Write-Host ""
+10 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# skd-info v1.4 — Analyze 1C DCS structure
# skd-info v1.6 — Analyze 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -278,6 +278,7 @@ def main():
parser.add_argument("-Limit", type=int, default=150)
parser.add_argument("-Offset", type=int, default=0)
parser.add_argument("-OutFile", default=None)
parser.add_argument("-Raw", action="store_true")
args = parser.parse_args()
# --- Resolve path ---
@@ -634,6 +635,13 @@ def main():
sys.exit(1)
raw_query = unescape_xml("".join(query_node.itertext()))
# Raw mode: emit verbatim query text only (no headers/TOC/batch split) for round-trip
if args.Raw:
for ql in raw_query.strip().split("\n"):
lines.append(ql.rstrip())
return
ds_name_str = (target_ds.find("s:name", NSMAP).text or "")
# Split into batches
@@ -1719,7 +1727,7 @@ def main():
sys.exit(0)
result = result[args.Offset:]
if len(result) > args.Limit:
if not args.Raw and len(result) > args.Limit:
shown = result[:args.Limit]
for line in shown:
print(line)
+29 -29
View File
@@ -1,29 +1,29 @@
---
name: skd-validate
description: Валидация схемы компоновки данных 1С (СКД). Используй после создания или модификации СКД для проверки корректности
argument-hint: <TemplatePath> [-Detailed] [-MaxErrors 20]
allowed-tools:
- Bash
- Read
- Glob
---
# /skd-validate — валидация СКД (DataCompositionSchema)
Проверяет структурную корректность Template.xml схемы компоновки данных. Выявляет ошибки формата, битые ссылки, дубликаты имён.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|--------------|:-----:|---------|---------------------------------------------------------|
| TemplatePath | да | — | Путь к Template.xml или каталогу макета |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 20 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-validate.ps1" -TemplatePath "src/МойОтчёт/Templates/ОсновнаяСхема"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-validate.ps1" -TemplatePath "Catalogs/Номенклатура/Templates/СКД/Ext/Template.xml"
```
---
name: skd-validate
description: Валидация схемы компоновки данных 1С (СКД). Используй после создания или модификации СКД для проверки корректности
argument-hint: <TemplatePath> [-Detailed] [-MaxErrors 20]
allowed-tools:
- Bash
- Read
- Glob
---
# /skd-validate — валидация СКД (DataCompositionSchema)
Проверяет структурную корректность Template.xml схемы компоновки данных. Выявляет ошибки формата, битые ссылки, дубликаты имён.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|--------------|:-----:|---------|---------------------------------------------------------|
| TemplatePath | да | — | Путь к Template.xml или каталогу макета |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 20 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/skd-validate.py" -TemplatePath "src/МойОтчёт/Templates/ОсновнаяСхема"
python "${CLAUDE_SKILL_DIR}/scripts/skd-validate.py" -TemplatePath "Catalogs/Номенклатура/Templates/СКД/Ext/Template.xml"
```
@@ -1,4 +1,4 @@
# skd-validate v1.1 — Validate 1C DCS structure
# skd-validate v1.2 — Validate 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -438,6 +438,17 @@ if ($script:stopped) { & $finalize; exit 1 }
if ($calcFieldNodes.Count -gt 0) {
$cfOk = $true
$cfSeen = @{}
# Collect totalField dataPaths — an empty calculatedField is legitimate if a
# totalField with the same dataPath provides the expression (real-world
# pattern in vendor ERP/БП reports for fields visible only in totals).
$tfPaths = @{}
foreach ($tf in $totalFieldNodes) {
$tfDp = $tf.SelectSingleNode("s:dataPath", $ns)
if ($tfDp -and $tfDp.InnerText) {
$tfPaths[$tfDp.InnerText] = $true
}
}
foreach ($cf in $calcFieldNodes) {
$dp = $cf.SelectSingleNode("s:dataPath", $ns)
$expr = $cf.SelectSingleNode("s:expression", $ns)
@@ -457,8 +468,15 @@ if ($calcFieldNodes.Count -gt 0) {
}
if (-not $expr -or -not $expr.InnerText.Trim()) {
Report-Error "CalculatedField '$path' has empty expression"
$cfOk = $false
# Empty expression is legitimate in several vendor patterns:
# - totalField with same dataPath provides the calculation
# - groupTemplate uses the field as group name (declarative only)
# - field is referenced only by settingsVariants for grouping
# Surface as warning, not error, to avoid false positives on real
# ERP/БП reports while still flagging the unusual shape.
if (-not $tfPaths.ContainsKey($path)) {
Report-Warn "CalculatedField '$path' has empty expression (declarative-only?)"
}
}
# Warn if collides with a dataset field
@@ -542,14 +560,16 @@ if ($templateNodes.Count -gt 0) {
}
$tName = $nameNode.InnerText
if ($tplSeen.ContainsKey($tName)) {
Report-Error "Duplicate template name: $tName"
$tplOk = $false
# Vendor configs (ERP/БП) ship templates with repeating names — the
# platform identifies them by position/context, not by <name>. Demote
# to warning so the check still surfaces the collision without failing.
Report-Warn "Duplicate template name: $tName (allowed by platform but ambiguous)"
} else {
$tplSeen[$tName] = $true
}
}
if ($tplOk) {
Report-OK "$($templateNodes.Count) template(s): names unique"
Report-OK "$($templateNodes.Count) template(s) found"
}
}
@@ -581,7 +601,8 @@ if ($script:stopped) { & $finalize; exit 1 }
$validComparisonTypes = @(
"Equal","NotEqual","Greater","GreaterOrEqual","Less","LessOrEqual",
"InList","NotInList","InHierarchy","InListByHierarchy",
"InList","NotInList","InHierarchy","NotInHierarchy",
"InListByHierarchy","NotInListByHierarchy",
"Contains","NotContains","BeginsWith","NotBeginsWith",
"Filled","NotFilled"
)
@@ -734,6 +755,176 @@ if ($variantNodes.Count -eq 0) {
}
}
# --- 16. valueType structural checks ---
# Catches broken XDTO that XML/structural checks miss (decimal without xs:,
# missing qualifiers, mismatched qualifier blocks, unknown sign/length tokens).
$validTypeQualifier = @{
'xs:decimal' = 'v8:NumberQualifiers'
'xs:string' = 'v8:StringQualifiers'
'xs:dateTime' = 'v8:DateQualifiers'
'xs:boolean' = ''
'v8:StandardPeriod' = ''
'v8:UUID' = ''
'v8:Null' = ''
'v8:Type' = ''
'v8:ValueStorage' = ''
}
$validSign = @('Any', 'Nonnegative', 'Negative')
$validLength = @('Variable', 'Fixed')
$validFractions = @('Date', 'DateTime', 'Time')
# DCS supports composite types: multiple <v8:Type> blocks may share a single
# trailing qualifier block (e.g. xs:string + CatalogRef.X + StringQualifiers).
# So we collect all types and qualifiers per valueType, then check consistency.
$qualifierProducers = @{
'v8:NumberQualifiers' = 'xs:decimal'
'v8:StringQualifiers' = 'xs:string'
'v8:DateQualifiers' = 'xs:dateTime'
}
$valueTypeNodes = $root.SelectNodes("//s:valueType", $ns)
$vtChecked = 0
$vtOk = $true
foreach ($vt in $valueTypeNodes) {
$vtChecked++
$types = @() # list of short type strings; '' marks a ref type
$qualifiers = @() # list of @{ name = 'v8:XQualifiers'; node = $child }
foreach ($child in $vt.ChildNodes) {
if ($child.NodeType -ne 'Element') { continue }
if ($child.NamespaceURI -ne 'http://v8.1c.ru/8.1/data/core') { continue }
$localName = $child.LocalName
if ($localName -eq 'Type') {
$t = "$($child.InnerText)".Trim()
if (-not $t) {
Report-Error "valueType: <v8:Type> is empty"
$vtOk = $false
continue
}
if ($t -match '^([A-Za-z][A-Za-z0-9]*):(.+)$') {
$prefix = $Matches[1]
$localT = $Matches[2]
if ($prefix -eq 'xs' -or $prefix -eq 'v8') {
if (-not $validTypeQualifier.ContainsKey($t)) {
Report-Error "valueType: unknown type '$t' (allowed: xs:decimal/xs:string/xs:dateTime/xs:boolean/v8:StandardPeriod or <prefix>:*Ref.X)"
$vtOk = $false
} else {
$types += $t
}
} else {
$prefixNs = $child.GetNamespaceOfPrefix($prefix)
if ($prefixNs -eq 'http://v8.1c.ru/8.1/data/enterprise/current-config') {
if (-not ($localT -match '^[A-Za-z]+(Ref)?\.')) {
Report-Error "valueType: ref type '$t' must look like '<prefix>:<Kind>.<Name>' (e.g. d5p1:CatalogRef.X)"
$vtOk = $false
} else {
$types += '' # ref — no qualifier needed
}
} elseif ($prefixNs -eq 'http://v8.1c.ru/8.1/data/enterprise') {
# System types: AccumulationRecordType etc. — no qualifiers
if (-not ($localT -match '^[A-Za-z][A-Za-z0-9]*$')) {
Report-Error "valueType: system type '$t' has unexpected local-name shape"
$vtOk = $false
} else {
$types += ''
}
} else {
Report-Error "valueType: type '$t' uses prefix '$prefix' bound to unexpected namespace '$prefixNs'"
$vtOk = $false
}
}
} else {
Report-Error "valueType: type '$t' has no namespace prefix (expected xs:/v8:/d5p1: — e.g. xs:decimal not decimal)"
$vtOk = $false
}
} elseif ($localName -match 'Qualifiers$') {
$qName = "v8:$localName"
$qualifiers += @{ name = $qName; node = $child }
# Validate qualifier internals
if ($qName -eq 'v8:NumberQualifiers') {
$digits = $child.SelectSingleNode("v8:Digits", $ns)
$frac = $child.SelectSingleNode("v8:FractionDigits", $ns)
$sign = $child.SelectSingleNode("v8:AllowedSign", $ns)
if (-not $digits -or -not ($digits.InnerText -match '^\d+$')) {
Report-Error "v8:NumberQualifiers: <v8:Digits> missing or not a non-negative integer"
$vtOk = $false
}
if (-not $frac -or -not ($frac.InnerText -match '^\d+$')) {
Report-Error "v8:NumberQualifiers: <v8:FractionDigits> missing or not a non-negative integer"
$vtOk = $false
}
if ($sign -and $sign.InnerText -and $sign.InnerText -notin $validSign) {
Report-Error "v8:NumberQualifiers: <v8:AllowedSign>$($sign.InnerText)</v8:AllowedSign> — must be one of: $($validSign -join ', ')"
$vtOk = $false
}
} elseif ($qName -eq 'v8:StringQualifiers') {
$len = $child.SelectSingleNode("v8:Length", $ns)
$al = $child.SelectSingleNode("v8:AllowedLength", $ns)
if (-not $len -or -not ($len.InnerText -match '^\d+$')) {
Report-Error "v8:StringQualifiers: <v8:Length> missing or not a non-negative integer"
$vtOk = $false
}
if ($al -and $al.InnerText -and $al.InnerText -notin $validLength) {
Report-Error "v8:StringQualifiers: <v8:AllowedLength>$($al.InnerText)</v8:AllowedLength> — must be one of: $($validLength -join ', ')"
$vtOk = $false
}
} elseif ($qName -eq 'v8:DateQualifiers') {
$df = $child.SelectSingleNode("v8:DateFractions", $ns)
if ($df -and $df.InnerText -and $df.InnerText -notin $validFractions) {
Report-Error "v8:DateQualifiers: <v8:DateFractions>$($df.InnerText)</v8:DateFractions> — must be one of: $($validFractions -join ', ')"
$vtOk = $false
}
}
}
}
# Cross-check: every qualifier must have a matching scalar type in this valueType
foreach ($q in $qualifiers) {
$producer = $qualifierProducers[$q.name]
if (-not $producer) { continue }
if ($types -notcontains $producer) {
Report-Error "valueType: <$($q.name)> has no matching <v8:Type>$producer</v8:Type> in this valueType"
$vtOk = $false
}
}
}
if ($vtChecked -gt 0 -and $vtOk) {
Report-OK "$vtChecked valueType block(s): structure and qualifiers OK"
}
if ($script:stopped) { & $finalize; exit 1 }
# --- 17. value content checks ---
# Catches literal placeholders ("_") and empty strings in DesignTimeValue refs
# that XDTO would reject at db-load-xml.
$valueNodes = @()
$valueNodes += @($root.SelectNodes("//s:value[@xsi:type]", $ns))
$valueNodes += @($root.SelectNodes("//dcscor:value[@xsi:type]", $ns))
$vChecked = 0
$vOk = $true
foreach ($vn in $valueNodes) {
if (-not $vn) { continue }
$vChecked++
$xsiType = $vn.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance")
$text = $vn.InnerText
if ($xsiType -eq 'dcscor:DesignTimeValue') {
if (-not $text -or $text.Trim() -eq '' -or $text.Trim() -eq '_') {
Report-Error "<value xsi:type=`"dcscor:DesignTimeValue`">$text</value> — DesignTimeValue must be a reference path (e.g. Перечисление.X.Y), not '$text'"
$vOk = $false
} elseif (-not ($text -match '^[A-Za-zА-Яа-яЁё]+\.[A-Za-zА-Яа-яЁё0-9_]+')) {
Report-Warn "<value xsi:type=`"dcscor:DesignTimeValue`">$text</value> — doesn't look like a typical ref path"
}
}
}
if ($vChecked -gt 0 -and $vOk) {
Report-OK "$vChecked <value> element(s) with xsi:type: content OK"
}
if ($script:stopped) { & $finalize; exit 1 }
# --- Final output ---
& $finalize
@@ -1,4 +1,4 @@
# skd-validate v1.1 — Validate 1C DCS structure (Python port)
# skd-validate v1.2 — Validate 1C DCS structure (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -434,6 +434,15 @@ if stopped:
if len(calc_field_nodes) > 0:
cf_ok = True
cf_seen = {}
# Collect totalField dataPaths — an empty calculatedField is legitimate if a
# totalField with the same dataPath provides the expression (real-world
# pattern in vendor ERP/БП reports for fields visible only in totals).
tf_paths = set()
for tf in total_field_nodes:
tf_dp = find(tf, "s:dataPath")
if tf_dp is not None and inner_text(tf_dp):
tf_paths.add(inner_text(tf_dp))
for cf in calc_field_nodes:
dp = find(cf, "s:dataPath")
expr = find(cf, "s:expression")
@@ -451,8 +460,14 @@ if len(calc_field_nodes) > 0:
cf_seen[path] = True
if expr is None or not text_of(expr):
report_error(f"CalculatedField '{path}' has empty expression")
cf_ok = False
# Empty expression is legitimate in several vendor patterns:
# - totalField with same dataPath provides the calculation
# - groupTemplate uses the field as group name (declarative only)
# - field is referenced only by settingsVariants for grouping
# Surface as warning, not error, to avoid false positives on real
# ERP/БП reports while still flagging the unusual shape.
if path not in tf_paths:
report_warn(f"CalculatedField '{path}' has empty expression (declarative-only?)")
# Warn if collides with a dataset field
if path in all_field_paths:
@@ -526,12 +541,14 @@ if len(template_nodes) > 0:
continue
t_name = inner_text(name_node)
if t_name in tpl_seen:
report_error(f"Duplicate template name: {t_name}")
tpl_ok = False
# Vendor configs (ERP/БП) ship templates with repeating names — the
# platform identifies them by position/context, not by <name>. Demote
# to warning so the check still surfaces the collision without failing.
report_warn(f"Duplicate template name: {t_name} (allowed by platform but ambiguous)")
else:
tpl_seen[t_name] = True
if tpl_ok:
report_ok(f"{len(template_nodes)} template(s): names unique")
report_ok(f"{len(template_nodes)} template(s) found")
# ── 13. GroupTemplate checks ─────────────────────────────────
@@ -558,7 +575,8 @@ if stopped:
valid_comparison_types = (
"Equal", "NotEqual", "Greater", "GreaterOrEqual", "Less", "LessOrEqual",
"InList", "NotInList", "InHierarchy", "InListByHierarchy",
"InList", "NotInList", "InHierarchy", "NotInHierarchy",
"InListByHierarchy", "NotInListByHierarchy",
"Contains", "NotContains", "BeginsWith", "NotBeginsWith",
"Filled", "NotFilled",
)
@@ -685,6 +703,166 @@ else:
if v_ok:
report_ok(f"{len(variant_nodes)} settingsVariant(s) found")
# ── 16. valueType structural checks ───────────────────────────
# Catches broken XDTO that XML/structural checks miss (decimal without xs:,
# missing qualifiers, mismatched qualifier blocks, unknown sign/length tokens).
import re as _re_vt
_VALID_TYPE_QUALIFIER = {
'xs:decimal': 'v8:NumberQualifiers',
'xs:string': 'v8:StringQualifiers',
'xs:dateTime': 'v8:DateQualifiers',
'xs:boolean': '',
'v8:StandardPeriod': '',
'v8:UUID': '',
'v8:Null': '',
'v8:Type': '',
'v8:ValueStorage': '',
}
_VALID_SIGN = ('Any', 'Nonnegative', 'Negative')
_VALID_LENGTH = ('Variable', 'Fixed')
_VALID_FRACTIONS = ('Date', 'DateTime', 'Time')
_V8_NS_URI = 'http://v8.1c.ru/8.1/data/core'
_CONFIG_NS_URI = 'http://v8.1c.ru/8.1/data/enterprise/current-config'
# DCS supports composite types: multiple <v8:Type> blocks may share a single
# trailing qualifier block (e.g. xs:string + CatalogRef.X + StringQualifiers).
# So we collect all types and qualifiers per valueType, then check consistency.
_QUALIFIER_PRODUCERS = {
'v8:NumberQualifiers': 'xs:decimal',
'v8:StringQualifiers': 'xs:string',
'v8:DateQualifiers': 'xs:dateTime',
}
vt_nodes = find_all(root, "//s:valueType")
vt_checked = 0
vt_ok = True
for vt in vt_nodes:
vt_checked += 1
types = [] # short type strings; '' marks a ref type
qualifiers = [] # list of (qName, node)
for child in vt:
if not isinstance(child.tag, str):
continue
qn = etree.QName(child.tag)
if qn.namespace != _V8_NS_URI:
continue
local = qn.localname
if local == 'Type':
t = (child.text or '').strip()
if not t:
report_error("valueType: <v8:Type> is empty")
vt_ok = False
continue
m = _re_vt.match(r'^([A-Za-z][A-Za-z0-9]*):(.+)$', t)
if not m:
report_error(f"valueType: type '{t}' has no namespace prefix (expected xs:/v8:/d5p1: — e.g. xs:decimal not decimal)")
vt_ok = False
continue
prefix, local_t = m.group(1), m.group(2)
if prefix in ('xs', 'v8'):
if t not in _VALID_TYPE_QUALIFIER:
report_error(f"valueType: unknown type '{t}' (allowed: xs:decimal/xs:string/xs:dateTime/xs:boolean/v8:StandardPeriod or <prefix>:*Ref.X)")
vt_ok = False
else:
types.append(t)
else:
prefix_ns = child.nsmap.get(prefix)
if prefix_ns == _CONFIG_NS_URI:
if not _re_vt.match(r'^[A-Za-z]+(Ref)?\.', local_t):
report_error(f"valueType: ref type '{t}' must look like '<prefix>:<Kind>.<Name>' (e.g. d5p1:CatalogRef.X)")
vt_ok = False
else:
types.append('') # ref — no qualifier needed
elif prefix_ns == 'http://v8.1c.ru/8.1/data/enterprise':
# System types: AccumulationRecordType etc. — no qualifiers
if not _re_vt.match(r'^[A-Za-z][A-Za-z0-9]*$', local_t):
report_error(f"valueType: system type '{t}' has unexpected local-name shape")
vt_ok = False
else:
types.append('')
else:
report_error(f"valueType: type '{t}' uses prefix '{prefix}' bound to unexpected namespace '{prefix_ns}'")
vt_ok = False
elif local.endswith('Qualifiers'):
q_name = f"v8:{local}"
qualifiers.append((q_name, child))
if q_name == 'v8:NumberQualifiers':
digits = find(child, "v8:Digits")
frac = find(child, "v8:FractionDigits")
sign = find(child, "v8:AllowedSign")
if digits is None or not _re_vt.match(r'^\d+$', text_of(digits)):
report_error("v8:NumberQualifiers: <v8:Digits> missing or not a non-negative integer")
vt_ok = False
if frac is None or not _re_vt.match(r'^\d+$', text_of(frac)):
report_error("v8:NumberQualifiers: <v8:FractionDigits> missing or not a non-negative integer")
vt_ok = False
if sign is not None and text_of(sign) and text_of(sign) not in _VALID_SIGN:
report_error(f"v8:NumberQualifiers: <v8:AllowedSign>{text_of(sign)}</v8:AllowedSign> — must be one of: {', '.join(_VALID_SIGN)}")
vt_ok = False
elif q_name == 'v8:StringQualifiers':
length = find(child, "v8:Length")
al = find(child, "v8:AllowedLength")
if length is None or not _re_vt.match(r'^\d+$', text_of(length)):
report_error("v8:StringQualifiers: <v8:Length> missing or not a non-negative integer")
vt_ok = False
if al is not None and text_of(al) and text_of(al) not in _VALID_LENGTH:
report_error(f"v8:StringQualifiers: <v8:AllowedLength>{text_of(al)}</v8:AllowedLength> — must be one of: {', '.join(_VALID_LENGTH)}")
vt_ok = False
elif q_name == 'v8:DateQualifiers':
df = find(child, "v8:DateFractions")
if df is not None and text_of(df) and text_of(df) not in _VALID_FRACTIONS:
report_error(f"v8:DateQualifiers: <v8:DateFractions>{text_of(df)}</v8:DateFractions> — must be one of: {', '.join(_VALID_FRACTIONS)}")
vt_ok = False
# Cross-check: every qualifier must have a matching scalar type in this valueType
for q_name, _ in qualifiers:
producer = _QUALIFIER_PRODUCERS.get(q_name)
if not producer:
continue
if producer not in types:
report_error(f"valueType: <{q_name}> has no matching <v8:Type>{producer}</v8:Type> in this valueType")
vt_ok = False
if vt_checked > 0 and vt_ok:
report_ok(f"{vt_checked} valueType block(s): structure and qualifiers OK")
if stopped:
finalize()
sys.exit(1)
# ── 17. value content checks ──────────────────────────────────
# Catches literal placeholders ('_') and empty strings in DesignTimeValue refs
# that XDTO would reject at db-load-xml.
value_nodes = find_all(root, "//s:value[@xsi:type]") + find_all(root, "//dcscor:value[@xsi:type]")
v_checked = 0
v_ok = True
for vn in value_nodes:
if vn is None:
continue
v_checked += 1
xsi_type = vn.get(XSI_TYPE) or ''
text = vn.text or ''
if xsi_type == 'dcscor:DesignTimeValue':
stripped = text.strip()
if not stripped or stripped == '_':
report_error(f"<value xsi:type=\"dcscor:DesignTimeValue\">{text}</value> — DesignTimeValue must be a reference path (e.g. Перечисление.X.Y), not '{text}'")
v_ok = False
elif not _re_vt.match(r'^[A-Za-zА-Яа-яЁё]+\.[A-Za-zА-Яа-яЁё0-9_]+', stripped):
report_warn(f"<value xsi:type=\"dcscor:DesignTimeValue\">{text}</value> — doesn't look like a typical ref path")
if v_checked > 0 and v_ok:
report_ok(f"{v_checked} <value> element(s) with xsi:type: content OK")
if stopped:
finalize()
sys.exit(1)
# ── Final output ──────────────────────────────────────────────
finalize()
+59 -59
View File
@@ -1,59 +1,59 @@
---
name: subsystem-compile
description: Создать подсистему 1С — XML-исходники из JSON-определения. Используй когда нужно добавить подсистему (раздел) в конфигурацию
argument-hint: "[-DefinitionFile <json> | -Value <json-string>] -OutputDir <ConfigDir> [-Parent <path>]"
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /subsystem-compile — генерация подсистемы из JSON
Принимает JSON-определение подсистемы → генерирует XML + файловую структуру + регистрирует в родителе (Configuration.xml или родительская подсистема).
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `DefinitionFile` | Путь к JSON-файлу определения |
| `Value` | Инлайн JSON-строка (альтернатива DefinitionFile) |
| `OutputDir` | Корень выгрузки (где `Subsystems/`, `Configuration.xml`) |
| `Parent` | Путь к XML родительской подсистемы (для вложенных) |
| `NoValidate` | Пропустить авто-валидацию |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/subsystem-compile.ps1" -Value '<json>' -OutputDir '<ConfigDir>'
```
## JSON-определение
```json
{
"name": "МояПодсистема",
"synonym": "Моя подсистема",
"comment": "",
"includeInCommandInterface": true,
"useOneCommand": false,
"explanation": "Описание раздела",
"picture": "CommonPicture.МояКартинка",
"content": ["Catalog.Товары", "Document.Заказ"]
}
```
Минимально: только `name`. Остальное — дефолты.
## Примеры
```powershell
# Минимальная подсистема
... -Value '{"name":"Тест"}' -OutputDir config/
# С составом и картинкой
... -Value '{"name":"Продажи","content":["Catalog.Товары","Report.Продажи"],"picture":"CommonPicture.Продажи"}' -OutputDir config/
# Вложенная подсистема
... -Value '{"name":"Дочерняя"}' -OutputDir config/ -Parent config/Subsystems/Продажи.xml
```
---
name: subsystem-compile
description: Создать подсистему 1С — XML-исходники из JSON-определения. Используй когда нужно добавить подсистему (раздел) в конфигурацию
argument-hint: "[-DefinitionFile <json> | -Value <json-string>] -OutputDir <ConfigDir> [-Parent <path>]"
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /subsystem-compile — генерация подсистемы из JSON
Принимает JSON-определение подсистемы → генерирует XML + файловую структуру + регистрирует в родителе (Configuration.xml или родительская подсистема).
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `DefinitionFile` | Путь к JSON-файлу определения |
| `Value` | Инлайн JSON-строка (альтернатива DefinitionFile) |
| `OutputDir` | Корень выгрузки (где `Subsystems/`, `Configuration.xml`) |
| `Parent` | Путь к XML родительской подсистемы (для вложенных) |
| `NoValidate` | Пропустить авто-валидацию |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/subsystem-compile.py" -Value '<json>' -OutputDir '<ConfigDir>'
```
## JSON-определение
```json
{
"name": "МояПодсистема",
"synonym": "Моя подсистема",
"comment": "",
"includeInCommandInterface": true,
"useOneCommand": false,
"explanation": "Описание раздела",
"picture": "CommonPicture.МояКартинка",
"content": ["Catalog.Товары", "Document.Заказ"]
}
```
Минимально: только `name`. Остальное — дефолты.
## Примеры
```powershell
# Минимальная подсистема
... -Value '{"name":"Тест"}' -OutputDir config/
# С составом и картинкой
... -Value '{"name":"Продажи","content":["Catalog.Товары","Report.Продажи"],"picture":"CommonPicture.Продажи"}' -OutputDir config/
# Вложенная подсистема
... -Value '{"name":"Дочерняя"}' -OutputDir config/ -Parent config/Subsystems/Продажи.xml
```
+57 -57
View File
@@ -1,57 +1,57 @@
---
name: subsystem-edit
description: Точечное редактирование подсистемы 1С. Используй когда нужно добавить или удалить объекты из подсистемы, управлять дочерними подсистемами или изменить свойства
argument-hint: -SubsystemPath <path> -Operation <op> -Value <value>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /subsystem-edit — редактирование подсистемы 1С
Точечное редактирование XML подсистемы: состав, дочерние подсистемы, свойства.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `SubsystemPath` | Путь к XML-файлу подсистемы |
| `DefinitionFile` | JSON-файл с массивом операций |
| `Operation` | Одна операция (альтернатива DefinitionFile) |
| `Value` | Значение для операции |
| `NoValidate` | Пропустить авто-валидацию |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/subsystem-edit.ps1" -SubsystemPath '<path>' -Operation add-content -Value 'Catalog.Товары'
```
## Операции
| Операция | Значение | Описание |
|----------|----------|----------|
| `add-content` | `"Catalog.X"` или `["Catalog.X","Document.Y"]` | Добавить объекты в Content |
| `remove-content` | `"Catalog.X"` или `["Catalog.X"]` | Удалить объекты из Content |
| `add-child` | `"ИмяПодсистемы"` | Добавить дочернюю подсистему в ChildObjects |
| `remove-child` | `"ИмяПодсистемы"` | Удалить дочернюю подсистему |
| `set-property` | `{"name":"prop","value":"val"}` | Изменить свойство (Synonym, IncludeInCommandInterface, UseOneCommand, etc.) |
## Примеры
```powershell
# Добавить объект в состав
... -SubsystemPath Subsystems/Продажи.xml -Operation add-content -Value "Document.Заказ"
# Добавить несколько объектов
... -SubsystemPath Subsystems/Продажи.xml -Operation add-content -Value '["Catalog.Товары","Report.Продажи"]'
# Удалить объект из состава
... -SubsystemPath Subsystems/Продажи.xml -Operation remove-content -Value "Report.Старый"
# Добавить дочернюю подсистему
... -SubsystemPath Subsystems/Продажи.xml -Operation add-child -Value "НоваяДочерняя"
# Изменить свойство
... -SubsystemPath Subsystems/Продажи.xml -Operation set-property -Value '{"name":"IncludeInCommandInterface","value":"false"}'
```
---
name: subsystem-edit
description: Точечное редактирование подсистемы 1С. Используй когда нужно добавить или удалить объекты из подсистемы, управлять дочерними подсистемами или изменить свойства
argument-hint: -SubsystemPath <path> -Operation <op> -Value <value>
allowed-tools:
- Bash
- Read
- Write
- Glob
---
# /subsystem-edit — редактирование подсистемы 1С
Точечное редактирование XML подсистемы: состав, дочерние подсистемы, свойства.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `SubsystemPath` | Путь к XML-файлу подсистемы |
| `DefinitionFile` | JSON-файл с массивом операций |
| `Operation` | Одна операция (альтернатива DefinitionFile) |
| `Value` | Значение для операции |
| `NoValidate` | Пропустить авто-валидацию |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/subsystem-edit.py" -SubsystemPath '<path>' -Operation add-content -Value 'Catalog.Товары'
```
## Операции
| Операция | Значение | Описание |
|----------|----------|----------|
| `add-content` | `"Catalog.X"` или `["Catalog.X","Document.Y"]` | Добавить объекты в Content |
| `remove-content` | `"Catalog.X"` или `["Catalog.X"]` | Удалить объекты из Content |
| `add-child` | `"ИмяПодсистемы"` | Добавить дочернюю подсистему в ChildObjects |
| `remove-child` | `"ИмяПодсистемы"` | Удалить дочернюю подсистему |
| `set-property` | `{"name":"prop","value":"val"}` | Изменить свойство (Synonym, IncludeInCommandInterface, UseOneCommand, etc.) |
## Примеры
```powershell
# Добавить объект в состав
... -SubsystemPath Subsystems/Продажи.xml -Operation add-content -Value "Document.Заказ"
# Добавить несколько объектов
... -SubsystemPath Subsystems/Продажи.xml -Operation add-content -Value '["Catalog.Товары","Report.Продажи"]'
# Удалить объект из состава
... -SubsystemPath Subsystems/Продажи.xml -Operation remove-content -Value "Report.Старый"
# Добавить дочернюю подсистему
... -SubsystemPath Subsystems/Продажи.xml -Operation add-child -Value "НоваяДочерняя"
# Изменить свойство
... -SubsystemPath Subsystems/Продажи.xml -Operation set-property -Value '{"name":"IncludeInCommandInterface","value":"false"}'
```
+62 -62
View File
@@ -1,62 +1,62 @@
---
name: subsystem-info
description: Анализ структуры подсистемы 1С из XML-выгрузки — состав, дочерние подсистемы, командный интерфейс, дерево иерархии. Используй для изучения структуры подсистем и навигации по конфигурации
argument-hint: <SubsystemPath> [-Mode overview|content|ci|tree|full] [-Name <элемент>]
allowed-tools:
- Bash
- Read
- Glob
---
# /subsystem-info — Структура подсистемы 1С
Читает XML подсистемы из выгрузки конфигурации 1С и выводит компактное описание структуры.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `SubsystemPath` | Путь к XML-файлу подсистемы, каталогу подсистемы или каталогу `Subsystems/` (для tree) |
| `Mode` | Режим: `overview` (default), `content`, `ci`, `tree`, `full` |
| `Name` | Drill-down: тип объекта в content, секция в ci, имя подсистемы в tree |
| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк) |
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/subsystem-info.ps1" -SubsystemPath "<путь>"
```
## Пять режимов
| Режим | Что показывает |
|---|---|
| `overview` *(default)* | Компактная сводка: свойства, состав (сгруппирован по типам), дочерние подсистемы, наличие CI |
| `content` | Список Content с группировкой по типу объекта. `-Name Catalog` — только каталоги |
| `ci` | Разбор CommandInterface.xml: видимость, размещение, порядок команд/подсистем/групп |
| `tree` | Рекурсивное дерево иерархии подсистем с маркерами [CI], [OneCmd], [Скрыт] |
| `full` | Полная сводка: overview + content + ci в одном вызове |
## Примеры
```powershell
# Обзор подсистемы
... -SubsystemPath Subsystems/Продажи.xml
# Состав подсистемы
... -SubsystemPath Subsystems/Администрирование.xml -Mode content
# Только документы в составе
... -SubsystemPath Subsystems/Продажи.xml -Mode content -Name Document
# Командный интерфейс подсистемы
... -SubsystemPath Subsystems/Продажи.xml -Mode ci
# Дерево подсистем от корня
... -SubsystemPath Subsystems -Mode tree
# Дерево от конкретной подсистемы
... -SubsystemPath Subsystems/Администрирование.xml -Mode tree
# Дерево только для одной подсистемы
... -SubsystemPath Subsystems -Mode tree -Name Администрирование
```
---
name: subsystem-info
description: Анализ структуры подсистемы 1С из XML-выгрузки — состав, дочерние подсистемы, командный интерфейс, дерево иерархии. Используй для изучения структуры подсистем и навигации по конфигурации
argument-hint: <SubsystemPath> [-Mode overview|content|ci|tree|full] [-Name <элемент>]
allowed-tools:
- Bash
- Read
- Glob
---
# /subsystem-info — Структура подсистемы 1С
Читает XML подсистемы из выгрузки конфигурации 1С и выводит компактное описание структуры.
## Параметры и команда
| Параметр | Описание |
|----------|----------|
| `SubsystemPath` | Путь к XML-файлу подсистемы, каталогу подсистемы или каталогу `Subsystems/` (для tree) |
| `Mode` | Режим: `overview` (default), `content`, `ci`, `tree`, `full` |
| `Name` | Drill-down: тип объекта в content, секция в ci, имя подсистемы в tree |
| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк) |
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/subsystem-info.py" -SubsystemPath "<путь>"
```
## Пять режимов
| Режим | Что показывает |
|---|---|
| `overview` *(default)* | Компактная сводка: свойства, состав (сгруппирован по типам), дочерние подсистемы, наличие CI |
| `content` | Список Content с группировкой по типу объекта. `-Name Catalog` — только каталоги |
| `ci` | Разбор CommandInterface.xml: видимость, размещение, порядок команд/подсистем/групп |
| `tree` | Рекурсивное дерево иерархии подсистем с маркерами [CI], [OneCmd], [Скрыт] |
| `full` | Полная сводка: overview + content + ci в одном вызове |
## Примеры
```powershell
# Обзор подсистемы
... -SubsystemPath Subsystems/Продажи.xml
# Состав подсистемы
... -SubsystemPath Subsystems/Администрирование.xml -Mode content
# Только документы в составе
... -SubsystemPath Subsystems/Продажи.xml -Mode content -Name Document
# Командный интерфейс подсистемы
... -SubsystemPath Subsystems/Продажи.xml -Mode ci
# Дерево подсистем от корня
... -SubsystemPath Subsystems -Mode tree
# Дерево от конкретной подсистемы
... -SubsystemPath Subsystems/Администрирование.xml -Mode tree
# Дерево только для одной подсистемы
... -SubsystemPath Subsystems -Mode tree -Name Администрирование
```
+29 -29
View File
@@ -1,29 +1,29 @@
---
name: subsystem-validate
description: Валидация подсистемы 1С. Используй после создания или модификации подсистемы для проверки корректности
argument-hint: <SubsystemPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /subsystem-validate — валидация подсистемы 1С
Проверяет структурную корректность XML-файла подсистемы из выгрузки конфигурации.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|---------------|:-----:|---------|--------------------------------------------|
| SubsystemPath | да | — | Путь к XML-файлу подсистемы |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/subsystem-validate.ps1" -SubsystemPath "Subsystems/Продажи"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/subsystem-validate.ps1" -SubsystemPath "Subsystems/Продажи.xml"
```
---
name: subsystem-validate
description: Валидация подсистемы 1С. Используй после создания или модификации подсистемы для проверки корректности
argument-hint: <SubsystemPath> [-Detailed] [-MaxErrors 30]
allowed-tools:
- Bash
- Read
- Glob
---
# /subsystem-validate — валидация подсистемы 1С
Проверяет структурную корректность XML-файла подсистемы из выгрузки конфигурации.
## Параметры
| Параметр | Обяз. | Умолч. | Описание |
|---------------|:-----:|---------|--------------------------------------------|
| SubsystemPath | да | — | Путь к XML-файлу подсистемы |
| Detailed | нет | — | Подробный вывод (все проверки, включая успешные) |
| MaxErrors | нет | 30 | Остановиться после N ошибок |
| OutFile | нет | — | Записать результат в файл |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/subsystem-validate.py" -SubsystemPath "Subsystems/Продажи"
python "${CLAUDE_SKILL_DIR}/scripts/subsystem-validate.py" -SubsystemPath "Subsystems/Продажи.xml"
```
+89 -89
View File
@@ -1,89 +1,89 @@
---
name: template-add
description: Добавить пустой макет к объекту 1С. Используй когда нужно создать у объекта новый макет
argument-hint: <ObjectName> <TemplateName> <TemplateType>
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /template-add — Добавление макета
Создаёт макет указанного типа и регистрирует его в корневом XML объекта.
## Usage
```
/template-add <ObjectName> <TemplateName> <TemplateType>
```
| Параметр | Обязательный | По умолчанию | Описание |
|---------------|:------------:|-----------------|--------------------------------------------------|
| ObjectName | да | — | Имя объекта |
| TemplateName | да | — | Имя макета |
| TemplateType | да | — | Тип: HTML, Text, SpreadsheetDocument, BinaryData, DataCompositionSchema |
| Synonym | нет | = TemplateName | Синоним макета |
| SrcDir | нет | `src` | Путь к папке типа объектов (`Reports`, `DataProcessors`, `Catalogs`, `Documents`...), внутри которой лежит `<ObjectName>.xml`. Дефолт `src` подходит для каталогов с внешними обработками/отчётами, лежащими рядом |
| -SetMainSKD | нет | — | Принудительно установить MainDataCompositionSchema |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/add-template.ps1" -ObjectName "<ObjectName>" -TemplateName "<TemplateName>" -TemplateType "<TemplateType>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"] [-SetMainSKD]
```
## Пример
Добавить основную СКД к отчёту в расширении:
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/add-template.ps1" -ObjectName "ОтчётПродажи" -TemplateName "ОсновнаяСхемаКомпоновкиДанных" -TemplateType "DataCompositionSchema" -SrcDir "src/cfe/МоёРасширение/Reports"
```
## Маппинг типов
Пользователь может указать тип в свободной форме. Определи нужный по контексту:
| Пользователь пишет | TemplateType | Расширение | Содержимое |
|---------------------------------------------|---------------------|------------|-------------------------|
| HTML | HTMLDocument | `.html` | Пустой HTML-документ |
| Text, текстовый документ, текст | TextDocument | `.txt` | Пустой файл |
| SpreadsheetDocument, табличный документ, MXL | SpreadsheetDocument | `.xml` | Минимальный spreadsheet |
| BinaryData, двоичные данные | BinaryData | `.bin` | Пустой файл |
| DataCompositionSchema, СКД, схема компоновки | DataCompositionSchema | `.xml` | Минимальная DCS-схема |
## Конвенция именования
Для макетов **печатных форм** (тип SpreadsheetDocument) применяй префикс `ПФ_MXL_`:
| Контекст | Формат имени | Пример |
|------------------------------------------------------------------|----------------------------|-------------------------|
| Печатная форма (дополнительная обработка вида ПечатнаяФорма, или пользователь явно говорит «печатная форма») | `ПФ_MXL_<КраткоеИмя>` | `ПФ_MXL_М11`, `ПФ_MXL_СчётФактура`, `ПФ_MXL_КонвертDL` |
| Прочие макеты (загрузка данных, служебные, настройки) | Без префикса | `МакетЗагрузки`, `НастройкиПечати` |
Если пользователь указал имя макета без префикса, но контекст — печатная форма, **добавь префикс `ПФ_MXL_` автоматически** и сообщи об этом.
## MainDataCompositionSchema (авто)
При добавлении макета типа `DataCompositionSchema` к `ExternalReport` или `Report`:
- Если `MainDataCompositionSchema` пуст — автоматически заполняется ссылкой на макет
- Используй `--SetMainSKD` чтобы перезаписать существующее значение
## Что создаётся
```
<SrcDir>/<ObjectName>/Templates/
├── <TemplateName>.xml # Метаданные макета (1 UUID)
└── <TemplateName>/
└── Ext/
└── Template.<ext> # Содержимое макета
```
## Что модифицируется
- `<SrcDir>/<ObjectName>.xml` — добавляется `<Template>` в конец `ChildObjects`
- Для ExternalReport/Report: может обновляться `MainDataCompositionSchema`
---
name: template-add
description: Добавить пустой макет к объекту 1С. Используй когда нужно создать у объекта новый макет
argument-hint: <ObjectName> <TemplateName> <TemplateType>
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /template-add — Добавление макета
Создаёт макет указанного типа и регистрирует его в корневом XML объекта.
## Usage
```
/template-add <ObjectName> <TemplateName> <TemplateType>
```
| Параметр | Обязательный | По умолчанию | Описание |
|---------------|:------------:|-----------------|--------------------------------------------------|
| ObjectName | да | — | Имя объекта |
| TemplateName | да | — | Имя макета |
| TemplateType | да | — | Тип: HTML, Text, SpreadsheetDocument, BinaryData, DataCompositionSchema |
| Synonym | нет | = TemplateName | Синоним макета |
| SrcDir | нет | `src` | Путь к папке типа объектов (`Reports`, `DataProcessors`, `Catalogs`, `Documents`...), внутри которой лежит `<ObjectName>.xml`. Дефолт `src` подходит для каталогов с внешними обработками/отчётами, лежащими рядом |
| -SetMainSKD | нет | — | Принудительно установить MainDataCompositionSchema |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/add-template.py" -ObjectName "<ObjectName>" -TemplateName "<TemplateName>" -TemplateType "<TemplateType>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"] [-SetMainSKD]
```
## Пример
Добавить основную СКД к отчёту в расширении:
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/add-template.py" -ObjectName "ОтчётПродажи" -TemplateName "ОсновнаяСхемаКомпоновкиДанных" -TemplateType "DataCompositionSchema" -SrcDir "src/cfe/МоёРасширение/Reports"
```
## Маппинг типов
Пользователь может указать тип в свободной форме. Определи нужный по контексту:
| Пользователь пишет | TemplateType | Расширение | Содержимое |
|---------------------------------------------|---------------------|------------|-------------------------|
| HTML | HTMLDocument | `.html` | Пустой HTML-документ |
| Text, текстовый документ, текст | TextDocument | `.txt` | Пустой файл |
| SpreadsheetDocument, табличный документ, MXL | SpreadsheetDocument | `.xml` | Минимальный spreadsheet |
| BinaryData, двоичные данные | BinaryData | `.bin` | Пустой файл |
| DataCompositionSchema, СКД, схема компоновки | DataCompositionSchema | `.xml` | Минимальная DCS-схема |
## Конвенция именования
Для макетов **печатных форм** (тип SpreadsheetDocument) применяй префикс `ПФ_MXL_`:
| Контекст | Формат имени | Пример |
|------------------------------------------------------------------|----------------------------|-------------------------|
| Печатная форма (дополнительная обработка вида ПечатнаяФорма, или пользователь явно говорит «печатная форма») | `ПФ_MXL_<КраткоеИмя>` | `ПФ_MXL_М11`, `ПФ_MXL_СчётФактура`, `ПФ_MXL_КонвертDL` |
| Прочие макеты (загрузка данных, служебные, настройки) | Без префикса | `МакетЗагрузки`, `НастройкиПечати` |
Если пользователь указал имя макета без префикса, но контекст — печатная форма, **добавь префикс `ПФ_MXL_` автоматически** и сообщи об этом.
## MainDataCompositionSchema (авто)
При добавлении макета типа `DataCompositionSchema` к `ExternalReport` или `Report`:
- Если `MainDataCompositionSchema` пуст — автоматически заполняется ссылкой на макет
- Используй `--SetMainSKD` чтобы перезаписать существующее значение
## Что создаётся
```
<SrcDir>/<ObjectName>/Templates/
├── <TemplateName>.xml # Метаданные макета (1 UUID)
└── <TemplateName>/
└── Ext/
└── Template.<ext> # Содержимое макета
```
## Что модифицируется
- `<SrcDir>/<ObjectName>.xml` — добавляется `<Template>` в конец `ChildObjects`
- Для ExternalReport/Report: может обновляться `MainDataCompositionSchema`
+47 -47
View File
@@ -1,47 +1,47 @@
---
name: template-remove
description: Удалить макет из объекта 1С (обработка, отчёт, справочник, документ и др.)
argument-hint: <ObjectName> <TemplateName>
disable-model-invocation: true
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /template-remove — Удаление макета
Удаляет макет и убирает его регистрацию из корневого XML объекта.
## Usage
```
/template-remove <ObjectName> <TemplateName>
```
| Параметр | Обязательный | По умолчанию | Описание |
|--------------|:------------:|--------------|-------------------------------------|
| ObjectName | да | — | Имя объекта |
| TemplateName | да | — | Имя макета для удаления |
| SrcDir | нет | `src` | Каталог исходников |
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/remove-template.ps1" -ObjectName "<ObjectName>" -TemplateName "<TemplateName>" [-SrcDir "<SrcDir>"]
```
## Что удаляется
```
<SrcDir>/<ObjectName>/Templates/<TemplateName>.xml # Метаданные макета
<SrcDir>/<ObjectName>/Templates/<TemplateName>/ # Каталог макета (рекурсивно)
```
## Что модифицируется
- `<SrcDir>/<ObjectName>.xml` — убирается `<Template>` из `ChildObjects`
- Для ExternalReport/Report: если удалённый макет был указан в `MainDataCompositionSchema` — значение очищается
---
name: template-remove
description: Удалить макет из объекта 1С (обработка, отчёт, справочник, документ и др.)
argument-hint: <ObjectName> <TemplateName>
disable-model-invocation: true
allowed-tools:
- Bash
- Read
- Write
- Edit
- Glob
- Grep
---
# /template-remove — Удаление макета
Удаляет макет и убирает его регистрацию из корневого XML объекта.
## Usage
```
/template-remove <ObjectName> <TemplateName>
```
| Параметр | Обязательный | По умолчанию | Описание |
|--------------|:------------:|--------------|-------------------------------------|
| ObjectName | да | — | Имя объекта |
| TemplateName | да | — | Имя макета для удаления |
| SrcDir | нет | `src` | Каталог исходников |
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/remove-template.py" -ObjectName "<ObjectName>" -TemplateName "<TemplateName>" [-SrcDir "<SrcDir>"]
```
## Что удаляется
```
<SrcDir>/<ObjectName>/Templates/<TemplateName>.xml # Метаданные макета
<SrcDir>/<ObjectName>/Templates/<TemplateName>/ # Каталог макета (рекурсивно)
```
## Что модифицируется
- `<SrcDir>/<ObjectName>.xml` — убирается `<Template>` из `ChildObjects`
- Для ExternalReport/Report: если удалённый макет был указан в `MainDataCompositionSchema` — значение очищается
+62 -62
View File
@@ -1,62 +1,62 @@
---
name: web-info
description: Статус Apache и веб-публикаций 1С — запущен ли сервер, какие базы опубликованы, ошибки. Используй когда пользователь спрашивает про статус веб-сервера, опубликованные базы, работает ли Apache
argument-hint: ""
allowed-tools:
- Bash
- Read
- Glob
---
# /web-info — Статус Apache и публикаций 1С
Показывает состояние Apache HTTP Server, список опубликованных баз и последние ошибки.
## Usage
```
/web-info
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
По умолчанию `tools/apache24` от корня проекта.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-info.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
## Формат вывода
```
=== Apache Web Server ===
Status: Запущен (PID: 12345)
Path: C:\...\tools\apache24
Port: 8081
Module: C:/Program Files/1cv8/8.3.24.1691/bin/wsap24.dll
=== Опубликованные базы ===
mydb http://localhost:8081/mydb File="C:\Bases\MyDB";
=== Последние ошибки ===
(пусто)
```
## Примеры
```powershell
# Статус по умолчанию
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-info.ps1"
# Указать путь к Apache
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-info.ps1" -ApachePath "C:\tools\apache24"
```
---
name: web-info
description: Статус Apache и веб-публикаций 1С — запущен ли сервер, какие базы опубликованы, ошибки. Используй когда пользователь спрашивает про статус веб-сервера, опубликованные базы, работает ли Apache
argument-hint: ""
allowed-tools:
- Bash
- Read
- Glob
---
# /web-info — Статус Apache и публикаций 1С
Показывает состояние Apache HTTP Server, список опубликованных баз и последние ошибки.
## Usage
```
/web-info
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
По умолчанию `tools/apache24` от корня проекта.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/web-info.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
## Формат вывода
```
=== Apache Web Server ===
Status: Запущен (PID: 12345)
Path: C:\...\tools\apache24
Port: 8081
Module: C:/Program Files/1cv8/8.3.24.1691/bin/wsap24.dll
=== Опубликованные базы ===
mydb http://localhost:8081/mydb File="C:\Bases\MyDB";
=== Последние ошибки ===
(пусто)
```
## Примеры
```powershell
# Статус по умолчанию
python "${CLAUDE_SKILL_DIR}/scripts/web-info.py"
# Указать путь к Apache
python "${CLAUDE_SKILL_DIR}/scripts/web-info.py" -ApachePath "C:\tools\apache24"
```
+101 -101
View File
@@ -1,101 +1,101 @@
---
name: web-publish
description: Публикация информационной базы 1С через Apache. Используй когда пользователь просит опубликовать базу, сервисы, настроить веб-доступ, веб-клиент, открыть в браузере
argument-hint: "[database]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /web-publish — Публикация 1С через Apache
Генерирует `default.vrd`, настраивает `httpd.conf` и запускает Apache HTTP Server для веб-доступа к информационной базе. При необходимости скачивает portable Apache. Идемпотентный — повторный вызов обновляет конфигурацию.
## Usage
```
/web-publish [database]
/web-publish dev
/web-publish dev --manual
/web-publish dev --port 9090
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
**ОБЯЗАТЕЛЬНО передавай все найденные параметры:**
- **`-V8Path`** — из `v8path` в `.v8-project.json`. Если не передать, скрипт автоопределит версию платформы, что может выбрать не ту версию
- **`-UserName`** — из поля `user` найденной записи базы (если есть)
- **`-Password`** — из поля `password` найденной записи базы (если есть)
- **`-ApachePath`** — из `webPath` в `.v8-project.json` (если есть)
Если файла `.v8-project.json` нет — предложи `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-publish.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (для wsap24.dll) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-AppName <имя>` | нет | Имя публикации (по умолчанию из имени каталога базы) |
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
| `-Port <порт>` | нет | Порт (по умолчанию `8081`) |
| `-Manual` | нет | Не скачивать — только проверить и дать инструкцию |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Несколько пользователей одной базы
Повторный вызов с тем же AppName **заменяет** публикацию (идемпотентность). Это используется для:
- смены пользователя: «опубликуй под Ивановым» → тот же AppName, новый `-UserName`
- перезапуска после `/web-stop`: тот же вызов поднимает Apache обратно
Если пользователь просит **параллельную** публикацию под другим пользователем (для тестирования разных наборов прав), добавь суффикс к AppName:
- база `bpdemo`, пользователь `Иванов``-AppName bpdemo-ivanov`
- база `bpdemo`, пользователь `Admin``-AppName bpdemo-admin` (или просто `bpdemo`)
Ключевые слова: «ещё одну публикацию», «дополнительно», «параллельно», «под другим пользователем не убирая текущую».
## После выполнения
1. Сообщи URL-ы:
- Веб-клиент: `http://localhost:{Port}/{AppName}`
- OData: `http://localhost:{Port}/{AppName}/odata/standard.odata`
- HTTP-сервисы: `http://localhost:{Port}/{AppName}/hs/<RootUrl>/...`
- Web-сервисы: `http://localhost:{Port}/{AppName}/ws/<Имя>?wsdl`
2. Предложи открыть в браузере
3. Если нужно протестировать сервис — помоги составить запрос
4. Если база не зарегистрирована — предложи `/db-list add`
## Примеры
```powershell
# Файловая база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-publish.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
# С явным именем публикации и портом
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-publish.ps1" -InfoBasePath "C:\Bases\MyDB" -AppName "mydb" -Port 9090
# Серверная база
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-publish.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret"
# Ручной режим (только инструкция)
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-publish.ps1" -InfoBasePath "C:\Bases\MyDB" -Manual
```
---
name: web-publish
description: Публикация информационной базы 1С через Apache. Используй когда пользователь просит опубликовать базу, сервисы, настроить веб-доступ, веб-клиент, открыть в браузере
argument-hint: "[database]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /web-publish — Публикация 1С через Apache
Генерирует `default.vrd`, настраивает `httpd.conf` и запускает Apache HTTP Server для веб-доступа к информационной базе. При необходимости скачивает portable Apache. Идемпотентный — повторный вызов обновляет конфигурацию.
## Usage
```
/web-publish [database]
/web-publish dev
/web-publish dev --manual
/web-publish dev --port 9090
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
**ОБЯЗАТЕЛЬНО передавай все найденные параметры:**
- **`-V8Path`** — из `v8path` в `.v8-project.json`. Если не передать, скрипт автоопределит версию платформы, что может выбрать не ту версию
- **`-UserName`** — из поля `user` найденной записи базы (если есть)
- **`-Password`** — из поля `password` найденной записи базы (если есть)
- **`-ApachePath`** — из `webPath` в `.v8-project.json` (если есть)
Если файла `.v8-project.json` нет — предложи `/db-list add`.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/web-publish.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (для wsap24.dll) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-AppName <имя>` | нет | Имя публикации (по умолчанию из имени каталога базы) |
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
| `-Port <порт>` | нет | Порт (по умолчанию `8081`) |
| `-Manual` | нет | Не скачивать — только проверить и дать инструкцию |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Несколько пользователей одной базы
Повторный вызов с тем же AppName **заменяет** публикацию (идемпотентность). Это используется для:
- смены пользователя: «опубликуй под Ивановым» → тот же AppName, новый `-UserName`
- перезапуска после `/web-stop`: тот же вызов поднимает Apache обратно
Если пользователь просит **параллельную** публикацию под другим пользователем (для тестирования разных наборов прав), добавь суффикс к AppName:
- база `bpdemo`, пользователь `Иванов``-AppName bpdemo-ivanov`
- база `bpdemo`, пользователь `Admin``-AppName bpdemo-admin` (или просто `bpdemo`)
Ключевые слова: «ещё одну публикацию», «дополнительно», «параллельно», «под другим пользователем не убирая текущую».
## После выполнения
1. Сообщи URL-ы:
- Веб-клиент: `http://localhost:{Port}/{AppName}`
- OData: `http://localhost:{Port}/{AppName}/odata/standard.odata`
- HTTP-сервисы: `http://localhost:{Port}/{AppName}/hs/<RootUrl>/...`
- Web-сервисы: `http://localhost:{Port}/{AppName}/ws/<Имя>?wsdl`
2. Предложи открыть в браузере
3. Если нужно протестировать сервис — помоги составить запрос
4. Если база не зарегистрирована — предложи `/db-list add`
## Примеры
```powershell
# Файловая база
python "${CLAUDE_SKILL_DIR}/scripts/web-publish.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
# С явным именем публикации и портом
python "${CLAUDE_SKILL_DIR}/scripts/web-publish.py" -InfoBasePath "C:\Bases\MyDB" -AppName "mydb" -Port 9090
# Серверная база
python "${CLAUDE_SKILL_DIR}/scripts/web-publish.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret"
# Ручной режим (только инструкция)
python "${CLAUDE_SKILL_DIR}/scripts/web-publish.py" -InfoBasePath "C:\Bases\MyDB" -Manual
```
+52 -52
View File
@@ -1,52 +1,52 @@
---
name: web-stop
description: Остановка Apache HTTP Server. Используй когда пользователь просит остановить веб-сервер, Apache, прекратить веб-публикацию
argument-hint: ""
allowed-tools:
- Bash
- Read
- Glob
---
# /web-stop — Остановка Apache
Останавливает Apache HTTP Server. Публикации сохраняются — при следующем `/web-publish` сервер запустится снова.
## Usage
```
/web-stop
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
По умолчанию `tools/apache24` от корня проекта.
## Команда
```powershell
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-stop.ps1" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
## После выполнения
Предложи пользователю:
- **Перезапуск**`/web-publish <база>` (повторный вызов поднимет Apache с существующими публикациями)
- **Удаление публикаций**`/web-unpublish <имя>` или `/web-unpublish --all`
## Примеры
```powershell
# Остановить Apache
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-stop.ps1"
# С указанием пути
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/web-stop.ps1" -ApachePath "C:\tools\apache24"
```
---
name: web-stop
description: Остановка Apache HTTP Server. Используй когда пользователь просит остановить веб-сервер, Apache, прекратить веб-публикацию
argument-hint: ""
allowed-tools:
- Bash
- Read
- Glob
---
# /web-stop — Остановка Apache
Останавливает Apache HTTP Server. Публикации сохраняются — при следующем `/web-publish` сервер запустится снова.
## Usage
```
/web-stop
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
По умолчанию `tools/apache24` от корня проекта.
## Команда
```powershell
python "${CLAUDE_SKILL_DIR}/scripts/web-stop.py" <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
## После выполнения
Предложи пользователю:
- **Перезапуск**`/web-publish <база>` (повторный вызов поднимет Apache с существующими публикациями)
- **Удаление публикаций**`/web-unpublish <имя>` или `/web-unpublish --all`
## Примеры
```powershell
# Остановить Apache
python "${CLAUDE_SKILL_DIR}/scripts/web-stop.py"
# С указанием пути
python "${CLAUDE_SKILL_DIR}/scripts/web-stop.py" -ApachePath "C:\tools\apache24"
```
+66 -22
View File
@@ -69,6 +69,12 @@ SCRIPT
# 2b. Execute without video recording (for debugging/testing)
cat script.js | node $RUN exec - --no-record
# 2c. Override exec HTTP timeout (default 30 min). Use for long scripts
# such as multi-block recordings + addNarration.
cat script.js | node $RUN exec - --timeout-min=120
cat script.js | node $RUN exec - --timeout=7200000
WEB_TEST_EXEC_TIMEOUT_MS=7200000 node $RUN exec script.js
# 3. Screenshot
node $RUN shot result.png
@@ -159,7 +165,7 @@ const form = await getFormState();
### Reading data
#### `readTable({ maxRows?, offset?, table? })``{ columns, rows, total, shown, offset }`
#### `readTable({ maxRows?, offset?, table? })``{ columns, rows, total, shown, offset, hasMore }`
Read actual grid data with pagination. Each row is `{ columnName: value }`.
| Option | Default | Description |
@@ -168,6 +174,12 @@ Read actual grid data with pagination. Each row is `{ columnName: value }`.
| `offset` | 0 | Skip first N rows |
| `table` | — | Grid name from `tables[]` (for multi-grid forms) |
**Picture columns.** Cells that render an icon (status/stage marks, the "ЭДО" mark, the attached-files paperclip) read as `'pic:<N>'` (`N` = icon frame/state) when shown, `''` when absent — so presence is truthy and icons differ by index. Icon-only columns (no header text) still appear, named by their tooltip or `'(picture)'`. These values are read-only — filter/select rows by a text column, not by `'pic:N'`.
```js
if (t.rows[0]['Присоединенные файлы']) { /* has an attached file */ }
t.rows[0]['ЭДО'] === 'pic:1'; // connected to 1С-ЭДО ('pic:0' = not)
```
Special row fields:
- `_kind: 'group'` — hierarchical group row
- `_kind: 'parent'` — parent row in hierarchy
@@ -177,10 +189,22 @@ Special row fields:
- `hierarchical: true` — list has groups (on result object)
- `viewMode: 'tree'` — tree view active (on result object)
**`total` is misleading for long lists.** 1С virtualizes both dynamic lists and form tabular sections — the DOM holds only a window of visible rows. `total` / `shown` count what's *loaded right now*, not the size of the underlying collection. Use **`hasMore`** to know if there's more data outside the window:
```js
const t = await readTable();
// t.hasMore = { above: false, below: true } ← form tabular section, scrollbar visible
// t.hasMore = { below: true } ← dynamic list (catalog/journal/register)
// t.hasMore = { below: false } ← everything visible / end of list reached
```
- `hasMore.below` — always present. `true` ⇒ scrolling down (PageDown / `clickElement` with `scroll:true`) will reveal more rows.
- `hasMore.above` — usually present too. Detected via the dynamic-list page-turn buttons (#vertButtonScroll) or the tabular-section scrollbar. Absent only for rare grids that have neither widget — treat absence as unknown.
```js
const t = await readTable({ maxRows: 50 });
console.log('Columns:', t.columns);
console.log('Rows:', t.rows.length, 'of', t.total);
console.log('Loaded:', t.shown, 'rows; more below:', t.hasMore.below);
// Pagination:
const page2 = await readTable({ maxRows: 50, offset: 50 });
```
@@ -211,7 +235,9 @@ Sections + all open tabs.
### Actions
#### `clickElement(text, { dblclick?, table?, expand?, modifier? })` → form state
**Return shape convention.** All action functions return a **flat form state** (same shape as `getFormState()`) with action-specific extras: `clicked`, `focused`, `selected`, `filled`, `notFilled`, `closed`, `opened`, `navigated`, `deleted`, `filtered`, `unfiltered`. Errors always sit at the top level under `.errors` (when present) — the exec-wrapper automatically throws on `.errors.modal` / `.errors.balloon`.
#### `clickElement(text, { dblclick?, table?, expand?, modifier?, scroll? })` → form state
Click button, hyperlink, tab, navigation panel link, or grid row (fuzzy match).
- `table` — scope button search to a specific grid's command panel (by name from `tables[]`):
@@ -233,6 +259,11 @@ Click button, hyperlink, tab, navigation panel link, or grid row (fuzzy match).
await clickElement('ИСУ ФХД'); // select row
await clickElement('ИСУ ФХД', { expand: true }); // expand/collapse
```
- **Focus a field** (last resort, when no `table` given): if `text` matches no clickable control but matches a form field's name/label, clicks the input to focus it **without changing its value**. Returns `focused: { field, id, ok }` (`ok: false` if the field couldn't take focus). Use it to drive focus-dependent keys:
```js
await clickElement('Контрагент'); // focus the reference field
await getPage().keyboard.press('F4'); // open its selection form
```
- **Multi-select rows** with `modifier: 'ctrl'` (add to selection) or `modifier: 'shift'` (select range):
```js
await clickElement('Номенклатура 1'); // select first row
@@ -242,26 +273,32 @@ Click button, hyperlink, tab, navigation panel link, or grid row (fuzzy match).
const t = await readTable();
t.rows.filter(r => r._selected); // rows with _selected: true
```
- **SpreadsheetDocument cells** (report drill-down): first argument can be `{ row, column }` object to click a cell in a rendered report. Coordinates match `readSpreadsheet()` output:
- **Cell click by (row, column)** first argument as `{ row, column }`. Routes: spreadsheet on form → spreadsheet drill-down; otherwise → grid cell. Pass `table: 'GridName'` to force a specific grid when both are present.
Spreadsheet report drill-down:
```js
const report = await readSpreadsheet();
// report.data[0] = { 'К1': 'Материалы строительные', 'К6': '150 000', ... }
// By data row index + column header name
await clickElement({ row: 0, column: 'К6' }, { dblclick: true });
// By cell value filter (fuzzy match)
await clickElement({ row: { 'К1': 'Материалы' }, column: 'К6' }, { dblclick: true });
// Totals row
await clickElement({ row: 'totals', column: 'К6' }, { dblclick: true });
await clickElement({ row: 0, column: 'К6' }, { dblclick: true }); // by index
await clickElement({ row: { 'К1': 'Материалы' }, column: 'К6' }, { dblclick: true }); // by filter
await clickElement({ row: 'totals', column: 'К6' }, { dblclick: true }); // totals row
await clickElement('150 000', { dblclick: true }); // fallback: by text
```
Text search also works as fallback — searches inside spreadsheet iframes:
Form grid cell (catalog list, journal, table part). Off-viewport columns auto-scroll horizontally (works around frozen columns). Use `scroll: true | number` for filter-based rows outside the current DOM window:
```js
await clickElement('150 000', { dblclick: true }); // finds cell by text in report
await clickElement({ row: 0, column: 'Количество' }, { table: 'Товары', dblclick: true });
await clickElement({ row: { 'Номенклатура': 'Бумага' }, column: 'Цена' }, { table: 'Товары' });
await clickElement({ row: { 'Номер': '0000-000601' }, column: 'Сумма' },
{ table: 'Реализации', scroll: true }); // PageDown loop, max 50
```
#### `fillFields({ name: value })``{ filled, form }`
Gotchas:
- `row: <number>` is the index in the **current DOM window**, not absolute — 1С virtualizes long lists. `row: 0` is the topmost loaded row after any prior scroll. For arbitrary rows in a long list use `row: { col: val }` + `scroll: true`.
- `scroll: true` walks **down only** (PageDown). For going up first press `Home` via `getPage().keyboard` or narrow with `filterList`.
- First matching row wins on duplicate filter matches — refine the filter to disambiguate.
#### `fillFields({ name: value })` → form state with `filled`
Fill form fields by label (fuzzy match). Auto-detects field type.
| Value | Field type | Method |
@@ -280,8 +317,7 @@ await fillFields({
});
```
Returns `{ filled: [{ field, ok, value, method }], form: {...} }`.
Method is one of: `'clear'` | `'toggle'` | `'radio'` | `'paste'` | `'dropdown'` | `'form'` | `'typeahead'`
Returns form state with `filled: [{ field, ok: true, value, method }]` (method: `clear`|`toggle`|`radio`|`paste`|`dropdown`|`form`|`typeahead`). **Throws on any per-field failure** with a detailed message listing problematic fields and available options — if the call returned, all fields were filled, no per-item check needed.
#### `selectValue(field, search, opts?)` → form state with `selected`
Select a value from reference field via dropdown or selection form. More reliable than `fillFields` for reference fields that need exact selection from a catalog. Pass empty `search` (`''` or `null`) to clear the field (Shift+F4).
@@ -304,14 +340,19 @@ await selectValue('Документ', '0000-000601', { type: 'Реализаци
Also supports DCS labels — auto-enables the paired checkbox.
#### `fillTableRow(fields, opts)` → form state
#### `fillTableRow(fields, opts)` → form state with `filled` (+ optional `notFilled`)
Fill table row cells via Tab navigation. Value is a plain string, `{ value, type }` for composite-type cells, or `''`/`null` to clear (Shift+F4).
Returns form state with `filled: [{ field, ok, ...}]`. Items are `{ field, ok: true, method, value }` on success (method: `direct`|`paste`|`dropdown`|`form`|`type-direct`|`skip`|`clear`|`toggle`) or `{ field, ok: false, error, message }` on per-field failure. Unmatched fields → `notFilled: [...]`.
**Unlike `fillFields`, `fillTableRow` does NOT throw on per-field failures** — errors appear as `ok: false` items in `filled[]` so the caller can react selectively (e.g. retry one cell while the rest of the row stays filled). Check via `r.filled.filter(f => !f.ok)`. Error codes: `composite_type`/`type_required`/`type_dialog_failed` (retry with `{value, type}`); `column_not_found` (check column name via `readTable`); `no_selection_form`/`no_selection_after_type` (retry or fall back to `selectValue`); `not_found`/`no_match`/`ambiguous` (refine search text); `still_open` (picked a group — pick a leaf row). Soft validation errors from 1C (`balloon`, `modal`) still throw via the exec-wrapper.
| Option | Description |
|--------|-------------|
| `tab` | Switch to tab before filling |
| `add` | Add new row before filling |
| `row` | Edit existing row by 0-based index |
| `row` | Edit existing row: 0-based index, **or** a `{ col: value }` filter (one or more columns) to locate the row by its cell values |
| `scroll` | With a `row` filter — scan beyond the current DOM window (`true` = up to 50 PageDowns, number = limit) |
| `table` | Grid name from `tables[]` (for multi-grid forms) |
```js
@@ -320,11 +361,14 @@ await fillTableRow(
{ 'Номенклатура': 'Бумага', 'Количество': '10', 'Цена': '100' },
{ tab: 'Товары', add: true }
);
// Edit existing row:
// Edit existing row by index:
await fillTableRow(
{ 'Количество': '20' },
{ tab: 'Товары', row: 0 }
);
// Edit existing row located by cell values (одна или несколько колонок):
await fillTableRow({ 'Цена': '120' }, { table: 'Товары', row: { 'Номенклатура': 'Бумага' } });
await fillTableRow({ 'Сумма': '500' }, { row: { 'Номер': '0000-000601', 'Дата': '29.12.2016' }, scroll: true });
// Multi-grid form — add row to specific table:
await fillTableRow(
{ 'Объект': 'БДДС' },
@@ -525,7 +569,7 @@ On error (auto-screenshot taken):
- **Headed mode** — 1C requires visible browser, no headless
- **Startup time** — 1C loads 30-60s on initial connect (built into `start`)
- **Fuzzy matching** — all name lookups: exact > startsWith > includes
- **Clipboard paste** — all text fields filled via Ctrl+V (triggers 1C events properly)
- **Clipboard paste** — all text fields filled via Ctrl+V (triggers 1C events properly). The OS clipboard is automatically saved before each action and restored after, so a local user's clipboard survives a test run. Opt out with `--no-preserve-clipboard` (any command), `WEB_TEST_PRESERVE_CLIPBOARD=0` env, or `preserveClipboard: false` in `webtest.config.mjs`
- **Cyrillic in bash** — use `cat <<'SCRIPT' | node $RUN exec -` to avoid escaping issues
- **Non-breaking spaces** — 1C uses `\u00a0` instead of regular spaces. All matching is normalized internally
- **Section panel display**`navigateSection()` works with any panel position (side, top) but requires "Picture and text" or "Text" display mode. Icon-only mode is not supported — API cannot read section names from icons alone
+155 -164
View File
@@ -5,9 +5,11 @@ Use this when the user asks to cover a 1C solution with automated regression tes
The runner is the same `run.mjs`. The mode is `test`:
```bash
node $RUN test [url] <dir|file> [flags]
node $RUN test <dir|file>... [flags]
```
Positional args are test paths (files and/or dirs, multiple allowed). URL is NOT positional — it comes from `webtest.config.mjs`; override with `--url=<url>`.
Tests live next to the project they cover (not inside the skill). Convention: `tests/` at the project root, with `_hooks.mjs` and `webtest.config.mjs` at the suite root. Tests are ES modules with `*.test.mjs` suffix.
## When to choose `test` over `exec`
@@ -15,7 +17,6 @@ Tests live next to the project they cover (not inside the skill). Convention: `t
| Goal | Mode |
|------|------|
| Explore a form, prototype a single step, debug one selector | `exec` (interactive session) |
| **Walk through a scenario live before committing it as a test** | `exec` first, then `test` |
| Reproduce a bug as a failing test before fixing it | `test` |
| Cover a feature so future changes are checked automatically | `test` |
| Run the project's regression on a new build | `test` |
@@ -25,73 +26,15 @@ Don't write a `.test.mjs` for a one-shot user request. Don't drive a regression
## Before writing tests — recon
Two layers, in order. Don't skip either.
Two layers, in order.
### 1. Static recon — metadata
**1. Static recon — metadata.** Never invent identifiers. For every metadata object the user mentions, run the matching info skill first: `/meta-info` (attributes/tabular sections), `/form-info` (form layout), `/skd-info` (DCS), `/mxl-info` (templates), `/role-info` (rights), `/subsystem-info` (composition / command interface). If the user names objects you can't find — stop and ask.
Never invent identifiers. For every metadata object the user mentions (or that you decide to cover), run the matching info skill first:
**2. Live recon — interactive walkthrough.** For any non-trivial scenario, walk the path live in `exec` mode before transcribing it. Metadata tells you what exists; the live walkthrough tells you what actually happens. Capture from `getFormState()`: exact button names (`'Провести и закрыть'`, not `'Сохранить'`), table section names for multi-grid forms, required fields, places where a real async wait is needed. Then transcribe the working sequence into `*.test.mjs`, wrapping logical chunks in `step('...', async () => { ... })`.
| Object type | Skill |
|-------------|-------|
| Catalog/document/register attributes, tabular sections | `/meta-info` |
| Form layout — fields, buttons, tabs, tables | `/form-info` |
| DCS report — fields, parameters, filters | `/skd-info` |
| Spreadsheet template areas/parameters | `/mxl-info` |
| Role rights / restrictions | `/role-info` |
| Subsystem composition / command interface | `/subsystem-info` |
The mechanics of `exec` / `getFormState` / `fillFields` / `clickElement` are in [SKILL.md](SKILL.md) — read it before recon if you haven't already.
This gives the real Russian field labels, command names, column headers, table-section names. Without it, fuzzy matching will silently land on the wrong element, or fail with no useful diagnostic.
If the user names objects you cannot find: stop and ask. Do not guess.
### 2. Live recon — interactive walkthrough
For any non-trivial scenario, walk the path live in `exec` mode before writing it down. Metadata tells you what exists; the live walkthrough tells you what actually happens — which button posts the document, which dialog 1C raises, how the form looks after `clickElement('Создать')`, what fields are required, where `wait()` is genuinely needed.
```bash
# Start a session (background).
node $RUN start http://localhost:9191/myapp/ru_RU
# Step the scenario interactively. After each step, inspect.
cat <<'EOF' | node $RUN exec -
await navigateSection('Склад');
const cmds = await getCommands();
console.log(cmds);
EOF
cat <<'EOF' | node $RUN exec -
await openCommand('Приходная накладная');
await clickElement('Создать');
const s = await getFormState();
console.log(JSON.stringify(s.fields.map(f => ({ name: f.name, label: f.label, required: f.required })), null, 2));
console.log('buttons:', s.buttons.map(b => b.name));
console.log('tables:', s.tables.map(t => ({ name: t.name, label: t.label, columns: t.columns })));
EOF
# Try the actions you plan to encode. If a step fails, fix and re-try
# before transcribing it.
cat <<'EOF' | node $RUN exec -
await fillFields({ 'Контрагент': 'ООО Север' });
await fillTableRow({ 'Номенклатура': 'Товар 01', 'Количество': '5' },
{ table: 'Товары', add: true });
await clickElement('Провести и закрыть');
console.log(JSON.stringify(await getFormState()));
EOF
# When done, stop the session (or leave it for the next test you write).
node $RUN stop
```
What to record from the walkthrough into the test:
- Exact button names (`'Провести и закрыть'`, not `'Сохранить'`).
- Field labels as 1C renders them (with possible non-breaking spaces — `fillFields` normalises, but be exact).
- Table section names from `getFormState().tables[].name`/`label` for multi-grid forms.
- Required `wait()` durations — only where a real async event happens (report generation, server-side calculation). Default actions await internally.
- The shape of `getFormState()` after each action — gives you the right `assert.equal(...)` paths.
After this, transcribe the working sequence into `*.test.mjs`, wrap each chunk in `step('...', async () => { ... })`, add assertions for the invariants you saw. Run the file once with `node $RUN test path/to/file.test.mjs` to confirm.
When live recon is overkill: trivial reads (`navigateSection` + `readTable` + assert non-empty), or scenarios you've already proven once in this session. When it's essential: anything with confirmation dialogs, posting/cancellation flows, reports with custom filters, multi-grid forms, or user-customised forms you've never seen.
When live recon is overkill: trivial reads (`navigateSection` + `readTable` + assert non-empty), or scenarios you've already proven once in this session. When it's essential: confirmation dialogs, posting/cancellation flows, reports with custom filters, multi-grid forms, user-customised forms.
## Suite layout
@@ -99,30 +42,20 @@ When live recon is overkill: trivial reads (`navigateSection` + `readTable` + as
```
tests/
web-test/ # engine self-tests (reserved if our repo layout)
<app-name>/ # application regression — one per solution
_hooks.mjs
webtest.config.mjs
_allure/ # optional static Allure config
01-login/
02-counterparties/
...
<another-app>/ # second solution, fully isolated
_hooks.mjs
...
```
`<app-name>` is the project/extension slug (`acc-payroll`, `erp-customisation`, etc.). Pick something stable and pass it on the CLI:
```bash
node $RUN test tests/<app-name>/
```
Inside the application subfolder, organize by **feature**, not by metadata kind. Numeric prefixes on both folder and file enforce run order (discovery is alphabetic by full path).
Inside the application subfolder, organize by **feature**, not by metadata kind. Numeric prefixes on both folder and file enforce run order — discovery walks recursively and sorts files by full relative path; entries starting with `_` or `.` are skipped (so `_hooks.mjs`, `_allure/` won't be picked up as tests).
```
tests/<app-name>/
_hooks.mjs # stand prep + cross-cutting hooks (optional)
webtest.config.mjs # url, contexts, defaults (optional)
01-login/
01-open-base.test.mjs
02-section-navigation.test.mjs
@@ -132,15 +65,11 @@ tests/<app-name>/
03-goods-receipt/
01-fill.test.mjs
02-post.test.mjs
03-unpost.test.mjs
04-balance-report/
01-generate.test.mjs
02-warehouse-filter.test.mjs
05-approval-process/
01-end-to-end.test.mjs # multi-user
```
Per-folder `_hooks.mjs` / `webtest.config.mjs` inside the application subfolder are NOT supported. Only the application-root copies are loaded.
Per-folder `_hooks.mjs` / `webtest.config.mjs` inside the application subfolder are NOT supported — only the application-root copies are loaded.
## Test file anatomy
@@ -185,18 +114,95 @@ export default async function(ctx) {
}
```
The runner injects every `browser.mjs` export into `ctx` plus `assert`, `step`, `log`, `testInfo`, `testResult` (afterEach only). For multi-context tests, each context name is its own scoped namespace (`ctx.clerk.clickElement(...)` etc.) — `step`/`assert` stay top-level.
**Step names — in Russian, descriptive.** Step labels surface in the console output, in JSON/JUnit, and as Allure step nodes. Russian-speaking QA reads them. Use a full action phrase (`'Создать нового контрагента'`), not a tag (`'create'`) and not a transliteration. Same applies to `export const name` and `displayName` in `webtest.config.mjs`.
**Step names — in Russian, descriptive.** Step labels surface in the console output, in JSON/JUnit, and as Allure step nodes. Russian-speaking QA reads them. Use a full action phrase (`'Создать нового контрагента'`, `'Проверить наличие документа в списке'`), not a tag (`'create'`, `'verify'`) and not a transliteration. Same applies to `export const name` and `displayName` in `webtest.config.mjs`.
## `ctx` contract
The runner injects every `browser.mjs` export into `ctx` (all 1C action functions auto-detect platform errors — see SKILL.md), plus the test utilities below.
### Test utilities
```js
step(name, fn) // async wrapper. Records start/stop. Nested calls supported.
// On throw: marks the step failed, re-throws.
// On screenshot='every-step': captures after fn().
log(...args) // adds a line to ctx.testInfo's output (goes into JSON / Allure
// attachment). Use instead of console.log inside tests.
assert.* // see "Assertions" below
```
### `ctx.testInfo` (always set, read-only)
```js
{
name, // 'Навигация по разделам' (with params substituted)
file, // '01-navigation.test.mjs' (basename)
filePath, // relative path inside testDir
tags, // ['nav', 'smoke']
timeout, // ms
attempt, // 1..maxAttempts (1-based)
maxAttempts, // 1 + retry
param, // { ... } | undefined (only when export const params is set)
contexts: { // mirrors config.contexts; includes custom fields like displayName
clerk: { url, isolation, displayName, ... },
manager: { ... },
},
primaryContext, // 'clerk' — name of the context active at test entry
// (= t.context for single, t.contexts[0] for multi)
}
```
### `ctx.testResult` (only in `afterEach`)
```js
{
status, // 'passed' | 'failed'
duration, // ms
attempts, // attempts actually executed
error, // { message, step?, screenshot? } | null
steps, // array of step results (each: { name, start, stop, status, error?, steps[] })
}
```
### Context shape
- **Single-context (default or `export const context = 'manager'`):** all API on `ctx` top-level — `ctx.clickElement(...)`, `ctx.getFormState()`, etc.
- **Multi-context (`export const contexts = ['clerk', 'manager']`):** each name is its own scoped namespace — `ctx.clerk.clickElement(...)`, `ctx.manager.fillFields(...)`. `step`, `assert`, `log`, `testInfo` stay top-level. Scoped methods auto-switch the active page before each call.
## Assertions
All on `ctx.assert`. Throw `AssertionError` with `.message`, `.actual`, `.expected`. No dependencies.
```js
// generic
assert.ok(value, msg?) // truthy
assert.equal(actual, expected, msg?) // ===
assert.notEqual(actual, expected, msg?) // !==
assert.deepEqual(actual, expected, msg?) // JSON-compare
assert.includes(haystack, needle, msg?) // string.includes / array.includes
assert.match(string, regex, msg?) // regex.test(string)
await assert.throws(asyncFn, msg?) // passes if fn throws (use await)
// 1C-specific — operate on getFormState() / readTable() output
assert.formHasField(state, 'Контрагент', msg?) // state.fields[name] exists
assert.formTitle(state, expected, msg?) // state.title includes expected
assert.tableHasRow(table, predicate, msg?) // predicate: object (partial match) or fn(row) => bool
// object form: { 'Наименование': 'Тест' }
// fn form: r => r['Сумма'] > 100
assert.tableRowCount(table, expected, msg?) // table.rows.length === expected
assert.noErrors(state, msg?) // !state.errors
```
Beyond these, just use plain JS (`throw new Error(...)`) — there's no custom matcher extension API. The 1C-specific helpers are the ones worth preferring over hand-rolled equivalents because their error messages name the actual fields/rows present, which speeds up triage.
## webtest.config.mjs
```js
export default {
// Single-context: just url.
// Single-context shorthand:
url: 'http://localhost:9191/myapp/ru_RU',
// OR multi-context: named contexts. Each test picks via `context`/`contexts` exports.
// OR multi-context:
// contexts: {
// clerk: { url: 'http://localhost:9191/myapp-clerk/ru_RU', displayName: 'Кладовщик' },
// manager: { url: 'http://localhost:9191/myapp-manager/ru_RU', displayName: 'Менеджер' },
@@ -205,7 +211,7 @@ export default {
timeout: 30000,
retries: 0,
screenshot: 'on-failure',
screenshot: 'on-failure', // 'every-step' | 'off'
record: false,
// Severity → tags mapping for Allure. Each tag at most one bucket.
@@ -217,7 +223,7 @@ export default {
};
```
CLI flags override config. Recommend latin context IDs + Russian `displayName` for video badges.
CLI flags override config. Use latin context IDs + Russian `displayName` for ergonomics — `ctx.testInfo.contexts.clerk.displayName` is friendlier than mixed-case Cyrillic keys.
## _hooks.mjs
@@ -228,74 +234,44 @@ import { execSync } from 'child_process';
// Infra — runs once around the whole suite.
export async function prepare({ hookArgs, log, config }) {
// Restore DB, publish to Apache, build EPF, etc.
// hookArgs = everything after `--` on the CLI. Parse yourself.
if (hookArgs.includes('--rebuild-stand')) { /* full rebuild */ }
// Use idempotent hash-locks to skip work on warm starts.
// hookArgs: everything after `--` on the CLI, as a string[]. Parse yourself.
const force = hookArgs.includes('--rebuild-stand');
const dataArg = hookArgs.find(a => a.startsWith('--data='))?.slice('--data='.length);
log('preparing stand, force=', force, 'data=', dataArg);
// Idempotent hash-locks on inputs (config sources, EPF spec, DB dump) keep
// warm starts to a liveness probe.
}
export async function cleanup({ log, config }) {
// Tear down or leave the stand running. Choose per project.
}
export async function cleanup({ log, config }) { /* optional */ }
// Testlevel — runs with browser ctx.
export async function beforeAll(ctx) { /* once after first context opens */ }
export async function afterAll(ctx) { /* once before final teardown */ }
export async function beforeEach(ctx) { /* ctx.testInfo is set */ }
export async function afterEach(ctx) { /* ctx.testResult is set */ }
export async function afterEach(ctx) { /* ctx.testInfo + ctx.testResult set */ }
// Per-context — runs whenever a context is created/closed.
export async function afterOpenContext(ctx, name, spec) { /* spec = config.contexts[name] */ }
export async function beforeCloseContext(ctx, name, spec) { }
```
Built-in state reset (`dismissPendingErrors` + close all forms) runs after `afterEach` automatically. Don't reimplement it.
Built-in state reset (`dismissPendingErrors` + close all forms) runs after `afterEach` automatically. Don't reimplement it in `afterEach`.
Pass hook args after `--`:
```bash
node $RUN test tests/<app-name>/ --bail -- --rebuild-stand --data=demo
└─runner─┘ └────── hookArgs ─────────┘
```
**Where to put data setup:**
- DB restore, publication, EPF build → `prepare()`. Make it idempotent (hash-locks on inputs — config sources, EPF spec, DB dump) so warm starts skip everything but a liveness probe.
- Test-specific seed data (the document this test will edit, the counterparty it expects) → per-test `setup`.
- DB restore, publication, EPF build → `prepare()`. Make it idempotent (hash-locks).
- Test-specific seed data → per-test `setup`.
- Shared session-wide warmup → `beforeAll`.
## Ready-to-paste patterns
### Catalog full cycle
```js
await step('Создать контрагента', async () => {
await navigateSection('Продажи');
await openCommand('Контрагенты');
await clickElement('Создать');
await fillFields({ 'Наименование': 'ТД Тест', 'ИНН': '7707083893' });
await clickElement('Записать и закрыть');
});
await step('Проверить наличие в списке', async () => {
const t = await readTable({ maxRows: 50 });
assert.tableHasRow(t, { 'Наименование': 'ТД Тест' });
});
await step('Удалить контрагента и подтвердить удаление', async () => {
await clickElement('ТД Тест');
const page = await getPage();
await page.keyboard.press('Delete');
await clickElement('Да');
});
```
### Document create + post
```js
const marker = 'Тест-' + Date.now();
await openCommand('Приходная накладная');
await clickElement('Создать');
await fillFields({ 'Контрагент': 'ООО Север', 'Комментарий': marker });
await fillTableRow(
{ 'Номенклатура': 'Товар 01', 'Количество': '5', 'Цена': '100' },
{ table: 'Товары', add: true }
);
await clickElement('Провести и закрыть');
// Verify: re-open list, filter or scan, assert by `marker`.
```
Use a unique marker (`Date.now()` or random suffix) so re-runs don't collide. Identify your own row by it, not by position or natural keys that may already exist in the DB.
A minimal CRUD shape is in *Test file anatomy* above — use it as the rhythm for catalog/document tests, swapping in the right section/command/fields. The patterns below cover what's specific to the regression engine, not the browser API (those live in SKILL.md).
### DCS report
@@ -335,7 +311,7 @@ export default async function({ clerk, manager, step, assert }) {
});
await step('Кладовщик видит новый статус', async () => {
const s = await clerk.getFormState();
assert.equal(s.fields.find(f => f.name === 'Статус')?.value, 'Утверждён');
assert.equal(s.fields['Статус']?.value, 'Утверждён');
});
await step('Освободить сессию кладовщика', async () => {
await manager.closeContext('clerk'); // free a 1C license for the next test
@@ -343,7 +319,7 @@ export default async function({ clerk, manager, step, assert }) {
}
```
License caveat: stock 1C allows ~2 web sessions concurrently. Close contexts you no longer need before the next multi-user test starts.
Close contexts you no longer need (`manager.closeContext('clerk')`) before the next multi-user test starts — frees a 1C web-client license and stops the previous role from holding state.
### Failing-test repro
@@ -356,37 +332,52 @@ export default async function({ openCommand, clickElement, getFormState, assert,
await clickElement('Создать');
await clickElement('Провести');
const s = await getFormState();
assert.ok(s.errorModal || s.fields.find(f => f.name === 'Контрагент')?.required,
assert.ok(s.errorModal || s.fields['Контрагент']?.required,
'Должна быть ошибка валидации или поле помечено обязательным');
}
```
Write it red first, hand it to the user, fix the underlying issue, re-run green.
### Parameterised test
```js
export const name = 'Заполнение поля {type}';
export const params = [
{ type: 'String', field: 'Наименование', value: 'Тест' },
{ type: 'Number', field: 'Цена', value: '100.50' },
{ type: 'Date', field: 'ДатаПоступления', value: '01.01.2024' },
];
export default async function({ fillFields, getFormState, assert }, { type, field, value }) {
await fillFields({ [field]: value });
const state = await getFormState();
assert.equal(state.fields[field]?.value, String(value));
}
```
Each `params` entry becomes its own test in the report. `{key}` placeholders in `name` get substituted; without placeholders, a `[index]` suffix is added. `ctx.testInfo.param` carries the current row.
## Running
```bash
node $RUN test tests/<app-name>/ # full app suite
node $RUN test tests/<app-name>/03-goods-receipt/ # one feature folder
node $RUN test tests/<app-name>/ # full app suite
node $RUN test tests/<app-name>/03-goods-receipt/ # one feature folder
node $RUN test tests/<app-name>/02-counterparties/01-create.test.mjs # one file
node $RUN test tests/<app-name>/ --tags=smoke # by tag (intersection)
node $RUN test tests/<app-name>/ --grep='накладн' # by name regex
node $RUN test tests/<app-name>/ --bail --retry=1 # stop on first fail, allow 1 retry
node $RUN test tests/<app-name>/02-x.test.mjs tests/<app-name>/05-y.test.mjs # several files
node $RUN test tests/<app-name>/ --tags=smoke # by tag (intersection)
node $RUN test tests/<app-name>/ --grep='накладн' # by name regex
node $RUN test tests/<app-name>/ --bail --retry=1 # stop on first fail, allow 1 retry
node $RUN test tests/<app-name>/ --report=allure-results --format=allure --report-dir=allure-results
node $RUN test tests/<app-name>/ -- --rebuild-stand # everything after `--` goes to hooks
node $RUN test tests/<app-name>/ --report=- # machine JSON to stdout, progress to stderr
node $RUN test tests/<app-name>/ -- --rebuild-stand # after `--` → hookArgs
```
Default report is JSON when `--report=` is given. Allure needs `--format=allure` + a directory. JUnit similarly with `--format=junit`.
**Output contract.** `test` behaves like a test runner: by default the human report (with the summary as the last line) goes to **stdout** — read the tail of stdout + exit code. The machine report is opt-in via `--report`: `--report=path` writes it to a file (default JSON; XML for `--format=junit`), `--report=-` writes it to stdout while progress moves to stderr. Allure needs `--format=allure` + a directory (`-` is invalid for allure). For detailed triage use `--report=path` or `--report=-`. **In `--report=-` mode never use `2>&1`** — it merges stderr progress into the stdout JSON. (In the default mode there is no JSON in stdout, so `… | tail` is safe.)
### Allure static config — `_allure/` directory
### Allure static config — `_allure/`
The runner copies `<testDir>/_allure/` into the report directory before generating Allure output. Standard Allure convention applies — three files are typically used:
- **`categories.json`** — failure classification. Always emit this when setting up a suite, with 1C-specific patterns: license pool exhaustion (`Не обнаружено свободной лицензии`), 1C application errors (`ВызватьИсключение|Произошла ошибка|…`), navigation/element lookup misses, runner timeouts, assertion failures.
- **`environment.properties`** — `key=value` lines for the Environment widget. Useful when the suite runs across builds/branches (URL, 1C platform version, git branch, configuration version). Often emitted dynamically by `prepare()` rather than committed as a static file.
- **`executor.json`** — CI metadata (Jenkins URL, GitHub run ID, etc.). Only relevant when the suite runs on a CI server; for local runs, skip it.
Discovery skips the underscored directory, so it never collides with tests.
The runner copies `<testDir>/_allure/` into the report directory before generating Allure output. Drop in `categories.json` (regex-based failure classification — useful for 1C-specific buckets: license pool exhaustion, platform exceptions, runner timeouts, assertion failures), `environment.properties` (optional, often emitted dynamically by `prepare()`), `executor.json` (CI metadata, skip locally). The underscore prefix keeps the directory out of test discovery.
## Severity guidance
@@ -404,26 +395,26 @@ Don't promote everything to `critical` — it loses signal in the Allure dashboa
## Anti-patterns
- **Sleeps as a substitute for assertions.** `wait(5)` after `openCommand` is fine; `wait(30)` because something flakes is a bug — find what state you can wait on with `getFormState` instead.
- **Sleeps as a substitute for assertions.** `wait(5)` after `openCommand` is fine; `wait(30)` because something flakes is a bug — wait on `getFormState` instead.
- **Retry as a substitute for understanding.** "Not found" twice means the data isn't there or the label is wrong. Don't loop.
- **Raw DOM via `getPage().$$(...)`.** Use `getFormState`, `readTable`, `readSpreadsheet`. Raw selectors break across 1C platform versions.
- **`clickElement('×')` or `clickElement('Закрыть')`** to dismiss a form. Use `closeForm({ save: true|false })` — handles confirmation correctly.
- **Position-based row identification** (`rows[0]`) when the DB has shared seed data. Filter by unique marker or label instead.
- **Skipping recon** because "I know what this catalog looks like." You don't — the project's customisation almost certainly differs from a stock config.
- **Position-based row identification** (`rows[0]`) when the DB has shared seed data. Filter by a unique marker (`Date.now()` suffix) instead.
- **Hand-writing reset code in `afterEach`.** The runner already closes forms and dismisses errors after the hook.
- **Cross-test state assumptions.** Each test must start from the desktop and seed its own data. Order-of-execution coupling is a regression-suite trap.
- **`tags: ['smoke']` on a 90-second test.** Smoke means fast.
- **Hand-writing reset code** in `afterEach`. The runner already closes forms and dismisses errors.
- **Cross-test state assumptions.** Each test must start from desktop and seed its own data. Order-of-execution coupling is a regression-suite trap.
- **Skipping recon** because "I know what this catalog looks like." The project's customisation almost certainly differs from stock.
(General browser-API anti-patterns — raw DOM, `clickElement('Закрыть')` instead of `closeForm()` — live in SKILL.md.)
## After a run — failure triage
1. Scan the JSON or Allure summary for `failed`.
2. For each failure, read `error.message` + `error.step` + screenshot (saved next to the report).
2. For each failure, read `error.message` + `error.step` + screenshot.
3. If `error.onecError.stack` is present — it's a 1C exception, look at the platform trace.
4. Classify:
- **Test bug** — selector wrong, expectation wrong, race with no anchor → fix the test.
- **Application bug** — actual misbehaviour reproduced → report to the user with the failing step name and the platform stack.
- **Stand flake** — Apache timeout, login form not loading, license shortage → fix the hook idempotency or session-cleanup logic, not the test.
5. After fixes, re-run only the affected files (`node $RUN test tests/03-goods-receipt/`) before the full suite.
5. After fixes, re-run only the affected files before the full suite.
Report back to the user with the classification, not raw failure dumps.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,36 @@
// web-test cli/commands/exec v1.0 — send script to running server
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import http from 'http';
import { readFileSync } from 'fs';
import { resolve } from 'path';
import { out, die, readStdin } from '../util.mjs';
import { loadSession } from '../session.mjs';
export async function cmdExec(fileOrDash, flags = {}) {
if (!fileOrDash) die('Usage: node src/run.mjs exec <file|-> [--no-record]');
const code = fileOrDash === '-'
? await readStdin()
: readFileSync(resolve(fileOrDash), 'utf-8');
const sess = loadSession();
const headers = {};
if (flags.noRecord) headers['x-no-record'] = '1';
const timeoutMs = flags.execTimeoutMs ?? 30 * 60 * 1000;
const result = await new Promise((resolveP, reject) => {
const req = http.request({
hostname: '127.0.0.1', port: sess.port, path: '/exec',
method: 'POST', timeout: timeoutMs, headers,
}, res => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => { try { resolveP(JSON.parse(data)); } catch { reject(new Error(data)); } });
});
req.on('error', reject);
req.on('timeout', () => { req.destroy(new Error(`Exec timeout (${Math.round(timeoutMs / 60000)} min)`)); });
req.write(code);
req.end();
});
out(result);
if (!result.ok) process.exit(1);
}
@@ -0,0 +1,22 @@
// web-test cli/commands/run v1.0 — autonomous connect → exec → disconnect (no server)
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { readFileSync } from 'fs';
import { resolve } from 'path';
import * as browser from '../../browser.mjs';
import { out, die, readStdin } from '../util.mjs';
import { executeScript } from '../exec-context.mjs';
export async function cmdRun(url, fileOrDash) {
if (!url || !fileOrDash) die('Usage: node src/run.mjs run <url> <file|->');
const code = fileOrDash === '-'
? await readStdin()
: readFileSync(resolve(fileOrDash), 'utf-8');
await browser.connect(url);
const result = await executeScript(code);
await browser.disconnect();
out(result);
if (!result.ok) process.exit(1);
}
@@ -0,0 +1,18 @@
// web-test cli/commands/shot v1.0 — take screenshot via server
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { writeFileSync } from 'fs';
import { out, die } from '../util.mjs';
import { loadSession } from '../session.mjs';
export async function cmdShot(file) {
const sess = loadSession();
const resp = await fetch(`http://127.0.0.1:${sess.port}/shot`);
if (!resp.ok) {
const err = await resp.text();
die(`Screenshot failed: ${err}`);
}
const buf = Buffer.from(await resp.arrayBuffer());
const outFile = file || 'shot.png';
writeFileSync(outFile, buf);
out({ ok: true, file: outFile });
}
@@ -0,0 +1,33 @@
// web-test cli/commands/start v1.0
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import http from 'http';
import { writeFileSync } from 'fs';
import * as browser from '../../browser.mjs';
import { out, die } from '../util.mjs';
import { SESSION_FILE, cleanup } from '../session.mjs';
import { handleRequest } from '../server.mjs';
export async function cmdStart(url) {
if (!url) die('Usage: node src/run.mjs start <url>');
const state = await browser.connect(url);
const httpServer = http.createServer(handleRequest);
httpServer.listen(0, '127.0.0.1', () => {
const port = httpServer.address().port;
const session = {
port,
url,
pid: process.pid,
startedAt: new Date().toISOString()
};
writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
out({ ok: true, message: 'Browser ready', port, ...state });
});
process.on('SIGINT', async () => {
await browser.disconnect();
cleanup();
process.exit(0);
});
}
@@ -0,0 +1,14 @@
// web-test cli/commands/status v1.0 — check session
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { existsSync, readFileSync } from 'fs';
import { out } from '../util.mjs';
import { SESSION_FILE } from '../session.mjs';
export function cmdStatus() {
if (!existsSync(SESSION_FILE)) {
out({ ok: false, message: 'No active session' });
process.exit(1);
}
const sess = JSON.parse(readFileSync(SESSION_FILE, 'utf-8'));
out({ ok: true, ...sess });
}
@@ -0,0 +1,17 @@
// web-test cli/commands/stop v1.0 — send stop to server
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { out } from '../util.mjs';
import { loadSession, cleanup } from '../session.mjs';
export async function cmdStop() {
const sess = loadSession();
try {
const resp = await fetch(`http://127.0.0.1:${sess.port}/stop`, { method: 'POST' });
const result = await resp.json();
out(result);
} catch {
// Server may have already exited before responding
out({ ok: true, message: 'Stopped' });
}
cleanup();
}
@@ -0,0 +1,458 @@
// web-test cli/commands/test v1.3 — regression test runner
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { existsSync, writeFileSync, mkdirSync } from 'fs';
import { resolve, dirname, basename, relative } from 'path';
import * as browser from '../../browser.mjs';
import { out, die, elapsed, slugify, formatDuration, interpolate, printSteps } from '../util.mjs';
import { buildContext, buildScopedContext } from '../exec-context.mjs';
import { createAssertions } from '../test-runner/assertions.mjs';
import { buildSeverityIndex } from '../test-runner/severity.mjs';
import { writeAllure, buildJUnit, syncAllureExtras } from '../test-runner/reporters.mjs';
import { discoverTests, resetState } from '../test-runner/discover.mjs';
export async function cmdTest(rawArgs) {
// Split off everything after `--` — those args belong to user-defined hooks
// (see spec §6: "all arguments after `--` are forwarded verbatim to _hooks.mjs
// via the hookArgs field; the runner does not interpret them").
const sepIdx = rawArgs.indexOf('--');
const ownArgs = sepIdx >= 0 ? rawArgs.slice(0, sepIdx) : rawArgs;
const hookArgs = sepIdx >= 0 ? rawArgs.slice(sepIdx + 1) : [];
// Parse flags
const opts = { bail: false, retry: 0, timeout: 30000, report: null, format: 'json', screenshot: null, reportDir: null, record: false };
let tags = null, grep = null, urlFlag = null;
const positional = [];
for (const a of ownArgs) {
if (a.startsWith('--tags=')) tags = a.slice(7).split(',');
else if (a.startsWith('--grep=')) grep = new RegExp(a.slice(7), 'i');
else if (a.startsWith('--url=')) urlFlag = a.slice(6);
else if (a === '--bail') opts.bail = true;
else if (a.startsWith('--retry=')) opts.retry = parseInt(a.slice(8)) || 0;
else if (a.startsWith('--timeout=')) opts.timeout = parseInt(a.slice(10)) || 30000;
else if (a.startsWith('--report=')) opts.report = a.slice(9);
else if (a.startsWith('--format=')) opts.format = a.slice(9);
else if (a.startsWith('--screenshot=')) opts.screenshot = a.slice(13);
else if (a.startsWith('--report-dir=')) opts.reportDir = a.slice(13);
else if (a === '--record') opts.record = true;
else if (!a.startsWith('--')) positional.push(a);
}
// Positional args are ALWAYS test paths (one or many). URL comes from --url= or config
// (see webtest.config.mjs). This matches pytest/jest/playwright; a positional that looks
// like a URL is a mistake → fail fast with a hint instead of feeding it to page.goto().
const isUrl = (s) => /^https?:\/\//i.test(s);
let url = urlFlag || null;
const testPaths = [...positional];
if (testPaths.length === 0) {
die('Usage: node run.mjs test <dir|file>... [--url=URL] [--tags=...] [--grep=...] [--bail] [--retry=N] [--timeout=ms] [--report=path]');
}
for (const p of testPaths) {
if (existsSync(resolve(p))) continue;
if (isUrl(p)) {
die(`"${p}" looks like a URL — use --url=<url>; positional args are test paths.`);
}
die(`Test path not found: "${p}". To run a subset use --grep= / --tags=, or pass an existing dir/file.`);
}
// Load config if exists. config (webtest.config.mjs) and hooks (_hooks.mjs) resolve from
// the FIRST path's directory — list paths from the same suite folder.
const firstPath = resolve(testPaths[0]);
const isFile = firstPath.endsWith('.test.mjs');
const testDir = isFile ? dirname(firstPath) : firstPath;
const configPath = resolve(testDir, 'webtest.config.mjs');
let config = {};
if (existsSync(configPath)) {
const mod = await import('file:///' + configPath.replace(/\\/g, '/'));
config = mod.default || {};
}
const severityIndex = buildSeverityIndex(config);
// Build context registry: name → url. Supports config.contexts or single config.url / CLI url.
const contextSpecs = {};
let defaultContextName = 'default';
const defaultIsolation = config.isolation || 'tab';
if (config.contexts && typeof config.contexts === 'object' && Object.keys(config.contexts).length) {
for (const [n, spec] of Object.entries(config.contexts)) {
contextSpecs[n] = { ...spec };
}
defaultContextName = config.defaultContext || Object.keys(config.contexts)[0];
if (url) contextSpecs[defaultContextName] = { ...contextSpecs[defaultContextName], url };
} else {
const fallbackUrl = url || config.url;
if (!fallbackUrl) die('No URL provided and no webtest.config.mjs found');
contextSpecs.default = { url: fallbackUrl };
}
if (!contextSpecs[defaultContextName]) {
die(`defaultContext "${defaultContextName}" not found in contexts: [${Object.keys(contextSpecs).join(', ')}]`);
}
if (!url) url = contextSpecs[defaultContextName].url;
// Apply config defaults (CLI flags override)
if (!tags && config.tags) tags = config.tags;
opts.timeout = ownArgs.some(a => a.startsWith('--timeout=')) ? opts.timeout : (config.timeout || opts.timeout);
opts.retry = ownArgs.some(a => a.startsWith('--retry=')) ? opts.retry : (config.retries || opts.retry);
if (config.preserveClipboard === false && !ownArgs.includes('--no-preserve-clipboard')) {
browser.setPreserveClipboard(false);
}
opts.record = opts.record || !!config.record;
opts.screenshot = opts.screenshot || config.screenshot || 'on-failure';
if (!['on-failure', 'every-step', 'off'].includes(opts.screenshot)) {
die(`Invalid --screenshot=${opts.screenshot} (expected on-failure|every-step|off)`);
}
if (!['json', 'allure', 'junit'].includes(opts.format)) {
die(`Invalid --format=${opts.format} (expected json|allure|junit)`);
}
if (opts.format === 'junit' && !opts.report) {
die('--format=junit requires --report=path.xml');
}
// `--report=-` means "machine report to stdout" (Unix `-` convention).
// Only meaningful for streamable formats (json/junit); allure is a directory.
const reportToStdout = opts.report === '-';
if (reportToStdout && opts.format === 'allure') {
die('--report=- (stdout) is not valid with --format=allure: allure emits a directory of files, not a single stream. Use --report-dir=<dir> instead.');
}
const reportDir = opts.reportDir
? resolve(opts.reportDir)
: (opts.report && !reportToStdout ? dirname(resolve(opts.report)) : testDir);
if (opts.screenshot !== 'off') {
try { mkdirSync(reportDir, { recursive: true }); } catch {}
}
// Discover test files
const testFiles = discoverTests(testPaths);
if (!testFiles.length) die(`No *.test.mjs files found in ${testPaths.join(', ')}`);
// Import and filter tests
const tests = [];
let hasOnly = false;
for (const file of testFiles) {
const mod = await import('file:///' + file.replace(/\\/g, '/'));
const base = {
file: relative(testDir, file).replace(/\\/g, '/'),
name: mod.name || basename(file, '.test.mjs'),
tags: mod.tags || [],
timeout: mod.timeout || opts.timeout,
skip: mod.skip || false,
only: mod.only || false,
setup: mod.setup,
teardown: mod.teardown,
fn: mod.default,
param: undefined,
context: mod.context || null,
contexts: Array.isArray(mod.contexts) ? mod.contexts : null,
severity: typeof mod.severity === 'string' ? mod.severity : null,
};
if (base.only) hasOnly = true;
if (Array.isArray(mod.params) && mod.params.length) {
for (let i = 0; i < mod.params.length; i++) {
const p = mod.params[i];
const name = base.name.includes('{') ? interpolate(base.name, p) : `${base.name}[${i}]`;
tests.push({ ...base, name, param: p });
}
} else {
tests.push(base);
}
}
// Filter
const filtered = tests.filter(t => {
if (hasOnly && !t.only) return false;
if (tags && !tags.some(tag => t.tags.includes(tag))) return false;
if (grep && !grep.test(t.name)) return false;
return true;
});
// Load hooks
const hooksPath = resolve(testDir, '_hooks.mjs');
let hooks = {};
if (existsSync(hooksPath)) {
hooks = await import('file:///' + hooksPath.replace(/\\/g, '/'));
}
// Human-readable report goes to stdout (test-runner convention: jest/pytest/playwright).
// In `--report -` mode the machine JSON/XML takes over stdout, so progress moves to stderr.
const W = reportToStdout ? process.stderr : process.stdout;
W.write(`\nweb-test -- ${url}\n`);
W.write(`Running ${filtered.length} tests from ${relative(process.cwd(), testDir).replace(/\\/g, '/') || '.'}/\n\n`);
const startedAt = new Date().toISOString();
const results = [];
let passCount = 0, failCount = 0, skipCount = 0;
const hookLog = (...a) => W.write(`[hooks] ${a.map(String).join(' ')}\n`);
const hookEnv = { hookArgs, log: hookLog, config };
if (hooks.prepare) await hooks.prepare(hookEnv);
// Lazy context creation
async function ensureContext(name) {
if (browser.hasContext(name)) return;
const spec = contextSpecs[name];
if (!spec) throw new Error(`Unknown context "${name}". Defined: [${Object.keys(contextSpecs).join(', ')}]`);
await browser.createContext(name, spec.url, { isolation: spec.isolation || defaultIsolation });
if (hooks.afterOpenContext && hookCtx) {
try { await hooks.afterOpenContext(hookCtx, name, spec); }
catch (e) { hookLog(`afterOpenContext("${name}") threw: ${e.message.split('\n')[0]}`); }
}
}
let hookCtx = null;
function wrapCloseContextHook(target) {
const orig = target.closeContext;
if (typeof orig !== 'function') return;
target.closeContext = async (name) => {
if (hooks.beforeCloseContext) {
try { await hooks.beforeCloseContext(target, name, contextSpecs[name]); }
catch (e) { hookLog(`beforeCloseContext("${name}") threw: ${e.message.split('\n')[0]}`); }
}
return await orig(name);
};
}
try {
// Connect: create default context up front
await ensureContext(defaultContextName);
const ctx = buildContext({ noRecord: false });
ctx.assert = createAssertions();
ctx.log = (...a) => { /* per-test, overridden below */ };
wrapCloseContextHook(ctx);
hookCtx = ctx;
// Default context was created BEFORE hookCtx existed → fire afterOpenContext now.
if (hooks.afterOpenContext) {
try { await hooks.afterOpenContext(ctx, defaultContextName, contextSpecs[defaultContextName]); }
catch (e) { hookLog(`afterOpenContext("${defaultContextName}") threw: ${e.message.split('\n')[0]}`); }
}
if (hooks.beforeAll) await hooks.beforeAll(ctx);
let testIdx = 0;
for (const t of filtered) {
testIdx++;
const declaredContexts = t.contexts && t.contexts.length
? t.contexts
: [t.context || defaultContextName];
if (t.skip) {
const reason = typeof t.skip === 'string' ? t.skip : '';
W.write(`${t.name}${reason ? ` (skip: ${reason})` : ' (skip)'}\n`);
results.push({ name: t.name, file: t.file, tags: t.tags, contexts: declaredContexts, status: 'skipped', duration: 0, attempts: 0, steps: [], output: '', error: null, screenshot: null });
skipCount++;
continue;
}
const testContextNames = declaredContexts;
try {
for (const cn of testContextNames) await ensureContext(cn);
await browser.setActiveContext(testContextNames[0]);
} catch (e) {
W.write(`${t.name} (context setup failed: ${e.message})\n`);
results.push({ name: t.name, file: t.file, tags: t.tags, contexts: declaredContexts, status: 'failed', duration: 0, attempts: 0, steps: [], output: '', error: { message: e.message }, screenshot: null });
failCount++;
if (opts.bail) break;
continue;
}
let lastError = null;
let testResult = null;
const maxAttempts = 1 + opts.retry;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const output = [];
let steps = [];
let currentSteps = steps;
let stepIdx = 0;
const t0 = Date.now();
ctx.testInfo = {
name: t.name,
file: basename(t.file),
filePath: t.file,
tags: t.tags,
timeout: t.timeout,
attempt,
maxAttempts,
param: t.param,
contexts: Object.fromEntries(testContextNames.map(n => [n, contextSpecs[n]])),
primaryContext: testContextNames[0],
};
ctx.testResult = null;
let videoFile = null;
if (opts.record) {
videoFile = resolve(reportDir, `${testIdx}-${slugify(t.name)}.mp4`);
try { await browser.startRecording(videoFile, { force: true }); } catch { videoFile = null; }
}
ctx.log = (...a) => output.push(a.map(String).join(' '));
ctx.step = async (name, fn) => {
const s = { name, start: Date.now(), status: 'passed', steps: [] };
currentSteps.push(s);
const prev = currentSteps;
currentSteps = s.steps;
stepIdx++;
const myIdx = stepIdx;
try {
await fn();
} catch (e) {
s.status = 'failed';
s.error = e.message;
throw e;
} finally {
s.stop = Date.now();
currentSteps = prev;
if (opts.screenshot === 'every-step' && s.status === 'passed') {
try {
const slug = slugify(name);
const file = resolve(reportDir, `${testIdx}-${myIdx}-${slug}.png`);
const png = await browser.screenshot();
writeFileSync(file, png);
s.screenshot = file;
} catch {}
}
}
};
const scopedKeys = [];
if (t.contexts && t.contexts.length) {
for (const cn of t.contexts) {
ctx[cn] = buildScopedContext(cn);
wrapCloseContextHook(ctx[cn]);
scopedKeys.push(cn);
}
}
try {
if (hooks.beforeEach) await hooks.beforeEach(ctx);
if (t.setup) await t.setup(ctx);
let timeoutTimer;
try {
await Promise.race([
t.fn(ctx, t.param),
new Promise((_, reject) => { timeoutTimer = setTimeout(() => reject(new Error(`Timeout (${t.timeout}ms)`)), t.timeout); }),
]);
} finally {
// Clear the guard timer — otherwise it stays armed in the event loop and,
// since the success path never calls process.exit(), node can't exit until
// it fires (up to `timeout` ms after the last test finished).
clearTimeout(timeoutTimer);
}
if (t.teardown) try { await t.teardown(ctx); } catch {}
ctx.testResult = { status: 'passed', duration: elapsed(t0), attempts: attempt, error: null, steps };
if (hooks.afterEach) try { await hooks.afterEach(ctx); } catch {}
for (const cn of testContextNames) {
try { await browser.setActiveContext(cn); await resetState(ctx); } catch {}
}
for (const k of scopedKeys) delete ctx[k];
if (videoFile) {
try { await browser.stopRecording(); } catch {}
}
const dur = elapsed(t0);
testResult = { name: t.name, file: t.file, tags: t.tags, contexts: testContextNames, severity: t.severity, status: 'passed', duration: dur, attempts: attempt, start: t0, stop: Date.now(), steps, output: output.join('\n'), error: null, screenshot: null, video: videoFile };
lastError = null;
break;
} catch (e) {
// Screenshot on failure FIRST — before teardown/afterEach/resetState reset the UI.
let shotFile = e.onecError?.screenshot;
if (!shotFile && opts.screenshot !== 'off') {
try {
const png = await browser.screenshot();
shotFile = resolve(reportDir, `error-${testIdx}-${slugify(t.file.replace(/\.test\.mjs$/, ''))}.png`);
writeFileSync(shotFile, png);
} catch {}
}
if (t.teardown) try { await t.teardown(ctx); } catch {}
const errInfo = { message: e.message, step: e.onecError?.step, screenshot: shotFile, onecError: e.onecError };
ctx.testResult = { status: 'failed', duration: elapsed(t0), attempts: attempt, error: errInfo, steps };
if (hooks.afterEach) try { await hooks.afterEach(ctx); } catch {}
for (const cn of testContextNames) {
try { await browser.setActiveContext(cn); await resetState(ctx); } catch {}
}
for (const k of scopedKeys) delete ctx[k];
if (videoFile) {
try { await browser.stopRecording(); } catch {}
}
lastError = errInfo;
const dur = elapsed(t0);
testResult = { name: t.name, file: t.file, tags: t.tags, contexts: testContextNames, severity: t.severity, status: 'failed', duration: dur, attempts: attempt, start: t0, stop: Date.now(), steps, output: output.join('\n'), error: errInfo, screenshot: shotFile, video: videoFile };
}
}
results.push(testResult);
if (testResult.status === 'passed') {
passCount++;
W.write(`${t.name} (${testResult.duration}s)\n`);
} else {
failCount++;
W.write(`${t.name} (${testResult.duration}s)\n`);
printSteps(W, testResult.steps, ' ');
if (lastError?.message) W.write(` ${lastError.message}\n`);
if (lastError?.screenshot) W.write(` screenshot: ${lastError.screenshot}\n`);
}
if (opts.bail && testResult.status === 'failed') break;
}
if (hooks.afterAll) try { await hooks.afterAll(ctx); } catch {}
} finally {
// Per-context teardown
try {
const remaining = browser.listContexts();
if (remaining.length > 0) {
const survivor = remaining[0];
try { await browser.setActiveContext(survivor); } catch {}
for (let i = remaining.length - 1; i >= 1; i--) {
const name = remaining[i];
if (hooks.beforeCloseContext && hookCtx) {
try { await hooks.beforeCloseContext(hookCtx, name, contextSpecs[name]); }
catch (e) { hookLog(`beforeCloseContext("${name}") threw: ${e.message.split('\n')[0]}`); }
}
try { await browser.closeContext(name); }
catch (e) { hookLog(`closeContext("${name}") failed: ${e.message.split('\n')[0]}`); }
}
if (hooks.beforeCloseContext && hookCtx) {
try { await hooks.beforeCloseContext(hookCtx, survivor, contextSpecs[survivor]); }
catch (e) { hookLog(`beforeCloseContext("${survivor}") threw: ${e.message.split('\n')[0]}`); }
}
}
} catch (e) {
hookLog(`final teardown loop failed: ${e.message.split('\n')[0]}`);
}
try { await browser.disconnect(); } catch {}
if (hooks.cleanup) try { await hooks.cleanup(hookEnv); } catch {}
}
const finishedAt = new Date().toISOString();
const totalDuration = results.reduce((s, r) => s + r.duration, 0);
W.write(`\n${passCount} passed, ${failCount} failed, ${skipCount} skipped (${formatDuration(totalDuration)})\n\n`);
const report = {
runner: 'web-test', url, startedAt, finishedAt,
duration: totalDuration,
summary: { total: results.length, passed: passCount, failed: failCount, skipped: skipCount },
tests: results,
};
if (opts.format === 'allure') {
writeAllure(results, reportDir, severityIndex);
syncAllureExtras(testDir, reportDir);
} else if (opts.format === 'junit') {
if (reportToStdout) process.stdout.write(buildJUnit(report, testDir) + '\n');
else writeFileSync(resolve(opts.report), buildJUnit(report, testDir));
} else if (reportToStdout) {
out(report);
} else if (opts.report) {
writeFileSync(resolve(opts.report), JSON.stringify(report, null, 2));
}
if (failCount > 0) process.exit(1);
}
@@ -0,0 +1,148 @@
// web-test cli/exec-context v1.0 — buildContext + executeScript для run/exec/test
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { readFileSync, writeFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import * as browser from '../browser.mjs';
import { elapsed } from './util.mjs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ERROR_SHOT_PATH = resolve(__dirname, '..', '..', 'error-shot.png');
/**
* Build a per-context wrapper: same shape as buildContext output, but every call
* is prefixed with `setActiveContext(name)` so the test can interleave actions
* across contexts (`ctx.a.click(...); ctx.b.click(...)`).
*/
export function buildScopedContext(name) {
const inner = buildContext({ noRecord: false });
const scoped = {};
for (const [k, v] of Object.entries(inner)) {
if (typeof v === 'function') {
scoped[k] = async (...args) => {
await browser.setActiveContext(name);
return v(...args);
};
} else {
scoped[k] = v;
}
}
return scoped;
}
export function buildContext({ noRecord = false } = {}) {
const ctx = {};
for (const [k, v] of Object.entries(browser)) {
if (k !== 'default') ctx[k] = v;
}
ctx.writeFileSync = writeFileSync;
ctx.readFileSync = readFileSync;
// --no-record: stub recording/narration functions to return safe defaults
if (noRecord) {
const noop = async () => {};
ctx.startRecording = noop;
ctx.stopRecording = async () => ({ file: null, duration: 0, size: 0 });
ctx.addNarration = async () => ({ file: null, duration: 0, size: 0, captions: 0 });
for (const fn of ['showCaption', 'hideCaption']) {
ctx[fn] = noop;
}
ctx.isRecording = () => false;
ctx.getCaptions = () => [];
}
// Wrap action functions to auto-detect 1C errors (modal, balloon)
// and stop execution immediately with diagnostic info
const ACTION_FNS = [
'clickElement', 'fillFields', 'fillField', 'selectValue', 'fillTableRow',
'deleteTableRow', 'openCommand', 'navigateSection', 'navigateLink', 'openFile',
'closeForm', 'filterList', 'unfilterList'
];
for (const name of ACTION_FNS) {
if (typeof ctx[name] !== 'function') continue;
const orig = ctx[name];
ctx[name] = async (...args) => {
const result = await orig(...args);
const errors = result?.errors;
if (errors?.modal || errors?.balloon) {
// Screenshot while the error modal is still visible (before fetchErrorStack closes it)
let errorShot;
try {
const png = await ctx.screenshot();
errorShot = ERROR_SHOT_PATH;
writeFileSync(errorShot, png);
} catch {}
// Try to fetch call stack for modal errors before throwing
let stack = null;
if (errors?.modal && typeof ctx.fetchErrorStack === 'function') {
try {
stack = await ctx.fetchErrorStack(errors.modal.formNum, errors.modal.hasReport);
} catch { /* don't fail if stack fetch fails */ }
}
const msg = errors.modal?.message || errors.balloon?.message || 'Unknown 1C error';
const err = new Error(msg);
err.onecError = { step: name, args, errors, formState: result, stack, screenshot: errorShot };
throw err;
}
return result;
};
}
return ctx;
}
export async function executeScript(code, { noRecord } = {}) {
const output = [];
const origLog = console.log;
const origErr = console.error;
console.log = (...a) => output.push(a.map(String).join(' '));
console.error = (...a) => output.push('[ERR] ' + a.map(String).join(' '));
const t0 = Date.now();
try {
const ctx = buildContext({ noRecord });
// Normalize Windows backslash paths to prevent JS parse errors
// (e.g. C:\Users\... → \u triggers "Invalid Unicode escape sequence")
code = code.replace(/[A-Za-z]:\\[^\s'"`;\n)}\]]+/g, m => m.replace(/\\/g, '/'));
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const fn = new AsyncFunction(...Object.keys(ctx), code);
await fn(...Object.values(ctx));
console.log = origLog;
console.error = origErr;
return { ok: true, output: output.join('\n'), elapsed: elapsed(t0) };
} catch (e) {
console.log = origLog;
console.error = origErr;
// Auto-stop recording if active (prevents "Already recording" on next exec)
if (browser.isRecording()) {
try { await browser.stopRecording(); } catch {}
}
// Error screenshot (skip if already taken before fetchErrorStack closed the modal)
let shotFile = e.onecError?.screenshot;
if (!shotFile) {
try {
const png = await browser.screenshot();
shotFile = ERROR_SHOT_PATH;
writeFileSync(shotFile, png);
} catch {}
}
const result = { ok: false, error: e.message, output: output.join('\n'), screenshot: shotFile, elapsed: elapsed(t0) };
// Enrich with 1C error context if available
if (e.onecError) {
result.step = e.onecError.step;
result.stepArgs = e.onecError.args;
result.onecErrors = e.onecError.errors;
result.formState = e.onecError.formState;
if (e.onecError.stack) result.stack = e.onecError.stack;
}
return result;
}
}
@@ -0,0 +1,37 @@
// web-test cli/server v1.0 — HTTP server для exec/shot/stop/status в процессе start
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import * as browser from '../browser.mjs';
import { json, readBody } from './util.mjs';
import { cleanup } from './session.mjs';
import { executeScript } from './exec-context.mjs';
export async function handleRequest(req, res) {
try {
if (req.method === 'POST' && req.url === '/exec') {
const code = await readBody(req);
const noRecord = req.headers['x-no-record'] === '1';
const result = await executeScript(code, { noRecord });
json(res, result);
} else if (req.method === 'GET' && req.url === '/shot') {
const png = await browser.screenshot();
res.writeHead(200, { 'Content-Type': 'image/png' });
res.end(png);
} else if (req.method === 'POST' && req.url === '/stop') {
json(res, { ok: true, message: 'Stopping' });
await browser.disconnect();
cleanup();
process.exit(0);
} else if (req.method === 'GET' && req.url === '/status') {
json(res, { ok: true, connected: browser.isConnected() });
} else {
res.writeHead(404);
res.end('Not found');
}
} catch (e) {
json(res, { ok: false, error: e.message }, 500);
}
}
@@ -0,0 +1,20 @@
// web-test cli/session v1.0 — session-file helpers for HTTP-server mode
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { existsSync, readFileSync, unlinkSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { die } from './util.mjs';
const __dirname = dirname(fileURLToPath(import.meta.url));
export const SESSION_FILE = resolve(__dirname, '..', '..', '.browser-session.json');
export function loadSession() {
if (!existsSync(SESSION_FILE)) {
die('No active session. Run: node src/run.mjs start <url>');
}
return JSON.parse(readFileSync(SESSION_FILE, 'utf-8'));
}
export function cleanup() {
try { unlinkSync(SESSION_FILE); } catch {}
}
@@ -0,0 +1,64 @@
// web-test cli/test-runner/assertions v1.0 — ctx.assert API
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
export function createAssertions() {
class AssertionError extends Error {
constructor(msg, actual, expected) {
super(msg);
this.name = 'AssertionError';
this.actual = actual;
this.expected = expected;
}
}
return {
ok(value, msg) {
if (!value) throw new AssertionError(msg || `Expected truthy, got ${JSON.stringify(value)}`, value, true);
},
equal(actual, expected, msg) {
if (actual !== expected) throw new AssertionError(msg || `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`, actual, expected);
},
notEqual(actual, expected, msg) {
if (actual === expected) throw new AssertionError(msg || `Expected not ${JSON.stringify(expected)}`, actual, expected);
},
deepEqual(actual, expected, msg) {
const a = JSON.stringify(actual), b = JSON.stringify(expected);
if (a !== b) throw new AssertionError(msg || `Deep equal failed:\n actual: ${a}\n expected: ${b}`, actual, expected);
},
includes(haystack, needle, msg) {
const h = Array.isArray(haystack) ? haystack : String(haystack);
if (!h.includes(needle)) throw new AssertionError(msg || `Expected ${JSON.stringify(h)} to include ${JSON.stringify(needle)}`, haystack, needle);
},
match(string, regex, msg) {
if (!regex.test(string)) throw new AssertionError(msg || `Expected ${JSON.stringify(string)} to match ${regex}`, string, regex);
},
async throws(fn, msg) {
try { await fn(); } catch { return; }
throw new AssertionError(msg || 'Expected function to throw');
},
// 1C-specific
formHasField(state, fieldName, msg) {
if (!state?.fields?.[fieldName]) throw new AssertionError(msg || `Field "${fieldName}" not found in form. Available: ${Object.keys(state?.fields || {}).join(', ')}`, null, fieldName);
},
formTitle(state, expected, msg) {
if (!state?.title?.includes(expected)) throw new AssertionError(msg || `Form title "${state?.title}" does not contain "${expected}"`, state?.title, expected);
},
tableHasRow(table, predicate, msg) {
const rows = table?.rows || [];
let found;
if (typeof predicate === 'function') {
found = rows.some(predicate);
} else {
found = rows.some(r => Object.entries(predicate).every(([k, v]) => r[k] === v));
}
if (!found) throw new AssertionError(msg || `No row matching predicate in table (${rows.length} rows)`, null, predicate);
},
tableRowCount(table, expected, msg) {
const actual = table?.rows?.length ?? 0;
if (actual !== expected) throw new AssertionError(msg || `Expected ${expected} rows, got ${actual}`, actual, expected);
},
noErrors(state, msg) {
if (state?.errors) throw new AssertionError(msg || `Form has errors: ${JSON.stringify(state.errors)}`, state.errors, null);
},
};
}
@@ -0,0 +1,43 @@
// web-test cli/test-runner/discover v1.1 — test file discovery + state reset between tests
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { existsSync, readdirSync } from 'fs';
import { resolve } from 'path';
// Accepts a single path or an array of paths (files and/or dirs). Each .test.mjs file is
// taken directly; each directory is walked recursively (skipping _ / . prefixes). Results
// are deduped and sorted — sorting preserves the numeric-prefix order the suite relies on
// (00-, 01-, …) even when paths are listed out of order.
export function discoverTests(testPaths) {
const paths = Array.isArray(testPaths) ? testPaths : [testPaths];
const files = [];
function walk(dir) {
for (const entry of readdirSync(dir, { withFileTypes: true })) {
if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;
const full = resolve(dir, entry.name);
if (entry.isDirectory()) walk(full);
else if (entry.name.endsWith('.test.mjs')) files.push(full);
}
}
for (const p of paths) {
const full = resolve(p);
if (full.endsWith('.test.mjs')) {
if (existsSync(full)) files.push(full);
} else if (existsSync(full)) {
walk(full);
}
}
return [...new Set(files)].sort();
}
export async function resetState(ctx) {
try { if (typeof ctx.dismissPendingErrors === 'function') await ctx.dismissPendingErrors(); } catch {}
for (let i = 0; i < 10; i++) {
try {
const state = await ctx.getFormState();
// form === null means no form open (desktop). form === 0 is a real background form
// 1C exposes in some states — must still close it to fully reset.
if (state.form == null) break;
await ctx.closeForm({ save: false });
} catch { break; }
}
}
@@ -0,0 +1,113 @@
// web-test cli/test-runner/reporters v1.0 — Allure/JUnit writers + extras sync
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { writeFileSync, existsSync, readdirSync, copyFileSync, statSync } from 'fs';
import { resolve, dirname, basename, relative } from 'path';
import { randomUUID } from 'crypto';
import { xmlEscape } from '../util.mjs';
import { resolveSeverity } from './severity.mjs';
/**
* Copy any files from `<testDir>/_allure/` into `reportDir`. Convention for
* Allure customization that doesn't fit inside per-test JSON:
* - `categories.json` failure classification (regex bucket)
* - `environment.properties` values shown in the Environment widget
* - `executor.json` CI/CD metadata
* Underscored folder mirrors `_hooks.mjs` convention (infra, not a test).
* Silent if folder absent.
*/
export function syncAllureExtras(testDir, reportDir) {
const extrasDir = resolve(testDir, '_allure');
if (!existsSync(extrasDir)) return;
try {
if (!statSync(extrasDir).isDirectory()) return;
} catch { return; }
for (const entry of readdirSync(extrasDir, { withFileTypes: true })) {
if (!entry.isFile()) continue;
try { copyFileSync(resolve(extrasDir, entry.name), resolve(reportDir, entry.name)); }
catch { /* best-effort */ }
}
}
export function writeAllure(results, reportDir, severityIndex) {
for (const tr of results) {
if (tr.status === 'skipped') continue; // Allure ignores skipped without start/stop
const uuid = randomUUID();
const suite = dirname(tr.file);
const suiteLabel = (suite && suite !== '.') ? suite : 'root';
const severity = resolveSeverity(tr, severityIndex);
const out = {
uuid,
name: tr.name,
fullName: tr.file,
status: tr.status,
stage: 'finished',
start: tr.start,
stop: tr.stop,
labels: [
...(tr.tags || []).map(t => ({ name: 'tag', value: t })),
{ name: 'suite', value: suiteLabel },
{ name: 'severity', value: severity },
],
steps: (tr.steps || []).map(allureStep),
attachments: [
...(tr.screenshot ? [{ name: 'Screenshot on failure', source: basename(tr.screenshot), type: 'image/png' }] : []),
...(tr.video ? [{ name: 'Video', source: basename(tr.video), type: 'video/mp4' }] : []),
],
};
if (tr.status === 'failed' && tr.error) {
const traceParts = [];
if (tr.output) traceParts.push(tr.output);
const onecStack = tr.error.onecError?.stack?.raw;
if (onecStack) {
if (traceParts.length) traceParts.push('\n--- 1C stack ---\n');
traceParts.push(onecStack);
}
out.statusDetails = { message: tr.error.message || '', trace: traceParts.join('') };
}
writeFileSync(resolve(reportDir, `${uuid}-result.json`), JSON.stringify(out, null, 2));
}
}
function allureStep(s) {
const out = {
name: s.name,
status: s.status,
stage: 'finished',
start: s.start,
stop: s.stop,
steps: (s.steps || []).map(allureStep),
};
if (s.screenshot) {
out.attachments = [{ name: 'Screenshot', source: basename(s.screenshot), type: 'image/png' }];
}
if (s.status === 'failed' && s.error) {
out.statusDetails = { message: s.error, trace: s.error };
}
return out;
}
export function buildJUnit(report, testDir) {
const { summary, duration, tests } = report;
const suiteName = relative(process.cwd(), testDir).replace(/\\/g, '/') || '.';
const lines = ['<?xml version="1.0" encoding="UTF-8"?>'];
lines.push(`<testsuites name="web-test" tests="${summary.total}" failures="${summary.failed}" skipped="${summary.skipped}" time="${duration.toFixed(3)}">`);
lines.push(` <testsuite name="${xmlEscape(suiteName)}" tests="${summary.total}" failures="${summary.failed}" skipped="${summary.skipped}" time="${duration.toFixed(3)}">`);
for (const t of tests) {
const attrs = `name="${xmlEscape(t.name)}" classname="${xmlEscape(t.file)}" time="${(t.duration || 0).toFixed(3)}"`;
if (t.status === 'passed') {
lines.push(` <testcase ${attrs}/>`);
} else if (t.status === 'skipped') {
lines.push(` <testcase ${attrs}><skipped/></testcase>`);
} else {
lines.push(` <testcase ${attrs}>`);
const msg = t.error?.message || '';
const trace = t.output || '';
lines.push(` <failure message="${xmlEscape(msg)}">${xmlEscape(trace)}</failure>`);
if (t.screenshot) lines.push(` <system-out>screenshot: ${xmlEscape(t.screenshot)}</system-out>`);
lines.push(` </testcase>`);
}
}
lines.push(` </testsuite>`);
lines.push(`</testsuites>`);
return lines.join('\n');
}
@@ -0,0 +1,66 @@
// web-test cli/test-runner/severity v1.0 — Allure severity policy resolver
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { die } from '../util.mjs';
export const SEVERITY_RANK = { blocker: 5, critical: 4, normal: 3, minor: 2, trivial: 1 };
export const SEVERITY_LEVELS = Object.keys(SEVERITY_RANK);
/**
* Validate config.severity (inverted map: severity [tags]) at config load time.
* Returns:
* - tagToSeverity: Map<tag, severity> (precomputed lookup for the resolver)
* - defaultSeverity: string (validated, defaults to 'normal')
* Throws (via die) on invalid keys, invalid default, or duplicate tag across buckets.
*/
export function buildSeverityIndex(config) {
const tagToSeverity = new Map();
const sev = config.severity || {};
if (typeof sev !== 'object' || Array.isArray(sev)) {
die(`config.severity must be an object, got ${typeof sev}`);
}
for (const [level, tags] of Object.entries(sev)) {
if (!SEVERITY_LEVELS.includes(level)) {
die(`config.severity: unknown level "${level}". Allowed: ${SEVERITY_LEVELS.join('|')}`);
}
if (!Array.isArray(tags)) {
die(`config.severity.${level} must be an array of tag names, got ${typeof tags}`);
}
for (const tag of tags) {
if (tagToSeverity.has(tag)) {
die(`config.severity: tag "${tag}" listed under both "${tagToSeverity.get(tag)}" and "${level}" — pick one`);
}
tagToSeverity.set(tag, level);
}
}
const def = config.defaultSeverity || 'normal';
if (!SEVERITY_LEVELS.includes(def)) {
die(`config.defaultSeverity: "${def}" is not a valid level. Allowed: ${SEVERITY_LEVELS.join('|')}`);
}
return { tagToSeverity, defaultSeverity: def };
}
/**
* Resolve a test's severity. Precedence:
* 1. explicit `export const severity` from the test module
* 2. max-rank severity found among tags (either standard severity name, or mapped via config)
* 3. defaultSeverity from config (or 'normal' if not set)
* Returns one of SEVERITY_LEVELS.
*/
export function resolveSeverity(t, severityIndex) {
if (t.severity) {
if (!SEVERITY_LEVELS.includes(t.severity)) {
return severityIndex.defaultSeverity;
}
return t.severity;
}
let best = null;
for (const tag of t.tags || []) {
let candidate = null;
if (SEVERITY_LEVELS.includes(tag)) candidate = tag;
else if (severityIndex.tagToSeverity.has(tag)) candidate = severityIndex.tagToSeverity.get(tag);
if (candidate && (best === null || SEVERITY_RANK[candidate] > SEVERITY_RANK[best])) {
best = candidate;
}
}
return best || severityIndex.defaultSeverity;
}
@@ -0,0 +1,113 @@
// web-test cli/util v1.2 — generic helpers for CLI commands
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
export function out(obj) {
process.stdout.write(JSON.stringify(obj, null, 2) + '\n');
}
export function die(msg) {
process.stderr.write(msg + '\n');
process.exit(1);
}
export function json(res, obj, status = 200) {
res.writeHead(status, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(obj, null, 2));
}
export async function readBody(req) {
const chunks = [];
for await (const chunk of req) chunks.push(chunk);
return Buffer.concat(chunks).toString('utf-8');
}
export async function readStdin() {
const chunks = [];
for await (const chunk of process.stdin) chunks.push(chunk);
return Buffer.concat(chunks).toString('utf-8');
}
export function elapsed(t0) {
return Math.round((Date.now() - t0) / 100) / 10;
}
export function elapsed2(start, stop) {
return Math.round(((stop || Date.now()) - start) / 100) / 10;
}
export function slugify(s) {
return String(s).trim()
.replace(/[\s/\\:*?"<>|]+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '')
.slice(0, 60) || 'step';
}
export function formatDuration(seconds) {
if (seconds < 60) return `${Math.round(seconds * 10) / 10}s`;
const m = Math.floor(seconds / 60);
const s = Math.round((seconds - m * 60) * 10) / 10;
return `${m}m ${s}s`;
}
export function xmlEscape(s) {
return String(s == null ? '' : s)
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/"/g, '&quot;').replace(/'/g, '&apos;');
}
export function interpolate(template, params) {
return String(template).replace(/\{(\w+)\}/g, (_, key) =>
params[key] !== undefined ? String(params[key]) : `{${key}}`);
}
export function printSteps(W, steps, indent) {
for (let i = 0; i < steps.length; i++) {
const s = steps[i];
const last = i === steps.length - 1;
const prefix = last ? '└' : '├';
const mark = s.status === 'failed' ? '✗ ' : '';
W.write(`${indent}${prefix} ${mark}${s.name} (${elapsed2(s.start, s.stop)}s)\n`);
if (s.error && s.status === 'failed') {
W.write(`${indent} ${s.error}\n`);
}
if (s.steps.length) printSteps(W, s.steps, indent + ' ');
}
}
export function usage() {
die(`Usage: node run.mjs <command> [args]
Commands:
start <url> Launch browser and connect to 1C web client
run <url> <file|-> Autonomous: connect, execute script, disconnect
exec <file|-> [options] Execute script (file path or - for stdin)
shot [file] Take screenshot (default: shot.png)
stop Logout and close browser
status Check session status
test <dir|file>... Run regression tests (*.test.mjs); accepts multiple paths
Options for exec:
--no-record Skip video recording (record() becomes no-op)
Global options (any command):
--no-preserve-clipboard Don't save/restore OS clipboard around action calls.
Default: on (env: WEB_TEST_PRESERVE_CLIPBOARD=0 to disable globally).
Options for test:
--url=URL Override the base URL (default: from webtest.config.mjs)
--tags=smoke,crud Filter tests by tags
--grep=pattern Filter tests by name (regex)
--bail Stop on first failure
--retry=N Retry failed tests N times
--timeout=ms Per-test timeout (default: 30000)
--report=path Write machine report (JSON/JUnit) to file
--report=- Write machine report to stdout (progress moves to stderr)
--report-dir=path Directory for screenshots and other artifacts
--screenshot=mode on-failure (default) | every-step | off
--format=fmt json (default) | allure | junit
--record Record video for each test (mp4 in report-dir)
-- <hook-args...> Everything after \`--\` is forwarded to _hooks.mjs
prepare/cleanup as hookArgs (runner does not parse it).
Example: ... tests/web-test/ -- --rebuild-stand`);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,391 @@
// web-test dom shared v1.0 — embedded JS function constants
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
/**
* Shared function strings embedded into page.evaluate() generators.
* Не экспортируются наружу через dom.mjs facade внутренняя кухня.
*/
/** Find visible #modalSurface. 1C may leave multiple #modalSurface in DOM (duplicate id),
* e.g. when a second form (drill-down) creates its own alongside a stale one from the first
* form. getElementById returns the FIRST in document order, which may be hidden. Scan all. */
export const HAS_VISIBLE_MODAL_FN = `function hasVisibleModal() {
const all = document.querySelectorAll('#modalSurface');
for (const el of all) { if (el.offsetWidth > 0) return true; }
return false;
}`;
/** Detect active form number. Picks form with most visible elements, skipping form0.
* When modalSurface is visible prefer the highest-numbered form (modal dialog). */
export const DETECT_FORM_FN = HAS_VISIBLE_MODAL_FN + `
function detectForm() {
const counts = {};
document.querySelectorAll('input.editInput[id], textarea[id], a.press[id]').forEach(el => {
if (el.offsetWidth === 0) return;
const m = el.id.match(/^form(\\d+)_/);
if (m) counts[m[1]] = (counts[m[1]] || 0) + 1;
});
const nums = Object.keys(counts).map(Number);
if (!nums.length) return null;
const candidates = nums.filter(n => n > 0);
if (!candidates.length) return nums[0];
// When modal surface is visible, prefer the highest-numbered form (modal dialog)
if (hasVisibleModal()) {
const maxForm = Math.max(...candidates);
if (counts[maxForm] >= 1) return maxForm;
}
return candidates.reduce((best, n) => counts[n] > counts[best] ? n : best);
}`;
/** Detect all open forms + modal state. Returns { activeForm, allForms, formCount, modal }.
* Works even when the open-windows tab bar is hidden. */
export const DETECT_FORMS_FN = HAS_VISIBLE_MODAL_FN + `
function detectForms() {
const counts = {};
document.querySelectorAll('input.editInput[id], textarea[id], a.press[id]').forEach(el => {
if (el.offsetWidth === 0) return;
const m = el.id.match(/^form(\\d+)_/);
if (m) counts[m[1]] = (counts[m[1]] || 0) + 1;
});
const nums = Object.keys(counts).map(Number);
return { allForms: nums.sort((a, b) => a - b), formCount: nums.length, modal: hasVisibleModal() };
}`;
/** Read form state given prefix p. Returns { fields, buttons, tabs, texts, hyperlinks, table, iframes }. */
export const READ_FORM_FN = `function readForm(p) {
const result = {};
const fields = [];
const buttons = [];
const formTabs = [];
const texts = [];
const hyperlinks = [];
// Normalize non-breaking spaces to regular spaces
const nbsp = s => (s || '').replace(/\\u00a0/g, ' ');
// Fields (inputs)
document.querySelectorAll('input.editInput[id^="' + p + '"]').forEach(el => {
if (el.offsetWidth === 0) return;
const name = el.id.replace(p, '').replace(/_i\\d+$/, '');
const titleEl = document.getElementById(p + name + '#title_text')
|| document.getElementById(p + name + '#title_div');
const label = nbsp((titleEl?.innerText?.trim() || '').replace(/\\n/g, ' '));
const actions = [];
if (document.getElementById(p + name + '_DLB')?.offsetWidth > 0) actions.push('select');
if (document.getElementById(p + name + '_OB')?.offsetWidth > 0) actions.push('open');
if (document.getElementById(p + name + '_CLR')?.offsetWidth > 0) actions.push('clear');
if (document.getElementById(p + name + '_CB')?.offsetWidth > 0) actions.push('pick');
const field = { name, value: el.value || '' };
// Multi-value reference fields keep their value in .chipsItem chips, not in input.value
if (!field.value) {
const labelEl = document.getElementById(p + name);
if (labelEl) {
const chipTexts = [...labelEl.querySelectorAll('.chipsItem .chipsTitle')]
.map(c => nbsp(c.innerText?.trim() || ''))
.filter(Boolean);
if (chipTexts.length) field.value = chipTexts.join(', ');
}
}
if (label && label !== name) field.label = label;
if (el.readOnly) field.readonly = true;
if (el.disabled) field.disabled = true;
if (el.type && el.type !== 'text') field.type = el.type;
if (document.activeElement === el) field.focused = true;
if (actions.length) field.actions = actions;
if (el.closest('.inputsBox')?.classList.contains('markIncomplete')) field.required = true;
fields.push(field);
});
// Textareas
document.querySelectorAll('textarea[id^="' + p + '"]').forEach(el => {
if (el.offsetWidth === 0) return;
const name = el.id.replace(p, '').replace(/_i\\d+$/, '');
const titleEl = document.getElementById(p + name + '#title_text')
|| document.getElementById(p + name + '#title_div');
const label = nbsp((titleEl?.innerText?.trim() || '').replace(/\\n/g, ' '));
const field = { name, value: el.value || '', type: 'textarea' };
if (label && label !== name) field.label = label;
if (el.readOnly) field.readonly = true;
if (el.disabled) field.disabled = true;
if (document.activeElement === el) field.focused = true;
if (el.closest('.inputsBox')?.classList.contains('markIncomplete')) field.required = true;
fields.push(field);
});
// Checkboxes
document.querySelectorAll('[id^="' + p + '"].checkbox').forEach(el => {
if (el.offsetWidth === 0) return;
const name = el.id.replace(p, '');
const titleEl = document.getElementById(p + name + '#title_text');
const label = nbsp(titleEl?.innerText?.trim() || '');
const field = {
name,
value: el.classList.contains('checked') || el.classList.contains('checkboxOn') || el.classList.contains('select'),
type: 'checkbox'
};
if (label && label !== name) field.label = label;
fields.push(field);
});
// Radio buttons — base element is option 0, others are #N#radio (N >= 1)
const radioGroups = {};
document.querySelectorAll('[id^="' + p + '"].radio').forEach(el => {
if (el.offsetWidth === 0) return;
const id = el.id.replace(p, '');
const m = id.match(/^(.+?)#(\\d+)#radio$/);
if (m) {
// Options 1, 2, ... have explicit #N#radio suffix
const [, groupName, idx] = m;
if (!radioGroups[groupName]) radioGroups[groupName] = [];
const labelEl = document.getElementById(p + groupName + '#' + idx + '#radio_text');
const label = nbsp(labelEl?.innerText?.trim() || 'option' + idx);
radioGroups[groupName].push({ index: parseInt(idx), label, selected: el.classList.contains('select') });
} else if (!id.includes('#')) {
// Base element = option 0 (no #0#radio suffix)
if (!radioGroups[id]) radioGroups[id] = [];
const labelEl = document.getElementById(p + id + '#0#radio_text');
const label = nbsp(labelEl?.innerText?.trim() || 'option0');
radioGroups[id].unshift({ index: 0, label, selected: el.classList.contains('select') });
}
});
for (const [name, options] of Object.entries(radioGroups)) {
const titleEl = document.getElementById(p + name + '#title_text');
const label = titleEl?.innerText?.trim() || '';
const selected = options.find(o => o.selected);
const field = {
name,
value: selected?.label || '',
type: 'radio',
options: options.map(o => o.label)
};
if (label && label !== name) field.label = label;
fields.push(field);
}
// Buttons (a.press)
document.querySelectorAll('a.press[id^="' + p + '"]').forEach(el => {
if (el.offsetWidth === 0) return;
const idName = el.id.replace(p, '');
if (/_(?:DLB|CLR|OB|CB)$/.test(idName)) return;
const span = el.querySelector('.submenuText') || el.querySelector('span');
const text = nbsp(span?.textContent?.trim() || el.innerText?.trim() || '');
if (!text && !el.classList.contains('pressCommand')) return;
const btn = { name: text || idName };
if (el.classList.contains('pressDefault')) btn.default = true;
if (el.classList.contains('pressDisabled')) btn.disabled = true;
// Icon-only buttons: expose tooltip from DOM title attribute (1C puts title on parent .framePress)
if (!text) {
const tip = nbsp(el.title || el.parentElement?.title || '');
if (tip) btn.tooltip = tip;
}
buttons.push(btn);
});
// Frame buttons
document.querySelectorAll('[id^="' + p + '"].frameButton, [id^="' + p + '"] .frameButton').forEach(el => {
if (el.offsetWidth === 0) return;
const text = nbsp(el.innerText?.trim() || '');
const idName = el.id?.replace(p, '') || '';
if (!text && !idName) return;
buttons.push({ name: text || idName, frame: true });
});
// Tumbler items
document.querySelectorAll('[id^="' + p + '"].tumblerItem').forEach(el => {
if (el.offsetWidth === 0) return;
const text = el.innerText?.trim();
const idName = el.id?.replace(p, '') || '';
buttons.push({ name: text || idName, tumbler: true });
});
// Tabs — scoped to form by checking ancestor IDs
document.querySelectorAll('[data-content]').forEach(el => {
if (el.offsetWidth === 0) return;
let node = el.parentElement;
let inForm = false;
while (node) {
if (node.id && node.id.startsWith(p)) { inForm = true; break; }
node = node.parentElement;
}
if (!inForm) return;
const tab = { name: el.dataset.content };
if (el.classList.contains('select')) tab.active = true;
formTabs.push(tab);
});
// Static texts and hyperlinks
document.querySelectorAll('[id^="' + p + '"].staticText').forEach(el => {
if (el.offsetWidth === 0) return;
const name = el.id.replace(p, '');
if (name.endsWith('_div') || name.includes('#title')) return;
const text = el.innerText?.trim();
if (!text) return;
if (el.classList.contains('staticTextHyper')) {
hyperlinks.push({ name: text });
} else {
const titleEl = document.getElementById(p + name + '#title_text');
const label = titleEl?.innerText?.trim() || '';
const entry = { name, value: text };
if (label) entry.label = label;
texts.push(entry);
}
});
// Tables/grids — collect ALL visible grids
const allGrids = [...document.querySelectorAll('[id^="' + p + '"].grid, [id^="' + p + '"] .grid')]
.filter(g => g.offsetWidth > 0 && g.offsetHeight > 0);
if (allGrids.length > 0) {
const tables = allGrids.map(grid => {
const name = grid.id ? grid.id.replace(p, '') : '';
const head = grid.querySelector('.gridHead');
const body = grid.querySelector('.gridBody');
const columns = [];
if (head) {
const headLine = head.querySelector('.gridLine') || head;
[...headLine.children].forEach(box => {
if (box.offsetWidth === 0) return;
const textEl = box.querySelector('.gridBoxText');
const text = (textEl || box).innerText?.trim().replace(/\\n/g, ' ') || '';
if (text) {
const r = box.getBoundingClientRect();
columns.push({ text, x: r.x, right: r.x + r.width, y: r.y, h: r.height });
} else {
// Unnamed column — check if data cells contain checkboxes
const firstLine = body?.querySelector('.gridLine');
if (firstLine) {
const visibleHeaders = [...headLine.children].filter(c => c.offsetWidth > 0);
const idx = visibleHeaders.indexOf(box);
const cells = [...firstLine.children].filter(c => c.offsetWidth > 0);
if (cells[idx]?.querySelector('.checkbox')) {
columns.push({ text: '(checkbox)', x: 0, right: 0, y: 0, h: 0 });
}
}
}
});
// Expand single merged headers with multiple data sub-rows (e.g. "Субконто Дт" → 1/2/3)
const firstLine = body?.querySelector('.gridLine');
if (firstLine && columns.length > 0) {
const xGrp = new Map();
columns.forEach(c => {
const k = Math.round(c.x) + ':' + Math.round(c.right);
if (!xGrp.has(k)) xGrp.set(k, []);
xGrp.get(k).push(c);
});
for (const [k, hdrs] of xGrp) {
if (hdrs.length !== 1) continue;
let cnt = 0;
[...firstLine.children].forEach(box => {
if (box.offsetWidth === 0) return;
const r = box.getBoundingClientRect();
const cx = r.x + r.width / 2;
if (cx >= hdrs[0].x && cx < hdrs[0].right) cnt++;
});
if (cnt > 1) {
const base = hdrs[0];
const baseIdx = columns.indexOf(base);
columns.splice(baseIdx, 1);
for (let si = 0; si < cnt; si++) {
columns.splice(baseIdx + si, 0, { text: base.text + ' ' + (si + 1), x: base.x, right: base.right, y: 0, h: 0 });
}
}
}
}
}
const colNames = columns.map(c => c.text);
const rowCount = body ? body.querySelectorAll('.gridLine').length : 0;
// Visual label from group title (e.g. "Входящие:" for grid "Входящие")
const titleEl = document.getElementById(p + name + '#title_div')
|| document.getElementById(p + 'Группа' + name + '#title_div');
const label = titleEl ? (titleEl.innerText?.trim().replace(/:\\s*$/, '').replace(/\\u00a0/g, ' ') || null) : null;
return { name, columns: colNames, rowCount, ...(label ? { label } : {}) };
});
result.tables = tables;
// Backward compat: table = first grid summary
const first = tables[0];
result.table = { present: true, columns: first.columns, rowCount: first.rowCount };
}
// Active filters (train badges above grid: *СостояниеПросмотра)
const filters = [];
document.querySelectorAll('[id^="' + p + '"].trainItem').forEach(el => {
if (el.offsetWidth === 0) return;
const titleEl = el.querySelector('.trainName');
const valueEl = el.querySelector('.trainTitle');
if (!titleEl && !valueEl) return;
const field = (titleEl?.innerText?.trim() || '').replace(/\\n/g, ' ').replace(/\\s*:$/, '').trim();
const value = valueEl?.innerText?.trim()?.replace(/\\n/g, ' ') || '';
if (field || value) filters.push({ field, value });
});
// Also check search field value
const searchInput = [...document.querySelectorAll('input.editInput[id^="' + p + '"]')]
.find(el => el.offsetWidth > 0 && /Строк[аи]Поиска|SearchString/i.test(el.id));
if (searchInput?.value) {
filters.push({ type: 'search', value: searchInput.value });
}
if (filters.length) result.filters = filters;
// Navigation panel (FormNavigationPanel) — lives in parent page{N} container
const navigation = [];
const formEl = document.querySelector('[id^="' + p + '"]');
if (formEl) {
let pageEl = formEl.parentElement;
while (pageEl && !(pageEl.id && /^page\\d+$/.test(pageEl.id))) pageEl = pageEl.parentElement;
if (pageEl) {
pageEl.querySelectorAll('.navigationItem').forEach(el => {
if (el.offsetWidth === 0) return;
const nameEl = el.querySelector('.navigationItemName');
const text = (nameEl?.innerText?.trim() || '').replace(/\\u00a0/g, ' ');
if (!text) return;
const nav = { name: text };
if (el.classList.contains('select')) nav.active = true;
navigation.push(nav);
});
}
}
// Iframes
let iframeCount = 0;
document.querySelectorAll('[id^="' + p + '"] iframe, iframe[id^="' + p + '"]').forEach(el => {
if (el.offsetWidth > 0 && el.offsetHeight > 0) iframeCount++;
});
if (iframeCount) result.iframes = iframeCount;
if (fields.length) result.fields = fields;
if (buttons.length) result.buttons = buttons;
if (formTabs.length) result.tabs = formTabs;
if (navigation.length) result.navigation = navigation;
if (texts.length) result.texts = texts;
if (hyperlinks.length) result.hyperlinks = hyperlinks;
// Group DCS report settings into readable format
if (result.fields) {
const dcsRe = /^(.+Элемент(\\d+))(Использование|Значение|ВидСравнения)$/;
const dcsGroups = {};
const dcsNames = new Set();
for (const f of result.fields) {
const m = f.name.match(dcsRe);
if (!m) continue;
if (!dcsGroups[m[1]]) dcsGroups[m[1]] = { _n: parseInt(m[2]) };
dcsGroups[m[1]][m[3]] = f;
dcsNames.add(f.name);
}
const dcsEntries = Object.entries(dcsGroups).sort((a, b) => a[1]._n - b[1]._n);
if (dcsEntries.length) {
result.reportSettings = dcsEntries.map(([, g]) => {
const cb = g['Использование'];
const val = g['Значение'];
if (!cb && !val) return null;
// No checkbox present (class="staticText" instead of .checkbox) — setting is always enabled
const label = (val?.label || cb?.label || val?.name || cb?.name || '').replace(/:$/, '').trim();
const s = { name: label, enabled: cb ? !!cb.value : true };
if (val) {
s.value = val.value || '';
if (val.actions && val.actions.length) s.actions = val.actions;
}
return s;
}).filter(Boolean);
result.fields = result.fields.filter(f => !dcsNames.has(f.name));
if (!result.fields.length) delete result.fields;
}
}
return result;
}`;
+108
View File
@@ -0,0 +1,108 @@
// web-test dom/edd v1.0 — DOM scripts for the #editDropDown autocomplete popup
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
/**
* Read the `#editDropDown` autocomplete popup.
*
* Returns `{ visible: false }` when EDD is absent/hidden, or
* `{ visible: true, items: [{ name, x, y }] }` with center coords suitable
* for `page.mouse.click(x, y)`.
*
* Note: `page.mouse.click` is often intercepted by `div.surface` overlays
* from DLB prefer `clickEddItemViaDispatchScript` for those cases.
*/
export function readEddScript() {
return `(() => {
const edd = document.getElementById('editDropDown');
if (!edd || edd.offsetWidth === 0) return { visible: false };
const eddTexts = [...edd.querySelectorAll('.eddText')].filter(el => el.offsetWidth > 0);
return {
visible: true,
items: eddTexts.map(el => {
const r = el.getBoundingClientRect();
return { name: el.innerText?.trim() || '', x: r.x + r.width / 2, y: r.y + r.height / 2 };
})
};
})()`;
}
/**
* Is the EDD popup currently visible? Returns boolean.
* Lighter than `readEddScript` when only presence matters.
*/
export function isEddVisibleScript() {
return `(() => {
const edd = document.getElementById('editDropDown');
return !!(edd && edd.offsetWidth > 0);
})()`;
}
/**
* Click an EDD item by name via `dispatchEvent` bypasses `div.surface`
* overlays from DLB that intercept `page.mouse.click`.
*
* Matching is fuzzy: exact (with optional `(suffix)` strip) includes,
* normalizes ё/е and NBSP.
*
* Returns the clicked item's innerText (trimmed), or `null` when no match.
*/
export function clickEddItemViaDispatchScript(itemName) {
return `(() => {
const edd = document.getElementById('editDropDown');
if (!edd || edd.offsetWidth === 0) return null;
const ny = s => s.replace(/ё/gi, 'е').replace(/\\u00a0/g, ' ');
const target = ny(${JSON.stringify(itemName.toLowerCase())});
const items = [...edd.querySelectorAll('.eddText')].filter(el => el.offsetWidth > 0);
function clickEl(el) {
const r = el.getBoundingClientRect();
const opts = { bubbles: true, cancelable: true, clientX: r.x + r.width/2, clientY: r.y + r.height/2 };
el.dispatchEvent(new MouseEvent('mousedown', opts));
el.dispatchEvent(new MouseEvent('mouseup', opts));
el.dispatchEvent(new MouseEvent('click', opts));
return el.innerText.trim();
}
// Pass 1: exact match (prefer over partial)
for (const el of items) {
const t = ny((el.innerText?.trim() || '').toLowerCase());
if (t === target) return clickEl(el);
const stripped = t.replace(/\\s*\\([^)]*\\)\\s*$/, '');
if (stripped === target) return clickEl(el);
}
// Pass 2: partial match
for (const el of items) {
const t = ny((el.innerText?.trim() || '').toLowerCase());
if (t.includes(target) || target.includes(t.replace(/\\s*\\([^)]*\\)\\s*$/, ''))) return clickEl(el);
}
return null;
})()`;
}
/**
* Click the "Показать все" / "Show all" link in the EDD footer via
* `dispatchEvent`. Tries `.eddBottom .hyperlink` first, then falls back
* to scanning for span/div/a with the literal text.
*
* Returns boolean whether the link was found and clicked.
*/
export function clickShowAllInEddScript() {
return `(() => {
const edd = document.getElementById('editDropDown');
if (!edd || edd.offsetWidth === 0) return false;
let el = edd.querySelector('.eddBottom .hyperlink');
if (!el || el.offsetWidth === 0) {
const candidates = [...edd.querySelectorAll('span, div, a')]
.filter(e => e.offsetWidth > 0 && e.children.length === 0);
el = candidates.find(e => {
const t = (e.innerText?.trim() || '').toLowerCase();
return t === 'показать все' || t === 'show all';
});
}
if (!el) return false;
const r = el.getBoundingClientRect();
const opts = { bubbles: true, cancelable: true, clientX: r.x + r.width/2, clientY: r.y + r.height/2 };
el.dispatchEvent(new MouseEvent('mousedown', opts));
el.dispatchEvent(new MouseEvent('mouseup', opts));
el.dispatchEvent(new MouseEvent('click', opts));
return true;
})()`;
}

Some files were not shown because too many files have changed in this diff Show More