- move self-hosted Convex infra and root placeholder into recycle - update architecture docs to remove active infra/convex deployment guidance - extend local-first Convex guard to block retired infra regressions
697 lines
30 KiB
Markdown
697 lines
30 KiB
Markdown
# 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 -- <changed-files>`
|
||
- [ ] 与阶段相关的 Rust 单测。
|
||
- [ ] 与阶段相关的 browser smoke。
|
||
- [ ] `npm run check:local-first-convex-guard`
|
||
- [ ] 把验证证据写回本 checklist。
|
||
|
||
阶段迁移到 `done/` 的标准:
|
||
|
||
- [ ] checklist 项全部勾选。
|
||
- [ ] 真实代码已落地。
|
||
- [ ] 单测与 smoke 有证据。
|
||
- [ ] 不再依赖临时 compat 作为新增能力主路径。
|