Files
u-tabs/docs/2026-05-16-备忘录-历史会话功能.md
绝尘 a027fe1703 新增: u-tabs 初始版本
Go TUI 项目启动器,基于 bubbletea v2 + lipgloss v2。
支持分组 Tab、多选启动、编号跳转、Windows Terminal 集成。
2026-05-16 21:01:03 +08:00

246 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# u-tabs 历史会话功能 — 需求备忘录
> 日期: 2026-05-16 | 状态: 分析完成
---
## 1. 需求概述
在 u-tabs 最后一个 Tab 新增「历史会话」功能,浏览和管理 Claude Code 所有项目的历史会话记录。
## 2. 核心需求
### 2.1 新增 HISTORY Tab
- 作为最后一个 Tab 追加到现有 Tab 栏CORE / LAB / TOOLS / ME / **HISTORY**
- 切换到该 Tab 时展示三栏布局(其他 Tab 保持原有两栏不变)
### 2.2 三栏布局
```
┌──────────────┬────────────────────┬──────────────────────────┐
│ 项目目录 │ 会话列表 │ 会话详情 │
│ │ │ │
│ ▸ E:/wk-flux │ ▸ 05-16 01:27 │ 标题: 龙享花API对接 │
│ E:/wk-lab │ 05-15 23:01 │ 时间: 05-16 01:27 │
│ E:/wk-oth │ 05-14 15:30 │ 目录: E:/wk-flux │
│ E:/wk-abc │ │ 消息: 94条 │
│ ... │ │ 摘要: 整理龙享花平台API │
│ │ │ 文档并编写测试代码... │
└──────────────┴────────────────────┴──────────────────────────┘
```
| 栏位 | 内容 | 交互 |
|------|------|------|
| 左栏 | 按 `cwd` 分组的项目目录列表 | 上下键切换目录 |
| 中栏 | 当前目录下的会话列表(时间+标题) | 上下键切换会话 |
| 右栏 | 选中会话的详情(标题/时间/消息数/AI摘要 | 只读展示 |
### 2.3 恢复会话
-`Enter` 在对应项目目录下执行 `claude -r <session-id>` 恢复会话
- 通过 `wt.exe` 打开新 Tab 执行(与现有启动逻辑一致)
### 2.4 AI 摘要生成
- 会话标题和摘要通过 AI 分析生成(`claude -p` 非交互模式)
- 生成结果缓存到本地(`~/.u-tabs/session-cache.json`),避免重复分析
- 分层策略:
1. 优先用已有的 `awaySummary`Claude 自动生成的离开摘要)
2. 次选 `customTitle` + 首条用户消息 + 消息数
3. 用户按 `s` 键触发 AI 按需生成,结果缓存
---
## 3. 数据源分析
### 3.1 存储位置
```
~/.claude/projects/<编码目录>/<session-uuid>.jsonl
```
编码规则:`E:\wk-lab\u-tabs``E--wk-lab-u-tabs`
### 3.2 JSONL 关键 entry 类型
| type | 关键字段 | 用途 |
|------|----------|------|
| `custom-title` | `customTitle` | 会话标题 |
| `user` | `message.content` | 用户消息string 或 text block 数组) |
| `assistant` | `message.content` | 助手回复 |
| `system` (subtype=`away_summary`) | `content` | AI 自动生成的离开摘要 |
| 大多数 entry | `cwd`, `timestamp`, `sessionId`, `gitBranch` | 通用元数据 |
### 3.3 扫描策略
**流式扫描,不全量加载:**
- `bufio.Scanner` 逐行读取,`bytes.Contains` 预过滤避免无用 JSON 解析
- 超过 2000 行的文件提前终止(元数据通常在前 50-100 行)
- 缓存机制:`~/.u-tabs/session-cache.json` 记录每个 session 的 modTime + 元数据
- 只重新读取 modTime 变化的文件
- 后续启动从缓存加载,接近即时完成
---
## 4. 技术方案
### 4.1 现有代码结构
```
internal/
├── app.go # Model, Update, View, 启动逻辑 (405行)
├── workspace.go # Workspace/Group 结构体, 运行时状态
├── config.go # YAML 配置加载
└── style/style.go # Tokyo Night 样式
```
### 4.2 文件变更清单
| 文件 | 操作 | 职责 |
|------|------|------|
| `internal/history.go` | **新建** | Session/ProjectDir/HistoryState 结构体、JSONL 扫描器、缓存、三栏渲染、按键处理、会话恢复 |
| `internal/app.go` | **修改** | Model 增加 `history` 字段、Update/View 分支 HISTORY 逻辑、Tab 栏追加 HISTORY、ScanCompleteMsg 处理 |
| `internal/style/style.go` | **修改** | GroupStyles 增加 HISTORY、会话列表/详情专用样式 |
| `internal/workspace.go` | 不变 | — |
| `internal/config.go` | 不变 | — |
| `main.go` | 不变 | — |
### 4.3 核心结构体
```go
// Session — 单个会话的元数据
type Session struct {
ID string // UUID (文件名)
CustomTitle string // customTitle 字段
Cwd string // 实际工作目录
StartTime time.Time // 首条 timestamp
EndTime time.Time // 末条 timestamp
MsgCount int // user + assistant 行数
FirstMsg string // 首条用户消息 (截断)
AwaySummary string // away_summary 系统摘要
}
// ProjectDir — 按目录分组的会话
type ProjectDir struct {
Dir string // 完整路径
Sessions []*Session // 按时间倒序
}
// HistoryState — HISTORY Tab 视图状态
type HistoryState struct {
Projects []*ProjectDir
DirCursor int // 左栏光标
SessCursor int // 中栏光标
FocusPanel int // 0=左栏 1=中栏
Loaded bool
Scanning bool
}
```
### 4.4 Model 修改
```go
type Model struct {
// ... 现有字段不变 ...
history HistoryState // 新增HISTORY Tab 状态
}
```
HISTORY Tab 判断:`m.activeGroup == len(Groups)`(最后一个位置)。
### 4.5 Tab 切换改动
- 现有:`% len(Groups)` 循环
- 改为:`% (len(Groups) + 1)` 包含 HISTORY
- 新增 `5` 键直接跳转 HISTORY
### 4.6 三栏渲染
```
可用宽度 = terminal width - 2 (分隔符)
左栏 (目录): 20% 宽度, 最小 20 字符
中栏 (会话): 40% 宽度, 最小 30 字符
右栏 (详情): 剩余宽度, 最小 30 字符
```
### 4.7 异步扫描
```go
type ScanCompleteMsg struct {
Projects []*ProjectDir
}
// 首次进入 HISTORY Tab 时触发
func ScanSessionsCmd() tea.Cmd {
return func() tea.Msg {
return ScanCompleteMsg{Projects: scanAllProjects()}
}
}
```
扫描期间显示 "scanning..." 占位。
### 4.8 会话恢复
复用现有 `encodePSCommand` + `wt.exe` 模式,改用 `claude -r <session-id>`:
```go
func resumeSession(s *Session) {
script := fmt.Sprintf(`cd "%s"; claude -r %s`, s.Cwd, s.ID)
encoded := encodePSCommand(script)
exec.Command("wt.exe", "-w", "0", "-d", s.Cwd,
"--tabColor", randomColor,
"pwsh", "-NoExit", "-EncodedCommand", encoded).Start()
}
```
### 4.9 HISTORY Tab 按键
| 键 | 动作 |
|----|------|
| `j`/`down` | 当前面板光标下移 |
| `k`/`up` | 当前面板光标上移 |
| `tab`/`right`/`l` | 焦点切到中栏 |
| `shift+tab`/`left`/`h` | 焦点切到左栏 |
| `enter` | 恢复选中会话 |
| `s` | AI 生成摘要(按需) |
| `5` | 从其他 Tab 跳转到 HISTORY |
| `q`/`ctrl+c` | 退出 |
---
## 5. 实现阶段
| 阶段 | 内容 | 涉及文件 |
|------|------|----------|
| P1 数据层 | Session 结构体 + JSONL 流式扫描器 + 缓存 | `history.go` |
| P2 集成 | Model 扩展 + Update 分支 + Tab 栏扩展 | `app.go` |
| P3 渲染 | 三栏布局 + 目录/会话/详情面板 | `history.go` |
| P4 动作 | 会话恢复 + AI 摘要按需生成 | `history.go`, `app.go` |
| P5 样式 | HISTORY Tab 样式 + 会话专用样式 | `style.go` |
---
## 6. 风险与对策
| 风险 | 对策 |
|------|------|
| 大文件 (1MB+) 扫描慢 | 流式扫描 + 2000 行截断 + modTime 缓存 |
| 项目目录过多 | 左栏滚动显示,按最近活跃排序 |
| `claude -p` 生成摘要慢 | 按需触发(`s` 键),非自动;结果缓存 |
| 窄终端三栏挤压 | 定义面板最小宽度,不足时降级为两栏 |
---
## 7. 验证标准
1. HISTORY Tab 出现在 Tab 栏末尾,样式与其他 Tab 一致
2. 左栏列出所有有会话的项目目录,按路径排序
3. 选中目录后中栏显示该目录下所有会话,按时间倒序
4. 选中会话后右栏显示完整详情
5. `Enter` 键在正确目录下通过 `wt.exe` 恢复会话
6. `s` 键触发 AI 摘要生成,结果写入缓存
7. 其他 Tab 功能不受影响
8. 首次进入扫描显示 loading二次进入从缓存加载