Bladeren bron

refactor(docker): 简化 Web 服务器配置,统一 MCP 端口环境变量,新增 Issue 审核,升级至 v6.6.1/mcp-v4.0.3

sansan 1 maand geleden
bovenliggende
commit
fb89342bf7
15 gewijzigde bestanden met toevoegingen van 133 en 164 verwijderingen
  1. 96 0
      .github/workflows/issue-guard.yml
  2. 4 9
      README-EN.md
  3. 4 9
      README.md
  4. 10 14
      docker/.env
  5. 3 5
      docker/Dockerfile.mcp
  6. 2 4
      docker/docker-compose-build.yml
  7. 2 4
      docker/docker-compose.yml
  8. 3 22
      docker/entrypoint.sh
  9. 3 91
      docker/manage.py
  10. 1 1
      mcp_server/__init__.py
  11. 1 1
      pyproject.toml
  12. 1 1
      trendradar/__init__.py
  13. 1 1
      uv.lock
  14. 1 1
      version
  15. 1 1
      version_mcp

+ 96 - 0
.github/workflows/issue-guard.yml

@@ -0,0 +1,96 @@
+name: Issue Guard
+
+on:
+  issues:
+    types: [opened]
+  issue_comment:
+    types: [created]
+  pull_request_review_comment:
+    types: [created]
+
+jobs:
+  moderate:
+    runs-on: ubuntu-latest
+    permissions:
+      issues: write
+      pull-requests: write
+      models: read
+      contents: read
+    steps:
+      - uses: actions/checkout@v4
+
+      # AI 内容审核(垃圾检测 + 链接检测 + AI 生成检测)
+      - uses: github/ai-moderator@v1
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
+          spam-label: 'spam'
+          ai-label: 'ai-generated'
+          minimize-detected-comments: true
+          enable-spam-detection: true
+          enable-link-spam-detection: true
+          enable-ai-detection: true
+
+      # 账号年龄检查(仅针对新建 Issue)
+      - name: Account age check
+        if: github.event_name == 'issues'
+        uses: actions/github-script@v7
+        with:
+          script: |
+            const issue = context.payload.issue;
+            const username = issue.user.login;
+
+            // 跳过项目成员
+            if (['OWNER', 'MEMBER', 'COLLABORATOR'].includes(issue.author_association)) {
+              core.info(`Skip check for ${username} (${issue.author_association})`);
+              return;
+            }
+
+            // 获取用户信息
+            const { data: user } = await github.rest.users.getByUsername({ username });
+            const accountAgeDays = Math.floor((Date.now() - new Date(user.created_at)) / 86400000);
+            const isNewAccount = accountAgeDays < 30;
+
+            if (!isNewAccount) {
+              core.info(`${username} account age: ${accountAgeDays} days, OK`);
+              return;
+            }
+
+            // 检查 AI moderator 是否已打 spam 标签
+            const { data: labels } = await github.rest.issues.listLabelsOnIssue({
+              ...context.repo,
+              issue_number: issue.number
+            });
+            const hasSpamLabel = labels.some(l => l.name === 'spam');
+
+            // 两个条件都满足:新账号 + AI 判定为垃圾 → 关闭 + 锁定
+            if (isNewAccount && hasSpamLabel) {
+              await github.rest.issues.createComment({
+                ...context.repo,
+                issue_number: issue.number,
+                body: [
+                  '👋 你好,感谢你对本项目的关注!',
+                  '',
+                  '为维护社区环境、防止垃圾信息和自动化 bot 的干扰,我们对 Issue 进行了自动审核。',
+                  '很遗憾,你的 Issue 未能通过审核(账号注册时间较短且内容触发了自动检测)。',
+                  '',
+                  '**如有误判,还请见谅!** 你可以在账号满 30 天后重新提交,或通过项目 README 中的联系方式反馈。',
+                  '',
+                  '感谢理解与支持 🙏',
+                ].join('\n')
+              });
+
+              await github.rest.issues.update({
+                ...context.repo,
+                issue_number: issue.number,
+                state: 'closed',
+                state_reason: 'not_planned'
+              });
+
+              await github.rest.issues.lock({
+                ...context.repo,
+                issue_number: issue.number,
+                lock_reason: 'spam'
+              });
+
+              core.info(`Issue #${issue.number} closed: new account (${accountAgeDays}d) + spam detected`);
+            }

