Public/Initialize-KadenRepo.ps1

function Initialize-KadenRepo {
    <#
    .SYNOPSIS
        Initialize a child repository from the installed Kaden payload.
    .DESCRIPTION
        When this installed release channel is beta, validates the PascalCase beta
        invitation passphrase before any repository change. A missing or incorrectly
        formed -BetaInvitation fails with KDN-BETA-INVITATION-INVALID and does not
        change the repository. When the installed release channel is ga, beta acknowledgement
        is not requested. Then checks the embedded payload, applies allowlisted
        managed files, and writes `.kaden.json` / `.kaden.local.json`.
        When shared configuration is absent and `.sync-project-id` holds a valid
        project identity, that identity is recorded and the legacy file is left unchanged.
        A later general-availability install does not change an earlier installed copy.
        Missing starter READMEs are created under docs/adr/, docs/harness/, docs/harness/features/, and docs/wip/.
        A missing AGENTS.md is created with a project header and command table outside the markers.
        The markers are <!-- KADEN:START --> and <!-- KADEN:END -->.
        An existing AGENTS.md or .github/copilot-instructions.md with an ordered marker pair changes only between those markers.
        A file that has neither marker keeps its project text and receives the delimited block at the end.
        A malformed marker pair is left unchanged and listed on InstructionFindings.
        Project instruction overlays under .github/instructions/ are not modified.
        The base Copilot instructions file .github/copilot-instructions.md receives the same delimited block.
        -Stack selects which missing starter configs to seed. Existing matrix files
        are never overwritten. Recommended doc folders are created with starter
        READMEs when those READMEs are missing.
    .PARAMETER Path
        Child repository root to initialize.
    .PARAMETER ProjectId
        Project identity recorded in `.kaden.json` when shared configuration is new.
    .PARAMETER BetaInvitation
        PascalCase beta invitation required while the installed channel is beta.
        Consumers paste the passphrase a maintainer already gave them.
        New-KadenBetaInvitation is for the maintainer, not for consumers.
    .PARAMETER Stack
        Starter stack seeded when the matching files are missing.
        Valid values are Node, PowerShell, Python, SQL, Polyglot, and None.
        The default is None.
        None seeds .editorconfig, .gitattributes, and .vscode/settings.json.
        Node also seeds eslint.config.mjs, .jsbeautifyrc, stryker.config.mjs, and vitest.config.js.
        PowerShell also seeds PSScriptAnalyzerSettings.psd1, PowerShellLintPaths.psd1, and powershell-security.semgrep.yml.
        Python also seeds .pre-commit-config.yaml and requirements.txt.
        SQL also seeds .sqlfluff and .sqlfluffignore.
        Polyglot seeds every file named for Node, PowerShell, Python, and SQL.
        Existing matrix files are left unchanged on initialize and on update.
    .EXAMPLE
        # Maintainer dogfood. Consumers paste the passphrase they were given.
        $invite = New-KadenBetaInvitation
        Initialize-KadenRepo -Path . -ProjectId 'mac-test-suite' -BetaInvitation $invite
    .EXAMPLE
        # Maintainer dogfood with a stack seed. Consumers paste the passphrase they were given.
        $invite = New-KadenBetaInvitation
        Initialize-KadenRepo -Path . -ProjectId 'mac-test-suite' -BetaInvitation $invite -Stack Node
    .EXAMPLE
        # This installed module is beta. Omitting -BetaInvitation fails with
        # KDN-BETA-INVITATION-INVALID and does not change the repository.
        # A later package whose channel is ga accepts initialize without -BetaInvitation.
    .NOTES
        On the beta channel the failure code is KDN-BETA-INVITATION-INVALID.
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,

        [Parameter(Mandatory = $true)]
        [string]$ProjectId,

        [Parameter(Mandatory = $false)]
        [AllowEmptyString()]
        [string]$BetaInvitation,

        [Parameter(Mandatory = $false)]
        [ValidateSet('Node', 'PowerShell', 'Python', 'SQL', 'Polyglot', 'None')]
        [string]$Stack = 'None'
    )

    $childRoot = Resolve-KadenChildRoot -Path $Path
    if (-not (Test-Path -LiteralPath $childRoot)) {
        throw "KDN-TXN-PREFLIGHT-FAILED: Child repository path does not exist: $childRoot"
    }

    $channel = Get-KadenReleaseChannel
    if ($channel -eq 'ga') {
        $guidance = 'General-availability release: no beta invitation needed. Earlier installed copies stay on the machine unchanged.'
    }
    else {
        $invitation = Test-KadenBetaInvitation -Invitation ([string]$BetaInvitation)
        if (-not $invitation.Valid) {
            throw $invitation.Message
        }
        $guidance = $invitation.Message
    }

    if (-not $PSCmdlet.ShouldProcess($childRoot, 'Initialize-KadenRepo')) {
        return
    }

    $payload = Test-KadenPackagePayload
    if (-not $payload.Valid) {
        throw $payload.Message
    }

    $moduleVersion = Get-KadenRunningModuleVersion

    $effectiveProjectId = $ProjectId
    $sharedPath = Join-Path $childRoot '.kaden.json'
    if (-not (Test-Path -LiteralPath $sharedPath)) {
        $legacyProjectId = Get-KadenLegacyProjectId -ChildRoot $childRoot
        if (-not [string]::IsNullOrWhiteSpace($legacyProjectId)) {
            $effectiveProjectId = $legacyProjectId
        }
    }
    if (-not (Test-KadenProjectId -ProjectId $effectiveProjectId)) {
        throw 'KDN-PROJECT-ID-INVALID: ProjectId must be at most 64 characters of lowercase letters, digits, and single hyphens.'
    }

    $instructionFindings = @(Invoke-KadenManagedInstructionUpdate -ChildRoot $childRoot -ProjectId $effectiveProjectId `
            -Manifest $payload.Manifest -PayloadRoot (Get-KadenPayloadRoot) -ModuleVersion $moduleVersion -CreateMissingAgents)

    Add-KadenWorkspaceSeed -ChildRoot $childRoot -Stack $Stack

    return [pscustomobject]@{
        Succeeded            = $true
        Path                 = $childRoot
        ProjectId            = $effectiveProjectId
        AppliedVersion       = $moduleVersion
        Guidance             = $guidance
        InstructionFindings  = $instructionFindings
    }
}