diff --git a/.claude/skills/xdto-edit/scripts/xdto-edit.ps1 b/.claude/skills/xdto-edit/scripts/xdto-edit.ps1 index fd42a646..a1438723 100644 --- a/.claude/skills/xdto-edit/scripts/xdto-edit.ps1 +++ b/.claude/skills/xdto-edit/scripts/xdto-edit.ps1 @@ -127,6 +127,27 @@ $decompileScript = Join-Path (Join-Path $PSScriptRoot "..\..\xdto-decompile") "s $compileScript = Join-Path (Join-Path $PSScriptRoot "..\..\xdto-compile") "scripts\xdto-compile.ps1" $validateScript = Join-Path (Join-Path $PSScriptRoot "..\..\xdto-validate") "scripts\xdto-validate.ps1" +# Исключение из автономности навыков, сделанное осознанно: конвертер XSD ↔ модель +# нельзя скопировать буквально (xdto-compile — скрипт со сквозным потоком, не библиотека), +# а вторая его реализация разошлась бы с первой. Обещание «правка не меняет ни байта +# в нетронутом» держится именно на том, что код тот же самый. +# Проверяем комплектность заранее, чтобы не падать на середине правки. +function Assert-SiblingsPresent([string]$operation) { + $needed = @{} + if (@("rename", "set-synonym", "set-comment") -notcontains $operation) { + $needed["xdto-decompile"] = $decompileScript + $needed["xdto-compile"] = $compileScript + } + $missing = @() + foreach ($k in $needed.Keys) { if (-not (Test-Path $needed[$k])) { $missing += $k } } + if ($missing.Count -gt 0) { + throw ("Навык неработоспособен: рядом нет " + ($missing -join ", ") + ".`n" + + "Операция `"$operation`" выполняется через них, поэтому обойтись без них нельзя.`n" + + "Навыки устанавливаются комплектом — скопируйте каталог .claude/skills целиком, " + + "а не отдельные подкаталоги.") + } +} + function Invoke-Sibling([string]$script, [string[]]$argList, [string]$what) { if (-not (Test-Path $script)) { throw "Не найден навык $what по пути: $script" } $out = & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $script @argList 2>&1 @@ -444,6 +465,8 @@ function Apply-ModelOperation($schema) { $metaOps = @("rename", "set-synonym", "set-comment") $touchesModel = ($metaOps -notcontains $Operation) +Assert-SiblingsPresent $Operation + Write-Host "Пакет: $pkgName" if ($Operation -eq "rename") { diff --git a/.claude/skills/xdto-edit/scripts/xdto-edit.py b/.claude/skills/xdto-edit/scripts/xdto-edit.py index 403dcfcf..0057ae03 100644 --- a/.claude/skills/xdto-edit/scripts/xdto-edit.py +++ b/.claude/skills/xdto-edit/scripts/xdto-edit.py @@ -153,6 +153,24 @@ COMPILE = os.path.join(SKILLS, "xdto-compile", "scripts", "xdto-compile.py") VALIDATE = os.path.join(SKILLS, "xdto-validate", "scripts", "xdto-validate.py") +# Исключение из автономности навыков, сделанное осознанно: конвертер XSD <-> модель +# нельзя скопировать буквально (xdto-compile — скрипт со сквозным потоком, не библиотека), +# а вторая его реализация разошлась бы с первой. Обещание «правка не меняет ни байта +# в нетронутом» держится именно на том, что код тот же самый. +# Проверяем комплектность заранее, чтобы не падать на середине правки. +def assert_siblings_present(operation): + needed = {} + if operation not in ("rename", "set-synonym", "set-comment"): + needed["xdto-decompile"] = DECOMPILE + needed["xdto-compile"] = COMPILE + missing = [k for k, v in needed.items() if not os.path.exists(v)] + if missing: + die("Навык неработоспособен: рядом нет " + ", ".join(missing) + ".\n" + + f'Операция "{operation}" выполняется через них, поэтому обойтись без них нельзя.\n' + + "Навыки устанавливаются комплектом — скопируйте каталог .claude/skills целиком, " + "а не отдельные подкаталоги.") + + def invoke_sibling(script, argv, what): if not os.path.exists(script): die(f"Не найден навык {what} по пути: {script}") @@ -433,6 +451,8 @@ def apply_model_operation(schema): # ── dispatch ───────────────────────────────────────────────── +assert_siblings_present(args.Operation) + print(f"Пакет: {pkg_name}") old_namespace = None