nber-cli 0.3.1__tar.gz → 0.4.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 (81) hide show
  1. {nber_cli-0.3.1 → nber_cli-0.4.0}/CHANGELOG.md +16 -0
  2. {nber_cli-0.3.1 → nber_cli-0.4.0}/PKG-INFO +1 -1
  3. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/changelog.md +18 -0
  4. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/cli.md +79 -0
  5. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/configuration.md +11 -1
  6. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/python-api.md +91 -0
  7. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/changelog.md +18 -0
  8. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/cli.md +79 -0
  9. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/configuration.md +11 -1
  10. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/python-api.md +91 -0
  11. {nber_cli-0.3.1 → nber_cli-0.4.0}/pyproject.toml +1 -1
  12. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/__init__.py +22 -0
  13. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/cli.py +205 -10
  14. nber_cli-0.4.0/src/nber_cli/config_store.py +154 -0
  15. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/core/models.py +12 -0
  16. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/db.py +186 -32
  17. nber_cli-0.4.0/src/nber_cli/info_cache.py +51 -0
  18. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/mcp.py +3 -7
  19. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/conftest.py +4 -1
  20. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/test_cli.py +264 -5
  21. nber_cli-0.4.0/tests/test_config_store.py +88 -0
  22. nber_cli-0.4.0/tests/test_info_cache.py +281 -0
  23. nber_cli-0.4.0/tests/test_info_cache_flow.py +99 -0
  24. {nber_cli-0.3.1 → nber_cli-0.4.0}/uv.lock +1 -1
  25. nber_cli-0.3.1/tests/test_info_cache.py +0 -148
  26. {nber_cli-0.3.1 → nber_cli-0.4.0}/.claude/agents/code-to-docs.md +0 -0
  27. {nber_cli-0.3.1 → nber_cli-0.4.0}/.claude/agents/sync-docs-for-i18n.md +0 -0
  28. {nber_cli-0.3.1 → nber_cli-0.4.0}/.claude/settings.json +0 -0
  29. {nber_cli-0.3.1 → nber_cli-0.4.0}/.claude-plugin/marketplace.json +0 -0
  30. {nber_cli-0.3.1 → nber_cli-0.4.0}/.codex/config.toml +0 -0
  31. {nber_cli-0.3.1 → nber_cli-0.4.0}/.github/workflows/docs.yml +0 -0
  32. {nber_cli-0.3.1 → nber_cli-0.4.0}/.github/workflows/lint.yml +0 -0
  33. {nber_cli-0.3.1 → nber_cli-0.4.0}/.github/workflows/publish.yml +0 -0
  34. {nber_cli-0.3.1 → nber_cli-0.4.0}/.github/workflows/pytest.yml +0 -0
  35. {nber_cli-0.3.1 → nber_cli-0.4.0}/.gitignore +0 -0
  36. {nber_cli-0.3.1 → nber_cli-0.4.0}/.mcp.json +0 -0
  37. {nber_cli-0.3.1 → nber_cli-0.4.0}/.python-version +0 -0
  38. {nber_cli-0.3.1 → nber_cli-0.4.0}/LICENSE +0 -0
  39. {nber_cli-0.3.1 → nber_cli-0.4.0}/README.md +0 -0
  40. {nber_cli-0.3.1 → nber_cli-0.4.0}/README.zh-CN.md +0 -0
  41. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/agents/claude-code.md +0 -0
  42. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/agents/codex.md +0 -0
  43. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/agents/index.md +0 -0
  44. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/agents/openclaw.md +0 -0
  45. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/agents/others.md +0 -0
  46. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/contributing.md +0 -0
  47. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/development.md +0 -0
  48. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/getting-started.md +0 -0
  49. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/index.md +0 -0
  50. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/mcp.md +0 -0
  51. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/en/policy.md +0 -0
  52. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/agents/claude-code.md +0 -0
  53. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/agents/codex.md +0 -0
  54. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/agents/index.md +0 -0
  55. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/agents/openclaw.md +0 -0
  56. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/agents/others.md +0 -0
  57. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/contributing.md +0 -0
  58. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/development.md +0 -0
  59. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/getting-started.md +0 -0
  60. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/index.md +0 -0
  61. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/mcp.md +0 -0
  62. {nber_cli-0.3.1 → nber_cli-0.4.0}/docs/zh/policy.md +0 -0
  63. {nber_cli-0.3.1 → nber_cli-0.4.0}/mkdocs.yml +0 -0
  64. {nber_cli-0.3.1 → nber_cli-0.4.0}/plugins/nber-cli/.claude-plugin/plugin.json +0 -0
  65. {nber_cli-0.3.1 → nber_cli-0.4.0}/plugins/nber-cli/.codex-plugin/plugin.json +0 -0
  66. {nber_cli-0.3.1 → nber_cli-0.4.0}/plugins/nber-cli/.mcp.json +0 -0
  67. {nber_cli-0.3.1 → nber_cli-0.4.0}/plugins/nber-cli/skills/NBER-CLI/SKILL.md +0 -0
  68. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/__main__.py +0 -0
  69. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/config.py +0 -0
  70. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/core/__init__.py +0 -0
  71. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/download.py +0 -0
  72. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/feed.py +0 -0
  73. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/fetcher.py +0 -0
  74. {nber_cli-0.3.1 → nber_cli-0.4.0}/src/nber_cli/formatters.py +0 -0
  75. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/__init__.py +0 -0
  76. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/test_db.py +0 -0
  77. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/test_downloader.py +0 -0
  78. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/test_feed.py +0 -0
  79. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/test_fetcher.py +0 -0
  80. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/test_logs.py +0 -0
  81. {nber_cli-0.3.1 → nber_cli-0.4.0}/tests/test_main.py +0 -0
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.4.0] - 2026-06-04
6
+
7
+ ### Added
8
+ - `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.
9
+ - `nber-cli info cache --turn-on` / `--turn-off` toggle the `info_cache` lookup globally and persist the state to `~/.nber-cli/config.json`.
10
+ - `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.
11
+ - `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`.
12
+ - `nber-cli info cache` (no sub-action) prints the current cache state, TTL, and cached row count.
13
+ - 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`).
14
+ - New `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, so callers (CLI and MCP) can surface a "loaded from cache" hint.
15
+ - Public Python API exports: `InfoCacheSettings`, `InfoCacheLookupResult`, `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`.
16
+
17
+ ### Changed
18
+ - `~/.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.
19
+ - `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.
20
+
5
21
  ## [0.3.1] - 2026-06-03
