设计文档-CC-Switch-CLI-TUI设计文档

CC-Switch CLI TUI 前端设计文档

这个是Claude阅读完https://github.com/SaladDay/cc-switch-cli代码后,提取的tui设计文档。这个tui设计比较简洁好用,后续相关设计可以参考。

基于 src-tauri/src/cli/tui/ 目录源码 v5.8.2。


目录

  1. 概述
  2. 架构概览
  3. 数据层设计
  4. 页面设计
  5. 交互逻辑
  6. Overlay 系统
  7. 表单系统
  8. 编辑器系统
  9. 主题系统
  10. Worker 系统
  11. 关键数据结构参考

1. 概述

CC-Switch TUI 是一个基于 Ratatui + Crossterm 的终端文本用户界面,用于管理多 AI 客户端(Claude Code、Codex、Gemini、OpenCode、Hermes、OpenClaw)的 Provider 配置、MCP 服务器、Prompt、Skills、代理设置、用量查询等。

1.1 技术栈

层次技术
终端渲染Ratatui (0.x)
事件输入Crossterm
动画效果TachyonFX
数据结构纯 Rust struct/enum
并发模型mpsc channel + Worker 系统
国际化内置 i18n(中/英)

1.2 文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
tui/
├── mod.rs # 入口: run() 事件循环 + Worker 协调
├── ui.rs # 渲染入口: render() + 页面路由分发
├── route.rs # Route / NavItem 枚举
├── theme.rs # 主题色、颜色检测
├── data.rs # UiData 快照 + 所有数据行类型
├── help.rs # 上下文敏感帮助系统
├── terminal.rs # TuiTerminal: 原始模式、备用屏幕
├── text_edit.rs # TextInput 行编辑器(readline 风格)
├── form.rs # 表单状态 struct 定义
├── app/
│ ├── mod.rs # 子模块重导出
│ ├── app_state.rs # App struct + Action enum + 导航逻辑
│ ├── types.rs # Overlay/Toast/FilterState/UsageState 等
│ ├── helpers.rs # 过滤、选择器可见性
│ ├── editor_state.rs # EditorState 定义
│ ├── editor_handlers.rs # 编辑器按键处理
│ ├── menu.rs # 导航菜单逻辑
│ ├── form_handlers/ # 表单按键处理
│ ├── overlay_handlers/ # Overlay 按键处理
│ ├── content_*.rs # 各页面按键��辑
│ └── tests.rs
├── form/ # 表单渲染辅助
│ ├── mod.rs
│ ├── provider_*.rs
│ ├── mcp.rs
│ ├── prompt.rs
│ └── codex_config.rs
├── runtime_actions/ # Action → 实际业务逻辑映射
│ ├── mod.rs # handle_action() 分发
│ └── *.rs
├── runtime_systems/ # 后台 Worker 系统
│ ├── mod.rs # 启动函数集合
│ ├── types.rs # Request/Message 类型
│ ├── workers.rs # Worker 实现
│ └── handlers.rs # Worker 消息处理器
└── ui/ # 渲染子模块
├── mod.rs
├── chrome.rs # Header / Nav / Footer / Toast
├── main_page.rs # Dashboard 首页
├── providers.rs # Provider 列表 + 详情
├── usage.rs # 用量统计
├── pricing.rs # 模型定价表
├── sessions.rs # 会话浏览器
├── mcp.rs # MCP 服务器列表
├── prompts.rs # Prompt 管理
├── config.rs # 配置管理
├── editor.rs # 内联编辑器渲染
├── proxy_wave.rs # 代理活动波形图
├── overlay/ # Overlay 渲染
├── forms/ # 表单渲染
└── skills/ # Skills 渲染

2. 架构概览

2.1 整体数据流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
用户输入 (Key/Mouse)


event::poll() ──→ event::read() ──→ KeyEvent/MouseEvent


App::on_key(key) # 将按键转换为 Action


handle_action(action) # runtime_actions/mod.rs 分发

├── 直接修改 App 状态
├── 发送 Worker 请求 (mpsc channel)
└── 显示 Toast / 弹出 Overlay


下一帧渲染循环


ui::render(Frame, App, UiData)

