# CLI 使用说明

这份文档是 `paper-fetch` 命令行行为的权威说明，重点解释主输出、artifact、资产下载和常见参数组合。

## 基本用法

```bash
paper-fetch --query "10.1186/1471-2105-11-421"
```

`--query` 可以是 DOI、论文 landing URL 或标题查询。CLI 默认会优先尝试全文；如果全文不可用，可能返回摘要或 metadata-only 结果。

## 批量抓取

批量模式使用 `--query-file <path>`，文件中每行一个 DOI、论文 landing URL 或标题；空行和以 `#` 开头的注释行会被忽略。`--query` 与 `--query-file` 互斥，必须二选一。

```bash
paper-fetch --query-file ./queries.txt --output-dir ./papers
```

批量模式不会把每篇正文打印到 stdout。每篇论文仍按 `--format` 写出主输出：

- `markdown`：`<output-dir>/<doi-or-title>.md`
- `json`：`<output-dir>/<doi-or-title>.json`
- `both`：`<output-dir>/<doi-or-title>.both.json`

如果未提供 `--output-dir`，CLI 使用默认下载目录。默认汇总文件是 `<output-dir>/batch-results.jsonl`，可用 `--batch-results <path>` 覆盖。每行是一条 JSON 结果，包含 `index`、`query`、`status`、`doi`、`source`、`output_path`、`saved_markdown_path`、`warnings` 和 `error`。

```bash
paper-fetch --query-file ./queries.txt \
  --output-dir ./papers \
  --batch-concurrency 4 \
  --batch-results ./papers/results.jsonl
```

`--batch-concurrency` 默认是 `1`，允许范围是 `1..8`。单篇失败不会终止整批，失败条目会写入 JSONL 的 `error` 字段；全部成功退出码为 `0`，存在失败则为非零，并优先按 `no_access`、`rate_limited`、`ambiguous` 映射到 `3`、`4`、`2`。

### 批量并行

批量抓取默认是串行执行，也就是 `--batch-concurrency 1`。当 `--batch-concurrency` 大于 `1` 时，CLI 会并行抓取多篇论文：

```bash
paper-fetch --query-file ./queries.txt \
  --output-dir ./papers \
  --batch-concurrency 4
```

上面的命令最多同时抓取 `4` 篇。每篇抓取会独立创建运行时上下文，避免跨任务共享 provider/runtime 状态；同一个 batch 会共享 HTTP transport，因此连接池、同 host 限流和请求缓存可以跨条目复用。JSONL 汇总仍由主线程写入，避免并发写文件。并行模式下 `batch-results.jsonl` 按任务完成顺序追加，不保证与输入文件顺序一致；需要还原输入顺序时使用每条记录里的 `index` 字段。

## 主输出

主输出是本次命令最终要给用户的结果正文或结构化结果。它由 `--format`、`--output` 和 `--output-dir` 共同决定。

- `--format markdown|json|both` 控制主输出格式，默认是 `markdown`。
- 未提供 `--output-dir` 且未显式传 `--output` 时，主输出打印到 stdout。
- 提供 `--output-dir <dir>` 且未显式传 `--output` 时，主输出写入该目录，不打印正文到 stdout。
- 显式 `--output -` 会强制打印到 stdout，即使同时提供 `--output-dir`。
- 显式 `--output <path>` 会把主输出写到该路径，`--output-dir` 不再接管主输出。

当 `--output-dir` 承接主输出时，默认文件名来自 DOI 或标题并经过安全化处理：

| 格式 | 主输出文件 |
| --- | --- |
| `markdown` | `<doi>.md` |
| `json` | `<doi>.json` |
| `both` | `<doi>.both.json` |

例如 DOI `10.1016/test` 会写成 `10.1016_test.md`。

## 输出格式

- `markdown`：AI 友好的 Markdown 正文，适合直接阅读或交给 agent。
- `json`：结构化 `ArticleModel` JSON，适合程序消费。
- `both`：JSON 对象，包含 `article` 和 `markdown` 两部分。

`both` 的形状是：

```json
{
  "article": {},
  "markdown": "..."
}
```

## 主输出与 Artifact

主输出是用户请求的最终结果；artifact 是为了阅读、复现、调试或引用资产而保存的副产物。

常见 artifact 包括：

- Markdown artifact：`<doi>.md`
- 资产目录：`<doi>_assets/`
- PDF fallback 源文件
- provider 原始 HTML/XML/PDF
- HTTP textual cache：`.paper-fetch-http-cache/`
- adapter cache 或调试 JSON sidecar
- 资产下载诊断

`--artifact-mode none` 只关闭 artifact，不关闭主输出。因此下面命令仍会写主输出：

```bash
paper-fetch --query "10.1016/test" --format json --output-dir ./papers --artifact-mode none
```

结果是：

```text
./papers/10.1016_test.json
```

不会额外保存 Markdown、资产或 provider 调试文件。

