#!/usr/bin/env bash # status.sh — 查看 moziplus v2 运行状态 set -euo pipefail TARGET_DIR="$HOME/.sanguo_projects/sanguo_moziplus_v2" PM2_NAME="sanguo-moziplus-v2" DETAILED=false usage() { echo "Usage: $0 [options]" echo " -v, --verbose 显示详细信息" echo " -h, --help 显示帮助" exit 0 } for arg in "$@"; do case "$arg" in -v|--verbose) DETAILED=true ;; -h|--help) usage ;; esac done echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " moziplus v2 — Status" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" # ── 版本 ── VERSION=$(grep "^version" "$TARGET_DIR/pyproject.toml" 2>/dev/null | head -1 | cut -d= -f2 | tr -d " \"\047\t") echo " Version: v${VERSION}" # ── 安装目录 ── if [ -d "$TARGET_DIR" ]; then echo " Install: $TARGET_DIR ✅" else echo " Install: $TARGET_DIR ❌ (not found)" exit 1 fi # ── PM2 状态 ── echo "" if pm2 describe "$PM2_NAME" >/dev/null 2>&1; then PM2_DESC=$(pm2 describe "$PM2_NAME" 2>/dev/null) STATUS=$(echo "$PM2_DESC" | grep "status" | head -1 | perl -pe 's/.*?\s+(\S+)\s*$/\1/') PID=$(echo "$PM2_DESC" | grep -E "pid " | head -1 | perl -pe 's/.*?\s+(\d+)\s*$/\1/') UPTIME=$(echo "$PM2_DESC" | grep "uptime" | head -1 | perl -pe 's/^.*\x{2502}\s*//; s/\s*$//') RESTARTS=$(echo "$PM2_DESC" | grep "restarts" | head -1 | perl -pe 's/^.*\x{2502}\s*//; s/\s*$//') if [ "$STATUS" = "online" ]; then echo " PM2: online ✅" else echo " PM2: $STATUS ❌" fi echo " PID: ${PID:-?}" echo " Uptime: ${UPTIME:-?}" echo " Restarts: ${RESTARTS:-0}" # Memory/CPU from pm2 list PM2_MEM_CPU=$(pm2 jlist 2>/dev/null | python3 -c " import sys, json for p in json.load(sys.stdin): if p['name'] == '$PM2_NAME': m = round(p['monit']['memory'] / 1024 / 1024, 1) c = p['monit']['cpu'] print(f'{m}|{c}') break " 2>/dev/null || echo "?|?") IFS='|' read -r MEM CPU <<< "$PM2_MEM_CPU" echo " Memory: ${MEM}MB" echo " CPU: ${CPU}%" else echo " PM2: not found ❌" fi # ── 健康检查 ── echo "" HEALTH=$(curl -sf http://localhost:8083/api/daemon/status 2>/dev/null || echo "") if [ -n "$HEALTH" ]; then H_STATUS=$(echo "$HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('status','?'))" 2>/dev/null || echo "?") H_TICKS=$(echo "$HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('tick_count','?'))" 2>/dev/null || echo "?") H_VERSION=$(echo "$HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('version','?'))" 2>/dev/null || echo "?") echo " Health: ${H_STATUS} ✅" echo " API ver: ${H_VERSION}" echo " Ticks: ${H_TICKS}" else echo " Health: unreachable ❌" fi # ── 数据统计 ── echo "" DATA_DIR="$TARGET_DIR/data" if [ -d "$DATA_DIR" ]; then PROJ_COUNT=$(find "$DATA_DIR" -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ') DATA_SIZE=$(du -sh "$DATA_DIR" 2>/dev/null | cut -f1) echo " Projects: $PROJ_COUNT" echo " Data size: $DATA_SIZE" if [ "$DETAILED" = true ]; then echo "" echo " Project details:" for proj_dir in "$DATA_DIR"/*/; do proj_name=$(basename "$proj_dir") db_file="$proj_dir/blackboard.db" if [ -f "$db_file" ]; then TASK_COUNT=$(sqlite3 "$db_file" "SELECT COUNT(*) FROM tasks" 2>/dev/null || echo "?") ACTIVE_COUNT=$(sqlite3 "$db_file" "SELECT COUNT(*) FROM tasks WHERE status NOT IN ('done','cancelled','archived')" 2>/dev/null || echo "?") PROJ_SIZE=$(du -sh "$proj_dir" 2>/dev/null | cut -f1) printf " %-25s %s tasks (%s active) %s\n" "$proj_name" "$TASK_COUNT" "$ACTIVE_COUNT" "$PROJ_SIZE" else printf " %-25s (no db)\n" "$proj_name" fi done fi fi # ── 配置 ── if [ "$DETAILED" = true ]; then echo "" CONFIG_YAML="$TARGET_DIR/config/default.yaml" if [ -f "$CONFIG_YAML" ]; then echo " Config:" PORT_VAL=$(grep "port:" "$CONFIG_YAML" 2>/dev/null | head -1 | awk '{print $2}') INTERVAL_VAL=$(grep "interval:" "$CONFIG_YAML" 2>/dev/null | head -1 | awk '{print $2}') AGENT_COUNT=$(grep " - " "$CONFIG_YAML" 2>/dev/null | wc -l | tr -d ' ') echo " Port: ${PORT_VAL:-8083}" echo " Interval: ${INTERVAL_VAL:-30}" echo " Agents: ${AGENT_COUNT:-0} configured" fi fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"