zop-cli 0.2.0__tar.gz

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 (66) hide show
  1. zop_cli-0.2.0/.gitattributes +15 -0
  2. zop_cli-0.2.0/.github/workflows/ci.yml +55 -0
  3. zop_cli-0.2.0/.gitignore +50 -0
  4. zop_cli-0.2.0/CONTRIBUTING.md +128 -0
  5. zop_cli-0.2.0/LICENSE +21 -0
  6. zop_cli-0.2.0/PKG-INFO +96 -0
  7. zop_cli-0.2.0/README.md +68 -0
  8. zop_cli-0.2.0/docs/ARCHITECTURE.md +312 -0
  9. zop_cli-0.2.0/pyproject.toml +134 -0
  10. zop_cli-0.2.0/skills/zop/README.md +27 -0
  11. zop_cli-0.2.0/skills/zop/SKILL.md +107 -0
  12. zop_cli-0.2.0/src/zop/__init__.py +5 -0
  13. zop_cli-0.2.0/src/zop/__main__.py +6 -0
  14. zop_cli-0.2.0/src/zop/_version.py +5 -0
  15. zop_cli-0.2.0/src/zop/adapters/__init__.py +6 -0
  16. zop_cli-0.2.0/src/zop/adapters/sqlite_reader.py +476 -0
  17. zop_cli-0.2.0/src/zop/adapters/zotero_api.py +315 -0
  18. zop_cli-0.2.0/src/zop/cli.py +96 -0
  19. zop_cli-0.2.0/src/zop/commands/__init__.py +21 -0
  20. zop_cli-0.2.0/src/zop/commands/collection.py +221 -0
  21. zop_cli-0.2.0/src/zop/commands/export.py +71 -0
  22. zop_cli-0.2.0/src/zop/commands/item.py +176 -0
  23. zop_cli-0.2.0/src/zop/commands/library.py +63 -0
  24. zop_cli-0.2.0/src/zop/commands/note.py +68 -0
  25. zop_cli-0.2.0/src/zop/commands/pdf.py +71 -0
  26. zop_cli-0.2.0/src/zop/commands/tag.py +94 -0
  27. zop_cli-0.2.0/src/zop/core/__init__.py +5 -0
  28. zop_cli-0.2.0/src/zop/core/concurrency.py +38 -0
  29. zop_cli-0.2.0/src/zop/core/config.py +66 -0
  30. zop_cli-0.2.0/src/zop/core/envelope.py +71 -0
  31. zop_cli-0.2.0/src/zop/core/errors.py +92 -0
  32. zop_cli-0.2.0/src/zop/models/__init__.py +15 -0
  33. zop_cli-0.2.0/src/zop/models/collection.py +45 -0
  34. zop_cli-0.2.0/src/zop/models/common.py +30 -0
  35. zop_cli-0.2.0/src/zop/models/envelope.py +58 -0
  36. zop_cli-0.2.0/src/zop/models/item.py +34 -0
  37. zop_cli-0.2.0/src/zop/services/__init__.py +19 -0
  38. zop_cli-0.2.0/src/zop/services/collections.py +326 -0
  39. zop_cli-0.2.0/src/zop/services/export.py +187 -0
  40. zop_cli-0.2.0/src/zop/services/items.py +142 -0
  41. zop_cli-0.2.0/src/zop/services/library.py +30 -0
  42. zop_cli-0.2.0/src/zop/services/notes.py +47 -0
  43. zop_cli-0.2.0/src/zop/services/pdf.py +130 -0
  44. zop_cli-0.2.0/src/zop/services/tags.py +99 -0
  45. zop_cli-0.2.0/tests/__init__.py +1 -0
  46. zop_cli-0.2.0/tests/conftest.py +38 -0
  47. zop_cli-0.2.0/tests/fixtures/test_plan.json +8 -0
  48. zop_cli-0.2.0/tests/test_cli_collection.py +47 -0
  49. zop_cli-0.2.0/tests/test_cli_export.py +51 -0
  50. zop_cli-0.2.0/tests/test_cli_item.py +64 -0
  51. zop_cli-0.2.0/tests/test_cli_library.py +77 -0
  52. zop_cli-0.2.0/tests/test_cli_main.py +27 -0
  53. zop_cli-0.2.0/tests/test_cli_note.py +31 -0
  54. zop_cli-0.2.0/tests/test_cli_plan.py +142 -0
  55. zop_cli-0.2.0/tests/test_cli_tag.py +31 -0
  56. zop_cli-0.2.0/tests/test_collections.py +193 -0
  57. zop_cli-0.2.0/tests/test_envelope.py +133 -0
  58. zop_cli-0.2.0/tests/test_export.py +78 -0
  59. zop_cli-0.2.0/tests/test_items_service.py +127 -0
  60. zop_cli-0.2.0/tests/test_library.py +90 -0
  61. zop_cli-0.2.0/tests/test_notes_service.py +43 -0
  62. zop_cli-0.2.0/tests/test_tags_service.py +87 -0
  63. zop_cli-0.2.0/tests/test_zotero_api.py +184 -0
  64. zop_cli-0.2.0/tools/inspect_sqlite.py +48 -0
  65. zop_cli-0.2.0/tools/inspect_tables.py +17 -0
  66. zop_cli-0.2.0/uv.lock +607 -0
