sync-mesh.ps1 (3996B)
1 # sync-mesh.ps1 — Materialize remote squad state locally 2 # 3 # Reads mesh.json, fetches remote squads into local directories. 4 # Run before agent reads. No daemon. No service. ~40 lines. 5 # 6 # Usage: .\sync-mesh.ps1 [path-to-mesh.json] 7 # .\sync-mesh.ps1 -Init [path-to-mesh.json] 8 # Requires: git 9 param( 10 [switch]$Init, 11 [string]$MeshJson = "mesh.json" 12 ) 13 $ErrorActionPreference = "Stop" 14 15 # Handle -Init mode 16 if ($Init) { 17 if (-not (Test-Path $MeshJson)) { 18 Write-Host "❌ $MeshJson not found" 19 exit 1 20 } 21 22 Write-Host "🚀 Initializing mesh state repository..." 23 $config = Get-Content $MeshJson -Raw | ConvertFrom-Json 24 $squads = $config.squads.PSObject.Properties.Name 25 26 # Create squad directories with placeholder SUMMARY.md 27 foreach ($squad in $squads) { 28 if (-not (Test-Path $squad)) { 29 New-Item -ItemType Directory -Path $squad | Out-Null 30 Write-Host " ✓ Created $squad/" 31 } else { 32 Write-Host " • $squad/ exists (skipped)" 33 } 34 35 $summaryPath = "$squad/SUMMARY.md" 36 if (-not (Test-Path $summaryPath)) { 37 "# $squad`n`n_No state published yet._" | Set-Content $summaryPath 38 Write-Host " ✓ Created $summaryPath" 39 } else { 40 Write-Host " • $summaryPath exists (skipped)" 41 } 42 } 43 44 # Generate root README.md 45 if (-not (Test-Path "README.md")) { 46 $readme = @" 47 # Squad Mesh State Repository 48 49 This repository tracks published state from participating squads. 50 51 ## Participating Squads 52 53 "@ 54 foreach ($squad in $squads) { 55 $zone = $config.squads.$squad.zone 56 $readme += "- **$squad** (Zone: $zone)`n" 57 } 58 $readme += @" 59 60 Each squad directory contains a ``SUMMARY.md`` with their latest published state. 61 State is synchronized using ``sync-mesh.sh`` or ``sync-mesh.ps1``. 62 "@ 63 $readme | Set-Content "README.md" 64 Write-Host " ✓ Created README.md" 65 } else { 66 Write-Host " • README.md exists (skipped)" 67 } 68 69 Write-Host "" 70 Write-Host "✅ Mesh state repository initialized" 71 exit 0 72 } 73 74 $config = Get-Content $MeshJson -Raw | ConvertFrom-Json 75 76 # Zone 2: Remote-trusted — git clone/pull 77 foreach ($entry in $config.squads.PSObject.Properties | Where-Object { $_.Value.zone -eq "remote-trusted" }) { 78 $squad = $entry.Name 79 $source = $entry.Value.source 80 $ref = if ($entry.Value.ref) { $entry.Value.ref } else { "main" } 81 $target = $entry.Value.sync_to 82 83 if (Test-Path "$target/.git") { 84 git -C $target pull --rebase --quiet 2>$null 85 if ($LASTEXITCODE -ne 0) { Write-Host "⚠ ${squad}: pull failed (using stale)" } 86 } else { 87 New-Item -ItemType Directory -Force -Path (Split-Path $target -Parent) | Out-Null 88 git clone --quiet --depth 1 --branch $ref $source $target 2>$null 89 if ($LASTEXITCODE -ne 0) { Write-Host "⚠ ${squad}: clone failed (unavailable)" } 90 } 91 } 92 93 # Zone 3: Remote-opaque — fetch published contracts 94 foreach ($entry in $config.squads.PSObject.Properties | Where-Object { $_.Value.zone -eq "remote-opaque" }) { 95 $squad = $entry.Name 96 $source = $entry.Value.source 97 $target = $entry.Value.sync_to 98 $auth = $entry.Value.auth 99 100 New-Item -ItemType Directory -Force -Path $target | Out-Null 101 $params = @{ Uri = $source; OutFile = "$target/SUMMARY.md"; UseBasicParsing = $true } 102 if ($auth -eq "bearer") { 103 $tokenVar = ($squad.ToUpper() -replace '-', '_') + "_TOKEN" 104 $token = [Environment]::GetEnvironmentVariable($tokenVar) 105 if ($token) { $params.Headers = @{ Authorization = "Bearer $token" } } 106 } 107 try { Invoke-WebRequest @params -ErrorAction Stop } 108 catch { "# ${squad} — unavailable ($(Get-Date))" | Set-Content "$target/SUMMARY.md" } 109 } 110 111 Write-Host "✓ Mesh sync complete"