Private/Get-KadenRepoHealthFinding.ps1
|
function Get-KadenRepoHealthFinding { <# .SYNOPSIS Collect read-only health findings for a child repository. .DESCRIPTION Reads the seed ignore list through Get-KadenRequiredIgnoreLine and the doc-scaffold inventory. Findings use Area Ignore, Hooks, DocScaffold, or AgentsInjection. Checks those surfaces plus hook files and the AGENTS.md marker pair. An AGENTS.md larger than 1 MB is not scanned. Does not create or edit files. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$ChildRoot ) $seedRoot = Join-Path $script:KadenModuleRoot 'Seeds' $manifestPath = Join-Path $seedRoot 'manifest.psd1' if (-not (Test-Path -LiteralPath $manifestPath -PathType Leaf)) { throw 'KDN-SEED-MISSING: Seeds/manifest.psd1 is not in the module.' } $manifest = Import-PowerShellDataFile -Path $manifestPath $requiredIgnore = @(Get-KadenRequiredIgnoreLine -SeedRoot $seedRoot -Manifest $manifest) $docs = @($manifest.Docs) if ($docs.Count -lt 1) { throw 'KDN-SEED-MISSING: Seeds/manifest.psd1 has no Docs entries.' } $findings = New-Object System.Collections.Generic.List[object] $gitignorePath = Resolve-KadenContainedPath -Root $ChildRoot -RelativePath '.gitignore' $existingIgnore = @() if (Test-Path -LiteralPath $gitignorePath -PathType Leaf) { $existingIgnore = @(Get-Content -LiteralPath $gitignorePath) } foreach ($line in $requiredIgnore) { $present = $false foreach ($existingLine in $existingIgnore) { if ([string]::Equals($existingLine, $line, [System.StringComparison]::Ordinal)) { $present = $true break } } $detail = if ($present) { "Ignore entry $line is present." } else { "Missing ignore entry $line." } $findings.Add([pscustomobject]@{ Area = 'Ignore' Name = $line Passed = $present Detail = $detail }) } $hookPaths = @('.cursor/hooks.json', '.github/hooks/harness.json') foreach ($relative in $hookPaths) { $full = Resolve-KadenContainedPath -Root $ChildRoot -RelativePath $relative $present = Test-Path -LiteralPath $full -PathType Leaf $detail = if ($present) { "Hook file $relative is present." } else { "Missing hook file $relative." } $findings.Add([pscustomobject]@{ Area = 'Hooks' Name = $relative Passed = $present Detail = $detail }) } foreach ($relative in $docs) { $scaffold = [string]$relative $full = Resolve-KadenContainedPath -Root $ChildRoot -RelativePath $scaffold $present = Test-Path -LiteralPath $full -PathType Leaf $detail = if ($present) { "Doc scaffold $scaffold is present." } else { "Missing doc scaffold $scaffold." } $findings.Add([pscustomobject]@{ Area = 'DocScaffold' Name = $scaffold Passed = $present Detail = $detail }) } $startToken = '<!-- KADEN:START -->' $endToken = '<!-- KADEN:END -->' $agentsPath = Resolve-KadenContainedPath -Root $ChildRoot -RelativePath 'AGENTS.md' $agentsPassed = $false $agentsDetail = 'AGENTS.md is missing the Kaden marker pair.' $agentsMaxBytes = 1MB if (-not (Test-Path -LiteralPath $agentsPath -PathType Leaf)) { $agentsDetail = 'AGENTS.md is missing.' } elseif ((Get-Item -LiteralPath $agentsPath -Force).Length -gt $agentsMaxBytes) { $agentsDetail = 'AGENTS.md is larger than 1 MB, so the marker pair was not scanned.' } else { $agentsText = Get-Content -LiteralPath $agentsPath -Raw if ($null -eq $agentsText) { $agentsText = '' } $startAt = $agentsText.IndexOf($startToken, [System.StringComparison]::Ordinal) $endAt = $agentsText.IndexOf($endToken, [System.StringComparison]::Ordinal) if ($startAt -ge 0 -and $endAt -gt $startAt) { $agentsPassed = $true $agentsDetail = 'AGENTS.md contains the Kaden marker pair.' } } $findings.Add([pscustomobject]@{ Area = 'AgentsInjection' Name = 'AGENTS.md' Passed = $agentsPassed Detail = $agentsDetail }) return @($findings.ToArray()) } |