From bc4778d6cc94490bd017535552d231ddb5dd2920 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 22 Feb 2026 16:28:22 +0300 Subject: [PATCH] feat(web): add web publishing skills (web-publish, web-info, web-stop, web-unpublish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .claude/skills/web-info/SKILL.md | 62 ++++ .claude/skills/web-info/scripts/web-info.ps1 | 127 +++++++ .claude/skills/web-publish/SKILL.md | 79 +++++ .../web-publish/scripts/web-publish.ps1 | 328 ++++++++++++++++++ .claude/skills/web-stop/SKILL.md | 46 +++ .claude/skills/web-stop/scripts/web-stop.ps1 | 75 ++++ .claude/skills/web-unpublish/SKILL.md | 51 +++ .../web-unpublish/scripts/web-unpublish.ps1 | 109 ++++++ docs/web-guide.md | 117 +++++++ docs/web-spec.md | 184 ++++++++++ 10 files changed, 1178 insertions(+) create mode 100644 .claude/skills/web-info/SKILL.md create mode 100644 .claude/skills/web-info/scripts/web-info.ps1 create mode 100644 .claude/skills/web-publish/SKILL.md create mode 100644 .claude/skills/web-publish/scripts/web-publish.ps1 create mode 100644 .claude/skills/web-stop/SKILL.md create mode 100644 .claude/skills/web-stop/scripts/web-stop.ps1 create mode 100644 .claude/skills/web-unpublish/SKILL.md create mode 100644 .claude/skills/web-unpublish/scripts/web-unpublish.ps1 create mode 100644 docs/web-guide.md create mode 100644 docs/web-spec.md 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 варианта: остановка + запуск.