6
22
 
7
23
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nber-cli
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: A command line interface for reaching the National Bureau of Economic Research (NBER) paper without brower.
5
5
  Project-URL: Homepage, https://github.com/sepinetam/nber-cli
6
6
  Project-URL: Repository, https://github.com/sepinetam/nber-cli
@@ -2,6 +2,24 @@
2
2
 
3
3
  All notable changes to this project will be documented here.
4
4
 
5
+ ## 0.4.0 - 2026-06-04
6
+
7
+ ### Added
8
+
9
+ - 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.
10
+ - 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`.
11
+ - 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.
12
+ - 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`.
13
+ - Added `nber-cli info cache` (no sub-action) to print the current cache state, TTL, and cached row count.
14
+ - 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`.
15
+ - 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.
16
+ - Added public Python API exports for the new info cache helpers and `NBERInfoCacheClearResult` model.
17
+
18
+ ### Changed
19
+
20
+ - `~/.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.
21
+ - `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.
22
+
5
23
  ## 0.3.1 - 2026-06-03
6
24
 
7
25
  ### Added
@@ -100,6 +100,85 @@ nber-cli info w25000 -f json
100
100
  | `paper_id` | Required paper ID, with or without the `w` prefix. |
101
101
  | `--all`, `-a` | Include related fields and published-version information when available. |
102
102
  | `--format`, `-f` | Output format: `list` or `json`. Defaults to `list`. |
103
+ | `--refresh` | Bypass the local `info_cache` and re-fetch from NBER. The new data is written back to the cache when the cache is enabled. |
104
+
105
+ 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
+
107
+ The MCP `get_paper_info` tool follows the same cache behavior, including the `--refresh` flag.
108
+
109
+ ## info cache
110
+
111
+ Manage the `info_cache` lookup behavior and clear cached records.
112
+
113
+ Show the current cache state, TTL, and row count:
114
+
115
+ ```bash
116
+ nber-cli info cache
117
+ ```
118
+
119
+ Toggle the cache globally:
120
+
121
+ ```bash
122
+ nber-cli info cache --turn-on
123
+ nber-cli info cache --turn-off
124
+ ```
125
+
126
+ Set the cache refresh interval in days:
127
+
128
+ ```bash
129
+ nber-cli info cache --set-refresh 7
130
+ nber-cli info cache --set-refresh 30
131
+ ```
132
+
133
+ `--set-refresh` requires a positive integer. The new value is written to `~/.nber-cli/config.json` and used as the TTL for every subsequent `info` call.
134
+
135
+ Clean cached records not refreshed in the last 30 days:
136
+
137
+ ```bash
138
+ nber-cli info cache clear
139
+ nber-cli info cache clear --days 30
140
+ ```
141
+
142
+ Clean all cached records:
143
+
144
+ ```bash
145
+ nber-cli info cache clear --all
146
+ nber-cli info cache clean
147
+ ```
148
+
149
+ `info cache clean` is a convenience alias for `info cache clear --all`.
150
+
151
+ Clean cached records by `last_fetched_at` date:
152
+
153
+ ```bash
154
+ nber-cli info cache clear --end-date 2026-06-01
155
+ nber-cli info cache clear --start-date 2026-05-01 --end-date 2026-06-01
156
+ ```
157
+
158
+ `--end-date` without `--start-date` cleans from the earliest cached record through the end date. `--start-date` and `--end-date` are inclusive. Passing only `--start-date` is invalid.
159
+
160
+ Before deleting anything, `info cache clear` prints how many cached records match and asks for confirmation:
161
+
162
+ ```text
163
+ This operation is irreversible.
164
+ Deleted info cache records may be fetched again from NBER.
165
+ Continue? [y/N]:
166
+ ```
167
+
168
+ Only `y` or `Y` continues. Any other response aborts without deleting records.
169
+
170
+ ### info cache Options
171
+
172
+ | Subcommand | Option | Description |
173
+ | --- | --- | --- |
174
+ | (none) | `--turn-on` | Enable the info cache globally. |
175
+ | (none) | `--turn-off` | Disable the info cache globally. |
176
+ | (none) | `--set-refresh` | Set the info cache refresh interval in days. Must be a positive integer. |
177
+ | `clear` | `--days` | Clean cached records not refreshed for this many days. Defaults to `30`. |
178
+ | `clear` | `--all` | Clean all cached records. |
179
+ | `clear` | `--start-date` | Clean cached records refreshed on or after this date, formatted `YYYY-MM-DD`. |
180
+ | `clear` | `--end-date` | Clean cached records refreshed on or before this date, formatted `YYYY-MM-DD`. |
181
+ | `clean` | — | Alias for `clear --all`. |
103
182
 
104
183
  ## search
105
184
 
@@ -30,6 +30,10 @@ Current schema:
30
30
  "schema_version": 2,
31
31
  "feed": {
32
32
  "db-path": "/Users/name/.nber-cli/nber.db"
33
+ },
34
+ "info": {
35
+ "cache_enabled": true,
36
+ "cache_ttl_days": 30
33
37
  }
34
38
  }
35
39
  ```
