---
url: /wave-agent/specs/editor/ide-context-mentions.md
description: >-
  输入框 @ 手动附加 IDE 运行时上下文：终端输出（@terminal）、当前文件问题（@problems），发送时取内容并入消息、渲染为用户气泡里的标签
  + 弹窗预览
---

# 功能规格说明：IDE 上下文提及

**创建日期**：2026-10-22

> **平台边界**：仅插件端（VS Code 扩展 / JetBrains 插件）。CLI、桌面端与远控页不提供这两个提及——它们没有插件端可读的数据源，`@` 下拉里不出现对应条目。

## 背景与取舍

agent 自己的 Bash 工具与用户的 IDE 终端是两个互不相通的进程：用户在终端里看到的启动失败、端口占用、依赖安装报错，agent 一条都看不到；编译器/检查器报错同理。要让 agent 收敛，只能由用户把文本复制过来。

本规格采用**用户 `@` 手动附加**的形态：

| 形态                   | 取舍                                                                                                           |
| ---------------------- | -------------------------------------------------------------------------------------------------------------- |
| `@` 手动附加（本规格） | 由用户决定附加哪一类上下文；无调用成本、无时序等待。Continue 的 `@terminal` / `@problems` 是同一形态的完整先例 |
| 模型主动调用工具       | Claude Code 的 `getDiagnostics` 属此类，但 Claude Code 两个插件都不读取用户终端，终端侧无先例                  |
| 每轮自动注入           | Roo Code 每轮把终端输出与增量诊断塞进 `environment_details`，token 成本无条件发生，且要等终端冷却              |

### 内容怎么进消息、怎么呈现

**内容在发送那一刻取一次，作为文本拼进用户消息正文；界面渲染为用户气泡里的标签，点标签在弹窗里看全文。** 由此带来三条硬性质：

1. **消息自包含**：历史重放不再读 IDE 状态，切会话/重开面板/换机器看到的都是当初发出去的那份文本。
2. **所见即所发**：用户点开标签就能看到 agent 到底拿到了什么，不是隐藏注入。
3. **组装只有一份**：宿主只负责"读数据"（两端的 IDE API 本就不同，这层重复无法避免），标题、上限、排序、清理转义这些格式逻辑放在共享 webview 里，不在 TS 与 Kotlin 各写一遍。

### 与参考实现的差异

* **内容进消息正文、点标签可见**：Continue 把 `@terminal` / `@problems` 留作文本标记，在请求时刻解析成上下文项，用户在对话里看不到具体内容。本规格改成发送时取内容并入消息，并在用户消息里以标签留存、点开弹窗看全文。
* **统一的终端范围**：Continue 自己两端不一致——VS Code 端取最后 1 条命令（`getTerminalContents(1)`），JetBrains 端读整个 buffer（history + screen）。本规格两端统一取「最后一条命令及其输出」。
* **补了上限与转义清理**：Continue 的两个 provider 都不做截断与 ANSI 清理（`compressTerminalOutput` 在 Roo Code 里，不在 Continue）。终端输出长度无上限，token 成本必须封顶。
* **`@problems` 用结构化定位而非内联源码**：Continue 每条给的是「±2 行源码 + message」，`getProblems` 的映射里丢掉了 severity、正文也不写行号（JetBrains 端反而过滤 ERROR/WARNING，两端同样不一致）。本规格给「行:列 + 严重级 + 消息」：wave 的 agent 有 Read 工具，拿定位能自己取源码，不必把源码搬进上下文。
* **不做调试上下文**：Continue 的 `@debugger` 在 JetBrains 侧三个方法均 `throw NotImplementedError`（该宿主从没实现过），只覆盖 VS Code 的已暂停会话，两端不对称；本轮两端都不做，见「非目标」。

## 用户场景与测试 *（必填）*

### 用户故事：附加终端输出（优先级：P1）

作为插件端用户，我希望把终端里最后一条命令的输出附加到消息里，以便我不用复制粘贴就能让 agent 看到那个只在我 shell 里出现的问题。

**为什么是这个优先级**：agent 无法通过运行命令重建用户终端的历史，这是唯一能把该信息交给它的通道。

**独立测试**：在 IDE 终端执行一条有输出的命令，输入 `@` 选中 `Terminal` 后发送，点开用户消息里的终端标签，验证弹窗中含该命令的命令行与输出。

**验收场景**：

1. **假设**存在活动终端且已执行过命令，**当**用户选中 `@terminal` 并发送时，**则**消息正文必须含该终端最后一条命令的命令行与其输出。
2. **假设**用户附加了 `@terminal` 之后又在终端里跑了一条新命令，**当**用户随后发送时，**则**取的是**发送时刻**的最后一条命令，而非附加时刻的。
3. **假设**终端输出包含 ANSI 颜色/控制转义或进度条重绘，**当**内容进入消息时，**则**必须清理控制字符，只留可读文本。
4. **假设**输出长度超过上限，**当**内容进入消息时，**则**只保留尾部，并在该块首行注明已截断。
5. **假设**没有任何终端，或活动终端没有任何输出，**当**用户发送时，**则**该块替换为一行明确的不可用说明（含原因），消息照常发送。
6. **假设**同一消息里用户附加了两次 `@terminal`，**当**发送时，**则**只取一份内容。

