# OpenClaw TUI 配置交互设计规范

## 目的

这份文档沉淀本次 OpenClaw TUI 配置页交互整理后的稳定规则，供后续修改 `环境变量`、`Workspace 文件管理`、`工具权限`、`Agents 配置` 以及相邻配置路由时复用。

目标只有两个：

1. 让页面上看到的交互形态和真实行为一致。
2. 把影响范围控制在当前路由内，避免顺手改坏别的编辑流程。

## 适用范围

当前优先适用于以下 OpenClaw TUI 配置路由：

- `环境变量`
- `Workspace 文件管理`
- `工具权限`
- `Agents 配置`

以及与这些配置状态直接相关的共享摘要区，例如顶栏右上角状态 badge。

在相邻配置页复用这些模式时，也应优先遵守这里的规则，除非该路由已经有更明确的既有约束。

## 核心原则

### 1. 交互类型要和控件外观一致

- 选择型字段用 picker，不要伪装成行内切换器。
- 文本或数值字段用 popup editor，不要看起来像可直接内联编辑。
- 列表项用明确的“编辑 / 删除 / 新增”语义，不要依赖占位空行或隐式模式切换。

### 2. 自动保存只在路由本地生效

- `工具权限` 和 `Agents 配置` 使用 route-local auto-save。
- picker 内移动选项不保存，只有确认才保存。
- popup editor 输入过程中不保存，只有确认才保存。
- 保存成功保持安静，不弹 success toast。
- 保存失败显示 error toast。

### 3. 不把“清空”藏进空输入提交

- 空提交默认是非破坏性的 no-op。
- 真正的清空动作必须显式触发。
- 对支持清空的行，统一使用 `Delete` 或 `Backspace`。

### 4. 影响范围要收紧

- 改 OpenClaw 配置路由时，不要顺带改共享编辑器的通用行为，也不要把某个路由的局部排版规则扩散到别的产品或全局配置页。
- 如果只是局部路由需要特殊交互，优先做 route-local 处理，不要扩散到全局编辑工作流。

### 5. 共享摘要区要服务于识别和判断

- 摘要区只展示用户当前能据此做判断的状态，不展示“技术上存在、语义上不成立”的占位字段。
- 能力缺失和功能关闭是两种不同语义。前者应隐藏或旁路，后者才显示关闭态。
- 摘要区可以保留稳定的主状态锚点，但这个锚点展示什么，要由当前 app 最核心的配置语义决定，不要机械复用统一 label。

## 具体交互规则

### Env 路由

#### 正文排版与可读性

- warning banner、顶部说明文案、环境变量列表之间要显式分层，不要直接贴在一起。
- 顶部说明文案使用弱化样式展示，只承担解释作用，不和变量值争抢视觉优先级。
- 环境变量列表按 `变量名  值` 的两列形态渲染，变量名列以当前页最长 key 为基准对齐。
- 被保护的值继续显示为 `[redacted]` 这类占位文案，不泄露真实内容。
- 保护值需要有独立强调样式，彩色模式下用 warning 语义，`NO_COLOR` 模式下至少保留粗体可见性。
- 空列表使用明确空状态文案，不回退到通用 `None`。

### Workspace 路由

#### 正文排版与可读性

- `Workspace directory` 作为顶部摘要单独展示，不和 `Workspace 文件` 列表混在同一个带标题区块里。
- `Workspace 文件` 和 `Daily Memory` 保持两个独立区块，文件区块是主交互块，视觉权重要高于附属信息块。
- 文件列表行按 `文件名  状态` 的两列形态渲染，状态列在已存在 / 缺失之间保持同一竖向起点。
- 当前选中行不再依赖字面 `>` 前缀，彩色模式使用选中样式，`NO_COLOR` 模式继续保留明确反转强调。
- 短视口下优先保证当前选中的文件行或 `Daily Memory` 摘要行仍可见，并把可用高度优先让给当前聚焦区块。
- 长路径、memory 目录、最新预览文本允许换行，但正文首个内容块不要在快捷键栏后留下无意义空白。

### Tools 路由

#### 权限档位

- 使用单行展示：`配置档位: <当前值>`。
- 不再在页面正文里常驻显示整条内联选项条。
- `Enter` 打开 picker。
- picker 只展示受支持的档位。
- 当前值如果是非标准保留值，可以继续显示在主页面，但 picker 不应伪造预选状态。