@@ -38,6 +42,12 @@ Current schema:
38
42
 
39
43
  `schema_version` records the current database schema version. NBER-CLI updates it after `db init` or schema upgrades.
40
44
 
45
+ `info.cache_enabled` controls the `info_cache` lookup globally. Set to `false` to force every `info` call (and the MCP `get_paper_info` tool) to go straight to NBER. Defaults to `true`.
46
+
47
+ `info.cache_ttl_days` sets the refresh interval in days. Cached entries older than this threshold are treated as cache misses and re-fetched on the next `info` call. Must be a positive integer. Defaults to `30`.
48
+
49
+ Both `info` keys are managed by `nber-cli info cache --turn-on/--off/--set-refresh <N>`. Missing or malformed fields fall back to defaults and never cause NBER-CLI to fail.
50
+
41
51
  ## Local Database
42
52
 
43
53
  Default database path:
@@ -69,7 +79,7 @@ If you upgraded from 0.3.0 and still have `~/.nber-cli/feed.db`, NBER-CLI will k
69
79
  The database holds:
70
80
 
71
81
  - `feed_items` and `feed_fetches`: RSS cache used by `feed fetch` and `feed clean`.
72
- - `info_cache`: paper metadata cache used by `info` and the MCP `get_paper_info` tool.
82
+ - `info_cache`: paper metadata cache used by `info` and the MCP `get_paper_info` tool. Cache reads are gated by `info.cache_enabled` and respect the `info.cache_ttl_days` TTL.
73
83
  - `query_log`, `download_log`, `info_log`: behavior logs for search keywords, download outcomes, and info lookups.
