vibes-plug 1.0.0 → 2.11.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 (183) hide show
  1. package/.claude/rules/vibes-plug-core.md +32 -0
  2. package/.cursor/rules/vibes-plug-core.mdc +51 -0
  3. package/.cursorrules +42 -0
  4. package/AGENTS.md +96 -0
  5. package/BLUEPRINT.md +309 -125
  6. package/CHANGELOG.md +183 -1
  7. package/CLAUDE.md +70 -0
  8. package/LICENSE +1 -1
  9. package/README.md +641 -263
  10. package/index.js +19 -0
  11. package/package.json +61 -25
  12. package/plugin.json +24 -7
  13. package/scripts/generate_swarm_gif.py +295 -0
  14. package/scripts/install.js +201 -0
  15. package/skills/accessibility-testing-expert/SKILL.md +116 -0
  16. package/skills/ai-cost-token-optimizer/SKILL.md +82 -0
  17. package/skills/ai-evals-benchmark-expert/SKILL.md +188 -0
  18. package/skills/ai-llm-integration-expert/SKILL.md +147 -122
  19. package/skills/ai-media-generation-expert/SKILL.md +172 -0
  20. package/skills/ai-prompt-engineering-expert/SKILL.md +84 -0
  21. package/skills/angular-expert/SKILL.md +148 -0
  22. package/skills/api-design-expert/SKILL.md +316 -309
  23. package/skills/api-gateway-proxy-expert/SKILL.md +81 -0
  24. package/skills/app-analyzer-optimizer/SKILL.md +195 -188
  25. package/skills/apple-ecosystem-expert/SKILL.md +145 -0
  26. package/skills/{asisten_ramah → asisten-ramah}/SKILL.md +7 -1
  27. package/skills/astro-framework-expert/SKILL.md +200 -0
  28. package/skills/async-queue-temporal-expert/SKILL.md +240 -0
  29. package/skills/authentication-identity-expert/SKILL.md +279 -45
  30. package/skills/auto-doc-updater/SKILL.md +219 -203
  31. package/skills/autonomous-chaos-monkey/SKILL.md +63 -0
  32. package/skills/autonomous-red-teamer/SKILL.md +203 -0
  33. package/skills/autonomous-tdd-debugger/SKILL.md +71 -0
  34. package/skills/background-jobs-queue-expert/SKILL.md +235 -0
  35. package/skills/biome-linter-formatter-expert/SKILL.md +89 -0
  36. package/skills/blockchain-web3-expert/SKILL.md +115 -0
  37. package/skills/bootstrap-to-modern/SKILL.md +93 -86
  38. package/skills/brainstorming/SKILL.md +381 -353
  39. package/skills/browser-automation-expert/SKILL.md +222 -0
  40. package/skills/bun-runtime-expert/SKILL.md +7 -1
  41. package/skills/chatbot-messaging-expert/SKILL.md +114 -0
  42. package/skills/ci-cd-devops-architect/SKILL.md +81 -45
  43. package/skills/cloud-hosting-expert/SKILL.md +249 -243
  44. package/skills/coderabbit/SKILL.md +197 -191
  45. package/skills/compliance-gdpr-privacy-expert/SKILL.md +85 -0
  46. package/skills/cron-scheduler-expert/SKILL.md +304 -0
  47. package/skills/data-pipeline-etl-expert/SKILL.md +84 -0
  48. package/skills/data-telemetry-expert/SKILL.md +218 -212
  49. package/skills/data-visualization-expert/SKILL.md +154 -0
  50. package/skills/database-migration-versioning-expert/SKILL.md +90 -0
  51. package/skills/database-orm-expert/SKILL.md +303 -293
  52. package/skills/dependency-upgrade-migrator/SKILL.md +301 -0
  53. package/skills/design-system-architect/SKILL.md +278 -242
  54. package/skills/desktop-electron-expert/SKILL.md +128 -0
  55. package/skills/documentation-site-expert/SKILL.md +59 -0
  56. package/skills/doku-mcp-server/SKILL.md +257 -0
  57. package/skills/doku-payment-gateway/SKILL.md +233 -0
  58. package/skills/domain-driven-design-expert/SKILL.md +82 -0
  59. package/skills/e2e-testing-expert/SKILL.md +320 -314
  60. package/skills/ecommerce-expert/SKILL.md +87 -0
  61. package/skills/edge-serverless-db-expert/SKILL.md +99 -0
  62. package/skills/email-notification-expert/SKILL.md +368 -0
  63. package/skills/error-resilience-expert/SKILL.md +486 -0
  64. package/skills/event-driven-architect/SKILL.md +86 -80
  65. package/skills/feature-flag-analytics-expert/SKILL.md +66 -0
  66. package/skills/file-upload-media-expert/SKILL.md +437 -0
  67. package/skills/firebase-security-expert/SKILL.md +7 -1
  68. package/skills/form-validation-expert/SKILL.md +407 -0
  69. package/skills/fullstack-expert/SKILL.md +260 -201
  70. package/skills/fullstack-expert/references/api_design_guide.md +466 -466
  71. package/skills/fullstack-expert/references/multi_language_backend.md +528 -528
  72. package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -253
  73. package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -326
  74. package/skills/gemini-agent-booster/SKILL.md +142 -104
  75. package/skills/geospatial-maps-expert/SKILL.md +80 -0
  76. package/skills/global-a11y-i18n-expert/SKILL.md +86 -80
  77. package/skills/glsl-shader-expert/SKILL.md +107 -0
  78. package/skills/go-programming-expert/SKILL.md +300 -294
  79. package/skills/graph-rag-knowledge-expert/SKILL.md +159 -0
  80. package/skills/graphql-apollo-expert/SKILL.md +114 -0
  81. package/skills/headless-cms-expert/SKILL.md +181 -0
  82. package/skills/hig/SKILL.md +193 -187
  83. package/skills/js-backend-expert/SKILL.md +218 -191
  84. package/skills/legacy-code-translator/SKILL.md +71 -0
  85. package/skills/local-slm-edge-ai-expert/SKILL.md +167 -0
  86. package/skills/logging-error-tracking-expert/SKILL.md +344 -0
  87. package/skills/mcp-client-orchestrator/SKILL.md +76 -0
  88. package/skills/mcp-server-architect/SKILL.md +226 -126
  89. package/skills/micro-frontend-architect/SKILL.md +112 -0
  90. package/skills/mobile-expo-expert/SKILL.md +191 -185
  91. package/skills/mobile-push-notification-expert/SKILL.md +71 -0
  92. package/skills/modern-css-native-expert/SKILL.md +189 -0
  93. package/skills/monday-design-aesthetic/SKILL.md +72 -66
  94. package/skills/monorepo-architect/SKILL.md +232 -226
  95. package/skills/mpa-orchestrator/SKILL.md +120 -101
  96. package/skills/multi-agent-orchestration/SKILL.md +173 -153
  97. package/skills/multiple-entry-points/SKILL.md +91 -55
  98. package/skills/mvc-expert/SKILL.md +237 -231
  99. package/skills/n8n-automation-expert/SKILL.md +89 -0
  100. package/skills/nextjs-app-router-expert/SKILL.md +148 -0
  101. package/skills/openapi-swagger-codegen-expert/SKILL.md +67 -0
  102. package/skills/payment-gateway-expert/SKILL.md +129 -45
  103. package/skills/pdf-document-generation-expert/SKILL.md +91 -0
  104. package/skills/performance-web-vitals/SKILL.md +337 -331
  105. package/skills/post-quantum-crypto-migrator/SKILL.md +57 -0
  106. package/skills/prd-architect/SKILL.md +206 -190
  107. package/skills/proactive-background-watcher/SKILL.md +68 -0
  108. package/skills/production-ready-hardener/PRODUCTION_READINESS_REPORT.md +67 -0
  109. package/skills/production-ready-hardener/SKILL.md +461 -468
  110. package/skills/production-ready-hardener/references/production_checklist.md +161 -161
  111. package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +881 -875
  112. package/skills/project-context-mapper/SKILL.md +85 -0
  113. package/skills/pwa-offline-first-expert/SKILL.md +185 -0
  114. package/skills/python-programming-expert/SKILL.md +407 -270
  115. package/skills/rate-limit-abuse-prevention/SKILL.md +377 -0
  116. package/skills/realtime-collaboration-expert/SKILL.md +99 -45
  117. package/skills/rich-text-editor-expert/SKILL.md +177 -0
  118. package/skills/rust-programming-expert/SKILL.md +240 -234
  119. package/skills/saas-billing/SKILL.md +382 -376
  120. package/skills/saas-multi-tenant/SKILL.md +256 -236
  121. package/skills/saas-mvp-launcher/SKILL.md +30 -1
  122. package/skills/saas-transformer/SKILL.md +499 -445
  123. package/skills/saas-transformer/references/billing_integration_guide.md +401 -401
  124. package/skills/saas-transformer/references/feature_gating_patterns.md +137 -137
  125. package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -121
  126. package/skills/saas-transformer/scripts/saas_transformation_scanner.py +39 -29
  127. package/skills/scalability-clean-code/SKILL.md +234 -228
  128. package/skills/search-engine-expert/SKILL.md +89 -0
  129. package/skills/secure-fuzz-testing/SKILL.md +7 -1
  130. package/skills/self-evolving-memory-graph/SKILL.md +91 -0
  131. package/skills/self-healing-cloud-orchestrator/SKILL.md +57 -0
  132. package/skills/senior-frontend/SKILL.md +85 -105
  133. package/skills/seo/SKILL.md +258 -224
  134. package/skills/session-context-loader/SKILL.md +83 -0
  135. package/skills/session-handoff-resume/SKILL.md +163 -157
  136. package/skills/{skill_baru → skill-baru}/SKILL.md +177 -146
  137. package/skills/solidjs-expert/SKILL.md +80 -0
  138. package/skills/spa-orchestrator/SKILL.md +306 -287
  139. package/skills/sse-websocket-streaming-expert/SKILL.md +93 -0
  140. package/skills/state-management-expert/SKILL.md +277 -271
  141. package/skills/supabase-migration/SKILL.md +47 -1
  142. package/skills/supabase-security-expert/SKILL.md +248 -242
  143. package/skills/svelte-sveltekit-expert/SKILL.md +91 -0
  144. package/skills/svg-animation-motion-expert/SKILL.md +115 -0
  145. package/skills/tailwind-expert/SKILL.md +139 -187
  146. package/skills/tanstack-query-expert/SKILL.md +204 -198
  147. package/skills/tauri-expert/SKILL.md +7 -1
  148. package/skills/token-saver/SKILL.md +118 -110
  149. package/skills/typescript-expert/SKILL.md +329 -278
  150. package/skills/ui-components-expert/SKILL.md +166 -63
  151. package/skills/ui-ux-pro-max/SKILL.md +221 -200
  152. package/skills/vector-db-rag-expert/SKILL.md +208 -0
  153. package/skills/vibe-code-gardener/SKILL.md +180 -172
  154. package/skills/visual-qa-vision-agent/SKILL.md +71 -0
  155. package/skills/voice-ai-realtime-agent/SKILL.md +202 -0
  156. package/skills/vue-frontend-expert/SKILL.md +132 -0
  157. package/skills/wasm-edge-computing-expert/SKILL.md +97 -0
  158. package/skills/web-3d-graphics-expert/SKILL.md +137 -0
  159. package/skills/web-game-engine-expert/SKILL.md +102 -0
  160. package/skills/web-scraper/SKILL.md +98 -146
  161. package/skills/website-design-cloner/SKILL.md +180 -0
  162. package/skills/webxr-ar-vr-expert/SKILL.md +123 -0
  163. package/skills/wordpress-headless-expert/SKILL.md +144 -0
  164. package/skills/zero-to-prod-orchestrator/SKILL.md +231 -180
  165. package/skills/zero-trust-secret-vault/SKILL.md +88 -0
  166. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  167. package/CONTRIBUTING.md +0 -199
  168. package/SECURITY.md +0 -21
  169. package/banner.png +0 -0
  170. package/skills/senior-fullstack/SKILL.md +0 -167
  171. package/skills/senior-fullstack/references/architecture_patterns.md +0 -160
  172. package/skills/senior-fullstack/references/development_workflows.md +0 -222
  173. package/skills/senior-fullstack/references/tech_stack_guide.md +0 -190
  174. package/skills/senior-fullstack/scripts/code_quality_analyzer.py +0 -114
  175. package/skills/senior-fullstack/scripts/fullstack_scaffolder.py +0 -114
  176. package/skills/senior-fullstack/scripts/project_scaffolder.py +0 -114
  177. package/skills/seo-aeo-landing-page-writer/SKILL.md +0 -97
  178. package/skills/seo-geo/SKILL.md +0 -188
  179. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
  180. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-312.pyc +0 -0
  181. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
  182. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-312.pyc +0 -0
  183. package/skills/ui_ux_expert/SKILL.md +0 -114
