# 13 Hermes VSCode 插件对照审查 v1

> 状态：reference
>
> 归档说明（2026-05-21）：P0 缺口已拆分到 `7-30` 至 `7-33` 并完成归档；本文保留 Hermes VSCode 插件对照证据和 P1/P2 参考项。
>
> 日期：2026-05-20
>
> 范围：`reference-code/hermes-vscode-main` 对照 MNote 当前 `mnote-web` Hermes / ACP / Page AI 实现。

## 1. 审查方法

本轮先以 Hermes VSCode 插件为参考实现，核查它对 ACP runtime、会话恢复、权限请求、tool call、上下文注入和 Webview 控制面的处理方式，再对照 MNote 当前 Rust Web 主链：

- 参考实现：`src/acpClient.ts`、`src/sessionManager.ts`、`src/protocol.ts`、`src/chatPanel.ts`、`src/sessionStore.ts`、`src/webview/main.ts`、`src/webview/renderers.ts`、`src/modelCatalog.ts`、`src/skillCatalog.ts`。
- MNote 实现：`rust/crates/mnote-web/src/acp_client.rs`、`acp_session_manager.rs`、`acp_bridge.rs`、`routes/hermes_client.rs`、`ssr/pages/layout.rs`。
- 审查口径：不把 VSCode UI 状态照搬为 MNote 真相源；MNote 继续遵守 local-first、Rust Web 承载、Page AI 文件引用 + agent 原生 patch/diff + watcher 同步主线。

## 2. Hermes VSCode 可借鉴模型

- `SessionManager.ensureSession()` 在已有 `storedSessionId` 时必须调用 ACP `session/load`。仅把旧 session id 写回内存会产生 phantom session，后续 `session/prompt` 可能静默失败。
- `AcpClient` 区分 JSON-RPC response、notification 和 incoming request；`session/request_permission` 通过 handler 返回真实 allow / deny 结果。
- `session/update` 中的 `tool_call.locations[]` 会被解析保存；`tool_call_update completed` 后，`read` 打开 preview editor，`edit` 打开 persistent editor。
- `session_info_update` 会更新会话标题；`plan` / todo tool 输出可渲染为任务 overlay，而不是丢弃。
- Webview 对 slash command 有 allowlist，slash 响应渲染为居中的 system message，不混入普通 user / assistant 泡泡。
- model / skill picker 来自 Hermes 本地缓存和 `SKILL.md` 目录，作为 agent 控制面的一部分。
- Prompt 注入包含 cwd、active file、selection、open tabs、附件引用和 skills advisory，不把这些上下文当成长期正文真相。

## 3. MNote 当前状态

- Rust `AcpSessionManager` 已有 `session/new`、`session/prompt`、`session/cancel`、streaming dedup、typed event 和 usage / thought / tool / plan / session info 解析雏形。
- `acp_bridge.rs` 已把 TextDelta、ThoughtDelta、ToolCall、ToolCallUpdate、UsageUpdate、PermissionRequest 转成 SSE，但 `SessionInfoUpdate` 和 `PlanUpdate` 当前仍被丢弃。
- `layout.rs` Page AI 已有 session list/detail/search/resume/rename/delete、localStorage cache、SQLite control-plane / local AI session store、permission dialog、tool event UI、profile/skills 控制面和 usage summary；旧 Convex ACP runtime store 仅属 legacy compat。
- `routes/hermes_client.rs` 已有 local-first AI session JSONL、SQLite control-plane ACP runtime store、run queue、abort 和 local agent audit；旧 Convex ACP runtime store 仅属 legacy compat。
- 当前 `resume_session` 只恢复 MNote SQLite/local 或显式 legacy Convex 会话历史，不等同于对 ACP adapter 调用 `session/load` 注册底层 ACP session。
- 当前 `AcpClient` 对 incoming `session/request_permission` 仍立即返回 unsupported/deny，前端按钮没有真正回传 ACP 决策。
- 当前 `SessionUpdate::ToolCall` 类型未保留 `locations`，因此无法像 Hermes VSCode 一样把 read/edit 工具结果联动到主编辑器 tab。

## 4. P0 缺口

### P0-1 ACP `session/load` 恢复缺失

MNote 有会话列表、恢复按钮和 runtime store，但恢复更多是 MNote 会话历史层的恢复。对 ACP runtime 来说，若没有对 adapter 调用 `session/load { sessionId, cwd, mcpServers: [] }`，后续 prompt 可能对应不到 agent 侧真实 session。