2.2 主循环 (run())

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// mod.rs 中的主事件循环 (约 200ms tick)
loop {
// 1. 绘制帧
terminal.draw(|f| { ui::render(f, &app, &data); ... });

// 2. 排空所有 Worker 消息 (mpsc channels)
drain worker messages (speedtest, stream_check, proxy,
quota, app_data, usage_pricing, sessions, skills,
webdav, update, model_fetch, managed_auth, local_env)

// 3. 轮询用户事件
if event::poll(tick_rate) {
match event::read() {
Event::Key(key) => {
let action = app.on_key(key, &data);
handle_action(terminal, &mut app, &mut data,
channels, action)?;
}
Event::Mouse(mouse) => {
// ScrollUp/Down → 映射为 Up/Down key events
}
_ => {}
}
}

// 4. 周期 tick (200ms)
if last_tick.elapsed() >= tick_rate {
app.on_tick();
// 配额自动刷新、代理活动轮询等
}
}

2.3 TCA 架构

TUI 遵循 The Composable Architecture 模式:

  • State: App (视图状态 + 导航) + UiData (加载数据) + Overlay (模态叠加层)
  • Action: Action 枚举 (80+ 变体)
  • View: render(Frame, App, UiData) — 纯函数,按路由分发到页面渲染器
  • Data Flow: 事件 → Action → handle_action → Worker channel 或直接状态变更 → 重渲染

