ceylon-runtime 0.1.3

A Rust-based agent mesh framework for building local and distributed AI agent systems
Documentation
# Ceylon Runtime - Smart Publish Script
# Publishes crates in correct dependency order, skipping already-published versions
# Usage: .\publish-smart.ps1 [-DryRun] [-AllowDirty]

param(
    [switch]$DryRun,       # Preview what would be published without actually publishing
    [switch]$AllowDirty    # Allow uncommitted changes
)

$ErrorActionPreference = "Stop"

$runtimeDir = $PSScriptRoot
$cratesDir = Join-Path $runtimeDir "crates"

# IMPORTANT: Dependency order matters!
# 1. Core crates (no internal deps)
# 2. ceylon-runtime (depends on core crates)
# 3. Crates that depend on ceylon-runtime (server, cli)

$coreCrates = @(
    @{ Name = "ceylon-core"; Path = "ceylon-core" },
    @{ Name = "ceylon-observability"; Path = "ceylon-observability" },
    @{ Name = "ceylon-llm"; Path = "ceylon-llm" },
    @{ Name = "ceylon-local"; Path = "ceylon-local" },
    @{ Name = "ceylon-memory"; Path = "ceylon-memory" },
    @{ Name = "ceylon-mcp"; Path = "ceylon-mcp" }
)

# These depend on ceylon-runtime, so must be published AFTER it
$dependentCrates = @(
    @{ Name = "ceylon-server"; Path = "ceylon-server" },
    @{ Name = "ceylon-cli"; Path = "ceylon-cli" }
)

function Get-LocalVersion {
    param([string]$CargoTomlPath)
    
    $content = Get-Content $CargoTomlPath -Raw
    if ($content -match 'version\s*=\s*"([^"]+)"') {
        return $matches[1]
    }
    return $null
}

function Get-CratesIoVersion {
    param([string]$CrateName)
    
    try {
        $response = Invoke-RestMethod -Uri "https://crates.io/api/v1/crates/$CrateName" -TimeoutSec 10
        return $response.crate.max_version
    }
    catch {
        return $null
    }
}

function Compare-Versions {
    param([string]$Local, [string]$Published)
    
    if (-not $Published) { return "NEW" }
    if ($Local -eq $Published) { return "SAME" }
    
    $localParts = $Local -split '\.'
    $pubParts = $Published -split '\.'
    
    for ($i = 0; $i -lt 3; $i++) {
        $l = [int]($localParts[$i] -replace '[^0-9]', '')
        $p = [int]($pubParts[$i] -replace '[^0-9]', '')
        if ($l -gt $p) { return "NEWER" }
        if ($l -lt $p) { return "OLDER" }
    }
    return "SAME"
}

function Check-Crate {
    param($Crate, [string]$BasePath)
    
    $cratePath = Join-Path $BasePath $Crate.Path
    $cargoToml = Join-Path $cratePath "Cargo.toml"
    
    if (-not (Test-Path $cargoToml)) { return $null }
    
    $localVersion = Get-LocalVersion $cargoToml
    $publishedVersion = Get-CratesIoVersion $Crate.Name
    $comparison = Compare-Versions $localVersion $publishedVersion
    
    return @{
        Name             = $Crate.Name
        Path             = $cratePath
        LocalVersion     = $localVersion
        PublishedVersion = $publishedVersion
        Status           = $comparison
    }
}

function Show-CrateStatus {
    param($Info)
    
    switch ($Info.Status) {
        "NEW" { Write-Host "  [NEW]  $($Info.Name) v$($Info.LocalVersion)" -ForegroundColor Green }
        "NEWER" { Write-Host "  [BUMP] $($Info.Name) v$($Info.LocalVersion) (was: v$($Info.PublishedVersion))" -ForegroundColor Green }
        "SAME" { Write-Host "  [SKIP] $($Info.Name) v$($Info.LocalVersion) (already published)" -ForegroundColor DarkGray }
        "OLDER" { Write-Host "  [WARN] $($Info.Name) v$($Info.LocalVersion) < v$($Info.PublishedVersion)" -ForegroundColor Yellow }
    }
}

