chore: align local-first control plane and editor fixes

- wire SQLite control-plane access/session paths into Rust web local-folder routes

- preserve local Markdown attachment semantics across upload, reload, and secondary-pane resource tabs

- refresh design governance docs, Reasonix task templates, and bug records

- retire root .mcp.json local MCP config
This commit is contained in:
lix-2026
2026-05-23 23:38:42 +08:00
parent 42fb58310c
commit 5f97800489
110 changed files with 5344 additions and 889 deletions
@@ -5,7 +5,7 @@
> 上位依据:
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v2.md`
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
>
> 状态说明:
> - 本稿对应 `Phase 7 v2` 的“文档页 AI 最小闭环”已完成,故迁入 `done/`
@@ -9,9 +9,9 @@
> 本稿目的:在 7-12 已排除第二套 AI runtime 的前提下,补上 Hermes tool execution → Convex 持久化之间缺失的 Rust 编辑运行时中继层,实现「内存态 apply → 编辑器就地 patch → Convex 异步持久化 → 事件增量通知」的四步闭环。
>
> 关联文档:
> - `/mnt/Data1T/mnote/design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-13-page-block-identity-and-command-contract-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
@@ -395,7 +395,7 @@ mnote-web 重启
| 5-13 块身份合同 | EditorBlockDocument 就是 blockDocument 的内存态 |
| 4-6 tree command cutover | EditorRuntimeActor 不碰 tree 命令;page 级和 block 级命令保持独立 |
| 3-3 tree realtime event stream | Phase C 新增 `block.delta` event,扩展而非替代 resync_required |
| 7-14 markdown 编辑收敛 | EditorRuntimeActor 后续需适配 markdown_edit:内部做 markdown diff 后复用 BlockDelta 通道推送编辑器更新。当前先走完整 markdown → blocks → apply 路径 |
| 7-14 markdown 编辑收敛 | 历史口径。`7-14` 已移入 old;当前 `7-18` 口径下,普通 Markdown 编辑不再要求 EditorRuntimeActor 适配 `markdown_edit`,而是由 agent 原生文件 patch/diff 后经 watcher / BufferStore / Page Aggregate 回流 |
---
@@ -407,8 +407,8 @@ mnote-web 重启
- 不要求编辑器同步等待 Convex 写入完成才展示 AI 编辑结果。
- 不改变已有的 `ensure_write_contract` 校验链。
- 不新增写工具;Phase A/B/C 只加速已有工具的落地速度。
- **按 7-14**`mnote.doc.markdown_edit` 的新增不违反本禁止项——它是新增工具,但复用 EditorRuntimeActor 的 delta 通道,属于 Phase D 适配范围
- delta channel 不改写 Tiptap 的协作/undo/redo 栈;仅新增 AI 编辑的增量入口。markdown_edit 的 delta 推送同样遵守此约束。
- **按 7-18**local-first 普通 Markdown 编辑不再新增或依赖 `mnote.doc.markdown_edit`EditorRuntimeActor 不承担普通 Markdown 工具写入适配
- delta channel 不改写 Tiptap 的协作/undo/redo 栈;若后续只用于结构性辅助,也必须遵守此约束。
---
@@ -17,8 +17,8 @@
>
> 关联文档:
> - `/mnt/Data1T/mnote/recycle/design/07-ai/retired-http-hermes/7-5-hermes-client-proxy-contract-v1.md`(已退役历史背景)
> - `/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-14-online-local-ai-markdown-editing-convergence-v1.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/reference/7-17-acp-session-convex-sharing-contract-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-vscode-main/`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/DeepSeek-Reasonix-main/`
@@ -7,8 +7,8 @@
> 归档说明(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/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/reference/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`
---
@@ -19,8 +19,8 @@
本文只承接这些剩余 smoke,不新增 AI 功能面,不改变当前主路径:
- local-first 普通 Markdown 编辑主路径仍是“授权文件引用 + agent 原生 patch/diff + watcher 同步”;本文只验证 mnote tools 的结构性辅助和 compat fallback
- `mnote.doc.markdown_edit` 作为 cloud / remote agent / compat fallback 的 smoke 对象
- local-first 普通 Markdown 编辑主路径仍是“授权文件引用 + agent 原生 patch/diff + watcher 同步”;本文只验证 mnote tools 的历史结构性辅助和兼容证据
- 2026-05-22 之后,`mnote.doc.markdown_edit` 不再作为 local-first 默认、fallback 或 remote fallback;本文中的 smoke 只代表历史在线 / compat 回归证据
- `mnote.block.*` 仍只作为结构性辅助。
- `mnote.page.save` 仍只作为页面级粗粒度兜底。
- Phase C review / streaming apply 仍冻结,当前只验证基础合同和安全边界。
@@ -4,9 +4,9 @@
>
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-tree-first-graph-kernel-v1.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-tree-first-graph-kernel-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-1-phase7-document-ai-minimum-loop-checklist-v1.md`
>
@@ -4,16 +4,20 @@
>
> 2026-05-19 local-first 口径补充:
> - 本文仍适用于 `convex_workspace` / 在线文档的 `mnote.doc.markdown_edit` 修复,但当前默认产品形态已切到 local-first workspace。
> - 本地 `.md` 路径的默认 AI 编辑主路径是“授权文件引用 + agent 原生 patch/diff + watcher 同步”`mnote.doc.markdown_edit` 只作为本地受控代理 fallback、cloud / remote agent 或 compat 路径
> - 本地 `.md` 路径的默认 AI 编辑主路径是“授权文件引用 + agent 原生 patch/diff + watcher 同步”。
> - 后续新增 AI 编辑能力默认先保证本地 `.md` 与 `{mdBase}.assets/` 相对路径不被改写为 Convex media asset;在线 Convex 文档路径只作为可选 cloud / sync / share source。
>
> 2026-05-22 口径修正:`mnote.doc.markdown_edit` 不再作为 local-first 默认、fallback 或 remote fallback。本文只保留在线 / compat 写回修复的历史证据;当前 active 设计以 `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md` 为准。
>
> 当前状态:`DONE`(已归档,代码验证通过 2026-05-21
>
> 关联缺陷:`bugs/07-ai/done/7-24-markdown-edit-online-write-does-not-use-final-markdown-v1.md`
> `bugs/07-ai/done/7-25-reasonix-block-edit-workflow-empty-block-ops-after-markdown-match-v1.md`
> `bugs/07-ai/done/7-17-markdown-edit-same-block-multi-op-overwrite-v1.md`
>
> 上位设计:`design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md`
> 历史上位设计:`design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`
>
> 当前 active 设计:`design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
>
> 参考实现:`design/05-editor-mainline/reference-code/cli-main/shortcuts/doc/`str_replace skill
> `rust/crates/mnote-web/src/routes/local_markdown_parser.rs`(已有 GFM→blocks 解析器)
@@ -82,8 +82,8 @@ Owner
只读参考:
- `design/07-ai/process/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
- `design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
- `design/07-ai/done/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
- `design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
- `rust/crates/mnote-web/src/acp_client.rs`
- `rust/crates/mnote-web/src/acp_session_manager.rs`
- `rust/crates/mnote-web/src/acp_runtime.rs`
@@ -5,9 +5,9 @@
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-10-wolai-page-settings-and-ai-surface-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-2-phase7-structured-artifact-write-chain-v1.md`
@@ -94,7 +94,7 @@ Owner
只读范围:
- `design/07-ai/process/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
- `design/07-ai/done/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
- `design/07-ai/done/7-25-acp-session-runtime-enhancement-plan-v1.md`
- `scripts/`
- `rust/crates/mnote-web/src/acp_*.rs`
@@ -7,10 +7,10 @@
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-10-wolai-page-settings-and-ai-surface-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-11-wolai-page-settings-and-ai-surface-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18`
@@ -564,7 +564,7 @@ MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-sm
- `rust/crates/mnote-web/src/hermes_tools/page.rs`
- `rust/crates/bridge-runtime/src/lib.rs`
- `design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md` 仅回填完成证据
- `design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md` 仅回填完成证据
- smoke
- `scripts/task-hermes-page-ai-title-options-smoke.js`
@@ -789,10 +789,10 @@ MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-sm
- `design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`
- `design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`
- `design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`
- `design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md`
- `design/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.md`
- `design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
- `design/05-editor-mainline/process/5-9-wolai-aline-continuous-checklist-v1.md`
- `design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
- `design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md`
- `design/old/07-ai/process/*`
执行步骤:
@@ -1010,7 +1010,7 @@ MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-sm
2026-05-14 K1 执行证据:
- [x] rg 命中已归类:`design/old/**``design/07-ai/done/7-1**` 为历史证据;`scripts/task-hermes-page-ai-retirement-guard.js``rust/crates/mnote-web/src/routes/compat.rs` 为 legacy guard;旧 E27/phase7/page-ai smoke 已默认退役;`wolai-frontend` 中 Mindmap / OnlyOffice / generic AI 面板调用点归为非当前页面 AI 主链的 legacy domain 调用点,后续按各自 domain 迁移。
- [x] 修改文件:`rust/crates/mnote-web/src/routes/compat.rs``scripts/task-hermes-page-ai-retirement-guard.js`、历史退役 smoke 当前本机归档于 gitignored `recycle/scripts/retired-ai-agent-run-smokes/``design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md``design/05-editor-mainline/process/5-9-wolai-aline-continuous-checklist-v1.md``design/10-review/04-secondary-domains-and-design-governance-review.md`
- [x] 修改文件:`rust/crates/mnote-web/src/routes/compat.rs``scripts/task-hermes-page-ai-retirement-guard.js`、历史退役 smoke 当前本机归档于 gitignored `recycle/scripts/retired-ai-agent-run-smokes/``design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md``design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md``design/10-review/04-secondary-domains-and-design-governance-review.md`
- [x] 旧 smoke 默认退役验证:上述 6 个历史 smoke 均返回 `{ ok: true, retired: true }`
**验收标准:**
@@ -1094,8 +1094,8 @@ MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-sm
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | 处理方式 |
| --- | --- | --- | --- |
| Page Aggregate 口径 | `design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md` | 搜索 `/api/ai-agent/run``mnote-cli host``页面 AI` | 改成历史残留 / 已覆盖 / 待迁移证据,不写成长期主线 |
| Wolai-aline 过渡基线 | `design/05-editor-mainline/process/5-9-wolai-aline-continuous-checklist-v1.md` | 搜索 `E27``mnote-cli``页面 AI` | 保留为对标基线时必须标明过渡状态 |
| Page Aggregate 口径 | `design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md` | 搜索 `/api/ai-agent/run``mnote-cli host``页面 AI` | 改成历史残留 / 已覆盖 / 待迁移证据,不写成长期主线 |
| Wolai-aline 过渡基线 | `design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md` | 搜索 `E27``mnote-cli``页面 AI` | 保留为对标基线时必须标明过渡状态 |
| 二级域 review 建议 | `design/10-review/04-secondary-domains-and-design-governance-review.md` | 搜索 `Hermes``plugin``mnote-cli``CLI-first` | 指向 Hermes plugin / Rust bridge 的当前口径 |
| 07-ai 历史稿 | `design/old/07-ai/process/` | 搜索 `CLI-first``mnote-cli` | 继续标 `[recycle]`,不迁回活跃 process |
@@ -1111,7 +1111,7 @@ MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-sm
2026-05-14 N1 执行证据:
- [x] `rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first|/api/ai-agent/run|provider=hermes" design --glob '*.md'` 已跑完,活跃命中已逐项归类。
- [x] 活跃命中主要落在 `design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md``design/05-editor-mainline/process/5-9-wolai-aline-continuous-checklist-v1.md``design/10-review/04-secondary-domains-and-design-governance-review.md``design/10-review/06-execution-checklist-and-acceptance.md``design/01-tree-first-graph-kernel/process/1-1-tree-first-graph-kernel-checklist-v2.md``design/03-rust-web/process/3-1-rust-web-long-term-checklist-v2.md``design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md``design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md``design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md``design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`
- [x] 活跃命中主要落在 `design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md``design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md``design/10-review/04-secondary-domains-and-design-governance-review.md``design/10-review/06-execution-checklist-and-acceptance.md``design/01-tree-first-graph-kernel/reference/1-1-tree-first-graph-kernel-checklist-v2.md``design/03-rust-web/reference/3-1-rust-web-long-term-checklist-v2.md``design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md``design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md``design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md``design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`
- [x] `design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md` 与同目录旧稿继续保留 `[recycle]`,只作为历史证据。
- [x] 本轮对 `5-6``5-9``10-review/04``10-review/06``1-1``3-1` 的旧口径改写已完成;活跃文档现已统一为 Hermes 页面内客户端 + mnote Hermes plugin/tool 口径。
- [x] 本文件仍保留在 `process/`,原因是它是执行清单而不是代码实现文件;若后续需要归档,可按 `N1.5` 的规则移动并同步更新引用。
@@ -6,7 +6,9 @@
>
> Hermes Web UI 参考:`packages/client/src/api/hermes/plugins.ts`、`packages/client/src/api/hermes/skills.ts`、`packages/server/src/services/hermes/plugins.ts`、`packages/server/src/services/hermes/chat-run-socket.ts`
>
> 2026-05-16 口径补充:本文定义的是页面 AI 最小可用工具合同。`mnote.page.save` 只作为页面级兜底写入工具,不再代表长期精确块编辑方案;页面/块级 AI 工具体系路线图已归档到 `design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`,执行验收继续以 `design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md` 为准
> 2026-05-16 口径补充:本文定义的是页面 AI 最小可用工具合同。`mnote.page.save` 只作为页面级兜底写入工具,不再代表长期精确块编辑方案;页面/块级 AI 工具体系路线图已归档到 `design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`。
>
> 2026-05-22 归档治理补充:旧 `7-10` 已移入 `design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`,不再作为当前执行验收入口;`7-14` 也已移入 `design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`。当前 AI 编辑 active 口径以 `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md` 为准,MNote 不再提供普通 Markdown 编辑工具。
## 1. 总边界
@@ -7,9 +7,9 @@
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`
@@ -20,12 +20,12 @@
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-13-page-block-identity-and-command-contract-v1.md`
> - `/mnt/Data1T/mnote/design/02-convex-rust-long-term-architecture/done/2-1-page-block-storage-projection-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-8-page-ai-hermes-runtime-bff-next-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
---
@@ -964,7 +964,7 @@ Rust 内部结构化文档模型,是 PageXML/PageMarkdown 到 Page Aggregate /
本文作为页面/块 AI 工具体系路线图与合同已经归档为 `DONE`;执行验收不再由本文继续承接,而是转入:
- `/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
- `/mnt/Data1T/mnote/design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
当前已成立的 done 边界:
@@ -1,488 +0,0 @@
# 7-10 [process] 页面块 AI 工具执行 checklist v1
> 更新时间:2026-05-16
>
> 当前状态:`PROCESS`。
>
> 关联文档:
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-13-page-block-identity-and-command-contract-v1.md`
> - `/mnt/Data1T/mnote/design/02-convex-rust-long-term-architecture/done/2-1-page-block-storage-projection-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
---
## 1. 目的
本 checklist 把 `7-9` 的路线图拆成可验收执行链,避免页面块 AI 工具停留在“工具名已设计、真实页面不可回读”的状态。
## 1.0 执行口径修正(2026-05-16
本文继续作为页面块 AI 工具执行 checklist 保留在 `process/`,不移入 `old/`。但后续所有“页面 AI runtime / fast workflow / planner / apply controller”相关任务必须按 `7-12` 的边界解释:
- Hermes 继续是唯一页面 AI agent runtime。
- mnote 本地层只提供工具路由、工具提示、上下文冻结、dry-run/review、Rust 写入校验和 readback。
- `PageAIIntentParser` 后续读作 `PageAICommandRouter`,输出 `recommendedToolCall`,不维护独立对话 runtime。
- `PageAIOperationPlanner` 后续只构造 tool args 或 dry-run plan,不能绕过 Hermes tool manifest/profile toggle/audit。
- `PageAIOperationValidator` 继续有效,但归属 mnote Rust tool executor / projection validation。
- `PageAIApplyController` 后续应收口为 review session / tool executor / readback controller,不能成为第二套 agent 编排中心。
- 当前 `usedHermesRun=false` 的快路径只能理解为 deterministic shortcut,不代表 mnote 新建长期 agent runtime。
## 1.0.1 当前主路径修正(2026-05-19
`2-2 local-first` 完成后,本文继续保留为页面块 / 结构性工具 checklist,但普通 Markdown 正文编辑主路径已经转为 VSCode-like 文件编辑:
- local-first 普通正文编辑默认给 Hermes / Reasonix 当前文件引用、selection 和 allowed roots,由 agent 使用自身 patch / diff / 文件编辑能力写本地 `.md`
- `mnote.doc.markdown_edit` 是 cloud / remote agent / compat fallback,不再是 local-first 普通 Markdown 编辑唯一主路径。
- `/api/page-ai/block-edit-workflow` 只保留为兼容门面或非 local source 的快捷路径,不作为 local-first 默认主路径。
- `mnote.doc.apply_block_ops` / `mnote.block.*` 保留为结构性块操作辅助,例如块移动、资源块、复杂子块或必须按 blockId 精确处理的场景。
- Phase C 的 review session / streaming apply 仍冻结;本文只继续跟踪基础工具合同、上下文、冲突校验、幂等和审阅面边界。
- 当前 page AI runtime 口径以 `design/02-convex-rust-long-term-architecture/done/2-2-local-first-workspace-convex-control-plane-v1.md``design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md``design/07-ai/process/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md` 为准。
## 1.1 当前执行状态(2026-05-16
已完成并有代码/测试/smoke 证据:
- Page Aggregate 输出 `blockDocument/blockProjectionVersion/projectionSource`
- `mnote.doc.fetch``mnote.doc.find``mnote.block.fetch` 已接入 Hermes tool manifest 与 dispatch。
- `mnote.doc.plan_update` 已提供块级 dry-run 计划和移动阻断诊断。
- `mnote.block.replace``mnote.block.insert_after``mnote.block.move_after` 已通过 Rust `EditorCommand` 生成 canonical content,再经 `page.body.save -> documents:updateContent` 持久化。
- `revision/conflictDetectionKey/revisionRef/idempotencyKey/dryRun` 写入前置约束已接入,并修复 `content_revision` 投影对齐。
- 真实 smoke`/mnt/Data1T/mnote/scripts/task-page-block-ai-tools-smoke.js`,证据位于 `/mnt/Data1T/mnote/tmp/page-block-ai-tools-smoke/mp7xgyqs.json` 与同名截图。
- 页面 AI Runtime `mnote tools` 面板已读取真实 manifest,展示 13 个 mnote tools,并支持当前 Hermes profile 下开关工具。
- `/api/hermes/client/tools/toggle` 已持久化 `mnote.tools.disabled``/api/hermes/tools/mnote/call` 在执行前按 profile 拦截关闭工具,返回 `mnote_tool_disabled`
- Hermes 外部 mnote plugin/skill 已完成,不改 Hermes 应用本体:
- `/home/lix/.hermes/plugins/mnote/plugin.yaml`
- `/home/lix/.hermes/plugins/mnote/__init__.py`
- `/home/lix/.hermes/skills/note-taking/mnote-block-ai/SKILL.md`
- Hermes 外部 plugin schema 已对齐真实块工具参数:`mnote_doc_fetch(scope/detail/format/query/maxBlocks/blockId/selectedBlockIds/allowedTargetBlockIds)``mnote_doc_plan_update(command/blockId/anchorBlockId/content)``mnote_block_fetch(blockId/includeChildren/contextBefore/contextAfter/format)`
- Hermes CLI 真实 plugin 块操作已通过:
- 测试页:`workspaceId=tree_1777430834634_3``documentId=tree_1778915893346_1``suffix=mp80lbze`
- 工具链:`mnote_doc_fetch -> mnote_block_fetch -> mnote_doc_plan_update(dryRun block_replace) -> mnote_block_replace -> mnote_doc_plan_update(dryRun block_insert_after) -> mnote_block_insert_after -> mnote_doc_plan_update(dryRun block_move_after) -> mnote_block_move_after -> mnote_doc_fetch`
- 结果:`finalOrder=["p_1","p_3","ai_block_req_1778916033994_21","p_2"]``finalTexts` 分别为 `Hermes 块插件第一段 mp80lbze``Hermes 块插件第三段 mp80lbze``Hermes 插件插入段 mp80lbze``Hermes 插件替换第二段 mp80lbze``errors=[]`
- 修复点:Hermes 可能把 `doc.fetch` 返回的 projection `payload/contentNodes` 形状传回写工具,`rust/crates/mnote-web/src/hermes_tools/block.rs` 已补齐 `content_to_text` 解析并加单测,避免 replace/insert 写成空段。
- 浏览器回读验证已通过:打开 `http://127.0.0.1:3000/documents/tree_1778915893346_1?workspaceId=tree_1777430834634_3` 后四段目标文本可见,截图 `/mnt/Data1T/mnote/tmp/hermes-plugin-block-ai/mp80lbze-page.png`
- 页面 AI 工具面板浏览器验证:3000 最新 `mnote-web` 进程下 Runtime 面板可见 13 个工具;关闭 `mnote.block.fetch``/api/hermes/client/tools` 显示 `enabled=false/status=disabled`,直接调用 `mnote.block.fetch` 返回 `mnote_tool_disabled`,随后已恢复开启;截图 `/mnt/Data1T/mnote/tmp/page-ai-tools-runtime/mnote-page-ai-tools-runtime-20260516.png`
- 页面 AI context / format focused smoke 已完成:
- 脚本:`/mnt/Data1T/mnote/scripts/task-page-block-ai-context-format-smoke.js`
- 证据:`/mnt/Data1T/mnote/tmp/page-block-ai-context-format-smoke/mp8ddr4n.json`,截图 `/mnt/Data1T/mnote/tmp/page-block-ai-context-format-smoke/mp8ddr4n-page.png`
- 覆盖:`mnote.doc.fetch scope=selection selectedBlockIds=["p_2"] format=page_xml/text``mnote.block.fetch format=page_xml/text`、manifest annotations、`mnote.page.save` destructive/yolo 粗粒度兜底定位、`mnote.doc.apply_block_ops allowedTargetBlockIds` 越界阻断 `mnote_block_target_out_of_scope`
- 边界:`doc.apply_block_ops` 与单个 `mnote.block.*` 写工具的 `allowedTargetBlockIds` selection scope guard 均已完成矩阵验证。
- 页面 AI 快速块编辑第一阶段已完成:
- 新增 `/api/page-ai/block-edit-workflow`,简单块增删改不再默认进入 Hermes agent run。
- 对明确中文指令 `把「A」替换为「B」/ 在「C」后插入「D」/ 删除「E」` 已先由 mnote 本地 planner 生成 `mnote.doc.apply_block_ops` operations;无法解析时才进入小模型 operations 路径。
- 快路径失败时,除 `page_ai_workflow_not_block_edit` 外不再自动 fallback 到 `/api/hermes/client/runs`,避免一次请求叠加“快路径失败成本 + Hermes agent 成本”。
- 真实浏览器 smoke`/mnt/Data1T/mnote/scripts/task-page-ai-block-edit-workflow-smoke.js`,最新证据 `/mnt/Data1T/mnote/tmp/page-ai-block-edit-workflow-smoke/mp86uciu.json`
- 验证结果:`pageAiWriteVisible=788ms``usedFastWorkflow=true``usedHermesRun=false`;后端日志 `operation_source=local_rule``model_ms=0``apply_ms=42``total_ms=42`
- 详细 review 历史快照:`/mnt/Data1T/mnote/design/10-review/done/09-page-ai-fast-block-edit-runtime-review.md`
仍未完成,本文继续留在 `process/`
- 剩余真实页面 smoke 已由 `/mnt/Data1T/mnote/design/07-ai/done/7-16-page-block-ai-real-smoke-followup-matrix-v1.md` 完成并归档;本文只保留总 checklist、历史证据和 Phase 8 / Review Mode 冻结缺口。
- 复杂块移动阻断矩阵已补隔离 route smoke 覆盖标题带子块、列表项、表格、mindmap/resource;真实浏览器页面 smoke 仍未补。
- 持久审阅/preview UI 仍是后续可选项;当前默认 yolo 模式不做写入审批,`scope=selection``format=page_xml/text` 已进入工具与 PageAIContextBuilder 首版。
- PageAIIntentParser / PageAIOperationPlanner / PageAIOperationValidator / PageAIApplyController 仍需继续建设;当前本地 planner 只覆盖低歧义文本块增删改,不应被视为完整 AI 编辑 runtime。
执行顺序固定为:
```text
fetch/find
-> block.fetch
-> plan_update
-> block.replace
-> block.insert_after
-> block.move_after
```
每一步都必须满足:
- Rust command 或 projection 有测试。
- Hermes tool 有结构化返回。
- 真实页面 smoke 通过。
- 写入后能通过 Page Aggregate 与 AI fetch 回读。
---
## 2. Phase 0:设计与基线冻结
- [x] `5-13` 已冻结 block identity、command、Tiptap boundary。
- [x] `2-1` 已冻结 `documents.content``blocks` 表、Page Aggregate、revision/conflict key 的关系。
- [x] `7-9` 已更新 Tiptap AI Toolkit 对照,不再写成“Tiptap 没有官方 AI 文档工具”。
- [x] `7-9` 明确 `mnote.page.save` 是粗粒度兜底,不是精确块工具。
- [x] 当前 reference code 已在 `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/tiptap-docs``tiptap-main` 可读。
验收:
- [x] `rg -n "Tiptap AI Toolkit|tiptapRead|tiptapEdit|UniqueID|_hash|blockDocument" design/05-editor-mainline/{process,done} design/02-convex-rust-long-term-architecture/{process,done} design/07-ai/{process,done}` 能找到对应设计。
---
## 3. Phase 1Page Aggregate Block Projection
目标:
> 每个可编辑块都能从 Page Aggregate 读到稳定身份和冲突辅助信息。
任务:
- [x] `PageBody` 增加 `blockDocument` 或等价稳定字段。
- [x]`documents.content` 生成 `EditorBlockDocument`
- [x] 从 Tiptap JSON 生成 `EditorBlockDocument` 的 bridge 测试覆盖当前主类型。
- [x] 每个块输出 `blockId/type/text/attrs/children/parentBlockId/order/path/depth/revisionRef/editable`
- [x] 对无 id legacy block 生成稳定迁移策略或 warning。
- [x] 复杂块输出 `editable=false` 或受限能力。
验证命令:
```bash
cargo test -p core-protocol editor_tiptap_bridge
cargo test -p bridge-runtime editor_document
```
真实页面 smoke
- [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 补充真实页面 smoke 证据:
- 最新证据:`tmp/page-block-ai-tools-smoke/mpag4966.json`Page Aggregate`tmp/hermes-tester/page-block-ai-tools-mpag4966/page-aggregate.json`,截图:`tmp/page-block-ai-tools-smoke/mpag4966-page.png`
- 覆盖:Page Aggregate `blockProjectionVersion=1``projectionSource=documents.content``aggregateBlockCount=10`,与 `mnote.doc.fetch` 块顺序一致;刷新后 `afterRefreshBlockIds` 保持最终顺序;`table_1/mindmap_1/resource_1` 返回 `editable=false``unsupportedReason=复杂块暂不开放 AI 精确写入`
---
## 4. Phase 2`mnote.doc.fetch` / `mnote.doc.find`
目标:
> AI 能先读取和定位,不需要猜整页 `content` shape。
任务:
- [x] tool manifest 增加 `mnote.doc.fetch`
- [x] tool manifest 增加 `mnote.doc.find`
- [x] `doc.fetch` 支持 `scope=full/outline/keyword/block/selection`
- [x] `doc.fetch` 支持 `detail=simple/with_ids/full`
- [x] `doc.find` 支持按 text/type/blockId 查找。
- [x] 返回 page `revision/conflictDetectionKey`
- [x] 返回可直接传入 `block.fetch/replace/insert_after``blockId`
验证命令:
```bash
cargo test -p mnote-web hermes_tools
cargo test -p bridge-runtime doc_find
```
真实页面 smoke
- [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`
补充 smoke 证据:
- [x] `mnote.doc.fetch scope=selection selectedBlockIds=["p_2"] format=page_xml` 读取真实页面选区上下文,只返回 `p_2`,返回 `schema=mnote.page_ai_context.v1``allowedTargetBlockIds=["p_2"]``revision/conflictDetectionKey` 和 block `revisionRef`。证据:`tmp/page-block-ai-context-format-smoke/mp8ddr4n.json`
- [x] `mnote.doc.fetch scope=selection format=text` 只返回 `[p_2] 第二段 mp8ddr4n`,不包含未选中块。证据:`tmp/page-block-ai-context-format-smoke/mp8ddr4n.json`
通过标准:
- [x] 不读取浏览器 DOM。
- [x] `doc.find` 返回的 block id 能被 `block.fetch` 读取。
- [x] 大页面默认分块或限制输出,不默认返回无限正文。
2026-05-18 补充证据:
- `mnote.doc.fetch``aggregate_value` / Page Aggregate block projection 构造上下文,不读取浏览器 DOM;代码入口:`rust/crates/mnote-web/src/hermes_tools/doc.rs`
- `hermes_tools_doc_find_and_block_fetch_use_block_projection` 覆盖 `doc.find` 返回 `heading_1` 后继续用同一个 id 调 `mnote.block.fetch`
- `mnote.doc.fetch` 默认 `maxBlocks=120`,运行时 clamp 到 `1..=240`;超限返回 `truncated/continuation/warnings`
- 真实 3000 smoke`tmp/page-block-ai-tools-smoke/mpaes2hg.json` 覆盖 `doc.fetch full` 读取 `heading_1/p_1/p_2/p_3``doc.fetch outline` 只返回 `heading_1``doc.find` 定位 `p_2``maxBlocks=2` 返回 `truncated=true`
---
## 5. Phase 3`mnote.block.fetch`
目标:
> AI 能读取单块、子块和同父级上下文,形成写入前确认。
任务:
- [x] tool manifest 增加 `mnote.block.fetch`
- [x] 支持 `includeChildren`
- [x] 支持 `contextBefore/contextAfter`
- [x] 支持 `format=json/markdown/page_xml/text`
- [x] 返回 `revisionRef``editable``unsupportedReason`
- [x] 不存在 block 返回 `mnote_block_not_found`
验证命令:
```bash
cargo test -p mnote-web block_fetch
```
真实页面 smoke
- [x]`doc.find` 结果选择一个段落 block。
- [x]`mnote.block.fetch includeChildren=true contextBefore=1 contextAfter=1`
- [x] 断言 before/after 只来自同父级。
补充 smoke 证据:
- [x] `mnote.block.fetch blockId=p_2 format=page_xml/text contextBefore=1 contextAfter=1` 返回目标块 `p_2``revisionRef` 与同父级 before/after `p_1/p_3`。证据:`tmp/page-block-ai-context-format-smoke/mp8ddr4n.json`
- [x] `doc.find` 定位 `p_2` 后,`mnote.block.fetch includeChildren=true contextBefore=1 contextAfter=1` 回读 `p_2`,返回 `revisionRef`、同父级 before `p_1` 和 after `p_3`。证据:`tmp/page-block-ai-tools-smoke/mpag4966.json`
- [x] `table_1/mindmap_1/resource_1` 复杂块在真实 3000 smoke 中返回 `editable=false``unsupportedReason=复杂块暂不开放 AI 精确写入`。证据:`tmp/page-block-ai-tools-smoke/mpag4966.json`
通过标准:
- [x] block 文本与页面显示一致。
- [x] `revisionRef` 可被后续 dry-run 使用。
- [x] 复杂块不会伪装成完全可编辑。
---
## 6. Phase 4`mnote.doc.plan_update`
目标:
> 所有写入先 dry-run,返回 diff、warnings、risk,不改变页面。
任务:
- [x] tool manifest 增加 `mnote.doc.plan_update`
- [x] 支持 `command=block_replace`
- [x] 支持 `command=block_insert_after`
- [x] 支持 `command=block_move_after` dry-run。
- [x] `command=str_replace` 不再作为本 checklist 当前目标;cloud / remote / compat 的普通正文 search/replace 已收口到 `mnote.doc.markdown_edit`,多重匹配/无法安全映射阻断由 markdown_edit 合同覆盖。local-first 普通 Markdown 编辑默认走授权文件 + agent 原生 patch/diff。
- [x] 缺少 `revision/conflictDetectionKey` 时只允许 dry-run。
- [x] 返回 `planId``diff``warnings``risk``blocked`
2026-05-19 口径修正:
- `7-18``7-25` 收口后,普通正文替换不再继续扩 `mnote.doc.plan_update command=str_replace`compat 实现路径是 `page_ai_workflow.rs -> mnote.doc.markdown_edit`
- `mnote.doc.markdown_edit` 已覆盖精确匹配、归一化匹配、多操作同块合并、无法安全映射时失败;相关测试由 `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocapture` 覆盖。它不再代表 local-first 普通 Markdown 编辑默认入口。
验证命令:
```bash
cargo test -p mnote-web plan_update
cargo test -p bridge-runtime doc_replace_range
cargo test -p bridge-runtime doc_insert_blocks
```
真实页面 smoke
- [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 补充真实页面 smoke 证据:
- 最新证据:`tmp/page-block-ai-tools-smoke/mpag4966.json`,截图:`tmp/page-block-ai-tools-smoke/mpag4966-page.png`
- 覆盖:`plan_update.dry_run.replaceDiff.before/after``insertDiff.after/content``block_move_after p_3 -> p_1 dryRun` 不阻断、不支持 `p_3 -> p_3` 返回 `blocked=true`、dry-run 后 revision / Page Aggregate conflictDetectionKey / 正文文本不变。
---
## 7. Phase 5`mnote.block.replace`
目标:
> 第一条最小精确块写入闭环。
任务:
- [x] tool manifest 增加 `mnote.block.replace`
- [x] 输入必须包含 `blockId/revision/conflictDetectionKey/idempotencyKey/dryRun`
- [x] `dryRun=true` 只返回 plan。
- [x] `dryRun=false` 生成 `EditorCommand::ReplaceBlock`
- [x] Rust 应用命令生成 canonical content。
- [x] 通过 `page.body.save -> documents:updateContent` 持久化。
- [x] 返回新 revision、changedBlocks、audit。
验证命令:
```bash
cargo test -p mnote-web block_replace
cargo test -p bridge-runtime doc_replace_range_tool_executes_in_rust_runtime
```
真实页面 smoke
- [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 补充真实页面 smoke 证据:
- 最新证据:`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`,相邻块仍为 `第一段 mpag4966` / `第三段 mpag4966`,最终 `mnote.doc.fetch` 与 Page Aggregate 均回读到 `第二段已替换 mpag4966`Page Aggregate `aggregateRevision=2``aggregateConflictDetectionKey=tree_1779062903017_3:2`
- 冲突 / 幂等补充证据:`tmp/page-block-ai-conflict-idempotency-smoke/mpafrevs.json`,截图:`tmp/page-block-ai-conflict-idempotency-smoke/mpafrevs-page.png`
- 覆盖:首次 `block.replace` 携带最新 `revision/conflictDetectionKey/blockRevisionRef/idempotencyKey` 成功写入;重复同一 `idempotencyKey` replay 同一 `commandId` 且 revision 不再次递增;旧 `revision/conflictDetectionKey` 与旧 `blockRevisionRef` 均返回 HTTP `400` / `mnote_tool_conflict`,正文保持首次替换结果。
---
## 8. Phase 6`mnote.block.insert_after`
目标:
> AI 能在指定块后插入新块,并拿到新 block id。
任务:
- [x] tool manifest 增加 `mnote.block.insert_after`
- [x] 输入必须包含 `anchorBlockId/revision/conflictDetectionKey/idempotencyKey/dryRun`
- [x] 新块 id 由 Rust runtime 分配。
- [x] 支持单块和最多 20 个普通块插入。
- [x] 第一阶段支持 paragraph/heading/todo。
- [x] 返回 inserted block ids 和新 revision。
2026-05-18 补充证据:
- `rust/crates/mnote-web/src/hermes_tools/block.rs``mnote.block.insert_after` 已支持 `content` / `block` 单块兼容输入,以及 `blocks` 数组输入。
- `blocks` 运行时限制为 `1..=20`,超过 20 个返回 `mnote_tool_bad_request`;多块写入按输入顺序连续插在 anchor 后。
- `rust/crates/mnote-web/src/hermes_tools/manifest.rs` 的 manifest 已将 `content | block | blocks` 写为 `anyOf`,并声明 `blocks.minItems=1/maxItems=20`
- 新增回归:`hermes_tools_block_insert_after_accepts_multiple_blocks_and_returns_ids``hermes_tools_block_insert_after_rejects_more_than_twenty_blocks`
验证命令:
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block_insert_after -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocapture
cargo test -p bridge-runtime doc_insert_blocks_tool_emits_editor_commands
```
真实页面 smoke
- [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 补充证据:
- `mnote.block.insert_after` 运行时分配 `ai_block_{request_id}` 或多块 `ai_block_{request_id}_{index}`,不会采用模型输入中的未校验 id。
- `hermes_tools_block_insert_after_accepts_multiple_blocks_and_returns_ids` 断言返回的 `insertedBlockIds` 均以 `ai_block_` 开头。
- 真实 3000 smoke`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` 通过。
- 最新证据:`tmp/page-block-ai-tools-smoke/mpag4966.json`,截图:`tmp/page-block-ai-tools-smoke/mpag4966-page.png`
- 覆盖:`insert_after` 插入 `todo` 块、`orderAfterInsert=["heading_1","p_1","ai_block_req_1779061213631_259","p_2","p_3"]``block.fetch` 可读取新块、重复 `idempotencyKey` replay 同一 `commandId` 且 revision 不再次递增、刷新后插入文本仍可见。
---
## 9. Phase 7`mnote.block.move_after`
目标:
> 第一阶段只开放同父级普通叶子块移动。
任务:
- [x] tool manifest 增加 `mnote.block.move_after`
- [x] `dryRun=true` 支持同父级叶子块 diff。
- [x] `dryRun=false` 前先继续阻断所有复杂块。(已有同父级/叶子/类型/editable/self 阻断,复杂块矩阵 route smoke 已补。)
- [x] 检查 `blockRevisionRef``anchorRevisionRef`
- [x] 阻断移动到自身、移动到子树、跨页面移动。
- [x] 返回 from/to parent/order。
2026-05-18 补充证据:
- `mnote.block.move_after` 保持同父级、叶子块、可移动类型、editable、自身移动阻断条件。
- 新增隔离 fixture route smoke`hermes_tools_block_move_after_blocks_complex_and_nested_blocks`,覆盖标题带子块、列表项、表格、mindmap、resource,均返回 `blocked=true``block_move_after_blocked`
验证命令:
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block_move_after_blocks_complex_and_nested_blocks -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocapture
cargo test -p mnote-editor-core command_executor
```
真实页面 smoke
- [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 补充真实页面 smoke 证据:
- 最新证据:`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` 且正文不变化;普通 `block.move_after.dryRunBlocked=false`,正式写入后顺序为 `heading_1,p_1,p_3,ai_block_...,p_2,...``movingBlockStillExists=true`
---
## 10. Phase 8UI 与 Review Mode
目标:
> AI 写入可解释、可确认,不把 preview 当持久审阅事实。
任务:
- [ ] Hermes tool event UI 展示 `plan/diff/warnings/risk`
- [x] `page.save` 标记为粗粒度高风险兜底。
- [x] `block.replace/insert_after/move_after` 展示 changedBlocks。
- [x] manifest annotations 能区分只读 / 粗粒度破坏性写入 / selectionEffect / runtimeOwner / writeOwner`mnote.page.save` 在 manifest 中为 `destructive=true``approvalMode=yolo`,不作为精确块编辑主入口。证据:`tmp/page-block-ai-context-format-smoke/mp8ddr4n.json`
- [ ] 本地 preview/suggestion 与持久 comment/tracked-change 分开。
- [ ] 协作可见审阅必须另走正式 comment/history/tracked-change 设计。
通过标准:
- [ ] 用户能看到 AI 将改哪个 block。
- [ ] `blocked=true` 的工具调用不会出现写入按钮。
- [ ] preview 不写入正式 comment/history。
---
## 11. DONE 条件
本 checklist 不能移动到 `done/`,直到:
- [x] Phase 1 到 Phase 6 全部完成。
- [x] Phase 7 至少完成 dry-run 和阻断规则;若真实 move 未完成,`7-9` 必须仍标注受限。
- [x] 每个写工具都有真实页面 smoke 证据。
- [x] 失败项已经写入 `bugs/07-ai/process/` 或真实 owner 分类。
- [x] `mnote.page.save` 不再被任何设计描述为精确块编辑主入口。
- [ ] Phase 8 UI / Review Mode 仍按 Phase C 边界冻结;若后续进入实施,需要另补 UI smoke。
@@ -1,751 +0,0 @@
# 7-14 [process] 在线 / 本地文档 AI Markdown 编辑路径收敛 v2
> 创建时间:2026-05-16
>
> 更新时间:2026-05-16v3:深度参考 CLI Main skill 系统,补全成熟度采纳清单)
>
> 2026-05-18 口径补充:
> - local-first workspace 已成为早期产品默认形态;本地 `.md` 是默认 AI 编辑目标,在线 Convex 文档降级为可选 cloud / sync / share source。
> - 本文早期把 `mnote.doc.markdown_edit` 描述为统一主路径;最新口径改为:local-first 普通 Markdown 编辑优先给 agent 授权文件引用,由 agent 使用自身成熟的 diff / apply_patch / 文件编辑能力完成;`mnote.doc.markdown_edit` 保留为 cloud / remote agent / compat fallback。
> - 页面内图片 / 附件上传已在 local source 下写入 `{mdBase}.assets/` 并保存相对 Markdown 路径,AI 后续处理附件引用时也应保留相对路径,不改写为 Convex media asset。
>
> 当前状态:`PROCESS`
>
> 本稿目的:
> 1. 纠正 7-9 / 7-10 / 7-12 / 7-13 中隐含的「块级编辑是 AI 唯一写入路径」假设
> 2. 基于 CLI Main 参考实现,确立 mnote 的「agent 原生文件 patch/diff 为 local-first 默认路径,MNote 文本级兼容工具 + 块级结构性操作为 fallback / 辅助」两层模型
> 3. 规划 BlockNote AI 流式/review 能力的远期方向(当前不实施)
> 4. 统一 cloud / remote / compat 文档和本地 `.md` 文件的 AI 读取、权限、冲突与回读口径
>
> 关联文档:
> - `/mnt/Data1T/mnote/design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`
> - `/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/07-ai/done/7-13-page-block-editor-runtime-actor-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-13-rust-web-local-markdown-gfm-ast-parser-migration-v1.md`
> - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-22-local-folder-convex-unified-tree-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/bugs/07-ai/process/page-ai-block-edit-model-fallback-missing-content.md`
>
> 参考实现(已分析):
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/cli-main/` — **主参考**skill 系统、scope/detail 上下文、两层操作、工作流、参考文件模式、CI 校验
> - `skills/lark-doc/SKILL.md` + `references/`
> - `skill-template/`master-skill-template.md、skill-template.md
> - `shortcuts/doc/`、`internal/skillscheck/`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocknote-ai/packages/xl-ai/` — 远期参考:流式/review
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/tiptap-ai-autocomplete/` — 独立功能:内联补全
>
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
---
## 1. 结论
**在线 Convex 文档和本地 `.md` 文件本质上是同一个东西:一段 markdown 文本,Tiptap 只是块级 UI 表现层。** 进一步切到 local-first 后,本地 `.md` 已经是普通文件,因此不需要再为常规正文编辑发明一套 MNote 专用工具。当前 07-ai 设计把 AI 编辑契约钉死在 `EditorBlockDocument` 的块级操作上,导致三个连锁问题:
1. **AI 被迫在块级操作**:对「改写这段话」「补充一段总结」「调整语气」「把所有 TODO 改成 DONE」等自然请求,AI 必须产出 `{ op: "replace", blockId: "block_1", ... }` 格式的块操作,而不能直接产出修改后的文本或搜索替换对。这增加了 AI 的认知负担和出错概率。
2. **本地 `.md` 文件没有 AI 能力**:本地文件没有稳定的 `blockId`(每次解析重新分配),因此块级工具无法应用于本地文件。当前 Hermes 的 13 个工具没有一个是面向本地文件的。
3. **两套口径维护**:在线文档(块操作)和本地文档(无 AI 路径)长期走两套路径,维护成本翻倍。
### 参考实现的验证
分析了三个参考实现后,确认 mnote 的方向是正确的:
| 参考实现 | AI 编辑模型 | mnote 采纳 |
|----------|-----------|-----------|
| **CLI Main (Lark Doc)** | 文本级 `str_replace` + 块级 `block_replace/insert_after/delete/move_after` 两层操作 | ✅ **主参考**:两层模型 + AI skill 合同设计 |
| **BlockNote AI** | 纯块级 `add/update/delete`(依赖 blockId),流式 apply + suggest/review | ✅ **远期参考**:流式/review 能力,Phase C 规划 |
| **Tiptap AI Autocomplete** | 纯文本补全,单句接龙,无工具 | ⏳ 独立功能:内联 AI 补全(非本文讨论范围) |
**CLI Main 最关键的设计决策**:它不把 AI 钉死在某一层。`str_replace` 用于文本级修改(不需要 blockId),`block_*` 用于精确块结构调整。格式上,**XML 用于精确编辑场景,Markdown 用于整篇导入/导出**。mnote 的不同之处在于:local-first 之后,默认对象就是本地 `.md` 文件,因此可以直接复用 Codex / Hermes / Reasonix 自身成熟的 diff、apply_patch、文件编辑能力;MNote 的职责收口为权限沙箱、文件引用解析、审计和刷新。
### 正确方向
> mnote 的 AI 编辑路线:**本地授权文件 + agent 原生 patch/diff 为主;MNote 兼容工具为 cloud/remote/结构化辅助;BlockNote AI 的流式/review 只作为远期交互参考。**
具体:
- **当前实施**Phase A/B):local-first 页面 AI 只传当前文件引用、可选 selection 和用户指令;MNote 校验 `AiAccessScope` 后让 agent 在受限目录中使用原生 patch/diff 编辑 `.md``mnote.doc.markdown_edit` 作为兼容 / 远端代理 fallback,`mnote.block.*` 作为复杂结构辅助。
- **远期规划**Phase C):BlockNote AI 的流式增量 apply + suggest/review 层。当前先设计,不实施。
---
## 2. 参考实现详解
### 2.1 CLI MainLark Doc)— 两层操作模型
CLI Main 的 `skills/lark-doc/SKILL.md` 是飞书文档的 AI skill 定义。它把文档操作分成两层:
**文本级操作**(不需要 blockId):
```
docs +update --command str_replace --search "原文片段" --replace "新文本"
```
AI 只需要匹配文本,不需要知道块在哪儿。适用于所有内容修改场景。
**块级操作**(需要 blockId):
```
docs +update --command block_replace --block-id "block_1" --content "<xml>...</xml>"
docs +update --command block_insert_after --block-id "block_1" --content "<xml>...</xml>"
docs +update --command block_delete --block-id "block_1"
docs +update --command block_move_after --block-id "block_3" --target-block-id "block_1"
```
适用于精确块结构调整。AI 需要知道 `blockId`,因此依赖前置的 `docs +fetch` 返回带 id 的内容。
**格式选择规则**CLI Main 的 skill 中内联):
| 场景 | 格式 | 原因 |
|------|------|------|
| 精确块编辑(替换/插入/删除指定块) | XML | XML 保留块 id、类型、属性 |
| 整篇文档导入/导出 | Markdown | 人类可读,和 `.md` 文件互通 |
| AI 对话中的内容引用 | Markdown | 模型理解 markdown 远好于 XML |
**对 mnote 的启示**
1. **两层操作模型直接适用**。mnote 的 `markdown_edit` = CLI Main 的 `str_replace`(文本级),`apply_block_ops` = CLI Main 的 `block_*`(块级)。
2. **但 mnote 的主格式是 markdown 而非 XML**。在线文档的持久化格式(Convex `documents.content`)可以投影为 markdown,本地文件本身就是 markdown。所以我们不需要 XML 这一层——markdown 既是 AI 编辑格式,也是人类可读格式。
3. **CLI Main 的 skill 格式**YAML frontmatter + Markdown body,定义 tool shortcuts + 上下文格式规范)值得学习。mnote 的 Hermes `mnote` plugin 可以用类似方式组织。
#### 2.1.1 Skill YAML 前端元数据
> 参考文件:`skill-template/master-skill-template.md`、`skill-template/skill-template.md`、`scripts/skill-format-check/index.js`
每个 skill 文件以 YAML frontmatter`---` 包裹)开头:
```yaml
---
name: lark-doc
description: "飞书云文档 / Docx / 知识库 Wiki 文档(v2):创建、打开、读取..."
metadata:
requires:
bins: ["lark-cli"]
cliHelp: "lark-cli docs --api-version v2 --help; ..."
---
```
CI 自动化校验(`skill-format-check.yml` + `scripts/skill-format-check/index.js`)确保 `name``description` 必填。
**→ mnote 采纳**Hermes 的 `mnote` plugin 已采用 YAML frontmatter`/home/lix/.hermes/plugins/mnote/plugin.yaml`)。在此基础上规范化:
- `name``mnote`
- `description`:一段完整的 skill 描述,含覆盖的工具和适用场景
- `metadata.domain``mnote-doc`(文档域),后续可扩展 `mnote-tree``mnote-file`
- CI 校验:确保每个 plugin 的 `plugin.yaml` 含必填字段
#### 2.1.2 Scope / Detail 上下文控制
> 参考文件:`skills/lark-doc/references/lark-doc-fetch.md`、`shortcuts/doc/docs_fetch_v2.go`
CLI Main 的 `docs +fetch` 支持五个 `--scope` 级别,精确控制注入 AI 上下文的文档量:
| `--scope` | 返回内容 | AI 场景 |
|-----------|---------|--------|
| `outline` | 标题树(h1-hN+ blockId | "给我看目录" |
| `section` | 指定标题下的完整节 | "精读第三章" |
| `range` | blockId 区间 | "给我 100-200 行" |
| `keyword` | 关键词周围最小片段 | "找提到 deployment 的地方" |
| `full`(默认) | 全文 | 最后手段 |
三个 `--detail` 级别控制元数据量:
| `--detail` | blockId | 样式属性 | AI 场景 |
|-----------|---------|---------|--------|
| `simple` | ❌ | ❌ | 只读、总结 |
| `with-ids` | ✅ | ❌ | 需要精确寻址时 |
| `full` | ✅ | ✅ | 即将编辑该节 |
片段包装:`<fragment requested-start="..." requested-end="...">``<excerpt top-block-id="..." parent-block-path="...">` 标记告知 AI"这是部分视图,非完整块"。
**→ mnote 采纳**(高优先级):
```
mnote.doc.fetch({
scope: "section" | "outline" | "keyword" | "full",
detail: "simple" | "with_ids" | "full",
format: "markdown",
maxChars: 8000
})
```
- `scope` 的四级映射:outline(标题树)、section(当前节)、keyword(搜索关键词)、full(全文)
- `detail` 的三级映射:simple(纯文本)、with_ids(带块标记)、full(带属性)
- 片段包装:markdown 中用 `<!-- fragment: section "标题" -->` 注释标记部分视图边界
- 实现位置:`mnote-web``mnote.doc.fetch` handler
#### 2.1.3 更新工作流:Code-Act Loop
> 参考文件:`skills/lark-doc/references/style/lark-doc-update-workflow.md`
CLI Main 的文档编辑遵循 **Plan → Execute → Observe → Iterate** 四步循环:
```
1. Plan(先读后改):
docs +fetch --scope section --detail full
→ 分析当前状态 → 制定操作序列
2. Execute(精准手术,不全量覆盖):
默认用 str_replace / block_insert_after / block_delete
block_move_after 用于重排
overwrite 仅在有明确指令时使用
append + block_delete 组合优于 overwrite
3. Observe(每次写后回读):
docs +fetch --scope section
→ 确认修改正确
4. Iterate(修复差异):
如发现偏差 → 回到 Plan
```
更新命令决策树:
```
需要修改文本内容(不改块结构)?
→ str_replace(文本级,不需要 blockId
需要整段替换?
→ block_replace --block-id xxx(需要先 fetch --detail with_ids
需要插入/删除?
→ block_insert_after / block_delete
需要重排结构?
→ block_move_after / block_copy_insert_after
```
**→ mnote 采纳**(当前 Hermes 的 `mnote` plugin 应内置此工作流):
- Hermes `mnote` skill 的 `SKILL.md` 中内联 Code-Act Loop 指导
- `mnote.doc.markdown_edit`(文本级搜索替换)优先于 `mnote.doc.apply_block_ops`(块级精确操作)
- 模型 system prompt 追加:"永远不要在不确定时使用全文覆盖;优先搜索替换;每次写入后回读确认"
#### 2.1.4 参考文件分离模式
> 参考文件:`skills/lark-doc/references/`24 个独立 .md 文件)
CLI Main 把详细工具规格从主 `SKILL.md` 中分离到 `references/` 子目录:
```
skills/lark-doc/
SKILL.md ← 技能概述 + 决策表 + 路由规则
references/
lark-doc-fetch.md ← fetch 工具详细规格
lark-doc-update.md ← update 工具详细规格
lark-doc-xml.md ← XML 块语法参考
lark-doc-md.md ← Markdown 格式规则
style/
lark-doc-update-workflow.md ← 编辑工作流
lark-doc-style.md ← 写作风格指南
```
**→ mnote 采纳**Hermes `mnote` plugin 应采用相同结构:
```
~/.hermes/plugins/mnote/
plugin.yaml ← YAML 前端元数据
SKILL.md ← 技能概述 + 工具决策表
references/
mnote-doc-fetch.md ← fetch 详细规格(scope/detail/format
mnote-doc-update.md ← 更新命令规格(search/replace + block ops
mnote-doc-workflow.md ← Code-Act Loop
mnote-doc-context.md ← 上下文冻结与格式化规则
```
#### 2.1.5 跨域资源路由
> 参考文件:`skills/lark-doc/SKILL.md`(嵌入式资源路由表)
CLI Main 的 lark-doc skill 定义了嵌入式资源的显式路由表:
```
| 嵌入标签 | 提取字段 | 代理 skill |
|-----------------------------|--------------------------|---------------|
| <sheet token="..." ...> | token → spreadsheet_token | lark-sheets |
| <bitable token="..." ...> | token → app_token | lark-base |
| <whiteboard token="..."> | board_token | lark-whiteboard|
```
**→ mnote 采纳**(远期,当文档内嵌入其他资源类型时):
- 在线文档中嵌入的思维导图 → 路由到 `mnote-mindmap` skill
- 嵌入的附件/文件 → 路由到 `mnote-file` skill
- 当前 Phase A 不实施,预留路由表字段
#### 2.1.6 格式策略:XML vs Markdown
> 参考文件:`skills/lark-doc/references/lark-doc-xml.md`、`lark-doc-md.md`
CLI Main 的格式选择规则:
| 场景 | 格式 | 原因 |
|------|------|------|
| 精确块编辑 | XML(默认) | 保留 blockId、样式属性、结构 |
| 整篇导入/导出 | Markdown | 人类可读,和 `.md` 互通 |
| AI 对话引用 | Markdown | 模型理解 markdown 远好于 XML |
**→ mnote 采纳**CLI Main 用 XML 做默认格式是因为飞书文档本身是 XML 存储。mnote 的在线文档持久化格式(Convex `documents.content`)和本地文件都是 markdown,因此 markdown 是 mnote 的默认和唯一 AI 格式。这是正确的差异化决策。
#### 2.1.7 Skill CI 校验
> 参考文件:`.github/workflows/skill-format-check.yml`、`scripts/skill-format-check/`
CLI Main 的 CI 自动检查每个 `SKILL.md`
1.`---\n` 开头
2. YAML frontmatter 语法有效
3. `name``description` 必填
4. `metadata` 缺失仅为警告
**→ mnote 采纳**:对 Hermes `mnote` plugin 和所有 `~/.hermes/skills/note-taking/mnote-*/SKILL.md` 执行同等校验。在 CI 中增加 `skill-format-check` 步骤。
### 2.2 BlockNote AI — 流式 apply + suggest/review
BlockNote AI 的 `StreamTool` 实现了一套完整的 AI 编辑体验闭环:
**核心机制**
```
LLM 流式输出 partial JSON
→ StreamToolExecutor 逐 chunk 解析
→ 匹配 operation type → validate → execute
→ ProseMirror 事务逐条 apply(带延迟,模拟"AI 正在打字"
→ suggestChanges 标记 AI 编辑为 suggestion(红绿对比)
→ 用户逐条 accept / reject
→ 确认后才写入持久层
```
**关键组件**
| 组件 | 功能 | mnote 远期对标 |
|------|------|---------------|
| `StreamTool` | 单操作的定义:name + inputSchema + validate + execute | mnote 已有(`mnote.block.*` / `mnote.doc.*`),不需要重构 |
| `StreamToolExecutor` | 流式解析 partial JSON → 逐条 enqueue → 按顺序 execute | Phase C 新增:`StreamApplyController` |
| `suggestChanges` | ProseMirror suggestion marksAI 编辑不直接落盘,先标记为待审阅 | Phase C 新增:在线文档的 `ReviewSession` |
| `RebaseTool` | 协作场景:用户同时在编辑 → AI 操作 rebase 到最新文档状态 | Phase C 考虑(协作场景依赖 Convex 的 revision 乐观锁) |
| `delayAgentStep` | 逐条 apply 之间加 50-200ms 延迟,给用户"AI 正在操作"的可见性 | Phase C 可选改善 |
**BlockNote AI 不适合直接搬的原因**:它的所有操作都通过 `id`blockId)寻址。`add` 需要 `referenceId``update` 需要 `id``delete` 需要 `id`。这意味着:
- 本地 `.md` 文件无法使用(没有稳定 blockId)
- 跨块内容修改("把所有 TODO 改成 DONE")需要模型逐一产出 N 个带 blockId 的操作
- 这和 mnote 的"markdown 优先"方向背道而驰
**但我们可以在 markdown_edit 之上叠加流式/review**Phase C 时,`mnote.doc.markdown_edit` 的 apply 过程可以流式化——逐条 search/replace 执行后推送 BlockDelta,编辑器逐条渲染,用户可逐条撤回。这和 BlockNote AI 的体验效果一致,但底层是文本级操作而非块级操作。
### 2.3 Tiptap AI Autocomplete — 内联补全(独立功能)
纯文本补全器:发送光标前文本 → 返回下一句。不是文档编辑方案。mnote 将来可以考虑作为独立的"内联 AI 补全"功能,和本文讨论的文档编辑工具分开设计。
---
## 3. 当前问题
### 3.1 块级编辑是 AI 的过度抽象
> 参考对照:CLI Main 证明 `str_replace` 足以覆盖大多数 AI 编辑场景,不需要强迫模型理解 blockId。
当前 AI 写入链路的问题不在于技术实现,而在于**模型必须理解 blockId 这个 UI 层的概念**
```
用户: "把第一段改简洁一些"
→ 当前路径:模型 → { op: "replace", blockId: "block_1", content: "..." }
→ 期望路径:模型 → { search: "第一段原文", replace: "改写后文本" }
```
「把文章中所有 TODO 改成 DONE」这类跨块请求,当前需要逐一产出 N 个 `{ op: "replace", blockId: "..." }`。文本级 search/replace 只需一条:`{ search: "TODO", replace: "DONE" }`
### 3.2 本地文件没有 AI 写入路径
> 参考对照:CLI Main 的 skill 可以操作任何 `doc-token`(包括本地文件和云端文档),因为它用的是文本级 + XML 级工具,不依赖特定存储。
mnote 当前:Hermes 只知道 workspace/document 模型,不知道本地文件夹/文件模型。本地 `.md` 文件在 AI 视角完全不可见。
### 3.3 两套体系互不相认
| | 在线 Convex 文档 | 本地 .md 文件 |
|---|---|---|
| 存储 | Convex `documents.content` | 文件系统 `*.md` |
| AI 读取 | `mnote.doc.fetch`block projection | 无 |
| AI 写入 | `mnote.block.*` / `mnote.doc.apply_block_ops` | 无 |
| 写入粒度 | 块级(需要 blockId) | —(无 AI 路径) |
| 设计覆盖 | 07-ai 全部文档 | 仅在 03-rust-web 讨论解析 |
两份体系在设计中互不相认。3-13 写明"不影响 Convex workspace 链路"——这是主动划清界限。**收敛是必须的,markdown 是共同分母。**
---
## 4. 设计原则
### 4.1 Markdown 是 AI 编辑的第一公民
> 参考对照:CLI Main 用 Markdown 做整篇导入/导出和对话引用,用 XML 做精确块编辑。mnote 直接用 Markdown 做所有 AI 操作,因为 mnote 没有 XML 存储层。
AI 最自然的编辑方式是对文本进行操作。块是 UI 概念,不是 AI 概念。在线文档的持久化格式和本地文件的持久化格式都可以投影为 markdown。
### 4.2 两层操作模型(兼容层)
| 层 | 工具 | 寻址方式 | 适用场景 | 占比 |
|----|------|---------|---------|------|
| **文件级(主)** | agent 原生 `diff/apply_patch/文件编辑` | 授权文件引用 / selection | local-first 普通 Markdown 改写 | 80%+ |
| **文本级(兼容)** | `mnote.doc.markdown_edit` | search/replace 文本对 | cloud / remote agent / 兼容旧页面 AI | 次要 |
| **块级(辅助)** | `mnote.doc.apply_block_ops` | blockId / matchText | "把第三块拖到第一块后面"、"精确删除引用块" | <20% |
### 4.3 在线和本地的主写入路径
```
页面 AI / ACP
→ resolve_source(documentId) → Convex | LocalFS
→ local-first: 传授权文件引用给 agent runtime
→ agent 原生 patch/diff 写入文件
→ MNote 做权限 / 审计 / refresh
→ cloud / remote fallback: mnote.doc.markdown_edit
```
差异主要在执行层:local-first 直接让 agent 修改授权文件;cloud 或受限 remote runtime 无法直接访问本地文件时,再走 `mnote.doc.markdown_edit` 代理。这和 CLI Main 的 `docs +update` 可以操作任何 `doc-token` 的设计一致,只是 mnote 进一步把“编辑算法”让渡给 agent runtime。
### 4.4 Diff 是内部实现细节
对兼容 `mnote.doc.markdown_edit` 来说,AI **不**产出 unified diff(行号/上下文极易出错),而是产出两种形式之一:
| 形式 | 适用场景 | AI 负担 |
|------|---------|---------|
| `operations: [{ search, replace }]` | 局部修改 | 低:只需找原文片段 |
| `full_content: "..."` | 小文档全文改写 | 低:直接写完整 markdown |
而在 local-first 主路径中,agent runtime 自己可以安全使用成熟的 diff / apply_patch / 直接文件编辑能力;MNote 只要求这些写入被限制在授权路径内,并把 changed files / diff 摘要收回审计。
---
## 5. 工具合同
### 5.1 `mnote.doc.fetch`(已有,增强)
```json
{
"toolName": "mnote.doc.fetch",
"args": {
"documentId": "tree_xxx 或 /path/to/file.md",
"format": "markdown",
"scope": "full",
"query": "TODO",
"maxChars": 8000
}
}
```
增强点:
- `format: "markdown"` — 新增值。在线文档由 Page Aggregate 产出 PageMarkdown;本地文件直接返回 `.md` 原文。
- `documentId` — 自动检测 sourceConvex workspace 文档 vs 本地文件系统路径。
返回:
```json
{
"ok": true,
"source": "convex",
"documentId": "tree_xxx",
"revision": 3,
"format": "markdown",
"content": "# 标题\n\n段落内容...\n\n## 子标题\n\n...",
"truncated": false,
"charCount": 1234
}
```
### 5.2 `mnote.doc.markdown_edit`(新增,兼容 / fallback
```json
{
"toolName": "mnote.doc.markdown_edit",
"args": {
"documentId": "tree_xxx 或 /path/to/file.md",
"operations": [
{ "search": "原文片段", "replace": "新文本" },
{ "search": "另一段", "replace": "改写后的内容" }
]
}
}
```
服务端处理流程:
```
1. resolve_source(documentId) → ConvexAdapter | LocalFSAdapter
2. 读取当前 markdown 全文
3. 逐条 search_replace(精确匹配 → fuzzy fallback
4. 计算内部 diff(用于 BlockDelta 推送)
5. 写入目标
6. 返回结果
```
返回:
```json
{
"ok": true,
"source": "convex",
"documentId": "tree_xxx",
"revision": { "before": 3, "after": 4 },
"operationsApplied": 2,
"operationsFailed": 0,
"failedOperations": [],
"changedText": "已将「原文片段」替换为「新文本」\n已将「另一段」替换为「改写后的内容」",
"blockDelta": {
"documentId": "tree_xxx",
"revision": 4,
"operations": [...]
}
}
```
### 5.3 `mnote.doc.apply_block_ops`(已有,辅助路径)
保留不变。用于精确块结构调整(拖拽排序、指定 blockId 的精确删除)。在 Hermes tool manifest 中 `markdown_edit` 排在 `apply_block_ops` 前面。
---
## 6. 搜索替换语义
> 参考对照:CLI Main 的 `str_replace` 使用精确子串匹配。mnote 增加 fuzzy fallback 以提高模型输出容错率。
| 优先级 | 策略 | 说明 |
|--------|------|------|
| 1 | 精确匹配 | 原文字串精确匹配,区分大小写 |
| 2 | 宽松匹配 | 忽略首尾空白、全角/半角差异后匹配 |
| 3 | 段落 fuzzy | 按换行分段,每段独立 fuzzy match(允许 30% 字符差异) |
| 4 | 失败 | 返回 `operationsFailed`,列出无法匹配的 search 和原因 |
多条 operation 按数组顺序串行执行。前一条的替换结果对后一条可见(和 sed 语义一致)。
**乐观锁**:执行前用 `revision` 检测。如果写入时 revision 已过期,返回冲突错误,让 AI 重新 fetch + edit。
---
## 7. 远期规划:流式 apply + suggest/reviewPhase C,当前不实施)
> 参考对照:BlockNote AI 的 `StreamToolExecutor` + `suggestChanges` + `delayAgentStep`。本节仅做设计规划,不列入当前实施阶段。
### 7.1 目标
当用户通过页面 AI 面板发起编辑后,不是等所有操作完成后一次性刷新,而是:
1. AI 逐条产出 search/replace 对(流式)
2. 服务端逐条 apply 并推送 BlockDelta
3. 编辑器逐条渲染修改(带延迟,模拟"AI 正在编辑"
4. 用户可逐条 accept / rejectsuggestion 模式)
5. 确认后才最终写入 Convexreview 模式)
### 7.2 与 BlockNote AI 的差异
| | BlockNote AI | mnote Phase C |
|---|---|---|
| 操作粒度 | 块级(add/update/delete block | 文本级(search/replace 文本对) |
| blockId 依赖 | 必须 | 不需要(文本匹配) |
| 本地文件支持 | 不支持(无稳定 blockId) | 支持(文本匹配不依赖 blockId) |
| Suggestion 层 | ProseMirror `suggestChanges` marks | Tiptap 的 suggestion 扩展或自建 |
| 写入时机 | 用户 accept 后统一写入 | 同 |
### 7.3 组件设计(草图)
```
StreamApplyController(新增)
输入:LLM 流式输出的 partial operations JSON
处理:
1. 解析 partial JSON → 提取已完成的 operation
2. 执行 search_replace → 产生 BlockDelta
3. 通过 SSE 推送 delta 到编辑器
4. 可选:注入 delay50-200ms)模拟人类编辑节奏
输出:逐条 BlockDelta
ReviewSession(新增,在线文档)
状态:pending → accepted | rejected
存储:Convex review_session 表或 documents 的 review 字段
生命周期:
- AI 编辑 → 创建 ReviewSession → 所有修改标记为 pending
- 用户逐条操作 → accept/reject → 更新 session 状态
- 全部处理或用户确认 → 最终写入 → 关闭 session
GhostTextOverlay(新增,编辑器)
参考:Tiptap AI Autocomplete 的 ghost text 覆盖层
用于:展示 AI 修改前后的 diff(红删绿增),用户 hover 查看详情
```
### 7.4 分阶段实施顺序
| 阶段 | 内容 | 依赖 |
|------|------|------|
| C-1 | `StreamApplyController`:流式 apply + SSE 逐条推送 delta | 7-13 EditorRuntimeActor delta 通道 |
| C-2 | `GhostTextOverlay`:编辑器内 diff 展示(红删绿增) | leptos-tiptap 的 decoration 能力 |
| C-3 | `ReviewSession`:在线文档的 accept/reject session | Convex review 表设计 |
| C-4 | `delayAgentStep`:可选的编辑节奏模拟 | C-1 完成 |
**当前不做实施决策**。Phase C 的启动时机以 Phase A/B 完成后,编辑器能力和 Convex review 表设计就绪为前置条件。
---
## 8. 实施阶段(当前)
### Phase A:文件引用主路径 + `mnote.doc.*` 兼容层
- [x] `mnote.doc.fetch` 增加 `format: "markdown"`(在线文档 Page Aggregate → PageMarkdown
- [x] `mnote.doc.fetch` 增加本地文件 source 路由(自动检测 Convex vs 文件系统路径)
- [x] 实现 `resolve_source(documentId)` — 本地文件路径 `local_fs` vs 其余走 Convex
- [ ] 页面 AI / ACP 普通正文编辑默认只传当前文件引用、可选 selection 和用户指令,不再默认构造完整 page context
- [ ] 本地 agent runtime 在 `allowed_roots / allowed_file_paths` 内执行 patch/diff,并把 changed files / diff 摘要回传 MNote
- [x] 实现 `search_replace(text, operations)` — 四级匹配策略(精确→宽松→段落 fuzzy→失败)
- [x] 实现 Convex 写入 adapter(复用 `doc_apply_block_ops` 链路)
- [x] 实现本地文件写入 adapter`mnote.doc.markdown_edit` 检测到本地文件路径时直接 `fs::write` 写回,不经过 Convex
- [ ] 内部 diff 生成 + BlockDelta 推送(复用 7-13 delta 基础设施,待 Phase C 实现)
- [x] Hermes tool manifest 注册 `mnote.doc.markdown_edit`
- [x] Hermes `mnote` plugin 更新:`mnote_doc_fetch` schema + `mnote_doc_markdown_edit` 新增
- [x] 乐观锁:`revision` 冲突检测(`doc_apply_block_ops` 已有)
- [x] 浏览器 smoke(在线文档 `format: "markdown"` + `markdown_edit` 搜索替换)
- [x] 单元测试(`search_replace` 精确/失败/全文、`blocks_to_markdown` with_ids/heading 共 5 测试通过)
- [x] 浏览器 smoke(本地 `.md` 文件读取 `mnote_doc_fetch` + 写入 `mnote_doc_markdown_edit``full_content` 创建 + `operations` 搜索替换 + 回读验证全部通过)
### Phase B`page_ai_workflow.rs` 收口
- [x] 退役 `direct_block_edit_operations`(正则抠「」的快路径,代码保留但路由跳过)
- [x] `/api/page-ai/block-edit-workflow` 不再被当作 local-first 主路径
- [x] 模型 system prompt 重构:从产块操作 JSON 改为产 search/replace 文本对
- [x] 补全 operation schema`extract_markdown_operations_from_model_text` 处理新旧格式
- [x] 浏览器 smoke`markdown_edit` 搜索替换通过,自然语言编辑路径可用
### Phase C:流式/review(规划中,不实施)
- [ ] 流式 apply`StreamApplyController`
- [ ] suggest/review`ReviewSession` + `GhostTextOverlay`
- [ ] `delayAgentStep` 编辑节奏模拟
> 见 §7。当前仅做设计规划,不实施。
---
## 9. 与参考实现和其他设计稿的关系
### 9.1 与 CLI Main 的关系
| CLI Main 概念 | mnote 对应 |
|--------------|-----------|
| `str_replace`(文本级) | `mnote.doc.markdown_edit`(兼容 / fallback |
| `block_replace/insert_after/delete/move_after`(块级) | `mnote.doc.apply_block_ops`(辅助路径) |
| XML 用于精确编辑 | mnote 不用 XML(没有 XML 存储层),direct path 退役后全部走 markdown |
| Markdown 用于导入/导出/对话引用 | mnote 全部 AI 交互走 markdown |
| Skill 格式(YAML + Markdown + tool shortcuts | Hermes `mnote` plugin`plugin.yaml` + `SKILL.md` + tool manifest |
### 9.2 与 BlockNote AI 的关系
| BlockNote AI 概念 | mnote 远期对应 | 状态 |
|-------------------|---------------|------|
| `StreamTool` + `StreamToolExecutor` | `StreamApplyController` | Phase C 规划 |
| `suggestChanges` + `AIExtension` state machine | `ReviewSession` + `GhostTextOverlay` | Phase C 规划 |
| `delayAgentStep` | 可选改善 | Phase C 规划 |
| `RebaseTool` | revision 乐观锁(已有) | 当前已覆盖 |
| 纯 blockId 寻址 | ❌ 不采用。mnote 用文本匹配 | — |
### 9.3 与其他设计稿的关系
| 设计稿 | 关系 | 修正状态 |
|--------|------|---------|
| 7-9 路线图 | 块级编辑降级为辅助,local-first 普通编辑改为授权文件 + agent patch/diffmarkdown_edit 退到兼容层 | ✅ 已修正 |
| 7-10 checklist | 新增 Phase 9 markdown_edit | ✅ 已修正 |
| 7-12 工具路由 | PageAICommandRouter 主输出改为 markdown_edit | ✅ 已修正 |
| 7-13 EditorRuntimeActor | 补充 markdown_edit 的 delta 适配 | ✅ 已修正 |
| 3-13 本地 markdown | 新增 AI 工具接入章节 | ✅ 已修正 |
---
## 10. 禁止项
- 不删除 `mnote.block.*` 工具(保留为辅助路径)。
- 不强迫 local-first agent 产出 MNote 自定义 diffHermes / Reasonix 可使用自身成熟 patch / diff / apply_patch 能力,MNote 负责白名单权限、文件版本冲突和审计。
- 不要求本地文件有稳定的 `blockId`(本地文件没有 block identity)。
- 不在 markdown_edit 内部引入新的 AI 模型调用(diff 是确定性算法)。
- 不把 Convex `documents:updateContent` 重新提升为 local-first 正文主存储;`markdown_edit` 在 cloud / compat 场景可复用受控保存路径。
- 不把 `mnote.page.save` 重新描述为精确编辑主入口(它仍是兜底工具)。
- **不照搬 BlockNote AI 的纯 blockId 寻址模式**(与 mnote 的 markdown 优先策略冲突)。
---
## 11. 成功标准
- [x] `mnote.doc.fetch(documentId, format: "markdown")` 对在线文档返回正确 markdown
- [ ] `mnote.doc.fetch(documentId, format: "markdown")` 对本地 `.md` 文件返回正确 markdown(兼容路径)
- [x] `mnote.doc.markdown_edit` 的简单搜索替换(1 条 operation)浏览器 smoke 通过
- [ ] `mnote.doc.markdown_edit` 的复杂改写(3+ 条 operations)成功率 > 80%
- [ ] 本地 `.md` 文件通过页面 AI 面板可被读取和写入,且默认通过 agent 原生 patch/diff 完成
- [x] 在线文档的 markdown_edit 不增加 Convex RTT(和当前块操作持平)
- [x] `direct_block_edit_operations` 已退役(路由跳过,代码保留)
- [x] `page_ai_workflow.rs` 的 system prompt 已补全 search/replace schema
- [x] Phase C(流式/review)的设计已冻结,不阻塞 A/B 实施
---
## 12. CLI Main 成熟度采纳清单
以下清单按优先级排列,标注当前状态和对应 CLI Main 参考位置。
### 12.1 当前 Phase A/B 必须完成的
| # | CLI Main 模式 | mnote 实施项 | 状态 | 参考文件 |
|---|-------------|-------------|------|---------|
| 1 | 两层操作模型 | local-first 默认 agent 原生 patch/diff`markdown_edit`compat fallback+ `apply_block_ops`(结构辅助)已在 7-10 Phase 9 登记 | 📋 设计完成,已按 2-2 改口径 | `lark-doc-update.md` |
| 2 | Scope 四级控制 | `mnote.doc.fetch` 增加 `scope: full/section/outline/keyword` | 🔜 Phase A | `lark-doc-fetch.md` |
| 3 | Detail 三级控制 | `mnote.doc.fetch` 增加 `detail: simple/with_ids/full` | 🔜 Phase A | `lark-doc-fetch.md` |
| 4 | 片段包装 | fetch 返回中标记 `<!-- fragment -->` / `<!-- excerpt -->` 告知 AI 部分视图 | 🔜 Phase A | `lark-doc-fetch.md`fragment/excerpt 模式) |
| 5 | Code-Act Loop | Hermes `mnote` plugin SKILL.md 中内联 Plan→Execute→Observe→Iterate 指导 | ✅ 已写入 `~/.hermes/skills/note-taking/mnote-block-ai/SKILL.md` | `lark-doc-update-workflow.md` |
| 6 | 更新命令决策树 | 模型 system prompt 追加"优先搜索替换,不全文覆盖"规则 | 🔜 Phase B | `lark-doc-update.md`str_replace vs block_* 决策) |
| 7 | 写后回读 | Hermes 每次写操作结束后自动 `mnote.doc.fetch` 回读 | 🔜 Phase B | `lark-doc-update-workflow.md` |
| 8 | Markdown 优先格式策略 | mnote 默认和唯一 AI 格式为 markdown(不需要 XML | ✅ 已确认 | `lark-doc-md.md`(对比 XML 路线) |
### 12.2 Phase A/B 完成后应补充的
| # | CLI Main 模式 | mnote 实施项 | 状态 | 参考文件 |
|---|-------------|-------------|------|---------|
| 9 | Skill YAML 规范化 | Hermes `mnote` plugin 的 `plugin.yaml` 增加 `description``metadata.domain` | ✅ 已更新 v0.2.0 | `master-skill-template.md` |
| 10 | 参考文件分离 | `~/.hermes/skills/note-taking/mnote-block-ai/references/` 目录已创建,`mnote-doc-fetch.md` 已写入 | ✅ 已创建(fetch),其余按需补充 | `skills/lark-doc/references/` |
| 11 | Skill CI 校验 | CI 步骤:检查所有 plugin.yaml 和 SKILL.md 的 YAML frontmatter 有效性 | 📋 待实施 | `skill-format-check.yml` |
| 12 | 格式规则文档 | `references/mnote-doc-md.md`:定义 markdown 中 AI 应理解的特殊语法(任务列表标记 `- [ ]`、附件链接 `[file:...]` 等) | 📋 待实施 | `lark-doc-md.md` |
| 13 | 上下文冻结规范 | `references/mnote-doc-context.md`:冻结时保留哪些字段、截断规则、revision 注入方式 | 📋 待实施 | `lark-doc-fetch.md`fetch body 构建) |
### 12.3 远期规划(Phase C 及以后)
| # | CLI Main 模式 | mnote 实施项 | 状态 | 参考文件 |
|---|-------------|-------------|------|---------|
| 14 | 跨域资源路由 | 文档内嵌思维导图/附件时,路由到对应 skill(见 §2.1.5 | ⏳ Phase C 后 | `lark-doc/SKILL.md`(路由表) |
| 15 | 流式增量 apply | BlockNote AI 的 `StreamToolExecutor` 模式,见 §7 | ⏳ Phase C 规划 | `blocknote-ai/packages/xl-ai/` |
| 16 | suggest/review | BlockNote AI 的 `suggestChanges` 模式,见 §7 | ⏳ Phase C 规划 | `blocknote-ai/packages/xl-ai/` |
### 12.4 与 BlockNote AI / Tiptap AI Autocomplete 的采纳清单
| # | 参考模式 | mnote 采纳 | 时机 | 参考文件 |
|---|---------|-----------|------|---------|
| B1 | `StreamTool` 流式 apply | `StreamApplyController`(§7.3 | Phase C | `blocknote-ai/packages/xl-ai/src/streamTool/` |
| B2 | `suggestChanges` review 层 | `ReviewSession` + `GhostTextOverlay`(§7.3 | Phase C | `blocknote-ai/packages/xl-ai/src/AIExtension.ts` |
| B3 | `delayAgentStep` 编辑节奏 | 可选改善 | Phase C | `blocknote-ai/packages/xl-ai/src/streamTool/` |
| T1 | ghost text 内联补全 | 独立功能(非本文档范围) | 独立立项 | `tiptap-ai-autocomplete/src/` |
### 12.5 实施优先级总结
```
Phase A(当前立即)
├── #2 Scope 四级控制 ← mnote.doc.fetch 增强
├── #3 Detail 三级控制 ← mnote.doc.fetch 增强
├── #4 片段包装 ← fetch 返回值增强
├── #8 Markdown 优先 ← 已确认
└── 授权文件引用 + agent 原生 patch/diff 主路径;mnote.doc.markdown_edit 作为 compat fallback
Phase BPhase A 完成后)
├── #5 Code-Act Loop ← Hermes plugin SKILL.md
├── #6 更新决策树 ← 模型 system prompt
└── #7 写后回读 ← Hermes tool loop 逻辑
Phase A/B 完成后补充
├── #9-#13 Skill 规范化、参考文件分离、CI 校验、格式文档、上下文规范
Phase C(远期)
├── #14 跨域路由(Phase C 后)
├── #15 流式 applyPhase C
└── #16 suggest/reviewPhase C
```
@@ -0,0 +1,332 @@
# 7-18 [process] local-first agent 文件编辑控制面 v1
> 创建时间:2026-05-22
>
> 当前状态:`PROCESS`
>
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-8-mvp-post-process-execution-order-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
>
> 覆盖旧稿:`/mnt/Data1T/mnote/design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`
>
> 口径说明:旧 `7-14` 仍受 CLI Main / Lark Doc / tool-first 写入模型影响。CLI Main 可以参考 agent workflow 纪律,但不作为 MNote local-first Markdown 编辑架构主参考。
## 1. 第一结论
MNote 不提供普通 Markdown 正文编辑工具。
MNote 在 local-first 下只提供:
- 页面和文件定位。
- agent target 选择与冻结。
- `AiAccessScope`、allowed roots、allowed files、readonly / dirty / permission context。
- selection、当前光标附近上下文、相关资源引用。
- agent runtime session、审计、changed files / diff 回收。
- watcher、BufferStore、Page Aggregate、ProseMirror 前台同步。
Hermes / Reasonix 是已知 agent,使用自身文件 read / write / patch / diff 能力在授权目录内完成普通 `.md` 编辑。
## 2. 明确退役项
### 2.1 `mnote.doc.markdown_edit`
`mnote.doc.markdown_edit` 不再作为:
- local-first 普通 Markdown 编辑默认入口。
- local-first 普通 Markdown 编辑 fallback。
- remote fallback。
- 新 agent runtime 的推荐工具。
- 新 checklist 的验收目标。
已有代码和 smoke 若仍覆盖 `markdown_edit`,只代表历史在线 / compat 路径的回归证据;不得再由它反推出“local-first 应继续提供 Markdown 编辑工具”。
### 2.2 `mnote.doc.fetch`
`mnote.doc.fetch` 不作为普通正文读取主入口。
local-first 默认路径中,agent 直接读取授权文件。MNote 可以把 selection、文件摘要、block projection 或结构化上下文放进 run input,但不要求 agent 通过 `mnote.doc.fetch` 再读正文。
### 2.3 `page_ai_workflow` / `mnote.block.*` / `mnote.page.save`
- `page_ai_workflow` 只保留为 debug / 历史兼容门面,不进入 local-first 普通编辑主路径。
- `mnote.block.*` 只保留为复杂结构辅助,例如拖拽排序、精确块删除、非 Markdown 结构资源辅助。
- `mnote.page.save` 只保留为页面级兜底写入工具,不作为精确 Markdown 编辑入口。
## 3. 主路径数据流
```text
Page / active editor
-> Agent Target Resolver freezes selected target package
-> resolve canonical .md file / resource file
-> build AiAccessScope
-> freeze allowed roots / allowed files / readonly / dirty / selection
-> start Hermes / Reasonix run with file refs and context
-> agent native patch / diff / write inside allowed roots
-> MNote collects changed files / diff / audit
-> watcher observes file changes
-> BufferStore arbitrates clean / dirty / conflict state
-> Page Aggregate rebuilds projection
-> ProseMirror / tiptap island refreshes visible document
```
关键点:
- MNote 只给位置、权限和上下文,不给普通 Markdown 编辑工具。
- 多工作区、多 tab、多资源同时打开时,默认 target 只能来自最后获得编辑焦点的 editor / resource tab;不允许用“第一个 tab”“树选中项”或 URL documentId 静默猜测。
- 写入动作发生在 agent 自身文件能力内,并受 allowed roots / allowed files 限制。
- 前台同步由 watcher / BufferStore / Page Aggregate 接回,不由 agent 直接推 UI 状态。
- dirty buffer 时不得静默覆盖,必须进入冲突或 review 状态。
## 4. Agent Target Resolver
Agent Target Resolver 是 MNote 发送给 agent 前的唯一目标解析层。它的职责是把当前 UI 状态冻结为一份明确的 `targetPackage`,而不是让 agent 或 API 自行猜“当前页”。
### 4.1 选择原则
- **workspace 是权限边界**:默认一次 run 只属于一个 workspace;跨 workspace 必须由用户显式多选,并生成多个 `allowedRoots`
- **tab 是视图,不是真相**:tab 只帮助判断用户正在看的对象;最终 target 必须落到 `objectIdentity``resourceKind` 和 canonical path。
- **last focused editor 优先**:默认 target 是最后获得编辑焦点的 editor / resource tab。
- **selection 覆盖 whole file**:存在真实选区时,默认 scope 为 selection;没有选区时才是 whole file / current resource。
- **树选中项只作为候选**FileTree / PageTree selection 不自动成为 agent target,除非用户在 target picker 中选择“树选中项”。
- **歧义时不发送**:如果焦点不明确、target dirty 且会被写入、或跨 workspace 未显式确认,发送按钮进入需要选择状态。
### 4.2 targetPackage 合同
```json
{
"schema": "mnote.agent_target_package.v1",
"primaryTargetId": "target-1",
"targets": [
{
"targetId": "target-1",
"workspaceId": "local:design",
"workspaceSource": "local_folder",
"workspaceRoot": "/workspace/design",
"editorGroupId": "main",
"tabId": "tab-design-md",
"focusRank": 1,
"objectIdentity": "local_folder:/workspace/design/design.md",
"resourceKind": "markdown_page",
"title": "design.md",
"canonicalPath": "/workspace/design/design.md",
"uri": "file:///workspace/design/design.md",
"version": "mtime:size:hash",
"scope": "selection",
"selection": {
"text": "当前选区文本",
"anchor": "pm:block:p_1:0..12"
},
"dirty": false,
"readonly": false,
"ownerPage": null,
"relatedResources": []
}
],
"allowedRoots": ["/workspace/design"],
"allowedFiles": ["/workspace/design/design.md"],
"policy": {
"writeMode": "agent_native_file_patch",
"requiresConfirmation": false,
"crossWorkspace": false
}
}
```
### 4.3 resourceKind
`resourceKind` 至少需要区分:
- `markdown_page`:普通 `.md` 页面正文。
- `mindmap`mindmap 资源文件;可带 `ownerPage`,但不伪装成正文。
- `office`OnlyOffice 资源;默认只读上下文,除非明确进入 office 编辑 agent flow。
- `raw_file`:普通文件。
- `folder`:目录范围;只在用户显式选择“把这个文件夹作为上下文”时出现。
## 5. UI 设计
当前右侧页面 AI 抽屉已有 runtime / profile / context scope,但“上下文:当前页/选区/块/页面设置”不够表达多工作区、多 tab 和资源 tab。需要把它升级为明确的 target UI。
### 5.1 默认展示
AI composer 上方固定显示 target chip,不放到设置页深处:
```text
[工作区: design] [design.md] [当前选区] [可写]
```
如果当前焦点是截图中的右侧 mindmap,则显示:
```text
[工作区: local] [新页面165037 / KMIND] [mindmap] [可写]
```
chip 必须可点击,打开 target picker。chip 内容优先显示用户能识别的名称,不优先显示内部 id;hover / detail 再显示 path、workspace root、object identity。
### 5.2 target picker
点击 target chip 后打开轻量 popover,不跳转页面。结构为:
```text
发送给 Agent
当前焦点
● design.md markdown_page 当前选区 /workspace/design/design.md
打开的 Tab
○ 新页面223322 markdown_page 全文
○ design.md markdown_page 当前选区
○ 新页面165037 / KMIND mindmap 当前资源
树选中项
○ 3 个文件 只读上下文
范围
( ) 当前选区 ( ) 当前文件 ( ) 当前资源 ( ) 多选 tab ( ) 文件夹
[取消] [使用这个目标]
```
交互规则:
- 单选是默认;多选必须用户点击“多选 tab”或勾选多个候选。
- 多 workspace 候选默认折叠在各自 workspace 组下,跨 workspace 多选时出现权限提示。
- dirty target 显示 `未保存` 标记;如果 agent 可能写入,发送前需要确认。
- readonly target 显示 `只读`,发送按钮文案变成“只读提问”或禁用写入型 intent。
- resource target 不能显示成“当前页”;必须显示 `mindmap` / `office` / `raw file`
### 5.3 composer 中的 context scope
`context scope` select 不应继续承担 target 选择职责。它只控制 primary target 内部范围:
- `selection`:当前选区。
- `file`:当前文件。
- `resource`:当前资源文件。
- `related`:当前页面引用的相关资源,只读附加上下文。
不再把 `page / block / options` 混成同一层 target 选择。页面设置属于 target 的辅助上下文,不是普通 Markdown 编辑范围。
### 5.4 发送前状态
发送按钮按 targetPackage 状态变化:
- `发送`:单 target、clean、可写或只读问答。
- `选择目标`:没有明确 last focused target,或当前焦点和 URL / active tab 冲突。
- `确认发送`:跨 workspace、多 target、dirty write、folder scope。
- `只读提问`readonly target 或用户选择只读上下文。
发送后第一条用户消息旁边显示冻结的 target 摘要,避免 run 过程中用户切 tab 后误以为 agent 改了新 tab
```text
目标:design.md / 当前选区 / local_folder / 12:31:05 冻结
```
## 6. SQLite control-plane 职责
Rust SQLite control-plane 是默认控制面,负责:
- auth / session / membership。
- share grants / sync state。
- AI policy、workspace policy、allowed roots / allowed files。
- ACP / Hermes / Reasonix runtime session。
- targetPackage 审计与用户确认记录。
- permission decision、approval decision、tool / file access audit。
- changed files / diff / command context 记录。
它不持有普通 Markdown 正文真相。本地 `.md` 文件仍是正文真相。
## 7. 运行时输入合同
每次从页面触发 agent 编辑时,run input 至少应包含:
```json
{
"workspaceSource": "local_folder",
"targetPackage": {
"schema": "mnote.agent_target_package.v1",
"primaryTargetId": "target-1",
"targets": []
},
"currentFile": {
"path": "/workspace/page.md",
"uri": "file:///workspace/page.md",
"version": "mtime:size:hash"
},
"allowedRoots": ["/workspace"],
"allowedFiles": ["/workspace/page.md"],
"selection": {
"text": "当前选区文本",
"anchor": "可选的 editor/block/offset 引用"
},
"context": {
"readonly": false,
"dirty": false,
"resourceRefs": []
}
}
```
后续可以补充 page id、object identity、resource refs、outline、nearby context,但不得把普通正文写入重新包装成 `mnote.doc.markdown_edit`
## 8. 验收清单
### Phase A0target selection 与 UI
- [ ] Page AI composer 可见 target chip,显示 workspace、target title、resourceKind、scope、readonly / dirty 状态。
- [ ] 点击 target chip 打开 target picker,可在当前焦点、打开 tabs、树选中项之间选择。
- [ ] 默认 target 来自 last focused editor / resource tab,不来自第一个 tab、URL documentId 或树选中项。
- [ ] mindmap / office / raw file target 显示真实 resourceKind,不伪装成 markdown page。
- [ ] 多 tab / 跨 workspace / dirty write 时发送前需要显式确认。
- [ ] 发送后消息记录冻结 target 摘要,切换 tab 不影响已启动 run。
### Phase A:运行时输入与权限边界
- [ ] 从文档页发起 Hermes / Reasonix run 时,request body 包含 `currentFile``allowedRoots``allowedFiles`、selection 和 dirty / readonly context。
- [ ] run body 包含 `targetPackage`,且 `allowedRoots` / `allowedFiles` 从 targetPackage 推导。
- [ ] local-first 普通 Markdown 编辑 run 不包含 `mnote.doc.markdown_edit` 推荐工具。
- [ ] allowed roots 外文件写入被 agent runtime 或 MNote 审计层拒绝。
- [ ] readonly 页面不会启动可写 run,或只启动只读问答 run。
### Phase B:写入回收与前台同步
- [ ] agent 修改当前 `.md` 后,MNote 能回收 changed files / diff。
- [ ] clean buffer 下 watcher -> BufferStore -> Page Aggregate -> ProseMirror 可见更新通过 browser smoke。
- [ ] dirty buffer 下外部 agent 写入不会静默覆盖,必须出现冲突或 review 状态。
- [ ] changed files / diff 与 session / run / actor 关联写入审计。
### Phase C:旧工具退役
- [ ] local-first 普通 Markdown 编辑 smoke 断言未调用 `/api/documents/save`
- [ ] local-first 普通 Markdown 编辑 smoke 断言未调用 `mnote.doc.markdown_edit`
- [ ] Hermes / Reasonix manifest 或 system prompt 不再鼓励普通 Markdown 编辑调用 `mnote.doc.markdown_edit`
- [ ]`markdown_edit` 测试只保留为历史 online / compat 回归,并在文档中标明不指导新实现。
### Phase D:结构辅助边界
- [ ] `mnote.block.*` 只在复杂结构辅助场景出现,例如结构块排序、非 Markdown 资源辅助。
- [ ] `mnote.page.save` 只作为页面级兜底写入,不作为默认精确编辑入口。
- [ ] `mnote.doc.fetch` 不作为 local-first 正文读取主入口;需要结构化上下文时由 MNote 在 run input 中提供摘要或 projection。
## 9. 不做事项
- 不参考 CLI Main 的 Lark Doc 在线文档写入架构来设计 local-first 普通 Markdown 编辑。
- 不新增 MNote 普通 Markdown 编辑工具。
- 不把 Convex 恢复为默认正文或 AI 会话全文主存储。
- 不实现 Phase C Review Mode / StreamApplyController / GhostTextOverlay。
- 不让前端维护第二份正文真相。
- 不把所有打开 tab 默认发送给 agent。
- 不把跨 workspace 自动合并为一个隐式上下文。
## 10. 归档条件
满足以下条件后,本稿可归档到 `design/07-ai/done/`
- Phase A0 target UI 有真实浏览器 smoke 证据。
- Phase A / B / C 至少各有一条真实浏览器或 targeted test 证据。
- local-first agent 文件编辑主路径已能在 clean buffer 下完成真实 `.md` 修改并同步回 tiptap。
- dirty conflict 不静默覆盖。
- 文档和 manifest 不再把 `mnote.doc.markdown_edit` 描述为 local-first fallback。
@@ -1,14 +1,16 @@
# 7-12 [process] 页面 AI Hermes 工具路由与编辑审阅面设计 v1
# 7-12 [reference] 页面 AI Hermes 工具路由与编辑审阅面设计 v1
> 更新时间:2026-05-19
>
> 当前状态:`PROCESS`
> 当前状态:`reference / frozen`
>
> 归档说明(2026-05-22):本文保留 Hermes 工具路由、manifest 和 review surface 的设计边界;Phase C Review Mode 继续冻结。`7-14` 已移入 `design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`,当前 active AI 编辑口径以 `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md` 为准。
>
> 本稿目的:修正“页面 AI 快速块编辑”后续方向,明确 mnote 不再建设独立 AI agent runtimemnote 只建设 Hermes 可消费的编辑工具路由、工具 manifest、上下文冻结、dry-run/review 和 Rust 写入安全边界。
>
> 关联文档:
> - `/mnt/Data1T/mnote/design/10-review/done/09-page-ai-fast-block-edit-runtime-review.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/cli-main`
@@ -22,7 +24,7 @@
本稿仍作为 Hermes 工具路由与审阅面设计保留在 `process/`,但以下口径已经更新:
- `/api/page-ai/block-edit-workflow` 当前不再以 `local_rule -> apply_block_ops` 作为主路径;local-first 普通 Markdown 编辑默认给 Hermes / Reasonix 授权文件引用,由 agent 使用自身 patch / diff / 文件编辑能力写本地 `.md`
- `mnote.doc.markdown_edit` 保留cloud / remote agent / compat fallback;模型生成 markdown `search/replace``full_content` 后调用该工具,只适用于 agent 不能直接访问授权文件或需要受控代理写入的场景
- `mnote.doc.markdown_edit` 不再作为 local-first 默认、fallback 或 remote fallback;本文后续出现的 `markdown_edit` 只代表历史 tool / review surface 证据,不指导新 agent 文件编辑主路径。当前 active 口径见 `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
- `page_ai_workflow` 已复用统一 mnote tool executor,不再绕过 Hermes tool toggle / audit / write contract。
- `mnote.doc.apply_block_ops` / `mnote.block.*` 保留为结构性块操作辅助,不再作为普通正文 search/replace 的优先入口。
- 本稿中的 `PageAIReviewSession` 只定义 Phase C 的安全合同和状态机边界;当前 Phase C 仍冻结,不实施流式 apply 或新的审阅 UI。
@@ -653,7 +655,7 @@ profile disabled mnote.block.fetch
`7-10` 是页面块 AI 工具执行 checklist,包含真实代码和 smoke 证据。它仍然有效,继续保留在:
```text
design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md
design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md
```
但后续执行必须按本文修正口径:
@@ -15,9 +15,9 @@
> 4. 为后续项目基本完成后扩展共享能力预留 schema、API 和验证边界。
>
> 关联文档:
> - `/mnt/Data1T/mnote/design/07-ai/process/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-25-acp-session-runtime-enhancement-plan-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`
> - `/mnt/Data1T/mnote/recycle/design/07-ai/retired-http-hermes/`
---