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,326 +1,326 @@
1
- #!/usr/bin/env python3
2
- """
3
- Fullstack Architecture Analyzer
4
- Analyzes fullstack project structure, detects anti-patterns, and validates architecture health.
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 ArchitectureAnalyzer:
16
- """Analyzes fullstack project architecture for anti-patterns and best practices."""
17
-
18
- # Common fullstack project indicators
19
- FRONTEND_MARKERS = {
20
- 'package.json', 'next.config.js', 'next.config.ts', 'next.config.mjs',
21
- 'vite.config.ts', 'vite.config.js', 'nuxt.config.ts', 'svelte.config.js',
22
- 'astro.config.mjs',
23
- }
24
- BACKEND_MARKERS = {
25
- 'requirements.txt', 'pyproject.toml', 'go.mod', 'Cargo.toml',
26
- 'pom.xml', 'build.gradle', 'Gemfile',
27
- }
28
- INFRA_MARKERS = {
29
- 'Dockerfile', 'docker-compose.yml', 'docker-compose.yaml',
30
- 'terraform.tf', 'main.tf', 'pulumi.yaml', 'serverless.yml',
31
- 'k8s/', 'kubernetes/', 'helm/',
32
- }
33
- CONFIG_MARKERS = {
34
- '.env', '.env.example', '.env.local',
35
- 'tsconfig.json', 'eslint.config.js', '.eslintrc.js',
36
- }
37
-
38
- def __init__(self, target_path: str, verbose: bool = False):
39
- self.target_path = Path(target_path)
40
- self.verbose = verbose
41
- self.results: Dict = {
42
- 'status': 'pending',
43
- 'target': str(self.target_path),
44
- 'stack': {},
45
- 'findings': [],
46
- 'score': 100,
47
- }
48
-
49
- def run(self) -> Dict:
50
- """Execute the full architecture analysis."""
51
- print(f"🏗️ Running Architecture Analyzer...")
52
- print(f"📁 Target: {self.target_path}")
53
-
54
- try:
55
- self.validate_target()
56
- self.detect_stack()
57
- self.check_project_structure()
58
- self.check_security_basics()
59
- self.check_database_patterns()
60
- self.check_testing_setup()
61
- self.check_ci_cd()
62
- self.check_docker_setup()
63
- self.generate_report()
64
-
65
- self.results['status'] = 'success'
66
- print("✅ Analysis completed!")
67
- return self.results
68
-
69
- except Exception as e:
70
- print(f"❌ Error: {e}")
71
- sys.exit(1)
72
-
73
- def validate_target(self):
74
- """Validate the target path exists."""
75
- if not self.target_path.exists():
76
- raise ValueError(f"Target path does not exist: {self.target_path}")
77
- if self.verbose:
78
- print(f"✓ Target validated: {self.target_path}")
79
-
80
- def detect_stack(self):
81
- """Detect the technology stack used in the project."""
82
- stack = {'frontend': [], 'backend': [], 'infrastructure': [], 'database': []}
83
-
84
- # Check for frontend frameworks
85
- if (self.target_path / 'next.config.js').exists() or \
86
- (self.target_path / 'next.config.ts').exists() or \
87
- (self.target_path / 'next.config.mjs').exists():
88
- stack['frontend'].append('Next.js')
89
-
90
- if (self.target_path / 'vite.config.ts').exists() or \
91
- (self.target_path / 'vite.config.js').exists():
92
- stack['frontend'].append('Vite')
93
-
94
- if (self.target_path / 'nuxt.config.ts').exists():
95
- stack['frontend'].append('Nuxt')
96
-
97
- # Check for backend languages
98
- if (self.target_path / 'go.mod').exists():
99
- stack['backend'].append('Go')
100
- if (self.target_path / 'Cargo.toml').exists():
101
- stack['backend'].append('Rust')
102
- if (self.target_path / 'pyproject.toml').exists() or \
103
- (self.target_path / 'requirements.txt').exists():
104
- stack['backend'].append('Python')
105
-
106
- # Check package.json for more details
107
- pkg_json = self.target_path / 'package.json'
108
- if pkg_json.exists():
109
- try:
110
- with open(pkg_json) as f:
111
- pkg = json.load(f)
112
- deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
113
-
114
- if 'drizzle-orm' in deps:
115
- stack['database'].append('Drizzle ORM')
116
- if 'prisma' in deps or '@prisma/client' in deps:
117
- stack['database'].append('Prisma')
118
- if 'hono' in deps:
119
- stack['backend'].append('Hono')
120
- if 'fastify' in deps:
121
- stack['backend'].append('Fastify')
122
- if 'express' in deps:
123
- stack['backend'].append('Express')
124
- except (json.JSONDecodeError, IOError):
125
- pass
126
-
127
- # Check for infrastructure
128
- if (self.target_path / 'Dockerfile').exists():
129
- stack['infrastructure'].append('Docker')
130
- if (self.target_path / 'docker-compose.yml').exists() or \
131
- (self.target_path / 'docker-compose.yaml').exists():
132
- stack['infrastructure'].append('Docker Compose')
133
- if (self.target_path / 'main.tf').exists():
134
- stack['infrastructure'].append('Terraform')
135
-
136
- self.results['stack'] = stack
137
- if self.verbose:
138
- print(f"✓ Stack detected: {stack}")
139
-
140
- def check_project_structure(self):
141
- """Check for proper project structure and organization."""
142
- # Check for src/ or app/ directory
143
- has_src = (self.target_path / 'src').is_dir()
144
- has_app = (self.target_path / 'app').is_dir()
145
- has_lib = (self.target_path / 'lib').is_dir()
146
-
147
- if not has_src and not has_app:
148
- self._add_finding('warning', 'Missing organized source directory (src/ or app/)')
149
-
150
- # Check for proper separation of concerns
151
- if has_src:
152
- src = self.target_path / 'src'
153
- subdirs = [d.name for d in src.iterdir() if d.is_dir()]
154
- expected = {'routes', 'handlers', 'services', 'middleware', 'lib', 'utils', 'db', 'models'}
155
- found = set(subdirs) & expected
156
- if len(found) < 2:
157
- self._add_finding('info', f'Consider organizing src/ with subdirectories: {expected - found}')
158
-
159
- def check_security_basics(self):
160
- """Check for basic security configurations."""
161
- # Check for .env in .gitignore
162
- gitignore = self.target_path / '.gitignore'
163
- if gitignore.exists():
164
- content = gitignore.read_text()
165
- if '.env' not in content:
166
- self._add_finding('critical', '.env is not in .gitignore — secrets may be committed!')
167
- self.results['score'] -= 20
168
- else:
169
- self._add_finding('warning', 'No .gitignore found')
170
- self.results['score'] -= 10
171
-
172
- # Check for hardcoded secrets in common config files
173
- env_file = self.target_path / '.env'
174
- if env_file.exists():
175
- self._add_finding('info', '.env file found — ensure it is not committed to version control')
176
-
177
- # Check for .env.example
178
- env_example = self.target_path / '.env.example'
179
- if not env_example.exists():
180
- self._add_finding('warning', 'No .env.example found — document required environment variables')
181
-
182
- def check_database_patterns(self):
183
- """Check for database best practices."""
184
- # Check for migration files
185
- migration_dirs = ['migrations', 'prisma/migrations', 'drizzle', 'alembic']
186
- has_migrations = any((self.target_path / d).is_dir() for d in migration_dirs)
187
-
188
- if not has_migrations and self.results['stack'].get('database'):
189
- self._add_finding('warning', 'No database migration directory found — use managed migrations')
190
- self.results['score'] -= 10
191
-
192
- def check_testing_setup(self):
193
- """Check for testing configuration."""
194
- test_configs = [
195
- 'vitest.config.ts', 'vitest.config.js',
196
- 'jest.config.ts', 'jest.config.js',
197
- 'playwright.config.ts', 'pytest.ini', 'conftest.py',
198
- ]
199
- has_tests = any((self.target_path / c).exists() for c in test_configs)
200
-
201
- test_dirs = ['__tests__', 'tests', 'test', 'e2e', 'spec']
202
- has_test_dir = any((self.target_path / d).is_dir() for d in test_dirs)
203
-
204
- if not has_tests and not has_test_dir:
205
- self._add_finding('warning', 'No testing setup detected — add unit and integration tests')
206
- self.results['score'] -= 15
207
-
208
- def check_ci_cd(self):
209
- """Check for CI/CD pipeline configuration."""
210
- ci_paths = [
211
- '.github/workflows',
212
- '.gitlab-ci.yml',
213
- '.circleci',
214
- 'Jenkinsfile',
215
- '.drone.yml',
216
- ]
217
- has_ci = any(
218
- (self.target_path / p).exists() or (self.target_path / p).is_dir()
219
- for p in ci_paths
220
- )
221
-
222
- if not has_ci:
223
- self._add_finding('info', 'No CI/CD pipeline detected — consider adding automated checks')
224
-
225
- def check_docker_setup(self):
226
- """Check Docker configuration best practices."""
227
- dockerfile = self.target_path / 'Dockerfile'
228
- if dockerfile.exists():
229
- content = dockerfile.read_text()
230
- if 'FROM' in content:
231
- # Check for multi-stage build
232
- from_count = content.count('FROM ')
233
- if from_count < 2:
234
- self._add_finding('info', 'Consider using multi-stage Docker builds for smaller images')
235
-
236
- # Check for non-root user
237
- if 'USER ' not in content and 'useradd' not in content and 'adduser' not in content:
238
- self._add_finding('warning', 'Dockerfile runs as root — add a non-root USER')
239
- self.results['score'] -= 5
240
-
241
- # Check for HEALTHCHECK
242
- if 'HEALTHCHECK' not in content:
243
- self._add_finding('info', 'Consider adding HEALTHCHECK to Dockerfile')
244
-
245
- def _add_finding(self, severity: str, message: str):
246
- """Add a finding to the results."""
247
- self.results['findings'].append({
248
- 'severity': severity,
249
- 'message': message,
250
- })
251
- if self.verbose:
252
- icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(severity, '⚪')
253
- print(f" {icon} [{severity.upper()}] {message}")
254
-
255
- def generate_report(self):
256
- """Generate and display the analysis report."""
257
- findings = self.results['findings']
258
- critical = len([f for f in findings if f['severity'] == 'critical'])
259
- warnings = len([f for f in findings if f['severity'] == 'warning'])
260
- info = len([f for f in findings if f['severity'] == 'info'])
261
-
262
- score = max(0, self.results['score'])
263
- self.results['score'] = score
264
-
265
- print(f"\n{'='*60}")
266
- print("🏗️ ARCHITECTURE ANALYSIS REPORT")
267
- print(f"{'='*60}")
268
- print(f"Target: {self.results['target']}")
269
- print(f"Score: {score}/100")
270
- print(f"Findings: {critical} critical, {warnings} warnings, {info} info")
271
- print(f"\nStack Detected:")
272
- for layer, techs in self.results['stack'].items():
273
- if techs:
274
- print(f" {layer}: {', '.join(techs)}")
275
- print(f"\nFindings:")
276
- for f in findings:
277
- icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(f['severity'], '⚪')
278
- print(f" {icon} [{f['severity'].upper()}] {f['message']}")
279
- print(f"{'='*60}\n")
280
-
281
-
282
- def main():
283
- """Main entry point."""
284
- parser = argparse.ArgumentParser(
285
- description="Fullstack Architecture Analyzer — detects anti-patterns and validates best practices"
286
- )
287
- parser.add_argument(
288
- 'target',
289
- help='Target project path to analyze'
290
- )
291
- parser.add_argument(
292
- '--verbose', '-v',
293
- action='store_true',
294
- help='Enable verbose output'
295
- )
296
- parser.add_argument(
297
- '--json',
298
- action='store_true',
299
- help='Output results as JSON'
300
- )
301
- parser.add_argument(
302
- '--output', '-o',
303
- help='Output file path'
304
- )
305
-
306
- args = parser.parse_args()
307
-
308
- analyzer = ArchitectureAnalyzer(
309
- args.target,
310
- verbose=args.verbose
311
- )
312
-
313
- results = analyzer.run()
314
-
315
- if args.json:
316
- output = json.dumps(results, indent=2)
317
- if args.output:
318
- with open(args.output, 'w') as f:
319
- f.write(output)
320
- print(f"Results written to {args.output}")
321
- else:
322
- print(output)
323
-
324
-
325
- if __name__ == '__main__':
326
- main()
1
+ #!/usr/bin/env python3
2
+ """
3
+ Fullstack Architecture Analyzer
4
+ Analyzes fullstack project structure, detects anti-patterns, and validates architecture health.
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 ArchitectureAnalyzer:
16
+ """Analyzes fullstack project architecture for anti-patterns and best practices."""
17
+
18
+ # Common fullstack project indicators
19
+ FRONTEND_MARKERS = {
20
+ 'package.json', 'next.config.js', 'next.config.ts', 'next.config.mjs',
21
+ 'vite.config.ts', 'vite.config.js', 'nuxt.config.ts', 'svelte.config.js',
22
+ 'astro.config.mjs',
23
+ }
24
+ BACKEND_MARKERS = {
25
+ 'requirements.txt', 'pyproject.toml', 'go.mod', 'Cargo.toml',
26
+ 'pom.xml', 'build.gradle', 'Gemfile',
27
+ }
28
+ INFRA_MARKERS = {
29
+ 'Dockerfile', 'docker-compose.yml', 'docker-compose.yaml',
30
+ 'terraform.tf', 'main.tf', 'pulumi.yaml', 'serverless.yml',
31
+ 'k8s/', 'kubernetes/', 'helm/',
32
+ }
33
+ CONFIG_MARKERS = {
34
+ '.env', '.env.example', '.env.local',
35
+ 'tsconfig.json', 'eslint.config.js', '.eslintrc.js',
36
+ }
37
+
38
+ def __init__(self, target_path: str, verbose: bool = False):
39
+ self.target_path = Path(target_path)
40
+ self.verbose = verbose
41
+ self.results: Dict = {
42
+ 'status': 'pending',
43
+ 'target': str(self.target_path),
44
+ 'stack': {},
45
+ 'findings': [],
46
+ 'score': 100,
47
+ }
48
+
49
+ def run(self) -> Dict:
50
+ """Execute the full architecture analysis."""
51
+ print(f"🏗️ Running Architecture Analyzer...")
52
+ print(f"📁 Target: {self.target_path}")
53
+
54
+ try:
55
+ self.validate_target()
56
+ self.detect_stack()
57
+ self.check_project_structure()
58
+ self.check_security_basics()
59
+ self.check_database_patterns()
60
+ self.check_testing_setup()
61
+ self.check_ci_cd()
62
+ self.check_docker_setup()
63
+ self.generate_report()
64
+
65
+ self.results['status'] = 'success'
66
+ print("✅ Analysis completed!")
67
+ return self.results
68
+
69
+ except Exception as e:
70
+ print(f"❌ Error: {e}")
71
+ sys.exit(1)
72
+
73
+ def validate_target(self):
74
+ """Validate the target path exists."""
75
+ if not self.target_path.exists():
76
+ raise ValueError(f"Target path does not exist: {self.target_path}")
77
+ if self.verbose:
78
+ print(f"✓ Target validated: {self.target_path}")
79
+
80
+ def detect_stack(self):
81
+ """Detect the technology stack used in the project."""
82
+ stack = {'frontend': [], 'backend': [], 'infrastructure': [], 'database': []}
83
+
84
+ # Check for frontend frameworks
85
+ if (self.target_path / 'next.config.js').exists() or \
86
+ (self.target_path / 'next.config.ts').exists() or \
87
+ (self.target_path / 'next.config.mjs').exists():
88
+ stack['frontend'].append('Next.js')
89
+
90
+ if (self.target_path / 'vite.config.ts').exists() or \
91
+ (self.target_path / 'vite.config.js').exists():
92
+ stack['frontend'].append('Vite')
93
+
94
+ if (self.target_path / 'nuxt.config.ts').exists():
95
+ stack['frontend'].append('Nuxt')
96
+
97
+ # Check for backend languages
98
+ if (self.target_path / 'go.mod').exists():
99
+ stack['backend'].append('Go')
100
+ if (self.target_path / 'Cargo.toml').exists():
101
+ stack['backend'].append('Rust')
102
+ if (self.target_path / 'pyproject.toml').exists() or \
103
+ (self.target_path / 'requirements.txt').exists():
104
+ stack['backend'].append('Python')
105
+
106
+ # Check package.json for more details
107
+ pkg_json = self.target_path / 'package.json'
108
+ if pkg_json.exists():
109
+ try:
110
+ with open(pkg_json) as f:
111
+ pkg = json.load(f)
112
+ deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
113
+
114
+ if 'drizzle-orm' in deps:
115
+ stack['database'].append('Drizzle ORM')
116
+ if 'prisma' in deps or '@prisma/client' in deps:
117
+ stack['database'].append('Prisma')
118
+ if 'hono' in deps:
119
+ stack['backend'].append('Hono')
120
+ if 'fastify' in deps:
121
+ stack['backend'].append('Fastify')
122
+ if 'express' in deps:
123
+ stack['backend'].append('Express')
124
+ except (json.JSONDecodeError, IOError):
125
+ pass
126
+
127
+ # Check for infrastructure
128
+ if (self.target_path / 'Dockerfile').exists():
129
+ stack['infrastructure'].append('Docker')
130
+ if (self.target_path / 'docker-compose.yml').exists() or \
131
+ (self.target_path / 'docker-compose.yaml').exists():
132
+ stack['infrastructure'].append('Docker Compose')
133
+ if (self.target_path / 'main.tf').exists():
134
+ stack['infrastructure'].append('Terraform')
135
+
136
+ self.results['stack'] = stack
137
+ if self.verbose:
138
+ print(f"✓ Stack detected: {stack}")
139
+
140
+ def check_project_structure(self):
141
+ """Check for proper project structure and organization."""
142
+ # Check for src/ or app/ directory
143
+ has_src = (self.target_path / 'src').is_dir()
144
+ has_app = (self.target_path / 'app').is_dir()
145
+ has_lib = (self.target_path / 'lib').is_dir()
146
+
147
+ if not has_src and not has_app:
148
+ self._add_finding('warning', 'Missing organized source directory (src/ or app/)')
149
+
150
+ # Check for proper separation of concerns
151
+ if has_src:
152
+ src = self.target_path / 'src'
153
+ subdirs = [d.name for d in src.iterdir() if d.is_dir()]
154
+ expected = {'routes', 'handlers', 'services', 'middleware', 'lib', 'utils', 'db', 'models'}
155
+ found = set(subdirs) & expected
156
+ if len(found) < 2:
157
+ self._add_finding('info', f'Consider organizing src/ with subdirectories: {expected - found}')
158
+
159
+ def check_security_basics(self):
160
+ """Check for basic security configurations."""
161
+ # Check for .env in .gitignore
162
+ gitignore = self.target_path / '.gitignore'
163
+ if gitignore.exists():
164
+ content = gitignore.read_text()
165
+ if '.env' not in content:
166
+ self._add_finding('critical', '.env is not in .gitignore — secrets may be committed!')
167
+ self.results['score'] -= 20
168
+ else:
169
+ self._add_finding('warning', 'No .gitignore found')
170
+ self.results['score'] -= 10
171
+
172
+ # Check for hardcoded secrets in common config files
173
+ env_file = self.target_path / '.env'
174
+ if env_file.exists():
175
+ self._add_finding('info', '.env file found — ensure it is not committed to version control')
176
+
177
+ # Check for .env.example
178
+ env_example = self.target_path / '.env.example'
179
+ if not env_example.exists():
180
+ self._add_finding('warning', 'No .env.example found — document required environment variables')
181
+
182
+ def check_database_patterns(self):
183
+ """Check for database best practices."""
184
+ # Check for migration files
185
+ migration_dirs = ['migrations', 'prisma/migrations', 'drizzle', 'alembic']
186
+ has_migrations = any((self.target_path / d).is_dir() for d in migration_dirs)
187
+
188
+ if not has_migrations and self.results['stack'].get('database'):
189
+ self._add_finding('warning', 'No database migration directory found — use managed migrations')
190
+ self.results['score'] -= 10
191
+
192
+ def check_testing_setup(self):
193
+ """Check for testing configuration."""
194
+ test_configs = [
195
+ 'vitest.config.ts', 'vitest.config.js',
196
+ 'jest.config.ts', 'jest.config.js',
197
+ 'playwright.config.ts', 'pytest.ini', 'conftest.py',
198
+ ]
199
+ has_tests = any((self.target_path / c).exists() for c in test_configs)
200
+
201
+ test_dirs = ['__tests__', 'tests', 'test', 'e2e', 'spec']
202
+ has_test_dir = any((self.target_path / d).is_dir() for d in test_dirs)
203
+
204
+ if not has_tests and not has_test_dir:
205
+ self._add_finding('warning', 'No testing setup detected — add unit and integration tests')
206
+ self.results['score'] -= 15
207
+
208
+ def check_ci_cd(self):
209
+ """Check for CI/CD pipeline configuration."""
210
+ ci_paths = [
211
+ '.github/workflows',
212
+ '.gitlab-ci.yml',
213
+ '.circleci',
214
+ 'Jenkinsfile',
215
+ '.drone.yml',
216
+ ]
217
+ has_ci = any(
218
+ (self.target_path / p).exists() or (self.target_path / p).is_dir()
219
+ for p in ci_paths
220
+ )
221
+
222
+ if not has_ci:
223
+ self._add_finding('info', 'No CI/CD pipeline detected — consider adding automated checks')
224
+
225
+ def check_docker_setup(self):
226
+ """Check Docker configuration best practices."""
227
+ dockerfile = self.target_path / 'Dockerfile'
228
+ if dockerfile.exists():
229
+ content = dockerfile.read_text()
230
+ if 'FROM' in content:
231
+ # Check for multi-stage build
232
+ from_count = content.count('FROM ')
233
+ if from_count < 2:
234
+ self._add_finding('info', 'Consider using multi-stage Docker builds for smaller images')
235
+
236
+ # Check for non-root user
237
+ if 'USER ' not in content and 'useradd' not in content and 'adduser' not in content:
238
+ self._add_finding('warning', 'Dockerfile runs as root — add a non-root USER')
239
+ self.results['score'] -= 5
240
+
241
+ # Check for HEALTHCHECK
242
+ if 'HEALTHCHECK' not in content:
243
+ self._add_finding('info', 'Consider adding HEALTHCHECK to Dockerfile')
244
+
245
+ def _add_finding(self, severity: str, message: str):
246
+ """Add a finding to the results."""
247
+ self.results['findings'].append({
248
+ 'severity': severity,
249
+ 'message': message,
250
+ })
251
+ if self.verbose:
252
+ icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(severity, '⚪')
253
+ print(f" {icon} [{severity.upper()}] {message}")
254
+
255
+ def generate_report(self):
256
+ """Generate and display the analysis report."""
257
+ findings = self.results['findings']
258
+ critical = len([f for f in findings if f['severity'] == 'critical'])
259
+ warnings = len([f for f in findings if f['severity'] == 'warning'])
260
+ info = len([f for f in findings if f['severity'] == 'info'])
261
+
262
+ score = max(0, self.results['score'])
263
+ self.results['score'] = score
264
+
265
+ print(f"\n{'='*60}")
266
+ print("🏗️ ARCHITECTURE ANALYSIS REPORT")
267
+ print(f"{'='*60}")
268
+ print(f"Target: {self.results['target']}")
269
+ print(f"Score: {score}/100")
270
+ print(f"Findings: {critical} critical, {warnings} warnings, {info} info")
271
+ print(f"\nStack Detected:")
272
+ for layer, techs in self.results['stack'].items():
273
+ if techs:
274
+ print(f" {layer}: {', '.join(techs)}")
275
+ print(f"\nFindings:")
276
+ for f in findings:
277
+ icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(f['severity'], '⚪')
278
+ print(f" {icon} [{f['severity'].upper()}] {f['message']}")
279
+ print(f"{'='*60}\n")
280
+
281
+
282
+ def main():
283
+ """Main entry point."""
284
+ parser = argparse.ArgumentParser(
285
+ description="Fullstack Architecture Analyzer — detects anti-patterns and validates best practices"
286
+ )
287
+ parser.add_argument(
288
+ 'target',
289
+ help='Target project path to analyze'
290
+ )
291
+ parser.add_argument(
292
+ '--verbose', '-v',
293
+ action='store_true',
294
+ help='Enable verbose output'
295
+ )
296
+ parser.add_argument(
297
+ '--json',
298
+ action='store_true',
299
+ help='Output results as JSON'
300
+ )
301
+ parser.add_argument(
302
+ '--output', '-o',
303
+ help='Output file path'
304
+ )
305
+
306
+ args = parser.parse_args()
307
+
308
+ analyzer = ArchitectureAnalyzer(
309
+ args.target,
310
+ verbose=args.verbose
311
+ )
312
+
313
+ results = analyzer.run()
314
+
315
+ if args.json:
316
+ output = json.dumps(results, indent=2)
317
+ if args.output:
318
+ with open(args.output, 'w') as f:
319
+ f.write(output)
320
+ print(f"Results written to {args.output}")
321
+ else:
322
+ print(output)
323
+
324
+
325
+ if __name__ == '__main__':
326
+ main()