# scrie_backstop_skills.ps1 - scrie blocul backstop de rutare a skill-urilor in AGENTS.md si CLAUDE.md # ale fiecarui proiect ROA. Sursa unica: backstop_skills.txt (langa acest script). # Idempotent: a doua rulare nu schimba nimic. -DryRun doar listeaza ce ar face. # Utilizare: # powershell -File COMUN\utile\scrie_backstop_skills.ps1 -Root D:\ROA # powershell -File COMUN\utile\scrie_backstop_skills.ps1 -Root D:\ROA -DryRun param( [string]$Root = 'D:\ROA', [switch]$DryRun ) $ErrorActionPreference = 'Stop' $MarkerStart = '' $MarkerEnd = '' $TitluAgents = '# AGENTS.md' $NumeSarite = @('COMUNROA', 'UTIL') $Utf8FaraBom = New-Object System.Text.UTF8Encoding($false) $sursa = Join-Path $PSScriptRoot 'backstop_skills.txt' if (-not (Test-Path -LiteralPath $sursa -PathType Leaf)) { Write-Output ('scrie_backstop_skills: nu gasesc blocul canonic ' + $sursa + ' - nimic de facut.') exit 0 } $bloc = ([IO.File]::ReadAllText($sursa)).Replace("`r`n", "`n").TrimEnd("`n") function Ia-Sectiune { # sectiunea marcata, cu terminatorii de linie dati param([string]$nl) return $MarkerStart + $nl + $bloc.Replace("`n", $nl) + $nl + $MarkerEnd } function Ia-Terminator { param([string]$Continut) if ($Continut.Contains("`r`n")) { return "`r`n" } if ($Continut.Contains("`n")) { return "`n" } return "`r`n" } function Ia-Encoding { # pastreaza BOM-ul original daca exista, altfel scrie UTF-8 fara BOM param([string]$Cale) $b = [IO.File]::ReadAllBytes($Cale) if ($b.Length -ge 3 -and $b[0] -eq 0xEF -and $b[1] -eq 0xBB -and $b[2] -eq 0xBF) { return (New-Object System.Text.UTF8Encoding($true)) } return $Utf8FaraBom } function Continut-Marcat { # noul continut, sau $null daca nu e nevoie de nicio schimbare (idempotent) param([string]$Continut, [string]$nl) $sect = Ia-Sectiune $nl $si = $Continut.IndexOf($MarkerStart) $ei = $Continut.IndexOf($MarkerEnd) if ($si -ge 0 -and $ei -gt $si) { $nou = $Continut.Substring(0, $si) + $sect + $Continut.Substring($ei + $MarkerEnd.Length) } else { $nou = $Continut.TrimEnd("`r", "`n") + $nl + $nl + $sect + $nl } if ($nou -eq $Continut) { return $null } return $nou } if (-not (Test-Path -LiteralPath $Root -PathType Container)) { Write-Output ('scrie_backstop_skills: nu gasesc radacina ' + $Root + ' - nimic de facut.') exit 0 } $proiecte = @(Get-ChildItem -LiteralPath $Root -Directory -ErrorAction SilentlyContinue | Sort-Object Name) $gasite = 0; $create = 0; $actualizate = 0; $ok = 0; $sarite = 0 foreach ($p in $proiecte) { if ($NumeSarite -contains $p.Name) { continue } if (-not (Test-Path -LiteralPath (Join-Path $p.FullName 'COMUN') -PathType Container)) { continue } $areSvn = Test-Path -LiteralPath (Join-Path $p.FullName '.svn') -PathType Container $areGit = Test-Path -LiteralPath (Join-Path $p.FullName '.git') -PathType Container if (-not ($areSvn -or $areGit)) { continue } $gasite++ Write-Output ('Proiect: ' + $p.Name) foreach ($nume in @('AGENTS.md', 'CLAUDE.md')) { $cale = Join-Path $p.FullName $nume if (-not (Test-Path -LiteralPath $cale -PathType Leaf)) { if ($nume -eq 'CLAUDE.md') { Write-Output (' ' + $nume + ' sarit - lipseste') $sarite++ continue } $nl = "`r`n" $nou = $TitluAgents + $nl + $nl + (Ia-Sectiune $nl) + $nl if ($DryRun) { Write-Output (' ' + $nume + ' ar crea') } else { [IO.File]::WriteAllText($cale, $nou, $Utf8FaraBom) Write-Output (' ' + $nume + ' creat') } $create++ continue } $raw = [IO.File]::ReadAllText($cale) $nl = Ia-Terminator $raw $nou = Continut-Marcat -Continut $raw -nl $nl if ($null -eq $nou) { Write-Output (' ' + $nume + ' ok') $ok++ continue } if ($DryRun) { Write-Output (' ' + $nume + ' ar actualiza') } else { [IO.File]::WriteAllText($cale, $nou, (Ia-Encoding $cale)) Write-Output (' ' + $nume + ' actualizat') } $actualizate++ } } Write-Output '' $eticheta = 'scrie_backstop_skills' if ($DryRun) { $eticheta = $eticheta + ' (DryRun)' } Write-Output ($eticheta + ': ' + $gasite + ' proiecte, ' + $create + ' create, ' + $actualizate + ' actualizate, ' + $ok + ' neschimbate, ' + $sarite + ' sarite') exit 0