246 lines
8.1 KiB
Markdown
246 lines
8.1 KiB
Markdown
# 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,二次进入从缓存加载
|