| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- """
- Workbook resolution helpers for the Wuling overseas dealer expansion skill.
- Rules:
- - An explicit --excel path always wins.
- - Otherwise, prefer an existing project workbook in the current directory or parents.
- - Preview mode never creates a workbook.
- - Write mode may copy the blank skill template into the project directory.
- - Never write directly to the skill template.
- """
- from __future__ import annotations
- import shutil
- from pathlib import Path
- from typing import Any, Dict, Optional
- CANONICAL_WORKBOOK_NAME = "\u6469\u6d1b\u54e5\u5ba2\u6237\u5efa\u8054\u8868-\u6309\u6e20\u9053\u5206\u7c7b.xlsx"
- TEMPLATE_RELATIVE_PATH = Path("assets") / "blank_customer_outreach_workbook.xlsx"
- WORKBOOK_NAME_MARKERS = (
- "\u6469\u6d1b\u54e5\u5ba2\u6237\u5efa\u8054\u8868-\u6309\u6e20\u9053\u5206\u7c7b",
- "\u5ba2\u6237\u5efa\u8054\u8868",
- )
- EXCLUDE_NAME_MARKERS = (
- "~$",
- "_backup_",
- "backup_before",
- "_with_",
- "sent_",
- "preview",
- "candidate",
- "filtered",
- )
- def skill_root() -> Path:
- return Path(__file__).resolve().parents[2]
- def template_workbook_path(root: Optional[Path] = None) -> Path:
- return (root or skill_root()) / TEMPLATE_RELATIVE_PATH
- def _resolve_user_path(excel_path: str) -> Path:
- path = Path(excel_path).expanduser()
- if not path.is_absolute():
- path = Path.cwd() / path
- return path.resolve()
- def _excluded(path: Path) -> bool:
- name = path.name
- lowered = name.casefold()
- return name.startswith("~$") or any(marker.casefold() in lowered for marker in EXCLUDE_NAME_MARKERS)
- def _looks_like_workbook(path: Path) -> bool:
- if path.suffix.casefold() != ".xlsx" or _excluded(path):
- return False
- return any(marker in path.name for marker in WORKBOOK_NAME_MARKERS)
- def find_project_workbook(start_dir: Optional[Path] = None) -> Optional[Path]:
- """Find the newest likely outreach workbook in start_dir or its parents."""
- current = (start_dir or Path.cwd()).resolve()
- search_dirs = [current, *current.parents]
- for directory in search_dirs:
- if not directory.exists() or not directory.is_dir():
- continue
- candidates = [path for path in directory.glob("*.xlsx") if _looks_like_workbook(path)]
- if not candidates:
- continue
- exact = [path for path in candidates if path.name == CANONICAL_WORKBOOK_NAME]
- return sorted(exact or candidates, key=lambda path: path.stat().st_mtime, reverse=True)[0]
- return None
- def _copy_template_to(target: Path, root: Optional[Path] = None) -> Path:
- template = template_workbook_path(root)
- if not template.exists():
- raise FileNotFoundError(f"Blank workbook template not found: {template}")
- if template.resolve() == target.resolve():
- raise ValueError("Refusing to write directly to the skill blank workbook template.")
- target.parent.mkdir(parents=True, exist_ok=True)
- shutil.copy2(template, target)
- return target
- def resolve_workbook_path(
- excel_path: str = "",
- *,
- start_dir: Optional[Path] = None,
- create_from_template: bool = False,
- template_root: Optional[Path] = None,
- ) -> Dict[str, Any]:
- """
- Resolve the workbook path according to skill rules.
- Returns a dict with: path, source, created.
- source is one of explicit, explicit_template_copy, project, template_copy, missing.
- """
- if excel_path:
- path = _resolve_user_path(excel_path)
- if path.resolve() == template_workbook_path(template_root).resolve():
- raise ValueError("Do not write to the skill blank workbook template. Copy it to the project first.")
- if create_from_template and not path.exists():
- _copy_template_to(path, template_root)
- return {"path": path, "source": "explicit_template_copy", "created": True}
- return {"path": path, "source": "explicit", "created": False}
- project = find_project_workbook(start_dir)
- if project:
- return {"path": project, "source": "project", "created": False}
- if create_from_template:
- target_dir = (start_dir or Path.cwd()).resolve()
- target = target_dir / CANONICAL_WORKBOOK_NAME
- _copy_template_to(target, template_root)
- return {"path": target, "source": "template_copy", "created": True}
- return {"path": None, "source": "missing", "created": False}
|