function Publish-Crate {
    param($Info, [switch]$AllowDirty)
    
    Write-Host "Publishing $($Info.Name) v$($Info.LocalVersion)..." -ForegroundColor Yellow
    
    Push-Location $Info.Path
    try {
        $args = @("publish")
        if ($AllowDirty) { $args += "--allow-dirty" }
        
        & cargo @args
        if ($LASTEXITCODE -ne 0) {
            Write-Host "Failed to publish $($Info.Name)" -ForegroundColor Red
            return $false
        }
        Write-Host "Successfully published $($Info.Name)" -ForegroundColor Green
        return $true
    }
    finally {
        Pop-Location
    }
}

Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "  Ceylon Runtime - Smart Publish" -ForegroundColor Cyan
if ($DryRun) { Write-Host "  (DRY RUN)" -ForegroundColor Yellow }
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""

# Phase 1: Check core crates
Write-Host "Phase 1: Core Crates" -ForegroundColor Magenta
$coreToPublish = @()
foreach ($crate in $coreCrates) {
    $info = Check-Crate $crate $cratesDir
    if ($info) {
        Show-CrateStatus $info
        if ($info.Status -in @("NEW", "NEWER")) { $coreToPublish += $info }
    }
}

# Phase 2: Check ceylon-runtime (depends on core crates)
Write-Host ""
Write-Host "Phase 2: Main Runtime" -ForegroundColor Magenta
$runtimeInfo = @{
    Name             = "ceylon-runtime"
    Path             = $runtimeDir
    LocalVersion     = Get-LocalVersion (Join-Path $runtimeDir "Cargo.toml")
    PublishedVersion = Get-CratesIoVersion "ceylon-runtime"
}
$runtimeInfo.Status = Compare-Versions $runtimeInfo.LocalVersion $runtimeInfo.PublishedVersion
Show-CrateStatus $runtimeInfo
$publishRuntime = $runtimeInfo.Status -in @("NEW", "NEWER")

# Phase 3: Check dependent crates (depend on ceylon-runtime)
Write-Host ""
Write-Host "Phase 3: Dependent Crates" -ForegroundColor Magenta
$dependentToPublish = @()
foreach ($crate in $dependentCrates) {
    $info = Check-Crate $crate $cratesDir
    if ($info) {
        Show-CrateStatus $info
        if ($info.Status -in @("NEW", "NEWER")) { $dependentToPublish += $info }
    }
}

# Summary
Write-Host ""
Write-Host "----------------------------------------" -ForegroundColor DarkGray
$totalCount = $coreToPublish.Count + $(if ($publishRuntime) { 1 } else { 0 }) + $dependentToPublish.Count

if ($totalCount -eq 0) {
    Write-Host ""
    Write-Host "Nothing to publish - all versions up to date!" -ForegroundColor Green
    exit 0
}

Write-Host ""
Write-Host "Publish order:" -ForegroundColor Cyan
$order = 1
foreach ($c in $coreToPublish) { Write-Host "  $order. $($c.Name)" -ForegroundColor White; $order++ }
if ($publishRuntime) { Write-Host "  $order. ceylon-runtime" -ForegroundColor White; $order++ }
foreach ($c in $dependentToPublish) { Write-Host "  $order. $($c.Name)" -ForegroundColor White; $order++ }
Write-Host ""

if ($DryRun) {
    Write-Host "DRY RUN complete. Run without -DryRun to publish." -ForegroundColor Yellow
    exit 0
}

# Publish in correct order
$waitTime = 30

# Phase 1: Publish core crates
foreach ($info in $coreToPublish) {
    if (-not (Publish-Crate $info -AllowDirty:$AllowDirty)) { exit 1 }
    Write-Host "Waiting ${waitTime}s for crates.io..." -ForegroundColor Gray
    Start-Sleep -Seconds $waitTime
}

# Phase 2: Publish ceylon-runtime
if ($publishRuntime) {
    if (-not (Publish-Crate $runtimeInfo -AllowDirty:$AllowDirty)) { exit 1 }
    Write-Host "Waiting ${waitTime}s for crates.io..." -ForegroundColor Gray
    Start-Sleep -Seconds $waitTime
}

# Phase 3: Publish dependent crates (AFTER ceylon-runtime)
foreach ($info in $dependentToPublish) {
    if (-not (Publish-Crate $info -AllowDirty:$AllowDirty)) { exit 1 }
    Write-Host "Waiting ${waitTime}s for crates.io..." -ForegroundColor Gray
    Start-Sleep -Seconds $waitTime
}

Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "  All crates published successfully!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan