Skill: damiencronw/port-manager (version 1.0.0)

--- name: port-manager description: "Port Manager - Track and manage system port usage. Use when: (1) Port conflict when installing software, (2) Check port usage, (3) Release occupied ports, (4) List all recorded service ports" metadata: {"openclaw": {"emoji": "🔌"}} --- # Port Manager Skill Intelligently manage system port usage and avoid conflicts. ## Features ### 1. Record Port (--record) Record a port when starting a service: ``` Port record <service_name> <port> Example: port record postgres 5432 ``` ### 2. Query Port (--query) Check usage of a specific port: ``` Port query 5432 ``` ### 3. List All Ports (--list) Show all recorded services and ports: ``` Port list ``` ### 4. Free Port (--free) Release an occupied port (terminate the process): ``` Port free 5432 ``` ### 5. Check and Resolve Conflicts (--check) Check if a port is occupied, and ask user if they want to free it: ``` Port check 5432 ``` ### 6. Auto Port Allocation (--allocate) When port is occupied, automatically allocate an available port: ``` Port allocate <service_name> [preferred_port] ``` ## File Location - Port records: `~/.openclaw/workspace/.port-manager/ports.json` ## Usage Scenarios 1. **Check before installing software** - Check port 5432 before installing PostgreSQL - If occupied, ask user whether to free it 2. **Service startup recording** - Record ports like 2375, 5432 when starting Docker - Quickly see which services should run after restart 3. **Port conflict resolution** - Two services fighting for the same port - Auto-assign new port or free old port ## Command Examples ```bash # Record ports port record mysql 3306 port record redis 6379 port record postgres 5432 # List all port list # Check port port check 8080 # Free port port free 5432 # Auto allocate port allocate nginx 80 ``` ## Implementation Use `lsof` and `netstat` to check ports: ```bash # Check port usage lsof -i :5432 # Kill process kill $(lsof -t -i :5432) ```

path: port-manager/_meta.json
content: {
  "name": "port-manager",
  "version": "1.0.0",
  "author": "damien",
  "description": "Port Manager - Track and manage system port usage, avoid conflicts",
  "keywords": ["port", "manager", "network", "system"],
  "platform": ["darwin", "linux"],
  "license": "MIT"
}


path: _meta.json
content: {
  "name": "port-manager",
  "version": "1.0.0",
  "author": "damien",
  "description": "Port Manager - Track and manage system port usage, avoid conflicts",
  "keywords": ["port", "manager", "network", "system"],
  "platform": ["darwin", "linux"],
  "license": "MIT"
}


path: scripts/port.sh
content: #!/bin/bash

# Port Manager - 端口管理脚本

PORTS_FILE="$HOME/.openclaw/workspace/skills/port-manager/.data/ports.json"

# 初始化文件
init_file() {
    if [ ! -f "$PORTS_FILE" ]; then
        mkdir -p "$(dirname "$PORTS_FILE")"
        echo '{"services": []}' > "$PORTS_FILE"
    fi
}

# 记录端口
record() {
    init_file
    local service=$1
    local port=$2
    
    if [ -z "$service" ] || [ -z "$port" ]; then
        echo "用法: port record <服务名> <端口>"
        return 1
    fi
    
    # 检查端口是否已被占用
    local pid=$(lsof -t -i :$port 2>/dev/null)
    local existing_service=""
    
    if [ -n "$pid" ]; then
        existing_service=$(ps -p $pid - comm= 2>/dev/null | head -1)
        echo "⚠️  端口 $port 已被占用 (PID: $pid, 进程: $existing_service)"
    fi
    
    # 使用 jq 更新 JSON
    local temp=$(mktemp)
    jq --arg service "$service" --arg port "$port" \
        '.services |= map(select(.service != $service)) + [{"service": $service, "port": $port, "recorded_at": now | strftime("%Y-%m-%d %H:%M:%S")}]' \
        "$PORTS_FILE" > "$temp" && mv "$temp" "$PORTS_FILE"
    
    echo "✅ 已记录: $service -> 端口 $port"
}

# 列出所有端口
list() {
    init_file
    echo "📋 已记录的端口:"
    echo ""
    jq -r '.services[] | "  \(.service): 端口 \(.port) (记录于: \(.recorded_at))"' "$PORTS_FILE"
    echo ""
    echo "📡 当前系统端口占用:"
    echo ""
    lsof -i -P -n 2>/dev/null | grep LISTEN | awk '{print "  端口 " $9 " -> " $1 " (PID: " $2 ")"}' | sed 's/.*: //' | sort -u
}

# 查询端口
query() {
    local port=$1
    
    if [ -z "$port" ]; then
        echo "用法: port query <端口>"
        return 1
    fi
    
    echo "🔍 端口 $port 占用情况:"
    
    # 检查系统
    local info=$(lsof -i :$port 2>/dev/null)
    if [ -n "$info" ]; then
        echo "$info"
    else
        echo "  当前没有被占用"
    fi
    
    # 检查记录
    local recorded=$(jq -r --arg port "$port" '.services[] | select(.port == $port) | .service' "$PORTS_FILE" 2>/dev/null)
    if [ -n "$recorded" ]; then
        echo "  已记录的服务: $recorded"
    fi
}

# 释放端口
free() {
    local port=$1
    
    if [ -z "$port" ]; then
        echo "用法: port free <端口>"
        return 1
    fi
    
    # 获取占用进程
    local pid=$(lsof -t -i :$port 2>/dev/null)
    
    if [ -z "$pid" ]; then
        echo "端口 $port 没有被占用"
        return 1
    fi
    
    local pname=$(ps -p $pid - comm= 2>/dev/null | head -1)
    echo "⚠️  端口 $port 被 $pname (PID: $pid) 占用"
    echo "是否释放? (y/n)"
    
    read -r confirm
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        kill $pid
        echo "✅ 已释放端口 $port (终止了进程 $pid)"
    else
        echo "❌ 已取消"
    fi
}

# 检查端口
check() {
    local port=$1
    
    if [ -z "$port" ]; then
        echo "用法: port check <端口>"
        return 1
    fi
    
    local pid=$(lsof -t -i :$port 2>/dev/null)
    
    if [ -n "$pid" ]; then
        local pname=$(ps -p $pid - comm= 2>/dev/null | head -1)
        echo "⚠️  端口 $port 已被占用!"
        echo "  进程: $pname (PID: $pid)"
        
        # 查找记录
        local recorded=$(jq -r --arg port "$port" '.services[] | select(.port == $port) | .service' "$PORTS_FILE" 2>/dev/null)
        if [ -n "$recorded" ]; then
            echo "  已记录的服务: $recorded"
        fi
        
        echo ""
        echo "是否释放此端口? (y/n)"
        read -r confirm
        if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
            free $port
        fi
    else
        echo "✅ 端口 $port 可用"
    fi
}

# 自动分配端口
allocate() {
    local service=$1
    local preferred=$2
    
    if [ -z "$service" ]; then
        echo "用法: port allocate <服务名> [首选端口]"
        return 1
    fi
    
    local port=$preferred
    
    # 如果没有首选，随机一个
    if [ -z "$port" ]; then
        port=$((8000 + RANDOM % 1000))
    fi
    
    # 检查端口
    while true; do
        if lsof -t -i :$port >/dev/null 2>&1; then
            if [ -n "$preferred" ]; then
                echo "⚠️  首选端口 $port 被占用"
            fi
            port=$((port + 1))
            if [ $port -gt 9000 ]; then
                echo "❌ 无法找到可用端口"
                return 1
            fi
        else
            break
        fi
    done
    
    echo "✅ 为 $service 分配端口: $port"
    record $service $port
}

# 主命令
case "$1" in
    record)
        record "$2" "$3"
        ;;
    list)
        list
        ;;
    query)
        query "$2"
        ;;
    free)
        free "$2"
        ;;
    check)
        check "$2"
        ;;
    allocate)
        allocate "$2" "$3"
        ;;
    *)
        echo "Port Manager - 端口管理工具"
        echo ""
        echo "用法: port <命令> [参数]"
        echo ""
        echo "命令:"
        echo "  record <服务名> <端口>   记录端口占用"
        echo "  list                      列出所有记录的端口"
        echo "  query <端口>              查询端口占用情况"
        echo "  free <端口>               释放指定端口"
        echo "  check <端口>             检查端口并询问是否释放"
        echo "  allocate <服务名> [端口]  自动分配可用端口"
        ;;
esac


