improve(skills): auto-resolve ConfigPath, auto-register forms, handle LF line endings

- cfe-init, cfe-borrow SKILL.md: auto-resolve ConfigPath from .v8-project.json configSrc
- form-compile: auto-register <Form> in parent ChildObjects from OutputPath convention
- form-compile SKILL.md: document new workflow (form-add no longer required first)
- cfe-borrow: handle LF line endings in OuterXml split (-split "\r?\n")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-02-21 17:22:05 +03:00
parent 3565e1c97f
commit 6f32e18e37
5 changed files with 89 additions and 6 deletions
+8
View File
@@ -16,6 +16,14 @@ allowed-tools:
Расширение должно быть создано (`/cfe-init`) и содержать валидный `Configuration.xml`.
### Авто-определение ConfigPath
Если пользователь не указал `-ConfigPath` — попробуй определить автоматически:
1. Прочитай `.v8-project.json` из корня проекта
2. Разреши целевую базу (по имени, ветке или `default` — алгоритм из `/db-list`)
3. Если у базы есть поле `configSrc` — используй как `-ConfigPath`
4. Если `configSrc` нет — спроси у пользователя
## Параметры
| Параметр | Описание |
@@ -537,7 +537,7 @@ function Borrow-Form {
if ($autoCmdXml) {
# Reindent for BaseForm: first line gets 2 tabs, other lines get +1 tab
$acLines = $autoCmdXml -split "`r`n"
$acLines = $autoCmdXml -split "`r?`n"
for ($li = 0; $li -lt $acLines.Count; $li++) {
if ($li -eq 0) { $formXmlSb.Append("`t`t$($acLines[$li])") | Out-Null }
else { $formXmlSb.Append("`t$($acLines[$li])") | Out-Null }
@@ -545,7 +545,7 @@ function Borrow-Form {
}
}
$ciLines = $childItemsXml -split "`r`n"
$ciLines = $childItemsXml -split "`r?`n"
for ($li = 0; $li -lt $ciLines.Count; $li++) {
if ($li -eq 0) { $formXmlSb.Append("`t`t$($ciLines[$li])") | Out-Null }
else { $formXmlSb.Append("`t$($ciLines[$li])") | Out-Null }
+8 -4
View File
@@ -16,11 +16,15 @@ allowed-tools:
Если есть выгрузка базовой конфигурации, передай `-ConfigPath` — скрипт автоматически определит `CompatibilityMode` и UUID языка из базовой конфигурации.
Если `-ConfigPath` не задан, рекомендуется предварительно получить режим совместимости:
### Авто-определение ConfigPath
```
/cf-info <ConfigPath> -Mode brief
```
Если пользователь не указал `-ConfigPath` — попробуй определить автоматически:
1. Прочитай `.v8-project.json` из корня проекта
2. Разреши целевую базу (по имени, ветке или `default` — алгоритм из `/db-list`)
3. Если у базы есть поле `configSrc` — используй как `-ConfigPath`
4. Если `configSrc` нет — спроси у пользователя
Если `.v8-project.json` не найден и `-ConfigPath` не задан — расширение создастся с предупреждением (UUID языка = нули, CompatibilityMode по умолчанию).
## Параметры
+6
View File
@@ -395,6 +395,12 @@ powershell.exe -NoProfile -File .claude/skills/form-compile/scripts/form-compile
- **ID**: последовательная нумерация, AutoCommandBar = id="-1"
- **Unknown keys**: выводится предупреждение о нераспознанных ключах
## Workflow
1. **Компиляция**: `/form-compile` генерирует `Form.xml` и автоматически регистрирует `<Form>` в `ChildObjects` родительского объекта (если OutputPath следует конвенции `.../TypePlural/ObjectName/Forms/FormName/Ext/Form.xml`).
2. **Метаданные формы** (`ФормаСписка.xml`) и `Module.bsl` создаёт `/form-add`. Если `/form-add` ещё не вызывался — вызови после `/form-compile`. Он не перезаписывает существующий Form.xml.
3. **Проверка**: `/form-validate`, `/form-info`.
## Верификация
```
@@ -1137,6 +1137,71 @@ if (-not (Test-Path $outDir)) {
$enc = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($outPath, $xml.ToString(), $enc)
# --- 13b. Auto-register form in parent object XML ---
# Infer parent from OutputPath: .../TypePlural/ObjectName/Forms/FormName/Ext/Form.xml
$formXmlDir = [System.IO.Path]::GetDirectoryName($outPath)
$formNameDir = [System.IO.Path]::GetDirectoryName($formXmlDir)
$formsDir = [System.IO.Path]::GetDirectoryName($formNameDir)
$objectDir = [System.IO.Path]::GetDirectoryName($formsDir)
$typePluralDir = [System.IO.Path]::GetDirectoryName($objectDir)
$formName = [System.IO.Path]::GetFileName($formNameDir)
$objectName = [System.IO.Path]::GetFileName($objectDir)
$formsLeaf = [System.IO.Path]::GetFileName($formsDir)
if ($formsLeaf -eq 'Forms') {
$objectXmlPath = Join-Path $typePluralDir "$objectName.xml"
if (Test-Path $objectXmlPath) {
$objDoc = New-Object System.Xml.XmlDocument
$objDoc.PreserveWhitespace = $true
$objDoc.Load($objectXmlPath)
$nsMgr = New-Object System.Xml.XmlNamespaceManager($objDoc.NameTable)
$nsMgr.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses")
$childObjects = $objDoc.SelectSingleNode("//md:ChildObjects", $nsMgr)
if ($childObjects) {
$existing = $childObjects.SelectSingleNode("md:Form[text()='$formName']", $nsMgr)
if (-not $existing) {
$formElem = $objDoc.CreateElement("Form", "http://v8.1c.ru/8.3/MDClasses")
$formElem.InnerText = $formName
$insertBefore = $childObjects.SelectSingleNode("md:Template", $nsMgr)
if (-not $insertBefore) { $insertBefore = $childObjects.SelectSingleNode("md:TabularSection", $nsMgr) }
if ($insertBefore) {
$childObjects.InsertBefore($formElem, $insertBefore) | Out-Null
$ws = $objDoc.CreateWhitespace("`n`t`t`t")
$childObjects.InsertBefore($ws, $insertBefore) | Out-Null
} else {
$lastChild = $childObjects.LastChild
if ($lastChild -and $lastChild.NodeType -eq [System.Xml.XmlNodeType]::Whitespace) {
$childObjects.InsertBefore($objDoc.CreateWhitespace("`n`t`t`t"), $lastChild) | Out-Null
$childObjects.InsertBefore($formElem, $lastChild) | Out-Null
} else {
$childObjects.AppendChild($objDoc.CreateWhitespace("`n`t`t`t")) | Out-Null
$childObjects.AppendChild($formElem) | Out-Null
$childObjects.AppendChild($objDoc.CreateWhitespace("`n`t`t")) | Out-Null
}
}
$regEnc = New-Object System.Text.UTF8Encoding($true)
$regSettings = New-Object System.Xml.XmlWriterSettings
$regSettings.Encoding = $regEnc
$regSettings.Indent = $false
$regStream = New-Object System.IO.FileStream($objectXmlPath, [System.IO.FileMode]::Create)
$regWriter = [System.Xml.XmlWriter]::Create($regStream, $regSettings)
$objDoc.Save($regWriter)
$regWriter.Close()
$regStream.Close()
Write-Host " Registered: <Form>$formName</Form> in $objectName.xml"
}
}
}
}
# --- 14. Summary ---
$elCount = $script:nextId - 1