Private/Update-KadenInstructionBlock.ps1
|
function Update-KadenInstructionBlock { <# .SYNOPSIS Create or refresh delimited Kaden blocks without wiping project text. .DESCRIPTION AGENTS.md receives a project header only when it is missing and -CreateMissingAgents is set. Update leaves a missing AGENTS.md alone. A missing .github/copilot-instructions.md is created with a short project header and the delimited block. A file that already exists changes only between <!-- KADEN:START --> and <!-- KADEN:END -->. A broken marker pair is left untouched and reported. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Initialize-KadenRepo and Update-KadenRepo already confirm ShouldProcess before this private write.')] [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$ChildRoot, [Parameter(Mandatory = $true)] [string]$ProjectId, [Parameter(Mandatory = $false)] [switch]$CreateMissingAgents, [Parameter(Mandatory = $false)] [switch]$AssumeLock ) if ($CreateMissingAgents -and -not (Test-KadenProjectId -ProjectId $ProjectId)) { throw 'KDN-PROJECT-ID-INVALID: ProjectId must be at most 64 characters of lowercase letters, digits, and single hyphens.' } $contract = @{ StartToken = '<!-- KADEN:START -->' EndToken = '<!-- KADEN:END -->' Notice = '<!-- Managed by Kaden. Do not edit content within this block. -->' } $agentsBody = Get-KadenInstructionBodyText -LiteralPath (Join-Path $script:KadenModuleRoot (Join-Path 'InstructionBlocks' 'agents-block.md')) $copilotSource = Join-Path (Get-KadenPayloadRoot) (Join-Path 'github' 'copilot-instructions.md') $copilotBody = Get-KadenInstructionBodyText -LiteralPath $copilotSource $findings = New-Object System.Collections.Generic.List[string] $delimitedDestinations = @(Get-KadenDelimitedInstructionDestination) $copilotRelative = $null foreach ($destination in $delimitedDestinations) { if ($destination -eq '.github/copilot-instructions.md') { $copilotRelative = $destination break } } if (-not $copilotRelative) { throw 'KDN-INSTRUCTION-DESTINATION-MISSING: managed manifest has no delimited instruction destination.' } $agentsHeader = @( "# AGENTS.md - $ProjectId" '' 'Project commands and notes stay outside the Kaden markers.' '' '## Commands' '' '| Action | Command |' '|--------|---------|' '| Harness entry | `pwsh -File scripts/kaden/harness-invoke.ps1 <harness-script> [args...]` |' '' ) -join "`n" $copilotHeader = @( '# Project Copilot instructions' '' 'Project policy stays outside the Kaden markers.' '' ) -join "`n" $transactionId = [guid]::NewGuid().ToString('N') $lockPath = Join-Path $ChildRoot (Join-Path '.kaden' (Join-Path 'transactions' 'update.lock')) if (-not $AssumeLock) { Lock-KadenUpdate -LockPath $lockPath -TransactionId $transactionId } try { $agentsContent = @{ Header = $agentsHeader Body = $agentsBody CreateWhenMissing = [bool]$CreateMissingAgents StartToken = $contract.StartToken EndToken = $contract.EndToken Notice = $contract.Notice } $copilotContent = @{ Header = $copilotHeader Body = $copilotBody CreateWhenMissing = $true StartToken = $contract.StartToken EndToken = $contract.EndToken Notice = $contract.Notice } Update-KadenDelimitedInstructionFile -ChildRoot $ChildRoot -RelativePath 'AGENTS.md' -Content $agentsContent -Findings $findings Update-KadenDelimitedInstructionFile -ChildRoot $ChildRoot -RelativePath $copilotRelative -Content $copilotContent -Findings $findings } finally { if (-not $AssumeLock) { Remove-Item -LiteralPath $lockPath -Force -ErrorAction SilentlyContinue } } foreach ($finding in @($findings)) { Write-Warning $finding } return @($findings) } |