# dsh-mindmap

[English](./README.md)

一个 DeepSeek Harness 插件：把工作目录里的普通 Markdown 文件变成一颗**实时脑图**。聊天框是编辑它的助手——你聊一句、AI 改一步 `.md`、右侧悬浮面板实时跟着变。

> 项目状态：pre-1.0。当前功能集（见 [CHANGELOG](./CHANGELOG.md)）已实现并有单元测试覆盖，但开发环境之外的跨版本兼容性尚未认证。

## 核心思想

- 打开一个 Markdown 文档，它就是一颗脑图；
- 聊天框不是主角，而是「旁边帮你编辑这颗脑图的助手」；
- 人聊一句、AI 改一步（改 markdown）、脑图实时跟着变；
- 脑图 = markdown，天然可 diff、可分享、可进 git。

## 功能

- **四个工具**（`mindmap_create` / `mindmap_open` / `mindmap_get` / `mindmap_update`）——会话工作目录里的普通 `.md` 文件；根节点标题 = 文件名，双向同步（`renameRoot` 触发文件重命名，撞名报错不覆盖）。
- **零通道实时面板**——面板直接消费会话快照里的 `mindmap_*` 工具结果，AI 每改一步面板即渲染一次。
- **打开必达 + 加载态可恢复**——AI create/open 结果落地，面板必展开（节点结构指纹驱动快照重算，不受宿主数组引用稳定性影响）；点目录树 `.md` 会先走本地只读路由直接显示，AI fallback 加载态仍支持大小写路径自动匹配、工具错误提示、约 30 秒超时和一键重试。
- **原生侧栏 Tab 或右侧悬浮面板**——安装了 `dsh-better-sidebar` 时，脑图注册为 Better Sidebar 内的原生单实例 Tab（`dsh-mindmap:mindmap`），工具栏只有一行（脑图列表、当前脑图、导出图片在同一行）；头部「思维脑图」按钮打开或聚焦该 Tab。未安装时回退为独立的右侧悬浮面板——会话头部按钮开合，宽度可拖（280px ~ 80% 视口）并持久化，打开时**聊天区向左让位**（布局推挤，互不遮挡）。AI 创建、打开或查看脑图时自动展开或聚焦面板/Tab 并切换到目标文档，即使当前收起或重复打开同一文档也能接续跟随。模式切换完全可逆：Better Sidebar 运行中卸载后，独立面板与布局推挤 CSS 自动恢复。
- **常驻目录树 tab**——工作目录结构懒加载树（插件自建只读路由）；空白处右键新建到脑图收件箱、目录右键新建到该目录；左键点 `.md` 先通过只读路由直接显示，再在草稿为空时交给 AI 对话编辑。独立面板模式标签为「目录」，侧栏模式标签为「脑图列表」。
- **单脑图模式**——面板只有树/列表和「脑图」两个 tab，打开新脑图替换旧的那颗。
- **「所见即所编」焦点同步**——可见脑图与 AI 工作文档不一致时，面板自动让 AI 打开它，聊天焦点始终跟随你的眼睛。
- **MarkGrove 同款映射与连线**——标题层级挂树、列表缩进（空项 = 占位节点）、代码块叶节点、段落升格为独立节点（019 块概念）、稳定结构 ID、节点间直角折线。
- **画布居中、缩放与平移**——脑图打开后居中呈现（超出画布时可滚动、无边缘裁剪）；画布右上角浮动缩放条（缩小 / 比例 / 放大 / 适配），打开时自动适配合适比例（小图保持 100%），25%–300% 逐级缩放且视图中心不跳变，AI 编辑后持续自动再适配，直到你手动缩放。点击任意节点即可聚焦：节点从被点位置平滑滑向画布左侧居中锚位（无首帧突跳），视图平滑放大到它和整棵子树完整可见（上限 100%，且单次点击缩放变化不超过 2 倍，巨图上连点渐进深入）；动画期间直接操作画布层、不逐帧重绘整棵树，聚焦动画可随时被拖拽、缩放或新点击打断。AI 编辑后若聚焦的节点被顶出视野，画布只做最小滚动把它带回边缘，不打乱你选定的缩放。窄面板（侧栏模式）下自动改按高度适配，宽出的部分靠平移浏览；滚动条槽位常驻，适配比例不再因滚动条出现而反复跳变。画布还能拖着走：**中键**随处拖（含节点上）、**空白处左键拖**（Mac 触控板「点按并拖移」）、或 **Space + 左键拖**（必须从节点上起手时）；无论内容是否溢出都可横纵双向拖动，内容跟手 1:1，空白处呈抓手光标，4px 阈值把拖与点分开——点空白仍取消选中、点节点仍聚焦，真拖不会误清选中圈。
- **子树折叠**——有子节点的节点在连线起点上带一个小开关：折叠后隐藏整棵子树并提示隐藏了多少节点，超大脑图也能逐层看。折叠只是视图状态，不改 markdown 文件，导出图片仍是完整子树；切换文档自动全部展开。
- **PNG 导出**——面板右上角「导出图片」一键导出当前脑图。
- **复制全文**——「导出图片」左侧一键把当前脑图的 Markdown 原文复制到系统剪贴板：粘到飞书文档 / Notion / Obsidian 等支持 Markdown 的目标会自动还原标题、嵌套列表和表格，粘到纯文本环境则是带 `#`、`-` 符号的源码，零信息损失。成功后按钮短暂显示「已复制 ✓」（约 2 秒），失败复用导出错误的红字提示位。
- **节点搜索与快速定位**——⌘/Ctrl+F（或缩放条上的 🔍）在当前脑图中搜索文字，Enter / ↑ ↓ 逐个跳转匹配节点（双向环绕），并自动展开被折叠分支中的搜索结果；跳转保留当前缩放、只滚动视图。搜索只改视图状态，绝不动 Markdown。
- **安全**——写入确认默认采用“本会话一次”：同一会话内同一脑图首次写入确认后，后续普通 `mindmap_update` 不再重复弹窗；也可切换为“每次确认”或“关闭普通确认”。重命名、删除和大范围重写仍需单独确认；当前脑图工作区会显示并可撤销本会话授权。受信自动化可显式设置 `requireApproval: false` 关闭普通确认，但高风险写入仍需确认。客户端**没有任何写文件通道**，一切编辑都经 AI 工具。

