# 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 秒超时和一键重试。
- **磁盘刷新**——「刷新脑图」直接重读当前文件，保留聊天草稿和附件，不发送模型请求。直读的新内容保留到后续工具结果到来；连续打开、关闭或切换会话后，旧请求不能覆盖新视图。读取失败保留原画布并显示可重试的错误。
- **草稿保护**——从宿主正式输入快照读取当前文字、引用和附件；存在未发送内容或状态暂时不可读时，不替换输入、不自动发送。目录文件仍可直接打开，编辑指令可手动发送。
- **解析失败显式成态**——文档 Markdown 万一让解析器崩掉，面板绝不整体炸：脑图区显示明确的解析失败态并带错误信息，原文件内容原样未动，可切回目录 tab 查看，或让 AI 修正后重新打开。正常文档永远走不到这里。
- **原生侧栏 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、节点间直角折线。
- **画布居中、缩放与平移**——脑图打开时自动「适配」：13px 的节点文字有效字号不低于 12px（代码块、表格、行内代码同为 13px 基准），放不下时由滚动和平移浏览。缩放条另有「全图」：允许缩到可读下限以下，尽量把整棵树放进视口，但最低仍是 25%，极大图仍可能溢出。手动缩放范围为 25%–300%；AI 编辑后会持续自动适配，直到你手动缩放或点击「全图」，点「适配」可恢复自动模式。
  点击节点会平滑聚焦到画布左侧约四分之一处，过大的子树可能超出视口；动画不逐帧重绘整棵树，通常单次缩放变化不超过 2 倍，若此前手动缩到可读下限以下则会直接恢复可读比例。AI 编辑后若选中节点完全离开视口，画布只做最小滚动把它拉回，不改变你的缩放。窄面板按高度适配，宽出的部分靠平移浏览；滚动条槽位常驻，避免适配值反复跳动。
  用**中键**随处拖动、在**空白处左键拖动**（包括 Mac 触控板点按并拖移），或按住 **Space + 左键**从节点上拖动。内容跟手移动，滚到边缘后仍可继续平移；4px 阈值区分拖与点，避免误清选中圈。
- **子树折叠**——有子节点的节点在连线起点上带一个小开关：折叠后隐藏整棵子树并提示隐藏了多少节点，超大脑图也能逐层看。折叠只是视图状态，不改 markdown 文件，导出图片仍是完整子树；切换文档自动全部展开。
- **PNG 导出**——面板右上角「导出图片」一键导出当前脑图。
- **复制全文**——「导出图片」左侧一键把当前脑图的 Markdown 原文复制到系统剪贴板：粘到飞书文档 / Notion / Obsidian 等支持 Markdown 的目标会自动还原标题、嵌套列表和表格，粘到纯文本环境则是带 `#`、`-` 符号的源码，零信息损失。成功后按钮短暂显示「已复制 ✓」（约 2 秒），失败复用导出错误的红字提示位。
- **复制当前节点文本内容**——节点右键菜单中位于「复制节点路径」正上方。只复制当前节点自身的完整文本，保留原有换行；不包含父节点、路径或子节点，不修改脑图或聊天草稿。
- **复制节点路径**——节点右键菜单新增「复制节点路径」，把根节点到当前节点的完整路径复制为单行纯文本，例如 `节点1--->节点2--->节点3--->节点4`。不包含子节点，也不自动发送消息或覆盖聊天草稿；复制失败时保留菜单并提示原因。
- **节点搜索与快速定位**——⌘/Ctrl+F（或缩放条上的 🔍）在当前脑图中搜索文字，Enter / ↑ ↓ 逐个跳转匹配节点（双向环绕），并自动展开被折叠分支中的搜索结果；跳转保留当前缩放、只滚动视图。搜索只改视图状态，绝不动 Markdown。
- **安全**——宿主对当前会话明确授予 `danger-full-access`（完全文件权限）时，新建、更新、重命名、清空和大范围重写均不额外请求插件确认。判断依据是宿主实时解析的文件权限（包括自定义预设），不是审批弹窗开关；宿主其他审批决定与路径、重名、大小、版本冲突检查仍保留。其他情况下，写入确认默认采用“本会话一次”，也可切换为“每次确认”或“关闭普通确认”；当前脑图工作区会显示并可撤销本会话授权。非完全权限时，重命名、清空和大范围重写仍需单独确认，`approvalMode: off` 或 `requireApproval: false` 只能关闭普通确认。仅关闭审批弹窗不等于授予文件权限：宿主会自动拒绝仍需确认的请求。宿主策略接口缺失、解析失败或返回未知值时，沿用配置的确认策略。完全权限下不积累可复用的文档授权，切回受限权限后恢复配置的确认策略。客户端**没有任何写文件通道**，一切编辑都经 AI 工具。

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

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

## 新建的脑图放在哪

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

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

- 设置面板新增 **「默认脑图命名是否添加AI工具标记」**，默认开启。标记指用户正在使用的宿主工具，所以这里是 **DSH**，不是内嵌模型、引擎或供应商；关闭后恢复 `YYYYMMDD-HHmmss-中文描述.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` |

新版输入快照、设置与会话接口按 `0.2.0-rc.2` / `0.2.1-alpha.1` 契约补有离线回归覆盖；不等同于全部宿主版本的完整验收。带路径前缀的 Web 页面使用页面基础地址请求脑图 API，保留反向代理前缀并检查同源。

## 安装

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

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

发布 tag：

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

npm 精确版本安装：

```bash
dsh plugin --profile <profile> add dsh-mindmap@<version>
```

新发布版本可能受到安装器的新版本冷却策略影响；安装后核对插件管理页显示的实际版本，需要指定版本时使用上述精确版本写法。

## 工具

脑图请求直接使用下面四个 `mindmap_*` 原生工具，不需要查找或加载技能；`find-skills` 和 `workbuddy-mindmap` 不属于本插件的操作流程。AI 指引及新建／打开入口明确要求只用原生工具，不运行外部脚本，也不改用通用写文件工具。工具失败时如实报告，不换工具绕过权限。

| 工具 | 说明 |
| --- | --- |
| `mindmap_create(name? \| description, directory?)` | 新建脑图并显示到面板（文件已存在则报错）。给了 `name` 就建 `<name>.md`；没给就传一句短 `description`，由 host 默认命名成 `.mindmaps/YYYYMMDD-HHmmss-DSH-<description>.md`，可在设置中关闭 DSH 标记。只有用户点了位置才传 `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 run bench:client  # 虚构长会话的纯计算重放基准，不启动服务或浏览器
npm pack --dry-run    # 检查将进入 npm 包的文件
```

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

文档重放共享会话内的解析缓存，文本变化时失效，切换会话后重新建立。基准脚本使用 3000 个虚构会话节点、200 个脑图工具结果，先核对缓存与完整重放的结果一致，再比较耗时；它衡量重放成本，不代表浏览器帧率或完整 UI 性能。

## License

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