Skill: weznai/skill-system-monitor (version 1.0.1)

--- name: skill-system-monitor description: 跨平台系统监控工具，支持 Linux 和 Windows，监控硬盘、内存、CPU 使用情况，记录历史数据，支持变化对比和预警。**适合定时任务**。触发场景：(1) 定时系统健康检查（推荐每6小时），(2) 用户询问系统状态、资源使用情况，(3) 资源异常预警，(4) 查看历史监控数据对比。 --- # System Monitor - 系统监控技能 跨平台系统监控工具，**自动检测操作系统类型**，支持 Linux 和 Windows，用于监控服务器硬盘、内存、CPU 使用情况，记录历史快照，支持变化趋势对比和异常预警。 **🎯 本技能特别适合定时任务使用**，推荐频率： - 生产服务器：1-2 小时 - 个人服务器：2-4 小时 - 开发环境：6-12 小时 ## 功能特点 - 💾 **硬盘监控** - 检查硬盘使用率，支持预警阈值 - 🧠 **内存监控** - 检查内存和 Swap/页面文件使用情况 - ⚙️ **CPU 负载** - 监控 CPU 负载/使用率 - 📊 **进程监控** - 显示资源占用 TOP 进程 - ⏱️ **运行时间** - 显示系统运行时长 - 🌐 **网络流量** - 监控网络接收/发送流量 - 💿 **磁盘 I/O** - 磁盘读写速率和利用率（Linux） - 🐳 **Docker 状态** - 容器运行/停止数量（Linux） - 🔧 **服务状态** - 关键服务运行状态（MongoDB/MySQL/PostgreSQL/Docker/Nginx/OpenClaw） - 📜 **历史记录** - 自动保存监控快照 - 📈 **趋势对比** - 对比历史数据，分析变化趋势 - ⚠️ **异常预警** - 自动判断状态并预警 - 🖥️ **跨平台支持** - 自动检测 Linux/Windows/macOS，调用对应脚本 ## 配置说明 ### 配置文件位置 配置文件按优先级查找： 1. **环境变量指定**: `$SYSTEM_MONITOR_CONFIG` 2. **技能配置目录**: `~/.openclaw/skills/config/skill-system-monitor/config.json` ⭐ **推荐** 3. **技能安装目录**: `~/.openclaw/skills/skill-system-monitor/config.json` > **推荐**：使用技能配置目录（#2），独立于技能安装目录，卸载重装不会丢失配置。 ### 快速配置 **1. 复制示例配置：** ```bash mkdir -p ~/.openclaw/skills/config/skill-system-monitor cp ~/.openclaw/skills/skill-system-monitor/config.example.json ~/.openclaw/skills/config/skill-system-monitor/config.json ``` **2. 编辑配置：** ```bash nano ~/.openclaw/skills/config/skill-system-monitor/config.json ``` ### 配置项说明 ```json { "alerts": { "disk": { "warning": 70, // 硬盘警告阈值 (%) "critical": 85 // 硬盘危险阈值 (%) }, "memory": { "warning": 70, // 内存警告阈值 (%) "critical": 85 // 内存危险阈值 (%) }, "cpu": { "warning": 1, // CPU 负载警告 (倍核心数) "critical": 2 // CPU 负载危险 (倍核心数) } }, "monitor": { "disk": true, // 是否监控硬盘 "memory": true, // 是否监控内存 "swap": true, // 是否监控 Swap "cpu": true, // 是否监控 CPU "uptime": true, // 是否显示运行时间 "network": true, // 是否监控网络流量 "disk_io": true, // 是否监控磁盘 I/O "docker": true, // 是否监控 Docker "services": true, // 是否监控关键服务 "top_processes": 5 // TOP 进程数量 } } ``` ### 禁用某些监控 如果不需要某些监控项，可以设置为 `false`： ```json { "monitor": { "disk_io": false, // 不监控磁盘 I/O "docker": false, // 不监控 Docker "services": false // 不监控服务状态 } } ``` ### 自定义服务监控（Linux） 服务监控使用 systemd，如需自定义，可在脚本中修改 `check_service` 函数。 ### 自定义预警阈值 根据服务器配置调整阈值： ```json { "alerts": { "disk": { "warning": 80, // 硬盘 80% 才警告 "critical": 90 // 硬盘 90% 才危险 }, "memory": { "warning": 80, "critical": 90 } } } ``` ## 使用方法 ### 方式一：随时调用（手动触发） 直接运行监控脚本，获取当前系统状态： ```bash # Linux / macOS（自动检测） bash /path/to/skill-system-monitor/scripts/monitor.sh # Windows (PowerShell) powershell -ExecutionPolicy Bypass -File scripts\monitor-windows.ps1 ``` **适用场景**： - 用户询问"系统状态"、"服务器监控"、"资源使用情况" - 排查性能问题 - 临时检查系统健康 ### 方式二：定时任务（推荐） 通过 OpenClaw cron 配置定时监控，自动检测并报告： ```json { "name": "系统监控（每6小时）", "schedule": { "kind": "every", "everyMs": 21600000 }, "payload": { "kind": "systemEvent", "text": "系统监控检查：运行监控脚本，报告系统状态，如有异常立即预警。" }, "sessionTarget": "main" } ``` **适用场景**： - 定期健康检查（建议每 6 小时） - 7x24 小时无人值守监控 - 异常自动告警通知 ### 方式三：对比历史数据 查看资源使用趋势变化： ```bash bash scripts/compare.sh ``` 输出示例： ``` 📊 系统监控报告 ================== 主机: wezn 时间: 2026-03-14 20:57:50 运行时间: up 1 day, 9 hours, 55 minutes 💾 硬盘状态 总容量: 69G | 已用: 45G (68%) | 可用: 22G 状态: ✅正常 🧠 内存状态 总内存: 4G | 已用: 2G (50%) | 可用: 2G Swap: 1G/2G 状态: ✅正常 ⚙️ CPU 负载 (4核) 1分钟: 0.01 | 5分钟: 0.03 | 15分钟: 0.00 状态: ✅正常 🌐 网络流量 接收: 360.2 MB | 发送: 385.9 MB 💿 磁盘 I/O 读: 0/s, 写: 0/s, 利用率: 0.0% 🐳 Docker 容器 运行: 0, 停止: 3 🔧 关键服务 MongoDB: ✅ | MySQL: ✅ | PostgreSQL: ✅ Docker: ✅ | Nginx: ✅ | OpenClaw: ✅ 🔴 资源占用 TOP 5 (内存) 1. clawdbot-gateway - 1122M (30.1%) 2. node (fund) - 129M (3.4%) 3. mongod - 103M (2.7%) ... ``` ### 对比历史数据 ```bash bash scripts/compare.sh ``` 输出示例： ``` 📈 变化趋势对比 ================== 对比时间: 2026-03-14 14:00 → 2026-03-14 20:48 💾 硬盘: 71% → 68% (-3%) 🧠 内存: 55% → 49% (-6%) ``` ### 查看历史记录 ```bash # 列出所有历史记录 ls history/ # 查看特定记录 cat history/2026-03-14_20-48.log ``` ## 目录结构 ``` skill-system-monitor/ ├── SKILL.md # 技能说明文档 ├── scripts/ │ ├── monitor.sh # 主监控脚本（自动检测 OS） │ ├── monitor-linux.sh # Linux 监控脚本 │ ├── monitor-windows.ps1 # Windows 监控脚本 (PowerShell) │ └── compare.sh # 对比脚本（分析变化趋势） └── history/ # 历史记录目录 ├── YYYY-MM-DD_HH-MM.json # JSON 格式（用于对比） └── YYYY-MM-DD_HH-MM.log # 文本格式（人类可读） ``` ## 定时监控配置 ### 推荐：通过 OpenClaw Cron 配置 使用 `cron` 工具配置定时监控任务： ```json { "name": "系统监控（每6小时）", "schedule": { "kind": "every", "everyMs": 21600000 }, "payload": { "kind": "systemEvent", "text": "系统监控检查：请运行监控脚本，检查系统健康状态，如有异常立即报告。" }, "sessionTarget": "main" } ``` ### 定时任务配置示例 **每 6 小时监控（推荐）：** ```json { "name": "系统健康检查", "schedule": { "kind": "every", "everyMs": 21600000 }, "payload": { "kind": "systemEvent", "text": "执行系统监控：运行 bash /home/app/.openclaw/skills/skill-system-monitor/scripts/monitor.sh，检查硬盘、内存、CPU、服务状态，如有异常立即预警。" }, "sessionTarget": "main" } ``` **每天早上 9 点监控：** ```json { "name": "每日系统报告", "schedule": { "kind": "cron", "expr": "0 9 * * *", "tz": "Asia/Shanghai" }, "payload": { "kind": "systemEvent", "text": "每日系统报告：运行监控脚本，生成系统状态报告。" }, "sessionTarget": "main" } ``` ### 预警行为 当监控发现异常时，会在报告中显示 ⚠️ 预警信息： - 硬盘使用率 ≥ 警告阈值（默认 70%） - 内存使用率 ≥ 警告阈值（默认 70%） - CPU 负载过高（> 2倍核心数） - 关键服务停止运行 **预警级别：** - ✅ **正常**：资源使用在合理范围内 - ⚠️ **警告**：资源使用偏高，建议关注 - 🔴 **危险**：资源使用过高，需要立即处理 ## 注意事项 1. **跨平台支持**：脚本会自动检测操作系统，调用对应平台的监控命令 2. **权限要求**： - Linux: 需要读取 `/proc` 文件系统和执行 `df`, `free` 等命令 - Windows: 需要运行 PowerShell 脚本的权限 3. **历史记录**：会持续累积，建议定期清理旧记录 4. **预警阈值**：可在脚本中根据实际情况调整 5. **依赖工具**： - Linux: `bc`（**必需**，用于 CPU 状态计算）、`iostat`（可选，磁盘 I/O） - 安装命令：`apt install bc sysstat -y`（Debian/Ubuntu） - Windows: 无额外依赖 ## 适用系统 | 平台 | 支持状态 | 脚本文件 | |------|----------|----------| | Linux (Ubuntu/Debian) | ✅ 完全支持 | `monitor-linux.sh` | | Linux (CentOS/RHEL) | ✅ 完全支持 | `monitor-linux.sh` | | Linux (Alpine) | ✅ 完全支持 | `monitor-linux.sh` | | macOS | ⚠️ 部分支持 | `monitor-linux.sh` | | Windows 10/11 | ✅ 完全支持 | `monitor-windows.ps1` | | Windows Server | ✅ 完全支持 | `monitor-windows.ps1` | | WSL | ✅ 完全支持 | `monitor-linux.sh` |