74
84
 
75
85
  ## Output Paths
@@ -161,6 +161,70 @@ if paper is None:
161
161
  print(paper.title)
162
162
  ```
163
163
 
164
+ Read the paper metadata cache through the high-level helper, which respects the user-config TTL and the global cache toggle:
165
+
166
+ ```python
167
+ import asyncio
168
+
169
+ from nber_cli import get_paper_with_info_cache_result
170
+
171
+
172
+ async def main() -> None:
173
+ result = await get_paper_with_info_cache_result(25000)
174
+ if result.from_cache:
175
+ print("Served from local info cache")
176
+ print(result.paper.title)
177
+
178
+
179
+ asyncio.run(main())
180
+ ```
181
+
182
+ `refresh=True` skips the cache lookup and re-fetches from NBER before optionally writing back:
183
+
184
+ ```python
185
+ import asyncio
186
+
187
+ from nber_cli import get_paper_with_info_cache_result
188
+
189
+
190
+ async def main() -> None:
191
+ result = await get_paper_with_info_cache_result(25000, refresh=True)
192
+ print(result.paper.title)
193
+
194
+
195
+ asyncio.run(main())
196
+ ```
197
+
198
+ Manage the user config (`~/.nber-cli/config.json`):
199
+
200
+ ```python
201
+ from nber_cli import (
202
+ get_info_cache_settings,
203
+ set_info_cache_enabled,
204
+ set_info_cache_ttl_days,
205
+ )
206
+
207
+ print(get_info_cache_settings())
208
+ set_info_cache_enabled(False)
209
+ set_info_cache_ttl_days(7)
210
+ ```
211
+
212
+ Clean cached paper metadata:
213
+
214
+ ```python
215
+ from nber_cli import clear_info_cache, count_info_cache
216
+
217
+ print(f"Cached rows: {count_info_cache()}")
218
+
219
+ preview = clear_info_cache(days=30, dry_run=True)
220
+ print(f"Matched: {preview.matched_count}")
221
+
222
+ result = clear_info_cache(days=30)
223
+ print(f"Deleted: {result.deleted_count}")
224
+ ```
225
+
226
+ The same `clear_info_cache` function also supports `delete_all=True` and `start_date` / `end_date` filters that mirror `clean_feed_cache`.
227
+
164
228
  ## Data Models
165
229
 
166
230
  ### NBER
@@ -226,6 +290,33 @@ print(paper.title)
226
290
  | `end_date` | `str` or `None` | Inclusive end date for `date-range` mode. |
227
291
  | `dry_run` | `bool` | Whether the operation only counted matching records. |
228
292
 
293
+ ### NBERInfoCacheClearResult
294
+
295
+ | Field | Type | Description |
296
+ | --- | --- | --- |
297
+ | `database_path` | `Path` | SQLite cache database path. |
298
+ | `matched_count` | `int` | Number of cache records matching the clean criteria. |
299
+ | `deleted_count` | `int` | Number of cache records deleted. |
300
+ | `mode` | `str` | Clean mode: `days`, `all`, or `date-range`. |
301
+ | `days` | `int` or `None` | Day threshold for `days` mode. |
302
+ | `start_date` | `str` or `None` | Inclusive start date for `date-range` mode. |
303
+ | `end_date` | `str` or `None` | Inclusive end date for `date-range` mode. |
304
+ | `dry_run` | `bool` | Whether the operation only counted matching records. |
305
+
306
+ ### InfoCacheSettings
307
+
308
+ | Field | Type | Description |
309
+ | --- | --- | --- |
310
+ | `cache_enabled` | `bool` | Global toggle for the `info_cache` lookup. |
311
+ | `cache_ttl_days` | `int` | Cache refresh interval in days. |
312
+
313
+ ### InfoCacheLookupResult
314
+
315
+ | Field | Type | Description |
316
+ | --- | --- | --- |
317
+ | `paper` | `NBER` | The paper returned by the lookup. |
318
+ | `from_cache` | `bool` | `True` when the paper was served from the local `info_cache`. |
319
+
229
320
  ### DownloadFailure
230
321
 
231
322
  | Field | Type | Description |
@@ -2,6 +2,24 @@
2
2
 
3
3
  这里记录项目的重要变更。
4
4
 
5
+ ## 0.4.0 - 2026-06-04
6
+
7
+ ### Added
8
+
9
+ - 新增 `nber-cli info --refresh`,跳过本地 `info_cache` 并直接从 NBER 重新拉取论文元数据。缓存开启时,新数据会写回缓存。
10
+ - 新增 `nber-cli info cache --turn-on` 和 `--turn-off`,全局开关 `info_cache` 读取行为,状态会持久化到 `~/.nber-cli/config.json`。
11
+ - 新增 `nber-cli info cache --set-refresh <N>`,设置缓存刷新间隔(天)。该值会持久化到 `~/.nber-cli/config.json`,并在后续每次 `info` 调用中作为 TTL 生效,默认 `30` 天。
12
+ - 新增 `nber-cli info cache clear`,参数集与 `feed clean` 一致:`--days`、`--all`、`--start-date`、`--end-date`,使用 `info_cache` 表的 `last_fetched_at` 字段过滤。`nber-cli info cache clean` 是 `clear --all` 的便利别名。
13
+ - 新增 `nber-cli info cache`(不带子动作),用于打印当前缓存状态、TTL 和已缓存行数。
14
+ - 新增 `nber_cli.config_store` 模块,集中处理 `~/.nber-cli/config.json` 的读写,包含 `InfoCacheSettings` 数据类及 `get_info_cache_settings`、`set_info_cache_enabled`、`set_info_cache_ttl_days` 等辅助函数。
15
+ - 新增 `nber_cli.info_cache.get_paper_with_info_cache_result` 异步辅助函数,返回包含 `NBER` 论文对象和 `from_cache` 标志的 `InfoCacheLookupResult`。
16
+ - 新增 info cache 相关辅助函数和 `NBERInfoCacheClearResult` 数据模型的 Python API 导出。
17
+
18
+ ### Changed
19
+
20
+ - `~/.nber-cli/config.json` 现在携带 `info` 段:`info.cache_enabled`(默认 `true`)和 `info.cache_ttl_days`(默认 `30`)。字段缺失或类型错误时回退到默认值。
21
+ - `info` 命令在从本地缓存命中时,会通过 stderr 打印一行提示,并指向 `nber-cli info <id> --refresh` 用于强制刷新。
22
+
5
23
  ## 0.3.1 - 2026-06-03
6
24
 
7
25
  ### Added
@@ -100,6 +100,85 @@ nber-cli info w25000 -f json
100
100
  | `paper_id` | 必填论文编号,可以带 `w` 前缀,也可以不带。 |
101
101
  | `--all`, `-a` | 如果可用,包含相关字段和 published-version 信息。 |
102
102
  | `--format`, `-f` | 输出格式:`list` 或 `json`,默认是 `list`。 |
103
+ | `--refresh` | 跳过本地 `info_cache` 并直接从 NBER 重新拉取。缓存开启时,新数据会写回缓存。 |
104
+
105
+ 当缓存开启且缓存条目尚未超过配置的 TTL 时,重复执行 `info` 会从本地数据库返回。TTL 到期后的第一次 `info` 调用,或任何携带 `--refresh` 的调用,都会执行实时网络拉取。
106
+
107
+ MCP 的 `get_paper_info` 工具遵循相同的缓存行为,也支持 `--refresh`。
108
+
109
+ ## info cache
110
+
111
+ 管理 `info_cache` 的读取行为并清理缓存记录。
112
+
113
+ 显示当前缓存状态、TTL 和已缓存行数:
114
+
115
+ ```bash
116
+ nber-cli info cache
117
+ ```
118
+
119
+ 全局开关缓存:
120
+
121
+ ```bash
122
+ nber-cli info cache --turn-on
123
+ nber-cli info cache --turn-off
124
+ ```
125
+
126
+ 设置缓存刷新间隔(天):
127
+
128
+ ```bash
129
+ nber-cli info cache --set-refresh 7
130
+ nber-cli info cache --set-refresh 30
131
+ ```
132
+
133
+ `--set-refresh` 必须是正整数。新值会写入 `~/.nber-cli/config.json`,并在后续每次 `info` 调用中作为 TTL 生效。
134
+
135
+ 清理 30 天内没有刷新的缓存记录:
136
+
137
+ ```bash
138
+ nber-cli info cache clear
139
+ nber-cli info cache clear --days 30
140
+ ```
141
+
142
+ 清理全部缓存记录:
143
+
144
+ ```bash
145
+ nber-cli info cache clear --all
146
+ nber-cli info cache clean
147
+ ```
148
+
149
+ `info cache clean` 是 `info cache clear --all` 的便利别名。
150
+
151
+ 按 `last_fetched_at` 日期清理缓存记录:
152
+
153
+ ```bash
154
+ nber-cli info cache clear --end-date 2026-06-01
155
+ nber-cli info cache clear --start-date 2026-05-01 --end-date 2026-06-01
156
+ ```
157
+
158
+ 只提供 `--end-date` 时,会从最早的缓存记录清理到该结束日期。`--start-date` 和 `--end-date` 都是前后包含的。只提供 `--start-date` 是无效的。
159
+
160
+ 删除前,`info cache clear` 会先打印匹配到的缓存记录数量,并要求确认:
161
+
162
+ ```text
163
+ This operation is irreversible.
164
+ Deleted info cache records may be fetched again from NBER.
165
+ Continue? [y/N]:
166
+ ```
167
+
168
+ 只有输入 `y` 或 `Y` 才会继续。其他输入都会中止,不删除记录。
169
+
170
+ ### info cache 选项
171
+
172
+ | 子命令 | 选项 | 说明 |
173
+ | --- | --- | --- |
174
+ | (无) | `--turn-on` | 全局启用 info cache。 |
175
+ | (无) | `--turn-off` | 全局禁用 info cache。 |
176
+ | (无) | `--set-refresh` | 设置 info cache 刷新间隔(天),必须是正整数。 |
177
+ | `clear` | `--days` | 清理这么多天没有刷新的缓存记录,默认是 `30`。 |
178
+ | `clear` | `--all` | 清理全部 info cache 记录。 |
179
+ | `clear` | `--start-date` | 清理 `last_fetched_at` 在该日期及之后的缓存记录,格式为 `YYYY-MM-DD`。 |
180
+ | `clear` | `--end-date` | 清理 `last_fetched_at` 在该日期及之前的缓存记录,格式为 `YYYY-MM-DD`。 |
181
+ | `clean` | — | `clear --all` 的别名。 |
103
182
 
104
183
  ## search
105
184
 
@@ -30,6 +30,10 @@ NBER-CLI 的大多数运行时行为使用内置默认值。本地数据库还
30
30
  "schema_version": 2,
31
31
  "feed": {
32
32
  "db-path": "/Users/name/.nber-cli/nber.db"
33
+ },
34
+ "info": {
35
+ "cache_enabled": true,
36
+ "cache_ttl_days": 30
33
37
  }
34
38
  }
35
39
  ```
