Saltar al contenido principal
S

dsh-paperdesk

shiyan688/dsh-paperdesk

Paper library and reading workbench: arXiv search, a local plain-file library (metadata / PDF / extracted full text), and three-level reading notes (overview / understanding / critique) kept as markdown beside the PDFs; seven model tools plus a web panel.

Instalar

dsh plugin --profile web add github:shiyan688/dsh-paperdesk

README

dsh-paperdesk

npm license

给 DeepSeek Harness 用的论文工作台: arXiv 检索 → 本地文库(题录 / PDF / 全文)→ L1-L2-L3 三层精读笔记。 宿主半区与浏览器半区在同一个包里,没有构建步骤,lib/ 里的文件就是跑起来的文件。

已发布到 npm:dsh-paperdesk@0.1.0(MIT)。线上产物与仓库源码逐字节一致 (dist.shasum 与本地 npm pack 相同),并已在一个干净 profile 上按普通用户路径 安装、启动、验证通过。


它解决什么问题

读论文的真实流程不是「下载」这一件事,而是三段:

  1. 收集 —— 在 arXiv 上找到它,存下来,别再靠浏览器书签;
  2. 读 —— 有全文可读,而不是只有一个摘要;
  3. 记住 —— 写点只有自己看得懂的东西,否则三个月后等于没读。

多数工具只做第 1 段。dsh-paperdesk 把三段接起来,并且第 3 段用固定结构逼你写:

层回答什么为什么必须单独一层
L1 速览这篇说了什么?一句话贡献是什么?筛掉不值得往下读的
L2 理解它凭什么成立?方法、关键设计、哪张表撑住了结论?区分「看懂了摘要」和「看懂了工作」
L3 批判假设成立吗?哪里可疑?哪些能搬回我自己的课题?大多数「读了但没读进去」的论文,缺的都是这一层

界面和模型工具读写的是同一份文库,所以你可以手点,也可以直接说「精读 1706.03762」。


安装

dsh plugin --profile web add dsh-paperdesk

dsh plugin 会把包装进 profile 的 node_modules,并把它在 package.json 的 dsh.profile.bundles 里登记; 包内自带的 cordis.patch.yml 作为一层 patch 被应用,把插件行插进组合配置:

- insert:
    - id: dsh-paperdesk
      name: 'dsh-paperdesk'
      config:
        root: ''          # 文库根目录;留空 = <dsh 进程工作目录>/.dsh-paperdesk
        pdfCommand: ''    # 自定义 PDF 抽取命令(pdftotext 兼容);留空 = 自动探测
        pythonCommand: '' # 自定义 python 解释器;留空 = 自动探测 python/python3/py

⚠️ 装完必须确认这一步(否则插件会静默不加载)

dsh plugin add 的工作方式是:装完包之后,按安装状态对账 dsh.profile.bundles —— 只有当一个依赖能被解析出来、并且它的 package.json 里声明了 dsh.bundle.patch,它才会入栈成为一层。 如果这一步没成功,包会作为普通依赖装进去:不报错、不加载、界面上什么都不会发生。

实测记录:在全新初始化的 profile 上出现过这个失败(包写进了 dependencies,dsh.profile.bundles 没变); 在一个已经在用的 profile 上,同样的 file: 安装一次就对账成功。所以这不是 file: 安装本身的问题, 但「新 profile + 首次安装」这个组合值得多看一眼。

所以请核对一次:

node node_modules/dsh-paperdesk/scripts/check-dsh-compat.mjs --profile web

它会把「依赖是否登记」「是否在 dsh.profile.bundles 里」逐条报出来。 如果报 不在 dsh.profile.bundles 里,手工把包名追加到 $DSH_HOME/profiles/web/package.json 的数组末尾即可:

"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-paperdesk"] } }

然后重启 profile(dsh web)。侧栏底部会出现 📚 论文 入口;启动日志里应能看到一行:

[paperdesk] 0.1.0 就绪 · 文库 <root> · 抽取器 <抽取器> · 工具 7 个 · 界面接口 已挂载

装好后,权威的健康检查是 GET http://127.0.0.1:<端口>/paperdesk/api/health(需要带上浏览器用的 token)。

卸载:

dsh plugin --profile web remove dsh-paperdesk

用它

界面(侧栏 📚 论文)

  • 文库:按状态(未读 / 在读 / 已读)、标题、作者、标签筛选;右侧是详情与三层笔记编辑框。
  • arXiv 检索:关键词或 arXiv 语法(ti:"world model" AND cat:cs.LG);一键「入库 + 下载全文」或「仅题录」。
  • 导入 PDF:扫描目录列出候选,或直接粘贴单个文件路径。导入会抽取全文,并用首页正文推断标题。

详情面板里还能:切状态、打星、改标签、在面板内分段读全文、打开文件所在目录、把论文移出文库。

模型工具

装好以后 Agent 会多出 7 个工具(同一份文库,和界面完全互通):

