diff --git a/.claude/skills/skd-edit/SKILL.md b/.claude/skills/skd-edit/SKILL.md
index 987f2de7..7d42864b 100644
--- a/.claude/skills/skd-edit/SKILL.md
+++ b/.claude/skills/skd-edit/SKILL.md
@@ -36,7 +36,7 @@ powershell.exe -NoProfile -File .claude\skills\skd-edit\scripts\skd-edit.ps1 -Te
-Operation add-field -Value "Цена: decimal(15,2) ;; Количество: decimal(15,3) ;; Сумма: decimal(15,2)"
```
-Работает для всех операций кроме `set-query` и `set-structure`.
+Работает для всех операций кроме `set-query`, `set-structure` и `add-dataSet`.
## Операции
@@ -123,6 +123,41 @@ Shorthand: `"Источник > Приёмник on ВырИсточника =
"Набор1 > Набор2 on Поле1 = Поле2 [param Связь]"
```
+### add-dataSet — добавить набор данных
+
+Shorthand: `"Имя: ТЕКСТ_ЗАПРОСА"` или `"ТЕКСТ_ЗАПРОСА"` (авто-имя `НаборДанныхN`).
+
+```
+"Доп: ВЫБРАТЬ 1 КАК Тест"
+"ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура"
+```
+
+`dataSource` берётся из первого существующего. Дубликат имени — предупреждение, пропуск. Не поддерживает пакетный режим (запрос может содержать `;;`).
+
+### add-variant — добавить вариант настроек
+
+Shorthand: `"Имя [Представление]"`. Представление опционально, по умолчанию = имя.
+
+```
+"Детальный"
+"Детальный [Детальный отчёт]"
+```
+
+Создаёт вариант с Auto selection + detail group. Дубликат имени — предупреждение, пропуск.
+
+### add-conditionalAppearance — добавить условное оформление
+
+Shorthand: `"Параметр = значение [when Поле оп правое] [for Поле1, Поле2]"`.
+
+```
+"ЦветТекста = web:Red when Сумма < 0"
+"ЦветФона = web:LightGreen when Статус = Одобрен for Статус"
+"МинимальнаяШирина = 50 for Организация"
+"Формат = ЧДЦ=2 for Цена, Сумма"
+```
+
+Типы значений (автодетект): `web:*`/`style:*`/`win:*` → цвет, `true`/`false` → boolean, иначе строка.
+
### set-query — заменить текст запроса
Не поддерживает пакетный режим. Value — полный текст запроса.
diff --git a/.claude/skills/skd-edit/scripts/skd-edit.ps1 b/.claude/skills/skd-edit/scripts/skd-edit.ps1
index 8204d70a..6d92c3e3 100644
--- a/.claude/skills/skd-edit/scripts/skd-edit.ps1
+++ b/.claude/skills/skd-edit/scripts/skd-edit.ps1
@@ -1,4 +1,4 @@
-# skd-edit v1.0 — Atomic 1C DCS editor
+# skd-edit v1.1 — Atomic 1C DCS editor
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -8,6 +8,7 @@ param(
[ValidateSet(
"add-field","add-total","add-calculated-field","add-parameter","add-filter",
"add-dataParameter","add-order","add-selection","add-dataSetLink",
+ "add-dataSet","add-variant","add-conditionalAppearance",
"set-query","set-outputParameter","set-structure",
"modify-field","modify-filter","modify-dataParameter",
"clear-selection","clear-order","clear-filter",
@@ -428,6 +429,78 @@ function Parse-DataSetLinkShorthand {
return $result
}
+function Parse-DataSetShorthand {
+ param([string]$s)
+
+ $s = $s.Trim()
+ # "Name: QUERY" — split on first ": " only if prefix is a single word (no spaces)
+ if ($s -match '^(\S+):\s(.+)$') {
+ return @{ name = $Matches[1]; query = $Matches[2] }
+ }
+ return @{ name = ""; query = $s }
+}
+
+function Parse-VariantShorthand {
+ param([string]$s)
+
+ $presentation = ""
+ if ($s -match '\[([^\]]+)\]') {
+ $presentation = $Matches[1]
+ $s = $s -replace '\s*\[[^\]]+\]', ''
+ }
+ $name = $s.Trim()
+ if (-not $presentation) { $presentation = $name }
+ return @{ name = $name; presentation = $presentation }
+}
+
+function Parse-ConditionalAppearanceShorthand {
+ param([string]$s)
+
+ $result = @{ param = ""; value = ""; filter = $null; fields = @() }
+
+ # Extract " when ..." — condition part
+ $whenIdx = $s.IndexOf(' when ')
+ $forIdx = $s.IndexOf(' for ')
+
+ # Determine boundaries
+ $mainEnd = $s.Length
+ if ($whenIdx -ge 0 -and $forIdx -ge 0) {
+ $mainEnd = [Math]::Min($whenIdx, $forIdx)
+ } elseif ($whenIdx -ge 0) {
+ $mainEnd = $whenIdx
+ } elseif ($forIdx -ge 0) {
+ $mainEnd = $forIdx
+ }
+
+ # Parse "for" fields
+ if ($forIdx -ge 0) {
+ $forEnd = $s.Length
+ if ($whenIdx -gt $forIdx) { $forEnd = $whenIdx }
+ $forPart = $s.Substring($forIdx + 5, $forEnd - $forIdx - 5).Trim()
+ $result.fields = @($forPart -split '\s*,\s*' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
+ }
+
+ # Parse "when" filter
+ if ($whenIdx -ge 0) {
+ $whenEnd = $s.Length
+ if ($forIdx -gt $whenIdx) { $whenEnd = $forIdx }
+ $whenPart = $s.Substring($whenIdx + 6, $whenEnd - $whenIdx - 6).Trim()
+ $result.filter = Parse-FilterShorthand $whenPart
+ }
+
+ # Parse main part: "Param = Value"
+ $mainPart = $s.Substring(0, $mainEnd).Trim()
+ $eqIdx = $mainPart.IndexOf('=')
+ if ($eqIdx -gt 0) {
+ $result.param = $mainPart.Substring(0, $eqIdx).Trim()
+ $result.value = $mainPart.Substring($eqIdx + 1).Trim()
+ } else {
+ $result.param = $mainPart
+ }
+
+ return $result
+}
+
function Parse-StructureShorthand {
param([string]$s)
@@ -838,6 +911,104 @@ function Build-DataSetLinkFragment {
return $lines -join "`r`n"
}
+function Build-DataSetQueryFragment {
+ param($parsed, [string]$indent)
+
+ $i = $indent
+ $lines = @()
+ $lines += "$i"
+ $lines += "$i`t$(Esc-Xml $parsed.name)"
+ $lines += "$i`t$(Esc-Xml $parsed.dataSource)"
+ $lines += "$i`t$(Esc-Xml $parsed.query)"
+ $lines += "$i"
+ return $lines -join "`r`n"
+}
+
+function Build-VariantFragment {
+ param($parsed, [string]$indent)
+
+ $i = $indent
+ $lines = @()
+ $lines += "$i"
+ $lines += "$i`t$(Esc-Xml $parsed.name)"
+ $lines += (Build-MLTextXml -tag "dcsset:presentation" -text $parsed.presentation -indent "$i`t")
+ $lines += "$i`t"
+ $lines += "$i`t`t"
+ $lines += "$i`t`t`t"
+ $lines += "$i`t`t"
+ $lines += "$i`t`t"
+ $lines += "$i`t`t`t"
+ $lines += "$i`t`t`t"
+ $lines += "$i`t`t`t`t"
+ $lines += "$i`t`t`t"
+ $lines += "$i`t`t`t"
+ $lines += "$i`t`t`t`t"
+ $lines += "$i`t`t`t"
+ $lines += "$i`t`t"
+ $lines += "$i`t"
+ $lines += "$i"
+ return $lines -join "`r`n"
+}
+
+function Build-ConditionalAppearanceItemFragment {
+ param($parsed, [string]$indent)
+
+ $i = $indent
+ $lines = @()
+ $lines += "$i"
+
+ # selection
+ if ($parsed.fields -and $parsed.fields.Count -gt 0) {
+ $lines += "$i`t"
+ foreach ($fld in $parsed.fields) {
+ $lines += "$i`t`t"
+ $lines += "$i`t`t`t$(Esc-Xml $fld)"
+ $lines += "$i`t`t"
+ }
+ $lines += "$i`t"
+ } else {
+ $lines += "$i`t"
+ }
+
+ # filter
+ if ($parsed.filter) {
+ $lines += "$i`t"
+ $f = $parsed.filter
+ $lines += "$i`t`t"
+ $lines += "$i`t`t`t$(Esc-Xml $f.field)"
+ $lines += "$i`t`t`t$(Esc-Xml $f.op)"
+ if ($null -ne $f.value) {
+ $vt = if ($f["valueType"]) { $f["valueType"] } else { "xs:string" }
+ $lines += "$i`t`t`t$(Esc-Xml "$($f.value)")"
+ }
+ $lines += "$i`t`t"
+ $lines += "$i`t"
+ } else {
+ $lines += "$i`t"
+ }
+
+ # appearance
+ $lines += "$i`t"
+
+ # Auto-detect value type
+ $val = $parsed.value
+ $valType = "xs:string"
+ if ($val -match '^(web|style|win):') {
+ $valType = "v8ui:Color"
+ } elseif ($val -eq "true" -or $val -eq "false") {
+ $valType = "xs:boolean"
+ }
+
+ $lines += "$i`t`t"
+ $lines += "$i`t`t`t$(Esc-Xml $parsed.param)"
+ $lines += "$i`t`t`t$(Esc-Xml $val)"
+ $lines += "$i`t`t"
+ $lines += "$i`t"
+
+ $lines += "$i"
+ return $lines -join "`r`n"
+}
+
function Build-StructureItemFragment {
param($item, [string]$indent)
@@ -1249,7 +1420,7 @@ $corNs = "http://v8.1c.ru/8.1/data-composition-system/core"
# --- 7. Batch value splitting ---
-if ($Operation -eq "set-query" -or $Operation -eq "set-structure") {
+if ($Operation -eq "set-query" -or $Operation -eq "set-structure" -or $Operation -eq "add-dataSet") {
$values = @($Value)
} else {
$values = @($Value -split ';;' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
@@ -1637,6 +1808,126 @@ switch ($Operation) {
}
}
+ "add-dataSet" {
+ $root = $xmlDoc.DocumentElement
+ $childIndent = Get-ChildIndent $root
+
+ $parsed = Parse-DataSetShorthand $Value
+
+ # Auto-name if empty
+ if (-not $parsed.name) {
+ $count = 0
+ foreach ($ch in $root.ChildNodes) {
+ if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'dataSet' -and $ch.NamespaceURI -eq $schNs) { $count++ }
+ }
+ $parsed.name = "НаборДанных$($count + 1)"
+ }
+
+ # Duplicate check
+ $existing = Find-ElementByChildValue $root "dataSet" "name" $parsed.name $schNs
+ if ($existing) {
+ Write-Host "[WARN] DataSet `"$($parsed.name)`" already exists — skipped"
+ } else {
+ # Get dataSource name from first existing
+ $dsSourceEl = Find-FirstElement $root @("dataSource") $schNs
+ $dsSourceName = "ИсточникДанных1"
+ if ($dsSourceEl) {
+ $nameEl = Find-FirstElement $dsSourceEl @("name") $schNs
+ if ($nameEl) { $dsSourceName = $nameEl.InnerText.Trim() }
+ }
+ $parsed["dataSource"] = $dsSourceName
+
+ $fragXml = Build-DataSetQueryFragment -parsed $parsed -indent $childIndent
+ $nodes = Import-Fragment $xmlDoc $fragXml
+
+ # Insert after last , or after if none
+ $lastDS = Find-LastElement $root "dataSet" $schNs
+ if ($lastDS) {
+ $refNode = $lastDS.NextSibling
+ while ($refNode -and ($refNode.NodeType -eq 'Whitespace' -or $refNode.NodeType -eq 'SignificantWhitespace')) {
+ $refNode = $refNode.NextSibling
+ }
+ } else {
+ $refNode = Find-FirstElement $root @("dataSetLink","calculatedField","totalField","parameter","template","groupTemplate","settingsVariant") $schNs
+ }
+
+ foreach ($node in $nodes) {
+ Insert-BeforeElement $root $node $refNode $childIndent
+ }
+
+ Write-Host "[OK] DataSet `"$($parsed.name)`" added (dataSource=$dsSourceName)"
+ }
+ }
+
+ "add-variant" {
+ $root = $xmlDoc.DocumentElement
+ $childIndent = Get-ChildIndent $root
+
+ foreach ($val in $values) {
+ $parsed = Parse-VariantShorthand $val
+
+ # Duplicate check — search for settingsVariant with matching dcsset:name
+ $isDup = $false
+ foreach ($ch in $root.ChildNodes) {
+ if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'settingsVariant' -and $ch.NamespaceURI -eq $schNs) {
+ foreach ($gc in $ch.ChildNodes) {
+ if ($gc.NodeType -eq 'Element' -and $gc.LocalName -eq 'name' -and $gc.NamespaceURI -eq $setNs -and $gc.InnerText -eq $parsed.name) {
+ $isDup = $true; break
+ }
+ }
+ if ($isDup) { break }
+ }
+ }
+ if ($isDup) {
+ Write-Host "[WARN] Variant `"$($parsed.name)`" already exists — skipped"
+ continue
+ }
+
+ $fragXml = Build-VariantFragment -parsed $parsed -indent $childIndent
+ $nodes = Import-Fragment $xmlDoc $fragXml
+
+ # Insert after last
+ $lastSV = Find-LastElement $root "settingsVariant" $schNs
+ if ($lastSV) {
+ $refNode = $lastSV.NextSibling
+ while ($refNode -and ($refNode.NodeType -eq 'Whitespace' -or $refNode.NodeType -eq 'SignificantWhitespace')) {
+ $refNode = $refNode.NextSibling
+ }
+ } else {
+ $refNode = $null
+ }
+
+ foreach ($node in $nodes) {
+ Insert-BeforeElement $root $node $refNode $childIndent
+ }
+
+ Write-Host "[OK] Variant `"$($parsed.name)`" [`"$($parsed.presentation)`"] added"
+ }
+ }
+
+ "add-conditionalAppearance" {
+ $settings = Resolve-VariantSettings
+ $varName = Get-VariantName
+
+ foreach ($val in $values) {
+ $parsed = Parse-ConditionalAppearanceShorthand $val
+
+ $caEl = Ensure-SettingsChild $settings "conditionalAppearance" @("outputParameters","order","filter","selection")
+ $caIndent = Get-ContainerChildIndent $caEl
+
+ $fragXml = Build-ConditionalAppearanceItemFragment -parsed $parsed -indent $caIndent
+ $nodes = Import-Fragment $xmlDoc $fragXml
+ foreach ($node in $nodes) {
+ Insert-BeforeElement $caEl $node $null $caIndent
+ }
+
+ $desc = "$($parsed.param) = $($parsed.value)"
+ if ($parsed.filter) { $desc += " when $($parsed.filter.field) $($parsed.filter.op)" }
+ if ($parsed.fields -and $parsed.fields.Count -gt 0) { $desc += " for $($parsed.fields -join ', ')" }
+ Write-Host "[OK] ConditionalAppearance `"$desc`" added to variant `"$varName`""
+ }
+ }
+
"clear-selection" {
$settings = Resolve-VariantSettings
$varName = Get-VariantName