diff --git a/AGENTS.md b/AGENTS.md index 9da541bd..df58aa67 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,8 +10,8 @@ - Next `documents/page` 读取主链已优先消费 Rust `mnote.page_aggregate.v1` 快照;TS `page-aggregate-builder` 仅保留为历史 adapter / test helper,不再作为 runtime fallback,也不再把“前端手工拼 `meta + content`”描述为当前主路径。 - `3000` 当前主壳已接入 Rust Web `/api/tree/events` 的 snapshot / delta / resync consumer,并已有 browser smoke 验证;后续收口重点是统一 live cache 与减少补偿链,而不是把它描述成“还没接 live stream”。 - 文档页默认主编辑器已切到页面内 `leptos-tiptap` island;`BlockNote` 已退出文档页默认主路径,只保留为历史参考实现 / 对照材料。 -- Page Aggregate 当前已输出 `blockDocument / blockProjectionVersion / projectionSource`,页面/块 AI 最小工具链已通过 Rust Hermes tools 读取和写入块投影;但这仍是从 `documents.content` / local markdown content 投影出来的过渡态,不是 EditorBlockDocument 原生落库完成态。 -- 当前最优先的架构收口不是继续扩编辑器 UI,而是 `Page Aggregate`、`tree command cutover`、`tree realtime event stream` 三条主线;AI 侧并行补 `7-10` 剩余验收矩阵,不把粗粒度 `mnote.page.save` 当成精确块编辑主入口。 +- Page Aggregate 当前已输出 `blockDocument / blockProjectionVersion / projectionSource`(`projectionSource=documents.content`),标题/正文/页面设置写入后 smoke 已通过(`task110`、`task-page-aggregate-body-sync-smoke`、`task-page-aggregate-options-sync-smoke`);页面/块 AI 最小工具链已通过 Rust Hermes tools 读取和写入块投影;但这仍是从 `documents.content` / local markdown content 投影出来的过渡态,不是 EditorBlockDocument 原生落库完成态。客户端 `PageAggregateClientState` reducer 仍在,页面域单一真源未完全闭环。 +- 当前最优先的架构收口不是继续扩编辑器 UI,而是 `Page Aggregate` 单一真源收口(标题/正文/页面设置 smoke 已通过)、`tree command cutover` 收尾、`tree realtime event stream` live cache 统一三条主线;AI 侧当前只做 Phase A(`mnote.doc.markdown_edit` + `mnote.doc.fetch` 增强,search/replace + `format: "markdown"` + local source),退役 `local_rule` planner 作为 Phase B;`review session`/流式 apply 属于 Phase C(设计冻结,当前不实施),不扩新 AI 功能,不把粗粒度 `mnote.page.save` 当成精确块编辑主入口。 ## 组件定位 @@ -19,6 +19,8 @@ - `BlockNote` 是历史参考实现 / 对照材料,不再是运行时系统组件、默认回退编辑器或系统事实源。 - `Mindmap` 是 `tree-first graph` 的一种视图和编辑挂件,不是对象真相层。 - `OnlyOffice` 是独立页面型编辑器,不直接嵌入 `BlockNote` 画布;正文中通常通过附件块跳转进入。 +- `page-ai/block-edit-workflow` route 是当前简单编辑的 fast-path 入口(`local_rule` planner 为过渡实现);长期方向是将 AI 编辑主路径收敛到 `mnote.doc.markdown_edit`(markdown 级 search/replace,见 7-14),`mnote.block.*` 保留为结构性辅助。复杂任务仍走 Hermes agent。 +- 树域三层模型:`Resource Tree`(kernel 对象组织真源)→ `File Tree`(主组织投影,`{title}.md` 为页面正文行)→ `Page Tree`(导航投影,不持有结构真相)。涉及资源归属优先走 Rust kernel 的 `KernelObjectIdentity` / `KernelProjectionResourceKind`。 ## 目录优先级 @@ -49,6 +51,8 @@ - 涉及文档页标题、页面设置、正文保存、页头与树一致性时,优先判断是否应收口到 `Page Aggregate`,不要继续在页面壳或 island 外侧拼第二份页面真相。 - 涉及页面新建、重命名、移动、归档、恢复、嵌入时,优先沿 `tree.*` 正式命名推进;`documents.*` 只视为兼容层,不应继续扩写为长期命令面。 - 涉及 AI 读取、定位或精确编辑页面块时,优先沿 `mnote.doc.*` / `mnote.block.*` Hermes tools 与 Rust `EditorCommand` 推进;`mnote.page.save` 只作为页面级兜底写入工具。 +- 涉及资源归属(哪个页面拥有哪个 mindmap/附件)、object identity 和资源生命周期时,优先沿 Resource Tree → File Tree projection → `tree.resource.*` 命令面推进;`tree.*` 是正式命令面,`documents.*` 只视为兼容层。 +- 页面 AI 编辑长期主路径为 `mnote.doc.markdown_edit`(search/replace 或 full_content,markdown 文本级),在线文档和本地 `.md` 文件共用。当前过渡实现为 `POST /api/page-ai/block-edit-workflow` fast-path(`local_rule` planner,Phase B 退役)。`mnote.block.*` 保留为结构性辅助(拖拽排序等)。两层操作模型已获 CLI Main(Lark Doc)参考实现验证。流式 apply + suggest/review(参考 BlockNote AI)作为 Phase C 设计冻结,当前不实施。复杂任务进入 `/api/hermes/client/runs`。模型不直接产出 unified diff 或 blockId 操作;最终定位、校验和写入由 Rust runtime 负责。 - 需要架构判断时,优先参考: - `/mnt/Data1T/mnote/ARCHITECTURE.md` - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md` @@ -59,6 +63,11 @@ - `/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md` - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md` - `/mnt/Data1T/mnote/design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md` + - `/mnt/Data1T/mnote/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md` + - `/mnt/Data1T/mnote/design/10-review/process/09-page-ai-fast-block-edit-runtime-review.md` + - `/mnt/Data1T/mnote/design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md` + - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-24-resource-tree-filetree-pagetree-source-contract-checklist-v1.md` + - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-12-main-editor-object-tab-resource-alignment-checklist-v1.md` ## 设计稿目录规则 diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index aff4ca44..296ee529 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,6 +1,8 @@ # MNOTE 当前架构梳理 > 更新时间:2026-05-16 +> +> **当前阶段:初步 MVP 已达成。** 3000 下文档页完整读写链路(标题、正文、页面设置、Page Aggregate)、Sidebar/File Tree/Page Tree 三层树模型、tree command(`tree.*` preferred)、tree realtime SSE(snapshot/delta/resync)、页面 AI 快速编辑(fast-path < 1s,当前 `local_rule` planner 为过渡实现,长期方向为 markdown 级编辑,见 7-14)均已通过真实浏览器 smoke 验证。剩余工作集中在单一真源收口、live cache 统一、AI 编辑路径从块级收敛到 markdown 文本层,而非继续证明架构可行性。 本文只描述当前仓库中真实成立的主线结构,以及当前最优先的架构收口点。 @@ -19,6 +21,7 @@ 3. `mnote-web` 是当前 Rust Web 主执行面,负责 3000 gateway、server-first shell、query / command / projection / transport 与 realtime stream;Next App Router 已降为 legacy compat / island bundle source,不再是当前主入口 4. 文档页默认主编辑器已切到页面内 `leptos-tiptap` island 5. `BlockNote` 已退出文档页默认主路径,仅作为历史参考实现 / 对照材料保留 +6. 页面 AI 工具链已建立最小闭环:`POST /api/page-ai/block-edit-workflow` 提供快速编辑 route(当前 `local_rule` planner 为过渡态,长期方向为 `mnote.doc.markdown_edit` 文本级搜索替换,见 7-14);Hermes tools(`mnote.doc.*` / `mnote.block.*`)承担复杂任务编排 一句话收口: @@ -27,6 +30,8 @@ 补充口径: > **主 Web 执行面当前以 `mnote-web` 为 3000 owner;Next App Router 只保留为 legacy compat、交互 island bundle source 与显式 debug/迁移辅助边界。** +> +> **页面 AI 块编辑当前以 fast-path `local_rule` planner(`/api/page-ai/block-edit-workflow`)为简单操作首选;Hermes agent(`mnote.doc.*` / `mnote.block.*` tools)保留为复杂任务编排器。** ## 2. 当前主线目录 @@ -155,16 +160,23 @@ - `page_tree` / `pageSubtree` 已进入统一聚合入口 - 页面/块 AI tools 已开始通过 Page Aggregate block projection 读取、定位、dry-run、替换、插入和受限移动块,并经 `page.body.save -> documents:updateContent` 持久化 -但仍未完成的关键点是: +2026-05-16 更新:以下四项已通过真实 3000 browser smoke 验证(证据见 `tmp/page-aggregate-*` 目录): -1. Rust 侧虽已提供最小 `Page Aggregate` snapshot 和 block projection v1,但当前 block projection 仍主要从 `documents.content` / local markdown content 投影,不是 EditorBlockDocument 原生落库完成态 -2. 标题 / 正文 / 页面设置虽已开始收口到 `page.*` family,但 projection 回流与运行时语义仍未完全统一 -3. AI 块工具最小闭环已启动,但 `scope=selection`、`format=page_xml/text`、多块插入、复杂块移动矩阵和持久审阅 UI 仍未完成 -4. 客户端仍保留 preferred sidebar snapshot 与本地 aggregate state reducer,说明页面域单一真源仍在推进中 +- 标题写入后 Page Aggregate、页头、Breadcrumb、Sidebar、Page Tree、File Tree 一致性(`task110`) +- 正文保存后 `body.revision` / `conflictDetectionKey` / `blockDocument` 同步(`task-page-aggregate-body-sync-smoke`) +- 页面设置写入后 `layout.pageOptions` 与 island runtime DOM 同步,刷新后不退回(`task-page-aggregate-options-sync-smoke` / `task-page-aggregate-refresh-persistence-smoke`) +- Convex 不可用时返回 degraded error(503 + `x-error-code=convex_unavailable`),不返回伪 fixture(route 级负向测试) + +仍未完成的关键点是: + +1. Rust 侧已提供最小 `Page Aggregate` snapshot 和 block projection v1,但当前 block projection 仍主要从 `documents.content` / local markdown content 投影(`projectionSource=documents.content`),不是 EditorBlockDocument 原生落库完成态 +2. 标题 / 正文 / 页面设置虽已收口到 `page.*` family 并通过 smoke,但客户端仍保留 `PageAggregateClientState` reducer(混合 server snapshot / draft title / local content),页面域单一真源仍未完全闭环 +3. AI 块工具最小闭环已启动且 fast-path < 1s,但 `scope=selection`、`format=page_xml/text`、多块插入、复杂块移动矩阵和持久审阅 UI 仍未完成 +4. Sidebar 仍通过 preferred snapshot(initial / query / tree_stream)做 freshness 选择,tree realtime live cache 未统一 因此当前正确表述应是: -> **文档页读取主链已进入 Rust-first `page aggregate` 过渡态,但页面域单一真源仍未闭环。** +> **文档页读取主链已进入 Rust-first `page aggregate` 过渡态,标题/正文/页面设置 smoke 已通过,但页面域单一真源(ClientState → Rust snapshot)与 tree realtime live cache 仍未闭环。** ## 6. 当前树域结构 @@ -221,6 +233,20 @@ > **`3000` 主壳当前已不再通过 `/api/tree/projections/*` 额外维护第二条 runtime live fallback;snapshot / delta / resync 直接消费 `/api/tree/events` 载荷。** +### 6.4 Resource Tree / File Tree / Page Tree 三层模型 + +当前树域已建立三层语义(合同见 `design/04-tree-domain/done/4-24-*` 与 `design/05-editor-mainline/done/5-12-*`): + +- **Resource Tree**:长期 canonical 对象组织树,Rust kernel 持有语义。资源类型包括 page、mindmap、attachment、onlyoffice、code 等(`KernelObjectIdentity`、`KernelProjectionResourceKind` 已在 `core-protocol` 落地)。 +- **File Tree**:Resource Tree 的主组织投影。展示页面文件夹、`{title}.md`(非 `index.md`)、mindmap、附件等资源。文件树行消费 Rust `/api/tree/projections/file` 或等价 projection,不在前端临时拼装第二真相。 +- **Page Tree**:面向阅读/导航的快捷投影。只显示页面关系和导航语义,不拥有排序、父子、附件归属的最终真相。 + +关键规则: + +- 文件树点击 mindmap 打开 mindmap object editor,不被 `{title}.md` 吞掉 +- `{title}.md` 只代表页面正文(Page Aggregate body),mindmap / OnlyOffice / 附件是不同 object model +- 页面树不持有独立结构真相,只显示文档导航关系 + ## 7. Mindmap 与 OnlyOffice ### 7.1 Mindmap @@ -253,6 +279,17 @@ OnlyOffice 仍然是: 目标: - 让标题 / 页面设置 / 正文 / page tree 统一成同一组 page aggregate projection 与 command family +- 前端不在页面壳、island 外侧、Sidebar preferred snapshot 外再拼第二份页面真相 + +当前进度(2026-05-16): + +- ✅ 文档页读取主链已 Rust-first,TS builder 退出 runtime,Next compat 返回 410 +- ✅ 标题单一真源 smoke 通过(`task110`):页头/Breadcrumb/Sidebar/Page Tree/File Tree 一致 +- ✅ 正文写入后 `body.revision` / `blockDocument` 同步 smoke 通过 +- ✅ 页面设置写入后 `pageOptions` 同步与刷新持久化 smoke 通过 +- ✅ Convex 不可用时返回 degraded error,不返回伪 fixture +- ⬜ block projection 从 EditorBlockDocument 原生落库(当前仍从 `documents.content` 投影) +- ⬜ 客户端 `PageAggregateClientState` reducer 退役,页面域完全以 Rust snapshot 为单一运行时真相 对应设计稿: @@ -290,9 +327,58 @@ OnlyOffice 仍然是: - 把 `mnote.page.save` 固定为页面级兜底写入工具,不再代表长期精确块编辑主入口 - 补齐 `scope=selection`、`format=page_xml/text`、多块插入、复杂块移动矩阵和持久审阅 UI +当前进度(2026-05-16,按 7-14 v2 更新): + +- ✅ 页面 AI 快速编辑 route 已上线:`POST /api/page-ai/block-edit-workflow` +- ✅ 简单编辑本地 planner(`local_rule`)已验证:788ms(过渡实现,将被 `markdown_edit` 替代) +- ✅ Hermes tools(`mnote.doc.*` / `mnote.block.*`)已可读取和写入块投影 +- ✅ 参考实现已确认两层模型可行性:CLI Main(Lark Doc)`str_replace` 对应 `markdown_edit`,`block_*` 对应 `apply_block_ops` +- ⬜ **Phase A(当前唯一活跃实施)**:`mnote.doc.markdown_edit` + `mnote.doc.fetch` 增强(search/replace + `format: "markdown"` + local source + Hermes 注册) +- ⬜ **Phase B(下一阶段)**:退役 `direct_block_edit_operations`,`page_ai_workflow.rs` 改走 `markdown_edit`,system prompt 产 search/replace 对 +- ⬜ `scope=selection`、`format=page_xml/text` 稳定输出 +- ⬜ tool manifest annotations(`readonly` / `destructive` / `requiresApproval` 等) +- ⬜ **Phase C(设计冻结,不实施)**:`StreamApplyController` + `ReviewSession` + `GhostTextOverlay`(流式 apply + suggest/review) +- ⬜ stale revision / idempotency 重放保护(已有 revision 乐观锁覆盖,补端到端 smoke) + +关键原则(2026-05-16 补充,按 7-14 v2 更新): + +- **两层操作模型**(参考 CLI Main Lark Doc):文本级 `mnote.doc.markdown_edit`(str_replace)为主路径(覆盖 80%+ 场景),块级 `mnote.doc.apply_block_ops` 为结构性辅助(< 20%) +- AI 编辑主路径应从块级降维到 markdown 文本层:新增 `mnote.doc.markdown_edit`(search/replace 或 full_content)作为主要 AI 写入工具 +- `mnote.block.*` 降级为结构性辅助(拖拽排序、精确块删除等),不删除 +- 当前 `local_rule` planner(`direct_block_edit_operations`)是过渡实现,应退役并替换为模型产出 search/replace 对 +- 在线 Convex 文档和本地 `.md` 文件共用同一条 markdown AI 写入路径(`resolve_source` → Convex | LocalFS) +- Markdown 既是 AI 编辑格式也是人类可读格式,不需要 XML 中间层 +- 流式 apply + suggest/review(参考 BlockNote AI 的 `StreamToolExecutor` + `suggestChanges`)仅作为 Phase C 设计冻结,当前不实施 + 对应设计稿: - `/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md` +- `/mnt/Data1T/mnote/design/10-review/process/09-page-ai-fast-block-edit-runtime-review.md` +- `/mnt/Data1T/mnote/design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md` + +### 8.5 定向 Bug Hunt 与质量基线 + +目标: + +- 围绕已知架构风险做定向排查,而非泛泛"找 bug" + +优先关注: + +- Page Aggregate 回流不一致 +- AI 块写入 conflict / stale revision +- File Tree `{title}.md` 与 page title 同步 +- tree stream resync / 双浏览器一致性 +- debug / compat / fallback 是否混入首屏主链 + +已有 smoke 体系(`scripts/` 目录): + +- `task110-page-title-single-truth-smoke.js`:标题全链路一致性 +- `task-page-aggregate-body-sync-smoke.js`:正文写入后 Page Aggregate 同步 +- `task-page-aggregate-options-sync-smoke.js`:页面设置写入后同步 +- `task-page-aggregate-refresh-persistence-smoke.js`:刷新持久化 +- `task123-rust-web-tree-live-stream-consumer-smoke.js`:tree realtime 消费 +- `task169-mindmap-realtime-smoke.js`:mindmap 隔离与持久化 +- `task179-tree-create-delete-no-reload-smoke.js`:树操作无刷新 ## 9. 当前不该再用的旧口径 @@ -302,7 +388,9 @@ OnlyOffice 仍然是: - “主编辑器还没切到页面内 Leptos island” - “当前最优先是继续证明 `leptos-tiptap` 能不能跑” - “当前最优先是先做树域 UI 重构” +- “Rust Web 还只是实验,没有接真实页面链路” +- “页面 AI 编辑必须经过 Hermes agent,没有快路径” -当前真正的卡点已经变成: +当前真正的卡点已经从“能不能跑”变成: -> **单一真源如何收口,以及 projection / command / realtime 三条链如何从兼容态进入正式主链。** +> **单一真源如何收口(Page Aggregate ClientState → Rust snapshot),projection / command / realtime 三条链如何从兼容态进入正式主链,以及 AI 块编辑如何从“能写”变成产品级可靠(selection、review、conflict、idempotency)。** diff --git a/bugs/04-tree-domain/done/4-43-sidebar-duplicate-migrate-to-tree-commands-v1.md b/bugs/04-tree-domain/done/4-43-sidebar-duplicate-migrate-to-tree-commands-v1.md new file mode 100644 index 00000000..706d9c29 --- /dev/null +++ b/bugs/04-tree-domain/done/4-43-sidebar-duplicate-migrate-to-tree-commands-v1.md @@ -0,0 +1,19 @@ +# 4-43 [done] 侧栏「复制页面」从 `/api/documents/duplicate` 迁移到 `/api/tree/commands` + +> 更新时间:2026-05-16 +> +> 状态:`done` + +## 问题 + +`sidebar.tsx:924` 的 `handleDuplicateDocument` 直接 `fetch("/api/documents/duplicate")`,走旧 Next.js compat 路由,不经过 Rust tree command 链,不生成 tree domain event。 + +## 修复 + +改为调用 `tree-command-client.ts` 中已有的 `copyTreeCommand`,POST 到 `/api/tree/commands`,使用 `action: "copy"` + Rust `tree.subtree.copy` 命令。 + +## 证据 + +- `wolai-frontend/src/components/sidebar/sidebar.tsx`:`handleDuplicateDocument` 改为 `copyTreeCommand({ targetParentId: null, items: [{ documentId: node.id, recursive: true }] })` +- `wolai-frontend/src/components/sidebar/sidebar.tsx`:import 新增 `copyTreeCommand` +- 验证:单页面复制后 `/api/tree/commands` 应收到 `action: "copy"`,不走 `/api/documents/duplicate` diff --git a/bugs/04-tree-domain/done/4-44-sidebar-empty-trash-compat-todo-v1.md b/bugs/04-tree-domain/done/4-44-sidebar-empty-trash-compat-todo-v1.md new file mode 100644 index 00000000..7f51205e --- /dev/null +++ b/bugs/04-tree-domain/done/4-44-sidebar-empty-trash-compat-todo-v1.md @@ -0,0 +1,18 @@ +# 4-44 [done] 侧栏「清空垃圾箱」标注 TODO 等待 Rust `tree.trash.empty` 命令 + +> 更新时间:2026-05-16 +> +> 状态:`done` + +## 问题 + +`sidebar.tsx:2637` 的垃圾桶清空调用仍走旧 Next.js `/api/documents/empty-trash`。Rust 侧当前支持逐条 `purge`(`tree.node.purge`),但无批量 `empty_trash` 命令。 + +## 处理 + +- 代码中已添加 `// TODO: Rust tree.trash.empty 命令就绪后切到 /api/tree/commands` 标注 +- 当前行为不变:仍走 `/api/documents/empty-trash` → `page-command-adapter.ts` → Rust bridge(`documents.emptyTrashByWorkspace` alias),功能正常但命令名不统一 + +## 后续 + +Rust `tree.trash.empty` action 就绪后执行迁移。 diff --git a/bugs/04-tree-domain/done/4-45-create-child-dead-code-cleanup-v1.md b/bugs/04-tree-domain/done/4-45-create-child-dead-code-cleanup-v1.md new file mode 100644 index 00000000..994bfe17 --- /dev/null +++ b/bugs/04-tree-domain/done/4-45-create-child-dead-code-cleanup-v1.md @@ -0,0 +1,22 @@ +# 4-45 [done] `createChildDocumentCommand` 死代码清理 + +> 更新时间:2026-05-16 +> +> 状态:`done` + +## 问题 + +`tree-command-client.ts:225` 定义的 `createChildDocumentCommand` 导出但从未被任何模块 import。它 POST 到 `/api/documents/create-child` 旧 Next.js 路由。指向 `page-command-adapter.ts` 使用 `documents.create` compat alias。 + +## 修复 + +- 删除 `createChildDocumentCommand` 函数 +- 删除 `DocumentCreateChildCommandResult` 类型(仅被该函数使用) +- 删除 `CreateChildDocumentInput` 类型(仅被该函数使用) +- 删除 `/api/documents/create-child/route.ts` Next.js 路由文件 +- 调用者应使用已存在的 `createDocumentCommand(parentId)` → `/api/tree/commands`(`tree.node.create`) + +## 验证 + +- `grep -rn "createChildDocumentCommand\|DocumentCreateChildCommandResult\|CreateChildDocumentInput"` 确认无源文件引用 +- `pnpm test` 中相关测试不应因死代码删除而失败 diff --git a/bugs/05-editor-mainline/done/5-14-document-template-compat-todo-v1.md b/bugs/05-editor-mainline/done/5-14-document-template-compat-todo-v1.md new file mode 100644 index 00000000..687ee917 --- /dev/null +++ b/bugs/05-editor-mainline/done/5-14-document-template-compat-todo-v1.md @@ -0,0 +1,18 @@ +# 5-14 [done] 文档页「应用模板」标注 TODO 等待 Rust `tree.page.template` 命令 + +> 更新时间:2026-05-16 +> +> 状态:`done` + +## 问题 + +`document-content.tsx:780` 的 `handleAddToTemplates` 走旧 Next.js `/api/documents/template`。Rust 侧无对应 `tree.*` 命令。 + +## 处理 + +- 代码中已添加 `// TODO: Rust tree.page.template 或 page.layout.applyTemplate 命令就绪后切到 /api/tree/commands` 标注 +- 当前行为不变:仍走 `/api/documents/template` → `page-command-adapter.ts` → Rust bridge,功能正常但命令名不统一 + +## 后续 + +Rust `tree.page.template` action 就绪后执行迁移。 diff --git a/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md b/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md index c135ad69..baebff47 100644 --- a/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md +++ b/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md @@ -12,6 +12,7 @@ > - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-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/process/7-14-online-local-ai-markdown-editing-convergence-v1.md` > - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md` > - `/mnt/Data1T/mnote/design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md` @@ -35,12 +36,13 @@ - 标题、正文、页面设置、page tree、AI 写入口尚未完全闭环到同一组 projection / command family。 - `tree.*` 已是 preferred command name,但 `documents.*` 兼容命令面仍未完全降级。 - `/api/tree/events` 已是 tree realtime 主链,但 Sidebar、page subtree、filetree、preferred snapshot 还没有完全统一到一套 live cache。 -- AI 块工具已有最小闭环,但 selection、page_xml/text、多块插入、复杂块移动矩阵、持久 preview/review UI 和冲突矩阵仍未补齐。 +- AI 块工具已有最小闭环,但当前编辑路径以块操作(blockId)为中心——AI 被迫理解 UI 层概念,且本地 `.md` 文件无 AI 写入路径。`7-14` 提出应将 AI 编辑主路径修正为 markdown 文本级(search/replace),`mnote.block.*` 降级为结构性辅助,在线 Convex 文档与本地文件共用同一条 markdown 写入路径。 补充 BlockNote / Tiptap AI 参考后的判断: - BlockNote AI 和 Tiptap AI Toolkit 可以参考的是 AI runtime shape 与 tool contract,不是 mnote 的事实源。 - AI 方向下一步只应补基础底座:`PageAIContextBuilder`、`scope=selection`、`page_xml/text`、tool manifest annotations、`PageAIReviewSession`、accept/reject/retry/abort 状态机。 +- 2026-05-16 补充(受 `7-14` 方向修正):AI 编辑主路径应从块级操作调整为 markdown 文本级 search/replace,新增 `mnote.doc.markdown_edit` 作为主要 AI 写入工具;当前 `local_rule` planner(`direct_block_edit_operations`)是过渡实现,应退役。在线 Convex 文档和本地 `.md` 文件共用同一条写入路径。 - 在非 AI 主架构和 AI 基础合同打牢之前,不应扩展新的 AI agent 工作流、复杂 AI UI 或跨页面智能功能。 因此,下一阶段不应优先“大改架构”或“大量加新功能”,而应优先做: @@ -113,6 +115,14 @@ - 不新增复杂 AI 自动化功能面。 - 不把 `@blocknote/xl-ai` 或 BlockNote `AIExtension` 作为 runtime dependency。 - 不让 AI 写入绕过 `dryRun/idempotencyKey/revision/conflictDetectionKey/revisionRef`。 +- **不把 `direct_block_edit_operations` / `local_rule` planner 当作长期 AI 编辑路径(当前为过渡实现,将被 `markdown_edit` 替代)。** +- **不新增 `mnote.block.*` 工具;现有保留为结构性辅助。** + +**2026-05-16 新增(受 7-14 方向修正):** + +- **Phase A(当前唯一活跃实施)**:`mnote.doc.markdown_edit` + `mnote.doc.fetch` 增强(search/replace + `format: "markdown"` + local source + Hermes 注册,7-14 v2 Phase A)。 +- **Phase B(下一阶段)**:退役 `direct_block_edit_operations`,`page_ai_workflow.rs` 改走 `markdown_edit`(7-14 v2 Phase B)。 +- 在线 Convex 文档和本地 `.md` 文件共用同一条 markdown AI 写入路径(`resolve_source` → Convex | LocalFS)。 ### P1:定向 Bug Hunt @@ -225,6 +235,29 @@ cargo test --manifest-path rust/Cargo.toml -p mnote-web document_shell_errors_wi - [ ] 更新 `design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md` 的每个 phase 证据。 - [ ] 更新 `design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md` 的 Hermes 工具路由与审阅面 checklist。 +**新增(2026-05-16,受 7-14 方向修正):** + +**Phase A(当前唯一活跃实施):** +- [ ] `mnote.doc.markdown_edit` 核心实现:resolve_source → search_replace → write_target +- [ ] `mnote.doc.markdown_edit` 搜索替换语义:精确匹配 → fuzzy fallback → operationsFailed(7-14 §5) +- [ ] `mnote.doc.markdown_edit` Convex 写入 adapter(复用 `page.body.save` 链路) +- [ ] `mnote.doc.markdown_edit` 本地文件写入 adapter(`fs.writeFile` + GFM AST markdown 序列化) +- [ ] `mnote.doc.fetch format: "markdown"` 增强(Page Aggregate 产出 PageMarkdown) +- [ ] `mnote.doc.fetch` local source 支持(识别本地文件路径并返回 `.md` 原文) +- [ ] Hermes tool manifest 注册 `mnote.doc.markdown_edit` +- [ ] Hermes `mnote` plugin 更新:`mnote_doc_fetch` schema 增加 `format: "markdown"` 和本地文件路径支持 +- [ ] 乐观锁:`revision` 冲突检测 +- [ ] 单元测试 + smoke(在线 + 本地两种 source) + +**Phase B(下一阶段):** +- [ ] `direct_block_edit_operations` 退役(`page_ai_workflow.rs` `local_rule` 分支) +- [ ] `page_ai_workflow.rs` 修正:system prompt 改为产 search/replace 对,底层走 `mnote.doc.markdown_edit` +- [ ] 补全 operation schema(`content` 字段) +- [ ] 浏览器 smoke:自然语言编辑可用(不使用「」格式) + +**Phase C(设计冻结,不实施):** +- [ ] 流式 apply + suggest/review 设计已冻结,不阻塞 Phase A/B 实施 + 2026-05-16 Page Block AI context / format focused smoke 证据: - 新增并运行 `scripts/task-page-block-ai-context-format-smoke.js`,通过真实 3000 + 测试账号创建临时页,用 `mnote.page.save` 初始化 `p_1/p_2/p_3`,再验证 Hermes mnote tools 的 context / format / annotations / selection guard。 @@ -471,6 +504,8 @@ MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:300 - [ ] 不把 `mnote.page.save` 包装成精确块编辑长期方案。 - [ ] 不在 compat route 继续扩写长期业务语义。 - [ ] 不把 BlockNote / Tiptap AI runtime 作为 mnote runtime 依赖。 +- [ ] 不把 `direct_block_edit_operations` / `local_rule` planner 当作长期 AI 编辑路径(当前为过渡实现,将被 `mnote.doc.markdown_edit` 替代)。 +- [ ] 不新增 `mnote.block.*` 工具;`mnote.block.*` 保留为结构性辅助,不做块操作向新工具的扩张。 --- @@ -481,6 +516,7 @@ MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:300 - [ ] Page Aggregate 的标题 / 正文 / 页面设置 / page tree / AI fetch 回读形成同一组可验证真相。 - [ ] `7-10` 的 Page Block AI Tooling 剩余矩阵完成或明确拆出后续 process 文档。 - [ ] `7-11` 的 AI 基础 runtime 口径完成:context、format、manifest annotations、review session、状态机边界都有代码或明确后续 checklist。 +- [ ] 7-14 v2 Phase A + B 全部完成(`mnote.doc.markdown_edit` + `mnote.doc.fetch` 增强 + `page_ai_workflow.rs` 收口);Phase C 设计已冻结。设计稿修正已由 7-14 v2 自行完成。 - [ ] `tree.*` command 面对主要页面生命周期动作成为唯一 preferred runtime 主链。 - [ ] tree realtime live cache 覆盖 Sidebar、Page Tree、File Tree、page subtree 的关键写后更新。 - [ ] 至少一轮定向 bug hunt 完成,所有 P0/P1 blocker 已归档到 `bugs/*/done/` 或明确保留为后续 process。 @@ -490,5 +526,5 @@ MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:300 ## 6. 给后续 /goal 的持续执行 Prompt ```text -/goal objective: 持续执行 /mnt/Data1T/mnote/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md,按 P0 -> P1 顺序推进 MNOTE 架构收口、AI 基础底座和定向 bug hunt。每轮开始先读取 /home/lix/.codex/memories/PROFILE.md 与 ACTIVE.md,再读取 AGENTS.md、ARCHITECTURE.md、design/01-05-current-priority-overview.md、本 checklist、design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md 和 design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md。必须保护用户已有未提交改动,不回滚、不覆盖、不删除无关文件。优先使用多个 subagent 并行做只读审查和浏览器验证,主线程只整合证据和做小范围实现。执行顺序固定为:1) Page Aggregate 单一真源;2) tree command cutover;3) tree realtime live cache;4) AI 基础工具与审阅底座,只补 context/selection/page_xml/tool annotations/review session/conflict/idempotency,不扩新 AI 功能;5) 定向 bug hunt。每完成一个小项都要更新本 checklist 和对应 design/bugs 文档,补真实验证命令或证据路径。不要优先扩新功能,不要大改架构,不要把 compat/debug/fallback 当主链,不要把 BlockNote/Tiptap AI runtime 作为 mnote runtime 依赖。验证至少包含 git diff --check、相关 cargo test / smoke;如涉及 3000 页面,使用 mnote-tester 或浏览器自动化并保留截图/JSON 证据。 +/goal objective: 持续执行 /mnt/Data1T/mnote/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md,按 P0 -> P1 顺序推进 MNOTE 架构收口、AI 基础底座和定向 bug hunt。每轮开始先读取 /home/lix/.codex/memories/PROFILE.md 与 ACTIVE.md,再读取 AGENTS.md、ARCHITECTURE.md、design/01-05-current-priority-overview.md、本 checklist、design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md、design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md、design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md。必须保护用户已有未提交改动,不回滚、不覆盖、不删除无关文件。优先使用多个 subagent 并行做只读审查和浏览器验证,主线程只整合证据和做小范围实现。执行顺序固定为:1) Page Aggregate 单一真源;2) tree command cutover;3) tree realtime live cache;4) AI 基础工具与审阅底座,按 `7-14` v2 方向优先做 Phase A(`mnote.doc.markdown_edit` + `mnote.doc.fetch` 增强),Phase B 退役 `local_rule` planner + `page_ai_workflow.rs` 收口;Phase C(流式 apply + suggest/review)仅设计冻结不实施。同时补 context/selection/page_xml/tool annotations,不扩新 AI 功能;5) 定向 bug hunt。每完成一个小项都要更新本 checklist 和对应 design/bugs 文档,补真实验证命令或证据路径。不要优先扩新功能,不要大改架构,不要把 compat/debug/fallback 当主链,不要把 BlockNote/Tiptap AI runtime 作为 mnote runtime 依赖。验证至少包含 git diff --check、相关 cargo test / smoke;如涉及 3000 页面,使用 mnote-tester 或浏览器自动化并保留截图/JSON 证据。 ``` diff --git a/wolai-frontend/src/app/api/documents/create-child/route.ts b/wolai-frontend/src/app/api/documents/create-child/route.ts deleted file mode 100644 index b7f63813..00000000 --- a/wolai-frontend/src/app/api/documents/create-child/route.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NextResponse } from "next/server"; -import { isConvexEnabled } from "@/lib/convex/enabled"; -import { executeDocumentCreateChildBridgeCommand } from "@/lib/documents/page-command-adapter"; - -export const dynamic = "force-dynamic"; - -export async function POST(request: Request) { - if (isConvexEnabled()) { - return executeDocumentCreateChildBridgeCommand(request); - } - - return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 }); -} diff --git a/wolai-frontend/src/components/editor/document-content.tsx b/wolai-frontend/src/components/editor/document-content.tsx index 88fc0861..c7501b66 100644 --- a/wolai-frontend/src/components/editor/document-content.tsx +++ b/wolai-frontend/src/components/editor/document-content.tsx @@ -788,6 +788,7 @@ export function DocumentContent({ return; } window.alert("已添加为模板"); + // TODO: Rust `tree.page.template` 或 `page.layout.applyTemplate` 命令就绪后切到 /api/tree/commands router.refresh(); }, [documentId, readOnly, router]); diff --git a/wolai-frontend/src/components/sidebar/sidebar.tsx b/wolai-frontend/src/components/sidebar/sidebar.tsx index 8bd525af..a2677b94 100644 --- a/wolai-frontend/src/components/sidebar/sidebar.tsx +++ b/wolai-frontend/src/components/sidebar/sidebar.tsx @@ -132,6 +132,7 @@ import { GroupManagerDialog } from "@/components/groups/group-manager-dialog"; import { copyTreeCommand, createDocumentCommand, + copyTreeCommand, deleteDocumentCommand, embedDocumentCommand, moveDocumentCommand, @@ -921,12 +922,12 @@ function SidebarContent({ initialData, sidebarData: externalSidebarData, sidebar const handleDuplicateDocument = useCallback( async (node: SidebarTreeNode) => { - const response = await fetch("/api/documents/duplicate", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ documentId: node.id }), - }); - if (!response.ok) { + try { + await copyTreeCommand({ + targetParentId: null, + items: [{ documentId: node.id, recursive: true }], + }); + } catch { window.alert("复制失败,请稍后再试"); return; } @@ -2645,6 +2646,7 @@ function SidebarContent({ initialData, sidebarData: externalSidebarData, sidebar return; } await Promise.all([sidebarQuery.refetch(), refreshTree()]); + // TODO: Rust `tree.trash.empty` 命令就绪后切到 /api/tree/commands } finally { setEmptyingTrash(false); } diff --git a/wolai-frontend/src/lib/documents/tree-command-client.ts b/wolai-frontend/src/lib/documents/tree-command-client.ts index 9f1e92f8..4baad9f8 100644 --- a/wolai-frontend/src/lib/documents/tree-command-client.ts +++ b/wolai-frontend/src/lib/documents/tree-command-client.ts @@ -71,12 +71,6 @@ export type DocumentCreateCommandResult = { meta?: DocumentCommandMeta; }; -export type DocumentCreateChildCommandResult = { - pageId: string; - title?: string | null; - meta?: DocumentCommandMeta; -}; - type RenameDocumentInput = { documentId: string; workspaceId?: string | null; @@ -141,12 +135,6 @@ type CopyTreeCommandInput = { }>; }; -type CreateChildDocumentInput = { - parentId: string | null; - title: string; - blocks: unknown[]; -}; - async function postDocumentCommand(path: string, payload: unknown, fallbackMessage: string): Promise { const response = await fetch(path, { method: "POST", @@ -222,16 +210,6 @@ export async function createDocumentCommand(parentId: string | null): Promise { - return postDocumentCommand( - "/api/documents/create-child", - input, - "创建子页面失败,请稍后再试", - ); -} - export async function renameDocumentCommand(input: RenameDocumentInput): Promise<{ ok: true; meta?: DocumentCommandMeta }> { const response = await postTreeCommand( {