内嵌 Better Sidebar 时，脑图列表采用宿主的 14px 正文字体。Markdown 文件显示紧凑的 M 徽标，文件夹与其他文件使用 14px 线框图标；其他格式文件仅展示，没有悬停反馈、打开、拖拽或右键菜单，文件夹仍可展开。标签、操作按钮和提示采用宿主的 12px 字体角色。独立模式保留原有外观；脑图节点的字体层级、缩放和图片导出保持不变。

内嵌 M 徽标采用透明底、粗体字母与细描边，字母和边框跟随文件名的主题文字颜色；浅色、深色及自定义皮肤切换时同步适配，不依赖品牌色与底色的对比。

## 新建的脑图放在哪

你说「创建一个脑图」「把刚才的讨论整理成脑图」「盘点一下这个问题」这类没点目录的请求时，文件落在 **`.mindmaps/`**——脑图收件箱：

```text
.mindmaps/20260918-155230-项目盘点.md
```

- `YYYYMMDD-HHmmss` 由 host 读本机时钟生成，模型只给那句短描述（按文件名安全规则清理，最长 24 字）。同一秒撞名依次加 `-2`、`-3` 后缀，**已有文件永不被覆盖**；写入确认框里报出的就是它准备创建的那条路径。
- 路径校验走两遍：画确认框时一遍，真正落盘前再按当前文件系统核一遍。你还在读确认框时目标目录被改名、或被换成指向工作区外的符号链接，本次创建直接失败，绝不会把文件写到会话工作目录外面。
- `.mindmaps/` 第一次需要时才建，不在安装时预生成。目录树里它显示为 **「脑图收件箱（.mindmaps）」**，免得点号目录被当成工具残留以为内容看不见。
- 不替你写 `.gitignore`。脑图仍是普通 Markdown：可以审阅、diff、提交，也可以挪去正式目录。
- 你点了位置就尊重位置：`docs/架构脑图.md`、`planning/迭代计划.md`，或在目录树上右键选「在此目录新建 Markdown 脑图」。显式目录不会被改判进收件箱，且照样受会话工作目录边界与符号链接越界校验约束。
- 根节点标题 = 文件名，所以默认新建的脑图暂时会把时间戳显示成根标题。把「文件名」和「显示标题」拆开是独立需求，想要干净标题就用 `renameRoot` 改名（会同步重命名文件）。

## 环境要求

| 组件 | 基线 |
| --- | --- |
| Node.js | 20.11 及以上 |
| DeepSeek Harness | 实测于 `0.1.1-rc.2`、`0.1.2-rc.1` 与 `0.1.5-rc.1` |

## 安装

开发（link 安装，实时源码）：

```bash
dsh plugin --profile web add link:/path/to/dsh-mindmap
```

发布 tag：

```bash
dsh plugin --profile <profile> add <pkg>#v<version>
```

## 工具

| 工具 | 说明 |
| --- | --- |
| `mindmap_create(name? \| description, directory?)` | 新建脑图并显示到面板（文件已存在则报错）。给了 `name` 就建 `<name>.md`；没给就传一句短 `description`，由 host 命名成 `.mindmaps/YYYYMMDD-HHmmss-<description>.md`。只有用户点了位置才传 `directory`。 |
| `mindmap_open(path)` | 把已有 `.md` 作为脑图打开到面板。 |
| `mindmap_get(path)` | 读取脑图文档的当前 Markdown 内容和 revision。 |
| `mindmap_update(path, content, renameRoot?, expectedRevision?)` | 写入完整的新 Markdown；带上读取时的 revision 可避免覆盖并发修改；可选重命名根节点（重命名文件，撞名拒绝）。 |

## 开发

```bash
npm run build:client  # 从 src/client 片段组装运行时 client.js
npm run verify        # 重建 + 语法检查 + node --test
npm pack --dry-run    # 检查将进入 npm 包的文件
```

浏览器端实现维护在 `src/client/` 下，构建后仍输出 DeepSeek Harness 要求的单一 `client.js` 入口。请修改源码片段后运行 `npm run build:client`，不要直接手改生成入口。

## License

MIT License，详见 [LICENSE](LICENSE)。
