diff --git a/.claude/skills/db-create/scripts/db-create.ps1 b/.claude/skills/db-create/scripts/db-create.ps1 index 159466f2..f46fff5e 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.5 — Create 1C information base +# db-create v1.6 — Create 1C information base # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -111,6 +111,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } # --- Validate connection --- @@ -147,8 +174,9 @@ try { } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Information base created successfully: $InfoBasePath" -ForegroundColor Green } else { diff --git a/.claude/skills/db-create/scripts/db-create.py b/.claude/skills/db-create/scripts/db-create.py index 37cd33c0..eb60ea8d 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.5 — Create 1C information base +# db-create v1.6 — Create 1C information base # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -123,7 +144,7 @@ def main(): 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") + result = run_ibcmd([v8path] + arguments, warn_no_user=False) if result.returncode == 0: print(f"Information base created successfully: {args.InfoBasePath}") else: 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 d572906c..75405cd7 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.5 — Dump 1C configuration to CF file +# db-dump-cf v1.6 — Dump 1C configuration to CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -120,6 +120,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } # --- Validate connection --- @@ -157,8 +184,9 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Configuration dumped successfully to: $OutputFile" -ForegroundColor Green } else { 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 9ecf0cfe..342c5e73 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.5 — Dump 1C configuration to CF file +# db-dump-cf v1.6 — Dump 1C configuration to CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -130,7 +151,7 @@ def main(): arguments.append(f"--password={args.Password}") 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") + result = run_ibcmd([v8path] + arguments, bool(args.UserName)) if result.returncode == 0: print(f"Configuration dumped successfully to: {args.OutputFile}") else: 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 c1c8aac0..b2f5339a 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.4 — Dump 1C information base to DT file +# db-dump-dt v1.5 — Dump 1C information base to DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -104,6 +104,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } # --- Validate connection --- @@ -137,8 +164,9 @@ try { $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Information base dumped successfully to: $OutputFile" -ForegroundColor Green } else { 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 e5b45cc6..7a603c6d 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.4 — Dump 1C information base to DT file +# db-dump-dt v1.5 — Dump 1C information base to DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -123,7 +144,7 @@ def main(): 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") + result = run_ibcmd([v8path] + arguments, bool(args.UserName)) if result.returncode == 0: print(f"Information base dumped successfully to: {args.OutputFile}") else: 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 47344d5c..43312610 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.7 — Dump 1C configuration to XML files +# db-dump-xml v1.8 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -143,6 +143,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } # --- Validate connection --- @@ -198,8 +225,9 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Configuration exported successfully to: $ConfigDir" -ForegroundColor Green } else { 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 490fb505..6df5bc32 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.7 — Dump 1C configuration to XML files +# db-dump-xml v1.8 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -161,7 +182,7 @@ def main(): arguments.append(f"--password={args.Password}") 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") + result = run_ibcmd([v8path] + arguments, bool(args.UserName)) if result.returncode == 0: print(f"Configuration exported successfully to: {args.ConfigDir}") else: 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 a4a865d8..843b2ccc 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.5 — Load 1C configuration from CF file +# db-load-cf v1.6 — Load 1C configuration from CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -120,6 +120,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } # --- Validate connection --- @@ -157,8 +184,9 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Configuration loaded successfully from: $InputFile" -ForegroundColor Green } else { 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 a2e68d83..f233518b 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.5 — Load 1C configuration from CF file +# db-load-cf v1.6 — Load 1C configuration from CF file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -130,7 +151,7 @@ def main(): arguments.append(f"--password={args.Password}") 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") + result = run_ibcmd([v8path] + arguments, bool(args.UserName)) if result.returncode == 0: print(f"Configuration loaded successfully from: {args.InputFile}") else: 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 dbba0ae3..e7d79bd2 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.4 — Load 1C information base from DT file +# db-load-dt v1.5 — Load 1C information base from DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -117,6 +117,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } # --- Validate connection --- @@ -151,8 +178,9 @@ try { $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Information base restored successfully from: $InputFile" -ForegroundColor Green } else { 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 ef72172f..a9f77bf7 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.4 — Load 1C information base from DT file +# db-load-dt v1.5 — Load 1C information base from DT file # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -127,7 +148,7 @@ def main(): 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") + result = run_ibcmd([v8path] + arguments, bool(args.UserName)) if result.returncode == 0: print(f"Information base restored successfully from: {args.InputFile}") else: 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 0b86628d..44135e42 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.9 — Load Git changes into 1C database +# db-load-git v1.10 — Load Git changes into 1C database # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -167,6 +167,33 @@ if (-not $DryRun) { # --- Detect engine + validate connection (skip if DryRun) --- $engine = "1cv8" if (-not $DryRun) { +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } if ($engine -eq "ibcmd") { if (-not $InfoBasePath) { @@ -344,8 +371,9 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -ne 0) { Write-Host "Error loading changes (code: $exitCode)" -ForegroundColor Red if ($output) { Write-Host ($output | Out-String) } @@ -359,8 +387,9 @@ try { if ($Password) { $applyArgs += "--password=$Password" } $applyArgs += "--data=$tempDir" Write-Host "Running: ibcmd $($applyArgs -join ' ')" - $applyOut = & $V8Path @applyArgs 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $applyArgs + $applyOut = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Database configuration updated successfully" -ForegroundColor Green } else { 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 6cb141ec..475f993f 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.9 — Load Git changes into 1C database +# db-load-git v1.10 — Load Git changes into 1C database # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def get_object_xml_from_subfile(relative_path): """Map sub-file path (BSL, HTML, etc.) to object XML path.""" parts = re.split(r"[\\/]", relative_path) @@ -287,7 +308,7 @@ def main(): arguments.append(f"--password={args.Password}") 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") + result = run_ibcmd([v8path] + arguments, bool(args.UserName)) if result.returncode != 0: print(f"Error loading changes (code: {result.returncode})", file=sys.stderr) if result.stdout: @@ -307,7 +328,7 @@ def main(): apply_args.append(f"--password={args.Password}") 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") + ar = run_ibcmd([v8path] + apply_args, bool(args.UserName)) exit_code = ar.returncode if exit_code == 0: print("Database configuration updated successfully") 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 4f840dd1..05210807 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.11 — Load 1C configuration from XML files +# db-load-xml v1.12 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -152,6 +152,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } # --- Validate connection --- @@ -218,8 +245,9 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -ne 0) { Write-Host "Error loading configuration from files (code: $exitCode)" -ForegroundColor Red if ($output) { Write-Host ($output | Out-String) } @@ -234,8 +262,9 @@ try { if ($Password) { $applyArgs += "--password=$Password" } $applyArgs += "--data=$tempDir" Write-Host "Running: ibcmd $($applyArgs -join ' ')" - $applyOut = & $V8Path @applyArgs 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $applyArgs + $applyOut = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Database configuration updated successfully" -ForegroundColor Green } else { 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 a9759ff4..f40f83fa 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.11 — Load 1C configuration from XML files +# db-load-xml v1.12 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -179,7 +200,7 @@ def main(): arguments.append(f"--password={args.Password}") 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") + result = run_ibcmd([v8path] + arguments, bool(args.UserName)) if result.returncode != 0: print(f"Error loading configuration from files (code: {result.returncode})", file=sys.stderr) if result.stdout: @@ -199,7 +220,7 @@ def main(): apply_args.append(f"--password={args.Password}") 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") + ar = run_ibcmd([v8path] + apply_args, bool(args.UserName)) exit_code = ar.returncode if exit_code == 0: print("Database configuration updated successfully") diff --git a/.claude/skills/db-update/scripts/db-update.ps1 b/.claude/skills/db-update/scripts/db-update.ps1 index c6ca1230..aec0fffa 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.5 — Update 1C database configuration +# db-update v1.6 — Update 1C database configuration # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -133,6 +133,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } # --- Validate connection --- @@ -165,8 +192,9 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "Database configuration updated successfully" -ForegroundColor Green } else { diff --git a/.claude/skills/db-update/scripts/db-update.py b/.claude/skills/db-update/scripts/db-update.py index 4d6e1bbc..97a03151 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.5 — Update 1C database configuration +# db-update v1.6 — Update 1C database configuration # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -131,7 +152,7 @@ def main(): arguments.append(f"--password={args.Password}") 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") + result = run_ibcmd([v8path] + arguments, bool(args.UserName)) if result.returncode == 0: print("Database configuration updated successfully") else: diff --git a/.claude/skills/epf-build/scripts/epf-build.ps1 b/.claude/skills/epf-build/scripts/epf-build.ps1 index 186b326f..dd32da8a 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.5 — Build external data processor or report (EPF/ERF) from XML sources +# epf-build v1.6 — Build external data processor or report (EPF/ERF) from XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -114,6 +114,33 @@ if (-not (Test-Path $V8Path)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $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 @@ -162,8 +189,9 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "External data processor/report built successfully: $OutputFile" -ForegroundColor Green } else { diff --git a/.claude/skills/epf-build/scripts/epf-build.py b/.claude/skills/epf-build/scripts/epf-build.py index 4deb68d2..383f58fb 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.5 — Build external data processor or report (EPF/ERF) from XML sources +# epf-build v1.6 — Build external data processor or report (EPF/ERF) from XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -146,7 +167,7 @@ def main(): arguments.append(f"--password={args.Password}") 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") + result = run_ibcmd([v8path] + arguments, warn_no_user=False) if result.returncode == 0: print(f"External data processor/report built successfully: {args.OutputFile}") else: diff --git a/.claude/skills/epf-build/scripts/stub-db-create.ps1 b/.claude/skills/epf-build/scripts/stub-db-create.ps1 index 7396c60c..e36d5f29 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.2 — Create temp 1C infobase with metadata stubs for EPF/ERF build +# stub-db-create v1.3 — Create temp 1C infobase with metadata stubs for EPF/ERF build # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -1253,6 +1253,33 @@ $propsXml $childObjLine } # --- 5a. Stub via ibcmd (one call: create [--import --apply]) --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $stubEngine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } if ($stubEngine -eq "ibcmd") { Write-Host "Creating infobase (ibcmd): $TempBasePath" @@ -1261,8 +1288,9 @@ if ($stubEngine -eq "ibcmd") { $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 - $ibRc = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $ibArgs + $ibOut = $__ib.Output + $ibRc = $__ib.ExitCode Remove-Item -Path $ibData -Recurse -Force -ErrorAction SilentlyContinue if ($ibRc -ne 0) { if ($ibOut) { Write-Host ($ibOut | Out-String) } diff --git a/.claude/skills/epf-build/scripts/stub-db-create.py b/.claude/skills/epf-build/scripts/stub-db-create.py index 21868f1f..6b8e6524 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.2 — Create temp 1C infobase with metadata stubs for EPF/ERF build +# stub-db-create v1.3 — Create temp 1C infobase with metadata stubs for EPF/ERF build # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -12,6 +12,27 @@ import tempfile import uuid +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def new_uuid(): return str(uuid.uuid4()) @@ -1044,7 +1065,7 @@ def main(): 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') + result = run_ibcmd(ib_args, warn_no_user=False) shutil.rmtree(ib_data, ignore_errors=True) if result.returncode != 0: if result.stdout: diff --git a/.claude/skills/epf-dump/scripts/epf-dump.ps1 b/.claude/skills/epf-dump/scripts/epf-dump.ps1 index 436e9976..eb79647a 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.5 — Dump external data processor or report (EPF/ERF) to XML sources +# epf-dump v1.6 — Dump external data processor or report (EPF/ERF) to XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: *nix-раскладку платформы (/opt/1cv8//1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется. <# @@ -128,6 +128,33 @@ if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { } # --- Detect engine (ibcmd vs 1cv8) by exe name --- +function Invoke-IbcmdProcess { + # Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt + # fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's + # native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process. + param([string]$Exe, [string[]]$IbArgs) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $Exe + $psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' ' + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.RedirectStandardInput = $true + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + try { + $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866) + $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866) + } catch {} + $p = [System.Diagnostics.Process]::Start($psi) + $p.StandardInput.Close() + $out = $p.StandardOutput.ReadToEnd() + $err = $p.StandardError.ReadToEnd() + $p.WaitForExit() + if ($err) { $out += $err } + return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode } +} + + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } if ($engine -eq "ibcmd") { if (-not $InfoBasePath) { @@ -163,8 +190,9 @@ try { if ($Password) { $arguments += "--password=$Password" } $arguments += "--data=$tempDir" Write-Host "Running: ibcmd $($arguments -join ' ')" - $output = & $V8Path @arguments 2>&1 - $exitCode = $LASTEXITCODE + $__ib = Invoke-IbcmdProcess $V8Path $arguments + $output = $__ib.Output + $exitCode = $__ib.ExitCode if ($exitCode -eq 0) { Write-Host "External data processor/report dumped successfully to: $OutputDir" -ForegroundColor Green } else { diff --git a/.claude/skills/epf-dump/scripts/epf-dump.py b/.claude/skills/epf-dump/scripts/epf-dump.py index 022c5876..9c4e1c31 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.5 — Dump external data processor or report (EPF/ERF) to XML sources +# epf-dump v1.6 — Dump external data processor or report (EPF/ERF) to XML sources # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -78,6 +78,27 @@ def resolve_v8path(v8path): return v8path +IBCMD_NOUSER_HINT = ( + "[ibcmd] No -UserName/-Password given; the infobase may require authentication. " + "On Windows ibcmd reads credentials from the console (stdin is ignored), so this " + "call may block instead of failing. If it does not return promptly, abort and " + "re-run with -UserName and -Password.\n" +) + + +def run_ibcmd(cmd, has_username=False, warn_no_user=True): + """Run an ibcmd command non-interactively. + + input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging. + On Windows without -UserName ibcmd reads the console directly and may still block — + that residual case is flagged via IBCMD_NOUSER_HINT (model-facing). + """ + if warn_no_user and os.name == "nt" and not has_username: + sys.stderr.write(IBCMD_NOUSER_HINT) + sys.stderr.flush() + return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace") + + def main(): sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") @@ -143,7 +164,7 @@ def main(): arguments.append(f"--password={args.Password}") 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") + result = run_ibcmd([v8path] + arguments, warn_no_user=False) if result.returncode == 0: print(f"External data processor/report dumped successfully to: {args.OutputDir}") else: