Compare commits

..

751 Commits

Author SHA1 Message Date
Nick Shirokov 7fa279c354 feat(skd-edit): clear-conditionalAppearance + multiline patch-query (доки)
- Новая операция clear-conditionalAppearance в стиле clear-selection/
  order/filter. Закрывает потребность "заменить набор правил оформления"
  через clear + re-add.
- patch-query: многострочные подстроки уже работали (string.Replace
  корректно обрабатывает \n). Зафиксировано в SKILL.md.
- add-total: shorthand-шаблон с тремя случаями (Func, Func(expr),
  identity-выражение) — после fix Bug 6 поведение нужно явно объяснить.
- Косметика: убрана утечка XML-внутренностей в комментарии примера
  set-field-role @period.
- Пример patch-query @once заменён на более типовой случай уникальной
  подстроки (КАК ВТ_СтароеИмя вместо ЛЕВОЕ СОЕДИНЕНИЕ).

Регресс: 33/33 PS, 33/33 PY, 33/33 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:39:24 +03:00
Nick Shirokov 28a2a34c84 fix(skd-edit): add-total identity expression для не-аггрегатных функций
Раньше "DataPath: X" всегда заворачивалось в X(DataPath). Если X не
аггрегатная функция (например, имя другого ресурса или сам DataPath),
получалось некорректное выражение типа Проверка(Проверка).

Зеркалю логику из skd-compile: whitelist аггрегатных функций
(Сумма, Количество, Минимум, Максимум, Среднее + EN-варианты).
Для остального — identity (использовать funcPart как есть).

Сообщение [OK] теперь показывает фактически записанный expression.

Регресс: 32/32 PS, 32/32 PY, 32/32 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:16:27 +03:00
Nick Shirokov f0f1e88aaa feat(skd-edit): patch-query @once — assert ровно одно вхождение
Защищает от случайных замен в комментариях/совпадениях имён:

  "ЛЕВОЕ СОЕДИНЕНИЕ => ВНУТРЕННЕЕ СОЕДИНЕНИЕ @once"
  # fail, если в запросе 0 или 2+ вхождений

Без флага default — replace-all (как раньше, обратная совместимость).

При успехе сообщение содержит фактическое число вхождений
"(N occurrence(s))", помогает заметить неожиданную множественность
без явного @once.

Регресс: 31/31 PS, 31/31 PY, 31/31 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:00:55 +03:00
Nick Shirokov e7cbf306a0 feat(skd-edit): availableValue — список с replace-семантикой и в add-parameter
- Единый list-синтаксис: availableValue=v1[: p1], v2[: p2], ...
  Элементы через запятую, представление после двоеточия.
- Запятые/двоеточия внутри значений и представлений — в одинарных кавычках:
  availableValue=Окр1: 'руб., коп.', Окр1000: руб.
- add-parameter теперь принимает availableValue= и создаёт начальный список
  в одном вызове (раньше требовался последующий modify-parameter).
- modify-parameter availableValue=... ЗАМЕНЯЕТ весь список (раньше
  append). Согласуется с остальными modify-* для одиночных свойств.
- SKILL.md: добавлен shorthand-шаблон для modify-parameter,
  расширен для add-parameter [availableValue=список].

Существующие тесты мигрированы со старого ;;-batch на новый list-синтаксис.
Снапшоты сохранились (тесты стартовали с пустого списка — semantics
совпадает для greenfield).

Регресс: 29/29 PS, 29/29 PY, 29/29 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:37:56 +03:00
Nick Shirokov 610720334b feat(skd-info): kv-параметры роли в детализации поля
В -Mode fields -Name <field> к сводке Role добавляются не-bool
параметры роли (balanceGroupName, balanceType, parentDimension,
accountTypeExpression и т.д.) в формате name=value.

Bool-флаги (@balance, @dimension, ...) отображаются как раньше.
False-значения по-прежнему скрыты.

Регресс: 6/6 PS, 6/6 PY (существующие snapshots не задеты).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:54:03 +03:00
Nick Shirokov 5090deb5bc feat(skd-edit): set-field-role — управление ролями поля
Новая операция: полная замена <role>-блока поля dataSet.

- Shorthand: "<dataPath> [@флаги] [kv=значение]"
- Флаги (зеркало skd-compile): @balance, @dimension, @account, @period,
  @required, @autoOrder, @ignoreNullValues
- KV: balanceGroupName, balanceType, parentDimension, accountTypeExpression,
  orderType, expression, periodNumber, periodType
- Пустой spec (только dataPath) — снимает роль целиком
- Поддерживает пакетный режим

Закрывает потребность временного toggle off/on роли при отладке
(было: ручной Edit XML), а также корректировку balance/dimension
после add-total.

Регресс: 27/27 PS, 27/27 PY, 27/27 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:53:55 +03:00
Nick Shirokov 8b0bcf0194 feat(skd-edit): флаги @hidden и @always для параметров
- @hidden — скрывает параметр от пользовательских настроек
  (useRestriction=true + availableAsField=false). Для констант-параметров.
- @always — параметр всегда подставляется в запрос (use=Always).
  Используется самостоятельно для видимых обязательных параметров.
- Композируются: @hidden @always одной строкой даёт типовой паттерн
  "скрытая константа всегда применяется".
- Поддержка в add-parameter и modify-parameter, идемпотентны.

Регресс: 25/25 PS, 25/25 PY, 25/25 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:14:19 +03:00
Nick Shirokov 529a5cacae feat(skd-edit): modify-structure + фиксы set-structure/parameter/patch-query
- modify-structure: новая операция, меняет groupItems группы по @name=,
  сохраняя Selection/order/filter/conditionalAppearance (Bug 1)
- set-structure: shorthand поддерживает запятую для нескольких полей
  в одном уровне группировки (Bug 2)
- set-structure: @name= с обрамляющими кавычками (двойными/одинарными)
  снимает их при записи в <dcsset:name> (Bug 3)
- add-parameter: ссылочные типы (CatalogRef, ChartOfAccountsRef, …)
  пишут <value xsi:type="dcscor:DesignTimeValue">, не xs:string (Bug 4a)
- modify-parameter: namespace-aware lookup существующих свойств
  — обновляет inplace, не плодит дубли (Bug 4b)
- modify-parameter value=…: пересборка <value> с корректным xsi:type
  из <valueType> (попутно лечит ранее битый XML)
- patch-query: батч ;;-сегментов триммится по краям (Bug 5)
- skd-compile: симметричный фикс ссылочных типов в emit_value

Регресс: 23/23 PS, 23/23 PY (skd-edit), 21/21 PS+PY (skd-compile),
23/23 платформенный verify-snapshots.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 13:40:49 +03:00
Nick Shirokov 8b0f55f1cc feat(form-validate): silent-skip числовых и UUID-DataPath в Check 5
В реальных выгрузках ERP/БП встречаются непрозрачные платформенные
DataPath, которые невозможно проверить из одного Form.xml:
- bare numeric ("10", "1000003") — внутренние индексы платформы
- "N/M:<uuid>" — ссылка на метаданные по UUID

Раньше Check 5 ругался на них "attribute not found". Теперь такие
пути пропускаются без счёта в paths checked и без ошибки.

Реалистичные пользовательские опечатки (кириллица в имени атрибута)
продолжают ловиться обычной проверкой attrMap.

Добавлен тест-кейс datapath-opaque-refs, версия v1.5 → v1.6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 11:40:27 +03:00
Nick Shirokov 54cbc69a59 feat(form-validate): резолв Items.<Table>.CurrentData.* и ~<Attr>.* в DataPath
В Check 5 раньше брался первый сегмент DataPath и искался в attrMap,
из-за чего ложно ругались реальные формы ERP/БП с путями вида
Items.<TableName>.CurrentData.<Field> (подвалы, инфо-панели) и
~<DynamicListAttr>.<Field> (текущая строка списка).

Теперь:
- ведущий ~ стрипается перед разбором сегментов;
- для Items.<Table>.CurrentData.* находим элемент-таблицу по name,
  берём её <DataPath> (атрибут DynamicList/TableSection) и проверяем
  его в attrMap. Если таблицы нет — Error; если третий сегмент не
  CurrentData — Warn.

Добавлен тест-кейс datapath-currentdata, версия скриптов v1.4 → v1.5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 11:38:56 +03:00
Nick Shirokov ac3047cf55 docs(readme): ссылка на гайд регрессионного тестирования
Добавлена строка в таблицу навыков и в перечень docs/ для нового
docs/web-test-regression-guide.md (был забыт при первичном коммите
регресс-гайда).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 20:41:33 +03:00
Nick Shirokov 5da154adea Merge feature/web-test-runner into dev
web-test regression runner: M5-pre синтетика + M6 автономный стенд +
M7 testInfo/contexts/testlevel-хуки + M8 per-context lifecycle +
Allure-форматтер с auto-suite/severity + _allure/categories.json +
пользовательский гайд регресса (docs/web-test-regression-guide.md) +
skill-инструкция regress.md.
2026-05-13 20:28:39 +03:00
Nick Shirokov f4748d76af docs(web-test): пользовательский гайд регресса + skill-инструкция regress.md
- docs/web-test-regression-guide.md — пользовательские сценарии работы
  с моделью для покрытия прикладного решения регрессом (русский, по
  аналогии с web-test-recording-guide.md): структура tests/<app-name>/,
  диалоги с моделью, пример организации покрытия, отчёты Allure +
  categories.json.
- .claude/skills/web-test/regress.md — инструкция модели по написанию
  регрессионного набора: разведка (метаданные + живой проход через exec),
  layout по фичам, готовые шаблоны (CRUD/document/DCS/multi-user/repro),
  severity, anti-patterns, failure triage, _allure/ конвенция.
- SKILL.md — указатель на regress.md в конце файла (рядом с recording).
- docs/web-test-runner-spec.md → upload/ (был внутренним планом
  разработки, не пользовательской документацией).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 20:25:44 +03:00
Nick Shirokov b992cd11c5 feat(web-test): _allure/ конвенция + categories.json для триажа падений
run.mjs:
- syncAllureExtras(testDir, reportDir) копирует все файлы из
  <testDir>/_allure/ в reportDir перед генерацией отчёта. Underscore
  в имени параллелен _hooks.mjs (инфра, не тест) — discovery его
  пропускает.
- Вызов после writeAllure при --format=allure.

tests/web-test/_allure/categories.json — 7 правил классификации падений
по нашему 1С-домену:
  1. License pool exhausted (1C) — известный multi-context flake.
  2. 1C application error (modal) — exception modal через fetchErrorStack.
  3. Section panel icon-only — деградация состояния стенда.
  4. Navigation lookup miss — navigateSection/openCommand/navigateLink/switchTab.
  5. Element not found — clickElement/fillField/selectValue/closeForm/fillTableRow/deleteTableRow.
  6. Test timeout — Timeout (Nms) от раннера.
  7. Assertion failure — наши createAssertions + 1С-specific (formHasField/tableHasRow/noErrors).

spec §9: раздел «Доп. файлы Allure через <testDir>/_allure/» с таблицей
поддерживаемых типов (categories.json / environment.properties /
executor.json) и минимальным примером.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 18:53:09 +03:00
Nick Shirokov fc76407877 feat(web-test): auto-suite + severity-резолвер для Allure
run.mjs:
- buildSeverityIndex(config) — валидация config.severity (inverted map
  «уровень → [теги]») при загрузке: ключи только из blocker|critical|
  normal|minor|trivial, теги не дублируются между bucket'ами,
  defaultSeverity тоже валидируется. fail-fast через die.
- resolveSeverity(t, severityIndex):
  1. mod.severity если задан и валидный — выигрывает.
  2. max-rank среди тегов (стандартные имена severity или маппинг).
  3. config.defaultSeverity или 'normal'.
  Rank: blocker(5) > critical(4) > normal(3) > minor(2) > trivial(1).
  Max-wins инвариантен к порядку тегов.
- writeAllure: добавлены labels suite (= dirname(t.file) или 'root') +
  severity. Тег `tag` остался как раньше.
- testResult пробрасывает t.severity (для passed/failed веток).
- SEVERITY_RANK/LEVELS объявлены в модульной шапке (top-level await на
  cmdTest начинается до конца тела модуля, TDZ-аккуратность).

webtest.config.mjs: severity policy для нашего сьюта (smoke +
multi-context → critical, recording → minor, defaultSeverity = normal).

spec.md §7: раздел про severity-policy в конфиге с валидацией.
spec.md §9: «Авто-эмиссия label-ов» — tag/suite/severity + правила резолва.

Регресс 19/19 ✓ (9m 7.6s). Распределение по уровням после исправления
'record' → 'recording' в маппинге: 13 critical / 5 normal / 1 minor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 18:37:58 +03:00
Nick Shirokov a55195ab66 docs(web-test): §16.1 — вложенные каталоги (что работает, что нет)
Зафиксирована конвенция:
- Discovery рекурсивный, путь попадает в отчёт.
- Per-folder hooks/config/context-default НЕ поддерживаются (by design).
- Группировку в отчётах делать через tags, не через путь.
- Сортировка по полному пути (`warehouse/01-x` после `sales/02-y`) —
  для глобального порядка нужны 3-значные префиксы или теги-фазы.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:33:10 +03:00
Nick Shirokov 1eff62de42 docs(web-test): полный sync спеки + contexts[] в testResult
spec.md v0.2 (последний sync 2026-05-13):

§1 CLI: добавлены --report-dir и `--` separator в таблицу флагов.
§1 «Режим выполнения»: убрана несуществующая «группировка по контексту»,
  описана реальная алфавитная модель + lazy ensureContext.
§2 пример multi-context: latin ID контекстов вместо кириллицы (clerk/manager)
  + showcase closeContext в финальном шаге.
§3 список API расширен: контексты (createContext/closeContext/setActive/
  listContexts/hasContext/getActiveContext), overlay-helpers (hideTitleSlide/
  hideImage/setHighlight/isHighlightMode), error-helpers (dismissPendingErrors/
  fetchErrorStack).
§6 пример _hooks.mjs: убран mock-навигация в beforeAll, добавлены примеры
  afterOpenContext/beforeCloseContext, afterEach показывает testResult.
§8 переписан раздел «Реализация в browser.mjs» (мульти-контекст уже live)
  + новая таблица режимов изоляции tab/window.
§9 JSON example: поле "context" → "contexts": [...] (массив).
§10: убрано упоминание несуществующего verbose-режима.
§13 «Параметризация»: убран статус «будущее», описана реальная семантика
  T6 (template name, param 2-м аргументом, testInfo.param).
§14 buildContext: переписан под done-состояние + scoped-вариант.
§16 каталог тест-кейсов: 13 → 19 файлов (multi-context, recording,
  errors-stack, tree-form, misc, hooks).
§17 дорожная карта: 10 → 18 пунктов, M4–M8 включены.

run.mjs:
- testResult получил поле contexts: [...names] во всех ветках
  (passed/failed/skipped/context-setup-failed). Раннер передаёт
  declaredContexts из единой точки до if(skip), чтобы skip-результаты
  тоже несли структурную информацию.

Регресс 19/19 ✓ (9m 8.7s) после --rebuild-stand.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:11:51 +03:00
Nick Shirokov eb87be5c04 feat(web-test): M8 — per-context lifecycle (closeContext + afterOpenContext/beforeCloseContext)
browser.mjs:
- + closeContext(name): logout slot + close page (tab) или context (window),
  удаление из реестра. Throw если name неактивен (рулило: nicht den aktiven
  closen, recorder always attached к active → invariant простой).
- _logoutSlot(slot, waitMs) — извлечён из disconnect, переиспользуется в
  closeContext.

run.mjs:
- ensureContext() после createContext вызывает hooks.afterOpenContext(ctx, name, spec).
- wrapCloseContextHook() оборачивает ctx.closeContext (и каждую scoped-обёртку)
  чтобы перед browser.closeContext fir'ить hooks.beforeCloseContext.
- Финальный teardown в finally: для всех живых контекстов кроме первого
  (survivor) — beforeCloseContext + closeContext; для survivor только хук,
  его закрывает disconnect().

_hooks.mjs v0.5:
- afterOpenContext инжектит persistent DOM-badge с displayName в правый
  верхний угол page — в записанном видео всегда видно, какой контекст.
- beforeCloseContext counter-only.
- _state расширен полями afterOpenContext / beforeCloseContext.

15-multi-context-handover.test.mjs:
- +2 шага: closeContext('b') после handover, попытка closeContext(active)
  ловится throw'ом с проверкой message.

00-hooks.test.mjs:
- +1 ассерт: afterOpenContext >= 1 (default уже создан), beforeCloseContext === 0
  в теле первого теста.

spec §6:
- Раздел «Контекстный уровень» (afterOpenContext / beforeCloseContext + правила closeContext).
- ASCII-диаграмма порядка хуков обновлена с per-context lifecycle.

Регресс 19/19 ✓ (9m 16.8s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:07:45 +03:00
Nick Shirokov 43ed9ba142 feat(web-test): M7.5 — title slide в beforeEach для --record
_hooks.mjs v0.4: beforeEach под условием ctx.isRecording() показывает
title slide с testInfo.name + displayName первичного контекста как
subtitle, ждёт 1.5с через ctx.wait() и убирает.

В обычном регрессе (без --record) — ветка скипается, overhead ноль.
Под --record: 01-navigation 12.1s → 13.9s (+1.8с на слайд).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:45:14 +03:00
Nick Shirokov 588382cec1 feat(web-test): M7.4 — testlevel-хуки + 00-hooks индикатор
_hooks.mjs v0.3: добавлены beforeAll/afterAll/beforeEach/afterEach
(counter-only) и shared `_state` (счётчики + events log).

tests/web-test/00-hooks.test.mjs (новый, 4 шага, 0s) — индикатор
порядка вызовов: проверяет beforeAll===1, beforeEach для текущего
теста, доступность ctx.testInfo, afterEach < beforeEach.

Multi-context хуки оставлены one-shot. Разведка beforeAll:
navigateSection не нужен, 1С после входа уже на дефолтной секции.

Регресс 19/19 ✓ (9m 12.7s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:35:20 +03:00
Nick Shirokov e0197683e1 feat(web-test): M7.1+M7.2 — ctx.testInfo + проброс custom-полей контекстов
- ctx.testInfo (name/file/filePath/tags/timeout/attempt/maxAttempts/param/contexts/primaryContext)
  выставляется перед каждой попыткой, доступен в beforeEach/test/afterEach
- ctx.testResult (status/duration/attempts/error/steps) доступен в afterEach
- run.mjs:411 spread полного contextSpec (был whitelist {url, isolation});
  CLI --url override сохраняет custom-поля через merge
- webtest.config.mjs: displayName для a/b
- spec §3 — подраздел «Метаданные теста», §6 — availability testInfo/testResult,
  §7 — рекомендация латинский ID + кириллический displayName
- Full regression 18/18 ✓ (9m 9.8s)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:44:07 +03:00
Nick Shirokov 96dad75b2f feat(web-test): M6-MVP follow-up — 13-misc setup + URL webtest-runner
13-misc.test.mjs: setup-шаг упрощён до `assert.ok(existsSync(epfPath))`.
EPF-сборку (epf-init → form-add → form-compile → epf-build) забрал
_hooks.mjs.prepare() — здесь только проверка артефакта с понятной
ошибкой при отсутствии: «запустите раннер с `-- --rebuild-epf`».

webtest.config.mjs: URL обоих контекстов переключён на
`/webtest-runner/ru_RU` — отдельная публикация автономного стенда,
не конфликтует с интерактивной разведкой через `/webtest` на 8081.
2026-05-12 20:25:54 +03:00
Nick Shirokov 5c734202b6 feat(web-test): M6-MVP — автономный стенд через _hooks.mjs
Новый tests/web-test/_hooks.mjs v0.2 с prepare()/cleanup().
prepare() поднимает изолированный стенд:
- Hash-locks `tests/skills/.cache/webtest-stand/{config,epf}.lock`
  на sha256 от build-steps и EPF_SPEC — автоматический skip
  пересборки при отсутствии изменений.
- Слои конфиг XML / БД / EPF пересобираются независимо. Триггер
  ручной — флаги `--rebuild-config`/`--reload-data`/`--rebuild-epf`/
  `--rebuild-stand` (через `-- ...` после CLI раннера).
- Smart Apache: web-stop+web-publish выполняются только когда
  пересоздаём БД (нужно освободить блокировку). Иначе probe-first:
  жив (200) → no-op; мёртв → publish + probeReady. На warm-старте
  prepare сводится к чтению локов и одному probe (~200ms).
- web-publish на собственном AppName `webtest-runner` :9191 — не
  пересекается с интерактивной публикацией `webtest`.
- Кросс-платформенно: env WEBTEST_HOOKS_RUNTIME=python переключает
  на зеркальные py-порты скиллов (для не-Windows стендов).

cleanup() пока stub — оставляем стенд поднятым между прогонами,
для full-shutdown ручной /web-stop или `-- --rebuild-stand`.

E2E-проверено: cold-start `--rebuild-stand` поднимает стенд за
~38s; warm-старт prepare = 0.0s; полный регресс 18/18 зелёный
за 9m 7.1s (включая оба multi-context-теста, которые исторически
флапали).
2026-05-12 20:25:47 +03:00
Nick Shirokov a92bce05fb feat(web-test): runner v1.11 — -- separator + spec §6.1
В CLI раннера всё после `--` собирается в массив hookArgs и
передаётся в инфра-хуки prepare/cleanup без интерпретации со
стороны раннера. Сигнатура расширена до { hookArgs, log, config }:
log — структурированный вывод раннера, config — разобранный
webtest.config.mjs. Шаблон «всё после `--` принадлежит вложенному
инструменту» — стандартная shell-конвенция (npm, cargo, pytest).

Спека §6 обновлена под новую сигнатуру, §6.1 закрепляет контракт
`--` ↔ hookArgs с примером. Help-строка раннера упоминает
разделитель.
2026-05-12 20:25:33 +03:00
Nick Shirokov b8ebbf6a6f feat(build-webtest-db): v0.2 — dual-mode CLI + module exports
Извлечены exports: getProjectInfo, resolveScript, execSkill,
replacePlaceholders, runSteps, platformLoadSteps, loadBuildSteps.
CLI-режим сохранён через import.meta.url-guard. Подготовка к
переиспользованию из tests/web-test/_hooks.mjs без дублирования
exec-логики и pipeline-шагов.
2026-05-12 20:25:25 +03:00
Nick Shirokov 43ba6ce16c feat(web-test): M5-pre #4b — 09-filter/unfilter-specific (multi-badge)
Раньше шаг был deferred с комментарием «требует список с видимой
filter-панелью». На самом деле существующая абстракция работает:
два advanced filterList на разных колонках Контрагентов создают
два badge'а в state.filters[], а unfilterList({field}) снимает
конкретный — оставляя остальные.

Новый шаг 09-filter/unfilter-specific (~14s):
- filterList('ООО', {field:'Наименование'}) + filterList('123', {field:'ИНН'})
  → state.filters = [{field:'Наименование',value:'ООО'}, {field:'ИНН',value:'123'}]
- unfilterList({field:'ИНН'}) → остался только Наименование badge
- unfilterList() → пусто

Старый комментарий «defer to filter-panel synthetic» удалён —
оказался устаревшим (видимо unfilterList({field}) уже умел работать
с advanced-filter badge'ами на синтетических списках).

timeout 09-filter поднят с 60000 → 120000ms (8 шагов теперь, +14s
для unfilter-specific).

Регресс: 16/18 зелёных. Два multi-context-теста (14/15) упали на
лицензионном пределе 1С — known environmental issue, не связано с
этим коммитом.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:01:00 +03:00
Nick Shirokov 51e37f9874 feat(web-test): M5-pre #4a — Менеджер (choiceHistoryOnInput=Auto) + selectValue/auto-history
Реквизит шапки ПриходнаяНакладная.Менеджер типа CatalogRef.Контрагенты
с дефолтным choiceHistoryOnInput=Auto. Существующий Контрагент в той же
шапке имеет DontUse, что даёт парный контраст для тестирования влияния
флага на selectValue.

Новый шаг 04-selectvalue/auto-history:
- selectValue('Менеджер', 'ООО Юг') → method='dropdown' (typeahead активен,
  префиксный поиск по Description находит «ООО Юг» в catalogue).
- Парный 04-selectvalue/direct-form (existing): selectValue('Контрагент',
  'Север') → method='form' (typeahead подавлен DontUse → форма выбора).

Тест покрывает существующее ветвление selectValue по флагу
choiceHistoryOnInput без engine-доработок. Истории на сервере писать
заранее не нужно: typeahead использует prefix-match по Description,
а не статистику истории.

Полный регресс **18/18 зелёный** (8m 47.3s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:56:00 +03:00
Nick Shirokov 62e864e474 feat(web-test): M5-pre #3 — textEdit:false поле + 03-fillfields/direct-edit-form
Расширение синтетики: реквизит Поставщик типа CatalogRef.Контрагенты
добавлен в шапку ПриходнаяНакладная. Элемент формы Поставщик скомпилирован
с textEdit:false (новый DSL ключ form-compile v1.21 из коммита 32bf9c1):
ручной ввод запрещён, селект-кнопки нет, выбор только через форму выбора
по pick-кнопке.

Новый шаг 03-fillfields/direct-edit-form (~7s) — fillFields на Поставщик
('ООО Юг') возвращает method:'form', минуя обычные paste/typeahead/dropdown
ветки. fillFields внутренне детектит textEdit:false и сразу идёт через
форму выбора (selectValue path).

Полный регресс **18/18 зелёный** (8m 40.6s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:11:46 +03:00
Nick Shirokov ddebd7b6df feat(web-test): M5-pre #2 — составной тип Источник + 03-fillfields/composite
Расширение синтетики: реквизит Источник составного типа
(CatalogRef.Контрагенты + CatalogRef.Номенклатура + CatalogRef.Организации)
добавлен в шапку ПриходнаяНакладная и в ТЧ Товары. meta-compile принимает
составной тип через строковый синтаксис `A + B + C` (см. SKILL.md:56) —
эмитит три `<v8:Type>` элемента с правильным `d5p1:` префиксом.

Элемент ТЧ-колонки переименован в ИсточникТЧ (path/title оставлены
оригинальные) — иначе form-compile генерирует одинаковые companion-имена
(`ИсточникКонтекстноеМеню`) для шапки и ТЧ, и платформа отказывает в
открытии формы документа: "К сожалению, возникла непредвиденная ошибка"
(server-side, без полезного stack). TODO в form-compile-bugs.md: учитывать
путь поля при генерации companion-имён, чтобы избежать конфликта.

Новый шаг 03-fillfields/composite (~25s) — покрывает selectValue с
параметром `{type}` на составном поле:
- Шапка: selectValue('Источник', 'ООО Север', {type:'Контрагенты'})
  → method:'form', type:'Контрагенты', выбор через каталог-форму.
- ТЧ: fillTableRow({Источник: {value:'Альфа', type:'Организации'}},
  {row:0}) → method:'form', type:'Организации' (quickChoice=true →
  без формы выбора, прямой dropdown).

fillFields на composite без type выбрасывает понятную ошибку
с инструкцией «specify the type: selectValue(...,{type:'ИмяТипа'})» —
поведение API стабильно.

timeout 03-fillfields поднят с 60000 → 120000ms (6 шагов суммарно
~63s, новый composite step добавляет ~25s).

Полный регресс **18/18 зелёный** (8m 28.7s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:51:41 +03:00
Nick Shirokov 3d16e35e80 feat(web-test): M5-pre #1 — ValueTree + ДеревоНоменклатуры + tree-form smoke
Расширение синтетики: новая обработка ДеревоНоменклатуры с реквизитом
формы Дерево типа ДеревоЗначений и колонками Номенклатура (ссылка,
read-only) + Цена (Number, editable). ПриСозданииНаСервере рекурсивно
обходит Справочник.Номенклатура и заполняет дерево, отражая иерархию
групп/элементов из справочника.

Обработка зарегистрирована в подсистеме Администрирование и в роли
Администратор (Use+View).

Новый smoke 16-tree-form.test.mjs (5 шагов, 17.1s) — покрывает
05-table/edit-form (fillTableRow method:'direct' на FormDataTree-колонке)
и 08-hierarchy/tree-edit (expand узла + правка Цены через index-row):
- setup: navigateLink('Обработка.ДеревоНоменклатуры'), таблица Дерево
- read-roots: 2 корневые группы (_kind:'group'), columns=Номенклатура,Цена
- expand: clickElement('Товары',{expand:true}) → 16 строк (1 + 15)
- tree-edit: fillTableRow({Цена:1500},{row:1}) → method:'direct',
  Цена становится '1 500,00' (с non-breaking space 1С)
- cleanup: closeForm

Гэп: fillTableRow с row-by-name ('Товар 01') ловит SyntaxError в JS
eval. Использую row-by-index (TODO в web-test-bugs).

Полный регресс **18/18 зелёный** (8m 9.8s) на порту 9191.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:03:28 +03:00
Nick Shirokov 56822c4533 test(web-test): switch webtest publication to port 9191
Чтобы не конфликтовать с интерактивной разработкой на основном
Apache (8081, занят сторонним проектом), регрессионный регресс
теперь использует отдельный httpd-процесс на порту 9191. Тот же
httpd запускает /web-publish webtest -Port 9191 -V8Path 8.3.24.

Один процесс Apache → собственный пул лицензий 1С. На 8081 другие
проекты — наши тесты их не блокируют и наоборот.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:03:15 +03:00
Nick Shirokov 32bf9c1a3f feat(form-compile): textEdit key for InputField (TextEdit=false)
v1.20 → v1.21 (ps1 + py).

Добавлен ключ DSL `textEdit` для элемента input. Эмитит
`<TextEdit>false</TextEdit>` после AutoMarkIncomplete (значение
true — дефолт платформы, не эмитируется). Закрывает блокер для
03-fillfields/direct-edit-form в синтетике web-test: поле с
запрещённым ручным вводом → выбор только через pick-кнопку/F4.

Snapshot-тест: tests/skills/cases/form-compile/text-edit-flag.json
(2 поля, проверяет наличие TextEdit только на втором). 30/30
form-compile зелёные обоих runtime'ов.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:56:35 +03:00
Nick Shirokov c94f86a9cd test(web-test): M4.D2 — openFile EPF + security confirm
Новый 13-misc.test.mjs (3 шага, 11s) — покрытие openFile() для
внешних обработок с автоматической обработкой security confirmation.

- setup: автономный билд EPF (идемпотентный) через epf-init →
  form-add → form-compile (с текстовой декорацией) → epf-build.
  child_process.spawnSync для вызова PowerShell скриптов.
- openFile: проверки state.form, activeTab='Тест открытия',
  state.texts[] содержит декорацию с ожидаемым value,
  opened.attempt>=1, security confirm modal не пробивается.
- cleanup: closeForm + soft-проверка activeTab (между тестами в
  desktop могут оставаться формы от других тестов — не настаиваем
  на formCount=0).

Артефакты в test-tmp/13-openfile/ (.gitignore). Полный регресс
17/17 зелёный (8m 8s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 18:27:22 +03:00
Nick Shirokov 8b5fed98e0 test(web-test): M4.E — hierarchy + tree-grid (Номенклатура)
Новый 08-hierarchy.test.mjs (7 шагов, 24s) — покрывает группы и
tree-grid режима «Дерево» на форме списка Номенклатуры через UI
переключение viewMode. Без расширения синтетики.

- setup: явное переключение в «Иерархический список» через Ещё →
  Режим просмотра (viewMode сохраняется между сессиями и НЕ
  сбрасывается «Установить стандартные настройки»).
- read-groups (P1): readTable возвращает 2 группы (_kind=group).
- group-expand (P1): clickElement({expand:true}) развёртывает группу,
  внутри 15 элементов.
- switch-tree: «Ещё → Режим просмотра → Дерево» → viewMode='tree'.
- read-tree (P2): readTable.rows[]._tree (collapsed|expanded) — проверка
  только наличия поля (состояние сохраняется между сессиями).
- tree-expand (P1): defensive свёртка через {expand:false} если узел
  expanded, затем {expand:true} → kind='gridTreeNode' toggled=true,
  видны 15 элементов под Товарами.
- cleanup: восстановить иерархический список.

Замечание: clickElement({expand:true}) — только развернуть (no-op для
expanded), {expand:false} — только свернуть, {toggle:true} —
безусловно переключить.

05-table/direct-edit-form, edit-dblclick остаются deferred — нужен
документ с иерархической ТЧ. Полный регресс 16/16 зелёный (7m 53s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:43:31 +03:00
Nick Shirokov 9e677cfc61 test(web-test): M4.F — recording smoke (video + captions + TTS + overlays)
Новый 15-recording.test.mjs (5 шагов, 20.7s) — покрытие полного
публичного API recording.md.

- record + captions: startRecording → 2× showCaption → stopRecording.
  Проверки isRecording, duration/size, mp4 на диске, .captions.json,
  getCaptions с правильными text и time.
- narration: addNarration через Edge TTS (ru-RU-DmitryNeural), narrated
  mp4 больше исходного (добавлен аудио-трек).
- title-slide: showTitleSlide/hideTitleSlide — overlay fullscreen
  (w==innerWidth, h==innerHeight).
- image-overlay: showImage/hideImage с тестовой картинкой из screenshot.
- highlight: setHighlight toggles isHighlightMode, manual highlight на
  кнопке «Создать» создаёт overlay позиционированный на элементе.

Артефакты в test-tmp/recording-smoke/ (.gitignore), идемпотентный.
Полный регресс 15/15 зелёный (7m 27s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:20:13 +03:00
Nick Shirokov 211a4726d6 test(web-test): M4.C+D — drill-down + submenu-read
11-report/drill-down: dblclick по ячейке Номенклатуры сформированного
DCS-отчёта открывает форму элемента (DCS auto-drill). После Сформировать
ищется первая строка с заполненной номенклатурой, проверяется что после
clickElement({row,column},{dblclick:true}) form изменился и есть кнопка
«Записать».

02-crud/more-menu усилен под P2 submenu-read: добавлены явные проверки
clicked.kind='submenu', наличия типовых пунктов «Создать», «Изменить»,
«Расширенный поиск» (length>=5).

Покрыто 2 P2-кейса coverage matrix (11-report/drill-down,
02-crud/submenu-read). Полный регресс 14/14 зелёный (7m 1.6s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:58:28 +03:00
Nick Shirokov 91b39b758b test(web-test): M4.B+G — subordinate-nav + platform dialogs в 12-formstate
Расширены тесты getFormState: проверка ветвей navigation[] и
platformDialogs[] возвращаемой структуры.

- subordinate-nav: форма элемента Контрагент → state.navigation содержит
  «Основное» (active) и «Контактные лица» (подчинённый каталог).
- platform-dialogs: открытый через hamburger «О программе…» виден в
  state.platformDialogs[{type:'about'}].
- platform-dialog-close: closeForm закрывает платформенный диалог,
  массив становится пустым.

Покрыто 3 P2-кейса coverage matrix (12-formstate/subordinate-nav,
platform-dialogs, platform-dialog-close). Полный регресс 14/14 зелёный.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:30:51 +03:00
Nick Shirokov 4af69f1600 test(web-test): M4.A — validation messages + exception modal + error stack
10-validation.test.mjs (3 шага): Сообщить() → state.errors.messages,
ВызватьИсключение → onecError.errors.modal с автоматическим закрытием
fetchErrorStack.

14-errors-stack.test.mjs (3 шага): Path 1 OpenReport автоматически фетчит
стек для серверных исключений (entries[] содержит кадр ОбщиеФункции);
оставленная error modal через raw page.click закрывается closeForm;
платформенный диалог «О программе» виден в state.platformDialogs и
закрывается closeForm.

Покрыто 4 P2-кейса coverage matrix: 10-validation/messages,
10-validation/exception-modal, 14-errors/path1, 14-errors/dismiss-platform
+ бонус dismiss-modal. Открытие обработки ТестовыеОшибки через
navigateLink('Обработка.ТестовыеОшибки') — стандартные команды у
DataProcessor отключены.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:21:11 +03:00
Nick Shirokov 8c7c442705 feat(meta-compile): DSL choiceHistoryOnInput для аттрибутов
meta-compile v1.12 (ps1 + py): Parse-AttributeShorthand принимает поле
choiceHistoryOnInput в object-форме аттрибута, Emit-Attribute эмитит его
вместо хардкода Auto. Покрывает атрибуты Catalog/Document/TabularSection
(Emit-Attribute, единственная точка эмиссии в работе). Другие контексты
(register dimensions, resources, etc.) пока эмитят Auto — расширим
при необходимости.

build-webtest-config: реквизит Документ.ПриходнаяНакладная.Контрагент
получил choiceHistoryOnInput='DontUse'. Это убирает 1С-историю выбора
для поля и фиксит pre-existing flake 04-selectvalue/direct-form:
после 03 значение «ООО Север» оставалось в истории и selectValue
выбирал его через dropdown вместо ожидаемой формы выбора.

Live: полный регресс 12/12 впервые зелёный (5m 28s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 13:47:50 +03:00
Nick Shirokov c541d51f33 fix(web-test): resetState не закрывал form 0 + error screenshot снимался после reset
run.mjs:

1. resetState проверял `if (!state.form) break`. form === 0 (фоновая
   форма 1С, которую detectForm может вернуть) рассматривался как
   "форм нет" → cleanup прерывался, форма оставалась → следующий тест
   получал грязное состояние. Замена на `state.form == null` корректно
   различает null (desktop) и 0 (реальная фоновая форма).

2. Error screenshot в catch-блоке cmdTest снимался ПОСЛЕ resetState,
   который уже закрывал все формы → скрин показывал пустой рабочий
   стол вместо места падения. Перенёс снимок в начало catch (до
   teardown/afterEach/resetState).

Эффекты:
- 15-multi-context-handover теперь стабильно проходит в полном прогоне
  (раньше падал когда предыдущий тест оставлял form=0).
- 04-selectvalue/direct-form остался pre-existing flake (история
  выбора 1С после 03 — отдельная задача в синтетике).
- Скриншоты падения теперь показывают реальный UI на момент исключения.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:52:22 +03:00
Nick Shirokov a650325baf fix(web-test): убрать стуб showCaption/hideCaption в cmdTest
run.mjs v1.10: cmdTest больше не передаёт noRecord:true в buildContext.
Тестам доступен полный API browser.mjs (showCaption, hideCaption,
startRecording, stopRecording, addNarration).

Изначальный стуб с noRecord:true прятал showCaption/hideCaption тестов
вместе с recording-функциями. Это блокировало визуальные оверлеи в
мульти-контекстных тестах: a.showCaption() тихо превращался в no-op,
баннер никогда не отображался даже под --record.

Smart wait внутри showCaption и так гейтится на наличие recorder
(`if (recorder && ...)`), поэтому без --record тесты остаются быстрыми
(никаких 2-секундных пауз на каждый вызов).

startRecording/stopRecording/addNarration теперь тоже доступны тестам.
При попытке вызвать startRecording в момент активной runner-записи
browser.startRecording бросает "Already recording" — loud failure
лучше silent no-op.

Регресс: 15-multi-context-handover один проходит за 19.9s. Полный
прогон 10/12 (04 и 15 флапают независимо в последовательности).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:37:42 +03:00
Nick Shirokov 6c19846051 feat(web-test): T4.6 — гибридные режимы изоляции контекстов (tab default, window opt-in)
browser.mjs v1.12 + run.mjs v1.9: createContext принимает isolation параметр.
По умолчанию 'tab' — все контексты живут в одном launchPersistentContext, каждый
слот получает свою Page (вкладку). Преимущества: 1С extension грузится
надёжно (через --load-extension в persistent profile), один процесс Chromium,
дешёвая память. Cookies делятся между вкладками, но скоупятся по URL-path —
для модели «разные пользователи через разные vrd-публикации» это естественно
и достаточно.

isolation: 'window' (opt-in) — старый путь chromium.launch() + newContext():
полная изоляция cookies, отдельный BrowserContext (и окно) на каждый слот,
но extension может не подняться. Использовать когда нужна изоляция auth
внутри одного URL.

Смешивать режимы в одном прогоне нельзя — createContext бросает явную
ошибку (первый createContext устанавливает activeMode, остальные обязаны
совпадать).

Конфиг tests/web-test/webtest.config.mjs: добавлен комментарий с описанием
обоих режимов. По умолчанию tab — синтетика и наши smoke-тесты идут им.

Live: 11/12 в полном прогоне (default tab) + 3/3 sanity-check в window mode
(01-navigation + 14 + 15). Видеозапись из T4.5 работает в обоих режимах.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 18:34:44 +03:00
Nick Shirokov eef4f4bcea feat(web-test): T4.5 — мульти-контекстная запись видео
browser.mjs v1.11: recorder стал глобальным (не per-slot) — один ffmpeg,
один mp4 на тест с любым числом переключений контекста.

Frame state (lastFrameBuf/lastFrameTime/handler) переехал в поля recorder.
Добавлен recorder._attachPage(targetPage) — стопает старый CDP screencast,
заводит новый на нужной странице, route'ит фреймы в тот же ffmpeg pipe.

setActiveContext: при активной записи делает _flushFrames (замораживает
хвост уходящего окна), затем _attachPage(page) после _activateSlot. Видео
получается непрерывным с плавным сюжетом — пока активен a, видно a; пока
активен b, видно b.

_saveActiveSlot/_activateSlot больше не трогают recorder/lastCaptions/
lastRecordingDuration — recorder следует за активной страницей через
_attachPage, не через slot mirror.

disconnect: убрал leftover из T4.1, который пытался итерировать slot.recorder.

Live: 15-multi-context-handover с --record → 17.84s mp4, 446 кадров @ 25fps,
извлечённые кадры показывают переключение между окнами a (1920x1042) и
b (982x546). Полный регресс 11/12 (04-selectvalue — pre-existing flake).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 17:58:31 +03:00
Nick Shirokov 2c553fee98 feat(web-test): T4 — мульти-контекст BrowserContext
browser.mjs v1.10: createContext/setActiveContext/listContexts/getActiveContext/
hasContext. Несколько изолированных BrowserContext в одном Chromium-процессе через
chromium.launch() + newContext(). Module-level page/sessionPrefix/seanceId/recorder
зеркалят активный слот (атомарный своп через _saveActiveSlot/_activateSlot).
connect() оставлен для exec/run/start без изменений (launchPersistentContext).

run.mjs v1.8: ensureContext(name) + ленивое создание. Single-routing через
export const context = 'name'. Multi через export const contexts = ['a','b'] +
buildScopedContext(name) строит ctx.a/ctx.b — каждое действие префиксится
setActiveContext. Reset state после теста по всем активным контекстам.

Конфиг tests/web-test/webtest.config.mjs: два контекста a/b на одну webtest
публикацию (изолированные cookies через newContext).

Smoke-тесты:
- 14-multi-context-routing.test.mjs — single routing в b (2.6s)
- 15-multi-context-handover.test.mjs — ctx.a создаёт Контрагента, ctx.b в
  независимой сессии видит запись через filterList, ctx.a cleanup (14.5s, 4/4)

Live: 11/12 в полном прогоне. 04-selectvalue/direct-form флапает —
pre-existing, воспроизводится на baseline 95e4674 (03→04 sequence).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 17:24:24 +03:00
Nick Shirokov 95e4674825 test(01-navigation): M3 P1 — section/command/switchTab errors + navigateLink
section-error / command-error / switchTab error: проверка throw для
несуществующих имён.

navigateLink: link-type (Catalog.Контрагенты) + e1cib URL (с soft-skip
для платформ без поддержки e1cib через Shift+F11).

Live на webtest: 10/10 passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 16:29:54 +03:00
Nick Shirokov 9751840cc8 test(09-filter): M3 P1 — exact, hidden-field, date, reference, unfilter-all
exact: filterList exact:true строго 1 совпадение.
hidden-field: filterList по неотображённому реквизиту через FieldSelector
DLB (КодКПП в синтетике нет — soft-skip).
date: filterList по колонке Дата поступления (синтетика выводит её в форму
списка Номенклатуры).
reference: filterList по ссылочной колонке Контрагент (форма списка ПН).
unfilter-all: unfilterList() полностью восстанавливает список.

unfilter-specific отложен — требует списка с видимой filter-панелью,
synthetic списки фильтруют без создания badge.
cancel-search/clear-input семантически дубликаты unfilter-all через
публичный API.
show-all-form требует quickChoice=true каталога с количеством > порога
(в синтетике нет).

Live на webtest: все 7 шагов passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 16:28:09 +03:00
Nick Shirokov f257bb428c test(12-formstate): M3 P1 — modal + tabs
modal: F4 на ref-поле открывает модальную форму выбора Контрагентов,
state.modal=true, formCount=2.

tabs: форма элемента Номенклатуры с двумя табами (Основное/Дополнительно)
возвращает state.tabs[].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:43:53 +03:00
Nick Shirokov 71e3691cf1 test(web-test): M3 P1 batch 1 — confirm-save-no/pending, more-menu, clear/ref-form, table checkbox/clear
02-crud: confirm-save-no (rollback при save:false), confirm-pending
(closeForm() без решения возвращает confirmation), more-menu (clickElement
'Ещё' возвращает submenu).

03-fillfields: clear (Shift+F4 через пустое значение), reference-non-quickchoice
(fillFields на quickChoice=false поле — method=dropdown через DLB; чистый
form-path требует hasPick && !hasSelect, такого поля в синтетике нет).

04-selectvalue: clear (selectValue '' → Shift+F4). show-all-form отложен —
требует quickChoice=true каталога с количеством > порога dropdown
(в синтетике нет).

05-table: checkbox (fillTableRow с Boolean), clear (Shift+F4 на ref-ячейке +
восстановление для последующего delete).

Live на webtest: все шаги проходят.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:40:27 +03:00
Nick Shirokov 1af318325d test(05-table): добавить явный tab-loop step с двумя числовыми полями
fillTableRow({Количество, Цена}, {row:1}) — purpose-built проверка inEdit
multi-cell tab-loop. method='direct' для обоих полей, значения
подставляются корректно (live на webtest).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:23:03 +03:00
Nick Shirokov 986480748e Merge branch 'dev' into feature/web-test-runner 2026-05-10 15:10:38 +03:00
Nick Shirokov 71309d2bc2 fix(tests): make cf-edit/set-home-page case platform-loadable
Кейс ссылался на CommonForm.* и DataProcessor.Поиск.Form.ФормаПоиска,
которых не было в workDir — verify-snapshots падал на db-load-xml,
а cf-validate Check 9 (валидация HP form refs) ловил это только под
--with-validation, поэтому в обычной регрессии проблема была не видна.

Поскольку CommonForm пока не умеет создавать ни meta-compile, ни form-add
(он привязывается к существующему объекту-владельцу), заменил ссылки
на формы Catalog/DataProcessor — DSL-покрытие сохранено целиком:
template, string-ref, height, visibility, русский синтаксис типа,
короткая и полная форма roles. Добавлен preRun из 10 шагов
(meta-compile + form-add + role-compile) для синтеза всех ссылок.

Поддержка CommonForm в meta-compile/form-add — отдельная задача.

verify-snapshots: 1/1 ✓ (db-load-xml, db-update проходят).
Полная регрессия: 349/349 ✓.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:57:30 +03:00
Nick Shirokov e1f81a0cde chore(tests): refresh snapshots after meta-compile QuickChoice + form-compile AutoTitle defaults
- QuickChoice<true→false> для Catalog (07b2ec3 «дефолты QuickChoice по реальным
  конфигам» — часть снапшотов уже обновили в dc0382c, эти были пропущены)
- автоген <Title>/<AutoTitle>/<TitleLocation>/<SavedData> в формах
  (76800fc «автоген Title из имени» и серия фич form-compile)
- column-group/ — новый снапшот для кейса из 4f9d9ae (был не закоммичен)

Все 349 unit-тестов и 6 integration-тестов зелёные. verify-snapshots
(платформенная загрузка) — 201/202; отдельный pre-existing fail
cf-edit/set-home-page (Check 9 не валидирует HP form refs) разбираем
отдельно, в дифф этой регенерации не входит.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:45:47 +03:00
Nick Shirokov e8cb5440d8 feat(switch): emit -ExecutionPolicy Bypass for codex target
Codex on Windows launches powershell.exe as a login-shell that loads
the user profile despite -NoProfile in our SKILL.md. With Restricted
ExecutionPolicy this spams "выполнение сценариев отключено". Add
-ExecutionPolicy Bypass for codex; keep canonical -NoProfile -File for
all other platforms.

Round-trip safe: cmd_install always copies fresh from .claude/skills/,
so switching codex→cursor strips the EP flag. cmd_switch_runtime
re-emits PS commands via normalize_ps_invocation each pass, so
in-place py↔ps in .codex/skills/ keeps the flag.

Also fix a pre-existing bug in cmd_switch_runtime: file-existence
check used repo_root() instead of project_dir, so in-place runtime
switch in a foreign project always tripped skip_runtime=True and
became a no-op. The bug was masked when project_dir == repo_root
(source-repo workflow).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 12:40:25 +03:00
Nick Shirokov c496047c6c fix(skills): force UTF-8 console encoding in 7 ps1 scripts
Codex runner on Windows launches PowerShell as login-shell and decodes
stdout/stderr without UTF-8, garbling Cyrillic output. The other 51 ps1
scripts already set `[Console]::OutputEncoding = UTF8`; bring these 7
in line and add `InputEncoding = UTF8` for symmetry.

Touched: epf-init, erf-init, form-add, form-remove, help-add,
template-add, template-remove. Versions bumped in both ps1 and py
headers to keep the pair in sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 12:16:44 +03:00
Nick Shirokov df9541470c chore(plugins): tighten descriptions and align marketplace entries with Codex schema
- Replace overreaching "полный цикл разработки... до записи видеоинструкций" pitch with grounded one-liner matching the GitHub repo description (XML/CLI abstractions + eyes & hands for web-client testing).
- Drop non-standard per-plugin `interface.shortDescription` from .agents/plugins/marketplace.json — MarketplaceInterface only describes `displayName`, openai/plugins keeps per-plugin entries minimal (name/source/policy/category).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:42:12 +03:00
Nick Shirokov 27ecfb707d revert(plugins): drop UTF-8 BOM on SKILL.md — Codex YAML parser breaks on it
BOM before `---` makes Codex's strict frontmatter parser reject every
SKILL.md ("Skipped loading 66 skill(s)"). Without BOM the skills load
and execute correctly; the only remaining issue is mojibake display of
Cyrillic in SKILL.md previews — that's a Codex rendering bug, not ours.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:27:08 +03:00
Nick Shirokov 35bec4a2a1 fix(plugins): prepend UTF-8 BOM to SKILL.md on codex branches
Codex on Windows opens SKILL.md without a declared encoding and
defaults to CP1252, mangling Cyrillic. Adding the BOM lets the loader
auto-detect UTF-8.

Applied only on codex/codex-py builds to leave other ports untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:19:10 +03:00
Nick Shirokov e635a5be52 fix(plugins): drop invalid authentication: OFF from Codex marketplace
Codex schema only accepts `ON_INSTALL` or `ON_USE`; the field is
optional, so omit it for an unauthenticated plugin.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:26:09 +03:00
Nick Shirokov dfb258dd3f fix(plugins): prefix descriptions with [PowerShell]/[Python] for distinct cards
Codex plugin browser truncates the description, so the runtime tag
needs to appear at the start. Apply the same prefix to Claude
marketplace.json and plugin.json for consistency.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:13:33 +03:00
Nick Shirokov 1866c1335a feat(plugins): Codex plugin support + Python plugin variant for Claude
- Add 1c-skills-py to .claude-plugin/marketplace.json (→ port-claude-code-py)
- New .agents/plugins/marketplace.json — Codex marketplace with PS + Py plugins
- Templates .github/templates/{codex,claude}-plugin.json.tmpl rendered by CI
- build-ports.yml: generate plugin manifests on port-codex/port-codex-py/port-claude-code-py; Codex version YYYY.M.D+sha7 auto-bumped per push
- README: install instructions for Codex + Py variant for Claude
- .gitignore: narrow .agents/ → .agents/skills/ so the marketplace is tracked

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:08:07 +03:00
Nick Shirokov 4813ec5cf2 docs(readme): inline "Другие платформы →" link, drop verbose intro line
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:41:20 +03:00
Nick Shirokov 06ad2f8f99 feat(ci): expand port matrix to all 13 platforms + bump deprecated actions
- Add 20 matrix entries: copilot, augment, cline, kilo, kiro, gemini, opencode, roo, windsurf, agents (PS+Py each)
- Total: 25 port-* branches (Claude Code PS = main, plus 13 × Py + 12 × PS)
- Bump actions/checkout@v4 → @v5, actions/setup-python@v5 → @v6 (removes Node.js 20 deprecation warnings)
- README: replace "соберите локально" placeholders with real branch links for all platforms

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:37:35 +03:00
Nick Shirokov c8ac191a01 feat(ci): port-branches workflow + README install matrix
- .github/workflows/build-ports.yml — auto-build orphan port-* branches on push to main (matrix: claude-code-py, cursor PS+Py, codex PS+Py)
- .github/templates/README.port.md.tmpl — minimal per-port README rendered in CI
- README — new "Версии навыков для разных платформ" section under intro (3 flagships × PS+Py), extended platform table with PowerShell/Python branch links, switch.py moved to "альтернативный способ" subsection
- README — "Work in progress" reworded to "Проект живой, активно развивается"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:29:52 +03:00
Nick Shirokov c9d83b1c92 docs(readme): add plugin install instructions
Document the recommended installation path via Claude Code plugin
marketplace:

  /plugin marketplace add https://github.com/Nikolay-Shirokov/cc-1c-skills
  /plugin install 1c-skills@cc-1c-skills

Plugin install becomes the recommended option; drop-in copy and
switch.py-based installs remain documented as alternatives for users
who prefer them or who target other AI platforms.

Closes #18.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:40:38 +03:00
Nick Shirokov b1a7e414d0 fix(switch): runtime conversion for ${CLAUDE_SKILL_DIR} paths
After the SKILL.md refactor, paths are wrapped in double quotes and
contain ${CLAUDE_SKILL_DIR}. The legacy RX_PS/RX_PY regexes captured
the leading quote into the path group and didn't accept '$', '{', '}'
characters, breaking three places:

- classify_skill_runtime: misdetected runtime since RX_PY didn't match
  python invocations of variable paths
- check_missing_files: built file paths like '"${CLAUDE_SKILL_DIR}/...py'
  that never existed → false-positive missing → runtime switch skipped
- switch_runtime_content: failed to convert PS->Py / Py->PS for skills
  using the new path format

Fix:
- Regexes now capture optional surrounding quote separately and accept
  any non-whitespace non-quote chars in the path
- New helper expand_skill_path() resolves ${CLAUDE_SKILL_DIR} to the
  actual on-disk path for file existence checks (handles cross-skill
  references via ../<other>/ too)
- check_missing_files derives skill_name from skill_dir to drive the
  expansion

Verified via:
  python scripts/switch.py claude-code --project-dir <tmp> --runtime python
  python scripts/switch.py claude-code --project-dir <tmp> --runtime powershell
  python scripts/switch.py codex --project-dir <tmp>

All produce correct output with quotes preserved and cross-skill
references resolved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:56:26 +03:00
Nick Shirokov 7736ad68a0 feat(switch): handle ${CLAUDE_SKILL_DIR} for non-Claude targets
After SKILL.md refactor, paths use ${CLAUDE_SKILL_DIR} which Claude Code
substitutes natively. Other agents (Cursor, Codex, Copilot, etc.) don't
know about this variable, so switch.py now expands it to a literal path
when the target is not claude-code:

  ${CLAUDE_SKILL_DIR}/<rest>            -> <target_prefix>/<skill_name>/<rest>
  ${CLAUDE_SKILL_DIR}/../<other>/<rest> -> <target_prefix>/<other>/<rest>

For claude-code target the variable is left intact — drop-in install via
copy still works because Claude Code resolves it identically in
project, personal, and plugin scopes.

Verified by running:
  python scripts/switch.py codex --project-dir <tmp>
  python scripts/switch.py claude-code --project-dir <tmp>

Both produce correct output with 0 leftover variable literals in
non-Claude targets and full preservation in Claude target.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:31:08 +03:00
Nick Shirokov 501bb58ddb feat(plugin): plugin and marketplace manifests
Add `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json` so
the repo can be installed via:

  /plugin marketplace add https://github.com/Nikolay-Shirokov/cc-1c-skills
  /plugin install 1c-skills@cc-1c-skills

Plugin name `1c-skills`, marketplace name `cc-1c-skills` (matches repo
name). Version is omitted in `plugin.json` so Claude Code uses the git
commit SHA — convenient for active development without manual bumps.

Closes part of #18.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:30:32 +03:00
Nick Shirokov cd3a242b12 refactor(skills): portable script paths via ${CLAUDE_SKILL_DIR}
Replace literal `.claude/skills/<owner>/...` paths in SKILL.md with the
`${CLAUDE_SKILL_DIR}` variable that Claude Code substitutes at invocation
time. Same-skill references become `${CLAUDE_SKILL_DIR}/<rest>`,
cross-skill references (erf-* → epf-*) become
`${CLAUDE_SKILL_DIR}/../<other>/<rest>`. All paths now wrapped in double
quotes to handle install locations with spaces.

This unblocks plugin-mode installation: literal `.claude/skills/...`
paths fail when the skill is loaded from `~/.claude/plugins/cache/...`
or from a personal `~/.claude/skills/` install. Drop-in mode continues
to work because Claude Code resolves the variable in all install scopes.

Verified via pilot:
- Project drop-in (cc-1c-skills repo)
- Personal `~/.claude/skills/cf-info/`
- Plugin via `/plugin marketplace add <local-path>`

Scope: 61 SKILL.md, 125 path replacements (8 cross-skill).
Scripts unchanged — they already use \$PSScriptRoot and ../<sibling>
patterns that resolve correctly under the bundled cache layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:30:06 +03:00
Nick Shirokov 7561faf736 test(web-test): покрыть Tumbler через clickElement в radio-шаге
Tumbler-представление RadioButtonField не парсится fillFields, но варианты
видны в state.buttons[] и кликаются через clickElement. Уточнили шаг radio:
- RadioButtons (КатегорияЦены) → fillFields с method=radio
- Tumbler (СпособУчёта) → проверка наличия в buttons[] + clickElement('ФИФО')

Семантика Tumbler через fillFields остаётся как баг web-test/browser.mjs
(см. upload/web-test-bugs.md пункт 5), но рабочий путь интеракции есть.

10/10 smoke зелёные после рестарта Apache.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 18:19:42 +03:00
Nick Shirokov 2849087fd9 test(web-test): покрытие quickChoice + radio (RadioButtons)
03-fillfields:
- reference-dropdown: переведён с Контрагент на Организация
  (после смены quickChoice Контрагенты идут через форму выбора)
- новый шаг radio: КатегорияЦены через method=radio (RadioButtons)

04-selectvalue:
- dropdown: переведён на Организация (quickChoice=true)
- новый шаг direct-form: Контрагент (quickChoice=false), method=form

Закрывает selectValue#3 dropdown (P0), selectValue#6 direct-form (P1),
fillFields#3 radio (P1) из coverage matrix.

Tumbler-представление радио (СпособУчёта) пока не покрыто — getFormState
не возвращает Tumbler в fields[]. Зафиксировано в upload/web-test-bugs.md
пункт 5.

10/10 smoke зелёные на webtest базе.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 16:17:19 +03:00
Nick Shirokov 105171cdc2 test(webtest-config): Организации/quickChoice + radio (RadioButtons+Tumbler)
Расширение синтетики под новые возможности meta-compile/form-compile,
закрывает три ветки coverage matrix:
- Catalog.Организации (quickChoice: true) → selectValue#3 dropdown (P0)
- Catalog.Контрагенты (дефолт quickChoice: false) → selectValue#6 direct-form (P1)
- form-compile radio с видами RadioButtons (КатегорияЦены) и Tumbler
  (СпособУчёта) → fillFields#3 radio (P1)

В шапку ПриходнаяНакладная добавлен реквизит Организация (dropdown ветка),
Контрагент остаётся на форме выбора. Фикстура ЗаполнитьОрганизации создаёт
2 организации (Альфа, Бета); первая подставляется в документы.

Платформенная верификация: build-webtest-db (45 шагов, 30.3s) зелёная,
db-create + db-load-xml + db-update проходят. Функциональный прогон
runner.mjs integration/build-webtest — 42 шага зелёные.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 14:58:27 +03:00
Nick Shirokov c9cd0d62ab Merge branch 'dev' into feature/web-test-runner 2026-05-04 13:15:49 +03:00
Nick Shirokov 4f9d9aee97 feat(form-compile): группировка колонок таблицы (ColumnGroup)
Новый DSL-ключ columnGroup со значением-ориентацией horizontal/vertical/inCell
для элемента <ColumnGroup> внутри columns таблицы. Поддерживает вложение,
showTitle/showInHeader/width, тихие синонимы ColumnGroup и ГруппаКолонок.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:48:35 +03:00
Nick Shirokov f3466e19fd docs(form-patterns): актуализация под новые возможности form-compile
- Архетипы «Форма обработки» и «Мастер»: кнопки действий перенесены
  с нижней горизонтальной группы на главную АКП формы (autoCmdBar)
- Конвенция «ГруппаКнопок» заменена на «ФормаКоманднаяПанель»
- Принцип компоновки №3: уточнено, что кнопки идут на АКП
- Сворачиваемые группы: исправлен пример — корректный DSL
  (group: collapsible, collapsed: true) вместо несуществующих
  ключей behavior/collapsed на vertical-группе
- Полный пример формы обработки переписан под autoCmdBar
- Из свойств мастера убран commandBarLocation: None (не нужен,
  когда мы сами наполняем АКП)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 20:10:10 +03:00
Nick Shirokov ebf92a8780 feat(form-compile): свойство collapsed для сворачиваемых групп
Добавлен ключ collapsed (для group=collapsible) → <Collapsed>true</Collapsed>:
группа создаётся уже свёрнутой. Раньше DSL умел только включать
сворачиваемое поведение, но начальное состояние задать было нельзя.

Также уточнено описание united: оно про выравнивание левого края полей
ввода (сквозное/локальное), а не про объединение рамок группы.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 20:07:18 +03:00
Nick Shirokov 3d80191ca7 feat(form-compile): поддержка maxWidth/maxHeight для input и label
Добавлены численные maxWidth/maxHeight (XML <MaxWidth>/<MaxHeight>) —
типичный приём для ограничения растяжения поля при autoMaxWidth: false.
До этого DSL знал только булев autoMaxWidth, и ограничить ширину
числом было невозможно.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 19:58:36 +03:00
Nick Shirokov 6c60398406 feat(form-compile): авто-вид кнопки по контексту АКП
Кнопки внутри cmdBar/autoCmdBar/popup автоматически получают
CommandBarButton (или CommandBarHyperlink при type="hyperlink") —
указывать вид вручную не нужно. Резолвер прощающий: принимает и
короткие DSL-формы, и XML-имена в любом контексте.

Пример «Диалог загрузки файла» в SKILL.md и тест-кейс file-dialog
переведены на нативный паттерн с autoCmdBar вместо отдельной
горизонтальной группы кнопок внизу формы.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 19:41:43 +03:00
Nick Shirokov 60de083a05 docs(1c-form-spec): RadioButtonField перенесён в статистику (~8.5% форм БП)
Замер по acc_8.3.24: 658 из 7723 форм содержат RadioButtonField
(всего 1389 элементов). Раньше ошибочно числился среди не встреченных.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:48:29 +03:00
Nick Shirokov 5690c82ab8 docs(form-dsl-spec): radio (RadioButtonField) в спецификации DSL
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:45:00 +03:00
Nick Shirokov dc0382cc06 chore(tests): обновлены снапшоты после meta-compile QuickChoice defaults
Снапшоты ссылочных реквизитов теперь содержат QuickChoice=false
в соответствии с дефолтами по реальным конфигам (см. 07b2ec3).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:43:33 +03:00
Nick Shirokov b1e29253d5 feat(form-compile): RadioButtonField и словарь синонимов типов элементов
Поле переключателя с RadioButtonType (Auto/RadioButtons/Tumbler) и
ChoiceList (массив value+presentation). Толерантно к написанию модели:
русские имена тегов (ПолеПереключателя, RadioButtonField),
ВидПереключателя по-русски (Авто/Переключатель/Тумблер),
Перечисление.X.Y без EnumValue, синоним title для presentation,
автогенерация презентации из имени значения.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:43:26 +03:00
Nick Shirokov 07b2ec36af feat(meta-compile): дефолты QuickChoice по реальным конфигам
Catalog/CCT/CoA/CoCT/ExchangePlan: дефолт false (раньше true). Enum: дефолт true (теперь параметризовано). Цифры из acc_8.3.27 + erp_8.3.24 — у Catalog ~95% объектов QuickChoice=false, у Enum ~99% true.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 17:34:16 +03:00
Nick Shirokov c1a0a54971 feat(web-test): --record и export const params
Раннер v1.7.

T5 --record: startRecording перед каждым тестом, stopRecording
после (и в passed, и в failed ветке). Файл
{reportDir}/{testIdx}-{slug}.mp4. testResult.video содержит путь.
В Allure — attachment типа video/mp4. config.record читается
тоже. Использует существующую инфраструктуру browser.mjs.

T6 export const params: материализация в N тестов на этапе
discovery. Имя через {key}-шаблон в mod.name (например
'demo {type}'); если шаблона нет — суффикс [index]. Тест-функция
получает param как второй аргумент: default(ctx, param).
В отчёте каждый набор — отдельная test entry с собственным uuid
в Allure / testcase в JUnit.

Live-проверка:
- params: 2 теста с именами demo A / demo B из шаблона.
- record: mp4 91KB на 6-секундном тесте, путь в JSON и
  Allure attachment video/mp4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 16:19:52 +03:00
Nick Shirokov 927c0827f3 feat(web-test): --format=allure и --format=junit
Раннер v1.6. Реализованы оба формата отчётов из spec §9.

allure: {reportDir}/{uuid}-result.json на каждый тест. uuid через
randomUUID, labels из tags, steps рекурсивно с attachments из
step.screenshot, statusDetails для упавших шагов и тестов.
Пропускает skipped (нет start/stop).

junit: один XML в --report=path.xml. Валидация: --format=junit
требует --report=. xmlEscape для name/message/trace. <failure>
для упавших, <skipped/> для пропущенных, <system-out> со ссылкой
на screenshot.

Валидация формата (json|allure|junit) на старте cmdTest.
testResult теперь хранит start/stop в мс — нужно для Allure
и полезно в JSON-отчёте.

Live-проверка: 01-navigation в Allure (5 шагов с attachments,
все ссылки на существующие PNG); JUnit с passed и forced-fail
(спецсимволы корректно экранированы).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 16:03:31 +03:00
Nick Shirokov 56cd18a6b4 feat(web-test): --screenshot=on-failure|every-step|off + --report-dir
Раннер v1.5. Парсит --screenshot и --report-dir, мерж с config.screenshot.
- every-step: после успешного step() пишет {reportDir}/{testIdx}-{stepIdx}-{slug}.png,
  путь в step.screenshot.
- off: ни пошаговых, ни error-shot.
- on-failure (default): error-shot уехал из .claude/skills/web-test/
  в {reportDir}/error-{testIdx}-{slug}.png.

reportDir фоллбэчит: --report-dir → dirname(--report) → testDir.

Известная нестыковка: error-shot из buildContext/executeScript остаётся в
.claude/skills/web-test/error-shot.png — затронем при T2 (Allure).

Live-проверка: 01-navigation с every-step (5 PNG), off (пусто),
default on-failure на стуб-failing тесте (error-shot в reportDir).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 15:54:38 +03:00
Nick Shirokov 3ac1d425cd test(11-report): DCS-отчёт ОстаткиТоваров + smoke с быстрым фильтром
Синтетика: добавлен template-add ОсновнаяСхемаКомпоновкиДанных к отчёту
(без него skd-compile писал Template.xml в незарегистрированный путь),
переписан DSL skd-compile — fields внутри dataSets, типы полей, totalFields,
явный settingsVariants со structure и быстрым отбором по Номенклатуре
(@off @user @quickAccess).

Тест 11-report покрывает: регистрацию команды в подсистеме, открытие формы
отчёта с дефолтной кнопкой Сформировать, видимость и структуру быстрого
DCS-фильтра, формирование отчёта, применение фильтра через selectValue
(auto-enable чекбокса + значение), пересчёт с фильтром, снятие фильтра
через fillFields toggle off с восстановлением исходных данных.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 15:22:22 +03:00
Nick Shirokov 3c596f4550 test(12-formstate): smoke базовых полей getFormState
Покрывает форму списка (form, formCount, openForms, tables, buttons)
и форму элемента (fields с label и value, проверка по конкретному
полю Наименование).
2026-05-02 20:15:20 +03:00
Nick Shirokov 36d29a51a9 test(09-filter): smoke filterList simple-search и advanced-column
Покрывает:
- filterList('Север') — поиск по всем колонкам списка Контрагенты
- filterList('Север', { field: 'Наименование' }) — фильтр по
  конкретной колонке через расширенный поиск
- unfilterList — восстановление исходного набора

Третий запланированный кейс (text-field filter) семантически совпадает
с advanced-column когда колонка строкового типа — оставлен на регресс P1.
2026-05-02 20:11:58 +03:00
Nick Shirokov 11e961c816 test(07-tabs): smoke переключение страниц формы Основное/Дополнительно
Покрывает clickElement по имени страницы как механизм переключения
вкладок формы. Используем форму элемента Номенклатура: page1
показывает шапку (Артикул, ВидНоменклатуры, ...), page2 — Дополнительно
(ЕдиницаИзмерения, Комментарий). Verify: набор state.fields различен
после переключения и совпадает после возврата.
2026-05-02 20:07:46 +03:00
Nick Shirokov 05ca810461 test(06-document): сверка с Комментарий=docId, защита от грязной базы
Раньше verify-list брал первый попавшийся проведённый документ Север —
если в базе уже лежал проведённый Север из прошлого прогона, тест
проходил даже если текущий не сохранился. Теперь среди кандидатов
открываем каждый и сверяем Комментарий с уникальным docId текущего
прогона; ассерт срабатывает только при совпадении.
2026-05-02 20:04:38 +03:00
Nick Shirokov a0407b74dc test(06-document): проверка закрытия по смене номера формы вместо костыля
Раньше использовалось отсутствие поля Контрагент после Провести и закрыть
как косвенный признак закрытия — это работало, но было привязано к
конкретному реквизиту накладной. Заменил на сравнение state.form до и
после: номер активной формы меняется (11 → 5), это прямой и общий
признак, что мы переключились с формы документа на другую.
2026-05-02 19:58:56 +03:00
Nick Shirokov 3aad254399 test(06-document): smoke workflow проведения накладной
Создание, заполнение шапки и табличной части, Провести и закрыть,
проверка появления документа в списке с Проведён=Да.

Проверка закрытия формы документа: в синтетике web-test форма списка и
форма документа делят один слот (formCount=1 в обоих состояниях),
поэтому используем признак отсутствия поля Контрагент в текущем
state.fields после Провести и закрыть — если поле есть, мы остались
на форме документа.
2026-05-02 19:54:34 +03:00
Nick Shirokov 07753921be test(05-table): smoke add/edit/delete для табличной части накладной
Покрывает работу с табличной частью Товары документа Приходная накладная:
- fillTableRow с add:true добавляет строки последовательно
- fillTableRow с row:N редактирует существующую строку (Tab-навигация)
- deleteTableRow удаляет строку по индексу

Закрытие формы без сохранения (save:false) — соответствует новой
семантике после фикса form-compile (SavedData).
2026-05-02 19:49:19 +03:00
Nick Shirokov ba0c71fa45 test(smoke): починить 01-navigation и 04-selectvalue после фикса form-compile
01-navigation: первое открытое окно 1С имеет form=0 (number), и
assert.ok(state.form, ...) валился на falsy при первом запуске сессии.
Сменил на state.form != null.

04-selectvalue: явный save:false при закрытии модифицированной формы
накладной — после фикса SavedData=true главного реквизита платформа
требует решения по confirmation dialog.
2026-05-02 19:45:15 +03:00
Nick Shirokov 33c9fdade0 test(03-fillfields): boolean → CheckBoxField, явный save:false при закрытии
После фикса form-compile (kind=check для Boolean + SavedData=true для
главного реквизита) Активен передаётся как настоящий boolean (toggle),
getFormState возвращает value:true/false. Закрытие модифицированных форм
теперь требует явного save:false — иначе платформа показывает
confirmation dialog «Записать?».
2026-05-02 19:40:26 +03:00
Nick Shirokov 1c1fe7b2d9 test(02-crud): убрать устаревший комментарий про T11/SavedData
После фикса form-compile (a59be4b SavedData=true для главного реквизита)
canonical confirm-save-yes flow работает без ручного патча Form.xml —
предупреждение в шаге неактуально.
2026-05-02 19:26:56 +03:00
Nick Shirokov 0bd2587e74 test(build-webtest-config): Активен как check вместо input для Boolean
После фикса form-compile (Дефект 2: kind=check → CheckBoxField) булевый
реквизит Активен в форме элемента и форме списка Номенклатуры теперь
описывается как check — рендерится настоящим чекбоксом.
2026-05-02 19:24:50 +03:00
Nick Shirokov 6f17b1c2f6 Merge branch 'dev' into feature/web-test-runner 2026-05-02 19:08:28 +03:00
Nick Shirokov b4514dc350 feat(form-compile): AutoMaxWidth=false по умолчанию для multiLine InputField
В реальных формах ERP/БП у ~60% многострочных полей ввода явно стоит
АвтоМаксимальнаяШирина=Ложь. Теперь form-compile проставляет это
автоматически при multiLine: true, если пользователь не задал
autoMaxWidth явно.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 19:05:50 +03:00
Nick Shirokov 8ad5d80f7f feat(form-compile): автоподстановка RowPictureDataPath для DynamicList с MainTable
Document/InformationRegister/AccumulationRegister List-генераторы теперь
прописывают `Список.DefaultPicture` (как делает ERP/БП в 594/600 форм
списка документов). Плюс fallback в эвристике DynamicList-таблицы:
если у главного реквизита есть `settings.mainTable`, поле
подставляется автоматически и для ручного DSL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 18:39:29 +03:00
Nick Shirokov fc19df604b chore(tests): --help в runner и verify-snapshots, синхронизация README
Чтобы --help/-h/? не запускали полный прогон тестов.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 18:17:24 +03:00
Nick Shirokov 76800fc92b feat(form-compile): автоген Title из имени для узлов без источника синонима
Реквизиты формы, команды, страницы, попапы и декорации теперь получают Title,
сгенерированный из CamelCase-имени, если в DSL он не задан явно. Поля с path
и кнопки с command по-прежнему опускают Title — синоним подхватится платформой.
Главные реквизиты (Объект/Список/Запись с main=true) исключены.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 18:17:19 +03:00
Nick Shirokov 36cd63d8bb fix(form-compile): AutoTitle=false по умолчанию при заданном Title формы
Когда у формы задан Title (через defn.title или properties.title), эмитим
AutoTitle=false если пользователь явно его не указал. Иначе платформа
добавляет суффикс синонима и получается двойной заголовок (Номенклатура:
Номенклатура). В выгрузках ERP так делает ~95% форм с form-level Title.

Снапшоты form-compile/form-compile-from-object обновлены под новое поведение.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 17:22:48 +03:00
Nick Shirokov e216db5734 fix(form-compile): default TitleLocation=Right для CheckBoxField
Платформенный default TitleLocation для CheckBoxField — Left, что почти
никогда не соответствует UX-ожиданиям. В acc 8.3.27 для CheckBoxField:
Right (явно): 811, без тега (=Left): 406, None: 140, Left: 14, Top: 3 —
доминирующий паттерн «заголовок справа от флажка».

Эмитим <TitleLocation>Right</TitleLocation> по умолчанию для check.
Переопределяется через titleLocation: 'Left' / 'None' / 'Top' / 'Bottom'.

v1.11. Обновил 5 snapshot'ов.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 16:59:31 +03:00
Nick Shirokov a59be4b914 fix(form-compile): SavedData=true для object/RecordManager главного реквизита
Без <SavedData>true</SavedData> платформа не маркирует форму как modified
при изменении главного реквизита — confirmation dialog при Esc не появляется,
canonical flow «изменил → Esc → Да» сломан.

Правило выведено из реальной выгрузки acc 8.3.27: SavedData ставится только
для редактируемых форм с типом *Object.X (Catalog/Document/ChartOf…/
ExchangePlan/BusinessProcess/Task) или *RecordManager.X. DynamicList/Report/
DataProcessor/ConstantsSet/RecordSet — не трогаем, отдаём решение DSL через
явный savedData: true.

Поднял версию до v1.10. Обновил 5 snapshot'ов (формы элементов/документа).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 16:51:43 +03:00
Nick Shirokov 36ad686316 feat(web-test): smoke-тест 04-selectvalue (dropdown быстрый выбор)
Один P0 кейс из coverage matrix:
- dropdown: selectValue('Контрагент', 'ООО Север') → method='dropdown'
  на форме новой ПриходнойНакладной (CatalogRef + малый список)

API возвращает form state с .selected = {field, search, method}.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:57:37 +03:00
Nick Shirokov 66e37fb8cc feat(web-test): smoke-тест 03-fillfields (text, dropdown, date, reference)
2 шага, 5 типов полей зелёные на синтетике webtest:
- text (paste): Артикул на форме Номенклатура
- dropdown (Да/Нет): Активен — Boolean рендерится как Да/Нет селектор
- dropdown (EnumRef): ВидНоменклатуры
- date (paste): ДатаПоступления
- reference (dropdown CatalogRef): Контрагент в новой ПриходнаяНакладная

NB: 1C рендерит Boolean-атрибут не как чекбокс, а как dropdown «Да/Нет»
(actions: ["select"]) — fillFields правильно определяет это.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:55:14 +03:00
Nick Shirokov 99c77e1dde fix(web-test): 02-crud использует canonical closeForm({save:true})
Гипотеза о баге fillField paste была ошибочной — реальная причина в form-compile
который не эмитит <SavedData>true</SavedData> для MainAttribute главной формы.
Платформа без SavedData не трекает modified-state, confirmation dialog не
появляется.

Платформенная верификация на патченной Form.xml: closeForm({save:true})
после fillField корректно ловит confirmation, жмёт «Да», изменения
сохраняются. См. T11 в upload/web-test-runner-tasks.md.

ВНИМАНИЕ: тест зависит от ручного патча Form.xml. После прогона
build-webtest-db.mjs тест упадёт до фикса form-compile (T11).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:44:39 +03:00
Nick Shirokov 8d6612027f feat(web-test): smoke-тест 02-crud (open-item, close-clean, read, save)
4 шага зелёные на синтетике webtest:
- read: список Контрагентов отдаёт колонки/строки/total
- open-item: dblclick открывает форму элемента
- close-clean: Escape без изменений закрывает форму без диалога
- save-via-button: fillField + «Записать и закрыть» → значение сохраняется

confirm-save-yes (P0 из coverage matrix) отложен — fillField через paste не
выставляет 1C "modified" флаг, confirmation dialog не появляется. Зафиксировано
в upload/web-test-runner-tasks.md как T11.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:34:37 +03:00
Nick Shirokov c3b67a18cb feat(tests): build-webtest-db скрипт для постоянной webtest базы
Заменяет одноразовый platform-webtest-config.test.mjs на скрипт сборки в
постоянные пути из .v8-project.json (tests/skills/.cache/webtest-config
+ C:\edt\IB\webtest). Переиспользует steps из build-webtest-config.test.mjs.

Generic platform-config.test.mjs уже покрывает regression «платформа принимает
сборку» — отдельный синтетический тест дублировал.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:23:42 +03:00
Nick Shirokov 4d1b66638c Merge branch 'dev' into feature/web-test-runner 2026-05-02 14:54:50 +03:00
Nick Shirokov 4b8d3b67dc fix(tests): platform-verifiable form-info DSL + external setup в verify-snapshots
- form-info/{rich-form,simple-form}: тип реквизита Объект исправлен
  с ExternalDataProcessorObject на DataProcessorObject — preRun создаёт
  обычную обработку, и платформа отвергала несоответствие XDTO-исключением.
- verify-snapshots.mjs: поддержка setup="external:<path>" — копирует
  внешний дамп (выгрузку ERP/БП) в workDir, пропускает cf-init и
  авто-регистрацию объектов через cf-edit. Платформенная загрузка
  целой вендорской конфы скипается — кейсы real-acc-form-* проверяют
  скрипт против реального XML, а не пригодность всей БП к чистой базе.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:31:18 +03:00
Nick Shirokov 6650d2b516 feat(form-info): показывать главную AutoCommandBar формы с учётом CommandBarLocation
Раньше AutoCommandBar (id=-1) полностью скрывалась как companion-элемент.
Из-за этого модель не видела главную панель и часто добавляла избыточную
дополнительную cmdBar снизу формы по образцу старых сгенерённых форм.

Теперь:
- AutoCommandBar формы выводится отдельным разделом с флагами
  (autofill/no-autofill, align=...) и списком кастомных кнопок.
- Позиция секции зависит от свойства формы CommandBarLocation:
  Auto/Top — над деревом элементов (нативное поведение платформы),
  Bottom — под деревом, None — секция скрыта.
- Если панель пустая с дефолтным autofill — выводится одной строкой.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 21:04:26 +03:00
Nick Shirokov 6b63177687 feat(form-compile): не эмитить HorizontalAlign по умолчанию + чистка SKILL.md
- HorizontalAlign не эмитится, если не задан явно через autoCmdBar.horizontalAlign.
  Раньше был хардкод Right; платформенный дефолт — Left, эталонные формы
  типовых (Бригады/ФормаСписка) тег вообще не содержат.
- horizontalAlign принимает Left/Center/Right.
- SKILL.md: убран раздел «Эвристики компилятора» (внутренняя кухня скрипта),
  сжато описание autoCmdBar и main — модель пишет DSL явно, помощь
  компилятора видна в [INFO]/[WARN]-логе.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:54:57 +03:00
Nick Shirokov 13174b63b1 feat(form-compile): нативная AutoCommandBar формы + autoCmdBar DSL
- Эвристика главной АКП: без cmdBar/autoCmdBar остаётся Autofill=true
  (как в Конфигураторе), с cmdBar — Autofill=false (обратная совместимость).
- Новый элемент autoCmdBar для наполнения главной АКП кастомными кнопками.
- Тихие синонимы commandBar↔cmdBar, autoCommandBar↔autoCmdBar.
- Инференс main-реквизита по типу (*Object.*, *RecordSet.*, DynamicList,
  ConstantsSet) — единственный кандидат проставляется молча с [INFO].
- Эвристика DynamicList → таблица: tableAutofill=false +
  commandBarLocation=None для привязанной таблицы (соответствие ERP).
- Косметика: <Autofill>true</Autofill> не эмитится явно.

Snapshot'ы form-* также обновлены до актуального состояния cf-init
(Ext/ClientApplicationInterface.xml).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:46:23 +03:00
Nick Shirokov 433a2955b5 fix(form-compile): лояльно стрипать cfg: префикс главного реквизита
Раньше тип `cfg:CatalogObject.X` мимо regex попадал в fallback и получал
второй `cfg:` поверх → `cfg:cfg:...`, db-load-xml падал. Теперь
Resolve-TypeStr срезает ведущий `cfg:` сразу, обе формы записи валидны.
Заодно сообщение об ошибке FormDataStructure согласовано с примером —
без префикса.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 19:32:53 +03:00
Nick Shirokov 42b96bbd21 feat(cf-*): set-home-page + drill-down -Section home-page + form-ref валидация
- cf-edit: новая операция set-home-page перезаписывает Ext/HomePageWorkArea.xml.
  DSL принимает template (OneColumn/TwoColumnsEqualWidth/TwoColumnsVariableWidth),
  left/right с записями форм (строка или объект form/height/visibility/roles).
  Тихая нормализация ссылок: русские типы, 3-сегмент → авто-Form, файловые пути
- cf-info: краткая HP-сводка (template + счётчики) в overview/full, детальный
  вид через -Section home-page (alias -Name) с раскладкой и переопределениями ролей
- cf-validate: Check 9 — валидация ссылок на формы из HomePageWorkArea и
  Default*Form свойств; битая ссылка → error
- reference.md: убран реализационный шум (canonical sort, авто-нормализация форм,
  panelDef detail, секция авто-валидации); путь src/ в примерах вместо репо-специфичных

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 19:13:18 +03:00
Nick Shirokov 363a9f34f2 Merge dev: cf-info раскладка, cf-edit set-panels с русскими синонимами 2026-05-01 17:06:51 +03:00
Nick Shirokov bd3b40852a feat(cf-edit): set-panels принимает русские имена панелей silently
cf-info отображает «Открытых», «Разделов», «Избранного», «История», «Функций»
(совпадает с подписями Конфигуратора). Если модель копирует эти названия в
set-panels value — теперь они тихо мапятся в каноничные английские алиасы.
Документация и сообщения об ошибках упоминают только английские формы.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:05:38 +03:00
Nick Shirokov 336dade274 feat(cf-edit): операция set-panels для раскладки панелей
JSON-DSL уровня имён: алиасы sections/open/favorites/history/functions
для платформенных uuid, объект {group:[...]} для стека (даёт <group>-
вложенность как у Конфигуратора), несколько записей в одной стороне =
соседние теги (рядом). Файл Ext/ClientApplicationInterface.xml
перезаписывается полностью; panelDef для всех 5 панелей пишется всегда.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:03:57 +03:00
Nick Shirokov 99e9c1e0b8 feat(cf-info): показывать раскладку панелей в overview/full
Читает Ext/ClientApplicationInterface.xml (если есть) и выводит секцию
«Раскладка панелей» с маппингом UUID → имя для 5 платформенных панелей.
Стек панелей внутри одной стороны отображается как «Стек(a, b)»,
несколько отдельных тегов стороны (рядом) — через « | ».

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 16:57:53 +03:00
Nick Shirokov 4f8ce7b747 chore(web-test): убрать инлайн ClientApplicationInterface.xml
Файл теперь генерируется самим cf-init с ERP-дефолтом (см. предыдущий
коммит на dev), отдельный writeFile в build-webtest-config больше не нужен.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 16:48:13 +03:00
Nick Shirokov fc48d68ed1 Merge dev: cf-init создаёт Ext/ClientApplicationInterface.xml 2026-05-01 16:46:30 +03:00
Nick Shirokov 3c3ed2ff46 feat(cf-init): генерить Ext/ClientApplicationInterface.xml с ERP-дефолтом
Без этого файла веб-клиент 1С рендерит секции icon-only (без подписей),
а web-test их не видит. Дефолтная раскладка как в типовых ERP/БП ≥ 8.3.24:
панель открытых сверху, панель разделов слева; функций/избранного/истории
объявлены через panelDef но не размещены.

Расширил docs/1c-configuration-spec.md § 4.2 моделью раскладки и таблицей
UUID 5 платформенных панелей. Обновил снапшоты cf-init под новый файл.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 16:43:39 +03:00
Nick Shirokov 3e34ec0bdd fix(web-test): заголовки и стиль вкладок на форме Номенклатуры
Page элементы в DSL получали name (через ключ 'page'), но не получали
title, поэтому вкладки рендерились пустыми квадратиками. Также Pages
без явного pagesRepresentation отображались в режиме None (без табов).

- Добавил title к каждой Page (Основное, Дополнительно)
- pagesRepresentation: 'TabsOnTop' на Pages

После: getFormState().tabs возвращает [{name:'Основное'},{name:'Дополнительно'}]
вместо пустого массива.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 15:33:19 +03:00
Nick Shirokov fff2e83960 fix(web-test): починить runtime синтетики для тонкого клиента
Два бага, найденные при попытке запустить синтетическую ИБ через
web-publish + web-test:

1. ОбщиеФункции без ServerCall=true — ManagedApplicationModule (клиент)
   не мог звать процедуры серверного модуля напрямую. ПриНачалеРаботыСистемы
   падал с ошибкой компиляции в runtime, страница не догружалась. Добавил
   serverCall: true в DSL meta-compile.

2. Без Ext/ClientApplicationInterface.xml панель разделов рендерилась
   icon-only (без подписей), web-test navigateSection не находил секции.
   Добавил writeFile-шаг с раскладкой панелей как в acc/erp:
   - top: панель разделов (8e10648b...) + панель информации (cbab57f2...)
   - left: панель функций текущего раздела (b553047f...)

Проверено end-to-end: после пересборки runner-ом + web-publish + start
работают navigateSection, openCommand, readTable. Фикстуры (4 контрагента,
25 номенклатуры в группах, 3 документа) автоматически заполняются при
первом старте через ManagedApplicationModule → ОбщиеФункции.ЗаполнитьФикстурыЕслиНужно.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 15:12:43 +03:00
Nick Shirokov 1ff209849f feat(web-test): первоначальное заполнение фикстур (M1 Step 5)
Покрытие matrix #9 — данные для smoke-тестов:
- Константа ДанныеЗаполнены (Boolean) — флаг идемпотентности
- ОбщиеФункции.ЗаполнитьФикстурыЕслиНужно() — транзакционно создаёт:
  * 4 контрагента (ООО Север/Юг/Восток, АО Запад)
  * 25 номенклатуры в группах Товары (15) и Услуги (10)
  * 3 приходных накладных по 3 строки
- Ext/ManagedApplicationModule.bsl с ПриНачалеРаботыСистемы — вызывает
  заполнение при первом старте тонкого клиента

Платформенная верификация компилирует BSL (43 шага, 23.7s). Реальное
выполнение заполнения произойдёт при первом подключении web-test
runner-а к синтетической базе.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:36:13 +03:00
Nick Shirokov 1a8415283e chore(web-test): убрать избыточный cf-edit (объекты регистрируются автоматически)
meta-compile/subsystem-compile/role-compile сами добавляют записи в
Configuration.xml. cf-edit в каждом прогоне рапортовал Added: 0 — был
no-op + дублировал список объектов, который надо было синхронизировать
руками при каждом изменении.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:32:48 +03:00
Nick Shirokov db1e78a534 feat(web-test): подчинённый каталог КонтактныеЛица (M1 Step 4)
Покрытие matrix #8 — getFormState.navigation (12-formstate/subordinate-nav):
- Catalog.КонтактныеЛица с Owner=Catalog.Контрагенты
- Реквизиты: Должность, Телефон
- ФормаЭлемента (с владельцем) + ФормаСписка
- Регистрация в Configuration + Subsystem.Склад + Role

Платформенная верификация: 41 шаг, 23.8s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:30:15 +03:00
Nick Shirokov a828f1847f feat(web-test): обработка ТестовыеОшибки + bsl-модули (M1 Step 3)
Покрытие matrix #6 — errors balloon/messages/modal (10-validation,
fetchErrorStack Path 2):
- ОбщиеФункции.ПоказатьСообщение() → Сообщить("Тестовое сообщение")
- ОбщиеФункции.ВызватьТестовоеИсключение() → ВызватьИсключение
- DataProcessor.ТестовыеОшибки + ФормаОбработки с двумя кнопками,
  каждая делает клиент→сервер вызов соответствующей процедуры
- Регистрация в Configuration + Subsystem.Администрирование

Runner расширен step-типом writeFile — записывает произвольный текст
(обычно Module.bsl) в workDir. Нет навыка для модификации bsl-кода
модулей, и плодить отдельный навык под одну задачу избыточно.

Платформенная верификация: 36 шагов, 21.2s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:27:38 +03:00
Nick Shirokov 3e8159b591 feat(web-test): формы списков с правильными колонками (M1 Step 2)
Расширение синтетики (пункты 3, 4, 5 из M1):
- Контрагенты.КодКПП: новый String реквизит, НЕ выводимый в форму списка
  (для теста filterList #5 — FieldSelector DLB по скрытой колонке)
- Catalog.Контрагенты.ФормаСписка: Code, Description, ИНН, Телефон, Адрес
- Catalog.Номенклатура.ФормаСписка: Code, Description, Артикул,
  ВидНоменклатуры, ДатаПоступления, Цена, Активен (date-колонка для
  filterList #6)
- Document.ПриходнаяНакладная.ФормаСписка: Date, Number, Контрагент, Posted
  (reference-колонка для filterList #7)

Платформенная верификация: 31 шаг, 21.4s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:23:38 +03:00
Nick Shirokov 57bb964c1e feat(web-test): ссылочные типы и Boolean в синтетике (M1 Step 1)
Расширение build-webtest-config под coverage matrix (пункты 1, 2, 7
из upload/web-test-runner-tasks.md M1):
- Перечисление КатегорииЦен (для будущего radio-button теста)
- Номенклатура.ВидНоменклатуры → EnumRef.ВидыНоменклатуры
- Номенклатура.КатегорияЦены → EnumRef.КатегорииЦен
- ПриходнаяНакладная.Контрагент: String → CatalogRef.Контрагенты
- ПриходнаяНакладная.Товары.Номенклатура: String → CatalogRef.Номенклатура
- ПриходнаяНакладная.Товары.Согласовано: новый Boolean (для checkbox
  в grid, fillTableRow ветка #6)
- Формы Номенклатура и Документ обновлены под новые поля
- Subsystem.Склад: добавлены Enum.* в content
- Configuration.xml регистрирует Enum.КатегорииЦен

Платформенная верификация (platform-webtest-config.test.mjs) зелёная,
25 шагов 16.7s.

Гэп: form-compile не умеет рендерить RadioButtonField — представление
КатегорияЦены остаётся обычным input. Будет отдельной задачей перед
тестами P1 fillFields/radio.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:21:22 +03:00
Nick Shirokov 41c4b6b1f7 fix(skills/tests): cleanupWorkspace терпимо переживает EBUSY от 1cv8
После платформенных тестов (db-create/db-load-xml/db-update) Windows
держит файловые хэндлы 1cv8 ещё несколько сотен миллисекунд. rmSync без
ретраев падал EBUSY на Roles/.../Rights.xml, и uncaught-ошибка в finally
рушила весь node-процесс — теряли результат теста.

Теперь rmSync с maxRetries: 10, retryDelay: 200 (≈2с буфер) и try/catch
вокруг — в худшем случае warning + лишняя tmp-папка вместо краша.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:21:08 +03:00
Nick Shirokov ffb0ee740d fix(web-test): восстановить синтетическую конфу + платформенная верификация
build-webtest-config упал после ужесточения form-compile (запрет runtime-типа
FormDataStructure для главного реквизита). Перевёл типы на конкретные
CatalogObject.X / DocumentObject.X без cfg:-префикса. Добавил
platform-webtest-config.test.mjs — переиспользует шаги сборки и в хвосте
делает db-create + db-load-xml + db-update. Зелёный, 24 шага.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 12:12:45 +03:00
Nick Shirokov f5e487096f Merge branch 'dev' into feature/web-test-runner 2026-05-01 11:58:28 +03:00
Nick Shirokov d75b4d96ca fix(verify-snapshots): структурные зависимости с preRun и ChartOfAccounts
getStructuralDeps теперь сканирует все inputs (caseData.input + preRun.input),
а не только верхний — без этого регистры, созданные через preRun, оставались
без документа-регистратора и платформа отвергала конфиг с
«Ни один из документов не является регистратором».

Добавлен случай ChartOfAccounts: при maxExtDimensionCount>0 (или непустых
extDimensionAccountingFlags) и без явной ссылки extDimensionTypes
автоматически создаётся стаб ChartOfCharacteristicTypes и линкуется через
meta-edit modify-property уже после preRun. Для этого getStructuralDeps
возвращает теперь { deps, hostEdits }, а в основной поток добавлен Step 3.5
(host-level structural edits).

InformationRegister с writeMode=Subordinate/RecorderSubordinate тоже
получает документ-регистратор.

Полный прогон verify-snapshots: 193/193.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:12:12 +03:00
Nick Shirokov 704fbc9f28 feat(verify-snapshots): платформенная верификация mxl-compile
Готовый Template.xml оборачивается в исходники EPF: epf-init создаёт
скелет, template-add регистрирует SpreadsheetDocument-макет, MXL копируется
поверх дефолтного, далее epf-build реально проверяет, что платформа
принимает разметку. mxl-compile убран из STANDALONE_SKILLS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:59:06 +03:00
Nick Shirokov cd74afa5e0 feat(verify-snapshots): платформенная верификация template-add и help-add
После main-скрипта определяется тип артефакта в workDir: Configuration.xml
→ обычная загрузка конфигурации, иначе по корню *.xml выбирается ветка
epf-build (.epf для ExternalDataProcessor, .erf для ExternalReport). Для
кейсов с cf-init теперь configDir переустанавливается на workDir, так что
конфиг действительно грузится в БД, а не пропускается.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:42:00 +03:00
Nick Shirokov 370873511d feat(verify-snapshots): платформенная верификация epf-init и erf-init
EPF_SKILLS превращён из «skip» в реальную сборку через epf-build —
строится .epf или .erf по расширению из map. Имя источника берётся
из caseData.params.name. erf-init добавлен в DEFAULT_SKILLS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 15:25:20 +03:00
Nick Shirokov 9ced410d8f feat(verify-snapshots): платформенная верификация skd-edit
skd-edit добавлен в SKD_PLATFORM_VERIFY — результат заворачивается в ERF и
собирается через epf-build, как уже сделано для skd-compile. Резолвер пути
шаблона теперь учитывает params.templatePath (фолбэк: outputPath, Template.xml).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 15:09:38 +03:00
Nick Shirokov 50ba38a9f6 docs(skd-compile): корректные имена ресурсов оборотов в примере @autoDates
Виртуальная таблица .Обороты(...) возвращает ресурсы регистра с
суффиксом «Оборот» — Продажи.Количество в запросе к Обороты не
существует, нужно Продажи.КоличествоОборот. Чтобы поле в наборе
осталось «Количество» (и совпадало с totalFields/fields), добавлен
алиас КАК.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 19:08:32 +03:00
Nick Shirokov d4b105bbe4 docs(skd-compile): починить пример «С ресурсами, параметрами и @autoDates»
В прежнем примере @autoDates не приносил пользы (запрос к физической
таблице регистра, а не к виртуальной Обороты), а Организация
использовалась в filter и structure, но не выбиралась в запросе и
не была описана в fields — так схема не собралась бы или собралась
бы с пустыми колонками.

Чиню:
- запрос → РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода)
- добавлено поле Организация: СправочникСсылка.Организации @dimension
- selection — явный список без "Auto" (все поля и так перечислены)
- dataParameters: "auto" вместо ручного перечисления

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 19:00:33 +03:00
Nick Shirokov 204a262746 feat(verify-snapshots): реальная платформенная проверка skd-compile
До сих пор для skd-compile (как и других STANDALONE_SKILLS)
verify-snapshots просто запускал скрипт и помечал PASS — без
платформенной нагрузки. Опасный пробел: можно было закоммитить
snapshot, который 1С Designer не примет.

Теперь для skd-compile snapshot оборачивается во внешний отчёт
(erf-init --WithSKD), Template.xml подменяется на сгенерированный
кейсом, и запускается erf-build. Платформа парсит схему — если
принимает, кейс PASS; если отклоняет, в errors попадает её stderr.
Ссылочные типы (CatalogRef.X и т.п.) не требуют реальной базы:
epf-build сам поднимает временную stub-конфигурацию.

Если v8 недоступен — мягкий skip с пометкой "no v8 context".

Замер: 21 кейс x ~5s avg = ~110s на полный verify-snapshots
--skill skd-compile. Все 21 текущих кейса проходят — значит каждый
snapshot гарантированно платформо-валиден.

Аналогичная обёртка для mxl-compile / role-compile — отдельной
задачей по образцу.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 18:56:13 +03:00
Nick Shirokov 210bde7b2e docs(skd-compile): убрать список синонимов типов из раздела «Поля»
Перечень русских/альтернативных синонимов (`число`, `строка`,
`СправочникСсылка.X`, `int`, `bool` и т.п.) — справочный шум для
модели-пользователя: она по умолчанию пишет канонические английские
имена, а парсер тихо принимает синонимы через Resolve-TypeStr без
необходимости их декларировать в SKILL.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 18:38:34 +03:00
Nick Shirokov a932841418 fix(skd-info): убрать лишний пробел в 'Templates: N defined ( bindings)'
При схеме без field- и group-привязок строка вывода Templates выглядела
как 'Templates: 4 defined ( bindings)' — пустой блок с одиноким пробелом
перед 'bindings)'. Теперь, когда привязок нет, скобки опускаются:
'Templates: 4 defined'.

Версия v1.3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 18:32:47 +03:00
Nick Shirokov 576f6dda8a feat(skd-compile): многоязычный title/presentation (объектная форма)
Везде, где DSL принимает title/presentation, теперь поддерживается
объектная форма с языками: "title": { "ru": "...", "en": "..." }.
Строка по-прежнему работает как ru-only.

Покрыто: field title, calculatedField title, parameter title/presentation,
settingsVariant title/presentation (root и в structure-items),
availableValue title/presentation, userSettingPresentation в filter/dataParameter,
mltext-значения в conditionalAppearance.appearance (ключи Текст/Заголовок/Формат).

Реализация:
- Хелпер emit_mltext / Emit-MLText расширен — принимает string|dict и
  итерирует по языкам.
- 8 inline-блоков LocalStringType в каждом скрипте заменены на вызовы
  хелпера (унификация — побочный эффект, бенефит на будущее).
- На входе сняты str()/"$()" коэрции для title/presentation, чтобы dict
  доходил до хелпера живым.

- SKILL.md: одна строка про объектную форму title.
- tests: новый snapshot-кейс multi-lang-title (5 узлов с ru+en).
- Версия v1.21.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 18:30:37 +03:00
Nick Shirokov 1a5b788305 feat(skd-compile): составной тип поля valueType (массив типов)
В объектной форме поля DataSet ключ "type" теперь принимает массив:
"type": ["CatalogRef.A", "CatalogRef.B"] — генерирует несколько <v8:Type>
внутри одного <valueType>. Типичный паттерн в ERP для полей-расшифровок
с составным ссылочным типом.

Shorthand остаётся одно-типовым (без перегрузки). Квалификаторы
((N)/(D,F)) применяются к каждому элементу массива независимо.

- skd-compile.ps1/py: Emit-ValueType/emit_value_type диспатчат на
  Emit-SingleValueType при строке или итерируют при массиве; field-парсер
  сохраняет массив, не приводя к строке. Версия v1.20.
- SKILL.md: один абзац после описания типов.
- tests: новый snapshot-кейс field-multi-type на 3 ссылочных типа.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 18:04:49 +03:00
Nick Shirokov b39da27d20 docs(skd-compile): описать presentationExpression и appearance на поле
В DSL skd-compile уже поддерживались ключи presentationExpression и
appearance в объектной форме поля DataSet, но в SKILL.md они не были
задокументированы — фичи существовали де-факто, но обнаружить их можно
было только чтением скрипта.

Заодно зафиксирован детерминизм порядка ключей appearance: PS5.1
hashtable не сохраняет порядок вставки, из-за чего PS- и PY-рантаймы
давали разный XML на одном входе. Заменено на [ordered]@{}.

- SKILL.md: новый блок «Дополнительные ключи объектной формы» в разделе «Поля»
- skd-compile.ps1/py: appearance = [ordered]@{} вместо @{}, версия v1.19
- tests: новый snapshot-кейс field-appearance-and-presentation,
  проходит на обоих рантаймах

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 17:57:04 +03:00
Nick Shirokov 1f23afe6f9 feat(skd-info): -Mode full перечисляет внешние наборы
Когда DataSetQuery нет, в секции query вместо безликого
"(no query datasets)" теперь печатается список objectName из
DataSetObject: "(no query datasets; external datasets: <names>)".
Не нужно скроллить вверх к Overview, чтобы увидеть источник схемы.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 16:47:01 +03:00
Nick Shirokov eda7279de0 fix(skd-info): -Mode full на схеме без DataSetQuery
Show-Query/show_query при отсутствии DataSetQuery делал exit 1, что
обрывало full режим после Show-Overview — секции fields/resources/
params/variant пользователь не видел. Теперь в full проверяем наличие
Query-набора и при отсутствии печатаем "(no query datasets)" и
продолжаем. Прямой -Mode query сохраняет прежнее поведение.

Воспроизводилось на схемах-приёмниках с одним DataSetObject
(например, ЖурналОшибок в ERP).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 16:38:57 +03:00
Nick Shirokov b3c2602439 docs(skd-compile): добавить пример DataSetObject
Внешний набор данных (objectName) был упомянут одной фразой в
type-dispatch summary, без примера. Добавлен компактный JSON-пример
+ короткое объяснение как объект подключается к
ПроцессорКомпоновкиДанных.Инициализировать.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 16:32:54 +03:00
Nick Shirokov 853313faed feat(skills): тихий -Path алиас для input-параметров
Добавлен Alias('Path') / "-Path" к основному файловому параметру
в *-info, *-validate, *-edit, *-decompile (24 навыка × PS+PY).
Не документируется — fallback на случай если модель напишет -Path
вместо -TemplatePath/-FormPath/-ObjectPath/-SubsystemPath/-RightsPath/
-ConfigPath/-ExtensionPath/-CIPath. Поведение строго аддитивное.

Регресс: 336/336 PS, 336/336 PY.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 16:17:30 +03:00
Nick Shirokov b7fbede819 fix(tests): починить pre-existing фейлы integration и skd-* snapshots
- build-config/build-epf: заменить runtime-тип FormDataStructure на корректный *Object.XXX
- platform-cfe/config/epf: form-compile принимает -OutputPath (путь до Form.xml), не -FormPath
- skd-edit/info/validate: перегенерированы snapshots после feat(skd-compile) denyIncompleteValues=true (3729b63)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 15:48:23 +03:00
Nick Shirokov bdc38caffa refactor(form-add): объединить с epf-add-form, удалить специфичный навык
form-add теперь покрывает и объекты конфигурации, и standalone EPF/ERF
source tree (тип определяется из корневого XML, маппинг типов уже был).

Изменения form-add scaffold:
- Module.bsl: пустые регионы вместо скелета процедуры ПриСозданииНаСервере
- Form.xml: убран <Events> (раньше привязывал OnCreateAtServer к процедуре)
- Form.xml: <SavedData>true</SavedData> теперь условный — ставится для
  Catalog/Document/etc (стандарт ERP, 99% форм), не ставится для
  DataProcessor/Report/External* (где у объекта нет состояния)

Это согласуется с workflow: form-compile перегенерирует Form.xml целиком,
поэтому привязки в scaffold могут стать orphan; пустые регионы +
без Events — корректная стартовая точка, которую form-edit/form-compile
наполняют атомарно.

Удалён навык epf-add-form (директория + тесты), вызовы заменены на
form-add в integration-тестах, в кейсах epf-validate/help-add, в
description epf-init/epf-bsp-init, в docs и README.

Перегенерированы snapshot'ы 5 навыков (form-add, form-compile,
form-edit, form-info, form-validate). Платформенная верификация в 1С 8.3.24
прошла для всех 9 кейсов form-add.

Bump form-add v1.3 → v1.4.
2026-04-25 15:26:54 +03:00
Nick Shirokov 2a86df1c98 refactor(skills): унифицировать стиль триггеров в description
Заменено «пользователь просит» → «нужно» в 12 навыках для согласования
с доминирующим стилем репозитория (cf-*, cfe-*, form-*, skd-*, mxl-*,
role-*, interface-*, subsystem-edit/info/validate уже используют «нужно»).

Дополнительно у db-list переформулирован триггер: вместо «"добавь базу"»
(что коллидирует с db-create) — «зарегистрировать базу в реестре»,
точнее отражает суть скилла (управление .v8-project.json).

Затронуто: db-create, db-dump-cf, db-dump-xml, db-list, db-load-cf,
db-load-git, db-load-xml, db-run, db-update, meta-compile, meta-remove,
subsystem-compile.
2026-04-25 13:35:44 +03:00
Nick Shirokov 2e1487fd17 feat(skills): добавить триггерные фразы в description 8 навыков
Навыки, у которых description содержал только «что делает» без условия
«когда использовать»: epf-init, erf-init, form-add, template-add, epf-add-form,
epf-bsp-init, epf-bsp-add-command, img-grid.

Добавлено второе предложение в стиле репозитория («Используй когда нужно …»).
Для epf-bsp-* уточнено назначение через ключевые термины БСП
(СведенияОВнешнейОбработке, «Дополнительные отчёты и обработки»).

Co-authored-by: Serg2000Mr <129394542+Serg2000Mr@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 13:29:20 +03:00
Nick Shirokov 3729b63b89 feat(skd-compile): @autoDates — дефолты use=Always + denyIncompleteValues=true
Производные &НачалоПериода/&КонецПериода требуют заполненный период,
поэтому сам параметр теперь по умолчанию получает use=Always и
denyIncompleteValues=true. В объектной форме явные значения перекрывают.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 12:24:22 +03:00
Nick Shirokov c3ec51e174 feat(template-add): автопоиск SrcDir по стандартным подпапкам
Если <SrcDir>/<ObjectName>.xml не найден — сканирует Reports,
DataProcessors, Documents, Catalogs и другие папки типа объектов.
При 1 совпадении расширяет SrcDir, при нескольких — ошибка со списком.
Попутно — уточнение описания SrcDir, обезличенный пример, флаг
-SetMainSKD в PS-стиле.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 11:51:07 +03:00
Nick Shirokov fb58a04700 feat(web-test): getFormState — полные reportSettings + chip-значения
На DCS-формах возвращались только настройки с явным чекбоксом «Использование» — остальные (всегда включённые) отбрасывались и пропадали из fields[]. Reference-поля с chip-контролом возвращали пустое value, потому что значение живёт в .chipsItem .chipsTitle, а не в input.value.

- DCS-группировка больше не требует наличия «Использование»; при его отсутствии setting.enabled = true (настройка всегда активна)
- При чтении input.value делается fallback на .chipsItem .chipsTitle в LABEL-родителе — через запятую, если значений несколько (первый элемент + «+N» при свёртке в UI)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:18:48 +03:00
Nick Shirokov a30b720c89 docs(skd-compile): SKILL.md — упростить описание @autoDates и dataParameters auto
Убрать XML-детали (useRestriction, xsi:type, <use>false</use>, <value xsi:nil>);
описывать поведение с точки зрения автора СКД, а не внутреннего представления.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:17:16 +03:00
Nick Shirokov 54d47aadad feat(skd-compile): dataParameters auto — копирование value всех типов (ЕРП-паттерн)
Раньше "auto" копировал только variant для StandardPeriod, остальные типы
теряли значение по умолчанию. Теперь:

- value задан (не-Custom для StandardPeriod) → value + use=true (implicit),
  правильный xsi:type: boolean/decimal/dateTime/string, DesignTimeValue для
  ссылочных типов.
- value отсутствует или StandardPeriod=Custom → <use>false</use>
  + <value xsi:nil="true"/>.

Соответствует тому, как 1С Designer и ЕРП-отчёты персистят
SettingsParameterValue. Тест auto-data-parameters расширен покрытием
decimal/string/ref/nil.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:13:04 +03:00
Nick Shirokov 3f23be8219 feat(skd-compile): @autoDates — НачалоПериода/КонецПериода вместо ДатаНачала/ДатаОкончания
Канонический паттерн БСП в Титан/ЕРП-отчётах использует имена
НачалоПериода/КонецПериода (~10:1 по частоте). Выражения
&Период.ДатаНачала/&Период.ДатаОкончания сохранены — это обращение
к внутренним полям StandardPeriod.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:51:22 +03:00
Nick Shirokov f5dd677ac8 fix(tests): cf-info/config-with-objects — preRun через meta-compile
Тест сломался с 0d5d345 (ужесточение cf-edit add-childObject: теперь требует, чтобы файл объекта существовал на диске). Там были пофикшены 4 теста cf-edit, но этот кейс cf-info с тем же паттерном в preRun пропустили.

Заменил cf-edit add-childObject на три meta-compile (Catalog.Товары, Document.Заказ, Enum.Статусы) — те сами регистрируют объекты в Configuration.xml и создают файлы. Snapshot перегенерирован.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:08:37 +03:00
Nick Shirokov 02e9053d00 feat(cf-validate,cfe-validate,epf-validate): поддержка платформы 8.5 (issue #13)
- `CompatibilityMode`, `ConfigurationExtensionCompatibilityMode`: добавлен `Version8_5_1`
- `InterfaceCompatibilityMode`: расширен до полного списка из 7 значений (Version8_2, Version8_2EnableTaxi, Taxi, TaxiEnableVersion8_2, TaxiEnableVersion8_5, Version8_5EnableTaxi, Version8_5) — заодно учтены недостающие 8.2-значения
- Принимается `version="2.21"` в заголовке MetaDataObject
- cf-edit/reference.md: обновлена таблица допустимых значений

Genrators (form-compile, form-add, cfe-borrow и др.) уже подхватывают версию формата через Detect-FormatVersion — не трогаем.

Closes #13

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:08:27 +03:00
Nick Shirokov bd462f4cc3 fix(web-test): hasVisibleModal — handle duplicate #modalSurface
1С оставляет стейл-элемент #modalSurface (display:none) после закрытия
формы и создаёт второй при открытии новой модалки — в DOM оказывается два
элемента с одинаковым id. getElementById возвращал первый (скрытый), из-за
чего detectForm/detectForms не видели активную модалку: getFormState
выдавал form+buttons от родительской формы, а clickElement кликал мимо
или падал.

Сканируем все #modalSurface через querySelectorAll и берём первый с
offsetWidth > 0.

Воспроизводилось стабильно на СКД-расшифровке после открытия "Настройки..."
в форме отчёта.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:24:44 +03:00
Nick Shirokov be74d224be feat(skd-compile): dataParameters auto — наследовать variant для StandardPeriod
Для параметров типа StandardPeriod в режиме "dataParameters": "auto" эмитируется <dcscor:value> с variant из дефолта параметра (Custom, если не задан) — как это делает 1C Designer при сохранении SettingsParameterValue для периодов.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:00:58 +03:00
Nick Shirokov 1b46eb4d85 feat(skd-compile): parameters — title и presentation как синонимы
- parameter принимает presentation как синоним title (1C UI показывает
  подпись параметра как "Представление" — модель по аналогии пишет presentation)
- availableValues[] принимает title как синоним presentation (обратная
  ошибка: модель пишет title по аналогии с самим параметром)

Обе формы пишутся в один и тот же XML-узел. Версии: skd-compile v1.13 → v1.14.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:37:00 +03:00
Nick Shirokov 1cea9e794e feat(skd-compile,skd-edit): calculatedFields — shorthand и объектные синонимы
- skd-compile v1.13: Parse-CalcShorthand теперь понимает "[Title]:type=expr#flags"
  (синхронно со skd-edit). Emit-CalcFields принимает name как синоним
  field/dataPath и строковую форму useRestriction ("#noField #noFilter ...").
- skd-edit v1.11: #restrict парсится по known-names pattern — исключает ложные
  срабатывания на # внутри строковых литералов в выражении.

Закрывает три ловушки из upload/bug-skd-compile-calculated-field-datapath.md,
где модель писала name вместо field и строковый useRestriction по аналогии
с shorthand-флагами.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:31:14 +03:00
Nick Shirokov 00fafd4af5 fix(web-test): scanSpreadsheetCells — use contentFrame() instead of index-based frame mapping
Replace fragile page.frames()[iframeIdx + 1] with handle.contentFrame() for
reliable iframe-to-Playwright-Frame resolution. The old index arithmetic could
break when 1C web client accumulates extra frames during prolonged sessions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 18:15:05 +03:00
Nick Shirokov e30b518935 feat(skd-info): auto-resolve object directory path to DCS template
When model passes report/dataprocessor path instead of template path,
scan Templates/*.xml metadata for DataCompositionSchema type and
auto-resolve. Single match → resolve with [i] hint, multiple → list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 17:23:56 +03:00
Nick Shirokov afdfc97fb1 fix(web-test): readSpreadsheet — поддержка text-only и отчётов с числовыми шапками
Рефакторинг buildSpreadsheetMapping на 3-уровневый алгоритм.
- Level 1: якорь по DCS-кодам (К1..Кn) — детерминированный для всех ФСД-отчётов, работает независимо от формата чисел (рубли/тыс/млн).
- Level 2: якорь по форматированным числам (пробел-группировка, запятая-десятичка, ведущий минус) вместо общей проверки — голые целые (коды счетов "50", "51") больше не принимаются за данные.
- Level 3: single-row header fallback для text-only данных и query-console.

Починено:
- ФСД-отчёты с числами в групповых шапках (ДДС по счетам 50/51/52/55/57) — был fallback raw rows, теперь структурированный вывод.
- query() из consoleЗапросов для text-only результатов — был data=[], теперь корректно парсит headers/data.

E2E проверено на titan: 4 отчёта (ДС, 45, 77, Ведомость) + 5 query-кейсов. Регрессий нет.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:38:47 +03:00
Nick Shirokov 82e70d2c30 feat(skd-compile,form-compile): Phase 3 — project-level presets
- skd-compile v1.12: scan-up from OutputPath for presets/skills/skd/skd-styles.json (PS1+PY)
- form-compile presets/README.md: full preset documentation (sections, keys, enums, example)
- docs/form-guide.md: --from-object mode + project-level presets sections
- skd-compile SKILL.md: updated styles search path description

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 11:08:22 +03:00
Nick Shirokov aedf6df674 fix(form-compile,meta-compile): PY ChartOfAccounts generators — list format + AccountingFlag name extraction
- form-compile.py: rewrite generate_chart_of_accounts_item_dsl and
  generate_chart_of_accounts_folder_dsl from dict-format to list-format
  (array of OrderedDict), matching PS1 canonical output
- meta-compile.py/ps1: extract flag['name'] from AccountingFlags and
  ExtDimensionAccountingFlags dicts instead of stringifying the whole object
- Update snapshots with clean flag names (Валютный/Количественный)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:55:33 +03:00
Nick Shirokov 0d31d17204 fix(form-compile): PY register list generators — array format for columns/elements
Fixed IR List and AccumReg List PY generators:
- columns: OrderedDict → list of OrderedDict (matching PS1 array format)
- table element: use 'table' key (not 'element'), 'tableAutofill' (not 'autoCommandBar'), 'None' (not 'none')
- elements: list (not OrderedDict wrapper)

PY tests: 10/12 (2 remaining CoA failures — PY CoA Item generator needs deeper rewrite from dict to list format)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:17:23 +03:00
Nick Shirokov 2206c4cf3e fix(form-compile): convert new generators from dict to array DSL format
Root cause: new generators (IR, AccumReg, CoA, CCOCT/EP wrappers) used
OrderedDict for elements/columns, but PS1 compiler expects array format.
ConvertTo-Json→ConvertFrom-Json wraps dict into single PSCustomObject,
not iterable array — so ChildItems were empty.

Converted all new generators to array format matching existing
Document/Catalog patterns: elements=@(), columns=@().

Also fixed CCOCT/EP wrapper inject logic to iterate array elements
instead of dict keys.

PS1: 12/12, PY: 8/12 (minor case/autofill differences in PY port).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:11:55 +03:00
Nick Shirokov 8a9f285da9 fix(form-compile): port bugfixes to Python — Number/Date in lists, UserVisible for Ref
Port PS1 bugfixes to Python:
- Document List: add Номер + Дата as first columns
- Hidden Ref: userVisible=false instead of visible=false (both Catalog and Document lists)
- Emitter: support <UserVisible><xr:Common>false</xr:Common></UserVisible>
- Add userVisible to KNOWN_KEYS

Note: new_field_element calls in Python were already correct (no Bug 1 equivalent).
Python snapshots updated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:55:56 +03:00
Nick Shirokov e5e3f199f2 fix(form-compile): empty forms, missing Number/Date in lists, UserVisible for Ref
Three bugs fixed in --from-object PS1 generators:

1. New-FieldElement called with wrong positional args in IR Record and CoA Item
   generators — hashtable passed as attrName instead of individual fields.
   Result: elements became "System.Collections.Hashtable" → compiler dropped them
   → empty forms. Fixed with named parameters.

2. Document List form missing Number/Date standard columns — only custom
   attributes were shown. Added Номер + Дата as first two columns.

3. Hidden Ref column used Visible=false (element completely hidden from
   "Customize form"). Changed to UserVisible=false so users can enable Ref
   and add sub-columns via dot notation. Matches ERP Контрагенты pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:34:45 +03:00
Nick Shirokov 3ee715939b test(form-compile): regression tests for new --from-object types
8 test cases covering InformationRegister (Record periodic/nonperiodic, List),
AccumulationRegister (List), ChartOfCharacteristicTypes (Item),
ExchangePlan (Item), ChartOfAccounts (Item, List).

All 12 tests pass on both PS1 and Python runtimes with form-validate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:46 +03:00
Nick Shirokov b8ab791456 feat(form-compile): add --from-object support for 5 new object types
Add InformationRegister (Record/List), AccumulationRegister (List),
ChartOfCharacteristicTypes (Item/Folder/List/Choice via Catalog delegation),
ExchangePlan (Item/List/Choice via Catalog delegation),
ChartOfAccounts (Item/Folder/List/Choice with AccountingFlags + ExtDimensionTypes).

Generalize extractAttrs → extractFields with tag parameter.
Add preset defaults and erp-standard.json keys for all new types.
Bump version to v1.6 in both PS1 and PY.

Also: form-add now supports AccumulationRegister (PS1+PY).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:30 +03:00
Nick Shirokov 97a2ef91d5 fix(form-compile): skip ValueStorage attributes in --from-object mode
ValueStorage is a non-displayable type that cannot be bound to form
elements. Filter it out in all generators: catalog item, catalog/document
list columns, document item (unclaimed + footer).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:02:31 +03:00
Nick Shirokov a41897a966 test(form-compile): regression tests for --from-object mode
4 snapshot tests: catalog item/list (Валюты-like) + document item/list
(АктВВР-like). Verified against platform 1C 8.3.24. Register
form-compile-from-object in verify-snapshots DEFAULT_SKILLS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:40:12 +03:00
Nick Shirokov 076bbcb9d5 feat(form-compile): add --from-object mode for auto form generation from metadata
Read 1C object XML (Document/Catalog), apply ERP preset, generate Form.xml
automatically. Supports Item/List/Choice/Folder purposes with auto-resolve
of object path and purpose from OutputPath convention. Also extends DSL
with DynamicList Settings, Table choiceMode/initialTreeView/enableDrag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:03:34 +03:00
Nick Shirokov 3c48451704 docs(meta-compile): add new Catalog props and multiline flag to specs
Update meta-dsl-spec.md and types-basic.md reference with:
limitLevelCount, levelCount, foldersOnTop, codeSeries,
subordinationUse, quickChoice, choiceMode, multiline flag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:00:04 +03:00
Nick Shirokov 801ceea2c0 feat(meta-compile): configurable Catalog props, owners, multiLine, fix reservedAttrNames
- Catalog: limitLevelCount, levelCount, foldersOnTop, subordinationUse,
  codeSeries, quickChoice, choiceMode now read from JSON (were hardcoded)
- Catalog owners: new `owners` array property with shorthand normalization
- Attribute MultiLine: configurable via `multiLine: true` or `| multiline` flag
- reservedAttrNames warning: now skipped for tabular/processor-tabular context
- 3 new enum validations: SubordinationUse, CodeSeries, ChoiceMode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 14:54:50 +03:00
Nick Shirokov 63de8bd27c fix(meta-compile,meta-edit,meta-validate): strict enum validation + fix RequireCalculationTypes
Normalize-EnumValue now uses 4-step logic: alias→case-insensitive→
error (if propName known)→pass-through (if unknown). Previously step 3
silently passed invalid values through to XML, causing cryptic 1C
LoadConfigFromFiles errors.

Also fixed RequireCalculationTypes→OnActionPeriod (the former never
existed in 1C; verified against ERP/ACC dumps). Added NotUsed→DontUse
alias, synced meta-edit.ps1 aliases with meta-compile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 12:29:46 +03:00
Nick Shirokov d1e770c843 test(form-edit): declare Поле1 in preRun form-compile attributes
add-element and add-group-with-fields built their baseline form with an
InputField whose DataPath pointed to "Поле1", but "Поле1" was never
declared as a form attribute. runner.mjs snapshot diffing accepted the
output, but verify-snapshots caught the real XDTO error at load time:
"Неверный путь к данным: Поле1".

Add the missing attribute to both preRun form-compile inputs and
regenerate snapshots (the new attribute takes id=5, so form-edit's added
"Поле2" now lands at id=6).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:03:34 +03:00
Nick Shirokov e3069ceb36 fix(form-compile): throw on known invalid attribute types
KNOWN_INVALID_TYPES (FormDataStructure, FormDataCollection, FormDataTree,
etc.) was checked but only produced a Write-Warning/print warning — the
script still emitted the bad <v8:Type> into Form.xml, which XDTO later
rejected with a cryptic load-time error. Turn the warning into a hard
throw so misuse is caught at compile time with the correct hint.

Reveals two broken test cases that shipped invalid forms:
- form-compile/catalog-form: main attribute was FormDataStructure, fixed
  to CatalogObject.Товары (what ERP's reference catalog forms actually
  use with the cfg: prefix).
- form-info/overview: preRun form-compile used the same wrong type, fixed
  the same way; snapshot regenerated.

Bumps form-compile to v1.4 on both runtimes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:03:24 +03:00
Nick Shirokov 0b2c09f8d9 fix(verify-snapshots): support case fixture setup and workDir cwd
Two harness gaps that masked real issues and leaked stray files:

1. Case-level `setup: "fixture:<name>"` was ignored — runner.mjs handled
   it, verify-snapshots did not. skd-edit/add-drilldown silently failed
   with "File not found: Template.xml" because the fixture never reached
   workDir. Added Step 0 fixture copy mirroring runner.mjs behavior.

2. `skillConfig.cwd === "workDir"` was ignored — main skill always ran
   with cwd=REPO_ROOT. mxl-compile cases pass relative -OutputPath
   "Template.xml", which landed in the repo root on every run. Plumb cwd
   through execSkill and set mainCwd from skillConfig.cwd.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:03:11 +03:00
Nick Shirokov 0d5d3451ff fix(cf-edit): reject add-childObject when object file is missing
cf-edit add-childObject was a low-level XML-manipulation operation
with no file-existence validation — callers could register a reference
to any Type.Name in Configuration.xml's ChildObjects without the
underlying file existing on disk. Platform then refused to load:
"Файл объекта не существует".

The 4 failing tests (add-objects, remove-object, add-default-role,
set-default-roles) all used this operation with fake references in
either main input or preRun, and had no way to pass verify-snapshots
because the cf-init-ed config had no actual object files.

User observation: this is the tests being wrong, not the skill.
meta-compile/role-compile/subsystem-compile already auto-register
every new object in Configuration.xml as part of their normal flow
(meta-compile.ps1:2949-3068, role-compile.ps1:667-747,
subsystem-compile.ps1:430-506). Nobody should be calling cf-edit
add-childObject to create a new object — they should be calling the
profile skill. cf-edit add-childObject is only for rare recovery
scenarios: rolled-back Configuration.xml with intact object files,
re-import from DB dump that clobbered the root but left srcfiles.

Changes:

1. cf-edit.ps1/py: Do-AddChildObject now checks that the target file
   exists at {ConfigDir}/{PluralDir}/{Name}.xml before registering.
   On miss, exits 1 with a message that names the expected path and
   points the user at the right skill (/meta-compile, /role-compile,
   or /subsystem-compile depending on type). TYPE_TO_DIR mapping for
   all 44 metadata types covers irregular plurals (FilterCriteria,
   BusinessProcesses, ChartsOfAccounts, ChartsOfCharacteristicTypes,
   ChartsOfCalculationTypes).

2. Tests: 4 existing cases rewritten to build realistic fixtures via
   meta-compile/role-compile preRun (both skills auto-register, so
   the resulting Configuration.xml already references the preRun
   objects). add-objects now exercises the round-trip recovery
   scenario: meta-compile creates Catalog.Товары and Document.ПриходТоваров
   (auto-registered) → cf-edit remove-childObject un-registers both
   (files remain) → main run re-registers via add-childObject. This
   tests exactly the rollback-recovery use case the operation exists for.

3. New add-missing-errors case: negative test with expectError:
   "Object file not found". Verifies the new hard-error path.

4. verify-snapshots.mjs: added symmetric expectError handling (runner.mjs
   already had it at line 514). If caseData.expectError is set,
   expect skill to fail; check stderr substring match; skip db-load
   and mark passed. Without this, negative tests would go red in
   verify-snapshots even though runner.mjs accepts them.

5. SKILL.md / reference.md: documented the new constraint and the
   redirection to profile skills. Kept mention of legitimate use case
   (rollback recovery).

Bumped cf-edit.ps1/py v1.0→v1.1.

Verification:
- runner --filter cf-edit (PS1): 2/6 → 7/7 (6 positive + 1 negative)
- runner --filter cf-edit --runtime python: 7/7 (dual-port clean)
- verify-snapshots --skill cf-edit: 2/6 → 7/7

With this landed P3 from debug/snapshot-verify/NEXT-STEPS.md is closed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:18:05 +03:00
Nick Shirokov 7a8f437e77 test(subsystem-compile): cover bottom-up -Parent flow; hide children shortcut
The bottom-up flow (compile child with -Parent pointing at parent's
XML — skill creates the real child file AND registers it in parent's
ChildObjects) has been the documented canonical way to build nested
subsystems since forever. It's in SKILL.md Примеры:58 and implemented
in subsystem-compile.ps1:430-506. But zero test cases exercised it —
all 7 pre-existing cases used the top-down `children: [...]` shortcut
that aa93031 made honest with stubs.

Two problems with the status quo:

1. A model reading SKILL.md saw `"children": ["ДочерняяА", "ДочерняяБ"]`
   right in the main JSON-definition example and took it as the
   canonical way to create nested structure. It's a trap — the
   shortcut creates placeholder stubs with empty Synonym/Content that
   the model almost never actually wants. The natural flow (one
   subsystem-compile call per real subsystem) wasn't visible where
   the model looks first.

2. The canonical flow had no test safety net — nothing caught regressions
   in the register-in-parent code path (lines 430-506).

Fix, minimal surface:

- SKILL.md: remove `"children": [...]` from the JSON-definition example.
  Leave the `-Parent` example in the Примеры section (already there).
  The children field stays fully supported in the scripts (aa93031 stub
  behavior unchanged) for legacy JSON — just not advertised.

- New test case `nested-parent.json`: preRun compiles "Продажи" parent,
  main run compiles "Настройки" child with `-Parent Subsystems/Продажи.xml`.
  Verifies the real bottom-up flow: snapshot shows full child file with
  real Synonym/Explanation AND parent's `<ChildObjects>` updated to
  reference the child. verify-snapshots confirms platform accepts it.

- Runner plumbing: `_skill.json` gains `{ "flag": "-Parent", "from":
  "workPath", "field": "parent", "optional": true }`. Required extending
  both `tests/skills/runner.mjs` and `tests/skills/verify-snapshots.mjs`
  (they each have their own copy of buildArgs) to support `optional: true`
  on workPath mappings — otherwise existing cases without params.parent
  would get the flag pushed with an empty value.

Verification:
- runner --filter subsystem-compile (PS1): 8/8 (was 7/7 +1)
- runner --filter subsystem-compile --runtime python: 8/8 (dual-port clean)
- verify-snapshots --skill subsystem-compile: 8/8

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:15:07 +03:00
Nick Shirokov dc4ffa1fc8 fix(form-compile): interpolate \$script:formatVersion in <Form> header
Third victim of the d155086 single-quote regression that 037062c
missed. Both <Form> header emissions at lines 1130 and 1140 used
`X '...version="$($script:formatVersion)"...'` — single-quoted, so
the literal text `$($script:formatVersion)` landed in the output
XML instead of the detected version number.

The bug was masked for a week because:
1. form-compile runner tests weren't rerun against the broken script
   after d155086 (snapshots still showed the pre-regression
   `version="2.17"` hardcode)
2. verify-snapshots was already red on form-compile for other reasons
   (P2 XDTO errors in some cases), so nobody noticed the wholesale
   script breakage
3. The .py port uses an f-string and was never broken

Found while auditing whether 037062c was complete — the earlier grep
for `'...\$formatVersion...'` single-line patterns had missed this
because `$($script:formatVersion)` is a subexpression-in-string form
that wasn't in the grep pattern.

Fix: convert both X calls to double-quoted strings with backtick-
escaped inner quotes, matching the 037062c pattern for
role-compile/subsystem-compile. Same approach, same precedent.

Bumped form-compile.ps1 v1.2→v1.3.

Verification:
- runner --filter form-compile (PS1): 0/10 → 10/10
- runner --filter form-compile --runtime python: 10/10 (dual-port clean)
- verify-snapshots --skill form-compile: surfaced from fully-masked
  to 9/10 (only catalog-form still fails — real P2 XDTO issue, not
  \$formatVersion)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:59:26 +03:00
Nick Shirokov 6805b9da02 fix(subsystem-edit): write stub XML on add-child operation
Do-AddChild / do_add_child added `<Subsystem>Name</Subsystem>` to the
parent's `<ChildObjects>`, but never wrote the corresponding
`Subsystems/{Parent}/Subsystems/{Name}.xml` file. Same silent-drop
pattern that bit subsystem-compile (aa93031): platform used to swallow
the missing-file reference, `-StrictLog` now surfaces it as "Файл
объекта не существует" and fails add-child on load.

Both ports now mirror the subsystem-compile fix:
- Write-ChildSubsystemStub / write_child_subsystem_stub helpers
  duplicated from subsystem-compile (per memory rule "skills are
  autonomous, duplication acceptable")
- format_version read from loaded XmlDoc root (no need to walk up
  to Configuration.xml — we already have the parent XML in memory)
- Stub creation guarded by Test-Path / os.path.exists so a pre-existing
  real child file is never clobbered

Bumped subsystem-edit.ps1 v1.1→v1.2 and subsystem-edit.py v1.1→v1.2.

Verification:
- verify-snapshots --skill subsystem-edit: 3/4 → 4/4
- runner --filter subsystem-edit (PS1): 4/4
- runner --filter subsystem-edit --runtime python: 4/4 (dual-port drift clean)

With this landed P1 from debug/snapshot-verify/NEXT-STEPS.md is fully
closed: subsystem-compile 7/7, subsystem-edit 4/4, interface-edit 4/4,
role-compile 8/8, meta-compile 30/30.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:49:40 +03:00
Nick Shirokov aa93031a3f fix(subsystem-compile): write stub XML for declared children
When a subsystem definition includes `children: [...]`, the parent XML
was emitted with `<ChildObjects><Subsystem>Name</Subsystem></ChildObjects>`
refs, but the referenced `Subsystems/{Parent}/Subsystems/{Child}.xml`
files were never created. Before 96d1dea (-StrictLog) the platform
silently dropped the refs on load (exit 0), so verify-snapshots showed
these cases green. With the new strict log parsing, `full` and
`with-children` started failing on "Файл объекта не существует".

Both PS1 and PY ports now emit a minimal valid child subsystem stub
(full MetaDataObject, empty Synonym/Content/ChildObjects) via new
Write-ChildSubsystemStub / write_child_subsystem_stub helpers. Stub
creation is guarded by Test-Path / os.path.exists, so a subsequent
compile of the same child via -Parent does not get clobbered, and
re-running the parent compile is idempotent. Дубли в children[]
дедуплицируются через seen-set.

Also removed the "Что генерируется" section from SKILL.md — filesystem
layout is covered by the OutputDir param + [OK] stdout lines; the
section was noise for model consumers.

Bumped subsystem-compile.ps1 v1.4→v1.5 and subsystem-compile.py
v1.3→v1.5 (PY caught up with PS1 version pin).

Verification:
- verify-snapshots --skill subsystem-compile: 5/7 → 7/7
- runner --filter subsystem-compile (PS1): 7/7
- runner --filter subsystem-compile --runtime python: 7/7 (dual-port drift clean)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:38:03 +03:00
Nick Shirokov 037062c728 fix(role-compile,subsystem-compile): interpolate \$formatVersion in XML output
Regression introduced by d155086 (auto-detect XML format version):
both scripts emit their root MetaDataObject element via X '...' with
single-quoted strings, which PowerShell does NOT interpolate. As a
result the literal text \$formatVersion landed in the generated XML,
and every load failed with "Неизвестная версия формата \$formatVersion".

This was masked for a week because the broken call sites aren't
version-dependent by themselves — the platform exits with code 1 on
this error, but verify-snapshots hadn't been re-run cleanly since
the offending commit (we only did a scoped role-compile smoke test
that happened to pass for unrelated reasons).

Fixed by switching both single-quoted X '...' calls to double-quoted
X "..." with escaped inner quotes. meta-compile / form-compile /
epf-add-form / help-add / template-add / interface-edit already used
here-strings or \$script:formatVersion with double-quoted wrappers
and were unaffected.

Bumped role-compile.ps1 to v1.5 and subsystem-compile.ps1 to v1.4.
verify-snapshots --skill role-compile now 8/8 green. subsystem-compile
re-verification is pending other unrelated fixes (see NEXT-STEPS.md).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:01:00 +03:00
Nick Shirokov 9cbda1989a test(meta-compile/document-journal): preRun creates documents with referenced attributes
Journal column references require the referenced document attribute to
actually exist at load time. Previously the test DSL relied on the
verify-snapshots stub mechanism, which creates minimal Document stubs
without the specific attributes the column refs point to → load failed
with "Неизвестный объект метаданных - Document.ПриходнаяНакладная.Attribute.Склад".
This was listed as D5 in the 2026-04-05 FINDINGS log ("low priority,
complex to implement").

Now the test case declares preRun steps that create both documents
with the exact attributes its journal columns reference (Склад on one,
Контрагент on both). Column "Контрагент" gained explicit references
(was a shorthand string before) because the platform rejects journal
columns without at least one reference at load time.

Regenerated the snapshot (gained Documents/ subtree from preRun output).
verify-snapshots --skill meta-compile is now 30/30 green with -StrictLog.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:00:34 +03:00
Nick Shirokov d34ddd41ff fix(meta-compile): strip FillFrom/FillValue/DataHistory for non-Info register attributes
Custom attributes on AccumulationRegister, AccountingRegister and
CalculationRegister do NOT support FillFromFillingValue, FillValue or
DataHistory — platform logs "Неверное свойство объекта метаданных" and
silently drops them. InformationRegister DOES support these properties
(verified against erp_8.3.24 dump for both variants).

Split the single "register" Emit-Attribute context into:
  - register-info  → emits the three properties (InformationRegister)
  - register-other → skips them (Accum/Acc/Calc)

Chart* context already handled by 3ba6072 remains as-is. Extended the
exclusion list in Emit-Attribute to cover register-other symmetrically
for FillFromFillingValue, FillValue and DataHistory.

Updated snapshots:
  - accounting-register: removed the 3 bad lines on Содержание attribute
  - accumulation-register/calculation-register: added test attributes
    to exercise the register-other path and regenerate snapshots cleanly

Closes the silent-rejection class #4 from upload/form-baseline/gotchas.md,
now caught by verify-snapshots -StrictLog on the E2E platform load.

Bumped meta-compile.ps1 + .py to v1.8.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:00:12 +03:00
Nick Shirokov 96d1dea552 fix(db-load-xml): surface silent platform rejections + opt-in -StrictLog
Platform writes load-time property/type/enum rejections ("Неверное
свойство объекта метаданных", "Неизвестное имя типа" и т.п.) into the
/Out log but still exits with code 0, silently dropping the offending
metadata. db-load-xml now parses the log for these patterns and prints
a yellow "[warning] N rejection(s)" block to stdout so users (and the
model) can see them immediately.

Exit code still mirrors the platform by default — we don't second-guess
its verdict. With the new -StrictLog switch, rejection patterns are
elevated to exit code 1, which is the mode verify-snapshots.mjs uses
for honest E2E verdicts. All three db-load-xml call sites in the
verifier (main config, CFE base, CFE extension) now pass -StrictLog.

Found while investigating upload/form-baseline/gotchas.md #4 where AR
attribute emission was wrong but verify-snapshots showed green because
the old exit-code-only check missed the silent drops.

Bumped db-load-xml.ps1 + .py to v1.3.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:59:50 +03:00
Nick Shirokov 83b289de32 feat(skd): canonical @autoDates pattern + new params operations + use preservation
Fix-pack from skills-improvements-v4 feedback addressing 6 issues found
during real-world ФСД report development.

skd-compile (v1.10 → v1.11):
- @autoDates: emit canonical БСП pattern for ДатаНачала/ДатаОкончания —
  with title, useRestriction=true, value 0001-01-01T00:00:00, expression.
  Removed availableAsField=false so БСП creates two separate Start/End
  fields in the quick settings panel (was rendering as a single picker).
- StandardPeriod value: always emit v8:startDate/v8:endDate to match how
  1C Designer saves the schema (avoids spurious diff on first re-save).
- parameter shorthand: support [Title] syntax mirroring add-field.

skd-edit (v1.9 → v1.10):
- modify-filter / modify-dataParameter: preserve <use> when @off/@on not
  explicitly set (was silently stripping <use>false</use>). Tristate
  parser: None=don't touch, False=@off, True=@on.
- modify-parameter: support [Title] for setting/replacing <title>.
- rename-parameter: new operation "OldName => NewName" — atomically
  renames parameter, updates &Name references in expressions of other
  parameters (full identifier match only), and dcscor:parameter entries
  in dataParameters of all variants. Query text is not touched.
- reorder-parameters: new operation "Name1, Name2, ..." — partial list,
  named params go first in given order, rest preserve original order.
- StandardPeriod value: same v8:startDate/v8:endDate fix as compile.

Tests: 4 new test cases (rename-parameter, reorder-parameters,
modify-parameter-title, modify-dataParameter-preserves-use).
48/48 passing on both PowerShell and Python runtimes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:22:40 +03:00
Nick Shirokov 384e68cab4 fix(skd-compile): object-form structure, OrGroup string items, useRestriction alias
- Default structure item type to 'group' when omitted; accept groupFields as alias for groupBy
- Parse string shorthand items inside OrGroup/AndGroup/NotGroup filter recursion
- Accept useRestriction key (object form { field: true }) alongside restrict array
- Deduplicate SelectedItemAuto in skd-edit add-selection
- Update SKILL.md with object structure and useRestriction docs
- Add test cases for all 4 fixes

skd-compile v1.9→v1.10, skd-edit v1.8→v1.9

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:54:38 +03:00
Nick Shirokov 46e065adb9 feat(skd-edit): add-drilldown operation for connecting DrillDown to DCS template resources
Adds DetailsAreaTemplateParameter + Расшифровка appearance binding
to all named templates for each specified resource. Comma-separated
value list, idempotent, nesting-aware template scan.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:36:50 +03:00
Nick Shirokov fdfe4ac2f4 fix(skd-edit): parse #restriction flags in add-calculated-field shorthand
Previously #noFilter/#noOrder/#noGroup flags were included verbatim in
<expression> instead of generating <useRestriction>. Now parsed and
handled identically to add-field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:34:55 +03:00
Nick Shirokov afacaa5ade fix(web-test): readSpreadsheet header detection for DCS reports with account codes
- Strict isNumericVal check excludes account codes like "68/78" from being
  treated as data values (require pure digits+spaces+commas)
- Require >=2 numeric cells to identify data rows (fallback to >=1)
- Detect DCS column code rows (К1..Кn) and always prefix with group/superRow
- 3-level header support: superRow values used as prefix when group is empty
- superRow excluded from title/meta section
- Fuzzy column matching in clickElement for short codes ("К6" → "84 / К6")
- Replace newlines with spaces in cell text (innerText instead of textContent)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:25:37 +03:00
Nick Shirokov 73242ee60e fix(skd-compile): identity totalField shorthand treated as aggregation function
When totalField shorthand right-hand side is not a known aggregate function
(e.g. "Проверка: Проверка"), emit expression as-is instead of wrapping it
as Проверка(Проверка). Known aggregates (Сумма, Количество, etc.) still wrap.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 17:33:36 +03:00
Nick Shirokov e2924c4ae0 fix(skd-compile): remove spurious vMerge flag from source cells in template DSL
The vertical merge flag (ОбъединятьПоВертикали) was incorrectly placed on
both the source cell (with content) and continuation cells ("|"). 1C only
expects it on continuation cells. Removed startsVMerge logic from both
PS1 and PY scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:49:56 +03:00
Nick Shirokov 123fc41b06 fix(web-test): selection form search order and type dialog fast path
pickFromSelectionForm: swap steps 2↔3 — try Alt+F advanced search
before search input to avoid overlay blocking row clicks.
pickFromTypeDialog: scan visible rows first, fall back to Ctrl+F
only for large virtual lists. Reduces 3s hardcoded wait to ~0.2s
for common case. scanGridRows: add isGroup flag via gridListH check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:43:44 +03:00
Nick Shirokov 338faa253d feat(web-test): multi-row grid support in readTable — split merged headers
readTable now handles multi-row grids (e.g. accounting journal entries)
where a single column header spans multiple data sub-rows:
- "Субконто Дт" with 3 data cells → "Субконто Дт 1", "Субконто Дт 2", "Субконто Дт 3"
- Stacked headers (2+ at same X) matched by Y-order (e.g. "Счет Дт" / "Подразделение Дт")
- getFormState tables[].columns also expanded for consistency
- Flat/simple grids unaffected (no multi-row detection triggers)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:41:58 +03:00
Nick Shirokov d3520a8945 fix(skd-edit): modify-parameter availableValue parsing and formatting bugs
Fix 3 bugs in modify-parameter: (1) first availableValue rendered as raw
text when combined with other kv pairs in same batch entry, (2) presentation
values with spaces truncated by \S+ regex, (3) denyIncompleteValues/use
inserted without line breaks. Root cause: if/else on rest.startsWith
missed availableValue when preceded by other keys. Also fix namespace-aware
element lookup using LocalName/local_name instead of SelectSingleNode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 21:34:04 +03:00
Nick Shirokov e731bde7f0 feat(skd-compile): horizontal cell merge ">" in template DSL
Add ">" cell syntax for horizontal merge (ОбъединятьПоГоризонтали),
analogous to "|" for vertical merge. Enables two-level headers with
colspan in DCS templates. Also fix PY decimal formatting (30.0 → 30).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 20:41:47 +03:00
Nick Shirokov 321e426f98 docs(skd): update dsl-spec and guide for new features, fix py compat
- skd-dsl-spec: availableValues/denyIncompleteValues, Folder in selection, DesignTimeValue/OrGroup in filters, Format as LocalStringType
- skd-guide: mention new CA types, Folder, availableValues
- Fix Python 3.13: inline regex flags, element truth-testing, OrGroup desc, dict structure wrap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:53:04 +03:00
Nick Shirokov 54c04cfe76 fix(skd): Python 3.13 compatibility fixes
- skd-edit.py: fix (?i) inline regex flag → re.IGNORECASE (Python 3.13 error)
- skd-edit.py: fix "if not sv" on XML element → "sv is None" (FutureWarning)
- skd-edit.py: fix OrGroup filter crash in output description (list vs dict)
- skd-compile.py: wrap dict structure in list before iteration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:48:35 +03:00
Nick Shirokov 9727635e5d test(skd): add snapshot tests for new features
- skd-edit: conditionalAppearance with DesignTimeValue/OrGroup/Format
- skd-edit: modify-parameter with use/denyIncompleteValues/availableValue
- skd-edit: set-structure @name= + add-selection Folder() @group=
- skd-compile: availableValues/denyIncompleteValues + Folder in selection
- Fix xsi namespace in @group= XPath query

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:42:12 +03:00
Nick Shirokov 6404016afb feat(skd-edit): add-selection @group= targets named StructureItemGroup
- add-selection supports @group=Name to add selection items to a named grouping instead of variant level
- Finds StructureItemGroup by dcsset:name, falls back to variant level if not found
- Document @group= in SKILL.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:35:07 +03:00
Nick Shirokov 17afd807d2 docs(skd): update SKILL.md for new features
- skd-edit: document modify-parameter, Folder() in selection, @name= in structure, OrGroup/DesignTimeValue/Format in conditionalAppearance
- skd-compile: document availableValues/denyIncompleteValues, Folder in selection, OrGroup, DesignTimeValue, Format as LocalStringType

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:32:14 +03:00
Nick Shirokov 9bfc431a6a feat(skd): @name= in set-structure, Folder in selection
- skd-edit: set-structure supports @name= for naming groupings (e.g. "Поле @name=ДанныеОтчета > details")
- skd-edit: add-selection supports Folder(Title: field1, field2) syntax for SelectedItemFolder
- skd-compile: selection supports {"folder": "Title", "items": [...]} for SelectedItemFolder
- Both generate lwsTitle, nested SelectedItemField items, and placement=Auto

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:23:18 +03:00
Nick Shirokov d755c41233 feat(skd): modify-parameter operation, availableValues/denyIncompleteValues support
- skd-edit: new modify-parameter operation — set use, denyIncompleteValues, add availableValue entries to existing parameters
- skd-compile: availableValues array and denyIncompleteValues in parameter JSON DSL
- Auto-detect DesignTimeValue type for reference values in availableValue entries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:19:32 +03:00
Nick Shirokov 87e636f644 feat(skd): DesignTimeValue in filters, Format as LocalStringType, OrGroup in conditionalAppearance
- Auto-detect DesignTimeValue type for enum/catalog/chart-of-accounts references in filter values (both skd-edit and skd-compile)
- Treat Формат appearance parameter as v8:LocalStringType (alongside Текст/Заголовок)
- Support OrGroup in conditionalAppearance filters via " or " syntax in skd-edit shorthand
- Bump skd-edit v1.5, skd-compile v1.6

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:15:44 +03:00
Nick Shirokov ae1dcaac07 feat(web-test): detect SpreadsheetDocument state bar (stateText)
Extract info bar messages from .stateWindowSupportSurface elements
into errors.stateText — covers missing parameters, "report not
generated", "settings changed", and "generating..." states.
readSpreadsheet() now includes the state message in its error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 16:27:24 +03:00
Nick Shirokov d155086444 feat(skills): auto-detect XML format version from Configuration.xml
When working with existing configs dumped from newer platforms (8.3.27+),
XML files use version="2.20" instead of "2.17". Skills now detect the
version from the nearest Configuration.xml walking up the directory tree,
falling back to "2.17" if not found. This prevents format version mismatch
errors during LoadConfigFromFiles.

Updated skills (11): meta-compile, form-compile, form-add, template-add,
cfe-borrow, epf-add-form, help-add, role-compile, subsystem-compile,
interface-edit. Also fixed form-validate to accept version 2.20.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:41:53 +03:00
Nick Shirokov 940eafb8e4 fix(skd-edit): patch-query with empty replacement (delete substring)
.strip()/.Trim() in batch-splitting was stripping the trailing space
of the " => " separator, making " => " (delete) unrecognizable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:02:22 +03:00
Nick Shirokov e4dcef8c90 fix(skd-compile): DesignTimeValue, useRestriction for hidden, named structure groups
- fix: auto-detect DesignTimeValue for ПланСчетов/Справочник/Перечисление/Документ values (#9)
- fix: hidden params auto-set useRestriction=true alongside availableAsField=false (#11)
- feat: named groups in structure shorthand "ИмяГруппы[Поле] > details" (#10)
- version bump: skd-compile v1.5

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:44:14 +03:00
Nick Shirokov 08688f5cab docs(skd): update specs for hidden, valueListAllowed, drilldown, groupHeaderTemplate
- skd-dsl-spec: @valueList, @hidden, field alias, dataParameters auto, drilldown, groupName/GroupHeader
- skd-guide: new parameter flags, dataParameters auto, groupName, drilldown
- 1c-dcs-spec: valueListAllowed element, DetailsAreaTemplateParameter, groupHeaderTemplate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:36:04 +03:00
Nick Shirokov 1bc5e8f07a feat(skd-compile): hidden, valueListAllowed, drilldown, groupHeaderTemplate, dataPath fix
- fix: calculatedField dataPath fallback from "field" key (#5)
- fix: groupHeaderTemplate vs groupTemplate, groupName support (#7)
- feat: @valueList / valueListAllowed for parameters (#4)
- feat: @hidden / hidden params + "dataParameters": "auto" (#1)
- feat: drilldown in template params — DetailsAreaTemplateParameter + appearance (#2+#3)
- fix(template-add): improved error message with path hint (#6)
- docs: SKILL.md updated with new keys and examples
- version bump: skd-compile v1.4, template-add v1.2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:17:33 +03:00
Nick Shirokov 358830c65b feat(meta-validate): Check 10 — warn on empty registers and broken RegisterRecords refs
Add two new validations found via platform snapshot verification:
- Registers without any Dimensions/Resources/Attributes → platform rejects
- Document.RegisterRecords referencing non-existent register objects

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:27:18 +03:00
Nick Shirokov 3ba6072660 fix(meta-compile): strip FillFromFillingValue/FillValue/DataHistory for Chart* attributes
ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes
attributes don't support FillFromFillingValue, FillValue, DataHistory
properties — platform rejects them with "Неверное свойство объекта
метаданных". Add "chart" context to Emit-Attribute to skip these.

Found via platform snapshot verification (Finding A1).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:11:47 +03:00
Nick Shirokov 20adf4f463 fix(tests): correct ExternalDataProcessorObject→DataProcessorObject in config-context DSLs
Fix test DSLs that used ExternalDataProcessorObject (EPF type) for
DataProcessors inside configurations. Also fix: chart-of-accounts
(remove maxExtDimensionCount without ПВХТ), calculation-register
(remove actionPeriod without infrastructure), document-multiple-tabparts
(remove registerRecords referencing non-existent register),
role-compile/explicit-rights (add dimensions to empty InformationRegister).

Regenerated all affected snapshots.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:10:49 +03:00
Nick Shirokov d5aacc9e60 fix(form-validate): context-aware Check 12 — ExternalDataProcessorObject is error in config
Detect config vs EPF context by walking up from FormPath looking for
Configuration.xml. ExternalDataProcessorObject/ExternalReportObject are
valid in EPF/ERF but cause XDTO exception in configuration context.

- EPF forms: no warning (ExternalDataProcessorObject is correct)
- Config forms: ERROR with hint to use DataProcessorObject/ReportObject
- Fix test DSLs: compiled-form, table-form used wrong External* type

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:01:24 +03:00
Nick Shirokov 3bd69baae6 fix(form-validate): add ExternalDataProcessorObject/ExternalReportObject to valid cfg prefixes
Check 12 was flagging cfg:ExternalDataProcessorObject.X as "unrecognized cfg
prefix", but this is a valid XDTO type for external data processor (EPF) forms.
Found via snapshot verification against epf-add-form snapshots.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:56:47 +03:00
Nick Shirokov b0fdc32053 feat(tests): verify-snapshots v0.3 — CFE support, preRun ref scanning, full coverage
- Add two-stage CFE pipeline: load base config → load extension
- Scan preRun inputs for type refs (fixes D3: meta-edit/add-ts-attribute)
- Support args-only cases (cf-init, form-add, epf-init, template-add, etc.)
- Add InformationRegister stubs with dimension (fixes D6)
- Results: 134/145 verified (16 new CFE cases all pass)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:43:42 +03:00
Nick Shirokov 731a652cae feat(tests): add platform verification script for skill snapshots
Runs each test case through the full pipeline: cf-init → stubs → preRun →
skill script → cf-edit → db-create → LoadConfigFromFiles → UpdateDBCfg.
Handles typed-input, args-only, standalone (SKD/MXL), and EPF skills.

Results: 118/145 pass, findings documented in debug/snapshot-verify/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:35:59 +03:00
Nick Shirokov 6d5c1a0b19 Merge branch 'dev' into feature/web-test-runner 2026-04-05 18:18:25 +03:00
Nick Shirokov dd88f78969 fix(form-compile,form-validate): warn on invalid XDTO types, add Check 12
form-compile now warns when model uses runtime types like
FormDataStructure that don't exist in XML schema. Expanded cfg:
regex to cover all 25 known prefixes.

form-validate adds Check 12 — validates all <v8:Type> values:
ERROR for known-invalid types, WARN for unrecognized bare types,
pass-through for unknown namespaced types (future-proof).

Updated SKILL.md with full type reference and invalid type warning.
Updated docs/1c-form-spec.md with missing type groups.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:07:07 +03:00
Nick Shirokov ff068202e3 fix(tests): update remaining snapshots with plural→singular content refs
Snapshots for subsystem-info and interface-validate still had
Catalogs.Товары from before normalization was added.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:48:27 +03:00
Nick Shirokov 91798e3838 feat(interface-edit): normalize command name type prefix (plural/Russian to singular)
All operations (hide, show, place, order) now auto-normalize
the first segment of command names — e.g. Catalogs.X → Catalog.X,
Справочник.X → Catalog.X.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:46:01 +03:00
Nick Shirokov 9620c3846a fix(subsystem): normalize content refs — plural/Russian to singular English
subsystem-compile and subsystem-edit now auto-normalize content type
prefixes (Catalogs→Catalog, Справочник→Catalog, Справочники→Catalog).
subsystem-validate detects plural forms as errors in check #6.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:39:17 +03:00
Nick Shirokov b322c02fdb fix(web-test): discoverTests для одиночного файла + первый smoke-тест
- Fix: discoverTests падал с ENOTDIR при передаче .test.mjs файла
- Добавлен 01-navigation.test.mjs — навигация по разделам, открытие
  списков через navigateLink, переключение между подсистемами

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:22:40 +03:00
Nick Shirokov 61ef7ac891 fix(web-test): фикс синтетической конфигурации для загрузки в платформу
- Подсистемы: singular формы в Content (Catalog вместо Catalogs)
- КурсыВалют: Independent вместо RecorderSubordinate
- Убран AccumulationRegister (требует регистратор, не нужен для UI)
- Отчёт: запрос из ТЧ документа вместо регистра

Формы загружаются без Form.xml (автогенерация платформой) —
баг form-compile (XDTO exception) требует отдельного исследования.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:09:43 +03:00
Nick Shirokov ba19b4111d feat(web-test): синтетическая конфигурация для регресс-тестов
22 шага: cf-init → meta-compile (10 объектов) → form-compile (3 формы,
вкл. 2 вкладки для Номенклатуры) → skd-compile → subsystem-compile
(Склад + Администрирование) → role-compile (полные права) → cf-validate.

Расширения: иерархический справочник, разнотипные реквизиты (Number,
Boolean, Date, String unlimited), FillChecking, вторая подсистема.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:57:52 +03:00
Nick Shirokov ded11437c5 docs(web-test): обновить статус дорожной карты — #1-5 done
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:55:00 +03:00
Nick Shirokov 5eda7f8eb3 feat(web-test): test runner — buildContext, cmdTest, assertions, step
- Извлечён buildContext() из executeScript (переиспользуется)
- Новая команда `test [url] <dir> [--tags/--bail/--retry/--timeout/--report]`
- Обнаружение *.test.mjs, импорт ES-модулей, фильтрация по тегам/grep/only
- Хуки: prepare/cleanup (без браузера) + beforeAll/afterAll/beforeEach/afterEach
- Встроенный сброс состояния (dismissPendingErrors + closeForm) после каждого теста
- step(name, fn) обёртка с вложенностью и таймингами
- Assertions: ok/equal/deepEqual/includes/match/throws + 1C-специфичные
- Консольный вывод с деревом шагов, JSON-отчёт
- Поддержка webtest.config.mjs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:53:33 +03:00
Nick Shirokov f39a0d9c5e docs(web-test): BrowserContext вместо sequential reconnect для мульти-контекста
Один процесс браузера, несколько изолированных BrowserContext'ов.
Мгновенное переключение между пользователями, состояние каждой
сессии сохраняется. Не требует полного рефакторинга createContext().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:47:26 +03:00
Nick Shirokov 2347859bdd docs(web-test): спецификация test runner для регрессионного тестирования
Единый механизм для внутреннего регресса browser.mjs API и
пользовательского регресса 1С-приложений. Паттерны Playwright Test.

Содержание: CLI, формат тестов, контексты, хуки, assertions, step(),
отчёты (JSON/Allure/JUnit), синтетическая конфигурация, дорожная карта.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:37:47 +03:00
Nick Shirokov ffc34904c5 fix(web-test): adaptive header detection threshold for narrow spreadsheets
Hardcoded threshold of 3 non-empty cells prevented header detection in
spreadsheets with 1-2 columns (e.g. query console results). Use
Math.min(3, maxCol + 1) so narrow tables can still be parsed structurally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:19:24 +03:00
Nick Shirokov b008c820f9 fix(web-test): stop group header carry-forward leaking into unrelated columns
When a spreadsheet has 3 header levels (group → detail → codes), the
carry-forward logic for merged group headers would bleed into columns
belonging to different top-level groups. Detect a "super-row" above the
group row and reset carry-forward when a new top-level header starts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 18:51:10 +03:00
Nick Shirokov e5697d6f5c fix(web-test): reliable arrow-key scroll for off-screen spreadsheet cells
Rewrites scrollSpreadsheetToCell with fixes for multiple issues discovered
during E2E testing:

- Use Playwright boundingBox (page-level coords) instead of frame-internal
  getBoundingClientRect for visibility checks — frame's clientWidth is wider
  than the actual visible iframe area clipped by parent elements
- Use iframe element's boundingBox to determine visible region — cells behind
  the section panel (x < iframeBox.x) were incorrectly considered "visible"
  and focus clicks hit the section panel instead of the spreadsheet
- Use div[y]+div[x] attribute selectors instead of div.RxCy CSS classes —
  the RxCy class numbering differs from y/x attribute values
- Accept cellLoc parameter from caller instead of re-searching — avoids
  selector mismatch and handles cells missing from some rows
- Native click through mxlCurrBody overlay (page.mouse.click) for focus —
  frame.locator().click() bypasses overlay causing header/data desync,
  page.mouse.click() + frameEl.focus() doesn't transfer keyboard focus
- Pick rightmost/leftmost fully-visible cell for focus based on scroll
  direction — each arrow press immediately triggers platform scroll

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 18:17:04 +03:00
Nick Shirokov 29ee294de6 fix(web-test): arrow-key scroll for off-screen spreadsheet cells (WIP)
Scroll via arrow keys with native platform behavior. Works for
moderate scroll (few columns off-screen). Known limitations:
- Far off-screen columns may timeout
- Re-clicking between direction changes can break scroll context
- Edge cells (first/last column) may not fully scroll into view

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 16:30:18 +03:00
Nick Shirokov d72cbacfd6 fix(web-test): scroll spreadsheet cell into view before clicking
Cells outside the visible iframe area couldn't be clicked because
boundingBox() returned null. Now scrollIntoView() is called first.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 14:45:31 +03:00
Nick Shirokov c8a7ba4683 docs(web-test): add getPage() usage example for keyboard shortcuts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 13:13:10 +03:00
Nick Shirokov ea8b28280d feat(web-test): add SpreadsheetDocument cell clicking to clickElement
Extend clickElement to support clicking cells in rendered reports
(SpreadsheetDocument). First argument accepts { row, column } object
where coordinates match readSpreadsheet() output. Text fallback also
searches spreadsheet iframes when element not found in main DOM.

Refactor readSpreadsheet internals into reusable helpers:
scanSpreadsheetCells, buildSpreadsheetMapping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 13:03:05 +03:00
Nick Shirokov eebc2a0679 feat(skd-edit): add patch-query operation for substring replacement in queries
Addresses user feedback: set-query is all-or-nothing, and editing XML
directly is fragile due to escaping. patch-query allows targeted string
replacement via "old => new" shorthand, with batch mode support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:46:01 +03:00
Nick Shirokov 974e8ff5e4 fix(meta-compile): create Ext/ lazily and add modules for Constant/Enum
Empty Ext/ directories for Constants, Enums, and DocumentJournals caused
platform to wipe all extension modules during LoadConfigFromFiles.
Now Ext/ is only created when files will be placed in it, and
Constant gets ManagerModule + ValueManagerModule, Enum gets ManagerModule.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:55:14 +03:00
Nick Shirokov 47c2e5d48f fix(web-test): detect textarea forms and normalize Windows paths
Simple EPF forms with textarea fields were invisible to form detection
(formCount: 0) and misclassified as modal error dialogs. Also, backslash
paths in exec scripts caused "Invalid Unicode escape sequence" JS parse errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:31:49 +03:00
Nick Shirokov e56a932ee2 docs(switch): document --link __dirname limitation
Node.js resolves __dirname through junctions to the real target
path, not the junction location. This causes Node.js-based skills
(e.g. web-test) to write output files to the skills repo directory
instead of the project directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:01:10 +03:00
Nick Shirokov 69f5e0b7ae docs(switch): mark --link as experimental
Junction/symlink install mode may cause intermittent MSYS bash
crashes on Windows (add_item / exit code 5). Demote from
recommended to experimental; recommend copy-based install instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:15:26 +03:00
Nick Shirokov 84462e3dd9 feat(web-test): highlight command groups on function panel
highlight() now supports command group headers (eAccentColor labels)
on the 1C function panel. Matches group name, collects header +
commands below it, draws multi-element bounding box overlay.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:27:50 +03:00
Nick Shirokov d574320849 fix(web-publish): auto-detect Apache download URL from apachelounge.com
Replace hardcoded Apache zip URL with dynamic parsing of the Apache
Lounge download page. Finds the latest Win64 build automatically,
so the script won't break when new versions are published.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:38:42 +03:00
Nick Shirokov 90ff1d53b6 feat(switch): add --link flag for junction/symlink install
Instead of copying skill folders, --link creates directory junctions
(Windows) or symlinks (Linux/Mac) so updates propagate automatically
via git pull. Only supported for claude-code platform (other platforms
require path rewriting in SKILL.md). Also adds safe_rmtree to prevent
shutil.rmtree from following junctions and deleting source files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:24:10 +03:00
Nick Shirokov 09bc0d00b8 fix(web-test): use target.y coordinates to find expand icon row
The expand/collapse code re-searched for the target row by first-cell
text, which was ambiguous when parent and child rows share the same
prefix (e.g. "БУ"). This caused expand to hit the wrong (already-
expanded) row and skip. Use target.y from the initial findClickTarget
instead — matches the exact row.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:17:40 +03:00
Nick Shirokov 66c6dc7aa1 fix(web-test): swap gridListH/V in isExpanded — hierarchy expand was inverted
gridListH = collapsed (▶), gridListV = expanded (▼). The old code had it
backwards, so `expand: true` on a collapsed group was a no-op.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:48:40 +03:00
Nick Shirokov 1d89b3ec69 refactor(skills): trim SKILL.md — remove file trees, output previews, usage advice
Remove redundant sections from 11 SKILL.md files:
- "Что генерируется" file trees (meta-compile, cf-init, cfe-init, epf-init, erf-init, form-add)
- Output previews (meta-remove, form-edit, cfe-diff, role-info)
- "Когда использовать" (meta-remove, form-edit, mxl-info)
- Internal details (meta-remove ref table, mxl-info column sets, overflow protection)
-276 lines total.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:36:03 +03:00
Nick Shirokov 43d1d09ee8 fix(skills): SKILL.md gaps — missing params, clarify docs, fix example bug
- interface-edit: expand SKILL.md from stub to full docs, remove redundant reference.md
- cf-edit: restore reference.md link with descriptive text
- cfe-borrow: clarify BorrowMainAttribute semantics (omit/Form/All)
- epf-bsp-add-command: fix example bug (Модификатор on non-print command)
- mxl-validate: keep only universal -TemplatePath in docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:17:46 +03:00
Nick Shirokov 404e6c6851 refactor(*-validate): trim SKILL.md — remove check tables, exit codes, clarify Detailed
All 11 validate skills: remove internal check tables and exit code lines
that provide no value to the model-user. Update Detailed param description
to be clearer. -221 lines, ~1550 tokens saved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:55:05 +03:00
Nick Shirokov 009022d04b fix(web-test): close DLB hint popup before paste fallback in fillReferenceField
When DLB dropdown shows only a hint ("Введите строку для поиска...") without
.eddText items, the code fell through without closing the popup. This left
editDropDown covering the input field, causing Playwright to wait up to 30s
for actionability on the next page.click(). Now we Escape the hint popup
when eddState.visible=true but items are empty (34s → 5s on cold cache).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:12:41 +03:00
Nick Shirokov 70e684d189 feat(skill-tests): add form-add + form-compile steps to platform integration tests
Now that ExtendedPresentation and InterfaceCompatibilityMode bugs are fixed,
platform integration tests can include full form generation:
- platform-config: form-add + form-compile for Catalog and Document forms
- platform-epf: epf-add-form + form-compile with elements/attributes/commands
- platform-cfe: form-add + form-compile for borrowed Catalog form

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 19:17:25 +03:00
Nick Shirokov 72bad1aaaa fix(form-add,cf-init,cfe-init): ExtendedPresentation + InterfaceCompatibilityMode
- form-add v1.2: ExtendedPresentation only for DataProcessor/Report/External* forms
  (Catalogs, Documents, Registers etc. don't have this property — platform rejects it)
- cf-init v1.1: InterfaceCompatibilityMode Taxi → TaxiEnableVersion8_2
  (matches all real configs: acc 8.3.20/24/27, erp 8.3.24)
- cfe-init v1.1: read InterfaceCompatibilityMode from -ConfigPath base config
  (analogous to existing CompatibilityMode auto-detection)
- Remove workaround in platform-cfe integration test (cf-edit modify-property)
- Update 162 snapshot Configuration.xml + 7 form metadata snapshots

Tests: 301/301 passed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 19:08:42 +03:00
Nick Shirokov 29a5cbae4c feat(skill-tests): platform integration tests via .v8-project.json
Runner reads v8path from .v8-project.json, skips platform tests if
1cv8.exe unavailable. Placeholders: {v8path}, {v8exe}, {dbPath}, etc.

- platform-config: cf-init → meta-compile → db-create → load → update
- platform-epf: epf-init → epf-build → db-create → epf-dump (roundtrip)
- platform-cfe: config + extension → db-create → load both → update both

All 6 integration tests green (3 file-only + 3 platform).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:59:44 +03:00
Nick Shirokov be1bbb2d26 feat(skill-tests): negative cases for platform-dependent skills
Add expectError test cases for db-create, db-load-xml, db-dump-xml,
db-dump-cf, db-load-cf, db-update, db-run, epf-build, epf-dump.
Tests parameter validation (missing args, bad file paths, partial
mode without required params). Total: 301 cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:40:26 +03:00
Nick Shirokov 5281fd54f2 feat: meta-edit v1.5 — normalize enum property values
Same alias dictionary + case-insensitive matching as meta-compile v1.4.
Applied at: fillChecking/indexing in attribute parsing, and scalar
property change in modify-attribute/modify-property operations.
Both PS1 and PY versions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:30:04 +03:00
Nick Shirokov f697ba3ff3 feat: meta-compile v1.4 — normalize enum property values
Add alias dictionary + case-insensitive matching for 23 system enum
properties (RegisterType, WriteMode, Periodicity, etc.). Accepts common
model mistakes like "Balances"→"Balance", "RecordSubordinate"→
"RecorderSubordinate", Russian synonyms, and wrong-case values.

Both PS1 and PY versions updated with identical dictionaries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:30:04 +03:00
Nick Shirokov 0778cc89ee feat: post-run validation + integration tests for skill pipeline
- runner.mjs v0.4: --with-validation flag runs validators on real output
- postValidate config in 20 _skill.json files (maps skill → validator)
- validatePath in ~100 positive test cases
- skipValidation for 5 cross-reference cases (isolated workspace limitation)
- Integration tests: build-config (19 steps), build-epf (6), build-cfe (4)
- base-config cache from build-config for downstream tests
- Fix chart-of-calculation-types test data (DependenceOnCalculationTypes)
- 285/285 unit + 3/3 integration, all green with validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:30:03 +03:00
Nick Shirokov 28b2765f68 fix: accept XML-style synonyms in interface-edit and skd-compile DSL
interface-edit v1.1: place/order operations accept value as object
(not just JSON string) from DefinitionFile — no more JSON-in-JSON.

skd-compile v1.3: dataSetLinks accept both DSL names (sourceExpr,
destExpr, source, dest) and XML names (sourceExpression,
destinationExpression, sourceDataSet, destinationDataSet).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 14:11:02 +03:00
Nick Shirokov 0d116863ec feat: role-compile OutputDir accepts config root (like meta-compile)
- OutputDir now accepts config root dir — creates Roles/ subdirectory
- Back-compat: if OutputDir ends with "Roles", uses it as-is
- Configuration.xml lookup adjusted accordingly
- Updated SKILL.md, PS1, PY scripts (v1.3)
- Updated test cases and snapshots for new Roles/ path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:51:24 +03:00
Nick Shirokov bc6bc01047 docs: update python-porting-guide with etree pitfalls from test session
- Fix save_xml_bom example: full declaration replace + lowercase encoding
- Add etree vs XmlDocument serialization differences table
- Add pitfalls: hashtable ordering, (?i) regex, missing property access

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 21:00:37 +03:00
Nick Shirokov 972cd5061d fix: resolve remaining 19 Python test failures — 285/285 on both runtimes
Script logic fixes (PY mirroring PS1):
- skd-compile: fix (?i) regex flag placement for Python 3.11+
- mxl-compile: handle list-of-lists row format (PS1 silently ignores)
- subsystem-compile: add "objects" → "content" synonym alias
- role-compile: add "rights" → "objects" synonym alias
- meta-compile: sort HTTP/Web service method/operation iteration
- form-edit: insert ChildItems after Events/AutoCommandBar (not at end)
- mxl-compile: sort colWidthMap iteration in both PS1 and PY for
  deterministic format indices

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 20:30:45 +03:00
Nick Shirokov 4565808b77 fix: Python XML compat — declaration quotes + runner normalization (112→266/285)
Scripts (production fix): fix XML declaration in 14 save_xml_bom scripts
- version='1.0' → version="1.0" (single→double quotes)
- encoding='UTF-8' → encoding="utf-8" (match PS1 XmlWriter output)
- Add trailing newline to etree.tostring output

Runner (test normalization, Python-only):
- normalizeXmlContent() applied only when --runtime python
- Handles etree serialization quirks: xmlns stripping, self-closing
  space, inter-tag whitespace, empty elements, &#13; entities
- PS1 tests remain strict — no normalization applied

19 remaining failures are real logic bugs in Python scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 19:05:49 +03:00
Nick Shirokov 250978c2fd fix: resolve FINDINGS — synonyms, path resolution, exit codes
Skill fixes (all ps1+py, version bumped to v1.1):
- role-compile: accept "rights" as synonym for "objects"
- subsystem-compile: accept "objects" as synonym for "content"
- form-add: resolve directory path to .xml (like meta-validate)
- form-info: resolve directory path to Ext/Form.xml (like form-validate)
- mxl-compile: support absolute OutputPath (IsPathRooted check)
- meta-remove: exit 1 when object not found; v1.1
- cfe-patch-method: accept plural type names (Catalogs → Catalog)

Test fixes:
- basic-role.json: use canonical "objects" key
- basic.json (subsystem): use canonical "content" key
- catalog-form.json: fix outdated DSL format
- New synonym test cases for role-compile and subsystem-compile
- error-not-found.json: expect error (exit 1)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 17:25:52 +03:00
Nick Shirokov 4551525718 feat: runner v0.3 — parallel execution, skip snapshots for external
Add parallel test execution with worker pool (default: CPU count).
New --concurrency N option (--concurrency 1 for sequential).
Pre-warm shared fixtures before parallel run.
Skip snapshot update/compare for external (read-only) workspaces —
prevents accidental copying of large config dumps.
Fix normalizeUuids for cf-info/cf-validate (false→true).

Result: 283 tests, 329s→84s (4x speedup).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:47:22 +03:00
Nick Shirokov 9422c66df4 feat: runner v0.2 — external setup, skip support, +24 real-data cases
Add `external:<path>` setup type for read-only access to real config
dumps without copying. Tests gracefully skip (○) when path unavailable.

Add 12 meta-compile cases for previously uncovered types (AccountingRegister,
CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes,
ChartOfCalculationTypes, BusinessProcess, Task, ExchangePlan,
DocumentJournal, EventSubscription, HTTPService, WebService).

Add 18 external cases for info/validate skills against real ACC 8.3.24
config dump (meta, form, skd, role, subsystem, cf).

Total: 283 tests, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:02:00 +03:00
Nick Shirokov a1b3fdd4e2 feat: deepen skill test coverage — 52 → 247 cases across all 43 skills
Add 195 new test cases covering examples from SKILL.md, edge cases,
and parameter combinations. Create _skill.json for form-edit, skd-edit,
subsystem-edit. Add fixtures for negative validate cases. Fix
normalizeUuids in meta-validate/meta-info configs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 15:38:06 +03:00
Nick Shirokov d6d44b8b35 feat: add interface-*, cfe-* tests (batches 8+9) — all skills covered
- interface-edit, interface-validate: 2 cases
- cfe-init, cfe-validate, cfe-borrow, cfe-patch-method, cfe-diff: 5 cases
- runner: switch params in preRun (true = no value)
- Findings: interface-edit JSON-in-JSON, cfe-patch-method type naming

52 tests across 40 skills, all passing (~48s).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:09:00 +03:00
Nick Shirokov b480fa0b49 feat: add form-*, skd-*, misc tests (batches 1, 2, 10)
New skills covered:
- form-add, form-compile, form-validate, form-info (batch 1)
- skd-compile, skd-validate, skd-info (batch 2)
- help-add, template-add, template-remove, meta-remove (batch 10)

Findings: form-add/form-info path resolution inconsistency,
meta-remove self-reference requires -Force.

45 tests across 33 skills, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:00:34 +03:00
Nick Shirokov 44a84f8ce7 feat: add role-*, subsystem-* tests (batches 4+5)
- role-compile, role-validate, role-info: 3 cases
- subsystem-compile, subsystem-validate, subsystem-info: 3 cases
- 34 tests across 22 skills, all passing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:52:38 +03:00
Nick Shirokov dcacecff7f feat: add cf-edit/validate/info, epf-init/validate/add-form, erf-init tests (batches 6+7)
7 new skills covered. All 28 tests across 16 skills passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:48:11 +03:00
Nick Shirokov 8b38f8f78d feat: add mxl-* tests (batch 3), support cwd in skill config and preRun
- mxl-compile, mxl-validate, mxl-info, mxl-decompile: 4 cases
- runner: cwd option in _skill.json and preRun steps for skills
  that resolve OutputPath relative to current directory
- Finding: mxl-compile only accepts relative OutputPath

21 tests across 9 skills, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:44:37 +03:00
Nick Shirokov 74b3f76a32 refactor: move broken fixtures into skill directory, remove global fixtures/
fixture: paths now resolve relative to skill's cases/ dir, not global.
Each validate skill keeps its broken fixtures locally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:31:34 +03:00
Nick Shirokov 671be7c6b5 docs: update README with all features — params, preRun, args_extra, workPath, verbose, failure workflow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:24:39 +03:00
Nick Shirokov 4a697db47a feat: show case id in failure output for easy navigation
Compact mode shows "cases/meta-compile/catalog-basic" next to failed
test name — model can open the file, rerun, or update snapshot.
Verbose mode shows id for all cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:21:25 +03:00
Nick Shirokov 34f582ddef feat: add total time to summary line
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:17:22 +03:00
Nick Shirokov eec626eb6f feat: compact output by default, --verbose for full tree
Default shows one line per skill: "✓ meta-compile  6/6 (3.3s)"
Failed tests expanded with details automatically.
--verbose/-v shows full tree with every case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:15:00 +03:00
Nick Shirokov 312d058412 feat: add meta-validate, meta-info tests and broken fixtures
- meta-validate: 3 cases (valid catalog, bad root element, file not found)
- meta-info: 2 cases (catalog overview with stdoutContains, not found error)
- fixtures/broken/catalog-bad-root for negative validate tests
- All 5 skill archetypes now covered: compile, init, edit, validate, info

17 tests, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:08:53 +03:00
Nick Shirokov 95776a4248 feat: add meta-edit tests, support preRun and workPath mapping
- meta-edit: 3 cases (add-attribute, add-tabpart, error-no-definition)
- runner: preRun steps for creating prerequisite objects before test
- runner: workPath arg mapping (workDir + case field) for path-based skills

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:05:17 +03:00
Nick Shirokov 347722ef0d feat: add cf-init test cases, support args_extra and params priority
- cf-init: 3 cases (basic, with-vendor, error-already-exists)
- runner: args_extra for optional CLI params per case
- runner: params.field takes priority over caseData.field in case.<field> mapping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:02:06 +03:00
Nick Shirokov 9f6793abae refactor: move snapshots into snapshots/ subdirectory
Reduces clutter when a skill has many test cases — all .json cases
are visible at top level, snapshots tucked away in one folder.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 12:52:20 +03:00
Nick Shirokov 0ddb675502 feat: add skill regression test runner with meta-compile pilot
Snapshot-based test runner (tests/skills/runner.mjs) for verifying
skill script output. Zero dependencies, runs on any machine with
Node.js — no 1C platform needed for daily regression.

Pilot: meta-compile with 6 cases (4 positive with snapshots, 2 negative).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 12:48:51 +03:00
Nick Shirokov d2dfcfd160 fix(web-test): normalize \u00a0 in getFormState, add tooltip for icon-only buttons
getFormState now replaces non-breaking spaces with regular spaces in all
button names, field labels, checkbox/radio labels. Icon-only buttons
(pressCommand without text) expose tooltip from parent .framePress title
attribute. clickElement fuzzy match includes tooltip as lowest-priority
candidate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:27:07 +03:00
Nick Shirokov 6c01f3a261 feat(web-test): multi-select rows with modifier + _selected in readTable
Add modifier option ('ctrl'|'shift') to clickElement for Ctrl+click
(add to selection) and Shift+click (select range) in grid rows.
Add _selected: true flag to readTable rows so the model can verify
which rows are currently selected before performing actions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:10:51 +03:00
Nick Shirokov 506f0b84df feat(web-test): clear fields via empty value — Shift+F4 in fillFields, selectValue, fillTableRow
Pass '' or null as value to clear any field (except checkbox/radio) via native 1C Shift+F4.
Returns method: 'clear'. Handles tree grids (close selection form first) and flat grids (dblclick to enter edit mode).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:15:52 +03:00
Nick Shirokov f5c02144cb fix(web-test): refine confirmation pause — remove from clickElement, reduce to 500ms in closeForm
clickElement confirmation handling is cleanup of stale dialogs — no pause needed.
closeForm confirmation is intentional user action — keep 500ms pause during recording
(on top of ~600ms from waitForStable = ~1.1s total dialog visibility).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:49:20 +03:00
Nick Shirokov d982c5082a fix(web-test): closeForm — pause before auto-clicking confirmation during recording
Same 1.5s pause as in clickElement for confirmation dialogs when video
recording is active. Applies when closeForm({ save: true/false }) auto-clicks
the confirmation button.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:39:15 +03:00
Nick Shirokov cce00a4def fix(web-test): clickElement — pause before auto-clicking confirmation during recording
When video recording is active, wait 1.5s before clicking confirmation
dialog buttons so viewers can see the dialog in the video.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:42:38 +03:00
Nick Shirokov bc4ee63986 fix(web-test): clickElement button wait — CDP network monitor for early exit
Replace 10s waitForSelector timeout with CDP-based network monitoring.
For buttons that trigger server operations without producing a modal/balloon,
the old code waited the full 10s. Now it monitors actual HTTP requests via
Chrome DevTools Protocol and exits 300ms after the last request completes.

- Add startNetworkMonitor() — creates CDP session before click, tracks pending requests
- waitDone() polls for network quiet (300ms debounce) or UI element appearance
- CDP session cleaned up in finally block via cleanup()
- Add optional {timeout} parameter to clickElement for custom wait limits
- Tested: Записать ~1.9s (was ~11.5s), Записать и закрыть ~0.9s, confirmation dialogs OK

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 10:53:24 +03:00
Nick Shirokov a314ec32fc fix(web-test): fillFields date/time fields — paste instead of selectValue
Date fields have a CB (Choose Button) that opens a calendar, not a selection
form. fillFields detected hasPick → delegated to selectValue → error
"DLB click did not open a popup or selection form".

Fix: detect date fields by `iCalendB` CSS class on CB button (dom.mjs),
propagate `isDate` flag through field mapping, and use clipboard paste
for date fields instead of selectValue. Reference fields with CB (without
iCalendB) continue using selectValue as before.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:40:12 +03:00
Nick Shirokov baefeaa05b fix(web-test): clickElement expand:false — idempotent expand/collapse
expand:false was silently ignored because `if (expand || toggle)` evaluates
to false when expand=false. Now uses `expand != null` to enter the branch,
checks current state (gridListH/gridListV for groups, backgroundImage gx=0
for tree nodes), and only clicks when the state needs to change.

- expand:true on collapsed → expand (click)
- expand:true on expanded → noop (idempotent)
- expand:false on expanded → collapse (click)
- expand:false on collapsed → noop (idempotent)
- toggle → always click (unchanged)

Returns `toggled: true/false` in result to indicate whether click happened.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:27:40 +03:00
Nick Shirokov 2d88cdc864 fix(web-test): fillTableRow row:N — colindex matching, scroll, field sorting
Root cause: fillTableRow used child-index matching between grid header and
body cells. When headers are merged (e.g. "Бизнес-процесс источник" spanning
two body columns), header has more children than body — indices diverge,
click lands on wrong cell, fields stay empty.

Fixes:
- Use `colindex` attribute (set by 1C platform) to match header→body cells
  reliably across merged headers (cellCoords + nextCoords)
- Add `scrollIntoView()` before clicking — fills cells behind horizontal scroll
- Sort fields by colindex before processing — Tab-loop goes left→right
  regardless of field order in the passed object
- Limit F4 to tree grids only — prevents calculator popup on numeric fields
  in flat grids which breaks Tab-loop focus
- Add paste fallback in directEditForm path for plain-text/numeric fields

Tested: 12/12 automated scenarios (single/multi field, add/edit, scroll,
reverse order, mixed types, tree grid, multiple tables, checkbox).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:22:25 +03:00
Nick Shirokov f7695a9534 feat(cfe-borrow): add -BorrowMainAttribute for borrowing object attributes with form
When adding a new attribute to a borrowed form, -BorrowMainAttribute
borrows the form's main attribute ("Объект") and all referenced object
attributes, tabular sections, and their transitive type dependencies.

Two modes: Form (default — only attributes referenced by form DataPath)
and All (all object attributes). Deep paths like Объект.A.B are resolved
transitively. Already-borrowed objects are not overwritten.

Also fixed: CommonPicture auto-borrow from AutoCommandBar, form-attribute
DataPath stripping (keep only Объект.* paths).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 19:56:26 +03:00
Nick Shirokov 252105396b feat(meta-compile): add ManagerModule.bsl for Report and DataProcessor
Create ManagerModule.bsl alongside ObjectModule.bsl for Report and
DataProcessor types — required for reports with НастроитьВариантыОтчета.

Bump version v1.2 → v1.3

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:38:13 +03:00
Nick Shirokov 42df4cd6b1 feat(skd-compile): compact AreaTemplate DSL, fix dataPath and presentation fallback
- Fix empty dataPath when field is specified as object { field, title }
- Add title to presentation fallback chain: presentation → title → name
- Add compact DSL for AreaTemplate: rows/widths/style instead of raw XML
- Built-in style presets: header, data, subheader, total
- User-defined presets via skd-styles.json (project-level overrides)
- Support vertical merge ("|"), parameters ("{Name}"), static text, null cells
- Update SKILL.md, skd-dsl-spec.md, skd-guide.md with template DSL docs
- Add examples/skd-styles.json with all supported keys
- Bump version v1.1 → v1.2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:38:04 +03:00
Nick Shirokov b9a04b235f docs(web-test): document error stack, platformDialogs in guide
Add stack auto-fetch and platformDialogs detection to web-test-guide.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:53:33 +03:00
Nick Shirokov 9bc0240e95 fix(web-test): take error screenshot before fetchErrorStack closes modal
Move screenshot capture to before fetchErrorStack call in the ACTION_FNS
wrapper, so the error modal is still visible on the screenshot. Skip the
duplicate screenshot in catch block when one was already taken.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:32:00 +03:00
Nick Shirokov 4cfcaaaa1c feat(web-test): auto-dismiss platform dialogs in dismissPendingErrors
dismissPendingErrors() now detects and closes leftover platform dialogs
(About, Support Info, Error Report) before checking for 1C error modals.
This prevents action functions from failing with timeouts when a stale
platform dialog blocks interaction via modalSurface.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:28:01 +03:00
Nick Shirokov f9c3792528 feat(web-test): detect and close platform dialogs in getFormState/closeForm
getFormState() now returns `platformDialogs` array when platform-level
dialogs are open (About, Support Info, Error Report). These dialogs are
invisible to 1C form detection and not closeable via Escape.
closeForm() detects platform dialogs first and closes them via
_closePlatformDialogs() instead of sending Escape, returning
closedPlatformDialogs in the result.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:20:32 +03:00
Nick Shirokov 9090a81e43 feat(web-test): auto-fetch error call stack on 1C exceptions
When a 1C error modal is detected, automatically retrieve the full call
stack before throwing. Uses two strategies: Path 1 clicks the OpenReport
link for platform exceptions, Path 2 navigates hamburger → About →
Support Info for handled ВызватьИсключение errors. The stack is returned
as structured {raw, entries[{location, code}], timestamp} in the error
result. Handles unstable modal redraws with a 1.5s re-check delay.
Platform dialogs are always cleaned up via try/finally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:10:52 +03:00
Nick Shirokov f037324ee9 feat(web-test): expose formCount, openForms, modal in getFormState; closed in closeForm
When the open-windows tab bar is hidden in 1C settings, the model had no
way to know how many forms are open or whether a form is modal. Now
getFormState returns openForms/formCount/modal derived from DOM form
elements (independent of tab bar), and closeForm compares form number
before/after Escape to return closed: true/false.

Tested on ncc (tab bar hidden) and bpdemo (tab bar visible).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:23:31 +03:00
Nick Shirokov 6f36e36166 feat(web-test): per-caption voice + speechRate for multi-voice narration
- addNarration: use cap.voice override per caption (fallback to global)
- showCaption/showImage/showTitleSlide: pass opts.voice to caption entry
- showCaption: record caption when text is empty but speech is explicit
- startRecording: add speechRate option (default 70ms/char, 85 for ElevenLabs)
- run.mjs: increase exec timeout to 30min for long recordings
- docs: update recording.md and web-test-recording-guide.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:30:02 +03:00
Nick Shirokov ca0dac2693 docs(db-load-git): trim SKILL.md, update mapping docs for v1.3
Remove redundant sections (Source table, exit codes, mapping internals)
and trim examples from 6 to 2. Update mapping description to reflect
that all non-XML files (not just BSL) are now handled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:37:26 +03:00
Nick Shirokov ab7d82ba20 fix(db-load-git): handle non-XML files (Help HTML) in partial load, fix PY encoding
- Remove .xml/.bsl-only filter — now any changed file (HTML, BSL, etc.)
  maps to parent object XML + pulls entire Ext/ directory
- Fix: ru.html changes without Help.xml in same commit range were silently
  skipped, leaving help text stale in the database
- Fix PY: add encoding="utf-8" to subprocess.run in run_git() — Cyrillic
  paths were garbled on Windows due to default cp1251 decoding
- Bump to v1.3

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:28:53 +03:00
Nick Shirokov 669b5f42f2 fix(help-add): remove EPF-specific artifacts, clarify ObjectName as path
v1.2: renamed processorDir→objectDir, removed ProcessorName alias,
generic error messages instead of "epf-init", HTML template "Описание"
instead of "Описание обработки". SKILL.md clarifies ObjectName format
(e.g. Catalogs/МойСправочник).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 15:46:59 +03:00
Nick Shirokov 5b6fcc7c74 fix(web-test): normalize \u00a0 in matching, prefer exact match in clickEddItem
- normYo now replaces \u00a0 (non-breaking space) with regular space — 1C web
  client uses \u00a0 in dropdown items, causing exact match failures
- clickEddItem does two passes: exact match first, then partial — prevents
  "Системы" from matching before "Системы и бизнес-процессы"
- Same \u00a0 fix applied to all inline ny() functions in evaluate scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 15:35:10 +03:00
Nick Shirokov df47128994 fix(web-test): route reference fields without DLB through selectValue
Reference fields with pick button (_CB) but no dropdown button (_DLB)
were going through the plain paste path, which silently failed for
non-editable fields. Now detected via hasPick flag in resolveFieldsScript
and delegated to selectValue (F4 → selection form).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 15:22:44 +03:00
Nick Shirokov ea453e5c97 fix(web-test,web-publish): DLB-first approach for combobox fields, fix relative Apache paths
web-test/browser.mjs: fillReferenceField now tries DLB (DropListButton) click
before falling back to paste approach. Combobox/enum fields are filled cleanly
in one step (click dropdown → select item) instead of the old Shift+F4 → Tab →
refocus → paste flow that caused visual artifacts.

web-publish v1.1: normalize ApachePath to absolute when agent passes a relative
path like "tools/apache24", preventing Apache "Forbidden" errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:51:28 +03:00
Nick Shirokov 14b0782904 refactor(web-test): replace fade transitions with auto-cleanup of overlays
CSS fade transitions don't work well with CDP screencast (causes desktop
flash between slides). Instead, showImage/showTitleSlide now automatically
remove the other overlay type — no need to call hide before showing next.

Pattern for consecutive slides:
  showTitleSlide(...) → showImage(...) → showImage(...) → hideImage()
No hideTitleSlide() needed between title and first image.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:41:17 +03:00
Nick Shirokov b7e3bd876d feat(web-test): add fade transitions to showTitleSlide/showImage overlays
- Fade-in (300ms ease) on show: element created with opacity:0, then
  transitioned to opacity:1 via requestAnimationFrame
- Fade-out (300ms ease) on hide: opacity set to 0, wait 350ms, remove
- Applied to showTitleSlide/hideTitleSlide and showImage/hideImage
- No change to showCaption (instant appearance fits subtitle UX better)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:28:33 +03:00
Nick Shirokov b68f4145ce fix(web-test): reduce smart TTS wait from 100ms/char to 70ms/char
Measured real Edge TTS (ru-RU-DmitryNeural) durations:
  57 chars → 4.4s (77ms/char)
  72 chars → 6.0s (84ms/char)
  126 chars → 8.2s (65ms/char)
  745 chars → 48.0s (64ms/char)

Old 100ms/char overestimated by 30-55%, causing long silent pauses
after speech in showImage/showTitleSlide/showCaption. New 70ms/char
gives ~10% safety margin without excessive silence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:05:13 +03:00
Nick Shirokov dc2056a5d5 fix(web-test): resolve file paths relative to project root, not cwd
All user-facing file functions now resolve relative paths from the
project root (where .claude/ lives) instead of process.cwd().
Fixes showImage, startRecording, addNarration, openFile failing when
the skill is installed in a different project.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:56:11 +03:00
Nick Shirokov bef4a13ba9 docs(web-test): sync API docs with actual implementation
- recording.md: add speech param to showCaption parameter table
- web-test-guide.md: add showImage, hideImage, addNarration, getCaptions
  to utilities table; add speech to showCaption/showTitleSlide descriptions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:04:58 +03:00
Nick Shirokov c280e52932 docs: update web-test-recording-guide with showImage and titleSlide speech
- Add presentation slides section (showImage with style presets)
- Add speech parameter to title slide example
- Update full example with title speech and image slide

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:00:08 +03:00
Nick Shirokov c86bf8779f docs(web-test): document showImage and showTitleSlide speech in recording.md
- Add showImage/hideImage API docs with style presets and scaling behavior
- Add speech parameter to showTitleSlide docs
- Update example to include title speech and image slide

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 19:57:25 +03:00
Nick Shirokov a4e0faaeb3 feat(web-test): add speech support to showTitleSlide
Title slides can now have TTS narration, same as showCaption/showImage.
Pass opts.speech as string for custom narration text, or true to use
the title text. Includes smart wait for video timeline sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 19:53:47 +03:00
Nick Shirokov 9d6ceae4f1 fix(web-test): showImage scaling and full preset improvements
- Use min-width/min-height 50% to upscale small images (was showing
  tiny 225px images at native size instead of scaling up)
- Keep max-width/max-height 92% for large images (no regression)
- Change full preset from cover to contain — no content cropping,
  black bars instead of cutting off edges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 19:36:22 +03:00
Nick Shirokov 18ad662378 feat(web-test): add showImage/hideImage for displaying images during recording
Show image files (PNG, JPG, etc.) as full-screen overlays during video
recording — useful for presentation slides in video instructions.

- Read file → base64 → inject as <img> overlay (same pattern as showTitleSlide)
- Style presets: blur (default), dark, light, full
- blur: blurred+dimmed copy as background with shadow
- full: object-fit cover, fills entire screen
- TTS speech support with smart wait (same as showCaption)
- Custom background overrides preset
- Fixed no-record stubs: showImage/showTitleSlide not stubbed (visual-only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 19:17:31 +03:00
Nick Shirokov 05fc7eba27 feat(skd): support @file references for query text in skd-compile and skd-edit
Allows using "@path/to/file.sql" instead of inline query text.
Path resolved relative to definition file, then CWD; absolute paths supported.

Closes #9

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 20:06:02 +03:00
Nick Shirokov ffa3189442 feat(meta-info): show LimitLevelCount/LevelCount for hierarchical catalogs
Closes #10

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 19:26:14 +03:00
Nick Shirokov bb02c1b0bd feat(web-test): clickElement support for icon-only frameButton + tumblerItem
Icon-only navigation buttons (Назад, Обновить) now match by idName fallback.
Tumbler segments (Справа/Снизу/Скрыть) collected as new kind in both
getFormState and findClickTarget.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 19:07:59 +03:00
Nick Shirokov 46f0e6be8c fix(web-test): auto-accept native browser dialogs (confirm/alert)
1C web client uses native confirm() for scripts like vis.js file
access. Without handling, these block Playwright execution.
Added page.on('dialog') handler to auto-accept.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 18:34:05 +03:00
Nick Shirokov 38ccded7d9 feat(web-test): auto-load 1C browser extension for file operations
Auto-detect 1C:Enterprise browser extension from Chrome/Edge profiles
and load it via launchPersistentContext. Enables native file dialogs
(Excel import/export) without "install extension" prompt.

- findExtension() scans Chrome/Edge User Data by extension ID
- connect() uses launchPersistentContext when extension found, falls
  back to chromium.launch() otherwise
- isConnected() handles both Browser and BrowserContext objects
- Temp userDataDir cleaned on disconnect()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 18:09:20 +03:00
Nick Shirokov 4e0ce5ba0f fix(web-test): clickElement normalizes ё in grid row text
Grid row search in findClickTargetScript used raw innerText without
norm() — missed ё→е normalization. Target was normalized but row text
was not, so "расчётным" didn't match "расчетным".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 14:19:12 +03:00
Nick Shirokov e948d39adb fix(web-test): clickElement expand support for gridGroup in hierarchy mode
When expand/toggle is passed for gridGroup/gridParent elements,
click the .gridListH/.gridListV triangle icon to expand/collapse
in place instead of dblclick which enters the group. Without
expand, dblclick behavior is preserved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 13:27:38 +03:00
Nick Shirokov d9e7d9c107 fix(web-test): fillTableRow enum support + clickElement tab ambiguity
Three fixes:

1. fillTableRow: match cells by column header text (headerText fallback)
   when INPUT id-based fuzzy match fails due to metadata typos

2. fillTableRow: EDD filter preserves standalone enum values like "Создать"
   by only filtering "Создать элемент/группу/:" patterns (was: startsWith)

3. clickElement: coordinate-based click for tabs without ID, avoiding
   global [data-content] selector that picks invisible duplicates from
   background forms

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 12:39:44 +03:00
Nick Shirokov 1da43109fc Merge branch 'dev' — checkbox support for readTable/getFormState/fillTableRow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:21:19 +03:00
Nick Shirokov 21a0e360ef fix(web-test): fillTableRow stops Tab early when only checkboxes remain
Tab past the last cell in 1C creates extra rows. Now when all unfilled
fields are checkboxes (boolean values), the Tab loop exits immediately
instead of pressing Tab 3 more times on non-INPUT cells.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:04:27 +03:00
Nick Shirokov 9f5e244f68 fix(web-test): fillTableRow add+checkbox targets correct row via addedRowIdx
Tab navigation skips checkbox cells (no INPUT). After Tab fill, unfilled
checkbox fields are retried via direct click. Previously the retry hit
the wrong row because the selected row shifted after Tab/commit. Now
we record row count before "Добавить" click and use that index for the
retry, ensuring checkboxes land on the same row as the text fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:59:06 +03:00
Nick Shirokov 18a198d12b fix(web-test): fillTableRow processes remaining fields after checkbox toggle
Previously fillTableRow returned immediately after toggling the first
checkbox field, ignoring any remaining fields. Now it recursively
processes the rest on the same row.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:40:15 +03:00
Nick Shirokov 8fca42193a feat(web-test): readTable/getFormState — expose unnamed checkbox columns
Unnamed checkbox columns (no header text) now appear as "(checkbox)" in
getFormState().tables[].columns and readTable().columns. Checkbox cell
values return "true"/"false" instead of empty strings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:36:38 +03:00
Nick Shirokov b603c7e3fa feat(web-test): expand alias, tree expand fix, fillTableRow checkbox support
- clickElement: add `expand` option (alias for `toggle`) for tree expand/collapse
- clickElement: fallback to dblclick when tree +/- icon not found
- dom.mjs: search [tree="true"] in entire line, not just first imgBox
- fillTableRow: detect checkbox cells via .gridBox > .checkbox, click checkbox
  icon directly (not cell center). Supports named columns (Активен, Проверен)
- SKILL.md: document `expand` instead of `toggle`

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:48:40 +03:00
Nick Shirokov b00289e62c feat(web-test): expand alias, tree expand fix, fillTableRow checkbox support
- clickElement: add `expand` option (alias for `toggle`) for tree expand/collapse
- clickElement: fallback to dblclick when tree +/- icon not found (was NumpadAdd)
- dom.mjs: search [tree="true"] in entire line, not just first imgBox
  (fixes trees with checkbox column before tree column)
- fillTableRow: detect checkbox cells after first click, return immediately
  without escalation (dblclick/F4). Checkbox state detected via .select class
- SKILL.md: document `expand` instead of `toggle`

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:47:35 +03:00
Nick Shirokov 97820111d5 feat(web-test): expand alias, tree expand fix, fillTableRow checkbox support
- clickElement: add `expand` option (alias for `toggle`) for tree expand/collapse
- clickElement: fallback to dblclick when tree +/- icon not found (was NumpadAdd)
- dom.mjs: search [tree="true"] in entire line, not just first imgBox
  (fixes trees with checkbox column before tree column)
- fillTableRow: detect checkbox cells after first click, return immediately
  without escalation (dblclick/F4). Checkbox state detected via .select class
- SKILL.md: document `expand` instead of `toggle`

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:51:20 +03:00
Nick Shirokov 0a2a36dbc6 refactor(form-info): trim SKILL.md further — drop redundant legend
Output is self-documenting; only note Group:AH/AV abbreviations.
217 → 30 lines.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 19:31:39 +03:00
Nick Shirokov b36232ae19 refactor(form-info): trim SKILL.md from 217 to 47 lines
Remove redundant output format docs — the output is self-documenting.
Keep only: command, parameters, and a compact legend for abbreviations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 19:29:08 +03:00
Nick Shirokov 1479f944f5 feat(form-info): add -Expand parameter for collapsed page drill-down
Pages are collapsed by default showing "(N items)". The new -Expand
parameter allows expanding by name, title, or * for all. A hint line
is shown when collapsed sections exist.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 19:21:51 +03:00
Nick Shirokov 9cffa81bcc fix(web-test): --no-record stubs return proper objects in run.mjs sandbox
The real fix: run.mjs sandbox was stubbing stopRecording/addNarration as
noop (returning undefined). Now returns { file: null, duration: 0 } so
video scripts work transparently with --no-record.
Also: browser.mjs stopRecording/addNarration handle missing state gracefully.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:59:30 +03:00
Nick Shirokov 6667ab38ee fix(web-test): stopRecording/addNarration return stub when not recording
Enables --no-record dry-run of video scripts without errors. stopRecording()
returns { file: null, duration: 0, size: 0 } instead of throwing, and
addNarration(null) returns a matching stub.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:36:19 +03:00
Nick Shirokov 26c5e849a5 fix(web-test): highlight groups — filter logicGroupContainer, keep _div for grids
Group search in highlight() now filters by !classList.contains('logicGroupContainer')
instead of removing _div selector entirely. This skips invisible Representation=None
groups while preserving grid/table _div elements (frameGrid) that are the actual
highlightable panels (Оргструктура, Системы, БизнесПроцессы).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 16:57:45 +03:00
Nick Shirokov ca681676b4 feat(web-test): highlight groups fix, recording auto-stop, fillField alias
- highlight(): exact match by name ignores size filter (supports Representation=None groups),
  error message lists available elements by category
- startRecording(): { force: true } option to restart if already recording
- executeScript(): auto-stop recording on script error (prevents "Already recording")
- fillField(name, value): silent alias for fillFields({ name: value })

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 15:37:21 +03:00
Nick Shirokov e3a9be0036 feat(web-test): add FormNavigationPanel support, fix --no-record server-side
1. Navigation panel: getFormState() returns `navigation` array with
   form navigation links (e.g. "Основное", "Объекты метаданных").
   clickElement() can now click navigation panel items (kind: navigation).
   DOM: `.navigationItem` inside parent `page{N}` container.

2. --no-record: move recording stub from client-side code injection to
   server-side sandbox export replacement. Stubs startRecording,
   stopRecording, addNarration, showCaption, hideCaption, showTitleSlide,
   hideTitleSlide as no-ops. Covers both direct calls and user wrappers
   like record()/finalize().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 12:10:19 +03:00
Nick Shirokov 361354cdd4 Merge branch 'dev' 2026-03-14 19:39:32 +03:00
Nick Shirokov 2ce7b12c4c feat(web-test): add --no-record flag for exec, document toggle option
- exec --no-record injects no-op record() to skip video recording during
  debugging/testing
- Document clickElement { toggle: true } for tree node expand/collapse
- Document --no-record in SKILL.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 19:39:29 +03:00
Nick Shirokov f244d5e507 Merge branch 'dev' 2026-03-14 19:32:31 +03:00
Nick Shirokov 6cb54a8f96 fix(web-test): show detailed message in fillFields error instead of error code
Previously fillFields errors showed only the error code (e.g. "not_found"),
making it ambiguous whether the field or the value was not found. Now shows
the message (e.g. 'Value "X" not found') when available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 19:32:28 +03:00
Nick Shirokov 75f56603b6 Merge branch 'dev' 2026-03-14 18:48:05 +03:00
Nick Shirokov 55ab172ba4 feat(web-test): clickElement on tree nodes defaults to select, toggle is explicit
Previously clickElement always toggled expand/collapse on tree nodes.
Now default = select (click text), and { toggle: true } = expand/collapse
(click tree icon). Hint in response guides the model to use toggle when needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 18:47:52 +03:00
Nick Shirokov e9e00c906d Merge branch 'dev' 2026-03-14 18:10:41 +03:00
Nick Shirokov 31792a8a2d feat(web-test): search all visible grids for clickElement row targets
Previously findClickTargetScript used querySelector (first grid only),
making clickElement unable to find rows in second+ grids on multi-grid
forms (e.g. system composition wizard). Now uses querySelectorAll to
search all visible grids, and returns gridId so the tree node handler
can locate the correct grid for expand/collapse.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 18:10:25 +03:00
Nick Shirokov fa2e3dd3e7 Merge branch 'dev' 2026-03-14 15:37:21 +03:00
Nick Shirokov 3e8a0a792f fix(web-test): skip includes() fuzzy match for short strings (< 4 chars)
Prevents false positives like "Да" matching "Удаляемые" (group) or
"КомандаУстановитьВсе" (button). Exact and startsWith still work.
Applied to highlight groups, findClickTargetScript buttons/grid-scoped/grid rows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 15:36:49 +03:00
Nick Shirokov d5e4bc3f21 Merge branch 'dev' 2026-03-14 14:28:37 +03:00
Nick Shirokov 7a6e63078d fix(web-test): commit fillTableRow by clicking grid header instead of data row
Clicking a different data row to exit edit mode re-entered edit on that
row, blocking subsequent button clicks like "Записать". Now the add-path
commit clicks the grid header which cleanly exits edit mode without
re-entering it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 14:27:08 +03:00
Nick Shirokov 55b0ffa4fd fix(web-test): pass table scope to highlight in clickElement
highlight() was ignoring the table parameter, always highlighting the
first matching button (e.g. "Добавить" for Входящие instead of
Исходящие). Now clickElement passes { table } to highlight, and
highlight pre-resolves the grid via resolveGridScript to pass
gridSelector to findClickTargetScript — same pattern as clickElement
itself.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 14:20:12 +03:00
Nick Shirokov d06ecb940f Merge branch 'dev' 2026-03-14 13:50:52 +03:00
Nick Shirokov 21de2a4749 fix(web-test): strip dashes in fuzzy match for fillTableRow cell names
CamelCase cell IDs like "ИсходящиеБизнесПроцессПриемник" have no
dashes, but user keys like "Бизнес-процесс приемник" do. The previous
regex only stripped spaces, leaving the dash and causing match failure.
Now strip both spaces and dashes with /[\s\-]+/g in both the Tab-loop
path and the row/dblclick column-lookup path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 13:50:03 +03:00
Nick Shirokov 07be2bcafd fix(web-test): use includes instead of startsWith for grid button id-prefix fallback
Button ids like allActionsРазделыКоманднаяПанель contain gridName
in the middle, not at the start. Using includes() catches both
prefix patterns (ИсходящиеКоманднаяПанель_Добавить) and infix
patterns (allActionsРазделыКоманднаяПанель).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:28:50 +03:00
Nick Shirokov 24a48b4a9f fix(web-test): add Группа+name fallback for grid label extraction
On some forms, #title_div is on the parent group element
(e.g. form0_ГруппаБизнесПроцессы#title_div) rather than
on the grid itself. Add fallback lookup for both getFormState
and resolveGridScript.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:11:10 +03:00
Nick Shirokov 91b5204ab2 feat(web-test): add visual label support for multi-grid tables
Extract group title text from #title_div DOM elements so tables can be
referenced by their visible on-screen names (e.g. "Входящие") in addition
to technical attribute names. Labels appear in getFormState().tables[] and
resolveGridScript cascade matching (exact name → exact label → contains).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:05:23 +03:00
Nick Shirokov f2bd42c54c docs(web-test): add multi-grid forms pattern to SKILL.md
Add "Work with multi-grid forms" section to Common patterns showing
the discover-then-act workflow: getFormState().tables → use table name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 11:56:46 +03:00
Nick Shirokov 7e56cd79db fix(web-test): skip checkbox columns in row clicks + document table parameter
Row selection clicks in deleteTableRow and fillTableRow commit now target
the second visible gridBox instead of the first, avoiding accidental
checkbox toggles on forms with checkbox columns (e.g. BP links master).

Also documents the new `table` parameter in SKILL.md for readTable,
clickElement, fillTableRow, deleteTableRow, and getFormState tables[].

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 11:48:57 +03:00
Nick Shirokov 1abc44334c feat(web-test): add table parameter for multi-grid forms
Add semantic table binding to readTable, clickElement, fillTableRow,
and deleteTableRow — resolves the correct grid by name when a form
has multiple tables (e.g. "Входящие"/"Исходящие" in BP links).

- New resolveGridScript() in dom.mjs: cascade match by gridName → columns
- findClickTargetScript: scoped button search within grid's parent container
- getFormState: reports all grids via tables[] array (table still present for compat)
- All grids[grids.length-1] fallbacks wrapped in gridSelector ternary

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 11:27:37 +03:00
Nick Shirokov 0ca2faa6a6 feat(web-test): navigateSection newline normalization + fillTableRow cell skip
navigateSection now normalizes \r\n to spaces, so callers don't need
literal newlines in section names. fillTableRow direct-edit path skips
cells that already contain the desired value (method: 'skip').

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 20:05:12 +03:00
Nick Shirokov 767b9fcaf0 fix(web-test): refactor pickFromSelectionForm + fillTableRow for tree grids and row commit
pickFromSelectionForm:
- 3-step escalation: scan visible → simple search → advanced search (Alt+F)
- Extract helpers: scanGridRows, dblclickAndVerify, advancedSearchInline
- dblclickAndVerify uses click+Enter instead of dblclick (dblclick toggles tree groups)
- Returns ok:false when selection form stays open (group/folder not selectable)
- Distinguish not_found vs not_selectable errors
- trySelect wrapper continues escalation on ok:false

fillTableRow direct-edit (tree grids):
- Click → dblclick → F4 escalation for entering edit mode
- F4 from INPUT mode for tree grid ref fields
- isTypeDialog check + pickFromTypeDialog for composite types
- Commit via click on different row instead of Escape (Escape cancels in tree grids)

fillTableRow regular path:
- Commit new row after fill loop by clicking another row or grid header
- Prevents Escape (e.g. from closeForm) from cancelling uncommitted new row
- Fixes accumulated unclosed forms from closeForm failing to close

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 19:10:31 +03:00
Nick Shirokov 598e223288 Merge branch 'dev' 2026-03-13 10:57:23 +03:00
Nick Shirokov f7a27e750d feat(db-load-xml, db-load-git): add -UpdateDB flag to combine load + update in one Designer run
Closes #8 — adds /UpdateDBCfg parameter support so users can load config
and update database in a single 1C Designer invocation instead of two.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:57:15 +03:00
Nick Shirokov 15840ed1ca Merge branch 'dev' 2026-03-13 10:43:12 +03:00
Nick Shirokov 733418e630 fix(db-load-git): normalize ConfigDir with Resolve-Path for reliable Ext/ path matching
FullName returns canonical Windows paths, but ConfigDir could have
forward slashes. Resolve-Path ensures consistent format so the
Replace() in Ext/ recursion always matches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:43:11 +03:00
Nick Shirokov b15fb999cf Merge branch 'dev' 2026-03-13 10:38:27 +03:00
Nick Shirokov 5414ac373e fix(db-load-git): use --relative for git diff when configSrc is nested
git diff --name-only returns paths relative to repo root, not cwd.
When configSrc is in a subdirectory (e.g. src/cf), paths were doubled
and files not found. Adding --relative makes git return paths relative
to configSrc. Also filter ErrorRecord objects from PS1 git output.

Fixes #7

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:38:06 +03:00
Nick Shirokov 0c4addaedc Merge branch 'dev' 2026-03-13 10:23:22 +03:00
Nick Shirokov cc0d577fc5 fix(cfe-validate): skip own extension sub-items in check 10
Add is_borrowed_sub_item filter to distinguish borrowed vs own
sub-items inside borrowed objects. Own Attributes/TabularSections/
EnumValues (added by extension) lack ObjectBelonging and
ExtendedConfigurationObject — validating them as borrowed was
a false positive. Inspired by PR #6.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:23:14 +03:00
Nick Shirokov 160a845bd8 Merge branch 'dev' 2026-03-12 17:43:17 +03:00
Nick Shirokov 184e4773a4 fix(web-test): clickElement retries when modal form is still loading
After F4/Enter that opens a modal, clickElement could fail because
detectFormScript found the parent form before the modal appeared.
Now retries up to 2s, re-detecting the form each time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:43:06 +03:00
Nick Shirokov 97105486b5 Merge branch 'dev' 2026-03-12 15:44:51 +03:00
Nick Shirokov 23f4cc0bbd fix(web-test): fillTableRow fuzzy match for CamelCase cell names
Cell IDs in 1C tables are CamelCase without spaces (e.g.
"ВариантыАрхитектурыВариантАрхитектуры"), but users pass keys with
spaces ("Вариант архитектуры"). Added space-stripped fallback to
fuzzy match so fillTableRow correctly maps user keys to grid cells.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:44:43 +03:00
Nick Shirokov c5c67600b3 Merge branch 'dev' 2026-03-12 15:15:36 +03:00
Nick Shirokov 85191dc759 fix(web-test): prioritize groups over buttons in highlight() search order
Group names often collide with command bar buttons (e.g. "БизнесПроцессы"
matched a tiny 38x35 button instead of the 959x580 panel). Move group
search before button/field search with min-size filter (100x50).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:15:16 +03:00
Nick Shirokov 064e42842e Merge branch 'dev' 2026-03-12 15:00:25 +03:00
Nick Shirokov 4507d9b59c feat(web-test): highlight() now finds form groups and panels
Added group/panel search step to highlight() — matches by visible title
or internal name (e.g. highlight('Оргструктура') finds the group container).
Search priority: popups → commands → form elements → groups → sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:00:15 +03:00
Nick Shirokov 17be0ca009 Merge branch 'dev' 2026-03-12 13:30:07 +03:00
Nick Shirokov 8f59d3bc66 fix(web-test): sync video timeline with wall-clock during static pauses
CDP screencast doesn't send frames for static pages, causing video to be
shorter than real time (gap-fill capped at 2s, smart pauses are 4-6s).

- Add _flushFrames() helper on recorder to write duplicate frames on demand
- Call _flushFrames() every 1s during smart TTS pauses in showCaption
- Call _flushFrames() in wait() for long explicit pauses during recording
- Call _flushFrames() in stopRecording for final gap before closing ffmpeg
- Increase gap-fill cap from fps*2 to fps*30 as safety net

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:22:16 +03:00
Nick Shirokov f93a1560a5 fix(web-test): don't treat small data forms as error modals
checkErrorsScript falsely classified small forms (e.g. register record
form opened by "Установить статус") as error modals because they had
< 100 elements + a pressDefault button + staticText. Added input field
check — forms with editInput elements are data entry forms, not errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:50:18 +03:00
Nick Shirokov 298589d7cc fix(web-test): fix amix silence with many adelay inputs (int64 overflow)
ffmpeg amix + adelay with large delays causes timestamp overflow
(dts near INT64_MAX), producing silent/truncated audio. Fix: use a
silence reference track as first amix input with duration=first,
so amix runs for full video length regardless of delayed stream
timestamps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:21:30 +03:00
Nick Shirokov c6a84e2f91 feat(web-test): smart TTS pause in showCaption + fix addNarration robustness
showCaption now auto-waits for estimated TTS duration during recording
(~100ms/char, min 2s). Subsequent wait() uses credit system to avoid
double-waiting. addNarration: cap atempo at 1.3x (was 2.5x), replace
-shortest with explicit -t to prevent video truncation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:59:57 +03:00
Nick Shirokov de7e943de1 fix(cfe-borrow): strip DataPath from AutoCommandBar buttons in borrowed forms
ERP catalog forms (e.g. Номенклатура.ФормаЭлемента) have buttons inside
AutoCommandBar with <DataPath>Объект.Ref</DataPath> — causes "Неверный
путь к данным" on load. DataPath was only stripped from form-level
ChildItems but not from AutoCommandBar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 09:49:50 +03:00
Nick Shirokov 4855cd1e01 merge: fix borrowed form CommandSet/ExcludedCommand/RowPictureDataPath stripping 2026-03-10 22:06:05 +03:00
Nick Shirokov 7abe26afee fix(cfe-borrow): strip CommandSet, ExcludedCommand and RowPictureDataPath from borrowed forms
ФормаСписка (list forms) contain elements invalid in extensions:
- <CommandSet><ExcludedCommand>Create</ExcludedCommand></CommandSet> at form root
- <ExcludedCommand> in nested AutoCommandBars within ChildItems
- <RowPictureDataPath> in table elements (e.g. Список.СостояниеДокумента)

All three cause "Неверное имя команды элемента формы" on load.
Verified against Configurator reference dump (ref-ext-dump-6).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 22:05:33 +03:00
Nick Shirokov 512562ca50 Merge branch 'dev' 2026-03-10 21:42:52 +03:00
Nick Shirokov 84d078bd05 fix(cfe-borrow,form-edit,cfe-patch-method): fix borrowed form structure to match Configurator
- cfe-borrow: keep AutoCommandBar ChildItems (buttons) with CommandName=0
  instead of stripping them — Configurator expects buttons to be present
- form-edit: insert Events section after AutoCommandBar, not before —
  matches Configurator's element ordering
- cfe-patch-method(py): fix \r\r\n double line endings by using
  newline="" in open() calls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:40:16 +03:00
Nick Shirokov 8584021446 fix(cfe-validate): remove false DataPath/TitleDataPath check from Check 11
Configurator stores DataPath inside <BaseForm> as original form snapshot —
this is normal behavior, not an error. Removes false WARN on
Configurator-exported extensions like JR2433.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:00:20 +03:00
Nick Shirokov e7e6c885c7 feat(cfe-validate): add checks 10-13 for deep extension validation
Add sub-item validation (Attribute, TabularSection, EnumValue, Form),
borrowed form structure checks, form dependency analysis (CommonPicture,
StyleItem with platform whitelist, Enum DesignTimeRef), and TypeLink
validation. Fix DataPath false positive by scoping check to BaseForm
content only. Both PS1 and Python ports updated to v1.2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:58:17 +03:00
Nick Shirokov b5a779bd5d fix(cfe-borrow): fix dict key casing in Python auto-borrow (Uuid/Properties)
read_source_object returns keys with capital letters (Uuid, Properties),
but auto-borrow sections for CommonPicture, StyleItem, and Enum used
lowercase. E2E tested: Python port loads into BP_DEMO successfully.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:23:34 +03:00
Nick Shirokov 6df64ae1c1 feat(cfe-borrow): full ChildItems form borrowing with auto-borrow dependencies
Borrow-Form now generates full ChildItems tree (matching Configurator output)
with stripping of DataPath, TitleDataPath, TypeLink, Events, CommandName→0.
Auto-borrows CommonPictures, StyleItems, and Enums+EnumValues referenced by
form elements. Verified loading into BP database with two production forms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:18:12 +03:00
Nick Shirokov 007b4ec69c fix(cfe-borrow): mirror minimal Form.xml changes to Python port
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:20:36 +03:00
Nick Shirokov cf5eae6428 fix(cfe-borrow): generate minimal Form.xml without ChildItems for borrowed forms
Configurator generates borrowed forms with only properties + AutoCommandBar +
empty Attributes — no ChildItems. ChildItems appear only when modifications are
added via form-edit. Copying full ChildItems caused XDTO errors on complex forms
due to unresolvable references (CommonPicture, StyleItem, xr: namespace elements).

Changes:
- Remove ChildItems extraction and output from Borrow-Form
- Strip ChildItems from AutoCommandBar (keep only Autofill property)
- Both main and BaseForm sections now contain only properties + minimal AutoCommandBar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:19:35 +03:00
Nick Shirokov c72f2210b5 fix(cfe-borrow): strip DataPath, Events and preserve form properties in Borrow-Form
Borrowed forms failed to load with "Неверный путь к данным" and "Событие не было загружено"
errors. Root cause: base form elements contained DataPath and Events referencing attributes
and handlers not present in the extension.

Changes:
- Strip <DataPath> from base elements in both AutoCommandBar and ChildItems
- Strip element-level <Events> from both sections
- Collect form-level properties (AutoTitle, WindowOpeningMode, etc.) and write them
  into both main and BaseForm sections
- Update 1c-extension-spec.md with rules 5-7

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:12:24 +03:00
Nick Shirokov 06584c29b2 Merge branch 'dev' 2026-03-09 20:43:43 +03:00
Nick Shirokov d94ffdea99 fix(skd-compile): quote argument-hint to fix YAML frontmatter parsing
Value starting with `[` was interpreted as YAML flow sequence,
breaking frontmatter parsing and the input hint in UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:43:08 +03:00
Nick Shirokov 9f370dd499 docs(role-validate): remove misleading OutFile hint for Cyrillic paths
Cyrillic stdout works fine — the hint caused weak models to waste
an extra turn writing to file and reading it back.

Verified: all 9 validate skills pass on Haiku in 4 turns each.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:30:49 +03:00
Nick Shirokov 903f1f2750 docs(validate): remove redundant ## Использование from all SKILL.md
The section duplicated ## Команда examples in slash-command format that
the model never needs — it receives arguments directly. Second example
paths moved into ## Команда as additional command lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:25:00 +03:00
Nick Shirokov 29b124f3fd docs(validate): concrete examples in SKILL.md, remove auto-resolve notes
- Replace abstract <...> placeholders with concrete paths in ## Команда
- Replace abstract examples with concrete paths in ## Использование
- Remove авторезолв notes from meta/epf/cf/cfe-validate
- Clean up erf-validate: remove Вывод/Верификация/Когда использовать,
  add -Detailed parameter, unify format with other validators

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:17:12 +03:00
Nick Shirokov ffdee04a95 refactor(validate): auto-detect metadata in role-validate, clean up SKILL.md
role-validate: remove MetadataPath param, auto-detect from RightsPath
(Roles/Name/Ext/Rights.xml → Roles/Name.xml). Always validate metadata
when file exists (was 7 checks, now 10). Deduplicate path computation.

SKILL.md: remove redundant auto-resolve notes (placeholder already shows
directory path), fix role-validate examples, replace mxl-validate
ProcessorName/TemplateName with concrete path examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:07:16 +03:00
Nick Shirokov b2a2534b5a feat(validate): auto-resolve directory paths, fix SKILL.md placeholders
Scripts now accept directory paths (e.g. Forms/ИмяФормы) and auto-resolve
to the target XML file. Silent fallbacks handle missing Ext/ level and
descriptor-to-file resolution. SKILL.md: concrete placeholders, unified
quotes, auto-resolve notes, role-validate MaxErrors in params.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:41:38 +03:00
Nick Shirokov 422e397381 feat(validate): brief output by default, -Detailed for verbose
All 10 validation skills (meta, epf, skd, cf, cfe, form, mxl, role,
subsystem, interface) now output a single summary line on success:
=== Validation OK: Type.Name (N checks) ===

Errors/warnings always shown. Full per-check [OK] output behind -Detailed flag.
Removed all N/A check lines. Unified role-validate output format.
Trimmed SKILL.md files from 42-119 to 51-67 lines.
Version bumps: meta-validate v1.2, all others v1.1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:14:44 +03:00
Nick Shirokov 191706b984 Merge branch 'dev' 2026-03-09 15:02:10 +03:00
Nick Shirokov 93e4130ff2 docs(README): update switch.py examples, remove stale src/ line
- Add claude-code --project-dir example for embedded clone workflow
- Remove misleading src/ directory from quick start tree
- Add note about git pull + re-run for updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:01:02 +03:00
Nick Shirokov 3f091b209c feat(switch): support claude-code install, smart runtime warnings, .gitignore propagation
- switch.py v1.2: `claude-code --project-dir` now copies skills (was error before)
- Skip runtime conversion for single-runtime skills (e.g. img-grid stays python)
- Distinguish info ("Python-версия не предусмотрена") from real missing-file warnings
- Print .gitignore recommendations for target project on install
- Copy root-level .gitignore from skills dir during install
- Interactive mode asks project path for all platforms, not just claude-code
- Add .gitignore in skills root (__pycache__/) and web-test/ (node_modules, *.png, *.mp4)
- Sync root .gitignore with all 13 platforms from PLATFORMS registry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:58:49 +03:00
Nick Shirokov 5d4ee6c58c chore: add debug/ to .gitignore for skill eval artifacts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:06:32 +03:00
Nick Shirokov 86c8440531 merge dev: meta-compile v1.2, meta-edit v1.4, batch mode, validation improvements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:46:52 +03:00
Nick Shirokov 42cc7acdbe chore: bump script versions (meta-compile v1.2, meta-edit v1.4)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:45:05 +03:00
Nick Shirokov 72a4015a8d fix(meta-compile,meta-edit): sync type handling and validation between scripts
meta-compile: bare Number→Number(10,0), ValueStorage→xs:base64Binary,
lowercase ref synonyms (catalogref, documentref, enumref).
meta-edit: bare String default 0→10, reserved attribute name warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:39:18 +03:00
Nick Shirokov 843916642c docs(meta-compile): restructure trigger — types in trigger, shorter description
Move type enumeration from description to trigger clause for better
skill discovery matching. Remove implementation details from description.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:09:53 +03:00
Nick Shirokov 84f3662c02 docs(meta-compile): add workflow steps, remove redundant verification section
Add explicit 4-step workflow (write JSON → run script → /meta-edit →
/meta-validate) to guide the model through the optimal path instead of
free exploration. Remove standalone "Верификация" section as it
duplicates workflow step 4.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 17:53:57 +03:00
Nick Shirokov 4cdd3377ae docs(meta-compile): soften reference guidance, prevent XML hunting
- Replace imperative "read reference before compiling" with conditional
  "if you need properties not shown in examples"
- Add explicit instruction not to search for XML in config dumps
- Rename "справочник" → "reference-файл" to avoid confusion with
  Catalog metadata type

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 17:43:04 +03:00
Nick Shirokov 730daf1089 fix(meta-compile): default bare String to String(10), fix SKILL.md examples
Bare `String` type (without length qualifier) now defaults to String(10)
instead of String(0) — matching 1C Designer behavior. String(0) means
unlimited length (NTEXT in SQL), which is rarely intended.

Also fixes SKILL.md: removes misleading `"synonym": "авто"` from JSON
example, clarifies synonym auto-generation from CamelCase name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 17:18:29 +03:00
Nick Shirokov c0255c71d0 docs(meta-compile): slim down SKILL.md with pattern-based examples
Replace 12 type-specific examples with 5 DSL pattern examples
(minimal, attributes, tabularSections, register, batch).
Strengthen reference file instruction to "прочитай перед компиляцией".
203 → 121 lines. Tested on Opus and Sonnet — both pass e2e.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:45:01 +03:00
Nick Shirokov cf1cd1a711 docs(meta-compile): add progressive disclosure reference files
Replace monolithic docs/meta-dsl-spec.md link with 4 domain-specific
reference files inside the skill directory. Agent reads only the
relevant file when compiling a specific type, reducing context usage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:12:49 +03:00
Nick Shirokov 5a1974be4e fix(meta-compile): parse shorthand syntax for Task AddressingAttributes
AddressingAttribute was taking the entire shorthand string (e.g.
"Name: String(100)") as the attribute name instead of parsing it
through Parse-AttributeShorthand. This caused String type without
length qualifiers (NTEXT in SQL), making Index creation impossible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 13:47:38 +03:00
Nick Shirokov 589091510b feat(meta-compile): add batch mode — JSON array in single file
Support passing a JSON array of object definitions in a single file.
Each element is compiled independently via subprocess isolation
(Start-Process in PS1, subprocess.call in PY).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 13:21:32 +03:00
Nick Shirokov 19667caccb feat(meta-validate): add batch mode — pipe-separated paths
Accept multiple object paths via pipe separator (|) in -ObjectPath.
Each object is validated separately with individual results, followed
by a summary line: "Batch: N objects, X passed, Y failed".
Single-path mode unchanged. Version bumped to v1.1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 12:38:21 +03:00
Nick Shirokov 97fc6dbd7f refactor(meta-compile): extract Build-TypeStr helper for type+length combination
Unify inline type string building logic (type + length/precision → "String(100)",
"Number(10,2)") into a shared Build-TypeStr/build_type_str function. Used by both
Parse-AttributeShorthand and Emit-ConstantProperties. Fix: check valueType before
type to avoid treating metadata type name (e.g. "Constant") as data type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 12:13:46 +03:00
Nick Shirokov 49108f72dc docs(meta-dsl-spec): update to v2.1 — reflect e2e-verified fixes
- §4.2: document separate type+length/precision fields in object form
- §7.4 Constant: add length/precision fields
- §7.7 DefinedType: document valueType (singular) alias
- §7.9 ScheduledJob: document CommonModule. auto-prefix for methodName
- §7.10 EventSubscription: document CommonModule. auto-prefix for handler
- §7.13 ExchangePlan: remove codeType/autonumbering/checkUnique (not valid)
- §7.14 ChartOfCharacteristicTypes: default String length 0→100
- §7.20 BusinessProcess: add task to example

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:18:52 +03:00
Nick Shirokov dbb39b7a3e fix(meta-compile): fix String/Number length loss, RegisterRecords format, CommonModule prefix
- Parse-AttributeShorthand: combine type + length/precision from separate
  JSON fields (String→String(N), Number→Number(D,F)) — fixes SDBL error
  "Строка без спецификации длины недопустима"
- Constant valueType: same length combination fix
- DefinedType: accept both valueType (singular) and valueTypes (plural)
- ChartOfCharacteristicTypes: default String length 0→100
- Document RegisterRecords: <xr:Record> → <xr:Item xsi:type="xr:MDObjectRef">
- ScheduledJob.MethodName, EventSubscription.Handler: auto-prepend CommonModule. prefix
- meta-validate check 13: support 3-part method format (CommonModule.Module.Proc)

E2E verified: 18 types (21 objects) pass cf-init → meta-compile → LoadConfigFromFiles → UpdateDBCfg

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:05:29 +03:00
Nick Shirokov 87dc18b120 feat(meta-validate): add method reference and DocumentJournal column checks
Check 13: validates EventSubscription.Handler and ScheduledJob.MethodName
reference format (CommonModuleName.ProcedureName), verifies CommonModule
exists and optionally checks BSL for exported procedure.

Check 14: validates DocumentJournal Column References are non-empty
(empty References causes LoadConfigFromFiles to fail).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:08:46 +03:00
Nick Shirokov ca328e3e8f feat(meta-validate): add cross-object register-registrar check
Detect configDir by walking up from object path to find
Configuration.xml. For AccumulationRegister, AccountingRegister,
CalculationRegister, and InformationRegister (RecorderSubordinate) scan
Documents/*.xml to verify at least one document references the register
in RegisterRecords. Warn if no registrar found.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:00:37 +03:00
Nick Shirokov c2b90a97ef feat(meta-validate): add forbidden property and DocumentJournal checks
Check 12: detect properties that are invalid for a given metadata type
and would cause LoadConfigFromFiles to fail:
- ChartOfCharacteristicTypes: CodeType
- ChartOfAccounts: Autonumbering, Hierarchical
- ChartOfCalculationTypes: CheckUnique, Autonumbering
- ExchangePlan: CodeType, CheckUnique, Autonumbering

Check 10 extensions:
- DocumentJournal: warn on empty RegisteredDocuments
- Add DependenceOnCalculationTypes to enum validation (Check 4)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:49:57 +03:00
Nick Shirokov e717d4a57f fix(meta-compile): remove invalid properties from ChartOf* types
ChartOfCharacteristicTypes: remove CodeType (not a valid property).
ChartOfAccounts: remove Autonumbering, Hierarchical (not valid).
ChartOfCalculationTypes: remove CheckUnique, Autonumbering (not valid),
fix DependenceOnCalculationTypes default from NotUsed to DontUse.

Verified against real ACC 8.3.24 dumps. E2E test passed:
cf-init → meta-compile ×18 → LoadConfigFromFiles → UpdateDBCfg.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:43:21 +03:00
Nick Shirokov 6051972391 fix(meta-compile,meta-validate): fix 7 e2e bugs, add hints and reserved name checks
Group 1: ExchangePlan — remove invalid CodeType/CheckUnique/Autonumbering;
Flowchart.xml — add version="2.17"; Content.xml — fix namespace + version.

Group 2: Add missing GeneratedType categories — DefinedType, ChartOfAccounts
ExtDimensionTypes/Row, CalculationRegister RecalculationsManager/Recalcs.

Group 3: BusinessProcess — emit <Task> property from DSL.

Group 4: Cross-reference [HINT] output after compilation for AccountingRegister,
CalculationRegister, BusinessProcess, ChartOfAccounts (oriented to /meta-edit DSL).

Group 5: Reserved attribute name warnings in meta-compile and meta-validate
(Check 7b); cross-reference validation in Check 10 with [HINT] output.

All changes synced to both PS1 and PY versions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:33:56 +03:00
Nick Shirokov 24751a59de docs(epf-guide): clarify register column category limitation
Explain why stub database may lose DataPath bindings when forms
contain register record sets — source XML lacks dimension/resource/
attribute classification for register fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:06:28 +03:00
Nick Shirokov b824759a05 docs(skills): remove redundant description paragraphs from epf/erf skills
The intro paragraph on line 14 duplicated the frontmatter description
field. Per Anthropic best practices, the body should contain only
implementation details — the heading and frontmatter are sufficient.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:53:13 +03:00
Nick Shirokov fb23cbda56 docs(skills): remove cross-references between epf/erf skills
Drop "см. /erf-*" from epf-build/epf-dump and "Использует общий скрипт
из /epf-*" from erf-build/erf-dump to prevent the model from reading
duplicate skill files and wasting context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:50:14 +03:00
Nick Shirokov 69c89d3d70 fix(meta-compile,stub-db-create): add missing GeneratedType categories
Add 6 missing categories to meta-compile (ps1+py):
- AccountingRegister: ExtDimensions
- ChartOfCharacteristicTypes: Characteristic
- ChartOfCalculationTypes: DisplacingCalculationTypesRow, BaseCalculationTypesRow, LeadingCalculationTypesRow
- BusinessProcess: RoutePointRef

Fix incorrect category name in stub-db-create (ps1+py):
- AccountingRegisterExtDimensionTypes/ExtDimensionTypes → AccountingRegisterExtDimensions/ExtDimensions

Add GeneratedType reference table to 1c-config-objects-spec.md (section 29).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:24:31 +03:00
Nick Shirokov dee85e19d5 docs: update build-spec and epf-guide for auto-stub and dump requirements
- build-spec: replace outdated notes about empty base with auto-stub info
- build-spec: add dump notes about irreversible type loss in empty base
- epf-guide: add build/dump section explaining auto-stub and base requirement

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:40:25 +03:00
Nick Shirokov 87348ec73c docs(skills): add trigger descriptions, remove redundant sections, fix paths
- Add "Используй когда..." triggers to epf-build, epf-dump, erf-build, erf-dump
- Remove "Коды возврата" sections (trivial info Claude already knows)
- Remove Hierarchical tree diagrams from dump skills (Claude sees output directly)
- Fix Windows backslashes to forward slashes in examples

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:35:08 +03:00
Nick Shirokov dd81c85366 fix(stub-db-create): warn about guessed register column categories
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:13:31 +03:00
Nick Shirokov c6f499a099 feat(stub-db-create): scan Form.xml for register column names
Parse form attributes of RegisterRecordSet types and extract column
names from DataPath references. Generate matching Dimension/Attribute
stubs in register metadata so form field bindings survive the build.

Limitation: column categories (Dimension vs Resource vs Attribute)
cannot be determined from EPF sources alone — only names are preserved.

Also add /Out log for UpdateDBCfg errors in both PS1 and PY.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:10:10 +03:00
Nick Shirokov b5826a61c4 docs(epf-dump,erf-dump): mark database connection as required
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:35:44 +03:00
Nick Shirokov 3097811dde fix(epf-dump): require database connection, remove auto-create empty base
Dump in an empty database irreversibly loses reference types (CatalogRef,
DocumentRef, etc.) — they get converted to xs:string. Instead of silently
creating an empty temp database, the script now exits with an error
explaining that a real database is required.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:34:32 +03:00
Nick Shirokov f01f9d6ae8 feat(epf-build): auto-create stub database for EPF/ERF with reference types
Add stub-db-create script (.ps1/.py) that scans EPF XML sources for
reference types (CatalogRef, DocumentRef, EnumRef, etc.) and generates
a minimal 1C configuration with metadata stubs. Supports 14 metadata
types including registers, charts, defined types.

epf-build/erf-build: if no database specified, auto-create stub DB
with matching metadata, build EPF, then cleanup temp DB.

epf-dump/erf-dump: if no database specified, create empty DB with
warning that reference types will be converted to strings.

SKILL.md updated: prefer real database from .v8-project.json first,
fall back to auto-created stub only when unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:27:38 +03:00
Nick Shirokov 0a1f8888dc feat(form-compile,form-edit): add type synonym resolution for resilient DSL
Add Resolve-TypeStr/resolve_type_str to form-compile and form-edit (PS+PY)
that silently normalizes Russian type names (Строка→string, Число→decimal,
Булево→boolean, etc.), Number→decimal alias, and Russian reference prefixes
(СправочникСсылка→CatalogRef, etc.). Also accept + as composite type
separator alongside |. This makes form skills more forgiving when the model
uses meta-compile DSL conventions instead of form-specific ones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:47:15 +03:00
Nick Shirokov 66eb0b19ec Merge dev-web: composite types, d5p1 namespace, IndentationError fixes
- meta-edit/meta-compile: composite types via + separator (PS+PY)
- d5p1 namespace for reference types instead of cfg:
- lxml post-processing fix for d5p1 in meta-edit PY
- meta-info/form-info: normalize d5p1 prefix in readers (PS+PY)
- Fix module-level IndentationError in 10 Python scripts
2026-03-05 14:01:18 +03:00
Nick Shirokov 872675652f fix: normalize d5p1 namespace in info scripts and fix Python IndentationErrors
- meta-info, form-info (PS+PY): recognize dNpN: prefix alongside cfg: in type parsing
- Fix module-level sys.stderr.reconfigure indentation in 9 Python scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 12:08:07 +03:00
Nick Shirokov fde6d346d7 feat(meta-compile): support composite types and fix d5p1 namespace
- Add composite type support via + separator in Emit-TypeContent (PS/PY)
- Fix reference types: cfg: → d5p1: with local xmlns declaration
  in Emit-TypeContent, valueTypes loop, EventSubscription source
- Fix lxml stripping xmlns:d5p1 in meta-edit.py save_xml (post-process)
- Fix IndentationError in meta-compile.py and meta-validate.py
- Document composite type syntax in SKILL.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 12:00:09 +03:00
Nick Shirokov 4490aeb533 feat(meta-edit): support composite types via + separator
Build-TypeContentXml / build_type_content_xml now detect " + " in type
string, split into parts and recursively generate separate <v8:Type>
entries with qualifiers for each type. JSON DSL supports type as array.

Also fix reference types to use local xmlns:d5p1 declaration instead of
root-level cfg: prefix — prevents "Неизвестное имя типа" build errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 11:32:59 +03:00
Nick Shirokov 6958cc558b perf(web-test): detect .confirm notification for early exit in clickElement
Add .confirm CSS selector to the server-response waitForSelector in
clickElement. 1C web client shows notifications (Изменение/Проведение)
as .confirm elements after write/post operations. This allows early
exit instead of waiting the full 10s timeout. Записать: 14s → 2.6s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:58:21 +03:00
Nick Shirokov 8a286d7191 perf(web-test): skip 10s server-wait for grid edit buttons in clickElement
When clicking toolbar buttons like "Добавить" that put focus into a grid
INPUT cell, skip the 10-second waitForSelector for modal/balloon since
no server round-trip is expected. Also replace fixed waits with polling
in fillTableRow add/row paths. Total: 121s → 62s on composite test suite.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:44:52 +03:00
Nick Shirokov a5fa730747 perf(web-test): replace fixed waits with polling in type-direct flow
Replace hardcoded waitForTimeout calls with polling loops that check
DOM state and exit early. Saves ~12s on composite-type test suite.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:33:02 +03:00
Nick Shirokov 53219cae6c fix(web-test): handle calculator/calendar popups and type inheritance in fillTableRow
When filling composite-type cells (String+Number+Date), the previous code
tried paste first and only fell back to type selection if paste was rejected.
This failed when rows inherited a type from previous rows — paste succeeded
but the value was silently converted to the wrong type.

Now when { value, type } is specified:
1. Always clear the cell first (Shift+F4) to reset inherited type
2. Open type dialog (F4) and select the requested type
3. Dismiss calculator/calendar popups with Escape
4. Re-enter edit mode if focus was lost, then paste the value

Tested with primitive types (Число/Строка/Дата) and reference types
(Физическое лицо via selection form). Regression-tested existing
composite-type flow in Операции.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:16:37 +03:00
Nick Shirokov b1187865ec feat(web-test): support composite-type fields in fillTableRow
Cells accepting multiple types (e.g. subconto on account 80.01) now
handled via { value, type } syntax. Paste rejection detected
automatically — F4 opens type dialog, picks type, then selects value
from the catalog form.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:18:27 +03:00
Nick Shirokov 22bf17ee00 feat(web-test): support per-field search in selectValue via object syntax
selectValue now accepts search as object { field: value } for per-field
disambiguation in selection forms. All fields use advanced search (Alt+F)
by specific column — more efficient than simple full-text search on large
tables, and navigates to exact row even in virtual grids.

Also fixes filterList modal cleanup: now checks specific dialog form
instead of generic modalSurface, preventing accidental closure of
parent modal forms (e.g. selection forms).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:59:07 +03:00
Nick Shirokov 2e0dcb773b fix(web-test): detect ambiguous type matches in selectValue
When multiple types match the search term in the type selection dialog,
throw a descriptive error listing all matches instead of silently
picking the first one. This prevents the model from getting a misleading
"not found" error when the wrong type was selected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:08:35 +03:00
Nick Shirokov c958f3f818 feat(web-test): support composite-type fields in selectValue
Add `{ type }` option to selectValue for fields that accept multiple
types (e.g. DocumentRef.*). When specified, selectValue navigates
through the type selection dialog via Ctrl+F search before opening
the value selection form. Auto-detects composite fields when type
is not specified and throws a helpful error message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:51:08 +03:00
Nick Shirokov 684e97e518 docs(web-test): document icon-only section panel limitation
navigateSection() now gives a clear error message when the section
panel is in icon-only mode instead of a confusing "not found" error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:09:16 +03:00
Nick Shirokov ce5651a5d7 feat(switch): add Windsurf, Kilo Code, Cline, Roo Code, Augment, Agent Skills platforms
Add 6 new platforms to switch.py (v1.0 → v1.1), total 13.
All follow the open Agent Skills standard (agentskills.io).
Update README with full platform table and agentskills.io reference.

Closes #4

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:56:02 +03:00
Nick Shirokov e706aca958 Merge branch 'dev-web' 2026-03-03 14:35:55 +03:00
Nick Shirokov 90b3d5d2e9 fix(web-test): require Message element for confirmation detection
Forms with multiple buttons but no form{N}_Message element were
falsely detected as confirmation dialogs. Real 1C confirmations
(Да/Нет) always have a Message element. Now skip forms without it.

Fixes false positives on small EPF forms with custom buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:29:57 +03:00
Nick Shirokov 1b37bad331 docs(web-test): add openFile to testing guide
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:21:05 +03:00
Nick Shirokov 8b0664b18d fix(web-test): avoid confusing small EPF form with info dialog in openFile
Check form change before checkForErrors() to prevent misidentifying
a small EPF form (< 20 elements) as an informational modal dialog.
Only call checkForErrors() on suspiciously tiny new forms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:19:24 +03:00
Nick Shirokov 2af73d25bf fix(web-test): handle follow-up info dialog after security confirmation in openFile
After clicking "Да" on the security confirmation, check for a second
informational modal ("please re-open the file"). If present, dismiss it
and retry the full Ctrl+O → filechooser cycle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:17:33 +03:00
Nick Shirokov 449e2f667e feat(web-test): add openFile() for opening external processors (EPF/ERF)
Opens EPF/ERF files via Ctrl+O → 1C file dialog → native file picker.
Handles security confirmation dialog with up to 2 attempts for re-open.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:11:43 +03:00
Nick Shirokov e032143157 Merge branch 'dev-web': TTS narration, ElevenLabs provider, video recording guide, v8-project reference 2026-03-03 13:18:24 +03:00
Nick Shirokov 09fc3a7f43 docs(v8-project): note that file is in .gitignore due to secrets
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:16:45 +03:00
Nick Shirokov 01315839fb docs: add .v8-project.json reference guide
Consolidate project config documentation into a single guide covering all
fields (v8path, databases, webPath, ffmpegPath, tts, webUrl), with "who fills"
column and resolution algorithm. Replace duplicated format sections in
db-guide.md and web-guide.md with links to the new guide.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:14:08 +03:00
Nick Shirokov 6505fb1986 docs(web-test): update TTS provider recommendations with ElevenLabs findings
Recommend professional voices with educational/business profile (Olga, Artem,
Denis) for ElevenLabs Russian content. Note articulation issues with
multilingual model on Russian terminology (stress, vowel quality).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 12:55:12 +03:00
Nick Shirokov 9e022c60f9 docs(web-test): add TTS provider recommendations to recording guide
Edge TTS recommended for Russian (better stress, intonation, semantic accents),
ElevenLabs for English/multilingual content (less robotic timbre).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 12:19:23 +03:00
Nick Shirokov e23a235ffa fix(web-test): limit ElevenLabs TTS concurrency to 2 and improve error logging
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 12:10:01 +03:00
Nick Shirokov 5bccca2475 feat(web-test): add ElevenLabs TTS provider
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:15:36 +03:00
Nick Shirokov a8d8007846 docs(web-test): update stopRecording return type in recording.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:00:03 +03:00
Nick Shirokov 37d2a5ee15 docs(web-test): add video recording guide for users
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:58:27 +03:00
Nick Shirokov 050d42a457 fix(web-test): use video-time timestamps for precise TTS sync
Caption timestamps now use actual video timeline position (frame
counter) instead of wall-clock time, eliminating sync drift from
non-uniform frame duplication in CDP screencast recordings.

Also replace silence-file concatenation with adelay+amix for
sample-accurate TTS placement, and fix exec timeout for long
scenarios (fetch → http.request with 10min timeout).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:13:32 +03:00
Nick Shirokov 5acb586bbf fix(web-test): fix audio-video sync drift in narration
Screencast frame duplication (Math.round) causes video to be ~5% longer
than wall-clock time. Caption timestamps are wall-clock based, so the
audio track drifted ahead by ~8s at the midpoint of a 5-minute video.

Fix:
- stopRecording() saves recordingDuration in captions.json
- addNarration() reads actual video duration via ffprobe and scales
  caption timestamps by videoDuration/recordingDuration ratio
- Phase 2 timeline now tracks actual cumulative position instead of
  computing gaps from previous caption data (prevents MP3 frame
  quantization drift)
- Also fixed findFfmpeg() → resolveFfmpeg() call in addNarration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:45:30 +03:00
Nick Shirokov 7f6ea32533 refactor(web-test): add resolveEdgeTts() with fallback chain
Mirrors resolveFfmpeg() pattern: tries global/project-level import
first, then tools/tts/node_modules/, then throws error with install
instructions. Caches resolved module for subsequent calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:03:16 +03:00
Nick Shirokov e9b53505ac fix(web-test): move TTS to tools/tts/, use atempo instead of trimming
- node-edge-tts installed in tools/tts/ (alongside tools/ffmpeg/)
- Speed up TTS with ffmpeg atempo when it exceeds gap to next caption,
  instead of hard-cutting the audio

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:46:50 +03:00
Nick Shirokov 6ce36f7d9b fix(web-test): resolve node-edge-tts from tools/node_modules
Dynamic import needs file:// URL on Windows and explicit entry point
for ESM resolution. Package installed in tools/ alongside ffmpeg.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:29:56 +03:00
Nick Shirokov a13f16e49d feat(web-test): add TTS narration for video recordings
showCaption() collects captions with optional speech parameter,
stopRecording() saves .captions.json, addNarration() generates
TTS voiceover (Edge TTS or OpenAI) and merges audio with video.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:10:37 +03:00
Nick Shirokov 8f130f2e83 docs: update project description in README
Reflect the full development cycle the project now covers: from XML
artifacts to database management, web publishing, browser testing,
and video recording.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:34:42 +03:00
Nick Shirokov 26ea09e2ff fix(web-test): correct video color range for H.264 players
JPEG full range (0-255) was tagged as pc/full in H.264 output, but most
players (VLC, etc.) expect limited range (16-235). Convert JPEG→limited
with scale filter and tag as tv. Also switch preset ultrafast→fast for
5-6x smaller files on static screen content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:05:32 +03:00
Nick Shirokov 98c416b5a7 fix(web-test): highlight commands before form elements
When the function panel is open over a form, highlight() was finding
buttons from the hidden form instead of visible commands on the panel.
Move command search (cmd_XXX_txt) to step 1 — before form-scoped
search — so visible panel commands always take priority. Form elements
searched at step 2 only if no command matched.

Highlight search order is now:
0. Open submenu/popup (elementFromPoint overlay)
1. Commands on function panel (visible cmd_ elements)
2. Form elements (buttons, fields, grid rows)
3. Sections (sidebar navigation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:14:26 +03:00
Nick Shirokov 98ece6206e fix(web-test): add startsWith matching to findClickTargetScript
The button/link search in findClickTargetScript jumped from exact
to includes matching, causing "Поступление" to match "Поступление
билетов" instead of "Поступление (акты, накладные, УПД)" when the
shorter name appeared first in DOM order. Add startsWith step for
both name and label between exact and includes matching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:03:34 +03:00
Nick Shirokov 0c0a1aea49 docs: add Kiro to supported platforms in README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:43:24 +03:00
Nikolay-Shirokov 5870fa200f Merge pull request #3 from JohnyDeath/main
Добавлена Kiro в switch.py
2026-03-01 20:38:17 +03:00
Nick Shirokov 7c10e5e4b1 fix(web-test): highlight submenu items and command startsWith matching
- Add submenu/popup as priority 0 in highlight() — checks open
  popups before form search, preventing false matches on grid rows
  behind the popup overlay
- Use elementFromPoint + direct overlay for submenu items instead
  of getElementById (1C duplicates IDs in cloud popups — hidden
  copy in form + visible copy in cloud)
- Add startsWith step between exact and includes for section and
  command matching — fixes "Поступление" matching "Поступление
  билетов" instead of "Поступление (акты, накладные, УПД)"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:06:20 +03:00
Nick Shirokov 665d5579d2 docs(web-test): add highlight API to recording docs and guides
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:06:12 +03:00
Nick Shirokov 0fec18bbc4 fix(web-test): unhighlight fillFields before Tab, not after
Move unhighlight() before the fill action in fillFields — prevents
our overlay staying visible while platform focus moves to next field
on Tab/Enter. Consistent with clickElement/selectValue pattern:
highlight → wait → unhighlight → action.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:34:06 +03:00
Nick Shirokov cc751a344e fix(web-test): fix highlight bugs — search priority, modal overlap, section/command support
- Reorder highlight() search: form elements first, sections/commands as
  fallback. Fixes false match where "ОК" matched section "Покупки" via
  substring .includes() ("пок" contains "ок")
- Unhighlight before action in clickElement/selectValue (was only in
  finally block, causing overlay to cover modals opened by the click)
- Add auto-highlight support to navigateSection and openCommand

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:26:49 +03:00
Nick Shirokov f956749e1e feat(web-test): add element highlighting for video recordings
Add highlight/unhighlight/setHighlight/isHighlightMode functions.
Overlay div tracks element position via requestAnimationFrame — follows
layout shifts from async banner loads. Search order: sections → commands
→ buttons/links → fields → grid rows. Auto-highlight mode integrates
with clickElement, fillFields, selectValue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:47:29 +03:00
Nick Shirokov 2a6f4b1d5f fix(web-test): correct video brightness via color_range flag
JPEG frames from CDP screencast use full range (0-255) but H.264
defaults to limited range (16-235). Add -color_range pc to preserve
full range in output MP4, fixing washed-out/bright appearance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 12:32:39 +03:00
Nick Shirokov 9318d05535 docs(web-test): fix caption timing pattern in recording example
Show caption before action with wait() pause, not after.
Viewer reads what will happen, then sees it happen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 12:25:33 +03:00
Nick Shirokov bb07bfae14 feat(web-test): add showTitleSlide/hideTitleSlide for video intros
Full-screen overlay with gradient background, centered title text,
optional subtitle. Useful for intro/outro frames in video recordings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:50:25 +03:00
Nick Shirokov 38c82f4a2f docs(web-test): update error handling and ё normalization notes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:34:55 +03:00
Nick Shirokov d5fa5349d4 fix(web-test): ё/е normalization, DLB intercept fix, throw on errors
Three improvements to browser automation reliability:

1. ё→е normalization: fuzzy matching now treats ё and е as equivalent
   across all comparison points in both dom.mjs (norm() functions,
   target variables) and browser.mjs (popup, radio, EDD, grid, confirmation
   dialog, advanced search, filter badges). Prevents silent failures when
   script uses ё but 1C displays е or vice versa.

2. DLB intercept handling in selectValue(): added force click + Escape
   fallback when funcPanel overlay blocks the dropdown button click,
   matching the pattern already used in clickElement().

3. Error handling: all exported functions now throw Error instead of
   returning { error } objects. Error messages include function name,
   what was searched, and available alternatives. Scenarios fail fast
   at the broken step; interactive callers can use try/catch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:33:19 +03:00
Evgeny Martynenkov ebc63c0264 Добавлена Kiro в switch.py 2026-03-01 00:21:33 +03:00
Nick Shirokov 99a5c7168a fix(web-test): real-time video playback via frame duplication
CDP screencast sends frames only on screen changes, causing ffmpeg
to compress pauses and produce sped-up video. Now duplicates the
previous frame to fill timing gaps, maintaining real-time speed.
Also add *.mp4 to .gitignore alongside *.png.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:30:46 +03:00
Nick Shirokov 751a6a8f12 fix(web-test): update ffmpeg download links and clarify prerequisites
Use direct gyan.dev URL instead of generic ffmpeg.org. Rewrite recording.md
prerequisites as clear alternatives (project / global / config).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:04:31 +03:00
Nick Shirokov 43a2691d6a feat(web-test): add video recording via CDP screencast + ffmpeg
New functions: startRecording, stopRecording, isRecording, showCaption, hideCaption.
Recording guide in recording.md with setup, API, examples, troubleshooting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:49:47 +03:00
Nick Shirokov e6da514b67 chore(web-test): add source header comments to all scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:32:39 +03:00
Nick Shirokov 1e5c42fa56 docs: clarify auto-activation as primary usage mode in platform table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:09:58 +03:00
Nick Shirokov 59627b0699 merge: dev-switch → main — unified cross-platform switch.py 2026-02-28 19:06:32 +03:00
Nick Shirokov 7b69228d23 feat: add unified switch.py for cross-platform skill porting
Single script to copy skills between AI platforms (Cursor, Codex,
Copilot, Gemini CLI, OpenCode) with path rewriting and optional
runtime switching. Includes interactive mode for newcomers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:05:12 +03:00
Nick Shirokov da0cedf256 docs: fix web-test description — interaction with web client, not browser automation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 18:24:01 +03:00
Nick Shirokov cc6b170488 docs(web-test): restructure guide — scenarios first, then technical details
User-facing examples and use cases at the top (navigation, search,
documents, reports, extensions, debugging), followed by modes explanation,
autonomous scenario example, then API reference tables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 18:12:28 +03:00
Nick Shirokov f9439dce6d docs(web-test): expand guide with detailed API, modes, and complex scenario
- Detailed description of autonomous vs interactive modes with examples
- Full API reference with signatures, return shapes, and code samples
- Complex autonomous scenario: compare stock reports across two warehouses
- Troubleshooting table for common errors
- Keyboard shortcuts reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 18:05:35 +03:00
Nick Shirokov 336466ae82 merge: dev-web → main — web-test browser automation skill 2026-02-28 17:59:24 +03:00
Nick Shirokov 59d223d72b docs: add web-test guide and README entry
- New docs/web-test-guide.md with usage scenarios, API overview, DCS filters
- README: add web-test row to skills table, directory structure, Node.js requirement

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:55:59 +03:00
Nick Shirokov f56f5dc849 docs(web-test): add anti-loop guidelines to SKILL.md
Prevent models from endlessly retrying the same failed search.
Rules: max 2 attempts per approach, try alternatives not repeats,
report partial results instead of silent retry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:53:04 +03:00
Nick Shirokov 1fd3d8ffb8 docs(web-test): rewrite SKILL.md following Anthropic best practices
- Structured API reference with signatures, return types, and inline examples
- Added readSpreadsheet structured format (title, headers, data, totals)
- Added readTable pagination, tree, hierarchy documentation
- Added DCS reportSettings and human-readable labels for fillFields/selectValue
- Added decision guides (when to use which reading/closing method)
- Progressive disclosure: quick start → modes → API → patterns → notes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:49:40 +03:00
Nick Shirokov d6befb0dc8 feat(web-test): DCS report settings — human-readable labels for fillFields/selectValue/getFormState
fillFields({ 'Склад': 'value' }) now auto-resolves via DCS pair label
and auto-enables the checkbox. getFormState() returns reportSettings
array with readable names instead of raw КомпоновщикНастроек... fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:05:16 +03:00
Nick Shirokov 5120b135f5 fix(web-test): use e1cib/app/ for reports and data processors
Reports and DataProcessors need e1cib/app/ prefix (opens app form),
while lists/registers/catalogs use e1cib/list/ (opens list form).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:38:21 +03:00
Nick Shirokov 5d18bf4501 fix(web-test): scope readSpreadsheet to current form, improve headers
Two fixes:
- Scope iframe scanning to current form container (prevents reading
  stale data from other open report tabs)
- Improved header detection: use LAST row before data as detail header,
  previous row as group header with fill-forward for merged cells.
  Fixes two-level headers like "Начальный остаток / Долг клиента"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:34:42 +03:00
Nick Shirokov 366378c4b5 feat(web-test): structured readSpreadsheet with header detection
Parse SpreadsheetDocument into { title, meta, headers, data, totals }:
- Auto-detect header row (most non-empty before first numeric row)
- Group header prefix for duplicate column names (Сейчас/Доступно)
- Data rows as objects {column: value}, only non-empty cells
- Separate totals row (Итого/Всего)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:17:40 +03:00
Nick Shirokov 56203e2b71 feat(web-test): add readSpreadsheet() for extracting report data
Reads 1C SpreadsheetDocument (report output) rendered in iframes.
Collects cells from div[x]/div[y] elements across all frames,
returns { rows: string[][], total }.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:07:19 +03:00
Nick Shirokov ff14880871 docs(web-test): simplify navigateLink examples in SKILL.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:48:12 +03:00
Nick Shirokov a17a81fe98 feat(web-test): normalize navigateLink URLs
- Auto-prepend e1cib/list/ when missing
- Translate English type names to Russian (AccumulationRegister → РегистрНакопления, etc.)
- Accepts: full e1cib/..., short Тип.Имя, or English Type.Имя

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:46:30 +03:00
Nick Shirokov e58f5c1f82 feat(web-test): add navigateLink() for direct 1C navigation links
- navigateLink(url): opens form via Shift+F11 dialog with clipboard paste
- Grant clipboard-read/write permissions on browser context creation
- Register navigateLink in ACTION_FNS for auto-error detection
- Document in SKILL.md with examples (e1cib/list/...)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:37:58 +03:00
Nick Shirokov 0fbdd298ca docs(web-test): improve SKILL.md API discoverability
- getFormState: clarify returns table meta (columns + rowCount), not row data
- readTable: document return shape, add hint to use for grid contents
- closeForm: document {save} parameter and auto-confirm behavior
- Update closing forms patterns with save:true/false/omit variants

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:17:05 +03:00
Nick Shirokov 68fd9bb4a7 feat(web-test): closeForm({ save }) auto-handles confirmation dialog
closeForm now accepts { save: true/false } option:
- save: false → clicks "Нет" on "Save changes?" dialog
- save: true  → clicks "Да" to save and close
- undefined   → returns confirmation as hint (previous behavior)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:06:19 +03:00
Nick Shirokov e18e8cd284 fix(web-test): auto-dismiss pending error modals before actions
Action functions now call dismissPendingErrors() at start, so a leftover
error modal from a previous operation doesn't block subsequent actions.
Diagnostic functions (getFormState, screenshot) are unchanged — they
show current state as-is.

Key fixes:
- Target OK button within modal's form container (#formN_container)
  to avoid clicking wrong pressDefault on the page
- Use force:true click to bypass #modalSurface pointer intercept
- Replace local dismissErrors() in fillReferenceField with shared fn

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:02:29 +03:00
Nick Shirokov 5ea6414585 fix(web-test): detect modal errors without #modalSurface dependency
1C platform shows some modal dialogs (e.g. "Не удалось записать") via
ps*win floating windows WITHOUT setting #modalSurface visible. Removed
the modalSurface gate from checkErrorsScript — now scans all small forms
for button patterns regardless of overlay state. The elCount > 100
threshold already filters content forms reliably.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 13:57:18 +03:00
Nick Shirokov 75558fe46c fix(web-test): detect server-side errors via waitForSelector and ancestry-based button grouping
Two problems solved:
1. Server-side exceptions (ВызватьИсключение in ПередЗаписью) produce modal dialogs
   AFTER the DOM stabilizes. clickElement now uses waitForSelector with MutationObserver
   (doesn't block JS event loop) to detect #modalSurface or .balloon appearance.
2. checkErrorsScript used button IDs to determine form ownership, but 1C modal dialog
   buttons often have empty IDs. Now uses closest('[id$="_container"]') ancestry to
   group pressButtons by form, correctly separating modal buttons from background form
   buttons (e.g. "Зачет оплаты" in ERP order form).

Tested with ТестОшибки CFE extension on ERP — error detected in 7.7s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 13:28:23 +03:00
Nick Shirokov 90ca2a7c4a feat(web-test): auto-detect 1C errors and stop script execution
Action functions (clickElement, fillFields, selectValue, etc.) are now
wrapped to check for 1C errors (modal dialogs, validation balloons)
after each call. When detected, execution stops immediately with full
diagnostic context:

- error: human-readable 1C error message
- step: which API function triggered the error
- stepArgs: arguments passed to that function
- onecErrors: raw balloon/messages/modal data from DOM
- formState: complete form state at the moment of error
- screenshot: auto-captured error-shot.png

This enables autonomous scripts (run mode) to fail fast with enough
information for the caller (agent or human) to diagnose and decide on
corrective action.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:15:17 +03:00
Nick Shirokov 500e05703e docs(web-test): update SKILL.md — autonomous run mode, cleaner workflow
- Add `run <url> <script>` as preferred mode for complete scenarios
- Reorganize workflow: autonomous (run) vs interactive (start/exec/stop)
- Remove obsolete "batch mode" section (replaced by run)
- Update URL section with .v8-project.json guidance
- Simplify script template

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:07:47 +03:00
Nick Shirokov ebda3e6608 feat(web-test): add autonomous run command
`node run.mjs run <url> <script>` — connect, execute, disconnect in one
call. No HTTP server, no session management. Process exits when done.

Useful for CI, subagents, and standalone test scenarios where the full
start/exec/stop lifecycle is unnecessary overhead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:05:34 +03:00
Nick Shirokov 328cb60f18 fix(web-test): strict search input detection in selection forms
Selection forms without a search field (e.g. ERP Соглашения) have only
filter fields like ТипСоглашения. The old code fell back to inputs[0],
typing the search text into the filter field and breaking the form.

Now pickFromSelectionForm only uses inputs whose ID matches known search
field patterns (поиск/search/строкапоиска/SearchString/find). When no
search input is found, it skips text entry and matches rows directly in
the grid — which works because the target value is visible among the rows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 11:46:10 +03:00
Nick Shirokov 5061d83282 fix(web-test): ERP compatibility — CB button fallback, div-based grid
selectValue: try DLB button first, fallback to CB (Choose Button).
ERP uses _CB suffix instead of _DLB for some reference fields
(Соглашение, Склад).

fillTableRow: handle non-INPUT focus between grid cells. ERP's
div-based grid puts DIV.gridBody focus between editable cells on Tab.
Also treat TEXTAREA cells (e.g. Содержание) as editable grid cells.
Added wrap-around detection to exit when Tab loops back to first cell.

Tested: Заказ клиента in ERP — all fields fill correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 11:02:41 +03:00
Nick Shirokov b10802d4d7 revert(web-test): restore fixed delays, keep waitForCondition utility
Smart wait polling showed no measurable speedup in benchmarks
(31.8s vs 32.0s baseline). 1C backend response time (~1.5-2s per
autocomplete) is the real bottleneck, not client-side delay calibration.
Reverted all 5 replacements to original fixed delays to reduce complexity.
Kept waitForCondition() utility for potential future use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 20:09:15 +03:00
Nick Shirokov ae0c3e3278 refactor(web-test): replace fixed delays with smart waitForCondition polls
Add waitForCondition() utility — polls JS expression every 100ms with
timeout fallback. Replace key fixed delays:
- fillReferenceField paste: 2000ms → poll for EDD/cloud (max 2s)
- fillTableRow add: 1000ms → poll for grid INPUT focus (max 2s)
- fillTableRow cell paste: 1500ms → poll for EDD/value (max 1.5s)
- fillTableRow Tab skip/commit: 300-1000ms → poll for focus change

Benchmark: 31.8s vs 32.0s baseline — no measurable speedup because
1C backend response time (~1.5-2s for autocomplete) is the real
bottleneck, not our delay calibration. Code is correct and will
benefit from faster backends.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 20:05:42 +03:00
Nick Shirokov 00ec14aed3 feat(web-test): add required field detection via markIncomplete CSS class
Fields with 1C fill-check enabled show `required: true` in getFormState()
when empty, allowing proactive filling before posting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 19:49:05 +03:00
Nick Shirokov 102a7b8849 fix(web-test): force click before Escape on surface intercept
Escape on document forms triggers "save changes?" dialog. Reorder
retry strategy: try force:true first (no side effects), then Escape
as fallback. Applied to both clickElement and fillReferenceField.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:43:41 +03:00
Nick Shirokov 68e346d645 fix(web-test): improve modal detection, surface retry, search regex
- detectFormScript: lower modal threshold from >=2 to >=1 visible elements
- clickElement: force:true on third retry when surface overlay persists
- filterList/unfilterList: add SearchString pattern for selection forms
- fillTableRow: wrap body in try/catch for structured error returns
- SKILL.md: add keyboard shortcuts reference (F8, Shift+F4, F4, Alt+F)
- gitignore: exclude *.png screenshot artifacts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:31:57 +03:00
Nick Shirokov c8f58b5461 feat(web-test): embed browser automation engine into skill
Move browser.mjs, dom.mjs, run.mjs from external 1c-web-client-mcp
project into .claude/skills/web-test/scripts/. Now the skill is
self-contained — copy .claude/skills/ + npm install is all that's
needed.

- Add scripts/package.json with playwright dependency
- Update SKILL.md with relative runner path and setup section
- Add node_modules/ and .browser-session.json to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:15:35 +03:00
Nick Shirokov ba963739d8 docs(web-test): advanced search works on hierarchical catalogs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:57:38 +03:00
Nick Shirokov afe760af4b docs(web-test): fix hierarchical list — simple filterList works
Simple filterList('text') works on hierarchical catalogs after
the search input regex fix. No need to switch view mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:40:00 +03:00
Nick Shirokov c6eae770f5 docs(web-test): fix hierarchical list — switch to flat mode before filter
The Alt+F (Найти) in 1C navigates the tree instead of filtering.
Correct approach: Ещё → Режим просмотра → Список, then filterList.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:32:37 +03:00
Nick Shirokov d28bea8f0a docs(web-test): add dblclick, closeForm, hierarchical, lifecycle docs
- clickElement {dblclick:true} for opening items from lists
- closeForm() API and closing forms patterns table
- Hierarchical lists search gotcha with filterList
- Startup lifecycle: start blocks, run in background
- status command in workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:14:33 +03:00
Nick Shirokov 475b6d9544 docs(web-test): rewrite SKILL.md for CLI runner workflow
- Replace MCP-based workflow with run.mjs CLI runner (start/exec/shot/stop)
- Add interactive mode (stdin pipe) and batch mode (file exec)
- Compact API reference table, remove verbose return value docs
- Add filterList/unfilterList/deleteTableRow (missing before)
- Remove implementation details (EDD, DLB internals)
- Universal paths, no hardcoded infrastructure specifics

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 09:38:15 +03:00
Nick Shirokov 2d69ecf709 docs: clarify PS1 as primary runtime, Python as derived port
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:45:19 +03:00
Nick Shirokov 88f74e96f0 fix(python): add stderr UTF-8 encoding for Windows compatibility
Without reconfiguring stderr, Cyrillic error messages appear garbled
on Windows (cp1251 default). Mirrors the existing stdout fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:31:27 +03:00
Nick Shirokov bce2d7c85c fix(epf-build,epf-dump): remove double-quoting in subprocess arguments
Same issue as db-* scripts: embedded quotes in list-based subprocess
args get escaped by list2cmdline, causing 1C to receive literal quote
characters in paths. Python's list2cmdline handles quoting automatically
for separate flag+value pairs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:15:53 +03:00
Nick Shirokov 8f3bde5cfc fix(db-create): restore quotes in CREATEINFOBASE connection string
File="path" quotes are part of 1C connection string syntax, not shell
quoting. Previous fix correctly removed quotes from /Out and /F args
(where list2cmdline handles quoting) but incorrectly removed them from
the CREATEINFOBASE connection string too.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:00:38 +03:00
Nick Shirokov 85cdea925e fix(db-*): remove double-quoting in subprocess arguments
Python subprocess.run() with list args handles quoting automatically.
Extra f'"{path}"' wrapping made quotes literal, breaking 1cv8.exe CLI.
Removed inner quotes from all 8 db-* scripts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:49:05 +03:00
Nick Shirokov 679f6bae94 fix(meta-compile): handle dict-format attributes in tabular sections
Python list(dict) returns only keys, losing values. Added _as_list()
helper to convert dict {"K":"V"} → ["K:V"] before passing to
parse_attribute_shorthand(). Fixes TS attribute generation for all
dict-format inputs (attributes, accountingFlags, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:16:52 +03:00
Nick Shirokov c5abfc3a4f fix(form-add): resolve directory path to sibling .xml file
When ObjectPath is a directory (e.g. Catalogs/Номенклатура),
auto-resolve to the sibling XML file (Catalogs/Номенклатура.xml)
before parsing. Matches behavior of other edit scripts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:02:56 +03:00
Nick Shirokov d9ce7b03cc fix(role-info): add missing -NoProfile flag to SKILL.md
Normalize PowerShell invocation to match all other skills,
ensuring clean round-trip through switch-to-python/switch-to-powershell.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 16:38:15 +03:00
Nick Shirokov d6abb2b651 fix(python): add stdout UTF-8 encoding for Windows compatibility
Python on Windows defaults to cp1251 for piped stdout, which cannot
handle Unicode box-drawing characters used in info/analysis output.
Added sys.stdout.reconfigure(encoding="utf-8") to all 59 Python scripts.

Tested on real config data: epf-init, epf-validate, cf-info, cf-validate,
meta-info, form-info, role-info, skd-info, subsystem-info — all passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 16:29:26 +03:00
Nick Shirokov 86a959a354 feat(crossplatform): add Python 3 ports for all 58 PS1 skill scripts
Add cross-platform Python alternatives alongside existing PowerShell
scripts. PS1 remains the default runtime; Python is opt-in via switch
scripts. All parameters are identical between runtimes.

New files:
- 58 Python scripts in .claude/skills/*/scripts/*.py
- scripts/switch-to-python.py and switch-to-powershell.py
- docs/python-porting-guide.md
- __pycache__/ added to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 16:16:07 +03:00
Nick Shirokov 8e7125d850 docs(web-test): fix navigation limitation — Shift+Tab works in 1C
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:27:08 +03:00
Nick Shirokov fa9fae49c2 docs(web-test): add fillTableRow API — table part row filling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:25:27 +03:00
Nick Shirokov c0e18ed428 docs(web-test): update SKILL.md — selectValue 3 patterns, clipboard paste
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 17:17:02 +03:00
Nick Shirokov 64453ebe08 docs(web-test): update SKILL.md — fillFields supports reference fields
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 13:32:56 +03:00
Nick Shirokov c91ad0a158 feat(web): add /web-test skill for browser automation scripting
Skill generates and runs .mjs scripts using browser.mjs API.
Includes function table, script template, and usage notes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:23:49 +03:00
Nick Shirokov 6b5992de34 Merge branch 'dev-web' 2026-02-22 18:53:06 +03:00
Nick Shirokov 9d5cbaab9f docs(readme): add web skills to groups table, specs and repo structure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:51:33 +03:00
Nick Shirokov fe8fa4bc3f fix(web): correct VRD service element format for 1C 8.3
ws uses pointEnableCommon (not publishByDefault), OData is attribute
enableStandardOdata on <point> (not child element). Verified against
live BP-demo: WSDL returns 200, SOAP call succeeds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:46:35 +03:00
Nick Shirokov 028c5292d7 feat(web): publish WS, HTTP services and OData by default
VRD now includes <ws>, <httpServices>, <standardOdata> elements so all
service types are available out of the box. web-info shows [WS HTTP OData]
tags per publication. Docs updated with service URL patterns and scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:38:55 +03:00
Nick Shirokov 31debfb61b fix(web-stop): add restart hint and "after execution" section
- Script: hint now mentions both restart (/web-publish) and delete (/web-unpublish)
- SKILL.md: add "После выполнения" section with restart/delete options

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:08:28 +03:00
Nick Shirokov a110c17066 docs(web): add multi-user publishing scenarios
- SKILL.md: add "multiple users" section with replace vs parallel rules
- web-guide: add scenarios for user switch and parallel publications

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 17:48:59 +03:00
Nick Shirokov b535dff609 fix(web): improve skills after haiku agent testing
- web-unpublish: add -All flag to remove all publications at once
- web-stop: add hint about /web-unpublish after stopping
- web-publish SKILL.md: emphasize mandatory -V8Path/-UserName params
- Fix Port default comment (8080 → 8081)
- Clean up descriptions: semantic matching only, no technical details
- web-guide: add "delete all" scenario

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 17:39:02 +03:00
Nick Shirokov 96b400ddb9 chore(web): change default port from 8080 to 8081
8080 is too commonly used (Tomcat, Jenkins, dev servers).
8081 is less likely to conflict in dev environments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:40:33 +03:00
Nick Shirokov b68013b2f2 fix(web): port check, process isolation, startup diagnostics
- web-publish: check port availability before starting, show which process
  holds it; run httpd -t on startup failure for diagnostics
- All scripts: filter httpd processes by path (Resolve-Path match) to avoid
  killing or misidentifying a global Apache installation
- web-info: warn about foreign httpd processes
- web-stop: only stop our Apache instance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:38:53 +03:00
Nick Shirokov e2f765fcc0 fix(web-publish): use WebClient for download, comment default Listen 80
- PS 5.1 Invoke-WebRequest fails on 308 redirects; WebClient handles them
- Updated Apache URL to 2.4.66 VS18 (current release)
- Comment out default Listen 80 when adding marker block to avoid port conflict

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:34:43 +03:00
Nick Shirokov a3e9e3c907 chore: add tools/ to .gitignore for portable Apache
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:29:34 +03:00
Nick Shirokov bc4778d6cc feat(web): add web publishing skills (web-publish, web-info, web-stop, web-unpublish)
Phase 1 of web publishing: publish 1C infobases via portable Apache HTTP Server.
Closes the feedback loop: edit → load → update → open in browser.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:28:22 +03:00
Nick Shirokov 2a0b896f5d Merge branch 'dev' 2026-02-21 20:03:06 +03:00
Nick Shirokov bc9087957f fix(skills): add file-not-found fallback for Dir/Name/Name.xml paths
When a non-existent path like Dir/Name/Name.xml is passed (common when
models construct paths from directory structure), auto-resolve tries
Dir/Name.xml as sibling. Applied to all 7 scripts with path resolution.
Also update meta-info SKILL.md to encourage skill usage over direct XML reads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:46:38 +03:00
Nick Shirokov 78e252af1e fix(skills): add sibling XML auto-resolve for directory paths
When a directory is passed (e.g. src/Name or Catalogs/Name), the
auto-resolve now also checks for a sibling file ../Name.xml, which
is the standard layout for both 1C config dumps and EPF/ERF sources.

Affected: meta-info, meta-edit, meta-validate, epf-validate,
subsystem-edit, subsystem-info, subsystem-validate (7 scripts).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:04:55 +03:00
Nick Shirokov 4c5e10a958 fix(db-run): warn on ERF files passed to /Execute
/Execute is EPF-only; passing .erf causes empty form or type confusion.
db-run now detects .erf extension and launches the database without
/Execute, advising the user to open the report via File→Open.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 18:48:44 +03:00
Nick Shirokov 7d0d2dbf3d Merge branch 'dev' 2026-02-21 17:52:44 +03:00
Nick Shirokov 89d1ad3a12 docs(readme): update status to testing phase, add specs index link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:52:10 +03:00
Nick Shirokov 9c75e9392e Merge branch 'dev' 2026-02-21 17:40:38 +03:00
Nick Shirokov 5f7ee6fcae fix(form-validate): skip DataPath check for base elements in borrowed forms
In extension forms with BaseForm, elements with id < 1000000 belong to the
base configuration and their attributes are not present in the extension.
Skip DataPath→Attribute validation for these elements to avoid false errors.
Show "N base skipped" in output for transparency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:34:36 +03:00
Nick Shirokov 6f32e18e37 improve(skills): auto-resolve ConfigPath, auto-register forms, handle LF line endings
- cfe-init, cfe-borrow SKILL.md: auto-resolve ConfigPath from .v8-project.json configSrc
- form-compile: auto-register <Form> in parent ChildObjects from OutputPath convention
- form-compile SKILL.md: document new workflow (form-add no longer required first)
- cfe-borrow: handle LF line endings in OuterXml split (-split "\r?\n")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:22:05 +03:00
Nick Shirokov 3565e1c97f fix(cfe): 6 fixes from E2E test — Manager types, borrowed form structure, ConfigPath, guard checks
1. meta-compile + cfe-borrow: add Manager GeneratedType for Report/DataProcessor
2. cfe-borrow: rewrite Form.xml generation — extract only visual elements
   (AutoCommandBar + ChildItems), replace CommandName→0, strip Attributes/Events/Parameters
3. cfe-init: add -ConfigPath to auto-resolve Language UUID and CompatibilityMode
4. form-add: guard against overwriting existing Form.xml and Module.bsl
5. docs: update GeneratedType table for Report/DataProcessor
6. docs: rewrite section 5.4.2 with accurate borrowed form structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:39:27 +03:00
Nick Shirokov 28b967f591 feat(cfe,form): add borrowed form support across 6 skills
- cfe-borrow: borrow forms via Type.Name.Form.FormName, auto-borrow parent,
  generate Form.xml with BaseForm + metadata + empty Module.bsl
- form-edit: formEvents, elementEvents, callType on events/commands,
  auto-detect extension mode (IDs 1000000+)
- form-info: [EXTENSION] marker, callType on events/commands, BaseForm footer
- form-validate: callType value checks, extension ID range warnings,
  BaseForm presence, callType-without-BaseForm detection
- cfe-diff: form-level analysis in Mode A — borrowed/own forms,
  callType interceptors on events and commands
- cfe-patch-method: warn if Form.xml missing for .Form. paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 14:59:16 +03:00
Nick Shirokov 9c1985b710 docs(cfe): expand section 5.4 with borrowed form structure (BaseForm, callType, IDs)
Previously section 5.4 only documented the metadata XML of borrowed forms.
Now covers: two-part Form.xml structure (result + BaseForm), callType attribute
(Before/After/Override) on events and commands, ID numbering convention (1000000+),
own forms vs borrowed forms distinction, and form module patterns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 14:23:33 +03:00
Nick Shirokov 99d37fb494 Merge branch 'dev' 2026-02-16 20:31:52 +03:00
Nick Shirokov 48de4cdc2a fix(db-run): use single-string ArgumentList for Cyrillic /Execute paths
Start-Process without -NoNewWindow uses ShellExecute API which corrupts
Cyrillic characters when ArgumentList is passed as an array. Switching
to a single concatenated string fixes file-not-found errors for paths
like МояОбработка.epf.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 20:15:20 +03:00
Nick Shirokov 544893b781 fix(skills): use forward slashes in script paths per best practices
Bash on Windows strips backslashes in unquoted paths, causing
"file not found" errors. Forward slashes work cross-platform.
Also fix pwsh → powershell.exe in epf-init and epf-add-form.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 20:01:30 +03:00
Nick Shirokov 8ecc5764ed feat(db,epf): add .ps1 wrapper scripts for all 1cv8 CLI skills
Wrap all remaining 1cv8.exe CLI calls with Start-Process .ps1 scripts
to fix Cyrillic parameter corruption in PowerShell 5.1 when using & operator.

New scripts (7):
- db-update.ps1: DESIGNER /UpdateDBCfg with Dynamic/Server/WarningsAsErrors
- db-dump-cf.ps1: DESIGNER /DumpCfg with Extension support
- db-load-cf.ps1: DESIGNER /LoadCfg with Extension support
- db-create.ps1: CREATEINFOBASE with UseTemplate/AddToList
- db-run.ps1: ENTERPRISE with Execute/CParam/URL (background, no wait)
- epf-build.ps1: DESIGNER /LoadExternalDataProcessorOrReportFromFiles (shared with erf-build)
- epf-dump.ps1: DESIGNER /DumpExternalDataProcessorOrReportToFiles (shared with erf-dump)

Updated SKILL.md (9): db-update, db-dump-cf, db-load-cf, db-create,
db-run, epf-build, epf-dump, erf-build, erf-dump — all now reference
powershell.exe -NoProfile -File invocation with parameter tables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 19:31:18 +03:00
Nick Shirokov 329d94dc55 feat(cfe): add Russian type synonyms to cfe-borrow, improve cfe-diff description
cfe-borrow silently resolves Russian type names (Справочник→Catalog, etc.)
as a fallback when the model uses the wrong type prefix. cfe-diff description
updated with better trigger words for agent discovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 18:50:13 +03:00
Nick Shirokov 7268b169d8 feat(skd,subsystem): add -Value param to skd-compile, full mode to skd-info and subsystem-info
- skd-compile: replace mandatory -JsonPath with -DefinitionFile/-Value pair,
  allowing inline JSON without temp files
- skd-info: extract 6 mode bodies into functions, add -Mode full combining
  overview+query+fields+resources+params+variant in one call
- subsystem-info: extract overview/content/ci into functions, add -Mode full
  combining all three in one call
- Update SKILL.md docs and guides accordingly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 18:29:00 +03:00
Nick Shirokov 2a4d2bf8df fix(skd-edit): add query modification trigger to skill description
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:58:32 +03:00
Nick Shirokov 6e7284fc79 Merge branch 'dev' 2026-02-16 17:54:19 +03:00
Nick Shirokov c9e991e1e8 docs(README): add subsystem-guide links to skills table and docs tree
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:53:42 +03:00
Nick Shirokov 2a0fff1416 Merge branch 'dev' 2026-02-16 17:38:33 +03:00
Nick Shirokov 1364f22df3 docs: add subsystem and command interface guide
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:35:18 +03:00
Nick Shirokov 4b0304d0c8 docs(db-guide): update resolution algorithm, add glob patterns for branches
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:14:36 +03:00
Nick Shirokov cfcc633257 docs: update README and guides with epf-validate, erf-validate, meta-remove
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:12:25 +03:00
Nick Shirokov d7f012b307 fix(meta-remove): exclude Configuration.xml, ConfigDumpInfo.xml and Subsystems from both search loops
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:04:55 +03:00
Nick Shirokov 27bb08d127 fix(meta-remove): add reference check before deletion and fix PS 5.1 variable interpolation
Block deletion when object has references in attributes, code, or forms.
Add -Force parameter to override. Exclude ConfigDumpInfo.xml from ref check.
Fix ${objType}.${objName} syntax for PS 5.1 compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:55:22 +03:00
Nick Shirokov 151ded9bae feat(skills): add epf-validate, erf-validate and meta-remove skills
- epf-validate/erf-validate: 10-check structural validator for EPF/ERF XML
  sources (root structure, InternalInfo/ClassId, properties, ChildObjects
  types/ordering, cross-references, attributes, tabular sections, name
  uniqueness, file existence, form descriptors). Single PS1 script
  auto-detects EPF vs ERF.

- meta-remove: delete metadata objects from config XML dump — removes files,
  deregisters from Configuration.xml ChildObjects, recursively cleans
  subsystem Content references. Supports -DryRun and -KeepFiles.

- db-list: updated resolution algorithm with glob pattern support for
  branch matching and post-execution registration offer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:35:23 +03:00
Nick Shirokov d84a2fb4cf Merge branch 'dev' 2026-02-16 16:13:12 +03:00
Nick Shirokov 05362aeb96 feat(skills): support raw connection params and offer to register untracked databases
Add priority step for user-provided connection parameters (path, server)
before name-based lookup in .v8-project.json. After task completion,
offer to register untracked databases via /db-list add.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:05:40 +03:00
Nick Shirokov 01d02065a3 refactor(skills): unify database and platform resolution across all skills
Replace duplicated "Разрешение базы данных" sections in 8 db-* skills
with a compact "Параметры подключения" block referencing .v8-project.json.
Add Git branch-based database resolution priority (databases[].branches
matched against current branch before falling back to default).

Migrate epf-build, epf-dump, erf-build, erf-dump from V8_PATH/V8_BASE
environment variables to .v8-project.json — registered databases are now
preferred over empty build bases, solving XDTO errors with reference types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 15:52:30 +03:00
Nick Shirokov a711f05acc Merge branch 'dev' 2026-02-15 22:57:46 +03:00
Nick Shirokov 7003a46ad0 fix(meta): emit attribute properties based on stored/non-stored object context
DataProcessor/Report attributes incorrectly included Indexing, FullTextSearch,
DataHistory, FillFromFillingValue, FillValue, and Use properties. Added
"processor" and "processor-tabular" contexts to both meta-compile and meta-edit.
Also fixed Use emitted for Document (should be Catalog-only).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:57:35 +03:00
Nick Shirokov e29c184f8e fix(meta-compile): fix invalid XML properties and improve JSON input flexibility
A) XML bugs: skip FillFromFillingValue/FillValue for tabular attributes,
   emit Use=ForItem only for Catalog tabular sections (not Document).
B) JSON input: accept "objectType" as alias for "type", normalize array-format
   tabularSections, add "Каталог" synonym for "Catalog".
C) Update specs to match corrected behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 20:42:04 +03:00
Nick Shirokov 38c0ce11a9 fix: quote argument-hint values starting with [ in YAML frontmatter
YAML parses [value] as array, not string. Added quotes to 7 SKILL.md files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 20:14:20 +03:00
Nick Shirokov fcc85c9c6e fix(db): improve skill docs after comprehensive testing
- Add Russian morphology-aware matching for aliases and names
- Standardize empty password handling: omit /P entirely
- Add server base examples to db-create, db-load-cf, db-dump-xml, db-load-git
- Fix Unstaged description to include untracked files
- Add Partial mode hint to db-dump-xml

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 20:05:37 +03:00
Nick Shirokov 9331aa7825 Add .v8-project.json to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 19:56:30 +03:00
Nick Shirokov d6ad1eacdb feat(db): add 9 database management skills
- db-list: manage .v8-project.json registry (CRUD, resolve by id/alias/branch)
- db-create: CREATEINFOBASE for file and server databases
- db-dump-cf / db-load-cf: dump/load configuration as CF binary
- db-dump-xml: dump configuration to XML (full/incremental/partial/updateInfo)
- db-load-xml: load configuration from XML (full/partial)
- db-update: UpdateDBCfg with dynamic/background options
- db-run: launch 1C:Enterprise in user mode
- db-load-git: detect Git changes and partial-load into database
- Add db-guide.md, update README.md and build-spec.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 19:55:56 +03:00
Nick Shirokov 52875b4dea Expand build-spec.md to full 1C Designer batch mode reference
Cover configuration operations (CF, XML dump/load, partial load),
DB update, enterprise mode, connection params, authentication,
ConfigDumpInfo.xml — verified against vendor docs and real scripts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 17:26:50 +03:00
Nick Shirokov 2698a2b80b Merge branch 'dev' 2026-02-15 17:12:53 +03:00
Nick Shirokov 8e8660c52b Remove redundant reference.md files for cfe-init and cfe-borrow
After enriching SKILL.md bodies, the reference.md files became 90%+
duplicated. Moved the one unique bit (Version hint) into cfe-init SKILL.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:41:41 +03:00
Nick Shirokov 5d3eccc8eb Improve skill descriptions: add WHEN triggers, remove technical details
- Add "Используй когда/после..." triggers to 26 skill descriptions for better discovery
- Remove technical implementation details from descriptions (file names, XML elements, check lists)
- Enrich CFE skill SKILL.md bodies with parameters, examples, prerequisites, verification
- Clean description pattern: WHAT the skill does + WHEN to use it (user-facing terms only)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:37:12 +03:00
Nick Shirokov b8e3107d14 feat(cfe): add configuration extension skills
Add 5 new skills for 1C configuration extensions (CFE):
- cfe-init: create extension scaffold with Configuration.xml, Languages, Roles
- cfe-borrow: borrow objects from configuration with ObjectBelonging=Adopted
- cfe-patch-method: generate &Перед, &После, &ИзменениеИКонтроль decorators
- cfe-validate: validate extension structure with 9 checks
- cfe-diff: analyze extension and check transfer status

Remove ConfigDumpInfo.xml from cf-init scaffold as it's not required
for 1C configuration source files. Add cfe-guide documentation.
2026-02-15 16:13:55 +03:00
Nick Shirokov aae69664c5 Add CFE extension source format specification
New spec covers: extension Configuration.xml properties, borrowed vs own
objects (ObjectBelonging/ExtendedConfigurationObject), type extension
mechanisms (xr:PropertyState, xr:ExtendedProperty), module interceptors
(&Before/&After/&Instead), diff markers, predefined items, and full
directory structure reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:36:27 +03:00
Nick Shirokov bd947f2c0b Remove skill references from specs index
Specs index documents file formats only, not skills.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:00:31 +03:00
Nick Shirokov 1b6ab2f144 Add configuration root skills (4 new cf-* skills) and guide
New skills for working with root-level 1C configuration files:
- cf-info: analyze configuration structure (3 modes: brief/overview/full)
- cf-init: scaffold empty configuration (Configuration.xml, ConfigDumpInfo.xml, Languages/)
- cf-validate: validate structural correctness (8 checks)
- cf-edit: edit properties, ChildObjects, default roles (6 operations)

Also adds docs/cf-guide.md and updates README and specs index.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:00:13 +03:00
Nick Shirokov a6a708d14d Add subsystem and interface skills (6 new skills)
- subsystem-info: analyze subsystem structure (overview, content, ci, tree modes)
- subsystem-compile: create subsystem from JSON definition
- subsystem-edit: edit Content, ChildObjects, properties of existing subsystem
- subsystem-validate: validate subsystem XML structure (13 checks)
- interface-edit: edit CommandInterface.xml (hide/show, place, order)
- interface-validate: validate CommandInterface.xml structure (13 checks)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 21:52:17 +03:00
Nick Shirokov 3ec2d2594c Add root configuration spec and unified specs index
New docs:
- 1c-configuration-spec.md: Configuration.xml properties, ConfigDumpInfo.xml,
  Ext/ directory, Languages, 17 additional object types (CommonPicture,
  SessionParameter, FunctionalOption, etc.), version 2.17→2.20 differences
- 1c-specs-index.md: single entry point linking all 44 object types,
  nested formats (Form, DCS, MXL, Rights), EPF/ERF, and DSL specs

Updated cross-references in 1c-config-objects-spec.md and 1c-subsystem-spec.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 20:58:32 +03:00
Nick Shirokov 08d29c0341 Add meta-guide.md and link from README
Guide covers meta-* skills: workflow, 23 object types, inline/JSON modes,
typical scenarios (create, edit, validate), file structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 19:25:24 +03:00
Nick Shirokov 37ecb77256 Split meta-edit SKILL.md into compact router + 3 reference files
SKILL.md reduced from 391 to 105 lines (loaded every invocation).
Detailed syntax moved to on-demand reference files:
- child-operations.md: inline ops for attrs, TS, dims, resources, enums
- properties-reference.md: modify-property, Owners, RegisterRecords, etc.
- json-dsl.md: JSON mode structure, synonyms, supported object types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 19:14:34 +03:00
Nick Shirokov 9cfb62c5b1 Add CommandGroup, CommonCommand and object command specs to subsystem spec
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:35:13 +03:00
Nick Shirokov fff77d97ca meta-edit v1.3: positional TS-attr insert, modify-ts, JSON combo example
- add-ts-attribute now respects >> after / << before positioning
- Add modify-ts inline operation for TS properties (synonym, fillChecking, etc.)
- Add JSON combo example (create + edit TS in one definition) to SKILL.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:25:53 +03:00
Nick Shirokov 484ee44387 Add subsystem and command interface XML format specification
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:23:03 +03:00
Nick Shirokov 47174ee236 Rename docs/1c-xml-format-spec.md → docs/1c-epf-spec.md for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:19:51 +03:00
Nick Shirokov d02ca602a4 Update README and guides for renamed/new ERF skills
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:14:05 +03:00
Nick Shirokov f3b3f26af9 Rename /epf-remove-form → /form-remove, /epf-remove-template → /template-remove
Universal naming, ObjectName parameter (alias ProcessorName for compat).
template-remove now clears MainDataCompositionSchema if removed template was referenced.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:06:11 +03:00
Nick Shirokov be47935973 Add ERF skills and universalize template/help skills
- Add /erf-init: scaffold external report with optional --WithSKD
- Add /erf-build, /erf-dump: instructive skills for ERF build/dump CLI
- Rename /epf-add-template → /template-add: universal, auto-fill MainDataCompositionSchema for reports
- Rename /epf-add-help → /help-add: universal for any object type
- Extend /form-add: support ExternalDataProcessor and ExternalReport
- Update cross-references in epf-init, epf-bsp-init, epf-build, epf-dump

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:00:36 +03:00
Nick Shirokov 1312cd7db4 Expand EPF spec: object attributes, ChildObjects order, DCS template type
Add missing documentation: object-level Attributes with full 23-property
reference table, fixed ChildObjects ordering (Attribute → TabularSection →
Form → Template), DataCompositionSchema template type, expanded TabularSection
attribute properties (FillFromFillingValue/FillValue), cross-reference to
ERF spec.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:38:47 +03:00
Nick Shirokov a81c26afda Add TS attribute operations to /meta-edit: add/remove/modify attrs inside tabular sections
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:23:21 +03:00
Nick Shirokov 7044f125ed Add external report (ERF) XML format specification
Document the ExternalReport format based on analysis of 6 sample exports
(empty, withEmptySKD, withSimpleSKD, withModuleAndForm, withAttr, ERP report).
Covers differences from EPF: ClassId, Properties, GeneratedType naming,
report-specific form properties (ReportFormType, ReportResult, DetailsData),
object attributes, and module events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:20:10 +03:00
Nick Shirokov 989f4e49d9 Add inline mode and complex properties to /meta-edit skill
- Inline mode (-Operation/-Value) as alternative to JSON -DefinitionFile
  for quick single operations: add/remove/modify attributes, TS, dims,
  resources, enum values, forms, templates, commands
- Batch syntax with ;; separator, positional insertion (>> after, << before)
- Complex property support: Owners, RegisterRecords, BasedOn, InputByString
  with add-*/remove-*/set-* inline ops and JSON modify.properties arrays
- Paren-aware comma splitting for types like Number(15,2) in modify values

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:01:53 +03:00
Nick Shirokov cb4b5ec935 Add /meta-edit skill: point editing of 1C metadata objects
New skill for adding/removing/modifying attributes, tabular sections,
dimensions, resources, enum values, forms, templates, commands in
existing metadata XML. Supports Russian/English DSL synonyms,
positional insertion, idempotent add, auto-validation via meta-validate.

Also adds missing Source comment to meta-compile.ps1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 15:02:23 +03:00
Nick Shirokov 7c5700e40f Fix meta-validate false positives and expand reference data after ERP testing
Cross-checked against spec and tested on 23 ERP 8.3.24 object types.
Fixes: Enum optional StandardAttributes, Column without Type block,
adds missing GeneratedType categories and StandardAttributes for
CalculationRegister, ChartOfCharacteristicTypes, ChartOfCalculationTypes,
BusinessProcess, Report, DataProcessor, DefinedType.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:20:20 +03:00
Nick Shirokov a6bf6520ce Add /meta-validate skill: structural validation of 1C metadata XML
11 check categories covering all 23 metadata types:
root structure, InternalInfo, properties, enum values,
StandardAttributes, ChildObjects, child elements (UUID/Name/Type),
name uniqueness, TabularSections, cross-properties,
HTTPService/WebService nested structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:00:05 +03:00
Nick Shirokov ed45f54594 Improve -info skill descriptions with usage triggers
Add proactive usage hints to form-info, skd-info, mxl-info, role-info
so the model knows when to invoke them as components for composite tasks
(e.g. writing print code, analyzing reports, auditing permissions).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 12:59:07 +03:00
Nick Shirokov 099de2d850 Improve /meta-info skill description for better discoverability
Add trigger keywords (реквизиты, ТЧ, формы, движения, типы) and
proactive usage hint for composite tasks (queries, code).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 12:35:04 +03:00
Nick Shirokov 2d79c0b0ee Extend /meta-compile to 23 metadata types (Phase 2)
Add 17 new types: ExchangePlan, ChartOfAccounts, ChartOfCharacteristicTypes,
ChartOfCalculationTypes, AccountingRegister, CalculationRegister,
BusinessProcess, Task, DocumentJournal, Report, DataProcessor,
CommonModule, ScheduledJob, EventSubscription, HTTPService, WebService,
DefinedType. Update DSL spec to v2.0 and improve skill description.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 10:32:48 +03:00
Nick Shirokov acee4bd188 Add /meta-compile skill: JSON DSL → 1C metadata XML
Supports 6 types: Catalog, Document, Enum, Constant,
InformationRegister, AccumulationRegister. Includes DSL spec,
SKILL.md, and PowerShell compiler with CamelCase auto-synonyms,
shorthand attribute syntax, Russian type aliases, Configuration.xml
auto-registration, and module scaffolding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 21:16:33 +03:00
Nick Shirokov 01b20426fa Update spec and README with 6 new metadata types
Add sections 20-25 to config objects spec (DefinedType, CommonModule,
ScheduledJob, EventSubscription, HTTPService, WebService). Add /meta-info
skill group and spec link to README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:19:51 +03:00
Nick Shirokov 04e5360e52 Regroup supported types: Ссылочные/Регистры/Сервисные/Прочие
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:09:09 +03:00
Nick Shirokov 33fa6dbe9a Move План обмена into Планы group for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:06:16 +03:00
Nick Shirokov 11152d2443 Simplify /meta-info description: drop enumeration, keep essence
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:04:06 +03:00
Nick Shirokov daea0a72d1 Refine /meta-info description: "Структура" instead of "Сводка", more concise wording
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:02:48 +03:00
Nick Shirokov b4905fc3e3 Polish /meta-info SKILL.md per best practices: trigger clause in description, forward-slash paths, remove redundant intro and verification section
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 19:58:57 +03:00
Nick Shirokov 23555b513f Rewrite /meta-info SKILL.md: grouped types, generic mode descriptions, relative paths in examples
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 19:54:49 +03:00
Nick Shirokov 8aef749471 Add 6 new metadata types to /meta-info: DefinedType, CommonModule, ScheduledJob, EventSubscription, HTTPService, WebService
Support overview/brief/full modes for all 6 types plus drill-down
for HTTPService (URLTemplate) and WebService (Operation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 19:46:41 +03:00
Nick Shirokov bd30e48dae Improve /meta-info: Russian translations, sorting, Constants/Reports support
- Translate cfg:Characteristic.X → Характеристика.X (in both v8:Type and v8:TypeSet)
- Translate drill-down values to Russian: Indexing, Use, FillValue
- Translate truncation message to Russian
- Add Constant type display and Report MainDCS/forms/templates in overview
- Add DataProcessor forms/templates/commands in overview mode
- Sort attributes ref-first (references before primitives) in overview/full

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 19:02:37 +03:00
Nick Shirokov 92dc00e152 Add /meta-info skill for compact 1C metadata object summaries
Reads XML metadata files (catalogs, documents, enums, registers, etc.)
and outputs a concise summary with fields, types, tabular sections,
movements, forms. Three modes: overview, brief, full. Supports
drill-down into individual attributes, dimensions, and tabular sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:56:37 +03:00
Nick Shirokov 45c2587e4a Add configuration metadata objects XML format specification
Comprehensive spec covering all 17 metadata object types (Catalogs, Documents,
Registers, Charts, BusinessProcesses, Tasks, ExchangePlans, Enums, Constants,
Reports, DataProcessors, DocumentJournals) with common structure, type system,
standard attributes, child objects, and platform version differences (2.17→2.20).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 16:45:33 +03:00
Nick Shirokov 08722ff285 Merge branch 'dev' 2026-02-11 22:01:45 +03:00
Nick Shirokov 89c0775c65 Add work-in-progress notice to README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 22:00:12 +03:00
Nick Shirokov 5c0a55e090 Add /skd-edit to README and skd-guide documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:56:17 +03:00
Nick Shirokov 2f2ecca88b Clarify add-conditionalAppearance shorthand syntax in SKILL.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:13:27 +03:00
Nick Shirokov acb7a4eadc Expand /skd-edit to 25 operations with add-dataSet, add-variant, add-conditionalAppearance
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:10:53 +03:00
Nick Shirokov 28b8061d64 Compact skd-edit SKILL.md: remove redundant examples section
Reduce from 309 to 183 lines by removing duplicate full-command examples
(already shown inline per operation) and consolidating remove-*/clear-*
into a single table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 20:10:49 +03:00
Nick Shirokov 703c3e6f80 Add version headers with source URL to all 22 skill scripts
Each .ps1 now starts with skill name, version (v1.0), and repo link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 20:01:10 +03:00
Nick Shirokov 2d0835ba17 Fix XML formatting in batch insert and after clear operations
Two bugs caused tag concatenation (e.g. `</item><item`):
- Insert-BeforeElement: place new node before trailing whitespace, not before the preceding newline
- Get-ContainerChildIndent: check for Element children instead of HasChildNodes to correctly detect empty containers after clear-*

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 19:39:07 +03:00
Nick Shirokov a9b7a90672 Expand /skd-edit to 22 operations with modify, clear, structure, and dataSetLink
Add 7 new operations: modify-field, modify-filter, modify-dataParameter,
clear-selection, clear-order, clear-filter, add-dataSetLink, set-structure.
Add selection dedup for add-field/add-calculated-field and order dedup
for add-order. Fix SetAttribute output leak.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 18:50:13 +03:00
Nick Shirokov 69213930b3 Expand /skd-edit to 15 operations with batch mode and duplicate checks
Add 9 new operations: add-dataParameter, add-order, add-selection,
set-outputParameter, remove-field/total/calculated-field/parameter/filter.
Add batch mode (;; separator), duplicate detection with skip, title support
in fields and calculated fields, type support in calculated fields.
Fix set-query double-escaping and Parse-CalcShorthand title extraction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 17:38:13 +03:00
Nick Shirokov 151d1d77cb Add /skd-edit skill for atomic DCS modifications
New skill for point editing of existing Template.xml: add-field,
add-total, add-calculated-field, add-parameter (with @autoDates),
add-filter, set-query. Uses XmlDocument+PreserveWhitespace pattern
from form-edit and shorthand parsers from skd-compile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 16:56:02 +03:00
Nick Shirokov 70bb5074c8 Update SKD DSL spec and guide with new features documentation
Add conditionalAppearance, multi-group totalField, viewMode flags
(@normal, @inaccessible), userSettingPresentation, dataParameters
table. Update guide with @autoDates, structure/filter shorthand,
and modern examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 16:19:31 +03:00
Nick Shirokov 91d254b718 Add DCS template type, conditional appearance, filter/total enhancements
- epf-add-template: support DataCompositionSchema template type with
  minimal DCS scaffold (dataSource + Local)
- skd-compile: add conditionalAppearance with auto-detect value types
  (Color, LocalStringType, Boolean), selection, filter, presentation
- skd-compile: add @normal, @inaccessible viewMode shorthand flags
- skd-compile: add userSettingPresentation for filters and dataParameters
- skd-compile: support multiple group elements in totalField (array form)
- skd-compile SKILL.md: document all new features with examples

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 16:12:47 +03:00
Nick Shirokov 1382194201 Fix @period role to emit periodNumber/periodType instead of period
Real DCS files use <dcscom:periodNumber>1</dcscom:periodNumber> and
<dcscom:periodType>Main</dcscom:periodType> for period fields.
The element <dcscom:period> does not exist in the XDTO schema and
causes build failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 13:22:35 +03:00
Nick Shirokov 7e587b9a3e Emit Auto items only at group level, not top-level settings
Real DCS files place SelectedItemAuto and OrderItemAuto exclusively
inside StructureItem elements (groups, tables, charts), never at the
top-level settings. Added -skipAuto switch to Emit-Selection and
Emit-Order, applied at settings level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:48:52 +03:00
Nick Shirokov 4594c74d21 Document d5p1: inline namespace for reference types in DCS spec
Reference types in valueType use inline xmlns:d5p1 declaration with
URI http://v8.1c.ru/8.1/data/enterprise/current-config, not a
root-level cfg: prefix. Added XML example and supported type list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 11:47:04 +03:00
Nick Shirokov 2650b1a063 Fix reference types to use d5p1: namespace instead of cfg:
Real DCS files use inline xmlns:d5p1="http://v8.1c.ru/8.1/data/
enterprise/current-config" for reference types like CatalogRef.XXX.
Using cfg: prefix caused XDTO errors because the namespace was
undeclared. With correct d5p1: namespace, EPF builds successfully
in both empty and config-aware bases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 11:45:01 +03:00
Nick Shirokov f23a3e5536 Add MIT license
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 11:35:47 +03:00
Nick Shirokov eb6f8379e6 Skip cfg: reference types in DCS valueType to fix XDTO build errors
Real 1C DCS files (12,495 analyzed) never include cfg:CatalogRef.XXX
in <valueType> — the platform infers field types from query metadata.
Emitting them causes XDTO exceptions when building EPF. Reference
types in JSON DSL still set field roles but no longer emit valueType.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 11:32:17 +03:00
Nick Shirokov 91e4e1948f Add comprehensive XML escaping to skd-compile
Wrap all user-provided values in Esc-Xml() for safe XML output:
- ValueType references (CatalogRef, DocumentRef, etc.)
- Emit-ParamValue (all type branches: StandardPeriod, dateTime, boolean, decimal)
- DataParameters (variant, boolean, dateTime values, viewMode, userSettingID)
- Filter items (field, comparisonType, viewMode, userSettingID)
- Selection fields, Order fields, GroupItems fields
- GroupTemplates templateType, HorizontalAlign appearance value
- Parameter use element

Verified against 12,495 real DCS files: standard XML entity escaping
(&amp; &lt; &gt; &quot;) matches 1C platform behavior exactly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 09:44:23 +03:00
Nick Shirokov f4d60d67bf Add DSL v2 shorthand improvements to skd-compile
Type synonyms (число/строка/булево/дата/СправочникСсылка, case-insensitive),
@autoDates for auto-generating ДатаНачала/ДатаОкончания from StandardPeriod,
string shorthand for structure ("Организация > details"), filter shorthand
("Организация = _ @off @user"), dataParameters shorthand ("Период = LastMonth
@user"), and default selection/order ["Auto"] on all structure levels.
Compression ratio improved from 3.9x to 5.8x on the medium example.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 22:09:03 +03:00
Nick Shirokov b67f4b21e6 Add SKD group to README, create skd-guide.md
- README: add СКД row to skills table, specs section, directory tree
- docs/skd-guide.md: usage guide with workflow, DSL examples, scenarios

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 21:32:29 +03:00
Nick Shirokov d573f84c9d Add skd-compile and skd-validate skills for DCS schema generation
- skd-compile: JSON DSL → Template.xml (DataCompositionSchema)
  Shorthand parsers for fields, totals, parameters, calculated fields.
  Full type system, settings variants with selection/filter/order/structure.
- skd-validate: structural validation of Template.xml (~30 checks)
  DataSources, DataSets, fields, links, params, templates, variants.
- docs/skd-dsl-spec.md: full DSL specification

Tested on compiled examples and 5+ real DCS from acc_8.3.24 (0 errors).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 21:27:19 +03:00
Nick Shirokov c306d18648 Add templates mode for DCS template binding analysis
- Map (without -Name): field bindings with non-trivial expression
  detection, group bindings organized by group name (groupTemplate,
  groupHeaderTemplate, groupFooterTemplate, fieldTemplate)
- Detail (-Name <group|field>): template content with rows, cells
  (static text and parameters), non-trivial expressions only
- Trivial filter: Field=Field and Field=Представление(Field) hidden
- Updated overview: shows binding type counts, templates hint in Next

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 19:56:56 +03:00
Nick Shirokov d72dd1678e Extract detailed mode examples into modes-reference.md
SKILL.md: 288 -> 72 lines. Compact table of modes with
progressive disclosure pattern, typical workflow, command
reference. Detailed output examples moved to modes-reference.md
(loaded on demand via Read tool, not on every skill invocation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 19:01:16 +03:00
Nick Shirokov 0ca6d3f089 Add variant list mode, fix stale SKILL.md references
- variant without -Name now shows variant list (progressive disclosure)
- Fix Mode parameter: totals -> calculated, resources
- Fix fields -Name example: dataset name -> field name
- Improved error message when variant not found

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 18:52:20 +03:00
Nick Shirokov dddb9e3dac Make fields -Name drill into specific field for consistency
fields -Name now takes a field dataPath (like calculated -Name and
resources -Name) instead of a dataset name. Shows field detail:
dataset, title, type, role, restrict, format, presentationExpression.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 18:45:15 +03:00
Nick Shirokov f211ffa2f0 Split totals into calculated and resources modes
Each concept now has its own mode with clear naming that matches
the overview labels. Overview now shows "Resources:" instead of
"Totals:" for consistency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 18:40:50 +03:00
Nick Shirokov 21dded4d1c Add trace mode for field origin analysis
New mode traces a field from title/name to its full origin:
dataset fields, calculated expression with operands, resource
formulas. Searches by dataPath, exact title, or title substring.
Collapses 5-7 manual calls into one.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 18:34:12 +03:00
Nick Shirokov 941fa73803 Add progressive disclosure to fields and totals modes
Without -Name, both modes now show a compact map (field names
per dataset / calculated+resource names). With -Name, they
drill down to full detail. Totals -Name shows both calculated
expression and resource formula when field appears in both.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 18:23:02 +03:00
Nick Shirokov 24358f212f Split fields mode into fields, links, and totals modes
Separate concerns for cleaner output: fields shows only dataset
field tables, links shows dataset connections, totals shows
calculated fields and resources.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 18:00:30 +03:00
Nick Shirokov d210d21079 Add full link details to fields mode
Show dataSetLink field-level mappings (source.field -> dest.field
param=X) at the top of -Mode fields output. Overview keeps compact
dataset-pair summary, fields provides the detail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 17:46:29 +03:00
Nick Shirokov 2949682ce8 Update SKILL.md examples to match simplified overview
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 17:39:42 +03:00
Nick Shirokov e86620dbd7 Simplify /skd-info overview to pure navigation map
Overview now shows only counts for calculated/totals/templates.
Links compressed to dataset pairs. Params split into visible/hidden
with only visible names listed. Add "Next:" hints with available
modes and dataset names to guide further exploration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 17:39:16 +03:00
Nick Shirokov 9922f118d1 Improve /skd-info overview for large schemas
Switch to multi-line/compact format when element counts are high:
totals (>5) show grouped by field name, calculated (>10) truncated,
templates (>10) show counts, links (>2) multi-line, variant structure
groups identical items (e.g. "17x Group(...)"). Fix query mode to
prefer nested Query datasets over parent Union with same name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 17:31:30 +03:00
Nick Shirokov 8c833f042c Add /skd-info skill for DCS (Data Composition Schema) analysis
Implements 5 modes: overview (compact TOC), query (raw SQL with batch
splitting), fields (field table with roles/restrictions), params
(parameter table with types/defaults), variant (structure tree with
filters and output settings). Update DCS spec with totalField group info.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 17:24:43 +03:00
Nick Shirokov 1d593af63a Merge branch 'dev' 2026-02-10 14:11:58 +03:00
Nick Shirokov be216cd064 Document CatalogRef XDTO build failure in empty database
Verified experimentally: EPF build with CatalogRef/DocumentRef
types fails with XDTO exception in empty database (not silent
UUID substitution as previously documented). Updated epf-build,
form-compile, and build-spec accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 14:11:23 +03:00
Nick Shirokov 55b1ef4e06 Merge branch 'dev' 2026-02-10 13:31:23 +03:00
Nick Shirokov e229fc4873 Auto-register role in Configuration.xml
role-compile: after generating files, automatically inserts
<Role>Name</Role> into Configuration.xml ChildObjects (idempotent).
role-validate: checks that the role is registered, warns if not.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 13:29:50 +03:00
Nick Shirokov 3a4c1905f4 Fix Cyrillic encoding in role-info console output
Add [Console]::OutputEncoding = UTF8, matching role-compile
and role-validate scripts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 13:21:00 +03:00
Nick Shirokov 7aaa9fc070 Remove @use preset, merge DataProcessor/Report into @view
The @use preset name conflicted with the Use right semantics.
DataProcessor and Report require Use+View together (View cannot
be set without Use), so @view is the natural fit. Services
(WebService, HTTPService, IntegrationService) use explicit rights.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 13:18:08 +03:00
Nick Shirokov 8b8bc1225a Refactor role-compile SKILL.md with progressive disclosure
Extract detailed preset tables, Russian synonym tables, and extra
examples into dsl-reference.md (318 lines). Compact SKILL.md from
340 to 107 lines. Add role-dsl-spec.md project spec.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 13:13:59 +03:00
Nick Shirokov dc10422f10 Add script-based /role-compile and /role-validate skills
Convert /role-compile from instruction-based to PowerShell script with JSON DSL:
- Presets (@view, @edit, @use) for common right sets
- String shorthand and object form with RLS support
- Russian synonym translation for object types and rights
- Auto UUID generation, UTF-8 BOM output

Add /role-validate for structural validation of Rights.xml:
- XML well-formedness, namespace, global flags
- Right name validation per object type with typo suggestions
- RLS condition and template checks
- Optional metadata validation (UUID, Name, Synonym)

Update README and role-guide with new skills documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 10:29:59 +03:00
Nick Shirokov 65afdf2e55 Add 1C Data Composition Schema (DCS) XML format specification
Comprehensive spec covering DataCompositionSchema format based on
analysis of 930 schemas from accounting configuration (8.3.24):
dataSource, dataSet (Query/Object/Union), fields with roles and
restrictions, parameters, dataset links, calculated/total fields,
area templates, and settings variants with structure items.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 09:32:33 +03:00
Nick Shirokov f87c94e832 Merge branch 'dev' 2026-02-09 22:53:50 +03:00
Nick Shirokov 6681758121 Add /form-add skill for configuration objects
Create forms (metadata XML + Form.xml + Module.bsl) for Document,
Catalog, InformationRegister and other configuration object types.
Supports Object/List/Choice/Record purposes with automatic
ChildObjects registration and DefaultForm setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 22:53:13 +03:00
Nick Shirokov 89f0788585 Rename form-add to form-edit for clarity
The skill modifies existing forms (adds elements/attributes/commands),
not creates new ones. "form-edit" better reflects its purpose.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 22:05:33 +03:00
Nick Shirokov d27dfbf8e1 Add role-guide.md and update README with role skills
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 21:54:52 +03:00
Nick Shirokov fc24524c75 Add /role-info and /role-compile skills
role-info: PS1 script parsing Rights.xml into compact summary grouped
by object type. Supports -ShowDenied and -OutFile for UTF-8 output.
78K lines XML -> 1924 lines for largest role, ~100 for typical ones.

role-compile: Template-based SKILL.md (no script) with XML templates,
rights catalog per object type, and typical right sets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 21:21:04 +03:00
Nick Shirokov 2c96c90d45 Add 1C role XML format specification
Complete reference: file structure, rights catalog by object type,
nested object rights, RLS conditions, restriction templates.
Verified across platform versions 8.3.20/8.3.24/8.3.27 and
both ACC and ERP configurations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 21:06:01 +03:00
Nick Shirokov 8fc30c9b9a Merge dev: form skills (info, compile, validate, add, patterns)
Complete managed form pipeline:
- /form-info: compact XML analysis
- /form-compile: JSON DSL to Form.xml generation
- /form-validate: structural validation
- /form-add: add elements/attributes/commands to existing forms
- /form-patterns: layout guide with archetypes and conventions

Event validation, element-level stdCommand, ERP patterns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 19:03:45 +03:00
Nick Shirokov ecfb473827 Add /form-patterns skill for loading layout guide into context
Self-contained SKILL.md with all patterns inlined (no external file
dependencies). Archetypes, naming conventions, ERP patterns, DSL examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 19:02:00 +03:00
Nick Shirokov dc9e1fe3db Add advanced ERP patterns to form layout guide
Collapsible groups, status banners, popup menus, custom command bars,
hyperlink labels — with DSL examples for each pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:35:02 +03:00
Nick Shirokov 5c07dec82c Add form layout patterns guide with real-world conventions
Design patterns extracted from 1C:Accounting 8.3.24 forms:
- 5 archetypes: document, processor, list, catalog, wizard
- Naming conventions for groups, elements, event handlers
- Layout principles (2-column header, footer totals, filter pairs)
- Two complete DSL examples (processing form, list with filters)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:12:17 +03:00
Nick Shirokov c5fa794cf3 Add event validation and element-level stdCommand support
- stdCommand dot syntax: "Товары.Add" → Form.Item.Товары.StandardCommand.Add
- Event name validation: warn on unknown events per element type (13 types, ~60 events)
- Form-level event validation (19 known events)
- Document events reference and popup element in SKILL.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 17:39:29 +03:00
Nick Shirokov 7e0e30730c Add unknown key warnings to form-add, update form-guide.md
form-add: warn about unrecognized DSL keys in element definitions,
matching the same validation added to form-compile earlier.

form-guide.md: update form-info output examples to reflect new
Title-in-header format and DSL-friendly command display
(-> Name [cmd], -> Close [std]).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 16:03:17 +03:00
Nick Shirokov ad412dffa2 Expand form-compile SKILL.md with full DSL reference and patterns
Replace minimal docs with comprehensive reference:
- Per-element-type property tables (input, check, label, group,
  table, pages, button, cmdBar) with all supported keys
- Top-level structure documentation (title, properties, events, etc.)
- Table+attribute linkage section explaining the ValueTable pattern
- Three pattern examples: file import dialog, wizard with steps,
  list with filter and table
- Attribute and command definition examples

This helps the model generate correct JSON DSL from natural language
requirements on the first attempt without guessing undocumented keys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 15:58:15 +03:00
Nick Shirokov c665800916 Improve form skills: validation, docs, round-trip consistency
form-compile: warn about unknown DSL keys in element definitions,
document stdCommand/command button keys and EPF-specific notes.

form-validate: check that form-level Title uses multilingual XML,
not plain text (which causes XDTO errors at build time).

form-add: warn about duplicate element names, clarify after-not-found
message when using into+after together.

form-info: show Title in header instead of Properties line, display
commands as DSL-friendly format (-> Name [cmd], -> Close [std])
instead of raw Form.Command/Form.StandardCommand paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 15:44:32 +03:00
Nick Shirokov d05199d048 Replace hidden/disabled with visible/enabled in form DSL
Rename DSL keys to match 1C property names (Visible, Enabled):
- form-compile/form-add: accept "visible": false and "enabled": false
  as primary keys, keep hidden/disabled as synonyms
- form-info: output [visible:false] and [enabled:false] flags
- Update SKILL.md docs and form-guide.md

Improves round-trip consistency: form-info output now directly maps
to form-compile/form-add input keys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 15:05:14 +03:00
Nick Shirokov a9e59265dd Fix ID scanning in form-add and title emission in form-compile
form-add: Scan column IDs (same pool as attribute IDs) to prevent
duplicate ID collisions. Use XPath .//*[@id] instead of ChildItems
recursion to capture companion element IDs (ExtendedTooltip, ContextMenu).

form-compile: Extract title from properties and route through Emit-MLText
instead of generic Emit-Properties, which produced plain text <Title>
rejected by 1C XDTO schema.

Found during E2E testing of full pipeline (epf-init → form-compile →
form-add → epf-build).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 14:40:23 +03:00
Nick Shirokov 99f57a5ff2 Add form-add skill for modifying existing Form.xml
Adds elements, attributes, and commands to existing managed forms
via JSON input. Supports positional insertion (into/after), auto ID
allocation from correct pools, companion generation, and event handlers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 13:34:56 +03:00
Nick Shirokov a813c7fd46 Add form-validate skill for structural validation of Form.xml
Checks: unique IDs (per pool), companion elements, DataPath→attribute
refs, button→command refs, event handlers, command actions, MainAttribute.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:13:51 +03:00
Nick Shirokov cc2595b57a Add form-compile skill for generating Form.xml from JSON DSL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:57:58 +03:00
Nick Shirokov 580124a971 Add form-info skill for compact analysis of 1C managed forms
Parses Form.xml (up to 28K lines) and outputs a compact summary (40-180 lines):
element tree with group orientation, data bindings, events, visibility flags,
attributes with types, commands, and parameters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:09:42 +03:00
Nick Shirokov 044bc18974 Add img-grid skill and page auto-sizing to mxl-compile
- New skill /img-grid: overlays numbered grid on images to help
  determine column proportions for MXL template generation
- Add "page" field to MXL DSL ("A4-landscape", "A4-portrait", or
  number) that auto-calculates defaultWidth from column proportions
- Update DSL spec, mxl-compile SKILL.md, MXL guide, README

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 22:44:31 +03:00
Nick Shirokov 3819a5f7af Reorganize docs: README as hub + per-group guides
Split monolithic README into:
- README.md — concise hub with quick start and group links
- docs/epf-guide.md — EPF skills guide (content from old README)
- docs/mxl-guide.md — MXL skills guide (new scenarios and examples)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 21:36:44 +03:00
Nick Shirokov 56b1458545 Add ПФ_MXL_ naming convention for print form templates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 21:16:41 +03:00
Nick Shirokov bca022fba8 Add relative column width support ("Nx" syntax) to mxl-compile
Allows specifying column widths as multiplier of defaultWidth (e.g. "2x",
"0.5x") alongside absolute values. Makes template generation from images
easier — model specifies proportions instead of exact pixel values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 20:47:32 +03:00
Nick Shirokov 0e680d151d Remove unused styles, add empty row compression to DSL
- Decompiler: remove styles not referenced by any cell or rowStyle
- Decompiler: compress consecutive empty rows into {"empty": N}
- Compiler: support {"empty": N} row placeholder
- DSL spec: document empty field on rows

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 20:09:13 +03:00
Nick Shirokov 8092015807 Optimize mxl-decompile output: deduplicate fonts, remove noise
- Font deduplication: identical fonts reuse existing name (6→4 on Акт)
- Don't emit "rowStyle": "default" for empty styles
- Don't emit "cells": [] on empty rows
- Don't emit "default": {} in styles section
- Result: ~10% smaller JSON output, cleaner for Claude to read/write

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 19:48:00 +03:00
Nick Shirokov 03a6820f69 Add 1C managed form XML format specification
Comprehensive spec based on analysis of 7723 forms from
Бухгалтерия предприятия 3.0.180: all 15 UI control types,
form-level properties, events, attributes/type system,
parameters, commands, and namespace declarations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 19:34:51 +03:00
Nick Shirokov bfbef3c361 Add mxl-decompile skill for Template.xml → JSON DSL conversion
Reverse of /mxl-compile: reads Template.xml and produces compact
JSON definition with auto-generated font/style names, rowStyle
detection, span/rowspan mapping, and column width compression.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 19:07:08 +03:00
Nick Shirokov 298d503c64 Extract MXL DSL spec to docs/mxl-dsl-spec.md
Shared spec for mxl-compile and future mxl-decompile.
Compiler SKILL.md now references the spec instead of inlining it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:39:40 +03:00
Nick Shirokov 1ed5d783e8 Rename numberFormat to format in mxl-compile DSL
The field covers all 1C format strings: numbers, dates, booleans.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:35:44 +03:00
Nick Shirokov f0bb8c860f Add rowspan and numberFormat support to mxl-compile
- rowspan: vertical cell merging with rowStyle gap-fill awareness
- numberFormat: style field generates nested <format> in palette
- Updated SKILL.md: new fields, removed from limitations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:33:41 +03:00
Nick Shirokov 2f260ddb7f Add underline/strikeout fonts, individual borders, thick lines
- Fonts: underline and strikeout fields (default false)
- Borders: individual sides (left, right), comma combos ("top,bottom")
- Lines: borderWidth "thick" generates width=2 line entry
- SKILL.md updated with new fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:22:13 +03:00
Nick Shirokov 2771424c71 Fix XML escaping in mxl-compile text content
Add Esc-Xml helper to escape &, <, >, " in cell text and
template content to prevent invalid XML generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:18:24 +03:00
Nick Shirokov 96890598f9 Add mxl-compile skill: DSL compiler for SpreadsheetDocument
JSON DSL format compiles to valid 1C Template.xml with correct
format palettes, merges, named areas, and rowStyle gap-filling.
Tested on simple (4 areas) and invoice (7 areas) templates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:08:04 +03:00
Nick Shirokov 50dc9ceec9 Перевести SKILL.md навыков mxl-info и mxl-validate на русский
Для единообразия с остальными навыками проекта.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:29:57 +03:00
Nick Shirokov 455c12e6b6 Extract template parameters without -WithText flag
Parameters from [ParamName] placeholders in template text are now always
extracted and shown with [tpl] suffix. Numeric-only placeholders like [5]
(footnote references in legal forms) are filtered out.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:17:50 +03:00
Nick Shirokov 1a79e84598 Improve mxl-info output and document how to read it
Script improvements:
- Sort areas by position (top-to-bottom) instead of alphabetically
- Extract detailParameter (drill-down links)
- Show column set sizes in header and per-area [colset 20cols]
- Detect Rows+Columns intersections with GetArea hint

SKILL.md: add "Reading the Output" section explaining area order,
column sets, intersections, detailParameter, and text content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:11:54 +03:00
Nick Shirokov 76a0dd80be Add mxl-info and mxl-validate skills for SpreadsheetDocument analysis
- /mxl-info: extracts compact template structure (areas, parameters,
  column sets) from Template.xml. Supports -WithText for cell content,
  -Format json, and output truncation protection.
- /mxl-validate: 12 structural checks (format/font/line indices,
  column bounds per column set, named area ranges, merge bounds,
  columnsID references). Exit code 1 on errors.

Tested on 3 real templates: label (simple), invoice (medium),
УКД (complex — 7 column sets, Rectangle areas).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 15:59:49 +03:00
Nick Shirokov fdf661192d Add platform version compatibility section to spreadsheet spec
Documented cross-version comparison (8.3.20, 8.3.24, 8.3.27):
Template.xml is byte-identical, only MetaDataObject/Form version
attribute changes (2.17 → 2.20). Confirmed backward compatibility —
8.3.27 accepts version="2.17" files without issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 15:01:58 +03:00
Nick Shirokov be3a31ea94 Add advanced spreadsheet features: multiple column sets, verticalUnmerge, Rectangle areas
Based on УКД (universal correction document) template analysis.
Multiple <columns> with UUID allow rows to use independent
column grids. Merges and named areas also reference column sets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 14:25:11 +03:00
Nick Shirokov 061c73b23d Add SpreadsheetDocument XML format specification
Based on real templates from 1C:Accounting — invoice (horizontal
areas, 33 columns) and label (vertical area, drawing, barcode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 14:19:20 +03:00
Nick Shirokov 9f9a022659 Add .claude/settings.local.json to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 13:20:35 +03:00
Nick Shirokov 215319382a Simplify scenario 1 example in README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 13:16:25 +03:00
Nick Shirokov d6660a4d00 Remove docs/ references from skills to avoid confusion
Skills are self-contained — all templates and instructions are
in SKILL.md. Removed spec references that could mislead the
model into trying to read files that may not exist. Updated
README to note that docs/ is not needed when copying skills.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:49:44 +03:00
Nick Shirokov 4bc86decf8 Improve usage examples with real-world scenarios
README: replace abstract examples with realistic scenarios — processor
with form for data manipulation, BSP print form with spreadsheet
template, incremental additions. Emphasize natural language over slash
commands.

epf-add-template SKILL.md: add Russian name mapping for template types
(табличный документ, текстовый документ).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:37:42 +03:00
Nick Shirokov 34e88d2914 Add natural language usage examples to README
Show that users can describe tasks in free form — Claude will pick
the right skills automatically. Slash commands still work for precise
control.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:32:33 +03:00
Nick Shirokov b3dac25729 Add epf-add-help skill and help specification
New skill /epf-add-help creates built-in help files (Help.xml + HTML page)
for external data processors. Also adds IncludeHelpInContents to form
metadata if missing.

New spec docs/1c-help-spec.md documents the help file format, HTML
template, and help button integration on forms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 22:13:47 +03:00
Nick Shirokov c2348b6b68 Add BSP skills for additional processors/reports registration
New skills for working with BSP (Standard Subsystems Library) mechanism:
- epf-bsp-init: adds СведенияОВнешнейОбработке() to object module
- epf-bsp-add-command: adds commands to existing BSP processor

Both skills use code templates in SKILL.md (no PowerShell scripts) —
Claude modifies BSL code directly via Read/Edit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 21:48:43 +03:00
Nick Shirokov aaa4f65be1 Update README: argument hints, auto DefaultForm, usage guide
- Added parameters column to skills table
- Noted that remove skills are manual-only
- Removed --main from quick start (first form is auto-main)
- Added "Подключение к проекту" section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 20:16:31 +03:00
Nick Shirokov d34cbf7272 Add argument-hint to all skills, disable auto-invocation for remove skills
- argument-hint: shows expected parameters when typing /command
- disable-model-invocation on epf-remove-form and epf-remove-template
  prevents Claude from invoking destructive operations autonomously

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 20:02:25 +03:00
Nick Shirokov e3daaf233d Auto-set DefaultForm for the first form added
When adding the first form to a processor, DefaultForm is now set
automatically without requiring the --main flag. The --main flag
is still available to reassign DefaultForm to a different form.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 19:31:19 +03:00
Nick Shirokov 43333f1481 Initial commit: EPF skills for Claude Code
7 skills for working with 1C external data processor XML sources:
- epf-init: scaffold a new processor (root XML + ObjectModule.bsl)
- epf-add-form: add a managed form with BSL module
- epf-add-template: add a template (HTML/Text/SpreadsheetDocument/BinaryData)
- epf-remove-form: remove a form and update root XML
- epf-remove-template: remove a template and update root XML
- epf-build: build EPF from XML (documentation only)
- epf-dump: dump EPF to XML (documentation only)

Includes XML format spec and build/dump command reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 19:05:27 +03:00
2080 changed files with 169003 additions and 26929 deletions
+32
View File
@@ -0,0 +1,32 @@
{
"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
@@ -0,0 +1,24 @@
{
"$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-py",
"description": "[Python] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент. Linux/Mac или когда PowerShell недоступен.",
"name": "1c-skills",
"description": "[PowerShell] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент.",
"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
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 "ПолныеПрава ;; Администратор"
```
---
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 "ПолныеПрава ;; Администратор"
```
+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
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
```
---
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
```
+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
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 — валидировать
```
---
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 — валидировать
```
+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
python "${CLAUDE_SKILL_DIR}/scripts/cf-validate.py" -ConfigPath "upload/cfempty"
python "${CLAUDE_SKILL_DIR}/scripts/cf-validate.py" -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
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"
```
+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
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>
```
---
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>
```
+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
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
```
---
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
```
+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
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>
```
---
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>
```
+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
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: код перед вызовом оригинального метода
КонецПроцедуры
```
---
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: код перед вызовом оригинального метода
КонецПроцедуры
```
+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
python "${CLAUDE_SKILL_DIR}/scripts/cfe-validate.py" -ExtensionPath "src"
python "${CLAUDE_SKILL_DIR}/scripts/cfe-validate.py" -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
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"
```
+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
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 "Новая база"
```
---
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 "Новая база"
```
+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
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 "МоёРасширение"
```
---
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 "МоёРасширение"
```
+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
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 "МоёРасширение"
```
---
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 "МоёРасширение"
```
+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
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 "МоёРасширение"
```
---
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 "МоёРасширение"
```
+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
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"
```
---
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"
```
+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
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
```
---
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
```
+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
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 "ЗапуститьОбновление"
```
---
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 "ЗапуститьОбновление"
```
+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
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 "МоёРасширение"
```
---
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 "МоёРасширение"
```
+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
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"
```
---
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"
```
+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
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"
```
---
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"
```
+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
python "${CLAUDE_SKILL_DIR}/scripts/init.py" -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
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`
+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
python "${CLAUDE_SKILL_DIR}/scripts/epf-validate.py" -ObjectPath "src/МояОбработка"
python "${CLAUDE_SKILL_DIR}/scripts/epf-validate.py" -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
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"
```
+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
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"
```
---
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"
```
+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
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"
```
---
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"
```
+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
python "${CLAUDE_SKILL_DIR}/scripts/init.py" -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
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`
+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
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"
```
---
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"
```
+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
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` — проанализировать результат
---
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` — проанализировать результат
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
# form-compile v1.23 — Compile 1C managed form from JSON or object metadata
# form-compile v1.21 — 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;"valuesPicture"=1;"loadTransparent"=1
"src"=1
# cmdBar-specific
"autofill"=1
}
@@ -2134,7 +2134,6 @@ 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>" }
@@ -2723,16 +2722,6 @@ 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.23 — Compile 1C managed form from JSON or object metadata
# form-compile v1.21 — 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", "valuesPicture", "loadTransparent",
"src",
"autofill",
"choiceMode", "initialTreeView", "enableDrag", "enableStartDrag",
"rowPictureDataPath", "tableAutofill",
@@ -1933,8 +1933,6 @@ 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:
@@ -2364,16 +2362,6 @@ 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
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` — убедиться что добавилось правильно
---
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` — убедиться что добавилось правильно
+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
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.
---
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.
+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
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
---
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
+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
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"
```
---
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"
```
+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
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 формы.
---
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 формы.
+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
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>
```
---
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>
```
+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
python "${CLAUDE_SKILL_DIR}/scripts/interface-validate.py" -CIPath "Subsystems/Продажи"
python "${CLAUDE_SKILL_DIR}/scripts/interface-validate.py" -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
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"
```
+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
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.Валюты" }
]
```
---
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.Валюты" }
]
```
+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
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> — визуальная сводка
```
---
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> — визуальная сводка
```
+148 -148
View File
@@ -1,148 +1,148 @@
# 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 |
# 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 |
+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
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
```
---
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
```
+1 -28
View File
@@ -1,4 +1,4 @@
# meta-info v1.2 — Compact summary of 1C metadata object
# meta-info v1.1 — Compact summary of 1C metadata object
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory=$true)][Alias('Path')][string]$ObjectPath,
@@ -422,22 +422,6 @@ $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) {
@@ -609,17 +593,6 @@ 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
+1 -29
View File
@@ -1,4 +1,4 @@
# meta-info v1.2 — Compact summary of 1C metadata object (Python port)
# meta-info v1.1 — Compact summary of 1C metadata object (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -477,21 +477,6 @@ 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
@@ -651,19 +636,6 @@ 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
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.МойМодуль"
```
---
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.МойМодуль"
```
+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
python "${CLAUDE_SKILL_DIR}/scripts/meta-validate.py" -ObjectPath "Catalogs/Номенклатура/Номенклатура.xml"
python "${CLAUDE_SKILL_DIR}/scripts/meta-validate.py" -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
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/Заказ"
```
+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
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 учитывает занятые ячейки)
---
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 учитывает занятые ячейки)
+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
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`, а пустые ячейки исключаются из вывода.
---
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`, а пустые ячейки исключаются из вывода.
+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
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). Параметр внутри `[]` заполняется программно.
---
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). Параметр внутри `[]` заполняется программно.
+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
python "${CLAUDE_SKILL_DIR}/scripts/mxl-validate.py" -TemplatePath "Catalogs/Номенклатура/Templates/Макет"
python "${CLAUDE_SKILL_DIR}/scripts/mxl-validate.py" -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
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/ПечатнаяФорма"
```
+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
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> — визуальная сводка структуры
```
---
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> — визуальная сводка структуры
```
+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
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 строк
```
---
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 строк
```
+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
python "${CLAUDE_SKILL_DIR}/scripts/role-validate.py" -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
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/role-validate.ps1" -RightsPath "Roles/МояРоль"
```
+416 -436
View File
@@ -1,436 +1,416 @@
---
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 — проверка варианта настроек
```
---
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 — проверка варианта настроек
```
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-52
View File
@@ -1,52 +0,0 @@
---
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
+361 -373
View File
@@ -1,373 +1,361 @@
---
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> — визуальная сводка
```
---
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> — визуальная сводка
```
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+75 -80
View File
@@ -1,80 +1,75 @@
---
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> — трассировка поля
```
---
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> — трассировка поля
```
+246
View File
@@ -0,0 +1,246 @@
# /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
+4 -17
View File
@@ -1,4 +1,4 @@
# skd-info v1.6 — Analyze 1C DCS structure
# skd-info v1.4 — Analyze 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory=$true)]
@@ -10,8 +10,7 @@ param(
[int]$Batch = 0,
[int]$Limit = 150,
[int]$Offset = 0,
[string]$OutFile,
[switch]$Raw
[string]$OutFile
)
$ErrorActionPreference = "Stop"
@@ -656,13 +655,6 @@ 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
@@ -1883,12 +1875,7 @@ $totalLines = $result.Count
# OutFile
if ($OutFile) {
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
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)
[System.IO.File]::WriteAllLines((Join-Path (Get-Location) $OutFile), $result, $utf8Bom)
Write-Host "Written $totalLines lines to $OutFile"
exit 0
}
@@ -1902,7 +1889,7 @@ if ($Offset -gt 0) {
$result = $result[$Offset..($totalLines - 1)]
}
if (-not $Raw -and $result.Count -gt $Limit) {
if ($result.Count -gt $Limit) {
$shown = $result[0..($Limit - 1)]
foreach ($l in $shown) { Write-Host $l }
Write-Host ""
+2 -10
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# skd-info v1.6 — Analyze 1C DCS structure
# skd-info v1.4 — Analyze 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -278,7 +278,6 @@ 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 ---
@@ -635,13 +634,6 @@ 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
@@ -1727,7 +1719,7 @@ def main():
sys.exit(0)
result = result[args.Offset:]
if not args.Raw and len(result) > args.Limit:
if 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
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"
```
---
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"
```
@@ -1,4 +1,4 @@
# skd-validate v1.2 — Validate 1C DCS structure
# skd-validate v1.1 — Validate 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -438,17 +438,6 @@ 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)
@@ -468,15 +457,8 @@ if ($calcFieldNodes.Count -gt 0) {
}
if (-not $expr -or -not $expr.InnerText.Trim()) {
# 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?)"
}
Report-Error "CalculatedField '$path' has empty expression"
$cfOk = $false
}
# Warn if collides with a dataset field
@@ -560,16 +542,14 @@ if ($templateNodes.Count -gt 0) {
}
$tName = $nameNode.InnerText
if ($tplSeen.ContainsKey($tName)) {
# 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)"
Report-Error "Duplicate template name: $tName"
$tplOk = $false
} else {
$tplSeen[$tName] = $true
}
}
if ($tplOk) {
Report-OK "$($templateNodes.Count) template(s) found"
Report-OK "$($templateNodes.Count) template(s): names unique"
}
}
@@ -601,8 +581,7 @@ if ($script:stopped) { & $finalize; exit 1 }
$validComparisonTypes = @(
"Equal","NotEqual","Greater","GreaterOrEqual","Less","LessOrEqual",
"InList","NotInList","InHierarchy","NotInHierarchy",
"InListByHierarchy","NotInListByHierarchy",
"InList","NotInList","InHierarchy","InListByHierarchy",
"Contains","NotContains","BeginsWith","NotBeginsWith",
"Filled","NotFilled"
)
@@ -755,176 +734,6 @@ 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.2 — Validate 1C DCS structure (Python port)
# skd-validate v1.1 — Validate 1C DCS structure (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -434,15 +434,6 @@ 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")
@@ -460,14 +451,8 @@ if len(calc_field_nodes) > 0:
cf_seen[path] = True
if expr is None or not text_of(expr):
# 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?)")
report_error(f"CalculatedField '{path}' has empty expression")
cf_ok = False
# Warn if collides with a dataset field
if path in all_field_paths:
@@ -541,14 +526,12 @@ if len(template_nodes) > 0:
continue
t_name = inner_text(name_node)
if t_name in tpl_seen:
# 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)")
report_error(f"Duplicate template name: {t_name}")
tpl_ok = False
else:
tpl_seen[t_name] = True
if tpl_ok:
report_ok(f"{len(template_nodes)} template(s) found")
report_ok(f"{len(template_nodes)} template(s): names unique")
# ── 13. GroupTemplate checks ─────────────────────────────────
@@ -575,8 +558,7 @@ if stopped:
valid_comparison_types = (
"Equal", "NotEqual", "Greater", "GreaterOrEqual", "Less", "LessOrEqual",
"InList", "NotInList", "InHierarchy", "NotInHierarchy",
"InListByHierarchy", "NotInListByHierarchy",
"InList", "NotInList", "InHierarchy", "InListByHierarchy",
"Contains", "NotContains", "BeginsWith", "NotBeginsWith",
"Filled", "NotFilled",
)
@@ -703,166 +685,6 @@ 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
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
```
---
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
```
+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
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"}'
```
---
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"}'
```
+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
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 Администрирование
```
---
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 Администрирование
```
+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
python "${CLAUDE_SKILL_DIR}/scripts/subsystem-validate.py" -SubsystemPath "Subsystems/Продажи"
python "${CLAUDE_SKILL_DIR}/scripts/subsystem-validate.py" -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
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"
```
+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
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`
---
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`
+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
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` — значение очищается
---
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` — значение очищается
+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
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"
```
---
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"
```
+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
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
```
---
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
```
+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
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"
```
---
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"
```
+22 -66
View File
@@ -69,12 +69,6 @@ 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
@@ -165,7 +159,7 @@ const form = await getFormState();
### Reading data
#### `readTable({ maxRows?, offset?, table? })``{ columns, rows, total, shown, offset, hasMore }`
#### `readTable({ maxRows?, offset?, table? })``{ columns, rows, total, shown, offset }`
Read actual grid data with pagination. Each row is `{ columnName: value }`.
| Option | Default | Description |
@@ -174,12 +168,6 @@ 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
@@ -189,22 +177,10 @@ 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('Loaded:', t.shown, 'rows; more below:', t.hasMore.below);
console.log('Rows:', t.rows.length, 'of', t.total);
// Pagination:
const page2 = await readTable({ maxRows: 50, offset: 50 });
```
@@ -235,9 +211,7 @@ Sections + all open tabs.
### Actions
**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
#### `clickElement(text, { dblclick?, table?, expand?, modifier? })` → 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[]`):
@@ -259,11 +233,6 @@ 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
@@ -273,32 +242,26 @@ 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
```
- **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:
- **SpreadsheetDocument cells** (report drill-down): first argument can be `{ row, column }` object to click a cell in a rendered report. Coordinates match `readSpreadsheet()` output:
```js
const report = await readSpreadsheet();
// report.data[0] = { 'К1': 'Материалы строительные', 'К6': '150 000', ... }
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
```
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:
// 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 });
```
Text search also works as fallback — searches inside spreadsheet iframes:
```js
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
await clickElement('150 000', { dblclick: true }); // finds cell by text in report
```
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`
#### `fillFields({ name: value })``{ filled, form }`
Fill form fields by label (fuzzy match). Auto-detects field type.
| Value | Field type | Method |
@@ -317,7 +280,8 @@ await fillFields({
});
```
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.
Returns `{ filled: [{ field, ok, value, method }], form: {...} }`.
Method is one of: `'clear'` | `'toggle'` | `'radio'` | `'paste'` | `'dropdown'` | `'form'` | `'typeahead'`
#### `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).
@@ -340,19 +304,14 @@ await selectValue('Документ', '0000-000601', { type: 'Реализаци
Also supports DCS labels — auto-enables the paired checkbox.
#### `fillTableRow(fields, opts)` → form state with `filled` (+ optional `notFilled`)
#### `fillTableRow(fields, opts)` → form state
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: 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) |
| `row` | Edit existing row by 0-based index |
| `table` | Grid name from `tables[]` (for multi-grid forms) |
```js
@@ -361,14 +320,11 @@ await fillTableRow(
{ 'Номенклатура': 'Бумага', 'Количество': '10', 'Цена': '100' },
{ tab: 'Товары', add: true }
);
// Edit existing row by index:
// Edit existing row:
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(
{ 'Объект': 'БДДС' },
@@ -569,7 +525,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). 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`
- **Clipboard paste** — all text fields filled via Ctrl+V (triggers 1C events properly)
- **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
+164 -155
View File
@@ -5,11 +5,9 @@ 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 <dir|file>... [flags]
node $RUN test [url] <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`
@@ -17,6 +15,7 @@ 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` |
@@ -26,15 +25,73 @@ 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.
Two layers, in order. Don't skip either.
**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.
### 1. Static recon — metadata
**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 () => { ... })`.
Never invent identifiers. For every metadata object the user mentions (or that you decide to cover), run the matching info skill first:
The mechanics of `exec` / `getFormState` / `fillFields` / `clickElement` are in [SKILL.md](SKILL.md) — read it before recon if you haven't already.
| 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` |
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.
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.
## Suite layout
@@ -42,20 +99,30 @@ 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
...
```
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).
`<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).
```
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
@@ -65,11 +132,15 @@ 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
@@ -114,95 +185,18 @@ export default async function(ctx) {
}
```
**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`.
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.
## `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.
**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`.
## webtest.config.mjs
```js
export default {
// Single-context shorthand:
// Single-context: just url.
url: 'http://localhost:9191/myapp/ru_RU',
// OR multi-context:
// OR multi-context: named contexts. Each test picks via `context`/`contexts` exports.
// contexts: {
// clerk: { url: 'http://localhost:9191/myapp-clerk/ru_RU', displayName: 'Кладовщик' },
// manager: { url: 'http://localhost:9191/myapp-manager/ru_RU', displayName: 'Менеджер' },
@@ -211,7 +205,7 @@ export default {
timeout: 30000,
retries: 0,
screenshot: 'on-failure', // 'every-step' | 'off'
screenshot: 'on-failure',
record: false,
// Severity → tags mapping for Allure. Each tag at most one bucket.
@@ -223,7 +217,7 @@ export default {
};
```
CLI flags override config. Use latin context IDs + Russian `displayName` for ergonomics — `ctx.testInfo.contexts.clerk.displayName` is friendlier than mixed-case Cyrillic keys.
CLI flags override config. Recommend latin context IDs + Russian `displayName` for video badges.
## _hooks.mjs
@@ -234,44 +228,74 @@ import { execSync } from 'child_process';
// Infra — runs once around the whole suite.
export async function prepare({ hookArgs, log, config }) {
// 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.
// 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.
}
export async function cleanup({ log, config }) { /* optional */ }
export async function cleanup({ log, config }) {
// Tear down or leave the stand running. Choose per project.
}
// 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.testInfo + ctx.testResult set */ }
export async function afterEach(ctx) { /* ctx.testResult is 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 in `afterEach`.
Pass hook args after `--`:
```bash
node $RUN test tests/<app-name>/ --bail -- --rebuild-stand --data=demo
└─runner─┘ └────── hookArgs ─────────┘
```
Built-in state reset (`dismissPendingErrors` + close all forms) runs after `afterEach` automatically. Don't reimplement it.
**Where to put data setup:**
- DB restore, publication, EPF build → `prepare()`. Make it idempotent (hash-locks).
- Test-specific seed data → per-test `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`.
- Shared session-wide warmup → `beforeAll`.
## Ready-to-paste patterns
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).
### 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.
### DCS report
@@ -311,7 +335,7 @@ export default async function({ clerk, manager, step, assert }) {
});
await step('Кладовщик видит новый статус', async () => {
const s = await clerk.getFormState();
assert.equal(s.fields['Статус']?.value, 'Утверждён');
assert.equal(s.fields.find(f => f.name === 'Статус')?.value, 'Утверждён');
});
await step('Освободить сессию кладовщика', async () => {
await manager.closeContext('clerk'); // free a 1C license for the next test
@@ -319,7 +343,7 @@ export default async function({ clerk, manager, step, assert }) {
}
```
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.
License caveat: stock 1C allows ~2 web sessions concurrently. Close contexts you no longer need before the next multi-user test starts.
### Failing-test repro
@@ -332,52 +356,37 @@ export default async function({ openCommand, clickElement, getFormState, assert,
await clickElement('Создать');
await clickElement('Провести');
const s = await getFormState();
assert.ok(s.errorModal || s.fields['Контрагент']?.required,
assert.ok(s.errorModal || s.fields.find(f => f.name === 'Контрагент')?.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>/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>/ --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>/ --report=- # machine JSON to stdout, progress to stderr
node $RUN test tests/<app-name>/ -- --rebuild-stand # after `--` → hookArgs
node $RUN test tests/<app-name>/ -- --rebuild-stand # everything after `--` goes to hooks
```
**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.)
Default report is JSON when `--report=` is given. Allure needs `--format=allure` + a directory. JUnit similarly with `--format=junit`.
### Allure static config — `_allure/`
### Allure static config — `_allure/` directory
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.
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.
## Severity guidance
@@ -395,26 +404,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 — wait on `getFormState` instead.
- **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.
- **Retry as a substitute for understanding.** "Not found" twice means the data isn't there or the label is wrong. Don't loop.
- **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.
- **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.
- **`tags: ['smoke']` on a 90-second test.** Smoke means fast.
- **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.)
- **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.
## After a run — failure triage
1. Scan the JSON or Allure summary for `failed`.
2. For each failure, read `error.message` + `error.step` + screenshot.
2. For each failure, read `error.message` + `error.step` + screenshot (saved next to the report).
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 before the full suite.
5. After fixes, re-run only the affected files (`node $RUN test tests/03-goods-receipt/`) 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
@@ -1,36 +0,0 @@
// 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);
}
@@ -1,22 +0,0 @@
// 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);
}
@@ -1,18 +0,0 @@
// 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 });
}
@@ -1,33 +0,0 @@
// 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);
});
}
@@ -1,14 +0,0 @@
// 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 });
}
@@ -1,17 +0,0 @@
// 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();
}
@@ -1,458 +0,0 @@
// 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);
}
@@ -1,148 +0,0 @@
// 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;
}
}
@@ -1,37 +0,0 @@
// 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);
}
}
@@ -1,20 +0,0 @@
// 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 {}
}
@@ -1,64 +0,0 @@
// 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);
},
};
}
@@ -1,43 +0,0 @@
// 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; }
}
}
@@ -1,113 +0,0 @@
// 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');
}
@@ -1,66 +0,0 @@
// 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;
}
@@ -1,113 +0,0 @@
// 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
@@ -1,391 +0,0 @@
// 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
@@ -1,108 +0,0 @@
// 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