# 1-5 [process] 下一阶段顺序执行 checklist v1 > 创建时间:2026-05-19 > > 当前状态:`PROCESS` > > 上位依据: > - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-4-next-phase-execution-roadmap-v1.md` > - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-3-current-priority-execution-checklist-v1.md` > - `/mnt/Data1T/mnote/design/05-editor-mainline/reference/5-14-zed-lapce-vscode-reference-adoption-matrix-v1.md` > > 目标:给出一份可以顺序执行、每一步都有完成验收、且标明参考源码位置的下一阶段执行清单。 --- ## 0. 执行原则 - [ ] 每个阶段必须先补或确认测试,再改实现。 - [ ] 每个阶段只能收口当前主链,不新增通用 IDE 产品面。 - [ ] 新增长期命令必须优先走 `tree.*` / `tree.resource.*` / `page.*`,不能继续扩 `documents.*`。 - [ ] 涉及本地文件写入时,必须携带 workspace identity、allowed roots、expected file version。 - [ ] 涉及 UI / live stream 时,必须补 browser smoke 或复用既有 smoke。 - [ ] 每完成一个阶段,必须把验证命令和 smoke 证据写回本文件或 `1-3`。 --- ## 1. Phase A0:建立执行基线 目标: > **确认当前 P0-P3 既有能力仍然稳定,避免在架构收口前带着红灯推进。** ### 1.1 基线验证 - [ ] 运行 Rust 格式检查。 - 命令:`cargo fmt --check --all --manifest-path rust/Cargo.toml` - 完成验收:命令通过。 - [ ] 运行 local-first 权限与 workspace 基线测试。 - 命令:`cargo test -p mnote-web local_folder -- --nocapture` - 命令:`cargo test -p mnote-web local_access_policy -- --nocapture` - 命令:`cargo test -p mnote-web hermes_client_local_acp -- --nocapture` - 完成验收:三组测试通过。 - [ ] 运行 Page Aggregate / tree command 基线测试。 - 命令:`cargo test -p mnote-web page_aggregate -- --nocapture` - 命令:`cargo test -p mnote-web tree_command -- --nocapture` - 完成验收:两组测试通过。 - [ ] 运行 local-first guard。 - 命令:`npm run check:local-first-convex-guard` - 完成验收:命令通过,新增路径没有把 Convex 恢复成默认正文主存储。 ### 1.2 基线 smoke - [ ] 冲突 UI smoke。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task451-local-markdown-conflict-resolution-ui-smoke.js` - 完成验收:tiptap 与外部/agent 写入冲突仍能显示、合并、保存。 - [ ] 本地搜索索引 smoke。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task452-local-search-index-browser-smoke.js` - 完成验收:新建、重命名、搜索、反链、标签仍稳定。 - [ ] agent changed files smoke。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task453-local-folder-page-ai-changed-files-smoke.js` - 完成验收:AI 写入后 UI 能显示 `agent.changed_files`。 --- ## 2. Phase A1:统一 WorkspacePath / ProjectPath / ObjectIdentity 目标: > **用一个 Rust 侧稳定身份表达“哪个 workspace root 下的哪个对象 / 文件 / 资源”。** ### 2.1 当前代码锚点 - MNote: - `rust/crates/core-protocol/src/kernel.rs` - `KernelObjectIdentity` - `PageBodyWriteRequest` - `rust/crates/core-protocol/src/lib.rs` - `rust/crates/mnote-web/src/routes/local_folder_source.rs` - `rust/crates/mnote-web/src/ssr/pages/layout.rs` - `fileObjectIdentity` - `readFileTreeObjectIdentity` - `rust/crates/mnote-web/src/routes/tree.rs` ### 2.2 参考代码位置 - Zed: - `design/05-editor-mainline/reference-code/zed/crates/project/src/project.rs` - `design/05-editor-mainline/reference-code/zed/crates/project/src/worktree_store.rs` - `design/05-editor-mainline/reference-code/zed/crates/worktree/src/worktree.rs` - SideX: - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/path_util.rs` - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/multi_root.rs` - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/workspace.rs` ### 2.3 顺序任务 - [ ] 盘点当前所有 path key / object key。 - 搜索命令:`rg -n "ObjectIdentity|objectIdentity|rootUri|relativePath|fileVersion|documentId" rust/crates/mnote-web rust/crates/core-protocol -S` - 完成验收:列出哪些入口仍只用 `documentId`、绝对路径或前端拼接 key。 - [ ] 在 `core-protocol` 中明确 `WorkspacePath` 或等价结构。 - 建议字段:`workspace_id`、`root_uri`、`root_id`、`relative_path`、`source_kind`、`object_identity`、`resource_kind`。 - 完成验收:结构能表达页面 `.md`、mindmap、office、附件、目录节点。 - [ ] 给 local folder file tree 输出稳定 identity。 - 重点文件:`rust/crates/mnote-web/src/routes/local_folder_source.rs` - 完成验收:File Tree row、Page Tree row、Resource row 均能携带统一 identity,不再由前端临时猜测。 - [ ] 前端 sidebar/filetree 消费统一 identity。 - 重点文件:`rust/crates/mnote-web/src/ssr/pages/layout.rs` - 完成验收:`fileObjectIdentity` / `readFileTreeObjectIdentity` 不再作为事实源,只作为兼容读取层。 ### 2.4 验收 - [ ] 单测覆盖 identity 序列化与反序列化。 - 建议命令:`cargo test -p core-protocol object_identity -- --nocapture` - [ ] local folder tree 测试覆盖页面 `.md` 和资源对象 identity。 - 建议命令:`cargo test -p mnote-web local_folder -- --nocapture` - [ ] 浏览器 smoke 覆盖 filetree active reveal 和标题同步。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task438-filetree-title-md-active-reveal-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task440-page-title-filetree-md-sync-smoke.js` 完成标准: - [ ] 本地页面、资源、附件、目录节点都能映射到同一套 workspace identity。 - [ ] UI 不再需要通过文件名或 DOM 属性临时反推对象身份。 --- ## 3. Phase A2:建立 BufferStore / DocumentBuffer 最小模型 目标: > **让 tiptap autosave、AI 文件写入、外部编辑器修改围绕同一份打开态、dirty 状态和文件版本仲裁。** ### 3.1 当前代码锚点 - `rust/crates/core-protocol/src/kernel.rs` - `PageBodyWriteRequest.expected_file_version` - `rust/crates/mnote-web/src/routes/documents.rs` - `/api/page-body/write` - `/api/documents/save` compat - `rust/crates/mnote-web/src/routes/local_folder_source.rs` - `write_local_markdown_page_body` - `save_local_markdown_page` - `rust/crates/mnote-web/src/routes/web_shell.rs` - `conflictDetectionKey` - `fileVersion` - `rust/crates/mnote-web/src/routes/editor.rs` ### 3.2 参考代码位置 - Zed: - `design/05-editor-mainline/reference-code/zed/crates/project/src/buffer_store.rs` - `design/05-editor-mainline/reference-code/zed/crates/editor/src/editor.rs` - Lapce: - `design/05-editor-mainline/reference-code/lapce/lapce-app/src/doc.rs` - VS Code: - `design/05-editor-mainline/reference-code/vscode/src/vs/platform/files` - `design/05-editor-mainline/reference-code/vscode/src/vs/workbench/services/filesConfiguration` ### 3.3 顺序任务 - [ ] 盘点所有文件写入口。 - 搜索命令:`rg -n "documents.save|page.body.save|page-body/write|write_local_markdown|expectedFileVersion|conflictDetectionKey" rust/crates -S` - 完成验收:列出 tiptap、Hermes tool、page save、documents compat、外部 watcher 入口。 - [ ] 定义 `DocumentBuffer` 最小字段。 - 建议字段:`workspace_path`、`file_version`、`base_content_hash`、`current_content_hash`、`dirty_state`、`external_change_state`、`last_loaded_at`、`last_saved_at`。 - 完成验收:字段能覆盖 clean、dirty、stale、external modified、deleted 五种状态。 - [ ] 让 `/api/page-body/write` 成为本地 `.md` 正文写入主入口。 - 重点文件:`rust/crates/mnote-web/src/routes/documents.rs` - 完成验收:本地 markdown 写入必须携带 `expectedFileVersion`;`documents/save` 只作为 compat adapter。 - [ ] 把冲突 UI 的 source 数据改为来自 buffer 状态。 - 重点文件:`rust/crates/mnote-web/src/ssr/pages/layout.rs` - 完成验收:冲突面板能显示 editor base version、disk version、source actor。 ### 3.4 验收 - [ ] stale 写入被拒绝。 - 命令:`cargo test -p mnote-web local_folder_documents_save_rejects_stale_expected_file_version -- --nocapture` - [ ] Page Body 写入测试通过。 - 命令:`cargo test -p mnote-web page_aggregate -- --nocapture` - [ ] 冲突 UI smoke 通过。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task451-local-markdown-conflict-resolution-ui-smoke.js` 完成标准: - [ ] tiptap、AI、外部修改共享同一版本仲裁模型。 - [ ] 外部文件变更不能静默覆盖 dirty buffer。 - [ ] `documents/save` 不再被新增路径当作长期主入口。 --- ## 4. Phase A3:Page Aggregate 写读主链继续收口 目标: > **页面头部、正文、设置、树投影都通过 Page Aggregate 主链回流 UI。** ### 4.1 当前代码锚点 - `rust/crates/core-protocol/src/page_aggregate.rs` - `rust/crates/mnote-web/src/routes/documents.rs` - `rust/crates/mnote-web/src/ssr/pages/document.rs` - `rust/crates/mnote-web/src/ssr/pages/layout.rs` - `rust/crates/bridge-runtime/src/lib.rs` - `rust/crates/storage-convex-bridge/src/mapping.rs` ### 4.2 参考代码位置 - Zed: - `design/05-editor-mainline/reference-code/zed/crates/project/src/project.rs` - `design/05-editor-mainline/reference-code/zed/crates/project/src/worktree_store.rs` - VS Code: - `design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files` ### 4.3 顺序任务 - [ ] 盘点仍直接拼 `meta + content` 或读取 `documents.content` 的 runtime 路径。 - 搜索命令:`rg -n "documents.content|getContent|getMeta|meta \\+ content|page_aggregate|pageAggregate" rust/crates wolai-frontend src -S` - 完成验收:列出仍存在的 runtime fallback,并标记 `compat only` 或待删除。 - [ ] 标题、正文、页面设置写入后只触发 Page Aggregate refresh。 - 重点文件:`rust/crates/mnote-web/src/routes/documents.rs` - 重点文件:`rust/crates/mnote-web/src/ssr/pages/layout.rs` - 完成验收:写入后 UI 更新来源能追溯到 Page Aggregate,而不是局部补偿状态。 - [ ] 明确 `documents.*` 在 Page Aggregate 中的兼容边界。 - 重点文件:`rust/crates/storage-convex-bridge/src/mapping.rs` - 完成验收:新增语义不再加到 `documents.*`,旧命令只作为 adapter。 ### 4.4 验收 - [ ] Page Aggregate Rust 测试通过。 - 命令:`cargo test -p mnote-web page_aggregate -- --nocapture` - 命令:`cargo test -p bridge-runtime page_aggregate -- --nocapture` - [ ] 页面标题、正文、设置 smoke 通过。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task110-page-title-single-truth-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task-page-aggregate-body-sync-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task-page-aggregate-options-sync-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task-page-aggregate-refresh-persistence-smoke.js` 完成标准: - [ ] 文档页不再新增 `meta + content` 拼装真相。 - [ ] 标题、正文、页面设置刷新后仍一致。 - [ ] Page Aggregate provenance 能清楚区分 local markdown、compat join、kernel projection。 --- ## 5. Phase A4:tree command / tree.resource command 收口 目标: > **页面和资源操作统一走 `tree.*` / `tree.resource.*`,`documents.*` 只保留兼容。** ### 5.1 当前代码锚点 - `rust/crates/mnote-web/src/routes/tree.rs` - `rust/crates/bridge-runtime/src/lib.rs` - `rust/crates/storage-convex-bridge/src/mapping.rs` - `rust/crates/mnote-cli/src/lib.rs` - `rust/crates/mnote-web/src/transport/convex.rs` ### 5.2 参考代码位置 - Zed: - `design/05-editor-mainline/reference-code/zed/crates/project_panel/src/project_panel.rs` - VS Code: - `design/05-editor-mainline/reference-code/vscode/src/vs/platform/commands` - `design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files` - SideX: - `design/05-editor-mainline/reference-code/sidex-main/src-tauri/src/commands/fs.rs` - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/file_operations.rs` ### 5.3 顺序任务 - [ ] 盘点仍使用 `documents.*` 的命令入口。 - 搜索命令:`rg -n "\"documents\\.|documents\\." rust/crates infra src wolai-frontend -S` - 完成验收:输出保留清单,逐项标记为 `compat adapter`、`test fixture`、`must cutover`。 - [ ] 将新增页面操作固定为 `tree.node.*`。 - 完成验收:新建、重命名、移动、归档、恢复、删除不再新增 `documents.*` 调用。 - [ ] 将资源操作固定为 `tree.resource.*`。 - 完成验收:mindmap、office、附件 rename/move/archive/restore/purge 都有正式命令名。 - [ ] mnote-cli 中历史 `documents.*` 命令降级为 compat。 - 重点文件:`rust/crates/mnote-cli/src/lib.rs` - 完成验收:CLI 新增命令使用 `tree.*` 或 `tree.resource.*`。 ### 5.4 验收 - [ ] tree command 单测通过。 - 命令:`cargo test -p mnote-web tree_command -- --nocapture` - 命令:`cargo test -p bridge-runtime tree_command -- --nocapture` - [ ] 文件树操作 smoke 通过。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task179-tree-create-delete-no-reload-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task446-tree-rename-dual-browser-live-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task447-tree-move-order-dual-browser-live-smoke.js` 完成标准: - [ ] 新增长期命令面不再出现 `documents.*`。 - [ ] `storage-convex-bridge` 只把正式命令映射到 Convex 兼容 mutation。 - [ ] 资源生命周期命令能统一产生 tree stream delta hint。 --- ## 6. Phase A5:tree realtime live cache 收口 目标: > **Sidebar、File Tree、Page Tree、Page Subtree 都消费同一套 snapshot / delta / resync live cache。** ### 6.1 当前代码锚点 - `rust/crates/mnote-web/src/routes/sse.rs` - `rust/crates/mnote-web/src/routes/realtime_ws.rs` - `rust/crates/mnote-web/src/ssr/pages/layout.rs` - `tree:snapshot` - `tree:delta` - `tree:resync` - `deltaNeedsProjectionRefresh` - `rust/crates/bridge-runtime/src/lib.rs` - `tree_stream_delta_hint` - `materialize_tree_stream_delta` ### 6.2 参考代码位置 - Zed: - `design/05-editor-mainline/reference-code/zed/crates/worktree/src/worktree.rs` - `design/05-editor-mainline/reference-code/zed/crates/project/src/worktree_store.rs` - Lapce: - `design/05-editor-mainline/reference-code/lapce/lapce-proxy/src/watcher.rs` - SideX: - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/watcher.rs` ### 6.3 顺序任务 - [ ] 盘点所有 tree/page/filetree 刷新来源。 - 搜索命令:`rg -n "tree:snapshot|tree:delta|tree:resync|EventSource|WebSocket|poll|refetch|preferred snapshot|pageSubtree" rust/crates/mnote-web/src -S` - 完成验收:标出 WS 主链、SSE fallback、polling/refetch 补偿链。 - [ ] 明确 WS 是主链、SSE 是 fallback。 - 重点文件:`rust/crates/mnote-web/src/ssr/pages/layout.rs` - 完成验收:SSE 不和 WS 并行长期消费同一事件,只有 WS 不可用时 fallback。 - [ ] delta 能处理时直接 apply,不能处理时 resync。 - 重点文件:`rust/crates/mnote-web/src/ssr/pages/layout.rs` - 重点文件:`rust/crates/bridge-runtime/src/lib.rs` - 完成验收:`deltaNeedsProjectionRefresh` 不再成为常态路径。 - [ ] 删除或降级不必要的 polling / refetch 补偿链。 - 完成验收:页面/文件树操作不靠定时轮询才能稳定。 ### 6.4 验收 - [ ] realtime route 单测通过。 - 命令:`cargo test -p mnote-web tree_realtime -- --nocapture` - 命令:`cargo test -p mnote-web local_folder -- --nocapture` - [ ] 双浏览器 live smoke 通过。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task446-tree-rename-dual-browser-live-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task447-tree-move-order-dual-browser-live-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task448-tree-resync-recovery-dual-browser-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task449-tree-sse-reconnect-snapshot-recovery-smoke.js` 完成标准: - [ ] 双浏览器页面、文件、垃圾箱操作不刷新页面也能同步。 - [ ] WS 主链可用时 SSE 只作为 fallback。 - [ ] resync 是异常恢复路径,不是每次 delta 后的默认补偿。 --- ## 7. Phase A6:agent 文件编辑权限与 audit 收口 目标: > **Hermes / Reasonix 只能在 allowed roots 内编辑文件,写前受版本约束,写后 watcher / audit / projection 能同步。** ### 7.1 当前代码锚点 - `rust/crates/core-protocol/src/ai.rs` - `AiAccessScope` - `allowed_roots` - `rust/crates/mnote-web/src/routes/hermes_client.rs` - `acp_allowed_roots_env_for_payload` - `local_agent_audit_collect_snapshot` - `local_agent_audit_finalize_run` - `rust/crates/mnote-web/src/routes/hermes_tools.rs` - `local_agent_audit_record_write_rejected` - `local_agent_audit_record_tool_write` - `rust/crates/mnote-web/src/hermes_tools/doc.rs` - `rust/crates/mnote-web/src/hermes_tools/page.rs` ### 7.2 参考代码位置 - Zed: - `design/05-editor-mainline/reference-code/zed/crates/agent/src/tools/edit_file_tool.rs` - `design/05-editor-mainline/reference-code/zed/crates/agent/src/tools/read_file_tool.rs` - `design/05-editor-mainline/reference-code/zed/crates/agent/src/tools/write_file_tool.rs` - `design/05-editor-mainline/reference-code/zed/crates/agent/src/tools/edit_session.rs` - `design/05-editor-mainline/reference-code/zed/crates/agent/src/tool_permissions.rs` - SideX: - `design/05-editor-mainline/reference-code/sidex-main/src-tauri/src/commands/validation.rs` - `design/05-editor-mainline/reference-code/sidex-main/src-tauri/src/commands/fs.rs` ### 7.3 顺序任务 - [ ] 盘点所有 agent 写入口。 - 搜索命令:`rg -n "mnote.doc.markdown_edit|mnote.page.save|mnote.block|allowed_roots|AiAccessScope|write_rejected|agent_audit" rust/crates/mnote-web/src rust/crates/core-protocol/src -S` - 完成验收:列出 Hermes tool、Reasonix/ACP、agent native file edit、MNote tool 写入入口。 - [ ] allowed roots 校验统一到一个 Rust helper。 - 完成验收:所有写入口共用同一套 root canonicalization、symlink escape、read/write permission 校验。 - [ ] agent 写入前读取当前 file version。 - 完成验收:MNote tool 写入必须携带 `expectedFileVersion`;agent native 写入完成后必须进入 audit + watcher 同步路径。 - [ ] audit event 统一 run id 和 changed files 结构。 - 重点文件:`rust/crates/mnote-web/src/routes/hermes_client.rs` - 完成验收:agent native 写入和 MNote tool 写入可归入同一个 run audit。 ### 7.4 验收 - [ ] allowed roots env 测试通过。 - 命令:`cargo test -p mnote-web acp_allowed_roots -- --nocapture` - [ ] audit 单测通过。 - 命令:`cargo test -p mnote-web local_agent_audit_snapshot_detects_changed_files -- --nocapture` - 命令:`cargo test -p mnote-web hermes_tools_markdown_edit_shared_read -- --nocapture` - 命令:`cargo test -p mnote-web hermes_tools_page_save_local_folder_writes_markdown_file -- --nocapture` - [ ] changed files smoke 通过。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task453-local-folder-page-ai-changed-files-smoke.js` 完成标准: - [ ] read grant 下写入被拒绝并记录 audit。 - [ ] write grant 下写入后 UI 能显示 changed files。 - [ ] agent 不能通过 symlink 或 `..` 逃出 allowed roots。 --- ## 8. Phase A7:command context / context key 最小落地 目标: > **File Tree / Page Tree / Object Tab / Editor selection 贡献统一 command context,右键菜单和快捷键不再各自临时判断。** ### 8.1 当前代码锚点 - `rust/crates/mnote-web/src/ssr/pages/layout.rs` - `rust/crates/mnote-web/src/routes/tree.rs` - `rust/crates/core-protocol/src/command.rs` ### 8.2 参考代码位置 - VS Code: - `design/05-editor-mainline/reference-code/vscode/src/vs/platform/contextkey` - `design/05-editor-mainline/reference-code/vscode/src/vs/platform/commands` - SideX: - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-keymap/src/context.rs` - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-keymap/src/resolver.rs` - Lapce: - `design/05-editor-mainline/reference-code/lapce/lapce-app/src/command.rs` - `design/05-editor-mainline/reference-code/lapce/lapce-app/src/keypress/loader.rs` ### 8.3 顺序任务 - [x] 盘点当前菜单、快捷键、按钮 enablement 条件。 - 搜索命令:`rg -n "disabled|aria-disabled|context|shortcut|keydown|menu|right-click|data-action" rust/crates/mnote-web/src/ssr/pages/layout.rs -S` - 完成验收:列出至少 filetree、pagetree、editor、AI panel 的条件来源。 - **执行记录(Batch C Worker C)**:FileTree 右键菜单(delete-trash/rename/new-file/new-folder/paste-into 共 5 项,均携带 `when`)和 Delete/Backspace 快捷键已审计并完成上下文接入。AI panel 条件由 `ai.canWrite` 在 hermes_tools 守卫中消费。 - [x] 定义 MNote 最小 command context。 - 完成 key:`workspace.sourceKind`、`workspace.readonly`、`tree.focusKind`、`tree.selectionCount`、`tree.selectionResourceKind`、`editor.dirty`、`editor.hasSelection`、`ai.canWrite` 共 8 个 key。 - 完成验收:这些 key 已覆盖当前右键菜单、快捷键和 AI write guard enablement。 - **代码证明**:`rust/crates/core-protocol/src/command.rs` 中 `CommandContext` 结构体包含全部 8 个字段;7 个单测覆盖 when 求值全路径。 - [x] 先在 Rust 侧定义 context schema,再让前端消费。 - Rust 侧:`core-protocol/src/command.rs` — `CommandContext` + `WhenExprNode` + `evaluate_when` / `check_when` / `is_command_enabled`。 - 前端侧(SSR `layout.rs`):`buildSidebarFileTreeContext()` + `evaluateSidebarFileTreeWhen()` 两个 JS 等价物用于右键菜单启禁。 - 完成验收:FileTree 右键菜单和 Delete/Backspace 共享同一 `evaluateSidebarFileTreeWhen` 路径。 ### 8.4 验收 - [x] command context 单测覆盖 `when` 判断。 - 命令:`cargo test -p core-protocol command_context -- --nocapture` - **结果(2026-05-21)**:7 passed — 覆盖 key、`!key`、`==`、`!=`、`&&`、`||`、括号分组、number comparison、parse error fallback、`ai.canWrite` gate、`workspace.readonly` gate。 - [x] 文件树 DnD / readonly conflict smoke 通过。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task431-vscode-explorer-dnd-readonly-conflict-smoke.js` - **证据**:`tmp/task431-vscode-explorer-dnd-readonly-conflict-smoke/result.json` — `ok: true`,readonly-target 和 readonly-source 均返回 400。 完成标准: - [x] 同一命令在菜单、快捷键、按钮上使用同一 context 判断。 - FileTree 右键菜单(delete-trash/rename/new-file/new-folder/paste-into)与 Delete/Backspace 快捷键共享 `evaluateSidebarFileTreeWhen` 路径。 - **保留的缺口**:editor/object tab 上下文尚未接入 command context;AI tool 写入守卫 `ensure_write_authorized` 是独立路径(读 `args.commandContext`,非前端 context key)。 - [x] readonly / read grant / selected resource kind 的禁用态一致。 - FileTree 右键菜单 readonly 禁用已通过 `!workspace.readonly` when 表达式统一实现。 --- ## 9. Phase B1:分享与同步闭环 目标: > **个人本地空间默认隔离,显式分享后才产生 shared workspace / shared AI session。** ### 9.1 当前代码锚点 - `rust/crates/mnote-web/src/routes/local_access_policy.rs` - `rust/crates/mnote-web/src/routes/hermes_client.rs` - `rust/crates/core-protocol/src/ai.rs` - `recycle/20260522-convex-runtime-retirement/infra/convex/`(历史 Convex 自托管对照;不作为 active 部署入口) ### 9.2 参考代码位置 - VS Code: - `design/05-editor-mainline/reference-code/vscode/src/vs/platform/files` - Zed: - `design/05-editor-mainline/reference-code/zed/crates/collab` - 仅参考权限和协作边界,不采用完整协作产品。 ### 9.3 顺序任务 - [ ] 定义 share grant 与 local access grant 的关系。 - 完成验收:share grant 不自动扩大本机文件系统权限。 - [ ] shared AI session 只消费 share grant 允许的资源。 - 完成验收:shared AI session 不能访问 owner 本机未授权 root。 - [ ] 同步 cache 目录设计。 - 完成验收:cache 中保留来源、版本、actor、权限、冲突信息。 - [ ] 同步冲突复用 Phase A2 冲突 UI。 - 完成验收:冲突报告包含 local、remote、base、actor。 ### 9.4 验收 - [ ] 单测:share read 不允许写入。 - [ ] 单测:shared AI session 不扩大 workspace root。 - [ ] browser smoke:共享页面只读用户无法通过 AI 写入正文。 完成标准: - [ ] share / sync 不破坏 local-first 权限模型。 - [ ] shared AI session 不能越权读写。 --- ## 10. Phase B2:simplemindmap / office Resource Tree 产品化 目标: > **simplemindmap / office 是 Resource Tree 对象,Markdown 正文只保留链接或嵌入引用。** ### 10.1 当前代码锚点 - `rust/crates/mnote-web/src/routes/mindmap_api.rs` - `rust/crates/mnote-web/src/routes/mindmap_shell.rs` - `rust/crates/mnote-web/src/ssr/pages/mindmap.rs` - `rust/crates/mnote-web/src/routes/tree.rs` - `rust/crates/bridge-runtime/src/lib.rs` - `src/components/onlyoffice/` ### 10.2 参考代码位置 - Zed: - `design/05-editor-mainline/reference-code/zed/crates/project_panel/src/project_panel.rs` - VS Code: - `design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files` - SideX: - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/file_tree.rs` ### 10.3 顺序任务 - [ ] 盘点 simplemindmap object identity、保存路径、打开路径。 - 搜索命令:`rg -n "mindmap|tree.resource.mindmap|resource:mindmap|mindmapId" rust/crates src -S` - 完成验收:列出所有 mindmap 创建、打开、保存、删除路径。 - [ ] 盘点 office object identity、保存路径、打开路径。 - 搜索命令:`rg -n "onlyoffice|office|tree.resource.office|resource:office|assetId" rust/crates src -S` - 完成验收:列出所有 office 创建、打开、保存、删除路径。 - [ ] 统一资源生命周期到 `tree.resource.*`。 - 完成验收:rename / move / archive / restore / purge 不再走 document command。 - [ ] Markdown 中只写资源引用。 - 完成验收:mindmap / office 内容不塞回 `.md` 正文真相。 ### 10.4 验收 - [ ] 单测:resource rename 不走 document command。 - [ ] 单测:mindmap resource 删除 / 恢复不破坏 markdown 页面。 - [ ] browser smoke:mindmap 长中文保存和 index.md 不互相污染。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task443-filetree-mindmap-click-active-row-smoke.js` - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task445-filetree-mindmap-switch-no-flicker-smoke.js` 完成标准: - [ ] Page Tree 只做页面导航投影。 - [ ] File Tree 能显示资源行。 - [ ] Resource Tree 才是资源归属真相。 --- ## 11. Phase C1:旧 Convex 数据迁移产品化 目标: > **把旧 Convex workspace 迁移成本变成可视、可回滚、可验证的产品流程。** ### 11.1 当前代码锚点 - `rust/crates/storage-convex-bridge/src/mapping.rs` - `rust/crates/mnote-web/src/transport/convex.rs` - `rust/crates/mnote-web/src/routes/local_folder_source.rs` - `scripts/task444-convex-workspace-export-local-fixture-smoke.js` ### 11.2 参考代码位置 - VS Code: - `design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files/browser/fileImportExport.ts` - SideX: - `design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/file_operations.rs` ### 11.3 顺序任务 - [ ] 设计 dry run 导出计划。 - 完成验收:计划列出页面、资源、附件、目标路径、冲突项,不写文件。 - [ ] 导出前生成 backup / manifest。 - 完成验收:manifest 能记录本次新增、覆盖、跳过、失败。 - [ ] 目标 root 同名冲突不覆盖。 - 完成验收:生成冲突报告,用户明确选择前不写入。 - [ ] 回滚按 manifest 删除新增或恢复备份。 - 完成验收:回滚后 root 回到导出前状态。 - [ ] 导出完成后重建本地索引。 - 完成验收:迁移后页面可搜索,资源引用可查。 ### 11.4 验收 - [ ] Convex fixture 导出 smoke 通过。 - 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task444-convex-workspace-export-local-fixture-smoke.js` - [ ] 新增 smoke:同名文件冲突时不覆盖。 - [ ] 新增 smoke:回滚后 root 回到导出前状态。 完成标准: - [ ] 迁移支持 dry run。 - [ ] 迁移支持备份、冲突报告、回滚。 - [ ] 迁移后 local index 可用。 --- ## 12. 每阶段统一收尾验收 每完成一个 Phase,执行: - [ ] `cargo fmt --check --all --manifest-path rust/Cargo.toml` - [ ] `git diff --check -- ` - [ ] 与阶段相关的 Rust 单测。 - [ ] 与阶段相关的 browser smoke。 - [ ] `npm run check:local-first-convex-guard` - [ ] 把验证证据写回本 checklist。 阶段迁移到 `done/` 的标准: - [ ] checklist 项全部勾选。 - [ ] 真实代码已落地。 - [ ] 单测与 smoke 有证据。 - [ ] 不再依赖临时 compat 作为新增能力主路径。