From fae22435d4005ea412d2f7deab7343c2ffb76841 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 2 Aug 2026 15:35:17 +0300 Subject: [PATCH] =?UTF-8?q?fix(cfe-borrow,form-*,interface-edit,meta-compi?= =?UTF-8?q?le,role-compile,subsystem-compile,template-add):=20=D0=B4=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=B0=20=D1=81=D1=80=D0=B5=D0=B7=D0=B0=20Configura?= =?UTF-8?q?tion.xml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detect-FormatVersion читает префикс Configuration.xml как ReadAllText(...).Substring(0, Min(2000, (Get-Item).Length)). Размер файла — в БАЙТАХ, Substring считает СИМВОЛЫ: на кириллице байт больше, и если файл короче 2000 символов, длина среза выходит за строку и навык падает исключением. Проявлялось на маленьких конфигурациях — например на фикстуре EPF внутри конфигурации на поддержке. Функция расходится копиями по навыкам, поэтому правка одинаковая в восьми: длина берётся по самой строке. В help-add так было изначально; в meta-compile рядом (Detect-CompatibilityMode) уже стоял верный вариант. py-порты иммунны: там f.read(2000) в текстовом режиме — читает символы и не бросает исключение. Зеркалить нечего, версии выровнены по обоим портам. Заодно tests/skills/verify-snapshots.mjs: outputPath кейса читался только из params, тогда как runner.mjs берёт его с верхнего уровня — из-за расхождения харнесс искал результат не там, где навык его написал, и это маскировало падение как «выход не создан». Проверка: 1С-сертификация mxl-compile 13/13 (кейс guard-allow-external падал с начала кампании), полная сюита 630/630 на PowerShell и 627+3 skipped на python. Co-Authored-By: Claude Opus 5 (1M context) --- .claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 | 7 +++++-- .claude/skills/cfe-borrow/scripts/cfe-borrow.py | 2 +- .claude/skills/form-add/scripts/form-add.ps1 | 7 +++++-- .claude/skills/form-add/scripts/form-add.py | 2 +- .claude/skills/form-compile/scripts/form-compile.ps1 | 7 +++++-- .claude/skills/form-compile/scripts/form-compile.py | 2 +- .claude/skills/interface-edit/scripts/interface-edit.ps1 | 7 +++++-- .claude/skills/interface-edit/scripts/interface-edit.py | 2 +- .claude/skills/meta-compile/scripts/meta-compile.ps1 | 7 +++++-- .claude/skills/meta-compile/scripts/meta-compile.py | 2 +- .claude/skills/role-compile/scripts/role-compile.ps1 | 7 +++++-- .claude/skills/role-compile/scripts/role-compile.py | 2 +- .../skills/subsystem-compile/scripts/subsystem-compile.ps1 | 7 +++++-- .../skills/subsystem-compile/scripts/subsystem-compile.py | 2 +- .claude/skills/template-add/scripts/add-template.ps1 | 7 +++++-- .claude/skills/template-add/scripts/add-template.py | 2 +- tests/skills/verify-snapshots.mjs | 7 +++++-- 17 files changed, 53 insertions(+), 26 deletions(-) diff --git a/.claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 b/.claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 index 88916f8a..e67f6d9a 100644 --- a/.claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 +++ b/.claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 @@ -1,4 +1,4 @@ -# cfe-borrow v1.9 — Borrow objects from configuration into extension (CFE) +# cfe-borrow v1.10 — Borrow objects from configuration into extension (CFE) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)][string]$ExtensionPath, @@ -348,7 +348,10 @@ function Detect-FormatVersion([string]$dir) { while ($d) { $cfgPath = Join-Path $d "Configuration.xml" if (Test-Path $cfgPath) { - $head = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8).Substring(0, [Math]::Min(2000, (Get-Item $cfgPath).Length)) + $cfgText = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8) + # Длину среза берём по СТРОКЕ, а не по размеру файла: размер в БАЙТАХ, Substring считает + # СИМВОЛЫ, и на кириллице байт больше — короткий Configuration.xml ронял навык исключением. + $head = $cfgText.Substring(0, [Math]::Min(2000, $cfgText.Length)) if ($head -match ']+version="(\d+\.\d+)"') { return $Matches[1] } } $parent = Split-Path $d -Parent diff --git a/.claude/skills/cfe-borrow/scripts/cfe-borrow.py b/.claude/skills/cfe-borrow/scripts/cfe-borrow.py index 66511670..6628d91d 100644 --- a/.claude/skills/cfe-borrow/scripts/cfe-borrow.py +++ b/.claude/skills/cfe-borrow/scripts/cfe-borrow.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# cfe-borrow v1.9 — Borrow objects from configuration into extension (CFE) +# cfe-borrow v1.10 — Borrow objects from configuration into extension (CFE) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse diff --git a/.claude/skills/form-add/scripts/form-add.ps1 b/.claude/skills/form-add/scripts/form-add.ps1 index c05a579c..8200e1cc 100644 --- a/.claude/skills/form-add/scripts/form-add.ps1 +++ b/.claude/skills/form-add/scripts/form-add.ps1 @@ -1,4 +1,4 @@ -# form-add v1.11 — Add managed form to 1C config object +# form-add v1.12 — Add managed form to 1C config object # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -156,7 +156,10 @@ function Detect-FormatVersion([string]$dir) { while ($d) { $cfgPath = Join-Path $d "Configuration.xml" if (Test-Path $cfgPath) { - $head = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8).Substring(0, [Math]::Min(2000, (Get-Item $cfgPath).Length)) + $cfgText = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8) + # Длину среза берём по СТРОКЕ, а не по размеру файла: размер в БАЙТАХ, Substring считает + # СИМВОЛЫ, и на кириллице байт больше — короткий Configuration.xml ронял навык исключением. + $head = $cfgText.Substring(0, [Math]::Min(2000, $cfgText.Length)) if ($head -match ']+version="(\d+\.\d+)"') { return $Matches[1] } } $parent = Split-Path $d -Parent diff --git a/.claude/skills/form-add/scripts/form-add.py b/.claude/skills/form-add/scripts/form-add.py index 872d52e8..bb6ad167 100644 --- a/.claude/skills/form-add/scripts/form-add.py +++ b/.claude/skills/form-add/scripts/form-add.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# form-add v1.11 — Add managed form to 1C config object +# form-add v1.12 — Add managed form to 1C config object # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index 199943c2..77f2560a 100644 --- a/.claude/skills/form-compile/scripts/form-compile.ps1 +++ b/.claude/skills/form-compile/scripts/form-compile.ps1 @@ -1,4 +1,4 @@ -# form-compile v1.175 — Compile 1C managed form from JSON or object metadata +# form-compile v1.176 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -1337,7 +1337,10 @@ function Detect-FormatVersion([string]$dir) { while ($d) { $cfgPath = Join-Path $d "Configuration.xml" if (Test-Path $cfgPath) { - $head = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8).Substring(0, [Math]::Min(2000, (Get-Item $cfgPath).Length)) + $cfgText = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8) + # Длину среза берём по СТРОКЕ, а не по размеру файла: размер в БАЙТАХ, Substring считает + # СИМВОЛЫ, и на кириллице байт больше — короткий Configuration.xml ронял навык исключением. + $head = $cfgText.Substring(0, [Math]::Min(2000, $cfgText.Length)) if ($head -match ']+version="(\d+\.\d+)"') { return $Matches[1] } } $parent = Split-Path $d -Parent diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index 6f4cbd9d..0702aabc 100644 --- a/.claude/skills/form-compile/scripts/form-compile.py +++ b/.claude/skills/form-compile/scripts/form-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# form-compile v1.175 — Compile 1C managed form from JSON or object metadata +# form-compile v1.176 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy diff --git a/.claude/skills/interface-edit/scripts/interface-edit.ps1 b/.claude/skills/interface-edit/scripts/interface-edit.ps1 index b542a738..d40a66a8 100644 --- a/.claude/skills/interface-edit/scripts/interface-edit.ps1 +++ b/.claude/skills/interface-edit/scripts/interface-edit.ps1 @@ -1,4 +1,4 @@ -# interface-edit v1.8 — Edit 1C CommandInterface.xml +# interface-edit v1.9 — Edit 1C CommandInterface.xml # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)][Alias('Path')][string]$CIPath, @@ -164,7 +164,10 @@ function Detect-FormatVersion([string]$dir) { while ($d) { $cfgPath = Join-Path $d "Configuration.xml" if (Test-Path $cfgPath) { - $head = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8).Substring(0, [Math]::Min(2000, (Get-Item $cfgPath).Length)) + $cfgText = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8) + # Длину среза берём по СТРОКЕ, а не по размеру файла: размер в БАЙТАХ, Substring считает + # СИМВОЛЫ, и на кириллице байт больше — короткий Configuration.xml ронял навык исключением. + $head = $cfgText.Substring(0, [Math]::Min(2000, $cfgText.Length)) if ($head -match ']+version="(\d+\.\d+)"') { return $Matches[1] } } $parent = Split-Path $d -Parent diff --git a/.claude/skills/interface-edit/scripts/interface-edit.py b/.claude/skills/interface-edit/scripts/interface-edit.py index 8a5ab8a6..85a3dfd0 100644 --- a/.claude/skills/interface-edit/scripts/interface-edit.py +++ b/.claude/skills/interface-edit/scripts/interface-edit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# interface-edit v1.8 — Edit 1C CommandInterface.xml +# interface-edit v1.9 — Edit 1C CommandInterface.xml # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index 517788a8..56267e62 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -1,4 +1,4 @@ -# meta-compile v1.75 — Compile 1C metadata object from JSON +# meta-compile v1.76 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -4084,7 +4084,10 @@ function Detect-FormatVersion([string]$dir) { while ($d) { $cfgPath = Join-Path $d "Configuration.xml" if (Test-Path $cfgPath) { - $head = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8).Substring(0, [Math]::Min(2000, (Get-Item $cfgPath).Length)) + $cfgText = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8) + # Длину среза берём по СТРОКЕ, а не по размеру файла: размер в БАЙТАХ, Substring считает + # СИМВОЛЫ, и на кириллице байт больше — короткий Configuration.xml ронял навык исключением. + $head = $cfgText.Substring(0, [Math]::Min(2000, $cfgText.Length)) if ($head -match ']+version="(\d+\.\d+)"') { return $Matches[1] } } $parent = Split-Path $d -Parent diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 12129632..fb0242ac 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# meta-compile v1.75 — Compile 1C metadata object from JSON +# meta-compile v1.76 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse diff --git a/.claude/skills/role-compile/scripts/role-compile.ps1 b/.claude/skills/role-compile/scripts/role-compile.ps1 index 4e17d92f..fd6bc394 100644 --- a/.claude/skills/role-compile/scripts/role-compile.ps1 +++ b/.claude/skills/role-compile/scripts/role-compile.ps1 @@ -1,4 +1,4 @@ -# role-compile v1.9 — Compile 1C role from JSON +# role-compile v1.10 — Compile 1C role from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -646,7 +646,10 @@ function Detect-FormatVersion([string]$dir) { while ($d) { $cfgPath = Join-Path $d "Configuration.xml" if (Test-Path $cfgPath) { - $head = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8).Substring(0, [Math]::Min(2000, (Get-Item $cfgPath).Length)) + $cfgText = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8) + # Длину среза берём по СТРОКЕ, а не по размеру файла: размер в БАЙТАХ, Substring считает + # СИМВОЛЫ, и на кириллице байт больше — короткий Configuration.xml ронял навык исключением. + $head = $cfgText.Substring(0, [Math]::Min(2000, $cfgText.Length)) if ($head -match ']+version="(\d+\.\d+)"') { return $Matches[1] } } $parent = Split-Path $d -Parent diff --git a/.claude/skills/role-compile/scripts/role-compile.py b/.claude/skills/role-compile/scripts/role-compile.py index 0181c0b1..34bb98ee 100644 --- a/.claude/skills/role-compile/scripts/role-compile.py +++ b/.claude/skills/role-compile/scripts/role-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# role-compile v1.9 — Compile 1C role from JSON +# role-compile v1.10 — Compile 1C role from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json diff --git a/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 b/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 index 04c0b6c4..d9abf8da 100644 --- a/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 +++ b/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 @@ -1,4 +1,4 @@ -# subsystem-compile v1.10 — Create 1C subsystem from JSON definition +# subsystem-compile v1.11 — Create 1C subsystem from JSON definition # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$DefinitionFile, @@ -432,7 +432,10 @@ function Detect-FormatVersion([string]$dir) { while ($d) { $cfgPath = Join-Path $d "Configuration.xml" if (Test-Path $cfgPath) { - $head = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8).Substring(0, [Math]::Min(2000, (Get-Item $cfgPath).Length)) + $cfgText = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8) + # Длину среза берём по СТРОКЕ, а не по размеру файла: размер в БАЙТАХ, Substring считает + # СИМВОЛЫ, и на кириллице байт больше — короткий Configuration.xml ронял навык исключением. + $head = $cfgText.Substring(0, [Math]::Min(2000, $cfgText.Length)) if ($head -match ']+version="(\d+\.\d+)"') { return $Matches[1] } } $parent = Split-Path $d -Parent diff --git a/.claude/skills/subsystem-compile/scripts/subsystem-compile.py b/.claude/skills/subsystem-compile/scripts/subsystem-compile.py index 4ccf9c93..f640501e 100644 --- a/.claude/skills/subsystem-compile/scripts/subsystem-compile.py +++ b/.claude/skills/subsystem-compile/scripts/subsystem-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# subsystem-compile v1.10 — Create 1C subsystem from JSON definition +# subsystem-compile v1.11 — Create 1C subsystem from JSON definition # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json diff --git a/.claude/skills/template-add/scripts/add-template.ps1 b/.claude/skills/template-add/scripts/add-template.ps1 index acd7a4c7..8997860c 100644 --- a/.claude/skills/template-add/scripts/add-template.ps1 +++ b/.claude/skills/template-add/scripts/add-template.ps1 @@ -1,4 +1,4 @@ -# template-add v1.10 — Add template to 1C object +# template-add v1.11 — Add template to 1C object # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -222,7 +222,10 @@ function Detect-FormatVersion([string]$dir) { while ($d) { $cfgPath = Join-Path $d "Configuration.xml" if (Test-Path $cfgPath) { - $head = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8).Substring(0, [Math]::Min(2000, (Get-Item $cfgPath).Length)) + $cfgText = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8) + # Длину среза берём по СТРОКЕ, а не по размеру файла: размер в БАЙТАХ, Substring считает + # СИМВОЛЫ, и на кириллице байт больше — короткий Configuration.xml ронял навык исключением. + $head = $cfgText.Substring(0, [Math]::Min(2000, $cfgText.Length)) if ($head -match ']+version="(\d+\.\d+)"') { return $Matches[1] } } $parent = Split-Path $d -Parent diff --git a/.claude/skills/template-add/scripts/add-template.py b/.claude/skills/template-add/scripts/add-template.py index 410065bd..849778d4 100644 --- a/.claude/skills/template-add/scripts/add-template.py +++ b/.claude/skills/template-add/scripts/add-template.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# add-template v1.10 — Add template to 1C object +# add-template v1.11 — Add template to 1C object # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse diff --git a/tests/skills/verify-snapshots.mjs b/tests/skills/verify-snapshots.mjs index 21f86602..0255b6b8 100644 --- a/tests/skills/verify-snapshots.mjs +++ b/tests/skills/verify-snapshots.mjs @@ -907,7 +907,9 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) { log('platform-load', true, 'skipped (no v8 context)'); return result; } - const tplName = caseData.params?.templatePath || caseData.params?.outputPath || 'Template.xml'; + // outputPath у кейса бывает на ВЕРХНЕМ уровне (так его читает runner.mjs) и в params. + // Порядок должен совпадать с раннером, иначе файл ищется не там, где навык его написал. + const tplName = caseData.params?.templatePath || caseData.outputPath || caseData.params?.outputPath || 'Template.xml'; const tplPath = join(workDir, tplName); if (!existsSync(tplPath)) { result.errors.push(`Output not produced at ${tplPath}`); @@ -944,7 +946,8 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) { } if (MXL_PLATFORM_VERIFY.has(skillName)) { - const tplName = caseData.params?.outputPath || 'Template.xml'; + // См. выше: top-level outputPath имеет приоритет — так же, как в runner.mjs. + const tplName = caseData.outputPath || caseData.params?.outputPath || 'Template.xml'; const tplPath = join(workDir, tplName); if (!existsSync(tplPath)) { result.errors.push(`Output not produced at ${tplPath}`);