qa360 1.4.5 → 2.0.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 (209) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/ai.d.ts +41 -0
  3. package/dist/commands/ai.js +499 -0
  4. package/dist/commands/ask.js +12 -12
  5. package/dist/commands/coverage.d.ts +8 -0
  6. package/dist/commands/coverage.js +252 -0
  7. package/dist/commands/explain.d.ts +27 -0
  8. package/dist/commands/explain.js +630 -0
  9. package/dist/commands/flakiness.d.ts +73 -0
  10. package/dist/commands/flakiness.js +435 -0
  11. package/dist/commands/generate.d.ts +66 -0
  12. package/dist/commands/generate.js +438 -0
  13. package/dist/commands/init.d.ts +56 -9
  14. package/dist/commands/init.js +217 -10
  15. package/dist/commands/monitor.d.ts +27 -0
  16. package/dist/commands/monitor.js +225 -0
  17. package/dist/commands/ollama.d.ts +40 -0
  18. package/dist/commands/ollama.js +301 -0
  19. package/dist/commands/pack.d.ts +37 -9
  20. package/dist/commands/pack.js +240 -141
  21. package/dist/commands/regression.d.ts +8 -0
  22. package/dist/commands/regression.js +340 -0
  23. package/dist/commands/repair.d.ts +26 -0
  24. package/dist/commands/repair.js +307 -0
  25. package/dist/commands/retry.d.ts +43 -0
  26. package/dist/commands/retry.js +275 -0
  27. package/dist/commands/run.d.ts +8 -3
  28. package/dist/commands/run.js +45 -31
  29. package/dist/commands/slo.d.ts +8 -0
  30. package/dist/commands/slo.js +327 -0
  31. package/dist/core/adapters/playwright-native-api.d.ts +183 -0
  32. package/dist/core/adapters/playwright-native-api.js +461 -0
  33. package/dist/core/adapters/playwright-ui.d.ts +7 -0
  34. package/dist/core/adapters/playwright-ui.js +29 -1
  35. package/dist/core/ai/anthropic-provider.d.ts +50 -0
  36. package/dist/core/ai/anthropic-provider.js +211 -0
  37. package/dist/core/ai/deepseek-provider.d.ts +81 -0
  38. package/dist/core/ai/deepseek-provider.js +254 -0
  39. package/dist/core/ai/index.d.ts +60 -0
  40. package/dist/core/ai/index.js +18 -0
  41. package/dist/core/ai/llm-client.d.ts +45 -0
  42. package/dist/core/ai/llm-client.js +7 -0
  43. package/dist/core/ai/mock-provider.d.ts +49 -0
  44. package/dist/core/ai/mock-provider.js +121 -0
  45. package/dist/core/ai/ollama-provider.d.ts +78 -0
  46. package/dist/core/ai/ollama-provider.js +192 -0
  47. package/dist/core/ai/openai-provider.d.ts +48 -0
  48. package/dist/core/ai/openai-provider.js +188 -0
  49. package/dist/core/ai/provider-factory.d.ts +160 -0
  50. package/dist/core/ai/provider-factory.js +269 -0
  51. package/dist/core/auth/api-key-provider.d.ts +16 -0
  52. package/dist/core/auth/api-key-provider.js +63 -0
  53. package/dist/core/auth/aws-iam-provider.d.ts +35 -0
  54. package/dist/core/auth/aws-iam-provider.js +177 -0
  55. package/dist/core/auth/azure-ad-provider.d.ts +15 -0
  56. package/dist/core/auth/azure-ad-provider.js +99 -0
  57. package/dist/core/auth/basic-auth-provider.d.ts +26 -0
  58. package/dist/core/auth/basic-auth-provider.js +111 -0
  59. package/dist/core/auth/gcp-adc-provider.d.ts +27 -0
  60. package/dist/core/auth/gcp-adc-provider.js +126 -0
  61. package/dist/core/auth/index.d.ts +238 -0
  62. package/dist/core/auth/index.js +82 -0
  63. package/dist/core/auth/jwt-provider.d.ts +19 -0
  64. package/dist/core/auth/jwt-provider.js +160 -0
  65. package/dist/core/auth/manager.d.ts +84 -0
  66. package/dist/core/auth/manager.js +230 -0
  67. package/dist/core/auth/oauth2-provider.d.ts +17 -0
  68. package/dist/core/auth/oauth2-provider.js +114 -0
  69. package/dist/core/auth/totp-provider.d.ts +31 -0
  70. package/dist/core/auth/totp-provider.js +134 -0
  71. package/dist/core/auth/ui-login-provider.d.ts +26 -0
  72. package/dist/core/auth/ui-login-provider.js +198 -0
  73. package/dist/core/cache/index.d.ts +7 -0
  74. package/dist/core/cache/index.js +6 -0
  75. package/dist/core/cache/lru-cache.d.ts +203 -0
  76. package/dist/core/cache/lru-cache.js +397 -0
  77. package/dist/core/coverage/analyzer.d.ts +101 -0
  78. package/dist/core/coverage/analyzer.js +415 -0
  79. package/dist/core/coverage/collector.d.ts +74 -0
  80. package/dist/core/coverage/collector.js +459 -0
  81. package/dist/core/coverage/config.d.ts +37 -0
  82. package/dist/core/coverage/config.js +156 -0
  83. package/dist/core/coverage/index.d.ts +11 -0
  84. package/dist/core/coverage/index.js +15 -0
  85. package/dist/core/coverage/types.d.ts +267 -0
  86. package/dist/core/coverage/types.js +6 -0
  87. package/dist/core/coverage/vault.d.ts +95 -0
  88. package/dist/core/coverage/vault.js +405 -0
  89. package/dist/core/dashboard/assets.d.ts +6 -0
  90. package/dist/core/dashboard/assets.js +690 -0
  91. package/dist/core/dashboard/index.d.ts +6 -0
  92. package/dist/core/dashboard/index.js +5 -0
  93. package/dist/core/dashboard/server.d.ts +72 -0
  94. package/dist/core/dashboard/server.js +354 -0
  95. package/dist/core/dashboard/types.d.ts +70 -0
  96. package/dist/core/dashboard/types.js +5 -0
  97. package/dist/core/discoverer/index.d.ts +115 -0
  98. package/dist/core/discoverer/index.js +250 -0
  99. package/dist/core/flakiness/index.d.ts +228 -0
  100. package/dist/core/flakiness/index.js +384 -0
  101. package/dist/core/generation/code-formatter.d.ts +111 -0
  102. package/dist/core/generation/code-formatter.js +307 -0
  103. package/dist/core/generation/code-generator.d.ts +144 -0
  104. package/dist/core/generation/code-generator.js +293 -0
  105. package/dist/core/generation/generator.d.ts +40 -0
  106. package/dist/core/generation/generator.js +76 -0
  107. package/dist/core/generation/index.d.ts +30 -0
  108. package/dist/core/generation/index.js +28 -0
  109. package/dist/core/generation/pack-generator.d.ts +107 -0
  110. package/dist/core/generation/pack-generator.js +416 -0
  111. package/dist/core/generation/prompt-builder.d.ts +132 -0
  112. package/dist/core/generation/prompt-builder.js +672 -0
  113. package/dist/core/generation/source-analyzer.d.ts +213 -0
  114. package/dist/core/generation/source-analyzer.js +657 -0
  115. package/dist/core/generation/test-optimizer.d.ts +117 -0
  116. package/dist/core/generation/test-optimizer.js +328 -0
  117. package/dist/core/generation/types.d.ts +214 -0
  118. package/dist/core/generation/types.js +4 -0
  119. package/dist/core/index.d.ts +23 -1
  120. package/dist/core/index.js +39 -0
  121. package/dist/core/pack/validator.js +31 -1
  122. package/dist/core/pack-v2/index.d.ts +9 -0
  123. package/dist/core/pack-v2/index.js +8 -0
  124. package/dist/core/pack-v2/loader.d.ts +62 -0
  125. package/dist/core/pack-v2/loader.js +231 -0
  126. package/dist/core/pack-v2/migrator.d.ts +56 -0
  127. package/dist/core/pack-v2/migrator.js +455 -0
  128. package/dist/core/pack-v2/validator.d.ts +61 -0
  129. package/dist/core/pack-v2/validator.js +577 -0
  130. package/dist/core/regression/detector.d.ts +107 -0
  131. package/dist/core/regression/detector.js +497 -0
  132. package/dist/core/regression/index.d.ts +9 -0
  133. package/dist/core/regression/index.js +11 -0
  134. package/dist/core/regression/trend-analyzer.d.ts +102 -0
  135. package/dist/core/regression/trend-analyzer.js +345 -0
  136. package/dist/core/regression/types.d.ts +222 -0
  137. package/dist/core/regression/types.js +7 -0
  138. package/dist/core/regression/vault.d.ts +87 -0
  139. package/dist/core/regression/vault.js +289 -0
  140. package/dist/core/repair/engine/fixer.d.ts +24 -0
  141. package/dist/core/repair/engine/fixer.js +226 -0
  142. package/dist/core/repair/engine/suggestion-engine.d.ts +18 -0
  143. package/dist/core/repair/engine/suggestion-engine.js +187 -0
  144. package/dist/core/repair/index.d.ts +10 -0
  145. package/dist/core/repair/index.js +13 -0
  146. package/dist/core/repair/repairer.d.ts +90 -0
  147. package/dist/core/repair/repairer.js +284 -0
  148. package/dist/core/repair/types.d.ts +91 -0
  149. package/dist/core/repair/types.js +6 -0
  150. package/dist/core/repair/utils/error-analyzer.d.ts +28 -0
  151. package/dist/core/repair/utils/error-analyzer.js +264 -0
  152. package/dist/core/retry/flakiness-integration.d.ts +60 -0
  153. package/dist/core/retry/flakiness-integration.js +228 -0
  154. package/dist/core/retry/index.d.ts +14 -0
  155. package/dist/core/retry/index.js +16 -0
  156. package/dist/core/retry/retry-engine.d.ts +80 -0
  157. package/dist/core/retry/retry-engine.js +296 -0
  158. package/dist/core/retry/types.d.ts +178 -0
  159. package/dist/core/retry/types.js +52 -0
  160. package/dist/core/retry/vault.d.ts +77 -0
  161. package/dist/core/retry/vault.js +304 -0
  162. package/dist/core/runner/e2e-helpers.d.ts +102 -0
  163. package/dist/core/runner/e2e-helpers.js +153 -0
  164. package/dist/core/runner/phase3-runner.d.ts +101 -2
  165. package/dist/core/runner/phase3-runner.js +559 -24
  166. package/dist/core/self-healing/assertion-healer.d.ts +97 -0
  167. package/dist/core/self-healing/assertion-healer.js +371 -0
  168. package/dist/core/self-healing/engine.d.ts +122 -0
  169. package/dist/core/self-healing/engine.js +538 -0
  170. package/dist/core/self-healing/index.d.ts +10 -0
  171. package/dist/core/self-healing/index.js +11 -0
  172. package/dist/core/self-healing/selector-healer.d.ts +103 -0
  173. package/dist/core/self-healing/selector-healer.js +372 -0
  174. package/dist/core/self-healing/types.d.ts +152 -0
  175. package/dist/core/self-healing/types.js +6 -0
  176. package/dist/core/slo/config.d.ts +107 -0
  177. package/dist/core/slo/config.js +360 -0
  178. package/dist/core/slo/index.d.ts +11 -0
  179. package/dist/core/slo/index.js +15 -0
  180. package/dist/core/slo/sli-calculator.d.ts +92 -0
  181. package/dist/core/slo/sli-calculator.js +364 -0
  182. package/dist/core/slo/slo-tracker.d.ts +148 -0
  183. package/dist/core/slo/slo-tracker.js +379 -0
  184. package/dist/core/slo/types.d.ts +281 -0
  185. package/dist/core/slo/types.js +7 -0
  186. package/dist/core/slo/vault.d.ts +102 -0
  187. package/dist/core/slo/vault.js +427 -0
  188. package/dist/core/tui/index.d.ts +7 -0
  189. package/dist/core/tui/index.js +6 -0
  190. package/dist/core/tui/monitor.d.ts +92 -0
  191. package/dist/core/tui/monitor.js +271 -0
  192. package/dist/core/tui/renderer.d.ts +33 -0
  193. package/dist/core/tui/renderer.js +218 -0
  194. package/dist/core/tui/types.d.ts +63 -0
  195. package/dist/core/tui/types.js +5 -0
  196. package/dist/core/types/pack-v2.d.ts +425 -0
  197. package/dist/core/types/pack-v2.js +8 -0
  198. package/dist/core/vault/index.d.ts +116 -0
  199. package/dist/core/vault/index.js +400 -5
  200. package/dist/core/watch/index.d.ts +7 -0
  201. package/dist/core/watch/index.js +6 -0
  202. package/dist/core/watch/watch-mode.d.ts +213 -0
  203. package/dist/core/watch/watch-mode.js +389 -0
  204. package/dist/index.js +68 -68
  205. package/dist/utils/config.d.ts +5 -0
  206. package/dist/utils/config.js +136 -0
  207. package/package.json +5 -1
  208. package/dist/core/adapters/playwright-api.d.ts +0 -82
  209. package/dist/core/adapters/playwright-api.js +0 -264
