---
phase: 056-stop-the-bleeding
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - INSTALLATION.md
  - README.md
  - docs/ai-agent-setup-guide.md
  - docs/ai-agent-setup-guide-zh.md
  - paperforge/plugin/main.js
  - paperforge/plugin/versions.json
autonomous: true
requirements:
  - BLEED-03
  - BLEED-04

must_haves:
  truths:
    - "README.md 'Install' section links to INSTALLATION.md as the primary reference, with no competing install instructions"
    - "INSTALLATION.md exists at the repository root and presents the single unified install path (Obsidian plugin path as primary, CLI as secondary)"
    - "`docs/ai-agent-setup-guide.md` references INSTALLATION.md for the canonical install step rather than duplicating instructions"
    - "Plugin's `_syncRuntime`, setup wizard install, and `_autoUpdate` never fall back to a hardcoded stale version string"
    - "Plugin's `pip install` URL always pins to `manifest.version` — no version drift possible"
    - "`versions.json` has `\"1.4.3\": \"1.0.0\"` (restored to original historical value)"
  artifacts:
    - path: "INSTALLATION.md"
      provides: "Single unified install reference document"
      min_lines: 40
    - path: "README.md"
      provides: "Updated with INSTALLATION.md link, simplified install section"
      contains: "INSTALLATION.md"
    - path: "paperforge/plugin/versions.json"
      provides: "Fixed historical entry for 1.4.3"
      contains: "\"1.0.0\""
    - path: "paperforge/plugin/main.js"
      provides: "No hardcoded '1.4.17rc2' fallback strings"
      not_contains: "1\\.4\\.17rc2"
  key_links:
    - from: "README.md"
      to: "INSTALLATION.md"
      via: "Markdown link in Install section"
      pattern: "\\[INSTALLATION\\]\\(INSTALLATION\\.md\\)"
    - from: "INSTALLATION.md"
      to: "paperforge plugin install"
      via: "Step-by-step: plugin install + CLI pip install git+https://...@VERSION"
      pattern: "pip install.*PaperForge"
    - from: "paperforge/plugin/main.js"
      to: "plugin manifest version"
      via: "`this.plugin.manifest.version` or `this.manifest.version` — no stale fallback"
      pattern: "manifest\\.version"
---

<objective>
External consistency — install docs unification and plugin version pinning hardening.

Purpose: Eliminate conflicting install recommendations across documents (BLEED-03), and ensure the Obsidian plugin's runtime `pip install` always pins to the manifest-declared version (BLEED-04).

Output:
- `INSTALLATION.md` — new primary install reference document at repository root
- `README.md` — updated Install section linking to INSTALLATION.md
- `docs/ai-agent-setup-guide.md`, `docs/ai-agent-setup-guide-zh.md` — updated to reference unified install path
- `paperforge/plugin/main.js` — stale hardcoded version fallbacks replaced with safe guards
- `paperforge/plugin/versions.json` — historical entry restored
</objective>

<execution_context>
@C:/Users/Lin/.opencode/get-shit-done/workflows/execute-plan.md
@C:/Users/Lin/.opencode/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/056-stop-the-bleeding/056-CONTEXT.md

@README.md
@docs/ai-agent-setup-guide.md
@docs/ai-agent-setup-guide-zh.md
@paperforge/plugin/main.js
@paperforge/plugin/versions.json
@paperforge/plugin/manifest.json
@paperforge/__init__.py

<interfaces>
Current version: "1.4.17rc3" (from paperforge/__init__.py)

From README.md Install section (current state):
```markdown
### Obsidian (推荐)
1. From [latest Release](https://github.com/LLLin000/PaperForge/releases/latest) download plugin files.
2. Copy to `vault/.obsidian/plugins/paperforge/`.
3. Enable `PaperForge` in Obsidian.
4. Open Settings, click `Open Setup Wizard`.
5. Follow the 5-step wizard.

### CLI (Developer)
```bash
cd /path/to/your/vault
pip install git+https://github.com/LLLin000/PaperForge.git
python -m paperforge setup --headless --agent opencode --paddleocr-key <key>
```
```

