diff --git a/.claude/skills/skd-compile/scripts/skd-compile.ps1 b/.claude/skills/skd-compile/scripts/skd-compile.ps1
index a23ac423..bd1eb8b1 100644
--- a/.claude/skills/skd-compile/scripts/skd-compile.ps1
+++ b/.claude/skills/skd-compile/scripts/skd-compile.ps1
@@ -1367,6 +1367,22 @@ function Emit-Selection {
X "$indent`t`t$(Esc-Xml $item)"
X "$indent`t"
}
+ } elseif ($item.folder) {
+ X "$indent`t"
+ X "$indent`t`t"
+ X "$indent`t`t`t"
+ X "$indent`t`t`t`tru"
+ X "$indent`t`t`t`t$(Esc-Xml "$($item.folder)")"
+ X "$indent`t`t`t"
+ X "$indent`t`t"
+ foreach ($sub in $item.items) {
+ $subName = if ($sub -is [string]) { $sub } else { "$($sub.field)" }
+ X "$indent`t`t"
+ X "$indent`t`t`t$(Esc-Xml $subName)"
+ X "$indent`t`t"
+ }
+ X "$indent`t`tAuto"
+ X "$indent`t"
} else {
X "$indent`t"
X "$indent`t`t$(Esc-Xml "$($item.field)")"
diff --git a/.claude/skills/skd-compile/scripts/skd-compile.py b/.claude/skills/skd-compile/scripts/skd-compile.py
index cf7e3441..0fb0ebb4 100644
--- a/.claude/skills/skd-compile/scripts/skd-compile.py
+++ b/.claude/skills/skd-compile/scripts/skd-compile.py
@@ -1154,6 +1154,21 @@ def emit_selection(lines, items, indent, skip_auto=False):
lines.append(f'{indent}\t')
lines.append(f'{indent}\t\t{esc_xml(item)}')
lines.append(f'{indent}\t')
+ elif item.get('folder'):
+ lines.append(f'{indent}\t')
+ lines.append(f'{indent}\t\t')
+ lines.append(f'{indent}\t\t\t')
+ lines.append(f'{indent}\t\t\t\tru')
+ lines.append(f'{indent}\t\t\t\t{esc_xml(str(item["folder"]))}')
+ lines.append(f'{indent}\t\t\t')
+ lines.append(f'{indent}\t\t')
+ for sub in (item.get('items') or []):
+ sub_name = str(sub.get('field', sub)) if isinstance(sub, dict) else str(sub)
+ lines.append(f'{indent}\t\t')
+ lines.append(f'{indent}\t\t\t{esc_xml(sub_name)}')
+ lines.append(f'{indent}\t\t')
+ lines.append(f'{indent}\t\tAuto')
+ lines.append(f'{indent}\t')
else:
lines.append(f'{indent}\t')
lines.append(f'{indent}\t\t{esc_xml(str(item["field"]))}')
diff --git a/.claude/skills/skd-edit/scripts/skd-edit.ps1 b/.claude/skills/skd-edit/scripts/skd-edit.ps1
index abc9c1ca..0214e0ad 100644
--- a/.claude/skills/skd-edit/scripts/skd-edit.ps1
+++ b/.claude/skills/skd-edit/scripts/skd-edit.ps1
@@ -543,6 +543,11 @@ function Parse-StructureShorthand {
$seg = $segments[$i].Trim()
$group = @{ type = "group" }
+ if ($seg -match '@name=(.+)') {
+ $group["name"] = $Matches[1].Trim()
+ $seg = ($seg -replace '\s*@name=.+', '').Trim()
+ }
+
if ($seg -match '^(?i)(details|детали)$') {
$group["groupBy"] = @()
} else {
@@ -861,6 +866,32 @@ function Build-SelectionItemFragment {
$lines = @()
if ($fieldName -eq "Auto") {
$lines += "$i"
+ } elseif ($fieldName -match '^Folder\((.+)\)$') {
+ $inner = $Matches[1]
+ $colonIdx = $inner.IndexOf(':')
+ if ($colonIdx -gt 0) {
+ $title = $inner.Substring(0, $colonIdx).Trim()
+ $items = $inner.Substring($colonIdx + 1) -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }
+ } else {
+ $title = ""
+ $items = $inner -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }
+ }
+ $lines += "$i"
+ if ($title) {
+ $lines += "$i`t"
+ $lines += "$i`t`t"
+ $lines += "$i`t`t`tru"
+ $lines += "$i`t`t`t$(Esc-Xml $title)"
+ $lines += "$i`t`t"
+ $lines += "$i`t"
+ }
+ foreach ($item in $items) {
+ $lines += "$i`t"
+ $lines += "$i`t`t$(Esc-Xml $item)"
+ $lines += "$i`t"
+ }
+ $lines += "$i`tAuto"
+ $lines += "$i"
} else {
$lines += "$i"
$lines += "$i`t$(Esc-Xml $fieldName)"
@@ -1070,6 +1101,11 @@ function Build-StructureItemFragment {
$lines = @()
$lines += "$i"
+ # name
+ if ($item["name"]) {
+ $lines += "$i`t$(Esc-Xml $item["name"])"
+ }
+
# groupItems
$groupBy = $item["groupBy"]
if (-not $groupBy -or $groupBy.Count -eq 0) {
diff --git a/.claude/skills/skd-edit/scripts/skd-edit.py b/.claude/skills/skd-edit/scripts/skd-edit.py
index 27123fac..dfdb3a30 100644
--- a/.claude/skills/skd-edit/scripts/skd-edit.py
+++ b/.claude/skills/skd-edit/scripts/skd-edit.py
@@ -509,6 +509,11 @@ def parse_structure_shorthand(s):
seg = segments[i].strip()
group = {"type": "group"}
+ name_m = re.search(r'\s*@name=(.+)', seg)
+ if name_m:
+ group["name"] = name_m.group(1).strip()
+ seg = re.sub(r'\s*@name=.+', '', seg).strip()
+
if re.match(r'^(?i)(details|\u0434\u0435\u0442\u0430\u043b\u0438)$', seg):
group["groupBy"] = []
else:
@@ -767,6 +772,31 @@ def build_selection_item_fragment(field_name, indent):
i = indent
if field_name == "Auto":
return f'{i}'
+ m = re.match(r'^Folder\((.+)\)$', field_name)
+ if m:
+ inner = m.group(1)
+ colon_idx = inner.find(':')
+ if colon_idx > 0:
+ title = inner[:colon_idx].strip()
+ items = [x.strip() for x in inner[colon_idx + 1:].split(',') if x.strip()]
+ else:
+ title = ""
+ items = [x.strip() for x in inner.split(',') if x.strip()]
+ lines = [f'{i}']
+ if title:
+ lines.append(f"{i}\t")
+ lines.append(f"{i}\t\t")
+ lines.append(f"{i}\t\t\tru")
+ lines.append(f"{i}\t\t\t{esc_xml(title)}")
+ lines.append(f"{i}\t\t")
+ lines.append(f"{i}\t")
+ for item in items:
+ lines.append(f'{i}\t')
+ lines.append(f"{i}\t\t{esc_xml(item)}")
+ lines.append(f"{i}\t")
+ lines.append(f"{i}\tAuto")
+ lines.append(f"{i}")
+ return "\r\n".join(lines)
lines = [
f'{i}',
f"{i}\t{esc_xml(field_name)}",
@@ -944,6 +974,9 @@ def build_structure_item_fragment(item, indent):
i = indent
lines = [f'{i}']
+ if item.get("name"):
+ lines.append(f"{i}\t{esc_xml(item['name'])}")
+
group_by = item.get("groupBy", [])
if not group_by:
lines.append(f"{i}\t")