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,102 @@
1
+ /**
2
+ * SLO/SLI Vault Integration
3
+ *
4
+ * Integrates SLO/SLI data storage and retrieval with the Evidence Vault.
5
+ */
6
+ import type { Database } from 'sqlite3';
7
+ import type { SLO, SLI, SLIMeasurement, SLOViolation, SLOStatus } from './types.js';
8
+ /**
9
+ * SLO Vault class
10
+ */
11
+ export declare class SLOVault {
12
+ private db;
13
+ private dbRun;
14
+ private dbAll;
15
+ private dbGet;
16
+ constructor(db: Database);
17
+ /**
18
+ * Initialize SLO/SLI tables
19
+ */
20
+ initialize(): Promise<void>;
21
+ /**
22
+ * Store an SLO definition
23
+ */
24
+ storeSLO(slo: SLO): Promise<void>;
25
+ /**
26
+ * Store an SLI definition
27
+ */
28
+ storeSLI(sli: SLI): Promise<void>;
29
+ /**
30
+ * Store an SLI measurement
31
+ */
32
+ storeMeasurement(measurement: SLIMeasurement, runId?: string): Promise<void>;
33
+ /**
34
+ * Store an SLO snapshot
35
+ */
36
+ storeSLOSnapshot(sloId: string, data: {
37
+ currentValue: number;
38
+ target: number;
39
+ status: SLOStatus;
40
+ errorBudgetRemaining: number;
41
+ burnRate?: number;
42
+ windowStart: number;
43
+ windowEnd: number;
44
+ }, runId?: string): Promise<void>;
45
+ /**
46
+ * Store an SLO violation
47
+ */
48
+ storeViolation(violation: SLOViolation): Promise<void>;
49
+ /**
50
+ * Get all SLO definitions
51
+ */
52
+ getSLOs(): Promise<SLO[]>;
53
+ /**
54
+ * Get an SLO by ID
55
+ */
56
+ getSLO(id: string): Promise<SLO | null>;
57
+ /**
58
+ * Get all SLI definitions
59
+ */
60
+ getSLIs(): Promise<SLI[]>;
61
+ /**
62
+ * Get measurements for an SLI
63
+ */
64
+ getMeasurements(sliId: string, windowStart?: number, windowEnd?: number, limit?: number): Promise<SLIMeasurement[]>;
65
+ /**
66
+ * Get violations for an SLO
67
+ */
68
+ getViolations(sloId?: string, resolved?: boolean): Promise<SLOViolation[]>;
69
+ /**
70
+ * Get SLO snapshots for trend analysis
71
+ */
72
+ getSLOSnapshots(sloId: string, windowStart?: number, windowEnd?: number, limit?: number): Promise<Array<{
73
+ timestamp: number;
74
+ currentValue: number;
75
+ target: number;
76
+ status: SLOStatus;
77
+ errorBudgetRemaining: number;
78
+ burnRate?: number;
79
+ }>>;
80
+ /**
81
+ * Delete an SLO and its associated data
82
+ */
83
+ deleteSLO(id: string): Promise<void>;
84
+ /**
85
+ * Delete an SLI and its associated data
86
+ */
87
+ deleteSLI(id: string): Promise<void>;
88
+ /**
89
+ * Resolve a violation
90
+ */
91
+ resolveViolation(violationId: string): Promise<void>;
92
+ /**
93
+ * Get SLO statistics
94
+ */
95
+ getStatistics(): Promise<{
96
+ totalSLOs: number;
97
+ totalSLIs: number;
98
+ statusCounts: Record<SLOStatus, number>;
99
+ activeViolations: number;
100
+ totalMeasurements: number;
101
+ }>;
102
+ }
@@ -0,0 +1,427 @@
1
+ /**
2
+ * SLO/SLI Vault Integration
3
+ *
4
+ * Integrates SLO/SLI data storage and retrieval with the Evidence Vault.
5
+ */
6
+ import { promisify } from 'util';
7
+ /**
8
+ * SLO Vault class
9
+ */
10
+ export class SLOVault {
11
+ db;
12
+ dbRun;
13
+ dbAll;
14
+ dbGet;
15
+ constructor(db) {
16
+ this.db = db;
17
+ this.dbRun = promisify(db.run.bind(db));
18
+ this.dbAll = promisify(db.all.bind(db));
19
+ this.dbGet = promisify(db.get.bind(db));
20
+ }
21
+ /**
22
+ * Initialize SLO/SLI tables
23
+ */
24
+ async initialize() {
25
+ const schema = `
26
+ -- SLO definitions table
27
+ CREATE TABLE IF NOT EXISTS slo_definitions (
28
+ id TEXT PRIMARY KEY,
29
+ name TEXT NOT NULL,
30
+ description TEXT,
31
+ sli_ids TEXT NOT NULL,
32
+ target REAL NOT NULL,
33
+ window_ms INTEGER NOT NULL,
34
+ error_budget_json TEXT NOT NULL,
35
+ status TEXT NOT NULL DEFAULT 'unknown',
36
+ current_value REAL,
37
+ tags TEXT,
38
+ owner TEXT,
39
+ created_at INTEGER NOT NULL,
40
+ updated_at INTEGER NOT NULL
41
+ );
42
+
43
+ CREATE INDEX IF NOT EXISTS idx_slo_status ON slo_definitions(status);
44
+ CREATE INDEX IF NOT EXISTS idx_slo_owner ON slo_definitions(owner);
45
+ CREATE INDEX IF NOT EXISTS idx_slo_tags ON slo_definitions(tags);
46
+
47
+ -- SLI definitions table
48
+ CREATE TABLE IF NOT EXISTS sli_definitions (
49
+ id TEXT PRIMARY KEY,
50
+ name TEXT NOT NULL,
51
+ description TEXT,
52
+ type TEXT NOT NULL,
53
+ source TEXT NOT NULL,
54
+ query_json TEXT NOT NULL,
55
+ aggregation TEXT NOT NULL,
56
+ unit TEXT NOT NULL,
57
+ threshold_json TEXT NOT NULL,
58
+ category TEXT NOT NULL,
59
+ tags TEXT,
60
+ created_at INTEGER NOT NULL,
61
+ updated_at INTEGER NOT NULL
62
+ );
63
+
64
+ CREATE INDEX IF NOT EXISTS idx_sli_type ON sli_definitions(type);
65
+ CREATE INDEX IF NOT EXISTS idx_sli_category ON sli_definitions(category);
66
+
67
+ -- SLI measurements table
68
+ CREATE TABLE IF NOT EXISTS sli_measurements (
69
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
70
+ sli_id TEXT NOT NULL REFERENCES sli_definitions(id) ON DELETE CASCADE,
71
+ run_id TEXT REFERENCES runs(id) ON DELETE SET NULL,
72
+ timestamp INTEGER NOT NULL,
73
+ value REAL NOT NULL,
74
+ total INTEGER,
75
+ good INTEGER,
76
+ bad INTEGER,
77
+ unit TEXT NOT NULL,
78
+ window_start INTEGER NOT NULL,
79
+ window_end INTEGER NOT NULL
80
+ );
81
+
82
+ CREATE INDEX IF NOT EXISTS idx_sli_measurements_sli_id ON sli_measurements(sli_id);
83
+ CREATE INDEX IF NOT EXISTS idx_sli_measurements_run_id ON sli_measurements(run_id);
84
+ CREATE INDEX IF NOT EXISTS idx_sli_measurements_timestamp ON sli_measurements(timestamp);
85
+
86
+ -- SLO violations table
87
+ CREATE TABLE IF NOT EXISTS slo_violations (
88
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
89
+ slo_id TEXT NOT NULL REFERENCES slo_definitions(id) ON DELETE CASCADE,
90
+ timestamp INTEGER NOT NULL,
91
+ value REAL NOT NULL,
92
+ expected REAL NOT NULL,
93
+ severity TEXT NOT NULL,
94
+ context_json TEXT,
95
+ resolved INTEGER DEFAULT 0,
96
+ resolved_at INTEGER
97
+ );
98
+
99
+ CREATE INDEX IF NOT EXISTS idx_slo_violations_slo_id ON slo_violations(slo_id);
100
+ CREATE INDEX IF NOT EXISTS idx_slo_violations_timestamp ON slo_violations(timestamp);
101
+ CREATE INDEX IF NOT EXISTS idx_slo_violations_resolved ON slo_violations(resolved);
102
+
103
+ -- SLO snapshots (aggregated SLO status over time)
104
+ CREATE TABLE IF NOT EXISTS slo_snapshots (
105
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
106
+ slo_id TEXT NOT NULL REFERENCES slo_definitions(id) ON DELETE CASCADE,
107
+ run_id TEXT REFERENCES runs(id) ON DELETE SET NULL,
108
+ timestamp INTEGER NOT NULL,
109
+ current_value REAL NOT NULL,
110
+ target REAL NOT NULL,
111
+ status TEXT NOT NULL,
112
+ error_budget_remaining REAL NOT NULL,
113
+ burn_rate REAL,
114
+ window_start INTEGER NOT NULL,
115
+ window_end INTEGER NOT NULL
116
+ );
117
+
118
+ CREATE INDEX IF NOT EXISTS idx_slo_snapshots_slo_id ON slo_snapshots(slo_id);
119
+ CREATE INDEX IF NOT EXISTS idx_slo_snapshots_timestamp ON slo_snapshots(timestamp);
120
+ `;
121
+ const statements = schema
122
+ .split(';')
123
+ .map(s => s.trim())
124
+ .filter(s => s.length > 0);
125
+ for (const statement of statements) {
126
+ await this.dbRun(statement, []);
127
+ }
128
+ }
129
+ /**
130
+ * Store an SLO definition
131
+ */
132
+ async storeSLO(slo) {
133
+ await this.dbRun(`INSERT OR REPLACE INTO slo_definitions (
134
+ id, name, description, sli_ids, target, window_ms,
135
+ error_budget_json, status, current_value, tags, owner,
136
+ created_at, updated_at
137
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
138
+ slo.id,
139
+ slo.name,
140
+ slo.description || null,
141
+ JSON.stringify(slo.sliIds),
142
+ slo.target,
143
+ slo.windowMs,
144
+ JSON.stringify(slo.errorBudget),
145
+ slo.status,
146
+ slo.currentValue || null,
147
+ slo.tags ? JSON.stringify(slo.tags) : null,
148
+ slo.owner || null,
149
+ slo.createdAt,
150
+ Date.now()
151
+ ]);
152
+ }
153
+ /**
154
+ * Store an SLI definition
155
+ */
156
+ async storeSLI(sli) {
157
+ await this.dbRun(`INSERT OR REPLACE INTO sli_definitions (
158
+ id, name, description, type, source, query_json,
159
+ aggregation, unit, threshold_json, category, tags,
160
+ created_at, updated_at
161
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
162
+ sli.id,
163
+ sli.name,
164
+ sli.description || null,
165
+ sli.type,
166
+ sli.source,
167
+ JSON.stringify(sli.query),
168
+ sli.aggregation,
169
+ sli.unit,
170
+ JSON.stringify(sli.threshold),
171
+ sli.category,
172
+ sli.tags ? JSON.stringify(sli.tags) : null,
173
+ sli.createdAt,
174
+ Date.now()
175
+ ]);
176
+ }
177
+ /**
178
+ * Store an SLI measurement
179
+ */
180
+ async storeMeasurement(measurement, runId) {
181
+ await this.dbRun(`INSERT INTO sli_measurements (
182
+ sli_id, run_id, timestamp, value, total, good, bad,
183
+ unit, window_start, window_end
184
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
185
+ measurement.sliId,
186
+ runId || null,
187
+ measurement.timestamp,
188
+ measurement.value,
189
+ measurement.total || null,
190
+ measurement.good || null,
191
+ measurement.bad || null,
192
+ measurement.unit,
193
+ measurement.windowStart,
194
+ measurement.windowEnd
195
+ ]);
196
+ }
197
+ /**
198
+ * Store an SLO snapshot
199
+ */
200
+ async storeSLOSnapshot(sloId, data, runId) {
201
+ await this.dbRun(`INSERT INTO slo_snapshots (
202
+ slo_id, run_id, timestamp, current_value, target, status,
203
+ error_budget_remaining, burn_rate, window_start, window_end
204
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
205
+ sloId,
206
+ runId || null,
207
+ Date.now(),
208
+ data.currentValue,
209
+ data.target,
210
+ data.status,
211
+ data.errorBudgetRemaining,
212
+ data.burnRate || null,
213
+ data.windowStart,
214
+ data.windowEnd
215
+ ]);
216
+ }
217
+ /**
218
+ * Store an SLO violation
219
+ */
220
+ async storeViolation(violation) {
221
+ await this.dbRun(`INSERT INTO slo_violations (
222
+ slo_id, timestamp, value, expected, severity,
223
+ context_json, resolved, resolved_at
224
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
225
+ violation.sloId,
226
+ violation.timestamp,
227
+ violation.value,
228
+ violation.expected,
229
+ violation.severity,
230
+ violation.context ? JSON.stringify(violation.context) : null,
231
+ violation.resolved ? 1 : 0,
232
+ violation.resolvedAt || null
233
+ ]);
234
+ }
235
+ /**
236
+ * Get all SLO definitions
237
+ */
238
+ async getSLOs() {
239
+ const rows = await this.dbAll(`SELECT * FROM slo_definitions`, []);
240
+ return rows.map((r) => ({
241
+ id: r.id,
242
+ name: r.name,
243
+ description: r.description,
244
+ sliIds: JSON.parse(r.sli_ids),
245
+ target: r.target,
246
+ windowMs: r.window_ms,
247
+ errorBudget: JSON.parse(r.error_budget_json),
248
+ status: r.status,
249
+ currentValue: r.current_value,
250
+ tags: r.tags ? JSON.parse(r.tags) : undefined,
251
+ owner: r.owner,
252
+ createdAt: r.created_at,
253
+ updatedAt: r.updated_at
254
+ }));
255
+ }
256
+ /**
257
+ * Get an SLO by ID
258
+ */
259
+ async getSLO(id) {
260
+ const row = await this.dbGet(`SELECT * FROM slo_definitions WHERE id = ?`, [id]);
261
+ if (!row)
262
+ return null;
263
+ return {
264
+ id: row.id,
265
+ name: row.name,
266
+ description: row.description,
267
+ sliIds: JSON.parse(row.sli_ids),
268
+ target: row.target,
269
+ windowMs: row.window_ms,
270
+ errorBudget: JSON.parse(row.error_budget_json),
271
+ status: row.status,
272
+ currentValue: row.current_value,
273
+ tags: row.tags ? JSON.parse(row.tags) : undefined,
274
+ owner: row.owner,
275
+ createdAt: row.created_at,
276
+ updatedAt: row.updated_at
277
+ };
278
+ }
279
+ /**
280
+ * Get all SLI definitions
281
+ */
282
+ async getSLIs() {
283
+ const rows = await this.dbAll(`SELECT * FROM sli_definitions`, []);
284
+ return rows.map((r) => ({
285
+ id: r.id,
286
+ name: r.name,
287
+ description: r.description,
288
+ type: r.type,
289
+ source: r.source,
290
+ query: JSON.parse(r.query_json),
291
+ aggregation: r.aggregation,
292
+ unit: r.unit,
293
+ threshold: JSON.parse(r.threshold_json),
294
+ category: r.category,
295
+ tags: r.tags ? JSON.parse(r.tags) : undefined,
296
+ createdAt: r.created_at,
297
+ updatedAt: r.updated_at
298
+ }));
299
+ }
300
+ /**
301
+ * Get measurements for an SLI
302
+ */
303
+ async getMeasurements(sliId, windowStart, windowEnd, limit = 1000) {
304
+ let sql = `SELECT * FROM sli_measurements WHERE sli_id = ?`;
305
+ const params = [sliId];
306
+ if (windowStart) {
307
+ sql += ` AND timestamp >= ?`;
308
+ params.push(windowStart);
309
+ }
310
+ if (windowEnd) {
311
+ sql += ` AND timestamp <= ?`;
312
+ params.push(windowEnd);
313
+ }
314
+ sql += ` ORDER BY timestamp DESC LIMIT ?`;
315
+ params.push(limit);
316
+ const rows = await this.dbAll(sql, params);
317
+ return rows.map((r) => ({
318
+ sliId: r.sli_id,
319
+ timestamp: r.timestamp,
320
+ value: r.value,
321
+ total: r.total,
322
+ good: r.good,
323
+ bad: r.bad,
324
+ unit: r.unit,
325
+ windowStart: r.window_start,
326
+ windowEnd: r.window_end
327
+ }));
328
+ }
329
+ /**
330
+ * Get violations for an SLO
331
+ */
332
+ async getViolations(sloId, resolved) {
333
+ let sql = `SELECT * FROM slo_violations WHERE 1=1`;
334
+ const params = [];
335
+ if (sloId) {
336
+ sql += ` AND slo_id = ?`;
337
+ params.push(sloId);
338
+ }
339
+ if (resolved !== undefined) {
340
+ sql += ` AND resolved = ?`;
341
+ params.push(resolved ? 1 : 0);
342
+ }
343
+ sql += ` ORDER BY timestamp DESC`;
344
+ const rows = await this.dbAll(sql, params);
345
+ return rows.map((r) => ({
346
+ id: r.id?.toString() || '',
347
+ sloId: r.slo_id,
348
+ timestamp: r.timestamp,
349
+ value: r.value,
350
+ expected: r.expected,
351
+ severity: r.severity,
352
+ context: r.context_json ? JSON.parse(r.context_json) : undefined,
353
+ resolved: r.resolved === 1,
354
+ resolvedAt: r.resolved_at
355
+ }));
356
+ }
357
+ /**
358
+ * Get SLO snapshots for trend analysis
359
+ */
360
+ async getSLOSnapshots(sloId, windowStart, windowEnd, limit = 100) {
361
+ let sql = `SELECT * FROM slo_snapshots WHERE slo_id = ?`;
362
+ const params = [sloId];
363
+ if (windowStart) {
364
+ sql += ` AND timestamp >= ?`;
365
+ params.push(windowStart);
366
+ }
367
+ if (windowEnd) {
368
+ sql += ` AND timestamp <= ?`;
369
+ params.push(windowEnd);
370
+ }
371
+ sql += ` ORDER BY timestamp DESC LIMIT ?`;
372
+ params.push(limit);
373
+ const rows = await this.dbAll(sql, params);
374
+ return rows.map((r) => ({
375
+ timestamp: r.timestamp,
376
+ currentValue: r.current_value,
377
+ target: r.target,
378
+ status: r.status,
379
+ errorBudgetRemaining: r.error_budget_remaining,
380
+ burnRate: r.burn_rate
381
+ }));
382
+ }
383
+ /**
384
+ * Delete an SLO and its associated data
385
+ */
386
+ async deleteSLO(id) {
387
+ await this.dbRun(`DELETE FROM slo_definitions WHERE id = ?`, [id]);
388
+ }
389
+ /**
390
+ * Delete an SLI and its associated data
391
+ */
392
+ async deleteSLI(id) {
393
+ await this.dbRun(`DELETE FROM sli_definitions WHERE id = ?`, [id]);
394
+ }
395
+ /**
396
+ * Resolve a violation
397
+ */
398
+ async resolveViolation(violationId) {
399
+ await this.dbRun(`UPDATE slo_violations SET resolved = 1, resolved_at = ? WHERE id = ?`, [Date.now(), parseInt(violationId, 10)]);
400
+ }
401
+ /**
402
+ * Get SLO statistics
403
+ */
404
+ async getStatistics() {
405
+ const totalSLOs = await this.dbGet(`SELECT COUNT(*) as count FROM slo_definitions`, []);
406
+ const totalSLIs = await this.dbGet(`SELECT COUNT(*) as count FROM sli_definitions`, []);
407
+ const statusCounts = await this.dbAll(`SELECT status, COUNT(*) as count FROM slo_definitions GROUP BY status`, []);
408
+ const activeViolations = await this.dbGet(`SELECT COUNT(*) as count FROM slo_violations WHERE resolved = 0`, []);
409
+ const totalMeasurements = await this.dbGet(`SELECT COUNT(*) as count FROM sli_measurements`, []);
410
+ const statusMap = {
411
+ healthy: 0,
412
+ warning: 0,
413
+ breached: 0,
414
+ unknown: 0
415
+ };
416
+ for (const row of statusCounts) {
417
+ statusMap[row.status] = row.count;
418
+ }
419
+ return {
420
+ totalSLOs: totalSLOs?.count || 0,
421
+ totalSLIs: totalSLIs?.count || 0,
422
+ statusCounts: statusMap,
423
+ activeViolations: activeViolations?.count || 0,
424
+ totalMeasurements: totalMeasurements?.count || 0
425
+ };
426
+ }
427
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * QA360 TUI (Terminal UI) Module
3
+ * Phase 8: Real-time test execution monitoring
4
+ */
5
+ export type { TUIOptions, TUIState, TUIGateState, TUIEvent, TUIRenderer, TUIProgressBarOptions, TUITableOptions, TUILayout, TUISection } from './types.js';
6
+ export { TerminalRenderer } from './renderer.js';
7
+ export { TUIMonitor, createMonitor, monitorExecution } from './monitor.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * QA360 TUI (Terminal UI) Module
3
+ * Phase 8: Real-time test execution monitoring
4
+ */
5
+ export { TerminalRenderer } from './renderer.js';
6
+ export { TUIMonitor, createMonitor, monitorExecution } from './monitor.js';
@@ -0,0 +1,92 @@
1
+ /**
2
+ * TUI Monitor - Real-time test execution monitor
3
+ * Listens to Phase3Runner events and updates the terminal UI
4
+ */
5
+ import type { TUIOptions, TUIState, TUIEvent, TUIGateState } from './types.js';
6
+ export declare class TUIMonitor {
7
+ private options;
8
+ private renderer;
9
+ private state;
10
+ private refreshInterval?;
11
+ private eventBuffer;
12
+ private gateStartTime;
13
+ constructor(options?: TUIOptions);
14
+ /**
15
+ * Start monitoring a test run
16
+ */
17
+ start(totalGates: number): void;
18
+ /**
19
+ * Emit an event during test execution
20
+ */
21
+ emit(event: TUIEvent): void;
22
+ /**
23
+ * Update gate status
24
+ */
25
+ updateGate(name: string, updates: Partial<TUIGateState>): void;
26
+ /**
27
+ * Mark gate as started
28
+ */
29
+ startGate(name: string): void;
30
+ /**
31
+ * Mark gate as completed
32
+ */
33
+ completeGate(name: string, success: boolean, results?: {
34
+ total: number;
35
+ passed: number;
36
+ failed: number;
37
+ }): void;
38
+ /**
39
+ * Set current phase
40
+ */
41
+ setPhase(phase: string): void;
42
+ /**
43
+ * Set current progress (0-100)
44
+ */
45
+ setProgress(progress: number): void;
46
+ /**
47
+ * Update test progress for current gate
48
+ */
49
+ updateTestProgress(gateName: string, completed: number, total: number): void;
50
+ /**
51
+ * Mark run as failed
52
+ */
53
+ fail(error: string): void;
54
+ /**
55
+ * Mark run as completed
56
+ */
57
+ complete(): void;
58
+ /**
59
+ * Stop monitoring and cleanup
60
+ */
61
+ stop(): void;
62
+ /**
63
+ * Cleanup and restore terminal
64
+ */
65
+ cleanup(): void;
66
+ /**
67
+ * Get current state
68
+ */
69
+ getState(): Readonly<TUIState>;
70
+ /**
71
+ * Get event buffer
72
+ */
73
+ getEvents(): ReadonlyArray<TUIEvent>;
74
+ private processEvent;
75
+ private updateElapsed;
76
+ private calculateETA;
77
+ private updateProgress;
78
+ private printSummary;
79
+ private formatCount;
80
+ private formatDuration;
81
+ private setupExitHandlers;
82
+ private removeExitHandlers;
83
+ private handleExit;
84
+ }
85
+ /**
86
+ * Create a monitor instance for programmatic use
87
+ */
88
+ export declare function createMonitor(options?: TUIOptions): TUIMonitor;
89
+ /**
90
+ * Convenience function to monitor a Phase3Runner execution
91
+ */
92
+ export declare function monitorExecution(execute: (emit: (event: TUIEvent) => void) => Promise<void>, options?: TUIOptions): Promise<void>;