# dsh-md-notes 功能设计文档 本插件为 DSH 提供 **MD 笔记管理**:在侧边栏常驻入口,打开全屏笔记管理界面; 支持把任意一条回答及其提问直接记入指定笔记;并可选地把笔记同步到 Git 仓库 (共享仓库 / 独立仓库双模式)。 ## 1. 功能总览 | 功能 | 入口 | 说明 | |---|---|---| | 打开笔记管理 | 侧边栏「笔记」入口 | 全屏面板:左侧按工作区分组的列表 + 右侧编辑/预览 | | 新建笔记 | 激活工作区行「+」 | 自动生成标题(未命名笔记 日期),随即打开编辑 | | 编辑笔记 | 管理器右侧「编辑」Tab | markdown 源码编辑,点「保存」写入 | | 预览笔记 | 管理器右侧「预览」Tab | dsh `MarkdownText`(GFM / TeX 公式 / 代码高亮,安全内置) | | 删除笔记 | 列表项 🗑 | 页面内确认弹窗(Modal)后删除文件 | | 记入笔记 | 每条回答下方的 📝 | 选择/新建目标笔记,即时追加该回答及提问(文本由 client 从会话快照提取,host 只写文件) | | 笔记写入互斥 | — | 同一笔记写入期间跨会话锁定;入口 / 弹窗 / 管理器三处状态联动(见 §2.8) | | Git 同步 | 编辑器头部「更新/推送」 | 笔记本地固定 `<工作区>/.dsh-notes`,可同步到远程仓库 | | 版本更新提示 | 侧边栏入口 / 管理器标题栏 | npm 有新版时显示黄色「有新版本需要更新」tag | | 笔记引用进对话 | 对话输入框 `@` | 引用笔记,host 把内容注入模型上下文(见 [context.md](context.md)) | | 设置 | 管理器标题栏 ⚙ / dsh 设置面板「MD 笔记」 | 模式、仓库 URL、分支、自动拉取、作者等 | ## 2. 功能详述 ### 2.1 侧边栏入口(笔记) - 位置:左侧栏底部区域,通过 `sidebar.footer.action` slot 注册。 - 点击打开笔记管理全屏面板(`shell.overlay`)。 - 有笔记正在写入时,入口尾部(版本更新 tag 前)显示 loading,hover 提示「{count} 个笔记正在写入」。 ### 2.2 笔记管理界面 布局:全屏遮罩 + 居中面板(`shell.overlay` 注册),分左右两栏。 **左栏 — 笔记列表(按工作区分组)** - 每个 dsh 工作区一个分组,展示该工作区 `.dsh-notes/` 下的笔记(标题 + 更新时间倒序)。 - 工作区行:文件夹图标(激活时高亮)、折叠箭头,以及三个 icon 按钮——「更新」「推送」(Git 相关,见 §2.4)、「+」新建。 - 列表项:点击打开右侧预览(默认);🗑 删除(页面内 Modal 确认)。**正在写入的笔记**行尾显示 loading、删除按钮隐藏(仍可点击查看)。 - 空态:无工作区时显示引导提示;某工作区无笔记时显示空提示。 **右栏 — 编辑器** - 「编辑 / 预览」双 Tab(预览在前);「保存」写入本地文件。预览用 dsh `MarkdownText`(GFM / 公式 / 代码高亮)。 - 笔记所在工作区配置了仓库时,「保存」左侧出现「更新」、右侧出现「推送」; 远端有更新但本地不同时,更新按钮左侧显示黄色提示「远端有更新,需手动更新」。 - **正在写入的笔记**(当前选中时):编辑 Tab、更新、保存、推送全部禁用,更新按钮前的提示位 显示「正在写入文件」(优先级高于「远端有更新」提示)。 - 「推送」先弹 commit 弹层(提交信息,默认「笔记更新 <时间>」),确认后提交并推送。 - 底部同步状态行:分支、仓库内子路径、未提交数量、最近提交时间。 ### 2.3 记入笔记(📝) - 每条已完成的回答下方操作行有一个 📝 图标。 - 点击弹出选择面板(`shell.overlay`): - 按工作区分组列出**所有工作区**的笔记(可折叠浏览),支持**跨工作区记入**; - 每个工作区行有「+」按钮,可现场新建(自动生成「未命名笔记 <日期>」标题); - **正在写入的笔记不可选中**(行尾 loading); - 点「写入笔记」→ **即时**追加:提问 + 回答文本由 client 从浏览器会话快照提取 (与复制按钮同源,见 [context.md](context.md) §3.5),host 只做格式化 + 写文件; 写入中按钮显示「写入中…」,成功后按钮左侧出现绿色「已写入 ✓」再自动关闭(约 0.9 秒)。 - 追加内容格式: ```markdown --- ## <会话标题> -- <时间戳> ### 👤 <用户标签> <提问内容> ### 🤖 <助手标签> <回答内容> ``` > 段落标签(用户/助手/图片/空内容占位)由 client 按当前界面语言本地化后传入 > (中文「用户/DSH/(无)/[图片]」,英文对应),因此笔记内容跟随 dsh 的语言设置。 > **思考内容(reasoning)不记入**——只保留最终回答,与 dsh 界面(Think 为临时展示)一致。 ### 2.4 Git 同步 笔记本地永远保存在各工作区 `<工作区>/.dsh-notes`;Git 同步是可选能力,通过 **URL 驱动**的仓库(插件自动 `git clone` 到 `$DSH_HOME/md-notes-repos//`)。 两种互斥模式: - **共享仓库**(`gitMode: 'shared'`):一个仓库 URL(+ 可选分支,默认 main), 所有工作区笔记推到该仓库该分支、各自以工作区名命名的子目录。 - **独立仓库**(`gitMode: 'own'`):每工作区配仓库 URL + 分支(默认 main)+ 仓库内子路径(默认根)。 **交互**: - **保存** = 写入本地 `.md`(不碰 git);**推送** = 镜像同步本地笔记到仓库目标目录 (含删除同步)→ commit → push;**更新** = 拉取远端分支 → 同步回本地。 - **冲突交用户**:推送前检测远端同名笔记差异(`remote-changed`),弹确认窗 「用本地覆盖远端」/取消;更新时本地已修改的文件保守跳过,弹确认「用远端覆盖本地」。 - **自动拉取**:打开笔记时按 `gitAutoPull`(默认开)先保守拉取;有冲突时提示手动更新。 - 完整设计见 [git.md](git.md)。 ### 2.5 设置面板「MD 笔记」分区 dsh 设置面板(`settings.section` 注册)提供完整配置,表单控件与 dsh 一致 (DshInput / DshSelect,token 化配色、暗黑模式适配): - 模式三态:关闭 / 共享仓库 / 独立仓库; - 共享仓库:仓库 URL + 分支(默认 main); - 独立仓库:每工作区 仓库 URL + 分支 + 仓库内子路径; - 全局:自动拉取开关、提交作者名/邮箱; - 顶部提示面板:说明笔记本地保存在 `<工作区>/.dsh-notes`,Git 同步不影响本地位置。 ### 2.6 版本更新提示 插件初始化后(侧边栏入口或管理器首次挂载时)检查 npm 上 `dsh-md-notes` 的最新版本: - host 查询 `https://registry.npmjs.org/dsh-md-notes/latest`,与当前安装版本(包根 `package.json`)比较, 结果缓存 10 分钟;网络失败/读版本失败静默跳过。 - 有新版时: - **侧边栏笔记入口**按钮尾部显示黄色 tag「有新版本需要更新」(hover 显示最新版本号); - **笔记管理器标题栏**设置按钮旁同款 tag。 - 配色用 dsh 主题 warn token(amber 黄色系,20% 透明度背景 + 深黄文字),明暗主题自适应。 ### 2.7 笔记加入对话上下文(@ 引用,已实现) 在对话输入框通过 `@` 触发器引用笔记:选中后输入框出现 chip,发送时**host 把笔记内容注入 模型上下文**(`agent/pre-step`,§2.7.1)——模型直接拿到内容,不依赖它自己调用 `read`。 与「记入笔记」形成闭环。依赖 dsh 的 `ui-input-trigger` 引用管线。 交互流程: 1. 输入 `@` → 弹出候选菜单,列出**当前会话工作区**的笔记(行首为标题、副行为文件名, 前缀 📝 图标);无工作区的会话不弹候选(静默)。 2. 上下键/点击选中 → 输入框出现笔记 chip(占位符),可多选;chip 为 dsh 原生 4em 单元格, 标签前置截断(>4 字符 → 前 4 字符 + …,显示开头而非中间一截;短标题完整显示)。 3. **跨工作区**:输入部分工作区名(如 `@dsh-pl`)→ 候选出现**工作区行**(`dsh-plugin/`, 🗂️ 图标 + 「工作区」说明)和当前工作区过滤后的笔记;**点击工作区行自动补全** `@工作区名/` 并弹出该工作区笔记,继续输入即过滤(已进入工作区后只显示该工作区; **中文(无空格)工作区名已支持**,带空格的工作区名无法文本触发)。跨工作区笔记的 副行带 `工作区名 · 文件名`。 4. 发送 → 每个 chip 经 `codec.serialize` 序列化为**标准 markdown 链接语法**(随界面语言),如 `引用笔记 [标题](.dsh-notes/xxx.md)`(同工作区)或 `引用笔记 [标题](../dsh-work/.dsh-notes/xxx.md)` (跨工作区,相对会话工作区根);**host 端在模型请求前把笔记内容直接注入上下文** (`agent/pre-step`,界面显示为注入上下文行)——模型无需调用 `read` 也能引用。 5. **引用失效**:被引用笔记已删除/移动时发送被阻断(dsh 合约),提示 「<笔记名> 无法找到,请删除引用」,draft 与 chip 保留,不静默降级。 6. 纯文本 `@笔记名` 仅为装饰(lexicon 高亮,仅 ASCII 标题生效),不注入上下文; 真正引用必须走菜单 chip。 ### 2.7.1 注入行为(host 端) - 发送后 host 监听 `agent/pre-step`(dsh 原生机制,agent-instructions 同款):扫描已认领消息中的 笔记路径(`.dsh-notes/…` 相对会话 cwd 解析),读取内容并作为**注入上下文消息** (`source.kind: 'md-notes'`)折叠进模型请求——模型直接拿到内容,无需调用 `read`。 - 注入内容头部带**中英双语引用约定**:回答中如需引用本笔记,用 markdown 链接格式 `[标题](路径)`(与用户消息的序列化语法一致)。 - 注入消息随该 step 持久化进会话日志(渲染为对话里的「上下文注入」折叠行),**一次引用注入一次** (按 `source.path` 去重),并会留在会话上下文中直到 dsh 压缩旧历史(追问无需重新引用)。 - 引用失效:笔记已删除则跳过注入,用户消息里的路径行保留(模型可尝试 read 或说明缺失)。 - 内容边界:只读取 `.dsh-notes` 目录内的文件。 完整设计见 [context.md](context.md)。 ### 2.8 笔记写入互斥(写锁 + 全局写入状态) 对笔记的写操作(保存 / 记入笔记 / 删除)**跨会话互斥**——同一笔记写入期间,任何会话对其 再写都被拒绝(host 键控锁 `KeyedLock`,冲突返回 `note-writing`;client 端 busy 镜像负责 UI): - **记入弹窗**:写入中的笔记不可选中 + 行尾 loading; - **管理器**:该笔记行尾 loading + 删除隐藏;操作栏编辑 / 更新 / 保存 / 推送禁用、 提示位显示「正在写入文件」; - **笔记入口**:有任一笔记在写即显示 loading + tooltip「{count} 个笔记正在写入」 (位于版本更新 tag 前); - 写入完成(成功 / 失败)自动还原全部位置。 状态模型(通用 busy 切片,可扩展至 git / 导出等未来任务域)与方案详见 [state.md](state.md) 与 [write-lock.md](write-lock.md)。 ## 3. 交互状态与反馈 | 场景 | 反馈 | |---|---| | 新建成功 | 列表刷新 + 自动打开新笔记 + 提示「已创建 ✓」 | | 保存成功 | 提示「已保存」 | | 写入笔记成功 | 按钮前绿色「已写入 ✓」,900ms 后自动关闭弹窗 | | 写入进行中 | 按钮显示「写入中…」;该笔记在弹窗不可选 + 行尾 loading;入口 loading + tooltip | | 更新成功 | 提示「已更新 ✓」并刷新列表 | | 推送/更新冲突 | 页面内 Modal 确认(推送「用本地覆盖远端」/ 更新「用远端覆盖本地」) | | 删除 | 页面内 Modal 确认(红色确认按钮,提示不可撤销) | | 任一操作失败 | 面板内显示本地化错误信息(host 返回错误码 + client i18n 渲染) | ## 4. 数据模型 笔记 = 各工作区 `<工作区>/.dsh-notes/` 下的普通 `.md` 文件: ``` <工作区>/.dsh-notes/ ├── .md # 笔记内容(markdown) └── meta.json # { ".md": { title, updatedAt } } 标题与更新时间缓存(不入库) ``` - 文件名由标题规范化而来(非法字符转 `-`,强制 `.md` 后缀),重名自动加序号。 - `meta.json` 为最佳努力缓存:缺失或损坏时按文件名回退标题,不影响读写。 - **笔记本地位置恒定** `<工作区>/.dsh-notes`(v3/v4 定案):Git 仓库只是同步目标, 笔记位置不随仓库配置变化,不存在目录迁移问题。 - 笔记**深度绑定工作区**:没有工作区归属的会话无法读写笔记(`list` 返回 `noWorkspaces`,界面提示先新建工作区)。 ## 5. 非功能需求 - **普通文件可访问**:笔记就是 `.md` 文件,用户可直接在文件系统编辑,插件下次读取即生效。 - **无外部依赖**:Host/Client 通信走插件自带 HTTP 路由,不依赖 typert/Remote 工具链。 - **主题适配**:样式使用 DSH 主题 CSS 变量(`--dsw-alias-*`)并带静态兜底,明暗主题均可读; 表单控件(输入框/下拉框)用 DshInput/DshSelect 与 dsh 原生表单一致。 - **i18n**:所有 UI 文案中英双语(`zh.ts` 源字典 + `en.ts` 映射类型强制同键); host 错误以**错误码 + detail** 返回,client 用 `gitErrorText` 渲染本地化文案。 - **HMR 安全**:所有副作用(路由注册、样式注入、slot 注册)均挂在 `ctx.effect` 上,卸载时自动清理。 ## 6. Git 同步(已实现) Git 同步已实现(v3/v4 模型),详见 [git.md](git.md):笔记本地固定 `<工作区>/.dsh-notes`, 仓库由 URL 驱动(插件自动 clone)、共享/独立双模式、镜像同步(含删除)、冲突确认弹窗、 自动拉取、i18n 错误码。设计要点: - **URL 驱动**:仓库只配 URL,插件管理本地 clone(`$DSH_HOME/md-notes-repos//`), 无路径配置、无授权流程。 - **互斥模式**:`shared`(一个仓库管所有工作区)/ `own`(每工作区三件套)。 - **推送 = 镜像同步**:复制本地 `.md` 到仓库目标目录 + 删除本地已删文件 → commit → push。 - **更新 = 反向同步**:拉取远端分支 → 目标目录 `.md` 复制回本地(不覆盖本地已修改文件)。 - **冲突交用户**:推送/更新的覆盖都经页面内确认弹窗;`non-fast-forward` 提供「合并远端并重试」。