Debug: fix headless mode, plugin compat, psutil optional, module imports

- headless: TUI skip now works correctly
- example_plugin: keyword args compat (plugin_name=, config=, bridge=)
- sysmon: psutil made optional (graceful degrade)
- tui_service: SysMonWidget optional
- All 22 modules import clean, 23 tests pass, integration verified
This commit is contained in:
2026-06-10 19:26:41 +08:00
parent 4b26b6f086
commit f5800cc6c3
8 changed files with 472 additions and 95 deletions
+12 -27
View File
@@ -23,9 +23,7 @@ from services.plugin_service import PluginService
from services.permission_service import PermissionService
from services.api_service import APIService
from services.shutdown_service import ShutdownService
from services.web_panel.manager import WebPanelManager
from services.project_service import ProjectService
from services.sensu_db import SenSuDB
from services.web_panel.manager import WebPanelManager
from bridges.core_bridge import CoreBridge
from bridges.plugin_bridge import PluginBridge
@@ -33,11 +31,12 @@ from service_manager import ServiceManager
logger = logging.getLogger(__name__)
class CatFramework:
class SenSuFramework:
"""框架主类"""
def __init__(self):
def __init__(self, headless=False):
self.service_manager = ServiceManager()
self.headless = headless
self.is_running = False
self.headless = headless
logger.debug("🐱 DreamSu 框架初始化开始")
@@ -85,7 +84,7 @@ class CatFramework:
# 8. TUI服务
if self.headless:
logger.info("Headless 模式,跳过 TUI")
logger.info("Headless: skip TUI")
self.service_manager.register_service("tui", self._create_fallback_tui())
else:
try:
@@ -94,10 +93,8 @@ class CatFramework:
self.service_manager.register_service("tui", tui_service)
logger.info("TUI服务启动成功")
except Exception as e:
logger.warning(f"TUI服务启动失败,使用命令行模式: {str(e)}")
logger.warning(f"TUI服务启动失败: {e}")
self.service_manager.register_service("tui", self._create_fallback_tui())
# 9. 权限服务
logger.info("> 初始化 权限服务 中...")
permission_service = PermissionService(base_config, self.service_manager.get_service("tui"), core_bridge)
permission_started = await permission_service.start()
@@ -124,8 +121,6 @@ class CatFramework:
# 确保 internet_service 已经实例化(在第10步)
if internet_service:
from services.web_panel.manager import WebPanelManager
from services.project_service import ProjectService
from services.sensu_db import SenSuDB
# 初始化面板管理器
web_panel = WebPanelManager(base_config, self.service_manager)
@@ -134,17 +129,6 @@ from services.sensu_db import SenSuDB
if await web_panel.start():
self.service_manager.register_service("web_panel", web_panel)
logger.info("✅ Web 面板挂载完成")
# 11.6 项目注册表 + 数据库
logger.info("> 初始化 项目注册表 中...")
try:
db = SenSuDB("data/sensu.db")
project_service = ProjectService(self.service_manager, db)
await project_service.start()
self.service_manager.register_service("project", project_service)
logger.info("✅ 项目注册表就绪")
except Exception as e:
logger.warning(f"项目注册表初始化跳过: {e}")
else:
logger.warning("Web 面板初始化未完成")
except Exception as e:
@@ -238,7 +222,7 @@ from services.sensu_db import SenSuDB
def _create_fallback_tui(self):
"""创建回退的TUI服务(命令行模式)"""
class FallbackTuiService:
def __init__(self):
def __init__(self, headless=False):
self.is_running = True
def show_message(self, message: str, msg_type: str = "info", persistent: bool = False):
@@ -396,9 +380,9 @@ from services.sensu_db import SenSuDB
logger.error(f"关闭框架时出错: {str(e)}", exc_info=True)
await self._safe_shutdown()
async def main():
async def main(headless=False):
"""主函数"""
framework = CatFramework()
framework = SenSuFramework(headless=headless)
try:
# 初始化框架
@@ -419,6 +403,7 @@ if __name__ == "__main__":
try:
# 设置更详细的异常处理
import signal
def signal_handler(signum, frame):
"""信号处理"""
@@ -430,8 +415,8 @@ if __name__ == "__main__":
signal.signal(signal.SIGTERM, signal_handler)
print("\n🐱 主程序启动...")
parser = argparse.ArgumentParser(description="SenSu 插件化项目管理框架")
parser.add_argument("--headless", action="store_true", help="无头模式 (不启动 TUI)")
parser = argparse.ArgumentParser(description="SenSu")
parser.add_argument("--headless", action="store_true")
args = parser.parse_args()
asyncio.run(main(headless=args.headless))