@@ -0,0 +1,364 @@
1
+ /**
2
+ * SLI Calculator
3
+ *
4
+ * Calculates Service Level Indicators from various data sources.
5
+ * Supports ratio-based, threshold-based, and percentile-based SLIs.
6
+ */
7
+ /**
8
+ * SLI Calculator class
9
+ */
10
+ export class SLICalculator {
11
+ /**
12
+ * Calculate SLI from good/bad events (ratio-based)
13
+ */
14
+ calculateFromEvents(sli, events) {
15
+ const total = events.good + events.bad;
16
+ const value = total > 0 ? (events.good / total) * 100 : 0;
17
+ return {
18
+ sliId: sli.id,
19
+ timestamp: Date.now(),
20
+ value,
21
+ total,
22
+ good: events.good,
23
+ bad: events.bad,
24
+ unit: sli.unit,
25
+ windowStart: Date.now(),
26
+ windowEnd: Date.now()
27
+ };
28
+ }
29
+ /**
30
+ * Calculate SLI from time series data
31
+ */
32
+ calculateFromTimeSeries(sli, data, windowMs) {
33
+ const now = Date.now();
34
+ const windowStart = now - windowMs;
35
+ // Filter data within window
36
+ const windowData = data.filter(p => p.timestamp >= windowStart && p.timestamp <= now);
37
+ if (windowData.length === 0) {
38
+ return this.emptyMeasurement(sli, windowStart, now);
39
+ }
40
+ let value;
41
+ switch (sli.aggregation) {
42
+ case 'count':
43
+ value = windowData.length;
44
+ break;
45
+ case 'sum':
46
+ value = windowData.reduce((sum, p) => sum + p.value, 0);
47
+ break;
48
+ case 'avg':
49
+ value = windowData.reduce((sum, p) => sum + p.value, 0) / windowData.length;
50
+ break;
51
+ case 'max':
52
+ value = Math.max(...windowData.map(p => p.value));
53
+ break;
54
+ case 'min':
55
+ value = Math.min(...windowData.map(p => p.value));
56
+ break;
57
+ case 'p50':
58
+ value = this.percentile(windowData.map(p => p.value), 50);
59
+ break;
60
+ case 'p95':
61
+ value = this.percentile(windowData.map(p => p.value), 95);
62
+ break;
63
+ case 'p99':
64
+ value = this.percentile(windowData.map(p => p.value), 99);
65
+ break;
66
+ case 'p99_9':
67
+ value = this.percentile(windowData.map(p => p.value), 99.9);
68
+ break;
69
+ case 'rate':
70
+ // Calculate rate per second
71
+ const durationSec = windowMs / 1000;
72
+ value = windowData.length / durationSec;
73
+ break;
74
+ case 'ratio':
75
+ // Calculate success ratio
76
+ const successes = windowData.filter(p => p.success !== false).length;
77
+ value = (successes / windowData.length) * 100;
78
+ break;
79
+ default:
80
+ value = windowData[windowData.length - 1].value;
81
+ }
82
+ return {
83
+ sliId: sli.id,
84
+ timestamp: now,
85
+ value,
86
+ total: windowData.length,
87
+ unit: sli.unit,
88
+ windowStart,
89
+ windowEnd: now
90
+ };
91
+ }
92
+ /**
93
+ * Calculate SLI from QA360 test results
94
+ */
95
+ calculateFromTestResults(sli, results) {
96
+ const totalTests = results.total;
97
+ const passedTests = results.passed;
98
+ // For quality SLIs, we typically use passed/total
99
+ let value;
100
+ switch (sli.type) {
101
+ case 'quality':
102
+ case 'availability':
103
+ value = totalTests > 0 ? (passedTests / totalTests) * 100 : 0;
104
+ break;
105
+ case 'error_rate':
106
+ value = totalTests > 0 ? (results.failed / totalTests) * 100 : 0;
107
+ break;
108
+ case 'coverage':
109
+ // Assume results include coverage percentage
110
+ value = results.passed; // Treat passed as coverage percentage
111
+ break;
112
+ default:
113
+ value = totalTests > 0 ? (passedTests / totalTests) * 100 : 0;
114
+ }
115
+ return {
116
+ sliId: sli.id,
117
+ timestamp: Date.now(),
118
+ value,
119
+ total: totalTests,
120
+ good: passedTests,
121
+ bad: results.failed,
122
+ unit: sli.unit,
123
+ windowStart: Date.now(),
124
+ windowEnd: Date.now()
125
+ };
126
+ }
127
+ /**
128
+ * Calculate SLI from latency measurements
129
+ */
130
+ calculateLatency(sli, latencies, percentile = 'p95') {
131
+ if (latencies.length === 0) {
132
+ return this.emptyMeasurement(sli, Date.now(), Date.now());
133
+ }
134
+ const value = this.percentile(latencies, this.parsePercentile(percentile));
135
+ return {
136
+ sliId: sli.id,
137
+ timestamp: Date.now(),
138
+ value,
139
+ total: latencies.length,
140
+ unit: sli.unit,
141
+ windowStart: Date.now(),
142
+ windowEnd: Date.now()
143
+ };
144
+ }
145
+ /**
146
+ * Calculate multiple SLIs from a single data source
147
+ */
148
+ calculateBatch(slis, data) {
149
+ const measurements = [];
150
+ for (const sli of slis) {
151
+ if (Array.isArray(data) && data.length > 0 && 'timestamp' in data[0]) {
152
+ measurements.push(this.calculateFromTimeSeries(sli, data, 86400000));
153
+ }
154
+ else if ('good' in data && 'bad' in data) {
155
+ measurements.push(this.calculateFromEvents(sli, data));
156
+ }
157
+ else if ('total' in data) {
158
+ measurements.push(this.calculateFromTestResults(sli, data));
159
+ }
160
+ }
161
+ return measurements;
162
+ }
163
+ /**
164
+ * Calculate percentile value
165
+ */
166
+ percentile(values, p) {
167
+ if (values.length === 0)
168
+ return 0;
169
+ const sorted = [...values].sort((a, b) => a - b);
170
+ const index = (p / 100) * (sorted.length - 1);
171
+ if (index === Math.floor(index)) {
172
+ return sorted[index];
173
+ }
174
+ const lower = sorted[Math.floor(index)];
175
+ const upper = sorted[Math.ceil(index)];
176
+ return lower + (upper - lower) * (index - Math.floor(index));
177
+ }
178
+ /**
179
+ * Parse percentile string to number
180
+ */
181
+ parsePercentile(p) {
182
+ const match = p.match(/p(\d+(\.\d+)?)/);
183
+ if (match) {
184
+ return parseFloat(match[1]);
185
+ }
186
+ return 95; // Default to p95
187
+ }
188
+ /**
189
+ * Create empty measurement
190
+ */
191
+ emptyMeasurement(sli, windowStart, windowEnd) {
192
+ return {
193
+ sliId: sli.id,
194
+ timestamp: Date.now(),
195
+ value: 0,
196
+ total: 0,
197
+ unit: sli.unit,
198
+ windowStart,
199
+ windowEnd
200
+ };
201
+ }
202
+ /**
203
+ * Aggregate measurements over time
204
+ */
205
+ aggregateMeasurements(measurements, aggregation) {
206
+ if (measurements.length === 0) {
207
+ throw new Error('No measurements to aggregate');
208
+ }
209
+ const values = measurements.map(m => m.value);
210
+ const sliId = measurements[0].sliId;
211
+ const unit = measurements[0].unit;
212
+ const windowStart = Math.min(...measurements.map(m => m.windowStart));
213
+ const windowEnd = Math.max(...measurements.map(m => m.windowEnd));
214
+ let value;
215
+ switch (aggregation) {
216
+ case 'sum':
217
+ value = values.reduce((sum, v) => sum + v, 0);
218
+ break;
219
+ case 'avg':
220
+ value = values.reduce((sum, v) => sum + v, 0) / values.length;
221
+ break;
222
+ case 'max':
223
+ value = Math.max(...values);
224
+ break;
225
+ case 'min':
226
+ value = Math.min(...values);
227
+ break;
228
+ case 'p50':
229
+ value = this.percentile(values, 50);
230
+ break;
231
+ case 'p95':
232
+ value = this.percentile(values, 95);
233
+ break;
234
+ case 'p99':
235
+ value = this.percentile(values, 99);
236
+ break;
237
+ case 'p99_9':
238
+ value = this.percentile(values, 99.9);
239
+ break;
240
+ default:
241
+ value = values[values.length - 1];
242
+ }
243
+ return {
244
+ sliId,
245
+ timestamp: Date.now(),
246
+ value,
247
+ total: measurements.reduce((sum, m) => sum + (m.total || 0), 0),
248
+ unit,
249
+ windowStart,
250
+ windowEnd
251
+ };
252
+ }
253
+ /**
254
+ * Check if measurement meets threshold
255
+ */
256
+ meetsThreshold(measurement, threshold) {
257
+ const { operator, value } = threshold;
258
+ switch (operator) {
259
+ case 'gt':
260
+ return measurement.value > value;
261
+ case 'gte':
262
+ return measurement.value >= value;
263
+ case 'lt':
264
+ return measurement.value < value;
265
+ case 'lte':
266
+ return measurement.value <= value;
267
+ case 'eq':
268
+ return measurement.value === value;
269
+ case 'ne':
270
+ return measurement.value !== value;
271
+ default:
272
+ return false;
273
+ }
274
+ }
275
+ /**
276
+ * Calculate burn rate for error budget
277
+ */
278
+ calculateBurnRate(measurements, target, windowMs) {
279
+ if (measurements.length < 2) {
280
+ return {
281
+ current: 0,
282
+ status: 'healthy',
283
+ history: []
284
+ };
285
+ }
286
+ const now = Date.now();
287
+ const windowStart = now - windowMs;
288
+ // Filter measurements within window
289
+ const recentMeasurements = measurements.filter(m => m.timestamp >= windowStart);
290
+ if (recentMeasurements.length === 0) {
291
+ return {
292
+ current: 0,
293
+ status: 'healthy',
294
+ history: []
295
+ };
296
+ }
297
+ // Calculate error budget burn
298
+ // Each measurement below target contributes to burn
299
+ let totalBudgetDeficit = 0;
300
+ for (const m of recentMeasurements) {
301
+ if (m.value < target) {
302
+ totalBudgetDeficit += (target - m.value);
303
+ }
304
+ }
305
+ // Expected burn rate (assuming uniform distribution)
306
+ const expectedDeficit = (100 - target) * recentMeasurements.length;
307
+ const burnRate = expectedDeficit > 0 ? totalBudgetDeficit / expectedDeficit : 0;
308
+ // Determine status
309
+ let status;
310
+ if (burnRate >= 5) {
311
+ status = 'critical';
312
+ }
313
+ else if (burnRate >= 2) {
314
+ status = 'warning';
315
+ }
316
+ else {
317
+ status = 'healthy';
318
+ }
319
+ // Project exhaustion if burning fast
320
+ let projectedExhaustion;
321
+ if (burnRate > 1) {
322
+ const remainingBudget = 100 - target - totalBudgetDeficit / recentMeasurements.length;
323
+ if (remainingBudget > 0 && burnRate > 0) {
324
+ const burnPerMs = (100 - target) / windowMs * burnRate;
325
+ projectedExhaustion = now + (remainingBudget / burnPerMs);
326
+ }
327
+ }
328
+ // Build history
329
+ const history = recentMeasurements.map(m => {
330
+ const deficit = Math.max(0, target - m.value);
331
+ const rate = deficit > 0 ? deficit / (100 - target) : 0;
332
+ return {
333
+ timestamp: m.timestamp,
334
+ rate
335
+ };
336
+ });
337
+ return {
338
+ current: burnRate,
339
+ status,
340
+ projectedExhaustion,
341
+ history
342
+ };
343
+ }
344
+ /**
345
+ * Determine SLO status from current value and target
346
+ */
347
+ determineStatus(current, target, warningThreshold = 0.95) {
348
+ if (current >= target) {
349
+ return 'healthy';
350
+ }
351
+ else if (current >= target * warningThreshold) {
352
+ return 'warning';
353
+ }
354
+ else {
355
+ return 'breached';
356
+ }
357
+ }
358
+ }
359
+ /**
360
+ * Create an SLI calculator
361
+ */
362
+ export function createSLICalculator() {
363
+ return new SLICalculator();
364
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * SLO Tracker
3
+ *
4
+ * Tracks Service Level Objectives and manages error budgets.
5
+ * Monitors SLO compliance and generates reports.
6
+ */
7
+ import type { SLO, SLI, SLIMeasurement, SLOResult, SLOReport, SLOViolation, ErrorBudget, BurnRate } from './types.js';
8
+ /**
9
+ * SLO Tracker Options
10
+ */
11
+ export interface SLOTrackerOptions {
12
+ /** Warning threshold as % of target */
13
+ warningThreshold?: number;
14
+ /** Enable violation tracking */
15
+ trackViolations?: boolean;
16
+ /** Enable alerting */
17
+ enableAlerts?: boolean;
18
+ /** Alert callback */
19
+ onAlert?: (alert: SLOAlert) => void;
20
+ }
21
+ /**
22
+ * SLO Alert
23
+ */
24
+ export interface SLOAlert {
25
+ sloId: string;
26
+ sloName: string;
27
+ severity: 'warning' | 'critical';
28
+ message: string;
29
+ currentValue: number;
30
+ target: number;
31
+ errorBudgetRemaining: number;
32
+ timestamp: number;
33
+ }
34
+ /**
35
+ * SLO Tracker class
36
+ */
37
+ export declare class SLOTracker {
38
+ private slos;
39
+ private slis;
40
+ private measurements;
41
+ private violations;
42
+ private calculator;
43
+ private options;
44
+ constructor(options?: SLOTrackerOptions);
45
+ /**
46
+ * Register an SLO
47
+ */
48
+ registerSLO(slo: SLO): void;
49
+ /**
50
+ * Register an SLI
51
+ */
52
+ registerSLI(sli: SLI): void;
53
+ /**
54
+ * Register multiple SLOs
55
+ */
56
+ registerSLOs(slos: SLO[]): void;
57
+ /**
58
+ * Register multiple SLIs
59
+ */
60
+ registerSLIs(slis: SLI[]): void;
61
+ /**
62
+ * Get an SLO by ID
63
+ */
64
+ getSLO(id: string): SLO | undefined;
65
+ /**
66
+ * Get an SLI by ID
67
+ */
68
+ getSLI(id: string): SLI | undefined;
69
+ /**
70
+ * Get all registered SLOs
71
+ */
72
+ getAllSLOs(): SLO[];
73
+ /**
74
+ * Get all registered SLIs
75
+ */
76
+ getAllSLIs(): SLI[];
77
+ /**
78
+ * Record a measurement for an SLI
79
+ */
80
+ recordMeasurement(measurement: SLIMeasurement): void;
81
+ /**
82
+ * Get measurements for an SLI
83
+ */
84
+ getMeasurements(sliId: string, windowMs?: number): SLIMeasurement[];
85
+ /**
86
+ * Calculate SLO result
87
+ */
88
+ calculateSLOResult(sloId: string): SLOResult | null;
89
+ /**
90
+ * Calculate all SLO results
91
+ */
92
+ calculateAllResults(): SLOResult[];
93
+ /**
94
+ * Generate SLO report
95
+ */
96
+ generateReport(period?: {
97
+ start: number;
98
+ end: number;
99
+ }): SLOReport;
100
+ /**
101
+ * Get error budget for an SLO
102
+ */
103
+ getErrorBudget(sloId: string): ErrorBudget | null;
104
+ /**
105
+ * Calculate burn rate for an SLO
106
+ */
107
+ calculateBurnRate(sloId: string): BurnRate | null;
108
+ /**
109
+ * Get violations for an SLO
110
+ */
111
+ getViolations(sloId?: string): SLOViolation[];
112
+ /**
113
+ * Clear violations
114
+ */
115
+ clearViolations(sloId?: string): void;
116
+ /**
117
+ * Resolve a violation
118
+ */
119
+ resolveViolation(violationId: string): void;
120
+ /**
121
+ * Calculate error budget from current value and target
122
+ */
123
+ private calculateErrorBudget;
124
+ /**
125
+ * Update SLOs that depend on an SLI
126
+ */
127
+ private updateDependentSLOs;
128
+ /**
129
+ * Check for SLO violation
130
+ */
131
+ private checkForViolation;
132
+ /**
133
+ * Generate alerts for SLO status
134
+ */
135
+ private generateAlerts;
136
+ /**
137
+ * Get the longest window from all SLOs
138
+ */
139
+ private getLongestWindow;
140
+ /**
141
+ * Clear all data
142
+ */
143
+ clear(): void;
144
+ }
145
+ /**
146
+ * Create an SLO tracker
147
+ */
148
+ export declare function createSLOTracker(options?: SLOTrackerOptions): SLOTracker;