Skill-BidCreater/scripts/scan_project_materials.py
2026-03-09 22:20:38 +08:00

98 lines
3.5 KiB
Python

from __future__ import annotations
import argparse
from pathlib import Path
from typing import Any
from common import MATERIAL_CATALOG, ensure_output_layout, iter_material_entries, list_files, safe_filename, write_json, write_text
def match_catalog(file_name: str) -> dict[str, Any] | None:
lowered = file_name.lower()
for item in MATERIAL_CATALOG:
if any(keyword.lower() in lowered for keyword in item["keywords"]):
return item
return None
def serialize_files(project_dir: Path, paths: list[Path], source_root: Path) -> list[dict[str, Any]]:
results: list[dict[str, Any]] = []
for path in paths:
catalog = match_catalog(path.name)
results.append(
{
"name": path.name,
"path": str(path),
"relative_path": str(path.relative_to(project_dir)),
"source_root": source_root.name,
"source_root_path": str(source_root),
"matched_catalog_key": catalog["key"] if catalog else "",
"matched_catalog_label": catalog["label"] if catalog else "",
"safe_name": safe_filename(path.stem),
}
)
return results
def build_inventory(project_dir: Path) -> dict[str, Any]:
scan_roots: list[dict[str, str]] = []
material_files: list[dict[str, Any]] = []
for entry in iter_material_entries(project_dir):
scan_roots.append(
{
"name": entry.name,
"path": str(entry),
"type": "file" if entry.is_file() else "directory",
}
)
files = [entry] if entry.is_file() else list_files(entry)
material_files.extend(serialize_files(project_dir, files, entry))
material_files.sort(key=lambda item: item["relative_path"])
return {
"project_name": project_dir.name,
"project_dir": str(project_dir),
"scan_roots": scan_roots,
"material_files": material_files,
"summary": {
"scan_root_count": len(scan_roots),
"file_count": len(material_files),
"hinted_count": len([item for item in material_files if item["matched_catalog_key"]]),
},
}
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--project", required=True)
parser.add_argument("--out")
args = parser.parse_args()
project_dir = Path(args.project).resolve()
output_path = Path(args.out).resolve() if args.out else ensure_output_layout(project_dir)["work"] / "material_inventory.json"
inventory = build_inventory(project_dir)
write_json(output_path, inventory)
report_lines = [f"# {inventory['project_name']} 材料盘点", ""]
report_lines.append(f"- 扫描根:{inventory['summary']['scan_root_count']}")
report_lines.append(f"- 发现材料:{inventory['summary']['file_count']}")
report_lines.append(f"- 命中弱提示:{inventory['summary']['hinted_count']}")
report_lines.extend(["", "## 扫描根"])
report_lines.extend(
[f"- {item['name']} ({item['type']})" for item in inventory["scan_roots"]]
or ["- 暂无"]
)
report_lines.extend(["", "## 发现的材料"])
report_lines.extend(
[
f"- {item['relative_path']}"
+ (f" [提示:{item['matched_catalog_label']}]" if item["matched_catalog_label"] else "")
for item in inventory["material_files"]
]
or ["- 暂无"]
)
write_text(output_path.with_suffix(".md"), "\n".join(report_lines))
if __name__ == "__main__":
main()