@memef1f1y/opencode-timeline-plugin
v0.1.4
Published
Conversation history node viewer for the OpenCode TUI (sidebar timeline)
Maintainers
Readme
opencode-timeline-plugin
OpenCode TUI 对话历史导航:在侧边栏以时间线列出当前会话的用户消息,最新在最上,点击直达主视图对应位置(对标原生 /timeline)。
技术栈:TypeScript + Solid + OpenTUI,运行于 OpenCode TUI 插件宿主(
@opencode-ai/plugin/tui)。
功能
- 侧边栏时间线:
[角色图标] 摘要(30字符截断) HH:MM,只收录用户消息(assistant / tool 噪音已过滤),最新在最上 - 点击某行:选中 + 主会话视图滚动到该消息(复刻原生
/timeline:官方scrollToMessage优先,渲染树 best-effort 兜底) ⤓ 回到底部:主会话视图一键滚回最新处- 显示层 render 期间直读
api.state(与原生 Context/MCP/LSP 区块同款宿主订阅),进会话自动刷新,无需手动操作 - 上次选中经
api.kv持久化,重启可恢复
| 操作 | 效果 |
| ---- | ---- |
| 点击行 | 选中 + 跳转到该消息 |
| ⤓ 回到底部 | 主会话视图滚到最新处 |
| Alt+U(Windows/Linux)/ Ctrl+T(macOS) | 显示 / 隐藏面板 |
| ← / → | 收起 / 展开列表(等价于点击标题栏) |
安装
opencode plugin @memef1f1y/opencode-timeline-plugin@latest重启 opencode TUI 即可(不要加 --pure,那会禁用外部插件)。
本地开发版(改完即用,不用发包):
git clone https://github.com/1624318455/opencode-timeline-plugin.git
cd opencode-timeline-plugin
npm install然后在 tui.json 里用文件路径引用(见下)。
配置
~/.config/opencode/tui.json(全局,所有项目共用)或 <你的项目>/.opencode/tui.json(仅单个项目):
{
"$schema": "https://opencode.ai/tui.json",
"plugin": [
// npm 包写法(推荐)
["@memef1f1y/opencode-timeline-plugin@latest", { "maxItems": 50 }],
// 本地文件写法(开发调试,路径必须是绝对路径)
// ["/绝对路径/opencode-timeline-plugin/src/panel.tsx", { "maxItems": 50 }]
],
// 按插件 id 开关,默认全启用。关闭本插件:
// "plugin_enabled": { "timeline.viewer": false }
}| 参数 | 含义 | 默认 |
| ---- | ---- | ---- |
| maxItems | 列表最多显示的用户消息数,超出的旧消息收起并计数 | 50 |
| debug | 在面板顶部多渲染一行诊断快照(排查用) | 关闭 |
本仓库自带的
tui.json只是本地调试示例,OpenCode 不会读它。
使用
opencode启动 TUI 并进入一个会话,侧边栏出现Timeline面板。- 鼠标点击某行跳转到主视图对应消息;点
⤓ 回到底部回到最新处;Alt+U(macOS 用Ctrl+T)显示/隐藏;←/→收起/展开列表。 - 发一条新消息,列表自动置顶(最新在最上)。
macOS 说明
Alt+U默认按不出来:macOS 终端下Option+U输出¨而非ESC u(除非终端开了 Option as Meta),所以 Mac 请用Ctrl+T开关面板(Windows/Linux 继续用Alt+U,两者同时注册)。- 点不了标题/行:macOS 自带 Terminal.app 不支持鼠标上报;iTerm2 需在设置里开启鼠标报告(Preferences → Profiles → Terminal → Enable mouse reporting);VSCode 集成终端一般可用。鼠标不可用时,所有操作都有键盘等价:
←/→展开收起、↑/↓移动、Enter跳转、Esc关闭——先让输入框失焦(按Esc)再按这些键。 - 列表不实时刷新:先把
tui.json里该插件的 options 加上"debug": true重启,看诊断行total/user/kept是否在涨:total涨而kept为 0 说明宿主给了数据但被过滤(提 issue 请贴这行);两者都不涨多为旧版本缓存,执行一次opencode plugin remove @memef1f1y/opencode-timeline-plugin && opencode plugin @memef1f1y/opencode-timeline-plugin@latest清掉~/.cache/opencode/packages里的旧快照。
环境要求
opencode >= 1.0(已验证1.18.30~1.18.32)- Node 18+,npm 9+(或 bun 1.0+)
- macOS / Linux / WSL 均可;Windows 原生终端注意
Alt+U可能被终端占用 - 鼠标点击需要终端开启鼠标支持(能点侧边栏标题折叠即正常);macOS 无鼠标时用
←/→/Ctrl+T全键盘操作(见上)
开发
git pull
npm install # 依赖有变化时才需要
npm run typecheck # 期望:无输出即通过
# 重启 opencode 即可(tui.json 改了也要重启,不热重载)排错 FAQ
| 现象 | 检查 |
| ---- | ---- |
| 面板没出现 | 包是否装上(opencode plugin 列表里有没有);文件写法下路径是否为绝对路径;启动日志有无 loading tui config / ERROR |
| 点击没反应 | 终端鼠标是否可用(macOS 见上);是否进了会话(home 页侧边栏没有 session 上下文);无鼠标时用 ↑/↓+Enter |
| 跳转提示无滚动 API | 会话太老的消息可能不在本地渲染树里(TUI 只加载最近约 20 条分页),先 ⤓ 回到底部 再试 |
| npm run build 失败 | 预期行为,当前只有 typecheck,build 是占位脚本 |
项目结构
├── package.json # exports["./tui"] 指向 ./src/panel.tsx
├── tsconfig.json # jsxImportSource @opentui/solid
├── tui.json # 本地调试示例(非真实配置)
└── src/
├── panel.tsx # 插件入口:slots.register(sidebar_content),只做接线
├── types.ts # TimelineNode / truncate / roleIcon / formatTime
├── components/
│ ├── TimelinePanel.tsx # 面板:宿主跟踪读 + 标题 + 回到底部按钮
│ ├── Timeline.tsx # scrollbox 列表 + 选中自动滚入视口
│ └── NodeItem.tsx # 单节点行渲染 + 点击跳转
├── hooks/
│ ├── useMessages.ts # 快照/订阅/轮询/选中/跳转记账
│ ├── useKeybind.ts # Alt+U/Ctrl+T + ←/→ 图层注册与注销
│ └── useMouseTap.ts # down/up 双通道点按(macOS release-only 终端兜底)
└── api/
└── opencode.ts # state/event/kv/toast/跳转封装已知限制
- 跳转是 best-effort:优先官方
api.state.scrollToMessage(若宿主提供),否则走渲染树查找(findDescendantById→ 包围的 ScrollBox →scrollChildIntoView,等价原生scrollBy(child.y - scroll.y - 1)),再否则 toast + kv 兜底。TUI 本地只加载最近约 20 条分页,太老的消息可能无渲染节点(上游同款限制)。 - 键盘导航键(
↑/↓/Enter)在输入框聚焦时归编辑器,到不了侧边栏——这是宿主 keymap 焦点优先级,预期行为;主交互是鼠标点击。 - 树状视图:
TimelineNode.parentId/children已预留字段,UI 仍为线性。
