????# kb_emit_bootpack_dual_v1.1.ps1 # Objet : Generer bootpack_paste.txt (JSON compact) et bootpack.txt (pointer + SHA256 + Updated + Entries + SizeBytes), # sans embarquer de JSON massif dans bootpack.txt. PS 5.1 compatible, SAFE-WRITE, streaming, UTF-8 BOM. [CmdletBinding()] param( [switch]$Preview, [switch]$Execute, [string]$Root = "\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry", [string]$StageRoot = "C:\Temp_Gouvernance" ) function Ensure-Dir([string]$Path){ if(-not (Test-Path -LiteralPath $Path)){ New-Item -ItemType Directory -Force -Path $Path | Out-Null } } function Ensure-Parent([string]$Target){ $p=Split-Path -Parent $Target; if($p){ Ensure-Dir $p } } function Get-NowIso(){ (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssK") } function Read-JsonSansFooter([string]$Path){ $sr=New-Object IO.StreamReader($Path) try{ $L=New-Object 'System.Collections.Generic.List[string]' while(-not $sr.EndOfStream){ $line=$sr.ReadLine() if($line -match '^\s*---\s*DOC-VERSION-FOOTER'){ break } $L.Add($line)|Out-Null } ($L -join "`n") } finally { $sr.Dispose() } } function Get-FileSHA256([string]$Path){ if(-not(Test-Path -LiteralPath $Path)){ return "" } $sha=[Security.Cryptography.SHA256]::Create() $fs=[IO.File]::OpenRead($Path) try{ -join ($sha.ComputeHash($fs) | ForEach-Object { $_.ToString("x2") }) } finally { $fs.Dispose(); $sha.Dispose() } } function Write-SafeText([string]$Target,[string]$Content,[string]$StageRoot){ Ensure-Dir $StageRoot; Ensure-Parent $Target $tmp=Join-Path $StageRoot ("write_" + [IO.Path]::GetRandomFileName()) $utf8=New-Object Text.UTF8Encoding($true) # UTF-8 with BOM [IO.File]::WriteAllText($tmp,$Content,$utf8) $bak=$null if(Test-Path -LiteralPath $Target){ $bak=$Target+"."+(Get-Date -f yyyyMMdd_HHmmss)+".bak" Copy-Item -LiteralPath $Target -Destination $bak -Force } $tmpR="$Target.tmp" Copy-Item -LiteralPath $tmp -Destination $tmpR -Force Move-Item -LiteralPath $tmpR -Destination $Target -Force Remove-Item -LiteralPath $tmp -Force return $bak } # Paths $BugKbDir = Join-Path $Root "bug_kb" $BootDir = Join-Path $Root "bootpack" $KbCanon = Join-Path $BugKbDir "BUG_KB.json.txt" $BootTxt = Join-Path $BootDir "bootpack.txt" $BootPaste = Join-Path $BootDir "bootpack_paste.txt" Ensure-Dir $BugKbDir; Ensure-Dir $BootDir # Charger KB canonique (sans footer) et parser if(-not (Test-Path -LiteralPath $KbCanon)){ Write-Host "[ERR] KB canonique absente: $KbCanon"; exit 2 } $kbRaw = Read-JsonSansFooter $KbCanon try{ $kb = $kbRaw | ConvertFrom-Json -ErrorAction Stop } catch { Write-Host "[ERR] KB JSON invalide: $($_.Exception.Message)"; exit 3 } # Generer le JSON compact de paste $pasteJson = ($kb | ConvertTo-Json -Depth 6 -Compress) # Calculer la taille et le SHA sur le contenu tel qu'ecrit (temp local) Ensure-Dir $StageRoot $tmpPaste = Join-Path $StageRoot ("paste_" + [IO.Path]::GetRandomFileName()) $utf8=New-Object Text.UTF8Encoding($true) [IO.File]::WriteAllText($tmpPaste,$pasteJson,$utf8) $pasteSize = (Get-Item -LiteralPath $tmpPaste).Length $pasteSha = Get-FileSHA256 $tmpPaste Remove-Item -LiteralPath $tmpPaste -Force $updated = Get-NowIso # PS 5.1-safe: pas de ternaire $entries = 0 if($kb -and ($kb.PSObject.Properties.Name -contains 'entries') -and $kb.entries){ try { $entries = $kb.entries.Count } catch { $entries = 0 } } # Contenu du bootpack pointer-only $bootTxtContent = @" [BOOT-PACK] Name=ChatGPT-Gouvernance-Projets BootPack Version=1.0 Generated=$updated [POLICY] GOV_SCRIPT_GATE v1.3 SAFE-WRITE-RULE v1.1 TXT-ONLY SYNC-MEM-ARCHIVE-RULE KB_DUAL_BOOTPACK v1.0 [BUG_KB_JSON_POINTER] Path=$BootPaste SHA256=$pasteSha Updated=$updated Entries=$entries SizeBytes=$pasteSize --- DOC-VERSION-FOOTER --- Generated: $updated Policy: TXT-ONLY v1.0; SAFE-WRITE v1.1; GOV_SCRIPT_GATE v1.3; KB_DUAL_BOOTPACK v1.0 Source: KB_EMIT_BOOTPACK_DUAL_v1.1 "@ if($Preview -or (-not $Execute)){ Write-Host "== PREVIEW :: EMIT BOOTPACK DUAL ==" Write-Host ("Will write paste : {0} size~{1:n0} sha256={2}" -f $BootPaste, $pasteSize, $pasteSha) Write-Host ("Will write boot : {0} entries={1}" -f $BootTxt, $entries) Write-Host "No write performed (Preview)." exit 0 } # EXECUTE $bakPaste = Write-SafeText -Target $BootPaste -Content $pasteJson -StageRoot $StageRoot $bakBoot = Write-SafeText -Target $BootTxt -Content $bootTxtContent -StageRoot $StageRoot $bakPasteMsg = $bakPaste; if(-not $bakPasteMsg){ $bakPasteMsg = "" } $bakBootMsg = $bakBoot; if(-not $bakBootMsg){ $bakBootMsg = "" } Write-Host ("[OK] bootpack_paste.txt ecrit: {0} (bak={1})" -f $BootPaste, $bakPasteMsg) Write-Host ("[OK] bootpack.txt ecrit: {0} (bak={1})" -f $BootTxt, $bakBootMsg)