Public/Dashboard.ps1

# ---------------------------------------------------------------------------
# Formatted display -- ANSI-enhanced dashboard with interactive TUI mode
# ---------------------------------------------------------------------------

# ANSI escape sequences (PS5.1 compatible via [char]27)
$script:ESC   = [char]27
$script:RESET = "$($script:ESC)[0m"
$script:BOLD  = "$($script:ESC)[1m"
$script:REVERSE = "$($script:ESC)[7m"
$script:DIM   = "$($script:ESC)[90m"

# Status colors per UI-SPEC
$script:COLOR_LIVE    = "$($script:ESC)[92m"   # Bright Green
$script:COLOR_SUSP    = "$($script:ESC)[93m"   # Bright Yellow
$script:COLOR_DEAD    = "$($script:ESC)[91m"   # Bright Red
$script:COLOR_HIDDEN  = "$($script:ESC)[90m"   # Dark Gray
$script:COLOR_HEADER  = "$($script:ESC)[1;97m" # Bold White
$script:COLOR_PATH    = "$($script:ESC)[36m"   # Cyan
$script:COLOR_ID      = "$($script:ESC)[37m"   # White
$script:COLOR_NOTES   = "$($script:ESC)[35m"   # Magenta
$script:COLOR_WARN    = "$($script:ESC)[93m"   # Bright Yellow
$script:COLOR_ERROR   = "$($script:ESC)[91m"   # Bright Red

# Cursor control sequences for buffered rendering
$script:HIDE_CURSOR = "$($script:ESC)[?25l"
$script:SHOW_CURSOR = "$($script:ESC)[?25h"

function Format-TTStatusBadge {
    <#
    .SYNOPSIS Returns an 8-char ANSI-colored status badge for a session.
    #>

    param(
        [PSCustomObject]$Session,
        [bool]$IsSuspended = $false
    )
    if ($IsSuspended) {
        return "$($script:COLOR_SUSP)[SUSP ]$($script:RESET)"
    }
    if ($Session.Hidden -eq $true) {
        return "$($script:COLOR_HIDDEN)[HIDDEN]$($script:RESET)"
    }
    if ($Session.IsAlive) {
        return "$($script:COLOR_LIVE)[LIVE ]$($script:RESET)"
    }
    return "$($script:COLOR_DEAD)[DEAD ]$($script:RESET)"
}

function Format-TTSessionRow {
    <#
    .SYNOPSIS Formats a single session as a colored row string.
    #>

    param(
        [PSCustomObject]$Session,
        [bool]$IsSuspended = $false
    )
    $badge = Format-TTStatusBadge -Session $Session -IsSuspended $IsSuspended
    $id = "$($script:COLOR_ID)$($Session.Id)$($script:RESET)"
    $pid_str = if ($IsSuspended) { ' - ' } else { '{0,5}' -f $Session.Pid }
    $shell = "$($script:DIM)$($Session.Shell)$($script:RESET)"
    $cwd = "$($script:COLOR_PATH)$($Session.WorkingDirectory)$($script:RESET)"
    $updated = "$($script:DIM)$(if ($Session.LastUpdated) { ([datetime]$Session.LastUpdated).ToString('HH:mm:ss') } elseif ($Session.SuspendedTime) { ([datetime]$Session.SuspendedTime).ToString('HH:mm:ss') } else { '' })$($script:RESET)"

    " $id $badge $pid_str $shell $cwd $updated"
}

function ConvertTo-DeduplicatedSessionList {
    <#
    .SYNOPSIS Deduplicate sessions by PID, keeping the most recently updated entry per PID.
    #>

    param($Sessions)
    $byPid = @{}
    foreach ($s in $Sessions) {
        $key = $s.Pid
        if ($byPid.ContainsKey($key)) {
            $existing = $byPid[$key]
            $existingTime = if ($existing.LastUpdated) { [datetime]$existing.LastUpdated } else { [datetime]::MinValue }
            $newTime = if ($s.LastUpdated) { [datetime]$s.LastUpdated } else { [datetime]::MinValue }
            if ($newTime -gt $existingTime) {
                $byPid[$key] = $s
            }
        } else {
            $byPid[$key] = $s
        }
    }
    @($byPid.Values)
}

