🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

Zotero 文献助手 toustifer/zotero-dsh

DeepSeek Harness
toustifer33 天前有提交已提供中文文档扫描:含敏感能力

把 Zotero 和 DeepSeek Harness 接起来,双向。

30.5/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add toustifer/zotero-dsh
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · search
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 33 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/9/29) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装;安装清单取自 packages/dsh-plugin/package.json

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包@dsh-external/dsh-zotero(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/11 22:19:42

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 75 处,展示前 56 条)
  • 读取本地文件
    install/heal-sessions.cjs:75
    try { entries = fs.readdirSync(dir, { withFileTypes: true }) } catch { return out }
  • 写入本地文件
    install/heal-sessions.cjs:94
    fs.mkdirSync(QUARANTINE, { recursive: true })
  • 读取本地文件
    install/heal-sessions.cjs:95
    if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true })
  • 写入本地文件
    install/heal-sessions.cjs:96
    fs.renameSync(dir, dest)
  • 写入本地文件
    packages/dsh-plugin/src/fulltranslate.ts:93
    try { mkdirSync(dir, { recursive: true }) } catch { }
  • 读取本地文件
    packages/dsh-plugin/src/fulltranslate.ts:100
    if (!existsSync(p)) return null
  • 读取本地文件
    packages/dsh-plugin/src/fulltranslate.ts:101
    const j = JSON.parse(readFileSync(p, 'utf8')) as FullTranslateJob
  • 写入本地文件
    packages/dsh-plugin/src/fulltranslate.ts:113
    writeFileSync(tmp, JSON.stringify(job), 'utf8')
  • 写入本地文件
    packages/dsh-plugin/src/fulltranslate.ts:114
    renameSync(tmp, p)
  • 读取本地文件
    packages/dsh-plugin/src/fulltranslate.ts:129
    if (!existsSync(dir)) return []
  • 读取本地文件
    packages/dsh-plugin/src/fulltranslate.ts:144
    return readdirSync(dir)
  • 读取本地文件
    packages/dsh-plugin/src/mineru-manager.ts:54
    try { dirs = readdirSync(cacheRoot) } catch { dirs = [] }
  • 读取本地文件
    packages/dsh-plugin/src/mineru-manager.ts:58
    const sizeKb = existsSync(mdPath) ? Math.round(statSync(mdPath).size / 1024) : undefined
  • 读取本地文件
    packages/dsh-plugin/src/mineru-manager.ts:58
    const sizeKb = existsSync(mdPath) ? Math.round(statSync(mdPath).size / 1024) : undefined
  • 读取本地文件
    packages/dsh-plugin/src/mineru-manager.ts:151
    if (existsSync(dir)) rmSync(dir, { recursive: true, force: true })
  • 删除本地文件递归
    packages/dsh-plugin/src/mineru-manager.ts:151
    if (existsSync(dir)) rmSync(dir, { recursive: true, force: true })
  • 请求外部主机mineru.net
    packages/dsh-plugin/src/mineru-manager.ts:164
    const res = await fetch('https://mineru.net/api/v4/file-urls/batch', {
  • 发起网络请求
    packages/dsh-plugin/src/mineru-manager.ts:164
    const res = await fetch('https://mineru.net/api/v4/file-urls/batch', {
  • 发起网络请求
    packages/dsh-plugin/src/mineru-manager.ts:174
    const res = await fetch(`${base.replace(/ +$/, '')}/health`, { method: 'GET' })
  • 读取本地文件
    packages/dsh-plugin/src/panel-api.ts:193
    if (!existsSync(p)) return { conversations: [] }
  • 读取本地文件
    packages/dsh-plugin/src/panel-api.ts:194
    const raw = JSON.parse(readFileSync(p, 'utf8')) as any
  • 写入本地文件
    packages/dsh-plugin/src/panel-api.ts:239
    mkdirSync(dirname(chatStorePath()), { recursive: true })
  • 写入本地文件
    packages/dsh-plugin/src/panel-api.ts:240
    writeFileSync(chatStorePath(), JSON.stringify(store, null, 2), 'utf8')
  • 读取本地文件
    packages/dsh-plugin/src/panel-api.ts:1029
    if (!p || !existsSync(p)) return send(res, 404, { error: '产物不存在(任务可能未完成)' })
  • 读取本地文件
    packages/dsh-plugin/src/panel-api.ts:1359
    if (!existsSync(file)) return []
  • 读取本地文件
    packages/dsh-plugin/src/panel-api.ts:1360
    const doc = JSON.parse(readFileSync(file, 'utf8')) as {
  • 写入本地文件
    packages/dsh-plugin/src/panel-api.ts:1485
    try { mkdirSync(path, { recursive: true }) } catch (err: unknown) {
  • 写入本地文件
    packages/dsh-plugin/src/panel-api.ts:1509
    mkdirSync(targetDir, { recursive: true })
  • 读取本地文件
    packages/dsh-plugin/src/panel-api.ts:1516
    if (!existsSync(canvasFile)) {
  • 写入本地文件
    packages/dsh-plugin/src/panel-api.ts:1517
    writeFileSync(canvasFile, JSON.stringify({
  • 删除本地文件
    packages/dsh-plugin/src/panel-api.ts:1663
    try { if (existsSync(file)) rmSync(file, { force: true }) } catch { }
  • 写入本地文件
    packages/dsh-plugin/src/panel-api.ts:1666
    mkdirSync(workspacePath, { recursive: true })
  • 写入本地文件
    packages/dsh-plugin/src/pdf2zh.ts:38
    try { mkdirSync(dir, { recursive: true }) } catch { }
  • 读取本地文件
    packages/dsh-plugin/src/pdf2zh.ts:45
    const files = readdirSync(dir)
  • 读取本地文件
    packages/dsh-plugin/src/pdf2zh.ts:64
    try { if (existsSync(c)) return c } catch { }
  • 执行外部命令来自配置/变量
    packages/dsh-plugin/src/pdf2zh.ts:155
    const child = spawn(bin, args, { env, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] })
  • 读取本地文件
    packages/dsh-plugin/src/project-map.ts:240
    if (!existsSync(p)) return { ...EMPTY }
  • 读取本地文件
    packages/dsh-plugin/src/project-map.ts:241
    const raw = JSON.parse(readFileSync(p, 'utf8')) as Record<string, unknown>
  • 写入本地文件
    packages/dsh-plugin/src/project-map.ts:277
    mkdirSync(dirname(p), { recursive: true })
  • 写入本地文件
    packages/dsh-plugin/src/project-map.ts:278
    writeFileSync(p, JSON.stringify(m, null, 2), 'utf8')
  • 读取本地文件
    packages/dsh-plugin/src/runtime.ts:88
    if (!existsSync(p)) return {}
  • 读取本地文件
    packages/dsh-plugin/src/runtime.ts:89
    return sanitizeOverlay(JSON.parse(readFileSync(p, 'utf8')))
  • 写入本地文件
    packages/dsh-plugin/src/runtime.ts:98
    mkdirSync(join(settingsPath(), '..'), { recursive: true })
  • 写入本地文件
    packages/dsh-plugin/src/runtime.ts:99
    writeFileSync(settingsPath(), JSON.stringify(merged, null, 2), 'utf8')
  • 写入本地文件
    packages/dsh-plugin/src/tools-m2.ts:207
    writeFileSync(pdfPath, bytes)
  • 执行外部命令固定命令
    packages/dsh-plugin/src/tools-m2.ts:208
    const child = spawn('pdftotext', ['-layout', pdfPath, '-'], {
  • 删除本地文件递归
    packages/dsh-plugin/src/tools-m2.ts:217
    rmSync(tmp, { recursive: true, force: true })
  • 删除本地文件递归
    packages/dsh-plugin/src/tools-m2.ts:221
    rmSync(tmp, { recursive: true, force: true })
  • 读取本地文件
    packages/dsh-plugin/src/tools-m2.ts:1064
    if (!existsSync(imgDir)) return 0
  • 读取本地文件
    packages/dsh-plugin/src/tools-m2.ts:1065
    return readdirSync(imgDir).length
  • 读取本地文件
    packages/dsh-plugin/src/tools.ts:180
    if (!existsSync(wsPath)) {
  • 写入本地文件
    packages/dsh-plugin/src/translate.ts:54
    try { mkdirSync(dir, { recursive: true }) } catch { }
  • 读取本地文件
    packages/dsh-plugin/src/translate.ts:63
    if (existsSync(f)) return JSON.parse(readFileSync(f, 'utf8')) as TranslationCache
  • 读取本地文件
    packages/dsh-plugin/src/translate.ts:63
    if (existsSync(f)) return JSON.parse(readFileSync(f, 'utf8')) as TranslationCache
  • 写入本地文件
    packages/dsh-plugin/src/translate.ts:79
    writeFileSync(tmp, JSON.stringify(cache), 'utf8')
  • 写入本地文件
    packages/dsh-plugin/src/translate.ts:80
    renameSync(tmp, f)
扫描于 2026/11/2(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库
涉及外部主机:mineru.net

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 内嵌DSH对话面板
  • 检索与精读论文
  • 翻译标注整理
展开完整介绍(131 字)↓

Zotero 与 DeepSeek Harness 的双向桥:Zotero 右侧栏内嵌真正的 DSH 对话面板,DSH 里检索、精读、翻译、标注、整理论文。A two-way bridge between Zotero and DeepSeek Harness.

README

由 DeepSeek 最新模型翻译生成
zotero-dsh 把 Zotero 和 DeepSeek Harness 接起来,双向。 dsh-zotero 是「DSH 里的 Zotero」,zotero-dsh 是「Zotero 里的 DSH」。 这个仓库装的是后者,并且把两个方向放在一起。 姊妹项目:Fisfzy/dsh-zotero(DSH 侧,独立仓库)。 目录 | 包 | 方向 | 做什么 | | packages/zotero-addon | Zotero → DSH | 在 Zotero 右侧栏里嵌入真正的 DSH 界面 | | packages/dsh-plugin | DSH → Zotero | 在 DSH 里检索、精读、标注、整理论文 | 不想编译? 两步装完:[下载 xpi 装进 Zotero] + [跑一次安装脚本],都从 最新 Release 取预构建产物。 详见 install/README.md。 Zotero 里的 DSH — packages/zotero-addon Zotero 7 插件。在条目详情面板的右侧栏注册一个 section,里面用 XUL 内嵌 DSH 的 Web 界面 —— 不是截图,不是消息转发,是在 Zotero 里跑一个真的 DSH 会话。
展开完整文档(README 剩余 1 节)
zotero-dsh

把 Zotero 和 DeepSeek Harness 接起来,双向。

dsh-zotero 是「DSH 里的 Zotero」,zotero-dsh 是「Zotero 里的 DSH」。
这个仓库装的是后者,并且把两个方向放在一起。
姊妹项目:Fisfzy/dsh-zotero(DSH 侧,独立仓库)。

目录

| 包 | 方向 | 做什么 |
| packages/zotero-addon | Zotero → DSH | 在 Zotero 右侧栏里嵌入真正的 DSH 界面 |
| packages/dsh-plugin | DSH → Zotero | 在 DSH 里检索、精读、标注、整理论文 |

不想编译? 两步装完:[下载 xpi 装进 Zotero] + [跑一次安装脚本],都从 最新 Release 取预构建产物。
详见 install/README.md。

Zotero 里的 DSH — packages/zotero-addon

Zotero 7 插件。在条目详情面板的右侧栏注册一个 section,里面用 XUL 内嵌 DSH 的 Web 界面 —— 不是截图,不是消息转发,是在 Zotero 里跑一个真的 DSH 会话。

几个必须踩对的点(源码里都有注释):

- 必须 createXULElement("browser"),配 remote + maychangeremoteness + disableglobalhistory,否则静默失败或者直接把 Zotero 搞崩
- 导航只能走 browsingContext 的 PageData actor 的 sendQuery("loadURI"),直接调 browser.loadURI() 会 NS_ERROR_FAILURE
- DSH 每次启动都换 token,且不持久化。所以 base 来自偏好项,token 一律现取 ——从实例日志里读最后一条 dsh web: 行的 token。旧实现信任偏好项里的 token,于是 DSH 一重启,面板就停在 401 页

在 PDF 里选中文字送进 DSH

在 Zotero 自己的阅读器里选中一段话,气泡里会多出两个按钮:

- 送入 DSH —— 只把选段推进该论文的会话上下文,你接着自己写问题(对应 VSCode 聊天里 "Add to Chat" 的语义)
- 问 DSH —— 顺带追一轮,让它直接解读这段

会话按 itemKey 懒开:没打开过面板也能送,第一段送进来时会自动带上论文元数据。
实现走 renderTextSelectionPopup 事件 + POST /quote,不劫持 Zotero 的任何原生行为。

选段会出现在 DSH 输入框正上方。 DSH 侧注册在 conversation.input.dock 槽的引用卡显示刚送进来的那段话,点「附到问题」经 inputActions.setDraft 追加进草稿 —— DSH 唯一一个"把外部文本写进输入框"的公开接口。只加引用,不替你发送,和 VSCode 聊天里的 "Add to Chat" 是同一件事。送入的同一段话同时也注入了该论文会话的上下文,所以模型两处都看得到。

安装

从 最新 Release 下载 zotero-dsh.xpi, Zotero 里走 工具 → 插件 → 齿轮 → Install Plugin From File…,重启即可 —— 不需要先跑 "Load Plugin From Manifest" 那套开发流程。

自己打包

pwsh -File packages/zotero-addon/build.ps1

产出 packages/zotero-addon/zotero-dsh.xpi。

DSH 里的 Zotero — packages/dsh-plugin

DSH 插件(@dsh-external/dsh-zotero)。注册 12 个 agent 工具和一个右侧栏面板:

- 检索与阅读:Local API 搜索、条目详情、集合树、PDF/全文读取
- 全文解析:MinerU 通道(公式、表格保留),带缓存
- 精读与翻译:整篇总结、定向提问、逐段翻译、批量处理
- 标注与笔记:读 PDF 高亮与批注,回写 Markdown 笔记
- 论文 ↔ 工作区映射:区/组两级;组可以映射到真实目录,于是同一篇论文从不同 idea 打开会落到不同的工作目录
- 证据检索:索引 + 查询规划 + 重排,回答带出处

安装

从 最新 Release 下载 dsh-zotero-0.1.1.tgz 加上对应平台的脚本,放同一个目录:

pwsh -File install-dsh.ps1 # Windows

bash install-dsh.sh # macOS / Linux

脚本只做四件事:解包到 ~/.dsh/plugins/dsh-zotero、装唯一的运行依赖 pdfjs-dist、在 profile 的 node_modules 下建链接、往 cordis.patch.yml 补一次加载锚点。
不编译。 细节见 install/README.md。

宿主代码跨平台:唯一碰系统的位置是"打开文件或链接",已经按 process.platform 分了 open / xdg-open / cmd start 三条路。

自己构建

cd packages/dsh-plugin
pnpm install # 需要 DSH 环境提供的 @deepseek-ai/* peer 依赖
node scripts/build.mjs

关系图

Zotero ──[zotero-addon: 右侧栏嵌入]──► DSH ▲ │
└──────[dsh-plugin: 工具 + 面板]───────┘

两侧各走各的路,互不依赖:Zotero 侧只认一个 URL,DSH 侧只认 Zotero 的 Local API。

开发

两个包互相独立,没有共享构建。

Zotero 侧:改 addon/ 后重新打包,Zotero 里热重载或重启 pwsh -File packages/zotero-addon/build.ps1

DSH 侧:改 src/ 后重建,重启 DSH 实例
cd packages/dsh-plugin && node scripts/build.mjs

已知边界

- Zotero 侧的 token 解析按优先级扫候选日志,换实例只需改端口,不用改 token
- DSH 侧的面板依赖 DSH 的 sidebar.workspaces 相关槽位,DSH 大版本升级可能需要跟进
- 论文 ↔ 工作区映射存在本地 JSON,不进 Zotero 数据库

许可

AGPL-3.0-only。见 LICENSE。

DSH 侧源自 llm-for-zotero 的重构,后者以 AGPL-3.0 发布,因此本仓库整体采用同一许可。
预览分享卡片长什么样 ↓toustifer/zotero-dsh
分享 · DeepSeek Harness Hub
toustifer/zotero-dsh

把 Zotero 和 DeepSeek Harness 接起来,双向。

回到顶部