diff --git a/.claude/skills/web-info/SKILL.md b/.claude/skills/web-info/SKILL.md
new file mode 100644
index 00000000..51382845
--- /dev/null
+++ b/.claude/skills/web-info/SKILL.md
@@ -0,0 +1,62 @@
+---
+name: web-info
+description: Статус веб-публикации 1С — Apache, опубликованные базы, ошибки. Используй когда пользователь спрашивает про статус веб-сервера, опубликованные базы, работает ли Apache
+argument-hint: ""
+allowed-tools:
+ - Bash
+ - Read
+ - Glob
+---
+
+# /web-info — Статус Apache и публикаций 1С
+
+Показывает состояние Apache HTTP Server, список опубликованных баз и последние ошибки.
+
+## Usage
+
+```
+/web-info
+```
+
+## Параметры подключения
+
+Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
+По умолчанию `tools/apache24` от корня проекта.
+
+## Команда
+
+```powershell
+powershell.exe -NoProfile -File .claude/skills/web-info/scripts/web-info.ps1 <параметры>
+```
+
+### Параметры скрипта
+
+| Параметр | Обязательный | Описание |
+|----------|:------------:|----------|
+| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
+
+## Формат вывода
+
+```
+=== Apache Web Server ===
+Status: Запущен (PID: 12345)
+Path: C:\...\tools\apache24
+Port: 8080
+Module: C:/Program Files/1cv8/8.3.24.1691/bin/wsap24.dll
+
+=== Опубликованные базы ===
+ mydb http://localhost:8080/mydb File="C:\Bases\MyDB";
+
+=== Последние ошибки ===
+(пусто)
+```
+
+## Примеры
+
+```powershell
+# Статус по умолчанию
+powershell.exe -NoProfile -File .claude/skills/web-info/scripts/web-info.ps1
+
+# Указать путь к Apache
+powershell.exe -NoProfile -File .claude/skills/web-info/scripts/web-info.ps1 -ApachePath "C:\tools\apache24"
+```
diff --git a/.claude/skills/web-info/scripts/web-info.ps1 b/.claude/skills/web-info/scripts/web-info.ps1
new file mode 100644
index 00000000..75f8efdb
--- /dev/null
+++ b/.claude/skills/web-info/scripts/web-info.ps1
@@ -0,0 +1,127 @@
+# web-info v1.0 — Apache & 1C publication status
+# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
+<#
+.SYNOPSIS
+ Статус Apache и публикаций 1С
+
+.DESCRIPTION
+ Показывает состояние Apache HTTP Server, список опубликованных баз
+ и последние ошибки из error.log.
+
+.PARAMETER ApachePath
+ Корень Apache (по умолчанию tools\apache24)
+
+.EXAMPLE
+ .\web-info.ps1
+
+.EXAMPLE
+ .\web-info.ps1 -ApachePath "C:\tools\apache24"
+#>
+
+[CmdletBinding()]
+param(
+ [Parameter(Mandatory=$false)]
+ [string]$ApachePath
+)
+
+$OutputEncoding = [System.Text.Encoding]::UTF8
+[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
+
+# --- Resolve ApachePath ---
+if (-not $ApachePath) {
+ $projectRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName
+ $ApachePath = Join-Path $projectRoot "tools\apache24"
+}
+
+# --- Check Apache installation ---
+$httpdExe = Join-Path (Join-Path $ApachePath "bin") "httpd.exe"
+
+Write-Host "=== Apache Web Server ===" -ForegroundColor Cyan
+
+if (-not (Test-Path $httpdExe)) {
+ Write-Host "Status: Не установлен" -ForegroundColor Red
+ Write-Host "Path: $ApachePath (не найден)"
+ Write-Host ""
+ Write-Host "Используйте /web-publish для установки Apache." -ForegroundColor Yellow
+ exit 0
+}
+
+# --- Check process ---
+$httpdProc = Get-Process httpd -ErrorAction SilentlyContinue
+if ($httpdProc) {
+ $pids = ($httpdProc | ForEach-Object { $_.Id }) -join ", "
+ Write-Host "Status: Запущен (PID: $pids)" -ForegroundColor Green
+} else {
+ Write-Host "Status: Остановлен" -ForegroundColor Yellow
+}
+
+Write-Host "Path: $ApachePath"
+
+# --- Parse httpd.conf ---
+$confFile = Join-Path (Join-Path $ApachePath "conf") "httpd.conf"
+if (-not (Test-Path $confFile)) {
+ Write-Host "Config: httpd.conf не найден" -ForegroundColor Red
+ exit 0
+}
+
+$confContent = [System.IO.File]::ReadAllText($confFile)
+
+# Extract port from global block
+$port = "—"
+if ($confContent -match '(?m)^Listen\s+(\d+)') {
+ $port = $Matches[1]
+}
+Write-Host "Port: $port"
+
+# Extract wsap24 path
+if ($confContent -match 'LoadModule\s+_1cws_module\s+"([^"]+)"') {
+ Write-Host "Module: $($Matches[1])"
+}
+
+# --- Publications ---
+Write-Host ""
+Write-Host "=== Опубликованные базы ===" -ForegroundColor Cyan
+
+$pubPattern = '# --- 1C Publication: (.+?) ---'
+$pubMatches = [regex]::Matches($confContent, $pubPattern)
+
+if ($pubMatches.Count -eq 0) {
+ Write-Host "(нет публикаций)" -ForegroundColor Yellow
+} else {
+ foreach ($match in $pubMatches) {
+ $appName = $match.Groups[1].Value
+
+ # Read default.vrd for this publication
+ $vrdPath = Join-Path (Join-Path (Join-Path $ApachePath "publish") $appName) "default.vrd"
+ $ibInfo = "—"
+ if (Test-Path $vrdPath) {
+ $vrdContent = [System.IO.File]::ReadAllText($vrdPath)
+ if ($vrdContent -match 'ib="([^"]*)"') {
+ $ibInfo = $Matches[1] -replace '"','"'
+ }
+ }
+
+ $url = "http://localhost:$port/$appName"
+ Write-Host " $appName" -ForegroundColor White -NoNewline
+ Write-Host " $url" -ForegroundColor Gray -NoNewline
+ Write-Host " $ibInfo" -ForegroundColor DarkGray
+ }
+}
+
+# --- Error log ---
+Write-Host ""
+Write-Host "=== Последние ошибки ===" -ForegroundColor Cyan
+
+$errorLog = Join-Path (Join-Path $ApachePath "logs") "error.log"
+if (Test-Path $errorLog) {
+ $lines = Get-Content $errorLog -Tail 5 -ErrorAction SilentlyContinue
+ if ($lines -and $lines.Count -gt 0) {
+ foreach ($line in $lines) {
+ Write-Host " $line" -ForegroundColor DarkGray
+ }
+ } else {
+ Write-Host "(пусто)" -ForegroundColor Green
+ }
+} else {
+ Write-Host "(нет файла)" -ForegroundColor Green
+}
diff --git a/.claude/skills/web-publish/SKILL.md b/.claude/skills/web-publish/SKILL.md
new file mode 100644
index 00000000..fac54379
--- /dev/null
+++ b/.claude/skills/web-publish/SKILL.md
@@ -0,0 +1,79 @@
+---
+name: web-publish
+description: Публикация информационной базы 1С через Apache. Используй когда пользователь просит опубликовать базу, настроить веб-доступ, веб-клиент, открыть в браузере
+argument-hint: "[database]"
+allowed-tools:
+ - Bash
+ - Read
+ - Glob
+ - AskUserQuestion
+---
+
+# /web-publish — Публикация 1С через Apache
+
+Генерирует `default.vrd`, настраивает `httpd.conf` и запускает Apache HTTP Server для веб-доступа к информационной базе. При необходимости скачивает portable Apache. Идемпотентный — повторный вызов обновляет конфигурацию.
+
+## Usage
+
+```
+/web-publish [database]
+/web-publish dev
+/web-publish dev --manual
+/web-publish dev --port 9090
+```
+
+## Параметры подключения
+
+Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу:
+1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
+2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
+3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
+4. Если ветка не совпала — используй `default`
+Если `v8path` не задан — автоопределение.
+Если в `.v8-project.json` задан `webPath` — используй как `-ApachePath`.
+Если файла нет — предложи `/db-list add`.
+
+## Команда
+
+```powershell
+powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 <параметры>
+```
+
+### Параметры скрипта
+
+| Параметр | Обязательный | Описание |
+|----------|:------------:|----------|
+| `-V8Path <путь>` | нет | Каталог bin платформы (для wsap24.dll) |
+| `-InfoBasePath <путь>` | * | Файловая база |
+| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
+| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
+| `-UserName <имя>` | нет | Имя пользователя |
+| `-Password <пароль>` | нет | Пароль |
+| `-AppName <имя>` | нет | Имя публикации (по умолчанию из имени каталога базы) |
+| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
+| `-Port <порт>` | нет | Порт (по умолчанию `8080`) |
+| `-Manual` | нет | Не скачивать — только проверить и дать инструкцию |
+
+> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
+
+## После выполнения
+
+1. Сообщи URL: `http://localhost:{Port}/{AppName}`
+2. Предложи открыть в браузере
+3. Если база не зарегистрирована — предложи `/db-list add`
+
+## Примеры
+
+```powershell
+# Файловая база
+powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
+
+# С явным именем публикации и портом
+powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 -InfoBasePath "C:\Bases\MyDB" -AppName "mydb" -Port 9090
+
+# Серверная база
+powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret"
+
+# Ручной режим (только инструкция)
+powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 -InfoBasePath "C:\Bases\MyDB" -Manual
+```
diff --git a/.claude/skills/web-publish/scripts/web-publish.ps1 b/.claude/skills/web-publish/scripts/web-publish.ps1
new file mode 100644
index 00000000..eac97545
--- /dev/null
+++ b/.claude/skills/web-publish/scripts/web-publish.ps1
@@ -0,0 +1,328 @@
+# web-publish v1.0 — Publish 1C infobase via Apache
+# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
+<#
+.SYNOPSIS
+ Публикация информационной базы 1С через Apache HTTP Server
+
+.DESCRIPTION
+ Генерирует default.vrd и настраивает httpd.conf для веб-доступа
+ к информационной базе 1С. При необходимости скачивает portable Apache.
+ Идемпотентный — повторный вызов обновляет конфигурацию.
+
+.PARAMETER V8Path
+ Путь к каталогу bin платформы (для wsap24.dll)
+
+.PARAMETER InfoBasePath
+ Путь к файловой информационной базе
+
+.PARAMETER InfoBaseServer
+ Сервер 1С (для серверной базы)
+
+.PARAMETER InfoBaseRef
+ Имя базы на сервере
+
+.PARAMETER UserName
+ Имя пользователя 1С
+
+.PARAMETER Password
+ Пароль пользователя
+
+.PARAMETER AppName
+ Имя публикации (по умолчанию из имени каталога базы)
+
+.PARAMETER ApachePath
+ Корень Apache (по умолчанию tools\apache24)
+
+.PARAMETER Port
+ Порт (по умолчанию 8080)
+
+.PARAMETER Manual
+ Не скачивать Apache — только проверить и дать инструкцию
+
+.EXAMPLE
+ .\web-publish.ps1 -InfoBasePath "C:\Bases\MyDB"
+
+.EXAMPLE
+ .\web-publish.ps1 -InfoBasePath "C:\Bases\MyDB" -AppName "mydb" -Port 9090
+
+.EXAMPLE
+ .\web-publish.ps1 -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -Manual
+#>
+
+[CmdletBinding()]
+param(
+ [Parameter(Mandatory=$false)]
+ [string]$V8Path,
+
+ [Parameter(Mandatory=$false)]
+ [string]$InfoBasePath,
+
+ [Parameter(Mandatory=$false)]
+ [string]$InfoBaseServer,
+
+ [Parameter(Mandatory=$false)]
+ [string]$InfoBaseRef,
+
+ [Parameter(Mandatory=$false)]
+ [string]$UserName,
+
+ [Parameter(Mandatory=$false)]
+ [string]$Password,
+
+ [Parameter(Mandatory=$false)]
+ [string]$AppName,
+
+ [Parameter(Mandatory=$false)]
+ [string]$ApachePath,
+
+ [Parameter(Mandatory=$false)]
+ [int]$Port = 8080,
+
+ [Parameter(Mandatory=$false)]
+ [switch]$Manual
+)
+
+# --- Encoding ---
+$OutputEncoding = [System.Text.Encoding]::UTF8
+[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
+
+# --- Resolve V8Path ---
+if (-not $V8Path) {
+ $found = Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" -ErrorAction SilentlyContinue | Sort-Object FullName -Descending | Select-Object -First 1
+ if ($found) {
+ $V8Path = Split-Path $found.FullName -Parent
+ } else {
+ Write-Host "Error: платформа 1С не найдена. Укажите -V8Path" -ForegroundColor Red
+ exit 1
+ }
+} elseif (Test-Path $V8Path -PathType Leaf) {
+ $V8Path = Split-Path $V8Path -Parent
+}
+
+# Validate wsap24.dll
+$wsapDll = Join-Path $V8Path "wsap24.dll"
+if (-not (Test-Path $wsapDll)) {
+ Write-Host "Error: wsap24.dll не найден в $V8Path" -ForegroundColor Red
+ exit 1
+}
+
+# --- Validate connection ---
+if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) {
+ Write-Host "Error: укажите -InfoBasePath или -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red
+ exit 1
+}
+
+# --- Resolve ApachePath ---
+if (-not $ApachePath) {
+ $projectRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName
+ $ApachePath = Join-Path $projectRoot "tools\apache24"
+}
+
+# --- Check / Install Apache ---
+$httpdExe = Join-Path (Join-Path $ApachePath "bin") "httpd.exe"
+
+if (-not (Test-Path $httpdExe)) {
+ if ($Manual) {
+ Write-Host "Apache не найден: $ApachePath" -ForegroundColor Yellow
+ Write-Host ""
+ Write-Host "Установите Apache вручную:" -ForegroundColor Cyan
+ Write-Host " 1. Скачайте Apache Lounge (x64 VS17) с https://www.apachelounge.com/download/"
+ Write-Host " 2. Распакуйте содержимое Apache24\ в: $ApachePath"
+ Write-Host " 3. Запустите скрипт повторно"
+ exit 1
+ }
+
+ Write-Host "Apache не найден. Скачиваю..." -ForegroundColor Cyan
+ $zipUrl = "https://www.apachelounge.com/download/VS17/binaries/httpd-2.4.62-240904-win64-VS17.zip"
+ $tmpZip = Join-Path $env:TEMP "apache24.zip"
+ $tmpDir = Join-Path $env:TEMP "apache24_extract"
+
+ try {
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+ Invoke-WebRequest -Uri $zipUrl -OutFile $tmpZip -UseBasicParsing
+ } catch {
+ Write-Host "Error: не удалось скачать Apache: $_" -ForegroundColor Red
+ Write-Host "Скачайте вручную: $zipUrl" -ForegroundColor Yellow
+ exit 1
+ }
+
+ Write-Host "Распаковка..."
+ if (Test-Path $tmpDir) { Remove-Item $tmpDir -Recurse -Force }
+ Expand-Archive -Path $tmpZip -DestinationPath $tmpDir -Force
+
+ # Move Apache24 contents up to ApachePath
+ $innerDir = Join-Path $tmpDir "Apache24"
+ if (-not (Test-Path $innerDir)) {
+ # Try to find Apache24 in nested folder
+ $innerDir = Get-ChildItem $tmpDir -Directory -Recurse -Filter "Apache24" | Select-Object -First 1
+ if ($innerDir) { $innerDir = $innerDir.FullName } else {
+ Write-Host "Error: каталог Apache24 не найден в архиве" -ForegroundColor Red
+ exit 1
+ }
+ }
+
+ if (-not (Test-Path $ApachePath)) {
+ New-Item -ItemType Directory -Path $ApachePath -Force | Out-Null
+ }
+ Copy-Item -Path (Join-Path $innerDir "*") -Destination $ApachePath -Recurse -Force
+
+ # Cleanup
+ Remove-Item $tmpZip -Force -ErrorAction SilentlyContinue
+ Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
+
+ # Patch ServerRoot in httpd.conf
+ $confFile = Join-Path (Join-Path $ApachePath "conf") "httpd.conf"
+ if (Test-Path $confFile) {
+ $apachePathFwd = $ApachePath -replace '\\','/'
+ $confContent = [System.IO.File]::ReadAllText($confFile)
+ $confContent = $confContent -replace '(?m)^Define SRVROOT .*$', "Define SRVROOT `"$apachePathFwd`""
+ [System.IO.File]::WriteAllText($confFile, $confContent)
+ Write-Host "ServerRoot обновлён: $apachePathFwd" -ForegroundColor Green
+ }
+
+ Write-Host "Apache установлен: $ApachePath" -ForegroundColor Green
+}
+
+# --- Derive AppName ---
+if (-not $AppName) {
+ if ($InfoBasePath) {
+ $AppName = (Split-Path $InfoBasePath -Leaf) -replace '[^\w]',''
+ } else {
+ $AppName = $InfoBaseRef -replace '[^\w]',''
+ }
+ $AppName = $AppName.ToLower()
+}
+$AppName = $AppName.ToLower()
+
+if (-not $AppName) {
+ Write-Host "Error: не удалось определить имя публикации. Укажите -AppName" -ForegroundColor Red
+ exit 1
+}
+
+Write-Host "Публикация: $AppName" -ForegroundColor Cyan
+
+# --- Create publish directory ---
+$publishDir = Join-Path (Join-Path $ApachePath "publish") $AppName
+if (-not (Test-Path $publishDir)) {
+ New-Item -ItemType Directory -Path $publishDir -Force | Out-Null
+}
+
+# --- Generate default.vrd ---
+$vrdPath = Join-Path $publishDir "default.vrd"
+
+$ibParts = @()
+if ($InfoBaseServer -and $InfoBaseRef) {
+ $ibParts += "Srvr="$InfoBaseServer""
+ $ibParts += "Ref="$InfoBaseRef""
+} else {
+ $ibParts += "File="$InfoBasePath""
+}
+if ($UserName) { $ibParts += "Usr="$UserName"" }
+if ($Password) { $ibParts += "Pwd="$Password"" }
+$ibString = ($ibParts -join ";") + ";"
+
+$vrdContent = @"
+
+
+
+"@
+
+$utf8Bom = New-Object System.Text.UTF8Encoding($true)
+[System.IO.File]::WriteAllText($vrdPath, $vrdContent, $utf8Bom)
+Write-Host "default.vrd: $vrdPath" -ForegroundColor Green
+
+# --- Update httpd.conf ---
+$confFile = Join-Path (Join-Path $ApachePath "conf") "httpd.conf"
+if (-not (Test-Path $confFile)) {
+ Write-Host "Error: httpd.conf не найден: $confFile" -ForegroundColor Red
+ exit 1
+}
+
+$confContent = [System.IO.File]::ReadAllText($confFile)
+$apachePathFwd = $ApachePath -replace '\\','/'
+$wsapDllFwd = $wsapDll -replace '\\','/'
+$publishDirFwd = $publishDir -replace '\\','/'
+$vrdPathFwd = $vrdPath -replace '\\','/'
+
+# --- Global block (Listen + LoadModule) ---
+$globalMarkerStart = "# --- 1C: global ---"
+$globalMarkerEnd = "# --- End: global ---"
+$globalBlock = @"
+$globalMarkerStart
+Listen $Port
+LoadModule _1cws_module "$wsapDllFwd"
+$globalMarkerEnd
+"@
+
+if ($confContent -match [regex]::Escape($globalMarkerStart)) {
+ # Replace existing global block
+ $pattern = [regex]::Escape($globalMarkerStart) + '[\s\S]*?' + [regex]::Escape($globalMarkerEnd)
+ $confContent = [regex]::Replace($confContent, $pattern, $globalBlock)
+} else {
+ # Append global block
+ $confContent = $confContent.TrimEnd() + "`n`n" + $globalBlock + "`n"
+}
+
+# --- Publication block ---
+$pubMarkerStart = "# --- 1C Publication: $AppName ---"
+$pubMarkerEnd = "# --- End: $AppName ---"
+$pubBlock = @"
+$pubMarkerStart
+Alias "/$AppName" "$publishDirFwd"
+
+ AllowOverride All
+ Require all granted
+ SetHandler 1c-application
+ ManagedApplicationDescriptor "$vrdPathFwd"
+
+$pubMarkerEnd
+"@
+
+if ($confContent -match [regex]::Escape($pubMarkerStart)) {
+ # Replace existing publication block
+ $pattern = [regex]::Escape($pubMarkerStart) + '[\s\S]*?' + [regex]::Escape($pubMarkerEnd)
+ $confContent = [regex]::Replace($confContent, $pattern, $pubBlock)
+} else {
+ # Append publication block
+ $confContent = $confContent.TrimEnd() + "`n`n" + $pubBlock + "`n"
+}
+
+[System.IO.File]::WriteAllText($confFile, $confContent)
+Write-Host "httpd.conf обновлён" -ForegroundColor Green
+
+# --- Start Apache if not running ---
+$httpdProc = Get-Process httpd -ErrorAction SilentlyContinue
+if ($httpdProc) {
+ Write-Host "Apache уже запущен (PID: $(($httpdProc | Select-Object -First 1).Id))" -ForegroundColor Yellow
+ Write-Host "Перезапуск для применения конфигурации..."
+ # Portable Apache: stop + start
+ $httpdProc | Stop-Process -Force -ErrorAction SilentlyContinue
+ Start-Sleep -Seconds 1
+}
+
+Write-Host "Запуск Apache..."
+Start-Process -FilePath $httpdExe -WorkingDirectory $ApachePath -WindowStyle Hidden
+
+Start-Sleep -Seconds 2
+
+$httpdCheck = Get-Process httpd -ErrorAction SilentlyContinue
+if ($httpdCheck) {
+ Write-Host "Apache запущен (PID: $(($httpdCheck | Select-Object -First 1).Id))" -ForegroundColor Green
+} else {
+ Write-Host "Apache не удалось запустить" -ForegroundColor Red
+ $errorLog = Join-Path (Join-Path $ApachePath "logs") "error.log"
+ if (Test-Path $errorLog) {
+ Write-Host "--- error.log (последние 10 строк) ---" -ForegroundColor Yellow
+ Get-Content $errorLog -Tail 10
+ }
+ exit 1
+}
+
+# --- Result ---
+Write-Host ""
+Write-Host "=== Публикация готова ===" -ForegroundColor Green
+Write-Host "URL: http://localhost:$Port/$AppName" -ForegroundColor Cyan
diff --git a/.claude/skills/web-stop/SKILL.md b/.claude/skills/web-stop/SKILL.md
new file mode 100644
index 00000000..69b0b8f0
--- /dev/null
+++ b/.claude/skills/web-stop/SKILL.md
@@ -0,0 +1,46 @@
+---
+name: web-stop
+description: Остановка Apache HTTP Server. Используй когда пользователь просит остановить веб-сервер, Apache, прекратить веб-публикацию
+argument-hint: ""
+allowed-tools:
+ - Bash
+ - Read
+ - Glob
+---
+
+# /web-stop — Остановка Apache
+
+Останавливает Apache HTTP Server. Публикации сохраняются — при следующем `/web-publish` сервер запустится снова.
+
+## Usage
+
+```
+/web-stop
+```
+
+## Параметры подключения
+
+Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
+По умолчанию `tools/apache24` от корня проекта.
+
+## Команда
+
+```powershell
+powershell.exe -NoProfile -File .claude/skills/web-stop/scripts/web-stop.ps1 <параметры>
+```
+
+### Параметры скрипта
+
+| Параметр | Обязательный | Описание |
+|----------|:------------:|----------|
+| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
+
+## Примеры
+
+```powershell
+# Остановить Apache
+powershell.exe -NoProfile -File .claude/skills/web-stop/scripts/web-stop.ps1
+
+# С указанием пути
+powershell.exe -NoProfile -File .claude/skills/web-stop/scripts/web-stop.ps1 -ApachePath "C:\tools\apache24"
+```
diff --git a/.claude/skills/web-stop/scripts/web-stop.ps1 b/.claude/skills/web-stop/scripts/web-stop.ps1
new file mode 100644
index 00000000..bf5aa66e
--- /dev/null
+++ b/.claude/skills/web-stop/scripts/web-stop.ps1
@@ -0,0 +1,75 @@
+# web-stop v1.0 — Stop Apache HTTP Server
+# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
+<#
+.SYNOPSIS
+ Остановка Apache HTTP Server
+
+.DESCRIPTION
+ Останавливает Apache HTTP Server. Сначала пытается graceful shutdown,
+ при неудаче — принудительная остановка.
+
+.PARAMETER ApachePath
+ Корень Apache (по умолчанию tools\apache24)
+
+.EXAMPLE
+ .\web-stop.ps1
+
+.EXAMPLE
+ .\web-stop.ps1 -ApachePath "C:\tools\apache24"
+#>
+
+[CmdletBinding()]
+param(
+ [Parameter(Mandatory=$false)]
+ [string]$ApachePath
+)
+
+$OutputEncoding = [System.Text.Encoding]::UTF8
+[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
+
+# --- Resolve ApachePath ---
+if (-not $ApachePath) {
+ $projectRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName
+ $ApachePath = Join-Path $projectRoot "tools\apache24"
+}
+
+# --- Check process ---
+$httpdProc = Get-Process httpd -ErrorAction SilentlyContinue
+if (-not $httpdProc) {
+ Write-Host "Apache не запущен" -ForegroundColor Yellow
+ exit 0
+}
+
+$pids = ($httpdProc | ForEach-Object { $_.Id }) -join ", "
+Write-Host "Останавливаю Apache (PID: $pids)..."
+
+# --- Stop processes ---
+$httpdProc | Stop-Process -Force -ErrorAction SilentlyContinue
+
+# --- Wait for shutdown ---
+$maxWait = 5
+$elapsed = 0
+while ($elapsed -lt $maxWait) {
+ Start-Sleep -Seconds 1
+ $elapsed++
+ $check = Get-Process httpd -ErrorAction SilentlyContinue
+ if (-not $check) {
+ Write-Host "Apache остановлен" -ForegroundColor Green
+ exit 0
+ }
+}
+
+# --- Fallback: force kill ---
+$remaining = Get-Process httpd -ErrorAction SilentlyContinue
+if ($remaining) {
+ Write-Host "Принудительная остановка..." -ForegroundColor Yellow
+ $remaining | Stop-Process -Force -ErrorAction SilentlyContinue
+ Start-Sleep -Seconds 1
+ $final = Get-Process httpd -ErrorAction SilentlyContinue
+ if ($final) {
+ Write-Host "Error: не удалось остановить Apache" -ForegroundColor Red
+ exit 1
+ }
+}
+
+Write-Host "Apache остановлен" -ForegroundColor Green
diff --git a/.claude/skills/web-unpublish/SKILL.md b/.claude/skills/web-unpublish/SKILL.md
new file mode 100644
index 00000000..677ad0fb
--- /dev/null
+++ b/.claude/skills/web-unpublish/SKILL.md
@@ -0,0 +1,51 @@
+---
+name: web-unpublish
+description: Удаление веб-публикации 1С. Используй когда пользователь просит убрать публикацию, удалить веб-доступ к базе
+argument-hint: ""
+allowed-tools:
+ - Bash
+ - Read
+ - Glob
+ - AskUserQuestion
+---
+
+# /web-unpublish — Удаление публикации 1С
+
+Удаляет публикацию из httpd.conf и каталог `publish/{appname}`. Если других публикаций не осталось — удаляет глобальный блок 1C и останавливает Apache.
+
+## Usage
+
+```
+/web-unpublish
+/web-unpublish bpdemo
+```
+
+## Параметры подключения
+
+Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
+По умолчанию `tools/apache24` от корня проекта.
+
+Если пользователь не указал `appname`, выполни `/web-info` чтобы показать список публикаций и спроси какую удалить.
+
+## Команда
+
+```powershell
+powershell.exe -NoProfile -File .claude/skills/web-unpublish/scripts/web-unpublish.ps1 <параметры>
+```
+
+### Параметры скрипта
+
+| Параметр | Обязательный | Описание |
+|----------|:------------:|----------|
+| `-AppName <имя>` | да | Имя публикации |
+| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
+
+## Примеры
+
+```powershell
+# Удалить публикацию
+powershell.exe -NoProfile -File .claude/skills/web-unpublish/scripts/web-unpublish.ps1 -AppName "bpdemo"
+
+# С указанием пути
+powershell.exe -NoProfile -File .claude/skills/web-unpublish/scripts/web-unpublish.ps1 -AppName "mydb" -ApachePath "C:\tools\apache24"
+```
diff --git a/.claude/skills/web-unpublish/scripts/web-unpublish.ps1 b/.claude/skills/web-unpublish/scripts/web-unpublish.ps1
new file mode 100644
index 00000000..c4265596
--- /dev/null
+++ b/.claude/skills/web-unpublish/scripts/web-unpublish.ps1
@@ -0,0 +1,109 @@
+# web-unpublish v1.0 — Remove 1C web publication
+# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
+<#
+.SYNOPSIS
+ Удаление публикации 1С из Apache
+
+.DESCRIPTION
+ Удаляет маркерный блок из httpd.conf и каталог публикации.
+ Если Apache запущен — перезапускает для применения.
+
+.PARAMETER AppName
+ Имя публикации (обязательный)
+
+.PARAMETER ApachePath
+ Корень Apache (по умолчанию tools\apache24)
+
+.EXAMPLE
+ .\web-unpublish.ps1 -AppName "mydb"
+
+.EXAMPLE
+ .\web-unpublish.ps1 -AppName "bpdemo" -ApachePath "C:\tools\apache24"
+#>
+
+[CmdletBinding()]
+param(
+ [Parameter(Mandatory=$true)]
+ [string]$AppName,
+
+ [Parameter(Mandatory=$false)]
+ [string]$ApachePath
+)
+
+$OutputEncoding = [System.Text.Encoding]::UTF8
+[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
+
+# --- Resolve ApachePath ---
+if (-not $ApachePath) {
+ $projectRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName
+ $ApachePath = Join-Path $projectRoot "tools\apache24"
+}
+
+# --- Remove marker block from httpd.conf ---
+$confFile = Join-Path (Join-Path $ApachePath "conf") "httpd.conf"
+if (-not (Test-Path $confFile)) {
+ Write-Host "Error: httpd.conf не найден: $confFile" -ForegroundColor Red
+ exit 1
+}
+
+$confContent = [System.IO.File]::ReadAllText($confFile)
+$pubMarkerStart = "# --- 1C Publication: $AppName ---"
+$pubMarkerEnd = "# --- End: $AppName ---"
+
+if ($confContent -match [regex]::Escape($pubMarkerStart)) {
+ $pattern = '\r?\n?' + [regex]::Escape($pubMarkerStart) + '[\s\S]*?' + [regex]::Escape($pubMarkerEnd) + '\r?\n?'
+ $confContent = [regex]::Replace($confContent, $pattern, "`n")
+ [System.IO.File]::WriteAllText($confFile, $confContent)
+ Write-Host "httpd.conf: блок публикации '$AppName' удалён" -ForegroundColor Green
+} else {
+ Write-Host "Публикация '$AppName' не найдена в httpd.conf" -ForegroundColor Yellow
+}
+
+# --- Check if any publications remain; if not, remove global block ---
+$remainingPubs = [regex]::Matches($confContent, '# --- 1C Publication: .+? ---')
+if ($remainingPubs.Count -eq 0) {
+ $globalMarkerStart = "# --- 1C: global ---"
+ $globalMarkerEnd = "# --- End: global ---"
+ if ($confContent -match [regex]::Escape($globalMarkerStart)) {
+ $globalPattern = '\r?\n?' + [regex]::Escape($globalMarkerStart) + '[\s\S]*?' + [regex]::Escape($globalMarkerEnd) + '\r?\n?'
+ $confContent = [regex]::Replace($confContent, $globalPattern, "`n")
+ [System.IO.File]::WriteAllText($confFile, $confContent)
+ Write-Host "httpd.conf: глобальный блок 1C удалён (нет публикаций)" -ForegroundColor Green
+ }
+}
+
+# --- Remove publish directory ---
+$publishDir = Join-Path (Join-Path $ApachePath "publish") $AppName
+if (Test-Path $publishDir) {
+ Remove-Item $publishDir -Recurse -Force
+ Write-Host "Каталог удалён: $publishDir" -ForegroundColor Green
+} else {
+ Write-Host "Каталог не найден: $publishDir" -ForegroundColor Yellow
+}
+
+# --- Restart Apache if running ---
+$httpdProc = Get-Process httpd -ErrorAction SilentlyContinue
+if ($httpdProc) {
+ Write-Host "Перезапуск Apache..."
+ $httpdExe = Join-Path (Join-Path $ApachePath "bin") "httpd.exe"
+ $httpdProc | Stop-Process -Force -ErrorAction SilentlyContinue
+ Start-Sleep -Seconds 1
+
+ # Only restart if there are remaining publications
+ if ($remainingPubs.Count -gt 0) {
+ Start-Process -FilePath $httpdExe -WorkingDirectory $ApachePath -WindowStyle Hidden
+ Start-Sleep -Seconds 2
+ $check = Get-Process httpd -ErrorAction SilentlyContinue
+ if ($check) {
+ Write-Host "Apache перезапущен" -ForegroundColor Green
+ } else {
+ Write-Host "Error: Apache не удалось перезапустить" -ForegroundColor Red
+ exit 1
+ }
+ } else {
+ Write-Host "Публикаций не осталось — Apache остановлен" -ForegroundColor Green
+ }
+}
+
+Write-Host ""
+Write-Host "Публикация '$AppName' удалена" -ForegroundColor Green
diff --git a/docs/web-guide.md b/docs/web-guide.md
new file mode 100644
index 00000000..26f47015
--- /dev/null
+++ b/docs/web-guide.md
@@ -0,0 +1,117 @@
+# Веб-публикация 1С
+
+Навыки группы `/web-*` позволяют публиковать информационные базы 1С через Apache HTTP Server для доступа из браузера (веб-клиент). Это замыкает цикл разработки: правка исходников → загрузка → обновление БД → **открытие в браузере**.
+
+## Навыки
+
+| Навык | Скрипт | Описание |
+|-------|:------:|----------|
+| `/web-publish` | `.ps1` | Публикация базы (VRD + httpd.conf + запуск Apache) |
+| `/web-info` | `.ps1` | Статус Apache и список публикаций |
+| `/web-stop` | `.ps1` | Остановка Apache |
+| `/web-unpublish` | `.ps1` | Удаление публикации |
+
+## Рабочий цикл
+
+```
+правки в исходниках → /db-load-xml → /db-update → /web-publish → браузер
+ ↑
+ /web-info ← статус |
+ /web-stop ← остановка|
+ /web-unpublish ← удаление
+```
+
+### Типичный цикл разработки
+
+1. **Настройка** — `/db-list add` зарегистрировать базу в `.v8-project.json`
+2. **Загрузка** — `/db-load-xml` загрузить конфигурацию
+3. **Обновление** — `/db-update` применить к БД
+4. **Публикация** — `/web-publish` опубликовать базу (при первом запуске скачает Apache)
+5. **Проверка** — открыть `http://localhost:8080/{appname}` в браузере
+6. **Правка** — изменить исходники
+7. **Синхронизация** — `/db-load-git` + `/db-update`
+8. **Проверка** — обновить страницу в браузере
+9. **Завершение** — `/web-stop` остановить Apache
+
+## Конфигурация `webPath` в `.v8-project.json`
+
+Поле `webPath` указывает путь к каталогу Apache. Если не задано, используется `tools/apache24` от корня проекта.
+
+```json
+{
+ "v8path": "C:\\Program Files\\1cv8\\8.3.24.1691\\bin",
+ "webPath": "C:\\tools\\apache24",
+ "databases": [
+ {
+ "id": "dev",
+ "name": "Разработка",
+ "type": "file",
+ "path": "C:\\Bases\\MyApp_Dev",
+ "user": "Admin"
+ }
+ ],
+ "default": "dev"
+}
+```
+
+> `webPath` — опционально. Если не задан, все навыки `/web-*` ищут Apache в `tools/apache24`.
+
+## Сценарии использования
+
+### Опубликовать базу
+
+```
+> Опубликуй базу bp-demo
+```
+
+Claude вызовет `/web-publish bp-demo` → скачает Apache (если нет) → сгенерирует VRD → настроит httpd.conf → запустит Apache → выдаст URL.
+
+### Проверить статус
+
+```
+> Что с веб-сервером?
+```
+
+Claude вызовет `/web-info` → покажет состояние Apache, порт, список публикаций, последние ошибки.
+
+### Опубликовать на другом порту
+
+```
+> Опубликуй ERP на порту 9090
+```
+
+Claude вызовет `/web-publish erp --port 9090`.
+
+### Остановить сервер
+
+```
+> Останови Apache
+```
+
+Claude вызовет `/web-stop`.
+
+### Удалить публикацию
+
+```
+> Убери публикацию bpdemo
+```
+
+Claude вызовет `/web-unpublish bpdemo` → удалит блок из httpd.conf → удалит каталог → перезапустит Apache (если есть другие публикации).
+
+## Ручная установка Apache
+
+Если автоматическая загрузка невозможна (прокси, firewall), используйте флаг `--manual`:
+
+```
+> Опубликуй базу --manual
+```
+
+Скрипт выдаст инструкцию:
+1. Скачайте Apache Lounge (x64 VS17) с https://www.apachelounge.com/download/
+2. Распакуйте содержимое `Apache24/` в `tools/apache24` (или путь из `webPath`)
+3. Запустите команду повторно
+
+## Спецификации
+
+- [web-spec.md](web-spec.md) — техническая спецификация (VRD, httpd.conf, wsap24.dll, portable Apache)
+- [build-spec.md](build-spec.md) — пакетный режим конфигуратора 1С
diff --git a/docs/web-spec.md b/docs/web-spec.md
new file mode 100644
index 00000000..16d327df
--- /dev/null
+++ b/docs/web-spec.md
@@ -0,0 +1,184 @@
+# Веб-публикация 1С — техническая спецификация
+
+Описание артефактов, необходимых для публикации информационной базы 1С через Apache HTTP Server.
+
+## default.vrd
+
+Дескриптор виртуального ресурса. XML-файл, описывающий подключение к информационной базе.
+
+### Формат
+
+```xml
+
+
+
+```
+
+### Атрибут `base`
+
+URL-путь публикации. Должен начинаться с `/`, совпадает с `Alias` в httpd.conf.
+
+### Атрибут `ib`
+
+Строка подключения к информационной базе.
+
+**Файловая база:**
+```
+File="C:\Bases\MyDB";
+```
+
+**Серверная база:**
+```
+Srvr="server01";Ref="MyDB";
+```
+
+**С авторизацией:**
+```
+File="C:\Bases\MyDB";Usr="Admin";Pwd="123";
+```
+
+> Кавычки внутри значения `ib` экранируются как `"` (XML-сущность).
+
+### Расположение
+
+`{ApachePath}/publish/{AppName}/default.vrd`
+
+## httpd.conf для 1С
+
+### LoadModule
+
+Apache загружает модуль расширения 1С:
+
+```apache
+LoadModule _1cws_module "C:/Program Files/1cv8/8.3.24.1691/bin/wsap24.dll"
+```
+
+- Модуль `wsap24.dll` — 64-разрядный, требует x64-версию Apache
+- Путь использует forward slashes
+
+### Listen
+
+```apache
+Listen 8080
+```
+
+Порт для веб-клиента. По умолчанию `8080` (стандартный `80` может быть занят).
+
+### Alias + Directory
+
+Для каждой публикации добавляется блок:
+
+```apache
+Alias "/appname" "C:/path/to/apache/publish/appname"
+
+ AllowOverride All
+ Require all granted
+ SetHandler 1c-application
+ ManagedApplicationDescriptor "C:/path/to/apache/publish/appname/default.vrd"
+
+```
+
+- `Alias` — URL-путь → физический каталог
+- `SetHandler 1c-application` — делегирование обработки запросов модулю wsap24
+- `ManagedApplicationDescriptor` — путь к default.vrd
+
+### Маркерный подход
+
+Скрипты используют маркерные комментарии для идемпотентного управления блоками:
+
+```apache
+# --- 1C: global ---
+Listen 8080
+LoadModule _1cws_module "C:/Program Files/1cv8/8.3.24.1691/bin/wsap24.dll"
+# --- End: global ---
+
+# --- 1C Publication: mydb ---
+Alias "/mydb" "C:/tools/apache24/publish/mydb"
+
+ AllowOverride All
+ Require all granted
+ SetHandler 1c-application
+ ManagedApplicationDescriptor "C:/tools/apache24/publish/mydb/default.vrd"
+
+# --- End: mydb ---
+```
+
+При повторном запуске блок между маркерами заменяется целиком.
+
+## wsap24.dll
+
+Модуль расширения Apache для 1С:Предприятие 8.3.
+
+- Расположение: `{V8Path}/wsap24.dll` (в каталоге `bin` платформы)
+- Архитектура: x64 (Apache тоже должен быть x64)
+- Имя модуля: `_1cws_module`
+
+## Portable Apache
+
+### Дистрибутив
+
+Apache Lounge — Windows-сборка Apache HTTP Server (x64):
+- Сайт: `https://www.apachelounge.com/download/`
+- Прямая ссылка (2.4.62, VS17): `https://www.apachelounge.com/download/VS17/binaries/httpd-2.4.62-240904-win64-VS17.zip`
+- Внутри ZIP: каталог `Apache24/` с полной структурой
+
+### Структура после установки
+
+```
+tools/apache24/
+├── bin/
+│ ├── httpd.exe
+│ └── ...
+├── conf/
+│ ├── httpd.conf
+│ └── ...
+├── logs/
+│ ├── error.log
+│ └── access.log
+├── modules/
+│ └── ...
+└── publish/
+ └── {appname}/
+ └── default.vrd
+```
+
+### Пост-распаковка
+
+1. `Expand-Archive` распаковывает ZIP во временный каталог
+2. Содержимое `Apache24/` перемещается в `{ApachePath}`
+3. В `httpd.conf` патчится `ServerRoot`:
+
+```apache
+Define SRVROOT "C:/path/to/apache24"
+ServerRoot "${SRVROOT}"
+```
+
+Путь `SRVROOT` — абсолютный, с forward slashes.
+
+### Запуск
+
+```
+httpd.exe # foreground (для отладки)
+httpd.exe -k start # фоновый запуск (не работает без установки сервиса)
+```
+
+> Portable Apache запускается напрямую через `Start-Process httpd.exe` без установки Windows-сервиса.
+
+### Остановка
+
+```
+httpd.exe -k stop # graceful shutdown (требует сервис)
+Stop-Process -Name httpd # принудительная остановка (portable)
+```
+
+### Перезагрузка
+
+```
+httpd.exe -k restart # graceful restart (требует сервис)
+```
+
+Для portable варианта: остановка + запуск.