function Show-TTActionMenu {
    <#
    .SYNOPSIS Displays an action menu for the selected session in interactive TUI mode.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSAvoidUsingWriteHost', '',
        Justification = 'Interactive TUI display function; Write-Host is intentional.'
    )]
    param([PSCustomObject]$Session)

    $isSuspended = ($Session.Type -eq 'suspended')

    # Detect if this session shares a WT host with the current terminal
    $isOwnWTHost = $false
    if (-not $isSuspended -and $Session.IsAlive) {
        try {
            $sessionCim = Get-CimInstance Win32_Process -Filter "ProcessId=$($Session.Pid)" -ErrorAction SilentlyContinue
            $selfCim = Get-CimInstance Win32_Process -Filter "ProcessId=$PID" -ErrorAction SilentlyContinue
            if ($sessionCim -and $selfCim) {
                # Both are children of the same WT? Walk up to find WT parent
                $sessionParent = $sessionCim.ParentProcessId
                $selfParent = $selfCim.ParentProcessId
                if ($sessionParent -eq $selfParent) {
                    $isOwnWTHost = $true
                }
            }
        } catch { }
    }

    Write-Host ""
    Write-Host " $($script:COLOR_HEADER)Actions for session $($Session.Id):$($script:RESET)"
    Write-Host " $($script:DIM)$('-' * 40)$($script:RESET)"
    Write-Host " [O] Open terminal here"
    if (-not $isSuspended) {
        Write-Host " [S] Suspend session"
    }
    if ($isSuspended) {
        Write-Host " [R] Resume session"
    }
    if (-not $isSuspended -and $Session.IsAlive) {
        if ($Session.Hidden) {
            Write-Host " [W] Show window"
        } elseif ($isOwnWTHost) {
            Write-Host " $($script:DIM)[H] Hide window (same WT host -- would hide this terminal too)$($script:RESET)"
        } else {
            Write-Host " [H] Hide window"
        }
    }
    Write-Host " [N] View / edit notes"
    Write-Host " [Q] Back"
    Write-Host ""

    $actionKey = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
    $char = [char]$actionKey.Character

    try {
        switch ($char.ToString().ToUpper()) {
            'O' { Open-TerminalAt -Directory $Session.WorkingDirectory }
            'S' { if (-not $isSuspended) { Suspend-TTSession -Id $Session.Id } }
            'R' { if ($isSuspended) { Resume-TTSession -Id $Session.Id } }
            'W' { if ($Session.Hidden) { Show-TTWindow -Id $Session.Id } }
            'H' {
                if (-not $Session.Hidden -and $Session.IsAlive) {
                    if ($isOwnWTHost) {
                        Write-Host " $($script:COLOR_WARN)Skipped: hiding this session would hide your current terminal.$($script:RESET)"
                        Start-Sleep -Milliseconds 1500
                    } else {
                        Hide-TTWindow -Id $Session.Id
                    }
                }
            }
            'N' {
                Write-Host " Current notes: $($script:COLOR_NOTES)$($Session.Notes)$($script:RESET)"
                [Console]::CursorVisible = $true
                $newNote = Read-Host " Enter new note (blank to keep)"
                [Console]::CursorVisible = $false
                if ($newNote) {
                    Set-TTNote -Id $Session.Id -Note $newNote
                }
            }
            'Q' { return }
            default { return }
        }
    } catch {
        Write-Host " $($script:COLOR_ERROR)Error: action failed - $($_.Exception.Message). Press any key to continue.$($script:RESET)"
        $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
    }
}

