auto-sync: 2026-05-22 18:26:46
This commit is contained in:
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Executable
+140
@@ -0,0 +1,140 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# status.sh — 查看 moziplus v2 运行状态
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TARGET_DIR="$HOME/.sanguo_projects/sanguo_moziplus_v2"
|
||||||
|
PM2_NAME="sanguo-moziplus-v2"
|
||||||
|
HEALTH_URL="http://localhost:8083/api/health"
|
||||||
|
DETAILED=false
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 [options]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --target=DIR 安装目录"
|
||||||
|
echo " -v, --verbose 显示详细信息(项目列表、磁盘占用等)"
|
||||||
|
echo " -h, --help 显示帮助"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--target=*) TARGET_DIR="${arg#*=}" ;;
|
||||||
|
-v|--verbose) DETAILED=true ;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " moziplus v2 — Status"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
|
||||||
|
# ── 版本 ──
|
||||||
|
VERSION=$(cd "$TARGET_DIR" 2>/dev/null && python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])' 2>/dev/null || echo 'unknown')
|
||||||
|
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 ""
|
||||||
|
PM2_STATUS=$(pm2 jlist 2>/dev/null | python3 -c "
|
||||||
|
import sys, json
|
||||||
|
procs = json.load(sys.stdin)
|
||||||
|
for p in procs:
|
||||||
|
if p['name'] == '$PM2_NAME':
|
||||||
|
s = p['pm2_env']['status']
|
||||||
|
pid = p['pid'] or '-'
|
||||||
|
uptime = p['pm2_env'].get('pm_uptime', 0)
|
||||||
|
restarts = p['pm2_env'].get('restart_time', 0)
|
||||||
|
mem = p['monit'].get('memory', 0)
|
||||||
|
mem_mb = round(mem / 1024 / 1024, 1)
|
||||||
|
cpu = p['monit'].get('cpu', 0)
|
||||||
|
print(f'{s}|{pid}|{uptime}|{restarts}|{mem_mb}|{cpu}')
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print('not_found|||||')
|
||||||
|
" 2>/dev/null || echo 'error|||||')
|
||||||
|
|
||||||
|
IFS='|' read -r STATUS PID UPTIME RESTARTS MEM CPU <<< "$PM2_STATUS"
|
||||||
|
if [ "$STATUS" = "online" ]; then
|
||||||
|
# 计算 uptime
|
||||||
|
if [ -n "$UPTIME" ] && [ "$UPTIME" != "0" ]; then
|
||||||
|
UPTIME_FMT=$(python3 -c "
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
delta = datetime.now(timezone.utc) - datetime.fromtimestamp($UPTIME/1000, tz=timezone.utc)
|
||||||
|
days = delta.days
|
||||||
|
hours, rem = divmod(delta.seconds, 3600)
|
||||||
|
mins, _ = divmod(rem, 60)
|
||||||
|
parts = []
|
||||||
|
if days: parts.append(f'{days}d')
|
||||||
|
if hours: parts.append(f'{hours}h')
|
||||||
|
parts.append(f'{mins}m')
|
||||||
|
print(' '.join(parts))
|
||||||
|
" 2>/dev/null || echo '?')
|
||||||
|
else
|
||||||
|
UPTIME_FMT="just started"
|
||||||
|
fi
|
||||||
|
echo " PM2: online ✅"
|
||||||
|
echo " PID: $PID"
|
||||||
|
echo " Uptime: $UPTIME_FMT"
|
||||||
|
echo " Restarts: $RESTARTS"
|
||||||
|
echo " Memory: ${MEM}MB"
|
||||||
|
echo " CPU: ${CPU}%"
|
||||||
|
else
|
||||||
|
echo " PM2: $STATUS ❌"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 健康检查 ──
|
||||||
|
echo ""
|
||||||
|
HEALTH=$(curl -sf "$HEALTH_URL" 2>/dev/null || echo '{"status":"unreachable"}')
|
||||||
|
HEALTH_STATUS=$(echo "$HEALTH" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','unknown'))" 2>/dev/null || echo 'unknown')
|
||||||
|
if [ "$HEALTH_STATUS" = "ok" ]; then
|
||||||
|
echo " Health: ok ✅"
|
||||||
|
else
|
||||||
|
echo " Health: $HEALTH_STATUS ❌"
|
||||||
|
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 ""
|
||||||
|
echo " Config:"
|
||||||
|
echo " Port: $(grep -o 'port:.*' "$TARGET_DIR/config/default.yaml" 2>/dev/null | head -1 || echo '8083 (default)')"
|
||||||
|
echo " Interval: $(grep -o 'interval:.*' "$TARGET_DIR/config/default.yaml" 2>/dev/null | head -1 || echo '?')"
|
||||||
|
echo " Agents: $(grep 'agents:' -A 20 "$TARGET_DIR/config/default.yaml" 2>/dev/null | grep ' - ' | wc -l | tr -d ' ') configured"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
Regular → Executable
Reference in New Issue
Block a user