Hardcoded fallbacks to fix in main.js (3 locations):
```
Line 1840: const ver = this.plugin.manifest.version || '1.4.17rc2';
Line 2420: const ver = this.plugin.manifest.version || '1.4.17rc2';
Line 2671: const ver = this.manifest.version || '1.4.17rc2';
```

versions.json (needs fix):
```json
{
  "1.4.3": "1.9.0",       // BUG: should be "1.0.0" — retroactively changed minAppVersion
  "1.4.17rc3": "1.9.0"    // correct
}
```
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 3: Create unified install documentation</name>
  <files>
    INSTALLATION.md
    README.md
    docs/ai-agent-setup-guide.md
    docs/ai-agent-setup-guide-zh.md
  </files>
  <action>
    Create and update install documentation to present ONE unified primary install path.

    **Subtask 3a: Create `INSTALLATION.md`** at the repository root.

    Structure:
    - Title: "# PaperForge Installation Guide"
    - One-line purpose: "This is the single canonical install reference for PaperForge."
    - **Primary path: Obsidian Plugin (Recommended)** — step-by-step:
      1. Download the latest Release (link)
      2. Copy to `vault/.obsidian/plugins/paperforge/`
      3. Enable in Obsidian Community Plugins
      4. Open Settings -> PaperForge -> "Open Setup Wizard"
      5. Follow the 5-step wizard
    - **CLI / Headless path** — for developers and AI agents:
      1. `pip install git+https://github.com/LLLin000/PaperForge.git`
      2. `python -m paperforge setup --headless --agent opencode --paddleocr-key <key>`
    - **Prerequisites** table (Python 3.10+, Zotero, Better BibTeX, PaddleOCR Key)
    - **Verification** section: `paperforge status` or `paperforge doctor`
    - Reference AGENTS.md for post-install workflow and Better BibTeX auto-export config
    - Write in English (zh-CN version already covered by the setup guide in docs/)

    **Subtask 3b: Update `README.md`**

    Replace the current "### 安装" section (lines ~45-73):
    - Change "### 安装" to "### 快速安装"
    - Keep the public badge row at top
    - Replace all numbered install steps with a short paragraph + link:
      ```
      完整安装指南见 [INSTALLATION.md](INSTALLATION.md)。

      **推荐路径**：Obsidian (5 )
      **/Headless **：`pip install git+https://github.com/LLLin000/PaperForge.git`
      ```
    - Remove the "### 前置准备" table entirely (it's in INSTALLATION.md now)
    - Remove the "### 命令行安装（开发者）" sub-section entirely (it's in INSTALLATION.md now)
    - Keep the rest of README.md unchanged

    **Subtask 3c: Update `docs/ai-agent-setup-guide.md`**

    In the Step 5 / install section (around line 178-225):
    - Add a sentence at the top: "For the canonical CLI install path, see [INSTALLATION.md](../INSTALLATION.md)"
    - Keep the existing agent-specific setup flow (it's about headless setup, not about choosing between install paths)
    - The change should be additive — the guide is for AI agents doing headless setup, which is a valid secondary path

    **Subtask 3d: Update `docs/ai-agent-setup-guide-zh.md`**

    Same change as 3c, in Chinese.

    After these changes, there should be ONLY ONE place where a PRIMARY install path is presented: INSTALLATION.md. README.md delegates to it. The AI agent setup guides reference it while keeping their agent-specific headless flow.
  </action>
  <verify>
    <automated>python -c "
import re
readme = open('README.md', 'r').read()
assert 'INSTALLATION.md' in readme, 'README.md must link to INSTALLATION.md'
assert 'pip install git+https://github.com/LLLin000/PaperForge.git' in readme, 'pip install command still referenced'
print('[OK] README.md links to INSTALLATION.md')
install = open('INSTALLATION.md', 'r').read()
assert 'canonical' in install.lower() or 'single' in install.lower(), 'INSTALLATION.md should identify itself as canonical'
assert len(install) > 200, 'INSTALLATION.md should be substantive'
print('[OK] INSTALLATION.md exists and is substantive')
"</automated>
  </verify>
  <done>
    - INSTALLATION.md exists at repo root with complete install guide
    - README.md Install section simplified to link to INSTALLATION.md
    - No conflicting install instructions in README.md
    - Both ai-agent-setup-guide.md files reference INSTALLATION.md
  </done>
</task>

<task type="auto">
  <name>Task 4: Harden plugin version pinning</name>
  <files>
    paperforge/plugin/main.js
    paperforge/plugin/versions.json
  </files>
  <action>
    Fix two issues that could cause version drift between the Obsidian plugin and the Python package.

    **Subtask 4a: Fix hardcoded fallback version strings in `main.js`**

    There are 3 locations with `|| '1.4.17rc2'` fallback. For each, replace with a guard that either:
    - Uses the manifest version directly with a runtime check (fail safely if undefined), OR
    - Falls back to the CURRENT version from __init__.py (`1.4.17rc3`) after verifying it matches manifest

    Recommended approach for each location:

    Location 1 (line ~1840, `_syncRuntime`):
    ```javascript
    const ver = this.plugin.manifest.version;
    if (!ver) {
      new Notice('[!!] Cannot sync: plugin version unknown', 6000);
      return;
    }
    ```

    Location 2 (line ~2420, setup wizard install):
    ```javascript
    const ver = this.plugin.manifest.version || '1.4.17rc3';
    ```
    Note: Use a dynamic reference pattern. Since manifest.version is set at build time and is always present when the plugin loads, the `||` here is a safety net that should never trigger. Keep it but update to current version.

    Location 3 (line ~2671, `_autoUpdate`):
    ```javascript
    const ver = this.manifest.version;
    if (!ver) return; // don't auto-update if version is unknown
    ```

    **Subtask 4b: Fix `versions.json` stale entry**

    Change `"1.4.3": "1.9.0"` back to `"1.4.3": "1.0.0"` — the original minAppVersion for that release. Retroactively changing it violates Obsidian plugin update mechanism expectations (old entries must reflect the requirements valid at the time of that release).

    ```json
    {
      "1.4.3": "1.0.0",
      "1.4.17rc3": "1.9.0"
    }
    ```

    Also ensure the file has a trailing newline (POSIX compatibility per review finding IN-03).

    Also update `build/lib/paperforge/plugin/versions.json` with the same fix — the build directory mirrors plugin artifacts.
  </action>
  <verify>
    <automated>python -c "
import json
# Check versions.json fix
v = json.load(open('paperforge/plugin/versions.json'))
assert v.get('1.4.3') == '1.0.0', '1.4.3 entry should be 1.0.0'
assert v.get('1.4.17rc3') == '1.9.0', '1.4.17rc3 entry should be 1.9.0'
print('[OK] versions.json entries correct')

# Check build copy
bv = json.load(open('build/lib/paperforge/plugin/versions.json'))
assert bv == v, 'build/ copy must match source'
print('[OK] build/ versions.json matches')

# Check no hardcoded rc2 string in main.js
content = open('paperforge/plugin/main.js', 'rb').read()
assert b'1.4.17rc2' not in content, 'No hardcoded 1.4.17rc2 should remain in main.js'
print('[OK] No stale rc2 fallback in main.js')
"</automated>
  </verify>
  <done>
    - All 3 hardcoded `'1.4.17rc2'` fallbacks in main.js replaced with safe guards
    - versions.json has `"1.4.3": "1.0.0"` (restored)
    - build/lib/paperforge/plugin/versions.json is synced
    - versions.json has trailing newline
  </done>
</task>

</tasks>

<verification>
1. Run python verification script from Task 4 verify block
2. Run python verification from Task 3 verify block
3. Verify `ruff check paperforge/plugin/main.js` has no new errors (ignore pre-existing ones)
4. Verify `README.md` has no `### 前置准备` heading or `### 命令行安装（开发者）` subheading
</verification>

<success_criteria>
- INSTALLATION.md is the single source of truth for install instructions
- README.md and both setup guides reference INSTALLATION.md for primary install path
- No hardcoded stale version string exists in main.js
- versions.json has correct historical entry for 1.4.3
- Build artifact copy of versions.json matches source
</success_criteria>

<output>
After completion, create `.planning/phases/056-stop-the-bleeding/056-02-SUMMARY.md`
</output>
