# Milestone: v1.4.2 — Headless Setup & Obsidian Plugin

**Started:** 2026-04-28
**Status:** In Progress
**Parent:** v1.4 Code Health & UX Hardening
**Phases:** 20 (single phase)

---

## Summary

v1.4.2 是 PaperForge v1.4 系列的第三个补丁版本，聚焦于降低安装门槛和 Obsidian 集成。

**核心交付三件事：**

1. **Headless 安装模式** — `paperforge setup --headless` 让 AI Agent 能代替用户完成安装，无需 Textual TUI
2. **最小 Obsidian 插件** — 安装时自动部署到 `.obsidian/plugins/paperforge/`，提供 Ctrl+P 命令面板集成
3. **AI Agent 安装指引** — AGENTS.md 新增 Agent 自安装章节，明确 Agent 应该问用户什么、执行什么命令

**不在此 milestone：**
- 多平台 Agent 命令生成（Cursor/Copilot/Claude 等）→ v1.5+
- Obsidian 插件的 Base 按钮 / 状态栏面板 / 侧边栏 → v1.5+
- Textual wizard 的 TUI 测试 → v1.5+

---

## Phase 20: Headless Setup + Obsidian Plugin Deployment

**Goal:** 用户（或 AI Agent）能用一条命令完成 PaperForge 全量安装，安装后 Obsidian 插件立即可用。

**Depends on:** v1.4.1 baseline

### Tasks

#### 20-01: Headless Setup CLI Entry

**目标：** `paperforge setup --headless` 跳过 Textual，走纯 CLI 路径完成安装。

**当前状态：** `cli.py:364-367` 调用 `setup_wizard.main()`，后者硬编码启动 `SetupWizardApp`（Textual TUI）。

**改动：**

1. `cli.py` — `setup` 子命令新增参数：
   ```
   --headless         跳过 Textual TUI，非交互模式
   --agent AGENT      选择 Agent 平台 (默认 opencode)
   --paddleocr-key KEY  PaddleOCR API Key (可选)
   --paddleocr-url URL  PaddleOCR API URL (可选，有默认值)
   --system-dir NAME  系统文件夹名 (默认 99_System)
   --resources-dir NAME  资源文件夹名 (默认 03_Resources)
   --literature-dir NAME  文献文件夹名 (默认 Literature)
   --control-dir NAME  控制文件夹名 (默认 LiteratureControl)
   --base-dir NAME  Base 文件夹名 (默认 05_Bases)
   --zotero-data PATH  Zotero 数据目录 (可选，自动检测)
   --skip-checks      跳过环境检测 (测试/CI 用)
   ```

2. `paperforge/setup_wizard.py` — 提取 `_deploy()` 的核心逻辑为独立函数 `headless_deploy(vault, config)`：
   - 环境检测（Python 版本、依赖、Zotero、BBT、JSON 导出）
   - 目录创建
   - 文件复制（workers、skills、commands、docs、AGENTS.md）
   - .env 创建
   - paperforge.json 创建
   - pip install -e . (注册 paperforge 命令)
   - 文件完整性验证

3. `cli.py` — headless 路径直接调用 `headless_deploy()` 而非 `SetupWizardApp`

**验证：**
- `paperforge setup --headless --vault /tmp/test-vault --skip-checks` 成功完成
- 生成的 vault 结构与 wizard 模式一致
- 返回 exit code 0 成功 / non-zero 失败 + stderr 错误信息

---

#### 20-02: 最小 Obsidian 插件

**目标：** 一个约 50 行的 Obsidian 插件，提供命令面板（Ctrl+P）集成。

**插件设计：**

```
.obsidian/plugins/paperforge/
├── main.js        # 插件主体 (~60 行)
└── manifest.json  # 插件元数据
```

**`main.js` 功能：**
- 注册 3 个 Obsidian 命令，注入到命令面板：
  - `PaperForge: 同步文献并生成笔记` → 执行 `python -m paperforge sync`
  - `PaperForge: 运行 OCR` → 执行 `python -m paperforge ocr`
  - `PaperForge: 查看状态` → 执行 `python -m paperforge status`
- 通过 `child_process.exec` 调起 Python，`cwd` 设为 vault 根目录
- 执行结果通过 `new Notice()` 浮窗提示
- 通过 `this.app.vault.adapter.basePath` 自动获取 vault 路径（无需用户配置）

**`manifest.json` 内容：**
```json
{
    "id": "paperforge",
    "name": "PaperForge",
    "version": "1.4.2",
    "minAppVersion": "1.0.0",
    "description": "PaperForge — Zotero + Obsidian literature pipeline integration",
    "author": "PaperForge",
    "authorUrl": "https://github.com/LLLin000/PaperForge",
    "isDesktopOnly": true
}
```

**`isDesktopOnly: true`** — 因为需要 `child_process` 调 Python，移动端不支持。

**路径处理：**
- 插件不硬编码任何路径 — `basePath` 就是 vault 根
- `paperforge` 命令需要已在 PATH 中（由 pip install 保证）
- Fallback: 如果 `paperforge` 不在 PATH，尝试 `python -m paperforge`
- 配置写入 `paperforge.json` 时记录 Python 路径，插件可读取
- `paperforge_paths()` 已处理 `worker_script` / `ld_deep_script` 的 fallback 查找

**部署：** setup wizard 的 deploy 步骤自动复制 `main.js` 和 `manifest.json` 到 `<vault>/.obsidian/plugins/paperforge/`

**用户启用步骤：** Obsidian → 设置 → 社区插件 → 已安装插件 → PaperForge → 启用