@@ -38,6 +42,12 @@ NBER-CLI 的大多数运行时行为使用内置默认值。本地数据库还
38
42
 
39
43
  `schema_version` 记录当前数据库 schema 的版本。NBER-CLI 在 `db init` 或 schema 升级后更新该字段。
40
44
 
45
+ `info.cache_enabled` 全局控制 `info_cache` 的读取行为。设为 `false` 时,每次 `info` 调用(以及 MCP `get_paper_info` 工具)都会直接访问 NBER。默认是 `true`。
46
+
47
+ `info.cache_ttl_days` 设置刷新间隔(天)。超过该阈值的缓存条目会被视为未命中,并在下一次 `info` 调用时重新拉取。必须是正整数。默认是 `30`。
48
+
49
+ 两个 `info` 字段由 `nber-cli info cache --turn-on/--off/--set-refresh <N>` 维护。字段缺失或类型错误时一律回退到默认值,不会导致 NBER-CLI 失败。
50
+
41
51
  ## 本地数据库
42
52
 
43
53
  默认数据库路径:
@@ -69,7 +79,7 @@ nber-cli db migrate ~/data/nber.db
69
79
  数据库包含以下内容:
70
80
 
71
81
  - `feed_items` 和 `feed_fetches`:`feed fetch` 和 `feed clean` 使用的 RSS 缓存。