@@ -0,0 +1,15 @@
1
+ # ─── Line endings ──────────────────────────────────────────────
2
+ # Force LF on all text files, regardless of OS. Eliminates the
3
+ # "LF will be replaced by CRLF" warnings on Windows checkouts
4
+ # and keeps diffs clean in cross-platform teams.
5
+ *.py text eol=lf
6
+ *.pyi text eol=lf
7
+ *.toml text eol=lf
8
+ *.cfg text eol=lf
9
+ *.md text eol=lf
10
+ *.rst text eol=lf
11
+ *.json text eol=lf
12
+ *.yml text eol=lf
13
+ *.yaml text eol=lf
14
+ *.sh text eol=lf
15
+ *.txt text eol=lf
@@ -0,0 +1,55 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master, main]
6
+ pull_request:
7
+ branches: [master, main]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ lint:
18
+ name: Ruff
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: astral-sh/ruff-action@v1
23
+
24
+ typecheck:
25
+ name: Mypy (strict)
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: actions/setup-python@v5
30
+ with:
31
+ python-version: "3.12"
32
+ - uses: astral-sh/setup-uv@v6
33
+ - run: uv sync
34
+ - run: uv run mypy src
35
+
36
+ test:
37
+ name: pytest (${{ matrix.python-version }})
38
+ runs-on: ubuntu-latest
39
+ strategy:
40
+ fail-fast: false
41
+ matrix:
42
+ python-version: ["3.12", "3.13"]
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - uses: actions/setup-python@v5
46
+ with:
47
+ python-version: ${{ matrix.python-version }}
48
+ - uses: astral-sh/setup-uv@v6
49
+ - run: uv sync
50
+ - run: uv run pytest --cov-report=xml
51
+ - if: matrix.python-version == '3.12'
52
+ uses: actions/upload-artifact@v4
53
+ with:
54
+ name: coverage-report
55
+ path: coverage.xml
@@ -0,0 +1,50 @@
1
+ # ─── Python build artifacts ────────────────────────────────────
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ wheels/
8
+
9
+ # ─── Virtual environments ──────────────────────────────────────
10
+ .venv/
11
+ venv/
12
+ env/
13
+
14
+ # ─── Test & coverage artifacts ─────────────────────────────────
15
+ .coverage
16
+ .coverage.*
17
+ htmlcov/
18
+ coverage.xml
19
+ .pytest_cache/
20
+
21
+ # ─── Linter & type-checker caches ──────────────────────────────
22
+ .mypy_cache/
23
+ .ruff_cache/
24
+
25
+ # ─── Local agent/tool config ───────────────────────────────────
26
+ # Plugin settings, skills, per-machine state — never commit
27
+ .claude/
28
+ .serena/
29
+ CLAUDE.local.md
30
+
31
+ # ─── Editor / IDE ──────────────────────────────────────────────
32
+ .vscode/
33
+ .idea/
34
+ *.swp
35
+ *.swo
36
+ *~
37
+
38
+ # ─── OS metadata ───────────────────────────────────────────────
39
+ .DS_Store
40
+ Thumbs.db
41
+ desktop.ini
42
+
43
+ # ─── Logs ──────────────────────────────────────────────────────
44
+ *.log
45
+ logs/
46
+
47
+ # ─── Local secrets & environment overrides ─────────────────────
48
+ .env
49
+ .env.*
50
+ !.env.example
@@ -0,0 +1,128 @@
1
+ # 贡献与维护指南
2
+
3
+ 面向 zop 的贡献者与维护者。终端用户的安装/使用请看 [README](README.md);架构设计请看 [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)。
4
+
5
+ ## 开发环境
6
+
7
+ 前置:**Python ≥ 3.12** 和 [uv](https://docs.astral.sh/uv/)。
8
+
9
+ ```bash
10
+ git clone https://github.com/kingdomad/zop.git
11
+ cd zop
12
+ uv sync # 创建 .venv 并安装主依赖 + dev 依赖(ruff/mypy/pytest 等)
13
+ uv run zop --version # 验证可运行
14
+ ```
15
+
16
+ ## 项目结构
17
+
18
+ 四层(端口/适配器)架构,详见 [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md):
19
+
20
+ ```
21
+ src/zop/
22
+ ├── core/ # 横切:config / errors / envelope / concurrency
23
+ ├── models/ # pydantic v2 数据模型 + 信封
24
+ ├── adapters/ # I/O 边界:sqlite_reader(读)/ zotero_api(写,async httpx)
25
+ ├── services/ # 业务编排(只调 adapter 公共方法)
26
+ └── commands/ # 薄 click 包装(无业务逻辑)
27
+ ```
28
+
29
+ **核心约束:service 层不得直接 import `httpx` / `sqlite3`** —— 只通过 adapter 的公共方法访问 I/O。这是可测试性和可替换性的基础。
30
+
31
+ ## 日常开发命令
32
+
33
+ ```bash
34
+ uv run ruff check . # lint(含 tools/、tests/)
35
+ uv run ruff format # 格式化
36
+ uv run mypy src # 严格类型检查(必须 0 错误)
37
+ uv run pytest # 全量测试 + 覆盖率报告
38
+ uv run pytest tests/test_collections.py -v # 单个文件
39
+ uv run pytest -k plan # 按名筛选
40
+ ```
41
+
42
+ 四者全绿才能提交。CI 跑的是同样的检查,本地绿 ≈ CI 绿(但 CI 在 Linux,注意跨平台)。
43
+
44
+ ## 测试约定
45
+
46
+ - **栈**:pytest + pytest-asyncio(`asyncio_mode = "auto"`,async 测试无需逐个 mark)+ pytest-cov。
47
+ - **fake_db**:`tests/conftest.py` 提供一个**空** sqlite 文件(SqliteReader 只检查路径存在);需要真实 schema 的测试在本地自建 —— 见 `tests/test_collections.py`(完整 10 表)和 `tests/test_cli_plan.py`(按需建表)。
48
+ - **写入路径**:adapter 测试用 `httpx.MockTransport`(零依赖,不引 pytest-httpx);service 测试用 `AsyncMock(spec=ZoteroApi)` 注入。
49
+ - **夹具**:自动化夹具放 `tests/fixtures/`(如 `test_plan.json`);一次性手工夹具别入库。
50
+ - **覆盖率**:当前 ~64%,无 `--cov-fail-under` gate。优先覆盖关键写入路径和 CLI 命令,不为数字硬凑。
51
+
52
+ ## 代码风格
53
+
54
+ - ruff:line-length 100,启用 E/W/F/I/B/UP/N/S/C4/RET/SIM/TID/PT/RUF;`tests/` 放宽 S101(assert)。
55
+ - mypy:`strict = true`,对外部 `pypdf.*` 用 `ignore_missing_imports`。
56
+ - 导入:禁止相对导入(`flake8-tidy-imports: ban-relative-imports = "all"`)。
57
+
58
+ ## 提交规范
59
+
60
+ 遵循 [Conventional Commits](https://www.conventionalcommits.org/):`feat` / `fix` / `test` / `refactor` / `chore` / `build` / `ci` / `docs`。一个逻辑单元一个原子提交。
61
+
62
+ 历史示例:`feat(skills): ...`、`test(plan): ...`、`build: rename distribution to zop-cli`。
63
+
64
+ ## CI
65
+
66
+ `.github/workflows/ci.yml` 在 push/PR 到 `main` 时触发,三个并行作业:
67
+
68
+ | 作业 | 内容 |
69
+ |------|------|
70
+ | Ruff | `ruff check`(全仓库) |
71
+ | Mypy | `uv sync` + `mypy src`(strict) |
72
+ | pytest | 矩阵 Python 3.12 / 3.13,`uv sync` + `pytest --cov-report=xml` |
73
+
74
+ 无覆盖率门槛 —— 测试全过即绿。
75
+
76
+ ## 版本管理
77
+
78
+ 单一来源:`src/zop/_version.py` 的 `__version__`(hatchling 读取,注入构建元数据)。发版流程:
79
+
80
+ 1. 改 `__version__`(如 `"0.3.0"`);
81
+ 2. 提交(`chore: bump version to 0.3.0`);
82
+ 3. 打 tag:`git tag v0.3.0 && git push --tags`;
83
+ 4. 按下一节发布到 PyPI。
84
+
85
+ ## 发布到 PyPI
86
+
87
+ 分发名是 **`zop-cli`**(命令仍是 `zop`,导入包仍是 `zop`)。
88
+
89
+ **1. 配置 token**(一次性):在 PyPI 为 `zop-cli` 项目建一个 scoped API token,设为环境变量。uv **不读** `~/.pypirc`,用环境变量:
90
+
91
+ ```powershell
92
+ # Windows(用户级,持久)
93
+ [Environment]::SetEnvironmentVariable("UV_PUBLISH_TOKEN", "pypi-xxxxxxxx", "User")
94
+ ```
95
+
96
+ ```bash
97
+ # macOS / Linux
98
+ echo 'export UV_PUBLISH_TOKEN=pypi-xxxxxxxx' >> ~/.bashrc
99
+ ```
100
+
101
+ **2. 构建 + 校验**:
102
+
103
+ ```bash
104
+ uv build # 产出 dist/zop_cli-X.Y.Z-*.whl 和 .tar.gz
105
+ uvx twine check dist/* # 校验元数据(License-Expression、entry point 等)
106
+ ```
107
+
108
+ **3. 发布**:
109
+
110
+ ```bash
111
+ uv publish # 自动读取 UV_PUBLISH_TOKEN
112
+ ```
113
+
114
+ **4. 验证**:换一个干净环境 `uv tool install zop-cli` 从 PyPI 装回来,确认 `zop --version` 和命令正常。
115
+
116
+ **备选(自动化)**:在 GitHub Actions 用 [trusted publishing](https://docs.pypi.org/trusted-publishers/)(OIDC,免本地 token)—— 打 tag 触发 workflow 自动发布。适合稳定后接入。
117
+
118
+ ## 维护 agent skill
119
+
120
+ 仓库带一个面向 agent 的 skill(`skills/zop/`),用户通过 `npx skills add kingdomad/zop --skill zop` 安装。
121
+
122
+ - **改 CLI 命令后,同步更新 `skills/zop/SKILL.md` 的命令表** —— agent 会照表调用,表里写错命令会导致 agent 调用失败。
123
+ - skill 的 frontmatter `description` 只写"何时触发",不总结工作流(否则 agent 会只读 description 跳过正文)。
124
+ - `skills/` 入库发布;`.claude/skills/` 是本地实验性 skill,**已 gitignore**,不会随仓库发布。
125
+
126
+ ## .gitignore 约定
127
+
128
+ 以下不入库(已在 `.gitignore`):`.claude/`、`.serena/`、`.venv/`、`.mypy_cache/`、`.pytest_cache/`、`.ruff_cache/`、`.coverage`、`*.sqlite`。新增临时/本地文件时遵循同样原则。
zop_cli-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zop contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
zop_cli-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,96 @@
1
+ Metadata-Version: 2.4
2
+ Name: zop-cli
3
+ Version: 0.2.0
4
+ Summary: High-throughput Zotero CLI focused on batch operations and automation
5
+ Project-URL: Homepage, https://github.com/anomalyco/zop
6
+ Project-URL: Issues, https://github.com/anomalyco/zop/issues
7
+ Author: zop contributors
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: batch,bibliography,cli,zotero
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
20
+ Classifier: Topic :: Utilities
21
+ Requires-Python: >=3.12
22
+ Requires-Dist: click>=8.1
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: platformdirs>=4.2
25
+ Requires-Dist: pydantic>=2.7
26
+ Requires-Dist: pypdf>=4.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # zop
30
+
31
+ 一个面向批量操作和自动化场景的高吞吐 Zotero 命令行工具。
32
+
33
+ ## 安装
34
+
35
+ 从 PyPI 安装(推荐):
36
+
37
+ ```bash
38
+ uv tool install zop-cli
39
+ ```
40
+
41
+ 也可用 pipx:`pipx install zop-cli`,或 pip:`pip install zop-cli`。安装后命令名为 `zop`。
42
+
43
+ 开发安装(可编辑,含开发依赖):
44
+
45
+ ```bash
46
+ uv sync
47
+ ```
48
+
49
+ 贡献与维护流程见 [CONTRIBUTING](CONTRIBUTING.md)。
50
+
51
+ ## 配置
52
+
53
+ 新建 `~/.config/zop/config.toml`:
54
+
55
+ ```toml
56
+ [zotero]
57
+ data_dir = "D:\\Program Data\\zotero"
58
+ library_id = "12345"
59
+ api_key = "your-api-key"
60
+ ```
61
+
62
+ 读取操作走本地 SQLite(`data_dir/zotero.sqlite`),写入操作走 Zotero Web API。
63
+ 读取无需联网,也不需要 API key。
64
+
65
+ ## 用法
66
+
67
+ ```bash
68
+ zop collection list # 列出所有集合
69
+ zop collection list --tree # 以父子树形展示
70
+ zop collection items ABC12345 # 列出某集合下的条目
71
+ zop collection create "新主题" # 创建集合
72
+ zop collection create "子主题" --parent "新主题"
73
+ zop collection delete ABC12345 # 删除集合(级联)
74
+ zop collection reparent ABC12345 --parent "新父级"
75
+ zop collection move KEY1 KEY2 --to TARGET_KEY # 移动条目
76
+ zop collection plan plan.json --dry-run # 校验批量计划
77
+ zop collection plan plan.json --execute # 执行批量计划
78
+ ```
79
+
80
+ ## Agent skill
81
+
82
+ 为 AI 编程助手(Claude Code、Codex、Cursor 等)配套了一个 [agent skill](https://skills.sh),教 agent 如何调用 `zop`、解析 JSON 信封输出、以及批量 plan 的 dry-run → execute 流程:
83
+
84
+ ```bash
85
+ npx skills add kingdomad/zop --skill zop -a claude-code -y
86
+ ```
87
+
88
+ 详见 [`skills/zop/SKILL.md`](skills/zop/SKILL.md)。
89
+
90
+ ## 与 `zot` 的差异
91
+
92
+ - **真正的批量**:创建集合使用 Zotero 的批量 POST(每请求 50 条)
93
+ - **有界并发 PATCH**:移动条目使用并行 PATCH(默认 8 路并发),而非逐条顺序调用
94
+ - **真正的 dry-run**:`zop collection plan --dry-run` 会实际检查名称冲突、父级解析与条目存在性
95
+ - **reparent 支持**:`zop collection reparent` 可用(`zot` 未暴露此能力)
96
+ - **单条失败隔离**:批量移动中某一条失败不会中断整批任务
@@ -0,0 +1,68 @@
1
+ # zop
2
+
3
+ 一个面向批量操作和自动化场景的高吞吐 Zotero 命令行工具。
4
+
5
+ ## 安装
6
+
7
+ 从 PyPI 安装(推荐):
8
+
9
+ ```bash
10
+ uv tool install zop-cli
11
+ ```
12
+
13
+ 也可用 pipx:`pipx install zop-cli`,或 pip:`pip install zop-cli`。安装后命令名为 `zop`。
14
+
15
+ 开发安装(可编辑,含开发依赖):
16
+
17
+ ```bash
18
+ uv sync
19
+ ```
20
+
21
+ 贡献与维护流程见 [CONTRIBUTING](CONTRIBUTING.md)。
22
+
23
+ ## 配置
24
+
25
+ 新建 `~/.config/zop/config.toml`:
26
+
27
+ ```toml
28
+ [zotero]
29
+ data_dir = "D:\\Program Data\\zotero"
30
+ library_id = "12345"
31
+ api_key = "your-api-key"
32
+ ```
33
+
34
+ 读取操作走本地 SQLite(`data_dir/zotero.sqlite`),写入操作走 Zotero Web API。
35
+ 读取无需联网,也不需要 API key。
36
+
37
+ ## 用法
38
+
39
+ ```bash
40
+ zop collection list # 列出所有集合
41
+ zop collection list --tree # 以父子树形展示
42
+ zop collection items ABC12345 # 列出某集合下的条目
43
+ zop collection create "新主题" # 创建集合
44
+ zop collection create "子主题" --parent "新主题"
45
+ zop collection delete ABC12345 # 删除集合(级联)
46
+ zop collection reparent ABC12345 --parent "新父级"
47
+ zop collection move KEY1 KEY2 --to TARGET_KEY # 移动条目
48
+ zop collection plan plan.json --dry-run # 校验批量计划
49
+ zop collection plan plan.json --execute # 执行批量计划
50
+ ```
51
+
52
+ ## Agent skill
53
+
54
+ 为 AI 编程助手(Claude Code、Codex、Cursor 等)配套了一个 [agent skill](https://skills.sh),教 agent 如何调用 `zop`、解析 JSON 信封输出、以及批量 plan 的 dry-run → execute 流程:
55
+
56
+ ```bash
57
+ npx skills add kingdomad/zop --skill zop -a claude-code -y
58
+ ```
59
+
60
+ 详见 [`skills/zop/SKILL.md`](skills/zop/SKILL.md)。
61
+
62
+ ## 与 `zot` 的差异
63
+
64
+ - **真正的批量**:创建集合使用 Zotero 的批量 POST(每请求 50 条)
65
+ - **有界并发 PATCH**:移动条目使用并行 PATCH(默认 8 路并发),而非逐条顺序调用
66
+ - **真正的 dry-run**:`zop collection plan --dry-run` 会实际检查名称冲突、父级解析与条目存在性
67
+ - **reparent 支持**:`zop collection reparent` 可用(`zot` 未暴露此能力)
68
+ - **单条失败隔离**:批量移动中某一条失败不会中断整批任务