← Files Research & Writing CopilotARCHIVED FILE
scripts/validate_package.py
2.63 KB · Nov 3, 2026 · 18:48 UTC
#!/usr/bin/env python3
"""Structural and metadata checks for this skills-only portable plugin."""
from pathlib import Path
import json,re,sys,hashlib
root=Path(__file__).resolve().parents[1]
p=json.loads((root/'plugin.json').read_text())
assert p['name']=='research-technical-writing-copilot'
assert p['version']=='0.2.0'
assert 'mcp.json' not in [x.name for x in root.iterdir()]
iface=p['extensions']['com.openai']['interface']
assert iface['displayName']=='Research & Writing Copilot'
assert iface['developerName']=='Tekris Labs'
assert len(iface['defaultPrompt'])<=3
assert all(len(v)<=128 for v in iface['defaultPrompt'])
assert len(iface['shortDescription'])<=30
assert len(iface['displayName'])<=30
for key in ('websiteURL','privacyPolicyURL','termsOfServiceURL','supportURL'):
assert iface[key].startswith('https://tekrislabs.com/')
for key in ('logo','composerIcon'):
assert (root/iface[key]).is_file()
assert (root/p['extensions']['com.openai']['onboardingSkill']).exists()
assert len(p['extensions']['com.openai']['interface']['capabilities'])<=20
skills=list((root/'skills').glob('*/SKILL.md'))
assert len(skills)==18,(len(skills),[str(x) for x in skills])
seen=set();checks=0
for s in skills:
v=s.read_text()
match=re.match(r'^---\nname: ([a-z0-9-]+)\ndescription: ([^\n]+)\n---\n',v)
assert match,s
name,desc=match.groups()
assert name==s.parent.name
assert name not in seen
assert len(p['name']+':'+name)<=64
assert len(desc)<=1024
assert len(v)>700,(name,len(v))
seen.add(name);checks+=7
for ref in re.findall(r'`\.\./\.\./references/([^`]+)`',v):
assert (root/'references'/ref).is_file(),(name,ref)
checks+=1
bench=json.loads((root/'benchmarks/cases.json').read_text())['cases']
assert len(bench)==30
assert len({x['id'] for x in bench})==len(bench)
assert all(x['skill'] in seen and x['status']=='not_run' for x in bench)
assert len(list((root/'references/original').glob('*.md')))==7
assert len(list((root/'templates').iterdir()))==10
compat=json.loads((root/'.codex-plugin/plugin.json').read_text())
assert compat['name']==p['name'] and compat['version']==p['version']
assert compat['interface']['developerName']==iface['developerName']
assert compat['interface']['defaultPrompt']==iface['defaultPrompt']
assert compat['interface']['logo']==iface['logo']
assert compat['interface']['composerIcon']==iface['composerIcon']
for src in ('assets/logo.png','assets/composer-icon.png'):
assert (root/src).stat().st_size>1000
print(json.dumps({'status':'pass','skills':len(skills),'benchmarks':len(bench),'reference_guides':len(list((root/'references').rglob('*.md'))),'templates':len(list((root/'templates').iterdir())),'structural_checks':checks+38},indent=2))
SHA-256: 2e94a8dfa7ae661bf0648164d256617f52c1ad4914236513e344ebd7fa207cf6