chore: align mvp design governance
- 统一 local-first MVP 后阶段架构口径,补充 process 执行总序和 Reasonix 协作记录 - 归档已完成的 design checklist,标注参考型 process,更新 AGENTS/REASONIX/架构文档 - 补充文件树/主编辑器下载与上下文菜单相关实现、bug 记录和 smoke 脚本 验证:git diff --check;codegraph sync .;cargo test -p mnote-web;node --check scripts/task476-filetree-editor-context-menu-download-smoke.js
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
# 7-16 [done] Page Block AI 真实页面 Smoke 后续矩阵 v1
|
||||
|
||||
> 创建时间:2026-05-18
|
||||
>
|
||||
> 当前状态:`DONE`
|
||||
>
|
||||
> 归档说明(2026-05-21):本文范围内可执行的真实页面 smoke 已完成;剩余 UI / Review Mode 属于 Phase C 冻结范围,解冻时应新建设计稿承接。
|
||||
>
|
||||
> 来源:
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. 目的
|
||||
|
||||
`7-10` 已完成大量工具合同、Rust route 测试和部分真实 3000 smoke,但仍有一组“必须真实页面验证”的矩阵项未完成。
|
||||
|
||||
本文只承接这些剩余 smoke,不新增 AI 功能面,不改变当前主路径:
|
||||
|
||||
- local-first 普通 Markdown 编辑主路径仍是“授权文件引用 + agent 原生 patch/diff + watcher 同步”;本文只验证 mnote tools 的结构性辅助和 compat fallback。
|
||||
- `mnote.doc.markdown_edit` 只作为 cloud / remote agent / compat fallback 的 smoke 对象。
|
||||
- `mnote.block.*` 仍只作为结构性辅助。
|
||||
- `mnote.page.save` 仍只作为页面级粗粒度兜底。
|
||||
- Phase C review / streaming apply 仍冻结,当前只验证基础合同和安全边界。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前已具备的前置证据
|
||||
|
||||
- `mnote.doc.fetch scope=selection format=page_xml/text`、`mnote.block.fetch format=page_xml/text`、manifest annotations、`mnote.doc.apply_block_ops allowedTargetBlockIds` 越界阻断已有真实 3000 smoke:
|
||||
- `tmp/page-block-ai-context-format-smoke/mp8ddr4n.json`
|
||||
- `tmp/page-block-ai-context-format-smoke/mp8ddr4n-page.png`
|
||||
- `mnote.block.replace` stale revision / stale blockRevisionRef / idempotency replay 已有真实 3000 smoke:
|
||||
- `scripts/task-page-block-ai-conflict-idempotency-smoke.js`
|
||||
- 证据记录在 `08` 的 Page Block AI Tooling 章节。
|
||||
- `mnote.block.insert_after` 多块插入和 20 个边界已有 Rust route 回归:
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block_insert_after -- --nocapture`
|
||||
- `mnote.block.move_after` 复杂块阻断矩阵已有隔离 route smoke:
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block_move_after_blocks_complex_and_nested_blocks -- --nocapture`
|
||||
|
||||
---
|
||||
|
||||
## 3. 后续真实页面 Smoke 矩阵
|
||||
|
||||
### 3.1 Page Aggregate Block Projection
|
||||
|
||||
- [x] 登录测试账号并创建综合页面 `TEST-AI-BLOCK-TOOLS-<timestamp>`。
|
||||
- [x] 写入段落、标题、todo、列表、mindmap/resource 占位。
|
||||
- [x] 调 `/api/page-aggregate/:id` 并保存响应到 `tmp/hermes-tester/page-block-ai-tools-<run-id>/page-aggregate.json`。
|
||||
- [x] 断言所有普通可编辑块有 `blockId` 和 `revisionRef`。
|
||||
- [x] 页面刷新后 block ids 不变化。
|
||||
- [x] projection 中 `blockCount` 与页面块数量一致;复杂块返回 `editable=false` 与 `unsupportedReason`。
|
||||
|
||||
证据(2026-05-18):
|
||||
|
||||
- JSON:`tmp/page-block-ai-tools-smoke/mpag4966.json`
|
||||
- Page Aggregate:`tmp/hermes-tester/page-block-ai-tools-mpag4966/page-aggregate.json`
|
||||
- 覆盖:Page Aggregate `blockProjectionVersion=1`、`projectionSource=documents.content`、`aggregateBlockCount=10`,与 `mnote.doc.fetch` 块顺序一致;刷新后 `afterRefreshBlockIds` 保持最终顺序;`table_1/mindmap_1/resource_1` 返回 `editable=false` 与 `unsupportedReason=复杂块暂不开放 AI 精确写入`。
|
||||
|
||||
### 3.2 `mnote.doc.fetch` / `mnote.doc.find`
|
||||
|
||||
- [x] 使用综合页面 `TEST-AI-BLOCK-TOOLS-<timestamp>`。
|
||||
- [x] `mnote.doc.fetch scope=full detail=with_ids` 读取整页。
|
||||
- [x] `mnote.doc.fetch scope=outline detail=with_ids` 只返回标题结构。
|
||||
- [x] `mnote.doc.find query=<唯一前缀>` 定位目标段落。
|
||||
- [x] 保存工具返回到 `tmp/hermes-tester/page-block-ai-tools-<run-id>/doc-fetch-find.json`。
|
||||
- [x] 确认读取不依赖浏览器 DOM。
|
||||
- [x] `doc.find` 返回的 block id 能被 `block.fetch` 读取。
|
||||
- [x] 大页面默认分块或限制输出,不默认返回无限正文。
|
||||
|
||||
证据(2026-05-18):
|
||||
|
||||
- 命令:`PLAYWRIGHT_CHROME_EXECUTABLE=/snap/bin/chromium MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-tools-smoke.js`
|
||||
- JSON:`tmp/page-block-ai-tools-smoke/mpag4966.json`
|
||||
- 工具返回:`tmp/hermes-tester/page-block-ai-tools-mpag4966/doc-fetch-find.json`
|
||||
- 覆盖:`doc.fetch.initial` 读取 `heading_1/p_1/p_2/p_3` 等 10 个块;`doc.fetch scope=outline` 只返回 `heading_1/heading_parent`;`doc.find query="第二段 <suffix>"` 定位 `p_2`;`maxBlocks=2` 返回 `truncated=true`。
|
||||
- 静态边界:`mnote.doc.fetch` 从 Page Aggregate block projection 构建上下文,不读取浏览器 DOM;默认 `maxBlocks=120` 且 clamp 到 `1..=240`。
|
||||
|
||||
### 3.3 `mnote.block.fetch`
|
||||
|
||||
- [x] 从 `doc.find` 结果选择一个段落 block。
|
||||
- [x] 调 `mnote.block.fetch includeChildren=true contextBefore=1 contextAfter=1`。
|
||||
- [x] 断言 before/after 只来自同父级。
|
||||
- [x] `revisionRef` 可被后续 dry-run 使用。
|
||||
- [x] 复杂块不会伪装成完全可编辑。
|
||||
|
||||
证据(2026-05-18):
|
||||
|
||||
- JSON:`tmp/page-block-ai-tools-smoke/mpag4966.json`
|
||||
- 覆盖:`block.fetch` 读取 `p_2`,返回 `revisionRef=pageRev:1:block:p_2:...`,同父级 `before=["p_1"]`、`after=["p_3"]`;`table_1/mindmap_1/resource_1` 均返回 `editable=false` 与 `unsupportedReason=复杂块暂不开放 AI 精确写入`。
|
||||
|
||||
### 3.4 `mnote.doc.plan_update` / dry-run
|
||||
|
||||
- [x] `command=str_replace` 不再作为当前 `plan_update` 目标;普通正文 search/replace 已由 `mnote.doc.markdown_edit` 合同承接。
|
||||
- [x] 对目标段落执行 `block_replace dryRun=true`。
|
||||
- [x] 对目标段落执行 `block_insert_after dryRun=true`。
|
||||
- [x] 对两个同父级普通块执行 `block_move_after dryRun=true`。
|
||||
- [x] dry-run 前后分别读取 `/api/page-aggregate/:id` 与 `mnote.doc.fetch`,确认 revision / conflictDetectionKey / 正文文本不变。
|
||||
- [x] dry-run 不写 Convex。
|
||||
- [x] plan 能解释 before/after。
|
||||
- [x] 不支持场景返回 `blocked=true`。
|
||||
|
||||
证据(2026-05-18):
|
||||
|
||||
- JSON:`tmp/page-block-ai-tools-smoke/mpag4966.json`
|
||||
- 覆盖:`plan_update.dry_run.replaceDiff.before/after`、`insertDiff.after/content`、不支持 `move_after p_3 -> p_3` 返回 `blocked=true`、dry-run 后 `revisionAfterDryRun=1` 且正文未变化。
|
||||
|
||||
### 3.5 `mnote.block.replace`
|
||||
|
||||
- [x] 使用综合页面 `TEST-AI-BLOCK-TOOLS-<timestamp>`。
|
||||
- [x] 写入两段不同文本。
|
||||
- [x] `doc.find` 找到第二段 block id。
|
||||
- [x] `block.replace dryRun=true` 查看 plan。
|
||||
- [x] `block.replace dryRun=false` 替换第二段。
|
||||
- [x] 页面截图和工具回读证明只替换第二段。
|
||||
- [x] `/api/page-aggregate/:id` 回读证明持久化。
|
||||
- [x] `mnote.doc.fetch` 再次证明 AI 可读回。
|
||||
- [x] 相邻块不变化。
|
||||
- [x] 目标 block id 保持不变。
|
||||
- [x] 旧 revision 写入返回 conflict。
|
||||
|
||||
证据(2026-05-18):
|
||||
|
||||
- JSON:`tmp/page-block-ai-tools-smoke/mpag4966.json`
|
||||
- 截图:`tmp/page-block-ai-tools-smoke/mpag4966-page.png`
|
||||
- 覆盖:`block.replace.changedBlocks[0]={blockId:"p_2",op:"replace"}`,`targetBlockStillExists=true`,`adjacentTexts=["第一段 mpag4966","第三段 mpag4966"]`,`mnote.doc.fetch` 与 Page Aggregate 均回读到 `第二段已替换 mpag4966`,Page Aggregate `aggregateRevision=2`、`aggregateConflictDetectionKey=tree_1779062903017_3:2`。
|
||||
- 冲突 / 幂等补充 JSON:`tmp/page-block-ai-conflict-idempotency-smoke/mpafrevs.json`,截图:`tmp/page-block-ai-conflict-idempotency-smoke/mpafrevs-page.png`。
|
||||
- 覆盖:首次 `block.replace` 写入 `p_2` 后,重复 `idempotencyKey=idem_conflict_replace_mpafrevs` replay 同一 `commandId=page_body_save_req_1779062303997_525` 且 `revisionAfterFirst=2`、`revisionAfterReplay=2`;旧 `revision/conflictDetectionKey` 与旧 `blockRevisionRef` 均返回 HTTP `400` / `mnote_tool_conflict`,最终文本保持 `第二段首次替换 mpafrevs`。
|
||||
|
||||
### 3.6 `mnote.block.insert_after`
|
||||
|
||||
- [x] 使用综合页面 `TEST-AI-BLOCK-TOOLS-<timestamp>`。
|
||||
- [x] 在第一段后插入 todo。
|
||||
- [x] 截图证明位置准确。
|
||||
- [x] 刷新页面后再次确认。
|
||||
- [x] `mnote.block.fetch` 能读取新 block id。
|
||||
- [x] 插入位置准确。
|
||||
- [x] 新 block id 不是 AI 自造未校验 id。
|
||||
- [x] 重复同一 `idempotencyKey` 不重复插入。
|
||||
|
||||
证据(2026-05-18):
|
||||
|
||||
- 命令:`PLAYWRIGHT_CHROME_EXECUTABLE=/snap/bin/chromium MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-tools-smoke.js`
|
||||
- JSON:`tmp/page-block-ai-tools-smoke/mpag4966.json`
|
||||
- 截图:`tmp/page-block-ai-tools-smoke/mpag4966-page.png`
|
||||
- 说明:该 smoke 使用 `TEST-AI-BLOCK-TOOLS-*` 综合页面,不是单独 `TEST-AI-BLOCK-INSERT-*` 页面;已覆盖 todo 插入、插入后顺序、block.fetch 回读、刷新后可见和重复 idempotencyKey replay。
|
||||
|
||||
### 3.7 `mnote.block.move_after`
|
||||
|
||||
- [x] 使用综合页面 `TEST-AI-BLOCK-TOOLS-<timestamp>`,包含三段普通段落。
|
||||
- [x] dry-run 移动第三段到第一段后。
|
||||
- [x] 正式执行同父级移动。
|
||||
- [x] 截图证明顺序为第一段、第三段、第二段。
|
||||
- [x] `mnote.doc.fetch` 回读顺序一致。
|
||||
- [x] 对标题带子块、列表项、表格、mindmap 执行 move dry-run,必须返回 blocked。
|
||||
- [x] moving block id 保持不变。
|
||||
- [x] 同父级顺序正确。
|
||||
- [x] 复杂块不被误移动。
|
||||
|
||||
证据(2026-05-18):
|
||||
|
||||
- JSON:`tmp/page-block-ai-tools-smoke/mpag4966.json`
|
||||
- 截图:`tmp/page-block-ai-tools-smoke/mpag4966-page.png`
|
||||
- 覆盖:`heading_parent/list_item_1/table_1/mindmap_1/resource_1` 的 `plan_update block_move_after dryRun=true` 与正式 `mnote.block.move_after dryRun=false` 均返回 `blocked=true` / `block_move_after_blocked`,阻断后 `revisionAfterBlocked=1` 且正文不变化;普通 `p_3 -> p_1` 正式移动后顺序为 `heading_1,p_1,p_3,ai_block_...,p_2,...`,`movingBlockStillExists=true`。
|
||||
|
||||
### 3.8 UI / Review Mode 边界
|
||||
|
||||
- [ ] Hermes tool event UI 展示 `plan/diff/warnings/risk`。
|
||||
- [ ] 本地 preview/suggestion 与持久 comment/tracked-change 分开。
|
||||
- [ ] 协作可见审阅必须另走正式 comment/history/tracked-change 设计。
|
||||
- [ ] 用户能看到 AI 将改哪个 block。
|
||||
- [ ] `blocked=true` 的工具调用不会出现写入按钮。
|
||||
- [ ] preview 不写入正式 comment/history。
|
||||
|
||||
---
|
||||
|
||||
## 4. 验证原则
|
||||
|
||||
- 所有真实页面 smoke 必须使用测试账号,优先从 `http://localhost:3000/auth` 快速登录。
|
||||
- 证据必须保留 JSON 和截图,默认放入 `tmp/hermes-tester/<run-id>/` 或专项 `tmp/page-block-ai-*` 目录。
|
||||
- 发现失败时按 owner 写入 `bugs/<category>/process/`,不要只在本矩阵中留描述。
|
||||
- 不用此矩阵扩展新 AI 功能;只补真实页面证据和安全边界。
|
||||
@@ -0,0 +1,55 @@
|
||||
# 7-30 ACP session/load 恢复 checklist v1
|
||||
|
||||
> 状态:done
|
||||
>
|
||||
> 归档说明(2026-05-21):ACP `session/load` / resume 核心闭环已完成并通过聚焦测试;session id 全链路持久化作为后续产品化项继续跟踪。
|
||||
>
|
||||
> Owner:ACP session lifecycle
|
||||
>
|
||||
> 参考:`reference-code/hermes-vscode-main/src/sessionManager.ts`
|
||||
|
||||
## 目标
|
||||
|
||||
让 MNote ACP runtime 在恢复已有 ACP session 时真正调用 adapter 的 `session/load`,避免只恢复 MNote 会话历史而产生 phantom ACP session。
|
||||
|
||||
## 允许修改范围
|
||||
|
||||
- `rust/crates/mnote-web/src/acp_session_manager.rs`
|
||||
- `rust/crates/mnote-web/src/routes/hermes_client.rs`
|
||||
- 与 session load/resume 直接相关的 Rust 测试
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 不改 Page AI 前端 UI。
|
||||
- 不改 Convex schema。
|
||||
- 不删除或覆盖现有 local AI session JSONL 逻辑。
|
||||
|
||||
## Checklist
|
||||
|
||||
- [x] 在 `AcpSessionManager` 增加 `load_session(session_id, cwd)` 或等价能力,参数与 Hermes VSCode 一致:`session/load { sessionId, cwd, mcpServers: [] }`。
|
||||
- [x] load 成功时把当前 ACP session id 设置为 loaded id;load 返回 null / error 时允许 fallback 到 `session/new`。
|
||||
- [ ] 明确区分 MNote session id 与 ACP adapter session id;需要持久化/返回时字段名不能混淆。
|
||||
- [x] ACP run 启动处优先尝试恢复已知 ACP session id,再创建新 session。
|
||||
- [x] 补 mock ACP 测试覆盖 `session/load` 成功、返回 null fallback、新 session 仍可 prompt。
|
||||
- [x] 更新本文件“执行记录”。
|
||||
|
||||
## 验收命令
|
||||
|
||||
```bash
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web acp_session_manager -- --test-threads=1
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web hermes_client_acp_resume -- --test-threads=1
|
||||
```
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-05-20 22:06 — Reasonix Code 执行,Codex 复核并通过聚焦测试。
|
||||
- `acp_types.rs`: 新增 `SessionLoadParams` / `SessionLoadResult` 类型。
|
||||
- `acp_session_manager.rs`:
|
||||
- 新增 `load_session(session_id, cwd)` → 调用 ACP `session/load`,成功时设置 internal session_id,null/error 返回 false。
|
||||
- 新增 `ensure_session(cwd, stored_session_id)` → 1) 复用已有 session,2) 有 stored id 时尝试 load,3) fallback 到 `session/new`。
|
||||
- 新增 7 个单元测试覆盖所有路径:load 成功、null fallback、复用 active、无 stored 创建新 session、fallback 后 prompt 仍可工作。
|
||||
- `hermes_client.rs`:
|
||||
- `acp_stream_events()` 中从 payload 提取 `acpSessionId`,传给 `ensure_session()` 替代原来的 `create_session`。
|
||||
- 错误码从 `acp_session_create_failed` 改为 `acp_session_ensure_failed`。
|
||||
- Codex 复核:当前 `acpSessionId` 只从 run payload 读取,前端/session store 仍未稳定持久化并传回该字段,因此“session id 字段全链路区分与持久化”保留未完成。
|
||||
- 验收:`cargo test -p mnote-web acp_session_manager -- --test-threads=1`、`cargo test -p mnote-web hermes_client_acp_resume -- --test-threads=1`、`cargo test -p mnote-web acp -- --test-threads=1` 通过。
|
||||
@@ -0,0 +1,52 @@
|
||||
# 7-31 ACP permission 决策闭环 checklist v1
|
||||
|
||||
> 状态:done
|
||||
>
|
||||
> Owner:ACP incoming request / permission loop
|
||||
>
|
||||
> 参考:`reference-code/hermes-vscode-main/src/acpClient.ts`、`src/sessionManager.ts`
|
||||
|
||||
## 目标
|
||||
|
||||
把 `session/request_permission` 从"后端立即 unsupported/deny"改成"后端发出 pending request,前端 allow/deny,后端回写 JSON-RPC response"的真实闭环;超时仍默认 deny。
|
||||
|
||||
## 允许修改范围
|
||||
|
||||
- `rust/crates/mnote-web/src/acp_client.rs`
|
||||
- `rust/crates/mnote-web/src/acp_session_manager.rs`
|
||||
- `rust/crates/mnote-web/src/acp_bridge.rs`
|
||||
- `rust/crates/mnote-web/src/routes/hermes_client.rs`
|
||||
- 只允许为接线 permission 按需小改 `rust/crates/mnote-web/src/ssr/pages/layout.rs`
|
||||
- 相关 Rust 测试
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 不把权限结果存为新的长期正文/附件真相。
|
||||
- 不默认 allow;超时、缺失 run、缺失 pending request 都必须 deny 或返回清晰错误。
|
||||
- 不大改 Page AI drawer 视觉结构。
|
||||
|
||||
## Checklist
|
||||
|
||||
- [x] `AcpClient` 支持注册 incoming request handler,并允许 handler 返回 JSON-RPC result/error。
|
||||
- [x] `session/request_permission` 进入 pending map,生成稳定 permission id,向 SSE 发 `permission.requested`。
|
||||
- [x] 增加 HTTP endpoint 或现有 endpoint 扩展:前端可按 run id / permission id 提交 allow/deny。
|
||||
- [x] 提交 allow/deny 后,ACP JSON-RPC request 得到对应 response;前端收到 `permission.allowed` / `permission.denied`。
|
||||
- [x] 超时默认 deny,并向 UI 和 runtime event 写明 timeout。
|
||||
- [ ] 补 mock ACP 测试:incoming request 等待决策、allow 返回 result、deny 返回 result/error、timeout deny。
|
||||
- [x] 更新本文件"执行记录"。
|
||||
|
||||
## 验收命令
|
||||
|
||||
```bash
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web acp_client -- --test-threads=1
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web acp_bridge -- --test-threads=1
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --test-threads=1
|
||||
```
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-05-20:Reasonix 实施,Codex 复核并修正 JSON-RPC id 保真与 permission response 语义。
|
||||
- 改动点:`AcpClient` 增加 `on_incoming_request()` / `respond_to_incoming()` / `respond_to_incoming_error()`;`dispatch_message` 将 incoming request 转发给 handler 而非立即 error;`AcpSessionManager.new()` 注册 incoming request handler,将 `session/request_permission` 存入 pending map + 发射 `permission.requested` + 启动 60s 超时自动 deny;`AcpSessionManager` 增加 `resolve_permission()` 方法;`acp_bridge` SSE 转换支持 `permission.requested`;`hermes_client.rs` 增加 `resolve_permission` HTTP endpoint;`routes/mod.rs` 注册路由;`layout.rs` 中 `pageAiResolvePermission` 调用后端。
|
||||
- Codex 修正:incoming JSON-RPC request id 使用原始 `serde_json::Value` 保存和回写,避免字符串 id 被改成 0;allow/deny 正常路径改为参考 Hermes VSCode 插件的 `{ outcome: "selected", optionId }`,并补 `permission_response_selects_allow_and_deny_options` 测试。
|
||||
- 未完成:已有 `acp_client` incoming request 基础测试和 option 选择 helper 测试,但还缺“mock ACP 发 permission -> HTTP resolve endpoint -> agent 收到 selected option”的端到端测试,故该 checklist 的 mock 闭环项保留未完成。
|
||||
- 验收:`cargo test -p mnote-web acp_client -- --test-threads=1`、`cargo test -p mnote-web acp_bridge -- --test-threads=1`、`cargo test -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --test-threads=1`、`cargo test -p mnote-web acp -- --test-threads=1` 通过。
|
||||
@@ -0,0 +1,56 @@
|
||||
# 7-32 ACP tool locations 与打开动作 checklist v1
|
||||
|
||||
> 状态:done
|
||||
>
|
||||
> 归档说明(2026-05-21):ACP tool locations 解析、SSE 桥接与前端打开动作已完成;浏览器 smoke 可作为后续补强。
|
||||
>
|
||||
> Owner:ACP tool event data + Page AI open action
|
||||
>
|
||||
> 参考:`reference-code/hermes-vscode-main/src/protocol.ts`、`src/chatPanel.ts`
|
||||
|
||||
## 目标
|
||||
|
||||
保留 ACP `tool_call.locations[]`,在 Page AI tool card 中展示位置,并对 read/edit 完成事件提供打开动作。默认打开到 MNote 主编辑器资源 tab / 当前工作区 tab,不默认新浏览器窗口。
|
||||
|
||||
## 允许修改范围
|
||||
|
||||
- `rust/crates/mnote-web/src/acp_types.rs`
|
||||
- `rust/crates/mnote-web/src/acp_session_manager.rs`
|
||||
- `rust/crates/mnote-web/src/acp_bridge.rs`
|
||||
- `rust/crates/mnote-web/src/ssr/pages/layout.rs`
|
||||
- 相关 Rust 测试和必要 smoke 脚本
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 不重写资源 tab registry。
|
||||
- 不新增与 Sidex workbench checklist 冲突的 editor group 模型。
|
||||
- 不默认 `window.open`。
|
||||
- 不绕过 existing allowed root / local workspace access。
|
||||
|
||||
## Checklist
|
||||
|
||||
- [x] `SessionUpdate::ToolCall` 解析 `locations: [{ path }]`。
|
||||
- [x] `AcpSessionEvent::ToolCall` 携带 locations,并通过 SSE `tool.started` 发送。
|
||||
- [x] `tool.completed` 能保留或关联此前相同 `toolCallId` 的 locations/kind/title。
|
||||
- [x] Page AI tool card 展示 location 摘要。
|
||||
- [x] 对 read/edit completed tool card 增加“打开”动作,优先复用已有 resource tab / file open resolver。
|
||||
- [ ] 补测试覆盖 locations parse、SSE 数据、前端字符串断言或 smoke。
|
||||
- [x] 更新本文件“执行记录”。
|
||||
|
||||
## 验收命令
|
||||
|
||||
```bash
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web acp_tool -- --test-threads=1
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --test-threads=1
|
||||
```
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-05-20 Reasonix Code 实现:
|
||||
- `acp_types.rs`: 新增 `ToolLocation` 结构体(含 `path` 字段),`SessionUpdate::ToolCall` 新增 `locations: Vec<ToolLocation>`(含反序列化支持)。
|
||||
- `acp_session_manager.rs`: `AcpSessionEvent::ToolCall` 新增 `locations: Vec<String>`,`session_update_to_event` 中映射 locations。
|
||||
- `acp_bridge.rs`: SSE `tool.started` 事件数据包含 `locations` 数组,桥测试中验证。
|
||||
- `layout.rs` 前端:SSE 消息解析提取 `locations`;`pageAiApplyToolEvent` 存储 `locations`;tool card 渲染显示位置路径与"打开"按钮;点击按钮调用 `openLocalResourceInActiveTab` 优先复用主编辑器资源 tab,失败则 fallback 为 `window.open`。
|
||||
- 测试覆盖:`test_session_update_tool_call_with_locations`(parse)、`acp_tool_events_keep_detail_for_collapsible_ui` 验证 SSE locations 字段、`page_ai_uses_backend_acp_session_runtime_store` 验证布局完整性。
|
||||
- Codex 复核:代码层已通过,但尚未做真实浏览器 smoke 点击 tool location 打开动作;因此“前端 smoke”保留未完成。
|
||||
- 验收通过:`cargo test -p mnote-web acp_bridge -- --test-threads=1`、`cargo test -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --test-threads=1`、`cargo test -p mnote-web acp -- --test-threads=1`。
|
||||
@@ -0,0 +1,51 @@
|
||||
# 7-33 ACP session info / plan UI checklist v1
|
||||
|
||||
> 状态:done
|
||||
>
|
||||
> 归档说明(2026-05-21):ACP session info / plan SSE 与 Page AI 轻量 UI 已完成;todo JSON 细化显示作为后续格式约定项。
|
||||
>
|
||||
> Owner:ACP metadata SSE + Page AI lightweight UI
|
||||
>
|
||||
> 参考:`reference-code/hermes-vscode-main/src/sessionManager.ts`、`src/webview/renderers.ts`
|
||||
|
||||
## 目标
|
||||
|
||||
把已解析但被丢弃的 `session_info_update` 和 `plan` 事件送到 Page AI UI:自动标题更新当前会话;plan/todo 以轻量状态面板或系统消息展示,不混入正文真相。
|
||||
|
||||
## 允许修改范围
|
||||
|
||||
- `rust/crates/mnote-web/src/acp_bridge.rs`
|
||||
- `rust/crates/mnote-web/src/routes/hermes_client.rs`
|
||||
- `rust/crates/mnote-web/src/ssr/pages/layout.rs`
|
||||
- 相关 Rust 测试
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 不改 ACP parser 类型,除非发现现有 PlanEntry 无法表达必要字段。
|
||||
- 不实现完整 Phase C review session。
|
||||
- 不把 plan/todo 写入页面正文。
|
||||
|
||||
## Checklist
|
||||
|
||||
- [x] `AcpSessionEvent::SessionInfoUpdate` 转成 `session.info.updated` SSE。
|
||||
- [x] `AcpSessionEvent::PlanUpdate` 转成 `plan.updated` SSE,data 包含 entries。
|
||||
- [x] Page AI 收到 session info 后更新当前 session title,并持久化 localStorage/local session view。
|
||||
- [x] Page AI 收到 plan 后渲染轻量 plan 状态(collapsible details/summary + 编号列表),不当作普通 assistant 正文。
|
||||
- [ ] tool raw output 中包含 todo JSON 时,可以复用 plan 区域或 tool card 状态显示。(风险可控,todo JSON 解析需额外确认格式约定;建议后续补)
|
||||
- [x] 补 bridge 单测和 `SIDEBAR_TREE_JS` 字符串断言。
|
||||
- [x] 更新本文件“执行记录”。
|
||||
|
||||
## 验收命令
|
||||
|
||||
```bash
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web acp_bridge -- --test-threads=1
|
||||
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --test-threads=1
|
||||
```
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-05-20 Reasonix:桥接 SessionInfoUpdate → `session.info.updated` SSE、PlanUpdate → `plan.updated` SSE。
|
||||
- 2026-05-20 Reasonix:前端 SSE handler 解析 session.info.updated 更新当前 session title 并持久化;plan.updated 在 pageAiMessages 末尾创建/更新 kind=plan 消息。
|
||||
- 2026-05-20 Reasonix:renderPageAiConversation 添加 kind===plan 渲染分支:collapsible details/summary 面板显示编号步骤列表。
|
||||
- 2026-05-20 Reasonix:acp_bridge 添加两个单测(session_info_update / plan_update);SIDEBAR_TREE_JS 添加 4 个断言。
|
||||
- 2026-05-20 Codex 复核:todo JSON 格式尚未确认,保留为未完成项;其余已通过 `cargo test -p mnote-web acp_bridge -- --test-threads=1`、`cargo test -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --test-threads=1`、`cargo test -p mnote-web acp -- --test-threads=1`。
|
||||
Reference in New Issue
Block a user