From eeb7cb1f3095c2ff4678c191b9731fb899dc6e59 Mon Sep 17 00:00:00 2001 From: Dan Velton Date: Sat, 4 Apr 2026 00:00:05 -0700 Subject: [PATCH] Address review feedback: soft imports, Windows Word support, doc fixes - Make PyMuPDF/Pillow/python-docx imports soft so setup-check runs without dependencies installed - Add _check_core_deps() guard at CLI command entry points - Add Windows Word detection in setup-check - Remove references to setup.sh (not included in plugin) - Fix usage docstring to show inline JSON instead of filename - Use consistent /eyeball.py paths in SKILL.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- skills/eyeball/SKILL.md | 11 ++----- skills/eyeball/tools/eyeball.py | 57 +++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/skills/eyeball/SKILL.md b/skills/eyeball/SKILL.md index 6edff3f2..8ace230d 100644 --- a/skills/eyeball/SKILL.md +++ b/skills/eyeball/SKILL.md @@ -42,12 +42,7 @@ Before first use, check that dependencies are installed: python3 /eyeball.py setup-check ``` -If anything is missing, run the setup script from the eyeball plugin directory: -```bash -bash /setup.sh -``` - -Or install manually: +If anything is missing, install the required dependencies: ```bash pip3 install pymupdf pillow python-docx playwright python3 -m playwright install chromium @@ -62,7 +57,7 @@ Follow these steps exactly. The order matters. Before writing any analysis, extract and read the full text of the source document: ```bash -python3 eyeball.py extract-text --source "" +python3 /eyeball.py extract-text --source "" ``` Read the output carefully. Identify actual section numbers, headings, page numbers, and key language. @@ -118,7 +113,7 @@ RIGHT -- includes the section number for precision, targets the correct page: Construct a JSON array of sections and call the build command: ```bash -python3 eyeball.py build \ +python3 /eyeball.py build \ --source "" \ --output ~/Desktop/.docx \ --title "Analysis Title" \ diff --git a/skills/eyeball/tools/eyeball.py b/skills/eyeball/tools/eyeball.py index 3534fc4c..0fa31a44 100755 --- a/skills/eyeball/tools/eyeball.py +++ b/skills/eyeball/tools/eyeball.py @@ -11,7 +11,7 @@ Usage (called by the Copilot CLI skill, not typically invoked directly): python3 eyeball.py build \ --source <path-or-url> \ --output <output.docx> \ - --sections sections.json + --sections '[{"heading": "Section 1", "analysis": "Example analysis text"}]' python3 eyeball.py setup-check @@ -36,13 +36,38 @@ import tempfile try: import fitz # PyMuPDF +except ImportError: + fitz = None + +try: from PIL import Image, ImageDraw +except ImportError: + Image = None + ImageDraw = None + +try: from docx import Document from docx.shared import Inches, Pt, RGBColor -except ImportError as e: - print(f"Missing dependency: {e}", file=sys.stderr) - print("Run setup.sh or: pip3 install pymupdf pillow python-docx playwright", file=sys.stderr) - sys.exit(1) +except ImportError: + Document = None + Inches = None + Pt = None + RGBColor = None + + +def _check_core_deps(): + """Raise if core dependencies are missing.""" + missing = [] + if fitz is None: + missing.append("pymupdf") + if Image is None: + missing.append("pillow") + if Document is None: + missing.append("python-docx") + if missing: + print(f"Missing dependencies: {', '.join(missing)}", file=sys.stderr) + print("Install with: pip3 install pymupdf pillow python-docx playwright", file=sys.stderr) + sys.exit(1) # --------------------------------------------------------------------------- @@ -436,6 +461,7 @@ def cmd_setup_check(): "Playwright": False, "Chromium browser": False, "Word (macOS)": False, + "Word (Windows)": False, "LibreOffice": False, } @@ -476,6 +502,22 @@ def cmd_setup_check(): if platform.system() == "Darwin" and os.path.exists("/Applications/Microsoft Word.app"): checks["Word (macOS)"] = True + if platform.system() == "Windows": + try: + import winreg + winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, + r"SOFTWARE\Microsoft\Office\ClickToRun\Configuration") + checks["Word (Windows)"] = True + except (ImportError, OSError): + # Fallback: check if win32com can dispatch Word + try: + import win32com.client + word = win32com.client.Dispatch("Word.Application") + word.Quit() + checks["Word (Windows)"] = True + except Exception: + pass + if shutil.which("libreoffice") or shutil.which("soffice"): checks["LibreOffice"] = True @@ -488,7 +530,7 @@ def cmd_setup_check(): if name in ("PyMuPDF", "Pillow", "python-docx") and not ok: all_core = False - has_converter = checks["Word (macOS)"] or checks["LibreOffice"] + has_converter = checks["Word (macOS)"] or checks["Word (Windows)"] or checks["LibreOffice"] has_web = checks["Playwright"] and checks["Chromium browser"] print("") @@ -515,6 +557,7 @@ def cmd_convert(args): def cmd_screenshot(args): """Generate a single screenshot from a PDF.""" + _check_core_deps() pdf_doc = fitz.open(os.path.expanduser(args.source)) anchors = json.loads(args.anchors) target_page = args.page @@ -541,6 +584,7 @@ def cmd_screenshot(args): def cmd_build(args): """Build a complete analysis document.""" + _check_core_deps() source = os.path.expanduser(args.source) output = os.path.expanduser(args.output) sections = json.loads(args.sections) @@ -581,6 +625,7 @@ def cmd_build(args): def cmd_extract_text(args): """Extract text from a source document (for the AI to read before writing analysis).""" + _check_core_deps() source = os.path.expanduser(args.source) with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp: