初步规划TuUi模式,并预留接口
This commit is contained in:
170
ai.md
170
ai.md
@@ -1,5 +1,8 @@
|
||||
# NebulaShell AI 开发文档
|
||||
|
||||
> **架构决策**:`nebula cli` 采用前后端分离设计,TUI 前端直连后端 JSON API,
|
||||
> 不使用 HTML→ANSI 转换引擎。详见下文 [TUI 架构决策](#tui-架构决策)。
|
||||
|
||||
## 项目介绍
|
||||
|
||||
NebulaShell 是一个企业级插件化运行时框架 (v1.2.0),核心理念是「一切皆为插件」。它提供了一个最小化的核心系统,仅负责加载 `plugin-loader` 插件,其余 26+ 个官方插件均由该加载器管理。
|
||||
@@ -23,130 +26,77 @@ NebulaShell 是一个企业级插件化运行时框架 (v1.2.0),核心理念
|
||||
|
||||
---
|
||||
|
||||
## TUI + WebUI 双启动架构
|
||||
## TUI 架构决策
|
||||
|
||||
### 架构概述
|
||||
### 废弃方案:HTML→ANSI 动态转换层(v1.3)
|
||||
|
||||
系统现在默认同时启动 WebUI 和 TUI:
|
||||
- **WebUI**:在浏览器中运行,提供完整的图形界面
|
||||
- **TUI**:在终端中运行,通过强大的转换层 (v1.3) 自动解析 WebUI 的 `/tui` 接口
|
||||
**已废弃。** 早期方案通过 `oss/tui/converter.py`(1430 行)在运行时将 WebUI 的 HTML 页面解析为终端元素,存在以下问题:
|
||||
|
||||
### TUI 转换层核心能力 (v1.3)
|
||||
| 问题 | 说明 |
|
||||
|------|------|
|
||||
| **布局失真** | CSS Flex/Grid 布局模型无法映射到终端字符网格 |
|
||||
| **交互断层** | JavaScript 事件系统只能在终端模拟,与真实浏览器行为不一致 |
|
||||
| **维护成本高** | 1430 行转换引擎 + 每个 WebUI 页面需维护 TUI 兼容标记 |
|
||||
| **渲染性能差** | 每次导航需对整个 HTML 进行 DOM 解析和布局计算 |
|
||||
| **调试困难** | 终端渲染错误难以定位是 HTML 问题还是转换器 Bug |
|
||||
|
||||
TUI 转换层是一个强大的渲染引擎,能够自动访问 WebUI 开放的 `/tui` 接口,解析特殊的 `.html` 文件(入口为 `index.html`),并将其转换为终端界面。
|
||||
|
||||
#### 支持的组件类型 (64+)
|
||||
### 当前方案:前后端分离,原生 ANSI 渲染
|
||||
|
||||
```
|
||||
基础组件: 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
|
||||
nebula serve ─── JSON API ───→ nebula cli (TUI 前端)
|
||||
(后端) (原生 ANSI 终端渲染)
|
||||
```
|
||||
|
||||
#### CSS 样式支持
|
||||
**后端职责**(`nebula serve`):
|
||||
- 提供 RESTful JSON API(如 `/api/dashboard/stats`)
|
||||
- WebSocket 实时推送
|
||||
- 不感知 TUI 存在
|
||||
|
||||
转换层支持终端兼容的 CSS 样式:
|
||||
**前端职责**(`nebula cli`):
|
||||
- 通过 HTTP/WebSocket 消费后端 JSON 数据
|
||||
- 使用 ANSI 转义码直接在终端绘制界面
|
||||
- 不依赖任何 HTML/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 交互功能:
|
||||
|
||||
```javascript
|
||||
// 键盘事件
|
||||
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')
|
||||
```
|
||||
|
||||
### 使用方式
|
||||
|
||||
#### 启动服务
|
||||
|
||||
```bash
|
||||
# 方式 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 交互逻辑
|
||||
终端控制:
|
||||
raw mode ─── tty.setraw(),单字节读取
|
||||
ONLCR ─── 重新开启 \n→\r\n 映射,避免阶梯乱码
|
||||
SGR 鼠标 ─── \x1b[?1000h\x1b[?1006h,解析 \x1b[<button;x;y;M
|
||||
SIGWINCH ─── 捕获终端 resize,全屏重绘
|
||||
|
||||
ANSI 绘制:
|
||||
24-bit 真彩色 ─── \x1b[38;2;R;G;Bm / \x1b[48;2;R;G;Bm
|
||||
字符图形 ─── █ ░ ▓ 等 Unicode 块字符作进度条
|
||||
光标定位 ─── \x1b[{row};{col}H
|
||||
|
||||
页面导航:
|
||||
热点区域映射 ─── 预计算每行点击区域 (y → page_id)
|
||||
键盘备选 ─── 数字键 1-5 作为鼠标候补
|
||||
```
|
||||
|
||||
这些文件不包含给用户直接查看的内容,而是包含特殊的 `data-tui-*` 标记供转换层解析。
|
||||
### 开放代码(opencode)TUI 架构分析
|
||||
|
||||
[opencode](https://opencode.ai) 是目前最成熟的终端 AI 编程助手,其 TUI 架构可参考:
|
||||
|
||||
| 特性 | opencode 实现 |
|
||||
|------|-------------|
|
||||
| **渲染引擎** | 原生终端渲染,无 HTML 中间层。直接操作终端缓冲区 |
|
||||
| **组件系统** | 类似 React 的组件化方案,但所有组件直接输出 ANSI 字符串 |
|
||||
| **输入处理** | raw mode + SGR 鼠标 + 组合键解析,支持 `Tab` 切换模式 |
|
||||
| **布局** | 弹性布局引擎,组件根据终端宽度自动折行/折叠 |
|
||||
| **状态管理** | 全局状态树,每次状态变更触发受控重绘(非全屏重绘)|
|
||||
| **会话管理** | 多会话并行,每个会话独立维护上下文和渲染状态 |
|
||||
| **主题系统** | 完整的配色方案,支持暗色/亮色主题切换 |
|
||||
|
||||
**关键差异**:opencode 不使用任何 Web 技术栈做 TUI,其所有界面元素(输入框、按钮、列表、状态栏、侧边栏)都是直接通过 ANSI 转义码在终端绘制的。每个组件是一个纯 Python/TypeScript 类,`render()` 方法返回 ANSI 字符串。
|
||||
|
||||
**对我们的启发**:
|
||||
1. 放弃 HTML 转换层是正确的方向
|
||||
2. 直接 ANSI 渲染的架构更可控、性能更好
|
||||
3. 需要设计自己的组件化终端渲染库(参考 opencode 的组件系统)
|
||||
4. `nebula cli` 命令已预留,后续在此框架上构建原生 TUI
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user