path: config.example.json
content: {
  "services": {
    "mongod": {
      "name": "MongoDB",
      "enabled": true,
      "type": "systemd"
    },
    "mysql": {
      "name": "MySQL",
      "enabled": true,
      "type": "systemd"
    },
    "postgresql": {
      "name": "PostgreSQL",
      "enabled": true,
      "type": "systemd"
    },
    "docker": {
      "name": "Docker",
      "enabled": true,
      "type": "systemd"
    },
    "nginx": {
      "name": "Nginx",
      "enabled": true,
      "type": "systemd"
    },
    "openclaw": {
      "name": "OpenClaw",
      "enabled": true,
      "type": "process",
      "pattern": "clawdbot-gateway"
    }
  },
  "alerts": {
    "disk": {
      "warning": 70,
      "critical": 85
    },
    "memory": {
      "warning": 70,
      "critical": 85
    },
    "cpu": {
      "warning": 1,
      "critical": 2,
      "mode": "multiplier"
    }
  },
  "monitor": {
    "disk": true,
    "memory": true,
    "swap": true,
    "cpu": true,
    "uptime": true,
    "network": true,
    "disk_io": true,
    "docker": true,
    "services": true,
    "top_processes": 5
  }
}


path: scripts/compare.sh
content: #!/bin/bash
# 系统监控对比脚本 - 对比最近两次快照