+ 4 - 9
README-EN.md

@@ -11,7 +11,7 @@ Deploy in <strong>30 seconds</strong> — Say goodbye to endless scrolling, only
 [![GitHub Stars](https://img.shields.io/github/stars/sansan0/TrendRadar?style=flat-square&logo=github&color=yellow)](https://github.com/sansan0/TrendRadar/stargazers)
 [![GitHub Forks](https://img.shields.io/github/forks/sansan0/TrendRadar?style=flat-square&logo=github&color=blue)](https://github.com/sansan0/TrendRadar/network/members)
 [![License](https://img.shields.io/badge/license-GPL--3.0-blue.svg?style=flat-square)](LICENSE)
-[![Version](https://img.shields.io/badge/version-v6.6.0-blue.svg)](https://github.com/sansan0/TrendRadar)
+[![Version](https://img.shields.io/badge/version-v6.6.1-blue.svg)](https://github.com/sansan0/TrendRadar)
 [![MCP](https://img.shields.io/badge/MCP-v4.0.2-green.svg)](https://github.com/sansan0/TrendRadar)
 [![RSS](https://img.shields.io/badge/RSS-Feed_Support-orange.svg?style=flat-square&logo=rss&logoColor=white)](https://github.com/sansan0/TrendRadar)
 [![AI Translation](https://img.shields.io/badge/AI-Multi--Language-purple.svg?style=flat-square)](https://github.com/sansan0/TrendRadar)
@@ -2675,10 +2675,7 @@ current directory/
 
    | Environment Variable | Corresponding Config | Example Value | Description |
    |---------------------|---------------------|---------------|-------------|
-   | `ENABLE_WEBSERVER` | - | `true` / `false` | Auto-start web server |
    | `WEBSERVER_PORT` | - | `8080` | Web server port |
-   | `WEBSERVER_WATCHDOG` | - | `true` / `false` | Turn on "auto-recover web page service" (restarts it if it crashes) |
-   | `WEBSERVER_WATCHDOG_INTERVAL` | - | `60` | How often to check and auto-recover (seconds) |
    | `FEISHU_WEBHOOK_URL` | `notification.channels.feishu.webhook_url` | `https://...` | Feishu Webhook (multi-account use `;` separator) |
    | `AI_ANALYSIS_ENABLED` | `ai_analysis.enabled` | `true` / `false` | Enable AI analysis (v5.0.0 new) |
    | `AI_API_KEY` | `ai.api_key` | `sk-xxx...` | AI API Key (shared by ai_analysis and ai_translation) |
@@ -2839,13 +2836,11 @@ docker rm trendradar
 ```
 
 > 💡 **Web Server Notes**:
-> - After starting, access latest report at `http://localhost:8080`
+> - Auto-starts in cron mode, access latest report at `http://localhost:8080`
 > - Access historical reports via directory navigation (e.g., `http://localhost:8080/2025-xx-xx/`)
 > - Port can be configured in `.env` file with `WEBSERVER_PORT` parameter
-> - Auto-start: Set `ENABLE_WEBSERVER=true` in `.env`
-> - Auto-recover: `WEBSERVER_WATCHDOG=true` (default). It checks every `WEBSERVER_WATCHDOG_INTERVAL` seconds and restarts the web page service if needed
-> - `stop_webserver` means you manually turn off the web page service (command: `docker exec -it trendradar python manage.py stop_webserver`)
-> - "Auto restart" means the system turns that web page service back on automatically. If you stopped it manually and want it back, run `docker exec -it trendradar python manage.py start_webserver`
+> - Stop manually: `docker exec -it trendradar python manage.py stop_webserver`
+> - Start manually: `docker exec -it trendradar python manage.py start_webserver`
 > - Security: Static files only, limited to output directory, localhost binding only
 
 #### Data Persistence

+ 4 - 9
README.md

@@ -12,7 +12,7 @@
 [![GitHub Stars](https://img.shields.io/github/stars/sansan0/TrendRadar?style=flat-square&logo=github&color=yellow)](https://github.com/sansan0/TrendRadar/stargazers)
 [![GitHub Forks](https://img.shields.io/github/forks/sansan0/TrendRadar?style=flat-square&logo=github&color=blue)](https://github.com/sansan0/TrendRadar/network/members)
 [![License](https://img.shields.io/badge/license-GPL--3.0-blue.svg?style=flat-square)](LICENSE)
-[![Version](https://img.shields.io/badge/version-v6.6.0-blue.svg)](https://github.com/sansan0/TrendRadar)
+[![Version](https://img.shields.io/badge/version-v6.6.1-blue.svg)](https://github.com/sansan0/TrendRadar)
 [![MCP](https://img.shields.io/badge/MCP-v4.0.2-green.svg)](https://github.com/sansan0/TrendRadar)
 [![RSS](https://img.shields.io/badge/RSS-订阅源支持-orange.svg?style=flat-square&logo=rss&logoColor=white)](https://github.com/sansan0/TrendRadar)
 [![AI翻译](https://img.shields.io/badge/AI-多语言推送-purple.svg?style=flat-square)](https://github.com/sansan0/TrendRadar)
@@ -2726,10 +2726,7 @@ TrendRadar 提供两个独立的 Docker 镜像,可根据需求选择部署:
 
    | 环境变量 | 对应配置 | 示例值 | 说明 |
    |---------|---------|-------|------|
-   | `ENABLE_WEBSERVER` | - | `true` / `false` | 是否自动启动 Web 服务器 |
    | `WEBSERVER_PORT` | - | `8080` | Web 服务器端口 |
-   | `WEBSERVER_WATCHDOG` | - | `true` / `false` | 是否开启"网页服务自动恢复"(服务异常时自动重开) |
-   | `WEBSERVER_WATCHDOG_INTERVAL` | - | `60` | 自动恢复检查间隔(秒) |
    | `FEISHU_WEBHOOK_URL` | `notification.channels.feishu.webhook_url` | `https://...` | 飞书 Webhook(多账号用 `;` 分隔) |
    | `AI_ANALYSIS_ENABLED` | `ai_analysis.enabled` | `true` / `false` | 是否启用 AI 分析(v5.0.0 新增) |
    | `AI_API_KEY` | `ai.api_key` | `sk-xxx...` | AI API Key(ai_analysis 和 ai_translation 共享) |
@@ -2890,13 +2887,11 @@ docker rm trendradar
 ```
 
 > 💡 **Web 服务器说明**:
-> - 启动后可通过浏览器访问 `http://localhost:8080` 查看最新报告
+> - cron 模式下自动启动,通过浏览器访问 `http://localhost:8080` 查看最新报告
 > - 通过目录导航访问历史报告(如:`http://localhost:8080/2025-xx-xx/`)
 > - 端口可在 `.env` 文件中配置 `WEBSERVER_PORT` 参数
-> - 自动启动:在 `.env` 中设置 `ENABLE_WEBSERVER=true`
-> - 自动恢复:`WEBSERVER_WATCHDOG=true`(默认开启),每隔 `WEBSERVER_WATCHDOG_INTERVAL` 秒检查一次,异常会自动重开网页服务
-> - `stop_webserver` 的意思是"你主动手动关闭网页服务"(命令:`docker exec -it trendradar python manage.py stop_webserver`)
-> - "自动拉起"就是"系统自动把网页服务重新打开";若你手动关闭后想恢复,请执行 `docker exec -it trendradar python manage.py start_webserver`
+> - 手动停止:`docker exec -it trendradar python manage.py stop_webserver`
+> - 手动启动:`docker exec -it trendradar python manage.py start_webserver`
 > - 安全提示:仅提供静态文件访问,限制在 output 目录,只绑定本地访问
 
 #### 数据持久化

+ 10 - 14
docker/.env

@@ -2,23 +2,10 @@
 # Web 服务器配置
 # ============================================
 
-# 是否自动启动 Web 服务器托管 output 目录 (true/false)
-# 启用后可通过 http://localhost:{WEBSERVER_PORT} 访问生成的报告
-# 手动控制:docker exec -it trendradar python manage.py start_webserver
-ENABLE_WEBSERVER=false
-
 # Web 服务器端口(默认 8080,可自定义避免冲突)
-# 注意:修改后需要重启容器生效
+# cron 模式下自动启动,通过 http://localhost:{WEBSERVER_PORT} 访问报告
 WEBSERVER_PORT=8080
 
-# 是否开启“网页服务自动恢复”功能 (true/false)
-# true:网页服务挂了会自动重开(推荐)
-# false:不会自动重开,适合你想长期手动关闭网页服务的场景
-WEBSERVER_WATCHDOG=true
-
-# 自动恢复检查间隔(秒),默认每 60 秒检查一次
-WEBSERVER_WATCHDOG_INTERVAL=60
-
 # ============================================
 # 通知渠道配置(多账号用 ; 分隔)
 # ============================================
@@ -89,6 +76,15 @@ S3_ACCESS_KEY_ID=
 S3_SECRET_ACCESS_KEY=
 S3_REGION=
 
+# ============================================
+# MCP Server 配置
+# ============================================
+
+# MCP 监听地址(默认 127.0.0.1 仅本机访问,改 0.0.0.0 允许外部访问)
+# MCP_HOST=127.0.0.1
+# MCP 端口(默认 3333,如与其他服务冲突可修改)
+# MCP_PORT=3333
+
 # ============================================
 # 运行配置
 # ============================================

+ 3 - 5
docker/Dockerfile.mcp

@@ -25,11 +25,9 @@ ENV PYTHONUNBUFFERED=1 \
     CONFIG_PATH=/app/config/config.yaml \
     FREQUENCY_WORDS_PATH=/app/config/frequency_words.txt
 
-# MCP HTTP 服务端口
+# MCP HTTP 服务端口(默认 3333,可通过环境变量 MCP_PORT 覆盖)
+ENV MCP_PORT=3333
 EXPOSE 3333
 
-HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
-    CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:3333/mcp')" || exit 1
-
 # 启动 MCP 服务器(HTTP 模式)
-CMD ["python", "-m", "mcp_server.server", "--transport", "http", "--host", "0.0.0.0", "--port", "3333"]
+CMD sh -c "python -m mcp_server.server --transport http --host 0.0.0.0 --port ${MCP_PORT}"

+ 2 - 4
docker/docker-compose-build.yml

@@ -16,10 +16,7 @@ services:
     environment:
       - TZ=Asia/Shanghai
       # Web 服务器
-      - ENABLE_WEBSERVER=${ENABLE_WEBSERVER:-false}
       - WEBSERVER_PORT=${WEBSERVER_PORT:-8080}
-      - WEBSERVER_WATCHDOG=${WEBSERVER_WATCHDOG:-true}
-      - WEBSERVER_WATCHDOG_INTERVAL=${WEBSERVER_WATCHDOG_INTERVAL:-60}
       # 通知渠道
       - FEISHU_WEBHOOK_URL=${FEISHU_WEBHOOK_URL:-}
       - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
@@ -68,7 +65,7 @@ services:
     restart: unless-stopped
 
     ports:
-      - "127.0.0.1:3333:3333"
+      - "${MCP_HOST:-127.0.0.1}:${MCP_PORT:-3333}:3333"
 
     volumes:
       - ../config:/app/config:ro
@@ -76,3 +73,4 @@ services:
 
     environment:
       - TZ=Asia/Shanghai
+      - MCP_PORT=${MCP_PORT:-3333}

+ 2 - 4
docker/docker-compose.yml

@@ -14,10 +14,7 @@ services:
     environment:
       - TZ=Asia/Shanghai
       # Web 服务器
-      - ENABLE_WEBSERVER=${ENABLE_WEBSERVER:-false}
       - WEBSERVER_PORT=${WEBSERVER_PORT:-8080}
-      - WEBSERVER_WATCHDOG=${WEBSERVER_WATCHDOG:-true}
-      - WEBSERVER_WATCHDOG_INTERVAL=${WEBSERVER_WATCHDOG_INTERVAL:-60}
       # 通知渠道
       - FEISHU_WEBHOOK_URL=${FEISHU_WEBHOOK_URL:-}
       - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
@@ -64,7 +61,7 @@ services:
     restart: unless-stopped
 
     ports:
-      - "127.0.0.1:3333:3333"
+      - "${MCP_HOST:-127.0.0.1}:${MCP_PORT:-3333}:3333"
 
     volumes:
       - ../config:/app/config:ro
@@ -72,3 +69,4 @@ services:
 
     environment:
       - TZ=Asia/Shanghai
+      - MCP_PORT=${MCP_PORT:-3333}

+ 3 - 22
docker/entrypoint.sh

@@ -37,28 +37,9 @@ case "${RUN_MODE:-cron}" in
         python -m trendradar
     fi
 
-    # 启动 Web 服务器(如果配置了)
-    if [ "${ENABLE_WEBSERVER:-false}" = "true" ]; then
-        echo "🌐 启动 Web 服务器..."
-        python manage.py start_webserver
-
-        WEBSERVER_WATCHDOG_ENABLED=$(echo "${WEBSERVER_WATCHDOG:-true}" | tr '[:upper:]' '[:lower:]')
-        WEBSERVER_WATCHDOG_INTERVAL=${WEBSERVER_WATCHDOG_INTERVAL:-60}
-        if [ "$WEBSERVER_WATCHDOG_ENABLED" = "true" ] || [ "$WEBSERVER_WATCHDOG_ENABLED" = "1" ] || [ "$WEBSERVER_WATCHDOG_ENABLED" = "yes" ] || [ "$WEBSERVER_WATCHDOG_ENABLED" = "on" ]; then
-            # 启动后台 watchdog 定期检查 Web 服务器健康状态
-            echo "🔄 启动 Web 服务器 watchdog (间隔: ${WEBSERVER_WATCHDOG_INTERVAL}s)..."
-            (
-                while true; do
-                    sleep "$WEBSERVER_WATCHDOG_INTERVAL"
-                    python manage.py webserver_autofix
-                done
-            ) &
-            WEBSERVER_WATCHDOG_PID=$!
-            echo "  ✅ watchdog 已启动 (PID: $WEBSERVER_WATCHDOG_PID)"
-        else
-            echo "⏸️ Web 服务器 watchdog 已禁用"
-        fi
-    fi
+    # 启动 Web 服务器
+    echo "🌐 启动 Web 服务器..."
+    python manage.py start_webserver
 
     echo "⏰ 启动supercronic: $CRON_EXPR"
     echo "🎯 supercronic 将作为 PID 1 运行"

+ 3 - 91
docker/manage.py

@@ -16,20 +16,6 @@ from datetime import datetime
 WEBSERVER_PORT = int(os.environ.get("WEBSERVER_PORT", "8080"))
 WEBSERVER_DIR = "/app/output"
 WEBSERVER_PID_FILE = "/tmp/webserver.pid"
-WEBSERVER_MANUAL_STOP_FILE = "/tmp/webserver.manual_stop"
-
-
-def _env_bool(name: str, default: bool) -> bool:
-    """读取布尔环境变量,兼容 true/1/yes/on。"""
-    value = os.environ.get(name)
-    if value is None:
-        return default
-    return value.strip().lower() in {"1", "true", "yes", "on"}
-
-
-WEBSERVER_AUTOFIX_LOG_HEALTHY = _env_bool("WEBSERVER_AUTOFIX_LOG_HEALTHY", False)
-
-
 def get_timestamp():
     """获取当前时间戳字符串"""
     return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@@ -485,29 +471,6 @@ def _is_expected_webserver_process(pid: int) -> bool:
     return "http.server" in cmdline and str(WEBSERVER_PORT) in cmdline
 
 
-def _is_manual_stop_requested() -> bool:
-    """是否处于手动停服状态。"""
-    return Path(WEBSERVER_MANUAL_STOP_FILE).exists()
-
-
-def _set_manual_stop_marker():
-    """写入手动停服标记,防止 watchdog 自动拉起。"""
-    try:
-        with open(WEBSERVER_MANUAL_STOP_FILE, "w", encoding="utf-8") as f:
-            f.write(get_timestamp())
-    except Exception:
-        pass
-
-
-def _clear_manual_stop_marker():
-    """清理手动停服标记。"""
-    try:
-        if Path(WEBSERVER_MANUAL_STOP_FILE).exists():
-            os.remove(WEBSERVER_MANUAL_STOP_FILE)
-    except Exception:
-        pass
-
-
 def _terminate_webserver_process(pid: int, require_expected: bool = True) -> bool:
     """尝试终止 Web 服务器进程。
 
@@ -577,17 +540,11 @@ def _cleanup_stale_pid():
         return False
 
 
-def start_webserver(force: bool = False):
+def start_webserver():
     """启动 Web 服务器托管 output 目录"""
     print(f"🌐 启动 Web 服务器 (端口: {WEBSERVER_PORT})...")
     print(f"  🔒 安全提示:仅提供静态文件访问,限制在 {WEBSERVER_DIR} 目录")
 
-    if force:
-        _clear_manual_stop_marker()
-    elif _is_manual_stop_requested():
-        print("  ℹ️ 检测到手动停服标记,跳过自动启动")
-        return
-
     # 检查是否已经运行
     if Path(WEBSERVER_PID_FILE).exists():
         try:
@@ -635,8 +592,6 @@ def start_webserver(force: bool = False):
             # 保存 PID
             with open(WEBSERVER_PID_FILE, 'w') as f:
                 f.write(str(process.pid))
-            _clear_manual_stop_marker()
-
             print(f"  ✅ Web 服务器已启动 (PID: {process.pid})")
             print(f"  📁 服务目录: {WEBSERVER_DIR} (只读,仅静态文件)")
             print(f"  🌐 访问地址: http://localhost:{WEBSERVER_PORT}")
@@ -651,11 +606,9 @@ def start_webserver(force: bool = False):
 def stop_webserver():
     """停止 Web 服务器"""
     print("🛑 停止 Web 服务器...")
-    _set_manual_stop_marker()
 
     if not Path(WEBSERVER_PID_FILE).exists():
         print("  ℹ️ Web 服务器未运行")
-        print("  ℹ️ 已写入手动停服标记,watchdog 不会自动拉起")
         return
 
     try:
@@ -664,7 +617,6 @@ def stop_webserver():
         _terminate_webserver_process(pid, require_expected=True)
         if Path(WEBSERVER_PID_FILE).exists():
             os.remove(WEBSERVER_PID_FILE)
-        print("  ℹ️ 已写入手动停服标记,watchdog 不会自动拉起")
     except Exception as e:
         print(f"  ❌ 停止失败: {e}")
         # 尝试清理 PID 文件
@@ -680,8 +632,6 @@ def webserver_status():
 
     if not Path(WEBSERVER_PID_FILE).exists():
         print("  ⭕ 未运行")
-        if _is_manual_stop_requested():
-            print("  ℹ️ 当前为手动停服状态,watchdog 不会自动拉起")
         print(f"  💡 启动服务: python manage.py start_webserver")
         return
 
@@ -704,43 +654,6 @@ def webserver_status():
         print(f"  ❌ 状态检查失败: {e}")
 
 
-def webserver_autofix():
-    """Web 服务器健康检查和自动修复
-
-    供 watchdog/定时任务调用,检查服务状态并在需要时自动重启。
-    输出日志格式便于外部监控系统解析。
-    """
-    if _is_manual_stop_requested():
-        if WEBSERVER_AUTOFIX_LOG_HEALTHY:
-            print(f"[{get_timestamp()}] ℹ️ 手动停服状态,跳过自动修复")
-        return
-
-    if not Path(WEBSERVER_PID_FILE).exists():
-        print(f"[{get_timestamp()}] ℹ️ Web 服务器未运行,启动中...")
-        start_webserver(force=False)
-        return
-
-    try:
-        with open(WEBSERVER_PID_FILE, 'r') as f:
-            pid = int(f.read().strip())
-
-        # 使用增强检查
-        if not _is_webserver_running(pid):
-            print(f"[{get_timestamp()}] ⚠️ Web 服务器不可用 (PID: {pid}),尝试重启...")
-            _terminate_webserver_process(pid, require_expected=True)
-            _cleanup_stale_pid()
-            start_webserver(force=False)
-            return
-
-        if WEBSERVER_AUTOFIX_LOG_HEALTHY:
-            print(f"[{get_timestamp()}] ✅ Web 服务器健康 (PID: {pid})")
-
-    except Exception as e:
-        print(f"[{get_timestamp()}] ❌ 健康检查异常: {e}")
-        _cleanup_stale_pid()
-        start_webserver(force=False)
-
-
 def show_help():
     """显示帮助信息"""
     help_text = """
@@ -791,7 +704,7 @@ def show_help():
 
   5. Web 服务器管理:
      - 启动: start_webserver
-     - 停止: stop_webserver(写入手动停服标记,watchdog 不自动拉起)
+     - 停止: stop_webserver
      - 状态: webserver_status
      - 访问: http://localhost:8080
 """
@@ -811,10 +724,9 @@ def main():
         "files": show_files,
         "logs": show_logs,
         "restart": restart_supercronic,
-        "start_webserver": lambda: start_webserver(force=True),
+        "start_webserver": start_webserver,
         "stop_webserver": stop_webserver,
         "webserver_status": webserver_status,
-        "webserver_autofix": webserver_autofix,
         "help": show_help,
     }
 

+ 1 - 1
mcp_server/__init__.py

@@ -5,4 +5,4 @@ TrendRadar MCP Server
 
 """
 
-__version__ = "4.0.2"
+__version__ = "4.0.3"

+ 1 - 1
pyproject.toml

@@ -1,6 +1,6 @@
 [project]
 name = "trendradar"
-version = "6.6.0"
+version = "6.6.1"
 description = "TrendRadar - 热点新闻聚合与分析工具"
 requires-python = ">=3.12"
 dependencies = [

+ 1 - 1
trendradar/__init__.py

@@ -9,5 +9,5 @@ TrendRadar - 热点新闻聚合与分析工具
 
 from trendradar.context import AppContext
 
-__version__ = "6.6.0"
+__version__ = "6.6.1"
 __all__ = ["AppContext", "__version__"]

+ 1 - 1
uv.lock

@@ -1996,7 +1996,7 @@ wheels = [
 
 [[package]]
 name = "trendradar"
-version = "6.6.0"
+version = "6.6.1"
 source = { editable = "." }
 dependencies = [
     { name = "boto3" },

+ 1 - 1
version

@@ -1 +1 @@
-6.6.0
+6.6.1

+ 1 - 1
version_mcp

@@ -1 +1 @@
-4.0.2
+4.0.3