72
- - `info_cache`:`info` 和 MCP `get_paper_info` 工具使用的论文元数据缓存。
82
+ - `info_cache`:`info` 和 MCP `get_paper_info` 工具使用的论文元数据缓存。读取行为受 `info.cache_enabled` 控制,并受 `info.cache_ttl_days` 的 TTL 约束。
73
83
  - `query_log`、`download_log`、`info_log`:搜索关键词、下载结果和 info 查询的行为日志。
74
84
 
75
85
  ## 输出路径
@@ -161,6 +161,70 @@ if paper is None:
161
161
  print(paper.title)
162
162
  ```
163
163
 
164
+ 通过高层辅助函数读取论文元数据缓存,该函数会遵守用户配置中的 TTL 和全局缓存开关:
165
+
166
+ ```python
167
+ import asyncio
168
+
169
+ from nber_cli import get_paper_with_info_cache_result
170
+
171
+
172
+ async def main() -> None:
173
+ result = await get_paper_with_info_cache_result(25000)
174
+ if result.from_cache:
175
+ print("Served from local info cache")
176
+ print(result.paper.title)
177
+
178
+
179
+ asyncio.run(main())
180
+ ```
181
+
182
+ `refresh=True` 跳过缓存读取,重新从 NBER 拉取,并在缓存开启时写回:
183
+
184
+ ```python
185
+ import asyncio
186
+
187
+ from nber_cli import get_paper_with_info_cache_result
188
+
189
+
190
+ async def main() -> None:
191
+ result = await get_paper_with_info_cache_result(25000, refresh=True)
192
+ print(result.paper.title)
193
+
194
+
195
+ asyncio.run(main())
196
+ ```
197
+
198
+ 管理用户配置(`~/.nber-cli/config.json`):
199
+
200
+ ```python
201
+ from nber_cli import (
202
+ get_info_cache_settings,
203
+ set_info_cache_enabled,
204
+ set_info_cache_ttl_days,
205
+ )
206
+
207
+ print(get_info_cache_settings())
208
+ set_info_cache_enabled(False)
209
+ set_info_cache_ttl_days(7)
210
+ ```
211
+
212
+ 清理论文元数据缓存:
213
+
214
+ ```python
215
+ from nber_cli import clear_info_cache, count_info_cache
216
+
217
+ print(f"Cached rows: {count_info_cache()}")
218
+
219
+ preview = clear_info_cache(days=30, dry_run=True)
220
+ print(f"Matched: {preview.matched_count}")
221
+
222
+ result = clear_info_cache(days=30)
223
+ print(f"Deleted: {result.deleted_count}")
224
+ ```
225
+
226
+ `clear_info_cache` 同时支持 `delete_all=True` 以及 `start_date` / `end_date` 过滤,与 `clean_feed_cache` 的语义一致。
227
+
164
228
  ## 数据模型
165
229
 
166
230
  ### NBER
@@ -226,6 +290,33 @@ print(paper.title)
226
290
  | `end_date` | `str` 或 `None` | `date-range` 模式下前后包含的结束日期。 |
227
291
  | `dry_run` | `bool` | 是否只统计匹配记录而不删除。 |
228
292
 
293
+ ### NBERInfoCacheClearResult
294
+
295
+ | 字段 | 类型 | 说明 |
296
+ | --- | --- | --- |
297
+ | `database_path` | `Path` | SQLite 缓存数据库路径。 |
298
+ | `matched_count` | `int` | 符合清理条件的缓存记录数量。 |
299
+ | `deleted_count` | `int` | 已删除的缓存记录数量。 |
300
+ | `mode` | `str` | 清理模式:`days`、`all` 或 `date-range`。 |
301
+ | `days` | `int` 或 `None` | `days` 模式下的天数阈值。 |
302
+ | `start_date` | `str` 或 `None` | `date-range` 模式下前后包含的开始日期。 |
303
+ | `end_date` | `str` 或 `None` | `date-range` 模式下前后包含的结束日期。 |
304
+ | `dry_run` | `bool` | 是否只统计匹配记录而不删除。 |
305
+
306
+ ### InfoCacheSettings
307
+
308
+ | 字段 | 类型 | 说明 |
309
+ | --- | --- | --- |
310
+ | `cache_enabled` | `bool` | `info_cache` 读取的全局开关。 |
311
+ | `cache_ttl_days` | `int` | 缓存刷新间隔(天)。 |
312
+
313
+ ### InfoCacheLookupResult
314
+
315
+ | 字段 | 类型 | 说明 |
316
+ | --- | --- | --- |
317
+ | `paper` | `NBER` | 查询返回的论文对象。 |
318
+ | `from_cache` | `bool` | 当论文来自本地 `info_cache` 时为 `True`。 |
319
+
229
320
  ### DownloadFailure
230
321
 
231
322
  | 字段 | 类型 | 说明 |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nber-cli"
3
- version = "0.3.1"
3
+ version = "0.4.0"
4
4
  description = "A command line interface for reaching the National Bureau of Economic Research (NBER) paper without brower."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -4,6 +4,12 @@ from __future__ import annotations
4
4
 
5
5
  from .cli import main
6
6
  from .config import NBER_CLI_CONFIG, NBERCLIConfig
7
+ from .config_store import (
8
+ InfoCacheSettings,
9
+ get_info_cache_settings,
10
+ set_info_cache_enabled,
11
+ set_info_cache_ttl_days,
12
+ )
7
13
  from .core.models import (
8
14
  DownloadBatchResult,
9
15
  DownloadFailure,
@@ -11,12 +17,18 @@ from .core.models import (
11
17
  NBERFeedCleanResult,
12
18
  NBERFeedFetchResult,
13
19
  NBERFeedItem,
20
+ NBERInfoCacheClearResult,
14
21
  NBERSearchResults,
15
22
  )
16
23
  from .db import (
24
+ clear_info_cache,
25
+ count_info_cache,
17
26
  get_database_path,
27
+ get_info_cache_ttl_days,
18
28
  get_schema_version,
19
29
  init_database,
30
+ is_info_cache_enabled,
31
+ is_info_cache_expired,
20
32
  migrate_database,
21
33
  read_info_cache,
22
34
  record_download,
@@ -39,25 +51,33 @@ from .formatters import feed_results, info, related, search_results
39
51
  __all__ = [
40
52
  "DownloadBatchResult",
41
53
  "DownloadFailure",
54
+ "InfoCacheSettings",
42
55
  "NBER",
43
56
  "NBERCLIConfig",
44
57
  "NBER_CLI_CONFIG",
45
58
  "NBERFeedCleanResult",
46
59
  "NBERFeedFetchResult",
47
60
  "NBERFeedItem",
61
+ "NBERInfoCacheClearResult",
48
62
  "NBERSearchResults",
63
+ "clear_info_cache",
49
64
  "clean_feed_cache",
65
+ "count_info_cache",
50
66
  "download_multiple_papers",
51
67
  "download_paper",
52
68
  "download_paper_to_file",
53
69
  "feed_results",
54
70
  "fetch_feed",
55
71
  "get_database_path",
72
+ "get_info_cache_settings",
73
+ "get_info_cache_ttl_days",
56
74
  "get_nber",
57
75
  "get_schema_version",
58
76
  "init_database",
59
77
  "init_feed_database",
60
78
  "info",
79
+ "is_info_cache_enabled",
80
+ "is_info_cache_expired",
61
81
  "main",
62
82
  "migrate_database",
63
83
  "migrate_feed_database",
@@ -69,6 +89,8 @@ __all__ = [
69
89
  "related",
70
90
  "search_nber",
71
91
  "search_results",
92
+ "set_info_cache_enabled",
93
+ "set_info_cache_ttl_days",
72
94
  "touch_info_cache",
73
95
  "write_info_cache",
74
96
  ]