Merge integration/rpa-dashboard-skills (ticket 03) into ticket 02

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
VasanthandClaude Opus 5.5 committed 2026-10-16 14:30:09 +05:30
commit 1b6ae23573
15 files changed
+1213 -14

No files matched your search

+59 -4
View File
@@ -9,6 +9,7 @@ prompt (`-p` can't answer questions). It then grades the reply, runs the Seam 1
check on the page it built, and writes tests/evals/results/<fixture>.json.
Exit code 0 means every check passed.
"""
import difflib
import importlib.util
import json
import os
@@ -45,7 +46,49 @@ FIXTURES = {
"never_asks": [r"\bkeep\b|restyle", r"desktop|web"],
"bot": True,
},
# (c) existing teal frontend in web/, run once per answer to keep-or-restyle.
"c-keep": {
"fixture": "c-web-existing-frontend",
"prompt": "Build me an RPA dashboard for this project. I can't answer questions while you "
"work, so here are my answers to anything the skill asks. Keep or restyle the "
"existing frontend: keep its look. Optional sections: none.",
"frontend": r"(?=.*\bweb\b)(?=.*html)(?=.*(#0f766e|--color-brand))",
"asks": [r"keep|restyle", r"section"],
"never_asks": [r"^(?!.*(keep|restyle)).*(colou?r|Tebra Sky|Ember)", r"desktop"],
"page_has": ["--accent:#0f766e", "Trebuchet MS"],
"existing": "unchanged",
},
"c-restyle": {
"fixture": "c-web-existing-frontend",
"prompt": "Build me an RPA dashboard for this project. I can't answer questions while you "
"work, so here are my answers to anything the skill asks. Keep or restyle the "
"existing frontend: restyle it. Colours: Superbill Ember. Optional sections: none.",
"frontend": r"(?=.*\bweb\b)(?=.*html)(?=.*(#0f766e|--color-brand))",
"asks": [r"keep|restyle", r"Tebra Sky|Ember", r"section"],
"never_asks": [r"desktop"],
"page_has": ["--accent:#ff3049"],
"existing": "#ff3049", # only token lines may change, and the theme now uses this colour
},
}
# A line a restyle may change: a custom property, a comment, a blank, or a web-font link.
TOKEN_LINE = r"^\s*(--[\w-]+\s*:.*|/\*.*\*/|<link[^>]*fonts\.googleapis\.com.*|@import.*fonts\.googleapis\.com.*)?\s*$"
def squash(s):
"""Ignore spacing and case when looking for a token in the built page."""
return re.sub(r"\s+", "", s).lower()
def changed_lines(src, project):
"""Lines removed or added in the fixture's own files."""
out = []
for f in src.rglob("*"):
if f.is_file():
new = project / f.relative_to(src)
after = new.read_text(encoding="utf-8").splitlines() if new.exists() else []
out += [x[1:] for x in difflib.unified_diff(f.read_text(encoding="utf-8").splitlines(), after, lineterm="", n=0)
if x[:1] in "+-" and x[:3] not in ("+++", "---")]
return out
def bot_checks(project, html, checks, replay):
@@ -73,7 +116,8 @@ def main(fixture):
cfg = FIXTURES[fixture]
work = Path(tempfile.mkdtemp(prefix=f"rpa-eval-{fixture}-"))
project = work / "project"
shutil.copytree(ROOT / "tests" / "fixtures" / fixture, project)
src = ROOT / "tests" / "fixtures" / cfg.get("fixture", fixture)
shutil.copytree(src, project)
for skill in ROOT.glob("rpa-dashboard-*"):
shutil.copytree(skill, project / ".claude" / "skills" / skill.name)
@@ -91,12 +135,21 @@ def main(fixture):
return m[1] if m else ""
checks = {"frontend reported correctly": bool(re.search(cfg["frontend"], line("FRONTEND"), re.I))}
questions = line("QUESTIONS").split("|")
for pat in cfg["asks"]:
checks[f"asks /{pat}/"] = bool(re.search(pat, line("QUESTIONS"), re.I))
checks[f"asks /{pat}/"] = any(re.search(pat, q, re.I) for q in questions)
for pat in cfg["never_asks"]:
checks[f"never asks /{pat}/"] = not re.search(pat, line("QUESTIONS"), re.I)
checks[f"never asks /{pat}/"] = not any(re.search(pat, q, re.I) for q in questions)
if "existing" in cfg:
changed = changed_lines(src, project)
if cfg["existing"] == "unchanged":
checks["existing files unchanged"] = not changed
else:
checks["existing files: only token lines changed"] = bool(changed) and all(re.match(TOKEN_LINE, x) for x in changed)
checks[f"existing tokens now use {cfg['existing']}"] = any(cfg["existing"] in x.lower() for x in changed)
pages = [p for p in project.rglob("*.html") if ".claude" not in p.parts]
pages = [p for p in project.rglob("*.html")
if ".claude" not in p.parts and not (src / p.relative_to(project)).exists()] # new pages only
checks["exactly one page built"] = len(pages) == 1
results = ROOT / "tests" / "evals" / "results"
results.mkdir(exist_ok=True)
@@ -110,6 +163,8 @@ def main(fixture):
spec.loader.exec_module(palette)
t = palette.derive(cfg["brand"])
checks["custom palette applied"] = all(f"--accent:{t[m]['--accent']}" in html for m in t)
for needle in cfg.get("page_has", []):
checks[f"page has {needle}"] = squash(needle) in squash(html)
env = {**os.environ, "PAGE_CHECK_HTML": str(pages[0])}
if cfg.get("bot"):
env.update(bot_checks(project, html, checks, results / f"{fixture}.run.jsonl"))