在 DSH 对话中搜索、读取并安全读写用户自己的 Outline 知识库文档,写操作受白名单保护与审批约束。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:huangfuren/dsh-outline
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
DeepSeek Harness 的 Outline 插件:在对话中搜索、读取并在用户审批后创建、更新或删除文档。插件只连接用户配置的 Outline 实例,不携带任何组织内部地址、token、集合名或文档内容。
当前版本:0.9.1。支持的 DeepSeek Harness 基线为
0.1.5-rc.2(设置卡片依赖settings.installSection),Node.js 需要 22.19 或更高版本;原生支持 Windows / macOS / Linux 三大平台,经过全量跨平台兼容性测试(233 个单元测试 + 端到端冒烟)。
功能
- 搜索、读取、统计文档,并返回可点击的 Outline 链接;支持按作者姓名/邮箱过滤(服务端下推),命中附带作者名。
outline_context_search直接返回命中文档的摘要原文(正文前 800 字),可一步引用作答,不必再逐篇调outline_get_document;摘要并发拉取(≤4)并复用 60s 文档缓存。- 健壮性:429 限流自动重试(指数退避,最多 3 次);公网地址强制 HTTPS(localhost 与内网私有地址除外);读取缓存 TTL 可配置(
cacheTtlMs,默认 60s)且带条目上限。 - 列出集合、解析“集合/目录/子目录”路径、列出直接子文档。
- 提供通用需求文档模板。
- 创建、更新和删除属于写操作,每次执行前需要用户审批;删除还需要第二次确认。
- 设置卡片位于 设置 -> 插件 -> 插件配置;插件状态位于 设置 -> 插件 -> 插件列表。
- 未配置 Outline 地址或 token 时,插件仍可启动,工具会返回配置提示。
Outline 版本兼容
插件只调用 8 个核心端点(documents.search|list|info|create|update|delete、collections.list、users.list),它们的请求与响应形态从 v0.79 到 v1.12 没有变过。跨版本会变的是几个请求参数,插件在运行期适配,而不是绑定某一版的写法:
| 能力 | v0.79 – v1.8 | v1.9 – v1.11 | v1.12+ |
|---|---|---|---|
| 追加正文 | append: true |
editMode: "append" |
editMode: "append" |
| 集合 / 作者过滤 | 顶层 collectionId / userId |
同左(已标弃用) | filters 数组,与旧参数互斥 |
时间过滤(updatedAfter) |
服务端不支持 | 服务端不支持 | filters + updatedAt + gte |
具体处理方式:
- 追加同时发两个键:带
append: true时,请求体同时含append: true与editMode: "append"。老版本丢弃editMode用append;新版本把append转成editMode后删除。只发其中一个,会在另一侧静默退化成整篇覆盖——不报错、正文被替换,所以两个都发。 - 时间过滤按实例探测一次:用一次「未来时间点」的
documents.list判断实例是否认filters(返回空 = 认,返回真实总数 = 字段被丢弃)。认的实例把过滤下推到服务端并返回timeFilterMode: "server";不认的实例对取回的那一页本地筛选并返回timeFilterMode: "client";关键词为空时改走documents.list(天然按updatedAt降序)扫到时间边界即停,返回timeFilterMode: "list",结果精确且只需一次请求。老版本服务端根本没有updatedAfter这个参数——它在任何 Outline 版本里都不存在,没有可发的东西。 - 集合 / 作者过滤继续用顶层参数,各版本都接受。1.12+ 标了弃用但没移除;只有同时要求时间过滤时才走
filters路径,因为服务端拒绝两者并存。
安装
推荐:DSH 管理安装
从公开 GitHub 仓库安装,并固定到最新发布 tag:
dsh plugin --profile web add git+https://github.com/huangfuren/dsh-outline.git#v0.9.1
#v0.9.1 后缀固定到该发布版本;去掉后缀则跟随 main 分支最新提交。
安装后重启 dsh web。发布包已经包含编译后的 lib/,正常从 Git 安装时不依赖用户本地构建。本包不再包含任何安装生命周期脚本:早期版本带的 postinstall 清理钩子会触发 pnpm 的构建脚本审批(ERR_PNPM_IGNORED_BUILDS),导致桌面版等新 surface 的安装被中断。
交给 AI 安装时,只使用上面的 DSH 插件管理命令,不要再手动追加 cordis.patch.yml 或编辑 dsh.profile.bundles。如果启动错误指向其他插件,应单独修复或禁用错误中点名的插件。
本地 checkout 或解压后的目录可以使用:
dsh plugin --profile web add link:/absolute/path/to/dsh-outline
分发压缩包必须包含 package.json、lib/index.js、client.js、cordis.patch.yml 和 dsh.plugin.json;构建前先执行:
pnpm build
旧版热安装脚本
scripts/hot-install.mjs 只建议用于本地开发。它会创建 profile 链接并追加 patch 行,公开分发不要把它作为标准安装方式。
启动失败恢复
dsh plugin --profile <profile> why dsh-outline
<profile> 填你实际使用的 profile 名(网页版通常是 web,桌面版是 desktop)。
如果报无法解析 dsh-outline-ai,说明该 profile 的 package.json 或 cordis.patch.yml 里还留着 0.8.0 之前的旧包名。本包已不再带自动迁移脚本,请手工删掉那些旧行,再重新安装本包并重启。
如果安装报 ERR_PNPM_IGNORED_BUILDS 或 allowBuilds: ... set this to true or false,说明是旧版本包残留的 postinstall 钩子所致。升级到 v0.8.2 及以后即可(该钩子已移除);同时可以把 profile 的 pnpm-workspace.yaml 里那条待决的 allowBuilds 行删掉。
如果插件已加载但看不到卡片,重启 dsh web,先在插件列表确认 dsh-outline,再打开插件配置。宿主条目失败时不会注册 settings 命名空间。
配置
推荐在 设置 -> 插件 -> 插件配置 中填写:
| 字段 | 说明 |
|---|---|
| Service URL | Outline 实例根地址,例如 https://outline.example.com |
| API Token | 在 Outline 的 API keys 页面创建 |
| 可写目录(留空 = 只读) | 逗号分隔的目录路径,如 集合A,集合B/目录1;仅这些目录及其全部子级允许写入 |
| 同义词表(仅配置行) | 插件配置行 synonyms(YAML 映射,如 synonyms: { 部署: [上线, 发布] }):搜索零命中时按"原词 → 首词 → 同义词"阶梯自动重试 |
也可以使用环境变量 OUTLINE_BASE_URL 和 OUTLINE_API_TOKEN,或在 cordis.patch.yml 的插件配置行中设置。公开包不得把内部集合名写入 schema 默认值、界面文案、测试数据或示例 URL。
v0.3.0 默认只读:未配置可写目录时,所有写工具(outline_create / outline_update_document / outline_delete)直接拒绝执行,连审批弹窗都不会出现。要允许写入,需列出可写的目录:集合B/目录1 覆盖该目录及其全部子级,单独的 集合A 覆盖整个集合。目标路径解析失败(集合不存在、目录不可见、文档被移动)一律拒绝——写入永远 fail-closed。
从 0.2.x 升级:0.3.0 用 writablePaths 白名单取代了 protectedCollections 黑名单。升级后未配置可写目录前所有写入都会被拒绝;之前用黑名单保护的集合,只需不把它列入 writablePaths(未列出 = 不可写)。请删除插件配置行里的 protectedCollections,并把 writablePaths 设为实际要写入的目录。
跨平台兼容性
本插件经过全面测试,原生支持 Windows、macOS 和 Linux 三大平台。所有关键代码路径均采用平台无关的实现模式,无需用户手动配置或额外适配。
Windows 兼容性亮点
- ✅ 自动处理反斜杠输入习惯:在「可写目录」和「路径解析」功能中,用户输入
集合A\目录1(使用 Windows 标准的反斜杠)会被自动归一化为集合A/目录1,避免误判。 - ✅ 文件名安全化:本地保存时自动替换文件系统非法字符(
\ / : * ? " < > |),并保护 Windows 保留设备名(CON、NUL、COM1-9、LPT1-9)不被误用。 - ✅ MAX_PATH 路径长度保护:在 Windows 默认路径限制(260 字符)下,超长文档标题会被自动截断到安全长度(保留
.md扩展名),确保不会因路径过长导致保存失败。 - ✅ 错误提示可操作:文件系统错误(
ENOENT、EACCES、ENOSPC等)会翻译为用户可理解的中文提示,并根据平台给出针对性建议(例如 Windows 提示"路径过长",macOS 提示"目录不存在")。 - ✅ 环境变量回退链:
$DSH_HOME→$USERPROFILE→$HOME→ 当前工作目录,自动适配 Windows 用户主目录位置。
macOS / Linux 兼容性亮点
- ✅ IPv6 回环地址支持:
http://[::1]:3000形式的本地 IPv6 地址被正确识别为私有地址,不会误拒。 - ✅ 大小写不敏感文件系统:APFS(macOS 默认)和 ext4(Linux 可选)的 case-insensitive 模式下,文件去重逻辑正确处理大小写差异,不会产生冲突。
- ✅ LF/CRLF 行尾透明:Markdown 内容始终使用 LF(
\n),跨平台打开无显示异常。 - ✅ UTF-8 Unicode 规范化:支持 NFD(macOS)和 NFC(Windows/Linux)两种 Unicode 规范化形式的文件名,emoji 与 CJK 字符均可正常保存。
- ✅ POSIX 路径限制:macOS 和 Linux 的路径长度限制(通常 1024+ 字符)远高于 Windows,无需截断保护。
已知边界情况(非缺陷)
| 场景 | 行为 | 影响 |
|---|---|---|
| macOS 大小写不敏感 | Test.md 与 test.md 被视为同一文件,去重时会生成 test-2.md |
✅ 设计如此,避免覆盖 |
| Windows MAX_PATH 260 | 超长标题被自动截断到约 100-150 个中文字符 | ✅ 保护机制生效 |
| Legacy 记事本 | Windows 10 之前的记事本打开 LF 文件显示异常 | ⚠️ 请使用 VS Code / Notepad++ |
| iOS / Android | 不支持(Node.js 22.19+ 无法在移动系统运行) | ⚠️ 请使用 macOS/Windows/Linux 桌面系统 |
兼容性与发布检查
- 使用 DSH
0.1.5-rc.2或更高的同一兼容范围测试;更早版本既没有settings.installSection,也没有客户端注入兼容保证。 - 执行
pnpm typecheck、pnpm build、pnpm test(233 个单元测试,包含跨平台边界用例)和node scripts/smoke.mjs(端到端集成测试)。 - 压缩包排除
node_modules、.git、settings 文件、token、内部地址和内部文档名称。 - 在干净的
webprofile 中安装 GitHub 地址或压缩包,确认插件列表和插件配置两个入口都可见。 - 发布前搜索整个发布目录中的组织专属名称;检查失败就停止发布。
工具
outline_search、outline_context_search、outline_get_document、outline_count、outline_list_collections、outline_list_users、outline_resolve_path、outline_list_children、outline_doc_template、outline_save_local、outline_create、outline_update_document 和 outline_delete。
按时间检索(最近更新了什么)
- 问「今天/本周更新了哪些文档」时,给
outline_search传 空字符串 query +updatedAfter: 插件改走documents.list(天然按updatedAt降序)扫到时间边界即停,结果精确且通常一次请求完成。 - 空 query 时返回
timeFilterMode: "list";truncated: true表示达到单次上限还有更早文档, 按提示传offset续取即可。 - 带关键词时仍走关键词检索(相关度优先),此时的时间过滤在 Outline 1.12+ 下推服务端,
更老的版本只能对取回的候选本地筛选(
timeFilterMode: "client",覆盖有限)。
作者过滤(outline_list_users + outline_search 的 author)
- 想找"某人写的文档"时,先调
outline_list_users拿到成员 id/姓名/邮箱。 - 或直接给
outline_search传author=姓名/邮箱:插件会先outline_list_users解析(精确唯一→直接用、多匹配→返回候选列表让你确认、无匹配→提示"未找到"),再把userId下推到 Outline 服务端过滤——比盲搜后人工挑更高效、更省 token。 - 搜索命中会附带作者名(如
(作者:张三),实例未返回或 users.list 不可用时缺省)。
检索效率与准确度(v0.7.0)
- 搜索缓存:相同关键词(含过滤参数)短 TTL 缓存,同问不重打 API;增删改文档后自动失效。
all=true抓全:需要"列出全部相关文档"时让 AI 传all=true,插件自动翻页(上限 100 篇)并跨页去重;服务端无视 offset 时自动停,不会死循环。- 本地重排:服务端排序基础上叠加——标题命中权重高于摘要命中,一年内更新的文档有新近度加成(同分保持服务端原序)。
- 零命中回退阶梯:原词 → 首词(多词查询 AND 易落空)→ 同义词表变体(配置
synonyms),命中即停并标注实际生效词。 - 翻页提示:结果未显示完时尾部提示可用
offset/all继续获取。
本地保存(outline_save_local)
search / get_document 的结果末尾会多一段提示:是否把本次输出整理成 Markdown 文件存到本地,并给出实际存放目录。
- 默认目录:
$DSH_HOME/outline-auto-saves(无DSH_HOME时回退$HOME/outline-auto-saves)。 - 可在 设置 → 插件 → 插件配置 → Outline 知识库 卡片的「本地保存目录」中改成任意绝对路径(修改后需重启 web profile)。
- 用户在对话里回复"保存"后,AI 收集相关文档的
id调用outline_save_local(参数ids=文档id列表,逗号分隔,最多 50 篇):- 单篇 → 存为
YYYY-MM-DD-标题.md; - 多篇 → 合并为一个带目录的 Markdown(
首篇标题等N篇.md)。 - 同名文件自动追加序号
-2、-3… 不覆盖。
- 单篇 → 存为
- 该能力只写本地磁盘,不会向 Outline 知识库写入任何内容。
- 落盘目录有一层安全带:磁盘根(
C:\)、文件系统根(/)、共享根(\\server\share)与已知系统目录(C:\Windows、C:\Program Files、/etc、/usr等)一律拒绝。判定在折叠./..之后**进行(配置写成D:/saves/../..也挡得住),系统目录按盘符无关**比对(Windows 装在非 C 盘同样生效)。这只是防呆,不是沙箱 —— 真正的边界仍是文件系统权限。
写入与长文档(outline_create / outline_update_document / outline_delete)
text是整体替换:outline_update_document会用它覆盖正文,必须传完整内容。只想追加请传append: true(Outline 原生追加语义,不覆盖原文)。- 截断护栏:
outline_get_document默认只返回前 20000 字符。若把这份截断结果原样写回(新正文是原文的精确前缀,或恰好等于默认上限),审批文案会明确列出「原文 N 字符 → 写回 M 字符,将永久丢失 K 字符」并给出补救办法,由你带数据确认。outline_get_document的截断提示也会直接写明"不要交给 update 写回"。 - 未知参数一律拒绝:宿主对工具参数不强制封闭(未声明的键会被静默放行),因此本插件在写工具入口自查并报错 —— 避免出现「传了参数、返回成功、变更其实没生效」。
publish:outline_create与outline_update_document都接受publish,可显式发布或把文档转为草稿。实例未返回发布状态时,工具会如实说明"服务端未返回发布状态",不会把草稿报成已发布。
安全
所有写操作都要经过 DSH 原生审批与按部署配置的可写目录白名单,两者均 fail-closed:审批服务不可用、闸门内部异常、目标路径无法解析,一律拒绝而不是放行。此外还注册了宿主的单调守卫(ctx.tools.guard)作为地板:它不是可重排的 tools/pre-execute waterfall,任何监听器都无法把它的拒绝翻盘,因此即使闸被别的插件短路、或闸压根没装成,写调用仍会被拒绝。公开实例必须使用 HTTPS(本机回环与内网私网地址豁免),API token 只保存在 DSH 设置层,不会出现在工具返回值、日志或浏览器端;outline_delete 需要二次确认(第二次弹窗同样接入调用方 signal,取消本轮即中止),并且只有服务端明确返回成功标记时才报告"已删除",无法确认时如实报错而不是谎报成功。本地 Markdown 落盘被限制在配置的保存目录内,并按平台做了文件名与路径长度加固。
审批策略设为"永不询问"时,写操作会全部被拒绝。 这是 DSH 的 designed fail-closed 行为(无审批可用即拒绝),不是插件故障。如需写入,请把审批策略调回"询问"。
完整的威胁模型与漏洞上报方式见 SECURITY.md。
开发
pnpm typecheck
pnpm build
pnpm test
node scripts/smoke.mjs
真实 Outline 验证脚本需要环境变量 OUTLINE_BASE_URL 和 OUTLINE_API_TOKEN。token 只通过环境变量或用户本机 settings 传入,不要写入仓库。
License
链接
同类插件
tt-a1i/archify#integrations/deepseek-harness★ 92724
从仓库或系统描述生成经过校验的自包含交互式架构图、流程图、时序图、数据流图和生命周期图。
dream-num/dsh-univer-office★ 657
为 DeepSeek Harness 打造一个真正的办公环境。Univer Office 插件将电子表格、文档、幻灯片、画布、多维表格等汇聚到同一个运行时——数据互联、修改经过校验、变更按版本管理,并以隔离工作树支持多 Agent 协作。
ECNU/EduWork#dsh-knowledge-studio★ 275
基于工作区资料的 Studio,复用 DSH 模型与共享成果服务,制作报告、演示文稿、表格、思维导图、测验、闪卡及音视频。Office 生成需 Python 3.12+ 及相关依赖,并配置 DSH_OFFICE_PYTHON;媒体渲染需 Chromium;本地语音转写另需 whisper.cpp 和模型。
PerryLink/dsh-industry-research★ 215
面向 DeepSeek Harness 的确定性行业研究报告:公司与行业研究流程基于分阶段证据产出结构化、可核验的报告。
HuanLinOTO/dsh-plugin-mineru★ 51
向模型暴露 MineRU 文档解析工具。
PolinniZhong/dsh-knit★ 48
把会话工作区里已有的 Markdown 文档、源码、图片与视频列进 DSH 侧边栏,按与当前对话的相关性排序。默认的词法模式用最近几条消息在本地与标题、摘要、正文做带 IDF 加权的匹配(BM25)—— 不调用模型、没有网络出口,内容不出本机。列表来自工作区扫描,而不是「最近打开记录」,所以重启 DSH 或新开会话都不会变空。排序结果组织成主要 / 辅助 / 相关三层的阅读顺序,每一条都写明可核验的理由(命中了哪个字段、被哪一篇引用),点一行即可就地预览:Markdown 按渲染后的样子显示、相对路径图片真实渲染、源码走宿主自带的语法高亮、视频走 HTTP Range 流式播放。同一份 Context Pack 也作为 knit_docs 工具交给 agent。后续版本陆续补上读取证据与生命周期(归因在读那一刻冻结)、固定 / 排除(排除先于检索生效,且可恢复)、关系证据(引用 / 导入 / 测试,带行号)与增量索引(重启后复用)。v0.23 起还多一条可选的混合检索:默认关闭,只有你自己配好 Ollama 或 OpenAI 兼容的 embedding 服务才会生效。它生效时,发出去的是你这句查询原话加上每篇候选文件的标题与摘要 —— Markdown 的摘要取自正文首段(不超过 60 字),代码的摘要是它所在的工作区相对目录,图片 / 视频贡献的是文件名;完整正文与绝对路径都不发送,指向本机服务(loopback)时内容不出这台机器。v0.24 起还能做变更关联:用一条只读的 git status(固定 argv、不走 shell、子进程环境白名单),配合同一套引用 / 导入 / 测试 / 提及证据,指出这次改动大概率该一起看哪些文件 —— 默认关闭。语义检索的收益仍待真 provider 实测,因此不承诺召回提升。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。