tools/build-module.ps1

# Builds the distributable PowerShell module (dist/module/MaestroKit/) from the
# repo sources. The module wraps the canonical scripts — zero logic duplication:
# Install-Maestro / Test-MaestroKit / Invoke-MaestroSmokeInstall invoke the
# bundled Install-Maestro.ps1, tools/validate-bundle.ps1 and tools/smoke-install.ps1.
param(
    [string]$Root,
    [string]$ModuleName = 'MaestroKit',
    [string]$OutputDir
)

$ErrorActionPreference = "Stop"
if (-not $Root) { $Root = Split-Path -Parent $PSScriptRoot }
if (-not $OutputDir) { $OutputDir = Join-Path $Root ("dist/module/" + $ModuleName) }

$Version = ([System.IO.File]::ReadAllText((Join-Path $Root "VERSION"))).Trim()

# Latest CHANGELOG section becomes the gallery ReleaseNotes (flattened;
# single quotes doubled so the psd1 literal stays valid).
$clLines = (Get-Content -LiteralPath (Join-Path $Root "CHANGELOG.md")) -split "\r?\n"
$firstSection = ($clLines | Select-String -Pattern "^## " | Select-Object -First 1).LineNumber
$sectionLines = @()
for ($i = $firstSection - 1; $i -lt $clLines.Count; $i++) {
    if ($i -gt $firstSection - 1 -and $clLines[$i] -match "^## ") { break }
    if ($clLines[$i].Trim()) { $sectionLines += $clLines[$i].Trim() }
}
$ReleaseNotesFlat = ($sectionLines -join ' ').Replace("'", "''")

if (Test-Path -LiteralPath $OutputDir) { Remove-Item -LiteralPath $OutputDir -Recurse -Force }
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null

foreach ($item in @("skills", "references", "agents", "tools")) {
    Copy-Item -LiteralPath (Join-Path $Root $item) -Destination (Join-Path $OutputDir $item) -Recurse -Force
}
foreach ($file in @("Install-Maestro.ps1", "LICENSE", "CHANGELOG.md", "VERSION", "README.md")) {
    Copy-Item -LiteralPath (Join-Path $Root $file) -Destination (Join-Path $OutputDir $file) -Force
}

$manifest = @"
@{
    RootModule = '$($ModuleName).psm1'
    ModuleVersion = '$Version'
    GUID = 'b7e3a9c4-5d18-4f6a-9c2e-1a0d8f4b7e33'
    Author = 'Arthur Biazon Machado'
    Description = 'MaestroKit - plan/implement/test/document workflow installer, validators and packaging for AI coding agents.'
    Copyright = '(c) 2026 Arthur Biazon Machado. MIT licensed.'
    PowerShellVersion = '7.0'
    CompatiblePSEditions = @('Core')
    FunctionsToExport = @('Install-Maestro', 'Test-MaestroKit', 'Invoke-MaestroSmokeInstall')
    PrivateData = @{
        PSData = @{
            Tags = @('AgentSkills', 'AI', 'ClaudeCode', 'OpenCode', 'OhMyPi', 'Workflow')
            LicenseUri = 'https://gitlab.com/arthur_b_machado/maestro/-/blob/main/LICENSE'
            ProjectUri = 'https://gitlab.com/arthur_b_machado/maestro'
            ReleaseNotes = '$ReleaseNotesFlat'
        }
    }
}
"@

Set-Content -LiteralPath (Join-Path $OutputDir "$($ModuleName).psd1") -Value $manifest -Encoding UTF8

$psm1 = @'
# MaestroKit distribution module. Thin wrappers over the canonical scripts
# shipped in this directory — the git repo remains the single source of truth.

$script:BundleRoot = $PSScriptRoot

<#
.SYNOPSIS
Installs the Maestro bundle (skills, references, agents) into a target repo
(-Scope Project, the default) or into your profile (-Scope User).
.NOTES
Audience: everyone - primary deployment entry point.
.EXAMPLE
Install-Maestro -Target D:\repos\my-app -Locations .omp,.claude -Force
.EXAMPLE
Install-Maestro -Scope User -Locations .omp,.claude -Force
#>
function Install-Maestro {
    [CmdletBinding()]
    param(
        [string]$Target = (Get-Location).Path,
        [ValidateSet('Project', 'User')][string]$Scope = 'Project',
        [string[]]$Locations = @(".agents"),
        [switch]$Clean,
        [switch]$Force
    )
    $invokeArgs = @{ Scope = $Scope; Locations = $Locations; Clean = $Clean; Force = $Force }
    if ($PSBoundParameters.ContainsKey('Target')) { $invokeArgs.Target = $Target }
    & (Join-Path $script:BundleRoot "Install-Maestro.ps1") @invokeArgs
}

<#
.SYNOPSIS
Runs the source-bundle consistency validator against a checkout of the Maestro repo.
.NOTES
Audience: maintainers + end users running post-install self-checks.
#>
function Test-MaestroKit {
    [CmdletBinding()]
    param(
        [string]$Root,
        [string]$ToolsDir = (Join-Path $script:BundleRoot "tools")
    )
    $validator = Join-Path $ToolsDir "validate-bundle.ps1"
    $invokeArgs = @{}
    if ($Root) { $invokeArgs.Root = $Root }
    & $validator @invokeArgs
}

<#
.SYNOPSIS
End-to-end install gate: installs to a temp dir and asserts structure, substitution, version stamp.
.NOTES
Audience: maintainers + end users verifying their installed copy.
#>
function Invoke-MaestroSmokeInstall {
    [CmdletBinding()]
    param(
        [string]$Root,
        [switch]$Keep
    )
    $smoke = Join-Path $script:BundleRoot "tools/smoke-install.ps1"
    $invokeArgs = @{}
    if ($Root) { $invokeArgs.Root = $Root }
    if ($Keep) { $invokeArgs.Keep = $true }
    & $smoke @invokeArgs
}

Export-ModuleMember -Function Install-Maestro, Test-MaestroKit, Invoke-MaestroSmokeInstall
'@

Set-Content -LiteralPath (Join-Path $OutputDir "$($ModuleName).psm1") -Value $psm1 -Encoding UTF8

Write-Host ("module built: " + $OutputDir + " (v" + $Version + ")")