Import sap-architecture skill

This commit is contained in:
2026-07-24 20:47:16 +00:00
commit f3699e6f43
121 changed files with 127110 additions and 0 deletions
+265
View File
@@ -0,0 +1,265 @@
#!/usr/bin/env python3
"""Search the bundled SAP template registry for templates that match a design pattern.
This is the "if SAP did something similar, find it for me" tool. Use cases
the LLM should reach for it:
- "I need to draw 4 zones with a vertical network divider — what SAP
template has that already?"
- "Which templates use exactly TRUST + Authenticate + A2A + MCP pills?"
- "Show me templates with ≥ 6 BTP service icons inside a Cloud Solutions
band, so I can match the spacing/sizing they use."
- "Which templates have Joule as a separate purple zone (not nested in BTP)?"
The script reads the precomputed `assets/reference-examples/template-profiles.json`
(built by `profile_template.py --build-registry`) and ranks templates by how
well their structural profile matches the query.
Usage:
find_pattern.py "vertical network divider"
find_pattern.py "joule purple zone"
find_pattern.py --pill TRUST --pill A2A --pill MCP
find_pattern.py --zones 4 --icons-min 8
find_pattern.py --pattern tri-zone-joule-btp-third-party
find_pattern.py --top 5 --json "identity flow at bottom"
Output: ranked templates with the matching evidence per template.
"""
from __future__ import annotations
import argparse
import json
import re
import sys
from dataclasses import dataclass, field
from pathlib import Path
THIS_DIR = Path(__file__).resolve().parent
REGISTRY_DEFAULT = THIS_DIR.parent / "assets" / "reference-examples" / "template-profiles.json"
@dataclass
class Match:
name: str
score: float
reasons: list[str] = field(default_factory=list)
profile: dict = field(default_factory=dict)
def load_registry(path: Path) -> dict:
if not path.exists():
print(
f"registry not found: {path}\n"
"Run: python3 .../scripts/profile_template.py --build-registry",
file=sys.stderr,
)
sys.exit(2)
return json.loads(path.read_text(encoding="utf-8"))
def textual_score(profile: dict, terms: set[str]) -> tuple[float, list[str]]:
"""Score how often the search terms appear in the profile's textual fields."""
haystack_parts = [
profile.get("title", ""),
profile.get("description", ""),
" ".join(profile.get("aliases") or []),
" ".join(profile.get("tags") or []),
" ".join(profile.get("detected_patterns") or []),
" ".join(p.get("label", "") for p in (profile.get("zones") or [])),
" ".join(p.get("label", "") for p in (profile.get("cards") or [])),
" ".join(profile.get("pill_vocab") or []),
]
haystack = " ".join(str(s) for s in haystack_parts).lower()
hits = []
score = 0.0
for t in terms:
n = haystack.count(t)
if n > 0:
hits.append(f"{t}×{n}")
score += n
return score, hits
def pattern_match(profile: dict, want_patterns: list[str]) -> tuple[float, list[str]]:
have = set(profile.get("detected_patterns") or [])
matched = [p for p in want_patterns if p in have]
return (len(matched) * 8.0, matched)
def pill_match(profile: dict, want_pills: list[str]) -> tuple[float, list[str]]:
have = set(p.lower() for p in (profile.get("pill_vocab") or []))
matched = [p for p in want_pills if p.lower() in have]
return (len(matched) * 5.0, matched)
def structure_match(profile: dict, want: dict) -> tuple[float, list[str]]:
"""Partial-credit scoring for desired counts (zones, cards, icons, pills, edges)."""
structure = profile.get("structure_summary", {})
score = 0.0
reasons = []
pairs = {
"zones": "top_level_zones",
"nested_zones": "nested_zones",
"cards": "cards",
"icons": "icons",
"pills": "pills",
"edges": "edges",
}
for key, prof_key in pairs.items():
if want.get(key) is not None:
target = int(want[key])
actual = int(structure.get(prof_key, 0))
# Award full points when exact, partial when within 20%
if actual == target:
score += 6.0
reasons.append(f"{key}={actual}")
elif abs(actual - target) <= max(2, target * 0.2):
score += 3.0
reasons.append(f"{key}={actual}~={target}")
if want.get(f"{key}_min") is not None:
target = int(want[f"{key}_min"])
actual = int(structure.get(prof_key, 0))
if actual >= target:
score += 2.0
reasons.append(f"{key}>={actual}")
return score, reasons
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("query", nargs="*", help="free-text search across titles, tags, patterns, labels")
ap.add_argument("--registry", type=Path, default=REGISTRY_DEFAULT)
ap.add_argument("--top", type=int, default=5)
ap.add_argument("--json", action="store_true")
ap.add_argument("--pattern", action="append", default=[],
help="require a specific detected_patterns tag (repeatable)")
ap.add_argument("--pill", action="append", default=[],
help="require a specific pill verb in vocab (repeatable)")
ap.add_argument("--zones", type=int, help="prefer templates with this many top-level zones")
ap.add_argument("--zones-min", type=int)
ap.add_argument("--cards", type=int)
ap.add_argument("--cards-min", type=int)
ap.add_argument("--icons", type=int)
ap.add_argument("--icons-min", type=int)
ap.add_argument("--pills", type=int)
ap.add_argument("--pills-min", type=int)
ap.add_argument("--edges", type=int)
ap.add_argument("--edges-min", type=int)
ap.add_argument("--family", help="restrict to a specific family tag (e.g. ra0029, btp, ext-mdi)")
ap.add_argument("--list-patterns", action="store_true",
help="print every detected_patterns tag observed in the registry")
ap.add_argument("--list-pills", action="store_true",
help="print every pill verb observed across the registry")
args = ap.parse_args()
reg = load_registry(args.registry)
profiles = reg.get("templates", {})
if args.list_patterns:
all_pats: dict[str, int] = {}
for prof in profiles.values():
for p in (prof.get("detected_patterns") or []):
all_pats[p] = all_pats.get(p, 0) + 1
for pat, n in sorted(all_pats.items(), key=lambda kv: -kv[1]):
print(f" {n:>3}× {pat}")
return 0
if args.list_pills:
all_pills: dict[str, int] = {}
for prof in profiles.values():
for p in (prof.get("pill_vocab") or []):
all_pills[p] = all_pills.get(p, 0) + 1
for pill, n in sorted(all_pills.items(), key=lambda kv: -kv[1]):
print(f" {n:>3}× {pill!r}")
return 0
free_text = " ".join(args.query).lower().strip()
terms = set(re.findall(r"[a-z0-9]+", free_text)) if free_text else set()
want_structure = {
"zones": args.zones, "zones_min": args.zones_min,
"cards": args.cards, "cards_min": args.cards_min,
"icons": args.icons, "icons_min": args.icons_min,
"pills": args.pills, "pills_min": args.pills_min,
"edges": args.edges, "edges_min": args.edges_min,
}
matches: list[Match] = []
for name, profile in profiles.items():
if args.family and profile.get("family") != args.family:
continue
score = 0.0
reasons: list[str] = []
if terms:
s, hits = textual_score(profile, terms)
if s > 0:
score += s
reasons.append("text: " + ", ".join(hits[:8]))
if args.pattern:
s, hits = pattern_match(profile, args.pattern)
if s > 0:
score += s
reasons.append("pattern: " + ", ".join(hits))
else:
# Required patterns not found — skip this template
continue
if args.pill:
s, hits = pill_match(profile, args.pill)
if s > 0:
score += s
reasons.append("pills: " + ", ".join(hits))
s, hits = structure_match(profile, want_structure)
if s > 0:
score += s
reasons.append("structure: " + ", ".join(hits))
# Light prior: prefer primary templates when scores are tied
if profile.get("primary"):
score += 0.5
reasons.append("(primary)")
if score > 0 or not (terms or args.pattern or args.pill or any(want_structure.values())):
matches.append(Match(name=name, score=score, reasons=reasons, profile=profile))
matches.sort(key=lambda m: (-m.score, m.name))
matches = matches[: args.top]
if args.json:
out = [{
"name": m.name,
"score": round(m.score, 1),
"reasons": m.reasons,
"title": m.profile.get("title", ""),
"description": m.profile.get("description", ""),
"structure": m.profile.get("structure_summary", {}),
"detected_patterns": m.profile.get("detected_patterns", []),
"pill_vocab": m.profile.get("pill_vocab", []),
} for m in matches]
print(json.dumps(out, indent=2))
return 0
if not matches:
print("no templates matched the criteria")
return 0
for i, m in enumerate(matches, 1):
print(f"{i}. {m.score:5.1f} {m.name}")
if m.profile.get("title"):
print(f" title : {m.profile['title']}")
if m.profile.get("structure_summary"):
print(f" structure: {m.profile['structure_summary']}")
if m.profile.get("detected_patterns"):
print(f" patterns : {', '.join(m.profile['detected_patterns'][:8])}")
if m.profile.get("pill_vocab"):
print(f" pills : {', '.join(repr(p) for p in m.profile['pill_vocab'][:6])}")
for r in m.reasons:
print(f"{r}")
return 0
if __name__ == "__main__":
sys.exit(main())