feat(skd-info): флаг -Raw для lossless round-trip извлечения запроса

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) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-03 22:11:48 +03:00
parent 46ee078343
commit 9877fe403a
7 changed files with 75 additions and 255 deletions
+2
View File
@@ -256,6 +256,8 @@ Value — имена ресурсов (как в полях/вычисляемы
Не поддерживает пакетный режим. 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`.
+9 -4
View File
@@ -1,7 +1,7 @@
---
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>]
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
@@ -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 <N>` — посмотреть группировки и фильтры варианта
Подробные примеры вывода каждого режима — в `modes-reference.md`.
Переработка запроса (round-trip): `query -Name <набор> -Raw -OutFile q.sql`
правка `q.sql``/skd-edit <tpl> -Operation set-query -Value "@q.sql"`. Флаг
`-Raw` отдаёт запрос целиком без декораций, поэтому выгрузка ↔ возврат
точны (включая многопакетные запросы с временными таблицами).
## Верификация
-246
View File
@@ -1,246 +0,0 @@
# /skd-info — полная справка по режимам
Компактное описание — в [SKILL.md](SKILL.md).
## overview (по умолчанию) — карта схемы
Компактная навигационная карта (10-25 строк). Показывает структуру и подсказывает следующие шаги:
```
=== DCS: ОсновнаяСхемаКомпоновкиДанных (362 lines) ===
Sources: ИсточникДанных1 (Local)
Datasets:
[Query] НоменклатураСЦенами 7 fields, query 40 lines
Calculated: 1
Resources: 1
Templates: 1 templates, 1 group bindings
Params: (none)
Variants:
[1] НоменклатураИЦены "Номенклатура и цены" Table(detail) 3 filters
[2] НоменклатураБезЦен "Номенклатура без цен" Group(detail) 2 filters
Next:
-Mode query query text
-Mode fields field tables by dataset
-Mode calculated calculated field expressions
-Mode resources resource aggregation
-Mode variant -Name <N> variant structure (1..2)
```
Для DataSetUnion — дерево наборов + связи:
```
Datasets:
[Union] РасчетНалогаНаИмущество 52 fields
├─ [Query] РасчетНалогаНаИмущество 51 fields, query 181 lines
├─ [Query] ДанныеПоКадастровой 29 fields, query 40 lines
├─ [Query] ДанныеПоСреднегодовой 34 fields, query 41 lines
Links: РасчетНалогаНаИмущество -> СостояниеОС (2 fields)
```
Параметры разделяются на видимые/скрытые:
```
Params: 18 (7 visible, 11 hidden): Период, Ответственный, ...
```
## query — текст запроса
`-Name <набор>` — имя DataSet (обязателен если наборов > 1).
Извлекает raw-текст запроса с деэкранированием XML (`&amp;``&`, `&gt;``>`). Для пакетных запросов — оглавление батчей:
```
=== Query: ДанныеТ13 (334 lines, 13 batches) ===
Batch 1: lines 1-8 → ПОМЕСТИТЬ Представления_Периоды
Batch 2: lines 9-26 → ПОМЕСТИТЬ Представления_СотрудникиОрганизации
...
--- Batch 1 ---
ВЫБРАТЬ
ДАТАВРЕМЯ(1, 1, 1) КАК Период
ПОМЕСТИТЬ Представления_Периоды
...
```
Фильтр по номеру батча: `-Batch 3` покажет только 3-й пакет.
## fields — поля наборов данных
Без `-Name` — карта: имена полей по наборам:
```
=== Fields map ===
СостояниеОС [Query] (3): Организация, ОсновноеСредство, ДатаСостояния
РасчетНалогаНаИмущество [Union] (52): ДоляСтоимостиЧислитель, ...
РасчетНалогаНаИмущество [Query] (51): КадастроваяСтоимость, ...
```
С `-Name <поле>` — детали конкретного поля:
```
=== Field: ДатаСостояния "Дата ввода в эксплуатацию" ===
Dataset: СостояниеОС [Query]
Format: ДФ=dd.MM.yyyy
```
Показывает: dataset, title, type, role, useRestriction, format, presentationExpression.
## links — связи наборов данных
```
=== Links (4) ===
РасчетНалогаНаИмущество -> СостояниеОС :
Организация -> Организация
ОсновноеСредство -> ОсновноеСредство
```
Группирует по парам наборов. Показывает поля связи и параметры.
## calculated — вычисляемые поля
Без `-Name` — карта: имена и заголовки:
```
=== Calculated fields (23) ===
ДоляСтоимости "Доля стоимости"
КоэффициентКи "Коэффициент Ки"
...
```
С `-Name <поле>` — полное выражение:
```
=== Calculated: ДоляСтоимости ===
Expression:
ВЫБОР КОГДА ... ТОГДА "1" ИНАЧЕ ... КОНЕЦ
Title: Доля стоимости
Restrict: condition
```
## resources — ресурсы (итоги по группировкам)
Без `-Name` — карта: имена полей, `*` = есть формулы по группировкам:
```
=== Resources (51) ===
НалоговаяБаза
КоэффициентКи *
...
* = has group-level formulas
```
С `-Name <поле>` — формулы агрегации:
```
=== Resource: ДатаСостояния ===
[ОсновноеСредство] ЕстьNull(ДатаСостояния, "")
```
## params — параметры схемы
```
=== Parameters (16) ===
Name Type Default Visible Expression
Период StandardPeriod LastMonth yes -
НачалоПериода DateTime - hidden &Период.ДатаНачала
Организация CatalogRef.Организации null yes -
```
## variant — варианты отчёта
Без `-Name` — список вариантов:
```
=== Variants (2) ===
[1] НоменклатураИЦены "Номенклатура и цены" Table(detail) 3 filters
[2] НоменклатураБезЦен "Номенклатура без цен" Group(detail) 2 filters
```
С `-Name <N|имя>` — структура конкретного варианта:
```
=== Variant [1]: НоменклатураИЦены "Номенклатура и цены" ===
Structure:
Table "Таблица"
├── Columns: [ТипЦен Items]
│ Selection: Auto, Цена
└── Rows: [Номенклатура Items]
Selection: Номенклатура, УИД, Auto
Filter:
[ ] Номенклатура InHierarchy [user]
[ ] ТипЦен Equal
[x] ВАрхиве = false "Исключая скрытые товары"
DataParams: КлючВарианта="НоменклатураИЦены"
Output: style=ЧерноБелый groups=Separately totalsH=None totalsV=None
```
## templates — привязки шаблонов вывода
Три типа привязок: `fieldTemplate` (к полю), `groupTemplate` (к группировке, Header/Footer), `groupHeaderTemplate` (заголовок группы).
Без `-Name` — карта привязок:
```
=== Templates (70 defined: 49 field, 37 group) ===
Field bindings (49): (all trivial)
ОстаточнаяСтоимостьНа0101, ОстаточнаяСтоимостьНа0102, ...
Group bindings (37):
ВидНалоговойБазы
Header -> Макет3 (1 rows, 1 params)
СреднегодоваяСтоимость2019
Footer -> Макет50 (1 rows) spacer
GroupHeader -> Макет40 (3 rows)
```
С `-Name <группировка|поле>` — содержимое шаблонов:
```
=== Templates: СреднегодоваяСтоимость2019 ===
Footer -> Макет50 [1 rows, 1 cells]:
Row 1: (empty)
GroupHeader -> Макет40 [3 rows, 78 cells]:
Row 1: "№ п/п" | "###Группировки1###" | "Инв. номер" | ...
Row 2: "01.01" | "01.02" | ... | "31.12"
Row 3: "1" | "2" | ... | "26"
```
Для field-привязок:
```
=== Field template: ОстаточнаяСтоимостьНа0101 -> Макет4 ===
[1 rows, 1 cells]
Row 1: {ОстаточнаяСтоимостьНа0101}
(all params trivial)
```
**Тривиальность выражений**: `Поле = Поле` и `Поле = Представление(Поле)` считаются тривиальными и НЕ выводятся. Показываются только нетривиальные — когда выражение содержит другое поле, вызов метода, пустую строку и т.д.
## trace — трассировка поля от заголовка до запроса
Ищет поле по dataPath ИЛИ заголовку (включая подстроку) и показывает полную цепочку происхождения за один вызов:
```
=== Trace: КоэффициентКи "Коэффициент Ки" ===
Dataset: (schema-level only, not in dataset fields)
Calculated:
ВЫБОР КОГДА ... ТОГДА 0 ИНАЧЕ ... КОНЕЦ
Operands:
КоличествоМесяцевИспользования -> РасчетНалогаНаИмущество [Query]
КоличествоМесяцевВладения -> РасчетНалогаНаИмущество [Query]
Resource:
[ОсновноеСредство] Сумма(КоэффициентКи)
```
Типичный сценарий: пользователь видит колонку "Коэффициент Ки" в отчёте и спрашивает как она считается. Один вызов `trace` показывает: формулу вычисления, откуда берутся операнды, как агрегируется в ресурс.
## Что не выводится
- XML namespace-декларации
- Обёртки v8:item/v8:lang/v8:content (извлекаем чистый текст)
- userSettingID (GUID-ы пользовательских настроек)
- Дефолтные periodAdditionBegin/End = 0001-01-01
- viewMode
+11 -3
View File
@@ -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 ""
+10 -2
View File
@@ -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)
@@ -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"]
}
}
@@ -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"]
}
}