@vertaaux/cli 0.2.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 (198) hide show
  1. package/README.md +345 -0
  2. package/dist/auth/ci-token.d.ts +49 -0
  3. package/dist/auth/ci-token.d.ts.map +1 -0
  4. package/dist/auth/ci-token.js +83 -0
  5. package/dist/auth/device-flow.d.ts +66 -0
  6. package/dist/auth/device-flow.d.ts.map +1 -0
  7. package/dist/auth/device-flow.js +156 -0
  8. package/dist/auth/token-store.d.ts +53 -0
  9. package/dist/auth/token-store.d.ts.map +1 -0
  10. package/dist/auth/token-store.js +78 -0
  11. package/dist/baseline/diff.d.ts +57 -0
  12. package/dist/baseline/diff.d.ts.map +1 -0
  13. package/dist/baseline/diff.js +152 -0
  14. package/dist/baseline/hash.d.ts +54 -0
  15. package/dist/baseline/hash.d.ts.map +1 -0
  16. package/dist/baseline/hash.js +66 -0
  17. package/dist/baseline/manager.d.ts +89 -0
  18. package/dist/baseline/manager.d.ts.map +1 -0
  19. package/dist/baseline/manager.js +157 -0
  20. package/dist/cache/index.d.ts +8 -0
  21. package/dist/cache/index.d.ts.map +1 -0
  22. package/dist/cache/index.js +7 -0
  23. package/dist/cache/route-cache.d.ts +119 -0
  24. package/dist/cache/route-cache.d.ts.map +1 -0
  25. package/dist/cache/route-cache.js +213 -0
  26. package/dist/ci/changed-routes.d.ts +95 -0
  27. package/dist/ci/changed-routes.d.ts.map +1 -0
  28. package/dist/ci/changed-routes.js +304 -0
  29. package/dist/ci/github-api.d.ts +68 -0
  30. package/dist/ci/github-api.d.ts.map +1 -0
  31. package/dist/ci/github-api.js +138 -0
  32. package/dist/ci/gitlab-api.d.ts +75 -0
  33. package/dist/ci/gitlab-api.d.ts.map +1 -0
  34. package/dist/ci/gitlab-api.js +180 -0
  35. package/dist/ci/index.d.ts +6 -0
  36. package/dist/ci/index.d.ts.map +1 -0
  37. package/dist/ci/index.js +4 -0
  38. package/dist/commands/audit.d.ts +58 -0
  39. package/dist/commands/audit.d.ts.map +1 -0
  40. package/dist/commands/audit.js +862 -0
  41. package/dist/commands/baseline.d.ts +22 -0
  42. package/dist/commands/baseline.d.ts.map +1 -0
  43. package/dist/commands/baseline.js +210 -0
  44. package/dist/commands/comment.d.ts +14 -0
  45. package/dist/commands/comment.d.ts.map +1 -0
  46. package/dist/commands/comment.js +363 -0
  47. package/dist/commands/diff.d.ts +24 -0
  48. package/dist/commands/diff.d.ts.map +1 -0
  49. package/dist/commands/diff.js +196 -0
  50. package/dist/commands/doctor.d.ts +58 -0
  51. package/dist/commands/doctor.d.ts.map +1 -0
  52. package/dist/commands/doctor.js +338 -0
  53. package/dist/commands/download.d.ts +12 -0
  54. package/dist/commands/download.d.ts.map +1 -0
  55. package/dist/commands/download.js +183 -0
  56. package/dist/commands/explain.d.ts +62 -0
  57. package/dist/commands/explain.d.ts.map +1 -0
  58. package/dist/commands/explain.js +302 -0
  59. package/dist/commands/init.d.ts +12 -0
  60. package/dist/commands/init.d.ts.map +1 -0
  61. package/dist/commands/init.js +212 -0
  62. package/dist/commands/login.d.ts +14 -0
  63. package/dist/commands/login.d.ts.map +1 -0
  64. package/dist/commands/login.js +222 -0
  65. package/dist/commands/policy.d.ts +13 -0
  66. package/dist/commands/policy.d.ts.map +1 -0
  67. package/dist/commands/policy.js +347 -0
  68. package/dist/commands/upload.d.ts +12 -0
  69. package/dist/commands/upload.d.ts.map +1 -0
  70. package/dist/commands/upload.js +158 -0
  71. package/dist/config/defaults.d.ts +21 -0
  72. package/dist/config/defaults.d.ts.map +1 -0
  73. package/dist/config/defaults.js +49 -0
  74. package/dist/config/loader.d.ts +66 -0
  75. package/dist/config/loader.d.ts.map +1 -0
  76. package/dist/config/loader.js +167 -0
  77. package/dist/config/schema.d.ts +55 -0
  78. package/dist/config/schema.d.ts.map +1 -0
  79. package/dist/config/schema.js +6 -0
  80. package/dist/index.d.ts +9 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +1090 -0
  83. package/dist/interactive/fix-wizard.d.ts +44 -0
  84. package/dist/interactive/fix-wizard.d.ts.map +1 -0
  85. package/dist/interactive/fix-wizard.js +286 -0
  86. package/dist/interactive/init-wizard.d.ts +32 -0
  87. package/dist/interactive/init-wizard.d.ts.map +1 -0
  88. package/dist/interactive/init-wizard.js +193 -0
  89. package/dist/interactive/prompts.d.ts +62 -0
  90. package/dist/interactive/prompts.d.ts.map +1 -0
  91. package/dist/interactive/prompts.js +78 -0
  92. package/dist/monorepo/detector.d.ts +70 -0
  93. package/dist/monorepo/detector.d.ts.map +1 -0
  94. package/dist/monorepo/detector.js +278 -0
  95. package/dist/monorepo/index.d.ts +9 -0
  96. package/dist/monorepo/index.d.ts.map +1 -0
  97. package/dist/monorepo/index.js +8 -0
  98. package/dist/monorepo/workspace.d.ts +142 -0
  99. package/dist/monorepo/workspace.d.ts.map +1 -0
  100. package/dist/monorepo/workspace.js +171 -0
  101. package/dist/output/envelope.d.ts +21 -0
  102. package/dist/output/envelope.d.ts.map +1 -0
  103. package/dist/output/envelope.js +27 -0
  104. package/dist/output/factory.d.ts +73 -0
  105. package/dist/output/factory.d.ts.map +1 -0
  106. package/dist/output/factory.js +60 -0
  107. package/dist/output/formats.d.ts +11 -0
  108. package/dist/output/formats.d.ts.map +1 -0
  109. package/dist/output/formats.js +41 -0
  110. package/dist/output/html.d.ts +45 -0
  111. package/dist/output/html.d.ts.map +1 -0
  112. package/dist/output/html.js +607 -0
  113. package/dist/output/human.d.ts +41 -0
  114. package/dist/output/human.d.ts.map +1 -0
  115. package/dist/output/human.js +274 -0
  116. package/dist/output/json.d.ts +42 -0
  117. package/dist/output/json.d.ts.map +1 -0
  118. package/dist/output/json.js +37 -0
  119. package/dist/output/junit.d.ts +56 -0
  120. package/dist/output/junit.d.ts.map +1 -0
  121. package/dist/output/junit.js +135 -0
  122. package/dist/output/markdown.d.ts +77 -0
  123. package/dist/output/markdown.d.ts.map +1 -0
  124. package/dist/output/markdown.js +411 -0
  125. package/dist/output/sarif.d.ts +160 -0
  126. package/dist/output/sarif.d.ts.map +1 -0
  127. package/dist/output/sarif.js +207 -0
  128. package/dist/policy/evaluator.d.ts +111 -0
  129. package/dist/policy/evaluator.d.ts.map +1 -0
  130. package/dist/policy/evaluator.js +362 -0
  131. package/dist/policy/index.d.ts +15 -0
  132. package/dist/policy/index.d.ts.map +1 -0
  133. package/dist/policy/index.js +11 -0
  134. package/dist/policy/loader.d.ts +97 -0
  135. package/dist/policy/loader.d.ts.map +1 -0
  136. package/dist/policy/loader.js +281 -0
  137. package/dist/policy/schema.d.ts +297 -0
  138. package/dist/policy/schema.d.ts.map +1 -0
  139. package/dist/policy/schema.js +230 -0
  140. package/dist/quality-gate/evaluator.d.ts +58 -0
  141. package/dist/quality-gate/evaluator.d.ts.map +1 -0
  142. package/dist/quality-gate/evaluator.js +274 -0
  143. package/dist/quality-gate/index.d.ts +10 -0
  144. package/dist/quality-gate/index.d.ts.map +1 -0
  145. package/dist/quality-gate/index.js +7 -0
  146. package/dist/quality-gate/types.d.ts +103 -0
  147. package/dist/quality-gate/types.d.ts.map +1 -0
  148. package/dist/quality-gate/types.js +23 -0
  149. package/dist/templates/azure-devops.d.ts +25 -0
  150. package/dist/templates/azure-devops.d.ts.map +1 -0
  151. package/dist/templates/azure-devops.js +109 -0
  152. package/dist/templates/circleci.d.ts +28 -0
  153. package/dist/templates/circleci.d.ts.map +1 -0
  154. package/dist/templates/circleci.js +86 -0
  155. package/dist/templates/github-actions.d.ts +81 -0
  156. package/dist/templates/github-actions.d.ts.map +1 -0
  157. package/dist/templates/github-actions.js +393 -0
  158. package/dist/templates/gitlab-ci.d.ts +26 -0
  159. package/dist/templates/gitlab-ci.d.ts.map +1 -0
  160. package/dist/templates/gitlab-ci.js +70 -0
  161. package/dist/templates/index.d.ts +72 -0
  162. package/dist/templates/index.d.ts.map +1 -0
  163. package/dist/templates/index.js +112 -0
  164. package/dist/templates/jenkins.d.ts +26 -0
  165. package/dist/templates/jenkins.d.ts.map +1 -0
  166. package/dist/templates/jenkins.js +110 -0
  167. package/dist/ui/banner.d.ts +31 -0
  168. package/dist/ui/banner.d.ts.map +1 -0
  169. package/dist/ui/banner.js +84 -0
  170. package/dist/ui/diagnostics.d.ts +39 -0
  171. package/dist/ui/diagnostics.d.ts.map +1 -0
  172. package/dist/ui/diagnostics.js +153 -0
  173. package/dist/ui/spinner.d.ts +61 -0
  174. package/dist/ui/spinner.d.ts.map +1 -0
  175. package/dist/ui/spinner.js +101 -0
  176. package/dist/ui/table.d.ts +63 -0
  177. package/dist/ui/table.d.ts.map +1 -0
  178. package/dist/ui/table.js +236 -0
  179. package/dist/utils/client.d.ts +82 -0
  180. package/dist/utils/client.d.ts.map +1 -0
  181. package/dist/utils/client.js +128 -0
  182. package/dist/utils/detect-env.d.ts +59 -0
  183. package/dist/utils/detect-env.d.ts.map +1 -0
  184. package/dist/utils/detect-env.js +115 -0
  185. package/dist/utils/exit-codes.d.ts +47 -0
  186. package/dist/utils/exit-codes.d.ts.map +1 -0
  187. package/dist/utils/exit-codes.js +61 -0
  188. package/dist/utils/logger.d.ts +87 -0
  189. package/dist/utils/logger.d.ts.map +1 -0
  190. package/dist/utils/logger.js +185 -0
  191. package/dist/utils/sanitize.d.ts +36 -0
  192. package/dist/utils/sanitize.d.ts.map +1 -0
  193. package/dist/utils/sanitize.js +64 -0
  194. package/dist/utils/validators.d.ts +41 -0
  195. package/dist/utils/validators.d.ts.map +1 -0
  196. package/dist/utils/validators.js +123 -0
  197. package/package.json +63 -0
  198. package/schemas/vertaaux.config.schema.json +103 -0
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Policy file schema for vertaa.policy.yml.
3
+ *
4
+ * Enables policy-as-code for organizations to define:
5
+ * - Quality thresholds and assertions
6
+ * - Rule severity overrides
7
+ * - Branch-specific policies
8
+ * - Bypass labels for emergency deploys
9
+ *
10
+ * Modeled on Semgrep/ESLint policy patterns.
11
+ *
12
+ * Implements CICD-17: Policy-as-code support.
13
+ */
14
+ /**
15
+ * JSON Schema for vertaa.policy.yml validation.
16
+ *
17
+ * Used for:
18
+ * - Runtime validation with Ajv
19
+ * - IDE autocompletion and validation
20
+ * - Documentation generation
21
+ */
22
+ export const policyJsonSchema = {
23
+ $schema: "http://json-schema.org/draft-07/schema#",
24
+ $id: "https://vertaaux.ai/schemas/policy.json",
25
+ title: "VertaaUX Policy",
26
+ description: "Policy-as-code configuration for VertaaUX quality gates. Commit this file to your repository to define organization-wide UX standards.",
27
+ type: "object",
28
+ properties: {
29
+ $schema: {
30
+ type: "string",
31
+ description: "JSON Schema reference for IDE support",
32
+ },
33
+ version: {
34
+ type: "number",
35
+ enum: [1],
36
+ description: "Policy file format version (currently only version 1)",
37
+ },
38
+ name: {
39
+ type: "string",
40
+ description: "Human-readable policy name",
41
+ },
42
+ description: {
43
+ type: "string",
44
+ description: "Policy description for documentation",
45
+ },
46
+ assertions: {
47
+ type: "object",
48
+ description: "Threshold assertions that must pass",
49
+ properties: {
50
+ overall_score: {
51
+ type: "number",
52
+ minimum: 0,
53
+ maximum: 100,
54
+ description: "Minimum overall score (0-100)",
55
+ },
56
+ accessibility_score: {
57
+ type: "number",
58
+ minimum: 0,
59
+ maximum: 100,
60
+ description: "Minimum accessibility score (0-100)",
61
+ },
62
+ ux_score: {
63
+ type: "number",
64
+ minimum: 0,
65
+ maximum: 100,
66
+ description: "Minimum UX score (0-100)",
67
+ },
68
+ performance_score: {
69
+ type: "number",
70
+ minimum: 0,
71
+ maximum: 100,
72
+ description: "Minimum performance score (0-100)",
73
+ },
74
+ fail_on: {
75
+ type: "string",
76
+ enum: ["error", "warning", "info"],
77
+ description: "Fail on issues at or above this severity",
78
+ },
79
+ max_new_errors: {
80
+ type: "number",
81
+ minimum: 0,
82
+ description: "Maximum new error-severity issues allowed",
83
+ },
84
+ max_new_warnings: {
85
+ type: "number",
86
+ minimum: 0,
87
+ description: "Maximum new warning-severity issues allowed",
88
+ },
89
+ max_new_total: {
90
+ type: "number",
91
+ minimum: 0,
92
+ description: "Maximum total new issues allowed",
93
+ },
94
+ },
95
+ additionalProperties: false,
96
+ },
97
+ rules: {
98
+ type: "object",
99
+ description: "Rule-specific severity overrides",
100
+ additionalProperties: {
101
+ type: "object",
102
+ properties: {
103
+ severity: {
104
+ type: "string",
105
+ enum: ["error", "warning", "info", "ignore"],
106
+ description: "Override severity for this rule",
107
+ },
108
+ reason: {
109
+ type: "string",
110
+ description: "Reason for override (for audit trail)",
111
+ },
112
+ paths: {
113
+ type: "array",
114
+ items: { type: "string" },
115
+ description: "Apply override only to these paths (glob patterns)",
116
+ },
117
+ },
118
+ required: ["severity"],
119
+ additionalProperties: false,
120
+ },
121
+ },
122
+ branches: {
123
+ type: "object",
124
+ description: "Branch-specific policy overrides",
125
+ additionalProperties: {
126
+ type: "object",
127
+ properties: {
128
+ pattern: {
129
+ type: "string",
130
+ description: "Branch pattern (glob). If not specified, uses exact match.",
131
+ },
132
+ assertions: {
133
+ $ref: "#/properties/assertions",
134
+ description: "Override assertions for this branch",
135
+ },
136
+ },
137
+ additionalProperties: false,
138
+ },
139
+ },
140
+ bypass_labels: {
141
+ type: "array",
142
+ items: { type: "string" },
143
+ description: "PR labels that bypass quality gate entirely (e.g., emergency-fix)",
144
+ },
145
+ exclude_paths: {
146
+ type: "array",
147
+ items: { type: "string" },
148
+ description: "Path patterns to exclude from auditing",
149
+ },
150
+ required_version: {
151
+ type: "string",
152
+ description: "Required minimum CLI version (semver range, e.g., >=1.0.0)",
153
+ },
154
+ },
155
+ required: ["version", "assertions"],
156
+ additionalProperties: false,
157
+ };
158
+ /**
159
+ * Default policy with sensible enterprise defaults.
160
+ *
161
+ * - Only fail on errors (not warnings/info)
162
+ * - Only fail on NEW errors (existing debt allowed)
163
+ * - Common emergency bypass labels
164
+ */
165
+ export const DEFAULT_POLICY = {
166
+ version: 1,
167
+ assertions: {
168
+ fail_on: "error",
169
+ max_new_errors: 0,
170
+ },
171
+ bypass_labels: ["skip-vertaa", "emergency-fix"],
172
+ };
173
+ /**
174
+ * Policy templates for different strictness levels.
175
+ */
176
+ export const POLICY_TEMPLATES = {
177
+ /**
178
+ * Basic template - fail only on new errors.
179
+ */
180
+ basic: {
181
+ version: 1,
182
+ name: "Basic Policy",
183
+ description: "Block new error-severity issues only",
184
+ assertions: {
185
+ fail_on: "error",
186
+ max_new_errors: 0,
187
+ },
188
+ bypass_labels: ["skip-vertaa", "emergency-fix"],
189
+ },
190
+ /**
191
+ * Strict template - fail on warnings, require minimum scores.
192
+ */
193
+ strict: {
194
+ version: 1,
195
+ name: "Strict Policy",
196
+ description: "Maintain high quality standards with score thresholds and zero tolerance for new issues",
197
+ assertions: {
198
+ fail_on: "warning",
199
+ overall_score: 80,
200
+ max_new_errors: 0,
201
+ max_new_warnings: 0,
202
+ },
203
+ branches: {
204
+ main: {
205
+ assertions: {
206
+ overall_score: 85,
207
+ },
208
+ },
209
+ "release/*": {
210
+ pattern: "release/*",
211
+ assertions: {
212
+ overall_score: 90,
213
+ },
214
+ },
215
+ },
216
+ bypass_labels: ["emergency-fix"],
217
+ },
218
+ /**
219
+ * Lenient template - fail only on critical errors.
220
+ */
221
+ lenient: {
222
+ version: 1,
223
+ name: "Lenient Policy",
224
+ description: "Minimal quality gate for gradual adoption",
225
+ assertions: {
226
+ fail_on: "error",
227
+ },
228
+ bypass_labels: ["skip-vertaa", "emergency-fix", "wip"],
229
+ },
230
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Quality gate evaluation for CI pipelines.
3
+ *
4
+ * Determines whether a CI build should pass or fail based on audit results.
5
+ * Key principle: Only fail on NEW issues, not existing technical debt.
6
+ *
7
+ * Implements:
8
+ * - CICD-06: Fail on new issues only
9
+ * - CICD-07: Threshold enforcement
10
+ * - CICD-13: Budget-aware evaluation
11
+ */
12
+ import type { QualityGateConfig, QualityGateResult } from "./types.js";
13
+ import type { BaselineFile } from "../baseline/manager.js";
14
+ import type { Issue } from "../baseline/hash.js";
15
+ /**
16
+ * Audit result type for quality gate evaluation.
17
+ */
18
+ export interface AuditResultForGate {
19
+ /** Issues found during audit */
20
+ issues?: Issue[] | Record<string, Issue[]>;
21
+ /** Score breakdown */
22
+ scores?: Record<string, number | unknown>;
23
+ /** Any runtime error */
24
+ error?: unknown;
25
+ }
26
+ /**
27
+ * Options for quality gate evaluation.
28
+ */
29
+ export interface EvaluateOptions {
30
+ /** Audit result with issues and scores */
31
+ auditResult: AuditResultForGate;
32
+ /** Baseline for comparison (optional - if missing, all issues treated as new) */
33
+ baseline?: BaselineFile | null;
34
+ /** Quality gate configuration */
35
+ config: QualityGateConfig;
36
+ /** PR labels for bypass check */
37
+ labels?: string[];
38
+ }
39
+ /**
40
+ * Evaluate quality gate based on audit results.
41
+ *
42
+ * Evaluation order:
43
+ * 1. Check bypass labels (short-circuit if matched)
44
+ * 2. Compute diff against baseline (new vs existing)
45
+ * 3. Count new issues by severity
46
+ * 4. Check thresholds against scores
47
+ * 5. Build violations list
48
+ * 6. Determine exit code
49
+ *
50
+ * @param options - Evaluation options
51
+ * @returns Quality gate result with pass/fail status and violations
52
+ */
53
+ export declare function evaluateQualityGate(options: EvaluateOptions): QualityGateResult;
54
+ /**
55
+ * Format quality gate result for human-readable output.
56
+ */
57
+ export declare function formatQualityGateResult(result: QualityGateResult): string;
58
+ //# sourceMappingURL=evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../src/quality-gate/evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IAC1C,wBAAwB;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,WAAW,EAAE,kBAAkB,CAAC;IAChC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B,iCAAiC;IACjC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAiGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,iBAAiB,CAmJ/E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAyCzE"}
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Quality gate evaluation for CI pipelines.
3
+ *
4
+ * Determines whether a CI build should pass or fail based on audit results.
5
+ * Key principle: Only fail on NEW issues, not existing technical debt.
6
+ *
7
+ * Implements:
8
+ * - CICD-06: Fail on new issues only
9
+ * - CICD-07: Threshold enforcement
10
+ * - CICD-13: Budget-aware evaluation
11
+ */
12
+ import { computeDiff } from "../baseline/diff.js";
13
+ import { ExitCode } from "../utils/exit-codes.js";
14
+ /** Severity ranking for comparison */
15
+ const SEVERITY_RANK = {
16
+ error: 3,
17
+ critical: 3,
18
+ warning: 2,
19
+ serious: 2,
20
+ info: 1,
21
+ minor: 1,
22
+ moderate: 1,
23
+ };
24
+ /**
25
+ * Map common severity aliases to canonical values.
26
+ */
27
+ function normalizeSeverity(severity) {
28
+ const lower = (severity || "info").toLowerCase();
29
+ switch (lower) {
30
+ case "error":
31
+ case "critical":
32
+ return "error";
33
+ case "warning":
34
+ case "serious":
35
+ return "warning";
36
+ default:
37
+ return "info";
38
+ }
39
+ }
40
+ /**
41
+ * Get severity rank for comparison.
42
+ */
43
+ function severityRank(severity) {
44
+ return SEVERITY_RANK[severity.toLowerCase()] ?? 0;
45
+ }
46
+ /**
47
+ * Normalize issues from various API response formats to array.
48
+ */
49
+ function normalizeIssues(issues) {
50
+ if (Array.isArray(issues)) {
51
+ return issues;
52
+ }
53
+ if (issues && typeof issues === "object") {
54
+ const values = Object.values(issues);
55
+ return values.flatMap((value) => Array.isArray(value) ? value : []);
56
+ }
57
+ return [];
58
+ }
59
+ /**
60
+ * Count issues by normalized severity.
61
+ */
62
+ function countBySeverity(issues) {
63
+ const counts = { error: 0, warning: 0, info: 0 };
64
+ for (const issue of issues) {
65
+ const normalized = normalizeSeverity(issue.severity || "info");
66
+ counts[normalized]++;
67
+ }
68
+ return counts;
69
+ }
70
+ /**
71
+ * Extract numeric scores from audit result.
72
+ */
73
+ function extractScores(scores) {
74
+ const result = {};
75
+ if (!scores)
76
+ return result;
77
+ for (const [key, value] of Object.entries(scores)) {
78
+ if (typeof value === "number" && Number.isFinite(value)) {
79
+ result[key] = value;
80
+ }
81
+ }
82
+ return result;
83
+ }
84
+ /**
85
+ * Create empty baseline for when no baseline is provided.
86
+ */
87
+ function createEmptyBaseline() {
88
+ return {
89
+ version: 1,
90
+ created: new Date().toISOString(),
91
+ updated: new Date().toISOString(),
92
+ url: "",
93
+ issues: [],
94
+ };
95
+ }
96
+ /**
97
+ * Evaluate quality gate based on audit results.
98
+ *
99
+ * Evaluation order:
100
+ * 1. Check bypass labels (short-circuit if matched)
101
+ * 2. Compute diff against baseline (new vs existing)
102
+ * 3. Count new issues by severity
103
+ * 4. Check thresholds against scores
104
+ * 5. Build violations list
105
+ * 6. Determine exit code
106
+ *
107
+ * @param options - Evaluation options
108
+ * @returns Quality gate result with pass/fail status and violations
109
+ */
110
+ export function evaluateQualityGate(options) {
111
+ const { auditResult, baseline, config, labels = [] } = options;
112
+ // Initialize summary
113
+ const scores = extractScores(auditResult.scores);
114
+ const summary = {
115
+ newIssues: { error: 0, warning: 0, info: 0 },
116
+ fixedIssues: 0,
117
+ existingIssues: 0,
118
+ scores,
119
+ };
120
+ // 1. Check bypass labels first
121
+ const matchedBypass = config.bypassLabels.find((bypassLabel) => labels.some((prLabel) => prLabel.toLowerCase() === bypassLabel.toLowerCase()));
122
+ if (matchedBypass) {
123
+ return {
124
+ passed: true,
125
+ exitCode: ExitCode.SUCCESS,
126
+ violations: [],
127
+ summary,
128
+ bypassed: true,
129
+ bypassReason: `Label "${matchedBypass}" bypasses quality gate`,
130
+ };
131
+ }
132
+ // 2. Normalize issues and compute diff
133
+ const currentIssues = normalizeIssues(auditResult.issues);
134
+ // Use provided baseline or empty baseline (treats all issues as new)
135
+ const effectiveBaseline = baseline || createEmptyBaseline();
136
+ const diff = computeDiff(currentIssues, effectiveBaseline);
137
+ // Update summary
138
+ summary.newIssues = countBySeverity(diff.new);
139
+ summary.fixedIssues = diff.summary.fixedCount;
140
+ summary.existingIssues = diff.summary.presentCount;
141
+ // 3. Build violations list
142
+ const violations = [];
143
+ // 3a. Check new issues against failOn severity
144
+ if (config.failOn !== "none") {
145
+ const failOnRank = severityRank(config.failOn);
146
+ for (const issue of diff.new) {
147
+ const issueSeverity = issue.severity || "info";
148
+ if (severityRank(issueSeverity) >= failOnRank) {
149
+ violations.push({
150
+ type: "new_issue",
151
+ severity: normalizeSeverity(issueSeverity),
152
+ message: `New ${issueSeverity} issue: ${issue.ruleId || issue.rule_id || issue.id || "unknown"} - ${(issue.description || issue.title || "").slice(0, 100)}`,
153
+ details: {
154
+ ruleId: issue.ruleId || issue.rule_id || issue.id,
155
+ selector: issue.selector,
156
+ },
157
+ });
158
+ }
159
+ }
160
+ }
161
+ // 3b. Check existing issues if failOnExisting is enabled (legacy mode)
162
+ if (config.failOnExisting && config.failOn !== "none") {
163
+ const failOnRank = severityRank(config.failOn);
164
+ for (const issue of diff.present) {
165
+ const issueSeverity = issue.severity || "info";
166
+ if (severityRank(issueSeverity) >= failOnRank) {
167
+ violations.push({
168
+ type: "new_issue", // Using same type for consistency
169
+ severity: normalizeSeverity(issueSeverity),
170
+ message: `Existing ${issueSeverity} issue: ${issue.ruleId || issue.rule_id || issue.id || "unknown"} - ${(issue.description || issue.title || "").slice(0, 100)}`,
171
+ details: {
172
+ ruleId: issue.ruleId || issue.rule_id || issue.id,
173
+ selector: issue.selector,
174
+ },
175
+ });
176
+ }
177
+ }
178
+ }
179
+ // 3c. Check max new counts
180
+ for (const [severityKey, max] of Object.entries(config.maxNew)) {
181
+ const severity = severityKey;
182
+ const count = summary.newIssues[severity];
183
+ if (count > max) {
184
+ violations.push({
185
+ type: "max_exceeded",
186
+ severity,
187
+ message: `Too many new ${severity} issues: ${count} (max allowed: ${max})`,
188
+ details: {
189
+ count,
190
+ threshold: max,
191
+ },
192
+ });
193
+ }
194
+ }
195
+ // 3d. Check score thresholds
196
+ for (const [category, threshold] of Object.entries(config.thresholds)) {
197
+ if (threshold === undefined)
198
+ continue;
199
+ const actual = scores[category];
200
+ if (actual !== undefined && actual < threshold) {
201
+ violations.push({
202
+ type: "threshold",
203
+ severity: "error",
204
+ message: `${category} score ${actual} is below threshold ${threshold}`,
205
+ details: {
206
+ actual,
207
+ threshold,
208
+ },
209
+ });
210
+ }
211
+ }
212
+ // 4. Determine exit code
213
+ let exitCode = ExitCode.SUCCESS;
214
+ if (violations.length > 0) {
215
+ // Check if any threshold violations exist
216
+ const hasThresholdViolation = violations.some((v) => v.type === "threshold");
217
+ // Check if any new issue or max exceeded violations exist
218
+ const hasIssueViolation = violations.some((v) => v.type === "new_issue" || v.type === "max_exceeded");
219
+ // Exit code 1 (issues) takes precedence over exit code 3 (threshold)
220
+ if (hasIssueViolation) {
221
+ exitCode = ExitCode.ISSUES_FOUND;
222
+ }
223
+ else if (hasThresholdViolation) {
224
+ exitCode = ExitCode.THRESHOLD_BREACH;
225
+ }
226
+ }
227
+ return {
228
+ passed: violations.length === 0,
229
+ exitCode,
230
+ violations,
231
+ summary,
232
+ bypassed: false,
233
+ };
234
+ }
235
+ /**
236
+ * Format quality gate result for human-readable output.
237
+ */
238
+ export function formatQualityGateResult(result) {
239
+ const lines = [];
240
+ // Header
241
+ if (result.bypassed) {
242
+ lines.push(`Quality Gate: BYPASSED (${result.bypassReason})`);
243
+ }
244
+ else if (result.passed) {
245
+ lines.push("Quality Gate: PASSED");
246
+ }
247
+ else {
248
+ lines.push("Quality Gate: FAILED");
249
+ }
250
+ // Summary
251
+ lines.push("");
252
+ lines.push("Summary:");
253
+ lines.push(` New issues: ${result.summary.newIssues.error} errors, ${result.summary.newIssues.warning} warnings, ${result.summary.newIssues.info} info`);
254
+ lines.push(` Fixed: ${result.summary.fixedIssues}`);
255
+ lines.push(` Existing: ${result.summary.existingIssues}`);
256
+ // Scores
257
+ const scoreEntries = Object.entries(result.summary.scores);
258
+ if (scoreEntries.length > 0) {
259
+ lines.push("");
260
+ lines.push("Scores:");
261
+ for (const [category, score] of scoreEntries) {
262
+ lines.push(` ${category}: ${score}`);
263
+ }
264
+ }
265
+ // Violations
266
+ if (result.violations.length > 0) {
267
+ lines.push("");
268
+ lines.push(`Violations (${result.violations.length}):`);
269
+ for (const violation of result.violations) {
270
+ lines.push(` - [${violation.severity.toUpperCase()}] ${violation.message}`);
271
+ }
272
+ }
273
+ return lines.join("\n");
274
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Quality gate module for CI/CD integration.
3
+ *
4
+ * Exports evaluator and types for build gating based on audit results.
5
+ */
6
+ export { evaluateQualityGate, formatQualityGateResult } from "./evaluator.js";
7
+ export type { AuditResultForGate, EvaluateOptions, } from "./evaluator.js";
8
+ export { DEFAULT_QUALITY_GATE_CONFIG } from "./types.js";
9
+ export type { QualityGateConfig, QualityGateResult, GateViolation, ThresholdConfig, } from "./types.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/quality-gate/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAC9E,YAAY,EACV,kBAAkB,EAClB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Quality gate module for CI/CD integration.
3
+ *
4
+ * Exports evaluator and types for build gating based on audit results.
5
+ */
6
+ export { evaluateQualityGate, formatQualityGateResult } from "./evaluator.js";
7
+ export { DEFAULT_QUALITY_GATE_CONFIG } from "./types.js";
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Quality gate type definitions.
3
+ *
4
+ * Quality gates control when CI builds should fail based on audit results.
5
+ * Key principle: Fail only on NEW issues (not existing technical debt).
6
+ *
7
+ * Implements CICD-06: Fail on new issues only, not existing technical debt.
8
+ */
9
+ import type { ExitCodeType } from "../utils/exit-codes.js";
10
+ /**
11
+ * Quality gate configuration.
12
+ */
13
+ export interface QualityGateConfig {
14
+ /** Fail on issues at or above this severity. 'none' disables severity check. */
15
+ failOn: "error" | "warning" | "info" | "none";
16
+ /** Score thresholds (0-100). Undefined means threshold not enforced. */
17
+ thresholds: ThresholdConfig;
18
+ /** Maximum allowed new issues by severity */
19
+ maxNew: {
20
+ error: number;
21
+ warning: number;
22
+ info: number;
23
+ };
24
+ /** Whether to fail on existing issues (legacy mode, default: false) */
25
+ failOnExisting: boolean;
26
+ /** PR labels that bypass quality gate entirely */
27
+ bypassLabels: string[];
28
+ }
29
+ /**
30
+ * Score threshold configuration.
31
+ *
32
+ * Each field is optional - only specified thresholds are enforced.
33
+ */
34
+ export interface ThresholdConfig {
35
+ /** Overall score threshold (0-100) */
36
+ overall?: number;
37
+ /** Accessibility score threshold (0-100) */
38
+ accessibility?: number;
39
+ /** UX score threshold (0-100) */
40
+ ux?: number;
41
+ /** Performance score threshold (0-100) */
42
+ performance?: number;
43
+ }
44
+ /**
45
+ * Individual quality gate violation.
46
+ *
47
+ * Violations are categorized by type for clear reporting:
48
+ * - new_issue: A new issue above failOn severity
49
+ * - threshold: Score below minimum threshold
50
+ * - max_exceeded: More new issues than allowed by maxNew config
51
+ */
52
+ export interface GateViolation {
53
+ /** Type of violation */
54
+ type: "new_issue" | "threshold" | "max_exceeded";
55
+ /** Severity level of the violation */
56
+ severity: "error" | "warning" | "info";
57
+ /** Human-readable message */
58
+ message: string;
59
+ /** Additional details for debugging */
60
+ details?: {
61
+ ruleId?: string;
62
+ selector?: string;
63
+ actual?: number;
64
+ threshold?: number;
65
+ count?: number;
66
+ };
67
+ }
68
+ /**
69
+ * Result of quality gate evaluation.
70
+ */
71
+ export interface QualityGateResult {
72
+ /** Whether the gate passed (true = CI should succeed) */
73
+ passed: boolean;
74
+ /** Exit code to use for process.exit() */
75
+ exitCode: ExitCodeType;
76
+ /** List of violations (empty if passed) */
77
+ violations: GateViolation[];
78
+ /** Summary counts for reporting */
79
+ summary: {
80
+ newIssues: {
81
+ error: number;
82
+ warning: number;
83
+ info: number;
84
+ };
85
+ fixedIssues: number;
86
+ existingIssues: number;
87
+ scores: Record<string, number>;
88
+ };
89
+ /** Whether gate was bypassed via label */
90
+ bypassed: boolean;
91
+ /** Reason for bypass (label name) */
92
+ bypassReason?: string;
93
+ }
94
+ /**
95
+ * Default quality gate configuration.
96
+ *
97
+ * Defaults are designed to be adoption-friendly:
98
+ * - Only fail on errors (not warnings/info)
99
+ * - Only fail on NEW errors (existing debt allowed)
100
+ * - No score thresholds by default (opt-in)
101
+ */
102
+ export declare const DEFAULT_QUALITY_GATE_CONFIG: QualityGateConfig;
103
+ //# sourceMappingURL=types.d.ts.map