diff --git a/.claude/skills/db-dump-dt/SKILL.md b/.claude/skills/db-dump-dt/SKILL.md new file mode 100644 index 00000000..1aab41ad --- /dev/null +++ b/.claude/skills/db-dump-dt/SKILL.md @@ -0,0 +1,72 @@ +--- +name: db-dump-dt +description: Выгрузка информационной базы 1С в DT-файл (вся база — конфигурация + данные). Используй когда нужно выгрузить информационную базу, выгрузить архив базы, сделать бэкап, выгрузить dt +argument-hint: "[database] [output.dt]" +allowed-tools: + - Bash + - Read + - Glob + - AskUserQuestion +--- + +# /db-dump-dt — Выгрузка информационной базы в DT-файл + +Выгружает информационную базу целиком (конфигурация **+ данные**) в DT-файл — полный снимок ИБ. + +> В отличие от `/db-dump-cf` (только конфигурация), `.dt` содержит **всю базу**: данные, +> настройки, пользователей. Это бэкап/точка отката, а не выгрузка метаданных. + +## Usage + +``` +/db-dump-dt [database] [output.dt] +/db-dump-dt dev backup.dt +/db-dump-dt — база по умолчанию, имя файла по базе и дате +``` + +## Параметры подключения + +Прочитай `.v8-project.json` из корня проекта. Возьми `v8path` (путь к платформе) и разреши базу: +1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую +2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json` +3. Если не указал — сопоставь текущую ветку Git с `databases[].branches` +4. Если ветка не совпала — используй `default` +Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1` +Если файла нет — предложи `/db-list add`. +Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. + +## Команда + +```powershell +powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" <параметры> +``` + +### Параметры скрипта + +| Параметр | Обязательный | Описание | +|----------|:------------:|----------| +| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-InfoBasePath <путь>` | * | Файловая база | +| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | +| `-InfoBaseRef <имя>` | * | Имя базы на сервере | +| `-UserName <имя>` | нет | Имя пользователя | +| `-Password <пароль>` | нет | Пароль | +| `-OutputFile <путь>` | да | Путь к выходному DT-файлу | + +> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` + +## Примеры + +```powershell +# Выгрузка ИБ (файловая база) +powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "C:\backup\base.dt" + +# Серверная база +powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -OutputFile "base.dt" +``` + +## Связанные навыки + +- `/db-load-dt` — загрузка ИБ из DT (обратная операция) +- `/db-dump-cf` — выгрузка только конфигурации (без данных) +- `/db-create` — создать новую базу (в т.ч. из DT-шаблона) diff --git a/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 b/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 new file mode 100644 index 00000000..d6170081 --- /dev/null +++ b/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 @@ -0,0 +1,143 @@ +# db-dump-dt v1.0 — Dump 1C information base to DT file +# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills +<# +.SYNOPSIS + Выгрузка информационной базы 1С в DT-файл + +.DESCRIPTION + Выгружает информационную базу целиком (конфигурация + данные) в DT-файл. + +.PARAMETER V8Path + Путь к каталогу bin платформы или к 1cv8.exe + +.PARAMETER InfoBasePath + Путь к файловой информационной базе + +.PARAMETER InfoBaseServer + Сервер 1С (для серверной базы) + +.PARAMETER InfoBaseRef + Имя базы на сервере + +.PARAMETER UserName + Имя пользователя 1С + +.PARAMETER Password + Пароль пользователя + +.PARAMETER OutputFile + Путь к выходному DT-файлу + +.EXAMPLE + .\db-dump-dt.ps1 -InfoBasePath "C:\Bases\MyDB" -OutputFile "backup.dt" +#> + +[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=$true)] + [string]$OutputFile +) + +$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 = $found.FullName + } else { + Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red + exit 1 + } +} elseif (Test-Path $V8Path -PathType Container) { + $V8Path = Join-Path $V8Path "1cv8.exe" +} + +if (-not (Test-Path $V8Path)) { + Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red + exit 1 +} + +# --- Validate connection --- +if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { + Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red + exit 1 +} + +# --- Ensure output directory exists --- +$outDir = Split-Path $OutputFile -Parent +if ($outDir -and -not (Test-Path $outDir)) { + New-Item -ItemType Directory -Path $outDir -Force | Out-Null +} + +# --- Temp dir --- +$tempDir = Join-Path $env:TEMP "db_dump_dt_$(Get-Random)" +New-Item -ItemType Directory -Path $tempDir -Force | Out-Null + +try { + # --- Build arguments --- + $arguments = @("DESIGNER") + + if ($InfoBaseServer -and $InfoBaseRef) { + $arguments += "/S", "`"$InfoBaseServer/$InfoBaseRef`"" + } else { + $arguments += "/F", "`"$InfoBasePath`"" + } + + if ($UserName) { $arguments += "/N`"$UserName`"" } + if ($Password) { $arguments += "/P`"$Password`"" } + + $arguments += "/DumpIB", "`"$OutputFile`"" + + # --- Output --- + $outFile = Join-Path $tempDir "dump_dt_log.txt" + $arguments += "/Out", "`"$outFile`"" + $arguments += "/DisableStartupDialogs" + + # --- Execute --- + Write-Host "Running: 1cv8.exe $($arguments -join ' ')" + $process = Start-Process -FilePath $V8Path -ArgumentList $arguments -NoNewWindow -Wait -PassThru + $exitCode = $process.ExitCode + + # --- Result --- + if ($exitCode -eq 0) { + Write-Host "Information base dumped successfully to: $OutputFile" -ForegroundColor Green + } else { + Write-Host "Error dumping information base (code: $exitCode)" -ForegroundColor Red + } + + if (Test-Path $outFile) { + $logContent = Get-Content $outFile -Raw -ErrorAction SilentlyContinue + if ($logContent) { + Write-Host "--- Log ---" + Write-Host $logContent + Write-Host "--- End ---" + } + } + + exit $exitCode + +} finally { + if (Test-Path $tempDir) { + Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue + } +} diff --git a/.claude/skills/db-dump-dt/scripts/db-dump-dt.py b/.claude/skills/db-dump-dt/scripts/db-dump-dt.py new file mode 100644 index 00000000..feb3e27b --- /dev/null +++ b/.claude/skills/db-dump-dt/scripts/db-dump-dt.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# db-dump-dt v1.0 — Dump 1C information base to DT file +# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills + +import argparse +import glob +import os +import random +import shutil +import subprocess +import sys +import tempfile + + +def resolve_v8path(v8path): + """Resolve path to 1cv8.exe.""" + if not v8path: + found = sorted(glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")) + if found: + return found[-1] + else: + print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr) + sys.exit(1) + elif os.path.isdir(v8path): + v8path = os.path.join(v8path, "1cv8.exe") + + if not os.path.isfile(v8path): + print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr) + sys.exit(1) + return v8path + + +def main(): + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") + parser = argparse.ArgumentParser( + description="Dump 1C information base to DT file", + allow_abbrev=False, + ) + parser.add_argument("-V8Path", default="") + parser.add_argument("-InfoBasePath", default="") + parser.add_argument("-InfoBaseServer", default="") + parser.add_argument("-InfoBaseRef", default="") + parser.add_argument("-UserName", default="") + parser.add_argument("-Password", default="") + parser.add_argument("-OutputFile", required=True) + args = parser.parse_args() + + v8path = resolve_v8path(args.V8Path) + + # --- Validate connection --- + if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) + sys.exit(1) + + # --- Ensure output directory exists --- + out_dir = os.path.dirname(args.OutputFile) + if out_dir and not os.path.isdir(out_dir): + os.makedirs(out_dir, exist_ok=True) + + # --- Temp dir --- + temp_dir = os.path.join(tempfile.gettempdir(), f"db_dump_dt_{random.randint(0, 999999)}") + os.makedirs(temp_dir, exist_ok=True) + + try: + # --- Build arguments --- + arguments = ["DESIGNER"] + + if args.InfoBaseServer and args.InfoBaseRef: + arguments.extend(["/S", f"{args.InfoBaseServer}/{args.InfoBaseRef}"]) + else: + arguments.extend(["/F", args.InfoBasePath]) + + if args.UserName: + arguments.append(f"/N{args.UserName}") + if args.Password: + arguments.append(f"/P{args.Password}") + + arguments.extend(["/DumpIB", args.OutputFile]) + + # --- Output --- + out_file = os.path.join(temp_dir, "dump_dt_log.txt") + arguments.extend(["/Out", out_file]) + arguments.append("/DisableStartupDialogs") + + # --- Execute --- + print(f"Running: 1cv8.exe {' '.join(arguments)}") + result = subprocess.run( + [v8path] + arguments, + capture_output=True, + text=True, + ) + exit_code = result.returncode + + # --- Result --- + if exit_code == 0: + print(f"Information base dumped successfully to: {args.OutputFile}") + else: + print(f"Error dumping information base (code: {exit_code})", file=sys.stderr) + + if os.path.isfile(out_file): + try: + with open(out_file, "r", encoding="utf-8-sig") as f: + log_content = f.read() + if log_content: + print("--- Log ---") + print(log_content) + print("--- End ---") + except Exception: + pass + + sys.exit(exit_code) + + finally: + if os.path.isdir(temp_dir): + shutil.rmtree(temp_dir, ignore_errors=True) + + +if __name__ == "__main__": + main()