Files
NebulaShell/ai.md
qwen.ai[bot] 9f7ca46f96 Update TUI to v1.3 with enhanced conversion layer and dual UI architecture
- ai.md: Added comprehensive documentation for TUI v1.3 conversion layer with 64+ supported components, CSS styling, and JavaScript interaction capabilities
- oss/tui/: Created complete TUI module with converter.py implementing HTML/CSS/JS to terminal conversion engine, supporting 40+ component types and advanced styling
- oss/tui/plugin.py: Implemented TUI plugin with dual startup architecture accessing WebUI's /tui interface for HTML conversion and terminal rendering
- store/@{NebulaShell}/webui/tui/: Added TUI package with converter, configuration files, and index.html for terminal interface
- store/@{NebulaShell}/webui/core/server.py: Enhanced WebUI server with TUI interface endpoints (/tui/*) for providing special-marked HTML to conversion layer
- store/@{NebulaShell}/webui/main.py: Updated WebUI plugin to support TUI dual launch with automatic homepage redirection and navigation integration
- .gitignore: Updated ignore patterns for better project cleanliness

The update provides a sophisticated terminal interface that automatically converts WebUI content through a powerful transformation layer, enabling seamless dual-mode operation.
2026-05-02 12:04:27 +08:00

14 KiB
Raw Blame History

NebulaShell AI 开发文档

项目介绍

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 + WebUI 双启动架构

架构概述

系统现在默认同时启动 WebUI 和 TUI

  • WebUI:在浏览器中运行,提供完整的图形界面
  • TUI:在终端中运行,通过强大的转换层 (v1.3) 自动解析 WebUI 的 /tui 接口

TUI 转换层核心能力 (v1.3)

TUI 转换层是一个强大的渲染引擎,能够自动访问 WebUI 开放的 /tui 接口,解析特殊的 .html 文件(入口为 index.html),并将其转换为终端界面。

支持的组件类型 (64+)

基础组件: text, heading, paragraph, span, divider, spacer
容器组件: container, box, panel, card, grid, flex, stack
表单组件: input, button, checkbox, radio, select, textarea, slider
数据组件: table, list, tree, progress, gauge, chart, stat
导航组件: navbar, sidebar, menu, breadcrumb, tabs, pagination
反馈组件: alert, toast, modal, spinner, tooltip, badge
布局组件: row, col, section, article, aside, header, footer
特殊组件: code, pre, blockquote, mark, kbd, time, avatar

CSS 样式支持

转换层支持终端兼容的 CSS 样式:

/* 颜色系统 */
color: #RGB, #RRGGBB, rgb(), rgba(), hsl(), 颜色名称
background-color: 同上
border-color: 同上

/* 字体排版 */
font-size: small, medium, large, x-large, numeric(pt)
font-weight: normal, bold, bolder, lighter, numeric(100-900)
font-style: normal, italic, oblique
text-decoration: none, underline, overline, line-through
text-align: left, center, right, justify

/* 边框样式 */
border: width style color
border-style: none, solid, double, dashed, rounded, heavy, ascii
border-width: thin, medium, thick, numeric
border-radius: numeric (仅支持 rounded 样式)

/* 布局与间距 */
margin: numeric
padding: numeric
width: numeric, percentage, auto
height: numeric, percentage, auto
display: block, inline, flex, grid, none

/* 特殊效果 */
opacity: 0.0-1.0 (通过字符密度模拟)
white-space: normal, nowrap, pre
overflow: visible, hidden, scroll

JavaScript 交互支持

转换层模拟基础 JS 交互功能:

// 键盘事件
document.addEventListener('keydown', (e) => { ... })
document.addEventListener('keyup', (e) => { ... })

// 鼠标事件 (如果终端支持)
element.addEventListener('click', (e) => { ... })
element.addEventListener('mouseover', (e) => { ... })
element.addEventListener('mouseout', (e) => { ... })

// 焦点管理
element.focus()
element.blur()

// 类名切换
element.classList.add('active')
element.classList.remove('active')
element.classList.toggle('active')

使用方式

启动服务

# 方式 1: 直接启动
python main.py

# 方式 2: 模块方式
python -m oss.cli serve

# 方式 3: Docker
docker run -p 8080:8080 nebulashell:latest

启动后:

  • WebUI 自动在默认浏览器打开 (通常是 http://localhost:8080)
  • TUI 在终端中自动渲染,显示相同内容

TUI 交互

  • 方向键:导航焦点元素
  • Enter/Space:激活按钮/复选框
  • Tab/Shift+Tab:切换焦点
  • q / Ctrl+C:退出 TUI (WebUI 继续运行)
  • 鼠标点击:如果终端支持鼠标,可直接点击交互

访问 /tui 接口

WebUI 需要开放 /tui 路径提供特殊 HTML

GET /tui/index.html  - TUI 主页面
GET /tui/*.html      - 其他 TUI 页面
GET /tui/*.css       - TUI 专用样式
GET /tui/*.js        - TUI 交互逻辑

这些文件不包含给用户直接查看的内容,而是包含特殊的 data-tui-* 标记供转换层解析。


插件开发指南

插件基础结构

所有插件必须继承自 oss.plugin.types.Plugin 基类,并实现三个核心方法:

from oss.plugin.types import Plugin
from oss.plugin.decorators import plugin

@plugin(name="my-plugin", version="1.0.0", description="我的插件")
class MyPlugin(Plugin):
    """插件类"""
    
    def init(self) -> 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

插件装饰器参数

@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 路由

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)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>我的插件</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h1>欢迎使用我的插件</h1>
        <button id="action-btn">执行操作</button>
        <div id="result"></div>
    </div>
    <script src="app.js"></script>
</body>
</html>

TUI 页面 (tui/index.html)

<!-- TUI 专用页面,包含 data-tui 标记 -->
<div data-tui-type="panel" data-tui-title="我的插件" data-tui-border="rounded">
    <h1 data-tui-type="heading" data-tui-level="1" data-tui-align="center">
        欢迎使用我的插件
    </h1>
    
    <button 
        data-tui-type="button" 
        data-tui-label="执行操作"
        data-tui-id="action-btn"
        data-tui-style="primary">
    </button>
    
    <div 
        data-tui-type="text" 
        data-tui-id="result"
        data-tui-color="gray">
        等待操作...
    </div>
</div>

TUI 专用样式 (tui/styles.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)

// 仅支持基础交互
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 中定义插件配置:

# 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

在插件中读取配置:

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}")

插件间通信

# 调用其他插件的方法
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() 方法 (按依赖逆序)

调试插件

# 启用调试模式
export NEBULA_DEBUG=1
python main.py

# 查看特定插件日志
tail -f logs/nebula.log | grep my-plugin

# 热重载插件 (开发模式)
python main.py --dev --reload-plugins

打包插件

# 创建插件包
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. 错误处理

try:
    result = risky_operation()
except SpecificError as e:
    self.logger.error(f"操作失败: {e}")
    raise PluginError("操作执行失败", original_error=e)
finally:
    cleanup_resources()

3. 日志记录

# 不同级别的日志
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

# 设置环境变量
export NEBULA_TUI_ENABLED=false
python main.py

# 或在配置文件中
# config.yaml
tui:
  enabled: false

Q: TUI 显示乱码怎么办?

确保终端支持 UTF-8 和真彩色:

# 检查终端支持
echo $TERM  # 应该类似 xterm-256color

# 启用真彩色
export COLORTERM=truecolor

Q: 如何自定义 TUI 主题?

在插件的 tui/styles.css 中定义主题变量:

:root {
    --primary-color: #0066cc;
    --secondary-color: #6c757d;
    --success-color: #28a745;
    --danger-color: #dc3545;
    --bg-color: #1a1a2e;
    --text-color: #eeeeee;
}

Q: 插件加载失败如何排查?

# 查看详细日志
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

开发环境设置

# 克隆仓库
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 文件。

联系方式