#### 允许列表 / 拒绝列表

- 规则分成独立的 `允许列表` 和 `拒绝列表` 小节。
- 现有规则行按真实列表项渲染。
- `Enter` 编辑当前规则。
- `Delete` 删除当前规则。
- `+ 添加允许规则` / `+ 添加拒绝规则` 作为显式新增入口。
- 新增和编辑都走 popup editor。
- 不允许插入空白占位行来启动编辑。
- 空白确认无效，popup 保持打开，直到输入非空值或用户取消。

#### 正文排版与可读性

- 顶部说明文案使用弱化样式展示，只承担解释作用，不和 profile 行或规则行争抢视觉优先级。
- `Profile` 和 `Rules` 继续拆成两个区块，但视觉层级要拉开，规则区块是主交互块，profile 区块保持弱化。
- 允许列表 / 拒绝列表标题、现有规则行、`+ 添加…规则` 行共享同一条值列起点，不额外制造二级缩进。
- 当前选中行不再依赖字面 `>` 前缀，彩色模式使用选中样式，`NO_COLOR` 模式继续保留明确反转强调。
- 长规则值允许在区块内换行，但换行后仍要保持选中态可辨识。
- 短视口下要优先保证当前选中的 profile 行或规则行仍可见。

### Agents 路由

#### 模型配置

- `默认模型` 使用单行展示：`默认模型: <当前值>`。
- 每个回退模型使用单行展示：`回退模型: <当前值>`。
- `+ 添加回退模型` 保持显式新增入口。
- `Enter` 在默认模型、现有回退模型、添加回退模型这三类行上都走 picker。
- 现有回退模型的 picker 需要排除主模型和其他已选回退模型，但保留当前行自己的值，方便重开后直接取消。
- 不再允许模型行用 `Enter` 做循环切换。

#### 运行参数

- 四个字段统一渲染为 `标签: [值]`：
  - `工作区路径: [<value>]`
  - `超时时间（秒）: [<value>]`
  - `上下文 Token 数: [<value>]`
  - `最大并发数: [<value>]`
- 方括号值区是必需的，它用来强调“这是字段值”，不是普通尾随文本。
- `Enter` 打开 popup editor。
- `Delete` / `Backspace` 显式清空当前字段。

#### 正文排版与可读性

- `Agents 配置` 正文继续保留 `模型配置` 和 `运行参数` 两个区块，不额外插入摘要区或第三个主区块。
- 顶部说明文案使用弱化样式展示，并在第一个区块前保留一行明确的空白间隔，避免说明和字段挤在一起。
- 内层区块边框和标题要弱于外层主面板，不要和外围内容框争抢注意力。
- 字段标签在固定标签列内左对齐，不要为了“排整齐”把标签整体推得太靠右。
- 值列必须跨 `默认模型`、`回退模型`、运行参数行、`+ 添加回退模型` 保持同一条竖向起点。
- 字段行前导留白保持紧凑，当前基线是首字距区块左边框 2 列，只留出焦点强调线和最小呼吸感。
- 选中态不再依赖字面 `>` 前缀。彩色模式使用浅背景加左侧细强调线，`NO_COLOR` 模式继续使用可见的反转强调。
- 不在目录里的模型值继续保留 `value (供应商未配置)` 这种可见文案形态，只通过样式弱化尾随状态，不改写成新的文本结构。

### 顶栏摘要状态

#### 能力优先于占位

- 如果某个状态对当前 app 不适用，顶栏摘要不应通过 `开 / 关`、`有 / 无` 这类占位词假装它仍然成立。
- 是否展示某个 badge，应以真实能力判断为准，不要把 unsupported 语义折叠成默认值。

#### 主摘要要表达当前 app 的核心配置轴

- 最右侧主状态 badge 继续保留，因为它承担“当前 app 正处于什么状态”的快速摘要职责。
- 这个主摘要不要求所有 app 使用同一字段。哪个字段最能帮助用户快速判断配置是否正确，就应优先显示哪个字段。
- 统一性来自布局、层级和语气，不来自强迫所有 app 共用同一个 label。

#### 状态优先级