function Get-TTSessionVisibility {
    <#
    .SYNOPSIS Classify sessions as 'tab', 'standalone', or 'background'.
    .DESCRIPTION Uses session metadata (WTHost, AutoDiscovered) and a fast batch
                 Get-Process check for MainWindowHandle. No CIM/WMI queries.
    #>

    param($Sessions)
    $visibility = @{}

    # Build WT PID set for fallback parent check
    $wtPids = @{}
    Get-Process -Name WindowsTerminal -ErrorAction SilentlyContinue |
        ForEach-Object { $wtPids[$_.Id] = $true }

    # Collect PIDs that need further checks
    $checkPids = [System.Collections.Generic.List[int]]::new()

    foreach ($s in $Sessions) {
        $pid = $s.Pid
        if ($s.WTHost) {
            # Session has explicit WT host recorded — it's a real tab
            $visibility[$pid] = 'tab'
        } elseif (-not $s.AutoDiscovered) {
            # Registered by the prompt hook — definitely a real interactive terminal
            $visibility[$pid] = 'standalone'
        } else {
            # Auto-discovered without WTHost — check parent or window
            $checkPids.Add($pid)
        }
    }

    # For unknowns: fast parent PID check via Get-Process (PS7 has .Parent)
    # then fall back to MainWindowHandle check
    if ($checkPids.Count -gt 0) {
        $procIndex = @{}
        $shellNames = @('pwsh', 'powershell', 'cmd', 'bash')
        Get-Process -Name $shellNames -ErrorAction SilentlyContinue |
            ForEach-Object { $procIndex[$_.Id] = $_ }

        foreach ($pid in $checkPids) {
            $proc = if ($procIndex.ContainsKey($pid)) { $procIndex[$pid] } else { $null }
            if (-not $proc) {
                $visibility[$pid] = 'background'
                continue
            }

            # PS7: check if parent is a WT process
            $parentId = try { $proc.Parent.Id } catch { $null }
            if ($parentId -and $wtPids.ContainsKey($parentId)) {
                $visibility[$pid] = 'tab'
            } elseif ($proc.MainWindowHandle -ne [IntPtr]::Zero) {
                $visibility[$pid] = 'standalone'
            } else {
                $visibility[$pid] = 'background'
            }
        }
    }

    return $visibility
}

function Build-TTUnifiedSessionList {
    <#
    .SYNOPSIS Build a unified, deduplicated session list for the interactive TUI.
    .PARAMETER ShowAll If true, include background processes. If false, only tabs and standalone windows.
    #>

    param($Sessions, $Suspended, [bool]$ShowAll = $false)

    # Deduplicate active sessions by PID
    $deduped = ConvertTo-DeduplicatedSessionList $Sessions

    # Classify visibility
    $visibility = Get-TTSessionVisibility $deduped
    $bgCount = 0

    $list = [System.Collections.Generic.List[object]]::new()
    foreach ($s in $deduped) {
        $vis = if ($visibility.ContainsKey($s.Pid)) { $visibility[$s.Pid] } else { 'background' }
        if (-not $ShowAll -and $vis -eq 'background') {
            $bgCount++
            continue
        }
        $item = [PSCustomObject]@{
            Id               = $s.Id
            Pid              = $s.Pid
            ProcessName      = $s.ProcessName
            Shell            = $s.Shell
            WorkingDirectory = $s.WorkingDirectory
            LastUpdated      = $s.LastUpdated
            IsAlive          = $s.IsAlive
            Hidden           = $s.Hidden
            Notes            = $s.Notes
            Tags             = $s.Tags
            Type             = if ($vis -eq 'background') { 'background' } else { 'active' }
            SuspendedTime    = $null
            Visibility       = $vis
        }
        $list.Add($item)
    }
    foreach ($s in $Suspended) {
        $item = [PSCustomObject]@{
            Id               = $s.Id
            Pid              = 0
            ProcessName      = $s.ProcessName
            Shell            = $s.Shell
            WorkingDirectory = $s.WorkingDirectory
            LastUpdated      = $null
            IsAlive          = $false
            Hidden           = $false
            Notes            = $s.Notes
            Tags             = $s.Tags
            Type             = 'suspended'
            SuspendedTime    = $s.SuspendedTime
            Visibility       = 'suspended'
        }
        $list.Add($item)
    }

    # Attach background count as a note property on the list for the footer
    $list | Add-Member -NotePropertyName BackgroundCount -NotePropertyValue $bgCount -Force -ErrorAction SilentlyContinue
    return $list
}