path: .data/ports.json
content: {
  "services": [
    {"service": "postgres", "port": "5432", "recorded_at": "2026-03-11 02:22"},
    {"service": "rapportd", "port": "49152", "recorded_at": "2026-03-11 02:22"},
    {"service": "ARDAgent", "port": "3283", "recorded_at": "2026-03-11 02:22"},
    {"service": "Doubao", "port": "49853", "recorded_at": "2026-03-11 02:22"},
    {"service": "DingTalk", "port": "8440", "recorded_at": "2026-03-11 02:22"},
    {"service": "GitHub", "port": "49160", "recorded_at": "2026-03-11 02:22"},
    {"service": "mosquitto", "port": "1883", "recorded_at": "2026-03-11 02:22"},
    {"service": "Ollama", "port": "49498", "recorded_at": "2026-03-11 02:22"},
    {"service": "ollama", "port": "11434", "recorded_at": "2026-03-11 02:22"},
    {"service": "Python", "port": "8188", "recorded_at": "2026-03-11 02:22"},
    {"service": "OpenClaw", "port": "18789", "recorded_at": "2026-03-11 02:22"},
    {"service": "OpenClaw-alt", "port": "18791", "recorded_at": "2026-03-11 02:22"},
    {"service": "OpenClaw-alt2", "port": "18792", "recorded_at": "2026-03-11 02:22"},
    {"service": "Google", "port": "18800", "recorded_at": "2026-03-11 02:22"},
    {"service": "node-5678", "port": "5678", "recorded_at": "2026-03-11 02:22"},
    {"service": "node-5679", "port": "5679", "recorded_at": "2026-03-11 02:22"},
    {"service": "wpsclouds", "port": "4709", "recorded_at": "2026-03-11 02:22"},
    {"service": "wpsclouds-2", "port": "57307", "recorded_at": "2026-03-11 02:22"}
  ]
}


path: port-manager/.data/ports.json
content: {
  "services": [
    {"service": "postgres", "port": "5432", "recorded_at": "2026-03-11 02:22"},
    {"service": "rapportd", "port": "49152", "recorded_at": "2026-03-11 02:22"},
    {"service": "ARDAgent", "port": "3283", "recorded_at": "2026-03-11 02:22"},
    {"service": "Doubao", "port": "49853", "recorded_at": "2026-03-11 02:22"},
    {"service": "DingTalk", "port": "8440", "recorded_at": "2026-03-11 02:22"},
    {"service": "GitHub", "port": "49160", "recorded_at": "2026-03-11 02:22"},
    {"service": "mosquitto", "port": "1883", "recorded_at": "2026-03-11 02:22"},
    {"service": "Ollama", "port": "49498", "recorded_at": "2026-03-11 02:22"},
    {"service": "ollama", "port": "11434", "recorded_at": "2026-03-11 02:22"},
    {"service": "Python", "port": "8188", "recorded_at": "2026-03-11 02:22"},
    {"service": "OpenClaw", "port": "18789", "recorded_at": "2026-03-11 02:22"},
    {"service": "OpenClaw-alt", "port": "18791", "recorded_at": "2026-03-11 02:22"},
    {"service": "OpenClaw-alt2", "port": "18792", "recorded_at": "2026-03-11 02:22"},
    {"service": "Google", "port": "18800", "recorded_at": "2026-03-11 02:22"},
    {"service": "node-5678", "port": "5678", "recorded_at": "2026-03-11 02:22"},
    {"service": "node-5679", "port": "5679", "recorded_at": "2026-03-11 02:22"},
    {"service": "wpsclouds", "port": "4709", "recorded_at": "2026-03-11 02:22"},
    {"service": "wpsclouds-2", "port": "57307", "recorded_at": "2026-03-11 02:22"}
  ]
}


path: port-manager/scripts/port.sh
content: #!/bin/bash

# Port Manager - 端口管理脚本

PORTS_FILE="$HOME/.openclaw/workspace/skills/port-manager/.data/ports.json"

# 初始化文件
init_file() {
    if [ ! -f "$PORTS_FILE" ]; then
        mkdir -p "$(dirname "$PORTS_FILE")"
        echo '{"services": []}' > "$PORTS_FILE"
    fi
}

# 记录端口
record() {
    init_file
    local service=$1
    local port=$2
    
    if [ -z "$service" ] || [ -z "$port" ]; then
        echo "用法: port record <服务名> <端口>"
        return 1
    fi
    
    # 检查端口是否已被占用
    local pid=$(lsof -t -i :$port 2>/dev/null)
    local existing_service=""
    
    if [ -n "$pid" ]; then
        existing_service=$(ps -p $pid - comm= 2>/dev/null | head -1)
        echo "⚠️  端口 $port 已被占用 (PID: $pid, 进程: $existing_service)"
    fi
    
    # 使用 jq 更新 JSON
    local temp=$(mktemp)
    jq --arg service "$service" --arg port "$port" \
        '.services |= map(select(.service != $service)) + [{"service": $service, "port": $port, "recorded_at": now | strftime("%Y-%m-%d %H:%M:%S")}]' \
        "$PORTS_FILE" > "$temp" && mv "$temp" "$PORTS_FILE"
    