- 摘要区应优先暴露用户最需要立即注意的信息，通常遵循 `错误 > 未设置 > 当前有效值` 这类顺序。
- 当某个值来自用户配置本身时，展示阶段应尽量保留原始语义，不要为了“排整齐”偷偷改写内容。

#### 宽度退化策略

- 宽度不足时，先牺牲次要摘要，再压缩中间 tabs，最后才让主状态摘要进入 best-effort 截断。
- 只有在极窄视口下，才允许主摘要跟随现有截断逻辑一起退化，不为此单独重做 header 布局。

## 显式清空与保留值规则

### 默认模型

- `默认模型` 必须有显式 unset 路径。
- 这条路径不依赖打开 picker。
- 在默认模型行按 `Delete` 或 `Backspace` 时，应通过现有 auto-save 路径清空值。

### 保留的非字符串运行时值

- 如果运行时字段来自旧配置或非标准类型，主页面可以保留展示，避免偷偷吞掉用户数据。
- 但用户必须仍然有办法主动清空它。
- 清空字段时，不只要清空当前可见字符串，还要清掉对应的 preserved seed。
- 清空 `超时时间（秒）` 时，还要一并清掉 route-local legacy-timeout 状态，避免用户已经清空后，旧提示还残留。
- runtime popup 在空字符串或全空白确认时，必须保持 non-destructive。

## 视口与可见性规则

- 当 `Workspace 文件管理`、`工具权限` 或 `Agents 配置` 内容超过可视区域时，当前选中行必须保持可见。
- 这类滚动行为优先使用 derived viewport，不新增持久 scroll state，除非已经证明做不到。
- 重点保证以下行在短终端里仍可见：
  - Workspace 的当前选中文件行
  - Workspace 的 `Daily Memory` 摘要行
  - Tools 的 allow / deny 规则行
  - Tools 的 profile 行
  - Agents 的 `默认模型`
  - Agents 的回退模型行
  - Agents 的 `+ 添加回退模型`
  - Agents 的运行时参数行
- 包含说明文字、warning、preserved note 的块可以继续换行，但不能把当前选中交互行挤出视口。

## 可见文案与快捷键规则

- 对启用 route-local auto-save 的 `工具权限` 和 `Agents 配置`，不显示保存按钮。
- 这两个路由也不显示 `Ctrl+S` 保存提示。
- 不要在这两个路由上保留无效的 `Ctrl+S` 交互暗示。
- 相邻仍采用显式保存模式的路由，继续保留它们自己的保存提示，不受这里影响。

## 实现约束

- 优先少写代码、少加抽象、少引入跨文件耦合。
- 如果现有 route-local 逻辑已经能承载新交互，优先沿用，不要为了“统一”而重写共享编辑系统。
- 如果后端行为直接借鉴上游 `cc-switch`，尽量保持行为与命名一致；仓库特有适配逻辑优先旁路拆出。

## 验证要求

每次调整这套交互时，至少要覆盖下面几类验证：

- 焦点交互测试：picker、popup editor、删除、显式清空、新增规则、删除规则。
- 渲染测试：`环境变量` 的 warning / 说明 / 列表分层、key/value 两列对齐、保护值强调和显式空状态；`Workspace 文件管理` 的目录摘要、文件状态列对齐、短视口优先级和无字面 `>` 前缀焦点；`工具权限` 的分层区块、规则列对齐、短视口可见性和无字面 `>` 前缀焦点；`Agents 配置` 的 `标签: [值]` 形态、标签左对齐和值列对齐。
- Header 测试：能力缺失不会被误渲染成关闭态，主摘要字段与当前 app 的核心配置语义一致，错误态与空态的优先级正确，窄宽度下主状态 badge 的优先级与截断行为保持稳定。
- 邻近回归测试：共享编辑器脏状态确认、显式保存路由的快捷键提示，以及不在本次 route-local 改动范围内的全局编辑行为。
- 格式检查：Rust 代码改动后跑 `cargo fmt --check`。

## 使用方式

- 改 OpenClaw 配置页交互前，先读这份文档，再看对应 spec / plan。
- 如果新需求和这份规范冲突，先在 spec 里明确为什么要偏离，再改实现。
- 如果某条规则已经被新设计替换，更新这份文档，不要让项目级入口挂着过时引用。