**验证：**
- 安装后 `.obsidian/plugins/paperforge/main.js` 存在且内容正确
- 安装后 `.obsidian/plugins/paperforge/manifest.json` 存在且内容正确
- Obsidian 设置中可见 PaperForge 插件
- Ctrl+P 搜索 "PaperForge" 可看到 3 个命令

---

#### 20-03: AGENTS.md Agent 自安装指引

**目标：** AI Agent 在读取 AGENTS.md 后，能自主执行 PaperForge 安装。

**新增章节内容：**

```markdown
## 12. AI Agent 自安装指南

如果你是一个 AI Agent（OpenCode / Cursor / Claude Code 等），
并且用户还没有安装 PaperForge，请按以下步骤帮用户完成安装：

### 需要向用户确认的信息

1. **Obsidian Vault 路径**（必填）
   - 问："你的 Obsidian Vault 的完整路径是什么？"
   - 示例：`D:\Documents\MyVault` 或 `/Users/name/Documents/MyVault`

2. **AI Agent 平台**（必填）
   - 问："你使用哪个 AI Agent？"
   - 选项：opencode / cursor / claude / windsurf / github_copilot / cline / augment / trae

3. **PaddleOCR API Key**（可选，可后续配置）
   - 问："你有 PaddleOCR API Key 吗？（没有可以跳过，后续在 .env 中配置）"
   - 获取地址：https://paddleocr.baidu.com

### 执行安装

收集到 vault 路径后，运行：

```bash
# pip 安装
pip install git+https://github.com/LLLin000/PaperForge.git

# headless 安装
paperforge setup --headless \
  --vault "<用户填的vault路径>" \
  --agent <agent平台key> \
  [--paddleocr-key "<api key>"]
```

### 安装后告知用户

安装完成后，告知用户：
1. 打开 Obsidian
2. 设置 → 社区插件 → 已安装 → 启用 "PaperForge"
3. Ctrl+P 输入 "PaperForge" 即可使用命令

### 首次使用验证

运行 `paperforge status` 确认系统就绪。
```

---

### 20-04: 路径处理验证

**目标：** 确认 Obsidian 插件在各种环境下能正确找到 paperforge。

**场景矩阵：**

| 场景                  | 预期行为                                |
| --------------------- | --------------------------------------- |
| pip install 全局安装   | `paperforge sync` 直接可用              |
| pip install --user    | 取决于 PATH 是否包含用户 Scripts 目录    |
| pip install -e (dev)  | 同全局安装                              |
| python -m paperforge  | 始终可用（只要 python 在 PATH），推荐   |
| Obsidian 以管理员启动  | 环境变量可能不同，需 python -m fallback |

**插件内 fallback 逻辑：**

```javascript
// 优先用 paperforge 命令
exec('paperforge sync', { cwd: vault }, (err, stdout) => {
    if (err) {
        // Fallback: python -m paperforge
        exec('python -m paperforge sync', { cwd: vault }, (err2, stdout2) => {
            if (err2) new Notice('[!!] 找不到 paperforge 命令');
            else new Notice('[OK] ' + stdout2);
        });
    } else {
        new Notice('[OK] ' + stdout);
    }
});
```

**验证：**
- `python -m paperforge status` 在 headless 安装后的 vault 中正常输出
- 插件产生的输出与 CLI 手动执行一致

---

## Success Criteria

- [ ] `paperforge setup --headless --vault <path> --agent opencode` 完成全量安装，exit code 0
- [ ] headless 安装生成的 vault 结构与 wizard 模式一致（目录、文件、配置）
- [ ] `.obsidian/plugins/paperforge/main.js` 和 `manifest.json` 正确部署
- [ ] Obsidian Ctrl+P 可搜索到 "PaperForge" 命令
- [ ] AGENTS.md 包含完整的 Agent 自安装指引章节
- [ ] 现有 317 个测试全部通过，0 回归
- [ ] Headless 模式在缺失必填参数时给出明确错误提示（stderr + 非零退出码）

---

## Design Decisions

| 决策项                           | 选择                               | 理由                                                       |
| -------------------------------- | ---------------------------------- | ---------------------------------------------------------- |
| 插件实现方式                     | 本地插件，安装时自动部署            | 无需社区审核，无第三方依赖，setup 本来就往 vault 复制文件 |
| 插件调用 paperforge 的方式        | `python -m paperforge` + `cwd=vault` | 最可靠，不需要 paperforge 在 PATH                        |
| 插件功能范围                     | 只有命令面板（3 个命令）            | 先打通最小闭环，Base 按钮/状态栏等后续加                 |
| 多平台 Agent 命令                | 不在此 milestone                    | 工程量大（需研究每平台机制），独立做                     |
| headless 模式与 wizard 代码复用  | 提取 `headless_deploy()` 共享核心逻辑 | 避免两份 deploy 代码越走越远                             |

---

## Risks

| 风险                          | 缓解措施                                             |
| ----------------------------- | ---------------------------------------------------- |
| Obsidian 不在 PATH 的 Python  | 插件 fallback 链: paperforge → python -m paperforge |
| vault 路径有空格/中文          | child_process exec cwd 传 Path 对象，JS 自动处理     |
| 用户禁用了社区插件             | AGENTS.md 指引中说明需要启用                         |
| headless 模式下 Zotero 检测失败 | `--skip-checks` flag 可跳过，不阻塞安装             |

---

## Plan Checklist

- [x] 20-01: Headless Setup CLI Entry
- [x] 20-01 Implementation
- [x] 20-02: Minimal Obsidian Plugin Design
- [x] 20-02 Implementation
- [x] 20-03: AGENTS.md Agent Self-Install Guide
- [x] 20-03 Documentation Update
- [x] 20-04: Path Handling Verification Matrix
- [x] 20-04 Validation

---

*v1.4.2 Milestone | 2026-04-28*
