From 11bab7669d977e087cf86808831ca1b05e0fbfd1 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 21 Jun 2026 15:18:41 +0300 Subject: [PATCH 1/8] =?UTF-8?q?feat(db-dump-dt,db-load-dt):=20=D0=BF=D0=B8?= =?UTF-8?q?=D0=BB=D0=BE=D1=82=20ibcmd=20(=D0=B4=D0=B2=D0=B8=D0=B6=D0=BE?= =?UTF-8?q?=D0=BA=20=D0=BF=D0=BE=20=D0=B8=D0=BC=D0=B5=D0=BD=D0=B8=20exe=20?= =?UTF-8?q?=D0=B2=20-V8Path)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Если -V8Path указывает на ibcmd.exe — операция выполняется через утилиту автономного сервера (offline, без запуска платформы), иначе как прежде через 1cv8 DESIGNER. Выбор движка неявный (sniff имени exe), без новых параметров; в реестре .v8-project.json пользователь прописывает v8path = путь к ibcmd.exe. Пилот на dt-паре: - dump: ibcmd infobase dump --db-path= [--user][--password]
- restore: ibcmd infobase restore --db-path= [--create-database если нет 1Cv8.1CD] [--user][--password]
Только файловые базы (серверные под ibcmd → понятная ошибка: нужны креды СУБД, которых нет в реестре). Вывод ibcmd (UTF-8) захватывается из stdout/stderr (нет /Out-файла). 1cv8-ветка без изменений. Версия 1.1→1.2. E2E: dump 115281б, restore round-trip (свежий каталог +--create-database, overwrite существующей без флага), 1cv8-регресс, server+ibcmd→ошибка. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/db-dump-dt/SKILL.md | 4 ++- .../skills/db-dump-dt/scripts/db-dump-dt.ps1 | 32 ++++++++++++++++-- .../skills/db-dump-dt/scripts/db-dump-dt.py | 29 ++++++++++++++-- .claude/skills/db-load-dt/SKILL.md | 4 ++- .../skills/db-load-dt/scripts/db-load-dt.ps1 | 33 +++++++++++++++++-- .../skills/db-load-dt/scripts/db-load-dt.py | 31 +++++++++++++++-- 6 files changed, 123 insertions(+), 10 deletions(-) diff --git a/.claude/skills/db-dump-dt/SKILL.md b/.claude/skills/db-dump-dt/SKILL.md index 1aab41ad..76cdd197 100644 --- a/.claude/skills/db-dump-dt/SKILL.md +++ b/.claude/skills/db-dump-dt/SKILL.md @@ -45,7 +45,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" <п | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -54,6 +54,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" <п | `-OutputFile <путь>` | да | Путь к выходному DT-файлу | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — выгрузка идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ## Примеры diff --git a/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 b/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 index 63ff1193..5f801a05 100644 --- a/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 +++ b/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 @@ -1,4 +1,4 @@ -# db-dump-dt v1.1 — Dump 1C information base to DT file +# db-dump-dt v1.2 — Dump 1C information base to DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -102,8 +102,16 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + # --- Validate connection --- -if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } +} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -119,6 +127,26 @@ $tempDir = Join-Path $env:TEMP "db_dump_dt_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only) --- + $arguments = @("infobase", "dump", "--db-path=$InfoBasePath") + if ($UserName) { $arguments += "--user=$UserName" } + if ($Password) { $arguments += "--password=$Password" } + $arguments += "$OutputFile" + + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + 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 ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/db-dump-dt/scripts/db-dump-dt.py b/.claude/skills/db-dump-dt/scripts/db-dump-dt.py index 684aa9fc..15cd0e59 100644 --- a/.claude/skills/db-dump-dt/scripts/db-dump-dt.py +++ b/.claude/skills/db-dump-dt/scripts/db-dump-dt.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-dump-dt v1.1 — Dump 1C information base to DT file +# db-dump-dt v1.2 — Dump 1C information base to DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -82,9 +82,14 @@ def main(): args = parser.parse_args() v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" # --- Validate connection --- - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) @@ -93,6 +98,26 @@ def main(): if out_dir and not os.path.isdir(out_dir): os.makedirs(out_dir, exist_ok=True) + # --- ibcmd branch (file infobase only) --- + if engine == "ibcmd": + arguments = ["infobase", "dump", f"--db-path={args.InfoBasePath}"] + if args.UserName: + arguments.append(f"--user={args.UserName}") + if args.Password: + arguments.append(f"--password={args.Password}") + arguments.append(args.OutputFile) + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print(f"Information base dumped successfully to: {args.OutputFile}") + else: + print(f"Error dumping information base (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Temp dir --- temp_dir = os.path.join(tempfile.gettempdir(), f"db_dump_dt_{random.randint(0, 999999)}") os.makedirs(temp_dir, exist_ok=True) diff --git a/.claude/skills/db-load-dt/SKILL.md b/.claude/skills/db-load-dt/SKILL.md index fcecd4fa..d08ed2ec 100644 --- a/.claude/skills/db-load-dt/SKILL.md +++ b/.claude/skills/db-load-dt/SKILL.md @@ -59,7 +59,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" <п | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -70,6 +70,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" <п | `-UnlockCode <код>` | нет | Код разблокировки (`/UC`), если заблокировано начало сеансов | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — загрузка идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). Базу создаст при отсутствии. ## После выполнения diff --git a/.claude/skills/db-load-dt/scripts/db-load-dt.ps1 b/.claude/skills/db-load-dt/scripts/db-load-dt.ps1 index aa5108fb..6f39b878 100644 --- a/.claude/skills/db-load-dt/scripts/db-load-dt.ps1 +++ b/.claude/skills/db-load-dt/scripts/db-load-dt.ps1 @@ -1,4 +1,4 @@ -# db-load-dt v1.1 — Load 1C information base from DT file +# db-load-dt v1.2 — Load 1C information base from DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -115,8 +115,16 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + # --- Validate connection --- -if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } +} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -132,6 +140,27 @@ $tempDir = Join-Path $env:TEMP "db_load_dt_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only) --- + $arguments = @("infobase", "restore", "--db-path=$InfoBasePath") + if (-not (Test-Path (Join-Path $InfoBasePath "1Cv8.1CD"))) { $arguments += "--create-database" } + if ($UserName) { $arguments += "--user=$UserName" } + if ($Password) { $arguments += "--password=$Password" } + $arguments += "$InputFile" + + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Information base restored successfully from: $InputFile" -ForegroundColor Green + } else { + Write-Host "Error restoring information base (code: $exitCode)" -ForegroundColor Red + } + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/db-load-dt/scripts/db-load-dt.py b/.claude/skills/db-load-dt/scripts/db-load-dt.py index 2c5ff391..60e5f2fa 100644 --- a/.claude/skills/db-load-dt/scripts/db-load-dt.py +++ b/.claude/skills/db-load-dt/scripts/db-load-dt.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-load-dt v1.1 — Load 1C information base from DT file +# db-load-dt v1.2 — Load 1C information base from DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -84,9 +84,14 @@ def main(): args = parser.parse_args() v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" # --- Validate connection --- - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) @@ -95,6 +100,28 @@ def main(): print(f"Error: input file not found: {args.InputFile}", file=sys.stderr) sys.exit(1) + # --- ibcmd branch (file infobase only) --- + if engine == "ibcmd": + arguments = ["infobase", "restore", f"--db-path={args.InfoBasePath}"] + if not os.path.isfile(os.path.join(args.InfoBasePath, "1Cv8.1CD")): + arguments.append("--create-database") + if args.UserName: + arguments.append(f"--user={args.UserName}") + if args.Password: + arguments.append(f"--password={args.Password}") + arguments.append(args.InputFile) + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print(f"Information base restored successfully from: {args.InputFile}") + else: + print(f"Error restoring information base (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Temp dir --- temp_dir = os.path.join(tempfile.gettempdir(), f"db_load_dt_{random.randint(0, 999999)}") os.makedirs(temp_dir, exist_ok=True) From 4102b7005afcc20f672252ca483b58e056691529 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 21 Jun 2026 15:37:19 +0300 Subject: [PATCH 2/8] =?UTF-8?q?feat(db):=20=D1=82=D0=B8=D1=80=D0=B0=D0=B6?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20ibcmd=20?= =?UTF-8?q?=D0=BD=D0=B0=20create/cf/update/xml=20(=D0=BF=D0=BE=20=D0=B8?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B8=20exe=20=D0=B2=20-V8Path)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Распространение пилота dt-пары на остальные применимые навыки. Если -V8Path указывает на ibcmd.exe — операция идёт через автономный сервер (offline, без запуска платформы), иначе как прежде через 1cv8 DESIGNER. Маппинг (только файловые базы --db-path): - db-create → infobase create --create-database [--restore=dt|--load=cf --apply] - db-dump-cf → infobase config save - db-load-cf → infobase config load - db-update → infobase config apply --force (--force обязателен: без него ibcmd уходит в интерактивный [y/n] и в неинтерактиве отменяет, exit 102) - db-dump-xml→ infobase config export (иерархический, Mode Full/Changes) - db-load-xml→ infobase config import (+цепочка config apply при -UpdateDB) Несовместимое под ibcmd даёт понятную ошибку с указанием на 1cv8: серверные базы, -AllExtensions, -Format Plain, Mode Partial/UpdateInfo, Files/ListFile. 1cv8-ветки без изменений. Версии 1.1→1.2 (xml-load 1.5→1.6). E2E цепочка через ibcmd: create→dump-cf→load-cf→update→dump-xml→ load-xml+UpdateDB — всё exit 0; 1cv8-регресс (create/load-cf/update) цел. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/db-create/SKILL.md | 4 +- .../skills/db-create/scripts/db-create.ps1 | 35 +++++++++++- .claude/skills/db-create/scripts/db-create.py | 29 +++++++++- .claude/skills/db-dump-cf/SKILL.md | 4 +- .../skills/db-dump-cf/scripts/db-dump-cf.ps1 | 34 ++++++++++- .../skills/db-dump-cf/scripts/db-dump-cf.py | 30 +++++++++- .claude/skills/db-dump-xml/SKILL.md | 4 +- .../db-dump-xml/scripts/db-dump-xml.ps1 | 42 +++++++++++++- .../skills/db-dump-xml/scripts/db-dump-xml.py | 36 +++++++++++- .claude/skills/db-load-cf/SKILL.md | 4 +- .../skills/db-load-cf/scripts/db-load-cf.ps1 | 34 ++++++++++- .../skills/db-load-cf/scripts/db-load-cf.py | 30 +++++++++- .claude/skills/db-load-xml/SKILL.md | 4 +- .../db-load-xml/scripts/db-load-xml.ps1 | 56 ++++++++++++++++++- .../skills/db-load-xml/scripts/db-load-xml.py | 53 +++++++++++++++++- .claude/skills/db-update/SKILL.md | 4 +- .../skills/db-update/scripts/db-update.ps1 | 35 +++++++++++- .claude/skills/db-update/scripts/db-update.py | 34 ++++++++++- 18 files changed, 442 insertions(+), 30 deletions(-) diff --git a/.claude/skills/db-create/SKILL.md b/.claude/skills/db-create/SKILL.md index f7678fb8..1667d9fd 100644 --- a/.claude/skills/db-create/SKILL.md +++ b/.claude/skills/db-create/SKILL.md @@ -38,7 +38,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" <п | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Путь к файловой базе | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -47,6 +47,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" <п | `-ListName <имя>` | нет | Имя базы в списке | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ## После создания diff --git a/.claude/skills/db-create/scripts/db-create.ps1 b/.claude/skills/db-create/scripts/db-create.ps1 index 6d846d92..7078ab4f 100644 --- a/.claude/skills/db-create/scripts/db-create.ps1 +++ b/.claude/skills/db-create/scripts/db-create.ps1 @@ -1,4 +1,4 @@ -# db-create v1.1 — Create 1C information base +# db-create v1.2 — Create 1C information base # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -109,8 +109,16 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + # --- Validate connection --- -if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } +} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -126,6 +134,29 @@ $tempDir = Join-Path $env:TEMP "db_create_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only) --- + $arguments = @("infobase", "create", "--db-path=$InfoBasePath", "--create-database") + if ($UseTemplate) { + if ([System.IO.Path]::GetExtension($UseTemplate) -ieq ".dt") { + $arguments += "--restore=$UseTemplate" + } else { + $arguments += "--load=$UseTemplate", "--apply" + } + } + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Information base created successfully: $InfoBasePath" -ForegroundColor Green + } else { + Write-Host "Error creating information base (code: $exitCode)" -ForegroundColor Red + } + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("CREATEINFOBASE") diff --git a/.claude/skills/db-create/scripts/db-create.py b/.claude/skills/db-create/scripts/db-create.py index 8424eb28..c2257157 100644 --- a/.claude/skills/db-create/scripts/db-create.py +++ b/.claude/skills/db-create/scripts/db-create.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-create v1.1 — Create 1C information base +# db-create v1.2 — Create 1C information base # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -82,9 +82,14 @@ def main(): args = parser.parse_args() v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" # --- Validate connection --- - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) @@ -93,6 +98,26 @@ def main(): print(f"Error: template file not found: {args.UseTemplate}", file=sys.stderr) sys.exit(1) + # --- ibcmd branch (file infobase only) --- + if engine == "ibcmd": + arguments = ["infobase", "create", f"--db-path={args.InfoBasePath}", "--create-database"] + if args.UseTemplate: + if os.path.splitext(args.UseTemplate)[1].lower() == ".dt": + arguments.append(f"--restore={args.UseTemplate}") + else: + arguments.extend([f"--load={args.UseTemplate}", "--apply"]) + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print(f"Information base created successfully: {args.InfoBasePath}") + else: + print(f"Error creating information base (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Temp dir --- temp_dir = os.path.join(tempfile.gettempdir(), f"db_create_{random.randint(0, 999999)}") os.makedirs(temp_dir, exist_ok=True) diff --git a/.claude/skills/db-dump-cf/SKILL.md b/.claude/skills/db-dump-cf/SKILL.md index 84e3677a..60f853fe 100644 --- a/.claude/skills/db-dump-cf/SKILL.md +++ b/.claude/skills/db-dump-cf/SKILL.md @@ -42,7 +42,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" <п | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -53,6 +53,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" <п | `-AllExtensions` | нет | Выгрузить все расширения | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ## Примеры diff --git a/.claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 b/.claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 index 23ac9f41..f9e13e8d 100644 --- a/.claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 +++ b/.claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 @@ -1,4 +1,4 @@ -# db-dump-cf v1.1 — Dump 1C configuration to CF file +# db-dump-cf v1.2 — Dump 1C configuration to CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -118,8 +118,16 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + # --- Validate connection --- -if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } +} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -135,6 +143,28 @@ $tempDir = Join-Path $env:TEMP "db_dump_cf_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only) --- + if ($AllExtensions) { + Write-Host "Error: ibcmd config save does not support -AllExtensions (use -Extension)" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "save", "--db-path=$InfoBasePath") + if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "$OutputFile" + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Configuration dumped successfully to: $OutputFile" -ForegroundColor Green + } else { + Write-Host "Error dumping configuration (code: $exitCode)" -ForegroundColor Red + } + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/db-dump-cf/scripts/db-dump-cf.py b/.claude/skills/db-dump-cf/scripts/db-dump-cf.py index 5668e614..67ebc320 100644 --- a/.claude/skills/db-dump-cf/scripts/db-dump-cf.py +++ b/.claude/skills/db-dump-cf/scripts/db-dump-cf.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-dump-cf v1.1 — Dump 1C configuration to CF file +# db-dump-cf v1.2 — Dump 1C configuration to CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -84,9 +84,14 @@ def main(): args = parser.parse_args() v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" # --- Validate connection --- - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) @@ -95,6 +100,27 @@ def main(): if out_dir and not os.path.isdir(out_dir): os.makedirs(out_dir, exist_ok=True) + # --- ibcmd branch (file infobase only) --- + if engine == "ibcmd": + if args.AllExtensions: + print("Error: ibcmd config save does not support -AllExtensions (use -Extension)", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "save", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + arguments.append(args.OutputFile) + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print(f"Configuration dumped successfully to: {args.OutputFile}") + else: + print(f"Error dumping configuration (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Temp dir --- temp_dir = os.path.join(tempfile.gettempdir(), f"db_dump_cf_{random.randint(0, 999999)}") os.makedirs(temp_dir, exist_ok=True) diff --git a/.claude/skills/db-dump-xml/SKILL.md b/.claude/skills/db-dump-xml/SKILL.md index 12d44d2a..3199f5fa 100644 --- a/.claude/skills/db-dump-xml/SKILL.md +++ b/.claude/skills/db-dump-xml/SKILL.md @@ -44,7 +44,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" < | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -58,6 +58,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" < | `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ### Режимы выгрузки diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 index ffc472d5..c6702713 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 @@ -1,4 +1,4 @@ -# db-dump-xml v1.1 — Dump 1C configuration to XML files +# db-dump-xml v1.2 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -141,8 +141,16 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + # --- Validate connection --- -if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } +} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -164,6 +172,36 @@ $tempDir = Join-Path $env:TEMP "db_dump_xml_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only; hierarchical Full/Changes) --- + if ($Format -eq "Plain") { + Write-Host "Error: ibcmd config export supports hierarchical format only (use -Format Hierarchical or 1cv8)" -ForegroundColor Red + exit 1 + } + if ($AllExtensions) { + Write-Host "Error: ibcmd config export does not support -AllExtensions (use -Extension or 1cv8)" -ForegroundColor Red + exit 1 + } + if ($Mode -eq "Partial" -or $Mode -eq "UpdateInfo") { + Write-Host "Error: ibcmd config export supports Mode Full/Changes only; use 1cv8 for $Mode" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "export", "--db-path=$InfoBasePath") + if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "$ConfigDir" + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Configuration exported successfully to: $ConfigDir" -ForegroundColor Green + } else { + Write-Host "Error exporting configuration (code: $exitCode)" -ForegroundColor Red + } + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py index c8de84a5..cbb21d8d 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-dump-xml v1.1 — Dump 1C configuration to XML files +# db-dump-xml v1.2 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -98,9 +98,14 @@ def main(): # --- Resolve V8Path --- v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" # --- Validate connection --- - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) @@ -114,6 +119,33 @@ def main(): os.makedirs(args.ConfigDir, exist_ok=True) print(f"Created output directory: {args.ConfigDir}") + # --- ibcmd branch (file infobase only; hierarchical Full/Changes) --- + if engine == "ibcmd": + if args.Format == "Plain": + print("Error: ibcmd config export supports hierarchical format only (use -Format Hierarchical or 1cv8)", file=sys.stderr) + sys.exit(1) + if args.AllExtensions: + print("Error: ibcmd config export does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) + sys.exit(1) + if args.Mode in ("Partial", "UpdateInfo"): + print(f"Error: ibcmd config export supports Mode Full/Changes only; use 1cv8 for {args.Mode}", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "export", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + arguments.append(args.ConfigDir) + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print(f"Configuration exported successfully to: {args.ConfigDir}") + else: + print(f"Error exporting configuration (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Temp dir --- temp_dir = os.path.join(tempfile.gettempdir(), f"db_dump_xml_{random.randint(0, 999999)}") os.makedirs(temp_dir, exist_ok=True) diff --git a/.claude/skills/db-load-cf/SKILL.md b/.claude/skills/db-load-cf/SKILL.md index ef9c7d48..53d056e2 100644 --- a/.claude/skills/db-load-cf/SKILL.md +++ b/.claude/skills/db-load-cf/SKILL.md @@ -43,7 +43,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" <п | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -54,6 +54,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" <п | `-AllExtensions` | нет | Загрузить все расширения из архива | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ## После выполнения diff --git a/.claude/skills/db-load-cf/scripts/db-load-cf.ps1 b/.claude/skills/db-load-cf/scripts/db-load-cf.ps1 index 5766214a..08398684 100644 --- a/.claude/skills/db-load-cf/scripts/db-load-cf.ps1 +++ b/.claude/skills/db-load-cf/scripts/db-load-cf.ps1 @@ -1,4 +1,4 @@ -# db-load-cf v1.1 — Load 1C configuration from CF file +# db-load-cf v1.2 — Load 1C configuration from CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -118,8 +118,16 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + # --- Validate connection --- -if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } +} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -135,6 +143,28 @@ $tempDir = Join-Path $env:TEMP "db_load_cf_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only) --- + if ($AllExtensions) { + Write-Host "Error: ibcmd config load does not support -AllExtensions (use -Extension)" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "load", "--db-path=$InfoBasePath") + if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "$InputFile" + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Configuration loaded successfully from: $InputFile" -ForegroundColor Green + } else { + Write-Host "Error loading configuration (code: $exitCode)" -ForegroundColor Red + } + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/db-load-cf/scripts/db-load-cf.py b/.claude/skills/db-load-cf/scripts/db-load-cf.py index e00a7c8d..003d26b4 100644 --- a/.claude/skills/db-load-cf/scripts/db-load-cf.py +++ b/.claude/skills/db-load-cf/scripts/db-load-cf.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-load-cf v1.1 — Load 1C configuration from CF file +# db-load-cf v1.2 — Load 1C configuration from CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -84,9 +84,14 @@ def main(): args = parser.parse_args() v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" # --- Validate connection --- - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) @@ -95,6 +100,27 @@ def main(): print(f"Error: input file not found: {args.InputFile}", file=sys.stderr) sys.exit(1) + # --- ibcmd branch (file infobase only) --- + if engine == "ibcmd": + if args.AllExtensions: + print("Error: ibcmd config load does not support -AllExtensions (use -Extension)", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "load", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + arguments.append(args.InputFile) + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print(f"Configuration loaded successfully from: {args.InputFile}") + else: + print(f"Error loading configuration (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Temp dir --- temp_dir = os.path.join(tempfile.gettempdir(), f"db_load_cf_{random.randint(0, 999999)}") os.makedirs(temp_dir, exist_ok=True) diff --git a/.claude/skills/db-load-xml/SKILL.md b/.claude/skills/db-load-xml/SKILL.md index 0d4e721b..ef054f2c 100644 --- a/.claude/skills/db-load-xml/SKILL.md +++ b/.claude/skills/db-load-xml/SKILL.md @@ -45,7 +45,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" < | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -61,6 +61,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" < | `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ### Режимы загрузки diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 index c79945f2..ad7807de 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 @@ -1,4 +1,4 @@ -# db-load-xml v1.5 — Load 1C configuration from XML files +# db-load-xml v1.6 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -150,8 +150,16 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + # --- Validate connection --- -if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } +} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -173,6 +181,50 @@ $tempDir = Join-Path $env:TEMP "db_load_xml_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only; hierarchical full-directory import) --- + if ($Format -eq "Plain") { + Write-Host "Error: ibcmd config import supports hierarchical format only (use -Format Hierarchical or 1cv8)" -ForegroundColor Red + exit 1 + } + if ($AllExtensions) { + Write-Host "Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)" -ForegroundColor Red + exit 1 + } + if ($Mode -eq "Partial" -or $Files -or $ListFile) { + Write-Host "Error: ibcmd config import supports full-directory import only; use 1cv8 for partial/file lists" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "import", "--db-path=$InfoBasePath") + if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "$ConfigDir" + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { + Write-Host "Error loading configuration from files (code: $exitCode)" -ForegroundColor Red + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + Write-Host "Configuration loaded successfully from: $ConfigDir" -ForegroundColor Green + if ($output) { Write-Host ($output | Out-String) } + + if ($UpdateDB) { + $applyArgs = @("infobase", "config", "apply", "--db-path=$InfoBasePath", "--force") + Write-Host "Running: ibcmd $($applyArgs -join ' ')" + $applyOut = & $V8Path @applyArgs 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Database configuration updated successfully" -ForegroundColor Green + } else { + Write-Host "Error updating database configuration (code: $exitCode)" -ForegroundColor Red + } + if ($applyOut) { Write-Host ($applyOut | Out-String) } + } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.py b/.claude/skills/db-load-xml/scripts/db-load-xml.py index dca6a724..ef9b7b9b 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.py +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-load-xml v1.5 — Load 1C configuration from XML files +# db-load-xml v1.6 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -106,8 +106,14 @@ def main(): # --- Resolve V8Path --- v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" + # --- Validate connection --- - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) @@ -121,6 +127,49 @@ def main(): print("Error: -Files or -ListFile required for Partial mode", file=sys.stderr) sys.exit(1) + # --- ibcmd branch (file infobase only; hierarchical full-directory import) --- + if engine == "ibcmd": + if args.Format == "Plain": + print("Error: ibcmd config import supports hierarchical format only (use -Format Hierarchical or 1cv8)", file=sys.stderr) + sys.exit(1) + if args.AllExtensions: + print("Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) + sys.exit(1) + if args.Mode == "Partial" or args.Files or args.ListFile: + print("Error: ibcmd config import supports full-directory import only; use 1cv8 for partial/file lists", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "import", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + arguments.append(args.ConfigDir) + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode != 0: + print(f"Error loading configuration from files (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + print(f"Configuration loaded successfully from: {args.ConfigDir}") + if result.stdout: + print(result.stdout) + exit_code = 0 + if args.UpdateDB: + apply_args = ["infobase", "config", "apply", f"--db-path={args.InfoBasePath}", "--force"] + print(f"Running: ibcmd {' '.join(apply_args)}") + ar = subprocess.run([v8path] + apply_args, capture_output=True, encoding="utf-8", errors="replace") + exit_code = ar.returncode + if exit_code == 0: + print("Database configuration updated successfully") + else: + print(f"Error updating database configuration (code: {exit_code})", file=sys.stderr) + if ar.stdout: + print(ar.stdout) + if ar.stderr: + print(ar.stderr, file=sys.stderr) + sys.exit(exit_code) + # --- Temp dir --- temp_dir = os.path.join(tempfile.gettempdir(), f"db_load_xml_{random.randint(0, 999999)}") os.makedirs(temp_dir, exist_ok=True) diff --git a/.claude/skills/db-update/SKILL.md b/.claude/skills/db-update/SKILL.md index 96c88624..4a874ef7 100644 --- a/.claude/skills/db-update/SKILL.md +++ b/.claude/skills/db-update/SKILL.md @@ -42,7 +42,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" <п | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -55,6 +55,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" <п | `-WarningsAsErrors` | нет | Предупреждения считать ошибками | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ### Фоновое обновление (серверная база) diff --git a/.claude/skills/db-update/scripts/db-update.ps1 b/.claude/skills/db-update/scripts/db-update.ps1 index 3279a33b..f95d9ced 100644 --- a/.claude/skills/db-update/scripts/db-update.ps1 +++ b/.claude/skills/db-update/scripts/db-update.ps1 @@ -1,4 +1,4 @@ -# db-update v1.1 — Update 1C database configuration +# db-update v1.2 — Update 1C database configuration # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -131,8 +131,16 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + # --- Validate connection --- -if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } +} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -142,6 +150,29 @@ $tempDir = Join-Path $env:TEMP "db_update_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only) --- + if ($AllExtensions) { + Write-Host "Error: ibcmd config apply does not support -AllExtensions (use -Extension)" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "apply", "--db-path=$InfoBasePath", "--force") + if ($Dynamic -eq "+") { $arguments += "--dynamic=auto" } + elseif ($Dynamic -eq "-") { $arguments += "--dynamic=disable" } + if ($Extension) { $arguments += "--extension=$Extension" } + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Database configuration updated successfully" -ForegroundColor Green + } else { + Write-Host "Error updating database configuration (code: $exitCode)" -ForegroundColor Red + } + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/db-update/scripts/db-update.py b/.claude/skills/db-update/scripts/db-update.py index 3e66dad6..93918b31 100644 --- a/.claude/skills/db-update/scripts/db-update.py +++ b/.claude/skills/db-update/scripts/db-update.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-update v1.1 — Update 1C database configuration +# db-update v1.2 — Update 1C database configuration # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -87,11 +87,41 @@ def main(): v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" + # --- Validate connection --- - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) + # --- ibcmd branch (file infobase only) --- + if engine == "ibcmd": + if args.AllExtensions: + print("Error: ibcmd config apply does not support -AllExtensions (use -Extension)", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "apply", f"--db-path={args.InfoBasePath}", "--force"] + if args.Dynamic == "+": + arguments.append("--dynamic=auto") + elif args.Dynamic == "-": + arguments.append("--dynamic=disable") + if args.Extension: + arguments.append(f"--extension={args.Extension}") + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print("Database configuration updated successfully") + else: + print(f"Error updating database configuration (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Temp dir --- temp_dir = os.path.join(tempfile.gettempdir(), f"db_update_{random.randint(0, 999999)}") os.makedirs(temp_dir, exist_ok=True) From 27b9d539e01f8bf295497d402af994da401bc2ce Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 21 Jun 2026 16:33:07 +0300 Subject: [PATCH 3/8] =?UTF-8?q?feat(db):=20ibcmd=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=87=D0=B0=D1=81=D1=82=D0=B8=D1=87=D0=BD=D0=BE=D0=B9=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8/=D0=B7=D0=B0=D0=B3?= =?UTF-8?q?=D1=80=D1=83=D0=B7=D0=BA=D0=B8=20=D0=B8=D0=B7=20=D0=B8=D1=81?= =?UTF-8?q?=D1=85=D0=BE=D0=B4=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Закрыты частичные режимы, ранее дававшие «use 1cv8»: - db-dump-xml Mode=Partial → ibcmd config export objects <имена> --out= (выгрузка указанных объектов конфигурации); - db-load-xml Mode=Partial / -Files / -ListFile → ibcmd config import files <отн.пути> --base-dir= (--base-dir обязателен); - db-load-git → добавлена ibcmd-поддержка (раньше отсутствовала): config import files <изменённые из git> --base-dir=, с цепочкой config apply --force при -UpdateDB; DryRun не трогает движок. Несовместимое под ibcmd по-прежнему даёт чистую ошибку: -Format Plain, -AllExtensions, db-dump-xml Mode UpdateInfo. 1cv8-ветки без изменений. Версии: db-dump-xml 1.2→1.3, db-load-xml 1.6→1.7, db-load-git 1.5→1.6. E2E: export objects (только указанные объекты), import files round-trip (+apply), db-load-git staged→import files+apply, DryRun, error-кейсы, 1cv8-регресс Partial — всё зелёное. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../db-dump-xml/scripts/db-dump-xml.ps1 | 19 ++++--- .../skills/db-dump-xml/scripts/db-dump-xml.py | 21 +++++--- .claude/skills/db-load-git/SKILL.md | 4 +- .../db-load-git/scripts/db-load-git.ps1 | 52 +++++++++++++++++-- .../skills/db-load-git/scripts/db-load-git.py | 52 +++++++++++++++++-- .../db-load-xml/scripts/db-load-xml.ps1 | 29 ++++++++--- .../skills/db-load-xml/scripts/db-load-xml.py | 31 ++++++++--- 7 files changed, 175 insertions(+), 33 deletions(-) diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 index c6702713..e47aa7b8 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 @@ -1,4 +1,4 @@ -# db-dump-xml v1.2 — Dump 1C configuration to XML files +# db-dump-xml v1.3 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -182,13 +182,20 @@ try { Write-Host "Error: ibcmd config export does not support -AllExtensions (use -Extension or 1cv8)" -ForegroundColor Red exit 1 } - if ($Mode -eq "Partial" -or $Mode -eq "UpdateInfo") { - Write-Host "Error: ibcmd config export supports Mode Full/Changes only; use 1cv8 for $Mode" -ForegroundColor Red + if ($Mode -eq "UpdateInfo") { + Write-Host "Error: ibcmd config export does not support Mode UpdateInfo; use 1cv8" -ForegroundColor Red exit 1 } - $arguments = @("infobase", "config", "export", "--db-path=$InfoBasePath") - if ($Extension) { $arguments += "--extension=$Extension" } - $arguments += "$ConfigDir" + if ($Mode -eq "Partial") { + $objList = @($Objects -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) + $arguments = @("infobase", "config", "export", "objects") + $objList + $arguments += "--out=$ConfigDir", "--db-path=$InfoBasePath" + if ($Extension) { $arguments += "--extension=$Extension" } + } else { + $arguments = @("infobase", "config", "export", "--db-path=$InfoBasePath") + if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "$ConfigDir" + } Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py index cbb21d8d..3436dea0 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-dump-xml v1.2 — Dump 1C configuration to XML files +# db-dump-xml v1.3 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -127,13 +127,20 @@ def main(): if args.AllExtensions: print("Error: ibcmd config export does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) sys.exit(1) - if args.Mode in ("Partial", "UpdateInfo"): - print(f"Error: ibcmd config export supports Mode Full/Changes only; use 1cv8 for {args.Mode}", file=sys.stderr) + if args.Mode == "UpdateInfo": + print("Error: ibcmd config export does not support Mode UpdateInfo; use 1cv8", file=sys.stderr) sys.exit(1) - arguments = ["infobase", "config", "export", f"--db-path={args.InfoBasePath}"] - if args.Extension: - arguments.append(f"--extension={args.Extension}") - arguments.append(args.ConfigDir) + if args.Mode == "Partial": + obj_list = [o.strip() for o in args.Objects.split(",") if o.strip()] + arguments = ["infobase", "config", "export", "objects"] + obj_list + arguments += [f"--out={args.ConfigDir}", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + else: + arguments = ["infobase", "config", "export", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + arguments.append(args.ConfigDir) print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/db-load-git/SKILL.md b/.claude/skills/db-load-git/SKILL.md index d260aba0..11a544c9 100644 --- a/.claude/skills/db-load-git/SKILL.md +++ b/.claude/skills/db-load-git/SKILL.md @@ -45,7 +45,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" < | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -61,6 +61,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" < | `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — загрузка идёт через автономный сервер (`config import files`); поддерживаются **только файловые базы** (`-InfoBasePath`). ## После выполнения diff --git a/.claude/skills/db-load-git/scripts/db-load-git.ps1 b/.claude/skills/db-load-git/scripts/db-load-git.ps1 index 96767f23..5650c1d1 100644 --- a/.claude/skills/db-load-git/scripts/db-load-git.ps1 +++ b/.claude/skills/db-load-git/scripts/db-load-git.ps1 @@ -1,4 +1,4 @@ -# db-load-git v1.5 — Load Git changes into 1C database +# db-load-git v1.6 — Load Git changes into 1C database # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -163,9 +163,16 @@ if (-not $DryRun) { } } -# --- Validate connection (skip if DryRun) --- +# --- Detect engine + validate connection (skip if DryRun) --- +$engine = "1cv8" if (-not $DryRun) { - if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } + } elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red exit 1 } @@ -319,6 +326,45 @@ $tempDir = Join-Path $env:TEMP "db_load_git_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only; import specific files) --- + if ($Format -eq "Plain") { + Write-Host "Error: ibcmd config import supports hierarchical format only (use -Format Hierarchical or 1cv8)" -ForegroundColor Red + exit 1 + } + if ($AllExtensions) { + Write-Host "Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "import", "files") + $configFiles + $arguments += "--base-dir=$ConfigDir", "--db-path=$InfoBasePath" + if ($Extension) { $arguments += "--extension=$Extension" } + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { + Write-Host "Error loading changes (code: $exitCode)" -ForegroundColor Red + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + Write-Host "Changes loaded successfully ($($configFiles.Count) files)" -ForegroundColor Green + if ($output) { Write-Host ($output | Out-String) } + if ($UpdateDB) { + $applyArgs = @("infobase", "config", "apply", "--db-path=$InfoBasePath", "--force") + Write-Host "Running: ibcmd $($applyArgs -join ' ')" + $applyOut = & $V8Path @applyArgs 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Database configuration updated successfully" -ForegroundColor Green + } else { + Write-Host "Error updating database configuration (code: $exitCode)" -ForegroundColor Red + } + if ($applyOut) { Write-Host ($applyOut | Out-String) } + } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Write list file (UTF-8 with BOM) --- $listFile = Join-Path $tempDir "load_list.txt" $utf8Bom = New-Object System.Text.UTF8Encoding($true) diff --git a/.claude/skills/db-load-git/scripts/db-load-git.py b/.claude/skills/db-load-git/scripts/db-load-git.py index c51444e9..dcf22dfb 100644 --- a/.claude/skills/db-load-git/scripts/db-load-git.py +++ b/.claude/skills/db-load-git/scripts/db-load-git.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-load-git v1.5 — Load Git changes into 1C database +# db-load-git v1.6 — Load Git changes into 1C database # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -125,9 +125,15 @@ def main(): if not args.DryRun: v8path = resolve_v8path(args.V8Path) - # --- Validate connection (skip if DryRun) --- + # --- Detect engine + validate connection (skip if DryRun) --- + engine = "1cv8" if not args.DryRun: - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr) sys.exit(1) @@ -248,6 +254,46 @@ def main(): os.makedirs(temp_dir, exist_ok=True) try: + if engine == "ibcmd": + # --- ibcmd branch (file infobase only; import specific files) --- + if args.Format == "Plain": + print("Error: ibcmd config import supports hierarchical format only (use -Format Hierarchical or 1cv8)", file=sys.stderr) + sys.exit(1) + if args.AllExtensions: + print("Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "import", "files"] + config_files + arguments += [f"--base-dir={args.ConfigDir}", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode != 0: + print(f"Error loading changes (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + print(f"Changes loaded successfully ({len(config_files)} files)") + if result.stdout: + print(result.stdout) + exit_code = 0 + if args.UpdateDB: + apply_args = ["infobase", "config", "apply", f"--db-path={args.InfoBasePath}", "--force"] + print(f"Running: ibcmd {' '.join(apply_args)}") + ar = subprocess.run([v8path] + apply_args, capture_output=True, encoding="utf-8", errors="replace") + exit_code = ar.returncode + if exit_code == 0: + print("Database configuration updated successfully") + else: + print(f"Error updating database configuration (code: {exit_code})", file=sys.stderr) + if ar.stdout: + print(ar.stdout) + if ar.stderr: + print(ar.stderr, file=sys.stderr) + sys.exit(exit_code) + # --- Write list file (UTF-8 with BOM) --- list_file = os.path.join(temp_dir, "load_list.txt") with open(list_file, "w", encoding="utf-8-sig") as f: diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 index ad7807de..04907e15 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 @@ -1,4 +1,4 @@ -# db-load-xml v1.6 — Load 1C configuration from XML files +# db-load-xml v1.7 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -192,12 +192,29 @@ try { exit 1 } if ($Mode -eq "Partial" -or $Files -or $ListFile) { - Write-Host "Error: ibcmd config import supports full-directory import only; use 1cv8 for partial/file lists" -ForegroundColor Red - exit 1 + # partial: import specific files (relative to ConfigDir) + $fileList = @() + if ($ListFile) { + if (-not (Test-Path $ListFile)) { + Write-Host "Error: list file not found: $ListFile" -ForegroundColor Red + exit 1 + } + $fileList = @(Get-Content -Path $ListFile -Encoding UTF8 | ForEach-Object { $_.Trim() } | Where-Object { $_ }) + } elseif ($Files) { + $fileList = @($Files -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) + } + if ($fileList.Count -eq 0) { + Write-Host "Error: -Files or -ListFile required for partial import" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "import", "files") + $fileList + $arguments += "--base-dir=$ConfigDir", "--db-path=$InfoBasePath" + if ($Extension) { $arguments += "--extension=$Extension" } + } else { + $arguments = @("infobase", "config", "import", "--db-path=$InfoBasePath") + if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "$ConfigDir" } - $arguments = @("infobase", "config", "import", "--db-path=$InfoBasePath") - if ($Extension) { $arguments += "--extension=$Extension" } - $arguments += "$ConfigDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.py b/.claude/skills/db-load-xml/scripts/db-load-xml.py index ef9b7b9b..1ce4b15e 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.py +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-load-xml v1.6 — Load 1C configuration from XML files +# db-load-xml v1.7 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -136,12 +136,29 @@ def main(): print("Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) sys.exit(1) if args.Mode == "Partial" or args.Files or args.ListFile: - print("Error: ibcmd config import supports full-directory import only; use 1cv8 for partial/file lists", file=sys.stderr) - sys.exit(1) - arguments = ["infobase", "config", "import", f"--db-path={args.InfoBasePath}"] - if args.Extension: - arguments.append(f"--extension={args.Extension}") - arguments.append(args.ConfigDir) + # partial: import specific files (relative to ConfigDir) + if args.ListFile: + if not os.path.isfile(args.ListFile): + print(f"Error: list file not found: {args.ListFile}", file=sys.stderr) + sys.exit(1) + with open(args.ListFile, encoding="utf-8-sig") as f: + file_list = [ln.strip() for ln in f if ln.strip()] + elif args.Files: + file_list = [p.strip() for p in args.Files.split(",") if p.strip()] + else: + file_list = [] + if not file_list: + print("Error: -Files or -ListFile required for partial import", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "import", "files"] + file_list + arguments += [f"--base-dir={args.ConfigDir}", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + else: + arguments = ["infobase", "config", "import", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + arguments.append(args.ConfigDir) print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode != 0: From 3f5065221e6adbd0e613d2b099c30ce71a9e9d43 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 21 Jun 2026 17:09:23 +0300 Subject: [PATCH 4/8] =?UTF-8?q?feat(epf-build,epf-dump):=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=BD=D0=B0=D1=8F=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D0=B0?= =?UTF-8?q?/=D1=80=D0=B0=D0=B7=D0=B1=D0=BE=D1=80=D0=BA=D0=B0=20EPF=C2=B7ER?= =?UTF-8?q?F=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20ibcmd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Если -V8Path указывает на ibcmd.exe — обработки/отчёты собираются и разбираются автономным сервером (offline, без запуска платформы), иначе как прежде через 1cv8 DESIGNER. - epf-build → ibcmd infobase config import --out= --db-path - epf-dump → ibcmd infobase config export --file= --db-path - stub-db-create: при ibcmd создаёт stub-базу ОДНИМ вызовом ibcmd infobase create --db-path --create-database [--import=cfg --apply --force] вместо трёх стартов 1cv8 (CREATEINFOBASE/Load/Update). --force обязателен: иначе apply уходит в интерактивный [y/n] и отменяется. Только файловые базы (серверные/-Format Plain под ibcmd → чистая ошибка). 1cv8-ветки без изменений. Версии: epf-build/epf-dump 1.1→1.2, stub-db-create 1.0→1.1. E2E: dump (.epf→XML), build без ref-типов, build СО ссылочными типами через auto-stub на ibcmd (валидность подтверждена обратной разборкой), 1cv8-регресс — всё зелёное; оба порта. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/epf-build/SKILL.md | 4 ++- .../skills/epf-build/scripts/epf-build.ps1 | 26 +++++++++++++++- .claude/skills/epf-build/scripts/epf-build.py | 22 ++++++++++++- .../epf-build/scripts/stub-db-create.ps1 | 20 +++++++++++- .../epf-build/scripts/stub-db-create.py | 24 +++++++++++++- .claude/skills/epf-dump/SKILL.md | 4 ++- .claude/skills/epf-dump/scripts/epf-dump.ps1 | 31 ++++++++++++++++++- .claude/skills/epf-dump/scripts/epf-dump.py | 25 ++++++++++++++- 8 files changed, 148 insertions(+), 8 deletions(-) diff --git a/.claude/skills/epf-build/SKILL.md b/.claude/skills/epf-build/SKILL.md index a7f13331..702c73ec 100644 --- a/.claude/skills/epf-build/SKILL.md +++ b/.claude/skills/epf-build/SKILL.md @@ -47,7 +47,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" <п | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -56,6 +56,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" <п | `-SourceFile <путь>` | да | Путь к корневому XML-файлу исходников | | `-OutputFile <путь>` | да | Путь к выходному EPF/ERF-файлу | +> Если `-V8Path` указывает на `ibcmd.exe` — сборка идёт через автономный сервер (offline, быстрее; **только файловые базы**; для обработок со ссылочными типами stub-база тоже создаётся через ibcmd). + > `*` — опционально. Если не указано — автоматически создаётся временная база со заглушками метаданных ## Примеры diff --git a/.claude/skills/epf-build/scripts/epf-build.ps1 b/.claude/skills/epf-build/scripts/epf-build.ps1 index 7a021132..c2b1ae79 100644 --- a/.claude/skills/epf-build/scripts/epf-build.ps1 +++ b/.claude/skills/epf-build/scripts/epf-build.ps1 @@ -1,4 +1,4 @@ -# epf-build v1.1 — Build external data processor or report (EPF/ERF) from XML sources +# epf-build v1.2 — Build external data processor or report (EPF/ERF) from XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -112,6 +112,13 @@ if (-not (Test-Path $V8Path)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } +if ($engine -eq "ibcmd" -and $InfoBaseServer -and $InfoBaseRef) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath or omit for stub)" -ForegroundColor Red + exit 1 +} + # --- Auto-create stub database if no connection specified --- $autoCreatedBase = $null if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { @@ -146,6 +153,23 @@ $tempDir = Join-Path $env:TEMP "epf_build_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch: build EPF/ERF via config import --out --- + $srcDir = Split-Path $SourceFile -Parent + $arguments = @("infobase", "config", "import", "$srcDir", "--out=$OutputFile", "--db-path=$InfoBasePath") + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "External data processor/report built successfully: $OutputFile" -ForegroundColor Green + } else { + Write-Host "Error building external data processor/report (code: $exitCode)" -ForegroundColor Red + } + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/epf-build/scripts/epf-build.py b/.claude/skills/epf-build/scripts/epf-build.py index 0447d32d..6ea090cb 100644 --- a/.claude/skills/epf-build/scripts/epf-build.py +++ b/.claude/skills/epf-build/scripts/epf-build.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# epf-build v1.1 — Build external data processor or report (EPF/ERF) from XML sources +# epf-build v1.2 — Build external data processor or report (EPF/ERF) from XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -84,6 +84,10 @@ def main(): # --- Resolve V8Path --- v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" + if engine == "ibcmd" and args.InfoBaseServer and args.InfoBaseRef: + print("Error: ibcmd supports file infobases only (use -InfoBasePath or omit for stub)", file=sys.stderr) + sys.exit(1) # --- Auto-create stub database if no connection specified --- auto_created_base = None @@ -117,6 +121,22 @@ def main(): os.makedirs(temp_dir, exist_ok=True) try: + if engine == "ibcmd": + # --- ibcmd branch: build EPF/ERF via config import --out --- + src_dir = os.path.dirname(os.path.abspath(args.SourceFile)) + arguments = ["infobase", "config", "import", src_dir, f"--out={args.OutputFile}", f"--db-path={args.InfoBasePath}"] + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print(f"External data processor/report built successfully: {args.OutputFile}") + else: + print(f"Error building external data processor/report (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Build arguments --- arguments = ["DESIGNER"] diff --git a/.claude/skills/epf-build/scripts/stub-db-create.ps1 b/.claude/skills/epf-build/scripts/stub-db-create.ps1 index dde1a7bf..3d63e816 100644 --- a/.claude/skills/epf-build/scripts/stub-db-create.ps1 +++ b/.claude/skills/epf-build/scripts/stub-db-create.ps1 @@ -1,4 +1,4 @@ -# stub-db-create v1.0 — Create temp 1C infobase with metadata stubs for EPF/ERF build +# stub-db-create v1.1 — Create temp 1C infobase with metadata stubs for EPF/ERF build # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -1252,6 +1252,24 @@ $propsXml $childObjLine } } +# --- 5a. Stub via ibcmd (one call: create [--import --apply]) --- +$stubEngine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } +if ($stubEngine -eq "ibcmd") { + Write-Host "Creating infobase (ibcmd): $TempBasePath" + $ibArgs = @("infobase", "create", "--db-path=$TempBasePath", "--create-database") + if ($hasRefTypes) { $ibArgs += "--import=$(Join-Path $TempBasePath 'cfg')", "--apply", "--force" } + $ibOut = & $V8Path @ibArgs 2>&1 + if ($LASTEXITCODE -ne 0) { + if ($ibOut) { Write-Host ($ibOut | Out-String) } + Write-Error "Failed to create stub infobase (code: $LASTEXITCODE)" + exit 1 + } + if ($hasRefTypes) { Remove-Item -Path (Join-Path $TempBasePath "cfg") -Recurse -Force -ErrorAction SilentlyContinue } + Write-Host "[OK] Stub database created: $TempBasePath" + Write-Host $TempBasePath + exit 0 +} + # --- 5. Create infobase --- Write-Host "Creating infobase: $TempBasePath" $createArgs = "CREATEINFOBASE File=`"$TempBasePath`" /DisableStartupDialogs" diff --git a/.claude/skills/epf-build/scripts/stub-db-create.py b/.claude/skills/epf-build/scripts/stub-db-create.py index 2f9882e0..9e94d993 100644 --- a/.claude/skills/epf-build/scripts/stub-db-create.py +++ b/.claude/skills/epf-build/scripts/stub-db-create.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# stub-db-create v1.0 — Create temp 1C infobase with metadata stubs for EPF/ERF build +# stub-db-create v1.1 — Create temp 1C infobase with metadata stubs for EPF/ERF build # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -1034,6 +1034,28 @@ def main(): if register_columns: print('WARNING: Register column categories (Dimension/Resource/Attribute) are guessed. Form field bindings may not survive round-trip through a real database.') + # Stub via ibcmd (one call: create [--import --apply]) + stub_engine = "ibcmd" if os.path.basename(args.V8Path).lower().startswith("ibcmd") else "1cv8" + if stub_engine == "ibcmd": + print(f'Creating infobase (ibcmd): {temp_base}') + ib_args = [args.V8Path, 'infobase', 'create', f'--db-path={temp_base}', '--create-database'] + if has_ref_types: + ib_args += [f'--import={os.path.join(temp_base, "cfg")}', '--apply', '--force'] + result = subprocess.run(ib_args, capture_output=True, encoding='utf-8', errors='replace') + if result.returncode != 0: + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + print(f'Failed to create stub infobase (code: {result.returncode})', file=sys.stderr) + sys.exit(1) + if has_ref_types: + import shutil + shutil.rmtree(os.path.join(temp_base, 'cfg'), ignore_errors=True) + print(f'[OK] Stub database created: {temp_base}') + print(temp_base) + sys.exit(0) + # Create infobase print(f'Creating infobase: {temp_base}') result = subprocess.run( diff --git a/.claude/skills/epf-dump/SKILL.md b/.claude/skills/epf-dump/SKILL.md index a76106e7..4c056517 100644 --- a/.claude/skills/epf-dump/SKILL.md +++ b/.claude/skills/epf-dump/SKILL.md @@ -46,7 +46,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" <па | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -57,6 +57,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" <па | `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` | > `*` — обязательно хотя бы одно подключение. Без базы скрипт завершится с ошибкой (dump в пустой базе безвозвратно теряет ссылочные типы) +> +> Если `-V8Path` указывает на `ibcmd.exe` — разборка идёт через автономный сервер (offline; **только файловые базы**; `-Format Plain` не поддерживается). ## Примеры diff --git a/.claude/skills/epf-dump/scripts/epf-dump.ps1 b/.claude/skills/epf-dump/scripts/epf-dump.ps1 index 631a3619..15d53ab6 100644 --- a/.claude/skills/epf-dump/scripts/epf-dump.ps1 +++ b/.claude/skills/epf-dump/scripts/epf-dump.ps1 @@ -1,4 +1,4 @@ -# epf-dump v1.1 — Dump external data processor or report (EPF/ERF) to XML sources +# epf-dump v1.2 — Dump external data processor or report (EPF/ERF) to XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -126,6 +126,19 @@ if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { exit 1 } +# --- Detect engine (ibcmd vs 1cv8) by exe name --- +$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } +if ($engine -eq "ibcmd") { + if (-not $InfoBasePath) { + Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red + exit 1 + } + if ($Format -eq "Plain") { + Write-Host "Error: ibcmd config export supports hierarchical format only (use -Format Hierarchical or 1cv8)" -ForegroundColor Red + exit 1 + } +} + # --- Validate input file --- if (-not (Test-Path $InputFile)) { Write-Host "Error: input file not found: $InputFile" -ForegroundColor Red @@ -142,6 +155,22 @@ $tempDir = Join-Path $env:TEMP "epf_dump_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch: dump EPF/ERF via config export --file --- + $arguments = @("infobase", "config", "export", "--file=$InputFile", "$OutputDir", "--db-path=$InfoBasePath") + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "External data processor/report dumped successfully to: $OutputDir" -ForegroundColor Green + } else { + Write-Host "Error dumping external data processor/report (code: $exitCode)" -ForegroundColor Red + } + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Build arguments --- $arguments = @("DESIGNER") diff --git a/.claude/skills/epf-dump/scripts/epf-dump.py b/.claude/skills/epf-dump/scripts/epf-dump.py index efc0e1a4..85238b4b 100644 --- a/.claude/skills/epf-dump/scripts/epf-dump.py +++ b/.claude/skills/epf-dump/scripts/epf-dump.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# epf-dump v1.1 — Dump external data processor or report (EPF/ERF) to XML sources +# epf-dump v1.2 — Dump external data processor or report (EPF/ERF) to XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -90,12 +90,20 @@ def main(): # --- Resolve V8Path --- v8path = resolve_v8path(args.V8Path) + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" # --- Validate database connection --- if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): print("Error: database connection required. Specify -InfoBasePath or -InfoBaseServer/-InfoBaseRef", file=sys.stderr) print("Dump in an empty database loses reference types (CatalogRef, DocumentRef, etc.) irreversibly.") sys.exit(1) + if engine == "ibcmd": + if not args.InfoBasePath: + print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr) + sys.exit(1) + if args.Format == "Plain": + print("Error: ibcmd config export supports hierarchical format only (use -Format Hierarchical or 1cv8)", file=sys.stderr) + sys.exit(1) # --- Validate input file --- if not os.path.isfile(args.InputFile): @@ -111,6 +119,21 @@ def main(): os.makedirs(temp_dir, exist_ok=True) try: + if engine == "ibcmd": + # --- ibcmd branch: dump EPF/ERF via config export --file --- + arguments = ["infobase", "config", "export", f"--file={args.InputFile}", args.OutputDir, f"--db-path={args.InfoBasePath}"] + print(f"Running: ibcmd {' '.join(arguments)}") + result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") + if result.returncode == 0: + print(f"External data processor/report dumped successfully to: {args.OutputDir}") + else: + print(f"Error dumping external data processor/report (code: {result.returncode})", file=sys.stderr) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + sys.exit(result.returncode) + # --- Build arguments --- arguments = ["DESIGNER"] From 8fb3e9421d7bcbc4cc2dd46cbfe66c3ac34b3a2b Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 21 Jun 2026 17:17:15 +0300 Subject: [PATCH 5/8] =?UTF-8?q?feat(db-dump-xml,db-load-xml):=20-AllExtens?= =?UTF-8?q?ions=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20ibcmd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Закрыт последний частичный пробел расширений: -AllExtensions под ibcmd больше не ошибка, а реальные подкоманды: - db-dump-xml -AllExtensions → ibcmd infobase config export all-extensions - db-load-xml -AllExtensions → ibcmd infobase config import all-extensions (+ цепочка config apply --force при -UpdateDB) 1cv8-ветки без изменений. Версии: db-dump-xml 1.3→1.4, db-load-xml 1.7→1.8. E2E: база с двумя расширениями → export all-extensions (Ext1/Ext2) → import all-extensions обратно, оба порта; 1cv8-регресс (-AllExtensions -Mode Full) цел. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 | 11 ++++------- .claude/skills/db-dump-xml/scripts/db-dump-xml.py | 9 ++++----- .claude/skills/db-load-xml/scripts/db-load-xml.ps1 | 8 +++----- .claude/skills/db-load-xml/scripts/db-load-xml.py | 7 +++---- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 index e47aa7b8..bbb0b935 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 @@ -1,4 +1,4 @@ -# db-dump-xml v1.3 — Dump 1C configuration to XML files +# db-dump-xml v1.4 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -179,14 +179,11 @@ try { exit 1 } if ($AllExtensions) { - Write-Host "Error: ibcmd config export does not support -AllExtensions (use -Extension or 1cv8)" -ForegroundColor Red - exit 1 - } - if ($Mode -eq "UpdateInfo") { + $arguments = @("infobase", "config", "export", "all-extensions", "$ConfigDir", "--db-path=$InfoBasePath") + } elseif ($Mode -eq "UpdateInfo") { Write-Host "Error: ibcmd config export does not support Mode UpdateInfo; use 1cv8" -ForegroundColor Red exit 1 - } - if ($Mode -eq "Partial") { + } elseif ($Mode -eq "Partial") { $objList = @($Objects -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) $arguments = @("infobase", "config", "export", "objects") + $objList $arguments += "--out=$ConfigDir", "--db-path=$InfoBasePath" diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py index 3436dea0..5729c9eb 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-dump-xml v1.3 — Dump 1C configuration to XML files +# db-dump-xml v1.4 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -125,12 +125,11 @@ def main(): print("Error: ibcmd config export supports hierarchical format only (use -Format Hierarchical or 1cv8)", file=sys.stderr) sys.exit(1) if args.AllExtensions: - print("Error: ibcmd config export does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) - sys.exit(1) - if args.Mode == "UpdateInfo": + arguments = ["infobase", "config", "export", "all-extensions", args.ConfigDir, f"--db-path={args.InfoBasePath}"] + elif args.Mode == "UpdateInfo": print("Error: ibcmd config export does not support Mode UpdateInfo; use 1cv8", file=sys.stderr) sys.exit(1) - if args.Mode == "Partial": + elif args.Mode == "Partial": obj_list = [o.strip() for o in args.Objects.split(",") if o.strip()] arguments = ["infobase", "config", "export", "objects"] + obj_list arguments += [f"--out={args.ConfigDir}", f"--db-path={args.InfoBasePath}"] diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 index 04907e15..e40ab11a 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 @@ -1,4 +1,4 @@ -# db-load-xml v1.7 — Load 1C configuration from XML files +# db-load-xml v1.8 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -188,10 +188,8 @@ try { exit 1 } if ($AllExtensions) { - Write-Host "Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)" -ForegroundColor Red - exit 1 - } - if ($Mode -eq "Partial" -or $Files -or $ListFile) { + $arguments = @("infobase", "config", "import", "all-extensions", "$ConfigDir", "--db-path=$InfoBasePath") + } elseif ($Mode -eq "Partial" -or $Files -or $ListFile) { # partial: import specific files (relative to ConfigDir) $fileList = @() if ($ListFile) { diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.py b/.claude/skills/db-load-xml/scripts/db-load-xml.py index 1ce4b15e..030c720b 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.py +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-load-xml v1.7 — Load 1C configuration from XML files +# db-load-xml v1.8 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -133,9 +133,8 @@ def main(): print("Error: ibcmd config import supports hierarchical format only (use -Format Hierarchical or 1cv8)", file=sys.stderr) sys.exit(1) if args.AllExtensions: - print("Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) - sys.exit(1) - if args.Mode == "Partial" or args.Files or args.ListFile: + arguments = ["infobase", "config", "import", "all-extensions", args.ConfigDir, f"--db-path={args.InfoBasePath}"] + elif args.Mode == "Partial" or args.Files or args.ListFile: # partial: import specific files (relative to ConfigDir) if args.ListFile: if not os.path.isfile(args.ListFile): From 5bd6ba30cd11f6e93e11bb475f033083e542d0c0 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 21 Jun 2026 19:01:03 +0300 Subject: [PATCH 6/8] =?UTF-8?q?fix(db,epf):=20=D0=B8=D0=B7=D0=BE=D0=BB?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20--data?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D0=BA=D0=B0=D0=B6=D0=B4=D1=83=D1=8E=20ibcmd-?= =?UTF-8?q?=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ibcmd без --data использует общий каталог автономного сервера в %LOCALAPPDATA%\standalone-server: он копит реестр/локи, и зависший процесс (например, ушедший в консольный интерактив при нехватке кред) держит его лок, блокируя ВСЕ последующие ibcmd-операции «Рабочий каталог заблокирован процессом N». Теперь каждая ibcmd-операция получает свой одноразовый --data= и удаляет его после: зависший/параллельный вызов лочит только свой каталог, не накапливается реестр («уже зарегистрирована»). База (--db-path) и чужой автономный сервер на дефолтном каталоге не затрагиваются. Реализация: ps1 — --data=$tempDir (создаётся до try, finally чистит на exit); py — свой ib_data через tempfile.mkdtemp + atexit-очистка (надёжно на любом sys.exit); stub-db-create — свой ib_data + явная очистка. Проверено: A/B через навык с живым холдером — операция с общим --data падает «заблокирован процессом N», навык (свой --data) проходит; очистка temp-каталогов подтверждена (оба порта); 1cv8-ветки не затронуты. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/db-create/scripts/db-create.ps1 | 3 ++- .claude/skills/db-create/scripts/db-create.py | 6 +++++- .claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 | 3 ++- .claude/skills/db-dump-cf/scripts/db-dump-cf.py | 6 +++++- .claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 | 3 ++- .claude/skills/db-dump-dt/scripts/db-dump-dt.py | 6 +++++- .claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 | 3 ++- .claude/skills/db-dump-xml/scripts/db-dump-xml.py | 6 +++++- .claude/skills/db-load-cf/scripts/db-load-cf.ps1 | 3 ++- .claude/skills/db-load-cf/scripts/db-load-cf.py | 6 +++++- .claude/skills/db-load-dt/scripts/db-load-dt.ps1 | 3 ++- .claude/skills/db-load-dt/scripts/db-load-dt.py | 6 +++++- .claude/skills/db-load-git/scripts/db-load-git.ps1 | 4 +++- .claude/skills/db-load-git/scripts/db-load-git.py | 7 ++++++- .claude/skills/db-load-xml/scripts/db-load-xml.ps1 | 4 +++- .claude/skills/db-load-xml/scripts/db-load-xml.py | 7 ++++++- .claude/skills/db-update/scripts/db-update.ps1 | 3 ++- .claude/skills/db-update/scripts/db-update.py | 6 +++++- .claude/skills/epf-build/scripts/epf-build.ps1 | 3 ++- .claude/skills/epf-build/scripts/epf-build.py | 6 +++++- .claude/skills/epf-build/scripts/stub-db-create.ps1 | 11 ++++++++--- .claude/skills/epf-build/scripts/stub-db-create.py | 6 +++++- .claude/skills/epf-dump/scripts/epf-dump.ps1 | 3 ++- .claude/skills/epf-dump/scripts/epf-dump.py | 6 +++++- 24 files changed, 94 insertions(+), 26 deletions(-) diff --git a/.claude/skills/db-create/scripts/db-create.ps1 b/.claude/skills/db-create/scripts/db-create.ps1 index 7078ab4f..9f360833 100644 --- a/.claude/skills/db-create/scripts/db-create.ps1 +++ b/.claude/skills/db-create/scripts/db-create.ps1 @@ -1,4 +1,4 @@ -# db-create v1.2 — Create 1C information base +# db-create v1.3 — Create 1C information base # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -144,6 +144,7 @@ try { $arguments += "--load=$UseTemplate", "--apply" } } + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-create/scripts/db-create.py b/.claude/skills/db-create/scripts/db-create.py index c2257157..a5c9566c 100644 --- a/.claude/skills/db-create/scripts/db-create.py +++ b/.claude/skills/db-create/scripts/db-create.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-create v1.2 — Create 1C information base +# db-create v1.3 — Create 1C information base # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -106,6 +107,9 @@ def main(): arguments.append(f"--restore={args.UseTemplate}") else: arguments.extend([f"--load={args.UseTemplate}", "--apply"]) + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 b/.claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 index f9e13e8d..78d90c9e 100644 --- a/.claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 +++ b/.claude/skills/db-dump-cf/scripts/db-dump-cf.ps1 @@ -1,4 +1,4 @@ -# db-dump-cf v1.2 — Dump 1C configuration to CF file +# db-dump-cf v1.3 — Dump 1C configuration to CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -152,6 +152,7 @@ try { $arguments = @("infobase", "config", "save", "--db-path=$InfoBasePath") if ($Extension) { $arguments += "--extension=$Extension" } $arguments += "$OutputFile" + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-dump-cf/scripts/db-dump-cf.py b/.claude/skills/db-dump-cf/scripts/db-dump-cf.py index 67ebc320..3ec4cff9 100644 --- a/.claude/skills/db-dump-cf/scripts/db-dump-cf.py +++ b/.claude/skills/db-dump-cf/scripts/db-dump-cf.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-dump-cf v1.2 — Dump 1C configuration to CF file +# db-dump-cf v1.3 — Dump 1C configuration to CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -109,6 +110,9 @@ def main(): if args.Extension: arguments.append(f"--extension={args.Extension}") arguments.append(args.OutputFile) + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 b/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 index 5f801a05..3655b512 100644 --- a/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 +++ b/.claude/skills/db-dump-dt/scripts/db-dump-dt.ps1 @@ -1,4 +1,4 @@ -# db-dump-dt v1.2 — Dump 1C information base to DT file +# db-dump-dt v1.3 — Dump 1C information base to DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -134,6 +134,7 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "$OutputFile" + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-dump-dt/scripts/db-dump-dt.py b/.claude/skills/db-dump-dt/scripts/db-dump-dt.py index 15cd0e59..29aafef7 100644 --- a/.claude/skills/db-dump-dt/scripts/db-dump-dt.py +++ b/.claude/skills/db-dump-dt/scripts/db-dump-dt.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-dump-dt v1.2 — Dump 1C information base to DT file +# db-dump-dt v1.3 — Dump 1C information base to DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -106,6 +107,9 @@ def main(): if args.Password: arguments.append(f"--password={args.Password}") arguments.append(args.OutputFile) + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 index bbb0b935..8527bb2b 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 @@ -1,4 +1,4 @@ -# db-dump-xml v1.4 — Dump 1C configuration to XML files +# db-dump-xml v1.5 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -193,6 +193,7 @@ try { if ($Extension) { $arguments += "--extension=$Extension" } $arguments += "$ConfigDir" } + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py index 5729c9eb..ce8a228d 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-dump-xml v1.4 — Dump 1C configuration to XML files +# db-dump-xml v1.5 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -140,6 +141,9 @@ def main(): if args.Extension: arguments.append(f"--extension={args.Extension}") arguments.append(args.ConfigDir) + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/db-load-cf/scripts/db-load-cf.ps1 b/.claude/skills/db-load-cf/scripts/db-load-cf.ps1 index 08398684..1fa70603 100644 --- a/.claude/skills/db-load-cf/scripts/db-load-cf.ps1 +++ b/.claude/skills/db-load-cf/scripts/db-load-cf.ps1 @@ -1,4 +1,4 @@ -# db-load-cf v1.2 — Load 1C configuration from CF file +# db-load-cf v1.3 — Load 1C configuration from CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -152,6 +152,7 @@ try { $arguments = @("infobase", "config", "load", "--db-path=$InfoBasePath") if ($Extension) { $arguments += "--extension=$Extension" } $arguments += "$InputFile" + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-load-cf/scripts/db-load-cf.py b/.claude/skills/db-load-cf/scripts/db-load-cf.py index 003d26b4..c08cdd20 100644 --- a/.claude/skills/db-load-cf/scripts/db-load-cf.py +++ b/.claude/skills/db-load-cf/scripts/db-load-cf.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-load-cf v1.2 — Load 1C configuration from CF file +# db-load-cf v1.3 — Load 1C configuration from CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -109,6 +110,9 @@ def main(): if args.Extension: arguments.append(f"--extension={args.Extension}") arguments.append(args.InputFile) + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/db-load-dt/scripts/db-load-dt.ps1 b/.claude/skills/db-load-dt/scripts/db-load-dt.ps1 index 6f39b878..b2a8b01f 100644 --- a/.claude/skills/db-load-dt/scripts/db-load-dt.ps1 +++ b/.claude/skills/db-load-dt/scripts/db-load-dt.ps1 @@ -1,4 +1,4 @@ -# db-load-dt v1.2 — Load 1C information base from DT file +# db-load-dt v1.3 — Load 1C information base from DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -148,6 +148,7 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "$InputFile" + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-load-dt/scripts/db-load-dt.py b/.claude/skills/db-load-dt/scripts/db-load-dt.py index 60e5f2fa..bb08de35 100644 --- a/.claude/skills/db-load-dt/scripts/db-load-dt.py +++ b/.claude/skills/db-load-dt/scripts/db-load-dt.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-load-dt v1.2 — Load 1C information base from DT file +# db-load-dt v1.3 — Load 1C information base from DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -110,6 +111,9 @@ def main(): if args.Password: arguments.append(f"--password={args.Password}") arguments.append(args.InputFile) + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/db-load-git/scripts/db-load-git.ps1 b/.claude/skills/db-load-git/scripts/db-load-git.ps1 index 5650c1d1..7fca7fe7 100644 --- a/.claude/skills/db-load-git/scripts/db-load-git.ps1 +++ b/.claude/skills/db-load-git/scripts/db-load-git.ps1 @@ -1,4 +1,4 @@ -# db-load-git v1.6 — Load Git changes into 1C database +# db-load-git v1.7 — Load Git changes into 1C database # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -339,6 +339,7 @@ try { $arguments = @("infobase", "config", "import", "files") + $configFiles $arguments += "--base-dir=$ConfigDir", "--db-path=$InfoBasePath" if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE @@ -351,6 +352,7 @@ try { if ($output) { Write-Host ($output | Out-String) } if ($UpdateDB) { $applyArgs = @("infobase", "config", "apply", "--db-path=$InfoBasePath", "--force") + $applyArgs += "--data=$tempDir" Write-Host "Running: ibcmd $($applyArgs -join ' ')" $applyOut = & $V8Path @applyArgs 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-load-git/scripts/db-load-git.py b/.claude/skills/db-load-git/scripts/db-load-git.py index dcf22dfb..afa82c9f 100644 --- a/.claude/skills/db-load-git/scripts/db-load-git.py +++ b/.claude/skills/db-load-git/scripts/db-load-git.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-load-git v1.6 — Load Git changes into 1C database +# db-load-git v1.7 — Load Git changes into 1C database # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -266,6 +267,9 @@ def main(): arguments += [f"--base-dir={args.ConfigDir}", f"--db-path={args.InfoBasePath}"] if args.Extension: arguments.append(f"--extension={args.Extension}") + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode != 0: @@ -281,6 +285,7 @@ def main(): exit_code = 0 if args.UpdateDB: apply_args = ["infobase", "config", "apply", f"--db-path={args.InfoBasePath}", "--force"] + apply_args.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(apply_args)}") ar = subprocess.run([v8path] + apply_args, capture_output=True, encoding="utf-8", errors="replace") exit_code = ar.returncode diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 index e40ab11a..3fa152fc 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 @@ -1,4 +1,4 @@ -# db-load-xml v1.8 — Load 1C configuration from XML files +# db-load-xml v1.9 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -213,6 +213,7 @@ try { if ($Extension) { $arguments += "--extension=$Extension" } $arguments += "$ConfigDir" } + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE @@ -226,6 +227,7 @@ try { if ($UpdateDB) { $applyArgs = @("infobase", "config", "apply", "--db-path=$InfoBasePath", "--force") + $applyArgs += "--data=$tempDir" Write-Host "Running: ibcmd $($applyArgs -join ' ')" $applyOut = & $V8Path @applyArgs 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.py b/.claude/skills/db-load-xml/scripts/db-load-xml.py index 030c720b..7a40334f 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.py +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-load-xml v1.8 — Load 1C configuration from XML files +# db-load-xml v1.9 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -158,6 +159,9 @@ def main(): if args.Extension: arguments.append(f"--extension={args.Extension}") arguments.append(args.ConfigDir) + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode != 0: @@ -173,6 +177,7 @@ def main(): exit_code = 0 if args.UpdateDB: apply_args = ["infobase", "config", "apply", f"--db-path={args.InfoBasePath}", "--force"] + apply_args.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(apply_args)}") ar = subprocess.run([v8path] + apply_args, capture_output=True, encoding="utf-8", errors="replace") exit_code = ar.returncode diff --git a/.claude/skills/db-update/scripts/db-update.ps1 b/.claude/skills/db-update/scripts/db-update.ps1 index f95d9ced..89aecd5b 100644 --- a/.claude/skills/db-update/scripts/db-update.ps1 +++ b/.claude/skills/db-update/scripts/db-update.ps1 @@ -1,4 +1,4 @@ -# db-update v1.2 — Update 1C database configuration +# db-update v1.3 — Update 1C database configuration # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -160,6 +160,7 @@ try { if ($Dynamic -eq "+") { $arguments += "--dynamic=auto" } elseif ($Dynamic -eq "-") { $arguments += "--dynamic=disable" } if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-update/scripts/db-update.py b/.claude/skills/db-update/scripts/db-update.py index 93918b31..2d98c862 100644 --- a/.claude/skills/db-update/scripts/db-update.py +++ b/.claude/skills/db-update/scripts/db-update.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# db-update v1.2 — Update 1C database configuration +# db-update v1.3 — Update 1C database configuration # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -110,6 +111,9 @@ def main(): arguments.append("--dynamic=disable") if args.Extension: arguments.append(f"--extension={args.Extension}") + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/epf-build/scripts/epf-build.ps1 b/.claude/skills/epf-build/scripts/epf-build.ps1 index c2b1ae79..31ac7e25 100644 --- a/.claude/skills/epf-build/scripts/epf-build.ps1 +++ b/.claude/skills/epf-build/scripts/epf-build.ps1 @@ -1,4 +1,4 @@ -# epf-build v1.2 — Build external data processor or report (EPF/ERF) from XML sources +# epf-build v1.3 — Build external data processor or report (EPF/ERF) from XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -157,6 +157,7 @@ try { # --- ibcmd branch: build EPF/ERF via config import --out --- $srcDir = Split-Path $SourceFile -Parent $arguments = @("infobase", "config", "import", "$srcDir", "--out=$OutputFile", "--db-path=$InfoBasePath") + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/epf-build/scripts/epf-build.py b/.claude/skills/epf-build/scripts/epf-build.py index 6ea090cb..04abf2cb 100644 --- a/.claude/skills/epf-build/scripts/epf-build.py +++ b/.claude/skills/epf-build/scripts/epf-build.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# epf-build v1.2 — Build external data processor or report (EPF/ERF) from XML sources +# epf-build v1.3 — Build external data processor or report (EPF/ERF) from XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -125,6 +126,9 @@ def main(): # --- ibcmd branch: build EPF/ERF via config import --out --- src_dir = os.path.dirname(os.path.abspath(args.SourceFile)) arguments = ["infobase", "config", "import", src_dir, f"--out={args.OutputFile}", f"--db-path={args.InfoBasePath}"] + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/epf-build/scripts/stub-db-create.ps1 b/.claude/skills/epf-build/scripts/stub-db-create.ps1 index 3d63e816..7396c60c 100644 --- a/.claude/skills/epf-build/scripts/stub-db-create.ps1 +++ b/.claude/skills/epf-build/scripts/stub-db-create.ps1 @@ -1,4 +1,4 @@ -# stub-db-create v1.1 — Create temp 1C infobase with metadata stubs for EPF/ERF build +# stub-db-create v1.2 — Create temp 1C infobase with metadata stubs for EPF/ERF build # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -1256,12 +1256,17 @@ $propsXml $childObjLine $stubEngine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } if ($stubEngine -eq "ibcmd") { Write-Host "Creating infobase (ibcmd): $TempBasePath" + $ibData = Join-Path $env:TEMP "stub_data_$(Get-Random)" + New-Item -ItemType Directory -Path $ibData -Force | Out-Null $ibArgs = @("infobase", "create", "--db-path=$TempBasePath", "--create-database") if ($hasRefTypes) { $ibArgs += "--import=$(Join-Path $TempBasePath 'cfg')", "--apply", "--force" } + $ibArgs += "--data=$ibData" $ibOut = & $V8Path @ibArgs 2>&1 - if ($LASTEXITCODE -ne 0) { + $ibRc = $LASTEXITCODE + Remove-Item -Path $ibData -Recurse -Force -ErrorAction SilentlyContinue + if ($ibRc -ne 0) { if ($ibOut) { Write-Host ($ibOut | Out-String) } - Write-Error "Failed to create stub infobase (code: $LASTEXITCODE)" + Write-Error "Failed to create stub infobase (code: $ibRc)" exit 1 } if ($hasRefTypes) { Remove-Item -Path (Join-Path $TempBasePath "cfg") -Recurse -Force -ErrorAction SilentlyContinue } diff --git a/.claude/skills/epf-build/scripts/stub-db-create.py b/.claude/skills/epf-build/scripts/stub-db-create.py index 9e94d993..21868f1f 100644 --- a/.claude/skills/epf-build/scripts/stub-db-create.py +++ b/.claude/skills/epf-build/scripts/stub-db-create.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# stub-db-create v1.1 — Create temp 1C infobase with metadata stubs for EPF/ERF build +# stub-db-create v1.2 — Create temp 1C infobase with metadata stubs for EPF/ERF build # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -1037,11 +1037,15 @@ def main(): # Stub via ibcmd (one call: create [--import --apply]) stub_engine = "ibcmd" if os.path.basename(args.V8Path).lower().startswith("ibcmd") else "1cv8" if stub_engine == "ibcmd": + import shutil print(f'Creating infobase (ibcmd): {temp_base}') + ib_data = tempfile.mkdtemp(prefix="stub_data_") ib_args = [args.V8Path, 'infobase', 'create', f'--db-path={temp_base}', '--create-database'] if has_ref_types: ib_args += [f'--import={os.path.join(temp_base, "cfg")}', '--apply', '--force'] + ib_args.append(f'--data={ib_data}') result = subprocess.run(ib_args, capture_output=True, encoding='utf-8', errors='replace') + shutil.rmtree(ib_data, ignore_errors=True) if result.returncode != 0: if result.stdout: print(result.stdout) diff --git a/.claude/skills/epf-dump/scripts/epf-dump.ps1 b/.claude/skills/epf-dump/scripts/epf-dump.ps1 index 15d53ab6..fb01a70b 100644 --- a/.claude/skills/epf-dump/scripts/epf-dump.ps1 +++ b/.claude/skills/epf-dump/scripts/epf-dump.ps1 @@ -1,4 +1,4 @@ -# epf-dump v1.2 — Dump external data processor or report (EPF/ERF) to XML sources +# epf-dump v1.3 — Dump external data processor or report (EPF/ERF) to XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -158,6 +158,7 @@ try { if ($engine -eq "ibcmd") { # --- ibcmd branch: dump EPF/ERF via config export --file --- $arguments = @("infobase", "config", "export", "--file=$InputFile", "$OutputDir", "--db-path=$InfoBasePath") + $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/epf-dump/scripts/epf-dump.py b/.claude/skills/epf-dump/scripts/epf-dump.py index 85238b4b..31c0140a 100644 --- a/.claude/skills/epf-dump/scripts/epf-dump.py +++ b/.claude/skills/epf-dump/scripts/epf-dump.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# epf-dump v1.2 — Dump external data processor or report (EPF/ERF) to XML sources +# epf-dump v1.3 — Dump external data processor or report (EPF/ERF) to XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse +import atexit import glob import json import os @@ -122,6 +123,9 @@ def main(): if engine == "ibcmd": # --- ibcmd branch: dump EPF/ERF via config export --file --- arguments = ["infobase", "config", "export", f"--file={args.InputFile}", args.OutputDir, f"--db-path={args.InfoBasePath}"] + ib_data = tempfile.mkdtemp(prefix="ibcmd_data_") + atexit.register(shutil.rmtree, ib_data, ignore_errors=True) + arguments.append(f"--data={ib_data}") print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: From 89496f535d066f92c419d98595679a8131ea62fe Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Mon, 22 Jun 2026 13:07:28 +0300 Subject: [PATCH 7/8] =?UTF-8?q?docs(db,epf,erf):=20ibcmd=20=E2=80=94=20?= =?UTF-8?q?=D0=BE=D0=BF=D1=82-=D0=B8=D0=BD,=20=D1=83=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B4=D1=83=D0=B1=D0=BB=D1=8C=20=D0=B0=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=BB=D0=B0=D1=82=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit По итогам обсуждения: ibcmd оставляем на усмотрение опытных пользователей, не светим в основном потоке инструкций. - Убраны развёрнутые врезки «Если -V8Path указывает на ibcmd.exe — …» во всех SKILL.md. Упоминание остаётся только в описании параметра -V8Path (1cv8.exe / ibcmd.exe); ограничения и так enforced скриптом (чистая ошибка на серверной базе / -Format Plain / -AllExtensions). - Заменена неактуальная и дублирующая строка автоопределения платформы («Get-ChildItem … Sort -Desc | Select -First 1») — скрипт сам резолвит платформу (реестр → числовая сортировка → Program Files [+ x86]), модели не нужно дублировать ручной поиск. Только SKILL.md, скрипты и версии не затронуты. EOL/BOM сохранён. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/db-create/SKILL.md | 4 +--- .claude/skills/db-dump-cf/SKILL.md | 4 +--- .claude/skills/db-dump-dt/SKILL.md | 4 +--- .claude/skills/db-dump-xml/SKILL.md | 4 +--- .claude/skills/db-load-cf/SKILL.md | 4 +--- .claude/skills/db-load-dt/SKILL.md | 4 +--- .claude/skills/db-load-git/SKILL.md | 4 +--- .claude/skills/db-load-xml/SKILL.md | 4 +--- .claude/skills/db-run/SKILL.md | 2 +- .claude/skills/db-update/SKILL.md | 4 +--- .claude/skills/epf-build/SKILL.md | 4 +--- .claude/skills/epf-dump/SKILL.md | 4 +--- .claude/skills/erf-build/SKILL.md | 2 +- .claude/skills/erf-dump/SKILL.md | 2 +- 14 files changed, 14 insertions(+), 36 deletions(-) diff --git a/.claude/skills/db-create/SKILL.md b/.claude/skills/db-create/SKILL.md index 1667d9fd..21cfda61 100644 --- a/.claude/skills/db-create/SKILL.md +++ b/.claude/skills/db-create/SKILL.md @@ -25,7 +25,7 @@ allowed-tools: ## Параметры подключения Прочитай `.v8-project.json` из корня проекта для `v8path` (путь к платформе). -Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). После создания базы предложи зарегистрировать через `/db-list add`. ## Команда @@ -47,8 +47,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" <п | `-ListName <имя>` | нет | Имя базы в списке | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ## После создания diff --git a/.claude/skills/db-dump-cf/SKILL.md b/.claude/skills/db-dump-cf/SKILL.md index 60f853fe..faf43e76 100644 --- a/.claude/skills/db-dump-cf/SKILL.md +++ b/.claude/skills/db-dump-cf/SKILL.md @@ -28,7 +28,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. @@ -53,8 +53,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" <п | `-AllExtensions` | нет | Выгрузить все расширения | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ## Примеры diff --git a/.claude/skills/db-dump-dt/SKILL.md b/.claude/skills/db-dump-dt/SKILL.md index 76cdd197..3bb393ad 100644 --- a/.claude/skills/db-dump-dt/SKILL.md +++ b/.claude/skills/db-dump-dt/SKILL.md @@ -31,7 +31,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. @@ -54,8 +54,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" <п | `-OutputFile <путь>` | да | Путь к выходному DT-файлу | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — выгрузка идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ## Примеры diff --git a/.claude/skills/db-dump-xml/SKILL.md b/.claude/skills/db-dump-xml/SKILL.md index 3199f5fa..69e3ba04 100644 --- a/.claude/skills/db-dump-xml/SKILL.md +++ b/.claude/skills/db-dump-xml/SKILL.md @@ -29,7 +29,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. Если в записи базы указан `configSrc` — используй как каталог выгрузки по умолчанию. @@ -58,8 +58,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" < | `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ### Режимы выгрузки diff --git a/.claude/skills/db-load-cf/SKILL.md b/.claude/skills/db-load-cf/SKILL.md index 53d056e2..e989979c 100644 --- a/.claude/skills/db-load-cf/SKILL.md +++ b/.claude/skills/db-load-cf/SKILL.md @@ -29,7 +29,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. @@ -54,8 +54,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" <п | `-AllExtensions` | нет | Загрузить все расширения из архива | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ## После выполнения diff --git a/.claude/skills/db-load-dt/SKILL.md b/.claude/skills/db-load-dt/SKILL.md index d08ed2ec..9cd07565 100644 --- a/.claude/skills/db-load-dt/SKILL.md +++ b/.claude/skills/db-load-dt/SKILL.md @@ -45,7 +45,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. @@ -70,8 +70,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" <п | `-UnlockCode <код>` | нет | Код разблокировки (`/UC`), если заблокировано начало сеансов | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — загрузка идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). Базу создаст при отсутствии. ## После выполнения diff --git a/.claude/skills/db-load-git/SKILL.md b/.claude/skills/db-load-git/SKILL.md index 11a544c9..2915f308 100644 --- a/.claude/skills/db-load-git/SKILL.md +++ b/.claude/skills/db-load-git/SKILL.md @@ -30,7 +30,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. Если в записи базы указан `configSrc` — используй как каталог конфигурации. @@ -61,8 +61,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" < | `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — загрузка идёт через автономный сервер (`config import files`); поддерживаются **только файловые базы** (`-InfoBasePath`). ## После выполнения diff --git a/.claude/skills/db-load-xml/SKILL.md b/.claude/skills/db-load-xml/SKILL.md index ef054f2c..3cfb283c 100644 --- a/.claude/skills/db-load-xml/SKILL.md +++ b/.claude/skills/db-load-xml/SKILL.md @@ -30,7 +30,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. Если в записи базы указан `configSrc` — используй как каталог загрузки по умолчанию. @@ -61,8 +61,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" < | `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ### Режимы загрузки diff --git a/.claude/skills/db-run/SKILL.md b/.claude/skills/db-run/SKILL.md index c62ce4be..2c0ac7f3 100644 --- a/.claude/skills/db-run/SKILL.md +++ b/.claude/skills/db-run/SKILL.md @@ -29,7 +29,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. diff --git a/.claude/skills/db-update/SKILL.md b/.claude/skills/db-update/SKILL.md index 4a874ef7..fc788e1b 100644 --- a/.claude/skills/db-update/SKILL.md +++ b/.claude/skills/db-update/SKILL.md @@ -28,7 +28,7 @@ allowed-tools: 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` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если файла нет — предложи `/db-list add`. Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. @@ -55,8 +55,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" <п | `-WarningsAsErrors` | нет | Предупреждения считать ошибками | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` -> -> Если `-V8Path` указывает на `ibcmd.exe` — операция идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). ### Фоновое обновление (серверная база) diff --git a/.claude/skills/epf-build/SKILL.md b/.claude/skills/epf-build/SKILL.md index 702c73ec..de59cc49 100644 --- a/.claude/skills/epf-build/SKILL.md +++ b/.claude/skills/epf-build/SKILL.md @@ -34,7 +34,7 @@ allowed-tools: 5. Если ветка не совпала — используй `default` 6. Если `.v8-project.json` нет или база не найдена — не указывай параметры подключения: скрипт автоматически создаст временную базу. Для EPF со ссылочными типами (CatalogRef, DocumentRef и т.д.) генерируются заглушки метаданных. Временная база удаляется после сборки. -Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. ## Команда @@ -56,8 +56,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" <п | `-SourceFile <путь>` | да | Путь к корневому XML-файлу исходников | | `-OutputFile <путь>` | да | Путь к выходному EPF/ERF-файлу | -> Если `-V8Path` указывает на `ibcmd.exe` — сборка идёт через автономный сервер (offline, быстрее; **только файловые базы**; для обработок со ссылочными типами stub-база тоже создаётся через ibcmd). - > `*` — опционально. Если не указано — автоматически создаётся временная база со заглушками метаданных ## Примеры diff --git a/.claude/skills/epf-dump/SKILL.md b/.claude/skills/epf-dump/SKILL.md index 4c056517..b6057563 100644 --- a/.claude/skills/epf-dump/SKILL.md +++ b/.claude/skills/epf-dump/SKILL.md @@ -33,7 +33,7 @@ allowed-tools: 5. Если ветка не совпала — используй `default` 6. Если `.v8-project.json` нет или база не найдена — **сообщи пользователю об ошибке**. Для dump база обязательна: в пустой базе ссылочные типы (CatalogRef, DocumentRef и т.д.) безвозвратно сбрасываются в строки. Предложи указать базу или зарегистрировать через `/db-list add`. -Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. ## Команда @@ -57,8 +57,6 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" <па | `-Format <формат>` | нет | `Hierarchical` (по умолч.) / `Plain` | > `*` — обязательно хотя бы одно подключение. Без базы скрипт завершится с ошибкой (dump в пустой базе безвозвратно теряет ссылочные типы) -> -> Если `-V8Path` указывает на `ibcmd.exe` — разборка идёт через автономный сервер (offline; **только файловые базы**; `-Format Plain` не поддерживается). ## Примеры diff --git a/.claude/skills/erf-build/SKILL.md b/.claude/skills/erf-build/SKILL.md index c87e85ba..860505b1 100644 --- a/.claude/skills/erf-build/SKILL.md +++ b/.claude/skills/erf-build/SKILL.md @@ -34,7 +34,7 @@ allowed-tools: 5. Если ветка не совпала — используй `default` 6. Если `.v8-project.json` нет или база не найдена — не указывай параметры подключения: скрипт автоматически создаст временную базу. Для ERF со ссылочными типами (CatalogRef, DocumentRef и т.д.) генерируются заглушки метаданных. Временная база удаляется после сборки. -Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. ## Команда diff --git a/.claude/skills/erf-dump/SKILL.md b/.claude/skills/erf-dump/SKILL.md index 3a05af7c..d79a66b7 100644 --- a/.claude/skills/erf-dump/SKILL.md +++ b/.claude/skills/erf-dump/SKILL.md @@ -33,7 +33,7 @@ allowed-tools: 5. Если ветка не совпала — используй `default` 6. Если `.v8-project.json` нет или база не найдена — **сообщи пользователю об ошибке**. Для dump база обязательна: в пустой базе ссылочные типы (CatalogRef, DocumentRef и т.д.) безвозвратно сбрасываются в строки. Предложи указать базу или зарегистрировать через `/db-list add`. -Если `v8path` не задан — автоопределение: `Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" | Sort -Desc | Select -First 1` +Если `v8path` не задан — скрипт сам попытается определить платформу (`.v8-project.json` → Program Files). Если использованная база не зарегистрирована — после выполнения предложи добавить через `/db-list add`. ## Команда From ceacaa3509ee252d80525018af0d3fe26668f44f Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Mon, 22 Jun 2026 16:04:01 +0300 Subject: [PATCH 8/8] =?UTF-8?q?test(skills):=20=D0=B4=D0=B2=D0=B8=D0=B6?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2=D0=B0=D1=8F=20=D0=BC=D0=B0=D1=82=D1=80=D0=B8?= =?UTF-8?q?=D1=86=D0=B0=201cv8/ibcmd=20=D0=B2=20=D0=B8=D0=BD=D1=82=D0=B5?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Раннер: контекст платформы дорезолвит ibcmd.exe рядом с 1cv8.exe; тест объявляет `engines: ['1cv8','ibcmd']` → одни и те же шаги прогоняются на каждом движке ({v8path} подставляется в нужный exe), результаты помечаются суффиксом [1cv8]/[ibcmd]. ibcmd-проход авто-skip, если ibcmd.exe нет. Дефолт engines=['1cv8'] — прочие тесты не меняются. Новые типы шагов: editFile (подстановочная замена) и assertContains (проверка подстроки) — для round-trip проверок. platform-config и platform-epf переведены в матрицу. Новый platform-partial: частичная выгрузка/загрузка объекта с round-trip маркера на обоих движках. README: раздел про интеграционные тесты, матрицу и типы шагов. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/skills/README.md | 38 +++++++- .../integration/platform-config.test.mjs | 3 + .../skills/integration/platform-epf.test.mjs | 3 + .../integration/platform-partial.test.mjs | 86 +++++++++++++++++++ tests/skills/runner.mjs | 81 ++++++++++++++--- 5 files changed, 199 insertions(+), 12 deletions(-) create mode 100644 tests/skills/integration/platform-partial.test.mjs diff --git a/tests/skills/README.md b/tests/skills/README.md index f01106cf..dc58b1f4 100644 --- a/tests/skills/README.md +++ b/tests/skills/README.md @@ -31,6 +31,41 @@ node tests/skills/verify-snapshots.mjs --help # полный Перепрогоняет навык из DSL кейса и грузит результат в 1С — отлавливает случаи, когда снапшоты обновили, но платформа уже не принимает выход. +## Интеграционные тесты + +Помимо snapshot-кейсов есть многошаговые сценарии в `integration/<имя>.test.mjs` — цепочка навыков (init → compile → build → validate…), проверяющая что навыки работают вместе. Запуск: + +```bash +node tests/skills/runner.mjs integration # все интеграционные +node tests/skills/runner.mjs integration/platform-partial # один сценарий +``` + +Тест-модуль экспортирует `name`, `setup`, `steps` и опционально: + +| Экспорт | Описание | +|---|---| +| `requiresPlatform` | `true` — нужен 1С (резолвится из `.v8-project.json`). Без платформы тест `○ skipped` | +| `engines` | Массив движков для **матрицы**: по умолчанию `['1cv8']`. `['1cv8','ibcmd']` — те же шаги прогоняются на обоих движках | + +### Движковая матрица (1cv8 / ibcmd) + +Навыки `db-*`/`epf-*` выбирают движок по имени exe в `-V8Path` (опт-ин: `ibcmd.exe` → ibcmd, иначе DESIGNER). Тест с `engines: ['1cv8','ibcmd']` прогоняется по разу на каждый движок: на ibcmd-проходе плейсхолдер `{v8path}` подставляется в `ibcmd.exe`, на 1cv8 — в каталог `bin` (авто-резолв `1cv8.exe`). Результаты помечаются суффиксом id: `… [1cv8]` / `… [ibcmd]`. + +ibcmd-проход автоматически `○ skipped`, если рядом с `1cv8.exe` нет `ibcmd.exe`. Шаги тестов при этом **не меняются** — добавляется одна строка `export const engines`. Так контракт «операция держится на обоих движках» кодируется без дублирования сценария. + +### Типы шагов + +Шаг — это запуск навыка (`script` + `args` + опц. `input`/`validate`) либо один из вспомогательных: + +| Поле шага | Действие | +|---|---| +| `script` + `args` | Запустить навык. `args` поддерживают плейсхолдеры `{workDir}`, `{inputFile}`, `{v8path}` и др. | +| `input` | JSON, передаётся навыку через temp-файл (`{inputFile}`) | +| `writeFile` + `content` | Записать файл (путь — плейсхолдеры) | +| `editFile` + `replace` + `with` | Подстановочная замена в файле (напр. вставить маркер). Падает, если паттерн не найден | +| `assertContains` + `expect` | Упасть, если файл не содержит подстроку (проверка round-trip) | +| `validate` | Доп. валидация навыком после шага (только с `--with-validation`) | + ## Что делать при падении 1. Смотри **case id** в выводе — это путь к файлу кейса (можно перезапустить: `node runner.mjs `) @@ -221,10 +256,11 @@ node tests/skills/runner.mjs cases/meta-compile/enum --update-snapshots # од ``` tests/skills/ - runner.mjs # тест-раннер (snapshot-сравнение) + runner.mjs # тест-раннер (snapshot-сравнение + интеграционные) verify-snapshots.mjs # платформенная верификация снапшотов README.md # этот файл .cache/ # кэш фикстур (в .gitignore) + integration/ # многошаговые сценарии (*.test.mjs), в т.ч. движковая матрица 1cv8/ibcmd cases/ <навык>/ _skill.json # конфиг навыка diff --git a/tests/skills/integration/platform-config.test.mjs b/tests/skills/integration/platform-config.test.mjs index 599d3525..71e717d2 100644 --- a/tests/skills/integration/platform-config.test.mjs +++ b/tests/skills/integration/platform-config.test.mjs @@ -5,6 +5,9 @@ export const name = 'Загрузка конфигурации в платформу 1С'; export const setup = 'none'; export const requiresPlatform = true; +// Engine matrix: same load path must hold on DESIGNER (1cv8) and ibcmd. +// The ibcmd pass is skipped automatically when ibcmd.exe is not present. +export const engines = ['1cv8', 'ibcmd']; export const steps = [ // ── 1. Build minimal config ── diff --git a/tests/skills/integration/platform-epf.test.mjs b/tests/skills/integration/platform-epf.test.mjs index 626f9afc..c2ffc4b9 100644 --- a/tests/skills/integration/platform-epf.test.mjs +++ b/tests/skills/integration/platform-epf.test.mjs @@ -5,6 +5,9 @@ export const name = 'Сборка и разборка внешней обработки (roundtrip)'; export const setup = 'none'; export const requiresPlatform = true; +// Engine matrix: same roundtrip must hold on DESIGNER (1cv8) and ibcmd. +// The ibcmd pass is skipped automatically when ibcmd.exe is not present. +export const engines = ['1cv8', 'ibcmd']; export const steps = [ // ── 1. Create EPF ── diff --git a/tests/skills/integration/platform-partial.test.mjs b/tests/skills/integration/platform-partial.test.mjs new file mode 100644 index 00000000..d8a850db --- /dev/null +++ b/tests/skills/integration/platform-partial.test.mjs @@ -0,0 +1,86 @@ +// platform-partial.test.mjs — partial dump/load round-trip with marker survival +// Requires: 1C platform (1cv8.exe) via .v8-project.json +// Exercises partial config import (Mode Partial -Files) and partial export +// (Mode Partial -Objects) on BOTH engines: DESIGNER (1cv8) and ibcmd. Proves a +// partially-loaded change actually propagates by round-tripping a marker +// (ibtestMARK). Mirrors the proven debug/ibtest/lifecycle.sh partial flow. + +export const name = 'Частичная выгрузка/загрузка объекта (round-trip маркера)'; +export const setup = 'none'; +export const requiresPlatform = true; +// Engine matrix: partial round-trip must hold on DESIGNER (1cv8) and ibcmd. +export const engines = ['1cv8', 'ibcmd']; + +export const steps = [ + // ── 1. Build minimal config ── + { + name: 'cf-init: пустая конфигурация', + script: 'cf-init/scripts/cf-init', + args: { '-Name': 'ИбcmdТест', '-OutputDir': '{workDir}/config' }, + }, + { + name: 'meta-compile: Справочник Товары', + script: 'meta-compile/scripts/meta-compile', + input: { type: 'Catalog', name: 'Товары', codeLength: 9, descriptionLength: 100 }, + args: { '-JsonPath': '{inputFile}', '-OutputDir': '{workDir}/config' }, + }, + { + name: 'cf-edit: регистрация справочника', + script: 'cf-edit/scripts/cf-edit', + input: [{ operation: 'add-childObject', value: 'Catalog.Товары' }], + args: { '-ConfigPath': '{workDir}/config', '-DefinitionFile': '{inputFile}' }, + }, + + // ── 2. Create file IB and load baseline (full, unmarked) via ibcmd ── + { + name: 'db-create: файловая ИБ', + script: 'db-create/scripts/db-create', + args: { '-V8Path': '{v8path}', '-InfoBasePath': '{workDir}/testdb' }, + }, + { + name: 'db-load-xml: загрузка конфигурации (Full)', + script: 'db-load-xml/scripts/db-load-xml', + args: { '-V8Path': '{v8path}', '-InfoBasePath': '{workDir}/testdb', '-ConfigDir': '{workDir}/config' }, + }, + { + name: 'db-update: обновление БД', + script: 'db-update/scripts/db-update', + args: { '-V8Path': '{v8path}', '-InfoBasePath': '{workDir}/testdb' }, + }, + + // ── 3. Mark the source object, then partial-LOAD just that object ── + { + name: 'editFile: маркер в Comment справочника', + editFile: '{workDir}/config/Catalogs/Товары.xml', + replace: '', + with: 'ibtestMARK', + }, + { + name: 'db-load-xml: частичная загрузка Товары (Partial)', + script: 'db-load-xml/scripts/db-load-xml', + args: { + '-V8Path': '{v8path}', '-InfoBasePath': '{workDir}/testdb', + '-ConfigDir': '{workDir}/config', '-Mode': 'Partial', '-Files': 'Catalogs/Товары.xml', + }, + }, + { + name: 'db-update: обновление БД (после partial load)', + script: 'db-update/scripts/db-update', + args: { '-V8Path': '{v8path}', '-InfoBasePath': '{workDir}/testdb' }, + }, + + // ── 4. Partial-DUMP the object back and verify the marker survived ── + { + name: 'db-dump-xml: частичная выгрузка Товары (Partial)', + script: 'db-dump-xml/scripts/db-dump-xml', + args: { + '-V8Path': '{v8path}', '-InfoBasePath': '{workDir}/testdb', + '-ConfigDir': '{workDir}/pv', '-Mode': 'Partial', '-Objects': 'Справочник.Товары', + }, + }, + { + name: 'assert: маркер ibtestMARK пережил round-trip', + assertContains: '{workDir}/pv/Catalogs/Товары.xml', + expect: 'ibtestMARK', + }, +]; diff --git a/tests/skills/runner.mjs b/tests/skills/runner.mjs index bfaddc80..e47560b0 100644 --- a/tests/skills/runner.mjs +++ b/tests/skills/runner.mjs @@ -972,10 +972,12 @@ function loadV8Context() { const v8bin = proj.v8path; const v8exe = v8bin ? (existsSync(join(v8bin, '1cv8.exe')) ? join(v8bin, '1cv8.exe') : null) : null; if (!v8exe) return null; + const ibcmdExe = v8bin && existsSync(join(v8bin, 'ibcmd.exe')) ? join(v8bin, 'ibcmd.exe') : null; const defaultDb = proj.databases?.find(d => d.id === proj.default) || proj.databases?.[0]; return { v8path: v8bin, v8exe, + ibcmdExe, dbPath: defaultDb?.path || '', dbUser: defaultDb?.user || '', dbPassword: defaultDb?.password || '', @@ -994,20 +996,40 @@ async function discoverIntegration(filter) { const id = `integration/${testName}`; if (filter && !id.startsWith(filter) && !id.includes(filter)) continue; const mod = await import(`file://${join(INTEGRATION, file).replace(/\\/g, '/')}`); - results.push({ id, name: mod.name || testName, steps: mod.steps || [], file, cache: mod.cache, setup: mod.setup || 'empty-config', requiresPlatform: !!mod.requiresPlatform }); + const engines = Array.isArray(mod.engines) && mod.engines.length ? mod.engines : ['1cv8']; + results.push({ id, name: mod.name || testName, steps: mod.steps || [], file, cache: mod.cache, setup: mod.setup || 'empty-config', requiresPlatform: !!mod.requiresPlatform, engines }); } return results; } +// Run a test once per declared engine (engine matrix). The ibcmd pass swaps +// {v8path} → ibcmd.exe so the same steps exercise the ibcmd opt-in branch. async function runIntegrationTest(test, opts) { + const engines = test.engines && test.engines.length ? test.engines : ['1cv8']; + // No platform at all → single skipped result (don't multiply across engines) + if (test.requiresPlatform && !opts.v8ctx) { + return [{ id: test.id, name: test.name, passed: true, skipped: true, skipReason: 'no platform', steps: [], elapsed: '0.0s', errors: [] }]; + } + const out = []; + const labelEngine = engines.length > 1; + for (const engine of engines) { + out.push(await runIntegrationOnce(test, opts, engine, labelEngine)); + } + return out; +} + +async function runIntegrationOnce(test, opts, engine, labelEngine) { const t0 = performance.now(); const stepResults = []; let workspace = null; + const idSuffix = labelEngine ? ` [${engine}]` : ''; + const id = test.id + idSuffix; + const name = test.name + idSuffix; - // Skip platform-dependent tests if platform unavailable - if (test.requiresPlatform && !opts.v8ctx) { + // ibcmd pass requires ibcmd.exe alongside 1cv8.exe + if (engine === 'ibcmd' && !opts.v8ctx?.ibcmdExe) { const elapsed = ((performance.now() - t0) / 1000).toFixed(1); - return { id: test.id, name: test.name, passed: true, skipped: true, steps: [], elapsed: `${elapsed}s`, errors: [] }; + return { id, name, passed: true, skipped: true, skipReason: 'no ibcmd.exe', steps: [], elapsed: `${elapsed}s`, errors: [] }; } try { @@ -1015,17 +1037,19 @@ async function runIntegrationTest(test, opts) { const fixturePath = test.setup === 'none' ? null : ensureSetup(test.setup, opts.runtime, CASES); if (fixturePath === SKIP) { const elapsed = ((performance.now() - t0) / 1000).toFixed(1); - return { id: test.id, name: test.name, passed: true, skipped: true, steps: [], elapsed: `${elapsed}s`, errors: [] }; + return { id, name, passed: true, skipped: true, skipReason: 'fixture unavailable', steps: [], elapsed: `${elapsed}s`, errors: [] }; } workspace = createWorkspace(fixturePath, false); const workDir = workspace.path; - // Platform placeholders + // Platform placeholders. {v8path} resolves to ibcmd.exe on the ibcmd pass + // (engine detected by exe name) and to the bin dir otherwise (auto-resolves 1cv8.exe). const v8 = opts.v8ctx || {}; + const v8pathForEngine = engine === 'ibcmd' ? (v8.ibcmdExe || '') : (v8.v8path || ''); const replacePlaceholders = (s) => s .replace('{workDir}', workDir) .replace('{inputFile}', '') - .replace('{v8path}', v8.v8path || '') + .replace('{v8path}', v8pathForEngine) .replace('{v8exe}', v8.v8exe || '') .replace('{dbPath}', v8.dbPath || '') .replace('{dbUser}', v8.dbUser || '') @@ -1052,6 +1076,41 @@ async function runIntegrationTest(test, opts) { continue; } + // editFile step: substring replace in an existing file (e.g. inject a marker) + if (step.editFile) { + try { + const target = replacePlaceholders(step.editFile); + const abs = target.includes(':') || target.startsWith('/') ? target : join(workDir, target); + let txt = readFileSync(abs, 'utf8'); + if (!txt.includes(step.replace)) throw new Error(`pattern not found: ${step.replace}`); + txt = txt.replace(step.replace, replacePlaceholders(step.with ?? '')); + writeFileSync(abs, txt, 'utf8'); + const stepElapsed = ((performance.now() - stepT0) / 1000).toFixed(1); + stepResults.push({ name: step.name, passed: true, elapsed: `${stepElapsed}s` }); + } catch (e) { + stepResults.push({ name: step.name, passed: false, error: `editFile failed: ${e.message}` }); + break; + } + continue; + } + + // assertContains step: fail unless target file contains the expected substring + if (step.assertContains) { + try { + const target = replacePlaceholders(step.assertContains); + const abs = target.includes(':') || target.startsWith('/') ? target : join(workDir, target); + const txt = existsSync(abs) ? readFileSync(abs, 'utf8') : ''; + const needle = replacePlaceholders(step.expect ?? ''); + if (!txt.includes(needle)) throw new Error(`"${needle}" not found in ${target}`); + const stepElapsed = ((performance.now() - stepT0) / 1000).toFixed(1); + stepResults.push({ name: step.name, passed: true, elapsed: `${stepElapsed}s` }); + } catch (e) { + stepResults.push({ name: step.name, passed: false, error: `assert failed: ${e.message}` }); + break; + } + continue; + } + // Write input if provided let inputFile = null; if (step.input) { @@ -1112,10 +1171,10 @@ async function runIntegrationTest(test, opts) { const allPassed = stepResults.every(s => s.passed); const elapsed = ((performance.now() - t0) / 1000).toFixed(1); - return { id: test.id, name: test.name, passed: allPassed, steps: stepResults, elapsed: `${elapsed}s`, errors: allPassed ? [] : stepResults.filter(s => !s.passed).map(s => s.error) }; + return { id, name, passed: allPassed, steps: stepResults, elapsed: `${elapsed}s`, errors: allPassed ? [] : stepResults.filter(s => !s.passed).map(s => s.error) }; } catch (e) { const elapsed = ((performance.now() - t0) / 1000).toFixed(1); - return { id: test.id, name: test.name, passed: false, steps: stepResults, elapsed: `${elapsed}s`, errors: [`Runner error: ${e.message}`] }; + return { id, name, passed: false, steps: stepResults, elapsed: `${elapsed}s`, errors: [`Runner error: ${e.message}`] }; } finally { if (workspace) cleanupWorkspace(workspace); } @@ -1125,7 +1184,7 @@ function printIntegrationReport(results, opts) { console.log(''); for (const r of results) { const icon = r.skipped ? '\u25CB' : r.passed ? '\u2713' : '\u2717'; - const suffix = r.skipped ? ' [skipped — no platform]' : ''; + const suffix = r.skipped ? ` [skipped — ${r.skipReason || 'no platform'}]` : ''; console.log(` ${icon} ${r.name} (${r.elapsed}) ${r.id}${suffix}`); for (const step of r.steps) { const sIcon = step.passed ? '\u2713' : '\u2717'; @@ -1166,7 +1225,7 @@ async function main() { console.log(`\nRunning ${integrationTests.length} integration test(s)... [runtime: ${opts.runtime}${valStr}]`); const integrationResults = []; for (const test of integrationTests) { - integrationResults.push(await runIntegrationTest(test, opts)); + integrationResults.push(...await runIntegrationTest(test, opts)); } integrationOk = printIntegrationReport(integrationResults, opts); }