dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Click any sentence in an AI chat to turn it into a card, then hang the cards into your own knowledge tree. DeepSeek Harness (dsh) plugin + standalone web app. 从对话里把有用的句子挑出来,挂成自己的知识树。

快速开始(macOS / Linux,要 Python 3.11 和 Rust 工具链):
git clone https://github.com/lo2589/knowledge_database.git
git clone https://github.com/lo2589/FastNode.git Node # 底层节点库,必须放在同一层、目录名叫 Node
cd knowledge_database
./setup.sh # 建 .venv、从 ../Node 编 FastNode、装 PDF/Word 读取库
.venv/bin/python -m km --chat # 网页版:左边 Codex 对话,右边知识图
装进 dsh 用:再跑 ./dsh-install.sh,重启 dsh(见第八节)。
跟 agent 聊一下午,真正学到的可能就三五句,混在几百句里,过几天就找不到了。这个工具做的事:
A:… B:… / 1) … 2) … 记录逐条拆。公式、代码、图保持完整。/chat 左边是 Codex 对话、右边是同一张知识图——聊完一段,把有用的句子点进图里。为什么结构要自己挂、不让 AI 自动挂:AI 画的结构图更整齐,但人记不住;自己挂的更乱,记得反而牢。挂的这一下就是学习。
(需求清单、功能对照这类工作笔记留在本地,不随仓库发布。)
┌──────────── dsh 对话 ────────────┬──────────────── 知识库 ────────────────┐
│ 你问:残差学习是什么?… │ 库里有什么 │ 知识图(严格层级树) │
│ 回答(每一句都能点): │ 25 张卡… │ ┌─────┐ │
│ ▍H(x) = F(x) + x ✓已入库 │ 最近入库 │ │ 根 │ │
│ ▍F(x) 是残差函数… ✓已入库 │ 目录(树) │ ┌──┴──┐ ┌──┐ │
│ ▍梯度里天然带着 +1… │ ● Block │ │Block│──│…│ 彩色线=关系 │
│ │ ● 残差… │ └─────┘ └──┘ │
└──────────────────────────────────┴─────────────────────────────────────────┘
dsh-plugin-rightbar)里的「知识图」标签,和别的插件并排住在一栏;没装那个右栏时退回自己贴右边的浮动面板(拖它的左边缘调宽度,宽度记在 km-panel-w)。/api/version 轮询),不用手动刷新。| 动作 | 结果 |
|---|---|
| 点一句 | 这句变成右边知识图里的一张卡,挂在「挂载点」下面;这句标上 ✓ 已入库 |
| 再点已入库的那句 | 不在右边找:直接跳到那张卡(高亮闪一下) |
| Ctrl / ⌘ + 拖一个框 | 框住的句子全部标蓝,下面出现小条:合成一张卡(这些句子合成一张卡,正文按顺序连起来,每句的出处都留着)/ 取消。已经入库的句子自动跳过,Esc 清空选择。多选就是一张卡——框出来的是一块知识,不是一堆卡 |
| 流式回答 | 回答还在生成时不显示可点句子,生成完自动变成可点 |
| 用户消息、追问消息 | 一样逐句可点,来源记的是你自己说的话(user:序号) |
入库时一并记下:会话 id、消息 id、句子在消息里的位置、这句话在第几轮、说话人,以及它回答的那个问题(卡片「原文」里显示的就是这个问题)。
| 控件 | 用法 |
|---|---|
☰ | 展开/收起左边「库里有什么」目录栏(收起后图面占满视野;开合状态按会话记住) |
☷ | 脑图 ⇄ Outliner(一条一条的列表视图)切换,状态记住 |
⌁ | 关系索引:六种关系的颜色、说明和计数 |
+ | 新建卡片:写标题(可留空,自动取正文首句)和正文(支持 Markdown / 公式),然后 挂到当前节点 或 挂到选中的卡下面(后者=在那张卡下写一条子信息,不动挂载点);⌘↵ 等于保存 |
| 搜索框 | 像 Word 的查找:回车 / ↓ 跳下一个,Shift+回车 / ↑ 跳上一个(也可以点旁边的 ↑ ↓),右边显示 3 / 12;被折叠起来的分支会自动打开。Esc 清空。搜的范围:卡片标题、卡片正文、每张卡的「原文」(正文被改掉、合并过,原句照样搜得到)、核对依据、以及导入资料里还没成卡的句子(命中资料句子时,镜头移到左边那一栏并高亮)。大小写、全角半角、前后空格都不影响( FASTNODE / fastnode 都能搜到 fastnode);打多个词就是要求同时命中。折叠起来的分支照样算命中:计数会写「共 3 处命中,其中 3 处在折叠的分支里」,回车跳过去时那条分支会自动展开并把卡闪给你看 |
自适应 | 重新自动排版并把整张图铺开:手动拖到空白处的卡片回到树上,视图缩放到刚好装下全部(缩不到可读尺寸时就停在 0.7 并定位到挂载点)。平时不用它——打开库时画面只对准活跃那一段(见下) |
导出 | 打开导出面板(见第五节) |
| 导入框 | 填路径(单个文件或整个文件夹)或直接粘贴文字,回车即导入;导入的资料出现在图的左边那一栏 |
| 表格 | 表就是表:点它 = 整张表做成一张卡;Ctrl 点某一行(Mac 上 Ctrl+点=右键,也可以 ⌘+点)= 只取那一行(带列名,单独成卡读得懂);⌥ 点某一格 = 只取那一个数据。已经取过的行/格会在表里标绿 |
右边 新知识挂到:X | 当前挂载点。聊天里点的句子都挂到它下面;点它一下,画面回到这一段 |
从左到右:
| 图标 | 作用 |
|---|---|
⌖ | 设为挂载点(聊天里点的句子挂到这张卡下面);当前挂载点会高亮 |
✎ | 改正文(等价于双击卡片):原地变成编辑框 + 实时预览公式,⌘↵ 保存、Esc 取消;原句永远留在「原文」里 |
↗ | 跳到原文(有原文时才出现):左边对话滚到那句话并高亮;跨会话会先打开那个会话;那句还没加载就点对话自己的轮次标记把它翻回来 |
◉n | 看原文:每条原句都带出处,每条后面还有 ↗ |
⌁n | 折叠/展开关系连线(角标是关系条数) |
+ | 新建关系:选关系类型 → 搜另一张卡 → 选中就连上(回车选第一条) |
↵ | 把这张卡和它所有下级按层级写成一段文字,落进左边对话框,你回车就发出去 |
T | 改标题(等价于双击标题) |
⊕ | 融合:点它进入融合态,再去目标卡上点 ↳ 并入这里 |
| (图片) | 见下面「图片」一节:粘、拖、或路径导入,都会进卡片正文 |
−n | 折叠/展开下级(角标是下级数量);等价于点卡片底边中间的小圆圈 |
× | 删除这张卡(点一次就删),它的下级按原顺序接到它的上级下面 |
| 手势 | 作用 |
|---|---|
| 点一下卡片 | 设为挂载点并选中它(选中的卡按 Delete / Backspace 删除,按 回车 写进对话框) |
| 点两下卡片 | 原地改正文(⌘↵ 保存 / Esc 取消) |
| 拖动卡片 | 丢到空白处=就地摆放(位置记下来,下次还在那儿);丢到另一张卡的左右边缘=排到它前面/后面;丢到另一张卡的中间=两次合并成一张;拖到画面边缘会自动滚动 |
| Ctrl / ⌘ 点第一张,再 Ctrl 点第二张 | 第二张挂到第一张下面,并从原来的上级断开(它的下级一起走)。Esc 取消 |
| Ctrl / ⌘ + 拖(空白画布或资料句子) | 拉出一个框,框里的一切合成一张卡:资料句子成为这张卡的正文(每句各自的出处都留着),框里的卡片并进这张卡(正文、原文、下级、关系都跟着走);只框到卡片时,就是原本的「多张并一张」(保留最上面那张)。根节点永远不参与合并 |
| 点一条关系线 | 弹出小面板:改关系类型(下拉)/ × 断开 / ⌕ 关闭 |
选中关系线后按 Delete | 断开这条关系 |
| 滚轮 | 缩放(1×–2.5×);触控板两指滑动=平移 |
| 拖动空白画布 | 平移 |
| 窗口/右栏变宽变窄 | 重新排版(卡片宽度、间距按面板宽度算,很窄时卡片会变窄,保证一层还放得下) |
自适应 才是"把整张图铺开给我看"。新知识挂到:X 点一下,画面立刻回到这一段。⊕+↳ / Ctrl 拉框:正文拼接(留下的在前、并进来的在后)、原文两条都留、下级和所有关系一并转移,卡面直接显示合并后的正文。☰)☷)一条一张卡:▸/▾ 折叠下级、⌖ 设为挂载点、行里是标题 + #id · n 个下级 · 关系摘要、✎ 改正文、T 改标题、× 删除;双击行也是改正文。适合逐条读和重排。
一张图(截图、示意图、公式照片)可以这样进知识库:
| 怎么做 | 结果 |
|---|---|
| 在卡片编辑框里 ⌘V 粘贴 | 图插到光标处,⌘↵ 保存后卡片里就有它 |
| 在画布上 ⌘V 粘贴 | 直接做出一张新图卡(挂在当前挂载点下) |
| 把图片文件拖到某张卡上 | 追加到那张卡的正文末尾 |
| 把图片文件拖到空白画布 | 做出一张新图卡 |
| 导入框里填图片路径(.png/.jpg/.jpeg/.gif/.webp) | 做出一张新图卡 |
| Codex 对话页里点 图片(或直接粘图) | 图发给 Codex(codex exec -i),同时也出现在问题气泡里、可以点进知识图 |
data/images/,按内容命名(同一张图存两份也只有一个文件),卡片正文里留一行 ;渲染、Markdown / PDF 导出、打印版式都带着这张图。× 点一次就删(连带用它做的卡片)。✓ 已成卡;Ctrl 拖框把框住的几句合成一张卡。↗:来自导入资料的,跳到那份资料里的那一句并高亮;来自 dsh 对话的,跳到左边对话的那一句。导出 按钮)点开是一个小面板,选格式后先把全文显示在框里(文件名 / 行数 / 大小都写着),再按 下载文件 或 复制全部:
| 格式 | 内容 |
|---|---|
Markdown 大纲 | 整棵树变成文档:## 1 父卡 / ### 1.1 子卡 层级编号、正文、**原文**(资料):> 原句、相关 → 某卡、核对:对(依据…) |
Mermaid 图 | graph TD:严格层级 + 非层级关系画成带标签虚线 + 核对过的卡带颜色(.mmd) |
Mermaid 图(含正文) | 同上,节点标签里带上卡片正文 |
JSON 数据 | {nodes, structure: {root, entries: {level, parent, order, path}}, refs}——严格层级数据,knowledge_tree_viewer.html 能直接加载并通过校验 |
PDF | 按 A4 打印版式排好的一棵树(标题、正文、原文引用、关系、核对徽章、公式、代码),点了直接下载 .pdf(几秒钟) |
面板底部还有 打印 / 另存为 PDF:把同一个打印版式开在新标签页里,用系统打印对话框「另存为 PDF」。没有 Chrome / Chromium / Edge 时,点 PDF 会自动退到这条路,并说明原因。
服务端对应:GET /api/export?fmt=markdown|mermaid|mermaid-full|json、GET /api/pdf、GET /print(打印页)。
/chat)不经过 dsh,直接在浏览器里:
http://127.0.0.1:8795/chat
codex exec --json(桌面版自带,或用 KM_CODEX=/path/to/codex 指定),所以用的是你已经登录的账号和 ~/.codex/config.toml 里的模型,不用再配一遍 key。read-only,Codex 能读代码、能跑只读命令,但不会改你的文件;要放开就 KM_CODEX_SANDBOX=workspace-write。codex exec -i,图上还会出现在问题气泡里、可以点进知识图。同样支持:Ctrl/⌘ 拖框选多句 → 合成一张卡、已经入库的句子标 ✓ 已入库 再点就跳回那张卡、卡片上的 ↗ 跳回左边那句原文并高亮、思考过程折起来、跑了哪些命令、token 用量。data/chats/<对话 id>.json(线程 id、目录、每一轮的问答),和卡片所在的库分开存——关掉浏览器再回来,两边都还在。需要:Python 3.11、Rust 工具链(cargo,setup.sh 用 maturin 现编 FastNode)、FastNode 源码放在同级目录 Node:
git clone https://github.com/lo2589/FastNode.git ../Node # 只需一次;或用 FASTNODE_DIR=/别处/FastNode ./setup.sh
./setup.sh # Python 环境 + FastNode + 读 PDF/Word 的库
./dsh-install.sh # 装进 ~/.dsh/profiles/web(先备份 package.json);装完重启 dsh
重启 dsh 之后,右栏会出现「知识图」标签;插件会自己用 .venv 的 Python 起知识库服务(默认 8795 端口,被占就往后找),并轮流探活、挂了自动拉起。同一个服务也提供上面第六节的网页版 /chat,不装 dsh 一样能开。
不想装 dsh 也能单独开一个库看(没有 dsh 对话,只能看图和导入):
.venv/bin/python -m km --open # 按会话分库(默认 data/repos)
.venv/bin/python -m km --db data/repos/某个库.db --open # 只看这一个文件
python -m km 的参数:--port(默认 8790)、--repos(按会话分库的文件夹)、--db(只服务这一个库文件)、--open(启动后开白板)、--chat(启动后直接开网页版的 Codex 对话页)。
卸载:./dsh-install.sh remove。
别
pip install fastnode:PyPI 上那个同名包跟本项目无关。FastNode 只从 lo2589/FastNode 源码编。
PDF 直接用本机浏览器渲染。想指定用哪个:
KM_CHROME=/path/to/chrome。
没有默认库,也没有仓库切换。 白板永远只显示当前会话自己的那个库(data/repos/会话-<标题>-<尾号>.db):会话第一次打开时建好,以后回到这个会话还是它。别的会话的库不会出现在这里,也拿不到——请求不带会话 id 时服务端直接拒绝(这个白板只属于会话…)。
绑定关系写在 data/repos/repos.json 的 sessions 里(会话 id → 库文件)。想换机器或备份,整个 data/repos/ 拷走即可。
导入框里填路径(文件或文件夹),或者直接粘贴文字:
| 来源 | 说明 |
|---|---|
| 粘贴文字 / Markdown / 网页内容 | 直接粘进导入框 |
| 文件夹 / 代码仓库里的文档 | 填文件夹路径:递归收 .md .markdown .txt .tex .rst .html .htm .pdf .docx .ipynb,自动跳过 .git、node_modules、.venv、build、dist、target 等,最多 300 份、单份 20MB |
| 单个文件 | .md .txt .tex .rst .html .pdf .docx .ipynb |
| ChatGPT / Claude.ai 导出的 json | 填 .json 文件路径(按当前分支取,不把所有分支混在一起) |
| Claude Code 会话 | 填 ~/.claude/projects/**/*.jsonl 路径(GET /api/claude-sessions 能列出最近的) |
网页里 KaTeX / MathJax 渲染过的公式会还原成 TeX;Jupyter 的 markdown 单元原样、代码单元带语言标记;PDF 抽文字、docx 转 Markdown。
$…$、$$…$$、\(…\)、\[…\]、\begin{align}…、矩阵、```math、化学式 \ce{H2O};$5 和 $10、$HOME/bin:$PATH 这种不会被误当成公式;MAX_W),还放不下就整条等比缩小(不低于 55%,再往下横向滚动并留滚动条);每次排版后页面自己复查一遍,把「没显示全」的公式报给服务端(data/repos/selfcheck.json),所以被切掉的公式不会悄悄混过去。显示用的库(KaTeX、markdown-it、highlight.js、DOMPurify)都在 km/web/vendor/,断网也能用。
| 关系 | 读法 | 画法 |
|---|---|---|
| 属于 | A 属于 B(B 是 A 的上一级)。每张卡只有一个上级,组成层级树 | 灰色树线 |
| 前提是 | 先懂 B 才能懂 A | 橙 |
| 是…的例子 | A 是 B 的例子 | 绿 |
| 细化了 | A 把 B 讲细了 | 紫 |
| 矛盾 | A 和 B 说的对不上(比如 LLM 前后说法不一) | 红 |
| 相关 | 有关系但说不清是哪种 | 灰点线 |
| 正文提到 | 卡片正文里写了 [[B 的标题]],自动生成 | 灰虚线 |
正文里的链接:[[标题]]、[[标题|显示的字]]、[[#12]](按 id)。改名后别处的引用自动跟着改;先写了 [[还没有的卡]],等那张卡建好会自动连上;点一下链接就跳到那张卡。
0, 1, 2…;check_structure),不合格直接报错,不会画出坏图。底层是 FastNode(克隆在同级目录 Node,SQLite 上的节点库):
source 导入的一份资料
unit 拆出来的一句 / 一块 unit -in_source-> source
card 一张知识卡片 card -from_unit-> unit (出处)
card -belongs_to-> card (层级,唯一)
card -<其他关系>-> card (六种语义关系)
card -mentions-> card (正文 [[ ]] 自动维护)
卡片额外的属性:check / check_note(核对)、pos(同级顺序)、x / y(手动摆放,null 表示回到自动排版)。来源(source)上记着 dsh_session / dsh_message / dsh_turn,原文跳转就靠它们。
用 FastNode 自己的命令行也能读:../Node/target/release/fastnode data/repos/你的库.db stats。
.venv/bin/python -m unittest discover -s tests -v # 76 项:拆句 / 导入 / 存储 / 层级 / 接口 / 五种导出 + PDF
node --test dsh-plugin-known-manage/test/host.test.js \
dsh-plugin-known-manage/test/pick.test.js # 8 项:读会话、去系统注入、公式原样;选句把「第几轮」带进库;一次入库多句(真起一个知识库服务跑)
cd ../deepseek-harness && node --import tsx/esm \
../known_manage/tests/slot-rightbar.mjs # 插件进右栏「知识图」标签(没右栏时退回浮动面板)
tests/test_layout.py(7 项)是在白板自己身上量的,跑起来需要一个带 Chromium 的 Playwright;环境里没有就整文件跳过,不会假装通过:
| 检查 | 量的是什么 |
|---|---|
| 一层排不下就折行 | 一层 14 个兄弟、全部展开后画布宽度 ≤ 4200 像素(不折行的话是 4 536 像素一排) |
| 活跃节点和子节点完整 | 把取景对准活跃分支后,活跃那张卡和它的每一个子节点都整张在画面里 |
| 拖动停在墙上 | 往右下拖 3 200 像素,卡片位移不超过那面墙 |
| 远处的坐标被拉回 | 手动摆到 (8000, 6000) 的卡片,下次打开回到树上,服务端坐标被清空 |
| 折叠卡交代下面有什么 | 折叠的卡片上有汇总条目,点一条那张卡就出来 |
| 画面外留接字 | 把画面拖开后四边出现接字(带张数),点一下那张卡进画面 |
| 一屏有上限 | 400 张卡的树里,同时画出来的卡片不超过 140 张 |
界面上的关键动作都在真实 dsh 里点过(Playwright 驱动,含截图):逐句入库、框选批量入库、原文翻页跳转、导出面板(含拿到 .pdf)、打印页、窄栏排版与状态保持、折叠汇总条跳转、接字带人过去。
调试用的落盘证据:data/requests.log(每个请求一行,KM_REQLOG=off 可关)、data/repos/diag.json(页面自报的右栏几何和 JS 报错)、data/repos/selfcheck.json(没显示全的公式)。
km/split.py 拆句子 / 块(标点、块、表格、编号记录;公式代码图不拆)
km/importers.py 各种格式 → Markdown(md/txt/tex/rst/html/pdf/docx/ipynb/json/jsonl/文件夹)
km/store.py 卡片、关系、严格层级、核对、合并、Markdown / Mermaid / JSON 导出(FastNode)
km/repos.py 会话各自的库(一个会话一个库,没有默认库)
km/chat.py 把 codex exec --json 驱动成网页里的对话(事件流 → 页面能画的东西)
km/chats.py 每个 Codex 对话一条记录(线程 id、目录、每轮问答)
data/images/ 粘进卡片的图片(按内容命名;data/ 不进仓库)
km/pdf.py 用本机浏览器把打印页印成 PDF
km/server.py 本机 HTTP 接口 + 静态页面
km/__main__.py python -m km --port/--repos/--db/--open
km/web/index.html 白板页面
km/web/graph.js 白板交互(折行排版、折叠汇总、接字、拖拽、框选、编辑、关系、搜索、导出面板、状态保持)
km/web/render.js Markdown + KaTeX + 代码高亮渲染
km/web/graph.css 白板样式
km/web/print.* 打印版式 / PDF 用的那一页(print.html + print.js + print.css)
km/web/chat.* 网页版:左边 Codex 对话 + 右边知识图(chat.html + chat.js + chat.css)
km/web/vendor/ KaTeX / markdown-it / highlight.js / DOMPurify(本地,断网可用)
dsh-plugin-known-manage/
src/host.js dsh 宿主半边:起知识库服务、读会话文件、/plugins/known-manage/*
src/client.js dsh 页面半边:右栏「知识图」标签、逐句可点的回答、框选入库、原文跳转、写进对话框
cordis.patch.yml 插件挂载点
test/ node --test 用的测试
tests/ Python 单测(test_km.py)+ 白板几何检查(test_layout.py,要 Playwright)+ 右栏 slot 测试
127.0.0.1,库相关的一律要带 ?s=<会话 id>)GET /api/canvas 一次读全:卡片、层级、原文、关系、挂载点、资料列表(白板就用这一个)
GET /api/structure 严格层级结构 + refs(导出 JSON 用)
GET /api/tree /api/board /api/graph 树的骨架 / 画布数据 / 极简图
GET /api/meta 关系与核对状态的名字、统计、库名
GET /api/export?fmt=… markdown | mermaid | mermaid-full | json
GET /api/mermaid 只取 Mermaid 图(严格的层级 + 语义关系),不带别的东西
GET /api/pdf 浏览器渲染的 A4 PDF(字节流,带下载文件名)
GET /print 打印版式页面(/api/pdf 和「另存为 PDF」用的就是它)
GET /chat 网页版:Codex 对话 + 知识图(km/web/chat.*)
POST /api/images 收一张图(粘/拖来的 base64,或本机路径)→ 存成 /images/xxx.png
GET /images/<名字> 取回那张图(名字限定在图片目录里)
POST /api/chat 跑一轮 Codex,把事件流一行一个 JSON 地推回来(NDJSON)
GET /api/chat/<id> 某个对话的线程、目录和每一轮
GET /api/chats 最近对话(网页版的「最近」)
POST /api/pick 一句话入库(origin:kind=dsh|codex|claude + session/message/turn/…)
POST /api/pick-many 一批句子入库(merge=true 时合成一张)
GET /api/picked?message=… 这条消息里哪些句子已经是卡片
GET /api/target POST /api/target 读 / 设挂载点
GET /api/cards?q=… POST /api/cards 搜卡 / 新建卡
GET /api/cards/<id> PATCH DELETE 读 / 改标题正文 / 删(下级接到上级下)
POST /api/cards/merge 融合两张卡(正文、原文、关系都保留)
POST /api/cards/<id>/move 改上级 / 调同级顺序
POST /api/cards/<id>/place 手动摆放在 x,y(null 就是回到自动排版)
POST /api/cards/<id>/check 核对状态 + 依据
POST /api/links PATCH DELETE 连 / 改关系类型 / 断开
GET /api/sources POST 资料列表 / 导入(text|path|folder|claude_session|file_b64|messages)
PATCH /api/sources/<id> DELETE 改标题 / 删(连它做的卡一起删)
GET /api/sources/<id>/units 这份资料的句子
PATCH /api/units/<id> POST /api/units/merge 改句子 / 合并相邻句
POST /api/split 只拆句、不碰库(对话页面用它把回答切开)
GET /api/claude-sessions 最近的本机 Claude Code 会话
GET /api/version 页面自己的版本(改了文件就自动重载)
POST /api/selfcheck /api/diag 公式自查报告 / 页面自报几何与报错(只落盘,不影响画图)
dsh 插件自己的路由(由宿主半边提供):/plugins/known-manage/status | split | pick | pick-many | picked | session。