Standalone CLI that diffs two engine-surface snapshots across all four axes,
the foundation the FastAPI/DB layer will sit on.
- ams.snapshot : typed access to a snapshot.json
- ams.diff : keyed set-diff per axis (added/removed/changed) + cross-owner
method-move detection; types keyed by (script_name,
via_module_iface) so the dual MULTIARRAY stays stable;
filter_by_owner for per-class focus
- ams.render : human-readable report (+/-/~), owner-grouped
- ams.cli : python -m ams OLD NEW [--owner C] [--only ...] [--json]
6 tests pass, incl. an integration test over the committed golden pair
(asserts BlooMoo adds GRBUFFER/INTERNET, MOUSE grows 104->128, Animo gains
GETFPS, Animo script fields unchanged).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
50 lines
1.5 KiB
Python
50 lines
1.5 KiB
Python
"""CLI: diff two engine-surface snapshots.
|
|
|
|
python -m ams OLD.snapshot.json NEW.snapshot.json [--owner CMC_Animo] [--only types,methods] [--json]
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
|
|
from .diff import compute_diff, filter_by_owner
|
|
from .render import render_text
|
|
from .snapshot import Snapshot
|
|
|
|
_AXES = ["types", "methods", "events", "fields", "layout"]
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
p = argparse.ArgumentParser(prog="ams", description="Diff two engine-surface snapshots.")
|
|
p.add_argument("old", help="older snapshot.json")
|
|
p.add_argument("new", help="newer snapshot.json")
|
|
p.add_argument("--owner", help="restrict to one class, e.g. CMC_Animo")
|
|
p.add_argument("--only", help="comma-separated axes to show: " + ",".join(_AXES))
|
|
p.add_argument("--json", action="store_true", help="emit machine-readable JSON")
|
|
args = p.parse_args(argv)
|
|
|
|
old = Snapshot.load(args.old)
|
|
new = Snapshot.load(args.new)
|
|
diff = compute_diff(old, new)
|
|
if args.owner:
|
|
diff = filter_by_owner(diff, args.owner)
|
|
|
|
if args.json:
|
|
print(json.dumps(diff, indent=2, sort_keys=True))
|
|
return 0
|
|
|
|
only = None
|
|
if args.only:
|
|
only = {a.strip() for a in args.only.split(",") if a.strip()}
|
|
bad = only - set(_AXES)
|
|
if bad:
|
|
p.error("unknown axis: {0} (choose from {1})".format(",".join(sorted(bad)), ",".join(_AXES)))
|
|
print(render_text(diff, only=only))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|