@topy-ai/maggie 0.7.9 → 0.7.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -11
- package/bin/maggie.js +18 -21
- package/bundled-skills/README.md +0 -1
- package/bundled-skills/catalog.json +78 -0
- package/bundled-skills/maggie-dash/SKILL.md +39 -4
- package/bundled-skills/maggie-deployment/SKILL.md +6 -0
- package/bundled-skills/maggie-deployment/references/vps.md +33 -0
- package/bundled-skills/maggie-design/SKILL.md +30 -8
- package/bundled-skills/maggie-feedback/SKILL.md +2 -1
- package/bundled-skills/maggie-seo-geo/SKILL.md +7 -2
- package/bundled-templates/maggiedash/section-fanout.json +11 -0
- package/bundled-templates/maggiedash/section-registry.json +15 -0
- package/bundled-tools/clis/maggie_dash.py +80 -3
- package/bundled-tools/clis/maggie_design.py +134 -5
- package/bundled-tools/clis/maggie_feedback.py +3 -0
- package/bundled-tools/clis/maggie_icon_inventory.py +18 -6
- package/bundled-tools/clis/maggie_release.py +55 -0
- package/bundled-tools/clis/site_audit.py +34 -2
- package/bundled-tools/runtime/maggie_sections.py +140 -0
- package/bundled-tools/runtime/route_imports.py +23 -0
- package/bundled-tools/runtime/site_baseline.py +37 -4
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
import json
|
|
5
5
|
from datetime import datetime, timezone
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from urllib.parse import urlparse
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def snapshot(report: dict, reviewer: str) -> dict:
|
|
@@ -16,15 +17,25 @@ def snapshot(report: dict, reviewer: str) -> dict:
|
|
|
16
17
|
if not pages or len(pages) != crawl.get("discovered_url_count"):
|
|
17
18
|
raise ValueError("baseline page coverage is incomplete")
|
|
18
19
|
contracts = {}
|
|
20
|
+
content = {}
|
|
21
|
+
excluded_query_urls = []
|
|
19
22
|
for page in pages:
|
|
20
23
|
if not page.get("passed") or not isinstance(page.get("contract"), dict):
|
|
21
24
|
raise ValueError("baseline requires successful page contracts")
|
|
22
25
|
if page["url"] in contracts:
|
|
23
26
|
raise ValueError("duplicate page URL")
|
|
27
|
+
if urlparse(page["url"]).query:
|
|
28
|
+
excluded_query_urls.append(page["url"])
|
|
29
|
+
continue
|
|
24
30
|
contracts[page["url"]] = page["contract"]
|
|
31
|
+
if isinstance(page.get("contentContract"), dict):
|
|
32
|
+
content[page["url"]] = page["contentContract"]
|
|
33
|
+
if not contracts:
|
|
34
|
+
raise ValueError("baseline has no non-query page contracts")
|
|
25
35
|
return {"schemaVersion": "maggie-site-baseline.v1", "url": report["url"],
|
|
26
36
|
"reviewer": reviewer.strip(), "createdAt": datetime.now(timezone.utc).isoformat(),
|
|
27
|
-
"pages": contracts
|
|
37
|
+
"pages": contracts, "content": content,
|
|
38
|
+
"excludedQueryUrls": sorted(excluded_query_urls)}
|
|
28
39
|
|
|
29
40
|
|
|
30
41
|
def compare(baseline: dict, report: dict) -> dict:
|
|
@@ -36,7 +47,10 @@ def compare(baseline: dict, report: dict) -> dict:
|
|
|
36
47
|
errors.append("site origin/base URL differs from baseline")
|
|
37
48
|
if not crawl.get("enabled") or not crawl.get("complete"):
|
|
38
49
|
errors.append("complete sitemap crawl required")
|
|
39
|
-
|
|
50
|
+
crawl_pages = crawl.get("pages", [])
|
|
51
|
+
query_urls = sorted(page["url"] for page in crawl_pages if urlparse(page["url"]).query)
|
|
52
|
+
current = {page["url"]: page.get("contract") for page in crawl_pages if not urlparse(page["url"]).query}
|
|
53
|
+
current_content = {page["url"]: page.get("contentContract") for page in crawl_pages if not urlparse(page["url"]).query and isinstance(page.get("contentContract"), dict)}
|
|
40
54
|
expected = baseline["pages"]
|
|
41
55
|
added, removed = sorted(current.keys() - expected.keys()), sorted(expected.keys() - current.keys())
|
|
42
56
|
changes = []
|
|
@@ -48,8 +62,27 @@ def compare(baseline: dict, report: dict) -> dict:
|
|
|
48
62
|
fields = sorted(key for key in expected[url].keys() | actual.keys() if expected[url].get(key) != actual.get(key))
|
|
49
63
|
if fields:
|
|
50
64
|
changes.append({"url": url, "fields": fields})
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
expected_content = baseline.get("content", {})
|
|
66
|
+
content_changes = []
|
|
67
|
+
content_not_compared = []
|
|
68
|
+
if expected_content:
|
|
69
|
+
for url in sorted(expected_content.keys() & current_content.keys()):
|
|
70
|
+
expected_contract = expected_content[url]
|
|
71
|
+
current_contract = current_content[url]
|
|
72
|
+
ignored_legacy_fields = {"images", "imageAlts"} if "images" not in expected_contract else set()
|
|
73
|
+
fields = sorted(key for key in expected_contract.keys() | current_contract.keys() if key not in ignored_legacy_fields and expected_contract.get(key) != current_contract.get(key))
|
|
74
|
+
if "images" not in expected_contract:
|
|
75
|
+
content_not_compared.append({"url": url, "fields": ["images", "imageAlts"], "reason": "baseline predates image content contract"})
|
|
76
|
+
if fields:
|
|
77
|
+
content_changes.append({"url": url, "fields": fields})
|
|
78
|
+
missing_content = sorted(expected_content.keys() - current_content.keys())
|
|
79
|
+
if missing_content:
|
|
80
|
+
errors.append("missing content contract: " + ", ".join(missing_content))
|
|
81
|
+
return {"passed": not errors and not added and not removed and not changes and not content_changes,
|
|
82
|
+
"errors": errors, "added": added, "removed": removed, "changed": changes,
|
|
83
|
+
"contentChanged": content_changes,
|
|
84
|
+
"contentNotCompared": content_not_compared,
|
|
85
|
+
"excludedQueryUrls": query_urls}
|
|
53
86
|
|
|
54
87
|
|
|
55
88
|
def save(path: Path, baseline: dict) -> None:
|