Public/Repair-KadenRepo.ps1

function Repair-KadenRepo {
    <#
    .SYNOPSIS
        Continue or restore an interrupted managed-file transaction.
    .DESCRIPTION
        Resume applies only the payload version and digest recorded in the journal.
        Restore returns managed files to their recorded prior bytes and leaves child-owned files alone.
        A different installed module cannot be substituted on resume.
    .EXAMPLE
        Repair-KadenRepo -Path . -Action Resume
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,
        [Parameter(Mandatory = $true)]
        [ValidateSet('Resume', 'Restore')]
        [string]$Action
    )

    $childRoot = [System.IO.Path]::GetFullPath($Path)
    if (-not (Test-Path -LiteralPath $childRoot)) {
        throw "KDN-TXN-PREFLIGHT-FAILED: Child repository path does not exist: $childRoot"
    }
    if (-not $PSCmdlet.ShouldProcess("$childRoot ($Action)", 'Repair-KadenRepo')) {
        return
    }

    Clear-KadenExpiredTransaction -ChildRoot $childRoot
    $open = Get-KadenOpenJournal -ChildRoot $childRoot
    if (-not $open) {
        throw 'KDN-TXN-PREFLIGHT-FAILED: No incomplete Kaden transaction is waiting.'
    }

    $txnRoot = Join-Path $childRoot (Join-Path '.kaden' 'transactions')
    $lockPath = Join-Path $txnRoot 'update.lock'
    $transactionId = if ($open.Journal) { [string]$open.Journal.transactionId } else { 'repair' }
    Lock-KadenUpdate -LockPath $lockPath -TransactionId $transactionId
    try {
        if ($Action -eq 'Resume') {
            Invoke-KadenRepairResume -ChildRoot $childRoot -OpenJournal $open
        }
        else {
            Invoke-KadenRepairRestore -ChildRoot $childRoot -OpenJournal $open
        }
    }
    finally {
        Remove-Item -LiteralPath $lockPath -Force -ErrorAction SilentlyContinue
    }

    return [pscustomobject]@{
        Succeeded = $true
        Path      = $childRoot
        Action    = $Action
    }
}