1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! Subcommand implementations for the `doiget` CLI.
//!
//! Each module corresponds to a single `clap` subcommand declared in
//! `main.rs`. The dispatch table in `main.rs` calls `run(...)` on the
//! matching module. Subcommands return `anyhow::Result<()>`; any error
//! surfaces via the CLI's top-level error reporter (stderr).
//!
//! ## Phase 1 surface (so far)
//!
//! - [`audit_log`] — `doiget audit-log --verify` recomputes the SHA-256 hash
//! chain on the provenance log and reports any mismatches.
//! - [`batch`] — `doiget batch <path>` multi-ref orchestrator (rate-bounded).
//! - [`bib`] — `doiget bib <ref>` BibTeX exporter (Phase 2 starter).
//! - [`cite`] — `doiget cite <ref>` live-resolve BibTeX (doi2bib-style).
//! - [`config`] — `doiget config show/path/doctor`.
//! - [`csl`] — `doiget csl <ref>` exports a stored entry as CSL JSON 1.0.
//! - [`fetch`] — `doiget fetch <ref>` orchestrator (arXiv E2E + DOI metadata-only).
//! - [`info`] — prints a stored entry's `Metadata` as TOML on stdout.
//! - [`list_recent`] — prints up to N most-recently-fetched entries.
//! - [`search`] — case-insensitive substring search over stored metadata.
//!
//! Other subcommands (`serve`) land in separate PRs.
// Phase 4 / Slice 16. Compile-gated by the `citation` Cargo feature
// (which itself enables `doiget-core/citation`).
use ;
use Utf8PathBuf;
/// Resolve the path of the user `config.toml`, for messages that need to
/// name the file the user must edit.
///
/// Same resolution as [`config::ResolvedConfig::from_env`]
/// (`<dirs::config_dir()>/doiget/config.toml`), kept here so the fetch-side
/// denial help (issue #405) and `config doctor` cannot drift. Returns
/// `None` only when the platform has no config dir at all, in which case
/// callers should fall back to naming the file generically — a missing
/// config dir must never turn an advisory line into a hard error.
pub
/// Where a resolved store root came from (#441).
///
/// Reported by `doiget config doctor` so that a setting which did nothing
/// can no longer look like a setting that worked. That was the sharpest
/// part of #441: `config init` recommended `[store] root`, `doctor`
/// confirmed the recommendation, and the value was never read.
pub
/// Resolve the on-disk store root.
///
/// Resolution order (ADR-0036, `docs/CONFIG.md` §4):
///
/// 1. `DOIGET_STORE_ROOT`, if set and non-empty. `--store-root` is applied
/// by writing this variable, so the flag rides the same rung.
/// 2. `[store] root` in the user's `config.toml`, expanded via
/// [`doiget_core::user_extension::expand_store_root`].
/// 3. `./papers` — `papers/` directly under the current working directory
/// (#344 / ADR-0036), so fetched artifacts are visible where the user
/// (or an LLM agent) is working rather than hidden in a far-off home
/// directory.
///
/// Rung 2 is new in #441. It was documented from the start — ADR-0036
/// states the order, `docs/CONFIG.md` §3 lists the key, `config init`
/// writes it into the template it generates and `config doctor` recommends
/// it — and read by nothing, so the store silently kept following the cwd.
/// The old doc comment on this function said the config rung "lands with
/// the `config` subcommand"; that subcommand shipped in 0.8.8 without it.
pub
/// [`resolve_store_root`] plus which rung answered.
pub
/// `[store] root` from the user's `config.toml`, if any.
///
/// Does not fail the command on a malformed file — the store root is
/// resolved by every subcommand, and one bad line should not be a total
/// outage — but it does NOT stay quiet about it.
///
/// The previous comment here justified silence by claiming "a parse error
/// surfaces with a proper diagnostic on the network path that owns this
/// file". The #468 review checked that claim and it is false for most
/// callers: `list-recent`, `search`, `info`, `tag`, `bib` and `csl` never
/// build an HTTP client, so that diagnostic never runs for them. TOML fails
/// the whole document, so a typo anywhere — even under `[network]` — makes
/// `[store] root` unreadable, and the command silently used `./papers`
/// under the cwd as though nothing had been configured.
///
/// `search` then reports zero results, indistinguishable from an empty
/// library. Worse, `tag` **writes** metadata into the wrong store and
/// reports success. A warning is the minimum; the resolved source is also
/// reported by `config doctor`.