# NebulaShell AI 开发文档 > **架构决策**:`nebula cli` 采用前后端分离设计,TUI 前端直连后端 JSON API, > 不使用 HTML→ANSI 转换引擎。详见下文 [TUI 架构决策](#tui-架构决策)。 ## 项目介绍 NebulaShell 是一个企业级插件化运行时框架 (v1.2.0),核心理念是「一切皆为插件」。它提供了一个最小化的核心系统,仅负责加载 `plugin-loader` 插件,其余 26+ 个官方插件均由该加载器管理。 ### 核心特性 - **插件化架构**:所有功能均通过插件实现,支持热插拔 - **隐藏成就系统**:通过 `!!` 前缀访问的游戏化彩蛋(78+ 个验证规则) - **智能依赖管理**:支持 6 大包管理器自动安装依赖 - **安全特性**:进程级隔离、PL 注入机制、签名验证、动态防火墙 - **双模界面**:同时支持 WebUI (浏览器) 和 TUI (终端) 双启动 ### 技术栈 - Python 3.10+ - Click (命令行框架) - PyYAML (配置解析) - websockets (实时通信) - Rich (TUI 渲染引擎) - 纯静态 WebUI (HTML/CSS/JS) --- ## TUI 架构决策 ### 废弃方案:HTML→ANSI 动态转换层(v1.3) **已废弃。** 早期方案通过 `oss/tui/converter.py`(1430 行)在运行时将 WebUI 的 HTML 页面解析为终端元素,存在以下问题: | 问题 | 说明 | |------|------| | **布局失真** | CSS Flex/Grid 布局模型无法映射到终端字符网格 | | **交互断层** | JavaScript 事件系统只能在终端模拟,与真实浏览器行为不一致 | | **维护成本高** | 1430 行转换引擎 + 每个 WebUI 页面需维护 TUI 兼容标记 | | **渲染性能差** | 每次导航需对整个 HTML 进行 DOM 解析和布局计算 | | **调试困难** | 终端渲染错误难以定位是 HTML 问题还是转换器 Bug | ### 当前方案:前后端分离,原生 ANSI 渲染 ``` nebula serve ─── JSON API ───→ nebula cli (TUI 前端) (后端) (原生 ANSI 终端渲染) ``` **后端职责**(`nebula serve`): - 提供 RESTful JSON API(如 `/api/dashboard/stats`) - WebSocket 实时推送 - 不感知 TUI 存在 **前端职责**(`nebula cli`): - 通过 HTTP/WebSocket 消费后端 JSON 数据 - 使用 ANSI 转义码直接在终端绘制界面 - 不依赖任何 HTML/CSS 解析 #### 技术要点 ``` 终端控制: raw mode ─── tty.setraw(),单字节读取 ONLCR ─── 重新开启 \n→\r\n 映射,避免阶梯乱码 SGR 鼠标 ─── \x1b[?1000h\x1b[?1006h,解析 \x1b[ None: """初始化阶段:加载配置、注册路由等""" self.logger.info("插件初始化") def start(self) -> None: """启动阶段:启动服务、连接数据库等""" self.logger.info("插件启动") def stop(self) -> None: """停止阶段:清理资源、断开连接等""" self.logger.info("插件停止") ``` ### 插件目录结构 ``` plugins/ └── my-plugin/ ├── __init__.py # 插件入口 ├── plugin.py # 主插件类 ├── config.yaml # 配置文件 ├── routes/ # HTTP 路由 │ ├── __init__.py │ └── api.py ├── tui/ # TUI 专用页面 │ ├── index.html │ ├── styles.css │ └── interaction.js ├── webui/ # WebUI 页面 │ ├── index.html │ ├── styles.css │ └── app.js └── utils/ # 工具函数 └── helpers.py ``` ### 插件装饰器参数 ```python @plugin( name="unique-name", # 唯一插件名 (必填) version="1.0.0", # 版本号 (必填) description="插件描述", # 描述 (必填) author="作者名", # 作者 (可选) dependencies=["plugin-a"], # 依赖插件列表 (可选) optional_dependencies=["plugin-b"], # 可选依赖 (可选) min_core_version="1.0.0", # 最低核心版本要求 (可选) tags=["category", "type"], # 标签分类 (可选) enabled=True # 默认是否启用 (可选) ) ``` ### 注册 HTTP 路由 ```python from flask import Blueprint, jsonify # 创建路由蓝图 bp = Blueprint('my_plugin', __name__, url_prefix='/api/my-plugin') @bp.route('/health', methods=['GET']) def health_check(): """健康检查接口""" return jsonify({"status": "ok", "plugin": "my-plugin"}) @bp.route('/data', methods=['POST']) def receive_data(): """接收数据接口""" data = request.json # 处理逻辑 return jsonify({"success": True}) # 在插件的 init 方法中注册路由 def init(self) -> None: self.app.register_blueprint(bp) ``` ### 创建 TUI/WebUI 页面 #### WebUI 页面 (webui/index.html) ```html 我的插件

欢迎使用我的插件

``` #### TUI 页面 (tui/index.html) ```html

欢迎使用我的插件