@@ -1,253 +1,253 @@
1
- #!/usr/bin/env python3
2
- """
3
- API Contract Validator
4
- Validates API contracts (OpenAPI specs) and checks for best practices.
5
- """
6
-
7
- import os
8
- import sys
9
- import json
10
- import argparse
11
- from pathlib import Path
12
- from typing import Dict, List, Optional
13
-
14
-
15
- class ApiContractValidator:
16
- """Validates OpenAPI specs and API route files for best practices."""
17
-
18
- def __init__(self, target_path: str, verbose: bool = False):
19
- self.target_path = Path(target_path)
20
- self.verbose = verbose
21
- self.results: Dict = {
22
- 'status': 'pending',
23
- 'target': str(self.target_path),
24
- 'findings': [],
25
- 'api_routes': [],
26
- 'score': 100,
27
- }
28
-
29
- def run(self) -> Dict:
30
- """Execute the API contract validation."""
31
- print(f"📋 Running API Contract Validator...")
32
- print(f"📁 Target: {self.target_path}")
33
-
34
- try:
35
- self.validate_target()
36
- self.scan_api_routes()
37
- self.check_openapi_spec()
38
- self.check_validation_schemas()
39
- self.check_error_handling()
40
- self.check_authentication()
41
- self.check_rate_limiting()
42
- self.generate_report()
43
-
44
- self.results['status'] = 'success'
45
- print("✅ Validation completed!")
46
- return self.results
47
-
48
- except Exception as e:
49
- print(f"❌ Error: {e}")
50
- sys.exit(1)
51
-
52
- def validate_target(self):
53
- """Validate the target path exists."""
54
- if not self.target_path.exists():
55
- raise ValueError(f"Target path does not exist: {self.target_path}")
56
-
57
- def scan_api_routes(self):
58
- """Scan for API route definitions."""
59
- api_dirs = [
60
- 'app/api', 'src/routes', 'src/api', 'routes',
61
- 'internal/handler', 'src/handlers',
62
- ]
63
- route_files = []
64
-
65
- for api_dir in api_dirs:
66
- dir_path = self.target_path / api_dir
67
- if dir_path.is_dir():
68
- for f in dir_path.rglob('*'):
69
- if f.is_file() and f.suffix in {'.ts', '.tsx', '.js', '.py', '.go', '.rs'}:
70
- route_files.append(str(f.relative_to(self.target_path)))
71
-
72
- self.results['api_routes'] = route_files
73
- if self.verbose:
74
- print(f"✓ Found {len(route_files)} API route files")
75
-
76
- if not route_files:
77
- self._add_finding('info', 'No API routes found in standard directories')
78
-
79
- def check_openapi_spec(self):
80
- """Check for OpenAPI specification file."""
81
- spec_files = ['openapi.yaml', 'openapi.yml', 'openapi.json', 'swagger.yaml', 'swagger.json']
82
- has_spec = any((self.target_path / f).exists() for f in spec_files)
83
-
84
- # Also check in docs/ or api/ directories
85
- for subdir in ['docs', 'api', 'spec']:
86
- if (self.target_path / subdir).is_dir():
87
- has_spec = has_spec or any(
88
- (self.target_path / subdir / f).exists() for f in spec_files
89
- )
90
-
91
- if not has_spec and self.results['api_routes']:
92
- self._add_finding('warning', 'No OpenAPI spec found — consider spec-first API design')
93
- self.results['score'] -= 10
94
-
95
- def check_validation_schemas(self):
96
- """Check for input validation schemas (Zod, Pydantic, etc.)."""
97
- validation_patterns = ['zod', 'pydantic', 'joi', 'yup', 'class-validator']
98
- has_validation = False
99
-
100
- pkg_json = self.target_path / 'package.json'
101
- if pkg_json.exists():
102
- try:
103
- with open(pkg_json) as f:
104
- pkg = json.load(f)
105
- deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
106
- has_validation = any(v in deps for v in validation_patterns)
107
- except (json.JSONDecodeError, IOError):
108
- pass
109
-
110
- # Check Python
111
- pyproject = self.target_path / 'pyproject.toml'
112
- if pyproject.exists():
113
- try:
114
- content = pyproject.read_text()
115
- has_validation = has_validation or 'pydantic' in content
116
- except IOError:
117
- pass
118
-
119
- if not has_validation and self.results['api_routes']:
120
- self._add_finding('warning', 'No input validation library detected (Zod, Pydantic, etc.)')
121
- self.results['score'] -= 15
122
-
123
- def check_error_handling(self):
124
- """Check for structured error handling patterns."""
125
- error_files = []
126
- for pattern in ['**/error*.ts', '**/error*.py', '**/error*.go', '**/error*.rs']:
127
- error_files.extend(self.target_path.glob(pattern))
128
-
129
- if not error_files and self.results['api_routes']:
130
- self._add_finding('info', 'No dedicated error handling module found — consider structured error responses (RFC 7807)')
131
-
132
- def check_authentication(self):
133
- """Check for authentication middleware setup."""
134
- auth_indicators = ['auth', 'jwt', 'clerk', 'nextauth', 'lucia', 'passport']
135
- has_auth = False
136
-
137
- pkg_json = self.target_path / 'package.json'
138
- if pkg_json.exists():
139
- try:
140
- with open(pkg_json) as f:
141
- pkg = json.load(f)
142
- deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
143
- has_auth = any(
144
- any(indicator in dep for indicator in auth_indicators)
145
- for dep in deps
146
- )
147
- except (json.JSONDecodeError, IOError):
148
- pass
149
-
150
- if not has_auth and self.results['api_routes']:
151
- self._add_finding('info', 'No authentication library detected — ensure API endpoints are protected')
152
-
153
- def check_rate_limiting(self):
154
- """Check for rate limiting setup."""
155
- rate_limit_deps = ['rate-limit', 'ratelimit', 'limiter', 'throttle']
156
- has_rate_limit = False
157
-
158
- pkg_json = self.target_path / 'package.json'
159
- if pkg_json.exists():
160
- try:
161
- with open(pkg_json) as f:
162
- pkg = json.load(f)
163
- deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
164
- has_rate_limit = any(
165
- any(rl in dep for rl in rate_limit_deps)
166
- for dep in deps
167
- )
168
- except (json.JSONDecodeError, IOError):
169
- pass
170
-
171
- if not has_rate_limit and self.results['api_routes']:
172
- self._add_finding('warning', 'No rate limiting detected — protect API endpoints from abuse')
173
- self.results['score'] -= 5
174
-
175
- def _add_finding(self, severity: str, message: str):
176
- """Add a finding to the results."""
177
- self.results['findings'].append({
178
- 'severity': severity,
179
- 'message': message,
180
- })
181
- if self.verbose:
182
- icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(severity, '⚪')
183
- print(f" {icon} [{severity.upper()}] {message}")
184
-
185
- def generate_report(self):
186
- """Generate and display the validation report."""
187
- findings = self.results['findings']
188
- critical = len([f for f in findings if f['severity'] == 'critical'])
189
- warnings = len([f for f in findings if f['severity'] == 'warning'])
190
- info = len([f for f in findings if f['severity'] == 'info'])
191
-
192
- score = max(0, self.results['score'])
193
- self.results['score'] = score
194
-
195
- print(f"\n{'='*60}")
196
- print("📋 API CONTRACT VALIDATION REPORT")
197
- print(f"{'='*60}")
198
- print(f"Target: {self.results['target']}")
199
- print(f"Score: {score}/100")
200
- print(f"API Routes: {len(self.results['api_routes'])} files found")
201
- print(f"Findings: {critical} critical, {warnings} warnings, {info} info")
202
- print(f"\nFindings:")
203
- for f in findings:
204
- icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(f['severity'], '⚪')
205
- print(f" {icon} [{f['severity'].upper()}] {f['message']}")
206
- print(f"{'='*60}\n")
207
-
208
-
209
- def main():
210
- """Main entry point."""
211
- parser = argparse.ArgumentParser(
212
- description="API Contract Validator — validates API design best practices"
213
- )
214
- parser.add_argument(
215
- 'target',
216
- help='Target project path to validate'
217
- )
218
- parser.add_argument(
219
- '--verbose', '-v',
220
- action='store_true',
221
- help='Enable verbose output'
222
- )
223
- parser.add_argument(
224
- '--json',
225
- action='store_true',
226
- help='Output results as JSON'
227
- )
228
- parser.add_argument(
229
- '--output', '-o',
230
- help='Output file path'
231
- )
232
-
233
- args = parser.parse_args()
234
-
235
- validator = ApiContractValidator(
236
- args.target,
237
- verbose=args.verbose
238
- )
239
-
240
- results = validator.run()
241
-
242
- if args.json:
243
- output = json.dumps(results, indent=2)
244
- if args.output:
245
- with open(args.output, 'w') as f:
246
- f.write(output)
247
- print(f"Results written to {args.output}")
248
- else:
249
- print(output)
250
-
251
-
252
- if __name__ == '__main__':
253
- main()
1
+ #!/usr/bin/env python3
2
+ """
3
+ API Contract Validator
4
+ Validates API contracts (OpenAPI specs) and checks for best practices.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import json
10
+ import argparse
11
+ from pathlib import Path
12
+ from typing import Dict, List, Optional
13
+
14
+
15
+ class ApiContractValidator:
16
+ """Validates OpenAPI specs and API route files for best practices."""
17
+
18
+ def __init__(self, target_path: str, verbose: bool = False):
19
+ self.target_path = Path(target_path)
20
+ self.verbose = verbose
21
+ self.results: Dict = {
22
+ 'status': 'pending',
23
+ 'target': str(self.target_path),
24
+ 'findings': [],
25
+ 'api_routes': [],
26
+ 'score': 100,
27
+ }
28
+
29
+ def run(self) -> Dict:
30
+ """Execute the API contract validation."""
31
+ print(f"📋 Running API Contract Validator...")
32
+ print(f"📁 Target: {self.target_path}")
33
+
34
+ try:
35
+ self.validate_target()
36
+ self.scan_api_routes()
37
+ self.check_openapi_spec()
38
+ self.check_validation_schemas()
39
+ self.check_error_handling()
40
+ self.check_authentication()
41
+ self.check_rate_limiting()
42
+ self.generate_report()
43
+
44
+ self.results['status'] = 'success'
45
+ print("✅ Validation completed!")
46
+ return self.results
47
+
48
+ except Exception as e:
49
+ print(f"❌ Error: {e}")
50
+ sys.exit(1)
51
+
52
+ def validate_target(self):
53
+ """Validate the target path exists."""
54
+ if not self.target_path.exists():
55
+ raise ValueError(f"Target path does not exist: {self.target_path}")
56
+
57
+ def scan_api_routes(self):
58
+ """Scan for API route definitions."""
59
+ api_dirs = [
60
+ 'app/api', 'src/routes', 'src/api', 'routes',
61
+ 'internal/handler', 'src/handlers',
62
+ ]
63
+ route_files = []
64
+
65
+ for api_dir in api_dirs:
66
+ dir_path = self.target_path / api_dir
67
+ if dir_path.is_dir():
68
+ for f in dir_path.rglob('*'):
69
+ if f.is_file() and f.suffix in {'.ts', '.tsx', '.js', '.py', '.go', '.rs'}:
70
+ route_files.append(str(f.relative_to(self.target_path)))
71
+
72
+ self.results['api_routes'] = route_files
73
+ if self.verbose:
74
+ print(f"✓ Found {len(route_files)} API route files")
75
+
76
+ if not route_files:
77
+ self._add_finding('info', 'No API routes found in standard directories')
78
+
79
+ def check_openapi_spec(self):
80
+ """Check for OpenAPI specification file."""
81
+ spec_files = ['openapi.yaml', 'openapi.yml', 'openapi.json', 'swagger.yaml', 'swagger.json']
82
+ has_spec = any((self.target_path / f).exists() for f in spec_files)
83
+
84
+ # Also check in docs/ or api/ directories
85
+ for subdir in ['docs', 'api', 'spec']:
86
+ if (self.target_path / subdir).is_dir():
87
+ has_spec = has_spec or any(
88
+ (self.target_path / subdir / f).exists() for f in spec_files
89
+ )
90
+
91
+ if not has_spec and self.results['api_routes']:
92
+ self._add_finding('warning', 'No OpenAPI spec found — consider spec-first API design')
93
+ self.results['score'] -= 10
94
+
95
+ def check_validation_schemas(self):
96
+ """Check for input validation schemas (Zod, Pydantic, etc.)."""
97
+ validation_patterns = ['zod', 'pydantic', 'joi', 'yup', 'class-validator']
98
+ has_validation = False
99
+
100
+ pkg_json = self.target_path / 'package.json'
101
+ if pkg_json.exists():
102
+ try:
103
+ with open(pkg_json) as f:
104
+ pkg = json.load(f)
105
+ deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
106
+ has_validation = any(v in deps for v in validation_patterns)
107
+ except (json.JSONDecodeError, IOError):
108
+ pass
109
+
110
+ # Check Python
111
+ pyproject = self.target_path / 'pyproject.toml'
112
+ if pyproject.exists():
113
+ try:
114
+ content = pyproject.read_text()
115
+ has_validation = has_validation or 'pydantic' in content
116
+ except IOError:
117
+ pass
118
+
119
+ if not has_validation and self.results['api_routes']:
120
+ self._add_finding('warning', 'No input validation library detected (Zod, Pydantic, etc.)')
121
+ self.results['score'] -= 15
122
+
123
+ def check_error_handling(self):
124
+ """Check for structured error handling patterns."""
125
+ error_files = []
126
+ for pattern in ['**/error*.ts', '**/error*.py', '**/error*.go', '**/error*.rs']:
127
+ error_files.extend(self.target_path.glob(pattern))
128
+
129
+ if not error_files and self.results['api_routes']:
130
+ self._add_finding('info', 'No dedicated error handling module found — consider structured error responses (RFC 7807)')
131
+
132
+ def check_authentication(self):
133
+ """Check for authentication middleware setup."""
134
+ auth_indicators = ['auth', 'jwt', 'clerk', 'nextauth', 'lucia', 'passport']
135
+ has_auth = False
136
+
137
+ pkg_json = self.target_path / 'package.json'
138
+ if pkg_json.exists():
139
+ try:
140
+ with open(pkg_json) as f:
141
+ pkg = json.load(f)
142
+ deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
143
+ has_auth = any(
144
+ any(indicator in dep for indicator in auth_indicators)
145
+ for dep in deps
146
+ )
147
+ except (json.JSONDecodeError, IOError):
148
+ pass
149
+
150
+ if not has_auth and self.results['api_routes']:
151
+ self._add_finding('info', 'No authentication library detected — ensure API endpoints are protected')
152
+
153
+ def check_rate_limiting(self):
154
+ """Check for rate limiting setup."""
155
+ rate_limit_deps = ['rate-limit', 'ratelimit', 'limiter', 'throttle']
156
+ has_rate_limit = False
157
+
158
+ pkg_json = self.target_path / 'package.json'
159
+ if pkg_json.exists():
160
+ try:
161
+ with open(pkg_json) as f:
162
+ pkg = json.load(f)
163
+ deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
164
+ has_rate_limit = any(
165
+ any(rl in dep for rl in rate_limit_deps)
166
+ for dep in deps
167
+ )
168
+ except (json.JSONDecodeError, IOError):
169
+ pass
170
+
171
+ if not has_rate_limit and self.results['api_routes']:
172
+ self._add_finding('warning', 'No rate limiting detected — protect API endpoints from abuse')
173
+ self.results['score'] -= 5
174
+
175
+ def _add_finding(self, severity: str, message: str):
176
+ """Add a finding to the results."""
177
+ self.results['findings'].append({
178
+ 'severity': severity,
179
+ 'message': message,
180
+ })
181
+ if self.verbose:
182
+ icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(severity, '⚪')
183
+ print(f" {icon} [{severity.upper()}] {message}")
184
+
185
+ def generate_report(self):
186
+ """Generate and display the validation report."""
187
+ findings = self.results['findings']
188
+ critical = len([f for f in findings if f['severity'] == 'critical'])
189
+ warnings = len([f for f in findings if f['severity'] == 'warning'])
190
+ info = len([f for f in findings if f['severity'] == 'info'])
191
+
192
+ score = max(0, self.results['score'])
193
+ self.results['score'] = score
194
+
195
+ print(f"\n{'='*60}")
196
+ print("📋 API CONTRACT VALIDATION REPORT")
197
+ print(f"{'='*60}")
198
+ print(f"Target: {self.results['target']}")
199
+ print(f"Score: {score}/100")
200
+ print(f"API Routes: {len(self.results['api_routes'])} files found")
201
+ print(f"Findings: {critical} critical, {warnings} warnings, {info} info")
202
+ print(f"\nFindings:")
203
+ for f in findings:
204
+ icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(f['severity'], '⚪')
205
+ print(f" {icon} [{f['severity'].upper()}] {f['message']}")
206
+ print(f"{'='*60}\n")
207
+
208
+
209
+ def main():
210
+ """Main entry point."""
211
+ parser = argparse.ArgumentParser(
212
+ description="API Contract Validator — validates API design best practices"
213
+ )
214
+ parser.add_argument(
215
+ 'target',
216
+ help='Target project path to validate'
217
+ )
218
+ parser.add_argument(
219
+ '--verbose', '-v',
220
+ action='store_true',
221
+ help='Enable verbose output'
222
+ )
223
+ parser.add_argument(
224
+ '--json',
225
+ action='store_true',
226
+ help='Output results as JSON'
227
+ )
228
+ parser.add_argument(
229
+ '--output', '-o',
230
+ help='Output file path'
231
+ )
232
+
233
+ args = parser.parse_args()
234
+
235
+ validator = ApiContractValidator(
236
+ args.target,
237
+ verbose=args.verbose
238
+ )
239
+
240
+ results = validator.run()
241
+
242
+ if args.json:
243
+ output = json.dumps(results, indent=2)
244
+ if args.output:
245
+ with open(args.output, 'w') as f:
246
+ f.write(output)
247
+ print(f"Results written to {args.output}")
248
+ else:
249
+ print(output)
250
+
251
+
252
+ if __name__ == '__main__':
253
+ main()