Add macOS and Windows agents + multi-platform install UI
- agent/skywatch-agent-macos.sh: Full macOS bash agent (launchd) - CPU via top -l 2, memory via vm_stat/sysctl, disk via df -P - Network via netstat -ib, uptime via kern.boottime, OS via sw_vers - agent/install-agent-macos.sh: Installs macOS agent as launchd daemon - agent/skywatch-agent-windows.ps1: PowerShell agent (Task Scheduler) - CPU via Win32_PerfRawData two-sample delta, memory via Win32_OperatingSystem - Disk via Get-PSDrive, network via Get-NetAdapterStatistics - agent/install-agent-windows.ps1: Installs Windows agent via Task Scheduler - server/index.js: New routes for macOS and Windows agent scripts/installers - client/src/Agents.js: Multi-platform install panel with Linux/macOS/Windows tabs - client/src/Agents.css: Platform tab button styles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
784e539af3
commit
13b3e3612b
16 files changed
+1010
-35
No files matched your search
@@ -0,0 +1,130 @@
|
||||
#!/bin/bash
|
||||
# SkyWatch macOS Agent Installer v1.0.0
|
||||
# Installs the agent as a launchd daemon (runs at boot, requires sudo)
|
||||
#
|
||||
# Usage:
|
||||
# sudo bash install-agent-macos.sh --server-url https://skywatch.example.com
|
||||
#
|
||||
# Options:
|
||||
# --server-url <url> SkyWatch server URL (required)
|
||||
# --interval <secs> Reporting interval in seconds (default: 60)
|
||||
# --name <label> Agent display name (default: hostname)
|
||||
# --registration-key <key> Optional registration key
|
||||
# --uninstall Remove the agent
|
||||
|
||||
set -e
|
||||
|
||||
PLIST_LABEL="us.necloud.skywatch-agent"
|
||||
PLIST_PATH="/Library/LaunchDaemons/${PLIST_LABEL}.plist"
|
||||
AGENT_SCRIPT="/usr/local/bin/skywatch-agent-macos.sh"
|
||||
CONFIG_FILE="/etc/skywatch-agent-macos.conf"
|
||||
LOG_FILE="/var/log/skywatch-agent.log"
|
||||
|
||||
SERVER_URL=""
|
||||
INTERVAL=60
|
||||
AGENT_NAME="$(hostname -f 2>/dev/null || hostname)"
|
||||
REGISTRATION_KEY=""
|
||||
UNINSTALL=false
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--server-url) SERVER_URL="$2"; shift 2 ;;
|
||||
--interval) INTERVAL="$2"; shift 2 ;;
|
||||
--name) AGENT_NAME="$2"; shift 2 ;;
|
||||
--registration-key) REGISTRATION_KEY="$2"; shift 2 ;;
|
||||
--uninstall) UNINSTALL=true; shift ;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
step() { echo "==> $*"; }
|
||||
ok() { echo " OK: $*"; }
|
||||
|
||||
# ── Uninstall ──────────────────────────────────────────────────────────────────
|
||||
if [ "$UNINSTALL" = true ]; then
|
||||
step "Stopping and removing SkyWatch agent ..."
|
||||
launchctl unload "$PLIST_PATH" 2>/dev/null || true
|
||||
rm -f "$PLIST_PATH" "$AGENT_SCRIPT" "$CONFIG_FILE"
|
||||
ok "SkyWatch agent removed."
|
||||
ok "Log file kept at ${LOG_FILE} — remove manually if desired."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── Require root ───────────────────────────────────────────────────────────────
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "ERROR: This installer must be run as root: sudo bash $0 $*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$SERVER_URL" ]; then
|
||||
echo "ERROR: --server-url is required."
|
||||
echo "Usage: sudo bash install-agent-macos.sh --server-url https://skywatch.example.com"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Install ────────────────────────────────────────────────────────────────────
|
||||
step "Downloading agent script from ${SERVER_URL} ..."
|
||||
curl -fsSL "${SERVER_URL}/api/agents/script-macos" -o "$AGENT_SCRIPT"
|
||||
chmod +x "$AGENT_SCRIPT"
|
||||
ok "Agent script installed to ${AGENT_SCRIPT}"
|
||||
|
||||
step "Writing configuration ..."
|
||||
cat > "$CONFIG_FILE" << CONF
|
||||
SKYWATCH_URL="${SERVER_URL}"
|
||||
AGENT_TOKEN=""
|
||||
REPORT_INTERVAL="${INTERVAL}"
|
||||
AGENT_NAME="${AGENT_NAME}"
|
||||
REGISTRATION_KEY="${REGISTRATION_KEY}"
|
||||
CONF
|
||||
chmod 600 "$CONFIG_FILE"
|
||||
ok "Config written to ${CONFIG_FILE}"
|
||||
|
||||
step "Installing launchd daemon ..."
|
||||
cat > "$PLIST_PATH" << PLIST
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>${PLIST_LABEL}</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/bash</string>
|
||||
<string>${AGENT_SCRIPT}</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>CONFIG_FILE</key>
|
||||
<string>${CONFIG_FILE}</string>
|
||||
<key>LOG_FILE</key>
|
||||
<string>${LOG_FILE}</string>
|
||||
</dict>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>ThrottleInterval</key>
|
||||
<integer>10</integer>
|
||||
<key>StandardOutPath</key>
|
||||
<string>${LOG_FILE}</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>${LOG_FILE}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
PLIST
|
||||
chmod 644 "$PLIST_PATH"
|
||||
ok "Daemon plist written to ${PLIST_PATH}"
|
||||
|
||||
step "Loading daemon ..."
|
||||
launchctl unload "$PLIST_PATH" 2>/dev/null || true
|
||||
launchctl load -w "$PLIST_PATH"
|
||||
|
||||
echo ""
|
||||
echo "✅ SkyWatch Agent installed and started!"
|
||||
echo " Logs: tail -f ${LOG_FILE}"
|
||||
echo " Status: launchctl list | grep skywatch"
|
||||
echo " Uninstall: sudo bash install-agent-macos.sh --uninstall"
|
||||
echo ""
|
||||
echo "The agent will register with ${SERVER_URL} and appear in your"
|
||||
echo "SkyWatch dashboard within a minute."
|
||||
@@ -0,0 +1,144 @@
|
||||
#Requires -RunAsAdministrator
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
SkyWatch Windows Agent Installer v1.0.0
|
||||
.DESCRIPTION
|
||||
Downloads and installs the SkyWatch agent as a Windows Task Scheduler job
|
||||
that starts at boot and runs as SYSTEM.
|
||||
.PARAMETER ServerUrl
|
||||
SkyWatch server URL (required), e.g. https://skywatch.necloud.us
|
||||
.PARAMETER AgentName
|
||||
Display name for this agent (default: computer name)
|
||||
.PARAMETER Interval
|
||||
Reporting interval in seconds (default: 60)
|
||||
.PARAMETER RegistrationKey
|
||||
Optional registration key if server requires one
|
||||
.PARAMETER Uninstall
|
||||
Remove the agent and its scheduled task
|
||||
.EXAMPLE
|
||||
.\install-agent-windows.ps1 -ServerUrl https://skywatch.necloud.us
|
||||
.EXAMPLE
|
||||
.\install-agent-windows.ps1 -Uninstall
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$ServerUrl,
|
||||
[string]$AgentName,
|
||||
[int] $Interval = 60,
|
||||
[string]$RegistrationKey,
|
||||
[switch]$Uninstall
|
||||
)
|
||||
|
||||
$TaskName = "SkyWatch Agent"
|
||||
$InstallDir = "C:\ProgramData\SkyWatch"
|
||||
$AgentScript = "$InstallDir\skywatch-agent-windows.ps1"
|
||||
$ConfigFile = "$InstallDir\agent.conf"
|
||||
|
||||
function Write-Step { param([string]$Msg) Write-Host "==> $Msg" -ForegroundColor Cyan }
|
||||
function Write-OK { param([string]$Msg) Write-Host " $Msg" -ForegroundColor Green }
|
||||
function Write-Err { param([string]$Msg) Write-Host " ERROR: $Msg" -ForegroundColor Red; exit 1 }
|
||||
|
||||
# ── Uninstall ──────────────────────────────────────────────────────────────────
|
||||
if ($Uninstall) {
|
||||
Write-Step "Removing SkyWatch Agent ..."
|
||||
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
if (Test-Path $InstallDir) { Remove-Item $InstallDir -Recurse -Force }
|
||||
Write-OK "SkyWatch Agent removed."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ── Validate ───────────────────────────────────────────────────────────────────
|
||||
if (-not $ServerUrl) {
|
||||
Write-Err "ServerUrl is required.`nExample: .\install-agent-windows.ps1 -ServerUrl https://skywatch.necloud.us"
|
||||
}
|
||||
|
||||
# ── Install ────────────────────────────────────────────────────────────────────
|
||||
Write-Step "Creating install directory ..."
|
||||
if (-not (Test-Path $InstallDir)) {
|
||||
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
||||
}
|
||||
Write-OK $InstallDir
|
||||
|
||||
Write-Step "Downloading agent script from $ServerUrl ..."
|
||||
try {
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
|
||||
Invoke-WebRequest -Uri "$ServerUrl/api/agents/script-windows" `
|
||||
-OutFile $AgentScript -UseBasicParsing -TimeoutSec 30
|
||||
Write-OK "Saved to $AgentScript"
|
||||
} catch {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
|
||||
Write-Step "Writing configuration ..."
|
||||
$name = if ($AgentName) { $AgentName } else { $env:COMPUTERNAME }
|
||||
@"
|
||||
SKYWATCH_URL="$ServerUrl"
|
||||
AGENT_TOKEN=""
|
||||
REPORT_INTERVAL=$Interval
|
||||
AGENT_NAME="$name"
|
||||
REGISTRATION_KEY="$RegistrationKey"
|
||||
"@ | Set-Content $ConfigFile -Encoding UTF8
|
||||
Write-OK "Config saved to $ConfigFile"
|
||||
|
||||
# Allow scripts to run (per-machine, won't affect user policy)
|
||||
Write-Step "Setting PowerShell execution policy ..."
|
||||
try {
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force -ErrorAction Stop
|
||||
Write-OK "RemoteSigned (LocalMachine)"
|
||||
} catch {
|
||||
Write-Host " (Could not set policy — you may need to run: Set-ExecutionPolicy RemoteSigned)" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Step "Registering scheduled task ..."
|
||||
# Remove any previous install
|
||||
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
|
||||
$psArgs = "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$AgentScript`" -ConfigFile `"$ConfigFile`""
|
||||
|
||||
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $psArgs
|
||||
|
||||
$triggers = @(
|
||||
(New-ScheduledTaskTrigger -AtStartup),
|
||||
(New-ScheduledTaskTrigger -Once -At (Get-Date).AddSeconds(10) `
|
||||
-RepetitionInterval (New-TimeSpan -Minutes 5)) # restart every 5 min if it exits
|
||||
)
|
||||
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-ExecutionTimeLimit (New-TimeSpan -Hours 0) `
|
||||
-RestartCount 5 `
|
||||
-RestartInterval (New-TimeSpan -Minutes 1) `
|
||||
-MultipleInstances IgnoreNew `
|
||||
-StartWhenAvailable
|
||||
|
||||
$principal = New-ScheduledTaskPrincipal `
|
||||
-UserId "SYSTEM" `
|
||||
-LogonType ServiceAccount `
|
||||
-RunLevel Highest
|
||||
|
||||
Register-ScheduledTask `
|
||||
-TaskName $TaskName `
|
||||
-Action $action `
|
||||
-Trigger $triggers `
|
||||
-Settings $settings `
|
||||
-Principal $principal `
|
||||
-Force | Out-Null
|
||||
|
||||
Write-OK "Task '$TaskName' created"
|
||||
|
||||
Write-Step "Starting agent ..."
|
||||
Start-ScheduledTask -TaskName $TaskName
|
||||
Start-Sleep -Seconds 3
|
||||
|
||||
$state = (Get-ScheduledTask -TaskName $TaskName).State
|
||||
Write-OK "Task state: $state"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "✅ SkyWatch Agent installed!" -ForegroundColor Green
|
||||
Write-Host " Logs: Get-Content '$InstallDir\agent.log' -Wait"
|
||||
Write-Host " Status: Get-ScheduledTask -TaskName '$TaskName'"
|
||||
Write-Host " Uninstall: .\install-agent-windows.ps1 -Uninstall"
|
||||
Write-Host ""
|
||||
Write-Host "The agent will register with $ServerUrl and appear in your"
|
||||
Write-Host "SkyWatch dashboard within a minute."
|
||||
@@ -0,0 +1,287 @@
|
||||
#!/bin/bash
|
||||
# SkyWatch macOS Agent v1.0.0
|
||||
# Collects system metrics and sends to SkyWatch monitoring server
|
||||
#
|
||||
# Requirements: macOS 10.15+, bash 3.2+, curl
|
||||
# Run via launchd (see install-agent-macos.sh) or: bash skywatch-agent-macos.sh
|
||||
|
||||
VERSION="1.0.0"
|
||||
CONFIG_FILE="${CONFIG_FILE:-/etc/skywatch-agent-macos.conf}"
|
||||
LOG_FILE="${LOG_FILE:-/var/log/skywatch-agent.log}"
|
||||
|
||||
# Fall back to home dir if system paths aren't writable
|
||||
if [ ! -w "$(dirname "$CONFIG_FILE")" ] 2>/dev/null; then
|
||||
CONFIG_FILE="$HOME/.skywatch-agent-macos.conf"
|
||||
LOG_FILE="$HOME/.skywatch-agent.log"
|
||||
fi
|
||||
|
||||
log() {
|
||||
local ts
|
||||
ts=$(date '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "")
|
||||
local msg="[$ts] $*"
|
||||
echo "$msg" >> "$LOG_FILE" 2>/dev/null || true
|
||||
echo "$msg"
|
||||
}
|
||||
|
||||
load_config() {
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$CONFIG_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
save_config() {
|
||||
cat > "$CONFIG_FILE" << CONF
|
||||
SKYWATCH_URL="${SKYWATCH_URL:-}"
|
||||
AGENT_TOKEN="${AGENT_TOKEN:-}"
|
||||
REPORT_INTERVAL="${REPORT_INTERVAL:-60}"
|
||||
AGENT_NAME="${AGENT_NAME:-}"
|
||||
REGISTRATION_KEY="${REGISTRATION_KEY:-}"
|
||||
CONF
|
||||
chmod 600 "$CONFIG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# CPU usage % — two samples from top, 1 second apart
|
||||
get_cpu_percent() {
|
||||
local line idle
|
||||
line=$(top -l 2 -n 0 2>/dev/null | grep "^CPU usage:" | tail -1)
|
||||
# "CPU usage: 8.46% user, 11.45% sys, 80.08% idle"
|
||||
idle=$(echo "$line" | awk '{
|
||||
for (i = 1; i <= NF; i++) {
|
||||
if ($i ~ /idle/) {
|
||||
v = $(i - 1); gsub(/%/, "", v); print v; exit
|
||||
}
|
||||
}
|
||||
}')
|
||||
[ -z "$idle" ] && idle=0
|
||||
awk -v i="$idle" 'BEGIN { printf "%.1f", 100 - i }'
|
||||
}
|
||||
|
||||
# Memory stats in MB — uses vm_stat + sysctl
|
||||
get_memory() {
|
||||
local total_bytes vm_out page_size pages_free pages_inactive pages_spec
|
||||
|
||||
total_bytes=$(sysctl -n hw.memsize 2>/dev/null || echo 0)
|
||||
vm_out=$(vm_stat 2>/dev/null)
|
||||
|
||||
# Page size from vm_stat header (4096 on Intel, 16384 on Apple Silicon)
|
||||
page_size=$(echo "$vm_out" | awk '/page size of/ {
|
||||
for (i = 1; i <= NF; i++) if ($i ~ /^[0-9]+$/ && $(i+1) == "bytes") { print $i; exit }
|
||||
}')
|
||||
[ -z "$page_size" ] && page_size=$(sysctl -n hw.pagesize 2>/dev/null || echo 4096)
|
||||
|
||||
pages_free=$(echo "$vm_out" | awk '/^Pages free:/ { gsub(/\./, "", $NF); print $NF+0 }')
|
||||
pages_inactive=$(echo "$vm_out" | awk '/^Pages inactive:/ { gsub(/\./, "", $NF); print $NF+0 }')
|
||||
pages_spec=$(echo "$vm_out" | awk '/^Pages speculative:/ { gsub(/\./, "", $NF); print $NF+0 }')
|
||||
|
||||
awk -v total="$total_bytes" -v page="$page_size" \
|
||||
-v free="${pages_free:-0}" -v inact="${pages_inactive:-0}" -v spec="${pages_spec:-0}" \
|
||||
'BEGIN {
|
||||
total_mb = int(total / 1048576)
|
||||
avail_mb = int((free + inact + spec) * page / 1048576)
|
||||
used_mb = total_mb - avail_mb
|
||||
if (used_mb < 0) used_mb = 0
|
||||
pct = (total_mb > 0) ? used_mb * 100.0 / total_mb : 0
|
||||
printf "%d %d %.1f", total_mb, used_mb, pct
|
||||
}'
|
||||
}
|
||||
|
||||
# Disk info as JSON — real mounted volumes, skips macOS internal system volumes
|
||||
get_disk_json() {
|
||||
df -P -k 2>/dev/null | tail -n +2 | awk '
|
||||
$6 ~ /^\/System\/Volumes\// { next }
|
||||
$6 ~ /^\/private\/var\/vm/ { next }
|
||||
NF >= 6 {
|
||||
pct = $5; sub(/%/, "", pct)
|
||||
mp = $6
|
||||
gsub(/\\/, "\\\\", mp); gsub(/"/, "\\\"", mp)
|
||||
if (c > 0) printf ","
|
||||
printf "{\"path\":\"%s\",\"total_mb\":%d,\"used_mb\":%d,\"percent\":%d}",
|
||||
mp, int($2/1024), int($3/1024), int(pct)
|
||||
c++
|
||||
}
|
||||
BEGIN { printf "[" }
|
||||
END { printf "]" }
|
||||
'
|
||||
}
|
||||
|
||||
# Cumulative network bytes — hardware-level rows from netstat -ib, no loopback
|
||||
get_net_bytes() {
|
||||
netstat -ib 2>/dev/null | awk '
|
||||
/Name/ { next }
|
||||
/<Link#/ && !/^lo/ { recv += $7; sent += $10 }
|
||||
END { printf "%d %d", sent, recv }
|
||||
' || echo "0 0"
|
||||
}
|
||||
|
||||
# 1/5/15-min load averages from sysctl
|
||||
get_load() {
|
||||
sysctl -n vm.loadavg 2>/dev/null \
|
||||
| awk '{ printf "%s %s %s", $2, $3, $4 }' \
|
||||
|| echo "0.00 0.00 0.00"
|
||||
}
|
||||
|
||||
# System uptime in seconds from boot time
|
||||
get_uptime_seconds() {
|
||||
local boot_sec now_sec
|
||||
# kern.boottime: { sec = NNNN, usec = N }
|
||||
boot_sec=$(sysctl -n kern.boottime 2>/dev/null \
|
||||
| awk '{ for (i=1;i<=NF;i++) if ($i=="sec") { v=$(i+2); gsub(/[^0-9]/,"",v); print v; exit } }')
|
||||
now_sec=$(date +%s)
|
||||
if [ -n "$boot_sec" ] && [ "$boot_sec" -gt 0 ] 2>/dev/null; then
|
||||
echo $((now_sec - boot_sec))
|
||||
else
|
||||
echo 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Running process count
|
||||
get_process_count() {
|
||||
ps -ax 2>/dev/null | tail -n +2 | wc -l | tr -d ' \n'
|
||||
}
|
||||
|
||||
# Primary non-loopback IPv4
|
||||
get_ip_address() {
|
||||
local iface
|
||||
iface=$(route -n get default 2>/dev/null | awk '/interface:/ { print $2 }')
|
||||
if [ -n "$iface" ]; then
|
||||
ipconfig getifaddr "$iface" 2>/dev/null \
|
||||
|| ifconfig "$iface" 2>/dev/null | awk '/inet / { print $2; exit }'
|
||||
fi
|
||||
}
|
||||
|
||||
# macOS version string
|
||||
get_os_info() {
|
||||
local name ver
|
||||
name=$(sw_vers -productName 2>/dev/null || echo "macOS")
|
||||
ver=$(sw_vers -productVersion 2>/dev/null || echo "")
|
||||
echo "${name} ${ver}"
|
||||
}
|
||||
|
||||
# Register with server; saves token to config on success
|
||||
register_agent() {
|
||||
local name="${AGENT_NAME:-$(hostname -f 2>/dev/null || hostname)}"
|
||||
local hostname_val
|
||||
hostname_val=$(hostname -f 2>/dev/null || hostname)
|
||||
local ip
|
||||
ip=$(get_ip_address || echo "")
|
||||
local os
|
||||
os=$(get_os_info)
|
||||
|
||||
local esc_name esc_host esc_os
|
||||
esc_name="${name//\"/\\\"}"
|
||||
esc_host="${hostname_val//\"/\\\"}"
|
||||
esc_os="${os//\"/\\\"}"
|
||||
|
||||
log "Registering agent '${name}' with ${SKYWATCH_URL} ..."
|
||||
|
||||
local -a curl_args
|
||||
curl_args=(-sf -m 30 -X POST -H 'Content-Type: application/json')
|
||||
[ -n "${REGISTRATION_KEY:-}" ] && curl_args+=(-H "X-Registration-Key: ${REGISTRATION_KEY}")
|
||||
curl_args+=(-d "{\"name\":\"${esc_name}\",\"hostname\":\"${esc_host}\",\"ip_address\":\"${ip}\",\"os_info\":\"${esc_os}\"}")
|
||||
curl_args+=("${SKYWATCH_URL}/api/agents/register")
|
||||
|
||||
local response
|
||||
response=$(curl "${curl_args[@]}" 2>&1) || {
|
||||
log "ERROR: Could not reach ${SKYWATCH_URL}"
|
||||
return 1
|
||||
}
|
||||
|
||||
local token
|
||||
token=$(echo "$response" | grep -o '"token":"[^"]*"' | sed 's/"token":"//; s/"$//')
|
||||
if [ -z "$token" ]; then
|
||||
log "ERROR: Registration failed. Server said: ${response}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
AGENT_TOKEN="$token"
|
||||
save_config
|
||||
log "Registered. Token stored in ${CONFIG_FILE}"
|
||||
}
|
||||
|
||||
# Collect and POST metrics
|
||||
report_metrics() {
|
||||
local cpu
|
||||
cpu=$(get_cpu_percent) # includes ~1s sleep inside top
|
||||
|
||||
local mem_total mem_used mem_percent
|
||||
read -r mem_total mem_used mem_percent <<< "$(get_memory)"
|
||||
|
||||
local disk
|
||||
disk=$(get_disk_json)
|
||||
|
||||
local net_sent net_recv
|
||||
read -r net_sent net_recv <<< "$(get_net_bytes)"
|
||||
|
||||
local load1 load5 load15
|
||||
read -r load1 load5 load15 <<< "$(get_load)"
|
||||
|
||||
local uptime_secs
|
||||
uptime_secs=$(get_uptime_seconds)
|
||||
|
||||
local procs
|
||||
procs=$(get_process_count)
|
||||
|
||||
local ip
|
||||
ip=$(get_ip_address || echo "")
|
||||
|
||||
cpu="${cpu:-0.0}"; mem_total="${mem_total:-0}"; mem_used="${mem_used:-0}"
|
||||
mem_percent="${mem_percent:-0.0}"; disk="${disk:-[]}"; net_sent="${net_sent:-0}"
|
||||
net_recv="${net_recv:-0}"; load1="${load1:-0.00}"; load5="${load5:-0.00}"
|
||||
load15="${load15:-0.00}"; uptime_secs="${uptime_secs:-0}"; procs="${procs:-0}"
|
||||
|
||||
local payload
|
||||
payload=$(printf \
|
||||
'{"cpu_percent":%s,"mem_total":%d,"mem_used":%d,"mem_percent":%s,"disk":%s,"load_1":%s,"load_5":%s,"load_15":%s,"uptime_seconds":%d,"process_count":%d,"net_bytes_sent":%s,"net_bytes_recv":%s,"ip_address":"%s"}' \
|
||||
"$cpu" "$mem_total" "$mem_used" "$mem_percent" \
|
||||
"$disk" "$load1" "$load5" "$load15" \
|
||||
"$uptime_secs" "$procs" "$net_sent" "$net_recv" "${ip}")
|
||||
|
||||
local response
|
||||
response=$(curl -sf -m 15 \
|
||||
-X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer ${AGENT_TOKEN}" \
|
||||
-d "$payload" \
|
||||
"${SKYWATCH_URL}/api/agents/report" 2>&1) || {
|
||||
log "WARNING: Failed to send metrics (network error)"
|
||||
return 0
|
||||
}
|
||||
|
||||
if echo "$response" | grep -q '"ok":true'; then
|
||||
log "OK cpu=${cpu}% mem=${mem_used}/${mem_total}MB load=${load1}"
|
||||
else
|
||||
log "WARNING: Server rejected metrics: ${response}"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
load_config
|
||||
|
||||
if [ -z "${SKYWATCH_URL:-}" ]; then
|
||||
echo "ERROR: SKYWATCH_URL is not set."
|
||||
echo "Create ${CONFIG_FILE} or use the installer:"
|
||||
echo " sudo bash install-agent-macos.sh --server-url https://<your-server>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${AGENT_TOKEN:-}" ]; then
|
||||
if ! register_agent; then
|
||||
log "Retrying registration in 60 s..."
|
||||
sleep 60
|
||||
register_agent || exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local interval="${REPORT_INTERVAL:-60}"
|
||||
log "SkyWatch Agent v${VERSION} started (macOS) — server=${SKYWATCH_URL} interval=${interval}s"
|
||||
|
||||
while true; do
|
||||
report_metrics
|
||||
local sleep_time=$(( interval - 1 ))
|
||||
[ "$sleep_time" -lt 1 ] && sleep_time=1
|
||||
sleep "$sleep_time"
|
||||
done
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,257 @@
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
SkyWatch Windows Agent v1.0.0
|
||||
.DESCRIPTION
|
||||
Collects system metrics and sends to SkyWatch monitoring server.
|
||||
Metrics: CPU%, Memory, Disk, Network I/O, Process count, Uptime, OS info.
|
||||
Run via Task Scheduler (installed by install-agent-windows.ps1).
|
||||
.PARAMETER ConfigFile
|
||||
Path to the configuration file (default: C:\ProgramData\SkyWatch\agent.conf)
|
||||
#>
|
||||
param(
|
||||
[string]$ConfigFile = "C:\ProgramData\SkyWatch\agent.conf"
|
||||
)
|
||||
|
||||
$VERSION = "1.0.0"
|
||||
$LogFile = "C:\ProgramData\SkyWatch\agent.log"
|
||||
$InstallDir = Split-Path $ConfigFile
|
||||
|
||||
# ── Logging ───────────────────────────────────────────────────────────────────
|
||||
|
||||
function Write-Log {
|
||||
param([string]$Message)
|
||||
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
$line = "[$ts] $Message"
|
||||
Write-Host $line
|
||||
try { Add-Content -Path $LogFile -Value $line -ErrorAction Stop } catch {}
|
||||
}
|
||||
|
||||
# ── Config ────────────────────────────────────────────────────────────────────
|
||||
|
||||
function Load-Config {
|
||||
$script:SKYWATCH_URL = ""
|
||||
$script:AGENT_TOKEN = ""
|
||||
$script:REPORT_INTERVAL = 60
|
||||
$script:AGENT_NAME = ""
|
||||
$script:REGISTRATION_KEY = ""
|
||||
|
||||
if (Test-Path $ConfigFile) {
|
||||
Get-Content $ConfigFile | ForEach-Object {
|
||||
if ($_ -match '^([A-Z_]+)="?(.*?)"?\s*$') {
|
||||
$key = $matches[1]; $val = $matches[2]
|
||||
switch ($key) {
|
||||
"SKYWATCH_URL" { $script:SKYWATCH_URL = $val }
|
||||
"AGENT_TOKEN" { $script:AGENT_TOKEN = $val }
|
||||
"REPORT_INTERVAL" { $script:REPORT_INTERVAL = [int]$val }
|
||||
"AGENT_NAME" { $script:AGENT_NAME = $val }
|
||||
"REGISTRATION_KEY" { $script:REGISTRATION_KEY = $val }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Save-Config {
|
||||
if (-not (Test-Path $InstallDir)) {
|
||||
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
||||
}
|
||||
@"
|
||||
SKYWATCH_URL="$script:SKYWATCH_URL"
|
||||
AGENT_TOKEN="$script:AGENT_TOKEN"
|
||||
REPORT_INTERVAL=$script:REPORT_INTERVAL
|
||||
AGENT_NAME="$script:AGENT_NAME"
|
||||
REGISTRATION_KEY="$script:REGISTRATION_KEY"
|
||||
"@ | Set-Content $ConfigFile -Encoding UTF8
|
||||
}
|
||||
|
||||
# ── Metrics ───────────────────────────────────────────────────────────────────
|
||||
|
||||
function Get-CpuPercent {
|
||||
try {
|
||||
# Two raw counter samples 1 second apart for accurate delta
|
||||
$s1 = Get-CimInstance -ClassName Win32_PerfRawData_PerfOS_Processor -Filter "Name='_Total'"
|
||||
Start-Sleep -Seconds 1
|
||||
$s2 = Get-CimInstance -ClassName Win32_PerfRawData_PerfOS_Processor -Filter "Name='_Total'"
|
||||
|
||||
$idleDelta = $s2.PercentIdleTime - $s1.PercentIdleTime
|
||||
$totalDelta = $s2.Timestamp_Sys100NS - $s1.Timestamp_Sys100NS
|
||||
|
||||
if ($totalDelta -gt 0) {
|
||||
$idlePct = ($idleDelta / $totalDelta) * 100
|
||||
return [Math]::Round(100 - $idlePct, 1)
|
||||
}
|
||||
} catch {}
|
||||
|
||||
# Fallback: WMI LoadPercentage (less accurate but always available)
|
||||
try {
|
||||
$avg = (Get-WmiObject Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average
|
||||
return [Math]::Round($avg, 1)
|
||||
} catch { return 0.0 }
|
||||
}
|
||||
|
||||
function Get-MemoryStats {
|
||||
try {
|
||||
$os = Get-CimInstance Win32_OperatingSystem
|
||||
$totalMB = [long][Math]::Round($os.TotalVisibleMemorySize / 1024)
|
||||
$freeMB = [long][Math]::Round($os.FreePhysicalMemory / 1024)
|
||||
$usedMB = $totalMB - $freeMB
|
||||
$pct = if ($totalMB -gt 0) { [Math]::Round($usedMB * 100.0 / $totalMB, 1) } else { 0.0 }
|
||||
return @{ total = $totalMB; used = $usedMB; percent = $pct }
|
||||
} catch {
|
||||
return @{ total = 0; used = 0; percent = 0.0 }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-DiskStats {
|
||||
$disks = [System.Collections.Generic.List[hashtable]]::new()
|
||||
try {
|
||||
Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Root -match '^[A-Za-z]:\\' } | ForEach-Object {
|
||||
$total = $_.Used + $_.Free
|
||||
$totalMB = [long][Math]::Round($total / 1MB)
|
||||
$usedMB = [long][Math]::Round($_.Used / 1MB)
|
||||
$pct = if ($total -gt 0) { [int][Math]::Round($_.Used * 100.0 / $total) } else { 0 }
|
||||
$disks.Add(@{ path = $_.Root; total_mb = $totalMB; used_mb = $usedMB; percent = $pct })
|
||||
}
|
||||
} catch {}
|
||||
return $disks
|
||||
}
|
||||
|
||||
function Get-NetBytes {
|
||||
try {
|
||||
$up = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } | Select-Object -ExpandProperty Name
|
||||
if ($up) {
|
||||
$stats = Get-NetAdapterStatistics -Name $up -ErrorAction SilentlyContinue
|
||||
$sent = ($stats | Measure-Object -Property SentBytes -Sum).Sum
|
||||
$recv = ($stats | Measure-Object -Property ReceivedBytes -Sum).Sum
|
||||
return @{ sent = [long]$sent; recv = [long]$recv }
|
||||
}
|
||||
} catch {}
|
||||
return @{ sent = 0L; recv = 0L }
|
||||
}
|
||||
|
||||
function Get-UptimeSeconds {
|
||||
try {
|
||||
$boot = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
|
||||
return [long](New-TimeSpan -Start $boot -End (Get-Date)).TotalSeconds
|
||||
} catch { return 0L }
|
||||
}
|
||||
|
||||
function Get-OsInfo {
|
||||
try { return (Get-CimInstance Win32_OperatingSystem).Caption.Trim() }
|
||||
catch { return "Windows" }
|
||||
}
|
||||
|
||||
function Get-PrimaryIP {
|
||||
try {
|
||||
$route = Get-NetRoute -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue |
|
||||
Sort-Object RouteMetric | Select-Object -First 1
|
||||
if ($route) {
|
||||
$ip = Get-NetIPAddress -InterfaceIndex $route.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.IPAddress -notmatch '^169\.254\.' } |
|
||||
Select-Object -First 1 -ExpandProperty IPAddress
|
||||
return "$ip"
|
||||
}
|
||||
} catch {}
|
||||
return ""
|
||||
}
|
||||
|
||||
# ── Registration ──────────────────────────────────────────────────────────────
|
||||
|
||||
function Register-Agent {
|
||||
$name = if ($script:AGENT_NAME) { $script:AGENT_NAME } else { $env:COMPUTERNAME }
|
||||
$hostname = $env:COMPUTERNAME
|
||||
$ip = Get-PrimaryIP
|
||||
$os = Get-OsInfo
|
||||
|
||||
Write-Log "Registering agent '$name' with $script:SKYWATCH_URL ..."
|
||||
|
||||
$body = @{ name = $name; hostname = $hostname; ip_address = $ip; os_info = $os } | ConvertTo-Json
|
||||
$headers = @{ 'Content-Type' = 'application/json' }
|
||||
if ($script:REGISTRATION_KEY) { $headers['X-Registration-Key'] = $script:REGISTRATION_KEY }
|
||||
|
||||
try {
|
||||
$resp = Invoke-RestMethod -Uri "$script:SKYWATCH_URL/api/agents/register" `
|
||||
-Method POST -Body $body -Headers $headers -TimeoutSec 30
|
||||
if ($resp.token) {
|
||||
$script:AGENT_TOKEN = $resp.token
|
||||
Save-Config
|
||||
Write-Log "Registered. Token stored in $ConfigFile"
|
||||
return $true
|
||||
}
|
||||
} catch { Write-Log "ERROR: Registration failed: $_" }
|
||||
return $false
|
||||
}
|
||||
|
||||
# ── Metrics report ────────────────────────────────────────────────────────────
|
||||
|
||||
function Send-Metrics {
|
||||
$cpu = Get-CpuPercent # includes 1s sleep
|
||||
$mem = Get-MemoryStats
|
||||
$disks = Get-DiskStats
|
||||
$net = Get-NetBytes
|
||||
$uptime = Get-UptimeSeconds
|
||||
$procs = try { (Get-Process -ErrorAction SilentlyContinue).Count } catch { 0 }
|
||||
$ip = Get-PrimaryIP
|
||||
|
||||
$payload = [ordered]@{
|
||||
cpu_percent = $cpu
|
||||
mem_total = $mem.total
|
||||
mem_used = $mem.used
|
||||
mem_percent = $mem.percent
|
||||
disk = @($disks)
|
||||
load_1 = 0.0
|
||||
load_5 = 0.0
|
||||
load_15 = 0.0
|
||||
uptime_seconds = $uptime
|
||||
process_count = $procs
|
||||
net_bytes_sent = $net.sent
|
||||
net_bytes_recv = $net.recv
|
||||
ip_address = $ip
|
||||
} | ConvertTo-Json -Depth 3
|
||||
|
||||
try {
|
||||
$resp = Invoke-RestMethod `
|
||||
-Uri "$script:SKYWATCH_URL/api/agents/report" `
|
||||
-Method POST `
|
||||
-Body $payload `
|
||||
-Headers @{ 'Content-Type' = 'application/json'; 'Authorization' = "Bearer $script:AGENT_TOKEN" } `
|
||||
-TimeoutSec 15
|
||||
|
||||
if ($resp.ok) {
|
||||
Write-Log "OK cpu=$($cpu)% mem=$($mem.used)/$($mem.total)MB procs=$procs"
|
||||
} else {
|
||||
Write-Log "WARNING: Server rejected metrics"
|
||||
}
|
||||
} catch {
|
||||
Write-Log "WARNING: Failed to send metrics: $_"
|
||||
}
|
||||
}
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
# Ensure log directory exists
|
||||
if (-not (Test-Path $InstallDir)) { New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null }
|
||||
|
||||
Load-Config
|
||||
|
||||
if (-not $script:SKYWATCH_URL) {
|
||||
Write-Error "SKYWATCH_URL is not set. Edit $ConfigFile or re-run the installer."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not $script:AGENT_TOKEN) {
|
||||
if (-not (Register-Agent)) {
|
||||
Write-Log "Retrying registration in 60s ..."
|
||||
Start-Sleep -Seconds 60
|
||||
if (-not (Register-Agent)) { exit 1 }
|
||||
}
|
||||
}
|
||||
|
||||
$interval = if ($script:REPORT_INTERVAL -gt 0) { $script:REPORT_INTERVAL } else { 60 }
|
||||
Write-Log "SkyWatch Agent v$VERSION started (Windows) — server=$script:SKYWATCH_URL interval=${interval}s"
|
||||
|
||||
while ($true) {
|
||||
Send-Metrics
|
||||
Start-Sleep -Seconds ($interval - 1) # -1 accounts for the 1s CPU sample sleep
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.e143c118.css",
|
||||
"main.js": "/static/js/main.a720143a.js",
|
||||
"main.css": "/static/css/main.4668db54.css",
|
||||
"main.js": "/static/js/main.f791418f.js",
|
||||
"static/js/453.d456ce70.chunk.js": "/static/js/453.d456ce70.chunk.js",
|
||||
"index.html": "/index.html",
|
||||
"main.e143c118.css.map": "/static/css/main.e143c118.css.map",
|
||||
"main.a720143a.js.map": "/static/js/main.a720143a.js.map",
|
||||
"main.4668db54.css.map": "/static/css/main.4668db54.css.map",
|
||||
"main.f791418f.js.map": "/static/js/main.f791418f.js.map",
|
||||
"453.d456ce70.chunk.js.map": "/static/js/453.d456ce70.chunk.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.e143c118.css",
|
||||
"static/js/main.a720143a.js"
|
||||
"static/css/main.4668db54.css",
|
||||
"static/js/main.f791418f.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en" data-theme="dark"><head><meta charset="utf-8"/><link rel="icon" type="image/png" href="/app-icon.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="SkyWatch - Infrastructure monitoring and alerting system"/><link rel="apple-touch-icon" href="/app-icon.png"/><link rel="manifest" href="/manifest.json"/><title>SkyWatch</title><script defer="defer" src="/static/js/main.a720143a.js"></script><link href="/static/css/main.e143c118.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en" data-theme="dark"><head><meta charset="utf-8"/><link rel="icon" type="image/png" href="/app-icon.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="SkyWatch - Infrastructure monitoring and alerting system"/><link rel="apple-touch-icon" href="/app-icon.png"/><link rel="manifest" href="/manifest.json"/><title>SkyWatch</title><script defer="defer" src="/static/js/main.f791418f.js"></script><link href="/static/css/main.4668db54.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:#020617;color:#e2e8f0;font-family:Manrope,IBM Plex Sans,Segoe UI,sans-serif;margin:0}*{box-sizing:border-box}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}@keyframes skeleton-pulse{0%,to{opacity:.4}50%{opacity:.8}}.skeleton{animation:skeleton-pulse 1.4s ease-in-out infinite;background:#1e293b;background:var(--surface-2);border-radius:4px}.skeleton-row{min-height:72px;pointer-events:none}.skeleton-name{height:14px;margin-bottom:8px;width:40%}.skeleton-url{height:11px;width:60%}.skeleton-badge{border-radius:12px;height:22px;width:56px}.action-delete-confirm{color:#ef4444!important}.discovery-scanning{align-items:center;color:#94a3b8;color:var(--text-muted);display:flex;gap:.75rem;padding:1rem 0}@keyframes spin{to{transform:rotate(1turn)}}.discovery-spinner{animation:spin .8s linear infinite;border:2px solid #334155;border-top-color:#14b8a6;border:2px solid var(--border);border-radius:50%;border-top-color:var(--accent);flex-shrink:0;height:18px;width:18px}.discovery-list{display:flex;flex-direction:column;gap:.5rem;max-height:360px;overflow-y:auto}.discovery-row{align-items:center;background:#1e293b;background:var(--surface-2);border:1px solid #334155;border:1px solid var(--border);border-radius:6px;display:flex;gap:1rem;justify-content:space-between;padding:.6rem .75rem}.discovery-info{display:flex;flex-direction:column;gap:2px;min-width:0}.discovery-ip{color:#e2e8f0;color:var(--text);font-size:.9rem;font-weight:600}.discovery-hostname{color:#94a3b8;color:var(--text-muted);font-size:.8rem}.discovery-url{color:#14b8a6;color:var(--accent);font-family:monospace;font-size:.8rem;word-break:break-all}.discovery-ports{color:#64748b;color:var(--text-dim);font-size:.75rem}.btn-sm{font-size:.82rem;padding:.3rem .7rem;white-space:nowrap}:root{--app-bg:#020617;--surface:#0f172a;--surface-2:#1e293b;--border:#334155;--text:#e2e8f0;--text-muted:#94a3b8;--text-dim:#64748b;--accent:#14b8a6}[data-theme=light]{--app-bg:#f8fafc;--surface:#fff;--surface-2:#f1f5f9;--border:#e2e8f0;--text:#1e293b;--text-muted:#475569;--text-dim:#94a3b8;--accent:#0d9488}[data-theme=light] .App{background:#020617;background:var(--app-bg)}[data-theme=light] .navbar{background:#ffffffeb;border-bottom:1px solid #334155;border-bottom:1px solid var(--border);color:#e2e8f0;color:var(--text)}[data-theme=light] .nav-link{color:#475569}[data-theme=light] .nav-link:hover{background:#f1f5f9;box-shadow:inset 0 0 0 1px #e2e8f0;color:#1e293b}[data-theme=light] .container,[data-theme=light] .detail-section,[data-theme=light] .resource-row{background:#0f172a;background:var(--surface);color:#e2e8f0;color:var(--text)}.App{background:radial-gradient(circle at 15% 0,#1e40af33 0,#0000 42%),radial-gradient(circle at 95% 10%,#0f766e24 0,#0000 36%),#020617;min-height:100vh}.navbar{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);background:#0f172ad1;border-bottom:1px solid #334155;box-shadow:0 4px 18px #0f172a0f;color:#e2e8f0;padding:.85rem 2rem;position:-webkit-sticky;position:sticky;top:0;z-index:30}.navbar h1{font-size:1.5rem;letter-spacing:-.02em;margin:0}.navbar-inner{gap:1rem;justify-content:space-between;width:100%}.navbar-inner,.navbar-left{align-items:center;display:flex}.navbar-left{gap:1.5rem;min-width:0}.navbar-links{align-items:center;display:flex;flex-wrap:wrap;gap:.5rem}.nav-link{border-radius:7px;color:#cbd5e1;font-size:.92rem;font-weight:600;padding:.4rem .7rem;text-decoration:none;transition:background .2s,color .2s,box-shadow .2s}.nav-link:hover{background:#111827;box-shadow:inset 0 0 0 1px #334155;color:#f8fafc}.settings-link{align-items:center;display:inline-flex;gap:.4rem}.setup-badge{background:#facc15;border-radius:999px;color:#111827;font-size:.68rem;font-weight:700;padding:.15rem .5rem}.notifications-pill{align-items:center;background:#111827;border:1px solid #334155;border-radius:999px;color:#e2e8f0;display:flex;font-size:.82rem;gap:.45rem;padding:.3rem .7rem}.container{margin:0 auto;max-width:1400px;padding:2rem}.dashboard-toolbar{align-items:center;display:flex;gap:1rem;justify-content:space-between;margin-bottom:2rem}.dashboard-title{color:#f8fafc;font-size:1.85rem;letter-spacing:-.02em;margin:0}.dashboard-subtitle{color:#94a3b8;font-size:.9rem;margin:.2rem 0 0}.dashboard-actions{align-items:center;display:flex;flex-wrap:wrap;gap:.5rem}.quick-filter-row{display:flex;flex-wrap:wrap;gap:.45rem;margin:.2rem 0 .8rem}.quick-chip{background:#0f172a;border:1px solid #334155;border-radius:999px;color:#cbd5e1;cursor:pointer;font-size:.74rem;font-weight:700;letter-spacing:.02em;padding:.28rem .7rem}.quick-chip:hover{background:#111f34}.quick-chip.active{background:#14b8a6;border-color:#14b8a6;color:#052e2b}.tag-filter-input{background:#111827;border:1px solid #334155;border-radius:10px;color:#e2e8f0;min-width:180px;padding:.5rem .75rem}.actions-menu-wrapper{position:relative}.actions-menu{background:#fff;border:1px solid #Line truncated
|
||||
/*# sourceMappingURL=main.e143c118.css.map*/
|
||||
body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:#020617;color:#e2e8f0;font-family:Manrope,IBM Plex Sans,Segoe UI,sans-serif;margin:0}*{box-sizing:border-box}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}@keyframes skeleton-pulse{0%,to{opacity:.4}50%{opacity:.8}}.skeleton{animation:skeleton-pulse 1.4s ease-in-out infinite;background:#1e293b;background:var(--surface-2);border-radius:4px}.skeleton-row{min-height:72px;pointer-events:none}.skeleton-name{height:14px;margin-bottom:8px;width:40%}.skeleton-url{height:11px;width:60%}.skeleton-badge{border-radius:12px;height:22px;width:56px}.action-delete-confirm{color:#ef4444!important}.discovery-scanning{align-items:center;color:#94a3b8;color:var(--text-muted);display:flex;gap:.75rem;padding:1rem 0}@keyframes spin{to{transform:rotate(1turn)}}.discovery-spinner{animation:spin .8s linear infinite;border:2px solid #334155;border-top-color:#14b8a6;border:2px solid var(--border);border-radius:50%;border-top-color:var(--accent);flex-shrink:0;height:18px;width:18px}.discovery-list{display:flex;flex-direction:column;gap:.5rem;max-height:360px;overflow-y:auto}.discovery-row{align-items:center;background:#1e293b;background:var(--surface-2);border:1px solid #334155;border:1px solid var(--border);border-radius:6px;display:flex;gap:1rem;justify-content:space-between;padding:.6rem .75rem}.discovery-info{display:flex;flex-direction:column;gap:2px;min-width:0}.discovery-ip{color:#e2e8f0;color:var(--text);font-size:.9rem;font-weight:600}.discovery-hostname{color:#94a3b8;color:var(--text-muted);font-size:.8rem}.discovery-url{color:#14b8a6;color:var(--accent);font-family:monospace;font-size:.8rem;word-break:break-all}.discovery-ports{color:#64748b;color:var(--text-dim);font-size:.75rem}.btn-sm{font-size:.82rem;padding:.3rem .7rem;white-space:nowrap}:root{--app-bg:#020617;--surface:#0f172a;--surface-2:#1e293b;--border:#334155;--text:#e2e8f0;--text-muted:#94a3b8;--text-dim:#64748b;--accent:#14b8a6}[data-theme=light]{--app-bg:#f8fafc;--surface:#fff;--surface-2:#f1f5f9;--border:#e2e8f0;--text:#1e293b;--text-muted:#475569;--text-dim:#94a3b8;--accent:#0d9488}[data-theme=light] .App{background:#020617;background:var(--app-bg)}[data-theme=light] .navbar{background:#ffffffeb;border-bottom:1px solid #334155;border-bottom:1px solid var(--border);color:#e2e8f0;color:var(--text)}[data-theme=light] .nav-link{color:#475569}[data-theme=light] .nav-link:hover{background:#f1f5f9;box-shadow:inset 0 0 0 1px #e2e8f0;color:#1e293b}[data-theme=light] .container,[data-theme=light] .detail-section,[data-theme=light] .resource-row{background:#0f172a;background:var(--surface);color:#e2e8f0;color:var(--text)}.App{background:radial-gradient(circle at 15% 0,#1e40af33 0,#0000 42%),radial-gradient(circle at 95% 10%,#0f766e24 0,#0000 36%),#020617;min-height:100vh}.navbar{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);background:#0f172ad1;border-bottom:1px solid #334155;box-shadow:0 4px 18px #0f172a0f;color:#e2e8f0;padding:.85rem 2rem;position:-webkit-sticky;position:sticky;top:0;z-index:30}.navbar h1{font-size:1.5rem;letter-spacing:-.02em;margin:0}.navbar-inner{gap:1rem;justify-content:space-between;width:100%}.navbar-inner,.navbar-left{align-items:center;display:flex}.navbar-left{gap:1.5rem;min-width:0}.navbar-links{align-items:center;display:flex;flex-wrap:wrap;gap:.5rem}.nav-link{border-radius:7px;color:#cbd5e1;font-size:.92rem;font-weight:600;padding:.4rem .7rem;text-decoration:none;transition:background .2s,color .2s,box-shadow .2s}.nav-link:hover{background:#111827;box-shadow:inset 0 0 0 1px #334155;color:#f8fafc}.settings-link{align-items:center;display:inline-flex;gap:.4rem}.setup-badge{background:#facc15;border-radius:999px;color:#111827;font-size:.68rem;font-weight:700;padding:.15rem .5rem}.notifications-pill{align-items:center;background:#111827;border:1px solid #334155;border-radius:999px;color:#e2e8f0;display:flex;font-size:.82rem;gap:.45rem;padding:.3rem .7rem}.container{margin:0 auto;max-width:1400px;padding:2rem}.dashboard-toolbar{align-items:center;display:flex;gap:1rem;justify-content:space-between;margin-bottom:2rem}.dashboard-title{color:#f8fafc;font-size:1.85rem;letter-spacing:-.02em;margin:0}.dashboard-subtitle{color:#94a3b8;font-size:.9rem;margin:.2rem 0 0}.dashboard-actions{align-items:center;display:flex;flex-wrap:wrap;gap:.5rem}.quick-filter-row{display:flex;flex-wrap:wrap;gap:.45rem;margin:.2rem 0 .8rem}.quick-chip{background:#0f172a;border:1px solid #334155;border-radius:999px;color:#cbd5e1;cursor:pointer;font-size:.74rem;font-weight:700;letter-spacing:.02em;padding:.28rem .7rem}.quick-chip:hover{background:#111f34}.quick-chip.active{background:#14b8a6;border-color:#14b8a6;color:#052e2b}.tag-filter-input{background:#111827;border:1px solid #334155;border-radius:10px;color:#e2e8f0;min-width:180px;padding:.5rem .75rem}.actions-menu-wrapper{position:relative}.actions-menu{background:#fff;border:1px solid #Line truncated
|
||||
/*# sourceMappingURL=main.4668db54.css.map*/
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static/css/main.4668db54.css","mappings":"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 truncated
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"static/css/main.e143c118.css","mappings":"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 truncated
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"static/js/main.a720143a.js","mappings":"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 truncated
|
||||
@@ -1,3 +1,3 @@
|
||||
/*! For license information please see main.a720143a.js.LICENSE.txt */
|
||||
(()=>{var e={356:(e,t,n)=>{e.exports=n(9645).last},418:(e,t)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),t.toString=function e(t){if(null==t)return"";if("string"===typeof t)return t;if(Array.isArray(t))return t.map(e).join(",");const n=String(t);return"0"===n&&Object.is(Number(t),-0)?"-0":n}},579:(e,t,n)=>{"use strict";e.exports=n(2799)},870:(e,t)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),t.isObject=function(e){return null!==e&&("object"===typeof e||"function"===typeof e)}},1203:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(8420);t.isArrayLike=function(e){return null!=e&&"function"!==typeof e&&r.isLength(e.length)}},1293:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(4830);t.debounce=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};"object"!==typeof n&&(n={});const{leading:a=!1,trailing:i=!0,maxWait:o}=n,l=Array(2);let s;a&&(l[0]="leading"),i&&(l[1]="trailing");let c=null;const u=r.debounce(function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];s=e.apply(this,n),c=null},t,{edges:l}),d=function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];return null!=o&&(null===c&&(c=Date.now()),Date.now()-c>=o)?(s=e.apply(this,n),c=Date.now(),u.cancel(),u.schedule(),s):(u.apply(this,n),s)};return d.cancel=u.cancel,d.flush=()=>(u.flush(),s),d}},1444:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(418),a=n(3272);t.toPath=function(e){if(Array.isArray(e))return e.map(a.toKey);if("symbol"===typeof e)return[e];const t=[],n=(e=r.toString(e)).length;if(0===n)return t;let i=0,o="",l="",s=!1;for(46===e.charCodeAt(0)&&(t.push(""),i++);i<n;){const r=e[i];l?"\\"===r&&i+1<n?(i++,o+=e[i]):r===l?l="":o+=r:s?'"'===r||"'"===r?l=r:"]"===r?(s=!1,t.push(o),o=""):o+=r:"["===r?(s=!0,o&&(t.push(o),o="")):"."===r?o&&(t.push(o),o=""):o+=r,i++}return o&&t.push(o),t}},2086:(e,t,n)=>{"use strict";e.exports=n(5082)},2104:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(1203),a=n(9921);t.isArrayLikeObject=function(e){return a.isObjectLike(e)&&r.isArrayLike(e)}},2132:(e,t,n)=>{"use strict";var r=n(2897).default;Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const a=n(870),i=n(4803),o=n(9972);function l(e,t,n,u){if(t===e)return!0;switch(typeof t){case"object":return function(e,t,n,r){if(null==t)return!0;if(Array.isArray(t))return s(e,t,n,r);if(t instanceof Map)return function(e,t,n,r){if(0===t.size)return!0;if(!(e instanceof Map))return!1;for(const[a,i]of t.entries()){if(!1===n(e.get(a),i,a,e,t,r))return!1}return!0}(e,t,n,r);if(t instanceof Set)return c(e,t,n,r);const a=Object.keys(t);if(null==e)return 0===a.length;if(0===a.length)return!0;if(null!==r&&void 0!==r&&r.has(t))return r.get(t)===e;null===r||void 0===r||r.set(t,e);try{for(let o=0;o<a.length;o++){const l=a[o];if(!i.isPrimitive(e)&&!(l in e))return!1;if(void 0===t[l]&&void 0!==e[l])return!1;if(null===t[l]&&null!==e[l])return!1;if(!n(e[l],t[l],l,e,t,r))return!1}return!0}finally{null===r||void 0===r||r.delete(t)}}(e,t,n,u);case"function":return Object.keys(t).length>0?l(e,r({},t),n,u):o.eq(e,t);default:return a.isObject(e)?"string"!==typeof t||""===t:o.eq(e,t)}}function s(e,t,n,r){if(0===t.length)return!0;if(!Array.isArray(e))return!1;const a=new Set;for(let i=0;i<t.length;i++){const o=t[i];let l=!1;for(let s=0;s<e.length;s++){if(a.has(s))continue;let c=!1;if(n(e[s],o,i,e,t,r)&&(c=!0),c){a.add(s),l=!0;break}}if(!l)return!1}return!0}function c(e,t,n,r){return 0===t.size||e instanceof Set&&s([...e],[...t],n,r)}t.isMatchWith=function e(t,n,r){return"function"!==typeof r?e(t,n,()=>{}):l(t,n,function e(t,n,a,i,o,s){const c=r(t,n,a,i,o,s);return void 0!==c?Boolean(c):l(t,n,e,s)},new Map)},t.isSetMatch=c},2204:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(5316),a=n(7312),i=n(3799);t.sortBy=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o<t;o++)n[o-1]=arguments[o];const l=n.length;return l>1&&i.isIterateeCall(e,n[0],n[1])?n=[]:l>2&&i.isIterateeCall(n[0],n[1],n[2])&&(n=[n[0]]),r.orderBy(e,a.flatten(n),["asc"])}},2330:(e,t,n)=>{"use strict";var r=n(5043);var a="function"===typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e===1/t)||e!==e&&t!==t},i=r.useState,o=r.useEffect,l=r.useLayoutEffect,s=r.useDebugValue;function c(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!a(e,n)}catch(r){return!0}}var u="undefined"===typeof window||"undefined"===typeof window.document||"undefined"===typeof window.document.createElement?function(e,t){return t()}:function(e,t){var n=t(),r=i({inst:{value:n,getSnapshot:t}}),a=r[0].inst,u=r[1];return l(function(){a.value=n,a.getSnapshot=t,c(a)&&u({inst:a})},[e,n,t]),o(function(){return c(a)&&u({iLine truncated
|
||||
//# sourceMappingURL=main.a720143a.js.map
|
||||
/*! For license information please see main.f791418f.js.LICENSE.txt */
|
||||
(()=>{var e={356:(e,t,n)=>{e.exports=n(9645).last},418:(e,t)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),t.toString=function e(t){if(null==t)return"";if("string"===typeof t)return t;if(Array.isArray(t))return t.map(e).join(",");const n=String(t);return"0"===n&&Object.is(Number(t),-0)?"-0":n}},579:(e,t,n)=>{"use strict";e.exports=n(2799)},870:(e,t)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),t.isObject=function(e){return null!==e&&("object"===typeof e||"function"===typeof e)}},1203:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(8420);t.isArrayLike=function(e){return null!=e&&"function"!==typeof e&&r.isLength(e.length)}},1293:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(4830);t.debounce=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};"object"!==typeof n&&(n={});const{leading:a=!1,trailing:i=!0,maxWait:o}=n,l=Array(2);let s;a&&(l[0]="leading"),i&&(l[1]="trailing");let c=null;const u=r.debounce(function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];s=e.apply(this,n),c=null},t,{edges:l}),d=function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];return null!=o&&(null===c&&(c=Date.now()),Date.now()-c>=o)?(s=e.apply(this,n),c=Date.now(),u.cancel(),u.schedule(),s):(u.apply(this,n),s)};return d.cancel=u.cancel,d.flush=()=>(u.flush(),s),d}},1444:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(418),a=n(3272);t.toPath=function(e){if(Array.isArray(e))return e.map(a.toKey);if("symbol"===typeof e)return[e];const t=[],n=(e=r.toString(e)).length;if(0===n)return t;let i=0,o="",l="",s=!1;for(46===e.charCodeAt(0)&&(t.push(""),i++);i<n;){const r=e[i];l?"\\"===r&&i+1<n?(i++,o+=e[i]):r===l?l="":o+=r:s?'"'===r||"'"===r?l=r:"]"===r?(s=!1,t.push(o),o=""):o+=r:"["===r?(s=!0,o&&(t.push(o),o="")):"."===r?o&&(t.push(o),o=""):o+=r,i++}return o&&t.push(o),t}},2086:(e,t,n)=>{"use strict";e.exports=n(5082)},2104:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(1203),a=n(9921);t.isArrayLikeObject=function(e){return a.isObjectLike(e)&&r.isArrayLike(e)}},2132:(e,t,n)=>{"use strict";var r=n(2897).default;Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const a=n(870),i=n(4803),o=n(9972);function l(e,t,n,u){if(t===e)return!0;switch(typeof t){case"object":return function(e,t,n,r){if(null==t)return!0;if(Array.isArray(t))return s(e,t,n,r);if(t instanceof Map)return function(e,t,n,r){if(0===t.size)return!0;if(!(e instanceof Map))return!1;for(const[a,i]of t.entries()){if(!1===n(e.get(a),i,a,e,t,r))return!1}return!0}(e,t,n,r);if(t instanceof Set)return c(e,t,n,r);const a=Object.keys(t);if(null==e)return 0===a.length;if(0===a.length)return!0;if(null!==r&&void 0!==r&&r.has(t))return r.get(t)===e;null===r||void 0===r||r.set(t,e);try{for(let o=0;o<a.length;o++){const l=a[o];if(!i.isPrimitive(e)&&!(l in e))return!1;if(void 0===t[l]&&void 0!==e[l])return!1;if(null===t[l]&&null!==e[l])return!1;if(!n(e[l],t[l],l,e,t,r))return!1}return!0}finally{null===r||void 0===r||r.delete(t)}}(e,t,n,u);case"function":return Object.keys(t).length>0?l(e,r({},t),n,u):o.eq(e,t);default:return a.isObject(e)?"string"!==typeof t||""===t:o.eq(e,t)}}function s(e,t,n,r){if(0===t.length)return!0;if(!Array.isArray(e))return!1;const a=new Set;for(let i=0;i<t.length;i++){const o=t[i];let l=!1;for(let s=0;s<e.length;s++){if(a.has(s))continue;let c=!1;if(n(e[s],o,i,e,t,r)&&(c=!0),c){a.add(s),l=!0;break}}if(!l)return!1}return!0}function c(e,t,n,r){return 0===t.size||e instanceof Set&&s([...e],[...t],n,r)}t.isMatchWith=function e(t,n,r){return"function"!==typeof r?e(t,n,()=>{}):l(t,n,function e(t,n,a,i,o,s){const c=r(t,n,a,i,o,s);return void 0!==c?Boolean(c):l(t,n,e,s)},new Map)},t.isSetMatch=c},2204:(e,t,n)=>{"use strict";Object.defineProperty(t,Symbol.toStringTag,{value:"Module"});const r=n(5316),a=n(7312),i=n(3799);t.sortBy=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o<t;o++)n[o-1]=arguments[o];const l=n.length;return l>1&&i.isIterateeCall(e,n[0],n[1])?n=[]:l>2&&i.isIterateeCall(n[0],n[1],n[2])&&(n=[n[0]]),r.orderBy(e,a.flatten(n),["asc"])}},2330:(e,t,n)=>{"use strict";var r=n(5043);var a="function"===typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e===1/t)||e!==e&&t!==t},i=r.useState,o=r.useEffect,l=r.useLayoutEffect,s=r.useDebugValue;function c(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!a(e,n)}catch(r){return!0}}var u="undefined"===typeof window||"undefined"===typeof window.document||"undefined"===typeof window.document.createElement?function(e,t){return t()}:function(e,t){var n=t(),r=i({inst:{value:n,getSnapshot:t}}),a=r[0].inst,u=r[1];return l(function(){a.value=n,a.getSnapshot=t,c(a)&&u({inst:a})},[e,n,t]),o(function(){return c(a)&&u({iLine truncated
|
||||
//# sourceMappingURL=main.f791418f.js.map
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static/js/main.f791418f.js","mappings":"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 truncated
|
||||
@@ -49,6 +49,32 @@
|
||||
.ag-install-toggle:hover { background: var(--border); }
|
||||
.ag-install-toggle-active { border-color: var(--accent); color: var(--accent); }
|
||||
|
||||
/* ── Platform tabs ───────────────────────────────────── */
|
||||
.ag-platform-tabs {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
margin: 0.75rem 0 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ag-platform-tab {
|
||||
padding: 0.35rem 0.85rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface-2);
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
transition: background 0.15s, border-color 0.15s, color 0.15s;
|
||||
}
|
||||
.ag-platform-tab:hover { background: var(--border); color: var(--text); }
|
||||
.ag-platform-tab-active {
|
||||
background: rgba(20,184,166,0.12);
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── Install panel ───────────────────────────────────── */
|
||||
.ag-install-panel {
|
||||
margin-bottom: 2rem;
|
||||
|
||||
+110
-21
@@ -95,45 +95,134 @@ function CopyCmd({ cmd }) {
|
||||
);
|
||||
}
|
||||
|
||||
// ── Install instructions panel ────────────────────────────────────────────────
|
||||
|
||||
function InstallPanel({ serverUrl }) {
|
||||
const scriptCmd = `curl -fsSL ${serverUrl}/api/agents/script -o skywatch-agent.sh`;
|
||||
const installerCmd = `curl -fsSL ${serverUrl}/api/agents/installer -o install-agent.sh`;
|
||||
const runCmd = `sudo bash install-agent.sh --server-url ${serverUrl}`;
|
||||
// ── Platform-specific install steps ──────────────────────────────────────────
|
||||
|
||||
function LinuxSteps({ serverUrl }) {
|
||||
return (
|
||||
<div className="ag-install-panel">
|
||||
<h3 className="ag-install-title">Install agent on a Linux host</h3>
|
||||
<>
|
||||
<p className="ag-install-note">
|
||||
Run the following on the target machine (Ubuntu 16.04+ / Debian 9+ / RHEL 7+).
|
||||
The agent registers itself automatically and appears here within a minute.
|
||||
Ubuntu 16.04+ / Debian 9+ / RHEL 7+. Runs as a systemd service.
|
||||
</p>
|
||||
|
||||
<div className="ag-install-steps">
|
||||
<div className="ag-step">
|
||||
<span className="ag-step-num">1</span>
|
||||
<div className="ag-step-body">
|
||||
<div className="ag-step-label">Download the scripts</div>
|
||||
<CopyCmd cmd={scriptCmd} />
|
||||
<CopyCmd cmd={installerCmd} />
|
||||
<CopyCmd cmd={`curl -fsSL ${serverUrl}/api/agents/script -o skywatch-agent.sh`} />
|
||||
<CopyCmd cmd={`curl -fsSL ${serverUrl}/api/agents/installer -o install-agent.sh`} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ag-step">
|
||||
<span className="ag-step-num">2</span>
|
||||
<div className="ag-step-body">
|
||||
<div className="ag-step-label">Run the installer as root</div>
|
||||
<CopyCmd cmd={runCmd} />
|
||||
<CopyCmd cmd={`sudo bash install-agent.sh --server-url ${serverUrl}`} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="ag-install-note ag-install-note-sm">
|
||||
Optional: <code>--interval <secs></code>, <code>--name <label></code>,{' '}
|
||||
<code>--registration-key <key></code>.
|
||||
Remove: <code>sudo bash install-agent.sh --uninstall</code>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function MacosSteps({ serverUrl }) {
|
||||
return (
|
||||
<>
|
||||
<p className="ag-install-note">
|
||||
macOS 10.15+ (Intel & Apple Silicon). Runs as a launchd system daemon.
|
||||
</p>
|
||||
<div className="ag-install-steps">
|
||||
<div className="ag-step">
|
||||
<span className="ag-step-num">1</span>
|
||||
<div className="ag-step-body">
|
||||
<div className="ag-step-label">Download the scripts</div>
|
||||
<CopyCmd cmd={`curl -fsSL ${serverUrl}/api/agents/script-macos -o skywatch-agent-macos.sh`} />
|
||||
<CopyCmd cmd={`curl -fsSL ${serverUrl}/api/agents/installer-macos -o install-agent-macos.sh`} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="ag-step">
|
||||
<span className="ag-step-num">2</span>
|
||||
<div className="ag-step-body">
|
||||
<div className="ag-step-label">Run the installer as root</div>
|
||||
<CopyCmd cmd={`sudo bash install-agent-macos.sh --server-url ${serverUrl}`} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="ag-install-note ag-install-note-sm">
|
||||
Optional: <code>--interval <secs></code>, <code>--name <label></code>,{' '}
|
||||
<code>--registration-key <key></code>.
|
||||
Remove: <code>sudo bash install-agent-macos.sh --uninstall</code>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function WindowsSteps({ serverUrl }) {
|
||||
return (
|
||||
<>
|
||||
<p className="ag-install-note">
|
||||
Windows 10 / 11 / Server 2019+. Runs via Task Scheduler as SYSTEM.
|
||||
Open <strong>PowerShell as Administrator</strong> and run:
|
||||
</p>
|
||||
<div className="ag-install-steps">
|
||||
<div className="ag-step">
|
||||
<span className="ag-step-num">1</span>
|
||||
<div className="ag-step-body">
|
||||
<div className="ag-step-label">Download the installer</div>
|
||||
<CopyCmd cmd={`Invoke-WebRequest "${serverUrl}/api/agents/installer-windows" -OutFile install-agent-windows.ps1`} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="ag-step">
|
||||
<span className="ag-step-num">2</span>
|
||||
<div className="ag-step-body">
|
||||
<div className="ag-step-label">Run the installer</div>
|
||||
<CopyCmd cmd={`.\\install-agent-windows.ps1 -ServerUrl "${serverUrl}"`} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="ag-install-note ag-install-note-sm">
|
||||
Optional: <code>-Interval <secs></code>, <code>-AgentName <label></code>,{' '}
|
||||
<code>-RegistrationKey <key></code>.
|
||||
Remove: <code>.\\install-agent-windows.ps1 -Uninstall</code>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Install instructions panel ────────────────────────────────────────────────
|
||||
|
||||
const PLATFORMS = [
|
||||
{ id: 'linux', label: '🐧 Linux' },
|
||||
{ id: 'macos', label: '🍎 macOS' },
|
||||
{ id: 'windows', label: '🪟 Windows' },
|
||||
];
|
||||
|
||||
function InstallPanel({ serverUrl }) {
|
||||
const [platform, setPlatform] = useState('linux');
|
||||
|
||||
return (
|
||||
<div className="ag-install-panel">
|
||||
<h3 className="ag-install-title">Install agent on a host</h3>
|
||||
|
||||
<div className="ag-platform-tabs">
|
||||
{PLATFORMS.map(p => (
|
||||
<button
|
||||
key={p.id}
|
||||
className={`ag-platform-tab${platform === p.id ? ' ag-platform-tab-active' : ''}`}
|
||||
onClick={() => setPlatform(p.id)}
|
||||
>
|
||||
{p.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="ag-install-note ag-install-note-sm">
|
||||
Optional flags: <code>--interval <secs></code> (default 60),{' '}
|
||||
<code>--name <label></code>, <code>--registration-key <key></code>.
|
||||
To remove: <code>sudo bash install-agent.sh --uninstall</code>
|
||||
</p>
|
||||
{platform === 'linux' && <LinuxSteps serverUrl={serverUrl} />}
|
||||
{platform === 'macos' && <MacosSteps serverUrl={serverUrl} />}
|
||||
{platform === 'windows' && <WindowsSteps serverUrl={serverUrl} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -273,7 +362,7 @@ export default function Agents() {
|
||||
{/* ── Header ── */}
|
||||
<div className="ag-header">
|
||||
<div className="ag-header-left">
|
||||
<h2 className="ag-page-title">Linux Agents</h2>
|
||||
<h2 className="ag-page-title">Agents</h2>
|
||||
{agents.length > 0 && (
|
||||
<span className="ag-count-pill">
|
||||
{onlineCount} / {agents.length} online
|
||||
|
||||
@@ -2196,6 +2196,48 @@ app.get('/api/agents/installer', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// macOS agent scripts
|
||||
app.get('/api/agents/script-macos', (req, res) => {
|
||||
const fs = require('fs');
|
||||
const p = path.join(__dirname, '../agent/skywatch-agent-macos.sh');
|
||||
if (fs.existsSync(p)) {
|
||||
res.setHeader('Content-Type', 'text/x-sh');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="skywatch-agent-macos.sh"');
|
||||
res.sendFile(p);
|
||||
} else { res.status(404).json({ error: 'macOS agent script not found' }); }
|
||||
});
|
||||
|
||||
app.get('/api/agents/installer-macos', (req, res) => {
|
||||
const fs = require('fs');
|
||||
const p = path.join(__dirname, '../agent/install-agent-macos.sh');
|
||||
if (fs.existsSync(p)) {
|
||||
res.setHeader('Content-Type', 'text/x-sh');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="install-agent-macos.sh"');
|
||||
res.sendFile(p);
|
||||
} else { res.status(404).json({ error: 'macOS installer not found' }); }
|
||||
});
|
||||
|
||||
// Windows agent scripts
|
||||
app.get('/api/agents/script-windows', (req, res) => {
|
||||
const fs = require('fs');
|
||||
const p = path.join(__dirname, '../agent/skywatch-agent-windows.ps1');
|
||||
if (fs.existsSync(p)) {
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="skywatch-agent-windows.ps1"');
|
||||
res.sendFile(p);
|
||||
} else { res.status(404).json({ error: 'Windows agent script not found' }); }
|
||||
});
|
||||
|
||||
app.get('/api/agents/installer-windows', (req, res) => {
|
||||
const fs = require('fs');
|
||||
const p = path.join(__dirname, '../agent/install-agent-windows.ps1');
|
||||
if (fs.existsSync(p)) {
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="install-agent-windows.ps1"');
|
||||
res.sendFile(p);
|
||||
} else { res.status(404).json({ error: 'Windows installer not found' }); }
|
||||
});
|
||||
|
||||
// Register a new Linux agent — returns a bearer token the agent uses for all future calls
|
||||
app.post('/api/agents/register', rateLimit(5), (req, res) => {
|
||||
// Optional: if AGENT_REGISTRATION_KEY is set in env, require it as X-Registration-Key header
|
||||
|
||||
Reference in new issue
Block a user