收口本地工作区清理与资源投影
清理历史 Electron、Graphify、沙箱和截图等仓库跟踪残留,补充 CodeGraph 与 Convex active deploy source 协作说明。 新增 tree-first 下一阶段设计稿和 2026-05-20 清理总结,记录本地工作区、路径身份和 Zed/Lapce/VSCode 参考收口方向。 扩展 Rust Web 本地文件夹、DocumentBuffer、mindmap 资源、tree runtime 和页面聚合链路,并补充 task455 local-folder mindmap clean smoke。 验证:git diff --check 通过;pnpm store status --store-dir .pnpm-store 通过;npm ls --depth=0 --json 通过;find -L node_modules 未发现断链。cargo test -p mnote-web 当前 418 passed / 35 failed。
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
# 1-4 [process] 下一阶段执行路线图 v1
|
||||
|
||||
> 创建时间:2026-05-19
|
||||
>
|
||||
> 当前状态:`PROCESS`
|
||||
>
|
||||
> 上位依据:
|
||||
> - `/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/process/5-14-zed-lapce-vscode-reference-adoption-matrix-v1.md`
|
||||
> - `/mnt/Data1T/mnote/CURRENT_ARCHITECTURE.md`
|
||||
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
|
||||
>
|
||||
> 目标:把当前已经推进到混合态的主线,收口成一条更清晰的下一阶段路线,避免“功能继续堆、底座继续散”的问题。
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论
|
||||
|
||||
下一阶段不是全量重写,也不是继续优先补 UI 功能,而是:
|
||||
|
||||
> **以架构收口为主,带着产品化闭环往前推。**
|
||||
|
||||
这里的“架构收口”指的是把当前已经存在但还没完全统一的底座收束到少数几条正式主链上:
|
||||
|
||||
- `WorkspacePath / ProjectPath / ObjectIdentity`
|
||||
- `BufferStore / fileVersion / dirty / external change`
|
||||
- `Page Aggregate`
|
||||
- `tree.*` / `tree.resource.*`
|
||||
- `live cache` 的 snapshot / delta / resync 主链
|
||||
- agent 文件编辑权限与 allowed roots
|
||||
|
||||
这里的“产品化闭环”指的是在底座稳定后,继续做:
|
||||
|
||||
- 分享与同步
|
||||
- simplemindmap / office 资源模型
|
||||
- 旧 Convex 数据迁移
|
||||
|
||||
---
|
||||
|
||||
## 2. 为什么不是先做功能补全
|
||||
|
||||
`1-3` 里已经完成了比较多的可见功能:
|
||||
|
||||
- 管理员目录授权控制面。
|
||||
- VSCode-like 冲突处理 UI。
|
||||
- agent changed files / diff 审计。
|
||||
- 本地搜索、反链、资源引用索引。
|
||||
|
||||
`5-14` 也说明了一个更底层的事实:
|
||||
|
||||
- Zed 更适合作为主架构参考。
|
||||
- Lapce 更适合作为轻量实现参考。
|
||||
- SideX 更适合作为 VS Code 行为迁移到 Rust 后端的桥接参考。
|
||||
- 官方 VS Code 只适合作为行为规格参考。
|
||||
|
||||
这意味着当前真正缺的不是“再加一个功能”,而是:
|
||||
|
||||
> **把这些功能压在同一套身份、版本、命令、搜索和 watcher 主链上。**
|
||||
|
||||
如果继续优先做功能补全,结果通常是:
|
||||
|
||||
- 新功能依赖旧兼容面。
|
||||
- 新能力继续长在不同命令面上。
|
||||
- UI 看起来越来越完整,但底层真相越来越散。
|
||||
|
||||
---
|
||||
|
||||
## 3. 下一阶段三段式推进
|
||||
|
||||
### 3.1 阶段 A:架构收口
|
||||
|
||||
这是当前最优先的阶段。
|
||||
|
||||
目标:
|
||||
|
||||
> **把 workspace identity、buffer/version、page aggregate、tree command、live cache 收成统一主链。**
|
||||
|
||||
应优先推进的事:
|
||||
|
||||
- 统一 `WorkspacePath` / `ProjectPath` / `ObjectIdentity`。
|
||||
- 统一 `BufferStore` / dirty / save / external change 模型。
|
||||
- 继续瘦身 `documents.*`,新增只走 `tree.*` / `tree.resource.*`。
|
||||
- 让 `Page Aggregate` 继续成为页面主投影唯一入口。
|
||||
- 统一 Sidebar / filetree / page subtree / WS / SSE 到同一 live cache。
|
||||
- 让 agent 文件编辑权限、allowed roots、symlink escape、文件版本仲裁保持一致。
|
||||
|
||||
不该做的事:
|
||||
|
||||
- 不重建通用 IDE 壳。
|
||||
- 不优先做 terminal / debugger / extension host。
|
||||
- 不继续扩展旧兼容命令面。
|
||||
|
||||
### 3.2 阶段 B:资源与共享产品化
|
||||
|
||||
架构收口后,第二阶段做产品化闭环。
|
||||
|
||||
目标:
|
||||
|
||||
> **把 simplemindmap / office / 分享 / AI 访问权限纳入同一套资源与权限模型。**
|
||||
|
||||
应优先推进的事:
|
||||
|
||||
- `share grant` 与 `local access grant` 的关系。
|
||||
- `shared AI session` 的权限边界。
|
||||
- `tree.resource.*` 的资源创建 / 重命名 / 移动 / 删除 / 恢复。
|
||||
- simplemindmap / office 的 ObjectIdentity 和 Resource Tree 映射。
|
||||
|
||||
### 3.3 阶段 C:迁移与运营闭环
|
||||
|
||||
最后做迁移和收尾。
|
||||
|
||||
目标:
|
||||
|
||||
> **把旧 Convex 资产迁移成本变成可视、可回滚、可验证的产品流程。**
|
||||
|
||||
应优先推进的事:
|
||||
|
||||
- Convex workspace 导出到本地 root。
|
||||
- dry run。
|
||||
- 备份。
|
||||
- 冲突报告。
|
||||
- 回滚。
|
||||
|
||||
---
|
||||
|
||||
## 4. 和 `1-3` / `5-14` 的关系
|
||||
|
||||
### 4.1 `1-3` 负责告诉我们“当前还剩什么没收口”
|
||||
|
||||
`1-3` 已经把主线拆得很清楚:
|
||||
|
||||
- P0 到 P3 基本是已完成或接近完成的产品能力。
|
||||
- P4 到 P7 仍然是后续主线。
|
||||
- 其中 P7 明确指出:Page Aggregate / tree command / realtime 兼容链还要继续瘦身。
|
||||
|
||||
### 4.2 `5-14` 负责告诉我们“底座应该参考什么”
|
||||
|
||||
`5-14` 的作用不是多拉一个功能列表,而是告诉我们:
|
||||
|
||||
- workspace / project / buffer / search / agent 权限,主参考应是 Zed。
|
||||
- RPC / proxy / config / keymap 的轻量 Rust 组织方式,可以参考 Lapce 和 SideX。
|
||||
- VS Code 只用于行为规格校准。
|
||||
|
||||
### 4.3 合起来的结论
|
||||
|
||||
两份文档合起来,结论就是:
|
||||
|
||||
> **下一阶段的主线是“架构收口 + 产品化闭环”,不是“全量功能扩展”也不是“推倒重写”。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 明确优先级
|
||||
|
||||
### P0
|
||||
|
||||
- `WorkspacePath / ProjectPath / ObjectIdentity`
|
||||
- `BufferStore / fileVersion / dirty / conflict`
|
||||
- `Page Aggregate`
|
||||
- `tree.*` / `tree.resource.*`
|
||||
- `live cache` 主链
|
||||
- agent 文件编辑权限
|
||||
|
||||
### P1
|
||||
|
||||
- 本地搜索与快速打开继续巩固
|
||||
- File Tree / Page Tree / Resource Tree 命令上下文统一
|
||||
- command context / context key 统一
|
||||
|
||||
### P2
|
||||
|
||||
- share / sync
|
||||
- simplemindmap / office 资源产品化
|
||||
- 本地迁移与导出
|
||||
|
||||
### P3
|
||||
|
||||
- terminal / PTY 边界
|
||||
- MultiBuffer / excerpts
|
||||
- review diff / streaming apply
|
||||
- 插件运行时
|
||||
|
||||
---
|
||||
|
||||
## 6. 当前不做什么
|
||||
|
||||
- 不把 MNote 拉成通用 IDE。
|
||||
- 不先做 extension host / debugger / terminal 优先级升级。
|
||||
- 不让 `documents.*` 继续长成新主命令面。
|
||||
- 不把 Tauri desktop shell 当成当前主壳方向。
|
||||
- 不把 UI 功能增长误当成主线前进。
|
||||
|
||||
---
|
||||
|
||||
## 7. 下一步建议
|
||||
|
||||
接下来最合理的动作是:
|
||||
|
||||
1. 先按 `1-4` 这条路线图推进架构收口。
|
||||
2. 在 `1-3` 里把 `P7` 拆成明确的收口子任务。
|
||||
3. 等底座稳定后,再把 `P4-P6` 推成产品化闭环。
|
||||
|
||||
一句话结论:
|
||||
|
||||
> **先收口主链,再做产品化。**
|
||||
+687
@@ -0,0 +1,687 @@
|
||||
# 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/process/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 顺序任务
|
||||
|
||||
- [ ] 盘点当前菜单、快捷键、按钮 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 的条件来源。
|
||||
|
||||
- [ ] 定义 MNote 最小 command context。
|
||||
- 建议 key:`workspace.sourceKind`、`tree.focusKind`、`tree.selectionCount`、`tree.selectionResourceKind`、`editor.dirty`、`editor.hasSelection`、`ai.canWrite`、`workspace.readonly`。
|
||||
- 完成验收:这些 key 能覆盖当前右键菜单、快捷键和主按钮 enablement。
|
||||
|
||||
- [ ] 先在 Rust 侧定义 context schema,再让前端消费。
|
||||
- 完成验收:前端不再在多个分支里重复判断同一个能力。
|
||||
|
||||
### 8.4 验收
|
||||
|
||||
- [ ] command context 单测覆盖 `when` 判断。
|
||||
- 建议命令:`cargo test -p core-protocol command_context -- --nocapture`
|
||||
|
||||
- [ ] 文件树 DnD / readonly conflict smoke 通过。
|
||||
- 命令:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task431-vscode-explorer-dnd-readonly-conflict-smoke.js`
|
||||
|
||||
完成标准:
|
||||
|
||||
- [ ] 同一命令在菜单、快捷键、按钮上使用同一 context 判断。
|
||||
- [ ] readonly / read grant / selected resource kind 的禁用态一致。
|
||||
|
||||
---
|
||||
|
||||
## 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`
|
||||
- `infra/convex/`
|
||||
|
||||
### 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 作为新增能力主路径。
|
||||
@@ -0,0 +1,247 @@
|
||||
# 1-6 [process] 下一阶段缺口补齐 checklist v1
|
||||
|
||||
> 创建时间:2026-05-19
|
||||
>
|
||||
> 当前状态:`PARTIALLY_DONE`(Reasonix 已补 A2/A7 基础设施与 A2 保存/watcher 接入;A2 浏览器刷新可见读回、A0 browser smoke、A7 UI 接入、B2/C1 产品化仍未闭环)
|
||||
>
|
||||
> 上位依据:
|
||||
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-5-next-phase-sequential-execution-checklist-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-4-next-phase-execution-roadmap-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-14-zed-lapce-vscode-reference-adoption-matrix-v1.md`
|
||||
>
|
||||
> 目的:基于 Reasonix 执行汇总和本轮核对结果,列出仍不能标完成的缺口,形成可继续顺序执行的补充清单。
|
||||
|
||||
---
|
||||
|
||||
## 0. 当前核对结论
|
||||
|
||||
本轮已确认:
|
||||
|
||||
- [x] `ObjectWorkspacePath` 已在 `core-protocol` 定义并导出。
|
||||
- [x] local folder projection 已输出 `resourceMeta.workspacePath`。
|
||||
- [x] 前端 `fileObjectIdentity` 已优先读取 `resourceMeta.workspacePath.objectIdentity`。
|
||||
- [x] `DocumentBuffer` / `DocBufferDirtyState` 已在 `core-protocol` 定义并有状态机测试。
|
||||
- [x] `mnote.mindmap.*` / `mnote.office.*` Hermes resource tools 已出现,且最小测试通过。
|
||||
|
||||
本轮 Reasonix 执行后新增:
|
||||
|
||||
- [x] **Gap A0(部分)**: local-first guard 已通过 ✅(`npm run check:local-first-convex-guard` → `{ok: true, guard: "local-first-convex"}`);browser smoke 尚未复跑。
|
||||
- [x] **Gap A2(基础设施+运行时接入)**: `BufferStore` 已在 `rust/crates/mnote-web/src/document_buffer_store.rs` 实现,并加入 `AppState.buffer_store`。运行时接入完成:`write_local_markdown_page_body` → `mark_saved`、watcher → `mark_external_modified`、Hermes tools → 共享 helper。11 个单测全部通过(含 3 个新集成测试)。
|
||||
- [x] **Gap A2(运行时接入—完成)**: `write_local_markdown_page_body` 已接入 `BufferStore.mark_saved()`;`documents.rs` `page_body_write` 和 `save` 路由已传递 `state.buffer_store`;Hermes `doc_apply_block_ops` 和 `page_command` 已传递 `state.buffer_store`;watcher 已在 `spawn_local_folder_watcher` 内调用 `mark_external_modified`。3 个新集成测试覆盖运行时入口。
|
||||
- [ ] **Gap A2(浏览器可见闭环)**: Codex 浏览器复核显示 `POST /api/page-body/write` 200、磁盘 `.md` 与 local search index 均写入成功、`#__MNOTE_PAGE_AGGREGATE__` 包含保存文本;但刷新后编辑器 DOM/截图未显示该正文,仍需修复可见读回或编辑器 hydration。
|
||||
- [x] **Gap A7(基础设施)**: `CommandContext` + `when` evaluator 已在 `core-protocol/src/command.rs` 实现。7 个单测全部通过(含 3 个必补测试)。
|
||||
- [ ] **Gap A7(UI/命令接入)**: File Tree 右键菜单、快捷键、AI 写入能力尚未消费 `CommandContext`。
|
||||
- [x] **Gap B2(部分)**: `resource_rename_uses_resource_command_not_document_command` 测试通过;`local_agent_audit_snapshot_detects_resource_files` 通过;mindmap 生命周期测试通过。
|
||||
- [x] **Gap C1(部分)**: `scripts/task444-convex-workspace-export-local-fixture-smoke.js` 通过;`export-convex-workspace-to-local.js` 既有 `--dry-run`、`--manifest`、`--conflict-report`、`--rollback` 能力已确认,但本轮未新增对应 smoke。
|
||||
- [x] **core-protocol 全量测试**: 41 单元 + 6 editor bridge + 2 resource tree = 49 通过 ✅
|
||||
- [x] **mnote-web 相关测试**: BufferStore 8 通过 + resource_trash 6 通过 + audit 2 通过 = 16 通过 ✅
|
||||
|
||||
---
|
||||
|
||||
## 1. Gap A0:补齐基线验证证据 — 🔄 部分完成
|
||||
|
||||
### 1.1 必跑命令
|
||||
|
||||
- [x] 运行 local-first guard。
|
||||
- 命令:`npm run check:local-first-convex-guard`
|
||||
- 结果:`{"ok": true, "checkedLines": 1, "guard": "local-first-convex"}`
|
||||
- 验收:通过 ✅
|
||||
|
||||
- [ ] 冲突 UI smoke — `task451-local-markdown-conflict-resolution-ui-smoke.js`
|
||||
- 编号已存在脚本目录,需在完整后端环境下运行(依赖 mnote-web + Convex)
|
||||
- 验收:尚未复跑 browser smoke;单测级 `document_buffer_state_transitions` 不能替代 UI smoke。
|
||||
|
||||
- [ ] 本地搜索索引 smoke — `task452-local-search-index-browser-smoke.js`
|
||||
- 编号已存在脚本目录
|
||||
- 验收:尚未复跑 browser smoke。
|
||||
|
||||
- [ ] agent changed files smoke — `task453-local-folder-page-ai-changed-files-smoke.js`
|
||||
- 编号已存在脚本目录
|
||||
- 验收:尚未复跑 browser smoke;`local_agent_audit_snapshot_detects_changed_files` 和 `detects_resource_files` 只能覆盖 audit 单元路径。
|
||||
|
||||
### 1.2 收尾
|
||||
|
||||
- [x] guard 输出已记录(见上)
|
||||
- [ ] browser smokes 需完整后端环境运行(mnote-web + Convex + Playwright)
|
||||
- [ ] 失败归属:无失败
|
||||
|
||||
---
|
||||
|
||||
## 2. Gap A2:把 DocumentBuffer 接入运行时 BufferStore — 🔄 基础设施与运行时接入完成,浏览器可见读回未闭环
|
||||
|
||||
### 2.1 当前代码锚点(更新后)
|
||||
|
||||
- `rust/crates/mnote-web/src/document_buffer_store.rs` — **新增**:`BufferStore` + `BufferKey` 实现
|
||||
- `rust/crates/mnote-web/src/app.rs` — `buffer_store: BufferStore` 已加入 `AppState`
|
||||
- `rust/crates/mnote-web/src/lib.rs` — `pub mod document_buffer_store` 已注册
|
||||
- `rust/crates/core-protocol/src/kernel.rs` — `DocumentBuffer` / `DocBufferDirtyState` / `ObjectWorkspacePath`(已有未改)
|
||||
|
||||
### 2.2 顺序任务完成情况
|
||||
|
||||
- [x] 新增运行时 `BufferStore` owner:`rust/crates/mnote-web/src/document_buffer_store.rs`,通过 `AppState.buffer_store` 持有
|
||||
- [x] 定义 buffer key:以 `ObjectWorkspacePath` 的 `workspace_id + source_kind + root_uri + relative_path + document_id` 作为稳定 `BufferKey`
|
||||
- [x] 接入 tiptap 保存链:`write_local_markdown_page_body` / `documents.rs` `save` 路由已调用 `state.buffer_store.mark_saved()`
|
||||
- [x] 接入外部文件变更 watcher:`spawn_local_folder_watcher` 已通过 `buffer_store.mark_external_modified()` 更新对应 buffer
|
||||
- [x] 接入 Hermes/Reasonix 写入后状态更新:`hermes_tools/doc.rs` 和 `hermes_tools/page.rs` 已通过共享 helper `write_local_markdown_page_body` 自动消费 BufferStore
|
||||
- [ ] conflict UI 数据源改为 buffer state:API 已就绪,未接入
|
||||
- [ ] 浏览器可见读回:保存后磁盘与 PageAggregate 已更新,但刷新后 tiptap/editor DOM 未显示保存正文
|
||||
|
||||
### 2.3 必补测试
|
||||
|
||||
- [x] `document_buffer_reuses_workspace_path_key` — 通过 ✅
|
||||
- [x] `document_buffer_marks_external_modified_for_clean_buffer` — 通过 ✅
|
||||
- [x] `document_buffer_marks_stale_for_dirty_buffer` — 通过 ✅
|
||||
- [x] `document_buffer_mark_saved_after_page_body_write` — 通过 ✅
|
||||
- [x] 额外测试:`document_buffer_different_paths_different_keys` ✅
|
||||
- [x] 额外测试:`document_buffer_init_buffer_sets_file_version` ✅
|
||||
- [x] 额外测试:`document_buffer_mark_dirty_and_saved_round_trip` ✅
|
||||
- [x] 额外测试:`document_buffer_reuses_across_multiple_get_or_create_calls` ✅
|
||||
|
||||
### 2.4 当前完成标准
|
||||
|
||||
- [x] `DocumentBuffer` 已有 mnote-web runtime `BufferStore` owner
|
||||
- [x] `BufferKey` 可稳定区分不同文件
|
||||
- [x] 11 个单测覆盖了关键 path + state transitions + save round-trip + 运行时入口
|
||||
- [x] **已完成**:tiptap/保存路由/Hermes 写入链已通过 `write_local_markdown_page_body` 统一消费 `BufferStore`
|
||||
- [x] **已完成**:watcher 已通过 `spawn_local_folder_watcher` 调用 `mark_external_modified`
|
||||
- [ ] **未完成**:`documents/save` 的 conflict UI 数据源尚未改为 buffer state 查询
|
||||
- [ ] **未完成**:浏览器刷新后编辑器可见正文未读回;证据截图:`reasonix-a2-after-refresh-text-missing.png`
|
||||
|
||||
### 2.5 下一步
|
||||
|
||||
- 修复保存后刷新读回:`#__MNOTE_PAGE_AGGREGATE__` 已包含正文,但 `mnote-leptos-tiptap-editor-root` 可见 DOM 为空,需要定位 editor hydration / blockDocument 消费路径。
|
||||
- conflict UI 数据源改为 buffer state:前端查询 `/api/documents/buffer/state` 或 SSE 推送 buffer 变更事件。
|
||||
|
||||
---
|
||||
|
||||
## 3. Gap A7:落地 command context / context key — 🔄 基础设施完成,UI/命令接入未完成
|
||||
|
||||
### 3.1 当前代码锚点(更新后)
|
||||
|
||||
- `rust/crates/core-protocol/src/command.rs` — **已扩展**:新增 `CommandContext`、`WhenExprNode`、`parse_when_expr`、`evaluate_when`、`check_when`、`is_command_enabled`
|
||||
- `rust/crates/core-protocol/src/lib.rs` — **已更新**:导出所有 command context 类型和函数
|
||||
|
||||
### 3.2 顺序任务完成情况
|
||||
|
||||
- [x] 定义最小 `CommandContext` 结构:包含 `workspace.sourceKind`、`workspace.readonly`、`tree.focusKind`、`tree.selectionCount`、`tree.selectionResourceKind`、`editor.dirty`、`editor.hasSelection`、`ai.canWrite` 共 8 个 key
|
||||
- [x] 实现最小 `when` evaluator:支持 `key`、`!key`、`key == value`、`key != value`、`&&`、`||`、括号分组(完整的递归下降解析器 + AST evaluator)
|
||||
- [ ] 把 File Tree 右键菜单接入 context:`CommandContext` 和 `is_command_enabled` 已提供基础设施,但尚未在 SSR layout 中使用
|
||||
- [ ] 把快捷键接入 context:基础设施已就绪,未接入
|
||||
- [ ] 把 AI 写入能力接入 context:`ai.canWrite` key 已定义,未在 hermes_tools 中消费
|
||||
|
||||
### 3.3 必补测试
|
||||
|
||||
- [x] `command_context_when_clause` — 通过 ✅(覆盖 key、!key、==、!=、&&、||、括号分组)
|
||||
- [x] `command_context_disables_write_commands_for_readonly_workspace` — 通过 ✅
|
||||
- [x] `command_context_filters_resource_commands_by_kind` — 通过 ✅
|
||||
- [x] `command_context_default_is_allow` — 通过 ✅
|
||||
- [x] `command_context_number_comparison` — 通过 ✅
|
||||
- [x] `command_context_parse_error_returns_default` — 通过 ✅
|
||||
- [x] `command_context_ai_can_write_gates_ai_actions` — 通过 ✅
|
||||
|
||||
### 3.4 当前完成标准
|
||||
|
||||
- [x] 最小 `CommandContext` 定义 + `when` evaluator 可工作
|
||||
- [x] readonly / grant / resource kind 的禁用态可测试
|
||||
- [ ] **未完成**:当前 UI 中同一命令的多份 enablement 判断尚未统一
|
||||
- [ ] **未完成**:菜单、按钮、快捷键可用性尚未统一
|
||||
|
||||
### 3.5 下一步
|
||||
|
||||
在 `layout.rs` 的右键菜单和 `hermes_tools` 的写入守卫中引入 `is_command_enabled`。
|
||||
|
||||
---
|
||||
|
||||
## 4. Gap B2:Resource tools 到 Resource Tree 产品化 — 🔄 部分完成
|
||||
|
||||
### 4.1 当前代码锚点(已有未改)
|
||||
|
||||
- `rust/crates/mnote-web/src/routes/resource_trash.rs` — 媒体 / mindmap / table 生命周期使用 `tree.resource.*` 命令
|
||||
- `rust/crates/mnote-web/src/routes/hermes_tools.rs`
|
||||
- `rust/crates/mnote-web/src/hermes_tools/resource.rs`
|
||||
- `rust/crates/mnote-web/src/hermes_tools/manifest.rs`
|
||||
|
||||
### 4.2 顺序任务完成情况
|
||||
|
||||
- [x] 明确 resource tool 是辅助入口,不是资源真相 — 文档中已有此约定
|
||||
- [x] mindmap resource 生命周期走 `tree.resource.*` — 测试验证 ✅
|
||||
- [x] office resource 生命周期走 `tree.resource.*` — ✅(仅链路存在,需更多测试覆盖)
|
||||
- [ ] Resource Tree projection 显示资源对象 — 部分完成(filetree 已显示资源行)
|
||||
- [x] agent audit 包含 resource files — `local_agent_audit_snapshot_detects_resource_files` 通过 ✅
|
||||
|
||||
### 4.3 必补测试
|
||||
|
||||
- [x] `tree_resource_rename_does_not_emit_document_command` — 被现有测试覆盖:
|
||||
- `resource_rename_uses_resource_command_not_document_command` ✅(验证 canonicalCommand 为 `tree.resource.rename` 而非 `tree.node.rename`)
|
||||
- [ ] `mindmap_resource_trash_restore_keeps_markdown_body` — 部分覆盖:
|
||||
- `mindmap_delete_restore_keeps_markdown_reference_out_of_lifecycle_command` ✅(验证 mindmap 生命周期不携带 documentId 从而不影响 markdown 页面)
|
||||
- 尚未验证文档正文在 trash/restore 后是否完整
|
||||
- [x] `local_agent_audit_snapshot_detects_resource_files` — 通过 ✅
|
||||
- [ ] browser smokes:`task443`、`task445` 需 Playwright 后端环境
|
||||
|
||||
### 4.4 完成标准
|
||||
|
||||
- [x] Resource Tree 是资源归属真相的大部分覆盖
|
||||
- [ ] Markdown 正文只保留资源引用 — 已有原则,未额外验证
|
||||
- [x] AI resource tools 与 tree.resource 生命周期一致 — 验证通过
|
||||
|
||||
---
|
||||
|
||||
## 5. Gap C1:Convex 迁移产品化补证据 — 🔄 部分完成
|
||||
|
||||
### 5.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`
|
||||
- `scripts/export-convex-workspace-to-local.js`
|
||||
|
||||
### 5.2 顺序任务完成情况
|
||||
|
||||
- [x] 定义 dry run response — `export-convex-workspace-to-local.js` 支持 `--dry-run` 标识 ✅
|
||||
- [x] 定义 migration manifest — 支持 `--manifest` 参数 ✅
|
||||
- [x] 实现同名冲突不覆盖 — 导出时不覆盖已有文件,输出冲突报告 ✅
|
||||
- [x] 实现 rollback — 支持 `--rollback` 参数 ✅
|
||||
- [x] 导出完成后重建 local index — task444 smoke 验证通过 ✅
|
||||
|
||||
### 5.3 必补测试
|
||||
|
||||
- [x] `task444-convex-workspace-export-local-fixture-smoke.js` — 通过 ✅
|
||||
- [ ] 新增 smoke:dry run 不写文件 — `--dry-run` 已支持,需额外 smoke 验证
|
||||
- [ ] 新增 smoke:同名冲突不覆盖 — 已有冲突报告逻辑,需 smoke 验证
|
||||
- [ ] 新增 smoke:rollback 恢复导出前状态 — 已支持,需 smoke 验证
|
||||
|
||||
---
|
||||
|
||||
## 6. 最终收尾
|
||||
|
||||
### 6.1 验证命令结果
|
||||
|
||||
- [x] `cargo test -p core-protocol` — 41+6+2=49 passed ✅
|
||||
- [x] `cargo test -p mnote-web document_buffer` — 8 passed ✅
|
||||
- [x] `cargo test -p mnote-web resource_trash` — 6 passed ✅
|
||||
- [x] `cargo test -p mnote-web local_agent_audit_snapshot` — 2 passed ✅
|
||||
- [x] `npm run check:local-first-convex-guard` — `{"ok": true}` ✅
|
||||
- [x] `node scripts/task444-convex-workspace-export-local-fixture-smoke.js` — `{"ok": true}` ✅
|
||||
- [x] `cargo fmt --check --all --manifest-path rust/Cargo.toml` — 通过 ✅
|
||||
- [x] `git diff --check -- <changed-files>` — 通过 ✅
|
||||
|
||||
### 6.2 Browser smokes(需完整后端环境)
|
||||
|
||||
- [ ] `task431-vscode-explorer-dnd-readonly-conflict-smoke.js`
|
||||
- [ ] `task451-local-markdown-conflict-resolution-ui-smoke.js`
|
||||
- [ ] `task452-local-search-index-browser-smoke.js`
|
||||
- [ ] `task453-local-folder-page-ai-changed-files-smoke.js`
|
||||
- [ ] `task443-filetree-mindmap-click-active-row-smoke.js`
|
||||
- [ ] `task445-filetree-mindmap-switch-no-flicker-smoke.js`
|
||||
|
||||
### 6.3 总完成率
|
||||
|
||||
| Gap | 状态 | 关键产出 | 剩余 |
|
||||
|-----|------|----------|------|
|
||||
| A0 | 🔄 部分 | guard 通过,smoke 脚本已存在 | browser smokes 未复跑 |
|
||||
| A2 | 🔄 运行时接入完成,浏览器闭环未完成 | `BufferStore` 实现 + 11 tests;保存请求 200;磁盘和 PageAggregate 写入成功 | 刷新后 editor DOM 未显示正文;conflict UI 未接 buffer state |
|
||||
| A7 | 🔄 基础设施完成 | `CommandContext` + when evaluator + 7 tests | UI/快捷键/菜单接入 |
|
||||
| B2 | 🔄 部分 | 资源生命周期 + agent audit 测试通过 | mindmap body 测试、browser smokes |
|
||||
| C1 | 🔄 部分 | export/rollback/dry-run 脚本 + smoke 通过 | 额外 smoke 验证 |
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
# 1-7 Local Workspace Root Page Bundle Checklist v1
|
||||
|
||||
## 背景
|
||||
|
||||
当前默认本地工作区初始化会创建 `pages/`、`assets/`、`mindmaps/`、`ai-sessions/` 等顶层目录。这更像早期产品内部布局,不像用户真实打开的 VSCode 文件夹,也不利于页面导出。
|
||||
|
||||
本轮收口方向:
|
||||
|
||||
- 默认工作区只保留用户内容根目录和 `.mnote/` 系统目录。
|
||||
- 页面树允许把 `页面.md + 页面/` 解释成一个页面节点与其子页面容器。
|
||||
- 文件树必须真实展示文件系统,不合并、不隐藏同名 `.md` 和目录。
|
||||
- 新建页面使用 `新页面HHMMSS` 命名,避免重复创建同名 `新页面.md`。
|
||||
- 新建页面时同时创建 `新页面HHMMSS.md` 和 `新页面HHMMSS/`。
|
||||
- 附件、思维导图等页面资源默认进入同名目录下,而不是顶层 `assets/` / `mindmaps/`。
|
||||
|
||||
## 参考代码位置
|
||||
|
||||
- 当前默认工作区初始化:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
|
||||
- `create_default_local_workspace_for_actor_at_base`
|
||||
- `ensure_default_workspace_directories`
|
||||
- `ensure_default_workspace_home_page`
|
||||
- 当前本地页面创建:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
|
||||
- `execute_local_tree_command`
|
||||
- `create_local_markdown_page`
|
||||
- 当前本地资源上传:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
|
||||
- `write_local_markdown_asset`
|
||||
- 当前文件树真实扫描:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
|
||||
- `load_local_folder_file_tree_snapshot`
|
||||
- `scan_directory`
|
||||
- 当前页面树扫描:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
|
||||
- `load_local_folder_page_tree_snapshot`
|
||||
- `scan_markdown_page_tree`
|
||||
- 当前根入口默认初始化测试:`rust/crates/mnote-web/src/routes/gateway.rs`
|
||||
- `root_entry_initializes_default_local_workspace_page`
|
||||
- 当前上传 smoke:`scripts/task443-local-markdown-asset-upload-smoke.js`
|
||||
|
||||
## 目标目录契约
|
||||
|
||||
### 默认初始化
|
||||
|
||||
默认工作区初始化后应该是:
|
||||
|
||||
```text
|
||||
my-space/
|
||||
.mnote/
|
||||
workspace.json
|
||||
trash/
|
||||
初始化的新页面.md
|
||||
```
|
||||
|
||||
不再默认创建:
|
||||
|
||||
```text
|
||||
pages/
|
||||
assets/
|
||||
mindmaps/
|
||||
ai-sessions/
|
||||
```
|
||||
|
||||
`ai-sessions` 后续如果要落本地,应放入 `.mnote/ai-sessions/`,本轮只禁止默认创建顶层 `ai-sessions/`。
|
||||
|
||||
### 新建页面
|
||||
|
||||
在父目录下新建页面时,默认标题若为 `新页面`,真实落盘应为:
|
||||
|
||||
```text
|
||||
新页面HHMMSS.md
|
||||
新页面HHMMSS/
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
新页面061240.md
|
||||
新页面061240/
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- `HHMMSS` 使用本地时间或现有时间工具生成,精确到秒。
|
||||
- 即使有时间戳,也必须做磁盘冲突检查;同秒冲突时使用 `-2`、`-3` 追加。
|
||||
- `documentId` 仍使用路径型 `local-md:<relative_path>`。
|
||||
- `.md` 正文标题应使用最终安全标题,例如 `# 新页面061240`。
|
||||
|
||||
### 页面树和文件树边界
|
||||
|
||||
- 页面树:允许把 `X.md` 与同目录 `X/` 解释为一个页面 `X`,并把 `X/` 内 Markdown 作为页面 `X` 的子页面。
|
||||
- 文件树:必须真实展示 `X.md` 和 `X/` 两个磁盘条目。不得把二者合并为一个节点。
|
||||
|
||||
### 页面资源
|
||||
|
||||
对 `X.md` 上传附件或图片时,默认写入:
|
||||
|
||||
```text
|
||||
X/assets/<file>
|
||||
```
|
||||
|
||||
对 mindmap,后续默认写入:
|
||||
|
||||
```text
|
||||
X/mindmaps/<file>
|
||||
```
|
||||
|
||||
本轮先完成 `write_local_markdown_asset` 的附件/图片路径迁移。正文链接相对 `X.md` 应为:
|
||||
|
||||
```markdown
|
||||

|
||||
[spec.pdf](X/assets/spec.pdf)
|
||||
```
|
||||
|
||||
## 顺序执行 Checklist
|
||||
|
||||
### A0 基线保护
|
||||
|
||||
- [x] 记录当前 `git status --short`,不要清理与本任务无关的脏改动。
|
||||
- [x] 运行当前相关定向测试,确认改前基线:
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web create_default_local_workspace_uses_managed_data_root -- --nocapture`
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_asset_upload_copies_next_to_markdown_with_relative_path -- --nocapture`
|
||||
|
||||
验收:
|
||||
|
||||
- [x] 基线通过。两项测试均 ok。
|
||||
|
||||
### A1 默认工作区目录最小化
|
||||
|
||||
- [x] 修改 `ensure_default_workspace_directories`:默认只创建 `.mnote/trash`。
|
||||
- [x] 修改 `ensure_default_workspace_home_page`:初始化页改为 `root/初始化的新页面.md`,不再放入 `pages/`。
|
||||
- [x] 更新 `create_default_local_workspace_uses_managed_data_root`:
|
||||
- 断言 `初始化的新页面.md` 位于 root 下。
|
||||
- 断言 `pages/`、`assets/`、`mindmaps/`、顶层 `ai-sessions/` 不存在。
|
||||
- 保留 `.mnote/workspace.json` 与 `.mnote/trash` 断言。
|
||||
- [x] 更新 `root_entry_initializes_default_local_workspace_page`:
|
||||
- 断言 root 下存在 `初始化的新页面.md`。
|
||||
- 不再断言 `pages/初始化的新页面.md`。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web create_default_local_workspace_uses_managed_data_root -- --nocapture` — ok
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web root_entry_initializes_default_local_workspace_page -- --nocapture` — ok
|
||||
|
||||
### A2 新建页面创建 `.md + 同名目录`
|
||||
|
||||
- [x] 新增 helper `determine_page_stem`:
|
||||
- 输入默认标题 `新页面` 输出 `新页面HHMMSS`(本地时间 HHMMSS,失败时回退 UTC)。
|
||||
- 对非默认标题,仍使用用户标题的安全文件名。
|
||||
- 对冲突同时检查 `<name>.md` 与 `<name>/`,追加 `-2`、`-3`。
|
||||
- [x] 修改 `create_local_markdown_page`:
|
||||
- 创建 `<name>.md`。
|
||||
- 同步创建 `<name>/`。
|
||||
- 返回的 `relativePath` 仍是 `<name>.md`。
|
||||
- 返回的 `documentId` 仍是 `local-md:<relative_path>`。
|
||||
- [x] 增加单测 `local_tree_command_create_page_creates_timestamped_markdown_and_sibling_folder`:
|
||||
- 执行 `execute_local_tree_command(..., "create", ..., Some("新页面"))`。
|
||||
- 断言产生 `新页面\d{6}.md` 和同名目录。
|
||||
- 断言返回 `documentId` 指向 `.md`。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_tree_command_create_page_creates_timestamped_markdown_and_sibling_folder -- --nocapture` — ok
|
||||
|
||||
### A3 页面树使用同名目录作为页面子容器
|
||||
|
||||
- [x] 修改 `scan_markdown_page_tree`:
|
||||
- 如果同目录存在 `X.md` 和 `X/`,页面树只显示 `X.md` 对应的页面节点。
|
||||
- `X/` 内的 Markdown 节点挂在 `X.md` 页面节点下。
|
||||
- 没有同名 `.md` 的普通目录,如果包含 Markdown,继续作为 page group 显示。
|
||||
- [x] 增加单测:
|
||||
- 构造 `Root.md`、`Root/Child.md`。
|
||||
- 页面树断言 `Child.md` 的 `parent_node_id` 是 `Root.md` 的 `documentId`。
|
||||
- 页面树断言没有单独的 `local:page-group:Root` 行。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_tree_uses_sibling_directory_as_page_children_container -- --nocapture` — ok
|
||||
|
||||
### A4 文件树保持真实
|
||||
|
||||
- [x] 确认 `scan_directory` 不做任何同名 `.md + folder` 合并。
|
||||
- [x] 增加单测:
|
||||
- 构造 `Root.md`、`Root/Child.md`。
|
||||
- 文件树断言同时存在 `Root.md` markdown 行和 `Root` folder 行。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_file_tree_keeps_markdown_and_sibling_folder_as_separate_rows -- --nocapture` — ok
|
||||
|
||||
### A5 附件上传进入页面同名目录
|
||||
|
||||
- [x] 修改 `write_local_markdown_asset`:
|
||||
- `README.md` 的附件目录从 `README.assets/` 改为 `README/assets/`。
|
||||
- 返回的 `sourcePath` / `file_url` 相对 Markdown 文件目录,例如 `README/assets/photo.png`。
|
||||
- 保留重复文件名 `photo-1.png` 逻辑。
|
||||
- [x] 更新单测 `local_markdown_asset_upload_copies_next_to_markdown_with_relative_path`。
|
||||
- [x] 更新 `scripts/task443-local-markdown-asset-upload-smoke.js` 中对 `README.assets/...` 的断言为 `README/assets/...`。
|
||||
- [x] 只改本地 local_folder 上传路径,不改 cloud / Convex media 路径。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_asset_upload_copies_next_to_markdown_with_relative_path -- --nocapture` — ok
|
||||
- [x] `node scripts/task443-local-markdown-asset-upload-smoke.js` — ok,证据:`tmp/task443-local-markdown-asset-upload-smoke/result.json`
|
||||
|
||||
### A6 重命名 bundle 规则最小收口
|
||||
|
||||
- [x] 检查 `rename_local_entry`:
|
||||
- 当重命名 `X.md` 且同目录存在 `X/` 时,同步重命名目录为新标题目录。
|
||||
- 如果目标目录已存在,使用与文件一致的冲突策略或返回可解释错误,禁止覆盖。
|
||||
- [x] 增加单测:
|
||||
- `Old.md + Old/Child.md` 重命名为 `New`。
|
||||
- 断言 `New.md` 和 `New/Child.md` 存在。
|
||||
- 页面树中 `Child.md` 仍挂在 `New.md` 下。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_rename_markdown_page_renames_sibling_page_folder -- --nocapture` — ok
|
||||
|
||||
### A7 文档同步
|
||||
|
||||
- [x] 更新本 checklist 状态。
|
||||
- [x] 本 checklist 已明确覆盖旧的默认顶层 `pages/assets/mindmaps/ai-sessions` 初始化结构;未大范围改旧 done 文档。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] checklist 中已记录实际完成情况。
|
||||
|
||||
### A8 最终验证
|
||||
|
||||
- [x] `cargo fmt --check --all --manifest-path rust/Cargo.toml` — ok
|
||||
- [x] `cargo check --manifest-path rust/Cargo.toml -p mnote-web` — ok
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web create_default_local_workspace_uses_managed_data_root -- --nocapture` — ok
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_tree_command_create_page_creates_timestamped_markdown_and_sibling_folder -- --nocapture` — ok
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_tree_uses_sibling_directory_as_page_children_container -- --nocapture` — ok
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_file_tree_keeps_markdown_and_sibling_folder_as_separate_rows -- --nocapture` — ok
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_asset_upload_copies_next_to_markdown_with_relative_path -- --nocapture` — ok
|
||||
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_rename_markdown_page_renames_sibling_page_folder -- --nocapture` — ok
|
||||
- [x] `node scripts/task443-local-markdown-asset-upload-smoke.js` — ok
|
||||
|
||||
浏览器验收由 Codex 复核执行:
|
||||
|
||||
- [x] 使用临时 `MNOTE_LOCAL_WORKSPACE_BASE_DIR=/mnt/Data1T/mnote/tmp/page-bundle-data` 启动 `mnote-web`。
|
||||
- [x] 登录/注入测试 actor 后打开首页。
|
||||
- [x] 截图保存到 `tmp/`:
|
||||
- `tmp/page-bundle-home-3003.png`
|
||||
- `tmp/page-bundle-after-create-3003.png`
|
||||
- `tmp/page-bundle-filetree-3003.png`
|
||||
- [x] 检查磁盘:
|
||||
- root 下有 `初始化的新页面.md`。
|
||||
- root 下没有默认 `pages/`、`assets/`、`mindmaps/`、顶层 `ai-sessions/`。
|
||||
- 新建页面后有 `新页面HHMMSS.md` 和 `新页面HHMMSS/`。
|
||||
- 文件树能看到 `.md` 与同名目录两个真实条目。
|
||||
- 页面树把同名目录内子页面挂到 `.md` 页面下。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不迁移用户历史数据。
|
||||
- 不删除正式 `/mnt/Data1T/Mnote_data/users` 下旧测试目录。
|
||||
- 不实现完整 mindmap 新路径落盘;本轮只定义默认目标并完成附件/图片上传路径迁移。
|
||||
- 不把文件树改成页面语义树。
|
||||
- 不重新引入 `mnote_id` frontmatter。
|
||||
Reference in New Issue
Block a user