mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 10:42:25 +08:00
✨ 新增 WSL 環境檢測功能,並在相關函數中整合 WSL 支援,提升跨平台使用體驗。更新測試用例以涵蓋新功能。
This commit is contained in:
parent
eb77bf918b
commit
013aadf210
@ -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:
|
def is_remote_environment() -> bool:
|
||||||
"""
|
"""
|
||||||
檢測是否在遠端環境中運行
|
檢測是否在遠端環境中運行
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True 表示遠端環境,False 表示本地環境
|
bool: True 表示遠端環境,False 表示本地環境
|
||||||
"""
|
"""
|
||||||
|
# WSL 不應被視為遠端環境,因為它可以訪問 Windows 瀏覽器
|
||||||
|
if is_wsl_environment():
|
||||||
|
debug_log("WSL 環境不被視為遠端環境")
|
||||||
|
return False
|
||||||
|
|
||||||
# 檢查 SSH 連線指標
|
# 檢查 SSH 連線指標
|
||||||
for env_var in SSH_ENV_VARS:
|
for env_var in SSH_ENV_VARS:
|
||||||
if os.getenv(env_var):
|
if os.getenv(env_var):
|
||||||
debug_log(f"偵測到 SSH 環境變數: {env_var}")
|
debug_log(f"偵測到 SSH 環境變數: {env_var}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 檢查遠端開發環境
|
# 檢查遠端開發環境
|
||||||
for env_var in REMOTE_ENV_VARS:
|
for env_var in REMOTE_ENV_VARS:
|
||||||
if os.getenv(env_var):
|
if os.getenv(env_var):
|
||||||
debug_log(f"偵測到遠端開發環境: {env_var}")
|
debug_log(f"偵測到遠端開發環境: {env_var}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 檢查 Docker 容器
|
# 檢查 Docker 容器
|
||||||
if os.path.exists('/.dockerenv'):
|
if os.path.exists('/.dockerenv'):
|
||||||
debug_log("偵測到 Docker 容器環境")
|
debug_log("偵測到 Docker 容器環境")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Windows 遠端桌面檢查
|
# Windows 遠端桌面檢查
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
session_name = os.getenv('SESSIONNAME', '')
|
session_name = os.getenv('SESSIONNAME', '')
|
||||||
if session_name and 'RDP' in session_name:
|
if session_name and 'RDP' in session_name:
|
||||||
debug_log(f"偵測到 Windows 遠端桌面: {session_name}")
|
debug_log(f"偵測到 Windows 遠端桌面: {session_name}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Linux 無顯示環境檢查
|
# Linux 無顯示環境檢查(但排除 WSL)
|
||||||
if sys.platform.startswith('linux') and not os.getenv('DISPLAY'):
|
if sys.platform.startswith('linux') and not os.getenv('DISPLAY') and not is_wsl_environment():
|
||||||
debug_log("偵測到 Linux 無顯示環境")
|
debug_log("偵測到 Linux 無顯示環境")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
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:
|
def get_system_info() -> str:
|
||||||
"""
|
"""
|
||||||
獲取系統環境資訊
|
獲取系統環境資訊
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: JSON 格式的系統資訊
|
str: JSON 格式的系統資訊
|
||||||
"""
|
"""
|
||||||
is_remote = is_remote_environment()
|
is_remote = is_remote_environment()
|
||||||
|
is_wsl = is_wsl_environment()
|
||||||
can_gui = can_use_gui()
|
can_gui = can_use_gui()
|
||||||
|
|
||||||
system_info = {
|
system_info = {
|
||||||
"平台": sys.platform,
|
"平台": sys.platform,
|
||||||
"Python 版本": sys.version.split()[0],
|
"Python 版本": sys.version.split()[0],
|
||||||
|
"WSL 環境": is_wsl,
|
||||||
"遠端環境": is_remote,
|
"遠端環境": is_remote,
|
||||||
"GUI 可用": can_gui,
|
"GUI 可用": can_gui,
|
||||||
"建議介面": "Web UI" if is_remote or not can_gui else "Qt 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"),
|
"DISPLAY": os.getenv("DISPLAY"),
|
||||||
"VSCODE_INJECTION": os.getenv("VSCODE_INJECTION"),
|
"VSCODE_INJECTION": os.getenv("VSCODE_INJECTION"),
|
||||||
"SESSIONNAME": os.getenv("SESSIONNAME"),
|
"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)
|
return json.dumps(system_info, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,23 +162,27 @@ def test_environment_detection():
|
|||||||
"""Test environment detection logic"""
|
"""Test environment detection logic"""
|
||||||
debug_log("🔍 測試環境檢測功能")
|
debug_log("🔍 測試環境檢測功能")
|
||||||
debug_log("-" * 30)
|
debug_log("-" * 30)
|
||||||
|
|
||||||
try:
|
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()
|
remote_detected = is_remote_environment()
|
||||||
gui_available = can_use_gui()
|
gui_available = can_use_gui()
|
||||||
|
|
||||||
|
debug_log(f"WSL 環境檢測: {'是' if wsl_detected else '否'}")
|
||||||
debug_log(f"遠端環境檢測: {'是' if remote_detected else '否'}")
|
debug_log(f"遠端環境檢測: {'是' if remote_detected else '否'}")
|
||||||
debug_log(f"GUI 可用性: {'是' if gui_available 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 (適合遠端開發環境)")
|
debug_log("✅ 將使用 Web UI (適合遠端開發環境)")
|
||||||
else:
|
else:
|
||||||
debug_log("✅ 將使用 Qt GUI (本地環境)")
|
debug_log("✅ 將使用 Qt GUI (本地環境)")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug_log(f"❌ 環境檢測失敗: {e}")
|
debug_log(f"❌ 環境檢測失敗: {e}")
|
||||||
return False
|
return False
|
||||||
@ -245,27 +249,30 @@ def test_environment_web_ui_mode():
|
|||||||
"""Test environment-based Web UI mode"""
|
"""Test environment-based Web UI mode"""
|
||||||
debug_log("\n🌐 測試環境變數控制 Web UI 模式")
|
debug_log("\n🌐 測試環境變數控制 Web UI 模式")
|
||||||
debug_log("-" * 30)
|
debug_log("-" * 30)
|
||||||
|
|
||||||
try:
|
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
|
import os
|
||||||
|
|
||||||
# 顯示當前環境狀態
|
# 顯示當前環境狀態
|
||||||
|
is_wsl = is_wsl_environment()
|
||||||
is_remote = is_remote_environment()
|
is_remote = is_remote_environment()
|
||||||
gui_available = can_use_gui()
|
gui_available = can_use_gui()
|
||||||
force_web_env = os.getenv("FORCE_WEB", "").lower()
|
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 '未設定'}")
|
debug_log(f"FORCE_WEB 環境變數: {force_web_env or '未設定'}")
|
||||||
|
|
||||||
if force_web_env in ("true", "1", "yes", "on"):
|
if force_web_env in ("true", "1", "yes", "on"):
|
||||||
debug_log("✅ FORCE_WEB 已啟用,將強制使用 Web UI")
|
debug_log("✅ FORCE_WEB 已啟用,將強制使用 Web UI")
|
||||||
|
elif is_wsl:
|
||||||
|
debug_log("✅ WSL 環境,將使用 Web UI 並支援 Windows 瀏覽器啟動")
|
||||||
elif not is_remote and gui_available:
|
elif not is_remote and gui_available:
|
||||||
debug_log("ℹ️ 本地 GUI 環境,將使用 Qt GUI")
|
debug_log("ℹ️ 本地 GUI 環境,將使用 Qt GUI")
|
||||||
debug_log("💡 可設定 FORCE_WEB=true 強制使用 Web UI 進行測試")
|
debug_log("💡 可設定 FORCE_WEB=true 強制使用 Web UI 進行測試")
|
||||||
else:
|
else:
|
||||||
debug_log("ℹ️ 將自動使用 Web UI(遠端環境或 GUI 不可用)")
|
debug_log("ℹ️ 將自動使用 Web UI(遠端環境或 GUI 不可用)")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -4,18 +4,125 @@
|
|||||||
瀏覽器工具函數
|
瀏覽器工具函數
|
||||||
==============
|
==============
|
||||||
|
|
||||||
提供瀏覽器相關的工具函數。
|
提供瀏覽器相關的工具函數,包含 WSL 環境的特殊處理。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
import webbrowser
|
import webbrowser
|
||||||
from typing import Callable
|
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]:
|
def get_browser_opener() -> Callable[[str], None]:
|
||||||
"""
|
"""
|
||||||
獲取瀏覽器開啟函數
|
獲取瀏覽器開啟函數
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Callable: 瀏覽器開啟函數
|
Callable: 瀏覽器開啟函數
|
||||||
"""
|
"""
|
||||||
return webbrowser.open
|
return smart_browser_open
|
Loading…
x
Reference in New Issue
Block a user