dsh-zotero 0.3.2 → 0.4.0

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.
Files changed (41) hide show
  1. package/README.en.md +67 -173
  2. package/README.md +67 -173
  3. package/lib/client.js +2113 -1230
  4. package/lib/client.js.map +4 -4
  5. package/lib/config.d.ts.map +1 -1
  6. package/lib/config.js +29 -1
  7. package/lib/config.js.map +1 -1
  8. package/lib/constants.d.ts +7 -0
  9. package/lib/constants.d.ts.map +1 -1
  10. package/lib/constants.js +7 -0
  11. package/lib/constants.js.map +1 -1
  12. package/lib/export-items.d.ts +29 -0
  13. package/lib/export-items.d.ts.map +1 -0
  14. package/lib/export-items.js +61 -0
  15. package/lib/export-items.js.map +1 -0
  16. package/lib/export-mapping.d.ts +80 -0
  17. package/lib/export-mapping.d.ts.map +1 -0
  18. package/lib/export-mapping.js +215 -0
  19. package/lib/export-mapping.js.map +1 -0
  20. package/lib/normalize.d.ts.map +1 -1
  21. package/lib/normalize.js +4 -0
  22. package/lib/normalize.js.map +1 -1
  23. package/lib/presentation-meta.d.ts +89 -6
  24. package/lib/presentation-meta.d.ts.map +1 -1
  25. package/lib/presentation-meta.js +71 -7
  26. package/lib/presentation-meta.js.map +1 -1
  27. package/lib/provider-local.d.ts +17 -1
  28. package/lib/provider-local.d.ts.map +1 -1
  29. package/lib/provider-local.js +97 -6
  30. package/lib/provider-local.js.map +1 -1
  31. package/lib/tools/export.d.ts +53 -3
  32. package/lib/tools/export.d.ts.map +1 -1
  33. package/lib/tools/export.js +39 -6
  34. package/lib/tools/export.js.map +1 -1
  35. package/lib/tools/retrieve.d.ts +6 -0
  36. package/lib/tools/retrieve.d.ts.map +1 -1
  37. package/lib/tools/retrieve.js +9 -3
  38. package/lib/tools/retrieve.js.map +1 -1
  39. package/lib/types.d.ts +42 -3
  40. package/lib/types.d.ts.map +1 -1
  41. package/package.json +3 -2
package/README.en.md CHANGED
@@ -18,219 +18,113 @@
18
18
  <a href="README.md"><b>中文</b></a> · <b>English</b>
19
19
  </p>
20
20
 
