feat(web): add web publishing skills (web-publish, web-info, web-stop, web-unpublish)

Phase 1 of web publishing: publish 1C infobases via portable Apache HTTP Server.
Closes the feedback loop: edit → load → update → open in browser.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-02-22 16:28:22 +03:00
parent bc9087957f
commit bc4778d6cc
10 changed files with 1178 additions and 0 deletions
+62
View File
@@ -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"
```
@@ -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 '&quot;','"'
}
}
$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
}
+79
View File
@@ -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
```
@@ -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=&quot;$InfoBaseServer&quot;"
$ibParts += "Ref=&quot;$InfoBaseRef&quot;"
} else {
$ibParts += "File=&quot;$InfoBasePath&quot;"
}
if ($UserName) { $ibParts += "Usr=&quot;$UserName&quot;" }
if ($Password) { $ibParts += "Pwd=&quot;$Password&quot;" }
$ibString = ($ibParts -join ";") + ";"
$vrdContent = @"
<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/$AppName"
ib="$ibString">
</point>
"@
$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"
<Directory "$publishDirFwd">
AllowOverride All
Require all granted
SetHandler 1c-application
ManagedApplicationDescriptor "$vrdPathFwd"
</Directory>
$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
+46
View File
@@ -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"
```
@@ -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
+51
View File
@@ -0,0 +1,51 @@
---
name: web-unpublish
description: Удаление веб-публикации 1С. Используй когда пользователь просит убрать публикацию, удалить веб-доступ к базе
argument-hint: "<appname>"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /web-unpublish — Удаление публикации 1С
Удаляет публикацию из httpd.conf и каталог `publish/{appname}`. Если других публикаций не осталось — удаляет глобальный блок 1C и останавливает Apache.
## Usage
```
/web-unpublish <appname>
/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"
```
@@ -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
+117
View File
@@ -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С
+184
View File
@@ -0,0 +1,184 @@
# Веб-публикация 1С — техническая спецификация
Описание артефактов, необходимых для публикации информационной базы 1С через Apache HTTP Server.
## default.vrd
Дескриптор виртуального ресурса. XML-файл, описывающий подключение к информационной базе.
### Формат
```xml
<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/appname"
ib="connection-string">
</point>
```
### Атрибут `base`
URL-путь публикации. Должен начинаться с `/`, совпадает с `Alias` в httpd.conf.
### Атрибут `ib`
Строка подключения к информационной базе.
**Файловая база:**
```
File=&quot;C:\Bases\MyDB&quot;;
```
**Серверная база:**
```
Srvr=&quot;server01&quot;;Ref=&quot;MyDB&quot;;
```
**С авторизацией:**
```
File=&quot;C:\Bases\MyDB&quot;;Usr=&quot;Admin&quot;;Pwd=&quot;123&quot;;
```
> Кавычки внутри значения `ib` экранируются как `&quot;` (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"
<Directory "C:/path/to/apache/publish/appname">
AllowOverride All
Require all granted
SetHandler 1c-application
ManagedApplicationDescriptor "C:/path/to/apache/publish/appname/default.vrd"
</Directory>
```
- `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"
<Directory "C:/tools/apache24/publish/mydb">
AllowOverride All
Require all granted
SetHandler 1c-application
ManagedApplicationDescriptor "C:/tools/apache24/publish/mydb/default.vrd"
</Directory>
# --- 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 варианта: остановка + запуск.