dsh-plugin
DayuanJiang/next-ai-draw-iodsh 的 draw.io 绘图插件:通过 next-ai-drawio MCP 服务器作图,点回复里的链接在右侧栏打开实时预览,可以手动修改图,AI 的每次修改都是可以恢复的版本。需 Node.js 18+,首次使用由 npx 下载 MCP 服务器。
把本地 Obsidian 仓库变成专属 RAG 对话面板:侧栏一个完整页面,左侧笔记浏览、中间检索增强对话、右侧引用原文;检索用完全本地的 BM25 加中文 bigram,回答走 DSH 模型通道,\[n] 引用可点击,索引按 mtime 增量更新。
A DeepSeek Harness (DSH) plugin that turns your local Obsidian vault into a dedicated RAG chat panel inside the DSH GUI — a sidebar entry leading to a full three-pane page: note browser on the left, retrieval-augmented chat in the middle, cited note source on the right. The desktop app and the Web GUI ship the same browser-rendered client, so the panel behaves identically in both. Indexing and BM25 matching run 100% locally (no embedding model, no vector database); the optional planner query rewrite and answer generation go through the model channel you already configured in DSH — only your question, the recent conversation and the retrieved snippets are sent, never the vault itself.
Not an MCP integration, not an Obsidian plugin — this is a dual-half DSH plugin (host + browser client). The UI is injected into the DSH main window as a
mainslot page (same mechanism as switching conversations); model calls reuse the hostctx.llm; the knowledge base points at your local vault directory (Obsidian doesn't even need to be running).
Compatibility: checked against a live DeepSeek Harness 44.7.0 install (host ships
@deepseek-ai/dsh-typert-protocol@0.2.1-rc.2/ cordis 4.0.5); the declared peer range>=0.1.5-rc.1still covers it. Since v0.2.5 the browser half additionally pullsreact,react-domand@deepseek-ai/dsh-client-ui-primitivesout of the host's browser module table (that is how the model menu reuses the host's own primitives — the same three modules the sibling plugindsh-forget-sessionalready requires on 44.x); if a profile ever lacks them, the panel page fails to render rather than degrading. Changes after the 44.7.0 check are covered by the repo suite (node --test); the indexing and watcher numbers come from re-runs on a local synthetic 10k-note vault, while the UI batch (composer and model menu) has not had a fresh in-app regression pass.
github_pat_… are matched literally, and meaningful hidden folders (e.g. .workbuddy/) are indexed instead of silently skipped.ModelSelect ported rather than imitated: two-level "Model / Reasoning effort" menu, provider grouping with sticky headers, search once the list passes 4 entries, full keyboard navigation with focus hand-off, an upward-opening portal menu that repositions on scroll and resize, and per-row metadata (free / credits / context window / supported efforts). It shows the host's actual default model instead of a generic "default model" label, and the effort you see is the effort that gets sent. Selections apply to the panel's next message only — a per-message route override, your DSH global settings stay untouched.[n] in the answer and the chips below it open the exact note in the right-hand source pane. Chips are grouped by what the answer actually marked [n] (cited) versus what retrieval surfaced but the answer never cited (related snippets), using the same matcher that renders [n] in the body, and the .md export keeps the same two sections.≈50 ms covers build + commit + stats recompute of one note only: an end-to-end incremental pass still walks the directory and stats every file, which measured ≈0.9–1.0 s on the same vault. The watcher takes the targeted path instead, so a save lands in ≈0.2–0.26 s (it was ≈1.5 s before targeting).Option 1 — dsh-market (in-app, easiest): search the exact package name dsh-obsidian-board in the DSH plugin market and install (searching only obsidian also matches unrelated entries; the market display name is whatever the listing shows).
Option 2 — CLI:
dsh plugin --profile web add "dsh-obsidian-board"
Option 3 — from source (this repo):
dsh plugin --profile web add file:"<path to this repo clone>"
Or manually: add "dsh-obsidian-board": "file:<path>" to dependencies and "dsh-obsidian-board" to dsh.profile.bundles in ~/.dsh/profiles/<profile>/package.json, then run pnpm install in that directory and restart DSH.
Desktop app users: install into the
desktopprofile — swap--profile webfor--profile desktop(and~/.dsh/profiles/webfor~/.dsh/profiles/desktop) in the commands above. Everything else is identical.
Set the vault path in your profile patch (~/.dsh/profiles/<profile>/cordis.patch.yml):
- insert:
- id: dsh-obsidian-board
name: dsh-obsidian-board
config:
vaultPath: "D:\\notes\\MyVault" # vault root (absolute; ~ works too)
provider: "" # DSH llm provider route; empty = host default
model: "" # model id; empty = provider default
topK: 8 # retrieved chunks fed to the answer (only those marked [n] are labelled as citations)
chunkLimit: 1200 # max chars per chunk in the prompt
systemPrompt: "" # custom RAG system prompt (empty = built-in)
vaultPathmay stay empty — the panel shows a setup card on first open where you can discover/pick/paste the vault path interactively.
[1] [2] citations or the chips under the answer (grouped as cited / related snippets) → the note opens on the right.dsh-obsidian-board/
├── lib/
│ ├── index.js # Host half: ObsidianBoardGateway (TypertRemoteService)
│ │ # status/configure/discoverVaults/pickVault/revealVault/
│ │ # listNotes/readNote/search/reindex/chat
│ │ # BM25 runs locally; chat streams via ctx.llm (DSH model channel)
│ ├── typert.js # RPC contract (dual-key codec, 0.1.5-rc.x and 0.1.6+ compatible)
│ ├── vault.js # Zero-dependency Node indexer: scan/frontmatter/BM25/incremental
│ └── client.js # Browser half: main-slot page + sidebar panellist/footer entries
├── cordis.patch.yml
└── locale/*.json, icon.svg
The panel chat does not write to DSH session logs: history is namespaced per vault in the panel and synced to the host via historyGet/historySet, so it survives panel reloads (localStorage as the local fallback). The host-side history is in-memory and cleared on service restart. Model calls go through the host ctx.llm, so quotas, retries, and provider routing behave exactly like your main DSH sessions.
_公网收集, vendor, node_modules) is down-weighted so your own notes win — it is still retrievable, just ranked below your own writing..workbuddy is allow-listed); structural/caching folders (.obsidian, .trash, .git) are always skipped.Config in lib/index.js (covering all fields incl. planner, timeout, scan/watch tuning) — the cordis.patch.yml snippet in this README is only an install template (6 keys); the in-panel configure card can edit every field./ commands and no @ file references — same reason as above.MIT
把本地 Obsidian vault 变成 DeepSeek Harness 里的专属知识库对话页面(桌面端与 Web 端通用):侧栏多一个「Obsidian」入口,点开就是一个完整面板——左侧笔记浏览器、中间 RAG 聊天、右侧引用原文。索引与 BM25 召回全部本地完成,回答走 DSH 已配置的模型通道(只发送问题、最近对话与命中片段,整库不上传)。
不是 MCP 接入,也不是 Obsidian 插件——这是一个 DSH 客户端+宿主双半插件:UI 注入进 DSH 主窗口(
mainslot 页面,与切换对话同构),模型调用复用宿主ctx.llm,知识库指向你本地的 vault 目录(无需 Obsidian 运行)。
兼容性:已在真实安装的 DeepSeek Harness 44.7.0(宿主内置
@deepseek-ai/dsh-typert-protocol@0.2.1-rc.2/ cordis 4.0.5)上做过兼容性核对;声明的 peer 范围>=0.1.5-rc.1继续覆盖。自 v0.2.5 起,客户端半还会从宿主的浏览器模块表里取react、react-dom、@deepseek-ai/dsh-client-ui-primitives三项(模型菜单复用宿主自带 primitives 的代价——同目录的姊妹插件dsh-forget-session在 44.x 上就是按同样方式 require 这三个模块);万一某个 profile 缺这几项,面板页面会直接渲染不出来而不是降级。44.7.0 核对之后的改动由仓库测试(node --test)覆盖,索引与监听的性能数字是本机 10k 合成库复测所得;UI 批次(输入框与模型菜单)未在实机做过一轮完整回归。
github_pat_… 这类长标识符按字面精确匹配、有意义的隐藏目录(如 .workbuddy/)也会纳入索引而非被静默跳过。ModelSelect 移植过来:「模型 / 推理档位」两级菜单、provider 分组 + 吸顶分组头、超过 4 条自动出搜索框、完整键盘导航与焦点回归、向上弹出的 portal 菜单并在滚动/缩放时重新定位、每行带免费/费率/上下文窗口/可用档位信息。未显式选择时显示的是宿主配置的真实默认模型,而不是笼统的「默认模型」;看到的档位就是实际下发的档位。选择只作用于本面板的下一条消息(消息级路由覆盖),不改你在 DSH 的全局默认。[n] 与底部引用 chips 都能点开右栏对应笔记原文。chips 按「正文真的标了 [n]」分成引用与相关片段两组,判据与正文渲染 [n] 用的是同一条正则;导出的 .md 同样分两节写,不把召回一律冒充成引用。方式一——dsh-market(应用内,最简单): 在 DSH 插件市场按精确包名搜 dsh-obsidian-board 安装(只搜 obsidian 会同时命中其他无关条目;市场里的显示名以条目自身为准)。
方式二——CLI:
dsh plugin --profile web add "dsh-obsidian-board"
方式三——从本仓库源码:
dsh plugin --profile web add file:"<本仓库 clone 路径>"
或手动:在 ~/.dsh/profiles/<profile>/package.json 的 dependencies 加 "dsh-obsidian-board": "file:<路径>"、dsh.profile.bundles 加 "dsh-obsidian-board",然后在该目录 pnpm install 并重启 DSH。
桌面端装进
desktopprofile:把上面命令里的--profile web换成--profile desktop(~/.dsh/profiles/web换成~/.dsh/profiles/desktop),其余步骤相同。
编辑 profile 补丁(~/.dsh/profiles/<profile>/cordis.patch.yml)里 dsh-obsidian-board 条目的 config:
- insert:
- id: dsh-obsidian-board
name: dsh-obsidian-board
config:
vaultPath: "D:\\笔记库\\MyVault" # vault 根目录(绝对路径;支持 ~ 开头)
provider: "" # DSH llm provider 路由名;空=宿主默认路由
model: "" # 模型 id;空=provider 默认
topK: 8 # 每次送进回答的召回片段数(正文真标了 [n] 的才算引用)
chunkLimit: 1200 # 单片段最大字符数
systemPrompt: "" # 自定义 RAG 系统提示词(空=内置)
vaultPath 留空也可以:第一次打开面板时会有配置卡,在面板里直接发现/选择/粘贴路径连接。
[1] [2] 引用与底部 chips(引用 / 相关片段两组)可点击 → 右栏打开笔记原文dsh-obsidian-board/
├── lib/
│ ├── index.js # 宿主半:ObsidianBoardGateway(TypertRemoteService)
│ │ # status/configure/discoverVaults/pickVault/revealVault/
│ │ # listNotes/readNote/search/reindex/chat
│ │ # 检索本地 BM25;chat 走 ctx.llm.stream(DSH 模型通道)
│ ├── typert.js # RPC 契约(双键 codec,兼容 0.1.5-rc.x 与 0.1.6+)
│ ├── vault.js # 纯 Node 零依赖索引器:扫描/frontmatter/BM25/增量刷新
│ └── client.js # 客户端半:main slot 页面 + panellist/footer 入口
├── cordis.patch.yml
└── locale/*.json, icon.svg
面板对话不写入 DSH session log:面板历史按仓库隔离并与宿主端 historyGet/historySet 同步(localStorage 兜底),面板重载后仍在;宿主端历史为内存态,服务重启即清。模型调用走宿主 ctx.llm,所以配额、重试、provider 路由与 DSH 主会话完全一致。
_公网收集、vendor、node_modules 等路径)会降权,让你的自有笔记排在前面——不是剔除,真要查这些资料仍可召回,只是排序靠后。.workbuddy 已在白名单);.obsidian、.trash、.git 这类结构/缓存目录始终跳过。lib/index.js 的 Config 为准(含 planner、超时、扫描/监听调优等全部字段)——本 README 里 cordis.patch.yml 片段只是接入模板(仅 6 键);面板内配置卡可编辑全部字段。/ 指令与 @ 文件引用——同上,知识库问答不需要MIT