dsh-kp-notes
Maintenance: Activeunitysirx/dsh-kp-notes
Turns a Markdown notes directory into a card-based learning canvas with hierarchical chapters, knowledge points, exercises, KaTeX, Mermaid diagrams, mind maps, and in-panel editing.
$ dsh plugin add dsh-kp-notesInstall
dsh has no central install command — add this plugin’s entry (documented in its README below) to your profile or patch config, then restart.
How installs work0
stars
0
forks
JavaScript
Language
MIT
License
2026-10-03
Created
2026-10-15
Last push
README
学习画布 · dsh-kp-notes
把一整个目录的 Markdown 笔记变成一张可以平移、缩放的卡片画布 —— 一个目录 = 一章,一章 = 一张卡;知识点是卡片,题目自带答案遮挡,随手自测。
把一整个目录的 Markdown 笔记变成一张可以平移、缩放的卡片画布 —— 一个目录 = 一章,一章 = 一张卡;知识点是卡片,题目自带答案遮挡,随手自测。
写给 DeepSeek Harness 的插件(宿主半 + 浏览器半)。笔记就是普通的 markdown 文件,留在你自己的目录里:插件不建数据库、不改你的文件格式,删掉插件笔记照样能读。渲染引擎与编辑器随插件分发,不联网、不依赖 CDN、不需要构建;界面中英双语,跟随宿主语言。
界面预览
| 画布:章节卡 → 小节 → 知识点卡片墙 | 知识点详情:真表格 + LaTeX 公式(KaTeX) |
|---|---|
![]() |
![]() |
| 题目:答案默认折成「▸ 答案已遮挡」 | 点开自测:答案 + 解析 |
![]() |
![]() |
| 思维导图:章 → 小节 → 知识点 | 正文里的 mermaid 流程图(本地渲染) |
![]() |
![]() |
| 编辑知识点:笔记就是普通 markdown | 多画布:一个目录 = 一块画布 |
![]() |
![]() |
特性一览
| 画布 | 章节卡排成一行、不换行,可自由平移 / 缩放(20% ~ 240%);点小节在右侧展开知识点卡片墙 |
| 思维导图 | 同一份笔记切换成「章 → 小节 → 知识点 → 正文」的左→右树;正文按小标题拆成小知识点卡片,同一时刻只展开一个(手风琴) |
| 多画布 | 一级画布上每张卡 = 磁盘上一个笔记根目录(软考、别的考试、工作笔记各放一个,互不干扰);画布清单 / 移出记录 / 字号配色主题跨浏览器同步 |
| 题目与自测 | 一个知识点配一个题目文件,一个文件可放任意多道(每道一个 ## 题目 N);答案默认折叠成「▸ 答案已遮挡」,点开自测;选择题 / 案例题两种题型可视化录入 |
| 富文本编辑 | 编辑器抽屉默认所见即所得(Milkdown:/ 斜杠菜单、选区工具条),一键切回「markdown 源码 + 实时预览」;文件开头的 YAML 头不会被富文本碰坏;Milkdown 回吐 markdown 时会防御性转义(把正文里的 _ ~ & [ \ |、行首标点写成 _ ~ …),插件写回前会逐字验证「去掉后渲染完全一样」再去掉,a*b*c、行首 - 这类真在当语法用的原样保留;$A_i$ 这种成对转义的美元符号会还原成内联公式($A_i$`),题目 / 知识点弹窗与编辑器抽屉走同一套判官 |
| 公式与流程图 | 正文里直接写 LaTeX 与 mermaid,本地渲染;语法写错只在原地报错,不弹引擎那层关不掉的遮罩 |
| 输入助手 | 44 条公式模板 + 8 条结构 / 笔记 / 题目模板(模板本身就是两个可编辑的 markdown 文件),工具栏按钮 + 快捷键,外加一套自己实现的编辑键 |
| 配色与主题 | 插件配色(默认,自带 15 套皮肤:科技蓝 + 14 套 Material Design)/ 跟随主题(直接吃当前 DeepSeek Harness 主题的底色 / 文字 / 强调色,不覆盖平台主题)两档;还能让每张卡各用一色;整体字号 85% ~ 160%;全屏专注模式 |
| Git | ⎇ Git 提交 一次提交整个学习库(提交前自动 git pull --no-rebase),可 ✦ AI 生成 提交信息;绝不 reset / checkout / rebase,冲突了就停下来交给你 |
安装
需要 DeepSeek Harness(桌面版或 Web 版;开发环境为 0.2.0-rc.2)。插件没有 npm 依赖、也不需要构建 —— KaTeX / mermaid / zt-react-milkdown 都在 plugin/dsh-kp-notes/vendor/ 里随包分发。
从本仓库安装(现在就能用):先把仓库克隆到本地,然后
dsh plugin --profile <profile 名> add link:/绝对路径/rk-study/plugin/dsh-kp-notes
从 GitHub 直装(不用克隆):
dsh plugin --profile <profile 名> add github:UnitySirx/dsh-kp-notes#path:plugin/dsh-kp-notes
pnpm ≥10 会提示
The git-hosted package … has to be built but the build scripts were ignored—— 这个包没有构建步骤(没声明prepare/build,也没装任何依赖),忽略这条警告即可。
从 npm 安装(包尚未发布;发布后把 link: 那段换成包名即可):
dsh plugin --profile <profile 名> add dsh-kp-notes
装好后在「插件」面板里把 dsh-kp-notes(内部名 rk-study)打开 —— plugin/dsh-kp-notes/package.json 里声明了 dsh.bundle.patch(Node 半)与 dsh.client(浏览器半),宿主会把两半一起挂上;入口是左侧边栏面板列表里的「知识点笔记」(英文界面下是 Knowledge Notes,图标 plugin/dsh-kp-notes/icon.svg)。三种装法装完都一样。
改完代码怎么生效:改 plugin/dsh-kp-notes/client/ 或 client.js 后刷新页面(⌘R)即可;改 host.js / lib/ 下任何文件时把 ?v=N +1(碰了客户端模块的行为就再把 client.js 的 MODULE_VERSION +1),见「五、插件实现」开头。cordis.patch.yml 现在是发布形态的包名 dsh-kp-notes(没有 ?entry=N 缓存戳),关开 bundle 不会靠换 URL 重新 import 宿主模块;但实测保存后宿主半仍会被重新 import,隔几秒就生效(撞 ?v=N 是必须的:模块按完整 URL 缓存,只改文件内容不换 URL 会一直用缓存里的旧模块)。客户端那半关开一次 bundle(或改个按钮文案)就生效;不放心时重启 DeepSeek Harness 最稳。
快速开始
- 准备一个目录当画布(放插件目录外面,例如
~/Notes/系统架构师/)。面板右上角的+ 新建学习画布会帮你建好notes/与questions/两个子目录,也可以自己手工建。- 想一次管多张画布:先建一个空目录(比如
~/Notes/),用面板右上的⌂ 根目录把它设成根目录(列表里就是它下面那一层子目录),之后新建的画布都挂在它下面。
- 想一次管多张画布:先建一个空目录(比如
- 写笔记:在
notes/下按约定建目录与 markdown 文件(见下一节),或者直接在面板里点+ 新建章节/+ 新建小节/+ 新建知识点/+ 添加题目。 - 看画布:章节卡 → 点小节 → 右侧知识点卡片墙 → 点知识点看说明与题目;答案默认遮挡,点一下展开。
笔记目录(
notes//questions/)里不写任何配置文件:字号、配色、视野这类状态只存在浏览器、学习库那一级的.config/rk-study.json,以及每张画布自己目录下那份.config/rk-study.json(只记这张画布的视野与字号),笔记文件永远是纯粹的 markdown。
目录
下面开始,就是把「磁盘上的文件」和「画布上的卡片」一一对应起来的最完整说明。
一、目录结构与命名约定
| 文件系统 | 插件里 |
|---|---|
notes/ 下的一个目录 |
一个大章节(画布上的一张章节卡);目录名 = 章节名,卡上点「改名」即可重命名(目录本身跟着改) |
notes/<章>/<NN>-标题.md |
该章的第 NN 个小节(只放标题 + 小节导读) |
notes/<章>/<NN>-<MM>-标题.md |
小节 NN 下的第 MM 个知识点(一个文件 = 一张知识点卡片) |
questions/<章>/<同名文件>.md |
上面那个知识点的题目(一个文件可放多道,每道题一个 ## 题目 N) |
<画布根目录>/ ← 例如 ~/Notes/系统架构师/
├─ notes/
│ ├─ 01-架构设计基础/
│ │ ├─ 01-架构风格与架构视图.md ← 小节 01(标题 + 导读)
│ │ ├─ 01-01-五大类架构风格.md ← 知识点(只有说明,不写题)
│ │ ├─ 01-02-易混淆对比.md ← 知识点
│ │ └─ 02-架构评估方法与ATAM.md ← 小节 02
│ └─ 02-质量属性与战术/…
└─ questions/
└─ 01-架构设计基础/
├─ 01-01-五大类架构风格.md ← 知识点 01-01 的题目
└─ 02-04-敏感点-权衡点-风险点.md ← 知识点 02-04 的题目
挂在学习库下的画布(父目录里还有别的画布,例如
~/Notes/系统架构师/)自己不会有.templates/:模板统一放学习库根目录那一份。它自己的目录下会有一份.config/,但只放这张画布自己的东西 —— 视野与字号(rk-study.json)、发号计数器(同一个文件里的seq)与号池(rk-study-uids.json);画布清单、库级字号配色这类库级状态仍在库根目录那份里(见下面「学习库」与「设置存在哪」)。只有自带根目录的画布(不挂在任何学习库下)才会在它自己目录下建.templates/。
notes/、questions/ 是相对画布根目录的路径(不是相对插件仓库)。插件仓库里没有这两个目录:一个画布一个根目录,各自独立、也各自独立 git。
配对规则:题目文件与知识点文件路径同名(notes/X/Y.md ⇄ questions/X/Y.md)即自动配对;也可以在题目文件的 frontmatter 里写 point: notes/X/Y.md 显式指定。配不上的题目文件不会丢,会挂到对应章节目录下并在目录 JSON 的 orphanQuestions 里列出。
命名规则(不满足时会退化,不会丢文件):
- 第一个数字 = 小节号,决定这个文件挂在哪一小节下;第二个数字 = 小节内的知识点序号。
- 兼容旧写法:文件名里出现
例题/题目/案例/错题/真题/习题/已做等片段也判为题目文件,所以历史文件不用改名。 - 都不是、且没有第二个数字 → 判为小节文件(自己一行)。
- 想在 frontmatter 里显式指定,可写
type: point(知识点)/type: question(题目)/type: section(小节);不写就按文件名推断。 - 章节名 = 目录名去掉
01-这类序号前缀;章节序号也来自目录名,所以「第 2 章 · 质量属性与战术」= 目录notes/02-质量属性与战术/。像本仓库README.md这样直接放在画布根目录下的文件,属于「根目录」那一章,章名取其中第一个小节的标题。 - 没有对应小节文件的独立知识点不会消失:会作为一个小节单独列出来。
二、三类文件长什么样
小节文件(notes/<章>/<NN>-标题.md)
---
title: 架构评估方法与 ATAM
type: section
order: 2
tags: [ATAM, 架构评估]
---
# 架构评估方法与 ATAM
考点集中区:SAAM / ATAM / CBAM / SAEM 的区别、ATAM 的四阶段九步骤、效用树的三层结构。
小节文件只放标题 + 导读,内容都拆到知识点文件里。
知识点文件(notes/<章>/<NN>-<MM>-标题.md)
---
title: 敏感点 / 权衡点 / 风险点
type: point
order: 4
tags: [ATAM, 质量属性]
---
# 敏感点 / 权衡点 / 风险点
| 类型 | 含义 | 影响范围 |
| --- | --- | --- |
| 敏感点 | 为实现某一个质量属性,对某架构决策特别敏感的点 | 影响 1 个属性 |
- 按目录定性质:
notes/下的内容一律是知识点,questions/下的内容一律是题目 —— 不会从笔记里「抽」出题目,也不会把笔记切成子卡片。 - 知识点卡片上显示的是提取出来的说明文字,不是 markdown 源码;表格会转成文字摘要。
- 一个知识点文件(
# 标题或## 标题开头)就是一张知识点卡片:里面出现的所有标题(##、###、####……)都留在正文里,不会再拆成画布上的子卡片。 - 正文里的标题按级别分大小与颜色:
#20px/800 渐变白蓝、##17px/700 + 左侧 3px 色条、###15px/700 + 2px 色条、####13.6px、#####12.8px + 字距、######12px + 字距(色条颜色 = 标题色)。2~6 级各给一个鲜艳的颜色、互不撞色:青 → 紫 → 粉 → 琥珀 → 绿,默认皮肤写死在--rk-t2 … --rk-t6五个变量里;换「配色」时按主色色相旋转+0 / +62 / +128 / +200 / +268重算这五个值,所以既鲜艳又跟整体配色协调。正文、实时预览、详情页走同一套;小知识点的标题、左侧色条、序号块也按它自己的级别取同一组颜色(另有 16 / 14.8 / 13.4 / 12.8 / 12.3px 五档字号),右侧角标写着它是几级。 - 但详情页会把正文里的小标题显示成小知识点:取正文中最浅的那一级标题(只有
###就按###,同时有##与###就按##)当分界,标题前的内容是引子,每个标题带自己下面那段正文,上面加一行 小知识点 N;编号行(1.2.…)不算分界,留在它所属的小知识点里。代码块里的#不会被当成标题。写笔记时想在详情里分几小点,就用小标题分段。 - 知识点详情页里的题目来自
questions/目录(用题目文件 frontmatter 的point:指到这个知识点),或者你在详情页点 + 添加题目 加进去的;两者都会写进questions/。
题目文件(questions/<章>/<同名文件>.md)
---
title: 敏感点 / 权衡点 / 风险点 · 题目
type: question
order: 4
tags: [ATAM, 质量属性]
point: notes/01-架构设计基础/02-04-敏感点-权衡点-风险点.md
---
# 敏感点 / 权衡点 / 风险点 · 题目
## 题目 1
在 ATAM 评估中,若某个架构决策同时影响到系统的安全性和性能,则该决策点被称为( )。
A. 敏感点
B. 权衡点
C. 风险点
D. 非风险点
**答案**:B
**解析**:敏感点影响一个质量属性,权衡点影响多个质量属性。
## 题目 2
同一道题里还可以带 `### 问题 1`、`### 问题 2` 这样的子问题(案例题常用)。
**答案**:……
- 一个题目文件可以放任意多道题,每道题一个
## 题目 N,卡片样式与遮挡规则完全一样 —— 没有「例题 / 已做题目」之分,一律叫题目。 - 题目标题写在几级都可以(
## 题目 1最常用,# 题目 1/### 题目 1也认),检测与删除用的是同一套判定:界面上一道题,就一定能删掉。文件里没有任何题目标题时不会凭空造题,界面显示「题目 0 · 这个知识点还没有题目」,点+ 添加题目补一道标准的即可。 - 题目只出现在知识点详情页里,紧跟在知识点说明下面 —— 题目只属于知识点,不属于小节。
- 题目下面自带
### 问题 1这类子标题也可以,题干与答案会被正确切开。 - 两种题型自动识别,也决定
+ 添加题目打开哪个表单:- 选择题 —— 题干下面有
A. …到D. …若干行选项,**答案**:B只写字母,**解析**:…另起一行; - 案例题 —— 没有选项行,
**答案**:后面就是答案正文(可以带### 问题 N子标题、列表、表格)。 - 表单只管这些约定好的位置(题干 / 选项 / 答案行 / 解析行),答案正文里的 markdown 原样保留,不会被插件改写。
- 选择题 —— 题干下面有
答案遮挡
- 答案写在题干后面即可,
**答案**:B、答案:B、或另起一个## 答案小节都认。 - 从「答案」那一行往后(含解析)默认折叠成
▸ 答案已遮挡 · 点击展开,点一下展开。 - 知识点详情页的**「题目」那一行**(和
+ 添加题目并排)有「显示全部答案」,一次展开本知识点的全部答案。 - 选择题的 A/B/C/D 选项自动识别、按行排版。
公式与流程图
正文(知识点说明、答案、导读……)里可以直接写 LaTeX 公式和 mermaid 流程图,插件会渲染出来:

| 写法 | 渲染成 |
|---|---|
$A = \frac{MTBF}{MTBF + MTTR}$ |
行内公式 |
\(x^2 + y^2 = z^2\) |
行内公式(另一种写法) |
单独成段的 $$ … $$ |
居中的块级公式 |
```math / ```latex 围栏 |
块级公式 |
```mermaid 围栏 |
流程图 / 时序图 / 状态图等 mermaid 图 |
- 渲染引擎(KaTeX 0.16.47 + mermaid 11.17.2)作为静态资源随插件分发(
plugin/dsh-kp-notes/vendor/,约 7.1 MB:KaTeX 292 KB + mermaid 3.4 MB + zt-milkdown 3.1 MB),由插件自己的路由/rk-study/vendor/*直出;页面第一次遇到公式/图时才去取,之后走浏览器缓存 —— 不联网、不依赖 CDN、不需要构建。 - 只认识「像公式的」
$…$:价格 $100, 折扣 $20、$5 到 $10这类货币写法会原样显示,不会被当成公式吃掉。 - 引擎取不到时不会白屏:公式退回显示原始
$…$,流程图显示红框提示 + 原始代码,正文照常可读。 - 语法写错时不弹 mermaid 自带的那个红框(它是引擎直接挂到页面
body上的,React 管不到,会一直挡着关不掉):只在原地显示「流程图渲染失败:Parse error on line N」加出错的源码,改好语法自动重画。做法是mermaid.initialize({ suppressErrorRendering: true })让引擎先自己清理再抛错,再加一层按 id 兜底删临时节点的保险。 - 边写边看:编辑器抽屉默认是富文本所见即所得(Milkdown,见下条),点右上角「源码」切回「markdown 源码 + 实时预览」的左右分栏;编辑知识点 / 题目的弹窗仍是左右分栏,右边跟着左边实时渲染 —— 写公式和流程图不用先保存再刷新。
- YAML 头不会被富文本碰到:笔记文件开头那段
---…---元数据(title/type/tags/order)只在源码模式里显示和编辑,富文本里看不到也改不到,保存时再原样拼回去(抽屉头会亮一个「YAML ✓」小标)—— 所以打开富文本改正文、随手保存,不会把元数据变成一段普通文字。富文本回吐的正文还会顺手清掉空段落留下的<br />和行尾空格,头后面固定留一个空行。 - 编辑器也是随插件分发的静态资源:
plugin/dsh-kp-notes/vendor/zt-milkdown/里放的是zt-react-milkdown@0.1.32(MIT,Milkdown 内核;zt-milkdown.js1.6 MB +zt-milkdown.css1.6 MB,含内联字体)。加载方式是自己写的小加载器client/milkdown.js:注入样式 →fetch回 CJS 文本 → 用new Function('require','module','exports', code)执行,require只映射react/react-dom/react-dom/client/react/jsx-runtime(都用宿主那一份,react-dom/server给个空壳)—— 所以不需要 npm 安装、不联网、不打包。编辑器脚本取不到(文件缺失、浏览器拦截)时自动停在源码模式,不会白屏。
三、直接在插件里写

| 位置 | 操作 | 结果 |
|---|---|---|
| 画布右上角 | + 新建章节 | 弹出输入框,只输入章节名;创建目录 <父目录>/<NN>-<章节名>/(不生成任何文件,空章节也会立刻出现在画布上) |
| 章节卡右上角 | 改名 | 改章节名 = 改目录名(序号前缀保留);questions/ 下的同名题目目录一起改名,题目文件里的 point: 前缀同步更新 |
| 章节卡底部 | + 新建小节 | 创建 <章节目录>/<NN>-<标题>.md(type: section + 导读) |
| 小节页右上角 | + 新建知识点 | 创建 <章节目录>/<NN>-<MM>-<标题>.md(type: point + 说明骨架) |
| 知识点页 · 题目分组 | + 添加题目 | 弹出可视化表单(选择题 / 案例题两种),不用写 markdown |
| 每道题右上角 | 编辑此题 | 同一个表单,字段已经从文件里解析出来,改完保存即写回该题目文件 |
| 题目表单 · 选择题 | 题干 / 选项 A–D / 正确答案(点圆点)/ 解析 | 选项可增删(+ 加选项、每行 删除);留空的选项保存时丢掉,字母按顺序重排 |
| 题目表单 · 案例题 | 题干 + 答案正文(markdown) | 多问案例题就按「问题 1 / 答案 / 问题 2 / 答案」往下写,原样保存、原样读回 |
| 题目表单 / 知识点表单 | 左栏写、右栏实时预览 | 两个弹窗都是大号左右分栏:左边是表单,右边实时渲染 —— 题干/正文里的 $公式$ 与 ```mermaid 流程图边写边出,选项与答案按写入文件的样子预览。里面的 markdown 字段(题干 / 答案 / 解析 / 正文)默认就是 Milkdown 所见即所得(/ 斜杠菜单、选区工具条都在),标题行右侧 Markdown / 源码 一键切换(源码模式就是 markdown 源码框 + 输入助手工具栏);知识点弹窗的 Markdown 模式不占实时预览(源码框整栏通铺、编辑器更宽),切到 源码 才并排显示实时预览 |
| 题目表单底部 | 保存并继续添加(新建时) | 存下这一题、清空表单、继续录下一题 |
| 知识点页 | 编辑 | 弹出可视化表单:标题 + 标签 + 内容(正文 markdown),不用面对 frontmatter;改标题会同时改写 frontmatter 的 title: 与正文里的 # 标题,标签只在「整篇文件就是一个知识点」时出现(多知识点的小节文件里标签属于文件,不在单个知识点上) |
| 小节页 | 编辑 | 抽屉里直接改该小节文件的 markdown |
| 编辑器抽屉 | 插入题目模板(只在题目文件里) | 在当前光标处插入 ## 题目 N 骨架;其它文件没有这个按钮 |
| 编辑器抽屉 | Markdown / 源码 | 默认是所见即所得(Milkdown:标题、加粗、列表、表格、公式、代码块写的时候就是最终样子;/ 斜杠菜单、选区工具条、⌘B / ⌘I 等由编辑器自己管);点「源码」切回「markdown 源码 + 实时预览」左右分栏、抽屉收窄。编辑器自带查找替换面板、图片(链接)弹窗、表格操作、代码块语言选择;标题按层级上色(# 亮白、## 青、### 紫、#### 粉、##### 黄、###### 绿 —— 取的是「配色」那套 --rk-t2..t6,换配色跟着变,和预览 / 思维导图一致,## / ### 还带左侧色条);笔记的 YAML 头在富文本里不显示(抽屉头有「YAML ✓」),要改就在源码模式里改。脚本取不到时直接停在源码模式 |
| 新建小节 / 新建知识点 | 保存 | 抽屉里只有「目录(只读)+ 标题」两个输入框,回车或点保存即创建,随即关掉抽屉(不会自动打开编辑器);新建后可在卡片上点 编辑 再写内容 |
| 编辑器抽屉(源码时)/ 题目表单 / 知识点表单(源码时) | 输入框上方那一排小按钮 | markdown 输入助手:加粗、斜体、行内公式、块级公式、表格、流程图、列表、引用、链接、代码,最右边两个下拉 —— 公式 ▾(公式 / 符号两组)与 模板 ▾(结构 / 笔记 / 题目),点一条插进正文(详见下面「输入助手」) |
| 同上 | 快捷键 | ⌘B 粗体、⌘I 斜体、⌘M 行内公式、⇧⌘M 块级公式、⌘K 链接、⌘E 行内代码、Tab / ⇧Tab 整行缩进反缩进、⌘S 保存;另有一组插件自己实现的编辑键:⌘/Ctrl + Z 撤销、⇧⌘Z / Ctrl + Y 重做、⌘/Ctrl + C 复制、⌘/Ctrl + X 剪切、Ctrl + V 粘贴(⌘V 仍交给系统) |
三个弹窗(新建 / 改名章节、题目表单、知识点表单)只有点「取消」或按
Esc才关闭:点到弹窗外面的灰底不会误关,正在写的内容不会因为手滑点空而丢掉。弹窗里⌘S/Ctrl+S就是保存。
插入图片(落盘,不写 Base64)
编辑器(富文本 / 题目表单 / 知识点表单)里插的图不再写成一长串 Base64,而是交给插件落成真文件:
- 放哪:这篇笔记所属小节旁边,统一收在正文目录下的
.media/里 ——.media/<小节编号>.assestfiles/(例:notes/01-计算机硬件/.media/s0001.assestfiles/)。编号就是插件给每个小节发的s0001号(见「编号(uid)」一节)。中间那层.media/是为了让正文目录里只多一个素材目录,不和.md混在一起;点开头这一条还顺手解决了「素材目录被当成一章」—— 扫描本来就不看点开头的目录,它连判据都不用走。 - 叫什么:
<小节编号>-<序号>.<扩展名>——s0001-1.png、s0001-2.png…… 序号自动往后排,同名不会互相覆盖。 - 笔记里写什么:只写相对路径,例如
;在题目文件(questions/那一侧)里插的图落到同一个素材目录,路径写成../../notes/01-计算机硬件/.media/s0001.assestfiles/s0001-1.png—— 因为相对的是这篇笔记自己的位置。老布局里写的media/…也照旧认得到(认图按后缀找,见「路由」一节),所以旧笔记不改也能显示。 - 显示:卡片 / 思维导图 / 实时预览 / 编辑器都会把这段相对路径换成
/rk-study/media?path=…去取字节,所以写进去立刻能看到图;插件之外(别的 markdown 编辑器、导出、搬走整个库)也照样认,因为它就是普通相对路径。渲染器(client/md.js)把![]()渲染成真的<img>,相对路径→可显示地址的换算挂在面板根节点上统一的那个watchImages里(新插进来的节点也会被就地改写),所以源码模式的实时预览、卡片、详情里都能看到图。 - 入口是 ⌘⇧I:vendor(zt-milkdown)的斜杠菜单在打进 vendor 的这份 build 里没注册语言 / 菜单 spec,
/菜单是关的;插图只有「⌘⇧I 上传文件」和「粘贴」两个口子。 - 插图是两步(选文件 → 插入):选文件那一步一个字节都不写盘 ——
media.upload()同步交回一条blob:本地引用(URL.createObjectURL(file),浏览器自己的临时地址,弹窗拿它new Image()探得到、预览也看得见),文件对象先记在内存里;只有点了「插入图片」(或直接粘贴)之后,图片真进了正文,onChange交回的 markdown 里带着那条blob:时,才由media.settleText()把字节交给 host 落到.media/<小节编号>.assestfiles/,落完把正文里那段换成相对路径。选完就取消、或重新选一张,都不留孤儿图。 imageUpload上有两个必传项(vendor 的默认值都不合用):maxFileSize(默认只让传 5 MB,超限只console.error,粘贴路连提示都没有;现在给 16 MB —— host 那侧/rk-study/media收 24 MB 的 JSON body,base64 要膨胀 4/3)与allowedProtocols: ['blob:'](vendor 在 image 节点上装了协议白名单,只放行http:/https:/mailto:/tel:/data:,名单外的地址会被换成空串 ⇒ 图片节点被 markdown 序列化器静默跳过:文档里看得见图、markdown 里一个字都没有、onChange也永远不触发,落盘那步就永远等不到。vendor 允许调用方追加协议,所以把blob:补进去)。- 写盘收口:
media.toMarkdownSrc(text)把/rk-study/media?…显示地址与还没落盘的blob:换成相对路径,编辑器 / 弹窗的清洗函数各调一次,编辑器保存前再对整段跑一次 strict 收口(源码框里手打的地址也跑不掉;落盘失败时 strict 收口直接把那段图去掉,绝不把blob:写进文件)。 - 删图不删文件:从正文里删掉图片只删 markdown 里那一行,盘上的文件留着(想删就去那个目录删)。名字带序号、只增不改,所以图片可以放心长缓存。
- 支持的格式:
png/jpg/jpeg/gif/webp/avif/bmp/svg,单张上限 24 MB。 - 新建时例外:新建小节 / 知识点时文件还没落盘,此时插图仍是编辑器内置的 Base64;保存之后再插图就走上面这套了(把之前的 Base64 图删掉重插一次即可)。
- 素材目录不会被扫描成章节:新布局的
.media/是点开头的,扫描根本不看它;老布局的media/仍走判据 ——「里面除点开头的东西外全是*.assestfiles目录」(isMediaHome,所以 Finder 顺手丢进来的.DS_Store不会让它变成一章;你真建一个叫media的章节、里面有.md,它照样是章节)。两种布局都不会在画布上多出奇怪的卡片。 - 老布局的
media/会自己搬过来:往一个老小节里第一次插图时,插件顺手把<小节目录>/media/整层搬成<小节目录>/.media/(migrateLegacyMedia),并把notes/、questions/两侧正文里的media/<小节编号>.assestfiles/改成.media/…(rewriteLegacyMediaRefs,只动这一层,字节一个不碰)。目标位置已经存在同名素材目录(那个小节在新布局下已经插过图)时改成逐个文件并过去,同名文件留在原地不动 —— 名字一样就是同一张图,正文里那段路径改成.media/之后照旧点得开。搬完空掉的旧目录摘掉(只删空目录:里面还剩 Finder 的.DS_Store这类文件就留着,扫描反正不看它)。搬不动也不拦着插图。 - 删笔记时素材跟着走:删小节(含连带删掉的知识点 / 题目)⇒ 它那份
.media/<小节编号>.assestfiles/整份跟着进.remove/<桶>/;只删某个知识点 / 题目 ⇒ 只搬「这篇笔记引用、而别处已经不再引用」的那几张(别的笔记还在用的留着),搬完空掉的素材目录顺手清掉(老布局的media/一样认)。详见「删除」一节。
输入助手(快捷键 + 公式模板)
每个 markdown 源码框(编辑器抽屉切到「源码」、题目 / 知识点表单切到「源码」)上方都有一排小按钮,写笔记时不用手打符号 —— 它按光标位置插入,所以富文本模式里不显示(富文本用 / 菜单和选区工具条):
| 按钮 | 插入什么 | 快捷键 |
|---|---|---|
| B / I | 选中文字加粗 / 斜体(没选中就插占位符,光标停在中间) | ⌘B / ⌘I |
| ∑ | 行内公式 $…$ |
⌘M |
| ∫ | 块级公式 $$…$$(单独一段) |
⇧⌘M |
| 表格 | 3×3 markdown 表格骨架 | — |
| 流程图 | ```mermaid + flowchart TD 骨架 |
— |
| 列表 / 引用 / 链接 / 代码 | 无序清单 / > 引用 / [文字](url) / 行内代码 |
— |
| 公式 ▾ | 公式库菜单,四组:公式(行内 / 块级 / 分式 / 求和 / 积分 / 极限 / 根号 / 上标 / 下标 / 方程组 / 矩阵)、希腊字母、关系与运算符、箭头与集合 —— 一条就是一条,点哪个插哪个 | — |
| 模板 ▾ | 其余模板菜单:结构 / 笔记 / 题目 三组,点一条插进正文 | — |
编辑键(撤销 / 重做 / 复制 / 剪切 / 粘贴)也由插件自己实现,因为有些环境(Tauri 打包后的 WKWebView)不把 ⌘C / ⌘V / ⌘X / ⌘Z 交给网页、应用自己的原生菜单又不接管,这四个键就整个失效:
⌘/Ctrl + Z撤销、⇧⌘Z(或Ctrl + Y)重做 —— 走document.execCommand('undo' / 'redo'),用的是浏览器自己那份撤销栈,所以打字、粘贴、输入法上屏都能一步步退。⌘/Ctrl + C复制选中、⌘/Ctrl + X剪切选中 —— 走execCommand('copy' / 'cut'):剪贴板、撤销栈、input事件都和原生一致(受控 textarea 也能同步到 React 状态)。Ctrl + V粘贴 ——execCommand('paste')被浏览器禁掉,只能读navigator.clipboard.readText(),所以只有 Ctrl+V 走插件;⌘V仍交给系统(避免 WKWebView 的权限弹框把本来好用的⌘V弄坏)。- 三条都只在
execCommand返回true时才preventDefault:命令不被支持就原样交回系统,本来能用的环境不受影响。
模板放在两个单独的 markdown 文件里:.templates/公式模板.md(公式 ▾ 菜单)和 .templates/Markdown模板.md(模板 ▾ 菜单)—— 一个文件对应一个菜单,各改各的。模板统一放在学习库根目录的 .templates/(库里所有画布共用这一份,各画布自己不再存);只有自带根目录、不挂在学习库下的画布才放在它自己的 .templates/。老画布原来放在 notes/.templates/ 的继续认(那里有文件就用那里的)。
- 目录名以
.开头,所以它们不会出现在画布上(扫描时跳过点开头的目录),也不会被当成一章。它们在学习库根目录(不在任何画布里,也不在notes/里);面板的⎇ Git 提交是在一级画布(根节点)上按整个学习库提交的(git add -A),所以它们会一起进版本库 —— 除非你自己的.gitignore把它们排除掉。 - 文件格式只有三条规则:
##是分组名,###是模板名,模板名下面紧跟的第一个代码块里的内容就是插入到正文的文本;模板内容本身想带代码块(比如流程图),外面用四个反引号包起来。 - 一条只放一个公式或一个符号:菜单里每条的名字都带着它的 LaTeX 命令(
积分 \int、α \alpha、≤ \le),鼠标停在上面会显示要插入的完整代码,点下去只插这一条 —— 不会一次插一串。 - 想加自己的公式就写进
公式模板.md(照## 公式/## 希腊字母/## 关系与运算符/## 箭头与集合分组放,一条一个###),想加结构骨架就写进Markdown模板.md;保存后回到编辑器点对应菜单里的 重新读取 就能看到(工具栏每次打开时也会重新读一次)。要加第三类菜单得改代码(宿主lib/templates.js的TEMPLATE_FILES)。 - 加一条自己的公式:在文件里照着写
### 名字+ 代码块并保存,回到编辑器点 模板 ▾ → 重新读取 就能看到(工具栏每次打开时也会重新读一次)。 - 某个文件被删了也没关系:那个菜单底部会出现 建模板文件,点一下按内置默认库重新生成它(公式模板 44 条 —— 公式 11 条:行内 / 块级 / 分式 / 求和 / 积分 / 极限 / 根号 / 上标 / 下标 / 方程组 / 矩阵,希腊字母 17 条,关系与运算符 8 条,箭头与集合 8 条;Markdown模板 8 条 —— 结构 4 条:表格 / 流程图 / 无序清单 / 引用块,笔记 2 条:知识点骨架 / 小节骨架,题目 2 条:选择题骨架 / 案例题骨架)。
- 编辑模板文件 在菜单底部,点它直接在抽屉编辑器里打开这个菜单对应的那个文件,改完
⌘S保存(换文件时编辑器会重新挂载,不会残留上一个文件的内容)。
删除(不真删:一律移到当前画布的 .remove/,都有二次确认)
插件里的每个「删除」都是移动:目标被 rename 到当前一级画布根目录下的 .remove/,一次删除 = 在这里新建一个日期桶目录(名字就是当天的 YYYYMMDD,例如 20261004),桶里保留原来的相对路径结构(删掉章节 notes/01-第一章,桶里就是 notes/01-第一章/ 与 questions/01-第一章/)。桶与桶互不相干,所以删两次就留两份,谁也不覆盖谁(同一个章节删两次,第二次进的是新桶,第一次那份原样还在),也不会把不同次的删除混进同一条路径(先删整个章节、之后又删重建章节里的某个知识点 —— 后者进它自己那个新桶,不会落进上次那份章节备份里)。同一天里再删一次,名字往后排成 20261004-2、20261004-3(桶名只到「天」,一天里删几次就有几个桶;文件本身的修改时间由 rename 原样保留,想知道具体几点几分看它就行)。.remove 以点开头,扫描时跳过,所以它不会出现在画布、思维导图或搜索里。要找回:在画布根目录下打开 .remove/,挑日期对得上的那个桶,把东西移回原位即可;rm -rf .remove 就等于真正清空回收站。
编号(uid):每个一级画布与章节都有一个自己的、永不复用的编号,形如 c0001(画布)/ h0007(章节)/ s0012(小节)/ p0031(知识点)。题目是唯一把号写进文件里的(标题下一行的 <!-- rk-uid: q0001 -->,块被删/重排/换位置都跟着这道题走),但这个标记行在解析时会被摘掉,界面上只看到题干、看不到号。编号不写进文件名或目录名(文件怎么排、卡片长什么样一个字都没变),只当身份用:目录类实体(画布 / 章节)的号记在学习库的 .config/rk-study-uids.json 里(号池,就一张表 { "version": 1, "uids": { 绝对路径: 编号 } }),发号计数器 seq 仍跟界面设置一起放在 .config/rk-study.json,跟画布放在哪个目录、叫什么名字无关。删掉之后号不回收:把同名的章节/画布在原地重建,拿到的是新号(旧号只留在它自己的备份里),所以「先删 02 再建一个」不会让两个不同时期的东西共用一个身份。号会跟着实体走 —— 章节改名、画布改名(重命名目录)都是搬号,身份不变;章节被删除或画布被「移出列表」时,被带走的号会连同文件一起写进那个桶里的 .rk-uids.json({"at": …, "uids": {绝对路径: 编号}}),想恢复时认得回来:把目录搬回原位(被移出的画布还要在插件里重新导入一次),下次扫描就会按路径把原来那个号认回来 —— 恢复的是原身份,不是新号;同一个路径在多个桶里都留过号时,以最近一次删除留下的为准。老笔记不用迁移:第一次扫描到没有号的章节就会自动补上;小节与知识点另走一条更省事的路 —— 号就写在 markdown 的 frontmatter 里(uid: s0012),跟着文件内容走,所以改标题、挪位置、连文件名一起改都不丢。没有号的老笔记也不会被改文件:扫描时先把号按路径登记进号池(界面上立刻就有号可用),等这个文件下次被插件保存,号才写进它的 frontmatter,号池里那条按路径记的账同时摘掉(号从此跟着内容走,路径再变也不丢)。插件保存时取号的顺序是:文件里已有的 → 盘上旧文件里的(前端重建头部把 uid 弄丢也能认回来)→ 扫描时登记的号池 → 都没有才发新号;题目文件本身不发号,但每一道题有自己的号 —— 挂在它那个块的标题下一行(<!-- rk-uid: q0001 -->,渲染出来的笔记里看不见;单独一行是必须的,因为重排 ## 题目 N 会重写标题行);改题干、换选项、整段重排都不动它,删掉一道题时标记跟着那段原文一起进 .remove,号同时记进计数器(不再发放)。扫盘结果和接口里也带着号:/rk-study/notes 返回的 chapters / sections / points 每一项都有 uid 字段(章节的号在扫描时补上,小节 / 知识点直接读它文件里的),所以客户端想显示编号可以直接用。号池为什么单独一个文件:rk-study.json 从此只留界面设置(字号、配色、画布清单)与发号计数器 seq,这张随时在长、只有插件自己用得到的号表放旁边 rk-study-uids.json;老版本把 uids 混在 rk-study.json 里的那些库不用手动改 —— 插件照读老键,并在下一次发号 / 认号时把整张表写进号池文件、再把老键从 rk-study.json 里摘掉(一次自动迁移,号一个都不变)。移出列表的墓碑同样待遇:它按库里移出过的画布条数长,也住在同目录自己的文件 rk-study-removed.json 里({ "version": 1, "removed": [绝对路径] }),老版本混在 rk-study.json 里的 removed 照读、第一次写时自动搬过去并把老键摘掉。
| 位置 | 按钮 | 移到 .remove/<桶>/ 里的是什么 |
|---|---|---|
| 章节卡右上角 | 删除整章 | notes/<章>/ 整个目录 + questions/<章>/ 同名题目目录(含其下所有小节 / 知识点 / 题目文件),根目录章节不可删 |
| 小节行 | 删除小节 | 该小节文件 + 该小节下的全部知识点文件(NN-MM-*.md)+ 这些知识点在 questions/ 下的题目文件 |
| 知识点卡片底部 | 删除知识点 | 该知识点文件 + questions/<章>/<同名文件>.md(两侧同步移动) |
| 题目卡片右上角 | 删除此题 | 题目文件本身不动:被删掉的这一段 markdown 另存成 .remove/<桶>/<题目文件路径>.removed-<题号>.md(首行注释写明从哪个文件、第几题删的;同一题删两次就是两个桶里各一份,不覆盖),再重写剩下的题目 |
| 小节页 / 知识点页 / 编辑器 | 删除本文件 | 当前打开的这个文件(笔记文件同样连带移动配对题目文件) |
图也跟着走:笔记里引用的图片素材(.media/<小节编号>.assestfiles/…,老布局的 media/… 一样认)不会留在原地空着 ——
- 删小节(含它底下连带删掉的知识点 / 题目):这一份素材目录属于这个小节,整份跟着进同一个桶,桶里路径照旧(
<桶>/notes/01-第一章/.media/s0001.assestfiles/),恢复时图就在正文旁边; - 只删某个知识点 / 题目:那份素材目录是整个小节共用的,所以只搬「这篇笔记引用、而画布里别的笔记已经不再引用」的那几个文件 —— 还被别处引用的留着(判断就是拿文件名在
notes/与questions/的 markdown 正文里再找一遍,扫不完就一律留着,宁可少搬不多搬); - 搬走之后空掉的
<小节编号>.assestfiles/与它上面那层.media/(老布局是media/)顺手清掉(只删空目录)。 - 删除接口的返回里因此多一个
media字段(这次跟着搬走的素材路径),界面用不到,排查时看得见。
点一次按钮会在原处浮出「确认删除? / 取消 / 删除」,再点「删除」才真正执行。确认条是绝对定位浮层,不占布局 —— 所以列表里的按钮不会因为多出这行字而换行或位移,同一个位置连点两下第二次点到的仍然是「删除」(早先的写法会把按钮挤到下一行、让第二次点空或误点「取消」)。执行后自动回到章节图并刷新,提示条写「已移到 .remove/<桶>/ · <路径>」,并写明连带处理了几个关联文件。
配对规则:
notes/X/Y.md(知识点)与questions/X/Y.md(该知识点的题目)是同一实体的两侧,动任何一侧都会连带处理另一侧;直接操作题目文件(API 的{action:'delete', path:'questions/…'})只动题目文件本身,知识点文件保留。 画布自己也有同类操作:一级画布卡上的 移出列表 是把这个画布目录移到它同层的.remove/里(见下一章)。
回收站(工具条上的 ♻ 回收站:把删掉的东西搬回来)
上面那些「删除」都不真删,东西都在 .remove/<日期桶>/ 里 —— 工具条上的 ♻ 回收站 就是它的界面,而且只有两层有它:
- 根画布(还没进任何画布):列的是被「移出列表」的整只画布。画布目录躺在它上一层目录的
.remove里(学习画布可以散在不同目录),所以这层不是一个目录一只,而是把当前根、它上一层、以及画布列表里每张画布的目录各自上一层都算上(listRootBins),把这些.remove里的桶合起来按日期排;当来源不止一只目录时,桶头会多一行来自 <目录>,免得两个目录下的同名桶看混。恢复时按这条记录自己那只桶所属的目录落回原位(号也认那只目录的号池);恢复好的画布还会自动从「移出列表」的墓碑里放出来、重新登记进画布列表。 - 一级画布(走进某张画布之后):只看这张画布自己的
.remove,并把里面的记录按章并成一条(listChapterBin)——01-第一章一条,点↩ 恢复整章就把这一章(含里面被删过的小节 / 知识点 / 题目片段)整段合并回去(restoreChapter)。理由是你删东西时想找回来的通常是「那一章」本身,而不是散在几个日期桶里的同几个文件;同一章在不同日期删过几次,也都并到这一条上。
面板里每一条显示它原来的路径(按章聚合时就是章名)和它自己的编号(h0007 / s0012 / p0031…),右边一个 ↩ 恢复。恢复就是把它 rename 回原位,编号跟着回去(恢复的是原身份,不是新号)。
题目是内容级删除,桶里存的是一段片段(questions/01-第一章/01-01-知识点.md.removed-2.md,带一行注释记着它从哪个文件、什么时候删的)。题目仓库 questions/<章>/ 与笔记目录 notes/<章>/ 是平行结构,所以在面板上它们并进同一章,点「恢复整章」时一起搬回来;搬回来只是把这个片段文件放回原位旁边(原文件不动),要回到题库里还得自己把内容贴回知识点文件 —— 插件不替你把题目插回去,免得序号 / 编号对不上。片段也带着它那道题的号,面板上看得见 q0007。
原位已经有同名的文件时一律拒绝,绝不覆盖(提示「原位已经有同名的东西,先给它改名或删掉再恢复」),桶里的东西原样不动。按章恢复(以及根画布那层恢复整只画布)走的是合并:原位缺什么就搬回什么,原位已经有的目录往下钻着补,只有原位存在同名文件时才跳过(跳过几条会写在提示里)。恢复干净之后空掉的桶会自己从回收站里消失(.remove 里就剩一个 .rk-uids.json 的话,连空掉的 .remove 一并收掉)。要彻底不要了,rm -rf .remove 就是清空回收站。
老版本留下的 .remove(2025 年那阵子)也认得:那会儿的写法是 .remove/<那条记录当时的相对路径>(例如 .remove/senior-software-architect-review、.remove/notes/01-第一章),目录自己就是被搬走的那条记录,没有日期桶这一层。现在它会在面板上单独归成一只 旧格式 分组(桶名是空的,日期那栏显示「旧格式」),里面的每条记录跟新格式一样能 ↩ 恢复;原位还在的那一层只当路径容器(往下钻着找真正被搬走的那些),所以一整个目录不会因为被误当成桶而拆成一堆假条目。老格式没有「桶」可以整桶合并,所以那一组上的 ↩ 整桶恢复 是一条一条搬回去。
四、画布操作
More in Knowledge & Research
weknora
by tencent
Open-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.
honcho
by plastic-labs
Memory library for building stateful agents
webnovel-writer
by lingfengqaq
A long-form Chinese web-novel writing assistant for Claude Code and DeepSeek Harness, designed to reduce memory loss and hallucinations in serialized projects of up to 2 million characters.
mirage
by strukto-ai
The World's First Virtual Terminal for AI Agents