建议：在 `AcpSessionManager` 增加 stored ACP session id / `load_session` / `ensure_session` 能力；在 `hermes_client` 的 ACP run 启动处尽量使用已保存 ACP session id 进行 load，失败再 `session/new`。

### P0-2 权限请求缺少真实 allow / deny 闭环

前端存在 permission dialog，但后端 `AcpClient` 对 incoming request 立即返回 JSON-RPC error，再广播 denied。用户点击允许/拒绝不能影响当前 ACP 请求。

建议：`AcpClient` 增加 incoming request handler；`AcpSessionManager` 把 `session/request_permission` 转成 pending request；`routes/hermes_client` 提供按 run/session/permission id 决策的短生命周期接口；超时默认 deny。

### P0-3 tool `locations[]` 与 read/edit 打开联动缺失

Hermes VSCode 会保存 tool locations，并在 read/edit 完成后打开对应文件。MNote 当前 tool SSE 只有 raw input / output，不保留 `locations`，也没有把 tool 完成联动到 main editor resource tab / file tree target。

建议：扩展 ACP 类型、event 和 SSE 数据，保留 `locations`；前端对 completed read/edit 工具提供“打开”动作，优先复用现有 main editor resource tab，不默认新浏览器窗口。

### P0-4 `session_info_update` / `plan` 被桥接层丢弃

MNote 已在 `AcpSessionManager` 解析 `SessionInfoUpdate` 和 `PlanUpdate`，但 `acp_bridge` 当前返回 `None`。会话自动标题、agent plan/todo 不能进入 UI，也不能进入 runtime event 记录。

建议：转发 `session.info.updated` 和 `plan.updated` SSE；前端更新当前会话标题，并将 plan/todo 作为轻量状态面板或 tool/system message 渲染。

## 5. P1 缺口

- slash command 响应仍更像普通聊天消息，缺少参考实现中的 system message 视觉语义和 allowlist 明确边界。
- skills / model 控制面已存在，但未完全对齐 Hermes 本地 model cache 与 `SKILL.md` 目录；需要确认是否存在过期 profile / skill 混用。
- busy queue / interrupt cancel 已有队列和 stop，但与参考实现“第二条消息排队、interrupt 立即 unblock”的交互语义仍需 smoke 覆盖。
- Page AI session restore 需要区分 MNote session id、ACP adapter session id、run id，避免 UI 把任意历史 session 当作可继续底层 ACP 对话。
- tool raw output 中的 todo JSON 还没有独立 overlay，计划状态只能混在 tool card 中。

## 6. P2 缺口

- Webview markdown rendering / sanitization 参考实现使用 `marked` + `DOMPurify`；MNote 当前对 assistant 消息仍偏纯文本逃逸，后续可评估富文本安全渲染。
- active file / selection / open tabs 上下文注入需要继续与 MNote editor group / resource tab 模型对齐。
- Hermes 插件中 attachments 以 `[Referenced file: path]` 进入 prompt；MNote local-first 已有文件 scope，但附件引用提示仍可更清晰。
- session store 的 max 20 sessions / max 300 messages 可作为 MNote localStorage/local JSONL 裁剪策略参考。

## 7. 不建议照搬

- 不照搬 VSCode Webview 的 DOM/CSS 结构；MNote 仍使用 Wolai 主题 Page AI drawer。
- 不把 VSCode `workspaceState` 当作 MNote 会话真相；local-first 下本地 JSONL / SQLite control-plane / runtime registry 各自职责不变，Convex 只保留显式 legacy compat / sync replica。
- 不把 Hermes 插件中的自动打开文件行为做成不可控跳转；MNote 应默认在 main editor resource tab 打开，并保留显式新窗口入口。
- 不在 UI 层新增第二套文件权限真相；权限和 allowed roots 仍由 Rust Web / local-first scope 决定。
- 不把 Page AI block-edit workflow 扩成普通 Markdown 主路径；local folder 继续走文件引用 + agent 原生 patch/diff + watcher 同步。

## 8. 执行拆分

本 review 先拆四份 P0 checklist，允许并行推进：

- `design/07-ai/done/7-30-acp-session-load-resume-checklist-v1.md`
- `design/07-ai/done/7-31-acp-permission-decision-loop-checklist-v1.md`
- `design/07-ai/done/7-32-acp-tool-location-and-open-action-checklist-v1.md`
- `design/07-ai/done/7-33-acp-session-info-plan-ui-checklist-v1.md`

P0 收口后再拆 P1：

- slash/system message 与 model/skill 控制面收口。
- queue / interrupt cancel browser smoke。
- assistant markdown 安全渲染评估。
