From 9877fe403a891d38780f59a50e386a0f8a113fe6 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Wed, 3 Jun 2026 22:11:48 +0300 Subject: [PATCH] =?UTF-8?q?feat(skd-info):=20=D1=84=D0=BB=D0=B0=D0=B3=20-R?= =?UTF-8?q?aw=20=D0=B4=D0=BB=D1=8F=20lossless=20round-trip=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit skd-info -Mode query был просмотрщиком (заголовки, оглавление батчей, разделители --- Batch ---) и терял разделители пакетов при split, поэтому не годился как источник для skd-edit set-query @file. Флаг -Raw отдаёт текст запроса целиком, verbatim, без декораций и без дробления на пакеты — все ; и //// на месте. С -OutFile пишет чистый .sql, который без потерь возвращается через set-query @file. Stdout не усекается по -Limit. Версия v1.6 в обоих скриптах (ps1 + py). Документация: таблица параметров/режимов и round-trip workflow в skd-info, указатель + разводка patch-query vs set-query+-Raw в skd-edit. Тесты: query-raw (raw без декораций, разделитель //// сохранён) и query-view (просмотр не задет). Зелёные на ps1 и py. Чистка: удалён modes-reference.md — галерея примеров вывода избыточна для модели (инструмент самодемонстрирующийся), а человек покрыт docs/skd-guide.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/skd-edit/SKILL.md | 2 + .claude/skills/skd-info/SKILL.md | 13 +- .claude/skills/skd-info/modes-reference.md | 246 ------------------- .claude/skills/skd-info/scripts/skd-info.ps1 | 14 +- .claude/skills/skd-info/scripts/skd-info.py | 12 +- tests/skills/cases/skd-info/query-raw.json | 22 ++ tests/skills/cases/skd-info/query-view.json | 21 ++ 7 files changed, 75 insertions(+), 255 deletions(-) delete mode 100644 .claude/skills/skd-info/modes-reference.md create mode 100644 tests/skills/cases/skd-info/query-raw.json create mode 100644 tests/skills/cases/skd-info/query-view.json diff --git a/.claude/skills/skd-edit/SKILL.md b/.claude/skills/skd-edit/SKILL.md index be7feed6..3d44815d 100644 --- a/.claude/skills/skd-edit/SKILL.md +++ b/.claude/skills/skd-edit/SKILL.md @@ -256,6 +256,8 @@ Value — имена ресурсов (как в полях/вычисляемы Не поддерживает пакетный режим. Value — полный текст запроса или `@path/to/file.sql` (ссылка на внешний файл). Путь разрешается относительно Template.xml, затем CWD. +Когда что: **существенная переработка** (добавить поля, соединения, переписать пакет) → выгрузи запрос через `/skd-info -Mode query -Name <набор> -Raw -OutFile file.sql`, отредактируй файл, верни `set-query @file`. `-Raw` отдаёт запрос целиком без декораций, поэтому выгрузка ↔ возврат точны (включая многопакетные запросы). **Точечная замена** (переименовать идентификатор, заменить подстроку) → выгрузка не нужна, используй `patch-query` ниже. + ### patch-query — точечная замена в тексте запроса Shorthand: `"старое => новое [@once]"`. По умолчанию заменяет все вхождения подстроки. Поддерживает пакетный режим и `-DataSet`. diff --git a/.claude/skills/skd-info/SKILL.md b/.claude/skills/skd-info/SKILL.md index a594bbc1..962e3b15 100644 --- a/.claude/skills/skd-info/SKILL.md +++ b/.claude/skills/skd-info/SKILL.md @@ -1,7 +1,7 @@ --- name: skd-info description: Анализ структуры схемы компоновки данных 1С (СКД) — наборы, поля, параметры, варианты. Используй для понимания отчёта — источник данных (запрос), доступные поля, параметры -argument-hint: [-Mode overview|query|fields|links|calculated|resources|params|variant|templates|trace|full] [-Name ] +argument-hint: [-Mode overview|query|fields|links|calculated|resources|params|variant|templates|trace|full] [-Name ] [-Raw] allowed-tools: - Bash - Read @@ -20,7 +20,8 @@ allowed-tools: | `Mode` | Режим анализа (по умолчанию `overview`) | | `Name` | Имя набора (query), поля (fields/calculated/resources/trace), варианта (variant) или группировки/поля (templates) | | `Batch` | Номер пакета запроса, 0 = все (только query) | -| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк) | +| `Raw` | (только query) сырой текст запроса целиком, без заголовков/оглавления/разделителей пакетов. Для выгрузки в `.sql` и возврата через `skd-edit set-query @file` | +| `Limit` / `Offset` | Пагинация (по умолчанию 150 строк; `-Raw` не усекается) | | `OutFile` | Записать результат в файл (UTF-8 BOM) | ```powershell @@ -31,6 +32,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-info.ps1" -Temp ```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 СуммаНалога @@ -45,7 +47,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-info.ps1" -Temp | Режим | Без `-Name` | С `-Name` | |-------|-------------|-----------| | `overview` | Навигационная карта схемы + подсказки Next | — | -| `query` | — | Текст запроса набора (с оглавлением батчей) | +| `query` | — | Текст запроса набора (с оглавлением батчей); `-Raw` — чистая выгрузка для правки | | `fields` | Карта: имена полей по наборам | Деталь поля: набор, тип, роль, формат | | `links` | Все связи наборов | — | | `calculated` | Карта: имена вычисляемых полей | Выражение + заголовок + ограничения | @@ -65,7 +67,10 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-info.ps1" -Temp 3. `query -Name <набор>` — посмотреть текст SQL-запроса 4. `variant -Name ` — посмотреть группировки и фильтры варианта -Подробные примеры вывода каждого режима — в `modes-reference.md`. +Переработка запроса (round-trip): `query -Name <набор> -Raw -OutFile q.sql` → +правка `q.sql` → `/skd-edit -Operation set-query -Value "@q.sql"`. Флаг +`-Raw` отдаёт запрос целиком без декораций, поэтому выгрузка ↔ возврат +точны (включая многопакетные запросы с временными таблицами). ## Верификация diff --git a/.claude/skills/skd-info/modes-reference.md b/.claude/skills/skd-info/modes-reference.md deleted file mode 100644 index eb6bd983..00000000 --- a/.claude/skills/skd-info/modes-reference.md +++ /dev/null @@ -1,246 +0,0 @@ -# /skd-info — полная справка по режимам - -Компактное описание — в [SKILL.md](SKILL.md). - -## overview (по умолчанию) — карта схемы - -Компактная навигационная карта (10-25 строк). Показывает структуру и подсказывает следующие шаги: - -``` -=== DCS: ОсновнаяСхемаКомпоновкиДанных (362 lines) === - -Sources: ИсточникДанных1 (Local) - -Datasets: - [Query] НоменклатураСЦенами 7 fields, query 40 lines -Calculated: 1 -Resources: 1 -Templates: 1 templates, 1 group bindings -Params: (none) - -Variants: - [1] НоменклатураИЦены "Номенклатура и цены" Table(detail) 3 filters - [2] НоменклатураБезЦен "Номенклатура без цен" Group(detail) 2 filters - -Next: - -Mode query query text - -Mode fields field tables by dataset - -Mode calculated calculated field expressions - -Mode resources resource aggregation - -Mode variant -Name 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 (`&`→`&`, `>`→`>`). Для пакетных запросов — оглавление батчей: - -``` -=== 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 ` — структура конкретного варианта: -``` -=== 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 diff --git a/.claude/skills/skd-info/scripts/skd-info.ps1 b/.claude/skills/skd-info/scripts/skd-info.ps1 index 46bba981..066b0d0e 100644 --- a/.claude/skills/skd-info/scripts/skd-info.ps1 +++ b/.claude/skills/skd-info/scripts/skd-info.ps1 @@ -1,4 +1,4 @@ -# skd-info v1.5 — Analyze 1C DCS structure +# skd-info v1.6 — Analyze 1C DCS structure # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory=$true)] @@ -10,7 +10,8 @@ param( [int]$Batch = 0, [int]$Limit = 150, [int]$Offset = 0, - [string]$OutFile + [string]$OutFile, + [switch]$Raw ) $ErrorActionPreference = "Stop" @@ -655,6 +656,13 @@ function Show-Query { } $rawQuery = Unescape-Xml $queryNode.InnerText + + # Raw mode: emit verbatim query text only (no headers/TOC/batch split) for round-trip + if ($Raw) { + foreach ($ql in ($rawQuery.Trim() -split "`n")) { $lines.Add($ql.TrimEnd()) } + return + } + $dsNameStr = $targetDs.SelectSingleNode("s:name", $ns).InnerText # Split into batches @@ -1894,7 +1902,7 @@ if ($Offset -gt 0) { $result = $result[$Offset..($totalLines - 1)] } -if ($result.Count -gt $Limit) { +if (-not $Raw -and $result.Count -gt $Limit) { $shown = $result[0..($Limit - 1)] foreach ($l in $shown) { Write-Host $l } Write-Host "" diff --git a/.claude/skills/skd-info/scripts/skd-info.py b/.claude/skills/skd-info/scripts/skd-info.py index 3303a8fb..fda5e375 100644 --- a/.claude/skills/skd-info/scripts/skd-info.py +++ b/.claude/skills/skd-info/scripts/skd-info.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# skd-info v1.5 — Analyze 1C DCS structure +# skd-info v1.6 — Analyze 1C DCS structure # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -278,6 +278,7 @@ def main(): parser.add_argument("-Limit", type=int, default=150) parser.add_argument("-Offset", type=int, default=0) parser.add_argument("-OutFile", default=None) + parser.add_argument("-Raw", action="store_true") args = parser.parse_args() # --- Resolve path --- @@ -634,6 +635,13 @@ def main(): sys.exit(1) raw_query = unescape_xml("".join(query_node.itertext())) + + # Raw mode: emit verbatim query text only (no headers/TOC/batch split) for round-trip + if args.Raw: + for ql in raw_query.strip().split("\n"): + lines.append(ql.rstrip()) + return + ds_name_str = (target_ds.find("s:name", NSMAP).text or "") # Split into batches @@ -1719,7 +1727,7 @@ def main(): sys.exit(0) result = result[args.Offset:] - if len(result) > args.Limit: + if not args.Raw and len(result) > args.Limit: shown = result[:args.Limit] for line in shown: print(line) diff --git a/tests/skills/cases/skd-info/query-raw.json b/tests/skills/cases/skd-info/query-raw.json new file mode 100644 index 00000000..9a58a9af --- /dev/null +++ b/tests/skills/cases/skd-info/query-raw.json @@ -0,0 +1,22 @@ +{ + "name": "Raw-выгрузка многопакетного запроса без декораций", + "preRun": [ + { + "script": "skd-compile/scripts/skd-compile", + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ 1 КАК Поле\nПОМЕСТИТЬ ВТ_Первая\n;\n////////////////////////////////////////////////////////////////////////////////\nВЫБРАТЬ Поле ИЗ ВТ_Первая КАК Т", + "fields": ["Поле"] + }] + }, + "args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" } + } + ], + "params": { "templatePath": "Template.xml" }, + "args_extra": ["-Mode", "query", "-Name", "Основной", "-Raw"], + "expect": { + "stdoutContains": ["ПОМЕСТИТЬ ВТ_Первая", "////", "ВЫБРАТЬ Поле ИЗ ВТ_Первая"], + "stdoutNotContains": ["=== Query", "--- Batch", "Batch 1: lines"] + } +} diff --git a/tests/skills/cases/skd-info/query-view.json b/tests/skills/cases/skd-info/query-view.json new file mode 100644 index 00000000..cee45827 --- /dev/null +++ b/tests/skills/cases/skd-info/query-view.json @@ -0,0 +1,21 @@ +{ + "name": "Просмотр запроса (без -Raw) сохраняет декорации", + "preRun": [ + { + "script": "skd-compile/scripts/skd-compile", + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ 1 КАК Поле\nПОМЕСТИТЬ ВТ_Первая\n;\n////////////////////////////////////////////////////////////////////////////////\nВЫБРАТЬ Поле ИЗ ВТ_Первая КАК Т", + "fields": ["Поле"] + }] + }, + "args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" } + } + ], + "params": { "templatePath": "Template.xml" }, + "args_extra": ["-Mode", "query", "-Name", "Основной"], + "expect": { + "stdoutContains": ["=== Query", "--- Batch", "Batch 1: lines"] + } +}