vibes-plug 1.0.0 → 2.5.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 (123) hide show
  1. package/.github/workflows/publish.yml +20 -0
  2. package/AGENTS.md +66 -0
  3. package/BLUEPRINT.md +152 -60
  4. package/CHANGELOG.md +50 -0
  5. package/README.md +346 -194
  6. package/package.json +25 -25
  7. package/plugin.json +1 -1
  8. package/skills/ai-cost-token-optimizer/SKILL.md +52 -0
  9. package/skills/ai-llm-integration-expert/SKILL.md +180 -162
  10. package/skills/api-design-expert/SKILL.md +314 -310
  11. package/skills/app-analyzer-optimizer/SKILL.md +193 -189
  12. package/skills/apple-ecosystem-expert/SKILL.md +142 -0
  13. package/skills/async-queue-temporal-expert/SKILL.md +54 -0
  14. package/skills/authentication-identity-expert/SKILL.md +251 -20
  15. package/skills/auto-doc-updater/SKILL.md +214 -204
  16. package/skills/autonomous-chaos-monkey/SKILL.md +63 -0
  17. package/skills/autonomous-red-teamer/SKILL.md +59 -0
  18. package/skills/autonomous-swarm-director/SKILL.md +69 -0
  19. package/skills/autonomous-tdd-debugger/SKILL.md +65 -0
  20. package/skills/bootstrap-to-modern/SKILL.md +90 -86
  21. package/skills/brainstorming/SKILL.md +373 -353
  22. package/skills/browser-automation-expert/SKILL.md +46 -0
  23. package/skills/ci-cd-devops-architect/SKILL.md +72 -45
  24. package/skills/cloud-hosting-expert/SKILL.md +244 -244
  25. package/skills/coderabbit/SKILL.md +192 -192
  26. package/skills/cron-scheduler-expert/SKILL.md +298 -0
  27. package/skills/data-telemetry-expert/SKILL.md +213 -213
  28. package/skills/database-orm-expert/SKILL.md +294 -294
  29. package/skills/dependency-upgrade-migrator/SKILL.md +295 -0
  30. package/skills/design-system-architect/SKILL.md +27 -10
  31. package/skills/doku-mcp-server/SKILL.md +251 -0
  32. package/skills/doku-payment-gateway/SKILL.md +227 -0
  33. package/skills/e2e-testing-expert/SKILL.md +315 -315
  34. package/skills/edge-serverless-db-expert/SKILL.md +43 -0
  35. package/skills/email-notification-expert/SKILL.md +362 -0
  36. package/skills/error-resilience-expert/SKILL.md +480 -0
  37. package/skills/event-driven-architect/SKILL.md +81 -81
  38. package/skills/feature-flag-analytics-expert/SKILL.md +46 -0
  39. package/skills/file-upload-media-expert/SKILL.md +431 -0
  40. package/skills/form-validation-expert/SKILL.md +401 -0
  41. package/skills/fullstack-expert/SKILL.md +202 -202
  42. package/skills/fullstack-expert/references/api_design_guide.md +466 -466
  43. package/skills/fullstack-expert/references/multi_language_backend.md +528 -528
  44. package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -253
  45. package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -326
  46. package/skills/gemini-agent-booster/SKILL.md +135 -135
  47. package/skills/global-a11y-i18n-expert/SKILL.md +81 -81
  48. package/skills/glsl-shader-expert/SKILL.md +101 -0
  49. package/skills/go-programming-expert/SKILL.md +295 -295
  50. package/skills/graphql-apollo-expert/SKILL.md +108 -0
  51. package/skills/hig/SKILL.md +188 -188
  52. package/skills/hyper-context-synthesizer/SKILL.md +55 -0
  53. package/skills/js-backend-expert/SKILL.md +34 -9
  54. package/skills/legacy-code-translator/SKILL.md +65 -0
  55. package/skills/llm-cost-arbitrage-router/SKILL.md +59 -0
  56. package/skills/logging-error-tracking-expert/SKILL.md +338 -0
  57. package/skills/mcp-client-orchestrator/SKILL.md +70 -0
  58. package/skills/mcp-server-architect/SKILL.md +194 -194
  59. package/skills/micro-frontend-architect/SKILL.md +106 -0
  60. package/skills/mobile-expo-expert/SKILL.md +186 -186
  61. package/skills/mobile-push-notification-expert/SKILL.md +51 -0
  62. package/skills/monday-design-aesthetic/SKILL.md +67 -67
  63. package/skills/monorepo-architect/SKILL.md +227 -227
  64. package/skills/mpa-orchestrator/SKILL.md +101 -101
  65. package/skills/multi-agent-orchestration/SKILL.md +234 -234
  66. package/skills/multiple-entry-points/SKILL.md +55 -55
  67. package/skills/mvc-expert/SKILL.md +231 -231
  68. package/skills/payment-gateway-expert/SKILL.md +45 -45
  69. package/skills/performance-web-vitals/SKILL.md +332 -332
  70. package/skills/post-quantum-crypto-migrator/SKILL.md +57 -0
  71. package/skills/prd-architect/SKILL.md +201 -191
  72. package/skills/proactive-background-watcher/SKILL.md +62 -0
  73. package/skills/production-ready-hardener/PRODUCTION_READINESS_REPORT.md +67 -0
  74. package/skills/production-ready-hardener/SKILL.md +173 -186
  75. package/skills/production-ready-hardener/references/production_checklist.md +161 -161
  76. package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +881 -875
  77. package/skills/project-context-mapper/SKILL.md +79 -0
  78. package/skills/python-programming-expert/SKILL.md +263 -132
  79. package/skills/rate-limit-abuse-prevention/SKILL.md +371 -0
  80. package/skills/realtime-collaboration-expert/SKILL.md +45 -45
  81. package/skills/rust-programming-expert/SKILL.md +235 -235
  82. package/skills/saas-billing/SKILL.md +377 -377
  83. package/skills/saas-multi-tenant/SKILL.md +251 -237
  84. package/skills/saas-mvp-launcher/SKILL.md +10 -0
  85. package/skills/saas-transformer/SKILL.md +187 -144
  86. package/skills/saas-transformer/references/billing_integration_guide.md +401 -401
  87. package/skills/saas-transformer/references/feature_gating_patterns.md +137 -137
  88. package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -121
  89. package/skills/saas-transformer/scripts/saas_transformation_scanner.py +39 -29
  90. package/skills/scalability-clean-code/SKILL.md +229 -229
  91. package/skills/self-evolving-memory-graph/SKILL.md +75 -0
  92. package/skills/self-healing-cloud-orchestrator/SKILL.md +57 -0
  93. package/skills/senior-frontend/SKILL.md +161 -161
  94. package/skills/senior-fullstack/SKILL.md +167 -167
  95. package/skills/seo/SKILL.md +235 -225
  96. package/skills/seo-geo/SKILL.md +188 -188
  97. package/skills/session-context-loader/SKILL.md +77 -0
  98. package/skills/session-handoff-resume/SKILL.md +158 -158
  99. package/skills/skill_baru/SKILL.md +172 -147
  100. package/skills/spa-orchestrator/SKILL.md +288 -288
  101. package/skills/state-management-expert/SKILL.md +272 -272
  102. package/skills/supabase-security-expert/SKILL.md +243 -243
  103. package/skills/tailwind-expert/SKILL.md +188 -188
  104. package/skills/tanstack-query-expert/SKILL.md +199 -199
  105. package/skills/token-saver/SKILL.md +119 -111
  106. package/skills/typescript-expert/SKILL.md +324 -279
  107. package/skills/ui-components-expert/SKILL.md +263 -46
  108. package/skills/ui-ux-pro-max/SKILL.md +202 -201
  109. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
  110. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
  111. package/skills/ui_ux_expert/SKILL.md +17 -6
  112. package/skills/vector-db-rag-expert/SKILL.md +52 -0
  113. package/skills/vibe-code-gardener/SKILL.md +181 -173
  114. package/skills/visual-qa-vision-agent/SKILL.md +65 -0
  115. package/skills/vue-frontend-expert/SKILL.md +126 -0
  116. package/skills/web-3d-graphics-expert/SKILL.md +131 -0
  117. package/skills/web-game-engine-expert/SKILL.md +96 -0
  118. package/skills/web-scraper/SKILL.md +207 -205
  119. package/skills/website-design-cloner/SKILL.md +174 -0
  120. package/skills/webxr-ar-vr-expert/SKILL.md +117 -0
  121. package/skills/zero-to-prod-orchestrator/SKILL.md +206 -180
  122. package/skills/zero-trust-secret-vault/SKILL.md +40 -0
  123. package/vibes-swarm-demo.gif +0 -0
@@ -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()