src/public/Invoke-AitherProtocol.ps1

function Invoke-AitherProtocol {
    <#
    .SYNOPSIS
        Protocol handler for aither:// URLs

    .DESCRIPTION
        Handles deep links from browser/notifications/shortcuts:
        - aither://dashboard
        - aither://service/{name}/restart
        - aither://logs/{service}
        - aither://agent/{name}/ask?q={query}
        - aither://tools/{category}/{action}

    .PARAMETER Uri
        The aither:// URI to handle

    .EXAMPLE
        Invoke-AitherProtocol "aither://service/moltbook/restart"

    .EXAMPLE
        Invoke-AitherProtocol "aither://dashboard"
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position = 0, ValueFromPipeline)]
        [string]$Uri
    )

    process {
        # Helper for toast notifications (BurntToast)
        function Send-ProtocolNotification {
            param($Title, $Message, $Type = 'Info')
            if (-not (Get-Module BurntToast -ErrorAction SilentlyContinue)) {
                if (Get-Module -ListAvailable -Name BurntToast -ErrorAction SilentlyContinue) {
                    Import-Module BurntToast -ErrorAction SilentlyContinue
                }
            }
            if (Get-Command New-BurntToastNotification -ErrorAction SilentlyContinue) {
                $emoji = @{ Info = 'ℹ️'; Success = '✅'; Warning = '⚠️'; Error = '❌' }[$Type]
                $iconPath = Join-Path $script:ProjectRoot 'assets/icons/aitheros-logo.png'
                $params = @{ Text = @("$emoji $Title", $Message) }
                if (Test-Path $iconPath) { $params.AppLogo = $iconPath }
                New-BurntToastNotification @params
            }
            else {
                # Fallback to Write-Host
                $prefix = @{ Info = '[i]'; Success = '[OK]'; Warning = '[!]'; Error = '[X]' }[$Type]
                Write-Host "$prefix $Title - $Message" -ForegroundColor $(
                    @{ Info = 'Cyan'; Success = 'Green'; Warning = 'Yellow'; Error = 'Red' }[$Type]
                )
            }
        }

        try {
            # Clean URI
            $Uri = $Uri.Trim('"', "'", ' ')

    # Resolve project context for URLs
    $ctx = Get-AitherLiveContext
    $dashboardBase = "http://localhost:3000"
    $orchestratorBase = $ctx.OrchestratorURL
    $prefix = $ctx.ContainerPrefix

    # Parse URI
    Add-Type -AssemblyName System.Web
    $parsed = [System.Uri]::new($Uri)
    $action = $parsed.Host
    $pathParts = $parsed.AbsolutePath.Trim('/') -split '/'
    $query = [System.Web.HttpUtility]::ParseQueryString($parsed.Query)

    Write-Host "Handling: $Uri" -ForegroundColor Cyan
    Write-Host " Action: $action, Path: $($pathParts -join '/'), Query: $($parsed.Query)" -ForegroundColor Gray

    switch ($action) {
        'dashboard' {
            Start-Process $dashboardBase
            Send-ProtocolNotification "Dashboard" "Opening dashboard..."
        }

        'service' {
            $serviceName = $pathParts[0]
            $operation = if ($pathParts.Count -gt 1) { $pathParts[1] } else { 'status' }

            switch ($operation) {
                'restart' {
                    Send-ProtocolNotification "Restarting" "$serviceName is restarting..." "Info"
                    try {
                        if ($orchestratorBase) {
                            $result = Invoke-RestMethod -Uri "$orchestratorBase/api/services/$serviceName/restart" -Method POST -TimeoutSec 30
                            Send-ProtocolNotification "Restarted" "$serviceName restart initiated" "Success"
                        } else { throw "No orchestrator configured" }
                    }
                    catch {
                        $containerName = "$prefix-$($serviceName.ToLower() -replace $prefix, '')"
                        docker restart $containerName 2>&1 | Out-Null
                        Send-ProtocolNotification "Restarted" "$serviceName restarted via Docker" "Success"
                    }
                }
                'stop' {
                    docker stop "$prefix-$($serviceName.ToLower() -replace $prefix, '')" 2>&1 | Out-Null
                    Send-ProtocolNotification "Stopped" "$serviceName stopped" "Warning"
                }
                'start' {
                    docker start "$prefix-$($serviceName.ToLower() -replace $prefix, '')" 2>&1 | Out-Null
                    Send-ProtocolNotification "Started" "$serviceName started" "Success"
                }
                'logs' {
                    Start-Process "$dashboardBase/logs?service=$serviceName"
                }
                'status' {
                    try {
                        if (-not $orchestratorBase) { throw "No orchestrator configured" }
                        $health = Invoke-RestMethod -Uri "$orchestratorBase/services/$serviceName/health" -TimeoutSec 5
                        Send-ProtocolNotification "$serviceName Status" "Status: $($health.status)" "Success"
                    }
                    catch {
                        Send-ProtocolNotification "$serviceName Status" "Unable to reach service" "Error"
                    }
                }
            }
        }

        'logs' {
            $serviceName = $pathParts[0]
            if ($serviceName) {
                Start-Process "$dashboardBase/logs?service=$serviceName"
            } else {
                Start-Process "$dashboardBase/logs"
            }
        }

        'agent' {
            $agentName = $pathParts[0]
            $agentAction = if ($pathParts.Count -gt 1) { $pathParts[1] } else { 'chat' }
            $queryText = $query['q']

            switch ($agentAction) {
                'ask' {
                    if ($queryText) {
                        Start-Process "$dashboardBase/chat?agent=$agentName&q=$([uri]::EscapeDataString($queryText))"
                    }
                }
                'chat' {
                    Start-Process "$dashboardBase/chat?agent=$agentName"
                }
                default {
                    Start-Process "$dashboardBase/chat?agent=$agentName"
                }
            }
        }
        
        'vision' {
            $visionAction = $pathParts[0]
            $filePath = $query['file']
            
            switch ($visionAction) {
                'analyze' {
                    Send-ProtocolNotification "AitherVision" "Analyzing image..." "Info"
                    # TODO: Call vision service
                }
                'ocr' {
                    Send-ProtocolNotification "AitherVision" "Extracting text..." "Info"
                    # TODO: Call OCR service
                }
            }
        }
        
        'rag' {
            $ragAction = $pathParts[0]
            $filePath = $query['file']
            
            switch ($ragAction) {
                'index' {
                    Send-ProtocolNotification "RAG Index" "Indexing document..." "Info"
                    # TODO: Call RAG indexing
                }
                'search' {
                    $searchQuery = $query['q']
                    Start-Process "$dashboardBase/search?q=$([uri]::EscapeDataString($searchQuery))"
                }
            }
        }
        
        'tools' {
            $category = $pathParts[0]
            $tool = if ($pathParts.Count -gt 1) { $pathParts[1] } else { '' }
            
            switch ($category) {
                'json' {
                    switch ($tool) {
                        'validate' {
                            $clipboard = Get-Clipboard
                            try {
                                $null = $clipboard | ConvertFrom-Json
                                Send-ProtocolNotification "JSON Valid" "The JSON is valid ✓" "Success"
                            }
                            catch {
                                Send-ProtocolNotification "JSON Invalid" $_.Exception.Message "Error"
                            }
                        }
                        'format' {
                            $clipboard = Get-Clipboard
                            try {
                                $formatted = $clipboard | ConvertFrom-Json | ConvertTo-Json -Depth 10
                                Set-Clipboard $formatted
                                Send-ProtocolNotification "JSON Formatted" "Pretty JSON copied to clipboard" "Success"
                            }
                            catch {
                                Send-ProtocolNotification "Format Failed" $_.Exception.Message "Error"
                            }
                        }
                    }
                }
                'code' {
                    switch ($tool) {
                        'lint' {
                            Send-ProtocolNotification "Code Lint" "Linting code..." "Info"
                        }
                    }
                }
            }
        }
        
        'settings' {
            Start-Process "$dashboardBase/settings"
        }
        
        'health' {
            try {
                if (-not $orchestratorBase) { throw "No orchestrator configured" }
                $health = Invoke-RestMethod -Uri "$orchestratorBase/health-check" -TimeoutSec 10
                $healthy = ($health.services | Where-Object { $_.status -eq 'healthy' }).Count
                $total = $health.services.Count
                $status = if ($healthy -eq $total) { 'Success' } else { 'Warning' }
                Send-ProtocolNotification "System Health" "$healthy of $total services healthy" $status
            }
            catch {
                Send-ProtocolNotification "Health Check" "Could not reach orchestrator" "Error"
            }
        }
        
        'deploy' {
            Send-ProtocolNotification "Deploying" "Starting services..." "Info"
            $genesisScript = Join-Path $script:ProjectRoot "start_genesis.ps1"
            if ($IsWindows) {
                Start-Process pwsh -ArgumentList "-NoExit", "-File", $genesisScript
            } else {
                # Linux/Mac
                Start-Process pwsh -ArgumentList "-File", $genesisScript
            }
        }

        'inspect' {
            # Deep investigation: opens logs + dashboard + status in one click
            $serviceName = $pathParts[0]
            if ($serviceName) {
                $containerName = "$prefix-$($serviceName.ToLower() -replace $prefix, '')"

                # Open dashboard log page
                Start-Process "$dashboardBase/logs?service=$serviceName"
                
                # Open a terminal with live docker logs
                $wt = Get-Command wt -ErrorAction SilentlyContinue
                if ($wt) {
                    Start-Process wt -ArgumentList "-w", "aither", "nt", "--title", "$serviceName inspect", "docker", "logs", "-f", "--tail", "200", $containerName
                }
                else {
                    Start-Process pwsh -ArgumentList "-NoExit", "-Command", "docker logs -f --tail 200 $containerName"
                }
                
                # Show quick status notification
                try {
                    $inspect = docker inspect --format '{{.State.Status}} (exit {{.State.ExitCode}})' $containerName 2>&1
                    Send-ProtocolNotification "🔍 $serviceName" "Container: $inspect" "Info"
                }
                catch {
                    Send-ProtocolNotification "🔍 $serviceName" "Container not found" "Warning"
                }
            }
            else {
                Start-Process "$dashboardBase/monitoring"
            }
        }
        
        'container' {
            # Direct Docker container operations
            $containerName = $pathParts[0]
            $containerAction = if ($pathParts.Count -gt 1) { $pathParts[1] } else { 'logs' }
            
            if (-not $containerName) {
                Send-ProtocolNotification "Container" "No container specified" "Warning"
            }
            else {
                switch ($containerAction) {
                    'logs' {
                        $wt = Get-Command wt -ErrorAction SilentlyContinue
                        if ($wt) {
                            Start-Process wt -ArgumentList "-w", "aither", "nt", "--title", "$containerName logs", "docker", "logs", "-f", "--tail", "200", $containerName
                        }
                        else {
                            Start-Process pwsh -ArgumentList "-NoExit", "-Command", "docker logs -f --tail 200 $containerName"
                        }
                    }
                    'exec' {
                        $wt = Get-Command wt -ErrorAction SilentlyContinue
                        if ($wt) {
                            Start-Process wt -ArgumentList "-w", "aither", "nt", "--title", "$containerName shell", "docker", "exec", "-it", $containerName, "/bin/sh"
                        }
                        else {
                            Start-Process pwsh -ArgumentList "-NoExit", "-Command", "docker exec -it $containerName /bin/sh"
                        }
                    }
                    'restart' {
                        docker restart $containerName 2>&1 | Out-Null
                        Send-ProtocolNotification "Container Restarted" "$containerName restarted" "Success"
                    }
                    'status' {
                        try {
                            $state = docker inspect --format '{{json .State}}' $containerName 2>&1 | ConvertFrom-Json
                            $msg = "Status: $($state.Status), Running: $($state.Running), ExitCode: $($state.ExitCode)"
                            $sev = if ($state.Running) { 'Success' } else { 'Error' }
                            Send-ProtocolNotification "$containerName Status" $msg $sev
                        }
                        catch {
                            Send-ProtocolNotification "$containerName" "Could not inspect container" "Error"
                        }
                    }
                }
            }
        }
        
        default {
            Send-ProtocolNotification "Unknown Action" "aither://$action not recognized" "Warning"
        }
    }
}
catch {
    Send-ProtocolNotification "Protocol Error" $_.Exception.Message "Error"
    Write-Error $_
}
    } # end process
} # end function