function Enter-TTInteractiveMode {
    <#
    .SYNOPSIS Enters interactive TUI mode with arrow key navigation and action menu.
    .DESCRIPTION Provides cursor-based session selection, auto-refresh at MonitorIntervalSeconds,
                 and an action menu for session management operations. Uses buffered rendering
                 to eliminate flicker, viewport scrolling for long lists, and PID deduplication.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSAvoidUsingWriteHost', '',
        Justification = 'Interactive TUI display function; Write-Host is intentional.'
    )]
    param($Sessions, $Suspended)

    # Input redirection guard
    if ([Console]::IsInputRedirected) {
        Write-Warning 'Interactive TUI requires a real console. Run Show-TTDashboard from an interactive terminal.'
        return
    }

    # Build unified, deduplicated session list (tabs + standalone windows only by default)
    $showAll = $false
    $allSessions = Build-TTUnifiedSessionList -Sessions $Sessions -Suspended $Suspended -ShowAll $showAll

    if ($allSessions.Count -eq 0) {
        Write-Host " $($script:COLOR_WARN)No sessions to display in interactive mode.$($script:RESET)"
        return
    }

    # Hide cursor and clear screen
    [Console]::Write($script:HIDE_CURSOR)
    try { [Console]::Clear() } catch { Clear-Host }

    $headerText = @(
        ""
        " $($script:COLOR_HEADER)TerminalTracker -- Session Dashboard$($script:RESET)"
        " $($script:DIM)$('-' * 70)$($script:RESET)"
        " $($script:DIM)ID STATUS PID SHELL CWD UPDATED$($script:RESET)"
        " $($script:DIM)$('-' * 70)$($script:RESET)"
    )
    $headerLines = $headerText.Count

    # Write header once
    foreach ($line in $headerText) { Write-Host $line }

    $selectedIndex = 0
    $viewportTop = 0
    $action = $null
    $lastRefresh = [DateTime]::Now
    $config = Get-TTConfig
    $refreshMs = $config.MonitorIntervalSeconds * 1000

    # Footer uses: scroll-up indicator (1) + scroll-down indicator (1) + separator (1) + help (1)
    $footerReserve = 4

    while ($action -ne 'Quit') {
        # Refresh data if interval elapsed
        $elapsed = ([DateTime]::Now - $lastRefresh).TotalMilliseconds
        if ($elapsed -ge $refreshMs) {
            $sessions = ConvertTo-FlatArray (Get-TTSession -IncludeHidden)
            $suspended = ConvertTo-FlatArray (Get-TTSuspended)
            $suspended = @($suspended | Where-Object { $_.Id -and $_.WorkingDirectory })
            $allSessions = Build-TTUnifiedSessionList -Sessions $sessions -Suspended $suspended -ShowAll $showAll
            $lastRefresh = [DateTime]::Now
        }

        # Dynamic viewport sizing
        $winHeight = 24
        try { $winHeight = [Console]::WindowHeight } catch { }
        $winWidth = 80
        try { $winWidth = [Console]::WindowWidth } catch { }
        $visibleRows = [Math]::Max(3, $winHeight - $headerLines - $footerReserve)

        # Clamp selectedIndex
        if ($allSessions.Count -eq 0) {
            $selectedIndex = 0
        } elseif ($selectedIndex -ge $allSessions.Count) {
            $selectedIndex = $allSessions.Count - 1
        }

        # Scroll viewport to keep selection visible
        if ($selectedIndex -lt $viewportTop) {
            $viewportTop = $selectedIndex
        } elseif ($selectedIndex -ge ($viewportTop + $visibleRows)) {
            $viewportTop = $selectedIndex - $visibleRows + 1
        }
        $maxTop = [Math]::Max(0, $allSessions.Count - $visibleRows)
        $viewportTop = [Math]::Max(0, [Math]::Min($viewportTop, $maxTop))
        $viewportEnd = [Math]::Min($viewportTop + $visibleRows, $allSessions.Count)

        # --- Build entire frame into a single buffer ---
        $buf = [System.Text.StringBuilder]::new(4096)

        # Position cursor at start of data area
        $null = $buf.Append("$($script:ESC)[$($headerLines + 1);1H")

        # Scroll-up indicator
        if ($viewportTop -gt 0) {
            $upText = " $($script:DIM)... $($viewportTop) more above ...$($script:RESET)"
            $null = $buf.AppendLine($upText.PadRight($winWidth))
        } else {
            $null = $buf.AppendLine(''.PadRight($winWidth))
        }

        # Visible session rows
        for ($i = $viewportTop; $i -lt $viewportEnd; $i++) {
            $s = $allSessions[$i]
            $isSusp = ($s.Type -eq 'suspended')
            $row = Format-TTSessionRow -Session $s -IsSuspended $isSusp
            if ($i -eq $selectedIndex) {
                $null = $buf.AppendLine("$($script:REVERSE)$row$($script:RESET)".PadRight($winWidth))
            } else {
                $null = $buf.AppendLine("$row".PadRight($winWidth))
            }
        }

        # Fill remaining rows if list shorter than viewport
        $rendered = $viewportEnd - $viewportTop
        for ($j = $rendered; $j -lt $visibleRows; $j++) {
            $null = $buf.AppendLine(''.PadRight($winWidth))
        }

        # Scroll-down indicator
        $remaining = $allSessions.Count - $viewportEnd
        if ($remaining -gt 0) {
            $downText = " $($script:DIM)... $remaining more below ...$($script:RESET)"
            $null = $buf.AppendLine($downText.PadRight($winWidth))
        } else {
            $null = $buf.AppendLine(''.PadRight($winWidth))
        }

        # Footer
        $refreshInterval = $config.MonitorIntervalSeconds
        $null = $buf.AppendLine(" $($script:DIM)$('-' * 70)$($script:RESET)".PadRight($winWidth))
        $pos = $selectedIndex + 1
        $total = $allSessions.Count
        $bgCount = 0
        if ($allSessions.PSObject.Properties['BackgroundCount']) { $bgCount = $allSessions.BackgroundCount }
        $bgHint = if ($bgCount -gt 0 -and -not $showAll) { " * A=show $bgCount bg" } elseif ($showAll) { ' * A=hide bg' } else { '' }
        $footerText = " $($script:DIM)Up/Dn/PgUp/PgDn * Enter=act * Q=quit * ${pos}/${total}${bgHint} * ${refreshInterval}s$($script:RESET)"
        $null = $buf.Append($footerText.PadRight($winWidth))

        # Write entire frame in one call -- eliminates flicker
        [Console]::Write($buf.ToString())

        # Wait for key with polling for auto-refresh
        while (-not [Console]::KeyAvailable) {
            Start-Sleep -Milliseconds 100
            $elapsed = ([DateTime]::Now - $lastRefresh).TotalMilliseconds
            if ($elapsed -ge $refreshMs) { break }
        }
        if (-not [Console]::KeyAvailable) { continue }

        $key = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
        switch ($key.VirtualKeyCode) {
            38 { $selectedIndex = [Math]::Max(0, $selectedIndex - 1) }                           # Up
            40 { $selectedIndex = [Math]::Min($allSessions.Count - 1, $selectedIndex + 1) }      # Down
            33 { $selectedIndex = [Math]::Max(0, $selectedIndex - $visibleRows) }                 # PageUp
            34 { $selectedIndex = [Math]::Min($allSessions.Count - 1, $selectedIndex + $visibleRows) } # PageDown
            36 { $selectedIndex = 0 }                                                             # Home
            35 { $selectedIndex = $allSessions.Count - 1 }                                        # End
            13 {                                                                                   # Enter
                if ($allSessions.Count -gt 0) {
                    Show-TTActionMenu -Session $allSessions[$selectedIndex]
                    $lastRefresh = [DateTime]::MinValue
                    # Redraw header after action menu
                    try { [Console]::Clear() } catch { Clear-Host }
                    foreach ($line in $headerText) { Write-Host $line }
                }
            }
            65 {                                                                                   # A - toggle background
                $showAll = -not $showAll
                $selectedIndex = 0
                $viewportTop = 0
                $lastRefresh = [DateTime]::MinValue  # Force rebuild
            }
            { $_ -eq 81 -or $_ -eq 27 } { $action = 'Quit' }                                    # Q or Escape
        }
    }

    [Console]::Write($script:SHOW_CURSOR)
    try { [Console]::Clear() } catch { Clear-Host }
}

