vaspera 2.10.0 → 2.10.1

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 (173) hide show
  1. package/dist/__tests__/scanners/ai-code/ai-detector.test.d.ts +2 -0
  2. package/dist/__tests__/scanners/ai-code/ai-detector.test.d.ts.map +1 -0
  3. package/dist/__tests__/scanners/ai-code/ai-detector.test.js +188 -0
  4. package/dist/__tests__/scanners/ai-code/ai-detector.test.js.map +1 -0
  5. package/dist/__tests__/scanners/ai-code/confidence-scorer.test.d.ts +2 -0
  6. package/dist/__tests__/scanners/ai-code/confidence-scorer.test.d.ts.map +1 -0
  7. package/dist/__tests__/scanners/ai-code/confidence-scorer.test.js +363 -0
  8. package/dist/__tests__/scanners/ai-code/confidence-scorer.test.js.map +1 -0
  9. package/dist/__tests__/scanners/ai-code/hallucination-checker.test.d.ts +2 -0
  10. package/dist/__tests__/scanners/ai-code/hallucination-checker.test.d.ts.map +1 -0
  11. package/dist/__tests__/scanners/ai-code/hallucination-checker.test.js +226 -0
  12. package/dist/__tests__/scanners/ai-code/hallucination-checker.test.js.map +1 -0
  13. package/dist/__tests__/scanners/ai-code/index.test.d.ts +2 -0
  14. package/dist/__tests__/scanners/ai-code/index.test.d.ts.map +1 -0
  15. package/dist/__tests__/scanners/ai-code/index.test.js +214 -0
  16. package/dist/__tests__/scanners/ai-code/index.test.js.map +1 -0
  17. package/dist/__tests__/scanners/deploy/health-checker.test.d.ts +2 -0
  18. package/dist/__tests__/scanners/deploy/health-checker.test.d.ts.map +1 -0
  19. package/dist/__tests__/scanners/deploy/health-checker.test.js +67 -0
  20. package/dist/__tests__/scanners/deploy/health-checker.test.js.map +1 -0
  21. package/dist/__tests__/scanners/deploy/index.test.d.ts +2 -0
  22. package/dist/__tests__/scanners/deploy/index.test.d.ts.map +1 -0
  23. package/dist/__tests__/scanners/deploy/index.test.js +84 -0
  24. package/dist/__tests__/scanners/deploy/index.test.js.map +1 -0
  25. package/dist/__tests__/scanners/deploy/provider-detector.test.d.ts +2 -0
  26. package/dist/__tests__/scanners/deploy/provider-detector.test.d.ts.map +1 -0
  27. package/dist/__tests__/scanners/deploy/provider-detector.test.js +88 -0
  28. package/dist/__tests__/scanners/deploy/provider-detector.test.js.map +1 -0
  29. package/dist/__tests__/scanners/deploy/types.test.d.ts +2 -0
  30. package/dist/__tests__/scanners/deploy/types.test.d.ts.map +1 -0
  31. package/dist/__tests__/scanners/deploy/types.test.js +126 -0
  32. package/dist/__tests__/scanners/deploy/types.test.js.map +1 -0
  33. package/dist/__tests__/scanners/fp-feedback.test.js +1 -1
  34. package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -1
  35. package/dist/__tests__/scanners/fp-tracker.test.js +1 -1
  36. package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -1
  37. package/dist/__tests__/scanners/runtime/app-launcher.test.d.ts +2 -0
  38. package/dist/__tests__/scanners/runtime/app-launcher.test.d.ts.map +1 -0
  39. package/dist/__tests__/scanners/runtime/app-launcher.test.js +94 -0
  40. package/dist/__tests__/scanners/runtime/app-launcher.test.js.map +1 -0
  41. package/dist/__tests__/scanners/runtime/golden-path-runner.test.d.ts +2 -0
  42. package/dist/__tests__/scanners/runtime/golden-path-runner.test.d.ts.map +1 -0
  43. package/dist/__tests__/scanners/runtime/golden-path-runner.test.js +195 -0
  44. package/dist/__tests__/scanners/runtime/golden-path-runner.test.js.map +1 -0
  45. package/dist/__tests__/scanners/runtime/index.test.d.ts +2 -0
  46. package/dist/__tests__/scanners/runtime/index.test.d.ts.map +1 -0
  47. package/dist/__tests__/scanners/runtime/index.test.js +120 -0
  48. package/dist/__tests__/scanners/runtime/index.test.js.map +1 -0
  49. package/dist/__tests__/scanners/runtime/types.test.d.ts +2 -0
  50. package/dist/__tests__/scanners/runtime/types.test.d.ts.map +1 -0
  51. package/dist/__tests__/scanners/runtime/types.test.js +126 -0
  52. package/dist/__tests__/scanners/runtime/types.test.js.map +1 -0
  53. package/dist/__tests__/scanners/scale/bottleneck-detector.test.d.ts +2 -0
  54. package/dist/__tests__/scanners/scale/bottleneck-detector.test.d.ts.map +1 -0
  55. package/dist/__tests__/scanners/scale/bottleneck-detector.test.js +187 -0
  56. package/dist/__tests__/scanners/scale/bottleneck-detector.test.js.map +1 -0
  57. package/dist/__tests__/scanners/scale/index.test.d.ts +2 -0
  58. package/dist/__tests__/scanners/scale/index.test.d.ts.map +1 -0
  59. package/dist/__tests__/scanners/scale/index.test.js +87 -0
  60. package/dist/__tests__/scanners/scale/index.test.js.map +1 -0
  61. package/dist/__tests__/scanners/scale/load-profiler.test.d.ts +2 -0
  62. package/dist/__tests__/scanners/scale/load-profiler.test.d.ts.map +1 -0
  63. package/dist/__tests__/scanners/scale/load-profiler.test.js +122 -0
  64. package/dist/__tests__/scanners/scale/load-profiler.test.js.map +1 -0
  65. package/dist/__tests__/scanners/scale/types.test.d.ts +2 -0
  66. package/dist/__tests__/scanners/scale/types.test.d.ts.map +1 -0
  67. package/dist/__tests__/scanners/scale/types.test.js +129 -0
  68. package/dist/__tests__/scanners/scale/types.test.js.map +1 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +874 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/install-skills.d.ts +11 -0
  73. package/dist/install-skills.d.ts.map +1 -0
  74. package/dist/install-skills.js +81 -0
  75. package/dist/install-skills.js.map +1 -0
  76. package/dist/scanners/ai-code/ai-detector.d.ts +25 -0
  77. package/dist/scanners/ai-code/ai-detector.d.ts.map +1 -0
  78. package/dist/scanners/ai-code/ai-detector.js +192 -0
  79. package/dist/scanners/ai-code/ai-detector.js.map +1 -0
  80. package/dist/scanners/ai-code/confidence-scorer.d.ts +40 -0
  81. package/dist/scanners/ai-code/confidence-scorer.d.ts.map +1 -0
  82. package/dist/scanners/ai-code/confidence-scorer.js +148 -0
  83. package/dist/scanners/ai-code/confidence-scorer.js.map +1 -0
  84. package/dist/scanners/ai-code/hallucination-checker.d.ts +36 -0
  85. package/dist/scanners/ai-code/hallucination-checker.d.ts.map +1 -0
  86. package/dist/scanners/ai-code/hallucination-checker.js +298 -0
  87. package/dist/scanners/ai-code/hallucination-checker.js.map +1 -0
  88. package/dist/scanners/ai-code/index.d.ts +30 -0
  89. package/dist/scanners/ai-code/index.d.ts.map +1 -0
  90. package/dist/scanners/ai-code/index.js +224 -0
  91. package/dist/scanners/ai-code/index.js.map +1 -0
  92. package/dist/scanners/ai-code/types.d.ts +192 -0
  93. package/dist/scanners/ai-code/types.d.ts.map +1 -0
  94. package/dist/scanners/ai-code/types.js +37 -0
  95. package/dist/scanners/ai-code/types.js.map +1 -0
  96. package/dist/scanners/deploy/health-checker.d.ts +38 -0
  97. package/dist/scanners/deploy/health-checker.d.ts.map +1 -0
  98. package/dist/scanners/deploy/health-checker.js +272 -0
  99. package/dist/scanners/deploy/health-checker.js.map +1 -0
  100. package/dist/scanners/deploy/index.d.ts +44 -0
  101. package/dist/scanners/deploy/index.d.ts.map +1 -0
  102. package/dist/scanners/deploy/index.js +208 -0
  103. package/dist/scanners/deploy/index.js.map +1 -0
  104. package/dist/scanners/deploy/provider-detector.d.ts +25 -0
  105. package/dist/scanners/deploy/provider-detector.d.ts.map +1 -0
  106. package/dist/scanners/deploy/provider-detector.js +177 -0
  107. package/dist/scanners/deploy/provider-detector.js.map +1 -0
  108. package/dist/scanners/deploy/types.d.ts +406 -0
  109. package/dist/scanners/deploy/types.d.ts.map +1 -0
  110. package/dist/scanners/deploy/types.js +58 -0
  111. package/dist/scanners/deploy/types.js.map +1 -0
  112. package/dist/scanners/deploy/vercel-integration.d.ts +52 -0
  113. package/dist/scanners/deploy/vercel-integration.d.ts.map +1 -0
  114. package/dist/scanners/deploy/vercel-integration.js +280 -0
  115. package/dist/scanners/deploy/vercel-integration.js.map +1 -0
  116. package/dist/scanners/runtime/app-launcher.d.ts +33 -0
  117. package/dist/scanners/runtime/app-launcher.d.ts.map +1 -0
  118. package/dist/scanners/runtime/app-launcher.js +419 -0
  119. package/dist/scanners/runtime/app-launcher.js.map +1 -0
  120. package/dist/scanners/runtime/golden-path-runner.d.ts +48 -0
  121. package/dist/scanners/runtime/golden-path-runner.d.ts.map +1 -0
  122. package/dist/scanners/runtime/golden-path-runner.js +373 -0
  123. package/dist/scanners/runtime/golden-path-runner.js.map +1 -0
  124. package/dist/scanners/runtime/index.d.ts +41 -0
  125. package/dist/scanners/runtime/index.d.ts.map +1 -0
  126. package/dist/scanners/runtime/index.js +164 -0
  127. package/dist/scanners/runtime/index.js.map +1 -0
  128. package/dist/scanners/runtime/playwright-executor.d.ts +50 -0
  129. package/dist/scanners/runtime/playwright-executor.d.ts.map +1 -0
  130. package/dist/scanners/runtime/playwright-executor.js +387 -0
  131. package/dist/scanners/runtime/playwright-executor.js.map +1 -0
  132. package/dist/scanners/runtime/types.d.ts +215 -0
  133. package/dist/scanners/runtime/types.d.ts.map +1 -0
  134. package/dist/scanners/runtime/types.js +40 -0
  135. package/dist/scanners/runtime/types.js.map +1 -0
  136. package/dist/scanners/scale/bottleneck-detector.d.ts +17 -0
  137. package/dist/scanners/scale/bottleneck-detector.d.ts.map +1 -0
  138. package/dist/scanners/scale/bottleneck-detector.js +250 -0
  139. package/dist/scanners/scale/bottleneck-detector.js.map +1 -0
  140. package/dist/scanners/scale/capacity-estimator.d.ts +17 -0
  141. package/dist/scanners/scale/capacity-estimator.d.ts.map +1 -0
  142. package/dist/scanners/scale/capacity-estimator.js +197 -0
  143. package/dist/scanners/scale/capacity-estimator.js.map +1 -0
  144. package/dist/scanners/scale/index.d.ts +37 -0
  145. package/dist/scanners/scale/index.d.ts.map +1 -0
  146. package/dist/scanners/scale/index.js +101 -0
  147. package/dist/scanners/scale/index.js.map +1 -0
  148. package/dist/scanners/scale/load-profiler.d.ts +48 -0
  149. package/dist/scanners/scale/load-profiler.d.ts.map +1 -0
  150. package/dist/scanners/scale/load-profiler.js +377 -0
  151. package/dist/scanners/scale/load-profiler.js.map +1 -0
  152. package/dist/scanners/scale/types.d.ts +529 -0
  153. package/dist/scanners/scale/types.d.ts.map +1 -0
  154. package/dist/scanners/scale/types.js +57 -0
  155. package/dist/scanners/scale/types.js.map +1 -0
  156. package/dist/scanners/secrets.d.ts.map +1 -1
  157. package/dist/scanners/secrets.js +13 -2
  158. package/dist/scanners/secrets.js.map +1 -1
  159. package/package.json +4 -2
  160. package/skills/vaspera-add-tests/SKILL.md +102 -0
  161. package/skills/vaspera-ai-verify/SKILL.md +166 -0
  162. package/skills/vaspera-audit/SKILL.md +67 -0
  163. package/skills/vaspera-certify/SKILL.md +130 -0
  164. package/skills/vaspera-deploy/SKILL.md +152 -0
  165. package/skills/vaspera-fix-critical/SKILL.md +52 -0
  166. package/skills/vaspera-fix-high/SKILL.md +81 -0
  167. package/skills/vaspera-fix-medium/SKILL.md +56 -0
  168. package/skills/vaspera-fix-rls/SKILL.md +85 -0
  169. package/skills/vaspera-harden/SKILL.md +102 -0
  170. package/skills/vaspera-help/SKILL.md +61 -0
  171. package/skills/vaspera-load-test/SKILL.md +167 -0
  172. package/skills/vaspera-verify/SKILL.md +70 -0
  173. package/skills/vaspera-verify-e2e/SKILL.md +117 -0
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Bottleneck Detector
3
+ *
4
+ * Analyzes load test results and code patterns to identify performance bottlenecks.
5
+ *
6
+ * @module scanners/scale/bottleneck-detector
7
+ */
8
+ import type { Bottleneck, LoadTestResult } from "./types.js";
9
+ /**
10
+ * Detect bottlenecks in a project
11
+ */
12
+ export declare function detectBottlenecks(projectPath: string, loadTestResults?: LoadTestResult): Promise<Bottleneck[]>;
13
+ /**
14
+ * Calculate bottleneck score (100 = no bottlenecks)
15
+ */
16
+ export declare function calculateBottleneckScore(bottlenecks: Bottleneck[]): number;
17
+ //# sourceMappingURL=bottleneck-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bottleneck-detector.d.ts","sourceRoot":"","sources":["../../../src/scanners/scale/bottleneck-detector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA+M7D;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,UAAU,EAAE,CAAC,CA0BvB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAqB1E"}
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Bottleneck Detector
3
+ *
4
+ * Analyzes load test results and code patterns to identify performance bottlenecks.
5
+ *
6
+ * @module scanners/scale/bottleneck-detector
7
+ */
8
+ import { readFile, readdir } from "fs/promises";
9
+ import { join } from "path";
10
+ import { logger } from "../../logger.js";
11
+ /**
12
+ * N+1 query pattern detection
13
+ */
14
+ const N_PLUS_ONE_PATTERNS = [
15
+ // Prisma
16
+ /\.findMany\(\s*\{[^}]*include\s*:\s*\{/g,
17
+ // Sequelize
18
+ /\.findAll\(\s*\{[^}]*include\s*:\s*\[/g,
19
+ // TypeORM
20
+ /\.find\(\s*\{[^}]*relations\s*:\s*\[/g,
21
+ // Raw SQL in loop
22
+ /for\s*\([^)]*\)\s*\{[^}]*(?:SELECT|INSERT|UPDATE|DELETE)/gi,
23
+ // forEach with await
24
+ /\.forEach\(\s*async/g,
25
+ ];
26
+ /**
27
+ * Memory leak patterns
28
+ */
29
+ const MEMORY_LEAK_PATTERNS = [
30
+ // Growing arrays in closures
31
+ /const\s+\w+\s*=\s*\[\s*\][\s\S]*setInterval/g,
32
+ // Event listeners without cleanup
33
+ /addEventListener\([^)]+\)(?![\s\S]*removeEventListener)/g,
34
+ // Global state accumulation
35
+ /global\.\w+\s*=\s*\[[\s\S]*\.push\(/g,
36
+ ];
37
+ /**
38
+ * Blocking operation patterns
39
+ */
40
+ const BLOCKING_PATTERNS = [
41
+ // Sync file operations
42
+ /(?:readFileSync|writeFileSync|existsSync|statSync)/g,
43
+ // Blocking crypto
44
+ /crypto\.(?:pbkdf2Sync|scryptSync|randomBytes)\s*\(/g,
45
+ // Large JSON parsing
46
+ /JSON\.parse\([^)]*\.length\s*>\s*\d{6}/g,
47
+ ];
48
+ /**
49
+ * Analyze source code for potential bottlenecks
50
+ */
51
+ async function analyzeSourceCode(projectPath) {
52
+ const bottlenecks = [];
53
+ const srcDirs = ["src", "app", "pages", "api", "lib"];
54
+ for (const dir of srcDirs) {
55
+ try {
56
+ const dirPath = join(projectPath, dir);
57
+ const files = await readdir(dirPath, { recursive: true });
58
+ for (const file of files) {
59
+ if (typeof file !== "string")
60
+ continue;
61
+ if (!file.match(/\.(ts|js|tsx|jsx)$/))
62
+ continue;
63
+ try {
64
+ const filePath = join(dirPath, file);
65
+ const content = await readFile(filePath, "utf-8");
66
+ // Check for N+1 patterns
67
+ for (const pattern of N_PLUS_ONE_PATTERNS) {
68
+ const matches = content.match(pattern);
69
+ if (matches && matches.length > 0) {
70
+ bottlenecks.push({
71
+ type: "database",
72
+ location: `${dir}/${file}`,
73
+ severity: "high",
74
+ description: `Potential N+1 query pattern detected (${matches.length} occurrences)`,
75
+ metrics: {
76
+ current: matches.length,
77
+ threshold: 0,
78
+ unit: "patterns",
79
+ },
80
+ recommendation: "Consider using eager loading or batching queries",
81
+ });
82
+ }
83
+ }
84
+ // Check for memory leak patterns
85
+ for (const pattern of MEMORY_LEAK_PATTERNS) {
86
+ const matches = content.match(pattern);
87
+ if (matches && matches.length > 0) {
88
+ bottlenecks.push({
89
+ type: "memory",
90
+ location: `${dir}/${file}`,
91
+ severity: "medium",
92
+ description: `Potential memory leak pattern detected`,
93
+ metrics: {
94
+ current: matches.length,
95
+ threshold: 0,
96
+ unit: "patterns",
97
+ },
98
+ recommendation: "Ensure proper cleanup of resources and event listeners",
99
+ });
100
+ }
101
+ }
102
+ // Check for blocking patterns
103
+ for (const pattern of BLOCKING_PATTERNS) {
104
+ const matches = content.match(pattern);
105
+ if (matches && matches.length > 0) {
106
+ bottlenecks.push({
107
+ type: "cpu",
108
+ location: `${dir}/${file}`,
109
+ severity: "medium",
110
+ description: `Blocking operation detected: ${matches[0]}`,
111
+ metrics: {
112
+ current: matches.length,
113
+ threshold: 0,
114
+ unit: "occurrences",
115
+ },
116
+ recommendation: "Use async alternatives to avoid blocking the event loop",
117
+ });
118
+ }
119
+ }
120
+ }
121
+ catch {
122
+ // Skip files that can't be read
123
+ }
124
+ }
125
+ }
126
+ catch {
127
+ // Directory doesn't exist
128
+ }
129
+ }
130
+ return bottlenecks;
131
+ }
132
+ /**
133
+ * Analyze load test results for bottlenecks
134
+ */
135
+ function analyzeLoadTestResults(results) {
136
+ const bottlenecks = [];
137
+ // Check for high latency
138
+ if (results.summary.latency.p95 > 500) {
139
+ bottlenecks.push({
140
+ type: "endpoint",
141
+ location: "Overall API",
142
+ severity: results.summary.latency.p95 > 1000 ? "critical" : "high",
143
+ description: `High 95th percentile latency: ${results.summary.latency.p95.toFixed(0)}ms`,
144
+ metrics: {
145
+ current: results.summary.latency.p95,
146
+ threshold: 500,
147
+ unit: "ms",
148
+ },
149
+ recommendation: "Profile endpoints to identify slow operations, add caching, or optimize queries",
150
+ });
151
+ }
152
+ // Check for high error rate
153
+ if (results.summary.errorRate > 0.01) {
154
+ bottlenecks.push({
155
+ type: "endpoint",
156
+ location: "Overall API",
157
+ severity: results.summary.errorRate > 0.05 ? "critical" : "high",
158
+ description: `High error rate: ${(results.summary.errorRate * 100).toFixed(2)}%`,
159
+ metrics: {
160
+ current: results.summary.errorRate,
161
+ threshold: 0.01,
162
+ unit: "rate",
163
+ },
164
+ recommendation: "Check error logs, add retry logic, or scale resources",
165
+ });
166
+ }
167
+ // Check for low throughput
168
+ if (results.summary.avgThroughput < 100) {
169
+ bottlenecks.push({
170
+ type: "endpoint",
171
+ location: "Overall API",
172
+ severity: "medium",
173
+ description: `Low throughput: ${results.summary.avgThroughput.toFixed(1)} req/s`,
174
+ metrics: {
175
+ current: results.summary.avgThroughput,
176
+ threshold: 100,
177
+ unit: "req/s",
178
+ },
179
+ recommendation: "Consider horizontal scaling or optimizing request handling",
180
+ });
181
+ }
182
+ // Check individual endpoints
183
+ for (const scenario of results.scenarios) {
184
+ for (const endpoint of scenario.endpoints) {
185
+ if (endpoint.latency.p95 > 500) {
186
+ bottlenecks.push({
187
+ type: "endpoint",
188
+ location: `${endpoint.method} ${endpoint.path}`,
189
+ severity: endpoint.latency.p95 > 1000 ? "critical" : "high",
190
+ description: `Slow endpoint: p95=${endpoint.latency.p95.toFixed(0)}ms`,
191
+ metrics: {
192
+ current: endpoint.latency.p95,
193
+ threshold: 500,
194
+ unit: "ms",
195
+ },
196
+ recommendation: "Add endpoint-specific caching or optimize the handler",
197
+ });
198
+ }
199
+ }
200
+ }
201
+ return bottlenecks;
202
+ }
203
+ /**
204
+ * Detect bottlenecks in a project
205
+ */
206
+ export async function detectBottlenecks(projectPath, loadTestResults) {
207
+ const bottlenecks = [];
208
+ logger.info("scale.bottleneck_detection_started", { projectPath });
209
+ // Analyze source code
210
+ const codeBottlenecks = await analyzeSourceCode(projectPath);
211
+ bottlenecks.push(...codeBottlenecks);
212
+ // Analyze load test results if available
213
+ if (loadTestResults) {
214
+ const loadBottlenecks = analyzeLoadTestResults(loadTestResults);
215
+ bottlenecks.push(...loadBottlenecks);
216
+ }
217
+ // Sort by severity
218
+ const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
219
+ bottlenecks.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
220
+ logger.info("scale.bottleneck_detection_completed", {
221
+ total: bottlenecks.length,
222
+ critical: bottlenecks.filter((b) => b.severity === "critical").length,
223
+ high: bottlenecks.filter((b) => b.severity === "high").length,
224
+ });
225
+ return bottlenecks;
226
+ }
227
+ /**
228
+ * Calculate bottleneck score (100 = no bottlenecks)
229
+ */
230
+ export function calculateBottleneckScore(bottlenecks) {
231
+ let score = 100;
232
+ for (const bottleneck of bottlenecks) {
233
+ switch (bottleneck.severity) {
234
+ case "critical":
235
+ score -= 25;
236
+ break;
237
+ case "high":
238
+ score -= 15;
239
+ break;
240
+ case "medium":
241
+ score -= 8;
242
+ break;
243
+ case "low":
244
+ score -= 3;
245
+ break;
246
+ }
247
+ }
248
+ return Math.max(0, score);
249
+ }
250
+ //# sourceMappingURL=bottleneck-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bottleneck-detector.js","sourceRoot":"","sources":["../../../src/scanners/scale/bottleneck-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Capacity Estimator
3
+ *
4
+ * Estimates maximum capacity and projects costs based on load test results.
5
+ *
6
+ * @module scanners/scale/capacity-estimator
7
+ */
8
+ import type { CapacityEstimate, LoadTestResult, Bottleneck } from "./types.js";
9
+ /**
10
+ * Estimate capacity for a project
11
+ */
12
+ export declare function estimateCapacity(loadTestResult?: LoadTestResult, bottlenecks?: Bottleneck[]): Promise<CapacityEstimate>;
13
+ /**
14
+ * Calculate capacity score (100 = excellent capacity margin)
15
+ */
16
+ export declare function calculateCapacityScore(estimate: CapacityEstimate, targetConcurrent?: number): number;
17
+ //# sourceMappingURL=capacity-estimator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacity-estimator.d.ts","sourceRoot":"","sources":["../../../src/scanners/scale/capacity-estimator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAiK/E;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,cAAc,CAAC,EAAE,cAAc,EAC/B,WAAW,GAAE,UAAU,EAAO,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAuC3B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,gBAAgB,EAC1B,gBAAgB,GAAE,MAAY,GAC7B,MAAM,CAUR"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Capacity Estimator
3
+ *
4
+ * Estimates maximum capacity and projects costs based on load test results.
5
+ *
6
+ * @module scanners/scale/capacity-estimator
7
+ */
8
+ import { logger } from "../../logger.js";
9
+ /**
10
+ * Instance type pricing (approximate monthly costs)
11
+ */
12
+ const INSTANCE_PRICING = {
13
+ // AWS EC2 (us-east-1)
14
+ "t3.micro": { cpu: 2, memory: 1, price: 8 },
15
+ "t3.small": { cpu: 2, memory: 2, price: 15 },
16
+ "t3.medium": { cpu: 2, memory: 4, price: 30 },
17
+ "t3.large": { cpu: 2, memory: 8, price: 60 },
18
+ "t3.xlarge": { cpu: 4, memory: 16, price: 120 },
19
+ "m5.large": { cpu: 2, memory: 8, price: 70 },
20
+ "m5.xlarge": { cpu: 4, memory: 16, price: 140 },
21
+ "m5.2xlarge": { cpu: 8, memory: 32, price: 280 },
22
+ // Vercel (approximate)
23
+ "vercel-hobby": { cpu: 1, memory: 1, price: 0 },
24
+ "vercel-pro": { cpu: 1, memory: 1, price: 20 },
25
+ "vercel-enterprise": { cpu: 4, memory: 4, price: 500 },
26
+ // Railway
27
+ "railway-starter": { cpu: 1, memory: 0.5, price: 5 },
28
+ "railway-pro": { cpu: 2, memory: 2, price: 20 },
29
+ };
30
+ /**
31
+ * Estimate breakpoint (where system starts failing)
32
+ */
33
+ function estimateBreakpoint(loadTestResult) {
34
+ // Use Little's Law and observed metrics
35
+ const avgLatency = loadTestResult.summary.latency.mean;
36
+ const throughput = loadTestResult.summary.avgThroughput;
37
+ const errorRate = loadTestResult.summary.errorRate;
38
+ // Find the scenario with highest VUs
39
+ const maxVus = Math.max(...loadTestResult.scenarios.map((s) => s.vusMax));
40
+ // If error rate is already high, breakpoint is near current load
41
+ if (errorRate > 0.05) {
42
+ return {
43
+ vus: Math.round(maxVus * 0.8),
44
+ confidence: 0.7,
45
+ };
46
+ }
47
+ // If latency is degraded but not failing, estimate 50% more capacity
48
+ if (loadTestResult.summary.latency.p95 > 500) {
49
+ return {
50
+ vus: Math.round(maxVus * 1.2),
51
+ confidence: 0.6,
52
+ };
53
+ }
54
+ // System handling load well, estimate 2x capacity
55
+ if (errorRate < 0.01 && avgLatency < 200) {
56
+ return {
57
+ vus: Math.round(maxVus * 2.5),
58
+ confidence: 0.5,
59
+ };
60
+ }
61
+ // Default conservative estimate
62
+ return {
63
+ vus: Math.round(maxVus * 1.5),
64
+ confidence: 0.4,
65
+ };
66
+ }
67
+ /**
68
+ * Calculate maximum requests per second
69
+ */
70
+ function estimateMaxRPS(loadTestResult) {
71
+ const breakpoint = estimateBreakpoint(loadTestResult);
72
+ const currentRPS = loadTestResult.summary.avgThroughput;
73
+ const currentVUs = Math.max(...loadTestResult.scenarios.map((s) => s.vusMax));
74
+ if (currentVUs === 0)
75
+ return 0;
76
+ // Linear extrapolation with degradation factor
77
+ const rpsPerVU = currentRPS / currentVUs;
78
+ const degradationFactor = 0.8; // Assume 20% degradation at scale
79
+ return Math.round(breakpoint.vus * rpsPerVU * degradationFactor);
80
+ }
81
+ /**
82
+ * Generate recommendations based on results
83
+ */
84
+ function generateRecommendations(loadTestResult, bottlenecks) {
85
+ const recommendations = [];
86
+ // High latency recommendations
87
+ if (loadTestResult.summary.latency.p95 > 500) {
88
+ recommendations.push("Add application-level caching (Redis, Memcached) to reduce database load");
89
+ recommendations.push("Consider using a CDN for static assets and cacheable API responses");
90
+ }
91
+ // High error rate recommendations
92
+ if (loadTestResult.summary.errorRate > 0.01) {
93
+ recommendations.push("Implement circuit breakers to prevent cascade failures");
94
+ recommendations.push("Add rate limiting to protect against traffic spikes");
95
+ }
96
+ // Database bottlenecks
97
+ const dbBottlenecks = bottlenecks.filter((b) => b.type === "database");
98
+ if (dbBottlenecks.length > 0) {
99
+ recommendations.push("Optimize database queries - add indexes and use connection pooling");
100
+ recommendations.push("Consider read replicas for read-heavy workloads");
101
+ }
102
+ // Memory bottlenecks
103
+ const memBottlenecks = bottlenecks.filter((b) => b.type === "memory");
104
+ if (memBottlenecks.length > 0) {
105
+ recommendations.push("Profile memory usage and fix potential leaks");
106
+ recommendations.push("Consider increasing instance memory or using smaller request payloads");
107
+ }
108
+ // General scaling recommendations
109
+ if (loadTestResult.summary.avgThroughput < 100) {
110
+ recommendations.push("Consider horizontal scaling with a load balancer");
111
+ }
112
+ // Add default if no specific recommendations
113
+ if (recommendations.length === 0) {
114
+ recommendations.push("System performing well - monitor for degradation at higher loads");
115
+ }
116
+ return recommendations;
117
+ }
118
+ /**
119
+ * Project infrastructure costs
120
+ */
121
+ function projectCosts(maxRPS, maxConcurrent) {
122
+ // Simple heuristic: 1000 RPS per m5.large
123
+ const rpsPerInstance = 1000;
124
+ const instancesNeeded = Math.ceil(maxRPS / rpsPerInstance);
125
+ // Choose appropriate instance type
126
+ let instanceType = "t3.medium";
127
+ if (maxConcurrent > 500)
128
+ instanceType = "t3.large";
129
+ if (maxConcurrent > 1000)
130
+ instanceType = "m5.large";
131
+ if (maxConcurrent > 5000)
132
+ instanceType = "m5.xlarge";
133
+ const pricing = INSTANCE_PRICING[instanceType];
134
+ return {
135
+ provider: "AWS",
136
+ instanceType,
137
+ instances: Math.max(2, instancesNeeded), // At least 2 for HA
138
+ monthlyCost: Math.max(2, instancesNeeded) * pricing.price,
139
+ };
140
+ }
141
+ /**
142
+ * Estimate capacity for a project
143
+ */
144
+ export async function estimateCapacity(loadTestResult, bottlenecks = []) {
145
+ logger.info("scale.capacity_estimation_started");
146
+ // If no load test results, return conservative estimates
147
+ if (!loadTestResult) {
148
+ return {
149
+ maxConcurrentUsers: 100,
150
+ maxRequestsPerSecond: 50,
151
+ estimatedBreakpoint: {
152
+ vus: 200,
153
+ confidence: 0.2,
154
+ },
155
+ recommendations: [
156
+ "Run load tests to get accurate capacity estimates",
157
+ "Start with baseline performance monitoring",
158
+ ],
159
+ };
160
+ }
161
+ const breakpoint = estimateBreakpoint(loadTestResult);
162
+ const maxRPS = estimateMaxRPS(loadTestResult);
163
+ const recommendations = generateRecommendations(loadTestResult, bottlenecks);
164
+ const costProjection = projectCosts(maxRPS, breakpoint.vus);
165
+ const estimate = {
166
+ maxConcurrentUsers: breakpoint.vus,
167
+ maxRequestsPerSecond: maxRPS,
168
+ estimatedBreakpoint: breakpoint,
169
+ recommendations,
170
+ costProjection,
171
+ };
172
+ logger.info("scale.capacity_estimation_completed", {
173
+ maxConcurrent: estimate.maxConcurrentUsers,
174
+ maxRPS: estimate.maxRequestsPerSecond,
175
+ confidence: breakpoint.confidence,
176
+ });
177
+ return estimate;
178
+ }
179
+ /**
180
+ * Calculate capacity score (100 = excellent capacity margin)
181
+ */
182
+ export function calculateCapacityScore(estimate, targetConcurrent = 100) {
183
+ // Score based on how much headroom we have
184
+ const headroom = estimate.maxConcurrentUsers / targetConcurrent;
185
+ if (headroom >= 5)
186
+ return 100; // 5x headroom
187
+ if (headroom >= 3)
188
+ return 90; // 3x headroom
189
+ if (headroom >= 2)
190
+ return 80; // 2x headroom
191
+ if (headroom >= 1.5)
192
+ return 70; // 1.5x headroom
193
+ if (headroom >= 1)
194
+ return 50; // Just meeting target
195
+ return Math.round(headroom * 50); // Below target
196
+ }
197
+ //# sourceMappingURL=capacity-estimator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacity-estimator.js","sourceRoot":"","sources":["../../../src/scanners/scale/capacity-estimator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Scale Assessment Scanner
3
+ *
4
+ * Orchestrates load testing, bottleneck detection, and capacity estimation.
5
+ * This is the entry point for M8 scale assessment capabilities.
6
+ *
7
+ * @module scanners/scale
8
+ */
9
+ import { detectBottlenecks } from "./bottleneck-detector.js";
10
+ import type { ScaleAssessmentResult } from "./types.js";
11
+ export * from "./types.js";
12
+ export { detectLoadTool, discoverProfiles, runK6Test, generateSampleProfile, loadProfile, isK6Available, } from "./load-profiler.js";
13
+ export { detectBottlenecks, calculateBottleneckScore, } from "./bottleneck-detector.js";
14
+ export { estimateCapacity, calculateCapacityScore, } from "./capacity-estimator.js";
15
+ /**
16
+ * Run full scale assessment
17
+ *
18
+ * 1. Detect load testing tool
19
+ * 2. Discover and run load profiles
20
+ * 3. Detect bottlenecks
21
+ * 4. Estimate capacity
22
+ * 5. Calculate scores
23
+ */
24
+ export declare function runScaleAssessment(projectPath: string, baseUrl: string, options?: {
25
+ timeout?: number;
26
+ profileName?: string;
27
+ skipLoadTest?: boolean;
28
+ targetConcurrent?: number;
29
+ }): Promise<ScaleAssessmentResult>;
30
+ /**
31
+ * Quick bottleneck scan (no load testing)
32
+ */
33
+ export declare function quickBottleneckScan(projectPath: string): Promise<{
34
+ bottlenecks: Awaited<ReturnType<typeof detectBottlenecks>>;
35
+ score: number;
36
+ }>;
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/scale/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,OAAO,EACL,iBAAiB,EAElB,MAAM,0BAA0B,CAAC;AAKlC,OAAO,KAAK,EACV,qBAAqB,EAGtB,MAAM,YAAY,CAAC;AAEpB,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,qBAAqB,EACrB,WAAW,EACX,aAAa,GACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACtB,GACL,OAAO,CAAC,qBAAqB,CAAC,CA8EhC;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IACT,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAKD"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Scale Assessment Scanner
3
+ *
4
+ * Orchestrates load testing, bottleneck detection, and capacity estimation.
5
+ * This is the entry point for M8 scale assessment capabilities.
6
+ *
7
+ * @module scanners/scale
8
+ */
9
+ import { logger } from "../../logger.js";
10
+ import { detectLoadTool, discoverProfiles, runK6Test, } from "./load-profiler.js";
11
+ import { detectBottlenecks, calculateBottleneckScore, } from "./bottleneck-detector.js";
12
+ import { estimateCapacity, calculateCapacityScore, } from "./capacity-estimator.js";
13
+ export * from "./types.js";
14
+ export { detectLoadTool, discoverProfiles, runK6Test, generateSampleProfile, loadProfile, isK6Available, } from "./load-profiler.js";
15
+ export { detectBottlenecks, calculateBottleneckScore, } from "./bottleneck-detector.js";
16
+ export { estimateCapacity, calculateCapacityScore, } from "./capacity-estimator.js";
17
+ /**
18
+ * Run full scale assessment
19
+ *
20
+ * 1. Detect load testing tool
21
+ * 2. Discover and run load profiles
22
+ * 3. Detect bottlenecks
23
+ * 4. Estimate capacity
24
+ * 5. Calculate scores
25
+ */
26
+ export async function runScaleAssessment(projectPath, baseUrl, options = {}) {
27
+ const startTime = Date.now();
28
+ const { timeout = 600000, profileName, skipLoadTest = false, targetConcurrent = 100 } = options;
29
+ logger.info("scale.assessment_started", { projectPath, baseUrl });
30
+ let loadTestResult;
31
+ // Step 1: Run load tests if not skipped
32
+ if (!skipLoadTest) {
33
+ // Check for load testing tools
34
+ const tool = await detectLoadTool();
35
+ if (!tool) {
36
+ logger.warn("scale.no_load_tool", {
37
+ message: "No load testing tool found. Install k6 or Artillery.",
38
+ });
39
+ }
40
+ else {
41
+ // Discover profiles
42
+ const profiles = await discoverProfiles(projectPath);
43
+ if (profiles.length === 0) {
44
+ logger.info("scale.no_profiles_found", {
45
+ message: "No load profiles found. Generate one with scale_profile_generate.",
46
+ });
47
+ }
48
+ else {
49
+ // Find matching profile or use first
50
+ const selectedProfile = profileName
51
+ ? profiles.find((p) => p.profile.name === profileName)
52
+ : profiles[0];
53
+ if (selectedProfile && tool === "k6") {
54
+ loadTestResult = await runK6Test(selectedProfile.profile, baseUrl, {
55
+ timeout,
56
+ });
57
+ }
58
+ }
59
+ }
60
+ }
61
+ // Step 2: Detect bottlenecks
62
+ const bottlenecks = await detectBottlenecks(projectPath, loadTestResult);
63
+ const bottleneckScore = calculateBottleneckScore(bottlenecks);
64
+ // Step 3: Estimate capacity
65
+ const capacity = await estimateCapacity(loadTestResult, bottlenecks);
66
+ const capacityScore = calculateCapacityScore(capacity, targetConcurrent);
67
+ // Step 4: Calculate overall score
68
+ const loadTestScore = loadTestResult?.score ?? 50; // Neutral if no test
69
+ const overallScore = Math.round((loadTestScore * 0.4) + (bottleneckScore * 0.35) + (capacityScore * 0.25));
70
+ const result = {
71
+ success: overallScore >= 70,
72
+ loadTest: loadTestResult,
73
+ bottlenecks,
74
+ capacity,
75
+ score: {
76
+ loadTestScore,
77
+ bottleneckScore,
78
+ capacityScore,
79
+ overallScore,
80
+ },
81
+ duration: Date.now() - startTime,
82
+ };
83
+ logger.info("scale.assessment_completed", {
84
+ success: result.success,
85
+ overallScore,
86
+ loadTestScore,
87
+ bottleneckScore,
88
+ capacityScore,
89
+ duration: result.duration,
90
+ });
91
+ return result;
92
+ }
93
+ /**
94
+ * Quick bottleneck scan (no load testing)
95
+ */
96
+ export async function quickBottleneckScan(projectPath) {
97
+ const bottlenecks = await detectBottlenecks(projectPath);
98
+ const score = calculateBottleneckScore(bottlenecks);
99
+ return { bottlenecks, score };
100
+ }
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scanners/scale/index.ts"],"names":[],"mappings":"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"}