dsh-cite 0.3.5 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.en.md +30 -26
- package/README.md +24 -58
- package/cordis.patch.yml +1 -1
- package/docs/CHANGELOG.en.md +21 -0
- package/docs/USAGE.en.md +54 -0
- package/docs/USAGE.md +89 -0
- package/docs/VALIDATION.md +20 -0
- package/lib/citation-errors.d.ts +2 -0
- package/lib/citation-errors.js +50 -0
- package/lib/citation-model.d.ts +60 -0
- package/lib/citation-model.js +75 -0
- package/lib/citation-parser.d.ts +2 -0
- package/lib/citation-parser.js +29 -0
- package/lib/citation-store.d.ts +10 -0
- package/lib/citation-store.js +107 -0
- package/lib/citation-workbench.d.ts +105 -0
- package/lib/citation-workbench.js +277 -0
- package/lib/citation-worker.d.ts +1 -0
- package/lib/citation-worker.js +44 -0
- package/lib/client.js +69 -0
- package/lib/crossref.js +2 -1
- package/lib/format.d.ts +1 -1
- package/lib/format.js +29 -22
- package/lib/index.d.ts +7 -2
- package/lib/index.js +19 -9
- package/package.json +15 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# 更新记录
|
|
2
|
+
|
|
3
|
+
[返回简介](README.md) · [使用说明](docs/USAGE.md) · [验证记录](docs/VALIDATION.md)
|
|
4
|
+
|
|
5
|
+
[历史英文记录](docs/CHANGELOG.en.md)
|
|
6
|
+
|
|
7
|
+
## 0.4.1 (2026-10-03)
|
|
8
|
+
|
|
9
|
+
- 修复含多个出版社名称的 BibTeX 导出后再导入失败,保留出版社名称及原始来源。41 项 Windows 测试与真实下载文件的再导入通过。
|
|
10
|
+
|
|
11
|
+
## 0.4.0 (2026-10-03)
|
|
12
|
+
|
|
13
|
+
- 新增中文 / English 文献工作台和 `cite_batch`:DOI / BibTeX 批量导入、本地预览、选择保存、搜索及格式切换。原有五个工具保留。
|
|
14
|
+
- DOI 精确去重,缺少 DOI 时提示可能重复;原始来源随完整备份保留,BibTeX 导出使用唯一引用键。
|
|
15
|
+
- 在线补全需明确操作,只补空字段并保留差异;支持进度、取消及失败重试,文献库修订检查避免覆盖其他窗口的修改。
|
|
16
|
+
- 使用 Citation.js 的本地 BibTeX 解析器,限制输入和解析时间,不自动请求输入中的链接。
|
|
17
|
+
- 修复 MLA 机构名称与复合姓氏被按空格拆分的问题;Chicago note 保留名字、姓氏边界,英文缺失信息提示不再混入中文。
|
|
18
|
+
- 官方 DSH RC2 / 0.2.1-alpha.1 SDK、Windows 测试及真实浏览器导入、Crossref 查询、中英文切换和下载通过。原生桌面新界面尚未实际操作验收,见[验证记录](docs/VALIDATION.md)。
|
|
19
|
+
|
|
20
|
+
## 0.3.5 (2026-09-28)
|
|
21
|
+
|
|
22
|
+
- 更新官方 Harness 0.2.0-rc.1 的兼容声明和共同加载验证;运行时代码未变。验证范围见[验证记录](docs/VALIDATION.md)。
|
|
23
|
+
|
|
24
|
+
## 0.3.4 (2026-09-27)
|
|
25
|
+
|
|
26
|
+
修复 BibTeX 作者姓名顺序,保留复合姓氏;机构作者使用独立括号,避免被拆成人名。
|
|
27
|
+
|
|
28
|
+
## 更早的改动
|
|
29
|
+
|
|
30
|
+
完整历史可查阅 [GitHub 提交记录](https://github.com/STARDUSTLC666/dsh-cite/commits/master)。
|
package/README.en.md
CHANGED
|
@@ -1,45 +1,49 @@
|
|
|
1
1
|
# dsh-cite
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[中文](README.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Organize DOI lists or BibTeX into a reviewable local library, then export references and BibTeX.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/dsh-cite) [](https://www.npmjs.com/package/dsh-cite)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## What it does
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- Paste DOI lists or upload `.bib` files. Preview locally before choosing entries to save, with duplicate and missing-field warnings.
|
|
12
|
+
- Explicitly enrich empty fields through Crossref. Keep existing values, inspect differences and retry failed entries.
|
|
13
|
+
- Switch between basic GB/T 7714, APA, MLA and Chicago formats; download BibTeX, reference text or a full backup with original sources.
|
|
14
|
+
- Existing DOI lookup, bibliographic search and DOI-checking tools remain available.
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
## Install
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
In DSH Desktop, install `dsh-cite` from the Plugins panel. If the bundled dsh command is available:
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
| `cite_format` | Generate a formatted citation | `doi`; `style`: gb-t-7714 / apa / mla / chicago |
|
|
21
|
-
| `cite_bibtex` | Generate a BibTeX entry | `doi`; `key` optional |
|
|
22
|
-
| `cite_check` | Extract DOIs from text and validate them | `text`; `maxChecks` 1-50, default 10 |
|
|
23
|
-
| `cite_health` | Self-check: probe Crossref connectivity and report latency | none |
|
|
20
|
+
```bash
|
|
21
|
+
dsh plugin --profile desktop add dsh-cite
|
|
22
|
+
```
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
For the web version, replace `desktop` with `web`. Restart DSH after installation.
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
## Start using it
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
Open **Settings → Cite**, paste DOIs or upload a `.bib` file, choose **Local preview**, review the entries and **Save selected**. Select saved entries and explicitly request online enrichment when needed. UI text follows DSH's Chinese / English setting; bibliographic content stays in its original language.
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
dsh plugin --profile web add dsh-cite
|
|
33
|
-
```
|
|
30
|
+
Or ask the agent: “Preview these DOIs locally first. Save the entries I select, then export APA references and BibTeX.”
|
|
34
31
|
|
|
35
|
-
##
|
|
32
|
+
## Requirements and configuration
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
Local import, deduplication, library access and formatting work offline. Online enrichment and existing lookup tools query Crossref and require network access, with no separate API key. Limits: 256 KiB / 100 entries per batch, 500 saved entries.
|
|
35
|
+
|
|
36
|
+
Citation output uses the plugin's basic templates; check institution or journal requirements before submission. BibTeX exports contain mapped fields. The full backup preserves original input containing fields not mapped into the workbench.
|
|
37
|
+
|
|
38
|
+
Detailed configuration, tool arguments and troubleshooting are in the [usage guide](docs/USAGE.en.md). For standalone development, follow the Node requirement in [package.json](package.json).
|
|
39
|
+
|
|
40
|
+
## Documentation
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
- [Usage and troubleshooting](docs/USAGE.en.md)
|
|
43
|
+
- [Changelog](CHANGELOG.md)
|
|
44
|
+
- [Validation scope and history](docs/VALIDATION.md)
|
|
45
|
+
- [Report a problem or suggest a feature](https://github.com/STARDUSTLC666/dsh-cite/issues)
|
|
42
46
|
|
|
43
47
|
## License
|
|
44
48
|
|
|
45
|
-
MIT
|
|
49
|
+
[MIT](LICENSE)
|
package/README.md
CHANGED
|
@@ -1,83 +1,49 @@
|
|
|
1
1
|
# dsh-cite
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[English](README.en.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
把 DOI 列表或 BibTeX 整理成可核对的本地文献库,再导出参考文献与 BibTeX。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/dsh-cite) [](https://www.npmjs.com/package/dsh-cite)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## 功能
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## 工具
|
|
16
|
-
|
|
17
|
-
| 工具 | 作用 | 关键参数 |
|
|
18
|
-
| :-- | :-- | :-- |
|
|
19
|
-
| `cite_lookup` | 查文献元数据(DOI 精确查询 / 题录检索) | `doi` 或 `query` 至少一个;`limit` 1-10 默认 5 |
|
|
20
|
-
| `cite_format` | 生成规范引文 | `doi` 必填;`style`:gb-t-7714 / apa / mla / chicago |
|
|
21
|
-
| `cite_bibtex` | 生成 BibTeX 条目 | `doi` 必填;`key` 可选 |
|
|
22
|
-
| `cite_check` | 从文本提取 DOI 并并发校验是否存在(并发 3,保持输入顺序) | `text` 必填;`maxChecks` 1-50 默认 10 |
|
|
23
|
-
| `cite_health` | 自检:探测 Crossref 连通性并报告延迟 | 无 |
|
|
24
|
-
|
|
25
|
-
## 兼容性
|
|
26
|
-
|
|
27
|
-
已在官方 `@deepseek-ai/dsh@0.1.5-rc.1`、Node `24.16.0` 上验证(2026-09-11):18 个组件与 Modlens 同载,工具 schema、技能注册及离线只读调用检查通过。采用 `cordis.patch.yml` + `dsh.bundle.patch` 组合包模型。Node 要求与该版本 Harness 一致:22.19 及以上的 22.x,或 24 及以上。外部服务的实际业务操作需按各组件配置单独验证。
|
|
11
|
+
- 批量粘贴 DOI 或上传 `.bib`,本地预览后选择保存;提示精确重复、可能重复和缺失字段。
|
|
12
|
+
- 显式从 Crossref 补全作者、年份等空字段;保留已有内容并显示差异,支持部分失败重试。
|
|
13
|
+
- 切换 GB/T 7714、APA、MLA 或 Chicago 基本引文格式,下载 BibTeX、参考文献文本及含原始来源的完整备份。
|
|
14
|
+
- 原有 DOI 查询、题录搜索和 DOI 检查工具继续可用。
|
|
28
15
|
|
|
29
16
|
## 安装
|
|
30
17
|
|
|
31
|
-
|
|
32
|
-
dsh plugin --profile web add dsh-cite
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## 卸载
|
|
18
|
+
桌面版可在「插件」面板按包名 `dsh-cite` 安装。已配置 dsh 命令时也可使用:
|
|
36
19
|
|
|
37
20
|
```bash
|
|
38
|
-
dsh plugin --profile
|
|
21
|
+
dsh plugin --profile desktop add dsh-cite
|
|
39
22
|
```
|
|
40
23
|
|
|
41
|
-
|
|
42
|
-
|
|
24
|
+
网页版把命令中的 `desktop` 改为 `web`。安装后重启 DSH。
|
|
43
25
|
|
|
44
|
-
##
|
|
26
|
+
## 开始使用
|
|
45
27
|
|
|
46
|
-
|
|
47
|
-
用户:给我 10.1038/nature12345 的 GB/T 7714 引用
|
|
48
|
-
Agent:
|
|
49
|
-
cite_format { doi: "10.1038/nature12345", style: "gb-t-7714" }
|
|
50
|
-
→ LeCun Y, Bengio Y, Hinton G. Deep learning[J]. Nature, 2015, 521(7553): 436-444.
|
|
28
|
+
打开「设置 → Cite」,粘贴 DOI 或上传 `.bib`,点击「本地预览」,核对后「保存所选」。需要联网查询时再选择文献并点击「从 Crossref 在线补全所选项」。界面跟随 DSH 的中文 / English 设置,文献内容保持原文。
|
|
51
29
|
|
|
52
|
-
|
|
53
|
-
Agent:
|
|
54
|
-
cite_check { text: "..." }
|
|
55
|
-
```
|
|
30
|
+
也可对 Agent 说:“先本地预览这些 DOI,把我选中的条目保存到文献库,再导出 APA 参考文献和 BibTeX。”
|
|
56
31
|
|
|
57
|
-
##
|
|
32
|
+
## 依赖与配置
|
|
58
33
|
|
|
59
|
-
|
|
60
|
-
- id: cite
|
|
61
|
-
name: 'dsh-cite'
|
|
62
|
-
config:
|
|
63
|
-
timeoutMs: 15000 # Crossref 请求超时(也可用 DSH_CITE_TIMEOUT_MS)
|
|
64
|
-
# userAgent: ... # 自定义 User-Agent(也可用 DSH_CITE_USER_AGENT)
|
|
65
|
-
userAgent: '' # 自定义 UA(建议带上可联系邮箱)
|
|
66
|
-
```
|
|
34
|
+
本地导入、去重、文献库和格式切换不需要网络。在线补全及原有查询工具通过 Crossref,需要网络连接,不需要额外账号密钥。每批最多 256 KiB / 100 条,文献库最多 500 条。
|
|
67
35
|
|
|
68
|
-
|
|
36
|
+
引文采用原插件的基本模板;正式提交前核对学校或期刊要求。BibTeX 导出只包含已映射字段,完整备份保留未映射字段所在的原始输入。
|
|
69
37
|
|
|
70
|
-
|
|
71
|
-
- 引文为纯文本输出;格式按常见模板生成,正式投稿前请核对目标期刊的细节要求
|
|
72
|
-
- 不采集、不上传任何本地文献数据
|
|
38
|
+
详细配置、工具参数与排错见[使用说明](docs/USAGE.md)。从源码独立开发时,Node 要求以 [package.json](package.json) 为准。
|
|
73
39
|
|
|
74
|
-
##
|
|
40
|
+
## 文档
|
|
75
41
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
42
|
+
- [使用与排错](docs/USAGE.md)
|
|
43
|
+
- [更新记录](CHANGELOG.md)
|
|
44
|
+
- [验证范围与历史记录](docs/VALIDATION.md)
|
|
45
|
+
- [问题反馈与功能建议](https://github.com/STARDUSTLC666/dsh-cite/issues)
|
|
79
46
|
|
|
80
|
-
MIT
|
|
81
47
|
## License
|
|
82
48
|
|
|
83
|
-
MIT
|
|
49
|
+
[MIT](LICENSE)
|
package/cordis.patch.yml
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Historical release notes
|
|
2
|
+
|
|
3
|
+
[Current changelog](../CHANGELOG.md) · [Overview](../README.en.md)
|
|
4
|
+
|
|
5
|
+
These English notes preserve the earlier translations. The main changelog contains the consolidated version history.
|
|
6
|
+
|
|
7
|
+
## 0.4.1 (2026-10-03)
|
|
8
|
+
|
|
9
|
+
Fixes re-importing exported BibTeX containing publisher lists. Publisher names and original sources remain intact. All 41 Windows tests and re-importing the actual browser download pass.
|
|
10
|
+
|
|
11
|
+
## 0.4.0 (2026-10-03)
|
|
12
|
+
|
|
13
|
+
Adds a Chinese / English citation workbench and `cite_batch` for offline DOI / BibTeX preview, selective import, duplicate review, search and basic citation exports. Explicit Crossref enrichment fills empty fields, retains local differences and supports progress, cancellation and retry. Original input is preserved in full backups; revision checks protect concurrent changes. The existing five tools remain available.
|
|
14
|
+
|
|
15
|
+
Official RC2 / alpha SDK checks, Windows tests and visible browser flows pass. Native desktop interaction with this new workbench remains unverified; see the [validation record](VALIDATION.md).
|
|
16
|
+
|
|
17
|
+
## 0.3.4 (2026-09-27)
|
|
18
|
+
|
|
19
|
+
Preserves given/family name boundaries and compound surnames in BibTeX. Corporate authors are protected with braces instead of being parsed as personal names.
|
|
20
|
+
|
|
21
|
+
Validation host: Harness `0.2.0-rc.1` built from official sources (commit `407e65c8`) with Node `24.16.0` on 2026-09-28. All 25 plugin tests pass in an isolated environment; all 18 plugins mount together in one host registering 5 tools, with tool schemas and health-check contracts passing. No live ports or external services were exercised in this round.
|
package/docs/USAGE.en.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# dsh-cite usage guide
|
|
2
|
+
|
|
3
|
+
[Overview](../README.en.md) · [Changelog](../CHANGELOG.md) · [Validation](VALIDATION.md)
|
|
4
|
+
|
|
5
|
+
## Citation workbench
|
|
6
|
+
|
|
7
|
+
1. Open **Settings → Cite**. Paste one DOI per line, paste BibTeX, or upload a `.bib` file.
|
|
8
|
+
2. Choose **Local preview** and review missing fields and duplicate warnings. Exact DOI duplicates cannot be selected. Possible duplicates without DOIs start unselected; review them before opting in.
|
|
9
|
+
3. **Save selected**. Input survives closing settings, but save it before reloading the browser. Uploading does not modify the original file.
|
|
10
|
+
4. Select saved entries and explicitly request **Crossref online enrichment**. Only empty fields are filled; existing values stay intact and differences appear under **Metadata and sources**. Select failed entries to retry. Cancelling prevents this job's enrichment from being written.
|
|
11
|
+
5. Switch the basic citation style or preview an individual reference in its details. BibTeX / reference downloads include selected entries, or the whole library when none are selected. Full backups always include the whole library and original input.
|
|
12
|
+
|
|
13
|
+
The UI follows DSH's Chinese / English preference. Bibliographic content stays in its original language and shares one library. The four existing styles are basic templates; check institution, journal and document-type requirements separately.
|
|
14
|
+
|
|
15
|
+
Limits: 256 KiB / 100 entries per batch, 500 saved entries, five seconds for local parsing. Data lives in `DSH_HOME/data/dsh-cite/library.json`. Revision checks prevent stale previews from overwriting concurrent edits. On a conflict, retain input, refresh and preview again. Invalid library files are preserved rather than silently reset.
|
|
16
|
+
|
|
17
|
+
Local BibTeX parsing uses Citation.js, including macros, nested braces, literal institutional authors and compound surnames. The workbench maps common fields. Unmapped custom fields remain in the backup's original source text; generated BibTeX is not a verbatim round trip. JSON backups currently provide inspection and preservation, without a one-click restore UI.
|
|
18
|
+
|
|
19
|
+
## Tools
|
|
20
|
+
|
|
21
|
+
| Tool | Purpose | Key parameters |
|
|
22
|
+
| :-- | :-- | :-- |
|
|
23
|
+
| `cite_lookup` | Look up metadata by DOI or bibliographic query | `doi` or `query`; `limit` 1-10, default 5 |
|
|
24
|
+
| `cite_format` | Generate a basic formatted citation | `doi`; `style`: gb-t-7714 / apa / mla / chicago |
|
|
25
|
+
| `cite_bibtex` | Generate a BibTeX entry | `doi`; `key` optional |
|
|
26
|
+
| `cite_check` | Extract DOIs from text and validate them | `text`; `maxChecks` 1-50, default 10 |
|
|
27
|
+
| `cite_health` | Self-check: probe Crossref connectivity and report latency | none |
|
|
28
|
+
| `cite_batch` | Local library shared with the settings page | `action`: list / preview / import / enrich / job / cancel / export |
|
|
29
|
+
|
|
30
|
+
`preview` accepts `kind: doi / bibtex`, `text` and optional `label`, returning a preview ID and zero-based row indices. `import` accepts that `preview` and a `selection` array. `enrich` accepts saved entry `ids` and the current `revision`, returning a job ID; use `job` / `cancel` to inspect or cancel it. `export` accepts `kind: bibtex / references / backup`, optional `style` / `lang`, and optional entry `ids`; full backups cannot be scoped to a selection.
|
|
31
|
+
|
|
32
|
+
## Network and data
|
|
33
|
+
|
|
34
|
+
Import, deduplication, formatting and backups work offline. Explicit enrichment sends selected DOIs to Crossref. Existing lookup, search and health tools also contact Crossref. The plugin does not upload BibTeX files, original source text or the entire library. No separate API key is needed.
|
|
35
|
+
|
|
36
|
+
No VPN or proxy is required by the plugin. Online queries depend on whether your network can reach Crossref; failures preserve saved data and can be retried later. The plugin and its new Citation.js / proper-lockfile dependencies are MIT licensed.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
dsh plugin --profile web add dsh-cite
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Uninstall
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
dsh plugin --profile web remove dsh-cite
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Then restart the web service. To clean up fully, also remove the plugin entry from your profile `cordis.patch.yml` if you overrode it.
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT (see [LICENSE](../LICENSE))
|
package/docs/USAGE.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# dsh-cite 使用说明
|
|
2
|
+
|
|
3
|
+
[返回简介](../README.md) · [更新记录](../CHANGELOG.md) · [验证记录](VALIDATION.md)
|
|
4
|
+
|
|
5
|
+
## 文献工作台
|
|
6
|
+
|
|
7
|
+
1. 打开「设置 → Cite」,选择 DOI 列表或 BibTeX。DOI 每行一条,也可上传 `.bib` 文件。
|
|
8
|
+
2. 点击「本地预览」,核对缺失字段与重复提示,选择要保存的条目。精确 DOI 重复不能再次导入;无 DOI 的可能重复项默认不选,可人工确认后选择。
|
|
9
|
+
3. 点击「保存所选」。输入在关闭设置后仍保留;刷新整个浏览器前应保存。上传不会改写原文件。
|
|
10
|
+
4. 需要元数据时,选择库中条目,点击「从 Crossref 在线补全所选项」。只补空字段;已有内容不覆盖,差异显示在「元数据与来源」中。失败项可重新选择后重试,取消本次任务不会写入该任务的补全结果。
|
|
11
|
+
5. 切换基本引文格式,或在条目详情中预览单条引文。BibTeX / 参考文献文本下载范围为所选项,未选择时下载全库;完整备份始终包括全库及原始来源。
|
|
12
|
+
|
|
13
|
+
界面跟随 DSH 的中文 / English 设置,不翻译或复制文献数据。导出沿用四种基本格式;不同文献类型、学校或期刊的细节要求需另行核对。
|
|
14
|
+
|
|
15
|
+
每批最多 256 KiB / 100 条,库最多 500 条;本地解析有 5 秒时间限制。文献库保存在 `DSH_HOME/data/dsh-cite/library.json`。并发窗口的修订检查会阻止旧预览覆盖新数据;遇到冲突,保留输入并刷新、重新预览。损坏的库文件会保留,不会自动重置。
|
|
16
|
+
|
|
17
|
+
BibTeX 解析使用 Citation.js 的本地解析器,支持宏、嵌套括号、机构作者和复合姓氏。工作台采用常用字段模型;未映射的自定义字段仍存在完整备份的原始输入中,不能把导出的 BibTeX 当成逐字往返复制。完整备份目前用于核对和恢复原始资料,尚无一键 JSON 恢复入口。
|
|
18
|
+
|
|
19
|
+
## 工具
|
|
20
|
+
|
|
21
|
+
| 工具 | 作用 | 关键参数 |
|
|
22
|
+
| :-- | :-- | :-- |
|
|
23
|
+
| `cite_lookup` | 查文献元数据(DOI 精确查询 / 题录检索) | `doi` 或 `query` 至少一个;`limit` 1-10 默认 5 |
|
|
24
|
+
| `cite_format` | 生成基本格式引文 | `doi` 必填;`style`:gb-t-7714 / apa / mla / chicago |
|
|
25
|
+
| `cite_bibtex` | 生成 BibTeX 条目 | `doi` 必填;`key` 可选 |
|
|
26
|
+
| `cite_check` | 从文本提取 DOI 并并发校验是否存在(并发 3,保持输入顺序) | `text` 必填;`maxChecks` 1-50 默认 10 |
|
|
27
|
+
| `cite_health` | 自检:探测 Crossref 连通性并报告延迟 | 无 |
|
|
28
|
+
| `cite_batch` | 本地文献工作台,与设置页共用文献库 | `action`:list / preview / import / enrich / job / cancel / export |
|
|
29
|
+
|
|
30
|
+
`cite_batch` 的 `preview` 接受 `kind: doi / bibtex`、`text` 和可选 `label`;返回预览编号和零起始行编号。`import` 接受 `preview` 与 `selection` 数组。`enrich` 接受已保存条目的 `ids` 与当前 `revision`,返回 `job` 编号;用 `job` / `cancel` 操作查询或取消。`export` 的 `kind` 为 bibtex / references / backup,可指定 `style`、`lang`;条目选择为可选 `ids`,完整备份不得附带选择。
|
|
31
|
+
|
|
32
|
+
## 安装
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
dsh plugin --profile web add dsh-cite
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 卸载
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
dsh plugin --profile web remove dsh-cite
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
卸载后重启 Web 服务。如需彻底清理,可再手动删除自己 profile `cordis.patch.yml` 中覆盖的插件行。
|
|
45
|
+
|
|
46
|
+
## 示例
|
|
47
|
+
|
|
48
|
+
示例论文:[Deep learning, Nature (2015)](https://www.nature.com/articles/nature14539)。
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
用户:给我 10.1038/nature14539 的 GB/T 7714 引用
|
|
52
|
+
Agent:
|
|
53
|
+
cite_format { doi: "10.1038/nature14539", style: "gb-t-7714" }
|
|
54
|
+
→ LeCun Y, Bengio Y, Hinton G. Deep learning[J]. Nature, 2015, 521(7553): 436-444.
|
|
55
|
+
|
|
56
|
+
用户:检查这段参考文献的 DOI 是否有效
|
|
57
|
+
Agent:
|
|
58
|
+
cite_check { text: "..." }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 配置
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
- id: cite
|
|
65
|
+
name: 'dsh-cite'
|
|
66
|
+
config:
|
|
67
|
+
timeoutMs: 15000 # Crossref 请求超时(也可用 DSH_CITE_TIMEOUT_MS)
|
|
68
|
+
# userAgent: ... # 自定义 User-Agent(也可用 DSH_CITE_USER_AGENT)
|
|
69
|
+
userAgent: '' # 自定义 UA(建议带上可联系邮箱)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 说明
|
|
73
|
+
|
|
74
|
+
- 数据源:Crossref REST API,无需 API key
|
|
75
|
+
- 引文为纯文本输出;格式按常见模板生成,正式投稿前请核对目标期刊的细节要求
|
|
76
|
+
- 本地导入、去重、格式化和备份不会联网。在线补全把选中的 DOI 发给 Crossref;原有查询、搜索和健康检查工具也会联系 Crossref。不会上传 BibTeX 文件、原始来源或整库。
|
|
77
|
+
- 不需要关闭 VPN 或强制使用代理;能否在线查询取决于当前网络能否访问 Crossref。失败不会丢失本地文献,可稍后重试。
|
|
78
|
+
|
|
79
|
+
本插件及新增依赖 Citation.js、proper-lockfile 均使用 MIT 许可;发布包不包含宿主密钥。
|
|
80
|
+
|
|
81
|
+
## 开发
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pnpm test # 构建并执行测试
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT(见 [LICENSE](../LICENSE))
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# dsh-cite 验证记录
|
|
2
|
+
|
|
3
|
+
本页整理原 README 的历史验证说明,保留当时的版本、日期与范围。自动测试、启动检查、浏览器操作和真实服务验收分别记录,不能相互替代。更详细的版本验收文件仍保留在仓库中。
|
|
4
|
+
|
|
5
|
+
## 0.4.1(含 0.4.0 功能,2026-10-03)
|
|
6
|
+
|
|
7
|
+
- Windows:41 项自动测试全部通过,无跳过。覆盖嵌套 BibTeX、宏、机构作者、复合姓氏、出版社列表的导出再导入、畸形输入、容量边界、精确与候选重复、并发修订冲突、部分失败重试、取消不写入、元数据差异保留和英文错误信息。
|
|
8
|
+
- 宿主契约:官方源码构建的 RC2(639ed015)和公开 npm 包 `0.2.1-alpha.1` 均在 E 盘隔离环境测试;18 插件共同注册 110 工具、35 技能,19 输出样例通过 schema 检查。未配置真实账号的健康检查可返回未配置,这不表示真实服务连接通过。
|
|
9
|
+
- 可见浏览器操作:官方 alpha 的设置页中实际上传 `.bib`、本地预览、选择保存、关闭 / 重开设置保留输入、搜索、引文预览及三种下载。DOI 大小写与链接形式的重复被跳过,错误行不可保存。中英文切换使用同一份两条题录的文献库,修订与原始资料未改变;390px 布局另作可见检查。
|
|
10
|
+
- 真实 Crossref:显式查询 `10.1038/nature12345`,作者、年份等空字段已补全;本地测试标题被保留,实际提供者标题作为差异显示。曾出现网络请求失败,重试后成功;不把网络波动当作已定位或修复的代理问题。没有 DOI 的条目显示单独失败。
|
|
11
|
+
- 备份核对:从实际下载取得的 JSON 包含两条文献、修订 2、原始 `.bib`、已填字段和标题差异;原始来源逐字保留。测试题录为合成数据,不能作为实际论文元数据使用。
|
|
12
|
+
- 生产依赖审计无已知漏洞。Citation.js 与 proper-lockfile 均使用 MIT 许可。
|
|
13
|
+
|
|
14
|
+
边界:本轮没有操作用户原生桌面窗口,没有上传真实文献库,也没有配置模型密钥。网页验证和桌面来源检查不能替代桌面新工作台的可见操作验收。四种引文采用基本模板,没有声明覆盖各期刊的全部规范。
|
|
15
|
+
|
|
16
|
+
## 原中文记录
|
|
17
|
+
|
|
18
|
+
## 0.3.5 原验证说明
|
|
19
|
+
|
|
20
|
+
验证宿主:官方源码构建的 Harness `0.2.0-rc.1`(commit `407e65c8`)+ Node `24.16.0`(2026-09-28)。25 项插件测试在隔离环境全部通过;同一个宿主里 18 个插件共同加载,注册 5 个工具,工具 schema 与健康检查契约通过。本轮未启用真实端口与外部服务。
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** English UI messages; bibliographic content and original source text stay unchanged. */
|
|
2
|
+
export function englishCitationError(raw) {
|
|
3
|
+
if (/^Crossref 请求失败:/.test(raw))
|
|
4
|
+
return raw.replace(/^Crossref 请求失败:/, 'Crossref request failed: ');
|
|
5
|
+
if (/^DOI 在 Crossref 中不存在:/.test(raw))
|
|
6
|
+
return raw.replace(/^DOI 在 Crossref 中不存在:/, 'DOI not found in Crossref: ');
|
|
7
|
+
if (/^Crossref 返回 HTTP/.test(raw))
|
|
8
|
+
return 'Crossref returned HTTP ' + (/HTTP (\d+)/.exec(raw)?.[1] || 'error') + '. Check network access or retry later.';
|
|
9
|
+
if (/DOI 格式不正确/.test(raw))
|
|
10
|
+
return 'Invalid DOI. Use a DOI such as 10.1038/nature12345, or its https://doi.org/ URL.';
|
|
11
|
+
if (/没有 DOI/.test(raw))
|
|
12
|
+
return 'This entry has no DOI and cannot be enriched through Crossref.';
|
|
13
|
+
if (/DOI 不匹配/.test(raw))
|
|
14
|
+
return 'Crossref returned a different DOI. The local entry was preserved.';
|
|
15
|
+
if (/已取消|解析已取消/.test(raw))
|
|
16
|
+
return 'Cancelled. This job did not write its enrichment into the library.';
|
|
17
|
+
if (/另一窗口更新|已更新|DOI 已存在/.test(raw))
|
|
18
|
+
return 'The library changed elsewhere. Your input is retained. Refresh and preview again before saving.';
|
|
19
|
+
if (/预览已过期/.test(raw))
|
|
20
|
+
return 'The preview expired or DSH restarted. Your input is retained; preview it again.';
|
|
21
|
+
if (/文献库记录损坏|文献库文件无效/.test(raw))
|
|
22
|
+
return 'The library file is invalid. It has been preserved. Back it up before investigating.';
|
|
23
|
+
if (/最多保存 500|超过 8|文献库.*容量限制/.test(raw))
|
|
24
|
+
return 'The library capacity has been reached. Back it up before importing more; this operation was not saved.';
|
|
25
|
+
if (/超过 256|超过 100|1–100|单批不能超过|请求超过容量限制/.test(raw))
|
|
26
|
+
return 'Import up to 256 KiB and 100 entries at a time. Split the input and retry; no partial batch was saved.';
|
|
27
|
+
if (/选择包含错误或精确重复|重复编号|选择中不能|有效预览/.test(raw))
|
|
28
|
+
return 'Select valid entries once each. Exact DOI duplicates cannot be imported.';
|
|
29
|
+
if (/请选择.*文献|至少选择/.test(raw))
|
|
30
|
+
return 'Select 1–100 entries before continuing.';
|
|
31
|
+
if (/解析失败|没有找到可导入|解析未完成/.test(raw))
|
|
32
|
+
return 'The input could not be parsed. Check BibTeX braces and commas, or use one DOI per line. Your original input is retained.';
|
|
33
|
+
if (/解析超过/.test(raw))
|
|
34
|
+
return 'Local parsing took more than five seconds. Split the input and retry.';
|
|
35
|
+
if (/正在解析|已有补全/.test(raw))
|
|
36
|
+
return 'A job is already running. Wait for it or cancel it before continuing.';
|
|
37
|
+
if (/不存在或 DSH|所选文献已不存在|不存在的文献/.test(raw))
|
|
38
|
+
return 'The selection or job is no longer available. Saved entries are retained; refresh the library.';
|
|
39
|
+
if (/输入类型/.test(raw))
|
|
40
|
+
return 'Input type must be DOI or BibTeX.';
|
|
41
|
+
if (/请先粘贴|请提供 DOI/.test(raw))
|
|
42
|
+
return 'Paste DOI / BibTeX input, or choose a .bib file first.';
|
|
43
|
+
if (/完整备份/.test(raw))
|
|
44
|
+
return 'A full backup includes every entry and original source, independent of selection.';
|
|
45
|
+
if (/文献库为空/.test(raw))
|
|
46
|
+
return 'The library is empty. Import entries before exporting references.';
|
|
47
|
+
if (!/[\u3400-\u9fff]/.test(raw))
|
|
48
|
+
return raw;
|
|
49
|
+
return 'The operation could not be completed. Check the input or refresh and retry. Saved entries and original sources are preserved.';
|
|
50
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type Work } from './crossref.js';
|
|
2
|
+
export declare const MAX_INPUT_BYTES: number;
|
|
3
|
+
export declare const MAX_BATCH = 100;
|
|
4
|
+
export declare const MAX_LIBRARY = 500;
|
|
5
|
+
export interface ImportInput {
|
|
6
|
+
kind: 'doi' | 'bibtex';
|
|
7
|
+
text: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ImportRow {
|
|
11
|
+
index: number;
|
|
12
|
+
key: string;
|
|
13
|
+
work: Work | null;
|
|
14
|
+
warnings: string[];
|
|
15
|
+
error?: string;
|
|
16
|
+
errorEn?: string;
|
|
17
|
+
duplicate?: 'batch' | 'library';
|
|
18
|
+
candidate?: boolean;
|
|
19
|
+
selectedDefault?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface SourceRecord extends ImportInput {
|
|
22
|
+
id: string;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
}
|
|
25
|
+
export interface FieldConflict {
|
|
26
|
+
field: string;
|
|
27
|
+
local: unknown;
|
|
28
|
+
crossref: unknown;
|
|
29
|
+
}
|
|
30
|
+
export interface LibraryEntry {
|
|
31
|
+
id: string;
|
|
32
|
+
work: Work;
|
|
33
|
+
bibKey: string;
|
|
34
|
+
sourceIds: string[];
|
|
35
|
+
createdAt: string;
|
|
36
|
+
updatedAt: string;
|
|
37
|
+
crossref?: {
|
|
38
|
+
doi: string;
|
|
39
|
+
fetchedAt: string;
|
|
40
|
+
filled: string[];
|
|
41
|
+
conflicts: FieldConflict[];
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface CitationLibrary {
|
|
45
|
+
version: 1;
|
|
46
|
+
revision: number;
|
|
47
|
+
entries: LibraryEntry[];
|
|
48
|
+
sources: SourceRecord[];
|
|
49
|
+
}
|
|
50
|
+
/** Never render provider/BibTeX markup as HTML. Keep the original source separately. */
|
|
51
|
+
export declare function plainText(value: unknown): string;
|
|
52
|
+
export declare function normalizeWork(value: unknown): Work;
|
|
53
|
+
export declare function workWarnings(work: Work): string[];
|
|
54
|
+
export declare function candidateKey(work: Work): string;
|
|
55
|
+
export declare function readImportInput(value: unknown): ImportInput;
|
|
56
|
+
export declare function citationId(value: unknown): string;
|
|
57
|
+
export declare function readSelection(value: unknown, max?: number): string[];
|
|
58
|
+
export declare class LibraryConflict extends Error {
|
|
59
|
+
readonly status = 409;
|
|
60
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { assertDoi } from './crossref.js';
|
|
2
|
+
export const MAX_INPUT_BYTES = 256 * 1024;
|
|
3
|
+
export const MAX_BATCH = 100;
|
|
4
|
+
export const MAX_LIBRARY = 500;
|
|
5
|
+
/** Never render provider/BibTeX markup as HTML. Keep the original source separately. */
|
|
6
|
+
export function plainText(value) {
|
|
7
|
+
if (value === undefined || value === null)
|
|
8
|
+
return '';
|
|
9
|
+
if (typeof value !== 'string' && typeof value !== 'number')
|
|
10
|
+
throw new Error('文献字段不是文本。');
|
|
11
|
+
const text = String(value);
|
|
12
|
+
if (text.length > 16384)
|
|
13
|
+
throw new Error('单个文献字段过长,请拆分或检查原始数据。');
|
|
14
|
+
return text.replace(/<[^>]*>/g, '').replace(/&(?:amp|lt|gt|quot|apos|nbsp);/g, token => ({ '&': '&', '<': '<', '>': '>', '"': '"', ''': "'", ' ': ' ' }[token]))
|
|
15
|
+
.replace(/&#(x[0-9a-f]+|\d+);/gi, (_, code) => { const n = code[0].toLowerCase() === 'x' ? parseInt(code.slice(1), 16) : Number(code); return n > 0 && n <= 0x10ffff && !(n >= 0xd800 && n <= 0xdfff) ? String.fromCodePoint(n) : '�'; })
|
|
16
|
+
.replace(/\s+/g, ' ').trim();
|
|
17
|
+
}
|
|
18
|
+
export function normalizeWork(value) {
|
|
19
|
+
if (!value || typeof value !== 'object')
|
|
20
|
+
throw new Error('文献记录无效。');
|
|
21
|
+
const raw = value, authors = raw.authors ?? [];
|
|
22
|
+
if (!Array.isArray(authors) || authors.length > 2000)
|
|
23
|
+
throw new Error('作者列表无效或超过 2000 人。');
|
|
24
|
+
const work = {
|
|
25
|
+
doi: plainText(raw.doi), type: plainText(raw.type) || 'other', title: plainText(raw.title),
|
|
26
|
+
authors: authors.map(a => { if (!a || typeof a !== 'object')
|
|
27
|
+
throw new Error('作者记录无效。'); return { given: plainText(a.given), family: plainText(a.family), name: plainText(a.name) }; }).filter(a => a.given || a.family || a.name),
|
|
28
|
+
containerTitle: plainText(raw.containerTitle), publisher: plainText(raw.publisher), year: typeof raw.year === 'number' && Number.isInteger(raw.year) && raw.year > 0 && raw.year <= 9999 ? raw.year : 0,
|
|
29
|
+
language: plainText(raw.language), volume: plainText(raw.volume), issue: plainText(raw.issue), page: plainText(raw.page), url: plainText(raw.url), isbn: plainText(raw.isbn),
|
|
30
|
+
};
|
|
31
|
+
if (work.doi)
|
|
32
|
+
work.doi = assertDoi(work.doi).toLowerCase();
|
|
33
|
+
return work;
|
|
34
|
+
}
|
|
35
|
+
export function workWarnings(work) {
|
|
36
|
+
return [!work.title && 'missing_title', !work.authors.length && 'missing_authors', !work.year && 'missing_year', !work.doi && 'missing_doi'].filter((v) => !!v);
|
|
37
|
+
}
|
|
38
|
+
export function candidateKey(work) {
|
|
39
|
+
if (!work.title)
|
|
40
|
+
return '';
|
|
41
|
+
const author = work.authors[0], name = author ? author.name || [author.family, author.given].join(' ') : '';
|
|
42
|
+
const norm = (s) => s.normalize('NFKC').toLowerCase().replace(/[^\p{L}\p{N}]/gu, '');
|
|
43
|
+
return [norm(work.title), work.year, norm(name)].join('|');
|
|
44
|
+
}
|
|
45
|
+
export function readImportInput(value) {
|
|
46
|
+
if (!value || typeof value !== 'object')
|
|
47
|
+
throw new Error('请提供 DOI 列表或 BibTeX 文本。');
|
|
48
|
+
const v = value;
|
|
49
|
+
if (!['doi', 'bibtex'].includes(String(v.kind)))
|
|
50
|
+
throw new Error('输入类型只能是 doi 或 bibtex。');
|
|
51
|
+
if (typeof v.text !== 'string' || !v.text.trim())
|
|
52
|
+
throw new Error('请先粘贴 DOI / BibTeX,或选择 .bib 文件。');
|
|
53
|
+
if (Buffer.byteLength(v.text) > MAX_INPUT_BYTES)
|
|
54
|
+
throw new Error('单次输入不能超过 256 KiB,请拆分导入。');
|
|
55
|
+
const label = typeof v.label === 'string' ? v.label.replace(/^.*[\\/]/, '').trim() : '';
|
|
56
|
+
if (label.length > 160)
|
|
57
|
+
throw new Error('来源名称过长。');
|
|
58
|
+
return { kind: v.kind, text: v.text, label: label || (v.kind === 'doi' ? 'DOI list' : 'BibTeX') };
|
|
59
|
+
}
|
|
60
|
+
export function citationId(value) {
|
|
61
|
+
if (typeof value !== 'string' || !/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(value))
|
|
62
|
+
throw new Error('文献、预览或任务编号无效。');
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
export function readSelection(value, max = MAX_BATCH) {
|
|
66
|
+
if (!Array.isArray(value) || !value.length || value.length > max)
|
|
67
|
+
throw new Error(`请选择 1–${max} 条文献。`);
|
|
68
|
+
const ids = value.map(citationId);
|
|
69
|
+
if (new Set(ids).size !== ids.length)
|
|
70
|
+
throw new Error('文献选择中不能有重复编号。');
|
|
71
|
+
return ids;
|
|
72
|
+
}
|
|
73
|
+
export class LibraryConflict extends Error {
|
|
74
|
+
status = 409;
|
|
75
|
+
}
|