## Artifact 模式

CLI 默认：

```bash
--artifact-mode markdown-assets
--asset-profile body
```

`--artifact-mode markdown-assets` 保存 Markdown、按 `--asset-profile` 保存本地资产，并保留 PDF fallback 源文件；不会保存 provider 原始 HTML/XML、调试 JSON sidecar 或 HTTP textual cache。

`--artifact-mode all` 保留完整调试 artifact，包括 provider HTML/PDF、辅助 artifact、HTTP textual cache 和调试 JSON sidecar 等。

`--artifact-mode none` 不保存 provider artifact 或资产；显式 `--output <path>`、`--save-markdown`，以及未显式 `--output` 时由 `--output-dir` 承接的主输出仍可写文件。

`--no-download` 是兼容旧参数，等价于 `--artifact-mode none`。

## 资产下载

`--asset-profile` 只控制本地内容资产下载范围，不决定主输出是否写文件。

- `none`：不下载本地资产；不主动清除 Markdown 中已有或 provider 可解析出的远程图片链接。
- `body`：默认值，保存正文图片、图表、公式图片等。
- `all`：在正文资产之外，额外保存可识别的补充材料等相关资产。

当 artifact mode 或 `--no-download` 禁止资产落盘时，即使 `--asset-profile` 是 `body` 或 `all`，资产也不会保存。

## `--save-markdown`

`--save-markdown` 是独立的 Markdown 保存步骤，只在实际拿到 full text 时写文件。

常见用途是主输出选择 JSON，但仍额外保存一份可阅读 Markdown：

```bash
paper-fetch --query "10.1016/test" \
  --format json \
  --output ./article.json \
  --output-dir ./papers \
  --save-markdown
```

如果主输出本身已经是 `--output-dir` 下的默认 Markdown 文件，CLI 会避免重复写同一个 Markdown。

## 常见命令

| 命令 | stdout | 主输出文件 | artifact / 资产 |
| --- | --- | --- | --- |
| `paper-fetch --query ...` | 打印 Markdown | 无显式主输出文件 | 拿到全文时在默认目录保存 Markdown/正文资产 |
| `paper-fetch --query ... --output-dir ./papers` | 不打印正文 | `./papers/<doi>.md` | 拿到全文时在 `./papers` 下保存正文资产 |
| `paper-fetch --query ... --format json --output-dir ./papers` | 不打印正文 | `./papers/<doi>.json` | 拿到全文时默认还保存 Markdown artifact 和正文资产 |
| `paper-fetch --query ... --format both --output-dir ./papers` | 不打印正文 | `./papers/<doi>.both.json` | 拿到全文时默认还保存 Markdown artifact 和正文资产 |
| `paper-fetch --query ... --output - --output-dir ./papers` | 打印 Markdown | 无默认主输出文件 | `./papers` 只用于 artifact/资产 |
| `paper-fetch --query ... --output ./result.md --output-dir ./papers` | 不打印正文 | `./result.md` | `./papers` 只用于 artifact/资产 |
| `paper-fetch --query ... --format json --output-dir ./papers --artifact-mode none` | 不打印正文 | `./papers/<doi>.json` | 不保存 artifact/资产 |
| `paper-fetch --query ... --output - --artifact-mode none` | 打印 Markdown | 无 | 不保存 artifact/资产 |
| `paper-fetch --query-file ./queries.txt --output-dir ./papers` | 不打印正文 | 每篇 `./papers/<doi-or-title>.md`，另有 `batch-results.jsonl` | 拿到全文时在 `./papers` 下保存正文资产 |

## 渲染选项

- `--include-refs none|top10|all` 控制 references 渲染范围。
- `--max-tokens full_text|<positive-int>` 控制 Markdown 渲染预算，默认是 `full_text`。

## 默认目录

未显式设置目录时，CLI 使用 `PAPER_FETCH_DOWNLOAD_DIR` 或用户数据目录下的 `paper-fetch/downloads`。如果用户数据目录创建失败，会退回 repo-local `live-downloads`。

`--output-dir` 会覆盖本次命令的落盘目录。

CLI 会在开始抓取前创建最终输出目录，包括显式 `--output-dir` 和 `PAPER_FETCH_DOWNLOAD_DIR` 指向的目录。如果该路径已存在但不是目录，命令会以普通错误退出。显式 `--output <path>` 只控制主输出文件，不会自动创建该文件的父目录。

## 错误输出

运行时抓取失败会把 JSON 写到 stderr，stdout 不输出正文。常见形状：

```json
{
  "status": "no_access",
  "reason": "...",
  "candidates": null
}
```

常见 exit code：

| exit code | 含义 |
| --- | --- |
| `0` | 成功 |
| `1` | 通用错误 |
| `2` | 查询歧义或 argparse 参数错误 |
| `3` | 无访问权限 |
| `4` | 被限速 |
