新增 WSL 環境檢測功能,並在相關函數中整合 WSL 支援,提升跨平台使用體驗。更新測試用例以涵蓋新功能。

This commit is contained in:
Minidoracat 2025-06-05 08:48:34 +08:00
parent eb77bf918b
commit 013aadf210
3 changed files with 189 additions and 29 deletions

View File

@ -114,42 +114,83 @@ mcp = FastMCP(SERVER_NAME, version=__version__, **fastmcp_settings)
# ===== 工具函數 =====
def is_wsl_environment() -> bool:
"""
檢測是否在 WSL (Windows Subsystem for Linux) 環境中運行
Returns:
bool: True 表示 WSL 環境False 表示其他環境
"""
try:
# 檢查 /proc/version 文件是否包含 WSL 標識
if os.path.exists('/proc/version'):
with open('/proc/version', 'r') as f:
version_info = f.read().lower()
if 'microsoft' in version_info or 'wsl' in version_info:
debug_log("偵測到 WSL 環境(通過 /proc/version")
return True
# 檢查 WSL 相關環境變數
wsl_env_vars = ['WSL_DISTRO_NAME', 'WSL_INTEROP', 'WSLENV']
for env_var in wsl_env_vars:
if os.getenv(env_var):
debug_log(f"偵測到 WSL 環境變數: {env_var}")
return True
# 檢查是否存在 WSL 特有的路徑
wsl_paths = ['/mnt/c', '/mnt/d', '/proc/sys/fs/binfmt_misc/WSLInterop']
for path in wsl_paths:
if os.path.exists(path):
debug_log(f"偵測到 WSL 特有路徑: {path}")
return True
except Exception as e:
debug_log(f"WSL 檢測過程中發生錯誤: {e}")
return False
def is_remote_environment() -> bool:
"""
檢測是否在遠端環境中運行
Returns:
bool: True 表示遠端環境False 表示本地環境
"""
# WSL 不應被視為遠端環境,因為它可以訪問 Windows 瀏覽器
if is_wsl_environment():
debug_log("WSL 環境不被視為遠端環境")
return False
# 檢查 SSH 連線指標
for env_var in SSH_ENV_VARS:
if os.getenv(env_var):
debug_log(f"偵測到 SSH 環境變數: {env_var}")
return True
# 檢查遠端開發環境
for env_var in REMOTE_ENV_VARS:
if os.getenv(env_var):
debug_log(f"偵測到遠端開發環境: {env_var}")
return True
# 檢查 Docker 容器
if os.path.exists('/.dockerenv'):
debug_log("偵測到 Docker 容器環境")
return True
# Windows 遠端桌面檢查
if sys.platform == 'win32':
session_name = os.getenv('SESSIONNAME', '')
if session_name and 'RDP' in session_name:
debug_log(f"偵測到 Windows 遠端桌面: {session_name}")
return True
# Linux 無顯示環境檢查
if sys.platform.startswith('linux') and not os.getenv('DISPLAY'):
# Linux 無顯示環境檢查(但排除 WSL
if sys.platform.startswith('linux') and not os.getenv('DISPLAY') and not is_wsl_environment():
debug_log("偵測到 Linux 無顯示環境")
return True
return False
@ -567,16 +608,18 @@ async def launch_web_ui_with_timeout(project_dir: str, summary: str, timeout: in
def get_system_info() -> str:
"""
獲取系統環境資訊
Returns:
str: JSON 格式的系統資訊
"""
is_remote = is_remote_environment()
is_wsl = is_wsl_environment()
can_gui = can_use_gui()
system_info = {
"平台": sys.platform,
"Python 版本": sys.version.split()[0],
"WSL 環境": is_wsl,
"遠端環境": is_remote,
"GUI 可用": can_gui,
"建議介面": "Web UI" if is_remote or not can_gui else "Qt GUI",
@ -586,9 +629,12 @@ def get_system_info() -> str:
"DISPLAY": os.getenv("DISPLAY"),
"VSCODE_INJECTION": os.getenv("VSCODE_INJECTION"),
"SESSIONNAME": os.getenv("SESSIONNAME"),
"WSL_DISTRO_NAME": os.getenv("WSL_DISTRO_NAME"),
"WSL_INTEROP": os.getenv("WSL_INTEROP"),
"WSLENV": os.getenv("WSLENV"),
}
}
return json.dumps(system_info, ensure_ascii=False, indent=2)

View File