工具用途
paper_search在 arXiv 上检索,返回编号 / 标题 / 作者 / 分类 / 摘要片段
paper_add入库一篇(默认同时下载 PDF 并抽取全文)
paper_list列出文库,可按状态 / 关键词 / 标签筛
paper_read读全文(没有 PDF 会自动下载、没有全文会自动抽取,分页返回)
paper_note写 L1 / L2 / L3 三层笔记,或改状态、评级、标签
paper_pdf单独下载 PDF 并抽取全文
paper_import把本地已有的 PDF 收进文库

于是可以直接说:

找 5 篇 diffusion policy 的论文收进来 精读 1706.03762,写完三层笔记 我读过但没写笔记的有哪些?


数据落在哪

<root>/
  state/index.json     题录 + 状态 + 标签 + 三层笔记(唯一事实来源)
  pdf/<id>.pdf         下载或导入的 PDF
  text/<id>.txt        抽取出来的全文
  notes/<id>.md        人类可读的三层笔记(可 diff、可进 git、可单独拿走)
  .tools/extract_pdf.py  自动生成的 python 抽取脚本(可随时删除,会重新生成)

<id> 对 arXiv 论文是不带版本号的编号(1706.03762),所以「先收 v7、后来更新到 v8」不会变成两条记录。 索引里的路径都是相对路径,整个 <root> 可以直接拷到别的机器。


依赖

  • Node ≥ 20(用到全局 fetch)。

  • 运行时零第三方依赖:宿主半区只用 node: 内置模块;唯一的外部 import 是 @deepseek-ai/schemastery, 它用来声明组合配置的 schema,属于宿主自带的 peer dependency。

  • PDF 全文抽取需要一个外部工具(只在用到时才有要求),按以下顺序自动探测:

    1. 配置里的 pdfCommand(任何 pdftotext 兼容 CLI)
    2. python / python3 / py + PyMuPDF(pip install pymupdf)或 pypdf
    3. PATH 上的 pdftotext(poppler 或 MiKTeX 都带)

    一个都没有也能用:题录、检索、笔记、导入全部正常,只有「抽取全文」会失败并在 /paperdesk/api/health 里说明原因。


兼容性

跨 DSH 版本的策略只有三条,细节见 COMPATIBILITY.md:

  1. 软版本门:声明支持区间只用来提示,从不阻止插件启动;
  2. 能力探测优先:需要的服务逐个 typeof 检查,缺哪个降级哪个,结果通过 /paperdesk/api/health 如实报出;
  3. 只用最稳的接口面:ctx.tools.register / ctx.webServer.register / ctx.get—— 不碰只在动态插件里存在的 harness.*,也不碰任何 @deepseek-ai/dsh-* 的内部符号。

peerDependencies 一律写 *:这个插件与宿主的耦合点是服务契约而不是版本号,写死范围只会在能用的组合上误报。


安全

  • 浏览器半区只通过 /paperdesk/api/* 与宿主通信,且该 API 逐请求校验来源必须是本机 (127.0.0.1 / ::1 / IPv4-mapped)。绑定到回环地址不等于安全:浏览器里的任意页面都能向 localhost 发请求。
  • 导入功能会读你显式给出的绝对路径 —— 这是它的功能,不是漏洞。相对路径被拒绝,因为相对路径的含义取决于宿主进程的 cwd。
  • 所有子进程都用 spawn(command, args) 数组形式调用,不经过 shell:带空格、中文、引号的路径不会变成命令注入。
  • 下载的 PDF 会校验 %PDF- 魔数并限制体积,避免把 HTML 错误页存成一个打不开的「论文」。

开发

npm test          # node --test test/  (零测试框架依赖)
npm run compat    # 在当前机器上核对本插件依赖的服务/接口是否齐备

架构分三层,改动时请守住边界:

lib/index.js        接线:解析服务 → 建 service → 注册工具与路由(唯一 import @deepseek-ai 的地方)
lib/core/service.js 业务逻辑:不依赖 DSH,可注入副作用,能被单测直接跑
lib/core/*.js       纯逻辑:text / store / arxiv / notes / pdf / config / compat / api / tools
lib/client.js       浏览器半区:自注册到 __ModuleLoader__,内联样式,只 fetch 回环 API

test/static-guard.test.mjs 会强制这些不变量:core 层不得出现 @deepseek-ai/、宿主半区不得碰浏览器全局、 package.json 的 files 必须覆盖运行时文件、cordis.patch.yml 里的配置键必须被 schema 认识、两处版本号必须一致。

改了行为就更新 CHANGELOG.md;改了兼容面就更新 COMPATIBILITY.md。


已知限制

  • 界面是浮层面板,不是中央主面板:这是为了用社区插件已验证过的 sidebar.footer.action + shell.overlay 两个插槽组合,跨版本最稳。
  • 打开所在目录 只在宿主与浏览器同机时有意义(远端部署时点它没用)。
  • 不做去重合并:同一篇论文的 arXiv 版与会议版会是两条记录,标签是你的手段。
  • 全文抽取质量取决于 PDF:双栏排版、扫描件、公式密集的页面会有噪声;这是 PDF 文本层的固有限制。

许可

MIT。欢迎 issue 与 PR:提 bug 时请附上 /paperdesk/api/health 的输出,它包含版本、能力探测与抽取器状态。

Plugins relacionados