HISTORY_DIR="/home/app/.openclaw/skills/skill-system-monitor/history"

# 获取最近两个 JSON 文件
LATEST_FILES=($(ls -t $HISTORY_DIR/*.json 2>/dev/null | head -2))

if [ ${#LATEST_FILES[@]} -lt 2 ]; then
    echo "⚠️ 历史记录不足，无法对比（需要至少2条记录）"
    exit 0
fi

CURRENT=${LATEST_FILES[0]}
PREVIOUS=${LATEST_FILES[1]}

# 读取数据
CURRENT_DISK=$(cat $CURRENT | grep -o '"percent": [0-9]*' | head -1 | grep -o '[0-9]*')
PREVIOUS_DISK=$(cat $PREVIOUS | grep -o '"percent": [0-9]*' | head -1 | grep -o '[0-9]*')

CURRENT_MEM=$(cat $CURRENT | grep -o '"percent": [0-9]*' | tail -1 | grep -o '[0-9]*')
PREVIOUS_MEM=$(cat $PREVIOUS | grep -o '"percent": [0-9]*' | tail -1 | grep -o '[0-9]*')

CURRENT_TIME=$(cat $CURRENT | grep -o '"timestamp": "[^"]*"' | cut -d'"' -f4)
PREVIOUS_TIME=$(cat $PREVIOUS | grep -o '"timestamp": "[^"]*"' | cut -d'"' -f4)

# 计算变化
DISK_DIFF=$((CURRENT_DISK - PREVIOUS_DISK))
MEM_DIFF=$((CURRENT_MEM - PREVIOUS_MEM))

# 输出对比结果
echo "📈 变化趋势对比"
echo "=================="
echo "对比时间: $PREVIOUS_TIME → $CURRENT_TIME"
echo ""
echo "💾 硬盘: ${PREVIOUS_DISK}% → ${CURRENT_DISK}% ($([ $DISK_DIFF -gt 0 ] && echo "+"; echo "$DISK_DIFF")%)"
echo "🧠 内存: ${PREVIOUS_MEM}% → ${CURRENT_MEM}% ($([ $MEM_DIFF -gt 0 ] && echo "+"; echo "$MEM_DIFF")%)"

# 预警判断
if [ $DISK_DIFF -gt 5 ]; then
    echo ""
    echo "⚠️ 硬盘使用增长较快 (+${DISK_DIFF}%)，建议检查！"
fi

if [ $MEM_DIFF -gt 10 ]; then
    echo ""
    echo "⚠️ 内存使用增长较快 (+${MEM_DIFF}%)，建议检查！"
fi


path: scripts/monitor-linux.sh
content: #!/bin/bash
# 系统监控脚本 - Linux 版本

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HISTORY_DIR="$SCRIPT_DIR/../history"
CONFIG_FILE="$HOME/.openclaw/skills/config/skill-system-monitor/config.json"

# 检查依赖
if ! command -v bc &> /dev/null; then
    echo "❌ 错误: 缺少依赖 'bc'，请安装: apt install bc -y"
    exit 1
fi
TIMESTAMP=$(date "+%Y-%m-%d_%H-%M")
DATE=$(date "+%Y-%m-%d %H:%M:%S")
HOSTNAME=$(hostname)

# 默认配置
DISK_WARNING=70
DISK_CRITICAL=85
MEM_WARNING=70
MEM_CRITICAL=85
MONITOR_DISK=true
MONITOR_MEMORY=true
MONITOR_CPU=true
MONITOR_DOCKER=true
MONITOR_SERVICES=true
TOP_PROCESSES=5

# 读取配置（如果存在）
if [ -f "$CONFIG_FILE" ]; then
    # 简单解析 JSON 配置
    if grep -q '"disk"[[:space:]]*:[[:space:]]*false' "$CONFIG_FILE"; then MONITOR_DISK=false; fi
    if grep -q '"memory"[[:space:]]*:[[:space:]]*false' "$CONFIG_FILE"; then MONITOR_MEMORY=false; fi
    if grep -q '"cpu"[[:space:]]*:[[:space:]]*false' "$CONFIG_FILE"; then MONITOR_CPU=false; fi
    if grep -q '"docker"[[:space:]]*:[[:space:]]*false' "$CONFIG_FILE"; then MONITOR_DOCKER=false; fi
    if grep -q '"services"[[:space:]]*:[[:space:]]*false' "$CONFIG_FILE"; then MONITOR_SERVICES=false; fi
    
    # 读取阈值
    DW=$(grep -A1 '"disk"' "$CONFIG_FILE" | grep '"warning"' | grep -o '[0-9]*' | head -1)
    DC=$(grep -A1 '"disk"' "$CONFIG_FILE" | grep '"critical"' | grep -o '[0-9]*' | head -1)
    MW=$(grep -A1 '"memory"' "$CONFIG_FILE" | grep '"warning"' | grep -o '[0-9]*' | head -1)
    MC=$(grep -A1 '"memory"' "$CONFIG_FILE" | grep '"critical"' | grep -o '[0-9]*' | head -1)
    
    [ -n "$DW" ] && DISK_WARNING=$DW
    [ -n "$DC" ] && DISK_CRITICAL=$DC
    [ -n "$MW" ] && MEM_WARNING=$MW
    [ -n "$MC" ] && MEM_CRITICAL=$MC
fi

# 硬盘信息
DISK_INFO=$(df -h / | tail -1)
DISK_TOTAL=$(echo $DISK_INFO | awk '{print $2}')
DISK_USED=$(echo $DISK_INFO | awk '{print $3}')
DISK_AVAIL=$(echo $DISK_INFO | awk '{print $4}')
DISK_PERCENT=$(echo $DISK_INFO | awk '{print $5}' | tr -d '%')

# 内存信息
MEM_INFO=$(free -m | grep Mem)
MEM_TOTAL=$(echo $MEM_INFO | awk '{printf "%.0f", $2/1024}')
MEM_USED=$(echo $MEM_INFO | awk '{printf "%.0f", $3/1024}')
MEM_AVAIL=$(echo $MEM_INFO | awk '{printf "%.0f", $7/1024}')
MEM_PERCENT=$(echo $MEM_INFO | awk '{printf "%.0f", ($3/$2)*100}')

# Swap 信息
SWAP_INFO=$(free -m | grep Swap)
SWAP_TOTAL=$(echo $SWAP_INFO | awk '{printf "%.0f", $2/1024}')
SWAP_USED=$(echo $SWAP_INFO | awk '{printf "%.0f", $3/1024}')

# CPU 负载
LOAD_AVG=$(cat /proc/loadavg)
LOAD_1=$(echo $LOAD_AVG | awk '{print $1}')
LOAD_5=$(echo $LOAD_AVG | awk '{print $2}')
LOAD_15=$(echo $LOAD_AVG | awk '{print $3}')
CPU_CORES=$(nproc)

# 系统运行时间
UPTIME=$(uptime -p 2>/dev/null || uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}')

# 网络流量
NET_INFO=$(cat /proc/net/dev | grep -E "eth0|ens" | head -1)
NET_RX=$(echo $NET_INFO | awk '{printf "%.1f", $2/1024/1024}')
NET_TX=$(echo $NET_INFO | awk '{printf "%.1f", $10/1024/1024}')

# 磁盘 I/O
if command -v iostat &> /dev/null; then
    DISK_IO=$(iostat -x 1 1 2>/dev/null | grep -A1 "Device" | tail -1 | awk '{printf "读: %.0f/s, 写: %.0f/s, 利用率: %.1f%%", $4, $8, $14}')
else
    DISK_IO="未安装 sysstat"
fi

# 判断状态
get_disk_status() {
    local percent=$1
    if [ $percent -lt $DISK_WARNING ]; then echo "✅正常"
    elif [ $percent -lt $DISK_CRITICAL ]; then echo "⚠️警告"
    else echo "🔴危险"; fi
}

get_mem_status() {
    local percent=$1
    if [ $percent -lt $MEM_WARNING ]; then echo "✅正常"
    elif [ $percent -lt $MEM_CRITICAL ]; then echo "⚠️警告"
    else echo "🔴危险"; fi
}

get_cpu_status() {
    local load=$1
    local cores=$CPU_CORES
    local double_cores=$(echo "$cores * 2" | bc)
    
    if (( $(echo "$load < $cores" | bc -l) )); then echo "✅正常"
    elif (( $(echo "$load < $double_cores" | bc -l) )); then echo "⚠️警告"
    else echo "🔴危险"; fi
}

DISK_STATUS=$(get_disk_status $DISK_PERCENT)
MEM_STATUS=$(get_mem_status $MEM_PERCENT)
CPU_STATUS=$(get_cpu_status $LOAD_1)

# TOP 5 内存进程
TOP_PROCESSES_OUTPUT=$(ps aux --sort=-%mem | head -6 | tail -5 | awk '{printf "%-25s %6s (%s%%)\n", substr($11,1,25), $6/1024"M", $4}')

# Docker 容器状态
if [ "$MONITOR_DOCKER" = "true" ] && command -v docker &> /dev/null; then
    DOCKER_RUNNING=$(docker ps -q 2>/dev/null | wc -l)
    DOCKER_STOPPED=$(docker ps -a --filter "status=exited" -q 2>/dev/null | wc -l)
    DOCKER_INFO="运行: $DOCKER_RUNNING, 停止: $DOCKER_STOPPED"
else
    DOCKER_INFO="未安装或已禁用"
fi

# 关键服务状态
check_service() {
    local name=$1
    local status=$(systemctl is-active $name 2>/dev/null)
    if [ "$status" = "active" ]; then echo "✅"
    elif [ "$status" = "inactive" ]; then echo "❌"
    else echo "❓"; fi
}

check_process() {
    local pattern=$1
    if pgrep -f "$pattern" > /dev/null 2>&1; then echo "✅"
    else echo "❌"; fi
}

SERVICES_STATUS=""
if [ "$MONITOR_SERVICES" = "true" ]; then
    SERVICE_MONGODB=$(check_service mongod)
    SERVICE_MYSQL=$(check_service mysql)
    SERVICE_POSTGRES=$(check_service postgresql)
    SERVICE_DOCKER=$(check_service docker)
    SERVICE_NGINX=$(check_service nginx)
    SERVICE_OPENCLAW=$(check_process "clawdbot-gateway")
    SERVICES_STATUS="MongoDB: $SERVICE_MONGODB | MySQL: $SERVICE_MYSQL | PostgreSQL: $SERVICE_POSTGRES
Docker: $SERVICE_DOCKER | Nginx: $SERVICE_NGINX | OpenClaw: $SERVICE_OPENCLAW"
fi

# 预警信息
WARNINGS=""
if [ $DISK_PERCENT -ge $DISK_CRITICAL ]; then
    WARNINGS="${WARNINGS}🔴 硬盘使用率过高 (${DISK_PERCENT}%)\n"
elif [ $DISK_PERCENT -ge $DISK_WARNING ]; then
    WARNINGS="${WARNINGS}⚠️ 硬盘使用率偏高 (${DISK_PERCENT}%)\n"
fi

if [ $MEM_PERCENT -ge $MEM_CRITICAL ]; then
    WARNINGS="${WARNINGS}🔴 内存使用率过高 (${MEM_PERCENT}%)\n"
elif [ $MEM_PERCENT -ge $MEM_WARNING ]; then
    WARNINGS="${WARNINGS}⚠️ 内存使用率偏高 (${MEM_PERCENT}%)\n"
fi

DOUBLE_CORES=$(echo "$CPU_CORES * 2" | bc)
if (( $(echo "$LOAD_1 > $DOUBLE_CORES" | bc -l) )); then
    WARNINGS="${WARNINGS}🔴 CPU 负载过高 (${LOAD_1})\n"
fi

# 生成报告
REPORT="📊 系统监控报告 (Linux)
==================
主机: $HOSTNAME
时间: $DATE
运行时间: $UPTIME"

if [ "$MONITOR_DISK" = "true" ]; then
REPORT="$REPORT

💾 硬盘状态
总容量: ${DISK_TOTAL} | 已用: ${DISK_USED} (${DISK_PERCENT}%) | 可用: ${DISK_AVAIL}
状态: $DISK_STATUS"
fi

if [ "$MONITOR_MEMORY" = "true" ]; then
REPORT="$REPORT

🧠 内存状态
总内存: ${MEM_TOTAL}G | 已用: ${MEM_USED}G (${MEM_PERCENT}%) | 可用: ${MEM_AVAIL}G
Swap: ${SWAP_USED}G/${SWAP_TOTAL}G
状态: $MEM_STATUS"
fi

if [ "$MONITOR_CPU" = "true" ]; then
REPORT="$REPORT

⚙️ CPU 负载 (${CPU_CORES}核)
1分钟: $LOAD_1 | 5分钟: $LOAD_5 | 15分钟: $LOAD_15
状态: $CPU_STATUS"
fi

REPORT="$REPORT

🌐 网络流量
接收: ${NET_RX} MB | 发送: ${NET_TX} MB

💿 磁盘 I/O
$DISK_IO"

if [ "$MONITOR_DOCKER" = "true" ]; then
REPORT="$REPORT

🐳 Docker 容器
$DOCKER_INFO"
fi

if [ "$MONITOR_SERVICES" = "true" ] && [ -n "$SERVICES_STATUS" ]; then
REPORT="$REPORT

🔧 关键服务
$SERVICES_STATUS"
fi

if [ "$TOP_PROCESSES" -gt 0 ]; then
REPORT="$REPORT

🔴 资源占用 TOP $TOP_PROCESSES (内存)
$TOP_PROCESSES_OUTPUT"
fi

if [ -n "$WARNINGS" ]; then
REPORT="$REPORT

⚠️ 预警信息
$WARNINGS"
fi

# 保存历史记录
mkdir -p "$HISTORY_DIR"
echo "$REPORT" > "$HISTORY_DIR/${TIMESTAMP}.log"

# 保存 JSON
cat > "$HISTORY_DIR/${TIMESTAMP}.json" << EOF
{
  "timestamp": "$DATE",
  "system": "linux",
  "uptime": "$UPTIME",
  "disk": {
    "total": "$DISK_TOTAL",
    "used": "$DISK_USED",
    "available": "$DISK_AVAIL",
    "percent": $DISK_PERCENT
  },
  "memory": {
    "total_mb": $(echo $MEM_INFO | awk '{print $2}'),
    "used_mb": $(echo $MEM_INFO | awk '{print $3}'),
    "available_mb": $(echo $MEM_INFO | awk '{print $7}'),
    "percent": $MEM_PERCENT,
    "swap_used_mb": $(echo $SWAP_INFO | awk '{print $3}'),
    "swap_total_mb": $(echo $SWAP_INFO | awk '{print $2}')
  },
  "cpu": {
    "load_1": $LOAD_1,
    "load_5": $LOAD_5,
    "load_15": $LOAD_15,
    "cores": $CPU_CORES
  },
  "network": {
    "rx_mb": $NET_RX,
    "tx_mb": $NET_TX
  },
  "docker": {
    "running": $DOCKER_RUNNING,
    "stopped": $DOCKER_STOPPED
  }
}
EOF

echo "$REPORT"


path: scripts/monitor.sh
content: #!/bin/bash
# 系统监控主脚本 - 自动检测系统类型并调用对应脚本

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HISTORY_DIR="$SCRIPT_DIR/../history"

# 清理超过 7 天的历史日志
cleanup_old_logs() {
    if [ -d "$HISTORY_DIR" ]; then
        local deleted=$(find "$HISTORY_DIR" -type f -name "*.json" -o -name "*.log" 2>/dev/null | xargs -r stat --format="%Y %n" 2>/dev/null | while read timestamp filepath; do
            local age_days=$(( ($(date +%s) - timestamp) / 86400 ))
            if [ "$age_days" -gt 7 ]; then
                rm -f "$filepath"
                echo "$filepath"
            fi
        done)
        if [ -n "$deleted" ] && [ -n "$(echo "$deleted" | tr -d '[:space:]')" ]; then
            echo "🧹 已清理超过 7 天的历史日志"
        fi
    fi
}

# 执行清理
cleanup_old_logs

# 检测操作系统
detect_os() {
    case "$(uname -s)" in
        Linux*)     echo "linux" ;;
        Darwin*)    echo "macos" ;;
        CYGWIN*)    echo "windows" ;;
        MINGW*)     echo "windows" ;;
        MSYS*)      echo "windows" ;;
        *)          echo "unknown" ;;
    esac
}

OS=$(detect_os)

case "$OS" in
    linux)
        if [ -f "$SCRIPT_DIR/monitor-linux.sh" ]; then
            bash "$SCRIPT_DIR/monitor-linux.sh"
        else
            echo "❌ 错误: 找不到 monitor-linux.sh"
            exit 1
        fi
        ;;
    macos)
        if [ -f "$SCRIPT_DIR/monitor-macos.sh" ]; then
            bash "$SCRIPT_DIR/monitor-macos.sh"
        else
            echo "❌ 错误: 找不到 monitor-macos.sh (尚未实现)"
            exit 1
        fi
        ;;
    windows)
        if [ -f "$SCRIPT_DIR/monitor-windows.ps1" ]; then
            powershell.exe -ExecutionPolicy Bypass -File "$SCRIPT_DIR/monitor-windows.ps1"
        else
            echo "❌ 错误: 找不到 monitor-windows.ps1"
            exit 1
        fi
        ;;
    *)
        echo "❌ 错误: 不支持的操作系统 $(uname -s)"
        exit 1
        ;;
esac


path: scripts/trend.sh
content: #!/bin/bash
# 7日趋势图（QuickChart）

HISTORY_DIR="/home/app/.openclaw/skills/skill-system-monitor/history"
DAYS=7

python3 << 'PYEOF'
import os
import json
import urllib.parse
from datetime import datetime, timedelta
from collections import defaultdict

HISTORY_DIR = "/home/app/.openclaw/skills/skill-system-monitor/history"
DAYS = 7

day_disk = defaultdict(list)
day_mem = defaultdict(list)

cutoff = datetime.now() - timedelta(days=DAYS)

for filename in os.listdir(HISTORY_DIR):
    if not filename.endswith('.json'):
        continue
    
    filepath = os.path.join(HISTORY_DIR, filename)
    mtime = datetime.fromtimestamp(os.path.getmtime(filepath))
    
    if mtime < cutoff:
        continue
    
    day = mtime.strftime('%Y-%m-%d')
    
    try:
        with open(filepath) as f:
            content = f.read()
            import re
            percents = re.findall(r'"percent":\s*(\d+)', content)
            if len(percents) >= 2:
                day_disk[day].append(int(percents[0]))
                day_mem[day].append(int(percents[-1]))
    except:
        continue

if not day_disk:
    print("⚠️ 无历史数据")
    exit(0)

sorted_days = sorted(day_disk.keys())

# 今天和昨天对比
today = datetime.now().strftime('%Y-%m-%d')
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')

print("📈 7日系统监控趋势")
print("================================")

if today in day_disk and yesterday in day_disk:
    today_disk = sum(day_disk[today]) // len(day_disk[today])
    yesterday_disk = sum(day_disk[yesterday]) // len(day_disk[yesterday])
    today_mem = sum(day_mem[today]) // len(day_mem[today])
    yesterday_mem = sum(day_mem[yesterday]) // len(day_mem[yesterday])
    
    disk_diff = today_disk - yesterday_disk
    mem_diff = today_mem - yesterday_mem
    
    disk_sign = "+" if disk_diff > 0 else ""
    mem_sign = "+" if mem_diff > 0 else ""
    
    print(f"💾 硬盘: {yesterday_disk}% → {today_disk}% ({disk_sign}{disk_diff}%)")
    print(f"🧠 内存: {yesterday_mem}% → {today_mem}% ({mem_sign}{mem_diff}%)")
    
    if disk_diff > 5:
        print("⚠️ 硬盘使用增长较快！")
    if mem_diff > 10:
        print("⚠️ 内存使用增长较快！")
else:
    print("⚠️ 缺少昨日数据，无法对比")

# QuickChart 链接
labels = [d[5:] for d in sorted_days]
disk_data = [sum(day_disk[d]) // len(day_disk[d]) for d in sorted_days]
mem_data = [sum(day_mem[d]) // len(day_mem[d]) for d in sorted_days]

config = {
    "type": "line",
    "data": {
        "labels": labels,
        "datasets": [
            {
                "label": "Disk (%)",
                "data": disk_data,
                "borderColor": "#3498db",
                "fill": False
            },
            {
                "label": "Memory (%)",
                "data": mem_data,
                "borderColor": "#e74c3c",
                "fill": False
            }
        ]
    },
    "options": {
        "title": {
            "display": True,
            "text": "7-Day System Monitor"
        }
    }
}

encoded = urllib.parse.quote(json.dumps(config))
print()
print("📊 图表:")
print(f"https://quickchart.io/chart?w=500&h=300&c={encoded}")
PYEOF


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)