    echo "✅ 已记录: $service -> 端口 $port"
}

# 列出所有端口
list() {
    init_file
    echo "📋 已记录的端口:"
    echo ""
    jq -r '.services[] | "  \(.service): 端口 \(.port) (记录于: \(.recorded_at))"' "$PORTS_FILE"
    echo ""
    echo "📡 当前系统端口占用:"
    echo ""
    lsof -i -P -n 2>/dev/null | grep LISTEN | awk '{print "  端口 " $9 " -> " $1 " (PID: " $2 ")"}' | sed 's/.*: //' | sort -u
}

# 查询端口
query() {
    local port=$1
    
    if [ -z "$port" ]; then
        echo "用法: port query <端口>"
        return 1
    fi
    
    echo "🔍 端口 $port 占用情况:"
    
    # 检查系统
    local info=$(lsof -i :$port 2>/dev/null)
    if [ -n "$info" ]; then
        echo "$info"
    else
        echo "  当前没有被占用"
    fi
    
    # 检查记录
    local recorded=$(jq -r --arg port "$port" '.services[] | select(.port == $port) | .service' "$PORTS_FILE" 2>/dev/null)
    if [ -n "$recorded" ]; then
        echo "  已记录的服务: $recorded"
    fi
}

# 释放端口
free() {
    local port=$1
    
    if [ -z "$port" ]; then
        echo "用法: port free <端口>"
        return 1
    fi
    
    # 获取占用进程
    local pid=$(lsof -t -i :$port 2>/dev/null)
    
    if [ -z "$pid" ]; then
        echo "端口 $port 没有被占用"
        return 1
    fi
    
    local pname=$(ps -p $pid - comm= 2>/dev/null | head -1)
    echo "⚠️  端口 $port 被 $pname (PID: $pid) 占用"
    echo "是否释放? (y/n)"
    
    read -r confirm
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        kill $pid
        echo "✅ 已释放端口 $port (终止了进程 $pid)"
    else
        echo "❌ 已取消"
    fi
}

# 检查端口
check() {
    local port=$1
    
    if [ -z "$port" ]; then
        echo "用法: port check <端口>"
        return 1
    fi
    
    local pid=$(lsof -t -i :$port 2>/dev/null)
    
    if [ -n "$pid" ]; then
        local pname=$(ps -p $pid - comm= 2>/dev/null | head -1)
        echo "⚠️  端口 $port 已被占用!"
        echo "  进程: $pname (PID: $pid)"
        
        # 查找记录
        local recorded=$(jq -r --arg port "$port" '.services[] | select(.port == $port) | .service' "$PORTS_FILE" 2>/dev/null)
        if [ -n "$recorded" ]; then
            echo "  已记录的服务: $recorded"
        fi
        
        echo ""
        echo "是否释放此端口? (y/n)"
        read -r confirm
        if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
            free $port
        fi
    else
        echo "✅ 端口 $port 可用"
    fi
}

# 自动分配端口
allocate() {
    local service=$1
    local preferred=$2
    
    if [ -z "$service" ]; then
        echo "用法: port allocate <服务名> [首选端口]"
        return 1
    fi
    
    local port=$preferred
    
    # 如果没有首选，随机一个
    if [ -z "$port" ]; then
        port=$((8000 + RANDOM % 1000))
    fi
    
    # 检查端口
    while true; do
        if lsof -t -i :$port >/dev/null 2>&1; then
            if [ -n "$preferred" ]; then
                echo "⚠️  首选端口 $port 被占用"
            fi
            port=$((port + 1))
            if [ $port -gt 9000 ]; then
                echo "❌ 无法找到可用端口"
                return 1
            fi
        else
            break
        fi
    done
    
    echo "✅ 为 $service 分配端口: $port"
    record $service $port
}

# 主命令
case "$1" in
    record)
        record "$2" "$3"
        ;;
    list)
        list
        ;;
    query)
        query "$2"
        ;;
    free)
        free "$2"
        ;;
    check)
        check "$2"
        ;;
    allocate)
        allocate "$2" "$3"
        ;;
    *)
        echo "Port Manager - 端口管理工具"
        echo ""
        echo "用法: port <命令> [参数]"
        echo ""
        echo "命令:"
        echo "  record <服务名> <端口>   记录端口占用"
        echo "  list                      列出所有记录的端口"
        echo "  query <端口>              查询端口占用情况"
        echo "  free <端口>               释放指定端口"
        echo "  check <端口>             检查端口并询问是否释放"
        echo "  allocate <服务名> [端口]  自动分配可用端口"
        ;;
esac


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