mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-10-31 05:25:49 -04:00
DOS+BE: skill updates
This commit is contained in:
1 parent
c25fd5f6af
commit
a91c3f0957
1 file changed
+102
-17
+102
-17
@@ -2,17 +2,27 @@
|
||||
"""
|
||||
Flag PRs that touch some but not all files in a group of mirrored skill
|
||||
files (`.gemini/skills/`, `.github/skills/`, `.claude/skills/`) without
|
||||
touching the others. `.gemini/skills/skills-index/SKILL.md` documents these
|
||||
groups and says to "keep body content identical" across them - but nothing
|
||||
previously enforced that, and the plugin-development pair had already
|
||||
drifted apart before this check existed.
|
||||
touching the others, and - for the groups documented in
|
||||
`.gemini/skills/skills-index/SKILL.md` as covering identical content -
|
||||
flag when their bodies have actually drifted apart, not just whether a
|
||||
change touched one side.
|
||||
|
||||
This can't verify the files still say the *same thing* (that needs
|
||||
judgment - some groups are intentionally different in depth, and the three
|
||||
devcontainer-management targets each cover only part of the Gemini file),
|
||||
only that a change to one file didn't forget the others exist. Exit
|
||||
non-zero (but the CI step calling this is non-blocking) when a group looks
|
||||
one-sided.
|
||||
Two independent checks:
|
||||
|
||||
1. Presence drift (every group): a PR touched some files in a group but
|
||||
not the others. Still only a hint ("did you forget the other file?"),
|
||||
not proof either way - a genuinely tool-specific change can legitimately
|
||||
touch just one side.
|
||||
2. Content drift (CONTENT_MATCH_GROUPS only): the groups the skills index
|
||||
explicitly documents as "All three cover [the same things]" should have
|
||||
byte-identical bodies (frontmatter excluded - `name`/`description` are
|
||||
allowed to differ per assistant). `settings`/`settings-management`,
|
||||
`mcp-activation`, `project-navigation`, and the three devcontainer-
|
||||
management targets are deliberately NOT in this list - the skills index
|
||||
documents them as intentionally different in depth/scope, not drifted.
|
||||
|
||||
Exit non-zero (but the CI step calling this is non-blocking) when either
|
||||
check finds something.
|
||||
|
||||
python3 scripts/check_skill_pairs.py origin/main
|
||||
"""
|
||||
@@ -44,6 +54,27 @@ GROUPS = [
|
||||
[".gemini/skills/devcontainer-management/SKILL.md", ".github/skills/devcontainer-configs/SKILL.md"],
|
||||
]
|
||||
|
||||
# Subset of GROUPS (by first-member path) the skills index documents as
|
||||
# covering identical content across every member - everything else in
|
||||
# GROUPS is documented there as intentionally different in depth/scope
|
||||
# (settings, mcp-activation, project-navigation) or intentionally partial
|
||||
# (the three devcontainer-management targets, each covering only part of
|
||||
# the Gemini file).
|
||||
CONTENT_MATCH_GROUP_KEYS = {
|
||||
".gemini/skills/plugin-development/plugin-skill.md",
|
||||
".gemini/skills/plugin-readme/plugin-readme-skill.md",
|
||||
".gemini/skills/testing-workflow/SKILL.md",
|
||||
".gemini/skills/pr-analysis/SKILL.md",
|
||||
".gemini/skills/scan-pipeline/SKILL.md",
|
||||
".gemini/skills/database-patterns/SKILL.md",
|
||||
".gemini/skills/prd-writing/SKILL.md",
|
||||
".gemini/skills/ux-design-patterns/SKILL.md",
|
||||
".gemini/skills/skill-hygiene/SKILL.md",
|
||||
".gemini/skills/plugin-review/SKILL.md",
|
||||
".gemini/skills/install-scripts/SKILL.md",
|
||||
".gemini/skills/logging-standards/SKILL.md",
|
||||
}
|
||||
|
||||
|
||||
def changed_files(base_ref):
|
||||
result = subprocess.run(
|
||||
@@ -53,12 +84,27 @@ def changed_files(base_ref):
|
||||
return set(result.stdout.splitlines())
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("usage: check_skill_pairs.py <base-ref>", file=sys.stderr)
|
||||
return 2
|
||||
def strip_frontmatter(text):
|
||||
"""Drop a leading YAML frontmatter block (--- ... ---) so name/
|
||||
description, which are allowed to differ per assistant, don't count as
|
||||
content drift. Returns the stripped-and-trimmed body, or the original
|
||||
text trimmed if there's no frontmatter block."""
|
||||
if text.startswith("---"):
|
||||
parts = text.split("---", 2)
|
||||
if len(parts) >= 3:
|
||||
return parts[2].strip()
|
||||
return text.strip()
|
||||
|
||||
changed = changed_files(sys.argv[1])
|
||||
|
||||
def read_body(path):
|
||||
try:
|
||||
with open(path, encoding="utf-8") as f:
|
||||
return strip_frontmatter(f.read())
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
|
||||
def check_presence_drift(changed):
|
||||
problems = []
|
||||
for group in GROUPS:
|
||||
touched = [path for path in group if path in changed]
|
||||
@@ -67,12 +113,51 @@ def main():
|
||||
problems.append(
|
||||
f"- touched {', '.join(touched)} but not {', '.join(untouched)}."
|
||||
)
|
||||
return problems
|
||||
|
||||
if problems:
|
||||
|
||||
def check_content_drift():
|
||||
problems = []
|
||||
for group in GROUPS:
|
||||
if group[0] not in CONTENT_MATCH_GROUP_KEYS:
|
||||
continue
|
||||
bodies = {path: read_body(path) for path in group}
|
||||
reference_path, reference_body = group[0], bodies[group[0]]
|
||||
for path, body in bodies.items():
|
||||
if path == reference_path:
|
||||
continue
|
||||
if body != reference_body:
|
||||
problems.append(
|
||||
f"- {path} and {reference_path} are documented as covering "
|
||||
f"identical content but their bodies differ."
|
||||
)
|
||||
return problems
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("usage: check_skill_pairs.py <base-ref>", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
changed = changed_files(sys.argv[1])
|
||||
presence_problems = check_presence_drift(changed)
|
||||
content_problems = check_content_drift()
|
||||
|
||||
if presence_problems:
|
||||
print("Possible skill-group drift (only some mirrored files were touched):")
|
||||
print("\n".join(problems))
|
||||
print("\n".join(presence_problems))
|
||||
print("\nIf the change is genuinely tool-specific, ignore this. "
|
||||
"Otherwise update the other file(s) too - see .gemini/skills/skills-index/SKILL.md.")
|
||||
|
||||
if content_problems:
|
||||
if presence_problems:
|
||||
print()
|
||||
print("Skill-pair content drift (bodies documented as identical, but aren't):")
|
||||
print("\n".join(content_problems))
|
||||
print("\nDiff the files directly to see what changed - "
|
||||
"see .gemini/skills/skills-index/SKILL.md for which groups this applies to.")
|
||||
|
||||
if presence_problems or content_problems:
|
||||
return 1
|
||||
|
||||
print("No skill-group drift detected.")
|
||||
|
||||
Reference in new issue
Block a user