nber-cli 0.4.0__tar.gz → 0.5.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.
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.claude-plugin/marketplace.json +2 -2
- nber_cli-0.5.0/CHANGELOG.md +112 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/PKG-INFO +10 -2
- {nber_cli-0.4.0 → nber_cli-0.5.0}/README.md +7 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/README.zh-CN.md +7 -1
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/agents/index.md +1 -1
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/agents/openclaw.md +1 -1
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/agents/others.md +1 -1
- nber_cli-0.5.0/docs/en/changelog.md +122 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/cli.md +41 -4
- nber_cli-0.5.0/docs/en/configuration.md +202 -0
- nber_cli-0.5.0/docs/en/development.md +134 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/getting-started.md +16 -0
- nber_cli-0.5.0/docs/en/mcp.md +141 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/policy.md +9 -2
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/python-api.md +114 -4
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/agents/index.md +1 -1
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/agents/openclaw.md +1 -1
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/agents/others.md +1 -1
- nber_cli-0.5.0/docs/zh/changelog.md +122 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/cli.md +41 -4
- nber_cli-0.5.0/docs/zh/configuration.md +202 -0
- nber_cli-0.5.0/docs/zh/development.md +134 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/getting-started.md +16 -0
- nber_cli-0.5.0/docs/zh/mcp.md +141 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/policy.md +8 -1
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/python-api.md +114 -4
- {nber_cli-0.4.0 → nber_cli-0.5.0}/plugins/nber-cli/.claude-plugin/plugin.json +2 -2
- {nber_cli-0.4.0 → nber_cli-0.5.0}/plugins/nber-cli/.codex-plugin/plugin.json +1 -1
- {nber_cli-0.4.0 → nber_cli-0.5.0}/pyproject.toml +11 -2
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/__init__.py +10 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/cli.py +163 -40
- nber_cli-0.5.0/src/nber_cli/config.py +49 -0
- nber_cli-0.5.0/src/nber_cli/config.schema.json +54 -0
- nber_cli-0.5.0/src/nber_cli/config_store.py +266 -0
- nber_cli-0.5.0/src/nber_cli/core/models.py +185 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/db.py +63 -15
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/download.py +82 -28
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/feed.py +110 -70
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/fetcher.py +47 -23
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/formatters.py +6 -7
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/mcp.py +43 -21
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/conftest.py +3 -4
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/test_cli.py +277 -12
- nber_cli-0.5.0/tests/test_config_store.py +226 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/test_db.py +138 -1
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/test_downloader.py +173 -126
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/test_feed.py +132 -8
- nber_cli-0.5.0/tests/test_fetcher.py +597 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/test_info_cache.py +61 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/test_info_cache_flow.py +29 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/test_logs.py +32 -0
- nber_cli-0.5.0/tests/test_mcp.py +121 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/uv.lock +191 -1
- nber_cli-0.4.0/CHANGELOG.md +0 -68
- nber_cli-0.4.0/docs/en/changelog.md +0 -74
- nber_cli-0.4.0/docs/en/configuration.md +0 -139
- nber_cli-0.4.0/docs/en/development.md +0 -89
- nber_cli-0.4.0/docs/en/mcp.md +0 -108
- nber_cli-0.4.0/docs/zh/changelog.md +0 -74
- nber_cli-0.4.0/docs/zh/configuration.md +0 -139
- nber_cli-0.4.0/docs/zh/development.md +0 -89
- nber_cli-0.4.0/docs/zh/mcp.md +0 -108
- nber_cli-0.4.0/src/nber_cli/config.py +0 -28
- nber_cli-0.4.0/src/nber_cli/config_store.py +0 -154
- nber_cli-0.4.0/src/nber_cli/core/models.py +0 -95
- nber_cli-0.4.0/tests/test_config_store.py +0 -88
- nber_cli-0.4.0/tests/test_fetcher.py +0 -138
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.claude/agents/code-to-docs.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.claude/agents/sync-docs-for-i18n.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.claude/settings.json +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.codex/config.toml +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.github/workflows/docs.yml +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.github/workflows/lint.yml +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.github/workflows/publish.yml +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.github/workflows/pytest.yml +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.gitignore +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.mcp.json +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/.python-version +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/LICENSE +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/agents/claude-code.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/agents/codex.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/contributing.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/en/index.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/agents/claude-code.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/agents/codex.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/contributing.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/docs/zh/index.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/mkdocs.yml +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/plugins/nber-cli/.mcp.json +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/plugins/nber-cli/skills/NBER-CLI/SKILL.md +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/__main__.py +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/core/__init__.py +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/src/nber_cli/info_cache.py +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/__init__.py +0 -0
- {nber_cli-0.4.0 → nber_cli-0.5.0}/tests/test_main.py +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
|
3
3
|
"name": "nber-cli",
|
|
4
4
|
"description": "Claude Code marketplace for NBER-CLI research workflows.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.4.0",
|
|
6
6
|
"owner": {
|
|
7
7
|
"name": "Song Tan",
|
|
8
8
|
"email": "sepinetam@gmail.com",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
{
|
|
13
13
|
"name": "nber-cli",
|
|
14
14
|
"description": "Use NBER-CLI to search, inspect, download, and serve NBER working paper workflows.",
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.4.0",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Song Tan",
|
|
18
18
|
"email": "sepinetam@gmail.com"
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
This file is the canonical release history. The English mirror at `docs/en/changelog.md` and the Chinese mirror at `docs/zh/changelog.md` are generated from the same source content and must stay in lock-step. Any release commit updates all three together.
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.5.0] - 2026-06-16
|
|
10
|
+
|
|
11
|
+
### Security
|
|
12
|
+
- RSS feed parsing now uses `defusedxml` to block XML external entity (XXE) and entity expansion attacks.
|
|
13
|
+
- CLI downloads are restricted to the current working directory and its subdirectories by default. Use `nber-cli download --restrict false` to override per invocation. The `download.restrict_dir` config key is stored and validated, but the current CLI default remains `true`.
|
|
14
|
+
- Database `init` and `migrate` paths on macOS and Linux must reside within the user's home directory.
|
|
15
|
+
- Synchronous HTTP requests enforce TLS 1.2 as the minimum version.
|
|
16
|
+
- Selected info/download failure paths now avoid raw exception text; download-log messages and soft database warnings use sanitized summaries or exception class names.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- `nber-cli config show` / `get <key>` / `set <key> <value>` / `verify` for inspecting and editing `~/.nber-cli/config.json`.
|
|
20
|
+
- `download.concurrency` configuration option (default `3`) and the `--concurrency` / `-c` CLI flag to cap concurrent downloads.
|
|
21
|
+
- `--restrict true|false` flag on `nber-cli download` to control directory restriction per invocation.
|
|
22
|
+
- `--yes` flag for `nber-cli mcp-server`; the existing `--port` option now requires explicit confirmation when set to a non-default value.
|
|
23
|
+
- `sse` transport for `nber-cli mcp-server`.
|
|
24
|
+
- JSON Schema (`config.schema.json`) for validating `~/.nber-cli/config.json`.
|
|
25
|
+
- Strict raw-configuration validation that reports malformed JSON, invalid section/value types, and schema-minimum violations without silently injecting defaults.
|
|
26
|
+
- Plugin manifests and marketplace metadata now share the package version, and the Claude plugin skill path uses the case-sensitive tracked `./skills/NBER-CLI` directory.
|
|
27
|
+
- Domain invariant validation in all core dataclasses (`NBER`, `NBERSearchResults`, `NBERFeedItem`, `NBERFeedFetchResult`, clean results, and download results).
|
|
28
|
+
- `get_config_value`, `set_config_value`, `read_config`, `write_config`, and `validate_config` exported from the package top level.
|
|
29
|
+
- Paper ID format validation (`w?\d+`) across CLI, download, and MCP entry points.
|
|
30
|
+
- Validation of fetched paper titles, positive citation IDs, and response/request paper-ID agreement before metadata is accepted.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- Replaced legacy `typing.Dict`, `List`, and `Optional` aliases with modern Python 3.11 syntax.
|
|
34
|
+
- Added `mypy` configuration and strengthened type annotations across `cli.py`, `config_store.py`, and `fetcher.py`.
|
|
35
|
+
- `mcp-server` transport name corrected to `streamable-http`; the existing `--port` option now uses `--yes` confirmation for non-default values.
|
|
36
|
+
- Retry loops in `fetcher.py` now use exponential backoff capped at 30 seconds.
|
|
37
|
+
- `feed fetch` skips malformed individual RSS items instead of failing the entire feed.
|
|
38
|
+
- Invalid configured or per-call download concurrency values are rejected or fall back to the documented safe default instead of creating an invalid semaphore.
|
|
39
|
+
- Database schema-changing and data-writing operations reject databases with a future `PRAGMA user_version`; the diagnostic schema-version reader remains read-only.
|
|
40
|
+
- Feed fetching establishes/validates the local schema before the network request, then writes feed items plus fetch history transactionally after the response is parsed; cleanup operations pair schema validation/upgrade and deletion in one SQLite transaction.
|
|
41
|
+
- `download.py` enables `raise_for_status=True` on `ClientSession`.
|
|
42
|
+
- Error handling narrowed to specific network/timeout exception types with preserved exception chains.
|
|
43
|
+
- Removed the info cache hit hint that was printed to stderr on cached `info` lookups.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- `feed fetch` now tolerates unescaped `<` characters followed by whitespace or a digit in RSS title and description text while keeping strict XML parsing for all other malformed input.
|
|
47
|
+
- RSS parse failures now report their line and column when available, and `feed fetch` reports runtime parse errors with exit code `1` without printing command usage.
|
|
48
|
+
|
|
49
|
+
## [0.4.0] - 2026-06-04
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
- `nber-cli info --refresh` skips the local `info_cache` and re-fetches the paper from NBER. The new data is written back to the cache when the cache is enabled.
|
|
53
|
+
- `nber-cli info cache --turn-on` / `--turn-off` toggle the `info_cache` lookup globally and persist the state to `~/.nber-cli/config.json`.
|
|
54
|
+
- `nber-cli info cache --set-refresh <N>` sets the cache refresh interval in days. The value is persisted to `~/.nber-cli/config.json` and used as the TTL for every subsequent `info` call. Defaults to `30` days.
|
|
55
|
+
- `nber-cli info cache clear` with `--days`, `--all`, `--start-date`, or `--end-date` mirrors the `feed clean` parameter set, using `last_fetched_at` from the `info_cache` table. `nber-cli info cache clean` is a convenience alias for `clear --all`.
|
|
56
|
+
- `nber-cli info cache` (no sub-action) prints the current cache state, TTL, and cached row count.
|
|
57
|
+
- New `nber_cli.config_store` module: centralised read and write of `~/.nber-cli/config.json` plus the `InfoCacheSettings` dataclass and helpers (`get_info_cache_settings`, `set_info_cache_enabled`, `set_info_cache_ttl_days`).
|
|
58
|
+
- New `nber_cli.info_cache.get_paper_with_info_cache_result` async helper (in the `nber_cli.info_cache` module) that returns an `InfoCacheLookupResult` carrying the `NBER` paper and a `from_cache` flag, so callers (CLI and MCP) can surface a "loaded from cache" hint.
|
|
59
|
+
- Public Python API exports from the package top level: `InfoCacheSettings`, `clear_info_cache`, `count_info_cache`, `get_info_cache_settings`, `get_info_cache_ttl_days`, `is_info_cache_enabled`, `is_info_cache_expired`, `set_info_cache_enabled`, `set_info_cache_ttl_days`, `NBERInfoCacheClearResult`. `InfoCacheLookupResult` and `get_paper_with_info_cache_result` are exposed from the `nber_cli.info_cache` module rather than the package top level; import them as `from nber_cli.info_cache import ...`.
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
- `~/.nber-cli/config.json` now carries an `info` section: `info.cache_enabled` (default `true`) and `info.cache_ttl_days` (default `30`). Missing or malformed fields fall back to defaults.
|
|
63
|
+
- `info` now prints a one-line stderr hint when the paper was served from the local cache, pointing to `nber-cli info <id> --refresh` for a fresh fetch.
|
|
64
|
+
|
|
65
|
+
## [0.3.1] - 2026-06-03
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
- `db init` and `db migrate` top-level subcommands replace `feed init` and `feed migrate`. The database is now general-purpose and stores feed cache, behavior logs, and paper metadata cache.
|
|
69
|
+
- `info_cache` table caches paper metadata fetched via `info` and the MCP `get_paper_info` tool. Subsequent lookups return immediately from the cache.
|
|
70
|
+
- `query_log`, `download_log`, and `info_log` tables record search keywords, download outcomes, and paper info lookups for later auditing.
|
|
71
|
+
- `schema_version` field written to `~/.nber-cli/config.json` so future schema migrations can roll forward safely.
|
|
72
|
+
|
|
73
|
+
### Changed
|
|
74
|
+
- Default database renamed from `feed.db` to `nber.db`. Existing `~/.nber-cli/feed.db` installations continue to work without manual steps.
|
|
75
|
+
- Database schema upgraded from `user_version = 1` to `user_version = 2`. Existing v1 databases are upgraded automatically on next CLI invocation; original `feed_items` rows are preserved.
|
|
76
|
+
- Database code consolidated into `nber_cli.db`. The original `init_feed_database`, `migrate_feed_database`, and `get_feed_database_path` helpers are kept as thin compatibility wrappers.
|
|
77
|
+
|
|
78
|
+
## [0.3.0] - 2026-06-03
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
- `feed init` subcommand: initialize a local SQLite feed cache and write its path to user config.
|
|
82
|
+
- `feed fetch` subcommand: fetch NBER's new working papers RSS feed, cache seen items, and show newly discovered papers by default.
|
|
83
|
+
- `feed fetch --max-items`: limit displayed feed output. When used without `--display-all`, display-all behavior is enabled automatically.
|
|
84
|
+
- `feed migrate` subcommand: move the feed cache database and SQLite sidecar files to a new path, then update user config.
|
|
85
|
+
- `feed clean` subcommand: clean cached feed database records by age, date range, or all records after interactive confirmation.
|
|
86
|
+
- Python API exports for feed cache helpers and feed result models.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
- Added user config support at `~/.nber-cli/config.json` for the feed cache database path.
|
|
90
|
+
- Expanded English and Chinese documentation for feed commands, configuration, Python API, and release notes.
|
|
91
|
+
|
|
92
|
+
## [0.2.0] - 2026-05-31
|
|
93
|
+
|
|
94
|
+
### Added
|
|
95
|
+
- `download` subcommand: single paper ID or batch mode (`--batch`), explicit file path (`--file`), target directory (`--save-base`).
|
|
96
|
+
- `info` subcommand: paper metadata with `--all` flag for full details and `--format json` option.
|
|
97
|
+
- `search` subcommand: full-text search with date filters (`--start-date`, `--end-date`), pagination (`--page`, `--per-page`), `--format json` option.
|
|
98
|
+
- `mcp-server` subcommand: MCP server for AI agent integration with stdio and streamable_http transports.
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
- Reworked CLI into subcommand syntax (`nber-cli <subcommand>`).
|
|
102
|
+
- Simplified downloader to direct async HTTP PDF fetches (removed database-backed state tracking).
|
|
103
|
+
- Removed legacy web UI module and script entrypoint.
|
|
104
|
+
|
|
105
|
+
## [0.1.4] - 2025-08-09
|
|
106
|
+
|
|
107
|
+
### Added
|
|
108
|
+
- Added `--version` / `-v` flag to display current version.
|
|
109
|
+
- Added comprehensive help message with examples.
|
|
110
|
+
- Added `__main__.py` file to support `python -m nber_cli` usage.
|
|
111
|
+
- Added argument grouping for better CLI organization.
|
|
112
|
+
- Added automatic help display when no arguments are provided.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nber-cli
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: A command
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: A command-line interface for accessing National Bureau of Economic Research (NBER) papers without a browser.
|
|
5
5
|
Project-URL: Homepage, https://github.com/sepinetam/nber-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/sepinetam/nber-cli
|
|
7
7
|
Project-URL: Issues, https://github.com/sepinetam/nber-cli/issues
|
|
@@ -22,6 +22,7 @@ Requires-Python: >=3.11
|
|
|
22
22
|
Requires-Dist: aiohttp
|
|
23
23
|
Requires-Dist: aiohttp-retry
|
|
24
24
|
Requires-Dist: certifi
|
|
25
|
+
Requires-Dist: defusedxml>=0.7.1
|
|
25
26
|
Requires-Dist: fake-useragent
|
|
26
27
|
Requires-Dist: mcp>=1.27.1
|
|
27
28
|
Description-Content-Type: text/markdown
|
|
@@ -33,6 +34,8 @@ A command line interface for reaching the National Bureau of Economic Research (
|
|
|
33
34
|
[](https://github.com/sepinetam/nber-cli/actions/workflows/lint.yml)
|
|
34
35
|
[](https://github.com/sepinetam/nber-cli/actions/workflows/docs.yml)
|
|
35
36
|
[](LICENSE)
|
|
37
|
+
[](https://pypi.org/project/nber-cli/)
|
|
38
|
+
[](https://pepy.tech/projects/nber-cli)
|
|
36
39
|
|
|
37
40
|
[简体中文](README.zh-CN.md) | [Documentation](docs/en/index.md)
|
|
38
41
|
|
|
@@ -43,9 +46,14 @@ A command line interface for reaching the National Bureau of Economic Research (
|
|
|
43
46
|
- Search NBER working papers by title, paper number, author, abstract, or keyword.
|
|
44
47
|
- Fetch structured metadata and abstracts for a paper ID such as `w25000`.
|
|
45
48
|
- Download single papers or batches as PDF files.
|
|
49
|
+
- Track newly released NBER working papers through a local RSS feed cache (`nber-cli feed fetch` / `feed clean`).
|
|
50
|
+
- Cache paper metadata locally (`nber-cli info` writes to `info_cache`) with a sliding TTL, plus a behavior log for `search`, `download`, and `info` lookups.
|
|
51
|
+
- Store the cache, RSS items, and behavior logs in a local SQLite database at `~/.nber-cli/nber.db` (path configurable via `nber-cli db init` / `db migrate`).
|
|
46
52
|
- Expose the same core workflows as MCP tools for AI agents.
|
|
47
53
|
- Return human-readable output by default, with JSON output for automation.
|
|
48
54
|
|
|
55
|
+
See [Configuration](docs/en/configuration.md) for the full list of configurable values and the local database layout, and [Usage Policy](docs/en/policy.md) for what NBER-CLI writes to disk by default.
|
|
56
|
+
|
|
49
57
|
## Quick Start
|
|
50
58
|
|
|
51
59
|
### Use in Agents
|
|
@@ -5,6 +5,8 @@ A command line interface for reaching the National Bureau of Economic Research (
|
|
|
5
5
|
[](https://github.com/sepinetam/nber-cli/actions/workflows/lint.yml)
|
|
6
6
|
[](https://github.com/sepinetam/nber-cli/actions/workflows/docs.yml)
|
|
7
7
|
[](LICENSE)
|
|
8
|
+
[](https://pypi.org/project/nber-cli/)
|
|
9
|
+
[](https://pepy.tech/projects/nber-cli)
|
|
8
10
|
|
|
9
11
|
[简体中文](README.zh-CN.md) | [Documentation](docs/en/index.md)
|
|
10
12
|
|
|
@@ -15,9 +17,14 @@ A command line interface for reaching the National Bureau of Economic Research (
|
|
|
15
17
|
- Search NBER working papers by title, paper number, author, abstract, or keyword.
|
|
16
18
|
- Fetch structured metadata and abstracts for a paper ID such as `w25000`.
|
|
17
19
|
- Download single papers or batches as PDF files.
|
|
20
|
+
- Track newly released NBER working papers through a local RSS feed cache (`nber-cli feed fetch` / `feed clean`).
|
|
21
|
+
- Cache paper metadata locally (`nber-cli info` writes to `info_cache`) with a sliding TTL, plus a behavior log for `search`, `download`, and `info` lookups.
|
|
22
|
+
- Store the cache, RSS items, and behavior logs in a local SQLite database at `~/.nber-cli/nber.db` (path configurable via `nber-cli db init` / `db migrate`).
|
|
18
23
|
- Expose the same core workflows as MCP tools for AI agents.
|
|
19
24
|
- Return human-readable output by default, with JSON output for automation.
|
|
20
25
|
|
|
26
|
+
See [Configuration](docs/en/configuration.md) for the full list of configurable values and the local database layout, and [Usage Policy](docs/en/policy.md) for what NBER-CLI writes to disk by default.
|
|
27
|
+
|
|
21
28
|
## Quick Start
|
|
22
29
|
|
|
23
30
|
### Use in Agents
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
[](https://github.com/sepinetam/nber-cli/actions/workflows/lint.yml)
|
|
6
6
|
[](https://github.com/sepinetam/nber-cli/actions/workflows/docs.yml)
|
|
7
7
|
[](LICENSE)
|
|
8
|
-
|
|
8
|
+
[](https://pypi.org/project/nber-cli/)
|
|
9
|
+
[](https://pepy.tech/projects/nber-cli)
|
|
9
10
|
[English](README.md) | [中文文档](docs/zh/index.md)
|
|
10
11
|
|
|
11
12
|
> **NBER** 是 [美国国家经济研究局](https://www.nber.org)(National Bureau of Economic Research)的注册商标。本项目是独立的开源工具,与美国国家经济研究局**不存在任何附属、认可或赞助关系**。使用本项目即视为同意[使用政策](docs/zh/policy.md)。
|
|
@@ -15,9 +16,14 @@
|
|
|
15
16
|
- 按标题、论文编号、作者、摘要或关键词搜索 NBER 工作论文。
|
|
16
17
|
- 通过 `w25000` 这样的论文编号获取结构化元数据和摘要。
|
|
17
18
|
- 下载单篇或批量论文 PDF。
|
|
19
|
+
- 通过本地 RSS feed 缓存追踪 NBER 新发布的工作论文(`nber-cli feed fetch` / `feed clean`)。
|
|
20
|
+
- 本地缓存论文元数据(`nber-cli info` 会写入 `info_cache`),采用滑动 TTL;同时为 `search`、`download` 和 `info` 查询记录行为日志。
|
|
21
|
+
- 把缓存、RSS 条目和行为日志统一存放在本地 SQLite 数据库 `~/.nber-cli/nber.db`(路径可通过 `nber-cli db init` / `db migrate` 配置)。
|
|
18
22
|
- 通过 MCP 工具把核心能力暴露给 AI Agent。
|
|
19
23
|
- 默认输出适合阅读的文本,也支持 JSON 输出用于自动化流程。
|
|
20
24
|
|
|
25
|
+
完整可配置项和本地数据库结构请见[配置](docs/zh/configuration.md),默认写入磁盘的内容请见[使用政策](docs/zh/policy.md)。
|
|
26
|
+
|
|
21
27
|
## 快速开始
|
|
22
28
|
|
|
23
29
|
### 在 Agent 中使用
|
|
@@ -33,7 +33,7 @@ Agents that support MCP can run NBER-CLI without a checked-out repository:
|
|
|
33
33
|
Agents that support skills should load the NBER-CLI skill from:
|
|
34
34
|
|
|
35
35
|
```text
|
|
36
|
-
plugins/nber-cli/skills/
|
|
36
|
+
plugins/nber-cli/skills/NBER-CLI/SKILL.md
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
The skill tells the agent when to use NBER-CLI, how to run `uvx nber-cli ...`, how to configure MCP, and how to interpret access errors.
|
|
@@ -24,7 +24,7 @@ This runs the published `nber-cli` package with `uvx`, so a checked-out copy of
|
|
|
24
24
|
If OpenClaw supports skill or instruction imports, load:
|
|
25
25
|
|
|
26
26
|
```text
|
|
27
|
-
plugins/nber-cli/skills/
|
|
27
|
+
plugins/nber-cli/skills/NBER-CLI/SKILL.md
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
The skill gives the agent the usage policy, command examples, JSON output guidance, and common error interpretation.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented here.
|
|
4
|
+
|
|
5
|
+
This page mirrors the canonical `CHANGELOG.md` at the repository root. The Chinese mirror at `docs/zh/changelog.md` carries the same content. Any release commit updates all three together.
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
## 0.5.0 - 2026-06-16
|
|
10
|
+
|
|
11
|
+
### Security
|
|
12
|
+
|
|
13
|
+
- RSS feed parsing now uses `defusedxml` to block XML external entity (XXE) and entity expansion attacks.
|
|
14
|
+
- CLI downloads are restricted to the current working directory and its subdirectories by default. Use `nber-cli download --restrict false` to override per invocation. The `download.restrict_dir` config key is stored and validated, but the current CLI default remains `true`.
|
|
15
|
+
- Database `init` and `migrate` paths on macOS and Linux must reside within the user's home directory.
|
|
16
|
+
- Synchronous HTTP requests enforce TLS 1.2 as the minimum version.
|
|
17
|
+
- Selected info/download failure paths now avoid raw exception text; download-log messages and soft database warnings use sanitized summaries or exception class names.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Added `nber-cli config show` / `get <key>` / `set <key> <value>` / `verify` for inspecting and editing `~/.nber-cli/config.json`.
|
|
22
|
+
- Added `download.concurrency` configuration option (default `3`) and the `--concurrency` / `-c` CLI flag to cap concurrent downloads.
|
|
23
|
+
- Added `--restrict true|false` flag on `nber-cli download` to control directory restriction per invocation.
|
|
24
|
+
- Added `--yes` for `nber-cli mcp-server`; the existing `--port` option now requires explicit confirmation when set to a non-default value.
|
|
25
|
+
- Added the `sse` transport for `nber-cli mcp-server`.
|
|
26
|
+
- Added JSON Schema (`config.schema.json`) for validating `~/.nber-cli/config.json`.
|
|
27
|
+
- Added strict raw-configuration validation that reports malformed JSON, invalid section/value types, and schema-minimum violations without silently injecting defaults.
|
|
28
|
+
- Added plugin manifest and marketplace metadata version synchronization, with the Claude plugin skill path corrected to the case-sensitive tracked `./skills/NBER-CLI` directory.
|
|
29
|
+
- Added domain invariant validation in all core dataclasses (`NBER`, `NBERSearchResults`, `NBERFeedItem`, `NBERFeedFetchResult`, clean results, and download results).
|
|
30
|
+
- Added `get_config_value`, `set_config_value`, `read_config`, `write_config`, and `validate_config` exports from the package top level.
|
|
31
|
+
- Added paper ID format validation (`w?\d+`) across CLI, download, and MCP entry points.
|
|
32
|
+
- Added validation of fetched paper titles, positive citation IDs, and response/request paper-ID agreement before metadata is accepted.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Replaced legacy `typing.Dict`, `List`, and `Optional` aliases with modern Python 3.11 syntax.
|
|
37
|
+
- Added `mypy` configuration and strengthened type annotations across `cli.py`, `config_store.py`, and `fetcher.py`.
|
|
38
|
+
- Corrected the `mcp-server` transport name to `streamable-http`; the existing `--port` option now uses `--yes` confirmation for non-default values.
|
|
39
|
+
- Retry loops in `fetcher.py` now use exponential backoff capped at 30 seconds.
|
|
40
|
+
- `feed fetch` skips malformed individual RSS items instead of failing the entire feed.
|
|
41
|
+
- Invalid configured or per-call download concurrency values are rejected or fall back to the documented safe default instead of creating an invalid semaphore.
|
|
42
|
+
- Database schema-changing and data-writing operations reject databases with a future `PRAGMA user_version`; the diagnostic schema-version reader remains read-only.
|
|
43
|
+
- Feed fetching establishes/validates the local schema before the network request, then writes feed items plus fetch history transactionally after the response is parsed; cleanup operations pair schema validation/upgrade and deletion in one SQLite transaction.
|
|
44
|
+
- `download.py` enables `raise_for_status=True` on `ClientSession`.
|
|
45
|
+
- Error handling narrowed to specific network/timeout exception types with preserved exception chains.
|
|
46
|
+
- Removed the info cache hit hint that was printed to stderr on cached `info` lookups.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- `feed fetch` now tolerates unescaped `<` characters followed by whitespace or a digit in RSS title and description text while keeping strict XML parsing for all other malformed input.
|
|
51
|
+
- RSS parse failures now report their line and column when available, and `feed fetch` reports runtime parse errors with exit code `1` without printing command usage.
|
|
52
|
+
|
|
53
|
+
## 0.4.0 - 2026-06-04
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- Added `nber-cli info --refresh` to bypass the local `info_cache` and re-fetch paper metadata from NBER. The fresh data is written back to the cache when the cache is enabled.
|
|
58
|
+
- Added `nber-cli info cache --turn-on` and `--turn-off` to toggle the `info_cache` lookup globally. The setting is persisted to `~/.nber-cli/config.json`.
|
|
59
|
+
- Added `nber-cli info cache --set-refresh <N>` to set the cache refresh interval in days. The value is persisted to `~/.nber-cli/config.json` and applied as the TTL for every subsequent `info` call. Defaults to `30` days.
|
|
60
|
+
- Added `nber-cli info cache clear` with the same parameter set as `feed clean`: `--days`, `--all`, `--start-date`, and `--end-date`. Filtering uses `last_fetched_at` from the `info_cache` table. `nber-cli info cache clean` is a convenience alias for `clear --all`.
|
|
61
|
+
- Added `nber-cli info cache` (no sub-action) to print the current cache state, TTL, and cached row count.
|
|
62
|
+
- Added `nber_cli.config_store` module with `InfoCacheSettings` and helpers (`get_info_cache_settings`, `set_info_cache_enabled`, `set_info_cache_ttl_days`) for reading and writing `~/.nber-cli/config.json`.
|
|
63
|
+
- Added `nber_cli.info_cache.get_paper_with_info_cache_result` async helper that returns an `InfoCacheLookupResult` carrying the `NBER` paper and a `from_cache` flag.
|
|
64
|
+
- Added public Python API exports from the package top level: `InfoCacheSettings`, `clear_info_cache`, `count_info_cache`, `get_info_cache_settings`, `get_info_cache_ttl_days`, `is_info_cache_enabled`, `is_info_cache_expired`, `set_info_cache_enabled`, `set_info_cache_ttl_days`, `NBERInfoCacheClearResult`. `InfoCacheLookupResult` and `get_paper_with_info_cache_result` are exposed from the `nber_cli.info_cache` module rather than the package top level; import them as `from nber_cli.info_cache import ...`.
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
|
|
68
|
+
- `~/.nber-cli/config.json` now stores an `info` section: `info.cache_enabled` (default `true`) and `info.cache_ttl_days` (default `30`). Missing or malformed fields fall back to defaults.
|
|
69
|
+
- `info` now prints a one-line stderr hint when the paper was served from the local cache, pointing to `nber-cli info <id> --refresh` for a fresh fetch.
|
|
70
|
+
|
|
71
|
+
## 0.3.1 - 2026-06-03
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- Added `nber-cli db init` and `nber-cli db migrate` for initializing and relocating the local database. These replace `feed init` and `feed migrate`.
|
|
76
|
+
- Added `info_cache` table so repeated `nber-cli info` and MCP `get_paper_info` calls return immediately from cache.
|
|
77
|
+
- Added `query_log`, `download_log`, and `info_log` tables for recording search keywords, download outcomes, and info lookups.
|
|
78
|
+
- Added `schema_version` field in `~/.nber-cli/config.json` for forward-compatible schema upgrades.
|
|
79
|
+
|
|
80
|
+
### Changed
|
|
81
|
+
|
|
82
|
+
- Renamed default database file from `feed.db` to `nber.db`. Existing `~/.nber-cli/feed.db` installations keep working without manual steps.
|
|
83
|
+
- Upgraded database schema from version 1 to version 2 with automatic upgrade on next invocation.
|
|
84
|
+
- Consolidated database code into `nber_cli.db`. Old `init_feed_database` and `migrate_feed_database` helpers remain as thin compatibility wrappers.
|
|
85
|
+
|
|
86
|
+
## 0.3.0 - 2026-06-03
|
|
87
|
+
|
|
88
|
+
### Added
|
|
89
|
+
|
|
90
|
+
- Added `nber-cli feed init` for creating a local SQLite feed cache.
|
|
91
|
+
- Added `nber-cli feed fetch` for fetching NBER's new working papers RSS feed and showing newly cached items.
|
|
92
|
+
- Added `nber-cli feed fetch --max-items` for limiting displayed feed output.
|
|
93
|
+
- Added `nber-cli feed migrate` for moving the feed cache database and updating user config.
|
|
94
|
+
- Added `nber-cli feed clean` for cleaning cached feed database records with confirmation.
|
|
95
|
+
- Added Python API documentation for feed cache helpers and feed data models.
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
|
|
99
|
+
- Added user config documentation for `~/.nber-cli/config.json` and `feed.db-path`.
|
|
100
|
+
- Expanded English and Chinese feed cache documentation across CLI, getting started, configuration, and Python API pages.
|
|
101
|
+
|
|
102
|
+
## 0.2.0 - 2026-05-31
|
|
103
|
+
|
|
104
|
+
### Changed
|
|
105
|
+
|
|
106
|
+
- Reworked the CLI into `nber-cli download ...` subcommand syntax.
|
|
107
|
+
- Added `--file/-f` and `--save-base/-s` path handling behavior.
|
|
108
|
+
- Added `--batch/-b` multi-ID download mode.
|
|
109
|
+
- Removed database-backed download state tracking.
|
|
110
|
+
- Simplified the downloader to direct async HTTP PDF fetches.
|
|
111
|
+
- Updated documentation for the v0.2 command model.
|
|
112
|
+
- Removed the legacy web UI module and script entrypoint.
|
|
113
|
+
|
|
114
|
+
## 0.1.4 - 2025-08-09
|
|
115
|
+
|
|
116
|
+
### Added
|
|
117
|
+
|
|
118
|
+
- Added `--version` / `-v` flag to display current version.
|
|
119
|
+
- Added comprehensive help message with examples.
|
|
120
|
+
- Added `__main__.py` support for `python -m nber_cli`.
|
|
121
|
+
- Added argument grouping for better CLI organization.
|
|
122
|
+
- Added automatic help display when no arguments are provided.
|
|
@@ -72,6 +72,17 @@ nber-cli download -b w34567 w25000 w32000 -s ~/papers/nber
|
|
|
72
72
|
- If neither `--file` nor `--save-base` is passed, PDFs are saved in the current working directory.
|
|
73
73
|
- If a paper is unavailable, NBER-CLI exits with code `1` and prints a readable error message.
|
|
74
74
|
|
|
75
|
+
### download Filesystem Behavior
|
|
76
|
+
|
|
77
|
+
- **Existing files are overwritten.** When the target PDF path already exists, NBER-CLI writes the new bytes in place and overwrites the previous file. There is no "skip if newer" or "preserve on error" mode.
|
|
78
|
+
- **No atomic rename.** The download is read fully into memory and then written to the target path in a single `write_bytes` call. If the process is killed, the host loses power, or the disk fills up mid-write, the file at the target path can be left empty, truncated, or partially written. The previous file (when it existed) is not preserved on the failure path.
|
|
79
|
+
- **Parent directories are auto-created.** The parent of the resolved output path is created with `mkdir(parents=True, exist_ok=True)`. Missing intermediate directories do not cause a failure, but the process needs write permission on the deepest existing ancestor.
|
|
80
|
+
- **Path resolution is literal.** The string passed to `--file` (or `<paper_id>.pdf` derived from `--save-base`) is used verbatim. Relative paths resolve against the current working directory. Tilde expansion (`~`) is **not** performed; if you want `~`-relative paths, your shell needs to expand them.
|
|
81
|
+
- **Single download is fully in-memory.** The full PDF body is buffered before any disk write, so a single download holds the entire PDF in memory for the duration of the transfer. Very large PDFs may briefly use several hundred MB of RAM.
|
|
82
|
+
- **Python API callers own their session.** When you call `download_paper` / `download_paper_to_file` / `download_multiple_papers` with a custom `session=...`, you own the underlying `ClientSession` (or `RetryClient`), its timeouts, its connector limits, and any retry behavior. NBER-CLI does not wrap your session in a retry client. The default NBER_CLI_CONFIG timeout and retry settings only apply when the function creates its own session.
|
|
83
|
+
|
|
84
|
+
For the Python API, see [Python API — Download PDF](python-api.md#download-a-pdf).
|
|
85
|
+
|
|
75
86
|
## info
|
|
76
87
|
|
|
77
88
|
Show paper metadata:
|
|
@@ -104,7 +115,9 @@ nber-cli info w25000 -f json
|
|
|
104
115
|
|
|
105
116
|
When the cache is enabled and the cached entry has not yet passed the configured TTL, repeated `info` calls are served from the local database. The first `info` call after a TTL expiry, or any call with `--refresh`, performs a live fetch.
|
|
106
117
|
|
|
107
|
-
The
|
|
118
|
+
The TTL is **sliding**: every cache hit updates `last_fetched_at` and increments `fetch_count`, so frequently consulted papers keep their cached copy until at least `cache_ttl_days` have passed since the most recent hit. "Last fetched" therefore means "last local hit", not "last network fetch from NBER". `--refresh` always bypasses the cache and writes a fresh row.
|
|
119
|
+
|
|
120
|
+
The MCP `get_paper_info` tool follows the same cache behavior, but it does not accept a per-call `--refresh` argument. The tool always honors the current `info_cache` toggle and TTL; agents that need a forced refresh must toggle the cache off, call `get_paper_info`, and toggle the cache back on (or rely on the next call after a TTL-driven re-fetch).
|
|
108
121
|
|
|
109
122
|
## info cache
|
|
110
123
|
|
|
@@ -114,8 +127,11 @@ Show the current cache state, TTL, and row count:
|
|
|
114
127
|
|
|
115
128
|
```bash
|
|
116
129
|
nber-cli info cache
|
|
130
|
+
nber-cli info cache status
|
|
117
131
|
```
|
|
118
132
|
|
|
133
|
+
`info cache` and `info cache status` are equivalent — both print the same status view (cache enabled/disabled, current TTL, and row count). The explicit `status` sub-action is provided for symmetry with `clear`/`clean` and for scripts that prefer an unambiguous form.
|
|
134
|
+
|
|
119
135
|
Toggle the cache globally:
|
|
120
136
|
|
|
121
137
|
```bash
|
|
@@ -174,6 +190,7 @@ Only `y` or `Y` continues. Any other response aborts without deleting records.
|
|
|
174
190
|
| (none) | `--turn-on` | Enable the info cache globally. |
|
|
175
191
|
| (none) | `--turn-off` | Disable the info cache globally. |
|
|
176
192
|
| (none) | `--set-refresh` | Set the info cache refresh interval in days. Must be a positive integer. |
|
|
193
|
+
| `status` | — | Print the current cache state, TTL, and row count. Equivalent to running `info cache` with no sub-action. |
|
|
177
194
|
| `clear` | `--days` | Clean cached records not refreshed for this many days. Defaults to `30`. |
|
|
178
195
|
| `clear` | `--all` | Clean all cached records. |
|
|
179
196
|
| `clear` | `--start-date` | Clean cached records refreshed on or after this date, formatted `YYYY-MM-DD`. |
|
|
@@ -239,6 +256,8 @@ nber-cli feed fetch --display-all true
|
|
|
239
256
|
nber-cli feed fetch --display-all
|
|
240
257
|
```
|
|
241
258
|
|
|
259
|
+
`--display-all` accepts a boolean value. The parser recognises (case-insensitive, whitespace tolerated) `true`, `false`, `1`, `0`, `yes`, `no`, `y`, `n`, `on`, `off`. When the flag is passed with no value (`--display-all` on its own) it defaults to `true`. Any other value is rejected with exit code `2`.
|
|
260
|
+
|
|
242
261
|
Limit displayed output:
|
|
243
262
|
|
|
244
263
|
```bash
|
|
@@ -254,6 +273,8 @@ nber-cli feed fetch --format json
|
|
|
254
273
|
nber-cli feed fetch -f json
|
|
255
274
|
```
|
|
256
275
|
|
|
276
|
+
NBER-CLI strictly parses the RSS XML. To tolerate a known upstream formatting issue, it repairs only unescaped `<` characters followed by whitespace or a digit inside RSS `title` and `description` text. Other malformed XML is rejected. Parse errors exit with code `1`, print a concise error with the line and column when available, and do not print command usage.
|
|
277
|
+
|
|
257
278
|
### feed clean
|
|
258
279
|
|
|
259
280
|
Clean cached feed database records. This deletes records from the local cache, not from NBER. Deleted cache records may be fetched again as new items if they still appear in the RSS feed.
|
|
@@ -294,7 +315,7 @@ Only `y` or `Y` continues. Any other response aborts without deleting records.
|
|
|
294
315
|
|
|
295
316
|
| Subcommand | Option | Description |
|
|
296
317
|
| --- | --- | --- |
|
|
297
|
-
| `fetch` | `--display-all [true
|
|
318
|
+
| `fetch` | `--display-all [true\|false]` | Display all fetched RSS items instead of only new items. Accepts `true`/`false`/`1`/`0`/`yes`/`no`/`y`/`n`/`on`/`off` (case-insensitive). When passed without a value, defaults to `true`. |
|
|
298
319
|
| `fetch` | `--format`, `-f` | Output format: `list` or `json`. Defaults to `list`. |
|
|
299
320
|
| `fetch` | `--max-items` | Maximum number of feed items to display. |
|
|
300
321
|
| `clean` | `--days` | Clean cached records not seen for this many days. Defaults to `30`. |
|
|
@@ -364,9 +385,25 @@ For client configuration and tool details, see [MCP Server](mcp.md).
|
|
|
364
385
|
| Code | Meaning |
|
|
365
386
|
| --- | --- |
|
|
366
387
|
| `0` | Command completed successfully, or help was printed. |
|
|
367
|
-
| `1` | Runtime failure such as a failed download. |
|
|
368
|
-
| `2` | Invalid command-line arguments. |
|
|
388
|
+
| `1` | Runtime failure such as a failed download, a network error, a parse error, or any other unhandled exception. |
|
|
389
|
+
| `2` | Invalid command-line arguments. Argparse raises `SystemExit(2)` and prints a usage message to stderr. |
|
|
390
|
+
|
|
391
|
+
A few extra rules that are easy to miss:
|
|
392
|
+
|
|
393
|
+
- A single `download` failure exits `1`. The successful `Successfully downloaded <id> to <path>` line goes to stdout; the `Failed to download <id>: <reason>` line goes to stderr. The download log row in `download_log` is written before the failure is printed.
|
|
394
|
+
- A batch `download` runs every requested paper and only exits `1` at the end if at least one paper failed. Successful files are written to stdout (`Successfully downloaded ...`), failures and the per-failure reasons go to stderr. The exit code is `0` only when every paper succeeded.
|
|
395
|
+
- A `feed fetch` RSS parse failure exits `1` and writes a concise error to stderr without printing command usage. The error includes the XML line and column when available.
|
|
396
|
+
- `db init`, `db migrate`, `info cache clear`, and `feed clean` print a confirmation prompt to stderr. The command aborts with exit code `0` if the user declines (`Abort.` is printed to stderr). The actual deletion (when confirmed) exits `0` on success.
|
|
397
|
+
- Database record-keeping failures (`record_query`, `record_download`, `record_info`, `touch_info_cache`, `write_info_cache`) print a one-line `warning: failed to ...` to stderr but do **not** raise. The main command's exit code is unaffected.
|
|
398
|
+
- The download module reads the entire PDF body into memory and then writes it in one call. A failure that occurs between the network read and the disk write (process kill, disk full, permission revoked) typically surfaces as a Python exception on the way out; the user sees the traceback on stderr and the process exits `1`. There is no atomic-rename guarantee, so a target file may be left empty or partially written when this happens.
|
|
369
399
|
|
|
370
400
|
## Output Formats
|
|
371
401
|
|
|
372
402
|
`info`, `search`, and `feed fetch` default to `list`, a readable text format. Use `--format json` when piping output into scripts or agent workflows.
|
|
403
|
+
|
|
404
|
+
The rule of thumb for scripting:
|
|
405
|
+
|
|
406
|
+
- **stdout** carries the human-readable output or the JSON payload (with `--format json`).
|
|
407
|
+
- **stderr** carries the cache-hit hint, every per-paper error message, every per-paper success line that is incidental to the main payload, the `warning: ...` line for failed background logging, and the confirmation prompts for destructive commands.
|
|
408
|
+
|
|
409
|
+
This means a script that wants the JSON payload can capture stdout with `2>/dev/null` (or simply `2>&-`), and a script that wants only errors can capture stderr with `2>&1 >/dev/null`.
|