21
- Let agents discover sources in your [Zotero](https://www.zotero.org) library, extract the evidence relevant to a question, and always keep the link between evidence and the source document.
21
+ dsh-zotero is a [Zotero](https://www.zotero.org) plugin designed for agent research workflows. Agents can search your library directly, view metadata and notes, extract evidence passages relevant to a question, open source PDFs, and generate citations and bibliographies.
22
22
 
23
- dsh-zotero is built for agent research workflows: from literature search and metadata/note inspection to evidence retrieval, opening the source, and citation generation, the Agent pulls what the current task needs step by step — without reading a whole paper or the whole library up front.
23
+ <p align="center">
24
+ <img src="docs/images/header-collage.png" width="70%" alt="dsh-zotero UI: sources panel, evidence extraction, export view">
25
+ </p>
24
26
 
25
27
  ## Tools
26
28
 
27
- | Tool | Purpose |
28
- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
29
- | `zotero_search` | Discover: search by title/creator/year, or indexed full text with `everything`; optionally scope to a collection or saved search. |
30
- | `zotero_get` | Inspect: read one item's structured core metadata, optionally with manifests and previews of its notes, annotations, and attachments. |
31
- | `zotero_retrieve` | Evidence: return the most relevant bounded evidence passages (annotations, notes, abstract, full-text chunks) for a query. |
32
- | `zotero_attachment` | Source: resolve an item or attachment ref to the original attachment's verified on-disk path or linked URL. |
33
- | `zotero_export` | Cite: let Zotero's own citation/export machinery produce citations, a CSL bibliography, or `bibtex` / `biblatex` / `ris` / `csljson`. |
34
-
35
- ## Usage example
36
-
37
- The Agent moves down the ladder as a request deepens. A typical conversation:
38
-
39
- > User: "Find papers about FlashAttention."
40
- > Agent → `zotero_search`, returning candidates with refs.
41
- >
42
- > User: "What is the first one? Have I read it before?"
43
- > Agent → `zotero_get`: metadata, 17 annotations, 2 notes, limited previews.
44
- >
45
- > User: "What did I think about its evaluation?"
46
- > Agent → `zotero_retrieve(query:"evaluation", sources:["annotations","notes"])`, returning matching note and annotation evidence.
47
- >
48
- > User: "How does the paper itself explain memory efficiency?"
49
- > Agent → `zotero_retrieve(query:"memory efficiency", sources:["fulltext","abstract"])`, returning abstract and full-text passages.
50
- >
51
- > User: "Show me the original PDF."
52
- > Agent → `zotero_attachment(item ref)`, returning the verified file path; if the composition has a PDF/file reader, the Agent hands it off for further analysis.
53
- >
54
- > User: "Generate an APA bibliography for these three."
55
- > Agent → `zotero_export(format:"bibliography", style:"apa")`.
56
-
57
- ## Command
58
-
59
- `/zotero status` reports connectivity, API/schema versions, and the database identity (Server ID, Zotero 10+). This is the only health check. Ordinary calls fail with typed domain errors.
60
-
61
- ## Requirements
62
-
63
- - Zotero desktop with the local API enabled: **Settings → Advanced → "Allow other applications on this computer to communicate with Zotero"**.
64
- - Read access is unauthenticated on `http://127.0.0.1:23119/api`. V1 has no path that modifies library data (items, notes, tags, collections).
65
- - Zotero ≥ 7 speaking local API version 3. Upgrade if the status command reports a version mismatch.
66
- - Node.js ≥ 22.19 (or 24+); the host dsh runtime is the rc.7 line. Runtime peer dependencies are declared in `package.json` `peerDependencies` (`@deepseek-ai/cordis` ≥ 4, `dsh-tools`, `dsh-llm`, `dsh-settings`, `dsh-user-questions`, `dsh-typert-protocol`, `dsh-typert-registry`, `dsh-api-remotes`, `dsh-commands`, `dsh-timeout`), all currently `^0.1.0-rc.7`.
67
-
68
- ### Capability boundary and side effects
29
+ | Tool | Purpose |
30
+ | ------------------- | ------------------------------------------------------------------------------- |
31
+ | `zotero_search` | Search by title/creator/year; `everything` mode also searches indexed full text |
32
+ | `zotero_get` | Read one item's metadata, optionally with notes, annotations, and attachments |
33
+ | `zotero_retrieve` | Return the most relevant evidence passages for a query |
34
+ | `zotero_attachment` | Resolve a ref to a verified on-disk path or linked URL |
35
+ | `zotero_export` | Generate citations, bibliographies, BibTeX/BibLaTeX/RIS/CSL JSON |
69
36
 
70
- - Network: only the loopback-forced `http://127.0.0.1:23119/api` (redirects refused, streaming byte bound); no external network calls.
71
- - Files: only `existsSync` checks of attachment disk paths — never written, never executed.
72
- - Process: no shell calls, no native modules, no resident background tasks or timers — every request is driven by a tool call, and loading the plugin never probes Zotero.
73
- - External side effects: the only persistent write is the settings card saving the `zotero:` section (user layer) of `$DSH_HOME/settings.yaml`; no telemetry.
37
+ [Full tool reference →](docs/tools.md)
74
38
 
75
39
  ## Install
76
40
 
77
- ### By package name
78
-
79
41
  ```sh
80
42
  dsh plugin --profile <name> add dsh-zotero
81
43
  ```
82
44
 
83
- The tarball ships the built `lib/` (the node half plus the browser half `lib/client.js`); no local build is needed. The browser half is the configuration card: dsh web scans the package's `dsh.client` manifest and mounts it automatically, with no extra setup.
84
-
85
- ### From a local tarball
45
+ From GitHub source:
86
46
 
87
47
  ```sh
88
- cd dsh-zotero
89
- npm pack
90
- dsh plugin --profile <name> add ./dsh-zotero-0.3.1.tgz
48
+ dsh plugin --profile <name> add github:Vncntvx/dsh-zotero
91
49
  ```
92
50
 
93
- `npm pack` runs `prepare` first, so the tarball carries a fresh `lib/`. Use this for unpublished or local trial installs.
94
-
95
- ### From the GitHub source
51
+ From a local tarball:
96
52
 
97
53
  ```sh
98
- dsh plugin --profile <name> add github:Vncntvx/dsh-zotero
54
+ cd dsh-zotero && npm pack
55
+ dsh plugin --profile <name> add ./dsh-zotero-*.tgz
99
56
  ```
100
57
 
101
- A git install fetches sources instead of built artifacts, so pnpm installs the dependencies and then runs this package's `prepare` to build in place (TypeScript and `@types/node` live in `dependencies`). pnpm ≥ 10 refuses to run a git dependency's `prepare` by default, so the first `add` fails and points at the fix: add the package key to the profile's `pnpm-workspace.yaml` and re-run:
102
-
103
- ```yaml
104
- allowBuilds:
105
- dsh-zotero: true
106
- ```
58
+ After installing, start a new session so the agent picks up the Zotero tools.
107
59
 
108
- `allowBuilds` grants permission to run the package's code on your machine at install time. Only allow sources you trust, and prefer pinning a commit (`github:Vncntvx/dsh-zotero#<sha>`).
60
+ The plugin provides a settings card under **Settings Plugins** where you can adjust the API address, concurrency limits, full-text retrieval toggle, and more. Changes take effect on save. See [Configuration](docs/configuration.md).
109
61
 
110
- The plugin mounts as id `zotero` and takes effect on the next dsh start. After installing or enabling the plugin, start a new session if the current one was created before the plugin loaded, so the Agent picks up the Zotero tools.
62
+ [Installation details →](docs/getting-started.md)
111
63
 
112
- ## Configuration
64
+ ## Requirements
113
65
 
114
- All values are `Config` fields changeable from the bundle's `config` block (e.g. via `dsh plugin config`). Defaults are shown.
66
+ - Zotero 7 with local API enabled: **Settings Advanced "Allow other applications on this computer to communicate with Zotero"**
67
+ - Node.js ≥ 22.19 (or ≥ 24)
68
+ - Local API at `http://127.0.0.1:23119/api`, unauthenticated, read-only
115
69
 
116
- | Field | Default | Meaning |
117
- | ---------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
118
- | `baseUrl` | `http://127.0.0.1:23119/api` | Local API base URL. Plain loopback HTTP only. |
119
- | `provider` | `local` | Provider id to select. |
120
- | `timeoutMs` | `5000` | Per-request provider deadline. |
121
- | `maxSearchResults` | `20` | Upper bound for `zotero_search` `limit`. |
122
- | `maxNoteScanRecords` | `200` | Upper bound for note records scanned for body matches by `zotero_search`. |
123
- | `maxEvidenceChars` | `6000` | Total character budget for retrieved evidence. |
124
- | `maxEvidencePassages` | `4` | Upper bound for evidence passage counts. |
125
- | `maxDetailChars` | `3000` | Character budget for `zotero_get` abstract previews. |
126
- | `maxNoteBodyChars` | `30000` | Character budget for a note item's own body returned by `zotero_get`. |
127
- | `maxNoteChars` | `2000` | Character budget per note preview in `zotero_get`. |
128
- | `maxNoteRecords` | `50` | Upper bound for note records returned by `zotero_get`. |
129
- | `maxAnnotationRecords` | `100` | Upper bound for annotation records returned by `zotero_get`. |
130
- | `fulltextChunkWords` | `200` | Word count per full-text passage entering evidence ranking. |
131
- | `maxFulltextChars` | `250000` | Full text accepted into evidence ranking. |
132
- | `maxResponseBytes` | `16777216` | Streaming byte bound for every API response. |
133
- | `maxExportChars` | `1000000` | Export output hard limit. Never mid-truncated. |
134
- | `maxExportRefs` | `50` | Upper bound for refs in one `zotero_export` call; citation batches past the API's 50-key per-request cap. |
135
- | `defaultStyle` | `apa` | CSL style for citation/bibliography formats. |
136
- | `defaultLocale` | `en-US` | CSL locale for citation/bibliography formats. |
137
- | `webEnabled` | `true` | Enables the dedicated Zotero tab at the top of the session; the toggle applies live — turning it off hides the tab right away, no reload needed. |
70
+ ## Usage example
138
71
 
139
- ### Web configuration
72
+ The agent calls tools step by step during a conversation. Each result becomes context for the next step.
140
73
 
141
- The plugin registers a "Zotero" card in dsh web's **Settings → Plugins → Plugin configuration** page listing every field in the table above. The card binds the `zotero` settings namespace: writes land in the `zotero:` section of `$DSH_HOME/settings.yaml` (layered over the patch entry's `config`, user layer wins), and **saves apply live** — the transport and the provider rebuild on the new values, so the next tool call or `/zotero status` uses them without a dsh restart.
74
+ ```text
75
+ User: Find papers about Risk
76
+ Agent → zotero_search(query: "Risk", itemType: "journalArticle")
77
+ 5 matches; user picks the first 3
142
78
 
143
- - Invalid values (a non-loopback `baseUrl`, a non-positive limit) are refused before the write; the card reports the failed save and keeps the draft, and the plugin keeps running on the last valid value.
144
- - Every field shows its effective value; fields overridden by the settings document carry an "Overridden" badge and offer a one-click reset (clears the user layer, back to the patch entry value).
145
- - External edits to the settings document (e.g. editing `settings.yaml` directly) hot-apply too.
146
- - Compositions without a settings service (pure headless) never register the namespace, and the plugin behaves exactly as if unconfigured.
79
+ User: What does the first one's abstract say?
80
+ Agent zotero_get(ref: 1, fields: ["abstractNote"])
81
+ Returns the full abstract
147
82
 
148
- ### Web view
83
+ User: Find the methodology discussion in this paper
84
+ Agent → zotero_retrieve(query: "methodology", sources: ["fulltext", "notes"])
85
+ Returns relevant passages with page numbers
149
86
 
150
- The dsh web session view is a tab ring (Chat, Trajectory, …). The plugin registers a dedicated **Zotero** tab (`conversation.view`, id `zotero`, after Trajectory and dsh-context) and leaves dsh's built-in chat and trajectory display untouched:
87
+ User: Export all three as BibTeX
88
+ Agent → zotero_export(refs: [1,2,3], format: "bibtex")
89
+ Generates BibTeX entries, ready to copy or download
90
+ ```
151
91
 
152
- - A **connection strip** leads the tab: one status probe on mount, another per explicit Refresh (request-driven, no polling timers); it shows the connection state, API/schema versions, Server ID (Zotero 10+), and the last-checked time, with the diagnosis when Zotero is unavailable.
153
- - Below it, the session's **Zotero tool activity**: every search, read, retrieve, attachment, and export call renders as a rich card (expandable, copyable refs, evidence passages labeled by source), fully replay-driven from the conversation snapshot — the same transcript renders the same cards, and missing meta degrades to the raw content.
154
- - The **Web → Session tool cards** toggle in the settings page (`webEnabled`, default on) controls the tab's registration; the toggle applies live — turning it off hides the tab immediately, no reload needed. When off, Zotero calls show as dsh's built-in generic cards in the trajectory.
92
+ More examples in [Features](docs/features.md).
155
93
 
156
94
  ## Limits
157
95
 
158
- - Read-only library: no path modifies items, notes, tags, or collections.
159
- - Full-text evidence depends on Zotero's index: `everything` search and `retrieve` full-text passages both require indexing.
160
- - Note-content search is a client-side scan: library/collection scopes and the first result page (offset 0) only, bounded by `maxNoteScanRecords`; matches fill the first page up to the limit and are reported in the `noteMatches` field, outside the paged `total`.
161
- - Attachment depth depends on the harness composition: `zotero_attachment` returns the file location; reading that PDF further needs a matching file/PDF capability.
162
- - Evidence ranking is term-based relevance, not embedding or semantic search.
96
+ - **Read-only library**: all operations are reads; items, notes, tags, and collections are unchanged
97
+ - **Loopback only**: network requests go only to `127.0.0.1:23119`
98
+ - **Evidence ranking is term-based**: BM25 ranks passages by query-term frequency match
99
+ - **Exports are static text**: returned as text, ready to copy into your target document
100
+ - **Full-text evidence depends on Zotero's index**: unindexed PDFs yield no full-text passages
101
+ - **Attachment depth depends on the harness**: `zotero_attachment` returns the file location; reading the PDF further needs a matching host capability
102
+
103
+ ## Documentation
104
+
105
+ | Doc | Covers |
106
+ | ------------------------------------------ | ------------------------------------------------------ |
107
+ | [Getting Started](docs/getting-started.md) | Installation, prerequisites, first verification |
108
+ | [Features](docs/features.md) | Sources panel, chat integration, evidence, exports |
109
+ | [Tool Reference](docs/tools.md) | Parameters, return values, error codes for all 5 tools |
110
+ | [Configuration](docs/configuration.md) | 20 config fields, defaults, hot-reload |
111
+ | [Architecture](docs/architecture.md) | Data flow, layer responsibilities, design boundaries |
112
+ | [Development](docs/development.md) | Build, test, local development |
113
+ | [Troubleshooting](docs/troubleshooting.md) | 11 common issues with symptoms and fixes |
163
114
 
164
115
  ## Development
165
116
 
166
- ### Commands
167
-
168
117
  ```sh
169
- npm install # uses a local npm cache (see the workspace note below)
170
- npm test # unit tests (mock Zotero server + browser card tests)
171
- npm run test:coverage # 100% coverage gate on src/
172
- npm run typecheck # tsc --noEmit, node / test / client projects
173
- npm run build # tsc emits the node half into lib/; esbuild emits the browser half lib/client.js
174
- npm run build:client # rebuild the browser half only (self-checks the loader handoff)
175
- npm run dev:client # watch the browser half (pair with the hot-swap overlay)
176
- npm run format # prettier --write across the repo
177
- npm run format:check # verify formatting (run before committing)
118
+ npm install --no-workspaces # this repo lives inside the deepseek-harness workspace
119
+ npm test # vitest unit tests against the mock Zotero server
120
+ npm run typecheck # tsc --noEmit for node, test, and client projects
121
+ npm run build # tsc emits node half into lib/; esbuild emits browser half lib/client.js
122
+ npm run dev # tsc --watch for host half hot reload
123
+ npm run dev:client # esbuild --watch for browser half hot reload
178
124
  ```
179
125
 
180
- > This checkout sits inside the deepseek-harness workspace tree: the parent `package.json` declares `workspaces`, so npm walks up to it and tries to install the whole workspace. Run `npm install --no-workspaces` instead (or drop a `.npmrc` with `workspaces=false` in this repository).
181
-
182
- Integration tests run against a live Zotero and stay skipped unless enabled:
183
-
184
- ```sh
185
- npm run test:integration
186
- # or: ZOTERO_INTEGRATION=1 npx vitest run tests/integration/zotero.integration.spec.ts
187
- ```
188
-
189
- ### Running locally
190
-
191
- #### From a dsh source checkout
192
-
193
- Build the checkout once (`pnpm install && pnpm run build`), then load the plugin source through the dev overlay:
194
-
195
- ```sh
196
- pnpm dsh web --patch ./dsh-zotero/dev.cordis.yml
197
- ```
198
-
199
- `dev.cordis.yml` points the plugin entry at the absolute `src/index.ts`. The dsh source launch loads that TypeScript entry through tsx, so the plugin requires no prebuild. Update the absolute path when the checkout location differs.
200
-
201
- #### With the npm-installed dsh
202
-
203
- This plugin builds in two halves: the **Node side** (`lib/`, emitted by `tsc`, holds the service, tools, provider, and other logic) and the **browser side** (`lib/client.js`, emitted by `esbuild`, holds the dsh web configuration card and the Zotero tab view). The three flows below cover the common cases.
204
-
205
- **① Resident instance verification (tarball install)**
206
-
207
- Pack a tarball and install it into a profile. The plugin runs from the tarball's built artifacts; code updates require re-packing and re-installing. Verify with the production-stack smoke after install:
208
-
209
- ```sh
210
- npm pack
211
- dsh plugin --profile <name> add ./dsh-zotero-0.3.1.tgz
212
- cd ~/.dsh/profiles/<name>
213
- node --input-type=module < /path/to/dsh-zotero/scripts/smoke.mjs
214
- ```
215
-
216
- The smoke must be run inside the profile directory, so bare imports resolve from the profile's flat `node_modules`. It verifies `status`, `search`, `get`, `retrieve`, `export`, the policy prompt section, and the registration of all five tools; `SMOKE PASS` indicates the packed plugin passes the installed-path checks.
217
-
218
- **② Node-side hot-swap development**
219
-
220
- The `dev-lib.cordis.yml` overlay disables the profile's tarball row (id `zotero`), inserts a `zotero-dev` row pointing at this checkout's `lib/index.js`, and re-enables HMR. The production web profile disables loader HMR by default, and HMR's watch root lives in the profile directory, so the overlay sets `base` explicitly. When the build output changes, HMR disposes the old instance and reconstructs the plugin in the same process — no dsh restart needed:
221
-
222
- ```sh
223
- cd ./dsh-zotero # from the deepseek-harness checkout
224
- npm run dev & # tsc --watch: rebuild lib on src changes
225
- dsh web --patch ./dev-lib.cordis.yml --port 3307
226
- ```
227
-
228
- Hot swap only affects the instance started with `--patch`; the resident instance keeps running the tarball version, independently.
229
-
230
- **③ Browser-side development**
231
-
232
- The web frontend only scans loader rows whose `name` is a bare package name (npm-resolvable to `package.json`) to load the browser-side bundle. `dev-lib.cordis.yml` uses an absolute-path row, which does not trigger browser-side loading, so the card does not appear in the ② dev instance. To develop the card, first install this checkout into the profile (`npm install <this repo path>` as a `file:` dependency, or pack and install the tarball), then pair `npm run dev:client` (esbuild watch) with the hot-swap overlay: browser-bundle changes make HMR re-fetch `/plugins/dsh-zotero/client.js`.
126
+ Build output splits into `lib/` (Node side) and `lib/client.js` (browser side settings card + Zotero tab). For full plugin development with both halves, use the `dev-lib.cordis.yml` overlay. See [Development](docs/development.md) for details.
233
127
 
234
128
  ## License
235
129
 
236
- MIT. See [LICENSE](./LICENSE).
130
+ [MIT](./LICENSE) — free to use, modify, and distribute.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  # dsh-zotero
4
4
 
5
5
  <img
6
- src="https://readme-typing-svg.demolab.com?font=JetBrains+Mono&weight=500&size=18&pause=2000&color=CC2936&center=true&vCenter=true&width=760&lines=%3E+Zotero+as+an+evidence+store+for+agents."
6
+ src="https://readme-typing-svg.demolab.com?font=JetBrains+Mono&weight=500&size=22&pause=2000&color=CC2936&center=true&vCenter=true&width=760&lines=%3E+Zotero+as+an+evidence+store+for+agents."
7
7
  alt="dsh-zotero"
8
8
  />
9
9
  <p align="center">
@@ -18,219 +18,113 @@
18
18
  <a href="README.en.md"><b>English</b></a> · <b>中文</b>
19
19
  </p>
20
20
 
21
- Agent 从你的 [Zotero](https://www.zotero.org) 文献库中发现来源、提取与问题相关的证据,并始终保留证据与原始文献之间的联系。
21
+ dsh-zotero 是面向 Agent 研究工作流的 [Zotero](https://www.zotero.org) 插件。Agent 可以直接从你的文献库中搜索文献、查看元数据和笔记、提取与问题相关的证据段落、打开原文 PDF,并生成引用和参考文献表。
22
22
 
23
- dsh-zotero 面向 Agent 的研究工作流设计:从文献检索、元数据与笔记查看,到证据检索、原文打开和引用生成,Agent 可以根据当前任务逐步获取所需信息,而不必一次读取整篇文献或整个文献库。
23
+ <p align="center">
24
+ <img src="docs/images/header-collage.png" width="70%" alt="dsh-zotero 界面:来源面板、证据提取、导出视图">
25
+ </p>
24
26
 
25
27
  ## 工具
26
28
 
27
- | 工具 | 用途 |
28
- | ------------------- | -------------------------------------------------------------------------------------------------------------------------- |
29
- | `zotero_search` | 发现:按标题/作者/年份搜索库里的资料,`everything` 模式连全文索引一起搜;可限定某个分类或已保存搜索 |
30
- | `zotero_get` | 检查:读取一条资料的结构化核心元数据,可选检查笔记、注释、附件的清单与预览。 |
31
- | `zotero_retrieve` | 取证:按问题返回最相关的有界证据片段(注释、笔记、摘要、全文分块) |
32
- | `zotero_attachment` | 原文:解析条目或附件 ref,返回原始附件已验证的磁盘路径或链接 URL |
33
- | `zotero_export` | 引用:让 Zotero 按自己的 citation/export 能力生成结果(引用、CSL 参考文献表、`bibtex` / `biblatex` / `ris` / `csljson`)。 |
34
-
35
- ## 使用示例
36
-
37
- Agent 按需求逐层深入,一段典型对话:
38
-
39
- > 用户:「帮我找 FlashAttention 相关论文」
40
- > Agent → `zotero_search`,返回候选条目与 ref。
41
- >
42
- > 用户:「第一篇是什么?我以前读过吗?」
43
- > Agent → `zotero_get`:元数据、17 条批注、2 条笔记与有限预览。
44
- >
45
- > 用户:「我当时对 evaluation 有什么意见?」
46
- > Agent → `zotero_retrieve(query:"evaluation", sources:["annotations","notes"])`,返回相关笔记与批注证据。
47
- >
48
- > 用户:「论文自己怎么解释 memory efficiency?」
49
- > Agent → `zotero_retrieve(query:"memory efficiency", sources:["fulltext","abstract"])`,返回摘要与全文片段。
50
- >
51
- > 用户:「我要看原 PDF」
52
- > Agent → `zotero_attachment(条目 ref)`,返回已验证的文件路径;若当前 Harness 配置了 PDF/file 读取能力,再交给该能力继续分析。
53
- >
54
- > 用户:「把这三篇生成 APA 参考文献表」
55
- > Agent → `zotero_export(format:"bibliography", style:"apa")`。
29
+ | 工具 | 用途 |
30
+ | ------------------- | ------------------------------------------------------- |
31
+ | `zotero_search` | 按标题/作者/年份搜索,`everything` 模式连全文索引一起搜 |
32
+ | `zotero_get` | 读取单条文献的元数据,可选返回笔记、批注、附件清单 |
33
+ | `zotero_retrieve` | 按查询词返回最相关的证据段落(批注/笔记/摘要/全文) |
34
+ | `zotero_attachment` | 将文献 ref 解析为已验证的磁盘路径或链接 URL |
35
+ | `zotero_export` | 生成引用、参考文献表、BibTeX/BibLaTeX/RIS/CSL JSON |
56
36
 
57
- ## 命令
58
-
59
- `/zotero status` 报告连通性、API/schema 版本和数据库身份标识(Server ID,Zotero 10+)。这是唯一的健康检查。普通调用失败时返回带类型的领域错误。
60
-
61
- ## 环境要求
62
-
63
- - 已安装 Zotero 桌面版,并启用本地 API:**设置 → 高级 → “Allow other applications on this computer to communicate with Zotero”**。
64
- - 本地 API 为无认证读取,地址为 `http://127.0.0.1:23119/api`。V1 没有任何修改文献库数据(条目、笔记、标签、分类等)的路径。
65
- - Zotero ≥ 7,本地 API 版本为 3。如果 status 命令报告版本不匹配,请升级。
66
- - Node.js ≥ 22.19(或 24+);宿主 dsh 运行时为 rc.7 系。运行时依赖(peer)见 `package.json` 的 `peerDependencies`(`@deepseek-ai/cordis` ≥ 4、`dsh-tools`、`dsh-llm`、`dsh-settings`、`dsh-user-questions`、`dsh-typert-protocol`、`dsh-typert-registry`、`dsh-api-remotes`、`dsh-commands`、`dsh-timeout`),当前均声明为 `^0.1.0-rc.7`。
67
-
68
- ### 能力边界与副作用
69
-
70
- - 网络:只访问强制回环的 `http://127.0.0.1:23119/api`(拒绝重定向、流式字节上限);没有任何外部网络调用。
71
- - 文件:仅读取附件磁盘路径的存在性(`existsSync`),不写入、不执行。
72
- - 进程:无 Shell 调用、无 native 模块、无常驻后台任务或定时器——所有请求都由工具调用驱动,加载插件不会探测 Zotero。
73
- - 外部副作用:唯一的持久化写入是设置卡片保存时对 `$DSH_HOME/settings.yaml` 中 `zotero:` 小节(用户层)的更新;无遥测、无埋点。
37
+ [完整工具参考 →](docs/tools.md)
74
38
 
75
39
  ## 安装
76
40
 
77
- ### 按包名安装
78
-
79
41
  ```sh
80
42
  dsh plugin --profile <name> add dsh-zotero
81
43
  ```
82
44
 
83
- tarball 内含已构建的 `lib/`(node 半与浏览器半 `lib/client.js`),无需本地构建。浏览器半边是配置卡片:dsh web 会扫描到包内声明的 `dsh.client` 清单并自动挂载,无需额外配置。
84
-
85
- ### 本地 tarball
86
-
87
- ```sh
88
- cd dsh-zotero
89
- npm pack
90
- dsh plugin --profile <name> add ./dsh-zotero-0.3.1.tgz
91
- ```
92
-
93
- `npm pack` 先运行 `prepare` 构建 `lib/`,适合未发布或本地试装。
94
-
95
- ### 从 GitHub 源码安装
45
+ GitHub 源码安装:
96
46
 
97
47
  ```sh
98
48
  dsh plugin --profile <name> add github:Vncntvx/dsh-zotero
99
49
  ```
100
50
 
101
- git 安装拉取源码而非构建产物,pnpm 安装依赖后运行本包的 `prepare` 现场构建(TypeScript 与 `@types/node` 在 `dependencies` 中)。pnpm ≥ 10 默认拒绝运行 git 依赖的 `prepare`,首次 `add` 会失败并提示:把包名加进 profile 的 `pnpm-workspace.yaml` 后重新执行:
51
+ 本地 tarball:
102
52
 
103
- ```yaml
104
- allowBuilds:
105
- dsh-zotero: true
53
+ ```sh
54
+ cd dsh-zotero && npm pack
55
+ dsh plugin --profile <name> add ./dsh-zotero-*.tgz
106
56
  ```
107
57
 
108
- `allowBuilds` 授权该包在安装时执行代码,只允许你信任的来源,建议固定到具体提交(`github:Vncntvx/dsh-zotero#<sha>`)。
109
-
110
- 插件以 id `zotero` 挂载,下次启动 dsh 时生效。安装或启用插件后,如果当前会话创建于插件加载之前,请新建会话,确保 Agent 获得 Zotero 工具。
111
-
112
- ## 配置
113
-
114
- 所有值都是 `Config` 字段,可在 bundle 的 `config` 块中修改(例如通过 `dsh plugin config`)。以下为默认值。
115
-
116
- | 字段 | 默认值 | 含义 |
117
- | ---------------------- | ---------------------------- | ------------------------------------------------------------------------------------ |
118
- | `baseUrl` | `http://127.0.0.1:23119/api` | 本地 API 基础 URL。仅支持纯回环 HTTP。 |
119
- | `provider` | `local` | 要选择的 provider id。 |
120
- | `timeoutMs` | `5000` | 每个请求的 provider 超时时间。 |
121
- | `maxSearchResults` | `20` | `zotero_search` `limit` 的上限。 |
122
- | `maxNoteScanRecords` | `200` | `zotero_search` 补扫笔记正文的笔记数量上限。 |
123
- | `maxEvidenceChars` | `6000` | 检索证据的总字符预算。 |
124
- | `maxEvidencePassages` | `4` | 证据片段数量的上限。 |
125
- | `maxDetailChars` | `3000` | `zotero_get` 摘要预览的字符预算。 |
126
- | `maxNoteBodyChars` | `30000` | `zotero_get` 返回 note 条目自身正文的字符预算。 |
127
- | `maxNoteChars` | `2000` | `zotero_get` 单条笔记预览的字符预算。 |
128
- | `maxNoteRecords` | `50` | `zotero_get` 返回笔记数量的上限。 |
129
- | `maxAnnotationRecords` | `100` | `zotero_get` 返回批注数量的上限。 |
130
- | `fulltextChunkWords` | `200` | 进入证据排序的全文片段词数。 |
131
- | `maxFulltextChars` | `250000` | 进入证据排序的全文大小上限。 |
132
- | `maxResponseBytes` | `16777216` | 每个 API 响应的流式字节上限。 |
133
- | `maxExportChars` | `1000000` | 导出输出的硬上限。不会中途截断。 |
134
- | `maxExportRefs` | `50` | 单次 `zotero_export` 的 refs 数量上限;citation 分批到该上限,其余格式单次最多 50。 |
135
- | `defaultStyle` | `apa` | 引用/参考文献使用的 CSL 样式。 |
136
- | `defaultLocale` | `en-US` | 引用/参考文献使用的 CSL locale。 |
137
- | `webEnabled` | `true` | 是否在会话顶部显示 Zotero 专属标签页;开关即时生效,关闭后立即隐藏标签页,无需刷新。 |
58
+ 安装后重启新建会话,Agent 即可使用 Zotero 工具。
138
59
 
139
- ### Web 配置
60
+ 插件在 **Settings → Plugins** 中提供配置卡片,可调整 API 地址、并发限制、全文检索开关等参数,保存即生效。详见 [配置](docs/configuration.md)。
140
61
 
141
- 插件在 dsh web 的 **Settings Plugins → Plugin configuration** 页面注册一张 "Zotero" 卡片,列出上表全部字段。卡片绑定 `zotero` 设置命名空间:写入落在 `$DSH_HOME/settings.yaml` 的 `zotero:` 小节(叠加在 patch 条目 `config` 之上,用户层优先),**保存即时生效**——传输层与 provider 按新值重建,下一次工具调用或 `/zotero status` 无需重启 dsh 即可使用。
62
+ [安装详情](docs/getting-started.md)
142
63
 
143
- - 非法值(非回环 `baseUrl`、非正数上限)在写入前被拒绝;卡片提示保存失败并保留草稿,插件继续运行在最后一个合法值上。
144
- - 每个字段显示有效值;被设置文档覆盖的字段带有 "Overridden" 徽标,提供一键重置(清除用户层,回到 patch 条目值)。
145
- - 直接编辑设置文档(如手工修改 `settings.yaml`)同样热生效。
146
- - 没有设置服务的组合(纯 headless)不会注册命名空间,插件行为与未配置时完全一致。
64
+ ## 前置条件
147
65
 
148
- ### Web 视图
66
+ - Zotero ≥ 7 桌面版,启用本地 API:**设置 → 高级 → "允许其他应用程序与 Zotero 通信"**
67
+ - Node.js ≥ 22.19(或 ≥ 24)
68
+ - 本地 API 地址 `http://127.0.0.1:23119/api`,无认证,只读
149
69
 
150
- dsh web 的会话视图是标签页环(Chat、Trajectory、…)。插件注册一个专属 **Zotero** 标签页(`conversation.view`,id `zotero`,位于 Trajectory 与 dsh-context 之后),不触碰 dsh 自带的聊天与轨迹视图:
151
-
152
- - 标签页顶部是**连接条**:挂载时探测一次、每次手动刷新再探测一次(请求驱动,无轮询定时器);显示连接状态、API/Schema 版本、Server ID(Zotero 10+)与上次检查时间;Zotero 不可用时显示诊断信息。
153
- - 下方是本会话的 **Zotero 工具活动**:每次搜索、精读、取证、附件解析与导出调用都渲染为富卡片(可展开、ref 可复制、证据段落标注来源),完全由会话快照重放驱动——同一段记录永远渲染出同样的卡片,meta 缺失时降级为原始内容。
154
- - 设置页的 **Web → 会话工具卡片** 开关(`webEnabled`,默认开启)控制标签页的注册;开关即时生效——打开立即显示、关闭立即隐藏,无需刷新页面。关闭后,Zotero 调用在轨迹中显示为 dsh 内置的通用卡片。
155
-
156
- ### 限制
157
-
158
- - 只读文献库:没有任何路径会修改条目、笔记、标签或合集。
159
- - 全文证据依赖 Zotero 的索引:`everything` 搜索与 `retrieve` 的全文段落都需要已建立索引。
160
- - 笔记正文搜索是客户端扫描:仅限 library/collection 作用域与第一页结果(offset 0),受 `maxNoteScanRecords` 限制;命中并入第一页直到 `limit`,计数在返回的 `noteMatches` 字段中,不计入分页 `total`。
161
- - 附件深度取决于宿主组合:`zotero_attachment` 返回文件位置;继续阅读该 PDF 需要宿主具备对应的文件/PDF 能力。
162
- - 证据排序是基于词项的相关性,而非向量或语义检索。
163
-
164
- ## 开发
70
+ ## 使用示例
165
71
 
166
- ### 命令
72
+ Agent 在对话中根据用户需求逐步调用工具,每次调用的结果作为下一步的上下文。
167
73
 
168
- ```sh
169
- npm install # 使用本地 npm 缓存(见下方 workspace 说明)
170
- npm test # 单元测试(mock Zotero server + 浏览器卡片测试)
171
- npm run test:coverage # 对 src/ 的 100% 覆盖率门禁
172
- npm run typecheck # tsc --noEmit,node / test / client 三个项目
173
- npm run build # tsc 生成 node 半 lib/ + esbuild 生成浏览器半 lib/client.js
174
- npm run build:client # 只重建浏览器半(含 loader 交接格式自检)
175
- npm run dev:client # 浏览器半 watch 模式(配合热替换 overlay)
176
- npm run format # prettier --write 全仓格式化
177
- npm run format:check # 校验格式化(提交前执行)
178
- ```
74
+ ```text
75
+ 用户:帮我找 Risk 相关的论文
76
+ Agent zotero_search(query: "Risk", itemType: "journalArticle")
77
+ 5 篇匹配结果,用户选择前 3
179
78
 
180
- > 本仓库位于 deepseek-harness workspace 树内:父目录 `package.json` 声明了 `workspaces`,npm 会向上找到它并尝试安装整个 workspace。请使用 `npm install --no-workspaces`(或在本仓库放置含 `workspaces=false` 的 `.npmrc`)。
79
+ 用户:第一篇的摘要说了什么?
80
+ Agent → zotero_get(ref: 1, fields: ["abstractNote"])
81
+ 返回摘要全文
181
82
 
182
- 集成测试面向真实 Zotero,默认跳过,需显式开启:
83
+ 用户:这篇里关于方法论的讨论,帮我找出来
84
+ Agent → zotero_retrieve(query: "methodology", sources: ["fulltext", "notes"])
85
+ 返回相关段落,带页码和来源
183
86
 
184
- ```sh
185
- npm run test:integration
186
- # 或:ZOTERO_INTEGRATION=1 npx vitest run tests/integration/zotero.integration.spec.ts
87
+ 用户:把这三篇导出为 BibTeX
88
+ Agent zotero_export(refs: [1,2,3], format: "bibtex")
89
+ 生成 BibTeX 条目,可复制或下载
187
90
  ```
188
91
 
189
- ### 本地启动
92
+ 更多示例见 [功能概览](docs/features.md)。
190
93
 
191
- #### 从 dsh 源码启动
94
+ ## 限制
192
95
 
193
- 在 deepseek-harness 源码 checkout 中构建一次(`pnpm install && pnpm run build`),然后通过 dev overlay 加载插件源码:
194
-
195
- ```sh
196
- pnpm dsh web --patch ./dsh-zotero/dev.cordis.yml
197
- ```
96
+ - **只读文献库**:所有操作均为读取,不修改条目、笔记、标签或分类
97
+ - **只访问本机**:网络请求仅发往 `127.0.0.1:23119`
98
+ - **证据排序是词项相关性**:基于 BM25,按查询词与 passage 的词频匹配度排序
99
+ - **导出是静态文本**:以文本形式返回,需要手动复制到目标位置
100
+ - **全文证据依赖 Zotero 索引**:未索引的 PDF 无法提供全文段落
101
+ - **附件深度取决于宿主**:`zotero_attachment` 返回文件位置,继续阅读 PDF 需要宿主具备对应能力
198
102
 
199
- `dev.cordis.yml` 将插件入口指向绝对的 `src/index.ts`。dsh 的源码启动经 tsx 加载该 TypeScript 入口,插件因此无需预构建;若 checkout 路径不同,需同步修改文件中的绝对路径。
103
+ ## 文档
200
104
 
201
- #### 使用 npm 安装的 dsh
105
+ | 文档 | 内容 |
106
+ | ----------------------------------- | ---------------------------------- |
107
+ | [快速上手](docs/getting-started.md) | 安装、前置条件、首次验证 |
108
+ | [功能概览](docs/features.md) | 来源面板、对话集成、证据提取、导出 |
109
+ | [工具参考](docs/tools.md) | 5 个工具的参数、返回值、错误码 |
110
+ | [配置](docs/configuration.md) | 20 个配置字段、默认值、热更新 |
111
+ | [架构](docs/architecture.md) | 数据流、各层职责、设计边界 |
112
+ | [开发指南](docs/development.md) | 构建、测试、本地开发 |
113
+ | [问题排查](docs/troubleshooting.md) | 11 个常见问题的症状和处理 |
202
114
 
203
- 本插件分两部分构建:**Node 端**(`lib/`,由 `tsc` 生成,包含服务、工具、provider 等逻辑)与**浏览器端**(`lib/client.js`,由 `esbuild` 生成,包含 dsh web 的配置卡片与 Zotero 标签视图)。下面三种开发流程覆盖了不同场景。
204
-
205
- **① 常驻实例验证(tarball 安装)**
206
-
207
- 打包为 tarball 并安装到 profile,插件以 tarball 内的构建产物运行;代码更新后需重新打包安装。安装后通过生产栈 smoke 脚本验证:
208
-
209
- ```sh
210
- npm pack
211
- dsh plugin --profile <name> add ./dsh-zotero-0.3.1.tgz
212
- cd ~/.dsh/profiles/<name>
213
- node --input-type=module < /path/to/dsh-zotero/scripts/smoke.mjs
214
- ```
215
-
216
- smoke 脚本必须在 profile 目录内运行,这样裸导入才能从 profile 的扁平 `node_modules` 中解析。脚本依次验证 `status`、`search`、`get`、`retrieve`、`export`、策略提示词分区,以及五个工具的注册情况;输出 `SMOKE PASS` 表示打包后的插件通过了安装路径验证。
217
-
218
- **② Node 端热替换开发**
219
-
220
- `dev-lib.cordis.yml` 覆盖层会禁用 profile 中的 tarball 行(id `zotero`),转而插入 `zotero-dev` 行指向本仓库的 `lib/index.js`,并重新启用 HMR。生产 web profile 默认关闭 loader HMR,且 HMR 的监视根位于 profile 目录,因此覆盖层显式设置了 `base`。构建产物变化后,HMR 会在同一进程内销毁旧实例并重新构造插件,无需重启 dsh:
115
+ ## 开发
221
116
 
222
117
  ```sh
223
- cd ./dsh-zotero # deepseek-harness checkout 进入本仓库
224
- npm run dev & # tsc --watch:修改 src 后自动重建 lib
225
- dsh web --patch ./dev-lib.cordis.yml --port 3307
118
+ npm install --no-workspaces # 本仓库在 deepseek-harness 工作区内,需要加 --no-workspaces
119
+ npm test # 单元测试(vitest,mock Zotero 服务器)
120
+ npm run typecheck # tsc --noEmit,覆盖 node、test、client 三个项目
121
+ npm run build # tsc 编译 node 部分到 lib/,esbuild 编译浏览器部分到 lib/client.js
122
+ npm run dev # tsc --watch,host half 热更新
123
+ npm run dev:client # esbuild --watch,浏览器部分热更新
226
124
  ```
227
125
 
228
- 热替换仅对通过 `--patch` 启动的实例生效;常驻实例仍运行 tarball 版本,互不影响。
229
-
230
- **③ 浏览器端开发**
231
-
232
- dsh web 只会扫描 Loader 行中 `name` 为裸包名(npm 能解析到 `package.json`)的条目来加载浏览器端 bundle。`dev-lib.cordis.yml` 使用的是绝对路径行,不会触发浏览器端加载,因此卡片不会出现在 ② 的 dev 实例中。开发卡片时需要先把本仓库装进 profile(`npm install <本仓库路径>` 作为 `file:` 依赖,或 `npm pack` 后安装 tarball),再配合 `npm run dev:client`(esbuild watch)与热替换 overlay 一起使用:浏览器 bundle 变化会触发 HMR 重新拉取 `/plugins/dsh-zotero/client.js`。
126
+ 构建产物分两部分:`lib/` 是 Node 侧代码,`lib/client.js` 是浏览器侧(settings 卡片 + Zotero tab)。本地开发推荐用 `dev-lib.cordis.yml` overlay 实现完整插件流程,详见 [开发指南](docs/development.md)。
233
127
 
234
128
  ## 许可证
235
129
 
236
- 本插件以 [MIT](./LICENSE) 许可证发布。
130
+ [MIT](./LICENSE) — 自由使用、修改和分发。