等待操作...
``` #### TUI 专用样式 (tui/styles.css) ```css /* 仅包含终端支持的样式 */ .container { padding: 2; margin: 1; } h1 { font-size: large; font-weight: bold; text-align: center; color: #00ff00; } button { background-color: #0066cc; color: #ffffff; border: 2 solid #004499; border-style: rounded; padding: 1 2; } #result { color: #888888; font-style: italic; } ``` #### TUI 交互逻辑 (tui/interaction.js) ```javascript // 仅支持基础交互 document.getElementById('action-btn').addEventListener('click', function() { // 发送请求到后端 fetch('/api/my-plugin/action', {method: 'POST'}) .then(res => res.json()) .then(data => { document.getElementById('result').textContent = data.message; }); }); // 键盘快捷键 document.addEventListener('keydown', function(e) { if (e.key === 'r') { // 刷新操作 location.reload(); } }); ``` ### 插件配置 在 `config.yaml` 中定义插件配置: ```yaml # plugins/my-plugin/config.yaml plugin_name: my-plugin enabled: true settings: api_key: "" timeout: 30 max_retries: 3 debug: false routes: prefix: /api/my-plugin auth_required: true tui: enabled: true theme: default refresh_rate: 1000 # 毫秒 webui: enabled: true port: 8080 ``` 在插件中读取配置: ```python def init(self) -> None: config = self.get_config() self.api_key = config.get('settings', {}).get('api_key', '') self.timeout = config.get('settings', {}).get('timeout', 30) self.logger.info(f"插件配置加载完成: timeout={self.timeout}") ``` ### 插件间通信 ```python # 调用其他插件的方法 other_plugin = self.get_plugin('other-plugin') if other_plugin: result = other_plugin.some_method(arg1, arg2) # 发布事件 self.emit_event('my-event', {'data': 'value'}) # 订阅事件 @self.on_event('other-event') def handle_event(event_data): self.logger.info(f"收到事件: {event_data}") ``` ### 插件生命周期 ``` 1. 发现阶段:扫描 plugins 目录,识别插件 2. 排序阶段:根据依赖关系确定加载顺序 3. 初始化阶段:调用每个插件的 init() 方法 4. 启动阶段:调用每个插件的 start() 方法 5. 运行阶段:插件正常提供服务 6. 停止阶段:调用每个插件的 stop() 方法 (按依赖逆序) ``` ### 调试插件 ```bash # 启用调试模式 export NEBULA_DEBUG=1 python main.py # 查看特定插件日志 tail -f logs/nebula.log | grep my-plugin # 热重载插件 (开发模式) python main.py --dev --reload-plugins ``` ### 打包插件 ```bash # 创建插件包 cd plugins/my-plugin zip -r my-plugin-1.0.0.zip . # 安装插件 nebula plugin install my-plugin-1.0.0.zip # 发布到插件市场 nebula plugin publish my-plugin-1.0.0.zip ``` --- ## 最佳实践 ### 1. 代码规范 - 遵循 PEP 8 编码规范 - 使用类型注解 - 编写单元测试 (覆盖率 > 80%) - 添加详细的文档字符串 ### 2. 错误处理 ```python try: result = risky_operation() except SpecificError as e: self.logger.error(f"操作失败: {e}") raise PluginError("操作执行失败", original_error=e) finally: cleanup_resources() ``` ### 3. 日志记录 ```python # 不同级别的日志 self.logger.debug("调试信息") self.logger.info("一般信息") self.logger.warning("警告信息") self.logger.error("错误信息") self.logger.critical("严重错误") # 带上下文的日志 self.logger.info( "用户操作", extra={"user_id": user_id, "action": "create"} ) ``` ### 4. 性能优化 - 使用异步操作处理 I/O 密集型任务 - 实现缓存机制减少重复计算 - 批量处理数据库操作 - 监控资源使用情况 ### 5. 安全考虑 - 验证所有用户输入 - 使用参数化查询防止 SQL 注入 - 实施速率限制 - 定期更新依赖 - 敏感信息使用环境变量 --- ## 常见问题 ### Q: 如何禁用 TUI 只使用 WebUI? ```bash # 设置环境变量 export NEBULA_TUI_ENABLED=false python main.py # 或在配置文件中 # config.yaml tui: enabled: false ``` ### Q: TUI 显示乱码怎么办? 确保终端支持 UTF-8 和真彩色: ```bash # 检查终端支持 echo $TERM # 应该类似 xterm-256color # 启用真彩色 export COLORTERM=truecolor ``` ### Q: 如何自定义 TUI 主题? 在插件的 `tui/styles.css` 中定义主题变量: ```css :root { --primary-color: #0066cc; --secondary-color: #6c757d; --success-color: #28a745; --danger-color: #dc3545; --bg-color: #1a1a2e; --text-color: #eeeeee; } ``` ### Q: 插件加载失败如何排查? ```bash # 查看详细日志 python main.py --verbose # 检查插件依赖 nebula plugin check my-plugin # 验证插件结构 nebula plugin validate my-plugin/ ``` --- ## 贡献指南 1. Fork 项目仓库 2. 创建功能分支 (`git checkout -b feature/amazing-feature`) 3. 提交更改 (`git commit -m 'Add amazing feature'`) 4. 推送到分支 (`git push origin feature/amazing-feature`) 5. 创建 Pull Request ### 开发环境设置 ```bash # 克隆仓库 git clone https://github.com/nebulashell/nebulashell.git cd nebulashell # 创建虚拟环境 python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate # 安装开发依赖 pip install -e ".[dev]" # 运行测试 pytest tests/ # 代码格式化 black . isort . flake8 . ``` --- ## 许可证 本项目采用 MIT 许可证,详见 LICENSE 文件。 ## 联系方式 - 官网:https://nebulashell.io - 文档:https://docs.nebulashell.io - 社区:https://community.nebulashell.io - GitHub: https://github.com/nebulashell/nebulashell