[CmdletBinding()] param([string]$PxhjRoot = 'E:\pxhj') $ErrorActionPreference = 'Stop' $projectRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..')) $staging = Join-Path $projectRoot 'runtime/console-pxhj-staging' $manifest = Get-Content -LiteralPath (Join-Path $staging 'baseline-manifest.json') -Raw | ConvertFrom-Json $targetRoot = [IO.Path]::GetFullPath($PxhjRoot).TrimEnd('\') $backupRoot = Join-Path $projectRoot ('runtime/console-bridge-backup-' + (Get-Date -Format 'yyyyMMdd-HHmmss')) foreach ($entry in $manifest.files) { $target = [IO.Path]::GetFullPath((Join-Path $targetRoot $entry.path)) if (-not $target.StartsWith($targetRoot + '\', [StringComparison]::OrdinalIgnoreCase)) { throw '补丁路径超出目标项目。' } $staged = Join-Path $staging $entry.path if ((Get-FileHash -LiteralPath $staged -Algorithm SHA256).Hash -ne $entry.sha256) { throw ('补丁文件校验失败:' + $entry.path) } if (Test-Path -LiteralPath $target) { $currentHash = (Get-FileHash -LiteralPath $target -Algorithm SHA256).Hash $baseline = @($manifest.modifiedBaseline | Where-Object path -eq $entry.path) if ($currentHash -ne $entry.sha256 -and ($baseline.Count -eq 0 -or $currentHash -ne $baseline[0].sha256)) { throw ('目标文件已变化,未覆盖:' + $entry.path) } } } foreach ($entry in $manifest.files) { $target = Join-Path $targetRoot $entry.path if (Test-Path -LiteralPath $target) { $backup = Join-Path $backupRoot $entry.path New-Item -ItemType Directory -Force -Path (Split-Path -Parent $backup) | Out-Null Copy-Item -LiteralPath $target -Destination $backup } New-Item -ItemType Directory -Force -Path (Split-Path -Parent $target) | Out-Null Copy-Item -LiteralPath (Join-Path $staging $entry.path) -Destination $target } Write-Output ('采集桥接源码已应用。备份目录:' + $backupRoot) Write-Output '运行中的后端不会自动加载新源码。'