Files
llm/scripts/render_1c_saved_state_watch_once_markdown.py
T

127 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""Render one-shot 1C saved-state watch manifest as Markdown."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from typing import Any
def load_json(path: Path) -> dict[str, Any]:
return json.loads(path.read_text(encoding="utf-8-sig"))
def line(text: str = "") -> str:
return text.rstrip() + "\n"
def bullet(text: str) -> str:
return f"- {text}\n"
def code(value: Any) -> str:
if value is None:
return "`null`"
return f"`{value}`"
def linked_path(manifest_path: Path, value: Any) -> Path | None:
if not value:
return None
path = Path(str(value))
if path.is_absolute():
return path
return (manifest_path.parent / path).resolve()
def render_delta_summary(manifest_path: Path, manifest: dict[str, Any]) -> str:
delta_path = linked_path(manifest_path, manifest.get("delta"))
if not delta_path or not delta_path.exists():
return ""
delta = load_json(delta_path)
objects = delta.get("objects") or {}
changed = objects.get("changed") or []
added = objects.get("added") or []
removed = objects.get("removed") or []
if not changed and not added and not removed:
return ""
out = line()
out += line("## Delta Objects")
for item in added:
out += bullet(f"Added {code(item.get('full_name'))}")
for item in removed:
out += bullet(f"Removed {code(item.get('full_name'))}")
for item in changed:
out += bullet(f"Changed {code(item.get('full_name'))}")
term_delta = item.get("term_delta") or {}
added_terms = ((term_delta.get("added_terms") or {}).get("added") or [])
removed_terms = ((term_delta.get("removed_terms") or {}).get("added") or [])
if added_terms:
out += f" New added terms: {', '.join(code(value) for value in added_terms)}\n"
if removed_terms:
out += f" New removed terms: {', '.join(code(value) for value in removed_terms)}\n"
for part in (item.get("part_delta") or {}).get("changed") or []:
before = part.get("before") or {}
after = part.get("after") or {}
out += (
f" Part changed: {code(part.get('file_name'))}, "
f"role={code(after.get('payload_role'))}, "
f"delta_chars {code(before.get('delta_chars'))}->{code(after.get('delta_chars'))}\n"
)
return out
def render(manifest_path: Path, manifest: dict[str, Any]) -> str:
counts = manifest.get("counts") or {}
safety = manifest.get("safety") or {}
out = ""
out += line("# 1C Saved State Watch Run")
out += line()
out += line(f"Database: `{manifest.get('database')}`")
out += line(f"Run dir: `{manifest.get('run_dir')}`")
out += line(f"Previous report: `{manifest.get('previous_report')}`")
out += line()
out += line("## Artifacts")
for key in ("report", "markdown", "check", "manifest_check", "delta", "delta_markdown", "delta_check"):
if manifest.get(key):
out += bullet(f"{key}: `{manifest.get(key)}`")
out += line()
out += line("## Counts")
for key in (
"object_changes",
"system_changes",
"delta_objects_added",
"delta_objects_removed",
"delta_objects_changed",
"delta_objects_unchanged",
):
out += bullet(f"{key}: `{counts.get(key)}`")
out += render_delta_summary(manifest_path, manifest)
out += line()
out += line("## Safety")
for key in ("read_only", "sql_write_performed", "secrets_in_report"):
out += bullet(f"{key}: `{safety.get(key)}`")
return out
def main() -> int:
parser = argparse.ArgumentParser(description="Render one-shot 1C saved-state watch Markdown.")
parser.add_argument("--manifest", type=Path, required=True)
parser.add_argument("--output", type=Path)
args = parser.parse_args()
markdown = render(args.manifest, load_json(args.manifest))
if args.output:
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(markdown, encoding="utf-8")
print(json.dumps({"output": str(args.output)}, ensure_ascii=False))
else:
print(markdown)
return 0
if __name__ == "__main__":
raise SystemExit(main())