@ -162,23 +162,27 @@ def test_environment_detection():
"""Test environment detection logic"""
debug_log("🔍 測試環境檢測功能")
debug_log("-" * 30)
try:
from .server import is_remote_environment, can_use_gui
from .server import is_remote_environment, is_wsl_environment, can_use_gui
wsl_detected = is_wsl_environment()
remote_detected = is_remote_environment()
gui_available = can_use_gui()
debug_log(f"WSL 環境檢測: {'' if wsl_detected else ''}")
debug_log(f"遠端環境檢測: {'' if remote_detected else ''}")
debug_log(f"GUI 可用性: {'' if gui_available else ''}")
if remote_detected:
if wsl_detected:
debug_log("✅ 檢測到 WSL 環境,將使用 Web UI 並支援 Windows 瀏覽器啟動")
elif remote_detected:
debug_log("✅ 將使用 Web UI (適合遠端開發環境)")
else:
debug_log("✅ 將使用 Qt GUI (本地環境)")
return True
except Exception as e:
debug_log(f"❌ 環境檢測失敗: {e}")
return False
@ -245,27 +249,30 @@ def test_environment_web_ui_mode():
"""Test environment-based Web UI mode"""
debug_log("\n🌐 測試環境變數控制 Web UI 模式")
debug_log("-" * 30)
try:
from .server import interactive_feedback, is_remote_environment, can_use_gui
from .server import interactive_feedback, is_remote_environment, is_wsl_environment, can_use_gui
import os
# 顯示當前環境狀態
is_wsl = is_wsl_environment()
is_remote = is_remote_environment()
gui_available = can_use_gui()
force_web_env = os.getenv("FORCE_WEB", "").lower()
debug_log(f"當前環境 - 遠端: {is_remote}, GUI 可用: {gui_available}")
debug_log(f"當前環境 - WSL: {is_wsl}, 遠端: {is_remote}, GUI 可用: {gui_available}")
debug_log(f"FORCE_WEB 環境變數: {force_web_env or '未設定'}")
if force_web_env in ("true", "1", "yes", "on"):
debug_log("✅ FORCE_WEB 已啟用,將強制使用 Web UI")
elif is_wsl:
debug_log("✅ WSL 環境,將使用 Web UI 並支援 Windows 瀏覽器啟動")
elif not is_remote and gui_available:
debug_log(" 本地 GUI 環境,將使用 Qt GUI")
debug_log("💡 可設定 FORCE_WEB=true 強制使用 Web UI 進行測試")
else:
debug_log(" 將自動使用 Web UI遠端環境或 GUI 不可用)")
return True
except Exception as e:

View File

@ -4,18 +4,125 @@
瀏覽器工具函數
==============
提供瀏覽器相關的工具函數
提供瀏覽器相關的工具函數包含 WSL 環境的特殊處理
"""
import os
import sys
import subprocess
import webbrowser
from typing import Callable
# 導入調試功能
from ...debug import server_debug_log as debug_log
def is_wsl_environment() -> bool:
"""
檢測是否在 WSL 環境中運行
Returns:
bool: True 表示 WSL 環境False 表示其他環境
"""
try:
# 檢查 /proc/version 文件是否包含 WSL 標識
if os.path.exists('/proc/version'):
with open('/proc/version', 'r') as f:
version_info = f.read().lower()
if 'microsoft' in version_info or 'wsl' in version_info:
return True
# 檢查 WSL 相關環境變數
wsl_env_vars = ['WSL_DISTRO_NAME', 'WSL_INTEROP', 'WSLENV']
for env_var in wsl_env_vars:
if os.getenv(env_var):
return True
# 檢查是否存在 WSL 特有的路徑
wsl_paths = ['/mnt/c', '/mnt/d', '/proc/sys/fs/binfmt_misc/WSLInterop']
for path in wsl_paths:
if os.path.exists(path):
return True
except Exception:
pass
return False
def open_browser_in_wsl(url: str) -> None:
"""
WSL 環境中開啟 Windows 瀏覽器
Args:
url: 要開啟的 URL
"""
try:
# 嘗試使用 cmd.exe 啟動瀏覽器
cmd = ['cmd.exe', '/c', 'start', url]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
debug_log(f"成功使用 cmd.exe 啟動瀏覽器: {url}")
return
else:
debug_log(f"cmd.exe 啟動失敗,返回碼: {result.returncode}, 錯誤: {result.stderr}")
except Exception as e:
debug_log(f"使用 cmd.exe 啟動瀏覽器失敗: {e}")
try:
# 嘗試使用 powershell.exe 啟動瀏覽器
cmd = ['powershell.exe', '-c', f'Start-Process "{url}"']
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
debug_log(f"成功使用 powershell.exe 啟動瀏覽器: {url}")
return
else:
debug_log(f"powershell.exe 啟動失敗,返回碼: {result.returncode}, 錯誤: {result.stderr}")
except Exception as e:
debug_log(f"使用 powershell.exe 啟動瀏覽器失敗: {e}")
try:
# 最後嘗試使用 wslview如果安裝了 wslu 套件)
cmd = ['wslview', url]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
debug_log(f"成功使用 wslview 啟動瀏覽器: {url}")
return
else:
debug_log(f"wslview 啟動失敗,返回碼: {result.returncode}, 錯誤: {result.stderr}")
except Exception as e:
debug_log(f"使用 wslview 啟動瀏覽器失敗: {e}")
# 如果所有方法都失敗,拋出異常
raise Exception("無法在 WSL 環境中啟動 Windows 瀏覽器")
def smart_browser_open(url: str) -> None:
"""
智能瀏覽器開啟函數根據環境選擇最佳方式
Args:
url: 要開啟的 URL
"""
if is_wsl_environment():
debug_log("檢測到 WSL 環境,使用 WSL 專用瀏覽器啟動方式")
open_browser_in_wsl(url)
else:
debug_log("使用標準瀏覽器啟動方式")
webbrowser.open(url)
def get_browser_opener() -> Callable[[str], None]:
"""
獲取瀏覽器開啟函數
Returns:
Callable: 瀏覽器開啟函數
"""
return webbrowser.open
return smart_browser_open