2026-05-06 03:40:24 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
PLUGIN_MAIN = REPO_ROOT / "paperforge" / "plugin" / "main.js"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_plugin_install_bootstraps_pip_before_setup() -> None:
|
|
|
|
|
"""First-time plugin install must install the Python package before setup."""
|
|
|
|
|
source = PLUGIN_MAIN.read_text(encoding="utf-8")
|
|
|
|
|
assert "python -m paperforge" in source or "'-m', 'paperforge'" in source
|
|
|
|
|
assert (
|
|
|
|
|
'"-m", "pip", "install"' in source
|
|
|
|
|
or "-m', 'pip', 'install'" in source
|
|
|
|
|
), "plugin install flow should bootstrap pip install before running paperforge setup"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_plugin_validates_setup_complete_against_paperforge_json() -> None:
|
|
|
|
|
"""setup_complete must be cross-checked against real vault config."""
|
|
|
|
|
source = PLUGIN_MAIN.read_text(encoding="utf-8")
|
|
|
|
|
assert "setup_complete" in source
|
|
|
|
|
assert "paperforge.json" in source, "plugin should verify setup_complete against paperforge.json"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_setup_args_global_vault_before_subcommand() -> None:
|
|
|
|
|
"""Global --vault argument must appear before subcommand 'setup'."""
|
|
|
|
|
source = PLUGIN_MAIN.read_text(encoding="utf-8")
|
|
|
|
|
# Check that '--vault' appears before 'setup' in the setupArgs array
|
|
|
|
|
vault_pos = source.find("'--vault'")
|
|
|
|
|
setup_pos = source.find("'setup'")
|
|
|
|
|
assert vault_pos > 0 and setup_pos > 0
|
|
|
|
|
assert vault_pos < setup_pos, (
|
|
|
|
|
f"'--vault' (pos {vault_pos}) must appear before 'setup' (pos {setup_pos}) "
|
|
|
|
|
"in setupArgs, because --vault is a global paperforge argument"
|
|
|
|
|
)
|
2026-05-06 03:57:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_setup_wizard_flat_command_falls_back_to_packaged_command_files() -> None:
|
2026-05-10 16:11:00 +00:00
|
|
|
"""pip-installed setup must deploy OpenCode commands via skill_deploy service."""
|
2026-05-06 03:57:02 +00:00
|
|
|
source = (REPO_ROOT / "paperforge" / "setup_wizard.py").read_text(encoding="utf-8")
|
2026-05-10 16:11:00 +00:00
|
|
|
assert "skill_deploy" in source
|
|
|
|
|
deploy_svc = (REPO_ROOT / "paperforge" / "services" / "skill_deploy.py").read_text(encoding="utf-8")
|
|
|
|
|
assert '"skills"' in deploy_svc
|
2026-05-06 03:57:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_setup_wizard_does_not_fail_if_agents_md_missing() -> None:
|
|
|
|
|
"""AGENTS.md is optional for pip-installed package deployments."""
|
|
|
|
|
source = (REPO_ROOT / "paperforge" / "setup_wizard.py").read_text(encoding="utf-8")
|
2026-05-10 13:05:05 +00:00
|
|
|
assert 'True if not agents_src.exists() else agents_dst.exists()' not in source
|
|
|
|
|
assert '(vault / "AGENTS.md").exists()' in source
|
2026-05-06 04:18:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_setup_wizard_uses_manual_zotero_path_for_checks() -> None:
|
|
|
|
|
"""Informational checks should honor user-provided zotero_data_dir."""
|
|
|
|
|
source = (REPO_ROOT / "paperforge" / "setup_wizard.py").read_text(encoding="utf-8")
|
|
|
|
|
assert "manual_zotero_path = Path(zotero_data).expanduser() if zotero_data else None" in source
|
|
|
|
|
assert "checker.check_zotero(manual_zotero_path)" in source
|
|
|
|
|
assert "checker.check_bbt(manual_zotero_path)" in source
|
2026-05-08 09:17:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_plugin_deep_reading_flow_does_not_depend_on_separate_file() -> None:
|
|
|
|
|
"""Deep-reading now lives in the main note, not a dedicated deep-reading.md file."""
|
|
|
|
|
source = PLUGIN_MAIN.read_text(encoding="utf-8")
|
|
|
|
|
assert "entry.deep_reading_path" not in source
|
|
|
|
|
assert "file.name === 'deep-reading.md'" not in source
|