function Show-TTDashboard {
    <#
    .SYNOPSIS Display a formatted dashboard of all terminal sessions.
    .DESCRIPTION Renders session status with ANSI color-coded badges.
                 Use -Interactive for cursor-navigable session selection with action menu.
    .PARAMETER Scan Force a discovery scan for new terminals before displaying.
    .PARAMETER Interactive Enter interactive TUI mode with arrow key navigation and action menu.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSAvoidUsingWriteHost', '',
        Justification = 'Show-TTDashboard is a display function; Write-Host colored output is intentional.'
    )]
    [CmdletBinding()]
    param(
        [switch]$Scan,
        [switch]$Interactive
    )
    Initialize-TTDataStore

    # Run a discovery cycle to pick up new terminals and clean dead ones
    if ($Scan) {
        Invoke-TTMonitorCycle
    }

    $sessions = ConvertTo-FlatArray (Get-TTSession -IncludeHidden)
    $suspended = ConvertTo-FlatArray (Get-TTSuspended)
    $suspended = @($suspended | Where-Object { $_.Id -and $_.WorkingDirectory })
    $config = Get-TTConfig

    # Deduplicate sessions by PID for display
    $sessions = ConvertTo-DeduplicatedSessionList $sessions

    # Filter out background processes (not WT tabs and no visible window)
    $visibility = Get-TTSessionVisibility $sessions
    $bgSessions = @($sessions | Where-Object { $visibility[$_.Pid] -eq 'background' })
    $sessions = @($sessions | Where-Object { $visibility[$_.Pid] -ne 'background' })

    # If interactive mode requested, delegate to interactive handler
    if ($Interactive) {
        Enter-TTInteractiveMode -Sessions $sessions -Suspended $suspended
        return
    }

    # --- Non-interactive ANSI rendering ---

    Write-Host ""
    Write-Host " $($script:COLOR_HEADER)TerminalTracker -- Session Dashboard$($script:RESET)"
    Write-Host " $($script:DIM)$('-' * 60)$($script:RESET)"

    if ($sessions.Count -eq 0 -and $suspended.Count -eq 0) {
        Write-Host " $($script:COLOR_WARN)No sessions tracked$($script:RESET)"
        Write-Host " $($script:DIM)No terminals found. Run 'tt scan' or open a new terminal.$($script:RESET)"
        Write-Host ""
        return
    }

    Write-Host " $($script:DIM)ID STATUS PID SHELL CWD UPDATED$($script:RESET)"
    Write-Host " $($script:DIM)$('-' * 60)$($script:RESET)"

    if ($sessions.Count -gt 0) {
        foreach ($s in $sessions) {
            $row = Format-TTSessionRow -Session $s -IsSuspended $false
            Write-Host $row
            # Show notes and tags on sub-lines if present
            if (-not [string]::IsNullOrWhiteSpace($s.Notes)) {
                Write-Host " $($script:COLOR_NOTES)Notes: $($s.Notes)$($script:RESET)"
            }
            $tagList = @($s.Tags | Where-Object { $_ })
            if ($tagList.Count -gt 0) {
                Write-Host " $($script:COLOR_NOTES)Tags: $($tagList -join ', ')$($script:RESET)"
            }
        }
    }

    if ($suspended.Count -gt 0) {
        Write-Host ""
        Write-Host " $($script:COLOR_SUSP)Suspended Sessions ($($suspended.Count)):$($script:RESET)"
        foreach ($s in $suspended) {
            $row = Format-TTSessionRow -Session $s -IsSuspended $true
            Write-Host $row
            if (-not [string]::IsNullOrWhiteSpace($s.Notes)) {
                Write-Host " $($script:COLOR_NOTES)Notes: $($s.Notes)$($script:RESET)"
            }
        }
    }

    Write-Host ""
    Write-Host " $($script:DIM)$('-' * 60)$($script:RESET)"

    # Monitor status
    $monitorJob = Get-Job -Name 'TerminalTracker-Monitor' -ErrorAction SilentlyContinue
    if ($monitorJob -and $monitorJob.State -eq 'Running') {
        Write-Host " Monitor: $($script:COLOR_LIVE)Running$($script:RESET)"
    } else {
        Write-Host " Monitor: $($script:COLOR_DEAD)Stopped$($script:RESET)"
    }

    # Config status
    $autoStartText = if ($config.AutoStart) { 'Enabled' } else { 'Disabled' }
    $autoReloadText = if ($config.AutoReload) { 'Enabled' } else { 'Disabled' }
    Write-Host " $($script:DIM)Auto-start: $autoStartText$($script:RESET)"
    Write-Host " $($script:DIM)Auto-reload: $autoReloadText$($script:RESET)"
    if ($config.SyncPath) {
        Write-Host " $($script:DIM)Sync path: $($config.SyncPath)$($script:RESET)"
    }

    if ($bgSessions.Count -gt 0) {
        Write-Host " $($script:DIM)($($bgSessions.Count) background processes hidden)$($script:RESET)"
    }
    Write-Host ""
    $footerHint = "Use 'Show-TTDashboard -Interactive' or double-click tray icon for interactive mode."
    Write-Host " $($script:DIM)$footerHint$($script:RESET)"
    Write-Host ""
}