# 2026-06-25 Mindraw 深链基础链路 ## 用户目标 继续推进 `.mindraw` 基本可用,进入 Phase 3.5:验证本机 `mindraw://` Global Link / Deep Link,让从任意位置点击链接打开 Mindraw 文件成为可实现路径。 ## 已完成事项 - 接入 Tauri 2 deep-link 插件: - `@tauri-apps/plugin-deep-link` - `tauri-plugin-deep-link` - `src-tauri/capabilities/default.json` 增加 `deep-link:default` - `src-tauri/tauri.conf.json` 增加 `plugins.deep-link.desktop.schemes = ["mindraw"]` - 新增链接格式:`mindraw://open?documentId=&element=`。 - 新增兼容解析:`mindraw://localhost?documentId=&elementId=`。 - 新增本机私有 registry:打开、保存、另存 `.mindraw` 包时登记 `documentId -> packagePath` 到 `mindraw-documents.json`。 - 新增后端 `resolve_mindraw_link`:解析 URL,查 registry,复核包内 manifest 的 `documentId`,返回 package path 和 element id。 - 补齐 registry 陈旧记录清理:registry 指向的路径已不是 `.mindraw` 目录包时,或包内 manifest `documentId` 与 registry key 不匹配时,删除对应 entry 并提示重新打开包刷新 registry。 - 新增前端 `openMindrawDeepLinkUrls()`,并在 `App.tsx` 接入 `getCurrent()` 和 `onOpenUrl()`。 - 修复 deep link 对象定位时机问题:`mindraw-focus-element` 事件可能早于新 active file 的 editor 监听器注册;现在由 `ExcalidrawEditor` 缓存目标,等 active `.mindraw` 和 Excalidraw API 就绪后选中并滚动。 - 接入 Excalidraw `generateLinkForSelection`:当前 active 文件是 `.mindraw` 且存在 `documentId` 时,`Copy link to object` 复制 `mindraw://open?documentId=...&element=...`,不再复制 `tauri://localhost?element=...`。 - 新增 QA 文档 `02-P/qa/mindraw-phase35-deeplink-check.md`。 - 新增 QA 截图 `02-P/qa/mindraw-phase35-deeplink-smoke.png`。 - 新增复制对象链接 smoke 截图 `02-P/qa/mindraw-phase35-copy-link-smoke.png`。 - 更新 `02-P/plan-progress.markdown`、`CODEGRAPH.md`、`INDEX.md`。 ## 关键决策 - Global Link 第一版不把本机路径写进链接,避免泄露用户名和目录结构。 - `documentId` 负责跨对话/跨文档引用,实际本机定位由私有 registry 完成。 - registry 陈旧 entry 清理只处理明确不可用的记录;包移动后的自动搜索/迁移不在本轮做,仍要求用户重新打开 `.mindraw` 包刷新本机索引。 - 本轮不覆盖 `/Applications/Mindraw.app`;改用临时唯一 bundle id QA app 验证系统级 URL 触发,避免影响用户当前安装版。 - `element` 参数进入第一版可用链路:打开包后定位并选中目标对象。 - 用户最早观察到的 `tauri://localhost?element=...` 只保留为普通非 `.mindraw` 文件的回退;`.mindraw` 包里的对象链接第一版使用 `documentId + element`。 ## 文件变更 - `package.json` - `package-lock.json` - `src-tauri/Cargo.toml` - `src-tauri/Cargo.lock` - `src-tauri/capabilities/default.json` - `src-tauri/tauri.conf.json` - `src-tauri/src/lib.rs` - `src/App.tsx` - `src/components/ExcalidrawEditor.tsx` - `src/lib/mindrawDeepLink.ts` - `src/lib/mindrawDeepLink.test.ts` - `src/types/index.ts` - `src/store/useStore.ts` - `src/store/useStore.test.ts` - `02-P/qa/mindraw-phase35-deeplink-check.md` - `02-P/qa/mindraw-phase35-deeplink-smoke.png` - `02-P/qa/mindraw-phase35-copy-link-smoke.png` - `02-P/plan-progress.markdown` - `CODEGRAPH.md` - `INDEX.md` ## 验证结果 - `npm run test:run -- src/lib/mindrawDeepLink.test.ts src/hooks/useMenuHandler.test.ts src/lib/obsidianExcalidraw.test.ts`:PASS,3 个测试文件,33 个测试通过。 - `npm run test:run -- src/lib/imageDrop.test.ts src/hooks/useMenuHandler.test.ts src/hooks/useKeyboardShortcuts.test.tsx src/lib/documentFormat.test.ts src/lib/obsidianExcalidraw.test.ts src/lib/mindrawDeepLink.test.ts src/store/useStore.test.ts`:PASS,7 个测试文件,84 个测试通过。 - `cargo test --locked --manifest-path src-tauri/Cargo.toml mindraw_deep_link_tests`:PASS,5 个测试通过。 - `cargo test --locked --manifest-path src-tauri/Cargo.toml`:PASS,31 个测试通过。 - `cargo check --manifest-path src-tauri/Cargo.toml`:PASS。 - `npm run build`:PASS,仍有既有字体、Tauri dialog import 和 chunk size warning。 - `npm run tauri -- build --debug --bundles app`:PASS,生成本地 QA debug `.app`。 - `git diff --check`:PASS。 - `Info.plist` 检查:debug `.app` 已生成 `CFBundleURLSchemes = ["mindraw"]`。 - 临时唯一 QA bundle 系统级 smoke:热启动 `open -b com.mindraw.desktop.codexqa "mindraw://open?documentId=mdoc_smoke_deeplink_20260625&element=deep_link_target_red"` PASS,打开 `TargetBoard.mindraw` 并选中/滚动到红色目标对象。 - 临时唯一 QA bundle 系统级 smoke:冷启动同一条 URL PASS,启动应用、打开 `TargetBoard.mindraw` 并选中/滚动到红色目标对象。 - 临时唯一 QA bundle 复制对象链接 smoke:右键红色目标对象,点击 `Copy link to object`,剪贴板为 `mindraw://open?documentId=mdoc_smoke_deeplink_20260625&element=deep_link_target_red`,不是 `tauri://localhost?element=...`。 - `cargo fmt --manifest-path src-tauri/Cargo.toml`:失败,当前 stable toolchain 未安装 `cargo-fmt` / `rustfmt`。 ## 未决问题 - 未覆盖正式 `/Applications/Mindraw.app` 的替换安装验证;本轮只用临时唯一 QA bundle 验证系统级冷/热启动,避免影响用户当前安装版。 - registry 陈旧 entry 清理已覆盖缺失/无效路径与 `documentId` 不匹配;包移动后的自动搜索/迁移策略仍未实现,仍需要重新打开包刷新 `documentId -> packagePath`。 ## 后续建议 - 后续若进入可分发/安装包流程,再用正式安装版替换验证 `mindraw://` 默认 handler。 - 后续设计包移动自动重定位/迁移策略:重复 `documentId`、registry 陈旧后的用户提示和恢复路径。