feat: terminal per-command blocks with hover add-to-conversation - #421
Open
havoc-rao wants to merge 2 commits into
Open
feat: terminal per-command blocks with hover add-to-conversation#421havoc-rao wants to merge 2 commits into
havoc-rao wants to merge 2 commits into
Conversation
- terminal-blocks.ts: pure block framework — the input stream (Enter in onData) segments the xterm buffer into per-command blocks (cleaned command + echo row anchor + output span), with wrap-aware plain-text extraction, pending-echo peeling, selection attribution and the fenced insert payload builder (mirrors selection-payload.ts). - TerminalView: ports the TextEditor "add to conversation" capability — an xterm selection raises the same floating popup (anchored at the .xterm-selection DOM rects), and a top-right pill offers the current block (last command + output) as one insertable unit; both go through appendToDraft. - tabs.tsx: terminal descriptor now passes ctx to TerminalView. - tests: 21 unit tests for the framework; design doc.
- TerminalBlockOverlay: hairline dividers at every CLI block boundary, hover span highlight + per-block 'add to conversation' pill at the hovered row; geometry from .xterm-screen rect + buffer row math (renderer-independent), self-ticking via rAF on scroll/write/resize, hover from host mousemove. - terminal-blocks: blocks pin their echo row with an xterm marker (tracker onSubmit hook; marker slides with trims/reflows, disposed marker = block gone); blockStartLine/blockEndLine/blockSpanLines resolve marker-aware spans for extraction, attribution and the layer. - TerminalView: session state drives the overlay; block commit resolves marker-aware boundaries; old pinned top-right pill removed (hover pill replaces it). - tests: marker-aware span/extraction/attribution + tracker onSubmit + overlay behavior (dividers, hover pill, commit, clear); design doc v2.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
终端是一条连续滚动流,无法把「某条命令 + 它的输出」作为一个整体引用。文本/代码 viewer 已有「添加到对话框」能力(TextEditor 选区浮钮 →
appendToDraft),终端完全缺失同款能力;xterm 自身也没有任何块级语义(无命令边界、无聚合提取、无稳定锚点)。Fix
src/client/terminal-blocks.ts(纯逻辑,随终端懒加载 chunk 分发,不进核心 bundle):TerminalBlockTracker:以输入流为界切分 block——onData 逐字符状态机清洗(CSI/OSC/粘贴标记/退格,裸回车不产生空块),Enter 提交命令并锚定 shell echo 行;onSubmit回调供视图钉锚点。term.registerMarker(0)(cursor 行 = echo 行)钉住每个 block 的边界——marker 随 scrollback trim / reflow 平移、滚出 buffer 自动 dispose;blockStartLine / blockEndLine / blockSpanLines统一走 marker 解析,disposed marker 解析为 +Infinity(行已消失 = block 整体不可见)。blockOutputText:纯文本提取(跳过 echo 行、折行还原、剥尾部空行与半条 pending 命令),marker 解析边界。buildTerminalInsert/blockForSelection:fence payload(info 行$ <command>、4000 字符截断 +\n…)与选区 → block 归属。src/client/TerminalBlockOverlay.tsx:视觉 block 层——每次 CLI 执行以 echo 行为界画 hairline 分隔线;悬停某 block → 行区间淡色高亮 + 悬停行右侧浮出「添加到对话」药丸(有文本选区时让位给选区 popup);几何 =.xterm-screenrect +(row - viewportY) × cellH(不依赖渲染器内部行元素),rAF 合并 tick(scroll / write-parsed / resize + ResizeObserver)自驱重绘,alt buffer 时整层让位;点击经appendToDraft整块插入对话草稿,复用既有addToConversationi18n key(19 语言零新增)。src/client/TerminalView.tsx/builtins/tabs.tsx/sidebar.module.css:会话 state 驱动 overlay 挂载;提交时 marker 解析边界;替换掉旧的右上角常驻药丸;.terminal增加定位上下文 + 层/分隔线/高亮/药丸样式(全 token 驱动)。Regression guard
tests/terminal-blocks.spec.ts(27 例):清洗状态机、提交/闭合/裸回车/多行粘贴/上限裁剪 + marker 解析(trim 漂移归属、disposed → +Infinity 不可见、cap 时 dispose 被丢弃 block 的 marker)、提取、归属、payload 形状。tests/terminal-block-overlay.spec.tsx(4 例,jsdom + mock rect + 队列化 rAF):每 block 一条分隔线、hover 高亮 + 药丸点击提交正确的 block、mouseleave 清除、!visible零渲染。blockForSelection按marker.line而非起始索引)、disposed marker 不可见(blockStartLine返回 +Infinity)、分割线数量。Verification
pnpm typecheck✅ /pnpm build✅(lib/client-terminal.js545KB,含新代码)/check:consumer-types✅agent-pty/smoke26 例posix_spawnp failed——沙箱禁止 node-pty 拉起真实 shell,git stash后在干净基线上同样复现(与本次改动无关)plugin-mountjob)覆盖终端懒加载 chunk 路径;本机沙箱无法起真实dsh web,未本地跑关联
docs/plans/2026-08-27-terminal-blocks-design.md(决策记录、marker 锚点、hover overlay 设计)feat/terminal-blocks(920549f+d976952两笔提交)