tribunal-kit 4.2.0 ā 4.3.1
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/.agent/ARCHITECTURE.md +21 -14
- package/.agent/agents/swarm-worker-contracts.md +5 -5
- package/.agent/agents/ui-ux-auditor.md +292 -0
- package/.agent/rules/GEMINI.md +8 -8
- package/.agent/scripts/__pycache__/_colors.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/_utils.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/case_law_manager.cpython-311.pyc +0 -0
- package/.agent/scripts/_colors.js +18 -0
- package/.agent/scripts/_utils.js +42 -0
- package/.agent/scripts/auto_preview.js +197 -0
- package/.agent/scripts/bundle_analyzer.js +290 -0
- package/.agent/scripts/case_law_manager.js +684 -0
- package/.agent/scripts/checklist.js +266 -0
- package/.agent/scripts/colors.js +17 -0
- package/.agent/scripts/compress_skills.js +141 -0
- package/.agent/scripts/consolidate_skills.js +149 -0
- package/.agent/scripts/context_broker.js +609 -0
- package/.agent/scripts/deep_compress.js +150 -0
- package/.agent/scripts/dependency_analyzer.js +272 -0
- package/.agent/scripts/graph_builder.js +199 -0
- package/.agent/scripts/graph_zoom.js +154 -0
- package/.agent/scripts/inner_loop_validator.js +465 -0
- package/.agent/scripts/lint_runner.js +187 -0
- package/.agent/scripts/minify_context.js +100 -0
- package/.agent/scripts/patch_skills_meta.js +156 -0
- package/.agent/scripts/patch_skills_output.js +244 -0
- package/.agent/scripts/schema_validator.js +297 -0
- package/.agent/scripts/security_scan.js +303 -0
- package/.agent/scripts/session_manager.js +276 -0
- package/.agent/scripts/skill_evolution.js +644 -0
- package/.agent/scripts/skill_integrator.js +313 -0
- package/.agent/scripts/strengthen_skills.js +193 -0
- package/.agent/scripts/strip_tribunal.js +47 -0
- package/.agent/scripts/swarm_dispatcher.js +360 -0
- package/.agent/scripts/test_runner.js +193 -0
- package/.agent/scripts/utils.js +32 -0
- package/.agent/scripts/verify_all.js +256 -0
- package/.agent/skills/agent-organizer/SKILL.md +12 -4
- package/.agent/skills/agentic-patterns/SKILL.md +12 -4
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +12 -4
- package/.agent/skills/api-patterns/SKILL.md +209 -201
- package/.agent/skills/api-security-auditor/SKILL.md +12 -4
- package/.agent/skills/app-builder/SKILL.md +12 -4
- package/.agent/skills/app-builder/templates/SKILL.md +76 -68
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +1 -1
- package/.agent/skills/appflow-wireframe/SKILL.md +12 -4
- package/.agent/skills/architecture/SKILL.md +12 -4
- package/.agent/skills/authentication-best-practices/SKILL.md +12 -4
- package/.agent/skills/bash-linux/SKILL.md +12 -4
- package/.agent/skills/behavioral-modes/SKILL.md +12 -4
- package/.agent/skills/brainstorming/SKILL.md +12 -4
- package/.agent/skills/building-native-ui/SKILL.md +12 -4
- package/.agent/skills/clean-code/SKILL.md +12 -4
- package/.agent/skills/code-review-checklist/SKILL.md +12 -4
- package/.agent/skills/config-validator/SKILL.md +12 -4
- package/.agent/skills/csharp-developer/SKILL.md +12 -4
- package/.agent/skills/data-validation-schemas/SKILL.md +290 -282
- package/.agent/skills/database-design/SKILL.md +202 -194
- package/.agent/skills/deployment-procedures/SKILL.md +12 -4
- package/.agent/skills/devops-engineer/SKILL.md +12 -4
- package/.agent/skills/devops-incident-responder/SKILL.md +12 -4
- package/.agent/skills/doc.md +1 -1
- package/.agent/skills/documentation-templates/SKILL.md +12 -4
- package/.agent/skills/edge-computing/SKILL.md +12 -4
- package/.agent/skills/error-resilience/SKILL.md +390 -382
- package/.agent/skills/extract-design-system/SKILL.md +12 -4
- package/.agent/skills/framer-motion-expert/SKILL.md +206 -199
- package/.agent/skills/frontend-design/SKILL.md +163 -155
- package/.agent/skills/game-design-expert/SKILL.md +12 -4
- package/.agent/skills/game-engineering-expert/SKILL.md +12 -4
- package/.agent/skills/geo-fundamentals/SKILL.md +12 -4
- package/.agent/skills/github-operations/SKILL.md +12 -4
- package/.agent/skills/gsap-core/SKILL.md +54 -48
- package/.agent/skills/gsap-frameworks/SKILL.md +54 -48
- package/.agent/skills/gsap-performance/SKILL.md +54 -48
- package/.agent/skills/gsap-plugins/SKILL.md +54 -48
- package/.agent/skills/gsap-react/SKILL.md +54 -48
- package/.agent/skills/gsap-scrolltrigger/SKILL.md +54 -48
- package/.agent/skills/gsap-timeline/SKILL.md +54 -48
- package/.agent/skills/gsap-utils/SKILL.md +54 -48
- package/.agent/skills/i18n-localization/SKILL.md +12 -4
- package/.agent/skills/intelligent-routing/SKILL.md +41 -33
- package/.agent/skills/knowledge-graph/SKILL.md +36 -0
- package/.agent/skills/lint-and-validate/SKILL.md +12 -4
- package/.agent/skills/llm-engineering/SKILL.md +12 -4
- package/.agent/skills/local-first/SKILL.md +12 -4
- package/.agent/skills/mcp-builder/SKILL.md +12 -4
- package/.agent/skills/mobile-design/SKILL.md +225 -217
- package/.agent/skills/monorepo-management/SKILL.md +296 -288
- package/.agent/skills/motion-engineering/SKILL.md +195 -187
- package/.agent/skills/nextjs-react-expert/SKILL.md +196 -188
- package/.agent/skills/nodejs-best-practices/SKILL.md +12 -4
- package/.agent/skills/observability/SKILL.md +12 -4
- package/.agent/skills/parallel-agents/SKILL.md +12 -4
- package/.agent/skills/performance-profiling/SKILL.md +12 -4
- package/.agent/skills/plan-writing/SKILL.md +12 -4
- package/.agent/skills/platform-engineer/SKILL.md +12 -4
- package/.agent/skills/playwright-best-practices/SKILL.md +12 -4
- package/.agent/skills/powershell-windows/SKILL.md +12 -4
- package/.agent/skills/project-idioms/SKILL.md +12 -4
- package/.agent/skills/python-patterns/SKILL.md +12 -4
- package/.agent/skills/python-pro/SKILL.md +285 -277
- package/.agent/skills/react-specialist/SKILL.md +239 -231
- package/.agent/skills/readme-builder/SKILL.md +12 -4
- package/.agent/skills/realtime-patterns/SKILL.md +12 -4
- package/.agent/skills/red-team-tactics/SKILL.md +12 -4
- package/.agent/skills/rust-pro/SKILL.md +12 -4
- package/.agent/skills/seo-fundamentals/SKILL.md +12 -4
- package/.agent/skills/server-management/SKILL.md +12 -4
- package/.agent/skills/shadcn-ui-expert/SKILL.md +12 -4
- package/.agent/skills/skill-creator/SKILL.md +12 -4
- package/.agent/skills/sql-pro/SKILL.md +12 -4
- package/.agent/skills/supabase-postgres-best-practices/SKILL.md +12 -4
- package/.agent/skills/swiftui-expert/SKILL.md +12 -4
- package/.agent/skills/systematic-debugging/SKILL.md +12 -4
- package/.agent/skills/tailwind-patterns/SKILL.md +12 -4
- package/.agent/skills/tdd-workflow/SKILL.md +12 -4
- package/.agent/skills/test-result-analyzer/SKILL.md +12 -4
- package/.agent/skills/testing-patterns/SKILL.md +12 -4
- package/.agent/skills/trend-researcher/SKILL.md +12 -4
- package/.agent/skills/typescript-advanced/SKILL.md +297 -289
- package/.agent/skills/ui-ux-pro-max/SKILL.md +12 -4
- package/.agent/skills/ui-ux-researcher/SKILL.md +12 -4
- package/.agent/skills/vue-expert/SKILL.md +237 -229
- package/.agent/skills/vulnerability-scanner/SKILL.md +12 -4
- package/.agent/skills/web-accessibility-auditor/SKILL.md +12 -4
- package/.agent/skills/web-design-guidelines/SKILL.md +12 -4
- package/.agent/skills/webapp-testing/SKILL.md +12 -4
- package/.agent/skills/whimsy-injector/SKILL.md +12 -4
- package/.agent/skills/workflow-optimizer/SKILL.md +12 -4
- package/.agent/workflows/audit.md +6 -6
- package/.agent/workflows/deploy.md +1 -1
- package/.agent/workflows/generate.md +23 -6
- package/.agent/workflows/session.md +5 -5
- package/.agent/workflows/swarm.md +2 -2
- package/README.md +242 -186
- package/bin/tribunal-kit.js +297 -57
- package/package.json +81 -77
- package/scripts/changelog.js +167 -0
- package/scripts/sync-version.js +81 -0
- package/scripts/validate-payload.js +73 -0
- package/.agent/scripts/__pycache__/auto_preview.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/bundle_analyzer.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/checklist.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/dependency_analyzer.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/security_scan.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/session_manager.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/skill_integrator.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/swarm_dispatcher.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/test_runner.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/verify_all.cpython-311.pyc +0 -0
- package/.agent/scripts/auto_preview.py +0 -180
- package/.agent/scripts/bundle_analyzer.py +0 -259
- package/.agent/scripts/case_law_manager.py +0 -755
- package/.agent/scripts/checklist.py +0 -209
- package/.agent/scripts/compress_skills.py +0 -167
- package/.agent/scripts/consolidate_skills.py +0 -173
- package/.agent/scripts/deep_compress.py +0 -202
- package/.agent/scripts/dependency_analyzer.py +0 -247
- package/.agent/scripts/lint_runner.py +0 -188
- package/.agent/scripts/minify_context.py +0 -80
- package/.agent/scripts/patch_skills_meta.py +0 -177
- package/.agent/scripts/patch_skills_output.py +0 -285
- package/.agent/scripts/schema_validator.py +0 -279
- package/.agent/scripts/security_scan.py +0 -224
- package/.agent/scripts/session_manager.py +0 -261
- package/.agent/scripts/skill_evolution.py +0 -563
- package/.agent/scripts/skill_integrator.py +0 -234
- package/.agent/scripts/strengthen_skills.py +0 -220
- package/.agent/scripts/strip_tribunal.py +0 -41
- package/.agent/scripts/swarm_dispatcher.py +0 -350
- package/.agent/scripts/test_runner.py +0 -192
- package/.agent/scripts/test_swarm_dispatcher.py +0 -163
- package/.agent/scripts/verify_all.py +0 -195
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
checklist.py ā Priority-based project audit runner for the Tribunal Agent Kit.
|
|
4
|
-
|
|
5
|
-
Runs a tiered audit sequence:
|
|
6
|
-
Priority 1: Security
|
|
7
|
-
Priority 2: Lint
|
|
8
|
-
Priority 3: Schema validation
|
|
9
|
-
Priority 4: Tests
|
|
10
|
-
Priority 5: UX / Accessibility
|
|
11
|
-
Priority 6: SEO
|
|
12
|
-
Priority 7: Lighthouse / E2E (requires --url)
|
|
13
|
-
|
|
14
|
-
Usage:
|
|
15
|
-
python .agent/scripts/checklist.py .
|
|
16
|
-
python .agent/scripts/checklist.py . --url http://localhost:3000
|
|
17
|
-
python .agent/scripts/checklist.py . --skip security,seo
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
import os
|
|
21
|
-
import sys
|
|
22
|
-
import subprocess
|
|
23
|
-
import argparse
|
|
24
|
-
from pathlib import Path
|
|
25
|
-
|
|
26
|
-
# āāā ANSI color output āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
27
|
-
RED = "\033[91m"
|
|
28
|
-
GREEN = "\033[92m"
|
|
29
|
-
YELLOW = "\033[93m"
|
|
30
|
-
BLUE = "\033[94m"
|
|
31
|
-
RESET = "\033[0m"
|
|
32
|
-
BOLD = "\033[1m"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def print_header(title: str) -> None:
|
|
36
|
-
print(f"\n{BOLD}{BLUE}āāā {title} āāā{RESET}")
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def print_ok(msg: str) -> None:
|
|
40
|
-
print(f" {GREEN}ā
{msg}{RESET}")
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def print_fail(msg: str) -> None:
|
|
44
|
-
print(f" {RED}ā {msg}{RESET}")
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def print_skip(msg: str) -> None:
|
|
48
|
-
print(f" {YELLOW}āļø Skipped: {msg}{RESET}")
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def run_check(label: str, cmd: list[str], cwd: str) -> bool:
|
|
52
|
-
"""Run a shell command and return True if it exits with code 0."""
|
|
53
|
-
try:
|
|
54
|
-
result = subprocess.run(
|
|
55
|
-
cmd,
|
|
56
|
-
cwd=cwd,
|
|
57
|
-
capture_output=True,
|
|
58
|
-
text=True,
|
|
59
|
-
timeout=60,
|
|
60
|
-
)
|
|
61
|
-
if result.returncode == 0:
|
|
62
|
-
print_ok(f"{label} passed")
|
|
63
|
-
return True
|
|
64
|
-
else:
|
|
65
|
-
print_fail(f"{label} failed")
|
|
66
|
-
if result.stdout.strip():
|
|
67
|
-
print(f" {result.stdout.strip()[:500]}")
|
|
68
|
-
if result.stderr.strip():
|
|
69
|
-
print(f" {result.stderr.strip()[:500]}")
|
|
70
|
-
return False
|
|
71
|
-
except FileNotFoundError:
|
|
72
|
-
print_skip(f"{label} ā command not found (tool not installed)")
|
|
73
|
-
return True # Don't block on tools that aren't installed
|
|
74
|
-
except subprocess.TimeoutExpired:
|
|
75
|
-
print_fail(f"{label} ā timed out after 60s")
|
|
76
|
-
return False
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def check_secrets(project_root: str) -> bool:
|
|
80
|
-
"""Scan for hardcoded secrets in source files."""
|
|
81
|
-
print_header("Security ā Secret Scan")
|
|
82
|
-
dangerous_patterns = [
|
|
83
|
-
"password=",
|
|
84
|
-
"secret=",
|
|
85
|
-
"api_key=",
|
|
86
|
-
"apikey=",
|
|
87
|
-
"AUTH_TOKEN=",
|
|
88
|
-
"PRIVATE_KEY=",
|
|
89
|
-
]
|
|
90
|
-
found_issues = False
|
|
91
|
-
source_extensions = {".ts", ".tsx", ".js", ".jsx", ".py", ".env"}
|
|
92
|
-
|
|
93
|
-
for root, dirs, files in os.walk(project_root):
|
|
94
|
-
# Skip known-safe directories
|
|
95
|
-
dirs[:] = [d for d in dirs if d not in {"node_modules", ".git", ".agent", "dist", "__pycache__"}]
|
|
96
|
-
for filename in files:
|
|
97
|
-
if not any(filename.endswith(ext) for ext in source_extensions):
|
|
98
|
-
continue
|
|
99
|
-
if filename.startswith(".env"):
|
|
100
|
-
continue # .env files are allowed to have these
|
|
101
|
-
filepath = os.path.join(root, filename)
|
|
102
|
-
try:
|
|
103
|
-
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
|
|
104
|
-
for line_num, line in enumerate(f, 1):
|
|
105
|
-
line_lower = line.lower().strip()
|
|
106
|
-
if any(pattern in line_lower for pattern in dangerous_patterns):
|
|
107
|
-
# Only flag if it looks like an actual value (contains = and a non-empty value)
|
|
108
|
-
if "=" in line and not line_lower.strip().startswith("#"):
|
|
109
|
-
rel = os.path.relpath(filepath, project_root)
|
|
110
|
-
print_fail(f"Possible secret: {rel}:{line_num} ā {line.strip()[:80]}")
|
|
111
|
-
found_issues = True
|
|
112
|
-
except (IOError, PermissionError):
|
|
113
|
-
pass
|
|
114
|
-
|
|
115
|
-
if not found_issues:
|
|
116
|
-
print_ok("No hardcoded secrets detected")
|
|
117
|
-
return not found_issues
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def run_all(project_root: str, url: str | None, skip: list[str]) -> int:
|
|
121
|
-
"""Run all checklist tiers. Returns number of failures."""
|
|
122
|
-
failures = 0
|
|
123
|
-
|
|
124
|
-
# Priority 1 ā Security
|
|
125
|
-
if "security" not in skip:
|
|
126
|
-
print_header("Priority 1 ā Security")
|
|
127
|
-
if not check_secrets(project_root):
|
|
128
|
-
failures += 1
|
|
129
|
-
else:
|
|
130
|
-
print_skip("Security tier")
|
|
131
|
-
|
|
132
|
-
# Priority 2 ā Lint
|
|
133
|
-
if "lint" not in skip:
|
|
134
|
-
print_header("Priority 2 ā Lint")
|
|
135
|
-
if not run_check("ESLint", ["npx", "eslint", ".", "--max-warnings=0"], project_root):
|
|
136
|
-
failures += 1
|
|
137
|
-
if not run_check("TypeScript", ["npx", "tsc", "--noEmit"], project_root):
|
|
138
|
-
failures += 1
|
|
139
|
-
else:
|
|
140
|
-
print_skip("Lint tier")
|
|
141
|
-
|
|
142
|
-
# Priority 3 ā Schema
|
|
143
|
-
if "schema" not in skip:
|
|
144
|
-
print_header("Priority 3 ā Schema")
|
|
145
|
-
print_skip("Schema check ā run manually if you have DB migrations")
|
|
146
|
-
else:
|
|
147
|
-
print_skip("Schema tier")
|
|
148
|
-
|
|
149
|
-
# Priority 4 ā Tests
|
|
150
|
-
if "tests" not in skip:
|
|
151
|
-
print_header("Priority 4 ā Tests")
|
|
152
|
-
if not run_check("Test suite", ["npm", "test", "--", "--passWithNoTests"], project_root):
|
|
153
|
-
failures += 1
|
|
154
|
-
else:
|
|
155
|
-
print_skip("Tests tier")
|
|
156
|
-
|
|
157
|
-
# Priority 5 ā UX
|
|
158
|
-
if "ux" not in skip:
|
|
159
|
-
print_header("Priority 5 ā UX / Accessibility")
|
|
160
|
-
print_skip("UX audit ā run /preview start then check manually or with Lighthouse")
|
|
161
|
-
else:
|
|
162
|
-
print_skip("UX tier")
|
|
163
|
-
|
|
164
|
-
# Priority 6 ā SEO
|
|
165
|
-
if "seo" not in skip:
|
|
166
|
-
print_header("Priority 6 ā SEO")
|
|
167
|
-
print_skip("SEO check ā use /ui-ux-pro-max for SEO-sensitive pages")
|
|
168
|
-
else:
|
|
169
|
-
print_skip("SEO tier")
|
|
170
|
-
|
|
171
|
-
# Priority 7 ā Lighthouse / E2E
|
|
172
|
-
if url and "e2e" not in skip:
|
|
173
|
-
print_header("Priority 7 ā Lighthouse / E2E")
|
|
174
|
-
if not run_check("Playwright E2E", ["npx", "playwright", "test"], project_root):
|
|
175
|
-
failures += 1
|
|
176
|
-
elif not url:
|
|
177
|
-
print_skip("E2E / Lighthouse ā pass --url to enable")
|
|
178
|
-
|
|
179
|
-
# āāā Summary āāā
|
|
180
|
-
print(f"\n{BOLD}āāā Checklist Summary āāā{RESET}")
|
|
181
|
-
if failures == 0:
|
|
182
|
-
print_ok(f"All checks passed ā ready to proceed")
|
|
183
|
-
else:
|
|
184
|
-
print_fail(f"{failures} tier(s) failed ā fix Critical issues before proceeding")
|
|
185
|
-
|
|
186
|
-
return failures
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def main() -> None:
|
|
190
|
-
parser = argparse.ArgumentParser(description="Tribunal project checklist runner")
|
|
191
|
-
parser.add_argument("path", help="Project root directory")
|
|
192
|
-
parser.add_argument("--url", help="Local server URL for Lighthouse/E2E checks", default=None)
|
|
193
|
-
parser.add_argument("--skip", help="Comma-separated tiers to skip (security,lint,schema,tests,ux,seo,e2e)", default="")
|
|
194
|
-
args = parser.parse_args()
|
|
195
|
-
|
|
196
|
-
project_root = os.path.abspath(args.path)
|
|
197
|
-
if not os.path.isdir(project_root):
|
|
198
|
-
print_fail(f"Directory not found: {project_root}")
|
|
199
|
-
sys.exit(1)
|
|
200
|
-
|
|
201
|
-
skip = [s.strip().lower() for s in args.skip.split(",") if s.strip()]
|
|
202
|
-
|
|
203
|
-
print(f"{BOLD}Tribunal Checklist ā {project_root}{RESET}")
|
|
204
|
-
failures = run_all(project_root, args.url, skip)
|
|
205
|
-
sys.exit(1 if failures > 0 else 0)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if __name__ == "__main__":
|
|
209
|
-
main()
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
compress_skills.py - Aggressive token reduction for .agent/skills/**/*.md files
|
|
4
|
-
WHAT IT DOES:
|
|
5
|
-
1. Strips ## šļø Tribunal Integration sections (in GEMINI.md globally)
|
|
6
|
-
2. Strips ## ā
Pre-Flight Self-Audit sections (duplication)
|
|
7
|
-
3. Strips ## Cross-Workflow Navigation sections
|
|
8
|
-
4. Strips ## Output Format sections
|
|
9
|
-
5. Strips inline comment blocks inside code (// Description of obvious stuff)
|
|
10
|
-
6. Collapses 3+ empty lines ā 1
|
|
11
|
-
7. Removes chatty intro paragraphs (patterns like "X is Y. If you Z, you're Z.")
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
import os, re, sys
|
|
15
|
-
|
|
16
|
-
# āāā Section strippers āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
17
|
-
|
|
18
|
-
SECTION_PATTERNS = [
|
|
19
|
-
# Tribunal / pre-flight boilerplate (global in GEMINI.md)
|
|
20
|
-
r'(?m)^## šļø Tribunal Integration[\s\S]*?(?=\n## |\n# |\Z)',
|
|
21
|
-
r'(?m)^## Tribunal Integration[\s\S]*?(?=\n## |\n# |\Z)',
|
|
22
|
-
r'(?m)^### ā
Pre-Flight Self-Audit[\s\S]*?(?=\n## |\n### |\n# |\Z)',
|
|
23
|
-
r'(?m)^## Pre-Flight Self-Audit[\s\S]*?(?=\n## |\n# |\Z)',
|
|
24
|
-
r'(?m)^## Cross-Workflow Navigation[\s\S]*?(?=\n## |\n# |\Z)',
|
|
25
|
-
r'(?m)^## Output Format\s*\n```[\s\S]*?```\s*\n',
|
|
26
|
-
r'(?m)^## VBC Protocol[\s\S]*?(?=\n## |\n# |\Z)',
|
|
27
|
-
r'(?m)^## LLM Traps[\s\S]*?(?=\n## |\n# |\Z)',
|
|
28
|
-
]
|
|
29
|
-
|
|
30
|
-
# āāā Chatty intro line patterns āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
31
|
-
# e.g. "React 19 is a paradigm shift. Server Components are the default."
|
|
32
|
-
# These are after the frontmatter H1 title ā motivational filler.
|
|
33
|
-
CHATTY_INTRO = re.compile(
|
|
34
|
-
r'(?m)^(# .+\n)\n[A-Z][^#\n]{60,}\n[A-Z][^#\n]{40,}\n\n---',
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
def strip_chatty_intro(content):
|
|
38
|
-
def replace(m):
|
|
39
|
-
return m.group(1) + '\n---'
|
|
40
|
-
return CHATTY_INTRO.sub(replace, content)
|
|
41
|
-
|
|
42
|
-
# āāā Trim verbose inline comments in code blocks āāāāāāāāāāāāāāāāāāāāāāāāā
|
|
43
|
-
# Removes "// comment that just restates the surrounding code name"
|
|
44
|
-
OBVIOUS_COMMENT = re.compile(
|
|
45
|
-
r'(?m)^(\s*)(// (default for most properties|shorthand|number of repeats|default: \d+|spring tension|resistance|weight|approximate duration|deceleration rate)[^\n]*)\n'
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
def strip_obvious_comments(content):
|
|
49
|
-
return OBVIOUS_COMMENT.sub('', content)
|
|
50
|
-
|
|
51
|
-
# āāā Long repetitive ā
/ā rule blocks that repeat main section āāāāāāāāāāāā
|
|
52
|
-
# These are usually "Performance Rules" text blocks restating code above
|
|
53
|
-
PERF_TEXT_BLOCK = re.compile(
|
|
54
|
-
r'(?m)^```\n(ā
Use \w[^\n]*\n ā [^\n]*\n\n?){3,}```\n'
|
|
55
|
-
)
|
|
56
|
-
def compress_perf_blocks(content):
|
|
57
|
-
def to_bullets(m):
|
|
58
|
-
text = m.group(0)
|
|
59
|
-
lines = text.strip('`\n').splitlines()
|
|
60
|
-
bullets = []
|
|
61
|
-
for line in lines:
|
|
62
|
-
stripped = line.strip()
|
|
63
|
-
if stripped.startswith('ā
') or stripped.startswith('ā'):
|
|
64
|
-
bullets.append(f'- {stripped}')
|
|
65
|
-
elif stripped.startswith('ā'):
|
|
66
|
-
bullets[-1] += f' ({stripped[1:].strip()})'
|
|
67
|
-
return '\n'.join(bullets) + '\n'
|
|
68
|
-
return PERF_TEXT_BLOCK.sub(to_bullets, content)
|
|
69
|
-
|
|
70
|
-
# āāā Collapse empty lines āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
71
|
-
def collapse_blanks(content):
|
|
72
|
-
return re.sub(r'\n{3,}', '\n\n', content)
|
|
73
|
-
|
|
74
|
-
# āāā Remove "This is X ā not Y" filler sentences before the first ## āāāāā
|
|
75
|
-
FILLER_BEFORE_SECTION = re.compile(
|
|
76
|
-
r'(?m)(^# .+\n\n)([A-Z][^\n]+\n){1,4}(\n---\n)',
|
|
77
|
-
re.MULTILINE
|
|
78
|
-
)
|
|
79
|
-
def remove_filler_between_title_and_hr(content):
|
|
80
|
-
def replacement(m):
|
|
81
|
-
return m.group(1) + m.group(3)
|
|
82
|
-
return FILLER_BEFORE_SECTION.sub(replacement, content)
|
|
83
|
-
|
|
84
|
-
# āāā Strip redundant version comment banners āāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
85
|
-
# e.g. "// motion.div, motion.span, motion.button, motion.svg, motion.path, etc."
|
|
86
|
-
# "// Any HTML or SVG element can be prefixed with `motion.`" - obvious
|
|
87
|
-
REDUNDANT_NOTE = re.compile(r'(?m)^// (motion\.\w+|Any HTML|Note:|Variant names propagate|// )[^\n]*\n')
|
|
88
|
-
|
|
89
|
-
def strip_redundant_notes(content):
|
|
90
|
-
return REDUNDANT_NOTE.sub('', content)
|
|
91
|
-
|
|
92
|
-
# āāā Main pipeline āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
93
|
-
|
|
94
|
-
def compress_file(path):
|
|
95
|
-
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
96
|
-
original = f.read()
|
|
97
|
-
|
|
98
|
-
content = original
|
|
99
|
-
|
|
100
|
-
# 1. Strip global boilerplate sections
|
|
101
|
-
for pattern in SECTION_PATTERNS:
|
|
102
|
-
content = re.sub(pattern, '', content)
|
|
103
|
-
|
|
104
|
-
# 2. Remove chatty intro paragraphs
|
|
105
|
-
content = strip_chatty_intro(content)
|
|
106
|
-
|
|
107
|
-
# 3. Remove filler between title and first ---
|
|
108
|
-
content = remove_filler_between_title_and_hr(content)
|
|
109
|
-
|
|
110
|
-
# 4. Strip obvious inline comments from code
|
|
111
|
-
content = strip_obvious_comments(content)
|
|
112
|
-
|
|
113
|
-
# 5. Strip redundant notes
|
|
114
|
-
content = strip_redundant_notes(content)
|
|
115
|
-
|
|
116
|
-
# 6. Compress verbose perf rule text blocks to bullet lists
|
|
117
|
-
content = compress_perf_blocks(content)
|
|
118
|
-
|
|
119
|
-
# 7. Collapse 3+ blank lines
|
|
120
|
-
content = collapse_blanks(content)
|
|
121
|
-
|
|
122
|
-
# Write back
|
|
123
|
-
with open(path, 'w', encoding='utf-8') as f:
|
|
124
|
-
f.write(content.strip() + '\n')
|
|
125
|
-
|
|
126
|
-
saved = len(original) - len(content)
|
|
127
|
-
return len(original), len(content), saved
|
|
128
|
-
|
|
129
|
-
def main():
|
|
130
|
-
base = '.agent/skills'
|
|
131
|
-
if not os.path.exists(base):
|
|
132
|
-
print(f"ERROR: '{base}' not found. Run from tribunal-kit root.", file=sys.stderr)
|
|
133
|
-
sys.exit(1)
|
|
134
|
-
|
|
135
|
-
total_orig = 0
|
|
136
|
-
total_new = 0
|
|
137
|
-
results = []
|
|
138
|
-
|
|
139
|
-
for root, _, files in os.walk(base):
|
|
140
|
-
for fname in files:
|
|
141
|
-
if fname.endswith('.md'):
|
|
142
|
-
path = os.path.join(root, fname)
|
|
143
|
-
orig, new, saved = compress_file(path)
|
|
144
|
-
total_orig += orig
|
|
145
|
-
total_new += new
|
|
146
|
-
if saved > 0:
|
|
147
|
-
results.append((saved, path))
|
|
148
|
-
|
|
149
|
-
results.sort(reverse=True)
|
|
150
|
-
|
|
151
|
-
print(f"\n{'='*55}")
|
|
152
|
-
print(f" Skill Compression Complete")
|
|
153
|
-
print(f"{'='*55}")
|
|
154
|
-
print(f" Original : {total_orig:,} bytes ({total_orig//1024}KB)")
|
|
155
|
-
print(f" After : {total_new:,} bytes ({total_new//1024}KB)")
|
|
156
|
-
saved_total = total_orig - total_new
|
|
157
|
-
pct = saved_total / total_orig * 100 if total_orig else 0
|
|
158
|
-
print(f" Saved : {saved_total:,} bytes ({saved_total//1024}KB) ā {pct:.1f}%")
|
|
159
|
-
print(f"\n Top savings:")
|
|
160
|
-
for saved, path in results[:15]:
|
|
161
|
-
skill = os.path.basename(os.path.dirname(path))
|
|
162
|
-
fname = os.path.basename(path)
|
|
163
|
-
print(f" -{saved//1024:2}KB {skill}/{fname}")
|
|
164
|
-
print()
|
|
165
|
-
|
|
166
|
-
if __name__ == '__main__':
|
|
167
|
-
main()
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
consolidate_skills.py
|
|
4
|
-
Merges all sub-files in skill directories into the main SKILL.md.
|
|
5
|
-
Strips: verbose intros, output format blocks, run scripts tables,
|
|
6
|
-
mandatory read tables, empty headers, redundant boilerplate.
|
|
7
|
-
Keeps: all code blocks, hallucination traps, checklist items.
|
|
8
|
-
|
|
9
|
-
Usage:
|
|
10
|
-
python .agent/scripts/consolidate_skills.py [skill_name]
|
|
11
|
-
python .agent/scripts/consolidate_skills.py # all skills
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
import os, re, sys
|
|
15
|
-
|
|
16
|
-
BASE = '.agent/skills'
|
|
17
|
-
|
|
18
|
-
# These patterns are global (GEMINI.md) ā strip from sub-files before merge
|
|
19
|
-
STRIP_PATTERNS = [
|
|
20
|
-
r'(?ms)^## šļø Tribunal Integration.*?(?=^## |\Z)',
|
|
21
|
-
r'(?ms)^## Tribunal Integration.*?(?=^## |\Z)',
|
|
22
|
-
r'(?ms)^### ā
Pre-Flight Self-Audit.*?(?=^###|^## |\Z)',
|
|
23
|
-
r'(?ms)^## Pre-Flight Self-Audit.*?(?=^## |\Z)',
|
|
24
|
-
r'(?ms)^## Output Format\b.*?(?=^## |\Z)',
|
|
25
|
-
r'(?ms)^## š§ Runtime Scripts.*?(?=^## |\Z)',
|
|
26
|
-
r'(?ms)^## š“ MANDATORY.*?(?=^## |\Z)',
|
|
27
|
-
r'(?ms)^## ā ļø CRITICAL: ASK BEFORE ASSUMING.*?(?=^## |\Z)',
|
|
28
|
-
r'(?ms)^## š CHECKPOINT \(MANDATORY.*?(?=^## |\Z)',
|
|
29
|
-
r'(?ms)^## Output Format.*?```\n[^`]*```\n?(?=^## |\Z)',
|
|
30
|
-
r'(?ms)^\*\*Execute these for validation.*?---\n',
|
|
31
|
-
r'(?ms)^\*\*VBC \(Verification-Before-Completion\).*?\n',
|
|
32
|
-
# MANDATORY read tables
|
|
33
|
-
r'(?ms)^\*\*ā DO NOT start.*?---\n?',
|
|
34
|
-
r'(?ms)^> š§ \*\*mobile-design.*?\n',
|
|
35
|
-
r'(?ms)^> \*\*STOP.*?\n',
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
# Heading level adjustment (sub-files use H1 ā convert to H2 in merged output)
|
|
39
|
-
def adjust_headings(content, offset=1):
|
|
40
|
-
"""Promote headings by adding # chars"""
|
|
41
|
-
lines = content.split('\n')
|
|
42
|
-
out = []
|
|
43
|
-
for line in lines:
|
|
44
|
-
m = re.match(r'^(#{1,5}) ', line)
|
|
45
|
-
if m:
|
|
46
|
-
level = len(m.group(1))
|
|
47
|
-
new_level = min(level + offset, 6)
|
|
48
|
-
line = '#' * new_level + line[level:]
|
|
49
|
-
out.append(line)
|
|
50
|
-
return '\n'.join(out)
|
|
51
|
-
|
|
52
|
-
def clean_content(content):
|
|
53
|
-
"""Apply strip patterns"""
|
|
54
|
-
for p in STRIP_PATTERNS:
|
|
55
|
-
content = re.sub(p, '', content)
|
|
56
|
-
content = re.sub(r'\n{3,}', '\n\n', content)
|
|
57
|
-
return content.strip()
|
|
58
|
-
|
|
59
|
-
def extract_frontmatter(content):
|
|
60
|
-
"""Return (frontmatter_dict_str, body)"""
|
|
61
|
-
m = re.match(r'^---\n(.*?)\n---\n', content, re.DOTALL)
|
|
62
|
-
if m:
|
|
63
|
-
return m.group(1), content[m.end():]
|
|
64
|
-
return '', content
|
|
65
|
-
|
|
66
|
-
def get_sub_title(content):
|
|
67
|
-
"""Get first H1 from a sub-file"""
|
|
68
|
-
m = re.search(r'^# (.+)', content, re.MULTILINE)
|
|
69
|
-
return m.group(1) if m else None
|
|
70
|
-
|
|
71
|
-
def consolidate(skill_dir):
|
|
72
|
-
skill_name = os.path.basename(skill_dir)
|
|
73
|
-
main_path = os.path.join(skill_dir, 'SKILL.md')
|
|
74
|
-
if not os.path.exists(main_path):
|
|
75
|
-
return False
|
|
76
|
-
|
|
77
|
-
# Find sub-files (non-SKILL.md markdown files)
|
|
78
|
-
sub_files = sorted([
|
|
79
|
-
f for f in os.listdir(skill_dir)
|
|
80
|
-
if f.endswith('.md') and f != 'SKILL.md'
|
|
81
|
-
])
|
|
82
|
-
|
|
83
|
-
if not sub_files:
|
|
84
|
-
return False
|
|
85
|
-
|
|
86
|
-
print(f'\n ā Consolidating: {skill_name} ({len(sub_files)} sub-files)')
|
|
87
|
-
|
|
88
|
-
# Read main SKILL.md
|
|
89
|
-
main_content = open(main_path, 'r', encoding='utf-8', errors='ignore').read()
|
|
90
|
-
frontmatter, main_body = extract_frontmatter(main_content)
|
|
91
|
-
|
|
92
|
-
# Clean & update frontmatter version
|
|
93
|
-
fm_lines = frontmatter.split('\n')
|
|
94
|
-
new_fm = []
|
|
95
|
-
for line in fm_lines:
|
|
96
|
-
if line.startswith('version:'):
|
|
97
|
-
new_fm.append('version: 3.1.0')
|
|
98
|
-
elif line.startswith('last-updated:'):
|
|
99
|
-
new_fm.append('last-updated: 2026-04-06')
|
|
100
|
-
else:
|
|
101
|
-
new_fm.append(line)
|
|
102
|
-
frontmatter = '\n'.join(new_fm)
|
|
103
|
-
|
|
104
|
-
# Clean main body
|
|
105
|
-
main_body = clean_content(main_body)
|
|
106
|
-
|
|
107
|
-
# Remove MANDATORY read table from main body
|
|
108
|
-
# (links like [file.md](file.md) in tables)
|
|
109
|
-
main_body = re.sub(r'\|.*?\.md.*?\|.*?\|.*?\|\n', '', main_body)
|
|
110
|
-
main_body = re.sub(r'^\|[-| ]+\|\n', '', main_body, flags=re.MULTILINE)
|
|
111
|
-
main_body = re.sub(r'\n{3,}', '\n\n', main_body)
|
|
112
|
-
|
|
113
|
-
# Merge sub-files
|
|
114
|
-
merged_sections = []
|
|
115
|
-
for fname in sub_files:
|
|
116
|
-
fpath = os.path.join(skill_dir, fname)
|
|
117
|
-
raw = open(fpath, 'r', encoding='utf-8', errors='ignore').read()
|
|
118
|
-
_, body = extract_frontmatter(raw)
|
|
119
|
-
body = clean_content(body)
|
|
120
|
-
# Adjust headings: H1āH2, H2āH3, etc.
|
|
121
|
-
body = adjust_headings(body, offset=1)
|
|
122
|
-
if body.strip():
|
|
123
|
-
merged_sections.append(body.strip())
|
|
124
|
-
|
|
125
|
-
# Build final output
|
|
126
|
-
combined = f'---\n{frontmatter}\n---\n\n{main_body}'
|
|
127
|
-
if merged_sections:
|
|
128
|
-
combined += '\n\n---\n\n' + '\n\n---\n\n'.join(merged_sections)
|
|
129
|
-
|
|
130
|
-
# Final cleanup
|
|
131
|
-
combined = re.sub(r'\n{3,}', '\n\n', combined)
|
|
132
|
-
combined = combined.strip() + '\n'
|
|
133
|
-
|
|
134
|
-
# Measure savings
|
|
135
|
-
total_sub_bytes = sum(os.path.getsize(os.path.join(skill_dir, f)) for f in sub_files)
|
|
136
|
-
print(f' Sub-files total: {total_sub_bytes//1024}KB')
|
|
137
|
-
|
|
138
|
-
# Write consolidated SKILL.md
|
|
139
|
-
with open(main_path, 'w', encoding='utf-8') as f:
|
|
140
|
-
f.write(combined)
|
|
141
|
-
|
|
142
|
-
new_size = os.path.getsize(main_path)
|
|
143
|
-
print(f' New SKILL.md: {new_size//1024}KB (from {len(main_content)//1024}KB main + {total_sub_bytes//1024}KB subs ā {new_size//1024}KB)')
|
|
144
|
-
|
|
145
|
-
# Delete sub-files
|
|
146
|
-
for fname in sub_files:
|
|
147
|
-
os.remove(os.path.join(skill_dir, fname))
|
|
148
|
-
print(f' Deleted: {fname}')
|
|
149
|
-
|
|
150
|
-
return True
|
|
151
|
-
|
|
152
|
-
def main():
|
|
153
|
-
target = sys.argv[1] if len(sys.argv) > 1 else None
|
|
154
|
-
|
|
155
|
-
total_saved = 0
|
|
156
|
-
processed = 0
|
|
157
|
-
|
|
158
|
-
for skill_name in os.listdir(BASE):
|
|
159
|
-
skill_dir = os.path.join(BASE, skill_name)
|
|
160
|
-
if not os.path.isdir(skill_dir):
|
|
161
|
-
continue
|
|
162
|
-
if target and skill_name != target:
|
|
163
|
-
continue
|
|
164
|
-
if consolidate(skill_dir):
|
|
165
|
-
processed += 1
|
|
166
|
-
|
|
167
|
-
if processed == 0:
|
|
168
|
-
print('No skills with sub-files found (or target not matched).')
|
|
169
|
-
else:
|
|
170
|
-
print(f'\nā
Consolidated {processed} skills.')
|
|
171
|
-
|
|
172
|
-
if __name__ == '__main__':
|
|
173
|
-
main()
|