tribunal-kit 4.2.0 → 4.3.0

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.
Files changed (182) hide show
  1. package/.agent/ARCHITECTURE.md +21 -14
  2. package/.agent/agents/swarm-worker-contracts.md +5 -5
  3. package/.agent/agents/ui-ux-auditor.md +292 -0
  4. package/.agent/rules/GEMINI.md +8 -8
  5. package/.agent/scripts/__pycache__/_colors.cpython-311.pyc +0 -0
  6. package/.agent/scripts/__pycache__/_utils.cpython-311.pyc +0 -0
  7. package/.agent/scripts/__pycache__/case_law_manager.cpython-311.pyc +0 -0
  8. package/.agent/scripts/_colors.js +18 -0
  9. package/.agent/scripts/_utils.js +42 -0
  10. package/.agent/scripts/auto_preview.js +197 -0
  11. package/.agent/scripts/bundle_analyzer.js +290 -0
  12. package/.agent/scripts/case_law_manager.js +684 -0
  13. package/.agent/scripts/checklist.js +266 -0
  14. package/.agent/scripts/colors.js +17 -0
  15. package/.agent/scripts/compress_skills.js +141 -0
  16. package/.agent/scripts/consolidate_skills.js +149 -0
  17. package/.agent/scripts/context_broker.js +609 -0
  18. package/.agent/scripts/deep_compress.js +150 -0
  19. package/.agent/scripts/dependency_analyzer.js +272 -0
  20. package/.agent/scripts/inner_loop_validator.js +465 -0
  21. package/.agent/scripts/lint_runner.js +187 -0
  22. package/.agent/scripts/minify_context.js +100 -0
  23. package/.agent/scripts/patch_skills_meta.js +156 -0
  24. package/.agent/scripts/patch_skills_output.js +244 -0
  25. package/.agent/scripts/schema_validator.js +297 -0
  26. package/.agent/scripts/security_scan.js +303 -0
  27. package/.agent/scripts/session_manager.js +276 -0
  28. package/.agent/scripts/skill_evolution.js +644 -0
  29. package/.agent/scripts/skill_integrator.js +313 -0
  30. package/.agent/scripts/strengthen_skills.js +193 -0
  31. package/.agent/scripts/strip_tribunal.js +47 -0
  32. package/.agent/scripts/swarm_dispatcher.js +360 -0
  33. package/.agent/scripts/test_runner.js +193 -0
  34. package/.agent/scripts/utils.js +32 -0
  35. package/.agent/scripts/verify_all.js +256 -0
  36. package/.agent/skills/agent-organizer/SKILL.md +3 -3
  37. package/.agent/skills/agentic-patterns/SKILL.md +3 -3
  38. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +3 -3
  39. package/.agent/skills/api-patterns/SKILL.md +3 -3
  40. package/.agent/skills/api-security-auditor/SKILL.md +3 -3
  41. package/.agent/skills/app-builder/SKILL.md +3 -3
  42. package/.agent/skills/app-builder/templates/SKILL.md +1 -1
  43. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +1 -1
  44. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +1 -1
  45. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +1 -1
  46. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +1 -1
  47. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +1 -1
  48. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +1 -1
  49. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +1 -1
  50. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +1 -1
  51. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
  52. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +1 -1
  53. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +1 -1
  54. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +1 -1
  55. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +1 -1
  56. package/.agent/skills/appflow-wireframe/SKILL.md +3 -3
  57. package/.agent/skills/architecture/SKILL.md +3 -3
  58. package/.agent/skills/authentication-best-practices/SKILL.md +3 -3
  59. package/.agent/skills/bash-linux/SKILL.md +3 -3
  60. package/.agent/skills/behavioral-modes/SKILL.md +3 -3
  61. package/.agent/skills/brainstorming/SKILL.md +3 -3
  62. package/.agent/skills/building-native-ui/SKILL.md +3 -3
  63. package/.agent/skills/clean-code/SKILL.md +3 -3
  64. package/.agent/skills/code-review-checklist/SKILL.md +3 -3
  65. package/.agent/skills/config-validator/SKILL.md +3 -3
  66. package/.agent/skills/csharp-developer/SKILL.md +3 -3
  67. package/.agent/skills/data-validation-schemas/SKILL.md +3 -3
  68. package/.agent/skills/database-design/SKILL.md +3 -3
  69. package/.agent/skills/deployment-procedures/SKILL.md +3 -3
  70. package/.agent/skills/devops-engineer/SKILL.md +3 -3
  71. package/.agent/skills/devops-incident-responder/SKILL.md +3 -3
  72. package/.agent/skills/doc.md +1 -1
  73. package/.agent/skills/documentation-templates/SKILL.md +3 -3
  74. package/.agent/skills/edge-computing/SKILL.md +3 -3
  75. package/.agent/skills/error-resilience/SKILL.md +3 -3
  76. package/.agent/skills/extract-design-system/SKILL.md +3 -3
  77. package/.agent/skills/framer-motion-expert/SKILL.md +3 -4
  78. package/.agent/skills/frontend-design/SKILL.md +3 -3
  79. package/.agent/skills/game-design-expert/SKILL.md +3 -3
  80. package/.agent/skills/game-engineering-expert/SKILL.md +3 -3
  81. package/.agent/skills/geo-fundamentals/SKILL.md +3 -3
  82. package/.agent/skills/github-operations/SKILL.md +3 -3
  83. package/.agent/skills/gsap-core/SKILL.md +0 -2
  84. package/.agent/skills/gsap-frameworks/SKILL.md +0 -2
  85. package/.agent/skills/gsap-performance/SKILL.md +0 -2
  86. package/.agent/skills/gsap-plugins/SKILL.md +0 -2
  87. package/.agent/skills/gsap-react/SKILL.md +0 -2
  88. package/.agent/skills/gsap-scrolltrigger/SKILL.md +0 -2
  89. package/.agent/skills/gsap-timeline/SKILL.md +0 -2
  90. package/.agent/skills/gsap-utils/SKILL.md +0 -2
  91. package/.agent/skills/i18n-localization/SKILL.md +3 -3
  92. package/.agent/skills/intelligent-routing/SKILL.md +3 -3
  93. package/.agent/skills/lint-and-validate/SKILL.md +3 -3
  94. package/.agent/skills/llm-engineering/SKILL.md +3 -3
  95. package/.agent/skills/local-first/SKILL.md +3 -3
  96. package/.agent/skills/mcp-builder/SKILL.md +3 -3
  97. package/.agent/skills/mobile-design/SKILL.md +3 -3
  98. package/.agent/skills/monorepo-management/SKILL.md +3 -3
  99. package/.agent/skills/motion-engineering/SKILL.md +4 -4
  100. package/.agent/skills/nextjs-react-expert/SKILL.md +3 -3
  101. package/.agent/skills/nodejs-best-practices/SKILL.md +3 -3
  102. package/.agent/skills/observability/SKILL.md +3 -3
  103. package/.agent/skills/parallel-agents/SKILL.md +3 -3
  104. package/.agent/skills/performance-profiling/SKILL.md +3 -3
  105. package/.agent/skills/plan-writing/SKILL.md +3 -3
  106. package/.agent/skills/platform-engineer/SKILL.md +3 -3
  107. package/.agent/skills/playwright-best-practices/SKILL.md +3 -3
  108. package/.agent/skills/powershell-windows/SKILL.md +3 -3
  109. package/.agent/skills/project-idioms/SKILL.md +3 -3
  110. package/.agent/skills/python-patterns/SKILL.md +3 -3
  111. package/.agent/skills/python-pro/SKILL.md +3 -3
  112. package/.agent/skills/react-specialist/SKILL.md +3 -3
  113. package/.agent/skills/readme-builder/SKILL.md +3 -3
  114. package/.agent/skills/realtime-patterns/SKILL.md +3 -3
  115. package/.agent/skills/red-team-tactics/SKILL.md +3 -3
  116. package/.agent/skills/rust-pro/SKILL.md +3 -3
  117. package/.agent/skills/seo-fundamentals/SKILL.md +3 -3
  118. package/.agent/skills/server-management/SKILL.md +3 -3
  119. package/.agent/skills/shadcn-ui-expert/SKILL.md +3 -3
  120. package/.agent/skills/skill-creator/SKILL.md +3 -3
  121. package/.agent/skills/sql-pro/SKILL.md +3 -3
  122. package/.agent/skills/supabase-postgres-best-practices/SKILL.md +3 -3
  123. package/.agent/skills/swiftui-expert/SKILL.md +3 -3
  124. package/.agent/skills/systematic-debugging/SKILL.md +3 -3
  125. package/.agent/skills/tailwind-patterns/SKILL.md +3 -3
  126. package/.agent/skills/tdd-workflow/SKILL.md +3 -3
  127. package/.agent/skills/test-result-analyzer/SKILL.md +3 -3
  128. package/.agent/skills/testing-patterns/SKILL.md +3 -3
  129. package/.agent/skills/trend-researcher/SKILL.md +3 -3
  130. package/.agent/skills/typescript-advanced/SKILL.md +3 -3
  131. package/.agent/skills/ui-ux-pro-max/SKILL.md +3 -3
  132. package/.agent/skills/ui-ux-researcher/SKILL.md +3 -3
  133. package/.agent/skills/vue-expert/SKILL.md +3 -3
  134. package/.agent/skills/vulnerability-scanner/SKILL.md +3 -3
  135. package/.agent/skills/web-accessibility-auditor/SKILL.md +3 -3
  136. package/.agent/skills/web-design-guidelines/SKILL.md +3 -3
  137. package/.agent/skills/webapp-testing/SKILL.md +3 -3
  138. package/.agent/skills/whimsy-injector/SKILL.md +3 -3
  139. package/.agent/skills/workflow-optimizer/SKILL.md +3 -3
  140. package/.agent/workflows/audit.md +6 -6
  141. package/.agent/workflows/deploy.md +1 -1
  142. package/.agent/workflows/generate.md +23 -6
  143. package/.agent/workflows/session.md +5 -5
  144. package/.agent/workflows/swarm.md +2 -2
  145. package/README.md +64 -8
  146. package/bin/tribunal-kit.js +277 -45
  147. package/package.json +9 -6
  148. package/scripts/changelog.js +167 -0
  149. package/scripts/sync-version.js +81 -0
  150. package/.agent/scripts/__pycache__/auto_preview.cpython-311.pyc +0 -0
  151. package/.agent/scripts/__pycache__/bundle_analyzer.cpython-311.pyc +0 -0
  152. package/.agent/scripts/__pycache__/checklist.cpython-311.pyc +0 -0
  153. package/.agent/scripts/__pycache__/dependency_analyzer.cpython-311.pyc +0 -0
  154. package/.agent/scripts/__pycache__/security_scan.cpython-311.pyc +0 -0
  155. package/.agent/scripts/__pycache__/session_manager.cpython-311.pyc +0 -0
  156. package/.agent/scripts/__pycache__/skill_integrator.cpython-311.pyc +0 -0
  157. package/.agent/scripts/__pycache__/swarm_dispatcher.cpython-311.pyc +0 -0
  158. package/.agent/scripts/__pycache__/test_runner.cpython-311.pyc +0 -0
  159. package/.agent/scripts/__pycache__/verify_all.cpython-311.pyc +0 -0
  160. package/.agent/scripts/auto_preview.py +0 -180
  161. package/.agent/scripts/bundle_analyzer.py +0 -259
  162. package/.agent/scripts/case_law_manager.py +0 -755
  163. package/.agent/scripts/checklist.py +0 -209
  164. package/.agent/scripts/compress_skills.py +0 -167
  165. package/.agent/scripts/consolidate_skills.py +0 -173
  166. package/.agent/scripts/deep_compress.py +0 -202
  167. package/.agent/scripts/dependency_analyzer.py +0 -247
  168. package/.agent/scripts/lint_runner.py +0 -188
  169. package/.agent/scripts/minify_context.py +0 -80
  170. package/.agent/scripts/patch_skills_meta.py +0 -177
  171. package/.agent/scripts/patch_skills_output.py +0 -285
  172. package/.agent/scripts/schema_validator.py +0 -279
  173. package/.agent/scripts/security_scan.py +0 -224
  174. package/.agent/scripts/session_manager.py +0 -261
  175. package/.agent/scripts/skill_evolution.py +0 -563
  176. package/.agent/scripts/skill_integrator.py +0 -234
  177. package/.agent/scripts/strengthen_skills.py +0 -220
  178. package/.agent/scripts/strip_tribunal.py +0 -41
  179. package/.agent/scripts/swarm_dispatcher.py +0 -350
  180. package/.agent/scripts/test_runner.py +0 -192
  181. package/.agent/scripts/test_swarm_dispatcher.py +0 -163
  182. package/.agent/scripts/verify_all.py +0 -195
