Bundle
@juzikexue/dsh-paper-digest
Paper digest plugin: every day at a configured time, collect quality papers on your topics (Chinese + English), rank them with transparent quality signals, and write a Markdown report into the workspace. Configured from its own page in DSH Settings.
- Source
- juzikexue
- License
- MIT
- Updated
- Updated 4 days ago
Readme
# dsh-paper-digest
每日论文日报插件。按设定的时间自动检索中英文高质量论文,按透明可审计的质量信号排序,生成一份按主题分组的 Markdown 日报写入工作区。全部配置在 DSH **设置 → 论文日报** 中完成。
> **v0.1.1 修复**(功能范围未变,只修交互缺陷与构建配置):
>
> 1. **启动期静默锁**:调度器在插件加载后 8 秒就会补跑当天日报并独占运行锁数分钟,而设置页完全看不到这次运行,于是首次点击「立即生成日报」会撞上 `已有一次运行在进行中`。现在运行状态携带**触发来源与已用时**,`POST /run` 在已有运行时不再返回 409,而是如实说明"已在进行中"并让前端跟踪那一次运行。
> 2. **按钮忙态不自同步**:面板原本只在挂载时读一次状态,且轮询被 `status.running` 门控,所以宿主侧发起的运行对面板不可见。现在面板会主动发现并跟踪进行中的运行,按钮与进度文案随之更新。
> 3. **包名改为单一事实来源**:`scripts/build-client.mjs` 不再硬编码模块 id,改为读 `package.json` 的 `name`。原先两处硬编码会静默漂移——宿主按清单名提供 bundle、而 banner 注册了另一个 id,结果是设置页永不出现且无任何日志。
> 4. **构建授权对准 pnpm 12**:`package.json` 里的 `pnpm.onlyBuiltDependencies` 已不被 pnpm 12 读取,导致新克隆 `pnpm install` 以 `ERR_PNPM_IGNORED_BUILDS` 失败。改为 `pnpm-workspace.yaml` 里的 `allowBuilds`。
## 它解决什么
"每天自动送 10 篇好论文"的真正难点不是推送,而是**判定质量**与**拿到中文文献**:
- 知网、万方、维普**都没有面向个人的公开 API**;
- "北大核心"是《中文核心期刊要目总览》这本书目,不是可查询的数据库;
- 新发表的论文**没有任何引用**,所以"按引用排序"在 T+0 完全无效(OpenAlex 对新论文返回 `fwci: null`)。
因此插件的排序依据是**当天就能算出来的信号**:场所权威(核心库收录 / 期刊 / 已录用)、内容证据(方法·结果·局限·数据公开)、时效、作者机构,以及很小的社区关注度。每篇论文都会在日报里写出**入选理由、命中关键词和评分构成**,可直接审计。
## 日报会话(找得到)
每份日报除了写成文件,还会**自动创建一个会话**:以日期命名(如 `2026-09-18 论文日报(10 篇)`),会话根目录是日报目录,并挂到对应工作区上——因此在左侧会话列表里直接点开就能读,不必去翻文件夹。
打开后你会看到一轮正常的对话:你自己的请求「生成今天的论文日报(日期)」→ **助手读完报告后给出的分主题速览**,并以**交付文件卡片**呈现日报本身(可直接点开或下载),末尾附本地全文路径与数据源失败情况。会话挂载的是部署默认的 agent 预设,所以能继续追问某篇论文的细节。
- **播种的那条消息必须用 `source: { kind: 'user' }`**。用 `plugin` 源会被判为*上下文注入*,渲染成折叠的「上下文注入」行而不是对话(第一版就是这样,对照截图确认后修正)。
- **摘要轮次是真的模型轮次**:创建会话后用 `agent.followup(message)`(等价于 `send(msg, 'next-turn', true)`)排一轮,让助手真正读取文件并总结——这才产出你期望的"助手总结 + 文件"形态,而不是把整份 Markdown 塞进消息里。
- **提示词里明确要求调用 `present`**:文件卡片由 `present` 工具产生,只在正文里写路径是不会有卡片的(这一点在我自己的回复里也踩过)。
- **零事件会话不会显示**:`agents.create` 建出来的是空日志(501 字节、零事件),侧边栏不渲染它——工作区展开后只有文件夹(已在真实 UI 上复现)。所以播种是必需的,不是可选项。
- **播种/追加失败会降级并如实报告**:退回空会话并把原因写进日报诊断,不会因为会话问题丢掉日报。
- 日报目录只建**一个**工作区,后续每天复用(按路径匹配,避免侧边栏堆满每日工作区)。
- 设置页有「**为上次日报新建会话**」按钮,用于补救历史日报。
- 关掉开关即只写文件、不建会话。
实现上有几个只靠猜一定会踩的坑,均已写进代码注释:
1. **`resolveByPath()` 定义在原型上**(列服务自己的方法时看不到),且 Workspace 的目录是通过 **`path()` 方法**暴露的、不是 `cwd` 属性——按 `cwd` 匹配永远失败,会每天重复建一个工作区。
2. **宿主服务必须每次运行惰性读取**:插件加载得早、工作区平面挂载得晚,激活时读一次会把 `undefined` 永久缓存(`ctx.get()` 不会触发重新激活)。
3. **会话事件有 surface 契约**:`user/message` 属于*表面事件*,必须带 `surfaceOp`(追加用 `'append'`)并可引用来源事件序号;序号从 0 连续;且不能留下未闭合的轮次,所以 `turn/end` 是必需的。写错的代价由日志校验器当场拒绝(不会写坏会话)。
4. **`agent.followup()` 是驱动一轮的官方原语**,`send(message, 'next-turn', true)` 等价;只 append 到 inbox 不足以让轮次跑起来。
## 中文速览
每篇入选论文会由**本机已配置的模型**(读取 `agentDefaultModel` 的当前选择,无需另配 API Key)根据标题与摘要生成 2–3 句中文速览,在日报里以「📌 一句话速览」置顶;原文摘要折叠保留在下方可展开核对。提示词明确要求**只使用给定信息、不得补充或推测**,摘要未交代方法与结论时如实说明。
几个由实测得来的设计点:
- **默认输出上限 1500 tokens**。思考型模型会先花预算思考:最初设 300 tokens 时 10 篇里有 9 篇返回**空内容**(预算被思考吃光)。
- **首次为空会自动加倍预算重试一次**。实测仍有 **3/10 篇**首次为空、重试后成功,所以这不是冗余逻辑。
- **思考档位可调**(继承 / minimal / low / medium / high / max)。速览只是归纳,嫌慢或嫌费可调 `minimal` 并相应调低输出上限。
- **单篇失败不影响整篇日报**:失败原因(含 finish 与思考 token 数)写进「运行诊断 → 中文速览」,其余论文照常出速览。
- 关闭开关即完全不调用模型。
## 全文获取
**只下载开放获取(OA)全文**,插件从不尝试绕过付费墙:
| 通道 | 说明 |
| --- | --- |
| arXiv | 作者自存预印本,PDF 直链稳定可下 |
| PubMed Central(经 Europe PMC) | 有 `pmcid` 即代表全文开放,PDF 接口精确 |
| 出版商 OA 版本 | OpenAlex 的 `best_oa_location.pdf_url` 明确标注开放时才会使用 |
| Unpaywall(可选) | 留空邮箱即关闭;填入你自己的邮箱后,可为付费论文**查找合法的 OA 副本** |
每个文件都先校验 `%PDF-` 魔数再落盘,所以验证码页 / HTML 错误页**不可能被存成 `.pdf`**;单文件上限 25MB,每轮下载数量可限。
**中文订阅库(知网 / 万方 / 维普)不抓取全文**,日报只给详情页链接。这不是技术限制而是刻意选择:其服务条款禁止批量下载,且从校园网跑脚本抓取一旦触发风控,受影响的是**全校 IP 段**。你在浏览器里用学校账号点开链接,一样省事但零风险。
产出位置:`outputDir`(日报 Markdown)与 `pdfDir`(默认 `outputDir/pdf`);默认根目录 `~/Documents/dsh-paper-digest`,可用环境变量 `DSH_PAPER_DIGEST_DIR` 覆盖。
## 安装
### 1. 取得源码并构建
```sh
git clone https://github.com/juzikexue/dsh-paper-digest.git
cd dsh-paper-digest
pnpm install
pnpm build:client # 必须执行,原因见下
pnpm test # 可选:69 项回归单测
```
> **`lib/client.js` 不入库**(esbuild 构建产物,见 `.gitignore`),所以克隆后必须自己构建一次。
> 跳过这一步插件**仍能启动、日报也照常生成**,但**设置页会是空的**——浏览器半加载不到,且没有任何报错。
> 这是装这个插件最容易漏掉的一步。
### 2. 以 `link:` 方式装入 web profile
```jsonc
// ~/.dsh/profiles/web/package.json
{
"dsh": {
"profile": {
"bundles": [ /* … */ "@juzikexue/dsh-paper-digest" ]
}
},
"dependencies": {
// 键名与值都必须用 package.json 里的 name,换成上一步克隆到的绝对路径
"@juzikexue/dsh-paper-digest": "link:/abs/path/to/dsh-paper-digest"
}
}
```
```sh
cd ~/.dsh/profiles/web && pnpm install
# 然后重启 dsh web
```
> 也可以直接用 CLI,它会自动把带 `dsh.bundle` 声明的依赖并入 `dsh.profile.bundles`:
>
> ```sh
> dsh plugin --profile web add "link:/abs/path/to/dsh-paper-digest"
> ```
插件的 `cordis.patch.yml` 只在 Loader 树里插一行 host row:该行负责配置/状态路由、每日调度与产出;浏览器半由 `package.json` 的 `dsh.client` 声明被 `dsh-client-modules` 发现。
## 设置项(设置 → 论文日报)
| 设置 | 说明 |
| --- | --- |
| 启用每日自动检索 | 关闭后只保留手动运行 |
| 发送时间 | 每天此刻**之后**首次检查时生成;若运行时刻机器休眠,唤醒后自动补跑 |
| 每日篇数 / 中英配比 | 中文是**软目标**,中文源不足时由英文补齐到总篇数 |
| 回溯天数 | 只收最近 N 天发表的论文(期刊 RSS 除外,见下) |
| 输出目录 | 日报写入此处,建议填会话工作区 |
| 研究主题 | 每个主题含**中文关键词**与**英文关键词** |
| CNKI 期刊监控 | 期刊代码 + 刊名 + 归属主题;中文主力通道 |
| 数据源开关 | 见下表 |
| 核心期刊表 | 可选,每行 `刊名关键词 = 等级`,命中即标记核心刊并提高评分 |
### 关键词写法(重要)
中英文的空格含义**不同**,这是刻意的:
- **中文**:空格 = **或**。`人工智能 教育` 表示"人工智能"或"教育"。但 2 字通用词(教育、学习、技术)**不单独作为证据**,否则"义务教育"论文会灌进"人工智能教育"主题。请写 3 字以上的词组。
- **英文**:空格 = **且**。`computer-assisted language learning` 是一个短语,所有词都必须在标题/摘要中出现。
日报会打印每篇论文的**命中关键词**,如果发现某篇不对口,照它去收紧关键词即可。
## 数据源与可靠性
| 源 | 语言 | 通道 | 状态 |
| --- | --- | --- | --- |
| CNKI 期刊 RSS | 中 | `rss.cnki.net` 的期刊最新目录(每刊约 20 条) | ✅ 稳定、免登录、无需验证码 |
| ChinaXiv | 中 | 中科院预印本公开 JSON API | ✅ 稳定;接口是全文检索,插件会自行做相关度过滤 |
| Europe PMC(中文) | 中 | `LANG:chi` 检索 | ⚠️ 仅医学(每两周约 35 条,几乎全是中华医学会系列),**默认关闭** |
| NCPSSD | 中 | 站点为 Vue SPA,无公开检索 JSON 接口 | ⚠️ 实验性,默认关闭 |
| OpenAlex | 英 | 官方 API,`primary_location.source.is_core` 作核心库标记 | ✅ 稳定、免费、无需 key |
| Crossref | 英 | 官方 API,标题检索 | ✅ 稳定、免费 |
| arXiv | 英 | Atom API,`arxiv:comment` 里的 "Accepted at XXX" 是强质量信号 | ✅ 可用(偶发超时,已隔离) |
**一个数据源失败不会中断日报**:失败会记进「运行诊断」,剩余源继续,英文补齐篇数。
### 为什么中文主力是期刊 RSS 而不是检索
知网检索页有滑块验证码,且用校园 IP 批量抓取检索结果有连累全校封禁的风险。期刊 RSS 是官方提供的、免登录的"最新一期目录",语义上恰好就是"我的领域这周有什么新论文",因此作为中文主力。期刊代码可在知网期刊导航页的 URL 中看到(如 `JJYJ`=经济研究、`JYYJ`=教育研究、`XLKX`=心理科学)。
## 质量评分
```
总分 = (期刊档次 30 + 内容证据 25 + 时效 15 + 数据开放 10 + 社区关注 10 + 作者机构 10)
× (0.45 + 0.55 × 主题相关度)
```
- **硬门槛**(打分前剔除):撤稿记录、标题缺失或过短、无链接且无 DOI、超期;期刊 RSS 条目豁免时效门槛,因为"最新一期"本身可能已出版数周。
- **内容证据**从标题+摘要抽取:是否含方法、结果、局限表述,是否有数据/代码公开线索。
- **社区关注**用引用数取对数;对新论文天然接近 0,这是有意的——它不该主导 T+0 排序。
## 运维
```sh
node scripts/live-run.mjs [输出文件] # 不经过 dsh,直接跑一次真实检索并打印统计
node --test "test/*.test.js" # 回归单测(关键词匹配、去重、选题、渲染)
node scripts/build-client.mjs # 重建设置面板 bundle(改 src/client 后必须执行)
```
配置与状态落盘在 `~/.dsh/storages/dsh-paper-digest/`(`config.json`、`status.json`、`core-journals.txt`)。配置**不使用** DSH 的 `settings` 服务:该服务对 out-of-tree 插件是 scope 隔离的,第三方插件注册不进去,所以插件自带 HTTP 路由持久化自己的配置。
## 已知限制
- **中文检索精度受关键词质量影响最大**。2 字通用词已被排除,但仍有语义歧义(例如关键词里的"技术"会命中核物理论文)。日报的「命中关键词」就是为排查这类问题而设。
- **订阅式电子期刊(PubScholar/NCPSSD)无法在纯 HTTP 下检索**,因为结果是浏览器内渲染的,且没有公开 JSON 接口。若要纳入,需要引入无头浏览器依赖。
- **核心期刊表需自行维护**(书目受版权保护且有多个版本),未配置时中文论文不做等级加权,仅按其他信号排序。
- arXiv 偶发超时;插件已设超时与重试并做源级隔离。
## 许可
MIT
Install
dsh plugin --profile web add github:juzikexue/dsh-paper-digest#60ad806139e72f924de4bdcd8ecafa0da630d210
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install juzikexue-dsh-paper-digest from the hub