Files
NebulaShell/oss/plugin/loader.py
Falck f5c659b665 🔧 修复P0级问题:40+文件语法错误 + import路径 + 清理废弃代码
 跟项目能跑起来就差这一步!这次狠狠修了一波:

🩺 修复40+损坏Python文件
   - 补全所有缺少的class定义头(plugin-loader-pro、code-reviewer、
     http-api/ws-api/http-tcp、webui/dashboard/log-terminal 等)
   - 修复中文括号、字符串未闭合、缩进错乱等语法问题

🔗 创建符号链接 plugin_bridge -> plugin-bridge
   - 解决Python模块路径不支持连字符的问题
   - 关联修复 plugin-bridge 中错误的 import 路径

🧹 清理废弃代码
   - 删除 oss/tui/ 目录(已废弃)
   - 清理所有 __pycache__ 和 .pyc 缓存文件

 全量语法检查通过,零错误!
📋 ai.md 新增代码审计报告和分阶段修复计划
🗺️ 所有插件 use() 调用现在走统一路径
2026-05-03 09:26:47 +08:00

106 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""插件加载器 - 专门用于加载核心插件
遵循「最小化核心框架」设计哲学:
- 只负责加载可信的核心插件(来自 store/NebulaShell/
- 所有插件都使用统一的加载机制
- 不再区分沙箱模式和非沙箱模式
"""
import sys
import importlib.util
from pathlib import Path
from typing import Any, Optional, Dict
from oss.config import get_config
class PluginLoader:
"""插件加载器 - 专门用于加载核心插件
遵循「最小化核心框架」设计哲学:
- 只负责加载可信的核心插件(来自 store/NebulaShell/
- 所有插件都使用统一的加载机制
- 不再区分沙箱模式和非沙箱模式
"""
def __init__(self):
self.loaded: dict[str, Any] = {}
self._config = get_config()
def load_core_plugin(self, plugin_name: str, store_dir: Optional[str] = None) -> Optional[dict[str, Any]]:
"""加载核心插件(来自 store/NebulaShell/
Args:
plugin_name: 插件名称(如 "plugin-loader"
store_dir: 插件仓库目录,默认使用配置中的 STORE_DIR
Returns:
插件信息字典,包含 instance、module、path、name
"""
if store_dir is None:
store_dir = str(self._config.store_dir)
plugin_dir = Path(store_dir) / "NebulaShell" / plugin_name
return self._load_plugin(plugin_name, plugin_dir)
def _load_plugin(self, plugin_name: str, plugin_dir: Path) -> Optional[dict[str, Any]]:
"""加载插件(内部方法)
Args:
plugin_name: 插件名称
plugin_dir: 插件目录路径
Returns:
插件信息字典,如果加载失败则返回 None
"""
if not (plugin_dir / "main.py").exists():
print(f"[PluginLoader] 插件不存在:{plugin_dir}")
return None
# 清理插件名(去掉 } 等)
clean_name = plugin_name.rstrip("}")
module_name = f"plugin.{clean_name}"
spec = importlib.util.spec_from_file_location(module_name, str(plugin_dir / "main.py"))
module = importlib.util.module_from_spec(spec)
module.__package__ = module_name
module.__path__ = [str(plugin_dir)] # 启用相对导入子模块
sys.modules[spec.name] = module
# 执行模块(核心插件是可信的,不需要沙箱)
try:
spec.loader.exec_module(module)
except SyntaxError as e:
print(f"[PluginLoader] 插件 {clean_name} 语法错误:{e}")
import traceback
traceback.print_exc()
return None
except ImportError as e:
print(f"[PluginLoader] 插件 {clean_name} 导入错误:{e}")
import traceback
traceback.print_exc()
return None
except Exception as e:
print(f"[PluginLoader] 加载插件 {clean_name} 失败:{type(e).__name__}: {e}")
import traceback
traceback.print_exc()
return None
if not hasattr(module, "New"):
print(f"[PluginLoader] 插件 {clean_name} 缺少 New() 函数")
return None
try:
instance = module.New()
except TypeError as e:
print(f"[PluginLoader] 创建插件 {clean_name} 实例失败:参数错误 - {e}")
return None
except Exception as e:
print(f"[PluginLoader] 创建插件 {clean_name} 实例失败:{type(e).__name__}: {e}")
return None
self.loaded[clean_name] = {
"instance": instance,
"module": module,
"path": str(plugin_dir),
"name": clean_name,
}
return self.loaded[clean_name]