@@ -1,80 +0,0 @@
1
- import os
2
- import re
3
-
4
- def minify_markdown(file_path):
5
- with open(file_path, 'r', encoding='utf-8') as f:
6
- content = f.read()
7
-
8
- original_len = len(content)
9
-
10
- # 1. Strip repetitive Output Format templates (These are huge and the LLM already knows how to output the Tribunal format from GEMINI.md)
11
- content = re.sub(r'## Output Format\n\n```[\s\S]*?```\n', '', content)
12
-
13
- # 2. Convert bloated Cross-Workflow Navigation tables to dense YAML lists
14
- # Find tables under Cross-Workflow Navigation
15
- def replace_table_with_list(match):
16
- table_text = match.group(0)
17
- lines = table_text.strip().split('\n')
18
- out = []
19
- for line in lines:
20
- if line.startswith('|') and not line.startswith('|:') and not line.startswith('| After'):
21
- parts = [p.strip() for p in line.split('|') if p.strip()]
22
- if len(parts) >= 2:
23
- out.append(f"- {parts[0]} -> {parts[1]}")
24
- return "\n".join(out) + "\n"
25
-
26
- content = re.sub(r'## Cross-Workflow Navigation\n\n\|.*?\|[\s\S]*?(?=\n## |\Z)', lambda m: '## Cross-Workflow Navigation\n' + replace_table_with_list(m), content)
27
-
28
- # 3. Collapse multiple empty lines into a single one
29
- content = re.sub(r'\n{3,}', '\n\n', content)
30
-
31
- # 4. Remove padding from remaining tables to save space tokens
32
- def unpad_table(match):
33
- line = match.group(0)
34
- # remove spaces around |
35
- line = re.sub(r'\s+\|\s+', '|', line)
36
- line = re.sub(r'\|\s+', '|', line)
37
- line = re.sub(r'\s+\|', '|', line)
38
- return line
39
- content = re.sub(r'^\|.+|$', unpad_table, content, flags=re.MULTILINE)
40
-
41
- # 5. Remove conversational blockquotes > if they don't contain WARNING/NOTE/IMPORTANT
42
- def remove_conversational_quotes(match):
43
- text = match.group(0)
44
- if '⚠️' in text or 'WARNING' in text or 'CRITICAL' in text or '!' in text:
45
- return text
46
- # Otherwise just return the text without quote
47
- return text.replace('> ', '').replace('>', '')
48
- content = re.sub(r'^>.*$', remove_conversational_quotes, content, flags=re.MULTILINE)
49
-
50
- # 6. Dense Examples (convert ❌ Bad: and ✅ Good: blocks to single lines)
51
- content = content.replace('\n❌ Bad:', ' ❌')
52
- content = content.replace('\n✅ Good:', ' ✅')
53
-
54
- with open(file_path, 'w', encoding='utf-8') as f:
55
- f.write(content)
56
-
57
- return original_len, len(content)
58
-
59
- def main():
60
- agent_dir = os.path.join('.agent')
61
- total_original = 0
62
- total_new = 0
63
-
64
- for root, _, files in os.walk(agent_dir):
65
- for file in files:
66
- if file.endswith('.md'):
67
- file_path = os.path.join(root, file)
68
- orig, new = minify_markdown(file_path)
69
- total_original += orig
70
- total_new += new
71
-
72
- saved = total_original - total_new
73
- percent = (saved / total_original * 100) if total_original > 0 else 0
74
- print(f"Minification Complete.")
75
- print(f"Original size: {total_original} bytes")
76
- print(f"New size: {total_new} bytes")
77
- print(f"Saved: {saved} bytes ({percent:.1f}%)")
78
-
79
- if __name__ == '__main__':
80
- main()
@@ -1,177 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- patch_skills_meta.py — Injects version/freshness metadata into SKILL.md frontmatter.
4
-
5
- Adds the following fields to YAML frontmatter if missing:
6
- version: 1.0.0
7
- last-updated: 2026-03-12
8
- applies-to-model: gemini-2.5-pro, claude-3-7-sonnet
9
-
10
- Usage:
11
- python .agent/scripts/patch_skills_meta.py .
12
- python .agent/scripts/patch_skills_meta.py . --dry-run
13
- python .agent/scripts/patch_skills_meta.py . --skill python-pro
14
- """
15
-
16
- import os
17
- import sys
18
- import argparse
19
- import re
20
- from pathlib import Path
21
-
22
- RED = "\033[91m"
23
- GREEN = "\033[92m"
24
- YELLOW = "\033[93m"
25
- BLUE = "\033[94m"
26
- BOLD = "\033[1m"
27
- RESET = "\033[0m"
28
-
29
- META_FIELDS = {
30
- "version": "1.0.0",
31
- "last-updated": "2026-03-12",
32
- "applies-to-model": "gemini-2.5-pro, claude-3-7-sonnet",
33
- }
34
-
35
-
36
- def header(title: str) -> None:
37
- print(f"\n{BOLD}{BLUE}━━━ {title} ━━━{RESET}")
38
-
39
-
40
- def ok(msg: str) -> None:
41
- print(f" {GREEN}✅ {msg}{RESET}")
42
-
43
-
44
- def skip(msg: str) -> None:
45
- print(f" {YELLOW}⏭️ {msg}{RESET}")
46
-
47
-
48
- def warn(msg: str) -> None:
49
- print(f" {YELLOW}⚠️ {msg}{RESET}")
50
-
51
-
52
- def fail(msg: str) -> None:
53
- print(f" {RED}❌ {msg}{RESET}")
54
-
55
-
56
- def patch_frontmatter(content: str) -> tuple[str, list[str]]:
57
- """
58
- Parse the YAML frontmatter block and inject missing meta fields.
59
- Returns (patched_content, list_of_added_fields).
60
- If no frontmatter is found, injects a minimal one.
61
- """
62
- added: list[str] = []
63
-
64
- # Match frontmatter block: starts and ends with ---
65
- fm_pattern = re.compile(r"^---\r?\n(.*?)\r?\n---", re.DOTALL)
66
- match = fm_pattern.match(content)
67
-
68
- if not match:
69
- # No frontmatter — prepend a minimal block
70
- new_fm_lines = ["---"]
71
- for key, value in META_FIELDS.items():
72
- new_fm_lines.append(f"{key}: {value}")
73
- added.append(key)
74
- new_fm_lines.append("---")
75
- new_fm = "\n".join(new_fm_lines)
76
- return new_fm + "\n\n" + content, added
77
-
78
- fm_text = match.group(1)
79
- fm_end = match.end()
80
-
81
- # Parse existing lines preserving order
82
- existing_keys = set()
83
- for line in fm_text.splitlines():
84
- m = re.match(r"^([a-zA-Z0-9_-]+)\s*:", line)
85
- if m:
86
- existing_keys.add(m.group(1))
87
-
88
- # Build new frontmatter
89
- new_fm_lines = fm_text.rstrip().splitlines()
90
- for key, value in META_FIELDS.items():
91
- if key not in existing_keys:
92
- new_fm_lines.append(f"{key}: {value}")
93
- added.append(key)
94
-
95
- if not added:
96
- return content, []
97
-
98
- new_fm_block = "---\n" + "\n".join(new_fm_lines) + "\n---"
99
- patched = new_fm_block + content[fm_end:]
100
- return patched, added
101
-
102
-
103
- def process_skill(skill_path: Path, dry_run: bool) -> str:
104
- """Process a single SKILL.md. Returns 'updated', 'skipped', or 'error'."""
105
- try:
106
- content = skill_path.read_text(encoding="utf-8")
107
- patched, added = patch_frontmatter(content)
108
-
109
- skill_name = skill_path.parent.name
110
-
111
- if not added:
112
- skip(f"{skill_name} — all meta fields present")
113
- return "skipped"
114
-
115
- field_list = ", ".join(added)
116
- if dry_run:
117
- warn(f"[DRY RUN] {skill_name} — would add: {field_list}")
118
- return "updated"
119
-
120
- skill_path.write_text(patched, encoding="utf-8")
121
- ok(f"{skill_name} — added: {field_list}")
122
- return "updated"
123
-
124
- except Exception as e:
125
- fail(f"{skill_path.parent.name} — {e}")
126
- return "error"
127
-
128
-
129
- def main() -> None:
130
- parser = argparse.ArgumentParser(
131
- description="Injects version/freshness metadata into SKILL.md frontmatter"
132
- )
133
- parser.add_argument("path", help="Project root directory")
134
- parser.add_argument("--dry-run", action="store_true", help="Show changes without writing")
135
- parser.add_argument("--skill", help="Only patch a specific skill by name")
136
- args = parser.parse_args()
137
-
138
- project_root = Path(args.path).resolve()
139
- skills_dir = project_root / ".agent" / "skills"
140
-
141
- if not skills_dir.is_dir():
142
- fail(f"Skills directory not found: {skills_dir}")
143
- sys.exit(1)
144
-
145
- print(f"{BOLD}Tribunal — patch_skills_meta.py{RESET}")
146
- if args.dry_run:
147
- print(f" {YELLOW}DRY RUN — no files will be written{RESET}")
148
- print(f"Skills dir: {skills_dir}\n")
149
-
150
- counts = {"updated": 0, "skipped": 0, "error": 0}
151
-
152
- header("Patching Frontmatter")
153
- for skill_dir in sorted(skills_dir.iterdir()):
154
- if not skill_dir.is_dir():
155
- continue
156
- if args.skill and skill_dir.name != args.skill:
157
- continue
158
- skill_md = skill_dir / "SKILL.md"
159
- if not skill_md.exists():
160
- warn(f"{skill_dir.name} — no SKILL.md found")
161
- continue
162
- result = process_skill(skill_md, args.dry_run)
163
- counts[result] += 1
164
-
165
- print(f"\n{BOLD}━━━ Summary ━━━{RESET}")
166
- print(f" {GREEN}✅ Updated: {counts['updated']}{RESET}")
167
- print(f" {YELLOW}⏭️ Skipped: {counts['skipped']}{RESET}")
168
- if counts["error"]:
169
- print(f" {RED}❌ Errors: {counts['error']}{RESET}")
170
- if args.dry_run:
171
- print(f" {YELLOW}(dry-run — nothing written){RESET}")
172
-
173
- sys.exit(1 if counts["error"] > 0 else 0)
174
-
175
-
176
- if __name__ == "__main__":
177
- main()
@@ -1,285 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- patch_skills_output.py — Adds structured Output Format sections to SKILL.md files.
4
-
5
- Inserts a domain-tailored '## Output Format' block before the Tribunal Integration
6
- section (or appends to the end if no Tribunal section is present).
7
-
8
- Skills already containing '## Output Format', '## Output', or '## Report Format'
9
- are skipped automatically.
10
-
11
- Usage:
12
- python .agent/scripts/patch_skills_output.py .
13
- python .agent/scripts/patch_skills_output.py . --dry-run
14
- python .agent/scripts/patch_skills_output.py . --skill python-pro
15
- """
16
-
17
- import os
18
- import sys
19
- import re
20
- import argparse
21
- from pathlib import Path
22
-
23
- RED = "\033[91m"
24
- GREEN = "\033[92m"
25
- YELLOW = "\033[93m"
26
- BLUE = "\033[94m"
27
- BOLD = "\033[1m"
28
- RESET = "\033[0m"
29
-
30
- # ─── Templates ───────────────────────────────────────────────────────────────
31
-
32
- CODE_QUALITY_TEMPLATE = """\
33
- ## Output Format
34
-
35
- When this skill produces or reviews code, structure your output as follows:
36
-
37
- ```
38
- ━━━ {skill_name} Report ━━━━━━━━━━━━━━━━━━━━━━━━
39
- Skill: {skill_name}
40
- Language: [detected language / framework]
41
- Scope: [N files · N functions]
42
- ─────────────────────────────────────────────────
43
- ✅ Passed: [checks that passed, or "All clean"]
44
- ⚠️ Warnings: [non-blocking issues, or "None"]
45
- ❌ Blocked: [blocking issues requiring fix, or "None"]
46
- ─────────────────────────────────────────────────
47
- VBC status: PENDING → VERIFIED
48
- Evidence: [test output / lint pass / compile success]
49
- ```
50
-
51
- **VBC (Verification-Before-Completion) is mandatory.**
52
- Do not mark status as VERIFIED until concrete terminal evidence is provided.
53
-
54
- """
55
-
56
- DECISION_CARD_TEMPLATE = """\
57
- ## Output Format
58
-
59
- When this skill produces a recommendation or design decision, structure your output as:
60
-
61
- ```
62
- ━━━ {skill_name} Recommendation ━━━━━━━━━━━━━━━━
63
- Decision: [what was chosen / proposed]
64
- Rationale: [why — one concise line]
65
- Trade-offs: [what is consciously accepted]
66
- Next action: [concrete next step for the user]
67
- ─────────────────────────────────────────────────
68
- Pre-Flight: ✅ All checks passed
69
- or ❌ [blocking item that must be resolved first]
70
- ```
71
-
72
- """
73
-
74
- GENERIC_TEMPLATE = """\
75
- ## Output Format
76
-
77
- When this skill completes a task, structure your output as:
78
-
79
- ```
80
- ━━━ {skill_name} Output ━━━━━━━━━━━━━━━━━━━━━━━━
81
- Task: [what was performed]
82
- Result: [outcome summary — one line]
83
- ─────────────────────────────────────────────────
84
- Checks: ✅ [N passed] · ⚠️ [N warnings] · ❌ [N blocked]
85
- VBC status: PENDING → VERIFIED
86
- Evidence: [link to terminal output, test result, or file diff]
87
- ```
88
-
89
- """
90
-
91
- # ─── Skill → template routing ────────────────────────────────────────────────
92
-
93
- CODE_GEN_SKILLS = {
94
- "python-pro", "clean-code", "dotnet-core-expert", "rust-pro",
95
- "nextjs-react-expert", "vue-expert", "react-specialist",
96
- "csharp-developer", "nodejs-best-practices", "python-patterns",
97
- "tailwind-patterns", "bash-linux", "powershell-windows",
98
- "llm-engineering", "mcp-builder", "game-development",
99
- "edge-computing", "local-first", "realtime-patterns",
100
- "tdd-workflow", "testing-patterns", "lint-and-validate",
101
- }
102
-
103
- DECISION_SKILLS = {
104
- "api-patterns", "database-design", "architecture", "observability",
105
- "devops-engineer", "platform-engineer", "deployment-procedures",
106
- "server-management", "security-auditor", "vulnerability-scanner",
107
- "red-team-tactics", "performance-profiling", "i18n-localization",
108
- "geo-fundamentals", "seo-fundamentals", "sql-pro",
109
- "brainstorming", "plan-writing", "behavioral-modes",
110
- "app-builder", "intelligent-routing", "mobile-design",
111
- "frontend-design", "ui-ux-pro-max", "ui-ux-researcher",
112
- "web-design-guidelines", "trend-researcher",
113
- }
114
-
115
- # Skills that already have output format sections — SKIP
116
- ALREADY_HAVE_OUTPUT = {
117
- "whimsy-injector", "workflow-optimizer",
118
- }
119
-
120
- # Markers indicating an existing output section
121
- EXISTING_OUTPUT_MARKERS = [
122
- "## Output Format",
123
- "## Output\n",
124
- "## Report Format",
125
- "## Output Card",
126
- "Whimsy Injection Report",
127
- "Workflow Optimization Report",
128
- ]
129
-
130
- # ─── Logic ───────────────────────────────────────────────────────────────────
131
-
132
- def get_template(skill_name: str) -> str:
133
- if skill_name in CODE_GEN_SKILLS:
134
- return CODE_QUALITY_TEMPLATE
135
- if skill_name in DECISION_SKILLS:
136
- return DECISION_CARD_TEMPLATE
137
- return GENERIC_TEMPLATE
138
-
139
-
140
- def has_output_section(content: str) -> bool:
141
- for marker in EXISTING_OUTPUT_MARKERS:
142
- if marker in content:
143
- return True
144
- return False
145
-
146
-
147
- def get_skill_name_from_frontmatter(content: str) -> str | None:
148
- """Extract the 'name:' field from YAML frontmatter."""
149
- match = re.search(r"^name:\s*(.+)$", content, re.MULTILINE)
150
- return match.group(1).strip() if match else None
151
-
152
-
153
- def build_block(template: str, skill_name: str) -> str:
154
- # Capitalise display name
155
- display = skill_name.replace("-", " ").title()
156
- return template.replace("{skill_name}", display)
157
-
158
-
159
- def inject_output_block(content: str, block: str) -> str:
160
- """
161
- Insert block before '## 🏛️ Tribunal Integration' if present,
162
- otherwise append to end of file.
163
- """
164
- tribunal_markers = [
165
- "## 🏛️ Tribunal Integration",
166
- "## Tribunal Integration",
167
- ]
168
- for marker in tribunal_markers:
169
- idx = content.find(marker)
170
- if idx != -1:
171
- return content[:idx] + block + "\n---\n\n" + content[idx:]
172
-
173
- # Append to end with a separator
174
- return content.rstrip() + "\n\n---\n\n" + block
175
-
176
-
177
- def process_skill(skill_dir: Path, dry_run: bool) -> str:
178
- """Returns 'updated', 'skipped', or 'error'."""
179
- skill_name = skill_dir.name
180
- skill_md = skill_dir / "SKILL.md"
181
-
182
- if not skill_md.exists():
183
- return "skipped"
184
-
185
- try:
186
- content = skill_md.read_text(encoding="utf-8")
187
-
188
- if skill_name in ALREADY_HAVE_OUTPUT or has_output_section(content):
189
- skip(f"{skill_name} — output format already present")
190
- return "skipped"
191
-
192
- # Determine display name
193
- display_name = get_skill_name_from_frontmatter(content) or skill_name
194
- template = get_template(skill_name)
195
- block = build_block(template, display_name)
196
- patched = inject_output_block(content, block)
197
-
198
- if dry_run:
199
- template_type = (
200
- "Code Quality" if skill_name in CODE_GEN_SKILLS
201
- else "Decision Card" if skill_name in DECISION_SKILLS
202
- else "Generic"
203
- )
204
- warn(f"[DRY RUN] {skill_name} — would add Output Format ({template_type})")
205
- return "updated"
206
-
207
- skill_md.write_text(patched, encoding="utf-8")
208
- template_type = (
209
- "Code Quality" if skill_name in CODE_GEN_SKILLS
210
- else "Decision Card" if skill_name in DECISION_SKILLS
211
- else "Generic"
212
- )
213
- ok(f"{skill_name} — added Output Format ({template_type})")
214
- return "updated"
215
-
216
- except Exception as e:
217
- fail(f"{skill_name} — {e}")
218
- return "error"
219
-
220
-
221
- def header(title: str) -> None:
222
- print(f"\n{BOLD}{BLUE}━━━ {title} ━━━{RESET}")
223
-
224
-
225
- def ok(msg: str) -> None:
226
- print(f" {GREEN}✅ {msg}{RESET}")
227
-
228
-
229
- def skip(msg: str) -> None:
230
- print(f" {YELLOW}⏭️ {msg}{RESET}")
231
-
232
-
233
- def warn(msg: str) -> None:
234
- print(f" {YELLOW}⚠️ {msg}{RESET}")
235
-
236
-
237
- def fail(msg: str) -> None:
238
- print(f" {RED}❌ {msg}{RESET}")
239
-
240
-
241
- def main() -> None:
242
- parser = argparse.ArgumentParser(
243
- description="Adds Output Format sections to SKILL.md files that are missing them"
244
- )
245
- parser.add_argument("path", help="Project root directory")
246
- parser.add_argument("--dry-run", action="store_true", help="Show changes without writing")
247
- parser.add_argument("--skill", help="Only patch a specific skill by name")
248
- args = parser.parse_args()
249
-
250
- project_root = Path(args.path).resolve()
251
- skills_dir = project_root / ".agent" / "skills"
252
-
253
- if not skills_dir.is_dir():
254
- fail(f"Skills directory not found: {skills_dir}")
255
- sys.exit(1)
256
-
257
- print(f"{BOLD}Tribunal — patch_skills_output.py{RESET}")
258
- if args.dry_run:
259
- print(f" {YELLOW}DRY RUN — no files will be written{RESET}")
260
- print(f"Skills dir: {skills_dir}\n")
261
-
262
- counts: dict[str, int] = {"updated": 0, "skipped": 0, "error": 0}
263
-
264
- header("Patching Output Format Sections")
265
- for skill_dir in sorted(skills_dir.iterdir()):
266
- if not skill_dir.is_dir():
267
- continue
268
- if args.skill and skill_dir.name != args.skill:
269
- continue
270
- result = process_skill(skill_dir, args.dry_run)
271
- counts[result] += 1
272
-
273
- print(f"\n{BOLD}━━━ Summary ━━━{RESET}")
274
- print(f" {GREEN}✅ Updated: {counts['updated']}{RESET}")
275
- print(f" {YELLOW}⏭️ Skipped: {counts['skipped']}{RESET}")
276
- if counts["error"]:
277
- print(f" {RED}❌ Errors: {counts['error']}{RESET}")
278
- if args.dry_run:
279
- print(f" {YELLOW}(dry-run — nothing written){RESET}")
280
-
281
- sys.exit(1 if counts["error"] > 0 else 0)
282
-
283
-
284
- if __name__ == "__main__":
285
- main()