2.4 视图布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──────────────────────────────────────────────────────┐ ← 3 行
│ CC-Switch CLI [claude] [codex] [gemini│ ← Header: 标题 + 应用切换 + 代理状态 + 当前 Provider
│ Proxy: ON failover Current: openai │
├────────┬─────────────────────────────────────────────┤
│ │ │
│ ► Home │ Provider List │ ← 动态高度
│ Providers │ ─── OpenAI ............... (current) │
│ MCP │ ─── Anthropic ............. │
│ Skills│ ─── Google Gemini ........................ │
│ ... │ │
│ │ │
├────────┴─────────────────────────────────────────────┤ ← 1 行
│ ←→ menu/content ↑↓ move [ ] switch app / filter │ ← Footer: 快捷键提示
└──────────────────────────────────────────────────────┘
  • 三行垂直布局: Header (3)Body (min)Footer (1)
  • Body 水平分割: Nav (固定宽度)Content (剩余空间)
  • Overlay/Toast 覆盖在最上层

3. 数据层设计

3.1 UiData 快照

UiData 是渲染层唯一的只读数据源,所有页面渲染均从它读取:

1
2
3
4
5
6
7
8
9
10
11
12
pub struct UiData {
pub providers: ProvidersSnapshot, // 供应商列表
pub mcp: McpSnapshot, // MCP 服务器列表
pub prompts: PromptsSnapshot, // Prompt 列表
pub config: ConfigSnapshot, // 配置信息 (路径/备份/WebDAV/OpenClaw/Hermes)
pub skills: SkillsSnapshot, // Skills 安装列表/仓库/同步方式
pub proxy: ProxySnapshot, // 本地代理状态
pub usage: UsageSnapshot, // 用量统计 (today/7d/30d/custom)
pub pricing: ModelPricingSnapshot, // 模型定价表
pub quota: QuotaSnapshot, // 配额状态
pub reload_token: UiDataReloadToken, // 重新加载标记
}

3.2 各模块数据行

ProviderRow

1
2
3
4
5
6
7
8
9
10
11
pub struct ProviderRow {
pub id: String, // 供应商 ID
pub provider: Provider, // 完整 Provider 数据
pub api_url: Option<String>, // API 基础地址
pub is_current: bool, // 是否为当前激活
pub is_in_config: bool, // 是否已写入客户端配置
pub is_saved: bool, // 是否已保存 (vs 仅存在于客户端配置)
pub is_default_model: bool, // 是否为默认模型
pub primary_model_id: Option<String>,
pub default_model_id: Option<String>,
}

McpRow

1
2
3
4
pub struct McpRow {
pub id: String,
pub server: McpServer,
}

PromptRow

1
2
3
4
pub struct PromptRow {
pub id: String,
pub prompt: Prompt,
}

Usage 数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
pub struct UsageSummarySnapshot {
pub total_requests: u64,
pub success_count: u64,
pub total_cost_usd: f64,
pub total_tokens: u64,
pub input_tokens: u64,
pub output_tokens: u64,
pub cache_read_tokens: u64,
pub cache_creation_tokens: u64,
pub avg_latency_ms: Option<u64>,
}

pub struct UsageTrendBucket {
pub key: String, // "09", "2024-01-01"
pub label: String, // "09:00", "01/01"
pub request_count: u64,
pub total_tokens: u64,
pub total_cost_usd: f64,
pub error_count: u64,
}

pub struct UsageProviderStatsRow {
pub provider_id: String,
pub provider_name: Option<String>,
pub request_count: u64,
pub success_count: u64,
pub total_tokens: u64,
pub total_cost_usd: f64,
pub avg_latency_ms: Option<u64>,
}

pub struct UsageModelStatsRow {
pub model: String,
pub request_count: u64,
pub success_count: u64,
pub total_tokens: u64,
pub total_cost_usd: f64,
pub avg_latency_ms: Option<u64>,
}

pub struct UsageLogRow {
pub request_id: String,
pub created_at: i64,
pub app_type: String,
pub provider_id: String,
pub provider_name: Option<String>,
pub model: String,
pub status_code: u16,
pub input_tokens: u64,
pub output_tokens: u64,
pub cache_read_tokens: u64,
pub cache_creation_tokens: u64,
pub total_cost_usd: f64,
pub latency_ms: u64,
pub first_token_ms: Option<u64>,
pub duration_ms: Option<u64>,
pub session_id: Option<String>,
pub error_message: Option<String>,
// ...
}

ProxySnapshot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pub struct ProxySnapshot {
pub enabled: bool,
pub running: bool,
pub managed_runtime: bool,
pub active_worker_apps: HashSet<String>,
pub auto_failover_enabled: bool,
pub claude_takeover: bool,
pub codex_takeover: bool,
pub gemini_takeover: bool,
pub configured_listen_address: String,
pub configured_listen_port: u16,
pub listen_address: String,
pub listen_port: u16,
pub uptime_seconds: u64,
pub total_requests: u64,
pub estimated_input_tokens_total: u64,
pub estimated_output_tokens_total: u64,
pub last_error: Option<String>,
}

SkillsSnapshot

1
2
3
4
5
pub struct SkillsSnapshot {
pub installed: Vec<InstalledSkill>,
pub repos: Vec<SkillRepo>,
pub sync_method: SyncMethod,
}

3.3 数据加载模式

模式用途
ProviderLoadMode::SyncLive同步客户端配置到数据库 (OpenClaw 等)
ProviderLoadMode::SnapshotOnly仅从数据库快照加载 (快速切换)
  • UiDataByAppCache: 按 App 类型缓存数据,实现应用间瞬时切换
  • 切换应用时显示 “loading projection” 占位状态

4. 页面设计

4.1 路由系统

Route 枚举 (route.rs)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
pub enum Route {
Main, // 首页 Dashboard
Providers, // Provider 列表
ProviderDetail { id }, // Provider 详情
Usage, // 用量统计
UsageLogs, // 用量日志
UsageLogDetail { request_id },// 单条日志详情
Pricing, // 模型定价表
Sessions, // 会话浏览器
Mcp, // MCP 服务器管理
Prompts, // Prompt 管理
HermesMemory, // Hermes 记忆编辑
Config, // 配置管理
ConfigOpenClawWorkspace, // OpenClaw 工作区
ConfigOpenClawDailyMemory, // OpenClaw 每日记忆
ConfigOpenClawEnv, // OpenClaw 环境变量
ConfigOpenClawTools, // OpenClaw 工具配置
ConfigOpenClawAgents, // OpenClaw 代理配置
ConfigWebDav, // WebDAV 同步
Skills, // Skills 已安装
SkillsDiscover, // Skills 发现
SkillsRepos, // Skills 仓库
SkillDetail { directory }, // Skill 详情
Settings, // 设置
SettingsProxy, // 代理设置
SettingsManagedAccounts, // 托管账号
}

导航菜单有 3 种配置,按 AppType 自适应:

菜单项通用OpenClawHermes
Main (Home)
Providers
Usage
Sessions
MCP
Prompts
HermesMemory
Config
Skills
OpenClawWorkspace
OpenClawEnv
OpenClawTools
OpenClawAgents
Settings
Exit

4.2 页面详解

4.2.1 首页 (Main / Dashboard)

渲染: ui/main_page.rs

内容: - 本地环境检查 (本地工具状态) — LocalEnvCheck - 代理状态卡片 (Running/Stopped/Taking Over) - 代理活动波形图 (TachyonFX 动画) - 快速操作入口

交互: - P — 启动/停止代理 - r — 刷新本地环境检查

4.2.2 Provider 管理 (Providers)

渲染: ui/providers.rs

列表展示: | 列 | 内容 | |—-|——| | 名称 | Provider 名称 | | Base URL | API 地址 | | 状态 | Current / Saved / In Config | | 模型 | 当前默认模型 |

操作: | 按键 | 操作 | |——|——| | Enter | 查看 Provider 详情 | | s | 切换为当前 Provider | | w | 写入配置到客户端 | | D | 删除 Provider | | d | 设置默认模型 | | t | 速度测试 | | S | 流检查 (Stream Check) | | Q | 配额刷新 | | M | 切换 Failover 队列 | | F | 模型抓取 | | e | 编辑 Provider | | c | 复制 Provider | | A | 添加新 Provider (表单) | | R | 从客户端配置导入 |

ProviderDetail 页面 (Route::ProviderDetail { id }): - 显示 Provider 完整配置 JSON 预览 - Claude 模型分层配置 - API 格式选择 - 用量查询配置 - Codex 本地路由设置 - OpenClaw 模型列表管理

4.2.3 用量统计 (Usage)

渲染: ui/usage.rs

状态管理: UsageState

1
2
3
4
5
6
7
8
pub struct UsageState {
pub range: UsageRangePreset, // Today / 7d / 30d / Custom
pub metric: UsageMetric, // Cost / Tokens / Requests / Errors
pub pane: UsagePane, // Models / Providers / Recent
pub selected_idx: usize,
pub logs_idx: usize,
// ...
}

三栏布局:

1
2
3
4
5
┌──────────────┬──────────────┬──────────────────┐
│ Trend Chart │ Provider/ │ Recent Logs │
│ (TachyonFX) │ Model Table │ (scrollable) │
│ │ │ │
└──────────────┴──────────────┴──────────────────┘

Tab 切换: - Tab / BackTab — 在 Models / Providers / Recent 三 Pane 间切换 - 时间选择: 1 Today / 2 7d / 3 30d / C Custom - 指标选择: c Cost / t Tokens / r Requests / e Errors

4.2.4 会话浏览器 (Sessions)

渲染: ui/sessions.rs

双 Pane 布局:

1
2
3
4
5
6
7
8
┌─────────────────────┬─────────────��──────────────┐
│ Session List │ Session Detail │
│ ── │ Prompt: ... │
│ [x] session1 │ Response: ... (streaming) │
│ [x] session2 │ │
│ session3 │ [Messages with filter] │
│ │ │
└─────────────────────┴────────────────────────────┘

状态管理: SessionsState - pane: SessionsPane::List | Detail - message_filter: TextInput — 消息内容搜索 - selected: HashSet<u64> — 批量删除

操作: - / — 在 List/Detail 间切换焦点 - / — 搜索会话 - m — 加载消息 - R — 刷新会话列表 - Enter — 打开详情 - d — 删除选中会话 - e — 恢复会话 (Resume)

4.2.5 MCP 管理 (MCP)

渲染: ui/mcp.rs

列表展示: | 列 | 内容 | |—-|——| | 名称 | MCP 服务器名称 | | 类型 | stdio / http / sse | | 传输 | Command/URL |

操作: - A — 添加 MCP 服务器 (表单) - e — 编辑 - T — 切换启用/禁用 - w — 设置可用客户端 - D — 删除 - I — 从已安装客户端导入

4.2.6 Prompt 管理 (Prompts)

渲染: ui/prompts.rs

列表展示: | 列 | 内容 | |—-|——| | 名称 | Prompt 名称 | | 描述 | Prompt 描述 | | 状态 | Active / Inactive |

操作: - Enter — 编辑 Prompt - a — 激活 / d — 停用 - e — 编辑元数据 - D — 删除 - I — 导入

首次打开时: 自动检测并提示导入现有 Prompt 文件

4.2.7 Skills 管理 (Skills)

渲染: ui/skills/

子页面: - Skills — 已安装 Skill 列表 - SkillsDiscover — 搜索发现 Skill - SkillsRepos — Skill 仓库管理 - SkillDetail { directory } — Skill 详情

操作: - Enter — 查看详情 / 启用 - i — 安装 - U — 卸载 - T — 切换启用 - w — 设置可用客户端 - F — 发现 (搜索) - S — 同步到客户端 - + — 添加仓库 - - — 移除仓库 - I — 批量导入 (从应用) - s — 设置同步方式

4.2.8 配置管理 (Config)

渲染: ui/config.rs

菜单项 (ConfigItem): | 项 | 说明 | |—-|——| | Path | 配置文件路径 | | Show Full | 显示完整配置 JSON | | Export | 导出配�� | | Import | 导入配置 | | Backup | 创建备份 | | Restore | 恢复备份 | | Validate | 验证配置 | | Common Snippet | 通用配置片段 | | OpenClaw Workspace | 工作区管理 | | OpenClaw Env | 环境变量 | | OpenClaw Tools | 工具配置 | | OpenClaw Agents | 代理配置 | | WebDAV Sync | WebDAV 同步设置 | | Reset | 重置配置 |

4.2.9 设置 (Settings)

渲染: ui/ — settings 对应模块

菜单项 (SettingsItem): | 项 | 说明 | |—-|——| | Managed Accounts | 托管账号管理 | | Language | 语言切换 (中/英) | | Visible Apps Mode | 可见应用模式 | | Visible Apps | 手动选择可见应用 | | OpenClaw Config Dir | OpenClaw 配置目录 | | Skip Claude Onboarding | 跳过 Claude 入门 | | Claude Plugin Integration | Claude 插件集成 | | Proxy | 本地代理设置 | | Check For Updates | 检查更新 |

4.2.10 代理设置 (SettingsProxy)

设置项 (LocalProxySettingsItem): | 项 | 说明 | |—-|——| | ListenAddress | 监听地址 (默认 127.0.0.1) | | ListenPort | 监听端口 (默认 5251) | | AutoFailover | 自动故障转移开关 |

4.2.11 模型定价 (Pricing)

渲染: ui/pricing.rs

列表展示: | 列 | 内容 | |—-|——| | 模型 | Model ID | | 输入价格 | Input cost per million | | 输出价格 | Output cost per million | | 缓存读取 | Cache read cost | | 缓存创建 | Cache creation cost | | 请求数 | Recent request count | | 总成本 | Recent total cost |

4.2.12 用量日志 (UsageLogs)

渲染: ui/ — 由 Usage 页面进入

表格展示最近日志,支持按时间范围筛选。点击行进入 UsageLogDetail 查看完整 JSON 响应。

4.2.13 OpenClaw 工作区 (ConfigOpenClawWorkspace)

展示文件: AGENTS.md, SOUL.md, USER.md, IDENTITY.md, TOOLS.md, MEMORY.md, HEARTBEAT.md, BOOTSTRAP.md, BOOT.md

操作: - Enter — 打开文件编辑 - / — 搜索每日记忆 - D — 删除每日记忆

4.2.14 托管账号 (SettingsManagedAccounts)

Codex OAuth 管理: - 设备码登录流程 (Device Code OAuth) - 账号绑定/解绑 - 默认账号设置 - 登录过期处理


5. 交互逻辑

5.1 焦点系统

1
2
3
4
pub enum Focus {
Nav, // 左侧导航栏被聚焦
Content, // 右侧内容区域被聚焦
}

焦点切换规则: - — 切换到 Nav - — 切换到 Content (仅当路由有内容列表时) - Tab / BackTab — 特定路由下的 Pane 切换 (Usage, Sessions)

5.2 选择器面��� (Special Focus Panes)

UsagePane: Models | Providers | Recent - 由 Tab / BackTab 切换

SessionsPane: List | Detail - 由 / Tab / BackTab 切换

5.3 路由导航

1
2
3
4
5
6
7
8
9
Nav 聚焦:
↑/↓ — 移动导航选择
Enter — 进入对应页面
Esc — 退出 (进入确认)

Content 聚焦 (通用):
↑/↓ — 移动列表选择
Enter — 查看详情/操作
q / Esc — 返回上一页

路由栈: route_stack: Vec<Route> — 支持多级后退

路由转换规则 (set_route_no_history): - 进入 Sessions 时重置时间锚点 - 进入 Main 时清空路由栈、聚焦 Nav - 离开 DailyMemory/OpenClawTools/OpenClawAgents 时清除表单状态

5.4 全局按键

按键操作
切换到导航栏
切换到内容
/ 上下移动
Enter确认/进入
Esc返回上一页 (首页则退出确认)
/打开过滤输入
Ctrl+F打开过滤输入
Ctrl+C退出 TUI
Ctrl+,跳到设置页
?打开上下文帮助
[ / ]切换应用 (前/后)
P首页启动/停止代理
h / j / k / lVim 风格导航 (等效 ←↓↑→)

5.5 过滤系统 (FilterState)

1
2
3
4
5
pub struct FilterState {
pub active: bool, // 过滤输入是否激活
pub input: TextInput, // 过滤文本
pub scope: FilterScope, // Global / SessionMessages
}
  • / 激活过滤输入
  • 按 Enter 清除过滤
  • 按 Esc 清除并退出
  • 过滤作用于当前页面的所有列表项

5.6 应用切换 (SetAppType)

  • 顶部 Header 显示所有可见应用的 Tab
  • 切换时显示 loading projection
  • UiDataByAppCache 实现快速切换

5.7 Toast 通知

1
2
3
4
5
6
pub struct Toast {
pub message: String,
pub kind: ToastKind, // Info / Success / Warning / Error
pub remaining_ticks: u16, // 12 ticks (2.4s) 自动消失
pub persistent: bool, // 持久显示 (如登录过期)
}

渲染位置: 屏幕下方居中,带彩色边框

5.8 确认对话框

1
2
3
4
5
6
7
8
9
10
11
12
13
pub enum ConfirmAction {
Quit,
ProviderDelete { id },
McpDelete { id },
PromptDelete { id },
ConfigImport { path },
ConfigRestoreBackup { id },
ConfigReset,
SessionDelete { key, provider_id, session_id, source_path },
SkillsUninstall { directory },
ProviderApiFormatProxyNotice,
// ... 20+ 种
}
  • 通过 Overlay::Confirm(ConfirmOverlay) 显示
  • Y/N 确认

6. Overlay 系统

6.1 Overlay 枚举

Overlay 是覆盖在主 UI 之上的模态界面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
pub enum Overlay {
None,
Help(HelpState), // 上下文帮助
Confirm(ConfirmOverlay), // 确认对话框
TextInput(TextInputState), // 文本输入框
BackupPicker { selected: usize }, // 备份选择器
TextView(TextViewState), // 文本查看器
CommonSnippetPicker { selected: usize }, // 通用片段选择
ProviderTestMenu { provider_id, selected },// Provider 测试菜单
FailoverQueueManager { selected: usize }, // Failover 队列管理器
ClaudeModelPicker { selected, editing }, // Claude 模型选择
ClaudeApiFormatPicker { selected }, // API 格式选择
UsageQueryTemplatePicker { selected }, // 用量查询模板选择
ManagedAccountPicker { ... }, // 托管账号选择
ManagedAccountActionPicker { ... }, // 托管账号操作选择
HermesModelsPicker { editing }, // Hermes 模型选择
ModelFetchPicker { ... }, // 模型抓取进度
OpenClawToolsProfilePicker, // OpenClaw 工具配置
OpenClawAgentsFallbackPicker { ... }, // OpenClaw 代理回退
McpAppsPicker { id, name, selected, apps },// MCP 客户端选择
VisibleAppsPicker { selected, apps }, // 可见应用选择
SkillsAppsPicker { ... }, // Skill 客户端选择
SkillsImportPicker { ... }, // Skill 批量导入
SkillsSyncMethodPicker, // Skill 同步方式选择
McpEnvPicker, McpTypePicker, McpEnvEntryEditor,
Loading { kind, title, message }, // 加载指示器
SpeedtestRunning { url }, // 速度测试运行中
SpeedtestResult { url, lines, scroll }, // 速度测试完成
StreamCheckRunning { provider_id, name }, // 流检查运行中
StreamCheckResult { ... }, // 流检查完成
UpdateAvailable { current, latest, selected },
UpdateDownloading { downloaded, total }, // 更新下载中
UpdateResult { success, message }, // 更新结果
}

6.2 Overlay 方法

方法说明
is_active()是否有任何 Overlay 打开
can_be_covered_by_help()是否可被帮助覆盖 (不关闭现有 Overlay)
is_editing()是否正在接受文本输入 (阻断 Vim 导航)

6.3 Overlay 层级

1
2
3
4
5
6
主 UI
├─ Header (3行)
├─ Nav + Content (动态)
├─ Footer (1行)
├─ Toast (浮动居中)
└─ Overlay (全屏 Clear 覆盖)

Toast 渲染优先级可在 Overlay 之前或之后 (持久 Toast + 确认登录场景例外)。

6.4 文本输入 Overlay

1
2
3
4
5
6
7
pub struct TextInputState {
pub title: String,
pub prompt: String,
pub input: TextInput,
pub submit: TextSubmit, // 提交动作类型
pub secret: bool, // 隐藏输入
}

TextSubmit 决定提交后触发的 Action: - ConfigExport, ConfigImport, ConfigBackupName - SettingsProxyListenAddress, SettingsProxyListenPort - SkillsInstallSpec, SkillsDiscoverQuery, SkillsRepoAdd - UsageCustomRange, WebDavJianguoyunUsername/Password - 等 20+ 种


7. 表单系统

7.1 表单类型

1
2
3
4
5
pub enum FormState {
ProviderAdd(ProviderAddFormState), // 添加/编辑 Provider
McpAdd(McpAddFormState), // 添加/编辑 MCP 服务器
PromptMeta(PromptMetaFormState), // Prompt 元数据编辑
}

7.2 表单状态

1
2
3
4
5
6
7
8
9
10
11
pub enum FormMode {
Add,
Edit { id: String },
}

pub enum FormFocus {
Templates, // 模板选择
Fields, // 字段填写
JsonPreview, // JSON 预览
Content, // 内容编辑
}

7.3 Provider 表单

子页面 (ProviderFormPage): | 页面 | 说明 | |——|——| | Main | 主表单 (供应商模板 → 字段 → 预览) | | CodexLocalRouting | Codex 本地路由配置 | | CodexModelCatalog | Codex 模型目录映射 | | UsageQuery | 用量查询配置 |

表单字段 (ProviderAddField, 30+ 字段):

字段类型适用 App
IdTextInput所有
NameTextInput所有
WebsiteUrlTextInput所有
NotesTextInput所有
BaseUrlTextInput所有 (按 app 变体)
ApiKeyTextInput所有 (按 app 变体)
ApiFormatPickerClaude / Codex
ModelConfigPickerClaude
ModelTextInputCodex
LocalRoutingToggleCodex
OAuthAccountPickerCodex
AuthTypePickerGemini
ModelsPicker + EditorHermes / OpenClaw
ApiModePickerHermes
RateLimitDelayTextInputHermes
NpmPackagePickerOpenCode
UserAgentToggleOpenClaw
ApiProtocolPickerOpenClaw
CommonSnippetTextInput所有 (通用片段)
UsageQueryToggle所有
HideAttributionToggleClaude

模板系统: 预设模板自动填入常见供应商的 URL、模型、API Key 格式等

7.4 MCP 表单

字段 (McpAddField): | 字段 | 类型 | |——|——| | Id | TextInput | | Name | TextInput | | Type | Picker (stdio/http/sse) | | Command | TextInput (stdio) | | Args | TextInput (stdio) | | Url | TextInput (http/sse) | | Env | 键值对编辑器 | | Apps | 多选 (Claude/Codex/Gemini/OpenCode/Hermes) |

7.5 Prompt 表单

字段 (PromptMetaField): | 字段 | 类型 | |——|——| | Id | TextInput | | Name | TextInput | | Description | TextInput | | Content | EditorState (全屏编辑器) |


8. 编辑器系统

8.1 EditorState

1
2
3
4
5
6
pub struct EditorState {
pub content: String,
pub cursor: usize,
pub kind: EditorKind,
pub mode: EditorMode,
}

8.2 行编辑器 (TextInput)

内联行编辑,支持 readline 风格快捷键:

快捷键操作
Ctrl+A行首
Ctrl+E行尾
Ctrl+B左移
Ctrl+F右移
Ctrl+D前删字符
Ctrl+K删到行尾
Ctrl+U删到行首
Ctrl+W前删单词
Alt+B左移单词
Alt+F右移单词
Backspace前删单词 (Alt 时)
Ctrl+HMac 兼容 → 等价 Backspace

支持策略: TextInputPolicy { max_chars, sanitize }

8.3 全屏编辑器

在表单中用于 Prompt 内容等长文本编辑,提供标准光标和文本操作。


9. 主题系统

9.1 主题结构

1
2
3
4
5
6
7
8
9
10
11
pub struct Theme {
pub accent: Color, // 应用相关强调色
pub ok: Color, // 成功 (绿 #50fa7b)
pub warn: Color, // 警告 (黄 #f1fa8c)
pub err: Color, // 错误 (红 #ff5555)
pub dim: Color, // 暗淡 (灰 #6272a4)
pub comment: Color, // 注释文本
pub cyan: Color, // 高亮值 (青 #8be9fd)
pub surface: Color, // 背景面 (深灰 #44475a)
pub no_color: bool,
}

9.2 应用强调色

App颜色Dracula RGB
Codex绿色(80, 250, 123)
Claude青色(139, 233, 253)
Gemini粉色(255, 121, 198)
OpenCode橙色(255, 184, 108)
Hermes黄色(241, 250, 140)
OpenClaw珊瑚红(255, 79, 64)

9.3 颜色模式

模式检测条件
NoColorNO_COLOR 环境变量存在
TrueColorCOLORTERM/TERM 含 truecolor/24bit,或未知能力
Ansi256TERM_PROGRAM=Apple_Terminal 或 SSH + plain xterm
CC_SWITCH_COLOR_MODE环境变量强制覆盖 (none/rgb/ansi256)

9.4 选择器样式

  • NoColor 模式: 反转视频 (reverse-video)
  • TrueColor/Ansi256: 强调色背景 + 白字

10. Worker 系统

10.1 后台 Worker

所有耗时 I/O 操作通过 mpsc channel 异步执行,不阻塞渲染循环:

Worker请求类型用途
app_dataAppDataReqProvider/Config/MCP/Prompt/Skills/Proxy 数据加载
usage_pricingUsagePricingReq用量统计 + 定价数据
sessionsSessionReq会话扫描/消息加载
proxyProxyReq代理启动/停止/状态
speedtestProvider 速度测试
stream_checkStreamCheckReqProvider 流检查
quotaQuotaReq配额刷新
skillsSkillsReqSkills 安装/卸载/同步/发现
webdavWebDevReqWebDAV 上传/下载/连接测试
updateUpdateReq版本检查/更新
model_fetchModelFetchReq远程模型列表抓取
managed_authManagedAuthReqCodex OAuth 设备码登录
local_envLocalEnvReq本地环境检查

10.2 Worker 消息流

1
2
3
4
5
6
7
UI 层                    Worker                    后端
│ │ │
├─ send(Req) ──────────→ ├─ 执行 I/O ────────────→ │
│ │ │
│←── recv(Msg) ─────────┤←── 返回结果 ────────────┤
│ │ │
├─ 更新 UiData/App 状态 │ │

10.3 App Data 加载

三种加载模式 (AppDataLoadKind): - Initial — 首次加载,全量 - Full — 全量刷新 - Snapshot — 快速快照 (应用切换时)

按 AppType 缓存 (UiDataByAppCache: HashMap<AppType, (AppData, ReloadToken)>)


11. 关键数据结构参考

11.1 App 主状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pub struct App {
pub app_type: AppType,
pub route: Route,
pub route_stack: Vec<Route>,
pub focus: Focus,
pub nav_idx: usize,
pub filter: FilterState,
pub editor: Option<EditorState>,
pub form: Option<FormState>,
pub pending_overlay: Option<Overlay>,
pub overlay: Overlay,
pub toast: Option<Toast>,
pub should_quit: bool,
pub last_size: Size,
pub tick: u64,
// 代理可视化
pub proxy_visual_state: Option<bool>,
pub proxy_visual_transition: Option<ProxyVisualTransition>,
pub proxy_input_activity_samples: Vec<u64>,
pub proxy_output_activity_samples: Vec<u64>,
// 业务选择器
pub provider_idx: usize,
pub mcp_idx: usize,
pub prompt_idx: usize,
pub skills_idx: usize,
pub usage: UsageState,
pub sessions: SessionsState,
// ... 30+ 其他字段
}

11.2 Action 枚举 (80+ 变体)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pub enum Action {
None,
ReloadData,
SwitchRoute(Route),
Quit,
SetAppType(AppType),
// Provider
ProviderSwitch { id },
ProviderDelete { id },
ProviderSpeedtest { url },
ProviderStreamCheck { id },
ProviderSetFailoverQueue { id, enabled },
ProviderModelFetch { base_url, api_key, ... },
// Usage
UsageCustomRange { range },
PricingDelete { model_id },
// Sessions
SessionsRefresh,
SessionMessagesLoad { key, provider_id, source_path },
SessionResume { command, cwd },
SessionDelete { key, provider_id, session_id, source_path },
// Skills
SkillsToggle { directory, enabled },
SkillsInstall { spec },
SkillsUninstall { directory },
SkillsSync { app },
SkillsDiscover { query },
// MCP / Prompt / Config / Settings / Proxy / ...
}

11.3 数据加载函数参考

函数模块返回
UiData::load()data.rs完整 UiData
UiData::load_fast_snapshot_from_state()data.rs快照 UiData
load_providers_with_mode()data.rsProvidersSnapshot
load_mcp()data.rsMcpSnapshot
load_prompts()data.rsPromptsSnapshot
load_config_snapshot()data.rsConfigSnapshot
load_usage_snapshot_for_range()data.rsUsageSnapshot
load_model_pricing_snapshot()data.rsModelPricingSnapshot
load_skills_snapshot()data.rsSkillsSnapshot
load_proxy_snapshot_from_state()data.rsProxySnapshot