Files
mnote/design/old/05-editor-mainline/process/ai-first-rust-block-editor-baseline-v1.md
T

937 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# [recycle] mnote AI-First Rust 块编辑器主基线定稿 v1
> 更新时间:2026-04-18
>
> 关联文档:
> - `/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/process/1-1-tree-first-graph-kernel-checklist-v2.md`
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/blockselect.md`
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/done/tiptap.md`
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/rust-block-editor-model-v0.md`
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/done/rust-block-editor-command-contract-v0.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/`
> - `/mnt/Data1T/mnote-next/docs/architecture/p1-human-stable-interface.md`
## 1. 文档目的
本文用于在新的产品前提下,重新冻结 `mnote` 后续块编辑器开发的主基线。
这版定稿不再以“是否尽量接近 `BlockNote` / `Tiptap` 的完整体验”为第一判断,而是以:
- AI-first
- CLI-first
- Rust-native
- 轻量块编辑
- 低复杂度、低维护成本
作为最高优先级。
本文回答四件事:
1. 后续块编辑器主线应该以谁为基准
2. `edita``blocks``kode``leptos-tiptap``mnote-next` 各自的正确定位
3. 在新的前提下,为何可以接受更轻量的编辑器能力面
4. 替换现有 `BlockNote` 的方向与开发阶段
---
## 2. 新前提
这版定稿建立在下面四条前提上。
### 2.1 `mnote-next` 只能提供内部交互样本,不能当主基准
`mnote-next` 中确实出现过一批值得回看的交互尝试,包括:
- 拆块
- 合并块
- 插入块
- 删除块
- 有限缩进
- 标题折叠
- 引用 token
- 基础块菜单与 slash 命令
这意味着:
> **我们不是从零开始想象块编辑器,但也不能把 `mnote-next` 当成已经外部验证完成的 benchmark。它更适合作为内部样例、回归样本和反例来源。**
### 2.2 用户真实高频需求不是完整 Notion
用户长期高频需求主要是:
- Markdown 风格记录
- 标题与列表
- 折叠
- 待办
- 基础引用
- 少量导入、修改、校对
而不是:
- 重度协作
- 复杂表格
- 大量富文本格式
- 高级评论系统
- 完整页面级可视化编辑生态
### 2.3 当前不需要协作
协作不是当前主线需求,因此:
- 不需要为协作牺牲大量复杂度
- 不需要为了 Yjs / Hocuspocus / comment thread 去设计第一版架构
- 不需要把“多人同时编辑一致性”当成当前编辑器路线的决定性条件
### 2.4 产品最终意义是 AI-first 笔记软件
项目最终方向固定为:
> **一个 AI 为底层、类似轻量化 Obsidian + CLI 的笔记软件;AI 是主要编辑与输出主体,人类主要负责导入、校对和局部修改。**
这意味着:
- 编辑器首先服务 AI 命令和结构化输出
- 人类编辑只是辅助链路
- 命令统一比富文本完整性更重要
- 结构可编排、可脚本化、可审计,比可视化 polish 更重要
---
## 3. 最终定稿结论
最终口径固定如下:
> **后续编辑器开发以 AI-first、CLI-first、Rust-native 的轻量块编辑器为主线;以 `edita-core + blocks + kode` 作为主基准组合;以 `leptos-tiptap` 作为 Leptos fallback 接入参考;`mnote-next` 只保留为内部交互样本,不作为主 benchmark。**
进一步展开就是:
- **事实源基线**:仍然只有 Rust kernel 的 `node / edge / subtree / projection / command`
- **编辑器主线基线**Rust-native minimal block editor
- **Rust 编辑器参考**`edita-core` 的 headless block editor / command 思路
- **块模型与转换参考**`blocks` 的文档模型、JSON/Markdown/HTML 转换、history / diff / merge 思路
- **Leptos 编辑输入参考**`kode``kode-core / kode-leptos / kode-doc` 分层与 Markdown/WYSIWYG/tree editor 构件
- **Leptos fallback 参考**`leptos-tiptap` 的组件、hook、runtime bridge 与 demo
- **第一阶段模型冻结**:以 `rust-block-editor-model-v0.md` 中的 `EditorDocument / EditorBlockNode / BlockProps / content_node` 口径为准
- **第一阶段命令冻结**:以 `rust-block-editor-command-contract-v0.md` 中的 `replace_block / insert_block_after / delete_block / split_block / merge_with_previous / move_block / indent_block / outdent_block / toggle_heading_collapse / attach_reference_token / detach_reference_token` 为准
- **内部样本参考**`mnote-next` 只作为曾尝试过的拆块、合并、缩进、折叠、引用交互样本,不作为采用优先级
一句话总结:
> **主线不再是“如何更好地使用 `Tiptap`”,而是“如何基于现有外部 Rust / Leptos 参考层拼出一个由 Rust command 驱动、以 AI 为主要操作者的最小块编辑器”。**
再收口一句:
> **这不是“从零全写编辑器”的路线,而是“先采用 `edita-core / blocks / kode / leptos-tiptap` 已有能力,再只为 `mnote` 的 kernel 接缝和特有语义补胶水”的路线。**
---
## 4. 主线选型口径
### 4.1 主线基准:`edita-core + blocks + kode`
主线基准不是某个现成成品,而是三部分外部参考组合:
1. `edita-core`
- 负责提供无头 Rust 编辑器的参考方向
- 重点参考:
- block model
- command execution
- headless editor 边界
2. `blocks`
- 负责提供块文档模型与多格式转换参考
- 重点参考:
- `Document / Block / BlockType`
- JSON / Markdown / HTML / Plain Text 双向转换
- history / undo redo 思路
- diff / merge / pipeline / sanitizer
3. `kode`
- 负责提供 Leptos 侧编辑输入和文档树构件参考
- 重点参考:
- `kode-core` 的 text buffer / selection / editing primitives
- `kode-leptos` 的 Leptos 组件组织
- `MarkdownEditorComponent`
- `kode-doc` 的 structured document model
补充两条非主基准但仍值得保留的参考:
4. `leptos-tiptap`
- 负责提供 Leptos 下对接成熟编辑器 runtime 的 fallback 样本
- 重点参考:
- `TiptapEditor` 组件
- `use_tiptap_editor` hook
- runtime bridge
- CSR / SSR demo
5. `mnote-next`
- 只作为内部交互样本和回归样例来源
- 重点参考:
- 曾经尝试过的拆块 / 合并 / 缩进 / 引用交互
- 曾经暴露过的问题与不稳定边界
- 不作为:
- 主 benchmark
- 外部成熟参考
- 第一采用优先级
这意味着:
> **`edita-core` 负责回答“命令核怎么组织”,`blocks` 负责回答“块与格式转换怎么组织”,`kode` 负责回答“Leptos 输入层怎么组织”,`leptos-tiptap` 负责回答“如果 Rust-native UI 壳受阻,Leptos 怎么对接成熟 editor runtime”,`mnote-next` 只负责提供内部样例。**
### 4.1.1 本地参考代码位置
下面这些参考代码已经拉到本地,后续讨论一律优先引用本地路径。
- `edita`(当前本地快照:`2045c3a`
- 仓库入口:[reference-code/edita/README.md](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/edita/README.md)
- headless core trait[reference-code/edita/edita-core/src/lib.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/edita/edita-core/src/lib.rs)
- editor 壳:[reference-code/edita/edita/src/editor.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/edita/edita/src/editor.rs)
- state 组织:[reference-code/edita/edita/src/state.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/edita/edita/src/state.rs)
- 基础 nodes[reference-code/edita/edita/src/nodes/paragraph.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/edita/edita/src/nodes/paragraph.rs)、[reference-code/edita/edita/src/nodes/heading.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/edita/edita/src/nodes/heading.rs)、[reference-code/edita/edita/src/nodes/task_item.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/edita/edita/src/nodes/task_item.rs)
- `blocks`(当前本地快照:`86b5e00`
- 仓库入口:[reference-code/blocks/README.md](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/README.md)
- 文档模型:[reference-code/blocks/src/document.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/src/document.rs)
- 块模型:[reference-code/blocks/src/block.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/src/block.rs)
- 转换层:[reference-code/blocks/src/converters.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/src/converters.rs)
- history[reference-code/blocks/src/history.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/src/history.rs)
- diff / merge[reference-code/blocks/src/diff.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/src/diff.rs)
- sanitizer[reference-code/blocks/src/sanitizer.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/src/sanitizer.rs)
- 示例:[reference-code/blocks/examples/json_api.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/examples/json_api.rs)、[reference-code/blocks/examples/file_ops.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocks/examples/file_ops.rs)
- `kode`(当前本地快照:`96ccff4`
- 仓库入口:[reference-code/kode/README.md](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/README.md)
- `kode-core` editor/buffer/selection/history[reference-code/kode/kode-core/src/editor.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-core/src/editor.rs)、[reference-code/kode/kode-core/src/buffer.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-core/src/buffer.rs)、[reference-code/kode/kode-core/src/selection.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-core/src/selection.rs)、[reference-code/kode/kode-core/src/history.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-core/src/history.rs)
- `kode-doc` 结构文档模型:[reference-code/kode/kode-doc/src/lib.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-doc/src/lib.rs)、[reference-code/kode/kode-doc/src/node.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-doc/src/node.rs)、[reference-code/kode/kode-doc/src/transform.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-doc/src/transform.rs)
- `kode-leptos` 组件入口:[reference-code/kode/kode-leptos/src/lib.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-leptos/src/lib.rs)
- Markdown/WYSIWYG 组件:[reference-code/kode/kode-leptos/src/markdown_editor_component.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-leptos/src/markdown_editor_component.rs)、[reference-code/kode/kode-leptos/src/wysiwyg/tree_editor.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-leptos/src/wysiwyg/tree_editor.rs)
- Markdown 规则:[reference-code/kode/kode-markdown/src/markdown_editor.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-markdown/src/markdown_editor.rs)、[reference-code/kode/kode-markdown/src/input_rules.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/kode/kode-markdown/src/input_rules.rs)
- `leptos-tiptap`(当前本地快照:`8f16e57`
- 仓库入口:[reference-code/leptos-tiptap/README.md](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/README.md)
- 组件入口:[reference-code/leptos-tiptap/src/api/component.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/src/api/component.rs)
- hook 入口:[reference-code/leptos-tiptap/src/api/use_tiptap_editor.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/src/api/use_tiptap_editor.rs)
- 命令与内容 API[reference-code/leptos-tiptap/src/api/commands.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/src/api/commands.rs)、[reference-code/leptos-tiptap/src/api/content.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/src/api/content.rs)
- runtime bridge[reference-code/leptos-tiptap/src/runtime/bridge.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/src/runtime/bridge.rs)、[reference-code/leptos-tiptap/tiptap/src/bridge_runtime.ts](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/tiptap/src/bridge_runtime.ts)
- demo[reference-code/leptos-tiptap/examples/demo-csr/src/main.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/examples/demo-csr/src/main.rs)、[reference-code/leptos-tiptap/examples/demo-ssr/src/app.rs](/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/examples/demo-ssr/src/app.rs)
- `mnote-next` 只作为内部样本
- 人层接口草案:[mnote-next/docs/architecture/p1-human-stable-interface.md](/mnt/Data1T/mnote-next/docs/architecture/p1-human-stable-interface.md)
- 编辑器尝试:[mnote-next/apps/web/app/components/editor/BlockEditor.tsx](/mnt/Data1T/mnote-next/apps/web/app/components/editor/BlockEditor.tsx)
- 用法约束:只用来回看交互样例与历史问题,不作为“已经验证完成”的外部 benchmark
### 4.2 复用优先原则
这条主线不是“从零全写”,而是:
> **优先复用参考层,只有缺口才自研胶水、集成层和最小必要功能。**
固定原则如下:
- 优先复用 `edita-core` 的 headless command / editor 组织思路
- 优先复用 `blocks` 的文档模型、导入导出、history、diff/merge 思路
- 优先复用 `kode-core / kode-leptos / kode-doc` 的输入、缓冲、Leptos 组件与 tree editor 构件思路
- 优先把 `leptos-tiptap` 留作 Leptos 接入成熟 runtime 的 fallback 样本
- `mnote-next` 只用于补充内部交互样例和回归案例,不进入“优先采用”序列
- 只在下面情况才自研:
- 参考库不覆盖你方场景
- 参考库抽象不适配 `tree-first graph kernel`
- 参考库能力过重或过轻
- 缺少稳定 API,必须用胶水层隔离
### 4.2.1 参考采用矩阵
| 参考层 | 优先直接采用 | 借鉴后接入 | 当前不作为主线采用 |
| --- | --- | --- | --- |
| `edita-core` | headless editor 边界、`Editor / Block / Command` 组织方式、命令执行框架 | 导出接口、块注册方式、状态编排方式 | 直接把它当成最终产品 UI 或完整文档系统 |
| `blocks` | `Document / Block / BlockType`、JSON/Markdown/HTML/Plain Text 转换、history、diff/merge、sanitizer 思路 | 与 `mnote` kernel 的格式映射、引用 token 扩展、最小 block props 扩展 | 自己先空白重写一套 import/export/history/diff/merge |
| `kode` | `kode-core` 的 text buffer / selection / editing primitives、`kode-leptos` 组件组织、`MarkdownEditorComponent``TreeWysiwygEditor``kode-doc` 分层 | 块内输入器、Leptos 焦点与菜单接缝、块级编排外壳 | 一开始就自建完整文本输入系统或重型 `contenteditable` 壳 |
| `leptos-tiptap` | Leptos 组件/hook、runtime bridge、demo、SSR/CSR 接入方式 | 某些 selection / 菜单 / 富文本细节处理思路 | 主线路线、长期语义事实源 |
| `mnote-next` | 旧交互样例、历史回归场景、失败边界 | 从旧实现里提取测试样例与交互反例 | 主 benchmark、已外部验证结论、第一采用优先级 |
执行口径固定为:
- 先证明参考层能不能直接承担,再决定是否补胶水
-`blocks` 已能承担转换或 history,就不再另起一套
-`kode` 已能承担块内输入器,就不先写大而全 `textarea/contenteditable` 内核
-`edita-core` 已能承担命令编排,就不先发明第二套 editor command 容器
- `mnote-next` 只能用来补样例,不得作为“因为我们以前写过,所以现在继续沿用”的理由
### 4.3 为什么不再把 `Tiptap` 作为主线 benchmark
`Tiptap` 仍然是成熟、强大、值得参考的编辑器体系。
但在新的产品前提下,它不再是主线 benchmark,原因是:
- 它的能力面明显大于当前真实需求
- 它解决了很多你当前并不需要的问题,例如复杂协作和完整富文本生态
- 它仍然会把主线注意力拉回浏览器富文本壳,而不是 Rust command 与 AI-first 流程
- 如果当前主要操作者是 AI 与 CLI,而不是人类重度可视化编辑,那么 `Tiptap` 的大量优势暂时用不上
因此这版定稿把它降级为:
- 体验参考
- fallback 方案
- 交互 benchmark
而不是主线目标。
### 4.4 为什么 `BlockNote` 更不应继续作为主线
在新的前提下,`BlockNote` 的问题更加明显:
- 它是更高一层的现成编辑器壳
- 对当前“轻量、命令驱动、AI-first”的目标来说过重
- 它会继续把设计重心拉回 UI 壳、兼容层和编辑器运行时
- 它不利于继续收口 Rust command 和 CLI 统一
因此:
> **`BlockNote` 只保留为历史实现与迁移来源,不再作为长期方向。**
---
## 5. 主线架构定义
后续块编辑器主线架构固定为五层。
## 5.1 Rust kernel 事实源层
负责:
- `node`
- `edge`
- `subtree`
- `projection`
- `command`
这一层继续是系统唯一事实源。
## 5.2 Rust editor core 层
负责:
- block model
- editor command
- content transform
- import / export
- undo / redo 基础能力
这一层应尽量 Rust-native,并尽量无头。
第一阶段模型与命令边界固定为:
- 块模型参考 `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/rust-block-editor-model-v0.md`
- 命令与 Markdown 边界参考 `/mnt/Data1T/mnote/design/old/05-editor-mainline/done/rust-block-editor-command-contract-v0.md`
这一层的复用优先级固定为:
- 第一优先:`edita-core`
- 第二优先:`blocks`
- 第三优先:在这两者之间补你方胶水与集成层
## 5.3 Leptos UI 壳层
负责:
- 块列表展示
- 文本输入
- 块菜单
- slash 菜单
- 拖拽或等价移动
- 焦点、选中、折叠等 UI 状态
这一层不再承担事实源角色。
这一层的复用优先级固定为:
- 第一优先:`kode-leptos` / `kode-core` / `kode-doc`
- 第二优先:`leptos-tiptap` 的 Leptos bridge / runtime 接法
- 第三优先:只在块级编排和你方特有语义处自研
## 5.4 CLI / AI command 层
负责:
- 直接调用统一 Rust command
- 结构化修改文档
- 自动导入、自动整理、自动总结、自动改写
长期上:
- CLI 与 AI 不应模拟 UI
- CLI 与 AI 应直接操作 editor command / kernel command
## 5.5 读态与导出层
负责:
- Markdown 输出
- HTML 输出
- 轻量阅读渲染
- 结构树与目录派生
---
## 6. 这条路线会得到什么
如果走这条主线,会得到下面这些收益。
### 6.1 更接近真正的全 Rust 架构
可以把下面几层都收口到 Rust
- kernel
- editor core
- command
- import/export
- AI bridge
- CLI
浏览器端只保留必要的 WASM / UI glue。
### 6.2 更容易实现底层统一
统一的对象将不再是“前端编辑器文档”,而是:
- Rust block model
- Rust command
- Rust kernel projection
这样:
- UI 改文档,走 Rust command
- CLI 改文档,走 Rust command
- AI 改文档,走 Rust command
这比 `BlockNote``Tiptap` 更容易收口成单一语义层。
### 6.3 更符合 AI-first 场景
AI-first 场景不要求复杂富文本壳,而要求:
- 可预测
- 可序列化
- 可 patch
- 可审计
- 可通过命令复用
Rust-native minimal editor 更符合这一点。
### 6.4 更容易保持轻量
只要控制能力面,就可以故意不做:
- 协作
- 评论
- 高级表格
- 大量 WYSIWYG 富文本
- 大型插件系统
从而保持更轻、更稳、更快。
---
## 7. 这条路线会牺牲什么
要明确承认,这条路线不是零代价。
### 7.1 会牺牲成熟富文本生态
你们会失去 `Tiptap / ProseMirror` 现成提供的大量能力:
- 完整富文本 mark 生态
- 复杂 selection 行为
- 丰富 node view 生态
- 复杂粘贴与 HTML 解析
- 大量成熟 extension
### 7.2 会牺牲“快速接近 Notion 视觉体验”的速度
如果走 Rust-native minimal editor,你们能更快得到“可用”,但更慢得到:
- polished Notion-like 体验
- 高级菜单
- 丰富交互细节
- 页面级完整富文本 polish
### 7.3 仍然需要自己补的,主要是胶水与 `mnote` 特有语义
这条路线并不等于“全部自己造”,真正需要你们补的应尽量只剩下面这些:
- Rust editor core 到 `tree-first graph kernel` 的映射层
- `[[page]]` / `((block))` 与页面、块引用语义的接缝
- `mnote` 特有 block props、projection、读态派生
- 主文档页 feature flag、迁移兼容、回滚链路
- AI / CLI 到统一 Rust command 的工具面
- `mindmap``onlineTable`、媒体等延期块的 placeholder 接缝
下面这些不应默认进入“先自研再说”的名单:
- import / export
- history / undo redo
- diff / merge
- 文本缓冲与 selection primitives
- Markdown round-trip
### 7.4 需要接受第一版更“工程化”
第一版应更像:
- AI-first 块 Markdown 编辑器
- 结构化块命令壳
- 轻量 Obsidian + CLI
而不是:
- 完整 Notion 替代品
---
## 8. 最小功能面
在新的主线下,MVP 功能面应明确收窄。
## 8.1 第一优先级必须有
- 段落
- 标题
- 有序列表
- 无序列表
- 待办
- 折叠标题 / toggle
- 引用块
- 代码块
- 分割线
- 拆块
- 合并块
- 插入块
- 删除块
- 上移下移或拖拽重排
- 有限缩进
- Markdown 快捷输入
- `[[page]]`
- `((block))` 或等价块引用
- Markdown 导入导出
## 8.2 第二优先级可以后补
- 媒体块
- 进度块
- 目录派生
- 基础只读渲染优化
- 基础批量选择
- 多块复制粘贴
## 8.3 明确不进入第一阶段
- 协作
- 评论
- 高级表格
- mindmap 深度编辑
- OnlyOffice 深度接入
- 富文本高级 mark 体系
- 完整 AI suggestion UI
---
## 9. 替换 `BlockNote` 的方向
替换方向不再是“平移到 `Tiptap`”,而是下面三步。
### 9.1 先抽离语义,不先抽离视觉
先把 `BlockNote` 里仍然有价值的东西抽成:
- 块类型
- 动作合同
- token 引用语义
- 读态派生规则
而不是先追求新 UI 和新视觉。
### 9.2 先对齐 Rust command,再做新编辑壳
应先收口出统一命令,例如:
- `replace_block`
- `insert_block_after`
- `delete_block`
- `move_block`
- `indent_block`
- `outdent_block`
- `toggle_heading_collapse`
- `attach_reference_token`
- `detach_reference_token`
只有命令稳定后,UI、CLI、AI 才能共用。
### 9.3 先做最小读写链,再做复杂块
优先保证:
- 打开文档
- 编辑基础块
- 保存
- 导出 Markdown
- AI 修改
之后再补:
- 媒体
- progress
- mindmap placeholder
- 更复杂的 read view
---
## 10. 开发阶段
## 阶段 0:冻结需求与能力边界
### 目标
在新前提下,重新冻结能力边界。
### 输出
- 一份“必须做 / 可延后 / 不做”的能力清单
- 一份内部交互样例摘录(来自 `mnote-next`,仅供对照)
- 一份 `BlockNote` 仍需迁移的块类型清单
### 完成判定
- 主线需求被限制在轻量块编辑器范围
- 协作和完整富文本不再进入第一阶段
### Checklist
- [x] 已完成 `BlockNote` 自定义块盘点与三档分级,基线以 [`rust-block-editor-phase0-baseline-v1.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/process/rust-block-editor-phase0-baseline-v1.md) 为准:阶段 1 固定 `heading`、基础段落/列表、等价待办、`pageReference``blockReference``media``progressMeter` 后补;`mindmap``onlineTable` 延期。
- [x] 已完成 `BlockNote` 读写重耦合盘点,确认当前主风险仍集中在 `HocuspocusProvider + Yjs``buildDocumentSavePayload``DocumentToc``comments/search palette/editor bridge`,并在迁移文档中保留为观察点。
- [x] 已完成 `mnote-next` 内部交互样例提取,见 [`rust-block-editor-interaction-samples-v1.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/done/rust-block-editor-interaction-samples-v1.md);这些样例只作为回归样本,不作为“已验证结论”或主 benchmark。
- [x] 已在本文中冻结“不进入第一阶段”的能力:协作、评论、高级表格、`mindmap` 深度编辑、`OnlyOffice` 深度接入、完整富文本 mark 体系。
- [x] 已明确第一阶段唯一主目标是 AI-first 的轻量块 Markdown 编辑器,不再追求完整 Notion 视觉和能力逼近。
- [x] 已冻结四个参考层的采用矩阵,并单独声明 `mnote-next` 只作为内部样本;当前执行口径是“先复用参考层,只有缺口才自研胶水”,详见 [`rust-block-editor-adoption-matrix-v0.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/done/rust-block-editor-adoption-matrix-v0.md)。
## 阶段 1:定义 Rust block model 与 command
### 目标
先把底层语言定下来。
### 输出
- Rust block model
- block props 结构
- editor command 列表
- Markdown import/export 边界
- kernel content node 载荷边界
### 完成判定
- UI、CLI、AI 都能围绕这套命令讨论
- 结构不再依赖 `BlockNote` JSON
### Checklist
- [x] 已完成 `edita-core` 适配性评估与最小 spike,明确 `Editor / Block / Command / 无头执行边界` 可直接映射为 `mnote` editor core,详见 [`rust-block-editor-edita-spike-v0.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/process/rust-block-editor-edita-spike-v0.md)。
- [x] 已完成 `blocks` 适配性评估与最小 spike,明确 Markdown round-trip、history、diff/merge 的可复用面与缺口,详见 [`rust-block-editor-blocks-spike-v0.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/process/rust-block-editor-blocks-spike-v0.md)。
- [x] 已冻结首批 Rust block type、`BlockProps`、editor command、Markdown import/export 边界与 `content_node` 载荷格式,见 [`rust-block-editor-model-v0.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/process/rust-block-editor-model-v0.md) 与 [`rust-block-editor-command-contract-v0.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/done/rust-block-editor-command-contract-v0.md)。
- [x] 已明确 editor command 与 kernel command 的关系,以及 `pageReference` / `blockReference` 第一版先走 token 方案;`blocks``kode-doc``leptos-tiptap` 的定位已写入阶段 1 采用矩阵 v0。
- [x] 当前阶段 1 的对外落点是:结构不再以 `BlockNote` JSON 为长期格式,UI / CLI / AI 均围绕同一套 Rust command 讨论。
## 阶段 2:实现最小 Rust editor core
### 目标
基于 `edita-core` 思路或等价自研实现最小无头编辑器核心。
### 范围
- 基础块
- 拆块 / 合并
- 插入 / 删除
- 缩进 / 反缩进
- 标题折叠
- 简单 undo / redo
### 完成判定
- 已经可以在纯命令层编辑文档
- CLI 可直接调用 editor core
### Checklist
- [x] 已选择“`edita-core` 思路 + `blocks` 转换能力 + `mnote` 胶水”的实现路径,并在 [`rust/crates/mnote-editor-core/`](/mnt/Data1T/mnote/rust/crates/mnote-editor-core/) 落地最小 Rust editor core。
- [x] 已实现 block document 内存模型、最小 command executor、undo/redo、Markdown import/export、只读结构树派生,并把 `replace/insert/delete/split/merge/move/indent/outdent/toggle collapse` 覆盖到纯 Rust 测试。
- [x] 已把 `mnote-next` 抽取的人层交互样例沉淀为回归样本,见 [`rust-block-editor-interaction-samples-v1.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/done/rust-block-editor-interaction-samples-v1.md)CLI 可直接调用 `markdown-roundtrip``session-demo``ai-pipeline`
- [x] 当前阶段 2 的客观验证已跑通:`cargo test -p mnote-editor-core``cargo test -p mnote-cli`
## 阶段 3:接 Leptos 最小 UI 壳
### 目标
在 Leptos 中做一个够用的块编辑壳。
### 范围
- 文本输入
- slash 菜单
- 块菜单
- 上移下移或拖拽
- token 引用
- 基础只读渲染
### 完成判定
- 人可以完成日常 Markdown + 折叠 + 列表式编辑
- 不再需要 `BlockNote` 才能完成基本写作
### Checklist
- [x] 当前阶段 3 已先以 [`mnote-web` 文档壳](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs) 达成最小 Rust-native UI 壳目标:block list、focus、selection、hover、slash 菜单、标题折叠、有限缩进、`[[page]]` / `((block))` token 交互都已可见并有测试覆盖。
- [x] `kode` / `kode-leptos` / `kode-doc` 的采用结论已冻结为“块内输入器与选择处理参考层”;当前基线先用 Rust shell + 最小 DOM 交互验证语义,不在第一版追求复杂 `contenteditable` 或整壳 Leptos 化。
- [x] 主文档页已经完成双路径切换:默认由 `mnoteWebDocumentShellEnabled` + `mnoteWebDocumentShellUrl` 驱动接入新壳,`?editor=compat` 保留旧 `BlockNote` 兼容入口。
- [x] 新 UI 壳首屏不依赖 `HocuspocusProvider``Yjs``comments`、旧 `BlockNoteView`;默认主路径只先加载文档壳 iframe,旧编辑器仅在 compat 路径进入。
- [x] 最小浏览器回归链已经补齐并跑通,见 [`task103-document-shell-cutover-smoke.js`](/mnt/Data1T/mnote/scripts/task103-document-shell-cutover-smoke.js)。
### 阶段 3 纠偏说明(2026-04-18
上面这些勾选只代表:
- `mnote-web` 的 document shell prototype 已经打通
- 默认文档页已经能够切到这个 prototype surface
- block list / focus / selection / slash / indent / 引用 token 这些外层交互语义已经有最小验证
它们**不等于**“真人可编辑 runtime 已完成”。
当前默认主路径仍缺下面这层真正决定“像不像 Tiptap / Wolai 块编辑器”的能力:
- 块内文本输入 runtime
- 光标与选区更新
- IME / `beforeinput` / composition 处理
- 回车拆块、退格合并、Tab 缩进这类真实编辑事务
- 与 Rust editor core 对接的保存链,而不是只在壳内维护局部 UI state
因此,后续任务必须把“document shell prototype”与“human editing runtime”明确拆开:
- 现有 `task-059..062` 应理解为 prototype 子阶段
- 新增的纠偏批次应以“真人可编辑 runtime 接入”作为真正的 Phase 3 主目标
- 在真人可编辑 runtime 没完成之前,不应把当前壳视作已经达到 Wolai/Tiptap 类块编辑器基线
### 阶段 3R-1:真人编辑 runtime 契约冻结(task-072
真人编辑 runtime 与 prototype shell 的边界固定如下:
- prototype shell 只证明:
- 默认主文档页可切到 `mnote-web` surface
- block list / focus / hover / slash 按钮等外层 UI 可见
- 兼容入口 `?editor=compat` 仍可保留
- human editing runtime 必须额外证明:
- 每个可编辑块都存在真实输入宿主,而不是只渲染标题/按钮
- 文本输入走 `beforeinput` / `input` / composition / selection 事件面
- Enter 拆块、Backspace 合并、Tab / Shift+Tab 缩进、块类型切换属于真实编辑事务
- 编辑结果会进入保存链,并在刷新后回放
- 阶段 3 后续验收一律按“真人 runtime 闭环”判定,而不是按“壳存在”判定
### 阶段 3R-2:真人编辑 runtime 实现路径冻结(task-073
这一批实现路径固定为三层:
1. `tree-first graph kernel + Rust command contract`
- 继续作为事实源与长期语义 owner
2. `mnote-web human editing runtime`
- 当前批次先在 `mnote-web` 文档壳内落最小真人输入 runtime
- 真实输入宿主采用“块级输入器 + selection / beforeinput / composition / autosave”闭环
- 结构事务优先通过 `mnote-editor-core` 命令执行,而不是继续停留在纯前端按钮改状态
3. `save / replay / compat bridge`
- 写回继续走 `documents.save`
- 刷新回放与 `?editor=compat` 对照保留为最后验收面
参考层采用口径固定如下:
- `kode`
- 仍是第一优先参考层
- 当前主要借用其 buffer / selection / input runtime 分层思路,而不是等待整壳 Leptos 化完成后再开始可写闭环
- `leptos-tiptap`
- 保留为 fallback 参考
- 只在 `mnote-web` 现批次无法尽快形成可写闭环时再启用
- `compat`
- 只作为回退与对照路径,不再作为默认主编辑器事实层
也就是说,当前批次的目标不是“继续美化 prototype shell”,而是先把:
- 文本输入
- 选区/光标
- IME / composition
- 结构事务
- 保存/刷新回放
这五条真人编辑 runtime 主链补齐,再决定下一步是否进一步把输入器向 `kode` 的更完整形态收敛。
## 阶段 4AI-first 编辑链打通
### 目标
让 AI 成为第一编辑主体。
### 范围
- AI 调用 Rust command
- AI 导入文本并结构化成块
- AI 重写、总结、扩写、整理块结构
- CLI 与 AI 共用同一动作合同
### 完成判定
- AI 已能稳定创建、改写、整理文档
- 人类编辑退居辅助地位
### Checklist
- [x] 已冻结 AI/CLI 共用的 Rust editor command tool contract,并明确 AI/CLI 不再模拟 DOM/UI,见 [`rust-block-editor-ai-tool-contract-v0.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/done/rust-block-editor-ai-tool-contract-v0.md)。
- [x] 已打通“纯文本导入 -> AI 结构化成块 -> 按目标重写文档 -> 返回审计与变更报告”的最小链路,代码位于 [`mnote-editor-core/src/pipeline.rs`](/mnt/Data1T/mnote/rust/crates/mnote-editor-core/src/pipeline.rs) 与 [`mnote-cli/src/lib.rs`](/mnt/Data1T/mnote/rust/crates/mnote-cli/src/lib.rs)。
- [x] CLI 与 AI 已共用同一条命令合同与输出面,当前验证已覆盖 `MeetingNotesToTodos``LongParagraphToTitle``PageReorder` 三种场景。
- [x] 已补 AI 回归样例与显式 `ai_regression_*` 测试;协作、评论、suggestion review UI 仍保持不进入当前 AI-first 基线。
## 阶段 5:清理旧 `BlockNote` 壳
### 目标
`BlockNote` 从主文档页和主数据链中移出。
### 输出
-`BlockNote` 退场清单
- 数据迁移或兼容策略
- 测试与回滚方案
### 完成判定
- 主文档页默认不再挂 `BlockNote`
- 新 Rust-native 编辑器成为唯一主路径
### Checklist
- [x] 已完成 `BlockNote` 入口、依赖与内容格式迁移策略盘点,见 [`rust-block-editor-blocknote-migration-v1.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/process/rust-block-editor-blocknote-migration-v1.md)。
- [x] 主文档页默认路径已不再挂旧 `BlockNote`,而是切到 `mnote-web` 新文档壳;兼容入口仍保留 `?editor=compat` / debug 用途。
- [x] 文档页测试基线已切到“默认新壳 + compat 回退”双路径,当前基线验证包括 `task103-document-shell-cutover-smoke.js``pnpm test``cargo test -p mnote-web`
- 后续收尾:`task-068` 继续清理 `@blocknote/*`、Yjs、Mantine、旧 CSS 覆盖,以及 `mindmap` / `onlineTable` / 媒体块里仅供旧编辑器使用的残留耦合。
- 后续收尾:在 compat/debug 真正退场后,再删除 `blocknote-editor.tsx` 及其最终调用点,并完成包依赖瘦身。
---
## 11. 参考层的最终定位
### `edita-core`
定位:
- 主线参考
- Rust editor core 思路参考
- 命令与块模型参考
不是:
- 可直接完整拿来用的产品方案
### `blocks`
定位:
- 主线参考
- Rust block document model 参考
- Markdown / HTML / JSON / Plain Text 转换参考
- history、diff / merge、sanitizer 参考
不是:
- UI 壳
- `mnote` kernel 的直接事实源
### `kode`
定位:
- 主线参考
- Leptos 编辑输入层参考
- 块内编辑器、buffer、selection、WYSIWYG/tree editor 构件参考
不是:
- `mnote` 整个块编排系统的现成成品
- `tree-first graph kernel` 的替代品
### `mnote-next`
定位:
- 内部原型与交互样例来源
- 历史回归样例与反例来源
不是:
- 主 benchmark
- 外部成熟参考
- “已经验证完成”的结论来源
### `Tiptap`
定位:
- fallback
- 体验 benchmark
- 交互参考
不是:
- 当前主线 benchmark
### `leptos-tiptap`
定位:
- 若 Rust-native 路线推进受阻时的现实 fallback 接入层
- 对照用接缝方案
不是:
- 当前第一优先开发基线
### `BlockNote`
定位:
- 历史实现来源
- 迁移对象
- 当前自定义块与读写耦合清点来源
不是:
- 长期主线
- 新编辑器 benchmark
---
## 12. 最终收口
本文之后,`mnote` 在块编辑器路线上的统一口径固定为:
> **后续编辑器开发以 AI-first、CLI-first、Rust-native 的轻量块编辑器为主线;以 `edita-core + blocks + kode` 作为主基准组合;以 `leptos-tiptap` 作为 Leptos fallback 接入参考;`mnote-next` 只保留为内部交互样本,不作为主 benchmark。**
对应推进原则固定为:
- 不再以 `BlockNote` 兼容性为最高约束
- 不再默认把完整 Notion 富文本体验当作必须目标
- 协作默认不进第一阶段
- 编辑器首先服务 AI 命令、CLI 和 Rust command 统一
- 优先复用 `edita-core``blocks``kode``leptos-tiptap` 的参考层,只在缺口处自研胶水与主线集成
- `mnote-next` 只作为内部样本与回归案例来源,不再作为主要参考
- 以轻量、结构化、可脚本化、可维护为最高优先级
---
## 13. 最终采用矩阵(2026-04-18 基线)
| 参考层 | 当前采用结论 | 当前已落地的主线位置 | 保留为后续/兼容的部分 |
| --- | --- | --- | --- |
| `edita-core` | 直接采用其无头 command / editor 组织思路 | [`mnote-editor-core`](/mnt/Data1T/mnote/rust/crates/mnote-editor-core/) 的 block model、command executor、history 组织 | 暂不直接复用其完整 UI 或最终导出壳 |
| `blocks` | 部分采用 | Markdown import/export、history / diff / merge 思路,以及阶段 1/2 的 spike 与采用矩阵结论 | 若后续需要更深的 HTML/JSON 转换,再继续补胶水 |
| `kode` | 部分采用 | 作为块内输入器、selection、输入规则、tree editor 分层的参考层;当前先冻结为下一阶段可继续下沉的输入策略 | 还未把整体文档壳彻底替换为 `kode-leptos` 实现 |
| `leptos-tiptap` | 仅保留 fallback 参考 | 作为 Leptos bridge / runtime 接法与 SSR/CSR 接入样例,不进入当前主路径 | 若 Rust-native 输入层受阻,可作为临时 fallback 样板 |
| `mnote-next` | 仅保留内部样本 | 已抽取为 [`rust-block-editor-interaction-samples-v1.md`](/mnt/Data1T/mnote/design/old/05-editor-mainline/done/rust-block-editor-interaction-samples-v1.md) 的回归语义样例 | 不再作为 benchmark 或“以前写过所以继续沿用”的理由 |
| `BlockNote` | 降级为 compat/debug 与迁移来源 | 默认主文档页当前已切到 document shell prototype`?editor=compat` 仍保留为真实可写回退链与迁移观察点 | 等真人可编辑 runtime 完成后,再执行依赖清理与最终删除主线路径 |