tribunal-kit 1.0.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 (190) hide show
  1. package/.agent/.shared/ui-ux-pro-max/README.md +4 -0
  2. package/.agent/ARCHITECTURE.md +75 -0
  3. package/.agent/GEMINI.md +89 -0
  4. package/.agent/agents/backend-specialist.md +178 -0
  5. package/.agent/agents/code-archaeologist.md +119 -0
  6. package/.agent/agents/database-architect.md +164 -0
  7. package/.agent/agents/debugger.md +151 -0
  8. package/.agent/agents/dependency-reviewer.md +55 -0
  9. package/.agent/agents/devops-engineer.md +175 -0
  10. package/.agent/agents/documentation-writer.md +137 -0
  11. package/.agent/agents/explorer-agent.md +142 -0
  12. package/.agent/agents/frontend-reviewer.md +80 -0
  13. package/.agent/agents/frontend-specialist.md +185 -0
  14. package/.agent/agents/game-developer.md +184 -0
  15. package/.agent/agents/logic-reviewer.md +66 -0
  16. package/.agent/agents/mobile-developer.md +152 -0
  17. package/.agent/agents/orchestrator.md +140 -0
  18. package/.agent/agents/penetration-tester.md +131 -0
  19. package/.agent/agents/performance-optimizer.md +139 -0
  20. package/.agent/agents/performance-reviewer.md +72 -0
  21. package/.agent/agents/product-manager.md +108 -0
  22. package/.agent/agents/product-owner.md +99 -0
  23. package/.agent/agents/project-planner.md +142 -0
  24. package/.agent/agents/qa-automation-engineer.md +138 -0
  25. package/.agent/agents/security-auditor.md +170 -0
  26. package/.agent/agents/seo-specialist.md +132 -0
  27. package/.agent/agents/sql-reviewer.md +73 -0
  28. package/.agent/agents/test-coverage-reviewer.md +81 -0
  29. package/.agent/agents/test-engineer.md +139 -0
  30. package/.agent/agents/type-safety-reviewer.md +65 -0
  31. package/.agent/mcp_config.json +40 -0
  32. package/.agent/rules/GEMINI.md +206 -0
  33. package/.agent/scripts/auto_preview.py +180 -0
  34. package/.agent/scripts/checklist.py +209 -0
  35. package/.agent/scripts/session_manager.py +120 -0
  36. package/.agent/scripts/verify_all.py +195 -0
  37. package/.agent/skills/api-patterns/SKILL.md +81 -0
  38. package/.agent/skills/api-patterns/api-style.md +42 -0
  39. package/.agent/skills/api-patterns/auth.md +24 -0
  40. package/.agent/skills/api-patterns/documentation.md +26 -0
  41. package/.agent/skills/api-patterns/graphql.md +41 -0
  42. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  43. package/.agent/skills/api-patterns/response.md +37 -0
  44. package/.agent/skills/api-patterns/rest.md +40 -0
  45. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  46. package/.agent/skills/api-patterns/security-testing.md +122 -0
  47. package/.agent/skills/api-patterns/trpc.md +41 -0
  48. package/.agent/skills/api-patterns/versioning.md +22 -0
  49. package/.agent/skills/app-builder/SKILL.md +75 -0
  50. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  51. package/.agent/skills/app-builder/feature-building.md +53 -0
  52. package/.agent/skills/app-builder/project-detection.md +34 -0
  53. package/.agent/skills/app-builder/scaffolding.md +118 -0
  54. package/.agent/skills/app-builder/tech-stack.md +40 -0
  55. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  56. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  57. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  58. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  59. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  60. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  61. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  62. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  63. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  64. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  65. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  66. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  67. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  68. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  69. package/.agent/skills/architecture/SKILL.md +55 -0
  70. package/.agent/skills/architecture/context-discovery.md +43 -0
  71. package/.agent/skills/architecture/examples.md +94 -0
  72. package/.agent/skills/architecture/pattern-selection.md +68 -0
  73. package/.agent/skills/architecture/patterns-reference.md +50 -0
  74. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  75. package/.agent/skills/bash-linux/SKILL.md +199 -0
  76. package/.agent/skills/behavioral-modes/SKILL.md +242 -0
  77. package/.agent/skills/brainstorming/SKILL.md +163 -0
  78. package/.agent/skills/brainstorming/dynamic-questioning.md +350 -0
  79. package/.agent/skills/clean-code/SKILL.md +201 -0
  80. package/.agent/skills/code-review-checklist/SKILL.md +109 -0
  81. package/.agent/skills/database-design/SKILL.md +52 -0
  82. package/.agent/skills/database-design/database-selection.md +43 -0
  83. package/.agent/skills/database-design/indexing.md +39 -0
  84. package/.agent/skills/database-design/migrations.md +48 -0
  85. package/.agent/skills/database-design/optimization.md +36 -0
  86. package/.agent/skills/database-design/orm-selection.md +30 -0
  87. package/.agent/skills/database-design/schema-design.md +56 -0
  88. package/.agent/skills/database-design/scripts/schema_validator.py +172 -0
  89. package/.agent/skills/deployment-procedures/SKILL.md +241 -0
  90. package/.agent/skills/doc.md +177 -0
  91. package/.agent/skills/documentation-templates/SKILL.md +194 -0
  92. package/.agent/skills/frontend-design/SKILL.md +418 -0
  93. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  94. package/.agent/skills/frontend-design/color-system.md +311 -0
  95. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  96. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  97. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  98. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  99. package/.agent/skills/frontend-design/typography-system.md +345 -0
  100. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  101. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  102. package/.agent/skills/game-development/2d-games/SKILL.md +119 -0
  103. package/.agent/skills/game-development/3d-games/SKILL.md +135 -0
  104. package/.agent/skills/game-development/SKILL.md +167 -0
  105. package/.agent/skills/game-development/game-art/SKILL.md +185 -0
  106. package/.agent/skills/game-development/game-audio/SKILL.md +190 -0
  107. package/.agent/skills/game-development/game-design/SKILL.md +129 -0
  108. package/.agent/skills/game-development/mobile-games/SKILL.md +108 -0
  109. package/.agent/skills/game-development/multiplayer/SKILL.md +132 -0
  110. package/.agent/skills/game-development/pc-games/SKILL.md +144 -0
  111. package/.agent/skills/game-development/vr-ar/SKILL.md +123 -0
  112. package/.agent/skills/game-development/web-games/SKILL.md +150 -0
  113. package/.agent/skills/geo-fundamentals/SKILL.md +156 -0
  114. package/.agent/skills/geo-fundamentals/scripts/geo_checker.py +289 -0
  115. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  116. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  117. package/.agent/skills/intelligent-routing/SKILL.md +335 -0
  118. package/.agent/skills/lint-and-validate/SKILL.md +45 -0
  119. package/.agent/skills/lint-and-validate/scripts/lint_runner.py +184 -0
  120. package/.agent/skills/lint-and-validate/scripts/type_coverage.py +173 -0
  121. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  122. package/.agent/skills/mobile-design/SKILL.md +394 -0
  123. package/.agent/skills/mobile-design/decision-trees.md +516 -0
  124. package/.agent/skills/mobile-design/mobile-backend.md +491 -0
  125. package/.agent/skills/mobile-design/mobile-color-system.md +420 -0
  126. package/.agent/skills/mobile-design/mobile-debugging.md +122 -0
  127. package/.agent/skills/mobile-design/mobile-design-thinking.md +357 -0
  128. package/.agent/skills/mobile-design/mobile-navigation.md +458 -0
  129. package/.agent/skills/mobile-design/mobile-performance.md +767 -0
  130. package/.agent/skills/mobile-design/mobile-testing.md +356 -0
  131. package/.agent/skills/mobile-design/mobile-typography.md +433 -0
  132. package/.agent/skills/mobile-design/platform-android.md +666 -0
  133. package/.agent/skills/mobile-design/platform-ios.md +561 -0
  134. package/.agent/skills/mobile-design/scripts/mobile_audit.py +670 -0
  135. package/.agent/skills/mobile-design/touch-psychology.md +537 -0
  136. package/.agent/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +312 -0
  137. package/.agent/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +240 -0
  138. package/.agent/skills/nextjs-react-expert/3-server-server-side-performance.md +490 -0
  139. package/.agent/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +264 -0
  140. package/.agent/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +581 -0
  141. package/.agent/skills/nextjs-react-expert/6-rendering-rendering-performance.md +432 -0
  142. package/.agent/skills/nextjs-react-expert/7-js-javascript-performance.md +684 -0
  143. package/.agent/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +150 -0
  144. package/.agent/skills/nextjs-react-expert/SKILL.md +286 -0
  145. package/.agent/skills/nextjs-react-expert/scripts/convert_rules.py +222 -0
  146. package/.agent/skills/nextjs-react-expert/scripts/react_performance_checker.py +252 -0
  147. package/.agent/skills/nodejs-best-practices/SKILL.md +333 -0
  148. package/.agent/skills/parallel-agents/SKILL.md +175 -0
  149. package/.agent/skills/performance-profiling/SKILL.md +143 -0
  150. package/.agent/skills/performance-profiling/scripts/lighthouse_audit.py +76 -0
  151. package/.agent/skills/plan-writing/SKILL.md +152 -0
  152. package/.agent/skills/powershell-windows/SKILL.md +167 -0
  153. package/.agent/skills/python-patterns/SKILL.md +441 -0
  154. package/.agent/skills/red-team-tactics/SKILL.md +199 -0
  155. package/.agent/skills/rust-pro/SKILL.md +176 -0
  156. package/.agent/skills/seo-fundamentals/SKILL.md +129 -0
  157. package/.agent/skills/seo-fundamentals/scripts/seo_checker.py +219 -0
  158. package/.agent/skills/server-management/SKILL.md +161 -0
  159. package/.agent/skills/systematic-debugging/SKILL.md +109 -0
  160. package/.agent/skills/tailwind-patterns/SKILL.md +269 -0
  161. package/.agent/skills/tdd-workflow/SKILL.md +149 -0
  162. package/.agent/skills/testing-patterns/SKILL.md +178 -0
  163. package/.agent/skills/testing-patterns/scripts/test_runner.py +219 -0
  164. package/.agent/skills/vulnerability-scanner/SKILL.md +276 -0
  165. package/.agent/skills/vulnerability-scanner/checklists.md +121 -0
  166. package/.agent/skills/vulnerability-scanner/scripts/security_scan.py +458 -0
  167. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  168. package/.agent/skills/webapp-testing/SKILL.md +187 -0
  169. package/.agent/skills/webapp-testing/scripts/playwright_runner.py +173 -0
  170. package/.agent/workflows/brainstorm.md +100 -0
  171. package/.agent/workflows/create.md +86 -0
  172. package/.agent/workflows/debug.md +104 -0
  173. package/.agent/workflows/deploy.md +102 -0
  174. package/.agent/workflows/enhance.md +107 -0
  175. package/.agent/workflows/generate.md +100 -0
  176. package/.agent/workflows/orchestrate.md +102 -0
  177. package/.agent/workflows/plan.md +108 -0
  178. package/.agent/workflows/preview.md +81 -0
  179. package/.agent/workflows/review.md +88 -0
  180. package/.agent/workflows/status.md +69 -0
  181. package/.agent/workflows/test.md +117 -0
  182. package/.agent/workflows/tribunal-backend.md +69 -0
  183. package/.agent/workflows/tribunal-database.md +88 -0
  184. package/.agent/workflows/tribunal-frontend.md +69 -0
  185. package/.agent/workflows/tribunal-full.md +77 -0
  186. package/.agent/workflows/ui-ux-pro-max.md +153 -0
  187. package/LICENSE +21 -0
  188. package/README.md +136 -0
  189. package/bin/tribunal-kit.js +289 -0
  190. package/package.json +34 -0
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ auto_preview.py — Start, stop, or check a local development server.
4
+
5
+ Usage:
6
+ python .agent/scripts/auto_preview.py start
7
+ python .agent/scripts/auto_preview.py stop
8
+ python .agent/scripts/auto_preview.py status
9
+ python .agent/scripts/auto_preview.py restart
10
+ """
11
+
12
+ import os
13
+ import sys
14
+ import json
15
+ import time
16
+ import signal
17
+ import socket
18
+ import subprocess
19
+ from pathlib import Path
20
+
21
+ PID_FILE = ".preview.pid"
22
+ DEFAULT_PORT = 3000
23
+ TIMEOUT_SECONDS = 30
24
+
25
+ GREEN = "\033[92m"
26
+ RED = "\033[91m"
27
+ YELLOW = "\033[93m"
28
+ BOLD = "\033[1m"
29
+ RESET = "\033[0m"
30
+
31
+
32
+ def find_start_command() -> tuple[list[str], bool]:
33
+ """
34
+ Read package.json for a dev/start script.
35
+ Returns (command, found) — found=False if no package.json or no scripts.
36
+ """
37
+ pkg_path = Path("package.json")
38
+ if not pkg_path.exists():
39
+ return [], False
40
+
41
+ try:
42
+ with open(pkg_path) as f:
43
+ pkg = json.load(f)
44
+ scripts = pkg.get("scripts", {})
45
+ if "dev" in scripts:
46
+ return ["npm", "run", "dev"], True
47
+ elif "start" in scripts:
48
+ return ["npm", "run", "start"], True
49
+ else:
50
+ return [], False
51
+ except (json.JSONDecodeError, IOError):
52
+ return [], False
53
+
54
+
55
+ def get_port_from_env() -> int:
56
+ env_path = Path(".env")
57
+ if env_path.exists():
58
+ try:
59
+ with open(env_path) as f:
60
+ for line in f:
61
+ if line.startswith("PORT="):
62
+ return int(line.split("=")[1].strip())
63
+ except (ValueError, IOError):
64
+ pass
65
+ return DEFAULT_PORT
66
+
67
+
68
+ def is_port_open(port: int) -> bool:
69
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
70
+ s.settimeout(1)
71
+ return s.connect_ex(("localhost", port)) == 0
72
+
73
+
74
+ def read_pid() -> int | None:
75
+ pid_file = Path(PID_FILE)
76
+ if pid_file.exists():
77
+ try:
78
+ return int(pid_file.read_text().strip())
79
+ except (ValueError, IOError):
80
+ pass
81
+ return None
82
+
83
+
84
+ def write_pid(pid: int) -> None:
85
+ Path(PID_FILE).write_text(str(pid))
86
+
87
+
88
+ def clear_pid() -> None:
89
+ pid_file = Path(PID_FILE)
90
+ if pid_file.exists():
91
+ pid_file.unlink()
92
+
93
+
94
+ def start_server() -> None:
95
+ port = get_port_from_env()
96
+
97
+ if is_port_open(port):
98
+ print(f"{YELLOW}⚠️ Port {port} is already in use.{RESET}")
99
+ pid = read_pid()
100
+ if pid:
101
+ print(f" Known PID: {pid}")
102
+ return
103
+
104
+ cmd, found = find_start_command()
105
+ if not found:
106
+ print(f"{RED}❌ No dev/start script found.{RESET}")
107
+ print(f" This project has no package.json, or its package.json has no 'dev' or 'start' script.")
108
+ print(f" Add a script to package.json, or start your server manually.")
109
+ return
110
+
111
+ print(f"{BOLD}Starting: {' '.join(cmd)}{RESET}")
112
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
113
+ write_pid(proc.pid)
114
+
115
+ print(f"Waiting for port {port}…", end="", flush=True)
116
+ for _ in range(TIMEOUT_SECONDS):
117
+ if is_port_open(port):
118
+ print()
119
+ print(f"\n{GREEN}✅ Server started{RESET}")
120
+ print(f" URL: http://localhost:{port}")
121
+ print(f" PID: {proc.pid}")
122
+ print(f" Command: {' '.join(cmd)}")
123
+ print(f"\nStop with: python .agent/scripts/auto_preview.py stop")
124
+ return
125
+ print(".", end="", flush=True)
126
+ time.sleep(1)
127
+
128
+ print()
129
+ print(f"{RED}❌ Server did not start within {TIMEOUT_SECONDS}s{RESET}")
130
+ proc.terminate()
131
+ clear_pid()
132
+
133
+
134
+ def stop_server() -> None:
135
+ pid = read_pid()
136
+ if not pid:
137
+ print(f"{YELLOW}⚠️ No stored server PID found{RESET}")
138
+ return
139
+ try:
140
+ os.kill(pid, signal.SIGTERM)
141
+ time.sleep(1)
142
+ print(f"{GREEN}✅ Server stopped (PID {pid}){RESET}")
143
+ except ProcessLookupError:
144
+ print(f"{YELLOW}Process {pid} was not running{RESET}")
145
+ finally:
146
+ clear_pid()
147
+
148
+
149
+ def show_status() -> None:
150
+ port = get_port_from_env()
151
+ pid = read_pid()
152
+ if is_port_open(port):
153
+ print(f"{GREEN}🟢 Running — http://localhost:{port}{RESET}")
154
+ if pid:
155
+ print(f" PID: {pid}")
156
+ else:
157
+ print(f"{RED}🔴 Not running on port {port}{RESET}")
158
+
159
+
160
+ def main() -> None:
161
+ actions = {"start", "stop", "status", "restart"}
162
+ if len(sys.argv) < 2 or sys.argv[1] not in actions:
163
+ print(f"Usage: auto_preview.py [start|stop|status|restart]")
164
+ sys.exit(1)
165
+
166
+ action = sys.argv[1]
167
+ if action == "start":
168
+ start_server()
169
+ elif action == "stop":
170
+ stop_server()
171
+ elif action == "status":
172
+ show_status()
173
+ elif action == "restart":
174
+ stop_server()
175
+ time.sleep(1)
176
+ start_server()
177
+
178
+
179
+ if __name__ == "__main__":
180
+ main()
@@ -0,0 +1,209 @@
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()
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ session_manager.py — Agent session state tracking for multi-conversation work.
4
+
5
+ Usage:
6
+ python .agent/scripts/session_manager.py save "working on auth"
7
+ python .agent/scripts/session_manager.py load
8
+ python .agent/scripts/session_manager.py show
9
+ python .agent/scripts/session_manager.py clear
10
+ """
11
+
12
+ import os
13
+ import sys
14
+ import json
15
+ from pathlib import Path
16
+ from datetime import datetime
17
+
18
+ STATE_FILE = ".agent_session.json"
19
+
20
+ GREEN = "\033[92m"
21
+ YELLOW = "\033[93m"
22
+ BLUE = "\033[94m"
23
+ RED = "\033[91m"
24
+ BOLD = "\033[1m"
25
+ RESET = "\033[0m"
26
+
27
+ VALID_COMMANDS = {"save", "load", "show", "clear"}
28
+
29
+
30
+ def load_state() -> dict:
31
+ path = Path(STATE_FILE)
32
+ if not path.exists():
33
+ return {}
34
+ try:
35
+ with open(path) as f:
36
+ return json.load(f)
37
+ except (json.JSONDecodeError, IOError):
38
+ return {}
39
+
40
+
41
+ def save_state(state: dict) -> None:
42
+ with open(STATE_FILE, "w") as f:
43
+ json.dump(state, f, indent=2)
44
+
45
+
46
+ def cmd_save(note: str) -> None:
47
+ state = load_state()
48
+ entry = {
49
+ "timestamp": datetime.now().isoformat(),
50
+ "note": note,
51
+ "session": len(state.get("history", [])) + 1,
52
+ }
53
+ state.setdefault("history", []).append(entry)
54
+ state["current"] = entry
55
+ save_state(state)
56
+ print(f"{GREEN}✅ Session saved:{RESET} {note}")
57
+ print(f" Time: {entry['timestamp']}")
58
+ print(f" Session: #{entry['session']}")
59
+
60
+
61
+ def cmd_load() -> None:
62
+ state = load_state()
63
+ current = state.get("current")
64
+ if not current:
65
+ print(f"{YELLOW}No active session — use 'save' first.{RESET}")
66
+ return
67
+ print(f"{BOLD}Current session:{RESET}")
68
+ print(f" Session: #{current['session']}")
69
+ print(f" Time: {current['timestamp']}")
70
+ print(f" Note: {current['note']}")
71
+
72
+
73
+ def cmd_show() -> None:
74
+ state = load_state()
75
+ history = state.get("history", [])
76
+ if not history:
77
+ print(f"{YELLOW}No session history.{RESET}")
78
+ return
79
+ print(f"{BOLD}Session History ({len(history)} total):{RESET}")
80
+ for entry in reversed(history[-10:]):
81
+ print(f"\n {BLUE}#{entry['session']}{RESET} — {entry['timestamp'][:16]}")
82
+ print(f" {entry['note']}")
83
+
84
+
85
+ def cmd_clear() -> None:
86
+ path = Path(STATE_FILE)
87
+ if path.exists():
88
+ path.unlink()
89
+ print(f"{GREEN}✅ Session state cleared.{RESET}")
90
+ else:
91
+ print(f"{YELLOW}No session file found — nothing to clear.{RESET}")
92
+
93
+
94
+ def main() -> None:
95
+ if len(sys.argv) < 2:
96
+ print(f"Usage: session_manager.py [save <note>|load|show|clear]")
97
+ sys.exit(1)
98
+
99
+ cmd = sys.argv[1].lower()
100
+
101
+ if cmd not in VALID_COMMANDS:
102
+ print(f"{RED}Unknown command: '{cmd}'{RESET}")
103
+ print(f"Valid commands: {', '.join(sorted(VALID_COMMANDS))}")
104
+ sys.exit(1)
105
+
106
+ if cmd == "save":
107
+ note = " ".join(sys.argv[2:]).strip()
108
+ if not note:
109
+ note = f"session {datetime.now().strftime('%Y-%m-%d %H:%M')}"
110
+ cmd_save(note)
111
+ elif cmd == "load":
112
+ cmd_load()
113
+ elif cmd == "show":
114
+ cmd_show()
115
+ elif cmd == "clear":
116
+ cmd_clear()
117
+
118
+
119
+ if __name__ == "__main__":
120
+ main()
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ verify_all.py — Full pre-deploy validation suite for the Tribunal Agent Kit.
4
+
5
+ Runs comprehensive checks before any production deployment.
6
+
7
+ Usage:
8
+ python .agent/scripts/verify_all.py
9
+ python .agent/scripts/verify_all.py --skip build,deps
10
+ """
11
+
12
+ import os
13
+ import sys
14
+ import subprocess
15
+ import argparse
16
+ from pathlib import Path
17
+
18
+ RED = "\033[91m"
19
+ GREEN = "\033[92m"
20
+ YELLOW = "\033[93m"
21
+ BLUE = "\033[94m"
22
+ BOLD = "\033[1m"
23
+ RESET = "\033[0m"
24
+
25
+ RESULTS: list[tuple[str, bool, str]] = []
26
+
27
+
28
+ def section(title: str) -> None:
29
+ print(f"\n{BOLD}{BLUE}━━━ {title} ━━━{RESET}")
30
+
31
+
32
+ def ok(label: str, note: str = "") -> None:
33
+ msg = f"{GREEN}✅ {label}{RESET}" + (f" {YELLOW}({note}){RESET}" if note else "")
34
+ print(f" {msg}")
35
+ RESULTS.append((label, True, note))
36
+
37
+
38
+ def fail(label: str, note: str = "") -> None:
39
+ note_str = f"\n {note}" if note else ""
40
+ print(f" {RED}❌ {label}{RESET}{note_str}")
41
+ RESULTS.append((label, False, note))
42
+
43
+
44
+ def skip(label: str, reason: str) -> None:
45
+ print(f" {YELLOW}⏭️ {label} — {reason}{RESET}")
46
+ RESULTS.append((label, True, f"skipped: {reason}"))
47
+
48
+
49
+ def run(label: str, cmd: list[str], cwd: str) -> bool:
50
+ try:
51
+ result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=120)
52
+ if result.returncode == 0:
53
+ ok(label)
54
+ return True
55
+ output = (result.stdout + result.stderr).strip()
56
+ fail(label, output[:500] if output else "non-zero exit code")
57
+ return False
58
+ except FileNotFoundError:
59
+ skip(label, "tool not installed — skipping")
60
+ return True
61
+ except subprocess.TimeoutExpired:
62
+ fail(label, "timed out after 120s")
63
+ return False
64
+
65
+
66
+ def scan_secrets(cwd: str) -> bool:
67
+ """Scan source files for obviously hardcoded credentials."""
68
+ patterns = ["password=", "secret=", "api_key=", "private_key=", "auth_token="]
69
+ found = []
70
+ for root, dirs, files in os.walk(cwd):
71
+ dirs[:] = [d for d in dirs if d not in {"node_modules", ".git", "dist", "__pycache__", ".agent"}]
72
+ for fname in files:
73
+ if not fname.endswith((".ts", ".js", ".tsx", ".jsx", ".py")):
74
+ continue
75
+ fpath = os.path.join(root, fname)
76
+ try:
77
+ with open(fpath, encoding="utf-8", errors="ignore") as f:
78
+ for i, line in enumerate(f, 1):
79
+ low = line.lower().strip()
80
+ if any(p in low for p in patterns) and not low.startswith("#") and "=" in low:
81
+ rel = os.path.relpath(fpath, cwd)
82
+ found.append(f"{rel}:{i}")
83
+ except (IOError, PermissionError):
84
+ pass
85
+ if found:
86
+ fail("Secret scan", "\n ".join(found[:5]))
87
+ return False
88
+ ok("Secret scan — no hardcoded credentials found")
89
+ return True
90
+
91
+
92
+ def has_npm(cwd: str) -> bool:
93
+ """Check if there's a package.json to run npm commands against."""
94
+ return Path(cwd, "package.json").exists()
95
+
96
+
97
+ def verify_all(cwd: str, skipped: list[str]) -> int:
98
+ failures = 0
99
+
100
+ section("1 — Secret Scan")
101
+ if "secrets" not in skipped:
102
+ if not scan_secrets(cwd):
103
+ failures += 1
104
+ else:
105
+ skip("Secret scan", "skipped by flag")
106
+
107
+ section("2 — TypeScript")
108
+ if "typescript" not in skipped:
109
+ if has_npm(cwd):
110
+ if not run("tsc --noEmit", ["npx", "tsc", "--noEmit"], cwd):
111
+ failures += 1
112
+ else:
113
+ skip("TypeScript", "no package.json found in project")
114
+ else:
115
+ skip("TypeScript", "skipped by flag")
116
+
117
+ section("3 — ESLint")
118
+ if "lint" not in skipped:
119
+ if has_npm(cwd):
120
+ if not run("ESLint", ["npx", "eslint", ".", "--max-warnings=0"], cwd):
121
+ failures += 1
122
+ else:
123
+ skip("ESLint", "no package.json found in project")
124
+ else:
125
+ skip("ESLint", "skipped by flag")
126
+
127
+ section("4 — Unit Tests")
128
+ if "tests" not in skipped:
129
+ if has_npm(cwd):
130
+ if not run("Test suite", ["npm", "test", "--", "--passWithNoTests"], cwd):
131
+ failures += 1
132
+ else:
133
+ skip("Tests", "no package.json found in project")
134
+ else:
135
+ skip("Tests", "skipped by flag")
136
+
137
+ section("5 — Build")
138
+ if "build" not in skipped:
139
+ if has_npm(cwd):
140
+ if not run("npm run build", ["npm", "run", "build"], cwd):
141
+ failures += 1
142
+ else:
143
+ skip("Build", "no package.json found in project")
144
+ else:
145
+ skip("Build", "skipped by flag")
146
+
147
+ section("6 — Dependency Audit")
148
+ if "deps" not in skipped:
149
+ if has_npm(cwd):
150
+ if not run("npm audit", ["npm", "audit", "--audit-level=high"], cwd):
151
+ failures += 1
152
+ else:
153
+ skip("Dependency audit", "no package.json found in project")
154
+ else:
155
+ skip("Dependency audit", "skipped by flag")
156
+
157
+ print(f"\n{BOLD}━━━ Summary ━━━{RESET}")
158
+ for label, passed, note in RESULTS:
159
+ status = f"{GREEN}✅{RESET}" if passed else f"{RED}❌{RESET}"
160
+ note_str = f" {YELLOW}({note}){RESET}" if not passed and note else ""
161
+ print(f" {status} {label}{note_str}")
162
+
163
+ print()
164
+ if failures == 0:
165
+ print(f"{GREEN}{BOLD}All checks passed — safe to deploy.{RESET}")
166
+ else:
167
+ print(f"{RED}{BOLD}{failures} check(s) failed — fix before deploying.{RESET}")
168
+
169
+ return failures
170
+
171
+
172
+ def main() -> None:
173
+ parser = argparse.ArgumentParser(
174
+ description="Tribunal pre-deploy validation suite",
175
+ usage="%(prog)s [--skip CHECKS]"
176
+ )
177
+ parser.add_argument(
178
+ "--skip",
179
+ default="",
180
+ help="Comma-separated checks to skip: secrets,typescript,lint,tests,build,deps"
181
+ )
182
+ args = parser.parse_args()
183
+
184
+ cwd = os.getcwd()
185
+ skipped = [s.strip().lower() for s in args.skip.split(",") if s.strip()]
186
+
187
+ print(f"{BOLD}Tribunal — verify_all.py{RESET}")
188
+ print(f"Project: {cwd}\n")
189
+
190
+ failures = verify_all(cwd, skipped)
191
+ sys.exit(1 if failures > 0 else 0)
192
+
193
+
194
+ if __name__ == "__main__":
195
+ main()