***

### 用户故事：附加当前文件的问题（优先级：P1）

作为插件端用户，我希望把当前文件的编译/检查报错附加到消息里，以便 agent 直接看到要修什么，而不是我逐条复制。

**为什么是这个优先级**：改完代码后确认"是否真的没错了"是最高频的动作，没有它每次都要人工搬运报错。

**独立测试**：在一个有错误的文件上打开编辑器，`@` 选中 `Problems` 后发送，点开用户消息里的问题标签，验证弹窗中列出该文件的错误条目（行:列 + 严重级 + 消息）。

**验收场景**：

1. **假设**活动编辑器所在文件有 ERROR/WARNING，**当**用户选中 `@problems` 并发送时，**则**消息正文必须含该文件的诊断条目，按行号顺序排列。
2. **假设**该文件没有任何诊断，**当**发送时，**则**块内写入明确的无问题说明，不是空块。
3. **假设**当前没有活动编辑器，**当**发送时，**则**块内写入不可用说明。
4. **假设**条目数超过上限，**当**发送时，**则**截断并在块首行报告总数与已列条数。
5. **假设**宿主读不到诊断（JetBrains 内部 API 在本版本不可用），**当**发送时，**则**块内写入明确失败原因，不抛异常、不中断发送。

***

### 用户故事：用户消息里的上下文标签（优先级：P1）

作为用户，我希望附加的 IDE 上下文在我自己那条消息里以标签形式留存，点开能在弹窗里看到完整内容，以便我知道这次到底把什么交给了 agent，同时不把聊天记录刷成一大段日志。

**为什么是这个优先级**：内容进了消息正文就必须能收起来，否则每次附加终端输出都会把对话顶出屏幕；同时"所见即所发"是这套能力的信任基础。

**独立测试**：发送一条带 `@terminal` 与 `@problems` 的消息，验证用户消息气泡里出现两个标签，分别点开后弹窗显示终端输出与诊断列表；重开面板后标签仍在，且不再访问 IDE。

**归属与形态**：

* **标签在用户消息气泡内**，排在用户输入的文字之后，与文件/选区/图片标签同一处、同一套观感（复用现有上下文标签组件）。
* 用户气泡里**只有标签、不放可展开的块**——可展开块是助手侧的范式（思考/工具），用户气泡遵循"附件清单 + 点击预览"，与图片标签一致。
* **点标签开弹窗预览**完整文本（复用现有图片预览那类全屏遮罩层），弹窗内容可选中复制，点遮罩或按 ESC 关闭。

**验收场景**：

1. **假设**消息含终端标签，**当**这条用户消息渲染时，**则**标签出现在**该用户消息气泡内**、用户文字之后，标签文案是英文名（见「条目文案」），与文件/选区标签同一套外观。
2. **假设**用户点击终端标签，**当**弹窗打开时，**则**弹窗标题是英文名、正文首行是块标题（两者不同名，避免同一个词出现两次），正文显示进入消息的完整文本，且该文本与 agent 实际收到的一致；文本可选中复制。
3. **假设**弹窗已打开，**当**用户点击遮罩或按 ESC 时，**则**弹窗关闭，消息本身不变。
4. **假设**同一条消息含两个标签，**当**用户点开其中一个时，**则**一次只显示一个弹窗。
5. **假设**该块内容被截断，**当**用户查看标签与弹窗时，**则**都能看到"已截断"的标注（标签上以角标/文案提示，弹窗内首行说明）。
6. **假设**宿主当时读不到数据，**当**渲染时，**则**标签照常出现（形态统一，不因失败换一种呈现），打开后弹窗内是那一行说明。
7. **假设**会话被重新加载，**当**消息历史重放时，**则**弹窗内文本来自消息本身，不产生任何 IDE 读取。
8. **假设**用户在发送前删掉了输入框里的标签，**当**发送时，**则**消息里不出现对应标签。
9. **假设**用户只用键盘，**当**焦点落在标签上时，**则**标签在 Tab 序内，Enter/Space 可打开弹窗，ESC 关闭后焦点回到该标签。

***

### 用户故事：`@` 下拉里混排固定条目与文件搜索（优先级：P1）

作为插件端用户，我希望 `@` 下拉同时能选文件、也能选这两类 IDE 上下文，且在没有 IDE 数据源的端不出现无效条目。

**为什么是这个优先级**：两个条目若各占一个独立入口（菜单、按钮），交互面会膨胀；并入现有 `@` 下拉是唯一不新增交互概念的做法。

**条目文案**：`@` 后面那个词（下拉条目名、输入框与消息气泡里的标签）用英文 `Terminal` / `Problems`——与 Cursor 的 `@Terminals`、TRAE 的 `#Problems` 同一形制，提及标记在所有产品里都保持英文名词。中文留在两处：条目下方的描述（"当前终端最后一条命令的输出"），以及消息正文里的块标题与说明行。

**独立测试**：输入 `@` 验证两个固定条目排在文件搜索结果之前；继续输入 `@ter` 验证只剩 `Terminal`（文件搜索同时照常过滤）；在桌面端与远控页输入 `@` 验证两个条目都不出现。

**验收场景**：

1. **假设**用户在插件端面板输入 `@`，**当**下拉展开时，**则**两个固定条目必须排在文件搜索结果之前。
2. **假设**用户继续输入过滤文本，**当**过滤文本匹配某固定条目的名称、描述或 id 时，**则**该条目保留；不匹配的固定条目收起，文件搜索结果不受影响。
3. **假设**用户选中某固定条目，**当**插入输入框时，**则**以原子标签形式呈现（不可在标签内编辑，退格整体删除），与文件/选区标签同一套行为。
4. **假设**输入框内容被持久化后重新加载（切会话/重开面板），**当**内容恢复时，**则**标签仍在，发送时照常取内容。
5. **假设**宿主是桌面端或远控页，**当**用户输入 `@` 时，**则**下拉里只有文件搜索结果，不出现这两个固定条目。

***

### 边界情况

* **VS Code 读终端靠剪贴板中转**：实现是「保存剪贴板 → 选中上一条命令 → 复制 → 读剪贴板 → 还原剪贴板 → 清除选区」。因此发送带 `@terminal` 的消息时会短暂占用系统剪贴板，若用户此刻正好在复制，可能互相干扰。
* **只影响活动终端**：VS Code 路径操作的是活动终端；用户切到别的终端时读到的是切换后的那个。
* **读数据有延迟**：VS Code 侧要执行内置命令、JetBrains 侧要读终端缓冲，两者都比普通发消息慢。读期间的发送必须等待，不能让用户点了发送却发出一个空块；超时按"不可用"处理并照常发送。
* **JetBrains 终端依赖 Shell 终端**：通过 Shell 终端 widget 的文本缓冲读取；非 Shell 终端、或拿不到 widget 时按"不可用"处理（终端场景 5）。
* **JetBrains 诊断读的是内部 API**：`HighlightInfo.fromRangeHighlighter` 属 `impl` 包，跨 IDE 大版本可能失效；失效必须降级为问题场景 5 的说明行，且不得影响另一个条目。
* **诊断可能未完成**：刚改完代码时检查器可能还在跑，读到的是上一轮结果；规格不等待分析完成（不做无界等待），但不得因此报错。
* **隐私**：终端输出可能含密钥/令牌，展开的是用户自己终端里已经打印出来的内容，不额外扩大读取范围；内容会留在会话历史里，与用户手动粘贴同性质。
* **多根工作区**：`@problems` 取的是活动文件，因此天然落在某个根内；消息里的路径按仓库相对路径呈现，便于 agent 直接读取。

## 非目标

* **不做调试上下文（`@debugger`）**：VS Code 侧可做（活动会话 → 当前帧局部变量），但参考实现在 JetBrains 侧从未实现，两端行为会不对称；本轮两端都不做。
* **不做工具形态**：不注册让模型主动调用的诊断/终端工具（与 Claude Code 的形态差异，留待后续评估）。
* **不做每轮自动注入**：不在环境信息里无条件携带终端输出或诊断。
* **不做全项目 problems**：`@problems` 只取当前活动文件，不做跨文件全量扫描。
* **不做终端选区/历史命令列表**：`@terminal` 固定取最后一条命令及其输出，不支持选择第 N 条或指定终端。
* **不做发送后刷新**：块内容固定在发送时刻，之后终端又输出了什么、诊断变没变，都不回写已有消息。
* **不做桌面端**：桌面端终端（PTY）不接入该能力。
* **不做 Visual Studio**：VS 的进程外扩展没有公开终端 API。

## 假设

* **宿主只提供原始数据**：新增一对请求/响应（webview 请求两个 provider 的内容，宿主返回终端文本与诊断条目数组），格式化与拼消息在共享 webview 里做。该命令需在四个路由实例登记（桌面端返回不可用），否则 webview 命令审计 CI 失败。
* **不回写 SDK 侧机制**：消息正文里就是最终的纯文本，SDK 不需要新工具，也不需要新的 RPC 类别。
* **条目可见性沿用已有宿主判据**：两个固定条目只在插件端出现，判据取 webview 现有的宿主标识（`isDesktopHost` / `isRemotePageHost`），不新增"宿主能力声明"请求。
* **VS Code 侧无 shell integration 依赖**：终端读取走内置命令 + 剪贴板，因此不要求终端启用 shell integration，也不要求 VS Code 1.93+ 的执行事件 API。
* **JetBrains 侧不要求 2025.3+**：终端走经典 Shell 终端 widget 的文本缓冲，不依赖 2025.3 起的新 Terminal API。
* **上限取设计默认值**：终端尾部行数、problems 条数各有硬上限，超出按"尾部/前 N 条优先"截断并在块首行注明。
