Public/Export-SLPolicy.ps1

function Export-SLPolicy {
    <#
    .SYNOPSIS
        Writes the reviewed shared development policy from this SecondLine release into a repo.
 
    .DESCRIPTION
        Copies the policy shipped with the loaded SecondLine, version header included,
        to -Destination (default docs/shared-development-policy.md under -Path). The
        copy can be verified offline by its header hash, so consumers don't need the
        SecondLine checkout.
 
        Overwrites an existing copy only if that copy is unmodified (its hash
        verifies). A locally modified copy, or a file without a header, is left alone
        unless -Force. It never edits CLAUDE.md or AGENTS.md: it prints the marker
        lines for you to add to them by hand, beside each project's own instructions.
 
    .PARAMETER Path
        The repo. Default: the current folder.
 
    .PARAMETER Destination
        Repo-relative path of the copy. Default: docs/shared-development-policy.md.
 
    .PARAMETER Force
        Overwrite a modified copy or a file without a header.
 
    .PARAMETER PassThru
        Return Path, Version, Action (Created | Updated | Unchanged | Refused) and Applied.
 
    .EXAMPLE
        Export-SLPolicy -Path C:\src\MyApp -WhatIf
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    param(
        [string] $Path,
        [string] $Destination = 'docs/shared-development-policy.md',
        [switch] $Force,
        [switch] $PassThru
    )
    if (-not $Path) { $Path = (Get-Location).ProviderPath }
    if (Test-SLNonPortablePath $Destination) { throw "Destination must be a relative path inside the repo, for example docs/shared-development-policy.md." }
    $source = Get-SLShippedPolicyPath
    if (-not $source) { throw 'This SecondLine package has no shared policy file.' }
    $shipped = Read-SLPolicyFile -Path $source
    if (-not $shipped.HasHeader -or $shipped.Modified) { throw "The shipped policy $source does not verify; it was changed after review. Nothing was written." }
    $target = Join-Path (Resolve-Path -LiteralPath $Path).ProviderPath $Destination
    $result = [pscustomobject]@{ Path = $target; Version = $shipped.Version; Action = 'Created'; Applied = $false }
    if (Test-Path -LiteralPath $target -PathType Leaf) {
        $existing = Read-SLPolicyFile -Path $target
        $result.Action = 'Updated'
        if ($existing.HasHeader -and -not $existing.Modified -and $existing.Hash -eq $shipped.Hash) { $result.Action = 'Unchanged' }
        elseif ((-not $existing.HasHeader -or $existing.Modified) -and -not $Force) {
            $result.Action = 'Refused'
            Write-Warning "$target is locally modified or has no SecondLine-Policy header; nothing was written. Move local rules into CLAUDE.md/AGENTS.md, then rerun, or pass -Force."
        }
    }
    if ($result.Action -in 'Created', 'Updated' -and $PSCmdlet.ShouldProcess($target, "$($result.Action) shared development policy version $($shipped.Version)")) {
        $dir = Split-Path $target -Parent
        if (-not (Test-Path -LiteralPath $dir)) { [void] (New-Item -ItemType Directory -Path $dir -Force) }
        # Text, not bytes: the repo's own .gitattributes decides the checkout ending; write LF.
        Write-SLTextLines -Path $target -Lines @(Read-SLTextLines -Path $source)
        $result.Applied = $true
    }
    $relative = $Destination.Replace('\', '/')
    Write-Host " Shared policy version $($shipped.Version): $($result.Action) $target" -ForegroundColor Green
    Write-Host ' Add these lines to both CLAUDE.md and AGENTS.md (by hand; this command never edits them):' -ForegroundColor Gray
    Write-Host " SecondLine-Policy: $($shipped.Version) $relative" -ForegroundColor Gray
    Write-Host ' SecondLine-Status: docs/status/current.md' -ForegroundColor Gray
    if ($PassThru) { $result }
}