diff --git a/.claude/skills/cf-info/scripts/cf-info.py b/.claude/skills/cf-info/scripts/cf-info.py
index 396de073..836556a7 100644
--- a/.claude/skills/cf-info/scripts/cf-info.py
+++ b/.claude/skills/cf-info/scripts/cf-info.py
@@ -9,7 +9,7 @@ from collections import OrderedDict
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# --- Argument parsing ---
parser = argparse.ArgumentParser(description="Analyze 1C configuration structure", allow_abbrev=False)
diff --git a/.claude/skills/form-edit/scripts/form-edit.py b/.claude/skills/form-edit/scripts/form-edit.py
index 8d8da185..c96f8f8e 100644
--- a/.claude/skills/form-edit/scripts/form-edit.py
+++ b/.claude/skills/form-edit/scripts/form-edit.py
@@ -9,7 +9,7 @@ import sys
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# ── arg parsing ──────────────────────────────────────────────
diff --git a/.claude/skills/form-info/scripts/form-info.ps1 b/.claude/skills/form-info/scripts/form-info.ps1
index 68f97be5..c904db61 100644
--- a/.claude/skills/form-info/scripts/form-info.ps1
+++ b/.claude/skills/form-info/scripts/form-info.ps1
@@ -58,8 +58,8 @@ function Format-Type($typeNode) {
$typeSet = $typeNode.SelectSingleNode("v8:TypeSet", $ns)
if ($typeSet) {
$val = $typeSet.InnerText
- # Strip cfg: prefix for DefinedType, keep as-is
- if ($val -like "cfg:*") { $val = $val.Substring(4) }
+ # Strip cfg:/d5p1: prefix for DefinedType, keep as-is
+ $val = $val -replace '^(cfg|d\d+p\d+):', ''
return $val
}
@@ -101,7 +101,7 @@ function Format-Type($typeNode) {
}
}
"xs:binary" { $parts += "binary" }
- "cfg:*" { $parts += $raw.Substring(4) }
+ { $_ -like "cfg:*" -or $_ -match '^d\d+p\d+:' } { $parts += ($raw -replace '^(cfg|d\d+p\d+):', '') }
"v8:ValueTable" { $parts += "ValueTable" }
"v8:ValueTree" { $parts += "ValueTree" }
"v8:ValueListType" { $parts += "ValueList" }
diff --git a/.claude/skills/form-info/scripts/form-info.py b/.claude/skills/form-info/scripts/form-info.py
index 60790cad..667a53bc 100644
--- a/.claude/skills/form-info/scripts/form-info.py
+++ b/.claude/skills/form-info/scripts/form-info.py
@@ -102,8 +102,8 @@ def format_type(type_node):
parts.append("dateTime")
elif raw == "xs:binary":
parts.append("binary")
- elif raw.startswith("cfg:"):
- parts.append(raw[4:])
+ elif raw.startswith("cfg:") or re.match(r'^d\d+p\d+:', raw):
+ parts.append(re.sub(r'^(?:cfg|d\d+p\d+):', '', raw))
elif raw == "v8:ValueTable":
parts.append("ValueTable")
elif raw == "v8:ValueTree":
diff --git a/.claude/skills/meta-compile/SKILL.md b/.claude/skills/meta-compile/SKILL.md
index 5bf94833..9af0db6b 100644
--- a/.claude/skills/meta-compile/SKILL.md
+++ b/.claude/skills/meta-compile/SKILL.md
@@ -69,6 +69,8 @@ Constant (Константа), DefinedType (ОпределяемыйТип), Com
Русские синонимы типов: `Строка`, `Число`, `Булево`, `Дата`, `СправочникСсылка.Xxx`, `ДокументСсылка.Xxx`, `ПланСчетовСсылка.Xxx`.
+Составной тип (несколько допустимых типов через `+`): `"Значение: Строка + Число(15,2) + Дата + CatalogRef.Контрагенты"`.
+
Флаги: `req`, `index`, `indexAdditional`, `nonneg`, `master`, `mainFilter`, `denyIncomplete`, `useInTotals`.
## Примеры
diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1
index 09ebcf5e..85dbee1d 100644
--- a/.claude/skills/meta-compile/scripts/meta-compile.ps1
+++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1
@@ -198,6 +198,15 @@ function Emit-TypeContent {
param([string]$indent, [string]$typeStr)
if (-not $typeStr) { return }
+ # Composite type: "Type1 + Type2 + Type3"
+ if ($typeStr.Contains(' + ')) {
+ $parts = $typeStr -split '\s*\+\s*'
+ foreach ($part in $parts) {
+ Emit-TypeContent $indent $part.Trim()
+ }
+ return
+ }
+
$typeStr = Resolve-TypeStr $typeStr
# Boolean
@@ -254,9 +263,9 @@ function Emit-TypeContent {
return
}
- # Reference types: CatalogRef.XXX, DocumentRef.XXX, etc.
+ # Reference types — use local xmlns declaration for 1C compatibility
if ($typeStr -match '^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$') {
- X "$indentcfg:$typeStr"
+ X "$indentd5p1:$typeStr"
return
}
@@ -1237,7 +1246,7 @@ function Emit-DefinedTypeProperties {
foreach ($vt in $valueTypes) {
$resolved = Resolve-TypeStr "$vt"
if ($resolved -match '^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.') {
- X "$i`tcfg:$resolved"
+ X "$i`td5p1:$resolved"
} elseif ($resolved -eq "Boolean") {
X "$i`txs:boolean"
} elseif ($resolved -match '^String') {
@@ -1342,7 +1351,7 @@ function Emit-EventSubscriptionProperties {
X "$i"
foreach ($src in $sources) {
$resolved = Resolve-TypeStr "$src"
- X "$i`tcfg:$resolved"
+ X "$i`td5p1:$resolved"
}
X "$i"
} else {
diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py
index 46f8b3a1..b2c6e548 100644
--- a/.claude/skills/meta-compile/scripts/meta-compile.py
+++ b/.claude/skills/meta-compile/scripts/meta-compile.py
@@ -11,7 +11,7 @@ import uuid
import xml.etree.ElementTree as ET
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# ---------------------------------------------------------------------------
# Inline utilities
@@ -207,6 +207,12 @@ def resolve_type_str(type_str):
def emit_type_content(indent, type_str):
if not type_str:
return
+ # Composite type: "Type1 + Type2 + Type3"
+ if ' + ' in type_str:
+ parts = [p.strip() for p in type_str.split('+')]
+ for part in parts:
+ emit_type_content(indent, part)
+ return
type_str = resolve_type_str(type_str)
# Boolean
if type_str == 'Boolean':
@@ -254,10 +260,10 @@ def emit_type_content(indent, type_str):
dt_name = m.group(1)
X(f'{indent}cfg:DefinedType.{dt_name}')
return
- # Reference types
+ # Reference types — use local xmlns declaration for 1C compatibility
m = re.match(r'^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$', type_str)
if m:
- X(f'{indent}cfg:{type_str}')
+ X(f'{indent}d5p1:{type_str}')
return
# Fallback
X(f'{indent}{type_str}')
@@ -1066,7 +1072,7 @@ def emit_defined_type_properties(indent):
for vt in value_types:
resolved = resolve_type_str(str(vt))
if re.match(r'^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.', resolved):
- X(f'{i}\tcfg:{resolved}')
+ X(f'{i}\td5p1:{resolved}')
elif resolved == 'Boolean':
X(f'{i}\txs:boolean')
elif re.match(r'^String', resolved):
@@ -1155,7 +1161,7 @@ def emit_event_subscription_properties(indent):
X(f'{i}')
for src in sources:
resolved = resolve_type_str(str(src))
- X(f'{i}\tcfg:{resolved}')
+ X(f'{i}\td5p1:{resolved}')
X(f'{i}')
else:
X(f'{i}')
diff --git a/.claude/skills/meta-edit/SKILL.md b/.claude/skills/meta-edit/SKILL.md
index e414d770..db42a069 100644
--- a/.claude/skills/meta-edit/SKILL.md
+++ b/.claude/skills/meta-edit/SKILL.md
@@ -81,6 +81,9 @@ Batch через `;;` во всех операциях. Подробный си
# Добавить реквизиты
-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)"
diff --git a/.claude/skills/meta-edit/child-operations.md b/.claude/skills/meta-edit/child-operations.md
index 5fc7f553..dc9a2dc1 100644
--- a/.claude/skills/meta-edit/child-operations.md
+++ b/.claude/skills/meta-edit/child-operations.md
@@ -18,6 +18,20 @@
-Operation add-attribute -Value "Склад: CatalogRef.Склады >> after Организация"
```
+## Составные типы
+
+Для реквизитов с несколькими допустимыми типами — разделитель `+`:
+```powershell
+-Operation add-attribute -Value "Значение: Строка + Число(15,2) + Дата + CatalogRef.Контрагенты"
+-Operation add-attribute -Value "Значение: Строка + Число(15,2) | req"
+-Operation modify-ts-attribute -Value "Данные.Значение: type=Строка + Число(15,2) + Дата"
+```
+
+В JSON DSL — массив в `type`:
+```json
+{ "name": "Значение", "type": ["Строка", "Число(15,2)", "Дата", "CatalogRef.Контрагенты"] }
+```
+
## add-attribute / add-dimension / add-resource / add-column
```powershell
diff --git a/.claude/skills/meta-edit/json-dsl.md b/.claude/skills/meta-edit/json-dsl.md
index f585d13b..4e3a116d 100644
--- a/.claude/skills/meta-edit/json-dsl.md
+++ b/.claude/skills/meta-edit/json-dsl.md
@@ -120,6 +120,19 @@ powershell.exe -NoProfile -File .claude/skills/meta-edit/scripts/meta-edit.ps1 -
| commands | команды |
| properties | свойства |
+## Составные типы
+
+Для полей с несколькими допустимыми типами — массив в `type`:
+
+```json
+{ "name": "Значение", "type": ["Строка", "Число(15,2)", "Дата", "CatalogRef.Контрагенты"] }
+```
+
+В inline-формате — через `+`:
+```
+"Значение: Строка + Число(15,2) + Дата + CatalogRef.Контрагенты"
+```
+
## Синонимы типов
`Строка(200)`, `Число(15,2)`, `Булево`, `Дата`, `ДатаВремя`, `ХранилищеЗначения`, `СправочникСсылка.XXX`, `ДокументСсылка.XXX`, `ПеречислениеСсылка.XXX`, `ОпределяемыйТип.XXX`.
diff --git a/.claude/skills/meta-edit/scripts/meta-edit.ps1 b/.claude/skills/meta-edit/scripts/meta-edit.ps1
index 74046d46..89ca13e0 100644
--- a/.claude/skills/meta-edit/scripts/meta-edit.ps1
+++ b/.claude/skills/meta-edit/scripts/meta-edit.ps1
@@ -269,6 +269,17 @@ function Build-TypeContentXml {
param([string]$indent, [string]$typeStr)
if (-not $typeStr) { return "" }
+ # Composite type: "Type1 + Type2 + Type3"
+ if ($typeStr.Contains(' + ')) {
+ $parts = $typeStr -split '\s*\+\s*'
+ $sb = New-Object System.Text.StringBuilder
+ foreach ($part in $parts) {
+ $inner = Build-TypeContentXml $indent $part.Trim()
+ if ($inner) { $sb.AppendLine($inner) | Out-Null }
+ }
+ return $sb.ToString().TrimEnd("`r","`n")
+ }
+
$typeStr = Resolve-TypeStr $typeStr
$sb = New-Object System.Text.StringBuilder
@@ -342,9 +353,9 @@ function Build-TypeContentXml {
return $sb.ToString().TrimEnd("`r","`n")
}
- # Reference types
+ # Reference types — use local xmlns declaration for 1C compatibility
if ($typeStr -match '^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$') {
- $sb.AppendLine("$indentcfg:$typeStr") | Out-Null
+ $sb.AppendLine("$indentd5p1:$typeStr") | Out-Null
return $sb.ToString().TrimEnd("`r","`n")
}
@@ -624,7 +635,7 @@ function Parse-AttributeShorthand {
$name = "$($val.name)"
$result = @{
name = $name
- type = if ($val.type) { "$($val.type)" } else { "" }
+ type = if ($val.type -is [array]) { ($val.type | ForEach-Object { "$_" }) -join ' + ' } elseif ($val.type) { "$($val.type)" } else { "" }
synonym = if ($val.synonym) { "$($val.synonym)" } else { Split-CamelCase $name }
comment = if ($val.comment) { "$($val.comment)" } else { "" }
flags = @(if ($val.flags) { $val.flags } else { @() })
diff --git a/.claude/skills/meta-edit/scripts/meta-edit.py b/.claude/skills/meta-edit/scripts/meta-edit.py
index a80334ad..e593f6c7 100644
--- a/.claude/skills/meta-edit/scripts/meta-edit.py
+++ b/.claude/skills/meta-edit/scripts/meta-edit.py
@@ -188,6 +188,16 @@ def build_type_content_xml(indent, type_str):
if not type_str:
return ""
+ # Composite type: "Type1 + Type2 + Type3"
+ if " + " in type_str:
+ parts = [p.strip() for p in type_str.split("+")]
+ results = []
+ for part in parts:
+ inner = build_type_content_xml(indent, part)
+ if inner:
+ results.append(inner)
+ return "\r\n".join(results)
+
type_str = resolve_type_str(type_str)
lines = []
@@ -258,14 +268,14 @@ def build_type_content_xml(indent, type_str):
lines.append(f"{indent}cfg:DefinedType.{dt_name}")
return "\r\n".join(lines)
- # Reference types
+ # Reference types — use local xmlns declaration for 1C compatibility
m = re.match(
r"^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|"
r"ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$",
type_str,
)
if m:
- lines.append(f"{indent}cfg:{type_str}")
+ lines.append(f'{indent}d5p1:{type_str}')
return "\r\n".join(lines)
# Fallback
@@ -538,7 +548,7 @@ def parse_attribute_shorthand(val):
name = str(val.get("name", ""))
result = {
"name": name,
- "type": str(val.get("type", "")),
+ "type": " + ".join(str(t) for t in val["type"]) if isinstance(val.get("type"), list) else str(val.get("type", "")),
"synonym": str(val.get("synonym", "")) if val.get("synonym") else split_camel_case(name),
"comment": str(val.get("comment", "")),
"flags": list(val.get("flags", [])),
@@ -1961,6 +1971,13 @@ def save_xml(tree, path):
xml_bytes = etree.tostring(tree, xml_declaration=True, encoding="UTF-8")
# Fix encoding quotes: encoding='UTF-8' -> encoding="UTF-8"
xml_bytes = xml_bytes.replace(b"encoding='UTF-8'", b'encoding="UTF-8"')
+ # Fix d5p1 namespace declarations stripped by lxml (it treats them as unused
+ # because d5p1: appears only in text content, not in element/attribute names)
+ xml_bytes = re.sub(
+ b'(d5p1:)',
+ b'\\1 xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config"\\2',
+ xml_bytes
+ )
with open(path, "wb") as f:
f.write(b"\xef\xbb\xbf")
f.write(xml_bytes)
diff --git a/.claude/skills/meta-info/scripts/meta-info.ps1 b/.claude/skills/meta-info/scripts/meta-info.ps1
index b0d91f8b..ce17e7a5 100644
--- a/.claude/skills/meta-info/scripts/meta-info.ps1
+++ b/.claude/skills/meta-info/scripts/meta-info.ps1
@@ -223,6 +223,8 @@ function Format-SingleType([string]$raw, $parentNode) {
"v8:UUID" { return "УникальныйИдентификатор" }
"v8:Null" { return "Null" }
default {
+ # Normalize d5p1:/dNpN: -> cfg:
+ $raw = $raw -replace '^d\d+p\d+:', 'cfg:'
# cfg:CatalogRef.Xxx -> СправочникСсылка.Xxx
if ($raw -match '^cfg:(\w+)Ref\.(.+)$') {
$prefix = "$($Matches[1])Ref"
@@ -356,6 +358,7 @@ function Decline-Cols([int]$n) {
}
function Format-SourceType([string]$raw) {
+ $raw = $raw -replace '^d\d+p\d+:', 'cfg:'
if ($raw -match '^cfg:(\w+)\.(.+)$') {
$prefix = $Matches[1]; $name = $Matches[2]
if ($objectTypeMap.ContainsKey($prefix)) { return "$($objectTypeMap[$prefix]).$name" }
diff --git a/.claude/skills/meta-info/scripts/meta-info.py b/.claude/skills/meta-info/scripts/meta-info.py
index 09964ec2..0191144f 100644
--- a/.claude/skills/meta-info/scripts/meta-info.py
+++ b/.claude/skills/meta-info/scripts/meta-info.py
@@ -8,7 +8,7 @@ import sys
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# ── arg parsing ──────────────────────────────────────────────
@@ -282,6 +282,8 @@ def format_single_type(raw, parent_node):
return "УникальныйИдентификатор"
if raw == "v8:Null":
return "Null"
+ # Normalize d5p1:/dNpN: → cfg: (both map to same namespace)
+ raw = re.sub(r'^d\d+p\d+:', 'cfg:', raw)
# cfg:CatalogRef.Xxx -> СправочникСсылка.Xxx
m = re.match(r'^cfg:(\w+)Ref\.(.+)$', raw)
if m:
@@ -410,6 +412,7 @@ def decline_cols(n):
def format_source_type(raw):
+ raw = re.sub(r'^d\d+p\d+:', 'cfg:', raw)
m = re.match(r'^cfg:(\w+)\.(.+)$', raw)
if m:
prefix = m.group(1)
diff --git a/.claude/skills/meta-validate/scripts/meta-validate.py b/.claude/skills/meta-validate/scripts/meta-validate.py
index 1b078c25..14004de4 100644
--- a/.claude/skills/meta-validate/scripts/meta-validate.py
+++ b/.claude/skills/meta-validate/scripts/meta-validate.py
@@ -8,7 +8,7 @@ import sys
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# ── arg parsing ──────────────────────────────────────────────
diff --git a/.claude/skills/mxl-info/scripts/mxl-info.py b/.claude/skills/mxl-info/scripts/mxl-info.py
index 5aa28b57..607cfc2c 100644
--- a/.claude/skills/mxl-info/scripts/mxl-info.py
+++ b/.claude/skills/mxl-info/scripts/mxl-info.py
@@ -10,7 +10,7 @@ import sys
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# --- Argument parsing ---
parser = argparse.ArgumentParser(description="Analyze 1C spreadsheet (MXL) structure", allow_abbrev=False)
diff --git a/.claude/skills/role-info/scripts/role-info.py b/.claude/skills/role-info/scripts/role-info.py
index e6c84d3a..d66d887f 100644
--- a/.claude/skills/role-info/scripts/role-info.py
+++ b/.claude/skills/role-info/scripts/role-info.py
@@ -9,7 +9,7 @@ from collections import OrderedDict
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# --- Argument parsing ---
parser = argparse.ArgumentParser(description="Analyze 1C role rights", allow_abbrev=False)
diff --git a/.claude/skills/skd-edit/scripts/skd-edit.py b/.claude/skills/skd-edit/scripts/skd-edit.py
index d4c2da5b..85502ba7 100644
--- a/.claude/skills/skd-edit/scripts/skd-edit.py
+++ b/.claude/skills/skd-edit/scripts/skd-edit.py
@@ -9,7 +9,7 @@ import uuid
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# ── arg parsing ──────────────────────────────────────────────
diff --git a/.claude/skills/skd-validate/scripts/skd-validate.py b/.claude/skills/skd-validate/scripts/skd-validate.py
index b926f7eb..171d926b 100644
--- a/.claude/skills/skd-validate/scripts/skd-validate.py
+++ b/.claude/skills/skd-validate/scripts/skd-validate.py
@@ -7,7 +7,7 @@ import sys
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# ── arg parsing ──────────────────────────────────────────────
diff --git a/.claude/skills/subsystem-info/scripts/subsystem-info.py b/.claude/skills/subsystem-info/scripts/subsystem-info.py
index 9f886908..0388ebb2 100644
--- a/.claude/skills/subsystem-info/scripts/subsystem-info.py
+++ b/.claude/skills/subsystem-info/scripts/subsystem-info.py
@@ -10,7 +10,7 @@ from collections import OrderedDict
from lxml import etree
sys.stdout.reconfigure(encoding="utf-8")
- sys.stderr.reconfigure(encoding="utf-8")
+sys.stderr.reconfigure(encoding="utf-8")
# --- Argument parsing ---
parser = argparse.ArgumentParser(description="Analyze 1C subsystem structure", allow_abbrev=False)